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-1/2/4(Part2) video reframer 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/avparse.h>
27 : #include <gpac/constants.h>
28 : #include <gpac/filters.h>
29 : #include <gpac/internal/media_dev.h>
30 :
31 : #ifndef GPAC_DISABLE_AV_PARSERS
32 :
33 : typedef struct
34 : {
35 : u64 pos;
36 : Double start_time;
37 : } MPGVidIdx;
38 :
39 : typedef struct
40 : {
41 : //filter args
42 : GF_Fraction fps;
43 : Double index;
44 : Bool vfr, importer;
45 :
46 : //only one input pid declared
47 : GF_FilterPid *ipid;
48 : //only one output pid declared
49 : GF_FilterPid *opid;
50 :
51 : GF_BitStream *bs;
52 : u64 cts, dts, prev_dts;
53 : u32 width, height;
54 : GF_Fraction64 duration;
55 : Double start_range;
56 : Bool in_seek;
57 : u32 timescale;
58 :
59 : u32 resume_from;
60 : GF_Fraction cur_fps;
61 :
62 : Bool is_mpg12, forced_packed;
63 : GF_M4VParser *vparser;
64 : GF_M4VDecSpecInfo dsi;
65 : u32 b_frames;
66 : Bool is_packed, is_vfr;
67 : GF_List *pck_queue;
68 : u64 last_ref_cts;
69 : Bool frame_started;
70 :
71 : u32 nb_i, nb_p, nb_b, nb_frames, max_b;
72 :
73 : u32 bytes_in_header;
74 : char *hdr_store;
75 : u32 hdr_store_size, hdr_store_alloc;
76 :
77 : Bool is_playing;
78 : Bool is_file, file_loaded;
79 : Bool initial_play_done;
80 :
81 : Bool input_is_au_start, input_is_au_end;
82 : Bool recompute_cts;
83 :
84 : GF_FilterPacket *src_pck;
85 :
86 : MPGVidIdx *indexes;
87 : u32 index_alloc_size, index_size;
88 : u32 bitrate;
89 : } GF_MPGVidDmxCtx;
90 :
91 :
92 111 : GF_Err mpgviddmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
93 : {
94 : Bool was_mpeg12;
95 : const GF_PropertyValue *p;
96 111 : GF_MPGVidDmxCtx *ctx = gf_filter_get_udta(filter);
97 :
98 111 : if (is_remove) {
99 3 : ctx->ipid = NULL;
100 3 : if (ctx->opid) {
101 3 : gf_filter_pid_remove(ctx->opid);
102 3 : ctx->opid = NULL;
103 : }
104 : return GF_OK;
105 : }
106 108 : if (! gf_filter_pid_check_caps(pid))
107 : return GF_NOT_SUPPORTED;
108 :
109 108 : ctx->ipid = pid;
110 108 : ctx->cur_fps = ctx->fps;
111 108 : if (!ctx->fps.num || !ctx->fps.den) {
112 108 : ctx->cur_fps.num = 25000;
113 108 : ctx->cur_fps.den = 1000;
114 : }
115 :
116 108 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
117 108 : if (p) {
118 33 : ctx->timescale = ctx->cur_fps.num = p->value.uint;
119 33 : ctx->cur_fps.den = 0;
120 33 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_FPS);
121 33 : if (p) {
122 11 : ctx->cur_fps = p->value.frac;
123 : }
124 33 : p = gf_filter_pid_get_property_str(pid, "nocts");
125 33 : if (p && p->value.boolean) ctx->recompute_cts = GF_TRUE;
126 : }
127 :
128 108 : was_mpeg12 = ctx->is_mpg12;
129 :
130 108 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
131 108 : if (p) {
132 33 : switch (p->value.uint) {
133 25 : case GF_CODECID_MPEG1:
134 : case GF_CODECID_MPEG2_422:
135 : case GF_CODECID_MPEG2_SNR:
136 : case GF_CODECID_MPEG2_HIGH:
137 : case GF_CODECID_MPEG2_MAIN:
138 : case GF_CODECID_MPEG2_SIMPLE:
139 : case GF_CODECID_MPEG2_SPATIAL:
140 25 : ctx->is_mpg12 = GF_TRUE;
141 25 : break;
142 : }
143 : }
144 : else {
145 75 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_MIME);
146 75 : if (p && p->value.string && (strstr(p->value.string, "m1v") || strstr(p->value.string, "m2v")) ) ctx->is_mpg12 = GF_TRUE;
147 : else {
148 75 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_FILE_EXT);
149 75 : if (p && p->value.string && (strstr(p->value.string, "m1v") || strstr(p->value.string, "m2v")) ) ctx->is_mpg12 = GF_TRUE;
150 : }
151 : }
152 :
153 108 : if (ctx->vparser && (was_mpeg12 != ctx->is_mpg12)) {
154 0 : gf_m4v_parser_del_no_bs(ctx->vparser);
155 0 : ctx->vparser = NULL;
156 : }
157 :
158 108 : if (ctx->timescale && !ctx->opid) {
159 23 : ctx->opid = gf_filter_pid_new(filter);
160 23 : gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
161 23 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
162 : }
163 : return GF_OK;
164 : }
165 :
166 :
167 14479 : static void mpgviddmx_check_dur(GF_Filter *filter, GF_MPGVidDmxCtx *ctx)
168 : {
169 :
170 : FILE *stream;
171 : GF_BitStream *bs;
172 : GF_M4VParser *vparser;
173 : GF_M4VDecSpecInfo dsi;
174 : GF_Err e;
175 : u64 duration, cur_dur, rate;
176 : const GF_PropertyValue *p;
177 28905 : if (!ctx->opid || ctx->timescale || ctx->file_loaded) return;
178 :
179 75 : if (ctx->index<=0) {
180 22 : ctx->file_loaded = GF_TRUE;
181 : return;
182 : }
183 :
184 53 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
185 53 : if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7)) {
186 0 : ctx->is_file = GF_FALSE;
187 0 : ctx->file_loaded = GF_TRUE;
188 : return;
189 : }
190 53 : ctx->is_file = GF_TRUE;
191 :
192 53 : stream = gf_fopen(p->value.string, "rb");
193 53 : if (!stream) return;
194 :
195 53 : ctx->index_size = 0;
196 :
197 53 : bs = gf_bs_from_file(stream, GF_BITSTREAM_READ);
198 :
199 53 : vparser = gf_m4v_parser_bs_new(bs, ctx->is_mpg12);
200 53 : e = gf_m4v_parse_config(vparser, &dsi);
201 53 : if (e) {
202 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[MPGVid] Could not parse video header - duration not estimated\n"));
203 0 : ctx->file_loaded = GF_TRUE;
204 : return;
205 : }
206 :
207 : duration = 0;
208 : cur_dur = 0;
209 13125 : while (gf_bs_available(bs)) {
210 : u8 ftype;
211 : u32 tinc;
212 : u64 fsize, start;
213 : Bool is_coded;
214 : u64 pos;
215 13072 : pos = gf_m4v_get_object_start(vparser);
216 13072 : e = gf_m4v_parse_frame(vparser, &dsi, &ftype, &tinc, &fsize, &start, &is_coded);
217 13072 : if (e<0) {
218 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[MPGVid] Could not parse video frame\n"));
219 0 : continue;
220 : }
221 :
222 13072 : duration += ctx->cur_fps.den;
223 13072 : cur_dur += ctx->cur_fps.den;
224 : //only index at I-frame start
225 13072 : if (pos && (ftype==0) && (cur_dur >= ctx->index * ctx->cur_fps.num) ) {
226 463 : if (!ctx->index_alloc_size) ctx->index_alloc_size = 10;
227 413 : else if (ctx->index_alloc_size == ctx->index_size) ctx->index_alloc_size *= 2;
228 463 : ctx->indexes = gf_realloc(ctx->indexes, sizeof(MPGVidIdx)*ctx->index_alloc_size);
229 463 : ctx->indexes[ctx->index_size].pos = pos;
230 463 : ctx->indexes[ctx->index_size].start_time = (Double) (duration-ctx->cur_fps.den);
231 463 : ctx->indexes[ctx->index_size].start_time /= ctx->cur_fps.num;
232 463 : ctx->index_size ++;
233 : cur_dur = 0;
234 : }
235 : }
236 53 : rate = gf_bs_get_position(bs);
237 53 : gf_m4v_parser_del(vparser);
238 53 : gf_fclose(stream);
239 :
240 53 : if (!ctx->duration.num || (ctx->duration.num * ctx->cur_fps.num != duration * ctx->duration.den)) {
241 53 : ctx->duration.num = (s32) duration;
242 53 : ctx->duration.den = ctx->cur_fps.num;
243 :
244 53 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
245 :
246 53 : if (duration && !gf_sys_is_test_mode() ) {
247 0 : rate *= 8 * ctx->duration.den;
248 0 : rate /= ctx->duration.num;
249 0 : ctx->bitrate = (u32) rate;
250 : }
251 : }
252 :
253 53 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
254 53 : if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
255 53 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CAN_DATAREF, & PROP_BOOL(GF_TRUE ) );
256 : }
257 :
258 :
259 34704 : static void mpgviddmx_enqueue_or_dispatch(GF_MPGVidDmxCtx *ctx, GF_FilterPacket *pck, Bool flush_ref, Bool is_eos)
260 : {
261 : //TODO: we are dispatching frames in "negctts mode", ie we may have DTS>CTS
262 : //need to signal this for consumers using DTS (eg MPEG-2 TS)
263 34704 : if (flush_ref && ctx->pck_queue) {
264 : //send all reference packet queued
265 8013 : u32 i, count = gf_list_count(ctx->pck_queue);
266 :
267 34474 : for (i=0; i<count; i++) {
268 : u64 cts;
269 26461 : GF_FilterPacket *q_pck = gf_list_get(ctx->pck_queue, i);
270 26461 : u8 carousel = gf_filter_pck_get_carousel_version(q_pck);
271 26461 : if (!carousel) {
272 5795 : gf_filter_pck_send(q_pck);
273 5795 : continue;
274 : }
275 20666 : gf_filter_pck_set_carousel_version(q_pck, 0);
276 20666 : cts = gf_filter_pck_get_cts(q_pck);
277 20666 : if (cts != GF_FILTER_NO_TS) {
278 : //offset the cts of the ref frame to the number of B frames in-between
279 18265 : if (ctx->last_ref_cts == cts) {
280 7080 : cts += ctx->b_frames * ctx->cur_fps.den;
281 7080 : gf_filter_pck_set_cts(q_pck, cts);
282 : } else {
283 : //shift all other frames (i.e. pending Bs) by 1 frame in the past since we move the ref frame after them
284 : assert(cts >= ctx->cur_fps.den);
285 11185 : cts -= ctx->cur_fps.den;
286 11185 : gf_filter_pck_set_cts(q_pck, cts);
287 : }
288 : }
289 20666 : if (is_eos && (i+1==count)) {
290 : Bool start, end;
291 45 : gf_filter_pck_get_framing(q_pck, &start, &end);
292 45 : gf_filter_pck_set_framing(q_pck, start, GF_TRUE);
293 : }
294 20666 : gf_filter_pck_send(q_pck);
295 : }
296 8013 : gf_list_reset(ctx->pck_queue);
297 : }
298 34704 : if (!pck) return;
299 :
300 26517 : if (!ctx->pck_queue) ctx->pck_queue = gf_list_new();
301 26517 : gf_list_add(ctx->pck_queue, pck);
302 : }
303 :
304 261 : static void mpgviddmx_check_pid(GF_Filter *filter, GF_MPGVidDmxCtx *ctx, u32 vosh_size, u8 *data)
305 : {
306 261 : if (!ctx->opid) {
307 75 : ctx->opid = gf_filter_pid_new(filter);
308 75 : gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
309 75 : mpgviddmx_check_dur(filter, ctx);
310 : }
311 :
312 261 : if ((ctx->width == ctx->dsi.width) && (ctx->height == ctx->dsi.height)) return;
313 :
314 : //copy properties at init or reconfig
315 101 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, & PROP_UINT(GF_STREAM_VISUAL));
316 101 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, & PROP_UINT(ctx->timescale ? ctx->timescale : ctx->cur_fps.num));
317 101 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FPS, & PROP_FRAC(ctx->cur_fps));
318 101 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
319 101 : if (ctx->duration.num)
320 56 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
321 :
322 101 : mpgviddmx_enqueue_or_dispatch(ctx, NULL, GF_TRUE, GF_FALSE);
323 :
324 101 : ctx->width = ctx->dsi.width;
325 101 : ctx->height = ctx->dsi.height;
326 101 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_WIDTH, & PROP_UINT( ctx->dsi.width));
327 101 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_HEIGHT, & PROP_UINT( ctx->dsi.height));
328 101 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAR, & PROP_FRAC_INT(ctx->dsi.par_num, ctx->dsi.par_den));
329 :
330 101 : if (ctx->is_mpg12) {
331 27 : const GF_PropertyValue *cid = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_CODECID);
332 27 : u32 PL = ctx->dsi.VideoPL;
333 27 : if (cid) {
334 15 : switch (cid->value.uint) {
335 : case GF_CODECID_MPEG2_MAIN:
336 : case GF_CODECID_MPEG2_422:
337 : case GF_CODECID_MPEG2_SNR:
338 : case GF_CODECID_MPEG2_HIGH:
339 : //keep same signaling
340 : PL = cid->value.uint;
341 : break;
342 : default:
343 : break;
344 : }
345 12 : }
346 27 : if (!PL) PL = GF_CODECID_MPEG2_MAIN;
347 27 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT(PL));
348 : } else {
349 74 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT(GF_CODECID_MPEG4_PART2));
350 : }
351 101 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PROFILE_LEVEL, & PROP_UINT (ctx->dsi.VideoPL) );
352 :
353 101 : if (ctx->bitrate) {
354 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT(ctx->bitrate));
355 : }
356 :
357 101 : ctx->b_frames = 0;
358 :
359 101 : if (vosh_size) {
360 : u32 i;
361 74 : char * dcfg = gf_malloc(sizeof(char)*vosh_size);
362 : memcpy(dcfg, data, sizeof(char)*vosh_size);
363 :
364 : /*remove packed flag if any (VOSH user data)*/
365 74 : ctx->is_packed = ctx->is_vfr = ctx->forced_packed = GF_FALSE;
366 : i=0;
367 300 : while (1) {
368 : char *frame = dcfg;
369 374 : while ((i+3<vosh_size) && ((frame[i]!=0) || (frame[i+1]!=0) || (frame[i+2]!=1))) i++;
370 374 : if (i+4>=vosh_size) break;
371 370 : if (strncmp(frame+i+4, "DivX", 4)) {
372 : i += 4;
373 300 : continue;
374 : }
375 70 : frame = strchr(dcfg + i + 4, 'p');
376 70 : if (frame) {
377 6 : ctx->forced_packed = GF_TRUE;
378 6 : frame[0] = 'n';
379 : }
380 : break;
381 : }
382 74 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, & PROP_DATA_NO_COPY(dcfg, vosh_size));
383 : }
384 :
385 101 : if (ctx->is_file && ctx->index) {
386 56 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PLAYBACK_MODE, & PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD) );
387 : }
388 : }
389 :
390 5128 : static Bool mpgviddmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
391 : {
392 : u32 i;
393 : u64 file_pos = 0;
394 : GF_FilterEvent fevt;
395 5128 : GF_MPGVidDmxCtx *ctx = gf_filter_get_udta(filter);
396 :
397 5128 : switch (evt->base.type) {
398 99 : case GF_FEVT_PLAY:
399 99 : if (!ctx->is_playing) {
400 99 : ctx->is_playing = GF_TRUE;
401 99 : ctx->cts = 0;
402 99 : ctx->bytes_in_header = 0;
403 : }
404 99 : if (! ctx->is_file) {
405 45 : if (!ctx->initial_play_done) {
406 45 : ctx->initial_play_done = GF_TRUE;
407 45 : if (evt->play.start_range>0.1) ctx->resume_from = 0;
408 : }
409 : return GF_FALSE;
410 : }
411 54 : ctx->start_range = evt->play.start_range;
412 54 : ctx->in_seek = GF_TRUE;
413 :
414 54 : if (ctx->start_range) {
415 2 : for (i=1; i<ctx->index_size; i++) {
416 2 : if ((ctx->indexes[i].start_time > ctx->start_range) || (i+1==ctx->index_size)) {
417 1 : ctx->cts = (u64) (ctx->indexes[i-1].start_time * ctx->cur_fps.num);
418 1 : file_pos = ctx->indexes[i-1].pos;
419 1 : break;
420 : }
421 : }
422 : }
423 54 : ctx->dts = ctx->cts;
424 54 : if (!ctx->initial_play_done) {
425 53 : ctx->initial_play_done = GF_TRUE;
426 : //seek will not change the current source state, don't send a seek
427 53 : if (!file_pos)
428 : return GF_TRUE;
429 : }
430 1 : ctx->resume_from = 0;
431 1 : ctx->bytes_in_header = 0;
432 : //post a seek
433 1 : GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
434 1 : fevt.seek.start_offset = file_pos;
435 1 : gf_filter_pid_send_event(ctx->ipid, &fevt);
436 :
437 : //cancel event
438 1 : return GF_TRUE;
439 :
440 43 : case GF_FEVT_STOP:
441 43 : ctx->is_playing = GF_FALSE;
442 43 : if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
443 43 : ctx->src_pck = NULL;
444 43 : if (ctx->pck_queue) {
445 98 : while (gf_list_count(ctx->pck_queue)) {
446 56 : GF_FilterPacket *pck=gf_list_pop_front(ctx->pck_queue);
447 56 : gf_filter_pck_discard(pck);
448 : }
449 : }
450 : //don't cancel event
451 : return GF_FALSE;
452 :
453 : case GF_FEVT_SET_SPEED:
454 : //cancel event
455 : return GF_TRUE;
456 : default:
457 : break;
458 : }
459 : //by default don't cancel event - to rework once we have downloading in place
460 4982 : return GF_FALSE;
461 : }
462 :
463 21035 : static GFINLINE void mpgviddmx_update_time(GF_MPGVidDmxCtx *ctx)
464 : {
465 : assert(ctx->cur_fps.num);
466 :
467 21035 : if (ctx->timescale) {
468 : u64 inc = 3000;
469 6182 : if (ctx->cur_fps.den && ctx->cur_fps.num) {
470 6170 : inc = ctx->cur_fps.den;
471 6170 : if (ctx->cur_fps.num != ctx->timescale) {
472 2039 : inc *= ctx->timescale;
473 2039 : inc /= ctx->cur_fps.num;
474 : }
475 : }
476 6182 : ctx->cts += inc;
477 6182 : ctx->dts += inc;
478 : } else {
479 : assert(ctx->cur_fps.den);
480 14853 : ctx->cts += ctx->cur_fps.den;
481 14853 : ctx->dts += ctx->cur_fps.den;
482 : }
483 21035 : }
484 :
485 :
486 : static s32 mpgviddmx_next_start_code(u8 *data, u32 size)
487 : {
488 : u32 v, bpos, found;
489 : s64 start, end;
490 :
491 : bpos = 0;
492 : found = 0;
493 : start = 0;
494 : end = 0;
495 :
496 : v = 0xffffffff;
497 : while (!end) {
498 4028533 : if (bpos == size)
499 : return -1;
500 4028165 : v = ( (v<<8) & 0xFFFFFF00) | data[bpos];
501 :
502 4028165 : bpos++;
503 4028165 : if ((v & 0xFFFFFF00) == 0x00000100) {
504 : end = start + bpos - 4;
505 : found = 1;
506 : break;
507 : }
508 : }
509 : if (!found)
510 : return -1;
511 : assert(end >= start);
512 22271 : return (s32) (end - start);
513 : }
514 :
515 16291 : GF_Err mpgviddmx_process(GF_Filter *filter)
516 : {
517 16291 : GF_MPGVidDmxCtx *ctx = gf_filter_get_udta(filter);
518 : GF_FilterPacket *pck, *dst_pck;
519 : u64 byte_offset;
520 : s64 vosh_start = -1;
521 : s64 vosh_end = -1;
522 : GF_Err e;
523 : char *data;
524 : u8 *start;
525 : u32 pck_size;
526 : s32 remain;
527 :
528 : //always reparse duration
529 16291 : if (!ctx->duration.num)
530 14404 : mpgviddmx_check_dur(filter, ctx);
531 :
532 16291 : pck = gf_filter_pid_get_packet(ctx->ipid);
533 16291 : if (!pck) {
534 7150 : if (gf_filter_pid_is_eos(ctx->ipid)) {
535 61 : mpgviddmx_enqueue_or_dispatch(ctx, NULL, GF_TRUE, GF_TRUE);
536 61 : if (ctx->opid)
537 61 : gf_filter_pid_set_eos(ctx->opid);
538 61 : if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
539 61 : ctx->src_pck = NULL;
540 61 : return GF_EOS;
541 : }
542 : return GF_OK;
543 : }
544 :
545 9141 : data = (char *) gf_filter_pck_get_data(pck, &pck_size);
546 9141 : byte_offset = gf_filter_pck_get_byte_offset(pck);
547 :
548 : start = data;
549 9141 : remain = pck_size;
550 :
551 : //input pid sets some timescale - we flushed pending data , update cts
552 9141 : if (!ctx->resume_from && ctx->timescale) {
553 6179 : u64 ts = gf_filter_pck_get_cts(pck);
554 6179 : if (ts != GF_FILTER_NO_TS) {
555 6179 : if (!ctx->cts || !ctx->recompute_cts)
556 2725 : ctx->cts = ts;
557 : }
558 6179 : ts = gf_filter_pck_get_dts(pck);
559 6179 : if (ts != GF_FILTER_NO_TS) {
560 6179 : if (!ctx->dts || !ctx->recompute_cts)
561 2725 : ctx->dts = ts;
562 :
563 6179 : if (!ctx->prev_dts) ctx->prev_dts = ts;
564 6145 : else if (ctx->prev_dts != ts) {
565 : u64 diff = ts;
566 6145 : diff -= ctx->prev_dts;
567 6145 : if (!ctx->cur_fps.den) ctx->cur_fps.den = (u32) diff;
568 6123 : else if (ctx->cur_fps.den > diff)
569 0 : ctx->cur_fps.den = (u32) diff;
570 : }
571 : }
572 6179 : gf_filter_pck_get_framing(pck, &ctx->input_is_au_start, &ctx->input_is_au_end);
573 : //this will force CTS recomput of each frame
574 6179 : if (ctx->recompute_cts) ctx->input_is_au_start = GF_FALSE;
575 6179 : if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
576 6179 : ctx->src_pck = pck;
577 6179 : gf_filter_pck_ref_props(&ctx->src_pck);
578 : }
579 :
580 : //we stored some data to find the complete vosh, aggregate this packet with current one
581 9141 : if (!ctx->resume_from && ctx->hdr_store_size) {
582 0 : if (ctx->hdr_store_alloc < ctx->hdr_store_size + pck_size) {
583 0 : ctx->hdr_store_alloc = ctx->hdr_store_size + pck_size;
584 0 : ctx->hdr_store = gf_realloc(ctx->hdr_store, sizeof(char)*ctx->hdr_store_alloc);
585 : }
586 0 : memcpy(ctx->hdr_store + ctx->hdr_store_size, data, sizeof(char)*pck_size);
587 0 : if (byte_offset != GF_FILTER_NO_BO) {
588 0 : if (byte_offset >= ctx->hdr_store_size)
589 0 : byte_offset -= ctx->hdr_store_size;
590 : else
591 : byte_offset = GF_FILTER_NO_BO;
592 : }
593 0 : ctx->hdr_store_size += pck_size;
594 0 : start = data = ctx->hdr_store;
595 0 : remain = pck_size = ctx->hdr_store_size;
596 : }
597 :
598 9141 : if (ctx->resume_from) {
599 266 : if (gf_filter_pid_would_block(ctx->opid))
600 : return GF_OK;
601 :
602 : //resume from data copied internally
603 266 : if (ctx->hdr_store_size) {
604 : assert(ctx->resume_from <= ctx->hdr_store_size);
605 0 : start = data = ctx->hdr_store + ctx->resume_from;
606 0 : remain = pck_size = ctx->hdr_store_size - ctx->resume_from;
607 : } else {
608 : assert(remain >= (s32) ctx->resume_from);
609 266 : start += ctx->resume_from;
610 266 : remain -= ctx->resume_from;
611 : }
612 266 : ctx->resume_from = 0;
613 : }
614 :
615 9141 : if (!ctx->bs) {
616 98 : ctx->bs = gf_bs_new(start, remain, GF_BITSTREAM_READ);
617 : } else {
618 9043 : gf_bs_reassign_buffer(ctx->bs, start, remain);
619 : }
620 9141 : if (!ctx->vparser) {
621 98 : ctx->vparser = gf_m4v_parser_bs_new(ctx->bs, ctx->is_mpg12);
622 : }
623 :
624 :
625 24991 : while (remain) {
626 : Bool full_frame;
627 : u8 *pck_data;
628 : s32 current;
629 : u8 sc_type, forced_sc_type=0;
630 : Bool sc_type_forced = GF_FALSE;
631 : Bool skip_pck = GF_FALSE;
632 : u8 ftype;
633 : u32 tinc;
634 22548 : u64 size=0;
635 : u64 fstart;
636 : Bool is_coded;
637 : u32 bytes_from_store = 0;
638 : u32 hdr_offset = 0;
639 : Bool copy_last_bytes = GF_FALSE;
640 :
641 : //not enough bytes to parse start code
642 22548 : if (remain<5) {
643 2 : memcpy(ctx->hdr_store, start, remain);
644 2 : ctx->bytes_in_header = remain;
645 6411 : break;
646 : }
647 : current = -1;
648 :
649 : //we have some potential bytes of a start code in the store, copy some more bytes and check if valid start code.
650 : //if not, dispatch these bytes as continuation of the data
651 22546 : if (ctx->bytes_in_header) {
652 :
653 2813 : memcpy(ctx->hdr_store + ctx->bytes_in_header, start, 8 - ctx->bytes_in_header);
654 2813 : current = mpgviddmx_next_start_code(ctx->hdr_store, 8);
655 :
656 : //no start code in stored buffer
657 2813 : if ((current<0) || (current >= (s32) ctx->bytes_in_header) ) {
658 2806 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, ctx->bytes_in_header, &pck_data);
659 3095 : if (!dst_pck) return GF_OUT_OF_MEM;
660 :
661 2806 : if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, dst_pck);
662 2806 : gf_filter_pck_set_cts(dst_pck, GF_FILTER_NO_TS);
663 2806 : gf_filter_pck_set_dts(dst_pck, GF_FILTER_NO_TS);
664 2806 : memcpy(pck_data, ctx->hdr_store, ctx->bytes_in_header);
665 2806 : gf_filter_pck_set_framing(dst_pck, GF_FALSE, GF_FALSE);
666 :
667 2806 : if (byte_offset != GF_FILTER_NO_BO) {
668 93 : gf_filter_pck_set_byte_offset(dst_pck, byte_offset - ctx->bytes_in_header);
669 : }
670 :
671 2806 : mpgviddmx_enqueue_or_dispatch(ctx, dst_pck, GF_FALSE, GF_FALSE);
672 2806 : if (current<0) current = -1;
673 2713 : else current -= ctx->bytes_in_header;
674 2806 : ctx->bytes_in_header = 0;
675 : } else {
676 : //we have a valid start code, check which byte in our store or in the packet payload is the start code type
677 : //and remember its location to reinit the parser from there
678 7 : hdr_offset = 4 - ctx->bytes_in_header + current;
679 : //bytes still to dispatch
680 : bytes_from_store = ctx->bytes_in_header;
681 7 : ctx->bytes_in_header = 0;
682 7 : if (!hdr_offset) {
683 2 : forced_sc_type = ctx->hdr_store[current+3];
684 : } else {
685 5 : forced_sc_type = start[hdr_offset-1];
686 : }
687 : sc_type_forced = GF_TRUE;
688 : }
689 : }
690 : //no starcode in store, look for startcode in packet
691 22546 : if (current == -1) {
692 : //locate next start code
693 19826 : current = mpgviddmx_next_start_code(start, remain);
694 : //no start code, dispatch the block
695 19826 : if (current<0) {
696 : u8 b3, b2, b1;
697 275 : if (! ctx->frame_started) {
698 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[MPGVid] no start code in block and no frame started, discarding data\n" ));
699 : break;
700 : }
701 275 : size = remain;
702 275 : b3 = start[remain-3];
703 275 : b2 = start[remain-2];
704 275 : b1 = start[remain-1];
705 : //we may have a startcode at the end of the packet, store it and don't dispatch the last 3 bytes !
706 275 : if (!b1 || !b2 || !b3) {
707 : copy_last_bytes = GF_TRUE;
708 : assert(size >= 3);
709 16 : size -= 3;
710 16 : ctx->bytes_in_header = 3;
711 : }
712 :
713 275 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, (u32) size, &pck_data);
714 275 : if (!dst_pck) return GF_OUT_OF_MEM;
715 :
716 275 : if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, dst_pck);
717 275 : memcpy(pck_data, start, (size_t) size);
718 275 : gf_filter_pck_set_framing(dst_pck, GF_FALSE, GF_FALSE);
719 275 : gf_filter_pck_set_cts(dst_pck, GF_FILTER_NO_TS);
720 275 : gf_filter_pck_set_dts(dst_pck, GF_FILTER_NO_TS);
721 :
722 275 : if (byte_offset != GF_FILTER_NO_BO) {
723 275 : gf_filter_pck_set_byte_offset(dst_pck, byte_offset);
724 : }
725 :
726 275 : mpgviddmx_enqueue_or_dispatch(ctx, dst_pck, GF_FALSE, GF_FALSE);
727 275 : if (copy_last_bytes) {
728 16 : memcpy(ctx->hdr_store, start+remain-3, 3);
729 : }
730 : break;
731 : }
732 : }
733 :
734 : assert(current>=0);
735 :
736 : //if we are in the middle of parsing the vosh, skip over bytes remaining from previous obj not parsed
737 22271 : if ((vosh_start>=0) && current) {
738 : assert(remain>=current);
739 91 : start += current;
740 91 : remain -= current;
741 : current = 0;
742 : }
743 : //also skip if no output pid
744 22271 : if (!ctx->opid && current) {
745 : assert(remain>=current);
746 0 : start += current;
747 0 : remain -= current;
748 : current = 0;
749 : }
750 : //dispatch remaining bytes
751 22271 : if (current>0) {
752 : //flush remaining
753 2401 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, current, &pck_data);
754 2401 : if (!dst_pck) return GF_OUT_OF_MEM;
755 :
756 2401 : if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, dst_pck);
757 2401 : gf_filter_pck_set_cts(dst_pck, GF_FILTER_NO_TS);
758 2401 : gf_filter_pck_set_dts(dst_pck, GF_FILTER_NO_TS);
759 2401 : gf_filter_pck_set_framing(dst_pck, GF_FALSE, GF_TRUE);
760 : //bytes were partly in store, partly in packet
761 2401 : if (bytes_from_store) {
762 4 : if (byte_offset != GF_FILTER_NO_BO) {
763 4 : gf_filter_pck_set_byte_offset(dst_pck, byte_offset - bytes_from_store);
764 : }
765 : assert(bytes_from_store>=(u32) current);
766 4 : bytes_from_store -= current;
767 4 : memcpy(pck_data, ctx->hdr_store, current);
768 : } else {
769 : //bytes were only in packet
770 2397 : if (byte_offset != GF_FILTER_NO_BO) {
771 2397 : gf_filter_pck_set_byte_offset(dst_pck, byte_offset);
772 : }
773 2397 : memcpy(pck_data, start, current);
774 : assert(remain>=current);
775 2397 : start += current;
776 2397 : remain -= current;
777 : current = 0;
778 : }
779 2401 : gf_filter_pck_set_carousel_version(dst_pck, 1);
780 :
781 2401 : mpgviddmx_enqueue_or_dispatch(ctx, dst_pck, GF_FALSE, GF_FALSE);
782 : }
783 :
784 : //parse headers
785 :
786 : //we have a start code loaded, eg the data packet does not have a full start code at the beginning
787 22271 : if (sc_type_forced) {
788 7 : gf_bs_reassign_buffer(ctx->bs, start + hdr_offset, remain - hdr_offset);
789 : sc_type = forced_sc_type;
790 : } else {
791 22264 : gf_bs_reassign_buffer(ctx->bs, start, remain);
792 22264 : gf_bs_read_int(ctx->bs, 24);
793 22264 : sc_type = gf_bs_read_int(ctx->bs, 8);
794 : }
795 :
796 22271 : if (ctx->is_mpg12) {
797 7246 : switch (sc_type) {
798 170 : case M2V_SEQ_START_CODE:
799 : case M2V_EXT_START_CODE:
800 170 : gf_bs_reassign_buffer(ctx->bs, start, remain);
801 170 : e = gf_m4v_parse_config(ctx->vparser, &ctx->dsi);
802 : //not enough data, accumulate until we can parse the full header
803 170 : if (e==GF_EOS) {
804 0 : if (vosh_start<0) vosh_start = 0;
805 0 : if (ctx->hdr_store_alloc < ctx->hdr_store_size + pck_size - vosh_start) {
806 0 : ctx->hdr_store_alloc = (u32) (ctx->hdr_store_size + pck_size - vosh_start);
807 0 : ctx->hdr_store = gf_realloc(ctx->hdr_store, sizeof(char)*ctx->hdr_store_alloc);
808 : }
809 0 : memcpy(ctx->hdr_store + ctx->hdr_store_size, data + vosh_start, (size_t) (pck_size - vosh_start) );
810 0 : ctx->hdr_store_size += pck_size - (u32) vosh_start;
811 0 : gf_filter_pid_drop_packet(ctx->ipid);
812 0 : return GF_OK;
813 170 : } else if (e != GF_OK) {
814 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[MPGVid] Failed to parse VOS header: %s\n", gf_error_to_string(e) ));
815 : } else {
816 170 : mpgviddmx_check_pid(filter, ctx, 0, NULL);
817 : }
818 : break;
819 : case M2V_PIC_START_CODE:
820 : break;
821 : default:
822 : break;
823 : }
824 :
825 : } else {
826 : u8 PL;
827 15025 : switch (sc_type) {
828 91 : case M4V_VOS_START_CODE:
829 91 : ctx->dsi.VideoPL = (u8) gf_bs_read_u8(ctx->bs);
830 91 : vosh_start = start - (u8 *)data;
831 : skip_pck = GF_TRUE;
832 : assert(remain>=5);
833 91 : start += 5;
834 91 : remain -= 5;
835 91 : break;
836 91 : case M4V_VOL_START_CODE:
837 91 : gf_bs_reassign_buffer(ctx->bs, start, remain);
838 91 : PL = ctx->dsi.VideoPL;
839 91 : e = gf_m4v_parse_config(ctx->vparser, &ctx->dsi);
840 91 : ctx->dsi.VideoPL = PL;
841 : //not enough data, accumulate until we can parse the full header
842 91 : if (e==GF_EOS) {
843 0 : if (vosh_start<0) vosh_start = 0;
844 0 : if (ctx->hdr_store_alloc < ctx->hdr_store_size + pck_size - vosh_start) {
845 0 : ctx->hdr_store_alloc = (u32) (ctx->hdr_store_size + pck_size - (u32) vosh_start);
846 0 : ctx->hdr_store = gf_realloc(ctx->hdr_store, sizeof(char)*ctx->hdr_store_alloc);
847 : }
848 0 : memcpy(ctx->hdr_store + ctx->hdr_store_size, data + vosh_start, (size_t) (pck_size - vosh_start) );
849 0 : ctx->hdr_store_size += pck_size - (u32) vosh_start;
850 0 : gf_filter_pid_drop_packet(ctx->ipid);
851 0 : return GF_OK;
852 91 : } else if (e != GF_OK) {
853 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[MPGVid] Failed to parse VOS header: %s\n", gf_error_to_string(e) ));
854 : } else {
855 91 : u32 obj_size = (u32) gf_m4v_get_object_start(ctx->vparser);
856 91 : if (vosh_start<0) vosh_start = 0;
857 91 : vosh_end = start - (u8 *)data + obj_size;
858 91 : vosh_end -= vosh_start;
859 91 : mpgviddmx_check_pid(filter, ctx,(u32) vosh_end, data+vosh_start);
860 : skip_pck = GF_TRUE;
861 : assert(remain>=(s32) obj_size);
862 91 : start += obj_size;
863 91 : remain -= obj_size;
864 : }
865 : break;
866 : case M4V_VOP_START_CODE:
867 : case M4V_GOV_START_CODE:
868 : break;
869 :
870 182 : case M4V_VO_START_CODE:
871 : case M4V_VISOBJ_START_CODE:
872 : default:
873 182 : if (vosh_start>=0) {
874 : skip_pck = GF_TRUE;
875 : assert(remain>=4);
876 182 : start += 4;
877 182 : remain -= 4;
878 : }
879 : break;
880 : }
881 : }
882 :
883 22271 : if (skip_pck) {
884 1311 : continue;
885 : }
886 :
887 21907 : if (!ctx->opid) {
888 : assert(remain>=4);
889 0 : start += 4;
890 0 : remain -= 4;
891 0 : continue;
892 : }
893 :
894 21907 : if (!ctx->is_playing) {
895 289 : ctx->resume_from = (u32) ((char *)start - (char *)data);
896 289 : return GF_OK;
897 : }
898 : //at this point, we no longer reaggregate packets
899 21618 : ctx->hdr_store_size = 0;
900 :
901 21618 : if (ctx->in_seek) {
902 53 : u64 nb_frames_at_seek = (u64) (ctx->start_range * ctx->cur_fps.num);
903 53 : if (ctx->cts + ctx->cur_fps.den >= nb_frames_at_seek) {
904 : //u32 samples_to_discard = (ctx->cts + ctx->dts_inc) - nb_samples_at_seek;
905 53 : ctx->in_seek = GF_FALSE;
906 : }
907 : }
908 : //may happen that after all our checks, only 4 bytes are left, continue to store these 4 bytes
909 21618 : if (remain<5)
910 0 : continue;
911 :
912 : //good to go
913 21618 : gf_m4v_parser_reset(ctx->vparser, sc_type_forced ? forced_sc_type + 1 : 0);
914 21618 : size = 0;
915 21618 : e = gf_m4v_parse_frame(ctx->vparser, &ctx->dsi, &ftype, &tinc, &size, &fstart, &is_coded);
916 : //true if we strip VO and VISOBJ assert(!fstart);
917 :
918 : //we skipped bytes already in store + end of start code present in packet, so the size of the first object
919 : //needs adjustement
920 21618 : if (bytes_from_store) {
921 7 : size += bytes_from_store + hdr_offset;
922 : }
923 :
924 21618 : if ((e == GF_EOS) && !ctx->input_is_au_end) {
925 6132 : u8 b3 = start[remain-3];
926 6132 : u8 b2 = start[remain-2];
927 6132 : u8 b1 = start[remain-1];
928 :
929 : //we may have a startcode at the end of the packet, store it and don't dispatch the last 3 bytes !
930 6132 : if (!b1 || !b2 || !b3) {
931 : copy_last_bytes = GF_TRUE;
932 : assert(size >= 3);
933 2798 : size -= 3;
934 2798 : ctx->bytes_in_header = 3;
935 : }
936 : full_frame = GF_FALSE;
937 : } else {
938 : full_frame = GF_TRUE;
939 : }
940 :
941 21618 : if (!is_coded) {
942 : /*if prev is B and we're parsing a packed bitstream discard n-vop*/
943 583 : if (ctx->forced_packed && ctx->b_frames) {
944 583 : ctx->is_packed = GF_TRUE;
945 : assert(remain>=size);
946 583 : start += size;
947 583 : remain -= (s32) size;
948 583 : continue;
949 : }
950 : /*policy is to import at variable frame rate, skip*/
951 0 : if (ctx->vfr) {
952 0 : ctx->is_vfr = GF_TRUE;
953 0 : mpgviddmx_update_time(ctx);
954 : assert(remain>=size);
955 0 : start += size;
956 0 : remain -= (s32) size;
957 0 : continue;
958 : }
959 : /*policy is to keep non coded frame (constant frame rate), add*/
960 : }
961 :
962 21035 : if (ftype==2) {
963 : //count number of B-frames since last ref
964 13010 : ctx->b_frames++;
965 13010 : ctx->nb_b++;
966 : } else {
967 : //flush all pending packets
968 8025 : mpgviddmx_enqueue_or_dispatch(ctx, NULL, GF_TRUE, GF_FALSE);
969 : //remeber the CTS of the last ref
970 8025 : ctx->last_ref_cts = ctx->cts;
971 8025 : if (ctx->max_b < ctx->b_frames) ctx->max_b = ctx->b_frames;
972 :
973 8025 : ctx->b_frames = 0;
974 8025 : if (ftype)
975 7064 : ctx->nb_p++;
976 : else
977 961 : ctx->nb_i++;
978 : }
979 21035 : ctx->nb_frames++;
980 :
981 21035 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, (u32) size, &pck_data);
982 21035 : if (!dst_pck) return GF_OUT_OF_MEM;
983 :
984 21035 : if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, dst_pck);
985 : //bytes come from both our store and the data packet
986 21035 : if (bytes_from_store) {
987 7 : memcpy(pck_data, ctx->hdr_store+current, bytes_from_store);
988 : assert(size >= bytes_from_store);
989 7 : size -= bytes_from_store;
990 7 : if (byte_offset != GF_FILTER_NO_BO) {
991 7 : gf_filter_pck_set_byte_offset(dst_pck, byte_offset - bytes_from_store);
992 : }
993 7 : memcpy(pck_data + bytes_from_store, start, (size_t) size);
994 : } else {
995 : //bytes only come the data packet
996 21028 : memcpy(pck_data, start, (size_t) size);
997 21028 : if (byte_offset != GF_FILTER_NO_BO) {
998 16275 : gf_filter_pck_set_byte_offset(dst_pck, byte_offset + start - (u8 *) data);
999 : }
1000 : }
1001 : assert(pck_data[0] == 0);
1002 : assert(pck_data[1] == 0);
1003 : assert(pck_data[2] == 0x01);
1004 :
1005 21035 : gf_filter_pck_set_framing(dst_pck, GF_TRUE, (full_frame || ctx->input_is_au_end) ? GF_TRUE : GF_FALSE);
1006 21035 : gf_filter_pck_set_cts(dst_pck, ctx->cts);
1007 21035 : gf_filter_pck_set_dts(dst_pck, ctx->dts);
1008 21035 : if (ctx->input_is_au_start) {
1009 2714 : ctx->input_is_au_start = GF_FALSE;
1010 : } else {
1011 : //we use the carousel flag temporarly to indicate the cts must be recomputed
1012 18321 : gf_filter_pck_set_carousel_version(dst_pck, 1);
1013 : }
1014 21035 : gf_filter_pck_set_sap(dst_pck, ftype ? GF_FILTER_SAP_NONE : GF_FILTER_SAP_1);
1015 21035 : gf_filter_pck_set_duration(dst_pck, ctx->cur_fps.den);
1016 21035 : if (ctx->in_seek) gf_filter_pck_set_seek_flag(dst_pck, GF_TRUE);
1017 21035 : ctx->frame_started = GF_TRUE;
1018 :
1019 21035 : mpgviddmx_enqueue_or_dispatch(ctx, dst_pck, GF_FALSE, GF_FALSE);
1020 :
1021 21035 : mpgviddmx_update_time(ctx);
1022 :
1023 21035 : if (!full_frame) {
1024 6132 : if (copy_last_bytes) {
1025 2798 : memcpy(ctx->hdr_store, start+remain-3, 3);
1026 : }
1027 : break;
1028 : }
1029 : assert(remain>=size);
1030 14903 : start += size;
1031 14903 : remain -= (s32) size;
1032 : }
1033 8852 : gf_filter_pid_drop_packet(ctx->ipid);
1034 :
1035 8852 : return GF_OK;
1036 : }
1037 :
1038 98 : static GF_Err mpgviddmx_initialize(GF_Filter *filter)
1039 : {
1040 98 : GF_MPGVidDmxCtx *ctx = gf_filter_get_udta(filter);
1041 98 : ctx->hdr_store_size = 0;
1042 98 : ctx->hdr_store_alloc = 8;
1043 98 : ctx->hdr_store = gf_malloc(sizeof(char)*8);
1044 98 : return GF_OK;
1045 : }
1046 :
1047 98 : static void mpgviddmx_finalize(GF_Filter *filter)
1048 : {
1049 98 : GF_MPGVidDmxCtx *ctx = gf_filter_get_udta(filter);
1050 98 : if (ctx->bs) gf_bs_del(ctx->bs);
1051 98 : if (ctx->vparser) gf_m4v_parser_del_no_bs(ctx->vparser);
1052 98 : if (ctx->indexes) gf_free(ctx->indexes);
1053 98 : if (ctx->hdr_store) gf_free(ctx->hdr_store);
1054 98 : if (ctx->pck_queue) {
1055 98 : while (gf_list_count(ctx->pck_queue)) {
1056 0 : GF_FilterPacket *pck = gf_list_pop_back(ctx->pck_queue);
1057 0 : gf_filter_pck_discard(pck);
1058 : }
1059 98 : gf_list_del(ctx->pck_queue);
1060 : }
1061 98 : if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
1062 98 : if (ctx->importer) {
1063 25 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("%s Import results: %d VOPs (%d Is - %d Ps - %d Bs)\n", ctx->is_mpg12 ? "MPEG-1/2" : "MPEG-4 (Part 2)", ctx->nb_frames, ctx->nb_i, ctx->nb_p, ctx->nb_b));
1064 25 : if (ctx->nb_b) {
1065 25 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("\t%d max consecutive B-frames%s\n", ctx->max_b, ctx->is_packed ? " - packed bitstream" : "" ));
1066 : }
1067 25 : if (ctx->is_vfr && ctx->nb_b && ctx->is_packed) {
1068 0 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("Warning: Mix of non-coded frames: packed bitstream and encoder skiped - unpredictable timing\n"));
1069 : }
1070 : }
1071 98 : }
1072 :
1073 : u32 gf_m4v_parser_get_obj_type(GF_M4VParser *m4v);
1074 :
1075 3072 : static const char * mpgvdmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
1076 : {
1077 : GF_M4VParser *parser;
1078 : u8 ftype;
1079 : u32 tinc, nb_frames;
1080 : u64 fsize, start;
1081 : Bool is_coded;
1082 : GF_Err e;
1083 : GF_M4VDecSpecInfo dsi;
1084 :
1085 : memset(&dsi, 0, sizeof(GF_M4VDecSpecInfo));
1086 3072 : parser = gf_m4v_parser_new((char*)data, size, GF_FALSE);
1087 : nb_frames = 0;
1088 : while (1) {
1089 4530 : ftype = 0;
1090 3801 : is_coded = GF_FALSE;
1091 3801 : e = gf_m4v_parse_frame(parser, &dsi, &ftype, &tinc, &fsize, &start, &is_coded);
1092 : //if start is more than 4 (start-code size), we have garbage at the beginning, do not parse
1093 3801 : if (!nb_frames && (start>4))
1094 : break;
1095 3577 : if (is_coded) nb_frames++;
1096 3577 : if (e==GF_EOS) {
1097 : //special case if the only frame we have is not coded
1098 2848 : if (gf_m4v_parser_get_obj_type(parser) == M4V_VOP_START_CODE) {
1099 66 : if (!nb_frames) nb_frames++;
1100 66 : is_coded = 1;
1101 : }
1102 :
1103 2848 : if (is_coded) nb_frames++;
1104 : e = GF_OK;
1105 : break;
1106 : }
1107 729 : if (ftype>2) break;
1108 729 : if (e) break;
1109 729 : nb_frames++;
1110 : }
1111 3072 : gf_m4v_parser_del(parser);
1112 3072 : if ((e==GF_OK) && (nb_frames>1)) {
1113 66 : *score = GF_FPROBE_MAYBE_SUPPORTED;
1114 66 : return "video/mp4v-es";
1115 : }
1116 :
1117 : memset(&dsi, 0, sizeof(GF_M4VDecSpecInfo));
1118 3006 : parser = gf_m4v_parser_new((char*)data, size, GF_TRUE);
1119 : nb_frames = 0;
1120 : while (1) {
1121 3100 : ftype = 0;
1122 3053 : is_coded = GF_FALSE;
1123 3053 : e = gf_m4v_parse_frame(parser, &dsi, &ftype, &tinc, &fsize, &start, &is_coded);
1124 : //if start is more than 4 (start-code size), we have garbage at the beginning, do not parse
1125 3053 : if (!nb_frames && (start>4))
1126 : break;
1127 2254 : if (is_coded) nb_frames++;
1128 2254 : if (e==GF_EOS) {
1129 2207 : if (is_coded) nb_frames++;
1130 : e = GF_OK;
1131 : break;
1132 : }
1133 47 : if (ftype>2) break;
1134 47 : if (e) break;
1135 47 : nb_frames++;
1136 : }
1137 3006 : gf_m4v_parser_del(parser);
1138 3006 : if ((e==GF_OK) && (nb_frames>1)) {
1139 9 : *score = GF_FPROBE_MAYBE_SUPPORTED;
1140 9 : return "video/mpgv-es";
1141 : }
1142 : return NULL;
1143 : }
1144 :
1145 : static const GF_FilterCapability MPGVidDmxCaps[] =
1146 : {
1147 : CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1148 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "cmp|m1v|m2v"),
1149 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "video/mp4v-es|video/mpgv-es"),
1150 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1151 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_MPEG4_PART2),
1152 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_MPEG1),
1153 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_MPEG2_SIMPLE),
1154 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_MPEG2_SPATIAL),
1155 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_MPEG2_SNR),
1156 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_MPEG2_MAIN),
1157 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_MPEG2_HIGH),
1158 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_MPEG2_422),
1159 : CAP_BOOL(GF_CAPS_OUTPUT_STATIC_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
1160 : {0},
1161 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1162 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG4_PART2),
1163 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG1),
1164 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_SPATIAL),
1165 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_SNR),
1166 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_SIMPLE),
1167 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_MAIN),
1168 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_HIGH),
1169 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_422),
1170 : CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
1171 : };
1172 :
1173 :
1174 : #define OFFS(_n) #_n, offsetof(GF_MPGVidDmxCtx, _n)
1175 : static const GF_FilterArgs MPGVidDmxArgs[] =
1176 : {
1177 : { OFFS(fps), "import frame rate (0 default to FPS from bitstream or 25 Hz)", GF_PROP_FRACTION, "0/1000", NULL, 0},
1178 : { OFFS(index), "indexing window length", GF_PROP_DOUBLE, "1.0", NULL, 0},
1179 : { OFFS(vfr), "set variable frame rate import", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
1180 : { OFFS(importer), "compatibility with old importer, displays import results", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
1181 : {0}
1182 : };
1183 :
1184 :
1185 : GF_FilterRegister MPGVidDmxRegister = {
1186 : .name = "rfmpgvid",
1187 : GF_FS_SET_DESCRIPTION("M1V/M2V/M4V reframer")
1188 : GF_FS_SET_HELP("This filter parses MPEG-1/2 and MPEG-4 part 2 video files/data and outputs corresponding video PID and frames.\n"
1189 : "Note: The demux uses negative CTS offsets: CTS is corrrect, but some frames may have DTS greater than CTS.")
1190 : .private_size = sizeof(GF_MPGVidDmxCtx),
1191 : .args = MPGVidDmxArgs,
1192 : .initialize = mpgviddmx_initialize,
1193 : .finalize = mpgviddmx_finalize,
1194 : SETCAPS(MPGVidDmxCaps),
1195 : .configure_pid = mpgviddmx_configure_pid,
1196 : .process = mpgviddmx_process,
1197 : .probe_data = mpgvdmx_probe_data,
1198 : .process_event = mpgviddmx_process_event
1199 : };
1200 :
1201 :
1202 2877 : const GF_FilterRegister *mpgviddmx_register(GF_FilterSession *session)
1203 : {
1204 2877 : return &MPGVidDmxRegister;
1205 : }
1206 :
1207 : #else
1208 : const GF_FilterRegister *mpgviddmx_register(GF_FilterSession *session)
1209 : {
1210 : return NULL;
1211 : }
1212 : #endif // GPAC_DISABLE_AV_PARSERS
1213 :
1214 :
|