[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