Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(43)

Side by Side Diff: content/common/gpu/media/v4l2_video_decode_accelerator.cc

Issue 839523002: V4L2VDA: Generalize EGLImage import and query driver for output formats. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « content/common/gpu/media/v4l2_video_decode_accelerator.h ('k') | content/common/gpu/media/v4l2_video_device.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698