[vlc-devel] [PATCH] DCP: allow to read subtitles

Valentin Vetter vvetter at outlook.com
Sat Mar 1 05:20:12 CET 2014


---
 modules/access/dcp/dcp.cpp       |  361 +++++++++++++++++++++++++++++++++++++-
 modules/access/dcp/dcpparser.cpp |   64 +++++--
 modules/access/dcp/dcpparser.h   |    6 +-
 3 files changed, 407 insertions(+), 24 deletions(-)

diff --git a/modules/access/dcp/dcp.cpp b/modules/access/dcp/dcp.cpp
index 7960c6e..3b17d05 100644
--- a/modules/access/dcp/dcp.cpp
+++ b/modules/access/dcp/dcp.cpp
@@ -48,6 +48,7 @@
 #include <vlc_plugin.h>
 #include <vlc_xml.h>
 #include <vlc_url.h>
+#include <vlc_memory.h>
 #include <vlc_aout.h>
 
 /* ASDCP headers */
@@ -115,6 +116,60 @@ struct audioReader_t
     The classes for handling these essence types are defined in AS_DCP.h and are different for each essence type, respectively. The demux_sys_t structure contains members for handling each of these essence types.
 */
 
+enum
+{
+    SUB_TYPE_UNKNOWN = -1,
+    SUB_TYPE_DCSUBTITLE
+};
+
+typedef struct
+{
+    int64_t i_start;
+    int64_t i_stop;
+
+    char    *psz_text;
+} subtitle_t;
+
+typedef struct
+{
+    xml_t        *xml;
+    xml_reader_t *xml_reader;
+    int          count;
+} sub_xml_t;
+
+struct demux_sub_sys_t
+{
+    int         i_type;
+    sub_xml_t   sub_xml;
+    es_out_id_t *es;
+
+    int64_t     i_next_demux_date;
+    int64_t     i_microsecperframe;
+
+    char        *psz_header;
+    int         i_subtitle;
+    int         i_subtitles;
+    subtitle_t  *subtitle;
+
+    int64_t     i_length;
+
+    struct
+    {
+        bool b_inited;
+
+        int i_comment;
+        int i_time_resolution;
+        int i_time_shift;
+    } jss;
+    struct
+    {
+        bool  b_inited;
+
+        float f_total;
+        float f_factor;
+    } mpsub;
+};
+
 class demux_sys_t
 {
  public:
@@ -127,12 +182,20 @@ class demux_sys_t
     /* ASDCP Audio MXF Reader */
     vector<audioReader_t> v_audioReader;
 
+    /* Subtitles information */
+    vector<demux_sub_sys_t*> v_sub_sys;
+
     /* audio buffer size */
     uint32_t i_audio_buffer;
 
     /* elementary streams */
     es_out_id_t *p_video_es;
     es_out_id_t *p_audio_es;
+    es_out_id_t *p_sub_es;
+
+    /* subtitle parser */
+    stream_t    *p_subtitle_parser;
+    stream_t    *p_subtitle_stream;
 
     /* DCP object */
     dcp_t *p_dcp;
@@ -153,6 +216,9 @@ class demux_sys_t
     /* current audio reel */
     unsigned int i_audio_reel;
 
+    /* current subtitle reel */
+    unsigned int i_sub_reel;
+
     uint8_t i_chans_to_reorder;            /* do we need channel reordering */
     uint8_t pi_chan_table[AOUT_CHAN_MAX];
     uint8_t i_channels;
@@ -163,13 +229,16 @@ class demux_sys_t
         PictureEssType ( ESS_UNKNOWN ),
         v_videoReader(),
         v_audioReader(),
+        v_sub_sys(),
         p_video_es( NULL ),
         p_audio_es( NULL ),
+        p_sub_es( NULL ),
         p_dcp( NULL ),
         frame_no( 0 ),
         frames_total( 0 ),
         i_video_reel( 0 ),
-        i_audio_reel( 0 ) {};
+        i_audio_reel( 0 ),
+        i_sub_reel( 0 ) {};
 
     ~demux_sys_t()
     {
@@ -281,6 +350,9 @@ static int Demux( demux_t * );
 static int Control( demux_t *, int, va_list );
 
 int dcpInit ( demux_t *p_demux );
+int OpenSubtitle( demux_t *p_demux, const char *filePath, int );
+int SubtitleDemux( demux_t *, int );
+static int ParseDCSubtitle ( demux_t *, subtitle_t *, int, int );
 int parseXML ( demux_t * p_demux );
 static inline void fillVideoFmt(
         video_format_t * fmt, unsigned int width, unsigned int height,
@@ -411,7 +483,6 @@ static int Open( vlc_object_t *obj )
                 break;
             }
             case ESS_MPEG2_VES: {
-
                 MPEG2::MXFReader *p_VideoMXFReader = new ( nothrow ) MPEG2::MXFReader();
 
                 videoReader_t videoReader;
@@ -533,7 +604,6 @@ static int Open( vlc_object_t *obj )
             audioReader_t audioReader;
             audioReader.p_AudioMXFReader = p_AudioMXFReader;
             p_sys->v_audioReader.push_back( audioReader );
-
         }
         es_format_Init( &audio_format, AUDIO_ES, VLC_CODEC_S24L );
         if( AudioDesc.AudioSamplingRate.Denominator != 0 )
@@ -573,9 +643,33 @@ static int Open( vlc_object_t *obj )
         retval = VLC_EGENERIC;
         goto error;
     }
+
+    /* Open subtitle file */
+    if( p_sys->p_dcp->sub_reels.size() > 0 )
+    {
+        for ( uint8_t i = 0; i < ( p_sys->p_dcp->sub_reels.size() ); i++)
+        {
+        if ( retval = OpenSubtitle( p_demux, p_sys->p_dcp->sub_reels[i].filename.c_str(), i ) )
+            return retval;
+        }
+    }
+
+    es_format_t fmt;
+    es_format_Init( &fmt, SPU_ES, VLC_CODEC_SUBT );
+    fmt.subs.psz_encoding = strdup( "UTF-8" );
+
+    if( ( p_demux->p_sys->p_sub_es = es_out_Add( p_demux->out, &fmt ) ) == NULL )
+    {
+        msg_Err( p_demux, "Failed to add subtitle es" );
+        free( p_sys );
+        return VLC_EGENERIC;
+    }
+
+    es_out_Control( p_demux->out, ES_OUT_SET_ES_DEFAULT, p_demux->p_sys->p_sub_es );
+    es_format_Clean( &fmt );
+
     p_demux->pf_demux = Demux;
     p_demux->pf_control = Control;
-    p_sys->frame_no = p_sys->p_dcp->video_reels[0].i_entrypoint;
 
     return VLC_SUCCESS;
 error:
@@ -631,6 +725,21 @@ static int Demux( demux_t *p_demux )
          }
      }
 
