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#define LOG_TAG "C2SoftMpeg2Dec"
19#include <log/log.h>
20
21#include <media/stagefright/foundation/MediaDefs.h>
22
23#include <C2Debug.h>
24#include <C2PlatformSupport.h>
25#include <SimpleC2Interface.h>
26
27#include "C2SoftMpeg2Dec.h"
28#include "impeg2d.h"
29
30namespace android {
31
32constexpr char COMPONENT_NAME[] = "c2.android.mpeg2.decoder";
33
34class C2SoftMpeg2Dec::IntfImpl : public SimpleInterface<void>::BaseParams {
35public:
36    explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
37        : SimpleInterface<void>::BaseParams(
38                helper,
39                COMPONENT_NAME,
40                C2Component::KIND_DECODER,
41                C2Component::DOMAIN_VIDEO,
42                MEDIA_MIMETYPE_VIDEO_MPEG2) {
43        noPrivateBuffers(); // TODO: account for our buffers here
44        noInputReferences();
45        noOutputReferences();
46        noInputLatency();
47        noTimeStretch();
48
49        // TODO: output latency and reordering
50
51        addParameter(
52                DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
53                .withConstValue(new C2ComponentAttributesSetting(C2Component::ATTRIB_IS_TEMPORAL))
54                .build());
55
56        addParameter(
57                DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
58                .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
59                .withFields({
60                    C2F(mSize, width).inRange(16, 1920, 4),
61                    C2F(mSize, height).inRange(16, 1088, 4),
62                })
63                .withSetter(SizeSetter)
64                .build());
65
66        addParameter(
67                DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
68                .withDefault(new C2StreamProfileLevelInfo::input(0u,
69                        C2Config::PROFILE_MP2V_SIMPLE, C2Config::LEVEL_MP2V_HIGH))
70                .withFields({
71                    C2F(mProfileLevel, profile).oneOf({
72                            C2Config::PROFILE_MP2V_SIMPLE,
73                            C2Config::PROFILE_MP2V_MAIN}),
74                    C2F(mProfileLevel, level).oneOf({
75                            C2Config::LEVEL_MP2V_LOW,
76                            C2Config::LEVEL_MP2V_MAIN,
77                            C2Config::LEVEL_MP2V_HIGH_1440,
78                            C2Config::LEVEL_MP2V_HIGH})
79                })
80                .withSetter(ProfileLevelSetter, mSize)
81                .build());
82
83        C2ChromaOffsetStruct locations[1] = { C2ChromaOffsetStruct::ITU_YUV_420_0() };
84        std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
85            C2StreamColorInfo::output::AllocShared(
86                    1u, 0u, 8u /* bitDepth */, C2Color::YUV_420);
87        memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
88
89        defaultColorInfo =
90            C2StreamColorInfo::output::AllocShared(
91                    { C2ChromaOffsetStruct::ITU_YUV_420_0() },
92                    0u, 8u /* bitDepth */, C2Color::YUV_420);
93        helper->addStructDescriptors<C2ChromaOffsetStruct>();
94
95        addParameter(
96                DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
97                .withConstValue(defaultColorInfo)
98                .build());
99
100        addParameter(
101                DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS)
102                .withDefault(new C2StreamColorAspectsTuning::input(
103                        0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
104                        C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
105                .withFields({
106                    C2F(mDefaultColorAspects, range).inRange(
107                                C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
108                    C2F(mDefaultColorAspects, primaries).inRange(
109                                C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
110                    C2F(mDefaultColorAspects, transfer).inRange(
111                                C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER),
112                    C2F(mDefaultColorAspects, matrix).inRange(
113                                C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)
114                })
115                .withSetter(DefaultColorAspectsSetter)
116                .build());
117
118        addParameter(
119                DefineParam(mCodedColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS)
120                .withDefault(new C2StreamColorAspectsInfo::input(
121                        0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
122                        C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
123                .withFields({
124                    C2F(mCodedColorAspects, range).inRange(
125                                C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
126                    C2F(mCodedColorAspects, primaries).inRange(
127                                C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
128                    C2F(mCodedColorAspects, transfer).inRange(
129                                C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER),
130                    C2F(mCodedColorAspects, matrix).inRange(
131                                C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)
132                })
133                .withSetter(CodedColorAspectsSetter)
134                .build());
135
136        addParameter(
137                DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS)
138                .withDefault(new C2StreamColorAspectsInfo::output(
139                        0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
140                        C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
141                .withFields({
142                    C2F(mColorAspects, range).inRange(
143                                C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
144                    C2F(mColorAspects, primaries).inRange(
145                                C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
146                    C2F(mColorAspects, transfer).inRange(
147                                C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER),
148                    C2F(mColorAspects, matrix).inRange(
149                                C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)
150                })
151                .withSetter(ColorAspectsSetter, mDefaultColorAspects, mCodedColorAspects)
152                .build());
153
154        // TODO: support more formats?
155        addParameter(
156                DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
157                .withConstValue(new C2StreamPixelFormatInfo::output(
158                                     0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
159                .build());
160    }
161
162    static C2R SizeSetter(bool mayBlock, const C2P<C2VideoSizeStreamInfo::output> &oldMe,
163                          C2P<C2VideoSizeStreamInfo::output> &me) {
164        (void)mayBlock;
165        C2R res = C2R::Ok();
166        if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
167            res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
168            me.set().width = oldMe.v.width;
169        }
170        if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
171            res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
172            me.set().height = oldMe.v.height;
173        }
174        return res;
175    }
176
177    static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
178                                  const C2P<C2StreamPictureSizeInfo::output> &size) {
179        (void)mayBlock;
180        (void)size;
181        (void)me;  // TODO: validate
182        return C2R::Ok();
183    }
184
185    static C2R DefaultColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsTuning::input> &me) {
186        (void)mayBlock;
187        (void)me;
188        // take all values
189        return C2R::Ok();
190    }
191
192    static C2R CodedColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::input> &me) {
193        (void)mayBlock;
194        (void)me;
195        // take all values
196        return C2R::Ok();
197    }
198
199    static C2R ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output> &me,
200                                  const C2P<C2StreamColorAspectsTuning::input> &def,
201                                  const C2P<C2StreamColorAspectsInfo::input> &coded) {
202        (void)mayBlock;
203        // take default values for all unspecified fields, and coded values for specified ones
204        me.set().range = coded.v.range == RANGE_UNSPECIFIED ? def.v.range : coded.v.range;
205        me.set().primaries = coded.v.primaries == PRIMARIES_UNSPECIFIED ? def.v.primaries : coded.v.primaries;
206        me.set().transfer = coded.v.transfer == TRANSFER_UNSPECIFIED ? def.v.transfer : coded.v.transfer;
207        me.set().matrix = coded.v.matrix == MATRIX_UNSPECIFIED ? def.v.matrix : coded.v.matrix;
208        // TODO: validate
209        return C2R::Ok();
210    }
211
212private:
213    std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
214    std::shared_ptr<C2VideoSizeStreamInfo::output> mSize;
215    std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
216    std::shared_ptr<C2StreamColorAspectsTuning::input> mDefaultColorAspects;
217    std::shared_ptr<C2StreamColorAspectsInfo::input> mCodedColorAspects;
218    std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects;
219    std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
220};
221
222static size_t getCpuCoreCount() {
223    long cpuCoreCount = 1;
224#if defined(_SC_NPROCESSORS_ONLN)
225    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
226#else
227    // _SC_NPROC_ONLN must be defined...
228    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
229#endif
230    CHECK(cpuCoreCount >= 1);
231    ALOGV("Number of CPU cores: %ld", cpuCoreCount);
232    return (size_t)cpuCoreCount;
233}
234
235static void *ivd_aligned_malloc(WORD32 alignment, WORD32 size) {
236    return memalign(alignment, size);
237}
238
239static void ivd_aligned_free(void *mem) {
240    free(mem);
241}
242
243C2SoftMpeg2Dec::C2SoftMpeg2Dec(
244        const char *name,
245        c2_node_id_t id,
246        const std::shared_ptr<IntfImpl> &intfImpl)
247    : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
248        mIntf(intfImpl),
249        mDecHandle(nullptr),
250        mMemRecords(nullptr),
251        mOutBufferDrain(nullptr),
252        mIvColorformat(IV_YUV_420P),
253        mWidth(320),
254        mHeight(240) {
255    // If input dump is enabled, then open create an empty file
256    GENERATE_FILE_NAMES();
257    CREATE_DUMP_FILE(mInFile);
258}
259
260C2SoftMpeg2Dec::~C2SoftMpeg2Dec() {
261    onRelease();
262}
263
264c2_status_t C2SoftMpeg2Dec::onInit() {
265    status_t err = initDecoder();
266    return err == OK ? C2_OK : C2_CORRUPTED;
267}
268
269c2_status_t C2SoftMpeg2Dec::onStop() {
270    if (OK != resetDecoder()) return C2_CORRUPTED;
271    resetPlugin();
272    return C2_OK;
273}
274
275void C2SoftMpeg2Dec::onReset() {
276    (void) onStop();
277}
278
279void C2SoftMpeg2Dec::onRelease() {
280    (void) deleteDecoder();
281    if (mOutBufferDrain) {
282        ivd_aligned_free(mOutBufferDrain);
283        mOutBufferDrain = nullptr;
284    }
285    if (mOutBlock) {
286        mOutBlock.reset();
287    }
288    if (mMemRecords) {
289        ivd_aligned_free(mMemRecords);
290        mMemRecords = nullptr;
291    }
292}
293
294c2_status_t C2SoftMpeg2Dec::onFlush_sm() {
295    if (OK != setFlushMode()) return C2_CORRUPTED;
296
297    uint32_t displayStride = mStride;
298    uint32_t displayHeight = mHeight;
299    uint32_t bufferSize = displayStride * displayHeight * 3 / 2;
300    mOutBufferDrain = (uint8_t *)ivd_aligned_malloc(128, bufferSize);
301    if (!mOutBufferDrain) {
302        ALOGE("could not allocate tmp output buffer (for flush) of size %u ", bufferSize);
303        return C2_NO_MEMORY;
304    }
305
306    while (true) {
307        ivd_video_decode_ip_t s_decode_ip;
308        ivd_video_decode_op_t s_decode_op;
309
310        setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, nullptr, 0, 0, 0);
311        (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
312        if (0 == s_decode_op.u4_output_present) {
313            resetPlugin();
314            break;
315        }
316    }
317
318    ivd_aligned_free(mOutBufferDrain);
319    mOutBufferDrain = nullptr;
320
321    return C2_OK;
322}
323
324status_t C2SoftMpeg2Dec::getNumMemRecords() {
325    iv_num_mem_rec_ip_t s_num_mem_rec_ip;
326    iv_num_mem_rec_op_t s_num_mem_rec_op;
327
328    s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip);
329    s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
330    s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op);
331
332    IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
333                                                     &s_num_mem_rec_ip,
334                                                     &s_num_mem_rec_op);
335    if (IV_SUCCESS != status) {
336        ALOGE("Error in getting mem records: 0x%x", s_num_mem_rec_op.u4_error_code);
337        return UNKNOWN_ERROR;
338    }
339    mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec;
340
341    return OK;
342}
343
344status_t C2SoftMpeg2Dec::fillMemRecords() {
345    iv_mem_rec_t *ps_mem_rec = (iv_mem_rec_t *) ivd_aligned_malloc(
346            128, mNumMemRecords * sizeof(iv_mem_rec_t));
347    if (!ps_mem_rec) {
348        ALOGE("Allocation failure");
349        return NO_MEMORY;
350    }
351    memset(ps_mem_rec, 0, mNumMemRecords * sizeof(iv_mem_rec_t));
352    for (size_t i = 0; i < mNumMemRecords; i++)
353        ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t);
354    mMemRecords = ps_mem_rec;
355
356    ivdext_fill_mem_rec_ip_t s_fill_mem_ip;
357    ivdext_fill_mem_rec_op_t s_fill_mem_op;
358
359    s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size = sizeof(ivdext_fill_mem_rec_ip_t);
360    s_fill_mem_ip.u4_share_disp_buf = 0;
361    s_fill_mem_ip.e_output_format = mIvColorformat;
362    s_fill_mem_ip.u4_deinterlace = 1;
363    s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
364    s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords;
365    s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = mWidth;
366    s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = mHeight;
367    s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size = sizeof(ivdext_fill_mem_rec_op_t);
368    IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
369                                                     &s_fill_mem_ip,
370                                                     &s_fill_mem_op);
371    if (IV_SUCCESS != status) {
372        ALOGE("Error in filling mem records: 0x%x",
373              s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code);
374        return UNKNOWN_ERROR;
375    }
376
377    CHECK_EQ(mNumMemRecords, s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled);
378    for (size_t i = 0; i < mNumMemRecords; i++, ps_mem_rec++) {
379        ps_mem_rec->pv_base = ivd_aligned_malloc(
380                ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
381        if (!ps_mem_rec->pv_base) {
382            ALOGE("Allocation failure for memory record #%zu of size %u",
383                  i, ps_mem_rec->u4_mem_size);
384            return NO_MEMORY;
385        }
386    }
387
388    return OK;
389}
390
391status_t C2SoftMpeg2Dec::createDecoder() {
392    ivdext_init_ip_t s_init_ip;
393    ivdext_init_op_t s_init_op;
394
395    s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t);
396    s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
397    s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords;
398    s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = mWidth;
399    s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = mHeight;
400    s_init_ip.u4_share_disp_buf = 0;
401    s_init_ip.u4_deinterlace = 1;
402    s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords;
403    s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorformat;
404    s_init_op.s_ivd_init_op_t.u4_size = sizeof(ivdext_init_op_t);
405
406    mDecHandle = (iv_obj_t *)mMemRecords[0].pv_base;
407    mDecHandle->pv_fxns = (void *)ivdec_api_function;
408    mDecHandle->u4_size = sizeof(iv_obj_t);
409
410    IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
411                                                     &s_init_ip,
412                                                     &s_init_op);
413    if (status != IV_SUCCESS) {
414        ALOGE("error in %s: 0x%x", __func__,
415              s_init_op.s_ivd_init_op_t.u4_error_code);
416        return UNKNOWN_ERROR;
417    }
418
419    return OK;
420}
421
422status_t C2SoftMpeg2Dec::setNumCores() {
423    ivdext_ctl_set_num_cores_ip_t s_set_num_cores_ip;
424    ivdext_ctl_set_num_cores_op_t s_set_num_cores_op;
425
426    s_set_num_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
427    s_set_num_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
428    s_set_num_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
429    s_set_num_cores_ip.u4_num_cores = mNumCores;
430    s_set_num_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
431    IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
432                                                     &s_set_num_cores_ip,
433                                                     &s_set_num_cores_op);
434    if (status != IV_SUCCESS) {
435        ALOGD("error in %s: 0x%x", __func__, s_set_num_cores_op.u4_error_code);
436        return UNKNOWN_ERROR;
437    }
438
439    return OK;
440}
441
442status_t C2SoftMpeg2Dec::setParams(size_t stride) {
443    ivd_ctl_set_config_ip_t s_set_dyn_params_ip;
444    ivd_ctl_set_config_op_t s_set_dyn_params_op;
445
446    s_set_dyn_params_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
447    s_set_dyn_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;
448    s_set_dyn_params_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
449    s_set_dyn_params_ip.u4_disp_wd = (UWORD32) stride;
450    s_set_dyn_params_ip.e_frm_skip_mode = IVD_SKIP_NONE;
451    s_set_dyn_params_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
452    s_set_dyn_params_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
453    s_set_dyn_params_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
454    IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
455                                                     &s_set_dyn_params_ip,
456                                                     &s_set_dyn_params_op);
457    if (status != IV_SUCCESS) {
458        ALOGE("error in %s: 0x%x", __func__, s_set_dyn_params_op.u4_error_code);
459        return UNKNOWN_ERROR;
460    }
461
462    return OK;
463}
464
465status_t C2SoftMpeg2Dec::getVersion() {
466    ivd_ctl_getversioninfo_ip_t s_get_versioninfo_ip;
467    ivd_ctl_getversioninfo_op_t s_get_versioninfo_op;
468    UWORD8 au1_buf[512];
469
470    s_get_versioninfo_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t);
471    s_get_versioninfo_ip.e_cmd = IVD_CMD_VIDEO_CTL;
472    s_get_versioninfo_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION;
473    s_get_versioninfo_ip.pv_version_buffer = au1_buf;
474    s_get_versioninfo_ip.u4_version_buffer_size = sizeof(au1_buf);
475    s_get_versioninfo_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t);
476    IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
477                                                     &s_get_versioninfo_ip,
478                                                     &s_get_versioninfo_op);
479    if (status != IV_SUCCESS) {
480        ALOGD("error in %s: 0x%x", __func__,
481              s_get_versioninfo_op.u4_error_code);
482    } else {
483        ALOGV("ittiam decoder version number: %s",
484              (char *) s_get_versioninfo_ip.pv_version_buffer);
485    }
486
487    return OK;
488}
489
490status_t C2SoftMpeg2Dec::initDecoder() {
491    status_t ret = getNumMemRecords();
492    if (OK != ret) return ret;
493
494    ret = fillMemRecords();
495    if (OK != ret) return ret;
496
497    if (OK != createDecoder()) return UNKNOWN_ERROR;
498
499    mNumCores = MIN(getCpuCoreCount(), MAX_NUM_CORES);
500    mStride = ALIGN64(mWidth);
501    mSignalledError = false;
502    mPreference = kPreferBitstream;
503    memset(&mDefaultColorAspects, 0, sizeof(ColorAspects));
504    memset(&mBitstreamColorAspects, 0, sizeof(ColorAspects));
505    memset(&mFinalColorAspects, 0, sizeof(ColorAspects));
506    mUpdateColorAspects = false;
507    resetPlugin();
508    (void) setNumCores();
509    if (OK != setParams(mStride)) return UNKNOWN_ERROR;
510    (void) getVersion();
511
512    return OK;
513}
514
515bool C2SoftMpeg2Dec::setDecodeArgs(ivd_video_decode_ip_t *ps_decode_ip,
516                                   ivd_video_decode_op_t *ps_decode_op,
517                                   C2ReadView *inBuffer,
518                                   C2GraphicView *outBuffer,
519                                   size_t inOffset,
520                                   size_t inSize,
521                                   uint32_t tsMarker) {
522    uint32_t displayStride = mStride;
523    uint32_t displayHeight = mHeight;
524    size_t lumaSize = displayStride * displayHeight;
525    size_t chromaSize = lumaSize >> 2;
526
527    ps_decode_ip->u4_size = sizeof(ivd_video_decode_ip_t);
528    ps_decode_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
529    if (inBuffer) {
530        ps_decode_ip->u4_ts = tsMarker;
531        ps_decode_ip->pv_stream_buffer = const_cast<uint8_t *>(inBuffer->data() + inOffset);
532        ps_decode_ip->u4_num_Bytes = inSize;
533    } else {
534        ps_decode_ip->u4_ts = 0;
535        ps_decode_ip->pv_stream_buffer = nullptr;
536        ps_decode_ip->u4_num_Bytes = 0;
537    }
538    ps_decode_ip->s_out_buffer.u4_min_out_buf_size[0] = lumaSize;
539    ps_decode_ip->s_out_buffer.u4_min_out_buf_size[1] = chromaSize;
540    ps_decode_ip->s_out_buffer.u4_min_out_buf_size[2] = chromaSize;
541    if (outBuffer) {
542        if (outBuffer->width() < displayStride || outBuffer->height() < displayHeight) {
543            ALOGE("Output buffer too small: provided (%dx%d) required (%ux%u)",
544                  outBuffer->width(), outBuffer->height(), displayStride, displayHeight);
545            return false;
546        }
547        ps_decode_ip->s_out_buffer.pu1_bufs[0] = outBuffer->data()[C2PlanarLayout::PLANE_Y];
548        ps_decode_ip->s_out_buffer.pu1_bufs[1] = outBuffer->data()[C2PlanarLayout::PLANE_U];
549        ps_decode_ip->s_out_buffer.pu1_bufs[2] = outBuffer->data()[C2PlanarLayout::PLANE_V];
550    } else {
551        ps_decode_ip->s_out_buffer.pu1_bufs[0] = mOutBufferDrain;
552        ps_decode_ip->s_out_buffer.pu1_bufs[1] = mOutBufferDrain + lumaSize;
553        ps_decode_ip->s_out_buffer.pu1_bufs[2] = mOutBufferDrain + lumaSize + chromaSize;
554    }
555    ps_decode_ip->s_out_buffer.u4_num_bufs = 3;
556    ps_decode_op->u4_size = sizeof(ivd_video_decode_op_t);
557
558    return true;
559}
560
561bool C2SoftMpeg2Dec::colorAspectsDiffer(
562        const ColorAspects &a, const ColorAspects &b) {
563    if (a.mRange != b.mRange
564        || a.mPrimaries != b.mPrimaries
565        || a.mTransfer != b.mTransfer
566        || a.mMatrixCoeffs != b.mMatrixCoeffs) {
567        return true;
568    }
569    return false;
570}
571
572void C2SoftMpeg2Dec::updateFinalColorAspects(
573        const ColorAspects &otherAspects, const ColorAspects &preferredAspects) {
574    Mutex::Autolock autoLock(mColorAspectsLock);
575    ColorAspects newAspects;
576    newAspects.mRange = preferredAspects.mRange != ColorAspects::RangeUnspecified ?
577        preferredAspects.mRange : otherAspects.mRange;
578    newAspects.mPrimaries = preferredAspects.mPrimaries != ColorAspects::PrimariesUnspecified ?
579        preferredAspects.mPrimaries : otherAspects.mPrimaries;
580    newAspects.mTransfer = preferredAspects.mTransfer != ColorAspects::TransferUnspecified ?
581        preferredAspects.mTransfer : otherAspects.mTransfer;
582    newAspects.mMatrixCoeffs = preferredAspects.mMatrixCoeffs != ColorAspects::MatrixUnspecified ?
583        preferredAspects.mMatrixCoeffs : otherAspects.mMatrixCoeffs;
584
585    // Check to see if need update mFinalColorAspects.
586    if (colorAspectsDiffer(mFinalColorAspects, newAspects)) {
587        mFinalColorAspects = newAspects;
588        mUpdateColorAspects = true;
589    }
590}
591
592status_t C2SoftMpeg2Dec::handleColorAspectsChange() {
593    if (mPreference == kPreferBitstream) {
594        updateFinalColorAspects(mDefaultColorAspects, mBitstreamColorAspects);
595    } else if (mPreference == kPreferContainer) {
596        updateFinalColorAspects(mBitstreamColorAspects, mDefaultColorAspects);
597    } else {
598        return C2_CORRUPTED;
599    }
600    return C2_OK;
601}
602
603bool C2SoftMpeg2Dec::getSeqInfo() {
604    ivdext_ctl_get_seq_info_ip_t s_ctl_get_seq_info_ip;
605    ivdext_ctl_get_seq_info_op_t s_ctl_get_seq_info_op;
606
607    s_ctl_get_seq_info_ip.u4_size = sizeof(ivdext_ctl_get_seq_info_ip_t);
608    s_ctl_get_seq_info_ip.e_cmd = IVD_CMD_VIDEO_CTL;
609    s_ctl_get_seq_info_ip.e_sub_cmd =
610        (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_GET_SEQ_INFO;
611    s_ctl_get_seq_info_op.u4_size = sizeof(ivdext_ctl_get_seq_info_op_t);
612    IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
613                                                     &s_ctl_get_seq_info_ip,
614                                                     &s_ctl_get_seq_info_op);
615    if (status != IV_SUCCESS) {
616        ALOGW("Error in getting Sequence info: 0x%x", s_ctl_get_seq_info_op.u4_error_code);
617        return false;
618    }
619
620    int32_t primaries = s_ctl_get_seq_info_op.u1_colour_primaries;
621    int32_t transfer = s_ctl_get_seq_info_op.u1_transfer_characteristics;
622    int32_t coeffs = s_ctl_get_seq_info_op.u1_matrix_coefficients;
623    bool full_range =  false;  // mpeg2 video has limited range.
624
625    ColorAspects colorAspects;
626    ColorUtils::convertIsoColorAspectsToCodecAspects(
627            primaries, transfer, coeffs, full_range, colorAspects);
628    // Update color aspects if necessary.
629    if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) {
630        mBitstreamColorAspects = colorAspects;
631        status_t err = handleColorAspectsChange();
632        CHECK(err == OK);
633    }
634
635    return true;
636}
637
638status_t C2SoftMpeg2Dec::setFlushMode() {
639    ivd_ctl_flush_ip_t s_set_flush_ip;
640    ivd_ctl_flush_op_t s_set_flush_op;
641
642    s_set_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
643    s_set_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL;
644    s_set_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
645    s_set_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t);
646    IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
647                                                     &s_set_flush_ip,
648                                                     &s_set_flush_op);
649    if (status != IV_SUCCESS) {
650        ALOGE("error in %s: 0x%x", __func__, s_set_flush_op.u4_error_code);
651        return UNKNOWN_ERROR;
652    }
653
654    return OK;
655}
656
657status_t C2SoftMpeg2Dec::resetDecoder() {
658    ivd_ctl_reset_ip_t s_reset_ip;
659    ivd_ctl_reset_op_t s_reset_op;
660
661    s_reset_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
662    s_reset_ip.e_cmd = IVD_CMD_VIDEO_CTL;
663    s_reset_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
664    s_reset_op.u4_size = sizeof(ivd_ctl_reset_op_t);
665    IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
666                                                     &s_reset_ip,
667                                                     &s_reset_op);
668    if (IV_SUCCESS != status) {
669        ALOGE("error in %s: 0x%x", __func__, s_reset_op.u4_error_code);
670        return UNKNOWN_ERROR;
671    }
672    (void) setNumCores();
673    mStride = 0;
674    mSignalledError = false;
675
676    return OK;
677}
678
679void C2SoftMpeg2Dec::resetPlugin() {
680    mSignalledOutputEos = false;
681    gettimeofday(&mTimeStart, nullptr);
682    gettimeofday(&mTimeEnd, nullptr);
683}
684
685status_t C2SoftMpeg2Dec::deleteDecoder() {
686    if (mMemRecords) {
687        iv_mem_rec_t *ps_mem_rec = mMemRecords;
688
689        for (size_t i = 0; i < mNumMemRecords; i++, ps_mem_rec++) {
690            if (ps_mem_rec->pv_base) {
691                ivd_aligned_free(ps_mem_rec->pv_base);
692            }
693        }
694        ivd_aligned_free(mMemRecords);
695        mMemRecords = nullptr;
696    }
697    mDecHandle = nullptr;
698
699    return OK;
700}
701
702status_t C2SoftMpeg2Dec::reInitDecoder() {
703    deleteDecoder();
704
705    status_t ret = initDecoder();
706    if (OK != ret) {
707        ALOGE("Failed to initialize decoder");
708        deleteDecoder();
709        return ret;
710    }
711    return OK;
712}
713
714void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
715    uint32_t flags = 0;
716    if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
717        flags |= C2FrameData::FLAG_END_OF_STREAM;
718        ALOGV("signalling eos");
719    }
720    work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
721    work->worklets.front()->output.buffers.clear();
722    work->worklets.front()->output.ordinal = work->input.ordinal;
723    work->workletsProcessed = 1u;
724}
725
726void C2SoftMpeg2Dec::finishWork(uint64_t index, const std::unique_ptr<C2Work> &work) {
727    std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(std::move(mOutBlock),
728                                                           C2Rect(mWidth, mHeight));
729    mOutBlock = nullptr;
730    auto fillWork = [buffer, index](const std::unique_ptr<C2Work> &work) {
731        uint32_t flags = 0;
732        if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
733                (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
734            flags |= C2FrameData::FLAG_END_OF_STREAM;
735            ALOGV("signalling eos");
736        }
737        work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
738        work->worklets.front()->output.buffers.clear();
739        work->worklets.front()->output.buffers.push_back(buffer);
740        work->worklets.front()->output.ordinal = work->input.ordinal;
741        work->workletsProcessed = 1u;
742    };
743    if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
744        fillWork(work);
745    } else {
746        finish(index, fillWork);
747    }
748}
749
750c2_status_t C2SoftMpeg2Dec::ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool) {
751    if (!mDecHandle) {
752        ALOGE("not supposed to be here, invalid decoder context");
753        return C2_CORRUPTED;
754    }
755    if (mStride != ALIGN64(mWidth)) {
756        mStride = ALIGN64(mWidth);
757        if (OK != setParams(mStride)) return C2_CORRUPTED;
758    }
759    if (mOutBlock &&
760            (mOutBlock->width() != mStride || mOutBlock->height() != mHeight)) {
761        mOutBlock.reset();
762    }
763    if (!mOutBlock) {
764        uint32_t format = HAL_PIXEL_FORMAT_YV12;
765        C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
766        c2_status_t err = pool->fetchGraphicBlock(mStride, mHeight, format, usage, &mOutBlock);
767        if (err != C2_OK) {
768            ALOGE("fetchGraphicBlock for Output failed with status %d", err);
769            return err;
770        }
771        ALOGV("provided (%dx%d) required (%dx%d)",
772              mOutBlock->width(), mOutBlock->height(), mStride, mHeight);
773    }
774
775    return C2_OK;
776}
777
778// TODO: can overall error checking be improved?
779// TODO: allow configuration of color format and usage for graphic buffers instead
780//       of hard coding them to HAL_PIXEL_FORMAT_YV12
781// TODO: pass coloraspects information to surface
782// TODO: test support for dynamic change in resolution
783// TODO: verify if the decoder sent back all frames
784void C2SoftMpeg2Dec::process(
785        const std::unique_ptr<C2Work> &work,
786        const std::shared_ptr<C2BlockPool> &pool) {
787    work->result = C2_OK;
788    work->workletsProcessed = 0u;
789    work->worklets.front()->output.configUpdate.clear();
790    if (mSignalledError || mSignalledOutputEos) {
791        work->result = C2_BAD_VALUE;
792        return;
793    }
794
795    size_t inOffset = 0u;
796    size_t inSize = 0u;
797    uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF;
798    C2ReadView rView = mDummyReadView;
799    if (work->input.buffers.empty()) {
800        rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
801        inSize = rView.capacity();
802        if (inSize && rView.error()) {
803            ALOGE("read view map failed %d", rView.error());
804            work->result = C2_CORRUPTED;
805            return;
806        }
807    }
808    bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
809    bool hasPicture = false;
810
811    ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
812          inSize, (int)work->input.ordinal.timestamp.peeku(),
813          (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
814    size_t inPos = 0;
815    while (inPos < inSize) {
816        if (C2_OK != ensureDecoderState(pool)) {
817            mSignalledError = true;
818            work->result = C2_CORRUPTED;
819            return;
820        }
821        C2GraphicView wView = mOutBlock->map().get();
822        if (wView.error()) {
823            ALOGE("graphic view map failed %d", wView.error());
824            work->result = C2_CORRUPTED;
825            return;
826        }
827
828        ivd_video_decode_ip_t s_decode_ip;
829        ivd_video_decode_op_t s_decode_op;
830        if (!setDecodeArgs(&s_decode_ip, &s_decode_op, &rView, &wView,
831                           inOffset + inPos, inSize - inPos, workIndex)) {
832            mSignalledError = true;
833            work->result = C2_CORRUPTED;
834            return;
835        }
836        // If input dump is enabled, then write to file
837        DUMP_TO_FILE(mInFile, s_decode_ip.pv_stream_buffer, s_decode_ip.u4_num_Bytes);
838        WORD32 delay;
839        GETTIME(&mTimeStart, NULL);
840        TIME_DIFF(mTimeEnd, mTimeStart, delay);
841        (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
842        WORD32 decodeTime;
843        GETTIME(&mTimeEnd, nullptr);
844        TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
845        ALOGV("decodeTime=%6d delay=%6d numBytes=%6d ", decodeTime, delay,
846              s_decode_op.u4_num_bytes_consumed);
847        if (IMPEG2D_UNSUPPORTED_DIMENSIONS == s_decode_op.u4_error_code) {
848            ALOGV("unsupported resolution : %dx%d", s_decode_op.u4_pic_wd, s_decode_op.u4_pic_ht);
849            drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
850            resetPlugin();
851            mWidth = s_decode_op.u4_pic_wd;
852            mHeight = s_decode_op.u4_pic_ht;
853
854            ALOGI("Configuring decoder: mWidth %d , mHeight %d ",
855                   mWidth, mHeight);
856            C2VideoSizeStreamInfo::output size(0u, mWidth, mHeight);
857            std::vector<std::unique_ptr<C2SettingResult>> failures;
858            c2_status_t err =
859                mIntf->config({&size}, C2_MAY_BLOCK, &failures);
860            if (err == OK) {
861                work->worklets.front()->output.configUpdate.push_back(
862                    C2Param::Copy(size));
863            } else {
864                ALOGE("Cannot set width and height");
865                mSignalledError = true;
866                work->result = C2_CORRUPTED;
867                return;
868            }
869
870            if (OK != reInitDecoder()) {
871                ALOGE("Failed to reinitialize decoder");
872                mSignalledError = true;
873                work->result = C2_CORRUPTED;
874                return;
875            }
876            continue;
877        } else if (IVD_RES_CHANGED == (s_decode_op.u4_error_code & 0xFF)) {
878            ALOGV("resolution changed");
879            drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
880            resetDecoder();
881            resetPlugin();
882            continue;
883        }
884        if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
885            if (s_decode_op.u4_pic_wd != mWidth ||  s_decode_op.u4_pic_ht != mHeight) {
886                mWidth = s_decode_op.u4_pic_wd;
887                mHeight = s_decode_op.u4_pic_ht;
888                CHECK_EQ(0u, s_decode_op.u4_output_present);
889
890                ALOGI("Configuring decoder out: mWidth %d , mHeight %d ",
891                       mWidth, mHeight);
892                C2VideoSizeStreamInfo::output size(0u, mWidth, mHeight);
893                std::vector<std::unique_ptr<C2SettingResult>> failures;
894                c2_status_t err =
895                    mIntf->config({&size}, C2_MAY_BLOCK, &failures);
896                if (err == OK) {
897                    work->worklets.front()->output.configUpdate.push_back(
898                        C2Param::Copy(size));
899                } else {
900                    ALOGE("Cannot set width and height");
901                    mSignalledError = true;
902                    work->result = C2_CORRUPTED;
903                    return;
904                }
905            }
906        }
907
908        (void) getSeqInfo();
909        if (mUpdateColorAspects) {
910            mUpdateColorAspects = false;
911        }
912        hasPicture |= (1 == s_decode_op.u4_frame_decoded_flag);
913        if (s_decode_op.u4_output_present) {
914            finishWork(s_decode_op.u4_ts, work);
915        }
916        inPos += s_decode_op.u4_num_bytes_consumed;
917        if (hasPicture && (inSize - inPos) != 0) {
918            ALOGD("decoded frame in current access nal, ignoring further trailing bytes %d",
919                  (int)inSize - (int)inPos);
920            break;
921        }
922    }
923
924    if (eos) {
925        drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
926        mSignalledOutputEos = true;
927    } else if (!hasPicture) {
928        fillEmptyWork(work);
929    }
930}
931
932c2_status_t C2SoftMpeg2Dec::drainInternal(
933        uint32_t drainMode,
934        const std::shared_ptr<C2BlockPool> &pool,
935        const std::unique_ptr<C2Work> &work) {
936    if (drainMode == NO_DRAIN) {
937        ALOGW("drain with NO_DRAIN: no-op");
938        return C2_OK;
939    }
940    if (drainMode == DRAIN_CHAIN) {
941        ALOGW("DRAIN_CHAIN not supported");
942        return C2_OMITTED;
943    }
944
945    if (OK != setFlushMode()) return C2_CORRUPTED;
946    while (true) {
947        if (C2_OK != ensureDecoderState(pool)) {
948            mSignalledError = true;
949            work->result = C2_CORRUPTED;
950            return C2_CORRUPTED;
951        }
952        C2GraphicView wView = mOutBlock->map().get();
953        if (wView.error()) {
954            ALOGE("graphic view map failed %d", wView.error());
955            return C2_CORRUPTED;
956        }
957        ivd_video_decode_ip_t s_decode_ip;
958        ivd_video_decode_op_t s_decode_op;
959        if (!setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, &wView, 0, 0, 0)) {
960            mSignalledError = true;
961            return C2_CORRUPTED;
962        }
963        (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
964        if (s_decode_op.u4_output_present) {
965            finishWork(s_decode_op.u4_ts, work);
966        } else {
967            break;
968        }
969    }
970    if (drainMode == DRAIN_COMPONENT_WITH_EOS &&
971            work && work->workletsProcessed == 0u) {
972        fillEmptyWork(work);
973    }
974
975    return C2_OK;
976}
977
978c2_status_t C2SoftMpeg2Dec::drain(
979        uint32_t drainMode,
980        const std::shared_ptr<C2BlockPool> &pool) {
981    return drainInternal(drainMode, pool, nullptr);
982}
983
984class C2SoftMpeg2DecFactory : public C2ComponentFactory {
985public:
986    C2SoftMpeg2DecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
987            GetCodec2PlatformComponentStore()->getParamReflector())) {
988    }
989
990    virtual c2_status_t createComponent(
991            c2_node_id_t id,
992            std::shared_ptr<C2Component>* const component,
993            std::function<void(C2Component*)> deleter) override {
994        *component = std::shared_ptr<C2Component>(
995                new C2SoftMpeg2Dec(COMPONENT_NAME,
996                                   id,
997                                   std::make_shared<C2SoftMpeg2Dec::IntfImpl>(mHelper)),
998                deleter);
999        return C2_OK;
1000    }
1001
1002    virtual c2_status_t createInterface(
1003            c2_node_id_t id,
1004            std::shared_ptr<C2ComponentInterface>* const interface,
1005            std::function<void(C2ComponentInterface*)> deleter) override {
1006        *interface = std::shared_ptr<C2ComponentInterface>(
1007                new SimpleInterface<C2SoftMpeg2Dec::IntfImpl>(
1008                        COMPONENT_NAME, id, std::make_shared<C2SoftMpeg2Dec::IntfImpl>(mHelper)),
1009                deleter);
1010        return C2_OK;
1011    }
1012
1013    virtual ~C2SoftMpeg2DecFactory() override = default;
1014
1015private:
1016    std::shared_ptr<C2ReflectorHelper> mHelper;
1017};
1018
1019}  // namespace android
1020
1021extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
1022    ALOGV("in %s", __func__);
1023    return new ::android::C2SoftMpeg2DecFactory();
1024}
1025
1026extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
1027    ALOGV("in %s", __func__);
1028    delete factory;
1029}
1030