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 |