1 /*
2 * GPAC - Multimedia Framework C SDK
3 *
4 * Authors: Jean Le Feuvre
5 * Copyright (c) Telecom ParisTech 2005-2017
6 * All rights reserved
7 *
8 * This file is part of GPAC / MPEG Program Stream 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_MPEG2PS
33 #include "../media_tools/mpeg2_ps.h"
34 #include <gpac/media_tools.h>
35
36 typedef struct
37 {
38 GF_FilterPid *opid;
39 u32 stream_type;
40 u32 stream_num;
41 Bool in_use;
42 u64 last_dts;
43 } M2PSStream;
44
45
46 typedef struct
47 {
48 GF_FilterPid *ipid;
49
50 const char *src_url;
51 mpeg2ps_t *ps;
52
53 Double start_range;
54 u64 first_dts;
55
56 u32 nb_playing;
57 GF_Fraction64 duration;
58 Bool in_seek;
59
60 GF_List *streams;
61 Bool initial_play_done;
62 } GF_M2PSDmxCtx;
63
m2psdmx_setup(GF_Filter * filter,GF_M2PSDmxCtx * ctx)64 static void m2psdmx_setup(GF_Filter *filter, GF_M2PSDmxCtx *ctx)
65 {
66 u32 i, nb_streams;
67 u32 sync_id = 0;
68 Double fps;
69 GF_Fraction64 dur;
70
71 dur.den = 1000;
72 dur.num = (s32) mpeg2ps_get_max_time_msec(ctx->ps);
73
74 ctx->first_dts = mpeg2ps_get_first_cts(ctx->ps);
75
76 nb_streams = mpeg2ps_get_video_stream_count(ctx->ps);
77 for (i=0; i<nb_streams; i++) {
78 u32 par;
79 u32 id;
80 GF_Fraction frac;
81 M2PSStream *st = NULL;
82 u32 j, count = gf_list_count(ctx->streams);
83 for (j=0; j<count; j++) {
84 st = gf_list_get(ctx->streams, j);
85 if ((st->stream_type==GF_STREAM_VISUAL) && !st->in_use) break;
86 st = NULL;
87 }
88 if (!st) {
89 GF_SAFEALLOC(st, M2PSStream);
90 if (!st) continue;
91 st->opid = gf_filter_pid_new(filter);
92 st->stream_type = GF_STREAM_VISUAL;
93 gf_list_add(ctx->streams, st);
94 }
95 st->in_use = GF_TRUE;
96 st->stream_num = i;
97 id = 0x100 | mpeg2ps_get_video_stream_id(ctx->ps, st->stream_num);
98 if (!sync_id) sync_id = id;
99
100 gf_filter_pid_copy_properties(st->opid, ctx->ipid);
101 gf_filter_pid_set_name(st->opid, "Video");
102 gf_filter_pid_set_property(st->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(st->stream_type) );
103 switch (mpeg2ps_get_video_stream_type(ctx->ps, st->stream_num)) {
104 case MPEG_VIDEO_MPEG1:
105 gf_filter_pid_set_property(st->opid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_MPEG1) );
106 break;
107 case MPEG_VIDEO_MPEG2:
108 gf_filter_pid_set_property(st->opid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_MPEG2_MAIN) );
109 break;
110 default:
111 break;
112 }
113 gf_filter_pid_set_property(st->opid, GF_PROP_PID_TIMESCALE, &PROP_UINT(90000) );
114 gf_filter_pid_set_property(st->opid, GF_PROP_PID_ID, &PROP_UINT( id) );
115 gf_filter_pid_set_property(st->opid, GF_PROP_PID_CLOCK_ID, &PROP_UINT( sync_id ) );
116
117 fps = mpeg2ps_get_video_stream_framerate(ctx->ps, i);
118 if (fps) {
119 gf_media_get_video_timing(fps, &frac.num, &frac.den);
120 gf_filter_pid_set_property(st->opid, GF_PROP_PID_FPS, &PROP_FRAC( frac ) );
121 }
122 gf_filter_pid_set_property(st->opid, GF_PROP_PID_WIDTH, &PROP_UINT( mpeg2ps_get_video_stream_width(ctx->ps, i) ) );
123 gf_filter_pid_set_property(st->opid, GF_PROP_PID_HEIGHT, &PROP_UINT( mpeg2ps_get_video_stream_height(ctx->ps, i) ) );
124 par = mpeg2ps_get_video_stream_aspect_ratio(ctx->ps, i);
125 if (par) {
126 frac.num = par>>16;
127 frac.den = (par&0xffff);
128 gf_filter_pid_set_property(st->opid, GF_PROP_PID_SAR, &PROP_FRAC( frac ) );
129 }
130 gf_filter_pid_set_property(st->opid, GF_PROP_PID_DURATION, &PROP_FRAC64( dur ) );
131 gf_filter_pid_set_property(st->opid, GF_PROP_PID_UNFRAMED, &PROP_BOOL( GF_TRUE ) );
132 gf_filter_pid_set_property_str(st->opid, "nocts", &PROP_BOOL(GF_TRUE ));
133
134 gf_filter_pid_set_property(st->opid, GF_PROP_PID_BITRATE, &PROP_UINT((u32) mpeg2ps_get_video_stream_bitrate(ctx->ps, i) ) );
135
136 gf_filter_pid_set_property(st->opid, GF_PROP_PID_PLAYBACK_MODE, &PROP_UINT(GF_PLAYBACK_MODE_SEEK ) );
137 }
138
139 nb_streams = mpeg2ps_get_audio_stream_count(ctx->ps);
140 for (i=0; i<nb_streams; i++) {
141 u32 id;
142 char szName[20];
143 M2PSStream *st = NULL;
144 u32 j, count = gf_list_count(ctx->streams);
145
146 if (mpeg2ps_get_audio_stream_type(ctx->ps, i) == MPEG_AUDIO_UNKNOWN) {
147 continue;
148 }
149
150 for (j=0; j<count; j++) {
151 st = gf_list_get(ctx->streams, j);
152 if ((st->stream_type==GF_STREAM_AUDIO) && !st->in_use) break;
153 st = NULL;
154 }
155 if (!st) {
156 GF_SAFEALLOC(st, M2PSStream);
157 if (!st) continue;
158 st->opid = gf_filter_pid_new(filter);
159 st->stream_type = GF_STREAM_AUDIO;
160 gf_list_add(ctx->streams, st);
161 }
162 st->in_use = GF_TRUE;
163 st->stream_num = i;
164 id = 0x100 | mpeg2ps_get_audio_stream_id(ctx->ps, st->stream_num);
165 if (!sync_id) sync_id = id;
166
167 gf_filter_pid_copy_properties(st->opid, ctx->ipid);
168 sprintf(szName, "Audio%d", i+1);
169 gf_filter_pid_set_name(st->opid, szName);
170 gf_filter_pid_set_property(st->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(st->stream_type) );
171 switch (mpeg2ps_get_audio_stream_type(ctx->ps, st->stream_num)) {
172 case MPEG_AUDIO_MPEG:
173 gf_filter_pid_set_property(st->opid, GF_PROP_PID_CODECID, &PROP_UINT( GF_CODECID_MPEG_AUDIO) );
174 break;
175 case MPEG_AUDIO_AC3:
176 gf_filter_pid_set_property(st->opid, GF_PROP_PID_CODECID, &PROP_UINT( GF_CODECID_AC3) );
177 gf_filter_pid_set_property(st->opid, GF_PROP_PID_UNFRAMED, &PROP_BOOL( GF_TRUE) );
178 break;
179 case MPEG_AUDIO_LPCM:
180 gf_filter_pid_set_property(st->opid, GF_PROP_PID_CODECID, &PROP_UINT(GF_4CC('L','P','C','M') ) );
181 break;
182 default:
183 break;
184 }
185 gf_filter_pid_set_property(st->opid, GF_PROP_PID_SAMPLE_RATE, &PROP_UINT( mpeg2ps_get_audio_stream_sample_freq(ctx->ps, i) ) );
186 gf_filter_pid_set_property(st->opid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT( mpeg2ps_get_audio_stream_channels(ctx->ps, i) ) );
187 gf_filter_pid_set_property(st->opid, GF_PROP_PID_BITRATE, &PROP_UINT( mpeg2ps_get_audio_stream_bitrate(ctx->ps, i) ) );
188
189 gf_filter_pid_set_property(st->opid, GF_PROP_PID_TIMESCALE, &PROP_UINT(90000) );
190 gf_filter_pid_set_property(st->opid, GF_PROP_PID_ID, &PROP_UINT( id) );
191 gf_filter_pid_set_property(st->opid, GF_PROP_PID_CLOCK_ID, &PROP_UINT( sync_id ) );
192 gf_filter_pid_set_property(st->opid, GF_PROP_PID_DURATION, &PROP_FRAC64( dur ) );
193 gf_filter_pid_set_property(st->opid, GF_PROP_PID_UNFRAMED, &PROP_BOOL( GF_TRUE ) );
194 gf_filter_pid_set_property_str(st->opid, "nocts", &PROP_BOOL(GF_TRUE ));
195
196 gf_filter_pid_set_property(st->opid, GF_PROP_PID_PLAYBACK_MODE, &PROP_UINT(GF_PLAYBACK_MODE_SEEK ) );
197 }
198 }
199
200
m2psdmx_configure_pid(GF_Filter * filter,GF_FilterPid * pid,Bool is_remove)201 GF_Err m2psdmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
202 {
203 u32 i;
204 const GF_PropertyValue *p;
205 GF_M2PSDmxCtx *ctx = gf_filter_get_udta(filter);
206
207 if (is_remove) {
208 ctx->ipid = NULL;
209 while (gf_list_count(ctx->streams) ) {
210 M2PSStream *st = gf_list_pop_back(ctx->streams);
211 gf_filter_pid_remove(st->opid);
212 gf_free(st);
213 }
214 return GF_OK;
215 }
216 if (! gf_filter_pid_check_caps(pid))
217 return GF_NOT_SUPPORTED;
218
219 if (!ctx->ipid) {
220 GF_FilterEvent fevt;
221 ctx->ipid = pid;
222
223 //we work with full file only, send a play event on source to indicate that
224 GF_FEVT_INIT(fevt, GF_FEVT_PLAY, pid);
225 fevt.play.start_range = 0;
226 fevt.base.on_pid = ctx->ipid;
227 fevt.play.full_file_only = GF_TRUE;
228 gf_filter_pid_send_event(ctx->ipid, &fevt);
229 }
230
231 p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
232 if (!p) return GF_NOT_SUPPORTED;
233
234 if (ctx->src_url && !strcmp(ctx->src_url, p->value.string)) return GF_OK;
235
236 if (ctx->ps) {
237 mpeg2ps_close(ctx->ps);
238 for (i=0; i<gf_list_count(ctx->streams); i++) {
239 M2PSStream *st = gf_list_get(ctx->streams, i);
240 st->in_use = GF_FALSE;
241 }
242 }
243 ctx->ps = NULL;
244
245 ctx->src_url = p->value.string;
246
247 return GF_OK;
248 }
249
m2psdmx_process_event(GF_Filter * filter,const GF_FilterEvent * evt)250 static Bool m2psdmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
251 {
252 u32 i;
253 GF_M2PSDmxCtx *ctx = gf_filter_get_udta(filter);
254
255 switch (evt->base.type) {
256 case GF_FEVT_PLAY:
257 if (ctx->nb_playing && (ctx->start_range == evt->play.start_range)) {
258 ctx->nb_playing++;
259 return GF_TRUE;
260 }
261 ctx->nb_playing++;
262 ctx->start_range = evt->play.start_range;
263 gf_filter_post_process_task(filter);
264
265 if (!ctx->initial_play_done) {
266 ctx->initial_play_done = GF_TRUE;
267 //seek will not change the current source state, don't send a seek
268 if (ctx->start_range<0.5)
269 return GF_TRUE;
270 }
271
272 for (i=0; i<gf_list_count(ctx->streams); i++) {
273 M2PSStream *pss = gf_list_get(ctx->streams, i);
274 if (pss->opid == evt->base.on_pid)
275 pss->in_use = GF_TRUE;
276 if (!pss->in_use) continue;
277
278 if (pss->stream_type==GF_STREAM_VISUAL) {
279 mpeg2ps_seek_video_frame(ctx->ps, pss->stream_num, (u64) (ctx->start_range*1000));
280 } else {
281 mpeg2ps_seek_audio_frame(ctx->ps, pss->stream_num, (u64) (ctx->start_range*1000) );
282 }
283 }
284 //cancel event
285 return GF_TRUE;
286
287 case GF_FEVT_STOP:
288 ctx->nb_playing--;
289 for (i=0; i<gf_list_count(ctx->streams); i++) {
290 M2PSStream *pss = gf_list_get(ctx->streams, i);
291 if (pss->opid == evt->base.on_pid)
292 pss->in_use = GF_FALSE;
293 }
294 //cancel event if not last stream playing
295 if (ctx->nb_playing) return GF_TRUE;
296
297 return GF_FALSE;
298
299 case GF_FEVT_SET_SPEED:
300 //cancel event
301 return GF_TRUE;
302 default:
303 break;
304 }
305 //by default don't cancel event - to rework once we have downloading in place
306 return GF_FALSE;
307 }
308
m2psdmx_process(GF_Filter * filter)309 GF_Err m2psdmx_process(GF_Filter *filter)
310 {
311 GF_M2PSDmxCtx *ctx = gf_filter_get_udta(filter);
312 Bool start, end;
313 u32 i, count, nb_done;
314 if (!ctx->ps) {
315 GF_FilterPacket *pck = gf_filter_pid_get_packet(ctx->ipid);
316 if (!pck) {
317 return GF_OK;
318 }
319 gf_filter_pck_get_framing(pck, &start, &end);
320 if (!end) {
321 gf_filter_pid_drop_packet(ctx->ipid);
322 return GF_OK;
323 }
324 gf_filter_pid_drop_packet(ctx->ipid);
325
326 ctx->ps = mpeg2ps_init(ctx->src_url);
327 if (!ctx->ps) {
328 GF_Err e = GF_NON_COMPLIANT_BITSTREAM;
329 if (! gf_file_exists(ctx->src_url)) e = GF_URL_ERROR;
330 gf_filter_setup_failure(filter, e);
331 return GF_NOT_SUPPORTED;
332 }
333 m2psdmx_setup(filter, ctx);
334 }
335 if (!ctx->nb_playing) return GF_OK;
336
337
338 nb_done = 0;
339 count = gf_list_count(ctx->streams);
340
341 if (ctx->in_seek) {
342 u64 seek_to = (u64) (1000*ctx->start_range);
343 for (i=0; i<count;i++) {
344 M2PSStream *st = gf_list_get(ctx->streams, i);
345 if (!st->in_use) continue;
346 if (st->stream_type==GF_STREAM_VISUAL) {
347 mpeg2ps_seek_video_frame(ctx->ps, st->stream_num, seek_to);
348 } else {
349 mpeg2ps_seek_audio_frame(ctx->ps, st->stream_num, seek_to);
350 }
351 }
352 ctx->in_seek = GF_FALSE;
353 }
354
355
356 for (i=0; i<count;i++) {
357 u8 *buf;
358 u32 buf_len;
359 u8 *pck_data;
360 GF_FilterPacket *dst_pck;
361 M2PSStream *st = gf_list_get(ctx->streams, i);
362 if (!st->in_use) {
363 nb_done++;
364 continue;
365 }
366
367 if (gf_filter_pid_would_block(st->opid)) continue;
368
369 if (st->stream_type==GF_STREAM_VISUAL) {
370 u8 ftype;
371 u64 dts, cts;
372 u32 res = mpeg2ps_get_video_frame(ctx->ps, st->stream_num, (u8 **) &buf, &buf_len, &ftype, TS_90000, &dts, &cts);
373 if (!res) {
374 nb_done++;
375 continue;
376 }
377
378 //bug in some streams, make sure we don't dispatch twice the same ts
379 if (st->last_dts == dts) dts++;;
380 st->last_dts = dts;
381
382 if ((buf[buf_len - 4] == 0) && (buf[buf_len - 3] == 0) && (buf[buf_len - 2] == 1)) buf_len -= 4;
383 dst_pck = gf_filter_pck_new_alloc(st->opid, buf_len, &pck_data);
384 memcpy(pck_data, buf, buf_len);
385 if (ftype==1) gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
386
387 if (cts != GF_FILTER_NO_TS) {
388 if (dts == GF_FILTER_NO_TS) dts = cts;
389 dts -= ctx->first_dts;
390 cts -= ctx->first_dts;
391 gf_filter_pck_set_dts(dst_pck, dts);
392 gf_filter_pck_set_cts(dst_pck, cts);
393 gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_FALSE);
394 } else {
395 gf_filter_pck_set_framing(dst_pck, GF_FALSE, GF_FALSE);
396 }
397 gf_filter_pck_send(dst_pck);
398 } else {
399 u64 cts;
400 u32 res = mpeg2ps_get_audio_frame(ctx->ps, st->stream_num, (u8**)&buf, &buf_len, TS_90000, NULL, &cts);
401 if (!res) {
402 nb_done++;
403 continue;
404 }
405 dst_pck = gf_filter_pck_new_alloc(st->opid, buf_len, &pck_data);
406 memcpy(pck_data, buf, buf_len);
407 if (cts != GF_FILTER_NO_TS) {
408 cts -= ctx->first_dts;
409 gf_filter_pck_set_cts(dst_pck, cts);
410 gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_FALSE);
411 } else {
412 gf_filter_pck_set_framing(dst_pck, GF_FALSE, GF_FALSE);
413 }
414 gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
415
416 gf_filter_pck_send(dst_pck);
417 }
418 }
419
420 if (nb_done==count) {
421 for (i=0; i<count;i++) {
422 M2PSStream *st = gf_list_get(ctx->streams, i);
423 gf_filter_pid_set_eos(st->opid);
424 }
425 return GF_EOS;
426 }
427 return GF_OK;
428 }
429
m2psdmx_initialize(GF_Filter * filter)430 GF_Err m2psdmx_initialize(GF_Filter *filter)
431 {
432 GF_M2PSDmxCtx *ctx = gf_filter_get_udta(filter);
433 ctx->streams = gf_list_new();
434 return GF_OK;
435 }
436
m2psdmx_finalize(GF_Filter * filter)437 void m2psdmx_finalize(GF_Filter *filter)
438 {
439 GF_M2PSDmxCtx *ctx = gf_filter_get_udta(filter);
440
441 while (gf_list_count(ctx->streams)) {
442 M2PSStream *st = gf_list_pop_back(ctx->streams);
443 gf_free(st);
444 }
445 gf_list_del(ctx->streams);
446 if (ctx->ps) mpeg2ps_close(ctx->ps);
447 }
448
m2psdmx_probe_data(const u8 * data,u32 size,GF_FilterProbeScore * score)449 static const char *m2psdmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
450 {
451 *score = GF_FPROBE_EXT_MATCH;
452 return "mpg|mpeg|vob";
453 }
454
455 static const GF_FilterCapability M2PSDmxCaps[] =
456 {
457 CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
458 CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "mpg|mpeg|vob"),
459 CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "video/mpeg|audio/mpeg"),
460 CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
461 CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
462 CAP_UINT(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_RAW),
463 };
464
465
466
467 GF_FilterRegister M2PSDmxRegister = {
468 .name = "m2psdmx",
469 GF_FS_SET_DESCRIPTION("MPEG PS demuxer")
470 GF_FS_SET_HELP("This filter demultiplexes MPEG-2 program stream files/data to produce media PIDs and frames.")
471 .private_size = sizeof(GF_M2PSDmxCtx),
472 .initialize = m2psdmx_initialize,
473 .finalize = m2psdmx_finalize,
474 SETCAPS(M2PSDmxCaps),
475 .configure_pid = m2psdmx_configure_pid,
476 .process = m2psdmx_process,
477 .process_event = m2psdmx_process_event,
478 .probe_data = m2psdmx_probe_data,
479 //this filter is not very reliable, prefer ffmpeg when available
480 .priority = 255
481 };
482
483 #endif // GPAC_DISABLE_MPEG2PS
484
m2psdmx_register(GF_FilterSession * session)485 const GF_FilterRegister *m2psdmx_register(GF_FilterSession *session)
486 {
487 #ifndef GPAC_DISABLE_MPEG2PS
488 return &M2PSDmxRegister;
489 #else
490 return NULL;
491 #endif
492 }
493
494