[vlc-devel] [PATCHv12] dcp: Creation of access-demux module for DCP

Nicolas Bertrand nicoinattendu at gmail.com
Tue Dec 10 14:31:18 CET 2013


This version only support 1-Reel-per-track DCPs, like trailers

---
 configure.ac                     |   17 +
 modules/access/Makefile.am       |    7 +
 modules/access/dcp/dcp.cpp       |  819 +++++++++++++++++++++++
 modules/access/dcp/dcpparser.cpp | 1356 ++++++++++++++++++++++++++++++++++++++
 modules/access/dcp/dcpparser.h   |  299 +++++++++
 5 files changed, 2498 insertions(+)
 create mode 100644 modules/access/dcp/dcp.cpp
 create mode 100644 modules/access/dcp/dcpparser.cpp
 create mode 100644 modules/access/dcp/dcpparser.h

diff --git a/configure.ac b/configure.ac
index 5f7ed24..e6951dc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1918,6 +1918,23 @@ fi
 AM_CONDITIONAL(HAVE_AVFOUNDATION, [test "${have_avfoundation}" != "no"])
 
 dnl
+dnl  DCP plugin (using asdcplib)
+dnl
+AC_ARG_ENABLE(dcp,
+  AS_HELP_STRING([--enable-dcp],[Digital Cinema Package support using asdcplib (default auto)]))
+have_asdcp="no"
+AS_IF([test "x${enable_dcp}" != "no"], [
+  AC_LANG_PUSH(C++)
+  AC_CHECK_HEADERS( [[AS@&t at _DCP.h]],
+    [have_asdcp="yes"],
+    [AS_IF( [test "x${enable_dcp}" = "yes"],
+      [AC_MSG_ERROR( [ ASDCP library cannot be found (needed for dcp module). Either use --enable-dcp=no or install asdcp library: http://www-dev.pub.cinecert.com/asdcplib/download/ ] )])
+     ])
+  AC_LANG_POP(C++)
+])
+AM_CONDITIONAL(HAVE_ASDCP, [test "${have_asdcp}" != "no"])
+
+dnl
 dnl  Demux plugins
 dnl
 
diff --git a/modules/access/Makefile.am b/modules/access/Makefile.am
index 6b48799..27193a1 100644
--- a/modules/access/Makefile.am
+++ b/modules/access/Makefile.am
@@ -9,6 +9,13 @@ AM_CPPFLAGS += -I$(srcdir)/access
 libattachment_plugin_la_SOURCES = access/attachment.c
 access_LTLIBRARIES += libattachment_plugin.la
 
+libdcp_plugin_la_SOURCES = access/dcp/dcpparser.h access/dcp/dcp.cpp access/dcp/dcpparser.cpp
+libdcp_plugin_la_CPPFLAGS = $(AM_CPPFLAGS)
+libdcp_plugin_la_LIBADD = $(AM_LIBADD) -lasdcp
+if HAVE_ASDCP
+access_LTLIBRARIES += libdcp_plugin.la
+endif
+
 libfilesystem_plugin_la_SOURCES = access/fs.h access/file.c access/directory.c access/fs.c
 libfilesystem_plugin_la_CPPFLAGS = $(AM_CPPFLAGS)
 if HAVE_WIN32
diff --git a/modules/access/dcp/dcp.cpp b/modules/access/dcp/dcp.cpp
new file mode 100644
index 0000000..1ae54ee
--- /dev/null
+++ b/modules/access/dcp/dcp.cpp
@@ -0,0 +1,819 @@
+/*****************************************************************************
+ * Copyright (C) 2012-2013 VLC authors and VideoLAN
+ *
+ * Authors:
+ *          Nicolas Bertrand <nico at isf.cc>
+ *          Simona-Marinela Prodea <simona dot marinela dot prodea at gmail dot com>
+ *          Jean-Baptiste Kempf <jb at videolan.org>
+ *          Pierre Villard <pierre dot villard dot fr at gmail dot com>
+ *          Claire Etienne
+ *          Aurélie Sbinné
+ *          Samuel Kerjose
+ *          Julien Puyobro
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/**
+ * @file dcp.cpp
+ * @brief DCP access-demux module for Digital Cinema Packages using asdcp library
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#define __STDC_CONSTANT_MACROS 1
+
+/* VLC core API headers */
+#include <vlc_common.h>
+#include <vlc_demux.h>
+#include <vlc_plugin.h>
+#include <vlc_xml.h>
+#include <vlc_url.h>
+#include <vlc_aout.h>
+
+/* ASDCP headers */
+#include <AS_DCP.h>
+
+#include "dcpparser.h"
+
+using namespace ASDCP;
+using namespace std;
+
+#define FRAME_BUFFER_SIZE 1302083 /* maximum frame length, in bytes, after
+                                     "Digital Cinema System Specification Version 1.2
+                                     with Errata as of 30 August 2012" */
+
+/* Forward declarations */
+static int Open( vlc_object_t * );
+static void Close( vlc_object_t * );
+
+/* Module descriptor */
+vlc_module_begin()
+    set_shortname( N_( "DCP" ) )
+    add_shortcut( "dcp" )
+    set_description( N_( "Digital Cinema Package module" ) )
+    set_capability( "access_demux", 0 )
+    set_category( CAT_INPUT )
+    set_subcategory( SUBCAT_INPUT_ACCESS )
+    set_callbacks( Open, Close )
+vlc_module_end()
+
+//! Kind of MXF MEDIA TYPE
+typedef enum MxfMedia_t {
+    MXF_UNKNOWN = 0,
+    MXF_PICTURE,
+    MXF_AUDIO,
+} MxfMedia_t;
+
+/* ASDCP library (version 1.10.48) can handle files having one of the following Essence Types, as defined in AS_DCP.h:
+    ESS_UNKNOWN,     // the file is not a supported AS-DCP essence container
+    ESS_MPEG2_VES,   // the file contains an MPEG video elementary stream
+    ESS_JPEG_2000,   // the file contains one or more JPEG 2000 codestreams
+    ESS_PCM_24b_48k, // the file contains one or more PCM audio pairs
+    ESS_PCM_24b_96k, // the file contains one or more PCM audio pairs
+    ESS_TIMED_TEXT,  // the file contains an XML timed text document and one or more resources
+    ESS_JPEG_2000_S, // the file contains one or more JPEG 2000 codestream pairs (stereoscopic).
+
+    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.
+*/
+
+class demux_sys_t
+{
+ public:
+    /* ASDCP Picture Essence Type */
+    EssenceType_t PictureEssType;
+
+    /* ASDCP Video MXF Reader */
+    union
+    {
+        /* JPEG2000 essence type */
+        JP2K::MXFReader *p_PicMXFReader;
+
+        /* JPEG2000 stereoscopic essence type */
+        JP2K::MXFSReader *p_PicMXFSReader;
+
+        /* MPEG2 essence type */
+        MPEG2::MXFReader *p_VideoMXFReader;
+    };
+
+    /* ASDCP Audio MXF Reader */
+    PCM::MXFReader *p_AudioMXFReader;
+
+    /* audio buffer size */
+    uint32_t i_audio_buffer;
+
+    /* elementary streams */
+    es_out_id_t *p_video_es;
+    es_out_id_t *p_audio_es;
+
+    /* DCP object */
+    dcp_t *p_dcp;
+
+    /* current frame number */
+    uint32_t frame_no;
+
+    /* frame rate */
+    unsigned int frame_rate_num;
+    unsigned int frame_rate_denom;
+
+    /* total number of frames */
+    uint32_t frames_total;
+
+    uint8_t i_chans_to_reorder;            /* do we need channel reordering */
+    uint8_t pi_chan_table[AOUT_CHAN_MAX];
+    uint8_t i_channels;
+
+    mtime_t i_pts;
+
+    demux_sys_t():
+        PictureEssType ( ESS_UNKNOWN ),
+        p_PicMXFReader( NULL ),
+        p_AudioMXFReader( NULL ),
+        p_video_es( NULL ),
+        p_audio_es( NULL ),
+        p_dcp( NULL ),
+        frame_no( 0 ) {};
+
+    ~demux_sys_t()
+    {
+        switch ( PictureEssType )
+        {
+            case ESS_UNKNOWN:
+                break;
+            case ESS_JPEG_2000:
+                delete p_PicMXFReader;
+                break;
+            case ESS_JPEG_2000_S:
+                delete p_PicMXFSReader;
+                break;
+            case ESS_MPEG2_VES:
+                delete p_VideoMXFReader;
+                break;
+            default:
+                break;
+        }
+        delete p_AudioMXFReader;
+        delete p_dcp;
+    }
+};
+
+/*TODO: basic correlation between SMPTE S428-3/S429-2
+ * Real sound is more complex with case of left/right surround, ...
+ * and hearing impaired/Narration channels */
+#define NB_AUDIO_CONFIGS 9
+
+/* 1 channel: mono */
+static const uint32_t i_channels_1[] =
+{ AOUT_CHAN_LEFT, 0 };
+
+/* 2 channels: stereo */
+static const uint32_t i_channels_2[]=
+{ AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, 0 };
+
+/* 4 channels */
+static const uint32_t i_channels_4[] =
+{   AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER,
+    AOUT_CHAN_LFE, 0  };
+
+/* 6 channels: 5.1 */
+static const uint32_t i_channels_6[] =
+{   AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,      AOUT_CHAN_CENTER,
+    AOUT_CHAN_LFE,  AOUT_CHAN_REARLEFT,   AOUT_CHAN_REARRIGHT,
+    0 };
+
+/* 7 channels: 6.1 */
+static const uint32_t i_channels_7[] =
+{   AOUT_CHAN_LEFT,       AOUT_CHAN_RIGHT,    AOUT_CHAN_CENTER,
+    AOUT_CHAN_LFE,        AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
+    AOUT_CHAN_REARCENTER, 0  };
+
+/* 8 channels:  7.1 */
+static const uint32_t i_channels_8[] =
+{   AOUT_CHAN_LEFT,        AOUT_CHAN_RIGHT,      AOUT_CHAN_CENTER,
+    AOUT_CHAN_LFE,         AOUT_CHAN_REARLEFT,   AOUT_CHAN_REARRIGHT,
+    AOUT_CHAN_MIDDLELEFT,  AOUT_CHAN_MIDDLERIGHT, 0 };
+
+/* 9 channels; 8.1 */
+static const uint32_t i_channels_9[] =
+{   AOUT_CHAN_LEFT,        AOUT_CHAN_RIGHT,      AOUT_CHAN_CENTER,
+    AOUT_CHAN_LFE,         AOUT_CHAN_REARLEFT,   AOUT_CHAN_REARRIGHT,
+    AOUT_CHAN_MIDDLELEFT,  AOUT_CHAN_MIDDLERIGHT, AOUT_CHAN_REARCENTER };
+
+static const uint32_t *pi_channels_aout [] =
+{   NULL,
+    i_channels_1,
+    i_channels_2,
+    NULL,
+    i_channels_4,
+    NULL,
+    i_channels_6,
+    i_channels_7,
+    i_channels_8,
+    i_channels_9 };
+
+static const unsigned i_channel_mask[] =
+{    0,
+    AOUT_CHAN_LEFT,
+    AOUT_CHANS_STEREO,
+    0,
+    AOUT_CHANS_3_1,
+    0,
+    AOUT_CHANS_5_1,
+    AOUT_CHANS_6_1_MIDDLE,
+    AOUT_CHANS_7_1,
+    AOUT_CHANS_8_1 };
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+
+static int Demux( demux_t * );
+static int Control( demux_t *, int, va_list );
+
+int dcpInit ( demux_t *p_demux );
+int parseXML ( demux_t * p_demux );
+static inline void fillVideoFmt(
+        video_format_t * fmt, unsigned int width, unsigned int height,
+        unsigned int frame_rate_num, unsigned int frame_rate_denom );
+void CloseDcpAndMxf( demux_t *p_demux );
+
+
+
+/*****************************************************************************
+ * Open: module init function
+ *****************************************************************************/
+static int Open( vlc_object_t *obj )
+{
+    demux_t *p_demux = ( demux_t* ) obj;
+    demux_sys_t *p_sys;
+    es_format_t video_format, audio_format;
+    int retval;
+
+    if( !p_demux->psz_file )
+        return VLC_EGENERIC;
+
+    p_sys = new ( nothrow ) demux_sys_t();
+    if( unlikely( p_sys == NULL ) ) {
+        return VLC_ENOMEM;
+    }
+    p_demux->p_sys = p_sys;
+
+    /* Allocate DCP object */
+    dcp_t *p_dcp = new ( nothrow ) dcp_t;
+    if( unlikely( p_dcp == NULL ) ) {
+        delete  p_sys;
+        return VLC_ENOMEM;
+    }
+    p_sys->p_dcp = p_dcp;
+
+
+    /* handle the DCP directory, saving the paths for audio and video file, returning error if unsuccessful */
+    if( ( retval = dcpInit( p_demux ) ) )
+        goto error;
+
+
+    /* Open video file */
+    EssenceType( p_sys->p_dcp->videofile.c_str(), p_sys->PictureEssType );
+
+    switch( p_sys->PictureEssType )
+    {
+        case ESS_UNKNOWN:
+            msg_Err( p_demux, "The file %s is not a supported AS_DCP essence container", p_sys->p_dcp->videofile.c_str() );
+            retval = VLC_EGENERIC;
+            goto error;
+
+        case ESS_JPEG_2000:
+        case ESS_JPEG_2000_S: {
+            JP2K::PictureDescriptor PicDesc;
+            if (p_sys->PictureEssType == ESS_JPEG_2000_S) {     /* 3D JPEG2000 */
+                JP2K::MXFSReader * p_PicMXFSReader = new ( nothrow ) JP2K::MXFSReader();
+
+                if( !p_PicMXFSReader) {
+                    retval = VLC_ENOMEM;
+                    goto error;
+                }
+                if( !ASDCP_SUCCESS( p_PicMXFSReader->OpenRead( p_sys->p_dcp->videofile.c_str() ) ) ) {
+                    msg_Err( p_demux, "File %s could not be opened with ASDCP", p_sys->p_dcp->videofile.c_str() );
+                    retval = VLC_EGENERIC;
+                    delete p_PicMXFSReader;
+                    goto error;
+                }
+
+                p_PicMXFSReader->FillPictureDescriptor( PicDesc );
+                p_sys->p_PicMXFSReader = p_PicMXFSReader;
+            } else {                                            /* 2D JPEG2000 */
+                JP2K::MXFReader *p_PicMXFReader = new ( nothrow ) JP2K::MXFReader();
+                if( !p_PicMXFReader ) {
+                    retval = VLC_ENOMEM;
+                    goto error;
+                }
+                if( !ASDCP_SUCCESS( p_PicMXFReader->OpenRead( p_sys->p_dcp->videofile.c_str() ) ) ) {
+                    msg_Err( p_demux, "File %s could not be opened with ASDCP",
+                                    p_sys->p_dcp->videofile.c_str() );
+                    retval = VLC_EGENERIC;
+                    delete p_PicMXFReader;
+                    goto error;
+                }
+
+                p_PicMXFReader->FillPictureDescriptor( PicDesc );
+                p_sys->p_PicMXFReader = p_PicMXFReader;
+            }
+            es_format_Init( &video_format, VIDEO_ES, VLC_CODEC_JPEG2000 );
+            fillVideoFmt( &video_format.video, PicDesc.StoredWidth, PicDesc.StoredHeight,
+                            PicDesc.EditRate.Numerator, PicDesc.EditRate.Denominator );
+
+            p_sys->frame_rate_num   = PicDesc.EditRate.Numerator;
+            p_sys->frame_rate_denom = PicDesc.EditRate.Denominator;
+            p_sys->frames_total     = PicDesc.ContainerDuration;
+            break;
+        }
+        case ESS_MPEG2_VES: {
+
+            MPEG2::MXFReader *p_VideoMXFReader = p_sys->p_VideoMXFReader = new ( nothrow ) MPEG2::MXFReader();
+            MPEG2::VideoDescriptor  VideoDesc;
+
+            if( !p_VideoMXFReader ) {
+                retval = VLC_ENOMEM;
+                goto error;
+            }
+
+            if( !ASDCP_SUCCESS( p_VideoMXFReader->OpenRead( p_sys->p_dcp->videofile.c_str() ) ) ) {
+                msg_Err( p_demux, "File %s could not be opened with ASDCP", p_sys->p_dcp->videofile.c_str() );
+                retval = VLC_EGENERIC;
+                goto error;
+            }
+
+            p_VideoMXFReader->FillVideoDescriptor( VideoDesc );
+
+            es_format_Init( &video_format, VIDEO_ES, VLC_CODEC_MPGV );
+            fillVideoFmt( &video_format.video, VideoDesc.StoredWidth, VideoDesc.StoredHeight,
+                          VideoDesc.EditRate.Numerator, VideoDesc.EditRate.Denominator );
+
+            p_sys->frame_rate_num   = VideoDesc.EditRate.Numerator;
+            p_sys->frame_rate_denom = VideoDesc.EditRate.Denominator;
+            p_sys->frames_total     = VideoDesc.ContainerDuration;
+            break;
+        }
+        default:
+            msg_Err( p_demux, "Unrecognized video format" );
+            retval = VLC_EGENERIC;
+            goto error;
+    }
+
+    if ( (p_sys->frame_rate_num == 0) || (p_sys->frame_rate_denom == 0) ) {
+        msg_Err(p_demux, "Invalid frame rate (%i/%i)",
+                p_sys->frame_rate_num, p_sys->frame_rate_denom);
+        retval = VLC_EGENERIC;
+        goto error;
+    }
+
+    if( ( p_sys->p_video_es = es_out_Add( p_demux->out, &video_format ) ) == NULL ) {
+        msg_Err( p_demux, "Failed to add video es" );
+        retval = VLC_EGENERIC;
+        goto error;
+    }
+
+    /* Open audio file */
+    EssenceType_t AudioEssType;
+    EssenceType( p_sys->p_dcp->audiofile.c_str(), AudioEssType );
+    if ( (AudioEssType == ESS_PCM_24b_48k) || (AudioEssType == ESS_PCM_24b_96k) ) {
+        PCM::MXFReader       *p_AudioMXFReader = new ( nothrow ) PCM::MXFReader();
+        PCM::AudioDescriptor AudioDesc;
+
+        if( !p_AudioMXFReader ) {
+            retval = VLC_ENOMEM;
+            goto error;
+        }
+
+        if( !ASDCP_SUCCESS( p_AudioMXFReader->OpenRead( p_sys->p_dcp->audiofile.c_str() ) ) ) {
+            msg_Err( p_demux, "File %s could not be opened with ASDCP",
+                            p_sys->p_dcp->audiofile.c_str() );
+            retval = VLC_EGENERIC;
+            delete p_AudioMXFReader;
+            goto error;
+        }
+
+        p_AudioMXFReader->FillAudioDescriptor( AudioDesc );
+
+        if (AudioDesc.ChannelCount > NB_AUDIO_CONFIGS) {
+            msg_Err(p_demux, " DCP module support not support %i channels",
+                AudioDesc.ChannelCount);
+            delete p_AudioMXFReader;
+        } else {
+            es_format_Init( &audio_format, AUDIO_ES, VLC_CODEC_S24L );
+            if( AudioDesc.AudioSamplingRate.Denominator != 0 )
+                audio_format.audio.i_rate =
+                    AudioDesc.AudioSamplingRate.Numerator
+                    / AudioDesc.AudioSamplingRate.Denominator;
+            else if ( AudioEssType == ESS_PCM_24b_96k )
+                audio_format.audio.i_rate = 96000;
+            else
+                audio_format.audio.i_rate = 48000;
+
+            p_sys->i_audio_buffer = PCM::CalcFrameBufferSize(AudioDesc);
+            if (p_sys->i_audio_buffer == 0) {
+                msg_Err( p_demux, "Failed to get audio buffer size" );
+                retval = VLC_EGENERIC;
+                delete p_AudioMXFReader;
+                goto error;
+            }
+
+            audio_format.audio.i_bitspersample = AudioDesc.QuantizationBits;
+            audio_format.audio.i_blockalign    = AudioDesc.BlockAlign;
+            audio_format.audio.i_channels      =
+            p_sys->i_channels                  = AudioDesc.ChannelCount;
+
+            /* Manage channel orders */
+            p_sys->i_chans_to_reorder =  aout_CheckChannelReorder(
+                    pi_channels_aout[ AudioDesc.ChannelCount], NULL,
+                    i_channel_mask[AudioDesc.ChannelCount],
+                    p_sys->pi_chan_table );
+
+            if( ( p_sys->p_audio_es = es_out_Add( p_demux->out, &audio_format ) ) == NULL ) {
+                msg_Err( p_demux, "Failed to add audio es" );
+                retval = VLC_EGENERIC;
+                delete p_AudioMXFReader;
+                goto error;
+            }
+            p_sys->p_AudioMXFReader = p_AudioMXFReader;
+        }
+    } else {
+        msg_Err( p_demux, "The file %s is not a supported AS_DCP essence container",
+                p_sys->p_dcp->audiofile.c_str() );
+        retval = VLC_EGENERIC;
+        goto error;
+    }
+    p_demux->pf_demux = Demux;
+    p_demux->pf_control = Control;
+
+    return VLC_SUCCESS;
+error:
+    CloseDcpAndMxf( p_demux );
+    return retval;
+}
+
+
+/*****************************************************************************
+ * Close: module destroy function
+ *****************************************************************************/
+static inline void Close( vlc_object_t *obj )
+{
+    demux_t *p_demux = ( demux_t* ) obj;
+    CloseDcpAndMxf( p_demux );
+}
+
+
+
+/*****************************************************************************
+ * Demux: DCP Demuxing function
+ *****************************************************************************/
+static int Demux( demux_t *p_demux )
+{
+    demux_sys_t *p_sys = p_demux->p_sys;
+    block_t *p_video_frame = NULL, *p_audio_frame = NULL;
+    uint32_t i = p_sys->frame_no;
+    PCM::FrameBuffer   AudioFrameBuff( p_sys->i_audio_buffer);
+
+    if( i == p_sys->frames_total )
+        return 0;
+
+    /* video frame */
+    switch( p_sys->PictureEssType )
+    {
+        case ESS_JPEG_2000:
+        case ESS_JPEG_2000_S:{
+            JP2K::FrameBuffer  PicFrameBuff(FRAME_BUFFER_SIZE);
+            if ( ( p_video_frame = block_Alloc( FRAME_BUFFER_SIZE )) == NULL )
+                goto error;
+
+            if ( ! ASDCP_SUCCESS(
+                    PicFrameBuff.SetData(p_video_frame->p_buffer, FRAME_BUFFER_SIZE)) )
+                goto error_asdcp;
+            if ( p_sys->PictureEssType == ESS_JPEG_2000_S ) {
+                if ( ! ASDCP_SUCCESS(
+                        p_sys->p_PicMXFSReader->ReadFrame(i + p_sys->p_dcp->i_video_entry, JP2K::SP_LEFT, PicFrameBuff, 0, 0)) ) {
+                    PicFrameBuff.SetData(0,0);
+                    goto error_asdcp;
+                }
+             } else {
+                if ( ! ASDCP_SUCCESS(
+                        p_sys->p_PicMXFReader->ReadFrame(i + p_sys->p_dcp->i_video_entry, PicFrameBuff, 0, 0)) ) {
+                    PicFrameBuff.SetData(0,0);
+                    goto error_asdcp;
+                }
+            }
+            p_video_frame->i_buffer = PicFrameBuff.Size();
+            break;
+        }
+        case ESS_MPEG2_VES: {
+            MPEG2::FrameBuffer VideoFrameBuff(FRAME_BUFFER_SIZE);
+            if ( ( p_video_frame = block_Alloc( FRAME_BUFFER_SIZE )) == NULL )
+                goto error;
+
+            if ( ! ASDCP_SUCCESS(
+                    VideoFrameBuff.SetData(p_video_frame->p_buffer, FRAME_BUFFER_SIZE)) )
+                goto error_asdcp;
+
+            if ( ! ASDCP_SUCCESS(
+                    p_sys->p_VideoMXFReader->ReadFrame(i + p_sys->p_dcp->i_video_entry, VideoFrameBuff, 0, 0)) ) {
+                VideoFrameBuff.SetData(0,0);
+                goto error_asdcp;
+            }
+
+            p_video_frame->i_buffer = VideoFrameBuff.Size();
+            break;
+        }
+        default:
+            msg_Err( p_demux, "Unrecognized video format" );
+            goto error;
+    }
+
+    p_video_frame->i_length = CLOCK_FREQ * p_sys->frame_rate_denom / p_sys->frame_rate_num;
+    p_video_frame->i_pts = CLOCK_FREQ * p_sys->frame_no * p_sys->frame_rate_denom / p_sys->frame_rate_num;
+
+    /* audio frame */
+    if ( ( p_audio_frame = block_Alloc( p_sys->i_audio_buffer )) == NULL ) {
+        goto error;
+    }
+    if ( ! ASDCP_SUCCESS(
+            AudioFrameBuff.SetData(p_audio_frame->p_buffer, p_sys->i_audio_buffer)) ) {
+        goto error_asdcp;
+    }
+
+    if ( ! ASDCP_SUCCESS(
+            p_sys->p_AudioMXFReader->ReadFrame(i + p_sys->p_dcp->i_audio_entry, AudioFrameBuff, 0, 0)) ) {
+        AudioFrameBuff.SetData(0,0);
+        goto error_asdcp;
+    }
+
+    if( p_sys->i_chans_to_reorder )
+        aout_ChannelReorder( p_audio_frame->p_buffer, p_audio_frame->i_buffer,
+                p_sys->i_channels,
+                p_sys->pi_chan_table, VLC_CODEC_S24L );
+
+    p_audio_frame->i_buffer = AudioFrameBuff.Size();
+    p_audio_frame->i_length = CLOCK_FREQ * p_sys->frame_rate_denom / p_sys->frame_rate_num;
+    p_audio_frame->i_pts = CLOCK_FREQ * p_sys->frame_no * p_sys->frame_rate_denom / p_sys->frame_rate_num;
+    /* Video is the main pts */
+    if ( p_audio_frame->i_pts != p_video_frame->i_pts ) {
+        msg_Err( p_demux, "Audio and video frame pts are not in sync" );
+    }
+
+    p_sys->i_pts = p_video_frame->i_pts;
+    es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pts );
+    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 );
+
+    p_sys->frame_no++;
+
+    return 1;
+
+error_asdcp:
+    msg_Err( p_demux, "Couldn't read frame with ASDCP");
+error:
+    if (p_video_frame)
+        block_Release(p_video_frame);
+    if (p_audio_frame)
+        block_Release(p_audio_frame);
+    return -1;
+}
+
+/*****************************************************************************
+ * Control: handle the controls
+ *****************************************************************************/
+static int Control( demux_t *p_demux, int query, va_list args )
+{
+    double f,*pf;
+    bool *pb;
+    int64_t *pi64, i64;
+    demux_sys_t *p_sys = p_demux->p_sys;
+
+    switch ( query )
+    {
+        case DEMUX_CAN_PAUSE:
+        case DEMUX_CAN_CONTROL_PACE:
+            pb = ( bool* ) va_arg ( args, bool* );
+            *pb = true;
+            break;
+
+        case DEMUX_CAN_SEEK:
+            pb = (bool *)va_arg( args, bool * );
+            if( p_sys->PictureEssType != ESS_MPEG2_VES )
+                *pb = true;
+            else
+                *pb = false;
+            break;
+
+        case DEMUX_GET_POSITION:
+            pf = ( double* ) va_arg ( args, double* ); *pf = 0.0;
+            if( p_sys->frames_total != 0 )
+                *pf = (double) p_sys->frame_no / (double) p_sys->frames_total;
+            else {
+                msg_Warn( p_demux, "Total number of frames is 0" );
+                *pf = 0.0;
+            }
+            break;
+
+        case DEMUX_SET_POSITION:
+            f = ( double ) va_arg ( args, double );
+            p_sys->frame_no = (int) ( f * p_sys->frames_total );
+            break;
+
+        case DEMUX_GET_LENGTH:
+            pi64 = ( int64_t* ) va_arg ( args, int64_t* );
+            *pi64 =  ( p_sys->frames_total * p_sys->frame_rate_denom / p_sys->frame_rate_num ) * CLOCK_FREQ;
+            break;
+
+        case DEMUX_GET_TIME:
+            pi64 = ( int64_t* ) va_arg ( args, int64_t* );
+            *pi64 = p_sys->i_pts >= 0 ? p_sys->i_pts : 0;
+            break;
+
+        case DEMUX_SET_TIME:
+            i64 = ( int64_t ) va_arg ( args, int64_t );
+            msg_Warn( p_demux, "DEMUX_SET_TIME"  );
+            p_sys->frame_no = i64 * p_sys->frame_rate_num / ( CLOCK_FREQ * p_sys->frame_rate_denom );
+            p_sys->i_pts= i64;
+            es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pts);
+            es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, ( mtime_t ) i64 );
+            break;
+        default:
+            msg_Warn( p_demux, "Unknown query %d in DCP Control", query );
+            return VLC_EGENERIC;
+    }
+
+    return VLC_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * Low-level functions : string manipulation, free function, etc
+ *****************************************************************************/
+/**
+ * Function to fill video_format_t fields for an elementary stream
+ * @param fmt video format structure
+ * @param width picture width
+ * @param height picture height
+ * @param frame_rate_num video frame rate numerator
+ * @param frame_rate_denom video frame rate denominator
+ */
+static inline void fillVideoFmt( video_format_t * fmt, unsigned int width, unsigned int height, unsigned int frame_rate_num, unsigned int frame_rate_denom )
+{
+    fmt->i_width = width;
+    fmt->i_height = height;
+    /* As input are square pixels let VLC  or decoder fix SAR, origin,
+     * and visible area */
+    fmt->i_frame_rate = frame_rate_num;
+    fmt->i_frame_rate_base = frame_rate_denom;
+}
+
+/**
+ * Function to free memory in case of error or when closing the module
+ * @param p_demux DCP access-demux
+ */
+void CloseDcpAndMxf( demux_t *p_demux )
+{
+    demux_sys_t *p_sys = p_demux->p_sys;
+    /* close the files */
+    switch( p_sys->PictureEssType )
+    {
+        case ESS_UNKNOWN:
+            break;
+        case ESS_JPEG_2000:
+            if( p_sys->p_PicMXFReader )
+                p_sys->p_PicMXFReader->Close();
+            break;
+        case ESS_JPEG_2000_S:
+            if( p_sys->p_PicMXFSReader )
+                p_sys->p_PicMXFSReader->Close();
+            break;
+        case ESS_MPEG2_VES:
+            if( p_sys->p_VideoMXFReader )
+                p_sys->p_VideoMXFReader->Close();
+            break;
+        default:
+            break;
+    }
+    if( p_sys->p_AudioMXFReader )
+        p_sys->p_AudioMXFReader->Close();
+
+    delete( p_demux->p_sys );
+}
+
+
+/*****************************************************************************
+ * DCP init
+ *****************************************************************************/
+
+/**
+ * Function to handle the operations with the DCP directory.
+ * @param p_demux Demux pointer.
+ * @return Integer according to the success or not of the process.
+ */
+int dcpInit ( demux_t *p_demux )
+{
+    int retval;
+
+    demux_sys_t *p_sys = p_demux->p_sys;
+    dcp_t *p_dcp = p_sys->p_dcp;
+
+    p_dcp->path = p_demux->psz_file;
+    /* Add a '/' in end of path if needed */
+    if ( *(p_dcp->path).rbegin() != '/')
+        p_dcp->path.append( "/" );
+
+    /* Parsing XML files to get audio and video files */
+    msg_Dbg( p_demux, "parsing XML files..." );
+    if( ( retval = parseXML( p_demux ) ) )
+        return retval;
+
+    msg_Dbg(p_demux, "parsing XML files done");
+
+#ifndef NDEBUG
+    msg_Dbg( p_demux, "path = %s", p_sys->p_dcp->path.c_str() );
+    msg_Dbg( p_demux, "video = %s", p_sys->p_dcp->videofile.c_str() );
+    msg_Dbg( p_demux, "audio = %s", p_sys->p_dcp->audiofile.c_str() );
+#endif
+
+    return VLC_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * functions for XML parsing
+ *****************************************************************************/
+
+/**
+ * Function to retrieve the path to the ASSETMAP file.
+ * @param p_demux DCP access_demux.
+ */
+static string assetmapPath( demux_t * p_demux )
+{
+    DIR *dir = NULL;
+    struct dirent *ent = NULL;
+    dcp_t *p_dcp = p_demux->p_sys->p_dcp;
+    string result;
+
+    if( ( dir = opendir (p_dcp->path.c_str() ) ) != NULL )
+    {
+        /* print all the files and directories within directory */
+        while( ( ent = readdir ( dir ) ) != NULL )
+        {
+            if( strcasecmp( "assetmap", ent->d_name ) == 0 || strcasecmp( "assetmap.xml", ent->d_name ) == 0 )
+            {
+                /* copy of "path" in "res" */
+                result = p_dcp->path;
+                result.append( ent->d_name );
+                break;
+            }
+        }
+        closedir( dir );
+    }
+    else
+        msg_Err( p_demux, "Could not open the directory: %s", p_dcp->path.c_str() );
+
+    /* if no assetmap file */
+    if( result.empty() )
+        msg_Err( p_demux, "No ASSETMAP found in the directory: %s", p_dcp->path.c_str() );
+
+    return result;
+}
+
+
+/**
+ * Function which parses XML files in DCP directory in order to get video and audio files
+ * @param p_demux Demux pointer.
+ * @return Integer according to the success or not of the operation
+ */
+int parseXML ( demux_t * p_demux )
+{
+    int retval;
+
+    string assetmap_path = assetmapPath( p_demux );
+    /* We get the ASSETMAP file path */
+    if( assetmap_path.empty() )
+        return VLC_EGENERIC;
+
+    /* We parse the ASSETMAP File in order to get CPL File path, PKL File path
+     and to store UID/Path of all files in DCP directory (except ASSETMAP file) */
+    AssetMap *assetmap = new (nothrow) AssetMap( p_demux, assetmap_path, p_demux->p_sys->p_dcp );
+    if( ( retval = assetmap->Parse() ) )
+        return retval;
+
+    delete assetmap;
+    return VLC_SUCCESS; /* TODO : perform checking on XML parsing */
+}
diff --git a/modules/access/dcp/dcpparser.cpp b/modules/access/dcp/dcpparser.cpp
new file mode 100644
index 0000000..86e65ed
--- /dev/null
+++ b/modules/access/dcp/dcpparser.cpp
@@ -0,0 +1,1356 @@
+/*****************************************************************************
+ * Copyright (C) 2013 VLC authors and VideoLAN
+ *
+ * Authors:
+ *          Nicolas Bertrand <nico at isf.cc>
+ *          Jean-Baptiste Kempf <jb at videolan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/**
+ * @file dcpparser.cpp
+ * @brief Parsing of DCP XML files
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* VLC core API headers */
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_xml.h>
+#include <vlc_url.h>
+
+#include <iostream>
+#include <string>
+#include <list>
+#include <vector>
+
+#include "dcpparser.h"
+
+using namespace std;
+
+static int ReadNextNode(xml_reader_t *p_xmlReader, string& p_node) {
+    const char * c_node;
+    int i;
+    i = xml_ReaderNextNode( p_xmlReader, &c_node );
+    p_node = c_node;
+    return i;
+}
+
+static int ReadEndNode( xml_reader_t *p_xmlReader, string p_node,
+                        int p_type, string &s_value) {
+    string node;
+
+    if ( xml_ReaderIsEmptyElement( p_xmlReader) )
+            return 0;
+
+    if (p_type != XML_READER_STARTELEM)
+        return -1;
+
+    if (ReadNextNode(p_xmlReader, node) == XML_READER_TEXT)
+    {
+        s_value = node;
+        if((ReadNextNode(p_xmlReader, node) == XML_READER_ENDELEM) &&
+                node == p_node)
+            return 0;
+    }
+    return -1;
+}
+
+typedef enum {
+    CHUNK_UNKNOWN = 0,
+    CHUNK_PATH,
+    CHUNK_VOL_INDEX,
+    CHUNK_OFFSET,
+    CHUNK_LENGTH
+} ChunkTag_t;
+
+
+typedef enum {
+    ASSET_UNKNOWN = 0,
+    ASSET_ID,
+    ASSET_ANNOTATION_TEXT,
+    ASSET_PACKING_LIST,
+    ASSET_CHUNK_LIST,
+    ASSET_HASH,
+    ASSET_SIZE,
+    ASSET_TYPE,
+    ASSET_ORIGINAL_FILENAME
+} AssetTag_t;
+
+static const string g_asset_names[] = {
+        "Id",
+        "AnnotationText",
+        "PackingList",
+        "ChunkList",
+        "Hash",
+        "Size",
+        "Type",
+        "OriginalFileName"
+    };
+
+
+typedef enum {
+    PKL_UNKNOWN = 0,
+    PKL_ID,
+    PKL_ISSUE_DATE,
+    PKL_ISSUER,
+    PKL_CREATOR,
+    PKL_ASSET_LIST,
+    PKL_ANNOTATION_TEXT, /* start of optional tags */
+    PKL_ICON_ID,
+    PKL_GROUP_ID,
+    PKL_SIGNER,
+    PKL_SIGNATURE,
+} PKLTag_t;
+
+typedef enum {
+    CPL_UNKNOWN = 0,
+    CPL_ID,
+    CPL_ANNOTATION_TEXT,        /* optional */
+    CPL_ICON_ID,                /* optional */
+    CPL_ISSUE_DATE,
+    CPL_ISSUER,                 /* optional */
+    CPL_CREATOR,                /* optional */
+    CPL_CONTENT_TITLE,
+    CPL_CONTENT_KIND,
+    CPL_CONTENT_VERSION,        /* not optional, but not always present*/
+    CPL_RATING_LIST,            /* not handled */
+    CPL_REEL_LIST,
+    CPL_SIGNER,                 /* optional - not handled */
+    CPL_SIGNATURE               /* optional - not handled */
+} CPLTag_t;
+
+
+class ChunkList: public std::list<Chunk> {
+public :
+    ChunkList();
+    ~ChunkList();
+};
+
+/*
+ * Chunk Class
+ */
+int Chunk::Parse( xml_reader_t *p_xmlReader, string p_node, int p_type){
+    string node;
+    int type;
+    string s_value;
+    static const string names[] = {"Path", "VolumeIndex", "Offset",
+                               "Length"};
+    if (p_type != XML_READER_STARTELEM)
+        return -1;
+    if( p_node != "Chunk")
+        return -1;
+    /* loop on Chunks Node */
+    while( ( type = ReadNextNode( p_xmlReader, node ) ) > 0 ) {
+        switch (type) {
+            case XML_READER_STARTELEM:
+            {
+                ChunkTag_t chunk_tag = CHUNK_UNKNOWN;
+                for(ChunkTag_t i = CHUNK_PATH; i <= CHUNK_LENGTH; i = ChunkTag_t(i+1)) {
+                    if( node == names[i-1]) {
+                        chunk_tag = i;
+                        if ( ReadEndNode(p_xmlReader, node, type, s_value))
+                            return -1;
+                        switch (chunk_tag) {
+                            case CHUNK_PATH:
+                                this->s_path = s_value;
+                                break;
+                            case CHUNK_VOL_INDEX:
+                                this->i_vol_index = atoi(s_value.c_str());
+                                break;
+                            case CHUNK_OFFSET:
+                                this->i_offset = atoi(s_value.c_str());
+                                break;
+                            case CHUNK_LENGTH:
+                                this->i_length = atoi(s_value.c_str());
+                                break;
+                            case CHUNK_UNKNOWN:
+                            default:
+                                break;
+                        }
+                        /* break the for loop as a tag is found*/
+                        break;
+                    }
+                }
+                if(chunk_tag == CHUNK_UNKNOWN)
+                    return -1;
+                break;
+            }
+            case XML_READER_TEXT:
+                s_value = node;
+                if (unlikely(node.empty()))
+                    return -1;
+                break;
+            case XML_READER_ENDELEM:
+                /* Verify if we reach Chuk endelem  */
+                if ( node == p_node) {
+                    /* verify path */
+                    if ( this->s_path.empty() ) {
+                        msg_Err(this->p_demux, "Chunk::Parse No path found");
+                        return -1;
+                    }
+                    if ( this->i_vol_index != 1 ) {
+                        msg_Err(this->p_demux, "Only one VOLINDEX suported. Patch welcome.");
+                        return -1;
+                    }
+                    /* end of chunk tag parse */
+                    return 0;
+                }
+                break;
+        }
+    }
+    return -1;
+}
+/*
+ * AssetMap Class
+ */
+
+AssetMap::~AssetMap() { }
+
+int AssetMap::Parse ( )
+{
+    int type = 0;
+    string node;
+
+    CPL  *cpl;
+    Reel *reel;
+    PKL  *pkl;
+    AssetList *_p_asset_list = NULL;
+
+    vector<string> pklfiles;
+
+    /* init XML parser */
+    if( this->OpenXml() ) {
+        msg_Err( p_demux, "Failed to initialize Assetmap XML parser" );
+        return -1;
+    }
+
+    /* reading ASSETMAP file to get the asset_list */
+    msg_Dbg( p_demux, "reading ASSETMAP file..." );
+    while( ( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) {
+        if ( (type == XML_READER_STARTELEM) && ( node =="AssetList")) {
+            _p_asset_list =  new (nothrow) AssetList();
+            if ( unlikely(_p_asset_list == NULL) ) {
+                this->CloseXml();
+                return -1;
+            }
+            p_dcp->p_asset_list = _p_asset_list;
+            if (this->ParseAssetList(p_xmlReader, node, type )) {
+                this->CloseXml();
+                return -1;
+            }
+        }
+    }
+
+
+    /* Look for PKLs path */
+    if ( (_p_asset_list == NULL) ||  (_p_asset_list->size() == 0) ) {
+        msg_Err( p_demux, "Asset list empty" );
+        this->CloseXml();
+        return -1;
+    }
+
+    for (AssetList::iterator iter = _p_asset_list->begin();
+            iter != _p_asset_list->end() ; ++iter) {
+        string s_filepath;
+        s_filepath = (*iter)->getPath();
+        if (s_filepath.empty()) {
+            msg_Err( p_demux, "No path element for asset" );
+            continue;
+        }
+        /* set an absolute file path */
+        s_filepath = p_dcp->path + s_filepath;
+
+        /* case of packing list */
+        if ((*iter)->isPackingList()) {
+            pklfiles.push_back( s_filepath );
+        }
+    }
+
+    /* TODO: case of only on PKL managed.
+     * Future work needed for managing severals
+     * the PKL vector will be used to select the required PKL  */
+    if( (pklfiles.size() == 0)  || (pklfiles[0].empty()) )
+    {
+        msg_Err( p_demux, "Could not find PKL file in ASSETMAP" );
+        this->CloseXml();
+        return -1;
+    }
+
+    /* Create the first PKL */
+    pkl = new (nothrow) PKL(p_demux, pklfiles[0], _p_asset_list, p_dcp->path);
+    if ( unlikely(pkl == NULL) ) {
+        this->CloseXml();
+        return -1;
+        }
+    if (pkl->Parse()) {
+        delete pkl;
+        this->CloseXml();
+        return -1;
+        }
+    p_dcp->pkls.push_back( pkl );
+
+    /* Now, CPL */
+    if ( pkl->FindCPLs() <= 0 ) {
+        msg_Err(p_demux, " No CPL found");
+        this->CloseXml();
+        return -1;
+    }
+    /* TODO: Only one CPL managed.
+     * Future work needed for managing severals
+     */
+
+    cpl = pkl->getCPL(0);
+    if( cpl == NULL ) {
+        msg_Err(p_demux, " No CPL found");
+        this->CloseXml();
+        return -1;
+    }
+    if ( cpl->Parse() ) {
+        this->CloseXml();
+        return -1;
+    }
+    /*TODO : case of 1st reel only managed */
+    reel = cpl->getReel(0);
+
+    Asset *asset;
+    /* Get picture */
+    asset = reel->getTrack(TRACK_PICTURE);
+    msg_Dbg( this->p_demux, "Video Track: %s",asset->getPath().c_str());
+    msg_Dbg( this->p_demux, "Entry point: %i",asset->getEntryPoint());
+    p_dcp->videofile = p_dcp->path + asset->getPath();
+    p_dcp->i_video_entry = asset->getEntryPoint();
+    /* Get audio */
+    asset = reel->getTrack(TRACK_SOUND);
+    msg_Dbg( this->p_demux, "Audio Track: %s",asset->getPath().c_str());
+    msg_Dbg( this->p_demux, "Entry point: %i",asset->getEntryPoint());
+    p_dcp->audiofile = p_dcp->path + asset->getPath();
+    p_dcp->i_audio_entry = asset->getEntryPoint();
+
+    /* free memory */
+    this->CloseXml();
+    return VLC_SUCCESS;
+}
+
+
+
+/*
+ * Asset Class
+ */
+Asset::~Asset() {}
+
+int Asset::Parse( xml_reader_t *p_xmlReader, string p_node, int p_type)
+{
+    string node;
+    int type;
+    string s_value;
+    const string s_root_node = "Asset";
+
+    if (p_type != XML_READER_STARTELEM)
+        return -1;
+    if( p_node != s_root_node)
+        return -1;
+    /* loop on Assets Node */
+    while( ( type = ReadNextNode( p_xmlReader, node ) ) > 0 ) {
+        switch (type) {
+            case XML_READER_STARTELEM:
+                {
+                    AssetTag_t _tag = ASSET_UNKNOWN;
+                    for(AssetTag_t i = ASSET_ID; i <= ASSET_ORIGINAL_FILENAME; i = AssetTag_t(i+1)) {
+                        if( node == g_asset_names[i-1]) {
+                            _tag = i;
+                            switch(_tag) {
+                                /* Case of complex nodes */
+                                case ASSET_PACKING_LIST:
+                                    /* case of <PackinkList/> tag, bur not compliant with SMPTE-429-9 2007*/
+                                    if (xml_ReaderIsEmptyElement( p_xmlReader))
+                                        this->b_is_packing_list = true;
+                                    else if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                        return -1;
+                                    if ( s_value == "true" )
+                                        this->b_is_packing_list = true;
+                                    break;
+                                case ASSET_CHUNK_LIST:
+                                    if ( this->parseChunkList(p_xmlReader, node, type ) )
+                                        return -1;
+                                    this->s_path = this->chunk_vec[0].getPath();
+                                    break;
+                                case ASSET_ID:
+                                    if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                        return -1;
+                                    this->s_id = s_value;
+                                    break;
+                                case ASSET_ANNOTATION_TEXT:
+                                    if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                        return -1;
+                                    this->s_annotation = s_value;
+                                    break;
+                                case ASSET_ORIGINAL_FILENAME:
+                                case ASSET_HASH:
+                                case ASSET_TYPE:
+                                case ASSET_SIZE:
+                                    /* Asset tags not in AssetMap */
+                                    break;
+                            }
+                            /* break the for loop as a tag is found*/
+                            break;
+                        }
+                    }
+                    if( _tag == ASSET_UNKNOWN )
+                        return -1;
+                    break;
+                }
+            case XML_READER_TEXT:
+                return -1;
+            case XML_READER_ENDELEM:
+                if ( node != s_root_node) {
+                    msg_Err(this->p_demux,
+                            "Something goes wrong in Asset parsing on Assetmap (node %s)", node.c_str());
+                    return -1;
+                } else {
+                    /*Check Presence of Id and Chunklist */
+                    if ( this->s_id.empty() ) {
+                        msg_Err(this->p_demux, " No Id element found in Asset");
+                        return -1;
+                    }
+                    if ( this->s_path.empty() ) {
+                        msg_Err(this->p_demux, " No path element found in Asset");
+                        return -1;
+                    }
+                    return 0;
+                }
+                break;
+        }
+    }
+    return -1;
+}
+
+
+
+int Asset::ParsePKL( xml_reader_t *p_xmlReader)
+{
+    string node;
+    int type;
+    string s_value;
+    const string s_root_node = "Asset";
+
+    while( ( type = ReadNextNode( p_xmlReader, node ) ) > 0 ) {
+        switch (type) {
+            case XML_READER_STARTELEM:
+                {
+                    AssetTag_t _tag = ASSET_UNKNOWN;
+                    for(AssetTag_t i = ASSET_ID; i <= ASSET_ORIGINAL_FILENAME; i = AssetTag_t(i+1)) {
+                        if( node == g_asset_names[i-1]) {
+                            _tag = i;
+                            switch(_tag) {
+                                case ASSET_ANNOTATION_TEXT:
+                                    if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                        return -1;
+                                    if ( this->s_annotation.empty() )
+                                        this->s_annotation = s_value;
+                                    else
+                                        this->s_annotation = this->s_annotation + "--" + s_value;
+                                    break;
+                                case ASSET_HASH:
+                                    if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                        return -1;
+                                    this->s_hash = s_value;
+                                    break;
+                                case ASSET_SIZE:
+                                    if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                        return -1;
+                                    this->ui_size = atol(s_value.c_str());
+                                    break;
+                                case ASSET_TYPE:
+                                    if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                        return -1;
+                                    this->s_type = s_value;
+                                    break;
+                                case ASSET_ORIGINAL_FILENAME:
+                                    if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                        return -1;
+                                    this->s_original_filename = s_value;
+                                    break;
+                                case ASSET_ID: /* already verified */
+                                case ASSET_PACKING_LIST:
+                                case ASSET_CHUNK_LIST:
+                                    /* Asset tags not in PKL */
+                                    break;
+                            }
+                            /* break the for loop as a tag is found*/
+                            break;
+                        }
+                    }
+                    if( _tag == ASSET_UNKNOWN )
+                        return -1;
+                break;
+            }
+            case XML_READER_TEXT:
+                return -1;
+            case XML_READER_ENDELEM:
+                if ( node != s_root_node) {
+                    msg_Err(this->p_demux,
+                            "Something goes wrong in Asset parsing on PKL (node %s)", node.c_str());
+                    return -1;
+                } else {
+                    /* Verify that mandatory attributes are filled */
+                    if (this->s_hash.empty()) {
+                        msg_Err(this->p_demux,"Asset Hash tag invalid");
+                        return -1;
+                    }
+                    if (this->ui_size == 0) {
+                        msg_Err(this->p_demux,"Asset Size tag invalid");
+                        return -1;
+                    }
+                    if (this->s_type.empty()) {
+                        msg_Err(this->p_demux,"Asset Type tag invalid");
+                        return -1;
+                    }
+                    return 0;
+                }
+                break;
+        }
+
+    }
+
+    return -1;
+}
+
+void Asset::Dump()
+{
+    msg_Dbg(this->p_demux,"Id              = %s", this->s_id.c_str());
+    msg_Dbg(this->p_demux,"Path            = %s", this->s_path.c_str());
+    msg_Dbg(this->p_demux,"Is PKL          = %s", this->b_is_packing_list ? "True" : "False");
+    msg_Dbg(this->p_demux,"Hash            = %s", this->s_hash.c_str());
+    msg_Dbg(this->p_demux,"Size            = %i", this->ui_size);
+    msg_Dbg(this->p_demux,"Type            = %s", this->s_type.c_str());
+    msg_Dbg(this->p_demux,"OrignalFileName = %s", this->s_original_filename.c_str());
+    msg_Dbg(this->p_demux,"AnnotationText  = %s", this->s_annotation.c_str());
+}
+
+int Asset::parseChunkList( xml_reader_t *p_xmlReader, string p_node, int p_type)
+{
+    string node;
+    int type;
+    string s_value;
+    std::vector<Chunk> chunk_vec;
+
+    if (p_type != XML_READER_STARTELEM)
+        return -1;
+    if( p_node != "ChunkList" )
+        return -1;
+    /* loop on Assets Node */
+    while( ( type = ReadNextNode( p_xmlReader, node ) ) > 0 ) {
+         switch (type) {
+            case XML_READER_STARTELEM:
+                {
+                    Chunk chunk(this->p_demux);
+                    if (node != "Chunk" )
+                        return -1;
+                    if ( chunk.Parse(p_xmlReader, node, type) )
+                        return -1;
+                    chunk_vec.push_back(chunk);
+                    break;
+                }
+            case XML_READER_ENDELEM:
+                if ( node == p_node) {
+                    if (chunk_vec.size() != 1 ) {
+                        msg_Err(this->p_demux, "chunklist of size greater than one not supported");
+                        return -1;
+                        }
+                    this->chunk_vec = chunk_vec;
+                    return 0;
+                }
+                break;
+        }
+    }
+    return -1;
+}
+
+int AssetMap::ParseAssetList (xml_reader_t *p_xmlReader, const string p_node, int p_type)
+{
+    string node;
+    int type;
+    Asset *asset;
+
+    if (p_type != XML_READER_STARTELEM)
+        return -1;
+    if( p_node != "AssetList" )
+        return -1;
+    /* loop on AssetList nodes */
+    while( ( type = ReadNextNode( p_xmlReader, node ) ) > 0 ) {
+        switch (type) {
+            case XML_READER_STARTELEM:
+                if (node != "Asset" )
+                    return -1;
+                asset = new (nothrow) Asset(this->p_demux);
+                if ( unlikely(asset == NULL) )
+                    return -1;
+                if (asset->Parse(p_xmlReader, node, type)){
+                    delete asset;
+                    return -1;
+                }
+                p_dcp->p_asset_list->push_back(asset);
+                break;
+
+            case XML_READER_ENDELEM:
+                if (node == p_node )
+                    return 0;
+                break;
+            default:
+            case XML_READER_TEXT:
+                msg_Err(this->p_demux, "Error parsing AssetList in AssetMap");
+                return -1;
+        }
+    }
+    return -1;
+}
+
+Asset * AssetMap::getAssetById(AssetList *asset_list, const string p_id)
+{
+    AssetList::iterator index = asset_list->begin() ;
+    for (index = asset_list->begin(); index != asset_list->end(); ++index)
+        if ((*index)->getId() == p_id )
+            return *index;
+    return NULL;
+}
+
+/*
+ * XmlFile Class
+ */
+XmlFile::~XmlFile() {}
+
+int XmlFile::OpenXml()
+{
+    char *psz_uri;
+
+    this->p_xml = xml_Create( this->p_demux );
+    if (! this->p_xml) {
+        return -1;
+    }
+    psz_uri = vlc_path2uri( this->s_path.c_str(), "file" );
+    this->p_stream = stream_UrlNew(this->p_demux, psz_uri );
+    free(psz_uri);
+    if( ! this->p_stream ) {
+        xml_Delete(this->p_xml );
+        return -1;
+    }
+
+    this->p_xmlReader = xml_ReaderCreate( this->p_xml, this->p_stream);
+    if( ! this->p_xmlReader ) {
+        stream_Delete( this->p_stream );
+        xml_Delete(this->p_xml );
+        return -1;
+    }
+    return 0;
+}
+
+void XmlFile::CloseXml() {
+    if( this->p_stream )
+        stream_Delete( this->p_stream );
+    if( this->p_xmlReader )
+        xml_ReaderDelete( this->p_xmlReader );
+    if( this->p_xml )
+        xml_Delete( this->p_xml );
+
+}
+
+/*
+ * PKL Class
+ */
+
+PKL::PKL(demux_t * p_demux, string s_path, AssetList *_asset_list, string s):
+    XmlFile(p_demux, s_path),
+    asset_list(_asset_list), s_dcp_path(s)
+{
+    type = XML_PKL;
+}
+
+PKL::~PKL() {
+    vlc_delete_all(vec_cpl);
+}
+
+int PKL::Parse()
+{
+    string node;
+    int type;
+    string s_value;
+    const string s_root_node = "PackingList";
+
+    static const string names[] = {
+        "Id",
+        "IssueDate",
+        "Issuer",
+        "Creator",
+        "AssetList",
+        "AnnotationText",
+        "IconId",
+        "GroupId",
+        "Signer",
+        "ds:Signature"
+    };
+
+    if (this->OpenXml())
+        return -1;
+
+    /* read 1st node  and verify that is a PKL*/
+    if (! ( ( XML_READER_STARTELEM == ReadNextNode(this->p_xmlReader, node) ) &&
+                (node == s_root_node) ) ) {
+        msg_Err( this->p_demux, "Not a valid XML Packing List");
+        goto error;
+    }
+    while( ( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) {
+        switch (type) {
+            case XML_READER_STARTELEM: {
+                PKLTag_t _tag = PKL_UNKNOWN;
+                for(PKLTag_t i = PKL_ID; i <= PKL_SIGNATURE; i = PKLTag_t(i+1)) {
+                    if( node == names[i-1]) {
+                        _tag = i;
+                        switch (_tag) {
+                            /* case for parsing non terminal nodes */
+                            case PKL_ASSET_LIST:
+                                if ( this->ParseAssetList(node, type) )
+                                    goto error;
+                                break;
+                            case PKL_SIGNER:
+                                if ( this->ParseSigner(node, type) )
+                                    goto error;
+                                break;
+                            case PKL_SIGNATURE:
+                                if ( this->ParseSignature(node, type) )
+                                    goto error;
+                                break;
+                            /* Parse simple/end nodes */
+                            case PKL_ID:
+                                if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                    goto error;
+                                this->s_id = s_value;
+                                break;
+                            case PKL_ISSUE_DATE:
+                                if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                    goto error;
+                                this->s_issue_date = s_value;
+                                break;
+                            case PKL_ISSUER:
+                                if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                    goto error;
+                                this->s_issuer = s_value;
+                                break;
+                            case PKL_CREATOR:
+                                if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                    goto error;
+                                this->s_creator = s_value;
+                                break;
+                            case PKL_ANNOTATION_TEXT:
+                                if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                    goto error;
+                                this->s_annotation = s_value;
+                                break;
+                            case PKL_ICON_ID:
+                                if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                    goto error;
+                                this->s_icon_id = s_value;
+                                break;
+                            case PKL_GROUP_ID:
+                                if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                    goto error;
+                                this->s_group_id = s_value;
+                                break;
+                        }
+                        /* break the for loop as a tag is found*/
+                        break;
+                    }
+                }
+                if( _tag == PKL_UNKNOWN )
+                    goto error;
+                break;
+            }
+            case XML_READER_TEXT:
+                goto error;
+            case XML_READER_ENDELEM:
+                if ( node != s_root_node) {
+                    msg_Err(this->p_demux,
+                        "Something goes wrong in PKL parsing (node %s)", node.c_str());
+                    goto error;
+                }
+                break;
+        }
+    }
+    /* TODO verify presence of mandatory fields*/
+
+    /* Close PKL XML*/
+    this->CloseXml();
+    return 0;
+error:
+    msg_Err( this->p_demux, "PKL parsing failed");
+    this->CloseXml();
+    return -1;
+}
+
+int PKL::FindCPLs()
+{
+    if ( this->vec_cpl.size() != 0 ) {
+        msg_Err(this->p_demux, "CPLs already checked");
+        return -1;
+    }
+
+    for (AssetList::iterator index = this->asset_list->begin();
+            index != this->asset_list->end(); ++index) {
+        Asset *asset = *index;
+        if ( asset->getType().find("text/xml") == string::npos) {
+            /* not an xml file */
+            continue;
+        }
+
+        CPL *cpl = new (nothrow) CPL(this->p_demux,
+                      this->s_dcp_path + asset->getPath(),
+                      this->asset_list);
+        if ( unlikely(cpl == NULL) )
+                    return -1;
+        if ( cpl->IsCPL() )
+            /* CPL Found */
+            this->vec_cpl.push_back(cpl);
+        else
+            delete cpl;
+    }
+    return this->vec_cpl.size();
+}
+
+
+int PKL::ParseAssetList(string p_node, int p_type) {
+    string node;
+    int type;
+
+    if (p_type != XML_READER_STARTELEM)
+        return -1;
+    if( p_node != "AssetList")
+        return -1;
+    while( ( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) {
+        switch (type) {
+            case XML_READER_STARTELEM:
+                if( node =="Asset") {
+                    if ( this->ParseAsset(node, type) )
+                        return -1;
+                } else
+                    return -1;
+                break;
+            case XML_READER_ENDELEM:
+                if ( node == p_node) {
+                    /* parse of chunklist finished */
+                    goto end;
+                }
+                break;
+            }
+    }
+end:
+    return 0;
+}
+
+int PKL::ParseAsset(string p_node, int p_type) {
+    string node;
+    int type;
+    string s_value;
+    Asset *asset = NULL;
+
+    if (p_type != XML_READER_STARTELEM)
+        return -1;
+    if( p_node != "Asset")
+        return -1;
+
+    /* 1st node shall be Id" */
+    if (( type = ReadNextNode( this->p_xmlReader, node ) ) > 0)
+        if ( ! ((type == XML_READER_STARTELEM) && (node == "Id")))
+            return -1;
+    if (( type = ReadNextNode( this->p_xmlReader, node ) ) > 0)
+         if (type == XML_READER_TEXT) {
+            s_value = node;
+            if (unlikely(node.empty()))
+                return -1;
+            }
+    if (( type = ReadNextNode( this->p_xmlReader, node ) ) > 0)
+        if (type == XML_READER_ENDELEM) {
+            asset = AssetMap::getAssetById(this->asset_list, s_value);
+            if (asset  == NULL)
+                return -1;
+        }
+     if (asset == NULL)
+        return -1;
+     if ( asset->ParsePKL(this->p_xmlReader) )
+        return -1;
+    return 0;
+}
+
+int PKL::ParseSigner(string p_node, int p_type)
+{
+    string node;
+    int type;
+
+    if (p_type != XML_READER_STARTELEM)
+        return -1;
+    if( p_node != "Signer")
+        return -1;
+
+    while( ( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) {
+        /* TODO not implemented. Just parse until end of Signer node */
+            if ((node == p_node) && (type = XML_READER_ENDELEM))
+                return 0;
+    }
+
+    msg_Err(this->p_demux, "Parse of Signer finished bad");
+    return -1;
+}
+
+int PKL::ParseSignature(string p_node, int p_type)
+{
+    string node;
+    int type;
+
+    if (p_type != XML_READER_STARTELEM)
+        return -1;
+    if( p_node != "ds:Signature")
+        return -1;
+
+    while (( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) {
+        /* TODO not implemented. Just parse until end of Signature node */
+            if ((node == p_node) && (type = XML_READER_ENDELEM))
+                return 0;
+    }
+    msg_Err(this->p_demux, "Parse of Signature finished bad");
+    return -1;
+}
+
+/*
+ * Reel Class
+ */
+int Reel::Parse(string p_node, int p_type) {
+    string node;
+    int type;
+    string s_value;
+
+    if (p_type != XML_READER_STARTELEM)
+        return -1;
+    if( p_node != "Reel")
+        return -1;
+
+    while (( type = ReadNextNode(this->p_xmlReader, node ) ) > 0 ) {
+        switch (type) {
+            case XML_READER_STARTELEM:
+                if (node =="Id") {
+                    if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
+                        return -1;
+                    this->s_id = s_value;
+                } else if (node == "AnnotationText") {
+                    if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
+                        return -1;
+                    this->s_annotation = s_value;
+                } else if ( node =="AssetList" ) {
+                    if (this->ParseAssetList(node, type))
+                        return -1;
+                } else {
+                    /* unknown tag */
+                    msg_Err(this->p_demux, "Reel::Parse, unknown tag:%s", node.c_str());
+                    return -1;
+                }
+                break;
+            case XML_READER_TEXT:
+                /* Error */
+                msg_Err(this->p_demux, "Reel parsing error");
+                return -1;
+            case XML_READER_ENDELEM:
+                /* verify correctness of end node */
+                if ( node == p_node) {
+                    /* TODO : verify Reel id */
+                    return 0;
+                }
+        }
+    }
+    return -1;
+}
+
+
+Asset * Reel::getTrack(TrackType_t e_track)
+{
+    switch (e_track) {
+        case TRACK_PICTURE:
+            return this->p_picture_track;
+        case TRACK_SOUND:
+            return this->p_sound_track;
+        case TRACK_SUBTITLE:
+            return this->p_subtitle_track;
+        case TRACK_UNKNOWN:
+        default:
+            break;
+    }
+    return NULL;
+}
+
+int Reel::ParseAssetList(string p_node, int p_type) {
+    string node;
+    int type;
+    string s_value;
+
+    if (p_type != XML_READER_STARTELEM)
+        return -1;
+    if( p_node != "AssetList")
+        return -1;
+
+    while (( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 )  {
+        switch (type) {
+            case XML_READER_STARTELEM:
+                if (node =="MainPicture") {
+                    if ( this->ParseAsset(node, type, TRACK_PICTURE) )
+                        return -1;
+                } else if (node =="MainSound") {
+                    if ( this->ParseAsset(node, type, TRACK_SOUND) )
+                        return -1;
+                } else if (node =="MainSubtitle") {
+                    if ( this->ParseAsset(node, type, TRACK_SUBTITLE) )
+                        return -1;
+                } else {
+                    /* unknown tag */
+                    msg_Err(this->p_demux, "Reel::ParseAssetList, unknown tag:%s", node.c_str());
+                    return -1;
+                }
+                break;
+            case XML_READER_TEXT:
+                /* Parsing error */
+                msg_Err(this->p_demux, "AssetList parsing error");
+                return -1;
+            case XML_READER_ENDELEM:
+                /* verify correctness of end node */
+                if ( node == p_node) {
+                    /* TODO : verify id */
+                    return 0;
+                }
+        }
+    }
+    return -1;
+}
+
+int Reel::ParseAsset(string p_node, int p_type, TrackType_t e_track) {
+    string node;
+    int type;
+    string s_value;
+    bool b_stop_parse = false;
+    Asset *asset = NULL;
+
+    if (p_type != XML_READER_STARTELEM)
+        return -1;
+
+    /* 1st node shall be Id */
+    if (( type = ReadNextNode( this->p_xmlReader, node ) ) > 0)
+        if ( ! ((type == XML_READER_STARTELEM) && (node == "Id")))
+            return -1;
+
+    if ( ReadEndNode(this->p_xmlReader, node, type, s_value) )
+        return -1;
+
+    asset = AssetMap::getAssetById(this->p_asset_list, s_value);
+    if (asset  == NULL)
+        return -1;
+
+    while(  (! b_stop_parse) &&
+            (( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) ) {
+        switch (type) {
+            case XML_READER_STARTELEM:
+                if (node =="EditRate") {
+                    if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
+                        return -1;
+                } else if (node == "AnnotationText") {
+                    if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
+                        return -1;
+                        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()));
+                } else if (node == "EntryPoint") {
+                    if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
+                        return -1;
+                        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()));
+                } else if (node == "KeyId") {
+                    if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
+                        return -1;
+                } else if (node == "Hash") {
+                    if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
+                        return -1;
+                } else if (node == "FrameRate") {
+                    if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
+                        return -1;
+                } else if (node == "ScreenAspectRatio") {
+                    if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
+                        return -1;
+                } else if (node == "Language") {
+                    if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
+                        return -1;
+                } else {
+                    /* unknown tag */
+                    msg_Err(this->p_demux, "Reel::ParseAsset unknown tag:%s", node.c_str());
+                    return -1;
+                }
+                break;
+            case XML_READER_TEXT:
+                /* impossible */
+                return -1;
+                break;
+            case XML_READER_ENDELEM:
+                /* verify correctness of end node */
+                if ( node == p_node) {
+                    /* TODO : verify id */
+                    b_stop_parse = true;
+                }
+        }
+    }
+    /* store by track */
+    switch (e_track) {
+        case TRACK_PICTURE:
+            this->p_picture_track = asset;
+            break;
+        case TRACK_SOUND:
+            this->p_sound_track = asset;
+            break;
+        case TRACK_SUBTITLE:
+            this->p_subtitle_track = asset;
+            break;
+        case TRACK_UNKNOWN:
+        default:
+            break;
+    }
+    return 0;
+}
+
+/*
+ * CPL Class
+ */
+
+CPL::CPL(demux_t * p_demux, string s_path, AssetList *_asset_list)
+    : XmlFile(p_demux, s_path), asset_list( _asset_list)
+{
+    string node;
+    int type;
+
+    this->type = XML_UNKNOWN;
+
+    if (this->OpenXml()) {
+        msg_Err(this->p_demux, "Failed to open CPL XML file");
+        return;
+        }
+
+    /* read 1st node  and verify that is a CPL */
+    if ( (type = ReadNextNode(p_xmlReader, node)) > 0) {
+        if ( (type == XML_READER_STARTELEM) && (node == "CompositionPlaylist") ) {
+            this->type = XML_CPL;
+        }
+    }
+    /* close xml */
+    this->CloseXml();
+};
+
+CPL::~CPL() {
+    vlc_delete_all(vec_reel);
+}
+
+int CPL::Parse()
+{
+    string node;
+    int type;
+    string s_value;
+    const string s_root_node = "CompositionPlaylist";
+
+    static const string names[] = {
+        "Id",
+        "AnnotationText",
+        "IconId",
+        "IssueDate",
+        "Issuer",
+        "Creator",
+        "ContentTitleText",
+        "ContentKind",
+        "ContentVersion",
+        "RatingList",
+        "ReelList",
+        "Signer",
+        "ds:Signature"
+    };
+
+    if (this->OpenXml())
+        return -1;
+
+    /* read 1st node  and verify that is a CPL*/
+    if (! ( ( XML_READER_STARTELEM == ReadNextNode(this->p_xmlReader, node) ) &&
+                (node == s_root_node) ) ) {
+        msg_Err( this->p_demux, "Not a valid XML Packing List");
+        goto error;
+    }
+
+    while( ( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) {
+        switch (type) {
+            case XML_READER_STARTELEM: {
+                CPLTag_t _tag = CPL_UNKNOWN;
+                for(CPLTag_t i = CPL_ID; i <= CPL_SIGNATURE; i = CPLTag_t(i+1)) {
+                    if( node == names[i-1]) {
+                        _tag = i;
+                        switch (_tag) {
+                            /* case for parsing non terminal nodes */
+                            case CPL_REEL_LIST:
+                                if ( this->ParseReelList(node, type) )
+                                    goto error;
+                                break;
+                            case CPL_CONTENT_VERSION:
+                            case CPL_SIGNER:
+                            case CPL_SIGNATURE:
+                            case CPL_RATING_LIST:
+                                if ( this->DummyParse(node,type) )
+                                    goto error;
+                                break;
+                                /* Parse simple/end nodes */
+                            case CPL_ID:
+                                if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                    goto error;
+                                this->s_id = s_value;
+                                break;
+                            case CPL_ANNOTATION_TEXT:
+                                if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                    goto error;
+                                this->s_annotation = s_value;
+                                break;
+                            case CPL_ICON_ID:
+                                if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                    goto error;
+                                this->s_icon_id = s_value;
+                                break;
+                            case CPL_ISSUE_DATE:
+                                if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                    goto error;
+                                this->s_issue_date= s_value;
+                                break;
+                            case CPL_ISSUER:
+                                if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                    goto error;
+                                this->s_issuer = s_value;
+                                break;
+                            case CPL_CREATOR:
+                                if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                    goto error;
+                                this->s_creator = s_value;
+                                break;
+                            case CPL_CONTENT_TITLE:
+                                if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                    goto error;
+                                this->s_content_title = s_value;
+                                break;
+                            case CPL_CONTENT_KIND:
+                                if ( ReadEndNode(p_xmlReader, node, type, s_value) )
+                                    goto error;
+                                this->s_content_kind = s_value;
+                                break;
+                        }
+
+                        /* break the for loop as a tag is found*/
+                        break;
+                    }
+                }
+                if( _tag == CPL_UNKNOWN )
+                    goto error;
+                break;
+            }
+            case XML_READER_TEXT:
+               goto error;
+            case XML_READER_ENDELEM:
+               if ( node != s_root_node) {
+                   msg_Err(this->p_demux,
+                           "Something goes wrong in CKL parsing (node %s)", node.c_str());
+                   goto error;
+               }
+               break;
+        }
+    }
+
+    /* TODO verify presence of mandatory fields*/
+
+    /* Close CPL XML*/
+    this->CloseXml();
+    return 0;
+error:
+    this->CloseXml();
+    return -1;
+}
+
+int CPL::ParseReelList(string p_node, int p_type) {
+    string node;
+    int type;
+
+    if (p_type != XML_READER_STARTELEM)
+        return -1;
+    if( p_node != "ReelList")
+        return -1;
+    while( ( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) {
+        switch (type) {
+            case XML_READER_STARTELEM: {
+                Reel *p_reel = new (nothrow) Reel( this->p_demux, this->asset_list, this->p_xmlReader);
+                if ( unlikely(p_reel == NULL) )
+                    return -1;
+                if( node =="Reel") {
+                    if ( p_reel->Parse(node, type) ) {
+                        delete p_reel;
+                        return -1;
+                    }
+                } else {
+                    delete p_reel;
+                    return -1;
+                }
+                this->vec_reel.push_back(p_reel);
+
+                break;
+            }
+            case XML_READER_TEXT:
+                /* impossible */
+                break;
+            case XML_READER_ENDELEM:
+                if ( node == p_node)
+                    return 0;
+                break;
+            }
+    }
+    return -1;
+}
+
+
+int CPL::DummyParse(string p_node, int p_type)
+{
+    string node;
+    int type;
+
+    if (p_type != XML_READER_STARTELEM)
+        return -1;
+
+    if (xml_ReaderIsEmptyElement( this->p_xmlReader))
+        return 0;
+
+    while (( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) {
+        /* TODO not implemented. Just pase until end of input node */
+        if ((node == p_node) && (type = XML_READER_ENDELEM))
+            return 0;
+    }
+
+    return -1;
+}
diff --git a/modules/access/dcp/dcpparser.h b/modules/access/dcp/dcpparser.h
new file mode 100644
index 0000000..9384d75
--- /dev/null
+++ b/modules/access/dcp/dcpparser.h
@@ -0,0 +1,299 @@
+/*****************************************************************************
+ * Copyright (C) 2013 VLC authors and VideoLAN
+ *
+ * Authors: Nicolas Bertrand <nico at isf.cc>
+ *          Jean-Baptiste Kempf <jb at videolan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/**
+ * @file dcpparser.h
+ * @brief Parse DCP XML files
+ */
+
+
+#ifndef _DCPPARSER_H
+#define _DCPPARSER_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* VLC core API headers */
+#include <vlc_common.h>
+#include <vlc_demux.h>
+#include <vlc_plugin.h>
+
+#include <iostream>
+#include <string>
+#include <list>
+#include <vector>
+
+using namespace std;
+typedef enum {
+    TRACK_UNKNOWN = 0,
+    TRACK_PICTURE,
+    TRACK_SOUND,
+    TRACK_SUBTITLE
+} TrackType_t;
+
+typedef enum {
+    XML_UNKNOWN = 0,
+    XML_ASSETMAP,
+    XML_CPL,
+    XML_PKL,
+    XML_SUB,
+} XmlType_t;
+
+
+class Asset;
+class AssetList: public std::list<Asset *> {};
+class PKL;
+
+/* This struct stores the most important information about the DCP */
+struct dcp_t
+{
+    string path;                    /* Path to DCP directory */
+
+    vector<PKL *> pkls;
+    AssetList *p_asset_list;
+
+    string videofile;               /* Picture file name */
+    string audiofile;               /* Sound file name */
+
+    int i_video_entry;              /* Picture entry point */
+    int i_audio_entry;              /* Sound entry point */
+
+
+    ~dcp_t( ) {
+        vlc_delete_all(pkls);
+        vlc_delete_all(*p_asset_list);
+        delete(p_asset_list);
+    }
+};
+
+
+class XmlFile
+{
+public:
+    XmlFile( demux_t * p_demux, string s_path):
+    p_demux(p_demux), s_path(s_path),
+    p_stream(NULL),
+    p_xml(NULL),
+    p_xmlReader(NULL),
+    type(XML_UNKNOWN) {}
+
+    virtual ~XmlFile( );
+
+    virtual int Parse() = 0;
+
+    bool IsCPL() { return type == XML_CPL; }
+protected:
+    demux_t      *p_demux;
+    string       s_path;
+    stream_t     *p_stream;
+
+    xml_t        *p_xml;
+    xml_reader_t *p_xmlReader;
+
+    int OpenXml();
+    void CloseXml();
+
+    XmlType_t type;
+};
+
+class Chunk {
+public:
+    Chunk(demux_t * demux):
+        i_vol_index(1), i_offset(0), i_length(0),
+        p_demux(demux) {};
+    int Parse(xml_reader_t *p_xmlReader, string p_node, int p_type);
+    string getPath() { return this->s_path; };
+private:
+    string s_path;
+    int i_vol_index;
+    int i_offset;
+    int i_length;
+    demux_t      *p_demux;
+};
+
+class Asset {
+public:
+    /* Constructor */
+    Asset (demux_t * demux):
+        b_is_packing_list(false),  ui_size(0),
+        i_intrisic_duration(0), i_entry_point(0), i_duration(0),
+        p_demux(demux) {}
+    virtual ~Asset() ;
+
+    void setId(string p_string ) { this->s_id = p_string; };
+    void setPath(string p_string) { this->s_path = p_string; };
+    void setAnnotation(string p_string) {
+        if (this->s_annotation.empty())
+            this->s_annotation = p_string;
+        else
+            this->s_annotation = this->s_annotation + "--" + p_string;
+    };
+    void setPackingList(bool p_bool) { this->s_path = p_bool; };
+    void setEntryPoint(int i_val) { this->i_entry_point = i_val; };
+    void setDuration (int i_val) { this->i_duration = i_val; };
+    void setIntrinsicDuration (int i_val) { this->i_intrisic_duration = i_val; };
+    string getId() const { return this->s_id; } ;
+    string getPath() const { return this->s_path; };
+    string getType() const { return this->s_type; };
+    int getEntryPoint() const { return this->i_entry_point; };
+    int getDuration() const { return this->i_duration; };
+    int getIntrinsicDuration() const { return this->i_intrisic_duration; };
+
+    bool isPackingList() const { return this->b_is_packing_list; };
+
+    int Parse( xml_reader_t *p_xmlReader, string node, int type);
+    int ParsePKL( xml_reader_t *p_xmlReader);
+
+    // TODO: remove
+    void Dump();
+
+private:
+    string      s_id;
+    string      s_path;
+    string      s_annotation;
+    bool        b_is_packing_list;
+    string      s_hash;
+    uint32_t    ui_size;
+    string      s_type;
+    string      s_original_filename;
+    TrackType_t e_track_type;
+    string      s_edit_rate;
+    int         i_intrisic_duration;
+    int         i_entry_point;
+    int         i_duration;
+    /* encryption attribute */
+    string      s_key_id;
+    /* Picture attributes */
+    string      s_frame_rate;
+    string      s_screen_aspect_ratio;
+    /* sound and subtitle */
+    string      s_language;
+
+    demux_t     *p_demux;
+    std::vector<Chunk> chunk_vec;
+
+
+    int parseChunkList( xml_reader_t *p_xmlReader, string p_node, int p_type);
+
+};
+
+
+
+class Reel
+{
+public:
+    Reel(demux_t * demux, AssetList *asset_list, xml_reader_t *xmlReader)
+        : p_asset_list(asset_list), p_xmlReader(xmlReader), p_demux(demux)
+         {};
+    int Parse(string p_node, int p_type);
+    Asset * getTrack(TrackType_t e_track);
+
+private:
+    AssetList *p_asset_list;
+    xml_reader_t *p_xmlReader;
+    demux_t      *p_demux;
+
+    string s_id;
+    string s_annotation;
+    Asset  *p_picture_track;
+    Asset  *p_sound_track;
+    Asset  *p_subtitle_track;
+
+    int ParseAssetList(string p_node, int p_type);
+    int ParseAsset(string p_node, int p_type, TrackType_t e_track);
+};
+
+class CPL : public XmlFile
+{
+public:
+    CPL(demux_t *, string, AssetList*);
+    ~CPL();
+    virtual int Parse();
+
+    Reel *getReel(int pos) { return this->vec_reel[pos]; } ;
+
+private :
+    AssetList *asset_list;
+
+    string s_id;
+    string s_annotation;
+    string s_icon_id;
+    string s_issue_date;
+    string s_issuer;
+    string s_creator;
+    string s_content_title;
+    string s_content_kind;
+    /* TODO:  ContentVersion, RatingList, signer and signature */
+
+    std::vector<Reel *>   vec_reel;
+    int DummyParse(string p_node, int p_type);
+    int ParseReelList(string p_node, int p_type);
+};
+
+
+class PKL : public XmlFile
+{
+public:
+    PKL ( demux_t * p_demux, string s_path, AssetList *asset_list,
+         string s_dcp_path);
+    ~PKL();
+    virtual int Parse();
+
+    int FindCPLs();
+    CPL *getCPL(int pos) { return this->vec_cpl[pos]; };
+
+private:
+    AssetList *asset_list;
+
+    string s_id;
+    string s_annotation;
+    string s_issue_date;
+    string s_issuer;
+    string s_creator;
+    string s_icon_id;
+    string s_group_id;
+    string s_dcp_path;
+    std::vector<CPL *> vec_cpl;
+
+    int ParseAssetList(string p_node, int p_type);
+    int ParseAsset(string p_node, int p_type);
+    int ParseSigner(string p_node, int p_type);
+    int ParseSignature(string p_node, int p_type);
+
+};
+
+class AssetMap : public XmlFile {
+
+public:
+    AssetMap( demux_t * p_demux, string s_path, dcp_t *_p_dcp)
+        : XmlFile( p_demux, s_path ), p_dcp( _p_dcp) {};
+    ~AssetMap();
+
+    static Asset * getAssetById(AssetList*, const string p_id);
+
+    virtual int Parse();
+private:
+    dcp_t *p_dcp;
+
+    int ParseAssetList (xml_reader_t *p_xmlReader, const string p_node, int p_type);
+};
+#endif /* _DCPPARSER_H */
-- 
1.7.9.5




More information about the vlc-devel mailing list