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