LCOV - code coverage report
Current view: top level - filters - tssplit.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 164 192 85.4 %
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 Paris 2019-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / MPEG Transport Stream splitter 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             : #include <gpac/mpegts.h>
      33             : 
      34             : typedef struct
      35             : {
      36             :         GF_FilterPid *opid;
      37             :         u32 pmt_pid;
      38             :         u8 pat_pck[192];
      39             :         u32 pat_pck_size;
      40             : 
      41             :         u8 *pck_buffer;
      42             :         u32 nb_pck;
      43             : } GF_M2TSSplit_SPTS;
      44             : 
      45             : 
      46             : typedef struct
      47             : {
      48             :         //options
      49             :         Bool dvb;
      50             :         s32 mux_id;
      51             :         Bool avonly;
      52             :         u32 nb_pack;
      53             : 
      54             :         //internal
      55             :         GF_Filter *filter;
      56             :         GF_FilterPid *ipid;
      57             : 
      58             :         GF_List *streams;
      59             : 
      60             :         GF_M2TS_Demuxer *dmx;
      61             : 
      62             :         u8 tsbuf[192];
      63             :         GF_BitStream *bsw;
      64             : 
      65             : } GF_M2TSSplitCtx;
      66             : 
      67             : 
      68             : 
      69      141926 : void m2tssplit_send_packet(GF_M2TSSplitCtx *ctx, GF_M2TSSplit_SPTS *stream, u8 *data, u32 size)
      70             : {
      71             :         u8 *buffer;
      72             :         GF_FilterPacket *pck;
      73      141926 :         if (ctx->nb_pack) {
      74             :                 assert (stream->nb_pck<ctx->nb_pack);
      75      141926 :                 if (data) {
      76      141920 :                         memcpy(stream->pck_buffer + size*stream->nb_pck, data, size);
      77      141920 :                         stream->nb_pck++;
      78      141920 :                         if (stream->nb_pck<ctx->nb_pack) {
      79      127732 :                                 return;
      80             :                         }
      81             :                 }
      82       14194 :                 u32 osize = size*stream->nb_pck;
      83       14194 :                 pck = gf_filter_pck_new_alloc(stream->opid, osize, &buffer);
      84       14194 :                 if (pck) {
      85       14194 :                         gf_filter_pck_set_framing(pck, GF_FALSE, GF_FALSE);
      86       14194 :                         memcpy(buffer, stream->pck_buffer, osize);
      87       14194 :                         gf_filter_pck_send(pck);
      88             :                 }
      89       14194 :                 stream->nb_pck = 0;
      90             :         } else {
      91           0 :                 pck = gf_filter_pck_new_alloc(stream->opid, size, &buffer);
      92           0 :                 if (pck) {
      93           0 :                         gf_filter_pck_set_framing(pck, GF_FALSE, GF_FALSE);
      94           0 :                         memcpy(buffer, data, size);
      95           0 :                         gf_filter_pck_send(pck);
      96             :                 }
      97             :         }
      98             : }
      99             : 
     100       14250 : void m2tssplit_flush(GF_M2TSSplitCtx *ctx)
     101             : {
     102             :         u32 i;
     103       14250 :         if (!ctx->nb_pack) return;
     104             : 
     105       99750 :         for (i=0; i<gf_list_count(ctx->streams); i++ ) {
     106       99750 :                 GF_M2TSSplit_SPTS *stream = gf_list_get(ctx->streams, i);
     107       99750 :                 if (stream->opid && stream->nb_pck)
     108           6 :                         m2tssplit_send_packet(ctx, stream, NULL, 0);
     109             :         }
     110             : 
     111             : }
     112             : 
     113           2 : GF_Err m2tssplit_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
     114             : {
     115           2 :         GF_M2TSSplitCtx *ctx = gf_filter_get_udta(filter);
     116             : 
     117           2 :         if (is_remove) {
     118           0 :                 ctx->ipid = NULL;
     119           0 :                 m2tssplit_flush(ctx);
     120           0 :                 while (gf_list_count(ctx->streams) ) {
     121           0 :                         GF_M2TSSplit_SPTS *st = gf_list_pop_back(ctx->streams);
     122           0 :                         if (st->opid) gf_filter_pid_remove(st->opid);
     123           0 :                         if (st->pck_buffer) gf_free(st->pck_buffer);
     124           0 :                         gf_free(st);
     125             :                 }
     126             :                 return GF_OK;
     127             :         }
     128           2 :         if (! gf_filter_pid_check_caps(pid))
     129             :                 return GF_NOT_SUPPORTED;
     130             : 
     131           2 :         ctx->ipid = pid;
     132           2 :         return GF_OK;
     133             : }
     134             : 
     135        5646 : static Bool m2tssplit_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
     136             : {
     137             : //      GF_M2TSSplitCtx *ctx = gf_filter_get_udta(filter);
     138             : 
     139        5646 :         switch (evt->base.type) {
     140             :         case GF_FEVT_PLAY:
     141             :                 //cancel event
     142             :                 return GF_TRUE;
     143             : 
     144           0 :         case GF_FEVT_STOP:
     145           0 :                 return GF_FALSE;
     146             : 
     147             :         case GF_FEVT_SET_SPEED:
     148             :                 //cancel event
     149             :                 return GF_TRUE;
     150             :         default:
     151             :                 break;
     152             :         }
     153             :         //by default don't cancel event - to rework once we have downloading in place
     154        5640 :         return GF_FALSE;
     155             : }
     156             : 
     157       19890 : GF_Err m2tssplit_process(GF_Filter *filter)
     158             : {
     159       19890 :         GF_M2TSSplitCtx *ctx = gf_filter_get_udta(filter);
     160             :         GF_FilterPacket *pck;
     161             :         const u8 *data;
     162             :         u32 data_size;
     163       19890 :         pck = gf_filter_pid_get_packet(ctx->ipid);
     164       19890 :         if (!pck) {
     165       14250 :                 if (gf_filter_pid_is_eos(ctx->ipid))
     166       14250 :                         m2tssplit_flush(ctx);
     167             :                 return GF_OK;
     168             :         }
     169        5640 :         data = gf_filter_pck_get_data(pck, &data_size);
     170        5640 :         if (data) {
     171        5640 :                 gf_m2ts_process_data(ctx->dmx, (u8 *)data, data_size);
     172             :         }
     173        5640 :         gf_filter_pid_drop_packet(ctx->ipid);
     174        5640 :         return GF_OK;
     175             : }
     176             : 
     177             : 
     178      151307 : void m2tssplit_on_event(struct tag_m2ts_demux *ts, u32 evt_type, void *par)
     179             : {
     180             :         u32 i;
     181      151307 :         GF_M2TSSplitCtx *ctx = ts->user;
     182             : 
     183      151307 :         if ((evt_type==GF_M2TS_EVT_PAT_FOUND) || (evt_type==GF_M2TS_EVT_PAT_UPDATE)) {
     184             :                 //todo, purge previous programs if PMT PID changes
     185          15 :                 for (i=0; i<gf_list_count(ctx->dmx->programs); i++) {
     186             :                         GF_M2TS_SectionInfo *sinfo = par;
     187             :                         GF_M2TSSplit_SPTS *stream=NULL;
     188             :                         u32 j, pck_size, tot_len=188, crc, offset=5, mux_id;
     189             :                         u8 *buffer;
     190             :                         Bool first_pck=GF_FALSE;
     191           7 :                         GF_M2TS_Program *prog = gf_list_get(ctx->dmx->programs, i);
     192             :                         assert(prog->pmt_pid);
     193             : 
     194          28 :                         for (j=0; j<gf_list_count(ctx->streams); j++) {
     195          21 :                                 stream = gf_list_get(ctx->streams, j);
     196          21 :                                 if (stream->pmt_pid==prog->pmt_pid)
     197             :                                         break;
     198             :                                 stream = NULL;
     199             :                         }
     200           7 :                         if (!stream) {
     201           7 :                                 GF_SAFEALLOC(stream, GF_M2TSSplit_SPTS);
     202           7 :                                 if (!stream) return;
     203           7 :                                 stream->pmt_pid = prog->pmt_pid;
     204             :                                 first_pck = GF_TRUE;
     205           7 :                                 prog->user = stream;
     206           7 :                                 if (ctx->nb_pack)
     207           7 :                                         stream->pck_buffer = gf_malloc(sizeof(char) * ctx->nb_pack * (ctx->dmx->prefix_present ? 192 : 188) );
     208             : 
     209           7 :                                 gf_list_add(ctx->streams, stream);
     210             : 
     211             :                                 //do not create output stream until we are sure we have AV component in program
     212             :                         }
     213             : 
     214             :                         //generate a pat
     215           7 :                         gf_bs_seek(ctx->bsw, 0);
     216           7 :                         if (ctx->dmx->prefix_present) {
     217             :                                 tot_len += 4;
     218             :                                 offset += 4;
     219           0 :                                 gf_bs_write_u32(ctx->bsw, 1);
     220             :                         }
     221           7 :                         gf_bs_write_u8(ctx->bsw, 0x47);
     222           7 :                         gf_bs_write_int(ctx->bsw,    0, 1);    // error indicator
     223           7 :                         gf_bs_write_int(ctx->bsw,    1, 1); // start ind
     224           7 :                         gf_bs_write_int(ctx->bsw,    0, 1);    // transport priority
     225           7 :                         gf_bs_write_int(ctx->bsw,    0, 13); // pid
     226           7 :                         gf_bs_write_int(ctx->bsw,    0, 2);    // scrambling
     227           7 :                         gf_bs_write_int(ctx->bsw,    1, 2);    // we do not use adaptation field for sections
     228           7 :                         gf_bs_write_int(ctx->bsw,    0, 4);   // continuity counter
     229           7 :                         gf_bs_write_u8(ctx->bsw,     0);   // ptr_field
     230           7 :                         gf_bs_write_int(ctx->bsw,    GF_M2TS_TABLE_ID_PAT, 8);
     231           7 :                         gf_bs_write_int(ctx->bsw,    1/*use_syntax_indicator*/, 1);
     232           7 :                         gf_bs_write_int(ctx->bsw,    0, 1);
     233           7 :                         gf_bs_write_int(ctx->bsw,    3, 2);  /* reserved bits are all set */
     234           7 :                         gf_bs_write_int(ctx->bsw,    5 + 4 + 4, 12); //syntax indicator section + PAT payload + CRC32
     235             :                         /*syntax indicator section*/
     236             : 
     237           7 :                         if (ctx->mux_id>=0) {
     238           0 :                                 mux_id = ctx->mux_id;
     239             :                         } else {
     240             :                                 //we use muxID*255 + streamIndex as the target mux ID if not configured
     241           7 :                                 mux_id = sinfo->ex_table_id;
     242           7 :                                 mux_id *= 255;
     243             :                         }
     244           7 :                         mux_id += i;
     245             : 
     246           7 :                         gf_bs_write_int(ctx->bsw,    mux_id, 16);
     247           7 :                         gf_bs_write_int(ctx->bsw,    3, 2); /* reserved bits are all set */
     248           7 :                         gf_bs_write_int(ctx->bsw,    sinfo->version_number, 5);
     249           7 :                         gf_bs_write_int(ctx->bsw,    1, 1); /* current_next_indicator = 1: we don't send version in advance */
     250           7 :                         gf_bs_write_int(ctx->bsw,    0, 8); //current section number
     251           7 :                         gf_bs_write_int(ctx->bsw,    0, 8); //last section number
     252             : 
     253             :                         /*PAT payload*/
     254           7 :                         gf_bs_write_u16(ctx->bsw, prog->number);
     255           7 :                         gf_bs_write_int(ctx->bsw, 0x7, 3);   /*reserved*/
     256           7 :                         gf_bs_write_int(ctx->bsw, prog->pmt_pid, 13);     /*reserved*/
     257             : 
     258           7 :                         pck_size = (u32) gf_bs_get_position(ctx->bsw);
     259             :                         /*write CRC32 starting from first field in section until last before CRC*/
     260           7 :                         crc = gf_crc_32(ctx->tsbuf + offset, pck_size - offset);
     261           7 :                         ctx->tsbuf[pck_size] = (crc >> 24) & 0xFF;
     262           7 :                         ctx->tsbuf[pck_size+1] = (crc >> 16) & 0xFF;
     263           7 :                         ctx->tsbuf[pck_size+2] = (crc  >> 8) & 0xFF;
     264           7 :                         ctx->tsbuf[pck_size+3] = crc & 0xFF;
     265           7 :                         pck_size += 4;
     266             : 
     267             :                         //pad the rest to 0xFF
     268           7 :                         memset(ctx->tsbuf + pck_size, 0xFF, tot_len - pck_size);
     269             :                         //copy over for PAT repeat
     270           7 :                         memcpy(stream->pat_pck, ctx->tsbuf, tot_len);
     271           7 :                         stream->pat_pck_size = tot_len;
     272             : 
     273             :                         //output new PAT
     274           7 :                         if (stream->opid) {
     275           0 :                                 GF_FilterPacket *pck = gf_filter_pck_new_alloc(stream->opid, tot_len, &buffer);
     276           0 :                                 if (pck) {
     277           0 :                                         gf_filter_pck_set_framing(pck, first_pck, GF_FALSE);
     278           0 :                                         memcpy(buffer, ctx->tsbuf, tot_len);
     279           0 :                                         gf_filter_pck_send(pck);
     280             :                                 }
     281             :                         }
     282             :                 }
     283             :                 return;
     284             :         }
     285             :         //resend PAT
     286      151306 :         if (evt_type==GF_M2TS_EVT_PAT_REPEAT) {
     287         630 :                 for (i=0; i<gf_list_count(ctx->dmx->programs); i++) {
     288             :                         u8 *buffer;
     289         630 :                         GF_M2TS_Program *prog = gf_list_get(ctx->dmx->programs, i);
     290         630 :                         GF_M2TSSplit_SPTS *stream = prog->user;
     291         720 :                         if (!stream) continue;
     292         630 :                         if (!stream->opid) continue;
     293             : 
     294         540 :                         GF_FilterPacket *pck = gf_filter_pck_new_alloc(stream->opid, stream->pat_pck_size, &buffer);
     295         540 :                         if (pck) {
     296         540 :                                 gf_filter_pck_set_framing(pck, GF_FALSE, GF_FALSE);
     297         540 :                                 memcpy(buffer, stream->pat_pck, stream->pat_pck_size);
     298         540 :                                 gf_filter_pck_send(pck);
     299             :                         }
     300             :                 }
     301             :                 return;
     302             :         }
     303      151216 :         if ((evt_type==GF_M2TS_EVT_PMT_FOUND) || (evt_type==GF_M2TS_EVT_PMT_UPDATE)) {
     304             :                 GF_M2TS_Program *prog = par;
     305           7 :                 GF_M2TSSplit_SPTS *stream = prog->user;
     306             :                 u32 known_streams = 0;
     307          35 :                 for (i=0; i<gf_list_count(prog->streams); i++) {
     308          28 :                         GF_M2TS_ES *es = gf_list_get(prog->streams, i);
     309          28 :                         switch (es->stream_type) {
     310          13 :                         case GF_M2TS_VIDEO_MPEG1:
     311             :                         case GF_M2TS_VIDEO_MPEG2:
     312             :                         case GF_M2TS_VIDEO_DCII:
     313             :                         case GF_M2TS_VIDEO_MPEG4:
     314             :                         case GF_M2TS_VIDEO_H264:
     315             :                         case GF_M2TS_VIDEO_SVC:
     316             :                         case GF_M2TS_VIDEO_HEVC:
     317             :                         case GF_M2TS_VIDEO_HEVC_TEMPORAL:
     318             :                         case GF_M2TS_VIDEO_HEVC_MCTS:
     319             :                         case GF_M2TS_VIDEO_SHVC:
     320             :                         case GF_M2TS_VIDEO_SHVC_TEMPORAL:
     321             :                         case GF_M2TS_VIDEO_MHVC:
     322             :                         case GF_M2TS_VIDEO_MHVC_TEMPORAL:
     323             :                         case GF_M2TS_VIDEO_VVC:
     324             :                         case GF_M2TS_VIDEO_VVC_TEMPORAL:
     325             :                         case GF_M2TS_VIDEO_VC1:
     326             :                         case GF_M2TS_AUDIO_MPEG1:
     327             :                         case GF_M2TS_AUDIO_MPEG2:
     328             :                         case GF_M2TS_AUDIO_LATM_AAC:
     329             :                         case GF_M2TS_AUDIO_AAC:
     330             :                         case GF_CODECID_AAC_MPEG2_MP:
     331             :                         case GF_CODECID_AAC_MPEG2_LCP:
     332             :                         case GF_CODECID_AAC_MPEG2_SSRP:
     333             :                         case GF_M2TS_AUDIO_AC3:
     334             :                         case GF_M2TS_AUDIO_EC3:
     335             :                         case GF_M2TS_SYSTEMS_MPEG4_SECTIONS:
     336             :                         case GF_M2TS_SYSTEMS_MPEG4_PES:
     337             :                         case GF_M2TS_METADATA_PES:
     338             :                         case GF_M2TS_METADATA_ID3_HLS:
     339          13 :                                 known_streams++;
     340          13 :                                 break;
     341             :                         default:
     342             :                                 break;
     343             :                         }
     344             :                 }
     345             :                 //if avonly mode and no known streams, do not forward program
     346           7 :                 if (ctx->avonly && !known_streams)
     347             :                         return;
     348             :                 //good to go, create output and send PAT
     349           6 :                 if (!stream->opid) {
     350             :                         u8 *buffer;
     351             : 
     352           6 :                         stream->opid = gf_filter_pid_new(ctx->filter);
     353           6 :                         gf_filter_pid_set_property(stream->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_FILE));
     354           6 :                         gf_filter_pid_set_property(stream->opid, GF_PROP_PID_MIME, &PROP_STRING("video/mpeg-2"));
     355           6 :                         gf_filter_pid_set_property(stream->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING("ts"));
     356           6 :                         gf_filter_pid_set_property(stream->opid, GF_PROP_PID_SERVICE_ID, &PROP_UINT(prog->number));
     357             : 
     358           6 :                         GF_FilterPacket *pck = gf_filter_pck_new_alloc(stream->opid, stream->pat_pck_size, &buffer);
     359           6 :                         if (pck) {
     360           6 :                                 gf_filter_pck_set_framing(pck, GF_TRUE, GF_FALSE);
     361           6 :                                 memcpy(buffer, stream->pat_pck, stream->pat_pck_size);
     362           6 :                                 gf_filter_pck_send(pck);
     363             :                         }
     364             :                 }
     365             :                 return;
     366             :         }
     367             : 
     368      151209 :         if (evt_type==GF_M2TS_EVT_PCK) {
     369             :                 GF_M2TS_TSPCK *tspck = par;
     370             :                 Bool do_fwd;
     371      149859 :                 GF_M2TSSplit_SPTS *stream = tspck->stream ? tspck->stream->program->user : NULL;
     372             : 
     373      141063 :                 if (stream) {
     374      141063 :                         if (!stream->opid) return;
     375             : 
     376      140852 :                         if (ctx->dmx->prefix_present) {
     377           0 :                                 u8 *data = tspck->data;
     378           0 :                                 data -= 4;
     379           0 :                                 m2tssplit_send_packet(ctx, stream, data, 192);
     380             :                         } else {
     381      140852 :                                 m2tssplit_send_packet(ctx, stream, tspck->data, 188);
     382             :                         }
     383             :                         return;
     384             :                 }
     385             : 
     386        8796 :                 if (!ctx->dvb) return;
     387             : 
     388             :                 do_fwd = GF_FALSE;
     389        8796 :                 switch (tspck->pid) {
     390             :                 case GF_M2TS_PID_CAT:
     391             :                 case GF_M2TS_PID_TSDT:
     392             :                 case GF_M2TS_PID_NIT_ST:
     393             :                 case GF_M2TS_PID_SDT_BAT_ST:
     394             :                 case GF_M2TS_PID_EIT_ST_CIT:
     395             :                 case GF_M2TS_PID_RST_ST:
     396             :                 case GF_M2TS_PID_TDT_TOT_ST:
     397             :                 case GF_M2TS_PID_NET_SYNC:
     398             :                 case GF_M2TS_PID_RNT:
     399             :                 case GF_M2TS_PID_IN_SIG:
     400             :                 case GF_M2TS_PID_MEAS:
     401             :                 case GF_M2TS_PID_DIT:
     402             :                 case GF_M2TS_PID_SIT:
     403             :                         do_fwd = GF_TRUE;
     404             :                 }
     405             :                 if (do_fwd) {
     406         178 :                         u32 count = gf_list_count(ctx->streams);
     407        1424 :                         for (i=0; i<count; i++) {
     408        1246 :                                 stream = gf_list_get(ctx->streams, i);
     409        1246 :                                 if (!stream->opid) continue;
     410             : 
     411        1068 :                                 if (ctx->dmx->prefix_present) {
     412           0 :                                         u8 *data = tspck->data;
     413           0 :                                         data -= 4;
     414           0 :                                         m2tssplit_send_packet(ctx, stream, data, 192);
     415             :                                 } else {
     416        1068 :                                         m2tssplit_send_packet(ctx, stream, tspck->data, 188);
     417             :                                 }
     418             :                         }
     419             :                 }
     420             :         }
     421             : }
     422             : 
     423           1 : GF_Err m2tssplit_initialize(GF_Filter *filter)
     424             : {
     425           1 :         GF_M2TSSplitCtx *ctx = gf_filter_get_udta(filter);
     426           1 :         ctx->streams = gf_list_new();
     427           1 :         ctx->dmx = gf_m2ts_demux_new();
     428           1 :         ctx->dmx->on_event = m2tssplit_on_event;
     429           1 :         ctx->dmx->split_mode = GF_TRUE;
     430           1 :         ctx->dmx->user = ctx;
     431           1 :         ctx->filter = filter;
     432           1 :         ctx->bsw = gf_bs_new(ctx->tsbuf, 192, GF_BITSTREAM_WRITE);
     433           1 :         if (ctx->nb_pack<=1)
     434           0 :                 ctx->nb_pack = 0;
     435           1 :         return GF_OK;
     436             : }
     437             : 
     438           1 : void m2tssplit_finalize(GF_Filter *filter)
     439             : {
     440           1 :         GF_M2TSSplitCtx *ctx = gf_filter_get_udta(filter);
     441             : 
     442           9 :         while (gf_list_count(ctx->streams)) {
     443           7 :                 GF_M2TSSplit_SPTS *st = gf_list_pop_back(ctx->streams);
     444           7 :                 if (st->pck_buffer) gf_free(st->pck_buffer);
     445           7 :                 gf_free(st);
     446             :         }
     447           1 :         gf_list_del(ctx->streams);
     448           1 :         gf_bs_del(ctx->bsw);
     449           1 :         gf_m2ts_demux_del(ctx->dmx);
     450           1 : }
     451             : 
     452             : static const GF_FilterCapability M2TSSplitCaps[] =
     453             : {
     454             :         CAP_UINT(GF_CAPS_INPUT_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
     455             :         CAP_STRING(GF_CAPS_INPUT_OUTPUT, GF_PROP_PID_FILE_EXT, "ts|m2t|mts|dmb|trp"),
     456             :         CAP_STRING(GF_CAPS_INPUT_OUTPUT, GF_PROP_PID_MIME, "video/mpeg-2|video/mp2t|video/mpeg"),
     457             : };
     458             : 
     459             : #define OFFS(_n)        #_n, offsetof(GF_M2TSSplitCtx, _n)
     460             : static const GF_FilterArgs M2TSSplitArgs[] =
     461             : {
     462             :         { OFFS(dvb), "forward all packets from global DVB PIDs", GF_PROP_BOOL, "true", NULL, GF_FS_ARG_HINT_ADVANCED},
     463             :         { OFFS(mux_id), "set initial ID of output mux; the first program will use mux_id, the second mux_id+1, etc. If not set, this value will be set to sourceMuxId*255", GF_PROP_SINT, "-1", NULL, GF_FS_ARG_HINT_EXPERT},
     464             :         { OFFS(avonly), "do not forward programs with no AV component", GF_PROP_BOOL, "true", NULL, GF_FS_ARG_HINT_ADVANCED},
     465             :         { OFFS(nb_pack), "pack N packets before sending", GF_PROP_UINT, "10", NULL, GF_FS_ARG_HINT_ADVANCED},
     466             : 
     467             :         {0}
     468             : };
     469             : 
     470             : 
     471             : 
     472             : GF_FilterRegister M2TSSplitRegister = {
     473             :         .name = "tssplit",
     474             :         GF_FS_SET_DESCRIPTION("MPEG Transport Stream splitter")
     475             :         GF_FS_SET_HELP("This filter splits an MPEG-2 transport stream into several single program transport streams.\n"
     476             :         "Only the PAT table is rewritten, the CAT table, PMT and all program streams are forwarded as is.\n"
     477             :         "In [-full]() mode, global DVB tables of the input multiplex are forwarded to each output mux; otherwise these tables are discarded.")
     478             :         .flags = GF_FS_REG_EXPLICIT_ONLY,
     479             :         .private_size = sizeof(GF_M2TSSplitCtx),
     480             :         .initialize = m2tssplit_initialize,
     481             :         .finalize = m2tssplit_finalize,
     482             :         .args = M2TSSplitArgs,
     483             :         SETCAPS(M2TSSplitCaps),
     484             :         .configure_pid = m2tssplit_configure_pid,
     485             :         .process = m2tssplit_process,
     486             :         .process_event = m2tssplit_process_event,
     487             : };
     488             : 
     489        2877 : const GF_FilterRegister *m2tssplit_register(GF_FilterSession *session)
     490             : {
     491        2877 :         return &M2TSSplitRegister;
     492             : }
     493             : 

Generated by: LCOV version 1.13