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 / M2TS demux 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 :
29 :
30 : #ifndef GPAC_DISABLE_MPEG2TS
31 :
32 : #include <gpac/mpegts.h>
33 : #include <gpac/thread.h>
34 :
35 : typedef struct {
36 : char *fragment;
37 : u32 id;
38 : /*if only pid is requested*/
39 : u32 pid;
40 : } GF_M2TSDmxCtx_Prog;
41 :
42 : typedef struct {
43 : u32 timeline_id;
44 : Bool is_loc;
45 : u32 len;
46 : u8 *data;
47 : } GF_TEMIInfo;
48 :
49 : enum
50 : {
51 : DMX_TUNE_DONE=0,
52 : DMX_TUNE_INIT,
53 : DMX_TUNE_WAIT_PROGS,
54 : DMX_TUNE_WAIT_SEEK,
55 :
56 : };
57 :
58 : typedef struct
59 : {
60 : //opts
61 : const char *temi_url;
62 : Bool dsmcc, seeksrc, sigfrag;
63 :
64 : GF_Filter *filter;
65 : GF_FilterPid *ipid;
66 :
67 : GF_M2TS_Demuxer *ts;
68 :
69 : GF_FilterPid *eit_pid;
70 :
71 : Bool is_file;
72 : u64 file_size;
73 : Bool in_seek;
74 : Bool initial_play_done;
75 : u32 nb_playing;
76 :
77 : //duration estimation
78 : GF_Fraction64 duration;
79 : u64 first_pcr_found;
80 : u16 pcr_pid;
81 : u64 nb_pck_at_pcr;
82 :
83 : u32 map_time_on_prog_id;
84 : Double media_start_range;
85 :
86 : u32 mux_tune_state;
87 : u32 wait_for_progs;
88 : } GF_M2TSDmxCtx;
89 :
90 :
91 15004 : static void m2tsdmx_estimate_duration(GF_M2TSDmxCtx *ctx, GF_M2TS_ES *stream)
92 : {
93 : Bool changed;
94 : Double pck_dur;
95 : const GF_PropertyValue *p;
96 :
97 15004 : if (ctx->duration.num) return;
98 2404 : if (!ctx->file_size) {
99 31 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_DOWN_SIZE);
100 31 : if (p) {
101 31 : ctx->file_size = p->value.longuint;
102 : } else {
103 0 : ctx->duration.num = 1;
104 : return;
105 : }
106 : }
107 :
108 2404 : if (!ctx->first_pcr_found) {
109 31 : ctx->first_pcr_found = stream->program->last_pcr_value;
110 31 : ctx->pcr_pid = stream->pid;
111 31 : ctx->nb_pck_at_pcr = ctx->ts->pck_number;
112 : return;
113 : }
114 2373 : if (ctx->pcr_pid != stream->pid) return;
115 1485 : if (stream->program->last_pcr_value < ctx->first_pcr_found) {
116 0 : ctx->first_pcr_found = stream->program->last_pcr_value;
117 0 : ctx->pcr_pid = stream->pid;
118 0 : ctx->nb_pck_at_pcr = ctx->ts->pck_number;
119 : return;
120 : }
121 1485 : if (stream->program->last_pcr_value - ctx->first_pcr_found <= 2*27000000)
122 : return;
123 :
124 : changed = GF_FALSE;
125 :
126 31 : pck_dur = (Double) (stream->program->last_pcr_value - ctx->first_pcr_found);
127 31 : pck_dur /= (ctx->ts->pck_number - ctx->nb_pck_at_pcr);
128 31 : pck_dur /= 27000;
129 :
130 31 : pck_dur *= ctx->file_size;
131 31 : pck_dur /= ctx->ts->prefix_present ? 192 : 188;
132 31 : if ((u32) ctx->duration.num != (u32) pck_dur) {
133 31 : ctx->duration.num = (s32) pck_dur;
134 31 : ctx->duration.den = 1000;
135 : changed = GF_TRUE;
136 : }
137 31 : ctx->first_pcr_found = stream->program->last_pcr_value;
138 31 : ctx->pcr_pid = stream->pid;
139 31 : ctx->nb_pck_at_pcr = ctx->ts->pck_number;
140 31 : GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[M2TSDmx] Estimated duration based on instant bitrate: %g sec\n", pck_dur/1000));
141 :
142 31 : if (changed) {
143 31 : u32 i, nb_streams = gf_filter_get_opid_count(ctx->filter);
144 0 : for (i=0; i<nb_streams; i++) {
145 0 : GF_FilterPid *opid = gf_filter_get_opid(ctx->filter, i);
146 0 : gf_filter_pid_set_property(opid, GF_PROP_PID_DURATION, &PROP_FRAC64(ctx->duration) );
147 : }
148 : }
149 : }
150 :
151 5266 : static void m2tsdmx_on_event_duration_probe(GF_M2TS_Demuxer *ts, u32 evt_type, void *param)
152 : {
153 5266 : GF_Filter *filter = (GF_Filter *) ts->user;
154 5266 : GF_M2TSDmxCtx *ctx = gf_filter_get_udta(filter);
155 :
156 5266 : if (evt_type == GF_M2TS_EVT_PES_PCR) {
157 : GF_M2TS_PES_PCK *pck = ((GF_M2TS_PES_PCK *) param);
158 :
159 2424 : if (pck->stream) m2tsdmx_estimate_duration(ctx, (GF_M2TS_ES *) pck->stream);
160 : }
161 5266 : }
162 :
163 117 : static void m2tsdmx_declare_pid(GF_M2TSDmxCtx *ctx, GF_M2TS_PES *stream, GF_ESD *esd)
164 : {
165 : u32 i, count, codecid=0, stype=0;
166 : GF_FilterPid *opid;
167 : Bool m4sys_stream = GF_FALSE;
168 : Bool m4sys_iod_stream = GF_FALSE;
169 : Bool has_scal_layer = GF_FALSE;
170 : Bool unframed = GF_FALSE;
171 : char szName[20];
172 : const char *stname;
173 144 : if (stream->user) return;
174 :
175 117 : if (stream->flags & GF_M2TS_GPAC_CODEC_ID) {
176 0 : codecid = stream->stream_type;
177 0 : stype = gf_codecid_type(codecid);
178 : unframed = GF_TRUE;
179 0 : if (!stype) {
180 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[M2TSDmx] Unrecognized gpac codec %s - ignoring pid\n", gf_4cc_to_str(codecid) ));
181 : return;
182 : }
183 : } else {
184 :
185 117 : switch (stream->stream_type) {
186 : case GF_M2TS_VIDEO_MPEG1:
187 : stype = GF_STREAM_VISUAL;
188 : codecid = GF_CODECID_MPEG1;
189 : unframed = GF_TRUE;
190 : break;
191 18 : case GF_M2TS_VIDEO_MPEG2:
192 : case GF_M2TS_VIDEO_DCII:
193 : stype = GF_STREAM_VISUAL;
194 : codecid = GF_CODECID_MPEG2_MAIN;
195 : unframed = GF_TRUE;
196 18 : break;
197 0 : case GF_M2TS_VIDEO_MPEG4:
198 : stype = GF_STREAM_VISUAL;
199 : codecid = GF_CODECID_MPEG4_PART2;
200 : unframed = GF_TRUE;
201 0 : break;
202 21 : case GF_M2TS_VIDEO_H264:
203 : stype = GF_STREAM_VISUAL;
204 : codecid = GF_CODECID_AVC;
205 : unframed = GF_TRUE;
206 21 : if (stream->program->is_scalable)
207 : has_scal_layer = GF_TRUE;
208 : break;
209 0 : case GF_M2TS_VIDEO_SVC:
210 : stype = GF_STREAM_VISUAL;
211 : codecid = GF_CODECID_SVC;
212 : has_scal_layer = GF_TRUE;
213 : unframed = GF_TRUE;
214 0 : break;
215 0 : case GF_M2TS_VIDEO_HEVC:
216 : case GF_M2TS_VIDEO_HEVC_TEMPORAL:
217 : case GF_M2TS_VIDEO_HEVC_MCTS:
218 : stype = GF_STREAM_VISUAL;
219 : codecid = GF_CODECID_HEVC;
220 : unframed = GF_TRUE;
221 0 : if (stream->program->is_scalable)
222 : has_scal_layer = GF_TRUE;
223 : break;
224 1 : case GF_M2TS_VIDEO_SHVC:
225 : case GF_M2TS_VIDEO_SHVC_TEMPORAL:
226 : case GF_M2TS_VIDEO_MHVC:
227 : case GF_M2TS_VIDEO_MHVC_TEMPORAL:
228 : stype = GF_STREAM_VISUAL;
229 : codecid = GF_CODECID_LHVC;
230 : has_scal_layer = GF_TRUE;
231 1 : break;
232 0 : case GF_M2TS_VIDEO_VVC:
233 : case GF_M2TS_VIDEO_VVC_TEMPORAL:
234 : stype = GF_STREAM_VISUAL;
235 : codecid = GF_CODECID_VVC;
236 : unframed = GF_TRUE;
237 0 : break;
238 0 : case GF_M2TS_VIDEO_VC1:
239 : stype = GF_STREAM_VISUAL;
240 : codecid = GF_CODECID_SMPTE_VC1;
241 0 : break;
242 24 : case GF_M2TS_AUDIO_MPEG1:
243 : stype = GF_STREAM_AUDIO;
244 : codecid = GF_CODECID_MPEG_AUDIO;
245 : unframed = GF_TRUE;
246 24 : break;
247 0 : case GF_M2TS_AUDIO_MPEG2:
248 : stype = GF_STREAM_AUDIO;
249 : codecid = GF_CODECID_MPEG2_PART3;
250 : unframed = GF_TRUE;
251 0 : break;
252 18 : case GF_M2TS_AUDIO_LATM_AAC:
253 : case GF_M2TS_AUDIO_AAC:
254 : case GF_CODECID_AAC_MPEG2_MP:
255 : case GF_CODECID_AAC_MPEG2_LCP:
256 : case GF_CODECID_AAC_MPEG2_SSRP:
257 : stype = GF_STREAM_AUDIO;
258 : codecid = GF_CODECID_AAC_MPEG4;
259 : unframed = GF_TRUE;
260 18 : break;
261 0 : case GF_M2TS_MHAS_MAIN:
262 : case GF_M2TS_MHAS_AUX:
263 : stype = GF_STREAM_AUDIO;
264 : codecid = GF_CODECID_MHAS;
265 : unframed = GF_TRUE;
266 0 : break;
267 2 : case GF_M2TS_AUDIO_AC3:
268 : stype = GF_STREAM_AUDIO;
269 : codecid = GF_CODECID_AC3;
270 : unframed = GF_TRUE;
271 2 : break;
272 0 : case GF_M2TS_AUDIO_EC3:
273 : stype = GF_STREAM_AUDIO;
274 : codecid = GF_CODECID_EAC3;
275 0 : break;
276 2 : case GF_M2TS_SYSTEMS_MPEG4_SECTIONS:
277 2 : ((GF_M2TS_ES*)stream)->flags |= GF_M2TS_ES_SEND_REPEATED_SECTIONS;
278 : //fallthrough
279 2 : case GF_M2TS_SYSTEMS_MPEG4_PES:
280 2 : if (!esd) {
281 : m4sys_iod_stream = GF_TRUE;
282 2 : count = gf_list_count(stream->program->pmt_iod->ESDescriptors);
283 3 : for (i=0; i<count; i++) {
284 3 : esd = gf_list_get(stream->program->pmt_iod->ESDescriptors, i);
285 3 : if (esd->ESID == stream->mpeg4_es_id) break;
286 : esd = NULL;
287 : }
288 : }
289 : m4sys_stream = GF_TRUE;
290 : //cannot setup stream yet
291 2 : if (!esd) return;
292 : break;
293 4 : case GF_M2TS_METADATA_PES:
294 : case GF_M2TS_METADATA_ID3_HLS:
295 : stype = GF_STREAM_METADATA;
296 : codecid = GF_CODECID_SIMPLE_TEXT;
297 4 : break;
298 0 : case 0xA1:
299 : stype = GF_STREAM_AUDIO;
300 : codecid = GF_CODECID_EAC3;
301 0 : break;
302 27 : default:
303 27 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[M2TSDmx] Stream type 0x%02X not supported - ignoring pid\n", stream->stream_type));
304 : return;
305 : }
306 : }
307 :
308 90 : opid = gf_filter_pid_new(ctx->filter);
309 90 : stream->user = opid;
310 90 : stream->flags |= GF_M2TS_ES_ALREADY_DECLARED;
311 :
312 90 : stname = gf_stream_type_name(stype);
313 90 : sprintf(szName, "P%d%c%d", stream->program->number, stname[0], 1+gf_list_find(stream->program->streams, stream));
314 90 : gf_filter_pid_set_name(opid, szName);
315 :
316 90 : gf_filter_pid_set_property(opid, GF_PROP_PID_ID, &PROP_UINT(stream->pid) );
317 90 : if (stream->mpeg4_es_id)
318 3 : gf_filter_pid_set_property(opid, GF_PROP_PID_ESID, &PROP_UINT(stream->mpeg4_es_id) );
319 :
320 90 : if (m4sys_stream) {
321 2 : if (stream->slcfg) gf_free(stream->slcfg);
322 :
323 2 : stream->slcfg = esd->slConfig;
324 2 : esd->slConfig = NULL;
325 :
326 2 : gf_filter_pid_set_property(opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(esd->decoderConfig ? esd->decoderConfig->streamType : GF_STREAM_SCENE) );
327 2 : gf_filter_pid_set_property(opid, GF_PROP_PID_CODECID, &PROP_UINT(esd->decoderConfig ? esd->decoderConfig->objectTypeIndication : GF_CODECID_BIFS) );
328 2 : gf_filter_pid_set_property(opid, GF_PROP_PID_CLOCK_ID, &PROP_UINT(esd->OCRESID ? esd->OCRESID : esd->ESID) );
329 2 : gf_filter_pid_set_property(opid, GF_PROP_PID_DEPENDENCY_ID, &PROP_UINT(esd->dependsOnESID) );
330 2 : if (esd->decoderConfig && esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->dataLength)
331 1 : gf_filter_pid_set_property(opid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength) );
332 :
333 2 : gf_filter_pid_set_property(opid, GF_PROP_PID_IN_IOD, &PROP_BOOL(m4sys_iod_stream) );
334 :
335 2 : gf_filter_pid_set_property(opid, GF_PROP_PID_TIMESCALE, &PROP_UINT(((GF_M2TS_ES*)stream)->slcfg->timestampResolution) );
336 2 : if (esd->decoderConfig && (esd->decoderConfig->streamType==GF_STREAM_OD))
337 1 : stream->flags |= GF_M2TS_ES_IS_MPEG4_OD;
338 : } else {
339 88 : gf_filter_pid_set_property(opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(stype) );
340 88 : gf_filter_pid_set_property(opid, GF_PROP_PID_CODECID, &PROP_UINT(codecid) );
341 88 : if (unframed)
342 83 : gf_filter_pid_set_property(opid, GF_PROP_PID_UNFRAMED, &PROP_BOOL(GF_TRUE) );
343 :
344 88 : gf_filter_pid_set_property(opid, GF_PROP_PID_TIMESCALE, &PROP_UINT(90000) );
345 88 : gf_filter_pid_set_property(opid, GF_PROP_PID_CLOCK_ID, &PROP_UINT(stream->program->pcr_pid) );
346 : }
347 90 : if (has_scal_layer)
348 1 : gf_filter_pid_set_property(opid, GF_PROP_PID_SCALABLE, &PROP_BOOL(GF_TRUE));
349 :
350 90 : gf_filter_pid_set_property(opid, GF_PROP_PID_SERVICE_ID, &PROP_UINT(stream->program->number) );
351 :
352 90 : if (ctx->duration.num>1) {
353 89 : gf_filter_pid_set_property(opid, GF_PROP_PID_DURATION, &PROP_FRAC64(ctx->duration) );
354 89 : gf_filter_pid_set_property(opid, GF_PROP_PID_PLAYBACK_MODE, &PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD ) );
355 : }
356 : /*indicate our coding dependencies if any*/
357 90 : if (!m4sys_stream) {
358 88 : if (stream->depends_on_pid) {
359 0 : gf_filter_pid_set_property(opid, GF_PROP_PID_DEPENDENCY_ID, &PROP_UINT(stream->depends_on_pid) );
360 0 : if ((stream->stream_type == GF_M2TS_VIDEO_HEVC_TEMPORAL) || (stream->stream_type == GF_M2TS_VIDEO_HEVC_MCTS)) {
361 0 : gf_filter_pid_set_property(opid, GF_PROP_PID_SUBLAYER, &PROP_BOOL(GF_TRUE) );
362 : }
363 : }
364 : }
365 90 : gf_m2ts_set_pes_framing((GF_M2TS_PES *)stream, GF_M2TS_PES_FRAMING_DEFAULT);
366 : }
367 :
368 50 : static void m2tsdmx_setup_program(GF_M2TSDmxCtx *ctx, GF_M2TS_Program *prog)
369 : {
370 : u32 i, count;
371 :
372 50 : count = gf_list_count(prog->streams);
373 : #ifdef FILTER_FIXME
374 : if (ctx->ts->tuner) {
375 : Bool found = 0;
376 : for (i=0; i<count; i++) {
377 : GF_M2TS_PES *pes = gf_list_get(prog->streams, i);
378 : if (pes->pid==ctx->ts->tuner->vpid) found = 1;
379 : else if (pes->pid==ctx->ts->tuner->apid) found = 1;
380 : }
381 : if (!found) return;
382 : }
383 : #endif
384 :
385 217 : for (i=0; i<count; i++) {
386 167 : GF_M2TS_PES *es = gf_list_get(prog->streams, i);
387 167 : if (es->pid==prog->pmt_pid) continue;
388 117 : if (! (es->flags & GF_M2TS_ES_IS_PES)) continue;
389 :
390 112 : if (es->stream_type == GF_M2TS_VIDEO_HEVC_TEMPORAL ) continue;
391 112 : if (es->depends_on_pid ) {
392 0 : prog->is_scalable = GF_TRUE;
393 0 : break;
394 : }
395 : }
396 :
397 167 : for (i=0; i<count; i++) {
398 : u32 ncount;
399 167 : GF_M2TS_ES *es = gf_list_get(prog->streams, i);
400 167 : if (es->pid==prog->pmt_pid) continue;
401 :
402 117 : if (! (es->flags & GF_M2TS_ES_ALREADY_DECLARED)) {
403 117 : m2tsdmx_declare_pid(ctx, (GF_M2TS_PES *)es, NULL);
404 : }
405 117 : ncount = gf_list_count(prog->streams);
406 234 : while (ncount<count) {
407 0 : i--;
408 0 : count--;
409 : }
410 : }
411 50 : }
412 :
413 20686 : static void m2tdmx_merge_temi(GF_M2TS_ES *stream, GF_FilterPacket *pck)
414 : {
415 20686 : if (stream->props) {
416 : char szID[100];
417 2782 : while (gf_list_count(stream->props)) {
418 1430 : GF_TEMIInfo *t = gf_list_pop_front(stream->props);
419 1430 : snprintf(szID, 100, "%s:%d", t->is_loc ? "temi_l" : "temi_t", t->timeline_id);
420 :
421 1430 : gf_filter_pck_set_property_dyn(pck, szID, &PROP_DATA_NO_COPY(t->data, t->len));
422 1430 : gf_free(t);
423 : }
424 1352 : gf_list_del(stream->props);
425 1352 : stream->props = NULL;
426 : }
427 20686 : }
428 :
429 20684 : static void m2tsdmx_send_packet(GF_M2TSDmxCtx *ctx, GF_M2TS_PES_PCK *pck)
430 : {
431 : GF_FilterPid *opid;
432 : GF_FilterPacket *dst_pck;
433 : u8 * data;
434 :
435 : /*pcr not initialized, don't send any data*/
436 : // if (! pck->stream->program->first_dts) return;
437 20684 : if (!pck->stream->user) return;
438 : opid = pck->stream->user;
439 :
440 20684 : dst_pck = gf_filter_pck_new_alloc(opid, pck->data_len, &data);
441 20684 : if (!dst_pck) return;
442 :
443 20684 : memcpy(data, pck->data, pck->data_len);
444 : //we don't have end of frame signaling
445 20684 : gf_filter_pck_set_framing(dst_pck, (pck->flags & GF_M2TS_PES_PCK_AU_START) ? GF_TRUE : GF_FALSE, GF_FALSE);
446 :
447 20684 : if (pck->flags & GF_M2TS_PES_PCK_AU_START) {
448 20682 : gf_filter_pck_set_cts(dst_pck, pck->PTS);
449 20682 : if (pck->DTS != pck->PTS) {
450 3349 : gf_filter_pck_set_dts(dst_pck, pck->DTS);
451 : }
452 20682 : gf_filter_pck_set_sap(dst_pck, (pck->flags & GF_M2TS_PES_PCK_RAP) ? GF_FILTER_SAP_1 : GF_FILTER_SAP_NONE);
453 : }
454 20684 : m2tdmx_merge_temi((GF_M2TS_ES *)pck->stream, dst_pck);
455 :
456 20684 : if (pck->stream->is_seg_start) {
457 0 : pck->stream->is_seg_start = GF_FALSE;
458 0 : gf_filter_pck_set_property(dst_pck, GF_PROP_PCK_CUE_START, &PROP_BOOL(GF_TRUE));
459 : }
460 20684 : gf_filter_pck_send(dst_pck);
461 : }
462 :
463 1 : static GF_M2TS_ES *m2tsdmx_get_m4sys_stream(GF_M2TSDmxCtx *ctx, u32 m4sys_es_id)
464 : {
465 : u32 i, j, count, count2;
466 1 : count = gf_list_count(ctx->ts->programs);
467 0 : for (i=0; i<count; i++) {
468 1 : GF_M2TS_Program *prog = gf_list_get(ctx->ts->programs, i);
469 1 : count2 = gf_list_count(prog->streams);
470 1 : for (j=0; j<count2; j++) {
471 2 : GF_M2TS_ES *pes = (GF_M2TS_ES *)gf_list_get(prog->streams, j);
472 2 : if (pes->mpeg4_es_id == m4sys_es_id) return pes;
473 : }
474 : }
475 : return NULL;
476 : }
477 2 : static GFINLINE void m2tsdmx_send_sl_packet(GF_M2TSDmxCtx *ctx, GF_M2TS_SL_PCK *pck)
478 : {
479 2 : GF_SLConfig *slc = ((GF_M2TS_ES*)pck->stream)->slcfg;
480 : GF_FilterPid *opid;
481 : GF_FilterPacket *dst_pck;
482 : u8 * data;
483 : Bool start, end;
484 : GF_SLHeader slh;
485 2 : u32 slh_len = 0;
486 :
487 2 : if (!pck->stream->user) return;
488 : opid = pck->stream->user;
489 :
490 : /*depacketize SL Header*/
491 2 : if (((GF_M2TS_ES*)pck->stream)->slcfg) {
492 2 : gf_sl_depacketize(slc, &slh, pck->data, pck->data_len, &slh_len);
493 2 : slh.m2ts_version_number_plus_one = pck->version_number + 1;
494 : } else {
495 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDmx] MPEG-4 SL-packetized stream without SLConfig assigned - ignoring packet\n") );
496 : return;
497 : }
498 :
499 2 : dst_pck = gf_filter_pck_new_alloc(opid, pck->data_len - slh_len, &data);
500 2 : if (!dst_pck) return;
501 :
502 2 : memcpy(data, pck->data + slh_len, pck->data_len - slh_len);
503 : start = end = GF_FALSE;
504 2 : if (slc->useAccessUnitStartFlag && slh.accessUnitStartFlag) start = GF_TRUE;
505 2 : if (slc->useAccessUnitEndFlag && slh.accessUnitEndFlag) end = GF_TRUE;
506 2 : gf_filter_pck_set_framing(dst_pck, start, end);
507 :
508 2 : if (slc->useTimestampsFlag && slh.decodingTimeStampFlag)
509 0 : gf_filter_pck_set_dts(dst_pck, slh.decodingTimeStamp);
510 :
511 2 : if (slc->useTimestampsFlag && slh.compositionTimeStampFlag)
512 2 : gf_filter_pck_set_cts(dst_pck, slh.compositionTimeStamp);
513 :
514 2 : if (slc->hasRandomAccessUnitsOnlyFlag || slh.randomAccessPointFlag)
515 2 : gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
516 :
517 2 : gf_filter_pck_set_carousel_version(dst_pck, pck->version_number);
518 :
519 2 : m2tdmx_merge_temi(pck->stream, dst_pck);
520 2 : if (pck->stream->is_seg_start) {
521 0 : pck->stream->is_seg_start = GF_FALSE;
522 0 : gf_filter_pck_set_property(dst_pck, GF_PROP_PCK_CUE_START, &PROP_BOOL(GF_TRUE));
523 : }
524 2 : gf_filter_pck_send(dst_pck);
525 :
526 2 : if (pck->version_number + 1 == pck->stream->slcfg->carousel_version)
527 : return;
528 2 : pck->stream->slcfg->carousel_version = 1 + pck->version_number;
529 :
530 :
531 2 : if (pck->stream->flags & GF_M2TS_ES_IS_MPEG4_OD) {
532 : /* We need to decode OD streams to get the SL config for other streams :( */
533 : GF_ESD *esd;
534 : GF_ODUpdate* odU;
535 : GF_ESDUpdate* esdU;
536 : u32 com_count, com_index, od_count, od_index, esd_index;
537 1 : GF_ODCodec *od_codec = gf_odf_codec_new();
538 :
539 1 : gf_odf_codec_set_au(od_codec, pck->data + slh_len, pck->data_len - slh_len);
540 1 : gf_odf_codec_decode(od_codec);
541 1 : com_count = gf_list_count(od_codec->CommandList);
542 2 : for (com_index = 0; com_index < com_count; com_index++) {
543 : GF_ODCom *com;
544 1 : com = (GF_ODCom *)gf_list_get(od_codec->CommandList, com_index);
545 1 : switch (com->tag) {
546 1 : case GF_ODF_OD_UPDATE_TAG:
547 : odU = (GF_ODUpdate*)com;
548 1 : od_count = gf_list_count(odU->objectDescriptors);
549 2 : for (od_index=0; od_index<od_count; od_index++) {
550 1 : GF_ObjectDescriptor *od = (GF_ObjectDescriptor *)gf_list_get(odU->objectDescriptors, od_index);
551 1 : esd_index = 0;
552 3 : while ( (esd = gf_list_enum(od->ESDescriptors, &esd_index)) ) {
553 1 : GF_M2TS_ES *es = m2tsdmx_get_m4sys_stream(ctx, esd->ESID);
554 :
555 1 : if (es && ! (es->flags & GF_M2TS_ES_ALREADY_DECLARED)) {
556 0 : m2tsdmx_declare_pid(ctx, (GF_M2TS_PES *)es, esd);
557 : }
558 : }
559 : }
560 : break;
561 0 : case GF_ODF_ESD_UPDATE_TAG:
562 : esdU = (GF_ESDUpdate*)com;
563 0 : esd_index = 0;
564 0 : while ( (esd = gf_list_enum(esdU->ESDescriptors, &esd_index)) ) {
565 0 : GF_M2TS_ES *es = m2tsdmx_get_m4sys_stream(ctx, esd->ESID);
566 0 : if (es && ! (es->flags & GF_M2TS_ES_ALREADY_DECLARED)) {
567 0 : m2tsdmx_declare_pid(ctx, (GF_M2TS_PES *)es, esd);
568 : }
569 : }
570 : break;
571 : }
572 : }
573 1 : gf_odf_codec_del(od_codec);
574 : }
575 : }
576 :
577 : #ifdef FILTER_FIXME
578 : static void m2tsdmx_declare_epg_pid(GF_M2TSDmxCtx *ctx)
579 : {
580 : assert(ctx->eit_pid == NULL);
581 : ctx->eit_pid = gf_filter_pid_new(ctx->filter);
582 : gf_filter_pid_set_property(ctx->eit_pid, GF_PROP_PID_ID, &PROP_UINT(GF_M2TS_PID_EIT_ST_CIT) );
583 : gf_filter_pid_set_property(ctx->eit_pid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_PRIVATE_SCENE) );
584 : gf_filter_pid_set_property(ctx->eit_pid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_DVB_EIT) );
585 : gf_filter_pid_set_property(ctx->eit_pid, GF_PROP_PID_TIMESCALE, &PROP_UINT(90000) );
586 : gf_filter_pid_set_property(ctx->eit_pid, GF_PROP_PID_CLOCK_ID, &PROP_UINT(GF_M2TS_PID_EIT_ST_CIT) );
587 : }
588 : #endif
589 :
590 49216 : static void m2tsdmx_on_event(GF_M2TS_Demuxer *ts, u32 evt_type, void *param)
591 : {
592 : u32 i, count;
593 49216 : GF_Filter *filter = (GF_Filter *) ts->user;
594 49216 : GF_M2TSDmxCtx *ctx = gf_filter_get_udta(filter);
595 :
596 49216 : switch (evt_type) {
597 : case GF_M2TS_EVT_PAT_UPDATE:
598 : break;
599 : case GF_M2TS_EVT_AIT_FOUND:
600 : break;
601 32 : case GF_M2TS_EVT_PAT_FOUND:
602 32 : if (ctx->mux_tune_state==DMX_TUNE_INIT) {
603 31 : ctx->mux_tune_state = DMX_TUNE_WAIT_PROGS;
604 31 : ctx->wait_for_progs = gf_list_count(ts->programs);
605 : }
606 : break;
607 : case GF_M2TS_EVT_DSMCC_FOUND:
608 : break;
609 50 : case GF_M2TS_EVT_PMT_FOUND:
610 50 : m2tsdmx_setup_program(ctx, param);
611 50 : if (ctx->mux_tune_state == DMX_TUNE_WAIT_PROGS) {
612 : assert(ctx->wait_for_progs);
613 49 : ctx->wait_for_progs--;
614 49 : if (!ctx->wait_for_progs) {
615 31 : ctx->mux_tune_state = DMX_TUNE_WAIT_SEEK;
616 : }
617 : }
618 : break;
619 : case GF_M2TS_EVT_PMT_REPEAT:
620 : break;
621 0 : case GF_M2TS_EVT_PMT_UPDATE:
622 0 : m2tsdmx_setup_program(ctx, param);
623 0 : break;
624 :
625 13 : case GF_M2TS_EVT_SDT_FOUND:
626 : case GF_M2TS_EVT_SDT_UPDATE:
627 : // case GF_M2TS_EVT_SDT_REPEAT:
628 13 : count = gf_list_count(ts->programs);
629 41 : for (i=0; i<count; i++) {
630 28 : GF_M2TS_Program *prog = gf_list_get(ts->programs, i);
631 28 : GF_M2TS_SDT *sdt = gf_m2ts_get_sdt_info(ts, prog->number);
632 28 : if (sdt) {
633 : u32 j, nb_streams;
634 25 : nb_streams = gf_list_count(prog->streams);
635 123 : for (j=0; j<nb_streams; j++) {
636 98 : GF_M2TS_ES *es = gf_list_get(prog->streams, j);
637 98 : if (es->user) {
638 : //TODO, translate non standard character maps to UTF8
639 : //we for now comment in test mode to avoid non UTF characters in text dumps
640 49 : if (isalnum(sdt->service[0]) || !gf_sys_is_test_mode())
641 43 : gf_filter_pid_set_property((GF_FilterPid *)es->user, GF_PROP_PID_SERVICE_NAME, &PROP_NAME( sdt->service ) );
642 :
643 49 : if (isalnum(sdt->provider[0]) || !gf_sys_is_test_mode())
644 45 : gf_filter_pid_set_property((GF_FilterPid *)es->user, GF_PROP_PID_SERVICE_PROVIDER, &PROP_NAME( sdt->provider ) );
645 : }
646 : }
647 : }
648 : }
649 : break;
650 7200 : case GF_M2TS_EVT_DVB_GENERAL:
651 7200 : if (ctx->eit_pid) {
652 : GF_M2TS_SL_PCK *pck = (GF_M2TS_SL_PCK *)param;
653 : u8 *data;
654 0 : GF_FilterPacket *dst_pck = gf_filter_pck_new_alloc(ctx->eit_pid, pck->data_len, &data);
655 0 : if (dst_pck) {
656 0 : memcpy(data, pck->data, pck->data_len);
657 0 : gf_filter_pck_send(dst_pck);
658 : }
659 : }
660 : break;
661 20858 : case GF_M2TS_EVT_PES_PCK:
662 20858 : if (ctx->mux_tune_state) break;
663 20684 : m2tsdmx_send_packet(ctx, param);
664 20684 : break;
665 4 : case GF_M2TS_EVT_SL_PCK: /* DMB specific */
666 4 : if (ctx->mux_tune_state) break;
667 2 : m2tsdmx_send_sl_packet(ctx, param);
668 2 : break;
669 12682 : case GF_M2TS_EVT_PES_PCR:
670 12682 : if (ctx->mux_tune_state) break;
671 : {
672 : u64 pcr;
673 : Bool map_time = GF_FALSE;
674 : GF_M2TS_PES_PCK *pck = ((GF_M2TS_PES_PCK *) param);
675 12580 : Bool discontinuity = ( ((GF_M2TS_PES_PCK *) param)->flags & GF_M2TS_PES_PCK_DISCONTINUITY) ? 1 : 0;
676 :
677 : assert(pck->stream);
678 12580 : m2tsdmx_estimate_duration(ctx, (GF_M2TS_ES *) pck->stream);
679 :
680 12580 : if (ctx->map_time_on_prog_id && (ctx->map_time_on_prog_id==pck->stream->program->number)) {
681 : map_time = GF_TRUE;
682 : }
683 :
684 : //we forward the PCR on each pid
685 12580 : pcr = ((GF_M2TS_PES_PCK *) param)->PTS;
686 12580 : pcr /= 300;
687 12580 : count = gf_list_count(pck->stream->program->streams);
688 55978 : for (i=0; i<count; i++) {
689 : GF_FilterPacket *dst_pck;
690 43398 : GF_M2TS_PES *stream = gf_list_get(pck->stream->program->streams, i);
691 43398 : if (!stream->user) continue;
692 :
693 24341 : dst_pck = gf_filter_pck_new_shared(stream->user, NULL, 0, NULL);
694 24341 : if (!dst_pck) continue;
695 :
696 24341 : gf_filter_pck_set_cts(dst_pck, pcr);
697 24341 : gf_filter_pck_set_clock_type(dst_pck, discontinuity ? GF_FILTER_CLOCK_PCR_DISC : GF_FILTER_CLOCK_PCR);
698 24341 : if (pck->stream->is_seg_start) {
699 0 : pck->stream->is_seg_start = GF_FALSE;
700 0 : gf_filter_pck_set_property(dst_pck, GF_PROP_PCK_CUE_START, &PROP_BOOL(GF_TRUE));
701 : }
702 24341 : gf_filter_pck_send(dst_pck);
703 :
704 24341 : if (map_time) {
705 56 : gf_filter_pid_set_info_str(stream->user, "time:timestamp", &PROP_LONGUINT(pcr) );
706 56 : gf_filter_pid_set_info_str(stream->user, "time:media", &PROP_DOUBLE(ctx->media_start_range) );
707 : }
708 : }
709 :
710 12580 : if (map_time) {
711 31 : ctx->map_time_on_prog_id = 0;
712 : }
713 : }
714 : break;
715 :
716 0 : case GF_M2TS_EVT_TDT:
717 0 : if (ctx->mux_tune_state) break;
718 : {
719 : GF_M2TS_TDT_TOT *tdt = (GF_M2TS_TDT_TOT *)param;
720 0 : u64 utc_ts = gf_net_get_utc_ts(tdt->year, tdt->month, tdt->day, tdt->hour, tdt->minute, tdt->second);
721 0 : count = gf_list_count(ts->programs );
722 0 : for (i=0; i<count; i++) {
723 0 : GF_M2TS_Program *prog = gf_list_get(ts->programs, i);
724 0 : u32 j, count2 = gf_list_count(prog->streams);
725 0 : for (j=0; j<count2; j++) {
726 0 : GF_M2TS_ES * stream = gf_list_get(prog->streams, j);
727 0 : if (stream->user) {
728 0 : gf_filter_pid_set_info(stream->user, GF_PROP_PID_UTC_TIME, & PROP_LONGUINT(utc_ts) );
729 0 : gf_filter_pid_set_info(stream->user, GF_PROP_PID_UTC_TIMESTAMP, & PROP_LONGUINT(prog->last_pcr_value / 300) );
730 : }
731 : }
732 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[M2TS In] Mapping TDT Time %04d/%02d/%02d %02d:%02d:%02d and PCR time "LLD" on program %d\n",
733 : tdt->year, tdt->month, tdt->day, tdt->hour, tdt->minute, tdt->second, prog->last_pcr_value/300, prog->number));
734 : }
735 : }
736 : break;
737 : case GF_M2TS_EVT_TOT:
738 : break;
739 :
740 0 : case GF_M2TS_EVT_DURATION_ESTIMATED:
741 : {
742 0 : u64 duration = ((GF_M2TS_PES_PCK *) param)->PTS;
743 0 : count = gf_list_count(ts->programs);
744 0 : for (i=0; i<count; i++) {
745 0 : GF_M2TS_Program *prog = gf_list_get(ts->programs, i);
746 : u32 j, count2;
747 0 : count2 = gf_list_count(prog->streams);
748 0 : for (j=0; j<count2; j++) {
749 0 : GF_M2TS_ES * stream = gf_list_get(prog->streams, j);
750 0 : if (stream->user) {
751 0 : gf_filter_pid_set_property(stream->user, GF_PROP_PID_DURATION, & PROP_FRAC64_INT(duration, 1000) );
752 : }
753 : }
754 : }
755 : }
756 : break;
757 :
758 46 : case GF_M2TS_EVT_TEMI_LOCATION:
759 : {
760 : GF_M2TS_TemiLocationDescriptor *temi_l = (GF_M2TS_TemiLocationDescriptor *)param;
761 : const char *url;
762 : u32 len;
763 : GF_BitStream *bs;
764 : GF_M2TS_ES *es=NULL;
765 : GF_TEMIInfo *t;
766 46 : if ((temi_l->pid<8192) && (ctx->ts->ess[temi_l->pid])) {
767 : es = ctx->ts->ess[temi_l->pid];
768 : }
769 46 : if (!es || !es->user) {
770 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[M2TSDmx] TEMI location not assigned to a given PID, not supported\n"));
771 : break;
772 : }
773 46 : GF_SAFEALLOC(t, GF_TEMIInfo);
774 46 : if (!t) break;
775 46 : t->timeline_id = temi_l->timeline_id;
776 46 : t->is_loc = GF_TRUE;
777 :
778 46 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
779 46 : if (ctx->temi_url)
780 : url = ctx->temi_url;
781 : else
782 46 : url = temi_l->external_URL;
783 46 : len = url ? (u32) strlen(url) : 0;
784 46 : gf_bs_write_data(bs, url, len);
785 46 : gf_bs_write_u8(bs, 0);
786 46 : gf_bs_write_int(bs, temi_l->is_announce, 1);
787 46 : gf_bs_write_int(bs, temi_l->is_splicing, 1);
788 46 : gf_bs_write_int(bs, temi_l->reload_external, 1);
789 46 : gf_bs_write_int(bs, 0, 5);
790 46 : gf_bs_write_double(bs, temi_l->activation_countdown);
791 46 : gf_bs_get_content(bs, &t->data, &t->len);
792 46 : gf_bs_del(bs);
793 :
794 46 : if (!es->props) {
795 42 : es->props = gf_list_new();
796 : }
797 46 : gf_list_add(es->props, t);
798 : }
799 46 : break;
800 1384 : case GF_M2TS_EVT_TEMI_TIMECODE:
801 : {
802 : GF_M2TS_TemiTimecodeDescriptor *temi_t = (GF_M2TS_TemiTimecodeDescriptor*)param;
803 : GF_BitStream *bs;
804 : GF_TEMIInfo *t;
805 : GF_M2TS_ES *es=NULL;
806 1384 : if ((temi_t->pid<8192) && (ctx->ts->ess[temi_t->pid])) {
807 : es = ctx->ts->ess[temi_t->pid];
808 : }
809 1384 : if (!es || !es->user) {
810 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[M2TSDmx] TEMI timing not assigned to a given PID, not supported\n"));
811 : break;
812 : }
813 1384 : GF_SAFEALLOC(t, GF_TEMIInfo);
814 1384 : if (!t) break;
815 1384 : t->timeline_id = temi_t->timeline_id;
816 :
817 1384 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
818 1384 : gf_bs_write_u32(bs, temi_t->media_timescale);
819 1384 : gf_bs_write_u64(bs, temi_t->media_timestamp);
820 1384 : gf_bs_write_u64(bs, temi_t->pes_pts);
821 1384 : gf_bs_write_int(bs, temi_t->force_reload, 1);
822 1384 : gf_bs_write_int(bs, temi_t->is_paused, 1);
823 1384 : gf_bs_write_int(bs, temi_t->is_discontinuity, 1);
824 1384 : gf_bs_write_int(bs, temi_t->ntp ? 1 : 0, 1);
825 1384 : gf_bs_write_int(bs, 0, 4);
826 1384 : if (temi_t->ntp)
827 0 : gf_bs_write_u64(bs, temi_t->ntp);
828 :
829 1384 : gf_bs_get_content(bs, &t->data, &t->len);
830 1384 : gf_bs_del(bs);
831 :
832 1384 : if (!es->props) {
833 1310 : es->props = gf_list_new();
834 : }
835 1384 : gf_list_add(es->props, t);
836 : }
837 1384 : break;
838 : }
839 49216 : }
840 :
841 37 : static GF_Err m2tsdmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
842 : {
843 : const GF_PropertyValue *p;;
844 : FILE *stream = NULL;
845 37 : GF_M2TSDmxCtx *ctx = gf_filter_get_udta(filter);
846 :
847 37 : if (is_remove) {
848 0 : ctx->ipid = NULL;
849 : // gf_filter_pid_remove(ctx->opid);
850 0 : return GF_OK;
851 : }
852 37 : if (! gf_filter_pid_check_caps(pid))
853 : return GF_NOT_SUPPORTED;
854 :
855 : //by default for all URLs, send packets as soon as the program is configured
856 37 : ctx->mux_tune_state = DMX_TUNE_DONE;
857 :
858 37 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_FILEPATH);
859 37 : if (p && p->value.string && !ctx->duration.num && strncmp(p->value.string, "gmem://", 7)) {
860 31 : stream = gf_fopen(p->value.string, "rb");
861 : }
862 :
863 31 : if (stream) {
864 31 : if (ctx->seeksrc) {
865 : //for local file we will send a seek and stop once all programs are configured, and reparse from start
866 31 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_URL);
867 31 : if (p && p->value.string && gf_file_exists(p->value.string)) {
868 31 : ctx->mux_tune_state = DMX_TUNE_INIT;
869 : }
870 : }
871 :
872 31 : ctx->ipid = pid;
873 31 : ctx->is_file = GF_TRUE;
874 31 : ctx->ts->seek_mode = GF_TRUE;
875 31 : ctx->ts->on_event = m2tsdmx_on_event_duration_probe;
876 18594 : while (!gf_feof(stream)) {
877 : char buf[1880];
878 18563 : u32 nb_read = (u32) gf_fread(buf, 1880, stream);
879 18563 : gf_m2ts_process_data(ctx->ts, buf, nb_read);
880 18563 : if (ctx->duration.num || (nb_read!=1880)) break;
881 : }
882 31 : gf_m2ts_demux_del(ctx->ts);
883 31 : gf_fclose(stream);
884 31 : ctx->ts = gf_m2ts_demux_new();
885 31 : ctx->ts->on_event = m2tsdmx_on_event;
886 31 : ctx->ts->user = filter;
887 6 : } else if (!p) {
888 : GF_FilterEvent evt;
889 1 : ctx->duration.num = 1;
890 :
891 : //not-file base TS, we need to start demuxing the first time we see the PID
892 1 : if (!ctx->ipid) {
893 1 : GF_FEVT_INIT(evt, GF_FEVT_PLAY, pid);
894 1 : gf_filter_pid_send_event(pid, &evt);
895 : }
896 : }
897 37 : ctx->ipid = pid;
898 37 : return GF_OK;
899 : }
900 :
901 :
902 96 : static GF_M2TS_PES *m2tsdmx_get_stream(GF_M2TSDmxCtx *ctx, GF_FilterPid *pid)
903 : {
904 : u32 i, j, count, count2;
905 96 : count = gf_list_count(ctx->ts->programs);
906 96 : for (i=0; i<count; i++) {
907 192 : GF_M2TS_Program *prog = gf_list_get(ctx->ts->programs, i);
908 192 : count2 = gf_list_count(prog->streams);
909 496 : for (j=0; j<count2; j++) {
910 592 : GF_M2TS_PES *pes = (GF_M2TS_PES *)gf_list_get(prog->streams, j);
911 592 : if (pes->user == pid) return pes;
912 : }
913 : }
914 : return NULL;
915 : }
916 :
917 0 : static void m2tsdmx_switch_quality(GF_M2TS_Program *prog, GF_M2TS_Demuxer *ts, Bool switch_up)
918 : {
919 : GF_M2TS_ES *es;
920 : u32 i, count;
921 :
922 0 : if (!prog->is_scalable)
923 : return;
924 :
925 0 : if (switch_up) {
926 0 : for (i = 0; i < GF_M2TS_MAX_STREAMS; i++) {
927 0 : es = ts->ess[i];
928 0 : if (es && (es->flags & GF_M2TS_ES_IS_PES) && (((GF_M2TS_PES *)es)->depends_on_pid == prog->pid_playing)) {
929 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("Turn on ES%d\n", es->pid));
930 0 : gf_m2ts_set_pes_framing((GF_M2TS_PES *)ts->ess[es->pid], GF_M2TS_PES_FRAMING_DEFAULT);
931 0 : prog->pid_playing = es->pid;
932 0 : return;
933 : }
934 : }
935 : }
936 : else {
937 0 : count = gf_list_count(prog->streams);
938 0 : for (i = 0; i < count; i++) {
939 0 : es = (GF_M2TS_ES *)gf_list_get(prog->streams, i);
940 0 : if (es && (es->pid == prog->pid_playing) && ((GF_M2TS_PES *)es)->depends_on_pid) {
941 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("Turn off ES%d - playing ES%d\n", es->pid, ((GF_M2TS_PES *)es)->depends_on_pid));
942 0 : gf_m2ts_set_pes_framing((GF_M2TS_PES *)ts->ess[es->pid], GF_M2TS_PES_FRAMING_SKIP);
943 :
944 : //do we want to send a reset ?
945 0 : prog->pid_playing = ((GF_M2TS_PES *)es)->depends_on_pid;
946 0 : return;
947 : }
948 : }
949 : }
950 : }
951 :
952 31942 : static Bool m2tsdmx_process_event(GF_Filter *filter, const GF_FilterEvent *com)
953 : {
954 : GF_M2TS_PES *pes;
955 : u64 file_pos = 0;
956 : GF_FilterEvent fevt;
957 31942 : GF_M2TSDmxCtx *ctx = gf_filter_get_udta(filter);
958 31942 : GF_M2TS_Demuxer *ts = ctx->ts;
959 :
960 31942 : if (com->base.type == GF_FEVT_QUALITY_SWITCH) {
961 : u32 i, count;
962 0 : count = gf_list_count(ts->programs);
963 0 : for (i = 0; i < count; i++) {
964 0 : GF_M2TS_Program *prog = (GF_M2TS_Program *)gf_list_get(ts->programs, i);
965 0 : m2tsdmx_switch_quality(prog, ts, com->quality_switch.up);
966 : }
967 : //don't cancel event for RTP source
968 : return GF_FALSE;
969 : }
970 :
971 : //don't cancel event for RTP source
972 31942 : if (!com->base.on_pid) return GF_FALSE;
973 31942 : switch (com->base.type) {
974 90 : case GF_FEVT_PLAY:
975 90 : pes = m2tsdmx_get_stream(ctx, com->base.on_pid);
976 90 : if (!pes) {
977 : if (com->base.on_pid == ctx->eit_pid) {
978 : return GF_FALSE;
979 : }
980 : return GF_FALSE;
981 : }
982 : /*mark pcr as not initialized*/
983 90 : if (pes->program->pcr_pid==pes->pid) pes->program->first_dts=0;
984 90 : gf_m2ts_set_pes_framing(pes, GF_M2TS_PES_FRAMING_DEFAULT);
985 90 : GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[M2TSDmx] Setting default reframing for PID %d\n", pes->pid));
986 :
987 : /*this is a multplex, only trigger the play command for the first stream activated*/
988 90 : ctx->nb_playing++;
989 90 : if (ctx->nb_playing>1) return GF_TRUE;
990 :
991 : //not file, don't cancel the event
992 32 : if (!ctx->is_file) {
993 1 : ctx->initial_play_done = GF_TRUE;
994 1 : return GF_FALSE;
995 : }
996 :
997 31 : ctx->map_time_on_prog_id = pes->program->number;
998 31 : ctx->media_start_range = com->play.start_range;
999 :
1000 :
1001 31 : if (ctx->is_file && ctx->duration.num) {
1002 31 : file_pos = (u64) (ctx->file_size * com->play.start_range);
1003 31 : file_pos *= ctx->duration.den;
1004 31 : file_pos /= ctx->duration.num;
1005 31 : if (file_pos > ctx->file_size) return GF_TRUE;
1006 : }
1007 :
1008 31 : if (!ctx->initial_play_done) {
1009 31 : ctx->initial_play_done = GF_TRUE;
1010 : //seek will not change the current source state, don't send a seek
1011 31 : if (!file_pos)
1012 : return GF_TRUE;
1013 : }
1014 :
1015 : //file and seek, cancel the event and post a seek event to source
1016 0 : ctx->in_seek = GF_TRUE;
1017 : //we seek so consider the mux tuned in
1018 0 : ctx->mux_tune_state = DMX_TUNE_DONE;
1019 :
1020 : //post a seek
1021 0 : GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
1022 0 : fevt.seek.start_offset = file_pos;
1023 0 : gf_filter_pid_send_event(ctx->ipid, &fevt);
1024 0 : return GF_TRUE;
1025 :
1026 6 : case GF_FEVT_STOP:
1027 6 : pes = m2tsdmx_get_stream(ctx, com->base.on_pid);
1028 6 : if (!pes) {
1029 : if (com->base.on_pid == ctx->eit_pid) {
1030 : return GF_FALSE;
1031 : }
1032 : return GF_FALSE;
1033 : }
1034 : /* In case of EOS, we may receive a stop command after no one is playing */
1035 6 : if (ctx->nb_playing)
1036 6 : ctx->nb_playing--;
1037 :
1038 6 : gf_m2ts_set_pes_framing(pes, GF_M2TS_PES_FRAMING_SKIP);
1039 : //don't cancel event if still playing
1040 6 : return ctx->nb_playing ? GF_TRUE : GF_FALSE;
1041 :
1042 : case GF_FEVT_PAUSE:
1043 : case GF_FEVT_RESUME:
1044 : return GF_FALSE;
1045 : default:
1046 : return GF_FALSE;
1047 : }
1048 : }
1049 :
1050 :
1051 :
1052 32 : static GF_Err m2tsdmx_initialize(GF_Filter *filter)
1053 : {
1054 32 : GF_M2TSDmxCtx *ctx = gf_filter_get_udta(filter);
1055 :
1056 32 : ctx->ts = gf_m2ts_demux_new();
1057 32 : if (!ctx->ts) return GF_OUT_OF_MEM;
1058 :
1059 32 : ctx->ts->on_event = m2tsdmx_on_event;
1060 32 : ctx->ts->user = filter;
1061 :
1062 32 : ctx->filter = filter;
1063 32 : if (ctx->dsmcc) {
1064 1 : gf_m2ts_demux_dmscc_init(ctx->ts);
1065 : }
1066 :
1067 : return GF_OK;
1068 : }
1069 :
1070 :
1071 32 : static void m2tsdmx_finalize(GF_Filter *filter)
1072 : {
1073 32 : GF_M2TSDmxCtx *ctx = gf_filter_get_udta(filter);
1074 32 : if (ctx->ts) gf_m2ts_demux_del(ctx->ts);
1075 :
1076 32 : }
1077 :
1078 31928 : static GF_Err m2tsdmx_process(GF_Filter *filter)
1079 : {
1080 31928 : GF_M2TSDmxCtx *ctx = gf_filter_get_udta(filter);
1081 31928 : GF_FilterPacket *pck = gf_filter_pid_get_packet(ctx->ipid);
1082 : const char *data;
1083 : u32 size;
1084 :
1085 31928 : if (!pck) {
1086 69 : if (gf_filter_pid_is_eos(ctx->ipid)) {
1087 34 : u32 i, nb_streams = gf_filter_get_opid_count(filter);
1088 :
1089 34 : gf_m2ts_flush_all(ctx->ts);
1090 129 : for (i=0; i<nb_streams; i++) {
1091 95 : GF_FilterPid *opid = gf_filter_get_opid(filter, i);
1092 95 : gf_filter_pid_set_eos(opid);
1093 : }
1094 : return GF_EOS;
1095 : }
1096 : return GF_OK;
1097 : }
1098 31859 : if (ctx->sigfrag) {
1099 : Bool is_start;
1100 0 : gf_filter_pck_get_framing(pck, &is_start, NULL);
1101 0 : if (is_start) {
1102 0 : gf_m2ts_mark_seg_start(ctx->ts);
1103 : }
1104 : }
1105 : //we process even if no stream playing: since we use unframed dispatch we may need to send packets to configure reframers
1106 : //which will in turn connect to the sink which will send the PLAY event marking stream(s) as playing
1107 31859 : if (ctx->in_seek) {
1108 0 : gf_m2ts_reset_parsers(ctx->ts);
1109 0 : ctx->in_seek = GF_FALSE;
1110 : } else {
1111 : u32 i, nb_streams, would_block = 0;
1112 31859 : nb_streams = gf_filter_get_opid_count(filter);
1113 281337 : for (i=0; i<nb_streams; i++) {
1114 249478 : GF_FilterPid *opid = gf_filter_get_opid(filter, i);
1115 249478 : if ( gf_filter_pid_would_block(opid) ) {
1116 7257 : would_block++;
1117 : }
1118 : }
1119 31859 : if (would_block && (would_block==nb_streams))
1120 : return GF_OK;
1121 : }
1122 :
1123 31859 : data = gf_filter_pck_get_data(pck, &size);
1124 31859 : if (data && size)
1125 31859 : gf_m2ts_process_data(ctx->ts, (char*) data, size);
1126 :
1127 31859 : gf_filter_pid_drop_packet(ctx->ipid);
1128 :
1129 31859 : if (ctx->mux_tune_state==DMX_TUNE_WAIT_SEEK) {
1130 : GF_FilterEvent fevt;
1131 31 : GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
1132 31 : gf_filter_pid_send_event(ctx->ipid, &fevt);
1133 31 : ctx->mux_tune_state = DMX_TUNE_DONE;
1134 31 : gf_m2ts_reset_parsers(ctx->ts);
1135 : }
1136 : return GF_OK;
1137 : }
1138 :
1139 3074 : static const char *m2tsdmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
1140 : {
1141 3074 : if (gf_m2ts_probe_data(data, size)) {
1142 34 : *score = GF_FPROBE_SUPPORTED;
1143 34 : return "video/mp2t";
1144 : }
1145 : return NULL;
1146 : }
1147 :
1148 : static const GF_FilterCapability M2TSDmxCaps[] =
1149 : {
1150 : CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1151 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "ts|m2t|mts|dmb|trp"),
1152 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "video/mpeg-2|video/mp2t|video/mpeg"),
1153 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1154 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1155 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_SCENE),
1156 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_OD),
1157 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_PRIVATE_SCENE),
1158 : CAP_UINT(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_RAW),
1159 : };
1160 :
1161 : #define OFFS(_n) #_n, offsetof(GF_M2TSDmxCtx, _n)
1162 : static const GF_FilterArgs M2TSDmxArgs[] =
1163 : {
1164 : { OFFS(temi_url), "force TEMI URL", GF_PROP_NAME, NULL, NULL, GF_FS_ARG_HINT_ADVANCED},
1165 : { OFFS(dsmcc), "enable DSMCC receiver", GF_PROP_BOOL, "no", NULL, GF_FS_ARG_HINT_EXPERT},
1166 : { OFFS(seeksrc), "seek local source file back to origin once all programs are setup", GF_PROP_BOOL, "true", NULL, GF_FS_ARG_HINT_EXPERT},
1167 : { OFFS(sigfrag), "signal segment boundaries of source on output packets", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
1168 : {0}
1169 : };
1170 :
1171 :
1172 : GF_FilterRegister M2TSDmxRegister = {
1173 : .name = "m2tsdmx",
1174 : GF_FS_SET_DESCRIPTION("MPEG-2 TS demuxer")
1175 : GF_FS_SET_HELP("This filter demultiplexes MPEG-2 Transport Stream files/data into a set of media PIDs and frames.")
1176 : .private_size = sizeof(GF_M2TSDmxCtx),
1177 : .initialize = m2tsdmx_initialize,
1178 : .finalize = m2tsdmx_finalize,
1179 : .args = M2TSDmxArgs,
1180 : .flags = GF_FS_REG_DYNAMIC_PIDS,
1181 : SETCAPS(M2TSDmxCaps),
1182 : .configure_pid = m2tsdmx_configure_pid,
1183 : .process = m2tsdmx_process,
1184 : .process_event = m2tsdmx_process_event,
1185 : .probe_data = m2tsdmx_probe_data,
1186 : };
1187 :
1188 :
1189 : #endif
1190 :
1191 2877 : const GF_FilterRegister *m2tsdmx_register(GF_FilterSession *session)
1192 : {
1193 : #ifndef GPAC_DISABLE_MPEG2TS
1194 2877 : return &M2TSDmxRegister;
1195 : #else
1196 : return NULL;
1197 : #endif
1198 : }
|