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 <linux/videodev2.h> | 6 #include <linux/videodev2.h> |
7 #include <string.h> | 7 #include <string.h> |
8 #include <sys/mman.h> | 8 #include <sys/mman.h> |
9 | 9 |
10 #include "base/big_endian.h" | 10 #include "base/big_endian.h" |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 }; | 105 }; |
106 | 106 |
107 V4L2JpegDecodeAccelerator::BufferRecord::BufferRecord() | 107 V4L2JpegDecodeAccelerator::BufferRecord::BufferRecord() |
108 : address(nullptr), length(0), at_device(false) { | 108 : address(nullptr), length(0), at_device(false) { |
109 } | 109 } |
110 | 110 |
111 V4L2JpegDecodeAccelerator::BufferRecord::~BufferRecord() { | 111 V4L2JpegDecodeAccelerator::BufferRecord::~BufferRecord() { |
112 } | 112 } |
113 | 113 |
114 V4L2JpegDecodeAccelerator::JobRecord::JobRecord( | 114 V4L2JpegDecodeAccelerator::JobRecord::JobRecord( |
115 media::BitstreamBuffer bitstream_buffer, | 115 const media::BitstreamBuffer& bitstream_buffer, |
116 scoped_refptr<media::VideoFrame> video_frame) | 116 scoped_refptr<media::VideoFrame> video_frame) |
117 : bitstream_buffer(bitstream_buffer), out_frame(video_frame) { | 117 : bitstream_buffer_id(bitstream_buffer.id()), |
118 } | 118 shm(bitstream_buffer, true), |
| 119 out_frame(video_frame) {} |
119 | 120 |
120 V4L2JpegDecodeAccelerator::JobRecord::~JobRecord() { | 121 V4L2JpegDecodeAccelerator::JobRecord::~JobRecord() { |
121 } | 122 } |
122 | 123 |
123 V4L2JpegDecodeAccelerator::V4L2JpegDecodeAccelerator( | 124 V4L2JpegDecodeAccelerator::V4L2JpegDecodeAccelerator( |
124 const scoped_refptr<V4L2Device>& device, | 125 const scoped_refptr<V4L2Device>& device, |
125 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) | 126 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) |
126 : output_buffer_pixelformat_(0), | 127 : output_buffer_pixelformat_(0), |
127 child_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 128 child_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
128 io_task_runner_(io_task_runner), | 129 io_task_runner_(io_task_runner), |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 | 262 |
262 for (; device_->Ioctl(VIDIOC_ENUM_FMT, &fmtdesc) == 0; ++fmtdesc.index) { | 263 for (; device_->Ioctl(VIDIOC_ENUM_FMT, &fmtdesc) == 0; ++fmtdesc.index) { |
263 if (fmtdesc.pixelformat == V4L2_PIX_FMT_JPEG) | 264 if (fmtdesc.pixelformat == V4L2_PIX_FMT_JPEG) |
264 return true; | 265 return true; |
265 } | 266 } |
266 return false; | 267 return false; |
267 } | 268 } |
268 | 269 |
269 void V4L2JpegDecodeAccelerator::DecodeTask(scoped_ptr<JobRecord> job_record) { | 270 void V4L2JpegDecodeAccelerator::DecodeTask(scoped_ptr<JobRecord> job_record) { |
270 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); | 271 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); |
271 job_record->shm.reset( | 272 if (!job_record->shm.Map()) { |
272 new base::SharedMemory(job_record->bitstream_buffer.handle(), true)); | |
273 if (!job_record->shm->Map(job_record->bitstream_buffer.size())) { | |
274 PLOG(ERROR) << __func__ << ": could not map bitstream_buffer"; | 273 PLOG(ERROR) << __func__ << ": could not map bitstream_buffer"; |
275 PostNotifyError(job_record->bitstream_buffer.id(), UNREADABLE_INPUT); | 274 PostNotifyError(job_record->bitstream_buffer_id, UNREADABLE_INPUT); |
276 return; | 275 return; |
277 } | 276 } |
278 input_jobs_.push(make_linked_ptr(job_record.release())); | 277 input_jobs_.push(make_linked_ptr(job_record.release())); |
279 | 278 |
280 ServiceDeviceTask(false); | 279 ServiceDeviceTask(false); |
281 } | 280 } |
282 | 281 |
283 size_t V4L2JpegDecodeAccelerator::InputBufferQueuedCount() { | 282 size_t V4L2JpegDecodeAccelerator::InputBufferQueuedCount() { |
284 return input_buffer_map_.size() - free_input_buffers_.size(); | 283 return input_buffer_map_.size() - free_input_buffers_.size(); |
285 } | 284 } |
286 | 285 |
287 size_t V4L2JpegDecodeAccelerator::OutputBufferQueuedCount() { | 286 size_t V4L2JpegDecodeAccelerator::OutputBufferQueuedCount() { |
288 return output_buffer_map_.size() - free_output_buffers_.size(); | 287 return output_buffer_map_.size() - free_output_buffers_.size(); |
289 } | 288 } |
290 | 289 |
291 bool V4L2JpegDecodeAccelerator::ShouldRecreateInputBuffers() { | 290 bool V4L2JpegDecodeAccelerator::ShouldRecreateInputBuffers() { |
292 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); | 291 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); |
293 if (input_jobs_.empty()) | 292 if (input_jobs_.empty()) |
294 return false; | 293 return false; |
295 | 294 |
296 linked_ptr<JobRecord> job_record = input_jobs_.front(); | 295 linked_ptr<JobRecord> job_record = input_jobs_.front(); |
297 // Check input buffer size is enough | 296 // Check input buffer size is enough |
298 return (input_buffer_map_.empty() || | 297 return (input_buffer_map_.empty() || |
299 (job_record->bitstream_buffer.size() + sizeof(kDefaultDhtSeg)) > | 298 (job_record->shm.size() + sizeof(kDefaultDhtSeg)) > |
300 input_buffer_map_.front().length); | 299 input_buffer_map_.front().length); |
301 } | 300 } |
302 | 301 |
303 bool V4L2JpegDecodeAccelerator::RecreateInputBuffers() { | 302 bool V4L2JpegDecodeAccelerator::RecreateInputBuffers() { |
304 DVLOG(3) << __func__; | 303 DVLOG(3) << __func__; |
305 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); | 304 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); |
306 | 305 |
307 // If running queue is not empty, we should wait until pending frames finish. | 306 // If running queue is not empty, we should wait until pending frames finish. |
308 if (!running_jobs_.empty()) | 307 if (!running_jobs_.empty()) |
309 return true; | 308 return true; |
(...skipping 24 matching lines...) Expand all Loading... |
334 | 333 |
335 bool V4L2JpegDecodeAccelerator::CreateInputBuffers() { | 334 bool V4L2JpegDecodeAccelerator::CreateInputBuffers() { |
336 DVLOG(3) << __func__; | 335 DVLOG(3) << __func__; |
337 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); | 336 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); |
338 DCHECK(!input_streamon_); | 337 DCHECK(!input_streamon_); |
339 DCHECK(!input_jobs_.empty()); | 338 DCHECK(!input_jobs_.empty()); |
340 linked_ptr<JobRecord> job_record = input_jobs_.front(); | 339 linked_ptr<JobRecord> job_record = input_jobs_.front(); |
341 // The input image may miss huffman table. We didn't parse the image before, | 340 // The input image may miss huffman table. We didn't parse the image before, |
342 // so we create more to avoid the situation of not enough memory. | 341 // so we create more to avoid the situation of not enough memory. |
343 // Reserve twice size to avoid recreating input buffer frequently. | 342 // Reserve twice size to avoid recreating input buffer frequently. |
344 size_t reserve_size = | 343 size_t reserve_size = (job_record->shm.size() + sizeof(kDefaultDhtSeg)) * 2; |
345 (job_record->bitstream_buffer.size() + sizeof(kDefaultDhtSeg)) * 2; | |
346 struct v4l2_format format; | 344 struct v4l2_format format; |
347 memset(&format, 0, sizeof(format)); | 345 memset(&format, 0, sizeof(format)); |
348 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | 346 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; |
349 format.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG; | 347 format.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG; |
350 format.fmt.pix.sizeimage = reserve_size; | 348 format.fmt.pix.sizeimage = reserve_size; |
351 format.fmt.pix.field = V4L2_FIELD_ANY; | 349 format.fmt.pix.field = V4L2_FIELD_ANY; |
352 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); | 350 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); |
353 | 351 |
354 struct v4l2_requestbuffers reqbufs; | 352 struct v4l2_requestbuffers reqbufs; |
355 memset(&reqbufs, 0, sizeof(reqbufs)); | 353 memset(&reqbufs, 0, sizeof(reqbufs)); |
(...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
712 | 710 |
713 if (dqbuf.flags & V4L2_BUF_FLAG_ERROR) { | 711 if (dqbuf.flags & V4L2_BUF_FLAG_ERROR) { |
714 DVLOG(1) << "Dequeue output buffer error."; | 712 DVLOG(1) << "Dequeue output buffer error."; |
715 PostNotifyError(kInvalidBitstreamBufferId, UNSUPPORTED_JPEG); | 713 PostNotifyError(kInvalidBitstreamBufferId, UNSUPPORTED_JPEG); |
716 } else { | 714 } else { |
717 // Copy the decoded data from output buffer to the buffer provided by the | 715 // Copy the decoded data from output buffer to the buffer provided by the |
718 // client. Do format conversion when output format is not | 716 // client. Do format conversion when output format is not |
719 // V4L2_PIX_FMT_YUV420. | 717 // V4L2_PIX_FMT_YUV420. |
720 if (!CopyOutputImage(output_buffer_pixelformat_, output_record.address, | 718 if (!CopyOutputImage(output_buffer_pixelformat_, output_record.address, |
721 output_buffer_coded_size_, job_record->out_frame)) { | 719 output_buffer_coded_size_, job_record->out_frame)) { |
722 PostNotifyError(job_record->bitstream_buffer.id(), PLATFORM_FAILURE); | 720 PostNotifyError(job_record->bitstream_buffer_id, PLATFORM_FAILURE); |
723 return; | 721 return; |
724 } | 722 } |
725 | 723 |
726 DVLOG(3) << "Decoding finished, returning bitstream buffer, id=" | 724 DVLOG(3) << "Decoding finished, returning bitstream buffer, id=" |
727 << job_record->bitstream_buffer.id(); | 725 << job_record->bitstream_buffer_id; |
728 | 726 |
729 child_task_runner_->PostTask( | 727 child_task_runner_->PostTask( |
730 FROM_HERE, | 728 FROM_HERE, base::Bind(&V4L2JpegDecodeAccelerator::VideoFrameReady, |
731 base::Bind(&V4L2JpegDecodeAccelerator::VideoFrameReady, weak_ptr_, | 729 weak_ptr_, job_record->bitstream_buffer_id)); |
732 job_record->bitstream_buffer.id())); | |
733 } | 730 } |
734 } | 731 } |
735 } | 732 } |
736 | 733 |
737 static bool AddHuffmanTable(const void* input_ptr, | 734 static bool AddHuffmanTable(const void* input_ptr, |
738 size_t input_size, | 735 size_t input_size, |
739 void* output_ptr, | 736 void* output_ptr, |
740 size_t output_size) { | 737 size_t output_size) { |
741 DCHECK(input_ptr); | 738 DCHECK(input_ptr); |
742 DCHECK(output_ptr); | 739 DCHECK(output_ptr); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
820 DCHECK(!free_input_buffers_.empty()); | 817 DCHECK(!free_input_buffers_.empty()); |
821 | 818 |
822 // Enqueue an input (VIDEO_OUTPUT) buffer for an input video frame. | 819 // Enqueue an input (VIDEO_OUTPUT) buffer for an input video frame. |
823 linked_ptr<JobRecord> job_record = input_jobs_.front(); | 820 linked_ptr<JobRecord> job_record = input_jobs_.front(); |
824 input_jobs_.pop(); | 821 input_jobs_.pop(); |
825 const int index = free_input_buffers_.back(); | 822 const int index = free_input_buffers_.back(); |
826 BufferRecord& input_record = input_buffer_map_[index]; | 823 BufferRecord& input_record = input_buffer_map_[index]; |
827 DCHECK(!input_record.at_device); | 824 DCHECK(!input_record.at_device); |
828 | 825 |
829 // It will add default huffman segment if it's missing. | 826 // It will add default huffman segment if it's missing. |
830 if (!AddHuffmanTable(job_record->shm->memory(), | 827 if (!AddHuffmanTable(job_record->shm.memory(), job_record->shm.size(), |
831 job_record->bitstream_buffer.size(), | |
832 input_record.address, input_record.length)) { | 828 input_record.address, input_record.length)) { |
833 PostNotifyError(job_record->bitstream_buffer.id(), PARSE_JPEG_FAILED); | 829 PostNotifyError(job_record->bitstream_buffer_id, PARSE_JPEG_FAILED); |
834 return false; | 830 return false; |
835 } | 831 } |
836 | 832 |
837 struct v4l2_buffer qbuf; | 833 struct v4l2_buffer qbuf; |
838 memset(&qbuf, 0, sizeof(qbuf)); | 834 memset(&qbuf, 0, sizeof(qbuf)); |
839 qbuf.index = index; | 835 qbuf.index = index; |
840 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | 836 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; |
841 qbuf.memory = V4L2_MEMORY_MMAP; | 837 qbuf.memory = V4L2_MEMORY_MMAP; |
842 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); | 838 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); |
843 input_record.at_device = true; | 839 input_record.at_device = true; |
844 running_jobs_.push(job_record); | 840 running_jobs_.push(job_record); |
845 free_input_buffers_.pop_back(); | 841 free_input_buffers_.pop_back(); |
846 | 842 |
847 DVLOG(3) << __func__ << ": enqueued frame id=" | 843 DVLOG(3) << __func__ |
848 << job_record->bitstream_buffer.id() << " to device."; | 844 << ": enqueued frame id=" << job_record->bitstream_buffer_id |
| 845 << " to device."; |
849 return true; | 846 return true; |
850 } | 847 } |
851 | 848 |
852 bool V4L2JpegDecodeAccelerator::EnqueueOutputRecord() { | 849 bool V4L2JpegDecodeAccelerator::EnqueueOutputRecord() { |
853 DCHECK(!free_output_buffers_.empty()); | 850 DCHECK(!free_output_buffers_.empty()); |
854 | 851 |
855 // Enqueue an output (VIDEO_CAPTURE) buffer. | 852 // Enqueue an output (VIDEO_CAPTURE) buffer. |
856 const int index = free_output_buffers_.back(); | 853 const int index = free_output_buffers_.back(); |
857 BufferRecord& output_record = output_buffer_map_[index]; | 854 BufferRecord& output_record = output_buffer_map_[index]; |
858 DCHECK(!output_record.at_device); | 855 DCHECK(!output_record.at_device); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
892 device_poll_thread_.Stop(); | 889 device_poll_thread_.Stop(); |
893 | 890 |
894 // Clear the interrupt now, to be sure. | 891 // Clear the interrupt now, to be sure. |
895 if (!device_->ClearDevicePollInterrupt()) | 892 if (!device_->ClearDevicePollInterrupt()) |
896 return false; | 893 return false; |
897 | 894 |
898 return true; | 895 return true; |
899 } | 896 } |
900 | 897 |
901 } // namespace content | 898 } // namespace content |
OLD | NEW |