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