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" |
11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
12 #include "content/common/gpu/gpu_channel.h" | 12 #include "content/common/gpu/gpu_channel.h" |
13 #include "content/common/gpu/media/gles2_texture_to_egl_image_translator.h" | 13 #include "content/common/gpu/media/gles2_texture_to_egl_image_translator.h" |
14 #include "media/base/bitstream_buffer.h" | 14 #include "media/base/bitstream_buffer.h" |
15 #include "media/video/picture.h" | 15 #include "media/video/picture.h" |
16 | 16 |
17 // Helper typedef for input buffers. This is used as the pAppPrivate field of | 17 // Helper typedef for input buffers. This is used as the pAppPrivate field of |
18 // OMX_BUFFERHEADERTYPEs of input buffers, to point to the data associated with | 18 // OMX_BUFFERHEADERTYPEs of input buffers, to point to the data associated with |
19 // them. | 19 // them. |
20 typedef std::pair<scoped_ptr<base::SharedMemory>, int32> SharedMemoryAndId; | 20 typedef std::pair<scoped_ptr<base::SharedMemory>, int32> SharedMemoryAndId; |
21 | 21 |
22 enum { kNumPictureBuffers = 4 }; | 22 enum { kNumPictureBuffers = 4 }; |
23 | 23 |
24 // Open the libnvomx here for now. | 24 // Open the libOmxCore here for now. |
25 void* omx_handle = dlopen("libnvomx.so", RTLD_NOW); | 25 void* omx_handle = dlopen("libOmxCore.so", RTLD_NOW); |
26 | 26 |
27 typedef OMX_ERRORTYPE (*OMXInit)(); | 27 typedef OMX_ERRORTYPE (*OMXInit)(); |
28 typedef OMX_ERRORTYPE (*OMXGetHandle)( | 28 typedef OMX_ERRORTYPE (*OMXGetHandle)( |
29 OMX_HANDLETYPE*, OMX_STRING, OMX_PTR, OMX_CALLBACKTYPE*); | 29 OMX_HANDLETYPE*, OMX_STRING, OMX_PTR, OMX_CALLBACKTYPE*); |
30 typedef OMX_ERRORTYPE (*OMXGetComponentsOfRole)(OMX_STRING, OMX_U32*, OMX_U8**); | 30 typedef OMX_ERRORTYPE (*OMXGetComponentsOfRole)(OMX_STRING, OMX_U32*, OMX_U8**); |
31 typedef OMX_ERRORTYPE (*OMXFreeHandle)(OMX_HANDLETYPE); | 31 typedef OMX_ERRORTYPE (*OMXFreeHandle)(OMX_HANDLETYPE); |
32 typedef OMX_ERRORTYPE (*OMXDeinit)(); | 32 typedef OMX_ERRORTYPE (*OMXDeinit)(); |
33 | 33 |
34 OMXInit omx_init = reinterpret_cast<OMXInit>(dlsym(omx_handle, "OMX_Init")); | 34 OMXInit omx_init = reinterpret_cast<OMXInit>(dlsym(omx_handle, "OMX_Init")); |
35 OMXGetHandle omx_gethandle = | 35 OMXGetHandle omx_gethandle = |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 | 153 |
154 if (!CreateComponent()) // Does its own RETURN_ON_FAILURE dances. | 154 if (!CreateComponent()) // Does its own RETURN_ON_FAILURE dances. |
155 return false; | 155 return false; |
156 | 156 |
157 DCHECK_EQ(current_state_change_, NO_TRANSITION); | 157 DCHECK_EQ(current_state_change_, NO_TRANSITION); |
158 current_state_change_ = INITIALIZING; | 158 current_state_change_ = INITIALIZING; |
159 BeginTransitionToState(OMX_StateIdle); | 159 BeginTransitionToState(OMX_StateIdle); |
160 | 160 |
161 if (!AllocateInputBuffers()) // Does its own RETURN_ON_FAILURE dances. | 161 if (!AllocateInputBuffers()) // Does its own RETURN_ON_FAILURE dances. |
162 return false; | 162 return false; |
| 163 if (!AllocateFakeOutputBuffers()) // Does its own RETURN_ON_FAILURE dances. |
| 164 return false; |
163 | 165 |
164 return true; | 166 return true; |
165 } | 167 } |
166 | 168 |
167 bool OmxVideoDecodeAccelerator::CreateComponent() { | 169 bool OmxVideoDecodeAccelerator::CreateComponent() { |
168 DCHECK_EQ(message_loop_, MessageLoop::current()); | 170 DCHECK_EQ(message_loop_, MessageLoop::current()); |
169 OMX_CALLBACKTYPE omx_accelerator_callbacks = { | 171 OMX_CALLBACKTYPE omx_accelerator_callbacks = { |
170 &OmxVideoDecodeAccelerator::EventHandler, | 172 &OmxVideoDecodeAccelerator::EventHandler, |
171 &OmxVideoDecodeAccelerator::EmptyBufferCallback, | 173 &OmxVideoDecodeAccelerator::EmptyBufferCallback, |
172 &OmxVideoDecodeAccelerator::FillBufferCallback | 174 &OmxVideoDecodeAccelerator::FillBufferCallback |
(...skipping 19 matching lines...) Expand all Loading... |
192 this, &omx_accelerator_callbacks); | 194 this, &omx_accelerator_callbacks); |
193 RETURN_ON_OMX_FAILURE(result, | 195 RETURN_ON_OMX_FAILURE(result, |
194 "Failed to OMX_GetHandle on: " << component.get(), | 196 "Failed to OMX_GetHandle on: " << component.get(), |
195 PLATFORM_FAILURE, false); | 197 PLATFORM_FAILURE, false); |
196 client_state_ = OMX_StateLoaded; | 198 client_state_ = OMX_StateLoaded; |
197 | 199 |
198 component_name_is_nvidia_h264ext_ = !strcmp( | 200 component_name_is_nvidia_h264ext_ = !strcmp( |
199 reinterpret_cast<char *>(component.get()), | 201 reinterpret_cast<char *>(component.get()), |
200 "OMX.Nvidia.h264ext.decode"); | 202 "OMX.Nvidia.h264ext.decode"); |
201 | 203 |
| 204 bool component_name_is_sec_h264ext = !strcmp( |
| 205 reinterpret_cast<char *>(component.get()), |
| 206 "OMX.SEC.AVC.Decoder"); |
| 207 Gles2TextureToEglImageTranslator* texture_to_egl_image_translator = |
| 208 new Gles2TextureToEglImageTranslator(component_name_is_sec_h264ext); |
| 209 texture_to_egl_image_translator_.reset(texture_to_egl_image_translator); |
| 210 |
202 // Get the port information. This will obtain information about the number of | 211 // Get the port information. This will obtain information about the number of |
203 // ports and index of the first port. | 212 // ports and index of the first port. |
204 OMX_PORT_PARAM_TYPE port_param; | 213 OMX_PORT_PARAM_TYPE port_param; |
205 InitParam(*this, &port_param); | 214 InitParam(*this, &port_param); |
206 result = OMX_GetParameter(component_handle_, OMX_IndexParamVideoInit, | 215 result = OMX_GetParameter(component_handle_, OMX_IndexParamVideoInit, |
207 &port_param); | 216 &port_param); |
208 RETURN_ON_FAILURE(result == OMX_ErrorNone && port_param.nPorts == 2, | 217 RETURN_ON_FAILURE(result == OMX_ErrorNone && port_param.nPorts == 2, |
209 "Failed to get Port Param: " << result << ", " | 218 "Failed to get Port Param: " << result << ", " |
210 << port_param.nPorts, | 219 << port_param.nPorts, |
211 PLATFORM_FAILURE, false); | 220 PLATFORM_FAILURE, false); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
260 // stream's real dimensions (which can only happen once some Decode() work has | 269 // stream's real dimensions (which can only happen once some Decode() work has |
261 // been done). | 270 // been done). |
262 port_format.format.video.nFrameWidth = -1; | 271 port_format.format.video.nFrameWidth = -1; |
263 port_format.format.video.nFrameHeight = -1; | 272 port_format.format.video.nFrameHeight = -1; |
264 result = OMX_SetParameter(component_handle_, | 273 result = OMX_SetParameter(component_handle_, |
265 OMX_IndexParamPortDefinition, | 274 OMX_IndexParamPortDefinition, |
266 &port_format); | 275 &port_format); |
267 RETURN_ON_OMX_FAILURE(result, | 276 RETURN_ON_OMX_FAILURE(result, |
268 "SetParameter(OMX_IndexParamPortDefinition) failed", | 277 "SetParameter(OMX_IndexParamPortDefinition) failed", |
269 PLATFORM_FAILURE, false); | 278 PLATFORM_FAILURE, false); |
270 | |
271 // Fill the component with fake output buffers. This seems to be required for | |
272 // the component to move from Loaded to Idle. How bogus. | |
273 for (int i = 0; i < kNumPictureBuffers; ++i) { | |
274 OMX_BUFFERHEADERTYPE* buffer; | |
275 result = OMX_UseBuffer(component_handle_, &buffer, output_port_, | |
276 NULL, 0, reinterpret_cast<OMX_U8*>(0x1)); | |
277 RETURN_ON_OMX_FAILURE(result, "OMX_UseBuffer failed", | |
278 PLATFORM_FAILURE, false); | |
279 buffer->pAppPrivate = NULL; | |
280 buffer->nTimeStamp = -1; | |
281 buffer->nOutputPortIndex = output_port_; | |
282 CHECK(fake_output_buffers_.insert(buffer).second); | |
283 } | |
284 return true; | 279 return true; |
285 } | 280 } |
286 | 281 |
287 void OmxVideoDecodeAccelerator::Decode( | 282 void OmxVideoDecodeAccelerator::Decode( |
288 const media::BitstreamBuffer& bitstream_buffer) { | 283 const media::BitstreamBuffer& bitstream_buffer) { |
289 TRACE_EVENT1("Video Decoder", "OVDA::Decode", | 284 TRACE_EVENT1("Video Decoder", "OVDA::Decode", |
290 "Buffer id", bitstream_buffer.id()); | 285 "Buffer id", bitstream_buffer.id()); |
291 DCHECK_EQ(message_loop_, MessageLoop::current()); | 286 DCHECK_EQ(message_loop_, MessageLoop::current()); |
292 | 287 |
293 if (current_state_change_ == RESETTING || | 288 if (current_state_change_ == RESETTING || |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 | 332 |
338 void OmxVideoDecodeAccelerator::AssignPictureBuffers( | 333 void OmxVideoDecodeAccelerator::AssignPictureBuffers( |
339 const std::vector<media::PictureBuffer>& buffers) { | 334 const std::vector<media::PictureBuffer>& buffers) { |
340 DCHECK_EQ(message_loop_, MessageLoop::current()); | 335 DCHECK_EQ(message_loop_, MessageLoop::current()); |
341 RETURN_ON_FAILURE(CanFillBuffer(), "Can't fill buffer", ILLEGAL_STATE,); | 336 RETURN_ON_FAILURE(CanFillBuffer(), "Can't fill buffer", ILLEGAL_STATE,); |
342 | 337 |
343 DCHECK_EQ(output_buffers_at_component_, 0); | 338 DCHECK_EQ(output_buffers_at_component_, 0); |
344 DCHECK_EQ(fake_output_buffers_.size(), 0U); | 339 DCHECK_EQ(fake_output_buffers_.size(), 0U); |
345 DCHECK_EQ(pictures_.size(), 0U); | 340 DCHECK_EQ(pictures_.size(), 0U); |
346 | 341 |
347 static Gles2TextureToEglImageTranslator texture2eglImage_translator; | |
348 for (size_t i = 0; i < buffers.size(); ++i) { | 342 for (size_t i = 0; i < buffers.size(); ++i) { |
349 EGLImageKHR egl_image = texture2eglImage_translator.TranslateToEglImage( | 343 EGLImageKHR egl_image = |
350 egl_display_, egl_context_, buffers[i].texture_id()); | 344 texture_to_egl_image_translator_->TranslateToEglImage( |
| 345 egl_display_, egl_context_, |
| 346 buffers[i].texture_id(), |
| 347 last_requested_picture_buffer_dimensions_); |
351 CHECK(pictures_.insert(std::make_pair( | 348 CHECK(pictures_.insert(std::make_pair( |
352 buffers[i].id(), OutputPicture(buffers[i], NULL, egl_image))).second); | 349 buffers[i].id(), OutputPicture(buffers[i], NULL, egl_image))).second); |
353 } | 350 } |
354 | 351 |
355 if (pictures_.size() < kNumPictureBuffers) | 352 if (pictures_.size() < kNumPictureBuffers) |
356 return; // get all the buffers first. | 353 return; // get all the buffers first. |
357 DCHECK_EQ(pictures_.size(), kNumPictureBuffers); | 354 DCHECK_EQ(pictures_.size(), kNumPictureBuffers); |
358 | 355 |
359 // These do their own RETURN_ON_FAILURE dances. | 356 // These do their own RETURN_ON_FAILURE dances. |
360 if (!AllocateOutputBuffers()) | 357 if (!AllocateOutputBuffers()) |
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
650 RETURN_ON_OMX_FAILURE(result, "OMX_UseBuffer() Input buffer error", | 647 RETURN_ON_OMX_FAILURE(result, "OMX_UseBuffer() Input buffer error", |
651 PLATFORM_FAILURE, false); | 648 PLATFORM_FAILURE, false); |
652 buffer->nInputPortIndex = input_port_; | 649 buffer->nInputPortIndex = input_port_; |
653 buffer->nOffset = 0; | 650 buffer->nOffset = 0; |
654 buffer->nFlags = 0; | 651 buffer->nFlags = 0; |
655 free_input_buffers_.push(buffer); | 652 free_input_buffers_.push(buffer); |
656 } | 653 } |
657 return true; | 654 return true; |
658 } | 655 } |
659 | 656 |
| 657 bool OmxVideoDecodeAccelerator::AllocateFakeOutputBuffers() { |
| 658 // Fill the component with fake output buffers. |
| 659 for (unsigned int i = 0; i < kNumPictureBuffers; ++i) { |
| 660 OMX_BUFFERHEADERTYPE* buffer; |
| 661 OMX_ERRORTYPE result; |
| 662 result = OMX_AllocateBuffer(component_handle_, &buffer, output_port_, |
| 663 NULL, 0); |
| 664 RETURN_ON_OMX_FAILURE(result, "OMX_AllocateBuffer failed", |
| 665 PLATFORM_FAILURE, false); |
| 666 buffer->pAppPrivate = NULL; |
| 667 buffer->nTimeStamp = -1; |
| 668 buffer->nOutputPortIndex = output_port_; |
| 669 CHECK(fake_output_buffers_.insert(buffer).second); |
| 670 } |
| 671 return true; |
| 672 } |
| 673 |
660 bool OmxVideoDecodeAccelerator::AllocateOutputBuffers() { | 674 bool OmxVideoDecodeAccelerator::AllocateOutputBuffers() { |
661 DCHECK_EQ(message_loop_, MessageLoop::current()); | 675 DCHECK_EQ(message_loop_, MessageLoop::current()); |
662 | 676 |
663 DCHECK(!pictures_.empty()); | 677 DCHECK(!pictures_.empty()); |
664 for (OutputPictureById::iterator it = pictures_.begin(); | 678 for (OutputPictureById::iterator it = pictures_.begin(); |
665 it != pictures_.end(); ++it) { | 679 it != pictures_.end(); ++it) { |
666 media::PictureBuffer& picture_buffer = it->second.picture_buffer; | 680 media::PictureBuffer& picture_buffer = it->second.picture_buffer; |
667 OMX_BUFFERHEADERTYPE** omx_buffer = &it->second.omx_buffer_header; | 681 OMX_BUFFERHEADERTYPE** omx_buffer = &it->second.omx_buffer_header; |
668 DCHECK(!*omx_buffer); | 682 DCHECK(!*omx_buffer); |
669 OMX_ERRORTYPE result = OMX_UseEGLImage( | 683 OMX_ERRORTYPE result = OMX_UseEGLImage( |
(...skipping 19 matching lines...) Expand all Loading... |
689 free_input_buffers_.pop(); | 703 free_input_buffers_.pop(); |
690 result = OMX_FreeBuffer(component_handle_, input_port_, omx_buffer); | 704 result = OMX_FreeBuffer(component_handle_, input_port_, omx_buffer); |
691 RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer", PLATFORM_FAILURE,); | 705 RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer", PLATFORM_FAILURE,); |
692 } | 706 } |
693 } | 707 } |
694 | 708 |
695 void OmxVideoDecodeAccelerator::FreeOutputBuffers() { | 709 void OmxVideoDecodeAccelerator::FreeOutputBuffers() { |
696 DCHECK_EQ(message_loop_, MessageLoop::current()); | 710 DCHECK_EQ(message_loop_, MessageLoop::current()); |
697 // Calls to OMX to free buffers. | 711 // Calls to OMX to free buffers. |
698 OMX_ERRORTYPE result; | 712 OMX_ERRORTYPE result; |
699 static Gles2TextureToEglImageTranslator texture2eglImage_translator; | |
700 for (OutputPictureById::iterator it = pictures_.begin(); | 713 for (OutputPictureById::iterator it = pictures_.begin(); |
701 it != pictures_.end(); ++it) { | 714 it != pictures_.end(); ++it) { |
702 OMX_BUFFERHEADERTYPE* omx_buffer = it->second.omx_buffer_header; | 715 OMX_BUFFERHEADERTYPE* omx_buffer = it->second.omx_buffer_header; |
703 DCHECK(omx_buffer); | 716 DCHECK(omx_buffer); |
704 delete reinterpret_cast<media::Picture*>(omx_buffer->pAppPrivate); | 717 delete reinterpret_cast<media::Picture*>(omx_buffer->pAppPrivate); |
705 result = OMX_FreeBuffer(component_handle_, output_port_, omx_buffer); | 718 result = OMX_FreeBuffer(component_handle_, output_port_, omx_buffer); |
706 RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer", PLATFORM_FAILURE,); | 719 RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer", PLATFORM_FAILURE,); |
707 texture2eglImage_translator.DestroyEglImage(egl_display_, | 720 texture_to_egl_image_translator_->DestroyEglImage(egl_display_, |
708 it->second.egl_image); | 721 it->second.egl_image); |
709 if (client_) | 722 if (client_) |
710 client_->DismissPictureBuffer(it->first); | 723 client_->DismissPictureBuffer(it->first); |
711 } | 724 } |
712 pictures_.clear(); | 725 pictures_.clear(); |
713 } | 726 } |
714 | 727 |
715 void OmxVideoDecodeAccelerator::OnOutputPortDisabled() { | 728 void OmxVideoDecodeAccelerator::OnOutputPortDisabled() { |
716 DCHECK_EQ(message_loop_, MessageLoop::current()); | 729 DCHECK_EQ(message_loop_, MessageLoop::current()); |
717 OMX_PARAM_PORTDEFINITIONTYPE port_format; | 730 OMX_PARAM_PORTDEFINITIONTYPE port_format; |
718 InitParam(*this, &port_format); | 731 InitParam(*this, &port_format); |
719 port_format.nPortIndex = output_port_; | 732 port_format.nPortIndex = output_port_; |
720 OMX_ERRORTYPE result = OMX_GetParameter( | 733 OMX_ERRORTYPE result = OMX_GetParameter( |
721 component_handle_, OMX_IndexParamPortDefinition, &port_format); | 734 component_handle_, OMX_IndexParamPortDefinition, &port_format); |
722 RETURN_ON_OMX_FAILURE(result, "OMX_GetParameter", PLATFORM_FAILURE,); | 735 RETURN_ON_OMX_FAILURE(result, "OMX_GetParameter", PLATFORM_FAILURE,); |
723 DCHECK_EQ(port_format.nBufferCountMin, kNumPictureBuffers); | 736 DCHECK_EQ(port_format.nBufferCountMin, kNumPictureBuffers); |
724 | 737 |
725 // TODO(fischman): to support mid-stream resize, need to free/dismiss any | 738 // TODO(fischman): to support mid-stream resize, need to free/dismiss any |
726 // |pictures_| we already have. Make sure that the shutdown-path agrees with | 739 // |pictures_| we already have. Make sure that the shutdown-path agrees with |
727 // this (there's already freeing logic there, which should not be duplicated). | 740 // this (there's already freeing logic there, which should not be duplicated). |
728 | 741 |
729 // Request picture buffers to be handed to the component. | 742 // Request picture buffers to be handed to the component. |
730 // ProvidePictureBuffers() will trigger AssignPictureBuffers, which ultimately | 743 // ProvidePictureBuffers() will trigger AssignPictureBuffers, which ultimately |
731 // assigns the textures to the component and re-enables the port. | 744 // assigns the textures to the component and re-enables the port. |
732 const OMX_VIDEO_PORTDEFINITIONTYPE& vformat = port_format.format.video; | 745 const OMX_VIDEO_PORTDEFINITIONTYPE& vformat = port_format.format.video; |
| 746 last_requested_picture_buffer_dimensions_.SetSize(vformat.nFrameWidth, |
| 747 vformat.nFrameHeight); |
733 if (client_) { | 748 if (client_) { |
734 client_->ProvidePictureBuffers( | 749 client_->ProvidePictureBuffers( |
735 kNumPictureBuffers, | 750 kNumPictureBuffers, |
736 gfx::Size(vformat.nFrameWidth, vformat.nFrameHeight)); | 751 gfx::Size(vformat.nFrameWidth, vformat.nFrameHeight)); |
737 } | 752 } |
738 } | 753 } |
739 | 754 |
740 void OmxVideoDecodeAccelerator::OnOutputPortEnabled() { | 755 void OmxVideoDecodeAccelerator::OnOutputPortEnabled() { |
741 DCHECK_EQ(message_loop_, MessageLoop::current()); | 756 DCHECK_EQ(message_loop_, MessageLoop::current()); |
742 | 757 |
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1033 | 1048 |
1034 bool OmxVideoDecodeAccelerator::SendCommandToPort( | 1049 bool OmxVideoDecodeAccelerator::SendCommandToPort( |
1035 OMX_COMMANDTYPE cmd, int port_index) { | 1050 OMX_COMMANDTYPE cmd, int port_index) { |
1036 DCHECK_EQ(message_loop_, MessageLoop::current()); | 1051 DCHECK_EQ(message_loop_, MessageLoop::current()); |
1037 OMX_ERRORTYPE result = OMX_SendCommand(component_handle_, | 1052 OMX_ERRORTYPE result = OMX_SendCommand(component_handle_, |
1038 cmd, port_index, 0); | 1053 cmd, port_index, 0); |
1039 RETURN_ON_OMX_FAILURE(result, "SendCommand() failed" << cmd, | 1054 RETURN_ON_OMX_FAILURE(result, "SendCommand() failed" << cmd, |
1040 PLATFORM_FAILURE, false); | 1055 PLATFORM_FAILURE, false); |
1041 return true; | 1056 return true; |
1042 } | 1057 } |
OLD | NEW |