+    /* swaping subtitle reels */
+    if  ( p_sys->frame_no == p_sys->p_dcp->sub_reels[p_sys->i_sub_reel].i_absolute_end )
+    {
+        if ( p_sys->i_sub_reel + 1 == p_sys->p_dcp->sub_reels.size() )
+        {
+            return 0;
+        }
+        else
+        {
+            p_sys->i_sub_reel++;
+            es_out_Control( p_demux->out, ES_OUT_SET_ES_DEFAULT, p_demux->p_sys->p_sub_es );
+        }
+     }
+
+
     /* video frame */
     switch( p_sys->PictureEssType )
     {
@@ -719,6 +828,9 @@ static int Demux( demux_t *p_demux )
     es_out_Send( p_demux->out, p_sys->p_video_es, p_video_frame );
     es_out_Send( p_demux->out, p_sys->p_audio_es, p_audio_frame );
 
+    if ( p_sys->v_sub_sys[p_sys->i_sub_reel] )
+        SubtitleDemux( p_demux, p_sys->i_sub_reel );
+
     p_sys->frame_no++;
 
     return 1;
@@ -743,6 +855,9 @@ static int Control( demux_t *p_demux, int query, va_list args )
     int64_t *pi64, i64;
     demux_sys_t *p_sys = p_demux->p_sys;
 
+    int i_reel = 0;
+    bool b_correct_reel = false;
+
     switch ( query )
     {
         case DEMUX_CAN_PAUSE:
@@ -970,3 +1085,241 @@ int parseXML ( demux_t * p_demux )
     delete assetmap;
     return VLC_SUCCESS; /* TODO : perform checking on XML parsing */
 }
+
+
+/*****************************************************************************
+ * functions for subtitles
+ *****************************************************************************/
+
+static int XmlLoad( demux_t * p_demux, stream_t *s, int sub_nb )
+{
+    demux_sub_sys_t *p_sys = p_demux->p_sys->v_sub_sys[sub_nb];
+    sub_xml_t *p_sub_xml = &p_sys->sub_xml;
+    xml_t *p_xml;
+    xml_reader_t *p_xml_reader;
+
+    /* Create XML parser */
+    p_xml = xml_Create( p_demux );
+    if( ! p_xml )
+        return VLC_EGENERIC;
+
+    /* Initialize XML reader */
+    p_xml_reader = xml_ReaderCreate( p_xml, s );
+    if( ! p_xml_reader )
+        return VLC_EGENERIC;
+    p_sub_xml->xml = p_xml;
+    p_sub_xml->xml_reader = p_xml_reader;
+    return VLC_SUCCESS;
+
+}
+
+static void XmlUnLoad ( demux_t *p_demux, int sub_nb )
+{
+    demux_sub_sys_t *p_sys = p_demux->p_sys->v_sub_sys[sub_nb];
+    sub_xml_t *p_sub_xml = &p_sys->sub_xml;
+    xml_ReaderDelete( p_sub_xml->xml_reader );
+    xml_Delete( p_sub_xml->xml );
+
+}
+
+static int  ParseDCSubtitle( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx, int sub_nb )
+{
+    demux_sub_sys_t *p_sys = p_demux->p_sys->v_sub_sys[sub_nb];
+    sub_xml_t *p_sub_xml = &p_sys->sub_xml;
+    xml_reader_t * p_xml_reader = p_sub_xml->xml_reader;
+    const char *node = NULL;
+    int type = 0;
+    bool b_subtitle_tag = false;
+    bool b_quit = false;
+    char *psz_text = NULL;
+    int i_len = 0;
+    while( ( b_quit == false ) && ( type = xml_ReaderNextNode( p_xml_reader, &node ) ) > 0 )
+    {
+        switch (type)
+        {
+            case XML_READER_STARTELEM:
+                if( strcmp( node, "Subtitle" ) == 0 ) {
+                    const char *val, *attr;
+                    int h1, m1, s1, d1;
+                    b_subtitle_tag = true;
+                    i_len = 0;
+                    while( ( attr = xml_ReaderNextAttr( p_xml_reader, &val ) ) )  {
+                        if( ( strcmp( attr, "TimeIn" ) == 0 ) ) {
+                            if( sscanf( val, "%d:%d:%d:%d", &h1, &m1, &s1, &d1 ) ==4 ) {
+                                p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
+                                                        (int64_t)m1 * 60*1000 +
+                                                        (int64_t)s1 * 1000 +
+                                                        (int64_t)d1 ) * 1000;
+                            }
+                        }
+                        if( ( strcmp(attr, "TimeOut" ) == 0 ) ) {
+                            if( sscanf(val, "%d:%d:%d:%d", &h1, &m1, &s1, &d1) ==4 ) {
+                                p_subtitle->i_stop = ( (int64_t)h1 * 3600*1000 +
+                                                        (int64_t)m1 * 60*1000 +
+                                                        (int64_t)s1 * 1000 +
+                                                        (int64_t)d1 ) * 1000;
+                            }
+                        }
+                    }
+                }
+                break;
+
+            case XML_READER_TEXT:
+                if( b_subtitle_tag ) {
+                    if( i_len == 0 ) {
+                        psz_text = strdup(node);
+                        i_len = strlen(psz_text);
+                    } else {
+                        int i_old = i_len;
+                        i_len = strlen(node);
+                        psz_text = (char *) realloc_or_free( psz_text, i_old + i_len + 1 + 1 );
+                        strcat( psz_text, "\n" );
+                        strcat( psz_text, node );
+                        i_len = strlen(psz_text);
+                    }
+                }
+                break;
+
+            case XML_READER_ENDELEM:
+                if( strcmp( node, "Subtitle" ) == 0 ) {
+                    p_subtitle->psz_text = psz_text;
+                        b_subtitle_tag = false ;
+                        b_quit = true;
+                    }
+                 if( strcmp(node, "DCSubtitle") == 0 ) {
+                    if( psz_text ) free(psz_text);
+                    return VLC_EGENERIC;
+                    }
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    return VLC_SUCCESS;
+}
+
+int OpenSubtitle( demux_t *p_demux, const char *filePath, int sub_nb )
+{
+    demux_sub_sys_t *p_sys ;
+    const char * s_url = vlc_path2uri( filePath, "file" );
+    stream_t *p_stream;
+    int ret;
+    int i_max;
+
+    /*TODO: Where put the free */
+    p_sys = new demux_sub_sys_t();
+    p_demux->p_sys->v_sub_sys.push_back( p_sys );
+    p_demux->p_sys->v_sub_sys[sub_nb] = p_sys = (demux_sub_sys_t *) malloc( sizeof( *p_sys ) );
+
+    if( p_sys == NULL )
+        return VLC_ENOMEM;
+
+    p_sys->psz_header         = NULL;
+    p_sys->i_subtitle         = 0;
+    p_sys->i_subtitles        = 0;
+    p_sys->subtitle           = NULL;
+    p_sys->i_microsecperframe = 40000;
+
+    p_sys->jss.b_inited       = false;
+    p_sys->mpsub.b_inited     = false;
+
+    /* HARD fix fps to 24 fps */
+    p_sys->i_microsecperframe = (int64_t)(1000000 / 24 );
+
+    p_sys->i_type = SUB_TYPE_DCSUBTITLE;
+
+    /* Load the whole file */
+    p_stream = stream_UrlNew( p_demux, s_url );
+    if( ! p_stream )
+        return VLC_EGENERIC;
+    if ( ret = XmlLoad( p_demux, p_stream, sub_nb ) ) {
+        msg_Warn( p_demux, "Failure on loading XML subfile" );
+        free( p_sys );
+        stream_Delete( p_stream );
+        return ret;
+    }
+
+    /* Parse it */
+    for( i_max = 0; ; )
+    {
+        if( p_sys->i_subtitles >= i_max )
+        {
+            i_max += 500;
+            if( !( p_sys->subtitle = (subtitle_t *)realloc_or_free( p_sys->subtitle,
+                                              sizeof(subtitle_t) * i_max ) ) )
+            {
+                XmlUnLoad( p_demux, sub_nb );
+                stream_Delete( p_stream );
+                free( p_sys );
+                return VLC_ENOMEM;
+            }
+        }
+
+        if( ParseDCSubtitle( p_demux, &p_sys->subtitle[p_sys->i_subtitles],
+                     p_sys->i_subtitles, sub_nb ) )
+            break;
+
+        p_sys->i_subtitles++;
+    }
+
+    XmlUnLoad( p_demux, sub_nb );
+    stream_Delete(p_stream);
+
+    return VLC_SUCCESS;
+}
+
+int SubtitleDemux( demux_t *p_demux, int sub_nb )
+{
+    demux_sub_sys_t *p_sys = p_demux->p_sys->v_sub_sys[sub_nb];
+    int64_t i_maxdate;
+
+
+    if( p_sys->i_subtitle >= p_sys->i_subtitles )
+        return 0;
+
+    i_maxdate = p_sys->i_next_demux_date;
+
+    if( i_maxdate <= 0 && p_sys->i_subtitle < p_sys->i_subtitles )
+    {
+        /* Should not happen */
+        i_maxdate = p_sys->subtitle[p_sys->i_subtitle].i_start + 1;
+    }
+
+    while( p_sys->i_subtitle < p_sys->i_subtitles &&
+           p_sys->subtitle[p_sys->i_subtitle].i_start < i_maxdate )
+    {
+        const subtitle_t *p_subtitle = &p_sys->subtitle[p_sys->i_subtitle];
+
+        block_t *p_block;
+        int i_len = strlen( p_subtitle->psz_text ) + 1;
+
+        if( i_len <= 1 || p_subtitle->i_start < 0 )
+        {
+            p_sys->i_subtitle++;
+            continue;
+        }
+
+        if( ( p_block = block_Alloc( i_len ) ) == NULL )
+        {
+            p_sys->i_subtitle++;
+            continue;
+        }
+
+        p_block->i_dts =
+        p_block->i_pts = VLC_TS_0 + p_subtitle->i_start + p_demux->p_sys->p_dcp->sub_reels[sub_nb].i_correction;
+
+        if( p_subtitle->i_stop >= 0 && p_subtitle->i_stop >= p_subtitle->i_start )
+            p_block->i_length = p_subtitle->i_stop - p_subtitle->i_start;
+
+        memcpy( p_block->p_buffer, p_subtitle->psz_text, i_len );
+
+        es_out_Send( p_demux->out, p_demux->p_sys->p_sub_es, p_block );
+
+        p_sys->i_subtitle++;
+    }
+
+    p_sys->i_next_demux_date = 0;
+    return 1;
+}
diff --git a/modules/access/dcp/dcpparser.cpp b/modules/access/dcp/dcpparser.cpp
index cd42922..e68bc46 100644
--- a/modules/access/dcp/dcpparser.cpp
+++ b/modules/access/dcp/dcpparser.cpp
@@ -234,6 +234,8 @@ int AssetMap::Parse ( )
     int index = 0;
     int sum_duration_vid = 0;
     int sum_duration_aud = 0;
+    int sum_duration_sub = 0;
+    int64_t i_conversion = (int64_t)(1000000 / 24);
     string node;
 
     CPL  *cpl;
@@ -268,7 +270,6 @@ int AssetMap::Parse ( )
         }
     }
 
