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