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

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

Issue 1125263005: MJPEG acceleration for V4L2 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: check dqbuf.flags Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <linux/videodev2.h>
6 #include <sys/mman.h>
7
8 #include "base/bind.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "content/common/gpu/media/v4l2_jpeg_decode_accelerator.h"
11
12 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_name) \
13 do { \
14 if (device_->Ioctl(type, arg) != 0) { \
15 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << type_name; \
16 PostNotifyError(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId, \
17 media::JpegDecodeAccelerator::PLATFORM_FAILURE); \
18 return value; \
19 } \
20 } while (0)
21
22 #define IOCTL_OR_ERROR_RETURN(type, arg) \
23 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, ((void)0), #type)
24
25 #define IOCTL_OR_ERROR_RETURN_FALSE(type, arg) \
26 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, false, #type)
27
28 #define IOCTL_OR_LOG_ERROR(type, arg) \
29 do { \
30 if (device_->Ioctl(type, arg) != 0) { \
31 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
32 PostNotifyError(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId, \
33 media::JpegDecodeAccelerator::PLATFORM_FAILURE); \
34 } \
35 } while (0)
36
37 namespace content {
38
39 V4L2JpegDecodeAccelerator::BufferRecord::BufferRecord()
40 : address(nullptr), length(0), at_device(false) {
41 }
42
43 V4L2JpegDecodeAccelerator::BufferRecord::~BufferRecord() {
44 }
45
46 V4L2JpegDecodeAccelerator::JobRecord::JobRecord(
47 media::BitstreamBuffer bitstream_buffer,
48 scoped_refptr<media::VideoFrame> video_frame)
49 : bitstream_buffer(bitstream_buffer), out_frame(video_frame) {
50 }
51
52 V4L2JpegDecodeAccelerator::JobRecord::~JobRecord() {
53 }
54
55 V4L2JpegDecodeAccelerator::V4L2JpegDecodeAccelerator(
56 const scoped_refptr<V4L2Device>& device,
57 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
58 : recreate_input_buffers_pending_(false),
59 recreate_output_buffers_pending_(false),
60 child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
61 io_task_runner_(io_task_runner),
62 client_(nullptr),
63 device_(device),
64 decoder_thread_("V4L2JpegDecodeThread"),
65 device_poll_thread_("V4L2JpegDecodeDevicePollThread"),
66 input_streamon_(false),
67 output_streamon_(false),
68 weak_factory_(this) {
69 }
70
71 V4L2JpegDecodeAccelerator::~V4L2JpegDecodeAccelerator() {
72 DCHECK(child_task_runner_->BelongsToCurrentThread());
73
74 if (decoder_thread_.IsRunning()) {
75 decoder_task_runner_->PostTask(
76 FROM_HERE, base::Bind(&V4L2JpegDecodeAccelerator::DestroyTask,
77 base::Unretained(this)));
78 decoder_thread_.Stop();
79 }
80 weak_factory_.InvalidateWeakPtrs();
81 DCHECK(!device_poll_thread_.IsRunning());
82 }
83
84 void V4L2JpegDecodeAccelerator::DestroyTask() {
85 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
86 while (!input_jobs_.empty())
87 input_jobs_.pop();
88 while (!running_jobs_.empty())
89 running_jobs_.pop();
90
91 // Stop streaming and the device_poll_thread_.
92 StopDevicePoll();
93
94 ResetQueues();
95 DestroyInputBuffers();
96 DestroyOutputBuffers();
97 }
98
99 void V4L2JpegDecodeAccelerator::NotifyError(int32_t bitstream_buffer_id,
100 Error error) {
101 DCHECK(child_task_runner_->BelongsToCurrentThread());
102 LOG(ERROR) << "Notifying of error " << error << " for buffer id "
103 << bitstream_buffer_id;
104 client_->NotifyError(bitstream_buffer_id, error);
105 }
106
107 void V4L2JpegDecodeAccelerator::PostNotifyError(
108 int32_t bitstream_buffer_id,
109 Error error) {
110 child_task_runner_->PostTask(
111 FROM_HERE,
112 base::Bind(&V4L2JpegDecodeAccelerator::NotifyError,
113 weak_factory_.GetWeakPtr(), bitstream_buffer_id, error));
piman 2015/07/08 00:18:07 I'm don't think it is generally safe to call GetWe
henryhsu 2015/07/08 03:10:31 Done.
114 }
115
116 bool V4L2JpegDecodeAccelerator::Initialize(Client* client) {
117 DCHECK(child_task_runner_->BelongsToCurrentThread());
118
119 // Capabilities check.
120 struct v4l2_capability caps;
121 const __u32 kCapsRequired = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
122 memset(&caps, 0, sizeof(caps));
123 if (device_->Ioctl(VIDIOC_QUERYCAP, &caps) != 0) {
124 PLOG(ERROR) << __func__ << "(): ioctl() failed: VIDIOC_QUERYCAP";
125 return false;
126 }
127 if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
128 LOG(ERROR) << "Initialize(): VIDIOC_QUERYCAP, caps check failed: 0x"
129 << std::hex << caps.capabilities;
130 return false;
131 }
132
133 if (!decoder_thread_.Start()) {
134 LOG(ERROR) << "Initialize(): decoder thread failed to start";
135 return false;
136 }
137 client_ = client;
138 decoder_task_runner_ = decoder_thread_.task_runner();
139
140 decoder_task_runner_->PostTask(
141 FROM_HERE, base::Bind(&V4L2JpegDecodeAccelerator::StartDevicePoll,
142 base::Unretained(this)));
143
144 DVLOG(1) << "V4L2JpegDecodeAccelerator initialized.";
145 return true;
146 }
147
148 void V4L2JpegDecodeAccelerator::Decode(
149 const media::BitstreamBuffer& bitstream_buffer,
150 const scoped_refptr<media::VideoFrame>& video_frame) {
151 DVLOG(1) << "Decode(): input_id=" << bitstream_buffer.id()
152 << ", size=" << bitstream_buffer.size();
153 DCHECK(io_task_runner_->BelongsToCurrentThread());
154
155 if (video_frame->format() != media::VideoFrame::I420) {
156 PostNotifyError(bitstream_buffer.id(), UNSUPPORTED_JPEG);
157 return;
158 }
159
160 scoped_ptr<JobRecord> job_record(
161 new JobRecord(bitstream_buffer, video_frame));
162
163 decoder_task_runner_->PostTask(
164 FROM_HERE, base::Bind(&V4L2JpegDecodeAccelerator::DecodeTask,
165 base::Unretained(this), base::Passed(&job_record)));
166 }
167
168 void V4L2JpegDecodeAccelerator::DecodeTask(scoped_ptr<JobRecord> job_record) {
169 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
170 job_record->shm.reset(
171 new base::SharedMemory(job_record->bitstream_buffer.handle(), true));
172 if (!job_record->shm->Map(job_record->bitstream_buffer.size())) {
173 PLOG(ERROR) << "DecodeTask(): could not map bitstream_buffer";
174 PostNotifyError(job_record->bitstream_buffer.id(), UNREADABLE_INPUT);
175 return;
176 }
177 input_jobs_.push(make_linked_ptr(job_record.release()));
178
179 ServiceDeviceTask();
180 }
181
182 size_t V4L2JpegDecodeAccelerator::InputBufferQueuedCount() {
183 return input_buffer_map_.size() - free_input_buffers_.size();
184 }
185
186 size_t V4L2JpegDecodeAccelerator::OutputBufferQueuedCount() {
187 return output_buffer_map_.size() - free_output_buffers_.size();
188 }
189
190 bool V4L2JpegDecodeAccelerator::ShouldRecreateInputBuffers() {
191 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
192 if (input_jobs_.empty())
193 return false;
194
195 linked_ptr<JobRecord> job_record = input_jobs_.front();
196 // Check input buffer size is enough
197 return (input_buffer_map_.empty() ||
198 job_record->bitstream_buffer.size() > input_buffer_map_.front().length);
199 }
200
201 bool V4L2JpegDecodeAccelerator::ShouldRecreateOutputBuffers() {
202 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
203 if (input_jobs_.empty())
204 return false;
205
206 linked_ptr<JobRecord> job_record = input_jobs_.front();
207 // Check image resolution is the same as previous.
208 if (job_record->out_frame->coded_size() != image_coded_size_) {
209 size_t frame_size = media::VideoFrame::AllocationSize(
210 job_record->out_frame->format(), job_record->out_frame->coded_size());
211 if (output_buffer_map_.empty() ||
212 frame_size > output_buffer_map_.front().length) {
213 return true;
214 }
215 }
216 return false;
217 }
218
219 bool V4L2JpegDecodeAccelerator::CreateBuffersIfNecessary() {
220 DVLOG(3) << __func__;
221 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
222
223 recreate_input_buffers_pending_ = ShouldRecreateInputBuffers();
224 recreate_output_buffers_pending_ = ShouldRecreateOutputBuffers();
225 if (!recreate_input_buffers_pending_ && !recreate_output_buffers_pending_)
226 return true;
227
228 // If input queue is not empty, we should wait until pending frames finish.
229 if (InputBufferQueuedCount())
230 return true;
231
232 if (input_streamon_ || output_streamon_) {
233 ResetQueues();
234 if (recreate_input_buffers_pending_)
235 DestroyInputBuffers();
236
237 if (recreate_output_buffers_pending_)
238 DestroyOutputBuffers();
239 }
240
241 if (recreate_input_buffers_pending_ && !CreateInputBuffers()) {
242 LOG(ERROR) << "Create input buffers failed.";
243 return false;
244 }
245 if (recreate_output_buffers_pending_ && !CreateOutputBuffers()) {
246 LOG(ERROR) << "Create output buffers failed.";
247 return false;
248 }
249
250 return true;
251 }
252
253 bool V4L2JpegDecodeAccelerator::CreateInputBuffers() {
254 DVLOG(3) << __func__;
255 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
256 DCHECK(!input_streamon_);
257 DCHECK(!input_jobs_.empty());
258 linked_ptr<JobRecord> job_record = input_jobs_.front();
259 // Reserve twice size to avoid recreating input buffer frequently.
260 size_t reserve_size = job_record->bitstream_buffer.size() * 2;
261
262 struct v4l2_format format;
263 memset(&format, 0, sizeof(format));
264 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
265 format.fmt.pix.width = job_record->out_frame->coded_size().width();
266 format.fmt.pix.height = job_record->out_frame->coded_size().height();
267 format.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
268 format.fmt.pix.sizeimage = reserve_size;
269 format.fmt.pix.field = V4L2_FIELD_ANY;
270 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format);
271
272 struct v4l2_requestbuffers reqbufs;
273 memset(&reqbufs, 0, sizeof(reqbufs));
274 reqbufs.count = kBufferCount;
275 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
276 reqbufs.memory = V4L2_MEMORY_MMAP;
277 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs);
278
279 DCHECK(input_buffer_map_.empty());
280 input_buffer_map_.resize(reqbufs.count);
281
282 for (size_t i = 0; i < input_buffer_map_.size(); ++i) {
283 free_input_buffers_.push_back(i);
284
285 struct v4l2_buffer buffer;
286 memset(&buffer, 0, sizeof(buffer));
287 buffer.index = i;
288 buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
289 buffer.memory = V4L2_MEMORY_MMAP;
290 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYBUF, &buffer);
291 void* address = device_->Mmap(NULL, buffer.length, PROT_READ | PROT_WRITE,
292 MAP_SHARED, buffer.m.offset);
293 if (address == MAP_FAILED) {
294 PLOG(ERROR) << "CreateInputBuffers(): mmap() failed";
295 PostNotifyError(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId,
296 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
297 return false;
298 }
299 input_buffer_map_[i].address = address;
300 input_buffer_map_[i].length = buffer.length;
301 }
302 recreate_input_buffers_pending_ = false;
303
304 return true;
305 }
306
307 bool V4L2JpegDecodeAccelerator::CreateOutputBuffers() {
308 DVLOG(3) << __func__;
309 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
310 DCHECK(!output_streamon_);
311 DCHECK(!input_jobs_.empty());
312 linked_ptr<JobRecord> job_record = input_jobs_.front();
313
314 size_t frame_size = media::VideoFrame::AllocationSize(
315 media::VideoFrame::I420, job_record->out_frame->coded_size());
316 struct v4l2_format format;
317 memset(&format, 0, sizeof(format));
318 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
319 format.fmt.pix.width = job_record->out_frame->coded_size().width();
320 format.fmt.pix.height = job_record->out_frame->coded_size().height();
321 format.fmt.pix.sizeimage = frame_size;
322 format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
323 format.fmt.pix.field = V4L2_FIELD_ANY;
324 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format);
325
326 struct v4l2_requestbuffers reqbufs;
327 memset(&reqbufs, 0, sizeof(reqbufs));
328 reqbufs.count = kBufferCount;
329 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
330 reqbufs.memory = V4L2_MEMORY_MMAP;
331 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs);
332
333 DCHECK(output_buffer_map_.empty());
334 output_buffer_map_.resize(reqbufs.count);
335
336 for (size_t i = 0; i < output_buffer_map_.size(); ++i) {
337 free_output_buffers_.push_back(i);
338
339 struct v4l2_buffer buffer;
340 memset(&buffer, 0, sizeof(buffer));
341 buffer.index = i;
342 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
343 buffer.memory = V4L2_MEMORY_MMAP;
344 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYBUF, &buffer);
345 void* address = device_->Mmap(NULL, buffer.length, PROT_READ | PROT_WRITE,
346 MAP_SHARED, buffer.m.offset);
347 if (address == MAP_FAILED) {
348 PLOG(ERROR) << "CreateOutputBuffers(): mmap() failed";
349 PostNotifyError(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId,
350 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
351 return false;
352 }
353 output_buffer_map_[i].address = address;
354 output_buffer_map_[i].length = buffer.length;
355 }
356 image_coded_size_ = job_record->out_frame->coded_size();
357 recreate_output_buffers_pending_ = false;
358
359 return true;
360 }
361
362 void V4L2JpegDecodeAccelerator::DestroyInputBuffers() {
363 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
364 DCHECK(!input_streamon_);
365
366 for (size_t buf = 0; buf < input_buffer_map_.size(); ++buf) {
367 BufferRecord& input_record = input_buffer_map_[buf];
368 device_->Munmap(input_record.address, input_record.length);
369 }
370
371 struct v4l2_requestbuffers reqbufs;
372 memset(&reqbufs, 0, sizeof(reqbufs));
373 reqbufs.count = 0;
374 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
375 reqbufs.memory = V4L2_MEMORY_MMAP;
376 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs);
377
378 input_buffer_map_.clear();
379 free_input_buffers_.clear();
380 }
381
382 void V4L2JpegDecodeAccelerator::DestroyOutputBuffers() {
383 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
384 DCHECK(!output_streamon_);
385
386 for (size_t buf = 0; buf < output_buffer_map_.size(); ++buf) {
387 BufferRecord& output_record = output_buffer_map_[buf];
388 device_->Munmap(output_record.address, output_record.length);
389 }
390
391 struct v4l2_requestbuffers reqbufs;
392 memset(&reqbufs, 0, sizeof(reqbufs));
393 reqbufs.count = 0;
394 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
395 reqbufs.memory = V4L2_MEMORY_MMAP;
396 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs);
397
398 output_buffer_map_.clear();
399 free_output_buffers_.clear();
400 }
401
402 void V4L2JpegDecodeAccelerator::DevicePollTask() {
403 DCHECK(device_poll_task_runner_->BelongsToCurrentThread());
404
405 bool event_pending;
406 if (!device_->Poll(true, &event_pending)) {
407 PLOG(ERROR) << "DevicePollTask(): Poll device error.";
408 PostNotifyError(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId,
409 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
410 return;
411 }
412
413 // All processing should happen on ServiceDeviceTask(), since we shouldn't
414 // touch decoder state from this thread.
415 decoder_task_runner_->PostTask(
416 FROM_HERE, base::Bind(&V4L2JpegDecodeAccelerator::ServiceDeviceTask,
417 base::Unretained(this)));
418 }
419
420 void V4L2JpegDecodeAccelerator::ServiceDeviceTask() {
421 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
422 // If DestroyTask() shuts |device_poll_thread_| down, we should early-out.
423 if (!device_poll_thread_.IsRunning())
424 return;
425
426 if (InputBufferQueuedCount() > 0 || OutputBufferQueuedCount() > 0)
wuchengli 2015/07/06 09:39:45 Change to !running_jobs_.empty()?
henryhsu 2015/07/07 10:04:47 Done.
427 Dequeue();
428 if (!CreateBuffersIfNecessary())
429 return;
430
431 EnqueueInput();
432 EnqueueOutput();
433
434 if (!running_jobs_.empty() &&
435 (InputBufferQueuedCount() > 0 || OutputBufferQueuedCount() > 0)) {
wuchengli 2015/07/06 09:39:45 Remove this because !running_jobs_.empty() is enou
henryhsu 2015/07/07 10:04:47 Done.
436 device_poll_task_runner_->PostTask(
437 FROM_HERE, base::Bind(&V4L2JpegDecodeAccelerator::DevicePollTask,
438 base::Unretained(this)));
439 }
440
441 DVLOG(2) << __func__ << ": buffer counts: INPUT["
442 << input_jobs_.size() << "] => DEVICE["
443 << free_input_buffers_.size() << "/"
444 << input_buffer_map_.size() << "->"
445 << free_output_buffers_.size() << "/"
446 << output_buffer_map_.size() << "]";
447 }
448
449 void V4L2JpegDecodeAccelerator::EnqueueInput() {
450 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
451 while (!input_jobs_.empty() && !free_input_buffers_.empty()) {
452 // Do not enqueue input record when input/output buffers are required to
453 // re-create until all pending frames are handled by device.
454 if (recreate_input_buffers_pending_ || recreate_output_buffers_pending_)
455 break;
456 if (!EnqueueInputRecord())
457 return;
458 recreate_input_buffers_pending_ = ShouldRecreateInputBuffers();
459 recreate_output_buffers_pending_ = ShouldRecreateOutputBuffers();
460 }
461 // Check here because we cannot STREAMON before QBUF in earlier kernel.
462 if (!input_streamon_ && InputBufferQueuedCount()) {
463 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
464 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON, &type);
465 input_streamon_ = true;
466 }
467 }
468
469 void V4L2JpegDecodeAccelerator::EnqueueOutput() {
470 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
471 // Output record can be enqueued because the output coded sizes of the frames
472 // currently in the pipeline are all the same.
473 while (running_jobs_.size() > OutputBufferQueuedCount() &&
474 !free_output_buffers_.empty()) {
475 if (!EnqueueOutputRecord())
476 return;
477 }
478 // Check here because we cannot STREAMON before QBUF in earlier kernel.
479 if (!output_streamon_ && OutputBufferQueuedCount()) {
480 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
481 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON, &type);
482 output_streamon_ = true;
483 }
484 }
485
486 void V4L2JpegDecodeAccelerator::Dequeue() {
487 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
488
489 // Dequeue completed input (VIDEO_OUTPUT) buffers,
490 // and recycle to the free list.
491 struct v4l2_buffer dqbuf;
492 while (InputBufferQueuedCount() > 0) {
493 DCHECK(input_streamon_);
494 memset(&dqbuf, 0, sizeof(dqbuf));
495 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
496 dqbuf.memory = V4L2_MEMORY_MMAP;
497 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) {
498 if (errno == EAGAIN) {
499 // EAGAIN if we're just out of buffers to dequeue.
500 break;
501 }
502 PLOG(ERROR) << "ioctl() failed: input buffer VIDIOC_DQBUF failed.";
503 PostNotifyError(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId,
504 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
505 return;
506 }
507 BufferRecord& input_record = input_buffer_map_[dqbuf.index];
508 DCHECK(input_record.at_device);
509 input_record.at_device = false;
510 free_input_buffers_.push_back(dqbuf.index);
511
512 if (dqbuf.flags & V4L2_BUF_FLAG_ERROR) {
wuchengli 2015/07/06 09:39:45 Please check with Pawel if both input and output b
henryhsu 2015/07/08 03:10:31 As discussed, we check both input and output error
513 DVLOG(1) << "Dequeue input buffer error.";
514 PostNotifyError(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId,
515 media::JpegDecodeAccelerator::UNSUPPORTED_JPEG);
516 running_jobs_.pop();
wuchengli 2015/07/06 09:39:45 As discussed, check with Pawel if we can still deq
517 }
518 }
519
520 // Dequeue completed output (VIDEO_CAPTURE) buffers, recycle to the free list.
521 // Return the finished buffer to the client via the job ready callback.
522 while (OutputBufferQueuedCount() > 0) {
wuchengli 2015/07/06 09:39:45 Change to while(!running_jobs_.empty()) and DCHECK
henryhsu 2015/07/07 10:04:47 Done.
523 DCHECK(output_streamon_);
524 memset(&dqbuf, 0, sizeof(dqbuf));
525 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
526 dqbuf.memory = V4L2_MEMORY_MMAP;
527 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) {
528 if (errno == EAGAIN) {
529 // EAGAIN if we're just out of buffers to dequeue.
530 break;
531 }
532 PLOG(ERROR) << "ioctl() failed: output buffer VIDIOC_DQBUF failed.";
533 PostNotifyError(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId,
534 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
535 return;
536 }
537 BufferRecord& output_record = output_buffer_map_[dqbuf.index];
538 DCHECK(output_record.at_device);
539 output_record.at_device = false;
540 free_output_buffers_.push_back(dqbuf.index);
541
542 // Jobs are always processed in FIFO order.
543 DCHECK(!running_jobs_.empty());
544 linked_ptr<JobRecord> job_record = running_jobs_.front();
545 running_jobs_.pop();
546
547 if (dqbuf.flags & V4L2_BUF_FLAG_ERROR) {
548 DVLOG(1) << "Dequeue output buffer error.";
549 PostNotifyError(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId,
550 media::JpegDecodeAccelerator::UNSUPPORTED_JPEG);
551 } else {
552 memcpy(job_record->out_frame->data(media::VideoFrame::kYPlane),
553 output_record.address, output_record.length);
554
555 DVLOG(3) << "Decoding finished, returning bitstream buffer, id="
556 << job_record->bitstream_buffer.id();
557
558 client_->VideoFrameReady(job_record->bitstream_buffer.id());
piman 2015/07/08 00:18:07 You can only call into client_ on the child thread
henryhsu 2015/07/08 03:10:31 Done.
559 }
560 }
561 }
562
563 bool V4L2JpegDecodeAccelerator::EnqueueInputRecord() {
564 DCHECK(!input_jobs_.empty());
565 DCHECK(!free_input_buffers_.empty());
566
567 // Enqueue an input (VIDEO_OUTPUT) buffer for an input video frame.
568 linked_ptr<JobRecord> job_record = input_jobs_.front();
569 input_jobs_.pop();
570 const int index = free_input_buffers_.back();
571 BufferRecord& input_record = input_buffer_map_[index];
572 DCHECK(!input_record.at_device);
573
574 struct v4l2_buffer qbuf;
575 memset(&qbuf, 0, sizeof(qbuf));
576 memcpy(input_record.address, job_record->shm->memory(),
577 job_record->bitstream_buffer.size());
578 qbuf.index = index;
579 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
580 qbuf.memory = V4L2_MEMORY_MMAP;
581 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf);
582 input_record.at_device = true;
583 running_jobs_.push(job_record);
584 free_input_buffers_.pop_back();
585
586 DVLOG(3) << __func__ << ": enqueued frame id="
587 << job_record->bitstream_buffer.id() << " to device.";
588 return true;
589 }
590
591 bool V4L2JpegDecodeAccelerator::EnqueueOutputRecord() {
592 DCHECK(!free_output_buffers_.empty());
593
594 // Enqueue an output (VIDEO_CAPTURE) buffer.
595 const int index = free_output_buffers_.back();
596 BufferRecord& output_record = output_buffer_map_[index];
597 DCHECK(!output_record.at_device);
598 struct v4l2_buffer qbuf;
599 memset(&qbuf, 0, sizeof(qbuf));
600 qbuf.index = index;
601 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
602 qbuf.memory = V4L2_MEMORY_MMAP;
603 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf);
604 output_record.at_device = true;
605 free_output_buffers_.pop_back();
606 return true;
607 }
608
609 void V4L2JpegDecodeAccelerator::ResetQueues() {
610 if (input_streamon_) {
611 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
612 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMOFF, &type);
613 input_streamon_ = false;
614 }
615
616 if (output_streamon_) {
617 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
618 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMOFF, &type);
619 output_streamon_ = false;
620 }
621
622 free_input_buffers_.clear();
623 for (size_t i = 0; i < input_buffer_map_.size(); ++i) {
624 BufferRecord& input_record = input_buffer_map_[i];
625 input_record.at_device = false;
626 free_input_buffers_.push_back(i);
627 }
628
629 free_output_buffers_.clear();
630 for (size_t i = 0; i < output_buffer_map_.size(); ++i) {
631 BufferRecord& output_record = output_buffer_map_[i];
632 output_record.at_device = false;
633 free_output_buffers_.push_back(i);
634 }
635 }
636
637 void V4L2JpegDecodeAccelerator::StartDevicePoll() {
638 DVLOG(3) << __func__ << ": starting device poll";
639 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
640 DCHECK(!device_poll_thread_.IsRunning());
641
642 if (!device_poll_thread_.Start()) {
643 LOG(ERROR) << "StartDevicePoll(): Device thread failed to start";
644 PostNotifyError(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId,
645 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
646 return;
647 }
648 device_poll_task_runner_ = device_poll_thread_.task_runner();
649 }
650
651 bool V4L2JpegDecodeAccelerator::StopDevicePoll() {
652 DVLOG(3) << __func__ << ": stopping device poll";
653 // Signal the DevicePollTask() to stop, and stop the device poll thread.
654 if (!device_->SetDevicePollInterrupt()) {
655 LOG(ERROR) << "StopDevicePoll(): SetDevicePollInterrupt failed.";
656 PostNotifyError(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId,
657 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
658 return false;
659 }
660
661 device_poll_thread_.Stop();
662
663 // Clear the interrupt now, to be sure.
664 if (!device_->ClearDevicePollInterrupt())
665 return false;
666
667 return true;
668 }
669
670 } // namespace content
OLDNEW
« no previous file with comments | « content/common/gpu/media/v4l2_jpeg_decode_accelerator.h ('k') | content/common/sandbox_linux/bpf_gpu_policy_linux.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698