-
     /* Look for PKLs path */
     if ( (_p_asset_list == NULL) ||  (_p_asset_list->size() == 0) ) {
         msg_Err( p_demux, "Asset list empty" );
@@ -345,6 +346,7 @@ int AssetMap::Parse ( )
         Asset *asset;
         struct info_reel video;
         struct info_reel audio;
+        struct info_reel subtitles;
 
         /* Get picture */
         asset = reel->getTrack(TRACK_PICTURE);
@@ -356,32 +358,51 @@ int AssetMap::Parse ( )
             video.i_duration = asset->getDuration();
             video.i_correction = video.i_entrypoint - sum_duration_vid + video.i_duration;
             video.i_absolute_end = sum_duration_vid;
+            video.i_nb_reel = index;
             p_dcp->video_reels.push_back(video);
             msg_Dbg( this->p_demux, "Video Track: %s",asset->getPath().c_str());
             msg_Dbg( this->p_demux, "Entry point: %i",asset->getEntryPoint());
         }
+
         /* Get audio */
         asset = reel->getTrack(TRACK_SOUND);
         if (asset != NULL)
         {
-            /*if (!p_dcp->audio_reels.empty())
-            {
-                sum_duration_aud = 0;
-                for (int i = 0; i != p_dcp->audio_reels.size(); ++i)
-                {
-                    sum_duration_aud += p_dcp->audio_reels(i).i_duration;
-                }
-            }*/
             sum_duration_aud += asset->getDuration();
             audio.filename = p_dcp->path + asset->getPath();
             audio.i_entrypoint = asset->getEntryPoint();
             audio.i_duration = asset->getDuration();
             audio.i_correction = audio.i_entrypoint - sum_duration_aud + audio.i_duration;
             audio.i_absolute_end = sum_duration_aud;
+            audio.i_nb_reel = index;
             p_dcp->audio_reels.push_back(audio);
             msg_Dbg( this->p_demux, "Audio Track: %s",asset->getPath().c_str());
             msg_Dbg( this->p_demux, "Entry point: %i",asset->getEntryPoint());
         }
