[vlc-devel] [RFC] dcp.cpp: Creation of access-demux module for DCP (using asdcplib)
Denis Charmet
typx at dinauz.org
Mon Jun 3 12:10:54 CEST 2013
Hi,
tldr;
Beware of "new" throwing exceptions.
Check returns
Don't leak :)
beware of division by 0
Le lundi 03 juin 2013 à 11:01:12, Simona-Marinela Prodea a écrit :
> The module only handles audio and video files in DCP, no subtitles yet. Is this form worthy of a patch?
>
> ---
> +++ b/modules/access/dcp.cpp
> [...]
> +
> +struct demux_sys_t
> +{
> + /* ASDCP Picture Essence Type */
> + EssenceType_t VideoEssType;
> +
> + /* ASDCP Video MXF Reader for JPEG2000 essence type */
> + JP2K::MXFReader *p_PicMXFReader;
> +
> + /* ASDCP Video MXF Reader for JPEG2000 stereoscopic essence type */
> + JP2K::MXFSReader *p_PicMXFSReader;
> +
> + /* ASDCP Video MXF Reader for MPEG2 essence type */
> + MPEG2::MXFReader *p_VideoMXFReader;
This should be an union if they all has the same goal and are not
present simultaneously.
> +
> + /* ASDCP Picture Descriptor ( for JPEG2000 and JPEG2000 stereoscopic )*/
> + JP2K::PictureDescriptor *p_PicDesc;
> +
> + /* ASDCP Video Descriptor ( for MPEG2 ) */
> + MPEG2::VideoDescriptor *p_VideoDesc;
> +
Same.
> + /* ASDCP Audio MXF Reader */
> + PCM::MXFReader *p_AudioMXFReader;
> +
> + /* ASDCP Audio Descriptor */
> + PCM::AudioDescriptor *p_AudioDesc;
> +
> + /* elementary streams */
> + es_out_id_t *p_video_es;
> + es_out_id_t *p_audio_es;
This assume that you only have one audio track
> +
> + /* DCP object */
> + dcp_t *p_dcp;
> +
> + /* current frame number */
> + uint32_t frame_no;
> +
> + /* frame rate */
> + double frame_rate;
> +
> + /* total number of frames */
> + uint32_t frames_total;
> +
> + demux_sys_t()
> + {
> + p_PicMXFReader = NULL;
> + p_PicMXFSReader = NULL;
> + p_PicDesc = NULL;
> + p_VideoMXFReader = NULL;
> + p_VideoDesc = NULL;
> + p_AudioMXFReader = NULL;
> + p_AudioDesc = NULL;
> + p_dcp = NULL;
> + }
Nitpicking: why not demux_sys_t(): p_PicMXFReader(NULL)...
> + ~demux_sys_t()
> + {
> + delete p_PicMXFReader;
> + delete p_PicMXFSReader;
> + delete p_PicDesc;
> + delete p_VideoMXFReader;
> + delete p_VideoDesc;
> + delete p_AudioMXFReader;
> + delete p_AudioDesc;
> + delete p_dcp;
> + }
> +};
> +
> +static int Demux( demux_t * );
> +static int Control( demux_t *, int, va_list );
> +
> +int dcpInit ( demux_t *p_demux );
> +int parserXML ( demux_t * p_demux );
> +void assetmapUri( demux_t * p_demux );
> +void parserAssetmapXML ( demux_t * p_demux );
> +void parserCplXML ( demux_t * p_demux );
> +int endsWith( const char * str, const char * suffix );
> +
> +static int Open( vlc_object_t *obj )
> +{
> + demux_t *p_demux = ( demux_t* ) obj;
> + demux_sys_t *p_sys = p_demux->p_sys = new demux_sys_t();
> + es_format_t video_format, audio_format;
> + vlc_fourcc_t fcc;
> +
> + msg_Dbg( p_demux, "Opening DCP access-demux module" );
> +
> + if( !p_demux->psz_file )
> + return VLC_EGENERIC;
> +
leaks p_sys
> + /* handle the DCP directory, saving the paths for audio and video file */
> + dcpInit( p_demux );
Maybe you should check the result.
> + p_sys = p_demux->p_sys;
leaks the p_sys you allocated in dcpInit
> +
> + /***************************************************
> + ***************** open video file *****************
> + ***************************************************/
> + msg_Dbg( p_demux, "Video file is : %s", p_sys->p_dcp->videofile );
> + EssenceType( p_sys->p_dcp->videofile, p_sys->VideoEssType );
> +
> + switch( p_sys->VideoEssType )
> + {
> + case ESS_UNKNOWN:
> + msg_Err( p_demux, "The file %s is not a supported AS_DCP essence container. DCP cannot be read.");
leaks
> + return VLC_EGENERIC;
> + case ESS_JPEG_2000:
> + {
> + fcc = VLC_FOURCC( 'J', 'P', '2', 'K' );
> + JP2K::MXFReader *p_PicMXFReader = p_sys->p_PicMXFReader = new JP2K::MXFReader();
> + JP2K::PictureDescriptor *p_PicDesc = p_sys->p_PicDesc = new JP2K::PictureDescriptor();
> +
> + Result_t result = p_PicMXFReader->OpenRead( p_sys->p_dcp->videofile );
> + if( ASDCP_SUCCESS( result ) )
> + msg_Dbg( p_demux, "File %s was successfully opened with asdcp", p_sys->p_dcp->videofile );
> + else
> + {
> + msg_Err( p_demux, "File %s could not be opened with asdcp!", p_sys->p_dcp->videofile );
> + return VLC_EGENERIC;
leaks
> + }
> +
> + p_PicMXFReader->FillPictureDescriptor( *p_PicDesc );
> +
> + msg_Dbg( p_demux, "PictureDescriptor: " );
> + msg_Dbg( p_demux, " EditRate: %d:%d", p_PicDesc->EditRate.Numerator, p_PicDesc->EditRate.Denominator );
> + msg_Dbg( p_demux, " ContainerDuration: %d", p_PicDesc->ContainerDuration );
> + msg_Dbg( p_demux, " SampleRate: %d:%d", p_PicDesc->SampleRate.Numerator, p_PicDesc->SampleRate.Denominator );
> + msg_Dbg( p_demux, " StoredWidth: %d", p_PicDesc->StoredWidth );
> + msg_Dbg( p_demux, " StoredHeight: %d", p_PicDesc->StoredHeight );
> + msg_Dbg( p_demux, " Rsize: %d", p_PicDesc->Rsize );
> + msg_Dbg( p_demux, " Xsize: %d", p_PicDesc->Xsize );
> + msg_Dbg( p_demux, " Ysize: %d", p_PicDesc->Ysize );
> + msg_Dbg( p_demux, " XOsize: %d", p_PicDesc->XOsize );
> + msg_Dbg( p_demux, " YOsize: %d", p_PicDesc->YOsize );
> + msg_Dbg( p_demux, " XTsize: %d", p_PicDesc->XTsize );
> + msg_Dbg( p_demux, " YTsize: %d", p_PicDesc->YTsize );
> + msg_Dbg( p_demux, " XTOsize: %d", p_PicDesc->XTOsize );
> + msg_Dbg( p_demux, " YTOsize: %d", p_PicDesc->YTOsize );
> + msg_Dbg( p_demux, " Csize: %d", p_PicDesc->Csize );
> + msg_Dbg( p_demux, " Aspect Ratio: %d:%d", p_PicDesc->AspectRatio.Numerator, p_PicDesc->AspectRatio.Denominator );
> + msg_Dbg( p_demux, " ImageComponents, CodingStyleDefault, QuantizationDefault - to see in asdcplib/src/AS_DCP.h" );
> +
> + p_sys->p_PicMXFReader = p_PicMXFReader;
> + p_sys->p_PicDesc = p_PicDesc;
> + p_sys->frame_no = 0;
> + p_sys->frame_rate = p_PicDesc->EditRate.Numerator / p_PicDesc->EditRate.Denominator;
Maybe check that the denominator isn't 0 before division.
> + p_sys->frames_total = p_PicDesc->ContainerDuration;
> +
> + es_format_Init( &video_format, VIDEO_ES, fcc );
> + video_format.video.i_width = p_PicDesc->StoredWidth;
> + video_format.video.i_height = p_PicDesc->StoredHeight;
> + /* As input are square pixels let VLC or decoder fix SAR, origin,
> + * and visible area */
> + video_format.video.i_frame_rate = p_PicDesc->EditRate.Numerator;
> + video_format.video.i_frame_rate_base = p_PicDesc->EditRate.Denominator;
> + break;
> + }
> + case ESS_JPEG_2000_S:
> + {
> + fcc = VLC_FOURCC( 'J', 'P', '2', 'K' );
> + JP2K::MXFSReader *p_PicMXFSReader = p_sys->p_PicMXFSReader = new JP2K::MXFSReader();
> + JP2K::PictureDescriptor *p_PicDesc = p_sys->p_PicDesc = new JP2K::PictureDescriptor();
> +
> + Result_t result = p_PicMXFSReader->OpenRead( p_sys->p_dcp->videofile );
> + if( ASDCP_SUCCESS( result ) )
> + msg_Dbg( p_demux, "File %s was successfully opened with asdcp", p_sys->p_dcp->videofile );
> + else
> + {
> + msg_Err( p_demux, "File %s could not be opened with asdcp!", p_sys->p_dcp->videofile );
leaks
> + return VLC_EGENERIC;
> + }
> +
> + p_PicMXFSReader->FillPictureDescriptor( *p_PicDesc );
> +
> + msg_Dbg( p_demux, "PictureDescriptor: " );
> + msg_Dbg( p_demux, " EditRate: %d:%d", p_PicDesc->EditRate.Numerator, p_PicDesc->EditRate.Denominator );
> + msg_Dbg( p_demux, " ContainerDuration: %d", p_PicDesc->ContainerDuration );
> + msg_Dbg( p_demux, " SampleRate: %d:%d", p_PicDesc->SampleRate.Numerator, p_PicDesc->SampleRate.Denominator );
> + msg_Dbg( p_demux, " StoredWidth: %d", p_PicDesc->StoredWidth );
> + msg_Dbg( p_demux, " StoredHeight: %d", p_PicDesc->StoredHeight );
> + msg_Dbg( p_demux, " Rsize: %d", p_PicDesc->Rsize );
> + msg_Dbg( p_demux, " Xsize: %d", p_PicDesc->Xsize );
> + msg_Dbg( p_demux, " Ysize: %d", p_PicDesc->Ysize );
> + msg_Dbg( p_demux, " XOsize: %d", p_PicDesc->XOsize );
> + msg_Dbg( p_demux, " YOsize: %d", p_PicDesc->YOsize );
> + msg_Dbg( p_demux, " XTsize: %d", p_PicDesc->XTsize );
> + msg_Dbg( p_demux, " YTsize: %d", p_PicDesc->YTsize );
> + msg_Dbg( p_demux, " XTOsize: %d", p_PicDesc->XTOsize );
> + msg_Dbg( p_demux, " YTOsize: %d", p_PicDesc->YTOsize );
> + msg_Dbg( p_demux, " Csize: %d", p_PicDesc->Csize );
> + msg_Dbg( p_demux, " Aspect Ratio: %d:%d", p_PicDesc->AspectRatio.Numerator, p_PicDesc->AspectRatio.Denominator );
> + msg_Dbg( p_demux, " ImageComponents, CodingStyleDefault, QuantizationDefault - to see in asdcplib/src/AS_DCP.h" );
> +
> + p_sys->p_PicMXFSReader = p_PicMXFSReader;
> + p_sys->p_PicDesc = p_PicDesc;
> + p_sys->frame_no = 0;
> + p_sys->frame_rate = p_PicDesc->EditRate.Numerator / p_PicDesc->EditRate.Denominator;
same than before
> + p_sys->frames_total = p_PicDesc->ContainerDuration;
> +
> + es_format_Init( &video_format, VIDEO_ES, fcc );
> + video_format.video.i_width = p_PicDesc->StoredWidth;
> + video_format.video.i_height = p_PicDesc->StoredHeight;
> + /* As input are square pixels let VLC or decoder fix SAR, origin,
> + * and visible area */
> + video_format.video.i_frame_rate = p_PicDesc->EditRate.Numerator;
> + video_format.video.i_frame_rate_base = p_PicDesc->EditRate.Denominator;
> + break;
> + }
> + case ESS_MPEG2_VES:
> + {
> + fcc = VLC_FOURCC( 'm', 'p', 'g', 'v' );
> + MPEG2::MXFReader *p_VideoMXFReader = p_sys->p_VideoMXFReader = new MPEG2::MXFReader();
> + MPEG2::VideoDescriptor *p_VideoDesc = p_sys->p_VideoDesc = new MPEG2::VideoDescriptor();
> +
> + Result_t result = p_VideoMXFReader->OpenRead( p_sys->p_dcp->videofile );
> + if( ASDCP_SUCCESS( result ) )
> + msg_Dbg( p_demux, "File %s was successfully opened with asdcp", p_sys->p_dcp->videofile );
> + else
> + {
> + msg_Err( p_demux, "File %s could not be opened with asdcp!", p_sys->p_dcp->videofile );
leaks
> + return VLC_EGENERIC;
> + }
> +
> + p_VideoMXFReader->FillVideoDescriptor( *p_VideoDesc );
> +
> + msg_Dbg( p_demux, "VideoDescriptor: " );
> + msg_Dbg( p_demux, " EditRate: %d:%d", p_VideoDesc->EditRate.Numerator, p_VideoDesc->EditRate.Denominator );
> + msg_Dbg( p_demux, " FrameRate: %d", p_VideoDesc->FrameRate );
> + msg_Dbg( p_demux, " SampleRate: %d:%d", p_VideoDesc->SampleRate.Numerator, p_VideoDesc->SampleRate.Denominator );
> + msg_Dbg( p_demux, " FrameLayout: %d", p_VideoDesc->FrameLayout );
> + msg_Dbg( p_demux, " StoredWidth: %d", p_VideoDesc->StoredWidth );
> + msg_Dbg( p_demux, " StoredHeight: %d", p_VideoDesc->StoredHeight );
> + msg_Dbg( p_demux, " Aspect Ratio: %d:%d", p_VideoDesc->AspectRatio.Numerator, p_VideoDesc->AspectRatio.Denominator );
> + msg_Dbg( p_demux, " ComponentDepth: %d", p_VideoDesc->ComponentDepth );
> + msg_Dbg( p_demux, " HorizontalSubsampling: %d", p_VideoDesc->HorizontalSubsampling );
> + msg_Dbg( p_demux, " VerticalSubsampling: %d", p_VideoDesc->VerticalSubsampling );
> + msg_Dbg( p_demux, " ColorSiting: %d", p_VideoDesc->ColorSiting );
> + msg_Dbg( p_demux, " CodedContentType: %d", p_VideoDesc->CodedContentType );
> + msg_Dbg( p_demux, " LowDelay: %s", p_VideoDesc->LowDelay ? "true" : "false" );
> + msg_Dbg( p_demux, " BitRate: %d", p_VideoDesc->BitRate );
> + msg_Dbg( p_demux, " ProfileAndLevel: %d", p_VideoDesc->ProfileAndLevel );
> + msg_Dbg( p_demux, " ContainerDuration: %d", p_VideoDesc->ContainerDuration );
> +
> + p_sys->p_VideoMXFReader = p_VideoMXFReader;
> + p_sys->p_VideoDesc = p_VideoDesc;
> + p_sys->frame_no = 0;
> + p_sys->frame_rate = p_VideoDesc->EditRate.Numerator / p_VideoDesc->EditRate.Denominator;
again division
> + p_sys->frames_total = p_VideoDesc->ContainerDuration;
> +
> + es_format_Init( &video_format, VIDEO_ES, fcc );
> + video_format.video.i_width = p_VideoDesc->StoredWidth;
> + video_format.video.i_height = p_VideoDesc->StoredHeight;
> + /* As input are square pixels let VLC or decoder fix SAR, origin,
> + * and visible area */
> + video_format.video.i_frame_rate = p_VideoDesc->EditRate.Numerator;
> + video_format.video.i_frame_rate_base = p_VideoDesc->EditRate.Denominator;
> + break;
> + }
> + default:
> + msg_Err( p_demux, "Video file has an audio or subtitle format. DCP may be broken. Check ASSETMAP file." );
leaks
> + return VLC_EGENERIC;
> + }
You can factorize the above code.
> +
> + if( ( p_sys->p_video_es = es_out_Add( p_demux->out, &video_format ) ) == NULL )
> + {
> + msg_Err( p_demux, "Failed to add video es" );
leaks
> + return VLC_EGENERIC;
> + }
>From now leaks will include p_video_es (unless you delete it in your
ps_s destructor) :)
> +
> + /***************************************************
> + ***************** open audio file *****************
> + ***************************************************/
> + msg_Dbg( p_demux, "Audio file is : %s", p_sys->p_dcp->audiofile );
> + EssenceType_t AudioEssType;
> + EssenceType( p_sys->p_dcp->audiofile, AudioEssType );
> + switch( AudioEssType )
> + {
> + case ESS_UNKNOWN:
> + msg_Err( p_demux, "The file %s is not a supported AS_DCP essence container. DCP cannot be read.");
> + return VLC_EGENERIC;
> + case ESS_PCM_24b_48k:
> + case ESS_PCM_24b_96k:
> + fcc = VLC_FOURCC( 's', '2', '4', 'l' );
> + break;
> + default:
> + msg_Err( p_demux, "Audio file has a video or subtitle format. DCP may be broken. Check ASSETMAP file." );
leaks
> + return VLC_EGENERIC;
> + }
> +
> + PCM::MXFReader *p_AudioMXFReader = p_sys->p_AudioMXFReader = new PCM::MXFReader();
> + PCM::AudioDescriptor *p_AudioDesc = p_sys->p_AudioDesc = new PCM::AudioDescriptor();
> +
> + Result_t result = p_AudioMXFReader->OpenRead( p_sys->p_dcp->audiofile );
> + if( ASDCP_SUCCESS( result ) )
> + msg_Dbg( p_demux, "File %s was successfully opened with asdcp", p_sys->p_dcp->audiofile );
> + else
> + {
> + msg_Err( p_demux, "File %s could not be opened with asdcp!", p_sys->p_dcp->audiofile );
leaks
> + return VLC_EGENERIC;
> + }
> +
> + p_AudioMXFReader->FillAudioDescriptor( *p_AudioDesc );
> +
> + es_format_Init( &audio_format, AUDIO_ES, fcc );
> +
> + msg_Dbg( p_demux, "AudioDescriptor: " );
> + msg_Dbg( p_demux, " EditRate: %d:%d", p_AudioDesc->EditRate.Numerator, p_AudioDesc->EditRate.Denominator );
> + msg_Dbg( p_demux, " AudioSamplingRate: %d:%d", p_AudioDesc->AudioSamplingRate.Numerator, p_AudioDesc->AudioSamplingRate.Denominator );
> + msg_Dbg( p_demux, " Locked: %d", p_AudioDesc->Locked );
> + msg_Dbg( p_demux, " ChannelCount: %d", p_AudioDesc->ChannelCount );
> + msg_Dbg( p_demux, " QuantizationBits: %d", p_AudioDesc->QuantizationBits );
> + msg_Dbg( p_demux, " BlockAlign: %d", p_AudioDesc->BlockAlign );
> + msg_Dbg( p_demux, " AvgBps: %d", p_AudioDesc->AvgBps );
> + msg_Dbg( p_demux, " LinkedTrackID: %d", p_AudioDesc->LinkedTrackID );
> + msg_Dbg( p_demux, " Containerduration: %d", p_AudioDesc->ContainerDuration );
> + msg_Dbg( p_demux, " ChannelFormat: %d", p_AudioDesc->ChannelFormat ); /* Does it print the right thing? */
> +
> + audio_format.audio.i_rate = p_AudioDesc->AudioSamplingRate.Numerator / p_AudioDesc->AudioSamplingRate.Denominator;
> + 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->p_AudioMXFReader = p_AudioMXFReader;
> + p_sys->p_AudioDesc = p_AudioDesc;
> +
> +
> + if( ( p_sys->p_audio_es = es_out_Add( p_demux->out, &audio_format ) ) == NULL )
> + {
> + msg_Err( p_demux, "Failed to add audio es" );
leaks
> + return VLC_EGENERIC;
> + }
> +
> + p_demux->pf_demux = Demux;
> + p_demux->pf_control = Control;
> + p_demux->p_sys = p_sys;
> +
> + return VLC_SUCCESS;
> +}
> +
> +static void Close( vlc_object_t *obj )
> +{
> + demux_t *p_demux = ( demux_t* ) obj;
> + demux_sys_t *p_sys = p_demux->p_sys;
> +
> + /* close the files */
> + if( p_sys->p_PicMXFReader )
> + p_sys->p_PicMXFReader->Close();
> + if( p_sys->p_PicMXFSReader )
> + p_sys->p_PicMXFSReader->Close();
> + if( p_sys->p_VideoMXFReader )
> + p_sys->p_VideoMXFReader->Close();
> + p_sys->p_AudioMXFReader->Close();
leaks p_video/audio_es
> +
> + delete( p_demux->p_sys );
> + msg_Dbg( p_demux, "Closing DCP access-demux module" );
> +}
> +
> +static int Demux( demux_t *p_demux )
> +{
> + demux_sys_t *p_sys = p_demux->p_sys;
> + block_t *p_frame = NULL;
> + uint32_t i = p_sys->frame_no;
> +
> + if( i == p_sys->frames_total )
> + return VLC_SUCCESS;
> +
> + /* video frame */
> + switch( p_sys->VideoEssType )
> + {
> + case ESS_JPEG_2000:
> + {
> + JP2K::MXFReader *p_PicMXFReader = p_sys->p_PicMXFReader;
> + JP2K::FrameBuffer PicFrameBuff( FRAME_BUFFER_SIZE );
> +
> + Result_t result = p_PicMXFReader->ReadFrame( i, PicFrameBuff, 0, 0 );
> + if( ! ASDCP_SUCCESS( result ) )
> + {
> + msg_Err( p_demux, "Couldn't read frame with ASDCP");
> + return VLC_EGENERIC;
> + }
> +
> + if( ( p_frame = block_Alloc( PicFrameBuff.Size() ) ) != NULL )
> + memcpy( p_frame->p_buffer, PicFrameBuff.Data(), PicFrameBuff.Size() );
> + else
> + {
> + msg_Err( p_demux, "Couldn't alloc block for elementary stream" );
> + return VLC_ENOMEM;
> + }
> +
> + p_frame->i_buffer = PicFrameBuff.Size();
> + break;
> + }
> + case ESS_JPEG_2000_S:
> + {
> + JP2K::MXFSReader *p_PicMXFReader = p_sys->p_PicMXFSReader;
> + JP2K::FrameBuffer PicFrameBuff( FRAME_BUFFER_SIZE );
> +
> + Result_t result = p_PicMXFReader->ReadFrame( i, JP2K::SP_LEFT, PicFrameBuff, 0, 0 );
> + if( ! ASDCP_SUCCESS( result ) )
> + {
> + msg_Err( p_demux, "Couldn't read frame with ASDCP");
> + return VLC_EGENERIC;
> + }
> +
> + if( ( p_frame = block_Alloc( PicFrameBuff.Size() ) ) != NULL )
> + memcpy( p_frame->p_buffer, PicFrameBuff.Data(), PicFrameBuff.Size() );
> + else
> + {
> + msg_Err( p_demux, "Couldn't alloc block for elementary stream" );
> + return VLC_ENOMEM;
> + }
> +
> + p_frame->i_buffer = PicFrameBuff.Size();
> + break;
> + }
> + case ESS_MPEG2_VES:
> + {
> + MPEG2::MXFReader *p_VideoMXFReader = p_sys->p_VideoMXFReader;
> + MPEG2::FrameBuffer VideoFrameBuff( FRAME_BUFFER_SIZE );
> +
> + Result_t result = p_VideoMXFReader->ReadFrame( i, VideoFrameBuff, 0, 0 );
> + if( ! ASDCP_SUCCESS( result ) )
> + {
> + msg_Err( p_demux, "Couldn't read frame with ASDCP");
> + return VLC_EGENERIC;
> + }
> +
> + if( ( p_frame = block_Alloc( VideoFrameBuff.Size() ) ) != NULL )
> + memcpy( p_frame->p_buffer, VideoFrameBuff.Data(), VideoFrameBuff.Size() );
> + else
> + {
> + msg_Err( p_demux, "Couldn't alloc block for elementary stream" );
> + return VLC_ENOMEM;
> + }
> +
> + p_frame->i_buffer = VideoFrameBuff.Size();
> + break;
> + }
> + default:
> + msg_Err( p_demux, "Video file has an audio or subtitle format. DCP may be broken. Check ASSETMAP file." );
> + return VLC_EGENERIC;
> + }
I think that you can factorize this code. Either with the union, an
inheritance from top class or a template.
> +
> + p_frame->i_flags |= BLOCK_FLAG_TYPE_I;
mpeg2 doesn't have all I frames.
> + p_frame->i_length = 1000000 / p_sys->frame_rate;
> + p_frame->i_pts = 1000000 * p_sys->frame_no / p_sys->frame_rate;
> +
> + es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_frame->i_pts );
This will work in most of the case but should still be the minimum dts
of audio/video.
> + es_out_Send( p_demux->out, p_sys->p_video_es, p_frame );
> +
> + /* audio frame */
> + PCM::MXFReader *p_AudioMXFReader = p_sys->p_AudioMXFReader;
> + PCM::FrameBuffer AudioFrameBuff( PCM::CalcFrameBufferSize( *p_sys->p_AudioDesc ) );
> + p_frame = NULL;
> +
> + Result_t result = p_AudioMXFReader->ReadFrame( i, AudioFrameBuff, 0, 0 );
> + if( ! ASDCP_SUCCESS( result ) )
> + {
> + msg_Err( p_demux, "Couldn't read frame with ASDCP");
> + return VLC_EGENERIC;
> + }
> +
> + if( ( p_frame = block_Alloc( AudioFrameBuff.Size() ) ) != NULL )
> + memcpy( p_frame->p_buffer, AudioFrameBuff.Data(), AudioFrameBuff.Size() );
> + else
> + {
> + msg_Err( p_demux, "Couldn't alloc block for elementary stream" );
> + return VLC_ENOMEM;
> + }
> +
> + p_frame->i_buffer = AudioFrameBuff.Size();
> + p_frame->i_length = 1000000 / p_sys->frame_rate;
> + p_frame->i_pts = 1000000 * p_sys->frame_no / p_sys->frame_rate;
> +
> + es_out_Send( p_demux->out, p_sys->p_audio_es, p_frame );
> +
> + p_sys->frame_no++;
> +
> + return 1;
> +}
> +
> +static int Control( demux_t *p_demux, int query, va_list args )
> +{
> + double f,*pf;
> + bool *pb;
> + int64_t *pi64;
> + demux_sys_t *p_sys = p_demux->p_sys;
> +
> + switch ( query )
> + {
> + case DEMUX_CAN_CONTROL_PACE:
> + pb = ( bool* ) va_arg ( args, bool* );
> + *pb = true;
> + return VLC_SUCCESS;
> + case DEMUX_GET_POSITION:
> + pf = ( double* ) va_arg ( args, double* ); *pf = 0.0;
> + *pf = ( p_sys->frame_no / p_sys->frame_rate ) / ( p_sys->frames_total / p_sys->frame_rate );
I think you can simplify the division by p_sys->frame_rate and check
that frames_total is not null.
> + return VLC_SUCCESS;
> + case DEMUX_SET_POSITION:
> + f = ( double ) va_arg ( args, double );
> + p_sys->frame_no = f * p_sys->frames_total;
Beware of macroblocks in not pure key frame streams (like MPEG2)
> + return VLC_SUCCESS;
> + case DEMUX_GET_LENGTH:
> + pi64 = ( int64_t* ) va_arg ( args, int64_t* );
> + *pi64 = ( p_sys->frames_total / p_sys->frame_rate ) * 1000000;
> + return VLC_SUCCESS;
> + case DEMUX_GET_TIME:
> + pi64 = ( int64_t* ) va_arg ( args, int64_t* );
> + *pi64 = ( p_sys->frame_no / p_sys->frame_rate ) * 1000000;
> + return VLC_SUCCESS;
> + case DEMUX_SET_TIME:
> + f = ( double ) va_arg ( args, double );
> + p_sys->frame_no = f * p_sys->frame_rate / 1000000;
Are you sure about that? isn't it f/p_sys->frame_rate*1000000?
> + return VLC_SUCCESS;
> + default:
> + msg_Err( p_demux, "Unknown query %d in DCP Control", query );
> + return VLC_EGENERIC;
> + }
> +
> + return VLC_SUCCESS;
> +}
> +
> +/**
> + * 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 )
> +{
> + msg_Dbg( p_demux, "dcpInit() in DCP Module : START" );
> +
> + /* Allocate internal state */
> + demux_sys_t *p_sys = new demux_sys_t();
> + if( unlikely( p_sys == NULL ) )
> + return VLC_ENOMEM;
> + p_demux->p_sys = p_sys;
> +
> + /* Allocate DCP object */
> + msg_Dbg( p_demux, "dcpInit() in DCP Module : allocation DCP object" );
> + dcp_t *p_dcp = new dcp_t;
> + if( unlikely( p_dcp == NULL ) )
Leaks p_sys;
> + return VLC_ENOMEM;
> +
> + p_sys->p_dcp = p_dcp;
> +
> + p_dcp->path = new char[ strlen( p_demux->psz_file ) + 5 ];
No check
> + /* We check if there is a "/" at the end of the path */
> + if( endsWith( p_demux->psz_file, "/" ) )
> + strcpy( p_dcp->path, p_demux->psz_file );
> + else
> + strcpy( p_dcp->path, strcat( p_demux->psz_file, "/" ) );
> +
> + /* Parsing XML files to get audio and video files */
> + msg_Dbg( p_demux, "dcpInit() in DCP Module : start parsing XML files" );
> + if( !parserXML( p_demux ) )
> + goto error;
> + msg_Dbg(p_demux, "dcpInit() in DCP Module : parsing XML files done");
> +
> + msg_Dbg( p_demux, "Path = %s", p_sys->p_dcp->path );
> + msg_Dbg( p_demux, "ASSETMAP = %s", p_sys->p_dcp->assetmapfile );
> + msg_Dbg( p_demux, "PKL = %s", p_sys->p_dcp->pklfile );
> + msg_Dbg( p_demux, "CPL = %s", p_sys->p_dcp->cplfile );
> + msg_Dbg( p_demux, "Video = %s", p_sys->p_dcp->videofile );
> + msg_Dbg( p_demux, "Audio = %s", p_sys->p_dcp->audiofile );
> +
> + return VLC_SUCCESS;
> +
> + error:
Leaks p_dcp and path
> + delete( p_demux->p_sys );
> + return VLC_EGENERIC;
> +}
> +
> +/**
> + * 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 parserXML ( demux_t * p_demux )
> +{
> + dcp_t *p_dcp = p_demux->p_sys->p_dcp;
> +
> + msg_Dbg( p_demux, "parserXML() in DCP Module : START" );
> +
> + /* We get the ASSETMAP file path */
> + assetmapUri( p_demux );
> +
> + msg_Dbg( p_demux, "Path to ASSETMAP file = %s", p_dcp->assetmapfile );
> +
> + /* 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) */
> + parserAssetmapXML( p_demux );
> +
> + msg_Dbg( p_demux, "Path to CPL file = %s", p_dcp->cplfile );
> +
> + /* We parse the CPL File : in order to retrieve video and audio files
> + according to UID of files described in CPL XML file */
> + parserCplXML( p_demux );
> +
> + msg_Dbg( p_demux, "parserXML() in DCP Module : END" );
> +
> + return 1; /* TODO : perform checking on XML parsing */
> +}
> +
> +/**
> + * Function to retrieve the path to the ASSETMAP file.
> + * @param p_demux DCP access_demux.
> + */
> +void assetmapUri( demux_t * p_demux )
> +{
> + DIR *dir = NULL;
> + struct dirent *ent = NULL;
> + int b_found = 0;
> +
> + char * result = new char[ strlen( p_demux->psz_file ) + 1 ];
> + char * result2 = NULL;
No check.
> +
> + /* copy of "path" in "res" */
> + strcpy( result, p_demux->psz_file );
> +
> + if( ( dir = opendir ( p_demux -> psz_file ) ) != 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 )
> + {
> + result2 = new char[ strlen( result ) + 1 ];
> + strcpy( result2, result );
> + delete result;
> + result = new char[ strlen( result2 ) + strlen( ent->d_name ) + 1 ];
> + strcpy( result, result2 );
> + strcat( result, ( const char * ) ent->d_name );
> + delete result2;
why? if you want to append a name to a path you don't need to copy it n
times.
result = new (std::nothrow) char[ strlen( p_demux->psz_file ) +
strlen( ent->d_name ) + 1 ];
if(!result)
{
...
}
sprintf("%s%s",p_demux->psz_file, strlen( ent->d_name
));
or something like that
Besides you should use delete[] when you allocate an array. Also beware
that new doesn't throw an exception instead of returning NULL.
> + b_found = 1;
break?
> + }
> + }
> + closedir( dir );
> + }
> + else
> + msg_Err( p_demux, "Could not open the directory : %s", p_demux -> psz_file );
> +
> + /* if no assetmap file */
> + if( !b_found )
> + {
> + msg_Err( p_demux, "No ASSETMAP found in the directory : %s", p_demux -> psz_file );
> + result = NULL;
> + }
> +
> +
> + /* We check if we actually get the ASSETMAP file path */
> + if( result == NULL )
> + msg_Err( p_demux, "No ASSETMAP XML file found in the DCP directory" );
> +
> + /* We copy the ASSETMAP file path in the DCP structure */
> + p_demux->p_sys->p_dcp->assetmapfile = new char[ strlen( result ) + 1 ];
> + strcpy( p_demux->p_sys->p_dcp->assetmapfile, result );
Why?
p_demux->p_sys->p_dcp->assetmapfile = result;
And you are done.
> +
> + /* free memory */
> + delete result;
> +}
> +
> +/**
> + * Function to parse the assetmap file in order to get CPL file path, PKL file path and
> + * to store UID/Path of files described in the ASSETMAP XML file.
> + * @param p_demux DCP access_demux.
> + */
> +void parserAssetmapXML ( demux_t * p_demux )
> +{
> + msg_Dbg( p_demux, "parserAssetmapXML() in DCP Module : START" );
> +
> + /* variables */
> + dcp_t *p_dcp = p_demux->p_sys->p_dcp;
> + int node = 0;
> + int packinglist = 0;
> + int file_number = 0;
> + int asset_list = 0;
> +
> + char * filepath = NULL;
> +
> + /* init libxml2 */
> + LIBXML_TEST_VERSION;
> +
> + /* init XML reader */
> + msg_Dbg( p_demux, "parserAssetmapXML() in DCP Module : loading XML reader with %s", p_dcp->assetmapfile );
> + xmlTextReaderPtr reader = xmlReaderForFile( ( const char * ) p_dcp->assetmapfile, NULL, 0 );
> +
> + msg_Dbg( p_demux, "parserAssetmapXML() in DCP Module : reading XML file" );
> +
> + /* reading XML file ( node by node ) */
> + node = xmlTextReaderRead( reader );
> + while( node == 1 )
> + {
> + /* Uncomment this line to print XML content node by node */
> + /* msg_Dbg(p_demux, "Name = %s, Value = %s", ( char * ) xmlTextReaderConstName( reader ), ( char * )xmlTextReaderConstValue( reader ) ); */
> +
> + /* This condition determines if we are in AssetList part or not */
> + if( strcmp( ( char * ) xmlTextReaderConstName( reader ), "AssetList" ) == 0 )
> + {
> + if( asset_list == 0 )
> + asset_list = 1;
> + else
> + asset_list = 0;
> + }
> +
> + /* When we are in AssetList part */
> + if( asset_list == 1 )
> + {
> + /* Set the UID of the file */
> + if( strcmp( ( char * ) xmlTextReaderConstName( reader ), "Id" ) == 0 )
> + {
> + xmlTextReaderRead( reader );
> + p_dcp->files[ file_number ] = new file_t;
> + p_dcp->files[ file_number ]->id = new char[ strlen( (char *)xmlTextReaderConstValue( reader ) ) + 1 ];
> + msg_Dbg( p_demux, "ID = %s", ( char* ) xmlTextReaderConstValue ( reader ) );
> + strcpy( p_dcp->files[file_number]->id, (char *)xmlTextReaderConstValue( reader ) );
> + xmlTextReaderRead( reader );
> + }
> +
> + /* It determines if it is PKL File or not */
> + /* For PKL File, we have : <PackingList>true</PackingList> */
> + /* This tag seems to be used only for PKL file */
> + if( strcmp( ( char * ) xmlTextReaderConstName( reader ), "PackingList" ) == 0 )
> + packinglist = 1; /* next path info will be for PKL file */
> +
> + /* Set the Path of the file */
> + /* If the file is a XML file, it is the PKL file or the CPL file */
> + if( strcmp( ( char * ) xmlTextReaderConstName( reader ), "Path" ) == 0 )
> + {
> + xmlTextReaderRead( reader );
> + msg_Dbg( p_demux, "Path = %s", ( char * ) xmlTextReaderConstValue( reader ) );
> + filepath = new char[ strlen( ( char* ) xmlTextReaderConstValue( reader ) ) + strlen( p_dcp->path ) + 1 ];
> + strcpy( filepath, p_dcp->path );
> + filepath = strcat( filepath, ( char * ) xmlTextReaderConstValue( reader ) );
> + msg_Dbg( p_demux, "filepath = %s", filepath );
> + if( endsWith( ( char * ) xmlTextReaderConstValue( reader ), ".xml" ) )
> + {
> + if( packinglist == 1 )
> + {
> + /* it is PKL file name */
> + p_dcp->pklfile = new char[ strlen( filepath ) + 1 ];
> + p_dcp->files[file_number]->path = new char[ strlen( filepath ) + 1 ];;
> + strcpy( p_dcp->pklfile, filepath );
> + strcpy( p_dcp->files[file_number]->path, filepath );
> + packinglist = 0;
> + }
> + else
> + {
> + /* it is CPL file name */
> + p_dcp->cplfile = new char[ strlen( filepath ) + 1 ];;
> + p_dcp->files[file_number]->path = new char[ strlen( filepath ) + 1 ];;
> + strcpy( p_dcp->cplfile, filepath );
> + strcpy( p_dcp->files[file_number]->path, filepath );
> + }
> + }
> + else
> + {
> + /* it is an other file (MXF in theory) */
> + p_dcp->files[file_number]->path = new char[ strlen( filepath ) + 1 ];;
> + strcpy( p_dcp->files[file_number]->path, filepath );
> + }
> +
> + /* next node */
> + xmlTextReaderRead( reader );
> +
> + /* next file */
> + file_number++;
> + }
> + }
> +
> + /* next node */
> + node = xmlTextReaderRead( reader );
> + }
> +
> + /* Set the number of files described in ASSETMAP file */
> + p_dcp->nb_files = file_number;
> +
> + /* free memory */
> + xmlFreeTextReader( reader );
> + xmlCleanupParser();
> + xmlMemoryDump();
> + delete filepath;
> +
> + msg_Dbg( p_demux, "parserAssetmapXML() in DCP Module : END" );
> +}
> +
> +/**
> + * Function to parse the CPL file in order to retrieve UID of video and audio files.
> + * When it is done, we can determine path to video and audio files using information
> + * about files described in ASSETMAP file
> + * @param p_demux DCP access_demux.
> + */
> +void parserCplXML ( demux_t * p_demux )
> +{
> + msg_Dbg( p_demux, "parserCplXML() in DCP Module : START" );
> +
> + /* variables */
> + dcp_t *p_dcp = p_demux->p_sys->p_dcp;
> + int incr = 0;
> + int node = 0;
> +
> + msg_Dbg( p_demux, "Full path to CPL file : %s", p_dcp->cplfile );
> +
> + /* init libxml2 */
> + LIBXML_TEST_VERSION;
> +
> + /* init XML reader */
> + msg_Dbg( p_demux, "parserCplXML() in DCP Module : loading XML reader with %s", p_dcp->cplfile );
> + xmlTextReaderPtr reader = xmlReaderForFile( ( const char * ) p_dcp->cplfile, NULL, 0 );
> +
> + msg_Dbg( p_demux, "parserCplXML() in DCP Module : reading XML file" );
> +
> + /* Read XML file node by node */
> + node = xmlTextReaderRead( reader );
> + while( node == 1 )
> + {
> + /* This variable is used to prevent the confusing case : foo</MainPicture><MainSound>foo */
> + incr = 0;
> +
> + /* Uncomment this line to print XML content node by node */
> + /* msg_Dbg( p_demux, "Name = %s, Value = %s", ( char * ) xmlTextReaderConstName( reader ), ( char * )xmlTextReaderConstValue( reader ) ); */
> +
> + /* MainPicture data */
> + if( strcmp( ( char * ) xmlTextReaderConstName( reader ), "MainPicture" ) == 0 || strcmp( ( char * ) xmlTextReaderConstName( reader ), "MainStereoscopicPicture" ) == 0 )
> + {
> + incr = 1;
> + node = xmlTextReaderRead( reader );
> + if( strcmp( ( char * ) xmlTextReaderConstName( reader ), "#text" ) == 0 )
> + {
> + node = xmlTextReaderRead( reader );
> + if( strcmp( ( char * ) xmlTextReaderConstName( reader ), "Id" ) == 0 )
> + {
> + node = xmlTextReaderRead( reader );
> + /* ID value contained in : ( char * ) xmlTextReaderConstValue( reader ) */
> + for( int i = 0; i < p_dcp->nb_files; i++ )
> + {
> + if( strcmp( p_dcp->files[i]->id,( char * ) xmlTextReaderConstValue( reader ) ) == 0 )
> + {
> + p_dcp->videofile = new char[ strlen( p_dcp->files[i]->path ) + 1 ];
> + strcpy( p_dcp->videofile, p_dcp->files[i]->path );
> + }
> + }
> + }
> + }
> + }
> +
> + /* MainSound data */
> + if( strcmp( ( char * ) xmlTextReaderConstName( reader ), "MainSound" ) == 0 )
> + {
> + incr = 1;
> + node = xmlTextReaderRead( reader );
> + if( strcmp( ( char * ) xmlTextReaderConstName( reader ), "#text" ) == 0 )
> + {
> + node = xmlTextReaderRead( reader );
> + if( strcmp( ( char * ) xmlTextReaderConstName( reader ), "Id" ) == 0 )
> + {
> + node = xmlTextReaderRead( reader );
> + /* ID value contained in : ( char * ) xmlTextReaderConstValue( reader ) */
> + for( int i = 0; i < p_dcp->nb_files; i++ )
> + {
> + if( strcmp( p_dcp->files[i]->id,( char * ) xmlTextReaderConstValue( reader ) ) == 0 )
> + {
> + p_dcp->audiofile = new char[ strlen( p_dcp->files[i]->path ) + 1 ];
> + strcpy( p_dcp->audiofile, p_dcp->files[i]->path );
> + }
> + }
> + }
> + }
> + }
> +
> + /* We do not go to the next node when we have </MainPicture><MainSound> */
> + if( incr == 0 )
> + node = xmlTextReaderRead( reader );
> + }
> +
> + /* free memory */
> + xmlFreeTextReader( reader );
> + xmlCleanupParser();
> + xmlMemoryDump();
> +
> + msg_Dbg( p_demux, "parserCplXML() in DCP Module : END" );
> +}
I did not check all the deallocation inside your p_dcp's destructor but
it may be useful to double check.
> +
> +///////////////////////////////////////////////////////////////////////////////////////////
> +///////////////////////////////////////////////////////////////////////////////////////////
> +/////// ///////
> +/////// Low-level functions : Strings manipulations, Free function ///////
> +/////// ///////
> +///////////////////////////////////////////////////////////////////////////////////////////
> +///////////////////////////////////////////////////////////////////////////////////////////
> +
> +/**
> + * Function to check if a file name ends with a given suffix
> + * @param str File name
> + * @param suffix Suffix to look for
> + * @return true if the file name ends with the given suffix, fale otherwise
> + */
> +int endsWith( const char * str, const char * suffix )
> +{
> + if( !str || !suffix )
> + return 0;
> + size_t lenstr = strlen( str );
> + size_t lensuffix = strlen( suffix );
> + if( lensuffix > lenstr )
> + return 0;
> + return strncasecmp( str + lenstr - lensuffix, suffix, lensuffix ) == 0;
> +}
Regards
--
Denis Charmet - TypX
Le mauvais esprit est un art de vivre
More information about the vlc-devel
mailing list