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(egl_display_, |
358 attrs[9] = 0; | 348 buffers[i].texture_id(), |
359 attrs[11] = frame_buffer_size_.width(); | 349 frame_buffer_size_, |
360 attrs[13] = output_record.fds[1]; | 350 i, |
361 attrs[15] = 0; | 351 output_planes_count_); |
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) { | 352 if (egl_image == EGL_NO_IMAGE_KHR) { |
367 DLOG(ERROR) << "AssignPictureBuffers(): could not create EGLImageKHR"; | 353 DLOG(ERROR) << "AssignPictureBuffers(): could not create EGLImageKHR"; |
368 // Ownership of EGLImages allocated in previous iterations of this loop | 354 // Ownership of EGLImages allocated in previous iterations of this loop |
369 // has been transferred to output_buffer_map_. After we error-out here | 355 // has been transferred to output_buffer_map_. After we error-out here |
370 // the destructor will handle their cleanup. | 356 // the destructor will handle their cleanup. |
371 NOTIFY_ERROR(PLATFORM_FAILURE); | 357 NOTIFY_ERROR(PLATFORM_FAILURE); |
372 return; | 358 return; |
373 } | 359 } |
374 | 360 |
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; | 361 output_record.egl_image = egl_image; |
379 output_record.picture_id = buffers[i].id(); | 362 output_record.picture_id = buffers[i].id(); |
380 free_output_buffers_.push(i); | 363 free_output_buffers_.push(i); |
381 DVLOG(3) << "AssignPictureBuffers(): buffer[" << i | 364 DVLOG(3) << "AssignPictureBuffers(): buffer[" << i |
382 << "]: picture_id=" << output_record.picture_id; | 365 << "]: picture_id=" << output_record.picture_id; |
383 } | 366 } |
384 | 367 |
385 pictures_assigned_.Signal(); | 368 pictures_assigned_.Signal(); |
386 } | 369 } |
387 | 370 |
(...skipping 610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
998 DCHECK_NE(decoder_state_, kUninitialized); | 981 DCHECK_NE(decoder_state_, kUninitialized); |
999 DVLOG(3) << "DequeueEvents()"; | 982 DVLOG(3) << "DequeueEvents()"; |
1000 | 983 |
1001 struct v4l2_event ev; | 984 struct v4l2_event ev; |
1002 memset(&ev, 0, sizeof(ev)); | 985 memset(&ev, 0, sizeof(ev)); |
1003 | 986 |
1004 while (device_->Ioctl(VIDIOC_DQEVENT, &ev) == 0) { | 987 while (device_->Ioctl(VIDIOC_DQEVENT, &ev) == 0) { |
1005 if (ev.type == V4L2_EVENT_RESOLUTION_CHANGE) { | 988 if (ev.type == V4L2_EVENT_RESOLUTION_CHANGE) { |
1006 DVLOG(3) << "DequeueEvents(): got resolution change event."; | 989 DVLOG(3) << "DequeueEvents(): got resolution change event."; |
1007 DCHECK(!resolution_change_pending_); | 990 DCHECK(!resolution_change_pending_); |
1008 resolution_change_pending_ = true; | 991 resolution_change_pending_ = IsResolutionChangeNecessary(); |
1009 } else { | 992 } else { |
1010 DLOG(FATAL) << "DequeueEvents(): got an event (" << ev.type | 993 DLOG(FATAL) << "DequeueEvents(): got an event (" << ev.type |
1011 << ") we haven't subscribed to."; | 994 << ") we haven't subscribed to."; |
1012 } | 995 } |
1013 } | 996 } |
1014 } | 997 } |
1015 | 998 |
1016 void V4L2VideoDecodeAccelerator::Dequeue() { | 999 void V4L2VideoDecodeAccelerator::Dequeue() { |
1017 DVLOG(3) << "Dequeue()"; | 1000 DVLOG(3) << "Dequeue()"; |
1018 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1001 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
1019 DCHECK_NE(decoder_state_, kUninitialized); | 1002 DCHECK_NE(decoder_state_, kUninitialized); |
1020 TRACE_EVENT0("Video Decoder", "V4L2VDA::Dequeue"); | 1003 TRACE_EVENT0("Video Decoder", "V4L2VDA::Dequeue"); |
1021 | 1004 |
1022 // Dequeue completed input (VIDEO_OUTPUT) buffers, and recycle to the free | 1005 // Dequeue completed input (VIDEO_OUTPUT) buffers, and recycle to the free |
1023 // list. | 1006 // list. |
1024 struct v4l2_buffer dqbuf; | |
1025 struct v4l2_plane planes[2]; | |
1026 while (input_buffer_queued_count_ > 0) { | 1007 while (input_buffer_queued_count_ > 0) { |
1027 DCHECK(input_streamon_); | 1008 DCHECK(input_streamon_); |
1009 struct v4l2_buffer dqbuf; | |
1010 struct v4l2_plane planes[1]; | |
1028 memset(&dqbuf, 0, sizeof(dqbuf)); | 1011 memset(&dqbuf, 0, sizeof(dqbuf)); |
1029 memset(planes, 0, sizeof(planes)); | 1012 memset(planes, 0, sizeof(planes)); |
1030 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 1013 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
1031 dqbuf.memory = V4L2_MEMORY_MMAP; | 1014 dqbuf.memory = V4L2_MEMORY_MMAP; |
1032 dqbuf.m.planes = planes; | 1015 dqbuf.m.planes = planes; |
1033 dqbuf.length = 1; | 1016 dqbuf.length = 1; |
1034 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { | 1017 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { |
1035 if (errno == EAGAIN) { | 1018 if (errno == EAGAIN) { |
1036 // EAGAIN if we're just out of buffers to dequeue. | 1019 // EAGAIN if we're just out of buffers to dequeue. |
1037 break; | 1020 break; |
1038 } | 1021 } |
1039 DPLOG(ERROR) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF"; | 1022 DPLOG(ERROR) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF"; |
1040 NOTIFY_ERROR(PLATFORM_FAILURE); | 1023 NOTIFY_ERROR(PLATFORM_FAILURE); |
1041 return; | 1024 return; |
1042 } | 1025 } |
1043 InputRecord& input_record = input_buffer_map_[dqbuf.index]; | 1026 InputRecord& input_record = input_buffer_map_[dqbuf.index]; |
1044 DCHECK(input_record.at_device); | 1027 DCHECK(input_record.at_device); |
1045 free_input_buffers_.push_back(dqbuf.index); | 1028 free_input_buffers_.push_back(dqbuf.index); |
1046 input_record.at_device = false; | 1029 input_record.at_device = false; |
1047 input_record.bytes_used = 0; | 1030 input_record.bytes_used = 0; |
1048 input_record.input_id = -1; | 1031 input_record.input_id = -1; |
1049 input_buffer_queued_count_--; | 1032 input_buffer_queued_count_--; |
1050 } | 1033 } |
1051 | 1034 |
1052 // Dequeue completed output (VIDEO_CAPTURE) buffers, and queue to the | 1035 // Dequeue completed output (VIDEO_CAPTURE) buffers, and queue to the |
1053 // completed queue. | 1036 // completed queue. |
1054 while (output_buffer_queued_count_ > 0) { | 1037 while (output_buffer_queued_count_ > 0) { |
1055 DCHECK(output_streamon_); | 1038 DCHECK(output_streamon_); |
1039 struct v4l2_buffer dqbuf; | |
1040 scoped_ptr<struct v4l2_plane[]> planes( | |
1041 new v4l2_plane[output_planes_count_]); | |
1056 memset(&dqbuf, 0, sizeof(dqbuf)); | 1042 memset(&dqbuf, 0, sizeof(dqbuf)); |
1057 memset(planes, 0, sizeof(planes)); | 1043 memset(planes.get(), 0, sizeof(struct v4l2_plane) * output_planes_count_); |
1058 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1044 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
1059 dqbuf.memory = V4L2_MEMORY_MMAP; | 1045 dqbuf.memory = V4L2_MEMORY_MMAP; |
1060 dqbuf.m.planes = planes; | 1046 dqbuf.m.planes = planes.get(); |
1061 dqbuf.length = 2; | 1047 dqbuf.length = output_planes_count_; |
1062 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { | 1048 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { |
1063 if (errno == EAGAIN) { | 1049 if (errno == EAGAIN) { |
1064 // EAGAIN if we're just out of buffers to dequeue. | 1050 // EAGAIN if we're just out of buffers to dequeue. |
1065 break; | 1051 break; |
1066 } | 1052 } |
1067 DPLOG(ERROR) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF"; | 1053 DPLOG(ERROR) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF"; |
1068 NOTIFY_ERROR(PLATFORM_FAILURE); | 1054 NOTIFY_ERROR(PLATFORM_FAILURE); |
1069 return; | 1055 return; |
1070 } | 1056 } |
1071 OutputRecord& output_record = output_buffer_map_[dqbuf.index]; | 1057 OutputRecord& output_record = output_buffer_map_[dqbuf.index]; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1147 DVLOG(1) << __func__ << " eglClientWaitSyncKHR failed!"; | 1133 DVLOG(1) << __func__ << " eglClientWaitSyncKHR failed!"; |
1148 } | 1134 } |
1149 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { | 1135 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { |
1150 DLOG(FATAL) << __func__ << " eglDestroySyncKHR failed!"; | 1136 DLOG(FATAL) << __func__ << " eglDestroySyncKHR failed!"; |
1151 NOTIFY_ERROR(PLATFORM_FAILURE); | 1137 NOTIFY_ERROR(PLATFORM_FAILURE); |
1152 return false; | 1138 return false; |
1153 } | 1139 } |
1154 output_record.egl_sync = EGL_NO_SYNC_KHR; | 1140 output_record.egl_sync = EGL_NO_SYNC_KHR; |
1155 } | 1141 } |
1156 struct v4l2_buffer qbuf; | 1142 struct v4l2_buffer qbuf; |
1157 struct v4l2_plane qbuf_planes[arraysize(output_record.fds)]; | 1143 scoped_ptr<struct v4l2_plane[]> qbuf_planes( |
1144 new v4l2_plane[output_planes_count_]); | |
1158 memset(&qbuf, 0, sizeof(qbuf)); | 1145 memset(&qbuf, 0, sizeof(qbuf)); |
1159 memset(qbuf_planes, 0, sizeof(qbuf_planes)); | 1146 memset( |
1147 qbuf_planes.get(), 0, sizeof(struct v4l2_plane) * output_planes_count_); | |
1160 qbuf.index = buffer; | 1148 qbuf.index = buffer; |
1161 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1149 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
1162 qbuf.memory = V4L2_MEMORY_MMAP; | 1150 qbuf.memory = V4L2_MEMORY_MMAP; |
1163 qbuf.m.planes = qbuf_planes; | 1151 qbuf.m.planes = qbuf_planes.get(); |
1164 qbuf.length = arraysize(output_record.fds); | 1152 qbuf.length = output_planes_count_; |
1165 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); | 1153 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); |
1166 free_output_buffers_.pop(); | 1154 free_output_buffers_.pop(); |
1167 output_record.at_device = true; | 1155 output_record.at_device = true; |
1168 output_buffer_queued_count_++; | 1156 output_buffer_queued_count_++; |
1169 return true; | 1157 return true; |
1170 } | 1158 } |
1171 | 1159 |
1172 void V4L2VideoDecodeAccelerator::ReusePictureBufferTask( | 1160 void V4L2VideoDecodeAccelerator::ReusePictureBufferTask( |
1173 int32 picture_buffer_id, scoped_ptr<EGLSyncKHRRef> egl_sync_ref) { | 1161 int32 picture_buffer_id, scoped_ptr<EGLSyncKHRRef> egl_sync_ref) { |
1174 DVLOG(3) << "ReusePictureBufferTask(): picture_buffer_id=" | 1162 DVLOG(3) << "ReusePictureBufferTask(): picture_buffer_id=" |
(...skipping 450 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1625 return false; | 1613 return false; |
1626 } | 1614 } |
1627 } | 1615 } |
1628 | 1616 |
1629 return true; | 1617 return true; |
1630 } | 1618 } |
1631 | 1619 |
1632 bool V4L2VideoDecodeAccelerator::CreateBuffersForFormat( | 1620 bool V4L2VideoDecodeAccelerator::CreateBuffersForFormat( |
1633 const struct v4l2_format& format) { | 1621 const struct v4l2_format& format) { |
1634 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1622 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
1635 CHECK_EQ(format.fmt.pix_mp.num_planes, 2); | 1623 output_planes_count_ = format.fmt.pix_mp.num_planes; |
1636 frame_buffer_size_.SetSize( | 1624 frame_buffer_size_.SetSize( |
1637 format.fmt.pix_mp.width, format.fmt.pix_mp.height); | 1625 format.fmt.pix_mp.width, format.fmt.pix_mp.height); |
1638 output_buffer_pixelformat_ = format.fmt.pix_mp.pixelformat; | 1626 output_buffer_pixelformat_ = format.fmt.pix_mp.pixelformat; |
1639 DCHECK_EQ(output_buffer_pixelformat_, V4L2_PIX_FMT_NV12M); | 1627 DCHECK_EQ(output_buffer_pixelformat_, device_->PreferredOutputFormat()); |
1640 DVLOG(3) << "CreateBuffersForFormat(): new resolution: " | 1628 DVLOG(3) << "CreateBuffersForFormat(): new resolution: " |
1641 << frame_buffer_size_.ToString(); | 1629 << frame_buffer_size_.ToString(); |
1642 | 1630 |
1643 if (!CreateOutputBuffers()) | 1631 if (!CreateOutputBuffers()) |
1644 return false; | 1632 return false; |
1645 | 1633 |
1646 return true; | 1634 return true; |
1647 } | 1635 } |
1648 | 1636 |
1649 bool V4L2VideoDecodeAccelerator::CreateInputBuffers() { | 1637 bool V4L2VideoDecodeAccelerator::CreateInputBuffers() { |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1726 // Output format setup in Initialize(). | 1714 // Output format setup in Initialize(). |
1727 | 1715 |
1728 // Allocate the output buffers. | 1716 // Allocate the output buffers. |
1729 struct v4l2_requestbuffers reqbufs; | 1717 struct v4l2_requestbuffers reqbufs; |
1730 memset(&reqbufs, 0, sizeof(reqbufs)); | 1718 memset(&reqbufs, 0, sizeof(reqbufs)); |
1731 reqbufs.count = output_dpb_size_ + kDpbOutputBufferExtraCount; | 1719 reqbufs.count = output_dpb_size_ + kDpbOutputBufferExtraCount; |
1732 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1720 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
1733 reqbufs.memory = V4L2_MEMORY_MMAP; | 1721 reqbufs.memory = V4L2_MEMORY_MMAP; |
1734 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); | 1722 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); |
1735 | 1723 |
1736 // Create DMABUFs from output buffers. | |
1737 output_buffer_map_.resize(reqbufs.count); | 1724 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 | 1725 |
1753 DVLOG(3) << "CreateOutputBuffers(): ProvidePictureBuffers(): " | 1726 DVLOG(3) << "CreateOutputBuffers(): ProvidePictureBuffers(): " |
1754 << "buffer_count=" << output_buffer_map_.size() | 1727 << "buffer_count=" << output_buffer_map_.size() |
1755 << ", width=" << frame_buffer_size_.width() | 1728 << ", width=" << frame_buffer_size_.width() |
1756 << ", height=" << frame_buffer_size_.height(); | 1729 << ", height=" << frame_buffer_size_.height(); |
1757 child_message_loop_proxy_->PostTask(FROM_HERE, | 1730 child_message_loop_proxy_->PostTask(FROM_HERE, |
1758 base::Bind(&Client::ProvidePictureBuffers, | 1731 base::Bind(&Client::ProvidePictureBuffers, |
1759 client_, | 1732 client_, |
1760 output_buffer_map_.size(), | 1733 output_buffer_map_.size(), |
1761 frame_buffer_size_, | 1734 frame_buffer_size_, |
1762 GL_TEXTURE_EXTERNAL_OES)); | 1735 device_->GetTextureTarget())); |
1763 | 1736 |
1764 // Wait for the client to call AssignPictureBuffers() on the Child thread. | 1737 // Wait for the client to call AssignPictureBuffers() on the Child thread. |
1765 // We do this, because if we continue decoding without finishing buffer | 1738 // We do this, because if we continue decoding without finishing buffer |
1766 // allocation, we may end up Resetting before AssignPictureBuffers arrives, | 1739 // allocation, we may end up Resetting before AssignPictureBuffers arrives, |
1767 // resulting in unnecessary complications and subtle bugs. | 1740 // resulting in unnecessary complications and subtle bugs. |
1768 // For example, if the client calls Decode(Input1), Reset(), Decode(Input2) | 1741 // 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 | 1742 // 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 | 1743 // without waiting, we might end up running Reset{,Done}Task() before |
1771 // AssignPictureBuffers is scheduled, thus cleaning up and pushing buffers | 1744 // AssignPictureBuffers is scheduled, thus cleaning up and pushing buffers |
1772 // to the free_output_buffers_ map twice. If we somehow marked buffers as | 1745 // 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 } | 1778 } |
1806 | 1779 |
1807 bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() { | 1780 bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() { |
1808 DVLOG(3) << "DestroyOutputBuffers()"; | 1781 DVLOG(3) << "DestroyOutputBuffers()"; |
1809 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 1782 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); |
1810 DCHECK(!output_streamon_); | 1783 DCHECK(!output_streamon_); |
1811 bool success = true; | 1784 bool success = true; |
1812 | 1785 |
1813 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { | 1786 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
1814 OutputRecord& output_record = output_buffer_map_[i]; | 1787 OutputRecord& output_record = output_buffer_map_[i]; |
1815 for (size_t j = 0; j < arraysize(output_record.fds); ++j) { | 1788 |
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) { | 1789 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { |
1824 if (eglDestroyImageKHR(egl_display_, output_record.egl_image) != | 1790 if (device_->DestroyEGLImage(egl_display_, output_record.egl_image) != |
1825 EGL_TRUE) { | 1791 EGL_TRUE) { |
1826 DVLOG(1) << __func__ << " eglDestroyImageKHR failed."; | 1792 DVLOG(1) << __func__ << " DestroyEGLImage failed."; |
1827 success = false; | 1793 success = false; |
1828 } | 1794 } |
1829 } | 1795 } |
1830 | 1796 |
1831 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { | 1797 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { |
1832 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { | 1798 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { |
1833 DVLOG(1) << __func__ << " eglDestroySyncKHR failed."; | 1799 DVLOG(1) << __func__ << " eglDestroySyncKHR failed."; |
1834 success = false; | 1800 success = false; |
1835 } | 1801 } |
1836 } | 1802 } |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1919 } | 1885 } |
1920 | 1886 |
1921 void V4L2VideoDecodeAccelerator::PictureCleared() { | 1887 void V4L2VideoDecodeAccelerator::PictureCleared() { |
1922 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_; | 1888 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_; |
1923 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1889 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
1924 DCHECK_GT(picture_clearing_count_, 0); | 1890 DCHECK_GT(picture_clearing_count_, 0); |
1925 picture_clearing_count_--; | 1891 picture_clearing_count_--; |
1926 SendPictureReady(); | 1892 SendPictureReady(); |
1927 } | 1893 } |
1928 | 1894 |
1895 bool V4L2VideoDecodeAccelerator::IsResolutionChangeNecessary() { | |
1896 DVLOG(3) << "IsResolutionChangeNecessary() "; | |
1897 | |
1898 struct v4l2_control ctrl; | |
1899 memset(&ctrl, 0, sizeof(ctrl)); | |
1900 ctrl.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE; | |
1901 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_G_CTRL, &ctrl); | |
1902 if (ctrl.value != output_dpb_size_) { | |
1903 DVLOG(3) | |
1904 << "IsResolutionChangeNecessary(): Returning true since DPB mismatch "; | |
1905 return true; | |
1906 } | |
1907 struct v4l2_format format; | |
1908 bool again = false; | |
1909 bool ret = GetFormatInfo(&format, &again); | |
1910 if (!ret || again) { | |
1911 DVLOG(3) << "IsResolutionChangeNecessary(): GetFormatInfo() failed"; | |
1912 return false; | |
Ami GONE FROM CHROMIUM
2014/03/28 17:10:01
Considering that the containing method is only cal
shivdasp
2014/03/28 18:54:11
See below response.
On 2014/03/28 17:10:01, Ami Fi
| |
1913 } | |
1914 gfx::Size new_size(base::checked_cast<int>(format.fmt.pix_mp.width), | |
1915 base::checked_cast<int>(format.fmt.pix_mp.height)); | |
1916 if (frame_buffer_size_ != new_size) { | |
1917 DVLOG(3) << "IsResolutionChangeNecessary(): Resolution change detected"; | |
1918 return true; | |
1919 } | |
1920 return false; | |
Ami GONE FROM CHROMIUM
2014/03/28 17:10:01
Last comment put another way: what can trigger V4L
shivdasp
2014/03/28 18:54:11
V4L2_EVENT_RESOLUTION change is enqueued by the dr
| |
1921 } | |
1922 | |
1929 } // namespace content | 1923 } // namespace content |
OLD | NEW |