| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 <dlfcn.h> | 5 #include <dlfcn.h> |
| 6 #include <errno.h> | 6 #include <errno.h> |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <linux/videodev2.h> | 8 #include <linux/videodev2.h> |
| 9 #include <poll.h> | 9 #include <poll.h> |
| 10 #include <sys/eventfd.h> | 10 #include <sys/eventfd.h> |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 output_buffer_queued_count_(0), | 181 output_buffer_queued_count_(0), |
| 182 output_dpb_size_(0), | 182 output_dpb_size_(0), |
| 183 output_planes_count_(0), | 183 output_planes_count_(0), |
| 184 picture_clearing_count_(0), | 184 picture_clearing_count_(0), |
| 185 pictures_assigned_(false, false), | 185 pictures_assigned_(false, false), |
| 186 device_poll_thread_("V4L2DevicePollThread"), | 186 device_poll_thread_("V4L2DevicePollThread"), |
| 187 make_context_current_(make_context_current), | 187 make_context_current_(make_context_current), |
| 188 egl_display_(egl_display), | 188 egl_display_(egl_display), |
| 189 egl_context_(egl_context), | 189 egl_context_(egl_context), |
| 190 video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), | 190 video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), |
| 191 output_format_fourcc_(0), | |
| 192 weak_this_factory_(this) { | 191 weak_this_factory_(this) { |
| 193 weak_this_ = weak_this_factory_.GetWeakPtr(); | 192 weak_this_ = weak_this_factory_.GetWeakPtr(); |
| 194 } | 193 } |
| 195 | 194 |
| 196 V4L2VideoDecodeAccelerator::~V4L2VideoDecodeAccelerator() { | 195 V4L2VideoDecodeAccelerator::~V4L2VideoDecodeAccelerator() { |
| 197 DCHECK(!decoder_thread_.IsRunning()); | 196 DCHECK(!decoder_thread_.IsRunning()); |
| 198 DCHECK(!device_poll_thread_.IsRunning()); | 197 DCHECK(!device_poll_thread_.IsRunning()); |
| 199 | 198 |
| 200 DestroyInputBuffers(); | 199 DestroyInputBuffers(); |
| 201 DestroyOutputBuffers(); | 200 DestroyOutputBuffers(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 221 break; | 220 break; |
| 222 case media::H264PROFILE_MAIN: | 221 case media::H264PROFILE_MAIN: |
| 223 DVLOG(2) << "Initialize(): profile H264PROFILE_MAIN"; | 222 DVLOG(2) << "Initialize(): profile H264PROFILE_MAIN"; |
| 224 break; | 223 break; |
| 225 case media::H264PROFILE_HIGH: | 224 case media::H264PROFILE_HIGH: |
| 226 DVLOG(2) << "Initialize(): profile H264PROFILE_HIGH"; | 225 DVLOG(2) << "Initialize(): profile H264PROFILE_HIGH"; |
| 227 break; | 226 break; |
| 228 case media::VP8PROFILE_ANY: | 227 case media::VP8PROFILE_ANY: |
| 229 DVLOG(2) << "Initialize(): profile VP8PROFILE_ANY"; | 228 DVLOG(2) << "Initialize(): profile VP8PROFILE_ANY"; |
| 230 break; | 229 break; |
| 231 case media::VP9PROFILE_ANY: | |
| 232 DVLOG(2) << "Initialize(): profile VP9PROFILE_ANY"; | |
| 233 break; | |
| 234 default: | 230 default: |
| 235 DLOG(ERROR) << "Initialize(): unsupported profile=" << profile; | 231 DLOG(ERROR) << "Initialize(): unsupported profile=" << profile; |
| 236 return false; | 232 return false; |
| 237 }; | 233 }; |
| 238 video_profile_ = profile; | 234 video_profile_ = profile; |
| 239 | 235 |
| 240 if (egl_display_ == EGL_NO_DISPLAY) { | 236 if (egl_display_ == EGL_NO_DISPLAY) { |
| 241 LOG(ERROR) << "Initialize(): could not get EGLDisplay"; | 237 LOG(ERROR) << "Initialize(): could not get EGLDisplay"; |
| 242 NOTIFY_ERROR(PLATFORM_FAILURE); | 238 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 243 return false; | 239 return false; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 263 V4L2_CAP_VIDEO_OUTPUT_MPLANE | | 259 V4L2_CAP_VIDEO_OUTPUT_MPLANE | |
| 264 V4L2_CAP_STREAMING; | 260 V4L2_CAP_STREAMING; |
| 265 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps); | 261 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps); |
| 266 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { | 262 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { |
| 267 LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP" | 263 LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP" |
| 268 ", caps check failed: 0x" << std::hex << caps.capabilities; | 264 ", caps check failed: 0x" << std::hex << caps.capabilities; |
| 269 NOTIFY_ERROR(PLATFORM_FAILURE); | 265 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 270 return false; | 266 return false; |
| 271 } | 267 } |
| 272 | 268 |
| 273 if (!SetupFormats()) | 269 if (!CreateInputBuffers()) |
| 274 return false; | 270 return false; |
| 275 | 271 |
| 272 // Output format has to be setup before streaming starts. |
| 273 struct v4l2_format format; |
| 274 memset(&format, 0, sizeof(format)); |
| 275 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 276 uint32 output_format_fourcc = device_->PreferredOutputFormat(); |
| 277 if (output_format_fourcc == 0) { |
| 278 // TODO(posciak): We should enumerate available output formats, as well as |
| 279 // take into account formats that the client is ready to accept. |
| 280 return false; |
| 281 } |
| 282 format.fmt.pix_mp.pixelformat = output_format_fourcc; |
| 283 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); |
| 284 |
| 276 // Subscribe to the resolution change event. | 285 // Subscribe to the resolution change event. |
| 277 struct v4l2_event_subscription sub; | 286 struct v4l2_event_subscription sub; |
| 278 memset(&sub, 0, sizeof(sub)); | 287 memset(&sub, 0, sizeof(sub)); |
| 279 sub.type = V4L2_EVENT_RESOLUTION_CHANGE; | 288 sub.type = V4L2_EVENT_RESOLUTION_CHANGE; |
| 280 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_SUBSCRIBE_EVENT, &sub); | 289 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_SUBSCRIBE_EVENT, &sub); |
| 281 | 290 |
| 291 // Initialize format-specific bits. |
| 282 if (video_profile_ >= media::H264PROFILE_MIN && | 292 if (video_profile_ >= media::H264PROFILE_MIN && |
| 283 video_profile_ <= media::H264PROFILE_MAX) { | 293 video_profile_ <= media::H264PROFILE_MAX) { |
| 284 decoder_h264_parser_.reset(new media::H264Parser()); | 294 decoder_h264_parser_.reset(new media::H264Parser()); |
| 285 } | 295 } |
| 286 | 296 |
| 287 if (!CreateInputBuffers()) | |
| 288 return false; | |
| 289 | |
| 290 if (!decoder_thread_.Start()) { | 297 if (!decoder_thread_.Start()) { |
| 291 LOG(ERROR) << "Initialize(): decoder thread failed to start"; | 298 LOG(ERROR) << "Initialize(): decoder thread failed to start"; |
| 292 NOTIFY_ERROR(PLATFORM_FAILURE); | 299 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 293 return false; | 300 return false; |
| 294 } | 301 } |
| 295 | 302 |
| 296 // StartDevicePoll will NOTIFY_ERROR on failure, so IgnoreResult is fine here. | 303 // StartDevicePoll will NOTIFY_ERROR on failure, so IgnoreResult is fine here. |
| 297 decoder_thread_.message_loop()->PostTask( | 304 decoder_thread_.message_loop()->PostTask( |
| 298 FROM_HERE, | 305 FROM_HERE, |
| 299 base::Bind( | 306 base::Bind( |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 349 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); | 356 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); |
| 350 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | 357 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
| 351 DCHECK_EQ(output_record.picture_id, -1); | 358 DCHECK_EQ(output_record.picture_id, -1); |
| 352 DCHECK_EQ(output_record.cleared, false); | 359 DCHECK_EQ(output_record.cleared, false); |
| 353 | 360 |
| 354 EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_, | 361 EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_, |
| 355 egl_context_, | 362 egl_context_, |
| 356 buffers[i].texture_id(), | 363 buffers[i].texture_id(), |
| 357 frame_buffer_size_, | 364 frame_buffer_size_, |
| 358 i, | 365 i, |
| 359 output_format_fourcc_, | |
| 360 output_planes_count_); | 366 output_planes_count_); |
| 361 if (egl_image == EGL_NO_IMAGE_KHR) { | 367 if (egl_image == EGL_NO_IMAGE_KHR) { |
| 362 LOG(ERROR) << "AssignPictureBuffers(): could not create EGLImageKHR"; | 368 LOG(ERROR) << "AssignPictureBuffers(): could not create EGLImageKHR"; |
| 363 // Ownership of EGLImages allocated in previous iterations of this loop | 369 // Ownership of EGLImages allocated in previous iterations of this loop |
| 364 // has been transferred to output_buffer_map_. After we error-out here | 370 // has been transferred to output_buffer_map_. After we error-out here |
| 365 // the destructor will handle their cleanup. | 371 // the destructor will handle their cleanup. |
| 366 NOTIFY_ERROR(PLATFORM_FAILURE); | 372 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 367 return; | 373 return; |
| 368 } | 374 } |
| 369 | 375 |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 675 decoder_partial_frame_pending_ = false; | 681 decoder_partial_frame_pending_ = false; |
| 676 return true; | 682 return true; |
| 677 } | 683 } |
| 678 } | 684 } |
| 679 *endpos = (nalu.data + nalu.size) - data; | 685 *endpos = (nalu.data + nalu.size) - data; |
| 680 } | 686 } |
| 681 NOTREACHED(); | 687 NOTREACHED(); |
| 682 return false; | 688 return false; |
| 683 } else { | 689 } else { |
| 684 DCHECK_GE(video_profile_, media::VP8PROFILE_MIN); | 690 DCHECK_GE(video_profile_, media::VP8PROFILE_MIN); |
| 685 DCHECK_LE(video_profile_, media::VP9PROFILE_MAX); | 691 DCHECK_LE(video_profile_, media::VP8PROFILE_MAX); |
| 686 // For VP8/9, we can just dump the entire buffer. No fragmentation needed, | 692 // For VP8, we can just dump the entire buffer. No fragmentation needed, |
| 687 // and we never return a partial frame. | 693 // and we never return a partial frame. |
| 688 *endpos = size; | 694 *endpos = size; |
| 689 decoder_partial_frame_pending_ = false; | 695 decoder_partial_frame_pending_ = false; |
| 690 return true; | 696 return true; |
| 691 } | 697 } |
| 692 } | 698 } |
| 693 | 699 |
| 694 void V4L2VideoDecodeAccelerator::ScheduleDecodeBufferTaskIfNeeded() { | 700 void V4L2VideoDecodeAccelerator::ScheduleDecodeBufferTaskIfNeeded() { |
| 695 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 701 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 696 | 702 |
| (...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1070 PLOG(ERROR) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF"; | 1076 PLOG(ERROR) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF"; |
| 1071 NOTIFY_ERROR(PLATFORM_FAILURE); | 1077 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1072 return; | 1078 return; |
| 1073 } | 1079 } |
| 1074 OutputRecord& output_record = output_buffer_map_[dqbuf.index]; | 1080 OutputRecord& output_record = output_buffer_map_[dqbuf.index]; |
| 1075 DCHECK(output_record.at_device); | 1081 DCHECK(output_record.at_device); |
| 1076 DCHECK(!output_record.at_client); | 1082 DCHECK(!output_record.at_client); |
| 1077 DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR); | 1083 DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR); |
| 1078 DCHECK_NE(output_record.picture_id, -1); | 1084 DCHECK_NE(output_record.picture_id, -1); |
| 1079 output_record.at_device = false; | 1085 output_record.at_device = false; |
| 1080 if (dqbuf.m.planes[0].bytesused == 0) { | 1086 if (dqbuf.m.planes[0].bytesused + dqbuf.m.planes[1].bytesused == 0) { |
| 1081 // This is an empty output buffer returned as part of a flush. | 1087 // This is an empty output buffer returned as part of a flush. |
| 1082 free_output_buffers_.push(dqbuf.index); | 1088 free_output_buffers_.push(dqbuf.index); |
| 1083 } else { | 1089 } else { |
| 1084 DCHECK_GE(dqbuf.timestamp.tv_sec, 0); | 1090 DCHECK_GE(dqbuf.timestamp.tv_sec, 0); |
| 1085 output_record.at_client = true; | 1091 output_record.at_client = true; |
| 1086 DVLOG(3) << "Dequeue(): returning input_id=" << dqbuf.timestamp.tv_sec | 1092 DVLOG(3) << "Dequeue(): returning input_id=" << dqbuf.timestamp.tv_sec |
| 1087 << " as picture_id=" << output_record.picture_id; | 1093 << " as picture_id=" << output_record.picture_id; |
| 1088 const media::Picture& picture = | 1094 const media::Picture& picture = |
| 1089 media::Picture(output_record.picture_id, | 1095 media::Picture(output_record.picture_id, |
| 1090 dqbuf.timestamp.tv_sec, | 1096 dqbuf.timestamp.tv_sec, |
| (...skipping 534 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1625 // EINVAL means we haven't seen sufficient stream to decode the format. | 1631 // EINVAL means we haven't seen sufficient stream to decode the format. |
| 1626 *again = true; | 1632 *again = true; |
| 1627 return true; | 1633 return true; |
| 1628 } else { | 1634 } else { |
| 1629 PLOG(ERROR) << __func__ << "(): ioctl() failed: VIDIOC_G_FMT"; | 1635 PLOG(ERROR) << __func__ << "(): ioctl() failed: VIDIOC_G_FMT"; |
| 1630 NOTIFY_ERROR(PLATFORM_FAILURE); | 1636 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1631 return false; | 1637 return false; |
| 1632 } | 1638 } |
| 1633 } | 1639 } |
| 1634 | 1640 |
| 1635 // Make sure we are still getting the format we set on initialization. | |
| 1636 if (format->fmt.pix_mp.pixelformat != output_format_fourcc_) { | |
| 1637 LOG(ERROR) << "Unexpected format from G_FMT on output"; | |
| 1638 return false; | |
| 1639 } | |
| 1640 | |
| 1641 return true; | 1641 return true; |
| 1642 } | 1642 } |
| 1643 | 1643 |
| 1644 bool V4L2VideoDecodeAccelerator::CreateBuffersForFormat( | 1644 bool V4L2VideoDecodeAccelerator::CreateBuffersForFormat( |
| 1645 const struct v4l2_format& format) { | 1645 const struct v4l2_format& format) { |
| 1646 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1646 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 1647 output_planes_count_ = format.fmt.pix_mp.num_planes; | 1647 output_planes_count_ = format.fmt.pix_mp.num_planes; |
| 1648 frame_buffer_size_.SetSize( | 1648 frame_buffer_size_.SetSize( |
| 1649 format.fmt.pix_mp.width, format.fmt.pix_mp.height); | 1649 format.fmt.pix_mp.width, format.fmt.pix_mp.height); |
| 1650 DVLOG(3) << "CreateBuffersForFormat(): new resolution: " | 1650 DVLOG(3) << "CreateBuffersForFormat(): new resolution: " |
| 1651 << frame_buffer_size_.ToString(); | 1651 << frame_buffer_size_.ToString(); |
| 1652 | 1652 |
| 1653 if (!CreateOutputBuffers()) | 1653 if (!CreateOutputBuffers()) |
| 1654 return false; | 1654 return false; |
| 1655 | 1655 |
| 1656 return true; | 1656 return true; |
| 1657 } | 1657 } |
| 1658 | 1658 |
| 1659 bool V4L2VideoDecodeAccelerator::CreateInputBuffers() { | 1659 bool V4L2VideoDecodeAccelerator::CreateInputBuffers() { |
| 1660 DVLOG(3) << "CreateInputBuffers()"; | 1660 DVLOG(3) << "CreateInputBuffers()"; |
| 1661 // We always run this as we prepare to initialize. | 1661 // We always run this as we prepare to initialize. |
| 1662 DCHECK_EQ(decoder_state_, kUninitialized); | 1662 DCHECK_EQ(decoder_state_, kUninitialized); |
| 1663 DCHECK(!input_streamon_); | 1663 DCHECK(!input_streamon_); |
| 1664 DCHECK(input_buffer_map_.empty()); | 1664 DCHECK(input_buffer_map_.empty()); |
| 1665 | 1665 |
| 1666 __u32 pixelformat = V4L2Device::VideoCodecProfileToV4L2PixFmt(video_profile_); |
| 1667 if (!pixelformat) { |
| 1668 NOTREACHED(); |
| 1669 return false; |
| 1670 } |
| 1671 |
| 1672 struct v4l2_format format; |
| 1673 memset(&format, 0, sizeof(format)); |
| 1674 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 1675 format.fmt.pix_mp.pixelformat = pixelformat; |
| 1676 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 1677 switches::kIgnoreResolutionLimitsForAcceleratedVideoDecode)) |
| 1678 format.fmt.pix_mp.plane_fmt[0].sizeimage = kInputBufferMaxSizeFor4k; |
| 1679 else |
| 1680 format.fmt.pix_mp.plane_fmt[0].sizeimage = kInputBufferMaxSizeFor1080p; |
| 1681 format.fmt.pix_mp.num_planes = 1; |
| 1682 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); |
| 1683 |
| 1666 struct v4l2_requestbuffers reqbufs; | 1684 struct v4l2_requestbuffers reqbufs; |
| 1667 memset(&reqbufs, 0, sizeof(reqbufs)); | 1685 memset(&reqbufs, 0, sizeof(reqbufs)); |
| 1668 reqbufs.count = kInputBufferCount; | 1686 reqbufs.count = kInputBufferCount; |
| 1669 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 1687 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 1670 reqbufs.memory = V4L2_MEMORY_MMAP; | 1688 reqbufs.memory = V4L2_MEMORY_MMAP; |
| 1671 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); | 1689 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); |
| 1672 input_buffer_map_.resize(reqbufs.count); | 1690 input_buffer_map_.resize(reqbufs.count); |
| 1673 for (size_t i = 0; i < input_buffer_map_.size(); ++i) { | 1691 for (size_t i = 0; i < input_buffer_map_.size(); ++i) { |
| 1674 free_input_buffers_.push_back(i); | 1692 free_input_buffers_.push_back(i); |
| 1675 | 1693 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1693 PLOG(ERROR) << "CreateInputBuffers(): mmap() failed"; | 1711 PLOG(ERROR) << "CreateInputBuffers(): mmap() failed"; |
| 1694 return false; | 1712 return false; |
| 1695 } | 1713 } |
| 1696 input_buffer_map_[i].address = address; | 1714 input_buffer_map_[i].address = address; |
| 1697 input_buffer_map_[i].length = buffer.m.planes[0].length; | 1715 input_buffer_map_[i].length = buffer.m.planes[0].length; |
| 1698 } | 1716 } |
| 1699 | 1717 |
| 1700 return true; | 1718 return true; |
| 1701 } | 1719 } |
| 1702 | 1720 |
| 1703 bool V4L2VideoDecodeAccelerator::SetupFormats() { | |
| 1704 // We always run this as we prepare to initialize. | |
| 1705 DCHECK_EQ(decoder_state_, kUninitialized); | |
| 1706 DCHECK(!input_streamon_); | |
| 1707 DCHECK(!output_streamon_); | |
| 1708 | |
| 1709 __u32 input_format_fourcc = | |
| 1710 V4L2Device::VideoCodecProfileToV4L2PixFmt(video_profile_); | |
| 1711 if (!input_format_fourcc) { | |
| 1712 NOTREACHED(); | |
| 1713 return false; | |
| 1714 } | |
| 1715 | |
| 1716 size_t input_size; | |
| 1717 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 1718 switches::kIgnoreResolutionLimitsForAcceleratedVideoDecode)) | |
| 1719 input_size = kInputBufferMaxSizeFor4k; | |
| 1720 else | |
| 1721 input_size = kInputBufferMaxSizeFor1080p; | |
| 1722 | |
| 1723 struct v4l2_format format; | |
| 1724 memset(&format, 0, sizeof(format)); | |
| 1725 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | |
| 1726 format.fmt.pix_mp.pixelformat = input_format_fourcc; | |
| 1727 format.fmt.pix_mp.plane_fmt[0].sizeimage = input_size; | |
| 1728 format.fmt.pix_mp.num_planes = 1; | |
| 1729 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); | |
| 1730 | |
| 1731 // We have to set up the format for output, because the driver may not allow | |
| 1732 // changing it once we start streaming; whether it can support our chosen | |
| 1733 // output format or not may depend on the input format. | |
| 1734 struct v4l2_fmtdesc fmtdesc; | |
| 1735 memset(&fmtdesc, 0, sizeof(fmtdesc)); | |
| 1736 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | |
| 1737 while (device_->Ioctl(VIDIOC_ENUM_FMT, &fmtdesc) == 0) { | |
| 1738 if (device_->CanCreateEGLImageFrom(fmtdesc.pixelformat)) { | |
| 1739 output_format_fourcc_ = fmtdesc.pixelformat; | |
| 1740 break; | |
| 1741 } | |
| 1742 ++fmtdesc.index; | |
| 1743 } | |
| 1744 | |
| 1745 if (output_format_fourcc_ == 0) { | |
| 1746 LOG(ERROR) << "Could not find a usable output format"; | |
| 1747 return false; | |
| 1748 } | |
| 1749 | |
| 1750 // Just set the fourcc for output; resolution, etc., will come from the | |
| 1751 // driver once it extracts it from the stream. | |
| 1752 memset(&format, 0, sizeof(format)); | |
| 1753 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | |
| 1754 format.fmt.pix_mp.pixelformat = output_format_fourcc_; | |
| 1755 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); | |
| 1756 | |
| 1757 return true; | |
| 1758 } | |
| 1759 | |
| 1760 bool V4L2VideoDecodeAccelerator::CreateOutputBuffers() { | 1721 bool V4L2VideoDecodeAccelerator::CreateOutputBuffers() { |
| 1761 DVLOG(3) << "CreateOutputBuffers()"; | 1722 DVLOG(3) << "CreateOutputBuffers()"; |
| 1762 DCHECK(decoder_state_ == kInitialized || | 1723 DCHECK(decoder_state_ == kInitialized || |
| 1763 decoder_state_ == kChangingResolution); | 1724 decoder_state_ == kChangingResolution); |
| 1764 DCHECK(!output_streamon_); | 1725 DCHECK(!output_streamon_); |
| 1765 DCHECK(output_buffer_map_.empty()); | 1726 DCHECK(output_buffer_map_.empty()); |
| 1766 | 1727 |
| 1767 // Number of output buffers we need. | 1728 // Number of output buffers we need. |
| 1768 struct v4l2_control ctrl; | 1729 struct v4l2_control ctrl; |
| 1769 memset(&ctrl, 0, sizeof(ctrl)); | 1730 memset(&ctrl, 0, sizeof(ctrl)); |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1973 gfx::Size new_size(base::checked_cast<int>(format.fmt.pix_mp.width), | 1934 gfx::Size new_size(base::checked_cast<int>(format.fmt.pix_mp.width), |
| 1974 base::checked_cast<int>(format.fmt.pix_mp.height)); | 1935 base::checked_cast<int>(format.fmt.pix_mp.height)); |
| 1975 if (frame_buffer_size_ != new_size) { | 1936 if (frame_buffer_size_ != new_size) { |
| 1976 DVLOG(3) << "IsResolutionChangeNecessary(): Resolution change detected"; | 1937 DVLOG(3) << "IsResolutionChangeNecessary(): Resolution change detected"; |
| 1977 return true; | 1938 return true; |
| 1978 } | 1939 } |
| 1979 return false; | 1940 return false; |
| 1980 } | 1941 } |
| 1981 | 1942 |
| 1982 } // namespace content | 1943 } // namespace content |
| OLD | NEW |