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

Denis Charmet typx at dinauz.org
Thu Dec 5 15:33:34 CET 2013


Hi,

Ready for v12? :)

Le mardi 03 décembre 2013 à 05:37:59, Nicolas Bertrand a écrit :
> +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_t *p_out;
Why keeping it if you never use it?
> +    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;
> +
> +    mtime_t i_pts;
> +
> +    demux_sys_t():
> +        PictureEssType ( ESS_UNKNOWN ),
> +        p_PicMXFReader( NULL ),
> +        p_AudioMXFReader( NULL ),
> +        p_out( 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;
> +    }
> +};
> +
> +/*****************************************************************************
> + * 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 );
> +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 * p_PicDesc = new ( nothrow ) JP2K::PictureDescriptor();
I'd let the descriptors on the stack. Except if they are too big.
> +            if ( !p_PicDesc ) {
> +                retval = VLC_ENOMEM;
> +                goto error;
> +            }
> +            if (p_sys->PictureEssType == ESS_JPEG_2000_S) {     /* 3D JPEG2000 */
> +                JP2K::MXFSReader * p_PicMXFSReader = new ( nothrow ) JP2K::MXFSReader();
> +
> +                if( !p_PicMXFSReader) {
> +                    retval = VLC_ENOMEM;
> +                    delete p_PicDesc;
> +                    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_PicDesc;
> +                    delete p_PicMXFSReader;
> +                    goto error;
> +                }
> +
> +                p_PicMXFSReader->FillPictureDescriptor( *p_PicDesc );
> +                p_sys->p_PicMXFSReader = p_PicMXFSReader;
> +            } else {                                            /* 2D JPEG2000 */
> +                JP2K::MXFReader *p_PicMXFReader = new ( nothrow ) JP2K::MXFReader();
> +                if( !p_PicMXFReader ) {
> +                    retval = VLC_ENOMEM;
> +                    delete p_PicDesc;
> +                    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_PicDesc;
> +                    delete p_PicMXFReader;
> +                    goto error;
> +                }
> +
> +                p_PicMXFReader->FillPictureDescriptor( *p_PicDesc );
> +                p_sys->p_PicMXFReader = p_PicMXFReader;
> +            }
> +            es_format_Init( &video_format, VIDEO_ES, VLC_CODEC_JPEG2000 );
> +            fillVideoFmt( &video_format.video, p_PicDesc->StoredWidth, p_PicDesc->StoredHeight, p_PicDesc->EditRate.Numerator, p_PicDesc->EditRate.Denominator );
> +
> +            p_sys->frame_rate_num = p_PicDesc->EditRate.Numerator;
> +            p_sys->frame_rate_denom = p_PicDesc->EditRate.Denominator;
> +            p_sys->frames_total = p_PicDesc->ContainerDuration;
> +            delete p_PicDesc;
> +            break;
> +        }
> +        case ESS_MPEG2_VES: {
> +
> +            MPEG2::MXFReader *p_VideoMXFReader = p_sys->p_VideoMXFReader = new ( nothrow ) MPEG2::MXFReader();
> +            MPEG2::VideoDescriptor  *p_VideoDesc = new ( nothrow ) MPEG2::VideoDescriptor();
> +
> +            if( !p_VideoMXFReader || !p_VideoDesc ) {
> +                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( *p_VideoDesc );
> +
> +            es_format_Init( &video_format, VIDEO_ES, VLC_CODEC_MPGV );
> +            fillVideoFmt( &video_format.video, p_VideoDesc->StoredWidth, p_VideoDesc->StoredHeight, p_VideoDesc->EditRate.Numerator, p_VideoDesc->EditRate.Denominator );
> +
> +            p_sys->frame_rate_num = p_VideoDesc->EditRate.Numerator;
> +            p_sys->frame_rate_denom = p_VideoDesc->EditRate.Denominator;
> +            p_sys->frames_total = p_VideoDesc->ContainerDuration;
> +            delete p_VideoDesc;
> +            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 *p_AudioDesc      = new ( nothrow ) PCM::AudioDescriptor();
> +
> +        if( !p_AudioMXFReader ) {
> +            retval = VLC_ENOMEM;
> +            goto error;
> +        }
> +
> +        if( !p_AudioDesc ) {
> +            retval = VLC_ENOMEM;
> +            delete p_AudioMXFReader;
> +            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_AudioDesc;
> +            delete p_AudioMXFReader;
> +            goto error;
> +        }
> +
> +        p_AudioMXFReader->FillAudioDescriptor( *p_AudioDesc );
> +
> +        es_format_Init( &audio_format, AUDIO_ES, VLC_CODEC_S24L );
> +        if( p_AudioDesc->AudioSamplingRate.Denominator != 0 )
> +            audio_format.audio.i_rate =
> +                  p_AudioDesc->AudioSamplingRate.Numerator
> +                / p_AudioDesc->AudioSamplingRate.Denominator;
> +        else if ( AudioEssType == ESS_PCM_24b_96k )
> +            audio_format.audio.i_rate = 96000;
> +        else
> +            audio_format.audio.i_rate = 48000;
> +
> +        audio_format.audio.i_bitspersample = p_AudioDesc->QuantizationBits;
> +        audio_format.audio.i_blockalign    = p_AudioDesc->BlockAlign;
> +        audio_format.audio.i_channels      = p_AudioDesc->ChannelCount;
> +
> +        p_sys->i_audio_buffer = PCM::CalcFrameBufferSize(*p_AudioDesc);
Maybe check if it's not null.
> +
> +        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_AudioDesc;
> +            delete p_AudioMXFReader;
> +            goto error;
> +        }
> +        p_sys->p_AudioMXFReader = p_AudioMXFReader;
> +        delete p_AudioDesc;
> +    } 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_sys->p_out = p_demux->out;
> +    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;
> +    }
> +
> +    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
Missing brackets
> +                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
> + */
> +void fillVideoFmt( video_format_t * fmt, unsigned int width, unsigned int height, unsigned int frame_rate_num, unsigned int frame_rate_denom )
I'd static inline that function
> +{
> +    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 AssetMap( p_demux, assetmap_path, p_demux->p_sys->p_dcp );
nothrow or try/catch
> +    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..7cecef6
> --- /dev/null
> +++ b/modules/access/dcp/dcpparser.cpp
> @@ -0,0 +1,1330 @@
> +/*****************************************************************************
> + * 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 (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;
> +                        }
> +                    }
> +                }
> +                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 if you found an element.
> +                        }
> +                    }
> +                    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;
> +                        }
> +                    }
> +                    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)
why not type(XML_PKL)?
> +{
> +    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;
> +                    }
> +                }
> +                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;
return 0;
> +                }
> +                break;
> +            }
> +    }
> +end:
> +    return 0;
Same remark than the last time. Is it normal to return 0 here?
> +}
> +
> +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 =="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::Parse, 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") {
No string trick loop here?
> +                    if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
> +                        return -1;
> +                } 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::Parse, 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;
> +
> +    if (this->OpenXml())
> +        return;
I don't like functions that can fail in constructors since you have no
way to know that it failed. At least please default this->type to
XML_UNKNOWN.
> +
> +    /* 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;
> +                        }
> +                    }
> +                }
> +                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..b0c4732
> --- /dev/null
> +++ b/modules/access/dcp/dcpparser.h
> @@ -0,0 +1,293 @@
> +/*****************************************************************************
> + * 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 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 */

Regards,

-- 
Denis Charmet - TypX
Le mauvais esprit est un art de vivre



More information about the vlc-devel mailing list