1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #ifdef MPEG4
19   #define LOG_TAG "C2SoftMpeg4Enc"
20 #else
21   #define LOG_TAG "C2SoftH263Enc"
22 #endif
23 #include <log/log.h>
24 
25 #include <inttypes.h>
26 
27 #include <media/hardware/VideoAPI.h>
28 #include <media/stagefright/foundation/AUtils.h>
29 #include <media/stagefright/MediaDefs.h>
30 #include <utils/misc.h>
31 
32 #include <C2Debug.h>
33 #include <C2PlatformSupport.h>
34 #include <SimpleC2Interface.h>
35 #include <util/C2InterfaceHelper.h>
36 
37 #include "C2SoftMpeg4Enc.h"
38 #include "mp4enc_api.h"
39 
40 namespace android {
41 
42 namespace {
43 
44 #ifdef MPEG4
45 constexpr char COMPONENT_NAME[] = "c2.android.mpeg4.encoder";
46 const char *MEDIA_MIMETYPE_VIDEO = MEDIA_MIMETYPE_VIDEO_MPEG4;
47 #else
48 constexpr char COMPONENT_NAME[] = "c2.android.h263.encoder";
49 const char *MEDIA_MIMETYPE_VIDEO = MEDIA_MIMETYPE_VIDEO_H263;
50 #endif
51 
52 } // namepsace
53 
54 class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams {
55    public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)56     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
57         : SimpleInterface<void>::BaseParams(
58                 helper,
59                 COMPONENT_NAME,
60                 C2Component::KIND_ENCODER,
61                 C2Component::DOMAIN_VIDEO,
62                 MEDIA_MIMETYPE_VIDEO) {
63         noPrivateBuffers(); // TODO: account for our buffers here
64         noInputReferences();
65         noOutputReferences();
66         noInputLatency();
67         noTimeStretch();
68         setDerivedInstance(this);
69 
70         addParameter(
71                 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
72                 .withConstValue(new C2ComponentAttributesSetting(
73                     C2Component::ATTRIB_IS_TEMPORAL))
74                 .build());
75 
76         addParameter(
77                 DefineParam(mUsage, C2_PARAMKEY_INPUT_STREAM_USAGE)
78                 .withConstValue(new C2StreamUsageTuning::input(
79                         0u, (uint64_t)C2MemoryUsage::CPU_READ))
80                 .build());
81 
82         addParameter(
83             DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
84                 .withDefault(new C2StreamPictureSizeInfo::input(0u, 176, 144))
85                 .withFields({
86 #ifdef MPEG4
87                     C2F(mSize, width).inRange(16, 176, 16),
88                     C2F(mSize, height).inRange(16, 144, 16),
89 #else
90                     C2F(mSize, width).oneOf({176, 352}),
91                     C2F(mSize, height).oneOf({144, 288}),
92 #endif
93                 })
94                 .withSetter(SizeSetter)
95                 .build());
96 
97         addParameter(
98             DefineParam(mFrameRate, C2_PARAMKEY_FRAME_RATE)
99                 .withDefault(new C2StreamFrameRateInfo::output(0u, 17.))
100                 // TODO: More restriction?
101                 .withFields({C2F(mFrameRate, value).greaterThan(0.)})
102                 .withSetter(
103                     Setter<decltype(*mFrameRate)>::StrictValueWithNoDeps)
104                 .build());
105 
106         addParameter(
107             DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
108                 .withDefault(new C2StreamBitrateInfo::output(0u, 64000))
109                 .withFields({C2F(mBitrate, value).inRange(4096, 12000000)})
110                 .withSetter(BitrateSetter)
111                 .build());
112 
113         addParameter(
114                 DefineParam(mSyncFramePeriod, C2_PARAMKEY_SYNC_FRAME_INTERVAL)
115                 .withDefault(new C2StreamSyncFrameIntervalTuning::output(0u, 1000000))
116                 .withFields({C2F(mSyncFramePeriod, value).any()})
117                 .withSetter(Setter<decltype(*mSyncFramePeriod)>::StrictValueWithNoDeps)
118                 .build());
119 
120 #ifdef MPEG4
121         addParameter(
122                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
123                 .withDefault(new C2StreamProfileLevelInfo::output(
124                         0u, PROFILE_MP4V_SIMPLE, LEVEL_MP4V_2))
125                 .withFields({
126                     C2F(mProfileLevel, profile).equalTo(
127                             PROFILE_MP4V_SIMPLE),
128                     C2F(mProfileLevel, level).oneOf({
129                             C2Config::LEVEL_MP4V_0,
130                             C2Config::LEVEL_MP4V_0B,
131                             C2Config::LEVEL_MP4V_1,
132                             C2Config::LEVEL_MP4V_2})
133                 })
134                 .withSetter(ProfileLevelSetter)
135                 .build());
136 #else
137         addParameter(
138                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
139                 .withDefault(new C2StreamProfileLevelInfo::output(
140                         0u, PROFILE_H263_BASELINE, LEVEL_H263_45))
141                 .withFields({
142                     C2F(mProfileLevel, profile).equalTo(
143                             PROFILE_H263_BASELINE),
144                     C2F(mProfileLevel, level).oneOf({
145                             C2Config::LEVEL_H263_10,
146                             C2Config::LEVEL_H263_20,
147                             C2Config::LEVEL_H263_30,
148                             C2Config::LEVEL_H263_40,
149                             C2Config::LEVEL_H263_45})
150                 })
151                 .withSetter(ProfileLevelSetter)
152                 .build());
153 #endif
154     }
155 
BitrateSetter(bool mayBlock,C2P<C2StreamBitrateInfo::output> & me)156     static C2R BitrateSetter(bool mayBlock, C2P<C2StreamBitrateInfo::output> &me) {
157         (void)mayBlock;
158         C2R res = C2R::Ok();
159         if (me.v.value <= 4096) {
160             me.set().value = 4096;
161         }
162         return res;
163     }
164 
SizeSetter(bool mayBlock,const C2P<C2StreamPictureSizeInfo::input> & oldMe,C2P<C2StreamPictureSizeInfo::input> & me)165     static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::input> &oldMe,
166                           C2P<C2StreamPictureSizeInfo::input> &me) {
167         (void)mayBlock;
168         C2R res = C2R::Ok();
169         if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
170             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
171             me.set().width = oldMe.v.width;
172         }
173         if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
174             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
175             me.set().height = oldMe.v.height;
176         }
177         return res;
178     }
179 
ProfileLevelSetter(bool mayBlock,C2P<C2StreamProfileLevelInfo::output> & me)180     static C2R ProfileLevelSetter(
181             bool mayBlock,
182             C2P<C2StreamProfileLevelInfo::output> &me) {
183         (void)mayBlock;
184         if (!me.F(me.v.profile).supportsAtAll(me.v.profile)) {
185 #ifdef MPEG4
186             me.set().profile = PROFILE_MP4V_SIMPLE;
187 #else
188             me.set().profile = PROFILE_H263_BASELINE;
189 #endif
190         }
191         if (!me.F(me.v.level).supportsAtAll(me.v.level)) {
192 #ifdef MPEG4
193             me.set().level = LEVEL_MP4V_2;
194 #else
195             me.set().level = LEVEL_H263_45;
196 #endif
197         }
198         return C2R::Ok();
199     }
200 
201     // unsafe getters
getSize_l() const202     std::shared_ptr<C2StreamPictureSizeInfo::input> getSize_l() const { return mSize; }
getFrameRate_l() const203     std::shared_ptr<C2StreamFrameRateInfo::output> getFrameRate_l() const { return mFrameRate; }
getBitrate_l() const204     std::shared_ptr<C2StreamBitrateInfo::output> getBitrate_l() const { return mBitrate; }
getSyncFramePeriod() const205     uint32_t getSyncFramePeriod() const {
206         if (mSyncFramePeriod->value < 0 || mSyncFramePeriod->value == INT64_MAX) {
207             return 0;
208         }
209         double period = mSyncFramePeriod->value / 1e6 * mFrameRate->value;
210         return (uint32_t)c2_max(c2_min(period + 0.5, double(UINT32_MAX)), 1.);
211     }
212 
213    private:
214     std::shared_ptr<C2StreamUsageTuning::input> mUsage;
215     std::shared_ptr<C2StreamPictureSizeInfo::input> mSize;
216     std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
217     std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
218     std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
219     std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mSyncFramePeriod;
220 };
221 
C2SoftMpeg4Enc(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)222 C2SoftMpeg4Enc::C2SoftMpeg4Enc(const char* name, c2_node_id_t id,
223                                const std::shared_ptr<IntfImpl>& intfImpl)
224     : SimpleC2Component(
225           std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
226       mIntf(intfImpl),
227       mHandle(nullptr),
228       mEncParams(nullptr),
229       mStarted(false),
230       mOutBufferSize(524288) {
231 }
232 
~C2SoftMpeg4Enc()233 C2SoftMpeg4Enc::~C2SoftMpeg4Enc() {
234     onRelease();
235 }
236 
onInit()237 c2_status_t C2SoftMpeg4Enc::onInit() {
238 #ifdef MPEG4
239     mEncodeMode = COMBINE_MODE_WITH_ERR_RES;
240 #else
241     mEncodeMode = H263_MODE;
242 #endif
243     if (!mHandle) {
244         mHandle = new tagvideoEncControls;
245     }
246 
247     if (!mEncParams) {
248         mEncParams = new tagvideoEncOptions;
249     }
250 
251     if (!(mEncParams && mHandle)) return C2_NO_MEMORY;
252 
253     mSignalledOutputEos = false;
254     mSignalledError = false;
255 
256     return initEncoder();
257 }
258 
onStop()259 c2_status_t C2SoftMpeg4Enc::onStop() {
260     if (!mStarted) {
261         return C2_OK;
262     }
263     if (mHandle) {
264         (void)PVCleanUpVideoEncoder(mHandle);
265     }
266     mStarted = false;
267     mSignalledOutputEos = false;
268     mSignalledError = false;
269     return C2_OK;
270 }
271 
onReset()272 void C2SoftMpeg4Enc::onReset() {
273     onStop();
274     initEncoder();
275 }
276 
onRelease()277 void C2SoftMpeg4Enc::onRelease() {
278     onStop();
279     if (mEncParams) {
280         delete mEncParams;
281         mEncParams = nullptr;
282     }
283     if (mHandle) {
284         delete mHandle;
285         mHandle = nullptr;
286     }
287 }
288 
onFlush_sm()289 c2_status_t C2SoftMpeg4Enc::onFlush_sm() {
290     return C2_OK;
291 }
292 
fillEmptyWork(const std::unique_ptr<C2Work> & work)293 static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
294     uint32_t flags = 0;
295     if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
296         flags |= C2FrameData::FLAG_END_OF_STREAM;
297         ALOGV("signalling eos");
298     }
299     work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
300     work->worklets.front()->output.buffers.clear();
301     work->worklets.front()->output.ordinal = work->input.ordinal;
302     work->workletsProcessed = 1u;
303 }
304 
initEncParams()305 c2_status_t C2SoftMpeg4Enc::initEncParams() {
306     if (mHandle) {
307         memset(mHandle, 0, sizeof(tagvideoEncControls));
308     } else return C2_CORRUPTED;
309     if (mEncParams) {
310         memset(mEncParams, 0, sizeof(tagvideoEncOptions));
311     } else return C2_CORRUPTED;
312 
313     if (!PVGetDefaultEncOption(mEncParams, 0)) {
314         ALOGE("Failed to get default encoding parameters");
315         return C2_CORRUPTED;
316     }
317 
318     if (mFrameRate->value == 0) {
319         ALOGE("Framerate should not be 0");
320         return C2_BAD_VALUE;
321     }
322 
323     mEncParams->encMode = mEncodeMode;
324     mEncParams->encWidth[0] = mSize->width;
325     mEncParams->encHeight[0] = mSize->height;
326     mEncParams->encFrameRate[0] = mFrameRate->value + 0.5;
327     mEncParams->rcType = VBR_1;
328     mEncParams->vbvDelay = 5.0f;
329     mEncParams->profile_level = CORE_PROFILE_LEVEL2;
330     mEncParams->packetSize = 32;
331     mEncParams->rvlcEnable = PV_OFF;
332     mEncParams->numLayers = 1;
333     mEncParams->timeIncRes = 1000;
334     mEncParams->tickPerSrc = mEncParams->timeIncRes / (mFrameRate->value + 0.5);
335     mEncParams->bitRate[0] = mBitrate->value;
336     mEncParams->iQuant[0] = 15;
337     mEncParams->pQuant[0] = 12;
338     mEncParams->quantType[0] = 0;
339     mEncParams->noFrameSkipped = PV_OFF;
340 
341     // PV's MPEG4 encoder requires the video dimension of multiple
342     if (mSize->width % 16 != 0 || mSize->height % 16 != 0) {
343         ALOGE("Video frame size %dx%d must be a multiple of 16",
344               mSize->width, mSize->height);
345         return C2_BAD_VALUE;
346     }
347 
348     // Set IDR frame refresh interval
349     mEncParams->intraPeriod = mIntf->getSyncFramePeriod();
350     mEncParams->numIntraMB = 0;
351     mEncParams->sceneDetect = PV_ON;
352     mEncParams->searchRange = 16;
353     mEncParams->mv8x8Enable = PV_OFF;
354     mEncParams->gobHeaderInterval = 0;
355     mEncParams->useACPred = PV_ON;
356     mEncParams->intraDCVlcTh = 0;
357 
358     return C2_OK;
359 }
360 
initEncoder()361 c2_status_t C2SoftMpeg4Enc::initEncoder() {
362     if (mStarted) {
363         return C2_OK;
364     }
365     {
366         IntfImpl::Lock lock = mIntf->lock();
367         mSize = mIntf->getSize_l();
368         mBitrate = mIntf->getBitrate_l();
369         mFrameRate = mIntf->getFrameRate_l();
370     }
371     c2_status_t err = initEncParams();
372     if (C2_OK != err) {
373         ALOGE("Failed to initialized encoder params");
374         mSignalledError = true;
375         return err;
376     }
377     if (!PVInitVideoEncoder(mHandle, mEncParams)) {
378         ALOGE("Failed to initialize the encoder");
379         mSignalledError = true;
380         return C2_CORRUPTED;
381     }
382 
383     // 1st buffer for codec specific data
384     mNumInputFrames = -1;
385     mStarted = true;
386     return C2_OK;
387 }
388 
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)389 void C2SoftMpeg4Enc::process(
390         const std::unique_ptr<C2Work> &work,
391         const std::shared_ptr<C2BlockPool> &pool) {
392     // Initialize output work
393     work->result = C2_OK;
394     work->workletsProcessed = 1u;
395     work->worklets.front()->output.flags = work->input.flags;
396     if (mSignalledError || mSignalledOutputEos) {
397         work->result = C2_BAD_VALUE;
398         return;
399     }
400 
401     // Initialize encoder if not already initialized
402     if (!mStarted && C2_OK != initEncoder()) {
403         ALOGE("Failed to initialize encoder");
404         mSignalledError = true;
405         work->result = C2_CORRUPTED;
406         return;
407     }
408 
409     std::shared_ptr<C2LinearBlock> block;
410     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
411     c2_status_t err = pool->fetchLinearBlock(mOutBufferSize, usage, &block);
412     if (err != C2_OK) {
413         ALOGE("fetchLinearBlock for Output failed with status %d", err);
414         work->result = C2_NO_MEMORY;
415         return;
416     }
417 
418     C2WriteView wView = block->map().get();
419     if (wView.error()) {
420         ALOGE("write view map failed %d", wView.error());
421         work->result = wView.error();
422         return;
423     }
424 
425     uint8_t *outPtr = (uint8_t *)wView.data();
426     if (mNumInputFrames < 0) {
427         // The very first thing we want to output is the codec specific data.
428         int32_t outputSize = mOutBufferSize;
429         if (!PVGetVolHeader(mHandle, outPtr, &outputSize, 0)) {
430             ALOGE("Failed to get VOL header");
431             mSignalledError = true;
432             work->result = C2_CORRUPTED;
433             return;
434         } else {
435             ALOGV("Bytes Generated in header %d\n", outputSize);
436         }
437 
438         ++mNumInputFrames;
439         std::unique_ptr<C2StreamInitDataInfo::output> csd =
440             C2StreamInitDataInfo::output::AllocUnique(outputSize, 0u);
441         if (!csd) {
442             ALOGE("CSD allocation failed");
443             mSignalledError = true;
444             work->result = C2_NO_MEMORY;
445             return;
446         }
447         memcpy(csd->m.value, outPtr, outputSize);
448         work->worklets.front()->output.configUpdate.push_back(std::move(csd));
449     }
450 
451     std::shared_ptr<const C2GraphicView> rView;
452     std::shared_ptr<C2Buffer> inputBuffer;
453     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
454     if (!work->input.buffers.empty()) {
455         inputBuffer = work->input.buffers[0];
456         rView = std::make_shared<const C2GraphicView>(
457                 inputBuffer->data().graphicBlocks().front().map().get());
458         if (rView->error() != C2_OK) {
459             ALOGE("graphic view map err = %d", rView->error());
460             work->result = rView->error();
461             return;
462         }
463     } else {
464         fillEmptyWork(work);
465         if (eos) {
466             mSignalledOutputEos = true;
467             ALOGV("signalled EOS");
468         }
469         return;
470     }
471 
472     uint64_t inputTimeStamp = work->input.ordinal.timestamp.peekull();
473     const C2ConstGraphicBlock inBuffer = inputBuffer->data().graphicBlocks().front();
474     if (inBuffer.width() < mSize->width ||
475         inBuffer.height() < mSize->height) {
476         /* Expect width height to be configured */
477         ALOGW("unexpected Capacity Aspect %d(%d) x %d(%d)", inBuffer.width(),
478               mSize->width, inBuffer.height(), mSize->height);
479         work->result = C2_BAD_VALUE;
480         return;
481     }
482 
483     const C2PlanarLayout &layout = rView->layout();
484     uint8_t *yPlane = const_cast<uint8_t *>(rView->data()[C2PlanarLayout::PLANE_Y]);
485     uint8_t *uPlane = const_cast<uint8_t *>(rView->data()[C2PlanarLayout::PLANE_U]);
486     uint8_t *vPlane = const_cast<uint8_t *>(rView->data()[C2PlanarLayout::PLANE_V]);
487     int32_t yStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
488     int32_t uStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
489     int32_t vStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
490     uint32_t width = mSize->width;
491     uint32_t height = mSize->height;
492     // width and height are always even (as block size is 16x16)
493     CHECK_EQ((width & 1u), 0u);
494     CHECK_EQ((height & 1u), 0u);
495     size_t yPlaneSize = width * height;
496     switch (layout.type) {
497         case C2PlanarLayout::TYPE_RGB:
498             [[fallthrough]];
499         case C2PlanarLayout::TYPE_RGBA: {
500             MemoryBlock conversionBuffer = mConversionBuffers.fetch(yPlaneSize * 3 / 2);
501             mConversionBuffersInUse.emplace(conversionBuffer.data(), conversionBuffer);
502             yPlane = conversionBuffer.data();
503             uPlane = yPlane + yPlaneSize;
504             vPlane = uPlane + yPlaneSize / 4;
505             yStride = width;
506             uStride = vStride = width / 2;
507             ConvertRGBToPlanarYUV(yPlane, yStride, height, conversionBuffer.size(), *rView.get());
508             break;
509         }
510         case C2PlanarLayout::TYPE_YUV: {
511             if (!IsYUV420(*rView)) {
512                 ALOGE("input is not YUV420");
513                 work->result = C2_BAD_VALUE;
514                 break;
515             }
516 
517             if (layout.planes[layout.PLANE_Y].colInc == 1
518                     && layout.planes[layout.PLANE_U].colInc == 1
519                     && layout.planes[layout.PLANE_V].colInc == 1
520                     && uStride == vStride
521                     && yStride == 2 * vStride) {
522                 // I420 compatible - planes are already set up above
523                 break;
524             }
525 
526             // copy to I420
527             MemoryBlock conversionBuffer = mConversionBuffers.fetch(yPlaneSize * 3 / 2);
528             mConversionBuffersInUse.emplace(conversionBuffer.data(), conversionBuffer);
529             MediaImage2 img = CreateYUV420PlanarMediaImage2(width, height, width, height);
530             status_t err = ImageCopy(conversionBuffer.data(), &img, *rView);
531             if (err != OK) {
532                 ALOGE("Buffer conversion failed: %d", err);
533                 work->result = C2_BAD_VALUE;
534                 return;
535             }
536             yPlane = conversionBuffer.data();
537             uPlane = yPlane + yPlaneSize;
538             vPlane = uPlane + yPlaneSize / 4;
539             yStride = width;
540             uStride = vStride = width / 2;
541             break;
542         }
543 
544         case C2PlanarLayout::TYPE_YUVA:
545             ALOGE("YUVA plane type is not supported");
546             work->result = C2_BAD_VALUE;
547             return;
548 
549         default:
550             ALOGE("Unrecognized plane type: %d", layout.type);
551             work->result = C2_BAD_VALUE;
552             return;
553     }
554 
555     CHECK(NULL != yPlane);
556     /* Encode frames */
557     VideoEncFrameIO vin, vout;
558     memset(&vin, 0, sizeof(vin));
559     memset(&vout, 0, sizeof(vout));
560     vin.yChan = yPlane;
561     vin.uChan = uPlane;
562     vin.vChan = vPlane;
563     vin.timestamp = (inputTimeStamp + 500) / 1000;  // in ms
564     vin.height = align(height, 16);
565     vin.pitch = align(width, 16);
566 
567     uint32_t modTimeMs = 0;
568     int32_t nLayer = 0;
569     MP4HintTrack hintTrack;
570     int32_t outputSize = mOutBufferSize;
571     if (!PVEncodeVideoFrame(mHandle, &vin, &vout, &modTimeMs, outPtr, &outputSize, &nLayer) ||
572         !PVGetHintTrack(mHandle, &hintTrack)) {
573         ALOGE("Failed to encode frame or get hint track at frame %" PRId64, mNumInputFrames);
574         mSignalledError = true;
575         work->result = C2_CORRUPTED;
576         return;
577     }
578     ALOGV("outputSize filled : %d", outputSize);
579     ++mNumInputFrames;
580     CHECK(NULL == PVGetOverrunBuffer(mHandle));
581 
582     fillEmptyWork(work);
583     if (outputSize) {
584         std::shared_ptr<C2Buffer> buffer = createLinearBuffer(block, 0, outputSize);
585         work->worklets.front()->output.ordinal.timestamp = inputTimeStamp;
586         if (hintTrack.CodeType == 0) {
587             buffer->setInfo(std::make_shared<C2StreamPictureTypeMaskInfo::output>(
588                     0u /* stream id */, C2Config::SYNC_FRAME));
589         }
590         work->worklets.front()->output.buffers.push_back(buffer);
591     }
592     if (eos) {
593         mSignalledOutputEos = true;
594     }
595 
596     mConversionBuffersInUse.erase(yPlane);
597 }
598 
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)599 c2_status_t C2SoftMpeg4Enc::drain(
600         uint32_t drainMode,
601         const std::shared_ptr<C2BlockPool> &pool) {
602     (void)pool;
603     if (drainMode == NO_DRAIN) {
604         ALOGW("drain with NO_DRAIN: no-op");
605         return C2_OK;
606     }
607     if (drainMode == DRAIN_CHAIN) {
608         ALOGW("DRAIN_CHAIN not supported");
609         return C2_OMITTED;
610     }
611 
612     return C2_OK;
613 }
614 
615 class C2SoftMpeg4EncFactory : public C2ComponentFactory {
616 public:
C2SoftMpeg4EncFactory()617     C2SoftMpeg4EncFactory()
618         : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
619               GetCodec2PlatformComponentStore()->getParamReflector())) {}
620 
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)621     virtual c2_status_t createComponent(
622             c2_node_id_t id,
623             std::shared_ptr<C2Component>* const component,
624             std::function<void(C2Component*)> deleter) override {
625         *component = std::shared_ptr<C2Component>(
626             new C2SoftMpeg4Enc(
627                 COMPONENT_NAME, id,
628                 std::make_shared<C2SoftMpeg4Enc::IntfImpl>(mHelper)),
629             deleter);
630         return C2_OK;
631     }
632 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)633     virtual c2_status_t createInterface(
634             c2_node_id_t id,
635             std::shared_ptr<C2ComponentInterface>* const interface,
636             std::function<void(C2ComponentInterface*)> deleter) override {
637         *interface = std::shared_ptr<C2ComponentInterface>(
638             new SimpleInterface<C2SoftMpeg4Enc::IntfImpl>(
639                 COMPONENT_NAME, id,
640                 std::make_shared<C2SoftMpeg4Enc::IntfImpl>(mHelper)),
641             deleter);
642         return C2_OK;
643     }
644 
645     virtual ~C2SoftMpeg4EncFactory() override = default;
646 
647 private:
648     std::shared_ptr<C2ReflectorHelper> mHelper;
649 };
650 
651 }  // namespace android
652 
CreateCodec2Factory()653 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
654     ALOGV("in %s", __func__);
655     return new ::android::C2SoftMpeg4EncFactory();
656 }
657 
DestroyCodec2Factory(::C2ComponentFactory * factory)658 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
659     ALOGV("in %s", __func__);
660     delete factory;
661 }
662