Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2018-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / GPAC stream serializer 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/bitstream.h>
29 : #include <gpac/network.h>
30 : #include <gpac/internal/media_dev.h>
31 : #include <gpac/crypt.h>
32 :
33 : typedef struct
34 : {
35 : GF_FilterPid *pid;
36 :
37 : u32 idx;
38 : u16 nb_frames;
39 : Bool eos;
40 : u8 config_version;
41 : u64 last_cts_config;
42 : u32 timescale;
43 : u32 is_file;
44 : } GSFStream;
45 :
46 : typedef struct
47 : {
48 : //opts
49 : Bool sigsn, sigdur, sigbo, sigdts, minp, mixed;
50 : u32 dbg;
51 : const char *magic;
52 : const char *skp;
53 : const char *ext, *mime, *dst;
54 : GF_PropData key;
55 : GF_PropData IV;
56 : GF_Fraction pattern;
57 : u32 mpck;
58 : Double crate;
59 :
60 : //only one output pid declared
61 : GF_FilterPid *opid;
62 :
63 : GF_List *streams;
64 :
65 : u8 *buffer;
66 : u32 alloc_size;
67 : GF_BitStream *bs_w;
68 :
69 : Bool is_start;
70 : u32 max_pid_idx;
71 :
72 : bin128 crypt_IV;
73 : GF_Crypt *crypt;
74 : Bool regenerate_tunein_info;
75 :
76 : u32 nb_frames;
77 : u32 nb_pck;
78 :
79 : GF_FilterCapability caps[4];
80 : Bool filemode;
81 : } GSFMxCtx;
82 :
83 :
84 : typedef enum
85 : {
86 : GFS_PCKTYPE_HDR=0,
87 : GFS_PCKTYPE_PID_CONFIG,
88 : GFS_PCKTYPE_PID_INFO_UPDATE,
89 : GFS_PCKTYPE_PID_REMOVE,
90 : GFS_PCKTYPE_PID_EOS,
91 : GFS_PCKTYPE_PCK,
92 :
93 : GFS_PCKTYPE_UNDEF1,
94 : GFS_PCKTYPE_UNDEF2,
95 : GFS_PCKTYPE_UNDEF3,
96 : GFS_PCKTYPE_UNDEF4,
97 : GFS_PCKTYPE_UNDEF5,
98 : GFS_PCKTYPE_UNDEF6,
99 : GFS_PCKTYPE_UNDEF7,
100 : GFS_PCKTYPE_UNDEF8,
101 : GFS_PCKTYPE_UNDEF9,
102 : GFS_PCKTYPE_UNDEF10,
103 :
104 : /*NO MORE PACKET TYPE AVAILABLE*/
105 : } GF_GSFPacketType;
106 :
107 :
108 : static GFINLINE u32 get_vlen_size(u32 len)
109 : {
110 17846 : if (len<=0x7F) return 1;
111 5355 : if (len<=0x3FFF) return 2;
112 1 : if (len<=0x1FFFFF) return 3;
113 0 : if (len<=0xFFFFFFF) return 4;
114 : return 5;
115 : }
116 :
117 54741 : static GFINLINE void gsfmx_write_vlen(GSFMxCtx *ctx, u32 len)
118 : {
119 54741 : if (len<=0x7F) {
120 43333 : gf_bs_write_int(ctx->bs_w, 0, 1);
121 43333 : gf_bs_write_int(ctx->bs_w, len, 7);
122 11408 : } else if (len <= 0x3FFF){
123 6346 : gf_bs_write_int(ctx->bs_w, 1, 1);
124 6346 : gf_bs_write_int(ctx->bs_w, 0, 1);
125 6346 : gf_bs_write_int(ctx->bs_w, len, 14);
126 5062 : } else if (len <= 0x1FFFFF){
127 1207 : gf_bs_write_int(ctx->bs_w, 1, 1);
128 1207 : gf_bs_write_int(ctx->bs_w, 1, 1);
129 1207 : gf_bs_write_int(ctx->bs_w, 0, 1);
130 1207 : gf_bs_write_int(ctx->bs_w, len, 21);
131 3855 : } else if (len <= 0xFFFFFFF){
132 1956 : gf_bs_write_int(ctx->bs_w, 1, 1);
133 1956 : gf_bs_write_int(ctx->bs_w, 1, 1);
134 1956 : gf_bs_write_int(ctx->bs_w, 1, 1);
135 1956 : gf_bs_write_int(ctx->bs_w, 0, 1);
136 1956 : gf_bs_write_int(ctx->bs_w, len, 28);
137 : } else {
138 1899 : gf_bs_write_int(ctx->bs_w, 1, 1);
139 1899 : gf_bs_write_int(ctx->bs_w, 1, 1);
140 1899 : gf_bs_write_int(ctx->bs_w, 1, 1);
141 1899 : gf_bs_write_int(ctx->bs_w, 1, 1);
142 1899 : gf_bs_write_long_int(ctx->bs_w, len, 36);
143 : }
144 54741 : }
145 :
146 8282 : static GFINLINE u32 gsfmx_get_header_size(GSFMxCtx *ctx, GSFStream *gst, Bool use_seq_num, Bool first_frag, Bool no_frag, u32 pck_size, u32 block_size, u32 block_offset)
147 : {
148 8282 : u32 hdr_size = 1 + get_vlen_size(pck_size);
149 16564 : hdr_size += get_vlen_size(gst ? gst->idx : 0);
150 8282 : if (use_seq_num) hdr_size += 2;
151 :
152 8282 : if (!no_frag) {
153 1250 : hdr_size += get_vlen_size(block_size);
154 1250 : if (!first_frag)
155 992 : hdr_size += get_vlen_size(block_offset);
156 : }
157 8282 : return hdr_size;
158 : }
159 :
160 676 : static void gsfmx_encrypt(GSFMxCtx *ctx, char *data, u32 nb_crypt_bytes)
161 : {
162 : #ifndef GPAC_DISABLE_CRYPTO
163 : u32 clear_trail;
164 :
165 : clear_trail = nb_crypt_bytes % 16;
166 : nb_crypt_bytes -= clear_trail;
167 676 : if (! nb_crypt_bytes) return;
168 :
169 : //reset IV at each packet
170 672 : gf_crypt_set_IV(ctx->crypt, ctx->crypt_IV, 16);
171 672 : if (ctx->pattern.den && ctx->pattern.num) {
172 336 : u32 bytes_per_pattern = 16 * (ctx->pattern.num + ctx->pattern.den);
173 : u32 offset = 0;
174 1078 : while (nb_crypt_bytes) {
175 732 : gf_crypt_encrypt(ctx->crypt, data + offset, nb_crypt_bytes >= (u32) (16*ctx->pattern.num) ? 16*ctx->pattern.num : nb_crypt_bytes);
176 732 : if (nb_crypt_bytes >= bytes_per_pattern) {
177 406 : offset += bytes_per_pattern;
178 406 : nb_crypt_bytes -= bytes_per_pattern;
179 : } else {
180 : nb_crypt_bytes = 0;
181 : }
182 : }
183 : } else {
184 336 : gf_crypt_encrypt(ctx->crypt, data, nb_crypt_bytes);
185 : }
186 : #endif // GPAC_DISABLE_CRYPTO
187 : }
188 :
189 7048 : static void gsfmx_send_packets(GSFMxCtx *ctx, GSFStream *gst, GF_GSFPacketType pck_type, Bool is_end, Bool is_redundant, u32 frame_size, u32 frame_hdr_size)
190 : {
191 : u32 pck_size, bytes_remain, pck_offset, block_offset;
192 : Bool first_frag = GF_TRUE;
193 : Bool no_frag = GF_TRUE;
194 : //for now only data packets are encrypted on a per-fragment base, others are fully encrypted
195 7048 : Bool frag_encryption = (pck_type==GFS_PCKTYPE_PCK) ? GF_TRUE : GF_FALSE;
196 7048 : Bool use_seq_num = (pck_type==GFS_PCKTYPE_HDR) ? GF_FALSE : ctx->sigsn;
197 :
198 7048 : gf_bs_get_content_no_truncate(ctx->bs_w, &ctx->buffer, &pck_size, &ctx->alloc_size);
199 :
200 : first_frag = GF_TRUE;
201 7048 : bytes_remain = pck_size;
202 : block_offset = pck_offset = 0;
203 7048 : if (!frame_size) frame_size = pck_size;
204 :
205 7048 : if (ctx->crypt && !frag_encryption) {
206 : u32 crypt_offset=0;
207 330 : if (pck_type == GFS_PCKTYPE_HDR) {
208 : crypt_offset=25; //sig + version + IV + pattern
209 : }
210 330 : gsfmx_encrypt(ctx, ctx->buffer + crypt_offset, pck_size - crypt_offset);
211 : }
212 :
213 14705 : while (bytes_remain) {
214 : u8 *output;
215 : GF_FilterPacket *dst_pck;
216 : Bool do_encrypt = GF_FALSE;
217 : u32 crypt_offset=0;
218 : u32 osize;
219 7657 : u32 to_write = bytes_remain;
220 7657 : u32 hdr_size = gsfmx_get_header_size(ctx, gst, use_seq_num, first_frag, no_frag, to_write, frame_size, block_offset);
221 7657 : if (ctx->mpck && (ctx->mpck < to_write + hdr_size)) {
222 : no_frag = GF_FALSE;
223 625 : hdr_size = gsfmx_get_header_size(ctx, gst, use_seq_num, first_frag, no_frag, ctx->mpck - hdr_size, frame_size, block_offset);
224 625 : to_write = ctx->mpck - hdr_size;
225 : }
226 7657 : osize = hdr_size + to_write;
227 :
228 7657 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, osize, &output);
229 7657 : if (!dst_pck) return;
230 :
231 : //format header
232 7657 : gf_bs_reassign_buffer(ctx->bs_w, output, osize);
233 :
234 7657 : if (ctx->crypt) do_encrypt = GF_TRUE;
235 :
236 7657 : gf_bs_write_int(ctx->bs_w, 0, 1); //reserved
237 : //fragment flag
238 7657 : if (no_frag) gf_bs_write_int(ctx->bs_w, 0, 2);
239 883 : else if (first_frag) gf_bs_write_int(ctx->bs_w, 1, 2);
240 625 : else gf_bs_write_int(ctx->bs_w, 2, 2);
241 : //encrypt flag
242 7657 : gf_bs_write_int(ctx->bs_w, do_encrypt ? 1 : 0, 1);
243 : //packet type
244 7657 : gf_bs_write_int(ctx->bs_w, pck_type, 4);
245 :
246 : //packet size and seq num
247 7657 : gsfmx_write_vlen(ctx, gst ? gst->idx : 0);
248 7657 : if (use_seq_num) {
249 961 : gf_bs_write_u16(ctx->bs_w, gst ? gst->nb_frames : ctx->nb_frames);
250 : }
251 :
252 : //block size and block offset
253 7657 : if (!no_frag) {
254 883 : gsfmx_write_vlen(ctx, frame_size);
255 883 : if (!first_frag) gsfmx_write_vlen(ctx, block_offset);
256 : }
257 :
258 7657 : gsfmx_write_vlen(ctx, to_write);
259 :
260 7657 : hdr_size = (u32) gf_bs_get_position(ctx->bs_w);
261 : assert(hdr_size + to_write == osize);
262 7657 : memcpy(output+hdr_size, ctx->buffer + pck_offset, to_write);
263 7657 : bytes_remain -= to_write;
264 7657 : pck_offset += to_write;
265 7657 : block_offset += to_write;
266 7657 : if (frame_hdr_size) {
267 4025 : if (frame_hdr_size > block_offset) {
268 0 : frame_hdr_size -= block_offset;
269 : block_offset = 0;
270 : } else {
271 4025 : block_offset -= frame_hdr_size;
272 : frame_hdr_size = 0;
273 : }
274 : }
275 :
276 7657 : if (ctx->mpck && (ctx->mpck < to_write)) {
277 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[GSFMux] packet type %d size %d exceeds max packet size %d!\n", pck_type, osize, ctx->mpck));
278 : }
279 : //this is just to detach the buffer from the bit writer
280 7657 : gf_bs_get_content_no_truncate(ctx->bs_w, &output, &to_write, NULL);
281 :
282 7657 : if (do_encrypt && frag_encryption) {
283 : //encrypt start after fragmentation block info, plus any additional offset based on packet type
284 : hdr_size += crypt_offset;
285 346 : gsfmx_encrypt(ctx, output+hdr_size, osize - hdr_size);
286 : }
287 :
288 7657 : if (is_redundant) {
289 1894 : gf_filter_pck_set_dependency_flags(dst_pck, 1);
290 1894 : gf_filter_pck_set_framing(dst_pck, GF_FALSE, GF_FALSE);
291 5763 : } else if (first_frag && bytes_remain) {
292 258 : gf_filter_pck_set_framing(dst_pck, ctx->is_start, GF_FALSE);
293 5505 : } else if (!first_frag && bytes_remain) {
294 367 : gf_filter_pck_set_framing(dst_pck, GF_FALSE, GF_FALSE);
295 5138 : } else if (first_frag) {
296 4880 : gf_filter_pck_set_framing(dst_pck, ctx->is_start, is_end);
297 : } else {
298 258 : gf_filter_pck_set_framing(dst_pck, GF_FALSE, is_end);
299 : }
300 7657 : gf_filter_pck_send(dst_pck);
301 :
302 : first_frag = GF_FALSE;
303 : }
304 : }
305 :
306 1 : static void gsfmx_send_pid_rem(GSFMxCtx *ctx, GSFStream *gst)
307 : {
308 1 : gf_bs_reassign_buffer(ctx->bs_w, ctx->buffer, ctx->alloc_size);
309 1 : gst->nb_frames++;
310 1 : gsfmx_send_packets(ctx, gst, GFS_PCKTYPE_PID_REMOVE, GF_FALSE, GF_FALSE, 0, 0);
311 1 : }
312 :
313 15 : static void gsfmx_send_pid_eos(GSFMxCtx *ctx, GSFStream *gst, Bool is_eos)
314 : {
315 15 : gf_bs_reassign_buffer(ctx->bs_w, ctx->buffer, ctx->alloc_size);
316 15 : gst->nb_frames++;
317 15 : gsfmx_send_packets(ctx, gst, GFS_PCKTYPE_PID_EOS, is_eos, GF_FALSE, 0, 0);
318 15 : }
319 :
320 90249 : static Bool gsfmx_can_serialize_prop(const GF_PropertyValue *p)
321 : {
322 90249 : switch (p->type) {
323 2 : case GF_PROP_POINTER:
324 2 : GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[GSFMux] Cannot serialize pointer property, ignoring !!\n"));
325 : case GF_PROP_FORBIDEN:
326 : return GF_FALSE;
327 90247 : default:
328 90247 : if (p->type>=GF_PROP_LAST_DEFINED)
329 : return GF_FALSE;
330 : return GF_TRUE;
331 : }
332 : }
333 :
334 28082 : static void gsfmx_write_prop(GSFMxCtx *ctx, const GF_PropertyValue *p)
335 : {
336 : u32 len, len2, i;
337 28082 : switch (p->type) {
338 13627 : case GF_PROP_SINT:
339 : case GF_PROP_UINT:
340 13627 : gsfmx_write_vlen(ctx, p->value.uint);
341 13627 : break;
342 0 : case GF_PROP_4CC:
343 0 : gf_bs_write_u32(ctx->bs_w, p->value.uint);
344 0 : break;
345 932 : case GF_PROP_LSINT:
346 : case GF_PROP_LUINT:
347 932 : gf_bs_write_u64(ctx->bs_w, p->value.longuint);
348 932 : break;
349 1161 : case GF_PROP_BOOL:
350 1161 : gf_bs_write_u8(ctx->bs_w, p->value.boolean ? 1 : 0);
351 1161 : break;
352 1141 : case GF_PROP_FRACTION:
353 1141 : gsfmx_write_vlen(ctx, p->value.frac.num);
354 1141 : gsfmx_write_vlen(ctx, p->value.frac.den);
355 1141 : break;
356 1093 : case GF_PROP_FRACTION64:
357 1093 : gf_bs_write_u64(ctx->bs_w, p->value.lfrac.num);
358 1093 : gf_bs_write_u64(ctx->bs_w, p->value.lfrac.den);
359 1093 : break;
360 1 : case GF_PROP_FLOAT:
361 1 : gf_bs_write_float(ctx->bs_w, FIX2FLT(p->value.fnumber) );
362 1 : break;
363 1 : case GF_PROP_DOUBLE:
364 1 : gf_bs_write_double(ctx->bs_w, p->value.number);
365 1 : break;
366 1 : case GF_PROP_VEC2I:
367 1 : gsfmx_write_vlen(ctx, p->value.vec2i.x);
368 1 : gsfmx_write_vlen(ctx, p->value.vec2i.y);
369 1 : break;
370 1 : case GF_PROP_VEC2:
371 1 : gf_bs_write_double(ctx->bs_w, p->value.vec2.x);
372 1 : gf_bs_write_double(ctx->bs_w, p->value.vec2.y);
373 1 : break;
374 1 : case GF_PROP_VEC3I:
375 1 : gsfmx_write_vlen(ctx, p->value.vec3i.x);
376 1 : gsfmx_write_vlen(ctx, p->value.vec3i.y);
377 1 : gsfmx_write_vlen(ctx, p->value.vec3i.z);
378 1 : break;
379 1 : case GF_PROP_VEC4I:
380 1 : gsfmx_write_vlen(ctx, p->value.vec4i.x);
381 1 : gsfmx_write_vlen(ctx, p->value.vec4i.y);
382 1 : gsfmx_write_vlen(ctx, p->value.vec4i.z);
383 1 : gsfmx_write_vlen(ctx, p->value.vec4i.w);
384 1 : break;
385 9025 : case GF_PROP_STRING:
386 : case GF_PROP_STRING_NO_COPY:
387 : case GF_PROP_NAME:
388 9025 : len = (u32) strlen(p->value.string);
389 9025 : gsfmx_write_vlen(ctx, len);
390 9025 : gf_bs_write_data(ctx->bs_w, p->value.string, len);
391 9025 : break;
392 :
393 1095 : case GF_PROP_DATA:
394 : case GF_PROP_DATA_NO_COPY:
395 : case GF_PROP_CONST_DATA:
396 1095 : len = p->value.data.size;
397 1095 : gsfmx_write_vlen(ctx, len);
398 1095 : gf_bs_write_data(ctx->bs_w, p->value.data.ptr, len);
399 1095 : break;
400 :
401 : //string list: memory is ALWAYS duplicated
402 1 : case GF_PROP_STRING_LIST:
403 1 : len2 = p->value.string_list.nb_items;
404 1 : gsfmx_write_vlen(ctx, len2);
405 2 : for (i=0; i<len2; i++) {
406 1 : const char *str = p->value.string_list.vals[i];
407 1 : len = (u32) strlen(str);
408 1 : gsfmx_write_vlen(ctx, len);
409 1 : gf_bs_write_data(ctx->bs_w, str, len);
410 : }
411 : break;
412 :
413 1 : case GF_PROP_UINT_LIST:
414 : case GF_PROP_SINT_LIST:
415 1 : len = p->value.uint_list.nb_items;
416 1 : gsfmx_write_vlen(ctx, len);
417 2 : for (i=0; i<len; i++) {
418 1 : gsfmx_write_vlen(ctx, p->value.uint_list.vals[i] );
419 : }
420 : break;
421 0 : case GF_PROP_4CC_LIST:
422 0 : len = p->value.uint_list.nb_items;
423 0 : gsfmx_write_vlen(ctx, len);
424 0 : for (i=0; i<len; i++) {
425 0 : gf_bs_write_u32(ctx->bs_w, p->value.uint_list.vals[i] );
426 : }
427 : break;
428 0 : case GF_PROP_VEC2I_LIST:
429 0 : len = p->value.v2i_list.nb_items;
430 0 : gsfmx_write_vlen(ctx, len);
431 0 : for (i=0; i<len; i++) {
432 0 : gsfmx_write_vlen(ctx, p->value.v2i_list.vals[i].x );
433 0 : gsfmx_write_vlen(ctx, p->value.v2i_list.vals[i].y );
434 : }
435 : break;
436 0 : case GF_PROP_POINTER:
437 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[GSFMux] Cannot serialize pointer property, ignoring !!\n"));
438 : break;
439 0 : default:
440 0 : if (gf_props_type_is_enum(p->type)) {
441 0 : gsfmx_write_vlen(ctx, p->value.uint);
442 0 : break;
443 : }
444 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[GSFMux] Cannot serialize property of unknown type, ignoring !!\n"));
445 : break;
446 : }
447 28082 : }
448 :
449 58790 : static GFINLINE Bool gsfmx_is_prop_skip(GSFMxCtx *ctx, u32 prop_4cc, const char *prop_name, u8 sep_l)
450 : {
451 58790 : if (ctx->minp) {
452 : u8 flags;
453 5216 : if (prop_name) return GF_TRUE;
454 :
455 5216 : flags = gf_props_4cc_get_flags(prop_4cc);
456 5216 : if (flags & GF_PROP_FLAG_GSF_REM) return GF_TRUE;
457 2934 : return GF_FALSE;
458 : }
459 53574 : if (ctx->skp) {
460 20880 : const char *pname = prop_name ? prop_name : gf_4cc_to_str(prop_4cc);
461 20880 : u32 plen = (u32) strlen(pname);
462 20880 : const char *sep = strstr(ctx->skp, pname);
463 20880 : if (sep && ((sep[plen]==sep_l) || !sep[plen]))
464 : return GF_TRUE;
465 20880 : if (prop_4cc) {
466 15186 : pname = gf_props_4cc_get_name(prop_4cc);
467 15186 : if (!pname) pname = gf_4cc_to_str(prop_4cc);
468 15186 : plen = (u32) strlen(pname);
469 15186 : sep = strstr(ctx->skp, pname);
470 15186 : if (sep && ((sep[plen]==sep_l) || !sep[plen]))
471 : return GF_TRUE;
472 : }
473 : }
474 : return GF_FALSE;
475 : }
476 :
477 2047 : static void gsfmx_write_pid_config(GF_Filter *filter, GSFMxCtx *ctx, GSFStream *gst)
478 : {
479 : const char *force_fext=NULL;
480 : const char *force_mime=NULL;
481 : const char *force_url=NULL;
482 : u32 nb_4cc_props=0;
483 : u32 nb_str_props=0;
484 2047 : u32 idx=0;
485 2047 : u8 sep_l = gf_filter_get_sep(filter, GF_FS_SEP_LIST);
486 :
487 : while (1) {
488 : u32 prop_4cc;
489 : const char *prop_name;
490 31442 : const GF_PropertyValue *p = gf_filter_pid_enum_properties(gst->pid, &idx, &prop_4cc, &prop_name);
491 31442 : if (!p) break;
492 31485 : if (!gsfmx_can_serialize_prop(p)) continue;
493 29395 : if ( gsfmx_is_prop_skip(ctx, prop_4cc, prop_name, sep_l) )
494 2090 : continue;
495 27305 : if (prop_4cc) {
496 24458 : if (gf_props_4cc_get_type(prop_4cc) == GF_PROP_FORBIDEN) {
497 950 : nb_str_props++;
498 : }
499 : //file, only send mime, url, ext and streamtype
500 23508 : else if (!gst->is_file) {
501 23394 : if (prop_4cc != GF_PROP_PID_MUX_SRC)
502 23231 : nb_4cc_props++;
503 : }
504 : }
505 2847 : else if (prop_name)
506 2847 : nb_str_props++;
507 : }
508 :
509 : //file, send mime, url, ext and streamtype
510 2047 : if (gst->is_file) {
511 6 : GSFMxCtx *alias_ctx = gf_filter_pid_get_alias_udta(gst->pid);
512 6 : if (alias_ctx) {
513 4 : force_fext = gf_file_ext_start(alias_ctx->dst);
514 4 : if (force_fext) force_fext++;
515 4 : force_url = alias_ctx->dst ? alias_ctx->dst : NULL;
516 4 : force_mime = alias_ctx->mime;
517 : } else {
518 2 : const GF_PropertyValue *p = gf_filter_pid_get_property(gst->pid, GF_PROP_PID_FILE_EXT);
519 2 : force_fext = (p && p->value.string) ? p->value.string : ctx->ext;
520 2 : p = gf_filter_pid_get_property(gst->pid, GF_PROP_PID_MIME);
521 2 : force_mime = (p && p->value.string) ? p->value.string : ctx->mime;
522 2 : force_url = ctx->dst;
523 2 : if (!force_url) force_url = "file";
524 : }
525 6 : nb_4cc_props++;
526 6 : if (force_url)
527 6 : nb_4cc_props++;
528 6 : if (force_mime)
529 6 : nb_4cc_props++;
530 6 : if (force_fext)
531 6 : nb_4cc_props++;
532 : }
533 2047 : gf_bs_write_u8(ctx->bs_w, gst->config_version);
534 2047 : gsfmx_write_vlen(ctx, nb_4cc_props);
535 2047 : gsfmx_write_vlen(ctx, nb_str_props);
536 :
537 2047 : if (gst->is_file) {
538 : GF_PropertyValue prop;
539 :
540 6 : gf_bs_write_u32(ctx->bs_w, GF_PROP_PID_STREAM_TYPE);
541 6 : prop.type = GF_PROP_UINT;
542 6 : prop.value.uint = GF_STREAM_FILE;
543 6 : gsfmx_write_prop(ctx, &prop);
544 :
545 6 : if (force_url) {
546 6 : gf_bs_write_u32(ctx->bs_w, GF_PROP_PID_URL);
547 6 : prop.type = GF_PROP_STRING;
548 6 : prop.value.string = (char *) force_url;
549 6 : gsfmx_write_prop(ctx, &prop);
550 : }
551 :
552 6 : if (force_mime) {
553 6 : gf_bs_write_u32(ctx->bs_w, GF_PROP_PID_MIME);
554 6 : prop.type = GF_PROP_STRING;
555 6 : prop.value.string = (char *) force_mime;
556 6 : gsfmx_write_prop(ctx, &prop);
557 : }
558 6 : if (force_fext) {
559 6 : gf_bs_write_u32(ctx->bs_w, GF_PROP_PID_FILE_EXT);
560 6 : prop.type = GF_PROP_STRING;
561 6 : prop.value.string = (char *) force_fext;
562 6 : gsfmx_write_prop(ctx, &prop);
563 : }
564 : }
565 :
566 :
567 2047 : idx=0;
568 : while (1) {
569 : u32 prop_4cc;
570 : const char *prop_name;
571 31442 : const GF_PropertyValue *p = gf_filter_pid_enum_properties(gst->pid, &idx, &prop_4cc, &prop_name);
572 31442 : if (!p) break;
573 35559 : if (!gsfmx_can_serialize_prop(p)) continue;
574 :
575 29395 : if (prop_name) continue;
576 26548 : if (gf_props_4cc_get_type(prop_4cc) == GF_PROP_FORBIDEN)
577 950 : continue;
578 :
579 25598 : if ( gsfmx_is_prop_skip(ctx, prop_4cc, prop_name, sep_l) )
580 2090 : continue;
581 :
582 23508 : if (gst->is_file) {
583 114 : continue;
584 : }
585 23394 : if (prop_4cc == GF_PROP_PID_MUX_SRC)
586 163 : continue;
587 :
588 23231 : gf_bs_write_u32(ctx->bs_w, prop_4cc);
589 :
590 23231 : gsfmx_write_prop(ctx, p);
591 : }
592 :
593 2047 : idx=0;
594 : while (1) {
595 : u32 prop_4cc, len;
596 : const char *prop_name;
597 31442 : const GF_PropertyValue *p = gf_filter_pid_enum_properties(gst->pid, &idx, &prop_4cc, &prop_name);
598 31442 : if (!p) break;
599 54993 : if (!gsfmx_can_serialize_prop(p)) continue;
600 29395 : if (prop_4cc && (gf_props_4cc_get_type(prop_4cc) != GF_PROP_FORBIDEN)) continue;
601 :
602 3797 : if ( gsfmx_is_prop_skip(ctx, prop_4cc, prop_name, sep_l) )
603 0 : continue;
604 3797 : if (!prop_name)
605 950 : prop_name = gf_4cc_to_str(prop_4cc);
606 :
607 3797 : len = (u32) strlen(prop_name);
608 3797 : gsfmx_write_vlen(ctx, len);
609 3797 : gf_bs_write_data(ctx->bs_w, prop_name, len);
610 :
611 3797 : gf_bs_write_u8(ctx->bs_w, p->type);
612 3797 : gsfmx_write_prop(ctx, p);
613 : }
614 2047 : }
615 :
616 :
617 :
618 960 : static void gsfmx_send_header(GF_Filter *filter, GSFMxCtx *ctx, Bool is_carousel_update)
619 : {
620 : u32 mlen=0;
621 :
622 960 : if (!ctx->bs_w) {
623 13 : ctx->bs_w = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
624 13 : if (!ctx->bs_w) return;
625 : } else {
626 947 : gf_bs_reassign_buffer(ctx->bs_w, ctx->buffer, ctx->alloc_size);
627 : }
628 :
629 960 : ctx->nb_frames++;
630 960 : if (ctx->magic) {
631 1 : mlen = (u32) strlen(ctx->magic);
632 : }
633 :
634 : //header:signature
635 960 : gf_bs_write_u32(ctx->bs_w, GF_4CC('G','S','5','F') );
636 : //header protocol version
637 960 : gf_bs_write_u8(ctx->bs_w, GF_GSF_VERSION);
638 :
639 960 : if (ctx->crypt) {
640 2 : gf_bs_write_data(ctx->bs_w, ctx->crypt_IV, 16);
641 2 : gf_bs_write_u16(ctx->bs_w, ctx->pattern.num);
642 2 : gf_bs_write_u16(ctx->bs_w, ctx->pattern.den);
643 : }
644 960 : gf_bs_write_int(ctx->bs_w, ctx->sigsn ? 1 : 0, 1);
645 960 : gf_bs_write_int(ctx->bs_w, 0, 7);
646 :
647 : //header:magic
648 960 : gsfmx_write_vlen(ctx, mlen);
649 960 : if (ctx->magic) {
650 1 : gf_bs_write_data(ctx->bs_w, ctx->magic, mlen);
651 : }
652 :
653 960 : gsfmx_send_packets(ctx, NULL, GFS_PCKTYPE_HDR, GF_FALSE, is_carousel_update ? GF_TRUE : GF_FALSE, 0, 0);
654 960 : ctx->is_start = GF_FALSE;
655 : }
656 :
657 2047 : static void gsfmx_send_pid_config(GF_Filter *filter, GSFMxCtx *ctx, GSFStream *gst, Bool is_info, Bool is_carousel_update)
658 : {
659 2047 : if (ctx->is_start) {
660 13 : gsfmx_send_header(filter, ctx, GF_FALSE);
661 : }
662 :
663 2047 : gf_bs_reassign_buffer(ctx->bs_w, ctx->buffer, ctx->alloc_size);
664 2047 : if (!is_info && !is_carousel_update) {
665 17 : gst->config_version++;
666 : }
667 2047 : gsfmx_write_pid_config(filter, ctx, gst);
668 2047 : gst->nb_frames++;
669 2047 : gsfmx_send_packets(ctx, gst, is_info ? GFS_PCKTYPE_PID_INFO_UPDATE : GFS_PCKTYPE_PID_CONFIG, GF_FALSE, is_carousel_update ? GF_TRUE : GF_FALSE, 0, 0);
670 2047 : }
671 :
672 4025 : static void gsfmx_write_data_packet(GSFMxCtx *ctx, GSFStream *gst, GF_FilterPacket *pck)
673 : {
674 4025 : u32 w=0, h=0, stride=0, stride_uv=0, pf=0;
675 4025 : u32 nb_planes=0, uv_height=0;
676 : const char *data;
677 : u32 frame_size, frame_hdr_size;
678 : GF_FilterFrameInterface *frame_ifce=NULL;
679 : u32 nb_4cc_props=0;
680 : u32 nb_str_props=0;
681 4025 : u32 idx=0;
682 : u32 tsmode=0;
683 : u32 tsmodebits=0;
684 : u32 tsdiffmode=0;
685 : u32 tsdiffmodebits=0;
686 : Bool start, end;
687 : const GF_PropertyValue *p;
688 :
689 4025 : if (ctx->dbg==2) return;
690 :
691 4025 : gst->nb_frames++;
692 :
693 : while (1) {
694 : u32 prop_4cc;
695 : const char *prop_name;
696 5056 : p = gf_filter_pck_enum_properties(pck, &idx, &prop_4cc, &prop_name);
697 5056 : if (!p) break;
698 1031 : if (!gsfmx_can_serialize_prop(p)) continue;
699 1030 : if (prop_4cc) {
700 1028 : if (gf_props_4cc_get_type(prop_4cc) == GF_PROP_FORBIDEN)
701 1018 : nb_str_props++;
702 : else
703 10 : nb_4cc_props++;
704 : }
705 2 : else if (prop_name)
706 2 : nb_str_props++;
707 : }
708 :
709 4025 : gf_bs_reassign_buffer(ctx->bs_w, ctx->buffer, ctx->alloc_size);
710 :
711 4025 : data = gf_filter_pck_get_data(pck, &frame_size);
712 4025 : if (!data) {
713 1 : frame_ifce = gf_filter_pck_get_frame_interface(pck);
714 1 : if (frame_ifce) {
715 1 : p = gf_filter_pid_get_property(gst->pid, GF_PROP_PID_WIDTH);
716 1 : w = p ? p->value.uint : 0;
717 1 : p = gf_filter_pid_get_property(gst->pid, GF_PROP_PID_HEIGHT);
718 1 : h = p ? p->value.uint : 0;
719 1 : p = gf_filter_pid_get_property(gst->pid, GF_PROP_PID_PIXFMT);
720 1 : pf = p ? p->value.uint : 0;
721 1 : p = gf_filter_pid_get_property(gst->pid, GF_PROP_PID_STRIDE);
722 1 : stride = p ? p->value.uint : 0;
723 1 : p = gf_filter_pid_get_property(gst->pid, GF_PROP_PID_STRIDE_UV);
724 1 : stride_uv = p ? p->value.uint : 0;
725 :
726 1 : if (! gf_pixel_get_size_info(pf, w, h, &frame_size, &stride, &stride_uv, &nb_planes, &uv_height)) {
727 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[GSFMux] Raw packet with unsupported pixel format, cannot send\n"));
728 : return;
729 : }
730 : }
731 : }
732 :
733 4025 : if (ctx->dbg) frame_size=0;
734 :
735 4025 : u64 dts = gf_filter_pck_get_dts(pck);
736 4025 : u64 cts = gf_filter_pck_get_cts(pck);
737 : u32 cts_diff=0;
738 : u8 has_dts=0;
739 : u8 has_cts=0;
740 : u8 neg_cts=0;
741 :
742 : //packet structure:
743 : //flags first byte: 1(has_dts) 1(has_cts) 1(has_dur) 1(cts_diff_neg) 2(ts_mode) 2(ts_diff_mode)
744 : //flags second byte: 3(sap) 2(encrypted) 1(has_sample_deps) 1(has builtin props) 1(has_ext)
745 : //if (ext) {
746 : // flags third byte: 1(has_byteoffset) 1(corrupted) 1(seek) 1(has_carousel) 2(ilaced) 2(cktype)
747 : // flags fourth byte: 1(au start) 1(au end) 1(has props) reserved(5)
748 : //}
749 : //if has_dts, dts on tsmodebits
750 : //if has_cts, has_dts ? cts_diff on ts_diff_mode : cts on tsmodebits
751 : //if durmode>0, dur on ts_diff_mode
752 : //if sap==4, roll on signed 16 bits
753 : //if (has sample deps) sample_deps_flags on 8 bits
754 : //if has_carousel, carousel version on 8 bits
755 : //if has_byteoffset, byte offset on 64 bits
756 : //if (has builtin) vlen nb builtin_props then props[builtin_props]
757 : //if (has props) vlen nb_str_props then props[nb_str_props]
758 : //data
759 :
760 :
761 4025 : u32 duration = ctx->sigdur ? gf_filter_pck_get_duration(pck) : 0;
762 :
763 4025 : if (ctx->sigdts && (dts!=GF_FILTER_NO_TS) && (dts!=cts)) {
764 : has_dts=1;
765 :
766 590 : if (dts>0xFFFFFFFFUL) tsmode=3;
767 590 : else if (dts>0xFFFFFF) tsmode=2;
768 405 : else if (dts>0xFFFF) tsmode=1;
769 : }
770 4025 : if (cts!=GF_FILTER_NO_TS) {
771 : has_cts=1;
772 4022 : if (has_dts) {
773 590 : s64 diff = ( (s64) cts - (s64) dts);
774 590 : if (diff>0) cts_diff = (u32) diff;
775 : else {
776 : neg_cts=1;
777 375 : cts_diff = (u32) (-diff);
778 : }
779 : } else {
780 3432 : if (cts>0xFFFFFFFFUL) tsmode=3;
781 3432 : else if (cts>0xFFFFFF) tsmode=2;
782 3209 : else if (cts>0xFFFF) tsmode=1;
783 : }
784 : }
785 :
786 4025 : if (tsmode==3) tsmodebits=64;
787 4025 : else if (tsmode==2) tsmodebits=32;
788 3617 : else if (tsmode==1) tsmodebits=24;
789 : else tsmodebits=16;
790 :
791 4025 : u32 max_dur = MAX(duration, cts_diff);
792 4025 : if (max_dur < 0xFF) { tsdiffmode=0; tsdiffmodebits=8; }
793 2848 : else if (max_dur < 0xFFFF) { tsdiffmode=1; tsdiffmodebits=16; }
794 865 : else if (max_dur < 0xFFFFFF) { tsdiffmode=2; tsdiffmodebits=24; }
795 : else { tsdiffmode=3; tsdiffmodebits=32; }
796 :
797 :
798 : assert(tsmodebits<=32);
799 :
800 : //first flags byte
801 : //flags first byte: 1(has_dts) 1(has_cts) 1(has_dur) 1(cts_diff_neg) 2(ts_mode) 2(ts_diff_mode)
802 4025 : gf_bs_write_int(ctx->bs_w, has_dts, 1);
803 4025 : gf_bs_write_int(ctx->bs_w, has_cts, 1);
804 4025 : gf_bs_write_int(ctx->bs_w, duration ? 1 : 0, 1);
805 4025 : gf_bs_write_int(ctx->bs_w, neg_cts, 1);
806 4025 : gf_bs_write_int(ctx->bs_w, tsmode, 2);
807 4025 : gf_bs_write_int(ctx->bs_w, tsdiffmode, 2);
808 :
809 : //flags second byte: 3(sap) 2(encrypted) 1(has_sample_deps) 1(has builtin props) 1(has_ext)
810 4025 : u8 sap = gf_filter_pck_get_sap(pck);
811 4025 : gf_bs_write_int(ctx->bs_w, sap, 3);
812 4025 : u8 crypt = gf_filter_pck_get_crypt_flags(pck);
813 4025 : gf_bs_write_int(ctx->bs_w, crypt, 2);
814 4025 : u8 depflags = gf_filter_pck_get_dependency_flags(pck);
815 4025 : gf_bs_write_int(ctx->bs_w, depflags ? 1 : 0, 1);
816 4025 : gf_bs_write_int(ctx->bs_w, nb_4cc_props ? 1 : 0, 1);
817 :
818 4025 : u8 needs_ext = nb_str_props ? 1 : 0;
819 4025 : u64 bo = ctx->sigbo ? gf_filter_pck_get_byte_offset(pck) : GF_FILTER_NO_BO;
820 1173 : if (bo != GF_FILTER_NO_BO) needs_ext=1;
821 4025 : u8 corr = gf_filter_pck_get_corrupted(pck);
822 4025 : if (corr) needs_ext=1;
823 4025 : u8 seek = gf_filter_pck_get_seek_flag(pck);
824 4025 : if (seek) needs_ext=1;
825 4025 : u8 carv = gf_filter_pck_get_carousel_version(pck);
826 4025 : if (carv) needs_ext=1;
827 4025 : u8 interl = gf_filter_pck_get_interlaced(pck);
828 4025 : if (interl) needs_ext=1;
829 4025 : u8 cktype = gf_filter_pck_get_clock_type(pck);
830 4025 : if (cktype) needs_ext=1;
831 4025 : gf_filter_pck_get_framing(pck, &start, &end);
832 4025 : if (!start || !end) needs_ext=1;
833 :
834 4025 : gf_bs_write_int(ctx->bs_w, needs_ext, 1);
835 :
836 : //extension header
837 4025 : if (needs_ext) {
838 : // flags third byte: 1(has_byteoffset) 1(corrupted) 1(seek) 1(has_carousel) 2(ilaced) 2(cktype)
839 1007 : gf_bs_write_int(ctx->bs_w, (bo==GF_FILTER_NO_BO) ? 0 : 1, 1);
840 1007 : gf_bs_write_int(ctx->bs_w, corr ? 1 : 0, 1);
841 1007 : gf_bs_write_int(ctx->bs_w, seek ? 1 : 0, 1);
842 1007 : gf_bs_write_int(ctx->bs_w, carv ? 1 : 0, 1);
843 1007 : gf_bs_write_int(ctx->bs_w, interl, 2);
844 1007 : gf_bs_write_int(ctx->bs_w, cktype, 2);
845 :
846 : // flags fourth byte: 1(au start) 1(au end) 1(has props) reserved(5)
847 1007 : gf_bs_write_int(ctx->bs_w, start ? 1 : 0, 1);
848 1007 : gf_bs_write_int(ctx->bs_w, end ? 1 : 0, 1);
849 1007 : gf_bs_write_int(ctx->bs_w, nb_str_props ? 1 : 0, 1);
850 1007 : gf_bs_write_int(ctx->bs_w, 0, 5);
851 : }
852 : //done with flags
853 :
854 4025 : if (has_dts) {
855 590 : if (tsmode==3) gf_bs_write_long_int(ctx->bs_w, dts, tsmodebits);
856 590 : else gf_bs_write_int(ctx->bs_w, (u32) dts, tsmodebits);
857 : }
858 4025 : if (has_cts) {
859 4022 : if (has_dts) {
860 590 : gf_bs_write_int(ctx->bs_w, cts_diff, tsdiffmodebits);
861 : } else {
862 3432 : if (tsmode==3) gf_bs_write_long_int(ctx->bs_w, cts, tsmodebits);
863 3432 : else gf_bs_write_int(ctx->bs_w, (u32) cts, tsmodebits);
864 : }
865 : }
866 :
867 4025 : if (duration) {
868 3848 : gf_bs_write_int(ctx->bs_w, duration, tsdiffmodebits);
869 : }
870 :
871 4025 : if ((sap==GF_FILTER_SAP_4) || (sap==GF_FILTER_SAP_4_PROL)) {
872 1 : s16 roll = gf_filter_pck_get_roll_info(pck);
873 1 : gf_bs_write_u16(ctx->bs_w, roll);
874 : }
875 4025 : if (depflags)
876 2 : gf_bs_write_u8(ctx->bs_w, depflags);
877 :
878 4025 : if (carv) {
879 2 : gf_bs_write_u8(ctx->bs_w, carv);
880 : }
881 4025 : if (bo!=GF_FILTER_NO_BO) {
882 1 : gf_bs_write_u64(ctx->bs_w, bo);
883 : }
884 4025 : if (nb_4cc_props) {
885 6 : gsfmx_write_vlen(ctx, nb_4cc_props);
886 :
887 : //write packet properties
888 6 : idx=0;
889 : while (1) {
890 : u32 prop_4cc;
891 : const char *prop_name;
892 17 : p = gf_filter_pck_enum_properties(pck, &idx, &prop_4cc, &prop_name);
893 17 : if (!p) break;
894 12 : if (!gsfmx_can_serialize_prop(p)) continue;
895 11 : if (prop_name) continue;
896 11 : if (gf_props_4cc_get_type(prop_4cc) == GF_PROP_FORBIDEN) continue;
897 :
898 10 : gf_bs_write_u32(ctx->bs_w, prop_4cc);
899 :
900 10 : gsfmx_write_prop(ctx, p);
901 : }
902 : }
903 4025 : if (nb_str_props) {
904 1000 : gsfmx_write_vlen(ctx, nb_str_props);
905 1000 : idx=0;
906 : while (1) {
907 : u32 prop_4cc, len;
908 : const char *prop_name;
909 2022 : p = gf_filter_pck_enum_properties(pck, &idx, &prop_4cc, &prop_name);
910 2022 : if (!p) break;
911 1024 : if (!gsfmx_can_serialize_prop(p)) continue;
912 1021 : if (prop_4cc && (gf_props_4cc_get_type(prop_4cc) != GF_PROP_FORBIDEN)) continue;
913 1020 : if (!prop_name) prop_name = gf_4cc_to_str(prop_4cc);
914 1020 : len = (u32) strlen(prop_name);
915 1020 : gsfmx_write_vlen(ctx, len);
916 1020 : gf_bs_write_data(ctx->bs_w, prop_name, len);
917 :
918 1020 : gf_bs_write_u8(ctx->bs_w, p->type);
919 1020 : gsfmx_write_prop(ctx, p);
920 : }
921 1000 : gsfmx_write_vlen(ctx, nb_str_props);
922 : }
923 :
924 4025 : frame_hdr_size = (u32) gf_bs_get_position(ctx->bs_w);
925 :
926 4025 : if (has_cts && ctx->crate>0) {
927 1000 : if (!gst->last_cts_config) {
928 2 : gst->last_cts_config = has_cts+1;
929 998 : } else if ( cts - (gst->last_cts_config-1) > ctx->crate * gst->timescale) {
930 947 : ctx->regenerate_tunein_info = GF_TRUE;
931 : }
932 : }
933 :
934 :
935 : //write packet data
936 4025 : if (ctx->dbg) {
937 :
938 4025 : } else if (data) {
939 4024 : u32 nb_write = gf_bs_write_data(ctx->bs_w, data, frame_size);
940 4024 : if (nb_write != frame_size) {
941 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[GSFMux] Write error, wrote %d bytes but had %d to write\n", nb_write, frame_size));
942 : }
943 4024 : gsfmx_send_packets(ctx, gst, GFS_PCKTYPE_PCK, GF_FALSE, GF_FALSE, frame_size, frame_hdr_size);
944 1 : } else if (frame_ifce) {
945 1 : u32 i, bpp = gf_pixel_get_bytes_per_pixel(pf);
946 2 : for (i=0; i<nb_planes; i++) {
947 : u32 j, write_h, lsize;
948 : const u8 *out_ptr;
949 1 : u32 out_stride = i ? stride_uv : stride;
950 1 : GF_Err e = frame_ifce->get_plane(frame_ifce, i, &out_ptr, &out_stride);
951 1 : if (e) {
952 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[GSFMux] Failed to fetch plane data from hardware frame, cannot write\n"));
953 0 : break;
954 : }
955 : write_h = h;
956 1 : if (i) write_h = uv_height;
957 1 : lsize = bpp * (i ? stride_uv : stride);
958 3 : for (j=0; j<write_h; j++) {
959 2 : u32 nb_write = (u32) gf_bs_write_data(ctx->bs_w, out_ptr, lsize);
960 2 : if (nb_write != lsize) {
961 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[GSFMux] Write error, wrote %d bytes but had %d to write\n", nb_write, lsize));
962 : }
963 2 : out_ptr += out_stride;
964 : }
965 : }
966 1 : gsfmx_send_packets(ctx, gst, GFS_PCKTYPE_PCK, GF_FALSE, GF_FALSE, frame_size, frame_hdr_size);
967 : }
968 : }
969 :
970 18 : GF_Err gsfmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
971 : {
972 : GSFStream *gst=NULL;
973 : const GF_PropertyValue *p;
974 18 : GSFMxCtx *ctx = gf_filter_get_udta(filter);
975 :
976 18 : if (is_remove) {
977 1 : gst = gf_filter_pid_get_udta(pid);
978 1 : if (!gst) return GF_OK;
979 :
980 1 : gsfmx_send_pid_rem(ctx, gst);
981 1 : gf_list_del_item(ctx->streams, gst);
982 1 : gf_free(gst);
983 1 : if (!gf_list_count(ctx->streams) && ctx->opid) {
984 1 : gf_filter_pid_remove(ctx->opid);
985 1 : ctx->opid = NULL;
986 : }
987 : return GF_OK;
988 : }
989 17 : if (! gf_filter_pid_check_caps(pid))
990 : return GF_NOT_SUPPORTED;
991 :
992 17 : if (!ctx->opid) {
993 13 : ctx->opid = gf_filter_pid_new(filter);
994 13 : gf_filter_pid_set_name(ctx->opid, "gsf_mux");
995 : //copy properties at init or reconfig
996 13 : gf_filter_pid_copy_properties(ctx->opid, pid);
997 13 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT( GF_STREAM_FILE ) );
998 13 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, NULL );
999 13 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_ENCRYPTED, NULL );
1000 13 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, NULL );
1001 13 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG_ENHANCEMENT, NULL );
1002 13 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING( "*" ) );
1003 13 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING("application/x-gpac-sf") );
1004 : }
1005 :
1006 17 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
1007 :
1008 17 : gst = gf_filter_pid_get_udta(pid);
1009 17 : if (!gst) {
1010 16 : GF_SAFEALLOC(gst, GSFStream);
1011 16 : if (!gst) return GF_OUT_OF_MEM;
1012 16 : gf_list_add(ctx->streams, gst);
1013 16 : gst->pid = pid;
1014 16 : gf_filter_pid_set_udta(pid, gst);
1015 16 : gst->idx = 1+ctx->max_pid_idx;
1016 16 : ctx->max_pid_idx++;
1017 16 : gst->timescale = 1000;
1018 16 : if (p && p->value.uint) gst->timescale = p->value.uint;
1019 :
1020 16 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_STREAM_TYPE);
1021 16 : if (p && (p->value.uint==GF_STREAM_FILE)) gst->is_file = GF_TRUE;
1022 : } else {
1023 1 : if (p && p->value.uint) gst->timescale = p->value.uint;
1024 1 : gst->last_cts_config = 0;
1025 : }
1026 17 : gsfmx_send_pid_config(filter, ctx, gst, GF_FALSE, GF_FALSE);
1027 17 : return GF_OK;
1028 : }
1029 :
1030 :
1031 3890 : GF_Err gsfmx_process(GF_Filter *filter)
1032 : {
1033 3890 : GSFMxCtx *ctx = gf_filter_get_udta(filter);
1034 3890 : u32 i, nb_eos, count = gf_list_count(ctx->streams);
1035 :
1036 : nb_eos = 0;
1037 8294 : for (i=0; i<count; i++) {
1038 4404 : GSFStream *gst = gf_list_get(ctx->streams, i);
1039 4404 : GF_FilterPacket *pck = gf_filter_pid_get_packet(gst->pid);
1040 4404 : if (!pck) {
1041 379 : if (gf_filter_pid_is_eos(gst->pid)) {
1042 257 : nb_eos++;
1043 257 : if (!gst->eos) {
1044 15 : gsfmx_send_pid_eos(ctx, gst, (nb_eos==count) ? GF_TRUE : GF_FALSE);
1045 15 : gst->eos = GF_TRUE;
1046 : }
1047 : }
1048 379 : continue;
1049 : }
1050 4025 : gst->eos = GF_FALSE;
1051 4025 : gsfmx_write_data_packet(ctx, gst, pck);
1052 4025 : gf_filter_pid_drop_packet(gst->pid);
1053 : }
1054 3890 : if (ctx->regenerate_tunein_info) {
1055 947 : ctx->regenerate_tunein_info = GF_FALSE;
1056 947 : gsfmx_send_header(filter, ctx, GF_TRUE);
1057 1894 : for (i=0; i<count; i++) {
1058 947 : GSFStream *gst = gf_list_get(ctx->streams, i);
1059 947 : gsfmx_send_pid_config(filter, ctx, gst, GF_FALSE, GF_TRUE);
1060 : }
1061 : }
1062 :
1063 3890 : if (count && (nb_eos==count) ) {
1064 12 : gf_filter_pid_set_eos(ctx->opid);
1065 12 : return GF_EOS;
1066 : }
1067 : return GF_OK;
1068 : }
1069 :
1070 1096 : static Bool gsfmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
1071 : {
1072 1096 : GSFMxCtx *ctx = gf_filter_get_udta(filter);
1073 1096 : if (evt->base.type==GF_FEVT_INFO_UPDATE) {
1074 1083 : GSFStream *gst = gf_filter_pid_get_udta(evt->base.on_pid);
1075 1083 : if (gst)
1076 1083 : gsfmx_send_pid_config(filter, ctx, gst, GF_TRUE, GF_FALSE);
1077 : }
1078 : //don't cancel events
1079 1096 : return GF_FALSE;
1080 : }
1081 :
1082 :
1083 :
1084 :
1085 :
1086 15 : static GF_Err gsfmx_initialize(GF_Filter *filter)
1087 : {
1088 15 : GSFMxCtx *ctx = gf_filter_get_udta(filter);
1089 15 : const char *ext = ctx->ext;
1090 :
1091 15 : if (!ext && ctx->dst) {
1092 4 : ext = gf_file_ext_start(ctx->dst);
1093 4 : if (ext) ext++;
1094 : }
1095 :
1096 15 : if (!gf_filter_is_dynamic(filter) && (ext || ctx->mime)) {
1097 4 : ctx->caps[0].code = GF_PROP_PID_STREAM_TYPE;
1098 4 : ctx->caps[0].val = PROP_UINT(GF_STREAM_FILE);
1099 4 : ctx->caps[0].flags = GF_CAPS_INPUT_OUTPUT;
1100 :
1101 4 : ctx->caps[1].code = ctx->mime ? GF_PROP_PID_MIME : GF_PROP_PID_FILE_EXT;
1102 4 : ctx->caps[1].val = ctx->mime ? PROP_STRING(ctx->mime) : PROP_STRING(ext);
1103 4 : ctx->caps[1].flags = GF_CAPS_INPUT;
1104 :
1105 4 : ctx->caps[2].code = GF_PROP_PID_FILE_EXT;
1106 4 : ctx->caps[2].val = PROP_STRING("gsf");
1107 4 : ctx->caps[2].flags = GF_CAPS_OUTPUT;
1108 :
1109 4 : ctx->caps[3].code = GF_PROP_PID_MIME;
1110 4 : ctx->caps[3].val = PROP_STRING("application/x-gpac-sf");
1111 4 : ctx->caps[3].flags = GF_CAPS_OUTPUT;
1112 :
1113 4 : gf_filter_override_caps(filter, ctx->caps, 4);
1114 :
1115 4 : if (gf_filter_is_alias(filter) && ctx->mixed) {
1116 1 : ctx->caps[0].code = GF_PROP_PID_STREAM_TYPE;
1117 1 : ctx->caps[0].val = PROP_UINT(GF_STREAM_UNKNOWN);
1118 1 : ctx->caps[0].flags = GF_CAPS_INPUT_EXCLUDED;
1119 1 : return GF_OK;
1120 : }
1121 :
1122 3 : gf_filter_act_as_sink(filter);
1123 3 : ctx->filemode = GF_TRUE;
1124 : }
1125 :
1126 :
1127 14 : gf_rand_init(GF_FALSE);
1128 :
1129 14 : if (ctx->key.size==16) {
1130 : #ifdef GPAC_DISABLE_CRYPTO
1131 : return GF_NOT_SUPPORTED;
1132 : #else
1133 : GF_Err e;
1134 2 : if (ctx->IV.size==16) {
1135 2 : memcpy(ctx->crypt_IV, ctx->IV.ptr, 16);
1136 0 : } else if (ctx->IV.size) {
1137 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[GSFMux] Wrong IV value, size %d expecting 16\n", ctx->key.size));
1138 : return GF_BAD_PARAM;
1139 : } else {
1140 : char szIV[64];
1141 : u32 i;
1142 0 : * (u32 *) &ctx->crypt_IV[0] = gf_rand();
1143 0 : * (u32 *) &ctx->crypt_IV[4] = gf_rand();
1144 0 : * (u32 *) &ctx->crypt_IV[8] = gf_rand();
1145 0 : * (u32 *) &ctx->crypt_IV[12] = gf_rand();
1146 0 : szIV[0] = 0;
1147 0 : for (i=0; i<16; i++) {
1148 : char szC[3];
1149 0 : sprintf(szC, "%02X", ctx->crypt_IV[i]);
1150 : strcat(szIV, szC);
1151 : }
1152 0 : GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[GSFMux] Generated IV value Ox%s\n", szIV));
1153 : }
1154 2 : ctx->crypt = gf_crypt_open(GF_AES_128, GF_CBC);
1155 2 : if (!ctx->crypt) {
1156 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[GSFMux] Failed to allocate crypt context\n"));
1157 : return GF_IO_ERR;
1158 : }
1159 2 : e = gf_crypt_init(ctx->crypt, ctx->key.ptr, ctx->crypt_IV);
1160 2 : if (e) {
1161 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[GSFMux] Failed to setup encryption: %s\n", gf_error_to_string(e) ));
1162 : return GF_IO_ERR;
1163 : }
1164 : #endif
1165 12 : } else if (ctx->key.size) {
1166 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[GSFMux] Wrong key value, size %d expecting 16\n", ctx->key.size));
1167 : return GF_BAD_PARAM;
1168 : }
1169 :
1170 14 : ctx->streams = gf_list_new();
1171 14 : if (!ctx->streams) return GF_OUT_OF_MEM;
1172 :
1173 14 : ctx->is_start = GF_TRUE;
1174 :
1175 :
1176 14 : return GF_OK;
1177 : }
1178 :
1179 15 : static void gsfmx_finalize(GF_Filter *filter)
1180 : {
1181 15 : GSFMxCtx *ctx = gf_filter_get_udta(filter);
1182 45 : while (gf_list_count(ctx->streams)) {
1183 15 : GSFStream *gst = gf_list_pop_back(ctx->streams);
1184 15 : gf_free(gst);
1185 : }
1186 15 : gf_list_del(ctx->streams);
1187 :
1188 15 : if (ctx->bs_w) gf_bs_del(ctx->bs_w);
1189 15 : if (ctx->buffer) gf_free(ctx->buffer);
1190 : #ifndef GPAC_DISABLE_CRYPTO
1191 15 : if (ctx->crypt) gf_crypt_close(ctx->crypt);
1192 : #endif
1193 15 : }
1194 :
1195 2 : static Bool gsfmx_use_alias(GF_Filter *filter, const char *url, const char *mime)
1196 : {
1197 2 : GSFMxCtx *ctx = gf_filter_get_udta(filter);
1198 2 : return ctx->filemode;
1199 : }
1200 :
1201 : static const GF_FilterCapability GSFMxCaps[] =
1202 : {
1203 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1204 : CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
1205 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_NONE),
1206 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1207 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "gsf"),
1208 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "application/x-gpac-sf"),
1209 : };
1210 :
1211 :
1212 :
1213 : #define OFFS(_n) #_n, offsetof(GSFMxCtx, _n)
1214 : static const GF_FilterArgs GSFMxArgs[] =
1215 : {
1216 : { OFFS(sigsn), "signal packet sequence number after header field and before size field. Sequence number is per PID, encoded on 16 bits. Header packet does not have a SN", GF_PROP_BOOL, "false", NULL, 0},
1217 : { OFFS(sigdur), "signal duration", GF_PROP_BOOL, "true", NULL, GF_FS_ARG_HINT_ADVANCED},
1218 : { OFFS(sigbo), "signal byte offset", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
1219 : { OFFS(sigdts), "signal decoding timestamp", GF_PROP_BOOL, "true", NULL, GF_FS_ARG_HINT_ADVANCED},
1220 : { OFFS(dbg), "set debug mode\n"
1221 : "- no: disable debug\n"
1222 : "- nodata: force packet size to 0\n"
1223 : "- nopck: skip packet", GF_PROP_UINT, "no", "no|nodata|nopck", GF_FS_ARG_HINT_EXPERT},
1224 : #ifndef GPAC_DISABLE_CRYPTO
1225 : { OFFS(key), "encrypt packets using given key - see filter helps", GF_PROP_DATA, NULL, NULL, 0},
1226 : { OFFS(IV), "set IV for encryption - a constant IV is used to keep packet overhead small (cbcs-like)", GF_PROP_DATA, NULL, NULL, 0},
1227 : { OFFS(pattern), "set nb_crypt / nb_skip block pattern. default is all encrypted", GF_PROP_FRACTION, "1/0", NULL, GF_FS_ARG_HINT_ADVANCED},
1228 : #endif // GPAC_DISABLE_CRYPTO
1229 : { OFFS(mpck), "set max packet size. 0 means no fragmentation (each AU is sent in one packet)", GF_PROP_UINT, "0", NULL, GF_FS_ARG_HINT_ADVANCED},
1230 : { OFFS(magic), "magic string to append in setup packet", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_HINT_ADVANCED},
1231 : { OFFS(skp), "comma separated list of pid property names to skip - see filter help", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_HINT_ADVANCED},
1232 : { OFFS(minp), "include only the minimum set of properties required for stream processing - see filter help", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
1233 : { OFFS(crate), "carousel period for tune-in info in seconds - see filter help", GF_PROP_DOUBLE, "0", NULL, GF_FS_ARG_HINT_ADVANCED},
1234 : { OFFS(ext), "file extension for file mode - see filter help", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_HINT_EXPERT},
1235 : { OFFS(dst), "target URL in file mode - see filter help", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_HINT_EXPERT|GF_FS_ARG_SINK_ALIAS},
1236 : { OFFS(mime), "file mime for file mode - see filter help", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_HINT_HIDE},
1237 : { OFFS(mixed), "allow GSF to contain both files and media streams - see filter help", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT|GF_FS_ARG_SINK_ALIAS},
1238 :
1239 : {0}
1240 : };
1241 :
1242 :
1243 : GF_FilterRegister GSFMxRegister = {
1244 : .name = "gsfmx",
1245 : GF_FS_SET_DESCRIPTION("GSF Muxer")
1246 : #ifndef GPAC_DISABLE_DOC
1247 : .help = "This filter provides GSF (__GPAC Serialized Format__) multiplexing.\n"
1248 : "It serializes the stream states (config/reconfig/info update/remove/eos) and packets of input PIDs. "
1249 : "This allows either saving to file a session, or forwarding the state/data of streams to another instance of GPAC "
1250 : "using either pipes or sockets. Upstream events are not serialized.\n"
1251 : "\n"
1252 : "The default behavior does not insert sequence numbers. When running over general protocols not ensuring packet order, this should be inserted.\n"
1253 : "The serializer sends tune-in packets (global and per pid) at the requested carousel rate - if 0, no carousel. These packets are marked as redundant so that they can be discarded by output filters if needed.\n"
1254 : "\n"
1255 : #ifndef GPAC_DISABLE_CRYPTO
1256 : "# Encryption\n"
1257 : "The stream format can be encrypted in AES 128 CBC mode. For all packets, the packet header (header, size, frame size/block offset and optional seq num) are in the clear "
1258 : "and the followings byte until the last byte of the last multiple of block size (16) fitting in the payload are encrypted.\n"
1259 : "For data packets, each fragment is encrypted individually to avoid error propagation in case of losses.\n"
1260 : "For other packets, the entire packet is encrypted before fragmentation (fragments cannot be processed individually).\n"
1261 : "For header/tunein packets, the first 25 bytes after the header are in the clear (signature,version,IV and pattern).\n"
1262 : "The [-IV]() is constant to avoid packet overhead, randomly generated if not set and sent in the initial stream header. "
1263 : "Pattern mode can be used (cf CENC cbcs) to encrypt K block and leave N blocks in the clear.\n"
1264 : "\n"
1265 : #endif
1266 : "# Filtering properties\n"
1267 : "The header/tunein packet may get quite big when all pid properties are kept. In order to help reduce its size, the [-minp]() option can be used: "
1268 : "this will remove all built-in properties marked as droppable (cf property help) as well as all non built-in properties.\n"
1269 : "The [-skp]() option may also be used to specify which property to drop:\n"
1270 : "EX skp=\"4CC1,Name2\n"\
1271 : "This will remove properties of type 4CC1 and properties (built-in or not) of name Name2.\n"
1272 : "\n"
1273 : "# File mode\n"
1274 : "By default the filter only accepts framed media streams as input PID, not files. This can be changed by explicitly loading the filter with [-ext]() or [-dst]() set.\n"
1275 : "EX gpac -i source.mp4 gsfmx:dst=manifest.mpd @ -o dump.gsf\n"
1276 : "This will DASH the source and store every files produced as PIDs in the GSF mux.\n"
1277 : "In order to demux such a file, the GSF demuxer will likely need to be explicitly loaded:\n"
1278 : "EX gpac -i mux.gsf gsfdmx @ -o dump/$File$:dynext:clone\n"
1279 : "This will extract all files from the GSF mux.\n"
1280 : "\n"
1281 : "When working in file mode, the filter by default only accepts PID of type `file` as input.\n"
1282 : "To allow a mix of files and streams, use [-mixed]():\n"
1283 : "EX gpac -i source.mp4 gsfmx:dst=manifest.mpd:mixed @ -o dump.gsf\n"
1284 : "This will DASH the source, store the manifest file and the media streams with their packet properties in the GSF mux.\n"
1285 : ,
1286 : #endif
1287 : .private_size = sizeof(GSFMxCtx),
1288 : .max_extra_pids = (u32) -1,
1289 : .args = GSFMxArgs,
1290 : .flags = GF_FS_REG_DYNAMIC_REDIRECT,
1291 : SETCAPS(GSFMxCaps),
1292 : .initialize = gsfmx_initialize,
1293 : .finalize = gsfmx_finalize,
1294 : .configure_pid = gsfmx_configure_pid,
1295 : .process = gsfmx_process,
1296 : .process_event = gsfmx_process_event,
1297 : .use_alias = gsfmx_use_alias
1298 : };
1299 :
1300 :
1301 2877 : const GF_FilterRegister *gsfmx_register(GF_FilterSession *session)
1302 : {
1303 2877 : return &GSFMxRegister;
1304 : }
|