xref: /aosp_15_r20/external/v4l2_codec2/v4l2/V4L2Decoder.cpp (revision 0ec5a0ec62797f775085659156625e7f1bdb369f)
1*0ec5a0ecSAndroid Build Coastguard Worker // Copyright 2020 The Chromium Authors. All rights reserved.
2*0ec5a0ecSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*0ec5a0ecSAndroid Build Coastguard Worker // found in the LICENSE file.
4*0ec5a0ecSAndroid Build Coastguard Worker 
5*0ec5a0ecSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
6*0ec5a0ecSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_VIDEO
7*0ec5a0ecSAndroid Build Coastguard Worker #define LOG_TAG "V4L2Decoder"
8*0ec5a0ecSAndroid Build Coastguard Worker 
9*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/v4l2/V4L2Decoder.h>
10*0ec5a0ecSAndroid Build Coastguard Worker 
11*0ec5a0ecSAndroid Build Coastguard Worker #include <stdint.h>
12*0ec5a0ecSAndroid Build Coastguard Worker 
13*0ec5a0ecSAndroid Build Coastguard Worker #include <algorithm>
14*0ec5a0ecSAndroid Build Coastguard Worker #include <vector>
15*0ec5a0ecSAndroid Build Coastguard Worker 
16*0ec5a0ecSAndroid Build Coastguard Worker #include <base/bind.h>
17*0ec5a0ecSAndroid Build Coastguard Worker #include <base/files/scoped_file.h>
18*0ec5a0ecSAndroid Build Coastguard Worker #include <base/memory/ptr_util.h>
19*0ec5a0ecSAndroid Build Coastguard Worker #include <log/log.h>
20*0ec5a0ecSAndroid Build Coastguard Worker #include <utils/Trace.h>
21*0ec5a0ecSAndroid Build Coastguard Worker 
22*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/Common.h>
23*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/Fourcc.h>
24*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/H264NalParser.h>
25*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/HEVCNalParser.h>
26*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/plugin_store/DmabufHelpers.h>
27*0ec5a0ecSAndroid Build Coastguard Worker 
28*0ec5a0ecSAndroid Build Coastguard Worker namespace android {
29*0ec5a0ecSAndroid Build Coastguard Worker namespace {
30*0ec5a0ecSAndroid Build Coastguard Worker 
31*0ec5a0ecSAndroid Build Coastguard Worker // Extra buffers for transmitting in the whole video pipeline.
32*0ec5a0ecSAndroid Build Coastguard Worker constexpr size_t kNumExtraOutputBuffers = 4;
33*0ec5a0ecSAndroid Build Coastguard Worker 
waitForDRC(const C2ConstLinearBlock & input,std::optional<VideoCodec> codec)34*0ec5a0ecSAndroid Build Coastguard Worker bool waitForDRC(const C2ConstLinearBlock& input, std::optional<VideoCodec> codec) {
35*0ec5a0ecSAndroid Build Coastguard Worker     C2ReadView view = input.map().get();
36*0ec5a0ecSAndroid Build Coastguard Worker     const uint8_t* pos = view.data();
37*0ec5a0ecSAndroid Build Coastguard Worker     // frame type takes the (2) position in first byte of VP9  uncompressed header
38*0ec5a0ecSAndroid Build Coastguard Worker     const uint8_t kVP9FrameTypeMask = 0x4;
39*0ec5a0ecSAndroid Build Coastguard Worker     // frame type takes the (0) position in first byte of VP8 uncompressed header
40*0ec5a0ecSAndroid Build Coastguard Worker     const uint8_t kVP8FrameTypeMask = 0x1;
41*0ec5a0ecSAndroid Build Coastguard Worker 
42*0ec5a0ecSAndroid Build Coastguard Worker     switch (*codec) {
43*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::H264: {
44*0ec5a0ecSAndroid Build Coastguard Worker         H264NalParser parser(view.data(), view.capacity());
45*0ec5a0ecSAndroid Build Coastguard Worker         return parser.locateIDR();
46*0ec5a0ecSAndroid Build Coastguard Worker     }
47*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::HEVC: {
48*0ec5a0ecSAndroid Build Coastguard Worker         HEVCNalParser parser(view.data(), view.capacity());
49*0ec5a0ecSAndroid Build Coastguard Worker         return parser.locateIDR();
50*0ec5a0ecSAndroid Build Coastguard Worker     }
51*0ec5a0ecSAndroid Build Coastguard Worker     // For VP8 and VP9 it is assumed that the input buffer contains a single
52*0ec5a0ecSAndroid Build Coastguard Worker     // frame that is not fragmented.
53*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::VP9:
54*0ec5a0ecSAndroid Build Coastguard Worker         // 0 - key frame; 1 - interframe
55*0ec5a0ecSAndroid Build Coastguard Worker         return ((pos[0] & kVP9FrameTypeMask) == 0);
56*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::VP8:
57*0ec5a0ecSAndroid Build Coastguard Worker         // 0 - key frame; 1 - interframe;
58*0ec5a0ecSAndroid Build Coastguard Worker         return ((pos[0] & kVP8FrameTypeMask) == 0);
59*0ec5a0ecSAndroid Build Coastguard Worker     }
60*0ec5a0ecSAndroid Build Coastguard Worker 
61*0ec5a0ecSAndroid Build Coastguard Worker     return false;
62*0ec5a0ecSAndroid Build Coastguard Worker }
63*0ec5a0ecSAndroid Build Coastguard Worker 
64*0ec5a0ecSAndroid Build Coastguard Worker }  // namespace
65*0ec5a0ecSAndroid Build Coastguard Worker 
66*0ec5a0ecSAndroid Build Coastguard Worker // static
Create(uint32_t debugStreamId,const VideoCodec & codec,const size_t inputBufferSize,const size_t minNumOutputBuffers,GetPoolCB getPoolCb,OutputCB outputCb,ErrorCB errorCb,scoped_refptr<::base::SequencedTaskRunner> taskRunner,bool isSecure)67*0ec5a0ecSAndroid Build Coastguard Worker std::unique_ptr<VideoDecoder> V4L2Decoder::Create(
68*0ec5a0ecSAndroid Build Coastguard Worker         uint32_t debugStreamId, const VideoCodec& codec, const size_t inputBufferSize,
69*0ec5a0ecSAndroid Build Coastguard Worker         const size_t minNumOutputBuffers, GetPoolCB getPoolCb, OutputCB outputCb, ErrorCB errorCb,
70*0ec5a0ecSAndroid Build Coastguard Worker         scoped_refptr<::base::SequencedTaskRunner> taskRunner, bool isSecure) {
71*0ec5a0ecSAndroid Build Coastguard Worker     std::unique_ptr<V4L2Decoder> decoder =
72*0ec5a0ecSAndroid Build Coastguard Worker             ::base::WrapUnique<V4L2Decoder>(new V4L2Decoder(debugStreamId, taskRunner));
73*0ec5a0ecSAndroid Build Coastguard Worker     if (!decoder->start(codec, inputBufferSize, minNumOutputBuffers, std::move(getPoolCb),
74*0ec5a0ecSAndroid Build Coastguard Worker                         std::move(outputCb), std::move(errorCb), isSecure)) {
75*0ec5a0ecSAndroid Build Coastguard Worker         return nullptr;
76*0ec5a0ecSAndroid Build Coastguard Worker     }
77*0ec5a0ecSAndroid Build Coastguard Worker     return decoder;
78*0ec5a0ecSAndroid Build Coastguard Worker }
79*0ec5a0ecSAndroid Build Coastguard Worker 
V4L2Decoder(uint32_t debugStreamId,scoped_refptr<::base::SequencedTaskRunner> taskRunner)80*0ec5a0ecSAndroid Build Coastguard Worker V4L2Decoder::V4L2Decoder(uint32_t debugStreamId,
81*0ec5a0ecSAndroid Build Coastguard Worker                          scoped_refptr<::base::SequencedTaskRunner> taskRunner)
82*0ec5a0ecSAndroid Build Coastguard Worker       : mDebugStreamId(debugStreamId), mTaskRunner(std::move(taskRunner)) {
83*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
84*0ec5a0ecSAndroid Build Coastguard Worker 
85*0ec5a0ecSAndroid Build Coastguard Worker     mWeakThis = mWeakThisFactory.GetWeakPtr();
86*0ec5a0ecSAndroid Build Coastguard Worker }
87*0ec5a0ecSAndroid Build Coastguard Worker 
~V4L2Decoder()88*0ec5a0ecSAndroid Build Coastguard Worker V4L2Decoder::~V4L2Decoder() {
89*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
90*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
91*0ec5a0ecSAndroid Build Coastguard Worker 
92*0ec5a0ecSAndroid Build Coastguard Worker     mWeakThisFactory.InvalidateWeakPtrs();
93*0ec5a0ecSAndroid Build Coastguard Worker 
94*0ec5a0ecSAndroid Build Coastguard Worker     // Streamoff input and output queue.
95*0ec5a0ecSAndroid Build Coastguard Worker     if (mOutputQueue) {
96*0ec5a0ecSAndroid Build Coastguard Worker         mOutputQueue->streamoff();
97*0ec5a0ecSAndroid Build Coastguard Worker         mOutputQueue->deallocateBuffers();
98*0ec5a0ecSAndroid Build Coastguard Worker         mOutputQueue = nullptr;
99*0ec5a0ecSAndroid Build Coastguard Worker     }
100*0ec5a0ecSAndroid Build Coastguard Worker     if (mInputQueue) {
101*0ec5a0ecSAndroid Build Coastguard Worker         mInputQueue->streamoff();
102*0ec5a0ecSAndroid Build Coastguard Worker         mInputQueue->deallocateBuffers();
103*0ec5a0ecSAndroid Build Coastguard Worker         mInputQueue = nullptr;
104*0ec5a0ecSAndroid Build Coastguard Worker     }
105*0ec5a0ecSAndroid Build Coastguard Worker     if (mDevice) {
106*0ec5a0ecSAndroid Build Coastguard Worker         mDevice->stopPolling();
107*0ec5a0ecSAndroid Build Coastguard Worker         mDevice = nullptr;
108*0ec5a0ecSAndroid Build Coastguard Worker     }
109*0ec5a0ecSAndroid Build Coastguard Worker     if (mInitialEosBuffer) {
110*0ec5a0ecSAndroid Build Coastguard Worker         mInitialEosBuffer = nullptr;
111*0ec5a0ecSAndroid Build Coastguard Worker     }
112*0ec5a0ecSAndroid Build Coastguard Worker }
113*0ec5a0ecSAndroid Build Coastguard Worker 
start(const VideoCodec & codec,const size_t inputBufferSize,const size_t minNumOutputBuffers,GetPoolCB getPoolCb,OutputCB outputCb,ErrorCB errorCb,bool isSecure)114*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Decoder::start(const VideoCodec& codec, const size_t inputBufferSize,
115*0ec5a0ecSAndroid Build Coastguard Worker                         const size_t minNumOutputBuffers, GetPoolCB getPoolCb, OutputCB outputCb,
116*0ec5a0ecSAndroid Build Coastguard Worker                         ErrorCB errorCb, bool isSecure) {
117*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
118*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(codec=%s, inputBufferSize=%zu, minNumOutputBuffers=%zu)", __func__,
119*0ec5a0ecSAndroid Build Coastguard Worker           VideoCodecToString(codec), inputBufferSize, minNumOutputBuffers);
120*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
121*0ec5a0ecSAndroid Build Coastguard Worker 
122*0ec5a0ecSAndroid Build Coastguard Worker     mMinNumOutputBuffers = minNumOutputBuffers;
123*0ec5a0ecSAndroid Build Coastguard Worker     mGetPoolCb = std::move(getPoolCb);
124*0ec5a0ecSAndroid Build Coastguard Worker     mOutputCb = std::move(outputCb);
125*0ec5a0ecSAndroid Build Coastguard Worker     mErrorCb = std::move(errorCb);
126*0ec5a0ecSAndroid Build Coastguard Worker     mCodec = codec;
127*0ec5a0ecSAndroid Build Coastguard Worker     mIsSecure = isSecure;
128*0ec5a0ecSAndroid Build Coastguard Worker 
129*0ec5a0ecSAndroid Build Coastguard Worker     if (mState == State::Error) {
130*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Ignore due to error state.");
131*0ec5a0ecSAndroid Build Coastguard Worker         return false;
132*0ec5a0ecSAndroid Build Coastguard Worker     }
133*0ec5a0ecSAndroid Build Coastguard Worker 
134*0ec5a0ecSAndroid Build Coastguard Worker     mDevice = V4L2Device::create(mDebugStreamId);
135*0ec5a0ecSAndroid Build Coastguard Worker 
136*0ec5a0ecSAndroid Build Coastguard Worker     const uint32_t inputPixelFormat = V4L2Device::videoCodecToPixFmt(codec);
137*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDevice->open(V4L2Device::Type::kDecoder, inputPixelFormat)) {
138*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to open device for %s", VideoCodecToString(codec));
139*0ec5a0ecSAndroid Build Coastguard Worker         return false;
140*0ec5a0ecSAndroid Build Coastguard Worker     }
141*0ec5a0ecSAndroid Build Coastguard Worker 
142*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDevice->hasCapabilities(V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING)) {
143*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Device does not have VIDEO_M2M_MPLANE and STREAMING capabilities.");
144*0ec5a0ecSAndroid Build Coastguard Worker         return false;
145*0ec5a0ecSAndroid Build Coastguard Worker     }
146*0ec5a0ecSAndroid Build Coastguard Worker 
147*0ec5a0ecSAndroid Build Coastguard Worker     if (!sendV4L2DecoderCmd(false)) {
148*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Device does not support flushing (V4L2_DEC_CMD_STOP)");
149*0ec5a0ecSAndroid Build Coastguard Worker         return false;
150*0ec5a0ecSAndroid Build Coastguard Worker     }
151*0ec5a0ecSAndroid Build Coastguard Worker 
152*0ec5a0ecSAndroid Build Coastguard Worker     // Subscribe to the resolution change event.
153*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_event_subscription sub;
154*0ec5a0ecSAndroid Build Coastguard Worker     memset(&sub, 0, sizeof(sub));
155*0ec5a0ecSAndroid Build Coastguard Worker     sub.type = V4L2_EVENT_SOURCE_CHANGE;
156*0ec5a0ecSAndroid Build Coastguard Worker     if (mDevice->ioctl(VIDIOC_SUBSCRIBE_EVENT, &sub) != 0) {
157*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("ioctl() failed: VIDIOC_SUBSCRIBE_EVENT: V4L2_EVENT_SOURCE_CHANGE");
158*0ec5a0ecSAndroid Build Coastguard Worker         return false;
159*0ec5a0ecSAndroid Build Coastguard Worker     }
160*0ec5a0ecSAndroid Build Coastguard Worker 
161*0ec5a0ecSAndroid Build Coastguard Worker     // Create Input/Output V4L2Queue, and setup input queue.
162*0ec5a0ecSAndroid Build Coastguard Worker     mInputQueue = mDevice->getQueue(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
163*0ec5a0ecSAndroid Build Coastguard Worker     mOutputQueue = mDevice->getQueue(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
164*0ec5a0ecSAndroid Build Coastguard Worker     if (!mInputQueue || !mOutputQueue) {
165*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to create V4L2 queue.");
166*0ec5a0ecSAndroid Build Coastguard Worker         return false;
167*0ec5a0ecSAndroid Build Coastguard Worker     }
168*0ec5a0ecSAndroid Build Coastguard Worker     if (!setupInputFormat(inputPixelFormat, inputBufferSize)) {
169*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to setup input format.");
170*0ec5a0ecSAndroid Build Coastguard Worker         return false;
171*0ec5a0ecSAndroid Build Coastguard Worker     }
172*0ec5a0ecSAndroid Build Coastguard Worker     if (!setupInitialOutput()) {
173*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Unable to setup initial output");
174*0ec5a0ecSAndroid Build Coastguard Worker         return false;
175*0ec5a0ecSAndroid Build Coastguard Worker     }
176*0ec5a0ecSAndroid Build Coastguard Worker 
177*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDevice->startPolling(mTaskRunner,
178*0ec5a0ecSAndroid Build Coastguard Worker                                ::base::BindRepeating(&V4L2Decoder::serviceDeviceTask, mWeakThis),
179*0ec5a0ecSAndroid Build Coastguard Worker                                ::base::BindRepeating(&V4L2Decoder::onError, mWeakThis))) {
180*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to start polling V4L2 device.");
181*0ec5a0ecSAndroid Build Coastguard Worker         return false;
182*0ec5a0ecSAndroid Build Coastguard Worker     }
183*0ec5a0ecSAndroid Build Coastguard Worker 
184*0ec5a0ecSAndroid Build Coastguard Worker     setState(State::Idle);
185*0ec5a0ecSAndroid Build Coastguard Worker     return true;
186*0ec5a0ecSAndroid Build Coastguard Worker }
187*0ec5a0ecSAndroid Build Coastguard Worker 
setupInputFormat(const uint32_t inputPixelFormat,const size_t inputBufferSize)188*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Decoder::setupInputFormat(const uint32_t inputPixelFormat, const size_t inputBufferSize) {
189*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(inputPixelFormat=%u, inputBufferSize=%zu)", __func__, inputPixelFormat,
190*0ec5a0ecSAndroid Build Coastguard Worker           inputBufferSize);
191*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
192*0ec5a0ecSAndroid Build Coastguard Worker 
193*0ec5a0ecSAndroid Build Coastguard Worker     // Check if the format is supported.
194*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<uint32_t> formats =
195*0ec5a0ecSAndroid Build Coastguard Worker             mDevice->enumerateSupportedPixelformats(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
196*0ec5a0ecSAndroid Build Coastguard Worker     if (std::find(formats.begin(), formats.end(), inputPixelFormat) == formats.end()) {
197*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Input codec s not supported by device.");
198*0ec5a0ecSAndroid Build Coastguard Worker         return false;
199*0ec5a0ecSAndroid Build Coastguard Worker     }
200*0ec5a0ecSAndroid Build Coastguard Worker 
201*0ec5a0ecSAndroid Build Coastguard Worker     // Setup the input format.
202*0ec5a0ecSAndroid Build Coastguard Worker     auto format = mInputQueue->setFormat(inputPixelFormat, ui::Size(), inputBufferSize, 0);
203*0ec5a0ecSAndroid Build Coastguard Worker     if (!format) {
204*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to call IOCTL to set input format.");
205*0ec5a0ecSAndroid Build Coastguard Worker         return false;
206*0ec5a0ecSAndroid Build Coastguard Worker     }
207*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(format->fmt.pix_mp.pixelformat == inputPixelFormat);
208*0ec5a0ecSAndroid Build Coastguard Worker 
209*0ec5a0ecSAndroid Build Coastguard Worker     if (mInputQueue->allocateBuffers(kNumInputBuffers, V4L2_MEMORY_DMABUF) == 0) {
210*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to allocate input buffer.");
211*0ec5a0ecSAndroid Build Coastguard Worker         return false;
212*0ec5a0ecSAndroid Build Coastguard Worker     }
213*0ec5a0ecSAndroid Build Coastguard Worker     if (!mInputQueue->streamon()) {
214*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to streamon input queue.");
215*0ec5a0ecSAndroid Build Coastguard Worker         return false;
216*0ec5a0ecSAndroid Build Coastguard Worker     }
217*0ec5a0ecSAndroid Build Coastguard Worker     return true;
218*0ec5a0ecSAndroid Build Coastguard Worker }
219*0ec5a0ecSAndroid Build Coastguard Worker 
setupInitialOutput()220*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Decoder::setupInitialOutput() {
221*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
222*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
223*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
224*0ec5a0ecSAndroid Build Coastguard Worker 
225*0ec5a0ecSAndroid Build Coastguard Worker     if (!setupMinimalOutputFormat()) {
226*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to set minimal resolution for initial output buffers");
227*0ec5a0ecSAndroid Build Coastguard Worker         return false;
228*0ec5a0ecSAndroid Build Coastguard Worker     }
229*0ec5a0ecSAndroid Build Coastguard Worker 
230*0ec5a0ecSAndroid Build Coastguard Worker     if (!startOutputQueue(1, V4L2_MEMORY_DMABUF)) {
231*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to start initialy output queue");
232*0ec5a0ecSAndroid Build Coastguard Worker         return false;
233*0ec5a0ecSAndroid Build Coastguard Worker     }
234*0ec5a0ecSAndroid Build Coastguard Worker 
235*0ec5a0ecSAndroid Build Coastguard Worker     std::optional<V4L2WritableBufferRef> eosBuffer = mOutputQueue->getFreeBuffer();
236*0ec5a0ecSAndroid Build Coastguard Worker     if (!eosBuffer) {
237*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to acquire initial EOS buffer");
238*0ec5a0ecSAndroid Build Coastguard Worker         return false;
239*0ec5a0ecSAndroid Build Coastguard Worker     }
240*0ec5a0ecSAndroid Build Coastguard Worker 
241*0ec5a0ecSAndroid Build Coastguard Worker     mInitialEosBuffer =
242*0ec5a0ecSAndroid Build Coastguard Worker             new GraphicBuffer(mCodedSize.getWidth(), mCodedSize.getHeight(),
243*0ec5a0ecSAndroid Build Coastguard Worker                               static_cast<PixelFormat>(HalPixelFormat::YCBCR_420_888),
244*0ec5a0ecSAndroid Build Coastguard Worker                               GraphicBuffer::USAGE_HW_VIDEO_ENCODER, "V4L2DecodeComponent");
245*0ec5a0ecSAndroid Build Coastguard Worker 
246*0ec5a0ecSAndroid Build Coastguard Worker     if (mInitialEosBuffer->initCheck() != NO_ERROR) {
247*0ec5a0ecSAndroid Build Coastguard Worker         return false;
248*0ec5a0ecSAndroid Build Coastguard Worker     }
249*0ec5a0ecSAndroid Build Coastguard Worker 
250*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<int> fds;
251*0ec5a0ecSAndroid Build Coastguard Worker     for (size_t i = 0; i < mInitialEosBuffer->handle->numFds; i++) {
252*0ec5a0ecSAndroid Build Coastguard Worker         fds.push_back(mInitialEosBuffer->handle->data[i]);
253*0ec5a0ecSAndroid Build Coastguard Worker     }
254*0ec5a0ecSAndroid Build Coastguard Worker 
255*0ec5a0ecSAndroid Build Coastguard Worker     if (!std::move(*eosBuffer).queueDMABuf(fds)) {
256*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to queue initial EOS buffer");
257*0ec5a0ecSAndroid Build Coastguard Worker         return false;
258*0ec5a0ecSAndroid Build Coastguard Worker     }
259*0ec5a0ecSAndroid Build Coastguard Worker 
260*0ec5a0ecSAndroid Build Coastguard Worker     return true;
261*0ec5a0ecSAndroid Build Coastguard Worker }
262*0ec5a0ecSAndroid Build Coastguard Worker 
setupMinimalOutputFormat()263*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Decoder::setupMinimalOutputFormat() {
264*0ec5a0ecSAndroid Build Coastguard Worker     ui::Size minResolution, maxResolution;
265*0ec5a0ecSAndroid Build Coastguard Worker 
266*0ec5a0ecSAndroid Build Coastguard Worker     for (const uint32_t& pixfmt :
267*0ec5a0ecSAndroid Build Coastguard Worker          mDevice->enumerateSupportedPixelformats(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
268*0ec5a0ecSAndroid Build Coastguard Worker         if (std::find(kSupportedOutputFourccs.begin(), kSupportedOutputFourccs.end(), pixfmt) ==
269*0ec5a0ecSAndroid Build Coastguard Worker             kSupportedOutputFourccs.end()) {
270*0ec5a0ecSAndroid Build Coastguard Worker             ALOGD("Pixel format %s is not supported, skipping...", fourccToString(pixfmt).c_str());
271*0ec5a0ecSAndroid Build Coastguard Worker             continue;
272*0ec5a0ecSAndroid Build Coastguard Worker         }
273*0ec5a0ecSAndroid Build Coastguard Worker 
274*0ec5a0ecSAndroid Build Coastguard Worker         mDevice->getSupportedResolution(pixfmt, &minResolution, &maxResolution);
275*0ec5a0ecSAndroid Build Coastguard Worker         if (minResolution.isEmpty()) {
276*0ec5a0ecSAndroid Build Coastguard Worker             minResolution.set(128, 128);
277*0ec5a0ecSAndroid Build Coastguard Worker         }
278*0ec5a0ecSAndroid Build Coastguard Worker 
279*0ec5a0ecSAndroid Build Coastguard Worker         if (mOutputQueue->setFormat(pixfmt, minResolution, 0) != std::nullopt) {
280*0ec5a0ecSAndroid Build Coastguard Worker             return true;
281*0ec5a0ecSAndroid Build Coastguard Worker         }
282*0ec5a0ecSAndroid Build Coastguard Worker     }
283*0ec5a0ecSAndroid Build Coastguard Worker 
284*0ec5a0ecSAndroid Build Coastguard Worker     ALOGE("Failed to find supported pixel format");
285*0ec5a0ecSAndroid Build Coastguard Worker     return false;
286*0ec5a0ecSAndroid Build Coastguard Worker }
287*0ec5a0ecSAndroid Build Coastguard Worker 
startOutputQueue(size_t minOutputBuffersCount,enum v4l2_memory memory)288*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Decoder::startOutputQueue(size_t minOutputBuffersCount, enum v4l2_memory memory) {
289*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
290*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
291*0ec5a0ecSAndroid Build Coastguard Worker 
292*0ec5a0ecSAndroid Build Coastguard Worker     const std::optional<struct v4l2_format> format = getFormatInfo();
293*0ec5a0ecSAndroid Build Coastguard Worker     std::optional<size_t> numOutputBuffers = getNumOutputBuffers();
294*0ec5a0ecSAndroid Build Coastguard Worker     if (!format || !numOutputBuffers) {
295*0ec5a0ecSAndroid Build Coastguard Worker         return false;
296*0ec5a0ecSAndroid Build Coastguard Worker     }
297*0ec5a0ecSAndroid Build Coastguard Worker     *numOutputBuffers = std::max(*numOutputBuffers, minOutputBuffersCount);
298*0ec5a0ecSAndroid Build Coastguard Worker 
299*0ec5a0ecSAndroid Build Coastguard Worker     const ui::Size codedSize(format->fmt.pix_mp.width, format->fmt.pix_mp.height);
300*0ec5a0ecSAndroid Build Coastguard Worker     if (!setupOutputFormat(codedSize)) {
301*0ec5a0ecSAndroid Build Coastguard Worker         return false;
302*0ec5a0ecSAndroid Build Coastguard Worker     }
303*0ec5a0ecSAndroid Build Coastguard Worker 
304*0ec5a0ecSAndroid Build Coastguard Worker     const std::optional<struct v4l2_format> adjustedFormat = getFormatInfo();
305*0ec5a0ecSAndroid Build Coastguard Worker     if (!adjustedFormat) {
306*0ec5a0ecSAndroid Build Coastguard Worker         return false;
307*0ec5a0ecSAndroid Build Coastguard Worker     }
308*0ec5a0ecSAndroid Build Coastguard Worker     mCodedSize.set(adjustedFormat->fmt.pix_mp.width, adjustedFormat->fmt.pix_mp.height);
309*0ec5a0ecSAndroid Build Coastguard Worker     mVisibleRect = getVisibleRect(mCodedSize);
310*0ec5a0ecSAndroid Build Coastguard Worker 
311*0ec5a0ecSAndroid Build Coastguard Worker     ALOGI("Need %zu output buffers. coded size: %s, visible rect: %s", *numOutputBuffers,
312*0ec5a0ecSAndroid Build Coastguard Worker           toString(mCodedSize).c_str(), toString(mVisibleRect).c_str());
313*0ec5a0ecSAndroid Build Coastguard Worker     if (isEmpty(mCodedSize)) {
314*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to get resolution from V4L2 driver.");
315*0ec5a0ecSAndroid Build Coastguard Worker         return false;
316*0ec5a0ecSAndroid Build Coastguard Worker     }
317*0ec5a0ecSAndroid Build Coastguard Worker 
318*0ec5a0ecSAndroid Build Coastguard Worker     if (mOutputQueue->isStreaming()) {
319*0ec5a0ecSAndroid Build Coastguard Worker         mOutputQueue->streamoff();
320*0ec5a0ecSAndroid Build Coastguard Worker     }
321*0ec5a0ecSAndroid Build Coastguard Worker     if (mOutputQueue->allocatedBuffersCount() > 0) {
322*0ec5a0ecSAndroid Build Coastguard Worker         mOutputQueue->deallocateBuffers();
323*0ec5a0ecSAndroid Build Coastguard Worker     }
324*0ec5a0ecSAndroid Build Coastguard Worker 
325*0ec5a0ecSAndroid Build Coastguard Worker     mFrameAtDevice.clear();
326*0ec5a0ecSAndroid Build Coastguard Worker     mBlockIdToV4L2Id.clear();
327*0ec5a0ecSAndroid Build Coastguard Worker     while (!mReuseFrameQueue.empty()) {
328*0ec5a0ecSAndroid Build Coastguard Worker         mReuseFrameQueue.pop();
329*0ec5a0ecSAndroid Build Coastguard Worker     }
330*0ec5a0ecSAndroid Build Coastguard Worker 
331*0ec5a0ecSAndroid Build Coastguard Worker     const size_t adjustedNumOutputBuffers =
332*0ec5a0ecSAndroid Build Coastguard Worker             mOutputQueue->allocateBuffers(*numOutputBuffers, memory);
333*0ec5a0ecSAndroid Build Coastguard Worker     if (adjustedNumOutputBuffers == 0) {
334*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to allocate output buffer.");
335*0ec5a0ecSAndroid Build Coastguard Worker         return false;
336*0ec5a0ecSAndroid Build Coastguard Worker     }
337*0ec5a0ecSAndroid Build Coastguard Worker 
338*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("Allocated %zu output buffers.", adjustedNumOutputBuffers);
339*0ec5a0ecSAndroid Build Coastguard Worker     if (!mOutputQueue->streamon()) {
340*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to streamon output queue.");
341*0ec5a0ecSAndroid Build Coastguard Worker         return false;
342*0ec5a0ecSAndroid Build Coastguard Worker     }
343*0ec5a0ecSAndroid Build Coastguard Worker 
344*0ec5a0ecSAndroid Build Coastguard Worker     return true;
345*0ec5a0ecSAndroid Build Coastguard Worker }
346*0ec5a0ecSAndroid Build Coastguard Worker 
decode(std::unique_ptr<ConstBitstreamBuffer> buffer,DecodeCB decodeCb)347*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Decoder::decode(std::unique_ptr<ConstBitstreamBuffer> buffer, DecodeCB decodeCb) {
348*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
349*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(id=%d)", __func__, buffer->id);
350*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
351*0ec5a0ecSAndroid Build Coastguard Worker 
352*0ec5a0ecSAndroid Build Coastguard Worker     if (mState == State::Error) {
353*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Ignore due to error state.");
354*0ec5a0ecSAndroid Build Coastguard Worker         mTaskRunner->PostTask(FROM_HERE, ::base::BindOnce(std::move(decodeCb),
355*0ec5a0ecSAndroid Build Coastguard Worker                                                           VideoDecoder::DecodeStatus::kError));
356*0ec5a0ecSAndroid Build Coastguard Worker         return;
357*0ec5a0ecSAndroid Build Coastguard Worker     }
358*0ec5a0ecSAndroid Build Coastguard Worker 
359*0ec5a0ecSAndroid Build Coastguard Worker     if (mState == State::Idle) {
360*0ec5a0ecSAndroid Build Coastguard Worker         setState(State::Decoding);
361*0ec5a0ecSAndroid Build Coastguard Worker     }
362*0ec5a0ecSAndroid Build Coastguard Worker 
363*0ec5a0ecSAndroid Build Coastguard Worker     // To determine if the DRC is pending, the access to the frame data is
364*0ec5a0ecSAndroid Build Coastguard Worker     // required. It's not possible to access the frame directly for the secure
365*0ec5a0ecSAndroid Build Coastguard Worker     // playback, so this check must be skipped. b/279834186
366*0ec5a0ecSAndroid Build Coastguard Worker     if (!mIsSecure && mInitialEosBuffer && !mPendingDRC)
367*0ec5a0ecSAndroid Build Coastguard Worker         mPendingDRC = waitForDRC(buffer->dmabuf, mCodec);
368*0ec5a0ecSAndroid Build Coastguard Worker 
369*0ec5a0ecSAndroid Build Coastguard Worker     mDecodeRequests.push(DecodeRequest(std::move(buffer), std::move(decodeCb)));
370*0ec5a0ecSAndroid Build Coastguard Worker     pumpDecodeRequest();
371*0ec5a0ecSAndroid Build Coastguard Worker }
372*0ec5a0ecSAndroid Build Coastguard Worker 
drain(DecodeCB drainCb)373*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Decoder::drain(DecodeCB drainCb) {
374*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
375*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
376*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
377*0ec5a0ecSAndroid Build Coastguard Worker 
378*0ec5a0ecSAndroid Build Coastguard Worker     switch (mState) {
379*0ec5a0ecSAndroid Build Coastguard Worker     case State::Idle:
380*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Nothing need to drain, ignore.");
381*0ec5a0ecSAndroid Build Coastguard Worker         mTaskRunner->PostTask(
382*0ec5a0ecSAndroid Build Coastguard Worker                 FROM_HERE, ::base::BindOnce(std::move(drainCb), VideoDecoder::DecodeStatus::kOk));
383*0ec5a0ecSAndroid Build Coastguard Worker         return;
384*0ec5a0ecSAndroid Build Coastguard Worker 
385*0ec5a0ecSAndroid Build Coastguard Worker     case State::Decoding:
386*0ec5a0ecSAndroid Build Coastguard Worker         mDecodeRequests.push(DecodeRequest(nullptr, std::move(drainCb)));
387*0ec5a0ecSAndroid Build Coastguard Worker         pumpDecodeRequest();
388*0ec5a0ecSAndroid Build Coastguard Worker         return;
389*0ec5a0ecSAndroid Build Coastguard Worker 
390*0ec5a0ecSAndroid Build Coastguard Worker     case State::Draining:
391*0ec5a0ecSAndroid Build Coastguard Worker     case State::Error:
392*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Ignore due to wrong state: %s", StateToString(mState));
393*0ec5a0ecSAndroid Build Coastguard Worker         mTaskRunner->PostTask(FROM_HERE, ::base::BindOnce(std::move(drainCb),
394*0ec5a0ecSAndroid Build Coastguard Worker                                                           VideoDecoder::DecodeStatus::kError));
395*0ec5a0ecSAndroid Build Coastguard Worker         return;
396*0ec5a0ecSAndroid Build Coastguard Worker     }
397*0ec5a0ecSAndroid Build Coastguard Worker }
398*0ec5a0ecSAndroid Build Coastguard Worker 
pumpDecodeRequest()399*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Decoder::pumpDecodeRequest() {
400*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
401*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
402*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
403*0ec5a0ecSAndroid Build Coastguard Worker 
404*0ec5a0ecSAndroid Build Coastguard Worker     if (mState != State::Decoding) return;
405*0ec5a0ecSAndroid Build Coastguard Worker 
406*0ec5a0ecSAndroid Build Coastguard Worker     while (!mDecodeRequests.empty()) {
407*0ec5a0ecSAndroid Build Coastguard Worker         // Drain the decoder.
408*0ec5a0ecSAndroid Build Coastguard Worker         if (mDecodeRequests.front().buffer == nullptr) {
409*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("Get drain request.");
410*0ec5a0ecSAndroid Build Coastguard Worker             // Send the flush command after all input buffers are dequeued. This makes
411*0ec5a0ecSAndroid Build Coastguard Worker             // sure all previous resolution changes have been handled because the
412*0ec5a0ecSAndroid Build Coastguard Worker             // driver must hold the input buffer that triggers resolution change. The
413*0ec5a0ecSAndroid Build Coastguard Worker             // driver cannot decode data in it without new output buffers. If we send
414*0ec5a0ecSAndroid Build Coastguard Worker             // the flush now and a queued input buffer triggers resolution change
415*0ec5a0ecSAndroid Build Coastguard Worker             // later, the driver will send an output buffer that has
416*0ec5a0ecSAndroid Build Coastguard Worker             // V4L2_BUF_FLAG_LAST. But some queued input buffer have not been decoded
417*0ec5a0ecSAndroid Build Coastguard Worker             // yet. Also, V4L2VDA calls STREAMOFF and STREAMON after resolution
418*0ec5a0ecSAndroid Build Coastguard Worker             // change. They implicitly send a V4L2_DEC_CMD_STOP and V4L2_DEC_CMD_START
419*0ec5a0ecSAndroid Build Coastguard Worker             // to the decoder.
420*0ec5a0ecSAndroid Build Coastguard Worker             if (mInputQueue->queuedBuffersCount() > 0) {
421*0ec5a0ecSAndroid Build Coastguard Worker                 ALOGV("Wait for all input buffers dequeued.");
422*0ec5a0ecSAndroid Build Coastguard Worker                 return;
423*0ec5a0ecSAndroid Build Coastguard Worker             }
424*0ec5a0ecSAndroid Build Coastguard Worker 
425*0ec5a0ecSAndroid Build Coastguard Worker             // If output queue is not streaming, then device is unable to notify
426*0ec5a0ecSAndroid Build Coastguard Worker             // whenever draining is finished. (EOS frame cannot be dequeued).
427*0ec5a0ecSAndroid Build Coastguard Worker             // This is likely to happen in the event of that the first resolution
428*0ec5a0ecSAndroid Build Coastguard Worker             // change event wasn't dequeued before the drain request.
429*0ec5a0ecSAndroid Build Coastguard Worker             if (!mOutputQueue->isStreaming()) {
430*0ec5a0ecSAndroid Build Coastguard Worker                 ALOGV("Wait for output queue to start streaming");
431*0ec5a0ecSAndroid Build Coastguard Worker                 return;
432*0ec5a0ecSAndroid Build Coastguard Worker             }
433*0ec5a0ecSAndroid Build Coastguard Worker 
434*0ec5a0ecSAndroid Build Coastguard Worker             auto request = std::move(mDecodeRequests.front());
435*0ec5a0ecSAndroid Build Coastguard Worker             mDecodeRequests.pop();
436*0ec5a0ecSAndroid Build Coastguard Worker 
437*0ec5a0ecSAndroid Build Coastguard Worker             // There is one more case that EOS frame cannot be dequeued because
438*0ec5a0ecSAndroid Build Coastguard Worker             // the first resolution change event wasn't dequeued before - output
439*0ec5a0ecSAndroid Build Coastguard Worker             // queues on the host are not streaming but ARCVM has no knowledge about
440*0ec5a0ecSAndroid Build Coastguard Worker             // it. Check if first resolution change event was received and if there
441*0ec5a0ecSAndroid Build Coastguard Worker             // was no previously sent non-empty frame (other than SPS/PPS/EOS) that
442*0ec5a0ecSAndroid Build Coastguard Worker             // may trigger config from host side.
443*0ec5a0ecSAndroid Build Coastguard Worker             // Drain can only be finished if we are sure there was no stream = no
444*0ec5a0ecSAndroid Build Coastguard Worker             // single frame in the stack.
445*0ec5a0ecSAndroid Build Coastguard Worker             if (mInitialEosBuffer && !mPendingDRC) {
446*0ec5a0ecSAndroid Build Coastguard Worker                 ALOGV("Terminate drain, because there was no stream");
447*0ec5a0ecSAndroid Build Coastguard Worker                 mTaskRunner->PostTask(FROM_HERE, ::base::BindOnce(std::move(request.decodeCb),
448*0ec5a0ecSAndroid Build Coastguard Worker                                                                   VideoDecoder::DecodeStatus::kOk));
449*0ec5a0ecSAndroid Build Coastguard Worker                 return;
450*0ec5a0ecSAndroid Build Coastguard Worker             }
451*0ec5a0ecSAndroid Build Coastguard Worker 
452*0ec5a0ecSAndroid Build Coastguard Worker             if (!sendV4L2DecoderCmd(false)) {
453*0ec5a0ecSAndroid Build Coastguard Worker                 std::move(request.decodeCb).Run(VideoDecoder::DecodeStatus::kError);
454*0ec5a0ecSAndroid Build Coastguard Worker                 onError();
455*0ec5a0ecSAndroid Build Coastguard Worker                 return;
456*0ec5a0ecSAndroid Build Coastguard Worker             }
457*0ec5a0ecSAndroid Build Coastguard Worker             mDrainCb = std::move(request.decodeCb);
458*0ec5a0ecSAndroid Build Coastguard Worker             setState(State::Draining);
459*0ec5a0ecSAndroid Build Coastguard Worker             return;
460*0ec5a0ecSAndroid Build Coastguard Worker         }
461*0ec5a0ecSAndroid Build Coastguard Worker 
462*0ec5a0ecSAndroid Build Coastguard Worker         auto dma_buf_id = getDmabufId(mDecodeRequests.front().buffer->dmabuf.handle()->data[0]);
463*0ec5a0ecSAndroid Build Coastguard Worker         if (!dma_buf_id) {
464*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Failed to get dmabuf id");
465*0ec5a0ecSAndroid Build Coastguard Worker             onError();
466*0ec5a0ecSAndroid Build Coastguard Worker             return;
467*0ec5a0ecSAndroid Build Coastguard Worker         }
468*0ec5a0ecSAndroid Build Coastguard Worker 
469*0ec5a0ecSAndroid Build Coastguard Worker         std::optional<V4L2WritableBufferRef> inputBuffer;
470*0ec5a0ecSAndroid Build Coastguard Worker         size_t targetIndex = 0;
471*0ec5a0ecSAndroid Build Coastguard Worker 
472*0ec5a0ecSAndroid Build Coastguard Worker         // If there's an existing input buffer for this dma buffer, use it.
473*0ec5a0ecSAndroid Build Coastguard Worker         for (; targetIndex < mNextInputBufferId; targetIndex++) {
474*0ec5a0ecSAndroid Build Coastguard Worker             if (mLastDmaBufferId[targetIndex] == dma_buf_id) {
475*0ec5a0ecSAndroid Build Coastguard Worker                 break;
476*0ec5a0ecSAndroid Build Coastguard Worker             }
477*0ec5a0ecSAndroid Build Coastguard Worker         }
478*0ec5a0ecSAndroid Build Coastguard Worker 
479*0ec5a0ecSAndroid Build Coastguard Worker         if (targetIndex < kNumInputBuffers) {
480*0ec5a0ecSAndroid Build Coastguard Worker             // If we didn't find a buffer and there is an unused buffer, use that one.
481*0ec5a0ecSAndroid Build Coastguard Worker             if (targetIndex == mNextInputBufferId) {
482*0ec5a0ecSAndroid Build Coastguard Worker                 mNextInputBufferId++;
483*0ec5a0ecSAndroid Build Coastguard Worker             }
484*0ec5a0ecSAndroid Build Coastguard Worker 
485*0ec5a0ecSAndroid Build Coastguard Worker             inputBuffer = mInputQueue->getFreeBuffer(targetIndex);
486*0ec5a0ecSAndroid Build Coastguard Worker         }
487*0ec5a0ecSAndroid Build Coastguard Worker 
488*0ec5a0ecSAndroid Build Coastguard Worker         // If we didn't find a reusable/unused input buffer, clobber a free one.
489*0ec5a0ecSAndroid Build Coastguard Worker         if (!inputBuffer) {
490*0ec5a0ecSAndroid Build Coastguard Worker             inputBuffer = mInputQueue->getFreeBuffer();
491*0ec5a0ecSAndroid Build Coastguard Worker         }
492*0ec5a0ecSAndroid Build Coastguard Worker 
493*0ec5a0ecSAndroid Build Coastguard Worker         // Pause if no free input buffer. We resume decoding after dequeueing input buffers.
494*0ec5a0ecSAndroid Build Coastguard Worker         if (!inputBuffer) {
495*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("There is no free input buffer.");
496*0ec5a0ecSAndroid Build Coastguard Worker             return;
497*0ec5a0ecSAndroid Build Coastguard Worker         }
498*0ec5a0ecSAndroid Build Coastguard Worker 
499*0ec5a0ecSAndroid Build Coastguard Worker         mLastDmaBufferId[inputBuffer->bufferId()] = *dma_buf_id;
500*0ec5a0ecSAndroid Build Coastguard Worker 
501*0ec5a0ecSAndroid Build Coastguard Worker         auto request = std::move(mDecodeRequests.front());
502*0ec5a0ecSAndroid Build Coastguard Worker         mDecodeRequests.pop();
503*0ec5a0ecSAndroid Build Coastguard Worker 
504*0ec5a0ecSAndroid Build Coastguard Worker         const int32_t bitstreamId = request.buffer->id;
505*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("QBUF to input queue, bitstreadId=%d", bitstreamId);
506*0ec5a0ecSAndroid Build Coastguard Worker         inputBuffer->setTimeStamp({.tv_sec = bitstreamId});
507*0ec5a0ecSAndroid Build Coastguard Worker         size_t planeSize = inputBuffer->getPlaneSize(0);
508*0ec5a0ecSAndroid Build Coastguard Worker         if (request.buffer->size > planeSize) {
509*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("The input size (%zu) is not enough, we need %zu", planeSize,
510*0ec5a0ecSAndroid Build Coastguard Worker                   request.buffer->size);
511*0ec5a0ecSAndroid Build Coastguard Worker             onError();
512*0ec5a0ecSAndroid Build Coastguard Worker             return;
513*0ec5a0ecSAndroid Build Coastguard Worker         }
514*0ec5a0ecSAndroid Build Coastguard Worker 
515*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Set bytes_used=%zu, offset=%zu", request.buffer->offset + request.buffer->size,
516*0ec5a0ecSAndroid Build Coastguard Worker               request.buffer->offset);
517*0ec5a0ecSAndroid Build Coastguard Worker         inputBuffer->setPlaneDataOffset(0, request.buffer->offset);
518*0ec5a0ecSAndroid Build Coastguard Worker         inputBuffer->setPlaneBytesUsed(0, request.buffer->offset + request.buffer->size);
519*0ec5a0ecSAndroid Build Coastguard Worker         std::vector<int> fds;
520*0ec5a0ecSAndroid Build Coastguard Worker         fds.push_back(std::move(request.buffer->dmabuf.handle()->data[0]));
521*0ec5a0ecSAndroid Build Coastguard Worker         if (!std::move(*inputBuffer).queueDMABuf(fds)) {
522*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("%s(): Failed to QBUF to input queue, bitstreamId=%d", __func__, bitstreamId);
523*0ec5a0ecSAndroid Build Coastguard Worker             onError();
524*0ec5a0ecSAndroid Build Coastguard Worker             return;
525*0ec5a0ecSAndroid Build Coastguard Worker         }
526*0ec5a0ecSAndroid Build Coastguard Worker 
527*0ec5a0ecSAndroid Build Coastguard Worker         mPendingDecodeCbs.insert(std::make_pair(bitstreamId, std::move(request.decodeCb)));
528*0ec5a0ecSAndroid Build Coastguard Worker     }
529*0ec5a0ecSAndroid Build Coastguard Worker }
530*0ec5a0ecSAndroid Build Coastguard Worker 
flush()531*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Decoder::flush() {
532*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
533*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
534*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
535*0ec5a0ecSAndroid Build Coastguard Worker 
536*0ec5a0ecSAndroid Build Coastguard Worker     if (mState == State::Idle) {
537*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Nothing need to flush, ignore.");
538*0ec5a0ecSAndroid Build Coastguard Worker         return;
539*0ec5a0ecSAndroid Build Coastguard Worker     }
540*0ec5a0ecSAndroid Build Coastguard Worker     if (mState == State::Error) {
541*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Ignore due to error state.");
542*0ec5a0ecSAndroid Build Coastguard Worker         return;
543*0ec5a0ecSAndroid Build Coastguard Worker     }
544*0ec5a0ecSAndroid Build Coastguard Worker 
545*0ec5a0ecSAndroid Build Coastguard Worker     // Call all pending callbacks.
546*0ec5a0ecSAndroid Build Coastguard Worker     for (auto& item : mPendingDecodeCbs) {
547*0ec5a0ecSAndroid Build Coastguard Worker         std::move(item.second).Run(VideoDecoder::DecodeStatus::kAborted);
548*0ec5a0ecSAndroid Build Coastguard Worker     }
549*0ec5a0ecSAndroid Build Coastguard Worker     mPendingDecodeCbs.clear();
550*0ec5a0ecSAndroid Build Coastguard Worker     if (mDrainCb) {
551*0ec5a0ecSAndroid Build Coastguard Worker         std::move(mDrainCb).Run(VideoDecoder::DecodeStatus::kAborted);
552*0ec5a0ecSAndroid Build Coastguard Worker     }
553*0ec5a0ecSAndroid Build Coastguard Worker 
554*0ec5a0ecSAndroid Build Coastguard Worker     // Streamoff both V4L2 queues to drop input and output buffers.
555*0ec5a0ecSAndroid Build Coastguard Worker     const bool isOutputStreaming = mOutputQueue->isStreaming();
556*0ec5a0ecSAndroid Build Coastguard Worker     mDevice->stopPolling();
557*0ec5a0ecSAndroid Build Coastguard Worker     mOutputQueue->streamoff();
558*0ec5a0ecSAndroid Build Coastguard Worker 
559*0ec5a0ecSAndroid Build Coastguard Worker     // Extract currently enqueued output picture buffers to be queued later first.
560*0ec5a0ecSAndroid Build Coastguard Worker     // See b/270003218 and b/297228544.
561*0ec5a0ecSAndroid Build Coastguard Worker     for (auto& [v4l2Id, frame] : mFrameAtDevice) {
562*0ec5a0ecSAndroid Build Coastguard Worker         // Find corresponding mapping block ID (DMABUF ID) to V4L2 buffer ID.
563*0ec5a0ecSAndroid Build Coastguard Worker         // The buffer was enqueued to device therefore such mapping have to exist.
564*0ec5a0ecSAndroid Build Coastguard Worker         auto blockIdIter =
565*0ec5a0ecSAndroid Build Coastguard Worker                 std::find_if(mBlockIdToV4L2Id.begin(), mBlockIdToV4L2Id.end(),
566*0ec5a0ecSAndroid Build Coastguard Worker                              [v4l2Id = v4l2Id](const auto& el) { return el.second == v4l2Id; });
567*0ec5a0ecSAndroid Build Coastguard Worker 
568*0ec5a0ecSAndroid Build Coastguard Worker         ALOG_ASSERT(blockIdIter != mBlockIdToV4L2Id.end());
569*0ec5a0ecSAndroid Build Coastguard Worker         size_t blockId = blockIdIter->first;
570*0ec5a0ecSAndroid Build Coastguard Worker         mReuseFrameQueue.push(std::make_pair(blockId, std::move(frame)));
571*0ec5a0ecSAndroid Build Coastguard Worker     }
572*0ec5a0ecSAndroid Build Coastguard Worker     mFrameAtDevice.clear();
573*0ec5a0ecSAndroid Build Coastguard Worker 
574*0ec5a0ecSAndroid Build Coastguard Worker     mInputQueue->streamoff();
575*0ec5a0ecSAndroid Build Coastguard Worker 
576*0ec5a0ecSAndroid Build Coastguard Worker     // Streamon both V4L2 queues.
577*0ec5a0ecSAndroid Build Coastguard Worker     mInputQueue->streamon();
578*0ec5a0ecSAndroid Build Coastguard Worker     if (isOutputStreaming) {
579*0ec5a0ecSAndroid Build Coastguard Worker         mOutputQueue->streamon();
580*0ec5a0ecSAndroid Build Coastguard Worker     }
581*0ec5a0ecSAndroid Build Coastguard Worker 
582*0ec5a0ecSAndroid Build Coastguard Worker     // If there is no free buffer at mOutputQueue, tryFetchVideoFrame() should be triggerred after
583*0ec5a0ecSAndroid Build Coastguard Worker     // a buffer is DQBUF from output queue. Now all the buffers are dropped at mOutputQueue, we
584*0ec5a0ecSAndroid Build Coastguard Worker     // have to trigger tryFetchVideoFrame() here.
585*0ec5a0ecSAndroid Build Coastguard Worker     if (mVideoFramePool) {
586*0ec5a0ecSAndroid Build Coastguard Worker         tryFetchVideoFrame();
587*0ec5a0ecSAndroid Build Coastguard Worker     }
588*0ec5a0ecSAndroid Build Coastguard Worker 
589*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDevice->startPolling(mTaskRunner,
590*0ec5a0ecSAndroid Build Coastguard Worker                                ::base::BindRepeating(&V4L2Decoder::serviceDeviceTask, mWeakThis),
591*0ec5a0ecSAndroid Build Coastguard Worker                                ::base::BindRepeating(&V4L2Decoder::onError, mWeakThis))) {
592*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to start polling V4L2 device.");
593*0ec5a0ecSAndroid Build Coastguard Worker         onError();
594*0ec5a0ecSAndroid Build Coastguard Worker         return;
595*0ec5a0ecSAndroid Build Coastguard Worker     }
596*0ec5a0ecSAndroid Build Coastguard Worker 
597*0ec5a0ecSAndroid Build Coastguard Worker     setState(State::Idle);
598*0ec5a0ecSAndroid Build Coastguard Worker }
599*0ec5a0ecSAndroid Build Coastguard Worker 
serviceDeviceTask(bool event)600*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Decoder::serviceDeviceTask(bool event) {
601*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
602*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(event=%d) state=%s InputQueue(%s):%zu+%zu/%zu, OutputQueue(%s):%zu+%zu/%zu", __func__,
603*0ec5a0ecSAndroid Build Coastguard Worker           event, StateToString(mState), (mInputQueue->isStreaming() ? "streamon" : "streamoff"),
604*0ec5a0ecSAndroid Build Coastguard Worker           mInputQueue->freeBuffersCount(), mInputQueue->queuedBuffersCount(),
605*0ec5a0ecSAndroid Build Coastguard Worker           mInputQueue->allocatedBuffersCount(),
606*0ec5a0ecSAndroid Build Coastguard Worker           (mOutputQueue->isStreaming() ? "streamon" : "streamoff"),
607*0ec5a0ecSAndroid Build Coastguard Worker           mOutputQueue->freeBuffersCount(), mOutputQueue->queuedBuffersCount(),
608*0ec5a0ecSAndroid Build Coastguard Worker           mOutputQueue->allocatedBuffersCount());
609*0ec5a0ecSAndroid Build Coastguard Worker 
610*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
611*0ec5a0ecSAndroid Build Coastguard Worker 
612*0ec5a0ecSAndroid Build Coastguard Worker     if (mState == State::Error) return;
613*0ec5a0ecSAndroid Build Coastguard Worker 
614*0ec5a0ecSAndroid Build Coastguard Worker     // Dequeue output and input queue.
615*0ec5a0ecSAndroid Build Coastguard Worker     bool inputDequeued = false;
616*0ec5a0ecSAndroid Build Coastguard Worker     while (mInputQueue->queuedBuffersCount() > 0) {
617*0ec5a0ecSAndroid Build Coastguard Worker         bool success;
618*0ec5a0ecSAndroid Build Coastguard Worker         V4L2ReadableBufferRef dequeuedBuffer;
619*0ec5a0ecSAndroid Build Coastguard Worker         std::tie(success, dequeuedBuffer) = mInputQueue->dequeueBuffer();
620*0ec5a0ecSAndroid Build Coastguard Worker         if (!success) {
621*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Failed to dequeue buffer from input queue.");
622*0ec5a0ecSAndroid Build Coastguard Worker             onError();
623*0ec5a0ecSAndroid Build Coastguard Worker             return;
624*0ec5a0ecSAndroid Build Coastguard Worker         }
625*0ec5a0ecSAndroid Build Coastguard Worker         if (!dequeuedBuffer) break;
626*0ec5a0ecSAndroid Build Coastguard Worker 
627*0ec5a0ecSAndroid Build Coastguard Worker         inputDequeued = true;
628*0ec5a0ecSAndroid Build Coastguard Worker 
629*0ec5a0ecSAndroid Build Coastguard Worker         // Run the corresponding decode callback.
630*0ec5a0ecSAndroid Build Coastguard Worker         int32_t id = dequeuedBuffer->getTimeStamp().tv_sec;
631*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("DQBUF from input queue, bitstreamId=%d", id);
632*0ec5a0ecSAndroid Build Coastguard Worker         auto it = mPendingDecodeCbs.find(id);
633*0ec5a0ecSAndroid Build Coastguard Worker         if (it == mPendingDecodeCbs.end()) {
634*0ec5a0ecSAndroid Build Coastguard Worker             ALOGW("Callback is already abandoned.");
635*0ec5a0ecSAndroid Build Coastguard Worker             continue;
636*0ec5a0ecSAndroid Build Coastguard Worker         }
637*0ec5a0ecSAndroid Build Coastguard Worker         std::move(it->second).Run(VideoDecoder::DecodeStatus::kOk);
638*0ec5a0ecSAndroid Build Coastguard Worker         mPendingDecodeCbs.erase(it);
639*0ec5a0ecSAndroid Build Coastguard Worker     }
640*0ec5a0ecSAndroid Build Coastguard Worker 
641*0ec5a0ecSAndroid Build Coastguard Worker     bool outputDequeued = false;
642*0ec5a0ecSAndroid Build Coastguard Worker     while (mOutputQueue->queuedBuffersCount() > 0) {
643*0ec5a0ecSAndroid Build Coastguard Worker         bool success;
644*0ec5a0ecSAndroid Build Coastguard Worker         V4L2ReadableBufferRef dequeuedBuffer;
645*0ec5a0ecSAndroid Build Coastguard Worker         std::tie(success, dequeuedBuffer) = mOutputQueue->dequeueBuffer();
646*0ec5a0ecSAndroid Build Coastguard Worker         if (!success) {
647*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Failed to dequeue buffer from output queue.");
648*0ec5a0ecSAndroid Build Coastguard Worker             onError();
649*0ec5a0ecSAndroid Build Coastguard Worker             return;
650*0ec5a0ecSAndroid Build Coastguard Worker         }
651*0ec5a0ecSAndroid Build Coastguard Worker         if (!dequeuedBuffer) break;
652*0ec5a0ecSAndroid Build Coastguard Worker 
653*0ec5a0ecSAndroid Build Coastguard Worker         outputDequeued = true;
654*0ec5a0ecSAndroid Build Coastguard Worker 
655*0ec5a0ecSAndroid Build Coastguard Worker         const size_t bufferId = dequeuedBuffer->bufferId();
656*0ec5a0ecSAndroid Build Coastguard Worker         const int32_t bitstreamId = static_cast<int32_t>(dequeuedBuffer->getTimeStamp().tv_sec);
657*0ec5a0ecSAndroid Build Coastguard Worker         const size_t bytesUsed = dequeuedBuffer->getPlaneBytesUsed(0);
658*0ec5a0ecSAndroid Build Coastguard Worker         const bool isLast = dequeuedBuffer->isLast();
659*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("DQBUF from output queue, bufferId=%zu, bitstreamId=%d, bytesused=%zu, isLast=%d",
660*0ec5a0ecSAndroid Build Coastguard Worker               bufferId, bitstreamId, bytesUsed, isLast);
661*0ec5a0ecSAndroid Build Coastguard Worker 
662*0ec5a0ecSAndroid Build Coastguard Worker         // Get the corresponding VideoFrame of the dequeued buffer.
663*0ec5a0ecSAndroid Build Coastguard Worker         auto it = mFrameAtDevice.find(bufferId);
664*0ec5a0ecSAndroid Build Coastguard Worker         ALOG_ASSERT(it != mFrameAtDevice.end(), "buffer %zu is not found at mFrameAtDevice",
665*0ec5a0ecSAndroid Build Coastguard Worker                     bufferId);
666*0ec5a0ecSAndroid Build Coastguard Worker         auto frame = std::move(it->second);
667*0ec5a0ecSAndroid Build Coastguard Worker         mFrameAtDevice.erase(it);
668*0ec5a0ecSAndroid Build Coastguard Worker 
669*0ec5a0ecSAndroid Build Coastguard Worker         if (bytesUsed > 0) {
670*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("Send output frame(bitstreamId=%d) to client", bitstreamId);
671*0ec5a0ecSAndroid Build Coastguard Worker             frame->setBitstreamId(bitstreamId);
672*0ec5a0ecSAndroid Build Coastguard Worker             frame->setVisibleRect(mVisibleRect);
673*0ec5a0ecSAndroid Build Coastguard Worker             mOutputCb.Run(std::move(frame));
674*0ec5a0ecSAndroid Build Coastguard Worker         } else {
675*0ec5a0ecSAndroid Build Coastguard Worker             // Workaround(b/168750131): If the buffer is not enqueued before the next drain is done,
676*0ec5a0ecSAndroid Build Coastguard Worker             // then the driver will fail to notify EOS. So we recycle the buffer immediately.
677*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("Recycle empty buffer %zu back to V4L2 output queue.", bufferId);
678*0ec5a0ecSAndroid Build Coastguard Worker             dequeuedBuffer.reset();
679*0ec5a0ecSAndroid Build Coastguard Worker             auto outputBuffer = mOutputQueue->getFreeBuffer(bufferId);
680*0ec5a0ecSAndroid Build Coastguard Worker             ALOG_ASSERT(outputBuffer, "V4L2 output queue slot %zu is not freed.", bufferId);
681*0ec5a0ecSAndroid Build Coastguard Worker 
682*0ec5a0ecSAndroid Build Coastguard Worker             if (!std::move(*outputBuffer).queueDMABuf(frame->getFDs())) {
683*0ec5a0ecSAndroid Build Coastguard Worker                 ALOGE("%s(): Failed to recycle empty buffer to output queue.", __func__);
684*0ec5a0ecSAndroid Build Coastguard Worker                 onError();
685*0ec5a0ecSAndroid Build Coastguard Worker                 return;
686*0ec5a0ecSAndroid Build Coastguard Worker             }
687*0ec5a0ecSAndroid Build Coastguard Worker             mFrameAtDevice.insert(std::make_pair(bufferId, std::move(frame)));
688*0ec5a0ecSAndroid Build Coastguard Worker         }
689*0ec5a0ecSAndroid Build Coastguard Worker 
690*0ec5a0ecSAndroid Build Coastguard Worker         if (mDrainCb && isLast) {
691*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("All buffers are drained.");
692*0ec5a0ecSAndroid Build Coastguard Worker             sendV4L2DecoderCmd(true);
693*0ec5a0ecSAndroid Build Coastguard Worker             std::move(mDrainCb).Run(VideoDecoder::DecodeStatus::kOk);
694*0ec5a0ecSAndroid Build Coastguard Worker             setState(State::Idle);
695*0ec5a0ecSAndroid Build Coastguard Worker         }
696*0ec5a0ecSAndroid Build Coastguard Worker     }
697*0ec5a0ecSAndroid Build Coastguard Worker 
698*0ec5a0ecSAndroid Build Coastguard Worker     // Handle resolution change event.
699*0ec5a0ecSAndroid Build Coastguard Worker     if (event && dequeueResolutionChangeEvent()) {
700*0ec5a0ecSAndroid Build Coastguard Worker         if (!changeResolution()) {
701*0ec5a0ecSAndroid Build Coastguard Worker             onError();
702*0ec5a0ecSAndroid Build Coastguard Worker             return;
703*0ec5a0ecSAndroid Build Coastguard Worker         }
704*0ec5a0ecSAndroid Build Coastguard Worker     }
705*0ec5a0ecSAndroid Build Coastguard Worker 
706*0ec5a0ecSAndroid Build Coastguard Worker     // We freed some input buffers, continue handling decode requests.
707*0ec5a0ecSAndroid Build Coastguard Worker     if (inputDequeued) {
708*0ec5a0ecSAndroid Build Coastguard Worker         mTaskRunner->PostTask(FROM_HERE,
709*0ec5a0ecSAndroid Build Coastguard Worker                               ::base::BindOnce(&V4L2Decoder::pumpDecodeRequest, mWeakThis));
710*0ec5a0ecSAndroid Build Coastguard Worker     }
711*0ec5a0ecSAndroid Build Coastguard Worker     // We free some output buffers, try to get VideoFrame.
712*0ec5a0ecSAndroid Build Coastguard Worker     if (outputDequeued) {
713*0ec5a0ecSAndroid Build Coastguard Worker         mTaskRunner->PostTask(FROM_HERE,
714*0ec5a0ecSAndroid Build Coastguard Worker                               ::base::BindOnce(&V4L2Decoder::tryFetchVideoFrame, mWeakThis));
715*0ec5a0ecSAndroid Build Coastguard Worker     }
716*0ec5a0ecSAndroid Build Coastguard Worker }
717*0ec5a0ecSAndroid Build Coastguard Worker 
dequeueResolutionChangeEvent()718*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Decoder::dequeueResolutionChangeEvent() {
719*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
720*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
721*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
722*0ec5a0ecSAndroid Build Coastguard Worker 
723*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_event ev;
724*0ec5a0ecSAndroid Build Coastguard Worker     memset(&ev, 0, sizeof(ev));
725*0ec5a0ecSAndroid Build Coastguard Worker     while (mDevice->ioctl(VIDIOC_DQEVENT, &ev) == 0) {
726*0ec5a0ecSAndroid Build Coastguard Worker         if (ev.type == V4L2_EVENT_SOURCE_CHANGE &&
727*0ec5a0ecSAndroid Build Coastguard Worker             ev.u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION) {
728*0ec5a0ecSAndroid Build Coastguard Worker             return true;
729*0ec5a0ecSAndroid Build Coastguard Worker         }
730*0ec5a0ecSAndroid Build Coastguard Worker     }
731*0ec5a0ecSAndroid Build Coastguard Worker     return false;
732*0ec5a0ecSAndroid Build Coastguard Worker }
733*0ec5a0ecSAndroid Build Coastguard Worker 
changeResolution()734*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Decoder::changeResolution() {
735*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
736*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
737*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
738*0ec5a0ecSAndroid Build Coastguard Worker 
739*0ec5a0ecSAndroid Build Coastguard Worker     if (mInitialEosBuffer) {
740*0ec5a0ecSAndroid Build Coastguard Worker         mInitialEosBuffer = nullptr;
741*0ec5a0ecSAndroid Build Coastguard Worker     }
742*0ec5a0ecSAndroid Build Coastguard Worker 
743*0ec5a0ecSAndroid Build Coastguard Worker     if (!startOutputQueue(mMinNumOutputBuffers, V4L2_MEMORY_DMABUF)) {
744*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to start output queue during DRC.");
745*0ec5a0ecSAndroid Build Coastguard Worker         return false;
746*0ec5a0ecSAndroid Build Coastguard Worker     }
747*0ec5a0ecSAndroid Build Coastguard Worker 
748*0ec5a0ecSAndroid Build Coastguard Worker     // If drain request is pending then it means that previous call to pumpDecodeRequest
749*0ec5a0ecSAndroid Build Coastguard Worker     // stalled the request, bacause there was no way of notifing the component that
750*0ec5a0ecSAndroid Build Coastguard Worker     // drain has finished. Send this request the drain to device.
751*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDecodeRequests.empty() && mDecodeRequests.front().buffer == nullptr) {
752*0ec5a0ecSAndroid Build Coastguard Worker         mTaskRunner->PostTask(FROM_HERE,
753*0ec5a0ecSAndroid Build Coastguard Worker                               ::base::BindOnce(&V4L2Decoder::pumpDecodeRequest, mWeakThis));
754*0ec5a0ecSAndroid Build Coastguard Worker     }
755*0ec5a0ecSAndroid Build Coastguard Worker 
756*0ec5a0ecSAndroid Build Coastguard Worker     // Release the previous VideoFramePool before getting a new one to guarantee only one pool
757*0ec5a0ecSAndroid Build Coastguard Worker     // exists at the same time.
758*0ec5a0ecSAndroid Build Coastguard Worker     mVideoFramePool.reset();
759*0ec5a0ecSAndroid Build Coastguard Worker     // Always use flexible pixel 420 format YCBCR_420_888 in Android.
760*0ec5a0ecSAndroid Build Coastguard Worker     mVideoFramePool = mGetPoolCb.Run(mCodedSize, HalPixelFormat::YCBCR_420_888,
761*0ec5a0ecSAndroid Build Coastguard Worker                                      mOutputQueue->allocatedBuffersCount());
762*0ec5a0ecSAndroid Build Coastguard Worker     if (!mVideoFramePool) {
763*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to get block pool with size: %s", toString(mCodedSize).c_str());
764*0ec5a0ecSAndroid Build Coastguard Worker         return false;
765*0ec5a0ecSAndroid Build Coastguard Worker     }
766*0ec5a0ecSAndroid Build Coastguard Worker 
767*0ec5a0ecSAndroid Build Coastguard Worker     tryFetchVideoFrame();
768*0ec5a0ecSAndroid Build Coastguard Worker     return true;
769*0ec5a0ecSAndroid Build Coastguard Worker }
770*0ec5a0ecSAndroid Build Coastguard Worker 
setupOutputFormat(const ui::Size & size)771*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Decoder::setupOutputFormat(const ui::Size& size) {
772*0ec5a0ecSAndroid Build Coastguard Worker     for (const uint32_t& pixfmt :
773*0ec5a0ecSAndroid Build Coastguard Worker          mDevice->enumerateSupportedPixelformats(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
774*0ec5a0ecSAndroid Build Coastguard Worker         if (std::find(kSupportedOutputFourccs.begin(), kSupportedOutputFourccs.end(), pixfmt) ==
775*0ec5a0ecSAndroid Build Coastguard Worker             kSupportedOutputFourccs.end()) {
776*0ec5a0ecSAndroid Build Coastguard Worker             ALOGD("Pixel format %s is not supported, skipping...", fourccToString(pixfmt).c_str());
777*0ec5a0ecSAndroid Build Coastguard Worker             continue;
778*0ec5a0ecSAndroid Build Coastguard Worker         }
779*0ec5a0ecSAndroid Build Coastguard Worker 
780*0ec5a0ecSAndroid Build Coastguard Worker         if (mOutputQueue->setFormat(pixfmt, size, 0) != std::nullopt) {
781*0ec5a0ecSAndroid Build Coastguard Worker             return true;
782*0ec5a0ecSAndroid Build Coastguard Worker         }
783*0ec5a0ecSAndroid Build Coastguard Worker     }
784*0ec5a0ecSAndroid Build Coastguard Worker 
785*0ec5a0ecSAndroid Build Coastguard Worker     ALOGE("Failed to find supported pixel format");
786*0ec5a0ecSAndroid Build Coastguard Worker     return false;
787*0ec5a0ecSAndroid Build Coastguard Worker }
788*0ec5a0ecSAndroid Build Coastguard Worker 
tryFetchVideoFrame()789*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Decoder::tryFetchVideoFrame() {
790*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
791*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
792*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
793*0ec5a0ecSAndroid Build Coastguard Worker 
794*0ec5a0ecSAndroid Build Coastguard Worker     if (!mVideoFramePool) {
795*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("mVideoFramePool is null, failed to get the instance after resolution change?");
796*0ec5a0ecSAndroid Build Coastguard Worker         onError();
797*0ec5a0ecSAndroid Build Coastguard Worker         return;
798*0ec5a0ecSAndroid Build Coastguard Worker     }
799*0ec5a0ecSAndroid Build Coastguard Worker 
800*0ec5a0ecSAndroid Build Coastguard Worker     if (mOutputQueue->freeBuffersCount() == 0) {
801*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("No free V4L2 output buffers, ignore.");
802*0ec5a0ecSAndroid Build Coastguard Worker         return;
803*0ec5a0ecSAndroid Build Coastguard Worker     }
804*0ec5a0ecSAndroid Build Coastguard Worker 
805*0ec5a0ecSAndroid Build Coastguard Worker     if (mReuseFrameQueue.empty()) {
806*0ec5a0ecSAndroid Build Coastguard Worker         if (!mVideoFramePool->getVideoFrame(
807*0ec5a0ecSAndroid Build Coastguard Worker                     ::base::BindOnce(&V4L2Decoder::onVideoFrameReady, mWeakThis))) {
808*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("%s(): Previous callback is running, ignore.", __func__);
809*0ec5a0ecSAndroid Build Coastguard Worker         }
810*0ec5a0ecSAndroid Build Coastguard Worker 
811*0ec5a0ecSAndroid Build Coastguard Worker         return;
812*0ec5a0ecSAndroid Build Coastguard Worker     }
813*0ec5a0ecSAndroid Build Coastguard Worker 
814*0ec5a0ecSAndroid Build Coastguard Worker     // Reuse output picture buffers that were abandoned after STREAMOFF first.
815*0ec5a0ecSAndroid Build Coastguard Worker     // NOTE(b/270003218 and b/297228544): This avoids issues with lack of
816*0ec5a0ecSAndroid Build Coastguard Worker     // ability to return all picture buffers on STREAMOFF from VDA and
817*0ec5a0ecSAndroid Build Coastguard Worker     // saves on IPC with BufferQueue increasing overall responsiveness.
818*0ec5a0ecSAndroid Build Coastguard Worker     uint32_t blockId = mReuseFrameQueue.front().first;
819*0ec5a0ecSAndroid Build Coastguard Worker     std::unique_ptr<VideoFrame> frame = std::move(mReuseFrameQueue.front().second);
820*0ec5a0ecSAndroid Build Coastguard Worker     mReuseFrameQueue.pop();
821*0ec5a0ecSAndroid Build Coastguard Worker 
822*0ec5a0ecSAndroid Build Coastguard Worker     // Avoid recursive calls
823*0ec5a0ecSAndroid Build Coastguard Worker     mTaskRunner->PostTask(FROM_HERE, ::base::BindOnce(&V4L2Decoder::onVideoFrameReady, mWeakThis,
824*0ec5a0ecSAndroid Build Coastguard Worker                                                       std::make_pair(std::move(frame), blockId)));
825*0ec5a0ecSAndroid Build Coastguard Worker }
826*0ec5a0ecSAndroid Build Coastguard Worker 
onVideoFrameReady(std::optional<VideoFramePool::FrameWithBlockId> frameWithBlockId)827*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Decoder::onVideoFrameReady(
828*0ec5a0ecSAndroid Build Coastguard Worker         std::optional<VideoFramePool::FrameWithBlockId> frameWithBlockId) {
829*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
830*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
831*0ec5a0ecSAndroid Build Coastguard Worker 
832*0ec5a0ecSAndroid Build Coastguard Worker     if (!frameWithBlockId) {
833*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Got nullptr VideoFrame.");
834*0ec5a0ecSAndroid Build Coastguard Worker         onError();
835*0ec5a0ecSAndroid Build Coastguard Worker         return;
836*0ec5a0ecSAndroid Build Coastguard Worker     }
837*0ec5a0ecSAndroid Build Coastguard Worker 
838*0ec5a0ecSAndroid Build Coastguard Worker     // Unwrap our arguments.
839*0ec5a0ecSAndroid Build Coastguard Worker     std::unique_ptr<VideoFrame> frame;
840*0ec5a0ecSAndroid Build Coastguard Worker     uint32_t blockId;
841*0ec5a0ecSAndroid Build Coastguard Worker     std::tie(frame, blockId) = std::move(*frameWithBlockId);
842*0ec5a0ecSAndroid Build Coastguard Worker 
843*0ec5a0ecSAndroid Build Coastguard Worker     std::optional<V4L2WritableBufferRef> outputBuffer;
844*0ec5a0ecSAndroid Build Coastguard Worker     // Find the V4L2 buffer that is associated with this block.
845*0ec5a0ecSAndroid Build Coastguard Worker     auto iter = mBlockIdToV4L2Id.find(blockId);
846*0ec5a0ecSAndroid Build Coastguard Worker     if (iter != mBlockIdToV4L2Id.end()) {
847*0ec5a0ecSAndroid Build Coastguard Worker         // If we have met this block in the past, reuse the same V4L2 buffer.
848*0ec5a0ecSAndroid Build Coastguard Worker         outputBuffer = mOutputQueue->getFreeBuffer(iter->second);
849*0ec5a0ecSAndroid Build Coastguard Worker         if (!outputBuffer) {
850*0ec5a0ecSAndroid Build Coastguard Worker             // NOTE(b/281477122): There is a bug in C2BufferQueueBlock. Its buffer queue slots
851*0ec5a0ecSAndroid Build Coastguard Worker             // cache is inconsistent when MediaSync is used and a buffer with the same dmabuf id
852*0ec5a0ecSAndroid Build Coastguard Worker             // can be returned twice despite being already in use by V4L2Decoder. We drop the
853*0ec5a0ecSAndroid Build Coastguard Worker             // buffer here in order to prevent unwanted errors. It is safe, bacause its allocation
854*0ec5a0ecSAndroid Build Coastguard Worker             // will be kept alive by the C2GraphicBlock instance.
855*0ec5a0ecSAndroid Build Coastguard Worker             ALOGW("%s(): The frame have been supplied again, despite being already enqueued",
856*0ec5a0ecSAndroid Build Coastguard Worker                   __func__);
857*0ec5a0ecSAndroid Build Coastguard Worker             tryFetchVideoFrame();
858*0ec5a0ecSAndroid Build Coastguard Worker             return;
859*0ec5a0ecSAndroid Build Coastguard Worker         }
860*0ec5a0ecSAndroid Build Coastguard Worker     } else if (mBlockIdToV4L2Id.size() < mOutputQueue->allocatedBuffersCount()) {
861*0ec5a0ecSAndroid Build Coastguard Worker         // If this is the first time we see this block, give it the next
862*0ec5a0ecSAndroid Build Coastguard Worker         // available V4L2 buffer.
863*0ec5a0ecSAndroid Build Coastguard Worker         const size_t v4l2BufferId = mBlockIdToV4L2Id.size();
864*0ec5a0ecSAndroid Build Coastguard Worker         mBlockIdToV4L2Id.emplace(blockId, v4l2BufferId);
865*0ec5a0ecSAndroid Build Coastguard Worker         outputBuffer = mOutputQueue->getFreeBuffer(v4l2BufferId);
866*0ec5a0ecSAndroid Build Coastguard Worker         ALOG_ASSERT(v4l2BufferId == outputBuffer->bufferId());
867*0ec5a0ecSAndroid Build Coastguard Worker     } else {
868*0ec5a0ecSAndroid Build Coastguard Worker         // If this happens, this is a bug in VideoFramePool. It should never
869*0ec5a0ecSAndroid Build Coastguard Worker         // provide more blocks than we have V4L2 buffers.
870*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Got more different blocks than we have V4L2 buffers for.");
871*0ec5a0ecSAndroid Build Coastguard Worker     }
872*0ec5a0ecSAndroid Build Coastguard Worker 
873*0ec5a0ecSAndroid Build Coastguard Worker     if (!outputBuffer) {
874*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("V4L2 buffer not available. blockId=%u", blockId);
875*0ec5a0ecSAndroid Build Coastguard Worker         onError();
876*0ec5a0ecSAndroid Build Coastguard Worker         return;
877*0ec5a0ecSAndroid Build Coastguard Worker     }
878*0ec5a0ecSAndroid Build Coastguard Worker 
879*0ec5a0ecSAndroid Build Coastguard Worker     uint32_t v4l2Id = outputBuffer->bufferId();
880*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("QBUF to output queue, blockId=%u, V4L2Id=%u", blockId, v4l2Id);
881*0ec5a0ecSAndroid Build Coastguard Worker 
882*0ec5a0ecSAndroid Build Coastguard Worker     if (!std::move(*outputBuffer).queueDMABuf(frame->getFDs())) {
883*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("%s(): Failed to QBUF to output queue, blockId=%u, V4L2Id=%u", __func__, blockId,
884*0ec5a0ecSAndroid Build Coastguard Worker               v4l2Id);
885*0ec5a0ecSAndroid Build Coastguard Worker         onError();
886*0ec5a0ecSAndroid Build Coastguard Worker         return;
887*0ec5a0ecSAndroid Build Coastguard Worker     }
888*0ec5a0ecSAndroid Build Coastguard Worker     if (mFrameAtDevice.find(v4l2Id) != mFrameAtDevice.end()) {
889*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("%s(): V4L2 buffer %d already enqueued.", __func__, v4l2Id);
890*0ec5a0ecSAndroid Build Coastguard Worker         onError();
891*0ec5a0ecSAndroid Build Coastguard Worker         return;
892*0ec5a0ecSAndroid Build Coastguard Worker     }
893*0ec5a0ecSAndroid Build Coastguard Worker     mFrameAtDevice.insert(std::make_pair(v4l2Id, std::move(frame)));
894*0ec5a0ecSAndroid Build Coastguard Worker 
895*0ec5a0ecSAndroid Build Coastguard Worker     tryFetchVideoFrame();
896*0ec5a0ecSAndroid Build Coastguard Worker }
897*0ec5a0ecSAndroid Build Coastguard Worker 
getNumOutputBuffers()898*0ec5a0ecSAndroid Build Coastguard Worker std::optional<size_t> V4L2Decoder::getNumOutputBuffers() {
899*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
900*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
901*0ec5a0ecSAndroid Build Coastguard Worker 
902*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_control ctrl;
903*0ec5a0ecSAndroid Build Coastguard Worker     memset(&ctrl, 0, sizeof(ctrl));
904*0ec5a0ecSAndroid Build Coastguard Worker     ctrl.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE;
905*0ec5a0ecSAndroid Build Coastguard Worker     if (mDevice->ioctl(VIDIOC_G_CTRL, &ctrl) != 0) {
906*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("ioctl() failed: VIDIOC_G_CTRL");
907*0ec5a0ecSAndroid Build Coastguard Worker         return std::nullopt;
908*0ec5a0ecSAndroid Build Coastguard Worker     }
909*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s() V4L2_CID_MIN_BUFFERS_FOR_CAPTURE returns %u", __func__, ctrl.value);
910*0ec5a0ecSAndroid Build Coastguard Worker 
911*0ec5a0ecSAndroid Build Coastguard Worker     return ctrl.value + kNumExtraOutputBuffers;
912*0ec5a0ecSAndroid Build Coastguard Worker }
913*0ec5a0ecSAndroid Build Coastguard Worker 
getFormatInfo()914*0ec5a0ecSAndroid Build Coastguard Worker std::optional<struct v4l2_format> V4L2Decoder::getFormatInfo() {
915*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
916*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
917*0ec5a0ecSAndroid Build Coastguard Worker 
918*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_format format;
919*0ec5a0ecSAndroid Build Coastguard Worker     memset(&format, 0, sizeof(format));
920*0ec5a0ecSAndroid Build Coastguard Worker     format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
921*0ec5a0ecSAndroid Build Coastguard Worker     if (mDevice->ioctl(VIDIOC_G_FMT, &format) != 0) {
922*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("ioctl() failed: VIDIOC_G_FMT");
923*0ec5a0ecSAndroid Build Coastguard Worker         return std::nullopt;
924*0ec5a0ecSAndroid Build Coastguard Worker     }
925*0ec5a0ecSAndroid Build Coastguard Worker 
926*0ec5a0ecSAndroid Build Coastguard Worker     return format;
927*0ec5a0ecSAndroid Build Coastguard Worker }
928*0ec5a0ecSAndroid Build Coastguard Worker 
getVisibleRect(const ui::Size & codedSize)929*0ec5a0ecSAndroid Build Coastguard Worker Rect V4L2Decoder::getVisibleRect(const ui::Size& codedSize) {
930*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
931*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
932*0ec5a0ecSAndroid Build Coastguard Worker 
933*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_rect* visible_rect = nullptr;
934*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_selection selection_arg;
935*0ec5a0ecSAndroid Build Coastguard Worker     memset(&selection_arg, 0, sizeof(selection_arg));
936*0ec5a0ecSAndroid Build Coastguard Worker     selection_arg.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
937*0ec5a0ecSAndroid Build Coastguard Worker     selection_arg.target = V4L2_SEL_TGT_COMPOSE;
938*0ec5a0ecSAndroid Build Coastguard Worker 
939*0ec5a0ecSAndroid Build Coastguard Worker     if (mDevice->ioctl(VIDIOC_G_SELECTION, &selection_arg) == 0) {
940*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("VIDIOC_G_SELECTION is supported");
941*0ec5a0ecSAndroid Build Coastguard Worker         visible_rect = &selection_arg.r;
942*0ec5a0ecSAndroid Build Coastguard Worker     } else {
943*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Fallback to VIDIOC_G_CROP");
944*0ec5a0ecSAndroid Build Coastguard Worker         struct v4l2_crop crop_arg;
945*0ec5a0ecSAndroid Build Coastguard Worker         memset(&crop_arg, 0, sizeof(crop_arg));
946*0ec5a0ecSAndroid Build Coastguard Worker         crop_arg.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
947*0ec5a0ecSAndroid Build Coastguard Worker 
948*0ec5a0ecSAndroid Build Coastguard Worker         if (mDevice->ioctl(VIDIOC_G_CROP, &crop_arg) != 0) {
949*0ec5a0ecSAndroid Build Coastguard Worker             ALOGW("ioctl() VIDIOC_G_CROP failed");
950*0ec5a0ecSAndroid Build Coastguard Worker             return Rect(codedSize.width, codedSize.height);
951*0ec5a0ecSAndroid Build Coastguard Worker         }
952*0ec5a0ecSAndroid Build Coastguard Worker         visible_rect = &crop_arg.c;
953*0ec5a0ecSAndroid Build Coastguard Worker     }
954*0ec5a0ecSAndroid Build Coastguard Worker 
955*0ec5a0ecSAndroid Build Coastguard Worker     Rect rect(visible_rect->left, visible_rect->top, visible_rect->left + visible_rect->width,
956*0ec5a0ecSAndroid Build Coastguard Worker               visible_rect->top + visible_rect->height);
957*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("visible rectangle is %s", toString(rect).c_str());
958*0ec5a0ecSAndroid Build Coastguard Worker     if (!contains(Rect(codedSize.width, codedSize.height), rect)) {
959*0ec5a0ecSAndroid Build Coastguard Worker         ALOGW("visible rectangle %s is not inside coded size %s", toString(rect).c_str(),
960*0ec5a0ecSAndroid Build Coastguard Worker               toString(codedSize).c_str());
961*0ec5a0ecSAndroid Build Coastguard Worker         return Rect(codedSize.width, codedSize.height);
962*0ec5a0ecSAndroid Build Coastguard Worker     }
963*0ec5a0ecSAndroid Build Coastguard Worker     if (rect.isEmpty()) {
964*0ec5a0ecSAndroid Build Coastguard Worker         ALOGW("visible size is empty");
965*0ec5a0ecSAndroid Build Coastguard Worker         return Rect(codedSize.width, codedSize.height);
966*0ec5a0ecSAndroid Build Coastguard Worker     }
967*0ec5a0ecSAndroid Build Coastguard Worker 
968*0ec5a0ecSAndroid Build Coastguard Worker     return rect;
969*0ec5a0ecSAndroid Build Coastguard Worker }
970*0ec5a0ecSAndroid Build Coastguard Worker 
sendV4L2DecoderCmd(bool start)971*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Decoder::sendV4L2DecoderCmd(bool start) {
972*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(start=%d)", __func__, start);
973*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
974*0ec5a0ecSAndroid Build Coastguard Worker 
975*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_decoder_cmd cmd;
976*0ec5a0ecSAndroid Build Coastguard Worker     memset(&cmd, 0, sizeof(cmd));
977*0ec5a0ecSAndroid Build Coastguard Worker     cmd.cmd = start ? V4L2_DEC_CMD_START : V4L2_DEC_CMD_STOP;
978*0ec5a0ecSAndroid Build Coastguard Worker     if (mDevice->ioctl(VIDIOC_DECODER_CMD, &cmd) != 0) {
979*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("ioctl() VIDIOC_DECODER_CMD failed: start=%d", start);
980*0ec5a0ecSAndroid Build Coastguard Worker         return false;
981*0ec5a0ecSAndroid Build Coastguard Worker     }
982*0ec5a0ecSAndroid Build Coastguard Worker 
983*0ec5a0ecSAndroid Build Coastguard Worker     return true;
984*0ec5a0ecSAndroid Build Coastguard Worker }
985*0ec5a0ecSAndroid Build Coastguard Worker 
onError()986*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Decoder::onError() {
987*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
988*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
989*0ec5a0ecSAndroid Build Coastguard Worker 
990*0ec5a0ecSAndroid Build Coastguard Worker     setState(State::Error);
991*0ec5a0ecSAndroid Build Coastguard Worker     mErrorCb.Run();
992*0ec5a0ecSAndroid Build Coastguard Worker }
993*0ec5a0ecSAndroid Build Coastguard Worker 
setState(State newState)994*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Decoder::setState(State newState) {
995*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(%s)", __func__, StateToString(newState));
996*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
997*0ec5a0ecSAndroid Build Coastguard Worker 
998*0ec5a0ecSAndroid Build Coastguard Worker     if (mState == newState) return;
999*0ec5a0ecSAndroid Build Coastguard Worker     if (mState == State::Error) {
1000*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Already in Error state.");
1001*0ec5a0ecSAndroid Build Coastguard Worker         return;
1002*0ec5a0ecSAndroid Build Coastguard Worker     }
1003*0ec5a0ecSAndroid Build Coastguard Worker 
1004*0ec5a0ecSAndroid Build Coastguard Worker     switch (newState) {
1005*0ec5a0ecSAndroid Build Coastguard Worker     case State::Idle:
1006*0ec5a0ecSAndroid Build Coastguard Worker         break;
1007*0ec5a0ecSAndroid Build Coastguard Worker     case State::Decoding:
1008*0ec5a0ecSAndroid Build Coastguard Worker         break;
1009*0ec5a0ecSAndroid Build Coastguard Worker     case State::Draining:
1010*0ec5a0ecSAndroid Build Coastguard Worker         if (mState != State::Decoding) newState = State::Error;
1011*0ec5a0ecSAndroid Build Coastguard Worker         break;
1012*0ec5a0ecSAndroid Build Coastguard Worker     case State::Error:
1013*0ec5a0ecSAndroid Build Coastguard Worker         break;
1014*0ec5a0ecSAndroid Build Coastguard Worker     }
1015*0ec5a0ecSAndroid Build Coastguard Worker 
1016*0ec5a0ecSAndroid Build Coastguard Worker     ALOGI("Set state %s => %s", StateToString(mState), StateToString(newState));
1017*0ec5a0ecSAndroid Build Coastguard Worker     mState = newState;
1018*0ec5a0ecSAndroid Build Coastguard Worker }
1019*0ec5a0ecSAndroid Build Coastguard Worker 
1020*0ec5a0ecSAndroid Build Coastguard Worker // static
StateToString(State state)1021*0ec5a0ecSAndroid Build Coastguard Worker const char* V4L2Decoder::StateToString(State state) {
1022*0ec5a0ecSAndroid Build Coastguard Worker     switch (state) {
1023*0ec5a0ecSAndroid Build Coastguard Worker     case State::Idle:
1024*0ec5a0ecSAndroid Build Coastguard Worker         return "Idle";
1025*0ec5a0ecSAndroid Build Coastguard Worker     case State::Decoding:
1026*0ec5a0ecSAndroid Build Coastguard Worker         return "Decoding";
1027*0ec5a0ecSAndroid Build Coastguard Worker     case State::Draining:
1028*0ec5a0ecSAndroid Build Coastguard Worker         return "Draining";
1029*0ec5a0ecSAndroid Build Coastguard Worker     case State::Error:
1030*0ec5a0ecSAndroid Build Coastguard Worker         return "Error";
1031*0ec5a0ecSAndroid Build Coastguard Worker     }
1032*0ec5a0ecSAndroid Build Coastguard Worker }
1033*0ec5a0ecSAndroid Build Coastguard Worker 
1034*0ec5a0ecSAndroid Build Coastguard Worker }  // namespace android
1035