• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 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 #include "GoldfishH264Helper.h"
18 
19 #define LOG_TAG "GoldfishH264Helper"
20 #include <log/log.h>
21 
22 
23 #define DEBUG 0
24 #if DEBUG
25 #define DDD(...) ALOGD(__VA_ARGS__)
26 #else
27 #define DDD(...) ((void)0)
28 #endif
29 
30 
31 #include <Codec2Mapper.h>
32 
33 #define ivdec_api_function              ih264d_api_function
34 #define ivdext_create_ip_t              ih264d_create_ip_t
35 #define ivdext_create_op_t              ih264d_create_op_t
36 #define ivdext_delete_ip_t              ih264d_delete_ip_t
37 #define ivdext_delete_op_t              ih264d_delete_op_t
38 #define ivdext_ctl_set_num_cores_ip_t   ih264d_ctl_set_num_cores_ip_t
39 #define ivdext_ctl_set_num_cores_op_t   ih264d_ctl_set_num_cores_op_t
40 #define ivdext_ctl_get_vui_params_ip_t  ih264d_ctl_get_vui_params_ip_t
41 #define ivdext_ctl_get_vui_params_op_t  ih264d_ctl_get_vui_params_op_t
42 #define ALIGN128(x)                     ((((x) + 127) >> 7) << 7)
43 #define MAX_NUM_CORES                   4
44 #define IVDEXT_CMD_CTL_SET_NUM_CORES    \
45         (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES
46 #define MIN(a, b)                       (((a) < (b)) ? (a) : (b))
47 
48 namespace android {
49 
ivd_aligned_malloc(void * ctxt,WORD32 alignment,WORD32 size)50 static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) {
51     (void) ctxt;
52     return memalign(alignment, size);
53 }
54 
ivd_aligned_free(void * ctxt,void * mem)55 static void ivd_aligned_free(void *ctxt, void *mem) {
56     (void) ctxt;
57     free(mem);
58 }
59 
60 
GoldfishH264Helper(int w,int h)61 GoldfishH264Helper::GoldfishH264Helper(int w, int h):mWidth(w),mHeight(h) { createDecoder(); }
62 
~GoldfishH264Helper()63 GoldfishH264Helper::~GoldfishH264Helper() {
64     destroyDecoder();
65 }
66 
createDecoder()67 void GoldfishH264Helper::createDecoder() {
68     ivdext_create_ip_t s_create_ip = {};
69     ivdext_create_op_t s_create_op = {};
70 
71     s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
72     s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
73     s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
74     s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorformat;
75     s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc;
76     s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free;
77     s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = nullptr;
78     s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t);
79     IV_API_CALL_STATUS_T status =
80         ivdec_api_function(mDecHandle, &s_create_ip, &s_create_op);
81     if (status != IV_SUCCESS) {
82         ALOGE("error in %s: 0x%x", __func__,
83               s_create_op.s_ivd_create_op_t.u4_error_code);
84         return;
85     }
86     mDecHandle = (iv_obj_t *)s_create_op.s_ivd_create_op_t.pv_handle;
87     mDecHandle->pv_fxns = (void *)ivdec_api_function;
88     mDecHandle->u4_size = sizeof(iv_obj_t);
89 
90     mStride = ALIGN128(mWidth);
91 
92     setNumCores();
93 }
94 
destroyDecoder()95 void GoldfishH264Helper::destroyDecoder() {
96     if (mDecHandle) {
97         ivdext_delete_ip_t s_delete_ip = {};
98         ivdext_delete_op_t s_delete_op = {};
99 
100         s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t);
101         s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE;
102         s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t);
103         IV_API_CALL_STATUS_T status =
104             ivdec_api_function(mDecHandle, &s_delete_ip, &s_delete_op);
105         if (status != IV_SUCCESS) {
106             ALOGE("error in %s: 0x%x", __func__,
107                   s_delete_op.s_ivd_delete_op_t.u4_error_code);
108         }
109         mDecHandle = nullptr;
110     }
111 }
112 
setNumCores()113 void GoldfishH264Helper::setNumCores() {
114     ivdext_ctl_set_num_cores_ip_t s_set_num_cores_ip = {};
115     ivdext_ctl_set_num_cores_op_t s_set_num_cores_op = {};
116 
117     s_set_num_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
118     s_set_num_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
119     s_set_num_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
120     s_set_num_cores_ip.u4_num_cores = mNumCores;
121     s_set_num_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
122     IV_API_CALL_STATUS_T status = ivdec_api_function(
123         mDecHandle, &s_set_num_cores_ip, &s_set_num_cores_op);
124     if (IV_SUCCESS != status) {
125         DDD("error in %s: 0x%x", __func__, s_set_num_cores_op.u4_error_code);
126     }
127 }
128 
resetDecoder()129 void GoldfishH264Helper::resetDecoder() {
130     ivd_ctl_reset_ip_t s_reset_ip = {};
131     ivd_ctl_reset_op_t s_reset_op = {};
132 
133     s_reset_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
134     s_reset_ip.e_cmd = IVD_CMD_VIDEO_CTL;
135     s_reset_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
136     s_reset_op.u4_size = sizeof(ivd_ctl_reset_op_t);
137     IV_API_CALL_STATUS_T status =
138         ivdec_api_function(mDecHandle, &s_reset_ip, &s_reset_op);
139     if (IV_SUCCESS != status) {
140         ALOGE("error in %s: 0x%x", __func__, s_reset_op.u4_error_code);
141     }
142     setNumCores();
143 }
144 
setParams(size_t stride,IVD_VIDEO_DECODE_MODE_T dec_mode)145 void GoldfishH264Helper::setParams(size_t stride,
146                                    IVD_VIDEO_DECODE_MODE_T dec_mode) {
147     ih264d_ctl_set_config_ip_t s_h264d_set_dyn_params_ip = {};
148     ih264d_ctl_set_config_op_t s_h264d_set_dyn_params_op = {};
149     ivd_ctl_set_config_ip_t *ps_set_dyn_params_ip =
150         &s_h264d_set_dyn_params_ip.s_ivd_ctl_set_config_ip_t;
151     ivd_ctl_set_config_op_t *ps_set_dyn_params_op =
152         &s_h264d_set_dyn_params_op.s_ivd_ctl_set_config_op_t;
153 
154     ps_set_dyn_params_ip->u4_size = sizeof(ih264d_ctl_set_config_ip_t);
155     ps_set_dyn_params_ip->e_cmd = IVD_CMD_VIDEO_CTL;
156     ps_set_dyn_params_ip->e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
157     ps_set_dyn_params_ip->u4_disp_wd = (UWORD32) stride;
158     ps_set_dyn_params_ip->e_frm_skip_mode = IVD_SKIP_NONE;
159     ps_set_dyn_params_ip->e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
160     ps_set_dyn_params_ip->e_vid_dec_mode = dec_mode;
161     ps_set_dyn_params_op->u4_size = sizeof(ih264d_ctl_set_config_op_t);
162     IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
163                                                      &s_h264d_set_dyn_params_ip,
164                                                      &s_h264d_set_dyn_params_op);
165     if (status != IV_SUCCESS) {
166         ALOGE("error in %s: 0x%x", __func__,
167               ps_set_dyn_params_op->u4_error_code);
168     }
169 }
170 
isSpsFrame(const uint8_t * frame,int inSize)171 bool GoldfishH264Helper::isSpsFrame(const uint8_t* frame, int inSize) {
172     if (inSize < 5) return false;
173     if (frame[0] == 0 && frame[1] == 0 && frame[2] == 0 && frame[3] == 1) {
174         const bool forbiddenBitIsInvalid = 0x80 & frame[4];
175         if (forbiddenBitIsInvalid) {
176             return false;
177         }
178         // nalu type is the lower 5 bits
179         uint8_t naluType = 0x1f & frame[4];
180         if (naluType == 7
181             || naluType == 8
182                 ) return true;
183         else return false;
184     } else {
185         return false;
186     }
187 }
188 
decodeHeader(const uint8_t * frame,int inSize)189 bool GoldfishH264Helper::decodeHeader(const uint8_t *frame, int inSize) {
190     // should we check the header for vps/sps/pps frame ? otherwise
191     // there is no point calling decoder
192     if (!isSpsFrame(frame, inSize)) {
193         DDD("could not find valid vps frame");
194         return false;
195     } else {
196         DDD("found valid vps frame");
197     }
198 
199     ih264d_video_decode_ip_t s_h264d_decode_ip = {};
200     ih264d_video_decode_op_t s_h264d_decode_op = {};
201     ivd_video_decode_ip_t *ps_decode_ip = &s_h264d_decode_ip.s_ivd_video_decode_ip_t;
202     ivd_video_decode_op_t *ps_decode_op = &s_h264d_decode_op.s_ivd_video_decode_op_t;
203 
204     // setup input/output arguments to decoder
205     setDecodeArgs(ps_decode_ip, ps_decode_op, frame, mStride,
206             0, // offset
207             inSize, // size
208             0 // time-stamp, does not matter
209             );
210 
211     setParams(mStride, IVD_DECODE_HEADER);
212 
213     // now kick off the decoding
214     IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, ps_decode_ip, ps_decode_op);
215     if (status != IV_SUCCESS) {
216         ALOGE("failed to call decoder function for header\n");
217         ALOGE("error in %s: 0x%x", __func__,
218               ps_decode_op->u4_error_code);
219     }
220 
221     if (IVD_RES_CHANGED == (ps_decode_op->u4_error_code & IVD_ERROR_MASK)) {
222         DDD("resolution changed, reset decoder");
223         resetDecoder();
224         setParams(mStride, IVD_DECODE_HEADER);
225         ivdec_api_function(mDecHandle, ps_decode_ip, ps_decode_op);
226     }
227 
228     // get the w/h and update
229     if (0 < ps_decode_op->u4_pic_wd && 0 < ps_decode_op->u4_pic_ht) {
230         DDD("success decode w/h %d %d", ps_decode_op->u4_pic_wd , ps_decode_op->u4_pic_ht);
231         DDD("existing w/h %d %d", mWidth, mHeight);
232         if (ps_decode_op->u4_pic_wd != mWidth ||  ps_decode_op->u4_pic_ht != mHeight) {
233             mWidth = ps_decode_op->u4_pic_wd;
234             mHeight = ps_decode_op->u4_pic_ht;
235             return true;
236         } else {
237             DDD("success decode w/h, but they are the same %d %d", ps_decode_op->u4_pic_wd , ps_decode_op->u4_pic_ht);
238         }
239     } else {
240         ALOGE("could not decode w/h");
241     }
242 
243     // get output delay
244     if (ps_decode_op->i4_reorder_depth >= 0) {
245         if (mOutputDelay != ps_decode_op->i4_reorder_depth) {
246             mOutputDelay = ps_decode_op->i4_reorder_depth;
247             DDD("New Output delay %d ", mOutputDelay);
248         } else {
249             DDD("same Output delay %d ", mOutputDelay);
250         }
251     }
252 
253     return false;
254 }
255 
setDecodeArgs(ivd_video_decode_ip_t * ps_decode_ip,ivd_video_decode_op_t * ps_decode_op,const uint8_t * inBuffer,uint32_t displayStride,size_t inOffset,size_t inSize,uint32_t tsMarker)256 bool GoldfishH264Helper::setDecodeArgs(ivd_video_decode_ip_t *ps_decode_ip,
257                                        ivd_video_decode_op_t *ps_decode_op,
258                                        const uint8_t *inBuffer,
259                                        uint32_t displayStride, size_t inOffset,
260                                        size_t inSize, uint32_t tsMarker) {
261     uint32_t displayHeight = mHeight;
262     size_t lumaSize = displayStride * displayHeight;
263     size_t chromaSize = lumaSize >> 2;
264 
265     if (mStride != displayStride) {
266         mStride = displayStride;
267     }
268 
269     // force decoder to always decode header and get dimensions,
270     // hope this will be quick and cheap
271     setParams(mStride, IVD_DECODE_HEADER);
272 
273     ps_decode_ip->u4_size = sizeof(ih264d_video_decode_ip_t);
274     ps_decode_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
275     if (inBuffer) {
276         ps_decode_ip->u4_ts = tsMarker;
277         ps_decode_ip->pv_stream_buffer = const_cast<uint8_t *>(inBuffer) + inOffset;
278         ps_decode_ip->u4_num_Bytes = inSize;
279     } else {
280         ps_decode_ip->u4_ts = 0;
281         ps_decode_ip->pv_stream_buffer = nullptr;
282         ps_decode_ip->u4_num_Bytes = 0;
283     }
284     DDD("setting pv_stream_buffer 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
285             ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[0],
286             ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[1],
287             ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[2],
288             ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[3],
289             ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[4],
290             ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[5],
291             ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[6],
292             ((uint8_t*)(ps_decode_ip->pv_stream_buffer))[7]
293             );
294     DDD("input bytes %d", ps_decode_ip->u4_num_Bytes);
295 
296     ps_decode_ip->s_out_buffer.u4_min_out_buf_size[0] = lumaSize;
297     ps_decode_ip->s_out_buffer.u4_min_out_buf_size[1] = chromaSize;
298     ps_decode_ip->s_out_buffer.u4_min_out_buf_size[2] = chromaSize;
299     {
300         ps_decode_ip->s_out_buffer.pu1_bufs[0] = nullptr;
301         ps_decode_ip->s_out_buffer.pu1_bufs[1] = nullptr;
302         ps_decode_ip->s_out_buffer.pu1_bufs[2] = nullptr;
303     }
304     ps_decode_ip->s_out_buffer.u4_num_bufs = 3;
305     ps_decode_op->u4_size = sizeof(ih264d_video_decode_op_t);
306     ps_decode_op->u4_output_present = 0;
307 
308     return true;
309 }
310 
311 } // namespace android
312