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 "media/gpu/v4l2_video_decode_accelerator.h" | 5 #include "media/gpu/v4l2_video_decode_accelerator.h" |
6 | 6 |
7 #include <dlfcn.h> | 7 #include <dlfcn.h> |
8 #include <errno.h> | 8 #include <errno.h> |
9 #include <fcntl.h> | 9 #include <fcntl.h> |
10 #include <linux/videodev2.h> | 10 #include <linux/videodev2.h> |
11 #include <poll.h> | 11 #include <poll.h> |
12 #include <string.h> | 12 #include <string.h> |
13 #include <sys/eventfd.h> | 13 #include <sys/eventfd.h> |
14 #include <sys/ioctl.h> | 14 #include <sys/ioctl.h> |
15 #include <sys/mman.h> | 15 #include <sys/mman.h> |
16 | 16 |
17 #include "base/bind.h" | 17 #include "base/bind.h" |
18 #include "base/command_line.h" | 18 #include "base/command_line.h" |
19 #include "base/memory/ptr_util.h" | |
19 #include "base/message_loop/message_loop.h" | 20 #include "base/message_loop/message_loop.h" |
20 #include "base/numerics/safe_conversions.h" | 21 #include "base/numerics/safe_conversions.h" |
21 #include "base/single_thread_task_runner.h" | 22 #include "base/single_thread_task_runner.h" |
22 #include "base/threading/thread_task_runner_handle.h" | 23 #include "base/threading/thread_task_runner_handle.h" |
23 #include "base/trace_event/trace_event.h" | 24 #include "base/trace_event/trace_event.h" |
24 #include "build/build_config.h" | 25 #include "build/build_config.h" |
25 #include "media/base/bind_to_current_loop.h" | 26 #include "media/base/bind_to_current_loop.h" |
26 #include "media/base/media_switches.h" | 27 #include "media/base/media_switches.h" |
27 #include "media/filters/h264_parser.h" | 28 #include "media/filters/h264_parser.h" |
28 #include "media/gpu/shared_memory_region.h" | 29 #include "media/gpu/shared_memory_region.h" |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
131 V4L2VideoDecodeAccelerator::InputRecord::InputRecord() | 132 V4L2VideoDecodeAccelerator::InputRecord::InputRecord() |
132 : at_device(false), address(NULL), length(0), bytes_used(0), input_id(-1) {} | 133 : at_device(false), address(NULL), length(0), bytes_used(0), input_id(-1) {} |
133 | 134 |
134 V4L2VideoDecodeAccelerator::InputRecord::~InputRecord() {} | 135 V4L2VideoDecodeAccelerator::InputRecord::~InputRecord() {} |
135 | 136 |
136 V4L2VideoDecodeAccelerator::OutputRecord::OutputRecord() | 137 V4L2VideoDecodeAccelerator::OutputRecord::OutputRecord() |
137 : state(kFree), | 138 : state(kFree), |
138 egl_image(EGL_NO_IMAGE_KHR), | 139 egl_image(EGL_NO_IMAGE_KHR), |
139 egl_sync(EGL_NO_SYNC_KHR), | 140 egl_sync(EGL_NO_SYNC_KHR), |
140 picture_id(-1), | 141 picture_id(-1), |
142 texture_id(0), | |
141 cleared(false) {} | 143 cleared(false) {} |
142 | 144 |
143 V4L2VideoDecodeAccelerator::OutputRecord::~OutputRecord() {} | 145 V4L2VideoDecodeAccelerator::OutputRecord::~OutputRecord() {} |
144 | 146 |
145 V4L2VideoDecodeAccelerator::PictureRecord::PictureRecord(bool cleared, | 147 V4L2VideoDecodeAccelerator::PictureRecord::PictureRecord(bool cleared, |
146 const Picture& picture) | 148 const Picture& picture) |
147 : cleared(cleared), picture(picture) {} | 149 : cleared(cleared), picture(picture) {} |
148 | 150 |
149 V4L2VideoDecodeAccelerator::PictureRecord::~PictureRecord() {} | 151 V4L2VideoDecodeAccelerator::PictureRecord::~PictureRecord() {} |
150 | 152 |
151 V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator( | 153 V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator( |
152 EGLDisplay egl_display, | 154 EGLDisplay egl_display, |
153 const GetGLContextCallback& get_gl_context_cb, | 155 const GetGLContextCallback& get_gl_context_cb, |
154 const MakeGLContextCurrentCallback& make_context_current_cb, | 156 const MakeGLContextCurrentCallback& make_context_current_cb, |
155 const scoped_refptr<V4L2Device>& device) | 157 const scoped_refptr<V4L2Device>& device) |
156 : child_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 158 : child_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
157 decoder_thread_("V4L2DecoderThread"), | 159 decoder_thread_("V4L2DecoderThread"), |
158 decoder_state_(kUninitialized), | 160 decoder_state_(kUninitialized), |
161 output_mode_(Config::OutputMode::ALLOCATE), | |
159 device_(device), | 162 device_(device), |
160 decoder_delay_bitstream_buffer_id_(-1), | 163 decoder_delay_bitstream_buffer_id_(-1), |
161 decoder_current_input_buffer_(-1), | 164 decoder_current_input_buffer_(-1), |
162 decoder_decode_buffer_tasks_scheduled_(0), | 165 decoder_decode_buffer_tasks_scheduled_(0), |
163 decoder_frames_at_client_(0), | 166 decoder_frames_at_client_(0), |
164 decoder_flushing_(false), | 167 decoder_flushing_(false), |
165 reset_pending_(false), | 168 reset_pending_(false), |
166 decoder_partial_frame_pending_(false), | 169 decoder_partial_frame_pending_(false), |
167 input_streamon_(false), | 170 input_streamon_(false), |
168 input_buffer_queued_count_(0), | 171 input_buffer_queued_count_(0), |
(...skipping 12 matching lines...) Expand all Loading... | |
181 egl_image_planes_count_(0), | 184 egl_image_planes_count_(0), |
182 weak_this_factory_(this) { | 185 weak_this_factory_(this) { |
183 weak_this_ = weak_this_factory_.GetWeakPtr(); | 186 weak_this_ = weak_this_factory_.GetWeakPtr(); |
184 } | 187 } |
185 | 188 |
186 V4L2VideoDecodeAccelerator::~V4L2VideoDecodeAccelerator() { | 189 V4L2VideoDecodeAccelerator::~V4L2VideoDecodeAccelerator() { |
187 DCHECK(!decoder_thread_.IsRunning()); | 190 DCHECK(!decoder_thread_.IsRunning()); |
188 DCHECK(!device_poll_thread_.IsRunning()); | 191 DCHECK(!device_poll_thread_.IsRunning()); |
189 | 192 |
190 DestroyInputBuffers(); | 193 DestroyInputBuffers(); |
194 DestroyEGLImages(); | |
191 DestroyOutputBuffers(); | 195 DestroyOutputBuffers(); |
192 | 196 |
193 // These maps have members that should be manually destroyed, e.g. file | 197 // These maps have members that should be manually destroyed, e.g. file |
194 // descriptors, mmap() segments, etc. | 198 // descriptors, mmap() segments, etc. |
195 DCHECK(input_buffer_map_.empty()); | 199 DCHECK(input_buffer_map_.empty()); |
196 DCHECK(output_buffer_map_.empty()); | 200 DCHECK(output_buffer_map_.empty()); |
197 } | 201 } |
198 | 202 |
199 bool V4L2VideoDecodeAccelerator::Initialize(const Config& config, | 203 bool V4L2VideoDecodeAccelerator::Initialize(const Config& config, |
200 Client* client) { | 204 Client* client) { |
201 DVLOGF(3) << "profile: " << config.profile; | 205 DVLOGF(3) << "profile: " << config.profile; |
202 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 206 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
203 DCHECK_EQ(decoder_state_, kUninitialized); | 207 DCHECK_EQ(decoder_state_, kUninitialized); |
204 | 208 |
205 if (!device_->SupportsDecodeProfileForV4L2PixelFormats( | 209 if (!device_->SupportsDecodeProfileForV4L2PixelFormats( |
206 config.profile, arraysize(supported_input_fourccs_), | 210 config.profile, arraysize(supported_input_fourccs_), |
207 supported_input_fourccs_)) { | 211 supported_input_fourccs_)) { |
208 DVLOGF(1) << "unsupported profile=" << config.profile; | 212 DVLOGF(1) << "unsupported profile=" << config.profile; |
209 return false; | 213 return false; |
210 } | 214 } |
211 | 215 |
212 if (config.is_encrypted) { | 216 if (config.is_encrypted) { |
213 NOTREACHED() << "Encrypted streams are not supported for this VDA"; | 217 NOTREACHED() << "Encrypted streams are not supported for this VDA"; |
214 return false; | 218 return false; |
215 } | 219 } |
216 | 220 |
217 if (config.output_mode != Config::OutputMode::ALLOCATE) { | 221 if (config.output_mode != Config::OutputMode::ALLOCATE && |
218 NOTREACHED() << "Only ALLOCATE OutputMode is supported by this VDA"; | 222 config.output_mode != Config::OutputMode::IMPORT) { |
223 NOTREACHED() << "Only ALLOCATE and IMPORT OutputModes are supported"; | |
219 return false; | 224 return false; |
220 } | 225 } |
221 | 226 |
222 if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { | |
223 NOTREACHED() << "GL callbacks are required for this VDA"; | |
224 return false; | |
225 } | |
226 | |
227 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); | 227 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); |
228 client_ = client_ptr_factory_->GetWeakPtr(); | 228 client_ = client_ptr_factory_->GetWeakPtr(); |
229 // If we haven't been set up to decode on separate thread via | 229 // If we haven't been set up to decode on separate thread via |
230 // TryToSetupDecodeOnSeparateThread(), use the main thread/client for | 230 // TryToSetupDecodeOnSeparateThread(), use the main thread/client for |
231 // decode tasks. | 231 // decode tasks. |
232 if (!decode_task_runner_) { | 232 if (!decode_task_runner_) { |
233 decode_task_runner_ = child_task_runner_; | 233 decode_task_runner_ = child_task_runner_; |
234 DCHECK(!decode_client_); | 234 DCHECK(!decode_client_); |
235 decode_client_ = client_; | 235 decode_client_ = client_; |
236 } | 236 } |
237 | 237 |
238 video_profile_ = config.profile; | 238 video_profile_ = config.profile; |
239 | 239 |
240 if (egl_display_ == EGL_NO_DISPLAY) { | 240 if (egl_display_ == EGL_NO_DISPLAY) { |
241 LOGF(ERROR) << "could not get EGLDisplay"; | 241 LOGF(ERROR) << "could not get EGLDisplay"; |
242 return false; | 242 return false; |
243 } | 243 } |
244 | 244 |
245 // We need the context to be initialized to query extensions. | 245 // We need the context to be initialized to query extensions. |
246 if (!make_context_current_cb_.Run()) { | 246 if (!make_context_current_cb_.is_null()) { |
247 LOGF(ERROR) << "could not make context current"; | 247 if (!make_context_current_cb_.Run()) { |
248 return false; | 248 LOGF(ERROR) << "could not make context current"; |
249 } | 249 return false; |
250 } | |
250 | 251 |
251 // TODO(posciak): crbug.com/450898. | 252 // TODO(posciak): crbug.com/450898. |
252 #if defined(ARCH_CPU_ARMEL) | 253 #if defined(ARCH_CPU_ARMEL) |
253 if (!gl::g_driver_egl.ext.b_EGL_KHR_fence_sync) { | 254 if (!gl::g_driver_egl.ext.b_EGL_KHR_fence_sync) { |
254 LOGF(ERROR) << "context does not have EGL_KHR_fence_sync"; | 255 LOGF(ERROR) << "context does not have EGL_KHR_fence_sync"; |
255 return false; | 256 return false; |
257 } | |
258 #endif | |
259 } else { | |
260 DVLOG(1) << "No GL callbacks provided, initializing without GL support"; | |
256 } | 261 } |
257 #endif | |
258 | 262 |
259 // Capabilities check. | 263 // Capabilities check. |
260 struct v4l2_capability caps; | 264 struct v4l2_capability caps; |
261 const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; | 265 const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; |
262 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps); | 266 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps); |
263 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { | 267 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { |
264 LOGF(ERROR) << "ioctl() failed: VIDIOC_QUERYCAP" | 268 LOGF(ERROR) << "ioctl() failed: VIDIOC_QUERYCAP" |
265 << ", caps check failed: 0x" << std::hex << caps.capabilities; | 269 << ", caps check failed: 0x" << std::hex << caps.capabilities; |
266 return false; | 270 return false; |
267 } | 271 } |
(...skipping 13 matching lines...) Expand all Loading... | |
281 | 285 |
282 if (!CreateInputBuffers()) | 286 if (!CreateInputBuffers()) |
283 return false; | 287 return false; |
284 | 288 |
285 if (!decoder_thread_.Start()) { | 289 if (!decoder_thread_.Start()) { |
286 LOGF(ERROR) << "decoder thread failed to start"; | 290 LOGF(ERROR) << "decoder thread failed to start"; |
287 return false; | 291 return false; |
288 } | 292 } |
289 | 293 |
290 decoder_state_ = kInitialized; | 294 decoder_state_ = kInitialized; |
295 output_mode_ = config.output_mode; | |
291 | 296 |
292 // StartDevicePoll will NOTIFY_ERROR on failure, so IgnoreResult is fine here. | 297 // StartDevicePoll will NOTIFY_ERROR on failure, so IgnoreResult is fine here. |
293 decoder_thread_.task_runner()->PostTask( | 298 decoder_thread_.task_runner()->PostTask( |
294 FROM_HERE, base::Bind(base::IgnoreResult( | 299 FROM_HERE, base::Bind(base::IgnoreResult( |
295 &V4L2VideoDecodeAccelerator::StartDevicePoll), | 300 &V4L2VideoDecodeAccelerator::StartDevicePoll), |
296 base::Unretained(this))); | 301 base::Unretained(this))); |
297 | 302 |
298 return true; | 303 return true; |
299 } | 304 } |
300 | 305 |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
352 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 357 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
353 reqbufs.memory = V4L2_MEMORY_MMAP; | 358 reqbufs.memory = V4L2_MEMORY_MMAP; |
354 IOCTL_OR_ERROR_RETURN(VIDIOC_REQBUFS, &reqbufs); | 359 IOCTL_OR_ERROR_RETURN(VIDIOC_REQBUFS, &reqbufs); |
355 | 360 |
356 if (reqbufs.count != buffers.size()) { | 361 if (reqbufs.count != buffers.size()) { |
357 DLOGF(ERROR) << "Could not allocate enough output buffers"; | 362 DLOGF(ERROR) << "Could not allocate enough output buffers"; |
358 NOTIFY_ERROR(PLATFORM_FAILURE); | 363 NOTIFY_ERROR(PLATFORM_FAILURE); |
359 return; | 364 return; |
360 } | 365 } |
361 | 366 |
362 if (image_processor_device_) { | |
363 DCHECK(!image_processor_); | |
364 image_processor_.reset(new V4L2ImageProcessor(image_processor_device_)); | |
365 // Unretained is safe because |this| owns image processor and there will be | |
366 // no callbacks after processor destroys. | |
367 if (!image_processor_->Initialize( | |
368 V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc_), | |
369 V4L2Device::V4L2PixFmtToVideoPixelFormat(egl_image_format_fourcc_), | |
370 V4L2_MEMORY_DMABUF, visible_size_, coded_size_, visible_size_, | |
371 visible_size_, buffers.size(), | |
372 base::Bind(&V4L2VideoDecodeAccelerator::ImageProcessorError, | |
373 base::Unretained(this)))) { | |
374 LOGF(ERROR) << "Initialize image processor failed"; | |
375 NOTIFY_ERROR(PLATFORM_FAILURE); | |
376 return; | |
377 } | |
378 DCHECK(image_processor_->output_allocated_size() == egl_image_size_); | |
379 if (image_processor_->input_allocated_size() != coded_size_) { | |
380 LOGF(ERROR) << "Image processor should be able to take the output coded " | |
381 << "size of decoder " << coded_size_.ToString() | |
382 << " without adjusting to " | |
383 << image_processor_->input_allocated_size().ToString(); | |
384 NOTIFY_ERROR(PLATFORM_FAILURE); | |
385 return; | |
386 } | |
387 } | |
388 | |
389 child_task_runner_->PostTask( | |
390 FROM_HERE, | |
391 base::Bind(&V4L2VideoDecodeAccelerator::CreateEGLImages, weak_this_, | |
392 buffers, egl_image_format_fourcc_, egl_image_planes_count_)); | |
393 } | |
394 | |
395 void V4L2VideoDecodeAccelerator::CreateEGLImages( | |
396 const std::vector<media::PictureBuffer>& buffers, | |
397 uint32_t output_format_fourcc, | |
398 size_t output_planes_count) { | |
399 DVLOGF(3); | |
400 DCHECK(child_task_runner_->BelongsToCurrentThread()); | |
401 | |
402 if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { | |
403 DLOGF(ERROR) << "GL callbacks required for binding to EGLImages"; | |
404 NOTIFY_ERROR(INVALID_ARGUMENT); | |
405 return; | |
406 } | |
407 | |
408 gl::GLContext* gl_context = get_gl_context_cb_.Run(); | |
409 if (!gl_context || !make_context_current_cb_.Run()) { | |
410 DLOGF(ERROR) << "No GL context"; | |
411 NOTIFY_ERROR(PLATFORM_FAILURE); | |
412 return; | |
413 } | |
414 | |
415 gl::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); | |
416 | |
417 std::vector<EGLImageKHR> egl_images; | |
418 for (size_t i = 0; i < buffers.size(); ++i) { | |
419 std::vector<base::ScopedFD> dmabuf_fds; | |
420 dmabuf_fds = egl_image_device_->GetDmabufsForV4L2Buffer( | |
421 i, egl_image_planes_count_, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); | |
422 if (dmabuf_fds.empty()) { | |
423 LOGF(ERROR) << "Failed to get DMABUFs for EGLImage."; | |
424 NOTIFY_ERROR(PLATFORM_FAILURE); | |
425 return; | |
426 } | |
427 | |
428 EGLImageKHR egl_image = egl_image_device_->CreateEGLImage( | |
429 egl_display_, gl_context->GetHandle(), buffers[i].texture_ids()[0], | |
430 buffers[i].size(), i, egl_image_format_fourcc_, dmabuf_fds); | |
431 if (egl_image == EGL_NO_IMAGE_KHR) { | |
432 LOGF(ERROR) << "could not create EGLImageKHR," | |
433 << " index=" << i | |
434 << " texture_id=" << buffers[i].texture_ids()[0]; | |
435 for (EGLImageKHR image : egl_images) { | |
436 if (egl_image_device_->DestroyEGLImage(egl_display_, image) != EGL_TRUE) | |
437 DVLOGF(1) << "DestroyEGLImage failed."; | |
438 } | |
439 NOTIFY_ERROR(PLATFORM_FAILURE); | |
440 return; | |
441 } | |
442 egl_images.push_back(egl_image); | |
443 } | |
444 | |
445 decoder_thread_.task_runner()->PostTask( | |
446 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::AssignEGLImages, | |
447 base::Unretained(this), buffers, egl_images)); | |
448 } | |
449 | |
450 void V4L2VideoDecodeAccelerator::AssignEGLImages( | |
451 const std::vector<media::PictureBuffer>& buffers, | |
452 const std::vector<EGLImageKHR>& egl_images) { | |
453 DVLOGF(3); | |
454 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | |
455 DCHECK_EQ(buffers.size(), egl_images.size()); | |
456 DCHECK(free_output_buffers_.empty()); | 367 DCHECK(free_output_buffers_.empty()); |
457 DCHECK(output_buffer_map_.empty()); | 368 DCHECK(output_buffer_map_.empty()); |
458 | |
459 output_buffer_map_.resize(buffers.size()); | 369 output_buffer_map_.resize(buffers.size()); |
370 if (image_processor_device_ && output_mode_ == Config::OutputMode::ALLOCATE) { | |
371 CreateImageProcessor(); | |
kcwu
2016/09/07 03:46:23
return if CreateImageProcessor failed.
| |
372 } | |
373 | |
460 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { | 374 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
461 DCHECK(buffers[i].size() == egl_image_size_); | 375 DCHECK(buffers[i].size() == egl_image_size_); |
376 DCHECK_EQ(1u, buffers[i].texture_ids().size()); | |
462 | 377 |
463 OutputRecord& output_record = output_buffer_map_[i]; | 378 OutputRecord& output_record = output_buffer_map_[i]; |
464 DCHECK_EQ(output_record.state, kFree); | 379 DCHECK_EQ(output_record.state, kFree); |
465 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); | 380 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); |
466 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | 381 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
467 DCHECK_EQ(output_record.picture_id, -1); | 382 DCHECK_EQ(output_record.picture_id, -1); |
383 DCHECK(output_record.processor_input_fds.empty()); | |
468 DCHECK_EQ(output_record.cleared, false); | 384 DCHECK_EQ(output_record.cleared, false); |
469 DCHECK_LE(1u, buffers[i].texture_ids().size()); | 385 |
386 output_record.picture_id = buffers[i].id(); | |
387 output_record.texture_id = buffers[i].texture_ids()[0]; | |
388 // This will remain kAtClient until ImportBufferForPicture is called, either | |
389 // by the client, or by ourselves, if we are allocating. | |
390 output_record.state = kAtClient; | |
470 | 391 |
471 if (image_processor_device_) { | 392 if (image_processor_device_) { |
472 std::vector<base::ScopedFD> fds = device_->GetDmabufsForV4L2Buffer( | 393 std::vector<base::ScopedFD> dmabuf_fds = device_->GetDmabufsForV4L2Buffer( |
473 i, output_planes_count_, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); | 394 i, output_planes_count_, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); |
474 if (fds.empty()) { | 395 if (dmabuf_fds.empty()) { |
475 LOGF(ERROR) << "Failed to get DMABUFs of decoder."; | 396 LOGF(ERROR) << "Failed to get DMABUFs of decoder."; |
476 NOTIFY_ERROR(PLATFORM_FAILURE); | 397 NOTIFY_ERROR(PLATFORM_FAILURE); |
477 return; | 398 return; |
478 } | 399 } |
479 output_record.fds = std::move(fds); | 400 output_record.processor_input_fds = std::move(dmabuf_fds); |
480 } | 401 } |
481 | 402 |
482 output_record.egl_image = egl_images[i]; | 403 if (output_mode_ == Config::OutputMode::ALLOCATE) { |
483 output_record.picture_id = buffers[i].id(); | 404 std::vector<base::ScopedFD> dmabuf_fds; |
484 | 405 dmabuf_fds = egl_image_device_->GetDmabufsForV4L2Buffer( |
485 free_output_buffers_.push(i); | 406 i, egl_image_planes_count_, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); |
486 DVLOGF(3) << "buffer[" << i << "]: picture_id=" << output_record.picture_id; | 407 if (dmabuf_fds.empty()) { |
487 } | 408 LOGF(ERROR) << "Failed to get DMABUFs for EGLImage."; |
488 | 409 NOTIFY_ERROR(PLATFORM_FAILURE); |
489 decoder_state_ = kDecoding; | 410 return; |
490 Enqueue(); | 411 } |
412 auto passed_dmabuf_fds(base::WrapUnique( | |
413 new std::vector<base::ScopedFD>(std::move(dmabuf_fds)))); | |
414 ImportBufferForPictureTask(output_record.picture_id, | |
415 std::move(passed_dmabuf_fds), | |
416 egl_image_size_.width()); | |
417 } // else we'll get triggered via ImportBufferForPicture() from client. | |
418 | |
419 DVLOGF(3) << "AssignPictureBuffers(): buffer[" << i | |
420 << "]: picture_id=" << output_record.picture_id; | |
421 } | |
422 } | |
423 | |
424 void V4L2VideoDecodeAccelerator::CreateEGLImageFor( | |
425 size_t buffer_index, | |
426 int32_t picture_buffer_id, | |
427 std::unique_ptr<std::vector<base::ScopedFD>> passed_dmabuf_fds, | |
428 GLuint texture_id, | |
429 const gfx::Size& size, | |
430 uint32_t fourcc) { | |
431 DVLOGF(3) << "index=" << buffer_index; | |
432 DCHECK(child_task_runner_->BelongsToCurrentThread()); | |
433 | |
434 if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { | |
435 DLOG(ERROR) << "GL callbacks required for binding to EGLImages"; | |
436 NOTIFY_ERROR(INVALID_ARGUMENT); | |
437 return; | |
438 } | |
439 | |
440 gl::GLContext* gl_context = get_gl_context_cb_.Run(); | |
441 if (!gl_context || !make_context_current_cb_.Run()) { | |
442 DLOG(ERROR) << "No GL context"; | |
443 NOTIFY_ERROR(PLATFORM_FAILURE); | |
444 return; | |
445 } | |
446 | |
447 gl::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); | |
448 | |
449 EGLImageKHR egl_image = egl_image_device_->CreateEGLImage( | |
450 egl_display_, gl_context->GetHandle(), texture_id, size, buffer_index, | |
451 fourcc, *passed_dmabuf_fds); | |
452 if (egl_image == EGL_NO_IMAGE_KHR) { | |
453 LOGF(ERROR) << "could not create EGLImageKHR," | |
454 << " index=" << buffer_index << " texture_id=" << texture_id; | |
455 NOTIFY_ERROR(PLATFORM_FAILURE); | |
456 return; | |
457 } | |
458 | |
459 decoder_thread_.task_runner()->PostTask( | |
460 FROM_HERE, | |
461 base::Bind(&V4L2VideoDecodeAccelerator::AssignEGLImage, | |
462 base::Unretained(this), buffer_index, picture_buffer_id, | |
463 egl_image, base::Passed(&passed_dmabuf_fds))); | |
464 } | |
465 | |
466 void V4L2VideoDecodeAccelerator::AssignEGLImage( | |
467 size_t buffer_index, | |
468 int32_t picture_buffer_id, | |
469 EGLImageKHR egl_image, | |
470 std::unique_ptr<std::vector<base::ScopedFD>> passed_dmabuf_fds) { | |
471 DVLOGF(3) << "index=" << buffer_index; | |
472 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | |
473 | |
474 // It's possible that while waiting for the EGLImages to be allocated and | |
475 // assigned, we have already decoded more of the stream and saw another | |
476 // resolution change. This is a normal situation, in such a case either there | |
477 // is no output record with this index awaiting an EGLImage to be assigned to | |
478 // it, or the record is already updated to use a newer PictureBuffer and is | |
479 // awaiting an EGLImage associated with a different picture_buffer_id. If so, | |
480 // just discard this image, we will get the one we are waiting for later. | |
481 if (buffer_index >= output_buffer_map_.size() || | |
482 output_buffer_map_[buffer_index].picture_id != picture_buffer_id) { | |
483 DVLOGF(3) << "Picture set already changed, dropping EGLImage"; | |
484 child_task_runner_->PostTask( | |
485 FROM_HERE, base::Bind(base::IgnoreResult(&V4L2Device::DestroyEGLImage), | |
486 device_, egl_display_, egl_image)); | |
487 return; | |
488 } | |
489 | |
490 OutputRecord& output_record = output_buffer_map_[buffer_index]; | |
491 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); | |
492 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | |
493 DCHECK_EQ(output_record.state, kFree); | |
494 DCHECK_EQ(std::count(free_output_buffers_.begin(), free_output_buffers_.end(), | |
495 buffer_index), | |
496 0); | |
497 output_record.egl_image = egl_image; | |
498 free_output_buffers_.push_back(buffer_index); | |
499 if (decoder_state_ == kAwaitingPictureBuffers) { | |
500 DVLOG(1) << "Change state to kDecoding"; | |
501 decoder_state_ = kDecoding; | |
502 } | |
491 if (reset_pending_) { | 503 if (reset_pending_) { |
492 FinishReset(); | 504 FinishReset(); |
493 return; | 505 return; |
494 } | 506 } |
495 | 507 if (decoder_state_ != kChangingResolution) { |
496 ScheduleDecodeBufferTaskIfNeeded(); | 508 Enqueue(); |
509 ScheduleDecodeBufferTaskIfNeeded(); | |
510 } | |
511 } | |
512 | |
513 void V4L2VideoDecodeAccelerator::ImportBufferForPicture( | |
514 int32_t picture_buffer_id, | |
515 const gfx::GpuMemoryBufferHandle& gpu_memory_buffer_handle) { | |
516 DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id; | |
517 DCHECK(child_task_runner_->BelongsToCurrentThread()); | |
518 | |
519 auto passed_dmabuf_fds(base::WrapUnique(new std::vector<base::ScopedFD>())); | |
520 int32_t stride = egl_image_size_.width(); | |
521 #if defined(USE_OZONE) | |
522 for (const auto& fd : gpu_memory_buffer_handle.native_pixmap_handle.fds) { | |
523 DCHECK_NE(fd.fd, -1); | |
524 passed_dmabuf_fds->push_back(base::ScopedFD(fd.fd)); | |
525 } | |
526 stride = gpu_memory_buffer_handle.native_pixmap_handle.planes[0].stride; | |
527 for (const auto& plane : | |
528 gpu_memory_buffer_handle.native_pixmap_handle.planes) { | |
529 DVLOGF(3) << ": offset=" << plane.offset << ", stride=" << plane.stride; | |
530 } | |
531 #endif | |
532 | |
533 if (output_mode_ != Config::OutputMode::IMPORT) { | |
534 LOGF(ERROR) << "Cannot import in non-import mode"; | |
535 NOTIFY_ERROR(INVALID_ARGUMENT); | |
536 return; | |
537 } | |
538 | |
539 decoder_thread_.message_loop()->PostTask( | |
540 FROM_HERE, | |
541 base::Bind(&V4L2VideoDecodeAccelerator::ImportBufferForPictureTask, | |
542 base::Unretained(this), picture_buffer_id, | |
543 base::Passed(&passed_dmabuf_fds), stride)); | |
544 } | |
545 | |
546 void V4L2VideoDecodeAccelerator::ImportBufferForPictureTask( | |
547 int32_t picture_buffer_id, | |
548 std::unique_ptr<std::vector<base::ScopedFD>> passed_dmabuf_fds, | |
549 int32_t stride) { | |
550 DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id; | |
551 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | |
552 | |
553 if (image_processor_device_ && !image_processor_) { | |
554 DVLOGF(3) << "Original egl_image_size=" << egl_image_size_.ToString() | |
555 << ", width is adjusted to=" << stride; | |
556 egl_image_size_.set_width(stride); | |
557 CreateImageProcessor(); | |
kcwu
2016/09/07 03:46:23
return if CreateImageProcessor failed.
| |
558 } | |
559 | |
560 const auto iter = | |
561 std::find_if(output_buffer_map_.begin(), output_buffer_map_.end(), | |
562 [picture_buffer_id](const OutputRecord& output_record) { | |
563 return output_record.picture_id == picture_buffer_id; | |
564 }); | |
565 if (iter == output_buffer_map_.end()) { | |
566 // It's possible that we've already posted a DismissPictureBuffer for this | |
567 // picture, but it has not yet executed when this ImportBufferForPicture was | |
568 // posted to us by the client. In that case just ignore this (we've already | |
569 // dismissed it and accounted for that). | |
570 DVLOGF(3) << "got picture id=" << picture_buffer_id | |
571 << " not in use (anymore?)."; | |
572 return; | |
573 } | |
574 | |
575 if (iter->state != kAtClient) { | |
576 LOGF(ERROR) << "Cannot import buffer that not owned by client"; | |
577 NOTIFY_ERROR(INVALID_ARGUMENT); | |
578 return; | |
579 } | |
580 | |
581 size_t index = iter - output_buffer_map_.begin(); | |
582 DCHECK_EQ(std::count(free_output_buffers_.begin(), free_output_buffers_.end(), | |
583 index), | |
584 0); | |
585 | |
586 iter->state = kFree; | |
587 if (iter->texture_id != 0) { | |
588 if (iter->egl_image != EGL_NO_IMAGE_KHR) { | |
589 child_task_runner_->PostTask( | |
590 FROM_HERE, | |
591 base::Bind(base::IgnoreResult(&V4L2Device::DestroyEGLImage), device_, | |
592 egl_display_, iter->egl_image)); | |
593 } | |
594 | |
595 child_task_runner_->PostTask( | |
596 FROM_HERE, | |
597 base::Bind(&V4L2VideoDecodeAccelerator::CreateEGLImageFor, weak_this_, | |
598 index, picture_buffer_id, base::Passed(&passed_dmabuf_fds), | |
599 iter->texture_id, egl_image_size_, | |
600 egl_image_format_fourcc_)); | |
601 } else { | |
602 // No need for an EGLImage, start using this buffer now. | |
603 DVLOGF(2) << "egl_image_planes_count_=" << egl_image_planes_count_ | |
604 << ", passed_dmabuf_fds->size()=" << passed_dmabuf_fds->size(); | |
605 DCHECK_EQ(egl_image_planes_count_, passed_dmabuf_fds->size()); | |
606 iter->processor_output_fds.swap(*passed_dmabuf_fds); | |
607 free_output_buffers_.push_back(index); | |
608 if (decoder_state_ == kAwaitingPictureBuffers) { | |
609 DVLOG(1) << "Change state to kDecoding"; | |
610 decoder_state_ = kDecoding; | |
611 } | |
612 if (decoder_state_ != kChangingResolution) { | |
613 Enqueue(); | |
614 ScheduleDecodeBufferTaskIfNeeded(); | |
615 } | |
616 } | |
497 } | 617 } |
498 | 618 |
499 void V4L2VideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_buffer_id) { | 619 void V4L2VideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_buffer_id) { |
500 DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id; | 620 DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id; |
501 // Must be run on child thread, as we'll insert a sync in the EGL context. | 621 // Must be run on child thread, as we'll insert a sync in the EGL context. |
502 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 622 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
503 | 623 |
504 if (!make_context_current_cb_.Run()) { | 624 std::unique_ptr<EGLSyncKHRRef> egl_sync_ref; |
505 LOGF(ERROR) << "could not make context current"; | |
506 NOTIFY_ERROR(PLATFORM_FAILURE); | |
507 return; | |
508 } | |
509 | 625 |
510 EGLSyncKHR egl_sync = EGL_NO_SYNC_KHR; | 626 if (!make_context_current_cb_.is_null()) { |
627 if (!make_context_current_cb_.Run()) { | |
628 LOGF(ERROR) << "could not make context current"; | |
629 NOTIFY_ERROR(PLATFORM_FAILURE); | |
630 return; | |
631 } | |
632 | |
633 EGLSyncKHR egl_sync = EGL_NO_SYNC_KHR; | |
511 // TODO(posciak): crbug.com/450898. | 634 // TODO(posciak): crbug.com/450898. |
512 #if defined(ARCH_CPU_ARMEL) | 635 #if defined(ARCH_CPU_ARMEL) |
513 egl_sync = eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL); | 636 egl_sync = eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL); |
514 if (egl_sync == EGL_NO_SYNC_KHR) { | 637 if (egl_sync == EGL_NO_SYNC_KHR) { |
515 LOGF(ERROR) << "eglCreateSyncKHR() failed"; | 638 LOGF(ERROR) << "eglCreateSyncKHR() failed"; |
516 NOTIFY_ERROR(PLATFORM_FAILURE); | 639 NOTIFY_ERROR(PLATFORM_FAILURE); |
517 return; | 640 return; |
518 } | 641 } |
519 #endif | 642 #endif |
520 | 643 |
521 std::unique_ptr<EGLSyncKHRRef> egl_sync_ref( | 644 egl_sync_ref.reset(new EGLSyncKHRRef(egl_display_, egl_sync)); |
522 new EGLSyncKHRRef(egl_display_, egl_sync)); | 645 } |
523 | 646 |
524 decoder_thread_.task_runner()->PostTask( | 647 decoder_thread_.task_runner()->PostTask( |
525 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::ReusePictureBufferTask, | 648 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::ReusePictureBufferTask, |
526 base::Unretained(this), picture_buffer_id, | 649 base::Unretained(this), picture_buffer_id, |
527 base::Passed(&egl_sync_ref))); | 650 base::Passed(&egl_sync_ref))); |
528 } | 651 } |
529 | 652 |
530 void V4L2VideoDecodeAccelerator::Flush() { | 653 void V4L2VideoDecodeAccelerator::Flush() { |
531 DVLOGF(3); | 654 DVLOGF(3); |
532 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 655 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
(...skipping 663 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1196 if (errno == EAGAIN) { | 1319 if (errno == EAGAIN) { |
1197 // EAGAIN if we're just out of buffers to dequeue. | 1320 // EAGAIN if we're just out of buffers to dequeue. |
1198 break; | 1321 break; |
1199 } | 1322 } |
1200 PLOGF(ERROR) << "ioctl() failed: VIDIOC_DQBUF"; | 1323 PLOGF(ERROR) << "ioctl() failed: VIDIOC_DQBUF"; |
1201 NOTIFY_ERROR(PLATFORM_FAILURE); | 1324 NOTIFY_ERROR(PLATFORM_FAILURE); |
1202 return; | 1325 return; |
1203 } | 1326 } |
1204 OutputRecord& output_record = output_buffer_map_[dqbuf.index]; | 1327 OutputRecord& output_record = output_buffer_map_[dqbuf.index]; |
1205 DCHECK_EQ(output_record.state, kAtDevice); | 1328 DCHECK_EQ(output_record.state, kAtDevice); |
1206 DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR); | 1329 // DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR); |
kcwu
2016/09/07 03:46:23
remove
| |
1207 DCHECK_NE(output_record.picture_id, -1); | 1330 DCHECK_NE(output_record.picture_id, -1); |
1208 output_buffer_queued_count_--; | 1331 output_buffer_queued_count_--; |
1209 if (dqbuf.m.planes[0].bytesused == 0) { | 1332 if (dqbuf.m.planes[0].bytesused == 0) { |
1210 // This is an empty output buffer returned as part of a flush. | 1333 // This is an empty output buffer returned as part of a flush. |
1211 output_record.state = kFree; | 1334 output_record.state = kFree; |
1212 free_output_buffers_.push(dqbuf.index); | 1335 free_output_buffers_.push_back(dqbuf.index); |
1213 } else { | 1336 } else { |
1214 int32_t bitstream_buffer_id = dqbuf.timestamp.tv_sec; | 1337 int32_t bitstream_buffer_id = dqbuf.timestamp.tv_sec; |
1215 DCHECK_GE(bitstream_buffer_id, 0); | 1338 DCHECK_GE(bitstream_buffer_id, 0); |
1216 DVLOGF(3) << "Dequeue output buffer: dqbuf index=" << dqbuf.index | 1339 DVLOGF(3) << "Dequeue output buffer: dqbuf index=" << dqbuf.index |
1217 << " bitstream input_id=" << bitstream_buffer_id; | 1340 << " bitstream input_id=" << bitstream_buffer_id; |
1218 if (image_processor_device_) { | 1341 if (image_processor_device_) { |
1219 output_record.state = kAtProcessor; | 1342 output_record.state = kAtProcessor; |
1220 image_processor_bitstream_buffer_ids_.push(bitstream_buffer_id); | 1343 image_processor_bitstream_buffer_ids_.push(bitstream_buffer_id); |
1221 std::vector<int> fds; | 1344 std::vector<int> processor_input_fds; |
1222 for (auto& fd : output_record.fds) { | 1345 for (auto& fd : output_record.processor_input_fds) { |
1223 fds.push_back(fd.get()); | 1346 processor_input_fds.push_back(fd.get()); |
1347 } | |
1348 std::vector<int> processor_output_fds; | |
1349 for (auto& fd : output_record.processor_output_fds) { | |
1350 processor_output_fds.push_back(fd.get()); | |
1224 } | 1351 } |
1225 scoped_refptr<VideoFrame> frame = VideoFrame::WrapExternalDmabufs( | 1352 scoped_refptr<VideoFrame> frame = VideoFrame::WrapExternalDmabufs( |
1226 V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc_), | 1353 V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc_), |
1227 coded_size_, gfx::Rect(visible_size_), visible_size_, fds, | 1354 coded_size_, gfx::Rect(visible_size_), visible_size_, |
1228 base::TimeDelta()); | 1355 processor_input_fds, base::TimeDelta()); |
1229 // Unretained is safe because |this| owns image processor and there will | 1356 // Unretained is safe because |this| owns image processor and there will |
1230 // be no callbacks after processor destroys. Also, this class ensures it | 1357 // be no callbacks after processor destroys. Also, this class ensures it |
1231 // is safe to post a task from child thread to decoder thread using | 1358 // is safe to post a task from child thread to decoder thread using |
1232 // Unretained. | 1359 // Unretained. |
1233 image_processor_->Process( | 1360 image_processor_->Process( |
1234 frame, dqbuf.index, | 1361 frame, dqbuf.index, processor_output_fds, |
1235 BindToCurrentLoop( | 1362 BindToCurrentLoop( |
1236 base::Bind(&V4L2VideoDecodeAccelerator::FrameProcessed, | 1363 base::Bind(&V4L2VideoDecodeAccelerator::FrameProcessed, |
1237 base::Unretained(this), bitstream_buffer_id))); | 1364 base::Unretained(this), bitstream_buffer_id))); |
1238 } else { | 1365 } else { |
1239 output_record.state = kAtClient; | 1366 output_record.state = kAtClient; |
1240 decoder_frames_at_client_++; | 1367 decoder_frames_at_client_++; |
1241 const Picture picture(output_record.picture_id, bitstream_buffer_id, | 1368 const Picture picture(output_record.picture_id, bitstream_buffer_id, |
1242 gfx::Rect(visible_size_), false); | 1369 gfx::Rect(visible_size_), false); |
1243 pending_picture_ready_.push( | 1370 pending_picture_ready_.push( |
1244 PictureRecord(output_record.cleared, picture)); | 1371 PictureRecord(output_record.cleared, picture)); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1280 } | 1407 } |
1281 | 1408 |
1282 bool V4L2VideoDecodeAccelerator::EnqueueOutputRecord() { | 1409 bool V4L2VideoDecodeAccelerator::EnqueueOutputRecord() { |
1283 DCHECK(!free_output_buffers_.empty()); | 1410 DCHECK(!free_output_buffers_.empty()); |
1284 | 1411 |
1285 // Enqueue an output (VIDEO_CAPTURE) buffer. | 1412 // Enqueue an output (VIDEO_CAPTURE) buffer. |
1286 const int buffer = free_output_buffers_.front(); | 1413 const int buffer = free_output_buffers_.front(); |
1287 DVLOGF(3) << "buffer " << buffer; | 1414 DVLOGF(3) << "buffer " << buffer; |
1288 OutputRecord& output_record = output_buffer_map_[buffer]; | 1415 OutputRecord& output_record = output_buffer_map_[buffer]; |
1289 DCHECK_EQ(output_record.state, kFree); | 1416 DCHECK_EQ(output_record.state, kFree); |
1290 DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR); | |
1291 DCHECK_NE(output_record.picture_id, -1); | 1417 DCHECK_NE(output_record.picture_id, -1); |
1292 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { | 1418 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { |
1293 TRACE_EVENT0("Video Decoder", | 1419 TRACE_EVENT0("Video Decoder", |
1294 "V4L2VDA::EnqueueOutputRecord: eglClientWaitSyncKHR"); | 1420 "V4L2VDA::EnqueueOutputRecord: eglClientWaitSyncKHR"); |
1295 // If we have to wait for completion, wait. Note that | 1421 // If we have to wait for completion, wait. Note that |
1296 // free_output_buffers_ is a FIFO queue, so we always wait on the | 1422 // free_output_buffers_ is a FIFO queue, so we always wait on the |
1297 // buffer that has been in the queue the longest. | 1423 // buffer that has been in the queue the longest. |
1298 if (eglClientWaitSyncKHR(egl_display_, output_record.egl_sync, 0, | 1424 if (eglClientWaitSyncKHR(egl_display_, output_record.egl_sync, 0, |
1299 EGL_FOREVER_KHR) == EGL_FALSE) { | 1425 EGL_FOREVER_KHR) == EGL_FALSE) { |
1300 // This will cause tearing, but is safe otherwise. | 1426 // This will cause tearing, but is safe otherwise. |
(...skipping 10 matching lines...) Expand all Loading... | |
1311 std::unique_ptr<struct v4l2_plane[]> qbuf_planes( | 1437 std::unique_ptr<struct v4l2_plane[]> qbuf_planes( |
1312 new v4l2_plane[output_planes_count_]); | 1438 new v4l2_plane[output_planes_count_]); |
1313 memset(&qbuf, 0, sizeof(qbuf)); | 1439 memset(&qbuf, 0, sizeof(qbuf)); |
1314 memset(qbuf_planes.get(), 0, | 1440 memset(qbuf_planes.get(), 0, |
1315 sizeof(struct v4l2_plane) * output_planes_count_); | 1441 sizeof(struct v4l2_plane) * output_planes_count_); |
1316 qbuf.index = buffer; | 1442 qbuf.index = buffer; |
1317 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1443 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
1318 qbuf.memory = V4L2_MEMORY_MMAP; | 1444 qbuf.memory = V4L2_MEMORY_MMAP; |
1319 qbuf.m.planes = qbuf_planes.get(); | 1445 qbuf.m.planes = qbuf_planes.get(); |
1320 qbuf.length = output_planes_count_; | 1446 qbuf.length = output_planes_count_; |
1447 DVLOG(2) << "qbuf.index=" << qbuf.index | |
1448 << ", output_mode_=" << (int)output_mode_ | |
1449 << ", output_planes_count_=" << output_planes_count_; | |
1321 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); | 1450 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); |
1322 free_output_buffers_.pop(); | 1451 free_output_buffers_.pop_front(); |
1323 output_record.state = kAtDevice; | 1452 output_record.state = kAtDevice; |
1324 output_buffer_queued_count_++; | 1453 output_buffer_queued_count_++; |
1325 return true; | 1454 return true; |
1326 } | 1455 } |
1327 | 1456 |
1328 void V4L2VideoDecodeAccelerator::ReusePictureBufferTask( | 1457 void V4L2VideoDecodeAccelerator::ReusePictureBufferTask( |
1329 int32_t picture_buffer_id, | 1458 int32_t picture_buffer_id, |
1330 std::unique_ptr<EGLSyncKHRRef> egl_sync_ref) { | 1459 std::unique_ptr<EGLSyncKHRRef> egl_sync_ref) { |
1331 DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id; | 1460 DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id; |
1332 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 1461 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
(...skipping 27 matching lines...) Expand all Loading... | |
1360 } | 1489 } |
1361 | 1490 |
1362 OutputRecord& output_record = output_buffer_map_[index]; | 1491 OutputRecord& output_record = output_buffer_map_[index]; |
1363 if (output_record.state != kAtClient) { | 1492 if (output_record.state != kAtClient) { |
1364 LOGF(ERROR) << "picture_buffer_id not reusable"; | 1493 LOGF(ERROR) << "picture_buffer_id not reusable"; |
1365 NOTIFY_ERROR(INVALID_ARGUMENT); | 1494 NOTIFY_ERROR(INVALID_ARGUMENT); |
1366 return; | 1495 return; |
1367 } | 1496 } |
1368 | 1497 |
1369 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | 1498 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
1370 output_record.egl_sync = egl_sync_ref->egl_sync; | |
1371 output_record.state = kFree; | 1499 output_record.state = kFree; |
1372 free_output_buffers_.push(index); | 1500 free_output_buffers_.push_back(index); |
1373 decoder_frames_at_client_--; | 1501 decoder_frames_at_client_--; |
1374 // Take ownership of the EGLSync. | 1502 if (egl_sync_ref) { |
1375 egl_sync_ref->egl_sync = EGL_NO_SYNC_KHR; | 1503 output_record.egl_sync = egl_sync_ref->egl_sync; |
1504 // Take ownership of the EGLSync. | |
1505 egl_sync_ref->egl_sync = EGL_NO_SYNC_KHR; | |
1506 } | |
1376 // We got a buffer back, so enqueue it back. | 1507 // We got a buffer back, so enqueue it back. |
1377 Enqueue(); | 1508 Enqueue(); |
1378 } | 1509 } |
1379 | 1510 |
1380 void V4L2VideoDecodeAccelerator::FlushTask() { | 1511 void V4L2VideoDecodeAccelerator::FlushTask() { |
1381 DVLOGF(3); | 1512 DVLOGF(3); |
1382 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 1513 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
1383 TRACE_EVENT0("Video Decoder", "V4L2VDA::FlushTask"); | 1514 TRACE_EVENT0("Video Decoder", "V4L2VDA::FlushTask"); |
1384 | 1515 |
1385 // Flush outstanding buffers. | 1516 // Flush outstanding buffers. |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1631 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_STREAMOFF, &type); | 1762 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_STREAMOFF, &type); |
1632 output_streamon_ = false; | 1763 output_streamon_ = false; |
1633 | 1764 |
1634 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { | 1765 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
1635 // After streamoff, the device drops ownership of all buffers, even if we | 1766 // After streamoff, the device drops ownership of all buffers, even if we |
1636 // don't dequeue them explicitly. Some of them may still be owned by the | 1767 // don't dequeue them explicitly. Some of them may still be owned by the |
1637 // client however. Reuse only those that aren't. | 1768 // client however. Reuse only those that aren't. |
1638 OutputRecord& output_record = output_buffer_map_[i]; | 1769 OutputRecord& output_record = output_buffer_map_[i]; |
1639 if (output_record.state == kAtDevice) { | 1770 if (output_record.state == kAtDevice) { |
1640 output_record.state = kFree; | 1771 output_record.state = kFree; |
1641 free_output_buffers_.push(i); | 1772 free_output_buffers_.push_back(i); |
1642 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | 1773 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
1643 } | 1774 } |
1644 } | 1775 } |
1645 output_buffer_queued_count_ = 0; | 1776 output_buffer_queued_count_ = 0; |
1646 return true; | 1777 return true; |
1647 } | 1778 } |
1648 | 1779 |
1649 bool V4L2VideoDecodeAccelerator::StopInputStream() { | 1780 bool V4L2VideoDecodeAccelerator::StopInputStream() { |
1650 DVLOGF(3); | 1781 DVLOGF(3); |
1651 if (!input_streamon_) | 1782 if (!input_streamon_) |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1701 void V4L2VideoDecodeAccelerator::FinishResolutionChange() { | 1832 void V4L2VideoDecodeAccelerator::FinishResolutionChange() { |
1702 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 1833 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
1703 DCHECK_EQ(decoder_state_, kChangingResolution); | 1834 DCHECK_EQ(decoder_state_, kChangingResolution); |
1704 DVLOGF(3); | 1835 DVLOGF(3); |
1705 | 1836 |
1706 if (decoder_state_ == kError) { | 1837 if (decoder_state_ == kError) { |
1707 DVLOGF(2) << "early out: kError state"; | 1838 DVLOGF(2) << "early out: kError state"; |
1708 return; | 1839 return; |
1709 } | 1840 } |
1710 | 1841 |
1842 DestroyOutputBuffers(); | |
1843 | |
1711 struct v4l2_format format; | 1844 struct v4l2_format format; |
1712 bool again; | 1845 bool again; |
1713 gfx::Size visible_size; | 1846 gfx::Size visible_size; |
1714 bool ret = GetFormatInfo(&format, &visible_size, &again); | 1847 bool ret = GetFormatInfo(&format, &visible_size, &again); |
1715 if (!ret || again) { | 1848 if (!ret || again) { |
1716 LOGF(ERROR) << "Couldn't get format information after resolution change"; | 1849 LOGF(ERROR) << "Couldn't get format information after resolution change"; |
1717 NOTIFY_ERROR(PLATFORM_FAILURE); | 1850 NOTIFY_ERROR(PLATFORM_FAILURE); |
1718 return; | 1851 return; |
1719 } | 1852 } |
1720 | 1853 |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1996 LOGF(ERROR) << "Can't find a usable input format from image processor"; | 2129 LOGF(ERROR) << "Can't find a usable input format from image processor"; |
1997 return false; | 2130 return false; |
1998 } | 2131 } |
1999 egl_image_format_fourcc_ = FindImageProcessorOutputFormat(); | 2132 egl_image_format_fourcc_ = FindImageProcessorOutputFormat(); |
2000 if (egl_image_format_fourcc_ == 0) { | 2133 if (egl_image_format_fourcc_ == 0) { |
2001 LOGF(ERROR) << "Can't find a usable output format from image processor"; | 2134 LOGF(ERROR) << "Can't find a usable output format from image processor"; |
2002 return false; | 2135 return false; |
2003 } | 2136 } |
2004 egl_image_device_ = image_processor_device_; | 2137 egl_image_device_ = image_processor_device_; |
2005 } else { | 2138 } else { |
2139 if (output_mode_ == Config::OutputMode::IMPORT) { | |
2140 LOGF(ERROR) << "Import mode is unsupported without image processor."; | |
2141 return false; | |
2142 } | |
2006 egl_image_format_fourcc_ = output_format_fourcc_; | 2143 egl_image_format_fourcc_ = output_format_fourcc_; |
2007 egl_image_device_ = device_; | 2144 egl_image_device_ = device_; |
2008 } | 2145 } |
2009 DVLOGF(2) << "Output format=" << output_format_fourcc_; | 2146 DVLOGF(2) << "Output format=" << output_format_fourcc_; |
2010 | 2147 |
2011 // Just set the fourcc for output; resolution, etc., will come from the | 2148 // Just set the fourcc for output; resolution, etc., will come from the |
2012 // driver once it extracts it from the stream. | 2149 // driver once it extracts it from the stream. |
2013 memset(&format, 0, sizeof(format)); | 2150 memset(&format, 0, sizeof(format)); |
2014 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 2151 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
2015 format.fmt.pix_mp.pixelformat = output_format_fourcc_; | 2152 format.fmt.pix_mp.pixelformat = output_format_fourcc_; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2062 for (uint32_t processor_output_format : processor_output_formats) { | 2199 for (uint32_t processor_output_format : processor_output_formats) { |
2063 if (device_->CanCreateEGLImageFrom(processor_output_format)) { | 2200 if (device_->CanCreateEGLImageFrom(processor_output_format)) { |
2064 DVLOGF(1) << "Image processor output format=" << processor_output_format; | 2201 DVLOGF(1) << "Image processor output format=" << processor_output_format; |
2065 return processor_output_format; | 2202 return processor_output_format; |
2066 } | 2203 } |
2067 } | 2204 } |
2068 | 2205 |
2069 return 0; | 2206 return 0; |
2070 } | 2207 } |
2071 | 2208 |
2209 void V4L2VideoDecodeAccelerator::CreateImageProcessor() { | |
2210 DVLOGF(3); | |
2211 image_processor_.reset(new V4L2ImageProcessor(image_processor_device_)); | |
2212 v4l2_memory output_memory_type = | |
2213 (output_mode_ == Config::OutputMode::ALLOCATE ? V4L2_MEMORY_MMAP | |
2214 : V4L2_MEMORY_DMABUF); | |
2215 // Unretained is safe because |this| owns image processor and there will be | |
2216 // no callbacks after processor destroys. | |
2217 if (!image_processor_->Initialize( | |
2218 V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc_), | |
2219 V4L2Device::V4L2PixFmtToVideoPixelFormat(egl_image_format_fourcc_), | |
2220 V4L2_MEMORY_DMABUF, output_memory_type, visible_size_, coded_size_, | |
2221 visible_size_, egl_image_size_, output_buffer_map_.size(), | |
2222 base::Bind(&V4L2VideoDecodeAccelerator::ImageProcessorError, | |
2223 base::Unretained(this)))) { | |
2224 LOGF(ERROR) << "Initialize image processor failed"; | |
2225 NOTIFY_ERROR(PLATFORM_FAILURE); | |
2226 return; | |
2227 } | |
2228 DCHECK(image_processor_->output_allocated_size() == egl_image_size_); | |
2229 DVLOGF(3) << "image_processor_->output_allocated_size()=" | |
2230 << image_processor_->output_allocated_size().ToString(); | |
2231 if (image_processor_->input_allocated_size() != coded_size_) { | |
2232 LOGF(ERROR) << "Image processor should be able to take the output coded " | |
2233 << "size of decoder " << coded_size_.ToString() | |
2234 << " without adjusting to " | |
2235 << image_processor_->input_allocated_size().ToString(); | |
2236 NOTIFY_ERROR(PLATFORM_FAILURE); | |
2237 return; | |
2238 } | |
2239 } | |
2240 | |
2241 void V4L2VideoDecodeAccelerator::FrameProcessed(int32_t bitstream_buffer_id, | |
2242 int output_buffer_index) { | |
2243 DVLOGF(3) << "output_buffer_index=" << output_buffer_index | |
2244 << ", bitstream_buffer_id=" << bitstream_buffer_id; | |
2245 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | |
2246 DCHECK_GE(output_buffer_index, 0); | |
2247 DCHECK_LT(output_buffer_index, static_cast<int>(output_buffer_map_.size())); | |
2248 | |
2249 OutputRecord& output_record = output_buffer_map_[output_buffer_index]; | |
2250 DCHECK_EQ(output_record.state, kAtProcessor); | |
2251 if (!image_processor_bitstream_buffer_ids_.empty() && | |
2252 image_processor_bitstream_buffer_ids_.front() == bitstream_buffer_id) { | |
2253 DVLOGF(3) << "picture_id=" << output_record.picture_id; | |
2254 DCHECK_NE(output_record.picture_id, -1); | |
2255 // Send the processed frame to render. | |
2256 output_record.state = kAtClient; | |
2257 decoder_frames_at_client_++; | |
2258 image_processor_bitstream_buffer_ids_.pop(); | |
2259 const Picture picture(output_record.picture_id, bitstream_buffer_id, | |
2260 gfx::Rect(visible_size_), false); | |
2261 pending_picture_ready_.push(PictureRecord(output_record.cleared, picture)); | |
2262 SendPictureReady(); | |
2263 output_record.cleared = true; | |
2264 // Flush or resolution change may be waiting image processor to finish. | |
2265 if (image_processor_bitstream_buffer_ids_.empty()) { | |
2266 NotifyFlushDoneIfNeeded(); | |
2267 if (decoder_state_ == kChangingResolution) | |
2268 StartResolutionChange(); | |
2269 } | |
2270 } else { | |
2271 DVLOGF(2) << "Bitstream buffer id " << bitstream_buffer_id << " not found " | |
2272 << "because of Reset. Drop the buffer"; | |
2273 output_record.state = kFree; | |
2274 free_output_buffers_.push_back(output_buffer_index); | |
2275 // Do not queue the buffer if a resolution change is in progress. The queue | |
2276 // is about to be destroyed anyway. Otherwise, the queue will be started in | |
2277 // Enqueue and REQBUFS(0) will fail. | |
2278 if (decoder_state_ != kChangingResolution) | |
2279 Enqueue(); | |
2280 } | |
2281 } | |
2282 | |
2283 void V4L2VideoDecodeAccelerator::ImageProcessorError() { | |
2284 LOGF(ERROR) << "Image processor error"; | |
2285 NOTIFY_ERROR(PLATFORM_FAILURE); | |
2286 } | |
2287 | |
2072 bool V4L2VideoDecodeAccelerator::CreateOutputBuffers() { | 2288 bool V4L2VideoDecodeAccelerator::CreateOutputBuffers() { |
2073 DVLOGF(3); | 2289 DVLOGF(3); |
2074 DCHECK(decoder_state_ == kInitialized || | 2290 DCHECK(decoder_state_ == kInitialized || |
2075 decoder_state_ == kChangingResolution); | 2291 decoder_state_ == kChangingResolution); |
2076 DCHECK(!output_streamon_); | 2292 DCHECK(!output_streamon_); |
2077 DCHECK(output_buffer_map_.empty()); | 2293 DCHECK(output_buffer_map_.empty()); |
2078 | 2294 |
2079 // Number of output buffers we need. | 2295 // Number of output buffers we need. |
2080 struct v4l2_control ctrl; | 2296 struct v4l2_control ctrl; |
2081 memset(&ctrl, 0, sizeof(ctrl)); | 2297 memset(&ctrl, 0, sizeof(ctrl)); |
2082 ctrl.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE; | 2298 ctrl.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE; |
2083 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_G_CTRL, &ctrl); | 2299 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_G_CTRL, &ctrl); |
2084 output_dpb_size_ = ctrl.value; | 2300 output_dpb_size_ = ctrl.value; |
2085 | 2301 |
2086 // Output format setup in Initialize(). | 2302 // Output format setup in Initialize(). |
2087 | 2303 |
2088 const uint32_t buffer_count = output_dpb_size_ + kDpbOutputBufferExtraCount; | 2304 const uint32_t buffer_count = output_dpb_size_ + kDpbOutputBufferExtraCount; |
2089 DVLOGF(3) << "buffer_count=" << buffer_count | 2305 DVLOGF(3) << "buffer_count=" << buffer_count |
2090 << ", coded_size=" << egl_image_size_.ToString(); | 2306 << ", coded_size=" << egl_image_size_.ToString(); |
2091 | 2307 |
2308 // With ALLOCATE mode the client can sample it as RGB and doesn't need to | |
2309 // know the precise format. | |
2310 VideoPixelFormat pixel_format = | |
2311 (output_mode_ == Config::OutputMode::IMPORT) | |
2312 ? V4L2Device::V4L2PixFmtToVideoPixelFormat(egl_image_format_fourcc_) | |
2313 : PIXEL_FORMAT_UNKNOWN; | |
2314 | |
2092 child_task_runner_->PostTask( | 2315 child_task_runner_->PostTask( |
2093 FROM_HERE, base::Bind(&Client::ProvidePictureBuffers, client_, | 2316 FROM_HERE, base::Bind(&Client::ProvidePictureBuffers, client_, |
2094 buffer_count, PIXEL_FORMAT_UNKNOWN, 1, | 2317 buffer_count, pixel_format, 1, egl_image_size_, |
2095 egl_image_size_, device_->GetTextureTarget())); | 2318 device_->GetTextureTarget())); |
2096 | 2319 |
2097 // Go into kAwaitingPictureBuffers to prevent us from doing any more decoding | 2320 // Go into kAwaitingPictureBuffers to prevent us from doing any more decoding |
2098 // or event handling while we are waiting for AssignPictureBuffers(). Not | 2321 // or event handling while we are waiting for AssignPictureBuffers(). Not |
2099 // having Pictures available would not have prevented us from making decoding | 2322 // having Pictures available would not have prevented us from making decoding |
2100 // progress entirely e.g. in the case of H.264 where we could further decode | 2323 // progress entirely e.g. in the case of H.264 where we could further decode |
2101 // non-slice NALUs and could even get another resolution change before we were | 2324 // non-slice NALUs and could even get another resolution change before we were |
2102 // done with this one. After we get the buffers, we'll go back into kIdle and | 2325 // done with this one. After we get the buffers, we'll go back into kIdle and |
2103 // kick off further event processing, and eventually go back into kDecoding | 2326 // kick off further event processing, and eventually go back into kDecoding |
2104 // once no more events are pending (if any). | 2327 // once no more events are pending (if any). |
2105 decoder_state_ = kAwaitingPictureBuffers; | 2328 decoder_state_ = kAwaitingPictureBuffers; |
(...skipping 18 matching lines...) Expand all Loading... | |
2124 reqbufs.count = 0; | 2347 reqbufs.count = 0; |
2125 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 2348 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
2126 reqbufs.memory = V4L2_MEMORY_MMAP; | 2349 reqbufs.memory = V4L2_MEMORY_MMAP; |
2127 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); | 2350 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); |
2128 | 2351 |
2129 input_buffer_map_.clear(); | 2352 input_buffer_map_.clear(); |
2130 free_input_buffers_.clear(); | 2353 free_input_buffers_.clear(); |
2131 } | 2354 } |
2132 | 2355 |
2133 bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() { | 2356 bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() { |
2357 struct v4l2_requestbuffers reqbufs; | |
2358 memset(&reqbufs, 0, sizeof(reqbufs)); | |
2359 reqbufs.count = 0; | |
2360 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | |
2361 reqbufs.memory = V4L2_MEMORY_MMAP; | |
2362 if (device_->Ioctl(VIDIOC_REQBUFS, &reqbufs) != 0) { | |
2363 PLOGF(ERROR) << "ioctl() failed: VIDIOC_REQBUFS"; | |
2364 NOTIFY_ERROR(PLATFORM_FAILURE); | |
2365 return false; | |
2366 } | |
2367 | |
2368 output_buffer_map_.clear(); | |
2369 while (!free_output_buffers_.empty()) | |
2370 free_output_buffers_.pop_front(); | |
2371 output_buffer_queued_count_ = 0; | |
2372 // The client may still hold some buffers. The texture holds a reference to | |
2373 // the buffer. It is OK to free the buffer and destroy EGLImage here. | |
2374 decoder_frames_at_client_ = 0; | |
2375 return true; | |
2376 } | |
2377 | |
2378 bool V4L2VideoDecodeAccelerator::DestroyEGLImages() { | |
2134 DVLOGF(3); | 2379 DVLOGF(3); |
2135 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 2380 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
2136 DCHECK(!output_streamon_); | 2381 DCHECK(!output_streamon_); |
2137 bool success = true; | 2382 bool success = true; |
2138 | 2383 |
2139 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { | 2384 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
2140 OutputRecord& output_record = output_buffer_map_[i]; | 2385 OutputRecord& output_record = output_buffer_map_[i]; |
2141 | 2386 |
2142 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { | 2387 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { |
2143 if (egl_image_device_->DestroyEGLImage( | 2388 if (egl_image_device_->DestroyEGLImage( |
2144 egl_display_, output_record.egl_image) != EGL_TRUE) { | 2389 egl_display_, output_record.egl_image) != EGL_TRUE) { |
2145 DVLOGF(1) << "DestroyEGLImage failed."; | 2390 DVLOGF(1) << "DestroyEGLImage failed."; |
2146 success = false; | 2391 success = false; |
2147 } | 2392 } |
2148 } | 2393 } |
2149 | 2394 |
2150 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { | 2395 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { |
2151 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { | 2396 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { |
2152 DVLOGF(1) << "eglDestroySyncKHR failed."; | 2397 DVLOGF(1) << "eglDestroySyncKHR failed."; |
2153 success = false; | 2398 success = false; |
2154 } | 2399 } |
2155 } | 2400 } |
2156 | 2401 |
2157 DVLOGF(1) << "dismissing PictureBuffer id=" << output_record.picture_id; | 2402 DVLOGF(1) << "dismissing PictureBuffer id=" << output_record.picture_id; |
2158 child_task_runner_->PostTask( | 2403 child_task_runner_->PostTask( |
2159 FROM_HERE, base::Bind(&Client::DismissPictureBuffer, client_, | 2404 FROM_HERE, base::Bind(&Client::DismissPictureBuffer, client_, |
2160 output_record.picture_id)); | 2405 output_record.picture_id)); |
2161 } | 2406 } |
2162 | 2407 |
2163 struct v4l2_requestbuffers reqbufs; | |
2164 memset(&reqbufs, 0, sizeof(reqbufs)); | |
2165 reqbufs.count = 0; | |
2166 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | |
2167 reqbufs.memory = V4L2_MEMORY_MMAP; | |
2168 if (device_->Ioctl(VIDIOC_REQBUFS, &reqbufs) != 0) { | |
2169 PLOGF(ERROR) << "ioctl() failed: VIDIOC_REQBUFS"; | |
2170 success = false; | |
2171 } | |
2172 | |
2173 output_buffer_map_.clear(); | |
2174 while (!free_output_buffers_.empty()) | |
2175 free_output_buffers_.pop(); | |
2176 output_buffer_queued_count_ = 0; | |
2177 // The client may still hold some buffers. The texture holds a reference to | |
2178 // the buffer. It is OK to free the buffer and destroy EGLImage here. | |
2179 decoder_frames_at_client_ = 0; | |
2180 | |
2181 return success; | 2408 return success; |
2182 } | 2409 } |
2183 | 2410 |
2184 void V4L2VideoDecodeAccelerator::ResolutionChangeDestroyBuffers() { | 2411 void V4L2VideoDecodeAccelerator::ResolutionChangeDestroyBuffers() { |
2185 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 2412 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
2186 DVLOGF(3); | 2413 DVLOGF(3); |
2187 | 2414 |
2188 if (!DestroyOutputBuffers()) { | 2415 if (!DestroyEGLImages()) { |
2189 LOGF(ERROR) << "Failed destroying output buffers."; | 2416 LOGF(ERROR) << "Failed destroying output buffers."; |
2190 NOTIFY_ERROR(PLATFORM_FAILURE); | 2417 NOTIFY_ERROR(PLATFORM_FAILURE); |
2191 return; | 2418 return; |
2192 } | 2419 } |
2193 | 2420 |
2194 // Finish resolution change on decoder thread. | 2421 // Finish resolution change on decoder thread. |
2195 decoder_thread_.task_runner()->PostTask( | 2422 decoder_thread_.task_runner()->PostTask( |
2196 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::FinishResolutionChange, | 2423 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::FinishResolutionChange, |
2197 base::Unretained(this))); | 2424 base::Unretained(this))); |
2198 } | 2425 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2240 } | 2467 } |
2241 | 2468 |
2242 void V4L2VideoDecodeAccelerator::PictureCleared() { | 2469 void V4L2VideoDecodeAccelerator::PictureCleared() { |
2243 DVLOGF(3) << "clearing count=" << picture_clearing_count_; | 2470 DVLOGF(3) << "clearing count=" << picture_clearing_count_; |
2244 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 2471 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
2245 DCHECK_GT(picture_clearing_count_, 0); | 2472 DCHECK_GT(picture_clearing_count_, 0); |
2246 picture_clearing_count_--; | 2473 picture_clearing_count_--; |
2247 SendPictureReady(); | 2474 SendPictureReady(); |
2248 } | 2475 } |
2249 | 2476 |
2250 void V4L2VideoDecodeAccelerator::FrameProcessed(int32_t bitstream_buffer_id, | |
2251 int output_buffer_index) { | |
2252 DVLOGF(3) << "output_buffer_index=" << output_buffer_index | |
2253 << ", bitstream_buffer_id=" << bitstream_buffer_id; | |
2254 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | |
2255 DCHECK_GE(output_buffer_index, 0); | |
2256 DCHECK_LT(output_buffer_index, static_cast<int>(output_buffer_map_.size())); | |
2257 | |
2258 OutputRecord& output_record = output_buffer_map_[output_buffer_index]; | |
2259 DCHECK_EQ(output_record.state, kAtProcessor); | |
2260 if (!image_processor_bitstream_buffer_ids_.empty() && | |
2261 image_processor_bitstream_buffer_ids_.front() == bitstream_buffer_id) { | |
2262 DVLOGF(3) << "picture_id=" << output_record.picture_id; | |
2263 DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR); | |
2264 DCHECK_NE(output_record.picture_id, -1); | |
2265 // Send the processed frame to render. | |
2266 output_record.state = kAtClient; | |
2267 decoder_frames_at_client_++; | |
2268 image_processor_bitstream_buffer_ids_.pop(); | |
2269 const Picture picture(output_record.picture_id, bitstream_buffer_id, | |
2270 gfx::Rect(visible_size_), false); | |
2271 pending_picture_ready_.push(PictureRecord(output_record.cleared, picture)); | |
2272 SendPictureReady(); | |
2273 output_record.cleared = true; | |
2274 // Flush or resolution change may be waiting image processor to finish. | |
2275 if (image_processor_bitstream_buffer_ids_.empty()) { | |
2276 NotifyFlushDoneIfNeeded(); | |
2277 if (decoder_state_ == kChangingResolution) | |
2278 StartResolutionChange(); | |
2279 } | |
2280 } else { | |
2281 DVLOGF(2) << "Bitstream buffer id " << bitstream_buffer_id << " not found " | |
2282 << "because of Reset. Drop the buffer"; | |
2283 output_record.state = kFree; | |
2284 free_output_buffers_.push(output_buffer_index); | |
2285 // Do not queue the buffer if a resolution change is in progress. The queue | |
2286 // is about to be destroyed anyway. Otherwise, the queue will be started in | |
2287 // Enqueue and REQBUFS(0) will fail. | |
2288 if (decoder_state_ != kChangingResolution) | |
2289 Enqueue(); | |
2290 } | |
2291 } | |
2292 | |
2293 void V4L2VideoDecodeAccelerator::ImageProcessorError() { | |
2294 LOGF(ERROR) << "Image processor error"; | |
2295 NOTIFY_ERROR(PLATFORM_FAILURE); | |
2296 } | |
2297 | |
2298 } // namespace media | 2477 } // namespace media |
OLD | NEW |