| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 <errno.h> | 5 #include <errno.h> |
| 6 #include <fcntl.h> | 6 #include <fcntl.h> |
| 7 #include <linux/videodev2.h> | 7 #include <linux/videodev2.h> |
| 8 #include <poll.h> | 8 #include <poll.h> |
| 9 #include <string.h> | 9 #include <string.h> |
| 10 #include <sys/eventfd.h> | 10 #include <sys/eventfd.h> |
| 11 #include <sys/ioctl.h> | 11 #include <sys/ioctl.h> |
| 12 #include <sys/mman.h> | 12 #include <sys/mman.h> |
| 13 | 13 |
| 14 #include "base/bind.h" | 14 #include "base/bind.h" |
| 15 #include "base/bind_helpers.h" | 15 #include "base/bind_helpers.h" |
| 16 #include "base/callback.h" | 16 #include "base/callback.h" |
| 17 #include "base/callback_helpers.h" | 17 #include "base/callback_helpers.h" |
| 18 #include "base/command_line.h" | 18 #include "base/command_line.h" |
| 19 #include "base/macros.h" | 19 #include "base/macros.h" |
| 20 #include "base/numerics/safe_conversions.h" | 20 #include "base/numerics/safe_conversions.h" |
| 21 #include "base/strings/stringprintf.h" | 21 #include "base/strings/stringprintf.h" |
| 22 #include "content/common/gpu/media/shared_memory_region.h" | 22 #include "content/common/gpu/media/shared_memory_region.h" |
| 23 #include "content/common/gpu/media/v4l2_slice_video_decode_accelerator.h" | 23 #include "content/common/gpu/media/v4l2_slice_video_decode_accelerator.h" |
| 24 #include "content/public/common/gpu_video_decode_accelerator_helpers.h" |
| 24 #include "media/base/bind_to_current_loop.h" | 25 #include "media/base/bind_to_current_loop.h" |
| 25 #include "media/base/media_switches.h" | 26 #include "media/base/media_switches.h" |
| 27 #include "ui/gl/gl_context.h" |
| 26 #include "ui/gl/scoped_binders.h" | 28 #include "ui/gl/scoped_binders.h" |
| 27 | 29 |
| 28 #define LOGF(level) LOG(level) << __FUNCTION__ << "(): " | 30 #define LOGF(level) LOG(level) << __FUNCTION__ << "(): " |
| 29 #define DVLOGF(level) DVLOG(level) << __FUNCTION__ << "(): " | 31 #define DVLOGF(level) DVLOG(level) << __FUNCTION__ << "(): " |
| 30 | 32 |
| 31 #define NOTIFY_ERROR(x) \ | 33 #define NOTIFY_ERROR(x) \ |
| 32 do { \ | 34 do { \ |
| 33 LOG(ERROR) << "Setting error state:" << x; \ | 35 LOG(ERROR) << "Setting error state:" << x; \ |
| 34 SetErrorState(x); \ | 36 SetErrorState(x); \ |
| 35 } while (0) | 37 } while (0) |
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface>& dec_surface) | 374 V4L2SliceVideoDecodeAccelerator::V4L2DecodeSurface>& dec_surface) |
| 373 : dec_surface_(dec_surface) { | 375 : dec_surface_(dec_surface) { |
| 374 } | 376 } |
| 375 | 377 |
| 376 V4L2VP8Picture::~V4L2VP8Picture() { | 378 V4L2VP8Picture::~V4L2VP8Picture() { |
| 377 } | 379 } |
| 378 | 380 |
| 379 V4L2SliceVideoDecodeAccelerator::V4L2SliceVideoDecodeAccelerator( | 381 V4L2SliceVideoDecodeAccelerator::V4L2SliceVideoDecodeAccelerator( |
| 380 const scoped_refptr<V4L2Device>& device, | 382 const scoped_refptr<V4L2Device>& device, |
| 381 EGLDisplay egl_display, | 383 EGLDisplay egl_display, |
| 382 EGLContext egl_context, | 384 const gpu_vda::GetGLContextCallback& get_gl_context_cb, |
| 383 const base::WeakPtr<Client>& io_client, | 385 const gpu_vda::MakeGLContextCurrentCallback& make_context_current_cb) |
| 384 const base::Callback<bool(void)>& make_context_current, | |
| 385 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) | |
| 386 : input_planes_count_(0), | 386 : input_planes_count_(0), |
| 387 output_planes_count_(0), | 387 output_planes_count_(0), |
| 388 child_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 388 child_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 389 io_task_runner_(io_task_runner), | |
| 390 io_client_(io_client), | |
| 391 device_(device), | 389 device_(device), |
| 392 decoder_thread_("V4L2SliceVideoDecodeAcceleratorThread"), | 390 decoder_thread_("V4L2SliceVideoDecodeAcceleratorThread"), |
| 393 device_poll_thread_("V4L2SliceVideoDecodeAcceleratorDevicePollThread"), | 391 device_poll_thread_("V4L2SliceVideoDecodeAcceleratorDevicePollThread"), |
| 394 input_streamon_(false), | 392 input_streamon_(false), |
| 395 input_buffer_queued_count_(0), | 393 input_buffer_queued_count_(0), |
| 396 output_streamon_(false), | 394 output_streamon_(false), |
| 397 output_buffer_queued_count_(0), | 395 output_buffer_queued_count_(0), |
| 398 video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), | 396 video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), |
| 399 output_format_fourcc_(0), | 397 output_format_fourcc_(0), |
| 400 state_(kUninitialized), | 398 state_(kUninitialized), |
| 401 decoder_flushing_(false), | 399 decoder_flushing_(false), |
| 402 decoder_resetting_(false), | 400 decoder_resetting_(false), |
| 403 surface_set_change_pending_(false), | 401 surface_set_change_pending_(false), |
| 404 picture_clearing_count_(0), | 402 picture_clearing_count_(0), |
| 405 make_context_current_(make_context_current), | |
| 406 egl_display_(egl_display), | 403 egl_display_(egl_display), |
| 407 egl_context_(egl_context), | 404 get_gl_context_cb_(get_gl_context_cb), |
| 405 make_context_current_cb_(make_context_current_cb), |
| 408 weak_this_factory_(this) { | 406 weak_this_factory_(this) { |
| 409 weak_this_ = weak_this_factory_.GetWeakPtr(); | 407 weak_this_ = weak_this_factory_.GetWeakPtr(); |
| 410 } | 408 } |
| 411 | 409 |
| 412 V4L2SliceVideoDecodeAccelerator::~V4L2SliceVideoDecodeAccelerator() { | 410 V4L2SliceVideoDecodeAccelerator::~V4L2SliceVideoDecodeAccelerator() { |
| 413 DVLOGF(2); | 411 DVLOGF(2); |
| 414 | 412 |
| 415 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 413 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 416 DCHECK(!decoder_thread_.IsRunning()); | 414 DCHECK(!decoder_thread_.IsRunning()); |
| 417 DCHECK(!device_poll_thread_.IsRunning()); | 415 DCHECK(!device_poll_thread_.IsRunning()); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 433 client_ptr_factory_.reset(); | 431 client_ptr_factory_.reset(); |
| 434 } | 432 } |
| 435 } | 433 } |
| 436 | 434 |
| 437 bool V4L2SliceVideoDecodeAccelerator::Initialize(const Config& config, | 435 bool V4L2SliceVideoDecodeAccelerator::Initialize(const Config& config, |
| 438 Client* client) { | 436 Client* client) { |
| 439 DVLOGF(3) << "profile: " << config.profile; | 437 DVLOGF(3) << "profile: " << config.profile; |
| 440 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 438 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 441 DCHECK_EQ(state_, kUninitialized); | 439 DCHECK_EQ(state_, kUninitialized); |
| 442 | 440 |
| 441 if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { |
| 442 NOTREACHED() << "GL callbacks are required for this VDA"; |
| 443 return false; |
| 444 } |
| 445 |
| 443 if (config.is_encrypted) { | 446 if (config.is_encrypted) { |
| 444 NOTREACHED() << "Encrypted streams are not supported for this VDA"; | 447 NOTREACHED() << "Encrypted streams are not supported for this VDA"; |
| 445 return false; | 448 return false; |
| 446 } | 449 } |
| 447 | 450 |
| 448 if (!device_->SupportsDecodeProfileForV4L2PixelFormats( | 451 if (!device_->SupportsDecodeProfileForV4L2PixelFormats( |
| 449 config.profile, arraysize(supported_input_fourccs_), | 452 config.profile, arraysize(supported_input_fourccs_), |
| 450 supported_input_fourccs_)) { | 453 supported_input_fourccs_)) { |
| 451 DVLOGF(1) << "unsupported profile " << config.profile; | 454 DVLOGF(1) << "unsupported profile " << config.profile; |
| 452 return false; | 455 return false; |
| 453 } | 456 } |
| 454 | 457 |
| 455 client_ptr_factory_.reset( | 458 client_ptr_factory_.reset( |
| 456 new base::WeakPtrFactory<VideoDecodeAccelerator::Client>(client)); | 459 new base::WeakPtrFactory<VideoDecodeAccelerator::Client>(client)); |
| 457 client_ = client_ptr_factory_->GetWeakPtr(); | 460 client_ = client_ptr_factory_->GetWeakPtr(); |
| 461 // If we haven't been set up to decode on separate thread via |
| 462 // TryToSetupDecodeOnSeparateThread(), use the main thread/client for |
| 463 // decode tasks. |
| 464 if (!decode_task_runner_) { |
| 465 decode_task_runner_ = child_task_runner_; |
| 466 DCHECK(!decode_client_); |
| 467 decode_client_ = client_; |
| 468 } |
| 458 | 469 |
| 459 video_profile_ = config.profile; | 470 video_profile_ = config.profile; |
| 460 | 471 |
| 461 if (video_profile_ >= media::H264PROFILE_MIN && | 472 if (video_profile_ >= media::H264PROFILE_MIN && |
| 462 video_profile_ <= media::H264PROFILE_MAX) { | 473 video_profile_ <= media::H264PROFILE_MAX) { |
| 463 h264_accelerator_.reset(new V4L2H264Accelerator(this)); | 474 h264_accelerator_.reset(new V4L2H264Accelerator(this)); |
| 464 decoder_.reset(new H264Decoder(h264_accelerator_.get())); | 475 decoder_.reset(new H264Decoder(h264_accelerator_.get())); |
| 465 } else if (video_profile_ >= media::VP8PROFILE_MIN && | 476 } else if (video_profile_ >= media::VP8PROFILE_MIN && |
| 466 video_profile_ <= media::VP8PROFILE_MAX) { | 477 video_profile_ <= media::VP8PROFILE_MAX) { |
| 467 vp8_accelerator_.reset(new V4L2VP8Accelerator(this)); | 478 vp8_accelerator_.reset(new V4L2VP8Accelerator(this)); |
| 468 decoder_.reset(new VP8Decoder(vp8_accelerator_.get())); | 479 decoder_.reset(new VP8Decoder(vp8_accelerator_.get())); |
| 469 } else { | 480 } else { |
| 470 NOTREACHED() << "Unsupported profile " << video_profile_; | 481 NOTREACHED() << "Unsupported profile " << video_profile_; |
| 471 return false; | 482 return false; |
| 472 } | 483 } |
| 473 | 484 |
| 474 // TODO(posciak): This needs to be queried once supported. | 485 // TODO(posciak): This needs to be queried once supported. |
| 475 input_planes_count_ = 1; | 486 input_planes_count_ = 1; |
| 476 output_planes_count_ = 1; | 487 output_planes_count_ = 1; |
| 477 | 488 |
| 478 if (egl_display_ == EGL_NO_DISPLAY) { | 489 if (egl_display_ == EGL_NO_DISPLAY) { |
| 479 LOG(ERROR) << "Initialize(): could not get EGLDisplay"; | 490 LOG(ERROR) << "Initialize(): could not get EGLDisplay"; |
| 480 return false; | 491 return false; |
| 481 } | 492 } |
| 482 | 493 |
| 483 // We need the context to be initialized to query extensions. | 494 // We need the context to be initialized to query extensions. |
| 484 if (!make_context_current_.Run()) { | 495 if (!make_context_current_cb_.Run()) { |
| 485 LOG(ERROR) << "Initialize(): could not make context current"; | 496 LOG(ERROR) << "Initialize(): could not make context current"; |
| 486 return false; | 497 return false; |
| 487 } | 498 } |
| 488 | 499 |
| 489 if (!gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync) { | 500 if (!gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync) { |
| 490 LOG(ERROR) << "Initialize(): context does not have EGL_KHR_fence_sync"; | 501 LOG(ERROR) << "Initialize(): context does not have EGL_KHR_fence_sync"; |
| 491 return false; | 502 return false; |
| 492 } | 503 } |
| 493 | 504 |
| 494 // Capabilities check. | 505 // Capabilities check. |
| (...skipping 683 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1178 decoder_display_queue_.pop(); | 1189 decoder_display_queue_.pop(); |
| 1179 | 1190 |
| 1180 DVLOGF(3) << "Device poll stopped"; | 1191 DVLOGF(3) << "Device poll stopped"; |
| 1181 return true; | 1192 return true; |
| 1182 } | 1193 } |
| 1183 | 1194 |
| 1184 void V4L2SliceVideoDecodeAccelerator::Decode( | 1195 void V4L2SliceVideoDecodeAccelerator::Decode( |
| 1185 const media::BitstreamBuffer& bitstream_buffer) { | 1196 const media::BitstreamBuffer& bitstream_buffer) { |
| 1186 DVLOGF(3) << "input_id=" << bitstream_buffer.id() | 1197 DVLOGF(3) << "input_id=" << bitstream_buffer.id() |
| 1187 << ", size=" << bitstream_buffer.size(); | 1198 << ", size=" << bitstream_buffer.size(); |
| 1188 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 1199 DCHECK(decode_task_runner_->BelongsToCurrentThread()); |
| 1189 | 1200 |
| 1190 if (bitstream_buffer.id() < 0) { | 1201 if (bitstream_buffer.id() < 0) { |
| 1191 LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id(); | 1202 LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id(); |
| 1192 if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle())) | 1203 if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle())) |
| 1193 base::SharedMemory::CloseHandle(bitstream_buffer.handle()); | 1204 base::SharedMemory::CloseHandle(bitstream_buffer.handle()); |
| 1194 NOTIFY_ERROR(INVALID_ARGUMENT); | 1205 NOTIFY_ERROR(INVALID_ARGUMENT); |
| 1195 return; | 1206 return; |
| 1196 } | 1207 } |
| 1197 | 1208 |
| 1198 decoder_thread_task_runner_->PostTask( | 1209 decoder_thread_task_runner_->PostTask( |
| 1199 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::DecodeTask, | 1210 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::DecodeTask, |
| 1200 base::Unretained(this), bitstream_buffer)); | 1211 base::Unretained(this), bitstream_buffer)); |
| 1201 } | 1212 } |
| 1202 | 1213 |
| 1203 void V4L2SliceVideoDecodeAccelerator::DecodeTask( | 1214 void V4L2SliceVideoDecodeAccelerator::DecodeTask( |
| 1204 const media::BitstreamBuffer& bitstream_buffer) { | 1215 const media::BitstreamBuffer& bitstream_buffer) { |
| 1205 DVLOGF(3) << "input_id=" << bitstream_buffer.id() | 1216 DVLOGF(3) << "input_id=" << bitstream_buffer.id() |
| 1206 << " size=" << bitstream_buffer.size(); | 1217 << " size=" << bitstream_buffer.size(); |
| 1207 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1218 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 1208 | 1219 |
| 1209 scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef( | 1220 scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef( |
| 1210 io_client_, io_task_runner_, | 1221 decode_client_, decode_task_runner_, |
| 1211 new SharedMemoryRegion(bitstream_buffer, true), bitstream_buffer.id())); | 1222 new SharedMemoryRegion(bitstream_buffer, true), bitstream_buffer.id())); |
| 1212 if (!bitstream_record->shm->Map()) { | 1223 if (!bitstream_record->shm->Map()) { |
| 1213 LOGF(ERROR) << "Could not map bitstream_buffer"; | 1224 LOGF(ERROR) << "Could not map bitstream_buffer"; |
| 1214 NOTIFY_ERROR(UNREADABLE_INPUT); | 1225 NOTIFY_ERROR(UNREADABLE_INPUT); |
| 1215 return; | 1226 return; |
| 1216 } | 1227 } |
| 1217 DVLOGF(3) << "mapped at=" << bitstream_record->shm->memory(); | 1228 DVLOGF(3) << "mapped at=" << bitstream_record->shm->memory(); |
| 1218 | 1229 |
| 1219 decoder_input_queue_.push( | 1230 decoder_input_queue_.push( |
| 1220 linked_ptr<BitstreamBufferRef>(bitstream_record.release())); | 1231 linked_ptr<BitstreamBufferRef>(bitstream_record.release())); |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1481 output_planes_count_)); | 1492 output_planes_count_)); |
| 1482 } | 1493 } |
| 1483 | 1494 |
| 1484 void V4L2SliceVideoDecodeAccelerator::CreateEGLImages( | 1495 void V4L2SliceVideoDecodeAccelerator::CreateEGLImages( |
| 1485 const std::vector<media::PictureBuffer>& buffers, | 1496 const std::vector<media::PictureBuffer>& buffers, |
| 1486 uint32_t output_format_fourcc, | 1497 uint32_t output_format_fourcc, |
| 1487 size_t output_planes_count) { | 1498 size_t output_planes_count) { |
| 1488 DVLOGF(3); | 1499 DVLOGF(3); |
| 1489 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 1500 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 1490 | 1501 |
| 1491 if (!make_context_current_.Run()) { | 1502 gfx::GLContext* gl_context = get_gl_context_cb_.Run(); |
| 1492 DLOG(ERROR) << "could not make context current"; | 1503 if (!gl_context || !make_context_current_cb_.Run()) { |
| 1504 DLOG(ERROR) << "No GL context"; |
| 1493 NOTIFY_ERROR(PLATFORM_FAILURE); | 1505 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1494 return; | 1506 return; |
| 1495 } | 1507 } |
| 1496 | 1508 |
| 1497 gfx::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); | 1509 gfx::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); |
| 1498 | 1510 |
| 1499 std::vector<EGLImageKHR> egl_images; | 1511 std::vector<EGLImageKHR> egl_images; |
| 1500 for (size_t i = 0; i < buffers.size(); ++i) { | 1512 for (size_t i = 0; i < buffers.size(); ++i) { |
| 1501 EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_, | 1513 EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_, |
| 1502 egl_context_, | 1514 gl_context->GetHandle(), |
| 1503 buffers[i].texture_id(), | 1515 buffers[i].texture_id(), |
| 1504 buffers[i].size(), | 1516 buffers[i].size(), |
| 1505 i, | 1517 i, |
| 1506 output_format_fourcc, | 1518 output_format_fourcc, |
| 1507 output_planes_count); | 1519 output_planes_count); |
| 1508 if (egl_image == EGL_NO_IMAGE_KHR) { | 1520 if (egl_image == EGL_NO_IMAGE_KHR) { |
| 1509 LOGF(ERROR) << "Could not create EGLImageKHR"; | 1521 LOGF(ERROR) << "Could not create EGLImageKHR"; |
| 1510 for (const auto& image_to_destroy : egl_images) | 1522 for (const auto& image_to_destroy : egl_images) |
| 1511 device_->DestroyEGLImage(egl_display_, image_to_destroy); | 1523 device_->DestroyEGLImage(egl_display_, image_to_destroy); |
| 1512 | 1524 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1558 } | 1570 } |
| 1559 | 1571 |
| 1560 ProcessPendingEventsIfNeeded(); | 1572 ProcessPendingEventsIfNeeded(); |
| 1561 } | 1573 } |
| 1562 | 1574 |
| 1563 void V4L2SliceVideoDecodeAccelerator::ReusePictureBuffer( | 1575 void V4L2SliceVideoDecodeAccelerator::ReusePictureBuffer( |
| 1564 int32_t picture_buffer_id) { | 1576 int32_t picture_buffer_id) { |
| 1565 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 1577 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 1566 DVLOGF(4) << "picture_buffer_id=" << picture_buffer_id; | 1578 DVLOGF(4) << "picture_buffer_id=" << picture_buffer_id; |
| 1567 | 1579 |
| 1568 if (!make_context_current_.Run()) { | 1580 if (!make_context_current_cb_.Run()) { |
| 1569 LOGF(ERROR) << "could not make context current"; | 1581 LOGF(ERROR) << "could not make context current"; |
| 1570 NOTIFY_ERROR(PLATFORM_FAILURE); | 1582 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1571 return; | 1583 return; |
| 1572 } | 1584 } |
| 1573 | 1585 |
| 1574 EGLSyncKHR egl_sync = | 1586 EGLSyncKHR egl_sync = |
| 1575 eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL); | 1587 eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL); |
| 1576 if (egl_sync == EGL_NO_SYNC_KHR) { | 1588 if (egl_sync == EGL_NO_SYNC_KHR) { |
| 1577 LOGF(ERROR) << "eglCreateSyncKHR() failed"; | 1589 LOGF(ERROR) << "eglCreateSyncKHR() failed"; |
| 1578 NOTIFY_ERROR(PLATFORM_FAILURE); | 1590 NOTIFY_ERROR(PLATFORM_FAILURE); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1634 | 1646 |
| 1635 void V4L2SliceVideoDecodeAccelerator::FlushTask() { | 1647 void V4L2SliceVideoDecodeAccelerator::FlushTask() { |
| 1636 DVLOGF(3); | 1648 DVLOGF(3); |
| 1637 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1649 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 1638 | 1650 |
| 1639 if (!decoder_input_queue_.empty()) { | 1651 if (!decoder_input_queue_.empty()) { |
| 1640 // We are not done with pending inputs, so queue an empty buffer, | 1652 // We are not done with pending inputs, so queue an empty buffer, |
| 1641 // which - when reached - will trigger flush sequence. | 1653 // which - when reached - will trigger flush sequence. |
| 1642 decoder_input_queue_.push( | 1654 decoder_input_queue_.push( |
| 1643 linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef( | 1655 linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef( |
| 1644 io_client_, io_task_runner_, nullptr, kFlushBufferId))); | 1656 decode_client_, decode_task_runner_, nullptr, kFlushBufferId))); |
| 1645 return; | 1657 return; |
| 1646 } | 1658 } |
| 1647 | 1659 |
| 1648 // No more inputs pending, so just finish flushing here. | 1660 // No more inputs pending, so just finish flushing here. |
| 1649 InitiateFlush(); | 1661 InitiateFlush(); |
| 1650 } | 1662 } |
| 1651 | 1663 |
| 1652 void V4L2SliceVideoDecodeAccelerator::InitiateFlush() { | 1664 void V4L2SliceVideoDecodeAccelerator::InitiateFlush() { |
| 1653 DVLOGF(3); | 1665 DVLOGF(3); |
| 1654 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1666 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| (...skipping 890 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2545 } | 2557 } |
| 2546 | 2558 |
| 2547 void V4L2SliceVideoDecodeAccelerator::SendPictureReady() { | 2559 void V4L2SliceVideoDecodeAccelerator::SendPictureReady() { |
| 2548 DVLOGF(3); | 2560 DVLOGF(3); |
| 2549 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 2561 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 2550 bool resetting_or_flushing = (decoder_resetting_ || decoder_flushing_); | 2562 bool resetting_or_flushing = (decoder_resetting_ || decoder_flushing_); |
| 2551 while (!pending_picture_ready_.empty()) { | 2563 while (!pending_picture_ready_.empty()) { |
| 2552 bool cleared = pending_picture_ready_.front().cleared; | 2564 bool cleared = pending_picture_ready_.front().cleared; |
| 2553 const media::Picture& picture = pending_picture_ready_.front().picture; | 2565 const media::Picture& picture = pending_picture_ready_.front().picture; |
| 2554 if (cleared && picture_clearing_count_ == 0) { | 2566 if (cleared && picture_clearing_count_ == 0) { |
| 2555 DVLOGF(4) << "Posting picture ready to IO for: " | 2567 DVLOGF(4) << "Posting picture ready to decode task runner for: " |
| 2556 << picture.picture_buffer_id(); | 2568 << picture.picture_buffer_id(); |
| 2557 // This picture is cleared. Post it to IO thread to reduce latency. This | 2569 // This picture is cleared. It can be posted to a thread different than |
| 2558 // should be the case after all pictures are cleared at the beginning. | 2570 // the main GPU thread to reduce latency. This should be the case after |
| 2559 io_task_runner_->PostTask( | 2571 // all pictures are cleared at the beginning. |
| 2560 FROM_HERE, base::Bind(&Client::PictureReady, io_client_, picture)); | 2572 decode_task_runner_->PostTask( |
| 2573 FROM_HERE, |
| 2574 base::Bind(&Client::PictureReady, decode_client_, picture)); |
| 2561 pending_picture_ready_.pop(); | 2575 pending_picture_ready_.pop(); |
| 2562 } else if (!cleared || resetting_or_flushing) { | 2576 } else if (!cleared || resetting_or_flushing) { |
| 2563 DVLOGF(3) << "cleared=" << pending_picture_ready_.front().cleared | 2577 DVLOGF(3) << "cleared=" << pending_picture_ready_.front().cleared |
| 2564 << ", decoder_resetting_=" << decoder_resetting_ | 2578 << ", decoder_resetting_=" << decoder_resetting_ |
| 2565 << ", decoder_flushing_=" << decoder_flushing_ | 2579 << ", decoder_flushing_=" << decoder_flushing_ |
| 2566 << ", picture_clearing_count_=" << picture_clearing_count_; | 2580 << ", picture_clearing_count_=" << picture_clearing_count_; |
| 2567 DVLOGF(4) << "Posting picture ready to GPU for: " | 2581 DVLOGF(4) << "Posting picture ready to GPU for: " |
| 2568 << picture.picture_buffer_id(); | 2582 << picture.picture_buffer_id(); |
| 2569 // If the picture is not cleared, post it to the child thread because it | 2583 // If the picture is not cleared, post it to the child thread because it |
| 2570 // has to be cleared in the child thread. A picture only needs to be | 2584 // has to be cleared in the child thread. A picture only needs to be |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2588 } | 2602 } |
| 2589 | 2603 |
| 2590 void V4L2SliceVideoDecodeAccelerator::PictureCleared() { | 2604 void V4L2SliceVideoDecodeAccelerator::PictureCleared() { |
| 2591 DVLOGF(3) << "clearing count=" << picture_clearing_count_; | 2605 DVLOGF(3) << "clearing count=" << picture_clearing_count_; |
| 2592 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 2606 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 2593 DCHECK_GT(picture_clearing_count_, 0); | 2607 DCHECK_GT(picture_clearing_count_, 0); |
| 2594 picture_clearing_count_--; | 2608 picture_clearing_count_--; |
| 2595 SendPictureReady(); | 2609 SendPictureReady(); |
| 2596 } | 2610 } |
| 2597 | 2611 |
| 2598 bool V4L2SliceVideoDecodeAccelerator::CanDecodeOnIOThread() { | 2612 bool V4L2SliceVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( |
| 2613 const base::WeakPtr<Client>& decode_client, |
| 2614 const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { |
| 2615 decode_client_ = decode_client_; |
| 2616 decode_task_runner_ = decode_task_runner; |
| 2599 return true; | 2617 return true; |
| 2600 } | 2618 } |
| 2601 | 2619 |
| 2602 // static | 2620 // static |
| 2603 media::VideoDecodeAccelerator::SupportedProfiles | 2621 media::VideoDecodeAccelerator::SupportedProfiles |
| 2604 V4L2SliceVideoDecodeAccelerator::GetSupportedProfiles() { | 2622 V4L2SliceVideoDecodeAccelerator::GetSupportedProfiles() { |
| 2605 scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); | 2623 scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); |
| 2606 if (!device) | 2624 if (!device) |
| 2607 return SupportedProfiles(); | 2625 return SupportedProfiles(); |
| 2608 | 2626 |
| 2609 return device->GetSupportedDecodeProfiles(arraysize(supported_input_fourccs_), | 2627 return device->GetSupportedDecodeProfiles(arraysize(supported_input_fourccs_), |
| 2610 supported_input_fourccs_); | 2628 supported_input_fourccs_); |
| 2611 } | 2629 } |
| 2612 | 2630 |
| 2613 } // namespace content | 2631 } // namespace content |
| OLD | NEW |