[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