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

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

Issue 833063003: Add accelerated video decoder interface, VP8 and H.264 implementations and hook up to V4L2SVDA. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed all comments. 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>
11 #include <sys/ioctl.h> 11 #include <sys/ioctl.h>
12 #include <sys/mman.h> 12 #include <sys/mman.h>
13 13
14 #include "base/bind.h" 14 #include "base/bind.h"
15 #include "base/command_line.h" 15 #include "base/command_line.h"
16 #include "base/debug/trace_event.h" 16 #include "base/debug/trace_event.h"
17 #include "base/memory/shared_memory.h" 17 #include "base/memory/shared_memory.h"
18 #include "base/message_loop/message_loop.h" 18 #include "base/message_loop/message_loop.h"
19 #include "base/message_loop/message_loop_proxy.h" 19 #include "base/message_loop/message_loop_proxy.h"
20 #include "base/numerics/safe_conversions.h" 20 #include "base/numerics/safe_conversions.h"
21 #include "content/common/gpu/media/v4l2_video_decode_accelerator.h" 21 #include "content/common/gpu/media/v4l2_video_decode_accelerator.h"
22 #include "media/base/media_switches.h" 22 #include "media/base/media_switches.h"
23 #include "media/filters/h264_parser.h" 23 #include "media/filters/h264_parser.h"
24 #include "ui/gl/scoped_binders.h" 24 #include "ui/gl/scoped_binders.h"
25 25
26 #define NOTIFY_ERROR(x) \ 26 #define NOTIFY_ERROR(x) \
27 do { \ 27 do { \
28 SetDecoderState(kError); \ 28 LOG(ERROR) << "Setting error state:" << x; \
29 LOG(ERROR) << "calling NotifyError(): " << x; \ 29 SetErrorState(x); \
30 NotifyError(x); \
31 } while (0) 30 } while (0)
32 31
33 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value) \ 32 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value) \
34 do { \ 33 do { \
35 if (device_->Ioctl(type, arg) != 0) { \ 34 if (device_->Ioctl(type, arg) != 0) { \
36 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \ 35 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
37 NOTIFY_ERROR(PLATFORM_FAILURE); \ 36 NOTIFY_ERROR(PLATFORM_FAILURE); \
38 return value; \ 37 return value; \
39 } \ 38 } \
40 } while (0) 39 } while (0)
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 const media::Picture& picture) 151 const media::Picture& picture)
153 : cleared(cleared), picture(picture) {} 152 : cleared(cleared), picture(picture) {}
154 153
155 V4L2VideoDecodeAccelerator::PictureRecord::~PictureRecord() {} 154 V4L2VideoDecodeAccelerator::PictureRecord::~PictureRecord() {}
156 155
157 V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator( 156 V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator(
158 EGLDisplay egl_display, 157 EGLDisplay egl_display,
159 EGLContext egl_context, 158 EGLContext egl_context,
160 const base::WeakPtr<Client>& io_client, 159 const base::WeakPtr<Client>& io_client,
161 const base::Callback<bool(void)>& make_context_current, 160 const base::Callback<bool(void)>& make_context_current,
162 scoped_ptr<V4L2Device> device, 161 scoped_refptr<V4L2Device> device,
scherkus (not reviewing) 2015/01/13 01:25:00 const ref
Pawel Osciak 2015/01/13 11:33:35 Done.
163 const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy) 162 const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy)
164 : child_message_loop_proxy_(base::MessageLoopProxy::current()), 163 : child_message_loop_proxy_(base::MessageLoopProxy::current()),
165 io_message_loop_proxy_(io_message_loop_proxy), 164 io_message_loop_proxy_(io_message_loop_proxy),
166 io_client_(io_client), 165 io_client_(io_client),
167 decoder_thread_("V4L2DecoderThread"), 166 decoder_thread_("V4L2DecoderThread"),
168 decoder_state_(kUninitialized), 167 decoder_state_(kUninitialized),
169 device_(device.Pass()), 168 device_(device),
170 decoder_delay_bitstream_buffer_id_(-1), 169 decoder_delay_bitstream_buffer_id_(-1),
171 decoder_current_input_buffer_(-1), 170 decoder_current_input_buffer_(-1),
172 decoder_decode_buffer_tasks_scheduled_(0), 171 decoder_decode_buffer_tasks_scheduled_(0),
173 decoder_frames_at_client_(0), 172 decoder_frames_at_client_(0),
174 decoder_flushing_(false), 173 decoder_flushing_(false),
175 resolution_change_pending_(false), 174 resolution_change_pending_(false),
176 resolution_change_reset_pending_(false), 175 resolution_change_reset_pending_(false),
177 decoder_partial_frame_pending_(false), 176 decoder_partial_frame_pending_(false),
178 input_streamon_(false), 177 input_streamon_(false),
179 input_buffer_queued_count_(0), 178 input_buffer_queued_count_(0),
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 DVLOG(2) << "Initialize(): profile VP9PROFILE_ANY"; 231 DVLOG(2) << "Initialize(): profile VP9PROFILE_ANY";
233 break; 232 break;
234 default: 233 default:
235 DLOG(ERROR) << "Initialize(): unsupported profile=" << profile; 234 DLOG(ERROR) << "Initialize(): unsupported profile=" << profile;
236 return false; 235 return false;
237 }; 236 };
238 video_profile_ = profile; 237 video_profile_ = profile;
239 238
240 if (egl_display_ == EGL_NO_DISPLAY) { 239 if (egl_display_ == EGL_NO_DISPLAY) {
241 LOG(ERROR) << "Initialize(): could not get EGLDisplay"; 240 LOG(ERROR) << "Initialize(): could not get EGLDisplay";
242 NOTIFY_ERROR(PLATFORM_FAILURE);
243 return false; 241 return false;
244 } 242 }
245 243
246 // We need the context to be initialized to query extensions. 244 // We need the context to be initialized to query extensions.
247 if (!make_context_current_.Run()) { 245 if (!make_context_current_.Run()) {
248 LOG(ERROR) << "Initialize(): could not make context current"; 246 LOG(ERROR) << "Initialize(): could not make context current";
249 NOTIFY_ERROR(PLATFORM_FAILURE);
250 return false; 247 return false;
251 } 248 }
252 249
253 if (!gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync) { 250 if (!gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync) {
254 LOG(ERROR) << "Initialize(): context does not have EGL_KHR_fence_sync"; 251 LOG(ERROR) << "Initialize(): context does not have EGL_KHR_fence_sync";
255 NOTIFY_ERROR(PLATFORM_FAILURE);
256 return false; 252 return false;
257 } 253 }
258 254
259 // Capabilities check. 255 // Capabilities check.
260 struct v4l2_capability caps; 256 struct v4l2_capability caps;
261 const __u32 kCapsRequired = 257 const __u32 kCapsRequired =
262 V4L2_CAP_VIDEO_CAPTURE_MPLANE | 258 V4L2_CAP_VIDEO_CAPTURE_MPLANE |
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);
270 return false; 265 return false;
271 } 266 }
272 267
273 if (!SetupFormats()) 268 if (!SetupFormats())
274 return false; 269 return false;
275 270
276 // Subscribe to the resolution change event. 271 // Subscribe to the resolution change event.
277 struct v4l2_event_subscription sub; 272 struct v4l2_event_subscription sub;
278 memset(&sub, 0, sizeof(sub)); 273 memset(&sub, 0, sizeof(sub));
279 sub.type = V4L2_EVENT_RESOLUTION_CHANGE; 274 sub.type = V4L2_EVENT_RESOLUTION_CHANGE;
280 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_SUBSCRIBE_EVENT, &sub); 275 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_SUBSCRIBE_EVENT, &sub);
281 276
282 if (video_profile_ >= media::H264PROFILE_MIN && 277 if (video_profile_ >= media::H264PROFILE_MIN &&
283 video_profile_ <= media::H264PROFILE_MAX) { 278 video_profile_ <= media::H264PROFILE_MAX) {
284 decoder_h264_parser_.reset(new media::H264Parser()); 279 decoder_h264_parser_.reset(new media::H264Parser());
285 } 280 }
286 281
287 if (!CreateInputBuffers()) 282 if (!CreateInputBuffers())
288 return false; 283 return false;
289 284
290 if (!decoder_thread_.Start()) { 285 if (!decoder_thread_.Start()) {
291 LOG(ERROR) << "Initialize(): decoder thread failed to start"; 286 LOG(ERROR) << "Initialize(): decoder thread failed to start";
292 NOTIFY_ERROR(PLATFORM_FAILURE);
293 return false; 287 return false;
294 } 288 }
295 289
290 decoder_state_ = kInitialized;
291
296 // StartDevicePoll will NOTIFY_ERROR on failure, so IgnoreResult is fine here. 292 // StartDevicePoll will NOTIFY_ERROR on failure, so IgnoreResult is fine here.
297 decoder_thread_.message_loop()->PostTask( 293 decoder_thread_.message_loop()->PostTask(
298 FROM_HERE, 294 FROM_HERE,
299 base::Bind( 295 base::Bind(
300 base::IgnoreResult(&V4L2VideoDecodeAccelerator::StartDevicePoll), 296 base::IgnoreResult(&V4L2VideoDecodeAccelerator::StartDevicePoll),
301 base::Unretained(this))); 297 base::Unretained(this)));
302 298
303 SetDecoderState(kInitialized);
304 return true; 299 return true;
305 } 300 }
306 301
307 void V4L2VideoDecodeAccelerator::Decode( 302 void V4L2VideoDecodeAccelerator::Decode(
308 const media::BitstreamBuffer& bitstream_buffer) { 303 const media::BitstreamBuffer& bitstream_buffer) {
309 DVLOG(1) << "Decode(): input_id=" << bitstream_buffer.id() 304 DVLOG(1) << "Decode(): input_id=" << bitstream_buffer.id()
310 << ", size=" << bitstream_buffer.size(); 305 << ", size=" << bitstream_buffer.size();
311 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); 306 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
312 307
313 // DecodeTask() will take care of running a DecodeBufferTask(). 308 // DecodeTask() will take care of running a DecodeBufferTask().
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( 425 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
431 &V4L2VideoDecodeAccelerator::DestroyTask, base::Unretained(this))); 426 &V4L2VideoDecodeAccelerator::DestroyTask, base::Unretained(this)));
432 pictures_assigned_.Signal(); 427 pictures_assigned_.Signal();
433 // DestroyTask() will cause the decoder_thread_ to flush all tasks. 428 // DestroyTask() will cause the decoder_thread_ to flush all tasks.
434 decoder_thread_.Stop(); 429 decoder_thread_.Stop();
435 } else { 430 } else {
436 // Otherwise, call the destroy task directly. 431 // Otherwise, call the destroy task directly.
437 DestroyTask(); 432 DestroyTask();
438 } 433 }
439 434
440 // Set to kError state just in case.
441 SetDecoderState(kError);
442
443 delete this; 435 delete this;
444 } 436 }
445 437
446 bool V4L2VideoDecodeAccelerator::CanDecodeOnIOThread() { return true; } 438 bool V4L2VideoDecodeAccelerator::CanDecodeOnIOThread() { return true; }
447 439
448 void V4L2VideoDecodeAccelerator::DecodeTask( 440 void V4L2VideoDecodeAccelerator::DecodeTask(
449 const media::BitstreamBuffer& bitstream_buffer) { 441 const media::BitstreamBuffer& bitstream_buffer) {
450 DVLOG(3) << "DecodeTask(): input_id=" << bitstream_buffer.id(); 442 DVLOG(3) << "DecodeTask(): input_id=" << bitstream_buffer.id();
451 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); 443 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
452 DCHECK_NE(decoder_state_, kUninitialized); 444 DCHECK_NE(decoder_state_, kUninitialized);
(...skipping 1138 matching lines...) Expand 10 before | Expand all | Expand 10 after
1591 &V4L2VideoDecodeAccelerator::NotifyError, weak_this_, error)); 1583 &V4L2VideoDecodeAccelerator::NotifyError, weak_this_, error));
1592 return; 1584 return;
1593 } 1585 }
1594 1586
1595 if (client_) { 1587 if (client_) {
1596 client_->NotifyError(error); 1588 client_->NotifyError(error);
1597 client_ptr_factory_.reset(); 1589 client_ptr_factory_.reset();
1598 } 1590 }
1599 } 1591 }
1600 1592
1601 void V4L2VideoDecodeAccelerator::SetDecoderState(State state) { 1593 void V4L2VideoDecodeAccelerator::SetErrorState(Error error) {
1602 DVLOG(3) << "SetDecoderState(): state=" << state;
1603
1604 // We can touch decoder_state_ only if this is the decoder thread or the 1594 // We can touch decoder_state_ only if this is the decoder thread or the
1605 // decoder thread isn't running. 1595 // decoder thread isn't running.
1606 if (decoder_thread_.message_loop() != NULL && 1596 if (decoder_thread_.message_loop() != NULL &&
1607 decoder_thread_.message_loop() != base::MessageLoop::current()) { 1597 decoder_thread_.message_loop() != base::MessageLoop::current()) {
1608 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( 1598 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
1609 &V4L2VideoDecodeAccelerator::SetDecoderState, 1599 &V4L2VideoDecodeAccelerator::SetErrorState,
1610 base::Unretained(this), state)); 1600 base::Unretained(this), error));
1611 } else { 1601 return;
1612 decoder_state_ = state;
1613 } 1602 }
1603
1604 // Post NotifyError only if we are already initialized, as the API does
1605 // not allow doing so before that.
1606 if (decoder_state_ != kError && decoder_state_ != kUninitialized)
1607 NotifyError(error);
1608
1609 decoder_state_ = kError;
1614 } 1610 }
1615 1611
1616 bool V4L2VideoDecodeAccelerator::GetFormatInfo(struct v4l2_format* format, 1612 bool V4L2VideoDecodeAccelerator::GetFormatInfo(struct v4l2_format* format,
1617 bool* again) { 1613 bool* again) {
1618 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); 1614 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
1619 1615
1620 *again = false; 1616 *again = false;
1621 memset(format, 0, sizeof(*format)); 1617 memset(format, 0, sizeof(*format));
1622 format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 1618 format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1623 if (device_->Ioctl(VIDIOC_G_FMT, format) != 0) { 1619 if (device_->Ioctl(VIDIOC_G_FMT, format) != 0) {
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
1700 return true; 1696 return true;
1701 } 1697 }
1702 1698
1703 bool V4L2VideoDecodeAccelerator::SetupFormats() { 1699 bool V4L2VideoDecodeAccelerator::SetupFormats() {
1704 // We always run this as we prepare to initialize. 1700 // We always run this as we prepare to initialize.
1705 DCHECK_EQ(decoder_state_, kUninitialized); 1701 DCHECK_EQ(decoder_state_, kUninitialized);
1706 DCHECK(!input_streamon_); 1702 DCHECK(!input_streamon_);
1707 DCHECK(!output_streamon_); 1703 DCHECK(!output_streamon_);
1708 1704
1709 __u32 input_format_fourcc = 1705 __u32 input_format_fourcc =
1710 V4L2Device::VideoCodecProfileToV4L2PixFmt(video_profile_); 1706 V4L2Device::VideoCodecProfileToV4L2PixFmt(video_profile_, false);
1711 if (!input_format_fourcc) { 1707 if (!input_format_fourcc) {
1712 NOTREACHED(); 1708 NOTREACHED();
1713 return false; 1709 return false;
1714 } 1710 }
1715 1711
1716 size_t input_size; 1712 size_t input_size;
1717 if (base::CommandLine::ForCurrentProcess()->HasSwitch( 1713 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1718 switches::kIgnoreResolutionLimitsForAcceleratedVideoDecode)) 1714 switches::kIgnoreResolutionLimitsForAcceleratedVideoDecode))
1719 input_size = kInputBufferMaxSizeFor4k; 1715 input_size = kInputBufferMaxSizeFor4k;
1720 else 1716 else
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after
1973 gfx::Size new_size(base::checked_cast<int>(format.fmt.pix_mp.width), 1969 gfx::Size new_size(base::checked_cast<int>(format.fmt.pix_mp.width),
1974 base::checked_cast<int>(format.fmt.pix_mp.height)); 1970 base::checked_cast<int>(format.fmt.pix_mp.height));
1975 if (frame_buffer_size_ != new_size) { 1971 if (frame_buffer_size_ != new_size) {
1976 DVLOG(3) << "IsResolutionChangeNecessary(): Resolution change detected"; 1972 DVLOG(3) << "IsResolutionChangeNecessary(): Resolution change detected";
1977 return true; 1973 return true;
1978 } 1974 }
1979 return false; 1975 return false;
1980 } 1976 }
1981 1977
1982 } // namespace content 1978 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698