asf.c

来自「VLC媒体播放程序」· C语言 代码 · 共 830 行 · 第 1/2 页

C
830
字号
/***************************************************************************** * asf.c : ASF demux module ***************************************************************************** * Copyright (C) 2002-2003 VideoLAN * $Id: asf.c,v 1.51 2004/01/31 05:27:02 fenrir Exp $ * * Authors: Laurent Aimar <fenrir@via.ecp.fr> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#include <stdlib.h>                                      /* malloc(), free() */#include <vlc/vlc.h>#include <vlc/input.h>#include "vlc_meta.h"#include "codecs.h"                        /* BITMAPINFOHEADER, WAVEFORMATEX */#include "libasf.h"/***************************************************************************** * Module descriptor *****************************************************************************/static int  Open  ( vlc_object_t * );static void Close ( vlc_object_t * );vlc_module_begin();    set_description( _("ASF v1.0 demuxer") );    set_capability( "demux", 200 );    set_callbacks( Open, Close );    add_shortcut( "asf" );vlc_module_end();/***************************************************************************** * Local prototypes *****************************************************************************/static int Demux  ( input_thread_t * );static int Control( input_thread_t *, int i_query, va_list args );typedef struct asf_stream_s{    int i_cat;    es_out_id_t     *p_es;    asf_object_stream_properties_t *p_sp;    mtime_t i_time;    block_t         *p_frame; /* use to gather complete frame */} asf_stream_t;struct demux_sys_t{    mtime_t             i_time;     /* 祍 */    mtime_t             i_length;   /* length of file file */    asf_object_root_t            *p_root;    asf_object_file_properties_t *p_fp;    unsigned int        i_streams;    asf_stream_t        *stream[128];    int64_t             i_data_begin;    int64_t             i_data_end;    vlc_meta_t          *meta;};static mtime_t  GetMoviePTS( demux_sys_t * );static int      DemuxPacket( input_thread_t *, vlc_bool_t b_play_audio );/***************************************************************************** * Open: check file and initializes ASF structures *****************************************************************************/static int Open( vlc_object_t * p_this ){    input_thread_t  *p_input = (input_thread_t *)p_this;    uint8_t         *p_peek;    guid_t          guid;    demux_sys_t     *p_sys;    unsigned int    i_stream, i;    asf_object_content_description_t *p_cd;    vlc_bool_t      b_seekable;    /* a little test to see if it could be a asf stream */    if( input_Peek( p_input, &p_peek, 16 ) < 16 )    {        msg_Warn( p_input, "ASF plugin discarded (cannot peek)" );        return VLC_EGENERIC;    }    ASF_GetGUID( &guid, p_peek );    if( !ASF_CmpGUID( &guid, &asf_object_header_guid ) )    {        msg_Warn( p_input, "ASF plugin discarded (not a valid file)" );        return VLC_EGENERIC;    }    /* Set p_input field */    p_input->pf_demux         = Demux;    p_input->pf_demux_control = Control;    p_input->p_demux_data = p_sys = malloc( sizeof( demux_sys_t ) );    memset( p_sys, 0, sizeof( demux_sys_t ) );    p_sys->i_time = -1;    p_sys->i_length = 0;    /* Now load all object ( except raw data ) */    stream_Control( p_input->s, STREAM_CAN_FASTSEEK, &b_seekable );    if( (p_sys->p_root = ASF_ReadObjectRoot( p_input->s, b_seekable )) == NULL )    {        msg_Warn( p_input, "ASF plugin discarded (not a valid file)" );        free( p_sys );        return VLC_EGENERIC;    }    p_sys->p_fp = p_sys->p_root->p_fp;    if( p_sys->p_fp->i_min_data_packet_size != p_sys->p_fp->i_max_data_packet_size )    {        msg_Warn( p_input,                  "ASF plugin discarded (invalid file_properties object)" );        goto error;    }    p_sys->i_streams = ASF_CountObject( p_sys->p_root->p_hdr,                                          &asf_object_stream_properties_guid );    if( !p_sys->i_streams )    {        msg_Warn( p_input, "ASF plugin discarded (cannot find any stream!)" );        goto error;    }    msg_Dbg( p_input, "found %d streams", p_sys->i_streams );    vlc_mutex_lock( &p_input->stream.stream_lock );    if( input_InitStream( p_input, 0 ) == -1)    {        vlc_mutex_unlock( &p_input->stream.stream_lock );        msg_Err( p_input, "cannot init stream" );        goto error;    }    p_input->stream.i_mux_rate = 0 ; /* updated later */    vlc_mutex_unlock( &p_input->stream.stream_lock );    for( i_stream = 0; i_stream < p_sys->i_streams; i_stream ++ )    {        asf_stream_t    *p_stream;        asf_object_stream_properties_t *p_sp;        p_sp = ASF_FindObject( p_sys->p_root->p_hdr,                               &asf_object_stream_properties_guid,                               i_stream );        p_stream =            p_sys->stream[p_sp->i_stream_number] =                malloc( sizeof( asf_stream_t ) );        memset( p_stream, 0, sizeof( asf_stream_t ) );        p_stream->i_time = -1;        p_stream->p_sp = p_sp;        p_stream->p_es = NULL;        p_stream->p_frame = NULL;        if( ASF_CmpGUID( &p_sp->i_stream_type, &asf_object_stream_type_audio ) &&            p_sp->i_type_specific_data_length >= sizeof( WAVEFORMATEX ) - 2 )        {            es_format_t  fmt;            uint8_t      *p_data = p_sp->p_type_specific_data;            es_format_Init( &fmt, AUDIO_ES, 0 );            wf_tag_to_fourcc( GetWLE( &p_data[0] ), &fmt.i_codec, NULL );            fmt.audio.i_channels        = GetWLE(  &p_data[2] );            fmt.audio.i_rate      = GetDWLE( &p_data[4] );            fmt.i_bitrate         = GetDWLE( &p_data[8] ) * 8;            fmt.audio.i_blockalign      = GetWLE(  &p_data[12] );            fmt.audio.i_bitspersample   = GetWLE(  &p_data[14] );            if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) )            {                fmt.i_extra = __MIN( GetWLE( &p_data[16] ),                                     p_sp->i_type_specific_data_length - sizeof( WAVEFORMATEX ) );                fmt.p_extra = malloc( fmt.i_extra );                memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )], fmt.i_extra );            }            p_stream->i_cat = AUDIO_ES;            p_stream->p_es = es_out_Add( p_input->p_es_out, &fmt );            msg_Dbg( p_input,                    "added new audio stream(codec:0x%x,ID:%d)",                    GetWLE( p_data ), p_sp->i_stream_number );        }        else if( ASF_CmpGUID( &p_sp->i_stream_type, &asf_object_stream_type_video ) &&                 p_sp->i_type_specific_data_length >= 11 + sizeof( BITMAPINFOHEADER ) )        {            es_format_t  fmt;            uint8_t      *p_data = &p_sp->p_type_specific_data[11];            es_format_Init( &fmt, VIDEO_ES,                            VLC_FOURCC( p_data[16], p_data[17], p_data[18], p_data[19] ) );            fmt.video.i_width = GetDWLE( p_data + 4 );            fmt.video.i_height= GetDWLE( p_data + 8 );            if( p_sp->i_type_specific_data_length > 11 + sizeof( BITMAPINFOHEADER ) )            {                fmt.i_extra = __MIN( GetDWLE( p_data ),                                     p_sp->i_type_specific_data_length - 11 - sizeof( BITMAPINFOHEADER ) );                fmt.p_extra = malloc( fmt.i_extra );                memcpy( fmt.p_extra, &p_data[sizeof( BITMAPINFOHEADER )], fmt.i_extra );            }            p_stream->i_cat = VIDEO_ES;            p_stream->p_es = es_out_Add( p_input->p_es_out, &fmt );            msg_Dbg( p_input, "added new video stream(ID:%d)",                     p_sp->i_stream_number );        }        else        {            p_stream->i_cat = UNKNOWN_ES;            msg_Dbg( p_input, "ignoring unknown stream(ID:%d)",                     p_sp->i_stream_number );        }    }    p_sys->i_data_begin = p_sys->p_root->p_data->i_object_pos + 50;    if( p_sys->p_root->p_data->i_object_size != 0 )    { /* local file */        p_sys->i_data_end = p_sys->p_root->p_data->i_object_pos +                                    p_sys->p_root->p_data->i_object_size;    }    else    { /* live/broacast */        p_sys->i_data_end = -1;    }    /* go to first packet */    stream_Seek( p_input->s, p_sys->i_data_begin );    /* try to calculate movie time */    if( p_sys->p_fp->i_data_packets_count > 0 )    {        int64_t i_count;        int64_t i_size = stream_Size( p_input->s );        if( p_sys->i_data_end > 0 && i_size > p_sys->i_data_end )        {            i_size = p_sys->i_data_end;        }        /* real number of packets */        i_count = ( i_size - p_sys->i_data_begin ) /                  p_sys->p_fp->i_min_data_packet_size;        /* calculate the time duration in micro-s */        p_sys->i_length = (mtime_t)p_sys->p_fp->i_play_duration / 10 *                   (mtime_t)i_count /                   (mtime_t)p_sys->p_fp->i_data_packets_count;        if( p_sys->i_length > 0 )        {            p_input->stream.i_mux_rate =                i_size / 50 * (int64_t)1000000 / p_sys->i_length;        }    }    /* Create meta informations */    p_sys->meta = vlc_meta_New();    if( ( p_cd = ASF_FindObject( p_sys->p_root->p_hdr,                                 &asf_object_content_description_guid, 0 ) ) )    {        if( p_cd->psz_title && *p_cd->psz_title )        {            vlc_meta_Add( p_sys->meta, VLC_META_TITLE, p_cd->psz_title );        }        if( p_cd->psz_author && *p_cd->psz_author )        {             vlc_meta_Add( p_sys->meta, VLC_META_AUTHOR, p_cd->psz_author );        }        if( p_cd->psz_copyright && *p_cd->psz_copyright )        {            vlc_meta_Add( p_sys->meta, VLC_META_COPYRIGHT, p_cd->psz_copyright );        }        if( p_cd->psz_description && *p_cd->psz_description )        {            vlc_meta_Add( p_sys->meta, VLC_META_DESCRIPTION, p_cd->psz_description );        }        if( p_cd->psz_rating && *p_cd->psz_rating )        {            vlc_meta_Add( p_sys->meta, VLC_META_RATING, p_cd->psz_rating );        }    }    for( i_stream = 0, i = 0; i < 128; i++ )    {        asf_object_codec_list_t *p_cl = ASF_FindObject( p_sys->p_root->p_hdr,                                                        &asf_object_codec_list_guid, 0 );        if( p_sys->stream[i] )        {            vlc_meta_t *tk = vlc_meta_New();            TAB_APPEND( p_sys->meta->i_track, p_sys->meta->track, tk );            if( p_cl && i_stream < p_cl->i_codec_entries_count )            {                if( p_cl->codec[i_stream].psz_name &&                    *p_cl->codec[i_stream].psz_name )                {                    vlc_meta_Add( tk, VLC_META_CODEC_NAME,                                  p_cl->codec[i_stream].psz_name );                }                if( p_cl->codec[i_stream].psz_description &&                    *p_cl->codec[i_stream].psz_description )                {                    vlc_meta_Add( tk, VLC_META_CODEC_DESCRIPTION,                                  p_cl->codec[i_stream].psz_description );                }            }            i_stream++;        }    }    return VLC_SUCCESS;error:    ASF_FreeObjectRoot( p_input->s, p_sys->p_root );    free( p_sys );    return VLC_EGENERIC;}/***************************************************************************** * Demux: read packet and send them to decoders *****************************************************************************/static int Demux( input_thread_t *p_input ){    demux_sys_t *p_sys = p_input->p_demux_data;    vlc_bool_t b_play_audio;    int i;    /* catch seek from user */    if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )    {        int64_t i_offset;        msleep( p_input->i_pts_delay );        i_offset = stream_Tell( p_input->s ) - p_sys->i_data_begin;        if( i_offset  < 0 )        {            i_offset = 0;        }        if( i_offset % p_sys->p_fp->i_min_data_packet_size > 0 )        {            i_offset -= i_offset % p_sys->p_fp->i_min_data_packet_size;        }        if( stream_Seek( p_input->s, i_offset + p_sys->i_data_begin ) )        {            msg_Warn( p_input, "cannot resynch after seek (EOF?)" );            return -1;        }        p_sys->i_time = -1;        for( i = 0; i < 128 ; i++ )        {#define p_stream p_sys->stream[i]            if( p_stream )            {                p_stream->i_time = -1;            }#undef p_stream        }    }    /* Check if we need to send the audio data to decoder */    b_play_audio = !p_input->stream.control.b_mute;    for( ;; )    {        mtime_t i_length;        mtime_t i_time_begin = GetMoviePTS( p_sys );        int i_result;        if( p_input->b_die )        {            break;        }        if( ( i_result = DemuxPacket( p_input, b_play_audio ) ) <= 0 )        {            return i_result;        }        if( i_time_begin == -1 )        {

⌨️ 快捷键说明

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