xref: /aosp_15_r20/external/v4l2_codec2/components/EncodeComponent.cpp (revision 0ec5a0ec62797f775085659156625e7f1bdb369f)
1*0ec5a0ecSAndroid Build Coastguard Worker // Copyright 2023 The Chromium Authors. All rights reserved.
2*0ec5a0ecSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*0ec5a0ecSAndroid Build Coastguard Worker // found in the LICENSE file
4*0ec5a0ecSAndroid Build Coastguard Worker 
5*0ec5a0ecSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
6*0ec5a0ecSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_VIDEO
7*0ec5a0ecSAndroid Build Coastguard Worker #define LOG_TAG "EncodeComponent"
8*0ec5a0ecSAndroid Build Coastguard Worker 
9*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/components/EncodeComponent.h>
10*0ec5a0ecSAndroid Build Coastguard Worker 
11*0ec5a0ecSAndroid Build Coastguard Worker #include <inttypes.h>
12*0ec5a0ecSAndroid Build Coastguard Worker 
13*0ec5a0ecSAndroid Build Coastguard Worker #include <algorithm>
14*0ec5a0ecSAndroid Build Coastguard Worker #include <utility>
15*0ec5a0ecSAndroid Build Coastguard Worker 
16*0ec5a0ecSAndroid Build Coastguard Worker #include <C2AllocatorGralloc.h>
17*0ec5a0ecSAndroid Build Coastguard Worker #include <C2PlatformSupport.h>
18*0ec5a0ecSAndroid Build Coastguard Worker #include <C2Work.h>
19*0ec5a0ecSAndroid Build Coastguard Worker #include <android/hardware/graphics/common/1.0/types.h>
20*0ec5a0ecSAndroid Build Coastguard Worker #include <base/bind.h>
21*0ec5a0ecSAndroid Build Coastguard Worker #include <base/bind_helpers.h>
22*0ec5a0ecSAndroid Build Coastguard Worker #include <log/log.h>
23*0ec5a0ecSAndroid Build Coastguard Worker #include <media/stagefright/MediaDefs.h>
24*0ec5a0ecSAndroid Build Coastguard Worker #include <ui/GraphicBuffer.h>
25*0ec5a0ecSAndroid Build Coastguard Worker #include <ui/Size.h>
26*0ec5a0ecSAndroid Build Coastguard Worker #include <utils/Trace.h>
27*0ec5a0ecSAndroid Build Coastguard Worker 
28*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/EncodeHelpers.h>
29*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/FormatConverter.h>
30*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/H264.h>
31*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/components/BitstreamBuffer.h>
32*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/components/EncodeInterface.h>
33*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/components/VideoEncoder.h>
34*0ec5a0ecSAndroid Build Coastguard Worker 
35*0ec5a0ecSAndroid Build Coastguard Worker using android::hardware::graphics::common::V1_0::BufferUsage;
36*0ec5a0ecSAndroid Build Coastguard Worker 
37*0ec5a0ecSAndroid Build Coastguard Worker namespace android {
38*0ec5a0ecSAndroid Build Coastguard Worker 
39*0ec5a0ecSAndroid Build Coastguard Worker namespace {
40*0ec5a0ecSAndroid Build Coastguard Worker // Create an input frame from the specified graphic block.
createInputFrame(const C2ConstGraphicBlock & block,VideoPixelFormat format,const std::vector<VideoFramePlane> & planes,uint64_t index,int64_t timestamp)41*0ec5a0ecSAndroid Build Coastguard Worker std::unique_ptr<VideoEncoder::InputFrame> createInputFrame(
42*0ec5a0ecSAndroid Build Coastguard Worker         const C2ConstGraphicBlock& block, VideoPixelFormat format,
43*0ec5a0ecSAndroid Build Coastguard Worker         const std::vector<VideoFramePlane>& planes, uint64_t index, int64_t timestamp) {
44*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<int> fds;
45*0ec5a0ecSAndroid Build Coastguard Worker     const C2Handle* const handle = block.handle();
46*0ec5a0ecSAndroid Build Coastguard Worker     for (int i = 0; i < handle->numFds; i++) {
47*0ec5a0ecSAndroid Build Coastguard Worker         fds.emplace_back(handle->data[i]);
48*0ec5a0ecSAndroid Build Coastguard Worker     }
49*0ec5a0ecSAndroid Build Coastguard Worker 
50*0ec5a0ecSAndroid Build Coastguard Worker     return std::make_unique<VideoEncoder::InputFrame>(std::move(fds), planes, format, index,
51*0ec5a0ecSAndroid Build Coastguard Worker                                                       timestamp);
52*0ec5a0ecSAndroid Build Coastguard Worker }
53*0ec5a0ecSAndroid Build Coastguard Worker }  // namespace
54*0ec5a0ecSAndroid Build Coastguard Worker 
55*0ec5a0ecSAndroid Build Coastguard Worker // Get the video frame layout from the specified |inputBlock|.
56*0ec5a0ecSAndroid Build Coastguard Worker // TODO(dstaessens): Clean up code extracting layout from a C2GraphicBlock.
getVideoFrameLayout(const C2ConstGraphicBlock & block,VideoPixelFormat * format)57*0ec5a0ecSAndroid Build Coastguard Worker std::optional<std::vector<VideoFramePlane>> getVideoFrameLayout(const C2ConstGraphicBlock& block,
58*0ec5a0ecSAndroid Build Coastguard Worker                                                                 VideoPixelFormat* format) {
59*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
60*0ec5a0ecSAndroid Build Coastguard Worker 
61*0ec5a0ecSAndroid Build Coastguard Worker     // Get the C2PlanarLayout from the graphics block. The C2GraphicView returned by block.map()
62*0ec5a0ecSAndroid Build Coastguard Worker     // needs to be released before calling getGraphicBlockInfo(), or the lockYCbCr() call will block
63*0ec5a0ecSAndroid Build Coastguard Worker     // Indefinitely.
64*0ec5a0ecSAndroid Build Coastguard Worker     C2PlanarLayout layout = block.map().get().layout();
65*0ec5a0ecSAndroid Build Coastguard Worker 
66*0ec5a0ecSAndroid Build Coastguard Worker     // The above layout() cannot fill layout information and memset 0 instead if the input format is
67*0ec5a0ecSAndroid Build Coastguard Worker     // IMPLEMENTATION_DEFINED and its backed format is RGB. We fill the layout by using
68*0ec5a0ecSAndroid Build Coastguard Worker     // ImplDefinedToRGBXMap in the case.
69*0ec5a0ecSAndroid Build Coastguard Worker     if (layout.type == C2PlanarLayout::TYPE_UNKNOWN) {
70*0ec5a0ecSAndroid Build Coastguard Worker         std::unique_ptr<ImplDefinedToRGBXMap> idMap = ImplDefinedToRGBXMap::create(block);
71*0ec5a0ecSAndroid Build Coastguard Worker         if (idMap == nullptr) {
72*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Unable to parse RGBX_8888 from IMPLEMENTATION_DEFINED");
73*0ec5a0ecSAndroid Build Coastguard Worker             return std::nullopt;
74*0ec5a0ecSAndroid Build Coastguard Worker         }
75*0ec5a0ecSAndroid Build Coastguard Worker         layout.type = C2PlanarLayout::TYPE_RGB;
76*0ec5a0ecSAndroid Build Coastguard Worker         // These parameters would be used in TYPE_GRB case below.
77*0ec5a0ecSAndroid Build Coastguard Worker         layout.numPlanes = 3;   // same value as in C2AllocationGralloc::map()
78*0ec5a0ecSAndroid Build Coastguard Worker         layout.rootPlanes = 1;  // same value as in C2AllocationGralloc::map()
79*0ec5a0ecSAndroid Build Coastguard Worker         layout.planes[C2PlanarLayout::PLANE_R].offset = idMap->offset();
80*0ec5a0ecSAndroid Build Coastguard Worker         layout.planes[C2PlanarLayout::PLANE_R].rowInc = idMap->rowInc();
81*0ec5a0ecSAndroid Build Coastguard Worker     }
82*0ec5a0ecSAndroid Build Coastguard Worker 
83*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<uint32_t> offsets(layout.numPlanes, 0u);
84*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<uint32_t> strides(layout.numPlanes, 0u);
85*0ec5a0ecSAndroid Build Coastguard Worker     switch (layout.type) {
86*0ec5a0ecSAndroid Build Coastguard Worker     case C2PlanarLayout::TYPE_YUV: {
87*0ec5a0ecSAndroid Build Coastguard Worker         android_ycbcr ycbcr = getGraphicBlockInfo(block);
88*0ec5a0ecSAndroid Build Coastguard Worker         offsets[C2PlanarLayout::PLANE_Y] =
89*0ec5a0ecSAndroid Build Coastguard Worker                 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(ycbcr.y));
90*0ec5a0ecSAndroid Build Coastguard Worker         offsets[C2PlanarLayout::PLANE_U] =
91*0ec5a0ecSAndroid Build Coastguard Worker                 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(ycbcr.cb));
92*0ec5a0ecSAndroid Build Coastguard Worker         offsets[C2PlanarLayout::PLANE_V] =
93*0ec5a0ecSAndroid Build Coastguard Worker                 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(ycbcr.cr));
94*0ec5a0ecSAndroid Build Coastguard Worker         strides[C2PlanarLayout::PLANE_Y] = static_cast<uint32_t>(ycbcr.ystride);
95*0ec5a0ecSAndroid Build Coastguard Worker         strides[C2PlanarLayout::PLANE_U] = static_cast<uint32_t>(ycbcr.cstride);
96*0ec5a0ecSAndroid Build Coastguard Worker         strides[C2PlanarLayout::PLANE_V] = static_cast<uint32_t>(ycbcr.cstride);
97*0ec5a0ecSAndroid Build Coastguard Worker 
98*0ec5a0ecSAndroid Build Coastguard Worker         bool crcb = false;
99*0ec5a0ecSAndroid Build Coastguard Worker         if (offsets[C2PlanarLayout::PLANE_U] > offsets[C2PlanarLayout::PLANE_V]) {
100*0ec5a0ecSAndroid Build Coastguard Worker             // Swap offsets, no need to swap strides as they are identical for both chroma planes.
101*0ec5a0ecSAndroid Build Coastguard Worker             std::swap(offsets[C2PlanarLayout::PLANE_U], offsets[C2PlanarLayout::PLANE_V]);
102*0ec5a0ecSAndroid Build Coastguard Worker             crcb = true;
103*0ec5a0ecSAndroid Build Coastguard Worker         }
104*0ec5a0ecSAndroid Build Coastguard Worker 
105*0ec5a0ecSAndroid Build Coastguard Worker         bool semiplanar = false;
106*0ec5a0ecSAndroid Build Coastguard Worker         if (ycbcr.chroma_step >
107*0ec5a0ecSAndroid Build Coastguard Worker             offsets[C2PlanarLayout::PLANE_V] - offsets[C2PlanarLayout::PLANE_U]) {
108*0ec5a0ecSAndroid Build Coastguard Worker             semiplanar = true;
109*0ec5a0ecSAndroid Build Coastguard Worker         }
110*0ec5a0ecSAndroid Build Coastguard Worker 
111*0ec5a0ecSAndroid Build Coastguard Worker         if (!crcb && !semiplanar) {
112*0ec5a0ecSAndroid Build Coastguard Worker             *format = VideoPixelFormat::I420;
113*0ec5a0ecSAndroid Build Coastguard Worker         } else if (!crcb && semiplanar) {
114*0ec5a0ecSAndroid Build Coastguard Worker             *format = VideoPixelFormat::NV12;
115*0ec5a0ecSAndroid Build Coastguard Worker         } else if (crcb && !semiplanar) {
116*0ec5a0ecSAndroid Build Coastguard Worker             // HACK: pretend YV12 is I420 now since VEA only accepts I420. (YV12 will be used
117*0ec5a0ecSAndroid Build Coastguard Worker             //       for input byte-buffer mode).
118*0ec5a0ecSAndroid Build Coastguard Worker             // TODO(dstaessens): Is this hack still necessary now we're not using the VEA directly?
119*0ec5a0ecSAndroid Build Coastguard Worker             //format = VideoPixelFormat::YV12;
120*0ec5a0ecSAndroid Build Coastguard Worker             *format = VideoPixelFormat::I420;
121*0ec5a0ecSAndroid Build Coastguard Worker         } else {
122*0ec5a0ecSAndroid Build Coastguard Worker             *format = VideoPixelFormat::NV21;
123*0ec5a0ecSAndroid Build Coastguard Worker         }
124*0ec5a0ecSAndroid Build Coastguard Worker         break;
125*0ec5a0ecSAndroid Build Coastguard Worker     }
126*0ec5a0ecSAndroid Build Coastguard Worker     case C2PlanarLayout::TYPE_RGB: {
127*0ec5a0ecSAndroid Build Coastguard Worker         offsets[C2PlanarLayout::PLANE_R] = layout.planes[C2PlanarLayout::PLANE_R].offset;
128*0ec5a0ecSAndroid Build Coastguard Worker         strides[C2PlanarLayout::PLANE_R] =
129*0ec5a0ecSAndroid Build Coastguard Worker                 static_cast<uint32_t>(layout.planes[C2PlanarLayout::PLANE_R].rowInc);
130*0ec5a0ecSAndroid Build Coastguard Worker         *format = VideoPixelFormat::ARGB;
131*0ec5a0ecSAndroid Build Coastguard Worker         break;
132*0ec5a0ecSAndroid Build Coastguard Worker     }
133*0ec5a0ecSAndroid Build Coastguard Worker     default:
134*0ec5a0ecSAndroid Build Coastguard Worker         ALOGW("Unknown layout type: %u", static_cast<uint32_t>(layout.type));
135*0ec5a0ecSAndroid Build Coastguard Worker         return std::nullopt;
136*0ec5a0ecSAndroid Build Coastguard Worker     }
137*0ec5a0ecSAndroid Build Coastguard Worker 
138*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<VideoFramePlane> planes;
139*0ec5a0ecSAndroid Build Coastguard Worker     for (uint32_t i = 0; i < layout.rootPlanes; ++i) {
140*0ec5a0ecSAndroid Build Coastguard Worker         // The mSize field is not used in our case, so we can safely set it to zero.
141*0ec5a0ecSAndroid Build Coastguard Worker         planes.push_back({strides[i], offsets[i], 0});
142*0ec5a0ecSAndroid Build Coastguard Worker     }
143*0ec5a0ecSAndroid Build Coastguard Worker     return planes;
144*0ec5a0ecSAndroid Build Coastguard Worker }
145*0ec5a0ecSAndroid Build Coastguard Worker 
146*0ec5a0ecSAndroid Build Coastguard Worker // Get the video frame stride for the specified |format| and |size|.
getVideoFrameStride(VideoPixelFormat format,ui::Size size)147*0ec5a0ecSAndroid Build Coastguard Worker std::optional<uint32_t> getVideoFrameStride(VideoPixelFormat format, ui::Size size) {
148*0ec5a0ecSAndroid Build Coastguard Worker     // Fetch a graphic block from the pool to determine the stride.
149*0ec5a0ecSAndroid Build Coastguard Worker     std::shared_ptr<C2BlockPool> pool;
150*0ec5a0ecSAndroid Build Coastguard Worker     c2_status_t status = GetCodec2BlockPool(C2BlockPool::BASIC_GRAPHIC, nullptr, &pool);
151*0ec5a0ecSAndroid Build Coastguard Worker     if (status != C2_OK) {
152*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to get basic graphic block pool (err=%d)", status);
153*0ec5a0ecSAndroid Build Coastguard Worker         return std::nullopt;
154*0ec5a0ecSAndroid Build Coastguard Worker     }
155*0ec5a0ecSAndroid Build Coastguard Worker 
156*0ec5a0ecSAndroid Build Coastguard Worker     // Android HAL format doesn't have I420, we use YV12 instead and swap the U and V planes when
157*0ec5a0ecSAndroid Build Coastguard Worker     // converting to NV12. YCBCR_420_888 will allocate NV12 by minigbm.
158*0ec5a0ecSAndroid Build Coastguard Worker     HalPixelFormat halFormat = (format == VideoPixelFormat::I420) ? HalPixelFormat::YV12
159*0ec5a0ecSAndroid Build Coastguard Worker                                                                   : HalPixelFormat::YCBCR_420_888;
160*0ec5a0ecSAndroid Build Coastguard Worker 
161*0ec5a0ecSAndroid Build Coastguard Worker     std::shared_ptr<C2GraphicBlock> block;
162*0ec5a0ecSAndroid Build Coastguard Worker     status = pool->fetchGraphicBlock(size.width, size.height, static_cast<uint32_t>(halFormat),
163*0ec5a0ecSAndroid Build Coastguard Worker                                      C2MemoryUsage(C2MemoryUsage::CPU_READ), &block);
164*0ec5a0ecSAndroid Build Coastguard Worker     if (status != C2_OK) {
165*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to fetch graphic block (err=%d)", status);
166*0ec5a0ecSAndroid Build Coastguard Worker         return std::nullopt;
167*0ec5a0ecSAndroid Build Coastguard Worker     }
168*0ec5a0ecSAndroid Build Coastguard Worker 
169*0ec5a0ecSAndroid Build Coastguard Worker     const C2ConstGraphicBlock constBlock = block->share(C2Rect(size.width, size.height), C2Fence());
170*0ec5a0ecSAndroid Build Coastguard Worker     VideoPixelFormat pixelFormat;
171*0ec5a0ecSAndroid Build Coastguard Worker     std::optional<std::vector<VideoFramePlane>> planes =
172*0ec5a0ecSAndroid Build Coastguard Worker             getVideoFrameLayout(constBlock, &pixelFormat);
173*0ec5a0ecSAndroid Build Coastguard Worker     if (!planes || planes.value().empty()) {
174*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to get video frame layout from block");
175*0ec5a0ecSAndroid Build Coastguard Worker         return std::nullopt;
176*0ec5a0ecSAndroid Build Coastguard Worker     }
177*0ec5a0ecSAndroid Build Coastguard Worker 
178*0ec5a0ecSAndroid Build Coastguard Worker     return planes.value()[0].mStride;
179*0ec5a0ecSAndroid Build Coastguard Worker }
180*0ec5a0ecSAndroid Build Coastguard Worker 
EncodeComponent(C2String name,c2_node_id_t id,std::shared_ptr<EncodeInterface> interface)181*0ec5a0ecSAndroid Build Coastguard Worker EncodeComponent::EncodeComponent(C2String name, c2_node_id_t id,
182*0ec5a0ecSAndroid Build Coastguard Worker                                  std::shared_ptr<EncodeInterface> interface)
183*0ec5a0ecSAndroid Build Coastguard Worker       : mName(name),
184*0ec5a0ecSAndroid Build Coastguard Worker         mId(id),
185*0ec5a0ecSAndroid Build Coastguard Worker         mInterface(std::move(interface)),
186*0ec5a0ecSAndroid Build Coastguard Worker         mComponentState(ComponentState::LOADED) {
187*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(%s)", __func__, name.c_str());
188*0ec5a0ecSAndroid Build Coastguard Worker }
189*0ec5a0ecSAndroid Build Coastguard Worker 
~EncodeComponent()190*0ec5a0ecSAndroid Build Coastguard Worker EncodeComponent::~EncodeComponent() {
191*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
192*0ec5a0ecSAndroid Build Coastguard Worker 
193*0ec5a0ecSAndroid Build Coastguard Worker     // Stop encoder thread and invalidate pointers if component wasn't stopped before destroying.
194*0ec5a0ecSAndroid Build Coastguard Worker     if (mEncoderThread.IsRunning() && !mEncoderTaskRunner->RunsTasksInCurrentSequence()) {
195*0ec5a0ecSAndroid Build Coastguard Worker         mEncoderTaskRunner->PostTask(
196*0ec5a0ecSAndroid Build Coastguard Worker                 FROM_HERE, ::base::BindOnce(
197*0ec5a0ecSAndroid Build Coastguard Worker                                    [](::base::WeakPtrFactory<EncodeComponent>* weakPtrFactory,
198*0ec5a0ecSAndroid Build Coastguard Worker                                       std::unique_ptr<VideoEncoder>* encoder) {
199*0ec5a0ecSAndroid Build Coastguard Worker                                        weakPtrFactory->InvalidateWeakPtrs();
200*0ec5a0ecSAndroid Build Coastguard Worker                                        encoder->reset();
201*0ec5a0ecSAndroid Build Coastguard Worker                                    },
202*0ec5a0ecSAndroid Build Coastguard Worker                                    &mWeakThisFactory, &mEncoder));
203*0ec5a0ecSAndroid Build Coastguard Worker         mEncoderThread.Stop();
204*0ec5a0ecSAndroid Build Coastguard Worker     }
205*0ec5a0ecSAndroid Build Coastguard Worker 
206*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(): done", __func__);
207*0ec5a0ecSAndroid Build Coastguard Worker }
208*0ec5a0ecSAndroid Build Coastguard Worker 
start()209*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t EncodeComponent::start() {
210*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
211*0ec5a0ecSAndroid Build Coastguard Worker 
212*0ec5a0ecSAndroid Build Coastguard Worker     // Lock while starting, to synchronize start/stop/reset/release calls.
213*0ec5a0ecSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mComponentLock);
214*0ec5a0ecSAndroid Build Coastguard Worker 
215*0ec5a0ecSAndroid Build Coastguard Worker     // According to the specification start() should only be called in the LOADED state.
216*0ec5a0ecSAndroid Build Coastguard Worker     if (mComponentState != ComponentState::LOADED) {
217*0ec5a0ecSAndroid Build Coastguard Worker         return C2_BAD_STATE;
218*0ec5a0ecSAndroid Build Coastguard Worker     }
219*0ec5a0ecSAndroid Build Coastguard Worker 
220*0ec5a0ecSAndroid Build Coastguard Worker     if (!mEncoderThread.Start()) {
221*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to start encoder thread");
222*0ec5a0ecSAndroid Build Coastguard Worker         return C2_CORRUPTED;
223*0ec5a0ecSAndroid Build Coastguard Worker     }
224*0ec5a0ecSAndroid Build Coastguard Worker     mEncoderTaskRunner = mEncoderThread.task_runner();
225*0ec5a0ecSAndroid Build Coastguard Worker     mWeakThis = mWeakThisFactory.GetWeakPtr();
226*0ec5a0ecSAndroid Build Coastguard Worker 
227*0ec5a0ecSAndroid Build Coastguard Worker     // Initialize the encoder on the encoder thread.
228*0ec5a0ecSAndroid Build Coastguard Worker     ::base::WaitableEvent done;
229*0ec5a0ecSAndroid Build Coastguard Worker     bool success = false;
230*0ec5a0ecSAndroid Build Coastguard Worker     mEncoderTaskRunner->PostTask(
231*0ec5a0ecSAndroid Build Coastguard Worker             FROM_HERE, ::base::Bind(&EncodeComponent::startTask, mWeakThis, &success, &done));
232*0ec5a0ecSAndroid Build Coastguard Worker     done.Wait();
233*0ec5a0ecSAndroid Build Coastguard Worker 
234*0ec5a0ecSAndroid Build Coastguard Worker     if (!success) {
235*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to initialize encoder");
236*0ec5a0ecSAndroid Build Coastguard Worker         return C2_CORRUPTED;
237*0ec5a0ecSAndroid Build Coastguard Worker     }
238*0ec5a0ecSAndroid Build Coastguard Worker 
239*0ec5a0ecSAndroid Build Coastguard Worker     setComponentState(ComponentState::RUNNING);
240*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OK;
241*0ec5a0ecSAndroid Build Coastguard Worker }
242*0ec5a0ecSAndroid Build Coastguard Worker 
stop()243*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t EncodeComponent::stop() {
244*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
245*0ec5a0ecSAndroid Build Coastguard Worker 
246*0ec5a0ecSAndroid Build Coastguard Worker     // Lock while stopping, to synchronize start/stop/reset/release calls.
247*0ec5a0ecSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mComponentLock);
248*0ec5a0ecSAndroid Build Coastguard Worker 
249*0ec5a0ecSAndroid Build Coastguard Worker     if (mComponentState != ComponentState::RUNNING && mComponentState != ComponentState::ERROR) {
250*0ec5a0ecSAndroid Build Coastguard Worker         return C2_BAD_STATE;
251*0ec5a0ecSAndroid Build Coastguard Worker     }
252*0ec5a0ecSAndroid Build Coastguard Worker 
253*0ec5a0ecSAndroid Build Coastguard Worker     // Return immediately if the component is already stopped.
254*0ec5a0ecSAndroid Build Coastguard Worker     if (!mEncoderThread.IsRunning()) {
255*0ec5a0ecSAndroid Build Coastguard Worker         return C2_OK;
256*0ec5a0ecSAndroid Build Coastguard Worker     }
257*0ec5a0ecSAndroid Build Coastguard Worker 
258*0ec5a0ecSAndroid Build Coastguard Worker     // Wait for the component to stop.
259*0ec5a0ecSAndroid Build Coastguard Worker     ::base::WaitableEvent done;
260*0ec5a0ecSAndroid Build Coastguard Worker     mEncoderTaskRunner->PostTask(FROM_HERE,
261*0ec5a0ecSAndroid Build Coastguard Worker                                  ::base::BindOnce(&EncodeComponent::stopTask, mWeakThis, &done));
262*0ec5a0ecSAndroid Build Coastguard Worker     done.Wait();
263*0ec5a0ecSAndroid Build Coastguard Worker     mEncoderThread.Stop();
264*0ec5a0ecSAndroid Build Coastguard Worker 
265*0ec5a0ecSAndroid Build Coastguard Worker     setComponentState(ComponentState::LOADED);
266*0ec5a0ecSAndroid Build Coastguard Worker 
267*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s() - done", __func__);
268*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OK;
269*0ec5a0ecSAndroid Build Coastguard Worker }
270*0ec5a0ecSAndroid Build Coastguard Worker 
reset()271*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t EncodeComponent::reset() {
272*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
273*0ec5a0ecSAndroid Build Coastguard Worker 
274*0ec5a0ecSAndroid Build Coastguard Worker     // The interface specification says: "This method MUST be supported in all (including tripped)
275*0ec5a0ecSAndroid Build Coastguard Worker     // states other than released".
276*0ec5a0ecSAndroid Build Coastguard Worker     if (mComponentState == ComponentState::UNLOADED) {
277*0ec5a0ecSAndroid Build Coastguard Worker         return C2_BAD_STATE;
278*0ec5a0ecSAndroid Build Coastguard Worker     }
279*0ec5a0ecSAndroid Build Coastguard Worker 
280*0ec5a0ecSAndroid Build Coastguard Worker     // TODO(dstaessens): Reset the component's interface to default values.
281*0ec5a0ecSAndroid Build Coastguard Worker     stop();
282*0ec5a0ecSAndroid Build Coastguard Worker 
283*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OK;
284*0ec5a0ecSAndroid Build Coastguard Worker }
285*0ec5a0ecSAndroid Build Coastguard Worker 
release()286*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t EncodeComponent::release() {
287*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
288*0ec5a0ecSAndroid Build Coastguard Worker 
289*0ec5a0ecSAndroid Build Coastguard Worker     // The interface specification says: "This method MUST be supported in stopped state.", but the
290*0ec5a0ecSAndroid Build Coastguard Worker     // release method seems to be called in other states as well.
291*0ec5a0ecSAndroid Build Coastguard Worker     reset();
292*0ec5a0ecSAndroid Build Coastguard Worker 
293*0ec5a0ecSAndroid Build Coastguard Worker     setComponentState(ComponentState::UNLOADED);
294*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OK;
295*0ec5a0ecSAndroid Build Coastguard Worker }
296*0ec5a0ecSAndroid Build Coastguard Worker 
queue_nb(std::list<std::unique_ptr<C2Work>> * const items)297*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t EncodeComponent::queue_nb(std::list<std::unique_ptr<C2Work>>* const items) {
298*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
299*0ec5a0ecSAndroid Build Coastguard Worker 
300*0ec5a0ecSAndroid Build Coastguard Worker     if (mComponentState != ComponentState::RUNNING) {
301*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Trying to queue work item while component is not running");
302*0ec5a0ecSAndroid Build Coastguard Worker         return C2_BAD_STATE;
303*0ec5a0ecSAndroid Build Coastguard Worker     }
304*0ec5a0ecSAndroid Build Coastguard Worker 
305*0ec5a0ecSAndroid Build Coastguard Worker     while (!items->empty()) {
306*0ec5a0ecSAndroid Build Coastguard Worker         mEncoderTaskRunner->PostTask(FROM_HERE,
307*0ec5a0ecSAndroid Build Coastguard Worker                                      ::base::BindOnce(&EncodeComponent::queueTask, mWeakThis,
308*0ec5a0ecSAndroid Build Coastguard Worker                                                       std::move(items->front())));
309*0ec5a0ecSAndroid Build Coastguard Worker         items->pop_front();
310*0ec5a0ecSAndroid Build Coastguard Worker     }
311*0ec5a0ecSAndroid Build Coastguard Worker 
312*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OK;
313*0ec5a0ecSAndroid Build Coastguard Worker }
314*0ec5a0ecSAndroid Build Coastguard Worker 
drain_nb(drain_mode_t mode)315*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t EncodeComponent::drain_nb(drain_mode_t mode) {
316*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
317*0ec5a0ecSAndroid Build Coastguard Worker 
318*0ec5a0ecSAndroid Build Coastguard Worker     if (mode == DRAIN_CHAIN) {
319*0ec5a0ecSAndroid Build Coastguard Worker         return C2_OMITTED;  // Tunneling is not supported for now.
320*0ec5a0ecSAndroid Build Coastguard Worker     }
321*0ec5a0ecSAndroid Build Coastguard Worker 
322*0ec5a0ecSAndroid Build Coastguard Worker     if (mComponentState != ComponentState::RUNNING) {
323*0ec5a0ecSAndroid Build Coastguard Worker         return C2_BAD_STATE;
324*0ec5a0ecSAndroid Build Coastguard Worker     }
325*0ec5a0ecSAndroid Build Coastguard Worker 
326*0ec5a0ecSAndroid Build Coastguard Worker     mEncoderTaskRunner->PostTask(FROM_HERE,
327*0ec5a0ecSAndroid Build Coastguard Worker                                  ::base::BindOnce(&EncodeComponent::drainTask, mWeakThis, mode));
328*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OK;
329*0ec5a0ecSAndroid Build Coastguard Worker }
330*0ec5a0ecSAndroid Build Coastguard Worker 
flush_sm(flush_mode_t mode,std::list<std::unique_ptr<C2Work>> * const flushedWork)331*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t EncodeComponent::flush_sm(flush_mode_t mode,
332*0ec5a0ecSAndroid Build Coastguard Worker                                       std::list<std::unique_ptr<C2Work>>* const flushedWork) {
333*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
334*0ec5a0ecSAndroid Build Coastguard Worker 
335*0ec5a0ecSAndroid Build Coastguard Worker     if (mode != FLUSH_COMPONENT) {
336*0ec5a0ecSAndroid Build Coastguard Worker         return C2_OMITTED;  // Tunneling is not supported by now
337*0ec5a0ecSAndroid Build Coastguard Worker     }
338*0ec5a0ecSAndroid Build Coastguard Worker 
339*0ec5a0ecSAndroid Build Coastguard Worker     if (mComponentState != ComponentState::RUNNING) {
340*0ec5a0ecSAndroid Build Coastguard Worker         return C2_BAD_STATE;
341*0ec5a0ecSAndroid Build Coastguard Worker     }
342*0ec5a0ecSAndroid Build Coastguard Worker 
343*0ec5a0ecSAndroid Build Coastguard Worker     // Work that can be immediately discarded should be returned in |flushedWork|. This method may
344*0ec5a0ecSAndroid Build Coastguard Worker     // be momentarily blocking but must return within 5ms, which should give us enough time to
345*0ec5a0ecSAndroid Build Coastguard Worker     // immediately abandon all non-started work on the encoder thread. We can return all work that
346*0ec5a0ecSAndroid Build Coastguard Worker     // can't be immediately discarded using onWorkDone() later.
347*0ec5a0ecSAndroid Build Coastguard Worker     ::base::WaitableEvent done;
348*0ec5a0ecSAndroid Build Coastguard Worker     mEncoderTaskRunner->PostTask(FROM_HERE, ::base::BindOnce(&EncodeComponent::flushTask, mWeakThis,
349*0ec5a0ecSAndroid Build Coastguard Worker                                                              &done, flushedWork));
350*0ec5a0ecSAndroid Build Coastguard Worker     done.Wait();
351*0ec5a0ecSAndroid Build Coastguard Worker 
352*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OK;
353*0ec5a0ecSAndroid Build Coastguard Worker }
354*0ec5a0ecSAndroid Build Coastguard Worker 
announce_nb(const std::vector<C2WorkOutline> & items)355*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t EncodeComponent::announce_nb(const std::vector<C2WorkOutline>& items) {
356*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OMITTED;  // Tunneling is not supported by now
357*0ec5a0ecSAndroid Build Coastguard Worker }
358*0ec5a0ecSAndroid Build Coastguard Worker 
setListener_vb(const std::shared_ptr<Listener> & listener,c2_blocking_t mayBlock)359*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t EncodeComponent::setListener_vb(const std::shared_ptr<Listener>& listener,
360*0ec5a0ecSAndroid Build Coastguard Worker                                             c2_blocking_t mayBlock) {
361*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mComponentState != ComponentState::UNLOADED);
362*0ec5a0ecSAndroid Build Coastguard Worker 
363*0ec5a0ecSAndroid Build Coastguard Worker     // Lock so we're sure the component isn't currently starting or stopping.
364*0ec5a0ecSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mComponentLock);
365*0ec5a0ecSAndroid Build Coastguard Worker 
366*0ec5a0ecSAndroid Build Coastguard Worker     // If the encoder thread is not running it's safe to update the listener directly.
367*0ec5a0ecSAndroid Build Coastguard Worker     if (!mEncoderThread.IsRunning()) {
368*0ec5a0ecSAndroid Build Coastguard Worker         mListener = listener;
369*0ec5a0ecSAndroid Build Coastguard Worker         return C2_OK;
370*0ec5a0ecSAndroid Build Coastguard Worker     }
371*0ec5a0ecSAndroid Build Coastguard Worker 
372*0ec5a0ecSAndroid Build Coastguard Worker     // The listener should be updated before exiting this function. If called while the component is
373*0ec5a0ecSAndroid Build Coastguard Worker     // currently running we should be allowed to block, as we can only change the listener on the
374*0ec5a0ecSAndroid Build Coastguard Worker     // encoder thread.
375*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mayBlock == c2_blocking_t::C2_MAY_BLOCK);
376*0ec5a0ecSAndroid Build Coastguard Worker 
377*0ec5a0ecSAndroid Build Coastguard Worker     ::base::WaitableEvent done;
378*0ec5a0ecSAndroid Build Coastguard Worker     mEncoderTaskRunner->PostTask(FROM_HERE, ::base::BindOnce(&EncodeComponent::setListenerTask,
379*0ec5a0ecSAndroid Build Coastguard Worker                                                              mWeakThis, listener, &done));
380*0ec5a0ecSAndroid Build Coastguard Worker     done.Wait();
381*0ec5a0ecSAndroid Build Coastguard Worker 
382*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OK;
383*0ec5a0ecSAndroid Build Coastguard Worker }
384*0ec5a0ecSAndroid Build Coastguard Worker 
intf()385*0ec5a0ecSAndroid Build Coastguard Worker std::shared_ptr<C2ComponentInterface> EncodeComponent::intf() {
386*0ec5a0ecSAndroid Build Coastguard Worker     return std::make_shared<SimpleInterface<EncodeInterface>>(mName.c_str(), mId, mInterface);
387*0ec5a0ecSAndroid Build Coastguard Worker }
388*0ec5a0ecSAndroid Build Coastguard Worker 
startTask(bool * success,::base::WaitableEvent * done)389*0ec5a0ecSAndroid Build Coastguard Worker void EncodeComponent::startTask(bool* success, ::base::WaitableEvent* done) {
390*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
391*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
392*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
393*0ec5a0ecSAndroid Build Coastguard Worker 
394*0ec5a0ecSAndroid Build Coastguard Worker     *success = initializeEncoder();
395*0ec5a0ecSAndroid Build Coastguard Worker     done->Signal();
396*0ec5a0ecSAndroid Build Coastguard Worker }
397*0ec5a0ecSAndroid Build Coastguard Worker 
stopTask(::base::WaitableEvent * done)398*0ec5a0ecSAndroid Build Coastguard Worker void EncodeComponent::stopTask(::base::WaitableEvent* done) {
399*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
400*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
401*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
402*0ec5a0ecSAndroid Build Coastguard Worker 
403*0ec5a0ecSAndroid Build Coastguard Worker     // Flushing the encoder will abort all pending work.
404*0ec5a0ecSAndroid Build Coastguard Worker     flush();
405*0ec5a0ecSAndroid Build Coastguard Worker 
406*0ec5a0ecSAndroid Build Coastguard Worker     mInputFormatConverter.reset();
407*0ec5a0ecSAndroid Build Coastguard Worker     mInputPixelFormat = VideoPixelFormat::UNKNOWN;
408*0ec5a0ecSAndroid Build Coastguard Worker     mInputLayout.clear();
409*0ec5a0ecSAndroid Build Coastguard Worker 
410*0ec5a0ecSAndroid Build Coastguard Worker     mEncoder.reset();
411*0ec5a0ecSAndroid Build Coastguard Worker     mOutputBlockPool.reset();
412*0ec5a0ecSAndroid Build Coastguard Worker 
413*0ec5a0ecSAndroid Build Coastguard Worker     // Invalidate all weak pointers so no more functions will be executed on the encoder thread.
414*0ec5a0ecSAndroid Build Coastguard Worker     mWeakThisFactory.InvalidateWeakPtrs();
415*0ec5a0ecSAndroid Build Coastguard Worker 
416*0ec5a0ecSAndroid Build Coastguard Worker     done->Signal();
417*0ec5a0ecSAndroid Build Coastguard Worker }
418*0ec5a0ecSAndroid Build Coastguard Worker 
queueTask(std::unique_ptr<C2Work> work)419*0ec5a0ecSAndroid Build Coastguard Worker void EncodeComponent::queueTask(std::unique_ptr<C2Work> work) {
420*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
421*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
422*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
423*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoder);
424*0ec5a0ecSAndroid Build Coastguard Worker 
425*0ec5a0ecSAndroid Build Coastguard Worker     // Currently only a single worklet per work item is supported. An input buffer should always be
426*0ec5a0ecSAndroid Build Coastguard Worker     // supplied unless this is a drain or CSD request.
427*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(work->input.buffers.size() <= 1u && work->worklets.size() == 1u);
428*0ec5a0ecSAndroid Build Coastguard Worker 
429*0ec5a0ecSAndroid Build Coastguard Worker     // Set the default values for the output worklet.
430*0ec5a0ecSAndroid Build Coastguard Worker     work->worklets.front()->output.flags = static_cast<C2FrameData::flags_t>(0);
431*0ec5a0ecSAndroid Build Coastguard Worker     work->worklets.front()->output.buffers.clear();
432*0ec5a0ecSAndroid Build Coastguard Worker     work->worklets.front()->output.ordinal = work->input.ordinal;
433*0ec5a0ecSAndroid Build Coastguard Worker 
434*0ec5a0ecSAndroid Build Coastguard Worker     uint64_t index = work->input.ordinal.frameIndex.peeku();
435*0ec5a0ecSAndroid Build Coastguard Worker     int64_t timestamp = static_cast<int64_t>(work->input.ordinal.timestamp.peeku());
436*0ec5a0ecSAndroid Build Coastguard Worker     bool endOfStream = work->input.flags & C2FrameData::FLAG_END_OF_STREAM;
437*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("Queuing next encode (index: %" PRIu64 ", timestamp: %" PRId64 ", EOS: %d)", index,
438*0ec5a0ecSAndroid Build Coastguard Worker           timestamp, endOfStream);
439*0ec5a0ecSAndroid Build Coastguard Worker 
440*0ec5a0ecSAndroid Build Coastguard Worker     // If input buffer list is not empty, it means we have some input to process
441*0ec5a0ecSAndroid Build Coastguard Worker     // on. However, input could be a null buffer. In such case, clear the buffer
442*0ec5a0ecSAndroid Build Coastguard Worker     // list before making call to process().
443*0ec5a0ecSAndroid Build Coastguard Worker     if (!work->input.buffers.empty() && !work->input.buffers[0]) {
444*0ec5a0ecSAndroid Build Coastguard Worker         ALOGD("Encountered null input buffer. Clearing the input buffer");
445*0ec5a0ecSAndroid Build Coastguard Worker         work->input.buffers.clear();
446*0ec5a0ecSAndroid Build Coastguard Worker     }
447*0ec5a0ecSAndroid Build Coastguard Worker 
448*0ec5a0ecSAndroid Build Coastguard Worker     // The codec 2.0 framework might queue an empty CSD request, but this is currently not
449*0ec5a0ecSAndroid Build Coastguard Worker     // supported. We will return the CSD with the first encoded buffer work.
450*0ec5a0ecSAndroid Build Coastguard Worker     if (work->input.buffers.empty() && !endOfStream) {
451*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Discarding empty CSD request");
452*0ec5a0ecSAndroid Build Coastguard Worker         reportWork(std::move(work));
453*0ec5a0ecSAndroid Build Coastguard Worker         return;
454*0ec5a0ecSAndroid Build Coastguard Worker     }
455*0ec5a0ecSAndroid Build Coastguard Worker 
456*0ec5a0ecSAndroid Build Coastguard Worker     // By the time we get an input buffer, the output block pool should be configured.
457*0ec5a0ecSAndroid Build Coastguard Worker     if (!mOutputBlockPool && !getBlockPool()) {
458*0ec5a0ecSAndroid Build Coastguard Worker         reportError(C2_CORRUPTED);
459*0ec5a0ecSAndroid Build Coastguard Worker         return;
460*0ec5a0ecSAndroid Build Coastguard Worker     }
461*0ec5a0ecSAndroid Build Coastguard Worker 
462*0ec5a0ecSAndroid Build Coastguard Worker     // If this is the first input frame, create an input format converter if the V4L2 device doesn't
463*0ec5a0ecSAndroid Build Coastguard Worker     // support the requested input format.
464*0ec5a0ecSAndroid Build Coastguard Worker     if ((mInputPixelFormat == VideoPixelFormat::UNKNOWN) && !work->input.buffers.empty()) {
465*0ec5a0ecSAndroid Build Coastguard Worker         VideoPixelFormat format = VideoPixelFormat::UNKNOWN;
466*0ec5a0ecSAndroid Build Coastguard Worker         if (!getVideoFrameLayout(work->input.buffers.front()->data().graphicBlocks().front(),
467*0ec5a0ecSAndroid Build Coastguard Worker                                  &format)) {
468*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Failed to get input block's layout");
469*0ec5a0ecSAndroid Build Coastguard Worker             reportError(C2_CORRUPTED);
470*0ec5a0ecSAndroid Build Coastguard Worker             return;
471*0ec5a0ecSAndroid Build Coastguard Worker         }
472*0ec5a0ecSAndroid Build Coastguard Worker         if (mEncoder->inputFormat() != format) {
473*0ec5a0ecSAndroid Build Coastguard Worker             ALOG_ASSERT(!mInputFormatConverter);
474*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("Creating input format convertor (%s)",
475*0ec5a0ecSAndroid Build Coastguard Worker                   videoPixelFormatToString(mEncoder->inputFormat()).c_str());
476*0ec5a0ecSAndroid Build Coastguard Worker             mInputFormatConverter =
477*0ec5a0ecSAndroid Build Coastguard Worker                     FormatConverter::create(mEncoder->inputFormat(), mEncoder->visibleSize(),
478*0ec5a0ecSAndroid Build Coastguard Worker                                             VideoEncoder::kInputBufferCount, mEncoder->codedSize());
479*0ec5a0ecSAndroid Build Coastguard Worker             if (!mInputFormatConverter) {
480*0ec5a0ecSAndroid Build Coastguard Worker                 ALOGE("Failed to created input format convertor");
481*0ec5a0ecSAndroid Build Coastguard Worker                 reportError(C2_CORRUPTED);
482*0ec5a0ecSAndroid Build Coastguard Worker                 return;
483*0ec5a0ecSAndroid Build Coastguard Worker             }
484*0ec5a0ecSAndroid Build Coastguard Worker         }
485*0ec5a0ecSAndroid Build Coastguard Worker     }
486*0ec5a0ecSAndroid Build Coastguard Worker 
487*0ec5a0ecSAndroid Build Coastguard Worker     // If conversion is required but no free buffers are available we queue the work item.
488*0ec5a0ecSAndroid Build Coastguard Worker     if (mInputFormatConverter && !mInputFormatConverter->isReady()) {
489*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Input format convertor ran out of buffers");
490*0ec5a0ecSAndroid Build Coastguard Worker         mInputConverterQueue.push(std::move(work));
491*0ec5a0ecSAndroid Build Coastguard Worker         return;
492*0ec5a0ecSAndroid Build Coastguard Worker     }
493*0ec5a0ecSAndroid Build Coastguard Worker 
494*0ec5a0ecSAndroid Build Coastguard Worker     // If we have data to encode send it to the encoder. If conversion is required we will first
495*0ec5a0ecSAndroid Build Coastguard Worker     // convert the data to the requested pixel format.
496*0ec5a0ecSAndroid Build Coastguard Worker     if (!work->input.buffers.empty()) {
497*0ec5a0ecSAndroid Build Coastguard Worker         C2ConstGraphicBlock inputBlock =
498*0ec5a0ecSAndroid Build Coastguard Worker                 work->input.buffers.front()->data().graphicBlocks().front();
499*0ec5a0ecSAndroid Build Coastguard Worker         if (mInputFormatConverter) {
500*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("Converting input block (index: %" PRIu64 ")", index);
501*0ec5a0ecSAndroid Build Coastguard Worker             c2_status_t status =
502*0ec5a0ecSAndroid Build Coastguard Worker                     mInputFormatConverter->convertBlock(index, inputBlock, &inputBlock);
503*0ec5a0ecSAndroid Build Coastguard Worker             if (status != C2_OK) {
504*0ec5a0ecSAndroid Build Coastguard Worker                 ALOGE("Failed to convert input block (index: %" PRIu64 ")", index);
505*0ec5a0ecSAndroid Build Coastguard Worker                 reportError(status);
506*0ec5a0ecSAndroid Build Coastguard Worker                 return;
507*0ec5a0ecSAndroid Build Coastguard Worker             }
508*0ec5a0ecSAndroid Build Coastguard Worker         } else {
509*0ec5a0ecSAndroid Build Coastguard Worker             // Android encoder framework reuses the same gpu buffers as
510*0ec5a0ecSAndroid Build Coastguard Worker             // inputs and doesn't call lock/unlock explicitly between writes.
511*0ec5a0ecSAndroid Build Coastguard Worker             // If there is format conversion, this is fine since we will
512*0ec5a0ecSAndroid Build Coastguard Worker             // read back what we've written first and then put it in another
513*0ec5a0ecSAndroid Build Coastguard Worker             // buffer. Whenever there is no format conversion, this causes
514*0ec5a0ecSAndroid Build Coastguard Worker             // sync issue on ARCVM since host side buffers never get updated.
515*0ec5a0ecSAndroid Build Coastguard Worker             // Fix this by explicitly calling lock/unlock before sending buffer
516*0ec5a0ecSAndroid Build Coastguard Worker             // to encoder.
517*0ec5a0ecSAndroid Build Coastguard Worker             const C2Handle* handle = inputBlock.handle();
518*0ec5a0ecSAndroid Build Coastguard Worker             uint32_t width, height, format, stride, generation, igbpSlot;
519*0ec5a0ecSAndroid Build Coastguard Worker             uint64_t usage, igbpId;
520*0ec5a0ecSAndroid Build Coastguard Worker             _UnwrapNativeCodec2GrallocMetadata(handle, &width, &height, &format, &usage, &stride,
521*0ec5a0ecSAndroid Build Coastguard Worker                                                &generation, &igbpId, &igbpSlot);
522*0ec5a0ecSAndroid Build Coastguard Worker             do {
523*0ec5a0ecSAndroid Build Coastguard Worker                 if (!(usage & GRALLOC_USAGE_SW_WRITE_MASK)) break;
524*0ec5a0ecSAndroid Build Coastguard Worker                 native_handle_t* gralloc_handle = UnwrapNativeCodec2GrallocHandle(handle);
525*0ec5a0ecSAndroid Build Coastguard Worker                 if (nullptr == gralloc_handle) break;
526*0ec5a0ecSAndroid Build Coastguard Worker                 sp<GraphicBuffer> buffer =
527*0ec5a0ecSAndroid Build Coastguard Worker                         new GraphicBuffer(gralloc_handle, GraphicBuffer::CLONE_HANDLE, width,
528*0ec5a0ecSAndroid Build Coastguard Worker                                           height, format, 1, usage, stride);
529*0ec5a0ecSAndroid Build Coastguard Worker                 native_handle_delete(gralloc_handle);
530*0ec5a0ecSAndroid Build Coastguard Worker                 void* pixels;
531*0ec5a0ecSAndroid Build Coastguard Worker                 if (buffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, &pixels)) break;
532*0ec5a0ecSAndroid Build Coastguard Worker                 buffer->unlock();
533*0ec5a0ecSAndroid Build Coastguard Worker             } while (0);
534*0ec5a0ecSAndroid Build Coastguard Worker         }
535*0ec5a0ecSAndroid Build Coastguard Worker         if (!encode(inputBlock, index, timestamp)) {
536*0ec5a0ecSAndroid Build Coastguard Worker             return;
537*0ec5a0ecSAndroid Build Coastguard Worker         }
538*0ec5a0ecSAndroid Build Coastguard Worker     }
539*0ec5a0ecSAndroid Build Coastguard Worker 
540*0ec5a0ecSAndroid Build Coastguard Worker     mWorkQueue.push_back(std::move(work));
541*0ec5a0ecSAndroid Build Coastguard Worker     if (endOfStream) {
542*0ec5a0ecSAndroid Build Coastguard Worker         mEncoder->drain();
543*0ec5a0ecSAndroid Build Coastguard Worker     }
544*0ec5a0ecSAndroid Build Coastguard Worker }
545*0ec5a0ecSAndroid Build Coastguard Worker 
drainTask(drain_mode_t)546*0ec5a0ecSAndroid Build Coastguard Worker void EncodeComponent::drainTask(drain_mode_t /*drainMode*/) {
547*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
548*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
549*0ec5a0ecSAndroid Build Coastguard Worker 
550*0ec5a0ecSAndroid Build Coastguard Worker     // We can only start draining if all work has been queued in the encoder, so we mark the last
551*0ec5a0ecSAndroid Build Coastguard Worker     // item waiting for conversion as EOS if required.
552*0ec5a0ecSAndroid Build Coastguard Worker     if (!mInputConverterQueue.empty()) {
553*0ec5a0ecSAndroid Build Coastguard Worker         C2Work* work = mInputConverterQueue.back().get();
554*0ec5a0ecSAndroid Build Coastguard Worker         work->input.flags = static_cast<C2FrameData::flags_t>(work->input.flags |
555*0ec5a0ecSAndroid Build Coastguard Worker                                                               C2FrameData::FLAG_END_OF_STREAM);
556*0ec5a0ecSAndroid Build Coastguard Worker         return;
557*0ec5a0ecSAndroid Build Coastguard Worker     }
558*0ec5a0ecSAndroid Build Coastguard Worker 
559*0ec5a0ecSAndroid Build Coastguard Worker     // Mark the last item in the output work queue as EOS, so we will only report it as finished
560*0ec5a0ecSAndroid Build Coastguard Worker     // after draining has completed.
561*0ec5a0ecSAndroid Build Coastguard Worker     if (!mWorkQueue.empty()) {
562*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Starting drain and marking last item in output work queue as EOS");
563*0ec5a0ecSAndroid Build Coastguard Worker         C2Work* work = mWorkQueue.back().get();
564*0ec5a0ecSAndroid Build Coastguard Worker         work->input.flags = static_cast<C2FrameData::flags_t>(work->input.flags |
565*0ec5a0ecSAndroid Build Coastguard Worker                                                               C2FrameData::FLAG_END_OF_STREAM);
566*0ec5a0ecSAndroid Build Coastguard Worker         mEncoder->drain();
567*0ec5a0ecSAndroid Build Coastguard Worker     }
568*0ec5a0ecSAndroid Build Coastguard Worker }
569*0ec5a0ecSAndroid Build Coastguard Worker 
onDrainDone(bool success)570*0ec5a0ecSAndroid Build Coastguard Worker void EncodeComponent::onDrainDone(bool success) {
571*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
572*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
573*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(!mWorkQueue.empty());
574*0ec5a0ecSAndroid Build Coastguard Worker 
575*0ec5a0ecSAndroid Build Coastguard Worker     if (!success) {
576*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("draining the encoder failed");
577*0ec5a0ecSAndroid Build Coastguard Worker         reportError(C2_CORRUPTED);
578*0ec5a0ecSAndroid Build Coastguard Worker         return;
579*0ec5a0ecSAndroid Build Coastguard Worker     }
580*0ec5a0ecSAndroid Build Coastguard Worker 
581*0ec5a0ecSAndroid Build Coastguard Worker     // Find the first work item marked as EOS. This might not be the first item in the queue, as
582*0ec5a0ecSAndroid Build Coastguard Worker     // previous buffers in the queue might still be waiting for their associated input buffers.
583*0ec5a0ecSAndroid Build Coastguard Worker     auto it = std::find_if(
584*0ec5a0ecSAndroid Build Coastguard Worker             mWorkQueue.cbegin(), mWorkQueue.cend(), [](const std::unique_ptr<C2Work>& work) {
585*0ec5a0ecSAndroid Build Coastguard Worker                 return ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
586*0ec5a0ecSAndroid Build Coastguard Worker                         !(work->worklets.back()->output.flags & C2FrameData::FLAG_END_OF_STREAM));
587*0ec5a0ecSAndroid Build Coastguard Worker             });
588*0ec5a0ecSAndroid Build Coastguard Worker     if (it == mWorkQueue.end()) {
589*0ec5a0ecSAndroid Build Coastguard Worker         ALOGW("No EOS work item found in queue");
590*0ec5a0ecSAndroid Build Coastguard Worker         return;
591*0ec5a0ecSAndroid Build Coastguard Worker     }
592*0ec5a0ecSAndroid Build Coastguard Worker 
593*0ec5a0ecSAndroid Build Coastguard Worker     // Mark the item in the output work queue as EOS done.
594*0ec5a0ecSAndroid Build Coastguard Worker     C2Work* eosWork = it->get();
595*0ec5a0ecSAndroid Build Coastguard Worker     eosWork->worklets.back()->output.flags = C2FrameData::FLAG_END_OF_STREAM;
596*0ec5a0ecSAndroid Build Coastguard Worker 
597*0ec5a0ecSAndroid Build Coastguard Worker     // Draining is done which means all buffers on the device output queue have been returned, but
598*0ec5a0ecSAndroid Build Coastguard Worker     // not all buffers on the device input queue might have been returned yet.
599*0ec5a0ecSAndroid Build Coastguard Worker     if ((eosWork != mWorkQueue.front().get()) || !isWorkDone(*eosWork)) {
600*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Draining done, waiting for input buffers to be returned");
601*0ec5a0ecSAndroid Build Coastguard Worker         return;
602*0ec5a0ecSAndroid Build Coastguard Worker     }
603*0ec5a0ecSAndroid Build Coastguard Worker 
604*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("Draining done");
605*0ec5a0ecSAndroid Build Coastguard Worker     reportWork(std::move(mWorkQueue.front()));
606*0ec5a0ecSAndroid Build Coastguard Worker     mWorkQueue.pop_front();
607*0ec5a0ecSAndroid Build Coastguard Worker }
608*0ec5a0ecSAndroid Build Coastguard Worker 
flushTask(::base::WaitableEvent * done,std::list<std::unique_ptr<C2Work>> * const flushedWork)609*0ec5a0ecSAndroid Build Coastguard Worker void EncodeComponent::flushTask(::base::WaitableEvent* done,
610*0ec5a0ecSAndroid Build Coastguard Worker                                 std::list<std::unique_ptr<C2Work>>* const flushedWork) {
611*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
612*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
613*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
614*0ec5a0ecSAndroid Build Coastguard Worker 
615*0ec5a0ecSAndroid Build Coastguard Worker     // Move all work that can immediately be aborted to flushedWork, and notify the caller.
616*0ec5a0ecSAndroid Build Coastguard Worker     if (flushedWork) {
617*0ec5a0ecSAndroid Build Coastguard Worker         while (!mInputConverterQueue.empty()) {
618*0ec5a0ecSAndroid Build Coastguard Worker             std::unique_ptr<C2Work> work = std::move(mInputConverterQueue.front());
619*0ec5a0ecSAndroid Build Coastguard Worker             work->input.buffers.clear();
620*0ec5a0ecSAndroid Build Coastguard Worker             flushedWork->push_back(std::move(work));
621*0ec5a0ecSAndroid Build Coastguard Worker             mInputConverterQueue.pop();
622*0ec5a0ecSAndroid Build Coastguard Worker         }
623*0ec5a0ecSAndroid Build Coastguard Worker     }
624*0ec5a0ecSAndroid Build Coastguard Worker     done->Signal();
625*0ec5a0ecSAndroid Build Coastguard Worker 
626*0ec5a0ecSAndroid Build Coastguard Worker     flush();
627*0ec5a0ecSAndroid Build Coastguard Worker }
628*0ec5a0ecSAndroid Build Coastguard Worker 
setListenerTask(const std::shared_ptr<Listener> & listener,::base::WaitableEvent * done)629*0ec5a0ecSAndroid Build Coastguard Worker void EncodeComponent::setListenerTask(const std::shared_ptr<Listener>& listener,
630*0ec5a0ecSAndroid Build Coastguard Worker                                       ::base::WaitableEvent* done) {
631*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
632*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
633*0ec5a0ecSAndroid Build Coastguard Worker 
634*0ec5a0ecSAndroid Build Coastguard Worker     mListener = listener;
635*0ec5a0ecSAndroid Build Coastguard Worker     done->Signal();
636*0ec5a0ecSAndroid Build Coastguard Worker }
637*0ec5a0ecSAndroid Build Coastguard Worker 
updateEncodingParameters()638*0ec5a0ecSAndroid Build Coastguard Worker bool EncodeComponent::updateEncodingParameters() {
639*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
640*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
641*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
642*0ec5a0ecSAndroid Build Coastguard Worker 
643*0ec5a0ecSAndroid Build Coastguard Worker     // Ask device to change bitrate if it's different from the currently configured bitrate. The C2
644*0ec5a0ecSAndroid Build Coastguard Worker     // framework doesn't offer a parameter to configure the peak bitrate, so we'll use a multiple of
645*0ec5a0ecSAndroid Build Coastguard Worker     // the target bitrate here. The peak bitrate is only used if the bitrate mode is set to VBR.
646*0ec5a0ecSAndroid Build Coastguard Worker     uint32_t bitrate = mInterface->getBitrate();
647*0ec5a0ecSAndroid Build Coastguard Worker     if (mBitrate != bitrate) {
648*0ec5a0ecSAndroid Build Coastguard Worker         ALOG_ASSERT(bitrate > 0u);
649*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Setting bitrate to %u", bitrate);
650*0ec5a0ecSAndroid Build Coastguard Worker         if (!mEncoder->setBitrate(bitrate)) {
651*0ec5a0ecSAndroid Build Coastguard Worker             reportError(C2_CORRUPTED);
652*0ec5a0ecSAndroid Build Coastguard Worker             return false;
653*0ec5a0ecSAndroid Build Coastguard Worker         }
654*0ec5a0ecSAndroid Build Coastguard Worker         mBitrate = bitrate;
655*0ec5a0ecSAndroid Build Coastguard Worker 
656*0ec5a0ecSAndroid Build Coastguard Worker         if (mBitrateMode == C2Config::BITRATE_VARIABLE) {
657*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("Setting peak bitrate to %u", bitrate * VideoEncoder::kPeakBitrateMultiplier);
658*0ec5a0ecSAndroid Build Coastguard Worker             // TODO(b/190336806): Our stack doesn't support dynamic peak bitrate changes yet, ignore
659*0ec5a0ecSAndroid Build Coastguard Worker             // errors for now.
660*0ec5a0ecSAndroid Build Coastguard Worker             mEncoder->setPeakBitrate(bitrate * VideoEncoder::kPeakBitrateMultiplier);
661*0ec5a0ecSAndroid Build Coastguard Worker         }
662*0ec5a0ecSAndroid Build Coastguard Worker     }
663*0ec5a0ecSAndroid Build Coastguard Worker 
664*0ec5a0ecSAndroid Build Coastguard Worker     // Ask device to change framerate if it's different from the currently configured framerate.
665*0ec5a0ecSAndroid Build Coastguard Worker     uint32_t framerate = static_cast<uint32_t>(std::round(mInterface->getFramerate()));
666*0ec5a0ecSAndroid Build Coastguard Worker     if (mFramerate != framerate) {
667*0ec5a0ecSAndroid Build Coastguard Worker         ALOG_ASSERT(framerate > 0u);
668*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Setting framerate to %u", framerate);
669*0ec5a0ecSAndroid Build Coastguard Worker         if (!mEncoder->setFramerate(framerate)) {
670*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Requesting framerate change failed");
671*0ec5a0ecSAndroid Build Coastguard Worker             reportError(C2_CORRUPTED);
672*0ec5a0ecSAndroid Build Coastguard Worker             return false;
673*0ec5a0ecSAndroid Build Coastguard Worker         }
674*0ec5a0ecSAndroid Build Coastguard Worker         mFramerate = framerate;
675*0ec5a0ecSAndroid Build Coastguard Worker     }
676*0ec5a0ecSAndroid Build Coastguard Worker 
677*0ec5a0ecSAndroid Build Coastguard Worker     // Check whether an explicit key frame was requested, if so reset the key frame counter to
678*0ec5a0ecSAndroid Build Coastguard Worker     // immediately request a key frame.
679*0ec5a0ecSAndroid Build Coastguard Worker     C2StreamRequestSyncFrameTuning::output requestKeyFrame;
680*0ec5a0ecSAndroid Build Coastguard Worker     c2_status_t status = mInterface->query({&requestKeyFrame}, {}, C2_DONT_BLOCK, nullptr);
681*0ec5a0ecSAndroid Build Coastguard Worker     if (status != C2_OK) {
682*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to query interface for key frame request (error code: %d)", status);
683*0ec5a0ecSAndroid Build Coastguard Worker         reportError(status);
684*0ec5a0ecSAndroid Build Coastguard Worker         return false;
685*0ec5a0ecSAndroid Build Coastguard Worker     }
686*0ec5a0ecSAndroid Build Coastguard Worker     if (requestKeyFrame.value == C2_TRUE) {
687*0ec5a0ecSAndroid Build Coastguard Worker         mEncoder->requestKeyframe();
688*0ec5a0ecSAndroid Build Coastguard Worker         requestKeyFrame.value = C2_FALSE;
689*0ec5a0ecSAndroid Build Coastguard Worker         std::vector<std::unique_ptr<C2SettingResult>> failures;
690*0ec5a0ecSAndroid Build Coastguard Worker         status = mInterface->config({&requestKeyFrame}, C2_MAY_BLOCK, &failures);
691*0ec5a0ecSAndroid Build Coastguard Worker         if (status != C2_OK) {
692*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Failed to reset key frame request on interface (error code: %d)", status);
693*0ec5a0ecSAndroid Build Coastguard Worker             reportError(status);
694*0ec5a0ecSAndroid Build Coastguard Worker             return false;
695*0ec5a0ecSAndroid Build Coastguard Worker         }
696*0ec5a0ecSAndroid Build Coastguard Worker     }
697*0ec5a0ecSAndroid Build Coastguard Worker 
698*0ec5a0ecSAndroid Build Coastguard Worker     C2Config::profile_t outputProfile = mInterface->getOutputProfile();
699*0ec5a0ecSAndroid Build Coastguard Worker     if (isH264Profile(outputProfile)) {
700*0ec5a0ecSAndroid Build Coastguard Worker         C2Config::level_t outputLevel = mInterface->getOutputLevel();
701*0ec5a0ecSAndroid Build Coastguard Worker         ui::Size inputSize = mInterface->getInputVisibleSize();
702*0ec5a0ecSAndroid Build Coastguard Worker         mMaxFramerate = maxFramerateForLevelH264(outputLevel, inputSize);
703*0ec5a0ecSAndroid Build Coastguard Worker     }
704*0ec5a0ecSAndroid Build Coastguard Worker 
705*0ec5a0ecSAndroid Build Coastguard Worker     return true;
706*0ec5a0ecSAndroid Build Coastguard Worker }
707*0ec5a0ecSAndroid Build Coastguard Worker 
encode(C2ConstGraphicBlock block,uint64_t index,int64_t timestamp)708*0ec5a0ecSAndroid Build Coastguard Worker bool EncodeComponent::encode(C2ConstGraphicBlock block, uint64_t index, int64_t timestamp) {
709*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
710*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
711*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
712*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoder);
713*0ec5a0ecSAndroid Build Coastguard Worker 
714*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("Encoding input block (index: %" PRIu64 ", timestamp: %" PRId64 ", size: %dx%d)", index,
715*0ec5a0ecSAndroid Build Coastguard Worker           timestamp, block.width(), block.height());
716*0ec5a0ecSAndroid Build Coastguard Worker 
717*0ec5a0ecSAndroid Build Coastguard Worker     // If this is the first input frame, determine the pixel format and layout.
718*0ec5a0ecSAndroid Build Coastguard Worker     if (mInputPixelFormat == VideoPixelFormat::UNKNOWN) {
719*0ec5a0ecSAndroid Build Coastguard Worker         ALOG_ASSERT(mInputLayout.empty());
720*0ec5a0ecSAndroid Build Coastguard Worker         VideoPixelFormat format = VideoPixelFormat::UNKNOWN;
721*0ec5a0ecSAndroid Build Coastguard Worker         std::optional<std::vector<VideoFramePlane>> inputLayout =
722*0ec5a0ecSAndroid Build Coastguard Worker                 getVideoFrameLayout(block, &format);
723*0ec5a0ecSAndroid Build Coastguard Worker         if (!inputLayout) {
724*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Failed to get input block's layout");
725*0ec5a0ecSAndroid Build Coastguard Worker             reportError(C2_CORRUPTED);
726*0ec5a0ecSAndroid Build Coastguard Worker             return false;
727*0ec5a0ecSAndroid Build Coastguard Worker         }
728*0ec5a0ecSAndroid Build Coastguard Worker         mInputPixelFormat = format;
729*0ec5a0ecSAndroid Build Coastguard Worker         mInputLayout = std::move(*inputLayout);
730*0ec5a0ecSAndroid Build Coastguard Worker     }
731*0ec5a0ecSAndroid Build Coastguard Worker 
732*0ec5a0ecSAndroid Build Coastguard Worker     // Dynamically adjust framerate based on the frame's timestamp if required.
733*0ec5a0ecSAndroid Build Coastguard Worker     constexpr int64_t kMaxFramerateDiff = 5;
734*0ec5a0ecSAndroid Build Coastguard Worker     if (mLastFrameTime && (timestamp > *mLastFrameTime)) {
735*0ec5a0ecSAndroid Build Coastguard Worker         int64_t newFramerate = std::max(
736*0ec5a0ecSAndroid Build Coastguard Worker                 static_cast<int64_t>(std::round(1000000.0 / (timestamp - *mLastFrameTime))),
737*0ec5a0ecSAndroid Build Coastguard Worker                 static_cast<int64_t>(1LL));
738*0ec5a0ecSAndroid Build Coastguard Worker         // Clients using input surface may exceed the maximum allowed framerate for the given
739*0ec5a0ecSAndroid Build Coastguard Worker         // profile. One of such examples is android.media.codec.cts.MediaCodecTest#testAbruptStop.
740*0ec5a0ecSAndroid Build Coastguard Worker         // To mitigate that, value is clamped to the maximum framerate for the given level and
741*0ec5a0ecSAndroid Build Coastguard Worker         // current frame size.
742*0ec5a0ecSAndroid Build Coastguard Worker         // See: b/362902868
743*0ec5a0ecSAndroid Build Coastguard Worker         if (newFramerate > mMaxFramerate) {
744*0ec5a0ecSAndroid Build Coastguard Worker             ALOGW("Frames are coming too fast - new framerate (%" PRIi64
745*0ec5a0ecSAndroid Build Coastguard Worker                   ") would exceed the maximum value (%" PRIu32 ")",
746*0ec5a0ecSAndroid Build Coastguard Worker                   newFramerate, mMaxFramerate);
747*0ec5a0ecSAndroid Build Coastguard Worker             newFramerate = mMaxFramerate;
748*0ec5a0ecSAndroid Build Coastguard Worker         }
749*0ec5a0ecSAndroid Build Coastguard Worker 
750*0ec5a0ecSAndroid Build Coastguard Worker         if (abs(mFramerate - newFramerate) > kMaxFramerateDiff) {
751*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("Adjusting framerate to %" PRId64 " based on frame timestamps", newFramerate);
752*0ec5a0ecSAndroid Build Coastguard Worker             mInterface->setFramerate(static_cast<uint32_t>(newFramerate));
753*0ec5a0ecSAndroid Build Coastguard Worker         }
754*0ec5a0ecSAndroid Build Coastguard Worker     }
755*0ec5a0ecSAndroid Build Coastguard Worker     mLastFrameTime = timestamp;
756*0ec5a0ecSAndroid Build Coastguard Worker 
757*0ec5a0ecSAndroid Build Coastguard Worker     // Update dynamic encoding parameters (bitrate, framerate, key frame) if requested.
758*0ec5a0ecSAndroid Build Coastguard Worker     if (!updateEncodingParameters()) return false;
759*0ec5a0ecSAndroid Build Coastguard Worker 
760*0ec5a0ecSAndroid Build Coastguard Worker     // Create an input frame from the graphic block.
761*0ec5a0ecSAndroid Build Coastguard Worker     std::unique_ptr<VideoEncoder::InputFrame> frame =
762*0ec5a0ecSAndroid Build Coastguard Worker             createInputFrame(block, mInputPixelFormat, mInputLayout, index, timestamp);
763*0ec5a0ecSAndroid Build Coastguard Worker     if (!frame) {
764*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to create video frame from input block (index: %" PRIu64
765*0ec5a0ecSAndroid Build Coastguard Worker               ", timestamp: %" PRId64 ")",
766*0ec5a0ecSAndroid Build Coastguard Worker               index, timestamp);
767*0ec5a0ecSAndroid Build Coastguard Worker         reportError(C2_CORRUPTED);
768*0ec5a0ecSAndroid Build Coastguard Worker         return false;
769*0ec5a0ecSAndroid Build Coastguard Worker     }
770*0ec5a0ecSAndroid Build Coastguard Worker 
771*0ec5a0ecSAndroid Build Coastguard Worker     if (!mEncoder->encode(std::move(frame))) {
772*0ec5a0ecSAndroid Build Coastguard Worker         return false;
773*0ec5a0ecSAndroid Build Coastguard Worker     }
774*0ec5a0ecSAndroid Build Coastguard Worker 
775*0ec5a0ecSAndroid Build Coastguard Worker     return true;
776*0ec5a0ecSAndroid Build Coastguard Worker }
777*0ec5a0ecSAndroid Build Coastguard Worker 
flush()778*0ec5a0ecSAndroid Build Coastguard Worker void EncodeComponent::flush() {
779*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
780*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
781*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
782*0ec5a0ecSAndroid Build Coastguard Worker 
783*0ec5a0ecSAndroid Build Coastguard Worker     mEncoder->flush();
784*0ec5a0ecSAndroid Build Coastguard Worker 
785*0ec5a0ecSAndroid Build Coastguard Worker     // Report all queued work items as aborted.
786*0ec5a0ecSAndroid Build Coastguard Worker     std::list<std::unique_ptr<C2Work>> abortedWorkItems;
787*0ec5a0ecSAndroid Build Coastguard Worker     while (!mInputConverterQueue.empty()) {
788*0ec5a0ecSAndroid Build Coastguard Worker         std::unique_ptr<C2Work> work = std::move(mInputConverterQueue.front());
789*0ec5a0ecSAndroid Build Coastguard Worker         work->result = C2_NOT_FOUND;
790*0ec5a0ecSAndroid Build Coastguard Worker         work->input.buffers.clear();
791*0ec5a0ecSAndroid Build Coastguard Worker         abortedWorkItems.push_back(std::move(work));
792*0ec5a0ecSAndroid Build Coastguard Worker         mInputConverterQueue.pop();
793*0ec5a0ecSAndroid Build Coastguard Worker     }
794*0ec5a0ecSAndroid Build Coastguard Worker     while (!mWorkQueue.empty()) {
795*0ec5a0ecSAndroid Build Coastguard Worker         std::unique_ptr<C2Work> work = std::move(mWorkQueue.front());
796*0ec5a0ecSAndroid Build Coastguard Worker         // Return buffer to the input format convertor if required.
797*0ec5a0ecSAndroid Build Coastguard Worker         if (mInputFormatConverter && work->input.buffers.empty()) {
798*0ec5a0ecSAndroid Build Coastguard Worker             mInputFormatConverter->returnBlock(work->input.ordinal.frameIndex.peeku());
799*0ec5a0ecSAndroid Build Coastguard Worker         }
800*0ec5a0ecSAndroid Build Coastguard Worker         work->result = C2_NOT_FOUND;
801*0ec5a0ecSAndroid Build Coastguard Worker         work->input.buffers.clear();
802*0ec5a0ecSAndroid Build Coastguard Worker         abortedWorkItems.push_back(std::move(work));
803*0ec5a0ecSAndroid Build Coastguard Worker         mWorkQueue.pop_front();
804*0ec5a0ecSAndroid Build Coastguard Worker     }
805*0ec5a0ecSAndroid Build Coastguard Worker     if (!abortedWorkItems.empty()) {
806*0ec5a0ecSAndroid Build Coastguard Worker         mListener->onWorkDone_nb(weak_from_this(), std::move(abortedWorkItems));
807*0ec5a0ecSAndroid Build Coastguard Worker     }
808*0ec5a0ecSAndroid Build Coastguard Worker }
809*0ec5a0ecSAndroid Build Coastguard Worker 
fetchOutputBlock(uint32_t size,std::unique_ptr<BitstreamBuffer> * buffer)810*0ec5a0ecSAndroid Build Coastguard Worker void EncodeComponent::fetchOutputBlock(uint32_t size, std::unique_ptr<BitstreamBuffer>* buffer) {
811*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
812*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("Fetching linear block (size: %u)", size);
813*0ec5a0ecSAndroid Build Coastguard Worker     std::shared_ptr<C2LinearBlock> block;
814*0ec5a0ecSAndroid Build Coastguard Worker     c2_status_t status = mOutputBlockPool->fetchLinearBlock(
815*0ec5a0ecSAndroid Build Coastguard Worker             size,
816*0ec5a0ecSAndroid Build Coastguard Worker             C2MemoryUsage(C2MemoryUsage::CPU_READ |
817*0ec5a0ecSAndroid Build Coastguard Worker                           static_cast<uint64_t>(BufferUsage::VIDEO_ENCODER)),
818*0ec5a0ecSAndroid Build Coastguard Worker             &block);
819*0ec5a0ecSAndroid Build Coastguard Worker     if (status != C2_OK) {
820*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to fetch linear block (error: %d)", status);
821*0ec5a0ecSAndroid Build Coastguard Worker         reportError(status);
822*0ec5a0ecSAndroid Build Coastguard Worker     }
823*0ec5a0ecSAndroid Build Coastguard Worker 
824*0ec5a0ecSAndroid Build Coastguard Worker     *buffer = std::make_unique<BitstreamBuffer>(std::move(block), 0, size);
825*0ec5a0ecSAndroid Build Coastguard Worker }
826*0ec5a0ecSAndroid Build Coastguard Worker 
onInputBufferDone(uint64_t index)827*0ec5a0ecSAndroid Build Coastguard Worker void EncodeComponent::onInputBufferDone(uint64_t index) {
828*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(): Input buffer done (index: %" PRIu64 ")", __func__, index);
829*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
830*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoder);
831*0ec5a0ecSAndroid Build Coastguard Worker 
832*0ec5a0ecSAndroid Build Coastguard Worker     // There are no guarantees the input buffers are returned in order, so we need to find the work
833*0ec5a0ecSAndroid Build Coastguard Worker     // item which this buffer belongs to.
834*0ec5a0ecSAndroid Build Coastguard Worker     C2Work* work = getWorkByIndex(index);
835*0ec5a0ecSAndroid Build Coastguard Worker     if (!work) {
836*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to find work associated with input buffer %" PRIu64, index);
837*0ec5a0ecSAndroid Build Coastguard Worker         reportError(C2_CORRUPTED);
838*0ec5a0ecSAndroid Build Coastguard Worker         return;
839*0ec5a0ecSAndroid Build Coastguard Worker     }
840*0ec5a0ecSAndroid Build Coastguard Worker 
841*0ec5a0ecSAndroid Build Coastguard Worker     // We're done using the input block, release reference to return the block to the client.
842*0ec5a0ecSAndroid Build Coastguard Worker     LOG_ASSERT(!work->input.buffers.empty());
843*0ec5a0ecSAndroid Build Coastguard Worker     work->input.buffers.front().reset();
844*0ec5a0ecSAndroid Build Coastguard Worker 
845*0ec5a0ecSAndroid Build Coastguard Worker     // Return the block to the convertor if required. If we have buffers awaiting conversion, we can
846*0ec5a0ecSAndroid Build Coastguard Worker     // now attempt to convert and encode them again.
847*0ec5a0ecSAndroid Build Coastguard Worker     if (mInputFormatConverter) {
848*0ec5a0ecSAndroid Build Coastguard Worker         c2_status_t status = mInputFormatConverter->returnBlock(index);
849*0ec5a0ecSAndroid Build Coastguard Worker         if (status != C2_OK) {
850*0ec5a0ecSAndroid Build Coastguard Worker             reportError(status);
851*0ec5a0ecSAndroid Build Coastguard Worker             return;
852*0ec5a0ecSAndroid Build Coastguard Worker         }
853*0ec5a0ecSAndroid Build Coastguard Worker         while (!mInputConverterQueue.empty() && mInputFormatConverter->isReady()) {
854*0ec5a0ecSAndroid Build Coastguard Worker             std::unique_ptr<C2Work> work = std::move(mInputConverterQueue.front());
855*0ec5a0ecSAndroid Build Coastguard Worker             mInputConverterQueue.pop();
856*0ec5a0ecSAndroid Build Coastguard Worker             queueTask(std::move(work));
857*0ec5a0ecSAndroid Build Coastguard Worker         }
858*0ec5a0ecSAndroid Build Coastguard Worker     }
859*0ec5a0ecSAndroid Build Coastguard Worker 
860*0ec5a0ecSAndroid Build Coastguard Worker     // Return all completed work items. The work item might have been waiting for it's input buffer
861*0ec5a0ecSAndroid Build Coastguard Worker     // to be returned, in which case we can report it as completed now. As input buffers are not
862*0ec5a0ecSAndroid Build Coastguard Worker     // necessarily returned in order we might be able to return multiple ready work items now.
863*0ec5a0ecSAndroid Build Coastguard Worker     while (!mWorkQueue.empty() && isWorkDone(*mWorkQueue.front())) {
864*0ec5a0ecSAndroid Build Coastguard Worker         reportWork(std::move(mWorkQueue.front()));
865*0ec5a0ecSAndroid Build Coastguard Worker         mWorkQueue.pop_front();
866*0ec5a0ecSAndroid Build Coastguard Worker     }
867*0ec5a0ecSAndroid Build Coastguard Worker }
868*0ec5a0ecSAndroid Build Coastguard Worker 
onOutputBufferDone(size_t dataSize,int64_t timestamp,bool keyFrame,std::unique_ptr<BitstreamBuffer> buffer)869*0ec5a0ecSAndroid Build Coastguard Worker void EncodeComponent::onOutputBufferDone(size_t dataSize, int64_t timestamp, bool keyFrame,
870*0ec5a0ecSAndroid Build Coastguard Worker                                          std::unique_ptr<BitstreamBuffer> buffer) {
871*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(): output buffer done (timestamp: %" PRId64 ", size: %zu, keyframe: %d)", __func__,
872*0ec5a0ecSAndroid Build Coastguard Worker           timestamp, dataSize, keyFrame);
873*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
874*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(buffer->dmabuf);
875*0ec5a0ecSAndroid Build Coastguard Worker 
876*0ec5a0ecSAndroid Build Coastguard Worker     C2ConstLinearBlock constBlock =
877*0ec5a0ecSAndroid Build Coastguard Worker             buffer->dmabuf->share(buffer->dmabuf->offset(), dataSize, C2Fence());
878*0ec5a0ecSAndroid Build Coastguard Worker 
879*0ec5a0ecSAndroid Build Coastguard Worker     // If no CSD (content-specific-data, e.g. SPS for H.264) has been submitted yet, we expect this
880*0ec5a0ecSAndroid Build Coastguard Worker     // output block to contain CSD. We only submit the CSD once, even if it's attached to each key
881*0ec5a0ecSAndroid Build Coastguard Worker     // frame.
882*0ec5a0ecSAndroid Build Coastguard Worker     if (mExtractCSD) {
883*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("No CSD submitted yet, extracting CSD");
884*0ec5a0ecSAndroid Build Coastguard Worker         std::unique_ptr<C2StreamInitDataInfo::output> csd;
885*0ec5a0ecSAndroid Build Coastguard Worker         C2ReadView view = constBlock.map().get();
886*0ec5a0ecSAndroid Build Coastguard Worker         if (!extractCSDInfo(&csd, view.data(), view.capacity())) {
887*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Failed to extract CSD");
888*0ec5a0ecSAndroid Build Coastguard Worker             reportError(C2_CORRUPTED);
889*0ec5a0ecSAndroid Build Coastguard Worker             return;
890*0ec5a0ecSAndroid Build Coastguard Worker         }
891*0ec5a0ecSAndroid Build Coastguard Worker 
892*0ec5a0ecSAndroid Build Coastguard Worker         // Attach the CSD to the first item in our output work queue.
893*0ec5a0ecSAndroid Build Coastguard Worker         LOG_ASSERT(!mWorkQueue.empty());
894*0ec5a0ecSAndroid Build Coastguard Worker         C2Work* work = mWorkQueue.front().get();
895*0ec5a0ecSAndroid Build Coastguard Worker         work->worklets.front()->output.configUpdate.push_back(std::move(csd));
896*0ec5a0ecSAndroid Build Coastguard Worker         mExtractCSD = false;
897*0ec5a0ecSAndroid Build Coastguard Worker     }
898*0ec5a0ecSAndroid Build Coastguard Worker 
899*0ec5a0ecSAndroid Build Coastguard Worker     // Get the work item associated with the timestamp.
900*0ec5a0ecSAndroid Build Coastguard Worker     C2Work* work = getWorkByTimestamp(timestamp);
901*0ec5a0ecSAndroid Build Coastguard Worker     if (!work) {
902*0ec5a0ecSAndroid Build Coastguard Worker         // It's possible we got an empty CSD request with timestamp 0, which we currently just
903*0ec5a0ecSAndroid Build Coastguard Worker         // discard.
904*0ec5a0ecSAndroid Build Coastguard Worker         if (timestamp != 0) {
905*0ec5a0ecSAndroid Build Coastguard Worker             reportError(C2_CORRUPTED);
906*0ec5a0ecSAndroid Build Coastguard Worker         }
907*0ec5a0ecSAndroid Build Coastguard Worker         return;
908*0ec5a0ecSAndroid Build Coastguard Worker     }
909*0ec5a0ecSAndroid Build Coastguard Worker 
910*0ec5a0ecSAndroid Build Coastguard Worker     std::shared_ptr<C2Buffer> linearBuffer = C2Buffer::CreateLinearBuffer(std::move(constBlock));
911*0ec5a0ecSAndroid Build Coastguard Worker     if (!linearBuffer) {
912*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to create linear buffer from block");
913*0ec5a0ecSAndroid Build Coastguard Worker         reportError(C2_CORRUPTED);
914*0ec5a0ecSAndroid Build Coastguard Worker         return;
915*0ec5a0ecSAndroid Build Coastguard Worker     }
916*0ec5a0ecSAndroid Build Coastguard Worker 
917*0ec5a0ecSAndroid Build Coastguard Worker     if (keyFrame) {
918*0ec5a0ecSAndroid Build Coastguard Worker         linearBuffer->setInfo(
919*0ec5a0ecSAndroid Build Coastguard Worker                 std::make_shared<C2StreamPictureTypeMaskInfo::output>(0u, C2Config::SYNC_FRAME));
920*0ec5a0ecSAndroid Build Coastguard Worker     }
921*0ec5a0ecSAndroid Build Coastguard Worker     work->worklets.front()->output.buffers.emplace_back(std::move(linearBuffer));
922*0ec5a0ecSAndroid Build Coastguard Worker 
923*0ec5a0ecSAndroid Build Coastguard Worker     // We can report the work item as completed if its associated input buffer has also been
924*0ec5a0ecSAndroid Build Coastguard Worker     // released. As output buffers are not necessarily returned in order we might be able to return
925*0ec5a0ecSAndroid Build Coastguard Worker     // multiple ready work items now.
926*0ec5a0ecSAndroid Build Coastguard Worker     while (!mWorkQueue.empty() && isWorkDone(*mWorkQueue.front())) {
927*0ec5a0ecSAndroid Build Coastguard Worker         reportWork(std::move(mWorkQueue.front()));
928*0ec5a0ecSAndroid Build Coastguard Worker         mWorkQueue.pop_front();
929*0ec5a0ecSAndroid Build Coastguard Worker     }
930*0ec5a0ecSAndroid Build Coastguard Worker }
931*0ec5a0ecSAndroid Build Coastguard Worker 
getWorkByIndex(uint64_t index)932*0ec5a0ecSAndroid Build Coastguard Worker C2Work* EncodeComponent::getWorkByIndex(uint64_t index) {
933*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(): getting work item (index: %" PRIu64 ")", __func__, index);
934*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
935*0ec5a0ecSAndroid Build Coastguard Worker 
936*0ec5a0ecSAndroid Build Coastguard Worker     auto it = std::find_if(mWorkQueue.begin(), mWorkQueue.end(),
937*0ec5a0ecSAndroid Build Coastguard Worker                            [index](const std::unique_ptr<C2Work>& w) {
938*0ec5a0ecSAndroid Build Coastguard Worker                                return w->input.ordinal.frameIndex.peeku() == index;
939*0ec5a0ecSAndroid Build Coastguard Worker                            });
940*0ec5a0ecSAndroid Build Coastguard Worker     if (it == mWorkQueue.end()) {
941*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to find work (index: %" PRIu64 ")", index);
942*0ec5a0ecSAndroid Build Coastguard Worker         return nullptr;
943*0ec5a0ecSAndroid Build Coastguard Worker     }
944*0ec5a0ecSAndroid Build Coastguard Worker     return it->get();
945*0ec5a0ecSAndroid Build Coastguard Worker }
946*0ec5a0ecSAndroid Build Coastguard Worker 
getWorkByTimestamp(int64_t timestamp)947*0ec5a0ecSAndroid Build Coastguard Worker C2Work* EncodeComponent::getWorkByTimestamp(int64_t timestamp) {
948*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(): getting work item (timestamp: %" PRId64 ")", __func__, timestamp);
949*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
950*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(timestamp >= 0);
951*0ec5a0ecSAndroid Build Coastguard Worker 
952*0ec5a0ecSAndroid Build Coastguard Worker     // Find the work with specified timestamp by looping over the output work queue. This should be
953*0ec5a0ecSAndroid Build Coastguard Worker     // very fast as the output work queue will never be longer then a few items. Ignore empty work
954*0ec5a0ecSAndroid Build Coastguard Worker     // items that are marked as EOS, as their timestamp might clash with other work items.
955*0ec5a0ecSAndroid Build Coastguard Worker     auto it = std::find_if(
956*0ec5a0ecSAndroid Build Coastguard Worker             mWorkQueue.begin(), mWorkQueue.end(), [timestamp](const std::unique_ptr<C2Work>& w) {
957*0ec5a0ecSAndroid Build Coastguard Worker                 return !(w->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
958*0ec5a0ecSAndroid Build Coastguard Worker                        w->input.ordinal.timestamp.peeku() == static_cast<uint64_t>(timestamp);
959*0ec5a0ecSAndroid Build Coastguard Worker             });
960*0ec5a0ecSAndroid Build Coastguard Worker     if (it == mWorkQueue.end()) {
961*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to find work (timestamp: %" PRIu64 ")", timestamp);
962*0ec5a0ecSAndroid Build Coastguard Worker         return nullptr;
963*0ec5a0ecSAndroid Build Coastguard Worker     }
964*0ec5a0ecSAndroid Build Coastguard Worker     return it->get();
965*0ec5a0ecSAndroid Build Coastguard Worker }
966*0ec5a0ecSAndroid Build Coastguard Worker 
isWorkDone(const C2Work & work) const967*0ec5a0ecSAndroid Build Coastguard Worker bool EncodeComponent::isWorkDone(const C2Work& work) const {
968*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
969*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
970*0ec5a0ecSAndroid Build Coastguard Worker 
971*0ec5a0ecSAndroid Build Coastguard Worker     if ((work.input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
972*0ec5a0ecSAndroid Build Coastguard Worker         !(work.worklets.front()->output.flags & C2FrameData::FLAG_END_OF_STREAM)) {
973*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Work item %" PRIu64 " is marked as EOS but draining has not finished yet",
974*0ec5a0ecSAndroid Build Coastguard Worker               work.input.ordinal.frameIndex.peeku());
975*0ec5a0ecSAndroid Build Coastguard Worker         return false;
976*0ec5a0ecSAndroid Build Coastguard Worker     }
977*0ec5a0ecSAndroid Build Coastguard Worker 
978*0ec5a0ecSAndroid Build Coastguard Worker     if (!work.input.buffers.empty() && work.input.buffers.front()) {
979*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Input buffer associated with work item %" PRIu64 " not returned yet",
980*0ec5a0ecSAndroid Build Coastguard Worker               work.input.ordinal.frameIndex.peeku());
981*0ec5a0ecSAndroid Build Coastguard Worker         return false;
982*0ec5a0ecSAndroid Build Coastguard Worker     }
983*0ec5a0ecSAndroid Build Coastguard Worker 
984*0ec5a0ecSAndroid Build Coastguard Worker     // If the work item had an input buffer to be encoded, it should have an output buffer set.
985*0ec5a0ecSAndroid Build Coastguard Worker     if (!work.input.buffers.empty() && work.worklets.front()->output.buffers.empty()) {
986*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Output buffer associated with work item %" PRIu64 " not returned yet",
987*0ec5a0ecSAndroid Build Coastguard Worker               work.input.ordinal.frameIndex.peeku());
988*0ec5a0ecSAndroid Build Coastguard Worker         return false;
989*0ec5a0ecSAndroid Build Coastguard Worker     }
990*0ec5a0ecSAndroid Build Coastguard Worker 
991*0ec5a0ecSAndroid Build Coastguard Worker     return true;
992*0ec5a0ecSAndroid Build Coastguard Worker }
993*0ec5a0ecSAndroid Build Coastguard Worker 
reportWork(std::unique_ptr<C2Work> work)994*0ec5a0ecSAndroid Build Coastguard Worker void EncodeComponent::reportWork(std::unique_ptr<C2Work> work) {
995*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
996*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(work);
997*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(): Reporting work item as finished (index: %llu, timestamp: %llu)", __func__,
998*0ec5a0ecSAndroid Build Coastguard Worker           work->input.ordinal.frameIndex.peekull(), work->input.ordinal.timestamp.peekull());
999*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
1000*0ec5a0ecSAndroid Build Coastguard Worker 
1001*0ec5a0ecSAndroid Build Coastguard Worker     work->result = C2_OK;
1002*0ec5a0ecSAndroid Build Coastguard Worker     work->workletsProcessed = static_cast<uint32_t>(work->worklets.size());
1003*0ec5a0ecSAndroid Build Coastguard Worker 
1004*0ec5a0ecSAndroid Build Coastguard Worker     std::list<std::unique_ptr<C2Work>> finishedWorkList;
1005*0ec5a0ecSAndroid Build Coastguard Worker     finishedWorkList.emplace_back(std::move(work));
1006*0ec5a0ecSAndroid Build Coastguard Worker     mListener->onWorkDone_nb(weak_from_this(), std::move(finishedWorkList));
1007*0ec5a0ecSAndroid Build Coastguard Worker }
1008*0ec5a0ecSAndroid Build Coastguard Worker 
getBlockPool()1009*0ec5a0ecSAndroid Build Coastguard Worker bool EncodeComponent::getBlockPool() {
1010*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
1011*0ec5a0ecSAndroid Build Coastguard Worker 
1012*0ec5a0ecSAndroid Build Coastguard Worker     auto sharedThis = weak_from_this().lock();
1013*0ec5a0ecSAndroid Build Coastguard Worker     if (!sharedThis) {
1014*0ec5a0ecSAndroid Build Coastguard Worker         ALOGI("%s(): V4L2EncodeComponent instance is already destroyed", __func__);
1015*0ec5a0ecSAndroid Build Coastguard Worker         return false;
1016*0ec5a0ecSAndroid Build Coastguard Worker     }
1017*0ec5a0ecSAndroid Build Coastguard Worker 
1018*0ec5a0ecSAndroid Build Coastguard Worker     C2BlockPool::local_id_t poolId = mInterface->getBlockPoolId();
1019*0ec5a0ecSAndroid Build Coastguard Worker     if (poolId == C2BlockPool::BASIC_LINEAR) {
1020*0ec5a0ecSAndroid Build Coastguard Worker         ALOGW("Using unoptimized linear block pool");
1021*0ec5a0ecSAndroid Build Coastguard Worker     }
1022*0ec5a0ecSAndroid Build Coastguard Worker     c2_status_t status = GetCodec2BlockPool(poolId, std::move(sharedThis), &mOutputBlockPool);
1023*0ec5a0ecSAndroid Build Coastguard Worker     if (status != C2_OK || !mOutputBlockPool) {
1024*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to get output block pool, error: %d", status);
1025*0ec5a0ecSAndroid Build Coastguard Worker         return false;
1026*0ec5a0ecSAndroid Build Coastguard Worker     }
1027*0ec5a0ecSAndroid Build Coastguard Worker     return true;
1028*0ec5a0ecSAndroid Build Coastguard Worker }
1029*0ec5a0ecSAndroid Build Coastguard Worker 
reportError(c2_status_t error)1030*0ec5a0ecSAndroid Build Coastguard Worker void EncodeComponent::reportError(c2_status_t error) {
1031*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
1032*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
1033*0ec5a0ecSAndroid Build Coastguard Worker 
1034*0ec5a0ecSAndroid Build Coastguard Worker     // TODO(dstaessens): Report all pending work items as finished upon failure.
1035*0ec5a0ecSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mComponentLock);
1036*0ec5a0ecSAndroid Build Coastguard Worker     if (mComponentState != ComponentState::ERROR) {
1037*0ec5a0ecSAndroid Build Coastguard Worker         setComponentState(ComponentState::ERROR);
1038*0ec5a0ecSAndroid Build Coastguard Worker         mListener->onError_nb(weak_from_this(), static_cast<uint32_t>(error));
1039*0ec5a0ecSAndroid Build Coastguard Worker     }
1040*0ec5a0ecSAndroid Build Coastguard Worker }
1041*0ec5a0ecSAndroid Build Coastguard Worker 
setComponentState(ComponentState state)1042*0ec5a0ecSAndroid Build Coastguard Worker void EncodeComponent::setComponentState(ComponentState state) {
1043*0ec5a0ecSAndroid Build Coastguard Worker     // Check whether the state change is valid.
1044*0ec5a0ecSAndroid Build Coastguard Worker     switch (state) {
1045*0ec5a0ecSAndroid Build Coastguard Worker     case ComponentState::UNLOADED:
1046*0ec5a0ecSAndroid Build Coastguard Worker         ALOG_ASSERT(mComponentState == ComponentState::LOADED);
1047*0ec5a0ecSAndroid Build Coastguard Worker         break;
1048*0ec5a0ecSAndroid Build Coastguard Worker     case ComponentState::LOADED:
1049*0ec5a0ecSAndroid Build Coastguard Worker         ALOG_ASSERT(mComponentState == ComponentState::UNLOADED ||
1050*0ec5a0ecSAndroid Build Coastguard Worker                     mComponentState == ComponentState::RUNNING ||
1051*0ec5a0ecSAndroid Build Coastguard Worker                     mComponentState == ComponentState::ERROR);
1052*0ec5a0ecSAndroid Build Coastguard Worker         break;
1053*0ec5a0ecSAndroid Build Coastguard Worker     case ComponentState::RUNNING:
1054*0ec5a0ecSAndroid Build Coastguard Worker         ALOG_ASSERT(mComponentState == ComponentState::LOADED);
1055*0ec5a0ecSAndroid Build Coastguard Worker         break;
1056*0ec5a0ecSAndroid Build Coastguard Worker     case ComponentState::ERROR:
1057*0ec5a0ecSAndroid Build Coastguard Worker         break;
1058*0ec5a0ecSAndroid Build Coastguard Worker     }
1059*0ec5a0ecSAndroid Build Coastguard Worker 
1060*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("Changed component state from %s to %s", componentStateToString(mComponentState),
1061*0ec5a0ecSAndroid Build Coastguard Worker           componentStateToString(state));
1062*0ec5a0ecSAndroid Build Coastguard Worker     mComponentState = state;
1063*0ec5a0ecSAndroid Build Coastguard Worker }
1064*0ec5a0ecSAndroid Build Coastguard Worker 
componentStateToString(EncodeComponent::ComponentState state)1065*0ec5a0ecSAndroid Build Coastguard Worker const char* EncodeComponent::componentStateToString(EncodeComponent::ComponentState state) {
1066*0ec5a0ecSAndroid Build Coastguard Worker     switch (state) {
1067*0ec5a0ecSAndroid Build Coastguard Worker     case ComponentState::UNLOADED:
1068*0ec5a0ecSAndroid Build Coastguard Worker         return "UNLOADED";
1069*0ec5a0ecSAndroid Build Coastguard Worker     case ComponentState::LOADED:
1070*0ec5a0ecSAndroid Build Coastguard Worker         return "LOADED";
1071*0ec5a0ecSAndroid Build Coastguard Worker     case ComponentState::RUNNING:
1072*0ec5a0ecSAndroid Build Coastguard Worker         return "RUNNING";
1073*0ec5a0ecSAndroid Build Coastguard Worker     case ComponentState::ERROR:
1074*0ec5a0ecSAndroid Build Coastguard Worker         return "ERROR";
1075*0ec5a0ecSAndroid Build Coastguard Worker     }
1076*0ec5a0ecSAndroid Build Coastguard Worker }
1077*0ec5a0ecSAndroid Build Coastguard Worker 
1078*0ec5a0ecSAndroid Build Coastguard Worker }  // namespace android
1079