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 { | |
| 394 public: | |
| 395 PictureSyncObject(); | |
| 396 ~PictureSyncObject(); | |
| 397 | |
| 398 // Create a sync object and insert into the GPU command stream. | |
| 399 // Returns false on failure. | |
| 400 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
| |
| 401 // Check the status of the sync object. Return true if synced or if an error | |
| 402 // occurred so as not to wait forever. | |
| 403 bool IsSynced(); | |
| 404 | |
| 405 private: | |
| 406 EGLSyncKHR egl_sync_obj_; | |
| 407 EGLDisplay egl_display_; | |
| 408 }; | |
| 409 | |
| 410 OmxVideoDecodeAccelerator::PictureSyncObject::PictureSyncObject() | |
| 411 : egl_sync_obj_(EGL_NO_SYNC_KHR), | |
| 412 egl_display_(EGL_NO_DISPLAY) { | |
| 413 } | |
| 414 | |
| 415 OmxVideoDecodeAccelerator::PictureSyncObject::~PictureSyncObject() { | |
| 416 if (egl_sync_obj_ != EGL_NO_SYNC_KHR && egl_display_ != EGL_NO_SYNC_KHR) | |
| 417 egl_destroy_sync_khr(egl_display_, egl_sync_obj_); | |
| 418 } | |
| 419 | |
| 420 bool OmxVideoDecodeAccelerator::PictureSyncObject::Create( | |
| 421 EGLDisplay egl_display) { | |
| 422 | |
| 423 egl_display_ = egl_display; | |
| 424 | |
| 425 // Create a sync object and insert it into the command stream. | |
| 426 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.
| |
| 427 if (egl_sync_obj_ == EGL_NO_SYNC_KHR) { | |
| 428 DLOG(WARNING) << "Could not create EGL sync object, will not sync."; | |
| 429 return false; | |
| 430 } | |
| 431 | |
| 432 return true; | |
| 433 } | |
| 434 | |
| 435 bool OmxVideoDecodeAccelerator::PictureSyncObject::IsSynced() { | |
| 436 EGLint value; | |
| 437 EGLBoolean ret = egl_get_sync_attrib_khr( | |
| 438 egl_display_, egl_sync_obj_, EGL_SYNC_STATUS_KHR, &value); | |
| 439 if (ret == EGL_TRUE && value == EGL_UNSIGNALED_KHR) | |
| 440 return false; | |
| 441 | |
| 442 // The object has been signalled or we got an error polling the state. If we | |
| 443 // got an error (ret == EGL_FALSE), we allow to continue as well. Worst case, | |
| 444 // we'll get some corruption, but the decoding can continue safely. | |
| 445 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.
| |
| 446 return true; | |
| 447 } | |
| 448 | |
| 389 void OmxVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { | 449 void OmxVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { |
| 450 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
| 390 TRACE_EVENT1("Video Decoder", "OVDA::ReusePictureBuffer", | 451 TRACE_EVENT1("Video Decoder", "OVDA::ReusePictureBuffer", |
| 391 "Picture id", picture_buffer_id); | 452 "Picture id", picture_buffer_id); |
| 453 scoped_ptr<PictureSyncObject> egl_sync_obj(new PictureSyncObject); | |
| 454 | |
| 455 | |
| 456 if (!egl_sync_obj->Create(egl_display_)) { | |
| 457 // If creating the sync object failed, just requeue it, we might | |
| 458 // get artifacts, but decoding will continue. | |
| 459 QueuePictureBuffer(picture_buffer_id); | |
| 460 return; | |
| 461 } | |
| 462 | |
| 463 // Inserted the object successfully, start checking it periodically. | |
| 464 CheckPictureStatus(picture_buffer_id, egl_sync_obj.Pass()); | |
| 465 } | |
| 466 | |
| 467 void OmxVideoDecodeAccelerator::CheckPictureStatus( | |
| 468 int32 picture_buffer_id, | |
| 469 scoped_ptr<PictureSyncObject> egl_sync_obj) { | |
| 470 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
| 471 | |
| 472 // 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.
| |
| 473 // destroyed. In that case we may never call QueuePictureBuffer(). | |
| 474 // This is fine though, because all pictures, irrespective of their state, | |
| 475 // are in pictures_ map and that's what will be used to do the clean up. | |
| 476 // 5ms feels like a good compromise, allowing some decoding ahead | |
| 477 // (up to 3 frames/vsync) to compensate for more difficult frames. | |
| 478 if (!egl_sync_obj->IsSynced()) { | |
| 479 MessageLoop::current()->PostDelayedTask(FROM_HERE, base::Bind( | |
| 480 &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-
| |
| 481 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.
| |
| 482 base::TimeDelta::FromMilliseconds(5)); | |
| 483 return; | |
| 484 } | |
| 485 | |
| 486 // 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.
| |
| 487 // reuse, in the latter case we might get some corruption, but decoding can | |
| 488 // continue safely. | |
| 489 QueuePictureBuffer(picture_buffer_id); | |
| 490 } | |
| 491 | |
| 492 void OmxVideoDecodeAccelerator::QueuePictureBuffer(int32 picture_buffer_id) { | |
| 392 DCHECK_EQ(message_loop_, MessageLoop::current()); | 493 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 393 | 494 |
| 394 // During port-flushing, do not call OMX FillThisBuffer. | 495 // During port-flushing, do not call OMX FillThisBuffer. |
| 395 if (current_state_change_ == RESETTING) { | 496 if (current_state_change_ == RESETTING) { |
| 396 queued_picture_buffer_ids_.push_back(picture_buffer_id); | 497 queued_picture_buffer_ids_.push_back(picture_buffer_id); |
| 397 return; | 498 return; |
| 398 } | 499 } |
| 399 | 500 |
| 400 RETURN_ON_FAILURE(CanFillBuffer(), "Can't fill buffer", ILLEGAL_STATE,); | 501 // We might have started destroying while waiting for the picture. It's safe |
| 502 // to drop it here, because we will free all the pictures regardless of their | |
| 503 // state using the pictures_ map. | |
| 504 if (!CanFillBuffer()) | |
| 505 return; | |
| 401 | 506 |
| 402 OutputPictureById::iterator it = pictures_.find(picture_buffer_id); | 507 OutputPictureById::iterator it = pictures_.find(picture_buffer_id); |
| 403 RETURN_ON_FAILURE(it != pictures_.end(), | 508 RETURN_ON_FAILURE(it != pictures_.end(), |
| 404 "Missing picture buffer id: " << picture_buffer_id, | 509 "Missing picture buffer id: " << picture_buffer_id, |
| 405 INVALID_ARGUMENT,); | 510 INVALID_ARGUMENT,); |
| 406 OutputPicture& output_picture = it->second; | 511 OutputPicture& output_picture = it->second; |
| 407 | 512 |
| 408 ++output_buffers_at_component_; | 513 ++output_buffers_at_component_; |
| 409 OMX_ERRORTYPE result = | 514 OMX_ERRORTYPE result = |
| 410 OMX_FillThisBuffer(component_handle_, output_picture.omx_buffer_header); | 515 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")); | 1189 omx_init = reinterpret_cast<OMXInit>(dlsym(omx_handle, "OMX_Init")); |
| 1085 omx_gethandle = | 1190 omx_gethandle = |
| 1086 reinterpret_cast<OMXGetHandle>(dlsym(omx_handle, "OMX_GetHandle")); | 1191 reinterpret_cast<OMXGetHandle>(dlsym(omx_handle, "OMX_GetHandle")); |
| 1087 omx_get_components_of_role = | 1192 omx_get_components_of_role = |
| 1088 reinterpret_cast<OMXGetComponentsOfRole>( | 1193 reinterpret_cast<OMXGetComponentsOfRole>( |
| 1089 dlsym(omx_handle, "OMX_GetComponentsOfRole")); | 1194 dlsym(omx_handle, "OMX_GetComponentsOfRole")); |
| 1090 omx_free_handle = | 1195 omx_free_handle = |
| 1091 reinterpret_cast<OMXFreeHandle>(dlsym(omx_handle, "OMX_FreeHandle")); | 1196 reinterpret_cast<OMXFreeHandle>(dlsym(omx_handle, "OMX_FreeHandle")); |
| 1092 omx_deinit = | 1197 omx_deinit = |
| 1093 reinterpret_cast<OMXDeinit>(dlsym(omx_handle, "OMX_Deinit")); | 1198 reinterpret_cast<OMXDeinit>(dlsym(omx_handle, "OMX_Deinit")); |
| 1199 | |
| 1200 egl_create_sync_khr = reinterpret_cast<PFNEGLCREATESYNCKHRPROC>( | |
| 1201 eglGetProcAddress("eglCreateSyncKHR")); | |
| 1202 egl_get_sync_attrib_khr = reinterpret_cast<PFNEGLGETSYNCATTRIBKHRPROC>( | |
| 1203 eglGetProcAddress("eglGetSyncAttribKHR")); | |
| 1204 egl_destroy_sync_khr = reinterpret_cast<PFNEGLDESTROYSYNCKHRPROC>( | |
| 1205 eglGetProcAddress("eglDestroySyncKHR")); | |
| 1206 | |
| 1094 return (omx_init && omx_gethandle && omx_get_components_of_role && | 1207 return (omx_init && omx_gethandle && omx_get_components_of_role && |
| 1095 omx_free_handle && omx_deinit); | 1208 omx_free_handle && omx_deinit && egl_create_sync_khr && |
| 1209 egl_get_sync_attrib_khr && egl_destroy_sync_khr); | |
| 1096 } | 1210 } |
| 1097 | 1211 |
| 1098 // static | 1212 // static |
| 1099 OMX_ERRORTYPE OmxVideoDecodeAccelerator::EventHandler(OMX_HANDLETYPE component, | 1213 OMX_ERRORTYPE OmxVideoDecodeAccelerator::EventHandler(OMX_HANDLETYPE component, |
| 1100 OMX_PTR priv_data, | 1214 OMX_PTR priv_data, |
| 1101 OMX_EVENTTYPE event, | 1215 OMX_EVENTTYPE event, |
| 1102 OMX_U32 data1, | 1216 OMX_U32 data1, |
| 1103 OMX_U32 data2, | 1217 OMX_U32 data2, |
| 1104 OMX_PTR event_data) { | 1218 OMX_PTR event_data) { |
| 1105 // Called on the OMX thread. | 1219 // Called on the OMX thread. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1160 | 1274 |
| 1161 bool OmxVideoDecodeAccelerator::SendCommandToPort( | 1275 bool OmxVideoDecodeAccelerator::SendCommandToPort( |
| 1162 OMX_COMMANDTYPE cmd, int port_index) { | 1276 OMX_COMMANDTYPE cmd, int port_index) { |
| 1163 DCHECK_EQ(message_loop_, MessageLoop::current()); | 1277 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 1164 OMX_ERRORTYPE result = OMX_SendCommand(component_handle_, | 1278 OMX_ERRORTYPE result = OMX_SendCommand(component_handle_, |
| 1165 cmd, port_index, 0); | 1279 cmd, port_index, 0); |
| 1166 RETURN_ON_OMX_FAILURE(result, "SendCommand() failed" << cmd, | 1280 RETURN_ON_OMX_FAILURE(result, "SendCommand() failed" << cmd, |
| 1167 PLATFORM_FAILURE, false); | 1281 PLATFORM_FAILURE, false); |
| 1168 return true; | 1282 return true; |
| 1169 } | 1283 } |
| OLD | NEW |