OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/common/gpu/media/omx_video_decode_accelerator.h" | 5 #include "content/common/gpu/media/omx_video_decode_accelerator.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/debug/trace_event.h" | 8 #include "base/debug/trace_event.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 OMX_U32 num_components = 1; | 183 OMX_U32 num_components = 1; |
184 scoped_array<OMX_U8> component(new OMX_U8[OMX_MAX_STRINGNAME_SIZE]); | 184 scoped_array<OMX_U8> component(new OMX_U8[OMX_MAX_STRINGNAME_SIZE]); |
185 OMX_ERRORTYPE result = omx_get_components_of_role( | 185 OMX_ERRORTYPE result = omx_get_components_of_role( |
186 role_name, &num_components, reinterpret_cast<OMX_U8**>(&component)); | 186 role_name, &num_components, reinterpret_cast<OMX_U8**>(&component)); |
187 RETURN_ON_OMX_FAILURE(result, "Unsupport role: " << role_name, | 187 RETURN_ON_OMX_FAILURE(result, "Unsupport role: " << role_name, |
188 PLATFORM_FAILURE, false); | 188 PLATFORM_FAILURE, false); |
189 RETURN_ON_FAILURE(num_components == 1, "No components for: " << role_name, | 189 RETURN_ON_FAILURE(num_components == 1, "No components for: " << role_name, |
190 PLATFORM_FAILURE, false); | 190 PLATFORM_FAILURE, false); |
191 | 191 |
192 // Get the handle to the component. | 192 // Get the handle to the component. |
193 AddRef(); // To reflect passing |this| to OMX_GetHandle below. | |
194 result = omx_gethandle( | 193 result = omx_gethandle( |
195 &component_handle_, reinterpret_cast<OMX_STRING>(component.get()), | 194 &component_handle_, reinterpret_cast<OMX_STRING>(component.get()), |
196 this, &omx_accelerator_callbacks); | 195 this, &omx_accelerator_callbacks); |
197 RETURN_ON_OMX_FAILURE(result, | 196 RETURN_ON_OMX_FAILURE(result, |
198 "Failed to OMX_GetHandle on: " << component.get(), | 197 "Failed to OMX_GetHandle on: " << component.get(), |
199 PLATFORM_FAILURE, false); | 198 PLATFORM_FAILURE, false); |
200 client_state_ = OMX_StateLoaded; | 199 client_state_ = OMX_StateLoaded; |
201 | 200 |
202 component_name_is_nvidia_h264ext_ = !strcmp( | 201 component_name_is_nvidia_h264ext_ = !strcmp( |
203 reinterpret_cast<char *>(component.get()), | 202 reinterpret_cast<char *>(component.get()), |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
430 } | 429 } |
431 | 430 |
432 void OmxVideoDecodeAccelerator::Reset() { | 431 void OmxVideoDecodeAccelerator::Reset() { |
433 DCHECK_EQ(message_loop_, MessageLoop::current()); | 432 DCHECK_EQ(message_loop_, MessageLoop::current()); |
434 DCHECK_EQ(current_state_change_, NO_TRANSITION); | 433 DCHECK_EQ(current_state_change_, NO_TRANSITION); |
435 DCHECK_EQ(client_state_, OMX_StateExecuting); | 434 DCHECK_EQ(client_state_, OMX_StateExecuting); |
436 current_state_change_ = RESETTING; | 435 current_state_change_ = RESETTING; |
437 BeginTransitionToState(OMX_StatePause); | 436 BeginTransitionToState(OMX_StatePause); |
438 } | 437 } |
439 | 438 |
440 void OmxVideoDecodeAccelerator::Destroy() { | 439 void OmxVideoDecodeAccelerator::Destroy( |
| 440 scoped_ptr<VideoDecodeAccelerator> self) { |
441 DCHECK_EQ(message_loop_, MessageLoop::current()); | 441 DCHECK_EQ(message_loop_, MessageLoop::current()); |
442 if (current_state_change_ == ERRORING || | 442 if (current_state_change_ == ERRORING || |
443 current_state_change_ == DESTROYING) { | 443 current_state_change_ == DESTROYING) { |
444 return; | 444 return; |
445 } | 445 } |
446 | 446 |
447 DCHECK(current_state_change_ == NO_TRANSITION || | 447 DCHECK(current_state_change_ == NO_TRANSITION || |
448 current_state_change_ == FLUSHING || | 448 current_state_change_ == FLUSHING || |
449 current_state_change_ == RESETTING) << current_state_change_; | 449 current_state_change_ == RESETTING) << current_state_change_; |
450 | 450 |
451 // If we were never initializeed there's no teardown to do. | 451 // If we were never initializeed there's no teardown to do. |
452 if (client_state_ == OMX_StateMax) | 452 if (client_state_ == OMX_StateMax) |
453 return; | 453 return; |
454 // If we can already call OMX_FreeHandle, simply do so. | 454 // If we can already call OMX_FreeHandle, simply do so. |
455 if (client_state_ == OMX_StateInvalid || client_state_ == OMX_StateLoaded) { | 455 if (client_state_ == OMX_StateInvalid || client_state_ == OMX_StateLoaded) { |
456 ShutdownComponent(); | 456 ShutdownComponent(); |
457 return; | 457 return; |
458 } | 458 } |
459 DCHECK(client_state_ == OMX_StateExecuting || | 459 DCHECK(client_state_ == OMX_StateExecuting || |
460 client_state_ == OMX_StateIdle || | 460 client_state_ == OMX_StateIdle || |
461 client_state_ == OMX_StatePause); | 461 client_state_ == OMX_StatePause); |
462 current_state_change_ = DESTROYING; | 462 current_state_change_ = DESTROYING; |
463 client_ = NULL; | 463 client_ = NULL; |
464 BeginTransitionToState(OMX_StateIdle); | 464 BeginTransitionToState(OMX_StateIdle); |
465 BusyLoopInDestroying(); | 465 BusyLoopInDestroying(self.Pass()); |
466 } | 466 } |
467 | 467 |
468 void OmxVideoDecodeAccelerator::BeginTransitionToState( | 468 void OmxVideoDecodeAccelerator::BeginTransitionToState( |
469 OMX_STATETYPE new_state) { | 469 OMX_STATETYPE new_state) { |
470 DCHECK_EQ(message_loop_, MessageLoop::current()); | 470 DCHECK_EQ(message_loop_, MessageLoop::current()); |
471 DCHECK_NE(current_state_change_, NO_TRANSITION); | 471 DCHECK_NE(current_state_change_, NO_TRANSITION); |
472 DCHECK_NE(current_state_change_, ERRORING); | 472 DCHECK_NE(current_state_change_, ERRORING); |
473 if (current_state_change_ == NO_TRANSITION || | 473 if (current_state_change_ == NO_TRANSITION || |
474 current_state_change_ == ERRORING) { | 474 current_state_change_ == ERRORING) { |
475 return; | 475 return; |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
555 client_->NotifyResetDone(); | 555 client_->NotifyResetDone(); |
556 } | 556 } |
557 | 557 |
558 // Alert: HORROR ahead! OMX shutdown is an asynchronous dance but our clients | 558 // Alert: HORROR ahead! OMX shutdown is an asynchronous dance but our clients |
559 // enjoy the fire-and-forget nature of a synchronous Destroy() call that | 559 // enjoy the fire-and-forget nature of a synchronous Destroy() call that |
560 // ensures no further callbacks are made. Since the interface between OMX | 560 // ensures no further callbacks are made. Since the interface between OMX |
561 // callbacks and this class is a MessageLoop, we need to ensure the loop | 561 // callbacks and this class is a MessageLoop, we need to ensure the loop |
562 // outlives the shutdown dance, even during process shutdown. We do this by | 562 // outlives the shutdown dance, even during process shutdown. We do this by |
563 // repeatedly enqueuing a no-op task until shutdown is complete, since | 563 // repeatedly enqueuing a no-op task until shutdown is complete, since |
564 // MessageLoop's shutdown drains pending tasks. | 564 // MessageLoop's shutdown drains pending tasks. |
565 void OmxVideoDecodeAccelerator::BusyLoopInDestroying() { | 565 void OmxVideoDecodeAccelerator::BusyLoopInDestroying( |
| 566 scoped_ptr<VideoDecodeAccelerator> self) { |
566 if (!component_handle_) return; | 567 if (!component_handle_) return; |
567 // Can't use PostDelayedTask here because MessageLoop doesn't drain delayed | 568 // Can't use PostDelayedTask here because MessageLoop doesn't drain delayed |
568 // tasks. Instead we sleep for 5ms. Really. | 569 // tasks. Instead we sleep for 5ms. Really. |
569 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(5)); | 570 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(5)); |
570 message_loop_->PostTask( | 571 message_loop_->PostTask( |
571 FROM_HERE, base::Bind( | 572 FROM_HERE, base::Bind( |
572 &OmxVideoDecodeAccelerator::BusyLoopInDestroying, this)); | 573 &OmxVideoDecodeAccelerator::BusyLoopInDestroying, |
| 574 base::Unretained(this), base::Passed(&self))); |
573 } | 575 } |
574 | 576 |
575 void OmxVideoDecodeAccelerator::OnReachedIdleInDestroying() { | 577 void OmxVideoDecodeAccelerator::OnReachedIdleInDestroying() { |
576 DCHECK(client_state_ == OMX_StateExecuting || | 578 DCHECK(client_state_ == OMX_StateExecuting || |
577 client_state_ == OMX_StateIdle || | 579 client_state_ == OMX_StateIdle || |
578 client_state_ == OMX_StatePause); | 580 client_state_ == OMX_StatePause); |
579 client_state_ = OMX_StateIdle; | 581 client_state_ = OMX_StateIdle; |
580 | 582 |
581 // Note that during the Executing -> Idle transition, the OMX spec guarantees | 583 // Note that during the Executing -> Idle transition, the OMX spec guarantees |
582 // buffers have been returned to the client, so we don't need to do an | 584 // buffers have been returned to the client, so we don't need to do an |
583 // explicit FlushIOPorts(). | 585 // explicit FlushIOPorts(). |
584 | 586 |
585 BeginTransitionToState(OMX_StateLoaded); | 587 BeginTransitionToState(OMX_StateLoaded); |
586 | 588 |
587 // TODO(fischman): evaluate what these conditionals are doing. What happens | 589 // TODO(fischman): evaluate what these conditionals are doing. What happens |
588 // if they're false?? | 590 // if they're false?? |
589 if (!input_buffers_at_component_) | 591 if (!input_buffers_at_component_) |
590 FreeInputBuffers(); | 592 FreeInputBuffers(); |
591 if (!output_buffers_at_component_) | 593 if (!output_buffers_at_component_) |
592 FreeOutputBuffers(); | 594 FreeOutputBuffers(); |
593 | |
594 BusyLoopInDestroying(); | |
595 } | 595 } |
596 | 596 |
597 void OmxVideoDecodeAccelerator::OnReachedLoadedInDestroying() { | 597 void OmxVideoDecodeAccelerator::OnReachedLoadedInDestroying() { |
598 DCHECK_EQ(client_state_, OMX_StateIdle); | 598 DCHECK_EQ(client_state_, OMX_StateIdle); |
599 client_state_ = OMX_StateLoaded; | 599 client_state_ = OMX_StateLoaded; |
600 current_state_change_ = NO_TRANSITION; | 600 current_state_change_ = NO_TRANSITION; |
601 ShutdownComponent(); | 601 ShutdownComponent(); |
602 } | 602 } |
603 | 603 |
604 void OmxVideoDecodeAccelerator::OnReachedInvalidInErroring() { | 604 void OmxVideoDecodeAccelerator::OnReachedInvalidInErroring() { |
605 client_state_ = OMX_StateInvalid; | 605 client_state_ = OMX_StateInvalid; |
606 ShutdownComponent(); | 606 ShutdownComponent(); |
607 } | 607 } |
608 | 608 |
609 void OmxVideoDecodeAccelerator::ShutdownComponent() { | 609 void OmxVideoDecodeAccelerator::ShutdownComponent() { |
610 OMX_ERRORTYPE result = omx_free_handle(component_handle_); | 610 OMX_ERRORTYPE result = omx_free_handle(component_handle_); |
611 if (result != OMX_ErrorNone) | 611 if (result != OMX_ErrorNone) |
612 DLOG(ERROR) << "OMX_FreeHandle() error. Error code: " << result; | 612 DLOG(ERROR) << "OMX_FreeHandle() error. Error code: " << result; |
| 613 client_state_ = OMX_StateMax; |
| 614 omx_deinit(); |
| 615 // Allow BusyLoopInDestroying to exit and delete |this|. |
613 component_handle_ = NULL; | 616 component_handle_ = NULL; |
614 client_state_ = OMX_StateMax; | |
615 // This Release() call must happen *after* any access to |*this| because it | |
616 // might result in |this| being deleted. | |
617 Release(); // Since OMX no longer has |this| to call back to. | |
618 omx_deinit(); | |
619 } | 617 } |
620 | 618 |
621 void OmxVideoDecodeAccelerator::StopOnError( | 619 void OmxVideoDecodeAccelerator::StopOnError( |
622 media::VideoDecodeAccelerator::Error error) { | 620 media::VideoDecodeAccelerator::Error error) { |
623 DCHECK_EQ(message_loop_, MessageLoop::current()); | 621 DCHECK_EQ(message_loop_, MessageLoop::current()); |
624 | 622 |
625 if (client_ && init_begun_) | 623 if (client_ && init_begun_) |
626 client_->NotifyError(error); | 624 client_->NotifyError(error); |
627 client_ = NULL; | 625 client_ = NULL; |
628 | 626 |
(...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
993 OMX_PTR priv_data, | 991 OMX_PTR priv_data, |
994 OMX_EVENTTYPE event, | 992 OMX_EVENTTYPE event, |
995 OMX_U32 data1, | 993 OMX_U32 data1, |
996 OMX_U32 data2, | 994 OMX_U32 data2, |
997 OMX_PTR event_data) { | 995 OMX_PTR event_data) { |
998 // Called on the OMX thread. | 996 // Called on the OMX thread. |
999 OmxVideoDecodeAccelerator* decoder = | 997 OmxVideoDecodeAccelerator* decoder = |
1000 static_cast<OmxVideoDecodeAccelerator*>(priv_data); | 998 static_cast<OmxVideoDecodeAccelerator*>(priv_data); |
1001 DCHECK_EQ(component, decoder->component_handle_); | 999 DCHECK_EQ(component, decoder->component_handle_); |
1002 decoder->message_loop_->PostTask(FROM_HERE, base::Bind( | 1000 decoder->message_loop_->PostTask(FROM_HERE, base::Bind( |
1003 &OmxVideoDecodeAccelerator::EventHandlerCompleteTask, decoder, | 1001 &OmxVideoDecodeAccelerator::EventHandlerCompleteTask, |
1004 event, data1, data2)); | 1002 base::AsWeakPtr(decoder), event, data1, data2)); |
1005 return OMX_ErrorNone; | 1003 return OMX_ErrorNone; |
1006 } | 1004 } |
1007 | 1005 |
1008 // static | 1006 // static |
1009 OMX_ERRORTYPE OmxVideoDecodeAccelerator::EmptyBufferCallback( | 1007 OMX_ERRORTYPE OmxVideoDecodeAccelerator::EmptyBufferCallback( |
1010 OMX_HANDLETYPE component, | 1008 OMX_HANDLETYPE component, |
1011 OMX_PTR priv_data, | 1009 OMX_PTR priv_data, |
1012 OMX_BUFFERHEADERTYPE* buffer) { | 1010 OMX_BUFFERHEADERTYPE* buffer) { |
1013 TRACE_EVENT1("Video Decoder", "OVDA::EmptyBufferCallback", | 1011 TRACE_EVENT1("Video Decoder", "OVDA::EmptyBufferCallback", |
1014 "Buffer id", buffer->nTimeStamp); | 1012 "Buffer id", buffer->nTimeStamp); |
1015 // Called on the OMX thread. | 1013 // Called on the OMX thread. |
1016 OmxVideoDecodeAccelerator* decoder = | 1014 OmxVideoDecodeAccelerator* decoder = |
1017 static_cast<OmxVideoDecodeAccelerator*>(priv_data); | 1015 static_cast<OmxVideoDecodeAccelerator*>(priv_data); |
1018 DCHECK_EQ(component, decoder->component_handle_); | 1016 DCHECK_EQ(component, decoder->component_handle_); |
1019 decoder->message_loop_->PostTask(FROM_HERE, base::Bind( | 1017 decoder->message_loop_->PostTask(FROM_HERE, base::Bind( |
1020 &OmxVideoDecodeAccelerator::EmptyBufferDoneTask, decoder, buffer)); | 1018 &OmxVideoDecodeAccelerator::EmptyBufferDoneTask, base::AsWeakPtr(decoder), |
| 1019 buffer)); |
1021 return OMX_ErrorNone; | 1020 return OMX_ErrorNone; |
1022 } | 1021 } |
1023 | 1022 |
1024 // static | 1023 // static |
1025 OMX_ERRORTYPE OmxVideoDecodeAccelerator::FillBufferCallback( | 1024 OMX_ERRORTYPE OmxVideoDecodeAccelerator::FillBufferCallback( |
1026 OMX_HANDLETYPE component, | 1025 OMX_HANDLETYPE component, |
1027 OMX_PTR priv_data, | 1026 OMX_PTR priv_data, |
1028 OMX_BUFFERHEADERTYPE* buffer) { | 1027 OMX_BUFFERHEADERTYPE* buffer) { |
1029 media::Picture* picture = | 1028 media::Picture* picture = |
1030 reinterpret_cast<media::Picture*>(buffer->pAppPrivate); | 1029 reinterpret_cast<media::Picture*>(buffer->pAppPrivate); |
1031 int picture_buffer_id = picture ? picture->picture_buffer_id() : -1; | 1030 int picture_buffer_id = picture ? picture->picture_buffer_id() : -1; |
1032 TRACE_EVENT2("Video Decoder", "OVDA::FillBufferCallback", | 1031 TRACE_EVENT2("Video Decoder", "OVDA::FillBufferCallback", |
1033 "Buffer id", buffer->nTimeStamp, | 1032 "Buffer id", buffer->nTimeStamp, |
1034 "Picture id", picture_buffer_id); | 1033 "Picture id", picture_buffer_id); |
1035 // Called on the OMX thread. | 1034 // Called on the OMX thread. |
1036 OmxVideoDecodeAccelerator* decoder = | 1035 OmxVideoDecodeAccelerator* decoder = |
1037 static_cast<OmxVideoDecodeAccelerator*>(priv_data); | 1036 static_cast<OmxVideoDecodeAccelerator*>(priv_data); |
1038 DCHECK_EQ(component, decoder->component_handle_); | 1037 DCHECK_EQ(component, decoder->component_handle_); |
1039 decoder->message_loop_->PostTask(FROM_HERE, base::Bind( | 1038 decoder->message_loop_->PostTask(FROM_HERE, base::Bind( |
1040 &OmxVideoDecodeAccelerator::FillBufferDoneTask, decoder, buffer)); | 1039 &OmxVideoDecodeAccelerator::FillBufferDoneTask, base::AsWeakPtr(decoder), |
| 1040 buffer)); |
1041 return OMX_ErrorNone; | 1041 return OMX_ErrorNone; |
1042 } | 1042 } |
1043 | 1043 |
1044 bool OmxVideoDecodeAccelerator::CanFillBuffer() { | 1044 bool OmxVideoDecodeAccelerator::CanFillBuffer() { |
1045 DCHECK_EQ(message_loop_, MessageLoop::current()); | 1045 DCHECK_EQ(message_loop_, MessageLoop::current()); |
1046 const CurrentStateChange csc = current_state_change_; | 1046 const CurrentStateChange csc = current_state_change_; |
1047 const OMX_STATETYPE cs = client_state_; | 1047 const OMX_STATETYPE cs = client_state_; |
1048 return (csc != DESTROYING && csc != ERRORING) && | 1048 return (csc != DESTROYING && csc != ERRORING) && |
1049 (cs == OMX_StateIdle || cs == OMX_StateExecuting || cs == OMX_StatePause); | 1049 (cs == OMX_StateIdle || cs == OMX_StateExecuting || cs == OMX_StatePause); |
1050 } | 1050 } |
1051 | 1051 |
1052 bool OmxVideoDecodeAccelerator::SendCommandToPort( | 1052 bool OmxVideoDecodeAccelerator::SendCommandToPort( |
1053 OMX_COMMANDTYPE cmd, int port_index) { | 1053 OMX_COMMANDTYPE cmd, int port_index) { |
1054 DCHECK_EQ(message_loop_, MessageLoop::current()); | 1054 DCHECK_EQ(message_loop_, MessageLoop::current()); |
1055 OMX_ERRORTYPE result = OMX_SendCommand(component_handle_, | 1055 OMX_ERRORTYPE result = OMX_SendCommand(component_handle_, |
1056 cmd, port_index, 0); | 1056 cmd, port_index, 0); |
1057 RETURN_ON_OMX_FAILURE(result, "SendCommand() failed" << cmd, | 1057 RETURN_ON_OMX_FAILURE(result, "SendCommand() failed" << cmd, |
1058 PLATFORM_FAILURE, false); | 1058 PLATFORM_FAILURE, false); |
1059 return true; | 1059 return true; |
1060 } | 1060 } |
OLD | NEW |