Chromium Code Reviews| 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" |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 29 typedef OMX_ERRORTYPE (*OMXGetComponentsOfRole)(OMX_STRING, OMX_U32*, OMX_U8**); | 29 typedef OMX_ERRORTYPE (*OMXGetComponentsOfRole)(OMX_STRING, OMX_U32*, OMX_U8**); |
| 30 typedef OMX_ERRORTYPE (*OMXFreeHandle)(OMX_HANDLETYPE); | 30 typedef OMX_ERRORTYPE (*OMXFreeHandle)(OMX_HANDLETYPE); |
| 31 typedef OMX_ERRORTYPE (*OMXDeinit)(); | 31 typedef OMX_ERRORTYPE (*OMXDeinit)(); |
| 32 | 32 |
| 33 OMXInit omx_init = NULL; | 33 OMXInit omx_init = NULL; |
| 34 OMXGetHandle omx_gethandle = NULL; | 34 OMXGetHandle omx_gethandle = NULL; |
| 35 OMXGetComponentsOfRole omx_get_components_of_role = NULL; | 35 OMXGetComponentsOfRole omx_get_components_of_role = NULL; |
| 36 OMXFreeHandle omx_free_handle = NULL; | 36 OMXFreeHandle omx_free_handle = NULL; |
| 37 OMXDeinit omx_deinit = NULL; | 37 OMXDeinit omx_deinit = NULL; |
| 38 | 38 |
| 39 static PFNEGLCREATESYNCKHRPROC egl_create_sync_khr = NULL; | |
| 40 static PFNEGLGETSYNCATTRIBKHRPROC egl_get_sync_attrib_khr = NULL; | |
| 41 static PFNEGLDESTROYSYNCKHRPROC egl_destroy_sync_khr = NULL; | |
| 42 | |
| 39 // Maps h264-related Profile enum values to OMX_VIDEO_AVCPROFILETYPE values. | 43 // Maps h264-related Profile enum values to OMX_VIDEO_AVCPROFILETYPE values. |
| 40 static OMX_U32 MapH264ProfileToOMXAVCProfile(uint32 profile) { | 44 static OMX_U32 MapH264ProfileToOMXAVCProfile(uint32 profile) { |
| 41 switch (profile) { | 45 switch (profile) { |
| 42 case media::H264PROFILE_BASELINE: | 46 case media::H264PROFILE_BASELINE: |
| 43 return OMX_VIDEO_AVCProfileBaseline; | 47 return OMX_VIDEO_AVCProfileBaseline; |
| 44 case media::H264PROFILE_MAIN: | 48 case media::H264PROFILE_MAIN: |
| 45 return OMX_VIDEO_AVCProfileMain; | 49 return OMX_VIDEO_AVCProfileMain; |
| 46 case media::H264PROFILE_EXTENDED: | 50 case media::H264PROFILE_EXTENDED: |
| 47 return OMX_VIDEO_AVCProfileExtended; | 51 return OMX_VIDEO_AVCProfileExtended; |
| 48 case media::H264PROFILE_HIGH: | 52 case media::H264PROFILE_HIGH: |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 379 return; // get all the buffers first. | 383 return; // get all the buffers first. |
| 380 DCHECK_EQ(pictures_.size(), kNumPictureBuffers); | 384 DCHECK_EQ(pictures_.size(), kNumPictureBuffers); |
| 381 | 385 |
| 382 // These do their own RETURN_ON_FAILURE dances. | 386 // These do their own RETURN_ON_FAILURE dances. |
| 383 if (!AllocateOutputBuffers()) | 387 if (!AllocateOutputBuffers()) |
| 384 return; | 388 return; |
| 385 if (!SendCommandToPort(OMX_CommandPortEnable, output_port_)) | 389 if (!SendCommandToPort(OMX_CommandPortEnable, output_port_)) |
| 386 return; | 390 return; |
| 387 } | 391 } |
| 388 | 392 |
| 393 class OmxVideoDecodeAccelerator::PictureSyncObject { | |
|
piman
2012/10/12 19:37:10
nit: we usually don't define inner classes in the
Pawel Osciak
2012/10/12 20:33:08
Ok, if that's the convention. (The idea was to hav
| |
| 394 public: | |
| 395 // Create a sync object and insert into the GPU command stream. | |
| 396 PictureSyncObject(EGLDisplay egl_display); | |
| 397 ~PictureSyncObject(); | |
| 398 | |
| 399 // Check the status of the sync object. Return true if synced. | |
|
Ami GONE FROM CHROMIUM
2012/10/12 19:34:46
Style-guide-sanctioned comment style would be:
//
Pawel Osciak
2012/10/12 20:33:08
Done.
| |
| 400 bool IsSynced(); | |
| 401 | |
| 402 private: | |
| 403 EGLSyncKHR egl_sync_obj_; | |
| 404 EGLDisplay egl_display_; | |
| 405 }; | |
| 406 | |
| 407 OmxVideoDecodeAccelerator::PictureSyncObject::PictureSyncObject( | |
| 408 EGLDisplay egl_display) | |
| 409 : egl_display_(egl_display) { | |
| 410 DCHECK(egl_display_ != EGL_NO_DISPLAY); | |
| 411 | |
| 412 egl_sync_obj_ = egl_create_sync_khr(egl_display_, EGL_SYNC_FENCE_KHR, NULL); | |
| 413 DCHECK(egl_sync_obj_ != EGL_NO_SYNC_KHR) | |
| 414 << "Failed creating a sync object, will not sync."; | |
|
Ami GONE FROM CHROMIUM
2012/10/12 19:34:46
msg is still bogus (not only will the process not
Pawel Osciak
2012/10/12 20:33:08
Heh. Somehow my brain won't acknowledge that this
| |
| 415 } | |
| 416 | |
| 417 OmxVideoDecodeAccelerator::PictureSyncObject::~PictureSyncObject() { | |
| 418 if (egl_sync_obj_ != EGL_NO_SYNC_KHR) | |
|
Ami GONE FROM CHROMIUM
2012/10/12 19:34:46
Not possible for this to be false anymore, so can
Pawel Osciak
2012/10/12 20:33:08
Done.
| |
| 419 egl_destroy_sync_khr(egl_display_, egl_sync_obj_); | |
| 420 } | |
| 421 | |
| 422 bool OmxVideoDecodeAccelerator::PictureSyncObject::IsSynced() { | |
| 423 EGLint value; | |
|
piman
2012/10/12 19:37:10
nit: = 0
Ami GONE FROM CHROMIUM
2012/10/12 19:43:56
OOC: Why?
Pawel Osciak
2012/10/12 20:33:08
Are you worried the call would exit early before o
Pawel Osciak
2012/10/12 20:34:54
Oh, but that's only only in debug builds. I really
| |
| 424 EGLBoolean ret = egl_get_sync_attrib_khr( | |
| 425 egl_display_, egl_sync_obj_, EGL_SYNC_STATUS_KHR, &value); | |
| 426 DCHECK(ret) << "Failed getting sync object state."; | |
| 427 | |
| 428 if (value == EGL_UNSIGNALED_KHR) | |
|
Ami GONE FROM CHROMIUM
2012/10/12 19:34:46
l.428-431 is equiv to
return value == EGL_SIGNALED
Pawel Osciak
2012/10/12 20:33:08
Done.
| |
| 429 return false; | |
| 430 | |
| 431 return true; | |
| 432 } | |
| 433 | |
| 389 void OmxVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { | 434 void OmxVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { |
| 435 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
| 390 TRACE_EVENT1("Video Decoder", "OVDA::ReusePictureBuffer", | 436 TRACE_EVENT1("Video Decoder", "OVDA::ReusePictureBuffer", |
| 391 "Picture id", picture_buffer_id); | 437 "Picture id", picture_buffer_id); |
| 438 scoped_ptr<PictureSyncObject> egl_sync_obj( | |
| 439 new PictureSyncObject(egl_display_)); | |
| 440 | |
| 441 // Start checking sync status periodically. | |
| 442 CheckPictureStatus(picture_buffer_id, egl_sync_obj.Pass()); | |
| 443 } | |
| 444 | |
| 445 void OmxVideoDecodeAccelerator::CheckPictureStatus( | |
| 446 int32 picture_buffer_id, | |
| 447 scoped_ptr<PictureSyncObject> egl_sync_obj) { | |
| 448 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
| 449 | |
| 450 // It's possible for this task to never run if the message loop is | |
| 451 // stopped. In that case we may never call QueuePictureBuffer(). | |
| 452 // This is fine though, because all pictures, irrespective of their state, | |
| 453 // are in pictures_ map and that's what will be used to do the clean up. | |
| 454 // 5ms feels like a good compromise, allowing some decoding ahead | |
| 455 // (up to 3 frames/vsync) to compensate for more difficult frames. | |
| 456 if (!egl_sync_obj->IsSynced()) { | |
| 457 MessageLoop::current()->PostDelayedTask(FROM_HERE, base::Bind( | |
| 458 &OmxVideoDecodeAccelerator::CheckPictureStatus, weak_this_, | |
| 459 picture_buffer_id, base::Passed(&egl_sync_obj)), | |
| 460 base::TimeDelta::FromMilliseconds(5)); | |
|
piman
2012/10/12 19:37:10
nit: can you make this a constant in global scope
Pawel Osciak
2012/10/12 20:33:08
Done.
| |
| 461 return; | |
| 462 } | |
| 463 | |
| 464 // Synced successfully. Queue the buffer for reuse. | |
| 465 QueuePictureBuffer(picture_buffer_id); | |
| 466 } | |
| 467 | |
| 468 void OmxVideoDecodeAccelerator::QueuePictureBuffer(int32 picture_buffer_id) { | |
| 392 DCHECK_EQ(message_loop_, MessageLoop::current()); | 469 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 393 | 470 |
| 394 // During port-flushing, do not call OMX FillThisBuffer. | 471 // During port-flushing, do not call OMX FillThisBuffer. |
| 395 if (current_state_change_ == RESETTING) { | 472 if (current_state_change_ == RESETTING) { |
| 396 queued_picture_buffer_ids_.push_back(picture_buffer_id); | 473 queued_picture_buffer_ids_.push_back(picture_buffer_id); |
| 397 return; | 474 return; |
| 398 } | 475 } |
| 399 | 476 |
| 400 RETURN_ON_FAILURE(CanFillBuffer(), "Can't fill buffer", ILLEGAL_STATE,); | 477 // We might have started destroying while waiting for the picture. It's safe |
| 478 // to drop it here, because we will free all the pictures regardless of their | |
| 479 // state using the pictures_ map. | |
| 480 if (!CanFillBuffer()) | |
| 481 return; | |
| 401 | 482 |
| 402 OutputPictureById::iterator it = pictures_.find(picture_buffer_id); | 483 OutputPictureById::iterator it = pictures_.find(picture_buffer_id); |
| 403 RETURN_ON_FAILURE(it != pictures_.end(), | 484 RETURN_ON_FAILURE(it != pictures_.end(), |
| 404 "Missing picture buffer id: " << picture_buffer_id, | 485 "Missing picture buffer id: " << picture_buffer_id, |
| 405 INVALID_ARGUMENT,); | 486 INVALID_ARGUMENT,); |
| 406 OutputPicture& output_picture = it->second; | 487 OutputPicture& output_picture = it->second; |
| 407 | 488 |
| 408 ++output_buffers_at_component_; | 489 ++output_buffers_at_component_; |
| 409 OMX_ERRORTYPE result = | 490 OMX_ERRORTYPE result = |
| 410 OMX_FillThisBuffer(component_handle_, output_picture.omx_buffer_header); | 491 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")); | 1165 omx_init = reinterpret_cast<OMXInit>(dlsym(omx_handle, "OMX_Init")); |
| 1085 omx_gethandle = | 1166 omx_gethandle = |
| 1086 reinterpret_cast<OMXGetHandle>(dlsym(omx_handle, "OMX_GetHandle")); | 1167 reinterpret_cast<OMXGetHandle>(dlsym(omx_handle, "OMX_GetHandle")); |
| 1087 omx_get_components_of_role = | 1168 omx_get_components_of_role = |
| 1088 reinterpret_cast<OMXGetComponentsOfRole>( | 1169 reinterpret_cast<OMXGetComponentsOfRole>( |
| 1089 dlsym(omx_handle, "OMX_GetComponentsOfRole")); | 1170 dlsym(omx_handle, "OMX_GetComponentsOfRole")); |
| 1090 omx_free_handle = | 1171 omx_free_handle = |
| 1091 reinterpret_cast<OMXFreeHandle>(dlsym(omx_handle, "OMX_FreeHandle")); | 1172 reinterpret_cast<OMXFreeHandle>(dlsym(omx_handle, "OMX_FreeHandle")); |
| 1092 omx_deinit = | 1173 omx_deinit = |
| 1093 reinterpret_cast<OMXDeinit>(dlsym(omx_handle, "OMX_Deinit")); | 1174 reinterpret_cast<OMXDeinit>(dlsym(omx_handle, "OMX_Deinit")); |
| 1175 | |
| 1176 egl_create_sync_khr = reinterpret_cast<PFNEGLCREATESYNCKHRPROC>( | |
| 1177 eglGetProcAddress("eglCreateSyncKHR")); | |
| 1178 egl_get_sync_attrib_khr = reinterpret_cast<PFNEGLGETSYNCATTRIBKHRPROC>( | |
| 1179 eglGetProcAddress("eglGetSyncAttribKHR")); | |
| 1180 egl_destroy_sync_khr = reinterpret_cast<PFNEGLDESTROYSYNCKHRPROC>( | |
| 1181 eglGetProcAddress("eglDestroySyncKHR")); | |
| 1182 | |
| 1094 return (omx_init && omx_gethandle && omx_get_components_of_role && | 1183 return (omx_init && omx_gethandle && omx_get_components_of_role && |
| 1095 omx_free_handle && omx_deinit); | 1184 omx_free_handle && omx_deinit && egl_create_sync_khr && |
| 1185 egl_get_sync_attrib_khr && egl_destroy_sync_khr); | |
| 1096 } | 1186 } |
| 1097 | 1187 |
| 1098 // static | 1188 // static |
| 1099 OMX_ERRORTYPE OmxVideoDecodeAccelerator::EventHandler(OMX_HANDLETYPE component, | 1189 OMX_ERRORTYPE OmxVideoDecodeAccelerator::EventHandler(OMX_HANDLETYPE component, |
| 1100 OMX_PTR priv_data, | 1190 OMX_PTR priv_data, |
| 1101 OMX_EVENTTYPE event, | 1191 OMX_EVENTTYPE event, |
| 1102 OMX_U32 data1, | 1192 OMX_U32 data1, |
| 1103 OMX_U32 data2, | 1193 OMX_U32 data2, |
| 1104 OMX_PTR event_data) { | 1194 OMX_PTR event_data) { |
| 1105 // Called on the OMX thread. | 1195 // Called on the OMX thread. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1160 | 1250 |
| 1161 bool OmxVideoDecodeAccelerator::SendCommandToPort( | 1251 bool OmxVideoDecodeAccelerator::SendCommandToPort( |
| 1162 OMX_COMMANDTYPE cmd, int port_index) { | 1252 OMX_COMMANDTYPE cmd, int port_index) { |
| 1163 DCHECK_EQ(message_loop_, MessageLoop::current()); | 1253 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 1164 OMX_ERRORTYPE result = OMX_SendCommand(component_handle_, | 1254 OMX_ERRORTYPE result = OMX_SendCommand(component_handle_, |
| 1165 cmd, port_index, 0); | 1255 cmd, port_index, 0); |
| 1166 RETURN_ON_OMX_FAILURE(result, "SendCommand() failed" << cmd, | 1256 RETURN_ON_OMX_FAILURE(result, "SendCommand() failed" << cmd, |
| 1167 PLATFORM_FAILURE, false); | 1257 PLATFORM_FAILURE, false); |
| 1168 return true; | 1258 return true; |
| 1169 } | 1259 } |
| OLD | NEW |