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