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 "media/gpu/v4l2_jpeg_decode_accelerator.h" | 5 #include "media/gpu/v4l2_jpeg_decode_accelerator.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <linux/videodev2.h> | 8 #include <linux/videodev2.h> |
9 #include <string.h> | 9 #include <string.h> |
10 #include <sys/mman.h> | 10 #include <sys/mman.h> |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
106 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, | 106 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, |
107 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, | 107 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, |
108 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA}; | 108 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA}; |
109 | 109 |
110 V4L2JpegDecodeAccelerator::BufferRecord::BufferRecord() | 110 V4L2JpegDecodeAccelerator::BufferRecord::BufferRecord() |
111 : address(nullptr), length(0), at_device(false) {} | 111 : address(nullptr), length(0), at_device(false) {} |
112 | 112 |
113 V4L2JpegDecodeAccelerator::BufferRecord::~BufferRecord() {} | 113 V4L2JpegDecodeAccelerator::BufferRecord::~BufferRecord() {} |
114 | 114 |
115 V4L2JpegDecodeAccelerator::JobRecord::JobRecord( | 115 V4L2JpegDecodeAccelerator::JobRecord::JobRecord( |
116 const media::BitstreamBuffer& bitstream_buffer, | 116 const BitstreamBuffer& bitstream_buffer, |
117 scoped_refptr<media::VideoFrame> video_frame) | 117 scoped_refptr<VideoFrame> video_frame) |
118 : bitstream_buffer_id(bitstream_buffer.id()), | 118 : bitstream_buffer_id(bitstream_buffer.id()), |
119 shm(bitstream_buffer, true), | 119 shm(bitstream_buffer, true), |
120 out_frame(video_frame) {} | 120 out_frame(video_frame) {} |
121 | 121 |
122 V4L2JpegDecodeAccelerator::JobRecord::~JobRecord() {} | 122 V4L2JpegDecodeAccelerator::JobRecord::~JobRecord() {} |
123 | 123 |
124 V4L2JpegDecodeAccelerator::V4L2JpegDecodeAccelerator( | 124 V4L2JpegDecodeAccelerator::V4L2JpegDecodeAccelerator( |
125 const scoped_refptr<V4L2Device>& device, | 125 const scoped_refptr<V4L2Device>& device, |
126 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) | 126 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) |
127 : output_buffer_pixelformat_(0), | 127 : output_buffer_pixelformat_(0), |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
219 | 219 |
220 decoder_task_runner_->PostTask( | 220 decoder_task_runner_->PostTask( |
221 FROM_HERE, base::Bind(&V4L2JpegDecodeAccelerator::StartDevicePoll, | 221 FROM_HERE, base::Bind(&V4L2JpegDecodeAccelerator::StartDevicePoll, |
222 base::Unretained(this))); | 222 base::Unretained(this))); |
223 | 223 |
224 DVLOG(1) << "V4L2JpegDecodeAccelerator initialized."; | 224 DVLOG(1) << "V4L2JpegDecodeAccelerator initialized."; |
225 return true; | 225 return true; |
226 } | 226 } |
227 | 227 |
228 void V4L2JpegDecodeAccelerator::Decode( | 228 void V4L2JpegDecodeAccelerator::Decode( |
229 const media::BitstreamBuffer& bitstream_buffer, | 229 const BitstreamBuffer& bitstream_buffer, |
230 const scoped_refptr<media::VideoFrame>& video_frame) { | 230 const scoped_refptr<VideoFrame>& video_frame) { |
231 DVLOG(1) << "Decode(): input_id=" << bitstream_buffer.id() | 231 DVLOG(1) << "Decode(): input_id=" << bitstream_buffer.id() |
232 << ", size=" << bitstream_buffer.size(); | 232 << ", size=" << bitstream_buffer.size(); |
233 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 233 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
234 | 234 |
235 if (bitstream_buffer.id() < 0) { | 235 if (bitstream_buffer.id() < 0) { |
236 LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id(); | 236 LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id(); |
237 if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle())) | 237 if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle())) |
238 base::SharedMemory::CloseHandle(bitstream_buffer.handle()); | 238 base::SharedMemory::CloseHandle(bitstream_buffer.handle()); |
239 PostNotifyError(bitstream_buffer.id(), INVALID_ARGUMENT); | 239 PostNotifyError(bitstream_buffer.id(), INVALID_ARGUMENT); |
240 return; | 240 return; |
241 } | 241 } |
242 | 242 |
243 if (video_frame->format() != media::PIXEL_FORMAT_I420) { | 243 if (video_frame->format() != PIXEL_FORMAT_I420) { |
244 PostNotifyError(bitstream_buffer.id(), UNSUPPORTED_JPEG); | 244 PostNotifyError(bitstream_buffer.id(), UNSUPPORTED_JPEG); |
245 return; | 245 return; |
246 } | 246 } |
247 | 247 |
248 std::unique_ptr<JobRecord> job_record( | 248 std::unique_ptr<JobRecord> job_record( |
249 new JobRecord(bitstream_buffer, video_frame)); | 249 new JobRecord(bitstream_buffer, video_frame)); |
250 | 250 |
251 decoder_task_runner_->PostTask( | 251 decoder_task_runner_->PostTask( |
252 FROM_HERE, base::Bind(&V4L2JpegDecodeAccelerator::DecodeTask, | 252 FROM_HERE, base::Bind(&V4L2JpegDecodeAccelerator::DecodeTask, |
253 base::Unretained(this), base::Passed(&job_record))); | 253 base::Unretained(this), base::Passed(&job_record))); |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
381 return true; | 381 return true; |
382 } | 382 } |
383 | 383 |
384 bool V4L2JpegDecodeAccelerator::CreateOutputBuffers() { | 384 bool V4L2JpegDecodeAccelerator::CreateOutputBuffers() { |
385 DVLOG(3) << __func__; | 385 DVLOG(3) << __func__; |
386 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); | 386 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); |
387 DCHECK(!output_streamon_); | 387 DCHECK(!output_streamon_); |
388 DCHECK(!running_jobs_.empty()); | 388 DCHECK(!running_jobs_.empty()); |
389 linked_ptr<JobRecord> job_record = running_jobs_.front(); | 389 linked_ptr<JobRecord> job_record = running_jobs_.front(); |
390 | 390 |
391 size_t frame_size = media::VideoFrame::AllocationSize( | 391 size_t frame_size = VideoFrame::AllocationSize( |
392 media::PIXEL_FORMAT_I420, job_record->out_frame->coded_size()); | 392 PIXEL_FORMAT_I420, job_record->out_frame->coded_size()); |
393 struct v4l2_format format; | 393 struct v4l2_format format; |
394 memset(&format, 0, sizeof(format)); | 394 memset(&format, 0, sizeof(format)); |
395 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 395 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
396 format.fmt.pix.width = job_record->out_frame->coded_size().width(); | 396 format.fmt.pix.width = job_record->out_frame->coded_size().width(); |
397 format.fmt.pix.height = job_record->out_frame->coded_size().height(); | 397 format.fmt.pix.height = job_record->out_frame->coded_size().height(); |
398 format.fmt.pix.sizeimage = frame_size; | 398 format.fmt.pix.sizeimage = frame_size; |
399 format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; | 399 format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; |
400 format.fmt.pix.field = V4L2_FIELD_ANY; | 400 format.fmt.pix.field = V4L2_FIELD_ANY; |
401 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); | 401 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); |
402 output_buffer_pixelformat_ = format.fmt.pix.pixelformat; | 402 output_buffer_pixelformat_ = format.fmt.pix.pixelformat; |
403 output_buffer_coded_size_.SetSize(format.fmt.pix.width, | 403 output_buffer_coded_size_.SetSize(format.fmt.pix.width, |
404 format.fmt.pix.height); | 404 format.fmt.pix.height); |
405 | 405 |
406 struct v4l2_requestbuffers reqbufs; | 406 struct v4l2_requestbuffers reqbufs; |
407 memset(&reqbufs, 0, sizeof(reqbufs)); | 407 memset(&reqbufs, 0, sizeof(reqbufs)); |
408 reqbufs.count = kBufferCount; | 408 reqbufs.count = kBufferCount; |
409 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 409 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
410 reqbufs.memory = V4L2_MEMORY_MMAP; | 410 reqbufs.memory = V4L2_MEMORY_MMAP; |
411 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); | 411 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); |
412 | 412 |
413 DCHECK(output_buffer_map_.empty()); | 413 DCHECK(output_buffer_map_.empty()); |
414 output_buffer_map_.resize(reqbufs.count); | 414 output_buffer_map_.resize(reqbufs.count); |
415 | 415 |
416 media::VideoPixelFormat output_format = | 416 VideoPixelFormat output_format = |
417 V4L2Device::V4L2PixFmtToVideoPixelFormat(output_buffer_pixelformat_); | 417 V4L2Device::V4L2PixFmtToVideoPixelFormat(output_buffer_pixelformat_); |
418 | 418 |
419 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { | 419 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
420 free_output_buffers_.push_back(i); | 420 free_output_buffers_.push_back(i); |
421 | 421 |
422 struct v4l2_buffer buffer; | 422 struct v4l2_buffer buffer; |
423 memset(&buffer, 0, sizeof(buffer)); | 423 memset(&buffer, 0, sizeof(buffer)); |
424 buffer.index = i; | 424 buffer.index = i; |
425 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 425 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
426 buffer.memory = V4L2_MEMORY_MMAP; | 426 buffer.memory = V4L2_MEMORY_MMAP; |
427 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYBUF, &buffer); | 427 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYBUF, &buffer); |
428 | 428 |
429 DCHECK_GE(buffer.length, | 429 DCHECK_GE(buffer.length, |
430 media::VideoFrame::AllocationSize( | 430 VideoFrame::AllocationSize( |
431 output_format, | 431 output_format, |
432 gfx::Size(format.fmt.pix.width, format.fmt.pix.height))); | 432 gfx::Size(format.fmt.pix.width, format.fmt.pix.height))); |
433 | 433 |
434 void* address = device_->Mmap(NULL, buffer.length, PROT_READ | PROT_WRITE, | 434 void* address = device_->Mmap(NULL, buffer.length, PROT_READ | PROT_WRITE, |
435 MAP_SHARED, buffer.m.offset); | 435 MAP_SHARED, buffer.m.offset); |
436 if (address == MAP_FAILED) { | 436 if (address == MAP_FAILED) { |
437 PLOG(ERROR) << __func__ << ": mmap() failed"; | 437 PLOG(ERROR) << __func__ << ": mmap() failed"; |
438 PostNotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE); | 438 PostNotifyError(kInvalidBitstreamBufferId, PLATFORM_FAILURE); |
439 return false; | 439 return false; |
440 } | 440 } |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
609 if (!output_streamon_ && OutputBufferQueuedCount()) { | 609 if (!output_streamon_ && OutputBufferQueuedCount()) { |
610 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 610 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
611 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON, &type); | 611 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON, &type); |
612 output_streamon_ = true; | 612 output_streamon_ = true; |
613 } | 613 } |
614 } | 614 } |
615 | 615 |
616 static bool CopyOutputImage(const uint32_t src_pixelformat, | 616 static bool CopyOutputImage(const uint32_t src_pixelformat, |
617 const void* src_addr, | 617 const void* src_addr, |
618 const gfx::Size& src_coded_size, | 618 const gfx::Size& src_coded_size, |
619 const scoped_refptr<media::VideoFrame>& dst_frame) { | 619 const scoped_refptr<VideoFrame>& dst_frame) { |
620 media::VideoPixelFormat format = | 620 VideoPixelFormat format = |
621 V4L2Device::V4L2PixFmtToVideoPixelFormat(src_pixelformat); | 621 V4L2Device::V4L2PixFmtToVideoPixelFormat(src_pixelformat); |
622 size_t src_size = media::VideoFrame::AllocationSize(format, src_coded_size); | 622 size_t src_size = VideoFrame::AllocationSize(format, src_coded_size); |
623 uint8_t* dst_y = dst_frame->data(media::VideoFrame::kYPlane); | 623 uint8_t* dst_y = dst_frame->data(VideoFrame::kYPlane); |
624 uint8_t* dst_u = dst_frame->data(media::VideoFrame::kUPlane); | 624 uint8_t* dst_u = dst_frame->data(VideoFrame::kUPlane); |
625 uint8_t* dst_v = dst_frame->data(media::VideoFrame::kVPlane); | 625 uint8_t* dst_v = dst_frame->data(VideoFrame::kVPlane); |
626 size_t dst_y_stride = dst_frame->stride(media::VideoFrame::kYPlane); | 626 size_t dst_y_stride = dst_frame->stride(VideoFrame::kYPlane); |
627 size_t dst_u_stride = dst_frame->stride(media::VideoFrame::kUPlane); | 627 size_t dst_u_stride = dst_frame->stride(VideoFrame::kUPlane); |
628 size_t dst_v_stride = dst_frame->stride(media::VideoFrame::kVPlane); | 628 size_t dst_v_stride = dst_frame->stride(VideoFrame::kVPlane); |
629 | 629 |
630 // If the source format is I420, ConvertToI420 will simply copy the frame. | 630 // If the source format is I420, ConvertToI420 will simply copy the frame. |
631 if (libyuv::ConvertToI420(static_cast<uint8_t*>(const_cast<void*>(src_addr)), | 631 if (libyuv::ConvertToI420(static_cast<uint8_t*>(const_cast<void*>(src_addr)), |
632 src_size, | 632 src_size, |
633 dst_y, dst_y_stride, | 633 dst_y, dst_y_stride, |
634 dst_u, dst_u_stride, | 634 dst_u, dst_u_stride, |
635 dst_v, dst_v_stride, | 635 dst_v, dst_v_stride, |
636 0, 0, | 636 0, 0, |
637 src_coded_size.width(), | 637 src_coded_size.width(), |
638 src_coded_size.height(), | 638 src_coded_size.height(), |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
739 DCHECK(input_ptr); | 739 DCHECK(input_ptr); |
740 DCHECK(output_ptr); | 740 DCHECK(output_ptr); |
741 DCHECK_LE((input_size + sizeof(kDefaultDhtSeg)), output_size); | 741 DCHECK_LE((input_size + sizeof(kDefaultDhtSeg)), output_size); |
742 | 742 |
743 base::BigEndianReader reader(static_cast<const char*>(input_ptr), input_size); | 743 base::BigEndianReader reader(static_cast<const char*>(input_ptr), input_size); |
744 bool has_marker_dht = false; | 744 bool has_marker_dht = false; |
745 bool has_marker_sos = false; | 745 bool has_marker_sos = false; |
746 uint8_t marker1, marker2; | 746 uint8_t marker1, marker2; |
747 READ_U8_OR_RETURN_FALSE(reader, &marker1); | 747 READ_U8_OR_RETURN_FALSE(reader, &marker1); |
748 READ_U8_OR_RETURN_FALSE(reader, &marker2); | 748 READ_U8_OR_RETURN_FALSE(reader, &marker2); |
749 if (marker1 != media::JPEG_MARKER_PREFIX || marker2 != media::JPEG_SOI) { | 749 if (marker1 != JPEG_MARKER_PREFIX || marker2 != JPEG_SOI) { |
750 DLOG(ERROR) << __func__ << ": The input is not a Jpeg"; | 750 DLOG(ERROR) << __func__ << ": The input is not a Jpeg"; |
751 return false; | 751 return false; |
752 } | 752 } |
753 | 753 |
754 // copy SOI marker (0xFF, 0xD8) | 754 // copy SOI marker (0xFF, 0xD8) |
755 memcpy(output_ptr, input_ptr, 2); | 755 memcpy(output_ptr, input_ptr, 2); |
756 size_t current_offset = 2; | 756 size_t current_offset = 2; |
757 | 757 |
758 while (!has_marker_sos && !has_marker_dht) { | 758 while (!has_marker_sos && !has_marker_dht) { |
759 const char* start_addr = reader.ptr(); | 759 const char* start_addr = reader.ptr(); |
760 READ_U8_OR_RETURN_FALSE(reader, &marker1); | 760 READ_U8_OR_RETURN_FALSE(reader, &marker1); |
761 if (marker1 != media::JPEG_MARKER_PREFIX) { | 761 if (marker1 != JPEG_MARKER_PREFIX) { |
762 DLOG(ERROR) << __func__ << ": marker1 != 0xFF"; | 762 DLOG(ERROR) << __func__ << ": marker1 != 0xFF"; |
763 return false; | 763 return false; |
764 } | 764 } |
765 do { | 765 do { |
766 READ_U8_OR_RETURN_FALSE(reader, &marker2); | 766 READ_U8_OR_RETURN_FALSE(reader, &marker2); |
767 } while (marker2 == media::JPEG_MARKER_PREFIX); // skip fill bytes | 767 } while (marker2 == JPEG_MARKER_PREFIX); // skip fill bytes |
768 | 768 |
769 uint16_t size; | 769 uint16_t size; |
770 READ_U16_OR_RETURN_FALSE(reader, &size); | 770 READ_U16_OR_RETURN_FALSE(reader, &size); |
771 // The size includes the size field itself. | 771 // The size includes the size field itself. |
772 if (size < sizeof(size)) { | 772 if (size < sizeof(size)) { |
773 DLOG(ERROR) << __func__ << ": Ill-formed JPEG. Segment size (" << size | 773 DLOG(ERROR) << __func__ << ": Ill-formed JPEG. Segment size (" << size |
774 << ") is smaller than size field (" << sizeof(size) << ")"; | 774 << ") is smaller than size field (" << sizeof(size) << ")"; |
775 return false; | 775 return false; |
776 } | 776 } |
777 size -= sizeof(size); | 777 size -= sizeof(size); |
778 | 778 |
779 switch (marker2) { | 779 switch (marker2) { |
780 case media::JPEG_DHT: { | 780 case JPEG_DHT: { |
781 has_marker_dht = true; | 781 has_marker_dht = true; |
782 break; | 782 break; |
783 } | 783 } |
784 case media::JPEG_SOS: { | 784 case JPEG_SOS: { |
785 if (!has_marker_dht) { | 785 if (!has_marker_dht) { |
786 memcpy(static_cast<uint8_t*>(output_ptr) + current_offset, | 786 memcpy(static_cast<uint8_t*>(output_ptr) + current_offset, |
787 kDefaultDhtSeg, sizeof(kDefaultDhtSeg)); | 787 kDefaultDhtSeg, sizeof(kDefaultDhtSeg)); |
788 current_offset += sizeof(kDefaultDhtSeg); | 788 current_offset += sizeof(kDefaultDhtSeg); |
789 } | 789 } |
790 has_marker_sos = true; | 790 has_marker_sos = true; |
791 break; | 791 break; |
792 } | 792 } |
793 default: | 793 default: |
794 break; | 794 break; |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
890 device_poll_thread_.Stop(); | 890 device_poll_thread_.Stop(); |
891 | 891 |
892 // Clear the interrupt now, to be sure. | 892 // Clear the interrupt now, to be sure. |
893 if (!device_->ClearDevicePollInterrupt()) | 893 if (!device_->ClearDevicePollInterrupt()) |
894 return false; | 894 return false; |
895 | 895 |
896 return true; | 896 return true; |
897 } | 897 } |
898 | 898 |
899 } // namespace media | 899 } // namespace media |
OLD | NEW |