Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2005-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / AVI demuxer 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 : #include <gpac/filters.h>
27 : #include <gpac/constants.h>
28 : #include <gpac/thread.h>
29 : #include <gpac/list.h>
30 : #include <gpac/bitstream.h>
31 :
32 : #ifndef GPAC_DISABLE_AVILIB
33 : #include <gpac/internal/avilib.h>
34 : #include <gpac/media_tools.h>
35 :
36 : typedef struct
37 : {
38 : GF_FilterPid *opid;
39 : u32 stream_num;
40 : Bool in_use;
41 : u32 aud_frame, audio_bps, nb_channels, freq;
42 : u64 audio_ts, seek_to_ts;
43 : Bool audio_done, is_aac, playing, init_play_done;
44 : } AVIAstream;
45 :
46 :
47 : typedef struct
48 : {
49 : //opts
50 : GF_Fraction fps;
51 : Bool importer;
52 :
53 : GF_FilterPid *ipid;
54 :
55 : GF_FilterPid *v_opid;
56 : Bool v_in_use;
57 : u32 nb_frames, cur_frame, nb_frame_sent;
58 : u32 dummy, nvops;
59 : const char *src_url;
60 : avi_t *avi;
61 :
62 : Bool use_file_fps;
63 : GF_Fraction64 duration;
64 : Bool v_playing;
65 : Bool v_init_play_done;
66 :
67 : GF_List *audios;
68 : } GF_AVIDmxCtx;
69 :
70 :
71 11 : static void avidmx_setup(GF_Filter *filter, GF_AVIDmxCtx *ctx)
72 : {
73 : u32 sync_id = 0;
74 : u32 codecid = 0;
75 : Bool unframed;
76 : u32 i, count, pfmt=0;
77 : GF_Fraction64 dur;
78 : char *comp;
79 :
80 11 : if (ctx->use_file_fps) {
81 11 : Double fps = AVI_frame_rate(ctx->avi);
82 11 : gf_media_get_video_timing(fps, &ctx->fps.num, &ctx->fps.den);
83 : }
84 :
85 11 : dur.den = ctx->fps.num;
86 11 : dur.num = (u64) (ctx->fps.den * AVI_video_frames(ctx->avi));
87 :
88 : unframed = GF_TRUE;
89 11 : comp = AVI_video_compressor(ctx->avi);
90 11 : if (!comp) {
91 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[AVIDmx] Cannot retrieve video compressor name, ignoring video stream\n"));
92 : }
93 : /*these are/should be OK*/
94 11 : else if (!stricmp(comp, "DIVX") || !stricmp(comp, "DX50") /*DivX*/
95 11 : || !stricmp(comp, "XVID") /*XviD*/
96 1 : || !stricmp(comp, "3iv2") /*3ivX*/
97 1 : || !stricmp(comp, "fvfw") /*ffmpeg*/
98 1 : || !stricmp(comp, "NDIG") /*nero*/
99 1 : || !stricmp(comp, "MP4V") /*!! not tested*/
100 1 : || !stricmp(comp, "M4CC") /*Divio - not tested*/
101 1 : || !stricmp(comp, "PVMM") /*PacketVideo - not tested*/
102 1 : || !stricmp(comp, "SEDG") /*Samsung - not tested*/
103 1 : || !stricmp(comp, "RMP4") /*Sigma - not tested*/
104 1 : || !stricmp(comp, "MP43") /*not tested*/
105 1 : || !stricmp(comp, "FMP4") /*not tested*/
106 1 : || !stricmp(comp, "VP6F") /*not tested*/
107 : ) {
108 : codecid = GF_CODECID_MPEG4_PART2;
109 1 : } else if ( !stricmp(comp, "H264") /*not tested*/
110 1 : || !stricmp(comp, "X264") /*not tested*/
111 : ) {
112 : codecid = GF_CODECID_AVC;
113 1 : } else if ( !stricmp(comp, "avc1") ) {
114 : codecid = GF_CODECID_AVC;
115 : unframed = GF_FALSE;
116 1 : } else if (!stricmp(comp, "DIV3") || !stricmp(comp, "DIV4")) {
117 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[AVIDmx] Video format %s not compliant with MPEG-4 Visual - please recompress the file first\n", comp));
118 1 : } else if (!comp[0]) {
119 : codecid = GF_CODECID_RAW;
120 : pfmt = GF_PIXEL_BGR;
121 : } else {
122 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[AVIDmx] Video format %s not supported, patch welcome\n", comp));
123 : }
124 :
125 11 : ctx->v_in_use = GF_FALSE;
126 11 : if (codecid) {
127 : u32 w, h;
128 11 : if (!ctx->v_opid) {
129 11 : ctx->v_opid = gf_filter_pid_new(filter);
130 : }
131 11 : ctx->nb_frames = (u32) AVI_video_frames(ctx->avi);
132 11 : ctx->cur_frame = 0;
133 : sync_id = 1;
134 11 : ctx->v_in_use = GF_TRUE;
135 :
136 11 : gf_filter_pid_set_property(ctx->v_opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_VISUAL) );
137 11 : gf_filter_pid_set_property(ctx->v_opid, GF_PROP_PID_CODECID, &PROP_UINT(codecid) );
138 11 : gf_filter_pid_set_property(ctx->v_opid, GF_PROP_PID_TIMESCALE, &PROP_UINT(ctx->fps.num) );
139 :
140 11 : gf_filter_pid_set_property(ctx->v_opid, GF_PROP_PID_ID, &PROP_UINT( sync_id) );
141 11 : gf_filter_pid_set_property(ctx->v_opid, GF_PROP_PID_CLOCK_ID, &PROP_UINT( sync_id ) );
142 11 : gf_filter_pid_set_property(ctx->v_opid, GF_PROP_PID_FPS, &PROP_FRAC( ctx->fps ) );
143 11 : w = AVI_video_width(ctx->avi);
144 11 : h = AVI_video_height(ctx->avi);
145 11 : gf_filter_pid_set_property(ctx->v_opid, GF_PROP_PID_WIDTH, &PROP_UINT( w ) );
146 11 : gf_filter_pid_set_property(ctx->v_opid, GF_PROP_PID_HEIGHT, &PROP_UINT( h ) );
147 11 : gf_filter_pid_set_property(ctx->v_opid, GF_PROP_PID_DURATION, &PROP_FRAC64( dur ) );
148 :
149 11 : gf_filter_pid_set_property(ctx->v_opid, GF_PROP_PID_PLAYBACK_MODE, &PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD ) );
150 :
151 11 : if (pfmt) {
152 1 : u32 stride=0;
153 1 : gf_pixel_get_size_info(pfmt, w, h, NULL, &stride, NULL, NULL, NULL);
154 1 : gf_filter_pid_set_property(ctx->v_opid, GF_PROP_PID_STRIDE, &PROP_UINT( stride ) );
155 1 : gf_filter_pid_set_property(ctx->v_opid, GF_PROP_PID_PIXFMT, &PROP_UINT( pfmt ) );
156 10 : } else if (unframed) {
157 10 : gf_filter_pid_set_property(ctx->v_opid, GF_PROP_PID_UNFRAMED, &PROP_BOOL(GF_TRUE) );
158 10 : gf_filter_pid_set_property_str(ctx->v_opid, "nocts", &PROP_BOOL( GF_TRUE ) );
159 0 : } else if (ctx->avi->extradata_size && ctx->avi->extradata) {
160 0 : gf_filter_pid_set_property(ctx->v_opid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA(ctx->avi->extradata, ctx->avi->extradata_size) );
161 :
162 : }
163 : }
164 :
165 : unframed = GF_FALSE;
166 11 : count = AVI_audio_tracks(ctx->avi);
167 14 : for (i=0; i<count; i++) {
168 : u32 a_fmt, afmt=0, nb_bits;
169 3 : AVI_set_audio_track(ctx->avi, i);
170 :
171 : codecid = 0;
172 3 : a_fmt = AVI_audio_format(ctx->avi);
173 3 : nb_bits = AVI_audio_bits(ctx->avi);
174 3 : switch (a_fmt) {
175 1 : case WAVE_FORMAT_PCM:
176 : case GF_4CC('P','C','M',' '):
177 : codecid = GF_CODECID_RAW;
178 1 : switch (nb_bits) {
179 : case 8:
180 : afmt = GF_AUDIO_FMT_U8;
181 : break;
182 1 : case 16:
183 : afmt = GF_AUDIO_FMT_S16;
184 1 : break;
185 0 : case 24:
186 : afmt = GF_AUDIO_FMT_S24;
187 0 : break;
188 0 : case 32:
189 : afmt = GF_AUDIO_FMT_S32;
190 0 : break;
191 0 : default:
192 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[AVIDmx] Audio bit depth %d not mapped, patch welcome\n", nb_bits));
193 : afmt = GF_AUDIO_FMT_S16;
194 : break;
195 : }
196 : break;
197 : case WAVE_FORMAT_ADPCM:
198 : codecid = GF_CODECID_ADPCM;
199 : break;
200 0 : case WAVE_FORMAT_IBM_CVSD:
201 : codecid = GF_CODECID_IBM_CVSD;
202 0 : break;
203 0 : case WAVE_FORMAT_ALAW:
204 : codecid = GF_CODECID_ALAW;
205 0 : break;
206 0 : case WAVE_FORMAT_MULAW:
207 : codecid = GF_CODECID_MULAW;
208 0 : break;
209 0 : case WAVE_FORMAT_OKI_ADPCM:
210 : codecid = GF_CODECID_OKI_ADPCM;
211 0 : break;
212 0 : case WAVE_FORMAT_DVI_ADPCM:
213 : codecid = GF_CODECID_DVI_ADPCM;
214 0 : break;
215 0 : case WAVE_FORMAT_DIGISTD:
216 : codecid = GF_CODECID_DIGISTD;
217 0 : break;
218 0 : case WAVE_FORMAT_YAMAHA_ADPCM:
219 : codecid = GF_CODECID_YAMAHA_ADPCM;
220 0 : break;
221 0 : case WAVE_FORMAT_DSP_TRUESPEECH:
222 : codecid = GF_CODECID_DSP_TRUESPEECH;
223 0 : break;
224 0 : case WAVE_FORMAT_GSM610:
225 : codecid = GF_CODECID_GSM610;
226 0 : break;
227 0 : case IBM_FORMAT_MULAW:
228 : codecid = GF_CODECID_IBM_MULAW;
229 0 : break;
230 0 : case IBM_FORMAT_ALAW:
231 : codecid = GF_CODECID_IBM_ALAW;
232 0 : break;
233 0 : case IBM_FORMAT_ADPCM:
234 : codecid = GF_CODECID_IBM_ADPCM;
235 0 : break;
236 2 : case WAVE_FORMAT_MP3:
237 : codecid = GF_CODECID_MPEG_AUDIO;
238 : unframed = GF_TRUE;
239 2 : break;
240 0 : case WAVE_FORMAT_AAC_ADTS:
241 : codecid = GF_CODECID_AAC_MPEG4;
242 : unframed = GF_TRUE;
243 0 : break;
244 0 : case WAVE_FORMAT_AAC:
245 : codecid = GF_CODECID_AAC_MPEG4;
246 0 : break;
247 0 : case WAVE_FORMAT_AC3:
248 : codecid = GF_CODECID_AC3;
249 0 : break;
250 0 : default:
251 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[AVIDmx] Audio format %d not supported, patch welcome\n", a_fmt));
252 : break;
253 : }
254 :
255 3 : if (codecid) {
256 : AVIAstream *st = NULL;
257 3 : u32 brate, j, c = gf_list_count(ctx->audios);
258 3 : for (j=0; j<c; j++) {
259 0 : st = gf_list_get(ctx->audios, j);
260 0 : if (!st->in_use) break;
261 : st = NULL;
262 : }
263 3 : if (!st) {
264 3 : GF_SAFEALLOC(st, AVIAstream);
265 3 : if (!st) continue;
266 3 : st->opid = gf_filter_pid_new(filter);
267 3 : gf_list_add(ctx->audios, st);
268 : }
269 3 : st->in_use = GF_TRUE;
270 3 : st->stream_num = i;
271 3 : if (!sync_id) sync_id = 2 + st->stream_num;
272 3 : st->audio_done = GF_FALSE;
273 :
274 3 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_AUDIO) );
275 3 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_CODECID, &PROP_UINT( codecid) );
276 3 : st->freq = AVI_audio_rate(ctx->avi);
277 3 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_SAMPLE_RATE, &PROP_UINT( st->freq ) );
278 3 : st->nb_channels = AVI_audio_channels(ctx->avi);
279 3 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT( st->nb_channels ) );
280 3 : brate = AVI_audio_mp3rate(ctx->avi);
281 : //for mp3 and aac
282 3 : if (brate && (unframed || (codecid == GF_CODECID_AAC_MPEG4)))
283 2 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_BITRATE, &PROP_UINT( brate ) );
284 3 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_ID, &PROP_UINT( 2 + st->stream_num) );
285 3 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_CLOCK_ID, &PROP_UINT( sync_id ) );
286 3 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_DURATION, &PROP_FRAC64( dur ) );
287 :
288 3 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_PLAYBACK_MODE, &PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD ) );
289 3 : st->audio_bps = 0;
290 3 : if (unframed) {
291 2 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_UNFRAMED, &PROP_BOOL( GF_TRUE ) );
292 : //we don't set timescale, let the reframer handle it
293 : } else {
294 1 : if (afmt) {
295 1 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(afmt) );
296 : }
297 1 : st->audio_bps = AVI_audio_bits(ctx->avi);
298 1 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_TIMESCALE, &PROP_UINT(st->freq) );
299 :
300 1 : if (codecid == GF_CODECID_AAC_MPEG4) {
301 : #ifndef GPAC_DISABLE_AV_PARSERS
302 : GF_M4ADecSpecInfo acfg;
303 0 : u8 *dsi=NULL;
304 0 : u32 dsi_len=0;
305 : memset(&acfg, 0, sizeof(GF_M4ADecSpecInfo));
306 0 : acfg.base_object_type = GF_M4A_AAC_LC;
307 0 : acfg.base_sr = st->freq;
308 0 : acfg.nb_chan = st->nb_channels;
309 : acfg.sbr_object_type = 0;
310 0 : acfg.audioPL = gf_m4a_get_profile(&acfg);
311 0 : gf_m4a_write_config(&acfg, &dsi, &dsi_len);
312 0 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA_NO_COPY(dsi, dsi_len) );
313 : #endif
314 0 : st->audio_bps = 0;
315 0 : st->is_aac = GF_TRUE;
316 : }
317 : }
318 :
319 : }
320 : }
321 11 : }
322 :
323 11 : GF_Err avidmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
324 : {
325 : const GF_PropertyValue *p;
326 11 : GF_AVIDmxCtx *ctx = gf_filter_get_udta(filter);
327 :
328 11 : if (is_remove) {
329 0 : ctx->ipid = NULL;
330 0 : if (ctx->v_opid) {
331 0 : gf_filter_pid_remove(ctx->v_opid);
332 0 : ctx->v_opid = NULL;
333 : }
334 0 : while (gf_list_count(ctx->audios) ) {
335 0 : AVIAstream *st = gf_list_pop_back(ctx->audios);
336 0 : if (st->opid)
337 0 : gf_filter_pid_remove(st->opid);
338 0 : gf_free(st);
339 : }
340 : return GF_OK;
341 : }
342 11 : if (! gf_filter_pid_check_caps(pid))
343 : return GF_NOT_SUPPORTED;
344 :
345 11 : if (!ctx->ipid) {
346 : GF_FilterEvent fevt;
347 11 : ctx->ipid = pid;
348 :
349 : //we work with full file only, send a play event on source to indicate that
350 11 : GF_FEVT_INIT(fevt, GF_FEVT_PLAY, pid);
351 : fevt.play.start_range = 0;
352 11 : fevt.base.on_pid = ctx->ipid;
353 11 : fevt.play.full_file_only = GF_TRUE;
354 11 : gf_filter_pid_send_event(ctx->ipid, &fevt);
355 : }
356 :
357 11 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
358 11 : if (!p) return GF_NOT_SUPPORTED;
359 :
360 11 : if (ctx->src_url && !strcmp(ctx->src_url, p->value.string)) return GF_OK;
361 :
362 11 : if (ctx->avi) {
363 : u32 i;
364 0 : AVI_close(ctx->avi);
365 0 : ctx->v_in_use = GF_FALSE;
366 0 : for (i=0; i<gf_list_count(ctx->audios); i++) {
367 0 : AVIAstream *st = gf_list_get(ctx->audios, i);
368 0 : st->in_use = GF_FALSE;
369 : }
370 : }
371 11 : ctx->avi = NULL;
372 :
373 11 : ctx->src_url = p->value.string;
374 :
375 11 : return GF_OK;
376 : }
377 :
378 3117 : static Bool avidmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
379 : {
380 3117 : GF_AVIDmxCtx *ctx = gf_filter_get_udta(filter);
381 :
382 3117 : switch (evt->base.type) {
383 14 : case GF_FEVT_PLAY:
384 14 : gf_filter_post_process_task(filter);
385 14 : if (evt->base.on_pid==ctx->v_opid) {
386 : u32 frame_idx = 0;
387 11 : ctx->v_playing = GF_TRUE;
388 11 : if ((evt->play.start_range==0) && !ctx->v_init_play_done) {
389 11 : ctx->v_init_play_done = GF_TRUE;
390 11 : return GF_TRUE;
391 : }
392 0 : ctx->v_init_play_done = GF_TRUE;
393 0 : frame_idx = (u32) (ctx->avi->fps * evt->play.start_range);
394 0 : if (frame_idx) {
395 0 : AVI_set_video_position(ctx->avi, frame_idx);
396 : } else {
397 0 : AVI_seek_start(ctx->avi);
398 0 : gf_filter_post_process_task(filter);
399 : }
400 0 : ctx->cur_frame = frame_idx;
401 : } else {
402 : u32 i;
403 0 : for (i=0; i<gf_list_count(ctx->audios); i++) {
404 3 : AVIAstream *st = gf_list_get(ctx->audios, i);
405 3 : if (st->opid != evt->base.on_pid) continue;
406 3 : st->playing = GF_TRUE;
407 3 : if ((evt->play.start_range==0) && !st->init_play_done) {
408 3 : st->init_play_done = GF_TRUE;
409 3 : return GF_TRUE;
410 : }
411 0 : st->init_play_done = GF_TRUE;
412 0 : AVI_set_audio_position(ctx->avi, 0);
413 0 : st->seek_to_ts = (u32) (evt->play.start_range * st->freq);
414 : }
415 : }
416 :
417 : //cancel play event, we work with full file
418 : return GF_TRUE;
419 :
420 4 : case GF_FEVT_STOP:
421 4 : if (evt->base.on_pid==ctx->v_opid) {
422 4 : ctx->v_playing = GF_FALSE;
423 : } else {
424 : u32 i;
425 0 : for (i=0; i<gf_list_count(ctx->audios); i++) {
426 0 : AVIAstream *st = gf_list_get(ctx->audios, i);
427 0 : if (st->opid != evt->base.on_pid) continue;
428 0 : st->playing = GF_TRUE;
429 : }
430 : }
431 : //don't cancel event
432 : return GF_FALSE;
433 :
434 : case GF_FEVT_SET_SPEED:
435 : //cancel event
436 : return GF_TRUE;
437 : default:
438 : break;
439 : }
440 : //by default don't cancel event - to rework once we have downloading in place
441 3099 : return GF_FALSE;
442 : }
443 :
444 5763 : GF_Err avidmx_process(GF_Filter *filter)
445 : {
446 5763 : GF_AVIDmxCtx *ctx = gf_filter_get_udta(filter);
447 : u32 i, count, nb_done, nb_active=0;
448 : Bool start, end, video_done;
449 :
450 5763 : if (!ctx->avi) {
451 3099 : GF_FilterPacket *pck = gf_filter_pid_get_packet(ctx->ipid);
452 3099 : if (!pck) {
453 : return GF_OK;
454 : }
455 3099 : gf_filter_pck_get_framing(pck, &start, &end);
456 3099 : gf_filter_pid_drop_packet(ctx->ipid);
457 :
458 3099 : if (!end) {
459 : return GF_OK;
460 : }
461 :
462 11 : ctx->avi = AVI_open_input_file((char *)ctx->src_url, 1);
463 11 : if (!ctx->avi) {
464 : GF_Err e = GF_NON_COMPLIANT_BITSTREAM;
465 0 : if (! gf_file_exists(ctx->src_url)) e = GF_URL_ERROR;
466 0 : gf_filter_setup_failure(filter, e);
467 0 : return GF_NOT_SUPPORTED;
468 : }
469 11 : avidmx_setup(filter, ctx);
470 11 : return GF_OK;
471 : }
472 : video_done = GF_FALSE;
473 4849 : if (ctx->v_in_use && ctx->v_playing && (ctx->cur_frame < ctx->nb_frames) && !gf_filter_pid_would_block(ctx->v_opid) ) {
474 : u32 key;
475 : u64 file_offset, cts;
476 : u8 *pck_data;
477 2185 : s32 size = AVI_frame_size(ctx->avi, ctx->cur_frame);
478 2185 : if (!size) {
479 0 : AVI_read_frame(ctx->avi, NULL, &key);
480 0 : ctx->dummy++;
481 : }
482 : //remove dummy frames
483 : else {
484 2185 : file_offset = (u64) AVI_get_video_position(ctx->avi, ctx->cur_frame);
485 2185 : cts = ctx->nb_frame_sent * ctx->fps.den;
486 :
487 2185 : if (size > 4) {
488 2180 : GF_FilterPacket *dst_pck = gf_filter_pck_new_alloc(ctx->v_opid, size, &pck_data);
489 2180 : if (!dst_pck) return GF_OUT_OF_MEM;
490 2180 : AVI_read_frame(ctx->avi, pck_data, &key);
491 2180 : gf_filter_pck_set_byte_offset(dst_pck, file_offset);
492 2180 : gf_filter_pck_set_cts(dst_pck, cts);
493 2180 : gf_filter_pck_set_duration(dst_pck, ctx->fps.den);
494 2180 : gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_TRUE);
495 2180 : if (key) gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
496 2180 : gf_filter_pck_send(dst_pck);
497 2180 : ctx->nb_frame_sent++;
498 : } else {
499 5 : AVI_read_frame(ctx->avi, NULL, &key);
500 5 : ctx->nvops++;
501 : }
502 : }
503 : nb_active++;
504 :
505 2185 : ctx->cur_frame++;
506 2185 : if (ctx->cur_frame < ctx->nb_frames)
507 2178 : gf_filter_post_process_task(filter);
508 : else
509 : video_done = GF_TRUE;
510 479 : } else if (!ctx->v_in_use) {
511 : video_done = GF_TRUE;
512 479 : } else if (ctx->cur_frame >= ctx->nb_frames) {
513 : video_done = GF_TRUE;
514 : }
515 :
516 : nb_done = 0;
517 2664 : count = gf_list_count(ctx->audios);
518 3825 : for (i=0; i<count; i++) {
519 : s32 size;
520 1161 : AVIAstream *st = gf_list_get(ctx->audios, i);
521 1161 : if (st->audio_done || !st->in_use) {
522 0 : nb_done++;
523 0 : continue;
524 : }
525 1161 : if (!st->playing || gf_filter_pid_would_block(st->opid) )
526 3 : continue;
527 1158 : AVI_set_audio_track(ctx->avi, st->stream_num);
528 1158 : nb_active++;
529 :
530 1158 : size = AVI_audio_size(ctx->avi, st->aud_frame);
531 :
532 1158 : if (st->seek_to_ts && size) {
533 0 : if (st->seek_to_ts > st->audio_ts) {
534 0 : st->aud_frame ++;
535 0 : continue;
536 : }
537 : else
538 0 : st->seek_to_ts = 0;
539 : }
540 :
541 1158 : if (size>0) {
542 : int continuous;
543 : u8 *pck_data;
544 : u64 file_offset;
545 1155 : GF_FilterPacket *dst_pck = gf_filter_pck_new_alloc(st->opid, size, &pck_data);
546 1155 : if (!dst_pck) return GF_OUT_OF_MEM;
547 :
548 1155 : file_offset = gf_ftell(ctx->avi->fdes);
549 1155 : AVI_read_audio(ctx->avi, pck_data, size, (int*)&continuous);
550 :
551 1155 : if (st->audio_bps) {
552 385 : u32 nb_samples = (8*size) / (st->audio_bps * st->nb_channels);
553 385 : gf_filter_pck_set_cts(dst_pck, st->audio_ts);
554 385 : gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
555 385 : st->audio_ts += nb_samples;
556 770 : } else if (st->is_aac) {
557 0 : gf_filter_pck_set_cts(dst_pck, st->audio_ts);
558 0 : gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
559 0 : st->audio_ts += 1024;
560 : }
561 :
562 1155 : if (continuous)
563 3 : gf_filter_pck_set_byte_offset(dst_pck, file_offset);
564 :
565 1155 : gf_filter_pck_send(dst_pck);
566 :
567 1155 : st->aud_frame ++;
568 : } else {
569 3 : st->audio_done = GF_TRUE;
570 3 : nb_done++;
571 : }
572 : }
573 2664 : if (!nb_active)
574 : return GF_OK;
575 2593 : if (video_done && (nb_done==count) ) {
576 7 : if (ctx->v_opid && ctx->v_in_use) gf_filter_pid_set_eos(ctx->v_opid);
577 :
578 3 : for (i=0; i<count;i++) {
579 3 : AVIAstream *st = gf_list_get(ctx->audios, i);
580 3 : gf_filter_pid_set_eos(st->opid);
581 : }
582 : return GF_EOS;
583 : }
584 2586 : gf_filter_post_process_task(filter);
585 2586 : return GF_OK;
586 : }
587 :
588 11 : GF_Err avidmx_initialize(GF_Filter *filter)
589 : {
590 11 : GF_AVIDmxCtx *ctx = gf_filter_get_udta(filter);
591 11 : ctx->use_file_fps = ctx->fps.den ? GF_FALSE : GF_TRUE;
592 11 : ctx->audios = gf_list_new();
593 11 : return GF_OK;
594 : }
595 :
596 11 : void avidmx_finalize(GF_Filter *filter)
597 : {
598 11 : GF_AVIDmxCtx *ctx = gf_filter_get_udta(filter);
599 11 : if (ctx->avi) AVI_close(ctx->avi);
600 14 : while (gf_list_count(ctx->audios)) {
601 3 : AVIAstream *st = gf_list_pop_back(ctx->audios);
602 3 : gf_free(st);
603 : }
604 11 : gf_list_del(ctx->audios);
605 :
606 11 : if (ctx->importer) {
607 4 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("AVI Removed Frames: 1 VFW delay frames - 296 N-VOPs\n", ctx->dummy, ctx->nvops));
608 : }
609 :
610 11 : }
611 :
612 :
613 : static const GF_FilterCapability AVIDmxCaps[] =
614 : {
615 : CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
616 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "avi"),
617 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "video/avi|video/x-avi"),
618 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
619 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
620 : };
621 :
622 :
623 : #define OFFS(_n) #_n, offsetof(GF_AVIDmxCtx, _n)
624 : static const GF_FilterArgs AVIDmxArgs[] =
625 : {
626 : { OFFS(fps), "import frame rate, default is AVI one", GF_PROP_FRACTION, "1/0", NULL, 0},
627 : { OFFS(importer), "compatibility with old importer, displays import results", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
628 : {0}
629 : };
630 :
631 :
632 : GF_FilterRegister AVIDmxRegister = {
633 : .name = "avidmx",
634 : GF_FS_SET_DESCRIPTION("AVI demuxer")
635 : GF_FS_SET_HELP("This filter demultiplexes AVI files/data to produce media PIDs and frames.")
636 : .private_size = sizeof(GF_AVIDmxCtx),
637 : .initialize = avidmx_initialize,
638 : .finalize = avidmx_finalize,
639 : .args = AVIDmxArgs,
640 : SETCAPS(AVIDmxCaps),
641 : .configure_pid = avidmx_configure_pid,
642 : .process = avidmx_process,
643 : .process_event = avidmx_process_event,
644 : };
645 :
646 : #endif // GPAC_DISABLE_AVILIB
647 :
648 2877 : const GF_FilterRegister *avidmx_register(GF_FilterSession *session)
649 : {
650 : #ifndef GPAC_DISABLE_AVILIB
651 2877 : return &AVIDmxRegister;
652 : #else
653 : return NULL;
654 : #endif
655 : }
656 :
|