LCOV - code coverage report
Current view: top level - filters - mux_gsf.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 613 656 93.4 %
Date: 2021-04-29 23:48:07 Functions: 20 20 100.0 %

          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             : }

Generated by: LCOV version 1.13