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 = 8 }; | 22 enum { kNumPictureBuffers = 8 }; |
23 | 23 |
| 24 // Delay between polling for texture sync status. 5ms feels like a good |
| 25 // compromise, allowing some decoding ahead (up to 3 frames/vsync) to compensate |
| 26 // for more difficult frames. |
| 27 enum { kSyncPollDelayMs = 5 }; |
| 28 |
24 void* omx_handle = NULL; | 29 void* omx_handle = NULL; |
25 | 30 |
26 typedef OMX_ERRORTYPE (*OMXInit)(); | 31 typedef OMX_ERRORTYPE (*OMXInit)(); |
27 typedef OMX_ERRORTYPE (*OMXGetHandle)( | 32 typedef OMX_ERRORTYPE (*OMXGetHandle)( |
28 OMX_HANDLETYPE*, OMX_STRING, OMX_PTR, OMX_CALLBACKTYPE*); | 33 OMX_HANDLETYPE*, OMX_STRING, OMX_PTR, OMX_CALLBACKTYPE*); |
29 typedef OMX_ERRORTYPE (*OMXGetComponentsOfRole)(OMX_STRING, OMX_U32*, OMX_U8**); | 34 typedef OMX_ERRORTYPE (*OMXGetComponentsOfRole)(OMX_STRING, OMX_U32*, OMX_U8**); |
30 typedef OMX_ERRORTYPE (*OMXFreeHandle)(OMX_HANDLETYPE); | 35 typedef OMX_ERRORTYPE (*OMXFreeHandle)(OMX_HANDLETYPE); |
31 typedef OMX_ERRORTYPE (*OMXDeinit)(); | 36 typedef OMX_ERRORTYPE (*OMXDeinit)(); |
32 | 37 |
33 OMXInit omx_init = NULL; | 38 OMXInit omx_init = NULL; |
34 OMXGetHandle omx_gethandle = NULL; | 39 OMXGetHandle omx_gethandle = NULL; |
35 OMXGetComponentsOfRole omx_get_components_of_role = NULL; | 40 OMXGetComponentsOfRole omx_get_components_of_role = NULL; |
36 OMXFreeHandle omx_free_handle = NULL; | 41 OMXFreeHandle omx_free_handle = NULL; |
37 OMXDeinit omx_deinit = NULL; | 42 OMXDeinit omx_deinit = NULL; |
38 | 43 |
| 44 static PFNEGLCREATESYNCKHRPROC egl_create_sync_khr = NULL; |
| 45 static PFNEGLGETSYNCATTRIBKHRPROC egl_get_sync_attrib_khr = NULL; |
| 46 static PFNEGLDESTROYSYNCKHRPROC egl_destroy_sync_khr = NULL; |
| 47 |
39 // Maps h264-related Profile enum values to OMX_VIDEO_AVCPROFILETYPE values. | 48 // Maps h264-related Profile enum values to OMX_VIDEO_AVCPROFILETYPE values. |
40 static OMX_U32 MapH264ProfileToOMXAVCProfile(uint32 profile) { | 49 static OMX_U32 MapH264ProfileToOMXAVCProfile(uint32 profile) { |
41 switch (profile) { | 50 switch (profile) { |
42 case media::H264PROFILE_BASELINE: | 51 case media::H264PROFILE_BASELINE: |
43 return OMX_VIDEO_AVCProfileBaseline; | 52 return OMX_VIDEO_AVCProfileBaseline; |
44 case media::H264PROFILE_MAIN: | 53 case media::H264PROFILE_MAIN: |
45 return OMX_VIDEO_AVCProfileMain; | 54 return OMX_VIDEO_AVCProfileMain; |
46 case media::H264PROFILE_EXTENDED: | 55 case media::H264PROFILE_EXTENDED: |
47 return OMX_VIDEO_AVCProfileExtended; | 56 return OMX_VIDEO_AVCProfileExtended; |
48 case media::H264PROFILE_HIGH: | 57 case media::H264PROFILE_HIGH: |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 // OMX-specific version of RETURN_ON_FAILURE which compares with OMX_ErrorNone. | 91 // OMX-specific version of RETURN_ON_FAILURE which compares with OMX_ErrorNone. |
83 #define RETURN_ON_OMX_FAILURE(omx_result, log, error, ret_val) \ | 92 #define RETURN_ON_OMX_FAILURE(omx_result, log, error, ret_val) \ |
84 RETURN_ON_FAILURE( \ | 93 RETURN_ON_FAILURE( \ |
85 ((omx_result) == OMX_ErrorNone), \ | 94 ((omx_result) == OMX_ErrorNone), \ |
86 log << ", OMX result: 0x" << std::hex << omx_result, \ | 95 log << ", OMX result: 0x" << std::hex << omx_result, \ |
87 error, ret_val) | 96 error, ret_val) |
88 | 97 |
89 // static | 98 // static |
90 bool OmxVideoDecodeAccelerator::pre_sandbox_init_done_ = false; | 99 bool OmxVideoDecodeAccelerator::pre_sandbox_init_done_ = false; |
91 | 100 |
| 101 class OmxVideoDecodeAccelerator::PictureSyncObject { |
| 102 public: |
| 103 // Create a sync object and insert into the GPU command stream. |
| 104 PictureSyncObject(EGLDisplay egl_display); |
| 105 ~PictureSyncObject(); |
| 106 |
| 107 bool IsSynced(); |
| 108 |
| 109 private: |
| 110 EGLSyncKHR egl_sync_obj_; |
| 111 EGLDisplay egl_display_; |
| 112 }; |
| 113 |
| 114 OmxVideoDecodeAccelerator::PictureSyncObject::PictureSyncObject( |
| 115 EGLDisplay egl_display) |
| 116 : egl_display_(egl_display) { |
| 117 DCHECK(egl_display_ != EGL_NO_DISPLAY); |
| 118 |
| 119 egl_sync_obj_ = egl_create_sync_khr(egl_display_, EGL_SYNC_FENCE_KHR, NULL); |
| 120 DCHECK_NE(egl_sync_obj_, EGL_NO_SYNC_KHR); |
| 121 } |
| 122 |
| 123 OmxVideoDecodeAccelerator::PictureSyncObject::~PictureSyncObject() { |
| 124 egl_destroy_sync_khr(egl_display_, egl_sync_obj_); |
| 125 } |
| 126 |
| 127 bool OmxVideoDecodeAccelerator::PictureSyncObject::IsSynced() { |
| 128 EGLint value = EGL_UNSIGNALED_KHR; |
| 129 EGLBoolean ret = egl_get_sync_attrib_khr( |
| 130 egl_display_, egl_sync_obj_, EGL_SYNC_STATUS_KHR, &value); |
| 131 DCHECK(ret) << "Failed getting sync object state."; |
| 132 |
| 133 return value == EGL_SIGNALED_KHR; |
| 134 } |
| 135 |
92 OmxVideoDecodeAccelerator::OmxVideoDecodeAccelerator( | 136 OmxVideoDecodeAccelerator::OmxVideoDecodeAccelerator( |
93 EGLDisplay egl_display, EGLContext egl_context, | 137 EGLDisplay egl_display, EGLContext egl_context, |
94 media::VideoDecodeAccelerator::Client* client, | 138 media::VideoDecodeAccelerator::Client* client, |
95 const base::Callback<bool(void)>& make_context_current) | 139 const base::Callback<bool(void)>& make_context_current) |
96 : message_loop_(MessageLoop::current()), | 140 : message_loop_(MessageLoop::current()), |
97 component_handle_(NULL), | 141 component_handle_(NULL), |
98 weak_this_(base::AsWeakPtr(this)), | 142 weak_this_(base::AsWeakPtr(this)), |
99 init_begun_(false), | 143 init_begun_(false), |
100 client_state_(OMX_StateMax), | 144 client_state_(OMX_StateMax), |
101 current_state_change_(NO_TRANSITION), | 145 current_state_change_(NO_TRANSITION), |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 DCHECK_EQ(pictures_.size(), kNumPictureBuffers); | 424 DCHECK_EQ(pictures_.size(), kNumPictureBuffers); |
381 | 425 |
382 // These do their own RETURN_ON_FAILURE dances. | 426 // These do their own RETURN_ON_FAILURE dances. |
383 if (!AllocateOutputBuffers()) | 427 if (!AllocateOutputBuffers()) |
384 return; | 428 return; |
385 if (!SendCommandToPort(OMX_CommandPortEnable, output_port_)) | 429 if (!SendCommandToPort(OMX_CommandPortEnable, output_port_)) |
386 return; | 430 return; |
387 } | 431 } |
388 | 432 |
389 void OmxVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { | 433 void OmxVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { |
| 434 DCHECK_EQ(message_loop_, MessageLoop::current()); |
390 TRACE_EVENT1("Video Decoder", "OVDA::ReusePictureBuffer", | 435 TRACE_EVENT1("Video Decoder", "OVDA::ReusePictureBuffer", |
391 "Picture id", picture_buffer_id); | 436 "Picture id", picture_buffer_id); |
| 437 scoped_ptr<PictureSyncObject> egl_sync_obj( |
| 438 new PictureSyncObject(egl_display_)); |
| 439 |
| 440 // Start checking sync status periodically. |
| 441 CheckPictureStatus(picture_buffer_id, egl_sync_obj.Pass()); |
| 442 } |
| 443 |
| 444 void OmxVideoDecodeAccelerator::CheckPictureStatus( |
| 445 int32 picture_buffer_id, |
| 446 scoped_ptr<PictureSyncObject> egl_sync_obj) { |
| 447 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 448 |
| 449 // It's possible for this task to never run if the message loop is |
| 450 // stopped. In that case we may never call QueuePictureBuffer(). |
| 451 // This is fine though, because all pictures, irrespective of their state, |
| 452 // are in pictures_ map and that's what will be used to do the clean up. |
| 453 if (!egl_sync_obj->IsSynced()) { |
| 454 MessageLoop::current()->PostDelayedTask(FROM_HERE, base::Bind( |
| 455 &OmxVideoDecodeAccelerator::CheckPictureStatus, weak_this_, |
| 456 picture_buffer_id, base::Passed(&egl_sync_obj)), |
| 457 base::TimeDelta::FromMilliseconds(kSyncPollDelayMs)); |
| 458 return; |
| 459 } |
| 460 |
| 461 // Synced successfully. Queue the buffer for reuse. |
| 462 QueuePictureBuffer(picture_buffer_id); |
| 463 } |
| 464 |
| 465 void OmxVideoDecodeAccelerator::QueuePictureBuffer(int32 picture_buffer_id) { |
392 DCHECK_EQ(message_loop_, MessageLoop::current()); | 466 DCHECK_EQ(message_loop_, MessageLoop::current()); |
393 | 467 |
394 // During port-flushing, do not call OMX FillThisBuffer. | 468 // During port-flushing, do not call OMX FillThisBuffer. |
395 if (current_state_change_ == RESETTING) { | 469 if (current_state_change_ == RESETTING) { |
396 queued_picture_buffer_ids_.push_back(picture_buffer_id); | 470 queued_picture_buffer_ids_.push_back(picture_buffer_id); |
397 return; | 471 return; |
398 } | 472 } |
399 | 473 |
400 RETURN_ON_FAILURE(CanFillBuffer(), "Can't fill buffer", ILLEGAL_STATE,); | 474 // We might have started destroying while waiting for the picture. It's safe |
| 475 // to drop it here, because we will free all the pictures regardless of their |
| 476 // state using the pictures_ map. |
| 477 if (!CanFillBuffer()) |
| 478 return; |
401 | 479 |
402 OutputPictureById::iterator it = pictures_.find(picture_buffer_id); | 480 OutputPictureById::iterator it = pictures_.find(picture_buffer_id); |
403 RETURN_ON_FAILURE(it != pictures_.end(), | 481 RETURN_ON_FAILURE(it != pictures_.end(), |
404 "Missing picture buffer id: " << picture_buffer_id, | 482 "Missing picture buffer id: " << picture_buffer_id, |
405 INVALID_ARGUMENT,); | 483 INVALID_ARGUMENT,); |
406 OutputPicture& output_picture = it->second; | 484 OutputPicture& output_picture = it->second; |
407 | 485 |
408 ++output_buffers_at_component_; | 486 ++output_buffers_at_component_; |
409 OMX_ERRORTYPE result = | 487 OMX_ERRORTYPE result = |
410 OMX_FillThisBuffer(component_handle_, output_picture.omx_buffer_header); | 488 OMX_FillThisBuffer(component_handle_, output_picture.omx_buffer_header); |
(...skipping 673 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1084 omx_init = reinterpret_cast<OMXInit>(dlsym(omx_handle, "OMX_Init")); | 1162 omx_init = reinterpret_cast<OMXInit>(dlsym(omx_handle, "OMX_Init")); |
1085 omx_gethandle = | 1163 omx_gethandle = |
1086 reinterpret_cast<OMXGetHandle>(dlsym(omx_handle, "OMX_GetHandle")); | 1164 reinterpret_cast<OMXGetHandle>(dlsym(omx_handle, "OMX_GetHandle")); |
1087 omx_get_components_of_role = | 1165 omx_get_components_of_role = |
1088 reinterpret_cast<OMXGetComponentsOfRole>( | 1166 reinterpret_cast<OMXGetComponentsOfRole>( |
1089 dlsym(omx_handle, "OMX_GetComponentsOfRole")); | 1167 dlsym(omx_handle, "OMX_GetComponentsOfRole")); |
1090 omx_free_handle = | 1168 omx_free_handle = |
1091 reinterpret_cast<OMXFreeHandle>(dlsym(omx_handle, "OMX_FreeHandle")); | 1169 reinterpret_cast<OMXFreeHandle>(dlsym(omx_handle, "OMX_FreeHandle")); |
1092 omx_deinit = | 1170 omx_deinit = |
1093 reinterpret_cast<OMXDeinit>(dlsym(omx_handle, "OMX_Deinit")); | 1171 reinterpret_cast<OMXDeinit>(dlsym(omx_handle, "OMX_Deinit")); |
| 1172 |
| 1173 egl_create_sync_khr = reinterpret_cast<PFNEGLCREATESYNCKHRPROC>( |
| 1174 eglGetProcAddress("eglCreateSyncKHR")); |
| 1175 egl_get_sync_attrib_khr = reinterpret_cast<PFNEGLGETSYNCATTRIBKHRPROC>( |
| 1176 eglGetProcAddress("eglGetSyncAttribKHR")); |
| 1177 egl_destroy_sync_khr = reinterpret_cast<PFNEGLDESTROYSYNCKHRPROC>( |
| 1178 eglGetProcAddress("eglDestroySyncKHR")); |
| 1179 |
1094 return (omx_init && omx_gethandle && omx_get_components_of_role && | 1180 return (omx_init && omx_gethandle && omx_get_components_of_role && |
1095 omx_free_handle && omx_deinit); | 1181 omx_free_handle && omx_deinit && egl_create_sync_khr && |
| 1182 egl_get_sync_attrib_khr && egl_destroy_sync_khr); |
1096 } | 1183 } |
1097 | 1184 |
1098 // static | 1185 // static |
1099 OMX_ERRORTYPE OmxVideoDecodeAccelerator::EventHandler(OMX_HANDLETYPE component, | 1186 OMX_ERRORTYPE OmxVideoDecodeAccelerator::EventHandler(OMX_HANDLETYPE component, |
1100 OMX_PTR priv_data, | 1187 OMX_PTR priv_data, |
1101 OMX_EVENTTYPE event, | 1188 OMX_EVENTTYPE event, |
1102 OMX_U32 data1, | 1189 OMX_U32 data1, |
1103 OMX_U32 data2, | 1190 OMX_U32 data2, |
1104 OMX_PTR event_data) { | 1191 OMX_PTR event_data) { |
1105 // Called on the OMX thread. | 1192 // Called on the OMX thread. |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1160 | 1247 |
1161 bool OmxVideoDecodeAccelerator::SendCommandToPort( | 1248 bool OmxVideoDecodeAccelerator::SendCommandToPort( |
1162 OMX_COMMANDTYPE cmd, int port_index) { | 1249 OMX_COMMANDTYPE cmd, int port_index) { |
1163 DCHECK_EQ(message_loop_, MessageLoop::current()); | 1250 DCHECK_EQ(message_loop_, MessageLoop::current()); |
1164 OMX_ERRORTYPE result = OMX_SendCommand(component_handle_, | 1251 OMX_ERRORTYPE result = OMX_SendCommand(component_handle_, |
1165 cmd, port_index, 0); | 1252 cmd, port_index, 0); |
1166 RETURN_ON_OMX_FAILURE(result, "SendCommand() failed" << cmd, | 1253 RETURN_ON_OMX_FAILURE(result, "SendCommand() failed" << cmd, |
1167 PLATFORM_FAILURE, false); | 1254 PLATFORM_FAILURE, false); |
1168 return true; | 1255 return true; |
1169 } | 1256 } |
OLD | NEW |