+
+        /* Get subtitle */
+        asset = reel->getTrack(TRACK_SUBTITLE);
+        if (asset != NULL)
+        {
+            sum_duration_sub += asset->getDuration();
+            subtitles.filename = p_dcp->path + asset->getPath();
+            subtitles.i_entrypoint = asset->getEntryPoint();
+            subtitles.i_duration = asset->getDuration();
+            /* Subtitle correction, not the same as for audio and video, unit is 10^(-6)*s */
+            if (index > 0 )
+            {
+                subtitles.i_correction = (p_dcp->video_reels[index-1].i_absolute_end + subtitles.i_entrypoint) * i_conversion;
+            }
+            else
+            {
+                subtitles.i_correction = (subtitles.i_entrypoint) * i_conversion;
+            }
+            subtitles.i_absolute_end = sum_duration_sub;
+            subtitles.i_nb_reel = index;
+            p_dcp->sub_reels.push_back(subtitles);
+            msg_Dbg( this->p_demux, "Subtitle Track: %s",asset->getPath().c_str());
+            msg_Dbg( this->p_demux, "Entry point: %i",asset->getEntryPoint());
+        }
     }
     /* free memory */
     this->CloseXml();
@@ -448,7 +469,7 @@ int Asset::Parse( xml_reader_t *p_xmlReader, string p_node, int p_type)
                                     /* Asset tags not in AssetMap */
                                     break;
                                 default:
