blob: 59e3b0c879cd3302cb18e3b1fdecd44b6332b945 [file] [log] [blame]
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +09001// Copyright 2020 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//#define LOG_NDEBUG 0
6#define LOG_TAG "V4L2Decoder"
7
8#include <v4l2_codec2/components/V4L2Decoder.h>
9
10#include <stdint.h>
11
12#include <base/bind.h>
13#include <base/memory/ptr_util.h>
14#include <log/log.h>
15
16namespace android {
17namespace {
18
19constexpr size_t kNumInputBuffers = 16;
20// Extra buffers for transmitting in the whole video pipeline.
21constexpr size_t kNumExtraOutputBuffers = 4;
22
23uint32_t VideoCodecToV4L2PixFmt(VideoCodec codec) {
24 switch (codec) {
25 case VideoCodec::H264:
26 return V4L2_PIX_FMT_H264;
27 case VideoCodec::VP8:
28 return V4L2_PIX_FMT_VP8;
29 case VideoCodec::VP9:
30 return V4L2_PIX_FMT_VP9;
31 }
32}
33
34} // namespace
35
36// static
37std::unique_ptr<VideoDecoder> V4L2Decoder::Create(
38 const VideoCodec& codec, const size_t inputBufferSize, GetPoolCB getPoolCb,
39 OutputCB outputCb, ErrorCB errorCb, scoped_refptr<::base::SequencedTaskRunner> taskRunner) {
40 std::unique_ptr<V4L2Decoder> decoder =
41 ::base::WrapUnique<V4L2Decoder>(new V4L2Decoder(taskRunner));
42 if (!decoder->start(codec, inputBufferSize, std::move(getPoolCb), std::move(outputCb),
43 std::move(errorCb))) {
44 return nullptr;
45 }
46 return decoder;
47}
48
49V4L2Decoder::V4L2Decoder(scoped_refptr<::base::SequencedTaskRunner> taskRunner)
50 : mTaskRunner(std::move(taskRunner)) {
51 ALOGV("%s()", __func__);
52
53 mWeakThis = mWeakThisFactory.GetWeakPtr();
54}
55
56V4L2Decoder::~V4L2Decoder() {
57 ALOGV("%s()", __func__);
58 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
59
60 mWeakThisFactory.InvalidateWeakPtrs();
61
62 // Streamoff input and output queue.
63 if (mOutputQueue) {
64 mOutputQueue->Streamoff();
65 mOutputQueue->DeallocateBuffers();
66 mOutputQueue = nullptr;
67 }
68 if (mInputQueue) {
69 mInputQueue->Streamoff();
70 mInputQueue->DeallocateBuffers();
71 mInputQueue = nullptr;
72 }
73 if (mDevice) {
74 mDevice->StopPolling();
75 mDevice = nullptr;
76 }
77}
78
79bool V4L2Decoder::start(const VideoCodec& codec, const size_t inputBufferSize, GetPoolCB getPoolCb,
80 OutputCB outputCb, ErrorCB errorCb) {
81 ALOGV("%s(codec=%s, inputBufferSize=%zu)", __func__, VideoCodecToString(codec),
82 inputBufferSize);
83 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
84
85 mGetPoolCb = std::move(getPoolCb);
86 mOutputCb = std::move(outputCb);
87 mErrorCb = std::move(errorCb);
88
89 if (mState == State::Error) {
90 ALOGE("Ignore due to error state.");
91 return false;
92 }
93
94 mDevice = media::V4L2Device::Create();
95
96 const uint32_t inputPixelFormat = VideoCodecToV4L2PixFmt(codec);
97 if (!mDevice->Open(media::V4L2Device::Type::kDecoder, inputPixelFormat)) {
98 ALOGE("Failed to open device for %s", VideoCodecToString(codec));
99 return false;
100 }
101
102 if (!mDevice->HasCapabilities(V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING)) {
103 ALOGE("Device does not have VIDEO_M2M_MPLANE and STREAMING capabilities.");
104 return false;
105 }
106
107 struct v4l2_decoder_cmd cmd;
108 memset(&cmd, 0, sizeof(cmd));
109 cmd.cmd = V4L2_DEC_CMD_STOP;
110 if (mDevice->Ioctl(VIDIOC_TRY_DECODER_CMD, &cmd) != 0) {
111 ALOGE("Device does not support flushing (V4L2_DEC_CMD_STOP)");
112 return false;
113 }
114
115 // Subscribe to the resolution change event.
116 struct v4l2_event_subscription sub;
117 memset(&sub, 0, sizeof(sub));
118 sub.type = V4L2_EVENT_SOURCE_CHANGE;
119 if (mDevice->Ioctl(VIDIOC_SUBSCRIBE_EVENT, &sub) != 0) {
120 ALOGE("ioctl() failed: VIDIOC_SUBSCRIBE_EVENT: V4L2_EVENT_SOURCE_CHANGE");
121 return false;
122 }
123
124 // Create Input/Output V4L2Queue, and setup input queue.
125 mInputQueue = mDevice->GetQueue(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
126 mOutputQueue = mDevice->GetQueue(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
127 if (!mInputQueue || !mOutputQueue) {
128 ALOGE("Failed to create V4L2 queue.");
129 return false;
130 }
131 if (!setupInputFormat(inputPixelFormat, inputBufferSize)) {
132 ALOGE("Failed to setup input format.");
133 return false;
134 }
135
136 if (!mDevice->StartPolling(::base::BindRepeating(&V4L2Decoder::serviceDeviceTask, mWeakThis),
137 ::base::BindRepeating(&V4L2Decoder::onError, mWeakThis))) {
138 ALOGE("Failed to start polling V4L2 device.");
139 return false;
140 }
141
142 setState(State::Idle);
143 return true;
144}
145
146bool V4L2Decoder::setupInputFormat(const uint32_t inputPixelFormat, const size_t inputBufferSize) {
147 ALOGV("%s(inputPixelFormat=%u, inputBufferSize=%zu)", __func__, inputPixelFormat,
148 inputBufferSize);
149 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
150
151 // Check if the format is supported.
152 std::vector<uint32_t> formats =
153 mDevice->EnumerateSupportedPixelformats(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
154 if (std::find(formats.begin(), formats.end(), inputPixelFormat) == formats.end()) {
155 ALOGE("Input codec s not supported by device.");
156 return false;
157 }
158
159 // Setup the input format.
160 auto format = mInputQueue->SetFormat(inputPixelFormat, media::Size(), inputBufferSize);
161 if (!format) {
162 ALOGE("Failed to call IOCTL to set input format.");
163 return false;
164 }
165 ALOG_ASSERT(format->fmt.pix_mp.pixelformat == inputPixelFormat);
166
167 if (mInputQueue->AllocateBuffers(kNumInputBuffers, V4L2_MEMORY_DMABUF) == 0) {
168 ALOGE("Failed to allocate input buffer.");
169 return false;
170 }
171 if (!mInputQueue->Streamon()) {
172 ALOGE("Failed to streamon input queue.");
173 return false;
174 }
175 return true;
176}
177
178void V4L2Decoder::decode(std::unique_ptr<BitstreamBuffer> buffer, DecodeCB decodeCb) {
179 ALOGV("%s(id=%d)", __func__, buffer->id);
180 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
181
182 if (mState == State::Error) {
183 ALOGE("Ignore due to error state.");
184 mTaskRunner->PostTask(FROM_HERE, ::base::BindOnce(std::move(decodeCb),
185 VideoDecoder::DecodeStatus::kError));
186 return;
187 }
188
189 if (mState == State::Idle) {
190 setState(State::Decoding);
191 }
192
193 mDecodeRequests.push(DecodeRequest(std::move(buffer), std::move(decodeCb)));
194 pumpDecodeRequest();
195}
196
197void V4L2Decoder::drain(DecodeCB drainCb) {
198 ALOGV("%s()", __func__);
199 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
200
201 switch (mState) {
202 case State::Idle:
203 ALOGD("Nothing need to drain, ignore.");
204 mTaskRunner->PostTask(
205 FROM_HERE, ::base::BindOnce(std::move(drainCb), VideoDecoder::DecodeStatus::kOk));
206 return;
207
208 case State::Decoding:
209 mDecodeRequests.push(DecodeRequest(nullptr, std::move(drainCb)));
210 pumpDecodeRequest();
211 return;
212
213 case State::Draining:
214 case State::Error:
215 ALOGE("Ignore due to wrong state: %s", StateToString(mState));
216 mTaskRunner->PostTask(FROM_HERE, ::base::BindOnce(std::move(drainCb),
217 VideoDecoder::DecodeStatus::kError));
218 return;
219 }
220}
221
222void V4L2Decoder::pumpDecodeRequest() {
223 ALOGV("%s()", __func__);
224 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
225
226 if (mState != State::Decoding) return;
227
228 while (!mDecodeRequests.empty()) {
229 // Drain the decoder.
230 if (mDecodeRequests.front().buffer == nullptr) {
231 ALOGV("Get drain request.");
232 // Send the flush command after all input buffers are dequeued. This makes
233 // sure all previous resolution changes have been handled because the
234 // driver must hold the input buffer that triggers resolution change. The
235 // driver cannot decode data in it without new output buffers. If we send
236 // the flush now and a queued input buffer triggers resolution change
237 // later, the driver will send an output buffer that has
238 // V4L2_BUF_FLAG_LAST. But some queued input buffer have not been decoded
239 // yet. Also, V4L2VDA calls STREAMOFF and STREAMON after resolution
240 // change. They implicitly send a V4L2_DEC_CMD_STOP and V4L2_DEC_CMD_START
241 // to the decoder.
242 if (mInputQueue->QueuedBuffersCount() > 0) {
243 ALOGD("Wait for all input buffers dequeued.");
244 return;
245 }
246
247 auto request = std::move(mDecodeRequests.front());
248 mDecodeRequests.pop();
249
250 if (!sendV4L2DecoderCmd(false)) {
251 std::move(request.decodeCb).Run(VideoDecoder::DecodeStatus::kError);
252 onError();
253 return;
254 }
255 mDrainCb = std::move(request.decodeCb);
256 setState(State::Draining);
257 return;
258 }
259
260 // Pause if no free input buffer. We resume decoding after dequeueing input buffers.
261 auto inputBuffer = mInputQueue->GetFreeBuffer();
262 if (!inputBuffer) {
263 ALOGV("There is no free input buffer.");
264 return;
265 }
266
267 auto request = std::move(mDecodeRequests.front());
268 mDecodeRequests.pop();
269
270 ALOGV("QBUF to input queue, bitstreadId=%d", request.buffer->id);
271 inputBuffer->SetTimeStamp({.tv_sec = request.buffer->id});
272 size_t planeSize = inputBuffer->GetPlaneSize(0);
273 if (request.buffer->size > planeSize) {
274 ALOGE("The input size (%zu) is not enough, we need %zu", planeSize,
275 request.buffer->size);
276 onError();
277 return;
278 }
279
280 ALOGV("Set bytes_used=%zu, offset=%zu", request.buffer->offset + request.buffer->size,
281 request.buffer->offset);
282 inputBuffer->SetPlaneDataOffset(0, request.buffer->offset);
283 inputBuffer->SetPlaneBytesUsed(0, request.buffer->offset + request.buffer->size);
284 std::vector<::base::ScopedFD> fds;
285 fds.push_back(std::move(request.buffer->dmabuf_fd));
286 std::move(*inputBuffer).QueueDMABuf(fds);
287
288 mPendingDecodeCbs.insert(std::make_pair(request.buffer->id, std::move(request.decodeCb)));
289 }
290}
291
292void V4L2Decoder::flush() {
293 ALOGV("%s()", __func__);
294 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
295
296 if (mState == State::Idle) {
297 ALOGD("Nothing need to flush, ignore.");
298 return;
299 }
300 if (mState == State::Error) {
301 ALOGE("Ignore due to error state.");
302 return;
303 }
304
305 // Call all pending callbacks.
306 for (auto& item : mPendingDecodeCbs) {
307 std::move(item.second).Run(VideoDecoder::DecodeStatus::kAborted);
308 }
309 mPendingDecodeCbs.clear();
310 if (mDrainCb) {
311 std::move(mDrainCb).Run(VideoDecoder::DecodeStatus::kAborted);
312 }
313
314 // Streamoff V4L2 queues to drop input and output buffers.
315 mDevice->StopPolling();
316 mOutputQueue->Streamoff();
317 mInputQueue->Streamoff();
318
319 // Streamon input queue again.
320 mInputQueue->Streamon();
321 if (!mDevice->StartPolling(::base::BindRepeating(&V4L2Decoder::serviceDeviceTask, mWeakThis),
322 ::base::BindRepeating(&V4L2Decoder::onError, mWeakThis))) {
323 ALOGE("Failed to start polling V4L2 device.");
324 onError();
325 return;
326 }
327
328 setState(State::Idle);
329}
330
331void V4L2Decoder::serviceDeviceTask(bool event) {
332 ALOGV("%s(event=%d) state=%s InputQueue:%zu+%zu/%zu, OutputQueue:%zu+%zu/%zu", __func__, event,
333 StateToString(mState), mInputQueue->FreeBuffersCount(), mInputQueue->QueuedBuffersCount(),
334 mInputQueue->AllocatedBuffersCount(), mOutputQueue->FreeBuffersCount(),
335 mOutputQueue->QueuedBuffersCount(), mOutputQueue->AllocatedBuffersCount());
336 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
337
338 if (mState == State::Error) return;
339
340 // Dequeue output and input queue.
341 bool inputDequeued = false;
342 while (mInputQueue->QueuedBuffersCount() > 0) {
343 bool success;
344 media::V4L2ReadableBufferRef dequeuedBuffer;
345 std::tie(success, dequeuedBuffer) = mInputQueue->DequeueBuffer();
346 if (!success) {
347 ALOGE("Failed to dequeue buffer from output queue.");
348 onError();
349 return;
350 }
351 if (!dequeuedBuffer) break;
352
353 inputDequeued = true;
354
355 // Run the corresponding decode callback.
356 int32_t id = dequeuedBuffer->GetTimeStamp().tv_sec;
357 ALOGV("DQBUF from input queue, bitstreamId=%d", id);
358 auto it = mPendingDecodeCbs.find(id);
359 if (it == mPendingDecodeCbs.end()) {
360 ALOGW("Callback is already abandoned.");
361 continue;
362 }
363 std::move(it->second).Run(VideoDecoder::DecodeStatus::kOk);
364 mPendingDecodeCbs.erase(it);
365 }
366
367 bool outputDequeued = false;
368 while (mOutputQueue->QueuedBuffersCount() > 0) {
369 bool success;
370 media::V4L2ReadableBufferRef dequeuedBuffer;
371 std::tie(success, dequeuedBuffer) = mOutputQueue->DequeueBuffer();
372 if (!success) {
373 ALOGE("Failed to dequeue buffer from output queue.");
374 onError();
375 return;
376 }
377 if (!dequeuedBuffer) break;
378
379 outputDequeued = true;
380
381 ALOGV("DQBUF from output queue, bufferId=%zu, corresponding bitstreamId=%d, bytesused=%zu",
382 dequeuedBuffer->BufferId(),
383 static_cast<int32_t>(dequeuedBuffer->GetTimeStamp().tv_sec),
384 dequeuedBuffer->GetPlaneBytesUsed(0));
385 if (dequeuedBuffer->GetPlaneBytesUsed(0) > 0) {
386 sendOutputBuffer(dequeuedBuffer);
387 }
388 if (mDrainCb && dequeuedBuffer->IsLast()) {
389 ALOGD("All buffers are drained.");
390 sendV4L2DecoderCmd(true);
391 std::move(mDrainCb).Run(VideoDecoder::DecodeStatus::kOk);
392 setState(State::Idle);
393 }
394 }
395
396 // Handle resolution change event.
397 if (event && dequeueResolutionChangeEvent()) {
398 if (!changeResolution()) {
399 onError();
400 return;
401 }
402 }
403
404 // We freed some input buffers, continue handling decode requests.
405 if (inputDequeued) {
406 mTaskRunner->PostTask(FROM_HERE,
407 ::base::BindOnce(&V4L2Decoder::pumpDecodeRequest, mWeakThis));
408 }
409 // We free some output buffers, try to get VideoFrame.
410 if (outputDequeued) {
411 mTaskRunner->PostTask(FROM_HERE,
412 ::base::BindOnce(&V4L2Decoder::tryFetchVideoFrame, mWeakThis));
413 }
414}
415
416void V4L2Decoder::sendOutputBuffer(media::V4L2ReadableBufferRef buffer) {
417 ALOGV("%s(bufferId=%zu)", __func__, buffer->BufferId());
418 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
419
420 size_t bufferId = buffer->BufferId();
421 auto it = mFrameAtDevice.find(bufferId);
422 ALOG_ASSERT(it != mFrameAtDevice.end(), "buffer %zu is not found at mFrameAtDevice", bufferId);
423 auto block = std::move(it->second);
424 mFrameAtDevice.erase(it);
425
426 block->setBitstreamId(buffer->GetTimeStamp().tv_sec);
427 block->setVisibleRect(mVisibleRect);
428 mOutputCb.Run(std::move(block));
429}
430
431bool V4L2Decoder::dequeueResolutionChangeEvent() {
432 ALOGV("%s()", __func__);
433 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
434
435 struct v4l2_event ev;
436 memset(&ev, 0, sizeof(ev));
437 while (mDevice->Ioctl(VIDIOC_DQEVENT, &ev) == 0) {
438 if (ev.type == V4L2_EVENT_SOURCE_CHANGE &&
439 ev.u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION) {
440 return true;
441 }
442 }
443 return false;
444}
445
446bool V4L2Decoder::changeResolution() {
447 ALOGV("%s()", __func__);
448 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
449
450 std::optional<struct v4l2_format> format = getFormatInfo();
451 std::optional<size_t> numOutputBuffers = getNumOutputBuffers();
452 if (!format || !numOutputBuffers) {
453 return false;
454 }
455
456 mCodedSize.SetSize(format->fmt.pix_mp.width, format->fmt.pix_mp.height);
457 mVisibleRect = getVisibleRect(mCodedSize);
458
459 ALOGI("Need %zu output buffers. coded size: %s, visible rect: %s", *numOutputBuffers,
460 mCodedSize.ToString().c_str(), mVisibleRect.ToString().c_str());
461 if (mCodedSize.IsEmpty()) {
462 ALOGE("Failed to get resolution from V4L2 driver.");
463 return false;
464 }
465
466 mOutputQueue->Streamoff();
467 mOutputQueue->DeallocateBuffers();
468
469 if (mOutputQueue->AllocateBuffers(*numOutputBuffers, V4L2_MEMORY_DMABUF) == 0) {
470 ALOGE("Failed to allocate output buffer.");
471 return false;
472 }
473 if (!mOutputQueue->Streamon()) {
474 ALOGE("Failed to streamon output queue.");
475 return false;
476 }
477
478 // Always use fexible pixel 420 format YCBCR_420_888 in Android.
479 mGetPoolCb.Run(&mVideoFramePool, mCodedSize, HalPixelFormat::YCBCR_420_888);
480 if (!mVideoFramePool) {
481 ALOGE("Failed to get block pool with size: %s", mCodedSize.ToString().c_str());
482 return false;
483 }
484
485 tryFetchVideoFrame();
486 return true;
487}
488
489void V4L2Decoder::tryFetchVideoFrame() {
490 ALOGV("%s()", __func__);
491 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
492 ALOG_ASSERT(mVideoFramePool, "mVideoFramePool is null, haven't get the instance yet?");
493
494 if (mState == State::Idle) return;
495
496 if (mVideoFramePool->hasPendingRequests()) {
497 ALOGD("Previous callback is running, ignore.");
498 return;
499 }
500
501 auto outputBuffer = mOutputQueue->GetFreeBuffer();
502 if (!outputBuffer) {
503 ALOGD("No free output buffer.");
504 return;
505 }
506 mVideoFramePool->getVideoFrame(
507 ::base::BindOnce(&V4L2Decoder::onVideoFrameReady, mWeakThis, std::move(*outputBuffer)));
508}
509
510void V4L2Decoder::onVideoFrameReady(media::V4L2WritableBufferRef outputBuffer,
511 std::unique_ptr<VideoFrame> frame) {
512 ALOGV("%s()", __func__);
513 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
514
515 if (!frame) {
516 ALOGE("Get nullptr VideoFrame.");
517 onError();
518 return;
519 }
520
521 size_t bufferId = outputBuffer.BufferId();
522 ALOGE("QBUF to output queue, bufferId=%zu", bufferId);
523 std::move(outputBuffer).QueueDMABuf(frame->getFDs());
524 mFrameAtDevice.insert(std::make_pair(bufferId, std::move(frame)));
525
526 tryFetchVideoFrame();
527}
528
529std::optional<size_t> V4L2Decoder::getNumOutputBuffers() {
530 ALOGV("%s()", __func__);
531 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
532
533 struct v4l2_control ctrl;
534 memset(&ctrl, 0, sizeof(ctrl));
535 ctrl.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE;
536 if (mDevice->Ioctl(VIDIOC_G_CTRL, &ctrl) != 0) {
537 ALOGE("ioctl() failed: VIDIOC_G_CTRL");
538 return std::nullopt;
539 }
540 ALOGV("%s() V4L2_CID_MIN_BUFFERS_FOR_CAPTURE returns %u", __func__, ctrl.value);
541
542 return ctrl.value + kNumExtraOutputBuffers;
543}
544
545std::optional<struct v4l2_format> V4L2Decoder::getFormatInfo() {
546 ALOGV("%s()", __func__);
547 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
548
549 struct v4l2_format format;
550 memset(&format, 0, sizeof(format));
551 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
552 if (mDevice->Ioctl(VIDIOC_G_FMT, &format) != 0) {
553 ALOGE("ioctl() failed: VIDIOC_G_FMT");
554 return std::nullopt;
555 }
556
557 return format;
558}
559
560media::Rect V4L2Decoder::getVisibleRect(const media::Size& codedSize) {
561 ALOGV("%s()", __func__);
562 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
563
564 struct v4l2_rect* visible_rect = nullptr;
565 struct v4l2_selection selection_arg;
566 memset(&selection_arg, 0, sizeof(selection_arg));
567 selection_arg.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
568 selection_arg.target = V4L2_SEL_TGT_COMPOSE;
569
570 if (mDevice->Ioctl(VIDIOC_G_SELECTION, &selection_arg) == 0) {
571 ALOGV("VIDIOC_G_SELECTION is supported");
572 visible_rect = &selection_arg.r;
573 } else {
574 ALOGV("Fallback to VIDIOC_G_CROP");
575 struct v4l2_crop crop_arg;
576 memset(&crop_arg, 0, sizeof(crop_arg));
577 crop_arg.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
578
579 if (mDevice->Ioctl(VIDIOC_G_CROP, &crop_arg) != 0) {
580 ALOGW("ioctl() VIDIOC_G_CROP failed");
581 return media::Rect(codedSize);
582 }
583 visible_rect = &crop_arg.c;
584 }
585
586 media::Rect rect(visible_rect->left, visible_rect->top, visible_rect->width,
587 visible_rect->height);
588 ALOGD("visible rectangle is %s", rect.ToString().c_str());
589 if (!media::Rect(codedSize).Contains(rect)) {
590 ALOGW("visible rectangle %s is not inside coded size %s", rect.ToString().c_str(),
591 codedSize.ToString().c_str());
592 return media::Rect(codedSize);
593 }
594 if (rect.IsEmpty()) {
595 ALOGW("visible size is empty");
596 return media::Rect(codedSize);
597 }
598
599 return rect;
600}
601
602bool V4L2Decoder::sendV4L2DecoderCmd(bool start) {
603 ALOGV("%s(start=%d)", __func__, start);
604 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
605
606 struct v4l2_decoder_cmd cmd;
607 memset(&cmd, 0, sizeof(cmd));
608 cmd.cmd = start ? V4L2_DEC_CMD_START : V4L2_DEC_CMD_STOP;
609 if (mDevice->Ioctl(VIDIOC_DECODER_CMD, &cmd) != 0) {
610 ALOGE("ioctl() VIDIOC_DECODER_CMD failed: start=%d", start);
611 return false;
612 }
613
614 return true;
615}
616
617void V4L2Decoder::onError() {
618 ALOGV("%s()", __func__);
619 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
620
621 setState(State::Error);
622 mErrorCb.Run();
623}
624
625void V4L2Decoder::setState(State newState) {
626 ALOGV("%s(%s)", __func__, StateToString(newState));
627 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
628
629 if (mState == newState) return;
630 if (mState == State::Error) {
631 ALOGV("Already in Error state.");
632 return;
633 }
634
635 switch (newState) {
636 case State::Idle:
637 break;
638 case State::Decoding:
639 break;
640 case State::Draining:
641 if (mState != State::Decoding) newState = State::Error;
642 break;
643 case State::Error:
644 break;
645 }
646
647 ALOGI("Set state %s => %s", StateToString(mState), StateToString(newState));
648 mState = newState;
649}
650
651// static
652const char* V4L2Decoder::StateToString(State state) {
653 switch (state) {
654 case State::Idle:
655 return "Idle";
656 case State::Decoding:
657 return "Decoding";
658 case State::Draining:
659 return "Draining";
660 case State::Error:
661 return "Error";
662 }
663}
664
665} // namespace android