Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(159)

Side by Side Diff: content/common/gpu/media/omx_video_decode_accelerator.cc

Issue 11076009: OVDA: Perform an egl sync before reusing a texture. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: LOG()->DLOG() Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698