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 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
155 address(nullptr), | 155 address(nullptr), |
156 length(0), | 156 length(0), |
157 bytes_used(0), | 157 bytes_used(0), |
158 at_device(false) { | 158 at_device(false) { |
159 } | 159 } |
160 | 160 |
161 V4L2SliceVideoDecodeAccelerator::OutputRecord::OutputRecord() | 161 V4L2SliceVideoDecodeAccelerator::OutputRecord::OutputRecord() |
162 : at_device(false), | 162 : at_device(false), |
163 at_client(false), | 163 at_client(false), |
164 picture_id(-1), | 164 picture_id(-1), |
165 texture_id(0), | |
165 egl_image(EGL_NO_IMAGE_KHR), | 166 egl_image(EGL_NO_IMAGE_KHR), |
166 egl_sync(EGL_NO_SYNC_KHR), | 167 egl_sync(EGL_NO_SYNC_KHR), |
167 cleared(false) { | 168 cleared(false) {} |
168 } | |
169 | 169 |
170 struct V4L2SliceVideoDecodeAccelerator::BitstreamBufferRef { | 170 struct V4L2SliceVideoDecodeAccelerator::BitstreamBufferRef { |
171 BitstreamBufferRef( | 171 BitstreamBufferRef( |
172 base::WeakPtr<VideoDecodeAccelerator::Client>& client, | 172 base::WeakPtr<VideoDecodeAccelerator::Client>& client, |
173 const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, | 173 const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, |
174 SharedMemoryRegion* shm, | 174 SharedMemoryRegion* shm, |
175 int32_t input_id); | 175 int32_t input_id); |
176 ~BitstreamBufferRef(); | 176 ~BitstreamBufferRef(); |
177 const base::WeakPtr<VideoDecodeAccelerator::Client> client; | 177 const base::WeakPtr<VideoDecodeAccelerator::Client> client; |
178 const scoped_refptr<base::SingleThreadTaskRunner> client_task_runner; | 178 const scoped_refptr<base::SingleThreadTaskRunner> client_task_runner; |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
388 device_(device), | 388 device_(device), |
389 decoder_thread_("V4L2SliceVideoDecodeAcceleratorThread"), | 389 decoder_thread_("V4L2SliceVideoDecodeAcceleratorThread"), |
390 device_poll_thread_("V4L2SliceVideoDecodeAcceleratorDevicePollThread"), | 390 device_poll_thread_("V4L2SliceVideoDecodeAcceleratorDevicePollThread"), |
391 input_streamon_(false), | 391 input_streamon_(false), |
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 output_mode_(Config::OutputMode::ALLOCATE), | |
398 decoder_flushing_(false), | 399 decoder_flushing_(false), |
399 decoder_resetting_(false), | 400 decoder_resetting_(false), |
400 surface_set_change_pending_(false), | 401 surface_set_change_pending_(false), |
401 picture_clearing_count_(0), | 402 picture_clearing_count_(0), |
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 } |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
514 if (!SetupFormats()) | 515 if (!SetupFormats()) |
515 return false; | 516 return false; |
516 | 517 |
517 if (!decoder_thread_.Start()) { | 518 if (!decoder_thread_.Start()) { |
518 DLOG(ERROR) << "Initialize(): device thread failed to start"; | 519 DLOG(ERROR) << "Initialize(): device thread failed to start"; |
519 return false; | 520 return false; |
520 } | 521 } |
521 decoder_thread_task_runner_ = decoder_thread_.task_runner(); | 522 decoder_thread_task_runner_ = decoder_thread_.task_runner(); |
522 | 523 |
523 state_ = kInitialized; | 524 state_ = kInitialized; |
525 output_mode_ = config.output_mode; | |
kcwu
2016/03/22 05:42:54
Should we validate the value here?
Owen Lin
2016/03/23 06:32:50
Maybe not, we will set this in ArcGVDA. I think Ar
Pawel Osciak
2016/03/28 01:31:29
It's an enum class, but I guess new values may be
| |
524 | 526 |
525 // InitializeTask will NOTIFY_ERROR on failure. | 527 // InitializeTask will NOTIFY_ERROR on failure. |
526 decoder_thread_task_runner_->PostTask( | 528 decoder_thread_task_runner_->PostTask( |
527 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::InitializeTask, | 529 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::InitializeTask, |
528 base::Unretained(this))); | 530 base::Unretained(this))); |
529 | 531 |
530 DVLOGF(1) << "V4L2SliceVideoDecodeAccelerator initialized"; | 532 DVLOGF(1) << "V4L2SliceVideoDecodeAccelerator initialized"; |
531 return true; | 533 return true; |
532 } | 534 } |
533 | 535 |
(...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
887 DVLOGF(3); | 889 DVLOGF(3); |
888 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 890 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
889 | 891 |
890 struct v4l2_buffer dqbuf; | 892 struct v4l2_buffer dqbuf; |
891 struct v4l2_plane planes[VIDEO_MAX_PLANES]; | 893 struct v4l2_plane planes[VIDEO_MAX_PLANES]; |
892 while (input_buffer_queued_count_ > 0) { | 894 while (input_buffer_queued_count_ > 0) { |
893 DCHECK(input_streamon_); | 895 DCHECK(input_streamon_); |
894 memset(&dqbuf, 0, sizeof(dqbuf)); | 896 memset(&dqbuf, 0, sizeof(dqbuf)); |
895 memset(&planes, 0, sizeof(planes)); | 897 memset(&planes, 0, sizeof(planes)); |
896 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 898 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
897 dqbuf.memory = V4L2_MEMORY_USERPTR; | 899 dqbuf.memory = V4L2_MEMORY_MMAP; |
898 dqbuf.m.planes = planes; | 900 dqbuf.m.planes = planes; |
899 dqbuf.length = input_planes_count_; | 901 dqbuf.length = input_planes_count_; |
900 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { | 902 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { |
901 if (errno == EAGAIN) { | 903 if (errno == EAGAIN) { |
902 // EAGAIN if we're just out of buffers to dequeue. | 904 // EAGAIN if we're just out of buffers to dequeue. |
903 break; | 905 break; |
904 } | 906 } |
905 PLOG(ERROR) << "ioctl() failed: VIDIOC_DQBUF"; | 907 PLOG(ERROR) << "ioctl() failed: VIDIOC_DQBUF"; |
906 NOTIFY_ERROR(PLATFORM_FAILURE); | 908 NOTIFY_ERROR(PLATFORM_FAILURE); |
907 return; | 909 return; |
908 } | 910 } |
909 InputRecord& input_record = input_buffer_map_[dqbuf.index]; | 911 InputRecord& input_record = input_buffer_map_[dqbuf.index]; |
910 DCHECK(input_record.at_device); | 912 DCHECK(input_record.at_device); |
911 input_record.at_device = false; | 913 input_record.at_device = false; |
912 ReuseInputBuffer(dqbuf.index); | 914 ReuseInputBuffer(dqbuf.index); |
913 input_buffer_queued_count_--; | 915 input_buffer_queued_count_--; |
914 DVLOGF(4) << "Dequeued input=" << dqbuf.index | 916 DVLOGF(4) << "Dequeued input=" << dqbuf.index |
915 << " count: " << input_buffer_queued_count_; | 917 << " count: " << input_buffer_queued_count_; |
916 } | 918 } |
917 | 919 |
918 while (output_buffer_queued_count_ > 0) { | 920 while (output_buffer_queued_count_ > 0) { |
919 DCHECK(output_streamon_); | 921 DCHECK(output_streamon_); |
920 memset(&dqbuf, 0, sizeof(dqbuf)); | 922 memset(&dqbuf, 0, sizeof(dqbuf)); |
921 memset(&planes, 0, sizeof(planes)); | 923 memset(&planes, 0, sizeof(planes)); |
922 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 924 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
923 dqbuf.memory = V4L2_MEMORY_MMAP; | 925 if (output_mode_ == Config::OutputMode::ALLOCATE) |
926 dqbuf.memory = V4L2_MEMORY_MMAP; | |
Owen Lin
2016/03/23 06:32:50
use the ternary operator: "? :"
Pawel Osciak
2016/03/28 01:31:28
Done.
| |
927 else | |
928 dqbuf.memory = V4L2_MEMORY_DMABUF; | |
924 dqbuf.m.planes = planes; | 929 dqbuf.m.planes = planes; |
925 dqbuf.length = output_planes_count_; | 930 dqbuf.length = output_planes_count_; |
926 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { | 931 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { |
927 if (errno == EAGAIN) { | 932 if (errno == EAGAIN) { |
928 // EAGAIN if we're just out of buffers to dequeue. | 933 // EAGAIN if we're just out of buffers to dequeue. |
929 break; | 934 break; |
930 } | 935 } |
931 PLOG(ERROR) << "ioctl() failed: VIDIOC_DQBUF"; | 936 PLOG(ERROR) << "ioctl() failed: VIDIOC_DQBUF"; |
932 NOTIFY_ERROR(PLATFORM_FAILURE); | 937 NOTIFY_ERROR(PLATFORM_FAILURE); |
933 return; | 938 return; |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1049 } | 1054 } |
1050 | 1055 |
1051 bool V4L2SliceVideoDecodeAccelerator::EnqueueOutputRecord(int index) { | 1056 bool V4L2SliceVideoDecodeAccelerator::EnqueueOutputRecord(int index) { |
1052 DVLOGF(3); | 1057 DVLOGF(3); |
1053 DCHECK_LT(index, static_cast<int>(output_buffer_map_.size())); | 1058 DCHECK_LT(index, static_cast<int>(output_buffer_map_.size())); |
1054 | 1059 |
1055 // Enqueue an output (VIDEO_CAPTURE) buffer. | 1060 // Enqueue an output (VIDEO_CAPTURE) buffer. |
1056 OutputRecord& output_record = output_buffer_map_[index]; | 1061 OutputRecord& output_record = output_buffer_map_[index]; |
1057 DCHECK(!output_record.at_device); | 1062 DCHECK(!output_record.at_device); |
1058 DCHECK(!output_record.at_client); | 1063 DCHECK(!output_record.at_client); |
1059 DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR); | |
1060 DCHECK_NE(output_record.picture_id, -1); | 1064 DCHECK_NE(output_record.picture_id, -1); |
1061 | 1065 |
1062 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { | 1066 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { |
1063 // If we have to wait for completion, wait. Note that | 1067 // If we have to wait for completion, wait. Note that |
1064 // free_output_buffers_ is a FIFO queue, so we always wait on the | 1068 // free_output_buffers_ is a FIFO queue, so we always wait on the |
1065 // buffer that has been in the queue the longest. | 1069 // buffer that has been in the queue the longest. |
1066 if (eglClientWaitSyncKHR(egl_display_, output_record.egl_sync, 0, | 1070 if (eglClientWaitSyncKHR(egl_display_, output_record.egl_sync, 0, |
1067 EGL_FOREVER_KHR) == EGL_FALSE) { | 1071 EGL_FOREVER_KHR) == EGL_FALSE) { |
1068 // This will cause tearing, but is safe otherwise. | 1072 // This will cause tearing, but is safe otherwise. |
1069 DVLOGF(1) << "eglClientWaitSyncKHR failed!"; | 1073 DVLOGF(1) << "eglClientWaitSyncKHR failed!"; |
1070 } | 1074 } |
1071 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { | 1075 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { |
1072 LOGF(ERROR) << "eglDestroySyncKHR failed!"; | 1076 LOGF(ERROR) << "eglDestroySyncKHR failed!"; |
1073 NOTIFY_ERROR(PLATFORM_FAILURE); | 1077 NOTIFY_ERROR(PLATFORM_FAILURE); |
1074 return false; | 1078 return false; |
1075 } | 1079 } |
1076 output_record.egl_sync = EGL_NO_SYNC_KHR; | 1080 output_record.egl_sync = EGL_NO_SYNC_KHR; |
1077 } | 1081 } |
1078 | 1082 |
1079 struct v4l2_buffer qbuf; | 1083 struct v4l2_buffer qbuf; |
1080 struct v4l2_plane qbuf_planes[VIDEO_MAX_PLANES]; | 1084 struct v4l2_plane qbuf_planes[VIDEO_MAX_PLANES]; |
1081 memset(&qbuf, 0, sizeof(qbuf)); | 1085 memset(&qbuf, 0, sizeof(qbuf)); |
1082 memset(qbuf_planes, 0, sizeof(qbuf_planes)); | 1086 memset(qbuf_planes, 0, sizeof(qbuf_planes)); |
1083 qbuf.index = index; | 1087 qbuf.index = index; |
1084 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1088 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
1085 qbuf.memory = V4L2_MEMORY_MMAP; | 1089 if (output_mode_ == Config::OutputMode::ALLOCATE) { |
1090 qbuf.memory = V4L2_MEMORY_MMAP; | |
1091 } else { | |
1092 qbuf.memory = V4L2_MEMORY_DMABUF; | |
1093 DCHECK_EQ(output_planes_count_, output_record.dmabuf_fds.size()); | |
1094 for (size_t i = 0; i < output_record.dmabuf_fds.size(); ++i) { | |
1095 DCHECK_NE(output_record.dmabuf_fds[i].get(), -1); | |
Owen Lin
2016/03/23 06:32:50
DCHECK(output_record.dmabuf_fds[i].is_valid());
Pawel Osciak
2016/03/28 01:31:29
Done.
| |
1096 qbuf_planes[i].m.fd = output_record.dmabuf_fds[i].get(); | |
1097 } | |
1098 } | |
1086 qbuf.m.planes = qbuf_planes; | 1099 qbuf.m.planes = qbuf_planes; |
1087 qbuf.length = output_planes_count_; | 1100 qbuf.length = output_planes_count_; |
1088 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); | 1101 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); |
1089 output_record.at_device = true; | 1102 output_record.at_device = true; |
1090 output_buffer_queued_count_++; | 1103 output_buffer_queued_count_++; |
1091 DVLOGF(4) << "Enqueued output=" << qbuf.index | 1104 DVLOGF(4) << "Enqueued output=" << qbuf.index |
1092 << " count: " << output_buffer_queued_count_; | 1105 << " count: " << output_buffer_queued_count_; |
1093 | 1106 |
1094 return true; | 1107 return true; |
1095 } | 1108 } |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1358 // yet. We will not start decoding without having surfaces available, | 1371 // yet. We will not start decoding without having surfaces available, |
1359 // and will schedule a decode task once the client provides the buffers. | 1372 // and will schedule a decode task once the client provides the buffers. |
1360 surface_set_change_pending_ = false; | 1373 surface_set_change_pending_ = false; |
1361 DVLOG(3) << "Surface set change finished"; | 1374 DVLOG(3) << "Surface set change finished"; |
1362 return true; | 1375 return true; |
1363 } | 1376 } |
1364 | 1377 |
1365 bool V4L2SliceVideoDecodeAccelerator::DestroyOutputs(bool dismiss) { | 1378 bool V4L2SliceVideoDecodeAccelerator::DestroyOutputs(bool dismiss) { |
1366 DVLOGF(3); | 1379 DVLOGF(3); |
1367 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1380 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
1368 std::vector<EGLImageKHR> egl_images_to_destroy; | 1381 std::vector<EGLImageKHR> egl_images_to_destroy; |
kcwu
2016/03/22 05:42:54
unused
Pawel Osciak
2016/03/28 01:31:28
Done.
| |
1369 std::vector<int32_t> picture_buffers_to_dismiss; | 1382 std::vector<int32_t> picture_buffers_to_dismiss; |
1370 | 1383 |
1371 if (output_buffer_map_.empty()) | 1384 if (output_buffer_map_.empty()) |
1372 return true; | 1385 return true; |
1373 | 1386 |
1374 for (auto output_record : output_buffer_map_) { | 1387 for (const auto& output_record : output_buffer_map_) { |
1375 DCHECK(!output_record.at_device); | 1388 DCHECK(!output_record.at_device); |
1376 | 1389 |
1377 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { | 1390 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { |
1378 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) | 1391 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) |
1379 DVLOGF(1) << "eglDestroySyncKHR failed."; | 1392 DVLOGF(1) << "eglDestroySyncKHR failed."; |
1380 } | 1393 } |
1381 | 1394 |
1382 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { | 1395 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { |
1383 child_task_runner_->PostTask( | 1396 child_task_runner_->PostTask( |
1384 FROM_HERE, | 1397 FROM_HERE, |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1469 << ", requested " << req_buffer_count << ")"; | 1482 << ", requested " << req_buffer_count << ")"; |
1470 NOTIFY_ERROR(INVALID_ARGUMENT); | 1483 NOTIFY_ERROR(INVALID_ARGUMENT); |
1471 return; | 1484 return; |
1472 } | 1485 } |
1473 | 1486 |
1474 // Allocate the output buffers. | 1487 // Allocate the output buffers. |
1475 struct v4l2_requestbuffers reqbufs; | 1488 struct v4l2_requestbuffers reqbufs; |
1476 memset(&reqbufs, 0, sizeof(reqbufs)); | 1489 memset(&reqbufs, 0, sizeof(reqbufs)); |
1477 reqbufs.count = buffers.size(); | 1490 reqbufs.count = buffers.size(); |
1478 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1491 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
1479 reqbufs.memory = V4L2_MEMORY_MMAP; | 1492 if (output_mode_ == Config::OutputMode::ALLOCATE) |
1493 reqbufs.memory = V4L2_MEMORY_MMAP; | |
Owen Lin
2016/03/23 06:32:50
ditto.
Pawel Osciak
2016/03/28 01:31:28
Done.
| |
1494 else | |
1495 reqbufs.memory = V4L2_MEMORY_DMABUF; | |
1480 IOCTL_OR_ERROR_RETURN(VIDIOC_REQBUFS, &reqbufs); | 1496 IOCTL_OR_ERROR_RETURN(VIDIOC_REQBUFS, &reqbufs); |
1481 | 1497 |
1482 if (reqbufs.count != buffers.size()) { | 1498 if (reqbufs.count != buffers.size()) { |
1483 DLOG(ERROR) << "Could not allocate enough output buffers"; | 1499 DLOG(ERROR) << "Could not allocate enough output buffers"; |
1484 NOTIFY_ERROR(PLATFORM_FAILURE); | 1500 NOTIFY_ERROR(PLATFORM_FAILURE); |
1485 return; | 1501 return; |
1486 } | 1502 } |
1487 | 1503 |
1488 child_task_runner_->PostTask( | 1504 DCHECK(free_output_buffers_.empty()); |
1489 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::CreateEGLImages, | 1505 DCHECK(output_buffer_map_.empty()); |
1490 weak_this_, buffers, output_format_fourcc_, | 1506 output_buffer_map_.resize(buffers.size()); |
1491 output_planes_count_)); | 1507 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
1508 DCHECK(buffers[i].size() == coded_size_); | |
1509 | |
1510 OutputRecord& output_record = output_buffer_map_[i]; | |
1511 DCHECK(!output_record.at_device); | |
1512 DCHECK(!output_record.at_client); | |
1513 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); | |
1514 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | |
1515 DCHECK_EQ(output_record.picture_id, -1); | |
1516 DCHECK(output_record.dmabuf_fds.empty()); | |
1517 DCHECK_EQ(output_record.cleared, false); | |
1518 | |
1519 output_record.picture_id = buffers[i].id(); | |
1520 output_record.texture_id = buffers[i].texture_id(); | |
1521 // This will remain true until ImportBufferForPicture is called, either by | |
1522 // the client, or by ourselves, if we are allocating. | |
1523 output_record.at_client = true; | |
Owen Lin
2016/03/23 06:32:50
As suggested by kcwu, maybe we can make it a singl
Pawel Osciak
2016/03/28 01:31:29
As discussed offline, to be addressed separately.
| |
1524 if (output_mode_ == Config::OutputMode::ALLOCATE) { | |
1525 std::vector<base::ScopedFD> dmabuf_fds = | |
1526 std::move(device_->GetDmabufsForV4L2Buffer( | |
1527 i, output_planes_count_, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)); | |
1528 if (dmabuf_fds.empty()) { | |
1529 NOTIFY_ERROR(PLATFORM_FAILURE); | |
1530 return; | |
1531 } | |
1532 | |
1533 auto passed_dmabuf_fds(make_scoped_ptr( | |
1534 new std::vector<base::ScopedFD>(std::move(dmabuf_fds)))); | |
1535 ImportBufferForPictureTask(output_record.picture_id, | |
1536 std::move(passed_dmabuf_fds)); | |
1537 } // else we'll get triggered via ImportBufferForPicture() from client. | |
1538 DVLOGF(3) << "buffer[" << i << "]: picture_id=" << output_record.picture_id; | |
1539 } | |
1540 | |
1541 if (!StartDevicePoll()) { | |
1542 NOTIFY_ERROR(PLATFORM_FAILURE); | |
1543 return; | |
1544 } | |
1492 } | 1545 } |
1493 | 1546 |
1494 void V4L2SliceVideoDecodeAccelerator::CreateEGLImages( | 1547 void V4L2SliceVideoDecodeAccelerator::CreateEGLImageFor( |
1495 const std::vector<media::PictureBuffer>& buffers, | 1548 size_t buffer_index, |
1496 uint32_t output_format_fourcc, | 1549 scoped_ptr<std::vector<base::ScopedFD>> passed_dmabuf_fds, |
1497 size_t output_planes_count) { | 1550 GLuint texture_id, |
1498 DVLOGF(3); | 1551 const gfx::Size& size, |
1552 uint32_t fourcc) { | |
1553 DVLOGF(3) << "index=" << buffer_index; | |
1499 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 1554 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
1500 | 1555 |
1501 gfx::GLContext* gl_context = get_gl_context_cb_.Run(); | 1556 gfx::GLContext* gl_context = get_gl_context_cb_.Run(); |
1502 if (!gl_context || !make_context_current_cb_.Run()) { | 1557 if (!gl_context || !make_context_current_cb_.Run()) { |
1503 DLOG(ERROR) << "No GL context"; | 1558 DLOG(ERROR) << "No GL context"; |
1504 NOTIFY_ERROR(PLATFORM_FAILURE); | 1559 NOTIFY_ERROR(PLATFORM_FAILURE); |
1505 return; | 1560 return; |
1506 } | 1561 } |
1507 | 1562 |
1508 gfx::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); | 1563 gfx::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); |
1509 | 1564 |
1510 std::vector<EGLImageKHR> egl_images; | 1565 EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_, |
1511 for (size_t i = 0; i < buffers.size(); ++i) { | 1566 gl_context->GetHandle(), |
1512 EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_, | 1567 texture_id, |
1513 gl_context->GetHandle(), | 1568 size, |
1514 buffers[i].texture_id(), | 1569 buffer_index, |
1515 buffers[i].size(), | 1570 fourcc, |
1516 i, | 1571 *passed_dmabuf_fds); |
1517 output_format_fourcc, | 1572 if (egl_image == EGL_NO_IMAGE_KHR) { |
1518 output_planes_count); | 1573 LOGF(ERROR) << "Could not create EGLImageKHR," |
1519 if (egl_image == EGL_NO_IMAGE_KHR) { | 1574 << " index=" << buffer_index << " texture_id=" << texture_id; |
kcwu
2016/03/22 05:42:54
why not NOTIFY_ERROR and return here?
Pawel Osciak
2016/03/28 01:31:29
Done.
| |
1520 LOGF(ERROR) << "Could not create EGLImageKHR"; | |
1521 for (const auto& image_to_destroy : egl_images) | |
1522 device_->DestroyEGLImage(egl_display_, image_to_destroy); | |
1523 | |
1524 NOTIFY_ERROR(PLATFORM_FAILURE); | |
1525 return; | |
1526 } | |
1527 | |
1528 egl_images.push_back(egl_image); | |
1529 } | 1575 } |
1530 | 1576 |
1531 decoder_thread_task_runner_->PostTask( | 1577 decoder_thread_task_runner_->PostTask( |
1532 FROM_HERE, base::Bind( | 1578 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::AssignEGLImage, |
1533 &V4L2SliceVideoDecodeAccelerator::AssignEGLImages, | 1579 base::Unretained(this), buffer_index, egl_image, |
1534 base::Unretained(this), buffers, egl_images)); | 1580 base::Passed(&passed_dmabuf_fds))); |
1535 } | 1581 } |
1536 | 1582 |
1537 void V4L2SliceVideoDecodeAccelerator::AssignEGLImages( | 1583 void V4L2SliceVideoDecodeAccelerator::AssignEGLImage( |
1538 const std::vector<media::PictureBuffer>& buffers, | 1584 size_t buffer_index, |
1539 const std::vector<EGLImageKHR>& egl_images) { | 1585 EGLImageKHR egl_image, |
1540 DVLOGF(3); | 1586 scoped_ptr<std::vector<base::ScopedFD>> passed_dmabuf_fds) { |
1587 DVLOGF(3) << "index=" << buffer_index; | |
1541 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1588 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
1542 DCHECK_EQ(buffers.size(), egl_images.size()); | |
1543 | 1589 |
1544 DCHECK(free_output_buffers_.empty()); | 1590 DCHECK_LT(buffer_index, output_buffer_map_.size()); |
1545 DCHECK(output_buffer_map_.empty()); | 1591 OutputRecord& output_record = output_buffer_map_[buffer_index]; |
1592 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); | |
1593 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | |
1594 DCHECK(!output_record.at_client); | |
1595 DCHECK(!output_record.at_device); | |
1546 | 1596 |
1547 output_buffer_map_.resize(buffers.size()); | 1597 output_record.egl_image = egl_image; |
1548 | 1598 if (output_mode_ == Config::OutputMode::IMPORT) { |
1549 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { | 1599 DCHECK(output_record.dmabuf_fds.empty()); |
1550 DCHECK(buffers[i].size() == coded_size_); | 1600 output_record.dmabuf_fds.swap(*passed_dmabuf_fds); |
Owen Lin
2016/03/23 06:32:50
std::move(*passed_dmabuf_fds);
Pawel Osciak
2016/03/28 01:31:28
Done.
| |
1551 | |
1552 OutputRecord& output_record = output_buffer_map_[i]; | |
1553 DCHECK(!output_record.at_device); | |
1554 DCHECK(!output_record.at_client); | |
1555 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); | |
1556 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | |
1557 DCHECK_EQ(output_record.picture_id, -1); | |
1558 DCHECK_EQ(output_record.cleared, false); | |
1559 | |
1560 output_record.egl_image = egl_images[i]; | |
1561 output_record.picture_id = buffers[i].id(); | |
1562 free_output_buffers_.push_back(i); | |
1563 DVLOGF(3) << "buffer[" << i << "]: picture_id=" << output_record.picture_id; | |
1564 } | 1601 } |
1565 | 1602 |
1566 if (!StartDevicePoll()) { | 1603 DCHECK_EQ(std::count(free_output_buffers_.begin(), free_output_buffers_.end(), |
Owen Lin
2016/03/23 06:32:50
Will it be nice to have a static function:
bool c
Pawel Osciak
2016/03/28 01:31:29
Hmm... Sound like a good idea, but I'm on the fenc
| |
1567 NOTIFY_ERROR(PLATFORM_FAILURE); | 1604 buffer_index), |
1605 0); | |
1606 free_output_buffers_.push_back(buffer_index); | |
1607 ScheduleDecodeBufferTaskIfNeeded(); | |
1608 } | |
1609 | |
1610 void V4L2SliceVideoDecodeAccelerator::ImportBufferForPicture( | |
1611 int32_t picture_buffer_id, | |
1612 const std::vector<gfx::GpuMemoryBufferHandle>& gpu_memory_buffer_handles) { | |
1613 DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id; | |
1614 DCHECK(child_task_runner_->BelongsToCurrentThread()); | |
1615 | |
1616 auto passed_dmabuf_fds(make_scoped_ptr(new std::vector<base::ScopedFD>)); | |
kcwu
2016/03/22 05:42:54
Add "()" for new.
new std::vector<base::ScopedFD>(
Pawel Osciak
2016/03/28 01:31:29
Done.
| |
1617 for (const auto& handle : gpu_memory_buffer_handles) { | |
1618 int fd = handle.native_pixmap_handle.fd.fd; | |
kcwu
2016/03/22 05:42:54
I found native_pixelmap_handle is only available i
Pawel Osciak
2016/03/28 01:31:29
Done.
| |
1619 DCHECK_NE(fd, -1); | |
1620 passed_dmabuf_fds->push_back(base::ScopedFD(fd)); | |
1621 } | |
1622 | |
1623 if (output_mode_ != Config::OutputMode::IMPORT) { | |
1624 LOGF(ERROR) << "Cannot import in non-import mode"; | |
1625 NOTIFY_ERROR(INVALID_ARGUMENT); | |
1568 return; | 1626 return; |
1569 } | 1627 } |
1570 | 1628 |
1571 ProcessPendingEventsIfNeeded(); | 1629 decoder_thread_task_runner_->PostTask( |
1630 FROM_HERE, | |
1631 base::Bind(&V4L2SliceVideoDecodeAccelerator::ImportBufferForPictureTask, | |
1632 base::Unretained(this), picture_buffer_id, | |
1633 base::Passed(&passed_dmabuf_fds))); | |
1634 } | |
1635 | |
1636 void V4L2SliceVideoDecodeAccelerator::ImportBufferForPictureTask( | |
1637 int32_t picture_buffer_id, | |
1638 scoped_ptr<std::vector<base::ScopedFD>> passed_dmabuf_fds) { | |
1639 DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id; | |
1640 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | |
1641 | |
1642 const auto iter = | |
1643 std::find_if(output_buffer_map_.begin(), output_buffer_map_.end(), | |
1644 [picture_buffer_id](const OutputRecord& output_record) { | |
1645 return output_record.picture_id == picture_buffer_id; | |
1646 }); | |
1647 if (iter == output_buffer_map_.end()) { | |
1648 LOGF(ERROR) << "Invalid picture_buffer_id=" << picture_buffer_id; | |
1649 NOTIFY_ERROR(INVALID_ARGUMENT); | |
1650 return; | |
1651 } | |
1652 | |
1653 if (!iter->at_client) { | |
1654 LOGF(ERROR) << "Cannot import buffer that not owned by client"; | |
1655 NOTIFY_ERROR(INVALID_ARGUMENT); | |
1656 return; | |
1657 } | |
1658 | |
1659 size_t index = iter - output_buffer_map_.begin(); | |
1660 DCHECK_EQ(std::count(free_output_buffers_.begin(), free_output_buffers_.end(), | |
1661 index), | |
1662 0); | |
1663 | |
1664 DCHECK(!iter->at_device); | |
1665 iter->at_client = false; | |
1666 if (iter->texture_id != 0) { | |
1667 if (iter->egl_image != EGL_NO_IMAGE_KHR) { | |
1668 child_task_runner_->PostTask( | |
1669 FROM_HERE, | |
1670 base::Bind(base::IgnoreResult(&V4L2Device::DestroyEGLImage), device_, | |
1671 egl_display_, iter->egl_image)); | |
1672 } | |
1673 | |
1674 child_task_runner_->PostTask( | |
1675 FROM_HERE, | |
1676 base::Bind(&V4L2SliceVideoDecodeAccelerator::CreateEGLImageFor, | |
1677 weak_this_, index, base::Passed(&passed_dmabuf_fds), | |
1678 iter->texture_id, coded_size_, output_format_fourcc_)); | |
1679 } else { | |
1680 // No need for an EGLImage, start using this buffer now. | |
1681 DCHECK_EQ(output_planes_count_, passed_dmabuf_fds->size()); | |
1682 iter->dmabuf_fds.swap(*passed_dmabuf_fds); | |
1683 free_output_buffers_.push_back(index); | |
1684 ScheduleDecodeBufferTaskIfNeeded(); | |
1685 } | |
1572 } | 1686 } |
1573 | 1687 |
1574 void V4L2SliceVideoDecodeAccelerator::ReusePictureBuffer( | 1688 void V4L2SliceVideoDecodeAccelerator::ReusePictureBuffer( |
1575 int32_t picture_buffer_id) { | 1689 int32_t picture_buffer_id) { |
1576 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 1690 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
1577 DVLOGF(4) << "picture_buffer_id=" << picture_buffer_id; | 1691 DVLOGF(4) << "picture_buffer_id=" << picture_buffer_id; |
1578 | 1692 |
1579 if (!make_context_current_cb_.Run()) { | 1693 if (!make_context_current_cb_.Run()) { |
1580 LOGF(ERROR) << "could not make context current"; | 1694 LOGF(ERROR) << "could not make context current"; |
1581 NOTIFY_ERROR(PLATFORM_FAILURE); | 1695 NOTIFY_ERROR(PLATFORM_FAILURE); |
(...skipping 921 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2503 OutputRecord& output_record = | 2617 OutputRecord& output_record = |
2504 output_buffer_map_[dec_surface->output_record()]; | 2618 output_buffer_map_[dec_surface->output_record()]; |
2505 | 2619 |
2506 bool inserted = | 2620 bool inserted = |
2507 surfaces_at_display_.insert(std::make_pair(output_record.picture_id, | 2621 surfaces_at_display_.insert(std::make_pair(output_record.picture_id, |
2508 dec_surface)).second; | 2622 dec_surface)).second; |
2509 DCHECK(inserted); | 2623 DCHECK(inserted); |
2510 | 2624 |
2511 DCHECK(!output_record.at_client); | 2625 DCHECK(!output_record.at_client); |
2512 DCHECK(!output_record.at_device); | 2626 DCHECK(!output_record.at_device); |
2513 DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR); | |
2514 DCHECK_NE(output_record.picture_id, -1); | 2627 DCHECK_NE(output_record.picture_id, -1); |
2515 output_record.at_client = true; | 2628 output_record.at_client = true; |
2516 | 2629 |
2517 // TODO(posciak): Use visible size from decoder here instead | 2630 // TODO(posciak): Use visible size from decoder here instead |
2518 // (crbug.com/402760). Passing (0, 0) results in the client using the | 2631 // (crbug.com/402760). Passing (0, 0) results in the client using the |
2519 // visible size extracted from the container instead. | 2632 // visible size extracted from the container instead. |
2520 media::Picture picture(output_record.picture_id, dec_surface->bitstream_id(), | 2633 media::Picture picture(output_record.picture_id, dec_surface->bitstream_id(), |
2521 gfx::Rect(0, 0), false); | 2634 gfx::Rect(0, 0), false); |
2522 DVLOGF(3) << dec_surface->ToString() | 2635 DVLOGF(3) << dec_surface->ToString() |
2523 << ", bitstream_id: " << picture.bitstream_buffer_id() | 2636 << ", bitstream_id: " << picture.bitstream_buffer_id() |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2609 } | 2722 } |
2610 | 2723 |
2611 bool V4L2SliceVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( | 2724 bool V4L2SliceVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( |
2612 const base::WeakPtr<Client>& decode_client, | 2725 const base::WeakPtr<Client>& decode_client, |
2613 const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { | 2726 const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { |
2614 decode_client_ = decode_client_; | 2727 decode_client_ = decode_client_; |
2615 decode_task_runner_ = decode_task_runner; | 2728 decode_task_runner_ = decode_task_runner; |
2616 return true; | 2729 return true; |
2617 } | 2730 } |
2618 | 2731 |
2732 media::VideoPixelFormat V4L2SliceVideoDecodeAccelerator::GetOutputFormat() | |
2733 const { | |
2734 return V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc_); | |
2735 } | |
2736 | |
2619 // static | 2737 // static |
2620 media::VideoDecodeAccelerator::SupportedProfiles | 2738 media::VideoDecodeAccelerator::SupportedProfiles |
2621 V4L2SliceVideoDecodeAccelerator::GetSupportedProfiles() { | 2739 V4L2SliceVideoDecodeAccelerator::GetSupportedProfiles() { |
2622 scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); | 2740 scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); |
2623 if (!device) | 2741 if (!device) |
2624 return SupportedProfiles(); | 2742 return SupportedProfiles(); |
2625 | 2743 |
2626 return device->GetSupportedDecodeProfiles(arraysize(supported_input_fourccs_), | 2744 return device->GetSupportedDecodeProfiles(arraysize(supported_input_fourccs_), |
2627 supported_input_fourccs_); | 2745 supported_input_fourccs_); |
2628 } | 2746 } |
2629 | 2747 |
2630 } // namespace content | 2748 } // namespace content |
OLD | NEW |