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 enum { kSyncTimeoutNanosec = 50000000 }; | |
23 | 24 |
24 void* omx_handle = NULL; | 25 void* omx_handle = NULL; |
25 | 26 |
26 typedef OMX_ERRORTYPE (*OMXInit)(); | 27 typedef OMX_ERRORTYPE (*OMXInit)(); |
27 typedef OMX_ERRORTYPE (*OMXGetHandle)( | 28 typedef OMX_ERRORTYPE (*OMXGetHandle)( |
28 OMX_HANDLETYPE*, OMX_STRING, OMX_PTR, OMX_CALLBACKTYPE*); | 29 OMX_HANDLETYPE*, OMX_STRING, OMX_PTR, OMX_CALLBACKTYPE*); |
29 typedef OMX_ERRORTYPE (*OMXGetComponentsOfRole)(OMX_STRING, OMX_U32*, OMX_U8**); | 30 typedef OMX_ERRORTYPE (*OMXGetComponentsOfRole)(OMX_STRING, OMX_U32*, OMX_U8**); |
30 typedef OMX_ERRORTYPE (*OMXFreeHandle)(OMX_HANDLETYPE); | 31 typedef OMX_ERRORTYPE (*OMXFreeHandle)(OMX_HANDLETYPE); |
31 typedef OMX_ERRORTYPE (*OMXDeinit)(); | 32 typedef OMX_ERRORTYPE (*OMXDeinit)(); |
32 | 33 |
33 OMXInit omx_init = NULL; | 34 OMXInit omx_init = NULL; |
34 OMXGetHandle omx_gethandle = NULL; | 35 OMXGetHandle omx_gethandle = NULL; |
35 OMXGetComponentsOfRole omx_get_components_of_role = NULL; | 36 OMXGetComponentsOfRole omx_get_components_of_role = NULL; |
36 OMXFreeHandle omx_free_handle = NULL; | 37 OMXFreeHandle omx_free_handle = NULL; |
37 OMXDeinit omx_deinit = NULL; | 38 OMXDeinit omx_deinit = NULL; |
38 | 39 |
40 static PFNEGLCREATESYNCKHRPROC egl_create_sync_khr = | |
41 reinterpret_cast<PFNEGLCREATESYNCKHRPROC>( | |
42 eglGetProcAddress("eglCreateSyncKHR")); | |
piman
2012/10/06 06:42:40
No static initialization. Realize that this code r
Pawel Osciak
2012/10/10 17:37:52
Ok, I was inspired by Gles2TextureToEglImageTransl
| |
43 static PFNEGLCLIENTWAITSYNCKHRPROC egl_client_wait_sync_khr = | |
44 reinterpret_cast<PFNEGLCLIENTWAITSYNCKHRPROC>( | |
45 eglGetProcAddress("eglClientWaitSyncKHR")); | |
46 static PFNEGLDESTROYSYNCKHRPROC egl_destroy_sync_khr = | |
47 reinterpret_cast<PFNEGLDESTROYSYNCKHRPROC>( | |
48 eglGetProcAddress("eglDestroySyncKHR")); | |
49 | |
50 static bool AreEGLExtensionsInitialized() { | |
51 return egl_create_sync_khr && egl_client_wait_sync_khr && | |
52 egl_destroy_sync_khr; | |
53 } | |
54 | |
39 // Maps h264-related Profile enum values to OMX_VIDEO_AVCPROFILETYPE values. | 55 // Maps h264-related Profile enum values to OMX_VIDEO_AVCPROFILETYPE values. |
40 static OMX_U32 MapH264ProfileToOMXAVCProfile(uint32 profile) { | 56 static OMX_U32 MapH264ProfileToOMXAVCProfile(uint32 profile) { |
41 switch (profile) { | 57 switch (profile) { |
42 case media::H264PROFILE_BASELINE: | 58 case media::H264PROFILE_BASELINE: |
43 return OMX_VIDEO_AVCProfileBaseline; | 59 return OMX_VIDEO_AVCProfileBaseline; |
44 case media::H264PROFILE_MAIN: | 60 case media::H264PROFILE_MAIN: |
45 return OMX_VIDEO_AVCProfileMain; | 61 return OMX_VIDEO_AVCProfileMain; |
46 case media::H264PROFILE_EXTENDED: | 62 case media::H264PROFILE_EXTENDED: |
47 return OMX_VIDEO_AVCProfileExtended; | 63 return OMX_VIDEO_AVCProfileExtended; |
48 case media::H264PROFILE_HIGH: | 64 case media::H264PROFILE_HIGH: |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
104 input_port_(0), | 120 input_port_(0), |
105 input_buffers_at_component_(0), | 121 input_buffers_at_component_(0), |
106 output_port_(0), | 122 output_port_(0), |
107 output_buffers_at_component_(0), | 123 output_buffers_at_component_(0), |
108 egl_display_(egl_display), | 124 egl_display_(egl_display), |
109 egl_context_(egl_context), | 125 egl_context_(egl_context), |
110 make_context_current_(make_context_current), | 126 make_context_current_(make_context_current), |
111 client_(client), | 127 client_(client), |
112 codec_(UNKNOWN), | 128 codec_(UNKNOWN), |
113 h264_profile_(OMX_VIDEO_AVCProfileMax), | 129 h264_profile_(OMX_VIDEO_AVCProfileMax), |
114 component_name_is_nvidia_h264ext_(false) { | 130 component_name_is_nvidia_h264ext_(false), |
131 sync_thread_("OVDASyncThread") { | |
132 RETURN_ON_FAILURE(AreEGLExtensionsInitialized(), | |
133 "Failed to load EGL extensions", PLATFORM_FAILURE,); | |
115 static bool omx_functions_initialized = PostSandboxInitialization(); | 134 static bool omx_functions_initialized = PostSandboxInitialization(); |
116 RETURN_ON_FAILURE(omx_functions_initialized, | 135 RETURN_ON_FAILURE(omx_functions_initialized, |
117 "Failed to load openmax library", PLATFORM_FAILURE,); | 136 "Failed to load openmax library", PLATFORM_FAILURE,); |
118 RETURN_ON_OMX_FAILURE(omx_init(), "Failed to init OpenMAX core", | 137 RETURN_ON_OMX_FAILURE(omx_init(), "Failed to init OpenMAX core", |
119 PLATFORM_FAILURE,); | 138 PLATFORM_FAILURE,); |
120 } | 139 } |
121 | 140 |
122 OmxVideoDecodeAccelerator::~OmxVideoDecodeAccelerator() { | 141 OmxVideoDecodeAccelerator::~OmxVideoDecodeAccelerator() { |
123 DCHECK_EQ(message_loop_, MessageLoop::current()); | 142 DCHECK_EQ(message_loop_, MessageLoop::current()); |
124 DCHECK(free_input_buffers_.empty()); | 143 DCHECK(free_input_buffers_.empty()); |
(...skipping 18 matching lines...) Expand all Loading... | |
143 h264_profile_ = MapH264ProfileToOMXAVCProfile(profile); | 162 h264_profile_ = MapH264ProfileToOMXAVCProfile(profile); |
144 RETURN_ON_FAILURE(h264_profile_ != OMX_VIDEO_AVCProfileMax, | 163 RETURN_ON_FAILURE(h264_profile_ != OMX_VIDEO_AVCProfileMax, |
145 "Unexpected profile", INVALID_ARGUMENT, false); | 164 "Unexpected profile", INVALID_ARGUMENT, false); |
146 } else if (profile == media::VP8PROFILE_MAIN) { | 165 } else if (profile == media::VP8PROFILE_MAIN) { |
147 codec_ = VP8; | 166 codec_ = VP8; |
148 } else { | 167 } else { |
149 RETURN_ON_FAILURE(false, "Unsupported profile: " << profile, | 168 RETURN_ON_FAILURE(false, "Unsupported profile: " << profile, |
150 INVALID_ARGUMENT, false); | 169 INVALID_ARGUMENT, false); |
151 } | 170 } |
152 | 171 |
172 CHECK(sync_thread_.Start()); | |
173 | |
153 if (!CreateComponent()) // Does its own RETURN_ON_FAILURE dances. | 174 if (!CreateComponent()) // Does its own RETURN_ON_FAILURE dances. |
154 return false; | 175 return false; |
155 | 176 |
156 DCHECK_EQ(current_state_change_, NO_TRANSITION); | 177 DCHECK_EQ(current_state_change_, NO_TRANSITION); |
157 current_state_change_ = INITIALIZING; | 178 current_state_change_ = INITIALIZING; |
158 BeginTransitionToState(OMX_StateIdle); | 179 BeginTransitionToState(OMX_StateIdle); |
159 | 180 |
160 if (!AllocateInputBuffers()) // Does its own RETURN_ON_FAILURE dances. | 181 if (!AllocateInputBuffers()) // Does its own RETURN_ON_FAILURE dances. |
161 return false; | 182 return false; |
162 if (!AllocateFakeOutputBuffers()) // Does its own RETURN_ON_FAILURE dances. | 183 if (!AllocateFakeOutputBuffers()) // Does its own RETURN_ON_FAILURE dances. |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
380 DCHECK_EQ(pictures_.size(), kNumPictureBuffers); | 401 DCHECK_EQ(pictures_.size(), kNumPictureBuffers); |
381 | 402 |
382 // These do their own RETURN_ON_FAILURE dances. | 403 // These do their own RETURN_ON_FAILURE dances. |
383 if (!AllocateOutputBuffers()) | 404 if (!AllocateOutputBuffers()) |
384 return; | 405 return; |
385 if (!SendCommandToPort(OMX_CommandPortEnable, output_port_)) | 406 if (!SendCommandToPort(OMX_CommandPortEnable, output_port_)) |
386 return; | 407 return; |
387 } | 408 } |
388 | 409 |
389 void OmxVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { | 410 void OmxVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { |
411 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
390 TRACE_EVENT1("Video Decoder", "OVDA::ReusePictureBuffer", | 412 TRACE_EVENT1("Video Decoder", "OVDA::ReusePictureBuffer", |
391 "Picture id", picture_buffer_id); | 413 "Picture id", picture_buffer_id); |
414 | |
415 // Create a sync object and insert it into the command stream. | |
416 EGLSyncKHR egl_sync_obj = egl_create_sync_khr(egl_display_, | |
sheu
2012/10/06 21:54:53
I'd be concerned about this leaking an EGLSyncKHR
sheu
2012/10/06 21:56:00
I meant: "if you eventually make these callbacks c
Pawel Osciak
2012/10/10 17:37:52
Yes, not happening now, but if we go with PostDela
| |
417 EGL_SYNC_FENCE_KHR, | |
418 0); | |
419 if (egl_sync_obj == EGL_NO_SYNC_KHR) { | |
420 DLOG(WARNING) << "Could not create EGL sync object."; | |
421 // If creating the sync object failed, just requeue it, we will lose | |
422 // the synchronization and could possible have artifacts, but decoding | |
423 // will continue. QueuePictureBuffer(picture_buffer_id); | |
424 return; | |
425 } | |
426 | |
427 // Inserted the object successfully, wait on the sync_thread_ for it to | |
428 // become signalled. | |
429 sync_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | |
430 &OmxVideoDecodeAccelerator::WaitForPictureSync, weak_this_, | |
piman
2012/10/06 06:42:40
You can't pass a weak pointer to another thread. I
Pawel Osciak
2012/10/10 17:37:52
I'll just use Unretained and weakptr back. This is
| |
431 picture_buffer_id, egl_sync_obj)); | |
432 } | |
433 | |
434 void OmxVideoDecodeAccelerator::WaitForPictureSync(int32 picture_buffer_id, | |
435 EGLSyncKHR egl_sync_obj) { | |
436 DCHECK_EQ(sync_thread_.message_loop(), MessageLoop::current()); | |
437 | |
438 EGLint ret = egl_client_wait_sync_khr(egl_display_, egl_sync_obj, | |
piman
2012/10/06 06:42:40
How do you know it's safe to access egl_display_ w
Pawel Osciak
2012/10/10 17:37:52
The thread is a member of this, so this can't be d
| |
439 EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, | |
440 kSyncTimeoutNanosec); | |
piman
2012/10/06 06:42:40
Why using a timeout at all?
A lock with a timeout
Pawel Osciak
2012/10/10 17:37:52
Well, the idea was to not block the whole thing fo
| |
441 // If the sync fails, ignore it. Worst case we'll get some artifacts, but | |
442 // will continue decoding. | |
443 if (ret != EGL_CONDITION_SATISFIED_KHR) | |
444 DLOG(WARNING) << "Failed EGL sync."; | |
445 | |
446 egl_destroy_sync_khr(egl_display_, egl_sync_obj); | |
447 | |
448 // Post back onto main thread to queue the picture for future use. | |
449 message_loop_->PostTask(FROM_HERE, base::Bind( | |
piman
2012/10/06 06:42:40
Same here, accessing message_loop_ isn't safe. Ins
Pawel Osciak
2012/10/10 17:37:52
Passing weak pointer to sync_thread is wrong and y
| |
450 &OmxVideoDecodeAccelerator::QueuePictureBuffer, weak_this_, | |
451 picture_buffer_id)); | |
452 } | |
453 | |
454 void OmxVideoDecodeAccelerator::QueuePictureBuffer(int32 picture_buffer_id) { | |
392 DCHECK_EQ(message_loop_, MessageLoop::current()); | 455 DCHECK_EQ(message_loop_, MessageLoop::current()); |
393 | 456 |
394 // During port-flushing, do not call OMX FillThisBuffer. | 457 // During port-flushing, do not call OMX FillThisBuffer. |
395 if (current_state_change_ == RESETTING) { | 458 if (current_state_change_ == RESETTING) { |
396 queued_picture_buffer_ids_.push_back(picture_buffer_id); | 459 queued_picture_buffer_ids_.push_back(picture_buffer_id); |
397 return; | 460 return; |
398 } | 461 } |
399 | 462 |
400 RETURN_ON_FAILURE(CanFillBuffer(), "Can't fill buffer", ILLEGAL_STATE,); | 463 RETURN_ON_FAILURE(CanFillBuffer(), "Can't fill buffer", ILLEGAL_STATE,); |
401 | 464 |
(...skipping 758 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1160 | 1223 |
1161 bool OmxVideoDecodeAccelerator::SendCommandToPort( | 1224 bool OmxVideoDecodeAccelerator::SendCommandToPort( |
1162 OMX_COMMANDTYPE cmd, int port_index) { | 1225 OMX_COMMANDTYPE cmd, int port_index) { |
1163 DCHECK_EQ(message_loop_, MessageLoop::current()); | 1226 DCHECK_EQ(message_loop_, MessageLoop::current()); |
1164 OMX_ERRORTYPE result = OMX_SendCommand(component_handle_, | 1227 OMX_ERRORTYPE result = OMX_SendCommand(component_handle_, |
1165 cmd, port_index, 0); | 1228 cmd, port_index, 0); |
1166 RETURN_ON_OMX_FAILURE(result, "SendCommand() failed" << cmd, | 1229 RETURN_ON_OMX_FAILURE(result, "SendCommand() failed" << cmd, |
1167 PLATFORM_FAILURE, false); | 1230 PLATFORM_FAILURE, false); |
1168 return true; | 1231 return true; |
1169 } | 1232 } |
OLD | NEW |