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 / SAF 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 : typedef struct
33 : {
34 : GF_FilterPid *opid;
35 : u32 au_sn, stream_id, ts_res, buffer_min;
36 : } GF_SAFStream;
37 :
38 : enum
39 : {
40 : SAF_FILE_LOCAL,
41 : SAF_FILE_REMOTE,
42 : SAF_LIVE_STREAM
43 : };
44 :
45 : typedef struct
46 : {
47 : GF_FilterPid *ipid;
48 :
49 :
50 : GF_List *streams;
51 :
52 : u32 saf_type;
53 :
54 : Double start_range, end_range;
55 : u32 nb_playing;
56 : Bool is_file, file_loaded;
57 : GF_Fraction64 duration;
58 : u64 file_pos, file_size;
59 :
60 : Bool initial_play_done;
61 :
62 : char *saf_data;
63 : u32 alloc_size, saf_size;
64 : } GF_SAFDmxCtx;
65 :
66 :
67 : static GFINLINE GF_SAFStream *saf_get_channel(GF_SAFDmxCtx *saf, u32 stream_id)
68 : {
69 : GF_SAFStream *st;
70 10 : u32 i=0;
71 12 : while ((st = (GF_SAFStream *)gf_list_enum(saf->streams, &i))) {
72 8 : if (st->stream_id==stream_id) return st;
73 : }
74 : return NULL;
75 : }
76 :
77 2 : static void safdmx_demux(GF_Filter *filter, GF_SAFDmxCtx *ctx, char *data, u32 data_size)
78 : {
79 : Bool is_rap, go;
80 : u32 cts, au_size, type, i, stream_id;
81 : u64 bs_pos;
82 : GF_BitStream *bs;
83 :
84 2 : if (ctx->alloc_size < ctx->saf_size + data_size) {
85 2 : ctx->saf_data = (char*)gf_realloc(ctx->saf_data, sizeof(char)*(ctx->saf_size + data_size) );
86 2 : ctx->alloc_size = ctx->saf_size + data_size;
87 : }
88 : //we could avoid a full copy of the buffer, but given how much SAF is used that's not very urgent ...
89 2 : memcpy(ctx->saf_data + ctx->saf_size, data, sizeof(char)*data_size);
90 2 : ctx->saf_size += data_size;
91 :
92 : /*first AU not complete yet*/
93 2 : if (ctx->saf_size<10) return;
94 :
95 2 : bs = gf_bs_new(ctx->saf_data, ctx->saf_size, GF_BITSTREAM_READ);
96 : bs_pos = 0;
97 :
98 : go = GF_TRUE;
99 2 : while (go) {
100 : GF_SAFStream *st;
101 12 : u64 avail = gf_bs_available(bs);
102 12 : bs_pos = gf_bs_get_position(bs);
103 :
104 12 : if (avail<10) break;
105 :
106 10 : is_rap = (Bool)gf_bs_read_int(bs, 1);
107 10 : /*au_sn = */gf_bs_read_int(bs, 15);
108 10 : gf_bs_read_int(bs, 2);
109 10 : cts = gf_bs_read_int(bs, 30);
110 10 : au_size = gf_bs_read_int(bs, 16);
111 10 : avail-=8;
112 :
113 10 : if (au_size > avail) break;
114 : assert(au_size>=2);
115 :
116 10 : type = gf_bs_read_int(bs, 4);
117 10 : stream_id = gf_bs_read_int(bs, 12);
118 10 : au_size -= 2;
119 :
120 : st = saf_get_channel(ctx, stream_id);
121 10 : switch (type) {
122 2 : case 1:
123 : case 2:
124 : case 7:
125 2 : if (st) {
126 0 : gf_bs_skip_bytes(bs, au_size);
127 : } else {
128 : u32 oti, stype;
129 2 : GF_SAFStream *first = (GF_SAFStream *)gf_list_get(ctx->streams, 0);
130 2 : GF_SAFEALLOC(st, GF_SAFStream);
131 2 : if (!st) {
132 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[SAF] Failed to allocate SAF channel"));
133 0 : gf_bs_del(bs);
134 0 : return;
135 : }
136 2 : st->stream_id = stream_id;
137 2 : st->opid = gf_filter_pid_new(filter);
138 2 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_ID, &PROP_UINT(stream_id));
139 2 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_ESID, &PROP_UINT(stream_id));
140 2 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_CLOCK_ID, &PROP_UINT(first ? first->stream_id : stream_id));
141 2 : if (!first) {
142 2 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_IN_IOD, &PROP_BOOL(GF_TRUE));
143 : }
144 2 : oti = gf_bs_read_u8(bs);
145 2 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_CODECID, &PROP_UINT(oti));
146 2 : stype = gf_bs_read_u8(bs);
147 2 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(stype));
148 2 : st->ts_res = gf_bs_read_u24(bs);
149 2 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_TIMESCALE, &PROP_UINT(st->ts_res));
150 2 : if (ctx->duration.num) {
151 2 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
152 2 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_PLAYBACK_MODE, &PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD ) );
153 : }
154 :
155 2 : /*bufferSizeDB = */gf_bs_read_u16(bs);
156 2 : au_size -= 7;
157 2 : if ((oti == 0xFF) && (stype == 0xFF) ) {
158 0 : u16 mimeLen = gf_bs_read_u16(bs);
159 0 : gf_bs_skip_bytes(bs, mimeLen);
160 0 : au_size -= mimeLen+2;
161 : }
162 2 : if (type==7) {
163 0 : u16 urlLen = gf_bs_read_u16(bs);
164 0 : char *url_string = (char*)gf_malloc(sizeof(char)*(urlLen+1));
165 0 : gf_bs_read_data(bs, url_string, urlLen);
166 0 : url_string[urlLen] = 0;
167 0 : au_size -= urlLen+2;
168 0 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_REMOTE_URL, &PROP_NAME(url_string));
169 : }
170 2 : if (au_size) {
171 2 : char *dsi = (char*)gf_malloc(sizeof(char)*au_size);
172 2 : gf_bs_read_data(bs, dsi, au_size);
173 2 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA_NO_COPY(dsi, au_size) );
174 : }
175 2 : gf_list_add(ctx->streams, st);
176 : }
177 : break;
178 6 : case 4:
179 6 : if (st) {
180 : GF_FilterPacket *pck;
181 : u8 *pck_data;
182 6 : bs_pos = gf_bs_get_position(bs);
183 6 : pck = gf_filter_pck_new_alloc(st->opid, au_size, &pck_data);
184 6 : if (pck) {
185 6 : memcpy(pck_data, ctx->saf_data+bs_pos, au_size);
186 : //TODO: map byte range pos ?
187 : //TODO: map AU SN ?
188 :
189 6 : gf_filter_pck_set_cts(pck, cts);
190 6 : if (is_rap)
191 2 : gf_filter_pck_set_sap(pck, GF_FILTER_SAP_1);
192 :
193 6 : if (ctx->start_range && (ctx->start_range * st->ts_res > cts*1000)) {
194 0 : gf_filter_pck_set_seek_flag(pck, GF_TRUE);
195 : }
196 6 : gf_filter_pck_send(pck);
197 : }
198 : }
199 6 : gf_bs_skip_bytes(bs, au_size);
200 6 : break;
201 0 : case 3:
202 0 : if (st && st->opid) gf_filter_pid_set_eos(st->opid);
203 : break;
204 2 : case 5:
205 2 : i=0;
206 6 : while ((st = (GF_SAFStream *)gf_list_enum(ctx->streams, &i))) {
207 2 : if (st->opid) gf_filter_pid_set_eos(st->opid);
208 : }
209 : break;
210 : }
211 : }
212 :
213 2 : gf_bs_del(bs);
214 2 : if (bs_pos) {
215 2 : u32 remain = (u32) (ctx->saf_size - bs_pos);
216 2 : if (remain) memmove(ctx->saf_data, ctx->saf_data+bs_pos, sizeof(char)*remain);
217 2 : ctx->saf_size = remain;
218 : }
219 : }
220 :
221 :
222 : typedef struct
223 : {
224 : u32 stream_id;
225 : u32 ts_res;
226 : } StreamInfo;
227 :
228 6 : static void safdmx_check_dur(GF_SAFDmxCtx *ctx)
229 : {
230 : u32 nb_streams, i, cts, au_size, au_type, stream_id, ts_res;
231 : GF_BitStream *bs;
232 : GF_Fraction64 dur;
233 : const GF_PropertyValue *p;
234 : StreamInfo si[1024];
235 : FILE *stream;
236 :
237 :
238 10 : if (ctx->duration.num) return;
239 :
240 2 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
241 2 : if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
242 :
243 2 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
244 2 : if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7)) {
245 0 : ctx->is_file = GF_FALSE;
246 0 : ctx->duration.num=1;
247 0 : return;
248 : }
249 2 : ctx->is_file = GF_TRUE;
250 2 : if (!ctx->file_loaded) return;
251 :
252 2 : stream = gf_fopen(p->value.string, "rb");
253 2 : if (!stream) return;
254 :
255 2 : bs = gf_bs_from_file(stream, GF_BITSTREAM_READ);
256 2 : ctx->file_size = gf_bs_get_size(bs);
257 :
258 : dur.num = 0;
259 : dur.den = 1000;
260 : nb_streams=0;
261 14 : while (gf_bs_available(bs)) {
262 10 : gf_bs_read_u16(bs);
263 10 : gf_bs_read_int(bs, 2);
264 10 : cts = gf_bs_read_int(bs, 30);
265 10 : au_size = gf_bs_read_int(bs, 16);
266 10 : au_type = gf_bs_read_int(bs, 4);
267 10 : stream_id = gf_bs_read_int(bs, 12);
268 10 : au_size-=2;
269 : ts_res = 0;
270 18 : for (i=0; i<nb_streams; i++) {
271 8 : if (si[i].stream_id==stream_id) ts_res = si[i].ts_res;
272 : }
273 10 : if (!ts_res) {
274 4 : if ((au_type==1) || (au_type==2) || (au_type==7)) {
275 2 : gf_bs_read_u16(bs);
276 2 : ts_res = gf_bs_read_u24(bs);
277 2 : au_size -= 5;
278 2 : si[nb_streams].stream_id = stream_id;
279 2 : si[nb_streams].ts_res = ts_res;
280 2 : nb_streams++;
281 : }
282 : }
283 10 : if (ts_res && (au_type==4)) {
284 6 : Double ts = cts;
285 6 : ts /= ts_res;
286 6 : if (ts * 1000 > dur.num) dur.num = (u32) (ts * 1000);
287 : }
288 10 : gf_bs_skip_bytes(bs, au_size);
289 : }
290 2 : gf_bs_del(bs);
291 2 : gf_fclose(stream);
292 :
293 2 : if (!ctx->duration.num || (ctx->duration.num * dur.den != dur.num * ctx->duration.den)) {
294 : GF_SAFStream *st;
295 2 : ctx->duration = dur;
296 2 : i=0;
297 4 : while ( (st = gf_list_enum(ctx->streams, &i)) ) {
298 0 : gf_filter_pid_set_property(st->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
299 : }
300 : }
301 : }
302 :
303 :
304 2 : GF_Err safdmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
305 : {
306 : u32 i;
307 2 : GF_SAFDmxCtx *ctx = gf_filter_get_udta(filter);
308 :
309 2 : if (is_remove) {
310 : GF_SAFStream *st;
311 0 : ctx->ipid = NULL;
312 :
313 0 : while ((st = (GF_SAFStream*)gf_list_enum(ctx->streams, &i))) {
314 0 : if (st->opid)
315 0 : gf_filter_pid_remove(st->opid);
316 : }
317 : return GF_OK;
318 : }
319 2 : if (! gf_filter_pid_check_caps(pid))
320 : return GF_NOT_SUPPORTED;
321 :
322 2 : ctx->ipid = pid;
323 2 : return GF_OK;
324 : }
325 :
326 4 : static Bool safdmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
327 : {
328 : GF_FilterEvent fevt;
329 4 : GF_SAFDmxCtx *ctx = gf_filter_get_udta(filter);
330 :
331 4 : switch (evt->base.type) {
332 2 : case GF_FEVT_PLAY:
333 2 : if (ctx->nb_playing && (ctx->start_range == evt->play.start_range)) {
334 : return GF_TRUE;
335 : }
336 2 : if (! ctx->is_file) {
337 : return GF_FALSE;
338 : }
339 2 : safdmx_check_dur(ctx);
340 :
341 2 : ctx->nb_playing++;
342 :
343 2 : ctx->start_range = evt->play.start_range;
344 2 : ctx->file_pos = 0;
345 2 : if (ctx->duration.num) {
346 2 : ctx->file_pos = (u64) (ctx->file_size * ctx->start_range);
347 2 : ctx->file_pos *= ctx->duration.den;
348 2 : ctx->file_pos /= ctx->duration.num;
349 2 : if (ctx->file_pos>ctx->file_size) return GF_TRUE;
350 : }
351 :
352 2 : if (!ctx->initial_play_done) {
353 2 : ctx->initial_play_done = GF_TRUE;
354 : //seek will not change the current source state, don't send a seek
355 2 : if (!ctx->file_pos)
356 : return GF_TRUE;
357 : }
358 : //post a seek to 0 - we would need to build an index of AUs to find the next place to seek
359 0 : GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
360 : fevt.seek.start_offset = 0;
361 0 : ctx->saf_size = 0;
362 0 : gf_filter_pid_send_event(ctx->ipid, &fevt);
363 :
364 : //cancel event
365 0 : return GF_TRUE;
366 :
367 0 : case GF_FEVT_STOP:
368 0 : ctx->nb_playing--;
369 : //don't cancel event
370 0 : return GF_FALSE;
371 :
372 : case GF_FEVT_SET_SPEED:
373 : //cancel event
374 : return GF_TRUE;
375 : default:
376 : break;
377 : }
378 : //by default don't cancel event - to rework once we have downloading in place
379 2 : return GF_FALSE;
380 : }
381 :
382 4 : GF_Err safdmx_process(GF_Filter *filter)
383 : {
384 4 : GF_SAFDmxCtx *ctx = gf_filter_get_udta(filter);
385 : GF_FilterPacket *pck;
386 : GF_SAFStream *st;
387 4 : u32 i=0, pkt_size;
388 : const char *data;
389 : u32 would_block = 0;
390 :
391 : //update duration
392 4 : safdmx_check_dur(ctx);
393 :
394 : //check if all the streams are in block state, if so return.
395 : //we need to check for all output since one pid could still be buffering
396 10 : while ((st = gf_list_enum(ctx->streams, &i))) {
397 2 : if (st->opid && gf_filter_pid_would_block(st->opid))
398 2 : would_block++;
399 : }
400 4 : if (would_block && (would_block+1==i))
401 : return GF_OK;
402 :
403 2 : pck = gf_filter_pid_get_packet(ctx->ipid);
404 2 : if (!pck) {
405 : // if (gf_filter_pid_is_eos(ctx->ipid)) oggdmx_signal_eos(ctx);
406 : return GF_OK;
407 : }
408 2 : data = gf_filter_pck_get_data(pck, &pkt_size);
409 2 : safdmx_demux(filter, ctx, (char *) data, pkt_size);
410 2 : gf_filter_pid_drop_packet(ctx->ipid);
411 2 : return GF_OK;
412 : }
413 :
414 2 : GF_Err safdmx_initialize(GF_Filter *filter)
415 : {
416 2 : GF_SAFDmxCtx *ctx = gf_filter_get_udta(filter);
417 2 : ctx->streams = gf_list_new();
418 2 : return GF_OK;
419 : }
420 :
421 2 : void safdmx_finalize(GF_Filter *filter)
422 : {
423 2 : GF_SAFDmxCtx *ctx = gf_filter_get_udta(filter);
424 :
425 6 : while (gf_list_count(ctx->streams)) {
426 2 : GF_SAFStream *st = (GF_SAFStream *)gf_list_last(ctx->streams);
427 2 : gf_list_rem_last(ctx->streams);
428 2 : gf_free(st);
429 : }
430 2 : if (ctx->saf_data) gf_free(ctx->saf_data);
431 2 : gf_list_del(ctx->streams);
432 2 : }
433 :
434 3074 : static const char *safdmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
435 : {
436 3074 : *score = GF_FPROBE_EXT_MATCH;
437 3074 : return "saf|lsr";
438 : }
439 :
440 : static const GF_FilterCapability SAFDmxCaps[] =
441 : {
442 : CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
443 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "saf|lsr"),
444 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "application/x-saf|application/saf"),
445 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
446 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
447 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_SCENE),
448 : };
449 :
450 : GF_FilterRegister SAFDmxRegister = {
451 : .name = "safdmx",
452 : GF_FS_SET_DESCRIPTION("SAF demuxer")
453 : GF_FS_SET_HELP("This filter demultiplexes SAF (MPEG-4 Simple Aggregation Format for LASeR) files/data into a set of media PIDs and frames.")
454 : .private_size = sizeof(GF_SAFDmxCtx),
455 : .initialize = safdmx_initialize,
456 : .finalize = safdmx_finalize,
457 : SETCAPS(SAFDmxCaps),
458 : .configure_pid = safdmx_configure_pid,
459 : .process = safdmx_process,
460 : .process_event = safdmx_process_event,
461 : .probe_data = safdmx_probe_data
462 : };
463 :
464 2877 : const GF_FilterRegister *safdmx_register(GF_FilterSession *session)
465 : {
466 2877 : return &SAFDmxRegister;
467 : }
468 :
|