vlc的MP4的Demux函数分析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vlc的MP4的Demux函数分析相关的知识,希望对你有一定的参考价值。

/*
 * 从stream中,分离出一包包数据包,并投递给解码器。
 *
 */
/*****************************************************************************
 * Demux: read packet and send them to decoders
 *****************************************************************************
 * TODO check for newly selected track (ie audio upt to now )
 *****************************************************************************/
static int Demux( demux_t *p_demux )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    unsigned int i_track;


    unsigned int i_track_selected;

    /* check for newly selected/unselected track */ //检查每一条媒体轨道,找出可用的媒体轨道。
    for( i_track = 0, i_track_selected = 0; i_track < p_sys->i_tracks;
         i_track++ )
    {
        mp4_track_t *tk = &p_sys->track[i_track]; //媒体轨道德上下文。
        bool b;

        if( !tk->b_ok || tk->b_chapter ||
            ( tk->b_selected && tk->i_sample >= tk->i_sample_count ) ) //貌似这条轨道不太正常。
        {
            continue;
        }

        es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b ); //看看解码器是否正常。

        if( tk->b_selected && !b )
        {
            MP4_TrackUnselect( p_demux, tk );
        }
        else if( !tk->b_selected && b)
        {
            MP4_TrackSelect( p_demux, tk, MP4_GetMoviePTS( p_sys ) );
        }

        if( tk->b_selected )
        {
            i_track_selected++;
        }
    }

    if( i_track_selected <= 0 )
    {
        p_sys->i_time += __MAX( p_sys->i_timescale / 10 , 1 );
        if( p_sys->i_timescale > 0 )
        {
            int64_t i_length = CLOCK_FREQ *
                               (mtime_t)p_sys->moovfragment.i_duration /
                               (mtime_t)p_sys->i_timescale;
            if( MP4_GetMoviePTS( p_sys ) >= i_length )
                return 0;
            return 1;
        }

        msg_Warn( p_demux, "no track selected, exiting..." );
        return 0;
    }

    /* */
    MP4_UpdateSeekpoint( p_demux );

    /* first wait for the good time to read a packet */
    p_sys->i_pcr = MP4_GetMoviePTS( p_sys );

    bool b_data_sent = false;

    /* Find next track matching contiguous data */
    mp4_track_t *tk = NULL;
    uint64_t i_candidate_pos = UINT64_MAX;
    mtime_t i_candidate_dts = INT64_MAX;
    for( i_track = 0; i_track < p_sys->i_tracks; i_track++ )
    {
        mp4_track_t *tk_tmp = &p_sys->track[i_track];
        if( !tk_tmp->b_ok || tk_tmp->b_chapter || !tk_tmp->b_selected || tk_tmp->i_sample >= tk_tmp->i_sample_count )
            continue;

        if ( p_sys->b_seekmode )
        {
            mtime_t i_dts = MP4_TrackGetDTS( p_demux, tk_tmp );
            if ( i_dts <= i_candidate_dts )
            {
                tk = tk_tmp;
                i_candidate_dts = i_dts;
                i_candidate_pos = MP4_TrackGetPos( tk_tmp );
            }
        }
        else
        {
            /* Try to avoid seeking on non fastseekable. Will fail with non interleaved content */
            uint64_t i_pos = MP4_TrackGetPos( tk_tmp );
            if ( i_pos <= i_candidate_pos )
            {
                i_candidate_pos = i_pos;
                tk = tk_tmp;
            }
        }
    }

    if ( !tk )
    {
        msg_Dbg( p_demux, "Could not select track by data position" );
        goto end;
    }
    else if ( p_sys->b_seekmode )
    {
        if( stream_Seek( p_demux->s, i_candidate_pos ) )
        {
            msg_Warn( p_demux, "track[0x%x] will be disabled (eof?)",
                      tk->i_track_ID );
            MP4_TrackUnselect( p_demux, tk );
            goto end;
        }
    }

