| 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 <string.h> | 10 #include <string.h> |
| 11 #include <sys/eventfd.h> | 11 #include <sys/eventfd.h> |
| 12 #include <sys/ioctl.h> | 12 #include <sys/ioctl.h> |
| 13 #include <sys/mman.h> | 13 #include <sys/mman.h> |
| 14 | 14 |
| 15 #include "base/bind.h" | 15 #include "base/bind.h" |
| 16 #include "base/command_line.h" | 16 #include "base/command_line.h" |
| 17 #include "base/macros.h" | 17 #include "base/macros.h" |
| 18 #include "base/memory/shared_memory.h" | 18 #include "base/memory/shared_memory.h" |
| 19 #include "base/message_loop/message_loop.h" | 19 #include "base/message_loop/message_loop.h" |
| 20 #include "base/numerics/safe_conversions.h" | 20 #include "base/numerics/safe_conversions.h" |
| 21 #include "base/thread_task_runner_handle.h" | 21 #include "base/thread_task_runner_handle.h" |
| 22 #include "base/trace_event/trace_event.h" | 22 #include "base/trace_event/trace_event.h" |
| 23 #include "build/build_config.h" | 23 #include "build/build_config.h" |
| 24 #include "content/common/gpu/media/v4l2_video_decode_accelerator.h" | 24 #include "content/common/gpu/media/v4l2_video_decode_accelerator.h" |
| 25 #include "media/base/media_switches.h" | 25 #include "media/base/media_switches.h" |
| 26 #include "media/filters/h264_parser.h" | 26 #include "media/filters/h264_parser.h" |
| 27 #include "ui/gfx/geometry/rect.h" | 27 #include "ui/gfx/geometry/rect.h" |
| 28 #include "ui/gl/gl_context.h" |
| 28 #include "ui/gl/scoped_binders.h" | 29 #include "ui/gl/scoped_binders.h" |
| 29 | 30 |
| 30 #define NOTIFY_ERROR(x) \ | 31 #define NOTIFY_ERROR(x) \ |
| 31 do { \ | 32 do { \ |
| 32 LOG(ERROR) << "Setting error state:" << x; \ | 33 LOG(ERROR) << "Setting error state:" << x; \ |
| 33 SetErrorState(x); \ | 34 SetErrorState(x); \ |
| 34 } while (0) | 35 } while (0) |
| 35 | 36 |
| 36 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_str) \ | 37 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_str) \ |
| 37 do { \ | 38 do { \ |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 150 | 151 |
| 151 V4L2VideoDecodeAccelerator::PictureRecord::PictureRecord( | 152 V4L2VideoDecodeAccelerator::PictureRecord::PictureRecord( |
| 152 bool cleared, | 153 bool cleared, |
| 153 const media::Picture& picture) | 154 const media::Picture& picture) |
| 154 : cleared(cleared), picture(picture) {} | 155 : cleared(cleared), picture(picture) {} |
| 155 | 156 |
| 156 V4L2VideoDecodeAccelerator::PictureRecord::~PictureRecord() {} | 157 V4L2VideoDecodeAccelerator::PictureRecord::~PictureRecord() {} |
| 157 | 158 |
| 158 V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator( | 159 V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator( |
| 159 EGLDisplay egl_display, | 160 EGLDisplay egl_display, |
| 160 EGLContext egl_context, | 161 const gpu_vda_helpers::GetGLContextCb& get_gl_context_cb, |
| 161 const base::WeakPtr<Client>& io_client, | 162 const gpu_vda_helpers::MakeGLContextCurrentCb& make_context_current_cb, |
| 162 const base::Callback<bool(void)>& make_context_current, | 163 const scoped_refptr<V4L2Device>& device) |
| 163 const scoped_refptr<V4L2Device>& device, | |
| 164 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) | |
| 165 : child_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 164 : child_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 166 io_task_runner_(io_task_runner), | |
| 167 io_client_(io_client), | |
| 168 decoder_thread_("V4L2DecoderThread"), | 165 decoder_thread_("V4L2DecoderThread"), |
| 169 decoder_state_(kUninitialized), | 166 decoder_state_(kUninitialized), |
| 170 device_(device), | 167 device_(device), |
| 171 decoder_delay_bitstream_buffer_id_(-1), | 168 decoder_delay_bitstream_buffer_id_(-1), |
| 172 decoder_current_input_buffer_(-1), | 169 decoder_current_input_buffer_(-1), |
| 173 decoder_decode_buffer_tasks_scheduled_(0), | 170 decoder_decode_buffer_tasks_scheduled_(0), |
| 174 decoder_frames_at_client_(0), | 171 decoder_frames_at_client_(0), |
| 175 decoder_flushing_(false), | 172 decoder_flushing_(false), |
| 176 resolution_change_reset_pending_(false), | 173 resolution_change_reset_pending_(false), |
| 177 decoder_partial_frame_pending_(false), | 174 decoder_partial_frame_pending_(false), |
| 178 input_streamon_(false), | 175 input_streamon_(false), |
| 179 input_buffer_queued_count_(0), | 176 input_buffer_queued_count_(0), |
| 180 output_streamon_(false), | 177 output_streamon_(false), |
| 181 output_buffer_queued_count_(0), | 178 output_buffer_queued_count_(0), |
| 182 output_dpb_size_(0), | 179 output_dpb_size_(0), |
| 183 output_planes_count_(0), | 180 output_planes_count_(0), |
| 184 picture_clearing_count_(0), | 181 picture_clearing_count_(0), |
| 185 pictures_assigned_(false, false), | 182 pictures_assigned_(false, false), |
| 186 device_poll_thread_("V4L2DevicePollThread"), | 183 device_poll_thread_("V4L2DevicePollThread"), |
| 187 make_context_current_(make_context_current), | |
| 188 egl_display_(egl_display), | 184 egl_display_(egl_display), |
| 189 egl_context_(egl_context), | 185 get_gl_context_cb_(get_gl_context_cb), |
| 186 make_context_current_cb_(make_context_current_cb), |
| 190 video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), | 187 video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), |
| 191 output_format_fourcc_(0), | 188 output_format_fourcc_(0), |
| 192 weak_this_factory_(this) { | 189 weak_this_factory_(this) { |
| 193 weak_this_ = weak_this_factory_.GetWeakPtr(); | 190 weak_this_ = weak_this_factory_.GetWeakPtr(); |
| 194 } | 191 } |
| 195 | 192 |
| 196 V4L2VideoDecodeAccelerator::~V4L2VideoDecodeAccelerator() { | 193 V4L2VideoDecodeAccelerator::~V4L2VideoDecodeAccelerator() { |
| 197 DCHECK(!decoder_thread_.IsRunning()); | 194 DCHECK(!decoder_thread_.IsRunning()); |
| 198 DCHECK(!device_poll_thread_.IsRunning()); | 195 DCHECK(!device_poll_thread_.IsRunning()); |
| 199 | 196 |
| 200 DestroyInputBuffers(); | 197 DestroyInputBuffers(); |
| 201 DestroyOutputBuffers(); | 198 DestroyOutputBuffers(); |
| 202 | 199 |
| 203 // These maps have members that should be manually destroyed, e.g. file | 200 // These maps have members that should be manually destroyed, e.g. file |
| 204 // descriptors, mmap() segments, etc. | 201 // descriptors, mmap() segments, etc. |
| 205 DCHECK(input_buffer_map_.empty()); | 202 DCHECK(input_buffer_map_.empty()); |
| 206 DCHECK(output_buffer_map_.empty()); | 203 DCHECK(output_buffer_map_.empty()); |
| 207 } | 204 } |
| 208 | 205 |
| 209 bool V4L2VideoDecodeAccelerator::Initialize(const Config& config, | 206 bool V4L2VideoDecodeAccelerator::Initialize(const Config& config, |
| 210 Client* client) { | 207 Client* client) { |
| 211 DVLOG(3) << "Initialize()"; | 208 DVLOG(3) << "Initialize()"; |
| 212 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 209 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 213 DCHECK_EQ(decoder_state_, kUninitialized); | 210 DCHECK_EQ(decoder_state_, kUninitialized); |
| 214 | 211 |
| 212 if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { |
| 213 NOTREACHED() << "GL callbacks are required for this VDA"; |
| 214 return false; |
| 215 } |
| 216 |
| 215 if (config.is_encrypted) { | 217 if (config.is_encrypted) { |
| 216 NOTREACHED() << "Encrypted streams are not supported for this VDA"; | 218 NOTREACHED() << "Encrypted streams are not supported for this VDA"; |
| 217 return false; | 219 return false; |
| 218 } | 220 } |
| 219 | 221 |
| 220 if (!device_->SupportsDecodeProfileForV4L2PixelFormats( | 222 if (!device_->SupportsDecodeProfileForV4L2PixelFormats( |
| 221 config.profile, arraysize(supported_input_fourccs_), | 223 config.profile, arraysize(supported_input_fourccs_), |
| 222 supported_input_fourccs_)) { | 224 supported_input_fourccs_)) { |
| 223 DVLOG(1) << "Initialize(): unsupported profile=" << config.profile; | 225 DVLOG(1) << "Initialize(): unsupported profile=" << config.profile; |
| 224 return false; | 226 return false; |
| 225 } | 227 } |
| 226 | 228 |
| 227 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); | 229 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); |
| 228 client_ = client_ptr_factory_->GetWeakPtr(); | 230 client_ = client_ptr_factory_->GetWeakPtr(); |
| 231 // If we haven't been set up to decode on separate thread via |
| 232 // TryToSetupDecodeOnSeparateThread(), use the main thread/client for |
| 233 // decode tasks. |
| 234 if (!decode_task_runner_) { |
| 235 decode_task_runner_ = child_task_runner_; |
| 236 DCHECK(!decode_client_); |
| 237 decode_client_ = client_; |
| 238 } |
| 229 | 239 |
| 230 video_profile_ = config.profile; | 240 video_profile_ = config.profile; |
| 231 | 241 |
| 232 if (egl_display_ == EGL_NO_DISPLAY) { | 242 if (egl_display_ == EGL_NO_DISPLAY) { |
| 233 LOG(ERROR) << "Initialize(): could not get EGLDisplay"; | 243 LOG(ERROR) << "Initialize(): could not get EGLDisplay"; |
| 234 return false; | 244 return false; |
| 235 } | 245 } |
| 236 | 246 |
| 237 // We need the context to be initialized to query extensions. | 247 // We need the context to be initialized to query extensions. |
| 238 if (!make_context_current_.Run()) { | 248 if (!make_context_current_cb_.Run()) { |
| 239 LOG(ERROR) << "Initialize(): could not make context current"; | 249 LOG(ERROR) << "Initialize(): could not make context current"; |
| 240 return false; | 250 return false; |
| 241 } | 251 } |
| 242 | 252 |
| 243 // TODO(posciak): crbug.com/450898. | 253 // TODO(posciak): crbug.com/450898. |
| 244 #if defined(ARCH_CPU_ARMEL) | 254 #if defined(ARCH_CPU_ARMEL) |
| 245 if (!gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync) { | 255 if (!gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync) { |
| 246 LOG(ERROR) << "Initialize(): context does not have EGL_KHR_fence_sync"; | 256 LOG(ERROR) << "Initialize(): context does not have EGL_KHR_fence_sync"; |
| 247 return false; | 257 return false; |
| 248 } | 258 } |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 289 base::IgnoreResult(&V4L2VideoDecodeAccelerator::StartDevicePoll), | 299 base::IgnoreResult(&V4L2VideoDecodeAccelerator::StartDevicePoll), |
| 290 base::Unretained(this))); | 300 base::Unretained(this))); |
| 291 | 301 |
| 292 return true; | 302 return true; |
| 293 } | 303 } |
| 294 | 304 |
| 295 void V4L2VideoDecodeAccelerator::Decode( | 305 void V4L2VideoDecodeAccelerator::Decode( |
| 296 const media::BitstreamBuffer& bitstream_buffer) { | 306 const media::BitstreamBuffer& bitstream_buffer) { |
| 297 DVLOG(1) << "Decode(): input_id=" << bitstream_buffer.id() | 307 DVLOG(1) << "Decode(): input_id=" << bitstream_buffer.id() |
| 298 << ", size=" << bitstream_buffer.size(); | 308 << ", size=" << bitstream_buffer.size(); |
| 299 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 309 DCHECK(decode_task_runner_->BelongsToCurrentThread()); |
| 300 | 310 |
| 301 if (bitstream_buffer.id() < 0) { | 311 if (bitstream_buffer.id() < 0) { |
| 302 LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id(); | 312 LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id(); |
| 303 if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle())) | 313 if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle())) |
| 304 base::SharedMemory::CloseHandle(bitstream_buffer.handle()); | 314 base::SharedMemory::CloseHandle(bitstream_buffer.handle()); |
| 305 NOTIFY_ERROR(INVALID_ARGUMENT); | 315 NOTIFY_ERROR(INVALID_ARGUMENT); |
| 306 return; | 316 return; |
| 307 } | 317 } |
| 308 | 318 |
| 309 // DecodeTask() will take care of running a DecodeBufferTask(). | 319 // DecodeTask() will take care of running a DecodeBufferTask(). |
| (...skipping 11 matching lines...) Expand all Loading... |
| 321 output_dpb_size_ + kDpbOutputBufferExtraCount; | 331 output_dpb_size_ + kDpbOutputBufferExtraCount; |
| 322 | 332 |
| 323 if (buffers.size() < req_buffer_count) { | 333 if (buffers.size() < req_buffer_count) { |
| 324 LOG(ERROR) << "AssignPictureBuffers(): Failed to provide requested picture" | 334 LOG(ERROR) << "AssignPictureBuffers(): Failed to provide requested picture" |
| 325 " buffers. (Got " << buffers.size() | 335 " buffers. (Got " << buffers.size() |
| 326 << ", requested " << req_buffer_count << ")"; | 336 << ", requested " << req_buffer_count << ")"; |
| 327 NOTIFY_ERROR(INVALID_ARGUMENT); | 337 NOTIFY_ERROR(INVALID_ARGUMENT); |
| 328 return; | 338 return; |
| 329 } | 339 } |
| 330 | 340 |
| 331 if (!make_context_current_.Run()) { | 341 gfx::GLContext* gl_context = get_gl_context_cb_.Run(); |
| 342 if (!gl_context || !make_context_current_cb_.Run()) { |
| 332 LOG(ERROR) << "AssignPictureBuffers(): could not make context current"; | 343 LOG(ERROR) << "AssignPictureBuffers(): could not make context current"; |
| 333 NOTIFY_ERROR(PLATFORM_FAILURE); | 344 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 334 return; | 345 return; |
| 335 } | 346 } |
| 336 | 347 |
| 337 gfx::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); | 348 gfx::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); |
| 338 | 349 |
| 339 // It's safe to manipulate all the buffer state here, because the decoder | 350 // It's safe to manipulate all the buffer state here, because the decoder |
| 340 // thread is waiting on pictures_assigned_. | 351 // thread is waiting on pictures_assigned_. |
| 341 | 352 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 361 | 372 |
| 362 OutputRecord& output_record = output_buffer_map_[i]; | 373 OutputRecord& output_record = output_buffer_map_[i]; |
| 363 DCHECK(!output_record.at_device); | 374 DCHECK(!output_record.at_device); |
| 364 DCHECK(!output_record.at_client); | 375 DCHECK(!output_record.at_client); |
| 365 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); | 376 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); |
| 366 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | 377 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
| 367 DCHECK_EQ(output_record.picture_id, -1); | 378 DCHECK_EQ(output_record.picture_id, -1); |
| 368 DCHECK_EQ(output_record.cleared, false); | 379 DCHECK_EQ(output_record.cleared, false); |
| 369 | 380 |
| 370 EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_, | 381 EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_, |
| 371 egl_context_, | 382 gl_context->GetHandle(), |
| 372 buffers[i].texture_id(), | 383 buffers[i].texture_id(), |
| 373 coded_size_, | 384 coded_size_, |
| 374 i, | 385 i, |
| 375 output_format_fourcc_, | 386 output_format_fourcc_, |
| 376 output_planes_count_); | 387 output_planes_count_); |
| 377 if (egl_image == EGL_NO_IMAGE_KHR) { | 388 if (egl_image == EGL_NO_IMAGE_KHR) { |
| 378 LOG(ERROR) << "AssignPictureBuffers(): could not create EGLImageKHR"; | 389 LOG(ERROR) << "AssignPictureBuffers(): could not create EGLImageKHR"; |
| 379 // Ownership of EGLImages allocated in previous iterations of this loop | 390 // Ownership of EGLImages allocated in previous iterations of this loop |
| 380 // has been transferred to output_buffer_map_. After we error-out here | 391 // has been transferred to output_buffer_map_. After we error-out here |
| 381 // the destructor will handle their cleanup. | 392 // the destructor will handle their cleanup. |
| 382 NOTIFY_ERROR(PLATFORM_FAILURE); | 393 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 383 return; | 394 return; |
| 384 } | 395 } |
| 385 | 396 |
| 386 output_record.egl_image = egl_image; | 397 output_record.egl_image = egl_image; |
| 387 output_record.picture_id = buffers[i].id(); | 398 output_record.picture_id = buffers[i].id(); |
| 388 free_output_buffers_.push(i); | 399 free_output_buffers_.push(i); |
| 389 DVLOG(3) << "AssignPictureBuffers(): buffer[" << i | 400 DVLOG(3) << "AssignPictureBuffers(): buffer[" << i |
| 390 << "]: picture_id=" << output_record.picture_id; | 401 << "]: picture_id=" << output_record.picture_id; |
| 391 } | 402 } |
| 392 | 403 |
| 393 pictures_assigned_.Signal(); | 404 pictures_assigned_.Signal(); |
| 394 } | 405 } |
| 395 | 406 |
| 396 void V4L2VideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_buffer_id) { | 407 void V4L2VideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_buffer_id) { |
| 397 DVLOG(3) << "ReusePictureBuffer(): picture_buffer_id=" << picture_buffer_id; | 408 DVLOG(3) << "ReusePictureBuffer(): picture_buffer_id=" << picture_buffer_id; |
| 398 // Must be run on child thread, as we'll insert a sync in the EGL context. | 409 // Must be run on child thread, as we'll insert a sync in the EGL context. |
| 399 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 410 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 400 | 411 |
| 401 if (!make_context_current_.Run()) { | 412 if (!make_context_current_cb_.Run()) { |
| 402 LOG(ERROR) << "ReusePictureBuffer(): could not make context current"; | 413 LOG(ERROR) << "ReusePictureBuffer(): could not make context current"; |
| 403 NOTIFY_ERROR(PLATFORM_FAILURE); | 414 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 404 return; | 415 return; |
| 405 } | 416 } |
| 406 | 417 |
| 407 EGLSyncKHR egl_sync = EGL_NO_SYNC_KHR; | 418 EGLSyncKHR egl_sync = EGL_NO_SYNC_KHR; |
| 408 // TODO(posciak): crbug.com/450898. | 419 // TODO(posciak): crbug.com/450898. |
| 409 #if defined(ARCH_CPU_ARMEL) | 420 #if defined(ARCH_CPU_ARMEL) |
| 410 egl_sync = eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL); | 421 egl_sync = eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL); |
| 411 if (egl_sync == EGL_NO_SYNC_KHR) { | 422 if (egl_sync == EGL_NO_SYNC_KHR) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 452 // DestroyTask() will cause the decoder_thread_ to flush all tasks. | 463 // DestroyTask() will cause the decoder_thread_ to flush all tasks. |
| 453 decoder_thread_.Stop(); | 464 decoder_thread_.Stop(); |
| 454 } else { | 465 } else { |
| 455 // Otherwise, call the destroy task directly. | 466 // Otherwise, call the destroy task directly. |
| 456 DestroyTask(); | 467 DestroyTask(); |
| 457 } | 468 } |
| 458 | 469 |
| 459 delete this; | 470 delete this; |
| 460 } | 471 } |
| 461 | 472 |
| 462 bool V4L2VideoDecodeAccelerator::CanDecodeOnIOThread() { return true; } | 473 bool V4L2VideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( |
| 474 const base::WeakPtr<Client>& decode_client, |
| 475 const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { |
| 476 decode_client_ = decode_client_; |
| 477 decode_task_runner_ = decode_task_runner; |
| 478 return true; |
| 479 } |
| 463 | 480 |
| 464 // static | 481 // static |
| 465 media::VideoDecodeAccelerator::SupportedProfiles | 482 media::VideoDecodeAccelerator::SupportedProfiles |
| 466 V4L2VideoDecodeAccelerator::GetSupportedProfiles() { | 483 V4L2VideoDecodeAccelerator::GetSupportedProfiles() { |
| 467 scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); | 484 scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); |
| 468 if (!device) | 485 if (!device) |
| 469 return SupportedProfiles(); | 486 return SupportedProfiles(); |
| 470 | 487 |
| 471 return device->GetSupportedDecodeProfiles(arraysize(supported_input_fourccs_), | 488 return device->GetSupportedDecodeProfiles(arraysize(supported_input_fourccs_), |
| 472 supported_input_fourccs_); | 489 supported_input_fourccs_); |
| 473 } | 490 } |
| 474 | 491 |
| 475 void V4L2VideoDecodeAccelerator::DecodeTask( | 492 void V4L2VideoDecodeAccelerator::DecodeTask( |
| 476 const media::BitstreamBuffer& bitstream_buffer) { | 493 const media::BitstreamBuffer& bitstream_buffer) { |
| 477 DVLOG(3) << "DecodeTask(): input_id=" << bitstream_buffer.id(); | 494 DVLOG(3) << "DecodeTask(): input_id=" << bitstream_buffer.id(); |
| 478 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 495 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 479 DCHECK_NE(decoder_state_, kUninitialized); | 496 DCHECK_NE(decoder_state_, kUninitialized); |
| 480 TRACE_EVENT1("Video Decoder", "V4L2VDA::DecodeTask", "input_id", | 497 TRACE_EVENT1("Video Decoder", "V4L2VDA::DecodeTask", "input_id", |
| 481 bitstream_buffer.id()); | 498 bitstream_buffer.id()); |
| 482 | 499 |
| 483 scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef( | 500 scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef( |
| 484 io_client_, io_task_runner_, | 501 decode_client_, decode_task_runner_, |
| 485 new base::SharedMemory(bitstream_buffer.handle(), true), | 502 new base::SharedMemory(bitstream_buffer.handle(), true), |
| 486 bitstream_buffer.size(), bitstream_buffer.id())); | 503 bitstream_buffer.size(), bitstream_buffer.id())); |
| 487 if (!bitstream_record->shm->Map(bitstream_buffer.size())) { | 504 if (!bitstream_record->shm->Map(bitstream_buffer.size())) { |
| 488 LOG(ERROR) << "Decode(): could not map bitstream_buffer"; | 505 LOG(ERROR) << "Decode(): could not map bitstream_buffer"; |
| 489 NOTIFY_ERROR(UNREADABLE_INPUT); | 506 NOTIFY_ERROR(UNREADABLE_INPUT); |
| 490 return; | 507 return; |
| 491 } | 508 } |
| 492 DVLOG(3) << "DecodeTask(): mapped at=" << bitstream_record->shm->memory(); | 509 DVLOG(3) << "DecodeTask(): mapped at=" << bitstream_record->shm->memory(); |
| 493 | 510 |
| 494 if (decoder_state_ == kResetting || decoder_flushing_) { | 511 if (decoder_state_ == kResetting || decoder_flushing_) { |
| (...skipping 774 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1269 DVLOG(2) << "FlushTask(): early out: kError state"; | 1286 DVLOG(2) << "FlushTask(): early out: kError state"; |
| 1270 return; | 1287 return; |
| 1271 } | 1288 } |
| 1272 | 1289 |
| 1273 // We don't support stacked flushing. | 1290 // We don't support stacked flushing. |
| 1274 DCHECK(!decoder_flushing_); | 1291 DCHECK(!decoder_flushing_); |
| 1275 | 1292 |
| 1276 // Queue up an empty buffer -- this triggers the flush. | 1293 // Queue up an empty buffer -- this triggers the flush. |
| 1277 decoder_input_queue_.push( | 1294 decoder_input_queue_.push( |
| 1278 linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef( | 1295 linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef( |
| 1279 io_client_, io_task_runner_, NULL, 0, kFlushBufferId))); | 1296 decode_client_, decode_task_runner_, NULL, 0, kFlushBufferId))); |
| 1280 decoder_flushing_ = true; | 1297 decoder_flushing_ = true; |
| 1281 SendPictureReady(); // Send all pending PictureReady. | 1298 SendPictureReady(); // Send all pending PictureReady. |
| 1282 | 1299 |
| 1283 ScheduleDecodeBufferTaskIfNeeded(); | 1300 ScheduleDecodeBufferTaskIfNeeded(); |
| 1284 } | 1301 } |
| 1285 | 1302 |
| 1286 void V4L2VideoDecodeAccelerator::NotifyFlushDoneIfNeeded() { | 1303 void V4L2VideoDecodeAccelerator::NotifyFlushDoneIfNeeded() { |
| 1287 if (!decoder_flushing_) | 1304 if (!decoder_flushing_) |
| 1288 return; | 1305 return; |
| 1289 | 1306 |
| (...skipping 702 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1992 | 2009 |
| 1993 void V4L2VideoDecodeAccelerator::SendPictureReady() { | 2010 void V4L2VideoDecodeAccelerator::SendPictureReady() { |
| 1994 DVLOG(3) << "SendPictureReady()"; | 2011 DVLOG(3) << "SendPictureReady()"; |
| 1995 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 2012 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 1996 bool resetting_or_flushing = | 2013 bool resetting_or_flushing = |
| 1997 (decoder_state_ == kResetting || decoder_flushing_); | 2014 (decoder_state_ == kResetting || decoder_flushing_); |
| 1998 while (pending_picture_ready_.size() > 0) { | 2015 while (pending_picture_ready_.size() > 0) { |
| 1999 bool cleared = pending_picture_ready_.front().cleared; | 2016 bool cleared = pending_picture_ready_.front().cleared; |
| 2000 const media::Picture& picture = pending_picture_ready_.front().picture; | 2017 const media::Picture& picture = pending_picture_ready_.front().picture; |
| 2001 if (cleared && picture_clearing_count_ == 0) { | 2018 if (cleared && picture_clearing_count_ == 0) { |
| 2002 // This picture is cleared. Post it to IO thread to reduce latency. This | 2019 // This picture is cleared. It can be posted to a thread different than |
| 2003 // should be the case after all pictures are cleared at the beginning. | 2020 // the main GPU thread to reduce latency. This should be the case after |
| 2004 io_task_runner_->PostTask( | 2021 // all pictures are cleared at the beginning. |
| 2005 FROM_HERE, base::Bind(&Client::PictureReady, io_client_, picture)); | 2022 decode_task_runner_->PostTask( |
| 2023 FROM_HERE, |
| 2024 base::Bind(&Client::PictureReady, decode_client_, picture)); |
| 2006 pending_picture_ready_.pop(); | 2025 pending_picture_ready_.pop(); |
| 2007 } else if (!cleared || resetting_or_flushing) { | 2026 } else if (!cleared || resetting_or_flushing) { |
| 2008 DVLOG(3) << "SendPictureReady()" | 2027 DVLOG(3) << "SendPictureReady()" |
| 2009 << ". cleared=" << pending_picture_ready_.front().cleared | 2028 << ". cleared=" << pending_picture_ready_.front().cleared |
| 2010 << ", decoder_state_=" << decoder_state_ | 2029 << ", decoder_state_=" << decoder_state_ |
| 2011 << ", decoder_flushing_=" << decoder_flushing_ | 2030 << ", decoder_flushing_=" << decoder_flushing_ |
| 2012 << ", picture_clearing_count_=" << picture_clearing_count_; | 2031 << ", picture_clearing_count_=" << picture_clearing_count_; |
| 2013 // If the picture is not cleared, post it to the child thread because it | 2032 // If the picture is not cleared, post it to the child thread because it |
| 2014 // has to be cleared in the child thread. A picture only needs to be | 2033 // has to be cleared in the child thread. A picture only needs to be |
| 2015 // cleared once. If the decoder is resetting or flushing, send all | 2034 // cleared once. If the decoder is resetting or flushing, send all |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2033 | 2052 |
| 2034 void V4L2VideoDecodeAccelerator::PictureCleared() { | 2053 void V4L2VideoDecodeAccelerator::PictureCleared() { |
| 2035 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_; | 2054 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_; |
| 2036 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 2055 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 2037 DCHECK_GT(picture_clearing_count_, 0); | 2056 DCHECK_GT(picture_clearing_count_, 0); |
| 2038 picture_clearing_count_--; | 2057 picture_clearing_count_--; |
| 2039 SendPictureReady(); | 2058 SendPictureReady(); |
| 2040 } | 2059 } |
| 2041 | 2060 |
| 2042 } // namespace content | 2061 } // namespace content |
| OLD | NEW |