⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mp4.c

📁 VLC媒体播放程序
💻 C
📖 第 1 页 / 共 4 页
字号:
    }    if( i_track_selected <= 0 )    {        msg_Warn( p_input, "no track selected, exiting..." );        return 0;    }    /* first wait for the good time to read a packet */    input_ClockManageRef( p_input,                          p_input->stream.p_selected_program,                          p_sys->i_pcr );    /* update pcr XXX in mpeg scale so in 90000 unit/s */    p_sys->i_pcr = MP4_GetMoviePTS( p_sys ) * 9 / 100;    /* we will read 100ms for each stream so ...*/    p_sys->i_time += __MAX( p_sys->i_timescale / 10 , 1 );    /* Check if we need to send the audio data to decoder */    b_play_audio = !p_input->stream.control.b_mute;    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 )        {            continue;        }        while( MP4_TrackGetPTS( p_input, tk ) < MP4_GetMoviePTS( p_sys ) )        {#if 0            msg_Dbg( p_input, "tk=%lld mv=%lld",                     MP4_TrackGetPTS( p_input, tk ),                     MP4_GetMoviePTS( p_sys ) );#endif            if( MP4_TrackSampleSize( tk ) > 0 &&                ( b_play_audio || tk->fmt.i_cat != AUDIO_ES ) )            {                block_t *p_block;                /* go,go go ! */                if( stream_Seek( p_input->s, MP4_TrackGetPos( tk ) ) )                {                    msg_Warn( p_input, "track[0x%x] will be disabled (eof?)", tk->i_track_ID );                    MP4_TrackUnselect( p_input, tk );                    break;                }                /* now read pes */                if( ( p_block = stream_Block( p_input->s,                                              MP4_TrackSampleSize( tk ) ) ) == NULL )                {                    msg_Warn( p_input, "track[0x%x] will be disabled (eof?)", tk->i_track_ID );                    MP4_TrackUnselect( p_input, tk );                    break;                }                if( tk->b_drms && tk->p_drms )                {                    drms_decrypt( tk->p_drms,                                  (uint32_t*)p_block->p_buffer,                                  p_block->i_buffer );                }                p_block->i_dts =                    input_ClockGetTS( p_input,                                      p_input->stream.p_selected_program,                                      MP4_TrackGetPTS( p_input, tk ) * 9/100 );                p_block->i_pts = tk->fmt.i_cat == VIDEO_ES ? 0 : p_block->i_dts;                if( !tk->b_drms || ( tk->b_drms && tk->p_drms ) )                {                    es_out_Send( p_input->p_es_out, tk->p_es, p_block );                }            }            /* Next sample */            if( MP4_TrackNextSample( p_input, tk ) )            {                break;            }        }    }    return 1;}/***************************************************************************** * Seek: Got to i_date ******************************************************************************/static int   Seek     ( input_thread_t *p_input, mtime_t i_date ){    demux_sys_t *p_sys = p_input->p_demux_data;    unsigned int i_track;    /* First update update global time */    p_sys->i_time = i_date * p_sys->i_timescale / 1000000;    p_sys->i_pcr  = i_date* 9 / 100;    /* Now for each stream try to go to this time */    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 )        {            MP4_TrackSeek( p_input, tk, i_date );        }    }    return( 1 );}/***************************************************************************** * Control: *****************************************************************************/static int Control( input_thread_t *p_input, int i_query, va_list args ){    demux_sys_t *p_sys = p_input->p_demux_data;    double f, *pf;    int64_t i64, *pi64;    switch( i_query )    {        case DEMUX_GET_POSITION:            pf = (double*)va_arg( args, double * );            if( p_sys->i_duration > 0 )            {                *pf = (double)p_sys->i_time / (double)p_sys->i_duration;            }            else            {                *pf = 0.0;            }            return VLC_SUCCESS;        case DEMUX_SET_POSITION:            f = (double)va_arg( args, double );            if( p_sys->i_timescale > 0 )            {                i64 = (int64_t)( f * (double)1000000 *                                 (double)p_sys->i_duration /                                 (double)p_sys->i_timescale );                return Seek( p_input, i64 );            }            else return VLC_SUCCESS;        case DEMUX_GET_TIME:            pi64 = (int64_t*)va_arg( args, int64_t * );            if( p_sys->i_timescale > 0 )            {                *pi64 = (mtime_t)1000000 *                        (mtime_t)p_sys->i_time /                        (mtime_t)p_sys->i_timescale;            }            else *pi64 = 0;            return VLC_SUCCESS;        case DEMUX_SET_TIME:            i64 = (int64_t)va_arg( args, int64_t );            return Seek( p_input, i64 );        case DEMUX_GET_LENGTH:            pi64 = (int64_t*)va_arg( args, int64_t * );            if( p_sys->i_timescale > 0 )            {                *pi64 = (mtime_t)1000000 *                        (mtime_t)p_sys->i_duration /                        (mtime_t)p_sys->i_timescale;            }            else *pi64 = 0;            return VLC_SUCCESS;        case DEMUX_GET_FPS:            msg_Warn( p_input, "DEMUX_GET_FPS unimplemented !!" );            return VLC_EGENERIC;        case DEMUX_GET_META:            return VLC_EGENERIC;        default:            msg_Err( p_input, "control query unimplemented !!!" );            return demux_vaControlDefault( p_input, i_query, args );    }}/***************************************************************************** * Close: frees unused data *****************************************************************************/static void Close ( vlc_object_t * p_this ){    unsigned int i_track;    input_thread_t *  p_input = (input_thread_t *)p_this;    demux_sys_t *p_sys = p_input->p_demux_data;    msg_Dbg( p_input, "freeing all memory" );    MP4_BoxFree( p_input, p_sys->p_root );    for( i_track = 0; i_track < p_sys->i_tracks; i_track++ )    {        MP4_TrackDestroy( p_input, &p_sys->track[i_track] );    }    FREE( p_sys->track );    free( p_sys );}/**************************************************************************** * Local functions, specific to vlc ****************************************************************************//* now create basic chunk data, the rest will be filled by MP4_CreateSamplesIndex */static int TrackCreateChunksIndex( input_thread_t *p_input,                                   mp4_track_t *p_demux_track ){    MP4_Box_t *p_co64; /* give offset for each chunk, same for stco and co64 */    MP4_Box_t *p_stsc;    unsigned int i_chunk;    unsigned int i_index, i_last;    if( ( !(p_co64 = MP4_BoxGet( p_demux_track->p_stbl, "stco" ) )&&          !(p_co64 = MP4_BoxGet( p_demux_track->p_stbl, "co64" ) ) )||        ( !(p_stsc = MP4_BoxGet( p_demux_track->p_stbl, "stsc" ) ) ))    {        return( VLC_EGENERIC );    }    p_demux_track->i_chunk_count = p_co64->data.p_co64->i_entry_count;    if( !p_demux_track->i_chunk_count )    {        msg_Warn( p_input, "no chunk defined" );        return( VLC_EGENERIC );    }    p_demux_track->chunk = calloc( p_demux_track->i_chunk_count,                                   sizeof( mp4_chunk_t ) );    /* first we read chunk offset */    for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )    {        p_demux_track->chunk[i_chunk].i_offset =                p_co64->data.p_co64->i_chunk_offset[i_chunk];    }    /* now we read index for SampleEntry( soun vide mp4a mp4v ...)        to be used for the sample XXX begin to 1        We construct it begining at the end */    i_last = p_demux_track->i_chunk_count; /* last chunk proceded */    i_index = p_stsc->data.p_stsc->i_entry_count;    if( !i_index )    {        msg_Warn( p_input, "cannot read chunk table or table empty" );        return( VLC_EGENERIC );    }    while( i_index )    {        i_index--;        for( i_chunk = p_stsc->data.p_stsc->i_first_chunk[i_index] - 1;                i_chunk < i_last; i_chunk++ )        {            p_demux_track->chunk[i_chunk].i_sample_description_index =                    p_stsc->data.p_stsc->i_sample_description_index[i_index];            p_demux_track->chunk[i_chunk].i_sample_count =                    p_stsc->data.p_stsc->i_samples_per_chunk[i_index];        }        i_last = p_stsc->data.p_stsc->i_first_chunk[i_index] - 1;    }    p_demux_track->chunk[0].i_sample_first = 0;    for( i_chunk = 1; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )    {        p_demux_track->chunk[i_chunk].i_sample_first =            p_demux_track->chunk[i_chunk-1].i_sample_first +                p_demux_track->chunk[i_chunk-1].i_sample_count;    }    msg_Dbg( p_input,             "track[Id 0x%x] read %d chunk",             p_demux_track->i_track_ID,             p_demux_track->i_chunk_count );    return( VLC_SUCCESS );}static int TrackCreateSamplesIndex( input_thread_t *p_input,                                    mp4_track_t *p_demux_track ){    MP4_Box_t *p_stts; /* makes mapping between sample and decoding time,                          ctts make same mapping but for composition time,                          not yet used and probably not usefull */    MP4_Box_t *p_stsz; /* gives sample size of each samples, there is also stz2                          that uses a compressed form FIXME make them in libmp4                          as a unique type */    /* TODO use also stss and stsh table for seeking */    /* FIXME use edit table */    int64_t i_sample;    int64_t i_chunk;    int64_t i_index;    int64_t i_index_sample_used;    int64_t i_last_dts;    p_stts = MP4_BoxGet( p_demux_track->p_stbl, "stts" );    p_stsz = MP4_BoxGet( p_demux_track->p_stbl, "stsz" ); /* FIXME and stz2 */    if( ( !p_stts )||( !p_stsz ) )    {        msg_Warn( p_input, "cannot read sample table" );        return( VLC_EGENERIC );    }    p_demux_track->i_sample_count = p_stsz->data.p_stsz->i_sample_count;    /* for sample size, there are 2 case */    if( p_stsz->data.p_stsz->i_sample_size )    {        /* 1: all sample have the same size, so no need to construct a table */        p_demux_track->i_sample_size = p_stsz->data.p_stsz->i_sample_size;        p_demux_track->p_sample_size = NULL;    }    else    {        /* 2: each sample can have a different size */        p_demux_track->i_sample_size = 0;        p_demux_track->p_sample_size =            calloc( p_demux_track->i_sample_count, sizeof( uint32_t ) );        for( i_sample = 0; i_sample < p_demux_track->i_sample_count; i_sample++ )        {            p_demux_track->p_sample_size[i_sample] =                    p_stsz->data.p_stsz->i_entry_size[i_sample];        }    }    /* we have extract all information from stsz,        now use stts */    /* if we don't want to waste too much memory, we can't expand       the box !, so each chunk will contain an "extract" of this table       for fast research */    i_last_dts = 0;    i_index = 0; i_index_sample_used =0;    /* create and init last data for each chunk */    for(i_chunk = 0 ; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )    {        int64_t i_entry, i_sample_count, i;        /* save last dts */        p_demux_track->chunk[i_chunk].i_first_dts = i_last_dts;    /* count how many entries needed for this chunk       for p_sample_delta_dts and p_sample_count_dts */        i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count;        i_entry = 0;        while( i_sample_count > 0 )        {            i_sample_count -= p_stts->data.p_stts->i_sample_count[i_index+i_entry];            if( i_entry == 0 )            {                i_sample_count += i_index_sample_used; /* don't count already used sample                                                   int this entry */            }            i_entry++;        }        /* allocate them */        p_demux_track->chunk[i_chunk].p_sample_count_dts =            calloc( i_entry, sizeof( uint32_t ) );        p_demux_track->chunk[i_chunk].p_sample_delta_dts =            calloc( i_entry, sizeof( uint32_t ) );        /* now copy */        i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count;        for( i = 0; i < i_entry; i++ )        {            int64_t i_used;            int64_t i_rest;            i_rest = p_stts->data.p_stts->i_sample_count[i_index] - i_index_sample_used;            i_used = __MIN( i_rest, i_sample_count );            i_index_sample_used += i_used;            i_sample_count -= i_used;            p_demux_track->chunk[i_chunk].p_sample_count_dts[i] = i_used;            p_demux_track->chunk[i_chunk].p_sample_delta_dts[i] =                        p_stts->data.p_stts->i_sample_delta[i_index];            i_last_dts += i_used *                    p_demux_track->chunk[i_chunk].p_sample_delta_dts[i];            if( i_index_sample_used >=                             p_stts->data.p_stts->i_sample_count[i_index] )            {                i_index++;                i_index_sample_used = 0;            }        }    }    msg_Dbg( p_input,             "track[Id 0x%x] read %d samples length:"I64Fd"s",             p_demux_track->i_track_ID,             p_demux_track->i_sample_count,             i_last_dts / p_demux_track->i_timescale );    return( VLC_SUCCESS );}/* * TrackCreateES: *  Create ES and PES to init decoder if needed, for a track starting at i_chunk */static int  TrackCreateES   ( input_thread_t   *p_input,                              mp4_track_t *p_track,                              unsigned int     i_chunk,                              es_out_id_t      **pp_es ){    MP4_Box_t   *p_sample;    MP4_Box_t   *p_esds;    *pp_es = NULL;    if( !p_track->chunk[i_chunk].i_sample_description_index )    {        msg_Warn( p_input,                  "invalid SampleEntry index (track[Id 0x%x])",                  p_track->i_track_ID );        return VLC_EGENERIC;    }    p_sample = MP4_BoxGet(  p_track->p_stsd, "[%d]",                p_track->chunk[i_chunk].i_sample_description_index - 1 );    if( !p_sample || !p_sample->data.p_data )    {        msg_Warn( p_input,                  "cannot find SampleEntry (track[Id 0x%x])",                  p_track->i_track_ID );        return( VLC_EGENERIC );    }    p_track->p_sample = p_sample;    if( p_track->i_sample_size == 1 )    {        MP4_Box_data_sample_soun_t *p_soun;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -