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

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