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

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: ioctl return -1 id 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 DestroyInputBuffers();
95 DestroyOutputBuffers();
96 }
97
98 void V4L2JpegDecodeAccelerator::NotifyError(int32_t bitstream_buffer_id,
99 Error error) {
100 DCHECK(child_task_runner_->BelongsToCurrentThread());
101 LOG(ERROR) << "Notifying of error " << error << " for buffer id "
102 << bitstream_buffer_id;
103 client_->NotifyError(bitstream_buffer_id, error);
104 }
105
106 void V4L2JpegDecodeAccelerator::PostNotifyError(
107 int32_t bitstream_buffer_id,
108 Error error) {
109 child_task_runner_->PostTask(
110 FROM_HERE,
111 base::Bind(&V4L2JpegDecodeAccelerator::NotifyError,
112 weak_factory_.GetWeakPtr(), bitstream_buffer_id, error));
113 }
114
115 bool V4L2JpegDecodeAccelerator::Initialize(Client* client) {
116 DCHECK(child_task_runner_->BelongsToCurrentThread());
117
118 // Capabilities check.
119 struct v4l2_capability caps;
120 const __u32 kCapsRequired = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
121 memset(&caps, 0, sizeof(caps));
122 if (device_->Ioctl(VIDIOC_QUERYCAP, &caps) != 0) {
123 PLOG(ERROR) << __func__ << "(): ioctl() failed: VIDIOC_QUERYCAP";
124 return false;
125 }
126 if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
127 LOG(ERROR) << "Initialize(): VIDIOC_QUERYCAP, caps check failed: 0x"
128 << std::hex << caps.capabilities;
129 return false;
130 }
131
132 if (!decoder_thread_.Start()) {
133 LOG(ERROR) << "Initialize(): decoder thread failed to start";
134 return false;
135 }
136 client_ = client;
137 decoder_task_runner_ = decoder_thread_.task_runner();
138
139 decoder_task_runner_->PostTask(
140 FROM_HERE, base::Bind(&V4L2JpegDecodeAccelerator::StartDevicePoll,
141 base::Unretained(this)));
142
143 DVLOG(1) << "V4L2JpegDecodeAccelerator initialized.";
144 return true;
145 }
146
147 void V4L2JpegDecodeAccelerator::Decode(
148 const media::BitstreamBuffer& bitstream_buffer,
149 const scoped_refptr<media::VideoFrame>& video_frame) {
150 DVLOG(1) << "Decode(): input_id=" << bitstream_buffer.id()
151 << ", size=" << bitstream_buffer.size();
152 DCHECK(io_task_runner_->BelongsToCurrentThread());
153
154 if (video_frame->format() != media::VideoFrame::I420) {
155 PostNotifyError(bitstream_buffer.id(), UNSUPPORTED_JPEG);
156 return;
157 }
158
159 scoped_ptr<JobRecord> job_record(
160 new JobRecord(bitstream_buffer, video_frame));
161
162 decoder_task_runner_->PostTask(
163 FROM_HERE, base::Bind(&V4L2JpegDecodeAccelerator::DecodeTask,
164 base::Unretained(this), base::Passed(&job_record)));
165 }
166
167 void V4L2JpegDecodeAccelerator::DecodeTask(scoped_ptr<JobRecord> job_record) {
168 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
169 job_record->shm.reset(
170 new base::SharedMemory(job_record->bitstream_buffer.handle(), true));
171 if (!job_record->shm->Map(job_record->bitstream_buffer.size())) {
172 PLOG(ERROR) << "DecodeTask(): could not map bitstream_buffer";
173 PostNotifyError(job_record->bitstream_buffer.id(), UNREADABLE_INPUT);
174 return;
175 }
176 input_jobs_.push(make_linked_ptr(job_record.release()));
177
178 ServiceDeviceTask();
179 }
180
181 size_t V4L2JpegDecodeAccelerator::InputBufferQueuedCount() {
182 return input_buffer_map_.size() - free_input_buffers_.size();
183 }
184
185 size_t V4L2JpegDecodeAccelerator::OutputBufferQueuedCount() {
186 return output_buffer_map_.size() - free_output_buffers_.size();
187 }
188
189 bool V4L2JpegDecodeAccelerator::ShouldRecreateInputBuffers() {
190 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
191 if (input_jobs_.empty())
192 return false;
193
194 linked_ptr<JobRecord> job_record = input_jobs_.front();
195 // Check input buffer size is enough
196 return (input_buffer_map_.empty() ||
197 job_record->bitstream_buffer.size() > input_buffer_map_.front().length);
198 }
199
200 bool V4L2JpegDecodeAccelerator::ShouldRecreateOutputBuffers() {
201 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
202 if (input_jobs_.empty())
203 return false;
204
205 linked_ptr<JobRecord> job_record = input_jobs_.front();
206 // Check image resolution is the same as previous.
207 if (job_record->out_frame->coded_size() != image_coded_size_) {
208 size_t frame_size = media::VideoFrame::AllocationSize(
209 job_record->out_frame->format(), job_record->out_frame->coded_size());
210 if (output_buffer_map_.empty() ||
211 frame_size > output_buffer_map_.front().length) {
212 return true;
213 }
214 }
215 return false;
216 }
217
218 bool V4L2JpegDecodeAccelerator::CreateBuffersIfNecessary() {
219 DVLOG(3) << __func__;
220 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
221
222 recreate_input_buffers_pending_ = ShouldRecreateInputBuffers();
223 recreate_output_buffers_pending_ = ShouldRecreateOutputBuffers();
224 if (!recreate_input_buffers_pending_ && !recreate_output_buffers_pending_)
225 return true;
226
227 // If input queue or output queue are not empty, we should wait until pending
228 // frames finish.
229 if (InputBufferQueuedCount() || OutputBufferQueuedCount())
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)
427 Dequeue();
428 if (!CreateBuffersIfNecessary()) return;
429
430 // Do not enqueue input record when input/output buffers are required to
431 // re-create until all pending frames are handled by device.
432 // Output record can be enqueued because the output coded sizes of the frames
433 // currently in the pipeline are all the same.
434 if (!recreate_input_buffers_pending_ && !recreate_output_buffers_pending_)
435 EnqueueInput();
436 EnqueueOutput();
437
438 if (InputBufferQueuedCount() > 0 || OutputBufferQueuedCount() > 0) {
439 device_poll_task_runner_->PostTask(
440 FROM_HERE, base::Bind(&V4L2JpegDecodeAccelerator::DevicePollTask,
441 base::Unretained(this)));
442 }
443
444 DVLOG(2) << __func__ << ": buffer counts: INPUT["
445 << input_jobs_.size() << "] => DEVICE["
446 << free_input_buffers_.size() << "/"
447 << input_buffer_map_.size() << "->"
448 << free_output_buffers_.size() << "/"
449 << output_buffer_map_.size() << "]";
450 }
451
452 void V4L2JpegDecodeAccelerator::EnqueueInput() {
453 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
454 if (!input_jobs_.empty() && !free_input_buffers_.empty() &&
wuchengli 2015/07/01 11:46:47 We should still allow to queue multiple input if t
henryhsu 2015/07/02 12:05:27 Done.
455 !EnqueueInputRecord()) {
456 return;
457 }
458 // Check here because we cannot STREAMON before QBUF in earlier kernel.
459 if (!input_streamon_ && InputBufferQueuedCount()) {
460 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
461 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON, &type);
462 input_streamon_ = true;
463 }
464 }
465
466 void V4L2JpegDecodeAccelerator::EnqueueOutput() {
467 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
468 if (running_jobs_.size() > OutputBufferQueuedCount() &&
wuchengli 2015/07/01 11:46:47 We should still allow multiple outputs to be queue
henryhsu 2015/07/02 12:05:27 Done.
469 !free_output_buffers_.empty() && !EnqueueOutputRecord()) {
470 return;
471 }
472 // Check here because we cannot STREAMON before QBUF in earlier kernel.
473 if (!output_streamon_ && OutputBufferQueuedCount()) {
474 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
475 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON, &type);
476 output_streamon_ = true;
477 }
478 }
479
480 void V4L2JpegDecodeAccelerator::Dequeue() {
481 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
482
483 // Dequeue completed input (VIDEO_OUTPUT) buffers,
484 // and recycle to the free list.
485 struct v4l2_buffer dqbuf;
486 while (InputBufferQueuedCount() > 0) {
487 DCHECK(input_streamon_);
488 memset(&dqbuf, 0, sizeof(dqbuf));
489 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
490 dqbuf.memory = V4L2_MEMORY_MMAP;
491 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) {
492 if (errno == EAGAIN) {
493 // EAGAIN if we're just out of buffers to dequeue.
494 break;
495 }
496 PLOG(ERROR) << "ioctl() failed: input buffer VIDIOC_DQBUF failed.";
497 PostNotifyError(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId,
498 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
499 return;
500 }
501 BufferRecord& input_record = input_buffer_map_[dqbuf.index];
502 DCHECK(input_record.at_device);
503 input_record.at_device = false;
504 free_input_buffers_.push_back(dqbuf.index);
505 }
506
507 // Dequeue completed output (VIDEO_CAPTURE) buffers, recycle to the free list.
508 // Return the finished buffer to the client via the job ready callback.
509 while (OutputBufferQueuedCount() > 0) {
510 DCHECK(output_streamon_);
511 memset(&dqbuf, 0, sizeof(dqbuf));
512 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
513 dqbuf.memory = V4L2_MEMORY_MMAP;
514 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) {
515 if (errno == EAGAIN) {
516 // EAGAIN if we're just out of buffers to dequeue.
517 break;
518 }
519 PLOG(ERROR) << "ioctl() failed: output buffer VIDIOC_DQBUF failed.";
520 PostNotifyError(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId,
521 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
522 return;
523 }
wuchengli 2015/07/01 11:46:47 From v4l2 API, does V4L2_BUF_FLAG_ERROR mean jpeg
henryhsu 2015/07/02 12:05:27 We check flags instead of bytesused. Added to noti
524 BufferRecord& output_record = output_buffer_map_[dqbuf.index];
525 DCHECK(output_record.at_device);
526 output_record.at_device = false;
527 free_output_buffers_.push_back(dqbuf.index);
528
529 // Jobs are always processed in FIFO order.
530 DCHECK(!running_jobs_.empty());
531 linked_ptr<JobRecord> job_record = running_jobs_.front();
532 running_jobs_.pop();
henryhsu 2015/07/01 11:32:04 Maybe we have to check dqbuf.flag is set V4L2_BUF_
wuchengli 2015/07/02 07:19:36 Yes. According to Pawel, please NotifyError if V4L
henryhsu 2015/07/02 12:05:27 Done.
533
534 memcpy(job_record->out_frame->data(media::VideoFrame::kYPlane),
535 output_record.address, output_record.length);
536
537 DVLOG(3) << "Decoding finished, returning bitstream buffer, id="
538 << job_record->bitstream_buffer.id();
539
540 client_->VideoFrameReady(job_record->bitstream_buffer.id());
541 }
542 }
543
544 bool V4L2JpegDecodeAccelerator::EnqueueInputRecord() {
545 DCHECK(!input_jobs_.empty());
546 DCHECK(!free_input_buffers_.empty());
547
548 // Enqueue an input (VIDEO_OUTPUT) buffer for an input video frame.
549 linked_ptr<JobRecord> job_record = input_jobs_.front();
550 input_jobs_.pop();
551 const int index = free_input_buffers_.back();
552 BufferRecord& input_record = input_buffer_map_[index];
553 DCHECK(!input_record.at_device);
554
555 struct v4l2_buffer qbuf;
556 memset(&qbuf, 0, sizeof(qbuf));
557 memcpy(input_record.address, job_record->shm->memory(),
558 job_record->bitstream_buffer.size());
559 qbuf.index = index;
560 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
561 qbuf.memory = V4L2_MEMORY_MMAP;
562 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf);
563 input_record.at_device = true;
564 running_jobs_.push(job_record);
565 free_input_buffers_.pop_back();
566
567 DVLOG(3) << __func__ << ": enqueued frame id="
568 << job_record->bitstream_buffer.id() << " to device.";
569 return true;
570 }
571
572 bool V4L2JpegDecodeAccelerator::EnqueueOutputRecord() {
573 DCHECK(!free_output_buffers_.empty());
574
575 // Enqueue an output (VIDEO_CAPTURE) buffer.
576 const int index = free_output_buffers_.back();
577 BufferRecord& output_record = output_buffer_map_[index];
578 DCHECK(!output_record.at_device);
579 struct v4l2_buffer qbuf;
580 memset(&qbuf, 0, sizeof(qbuf));
581 qbuf.index = index;
582 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
583 qbuf.memory = V4L2_MEMORY_MMAP;
584 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf);
585 output_record.at_device = true;
586 free_output_buffers_.pop_back();
587 return true;
588 }
589
590 void V4L2JpegDecodeAccelerator::ResetQueues() {
591 if (input_streamon_) {
592 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
593 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMOFF, &type);
594 input_streamon_ = false;
595 }
596
597 if (output_streamon_) {
598 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
599 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMOFF, &type);
600 output_streamon_ = false;
601 }
602
603 free_input_buffers_.clear();
604 for (size_t i = 0; i < input_buffer_map_.size(); ++i) {
605 BufferRecord& input_record = input_buffer_map_[i];
606 input_record.at_device = false;
607 free_input_buffers_.push_back(i);
608 }
609
610 free_output_buffers_.clear();
611 for (size_t i = 0; i < output_buffer_map_.size(); ++i) {
612 BufferRecord& output_record = output_buffer_map_[i];
613 output_record.at_device = false;
614 free_output_buffers_.push_back(i);
615 }
616 }
617
618 void V4L2JpegDecodeAccelerator::StartDevicePoll() {
619 DVLOG(3) << __func__ << ": starting device poll";
620 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
621 DCHECK(!device_poll_thread_.IsRunning());
622
623 if (!device_poll_thread_.Start()) {
624 LOG(ERROR) << "StartDevicePoll(): Device thread failed to start";
625 PostNotifyError(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId,
626 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
627 return;
628 }
629 device_poll_task_runner_ = device_poll_thread_.task_runner();
630 }
631
632 bool V4L2JpegDecodeAccelerator::StopDevicePoll() {
633 DVLOG(3) << __func__ << ": stopping device poll";
634 // Signal the DevicePollTask() to stop, and stop the device poll thread.
635 if (!device_->SetDevicePollInterrupt()) {
636 LOG(ERROR) << "StopDevicePoll(): SetDevicePollInterrupt failed.";
637 PostNotifyError(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId,
638 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
639 return false;
640 }
641
642 device_poll_thread_.Stop();
643
644 // Clear the interrupt now, to be sure.
645 if (!device_->ClearDevicePollInterrupt())
646 return false;
647
648 ResetQueues();
wuchengli 2015/07/01 11:46:47 Move this to DestroyTask. StopDevicePoll shouldn't
henryhsu 2015/07/02 12:05:27 Done.
649 return true;
650 }
651
652 } // 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