blob: 6a60dda2afd08a04b7e9fc07ec06252f2e466f99 [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) {
Chih-Yu Huangfa546d32020-07-02 16:26:52 +0900332 ALOGV("%s(event=%d) state=%s InputQueue(%s):%zu+%zu/%zu, OutputQueue(%s):%zu+%zu/%zu", __func__,
333 event, StateToString(mState), (mInputQueue->IsStreaming() ? "streamon" : "streamoff"),
334 mInputQueue->FreeBuffersCount(), mInputQueue->QueuedBuffersCount(),
335 mInputQueue->AllocatedBuffersCount(),
336 (mOutputQueue->IsStreaming() ? "streamon" : "streamoff"),
337 mOutputQueue->FreeBuffersCount(), mOutputQueue->QueuedBuffersCount(),
338 mOutputQueue->AllocatedBuffersCount());
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +0900339 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
340
341 if (mState == State::Error) return;
342
343 // Dequeue output and input queue.
344 bool inputDequeued = false;
345 while (mInputQueue->QueuedBuffersCount() > 0) {
346 bool success;
347 media::V4L2ReadableBufferRef dequeuedBuffer;
348 std::tie(success, dequeuedBuffer) = mInputQueue->DequeueBuffer();
349 if (!success) {
Chih-Yu Huangfa546d32020-07-02 16:26:52 +0900350 ALOGE("Failed to dequeue buffer from input queue.");
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +0900351 onError();
352 return;
353 }
354 if (!dequeuedBuffer) break;
355
356 inputDequeued = true;
357
358 // Run the corresponding decode callback.
359 int32_t id = dequeuedBuffer->GetTimeStamp().tv_sec;
360 ALOGV("DQBUF from input queue, bitstreamId=%d", id);
361 auto it = mPendingDecodeCbs.find(id);
362 if (it == mPendingDecodeCbs.end()) {
363 ALOGW("Callback is already abandoned.");
364 continue;
365 }
366 std::move(it->second).Run(VideoDecoder::DecodeStatus::kOk);
367 mPendingDecodeCbs.erase(it);
368 }
369
370 bool outputDequeued = false;
371 while (mOutputQueue->QueuedBuffersCount() > 0) {
372 bool success;
373 media::V4L2ReadableBufferRef dequeuedBuffer;
374 std::tie(success, dequeuedBuffer) = mOutputQueue->DequeueBuffer();
375 if (!success) {
376 ALOGE("Failed to dequeue buffer from output queue.");
377 onError();
378 return;
379 }
380 if (!dequeuedBuffer) break;
381
382 outputDequeued = true;
383
384 ALOGV("DQBUF from output queue, bufferId=%zu, corresponding bitstreamId=%d, bytesused=%zu",
385 dequeuedBuffer->BufferId(),
386 static_cast<int32_t>(dequeuedBuffer->GetTimeStamp().tv_sec),
387 dequeuedBuffer->GetPlaneBytesUsed(0));
388 if (dequeuedBuffer->GetPlaneBytesUsed(0) > 0) {
389 sendOutputBuffer(dequeuedBuffer);
390 }
391 if (mDrainCb && dequeuedBuffer->IsLast()) {
392 ALOGD("All buffers are drained.");
393 sendV4L2DecoderCmd(true);
394 std::move(mDrainCb).Run(VideoDecoder::DecodeStatus::kOk);
395 setState(State::Idle);
396 }
397 }
398
399 // Handle resolution change event.
400 if (event && dequeueResolutionChangeEvent()) {
401 if (!changeResolution()) {
402 onError();
403 return;
404 }
405 }
406
407 // We freed some input buffers, continue handling decode requests.
408 if (inputDequeued) {
409 mTaskRunner->PostTask(FROM_HERE,
410 ::base::BindOnce(&V4L2Decoder::pumpDecodeRequest, mWeakThis));
411 }
412 // We free some output buffers, try to get VideoFrame.
413 if (outputDequeued) {
414 mTaskRunner->PostTask(FROM_HERE,
415 ::base::BindOnce(&V4L2Decoder::tryFetchVideoFrame, mWeakThis));
416 }
417}
418
419void V4L2Decoder::sendOutputBuffer(media::V4L2ReadableBufferRef buffer) {
420 ALOGV("%s(bufferId=%zu)", __func__, buffer->BufferId());
421 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
422
423 size_t bufferId = buffer->BufferId();
424 auto it = mFrameAtDevice.find(bufferId);
425 ALOG_ASSERT(it != mFrameAtDevice.end(), "buffer %zu is not found at mFrameAtDevice", bufferId);
426 auto block = std::move(it->second);
427 mFrameAtDevice.erase(it);
428
429 block->setBitstreamId(buffer->GetTimeStamp().tv_sec);
430 block->setVisibleRect(mVisibleRect);
431 mOutputCb.Run(std::move(block));
432}
433
434bool V4L2Decoder::dequeueResolutionChangeEvent() {
435 ALOGV("%s()", __func__);
436 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
437
438 struct v4l2_event ev;
439 memset(&ev, 0, sizeof(ev));
440 while (mDevice->Ioctl(VIDIOC_DQEVENT, &ev) == 0) {
441 if (ev.type == V4L2_EVENT_SOURCE_CHANGE &&
442 ev.u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION) {
443 return true;
444 }
445 }
446 return false;
447}
448
449bool V4L2Decoder::changeResolution() {
450 ALOGV("%s()", __func__);
451 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
452
453 std::optional<struct v4l2_format> format = getFormatInfo();
454 std::optional<size_t> numOutputBuffers = getNumOutputBuffers();
455 if (!format || !numOutputBuffers) {
456 return false;
457 }
458
459 mCodedSize.SetSize(format->fmt.pix_mp.width, format->fmt.pix_mp.height);
460 mVisibleRect = getVisibleRect(mCodedSize);
461
462 ALOGI("Need %zu output buffers. coded size: %s, visible rect: %s", *numOutputBuffers,
463 mCodedSize.ToString().c_str(), mVisibleRect.ToString().c_str());
464 if (mCodedSize.IsEmpty()) {
465 ALOGE("Failed to get resolution from V4L2 driver.");
466 return false;
467 }
468
469 mOutputQueue->Streamoff();
470 mOutputQueue->DeallocateBuffers();
471
472 if (mOutputQueue->AllocateBuffers(*numOutputBuffers, V4L2_MEMORY_DMABUF) == 0) {
473 ALOGE("Failed to allocate output buffer.");
474 return false;
475 }
476 if (!mOutputQueue->Streamon()) {
477 ALOGE("Failed to streamon output queue.");
478 return false;
479 }
480
481 // Always use fexible pixel 420 format YCBCR_420_888 in Android.
482 mGetPoolCb.Run(&mVideoFramePool, mCodedSize, HalPixelFormat::YCBCR_420_888);
483 if (!mVideoFramePool) {
484 ALOGE("Failed to get block pool with size: %s", mCodedSize.ToString().c_str());
485 return false;
486 }
487
488 tryFetchVideoFrame();
489 return true;
490}
491
492void V4L2Decoder::tryFetchVideoFrame() {
493 ALOGV("%s()", __func__);
494 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
495 ALOG_ASSERT(mVideoFramePool, "mVideoFramePool is null, haven't get the instance yet?");
496
497 if (mState == State::Idle) return;
498
499 if (mVideoFramePool->hasPendingRequests()) {
500 ALOGD("Previous callback is running, ignore.");
501 return;
502 }
503
504 auto outputBuffer = mOutputQueue->GetFreeBuffer();
505 if (!outputBuffer) {
506 ALOGD("No free output buffer.");
507 return;
508 }
509 mVideoFramePool->getVideoFrame(
510 ::base::BindOnce(&V4L2Decoder::onVideoFrameReady, mWeakThis, std::move(*outputBuffer)));
511}
512
513void V4L2Decoder::onVideoFrameReady(media::V4L2WritableBufferRef outputBuffer,
514 std::unique_ptr<VideoFrame> frame) {
515 ALOGV("%s()", __func__);
516 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
517
518 if (!frame) {
519 ALOGE("Get nullptr VideoFrame.");
520 onError();
521 return;
522 }
523
524 size_t bufferId = outputBuffer.BufferId();
Chih-Yu Huangfa546d32020-07-02 16:26:52 +0900525 ALOGV("QBUF to output queue, bufferId=%zu", bufferId);
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +0900526 std::move(outputBuffer).QueueDMABuf(frame->getFDs());
527 mFrameAtDevice.insert(std::make_pair(bufferId, std::move(frame)));
528
529 tryFetchVideoFrame();
530}
531
532std::optional<size_t> V4L2Decoder::getNumOutputBuffers() {
533 ALOGV("%s()", __func__);
534 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
535
536 struct v4l2_control ctrl;
537 memset(&ctrl, 0, sizeof(ctrl));
538 ctrl.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE;
539 if (mDevice->Ioctl(VIDIOC_G_CTRL, &ctrl) != 0) {
540 ALOGE("ioctl() failed: VIDIOC_G_CTRL");
541 return std::nullopt;
542 }
543 ALOGV("%s() V4L2_CID_MIN_BUFFERS_FOR_CAPTURE returns %u", __func__, ctrl.value);
544
545 return ctrl.value + kNumExtraOutputBuffers;
546}
547
548std::optional<struct v4l2_format> V4L2Decoder::getFormatInfo() {
549 ALOGV("%s()", __func__);
550 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
551
552 struct v4l2_format format;
553 memset(&format, 0, sizeof(format));
554 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
555 if (mDevice->Ioctl(VIDIOC_G_FMT, &format) != 0) {
556 ALOGE("ioctl() failed: VIDIOC_G_FMT");
557 return std::nullopt;
558 }
559
560 return format;
561}
562
563media::Rect V4L2Decoder::getVisibleRect(const media::Size& codedSize) {
564 ALOGV("%s()", __func__);
565 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
566
567 struct v4l2_rect* visible_rect = nullptr;
568 struct v4l2_selection selection_arg;
569 memset(&selection_arg, 0, sizeof(selection_arg));
570 selection_arg.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
571 selection_arg.target = V4L2_SEL_TGT_COMPOSE;
572
573 if (mDevice->Ioctl(VIDIOC_G_SELECTION, &selection_arg) == 0) {
574 ALOGV("VIDIOC_G_SELECTION is supported");
575 visible_rect = &selection_arg.r;
576 } else {
577 ALOGV("Fallback to VIDIOC_G_CROP");
578 struct v4l2_crop crop_arg;
579 memset(&crop_arg, 0, sizeof(crop_arg));
580 crop_arg.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
581
582 if (mDevice->Ioctl(VIDIOC_G_CROP, &crop_arg) != 0) {
583 ALOGW("ioctl() VIDIOC_G_CROP failed");
584 return media::Rect(codedSize);
585 }
586 visible_rect = &crop_arg.c;
587 }
588
589 media::Rect rect(visible_rect->left, visible_rect->top, visible_rect->width,
590 visible_rect->height);
591 ALOGD("visible rectangle is %s", rect.ToString().c_str());
592 if (!media::Rect(codedSize).Contains(rect)) {
593 ALOGW("visible rectangle %s is not inside coded size %s", rect.ToString().c_str(),
594 codedSize.ToString().c_str());
595 return media::Rect(codedSize);
596 }
597 if (rect.IsEmpty()) {
598 ALOGW("visible size is empty");
599 return media::Rect(codedSize);
600 }
601
602 return rect;
603}
604
605bool V4L2Decoder::sendV4L2DecoderCmd(bool start) {
606 ALOGV("%s(start=%d)", __func__, start);
607 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
608
609 struct v4l2_decoder_cmd cmd;
610 memset(&cmd, 0, sizeof(cmd));
611 cmd.cmd = start ? V4L2_DEC_CMD_START : V4L2_DEC_CMD_STOP;
612 if (mDevice->Ioctl(VIDIOC_DECODER_CMD, &cmd) != 0) {
613 ALOGE("ioctl() VIDIOC_DECODER_CMD failed: start=%d", start);
614 return false;
615 }
616
617 return true;
618}
619
620void V4L2Decoder::onError() {
621 ALOGV("%s()", __func__);
622 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
623
624 setState(State::Error);
625 mErrorCb.Run();
626}
627
628void V4L2Decoder::setState(State newState) {
629 ALOGV("%s(%s)", __func__, StateToString(newState));
630 ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
631
632 if (mState == newState) return;
633 if (mState == State::Error) {
634 ALOGV("Already in Error state.");
635 return;
636 }
637
638 switch (newState) {
639 case State::Idle:
640 break;
641 case State::Decoding:
642 break;
643 case State::Draining:
644 if (mState != State::Decoding) newState = State::Error;
645 break;
646 case State::Error:
647 break;
648 }
649
650 ALOGI("Set state %s => %s", StateToString(mState), StateToString(newState));
651 mState = newState;
652}
653
654// static
655const char* V4L2Decoder::StateToString(State state) {
656 switch (state) {
657 case State::Idle:
658 return "Idle";
659 case State::Decoding:
660 return "Decoding";
661 case State::Draining:
662 return "Draining";
663 case State::Error:
664 return "Error";
665 }
666}
667
668} // namespace android