1 /*
2 *
3 * Copyright 2015 Rockchip Electronics Co. LTD
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #define MODULE_TAG "mpg4d_api"
19
20 #include <string.h>
21
22 #include "mpp_mem.h"
23 #include "mpp_debug.h"
24 #include "mpp_common.h"
25
26 #include "mpg4d_api.h"
27 #include "mpg4d_parser.h"
28 #include "mpp_packet_impl.h"
29 #include "mpp_dec_cb_param.h"
30
31 #define MPG4D_INIT_STREAM_SIZE SZ_64K
32
33 typedef struct {
34 // parameter interact with mpp_dec
35 MppBufSlots frame_slots;
36 MppBufSlots packet_slots;
37 RK_S32 task_count;
38 RK_U8 *stream;
39 size_t stream_size;
40 size_t left_length;
41 MppPacket task_pkt;
42 RK_U32 got_eos;
43
44 // runtime parameter
45 RK_U32 need_split;
46 RK_U32 frame_count;
47 RK_U32 internal_pts;
48
49 // parser context
50 Mpg4dParser parser;
51 } Mpg4dCtx;
52
mpg4d_init(void * dec,ParserCfg * cfg)53 static MPP_RET mpg4d_init(void *dec, ParserCfg *cfg)
54 {
55 Mpg4dParser parser = NULL;
56 MppPacket task_pkt = NULL;
57 Mpg4dCtx *p;
58 MPP_RET ret;
59 RK_U8 *stream;
60 size_t stream_size = MPG4D_INIT_STREAM_SIZE;
61
62 if (NULL == dec) {
63 mpp_err_f("found NULL intput dec %p cfg %p\n", dec, cfg);
64 return MPP_ERR_NULL_PTR;
65 }
66
67 stream = mpp_malloc_size(RK_U8, stream_size);
68 if (NULL == stream) {
69 mpp_err_f("failed to malloc stream buffer size %d\n", stream_size);
70 return MPP_ERR_MALLOC;
71 }
72
73 ret = mpp_packet_init(&task_pkt, stream, stream_size);
74 if (ret) {
75 mpp_err_f("failed to create mpp_packet for task\n");
76 goto ERR_RET;
77 }
78
79 // reset task packet length to zero
80 // NOTE: set length must after set pos
81 mpp_packet_set_pos(task_pkt, stream);
82 mpp_packet_set_length(task_pkt, 0);
83
84 ret = mpp_mpg4_parser_init(&parser, cfg);
85 if (ret) {
86 mpp_err_f("failed to init parser\n");
87 goto ERR_RET;
88 }
89
90 p = (Mpg4dCtx *)dec;
91 p->frame_slots = cfg->frame_slots;
92 p->packet_slots = cfg->packet_slots;
93 p->task_count = 2;
94 #ifdef __ANDROID__
95 p->need_split = 1;//cfg->need_split;
96 #else
97 p->need_split = cfg->cfg->base.split_parse;
98 #endif
99 p->internal_pts = cfg->cfg->base.internal_pts;
100 p->stream = stream;
101 p->stream_size = stream_size;
102 p->task_pkt = task_pkt;
103 p->parser = parser;
104 p->left_length = 0;
105 return MPP_OK;
106 ERR_RET:
107 if (task_pkt) {
108 mpp_packet_deinit(&task_pkt);
109 }
110 if (stream) {
111 mpp_free(stream);
112 stream = NULL;
113 }
114 return ret;
115 }
116
mpg4d_deinit(void * dec)117 static MPP_RET mpg4d_deinit(void *dec)
118 {
119 Mpg4dCtx *p;
120 if (NULL == dec) {
121 mpp_err_f("found NULL intput\n");
122 return MPP_ERR_NULL_PTR;
123 }
124
125 p = (Mpg4dCtx *)dec;
126 if (p->parser) {
127 mpp_mpg4_parser_deinit(p->parser);
128 p->parser = NULL;
129 }
130
131 if (p->task_pkt) {
132 mpp_packet_deinit(&p->task_pkt);
133 }
134
135 if (p->stream) {
136 mpp_free(p->stream);
137 p->stream = NULL;
138 }
139 return MPP_OK;
140 }
141
mpg4d_reset(void * dec)142 static MPP_RET mpg4d_reset(void *dec)
143 {
144 if (NULL == dec) {
145 mpp_err_f("found NULL intput\n");
146 return MPP_ERR_NULL_PTR;
147 }
148
149 Mpg4dCtx *p = (Mpg4dCtx *)dec;
150 p->left_length = 0;
151 p->got_eos = 0;
152 mpp_packet_set_length(p->task_pkt, 0);
153 mpp_packet_set_flag(p->task_pkt, 0);
154
155 return mpp_mpg4_parser_reset(p->parser);
156 }
157
mpg4d_flush(void * dec)158 static MPP_RET mpg4d_flush(void *dec)
159 {
160 if (NULL == dec) {
161 mpp_err_f("found NULL intput\n");
162 return MPP_ERR_NULL_PTR;
163 }
164
165 Mpg4dCtx *p = (Mpg4dCtx *)dec;
166 return mpp_mpg4_parser_flush(p->parser);
167 }
168
mpg4d_control(void * dec,MpiCmd cmd_type,void * param)169 static MPP_RET mpg4d_control(void *dec, MpiCmd cmd_type, void *param)
170 {
171 if (NULL == dec) {
172 mpp_err_f("found NULL intput\n");
173 return MPP_ERR_NULL_PTR;
174 }
175 (void)cmd_type;
176 (void)param;
177 return MPP_OK;
178 }
179
mpg4d_prepare(void * dec,MppPacket pkt,HalDecTask * task)180 static MPP_RET mpg4d_prepare(void *dec, MppPacket pkt, HalDecTask *task)
181 {
182 Mpg4dCtx *p;
183 RK_U8 *pos;
184 size_t length;
185 RK_U32 eos;
186
187 if (NULL == dec || NULL == pkt || NULL == task) {
188 mpp_err_f("found NULL intput dec %p pkt %p task %p\n", dec, pkt, task);
189 return MPP_ERR_NULL_PTR;
190 }
191
192 task->valid = 0;
193 p = (Mpg4dCtx *)dec;
194 pos = mpp_packet_get_pos(pkt);
195 length = mpp_packet_get_length(pkt);
196 eos = mpp_packet_get_eos(pkt);
197
198 if (p->got_eos) {
199 mpp_log_f("has got eos packet.\n");
200 mpp_packet_set_length(pkt, 0);
201 return MPP_OK;
202 }
203
204 if (NULL == p->stream) {
205 mpp_err("failed to malloc task buffer for hardware with size %d\n", length);
206 return MPP_ERR_UNKNOW;
207 }
208 mpp_packet_set_length(p->task_pkt, p->left_length);
209
210 /*
211 * Check have enough buffer to store stream
212 * NOTE: total length is the left size plus the new incoming
213 * packet length.
214 */
215 size_t total_length = MPP_ALIGN(p->left_length + length, 16) + 64; // add extra 64 bytes in tails
216
217 if (total_length > p->stream_size) {
218 RK_U8 *dst = NULL;
219 do {
220 p->stream_size <<= 1;
221 } while (total_length > p->stream_size);
222
223 dst = mpp_malloc_size(RK_U8, p->stream_size);
224 mpp_assert(dst);
225 // NOTE: copy remaining stream to new buffer
226 if (p->left_length > 0) {
227 memcpy(dst, p->stream, p->left_length);
228 }
229 mpp_free(p->stream);
230 p->stream = dst;
231 mpp_packet_set_data(p->task_pkt, p->stream);
232 mpp_packet_set_size(p->task_pkt, p->stream_size);
233 }
234
235 if (!p->need_split ||
236 (mpp_packet_get_flag(pkt) & MPP_PACKET_FLAG_EXTRA_DATA)) {
237 p->got_eos = eos;
238 task->flags.eos = eos;
239 // NOTE: empty eos packet
240 if (eos && !length) {
241 mpg4d_flush(dec);
242 return MPP_OK;
243 }
244 /*
245 * Copy packet mode:
246 * Decoder's user will insure each packet is one frame for process
247 * Parser will just copy packet to the beginning of stream buffer
248 */
249 memcpy(p->stream, pos, length);
250 mpp_packet_set_pos(p->task_pkt, p->stream);
251 mpp_packet_set_length(p->task_pkt, length);
252 mpp_packet_set_pts(p->task_pkt, mpp_packet_get_pts(pkt));
253 // set input packet length to 0 here
254 // indicate that the input packet has been all consumed
255 mpp_packet_set_pos(pkt, pos + length);
256 mpp_packet_set_length(pkt, 0);
257 /* this step will enable the task and goto parse stage */
258 task->valid = 1;
259 } else {
260 /*
261 * Split packet mode:
262 * Input packet can be any length and no need to be bound of on frame
263 * Parser will do split frame operation to find the beginning and end of one frame
264 */
265 if (MPP_OK == mpp_mpg4_parser_split(p->parser, p->task_pkt, pkt)) {
266 p->left_length = 0;
267 task->valid = 1;
268 } else {
269 task->valid = 0;
270 p->left_length = mpp_packet_get_length(p->task_pkt);
271 }
272 p->got_eos = mpp_packet_get_eos(p->task_pkt);
273 task->flags.eos = p->got_eos;
274 }
275 task->input_packet = p->task_pkt;
276
277 return MPP_OK;
278 }
279
mpg4d_parse(void * dec,HalDecTask * task)280 static MPP_RET mpg4d_parse(void *dec, HalDecTask *task)
281 {
282 MPP_RET ret;
283 Mpg4dCtx *p;
284
285 if (NULL == dec || NULL == task) {
286 mpp_err_f("found NULL intput dec %p task %p\n", dec, task);
287 return MPP_ERR_NULL_PTR;
288 }
289 p = (Mpg4dCtx *)dec;
290 ret = mpp_mpg4_parser_decode(p->parser, task->input_packet);
291 if (ret) {
292 // found error on decoding drop this task and clear remaining length
293 task->valid = 0;
294 task->output = -1;
295 mpp_packet_set_length(task->input_packet, 0);
296
297 return MPP_NOK;
298 }
299
300 mpp_mpg4_parser_setup_syntax(p->parser, &task->syntax);
301 mpp_mpg4_parser_setup_hal_output(p->parser, &task->output);
302 mpp_mpg4_parser_setup_refer(p->parser, task->refer, MAX_DEC_REF_NUM);
303 mpp_mpg4_parser_update_dpb(p->parser);
304
305 if (p->got_eos) {
306 task->flags.eos = 1;
307 mpg4d_flush(dec);
308 return MPP_OK;
309 }
310
311 p->frame_count++;
312
313 return MPP_OK;
314 }
315
mpg4d_callback(void * dec,void * err_info)316 static MPP_RET mpg4d_callback(void *dec, void *err_info)
317 {
318 Mpg4dCtx *p_Dec = (Mpg4dCtx *)dec;
319 DecCbHalDone *ctx = (DecCbHalDone *)err_info;
320
321 if (NULL == dec || NULL == err_info) {
322 mpp_err_f("found NULL input dec %p err_info %p\n", dec, err_info);
323 return MPP_ERR_NULL_PTR;
324 }
325
326 MppFrame mframe = NULL;
327 HalDecTask *task_dec = (HalDecTask *)ctx->task;
328
329 mpp_buf_slot_get_prop(p_Dec->frame_slots, task_dec->output, SLOT_FRAME_PTR, &mframe);
330 if (mframe) {
331 RK_U32 task_err = task_dec->flags.parse_err || task_dec->flags.ref_err;
332 if (ctx->hard_err || task_err) {
333 mpp_frame_set_errinfo(mframe, MPP_FRAME_ERR_UNKNOW);
334 mpp_log_f("[CALLBACK] g_no=%d, out_idx=%d, dpberr=%d, harderr=%d, ref_flag=%d, errinfo=%d, discard=%d\n",
335 p_Dec->frame_count, task_dec->output, task_err, ctx->hard_err, task_dec->flags.used_for_ref,
336 mpp_frame_get_errinfo(mframe), mpp_frame_get_discard(mframe));
337 }
338 }
339 return MPP_OK;
340 }
341
342 const ParserApi api_mpg4d_parser = {
343 .name = "api_mpg4d_parser",
344 .coding = MPP_VIDEO_CodingMPEG4,
345 .ctx_size = sizeof(Mpg4dCtx),
346 .flag = 0,
347 .init = mpg4d_init,
348 .deinit = mpg4d_deinit,
349 .prepare = mpg4d_prepare,
350 .parse = mpg4d_parse,
351 .reset = mpg4d_reset,
352 .flush = mpg4d_flush,
353 .control = mpg4d_control,
354 .callback = mpg4d_callback,
355 };
356
357