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