| 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> |
| (...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 input_buffer_queued_count_(0), | 392 input_buffer_queued_count_(0), |
| 393 output_streamon_(false), | 393 output_streamon_(false), |
| 394 output_buffer_queued_count_(0), | 394 output_buffer_queued_count_(0), |
| 395 video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), | 395 video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), |
| 396 output_format_fourcc_(0), | 396 output_format_fourcc_(0), |
| 397 state_(kUninitialized), | 397 state_(kUninitialized), |
| 398 decoder_flushing_(false), | 398 decoder_flushing_(false), |
| 399 decoder_resetting_(false), | 399 decoder_resetting_(false), |
| 400 surface_set_change_pending_(false), | 400 surface_set_change_pending_(false), |
| 401 picture_clearing_count_(0), | 401 picture_clearing_count_(0), |
| 402 pictures_assigned_(false, false), |
| 402 egl_display_(egl_display), | 403 egl_display_(egl_display), |
| 403 get_gl_context_cb_(get_gl_context_cb), | 404 get_gl_context_cb_(get_gl_context_cb), |
| 404 make_context_current_cb_(make_context_current_cb), | 405 make_context_current_cb_(make_context_current_cb), |
| 405 weak_this_factory_(this) { | 406 weak_this_factory_(this) { |
| 406 weak_this_ = weak_this_factory_.GetWeakPtr(); | 407 weak_this_ = weak_this_factory_.GetWeakPtr(); |
| 407 } | 408 } |
| 408 | 409 |
| 409 V4L2SliceVideoDecodeAccelerator::~V4L2SliceVideoDecodeAccelerator() { | 410 V4L2SliceVideoDecodeAccelerator::~V4L2SliceVideoDecodeAccelerator() { |
| 410 DVLOGF(2); | 411 DVLOGF(2); |
| 411 | 412 |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 546 | 547 |
| 547 void V4L2SliceVideoDecodeAccelerator::Destroy() { | 548 void V4L2SliceVideoDecodeAccelerator::Destroy() { |
| 548 DVLOGF(3); | 549 DVLOGF(3); |
| 549 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 550 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 550 | 551 |
| 551 if (decoder_thread_.IsRunning()) { | 552 if (decoder_thread_.IsRunning()) { |
| 552 decoder_thread_task_runner_->PostTask( | 553 decoder_thread_task_runner_->PostTask( |
| 553 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::DestroyTask, | 554 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::DestroyTask, |
| 554 base::Unretained(this))); | 555 base::Unretained(this))); |
| 555 | 556 |
| 557 // Wake up decoder thread in case we are waiting in CreateOutputBuffers |
| 558 // for client to provide pictures. Since this is Destroy, we won't be |
| 559 // getting them anymore (AssignPictureBuffers won't be called). |
| 560 pictures_assigned_.Signal(); |
| 561 |
| 556 // Wait for tasks to finish/early-exit. | 562 // Wait for tasks to finish/early-exit. |
| 557 decoder_thread_.Stop(); | 563 decoder_thread_.Stop(); |
| 558 } | 564 } |
| 559 | 565 |
| 560 delete this; | 566 delete this; |
| 561 DVLOGF(3) << "Destroyed"; | 567 DVLOGF(3) << "Destroyed"; |
| 562 } | 568 } |
| 563 | 569 |
| 564 void V4L2SliceVideoDecodeAccelerator::DestroyTask() { | 570 void V4L2SliceVideoDecodeAccelerator::DestroyTask() { |
| 565 DVLOGF(3); | 571 DVLOGF(3); |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 747 DVLOGF(3) << "buffer_count=" << num_pictures | 753 DVLOGF(3) << "buffer_count=" << num_pictures |
| 748 << ", visible size=" << visible_size_.ToString() | 754 << ", visible size=" << visible_size_.ToString() |
| 749 << ", coded size=" << coded_size_.ToString(); | 755 << ", coded size=" << coded_size_.ToString(); |
| 750 | 756 |
| 751 child_task_runner_->PostTask( | 757 child_task_runner_->PostTask( |
| 752 FROM_HERE, | 758 FROM_HERE, |
| 753 base::Bind(&VideoDecodeAccelerator::Client::ProvidePictureBuffers, | 759 base::Bind(&VideoDecodeAccelerator::Client::ProvidePictureBuffers, |
| 754 client_, num_pictures, 1, coded_size_, | 760 client_, num_pictures, 1, coded_size_, |
| 755 device_->GetTextureTarget())); | 761 device_->GetTextureTarget())); |
| 756 | 762 |
| 763 // Wait for the client to call AssignPictureBuffers() on the Child thread. |
| 764 // We do this, because if we continue decoding without finishing buffer |
| 765 // allocation, we may end up Resetting before AssignPictureBuffers arrives, |
| 766 // resulting in unnecessary complications and subtle bugs. |
| 767 pictures_assigned_.Wait(); |
| 768 |
| 757 return true; | 769 return true; |
| 758 } | 770 } |
| 759 | 771 |
| 760 void V4L2SliceVideoDecodeAccelerator::DestroyInputBuffers() { | 772 void V4L2SliceVideoDecodeAccelerator::DestroyInputBuffers() { |
| 761 DVLOGF(3); | 773 DVLOGF(3); |
| 762 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread() || | 774 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread() || |
| 763 !decoder_thread_.IsRunning()); | 775 !decoder_thread_.IsRunning()); |
| 764 DCHECK(!input_streamon_); | 776 DCHECK(!input_streamon_); |
| 765 | 777 |
| 766 for (auto& input_record : input_buffer_map_) { | 778 for (auto& input_record : input_buffer_map_) { |
| 767 if (input_record.address != nullptr) | 779 if (input_record.address != nullptr) |
| 768 device_->Munmap(input_record.address, input_record.length); | 780 device_->Munmap(input_record.address, input_record.length); |
| 769 } | 781 } |
| 770 | 782 |
| 771 struct v4l2_requestbuffers reqbufs; | 783 struct v4l2_requestbuffers reqbufs; |
| 772 memset(&reqbufs, 0, sizeof(reqbufs)); | 784 memset(&reqbufs, 0, sizeof(reqbufs)); |
| 773 reqbufs.count = 0; | 785 reqbufs.count = 0; |
| 774 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 786 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 775 reqbufs.memory = V4L2_MEMORY_MMAP; | 787 reqbufs.memory = V4L2_MEMORY_MMAP; |
| 776 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); | 788 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); |
| 777 | 789 |
| 778 input_buffer_map_.clear(); | 790 input_buffer_map_.clear(); |
| 779 free_input_buffers_.clear(); | 791 free_input_buffers_.clear(); |
| 780 } | 792 } |
| 781 | 793 |
| 782 void V4L2SliceVideoDecodeAccelerator::DismissPictures( | 794 void V4L2SliceVideoDecodeAccelerator::DismissPictures( |
| 783 const std::vector<int32_t>& picture_buffer_ids, | 795 std::vector<int32_t> picture_buffer_ids, |
| 784 base::WaitableEvent* done) { | 796 base::WaitableEvent* done) { |
| 785 DVLOGF(3); | 797 DVLOGF(3); |
| 786 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 798 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 787 | 799 |
| 788 for (auto picture_buffer_id : picture_buffer_ids) { | 800 for (auto picture_buffer_id : picture_buffer_ids) { |
| 789 DVLOGF(1) << "dismissing PictureBuffer id=" << picture_buffer_id; | 801 DVLOGF(1) << "dismissing PictureBuffer id=" << picture_buffer_id; |
| 790 client_->DismissPictureBuffer(picture_buffer_id); | 802 client_->DismissPictureBuffer(picture_buffer_id); |
| 791 } | 803 } |
| 792 | 804 |
| 793 done->Signal(); | 805 done->Signal(); |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 954 TryOutputSurfaces(); | 966 TryOutputSurfaces(); |
| 955 | 967 |
| 956 ProcessPendingEventsIfNeeded(); | 968 ProcessPendingEventsIfNeeded(); |
| 957 } | 969 } |
| 958 | 970 |
| 959 void V4L2SliceVideoDecodeAccelerator::ProcessPendingEventsIfNeeded() { | 971 void V4L2SliceVideoDecodeAccelerator::ProcessPendingEventsIfNeeded() { |
| 960 // Process pending events, if any, in the correct order. | 972 // Process pending events, if any, in the correct order. |
| 961 // We always first process the surface set change, as it is an internal | 973 // We always first process the surface set change, as it is an internal |
| 962 // event from the decoder and interleaving it with external requests would | 974 // event from the decoder and interleaving it with external requests would |
| 963 // put the decoder in an undefined state. | 975 // put the decoder in an undefined state. |
| 964 if (surface_set_change_pending_) { | 976 FinishSurfaceSetChangeIfNeeded(); |
| 965 if (!FinishSurfaceSetChange()) | |
| 966 return; | |
| 967 } | |
| 968 DCHECK(!surface_set_change_pending_); | |
| 969 | 977 |
| 970 // Process external (client) requests. | 978 // Process external (client) requests. |
| 971 if (decoder_flushing_) { | 979 FinishFlushIfNeeded(); |
| 972 if (!FinishFlush()) | 980 FinishResetIfNeeded(); |
| 973 return; | |
| 974 } | |
| 975 DCHECK(!decoder_flushing_); | |
| 976 | |
| 977 if (decoder_resetting_) { | |
| 978 if (!FinishReset()) | |
| 979 return; | |
| 980 } | |
| 981 DCHECK(!decoder_resetting_); | |
| 982 | |
| 983 if (state_ == kIdle) | |
| 984 state_ = kDecoding; | |
| 985 | |
| 986 ScheduleDecodeBufferTaskIfNeeded(); | |
| 987 } | 981 } |
| 988 | 982 |
| 989 void V4L2SliceVideoDecodeAccelerator::ReuseInputBuffer(int index) { | 983 void V4L2SliceVideoDecodeAccelerator::ReuseInputBuffer(int index) { |
| 990 DVLOGF(4) << "Reusing input buffer, index=" << index; | 984 DVLOGF(4) << "Reusing input buffer, index=" << index; |
| 991 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 985 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 992 | 986 |
| 993 DCHECK_LT(index, static_cast<int>(input_buffer_map_.size())); | 987 DCHECK_LT(index, static_cast<int>(input_buffer_map_.size())); |
| 994 InputRecord& input_record = input_buffer_map_[index]; | 988 InputRecord& input_record = input_buffer_map_[index]; |
| 995 | 989 |
| 996 DCHECK(!input_record.at_device); | 990 DCHECK(!input_record.at_device); |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1302 NOTIFY_ERROR(PLATFORM_FAILURE); | 1296 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1303 return; | 1297 return; |
| 1304 } | 1298 } |
| 1305 } | 1299 } |
| 1306 } | 1300 } |
| 1307 | 1301 |
| 1308 void V4L2SliceVideoDecodeAccelerator::InitiateSurfaceSetChange() { | 1302 void V4L2SliceVideoDecodeAccelerator::InitiateSurfaceSetChange() { |
| 1309 DVLOGF(2); | 1303 DVLOGF(2); |
| 1310 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1304 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 1311 | 1305 |
| 1306 DCHECK_EQ(state_, kDecoding); |
| 1312 state_ = kIdle; | 1307 state_ = kIdle; |
| 1313 | 1308 |
| 1314 DCHECK(!surface_set_change_pending_); | 1309 DCHECK(!surface_set_change_pending_); |
| 1315 surface_set_change_pending_ = true; | 1310 surface_set_change_pending_ = true; |
| 1316 | 1311 |
| 1317 ProcessPendingEventsIfNeeded(); | 1312 FinishSurfaceSetChangeIfNeeded(); |
| 1318 } | 1313 } |
| 1319 | 1314 |
| 1320 bool V4L2SliceVideoDecodeAccelerator::FinishSurfaceSetChange() { | 1315 void V4L2SliceVideoDecodeAccelerator::FinishSurfaceSetChangeIfNeeded() { |
| 1321 DVLOGF(2); | 1316 DVLOGF(2); |
| 1322 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1317 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 1323 | 1318 |
| 1324 DCHECK(surface_set_change_pending_); | 1319 if (!surface_set_change_pending_ || !surfaces_at_device_.empty()) |
| 1325 if (!surfaces_at_device_.empty()) | 1320 return; |
| 1326 return false; | |
| 1327 | 1321 |
| 1328 DCHECK_EQ(state_, kIdle); | 1322 DCHECK_EQ(state_, kIdle); |
| 1329 DCHECK(decoder_display_queue_.empty()); | 1323 DCHECK(decoder_display_queue_.empty()); |
| 1330 // All output buffers should've been returned from decoder and device by now. | 1324 // All output buffers should've been returned from decoder and device by now. |
| 1331 // The only remaining owner of surfaces may be display (client), and we will | 1325 // The only remaining owner of surfaces may be display (client), and we will |
| 1332 // dismiss them when destroying output buffers below. | 1326 // dismiss them when destroying output buffers below. |
| 1333 DCHECK_EQ(free_output_buffers_.size() + surfaces_at_display_.size(), | 1327 DCHECK_EQ(free_output_buffers_.size() + surfaces_at_display_.size(), |
| 1334 output_buffer_map_.size()); | 1328 output_buffer_map_.size()); |
| 1335 | 1329 |
| 1336 // Keep input queue running while we switch outputs. | 1330 // Keep input queue running while we switch outputs. |
| 1337 if (!StopDevicePoll(true)) { | 1331 if (!StopDevicePoll(true)) { |
| 1338 NOTIFY_ERROR(PLATFORM_FAILURE); | 1332 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1339 return false; | 1333 return; |
| 1340 } | 1334 } |
| 1341 | 1335 |
| 1342 // This will return only once all buffers are dismissed and destroyed. | 1336 // This will return only once all buffers are dismissed and destroyed. |
| 1343 // This does not wait until they are displayed however, as display retains | 1337 // This does not wait until they are displayed however, as display retains |
| 1344 // references to the buffers bound to textures and will release them | 1338 // references to the buffers bound to textures and will release them |
| 1345 // after displaying. | 1339 // after displaying. |
| 1346 if (!DestroyOutputs(true)) { | 1340 if (!DestroyOutputs(true)) { |
| 1347 NOTIFY_ERROR(PLATFORM_FAILURE); | 1341 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1348 return false; | 1342 return; |
| 1349 } | 1343 } |
| 1350 | 1344 |
| 1351 if (!CreateOutputBuffers()) { | 1345 if (!CreateOutputBuffers()) { |
| 1352 NOTIFY_ERROR(PLATFORM_FAILURE); | 1346 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1353 return false; | 1347 return; |
| 1354 } | 1348 } |
| 1355 | 1349 |
| 1356 // At this point we can safely say the surface set has been changed, even | 1350 if (!StartDevicePoll()) { |
| 1357 // though we haven't received the actual buffers via AssignPictureBuffers() | 1351 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1358 // yet. We will not start decoding without having surfaces available, | 1352 return; |
| 1359 // and will schedule a decode task once the client provides the buffers. | 1353 } |
| 1354 |
| 1355 DVLOGF(3) << "Surface set change finished"; |
| 1356 |
| 1360 surface_set_change_pending_ = false; | 1357 surface_set_change_pending_ = false; |
| 1361 DVLOG(3) << "Surface set change finished"; | 1358 state_ = kDecoding; |
| 1362 return true; | 1359 ScheduleDecodeBufferTaskIfNeeded(); |
| 1363 } | 1360 } |
| 1364 | 1361 |
| 1365 bool V4L2SliceVideoDecodeAccelerator::DestroyOutputs(bool dismiss) { | 1362 bool V4L2SliceVideoDecodeAccelerator::DestroyOutputs(bool dismiss) { |
| 1366 DVLOGF(3); | 1363 DVLOGF(3); |
| 1367 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1364 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 1368 std::vector<EGLImageKHR> egl_images_to_destroy; | 1365 std::vector<EGLImageKHR> egl_images_to_destroy; |
| 1369 std::vector<int32_t> picture_buffers_to_dismiss; | 1366 std::vector<int32_t> picture_buffers_to_dismiss; |
| 1370 | 1367 |
| 1371 if (output_buffer_map_.empty()) | 1368 if (output_buffer_map_.empty()) |
| 1372 return true; | 1369 return true; |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1442 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); | 1439 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); |
| 1443 | 1440 |
| 1444 return true; | 1441 return true; |
| 1445 } | 1442 } |
| 1446 | 1443 |
| 1447 void V4L2SliceVideoDecodeAccelerator::AssignPictureBuffers( | 1444 void V4L2SliceVideoDecodeAccelerator::AssignPictureBuffers( |
| 1448 const std::vector<media::PictureBuffer>& buffers) { | 1445 const std::vector<media::PictureBuffer>& buffers) { |
| 1449 DVLOGF(3); | 1446 DVLOGF(3); |
| 1450 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 1447 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 1451 | 1448 |
| 1452 decoder_thread_task_runner_->PostTask( | |
| 1453 FROM_HERE, base::Bind( | |
| 1454 &V4L2SliceVideoDecodeAccelerator::AssignPictureBuffersTask, | |
| 1455 base::Unretained(this), buffers)); | |
| 1456 } | |
| 1457 | |
| 1458 void V4L2SliceVideoDecodeAccelerator::AssignPictureBuffersTask( | |
| 1459 const std::vector<media::PictureBuffer>& buffers) { | |
| 1460 DVLOGF(3); | |
| 1461 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | |
| 1462 DCHECK_EQ(state_, kDecoding); | |
| 1463 | |
| 1464 const uint32_t req_buffer_count = decoder_->GetRequiredNumOfPictures(); | 1449 const uint32_t req_buffer_count = decoder_->GetRequiredNumOfPictures(); |
| 1465 | 1450 |
| 1466 if (buffers.size() < req_buffer_count) { | 1451 if (buffers.size() < req_buffer_count) { |
| 1467 DLOG(ERROR) << "Failed to provide requested picture buffers. " | 1452 DLOG(ERROR) << "Failed to provide requested picture buffers. " |
| 1468 << "(Got " << buffers.size() | 1453 << "(Got " << buffers.size() |
| 1469 << ", requested " << req_buffer_count << ")"; | 1454 << ", requested " << req_buffer_count << ")"; |
| 1470 NOTIFY_ERROR(INVALID_ARGUMENT); | 1455 NOTIFY_ERROR(INVALID_ARGUMENT); |
| 1471 return; | 1456 return; |
| 1472 } | 1457 } |
| 1473 | 1458 |
| 1459 gfx::GLContext* gl_context = get_gl_context_cb_.Run(); |
| 1460 if (!gl_context || !make_context_current_cb_.Run()) { |
| 1461 DLOG(ERROR) << "No GL context"; |
| 1462 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1463 return; |
| 1464 } |
| 1465 |
| 1466 gfx::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); |
| 1467 |
| 1468 // It's safe to manipulate all the buffer state here, because the decoder |
| 1469 // thread is waiting on pictures_assigned_. |
| 1470 |
| 1474 // Allocate the output buffers. | 1471 // Allocate the output buffers. |
| 1475 struct v4l2_requestbuffers reqbufs; | 1472 struct v4l2_requestbuffers reqbufs; |
| 1476 memset(&reqbufs, 0, sizeof(reqbufs)); | 1473 memset(&reqbufs, 0, sizeof(reqbufs)); |
| 1477 reqbufs.count = buffers.size(); | 1474 reqbufs.count = buffers.size(); |
| 1478 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1475 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 1479 reqbufs.memory = V4L2_MEMORY_MMAP; | 1476 reqbufs.memory = V4L2_MEMORY_MMAP; |
| 1480 IOCTL_OR_ERROR_RETURN(VIDIOC_REQBUFS, &reqbufs); | 1477 IOCTL_OR_ERROR_RETURN(VIDIOC_REQBUFS, &reqbufs); |
| 1481 | 1478 |
| 1482 if (reqbufs.count != buffers.size()) { | 1479 if (reqbufs.count != buffers.size()) { |
| 1483 DLOG(ERROR) << "Could not allocate enough output buffers"; | 1480 DLOG(ERROR) << "Could not allocate enough output buffers"; |
| 1484 NOTIFY_ERROR(PLATFORM_FAILURE); | 1481 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1485 return; | 1482 return; |
| 1486 } | 1483 } |
| 1487 | 1484 |
| 1488 child_task_runner_->PostTask( | 1485 output_buffer_map_.resize(buffers.size()); |
| 1489 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::CreateEGLImages, | |
| 1490 weak_this_, buffers, output_format_fourcc_, | |
| 1491 output_planes_count_)); | |
| 1492 } | |
| 1493 | |
| 1494 void V4L2SliceVideoDecodeAccelerator::CreateEGLImages( | |
| 1495 const std::vector<media::PictureBuffer>& buffers, | |
| 1496 uint32_t output_format_fourcc, | |
| 1497 size_t output_planes_count) { | |
| 1498 DVLOGF(3); | |
| 1499 DCHECK(child_task_runner_->BelongsToCurrentThread()); | |
| 1500 | |
| 1501 gfx::GLContext* gl_context = get_gl_context_cb_.Run(); | |
| 1502 if (!gl_context || !make_context_current_cb_.Run()) { | |
| 1503 DLOG(ERROR) << "No GL context"; | |
| 1504 NOTIFY_ERROR(PLATFORM_FAILURE); | |
| 1505 return; | |
| 1506 } | |
| 1507 | |
| 1508 gfx::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); | |
| 1509 | |
| 1510 std::vector<EGLImageKHR> egl_images; | |
| 1511 for (size_t i = 0; i < buffers.size(); ++i) { | |
| 1512 DCHECK_LE(1u, buffers[i].texture_ids().size()); | |
| 1513 | |
| 1514 EGLImageKHR egl_image = device_->CreateEGLImage( | |
| 1515 egl_display_, gl_context->GetHandle(), buffers[i].texture_ids()[0], | |
| 1516 buffers[i].size(), i, output_format_fourcc, output_planes_count); | |
| 1517 if (egl_image == EGL_NO_IMAGE_KHR) { | |
| 1518 LOGF(ERROR) << "Could not create EGLImageKHR"; | |
| 1519 for (const auto& image_to_destroy : egl_images) | |
| 1520 device_->DestroyEGLImage(egl_display_, image_to_destroy); | |
| 1521 | |
| 1522 NOTIFY_ERROR(PLATFORM_FAILURE); | |
| 1523 return; | |
| 1524 } | |
| 1525 | |
| 1526 egl_images.push_back(egl_image); | |
| 1527 } | |
| 1528 | |
| 1529 decoder_thread_task_runner_->PostTask( | |
| 1530 FROM_HERE, base::Bind( | |
| 1531 &V4L2SliceVideoDecodeAccelerator::AssignEGLImages, | |
| 1532 base::Unretained(this), buffers, egl_images)); | |
| 1533 } | |
| 1534 | |
| 1535 void V4L2SliceVideoDecodeAccelerator::AssignEGLImages( | |
| 1536 const std::vector<media::PictureBuffer>& buffers, | |
| 1537 const std::vector<EGLImageKHR>& egl_images) { | |
| 1538 DVLOGF(3); | |
| 1539 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | |
| 1540 DCHECK_EQ(buffers.size(), egl_images.size()); | |
| 1541 | 1486 |
| 1542 DCHECK(free_output_buffers_.empty()); | 1487 DCHECK(free_output_buffers_.empty()); |
| 1543 DCHECK(output_buffer_map_.empty()); | |
| 1544 | |
| 1545 output_buffer_map_.resize(buffers.size()); | |
| 1546 | |
| 1547 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { | 1488 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
| 1548 DCHECK(buffers[i].size() == coded_size_); | 1489 DCHECK(buffers[i].size() == coded_size_); |
| 1549 | 1490 |
| 1550 OutputRecord& output_record = output_buffer_map_[i]; | 1491 OutputRecord& output_record = output_buffer_map_[i]; |
| 1551 DCHECK(!output_record.at_device); | 1492 DCHECK(!output_record.at_device); |
| 1552 DCHECK(!output_record.at_client); | 1493 DCHECK(!output_record.at_client); |
| 1553 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); | 1494 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); |
| 1554 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | 1495 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
| 1555 DCHECK_EQ(output_record.picture_id, -1); | 1496 DCHECK_EQ(output_record.picture_id, -1); |
| 1556 DCHECK_EQ(output_record.cleared, false); | 1497 DCHECK_EQ(output_record.cleared, false); |
| 1557 | 1498 |
| 1558 output_record.egl_image = egl_images[i]; | 1499 DCHECK_LE(1u, buffers[i].texture_ids().size()); |
| 1500 EGLImageKHR egl_image = device_->CreateEGLImage( |
| 1501 egl_display_, gl_context->GetHandle(), buffers[i].texture_ids()[0], |
| 1502 buffers[i].size(), i, output_format_fourcc_, output_planes_count_); |
| 1503 if (egl_image == EGL_NO_IMAGE_KHR) { |
| 1504 LOGF(ERROR) << "Could not create EGLImageKHR"; |
| 1505 // Ownership of EGLImages allocated in previous iterations of this loop |
| 1506 // has been transferred to output_buffer_map_. After we error-out here |
| 1507 // the destructor will handle their cleanup. |
| 1508 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1509 return; |
| 1510 } |
| 1511 |
| 1512 output_record.egl_image = egl_image; |
| 1559 output_record.picture_id = buffers[i].id(); | 1513 output_record.picture_id = buffers[i].id(); |
| 1560 free_output_buffers_.push_back(i); | 1514 free_output_buffers_.push_back(i); |
| 1561 DVLOGF(3) << "buffer[" << i << "]: picture_id=" << output_record.picture_id; | 1515 DVLOGF(3) << "buffer[" << i << "]: picture_id=" << output_record.picture_id; |
| 1562 } | 1516 } |
| 1563 | 1517 |
| 1564 if (!StartDevicePoll()) { | 1518 pictures_assigned_.Signal(); |
| 1565 NOTIFY_ERROR(PLATFORM_FAILURE); | |
| 1566 return; | |
| 1567 } | |
| 1568 | |
| 1569 ProcessPendingEventsIfNeeded(); | |
| 1570 } | 1519 } |
| 1571 | 1520 |
| 1572 void V4L2SliceVideoDecodeAccelerator::ReusePictureBuffer( | 1521 void V4L2SliceVideoDecodeAccelerator::ReusePictureBuffer( |
| 1573 int32_t picture_buffer_id) { | 1522 int32_t picture_buffer_id) { |
| 1574 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 1523 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 1575 DVLOGF(4) << "picture_buffer_id=" << picture_buffer_id; | 1524 DVLOGF(4) << "picture_buffer_id=" << picture_buffer_id; |
| 1576 | 1525 |
| 1577 if (!make_context_current_cb_.Run()) { | 1526 if (!make_context_current_cb_.Run()) { |
| 1578 LOGF(ERROR) << "could not make context current"; | 1527 LOGF(ERROR) << "could not make context current"; |
| 1579 NOTIFY_ERROR(PLATFORM_FAILURE); | 1528 NOTIFY_ERROR(PLATFORM_FAILURE); |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1673 DVLOGF(1) << "Failed flushing the decoder."; | 1622 DVLOGF(1) << "Failed flushing the decoder."; |
| 1674 NOTIFY_ERROR(PLATFORM_FAILURE); | 1623 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1675 return; | 1624 return; |
| 1676 } | 1625 } |
| 1677 | 1626 |
| 1678 // Put the decoder in an idle state, ready to resume. | 1627 // Put the decoder in an idle state, ready to resume. |
| 1679 decoder_->Reset(); | 1628 decoder_->Reset(); |
| 1680 | 1629 |
| 1681 decoder_flushing_ = true; | 1630 decoder_flushing_ = true; |
| 1682 | 1631 |
| 1683 ProcessPendingEventsIfNeeded(); | 1632 decoder_thread_task_runner_->PostTask( |
| 1633 FROM_HERE, |
| 1634 base::Bind(&V4L2SliceVideoDecodeAccelerator::FinishFlushIfNeeded, |
| 1635 base::Unretained(this))); |
| 1684 } | 1636 } |
| 1685 | 1637 |
| 1686 bool V4L2SliceVideoDecodeAccelerator::FinishFlush() { | 1638 void V4L2SliceVideoDecodeAccelerator::FinishFlushIfNeeded() { |
| 1687 DVLOGF(3); | 1639 DVLOGF(3); |
| 1688 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1640 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 1689 | 1641 |
| 1690 DCHECK(decoder_flushing_); | 1642 if (!decoder_flushing_ || !surfaces_at_device_.empty()) |
| 1691 | 1643 return; |
| 1692 if (!surfaces_at_device_.empty()) | |
| 1693 return false; | |
| 1694 | 1644 |
| 1695 DCHECK_EQ(state_, kIdle); | 1645 DCHECK_EQ(state_, kIdle); |
| 1696 | 1646 |
| 1697 // At this point, all remaining surfaces are decoded and dequeued, and since | 1647 // At this point, all remaining surfaces are decoded and dequeued, and since |
| 1698 // we have already scheduled output for them in InitiateFlush(), their | 1648 // we have already scheduled output for them in InitiateFlush(), their |
| 1699 // respective PictureReady calls have been posted (or they have been queued on | 1649 // respective PictureReady calls have been posted (or they have been queued on |
| 1700 // pending_picture_ready_). So at this time, once we SendPictureReady(), | 1650 // pending_picture_ready_). So at this time, once we SendPictureReady(), |
| 1701 // we will have all remaining PictureReady() posted to the client and we | 1651 // we will have all remaining PictureReady() posted to the client and we |
| 1702 // can post NotifyFlushDone(). | 1652 // can post NotifyFlushDone(). |
| 1703 DCHECK(decoder_display_queue_.empty()); | 1653 DCHECK(decoder_display_queue_.empty()); |
| 1704 | 1654 |
| 1705 // Decoder should have already returned all surfaces and all surfaces are | 1655 // Decoder should have already returned all surfaces and all surfaces are |
| 1706 // out of hardware. There can be no other owners of input buffers. | 1656 // out of hardware. There can be no other owners of input buffers. |
| 1707 DCHECK_EQ(free_input_buffers_.size(), input_buffer_map_.size()); | 1657 DCHECK_EQ(free_input_buffers_.size(), input_buffer_map_.size()); |
| 1708 | 1658 |
| 1709 SendPictureReady(); | 1659 SendPictureReady(); |
| 1710 | 1660 |
| 1711 decoder_flushing_ = false; | |
| 1712 DVLOGF(3) << "Flush finished"; | |
| 1713 | |
| 1714 child_task_runner_->PostTask(FROM_HERE, | 1661 child_task_runner_->PostTask(FROM_HERE, |
| 1715 base::Bind(&Client::NotifyFlushDone, client_)); | 1662 base::Bind(&Client::NotifyFlushDone, client_)); |
| 1716 | 1663 |
| 1717 return true; | 1664 decoder_flushing_ = false; |
| 1665 |
| 1666 DVLOGF(3) << "Flush finished"; |
| 1667 state_ = kDecoding; |
| 1668 ScheduleDecodeBufferTaskIfNeeded(); |
| 1718 } | 1669 } |
| 1719 | 1670 |
| 1720 void V4L2SliceVideoDecodeAccelerator::Reset() { | 1671 void V4L2SliceVideoDecodeAccelerator::Reset() { |
| 1721 DVLOGF(3); | 1672 DVLOGF(3); |
| 1722 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 1673 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 1723 | 1674 |
| 1724 decoder_thread_task_runner_->PostTask( | 1675 decoder_thread_task_runner_->PostTask( |
| 1725 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::ResetTask, | 1676 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::ResetTask, |
| 1726 base::Unretained(this))); | 1677 base::Unretained(this))); |
| 1727 } | 1678 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1743 // Put the decoder in an idle state, ready to resume. | 1694 // Put the decoder in an idle state, ready to resume. |
| 1744 decoder_->Reset(); | 1695 decoder_->Reset(); |
| 1745 | 1696 |
| 1746 decoder_resetting_ = true; | 1697 decoder_resetting_ = true; |
| 1747 | 1698 |
| 1748 // Drop all remaining inputs. | 1699 // Drop all remaining inputs. |
| 1749 decoder_current_bitstream_buffer_.reset(); | 1700 decoder_current_bitstream_buffer_.reset(); |
| 1750 while (!decoder_input_queue_.empty()) | 1701 while (!decoder_input_queue_.empty()) |
| 1751 decoder_input_queue_.pop(); | 1702 decoder_input_queue_.pop(); |
| 1752 | 1703 |
| 1753 ProcessPendingEventsIfNeeded(); | 1704 FinishResetIfNeeded(); |
| 1754 } | 1705 } |
| 1755 | 1706 |
| 1756 bool V4L2SliceVideoDecodeAccelerator::FinishReset() { | 1707 void V4L2SliceVideoDecodeAccelerator::FinishResetIfNeeded() { |
| 1757 DVLOGF(3); | 1708 DVLOGF(3); |
| 1758 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1709 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 1759 | 1710 |
| 1760 DCHECK(decoder_resetting_); | 1711 if (!decoder_resetting_ || !surfaces_at_device_.empty()) |
| 1761 if (!surfaces_at_device_.empty()) | 1712 return; |
| 1762 return false; | |
| 1763 | 1713 |
| 1764 DCHECK_EQ(state_, kIdle); | 1714 DCHECK_EQ(state_, kIdle); |
| 1765 DCHECK(!decoder_flushing_); | 1715 DCHECK(!decoder_flushing_); |
| 1766 SendPictureReady(); | 1716 SendPictureReady(); |
| 1767 | 1717 |
| 1768 // Drop any pending outputs. | 1718 // Drop any pending outputs. |
| 1769 while (!decoder_display_queue_.empty()) | 1719 while (!decoder_display_queue_.empty()) |
| 1770 decoder_display_queue_.pop(); | 1720 decoder_display_queue_.pop(); |
| 1771 | 1721 |
| 1772 // At this point we can have no input buffers in the decoder, because we | 1722 // At this point we can have no input buffers in the decoder, because we |
| 1773 // Reset()ed it in ResetTask(), and have not scheduled any new Decode()s | 1723 // Reset()ed it in ResetTask(), and have not scheduled any new Decode()s |
| 1774 // having been in kIdle since. We don't have any surfaces in the HW either - | 1724 // having been in kIdle since. We don't have any surfaces in the HW either - |
| 1775 // we just checked that surfaces_at_device_.empty(), and inputs are tied | 1725 // we just checked that surfaces_at_device_.empty(), and inputs are tied |
| 1776 // to surfaces. Since there can be no other owners of input buffers, we can | 1726 // to surfaces. Since there can be no other owners of input buffers, we can |
| 1777 // simply mark them all as available. | 1727 // simply mark them all as available. |
| 1778 DCHECK_EQ(input_buffer_queued_count_, 0); | 1728 DCHECK_EQ(input_buffer_queued_count_, 0); |
| 1779 free_input_buffers_.clear(); | 1729 free_input_buffers_.clear(); |
| 1780 for (size_t i = 0; i < input_buffer_map_.size(); ++i) { | 1730 for (size_t i = 0; i < input_buffer_map_.size(); ++i) { |
| 1781 DCHECK(!input_buffer_map_[i].at_device); | 1731 DCHECK(!input_buffer_map_[i].at_device); |
| 1782 ReuseInputBuffer(i); | 1732 ReuseInputBuffer(i); |
| 1783 } | 1733 } |
| 1784 | 1734 |
| 1785 decoder_resetting_ = false; | 1735 decoder_resetting_ = false; |
| 1786 DVLOGF(3) << "Reset finished"; | |
| 1787 | 1736 |
| 1788 child_task_runner_->PostTask(FROM_HERE, | 1737 child_task_runner_->PostTask(FROM_HERE, |
| 1789 base::Bind(&Client::NotifyResetDone, client_)); | 1738 base::Bind(&Client::NotifyResetDone, client_)); |
| 1790 | 1739 |
| 1791 return true; | 1740 DVLOGF(3) << "Reset finished"; |
| 1741 |
| 1742 state_ = kDecoding; |
| 1743 ScheduleDecodeBufferTaskIfNeeded(); |
| 1792 } | 1744 } |
| 1793 | 1745 |
| 1794 void V4L2SliceVideoDecodeAccelerator::SetErrorState(Error error) { | 1746 void V4L2SliceVideoDecodeAccelerator::SetErrorState(Error error) { |
| 1795 // We can touch decoder_state_ only if this is the decoder thread or the | 1747 // We can touch decoder_state_ only if this is the decoder thread or the |
| 1796 // decoder thread isn't running. | 1748 // decoder thread isn't running. |
| 1797 if (decoder_thread_.IsRunning() && | 1749 if (decoder_thread_.IsRunning() && |
| 1798 !decoder_thread_task_runner_->BelongsToCurrentThread()) { | 1750 !decoder_thread_task_runner_->BelongsToCurrentThread()) { |
| 1799 decoder_thread_task_runner_->PostTask( | 1751 decoder_thread_task_runner_->PostTask( |
| 1800 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::SetErrorState, | 1752 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::SetErrorState, |
| 1801 base::Unretained(this), error)); | 1753 base::Unretained(this), error)); |
| (...skipping 817 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2619 V4L2SliceVideoDecodeAccelerator::GetSupportedProfiles() { | 2571 V4L2SliceVideoDecodeAccelerator::GetSupportedProfiles() { |
| 2620 scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); | 2572 scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); |
| 2621 if (!device) | 2573 if (!device) |
| 2622 return SupportedProfiles(); | 2574 return SupportedProfiles(); |
| 2623 | 2575 |
| 2624 return device->GetSupportedDecodeProfiles(arraysize(supported_input_fourccs_), | 2576 return device->GetSupportedDecodeProfiles(arraysize(supported_input_fourccs_), |
| 2625 supported_input_fourccs_); | 2577 supported_input_fourccs_); |
| 2626 } | 2578 } |
| 2627 | 2579 |
| 2628 } // namespace content | 2580 } // namespace content |
| OLD | NEW |