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 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
430 } | 430 } |
431 | 431 |
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 scoped_ptr<VideoDecodeAccelerator> self) { |
441 DCHECK_EQ(message_loop_, MessageLoop::current()); | 442 DCHECK_EQ(message_loop_, MessageLoop::current()); |
442 if (current_state_change_ == ERRORING || | 443 if (current_state_change_ == ERRORING || |
443 current_state_change_ == DESTROYING) { | 444 current_state_change_ == DESTROYING) { |
444 return; | 445 return; |
445 } | 446 } |
446 | 447 |
447 DCHECK(current_state_change_ == NO_TRANSITION || | 448 DCHECK(current_state_change_ == NO_TRANSITION || |
448 current_state_change_ == FLUSHING || | 449 current_state_change_ == FLUSHING || |
449 current_state_change_ == RESETTING) << current_state_change_; | 450 current_state_change_ == RESETTING) << current_state_change_; |
450 | 451 |
451 // If we were never initializeed there's no teardown to do. | 452 // If we were never initializeed there's no teardown to do. |
452 if (client_state_ == OMX_StateMax) | 453 if (client_state_ == OMX_StateMax) |
453 return; | 454 return; |
454 // If we can already call OMX_FreeHandle, simply do so. | 455 // If we can already call OMX_FreeHandle, simply do so. |
455 if (client_state_ == OMX_StateInvalid || client_state_ == OMX_StateLoaded) { | 456 if (client_state_ == OMX_StateInvalid || client_state_ == OMX_StateLoaded) { |
456 ShutdownComponent(); | 457 ShutdownComponent(); |
457 return; | 458 return; |
458 } | 459 } |
459 DCHECK(client_state_ == OMX_StateExecuting || | 460 DCHECK(client_state_ == OMX_StateExecuting || |
460 client_state_ == OMX_StateIdle || | 461 client_state_ == OMX_StateIdle || |
461 client_state_ == OMX_StatePause); | 462 client_state_ == OMX_StatePause); |
462 current_state_change_ = DESTROYING; | 463 current_state_change_ = DESTROYING; |
463 client_ = NULL; | 464 client_ = NULL; |
464 BeginTransitionToState(OMX_StateIdle); | 465 BeginTransitionToState(OMX_StateIdle); |
465 BusyLoopInDestroying(); | 466 BusyLoopInDestroying(self.Pass()); |
466 } | 467 } |
467 | 468 |
468 void OmxVideoDecodeAccelerator::BeginTransitionToState( | 469 void OmxVideoDecodeAccelerator::BeginTransitionToState( |
469 OMX_STATETYPE new_state) { | 470 OMX_STATETYPE new_state) { |
470 DCHECK_EQ(message_loop_, MessageLoop::current()); | 471 DCHECK_EQ(message_loop_, MessageLoop::current()); |
471 DCHECK_NE(current_state_change_, NO_TRANSITION); | 472 DCHECK_NE(current_state_change_, NO_TRANSITION); |
472 DCHECK_NE(current_state_change_, ERRORING); | 473 DCHECK_NE(current_state_change_, ERRORING); |
473 if (current_state_change_ == NO_TRANSITION || | 474 if (current_state_change_ == NO_TRANSITION || |
474 current_state_change_ == ERRORING) { | 475 current_state_change_ == ERRORING) { |
475 return; | 476 return; |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
555 client_->NotifyResetDone(); | 556 client_->NotifyResetDone(); |
556 } | 557 } |
557 | 558 |
558 // Alert: HORROR ahead! OMX shutdown is an asynchronous dance but our clients | 559 // 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 | 560 // enjoy the fire-and-forget nature of a synchronous Destroy() call that |
560 // ensures no further callbacks are made. Since the interface between OMX | 561 // 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 | 562 // 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 | 563 // outlives the shutdown dance, even during process shutdown. We do this by |
563 // repeatedly enqueuing a no-op task until shutdown is complete, since | 564 // repeatedly enqueuing a no-op task until shutdown is complete, since |
564 // MessageLoop's shutdown drains pending tasks. | 565 // MessageLoop's shutdown drains pending tasks. |
565 void OmxVideoDecodeAccelerator::BusyLoopInDestroying() { | 566 void OmxVideoDecodeAccelerator::BusyLoopInDestroying( |
| 567 scoped_ptr<VideoDecodeAccelerator> self) { |
566 if (!component_handle_) return; | 568 if (!component_handle_) return; |
567 // Can't use PostDelayedTask here because MessageLoop doesn't drain delayed | 569 // Can't use PostDelayedTask here because MessageLoop doesn't drain delayed |
568 // tasks. Instead we sleep for 5ms. Really. | 570 // tasks. Instead we sleep for 5ms. Really. |
569 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(5)); | 571 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(5)); |
570 message_loop_->PostTask( | 572 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
571 FROM_HERE, base::Bind( | 573 &OmxVideoDecodeAccelerator::BusyLoopInDestroying, |
572 &OmxVideoDecodeAccelerator::BusyLoopInDestroying, this)); | 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 decoder->weak_this(), 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, decoder->weak_this(), |
| 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, decoder->weak_this(), |
| 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 |