1 /*
2  * Copyright (C) 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 "C2SoftMpeg4Dec"
20 #else
21   #define LOG_TAG "C2SoftH263Dec"
22 #endif
23 #include <log/log.h>
24 
25 #include <media/stagefright/foundation/AUtils.h>
26 #include <media/stagefright/foundation/MediaDefs.h>
27 
28 #include <C2Debug.h>
29 #include <C2PlatformSupport.h>
30 #include <SimpleC2Interface.h>
31 
32 #include "C2SoftMpeg4Dec.h"
33 #include "mp4dec_api.h"
34 
35 namespace android {
36 constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
37 #ifdef MPEG4
38 constexpr char COMPONENT_NAME[] = "c2.android.mpeg4.decoder";
39 #else
40 constexpr char COMPONENT_NAME[] = "c2.android.h263.decoder";
41 #endif
42 
43 class C2SoftMpeg4Dec::IntfImpl : public SimpleInterface<void>::BaseParams {
44 public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)45     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
46         : SimpleInterface<void>::BaseParams(
47                 helper,
48                 COMPONENT_NAME,
49                 C2Component::KIND_DECODER,
50                 C2Component::DOMAIN_VIDEO,
51 #ifdef MPEG4
52                 MEDIA_MIMETYPE_VIDEO_MPEG4
53 #else
54                 MEDIA_MIMETYPE_VIDEO_H263
55 #endif
56                 ) {
57         noPrivateBuffers(); // TODO: account for our buffers here
58         noInputReferences();
59         noOutputReferences();
60         noInputLatency();
61         noTimeStretch();
62 
63         // TODO: Proper support for reorder depth.
64         addParameter(
65                 DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
66                 .withConstValue(new C2PortActualDelayTuning::output(1u))
67                 .build());
68 
69         addParameter(
70                 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
71                 .withConstValue(new C2ComponentAttributesSetting(C2Component::ATTRIB_IS_TEMPORAL))
72                 .build());
73 
74         addParameter(
75                 DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
76                 .withDefault(new C2StreamPictureSizeInfo::output(0u, 176, 144))
77                 .withFields({
78 #ifdef MPEG4
79                     C2F(mSize, width).inRange(2, 1920, 2),
80                     C2F(mSize, height).inRange(2, 1088, 2),
81 #else
82                     C2F(mSize, width).inRange(2, 352, 2),
83                     C2F(mSize, height).inRange(2, 288, 2),
84 #endif
85                 })
86                 .withSetter(SizeSetter)
87                 .build());
88 
89 #ifdef MPEG4
90         addParameter(
91                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
92                 .withDefault(new C2StreamProfileLevelInfo::input(0u,
93                         C2Config::PROFILE_MP4V_SIMPLE, C2Config::LEVEL_MP4V_3))
94                 .withFields({
95                     C2F(mProfileLevel, profile).equalTo(
96                             C2Config::PROFILE_MP4V_SIMPLE),
97                     C2F(mProfileLevel, level).oneOf({
98                             C2Config::LEVEL_MP4V_0,
99                             C2Config::LEVEL_MP4V_0B,
100                             C2Config::LEVEL_MP4V_1,
101                             C2Config::LEVEL_MP4V_2,
102                             C2Config::LEVEL_MP4V_3,
103                             C2Config::LEVEL_MP4V_3B,
104                             C2Config::LEVEL_MP4V_4,
105                             C2Config::LEVEL_MP4V_4A,
106                             C2Config::LEVEL_MP4V_5,
107                             C2Config::LEVEL_MP4V_6})
108                 })
109                 .withSetter(ProfileLevelSetter, mSize)
110                 .build());
111 #else
112         addParameter(
113                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
114                 .withDefault(new C2StreamProfileLevelInfo::input(0u,
115                         C2Config::PROFILE_H263_BASELINE, C2Config::LEVEL_H263_30))
116                 .withFields({
117                     C2F(mProfileLevel, profile).oneOf({
118                             C2Config::PROFILE_H263_BASELINE,
119                             C2Config::PROFILE_H263_ISWV2}),
120                     C2F(mProfileLevel, level).oneOf({
121                             C2Config::LEVEL_H263_10,
122                             C2Config::LEVEL_H263_20,
123                             C2Config::LEVEL_H263_30,
124                             C2Config::LEVEL_H263_40,
125                             C2Config::LEVEL_H263_45})
126                 })
127                 .withSetter(ProfileLevelSetter, mSize)
128                 .build());
129 #endif
130 
131         addParameter(
132                 DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
133 #ifdef MPEG4
134                 .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 1920, 1088))
135 #else
136                 .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 352, 288))
137 #endif
138                 .withFields({
139 #ifdef MPEG4
140                     C2F(mSize, width).inRange(2, 1920, 2),
141                     C2F(mSize, height).inRange(2, 1088, 2),
142 #else
143                     C2F(mSize, width).inRange(2, 352, 2),
144                     C2F(mSize, height).inRange(2, 288, 2),
145 #endif
146                 })
147                 .withSetter(MaxPictureSizeSetter, mSize)
148                 .build());
149 
150         addParameter(
151                 DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
152                 .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
153                 .withFields({
154                     C2F(mMaxInputSize, value).any(),
155                 })
156                 .calculatedAs(MaxInputSizeSetter, mMaxSize)
157                 .build());
158 
159         C2ChromaOffsetStruct locations[1] = { C2ChromaOffsetStruct::ITU_YUV_420_0() };
160         std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
161             C2StreamColorInfo::output::AllocShared(
162                     1u, 0u, 8u /* bitDepth */, C2Color::YUV_420);
163         memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
164 
165         defaultColorInfo =
166             C2StreamColorInfo::output::AllocShared(
167                     { C2ChromaOffsetStruct::ITU_YUV_420_0() },
168                     0u, 8u /* bitDepth */, C2Color::YUV_420);
169         helper->addStructDescriptors<C2ChromaOffsetStruct>();
170 
171         addParameter(
172                 DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
173                 .withConstValue(defaultColorInfo)
174                 .build());
175 
176         // TODO: support more formats?
177         addParameter(
178                 DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
179                 .withConstValue(new C2StreamPixelFormatInfo::output(
180                                      0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
181                 .build());
182     }
183 
SizeSetter(bool mayBlock,const C2P<C2StreamPictureSizeInfo::output> & oldMe,C2P<C2StreamPictureSizeInfo::output> & me)184     static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output> &oldMe,
185                           C2P<C2StreamPictureSizeInfo::output> &me) {
186         (void)mayBlock;
187         C2R res = C2R::Ok();
188         if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
189             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
190             me.set().width = oldMe.v.width;
191         }
192         if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
193             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
194             me.set().height = oldMe.v.height;
195         }
196         return res;
197     }
198 
MaxPictureSizeSetter(bool mayBlock,C2P<C2StreamMaxPictureSizeTuning::output> & me,const C2P<C2StreamPictureSizeInfo::output> & size)199     static C2R MaxPictureSizeSetter(bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output> &me,
200                                     const C2P<C2StreamPictureSizeInfo::output> &size) {
201         (void)mayBlock;
202         // TODO: get max width/height from the size's field helpers vs. hardcoding
203 #ifdef MPEG4
204         me.set().width = c2_min(c2_max(me.v.width, size.v.width), 1920u);
205         me.set().height = c2_min(c2_max(me.v.height, size.v.height), 1088u);
206 #else
207         me.set().width = c2_min(c2_max(me.v.width, size.v.width), 352u);
208         me.set().height = c2_min(c2_max(me.v.height, size.v.height), 288u);
209 #endif
210         return C2R::Ok();
211     }
212 
MaxInputSizeSetter(bool mayBlock,C2P<C2StreamMaxBufferSizeInfo::input> & me,const C2P<C2StreamMaxPictureSizeTuning::output> & maxSize)213     static C2R MaxInputSizeSetter(bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
214                                   const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
215         (void)mayBlock;
216         // assume compression ratio of 1
217         me.set().value = c2_max((((maxSize.v.width + 15) / 16)
218                 * ((maxSize.v.height + 15) / 16) * 384), kMinInputBufferSize);
219         return C2R::Ok();
220     }
221 
ProfileLevelSetter(bool mayBlock,C2P<C2StreamProfileLevelInfo::input> & me,const C2P<C2StreamPictureSizeInfo::output> & size)222     static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
223                                   const C2P<C2StreamPictureSizeInfo::output> &size) {
224         (void)mayBlock;
225         (void)size;
226         (void)me;  // TODO: validate
227         return C2R::Ok();
228     }
229 
getMaxWidth() const230     uint32_t getMaxWidth() const { return mMaxSize->width; }
getMaxHeight() const231     uint32_t getMaxHeight() const { return mMaxSize->height; }
232 
233 private:
234     std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
235     std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
236     std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
237     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
238     std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
239     std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
240 };
241 
C2SoftMpeg4Dec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)242 C2SoftMpeg4Dec::C2SoftMpeg4Dec(
243         const char *name,
244         c2_node_id_t id,
245         const std::shared_ptr<IntfImpl> &intfImpl)
246     : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
247       mIntf(intfImpl),
248       mDecHandle(nullptr),
249       mOutputBuffer{},
250       mInitialized(false) {
251 }
252 
~C2SoftMpeg4Dec()253 C2SoftMpeg4Dec::~C2SoftMpeg4Dec() {
254     onRelease();
255 }
256 
onInit()257 c2_status_t C2SoftMpeg4Dec::onInit() {
258     status_t err = initDecoder();
259     return err == OK ? C2_OK : C2_CORRUPTED;
260 }
261 
onStop()262 c2_status_t C2SoftMpeg4Dec::onStop() {
263     if (mInitialized) {
264         if (mDecHandle) {
265             PVCleanUpVideoDecoder(mDecHandle);
266         }
267         mInitialized = false;
268     }
269     for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
270         if (mOutputBuffer[i]) {
271             free(mOutputBuffer[i]);
272             mOutputBuffer[i] = nullptr;
273         }
274     }
275     mNumSamplesOutput = 0;
276     mFramesConfigured = false;
277     mSignalledOutputEos = false;
278     mSignalledError = false;
279 
280     return C2_OK;
281 }
282 
onReset()283 void C2SoftMpeg4Dec::onReset() {
284     (void)onStop();
285     (void)onInit();
286 }
287 
onRelease()288 void C2SoftMpeg4Dec::onRelease() {
289     if (mInitialized) {
290         if (mDecHandle) {
291             PVCleanUpVideoDecoder(mDecHandle);
292             delete mDecHandle;
293             mDecHandle = nullptr;
294         }
295         mInitialized = false;
296     }
297     if (mOutBlock) {
298         mOutBlock.reset();
299     }
300     for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
301         if (mOutputBuffer[i]) {
302             free(mOutputBuffer[i]);
303             mOutputBuffer[i] = nullptr;
304         }
305     }
306 }
307 
onFlush_sm()308 c2_status_t C2SoftMpeg4Dec::onFlush_sm() {
309     if (mInitialized) {
310         if (PV_TRUE != PVResetVideoDecoder(mDecHandle)) {
311             return C2_CORRUPTED;
312         }
313     }
314     mSignalledOutputEos = false;
315     mSignalledError = false;
316     return C2_OK;
317 }
318 
initDecoder()319 status_t C2SoftMpeg4Dec::initDecoder() {
320 #ifdef MPEG4
321     mIsMpeg4 = true;
322 #else
323     mIsMpeg4 = false;
324 #endif
325     if (!mDecHandle) {
326         mDecHandle = new tagvideoDecControls;
327     }
328     if (!mDecHandle) {
329         ALOGE("mDecHandle is null");
330         return NO_MEMORY;
331     }
332     memset(mDecHandle, 0, sizeof(tagvideoDecControls));
333 
334     /* TODO: bring these values to 352 and 288. It cannot be done as of now
335      * because, h263 doesn't seem to allow port reconfiguration. In OMX, the
336      * problem of larger width and height than default width and height is
337      * overcome by adaptivePlayBack() api call. This call gets width and height
338      * information from extractor. Such a thing is not possible here.
339      * So we are configuring to larger values.*/
340     mWidth = 1408;
341     mHeight = 1152;
342     mNumSamplesOutput = 0;
343     mInitialized = false;
344     mFramesConfigured = false;
345     mSignalledOutputEos = false;
346     mSignalledError = false;
347 
348     return OK;
349 }
350 
fillEmptyWork(const std::unique_ptr<C2Work> & work)351 void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
352     uint32_t flags = 0;
353     if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
354         flags |= C2FrameData::FLAG_END_OF_STREAM;
355         ALOGV("signalling eos");
356     }
357     work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
358     work->worklets.front()->output.buffers.clear();
359     work->worklets.front()->output.ordinal = work->input.ordinal;
360     work->workletsProcessed = 1u;
361 }
362 
finishWork(uint64_t index,const std::unique_ptr<C2Work> & work)363 void C2SoftMpeg4Dec::finishWork(uint64_t index, const std::unique_ptr<C2Work> &work) {
364     std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(std::move(mOutBlock),
365                                                            C2Rect(mWidth, mHeight));
366     mOutBlock = nullptr;
367     auto fillWork = [buffer, index](const std::unique_ptr<C2Work> &work) {
368         uint32_t flags = 0;
369         if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
370                 (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
371             flags |= C2FrameData::FLAG_END_OF_STREAM;
372             ALOGV("signalling eos");
373         }
374         work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
375         work->worklets.front()->output.buffers.clear();
376         work->worklets.front()->output.buffers.push_back(buffer);
377         work->worklets.front()->output.ordinal = work->input.ordinal;
378         work->workletsProcessed = 1u;
379     };
380     if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
381         fillWork(work);
382     } else {
383         finish(index, fillWork);
384     }
385 }
386 
ensureDecoderState(const std::shared_ptr<C2BlockPool> & pool)387 c2_status_t C2SoftMpeg4Dec::ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool) {
388     if (!mDecHandle) {
389         ALOGE("not supposed to be here, invalid decoder context");
390         return C2_CORRUPTED;
391     }
392 
393     mOutputBufferSize = align(mIntf->getMaxWidth(), 16) * align(mIntf->getMaxHeight(), 16) * 3 / 2;
394     for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
395         if (!mOutputBuffer[i]) {
396             mOutputBuffer[i] = (uint8_t *)malloc(mOutputBufferSize);
397             if (!mOutputBuffer[i]) {
398                 return C2_NO_MEMORY;
399             }
400         }
401     }
402     if (mOutBlock &&
403             (mOutBlock->width() != align(mWidth, 16) || mOutBlock->height() != mHeight)) {
404         mOutBlock.reset();
405     }
406     if (!mOutBlock) {
407         uint32_t format = HAL_PIXEL_FORMAT_YV12;
408         C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
409         c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16), mHeight, format, usage, &mOutBlock);
410         if (err != C2_OK) {
411             ALOGE("fetchGraphicBlock for Output failed with status %d", err);
412             return err;
413         }
414         ALOGV("provided (%dx%d) required (%dx%d)",
415               mOutBlock->width(), mOutBlock->height(), mWidth, mHeight);
416     }
417     return C2_OK;
418 }
419 
handleResChange(const std::unique_ptr<C2Work> & work)420 bool C2SoftMpeg4Dec::handleResChange(const std::unique_ptr<C2Work> &work) {
421     uint32_t disp_width, disp_height;
422     PVGetVideoDimensions(mDecHandle, (int32 *)&disp_width, (int32 *)&disp_height);
423 
424     uint32_t buf_width, buf_height;
425     PVGetBufferDimensions(mDecHandle, (int32 *)&buf_width, (int32 *)&buf_height);
426 
427     CHECK_LE(disp_width, buf_width);
428     CHECK_LE(disp_height, buf_height);
429 
430     ALOGV("display size (%dx%d), buffer size (%dx%d)",
431            disp_width, disp_height, buf_width, buf_height);
432 
433     bool resChanged = false;
434     if (disp_width != mWidth || disp_height != mHeight) {
435         mWidth = disp_width;
436         mHeight = disp_height;
437         resChanged = true;
438         for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
439             if (mOutputBuffer[i]) {
440                 free(mOutputBuffer[i]);
441                 mOutputBuffer[i] = nullptr;
442             }
443         }
444 
445         if (!mIsMpeg4) {
446             PVCleanUpVideoDecoder(mDecHandle);
447 
448             uint8_t *vol_data[1]{};
449             int32_t vol_size = 0;
450 
451             if (!PVInitVideoDecoder(
452                     mDecHandle, vol_data, &vol_size, 1, mIntf->getMaxWidth(), mIntf->getMaxHeight(), H263_MODE)) {
453                 ALOGE("Error in PVInitVideoDecoder H263_MODE while resChanged was set to true");
454                 mSignalledError = true;
455                 work->result = C2_CORRUPTED;
456                 return true;
457             }
458         }
459         mFramesConfigured = false;
460     }
461     return resChanged;
462 }
463 
464 /* TODO: can remove temporary copy after library supports writing to display
465  * buffer Y, U and V plane pointers using stride info. */
copyOutputBufferToYuvPlanarFrame(uint8_t * dst,uint8_t * src,size_t dstYStride,size_t dstUVStride,size_t srcYStride,uint32_t width,uint32_t height)466 static void copyOutputBufferToYuvPlanarFrame(
467         uint8_t *dst, uint8_t *src,
468         size_t dstYStride, size_t dstUVStride,
469         size_t srcYStride, uint32_t width,
470         uint32_t height) {
471     size_t srcUVStride = srcYStride / 2;
472     uint8_t *srcStart = src;
473     uint8_t *dstStart = dst;
474     size_t vStride = align(height, 16);
475     for (size_t i = 0; i < height; ++i) {
476          memcpy(dst, src, width);
477          src += srcYStride;
478          dst += dstYStride;
479     }
480     /* U buffer */
481     src = srcStart + vStride * srcYStride;
482     dst = dstStart + (dstYStride * height) + (dstUVStride * height / 2);
483     for (size_t i = 0; i < height / 2; ++i) {
484          memcpy(dst, src, width / 2);
485          src += srcUVStride;
486          dst += dstUVStride;
487     }
488     /* V buffer */
489     src = srcStart + vStride * srcYStride * 5 / 4;
490     dst = dstStart + (dstYStride * height);
491     for (size_t i = 0; i < height / 2; ++i) {
492          memcpy(dst, src, width / 2);
493          src += srcUVStride;
494          dst += dstUVStride;
495     }
496 }
497 
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)498 void C2SoftMpeg4Dec::process(
499         const std::unique_ptr<C2Work> &work,
500         const std::shared_ptr<C2BlockPool> &pool) {
501     // Initialize output work
502     work->result = C2_OK;
503     work->workletsProcessed = 1u;
504     work->worklets.front()->output.configUpdate.clear();
505     work->worklets.front()->output.flags = work->input.flags;
506 
507     if (mSignalledError || mSignalledOutputEos) {
508         work->result = C2_BAD_VALUE;
509         return;
510     }
511 
512     size_t inOffset = 0u;
513     size_t inSize = 0u;
514     uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF;
515     C2ReadView rView = mDummyReadView;
516     if (!work->input.buffers.empty()) {
517         rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
518         inSize = rView.capacity();
519         if (inSize && rView.error()) {
520             ALOGE("read view map failed %d", rView.error());
521             work->result = C2_CORRUPTED;
522             return;
523         }
524     }
525     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
526           inSize, (int)work->input.ordinal.timestamp.peeku(),
527           (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
528 
529     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
530     if (inSize == 0) {
531         fillEmptyWork(work);
532         if (eos) {
533             mSignalledOutputEos = true;
534         }
535         return;
536     }
537 
538     uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
539     uint32_t *start_code = (uint32_t *)bitstream;
540     bool volHeader = *start_code == 0xB0010000;
541     if (volHeader) {
542         PVCleanUpVideoDecoder(mDecHandle);
543         mInitialized = false;
544     }
545 
546     if (!mInitialized) {
547         uint8_t *vol_data[1]{};
548         int32_t vol_size = 0;
549 
550         bool codecConfig = (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0;
551         if (codecConfig || volHeader) {
552             vol_data[0] = bitstream;
553             vol_size = inSize;
554         }
555         MP4DecodingMode mode = (mIsMpeg4) ? MPEG4_MODE : H263_MODE;
556         if (!PVInitVideoDecoder(
557                 mDecHandle, vol_data, &vol_size, 1,
558                 mIntf->getMaxWidth(), mIntf->getMaxHeight(), mode)) {
559             ALOGE("PVInitVideoDecoder failed. Unsupported content?");
560             mSignalledError = true;
561             work->result = C2_CORRUPTED;
562             return;
563         }
564         mInitialized = true;
565         MP4DecodingMode actualMode = PVGetDecBitstreamMode(mDecHandle);
566         if (mode != actualMode) {
567             ALOGE("Decoded mode not same as actual mode of the decoder");
568             mSignalledError = true;
569             work->result = C2_CORRUPTED;
570             return;
571         }
572 
573         PVSetPostProcType(mDecHandle, 0);
574         if (handleResChange(work)) {
575             ALOGI("Setting width and height");
576             C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
577             std::vector<std::unique_ptr<C2SettingResult>> failures;
578             c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
579             if (err == OK) {
580                 work->worklets.front()->output.configUpdate.push_back(
581                     C2Param::Copy(size));
582             } else {
583                 ALOGE("Config update size failed");
584                 mSignalledError = true;
585                 work->result = C2_CORRUPTED;
586                 return;
587             }
588         }
589         if (codecConfig) {
590             fillEmptyWork(work);
591             return;
592         }
593     }
594 
595     size_t inPos = 0;
596     while (inPos < inSize) {
597         c2_status_t err = ensureDecoderState(pool);
598         if (C2_OK != err) {
599             mSignalledError = true;
600             work->result = err;
601             return;
602         }
603         C2GraphicView wView = mOutBlock->map().get();
604         if (wView.error()) {
605             ALOGE("graphic view map failed %d", wView.error());
606             work->result = C2_CORRUPTED;
607             return;
608         }
609 
610         uint32_t yFrameSize = sizeof(uint8) * mDecHandle->size;
611         if (mOutputBufferSize < yFrameSize * 3 / 2){
612             ALOGE("Too small output buffer: %zu bytes", mOutputBufferSize);
613             mSignalledError = true;
614             work->result = C2_NO_MEMORY;
615             return;
616         }
617 
618         if (!mFramesConfigured) {
619             PVSetReferenceYUV(mDecHandle,mOutputBuffer[1]);
620             mFramesConfigured = true;
621         }
622 
623         // Need to check if header contains new info, e.g., width/height, etc.
624         VopHeaderInfo header_info;
625         uint32_t useExtTimestamp = (inPos == 0);
626         int32_t tmpInSize = (int32_t)inSize;
627         uint8_t *bitstreamTmp = bitstream;
628         uint32_t timestamp = workIndex;
629         if (PVDecodeVopHeader(
630                     mDecHandle, &bitstreamTmp, &timestamp, &tmpInSize,
631                     &header_info, &useExtTimestamp,
632                     mOutputBuffer[mNumSamplesOutput & 1]) != PV_TRUE) {
633             ALOGE("failed to decode vop header.");
634             mSignalledError = true;
635             work->result = C2_CORRUPTED;
636             return;
637         }
638 
639         // H263 doesn't have VOL header, the frame size information is in short header, i.e. the
640         // decoder may detect size change after PVDecodeVopHeader.
641         bool resChange = handleResChange(work);
642         if (mIsMpeg4 && resChange) {
643             mSignalledError = true;
644             work->result = C2_CORRUPTED;
645             return;
646         } else if (resChange) {
647             ALOGI("Setting width and height");
648             C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
649             std::vector<std::unique_ptr<C2SettingResult>> failures;
650             c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
651             if (err == OK) {
652                 work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(size));
653             } else {
654                 ALOGE("Config update size failed");
655                 mSignalledError = true;
656                 work->result = C2_CORRUPTED;
657                 return;
658             }
659             continue;
660         }
661 
662         if (PVDecodeVopBody(mDecHandle, &tmpInSize) != PV_TRUE) {
663             ALOGE("failed to decode video frame.");
664             mSignalledError = true;
665             work->result = C2_CORRUPTED;
666             return;
667         }
668         if (handleResChange(work)) {
669             mSignalledError = true;
670             work->result = C2_CORRUPTED;
671             return;
672         }
673 
674         uint8_t *outputBufferY = wView.data()[C2PlanarLayout::PLANE_Y];
675         C2PlanarLayout layout = wView.layout();
676         size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
677         size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
678         (void)copyOutputBufferToYuvPlanarFrame(
679                 outputBufferY,
680                 mOutputBuffer[mNumSamplesOutput & 1],
681                 dstYStride, dstUVStride,
682                 align(mWidth, 16), mWidth, mHeight);
683 
684         inPos += inSize - (size_t)tmpInSize;
685         finishWork(workIndex, work);
686         ++mNumSamplesOutput;
687         if (inSize - inPos != 0) {
688             ALOGD("decoded frame, ignoring further trailing bytes %d",
689                   (int)inSize - (int)inPos);
690             break;
691         }
692     }
693 }
694 
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)695 c2_status_t C2SoftMpeg4Dec::drain(
696         uint32_t drainMode,
697         const std::shared_ptr<C2BlockPool> &pool) {
698     (void)pool;
699     if (drainMode == NO_DRAIN) {
700         ALOGW("drain with NO_DRAIN: no-op");
701         return C2_OK;
702     }
703     if (drainMode == DRAIN_CHAIN) {
704         ALOGW("DRAIN_CHAIN not supported");
705         return C2_OMITTED;
706     }
707     return C2_OK;
708 }
709 
710 class C2SoftMpeg4DecFactory : public C2ComponentFactory {
711 public:
C2SoftMpeg4DecFactory()712     C2SoftMpeg4DecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
713         GetCodec2PlatformComponentStore()->getParamReflector())) {
714     }
715 
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)716     virtual c2_status_t createComponent(
717             c2_node_id_t id,
718             std::shared_ptr<C2Component>* const component,
719             std::function<void(C2Component*)> deleter) override {
720         *component = std::shared_ptr<C2Component>(
721                 new C2SoftMpeg4Dec(COMPONENT_NAME,
722                                    id,
723                                    std::make_shared<C2SoftMpeg4Dec::IntfImpl>(mHelper)),
724                 deleter);
725         return C2_OK;
726     }
727 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)728     virtual c2_status_t createInterface(
729             c2_node_id_t id,
730             std::shared_ptr<C2ComponentInterface>* const interface,
731             std::function<void(C2ComponentInterface*)> deleter) override {
732         *interface = std::shared_ptr<C2ComponentInterface>(
733                 new SimpleInterface<C2SoftMpeg4Dec::IntfImpl>(
734                         COMPONENT_NAME, id, std::make_shared<C2SoftMpeg4Dec::IntfImpl>(mHelper)),
735                 deleter);
736         return C2_OK;
737     }
738 
739     virtual ~C2SoftMpeg4DecFactory() override = default;
740 
741 private:
742     std::shared_ptr<C2ReflectorHelper> mHelper;
743 };
744 
745 }  // namespace android
746 
CreateCodec2Factory()747 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
748     ALOGV("in %s", __func__);
749     return new ::android::C2SoftMpeg4DecFactory();
750 }
751 
DestroyCodec2Factory(::C2ComponentFactory * factory)752 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
753     ALOGV("in %s", __func__);
754     delete factory;
755 }
756