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

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