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