LCOV - code coverage report
Current view: top level - filters - dmx_vobsub.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 150 200 75.0 %
Date: 2021-04-29 23:48:07 Functions: 8 8 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 / NHNT 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             : #ifndef GPAC_DISABLE_VOBSUB
      33             : 
      34             : #include <gpac/internal/vobsub.h>
      35             : 
      36             : 
      37             : typedef struct
      38             : {
      39             :         //opts
      40             :         Bool blankframe;
      41             : 
      42             :         GF_FilterPid *idx_pid, *sub_pid;
      43             :         GF_Filter *sub_filter;
      44             :         GF_List *opids;
      45             :         Bool first;
      46             : 
      47             :         u32 idx_file_crc;
      48             :         FILE *mdia;
      49             : 
      50             :         Double start_range;
      51             :         u64 first_dts;
      52             : 
      53             :         u32 nb_playing;
      54             :         GF_Fraction64 duration;
      55             :         Bool in_seek;
      56             : 
      57             :         Bool initial_play_done;
      58             :         Bool idx_parsed;
      59             : 
      60             :         u32 timescale;
      61             : 
      62             :         vobsub_file *vobsub;
      63             : } GF_VOBSubDmxCtx;
      64             : 
      65             : 
      66           4 : GF_Err vobsubdmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
      67             : {
      68             :         u32 crc;
      69             :         const GF_PropertyValue *p;
      70           4 :         GF_VOBSubDmxCtx *ctx = gf_filter_get_udta(filter);
      71             : 
      72           4 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_URL);
      73           4 :         if (!p) {
      74           0 :                 gf_filter_setup_failure(filter, GF_URL_ERROR);
      75           0 :                 return GF_EOS;
      76             :         }
      77             : 
      78           4 :         if (is_remove) {
      79             :                 u32 i, count;
      80           0 :                 ctx->idx_pid = NULL;
      81           0 :                 ctx->sub_pid = NULL;
      82           0 :                 count = gf_filter_get_opid_count(filter);
      83           0 :                 for (i=0; i<count; i++) {
      84           0 :                         gf_filter_pid_remove( gf_filter_get_opid(filter, i) );
      85             :                 }
      86             :                 return GF_OK;
      87             :         }
      88           4 :         if (! gf_filter_pid_check_caps(pid))
      89             :                 return GF_NOT_SUPPORTED;
      90             : 
      91           4 :         if (!ctx->idx_pid) {
      92           2 :                 ctx->idx_pid = pid;
      93           2 :         } else if (ctx->idx_pid != pid) {
      94           2 :                 ctx->sub_pid = pid;
      95             :         }
      96             :         
      97           4 :         gf_filter_pid_set_framing_mode(pid, GF_TRUE);
      98             : 
      99           4 :         if (ctx->idx_pid==pid) {
     100             :                 GF_Err e;
     101             :                 Bool use_gfio = GF_FALSE;
     102             :                 char sURL[GF_MAX_PATH], *ext;
     103           2 :                 crc = gf_crc_32(p->value.string, (u32) strlen(p->value.string));
     104           2 :                 if (ctx->idx_file_crc == crc) return GF_OK;
     105           2 :                 ctx->idx_file_crc = crc;
     106             : 
     107           2 :                 if (ctx->sub_filter) {
     108           0 :                         gf_filter_remove_src(filter, ctx->sub_filter);
     109           0 :                         ctx->sub_filter = NULL;
     110             :                 }
     111           2 :                 if (!strncmp(p->value.string, "gfio://", 7)) {
     112             :                         use_gfio = GF_TRUE;
     113           0 :                         strcpy(sURL, gf_fileio_translate_url(p->value.string) );
     114             :                 } else {
     115             :                         strcpy(sURL, p->value.string);
     116             :                 }
     117           2 :                 ext = gf_file_ext_start(sURL);
     118           2 :                 if (ext) ext[0] = 0;
     119             :                 strcat(sURL, ".sub");
     120           2 :                 if (use_gfio) {
     121           0 :                         GF_FileIO *gfio = gf_fileio_from_url(p->value.string);
     122           0 :                         char *base = gf_file_basename(sURL);
     123           0 :                         const char *new_url = gf_fileio_factory(gfio, base ? base : sURL);
     124           0 :                         if (new_url) {
     125             :                                 strcpy(sURL, new_url);
     126             :                         }
     127             :                 }
     128             : 
     129           2 :                 ctx->sub_filter = gf_filter_connect_source(filter, sURL, NULL, GF_TRUE, &e);
     130           2 :                 if (e) return e;
     131           2 :                 if (ctx->mdia) gf_fclose(ctx->mdia);
     132           2 :                 ctx->mdia = NULL;
     133           2 :                 gf_filter_disable_probe(ctx->sub_filter);
     134             : 
     135           2 :                 ctx->first = GF_TRUE;
     136             :         }
     137             : 
     138             :         return GF_OK;
     139             : }
     140             : 
     141          36 : static Bool vobsubdmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
     142             : {
     143          36 :         GF_VOBSubDmxCtx *ctx = gf_filter_get_udta(filter);
     144             : 
     145          36 :         switch (evt->base.type) {
     146           2 :         case GF_FEVT_PLAY:
     147           2 :                 if (ctx->nb_playing) return GF_TRUE;
     148           2 :                 if (ctx->vobsub && (ctx->start_range != evt->play.start_range)) {
     149             :                         u32 i;
     150           0 :                         for (i=0; i<ctx->vobsub->num_langs; i++) {
     151           0 :                                 ctx->vobsub->langs[i].last_dts = 0;
     152           0 :                                 ctx->vobsub->langs[i].current = 0;
     153           0 :                                 ctx->vobsub->langs[i].is_seek = GF_TRUE;
     154             :                         }
     155             :                 }
     156           2 :                 ctx->start_range = evt->play.start_range;
     157           2 :                 ctx->nb_playing++;
     158             : 
     159             :                 //cancel event
     160           2 :                 return GF_TRUE;
     161             : 
     162           0 :         case GF_FEVT_STOP:
     163           0 :                 ctx->nb_playing--;
     164             :                 //don't cancel event
     165           0 :                 return GF_FALSE;
     166             : 
     167             :         case GF_FEVT_SET_SPEED:
     168             :                 //cancel event
     169             :                 return GF_TRUE;
     170             :         default:
     171             :                 break;
     172             :         }
     173             :         //by default don't cancel event - to rework once we have downloading in place
     174          34 :         return GF_FALSE;
     175             : }
     176             : 
     177           2 : GF_Err vobsubdmx_parse_idx(GF_Filter *filter, GF_VOBSubDmxCtx *ctx)
     178             : {
     179             :         FILE *file = NULL;
     180             :         int               version;
     181             :         GF_Err err = GF_OK;
     182             :         const GF_PropertyValue *p;
     183             : 
     184           2 :         if (!ctx->idx_pid) return GF_SERVICE_ERROR;
     185             : 
     186           2 :         p = gf_filter_pid_get_property(ctx->idx_pid, GF_PROP_PID_FILEPATH);
     187           2 :         if (!p) {
     188           0 :                 gf_filter_setup_failure(filter, GF_URL_ERROR);
     189           0 :                 return GF_EOS;
     190             :         }
     191             : 
     192           2 :         file = gf_fopen(p->value.string, "rb");
     193           2 :         if (!file) {
     194           0 :                 gf_filter_setup_failure(filter, GF_URL_ERROR);
     195           0 :                 return GF_EOS;
     196             :         }
     197             : 
     198           2 :         GF_SAFEALLOC(ctx->vobsub, vobsub_file);
     199           2 :         if (!ctx->vobsub) {
     200           0 :                 gf_fclose(file);
     201           0 :                 gf_filter_setup_failure(filter, GF_URL_ERROR);
     202           0 :                 return GF_EOS;
     203             :         }
     204             : 
     205           2 :         err = vobsub_read_idx(file, ctx->vobsub, &version);
     206           2 :         gf_fclose(file);
     207           2 :         if (err) {
     208           0 :                 gf_filter_setup_failure(filter, GF_URL_ERROR);
     209           0 :                 return GF_EOS;
     210             :         }
     211           2 :         if (!gf_filter_get_opid_count(filter) ) {
     212             :                 u32 i;
     213           2 :                 ctx->duration.num = 0;
     214             : 
     215           4 :                 for (i=0; i<ctx->vobsub->num_langs; i++) {
     216           2 :                         vobsub_pos *pos = (vobsub_pos*)gf_list_last(ctx->vobsub->langs[i].subpos);
     217           2 :                         if ((u64) ctx->duration.num < pos->start*90)
     218           2 :                                 ctx->duration.num = (s64) (pos->start*90);
     219             :                 }
     220           2 :                 ctx->duration.den = 90000;
     221             : 
     222           6 :                 for (i=0; i<ctx->vobsub->num_langs; i++) {
     223           2 :                         GF_FilterPid *opid = gf_filter_pid_new(filter);
     224             : 
     225             :                         //copy properties from idx pid
     226           2 :                         gf_filter_pid_copy_properties(opid, ctx->idx_pid);
     227             : 
     228           2 :                         gf_filter_pid_set_property(opid, GF_PROP_PID_ID, &PROP_UINT(i+1) );
     229           2 :                         gf_filter_pid_set_property(opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_TEXT) );
     230           2 :                         gf_filter_pid_set_property(opid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_SUBPIC) );
     231           2 :                         gf_filter_pid_set_property(opid, GF_PROP_PID_TIMESCALE, &PROP_UINT(90000) );
     232           2 :                         gf_filter_pid_set_property(opid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA((char*)&ctx->vobsub->palette[0][0], sizeof(ctx->vobsub->palette)) );
     233             : 
     234             : 
     235           2 :                         gf_filter_pid_set_property(opid, GF_PROP_PID_WIDTH, &PROP_UINT(ctx->vobsub->width) );
     236           2 :                         gf_filter_pid_set_property(opid, GF_PROP_PID_HEIGHT, &PROP_UINT(ctx->vobsub->height) );
     237           2 :                         gf_filter_pid_set_property(opid, GF_PROP_PID_LANGUAGE, &PROP_STRING(ctx->vobsub->langs[i].name) );
     238           2 :                         gf_filter_pid_set_property(opid, GF_PROP_PID_DURATION, &PROP_FRAC64(ctx->duration) );
     239           2 :                         gf_filter_pid_set_property(opid, GF_PROP_PID_PLAYBACK_MODE, &PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD ) );
     240             : 
     241           2 :                         gf_filter_pid_set_udta(opid, &ctx->vobsub->langs[i]);
     242             :                 }
     243             :         }
     244             :         return GF_OK;
     245             : }
     246             : 
     247          32 : static GF_Err vobsubdmx_send_stream(GF_VOBSubDmxCtx *ctx, GF_FilterPid *pid)
     248             : {
     249             :         static const u8 null_subpic[] = { 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0xFF };
     250             :         GF_List *subpic;
     251             :         vobsub_lang *vslang;
     252             :         u32 c, count;
     253             :         GF_FilterPacket *dst_pck;
     254             : 
     255             :         unsigned char buf[0x800];
     256             : 
     257          32 :         vslang = gf_filter_pid_get_udta(pid);
     258          32 :         subpic = vslang->subpos;
     259             : 
     260          32 :         count = gf_list_count(subpic);
     261             : 
     262          32 :         c = vslang->current;
     263             : 
     264          32 :         for (; c<count; c++) {
     265             :                 u32             i, left, size, psize, dsize, hsize, duration;
     266             :                 u8 *packet;
     267          30 :                 vobsub_pos *pos = (vobsub_pos*)gf_list_get(subpic, c);
     268             : 
     269          30 :                 if (vslang->is_seek) {
     270           0 :                         if (pos->start*90 < ctx->start_range * 90000) {
     271           0 :                                 continue;
     272             :                         }
     273           0 :                         vslang->is_seek = GF_FALSE;
     274             :                 }
     275             : 
     276          30 :                 gf_fseek(ctx->mdia, pos->filepos, SEEK_SET);
     277          30 :                 if (gf_ftell(ctx->mdia) != pos->filepos) {
     278           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[VobSub] Could not seek in file\n"));
     279          30 :                         return GF_IO_ERR;
     280             :                 }
     281             : 
     282          30 :                 if (!gf_fread(buf, sizeof(buf), ctx->mdia)) {
     283           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[VobSub] Could not read from file\n"));
     284             :                         return GF_IO_ERR;
     285             :                 }
     286             : 
     287          60 :                 if (*(u32*)&buf[0x00] != 0xba010000            ||
     288          90 :                             (buf[14] || buf[15] || (buf[16]!=0x01) || (buf[17]!=0xbd)) ||
     289          60 :                         !(buf[0x15] & 0x80)                            ||
     290          60 :                         (buf[0x17] & 0xf0) != 0x20                     ||
     291          30 :                         (buf[buf[0x16] + 0x17] & 0xe0) != 0x20)
     292             :                 {
     293           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[VobSub] Corrupted data found in file (1)\n"));
     294             :                         return GF_CORRUPTED_DATA;
     295             :                 }
     296             : 
     297          30 :                 psize = (buf[buf[0x16] + 0x18] << 8) + buf[buf[0x16] + 0x19];
     298          30 :                 dsize = (buf[buf[0x16] + 0x1a] << 8) + buf[buf[0x16] + 0x1b];
     299             : 
     300          30 :                 if (ctx->blankframe && !c && (pos->start>0)) {
     301           0 :                         dst_pck = gf_filter_pck_new_alloc(pid, sizeof(null_subpic), &packet);
     302           0 :                         if (!dst_pck) return GF_OUT_OF_MEM;
     303             : 
     304           0 :                         memcpy(packet, null_subpic, sizeof(null_subpic));
     305           0 :                         gf_filter_pck_set_cts(dst_pck, 0);
     306           0 :                         gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
     307           0 :                         gf_filter_pck_set_duration(dst_pck, (u32) (pos->start * 90) );
     308           0 :                         gf_filter_pck_send(dst_pck);
     309             :                 }
     310             : 
     311          30 :                 dst_pck = gf_filter_pck_new_alloc(pid, psize, &packet);
     312          30 :                 if (!dst_pck) return GF_OUT_OF_MEM;
     313             : 
     314          48 :                 for (i = 0, left = psize; i < psize; i += size, left -= size) {
     315          48 :                         hsize = 0x18 + buf[0x16];
     316          48 :                         size  = MIN(left, 0x800 - hsize);
     317          48 :                         memcpy(packet + i, buf + hsize, size);
     318             : 
     319          48 :                         if (size != left) {
     320          18 :                                 while (gf_fread(buf, sizeof(buf), ctx->mdia)) {
     321          18 :                                         if (buf[buf[0x16] + 0x17] == (vslang->idx | 0x20)) {
     322             :                                                 break;
     323             :                                         }
     324             :                                 }
     325             :                         }
     326             :                 }
     327             : 
     328          30 :                 if (i != psize || left > 0) {
     329           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[VobSub] Corrupted data found in file (2)\n"));
     330             :                         return GF_CORRUPTED_DATA;
     331             :                 }
     332             : 
     333          30 :                 if (vobsub_get_subpic_duration(packet, psize, dsize, &duration) != GF_OK) {
     334           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[VobSub] Corrupted data found in file (3)\n"));
     335             :                         return GF_CORRUPTED_DATA;
     336             :                 }
     337             : 
     338          30 :                 gf_filter_pck_set_cts(dst_pck, pos->start * 90);
     339          30 :                 gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
     340          30 :                 gf_filter_pck_set_duration(dst_pck, duration);
     341             : 
     342          30 :                 if (vslang->last_dts && (vslang->last_dts >= pos->start * 90)) {
     343           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[VobSub] Out of order timestamps in vobsub file\n"));
     344             :                 }
     345          30 :                 gf_filter_pck_send(dst_pck);
     346          30 :                 vslang->last_dts = pos->start * 90;
     347             : 
     348          30 :                 vslang->current++;
     349          30 :                 if (gf_filter_pid_would_block(pid)) return GF_OK;
     350             :         }
     351             :         return GF_EOS;
     352             : }
     353             : 
     354          52 : GF_Err vobsubdmx_process(GF_Filter *filter)
     355             : {
     356          52 :         GF_VOBSubDmxCtx *ctx = gf_filter_get_udta(filter);
     357             :         GF_FilterPacket *pck;
     358             :         u32 pkt_size, i, count, nb_eos;
     359             :         Bool start, end;
     360             : 
     361          52 :         if (!ctx->idx_parsed) {
     362             :                 GF_Err e;
     363           2 :                 pck = gf_filter_pid_get_packet(ctx->idx_pid);
     364           2 :                 if (!pck) return GF_OK;
     365           2 :                 gf_filter_pck_get_framing(pck, &start, &end);
     366             :                 //for now we only work with complete files
     367             :                 assert(end);
     368             : 
     369           2 :                 e = vobsubdmx_parse_idx(filter, ctx);
     370           2 :                 ctx->idx_parsed = GF_TRUE;
     371           2 :                 gf_filter_pid_drop_packet(ctx->idx_pid);
     372           2 :                 if (e) {
     373           0 :                         gf_filter_setup_failure(filter, e);
     374           0 :                         return e;
     375             :                 }
     376             :         }
     377             : 
     378          52 :         if (!ctx->nb_playing) return GF_OK;
     379             : 
     380          48 :         if (!ctx->mdia) {
     381             :                 const GF_PropertyValue *p;
     382           2 :                 if (!ctx->sub_pid) return GF_OK;
     383           2 :                 p = gf_filter_pid_get_property(ctx->sub_pid, GF_PROP_PID_FILEPATH);
     384           2 :                 if (!p) {
     385           0 :                         gf_filter_setup_failure(filter, GF_URL_ERROR);
     386           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[VobSub] Cannot open sub file\n"));
     387             :                         return GF_EOS;
     388             :                 }
     389           2 :                 ctx->mdia = gf_fopen(p->value.string, "rb");
     390             :         }
     391             : 
     392          48 :         pck = gf_filter_pid_get_packet(ctx->sub_pid);
     393          48 :         if (!pck) {
     394          16 :                 if (gf_filter_pid_is_eos(ctx->sub_pid)) return GF_EOS;
     395          16 :                 return GF_OK;
     396             :         }
     397             : 
     398          32 :         /*data =*/ gf_filter_pck_get_data(pck, &pkt_size);
     399          32 :         gf_filter_pck_get_framing(pck, &start, &end);
     400             :         //for now we only work with complete files
     401             :         assert(end);
     402             : 
     403             :         nb_eos = 0;
     404          32 :         count = gf_filter_get_opid_count(filter);
     405          64 :         for (i=0; i<count; i++) {
     406          32 :                 GF_FilterPid *opid = gf_filter_get_opid(filter, i);
     407          32 :                 GF_Err e = vobsubdmx_send_stream(ctx, opid);
     408          32 :                 if (e==GF_EOS) {
     409           2 :                         nb_eos++;
     410           2 :                         gf_filter_pid_set_eos(opid);
     411             :                 }
     412             :         }
     413             : 
     414          32 :         if (nb_eos==count) {
     415             :                 //only drop packet once we are done
     416           2 :                 gf_filter_pid_drop_packet(ctx->sub_pid);
     417           2 :                 return GF_EOS;
     418             :         }
     419             :         return GF_OK;
     420             : }
     421             : 
     422           2 : static void vobsubdmx_finalize(GF_Filter *filter)
     423             : {
     424           2 :         GF_VOBSubDmxCtx *ctx = gf_filter_get_udta(filter);
     425           2 :         if (ctx->vobsub) vobsub_free(ctx->vobsub);
     426           2 :         if (ctx->mdia) gf_fclose(ctx->mdia);
     427           2 : }
     428             : 
     429        3065 : static const char * vobsubdmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
     430             : {
     431        3065 :         if (!strncmp(data, "# VobSub", 8)) {
     432           2 :                 *score = GF_FPROBE_SUPPORTED;
     433           2 :                 return "text/vobsub";
     434             :         }
     435             :         return NULL;
     436             : }
     437             : 
     438             : #define OFFS(_n)        #_n, offsetof(GF_VOBSubDmxCtx, _n)
     439             : static const GF_FilterArgs GF_VOBSubDmxArgs[] =
     440             : {
     441             :         { OFFS(blankframe), "force inserting a blank frame if first subpic is not at 0", GF_PROP_BOOL, "true", NULL, GF_FS_ARG_HINT_ADVANCED},
     442             :         {0}
     443             : };
     444             : 
     445             : 
     446             : static const GF_FilterCapability VOBSubDmxCaps[] =
     447             : {
     448             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
     449             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "idx|sub"),
     450             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "text/vobsub"),
     451             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_TEXT),
     452             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_SUBPIC),
     453             : };
     454             : 
     455             : 
     456             : GF_FilterRegister VOBSubDmxRegister = {
     457             :         .name = "vobsubdmx",
     458             :         GF_FS_SET_DESCRIPTION("VobSub demuxer")
     459             :         GF_FS_SET_HELP("This filter demultiplexes VobSub files/data to produce media PIDs and frames.")
     460             :         .private_size = sizeof(GF_VOBSubDmxCtx),
     461             :         .max_extra_pids = 1,
     462             :         .args = GF_VOBSubDmxArgs,
     463             :         .finalize = vobsubdmx_finalize,
     464             :         SETCAPS(VOBSubDmxCaps),
     465             :         .configure_pid = vobsubdmx_configure_pid,
     466             :         .process = vobsubdmx_process,
     467             :         .probe_data = vobsubdmx_probe_data,
     468             :         .process_event = vobsubdmx_process_event
     469             : };
     470             : 
     471             : #endif
     472             : 
     473        2877 : const GF_FilterRegister *vobsubdmx_register(GF_FilterSession *session)
     474             : {
     475             : #ifndef GPAC_DISABLE_VOBSUB
     476        2877 :         return &VOBSubDmxRegister;
     477             : #else
     478             :         return NULL;
     479             : #endif
     480             : 
     481             : }
     482             : 

Generated by: LCOV version 1.13