| 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), |
| 191 weak_this_factory_(this) { | 192 weak_this_factory_(this) { |
| 192 weak_this_ = weak_this_factory_.GetWeakPtr(); | 193 weak_this_ = weak_this_factory_.GetWeakPtr(); |
| 193 } | 194 } |
| 194 | 195 |
| 195 V4L2VideoDecodeAccelerator::~V4L2VideoDecodeAccelerator() { | 196 V4L2VideoDecodeAccelerator::~V4L2VideoDecodeAccelerator() { |
| 196 DCHECK(!decoder_thread_.IsRunning()); | 197 DCHECK(!decoder_thread_.IsRunning()); |
| 197 DCHECK(!device_poll_thread_.IsRunning()); | 198 DCHECK(!device_poll_thread_.IsRunning()); |
| 198 | 199 |
| 199 DestroyInputBuffers(); | 200 DestroyInputBuffers(); |
| 200 DestroyOutputBuffers(); | 201 DestroyOutputBuffers(); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 262 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { | 263 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { |
| 263 LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP" | 264 LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP" |
| 264 ", caps check failed: 0x" << std::hex << caps.capabilities; | 265 ", caps check failed: 0x" << std::hex << caps.capabilities; |
| 265 NOTIFY_ERROR(PLATFORM_FAILURE); | 266 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 266 return false; | 267 return false; |
| 267 } | 268 } |
| 268 | 269 |
| 269 if (!CreateInputBuffers()) | 270 if (!CreateInputBuffers()) |
| 270 return false; | 271 return false; |
| 271 | 272 |
| 272 // Output format has to be setup before streaming starts. | 273 if (!SetupOutputFormat()) |
| 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; | 274 return false; |
| 281 } | |
| 282 format.fmt.pix_mp.pixelformat = output_format_fourcc; | |
| 283 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); | |
| 284 | 275 |
| 285 // Subscribe to the resolution change event. | 276 // Subscribe to the resolution change event. |
| 286 struct v4l2_event_subscription sub; | 277 struct v4l2_event_subscription sub; |
| 287 memset(&sub, 0, sizeof(sub)); | 278 memset(&sub, 0, sizeof(sub)); |
| 288 sub.type = V4L2_EVENT_RESOLUTION_CHANGE; | 279 sub.type = V4L2_EVENT_RESOLUTION_CHANGE; |
| 289 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_SUBSCRIBE_EVENT, &sub); | 280 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_SUBSCRIBE_EVENT, &sub); |
| 290 | 281 |
| 291 // Initialize format-specific bits. | |
| 292 if (video_profile_ >= media::H264PROFILE_MIN && | 282 if (video_profile_ >= media::H264PROFILE_MIN && |
| 293 video_profile_ <= media::H264PROFILE_MAX) { | 283 video_profile_ <= media::H264PROFILE_MAX) { |
| 294 decoder_h264_parser_.reset(new media::H264Parser()); | 284 decoder_h264_parser_.reset(new media::H264Parser()); |
| 295 } | 285 } |
| 296 | 286 |
| 297 if (!decoder_thread_.Start()) { | 287 if (!decoder_thread_.Start()) { |
| 298 LOG(ERROR) << "Initialize(): decoder thread failed to start"; | 288 LOG(ERROR) << "Initialize(): decoder thread failed to start"; |
| 299 NOTIFY_ERROR(PLATFORM_FAILURE); | 289 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 300 return false; | 290 return false; |
| 301 } | 291 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); | 346 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); |
| 357 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | 347 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
| 358 DCHECK_EQ(output_record.picture_id, -1); | 348 DCHECK_EQ(output_record.picture_id, -1); |
| 359 DCHECK_EQ(output_record.cleared, false); | 349 DCHECK_EQ(output_record.cleared, false); |
| 360 | 350 |
| 361 EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_, | 351 EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_, |
| 362 egl_context_, | 352 egl_context_, |
| 363 buffers[i].texture_id(), | 353 buffers[i].texture_id(), |
| 364 frame_buffer_size_, | 354 frame_buffer_size_, |
| 365 i, | 355 i, |
| 356 output_format_fourcc_, |
| 366 output_planes_count_); | 357 output_planes_count_); |
| 367 if (egl_image == EGL_NO_IMAGE_KHR) { | 358 if (egl_image == EGL_NO_IMAGE_KHR) { |
| 368 LOG(ERROR) << "AssignPictureBuffers(): could not create EGLImageKHR"; | 359 LOG(ERROR) << "AssignPictureBuffers(): could not create EGLImageKHR"; |
| 369 // Ownership of EGLImages allocated in previous iterations of this loop | 360 // Ownership of EGLImages allocated in previous iterations of this loop |
| 370 // has been transferred to output_buffer_map_. After we error-out here | 361 // has been transferred to output_buffer_map_. After we error-out here |
| 371 // the destructor will handle their cleanup. | 362 // the destructor will handle their cleanup. |
| 372 NOTIFY_ERROR(PLATFORM_FAILURE); | 363 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 373 return; | 364 return; |
| 374 } | 365 } |
| 375 | 366 |
| (...skipping 700 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1076 PLOG(ERROR) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF"; | 1067 PLOG(ERROR) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF"; |
| 1077 NOTIFY_ERROR(PLATFORM_FAILURE); | 1068 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1078 return; | 1069 return; |
| 1079 } | 1070 } |
| 1080 OutputRecord& output_record = output_buffer_map_[dqbuf.index]; | 1071 OutputRecord& output_record = output_buffer_map_[dqbuf.index]; |
| 1081 DCHECK(output_record.at_device); | 1072 DCHECK(output_record.at_device); |
| 1082 DCHECK(!output_record.at_client); | 1073 DCHECK(!output_record.at_client); |
| 1083 DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR); | 1074 DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR); |
| 1084 DCHECK_NE(output_record.picture_id, -1); | 1075 DCHECK_NE(output_record.picture_id, -1); |
| 1085 output_record.at_device = false; | 1076 output_record.at_device = false; |
| 1086 if (dqbuf.m.planes[0].bytesused + dqbuf.m.planes[1].bytesused == 0) { | 1077 if (dqbuf.m.planes[0].bytesused == 0) { |
| 1087 // This is an empty output buffer returned as part of a flush. | 1078 // This is an empty output buffer returned as part of a flush. |
| 1088 free_output_buffers_.push(dqbuf.index); | 1079 free_output_buffers_.push(dqbuf.index); |
| 1089 } else { | 1080 } else { |
| 1090 DCHECK_GE(dqbuf.timestamp.tv_sec, 0); | 1081 DCHECK_GE(dqbuf.timestamp.tv_sec, 0); |
| 1091 output_record.at_client = true; | 1082 output_record.at_client = true; |
| 1092 DVLOG(3) << "Dequeue(): returning input_id=" << dqbuf.timestamp.tv_sec | 1083 DVLOG(3) << "Dequeue(): returning input_id=" << dqbuf.timestamp.tv_sec |
| 1093 << " as picture_id=" << output_record.picture_id; | 1084 << " as picture_id=" << output_record.picture_id; |
| 1094 const media::Picture& picture = | 1085 const media::Picture& picture = |
| 1095 media::Picture(output_record.picture_id, | 1086 media::Picture(output_record.picture_id, |
| 1096 dqbuf.timestamp.tv_sec, | 1087 dqbuf.timestamp.tv_sec, |
| (...skipping 614 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1711 PLOG(ERROR) << "CreateInputBuffers(): mmap() failed"; | 1702 PLOG(ERROR) << "CreateInputBuffers(): mmap() failed"; |
| 1712 return false; | 1703 return false; |
| 1713 } | 1704 } |
| 1714 input_buffer_map_[i].address = address; | 1705 input_buffer_map_[i].address = address; |
| 1715 input_buffer_map_[i].length = buffer.m.planes[0].length; | 1706 input_buffer_map_[i].length = buffer.m.planes[0].length; |
| 1716 } | 1707 } |
| 1717 | 1708 |
| 1718 return true; | 1709 return true; |
| 1719 } | 1710 } |
| 1720 | 1711 |
| 1712 bool V4L2VideoDecodeAccelerator::SetupOutputFormat() { |
| 1713 // We have to set up the format for output beforehand, because the driver may |
| 1714 // not allow changing it once we start streaming; whether it can support our |
| 1715 // chosen output format or not may depend on the input format. |
| 1716 struct v4l2_fmtdesc fmtdesc; |
| 1717 memset(&fmtdesc, 0, sizeof(fmtdesc)); |
| 1718 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 1719 while (device_->Ioctl(VIDIOC_ENUM_FMT, &fmtdesc) == 0) { |
| 1720 if (device_->CanCreateEGLImageFrom(fmtdesc.pixelformat)) { |
| 1721 output_format_fourcc_ = fmtdesc.pixelformat; |
| 1722 break; |
| 1723 } |
| 1724 ++fmtdesc.index; |
| 1725 } |
| 1726 |
| 1727 if (output_format_fourcc_ == 0) { |
| 1728 LOG(ERROR) << "Could not find a usable output format"; |
| 1729 return false; |
| 1730 } |
| 1731 |
| 1732 // Just set the fourcc for output; resolution, etc., will come from the |
| 1733 // driver once it extracts it from the stream. |
| 1734 struct v4l2_format format; |
| 1735 memset(&format, 0, sizeof(format)); |
| 1736 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 1737 format.fmt.pix_mp.pixelformat = output_format_fourcc_; |
| 1738 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); |
| 1739 |
| 1740 return true; |
| 1741 } |
| 1742 |
| 1721 bool V4L2VideoDecodeAccelerator::CreateOutputBuffers() { | 1743 bool V4L2VideoDecodeAccelerator::CreateOutputBuffers() { |
| 1722 DVLOG(3) << "CreateOutputBuffers()"; | 1744 DVLOG(3) << "CreateOutputBuffers()"; |
| 1723 DCHECK(decoder_state_ == kInitialized || | 1745 DCHECK(decoder_state_ == kInitialized || |
| 1724 decoder_state_ == kChangingResolution); | 1746 decoder_state_ == kChangingResolution); |
| 1725 DCHECK(!output_streamon_); | 1747 DCHECK(!output_streamon_); |
| 1726 DCHECK(output_buffer_map_.empty()); | 1748 DCHECK(output_buffer_map_.empty()); |
| 1727 | 1749 |
| 1728 // Number of output buffers we need. | 1750 // Number of output buffers we need. |
| 1729 struct v4l2_control ctrl; | 1751 struct v4l2_control ctrl; |
| 1730 memset(&ctrl, 0, sizeof(ctrl)); | 1752 memset(&ctrl, 0, sizeof(ctrl)); |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1934 gfx::Size new_size(base::checked_cast<int>(format.fmt.pix_mp.width), | 1956 gfx::Size new_size(base::checked_cast<int>(format.fmt.pix_mp.width), |
| 1935 base::checked_cast<int>(format.fmt.pix_mp.height)); | 1957 base::checked_cast<int>(format.fmt.pix_mp.height)); |
| 1936 if (frame_buffer_size_ != new_size) { | 1958 if (frame_buffer_size_ != new_size) { |
| 1937 DVLOG(3) << "IsResolutionChangeNecessary(): Resolution change detected"; | 1959 DVLOG(3) << "IsResolutionChangeNecessary(): Resolution change detected"; |
| 1938 return true; | 1960 return true; |
| 1939 } | 1961 } |
| 1940 return false; | 1962 return false; |
| 1941 } | 1963 } |
| 1942 | 1964 |
| 1943 } // namespace content | 1965 } // namespace content |
| OLD | NEW |