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