xref: /aosp_15_r20/frameworks/av/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1 /*
2  * Copyright (C) 2014 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 "SoftHEVC"
19 #include <utils/Log.h>
20 
21 #include "ihevc_typedefs.h"
22 #include "iv.h"
23 #include "ivd.h"
24 #include "ihevcd_cxa.h"
25 #include "SoftHEVC.h"
26 
27 #include <media/stagefright/foundation/ADebug.h>
28 #include <media/stagefright/foundation/AUtils.h>
29 #include <media/stagefright/MediaDefs.h>
30 #include <OMX_VideoExt.h>
31 
32 namespace android {
33 
34 #define componentName                   "video_decoder.hevc"
35 #define codingType                      OMX_VIDEO_CodingHEVC
36 #define CODEC_MIME_TYPE                 MEDIA_MIMETYPE_VIDEO_HEVC
37 
38 /** Function and structure definitions to keep code similar for each codec */
39 #define ivdec_api_function              ihevcd_cxa_api_function
40 #define ivdext_create_ip_t              ihevcd_cxa_create_ip_t
41 #define ivdext_create_op_t              ihevcd_cxa_create_op_t
42 #define ivdext_delete_ip_t              ihevcd_cxa_delete_ip_t
43 #define ivdext_delete_op_t              ihevcd_cxa_delete_op_t
44 #define ivdext_ctl_set_num_cores_ip_t   ihevcd_cxa_ctl_set_num_cores_ip_t
45 #define ivdext_ctl_set_num_cores_op_t   ihevcd_cxa_ctl_set_num_cores_op_t
46 
47 #define IVDEXT_CMD_CTL_SET_NUM_CORES    \
48         (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES
49 
50 static const CodecProfileLevel kProfileLevels[] = {
51     { OMX_VIDEO_HEVCProfileMain,      OMX_VIDEO_HEVCMainTierLevel51 },
52     { OMX_VIDEO_HEVCProfileMainStill, OMX_VIDEO_HEVCMainTierLevel51 },
53 };
54 
SoftHEVC(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)55 SoftHEVC::SoftHEVC(
56         const char *name,
57         const OMX_CALLBACKTYPE *callbacks,
58         OMX_PTR appData,
59         OMX_COMPONENTTYPE **component)
60     : SoftVideoDecoderOMXComponent(name, componentName, codingType,
61             kProfileLevels, ARRAY_SIZE(kProfileLevels),
62             320 /* width */, 240 /* height */, callbacks,
63             appData, component),
64       mCodecCtx(NULL),
65       mFlushOutBuffer(NULL),
66       mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
67       mIvColorFormat(IV_YUV_420P),
68       mChangingResolution(false),
69       mSignalledError(false),
70       mStride(mWidth) {
71     const size_t kMinCompressionRatio = 4 /* compressionRatio (for Level 4+) */;
72     const size_t kMaxOutputBufferSize = 2048 * 2048 * 3 / 2;
73     // INPUT_BUF_SIZE is given by HEVC codec as minimum input size
74     initPorts(
75             kNumBuffers, max(kMaxOutputBufferSize / kMinCompressionRatio, (size_t)INPUT_BUF_SIZE),
76             kNumBuffers, CODEC_MIME_TYPE, kMinCompressionRatio);
77 }
78 
init()79 status_t SoftHEVC::init() {
80     return initDecoder();
81 }
82 
~SoftHEVC()83 SoftHEVC::~SoftHEVC() {
84     ALOGV("In SoftHEVC::~SoftHEVC");
85     CHECK_EQ(deInitDecoder(), (status_t)OK);
86 }
87 
ivd_aligned_malloc(void * ctxt,WORD32 alignment,WORD32 size)88 static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) {
89     UNUSED(ctxt);
90     return memalign(alignment, size);
91 }
92 
ivd_aligned_free(void * ctxt,void * buf)93 static void ivd_aligned_free(void *ctxt, void *buf) {
94     UNUSED(ctxt);
95     free(buf);
96     return;
97 }
98 
GetCPUCoreCount()99 static size_t GetCPUCoreCount() {
100     long cpuCoreCount = 1;
101 #if defined(_SC_NPROCESSORS_ONLN)
102     cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
103 #else
104     // _SC_NPROC_ONLN must be defined...
105     cpuCoreCount = sysconf(_SC_NPROC_ONLN);
106 #endif
107     CHECK(cpuCoreCount >= 1);
108     ALOGV("Number of CPU cores: %ld", cpuCoreCount);
109     return (size_t)cpuCoreCount;
110 }
111 
logVersion()112 void SoftHEVC::logVersion() {
113     ivd_ctl_getversioninfo_ip_t s_ctl_ip;
114     ivd_ctl_getversioninfo_op_t s_ctl_op;
115     UWORD8 au1_buf[512];
116     IV_API_CALL_STATUS_T status;
117 
118     s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
119     s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION;
120     s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t);
121     s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t);
122     s_ctl_ip.pv_version_buffer = au1_buf;
123     s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf);
124 
125     status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip,
126             (void *)&s_ctl_op);
127 
128     if (status != IV_SUCCESS) {
129         ALOGE("Error in getting version number: 0x%x",
130                 s_ctl_op.u4_error_code);
131     } else {
132         ALOGV("Ittiam decoder version number: %s",
133                 (char *)s_ctl_ip.pv_version_buffer);
134     }
135     return;
136 }
137 
setParams(size_t stride)138 status_t SoftHEVC::setParams(size_t stride) {
139     ivd_ctl_set_config_ip_t s_ctl_ip;
140     ivd_ctl_set_config_op_t s_ctl_op;
141     IV_API_CALL_STATUS_T status;
142     s_ctl_ip.u4_disp_wd = (UWORD32)stride;
143     s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
144 
145     s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
146     s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
147     s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
148     s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
149     s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
150     s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
151 
152     ALOGV("Set the run-time (dynamic) parameters stride = %zu", stride);
153     status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip,
154             (void *)&s_ctl_op);
155 
156     if (status != IV_SUCCESS) {
157         ALOGE("Error in setting the run-time parameters: 0x%x",
158                 s_ctl_op.u4_error_code);
159 
160         return UNKNOWN_ERROR;
161     }
162     return OK;
163 }
164 
resetPlugin()165 status_t SoftHEVC::resetPlugin() {
166     mIsInFlush = false;
167     mReceivedEOS = false;
168     memset(mTimeStamps, 0, sizeof(mTimeStamps));
169     memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid));
170 
171     /* Initialize both start and end times */
172     gettimeofday(&mTimeStart, NULL);
173     gettimeofday(&mTimeEnd, NULL);
174 
175     return OK;
176 }
177 
getVUIParams()178 bool SoftHEVC::getVUIParams() {
179     IV_API_CALL_STATUS_T status;
180     ihevcd_cxa_ctl_get_vui_params_ip_t s_ctl_get_vui_params_ip;
181     ihevcd_cxa_ctl_get_vui_params_op_t s_ctl_get_vui_params_op;
182 
183     s_ctl_get_vui_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;
184     s_ctl_get_vui_params_ip.e_sub_cmd =
185         (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_GET_VUI_PARAMS;
186 
187     s_ctl_get_vui_params_ip.u4_size =
188         sizeof(ihevcd_cxa_ctl_get_vui_params_ip_t);
189 
190     s_ctl_get_vui_params_op.u4_size = sizeof(ihevcd_cxa_ctl_get_vui_params_op_t);
191 
192     status = ivdec_api_function(
193             (iv_obj_t *)mCodecCtx, (void *)&s_ctl_get_vui_params_ip,
194             (void *)&s_ctl_get_vui_params_op);
195 
196     if (status != IV_SUCCESS) {
197         ALOGW("Error in getting VUI params: 0x%x",
198                 s_ctl_get_vui_params_op.u4_error_code);
199         return false;
200     }
201 
202     int32_t primaries = s_ctl_get_vui_params_op.u1_colour_primaries;
203     int32_t transfer = s_ctl_get_vui_params_op.u1_transfer_characteristics;
204     int32_t coeffs = s_ctl_get_vui_params_op.u1_matrix_coefficients;
205     bool fullRange = s_ctl_get_vui_params_op.u1_video_full_range_flag;
206 
207     ColorAspects colorAspects;
208     ColorUtils::convertIsoColorAspectsToCodecAspects(
209             primaries, transfer, coeffs, fullRange, colorAspects);
210 
211     // Update color aspects if necessary.
212     if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) {
213         mBitstreamColorAspects = colorAspects;
214         status_t err = handleColorAspectsChange();
215         CHECK(err == OK);
216     }
217     return true;
218 }
219 
resetDecoder()220 status_t SoftHEVC::resetDecoder() {
221     ivd_ctl_reset_ip_t s_ctl_ip;
222     ivd_ctl_reset_op_t s_ctl_op;
223     IV_API_CALL_STATUS_T status;
224 
225     s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
226     s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
227     s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
228     s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
229 
230     status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip,
231             (void *)&s_ctl_op);
232     if (IV_SUCCESS != status) {
233         ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code);
234         return UNKNOWN_ERROR;
235     }
236     mSignalledError = false;
237 
238     /* Set number of cores/threads to be used by the codec */
239     setNumCores();
240 
241     mStride = 0;
242     return OK;
243 }
244 
setNumCores()245 status_t SoftHEVC::setNumCores() {
246     ivdext_ctl_set_num_cores_ip_t s_set_cores_ip;
247     ivdext_ctl_set_num_cores_op_t s_set_cores_op;
248     IV_API_CALL_STATUS_T status;
249     s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
250     s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
251     s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES);
252     s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
253     s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
254     ALOGV("Set number of cores to %u", s_set_cores_ip.u4_num_cores);
255     status = ivdec_api_function(mCodecCtx, (void *)&s_set_cores_ip,
256             (void *)&s_set_cores_op);
257     if (IV_SUCCESS != status) {
258         ALOGE("Error in setting number of cores: 0x%x",
259                 s_set_cores_op.u4_error_code);
260         return UNKNOWN_ERROR;
261     }
262     return OK;
263 }
264 
setFlushMode()265 status_t SoftHEVC::setFlushMode() {
266     IV_API_CALL_STATUS_T status;
267     ivd_ctl_flush_ip_t s_video_flush_ip;
268     ivd_ctl_flush_op_t s_video_flush_op;
269 
270     s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL;
271     s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
272     s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
273     s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t);
274     ALOGV("Set the decoder in flush mode ");
275 
276     /* Set the decoder in Flush mode, subsequent decode() calls will flush */
277     status = ivdec_api_function(mCodecCtx, (void *)&s_video_flush_ip,
278             (void *)&s_video_flush_op);
279 
280     if (status != IV_SUCCESS) {
281         ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status,
282                 s_video_flush_op.u4_error_code);
283         return UNKNOWN_ERROR;
284     }
285 
286     mIsInFlush = true;
287     return OK;
288 }
289 
initDecoder()290 status_t SoftHEVC::initDecoder() {
291     IV_API_CALL_STATUS_T status;
292 
293     mNumCores = GetCPUCoreCount();
294     mCodecCtx = NULL;
295 
296     mStride = outputBufferWidth();
297 
298     /* Initialize the decoder */
299     {
300         ivdext_create_ip_t s_create_ip;
301         ivdext_create_op_t s_create_op;
302 
303         void *dec_fxns = (void *)ivdec_api_function;
304 
305         s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
306         s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
307         s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
308         s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t);
309         s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorFormat;
310         s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc;
311         s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free;
312         s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL;
313 
314         status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op);
315 
316         if (status != IV_SUCCESS) {
317             ALOGE("Error in create: 0x%x",
318                     s_create_op.s_ivd_create_op_t.u4_error_code);
319             deInitDecoder();
320             mCodecCtx = NULL;
321             return UNKNOWN_ERROR;
322         }
323 
324         mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
325         mCodecCtx->pv_fxns = dec_fxns;
326         mCodecCtx->u4_size = sizeof(iv_obj_t);
327     }
328 
329     /* Reset the plugin state */
330     resetPlugin();
331 
332     /* Set the run time (dynamic) parameters */
333     setParams(mStride);
334 
335     /* Set number of cores/threads to be used by the codec */
336     setNumCores();
337 
338     /* Get codec version */
339     logVersion();
340 
341     mFlushNeeded = false;
342     return OK;
343 }
344 
deInitDecoder()345 status_t SoftHEVC::deInitDecoder() {
346     size_t i;
347     IV_API_CALL_STATUS_T status;
348 
349     if (mCodecCtx) {
350         ivdext_delete_ip_t s_delete_ip;
351         ivdext_delete_op_t s_delete_op;
352 
353         s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t);
354         s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE;
355 
356         s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t);
357 
358         status = ivdec_api_function(mCodecCtx, (void *)&s_delete_ip, (void *)&s_delete_op);
359         if (status != IV_SUCCESS) {
360             ALOGE("Error in delete: 0x%x",
361                     s_delete_op.s_ivd_delete_op_t.u4_error_code);
362             return UNKNOWN_ERROR;
363         }
364     }
365 
366 
367     mChangingResolution = false;
368 
369     return OK;
370 }
371 
onReset()372 void SoftHEVC::onReset() {
373     ALOGV("onReset called");
374     SoftVideoDecoderOMXComponent::onReset();
375 
376     mSignalledError = false;
377     resetDecoder();
378     resetPlugin();
379 }
380 
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)381 bool SoftHEVC::setDecodeArgs(ivd_video_decode_ip_t *ps_dec_ip,
382         ivd_video_decode_op_t *ps_dec_op,
383         OMX_BUFFERHEADERTYPE *inHeader,
384         OMX_BUFFERHEADERTYPE *outHeader,
385         size_t timeStampIx) {
386     size_t sizeY = outputBufferWidth() * outputBufferHeight();
387     size_t sizeUV;
388 
389     ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t);
390     ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
391 
392     ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
393 
394     /* When in flush and after EOS with zero byte input,
395      * inHeader is set to zero. Hence check for non-null */
396     if (inHeader) {
397         ps_dec_ip->u4_ts = timeStampIx;
398         ps_dec_ip->pv_stream_buffer = inHeader->pBuffer
399                 + inHeader->nOffset;
400         ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen;
401     } else {
402         ps_dec_ip->u4_ts = 0;
403         ps_dec_ip->pv_stream_buffer = NULL;
404         ps_dec_ip->u4_num_Bytes = 0;
405     }
406 
407     sizeUV = sizeY / 4;
408     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY;
409     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
410     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
411 
412     uint8_t *pBuf;
413     if (outHeader) {
414         if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) {
415             android_errorWriteLog(0x534e4554, "27833616");
416             return false;
417         }
418         pBuf = outHeader->pBuffer;
419     } else {
420         // mFlushOutBuffer always has the right size.
421         pBuf = mFlushOutBuffer;
422     }
423 
424     ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf;
425     ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY;
426     ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV;
427     ps_dec_ip->s_out_buffer.u4_num_bufs = 3;
428     return true;
429 }
onPortFlushCompleted(OMX_U32 portIndex)430 void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) {
431     /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
432     if (kOutputPortIndex == portIndex) {
433         setFlushMode();
434 
435         /* Allocate a picture buffer to flushed data */
436         uint32_t displayStride = outputBufferWidth();
437         uint32_t displayHeight = outputBufferHeight();
438 
439         uint32_t bufferSize = displayStride * displayHeight * 3 / 2;
440         mFlushOutBuffer = (uint8_t *)memalign(128, bufferSize);
441         if (NULL == mFlushOutBuffer) {
442             ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize);
443             return;
444         }
445 
446         while (true) {
447             ivd_video_decode_ip_t s_dec_ip;
448             ivd_video_decode_op_t s_dec_op;
449             IV_API_CALL_STATUS_T status;
450             size_t sizeY, sizeUV;
451 
452             setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0);
453 
454             status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip,
455                     (void *)&s_dec_op);
456             if (0 == s_dec_op.u4_output_present) {
457                 resetPlugin();
458                 break;
459             }
460         }
461 
462         if (mFlushOutBuffer) {
463             free(mFlushOutBuffer);
464             mFlushOutBuffer = NULL;
465         }
466 
467     }
468 }
469 
onQueueFilled(OMX_U32 portIndex)470 void SoftHEVC::onQueueFilled(OMX_U32 portIndex) {
471     UNUSED(portIndex);
472 
473     if (mSignalledError) {
474         return;
475     }
476     if (mOutputPortSettingsChange != NONE) {
477         return;
478     }
479 
480     if (NULL == mCodecCtx) {
481         if (OK != initDecoder()) {
482             ALOGE("Failed to initialize decoder");
483             notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
484             mSignalledError = true;
485             return;
486         }
487     }
488     if (outputBufferWidth() != mStride) {
489         /* Set the run-time (dynamic) parameters */
490         mStride = outputBufferWidth();
491         setParams(mStride);
492     }
493 
494     List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
495     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
496 
497     while (!outQueue.empty()) {
498         BufferInfo *inInfo;
499         OMX_BUFFERHEADERTYPE *inHeader;
500 
501         BufferInfo *outInfo;
502         OMX_BUFFERHEADERTYPE *outHeader;
503         size_t timeStampIx;
504 
505         inInfo = NULL;
506         inHeader = NULL;
507 
508         if (!mIsInFlush) {
509             if (!inQueue.empty()) {
510                 inInfo = *inQueue.begin();
511                 inHeader = inInfo->mHeader;
512             } else {
513                 break;
514             }
515         }
516 
517         outInfo = *outQueue.begin();
518         outHeader = outInfo->mHeader;
519         outHeader->nFlags = 0;
520         outHeader->nTimeStamp = 0;
521         outHeader->nOffset = 0;
522 
523         if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
524             mReceivedEOS = true;
525             if (inHeader->nFilledLen == 0) {
526                 inQueue.erase(inQueue.begin());
527                 inInfo->mOwnedByUs = false;
528                 notifyEmptyBufferDone(inHeader);
529                 inHeader = NULL;
530                 setFlushMode();
531             }
532         }
533 
534         /* Get a free slot in timestamp array to hold input timestamp */
535         {
536             size_t i;
537             timeStampIx = 0;
538             for (i = 0; i < MAX_TIME_STAMPS; i++) {
539                 if (!mTimeStampsValid[i]) {
540                     timeStampIx = i;
541                     break;
542                 }
543             }
544             if (inHeader != NULL) {
545                 mTimeStampsValid[timeStampIx] = true;
546                 mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
547             }
548         }
549 
550         {
551             ivd_video_decode_ip_t s_dec_ip;
552             ivd_video_decode_op_t s_dec_op;
553             WORD32 timeDelay, timeTaken;
554             size_t sizeY, sizeUV;
555 
556             if (!setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) {
557                 ALOGE("Decoder arg setup failed");
558                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
559                 mSignalledError = true;
560                 return;
561             }
562 
563             GETTIME(&mTimeStart, NULL);
564             /* Compute time elapsed between end of previous decode()
565              * to start of current decode() */
566             TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
567 
568             IV_API_CALL_STATUS_T status;
569             status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
570 
571             bool unsupportedResolution =
572                 (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_dec_op.u4_error_code & IVD_ERROR_MASK));
573 
574             /* Check for unsupported dimensions */
575             if (unsupportedResolution) {
576                 ALOGE("Unsupported resolution : %dx%d", mWidth, mHeight);
577                 notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
578                 mSignalledError = true;
579                 return;
580             }
581 
582             bool allocationFailed =
583                 (IVD_MEM_ALLOC_FAILED == (s_dec_op.u4_error_code & IVD_ERROR_MASK));
584             if (allocationFailed) {
585                 ALOGE("Allocation failure in decoder");
586                 notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
587                 mSignalledError = true;
588                 return;
589             }
590 
591             if (IS_IVD_FATAL_ERROR(s_dec_op.u4_error_code)) {
592                 ALOGE("Fatal Error : 0x%x", s_dec_op.u4_error_code);
593                 notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
594                 mSignalledError = true;
595                 return;
596             }
597 
598             bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & IVD_ERROR_MASK));
599 
600             getVUIParams();
601 
602             GETTIME(&mTimeEnd, NULL);
603             /* Compute time taken for decode() */
604             TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
605 
606             ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
607                    s_dec_op.u4_num_bytes_consumed);
608             if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
609                 mFlushNeeded = true;
610             }
611 
612             if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
613                 /* If the input did not contain picture data, then ignore
614                  * the associated timestamp */
615                 mTimeStampsValid[timeStampIx] = false;
616             }
617 
618             // If the decoder is in the changing resolution mode and there is no output present,
619             // that means the switching is done and it's ready to reset the decoder and the plugin.
620             if (mChangingResolution && !s_dec_op.u4_output_present) {
621                 mChangingResolution = false;
622                 resetDecoder();
623                 resetPlugin();
624                 mStride = outputBufferWidth();
625                 setParams(mStride);
626                 continue;
627             }
628 
629             if (resChanged) {
630                 mChangingResolution = true;
631                 if (mFlushNeeded) {
632                     setFlushMode();
633                 }
634                 continue;
635             }
636 
637             // Combine the resolution change and coloraspects change in one PortSettingChange event
638             // if necessary.
639             if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
640                 uint32_t width = s_dec_op.u4_pic_wd;
641                 uint32_t height = s_dec_op.u4_pic_ht;
642                 bool portWillReset = false;
643                 handlePortSettingsChange(&portWillReset, width, height);
644 
645                 if (portWillReset) {
646                     resetDecoder();
647                     resetPlugin();
648                     return;
649                 }
650             } else if (mUpdateColorAspects) {
651                 notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
652                     kDescribeColorAspectsIndex, NULL);
653                 mUpdateColorAspects = false;
654                 return;
655             }
656 
657             if (s_dec_op.u4_output_present) {
658                 outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
659 
660                 outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts];
661                 mTimeStampsValid[s_dec_op.u4_ts] = false;
662 
663                 outInfo->mOwnedByUs = false;
664                 outQueue.erase(outQueue.begin());
665                 outInfo = NULL;
666                 notifyFillBufferDone(outHeader);
667                 outHeader = NULL;
668             } else if (mIsInFlush) {
669                 /* If in flush mode and no output is returned by the codec,
670                  * then come out of flush mode */
671                 mIsInFlush = false;
672 
673                 /* If EOS was recieved on input port and there is no output
674                  * from the codec, then signal EOS on output port */
675                 if (mReceivedEOS) {
676                     outHeader->nFilledLen = 0;
677                     outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
678 
679                     outInfo->mOwnedByUs = false;
680                     outQueue.erase(outQueue.begin());
681                     outInfo = NULL;
682                     notifyFillBufferDone(outHeader);
683                     outHeader = NULL;
684                     resetPlugin();
685                 }
686             }
687         }
688 
689         /* If input EOS is seen and decoder is not in flush mode,
690          * set the decoder in flush mode.
691          * There can be a case where EOS is sent along with last picture data
692          * In that case, only after decoding that input data, decoder has to be
693          * put in flush. This case is handled here  */
694 
695         if (mReceivedEOS && !mIsInFlush) {
696             setFlushMode();
697         }
698 
699         // TODO: Handle more than one picture data
700         if (inHeader != NULL) {
701             inInfo->mOwnedByUs = false;
702             inQueue.erase(inQueue.begin());
703             inInfo = NULL;
704             notifyEmptyBufferDone(inHeader);
705             inHeader = NULL;
706         }
707     }
708 }
709 
getColorAspectPreference()710 int SoftHEVC::getColorAspectPreference() {
711     return kPreferBitstream;
712 }
713 
714 }  // namespace android
715 
716 __attribute__((cfi_canonical_jump_table))
createSoftOMXComponent(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)717 android::SoftOMXComponent *createSoftOMXComponent(const char *name,
718         const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
719         OMX_COMPONENTTYPE **component) {
720     android::SoftHEVC *codec = new android::SoftHEVC(name, callbacks, appData, component);
721     if (codec->init() != android::OK) {
722         android::sp<android::SoftOMXComponent> release = codec;
723         return NULL;
724     }
725     return codec;
726 }
727