xref: /aosp_15_r20/external/v4l2_codec2/v4l2/V4L2Encoder.cpp (revision 0ec5a0ec62797f775085659156625e7f1bdb369f)
1*0ec5a0ecSAndroid Build Coastguard Worker // Copyright 2021 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 LOG_TAG "V4L2Encoder"
7*0ec5a0ecSAndroid Build Coastguard Worker 
8*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/v4l2/V4L2Encoder.h>
9*0ec5a0ecSAndroid Build Coastguard Worker 
10*0ec5a0ecSAndroid Build Coastguard Worker #include <stdint.h>
11*0ec5a0ecSAndroid Build Coastguard Worker #include <optional>
12*0ec5a0ecSAndroid Build Coastguard Worker #include <vector>
13*0ec5a0ecSAndroid Build Coastguard Worker 
14*0ec5a0ecSAndroid Build Coastguard Worker #include <base/bind.h>
15*0ec5a0ecSAndroid Build Coastguard Worker #include <base/files/scoped_file.h>
16*0ec5a0ecSAndroid Build Coastguard Worker #include <base/memory/ptr_util.h>
17*0ec5a0ecSAndroid Build Coastguard Worker #include <log/log.h>
18*0ec5a0ecSAndroid Build Coastguard Worker #include <ui/Rect.h>
19*0ec5a0ecSAndroid Build Coastguard Worker 
20*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/EncodeHelpers.h>
21*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/Fourcc.h>
22*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/components/BitstreamBuffer.h>
23*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/v4l2/V4L2Device.h>
24*0ec5a0ecSAndroid Build Coastguard Worker 
25*0ec5a0ecSAndroid Build Coastguard Worker namespace android {
26*0ec5a0ecSAndroid Build Coastguard Worker 
27*0ec5a0ecSAndroid Build Coastguard Worker namespace {
28*0ec5a0ecSAndroid Build Coastguard Worker 
29*0ec5a0ecSAndroid Build Coastguard Worker // The maximum size for output buffer, which is chosen empirically for a 1080p video.
30*0ec5a0ecSAndroid Build Coastguard Worker constexpr size_t kMaxBitstreamBufferSizeInBytes = 2 * 1024 * 1024;  // 2MB
31*0ec5a0ecSAndroid Build Coastguard Worker // The frame size for 1080p (FHD) video in pixels.
32*0ec5a0ecSAndroid Build Coastguard Worker constexpr int k1080PSizeInPixels = 1920 * 1080;
33*0ec5a0ecSAndroid Build Coastguard Worker // The frame size for 1440p (QHD) video in pixels.
34*0ec5a0ecSAndroid Build Coastguard Worker constexpr int k1440PSizeInPixels = 2560 * 1440;
35*0ec5a0ecSAndroid Build Coastguard Worker 
36*0ec5a0ecSAndroid Build Coastguard Worker // Use quadruple size of kMaxBitstreamBufferSizeInBytes when the input frame size is larger than
37*0ec5a0ecSAndroid Build Coastguard Worker // 1440p, double if larger than 1080p. This is chosen empirically for some 4k encoding use cases and
38*0ec5a0ecSAndroid Build Coastguard Worker // the Android CTS VideoEncoderTest (crbug.com/927284).
GetMaxOutputBufferSize(const ui::Size & size)39*0ec5a0ecSAndroid Build Coastguard Worker size_t GetMaxOutputBufferSize(const ui::Size& size) {
40*0ec5a0ecSAndroid Build Coastguard Worker     if (getArea(size) > k1440PSizeInPixels) return kMaxBitstreamBufferSizeInBytes * 4;
41*0ec5a0ecSAndroid Build Coastguard Worker     if (getArea(size) > k1080PSizeInPixels) return kMaxBitstreamBufferSizeInBytes * 2;
42*0ec5a0ecSAndroid Build Coastguard Worker     return kMaxBitstreamBufferSizeInBytes;
43*0ec5a0ecSAndroid Build Coastguard Worker }
44*0ec5a0ecSAndroid Build Coastguard Worker 
45*0ec5a0ecSAndroid Build Coastguard Worker // Define V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR control code if not present in header files.
46*0ec5a0ecSAndroid Build Coastguard Worker #ifndef V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR
47*0ec5a0ecSAndroid Build Coastguard Worker #define V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR (V4L2_CID_MPEG_BASE + 644)
48*0ec5a0ecSAndroid Build Coastguard Worker #endif
49*0ec5a0ecSAndroid Build Coastguard Worker 
50*0ec5a0ecSAndroid Build Coastguard Worker }  // namespace
51*0ec5a0ecSAndroid Build Coastguard Worker 
52*0ec5a0ecSAndroid Build Coastguard Worker // static
create(C2Config::profile_t outputProfile,std::optional<uint8_t> level,const ui::Size & visibleSize,uint32_t stride,uint32_t keyFramePeriod,C2Config::bitrate_mode_t bitrateMode,uint32_t bitrate,std::optional<uint32_t> peakBitrate,FetchOutputBufferCB fetchOutputBufferCb,InputBufferDoneCB inputBufferDoneCb,OutputBufferDoneCB outputBufferDoneCb,DrainDoneCB drainDoneCb,ErrorCB errorCb,scoped_refptr<::base::SequencedTaskRunner> taskRunner)53*0ec5a0ecSAndroid Build Coastguard Worker std::unique_ptr<VideoEncoder> V4L2Encoder::create(
54*0ec5a0ecSAndroid Build Coastguard Worker         C2Config::profile_t outputProfile, std::optional<uint8_t> level,
55*0ec5a0ecSAndroid Build Coastguard Worker         const ui::Size& visibleSize, uint32_t stride, uint32_t keyFramePeriod,
56*0ec5a0ecSAndroid Build Coastguard Worker         C2Config::bitrate_mode_t bitrateMode, uint32_t bitrate, std::optional<uint32_t> peakBitrate,
57*0ec5a0ecSAndroid Build Coastguard Worker         FetchOutputBufferCB fetchOutputBufferCb, InputBufferDoneCB inputBufferDoneCb,
58*0ec5a0ecSAndroid Build Coastguard Worker         OutputBufferDoneCB outputBufferDoneCb, DrainDoneCB drainDoneCb, ErrorCB errorCb,
59*0ec5a0ecSAndroid Build Coastguard Worker         scoped_refptr<::base::SequencedTaskRunner> taskRunner) {
60*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
61*0ec5a0ecSAndroid Build Coastguard Worker 
62*0ec5a0ecSAndroid Build Coastguard Worker     std::unique_ptr<V4L2Encoder> encoder = ::base::WrapUnique<V4L2Encoder>(new V4L2Encoder(
63*0ec5a0ecSAndroid Build Coastguard Worker             std::move(taskRunner), std::move(fetchOutputBufferCb), std::move(inputBufferDoneCb),
64*0ec5a0ecSAndroid Build Coastguard Worker             std::move(outputBufferDoneCb), std::move(drainDoneCb), std::move(errorCb)));
65*0ec5a0ecSAndroid Build Coastguard Worker     if (!encoder->initialize(outputProfile, level, visibleSize, stride, keyFramePeriod, bitrateMode,
66*0ec5a0ecSAndroid Build Coastguard Worker                              bitrate, peakBitrate)) {
67*0ec5a0ecSAndroid Build Coastguard Worker         return nullptr;
68*0ec5a0ecSAndroid Build Coastguard Worker     }
69*0ec5a0ecSAndroid Build Coastguard Worker     return encoder;
70*0ec5a0ecSAndroid Build Coastguard Worker }
71*0ec5a0ecSAndroid Build Coastguard Worker 
V4L2Encoder(scoped_refptr<::base::SequencedTaskRunner> taskRunner,FetchOutputBufferCB fetchOutputBufferCb,InputBufferDoneCB inputBufferDoneCb,OutputBufferDoneCB outputBufferDoneCb,DrainDoneCB drainDoneCb,ErrorCB errorCb)72*0ec5a0ecSAndroid Build Coastguard Worker V4L2Encoder::V4L2Encoder(scoped_refptr<::base::SequencedTaskRunner> taskRunner,
73*0ec5a0ecSAndroid Build Coastguard Worker                          FetchOutputBufferCB fetchOutputBufferCb,
74*0ec5a0ecSAndroid Build Coastguard Worker                          InputBufferDoneCB inputBufferDoneCb, OutputBufferDoneCB outputBufferDoneCb,
75*0ec5a0ecSAndroid Build Coastguard Worker                          DrainDoneCB drainDoneCb, ErrorCB errorCb)
76*0ec5a0ecSAndroid Build Coastguard Worker       : mFetchOutputBufferCb(fetchOutputBufferCb),
77*0ec5a0ecSAndroid Build Coastguard Worker         mInputBufferDoneCb(inputBufferDoneCb),
78*0ec5a0ecSAndroid Build Coastguard Worker         mOutputBufferDoneCb(outputBufferDoneCb),
79*0ec5a0ecSAndroid Build Coastguard Worker         mDrainDoneCb(std::move(drainDoneCb)),
80*0ec5a0ecSAndroid Build Coastguard Worker         mErrorCb(std::move(errorCb)),
81*0ec5a0ecSAndroid Build Coastguard Worker         mTaskRunner(std::move(taskRunner)) {
82*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
83*0ec5a0ecSAndroid Build Coastguard Worker 
84*0ec5a0ecSAndroid Build Coastguard Worker     mWeakThis = mWeakThisFactory.GetWeakPtr();
85*0ec5a0ecSAndroid Build Coastguard Worker }
86*0ec5a0ecSAndroid Build Coastguard Worker 
~V4L2Encoder()87*0ec5a0ecSAndroid Build Coastguard Worker V4L2Encoder::~V4L2Encoder() {
88*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
89*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
90*0ec5a0ecSAndroid Build Coastguard Worker 
91*0ec5a0ecSAndroid Build Coastguard Worker     mWeakThisFactory.InvalidateWeakPtrs();
92*0ec5a0ecSAndroid Build Coastguard Worker 
93*0ec5a0ecSAndroid Build Coastguard Worker     // Flushing the encoder will stop polling and streaming on the V4L2 device queues.
94*0ec5a0ecSAndroid Build Coastguard Worker     flush();
95*0ec5a0ecSAndroid Build Coastguard Worker 
96*0ec5a0ecSAndroid Build Coastguard Worker     // Deallocate all V4L2 device input and output buffers.
97*0ec5a0ecSAndroid Build Coastguard Worker     destroyInputBuffers();
98*0ec5a0ecSAndroid Build Coastguard Worker     destroyOutputBuffers();
99*0ec5a0ecSAndroid Build Coastguard Worker }
100*0ec5a0ecSAndroid Build Coastguard Worker 
encode(std::unique_ptr<InputFrame> frame)101*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Encoder::encode(std::unique_ptr<InputFrame> frame) {
102*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
103*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
104*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mState != State::UNINITIALIZED);
105*0ec5a0ecSAndroid Build Coastguard Worker 
106*0ec5a0ecSAndroid Build Coastguard Worker     // If we're in the error state we can immediately return, freeing the input buffer.
107*0ec5a0ecSAndroid Build Coastguard Worker     if (mState == State::ERROR) {
108*0ec5a0ecSAndroid Build Coastguard Worker         return false;
109*0ec5a0ecSAndroid Build Coastguard Worker     }
110*0ec5a0ecSAndroid Build Coastguard Worker 
111*0ec5a0ecSAndroid Build Coastguard Worker     if (!frame) {
112*0ec5a0ecSAndroid Build Coastguard Worker         ALOGW("Empty encode request scheduled");
113*0ec5a0ecSAndroid Build Coastguard Worker         return false;
114*0ec5a0ecSAndroid Build Coastguard Worker     }
115*0ec5a0ecSAndroid Build Coastguard Worker 
116*0ec5a0ecSAndroid Build Coastguard Worker     mEncodeRequests.push(EncodeRequest(std::move(frame)));
117*0ec5a0ecSAndroid Build Coastguard Worker 
118*0ec5a0ecSAndroid Build Coastguard Worker     // If we were waiting for encode requests, start encoding again.
119*0ec5a0ecSAndroid Build Coastguard Worker     if (mState == State::WAITING_FOR_INPUT_FRAME) {
120*0ec5a0ecSAndroid Build Coastguard Worker         setState(State::ENCODING);
121*0ec5a0ecSAndroid Build Coastguard Worker         mTaskRunner->PostTask(FROM_HERE,
122*0ec5a0ecSAndroid Build Coastguard Worker                               ::base::BindOnce(&V4L2Encoder::handleEncodeRequest, mWeakThis));
123*0ec5a0ecSAndroid Build Coastguard Worker     }
124*0ec5a0ecSAndroid Build Coastguard Worker 
125*0ec5a0ecSAndroid Build Coastguard Worker     return true;
126*0ec5a0ecSAndroid Build Coastguard Worker }
127*0ec5a0ecSAndroid Build Coastguard Worker 
drain()128*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Encoder::drain() {
129*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
130*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
131*0ec5a0ecSAndroid Build Coastguard Worker 
132*0ec5a0ecSAndroid Build Coastguard Worker     // We can only start draining if all the requests in our input queue has been queued on the V4L2
133*0ec5a0ecSAndroid Build Coastguard Worker     // device input queue, so we mark the last item in the input queue as EOS.
134*0ec5a0ecSAndroid Build Coastguard Worker     if (!mEncodeRequests.empty()) {
135*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Marking last item (index: %" PRIu64 ") in encode request queue as EOS",
136*0ec5a0ecSAndroid Build Coastguard Worker               mEncodeRequests.back().video_frame->index());
137*0ec5a0ecSAndroid Build Coastguard Worker         mEncodeRequests.back().end_of_stream = true;
138*0ec5a0ecSAndroid Build Coastguard Worker         return;
139*0ec5a0ecSAndroid Build Coastguard Worker     }
140*0ec5a0ecSAndroid Build Coastguard Worker 
141*0ec5a0ecSAndroid Build Coastguard Worker     // Start a drain operation on the device. If no buffers are currently queued the device will
142*0ec5a0ecSAndroid Build Coastguard Worker     // return an empty buffer with the V4L2_BUF_FLAG_LAST flag set.
143*0ec5a0ecSAndroid Build Coastguard Worker     handleDrainRequest();
144*0ec5a0ecSAndroid Build Coastguard Worker }
145*0ec5a0ecSAndroid Build Coastguard Worker 
flush()146*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Encoder::flush() {
147*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
148*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
149*0ec5a0ecSAndroid Build Coastguard Worker 
150*0ec5a0ecSAndroid Build Coastguard Worker     handleFlushRequest();
151*0ec5a0ecSAndroid Build Coastguard Worker }
152*0ec5a0ecSAndroid Build Coastguard Worker 
setBitrate(uint32_t bitrate)153*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Encoder::setBitrate(uint32_t bitrate) {
154*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
155*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
156*0ec5a0ecSAndroid Build Coastguard Worker 
157*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDevice->setExtCtrls(V4L2_CTRL_CLASS_MPEG,
158*0ec5a0ecSAndroid Build Coastguard Worker                               {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_BITRATE, bitrate)})) {
159*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Setting bitrate to %u failed", bitrate);
160*0ec5a0ecSAndroid Build Coastguard Worker         return false;
161*0ec5a0ecSAndroid Build Coastguard Worker     }
162*0ec5a0ecSAndroid Build Coastguard Worker     return true;
163*0ec5a0ecSAndroid Build Coastguard Worker }
164*0ec5a0ecSAndroid Build Coastguard Worker 
setPeakBitrate(uint32_t peakBitrate)165*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Encoder::setPeakBitrate(uint32_t peakBitrate) {
166*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
167*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
168*0ec5a0ecSAndroid Build Coastguard Worker 
169*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDevice->setExtCtrls(V4L2_CTRL_CLASS_MPEG,
170*0ec5a0ecSAndroid Build Coastguard Worker                               {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, peakBitrate)})) {
171*0ec5a0ecSAndroid Build Coastguard Worker         // TODO(b/190336806): Our stack doesn't support dynamic peak bitrate changes yet, ignore
172*0ec5a0ecSAndroid Build Coastguard Worker         // errors for now.
173*0ec5a0ecSAndroid Build Coastguard Worker         ALOGW("Setting peak bitrate to %u failed", peakBitrate);
174*0ec5a0ecSAndroid Build Coastguard Worker     }
175*0ec5a0ecSAndroid Build Coastguard Worker     return true;
176*0ec5a0ecSAndroid Build Coastguard Worker }
177*0ec5a0ecSAndroid Build Coastguard Worker 
setFramerate(uint32_t framerate)178*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Encoder::setFramerate(uint32_t framerate) {
179*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
180*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
181*0ec5a0ecSAndroid Build Coastguard Worker 
182*0ec5a0ecSAndroid Build Coastguard Worker     if (framerate == 0) {
183*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Requesting invalid framerate 0");
184*0ec5a0ecSAndroid Build Coastguard Worker         return false;
185*0ec5a0ecSAndroid Build Coastguard Worker     }
186*0ec5a0ecSAndroid Build Coastguard Worker 
187*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_streamparm parms;
188*0ec5a0ecSAndroid Build Coastguard Worker     memset(&parms, 0, sizeof(v4l2_streamparm));
189*0ec5a0ecSAndroid Build Coastguard Worker     parms.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
190*0ec5a0ecSAndroid Build Coastguard Worker     parms.parm.output.timeperframe.numerator = 1;
191*0ec5a0ecSAndroid Build Coastguard Worker     parms.parm.output.timeperframe.denominator = framerate;
192*0ec5a0ecSAndroid Build Coastguard Worker     if (mDevice->ioctl(VIDIOC_S_PARM, &parms) != 0) {
193*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Setting framerate to %u failed", framerate);
194*0ec5a0ecSAndroid Build Coastguard Worker         return false;
195*0ec5a0ecSAndroid Build Coastguard Worker     }
196*0ec5a0ecSAndroid Build Coastguard Worker     return true;
197*0ec5a0ecSAndroid Build Coastguard Worker }
198*0ec5a0ecSAndroid Build Coastguard Worker 
requestKeyframe()199*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Encoder::requestKeyframe() {
200*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
201*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
202*0ec5a0ecSAndroid Build Coastguard Worker 
203*0ec5a0ecSAndroid Build Coastguard Worker     mKeyFrameCounter = 0;
204*0ec5a0ecSAndroid Build Coastguard Worker }
205*0ec5a0ecSAndroid Build Coastguard Worker 
inputFormat() const206*0ec5a0ecSAndroid Build Coastguard Worker VideoPixelFormat V4L2Encoder::inputFormat() const {
207*0ec5a0ecSAndroid Build Coastguard Worker     return mInputLayout ? mInputLayout.value().mFormat : VideoPixelFormat::UNKNOWN;
208*0ec5a0ecSAndroid Build Coastguard Worker }
209*0ec5a0ecSAndroid Build Coastguard Worker 
initialize(C2Config::profile_t outputProfile,std::optional<uint8_t> level,const ui::Size & visibleSize,uint32_t stride,uint32_t keyFramePeriod,C2Config::bitrate_mode_t bitrateMode,uint32_t bitrate,std::optional<uint32_t> peakBitrate)210*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Encoder::initialize(C2Config::profile_t outputProfile, std::optional<uint8_t> level,
211*0ec5a0ecSAndroid Build Coastguard Worker                              const ui::Size& visibleSize, uint32_t stride, uint32_t keyFramePeriod,
212*0ec5a0ecSAndroid Build Coastguard Worker                              C2Config::bitrate_mode_t bitrateMode, uint32_t bitrate,
213*0ec5a0ecSAndroid Build Coastguard Worker                              std::optional<uint32_t> peakBitrate) {
214*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
215*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
216*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(keyFramePeriod > 0);
217*0ec5a0ecSAndroid Build Coastguard Worker 
218*0ec5a0ecSAndroid Build Coastguard Worker     mVisibleSize = visibleSize;
219*0ec5a0ecSAndroid Build Coastguard Worker     mKeyFramePeriod = keyFramePeriod;
220*0ec5a0ecSAndroid Build Coastguard Worker     mKeyFrameCounter = 0;
221*0ec5a0ecSAndroid Build Coastguard Worker 
222*0ec5a0ecSAndroid Build Coastguard Worker     // Open the V4L2 device for encoding to the requested output format.
223*0ec5a0ecSAndroid Build Coastguard Worker     // TODO(dstaessens): Avoid conversion to VideoCodecProfile and use C2Config::profile_t directly.
224*0ec5a0ecSAndroid Build Coastguard Worker     uint32_t outputPixelFormat = V4L2Device::c2ProfileToV4L2PixFmt(outputProfile, false);
225*0ec5a0ecSAndroid Build Coastguard Worker     if (!outputPixelFormat) {
226*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Invalid output profile %s", profileToString(outputProfile));
227*0ec5a0ecSAndroid Build Coastguard Worker         return false;
228*0ec5a0ecSAndroid Build Coastguard Worker     }
229*0ec5a0ecSAndroid Build Coastguard Worker 
230*0ec5a0ecSAndroid Build Coastguard Worker     mDevice = V4L2Device::create();
231*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDevice) {
232*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to create V4L2 device");
233*0ec5a0ecSAndroid Build Coastguard Worker         return false;
234*0ec5a0ecSAndroid Build Coastguard Worker     }
235*0ec5a0ecSAndroid Build Coastguard Worker 
236*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDevice->open(V4L2Device::Type::kEncoder, outputPixelFormat)) {
237*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to open device for profile %s (%s)", profileToString(outputProfile),
238*0ec5a0ecSAndroid Build Coastguard Worker               fourccToString(outputPixelFormat).c_str());
239*0ec5a0ecSAndroid Build Coastguard Worker         return false;
240*0ec5a0ecSAndroid Build Coastguard Worker     }
241*0ec5a0ecSAndroid Build Coastguard Worker 
242*0ec5a0ecSAndroid Build Coastguard Worker     // Make sure the device has all required capabilities (multi-planar Memory-To-Memory and
243*0ec5a0ecSAndroid Build Coastguard Worker     // streaming I/O), and whether flushing is supported.
244*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDevice->hasCapabilities(V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING)) {
245*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Device doesn't have the required capabilities");
246*0ec5a0ecSAndroid Build Coastguard Worker         return false;
247*0ec5a0ecSAndroid Build Coastguard Worker     }
248*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDevice->isCommandSupported(V4L2_ENC_CMD_STOP)) {
249*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Device does not support flushing (V4L2_ENC_CMD_STOP)");
250*0ec5a0ecSAndroid Build Coastguard Worker         return false;
251*0ec5a0ecSAndroid Build Coastguard Worker     }
252*0ec5a0ecSAndroid Build Coastguard Worker 
253*0ec5a0ecSAndroid Build Coastguard Worker     // Get input/output queues so we can send encode request to the device and get back the results.
254*0ec5a0ecSAndroid Build Coastguard Worker     mInputQueue = mDevice->getQueue(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
255*0ec5a0ecSAndroid Build Coastguard Worker     mOutputQueue = mDevice->getQueue(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
256*0ec5a0ecSAndroid Build Coastguard Worker     if (!mInputQueue || !mOutputQueue) {
257*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to get V4L2 device queues");
258*0ec5a0ecSAndroid Build Coastguard Worker         return false;
259*0ec5a0ecSAndroid Build Coastguard Worker     }
260*0ec5a0ecSAndroid Build Coastguard Worker 
261*0ec5a0ecSAndroid Build Coastguard Worker     // Configure the requested bitrate mode and bitrate on the device.
262*0ec5a0ecSAndroid Build Coastguard Worker     if (!configureBitrateMode(bitrateMode) || !setBitrate(bitrate)) return false;
263*0ec5a0ecSAndroid Build Coastguard Worker 
264*0ec5a0ecSAndroid Build Coastguard Worker     // If the bitrate mode is VBR we also need to configure the peak bitrate on the device.
265*0ec5a0ecSAndroid Build Coastguard Worker     if ((bitrateMode == C2Config::BITRATE_VARIABLE) && !setPeakBitrate(*peakBitrate)) return false;
266*0ec5a0ecSAndroid Build Coastguard Worker 
267*0ec5a0ecSAndroid Build Coastguard Worker     // First try to configure the specified output format, as changing the output format can affect
268*0ec5a0ecSAndroid Build Coastguard Worker     // the configured input format.
269*0ec5a0ecSAndroid Build Coastguard Worker     if (!configureOutputFormat(outputProfile)) return false;
270*0ec5a0ecSAndroid Build Coastguard Worker 
271*0ec5a0ecSAndroid Build Coastguard Worker     // Configure the input format. If the device doesn't support the specified format we'll use one
272*0ec5a0ecSAndroid Build Coastguard Worker     // of the device's preferred formats in combination with an input format convertor.
273*0ec5a0ecSAndroid Build Coastguard Worker     if (!configureInputFormat(kInputPixelFormat, stride)) return false;
274*0ec5a0ecSAndroid Build Coastguard Worker 
275*0ec5a0ecSAndroid Build Coastguard Worker     // Create input and output buffers.
276*0ec5a0ecSAndroid Build Coastguard Worker     if (!createInputBuffers() || !createOutputBuffers()) return false;
277*0ec5a0ecSAndroid Build Coastguard Worker 
278*0ec5a0ecSAndroid Build Coastguard Worker     // Configure the device, setting all required controls.
279*0ec5a0ecSAndroid Build Coastguard Worker     if (!configureDevice(outputProfile, level)) return false;
280*0ec5a0ecSAndroid Build Coastguard Worker 
281*0ec5a0ecSAndroid Build Coastguard Worker     // We're ready to start encoding now.
282*0ec5a0ecSAndroid Build Coastguard Worker     setState(State::WAITING_FOR_INPUT_FRAME);
283*0ec5a0ecSAndroid Build Coastguard Worker     return true;
284*0ec5a0ecSAndroid Build Coastguard Worker }
285*0ec5a0ecSAndroid Build Coastguard Worker 
handleEncodeRequest()286*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Encoder::handleEncodeRequest() {
287*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
288*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
289*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mState == State::ENCODING || mState == State::ERROR);
290*0ec5a0ecSAndroid Build Coastguard Worker 
291*0ec5a0ecSAndroid Build Coastguard Worker     // If we're in the error state we can immediately return.
292*0ec5a0ecSAndroid Build Coastguard Worker     if (mState == State::ERROR) {
293*0ec5a0ecSAndroid Build Coastguard Worker         return;
294*0ec5a0ecSAndroid Build Coastguard Worker     }
295*0ec5a0ecSAndroid Build Coastguard Worker 
296*0ec5a0ecSAndroid Build Coastguard Worker     // It's possible we flushed the encoder since this function was scheduled.
297*0ec5a0ecSAndroid Build Coastguard Worker     if (mEncodeRequests.empty()) {
298*0ec5a0ecSAndroid Build Coastguard Worker         return;
299*0ec5a0ecSAndroid Build Coastguard Worker     }
300*0ec5a0ecSAndroid Build Coastguard Worker 
301*0ec5a0ecSAndroid Build Coastguard Worker     // Get the next encode request from the queue.
302*0ec5a0ecSAndroid Build Coastguard Worker     EncodeRequest& encodeRequest = mEncodeRequests.front();
303*0ec5a0ecSAndroid Build Coastguard Worker 
304*0ec5a0ecSAndroid Build Coastguard Worker     // Check if the device has free input buffers available. If not we'll switch to the
305*0ec5a0ecSAndroid Build Coastguard Worker     // WAITING_FOR_INPUT_BUFFERS state, and resume encoding once we've dequeued an input buffer.
306*0ec5a0ecSAndroid Build Coastguard Worker     // Note: The input buffers are not copied into the device's input buffers, but rather a memory
307*0ec5a0ecSAndroid Build Coastguard Worker     // pointer is imported. We still have to throttle the number of enqueues queued simultaneously
308*0ec5a0ecSAndroid Build Coastguard Worker     // on the device however.
309*0ec5a0ecSAndroid Build Coastguard Worker     if (mInputQueue->freeBuffersCount() == 0) {
310*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Waiting for device to return input buffers");
311*0ec5a0ecSAndroid Build Coastguard Worker         setState(State::WAITING_FOR_V4L2_BUFFER);
312*0ec5a0ecSAndroid Build Coastguard Worker         return;
313*0ec5a0ecSAndroid Build Coastguard Worker     }
314*0ec5a0ecSAndroid Build Coastguard Worker 
315*0ec5a0ecSAndroid Build Coastguard Worker     // Request the next frame to be a key frame each time the counter reaches 0.
316*0ec5a0ecSAndroid Build Coastguard Worker     if (mKeyFrameCounter == 0) {
317*0ec5a0ecSAndroid Build Coastguard Worker         if (!mDevice->setExtCtrls(V4L2_CTRL_CLASS_MPEG,
318*0ec5a0ecSAndroid Build Coastguard Worker                                   {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME)})) {
319*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Failed requesting key frame");
320*0ec5a0ecSAndroid Build Coastguard Worker             onError();
321*0ec5a0ecSAndroid Build Coastguard Worker             return;
322*0ec5a0ecSAndroid Build Coastguard Worker         }
323*0ec5a0ecSAndroid Build Coastguard Worker     }
324*0ec5a0ecSAndroid Build Coastguard Worker     mKeyFrameCounter = (mKeyFrameCounter + 1) % mKeyFramePeriod;
325*0ec5a0ecSAndroid Build Coastguard Worker 
326*0ec5a0ecSAndroid Build Coastguard Worker     // Enqueue the input frame in the V4L2 device.
327*0ec5a0ecSAndroid Build Coastguard Worker     uint64_t index = encodeRequest.video_frame->index();
328*0ec5a0ecSAndroid Build Coastguard Worker     uint64_t timestamp = encodeRequest.video_frame->timestamp();
329*0ec5a0ecSAndroid Build Coastguard Worker     bool end_of_stream = encodeRequest.end_of_stream;
330*0ec5a0ecSAndroid Build Coastguard Worker     if (!enqueueInputBuffer(std::move(encodeRequest.video_frame))) {
331*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to enqueue input frame (index: %" PRIu64 ", timestamp: %" PRId64 ")", index,
332*0ec5a0ecSAndroid Build Coastguard Worker               timestamp);
333*0ec5a0ecSAndroid Build Coastguard Worker         onError();
334*0ec5a0ecSAndroid Build Coastguard Worker         return;
335*0ec5a0ecSAndroid Build Coastguard Worker     }
336*0ec5a0ecSAndroid Build Coastguard Worker     mEncodeRequests.pop();
337*0ec5a0ecSAndroid Build Coastguard Worker 
338*0ec5a0ecSAndroid Build Coastguard Worker     // Start streaming and polling on the input and output queue if required.
339*0ec5a0ecSAndroid Build Coastguard Worker     if (!mInputQueue->isStreaming()) {
340*0ec5a0ecSAndroid Build Coastguard Worker         ALOG_ASSERT(!mOutputQueue->isStreaming());
341*0ec5a0ecSAndroid Build Coastguard Worker         if (!mOutputQueue->streamon() || !mInputQueue->streamon()) {
342*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Failed to start streaming on input and output queue");
343*0ec5a0ecSAndroid Build Coastguard Worker             onError();
344*0ec5a0ecSAndroid Build Coastguard Worker             return;
345*0ec5a0ecSAndroid Build Coastguard Worker         }
346*0ec5a0ecSAndroid Build Coastguard Worker         startDevicePoll();
347*0ec5a0ecSAndroid Build Coastguard Worker     }
348*0ec5a0ecSAndroid Build Coastguard Worker 
349*0ec5a0ecSAndroid Build Coastguard Worker     // Queue buffers on output queue. These buffers will be used to store the encoded bitstream.
350*0ec5a0ecSAndroid Build Coastguard Worker     while (mOutputQueue->freeBuffersCount() > 0) {
351*0ec5a0ecSAndroid Build Coastguard Worker         if (!enqueueOutputBuffer()) return;
352*0ec5a0ecSAndroid Build Coastguard Worker     }
353*0ec5a0ecSAndroid Build Coastguard Worker 
354*0ec5a0ecSAndroid Build Coastguard Worker     // Drain the encoder if requested.
355*0ec5a0ecSAndroid Build Coastguard Worker     if (end_of_stream) {
356*0ec5a0ecSAndroid Build Coastguard Worker         handleDrainRequest();
357*0ec5a0ecSAndroid Build Coastguard Worker         return;
358*0ec5a0ecSAndroid Build Coastguard Worker     }
359*0ec5a0ecSAndroid Build Coastguard Worker 
360*0ec5a0ecSAndroid Build Coastguard Worker     if (mEncodeRequests.empty()) {
361*0ec5a0ecSAndroid Build Coastguard Worker         setState(State::WAITING_FOR_INPUT_FRAME);
362*0ec5a0ecSAndroid Build Coastguard Worker         return;
363*0ec5a0ecSAndroid Build Coastguard Worker     }
364*0ec5a0ecSAndroid Build Coastguard Worker 
365*0ec5a0ecSAndroid Build Coastguard Worker     // Schedule the next buffer to be encoded.
366*0ec5a0ecSAndroid Build Coastguard Worker     mTaskRunner->PostTask(FROM_HERE,
367*0ec5a0ecSAndroid Build Coastguard Worker                           ::base::BindOnce(&V4L2Encoder::handleEncodeRequest, mWeakThis));
368*0ec5a0ecSAndroid Build Coastguard Worker }
369*0ec5a0ecSAndroid Build Coastguard Worker 
handleFlushRequest()370*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Encoder::handleFlushRequest() {
371*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
372*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
373*0ec5a0ecSAndroid Build Coastguard Worker 
374*0ec5a0ecSAndroid Build Coastguard Worker     // Stop the device poll thread.
375*0ec5a0ecSAndroid Build Coastguard Worker     stopDevicePoll();
376*0ec5a0ecSAndroid Build Coastguard Worker 
377*0ec5a0ecSAndroid Build Coastguard Worker     // Stop streaming on the V4L2 device, which stops all currently queued encode operations and
378*0ec5a0ecSAndroid Build Coastguard Worker     // releases all buffers currently in use by the device.
379*0ec5a0ecSAndroid Build Coastguard Worker     for (auto& queue : {mInputQueue, mOutputQueue}) {
380*0ec5a0ecSAndroid Build Coastguard Worker         if (queue && queue->isStreaming() && !queue->streamoff()) {
381*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Failed to stop streaming on the device queue");
382*0ec5a0ecSAndroid Build Coastguard Worker             onError();
383*0ec5a0ecSAndroid Build Coastguard Worker         }
384*0ec5a0ecSAndroid Build Coastguard Worker     }
385*0ec5a0ecSAndroid Build Coastguard Worker 
386*0ec5a0ecSAndroid Build Coastguard Worker     // Clear all outstanding encode requests and references to input and output queue buffers.
387*0ec5a0ecSAndroid Build Coastguard Worker     while (!mEncodeRequests.empty()) {
388*0ec5a0ecSAndroid Build Coastguard Worker         mEncodeRequests.pop();
389*0ec5a0ecSAndroid Build Coastguard Worker     }
390*0ec5a0ecSAndroid Build Coastguard Worker     for (auto& buf : mInputBuffers) {
391*0ec5a0ecSAndroid Build Coastguard Worker         buf = nullptr;
392*0ec5a0ecSAndroid Build Coastguard Worker     }
393*0ec5a0ecSAndroid Build Coastguard Worker     for (auto& buf : mOutputBuffers) {
394*0ec5a0ecSAndroid Build Coastguard Worker         buf = nullptr;
395*0ec5a0ecSAndroid Build Coastguard Worker     }
396*0ec5a0ecSAndroid Build Coastguard Worker 
397*0ec5a0ecSAndroid Build Coastguard Worker     // Streaming and polling on the V4L2 device input and output queues will be resumed once new
398*0ec5a0ecSAndroid Build Coastguard Worker     // encode work is queued.
399*0ec5a0ecSAndroid Build Coastguard Worker     if (mState != State::ERROR) {
400*0ec5a0ecSAndroid Build Coastguard Worker         setState(State::WAITING_FOR_INPUT_FRAME);
401*0ec5a0ecSAndroid Build Coastguard Worker     }
402*0ec5a0ecSAndroid Build Coastguard Worker }
403*0ec5a0ecSAndroid Build Coastguard Worker 
handleDrainRequest()404*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Encoder::handleDrainRequest() {
405*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
406*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
407*0ec5a0ecSAndroid Build Coastguard Worker 
408*0ec5a0ecSAndroid Build Coastguard Worker     if (mState == State::DRAINING || mState == State::ERROR) {
409*0ec5a0ecSAndroid Build Coastguard Worker         return;
410*0ec5a0ecSAndroid Build Coastguard Worker     }
411*0ec5a0ecSAndroid Build Coastguard Worker 
412*0ec5a0ecSAndroid Build Coastguard Worker     setState(State::DRAINING);
413*0ec5a0ecSAndroid Build Coastguard Worker 
414*0ec5a0ecSAndroid Build Coastguard Worker     // If we're not streaming we can consider the request completed immediately.
415*0ec5a0ecSAndroid Build Coastguard Worker     if (!mInputQueue->isStreaming()) {
416*0ec5a0ecSAndroid Build Coastguard Worker         onDrainDone(true);
417*0ec5a0ecSAndroid Build Coastguard Worker         return;
418*0ec5a0ecSAndroid Build Coastguard Worker     }
419*0ec5a0ecSAndroid Build Coastguard Worker 
420*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_encoder_cmd cmd;
421*0ec5a0ecSAndroid Build Coastguard Worker     memset(&cmd, 0, sizeof(v4l2_encoder_cmd));
422*0ec5a0ecSAndroid Build Coastguard Worker     cmd.cmd = V4L2_ENC_CMD_STOP;
423*0ec5a0ecSAndroid Build Coastguard Worker     if (mDevice->ioctl(VIDIOC_ENCODER_CMD, &cmd) != 0) {
424*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to stop encoder");
425*0ec5a0ecSAndroid Build Coastguard Worker         onDrainDone(false);
426*0ec5a0ecSAndroid Build Coastguard Worker         return;
427*0ec5a0ecSAndroid Build Coastguard Worker     }
428*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(): Sent STOP command to encoder", __func__);
429*0ec5a0ecSAndroid Build Coastguard Worker }
430*0ec5a0ecSAndroid Build Coastguard Worker 
onDrainDone(bool done)431*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Encoder::onDrainDone(bool done) {
432*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
433*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
434*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mState == State::DRAINING || mState == State::ERROR);
435*0ec5a0ecSAndroid Build Coastguard Worker 
436*0ec5a0ecSAndroid Build Coastguard Worker     if (mState == State::ERROR) {
437*0ec5a0ecSAndroid Build Coastguard Worker         return;
438*0ec5a0ecSAndroid Build Coastguard Worker     }
439*0ec5a0ecSAndroid Build Coastguard Worker 
440*0ec5a0ecSAndroid Build Coastguard Worker     if (!done) {
441*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("draining the encoder failed");
442*0ec5a0ecSAndroid Build Coastguard Worker         mDrainDoneCb.Run(false);
443*0ec5a0ecSAndroid Build Coastguard Worker         onError();
444*0ec5a0ecSAndroid Build Coastguard Worker         return;
445*0ec5a0ecSAndroid Build Coastguard Worker     }
446*0ec5a0ecSAndroid Build Coastguard Worker 
447*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("Draining done");
448*0ec5a0ecSAndroid Build Coastguard Worker     mDrainDoneCb.Run(true);
449*0ec5a0ecSAndroid Build Coastguard Worker 
450*0ec5a0ecSAndroid Build Coastguard Worker     // Draining the encoder is done, we can now start encoding again.
451*0ec5a0ecSAndroid Build Coastguard Worker     if (!mEncodeRequests.empty()) {
452*0ec5a0ecSAndroid Build Coastguard Worker         setState(State::ENCODING);
453*0ec5a0ecSAndroid Build Coastguard Worker         mTaskRunner->PostTask(FROM_HERE,
454*0ec5a0ecSAndroid Build Coastguard Worker                               ::base::BindOnce(&V4L2Encoder::handleEncodeRequest, mWeakThis));
455*0ec5a0ecSAndroid Build Coastguard Worker     } else {
456*0ec5a0ecSAndroid Build Coastguard Worker         setState(State::WAITING_FOR_INPUT_FRAME);
457*0ec5a0ecSAndroid Build Coastguard Worker     }
458*0ec5a0ecSAndroid Build Coastguard Worker }
459*0ec5a0ecSAndroid Build Coastguard Worker 
configureInputFormat(VideoPixelFormat inputFormat,uint32_t stride)460*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Encoder::configureInputFormat(VideoPixelFormat inputFormat, uint32_t stride) {
461*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
462*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
463*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mState == State::UNINITIALIZED);
464*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(!mInputQueue->isStreaming());
465*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(!isEmpty(mVisibleSize));
466*0ec5a0ecSAndroid Build Coastguard Worker 
467*0ec5a0ecSAndroid Build Coastguard Worker     // First try to use the requested pixel format directly.
468*0ec5a0ecSAndroid Build Coastguard Worker     std::optional<struct v4l2_format> format;
469*0ec5a0ecSAndroid Build Coastguard Worker     auto fourcc = Fourcc::fromVideoPixelFormat(inputFormat, false);
470*0ec5a0ecSAndroid Build Coastguard Worker     if (fourcc) {
471*0ec5a0ecSAndroid Build Coastguard Worker         format = mInputQueue->setFormat(fourcc->toV4L2PixFmt(), mVisibleSize, 0, stride);
472*0ec5a0ecSAndroid Build Coastguard Worker     }
473*0ec5a0ecSAndroid Build Coastguard Worker 
474*0ec5a0ecSAndroid Build Coastguard Worker     // If the device doesn't support the requested input format we'll try the device's preferred
475*0ec5a0ecSAndroid Build Coastguard Worker     // input pixel formats and use a format convertor. We need to try all formats as some formats
476*0ec5a0ecSAndroid Build Coastguard Worker     // might not be supported for the configured output format.
477*0ec5a0ecSAndroid Build Coastguard Worker     if (!format) {
478*0ec5a0ecSAndroid Build Coastguard Worker         std::vector<uint32_t> preferredFormats =
479*0ec5a0ecSAndroid Build Coastguard Worker                 mDevice->preferredInputFormat(V4L2Device::Type::kEncoder);
480*0ec5a0ecSAndroid Build Coastguard Worker         for (uint32_t i = 0; !format && i < preferredFormats.size(); ++i) {
481*0ec5a0ecSAndroid Build Coastguard Worker             format = mInputQueue->setFormat(preferredFormats[i], mVisibleSize, 0, stride);
482*0ec5a0ecSAndroid Build Coastguard Worker         }
483*0ec5a0ecSAndroid Build Coastguard Worker     }
484*0ec5a0ecSAndroid Build Coastguard Worker 
485*0ec5a0ecSAndroid Build Coastguard Worker     if (!format) {
486*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to set input format to %s", videoPixelFormatToString(inputFormat).c_str());
487*0ec5a0ecSAndroid Build Coastguard Worker         return false;
488*0ec5a0ecSAndroid Build Coastguard Worker     }
489*0ec5a0ecSAndroid Build Coastguard Worker 
490*0ec5a0ecSAndroid Build Coastguard Worker     // Check whether the negotiated input format is valid. The coded size might be adjusted to match
491*0ec5a0ecSAndroid Build Coastguard Worker     // encoder minimums, maximums and alignment requirements of the currently selected formats.
492*0ec5a0ecSAndroid Build Coastguard Worker     auto layout = V4L2Device::v4L2FormatToVideoFrameLayout(*format);
493*0ec5a0ecSAndroid Build Coastguard Worker     if (!layout) {
494*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Invalid input layout");
495*0ec5a0ecSAndroid Build Coastguard Worker         return false;
496*0ec5a0ecSAndroid Build Coastguard Worker     }
497*0ec5a0ecSAndroid Build Coastguard Worker 
498*0ec5a0ecSAndroid Build Coastguard Worker     mInputLayout = layout.value();
499*0ec5a0ecSAndroid Build Coastguard Worker     if (!contains(Rect(mInputLayout->mCodedSize.width, mInputLayout->mCodedSize.height),
500*0ec5a0ecSAndroid Build Coastguard Worker                   Rect(mVisibleSize.width, mVisibleSize.height))) {
501*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Input size %s exceeds encoder capability, encoder can handle %s",
502*0ec5a0ecSAndroid Build Coastguard Worker               toString(mVisibleSize).c_str(), toString(mInputLayout->mCodedSize).c_str());
503*0ec5a0ecSAndroid Build Coastguard Worker         return false;
504*0ec5a0ecSAndroid Build Coastguard Worker     }
505*0ec5a0ecSAndroid Build Coastguard Worker 
506*0ec5a0ecSAndroid Build Coastguard Worker     // Calculate the input coded size from the format.
507*0ec5a0ecSAndroid Build Coastguard Worker     // TODO(dstaessens): How is this different from mInputLayout->coded_size()?
508*0ec5a0ecSAndroid Build Coastguard Worker     mInputCodedSize = V4L2Device::allocatedSizeFromV4L2Format(*format);
509*0ec5a0ecSAndroid Build Coastguard Worker 
510*0ec5a0ecSAndroid Build Coastguard Worker     // Configuring the input format might cause the output buffer size to change.
511*0ec5a0ecSAndroid Build Coastguard Worker     auto outputFormat = mOutputQueue->getFormat();
512*0ec5a0ecSAndroid Build Coastguard Worker     if (!outputFormat.first) {
513*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to get output format (errno: %i)", outputFormat.second);
514*0ec5a0ecSAndroid Build Coastguard Worker         return false;
515*0ec5a0ecSAndroid Build Coastguard Worker     }
516*0ec5a0ecSAndroid Build Coastguard Worker     uint32_t AdjustedOutputBufferSize = outputFormat.first->fmt.pix_mp.plane_fmt[0].sizeimage;
517*0ec5a0ecSAndroid Build Coastguard Worker     if (mOutputBufferSize != AdjustedOutputBufferSize) {
518*0ec5a0ecSAndroid Build Coastguard Worker         mOutputBufferSize = AdjustedOutputBufferSize;
519*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Output buffer size adjusted to: %u", mOutputBufferSize);
520*0ec5a0ecSAndroid Build Coastguard Worker     }
521*0ec5a0ecSAndroid Build Coastguard Worker 
522*0ec5a0ecSAndroid Build Coastguard Worker     // The coded input size might be different from the visible size due to alignment requirements,
523*0ec5a0ecSAndroid Build Coastguard Worker     // So we need to specify the visible rectangle. Note that this rectangle might still be adjusted
524*0ec5a0ecSAndroid Build Coastguard Worker     // due to hardware limitations.
525*0ec5a0ecSAndroid Build Coastguard Worker     Rect visibleRectangle(mVisibleSize.width, mVisibleSize.height);
526*0ec5a0ecSAndroid Build Coastguard Worker 
527*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_rect rect;
528*0ec5a0ecSAndroid Build Coastguard Worker     memset(&rect, 0, sizeof(rect));
529*0ec5a0ecSAndroid Build Coastguard Worker     rect.left = visibleRectangle.left;
530*0ec5a0ecSAndroid Build Coastguard Worker     rect.top = visibleRectangle.top;
531*0ec5a0ecSAndroid Build Coastguard Worker     rect.width = visibleRectangle.width();
532*0ec5a0ecSAndroid Build Coastguard Worker     rect.height = visibleRectangle.height();
533*0ec5a0ecSAndroid Build Coastguard Worker 
534*0ec5a0ecSAndroid Build Coastguard Worker     // Try to adjust the visible rectangle using the VIDIOC_S_SELECTION command. If this is not
535*0ec5a0ecSAndroid Build Coastguard Worker     // supported we'll try to use the VIDIOC_S_CROP command instead. The visible rectangle might be
536*0ec5a0ecSAndroid Build Coastguard Worker     // adjusted to conform to hardware limitations (e.g. round to closest horizontal and vertical
537*0ec5a0ecSAndroid Build Coastguard Worker     // offsets, width and height).
538*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_selection selection_arg;
539*0ec5a0ecSAndroid Build Coastguard Worker     memset(&selection_arg, 0, sizeof(selection_arg));
540*0ec5a0ecSAndroid Build Coastguard Worker     selection_arg.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
541*0ec5a0ecSAndroid Build Coastguard Worker     selection_arg.target = V4L2_SEL_TGT_CROP;
542*0ec5a0ecSAndroid Build Coastguard Worker     selection_arg.r = rect;
543*0ec5a0ecSAndroid Build Coastguard Worker     if (mDevice->ioctl(VIDIOC_S_SELECTION, &selection_arg) == 0) {
544*0ec5a0ecSAndroid Build Coastguard Worker         visibleRectangle = Rect(selection_arg.r.left, selection_arg.r.top,
545*0ec5a0ecSAndroid Build Coastguard Worker                                 selection_arg.r.left + selection_arg.r.width,
546*0ec5a0ecSAndroid Build Coastguard Worker                                 selection_arg.r.top + selection_arg.r.height);
547*0ec5a0ecSAndroid Build Coastguard Worker     } else {
548*0ec5a0ecSAndroid Build Coastguard Worker         struct v4l2_crop crop;
549*0ec5a0ecSAndroid Build Coastguard Worker         memset(&crop, 0, sizeof(v4l2_crop));
550*0ec5a0ecSAndroid Build Coastguard Worker         crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
551*0ec5a0ecSAndroid Build Coastguard Worker         crop.c = rect;
552*0ec5a0ecSAndroid Build Coastguard Worker         if (mDevice->ioctl(VIDIOC_S_CROP, &crop) != 0 ||
553*0ec5a0ecSAndroid Build Coastguard Worker             mDevice->ioctl(VIDIOC_G_CROP, &crop) != 0) {
554*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Failed to crop to specified visible rectangle");
555*0ec5a0ecSAndroid Build Coastguard Worker             return false;
556*0ec5a0ecSAndroid Build Coastguard Worker         }
557*0ec5a0ecSAndroid Build Coastguard Worker         visibleRectangle = Rect(crop.c.left, crop.c.top, crop.c.left + crop.c.width,
558*0ec5a0ecSAndroid Build Coastguard Worker                                 crop.c.top + crop.c.height);
559*0ec5a0ecSAndroid Build Coastguard Worker     }
560*0ec5a0ecSAndroid Build Coastguard Worker 
561*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("Input format set to %s (size: %s, adjusted size: %dx%d, coded size: %s)",
562*0ec5a0ecSAndroid Build Coastguard Worker           videoPixelFormatToString(mInputLayout->mFormat).c_str(), toString(mVisibleSize).c_str(),
563*0ec5a0ecSAndroid Build Coastguard Worker           visibleRectangle.width(), visibleRectangle.height(), toString(mInputCodedSize).c_str());
564*0ec5a0ecSAndroid Build Coastguard Worker 
565*0ec5a0ecSAndroid Build Coastguard Worker     mVisibleSize.set(visibleRectangle.width(), visibleRectangle.height());
566*0ec5a0ecSAndroid Build Coastguard Worker     return true;
567*0ec5a0ecSAndroid Build Coastguard Worker }
568*0ec5a0ecSAndroid Build Coastguard Worker 
configureOutputFormat(C2Config::profile_t outputProfile)569*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Encoder::configureOutputFormat(C2Config::profile_t outputProfile) {
570*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
571*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
572*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mState == State::UNINITIALIZED);
573*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(!mOutputQueue->isStreaming());
574*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(!isEmpty(mVisibleSize));
575*0ec5a0ecSAndroid Build Coastguard Worker 
576*0ec5a0ecSAndroid Build Coastguard Worker     auto format = mOutputQueue->setFormat(V4L2Device::c2ProfileToV4L2PixFmt(outputProfile, false),
577*0ec5a0ecSAndroid Build Coastguard Worker                                           mVisibleSize, GetMaxOutputBufferSize(mVisibleSize));
578*0ec5a0ecSAndroid Build Coastguard Worker     if (!format) {
579*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to set output format to %s", profileToString(outputProfile));
580*0ec5a0ecSAndroid Build Coastguard Worker         return false;
581*0ec5a0ecSAndroid Build Coastguard Worker     }
582*0ec5a0ecSAndroid Build Coastguard Worker 
583*0ec5a0ecSAndroid Build Coastguard Worker     // The device might adjust the requested output buffer size to match hardware requirements.
584*0ec5a0ecSAndroid Build Coastguard Worker     mOutputBufferSize = format->fmt.pix_mp.plane_fmt[0].sizeimage;
585*0ec5a0ecSAndroid Build Coastguard Worker 
586*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("Output format set to %s (buffer size: %u)", profileToString(outputProfile),
587*0ec5a0ecSAndroid Build Coastguard Worker           mOutputBufferSize);
588*0ec5a0ecSAndroid Build Coastguard Worker     return true;
589*0ec5a0ecSAndroid Build Coastguard Worker }
590*0ec5a0ecSAndroid Build Coastguard Worker 
configureDevice(C2Config::profile_t outputProfile,std::optional<const uint8_t> outputH264Level)591*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Encoder::configureDevice(C2Config::profile_t outputProfile,
592*0ec5a0ecSAndroid Build Coastguard Worker                                   std::optional<const uint8_t> outputH264Level) {
593*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
594*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
595*0ec5a0ecSAndroid Build Coastguard Worker 
596*0ec5a0ecSAndroid Build Coastguard Worker     // Enable frame-level bitrate control. This is the only mandatory general control.
597*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDevice->setExtCtrls(V4L2_CTRL_CLASS_MPEG,
598*0ec5a0ecSAndroid Build Coastguard Worker                               {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, 1)})) {
599*0ec5a0ecSAndroid Build Coastguard Worker         ALOGW("Failed enabling bitrate control");
600*0ec5a0ecSAndroid Build Coastguard Worker         // TODO(b/161508368): V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE is currently not supported yet,
601*0ec5a0ecSAndroid Build Coastguard Worker         // assume the operation was successful for now.
602*0ec5a0ecSAndroid Build Coastguard Worker     }
603*0ec5a0ecSAndroid Build Coastguard Worker 
604*0ec5a0ecSAndroid Build Coastguard Worker     // Additional optional controls:
605*0ec5a0ecSAndroid Build Coastguard Worker     // - Enable macroblock-level bitrate control.
606*0ec5a0ecSAndroid Build Coastguard Worker     // - Set GOP length to 0 to disable periodic key frames.
607*0ec5a0ecSAndroid Build Coastguard Worker     mDevice->setExtCtrls(V4L2_CTRL_CLASS_MPEG, {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, 1),
608*0ec5a0ecSAndroid Build Coastguard Worker                                                 V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0)});
609*0ec5a0ecSAndroid Build Coastguard Worker 
610*0ec5a0ecSAndroid Build Coastguard Worker     // All controls below are H.264-specific, so we can return here if the profile is not H.264.
611*0ec5a0ecSAndroid Build Coastguard Worker     if (outputProfile >= C2Config::PROFILE_AVC_BASELINE &&
612*0ec5a0ecSAndroid Build Coastguard Worker         outputProfile <= C2Config::PROFILE_AVC_ENHANCED_MULTIVIEW_DEPTH_HIGH) {
613*0ec5a0ecSAndroid Build Coastguard Worker         return configureH264(outputProfile, outputH264Level);
614*0ec5a0ecSAndroid Build Coastguard Worker     }
615*0ec5a0ecSAndroid Build Coastguard Worker 
616*0ec5a0ecSAndroid Build Coastguard Worker     return true;
617*0ec5a0ecSAndroid Build Coastguard Worker }
618*0ec5a0ecSAndroid Build Coastguard Worker 
configureH264(C2Config::profile_t outputProfile,std::optional<const uint8_t> outputH264Level)619*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Encoder::configureH264(C2Config::profile_t outputProfile,
620*0ec5a0ecSAndroid Build Coastguard Worker                                 std::optional<const uint8_t> outputH264Level) {
621*0ec5a0ecSAndroid Build Coastguard Worker     // When encoding H.264 we want to prepend SPS and PPS to each IDR for resilience. Some
622*0ec5a0ecSAndroid Build Coastguard Worker     // devices support this through the V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR control.
623*0ec5a0ecSAndroid Build Coastguard Worker     // Otherwise we have to cache the latest SPS and PPS and inject these manually.
624*0ec5a0ecSAndroid Build Coastguard Worker     if (mDevice->isCtrlExposed(V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR)) {
625*0ec5a0ecSAndroid Build Coastguard Worker         if (!mDevice->setExtCtrls(V4L2_CTRL_CLASS_MPEG,
626*0ec5a0ecSAndroid Build Coastguard Worker                                   {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR, 1)})) {
627*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Failed to configure device to prepend SPS and PPS to each IDR");
628*0ec5a0ecSAndroid Build Coastguard Worker             return false;
629*0ec5a0ecSAndroid Build Coastguard Worker         }
630*0ec5a0ecSAndroid Build Coastguard Worker         mInjectParamsBeforeIDR = false;
631*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Device supports prepending SPS and PPS to each IDR");
632*0ec5a0ecSAndroid Build Coastguard Worker     } else {
633*0ec5a0ecSAndroid Build Coastguard Worker         mInjectParamsBeforeIDR = true;
634*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Device doesn't support prepending SPS and PPS to IDR, injecting manually.");
635*0ec5a0ecSAndroid Build Coastguard Worker     }
636*0ec5a0ecSAndroid Build Coastguard Worker 
637*0ec5a0ecSAndroid Build Coastguard Worker     // Set the H.264 profile.
638*0ec5a0ecSAndroid Build Coastguard Worker     const int32_t profile = V4L2Device::c2ProfileToV4L2H264Profile(outputProfile);
639*0ec5a0ecSAndroid Build Coastguard Worker     if (profile < 0) {
640*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Trying to set invalid H.264 profile");
641*0ec5a0ecSAndroid Build Coastguard Worker         return false;
642*0ec5a0ecSAndroid Build Coastguard Worker     }
643*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDevice->setExtCtrls(V4L2_CTRL_CLASS_MPEG,
644*0ec5a0ecSAndroid Build Coastguard Worker                               {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_H264_PROFILE, profile)})) {
645*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed setting H.264 profile to %u", outputProfile);
646*0ec5a0ecSAndroid Build Coastguard Worker         return false;
647*0ec5a0ecSAndroid Build Coastguard Worker     }
648*0ec5a0ecSAndroid Build Coastguard Worker 
649*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<V4L2ExtCtrl> h264Ctrls;
650*0ec5a0ecSAndroid Build Coastguard Worker 
651*0ec5a0ecSAndroid Build Coastguard Worker     // No B-frames, for lowest decoding latency.
652*0ec5a0ecSAndroid Build Coastguard Worker     h264Ctrls.emplace_back(V4L2_CID_MPEG_VIDEO_B_FRAMES, 0);
653*0ec5a0ecSAndroid Build Coastguard Worker     // Quantization parameter maximum value (for variable bitrate control).
654*0ec5a0ecSAndroid Build Coastguard Worker     h264Ctrls.emplace_back(V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 51);
655*0ec5a0ecSAndroid Build Coastguard Worker 
656*0ec5a0ecSAndroid Build Coastguard Worker     // Set H.264 output level. Use Level 4.0 as fallback default.
657*0ec5a0ecSAndroid Build Coastguard Worker     int32_t h264Level =
658*0ec5a0ecSAndroid Build Coastguard Worker             static_cast<int32_t>(outputH264Level.value_or(V4L2_MPEG_VIDEO_H264_LEVEL_4_0));
659*0ec5a0ecSAndroid Build Coastguard Worker     h264Ctrls.emplace_back(V4L2_CID_MPEG_VIDEO_H264_LEVEL, h264Level);
660*0ec5a0ecSAndroid Build Coastguard Worker 
661*0ec5a0ecSAndroid Build Coastguard Worker     // Ask not to put SPS and PPS into separate bitstream buffers.
662*0ec5a0ecSAndroid Build Coastguard Worker     h264Ctrls.emplace_back(V4L2_CID_MPEG_VIDEO_HEADER_MODE,
663*0ec5a0ecSAndroid Build Coastguard Worker                            V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME);
664*0ec5a0ecSAndroid Build Coastguard Worker 
665*0ec5a0ecSAndroid Build Coastguard Worker     // Ignore return value as these controls are optional.
666*0ec5a0ecSAndroid Build Coastguard Worker     mDevice->setExtCtrls(V4L2_CTRL_CLASS_MPEG, std::move(h264Ctrls));
667*0ec5a0ecSAndroid Build Coastguard Worker 
668*0ec5a0ecSAndroid Build Coastguard Worker     return true;
669*0ec5a0ecSAndroid Build Coastguard Worker }
670*0ec5a0ecSAndroid Build Coastguard Worker 
configureBitrateMode(C2Config::bitrate_mode_t bitrateMode)671*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Encoder::configureBitrateMode(C2Config::bitrate_mode_t bitrateMode) {
672*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
673*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
674*0ec5a0ecSAndroid Build Coastguard Worker 
675*0ec5a0ecSAndroid Build Coastguard Worker     v4l2_mpeg_video_bitrate_mode v4l2BitrateMode =
676*0ec5a0ecSAndroid Build Coastguard Worker             V4L2Device::c2BitrateModeToV4L2BitrateMode(bitrateMode);
677*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDevice->setExtCtrls(V4L2_CTRL_CLASS_MPEG,
678*0ec5a0ecSAndroid Build Coastguard Worker                               {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_BITRATE_MODE, v4l2BitrateMode)})) {
679*0ec5a0ecSAndroid Build Coastguard Worker         // TODO(b/190336806): Our stack doesn't support bitrate mode changes yet. We default to CBR
680*0ec5a0ecSAndroid Build Coastguard Worker         // which is currently the only supported mode so we can safely ignore this for now.
681*0ec5a0ecSAndroid Build Coastguard Worker         ALOGW("Setting bitrate mode to %u failed", v4l2BitrateMode);
682*0ec5a0ecSAndroid Build Coastguard Worker     }
683*0ec5a0ecSAndroid Build Coastguard Worker     return true;
684*0ec5a0ecSAndroid Build Coastguard Worker }
685*0ec5a0ecSAndroid Build Coastguard Worker 
startDevicePoll()686*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Encoder::startDevicePoll() {
687*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
688*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
689*0ec5a0ecSAndroid Build Coastguard Worker 
690*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDevice->startPolling(mTaskRunner,
691*0ec5a0ecSAndroid Build Coastguard Worker                                ::base::BindRepeating(&V4L2Encoder::serviceDeviceTask, mWeakThis),
692*0ec5a0ecSAndroid Build Coastguard Worker                                ::base::BindRepeating(&V4L2Encoder::onPollError, mWeakThis))) {
693*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Device poll thread failed to start");
694*0ec5a0ecSAndroid Build Coastguard Worker         onError();
695*0ec5a0ecSAndroid Build Coastguard Worker         return false;
696*0ec5a0ecSAndroid Build Coastguard Worker     }
697*0ec5a0ecSAndroid Build Coastguard Worker 
698*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("Device poll started");
699*0ec5a0ecSAndroid Build Coastguard Worker     return true;
700*0ec5a0ecSAndroid Build Coastguard Worker }
701*0ec5a0ecSAndroid Build Coastguard Worker 
stopDevicePoll()702*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Encoder::stopDevicePoll() {
703*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
704*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
705*0ec5a0ecSAndroid Build Coastguard Worker 
706*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDevice->stopPolling()) {
707*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to stop polling on the device");
708*0ec5a0ecSAndroid Build Coastguard Worker         onError();
709*0ec5a0ecSAndroid Build Coastguard Worker         return false;
710*0ec5a0ecSAndroid Build Coastguard Worker     }
711*0ec5a0ecSAndroid Build Coastguard Worker 
712*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("Device poll stopped");
713*0ec5a0ecSAndroid Build Coastguard Worker     return true;
714*0ec5a0ecSAndroid Build Coastguard Worker }
715*0ec5a0ecSAndroid Build Coastguard Worker 
onPollError()716*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Encoder::onPollError() {
717*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
718*0ec5a0ecSAndroid Build Coastguard Worker     onError();
719*0ec5a0ecSAndroid Build Coastguard Worker }
720*0ec5a0ecSAndroid Build Coastguard Worker 
serviceDeviceTask(bool)721*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Encoder::serviceDeviceTask(bool /*event*/) {
722*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
723*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
724*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mState != State::UNINITIALIZED);
725*0ec5a0ecSAndroid Build Coastguard Worker 
726*0ec5a0ecSAndroid Build Coastguard Worker     if (mState == State::ERROR) {
727*0ec5a0ecSAndroid Build Coastguard Worker         return;
728*0ec5a0ecSAndroid Build Coastguard Worker     }
729*0ec5a0ecSAndroid Build Coastguard Worker 
730*0ec5a0ecSAndroid Build Coastguard Worker     // Dequeue completed input (VIDEO_OUTPUT) buffers, and recycle to the free list.
731*0ec5a0ecSAndroid Build Coastguard Worker     while (mInputQueue->queuedBuffersCount() > 0) {
732*0ec5a0ecSAndroid Build Coastguard Worker         if (!dequeueInputBuffer()) break;
733*0ec5a0ecSAndroid Build Coastguard Worker     }
734*0ec5a0ecSAndroid Build Coastguard Worker 
735*0ec5a0ecSAndroid Build Coastguard Worker     // Dequeue completed output (VIDEO_CAPTURE) buffers, and recycle to the free list.
736*0ec5a0ecSAndroid Build Coastguard Worker     while (mOutputQueue->queuedBuffersCount() > 0) {
737*0ec5a0ecSAndroid Build Coastguard Worker         if (!dequeueOutputBuffer()) break;
738*0ec5a0ecSAndroid Build Coastguard Worker     }
739*0ec5a0ecSAndroid Build Coastguard Worker 
740*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s() - done", __func__);
741*0ec5a0ecSAndroid Build Coastguard Worker }
742*0ec5a0ecSAndroid Build Coastguard Worker 
enqueueInputBuffer(std::unique_ptr<InputFrame> frame)743*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Encoder::enqueueInputBuffer(std::unique_ptr<InputFrame> frame) {
744*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
745*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mInputQueue->freeBuffersCount() > 0);
746*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mState == State::ENCODING);
747*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(frame);
748*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mInputLayout->mFormat == frame->pixelFormat());
749*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mInputLayout->mPlanes.size() == frame->planes().size());
750*0ec5a0ecSAndroid Build Coastguard Worker 
751*0ec5a0ecSAndroid Build Coastguard Worker     auto format = frame->pixelFormat();
752*0ec5a0ecSAndroid Build Coastguard Worker     auto& planes = frame->planes();
753*0ec5a0ecSAndroid Build Coastguard Worker     auto index = frame->index();
754*0ec5a0ecSAndroid Build Coastguard Worker     auto timestamp = frame->timestamp();
755*0ec5a0ecSAndroid Build Coastguard Worker 
756*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(): queuing input buffer (index: %" PRId64 ")", __func__, index);
757*0ec5a0ecSAndroid Build Coastguard Worker 
758*0ec5a0ecSAndroid Build Coastguard Worker     auto buffer = mInputQueue->getFreeBuffer();
759*0ec5a0ecSAndroid Build Coastguard Worker     if (!buffer) {
760*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to get free buffer from device input queue");
761*0ec5a0ecSAndroid Build Coastguard Worker         return false;
762*0ec5a0ecSAndroid Build Coastguard Worker     }
763*0ec5a0ecSAndroid Build Coastguard Worker 
764*0ec5a0ecSAndroid Build Coastguard Worker     // Mark the buffer with the frame's timestamp so we can identify the associated output buffers.
765*0ec5a0ecSAndroid Build Coastguard Worker     buffer->setTimeStamp(
766*0ec5a0ecSAndroid Build Coastguard Worker             {.tv_sec = static_cast<time_t>(timestamp / ::base::Time::kMicrosecondsPerSecond),
767*0ec5a0ecSAndroid Build Coastguard Worker              .tv_usec = static_cast<time_t>(timestamp % ::base::Time::kMicrosecondsPerSecond)});
768*0ec5a0ecSAndroid Build Coastguard Worker     size_t bufferId = buffer->bufferId();
769*0ec5a0ecSAndroid Build Coastguard Worker 
770*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<int> fds = frame->fds();
771*0ec5a0ecSAndroid Build Coastguard Worker     if (mInputLayout->mMultiPlanar) {
772*0ec5a0ecSAndroid Build Coastguard Worker         // If the input format is multi-planar, then we need to submit one memory plane per color
773*0ec5a0ecSAndroid Build Coastguard Worker         // plane of our input frames.
774*0ec5a0ecSAndroid Build Coastguard Worker         for (size_t i = 0; i < planes.size(); ++i) {
775*0ec5a0ecSAndroid Build Coastguard Worker             size_t bytesUsed = ::base::checked_cast<size_t>(
776*0ec5a0ecSAndroid Build Coastguard Worker                     getArea(planeSize(format, i, mInputLayout->mCodedSize)).value());
777*0ec5a0ecSAndroid Build Coastguard Worker 
778*0ec5a0ecSAndroid Build Coastguard Worker             // TODO(crbug.com/901264): The way to pass an offset within a DMA-buf is not defined
779*0ec5a0ecSAndroid Build Coastguard Worker             // in V4L2 specification, so we abuse data_offset for now. Fix it when we have the
780*0ec5a0ecSAndroid Build Coastguard Worker             // right interface, including any necessary validation and potential alignment.
781*0ec5a0ecSAndroid Build Coastguard Worker             buffer->setPlaneDataOffset(i, planes[i].mOffset);
782*0ec5a0ecSAndroid Build Coastguard Worker             bytesUsed += planes[i].mOffset;
783*0ec5a0ecSAndroid Build Coastguard Worker             // Workaround: filling length should not be needed. This is a bug of videobuf2 library.
784*0ec5a0ecSAndroid Build Coastguard Worker             buffer->setPlaneSize(i, mInputLayout->mPlanes[i].mSize + planes[i].mOffset);
785*0ec5a0ecSAndroid Build Coastguard Worker             buffer->setPlaneBytesUsed(i, bytesUsed);
786*0ec5a0ecSAndroid Build Coastguard Worker         }
787*0ec5a0ecSAndroid Build Coastguard Worker     } else {
788*0ec5a0ecSAndroid Build Coastguard Worker         ALOG_ASSERT(!planes.empty());
789*0ec5a0ecSAndroid Build Coastguard Worker         // If the input format is single-planar, then we only submit one buffer which contains
790*0ec5a0ecSAndroid Build Coastguard Worker         // all the color planes.
791*0ec5a0ecSAndroid Build Coastguard Worker         size_t bytesUsed = allocationSize(format, mInputLayout->mCodedSize);
792*0ec5a0ecSAndroid Build Coastguard Worker 
793*0ec5a0ecSAndroid Build Coastguard Worker         // TODO(crbug.com/901264): The way to pass an offset within a DMA-buf is not defined
794*0ec5a0ecSAndroid Build Coastguard Worker         // in V4L2 specification, so we abuse data_offset for now. Fix it when we have the
795*0ec5a0ecSAndroid Build Coastguard Worker         // right interface, including any necessary validation and potential alignment.
796*0ec5a0ecSAndroid Build Coastguard Worker         buffer->setPlaneDataOffset(0, planes[0].mOffset);
797*0ec5a0ecSAndroid Build Coastguard Worker         bytesUsed += planes[0].mOffset;
798*0ec5a0ecSAndroid Build Coastguard Worker         // Workaround: filling length should not be needed. This is a bug of videobuf2 library.
799*0ec5a0ecSAndroid Build Coastguard Worker         buffer->setPlaneSize(0, bytesUsed);
800*0ec5a0ecSAndroid Build Coastguard Worker         buffer->setPlaneBytesUsed(0, bytesUsed);
801*0ec5a0ecSAndroid Build Coastguard Worker         // We only have one memory plane so we shall submit only one FD. The others are duplicates
802*0ec5a0ecSAndroid Build Coastguard Worker         // of the first one anyway.
803*0ec5a0ecSAndroid Build Coastguard Worker         fds.resize(1);
804*0ec5a0ecSAndroid Build Coastguard Worker     }
805*0ec5a0ecSAndroid Build Coastguard Worker 
806*0ec5a0ecSAndroid Build Coastguard Worker     if (!std::move(*buffer).queueDMABuf(fds)) {
807*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to queue input buffer using QueueDMABuf");
808*0ec5a0ecSAndroid Build Coastguard Worker         onError();
809*0ec5a0ecSAndroid Build Coastguard Worker         return false;
810*0ec5a0ecSAndroid Build Coastguard Worker     }
811*0ec5a0ecSAndroid Build Coastguard Worker 
812*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("Queued buffer in input queue (index: %" PRId64 ", timestamp: %" PRId64
813*0ec5a0ecSAndroid Build Coastguard Worker           ", bufferId: %zu)",
814*0ec5a0ecSAndroid Build Coastguard Worker           index, timestamp, bufferId);
815*0ec5a0ecSAndroid Build Coastguard Worker 
816*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(!mInputBuffers[bufferId]);
817*0ec5a0ecSAndroid Build Coastguard Worker     mInputBuffers[bufferId] = std::move(frame);
818*0ec5a0ecSAndroid Build Coastguard Worker 
819*0ec5a0ecSAndroid Build Coastguard Worker     return true;
820*0ec5a0ecSAndroid Build Coastguard Worker }
821*0ec5a0ecSAndroid Build Coastguard Worker 
enqueueOutputBuffer()822*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Encoder::enqueueOutputBuffer() {
823*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
824*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
825*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mOutputQueue->freeBuffersCount() > 0);
826*0ec5a0ecSAndroid Build Coastguard Worker 
827*0ec5a0ecSAndroid Build Coastguard Worker     auto buffer = mOutputQueue->getFreeBuffer();
828*0ec5a0ecSAndroid Build Coastguard Worker     if (!buffer) {
829*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to get free buffer from device output queue");
830*0ec5a0ecSAndroid Build Coastguard Worker         onError();
831*0ec5a0ecSAndroid Build Coastguard Worker         return false;
832*0ec5a0ecSAndroid Build Coastguard Worker     }
833*0ec5a0ecSAndroid Build Coastguard Worker 
834*0ec5a0ecSAndroid Build Coastguard Worker     std::unique_ptr<BitstreamBuffer> bitstreamBuffer;
835*0ec5a0ecSAndroid Build Coastguard Worker     mFetchOutputBufferCb.Run(mOutputBufferSize, &bitstreamBuffer);
836*0ec5a0ecSAndroid Build Coastguard Worker     if (!bitstreamBuffer) {
837*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to fetch output block");
838*0ec5a0ecSAndroid Build Coastguard Worker         onError();
839*0ec5a0ecSAndroid Build Coastguard Worker         return false;
840*0ec5a0ecSAndroid Build Coastguard Worker     }
841*0ec5a0ecSAndroid Build Coastguard Worker 
842*0ec5a0ecSAndroid Build Coastguard Worker     size_t bufferId = buffer->bufferId();
843*0ec5a0ecSAndroid Build Coastguard Worker 
844*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<int> fds;
845*0ec5a0ecSAndroid Build Coastguard Worker     fds.push_back(bitstreamBuffer->dmabuf->handle()->data[0]);
846*0ec5a0ecSAndroid Build Coastguard Worker     if (!std::move(*buffer).queueDMABuf(fds)) {
847*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to queue output buffer using QueueDMABuf");
848*0ec5a0ecSAndroid Build Coastguard Worker         onError();
849*0ec5a0ecSAndroid Build Coastguard Worker         return false;
850*0ec5a0ecSAndroid Build Coastguard Worker     }
851*0ec5a0ecSAndroid Build Coastguard Worker 
852*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(!mOutputBuffers[bufferId]);
853*0ec5a0ecSAndroid Build Coastguard Worker     mOutputBuffers[bufferId] = std::move(bitstreamBuffer);
854*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(): Queued buffer in output queue (bufferId: %zu)", __func__, bufferId);
855*0ec5a0ecSAndroid Build Coastguard Worker     return true;
856*0ec5a0ecSAndroid Build Coastguard Worker }
857*0ec5a0ecSAndroid Build Coastguard Worker 
dequeueInputBuffer()858*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Encoder::dequeueInputBuffer() {
859*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
860*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
861*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mState != State::UNINITIALIZED);
862*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mInputQueue->queuedBuffersCount() > 0);
863*0ec5a0ecSAndroid Build Coastguard Worker 
864*0ec5a0ecSAndroid Build Coastguard Worker     if (mState == State::ERROR) {
865*0ec5a0ecSAndroid Build Coastguard Worker         return false;
866*0ec5a0ecSAndroid Build Coastguard Worker     }
867*0ec5a0ecSAndroid Build Coastguard Worker 
868*0ec5a0ecSAndroid Build Coastguard Worker     bool success;
869*0ec5a0ecSAndroid Build Coastguard Worker     V4L2ReadableBufferRef buffer;
870*0ec5a0ecSAndroid Build Coastguard Worker     std::tie(success, buffer) = mInputQueue->dequeueBuffer();
871*0ec5a0ecSAndroid Build Coastguard Worker     if (!success) {
872*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to dequeue buffer from input queue");
873*0ec5a0ecSAndroid Build Coastguard Worker         onError();
874*0ec5a0ecSAndroid Build Coastguard Worker         return false;
875*0ec5a0ecSAndroid Build Coastguard Worker     }
876*0ec5a0ecSAndroid Build Coastguard Worker     if (!buffer) {
877*0ec5a0ecSAndroid Build Coastguard Worker         // No more buffers ready to be dequeued in input queue.
878*0ec5a0ecSAndroid Build Coastguard Worker         return false;
879*0ec5a0ecSAndroid Build Coastguard Worker     }
880*0ec5a0ecSAndroid Build Coastguard Worker 
881*0ec5a0ecSAndroid Build Coastguard Worker     uint64_t index = mInputBuffers[buffer->bufferId()]->index();
882*0ec5a0ecSAndroid Build Coastguard Worker     int64_t timestamp = buffer->getTimeStamp().tv_usec +
883*0ec5a0ecSAndroid Build Coastguard Worker                         buffer->getTimeStamp().tv_sec * ::base::Time::kMicrosecondsPerSecond;
884*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("Dequeued buffer from input queue (index: %" PRId64 ", timestamp: %" PRId64
885*0ec5a0ecSAndroid Build Coastguard Worker           ", bufferId: %zu)",
886*0ec5a0ecSAndroid Build Coastguard Worker           index, timestamp, buffer->bufferId());
887*0ec5a0ecSAndroid Build Coastguard Worker 
888*0ec5a0ecSAndroid Build Coastguard Worker     mInputBuffers[buffer->bufferId()] = nullptr;
889*0ec5a0ecSAndroid Build Coastguard Worker 
890*0ec5a0ecSAndroid Build Coastguard Worker     mInputBufferDoneCb.Run(index);
891*0ec5a0ecSAndroid Build Coastguard Worker 
892*0ec5a0ecSAndroid Build Coastguard Worker     // If we previously used up all input queue buffers we can start encoding again now.
893*0ec5a0ecSAndroid Build Coastguard Worker     if ((mState == State::WAITING_FOR_V4L2_BUFFER) && !mEncodeRequests.empty()) {
894*0ec5a0ecSAndroid Build Coastguard Worker         setState(State::ENCODING);
895*0ec5a0ecSAndroid Build Coastguard Worker         mTaskRunner->PostTask(FROM_HERE,
896*0ec5a0ecSAndroid Build Coastguard Worker                               ::base::BindOnce(&V4L2Encoder::handleEncodeRequest, mWeakThis));
897*0ec5a0ecSAndroid Build Coastguard Worker     }
898*0ec5a0ecSAndroid Build Coastguard Worker 
899*0ec5a0ecSAndroid Build Coastguard Worker     return true;
900*0ec5a0ecSAndroid Build Coastguard Worker }
901*0ec5a0ecSAndroid Build Coastguard Worker 
dequeueOutputBuffer()902*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Encoder::dequeueOutputBuffer() {
903*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
904*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
905*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mState != State::UNINITIALIZED);
906*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mOutputQueue->queuedBuffersCount() > 0);
907*0ec5a0ecSAndroid Build Coastguard Worker 
908*0ec5a0ecSAndroid Build Coastguard Worker     if (mState == State::ERROR) {
909*0ec5a0ecSAndroid Build Coastguard Worker         return false;
910*0ec5a0ecSAndroid Build Coastguard Worker     }
911*0ec5a0ecSAndroid Build Coastguard Worker 
912*0ec5a0ecSAndroid Build Coastguard Worker     bool success;
913*0ec5a0ecSAndroid Build Coastguard Worker     V4L2ReadableBufferRef buffer;
914*0ec5a0ecSAndroid Build Coastguard Worker     std::tie(success, buffer) = mOutputQueue->dequeueBuffer();
915*0ec5a0ecSAndroid Build Coastguard Worker     if (!success) {
916*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to dequeue buffer from output queue");
917*0ec5a0ecSAndroid Build Coastguard Worker         onError();
918*0ec5a0ecSAndroid Build Coastguard Worker         return false;
919*0ec5a0ecSAndroid Build Coastguard Worker     }
920*0ec5a0ecSAndroid Build Coastguard Worker     if (!buffer) {
921*0ec5a0ecSAndroid Build Coastguard Worker         // No more buffers ready to be dequeued in output queue.
922*0ec5a0ecSAndroid Build Coastguard Worker         return false;
923*0ec5a0ecSAndroid Build Coastguard Worker     }
924*0ec5a0ecSAndroid Build Coastguard Worker 
925*0ec5a0ecSAndroid Build Coastguard Worker     size_t encodedDataSize = buffer->getPlaneBytesUsed(0) - buffer->getPlaneDataOffset(0);
926*0ec5a0ecSAndroid Build Coastguard Worker     ::base::TimeDelta timestamp = ::base::TimeDelta::FromMicroseconds(
927*0ec5a0ecSAndroid Build Coastguard Worker             buffer->getTimeStamp().tv_usec +
928*0ec5a0ecSAndroid Build Coastguard Worker             buffer->getTimeStamp().tv_sec * ::base::Time::kMicrosecondsPerSecond);
929*0ec5a0ecSAndroid Build Coastguard Worker 
930*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("Dequeued buffer from output queue (timestamp: %" PRId64
931*0ec5a0ecSAndroid Build Coastguard Worker           ", bufferId: %zu, data size: %zu, EOS: %d)",
932*0ec5a0ecSAndroid Build Coastguard Worker           timestamp.InMicroseconds(), buffer->bufferId(), encodedDataSize, buffer->isLast());
933*0ec5a0ecSAndroid Build Coastguard Worker 
934*0ec5a0ecSAndroid Build Coastguard Worker     if (!mOutputBuffers[buffer->bufferId()]) {
935*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to find output block associated with output buffer");
936*0ec5a0ecSAndroid Build Coastguard Worker         onError();
937*0ec5a0ecSAndroid Build Coastguard Worker         return false;
938*0ec5a0ecSAndroid Build Coastguard Worker     }
939*0ec5a0ecSAndroid Build Coastguard Worker 
940*0ec5a0ecSAndroid Build Coastguard Worker     std::unique_ptr<BitstreamBuffer> bitstreamBuffer =
941*0ec5a0ecSAndroid Build Coastguard Worker             std::move(mOutputBuffers[buffer->bufferId()]);
942*0ec5a0ecSAndroid Build Coastguard Worker     if (encodedDataSize > 0) {
943*0ec5a0ecSAndroid Build Coastguard Worker         if (!mInjectParamsBeforeIDR) {
944*0ec5a0ecSAndroid Build Coastguard Worker             // No need to inject SPS or PPS before IDR frames, we can just return the buffer as-is.
945*0ec5a0ecSAndroid Build Coastguard Worker             mOutputBufferDoneCb.Run(encodedDataSize, timestamp.InMicroseconds(),
946*0ec5a0ecSAndroid Build Coastguard Worker                                     buffer->isKeyframe(), std::move(bitstreamBuffer));
947*0ec5a0ecSAndroid Build Coastguard Worker         } else if (!buffer->isKeyframe()) {
948*0ec5a0ecSAndroid Build Coastguard Worker             // We need to inject SPS and PPS before IDR frames, but this frame is not a key frame.
949*0ec5a0ecSAndroid Build Coastguard Worker             // We can return the buffer as-is, but need to update our SPS and PPS cache if required.
950*0ec5a0ecSAndroid Build Coastguard Worker             C2ConstLinearBlock constBlock = bitstreamBuffer->dmabuf->share(
951*0ec5a0ecSAndroid Build Coastguard Worker                     bitstreamBuffer->dmabuf->offset(), encodedDataSize, C2Fence());
952*0ec5a0ecSAndroid Build Coastguard Worker             C2ReadView readView = constBlock.map().get();
953*0ec5a0ecSAndroid Build Coastguard Worker             extractSPSPPS(readView.data(), encodedDataSize, &mCachedSPS, &mCachedPPS);
954*0ec5a0ecSAndroid Build Coastguard Worker             mOutputBufferDoneCb.Run(encodedDataSize, timestamp.InMicroseconds(),
955*0ec5a0ecSAndroid Build Coastguard Worker                                     buffer->isKeyframe(), std::move(bitstreamBuffer));
956*0ec5a0ecSAndroid Build Coastguard Worker         } else {
957*0ec5a0ecSAndroid Build Coastguard Worker             // We need to inject our cached SPS and PPS NAL units to the IDR frame. It's possible
958*0ec5a0ecSAndroid Build Coastguard Worker             // this frame already has SPS and PPS NAL units attached, in which case we only need to
959*0ec5a0ecSAndroid Build Coastguard Worker             // update our cached SPS and PPS.
960*0ec5a0ecSAndroid Build Coastguard Worker             C2ConstLinearBlock constBlock = bitstreamBuffer->dmabuf->share(
961*0ec5a0ecSAndroid Build Coastguard Worker                     bitstreamBuffer->dmabuf->offset(), encodedDataSize, C2Fence());
962*0ec5a0ecSAndroid Build Coastguard Worker             C2ReadView readView = constBlock.map().get();
963*0ec5a0ecSAndroid Build Coastguard Worker 
964*0ec5a0ecSAndroid Build Coastguard Worker             // Allocate a new buffer to copy the data with prepended SPS and PPS into.
965*0ec5a0ecSAndroid Build Coastguard Worker             std::unique_ptr<BitstreamBuffer> prependedBitstreamBuffer;
966*0ec5a0ecSAndroid Build Coastguard Worker             mFetchOutputBufferCb.Run(mOutputBufferSize, &prependedBitstreamBuffer);
967*0ec5a0ecSAndroid Build Coastguard Worker             if (!prependedBitstreamBuffer) {
968*0ec5a0ecSAndroid Build Coastguard Worker                 ALOGE("Failed to fetch output block");
969*0ec5a0ecSAndroid Build Coastguard Worker                 onError();
970*0ec5a0ecSAndroid Build Coastguard Worker                 return false;
971*0ec5a0ecSAndroid Build Coastguard Worker             }
972*0ec5a0ecSAndroid Build Coastguard Worker             C2WriteView writeView = prependedBitstreamBuffer->dmabuf->map().get();
973*0ec5a0ecSAndroid Build Coastguard Worker 
974*0ec5a0ecSAndroid Build Coastguard Worker             // If there is not enough space in the output buffer just return the original buffer.
975*0ec5a0ecSAndroid Build Coastguard Worker             size_t newSize = prependSPSPPSToIDR(readView.data(), encodedDataSize, writeView.data(),
976*0ec5a0ecSAndroid Build Coastguard Worker                                                 writeView.size(), &mCachedSPS, &mCachedPPS);
977*0ec5a0ecSAndroid Build Coastguard Worker             if (newSize > 0) {
978*0ec5a0ecSAndroid Build Coastguard Worker                 mOutputBufferDoneCb.Run(newSize, timestamp.InMicroseconds(), buffer->isKeyframe(),
979*0ec5a0ecSAndroid Build Coastguard Worker                                         std::move(prependedBitstreamBuffer));
980*0ec5a0ecSAndroid Build Coastguard Worker             } else {
981*0ec5a0ecSAndroid Build Coastguard Worker                 mOutputBufferDoneCb.Run(encodedDataSize, timestamp.InMicroseconds(),
982*0ec5a0ecSAndroid Build Coastguard Worker                                         buffer->isKeyframe(), std::move(bitstreamBuffer));
983*0ec5a0ecSAndroid Build Coastguard Worker             }
984*0ec5a0ecSAndroid Build Coastguard Worker         }
985*0ec5a0ecSAndroid Build Coastguard Worker     }
986*0ec5a0ecSAndroid Build Coastguard Worker 
987*0ec5a0ecSAndroid Build Coastguard Worker     // If the buffer is marked as last and we were flushing the encoder, flushing is now done.
988*0ec5a0ecSAndroid Build Coastguard Worker     if ((mState == State::DRAINING) && buffer->isLast()) {
989*0ec5a0ecSAndroid Build Coastguard Worker         onDrainDone(true);
990*0ec5a0ecSAndroid Build Coastguard Worker         // Start the encoder again.
991*0ec5a0ecSAndroid Build Coastguard Worker         struct v4l2_encoder_cmd cmd;
992*0ec5a0ecSAndroid Build Coastguard Worker         memset(&cmd, 0, sizeof(v4l2_encoder_cmd));
993*0ec5a0ecSAndroid Build Coastguard Worker         cmd.cmd = V4L2_ENC_CMD_START;
994*0ec5a0ecSAndroid Build Coastguard Worker         if (mDevice->ioctl(VIDIOC_ENCODER_CMD, &cmd) != 0) {
995*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Failed to restart encoder after draining (V4L2_ENC_CMD_START)");
996*0ec5a0ecSAndroid Build Coastguard Worker             onError();
997*0ec5a0ecSAndroid Build Coastguard Worker             return false;
998*0ec5a0ecSAndroid Build Coastguard Worker         }
999*0ec5a0ecSAndroid Build Coastguard Worker     }
1000*0ec5a0ecSAndroid Build Coastguard Worker 
1001*0ec5a0ecSAndroid Build Coastguard Worker     // Queue a new output buffer to replace the one we dequeued.
1002*0ec5a0ecSAndroid Build Coastguard Worker     buffer = nullptr;
1003*0ec5a0ecSAndroid Build Coastguard Worker     enqueueOutputBuffer();
1004*0ec5a0ecSAndroid Build Coastguard Worker 
1005*0ec5a0ecSAndroid Build Coastguard Worker     return true;
1006*0ec5a0ecSAndroid Build Coastguard Worker }
1007*0ec5a0ecSAndroid Build Coastguard Worker 
createInputBuffers()1008*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Encoder::createInputBuffers() {
1009*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
1010*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
1011*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(!mInputQueue->isStreaming());
1012*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mInputBuffers.empty());
1013*0ec5a0ecSAndroid Build Coastguard Worker 
1014*0ec5a0ecSAndroid Build Coastguard Worker     // No memory is allocated here, we just generate a list of buffers on the input queue, which
1015*0ec5a0ecSAndroid Build Coastguard Worker     // will hold memory handles to the real buffers.
1016*0ec5a0ecSAndroid Build Coastguard Worker     if (mInputQueue->allocateBuffers(kInputBufferCount, V4L2_MEMORY_DMABUF) < kInputBufferCount) {
1017*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to create V4L2 input buffers.");
1018*0ec5a0ecSAndroid Build Coastguard Worker         return false;
1019*0ec5a0ecSAndroid Build Coastguard Worker     }
1020*0ec5a0ecSAndroid Build Coastguard Worker 
1021*0ec5a0ecSAndroid Build Coastguard Worker     mInputBuffers.resize(mInputQueue->allocatedBuffersCount());
1022*0ec5a0ecSAndroid Build Coastguard Worker     return true;
1023*0ec5a0ecSAndroid Build Coastguard Worker }
1024*0ec5a0ecSAndroid Build Coastguard Worker 
createOutputBuffers()1025*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Encoder::createOutputBuffers() {
1026*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
1027*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
1028*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(!mOutputQueue->isStreaming());
1029*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mOutputBuffers.empty());
1030*0ec5a0ecSAndroid Build Coastguard Worker 
1031*0ec5a0ecSAndroid Build Coastguard Worker     // No memory is allocated here, we just generate a list of buffers on the output queue, which
1032*0ec5a0ecSAndroid Build Coastguard Worker     // will hold memory handles to the real buffers.
1033*0ec5a0ecSAndroid Build Coastguard Worker     if (mOutputQueue->allocateBuffers(kOutputBufferCount, V4L2_MEMORY_DMABUF) <
1034*0ec5a0ecSAndroid Build Coastguard Worker         kOutputBufferCount) {
1035*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to create V4L2 output buffers.");
1036*0ec5a0ecSAndroid Build Coastguard Worker         return false;
1037*0ec5a0ecSAndroid Build Coastguard Worker     }
1038*0ec5a0ecSAndroid Build Coastguard Worker 
1039*0ec5a0ecSAndroid Build Coastguard Worker     mOutputBuffers.resize(mOutputQueue->allocatedBuffersCount());
1040*0ec5a0ecSAndroid Build Coastguard Worker     return true;
1041*0ec5a0ecSAndroid Build Coastguard Worker }
1042*0ec5a0ecSAndroid Build Coastguard Worker 
destroyInputBuffers()1043*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Encoder::destroyInputBuffers() {
1044*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
1045*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
1046*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(!mInputQueue->isStreaming());
1047*0ec5a0ecSAndroid Build Coastguard Worker 
1048*0ec5a0ecSAndroid Build Coastguard Worker     if (!mInputQueue || mInputQueue->allocatedBuffersCount() == 0) return;
1049*0ec5a0ecSAndroid Build Coastguard Worker     mInputQueue->deallocateBuffers();
1050*0ec5a0ecSAndroid Build Coastguard Worker     mInputBuffers.clear();
1051*0ec5a0ecSAndroid Build Coastguard Worker }
1052*0ec5a0ecSAndroid Build Coastguard Worker 
destroyOutputBuffers()1053*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Encoder::destroyOutputBuffers() {
1054*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
1055*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
1056*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(!mOutputQueue->isStreaming());
1057*0ec5a0ecSAndroid Build Coastguard Worker 
1058*0ec5a0ecSAndroid Build Coastguard Worker     if (!mOutputQueue || mOutputQueue->allocatedBuffersCount() == 0) return;
1059*0ec5a0ecSAndroid Build Coastguard Worker     mOutputQueue->deallocateBuffers();
1060*0ec5a0ecSAndroid Build Coastguard Worker     mOutputBuffers.clear();
1061*0ec5a0ecSAndroid Build Coastguard Worker }
1062*0ec5a0ecSAndroid Build Coastguard Worker 
onError()1063*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Encoder::onError() {
1064*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
1065*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
1066*0ec5a0ecSAndroid Build Coastguard Worker 
1067*0ec5a0ecSAndroid Build Coastguard Worker     if (mState != State::ERROR) {
1068*0ec5a0ecSAndroid Build Coastguard Worker         setState(State::ERROR);
1069*0ec5a0ecSAndroid Build Coastguard Worker         mErrorCb.Run();
1070*0ec5a0ecSAndroid Build Coastguard Worker     }
1071*0ec5a0ecSAndroid Build Coastguard Worker }
1072*0ec5a0ecSAndroid Build Coastguard Worker 
setState(State state)1073*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Encoder::setState(State state) {
1074*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
1075*0ec5a0ecSAndroid Build Coastguard Worker 
1076*0ec5a0ecSAndroid Build Coastguard Worker     // Check whether the state change is valid.
1077*0ec5a0ecSAndroid Build Coastguard Worker     switch (state) {
1078*0ec5a0ecSAndroid Build Coastguard Worker     case State::UNINITIALIZED:
1079*0ec5a0ecSAndroid Build Coastguard Worker         break;
1080*0ec5a0ecSAndroid Build Coastguard Worker     case State::WAITING_FOR_INPUT_FRAME:
1081*0ec5a0ecSAndroid Build Coastguard Worker         ALOG_ASSERT(mState != State::ERROR);
1082*0ec5a0ecSAndroid Build Coastguard Worker         break;
1083*0ec5a0ecSAndroid Build Coastguard Worker     case State::WAITING_FOR_V4L2_BUFFER:
1084*0ec5a0ecSAndroid Build Coastguard Worker         ALOG_ASSERT(mState == State::ENCODING);
1085*0ec5a0ecSAndroid Build Coastguard Worker         break;
1086*0ec5a0ecSAndroid Build Coastguard Worker     case State::ENCODING:
1087*0ec5a0ecSAndroid Build Coastguard Worker         ALOG_ASSERT(mState == State::WAITING_FOR_INPUT_FRAME ||
1088*0ec5a0ecSAndroid Build Coastguard Worker                     mState == State::WAITING_FOR_V4L2_BUFFER || mState == State::DRAINING);
1089*0ec5a0ecSAndroid Build Coastguard Worker         break;
1090*0ec5a0ecSAndroid Build Coastguard Worker     case State::DRAINING:
1091*0ec5a0ecSAndroid Build Coastguard Worker         ALOG_ASSERT(mState == State::ENCODING || mState == State::WAITING_FOR_INPUT_FRAME);
1092*0ec5a0ecSAndroid Build Coastguard Worker         break;
1093*0ec5a0ecSAndroid Build Coastguard Worker     case State::ERROR:
1094*0ec5a0ecSAndroid Build Coastguard Worker         break;
1095*0ec5a0ecSAndroid Build Coastguard Worker     }
1096*0ec5a0ecSAndroid Build Coastguard Worker 
1097*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("Changed encoder state from %s to %s", stateToString(mState), stateToString(state));
1098*0ec5a0ecSAndroid Build Coastguard Worker     mState = state;
1099*0ec5a0ecSAndroid Build Coastguard Worker }
1100*0ec5a0ecSAndroid Build Coastguard Worker 
stateToString(State state)1101*0ec5a0ecSAndroid Build Coastguard Worker const char* V4L2Encoder::stateToString(State state) {
1102*0ec5a0ecSAndroid Build Coastguard Worker     switch (state) {
1103*0ec5a0ecSAndroid Build Coastguard Worker     case State::UNINITIALIZED:
1104*0ec5a0ecSAndroid Build Coastguard Worker         return "UNINITIALIZED";
1105*0ec5a0ecSAndroid Build Coastguard Worker     case State::WAITING_FOR_INPUT_FRAME:
1106*0ec5a0ecSAndroid Build Coastguard Worker         return "WAITING_FOR_INPUT_FRAME";
1107*0ec5a0ecSAndroid Build Coastguard Worker     case State::WAITING_FOR_V4L2_BUFFER:
1108*0ec5a0ecSAndroid Build Coastguard Worker         return "WAITING_FOR_V4L2_BUFFER";
1109*0ec5a0ecSAndroid Build Coastguard Worker     case State::ENCODING:
1110*0ec5a0ecSAndroid Build Coastguard Worker         return "ENCODING";
1111*0ec5a0ecSAndroid Build Coastguard Worker     case State::DRAINING:
1112*0ec5a0ecSAndroid Build Coastguard Worker         return "DRAINING";
1113*0ec5a0ecSAndroid Build Coastguard Worker     case State::ERROR:
1114*0ec5a0ecSAndroid Build Coastguard Worker         return "ERROR";
1115*0ec5a0ecSAndroid Build Coastguard Worker     }
1116*0ec5a0ecSAndroid Build Coastguard Worker }
1117*0ec5a0ecSAndroid Build Coastguard Worker 
1118*0ec5a0ecSAndroid Build Coastguard Worker }  // namespace android
1119