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