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