Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / MPEG-4 visual p2 xvid decoder filter
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 :
27 : #include <gpac/filters.h>
28 : #include <gpac/avparse.h>
29 : #include <gpac/constants.h>
30 :
31 :
32 : /*if we don't have M4V (A)SP parser, we con't get width and height and xvid is then unusable ...*/
33 : #if !defined(GPAC_DISABLE_AV_PARSERS) && defined(GPAC_HAS_XVID)
34 :
35 : #if !defined(__GNUC__)
36 : # if defined(_WIN32_WCE) || defined (WIN32)
37 : # pragma comment(lib, "libxvidcore")
38 : # endif
39 : #endif
40 :
41 :
42 : #include <xvid.h>
43 :
44 : #ifndef XVID_DEC_FRAME
45 : #define XVID_DEC_FRAME xvid_dec_frame_t
46 : #define XVID_DEC_PARAM xvid_dec_create_t
47 : #else
48 : #define XVID_USE_OLD_API
49 : #endif
50 :
51 : //#undef XVID_USE_OLD_API
52 :
53 : static Bool xvid_is_init = GF_FALSE;
54 :
55 : typedef struct
56 : {
57 : Bool deblock_y;
58 : Bool deblock_uv;
59 : #ifndef XVID_USE_OLD_API
60 : Bool film_effect;
61 : Bool dering_y;
62 : Bool dering_uv;
63 : #endif
64 :
65 : GF_FilterPid *ipid, *opid;
66 : u32 cfg_crc;
67 : void *codec;
68 :
69 : u32 width, height, out_size;
70 : GF_Fraction pixel_ar;
71 : Bool first_frame;
72 : s32 base_filters;
73 : Float FPS;
74 : u32 offset;
75 :
76 : GF_List *src_packets;
77 : u64 next_cts;
78 :
79 : } GF_XVIDCtx;
80 :
81 29 : static GF_Err xviddec_initialize(GF_Filter *filter)
82 : {
83 29 : GF_XVIDCtx *ctx = gf_filter_get_udta(filter);
84 29 : if (!xvid_is_init) {
85 : #ifdef XVID_USE_OLD_API
86 : XVID_INIT_PARAM init;
87 : init.api_version = 0;
88 : init.core_build = 0;
89 : /*get info*/
90 : init.cpu_flags = XVID_CPU_CHKONLY;
91 : xvid_init(NULL, 0, &init, NULL);
92 : /*then init*/
93 : xvid_init(NULL, 0, &init, NULL);
94 : #else
95 : xvid_gbl_init_t init;
96 29 : init.debug = 0;
97 29 : init.version = XVID_VERSION;
98 29 : init.cpu_flags = 0; /*autodetect*/
99 29 : xvid_global(NULL, 0, &init, NULL);
100 : #endif
101 29 : xvid_is_init = GF_TRUE;
102 : }
103 :
104 : #ifndef XVID_USE_OLD_API
105 29 : if (ctx->film_effect) ctx->base_filters |= XVID_FILMEFFECT;
106 : #endif
107 :
108 : #ifdef XVID_USE_OLD_API
109 : if (ctx->deblock_y) ctx->base_filters |= XVID_DEC_DEBLOCKY;
110 : #else
111 29 : if (ctx->deblock_y) ctx->base_filters |= XVID_DEBLOCKY;
112 : #endif
113 :
114 : #ifdef XVID_USE_OLD_API
115 : if (ctx->deblock_uv) ctx->base_filters |= XVID_DEC_DEBLOCKUV;
116 : #else
117 29 : if (ctx->deblock_uv) ctx->base_filters |= XVID_DEBLOCKUV;
118 : #endif
119 :
120 : #ifndef XVID_USE_OLD_API
121 29 : if (ctx->dering_y) ctx->base_filters |= XVID_DERINGY | XVID_DEBLOCKY;
122 29 : if (ctx->dering_uv) ctx->base_filters |= XVID_DERINGUV | XVID_DEBLOCKUV;
123 : #endif
124 29 : ctx->src_packets = gf_list_new();
125 29 : return GF_OK;
126 : }
127 :
128 30 : static GF_Err xviddec_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
129 : {
130 : const GF_PropertyValue *p;
131 : GF_M4VDecSpecInfo dsi;
132 : GF_Err e;
133 : Bool is_first = GF_FALSE;
134 : #ifdef XVID_USE_OLD_API
135 : XVID_DEC_FRAME frame;
136 : XVID_DEC_PARAM par;
137 : #else
138 : xvid_dec_frame_t frame;
139 : xvid_dec_create_t par;
140 : #endif
141 30 : GF_XVIDCtx *ctx = gf_filter_get_udta(filter);
142 :
143 30 : if (is_remove) {
144 0 : if (ctx->opid) {
145 0 : gf_filter_pid_remove(ctx->opid);
146 0 : ctx->opid = NULL;
147 : }
148 0 : ctx->ipid = NULL;
149 0 : return GF_OK;
150 : }
151 30 : if (! gf_filter_pid_check_caps(pid))
152 : return GF_NOT_SUPPORTED;
153 :
154 29 : ctx->ipid = pid;
155 29 : if (!ctx->opid) {
156 29 : ctx->opid = gf_filter_pid_new(filter);
157 29 : gf_filter_pid_set_framing_mode(ctx->ipid, GF_TRUE);
158 : is_first = GF_TRUE;
159 : }
160 : //copy properties at init or reconfig
161 29 : gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
162 29 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_RAW) );
163 :
164 29 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
165 29 : if (p && p->value.data.ptr && p->value.data.size) {
166 29 : u32 ex_crc = gf_crc_32(p->value.data.ptr, p->value.data.size);
167 29 : if (ctx->cfg_crc == ex_crc) return GF_OK;
168 :
169 : //shoud we flush ?
170 29 : if (ctx->codec) xvid_decore(ctx->codec, XVID_DEC_DESTROY, NULL, NULL);
171 29 : ctx->codec = NULL;
172 :
173 29 : ctx->cfg_crc = ex_crc;
174 0 : } else if (!is_first) {
175 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[XVID] Reconfiguring without DSI not yet supported\n"));
176 : return GF_NOT_SUPPORTED;
177 : } else {
178 : return GF_OK;
179 : }
180 :
181 : /*decode DSI*/
182 29 : e = gf_m4v_get_config(p->value.data.ptr, p->value.data.size, &dsi);
183 29 : if (e) return e;
184 29 : if (!dsi.width || !dsi.height) return GF_NON_COMPLIANT_BITSTREAM;
185 :
186 : memset(&par, 0, sizeof(par));
187 29 : par.width = dsi.width;
188 29 : par.height = dsi.height;
189 : /*note that this may be irrelevant when used through systems (FPS is driven by systems CTS)*/
190 29 : ctx->FPS = dsi.clock_rate;
191 29 : ctx->FPS /= 1000;
192 29 : if (!ctx->FPS) ctx->FPS = 30.0f;
193 29 : ctx->pixel_ar.num = dsi.par_num;
194 29 : ctx->pixel_ar.den = dsi.par_den;
195 :
196 : #ifndef XVID_USE_OLD_API
197 29 : par.version = XVID_VERSION;
198 : #endif
199 :
200 29 : if (xvid_decore(NULL, XVID_DEC_CREATE, &par, NULL) < 0) return GF_NON_COMPLIANT_BITSTREAM;
201 :
202 29 : ctx->width = par.width;
203 29 : ctx->height = par.height;
204 29 : ctx->codec = par.handle;
205 :
206 : /*init decoder*/
207 : memset(&frame, 0, sizeof(frame));
208 29 : frame.bitstream = (void *) p->value.data.ptr;
209 29 : frame.length = p->value.data.size;
210 : #ifndef XVID_USE_OLD_API
211 29 : frame.version = XVID_VERSION;
212 29 : xvid_decore(ctx->codec, XVID_DEC_DECODE, &frame, NULL);
213 : #else
214 : /*don't perform error check, XviD doesn't like DSI only frame ...*/
215 : xvid_decore(ctx->codec, XVID_DEC_DECODE, &frame, NULL);
216 : #endif
217 :
218 29 : ctx->first_frame = GF_TRUE;
219 29 : ctx->out_size = ctx->width * ctx->height * 3 / 2;
220 :
221 29 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_WIDTH, &PROP_UINT(ctx->width) );
222 29 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_HEIGHT, &PROP_UINT(ctx->height) );
223 29 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STRIDE, &PROP_UINT(ctx->width) );
224 29 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PAR, &PROP_FRAC(ctx->pixel_ar) );
225 29 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PIXFMT, &PROP_UINT(GF_PIXEL_YUV) );
226 :
227 29 : return GF_OK;
228 : }
229 :
230 29 : static void xviddec_finalize(GF_Filter *filter)
231 : {
232 29 : GF_XVIDCtx *ctx = gf_filter_get_udta(filter);
233 29 : if (ctx->codec) xvid_decore(ctx->codec, XVID_DEC_DESTROY, NULL, NULL);
234 35 : while (gf_list_count(ctx->src_packets)) {
235 6 : GF_FilterPacket *pck = gf_list_pop_back(ctx->src_packets);
236 6 : gf_filter_pck_unref(pck);
237 : }
238 29 : gf_list_del(ctx->src_packets);
239 29 : }
240 :
241 4106 : static GF_Err xviddec_process(GF_Filter *filter)
242 : {
243 : #ifdef XVID_USE_OLD_API
244 : XVID_DEC_FRAME frame;
245 : #else
246 : xvid_dec_frame_t frame;
247 : #endif
248 : u8 *buffer;
249 : u32 i, count;
250 : Bool is_seek;
251 : #if 0
252 : s32 postproc;
253 : #endif
254 : s32 res;
255 4106 : GF_XVIDCtx *ctx = gf_filter_get_udta(filter);
256 : GF_FilterPacket *pck, *pck_ref, *src_pck, *dst_pck;
257 :
258 4106 : pck = gf_filter_pid_get_packet(ctx->ipid);
259 :
260 4106 : if (!ctx->codec)
261 0 : return ctx->cfg_crc ? GF_SERVICE_ERROR : GF_OK;
262 :
263 : memset(&frame, 0, sizeof(frame));
264 4106 : if (pck) {
265 4021 : u64 cts = gf_filter_pck_get_cts(pck);;
266 4021 : frame.bitstream = (char *) gf_filter_pck_get_data(pck, &frame.length);
267 :
268 : //append in cts order since we get output frames in cts order
269 4021 : pck_ref = pck;
270 4021 : gf_filter_pck_ref_props(&pck_ref);
271 4021 : count = gf_list_count(ctx->src_packets);
272 : src_pck = NULL;
273 5453 : for (i=0; i<count; i++) {
274 : u64 acts;
275 3992 : src_pck = gf_list_get(ctx->src_packets, i);
276 3992 : acts = gf_filter_pck_get_cts(src_pck);
277 3992 : if (acts==cts) {
278 0 : gf_filter_pck_unref(pck_ref);
279 0 : break;
280 : }
281 3992 : if (acts>cts) {
282 2560 : gf_list_insert(ctx->src_packets, pck_ref, i);
283 2560 : break;
284 : }
285 : src_pck = NULL;
286 : }
287 4021 : if (!src_pck)
288 1461 : gf_list_add(ctx->src_packets, pck_ref);
289 :
290 :
291 : } else {
292 : frame.bitstream = NULL;
293 85 : frame.length = -1;
294 : }
295 :
296 : packed_frame :
297 :
298 4106 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, ctx->width*ctx->height*3/2, &buffer);
299 4106 : if (!dst_pck) return GF_OUT_OF_MEM;
300 :
301 : #ifdef XVID_USE_OLD_API
302 : frame.colorspace = XVID_CSP_I420;
303 : frame.stride = ctx->width;
304 : frame.image = (void *) buffer;
305 : #else
306 4106 : frame.version = XVID_VERSION;
307 4106 : frame.output.csp = XVID_CSP_I420;
308 4106 : frame.output.stride[0] = ctx->width;
309 4106 : frame.output.plane[0] = (void *) buffer;
310 : #endif
311 :
312 :
313 : #if 0
314 : postproc = ctx->base_filters;
315 : /*to check, not convinced yet by results...*/
316 : switch (mmlevel) {
317 : case GF_CODEC_LEVEL_SEEK:
318 : case GF_CODEC_LEVEL_DROP:
319 : /*turn off all post-proc*/
320 : #ifdef XVID_USE_OLD_API
321 : postproc &= ~XVID_DEC_DEBLOCKY;
322 : postproc &= ~XVID_DEC_DEBLOCKUV;
323 : #else
324 : postproc &= ~XVID_DEBLOCKY;
325 : postproc &= ~XVID_DEBLOCKUV;
326 : postproc &= ~XVID_FILMEFFECT;
327 : #endif
328 : break;
329 : case GF_CODEC_LEVEL_VERY_LATE:
330 : /*turn off post-proc*/
331 : #ifdef XVID_USE_OLD_API
332 : postproc &= ~XVID_DEC_DEBLOCKY;
333 : #else
334 : postproc &= ~XVID_FILMEFFECT;
335 : postproc &= ~XVID_DEBLOCKY;
336 : #endif
337 : break;
338 : case GF_CODEC_LEVEL_LATE:
339 : #ifdef XVID_USE_OLD_API
340 : postproc &= ~XVID_DEC_DEBLOCKUV;
341 : #else
342 : postproc &= ~XVID_DEBLOCKUV;
343 : postproc &= ~XVID_FILMEFFECT;
344 : #endif
345 : break;
346 : }
347 : #endif
348 :
349 : /*xvid may keep the first I frame and force a 1-frame delay, so we simply trick it*/
350 4106 : if (ctx->first_frame) {
351 29 : buffer[0] = 'v';
352 29 : buffer[1] = 'o';
353 29 : buffer[2] = 'i';
354 29 : buffer[3] = 'd';
355 : }
356 4106 : src_pck = gf_list_get(ctx->src_packets, 0);
357 :
358 4106 : res = xvid_decore(ctx->codec, XVID_DEC_DECODE, &frame, NULL);
359 4106 : if (res < 0) {
360 62 : gf_filter_pck_discard(dst_pck);
361 62 : if (pck) gf_filter_pid_drop_packet(ctx->ipid);
362 62 : if (src_pck) {
363 0 : gf_filter_pck_unref(src_pck);
364 0 : gf_list_pop_front(ctx->src_packets);
365 : }
366 62 : if (gf_filter_pid_is_eos(ctx->ipid)) {
367 11 : gf_filter_pid_set_eos(ctx->opid);
368 11 : return GF_EOS;
369 : }
370 51 : return pck ? GF_NON_COMPLIANT_BITSTREAM : GF_OK;
371 : }
372 :
373 4044 : if (ctx->first_frame) {
374 29 : ctx->first_frame = GF_FALSE;
375 29 : if ((buffer[0] == 'v') && (buffer[1] == 'o') && (buffer[2] == 'i') && (buffer[3] =='d')) {
376 29 : gf_filter_pck_discard(dst_pck);
377 29 : if (pck) gf_filter_pid_drop_packet(ctx->ipid);
378 : return GF_OK;
379 : }
380 : }
381 :
382 4015 : if (src_pck) {
383 4015 : gf_filter_pck_merge_properties(src_pck, dst_pck);
384 4015 : is_seek = gf_filter_pck_get_seek_flag(src_pck);
385 4015 : ctx->next_cts = gf_filter_pck_get_cts(src_pck);
386 4015 : ctx->next_cts += gf_filter_pck_get_duration(src_pck);
387 4015 : gf_filter_pck_unref(src_pck);
388 4015 : gf_list_pop_front(ctx->src_packets);
389 : } else {
390 : is_seek = 0;
391 0 : gf_filter_pck_set_cts(dst_pck, ctx->next_cts);
392 : }
393 :
394 4015 : if (!pck || !is_seek )
395 4015 : gf_filter_pck_send(dst_pck);
396 : else
397 0 : gf_filter_pck_discard(dst_pck);
398 :
399 4015 : if (res + 6 < frame.length) {
400 0 : frame.bitstream = ((char *)frame.bitstream) + res;
401 0 : frame.length -= res;
402 0 : goto packed_frame;
403 : }
404 :
405 4015 : if (pck) {
406 3992 : gf_filter_pid_drop_packet(ctx->ipid);
407 : }
408 : //flush all frames if eos is detected
409 23 : else if (gf_filter_pid_is_eos(ctx->ipid)) {
410 6 : return xviddec_process(filter);
411 : }
412 :
413 : return GF_OK;
414 : }
415 :
416 : static const GF_FilterCapability XVIDCaps[] =
417 : {
418 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
419 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG4_PART2),
420 : CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
421 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
422 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
423 : };
424 :
425 : #define OFFS(_n) #_n, offsetof(GF_XVIDCtx, _n)
426 :
427 : static const GF_FilterArgs XVIDArgs[] =
428 : {
429 : { OFFS(deblock_y), "enable Y deblocking", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
430 : { OFFS(deblock_uv), "enable UV deblocking", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
431 : #ifndef XVID_USE_OLD_API
432 : { OFFS(film_effect), "enable film effect", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
433 : { OFFS(dering_y), "enable Y deblocking", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
434 : { OFFS(dering_uv), "enable UV deblocking", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
435 : #endif
436 : {0}
437 : };
438 :
439 : GF_FilterRegister XVIDRegister = {
440 : .name = "xviddec",
441 : GF_FS_SET_DESCRIPTION("XVid decoder")
442 : GF_FS_SET_HELP("This filter decodes MPEG-4 part 2 (and DivX) through libxvidcore library.")
443 : .private_size = sizeof(GF_XVIDCtx),
444 : .args = XVIDArgs,
445 : SETCAPS(XVIDCaps),
446 : .initialize = xviddec_initialize,
447 : .finalize = xviddec_finalize,
448 : .configure_pid = xviddec_configure_pid,
449 : .process = xviddec_process,
450 : //use low priorty, below ffmpeg one, so that hardware decs/other native impl in gpac can take over if needed
451 : //don't use lowest one since we use this for scalable codecs
452 : .priority = 100
453 : };
454 :
455 : #endif
456 :
457 2877 : const GF_FilterRegister *xviddec_register(GF_FilterSession *session)
458 : {
459 : #if !defined(GPAC_DISABLE_AV_PARSERS) && defined(GPAC_HAS_XVID)
460 2877 : return &XVIDRegister;
461 : #else
462 : return NULL;
463 : #endif
464 : }
|