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..473c73929f38cb0d0ef6b7deff210b198275e68d 100644 |
--- a/content/common/gpu/media/omx_video_decode_accelerator.cc |
+++ b/content/common/gpu/media/omx_video_decode_accelerator.cc |
@@ -36,6 +36,10 @@ OMXGetComponentsOfRole omx_get_components_of_role = NULL; |
OMXFreeHandle omx_free_handle = NULL; |
OMXDeinit omx_deinit = NULL; |
+static PFNEGLCREATESYNCKHRPROC egl_create_sync_khr = NULL; |
+static PFNEGLGETSYNCATTRIBKHRPROC egl_get_sync_attrib_khr = NULL; |
+static PFNEGLDESTROYSYNCKHRPROC egl_destroy_sync_khr = NULL; |
+ |
// Maps h264-related Profile enum values to OMX_VIDEO_AVCPROFILETYPE values. |
static OMX_U32 MapH264ProfileToOMXAVCProfile(uint32 profile) { |
switch (profile) { |
@@ -386,9 +390,106 @@ void OmxVideoDecodeAccelerator::AssignPictureBuffers( |
return; |
} |
+class OmxVideoDecodeAccelerator::PictureSyncObject { |
+ public: |
+ PictureSyncObject(); |
+ ~PictureSyncObject(); |
+ |
+ // Create a sync object and insert into the GPU command stream. |
+ // Returns false on failure. |
+ bool Create(EGLDisplay egl_display); |
Ami GONE FROM CHROMIUM
2012/10/12 17:20:05
All of the error conditions that can cause creates
Pawel Osciak
2012/10/12 17:50:50
Not sure what you mean, egl_create_sync_khr may fa
Ami GONE FROM CHROMIUM
2012/10/12 17:57:28
Where does the spec permit that?
Do you mean s/rea
Pawel Osciak
2012/10/12 18:39:28
Well, mostly things like out of memory or driver i
|
+ // Check the status of the sync object. Return true if synced or if an error |
+ // occurred so as not to wait forever. |
+ bool IsSynced(); |
+ |
+ private: |
+ EGLSyncKHR egl_sync_obj_; |
+ EGLDisplay egl_display_; |
+}; |
+ |
+OmxVideoDecodeAccelerator::PictureSyncObject::PictureSyncObject() |
+ : egl_sync_obj_(EGL_NO_SYNC_KHR), |
+ egl_display_(EGL_NO_DISPLAY) { |
+} |
+ |
+OmxVideoDecodeAccelerator::PictureSyncObject::~PictureSyncObject() { |
+ if (egl_sync_obj_ != EGL_NO_SYNC_KHR && egl_display_ != EGL_NO_SYNC_KHR) |
+ egl_destroy_sync_khr(egl_display_, egl_sync_obj_); |
+} |
+ |
+bool OmxVideoDecodeAccelerator::PictureSyncObject::Create( |
+ EGLDisplay egl_display) { |
+ |
+ egl_display_ = egl_display; |
+ |
+ // Create a sync object and insert it into the command stream. |
+ egl_sync_obj_ = egl_create_sync_khr(egl_display_, EGL_SYNC_FENCE_KHR, 0); |
Ami GONE FROM CHROMIUM
2012/10/12 17:20:05
s/0/NULL/
Pawel Osciak
2012/10/12 18:39:28
Done.
|
+ if (egl_sync_obj_ == EGL_NO_SYNC_KHR) { |
+ DLOG(WARNING) << "Could not create EGL sync object, will not sync."; |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+bool OmxVideoDecodeAccelerator::PictureSyncObject::IsSynced() { |
+ EGLint value; |
+ EGLBoolean ret = egl_get_sync_attrib_khr( |
+ egl_display_, egl_sync_obj_, EGL_SYNC_STATUS_KHR, &value); |
+ if (ret == EGL_TRUE && value == EGL_UNSIGNALED_KHR) |
+ return false; |
+ |
+ // The object has been signalled or we got an error polling the state. If we |
+ // got an error (ret == EGL_FALSE), we allow to continue as well. Worst case, |
+ // we'll get some corruption, but the decoding can continue safely. |
+ DCHECK(ret) << "EGL sync failed, continuing without syncing."; |
Ami GONE FROM CHROMIUM
2012/10/12 17:20:05
lolwat?
In Debug, ain't nuthin' continuing after a
Pawel Osciak
2012/10/12 17:50:50
lolled myself, not sure what I was thinking.
I'm n
Pawel Osciak
2012/10/12 18:39:28
Done.
|
+ return true; |
+} |
+ |
void OmxVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { |
+ DCHECK_EQ(message_loop_, MessageLoop::current()); |
TRACE_EVENT1("Video Decoder", "OVDA::ReusePictureBuffer", |
"Picture id", picture_buffer_id); |
+ scoped_ptr<PictureSyncObject> egl_sync_obj(new PictureSyncObject); |
+ |
+ |
+ if (!egl_sync_obj->Create(egl_display_)) { |
+ // If creating the sync object failed, just requeue it, we might |
+ // get artifacts, but decoding will continue. |
+ QueuePictureBuffer(picture_buffer_id); |
+ return; |
+ } |
+ |
+ // Inserted the object successfully, start checking it periodically. |
+ CheckPictureStatus(picture_buffer_id, egl_sync_obj.Pass()); |
+} |
+ |
+void OmxVideoDecodeAccelerator::CheckPictureStatus( |
+ int32 picture_buffer_id, |
+ scoped_ptr<PictureSyncObject> egl_sync_obj) { |
+ DCHECK_EQ(message_loop_, MessageLoop::current()); |
+ |
+ // It's possible for this task to get cancelled if the decoder is being |
Ami GONE FROM CHROMIUM
2012/10/12 17:20:05
s/get cancelled/never run/
Ami GONE FROM CHROMIUM
2012/10/12 17:20:05
s/decoder is destroyed/messageloop is stopped/
Pawel Osciak
2012/10/12 18:39:28
Done.
Pawel Osciak
2012/10/12 18:39:28
Done.
|
+ // destroyed. In that case we may never call QueuePictureBuffer(). |
+ // This is fine though, because all pictures, irrespective of their state, |
+ // are in pictures_ map and that's what will be used to do the clean up. |
+ // 5ms feels like a good compromise, allowing some decoding ahead |
+ // (up to 3 frames/vsync) to compensate for more difficult frames. |
+ if (!egl_sync_obj->IsSynced()) { |
+ MessageLoop::current()->PostDelayedTask(FROM_HERE, base::Bind( |
+ &OmxVideoDecodeAccelerator::CheckPictureStatus, base::Unretained(this), |
Ami GONE FROM CHROMIUM
2012/10/12 17:20:05
s/base::Unretained(this)/weak_this_/ because what
Pawel Osciak
2012/10/12 18:39:28
Another brain fart, must've still been in the sub-
|
+ picture_buffer_id, base::Passed(egl_sync_obj.Pass())), |
Ami GONE FROM CHROMIUM
2012/10/12 17:20:05
replace
egl_sync_obj.Pass()
with
&egl_sync_obj
Pawel Osciak
2012/10/12 18:39:28
Ok. FWIW got inspired by http://code.google.com/se
Ami GONE FROM CHROMIUM
2012/10/12 19:34:46
Huh; filed bug 155593 to eradicate that pattern.
|
+ base::TimeDelta::FromMilliseconds(5)); |
+ return; |
+ } |
+ |
+ // Synced successfully or getting sync status failed. Queue the buffer for |
Ami GONE FROM CHROMIUM
2012/10/12 17:20:05
drop "failed" clause
Pawel Osciak
2012/10/12 18:39:28
Done.
|
+ // reuse, in the latter case we might get some corruption, but decoding can |
+ // continue safely. |
+ QueuePictureBuffer(picture_buffer_id); |
+} |
+ |
+void OmxVideoDecodeAccelerator::QueuePictureBuffer(int32 picture_buffer_id) { |
DCHECK_EQ(message_loop_, MessageLoop::current()); |
// During port-flushing, do not call OMX FillThisBuffer. |
@@ -397,7 +498,11 @@ void OmxVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { |
return; |
} |
- RETURN_ON_FAILURE(CanFillBuffer(), "Can't fill buffer", ILLEGAL_STATE,); |
+ // We might have started destroying while waiting for the picture. It's safe |
+ // to drop it here, because we will free all the pictures regardless of their |
+ // state using the pictures_ map. |
+ if (!CanFillBuffer()) |
+ return; |
OutputPictureById::iterator it = pictures_.find(picture_buffer_id); |
RETURN_ON_FAILURE(it != pictures_.end(), |
@@ -1091,8 +1196,17 @@ bool OmxVideoDecodeAccelerator::PostSandboxInitialization() { |
reinterpret_cast<OMXFreeHandle>(dlsym(omx_handle, "OMX_FreeHandle")); |
omx_deinit = |
reinterpret_cast<OMXDeinit>(dlsym(omx_handle, "OMX_Deinit")); |
+ |
+ egl_create_sync_khr = reinterpret_cast<PFNEGLCREATESYNCKHRPROC>( |
+ eglGetProcAddress("eglCreateSyncKHR")); |
+ egl_get_sync_attrib_khr = reinterpret_cast<PFNEGLGETSYNCATTRIBKHRPROC>( |
+ eglGetProcAddress("eglGetSyncAttribKHR")); |
+ egl_destroy_sync_khr = reinterpret_cast<PFNEGLDESTROYSYNCKHRPROC>( |
+ eglGetProcAddress("eglDestroySyncKHR")); |
+ |
return (omx_init && omx_gethandle && omx_get_components_of_role && |
- omx_free_handle && omx_deinit); |
+ omx_free_handle && omx_deinit && egl_create_sync_khr && |
+ egl_get_sync_attrib_khr && egl_destroy_sync_khr); |
} |
// static |