| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 <dlfcn.h> | 5 #include <dlfcn.h> |
| 6 #include <errno.h> | 6 #include <errno.h> |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <linux/videodev2.h> | 8 #include <linux/videodev2.h> |
| 9 #include <poll.h> | 9 #include <poll.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/command_line.h" | 15 #include "base/command_line.h" |
| 16 #include "base/memory/shared_memory.h" | 16 #include "base/memory/shared_memory.h" |
| 17 #include "base/message_loop/message_loop.h" | 17 #include "base/message_loop/message_loop.h" |
| 18 #include "base/message_loop/message_loop_proxy.h" | |
| 19 #include "base/numerics/safe_conversions.h" | 18 #include "base/numerics/safe_conversions.h" |
| 20 #include "base/trace_event/trace_event.h" | 19 #include "base/trace_event/trace_event.h" |
| 21 #include "content/common/gpu/media/v4l2_video_decode_accelerator.h" | 20 #include "content/common/gpu/media/v4l2_video_decode_accelerator.h" |
| 22 #include "media/base/media_switches.h" | 21 #include "media/base/media_switches.h" |
| 23 #include "media/filters/h264_parser.h" | 22 #include "media/filters/h264_parser.h" |
| 24 #include "ui/gfx/geometry/rect.h" | 23 #include "ui/gfx/geometry/rect.h" |
| 25 #include "ui/gl/scoped_binders.h" | 24 #include "ui/gl/scoped_binders.h" |
| 26 | 25 |
| 27 #define NOTIFY_ERROR(x) \ | 26 #define NOTIFY_ERROR(x) \ |
| 28 do { \ | 27 do { \ |
| (...skipping 29 matching lines...) Expand all Loading... |
| 58 // TODO(posciak): remove once we update linux-headers. | 57 // TODO(posciak): remove once we update linux-headers. |
| 59 #ifndef V4L2_EVENT_RESOLUTION_CHANGE | 58 #ifndef V4L2_EVENT_RESOLUTION_CHANGE |
| 60 #define V4L2_EVENT_RESOLUTION_CHANGE 5 | 59 #define V4L2_EVENT_RESOLUTION_CHANGE 5 |
| 61 #endif | 60 #endif |
| 62 | 61 |
| 63 } // anonymous namespace | 62 } // anonymous namespace |
| 64 | 63 |
| 65 struct V4L2VideoDecodeAccelerator::BitstreamBufferRef { | 64 struct V4L2VideoDecodeAccelerator::BitstreamBufferRef { |
| 66 BitstreamBufferRef( | 65 BitstreamBufferRef( |
| 67 base::WeakPtr<Client>& client, | 66 base::WeakPtr<Client>& client, |
| 68 scoped_refptr<base::MessageLoopProxy>& client_message_loop_proxy, | 67 scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, |
| 69 base::SharedMemory* shm, | 68 base::SharedMemory* shm, |
| 70 size_t size, | 69 size_t size, |
| 71 int32 input_id); | 70 int32 input_id); |
| 72 ~BitstreamBufferRef(); | 71 ~BitstreamBufferRef(); |
| 73 const base::WeakPtr<Client> client; | 72 const base::WeakPtr<Client> client; |
| 74 const scoped_refptr<base::MessageLoopProxy> client_message_loop_proxy; | 73 const scoped_refptr<base::SingleThreadTaskRunner> client_task_runner; |
| 75 const scoped_ptr<base::SharedMemory> shm; | 74 const scoped_ptr<base::SharedMemory> shm; |
| 76 const size_t size; | 75 const size_t size; |
| 77 size_t bytes_used; | 76 size_t bytes_used; |
| 78 const int32 input_id; | 77 const int32 input_id; |
| 79 }; | 78 }; |
| 80 | 79 |
| 81 struct V4L2VideoDecodeAccelerator::EGLSyncKHRRef { | 80 struct V4L2VideoDecodeAccelerator::EGLSyncKHRRef { |
| 82 EGLSyncKHRRef(EGLDisplay egl_display, EGLSyncKHR egl_sync); | 81 EGLSyncKHRRef(EGLDisplay egl_display, EGLSyncKHR egl_sync); |
| 83 ~EGLSyncKHRRef(); | 82 ~EGLSyncKHRRef(); |
| 84 EGLDisplay const egl_display; | 83 EGLDisplay const egl_display; |
| 85 EGLSyncKHR egl_sync; | 84 EGLSyncKHR egl_sync; |
| 86 }; | 85 }; |
| 87 | 86 |
| 88 struct V4L2VideoDecodeAccelerator::PictureRecord { | 87 struct V4L2VideoDecodeAccelerator::PictureRecord { |
| 89 PictureRecord(bool cleared, const media::Picture& picture); | 88 PictureRecord(bool cleared, const media::Picture& picture); |
| 90 ~PictureRecord(); | 89 ~PictureRecord(); |
| 91 bool cleared; // Whether the texture is cleared and safe to render from. | 90 bool cleared; // Whether the texture is cleared and safe to render from. |
| 92 media::Picture picture; // The decoded picture. | 91 media::Picture picture; // The decoded picture. |
| 93 }; | 92 }; |
| 94 | 93 |
| 95 V4L2VideoDecodeAccelerator::BitstreamBufferRef::BitstreamBufferRef( | 94 V4L2VideoDecodeAccelerator::BitstreamBufferRef::BitstreamBufferRef( |
| 96 base::WeakPtr<Client>& client, | 95 base::WeakPtr<Client>& client, |
| 97 scoped_refptr<base::MessageLoopProxy>& client_message_loop_proxy, | 96 scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, |
| 98 base::SharedMemory* shm, size_t size, int32 input_id) | 97 base::SharedMemory* shm, |
| 98 size_t size, |
| 99 int32 input_id) |
| 99 : client(client), | 100 : client(client), |
| 100 client_message_loop_proxy(client_message_loop_proxy), | 101 client_task_runner(client_task_runner), |
| 101 shm(shm), | 102 shm(shm), |
| 102 size(size), | 103 size(size), |
| 103 bytes_used(0), | 104 bytes_used(0), |
| 104 input_id(input_id) { | 105 input_id(input_id) { |
| 105 } | 106 } |
| 106 | 107 |
| 107 V4L2VideoDecodeAccelerator::BitstreamBufferRef::~BitstreamBufferRef() { | 108 V4L2VideoDecodeAccelerator::BitstreamBufferRef::~BitstreamBufferRef() { |
| 108 if (input_id >= 0) { | 109 if (input_id >= 0) { |
| 109 client_message_loop_proxy->PostTask(FROM_HERE, base::Bind( | 110 client_task_runner->PostTask( |
| 110 &Client::NotifyEndOfBitstreamBuffer, client, input_id)); | 111 FROM_HERE, |
| 112 base::Bind(&Client::NotifyEndOfBitstreamBuffer, client, input_id)); |
| 111 } | 113 } |
| 112 } | 114 } |
| 113 | 115 |
| 114 V4L2VideoDecodeAccelerator::EGLSyncKHRRef::EGLSyncKHRRef( | 116 V4L2VideoDecodeAccelerator::EGLSyncKHRRef::EGLSyncKHRRef( |
| 115 EGLDisplay egl_display, EGLSyncKHR egl_sync) | 117 EGLDisplay egl_display, EGLSyncKHR egl_sync) |
| 116 : egl_display(egl_display), | 118 : egl_display(egl_display), |
| 117 egl_sync(egl_sync) { | 119 egl_sync(egl_sync) { |
| 118 } | 120 } |
| 119 | 121 |
| 120 V4L2VideoDecodeAccelerator::EGLSyncKHRRef::~EGLSyncKHRRef() { | 122 V4L2VideoDecodeAccelerator::EGLSyncKHRRef::~EGLSyncKHRRef() { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 : cleared(cleared), picture(picture) {} | 155 : cleared(cleared), picture(picture) {} |
| 154 | 156 |
| 155 V4L2VideoDecodeAccelerator::PictureRecord::~PictureRecord() {} | 157 V4L2VideoDecodeAccelerator::PictureRecord::~PictureRecord() {} |
| 156 | 158 |
| 157 V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator( | 159 V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator( |
| 158 EGLDisplay egl_display, | 160 EGLDisplay egl_display, |
| 159 EGLContext egl_context, | 161 EGLContext egl_context, |
| 160 const base::WeakPtr<Client>& io_client, | 162 const base::WeakPtr<Client>& io_client, |
| 161 const base::Callback<bool(void)>& make_context_current, | 163 const base::Callback<bool(void)>& make_context_current, |
| 162 const scoped_refptr<V4L2Device>& device, | 164 const scoped_refptr<V4L2Device>& device, |
| 163 const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy) | 165 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) |
| 164 : child_message_loop_proxy_(base::MessageLoopProxy::current()), | 166 : child_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 165 io_message_loop_proxy_(io_message_loop_proxy), | 167 io_task_runner_(io_task_runner), |
| 166 io_client_(io_client), | 168 io_client_(io_client), |
| 167 decoder_thread_("V4L2DecoderThread"), | 169 decoder_thread_("V4L2DecoderThread"), |
| 168 decoder_state_(kUninitialized), | 170 decoder_state_(kUninitialized), |
| 169 device_(device), | 171 device_(device), |
| 170 decoder_delay_bitstream_buffer_id_(-1), | 172 decoder_delay_bitstream_buffer_id_(-1), |
| 171 decoder_current_input_buffer_(-1), | 173 decoder_current_input_buffer_(-1), |
| 172 decoder_decode_buffer_tasks_scheduled_(0), | 174 decoder_decode_buffer_tasks_scheduled_(0), |
| 173 decoder_frames_at_client_(0), | 175 decoder_frames_at_client_(0), |
| 174 decoder_flushing_(false), | 176 decoder_flushing_(false), |
| 175 resolution_change_pending_(false), | 177 resolution_change_pending_(false), |
| (...skipping 26 matching lines...) Expand all Loading... |
| 202 | 204 |
| 203 // These maps have members that should be manually destroyed, e.g. file | 205 // These maps have members that should be manually destroyed, e.g. file |
| 204 // descriptors, mmap() segments, etc. | 206 // descriptors, mmap() segments, etc. |
| 205 DCHECK(input_buffer_map_.empty()); | 207 DCHECK(input_buffer_map_.empty()); |
| 206 DCHECK(output_buffer_map_.empty()); | 208 DCHECK(output_buffer_map_.empty()); |
| 207 } | 209 } |
| 208 | 210 |
| 209 bool V4L2VideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, | 211 bool V4L2VideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, |
| 210 Client* client) { | 212 Client* client) { |
| 211 DVLOG(3) << "Initialize()"; | 213 DVLOG(3) << "Initialize()"; |
| 212 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 214 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 213 DCHECK_EQ(decoder_state_, kUninitialized); | 215 DCHECK_EQ(decoder_state_, kUninitialized); |
| 214 | 216 |
| 215 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); | 217 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); |
| 216 client_ = client_ptr_factory_->GetWeakPtr(); | 218 client_ = client_ptr_factory_->GetWeakPtr(); |
| 217 | 219 |
| 218 switch (profile) { | 220 switch (profile) { |
| 219 case media::H264PROFILE_BASELINE: | 221 case media::H264PROFILE_BASELINE: |
| 220 DVLOG(2) << "Initialize(): profile H264PROFILE_BASELINE"; | 222 DVLOG(2) << "Initialize(): profile H264PROFILE_BASELINE"; |
| 221 break; | 223 break; |
| 222 case media::H264PROFILE_MAIN: | 224 case media::H264PROFILE_MAIN: |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 300 base::IgnoreResult(&V4L2VideoDecodeAccelerator::StartDevicePoll), | 302 base::IgnoreResult(&V4L2VideoDecodeAccelerator::StartDevicePoll), |
| 301 base::Unretained(this))); | 303 base::Unretained(this))); |
| 302 | 304 |
| 303 return true; | 305 return true; |
| 304 } | 306 } |
| 305 | 307 |
| 306 void V4L2VideoDecodeAccelerator::Decode( | 308 void V4L2VideoDecodeAccelerator::Decode( |
| 307 const media::BitstreamBuffer& bitstream_buffer) { | 309 const media::BitstreamBuffer& bitstream_buffer) { |
| 308 DVLOG(1) << "Decode(): input_id=" << bitstream_buffer.id() | 310 DVLOG(1) << "Decode(): input_id=" << bitstream_buffer.id() |
| 309 << ", size=" << bitstream_buffer.size(); | 311 << ", size=" << bitstream_buffer.size(); |
| 310 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 312 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 311 | 313 |
| 312 // DecodeTask() will take care of running a DecodeBufferTask(). | 314 // DecodeTask() will take care of running a DecodeBufferTask(). |
| 313 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 315 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| 314 &V4L2VideoDecodeAccelerator::DecodeTask, base::Unretained(this), | 316 &V4L2VideoDecodeAccelerator::DecodeTask, base::Unretained(this), |
| 315 bitstream_buffer)); | 317 bitstream_buffer)); |
| 316 } | 318 } |
| 317 | 319 |
| 318 void V4L2VideoDecodeAccelerator::AssignPictureBuffers( | 320 void V4L2VideoDecodeAccelerator::AssignPictureBuffers( |
| 319 const std::vector<media::PictureBuffer>& buffers) { | 321 const std::vector<media::PictureBuffer>& buffers) { |
| 320 DVLOG(3) << "AssignPictureBuffers(): buffer_count=" << buffers.size(); | 322 DVLOG(3) << "AssignPictureBuffers(): buffer_count=" << buffers.size(); |
| 321 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 323 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 322 | 324 |
| 323 if (buffers.size() != output_buffer_map_.size()) { | 325 if (buffers.size() != output_buffer_map_.size()) { |
| 324 LOG(ERROR) << "AssignPictureBuffers(): Failed to provide requested picture" | 326 LOG(ERROR) << "AssignPictureBuffers(): Failed to provide requested picture" |
| 325 " buffers. (Got " << buffers.size() | 327 " buffers. (Got " << buffers.size() |
| 326 << ", requested " << output_buffer_map_.size() << ")"; | 328 << ", requested " << output_buffer_map_.size() << ")"; |
| 327 NOTIFY_ERROR(INVALID_ARGUMENT); | 329 NOTIFY_ERROR(INVALID_ARGUMENT); |
| 328 return; | 330 return; |
| 329 } | 331 } |
| 330 | 332 |
| 331 if (!make_context_current_.Run()) { | 333 if (!make_context_current_.Run()) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 DVLOG(3) << "AssignPictureBuffers(): buffer[" << i | 374 DVLOG(3) << "AssignPictureBuffers(): buffer[" << i |
| 373 << "]: picture_id=" << output_record.picture_id; | 375 << "]: picture_id=" << output_record.picture_id; |
| 374 } | 376 } |
| 375 | 377 |
| 376 pictures_assigned_.Signal(); | 378 pictures_assigned_.Signal(); |
| 377 } | 379 } |
| 378 | 380 |
| 379 void V4L2VideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { | 381 void V4L2VideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { |
| 380 DVLOG(3) << "ReusePictureBuffer(): picture_buffer_id=" << picture_buffer_id; | 382 DVLOG(3) << "ReusePictureBuffer(): picture_buffer_id=" << picture_buffer_id; |
| 381 // Must be run on child thread, as we'll insert a sync in the EGL context. | 383 // Must be run on child thread, as we'll insert a sync in the EGL context. |
| 382 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 384 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 383 | 385 |
| 384 if (!make_context_current_.Run()) { | 386 if (!make_context_current_.Run()) { |
| 385 LOG(ERROR) << "ReusePictureBuffer(): could not make context current"; | 387 LOG(ERROR) << "ReusePictureBuffer(): could not make context current"; |
| 386 NOTIFY_ERROR(PLATFORM_FAILURE); | 388 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 387 return; | 389 return; |
| 388 } | 390 } |
| 389 | 391 |
| 390 EGLSyncKHR egl_sync = EGL_NO_SYNC_KHR; | 392 EGLSyncKHR egl_sync = EGL_NO_SYNC_KHR; |
| 391 // TODO(posciak): crbug.com/450898. | 393 // TODO(posciak): crbug.com/450898. |
| 392 #if defined(ARCH_CPU_ARMEL) | 394 #if defined(ARCH_CPU_ARMEL) |
| 393 egl_sync = eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL); | 395 egl_sync = eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL); |
| 394 if (egl_sync == EGL_NO_SYNC_KHR) { | 396 if (egl_sync == EGL_NO_SYNC_KHR) { |
| 395 LOG(ERROR) << "ReusePictureBuffer(): eglCreateSyncKHR() failed"; | 397 LOG(ERROR) << "ReusePictureBuffer(): eglCreateSyncKHR() failed"; |
| 396 NOTIFY_ERROR(PLATFORM_FAILURE); | 398 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 397 return; | 399 return; |
| 398 } | 400 } |
| 399 #endif | 401 #endif |
| 400 | 402 |
| 401 scoped_ptr<EGLSyncKHRRef> egl_sync_ref(new EGLSyncKHRRef( | 403 scoped_ptr<EGLSyncKHRRef> egl_sync_ref(new EGLSyncKHRRef( |
| 402 egl_display_, egl_sync)); | 404 egl_display_, egl_sync)); |
| 403 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 405 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| 404 &V4L2VideoDecodeAccelerator::ReusePictureBufferTask, | 406 &V4L2VideoDecodeAccelerator::ReusePictureBufferTask, |
| 405 base::Unretained(this), picture_buffer_id, base::Passed(&egl_sync_ref))); | 407 base::Unretained(this), picture_buffer_id, base::Passed(&egl_sync_ref))); |
| 406 } | 408 } |
| 407 | 409 |
| 408 void V4L2VideoDecodeAccelerator::Flush() { | 410 void V4L2VideoDecodeAccelerator::Flush() { |
| 409 DVLOG(3) << "Flush()"; | 411 DVLOG(3) << "Flush()"; |
| 410 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 412 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 411 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 413 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| 412 &V4L2VideoDecodeAccelerator::FlushTask, base::Unretained(this))); | 414 &V4L2VideoDecodeAccelerator::FlushTask, base::Unretained(this))); |
| 413 } | 415 } |
| 414 | 416 |
| 415 void V4L2VideoDecodeAccelerator::Reset() { | 417 void V4L2VideoDecodeAccelerator::Reset() { |
| 416 DVLOG(3) << "Reset()"; | 418 DVLOG(3) << "Reset()"; |
| 417 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 419 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 418 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 420 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| 419 &V4L2VideoDecodeAccelerator::ResetTask, base::Unretained(this))); | 421 &V4L2VideoDecodeAccelerator::ResetTask, base::Unretained(this))); |
| 420 } | 422 } |
| 421 | 423 |
| 422 void V4L2VideoDecodeAccelerator::Destroy() { | 424 void V4L2VideoDecodeAccelerator::Destroy() { |
| 423 DVLOG(3) << "Destroy()"; | 425 DVLOG(3) << "Destroy()"; |
| 424 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 426 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 425 | 427 |
| 426 // We're destroying; cancel all callbacks. | 428 // We're destroying; cancel all callbacks. |
| 427 client_ptr_factory_.reset(); | 429 client_ptr_factory_.reset(); |
| 428 weak_this_factory_.InvalidateWeakPtrs(); | 430 weak_this_factory_.InvalidateWeakPtrs(); |
| 429 | 431 |
| 430 // If the decoder thread is running, destroy using posted task. | 432 // If the decoder thread is running, destroy using posted task. |
| 431 if (decoder_thread_.IsRunning()) { | 433 if (decoder_thread_.IsRunning()) { |
| 432 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 434 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| 433 &V4L2VideoDecodeAccelerator::DestroyTask, base::Unretained(this))); | 435 &V4L2VideoDecodeAccelerator::DestroyTask, base::Unretained(this))); |
| 434 pictures_assigned_.Signal(); | 436 pictures_assigned_.Signal(); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 | 493 |
| 492 void V4L2VideoDecodeAccelerator::DecodeTask( | 494 void V4L2VideoDecodeAccelerator::DecodeTask( |
| 493 const media::BitstreamBuffer& bitstream_buffer) { | 495 const media::BitstreamBuffer& bitstream_buffer) { |
| 494 DVLOG(3) << "DecodeTask(): input_id=" << bitstream_buffer.id(); | 496 DVLOG(3) << "DecodeTask(): input_id=" << bitstream_buffer.id(); |
| 495 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 497 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 496 DCHECK_NE(decoder_state_, kUninitialized); | 498 DCHECK_NE(decoder_state_, kUninitialized); |
| 497 TRACE_EVENT1("Video Decoder", "V4L2VDA::DecodeTask", "input_id", | 499 TRACE_EVENT1("Video Decoder", "V4L2VDA::DecodeTask", "input_id", |
| 498 bitstream_buffer.id()); | 500 bitstream_buffer.id()); |
| 499 | 501 |
| 500 scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef( | 502 scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef( |
| 501 io_client_, io_message_loop_proxy_, | 503 io_client_, io_task_runner_, |
| 502 new base::SharedMemory(bitstream_buffer.handle(), true), | 504 new base::SharedMemory(bitstream_buffer.handle(), true), |
| 503 bitstream_buffer.size(), bitstream_buffer.id())); | 505 bitstream_buffer.size(), bitstream_buffer.id())); |
| 504 if (!bitstream_record->shm->Map(bitstream_buffer.size())) { | 506 if (!bitstream_record->shm->Map(bitstream_buffer.size())) { |
| 505 LOG(ERROR) << "Decode(): could not map bitstream_buffer"; | 507 LOG(ERROR) << "Decode(): could not map bitstream_buffer"; |
| 506 NOTIFY_ERROR(UNREADABLE_INPUT); | 508 NOTIFY_ERROR(UNREADABLE_INPUT); |
| 507 return; | 509 return; |
| 508 } | 510 } |
| 509 DVLOG(3) << "DecodeTask(): mapped at=" << bitstream_record->shm->memory(); | 511 DVLOG(3) << "DecodeTask(): mapped at=" << bitstream_record->shm->memory(); |
| 510 | 512 |
| 511 if (decoder_state_ == kResetting || decoder_flushing_) { | 513 if (decoder_state_ == kResetting || decoder_flushing_) { |
| (...skipping 756 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1268 | 1270 |
| 1269 void V4L2VideoDecodeAccelerator::FlushTask() { | 1271 void V4L2VideoDecodeAccelerator::FlushTask() { |
| 1270 DVLOG(3) << "FlushTask()"; | 1272 DVLOG(3) << "FlushTask()"; |
| 1271 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1273 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 1272 TRACE_EVENT0("Video Decoder", "V4L2VDA::FlushTask"); | 1274 TRACE_EVENT0("Video Decoder", "V4L2VDA::FlushTask"); |
| 1273 | 1275 |
| 1274 // Flush outstanding buffers. | 1276 // Flush outstanding buffers. |
| 1275 if (decoder_state_ == kInitialized || decoder_state_ == kAfterReset) { | 1277 if (decoder_state_ == kInitialized || decoder_state_ == kAfterReset) { |
| 1276 // There's nothing in the pipe, so return done immediately. | 1278 // There's nothing in the pipe, so return done immediately. |
| 1277 DVLOG(3) << "FlushTask(): returning flush"; | 1279 DVLOG(3) << "FlushTask(): returning flush"; |
| 1278 child_message_loop_proxy_->PostTask( | 1280 child_task_runner_->PostTask(FROM_HERE, |
| 1279 FROM_HERE, base::Bind(&Client::NotifyFlushDone, client_)); | 1281 base::Bind(&Client::NotifyFlushDone, client_)); |
| 1280 return; | 1282 return; |
| 1281 } else if (decoder_state_ == kError) { | 1283 } else if (decoder_state_ == kError) { |
| 1282 DVLOG(2) << "FlushTask(): early out: kError state"; | 1284 DVLOG(2) << "FlushTask(): early out: kError state"; |
| 1283 return; | 1285 return; |
| 1284 } | 1286 } |
| 1285 | 1287 |
| 1286 // We don't support stacked flushing. | 1288 // We don't support stacked flushing. |
| 1287 DCHECK(!decoder_flushing_); | 1289 DCHECK(!decoder_flushing_); |
| 1288 | 1290 |
| 1289 // Queue up an empty buffer -- this triggers the flush. | 1291 // Queue up an empty buffer -- this triggers the flush. |
| 1290 decoder_input_queue_.push( | 1292 decoder_input_queue_.push( |
| 1291 linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef( | 1293 linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef( |
| 1292 io_client_, io_message_loop_proxy_, NULL, 0, kFlushBufferId))); | 1294 io_client_, io_task_runner_, NULL, 0, kFlushBufferId))); |
| 1293 decoder_flushing_ = true; | 1295 decoder_flushing_ = true; |
| 1294 SendPictureReady(); // Send all pending PictureReady. | 1296 SendPictureReady(); // Send all pending PictureReady. |
| 1295 | 1297 |
| 1296 ScheduleDecodeBufferTaskIfNeeded(); | 1298 ScheduleDecodeBufferTaskIfNeeded(); |
| 1297 } | 1299 } |
| 1298 | 1300 |
| 1299 void V4L2VideoDecodeAccelerator::NotifyFlushDoneIfNeeded() { | 1301 void V4L2VideoDecodeAccelerator::NotifyFlushDoneIfNeeded() { |
| 1300 if (!decoder_flushing_) | 1302 if (!decoder_flushing_) |
| 1301 return; | 1303 return; |
| 1302 | 1304 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1326 // when doing MSE. This should be harmless otherwise. | 1328 // when doing MSE. This should be harmless otherwise. |
| 1327 if (!StopDevicePoll(false)) | 1329 if (!StopDevicePoll(false)) |
| 1328 return; | 1330 return; |
| 1329 | 1331 |
| 1330 if (!StartDevicePoll()) | 1332 if (!StartDevicePoll()) |
| 1331 return; | 1333 return; |
| 1332 | 1334 |
| 1333 decoder_delay_bitstream_buffer_id_ = -1; | 1335 decoder_delay_bitstream_buffer_id_ = -1; |
| 1334 decoder_flushing_ = false; | 1336 decoder_flushing_ = false; |
| 1335 DVLOG(3) << "NotifyFlushDoneIfNeeded(): returning flush"; | 1337 DVLOG(3) << "NotifyFlushDoneIfNeeded(): returning flush"; |
| 1336 child_message_loop_proxy_->PostTask( | 1338 child_task_runner_->PostTask(FROM_HERE, |
| 1337 FROM_HERE, base::Bind(&Client::NotifyFlushDone, client_)); | 1339 base::Bind(&Client::NotifyFlushDone, client_)); |
| 1338 | 1340 |
| 1339 // While we were flushing, we early-outed DecodeBufferTask()s. | 1341 // While we were flushing, we early-outed DecodeBufferTask()s. |
| 1340 ScheduleDecodeBufferTaskIfNeeded(); | 1342 ScheduleDecodeBufferTaskIfNeeded(); |
| 1341 } | 1343 } |
| 1342 | 1344 |
| 1343 void V4L2VideoDecodeAccelerator::ResetTask() { | 1345 void V4L2VideoDecodeAccelerator::ResetTask() { |
| 1344 DVLOG(3) << "ResetTask()"; | 1346 DVLOG(3) << "ResetTask()"; |
| 1345 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1347 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 1346 TRACE_EVENT0("Video Decoder", "V4L2VDA::ResetTask"); | 1348 TRACE_EVENT0("Video Decoder", "V4L2VDA::ResetTask"); |
| 1347 | 1349 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1413 if (output_buffer_map_.empty()) { | 1415 if (output_buffer_map_.empty()) { |
| 1414 // We must have gotten Reset() before we had a chance to request buffers | 1416 // We must have gotten Reset() before we had a chance to request buffers |
| 1415 // from the client. | 1417 // from the client. |
| 1416 decoder_state_ = kInitialized; | 1418 decoder_state_ = kInitialized; |
| 1417 } else { | 1419 } else { |
| 1418 decoder_state_ = kAfterReset; | 1420 decoder_state_ = kAfterReset; |
| 1419 } | 1421 } |
| 1420 | 1422 |
| 1421 decoder_partial_frame_pending_ = false; | 1423 decoder_partial_frame_pending_ = false; |
| 1422 decoder_delay_bitstream_buffer_id_ = -1; | 1424 decoder_delay_bitstream_buffer_id_ = -1; |
| 1423 child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 1425 child_task_runner_->PostTask(FROM_HERE, |
| 1424 &Client::NotifyResetDone, client_)); | 1426 base::Bind(&Client::NotifyResetDone, client_)); |
| 1425 | 1427 |
| 1426 // While we were resetting, we early-outed DecodeBufferTask()s. | 1428 // While we were resetting, we early-outed DecodeBufferTask()s. |
| 1427 ScheduleDecodeBufferTaskIfNeeded(); | 1429 ScheduleDecodeBufferTaskIfNeeded(); |
| 1428 } | 1430 } |
| 1429 | 1431 |
| 1430 void V4L2VideoDecodeAccelerator::DestroyTask() { | 1432 void V4L2VideoDecodeAccelerator::DestroyTask() { |
| 1431 DVLOG(3) << "DestroyTask()"; | 1433 DVLOG(3) << "DestroyTask()"; |
| 1432 TRACE_EVENT0("Video Decoder", "V4L2VDA::DestroyTask"); | 1434 TRACE_EVENT0("Video Decoder", "V4L2VDA::DestroyTask"); |
| 1433 | 1435 |
| 1434 // DestroyTask() should run regardless of decoder_state_. | 1436 // DestroyTask() should run regardless of decoder_state_. |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1549 // Keep input queue. | 1551 // Keep input queue. |
| 1550 if (!StopDevicePoll(true)) | 1552 if (!StopDevicePoll(true)) |
| 1551 return; | 1553 return; |
| 1552 | 1554 |
| 1553 decoder_state_ = kChangingResolution; | 1555 decoder_state_ = kChangingResolution; |
| 1554 DCHECK(resolution_change_pending_); | 1556 DCHECK(resolution_change_pending_); |
| 1555 resolution_change_pending_ = false; | 1557 resolution_change_pending_ = false; |
| 1556 | 1558 |
| 1557 // Post a task to clean up buffers on child thread. This will also ensure | 1559 // Post a task to clean up buffers on child thread. This will also ensure |
| 1558 // that we won't accept ReusePictureBuffer() anymore after that. | 1560 // that we won't accept ReusePictureBuffer() anymore after that. |
| 1559 child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 1561 child_task_runner_->PostTask( |
| 1560 &V4L2VideoDecodeAccelerator::ResolutionChangeDestroyBuffers, | 1562 FROM_HERE, |
| 1561 weak_this_)); | 1563 base::Bind(&V4L2VideoDecodeAccelerator::ResolutionChangeDestroyBuffers, |
| 1564 weak_this_)); |
| 1562 } | 1565 } |
| 1563 | 1566 |
| 1564 void V4L2VideoDecodeAccelerator::FinishResolutionChange() { | 1567 void V4L2VideoDecodeAccelerator::FinishResolutionChange() { |
| 1565 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1568 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 1566 DCHECK_EQ(decoder_state_, kChangingResolution); | 1569 DCHECK_EQ(decoder_state_, kChangingResolution); |
| 1567 DVLOG(3) << "FinishResolutionChange()"; | 1570 DVLOG(3) << "FinishResolutionChange()"; |
| 1568 | 1571 |
| 1569 if (decoder_state_ == kError) { | 1572 if (decoder_state_ == kError) { |
| 1570 DVLOG(2) << "FinishResolutionChange(): early out: kError state"; | 1573 DVLOG(2) << "FinishResolutionChange(): early out: kError state"; |
| 1571 return; | 1574 return; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1617 // All processing should happen on ServiceDeviceTask(), since we shouldn't | 1620 // All processing should happen on ServiceDeviceTask(), since we shouldn't |
| 1618 // touch decoder state from this thread. | 1621 // touch decoder state from this thread. |
| 1619 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 1622 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| 1620 &V4L2VideoDecodeAccelerator::ServiceDeviceTask, | 1623 &V4L2VideoDecodeAccelerator::ServiceDeviceTask, |
| 1621 base::Unretained(this), event_pending)); | 1624 base::Unretained(this), event_pending)); |
| 1622 } | 1625 } |
| 1623 | 1626 |
| 1624 void V4L2VideoDecodeAccelerator::NotifyError(Error error) { | 1627 void V4L2VideoDecodeAccelerator::NotifyError(Error error) { |
| 1625 DVLOG(2) << "NotifyError()"; | 1628 DVLOG(2) << "NotifyError()"; |
| 1626 | 1629 |
| 1627 if (!child_message_loop_proxy_->BelongsToCurrentThread()) { | 1630 if (!child_task_runner_->BelongsToCurrentThread()) { |
| 1628 child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 1631 child_task_runner_->PostTask( |
| 1629 &V4L2VideoDecodeAccelerator::NotifyError, weak_this_, error)); | 1632 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::NotifyError, |
| 1633 weak_this_, error)); |
| 1630 return; | 1634 return; |
| 1631 } | 1635 } |
| 1632 | 1636 |
| 1633 if (client_) { | 1637 if (client_) { |
| 1634 client_->NotifyError(error); | 1638 client_->NotifyError(error); |
| 1635 client_ptr_factory_.reset(); | 1639 client_ptr_factory_.reset(); |
| 1636 } | 1640 } |
| 1637 } | 1641 } |
| 1638 | 1642 |
| 1639 void V4L2VideoDecodeAccelerator::SetErrorState(Error error) { | 1643 void V4L2VideoDecodeAccelerator::SetErrorState(Error error) { |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1864 reqbufs.count = output_dpb_size_ + kDpbOutputBufferExtraCount; | 1868 reqbufs.count = output_dpb_size_ + kDpbOutputBufferExtraCount; |
| 1865 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1869 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 1866 reqbufs.memory = V4L2_MEMORY_MMAP; | 1870 reqbufs.memory = V4L2_MEMORY_MMAP; |
| 1867 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); | 1871 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); |
| 1868 | 1872 |
| 1869 output_buffer_map_.resize(reqbufs.count); | 1873 output_buffer_map_.resize(reqbufs.count); |
| 1870 | 1874 |
| 1871 DVLOG(3) << "CreateOutputBuffers(): ProvidePictureBuffers(): " | 1875 DVLOG(3) << "CreateOutputBuffers(): ProvidePictureBuffers(): " |
| 1872 << "buffer_count=" << output_buffer_map_.size() | 1876 << "buffer_count=" << output_buffer_map_.size() |
| 1873 << ", coded_size=" << coded_size_.ToString(); | 1877 << ", coded_size=" << coded_size_.ToString(); |
| 1874 child_message_loop_proxy_->PostTask(FROM_HERE, | 1878 child_task_runner_->PostTask( |
| 1875 base::Bind(&Client::ProvidePictureBuffers, | 1879 FROM_HERE, base::Bind(&Client::ProvidePictureBuffers, client_, |
| 1876 client_, | 1880 output_buffer_map_.size(), coded_size_, |
| 1877 output_buffer_map_.size(), | 1881 device_->GetTextureTarget())); |
| 1878 coded_size_, | |
| 1879 device_->GetTextureTarget())); | |
| 1880 | 1882 |
| 1881 // Wait for the client to call AssignPictureBuffers() on the Child thread. | 1883 // Wait for the client to call AssignPictureBuffers() on the Child thread. |
| 1882 // We do this, because if we continue decoding without finishing buffer | 1884 // We do this, because if we continue decoding without finishing buffer |
| 1883 // allocation, we may end up Resetting before AssignPictureBuffers arrives, | 1885 // allocation, we may end up Resetting before AssignPictureBuffers arrives, |
| 1884 // resulting in unnecessary complications and subtle bugs. | 1886 // resulting in unnecessary complications and subtle bugs. |
| 1885 // For example, if the client calls Decode(Input1), Reset(), Decode(Input2) | 1887 // For example, if the client calls Decode(Input1), Reset(), Decode(Input2) |
| 1886 // in a sequence, and Decode(Input1) results in us getting here and exiting | 1888 // in a sequence, and Decode(Input1) results in us getting here and exiting |
| 1887 // without waiting, we might end up running Reset{,Done}Task() before | 1889 // without waiting, we might end up running Reset{,Done}Task() before |
| 1888 // AssignPictureBuffers is scheduled, thus cleaning up and pushing buffers | 1890 // AssignPictureBuffers is scheduled, thus cleaning up and pushing buffers |
| 1889 // to the free_output_buffers_ map twice. If we somehow marked buffers as | 1891 // to the free_output_buffers_ map twice. If we somehow marked buffers as |
| 1890 // not ready, we'd need special handling for restarting the second Decode | 1892 // not ready, we'd need special handling for restarting the second Decode |
| 1891 // task and delaying it anyway. | 1893 // task and delaying it anyway. |
| 1892 // Waiting here is not very costly and makes reasoning about different | 1894 // Waiting here is not very costly and makes reasoning about different |
| 1893 // situations much simpler. | 1895 // situations much simpler. |
| 1894 pictures_assigned_.Wait(); | 1896 pictures_assigned_.Wait(); |
| 1895 | 1897 |
| 1896 Enqueue(); | 1898 Enqueue(); |
| 1897 return true; | 1899 return true; |
| 1898 } | 1900 } |
| 1899 | 1901 |
| 1900 void V4L2VideoDecodeAccelerator::DestroyInputBuffers() { | 1902 void V4L2VideoDecodeAccelerator::DestroyInputBuffers() { |
| 1901 DVLOG(3) << "DestroyInputBuffers()"; | 1903 DVLOG(3) << "DestroyInputBuffers()"; |
| 1902 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 1904 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 1903 DCHECK(!input_streamon_); | 1905 DCHECK(!input_streamon_); |
| 1904 | 1906 |
| 1905 for (size_t i = 0; i < input_buffer_map_.size(); ++i) { | 1907 for (size_t i = 0; i < input_buffer_map_.size(); ++i) { |
| 1906 if (input_buffer_map_[i].address != NULL) { | 1908 if (input_buffer_map_[i].address != NULL) { |
| 1907 device_->Munmap(input_buffer_map_[i].address, | 1909 device_->Munmap(input_buffer_map_[i].address, |
| 1908 input_buffer_map_[i].length); | 1910 input_buffer_map_[i].length); |
| 1909 } | 1911 } |
| 1910 } | 1912 } |
| 1911 | 1913 |
| 1912 struct v4l2_requestbuffers reqbufs; | 1914 struct v4l2_requestbuffers reqbufs; |
| 1913 memset(&reqbufs, 0, sizeof(reqbufs)); | 1915 memset(&reqbufs, 0, sizeof(reqbufs)); |
| 1914 reqbufs.count = 0; | 1916 reqbufs.count = 0; |
| 1915 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 1917 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 1916 reqbufs.memory = V4L2_MEMORY_MMAP; | 1918 reqbufs.memory = V4L2_MEMORY_MMAP; |
| 1917 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); | 1919 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); |
| 1918 | 1920 |
| 1919 input_buffer_map_.clear(); | 1921 input_buffer_map_.clear(); |
| 1920 free_input_buffers_.clear(); | 1922 free_input_buffers_.clear(); |
| 1921 } | 1923 } |
| 1922 | 1924 |
| 1923 bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() { | 1925 bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() { |
| 1924 DVLOG(3) << "DestroyOutputBuffers()"; | 1926 DVLOG(3) << "DestroyOutputBuffers()"; |
| 1925 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 1927 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 1926 DCHECK(!output_streamon_); | 1928 DCHECK(!output_streamon_); |
| 1927 bool success = true; | 1929 bool success = true; |
| 1928 | 1930 |
| 1929 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { | 1931 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
| 1930 OutputRecord& output_record = output_buffer_map_[i]; | 1932 OutputRecord& output_record = output_buffer_map_[i]; |
| 1931 | 1933 |
| 1932 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { | 1934 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { |
| 1933 if (device_->DestroyEGLImage(egl_display_, output_record.egl_image) != | 1935 if (device_->DestroyEGLImage(egl_display_, output_record.egl_image) != |
| 1934 EGL_TRUE) { | 1936 EGL_TRUE) { |
| 1935 DVLOG(1) << __func__ << " DestroyEGLImage failed."; | 1937 DVLOG(1) << __func__ << " DestroyEGLImage failed."; |
| 1936 success = false; | 1938 success = false; |
| 1937 } | 1939 } |
| 1938 } | 1940 } |
| 1939 | 1941 |
| 1940 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { | 1942 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { |
| 1941 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { | 1943 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { |
| 1942 DVLOG(1) << __func__ << " eglDestroySyncKHR failed."; | 1944 DVLOG(1) << __func__ << " eglDestroySyncKHR failed."; |
| 1943 success = false; | 1945 success = false; |
| 1944 } | 1946 } |
| 1945 } | 1947 } |
| 1946 | 1948 |
| 1947 DVLOG(1) << "DestroyOutputBuffers(): dismissing PictureBuffer id=" | 1949 DVLOG(1) << "DestroyOutputBuffers(): dismissing PictureBuffer id=" |
| 1948 << output_record.picture_id; | 1950 << output_record.picture_id; |
| 1949 child_message_loop_proxy_->PostTask( | 1951 child_task_runner_->PostTask( |
| 1950 FROM_HERE, | 1952 FROM_HERE, base::Bind(&Client::DismissPictureBuffer, client_, |
| 1951 base::Bind( | 1953 output_record.picture_id)); |
| 1952 &Client::DismissPictureBuffer, client_, output_record.picture_id)); | |
| 1953 } | 1954 } |
| 1954 | 1955 |
| 1955 struct v4l2_requestbuffers reqbufs; | 1956 struct v4l2_requestbuffers reqbufs; |
| 1956 memset(&reqbufs, 0, sizeof(reqbufs)); | 1957 memset(&reqbufs, 0, sizeof(reqbufs)); |
| 1957 reqbufs.count = 0; | 1958 reqbufs.count = 0; |
| 1958 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1959 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 1959 reqbufs.memory = V4L2_MEMORY_MMAP; | 1960 reqbufs.memory = V4L2_MEMORY_MMAP; |
| 1960 if (device_->Ioctl(VIDIOC_REQBUFS, &reqbufs) != 0) { | 1961 if (device_->Ioctl(VIDIOC_REQBUFS, &reqbufs) != 0) { |
| 1961 PLOG(ERROR) << "DestroyOutputBuffers() ioctl() failed: VIDIOC_REQBUFS"; | 1962 PLOG(ERROR) << "DestroyOutputBuffers() ioctl() failed: VIDIOC_REQBUFS"; |
| 1962 success = false; | 1963 success = false; |
| 1963 } | 1964 } |
| 1964 | 1965 |
| 1965 output_buffer_map_.clear(); | 1966 output_buffer_map_.clear(); |
| 1966 while (!free_output_buffers_.empty()) | 1967 while (!free_output_buffers_.empty()) |
| 1967 free_output_buffers_.pop(); | 1968 free_output_buffers_.pop(); |
| 1968 | 1969 |
| 1969 return success; | 1970 return success; |
| 1970 } | 1971 } |
| 1971 | 1972 |
| 1972 void V4L2VideoDecodeAccelerator::ResolutionChangeDestroyBuffers() { | 1973 void V4L2VideoDecodeAccelerator::ResolutionChangeDestroyBuffers() { |
| 1973 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 1974 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 1974 DVLOG(3) << "ResolutionChangeDestroyBuffers()"; | 1975 DVLOG(3) << "ResolutionChangeDestroyBuffers()"; |
| 1975 | 1976 |
| 1976 if (!DestroyOutputBuffers()) { | 1977 if (!DestroyOutputBuffers()) { |
| 1977 LOG(ERROR) << __func__ << " Failed destroying output buffers."; | 1978 LOG(ERROR) << __func__ << " Failed destroying output buffers."; |
| 1978 NOTIFY_ERROR(PLATFORM_FAILURE); | 1979 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1979 return; | 1980 return; |
| 1980 } | 1981 } |
| 1981 | 1982 |
| 1982 // Finish resolution change on decoder thread. | 1983 // Finish resolution change on decoder thread. |
| 1983 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 1984 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| 1984 &V4L2VideoDecodeAccelerator::FinishResolutionChange, | 1985 &V4L2VideoDecodeAccelerator::FinishResolutionChange, |
| 1985 base::Unretained(this))); | 1986 base::Unretained(this))); |
| 1986 } | 1987 } |
| 1987 | 1988 |
| 1988 void V4L2VideoDecodeAccelerator::SendPictureReady() { | 1989 void V4L2VideoDecodeAccelerator::SendPictureReady() { |
| 1989 DVLOG(3) << "SendPictureReady()"; | 1990 DVLOG(3) << "SendPictureReady()"; |
| 1990 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1991 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 1991 bool resetting_or_flushing = | 1992 bool resetting_or_flushing = |
| 1992 (decoder_state_ == kResetting || decoder_flushing_); | 1993 (decoder_state_ == kResetting || decoder_flushing_); |
| 1993 while (pending_picture_ready_.size() > 0) { | 1994 while (pending_picture_ready_.size() > 0) { |
| 1994 bool cleared = pending_picture_ready_.front().cleared; | 1995 bool cleared = pending_picture_ready_.front().cleared; |
| 1995 const media::Picture& picture = pending_picture_ready_.front().picture; | 1996 const media::Picture& picture = pending_picture_ready_.front().picture; |
| 1996 if (cleared && picture_clearing_count_ == 0) { | 1997 if (cleared && picture_clearing_count_ == 0) { |
| 1997 // This picture is cleared. Post it to IO thread to reduce latency. This | 1998 // This picture is cleared. Post it to IO thread to reduce latency. This |
| 1998 // should be the case after all pictures are cleared at the beginning. | 1999 // should be the case after all pictures are cleared at the beginning. |
| 1999 io_message_loop_proxy_->PostTask( | 2000 io_task_runner_->PostTask( |
| 2000 FROM_HERE, base::Bind(&Client::PictureReady, io_client_, picture)); | 2001 FROM_HERE, base::Bind(&Client::PictureReady, io_client_, picture)); |
| 2001 pending_picture_ready_.pop(); | 2002 pending_picture_ready_.pop(); |
| 2002 } else if (!cleared || resetting_or_flushing) { | 2003 } else if (!cleared || resetting_or_flushing) { |
| 2003 DVLOG(3) << "SendPictureReady()" | 2004 DVLOG(3) << "SendPictureReady()" |
| 2004 << ". cleared=" << pending_picture_ready_.front().cleared | 2005 << ". cleared=" << pending_picture_ready_.front().cleared |
| 2005 << ", decoder_state_=" << decoder_state_ | 2006 << ", decoder_state_=" << decoder_state_ |
| 2006 << ", decoder_flushing_=" << decoder_flushing_ | 2007 << ", decoder_flushing_=" << decoder_flushing_ |
| 2007 << ", picture_clearing_count_=" << picture_clearing_count_; | 2008 << ", picture_clearing_count_=" << picture_clearing_count_; |
| 2008 // If the picture is not cleared, post it to the child thread because it | 2009 // If the picture is not cleared, post it to the child thread because it |
| 2009 // has to be cleared in the child thread. A picture only needs to be | 2010 // has to be cleared in the child thread. A picture only needs to be |
| 2010 // cleared once. If the decoder is resetting or flushing, send all | 2011 // cleared once. If the decoder is resetting or flushing, send all |
| 2011 // pictures to ensure PictureReady arrive before reset or flush done. | 2012 // pictures to ensure PictureReady arrive before reset or flush done. |
| 2012 child_message_loop_proxy_->PostTaskAndReply( | 2013 child_task_runner_->PostTaskAndReply( |
| 2013 FROM_HERE, | 2014 FROM_HERE, base::Bind(&Client::PictureReady, client_, picture), |
| 2014 base::Bind(&Client::PictureReady, client_, picture), | |
| 2015 // Unretained is safe. If Client::PictureReady gets to run, |this| is | 2015 // Unretained is safe. If Client::PictureReady gets to run, |this| is |
| 2016 // alive. Destroy() will wait the decode thread to finish. | 2016 // alive. Destroy() will wait the decode thread to finish. |
| 2017 base::Bind(&V4L2VideoDecodeAccelerator::PictureCleared, | 2017 base::Bind(&V4L2VideoDecodeAccelerator::PictureCleared, |
| 2018 base::Unretained(this))); | 2018 base::Unretained(this))); |
| 2019 picture_clearing_count_++; | 2019 picture_clearing_count_++; |
| 2020 pending_picture_ready_.pop(); | 2020 pending_picture_ready_.pop(); |
| 2021 } else { | 2021 } else { |
| 2022 // This picture is cleared. But some pictures are about to be cleared on | 2022 // This picture is cleared. But some pictures are about to be cleared on |
| 2023 // the child thread. To preserve the order, do not send this until those | 2023 // the child thread. To preserve the order, do not send this until those |
| 2024 // pictures are cleared. | 2024 // pictures are cleared. |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2057 gfx::Size new_coded_size(base::checked_cast<int>(format.fmt.pix_mp.width), | 2057 gfx::Size new_coded_size(base::checked_cast<int>(format.fmt.pix_mp.width), |
| 2058 base::checked_cast<int>(format.fmt.pix_mp.height)); | 2058 base::checked_cast<int>(format.fmt.pix_mp.height)); |
| 2059 if (coded_size_ != new_coded_size) { | 2059 if (coded_size_ != new_coded_size) { |
| 2060 DVLOG(3) << "IsResolutionChangeNecessary(): Resolution change detected"; | 2060 DVLOG(3) << "IsResolutionChangeNecessary(): Resolution change detected"; |
| 2061 return true; | 2061 return true; |
| 2062 } | 2062 } |
| 2063 return false; | 2063 return false; |
| 2064 } | 2064 } |
| 2065 | 2065 |
| 2066 } // namespace content | 2066 } // namespace content |
| OLD | NEW |