-                                    msg_Warn(this->p_demux, "Unknow ASSET_TAG: %i", _tag );
+                                    msg_Warn( this->p_demux, "Unknow ASSET_TAG: %i", _tag );
                                     break;
                             }
                             /* break the for loop as a tag is found*/
@@ -482,6 +503,7 @@ int Asset::Parse( xml_reader_t *p_xmlReader, string p_node, int p_type)
         }
     }
     return -1;
+
 }
 
 
@@ -536,7 +558,7 @@ int Asset::ParsePKL( xml_reader_t *p_xmlReader)
                                     /* Asset tags not in PKL */
                                     break;
                                 default:
-                                    msg_Warn(this->p_demux, "Unknow ASSET_TAG: %i", _tag );
+                                    msg_Warn( this->p_demux, "Unknow ASSET_TAG: %i", _tag );
                                     break;
                             }
                             /* break the for loop as a tag is found*/
@@ -634,7 +656,6 @@ int AssetMap::ParseAssetList (xml_reader_t *p_xmlReader, const string p_node, in
     string node;
     int type;
     Asset *asset;
-
     if (p_type != XML_READER_STARTELEM)
         return -1;
     if( p_node != "AssetList" )
@@ -666,6 +687,7 @@ int AssetMap::ParseAssetList (xml_reader_t *p_xmlReader, const string p_node, in
         }
     }
     return -1;
