Index: content/common/gpu/media/omx_video_decode_accelerator.cc |
diff --git a/content/common/gpu/media/omx_video_decode_accelerator.cc b/content/common/gpu/media/omx_video_decode_accelerator.cc |
index a72756012b6c73c58183afb348725da7a437cd6e..f9d832f448dafb36d19d30b2fe8ae1aba6a3e641 100644 |
--- a/content/common/gpu/media/omx_video_decode_accelerator.cc |
+++ b/content/common/gpu/media/omx_video_decode_accelerator.cc |
@@ -20,6 +20,7 @@ |
typedef std::pair<scoped_ptr<base::SharedMemory>, int32> SharedMemoryAndId; |
enum { kNumPictureBuffers = 8 }; |
+enum { kSyncTimeoutNanosec = 50000000 }; |
void* omx_handle = NULL; |
@@ -36,6 +37,21 @@ OMXGetComponentsOfRole omx_get_components_of_role = NULL; |
OMXFreeHandle omx_free_handle = NULL; |
OMXDeinit omx_deinit = NULL; |
+static PFNEGLCREATESYNCKHRPROC egl_create_sync_khr = |
+ reinterpret_cast<PFNEGLCREATESYNCKHRPROC>( |
+ 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
|
+static PFNEGLCLIENTWAITSYNCKHRPROC egl_client_wait_sync_khr = |
+ reinterpret_cast<PFNEGLCLIENTWAITSYNCKHRPROC>( |
+ eglGetProcAddress("eglClientWaitSyncKHR")); |
+static PFNEGLDESTROYSYNCKHRPROC egl_destroy_sync_khr = |
+ reinterpret_cast<PFNEGLDESTROYSYNCKHRPROC>( |
+ eglGetProcAddress("eglDestroySyncKHR")); |
+ |
+static bool AreEGLExtensionsInitialized() { |
+ return egl_create_sync_khr && egl_client_wait_sync_khr && |
+ egl_destroy_sync_khr; |
+} |
+ |
// Maps h264-related Profile enum values to OMX_VIDEO_AVCPROFILETYPE values. |
static OMX_U32 MapH264ProfileToOMXAVCProfile(uint32 profile) { |
switch (profile) { |
@@ -111,7 +127,10 @@ OmxVideoDecodeAccelerator::OmxVideoDecodeAccelerator( |
client_(client), |
codec_(UNKNOWN), |
h264_profile_(OMX_VIDEO_AVCProfileMax), |
- component_name_is_nvidia_h264ext_(false) { |
+ component_name_is_nvidia_h264ext_(false), |
+ sync_thread_("OVDASyncThread") { |
+ RETURN_ON_FAILURE(AreEGLExtensionsInitialized(), |
+ "Failed to load EGL extensions", PLATFORM_FAILURE,); |
static bool omx_functions_initialized = PostSandboxInitialization(); |
RETURN_ON_FAILURE(omx_functions_initialized, |
"Failed to load openmax library", PLATFORM_FAILURE,); |
@@ -150,6 +169,8 @@ bool OmxVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile) { |
INVALID_ARGUMENT, false); |
} |
+ CHECK(sync_thread_.Start()); |
+ |
if (!CreateComponent()) // Does its own RETURN_ON_FAILURE dances. |
return false; |
@@ -387,8 +408,50 @@ void OmxVideoDecodeAccelerator::AssignPictureBuffers( |
} |
void OmxVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { |
+ DCHECK_EQ(message_loop_, MessageLoop::current()); |
TRACE_EVENT1("Video Decoder", "OVDA::ReusePictureBuffer", |
"Picture id", picture_buffer_id); |
+ |
+ // Create a sync object and insert it into the command stream. |
+ 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
|
+ EGL_SYNC_FENCE_KHR, |
+ 0); |
+ if (egl_sync_obj == EGL_NO_SYNC_KHR) { |
+ DLOG(WARNING) << "Could not create EGL sync object."; |
+ // If creating the sync object failed, just requeue it, we will lose |
+ // the synchronization and could possible have artifacts, but decoding |
+ // will continue. QueuePictureBuffer(picture_buffer_id); |
+ return; |
+ } |
+ |
+ // Inserted the object successfully, wait on the sync_thread_ for it to |
+ // become signalled. |
+ sync_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
+ &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
|
+ picture_buffer_id, egl_sync_obj)); |
+} |
+ |
+void OmxVideoDecodeAccelerator::WaitForPictureSync(int32 picture_buffer_id, |
+ EGLSyncKHR egl_sync_obj) { |
+ DCHECK_EQ(sync_thread_.message_loop(), MessageLoop::current()); |
+ |
+ 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
|
+ EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, |
+ 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
|
+ // If the sync fails, ignore it. Worst case we'll get some artifacts, but |
+ // will continue decoding. |
+ if (ret != EGL_CONDITION_SATISFIED_KHR) |
+ DLOG(WARNING) << "Failed EGL sync."; |
+ |
+ egl_destroy_sync_khr(egl_display_, egl_sync_obj); |
+ |
+ // Post back onto main thread to queue the picture for future use. |
+ 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
|
+ &OmxVideoDecodeAccelerator::QueuePictureBuffer, weak_this_, |
+ picture_buffer_id)); |
+} |
+ |
+void OmxVideoDecodeAccelerator::QueuePictureBuffer(int32 picture_buffer_id) { |
DCHECK_EQ(message_loop_, MessageLoop::current()); |
// During port-flushing, do not call OMX FillThisBuffer. |