Chromium Code Reviews| 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 <libdrm/drm_fourcc.h> | |
| 9 #include <linux/videodev2.h> | 8 #include <linux/videodev2.h> |
| 10 #include <poll.h> | 9 #include <poll.h> |
| 11 #include <sys/eventfd.h> | 10 #include <sys/eventfd.h> |
| 12 #include <sys/ioctl.h> | 11 #include <sys/ioctl.h> |
| 13 #include <sys/mman.h> | 12 #include <sys/mman.h> |
| 14 | 13 |
| 15 #include "base/bind.h" | 14 #include "base/bind.h" |
| 16 #include "base/debug/trace_event.h" | 15 #include "base/debug/trace_event.h" |
| 17 #include "base/memory/shared_memory.h" | 16 #include "base/memory/shared_memory.h" |
| 18 #include "base/message_loop/message_loop.h" | 17 #include "base/message_loop/message_loop.h" |
| 19 #include "base/message_loop/message_loop_proxy.h" | 18 #include "base/message_loop/message_loop_proxy.h" |
| 19 #include "base/numerics/safe_conversions.h" | |
| 20 #include "base/posix/eintr_wrapper.h" | 20 #include "base/posix/eintr_wrapper.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/filters/h264_parser.h" | 22 #include "media/filters/h264_parser.h" |
| 23 #include "ui/gl/scoped_binders.h" | 23 #include "ui/gl/scoped_binders.h" |
| 24 | 24 |
| 25 namespace content { | 25 namespace content { |
| 26 | 26 |
| 27 #define NOTIFY_ERROR(x) \ | 27 #define NOTIFY_ERROR(x) \ |
| 28 do { \ | 28 do { \ |
| 29 SetDecoderState(kError); \ | 29 SetDecoderState(kError); \ |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 132 V4L2VideoDecodeAccelerator::InputRecord::~InputRecord() { | 132 V4L2VideoDecodeAccelerator::InputRecord::~InputRecord() { |
| 133 } | 133 } |
| 134 | 134 |
| 135 V4L2VideoDecodeAccelerator::OutputRecord::OutputRecord() | 135 V4L2VideoDecodeAccelerator::OutputRecord::OutputRecord() |
| 136 : at_device(false), | 136 : at_device(false), |
| 137 at_client(false), | 137 at_client(false), |
| 138 egl_image(EGL_NO_IMAGE_KHR), | 138 egl_image(EGL_NO_IMAGE_KHR), |
| 139 egl_sync(EGL_NO_SYNC_KHR), | 139 egl_sync(EGL_NO_SYNC_KHR), |
| 140 picture_id(-1), | 140 picture_id(-1), |
| 141 cleared(false) { | 141 cleared(false) { |
| 142 for (size_t i = 0; i < arraysize(fds); ++i) | |
| 143 fds[i] = -1; | |
| 144 } | 142 } |
| 145 | 143 |
| 146 V4L2VideoDecodeAccelerator::OutputRecord::~OutputRecord() {} | 144 V4L2VideoDecodeAccelerator::OutputRecord::~OutputRecord() {} |
| 147 | 145 |
| 148 V4L2VideoDecodeAccelerator::PictureRecord::PictureRecord( | 146 V4L2VideoDecodeAccelerator::PictureRecord::PictureRecord( |
| 149 bool cleared, | 147 bool cleared, |
| 150 const media::Picture& picture) | 148 const media::Picture& picture) |
| 151 : cleared(cleared), picture(picture) {} | 149 : cleared(cleared), picture(picture) {} |
| 152 | 150 |
| 153 V4L2VideoDecodeAccelerator::PictureRecord::~PictureRecord() {} | 151 V4L2VideoDecodeAccelerator::PictureRecord::~PictureRecord() {} |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 177 input_buffer_queued_count_(0), | 175 input_buffer_queued_count_(0), |
| 178 output_streamon_(false), | 176 output_streamon_(false), |
| 179 output_buffer_queued_count_(0), | 177 output_buffer_queued_count_(0), |
| 180 output_buffer_pixelformat_(0), | 178 output_buffer_pixelformat_(0), |
| 181 output_dpb_size_(0), | 179 output_dpb_size_(0), |
| 182 picture_clearing_count_(0), | 180 picture_clearing_count_(0), |
| 183 pictures_assigned_(false, false), | 181 pictures_assigned_(false, false), |
| 184 device_poll_thread_("V4L2DevicePollThread"), | 182 device_poll_thread_("V4L2DevicePollThread"), |
| 185 make_context_current_(make_context_current), | 183 make_context_current_(make_context_current), |
| 186 egl_display_(egl_display), | 184 egl_display_(egl_display), |
| 187 video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN) {} | 185 video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), |
| 186 output_planes_count_(0) {} | |
| 188 | 187 |
| 189 V4L2VideoDecodeAccelerator::~V4L2VideoDecodeAccelerator() { | 188 V4L2VideoDecodeAccelerator::~V4L2VideoDecodeAccelerator() { |
| 190 DCHECK(!decoder_thread_.IsRunning()); | 189 DCHECK(!decoder_thread_.IsRunning()); |
| 191 DCHECK(!device_poll_thread_.IsRunning()); | 190 DCHECK(!device_poll_thread_.IsRunning()); |
| 192 | 191 |
| 193 DestroyInputBuffers(); | 192 DestroyInputBuffers(); |
| 194 DestroyOutputBuffers(); | 193 DestroyOutputBuffers(); |
| 195 | 194 |
| 196 // These maps have members that should be manually destroyed, e.g. file | 195 // These maps have members that should be manually destroyed, e.g. file |
| 197 // descriptors, mmap() segments, etc. | 196 // descriptors, mmap() segments, etc. |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 260 return false; | 259 return false; |
| 261 } | 260 } |
| 262 | 261 |
| 263 if (!CreateInputBuffers()) | 262 if (!CreateInputBuffers()) |
| 264 return false; | 263 return false; |
| 265 | 264 |
| 266 // Output format has to be setup before streaming starts. | 265 // Output format has to be setup before streaming starts. |
| 267 struct v4l2_format format; | 266 struct v4l2_format format; |
| 268 memset(&format, 0, sizeof(format)); | 267 memset(&format, 0, sizeof(format)); |
| 269 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 268 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 270 format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M; | 269 format.fmt.pix_mp.pixelformat = device_->PreferredOutputFormat(); |
| 271 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); | 270 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format); |
| 272 | 271 |
| 273 // Subscribe to the resolution change event. | 272 // Subscribe to the resolution change event. |
| 274 struct v4l2_event_subscription sub; | 273 struct v4l2_event_subscription sub; |
| 275 memset(&sub, 0, sizeof(sub)); | 274 memset(&sub, 0, sizeof(sub)); |
| 276 sub.type = V4L2_EVENT_RESOLUTION_CHANGE; | 275 sub.type = V4L2_EVENT_RESOLUTION_CHANGE; |
| 277 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_SUBSCRIBE_EVENT, &sub); | 276 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_SUBSCRIBE_EVENT, &sub); |
| 278 | 277 |
| 279 // Initialize format-specific bits. | 278 // Initialize format-specific bits. |
| 280 if (video_profile_ >= media::H264PROFILE_MIN && | 279 if (video_profile_ >= media::H264PROFILE_MIN && |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 323 return; | 322 return; |
| 324 } | 323 } |
| 325 | 324 |
| 326 if (!make_context_current_.Run()) { | 325 if (!make_context_current_.Run()) { |
| 327 DLOG(ERROR) << "AssignPictureBuffers(): could not make context current"; | 326 DLOG(ERROR) << "AssignPictureBuffers(): could not make context current"; |
| 328 NOTIFY_ERROR(PLATFORM_FAILURE); | 327 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 329 return; | 328 return; |
| 330 } | 329 } |
| 331 | 330 |
| 332 gfx::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); | 331 gfx::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); |
| 333 EGLint attrs[] = { | |
| 334 EGL_WIDTH, 0, EGL_HEIGHT, 0, | |
| 335 EGL_LINUX_DRM_FOURCC_EXT, 0, EGL_DMA_BUF_PLANE0_FD_EXT, 0, | |
| 336 EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, EGL_DMA_BUF_PLANE0_PITCH_EXT, 0, | |
| 337 EGL_DMA_BUF_PLANE1_FD_EXT, 0, EGL_DMA_BUF_PLANE1_OFFSET_EXT, 0, | |
| 338 EGL_DMA_BUF_PLANE1_PITCH_EXT, 0, EGL_NONE, }; | |
| 339 attrs[1] = frame_buffer_size_.width(); | |
| 340 attrs[3] = frame_buffer_size_.height(); | |
| 341 attrs[5] = DRM_FORMAT_NV12; | |
| 342 | 332 |
| 343 // It's safe to manipulate all the buffer state here, because the decoder | 333 // It's safe to manipulate all the buffer state here, because the decoder |
| 344 // thread is waiting on pictures_assigned_. | 334 // thread is waiting on pictures_assigned_. |
| 345 DCHECK(free_output_buffers_.empty()); | 335 DCHECK(free_output_buffers_.empty()); |
| 346 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { | 336 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
| 347 DCHECK(buffers[i].size() == frame_buffer_size_); | 337 DCHECK(buffers[i].size() == frame_buffer_size_); |
| 348 | 338 |
| 349 OutputRecord& output_record = output_buffer_map_[i]; | 339 OutputRecord& output_record = output_buffer_map_[i]; |
| 350 DCHECK(!output_record.at_device); | 340 DCHECK(!output_record.at_device); |
| 351 DCHECK(!output_record.at_client); | 341 DCHECK(!output_record.at_client); |
| 352 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); | 342 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); |
| 353 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | 343 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
| 354 DCHECK_EQ(output_record.picture_id, -1); | 344 DCHECK_EQ(output_record.picture_id, -1); |
| 355 DCHECK_EQ(output_record.cleared, false); | 345 DCHECK_EQ(output_record.cleared, false); |
| 356 | 346 |
| 357 attrs[7] = output_record.fds[0]; | 347 EGLImageKHR egl_image = device_->CreateEGLImage( |
| 358 attrs[9] = 0; | 348 egl_display_, buffers[i].texture_id(), frame_buffer_size_, i); |
| 359 attrs[11] = frame_buffer_size_.width(); | |
| 360 attrs[13] = output_record.fds[1]; | |
| 361 attrs[15] = 0; | |
| 362 attrs[17] = frame_buffer_size_.width(); | |
| 363 | |
| 364 EGLImageKHR egl_image = eglCreateImageKHR( | |
| 365 egl_display_, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attrs); | |
| 366 if (egl_image == EGL_NO_IMAGE_KHR) { | 349 if (egl_image == EGL_NO_IMAGE_KHR) { |
| 367 DLOG(ERROR) << "AssignPictureBuffers(): could not create EGLImageKHR"; | 350 DLOG(ERROR) << "AssignPictureBuffers(): could not create EGLImageKHR"; |
| 368 // Ownership of EGLImages allocated in previous iterations of this loop | 351 // Ownership of EGLImages allocated in previous iterations of this loop |
| 369 // has been transferred to output_buffer_map_. After we error-out here | 352 // has been transferred to output_buffer_map_. After we error-out here |
| 370 // the destructor will handle their cleanup. | 353 // the destructor will handle their cleanup. |
| 371 NOTIFY_ERROR(PLATFORM_FAILURE); | 354 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 372 return; | 355 return; |
| 373 } | 356 } |
| 374 | 357 |
| 375 glBindTexture(GL_TEXTURE_EXTERNAL_OES, buffers[i].texture_id()); | |
| 376 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_image); | |
| 377 | |
| 378 output_record.egl_image = egl_image; | 358 output_record.egl_image = egl_image; |
| 379 output_record.picture_id = buffers[i].id(); | 359 output_record.picture_id = buffers[i].id(); |
| 380 free_output_buffers_.push(i); | 360 free_output_buffers_.push(i); |
| 381 DVLOG(3) << "AssignPictureBuffers(): buffer[" << i | 361 DVLOG(3) << "AssignPictureBuffers(): buffer[" << i |
| 382 << "]: picture_id=" << output_record.picture_id; | 362 << "]: picture_id=" << output_record.picture_id; |
| 383 } | 363 } |
| 384 | 364 |
| 385 pictures_assigned_.Signal(); | 365 pictures_assigned_.Signal(); |
| 386 } | 366 } |
| 387 | 367 |
| (...skipping 610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 998 DCHECK_NE(decoder_state_, kUninitialized); | 978 DCHECK_NE(decoder_state_, kUninitialized); |
| 999 DVLOG(3) << "DequeueEvents()"; | 979 DVLOG(3) << "DequeueEvents()"; |
| 1000 | 980 |
| 1001 struct v4l2_event ev; | 981 struct v4l2_event ev; |
| 1002 memset(&ev, 0, sizeof(ev)); | 982 memset(&ev, 0, sizeof(ev)); |
| 1003 | 983 |
| 1004 while (device_->Ioctl(VIDIOC_DQEVENT, &ev) == 0) { | 984 while (device_->Ioctl(VIDIOC_DQEVENT, &ev) == 0) { |
| 1005 if (ev.type == V4L2_EVENT_RESOLUTION_CHANGE) { | 985 if (ev.type == V4L2_EVENT_RESOLUTION_CHANGE) { |
| 1006 DVLOG(3) << "DequeueEvents(): got resolution change event."; | 986 DVLOG(3) << "DequeueEvents(): got resolution change event."; |
| 1007 DCHECK(!resolution_change_pending_); | 987 DCHECK(!resolution_change_pending_); |
| 1008 resolution_change_pending_ = true; | 988 resolution_change_pending_ = IsResolutionChangeNecessary(); |
| 1009 } else { | 989 } else { |
| 1010 DLOG(FATAL) << "DequeueEvents(): got an event (" << ev.type | 990 DLOG(FATAL) << "DequeueEvents(): got an event (" << ev.type |
| 1011 << ") we haven't subscribed to."; | 991 << ") we haven't subscribed to."; |
| 1012 } | 992 } |
| 1013 } | 993 } |
| 1014 } | 994 } |
| 1015 | 995 |
| 1016 void V4L2VideoDecodeAccelerator::Dequeue() { | 996 void V4L2VideoDecodeAccelerator::Dequeue() { |
| 1017 DVLOG(3) << "Dequeue()"; | 997 DVLOG(3) << "Dequeue()"; |
| 1018 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 998 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 1019 DCHECK_NE(decoder_state_, kUninitialized); | 999 DCHECK_NE(decoder_state_, kUninitialized); |
| 1020 TRACE_EVENT0("Video Decoder", "V4L2VDA::Dequeue"); | 1000 TRACE_EVENT0("Video Decoder", "V4L2VDA::Dequeue"); |
| 1021 | 1001 |
| 1022 // Dequeue completed input (VIDEO_OUTPUT) buffers, and recycle to the free | 1002 // Dequeue completed input (VIDEO_OUTPUT) buffers, and recycle to the free |
| 1023 // list. | 1003 // list. |
| 1024 struct v4l2_buffer dqbuf; | 1004 struct v4l2_buffer dqbuf; |
| 1025 struct v4l2_plane planes[2]; | 1005 struct v4l2_plane planes[2]; |
|
Pawel Osciak
2014/03/28 06:21:46
Remaining plane number hardcode.
shivdasp
2014/03/28 06:40:43
Yes I am removing this in a follow up patchset.
Si
| |
| 1026 while (input_buffer_queued_count_ > 0) { | 1006 while (input_buffer_queued_count_ > 0) { |
| 1027 DCHECK(input_streamon_); | 1007 DCHECK(input_streamon_); |
| 1028 memset(&dqbuf, 0, sizeof(dqbuf)); | 1008 memset(&dqbuf, 0, sizeof(dqbuf)); |
| 1029 memset(planes, 0, sizeof(planes)); | 1009 memset(planes, 0, sizeof(planes)); |
| 1030 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 1010 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 1031 dqbuf.memory = V4L2_MEMORY_MMAP; | 1011 dqbuf.memory = V4L2_MEMORY_MMAP; |
| 1032 dqbuf.m.planes = planes; | 1012 dqbuf.m.planes = planes; |
| 1033 dqbuf.length = 1; | 1013 dqbuf.length = 1; |
| 1034 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { | 1014 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { |
| 1035 if (errno == EAGAIN) { | 1015 if (errno == EAGAIN) { |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1147 DVLOG(1) << __func__ << " eglClientWaitSyncKHR failed!"; | 1127 DVLOG(1) << __func__ << " eglClientWaitSyncKHR failed!"; |
| 1148 } | 1128 } |
| 1149 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { | 1129 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { |
| 1150 DLOG(FATAL) << __func__ << " eglDestroySyncKHR failed!"; | 1130 DLOG(FATAL) << __func__ << " eglDestroySyncKHR failed!"; |
| 1151 NOTIFY_ERROR(PLATFORM_FAILURE); | 1131 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1152 return false; | 1132 return false; |
| 1153 } | 1133 } |
| 1154 output_record.egl_sync = EGL_NO_SYNC_KHR; | 1134 output_record.egl_sync = EGL_NO_SYNC_KHR; |
| 1155 } | 1135 } |
| 1156 struct v4l2_buffer qbuf; | 1136 struct v4l2_buffer qbuf; |
| 1157 struct v4l2_plane qbuf_planes[arraysize(output_record.fds)]; | 1137 struct v4l2_plane qbuf_planes[output_planes_count_]; |
|
Pawel Osciak
2014/03/28 06:21:46
I don't think this is valid C++, it's an extension
shivdasp
2014/03/28 06:40:43
Will fix this in next patchset.
On 2014/03/28 06:2
| |
| 1158 memset(&qbuf, 0, sizeof(qbuf)); | 1138 memset(&qbuf, 0, sizeof(qbuf)); |
| 1159 memset(qbuf_planes, 0, sizeof(qbuf_planes)); | 1139 memset(qbuf_planes, 0, sizeof(qbuf_planes)); |
| 1160 qbuf.index = buffer; | 1140 qbuf.index = buffer; |
| 1161 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1141 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 1162 qbuf.memory = V4L2_MEMORY_MMAP; | 1142 qbuf.memory = V4L2_MEMORY_MMAP; |
| 1163 qbuf.m.planes = qbuf_planes; | 1143 qbuf.m.planes = qbuf_planes; |
| 1164 qbuf.length = arraysize(output_record.fds); | 1144 qbuf.length = output_planes_count_; |
| 1165 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); | 1145 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); |
| 1166 free_output_buffers_.pop(); | 1146 free_output_buffers_.pop(); |
| 1167 output_record.at_device = true; | 1147 output_record.at_device = true; |
| 1168 output_buffer_queued_count_++; | 1148 output_buffer_queued_count_++; |
| 1169 return true; | 1149 return true; |
| 1170 } | 1150 } |
| 1171 | 1151 |
| 1172 void V4L2VideoDecodeAccelerator::ReusePictureBufferTask( | 1152 void V4L2VideoDecodeAccelerator::ReusePictureBufferTask( |
| 1173 int32 picture_buffer_id, scoped_ptr<EGLSyncKHRRef> egl_sync_ref) { | 1153 int32 picture_buffer_id, scoped_ptr<EGLSyncKHRRef> egl_sync_ref) { |
| 1174 DVLOG(3) << "ReusePictureBufferTask(): picture_buffer_id=" | 1154 DVLOG(3) << "ReusePictureBufferTask(): picture_buffer_id=" |
| (...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1529 } | 1509 } |
| 1530 | 1510 |
| 1531 struct v4l2_format format; | 1511 struct v4l2_format format; |
| 1532 bool again; | 1512 bool again; |
| 1533 bool ret = GetFormatInfo(&format, &again); | 1513 bool ret = GetFormatInfo(&format, &again); |
| 1534 if (!ret || again) { | 1514 if (!ret || again) { |
| 1535 DVLOG(3) << "Couldn't get format information after resolution change"; | 1515 DVLOG(3) << "Couldn't get format information after resolution change"; |
| 1536 NOTIFY_ERROR(PLATFORM_FAILURE); | 1516 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1537 return; | 1517 return; |
| 1538 } | 1518 } |
| 1539 | |
|
Pawel Osciak
2014/03/28 06:21:46
Let's not remove this please.
shivdasp
2014/03/28 06:40:43
Done.
| |
| 1540 if (!CreateBuffersForFormat(format)) { | 1519 if (!CreateBuffersForFormat(format)) { |
| 1541 DVLOG(3) << "Couldn't reallocate buffers after resolution change"; | 1520 DVLOG(3) << "Couldn't reallocate buffers after resolution change"; |
| 1542 NOTIFY_ERROR(PLATFORM_FAILURE); | 1521 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1543 return; | 1522 return; |
| 1544 } | 1523 } |
| 1545 | 1524 |
| 1546 decoder_state_ = kDecoding; | 1525 decoder_state_ = kDecoding; |
| 1547 | 1526 |
| 1548 if (resolution_change_reset_pending_) { | 1527 if (resolution_change_reset_pending_) { |
| 1549 resolution_change_reset_pending_ = false; | 1528 resolution_change_reset_pending_ = false; |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1625 return false; | 1604 return false; |
| 1626 } | 1605 } |
| 1627 } | 1606 } |
| 1628 | 1607 |
| 1629 return true; | 1608 return true; |
| 1630 } | 1609 } |
| 1631 | 1610 |
| 1632 bool V4L2VideoDecodeAccelerator::CreateBuffersForFormat( | 1611 bool V4L2VideoDecodeAccelerator::CreateBuffersForFormat( |
| 1633 const struct v4l2_format& format) { | 1612 const struct v4l2_format& format) { |
| 1634 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1613 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 1635 CHECK_EQ(format.fmt.pix_mp.num_planes, 2); | 1614 output_planes_count_ = format.fmt.pix_mp.num_planes; |
| 1636 frame_buffer_size_.SetSize( | 1615 frame_buffer_size_.SetSize( |
| 1637 format.fmt.pix_mp.width, format.fmt.pix_mp.height); | 1616 format.fmt.pix_mp.width, format.fmt.pix_mp.height); |
| 1638 output_buffer_pixelformat_ = format.fmt.pix_mp.pixelformat; | 1617 output_buffer_pixelformat_ = format.fmt.pix_mp.pixelformat; |
| 1639 DCHECK_EQ(output_buffer_pixelformat_, V4L2_PIX_FMT_NV12M); | 1618 DCHECK_EQ(output_buffer_pixelformat_, device_->PreferredOutputFormat()); |
| 1640 DVLOG(3) << "CreateBuffersForFormat(): new resolution: " | 1619 DVLOG(3) << "CreateBuffersForFormat(): new resolution: " |
| 1641 << frame_buffer_size_.ToString(); | 1620 << frame_buffer_size_.ToString(); |
| 1642 | 1621 |
| 1643 if (!CreateOutputBuffers()) | 1622 if (!CreateOutputBuffers()) |
| 1644 return false; | 1623 return false; |
| 1645 | 1624 |
| 1646 return true; | 1625 return true; |
| 1647 } | 1626 } |
| 1648 | 1627 |
| 1649 bool V4L2VideoDecodeAccelerator::CreateInputBuffers() { | 1628 bool V4L2VideoDecodeAccelerator::CreateInputBuffers() { |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1726 // Output format setup in Initialize(). | 1705 // Output format setup in Initialize(). |
| 1727 | 1706 |
| 1728 // Allocate the output buffers. | 1707 // Allocate the output buffers. |
| 1729 struct v4l2_requestbuffers reqbufs; | 1708 struct v4l2_requestbuffers reqbufs; |
| 1730 memset(&reqbufs, 0, sizeof(reqbufs)); | 1709 memset(&reqbufs, 0, sizeof(reqbufs)); |
| 1731 reqbufs.count = output_dpb_size_ + kDpbOutputBufferExtraCount; | 1710 reqbufs.count = output_dpb_size_ + kDpbOutputBufferExtraCount; |
| 1732 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1711 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 1733 reqbufs.memory = V4L2_MEMORY_MMAP; | 1712 reqbufs.memory = V4L2_MEMORY_MMAP; |
| 1734 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); | 1713 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); |
| 1735 | 1714 |
| 1736 // Create DMABUFs from output buffers. | |
| 1737 output_buffer_map_.resize(reqbufs.count); | 1715 output_buffer_map_.resize(reqbufs.count); |
| 1738 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { | |
| 1739 OutputRecord& output_record = output_buffer_map_[i]; | |
| 1740 for (size_t j = 0; j < arraysize(output_record.fds); ++j) { | |
| 1741 // Export the DMABUF fd so we can export it as a texture. | |
| 1742 struct v4l2_exportbuffer expbuf; | |
| 1743 memset(&expbuf, 0, sizeof(expbuf)); | |
| 1744 expbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | |
| 1745 expbuf.index = i; | |
| 1746 expbuf.plane = j; | |
| 1747 expbuf.flags = O_CLOEXEC; | |
| 1748 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_EXPBUF, &expbuf); | |
| 1749 output_record.fds[j] = expbuf.fd; | |
| 1750 } | |
| 1751 } | |
| 1752 | 1716 |
| 1753 DVLOG(3) << "CreateOutputBuffers(): ProvidePictureBuffers(): " | 1717 DVLOG(3) << "CreateOutputBuffers(): ProvidePictureBuffers(): " |
| 1754 << "buffer_count=" << output_buffer_map_.size() | 1718 << "buffer_count=" << output_buffer_map_.size() |
| 1755 << ", width=" << frame_buffer_size_.width() | 1719 << ", width=" << frame_buffer_size_.width() |
| 1756 << ", height=" << frame_buffer_size_.height(); | 1720 << ", height=" << frame_buffer_size_.height(); |
| 1757 child_message_loop_proxy_->PostTask(FROM_HERE, | 1721 child_message_loop_proxy_->PostTask(FROM_HERE, |
| 1758 base::Bind(&Client::ProvidePictureBuffers, | 1722 base::Bind(&Client::ProvidePictureBuffers, |
| 1759 client_, | 1723 client_, |
| 1760 output_buffer_map_.size(), | 1724 output_buffer_map_.size(), |
| 1761 frame_buffer_size_, | 1725 frame_buffer_size_, |
| 1762 GL_TEXTURE_EXTERNAL_OES)); | 1726 device_->GetTextureTarget())); |
| 1763 | 1727 |
| 1764 // Wait for the client to call AssignPictureBuffers() on the Child thread. | 1728 // Wait for the client to call AssignPictureBuffers() on the Child thread. |
| 1765 // We do this, because if we continue decoding without finishing buffer | 1729 // We do this, because if we continue decoding without finishing buffer |
| 1766 // allocation, we may end up Resetting before AssignPictureBuffers arrives, | 1730 // allocation, we may end up Resetting before AssignPictureBuffers arrives, |
| 1767 // resulting in unnecessary complications and subtle bugs. | 1731 // resulting in unnecessary complications and subtle bugs. |
| 1768 // For example, if the client calls Decode(Input1), Reset(), Decode(Input2) | 1732 // For example, if the client calls Decode(Input1), Reset(), Decode(Input2) |
| 1769 // in a sequence, and Decode(Input1) results in us getting here and exiting | 1733 // in a sequence, and Decode(Input1) results in us getting here and exiting |
| 1770 // without waiting, we might end up running Reset{,Done}Task() before | 1734 // without waiting, we might end up running Reset{,Done}Task() before |
| 1771 // AssignPictureBuffers is scheduled, thus cleaning up and pushing buffers | 1735 // AssignPictureBuffers is scheduled, thus cleaning up and pushing buffers |
| 1772 // to the free_output_buffers_ map twice. If we somehow marked buffers as | 1736 // to the free_output_buffers_ map twice. If we somehow marked buffers as |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1805 } | 1769 } |
| 1806 | 1770 |
| 1807 bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() { | 1771 bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() { |
| 1808 DVLOG(3) << "DestroyOutputBuffers()"; | 1772 DVLOG(3) << "DestroyOutputBuffers()"; |
| 1809 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 1773 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); |
| 1810 DCHECK(!output_streamon_); | 1774 DCHECK(!output_streamon_); |
| 1811 bool success = true; | 1775 bool success = true; |
| 1812 | 1776 |
| 1813 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { | 1777 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
| 1814 OutputRecord& output_record = output_buffer_map_[i]; | 1778 OutputRecord& output_record = output_buffer_map_[i]; |
| 1815 for (size_t j = 0; j < arraysize(output_record.fds); ++j) { | 1779 |
| 1816 if (output_record.fds[j] != -1) { | |
| 1817 if (close(output_record.fds[j])) { | |
| 1818 DVPLOG(1) << __func__ << " close() on a dmabuf fd failed."; | |
| 1819 success = false; | |
| 1820 } | |
| 1821 } | |
| 1822 } | |
| 1823 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { | 1780 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { |
| 1824 if (eglDestroyImageKHR(egl_display_, output_record.egl_image) != | 1781 if (device_->DestroyEGLImage(egl_display_, output_record.egl_image) != |
| 1825 EGL_TRUE) { | 1782 EGL_TRUE) { |
| 1826 DVLOG(1) << __func__ << " eglDestroyImageKHR failed."; | 1783 DVLOG(1) << __func__ << " eglDestroyImageKHR failed."; |
|
Pawel Osciak
2014/03/28 06:21:46
Please update the comment.
shivdasp
2014/03/28 06:40:43
Will fix in next patchset.
| |
| 1827 success = false; | 1784 success = false; |
| 1828 } | 1785 } |
| 1829 } | 1786 } |
| 1830 | 1787 |
| 1831 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { | 1788 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { |
| 1832 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { | 1789 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { |
| 1833 DVLOG(1) << __func__ << " eglDestroySyncKHR failed."; | 1790 DVLOG(1) << __func__ << " eglDestroySyncKHR failed."; |
| 1834 success = false; | 1791 success = false; |
| 1835 } | 1792 } |
| 1836 } | 1793 } |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1919 } | 1876 } |
| 1920 | 1877 |
| 1921 void V4L2VideoDecodeAccelerator::PictureCleared() { | 1878 void V4L2VideoDecodeAccelerator::PictureCleared() { |
| 1922 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_; | 1879 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_; |
| 1923 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1880 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 1924 DCHECK_GT(picture_clearing_count_, 0); | 1881 DCHECK_GT(picture_clearing_count_, 0); |
| 1925 picture_clearing_count_--; | 1882 picture_clearing_count_--; |
| 1926 SendPictureReady(); | 1883 SendPictureReady(); |
| 1927 } | 1884 } |
| 1928 | 1885 |
| 1886 bool V4L2VideoDecodeAccelerator::IsResolutionChangeNecessary() { | |
| 1887 if (frame_buffer_size_.IsEmpty()) | |
|
Pawel Osciak
2014/03/28 06:21:46
We need to verify that GetFormatInfo doesn't fail
shivdasp
2014/03/28 06:40:43
This basically is used to trigger Decoder initiali
Pawel Osciak
2014/03/28 06:52:34
Yes.
shivdasp
2014/03/28 07:00:19
GetFormatInfo() can fail if the asynchronos decode
Pawel Osciak
2014/03/28 07:25:53
But then the driver should not send the event if i
shivdasp
2014/03/28 08:00:34
Yes you are right, this if frame_buffer_size_.IsEm
| |
| 1888 return true; | |
| 1889 | |
| 1890 struct v4l2_control ctrl; | |
| 1891 memset(&ctrl, 0, sizeof(ctrl)); | |
| 1892 ctrl.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE; | |
| 1893 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_G_CTRL, &ctrl); | |
| 1894 if (ctrl.value != output_dpb_size_) { | |
| 1895 DVLOG(3) | |
| 1896 << "IsResolutionChangeNecessary(): Returning true since DPB mismatch "; | |
| 1897 return true; | |
| 1898 } | |
| 1899 struct v4l2_format format; | |
| 1900 bool again = false; | |
| 1901 bool ret = GetFormatInfo(&format, &again); | |
| 1902 if (!ret || again) { | |
| 1903 DVLOG(3) << "IsResolutionChangeNecessary(): GetFormatInfo() failed"; | |
| 1904 return false; | |
| 1905 } | |
| 1906 gfx::Size new_size(base::checked_cast<int>(format.fmt.pix_mp.width), | |
| 1907 base::checked_cast<int>(format.fmt.pix_mp.height)); | |
| 1908 if (frame_buffer_size_ != new_size) { | |
| 1909 DVLOG(3) << "IsResolutionChangeNecessary(): Resolution change detected"; | |
| 1910 return true; | |
| 1911 } | |
| 1912 return false; | |
| 1913 } | |
| 1914 | |
| 1929 } // namespace content | 1915 } // namespace content |
| OLD | NEW |