+
 }
 
 Asset * AssetMap::getAssetById(AssetList *asset_list, const string p_id)
@@ -819,7 +841,7 @@ int PKL::Parse()
                                 this->s_group_id = s_value;
                                 break;
                             default:
-                                msg_Warn(this->p_demux, "Unknow PKG_TAG: %i", _tag );
+                                msg_Warn( this->p_demux, "Unknow PKG_TAG: %i", _tag );
                                 break;
                         }
                         /* break the for loop as a tag is found*/
@@ -992,6 +1014,10 @@ int Reel::Parse(string p_node, int p_type) {
     int type;
     string s_value;
 
+    this->p_picture_track = NULL;
+    this->p_sound_track = NULL;
+    this->p_subtitle_track = NULL;
+
     if (p_type != XML_READER_STARTELEM)
         return -1;
     if( p_node != "Reel")
@@ -1126,19 +1152,19 @@ int Reel::ParseAsset(string p_node, int p_type, TrackType_t e_track) {
                 } else if (node == "AnnotationText") {
                     if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
                         return -1;
-                        asset->setAnnotation(s_value);
+                    asset->setAnnotation(s_value);
                 } else if (node == "IntrinsicDuration") {
                     if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
                         return -1;
-                        asset->setIntrinsicDuration(atoi(s_value.c_str()));
+                    asset->setIntrinsicDuration(atoi(s_value.c_str()));
                 } else if (node == "EntryPoint") {
                     if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
                         return -1;
-                        asset->setEntryPoint(atoi(s_value.c_str()));
+                    asset->setEntryPoint(atoi(s_value.c_str()));
                 } else if (node == "Duration") {
                     if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
                         return -1;
-                        asset->setDuration(atoi(s_value.c_str()));
+                    asset->setDuration(atoi(s_value.c_str()));
                 } else if (node == "KeyId") {
                     if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
                         return -1;
@@ -1187,6 +1213,7 @@ int Reel::ParseAsset(string p_node, int p_type, TrackType_t e_track) {
         default:
             break;
     }
+
     return 0;
 }
 
@@ -1316,7 +1343,7 @@ int CPL::Parse()
                                 this->s_content_kind = s_value;
                                 break;
                             default:
-                                msg_Warn(this->p_demux, "Unknow CPL_TAG: %i", _tag );
+                                msg_Warn( this->p_demux, "Unknow CPL_TAG: %i", _tag );
                                 break;
                         }
 
@@ -1386,6 +1413,7 @@ int CPL::ParseReelList(string p_node, int p_type) {
                 break;
             }
     }
+
     return -1;
 }
 
diff --git a/modules/access/dcp/dcpparser.h b/modules/access/dcp/dcpparser.h
index 32059f5..f02a520 100644
--- a/modules/access/dcp/dcpparser.h
+++ b/modules/access/dcp/dcpparser.h
@@ -72,11 +72,12 @@ class PKL;
 /* This struct stores useful information about an MXF for demux() */
 struct info_reel
 {
+    int64_t i_correction;           /* entrypoint - sum of previous durations */
     string filename;
     int i_entrypoint;
     int i_duration;
-    int i_correction;       /* entrypoint - sum of previous durations */
-    uint32_t i_absolute_end;     /* correction + duration */
+    uint32_t i_absolute_end;    /* correction + duration */
+    int i_nb_reel;              /* number of the reel in the cpl reel list, start at 0 */
 };
 
 /* This struct stores the most important information about the DCP */
@@ -89,6 +90,7 @@ struct dcp_t
 
     vector<info_reel> audio_reels;
     vector<info_reel> video_reels;
+    vector<info_reel> sub_reels;
 
     dcp_t():
         p_asset_list(NULL) {};
-- 
1.7.9.5




More information about the vlc-devel mailing list