LCOV - code coverage report
Current view: top level - filters - dmx_saf.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 176 207 85.0 %
Date: 2021-04-29 23:48:07 Functions: 9 9 100.0 %

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

Generated by: LCOV version 1.13