#if 0
    msg_Dbg( p_demux, "tk(%i)=%"PRId64" mv=%"PRId64" pos=%"PRIu64, i_track,
             MP4_TrackGetDTS( p_demux, tk ),
             MP4_GetMoviePTS( p_sys ), i_candidate_pos );
#endif

    uint32_t i_nb_samples = 0;
    uint32_t i_samplessize = MP4_TrackGetReadSize( tk, &i_nb_samples );
    if( i_samplessize > 0 )
    {
        block_t *p_block;
        int64_t i_delta;
        uint64_t i_current_pos;

        /* go,go go ! */
        if ( !MP4_stream_Tell( p_demux->s, &i_current_pos ) )
            goto end;

        if( i_current_pos != i_candidate_pos )
        {
            if( stream_Seek( p_demux->s, i_candidate_pos ) )
            {
                msg_Warn( p_demux, "track[0x%x] will be disabled (eof?)",
                          tk->i_track_ID );
                MP4_TrackUnselect( p_demux, tk );
                goto end;
            }
        }

        /* now read pes */
        if( !(p_block = stream_Block( p_demux->s, i_samplessize )) )
        {
            msg_Warn( p_demux, "track[0x%x] will be disabled (eof?)",
                      tk->i_track_ID );
            MP4_TrackUnselect( p_demux, tk );
            goto end;
        }
        else if( tk->fmt.i_cat == SPU_ES )
        {
            if ( tk->fmt.i_codec != VLC_CODEC_TX3G &&
                 tk->fmt.i_codec != VLC_CODEC_SPU )
                p_block->i_buffer = 0;
        }

        /* dts */
        p_block->i_dts = VLC_TS_0 + MP4_TrackGetDTS( p_demux, tk );
        /* pts */
        i_delta = MP4_TrackGetPTSDelta( p_demux, tk );
        if( i_delta != -1 )
            p_block->i_pts = p_block->i_dts + i_delta;
        else if( tk->fmt.i_cat != VIDEO_ES )
            p_block->i_pts = p_block->i_dts;
        else
            p_block->i_pts = VLC_TS_INVALID;

        if ( !b_data_sent )
        {
            es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_sys->i_pcr );
            b_data_sent = true;
        }
        es_out_Send( p_demux->out, tk->p_es, p_block );
    }

    /* Next sample */
    if ( i_nb_samples ) /* sample size could be 0, need to go fwd. see return */
        MP4_TrackNextSample( p_demux, tk, i_nb_samples );

end:
    if ( b_data_sent )
    {
        p_sys->i_pcr = INT64_MAX;
        for( i_track = 0; i_track < p_sys->i_tracks; i_track++ )
        {
            mp4_track_t *tk = &p_sys->track[i_track];
            if ( !tk->b_ok || !tk->b_selected  ||
                 (tk->fmt.i_cat != AUDIO_ES && tk->fmt.i_cat != VIDEO_ES) )
                continue;

            mtime_t i_dts = MP4_TrackGetDTS( p_demux, tk );
            p_sys->i_pcr = __MIN( i_dts, p_sys->i_pcr );

            if ( !p_sys->b_seekmode && i_dts > p_sys->i_pcr + 2*CLOCK_FREQ )
            {
                msg_Dbg( p_demux, "that media doesn‘t look interleaved, will need to seek");
                p_sys->b_seekmode = true;
            }

            p_sys->i_time = p_sys->i_pcr * p_sys->i_timescale / CLOCK_FREQ;
        }
    }

    return b_data_sent || ( i_samplessize == 0 && i_nb_samples );
}

 

以上是关于vlc的MP4的Demux函数分析的主要内容,如果未能解决你的问题,请参考以下文章

如何分析netbean module之间的调用关系

(转)MP4文件两种格式AVC1和H264的区别及利用FFMPEG demux为h264码流事项

mux复用 demux解复用

从终端启动 VLC 并从一开始将默认渲染器设置为 ChromeCast(无 GUI)

vlc播放流程分析

vlc源码分析 播放流程