1 /*
2  * Copyright 2015 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 "SoftMPEG2"
19 #include <utils/Log.h>
20 
21 #include "iv_datatypedef.h"
22 #include "iv.h"
23 #include "ivd.h"
24 #include "impeg2d.h"
25 #include "SoftMPEG2.h"
26 
27 #include <media/stagefright/foundation/ADebug.h>
28 #include <media/stagefright/MediaDefs.h>
29 #include <OMX_VideoExt.h>
30 
31 namespace android {
32 
33 #define componentName                   "video_decoder.mpeg2"
34 #define codingType                      OMX_VIDEO_CodingMPEG2
35 #define CODEC_MIME_TYPE                 MEDIA_MIMETYPE_VIDEO_MPEG2
36 
37 /** Function and structure definitions to keep code similar for each codec */
38 #define ivdec_api_function              impeg2d_api_function
39 #define ivdext_init_ip_t                impeg2d_init_ip_t
40 #define ivdext_init_op_t                impeg2d_init_op_t
41 #define ivdext_fill_mem_rec_ip_t        impeg2d_fill_mem_rec_ip_t
42 #define ivdext_fill_mem_rec_op_t        impeg2d_fill_mem_rec_op_t
43 #define ivdext_ctl_set_num_cores_ip_t   impeg2d_ctl_set_num_cores_ip_t
44 #define ivdext_ctl_set_num_cores_op_t   impeg2d_ctl_set_num_cores_op_t
45 
46 #define IVDEXT_CMD_CTL_SET_NUM_CORES    \
47         (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_SET_NUM_CORES
48 
49 static const CodecProfileLevel kProfileLevels[] = {
50     { OMX_VIDEO_MPEG2ProfileSimple, OMX_VIDEO_MPEG2LevelHL  },
51 
52     { OMX_VIDEO_MPEG2ProfileMain  , OMX_VIDEO_MPEG2LevelHL  },
53 };
54 
SoftMPEG2(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)55 SoftMPEG2::SoftMPEG2(
56         const char *name,
57         const OMX_CALLBACKTYPE *callbacks,
58         OMX_PTR appData,
59         OMX_COMPONENTTYPE **component)
60     : SoftVideoDecoderOMXComponent(
61             name, componentName, codingType,
62             kProfileLevels, ARRAY_SIZE(kProfileLevels),
63             320 /* width */, 240 /* height */, callbacks,
64             appData, component),
65       mCodecCtx(NULL),
66       mMemRecords(NULL),
67       mFlushOutBuffer(NULL),
68       mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
69       mIvColorFormat(IV_YUV_420P),
70       mNewWidth(mWidth),
71       mNewHeight(mHeight),
72       mChangingResolution(false),
73       mSignalledError(false),
74       mStride(mWidth) {
75     initPorts(kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, CODEC_MIME_TYPE);
76 
77     // If input dump is enabled, then open create an empty file
78     GENERATE_FILE_NAMES();
79     CREATE_DUMP_FILE(mInFile);
80 }
81 
~SoftMPEG2()82 SoftMPEG2::~SoftMPEG2() {
83     if (OK != deInitDecoder()) {
84         ALOGE("Failed to deinit decoder");
85         notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
86         mSignalledError = true;
87         return;
88     }
89 }
90 
91 
getMinTimestampIdx(OMX_S64 * pNTimeStamp,bool * pIsTimeStampValid)92 static ssize_t getMinTimestampIdx(OMX_S64 *pNTimeStamp, bool *pIsTimeStampValid) {
93     OMX_S64 minTimeStamp = LLONG_MAX;
94     ssize_t idx = -1;
95     for (ssize_t i = 0; i < MAX_TIME_STAMPS; i++) {
96         if (pIsTimeStampValid[i]) {
97             if (pNTimeStamp[i] < minTimeStamp) {
98                 minTimeStamp = pNTimeStamp[i];
99                 idx = i;
100             }
101         }
102     }
103     return idx;
104 }
105 
GetCPUCoreCount()106 static size_t GetCPUCoreCount() {
107     long cpuCoreCount = 1;
108 #if defined(_SC_NPROCESSORS_ONLN)
109     cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
110 #else
111     // _SC_NPROC_ONLN must be defined...
112     cpuCoreCount = sysconf(_SC_NPROC_ONLN);
113 #endif
114     CHECK(cpuCoreCount >= 1);
115     ALOGV("Number of CPU cores: %ld", cpuCoreCount);
116     return (size_t)cpuCoreCount;
117 }
118 
logVersion()119 void SoftMPEG2::logVersion() {
120     ivd_ctl_getversioninfo_ip_t s_ctl_ip;
121     ivd_ctl_getversioninfo_op_t s_ctl_op;
122     UWORD8 au1_buf[512];
123     IV_API_CALL_STATUS_T status;
124 
125     s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
126     s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION;
127     s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t);
128     s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t);
129     s_ctl_ip.pv_version_buffer = au1_buf;
130     s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf);
131 
132     status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op);
133 
134     if (status != IV_SUCCESS) {
135         ALOGE("Error in getting version number: 0x%x",
136                 s_ctl_op.u4_error_code);
137     } else {
138         ALOGV("Ittiam decoder version number: %s",
139                 (char *)s_ctl_ip.pv_version_buffer);
140     }
141     return;
142 }
143 
setParams(size_t stride)144 status_t SoftMPEG2::setParams(size_t stride) {
145     ivd_ctl_set_config_ip_t s_ctl_ip;
146     ivd_ctl_set_config_op_t s_ctl_op;
147     IV_API_CALL_STATUS_T status;
148     s_ctl_ip.u4_disp_wd = (UWORD32)stride;
149     s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
150 
151     s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
152     s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
153     s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
154     s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
155     s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
156     s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
157 
158     ALOGV("Set the run-time (dynamic) parameters stride = %zu", stride);
159     status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op);
160 
161     if (status != IV_SUCCESS) {
162         ALOGE("Error in setting the run-time parameters: 0x%x",
163                 s_ctl_op.u4_error_code);
164 
165         return UNKNOWN_ERROR;
166     }
167     return OK;
168 }
169 
resetPlugin()170 status_t SoftMPEG2::resetPlugin() {
171     mIsInFlush = false;
172     mReceivedEOS = false;
173     memset(mTimeStamps, 0, sizeof(mTimeStamps));
174     memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid));
175 
176     /* Initialize both start and end times */
177     gettimeofday(&mTimeStart, NULL);
178     gettimeofday(&mTimeEnd, NULL);
179 
180     return OK;
181 }
182 
resetDecoder()183 status_t SoftMPEG2::resetDecoder() {
184     ivd_ctl_reset_ip_t s_ctl_ip;
185     ivd_ctl_reset_op_t s_ctl_op;
186     IV_API_CALL_STATUS_T status;
187 
188     s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
189     s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
190     s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
191     s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
192 
193     status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op);
194     if (IV_SUCCESS != status) {
195         ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code);
196         return UNKNOWN_ERROR;
197     }
198 
199     /* Set the run-time (dynamic) parameters */
200     setParams(outputBufferWidth());
201 
202     /* Set number of cores/threads to be used by the codec */
203     setNumCores();
204 
205     mStride = 0;
206     mSignalledError = false;
207 
208     return OK;
209 }
210 
setNumCores()211 status_t SoftMPEG2::setNumCores() {
212     ivdext_ctl_set_num_cores_ip_t s_set_cores_ip;
213     ivdext_ctl_set_num_cores_op_t s_set_cores_op;
214     IV_API_CALL_STATUS_T status;
215     s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
216     s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
217     s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES);
218     s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
219     s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
220 
221     status = ivdec_api_function(mCodecCtx, (void *)&s_set_cores_ip, (void *)&s_set_cores_op);
222     if (IV_SUCCESS != status) {
223         ALOGE("Error in setting number of cores: 0x%x",
224                 s_set_cores_op.u4_error_code);
225         return UNKNOWN_ERROR;
226     }
227     return OK;
228 }
229 
setFlushMode()230 status_t SoftMPEG2::setFlushMode() {
231     IV_API_CALL_STATUS_T status;
232     ivd_ctl_flush_ip_t s_video_flush_ip;
233     ivd_ctl_flush_op_t s_video_flush_op;
234 
235     s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL;
236     s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
237     s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
238     s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t);
239 
240     /* Set the decoder in Flush mode, subsequent decode() calls will flush */
241     status = ivdec_api_function(
242             mCodecCtx, (void *)&s_video_flush_ip, (void *)&s_video_flush_op);
243 
244     if (status != IV_SUCCESS) {
245         ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status,
246                 s_video_flush_op.u4_error_code);
247         return UNKNOWN_ERROR;
248     }
249 
250     mWaitForI = true;
251     mIsInFlush = true;
252     return OK;
253 }
254 
initDecoder()255 status_t SoftMPEG2::initDecoder() {
256     IV_API_CALL_STATUS_T status;
257 
258     UWORD32 u4_num_reorder_frames;
259     UWORD32 u4_num_ref_frames;
260     UWORD32 u4_share_disp_buf;
261 
262     mNumCores = GetCPUCoreCount();
263     mWaitForI = true;
264 
265     /* Initialize number of ref and reorder modes (for MPEG2) */
266     u4_num_reorder_frames = 16;
267     u4_num_ref_frames = 16;
268     u4_share_disp_buf = 0;
269 
270     uint32_t displayStride = outputBufferWidth();
271     uint32_t displayHeight = outputBufferHeight();
272     uint32_t displaySizeY = displayStride * displayHeight;
273 
274     {
275         iv_num_mem_rec_ip_t s_num_mem_rec_ip;
276         iv_num_mem_rec_op_t s_num_mem_rec_op;
277 
278         s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip);
279         s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op);
280         s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
281 
282         status = ivdec_api_function(
283                 mCodecCtx, (void *)&s_num_mem_rec_ip, (void *)&s_num_mem_rec_op);
284         if (IV_SUCCESS != status) {
285             ALOGE("Error in getting mem records: 0x%x",
286                     s_num_mem_rec_op.u4_error_code);
287             return UNKNOWN_ERROR;
288         }
289 
290         mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec;
291     }
292 
293     mMemRecords = (iv_mem_rec_t *)ivd_aligned_malloc(
294             128, mNumMemRecords * sizeof(iv_mem_rec_t));
295     if (mMemRecords == NULL) {
296         ALOGE("Allocation failure");
297         return NO_MEMORY;
298     }
299 
300     memset(mMemRecords, 0, mNumMemRecords * sizeof(iv_mem_rec_t));
301 
302     {
303         size_t i;
304         ivdext_fill_mem_rec_ip_t s_fill_mem_ip;
305         ivdext_fill_mem_rec_op_t s_fill_mem_op;
306         iv_mem_rec_t *ps_mem_rec;
307 
308         s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size =
309             sizeof(ivdext_fill_mem_rec_ip_t);
310 
311         s_fill_mem_ip.u4_share_disp_buf = u4_share_disp_buf;
312         s_fill_mem_ip.e_output_format = mIvColorFormat;
313         s_fill_mem_ip.u4_deinterlace = 1;
314         s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
315         s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords;
316         s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = displayStride;
317         s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = displayHeight;
318         s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size =
319             sizeof(ivdext_fill_mem_rec_op_t);
320 
321         ps_mem_rec = mMemRecords;
322         for (i = 0; i < mNumMemRecords; i++) {
323             ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t);
324         }
325 
326         status = ivdec_api_function(
327                 mCodecCtx, (void *)&s_fill_mem_ip, (void *)&s_fill_mem_op);
328 
329         if (IV_SUCCESS != status) {
330             ALOGE("Error in filling mem records: 0x%x",
331                     s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code);
332             return UNKNOWN_ERROR;
333         }
334         mNumMemRecords =
335             s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled;
336 
337         ps_mem_rec = mMemRecords;
338 
339         for (i = 0; i < mNumMemRecords; i++) {
340             ps_mem_rec->pv_base = ivd_aligned_malloc(
341                     ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
342             if (ps_mem_rec->pv_base == NULL) {
343                 ALOGE("Allocation failure for memory record #%zu of size %u",
344                         i, ps_mem_rec->u4_mem_size);
345                 status = IV_FAIL;
346                 return NO_MEMORY;
347             }
348 
349             ps_mem_rec++;
350         }
351     }
352 
353     /* Initialize the decoder */
354     {
355         ivdext_init_ip_t s_init_ip;
356         ivdext_init_op_t s_init_op;
357 
358         void *dec_fxns = (void *)ivdec_api_function;
359 
360         s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t);
361         s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
362         s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords;
363         s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = displayStride;
364         s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = displayHeight;
365 
366         s_init_ip.u4_share_disp_buf = u4_share_disp_buf;
367         s_init_ip.u4_deinterlace = 1;
368 
369         s_init_op.s_ivd_init_op_t.u4_size = sizeof(s_init_op);
370 
371         s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords;
372         s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorFormat;
373 
374         mCodecCtx = (iv_obj_t *)mMemRecords[0].pv_base;
375         mCodecCtx->pv_fxns = dec_fxns;
376         mCodecCtx->u4_size = sizeof(iv_obj_t);
377 
378         status = ivdec_api_function(mCodecCtx, (void *)&s_init_ip, (void *)&s_init_op);
379         if (status != IV_SUCCESS) {
380             ALOGE("Error in init: 0x%x",
381                     s_init_op.s_ivd_init_op_t.u4_error_code);
382             return UNKNOWN_ERROR;
383         }
384     }
385 
386     /* Reset the plugin state */
387     resetPlugin();
388 
389     /* Set the run time (dynamic) parameters */
390     mStride = outputBufferWidth();
391     setParams(mStride);
392 
393     /* Set number of cores/threads to be used by the codec */
394     setNumCores();
395 
396     /* Get codec version */
397     logVersion();
398 
399     /* Allocate internal picture buffer */
400     uint32_t bufferSize = displaySizeY * 3 / 2;
401     mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, bufferSize);
402     if (NULL == mFlushOutBuffer) {
403         ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize);
404         return NO_MEMORY;
405     }
406 
407     mInitNeeded = false;
408     mFlushNeeded = false;
409     return OK;
410 }
411 
deInitDecoder()412 status_t SoftMPEG2::deInitDecoder() {
413     size_t i;
414 
415     if (mMemRecords) {
416         iv_mem_rec_t *ps_mem_rec;
417 
418         ps_mem_rec = mMemRecords;
419         for (i = 0; i < mNumMemRecords; i++) {
420             if (ps_mem_rec->pv_base) {
421                 ivd_aligned_free(ps_mem_rec->pv_base);
422             }
423             ps_mem_rec++;
424         }
425         ivd_aligned_free(mMemRecords);
426         mMemRecords = NULL;
427     }
428 
429     if (mFlushOutBuffer) {
430         ivd_aligned_free(mFlushOutBuffer);
431         mFlushOutBuffer = NULL;
432     }
433 
434     mInitNeeded = true;
435     mChangingResolution = false;
436     mCodecCtx = NULL;
437 
438     return OK;
439 }
440 
reInitDecoder()441 status_t SoftMPEG2::reInitDecoder() {
442     status_t ret;
443 
444     deInitDecoder();
445 
446     ret = initDecoder();
447     if (OK != ret) {
448         ALOGE("Failed to initialize decoder");
449         deInitDecoder();
450         return ret;
451     }
452     mSignalledError = false;
453     return OK;
454 }
455 
onReset()456 void SoftMPEG2::onReset() {
457     SoftVideoDecoderOMXComponent::onReset();
458 
459     mWaitForI = true;
460 
461     resetDecoder();
462     resetPlugin();
463 }
464 
getSeqInfo()465 bool SoftMPEG2::getSeqInfo() {
466     IV_API_CALL_STATUS_T status;
467     impeg2d_ctl_get_seq_info_ip_t s_ctl_get_seq_info_ip;
468     impeg2d_ctl_get_seq_info_op_t s_ctl_get_seq_info_op;
469 
470     s_ctl_get_seq_info_ip.e_cmd = IVD_CMD_VIDEO_CTL;
471     s_ctl_get_seq_info_ip.e_sub_cmd =
472         (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_GET_SEQ_INFO;
473 
474     s_ctl_get_seq_info_ip.u4_size = sizeof(impeg2d_ctl_get_seq_info_ip_t);
475     s_ctl_get_seq_info_op.u4_size = sizeof(impeg2d_ctl_get_seq_info_op_t);
476 
477     status = ivdec_api_function(
478             (iv_obj_t *)mCodecCtx, (void *)&s_ctl_get_seq_info_ip,
479             (void *)&s_ctl_get_seq_info_op);
480 
481     if (status != IV_SUCCESS) {
482         ALOGW("Error in getting Sequence info: 0x%x",
483                 s_ctl_get_seq_info_op.u4_error_code);
484         return false;
485     }
486 
487 
488     int32_t primaries = s_ctl_get_seq_info_op.u1_colour_primaries;
489     int32_t transfer = s_ctl_get_seq_info_op.u1_transfer_characteristics;
490     int32_t coeffs = s_ctl_get_seq_info_op.u1_matrix_coefficients;
491     bool fullRange = false;  // mpeg2 video has limited range.
492 
493     ColorAspects colorAspects;
494     ColorUtils::convertIsoColorAspectsToCodecAspects(
495             primaries, transfer, coeffs, fullRange, colorAspects);
496 
497     // Update color aspects if necessary.
498     if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) {
499         mBitstreamColorAspects = colorAspects;
500         status_t err = handleColorAspectsChange();
501         CHECK(err == OK);
502     }
503     return true;
504 }
505 
internalSetParameter(OMX_INDEXTYPE index,const OMX_PTR params)506 OMX_ERRORTYPE SoftMPEG2::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) {
507     const uint32_t oldWidth = mWidth;
508     const uint32_t oldHeight = mHeight;
509     OMX_ERRORTYPE ret = SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
510     if (mWidth != oldWidth || mHeight != oldHeight) {
511         reInitDecoder();
512     }
513     return ret;
514 }
515 
setDecodeArgs(ivd_video_decode_ip_t * ps_dec_ip,ivd_video_decode_op_t * ps_dec_op,OMX_BUFFERHEADERTYPE * inHeader,OMX_BUFFERHEADERTYPE * outHeader,size_t timeStampIx)516 bool SoftMPEG2::setDecodeArgs(
517         ivd_video_decode_ip_t *ps_dec_ip,
518         ivd_video_decode_op_t *ps_dec_op,
519         OMX_BUFFERHEADERTYPE *inHeader,
520         OMX_BUFFERHEADERTYPE *outHeader,
521         size_t timeStampIx) {
522     size_t sizeY = outputBufferWidth() * outputBufferHeight();
523     size_t sizeUV;
524 
525     ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t);
526     ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
527 
528     ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
529 
530     /* When in flush and after EOS with zero byte input,
531      * inHeader is set to zero. Hence check for non-null */
532     if (inHeader) {
533         ps_dec_ip->u4_ts = timeStampIx;
534         ps_dec_ip->pv_stream_buffer = inHeader->pBuffer
535                 + inHeader->nOffset;
536         ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen;
537     } else {
538         ps_dec_ip->u4_ts = 0;
539         ps_dec_ip->pv_stream_buffer = NULL;
540         ps_dec_ip->u4_num_Bytes = 0;
541     }
542 
543     sizeUV = sizeY / 4;
544     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY;
545     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
546     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
547 
548     uint8_t *pBuf;
549     if (outHeader) {
550         if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) {
551             android_errorWriteLog(0x534e4554, "27833616");
552             return false;
553         }
554         pBuf = outHeader->pBuffer;
555     } else {
556         // mFlushOutBuffer always has the right size.
557         pBuf = mFlushOutBuffer;
558     }
559 
560     ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf;
561     ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY;
562     ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV;
563     ps_dec_ip->s_out_buffer.u4_num_bufs = 3;
564     return true;
565 }
onPortFlushCompleted(OMX_U32 portIndex)566 void SoftMPEG2::onPortFlushCompleted(OMX_U32 portIndex) {
567     /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
568     if (kOutputPortIndex == portIndex) {
569         setFlushMode();
570 
571         while (true) {
572             ivd_video_decode_ip_t s_dec_ip;
573             ivd_video_decode_op_t s_dec_op;
574             IV_API_CALL_STATUS_T status;
575             size_t sizeY, sizeUV;
576 
577             setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0);
578 
579             status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
580             if (0 == s_dec_op.u4_output_present) {
581                 resetPlugin();
582                 break;
583             }
584         }
585     }
586 }
587 
onQueueFilled(OMX_U32 portIndex)588 void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) {
589     UNUSED(portIndex);
590 
591     if (mSignalledError) {
592         return;
593     }
594     if (mOutputPortSettingsChange != NONE) {
595         return;
596     }
597 
598     if (NULL == mCodecCtx) {
599         if (OK != initDecoder()) {
600             ALOGE("Failed to initialize decoder");
601             notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
602             mSignalledError = true;
603             return;
604         }
605     }
606 
607     List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
608     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
609 
610     if (outputBufferWidth() != mStride) {
611         /* Set the run-time (dynamic) parameters */
612         mStride = outputBufferWidth();
613         setParams(mStride);
614     }
615 
616     while (!outQueue.empty()) {
617         BufferInfo *inInfo;
618         OMX_BUFFERHEADERTYPE *inHeader;
619 
620         BufferInfo *outInfo;
621         OMX_BUFFERHEADERTYPE *outHeader;
622         size_t timeStampIx;
623 
624         inInfo = NULL;
625         inHeader = NULL;
626 
627         if (!mIsInFlush) {
628             if (!inQueue.empty()) {
629                 inInfo = *inQueue.begin();
630                 inHeader = inInfo->mHeader;
631             } else {
632                 break;
633             }
634         }
635 
636         outInfo = *outQueue.begin();
637         outHeader = outInfo->mHeader;
638         outHeader->nFlags = 0;
639         outHeader->nTimeStamp = 0;
640         outHeader->nOffset = 0;
641 
642         if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
643             mReceivedEOS = true;
644             if (inHeader->nFilledLen == 0) {
645                 inQueue.erase(inQueue.begin());
646                 inInfo->mOwnedByUs = false;
647                 notifyEmptyBufferDone(inHeader);
648                 inHeader = NULL;
649                 setFlushMode();
650             }
651         }
652 
653         // When there is an init required and the decoder is not in flush mode,
654         // update output port's definition and reinitialize decoder.
655         if (mInitNeeded && !mIsInFlush) {
656             bool portWillReset = false;
657             handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
658 
659             if (OK != reInitDecoder()) {
660                 ALOGE("Failed to reinitialize decoder");
661             }
662             return;
663         }
664 
665         /* Get a free slot in timestamp array to hold input timestamp */
666         {
667             size_t i;
668             timeStampIx = 0;
669             for (i = 0; i < MAX_TIME_STAMPS; i++) {
670                 if (!mTimeStampsValid[i]) {
671                     timeStampIx = i;
672                     break;
673                 }
674             }
675             if (inHeader != NULL) {
676                 mTimeStampsValid[timeStampIx] = true;
677                 mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
678             }
679         }
680 
681         {
682             ivd_video_decode_ip_t s_dec_ip;
683             ivd_video_decode_op_t s_dec_op;
684             WORD32 timeDelay, timeTaken;
685             size_t sizeY, sizeUV;
686 
687             if (!setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) {
688                 ALOGE("Decoder arg setup failed");
689                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
690                 return;
691             }
692             // If input dump is enabled, then write to file
693             DUMP_TO_FILE(mInFile, s_dec_ip.pv_stream_buffer, s_dec_ip.u4_num_Bytes);
694 
695             if (s_dec_ip.u4_num_Bytes > 0) {
696                 char *ptr = (char *)s_dec_ip.pv_stream_buffer;
697             }
698 
699             GETTIME(&mTimeStart, NULL);
700             /* Compute time elapsed between end of previous decode()
701              * to start of current decode() */
702             TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
703 
704             IV_API_CALL_STATUS_T status;
705             status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
706 
707             bool unsupportedDimensions = (IMPEG2D_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code);
708             bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
709 
710             getSeqInfo();
711 
712             GETTIME(&mTimeEnd, NULL);
713             /* Compute time taken for decode() */
714             TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
715 
716             ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
717                    s_dec_op.u4_num_bytes_consumed);
718             if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
719                 mFlushNeeded = true;
720             }
721 
722             if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
723                 /* If the input did not contain picture data, then ignore
724                  * the associated timestamp */
725                 mTimeStampsValid[timeStampIx] = false;
726             }
727 
728             // This is needed to handle CTS DecoderTest testCodecResetsMPEG2WithoutSurface,
729             // which is not sending SPS/PPS after port reconfiguration and flush to the codec.
730             if (unsupportedDimensions && !mFlushNeeded) {
731                 bool portWillReset = false;
732                 handlePortSettingsChange(&portWillReset, s_dec_op.u4_pic_wd, s_dec_op.u4_pic_ht);
733 
734                 if (OK != reInitDecoder()) {
735                     ALOGE("Failed to reinitialize decoder");
736                     return;
737                 }
738 
739                 if (setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) {
740                     ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
741                 }
742                 return;
743             }
744 
745             // If the decoder is in the changing resolution mode and there is no output present,
746             // that means the switching is done and it's ready to reset the decoder and the plugin.
747             if (mChangingResolution && !s_dec_op.u4_output_present) {
748                 mChangingResolution = false;
749                 resetDecoder();
750                 resetPlugin();
751                 mStride = outputBufferWidth();
752                 setParams(mStride);
753                 continue;
754             }
755 
756             if (unsupportedDimensions || resChanged) {
757                 mChangingResolution = true;
758                 if (mFlushNeeded) {
759                     setFlushMode();
760                 }
761 
762                 if (unsupportedDimensions) {
763                     mNewWidth = s_dec_op.u4_pic_wd;
764                     mNewHeight = s_dec_op.u4_pic_ht;
765                     mInitNeeded = true;
766                 }
767                 continue;
768             }
769 
770             // Combine the resolution change and coloraspects change in one PortSettingChange event
771             // if necessary.
772             if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
773                 uint32_t width = s_dec_op.u4_pic_wd;
774                 uint32_t height = s_dec_op.u4_pic_ht;
775                 bool portWillReset = false;
776                 handlePortSettingsChange(&portWillReset, width, height);
777 
778                 if (portWillReset) {
779                     resetDecoder();
780                     resetPlugin();
781                     return;
782                 }
783             } else if (mUpdateColorAspects) {
784                 notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
785                     kDescribeColorAspectsIndex, NULL);
786                 mUpdateColorAspects = false;
787                 return;
788             }
789 
790             if (s_dec_op.u4_output_present) {
791                 ssize_t timeStampIdx;
792                 outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
793 
794                 timeStampIdx = getMinTimestampIdx(mTimeStamps, mTimeStampsValid);
795                 if (timeStampIdx < 0) {
796                     ALOGE("b/62872863, Invalid timestamp index!");
797                     android_errorWriteLog(0x534e4554, "62872863");
798                     return;
799                 }
800                 outHeader->nTimeStamp = mTimeStamps[timeStampIdx];
801                 mTimeStampsValid[timeStampIdx] = false;
802 
803                 /* mWaitForI waits for the first I picture. Once made FALSE, it
804                    has to remain false till explicitly set to TRUE. */
805                 mWaitForI = mWaitForI && !(IV_I_FRAME == s_dec_op.e_pic_type);
806 
807                 if (mWaitForI) {
808                     s_dec_op.u4_output_present = false;
809                 } else {
810                     ALOGV("Output timestamp: %lld, res: %ux%u",
811                             (long long)outHeader->nTimeStamp, mWidth, mHeight);
812                     DUMP_TO_FILE(mOutFile, outHeader->pBuffer, outHeader->nFilledLen);
813                     outInfo->mOwnedByUs = false;
814                     outQueue.erase(outQueue.begin());
815                     outInfo = NULL;
816                     notifyFillBufferDone(outHeader);
817                     outHeader = NULL;
818                 }
819             } else if (mIsInFlush) {
820                 /* If in flush mode and no output is returned by the codec,
821                  * then come out of flush mode */
822                 mIsInFlush = false;
823 
824                 /* If EOS was recieved on input port and there is no output
825                  * from the codec, then signal EOS on output port */
826                 if (mReceivedEOS) {
827                     outHeader->nFilledLen = 0;
828                     outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
829 
830                     outInfo->mOwnedByUs = false;
831                     outQueue.erase(outQueue.begin());
832                     outInfo = NULL;
833                     notifyFillBufferDone(outHeader);
834                     outHeader = NULL;
835                     resetPlugin();
836                 }
837             }
838         }
839 
840         /* If input EOS is seen and decoder is not in flush mode,
841          * set the decoder in flush mode.
842          * There can be a case where EOS is sent along with last picture data
843          * In that case, only after decoding that input data, decoder has to be
844          * put in flush. This case is handled here  */
845 
846         if (mReceivedEOS && !mIsInFlush) {
847             setFlushMode();
848         }
849 
850         // TODO: Handle more than one picture data
851         if (inHeader != NULL) {
852             inInfo->mOwnedByUs = false;
853             inQueue.erase(inQueue.begin());
854             inInfo = NULL;
855             notifyEmptyBufferDone(inHeader);
856             inHeader = NULL;
857         }
858     }
859 }
860 
getColorAspectPreference()861 int SoftMPEG2::getColorAspectPreference() {
862     return kPreferBitstream;
863 }
864 
865 }  // namespace android
866 
createSoftOMXComponent(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)867 android::SoftOMXComponent *createSoftOMXComponent(
868         const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
869         OMX_COMPONENTTYPE **component) {
870     return new android::SoftMPEG2(name, callbacks, appData, component);
871 }
872