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 "h263d_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 "h263d_api.h"
27 #include "h263d_parser.h"
28
29 #define h263d_INIT_STREAM_SIZE SZ_64K
30
31 typedef struct {
32 // parameter interact with mpp_dec
33 MppBufSlots frame_slots;
34 MppBufSlots packet_slots;
35 MppDecCfgSet *cfg;
36
37 RK_U8 *stream;
38 size_t stream_size;
39 MppPacket task_pkt;
40 RK_S64 task_pts;
41 RK_S64 task_dts;
42 RK_U32 task_eos;
43
44 // runtime parameter
45 RK_U32 frame_count;
46
47 // parser context
48 H263dParser parser;
49 } H263dCtx;
50
h263d_init(void * dec,ParserCfg * cfg)51 MPP_RET h263d_init(void *dec, ParserCfg *cfg)
52 {
53 H263dParser parser = NULL;
54 MppPacket task_pkt = NULL;
55 H263dCtx *p;
56 MPP_RET ret;
57 RK_U8 *stream;
58 size_t stream_size = h263d_INIT_STREAM_SIZE;
59
60 if (NULL == dec) {
61 mpp_err_f("found NULL intput dec %p cfg %p\n", dec, cfg);
62 return MPP_ERR_NULL_PTR;
63 }
64
65 stream = mpp_malloc_size(RK_U8, stream_size);
66 if (NULL == stream) {
67 mpp_err_f("failed to malloc stream buffer size %d\n", stream_size);
68 return MPP_ERR_MALLOC;
69 }
70
71 ret = mpp_packet_init(&task_pkt, stream, stream_size);
72 if (ret) {
73 mpp_err_f("failed to create mpp_packet for task\n");
74 goto ERR_RET;
75 }
76
77 // reset task packet length to zero
78 // NOTE: set length must after set pos
79 mpp_packet_set_pos(task_pkt, stream);
80 mpp_packet_set_length(task_pkt, 0);
81
82 ret = mpp_h263_parser_init(&parser, cfg->frame_slots);
83 if (ret) {
84 mpp_err_f("failed to init parser\n");
85 goto ERR_RET;
86 }
87
88 p = (H263dCtx *)dec;
89 p->frame_slots = cfg->frame_slots;
90 p->packet_slots = cfg->packet_slots;
91 p->cfg = cfg->cfg;
92 p->stream = stream;
93 p->stream_size = stream_size;
94 p->task_pkt = task_pkt;
95 p->parser = parser;
96
97 return MPP_OK;
98 ERR_RET:
99 if (task_pkt) {
100 mpp_packet_deinit(&task_pkt);
101 }
102 if (stream) {
103 mpp_free(stream);
104 stream = NULL;
105 }
106 return ret;
107 }
108
h263d_deinit(void * dec)109 MPP_RET h263d_deinit(void *dec)
110 {
111 H263dCtx *p;
112 if (NULL == dec) {
113 mpp_err_f("found NULL intput\n");
114 return MPP_ERR_NULL_PTR;
115 }
116
117 p = (H263dCtx *)dec;
118 if (p->parser) {
119 mpp_h263_parser_deinit(p->parser);
120 p->parser = NULL;
121 }
122
123 if (p->task_pkt) {
124 mpp_packet_deinit(&p->task_pkt);
125 }
126
127 if (p->stream) {
128 mpp_free(p->stream);
129 p->stream = NULL;
130 }
131 return MPP_OK;
132 }
133
h263d_reset(void * dec)134 MPP_RET h263d_reset(void *dec)
135 {
136 if (NULL == dec) {
137 mpp_err_f("found NULL intput\n");
138 return MPP_ERR_NULL_PTR;
139 }
140
141 H263dCtx *p = (H263dCtx *)dec;
142 return mpp_h263_parser_reset(p->parser);
143 }
144
145
h263d_flush(void * dec)146 MPP_RET h263d_flush(void *dec)
147 {
148 if (NULL == dec) {
149 mpp_err_f("found NULL intput\n");
150 return MPP_ERR_NULL_PTR;
151 }
152
153 H263dCtx *p = (H263dCtx *)dec;
154 return mpp_h263_parser_flush(p->parser);
155 }
156
157
h263d_control(void * dec,MpiCmd cmd_type,void * param)158 MPP_RET h263d_control(void *dec, MpiCmd cmd_type, void *param)
159 {
160 if (NULL == dec) {
161 mpp_err_f("found NULL intput\n");
162 return MPP_ERR_NULL_PTR;
163 }
164 (void)cmd_type;
165 (void)param;
166 return MPP_OK;
167 }
168
h263d_prepare(void * dec,MppPacket pkt,HalDecTask * task)169 MPP_RET h263d_prepare(void *dec, MppPacket pkt, HalDecTask *task)
170 {
171 H263dCtx *p;
172 RK_U8 *pos;
173 size_t length;
174 RK_U32 eos;
175
176 if (NULL == dec || NULL == pkt || NULL == task) {
177 mpp_err_f("found NULL intput dec %p pkt %p task %p\n", dec, pkt, task);
178 return MPP_ERR_NULL_PTR;
179 }
180
181 p = (H263dCtx *)dec;
182 pos = mpp_packet_get_pos(pkt);
183 length = mpp_packet_get_length(pkt);
184 eos = mpp_packet_get_eos(pkt);
185
186 if (eos && !length) {
187 task->valid = 0;
188 task->flags.eos = 1;
189 mpp_log("h263d flush eos");
190 h263d_flush(dec);
191 return MPP_OK;
192 }
193
194 if (NULL == p->stream) {
195 mpp_err("failed to malloc task buffer for hardware with size %d\n", length);
196 return MPP_ERR_UNKNOW;
197 }
198
199 if (!p->cfg->base.split_parse) {
200 /*
201 * Copy packet mode:
202 * Decoder's user will insure each packet is one frame for process
203 * Parser will just copy packet to the beginning of stream buffer
204 */
205 if (length > p->stream_size) {
206 // NOTE: here we double the buffer length to reduce frequency of realloc
207 do {
208 p->stream_size <<= 1;
209 } while (length > p->stream_size);
210
211 mpp_free(p->stream);
212 p->stream = mpp_malloc_size(RK_U8, p->stream_size);
213 mpp_assert(p->stream);
214 mpp_packet_set_data(p->task_pkt, p->stream);
215 mpp_packet_set_size(p->task_pkt, p->stream_size);
216 }
217
218 memcpy(p->stream, pos, length);
219 mpp_packet_set_pos(p->task_pkt, p->stream);
220 mpp_packet_set_length(p->task_pkt, length);
221 // set input packet length to 0 here
222 // indicate that the input packet has been all consumed
223 mpp_packet_set_pos(pkt, pos + length);
224 // always use latest pts for current packet
225 p->task_pts = mpp_packet_get_pts(pkt);
226 p->task_dts = mpp_packet_get_dts(pkt);
227 p->task_eos = mpp_packet_get_eos(pkt);
228 /* this step will enable the task and goto parse stage */
229 task->valid = 1;
230 } else {
231 /*
232 * Split packet mode:
233 * Input packet can be any length and no need to be bound of on frame
234 * Parser will do split frame operation to find the beginning and end of one frame
235 */
236 /*
237 * NOTE: on split mode total length is the left size plus the new incoming
238 * packet length.
239 */
240 size_t remain_length = mpp_packet_get_length(p->task_pkt);
241 size_t total_length = remain_length + length;
242 if (total_length > p->stream_size) {
243 RK_U8 *dst;
244 do {
245 p->stream_size <<= 1;
246 } while (length > p->stream_size);
247
248 // NOTE; split mode need to copy remaining stream to new buffer
249 dst = mpp_malloc_size(RK_U8, p->stream_size);
250 mpp_assert(dst);
251
252 memcpy(dst, p->stream, remain_length);
253 mpp_free(p->stream);
254 p->stream = dst;
255 mpp_packet_set_data(p->task_pkt, p->stream);
256 mpp_packet_set_size(p->task_pkt, p->stream_size);
257 }
258
259 // start parser split
260 if (MPP_OK == mpp_h263_parser_split(p->parser, p->task_pkt, pkt)) {
261 task->valid = 1;
262 }
263 p->task_pts = mpp_packet_get_pts(p->task_pkt);
264 p->task_dts = mpp_packet_get_dts(p->task_pkt);
265 p->task_eos = mpp_packet_get_eos(p->task_pkt);
266 }
267
268 mpp_packet_set_pts(p->task_pkt, p->task_pts);
269 mpp_packet_set_dts(p->task_pkt, p->task_dts);
270 task->input_packet = p->task_pkt;
271 task->flags.eos = p->task_eos;
272
273 return MPP_OK;
274 }
275
h263d_parse(void * dec,HalDecTask * task)276 MPP_RET h263d_parse(void *dec, HalDecTask *task)
277 {
278 MPP_RET ret;
279 H263dCtx *p;
280
281 if (NULL == dec || NULL == task) {
282 mpp_err_f("found NULL intput dec %p task %p\n", dec, task);
283 return MPP_ERR_NULL_PTR;
284 }
285 p = (H263dCtx *)dec;
286 ret = mpp_h263_parser_decode(p->parser, task->input_packet);
287 if (ret) {
288 // found error on decoding drop this task and clear remaining length
289 task->valid = 0;
290 task->output = -1;
291 mpp_packet_set_length(task->input_packet, 0);
292 return MPP_NOK;
293 }
294
295 mpp_h263_parser_setup_syntax(p->parser, &task->syntax);
296 mpp_h263_parser_setup_hal_output(p->parser, &task->output);
297 mpp_h263_parser_setup_refer(p->parser, task->refer, MAX_DEC_REF_NUM);
298 mpp_h263_parser_update_dpb(p->parser);
299
300 p->frame_count++;
301
302 return MPP_OK;
303 }
304
h263d_callback(void * dec,void * err_info)305 MPP_RET h263d_callback(void *dec, void *err_info)
306 {
307 (void)dec;
308 (void)err_info;
309 return MPP_OK;
310 }
311
312 const ParserApi api_h263d_parser = {
313 .name = "api_h263d_parser",
314 .coding = MPP_VIDEO_CodingH263,
315 .ctx_size = sizeof(H263dCtx),
316 .flag = 0,
317 .init = h263d_init,
318 .deinit = h263d_deinit,
319 .prepare = h263d_prepare,
320 .parse = h263d_parse,
321 .reset = h263d_reset,
322 .flush = h263d_flush,
323 .control = h263d_control,
324 .callback = h263d_callback,
325 };
326
327