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