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> |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |