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