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 );
}
时间: 2024-12-07 07:32:32

vlc的MP4的Demux函数分析的相关文章

linux C函数之strdup函数分析

一.函数分析 1.函数原型: #include <string.h>char *strdup(const char *s); 2.功能: strdup()函数主要是拷贝字符串s的一个副本,由函数返回值返回,这个副本有自己的内存空间,和s没有关联.strdup函数复制一个字符串,使用完后,要使用delete函数删除在函数中动态申请的内存,strdup函数的参数不能为NULL,一旦为NULL,就会报段错误,因为该函数包括了strlen函数,而该函数参数不能是NULL. 3.strdup函数实现 c

如何验证一个地址可否使用—— MmIsAddressValid函数分析

又是一篇内核函数分析的博文,我个人觉得Windows的内核是最好的老师,当你想实现一个功能之前可以看看Windows内核是怎么做的,说不定就有灵感呢:) 首先看下官方的注释说明: /*++ Routine Description: For a given virtual address this function returns TRUE if no page fault will occur for a read operation on the address, FALSE otherwis

page_address()函数分析--如何通过page取得虚拟地址

由于X86平台上面,内存是划分为低端内存和高端内存的,所以在两个区域内的page查找对应的虚拟地址是不一样的. 一. x86上关于page_address()函数的定义 在include/linux/mm.h里面,有对page_address()函数的三种宏定义,主要依赖于不同的平台: 首先来看看几个宏的定义:CONFIG_HIGHMEM:顾名思义,就是是否支持高端内存,可以查看config文件,一般推荐内存超过896M的时候,才配置为支持高端内存.WANT_PAGE_VIRTUAL:X86平台

Oracle官网JNI简介和接口函数分析

第一章 概述 本章主要介绍JNI(Java Native Interface),JNI是一种本地编程接口.它允许运行在JAVA虚拟机中的JAVA代码和用其他编程语言,诸如C语言.C++.汇编,写的应用和库之间的交互操作. JNI的最大优势在于没有强加任何限制在JAVA虚拟机的下层实现上,因此,JAVA虚拟机供应商能够提供JNI的支持而不影响虚拟机的其他部分,程序员只需写出一个版本的本地应用和库,就可使之运行在一切支持JNI的JAVA虚拟机上. 本章包含了以下的要点: ? JNI概述 ? 目标 ?

linux 内核移植(七)——rest_init函数分析

代码在start_kernel函数运行的最后到了rest_init()函数中 1:rest_init()函数分析 (1)rest_init中调用kernel_thread函数启动了2个内核线程,分别是:kernel_init和kthreadd (2)调用schedule函数开启了内核的调度系统,从此linux系统开始转起来了. (3)rest_init最终调用cpu_idle函数结束了整个内核的启动.也就是说linux内核最终结束了一个函数cpu_idle.这个函数里面肯定是死循环. (4)简单

如何验证一个地址可否使用——MmIsAddressValid函数分析

又是一篇内核函数分析的博文,我个人觉得Windows的内核是最好的老师,当你想实现一个功能之前可以看看Windows内核是怎么做的,说不定就有灵感呢:) 首先看下官方的注释说明: /*++ Routine Description: For a given virtual address this function returns TRUE if no page fault will occur for a read operation on the address, FALSE otherwis

Linux-0.11内核内存管理get_free_page()函数分析

/* *Author : DavidLin*Date : 2014-11-11pm*Email : [email protected] or [email protected]*world : the city of SZ, in China*Ver : 000.000.001*history : editor time do 1)LinPeng 2014-11-11 created this file! 2)*/Linux-0.11内存管理模块是源代码中比较难以理解的部分,现在把笔者个人的理解

Linux-0.11内核源代码分析系列:内存管理get_free_page()函数分析

Linux-0.11内存管理模块是源码中比較难以理解的部分,如今把笔者个人的理解发表 先发Linux-0.11内核内存管理get_free_page()函数分析 有时间再写其它函数或者文件的:) /*  *Author  : DavidLin  *Date    : 2014-11-11pm  *Email   : [email protected] or [email protected]  *world   : the city of SZ, in China  *Ver     : 000

string函数分析

string函数分析string函数包含在string.c文件中,经常被C文件使用.1. strcpy函数原型: char* strcpy(char* str1,char* str2);函数功能: 把str2指向的字符串拷贝到str1中去函数返回: 返回str1,即指向str1的指针 /** * strcpy - Copy a %NUL terminated string * @dest: Where to copy the string to * @src: Where to copy the