| 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 |