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