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