xref: /rockchip-linux_mpp/mpp/codec/dec/h263/h263d_api.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
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