mmsh.c

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

C
861
字号
/***************************************************************************** * mmsh.c: ***************************************************************************** * Copyright (C) 2001, 2002 VideoLAN * $Id: mmsh.c,v 1.8 2004/01/26 16:30:34 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. *****************************************************************************//* * TODO: *  * http_proxy * *//***************************************************************************** * Preamble *****************************************************************************/#include <stdlib.h>#include <vlc/vlc.h>#include <vlc/input.h>#include "network.h"#include "asf.h"#include "buffer.h"#include "mms.h"#include "mmsh.h"/***************************************************************************** * Local prototypes *****************************************************************************/int  E_(MMSHOpen)  ( input_thread_t * );void E_(MMSHClose) ( input_thread_t * );static ssize_t Read( input_thread_t *, byte_t *, size_t );static void    Seek( input_thread_t *, off_t );static ssize_t NetFill( input_thread_t *, access_sys_t *, int );static int  mmsh_start     ( input_thread_t *, off_t );static void mmsh_stop      ( input_thread_t * );static int  mmsh_get_packet( input_thread_t *, chunk_t * );static http_answer_t *http_answer_parse( uint8_t *, int );static void           http_answer_free ( http_answer_t * );static http_field_t  *http_field_find  ( http_field_t *, char * );static int chunk_parse( chunk_t *, uint8_t *, int );/**************************************************************************** * Open: connect to ftp server and ask for file ****************************************************************************/int  E_( MMSHOpen )  ( input_thread_t *p_input ){    access_sys_t    *p_sys;    uint8_t         *p;    http_answer_t   *p_ans;    http_field_t    *p_field;    chunk_t         ck;    vlc_value_t     val;    /* init p_sys */    p_input->p_access_data = p_sys = malloc( sizeof( access_sys_t ) );    p_sys->i_proto = MMS_PROTO_HTTP;    p_sys->fd       = -1;    p_sys->i_request_context = 1;    p_sys->i_buffer = 0;    p_sys->i_buffer_pos = 0;    p_sys->b_broadcast = VLC_TRUE;    p_sys->p_packet = NULL;    p_sys->i_packet_sequence = 0;    p_sys->i_packet_used = 0;    p_sys->i_packet_length = 0;    p_sys->i_pos = 0;    p_sys->i_request_context = 1;    E_( GenerateGuid )( &p_sys->guid );    /* open a tcp connection */    p_sys->p_url = E_( url_new )( p_input->psz_name );    if( *p_sys->p_url->psz_host == '\0' )    {        msg_Err( p_input, "invalid server addresse" );        goto exit_error;    }    if( p_sys->p_url->i_port <= 0 )    {        p_sys->p_url->i_port = 80;    }    if( ( p_sys->fd = net_OpenTCP( p_input, p_sys->p_url->psz_host,                                            p_sys->p_url->i_port ) ) < 0 )    {        msg_Err( p_input, "cannot connect" );        goto exit_error;    }    /* *** send first request *** */    p = &p_sys->buffer[0];    p += sprintf( p, "GET %s HTTP/1.0\r\n", p_sys->p_url->psz_path );    p += sprintf( p,"Accept: */*\r\n" );    p += sprintf( p, "User-Agent: NSPlayer/4.1.0.3856\r\n" );    p += sprintf( p, "Host: %s:%d\r\n",                  p_sys->p_url->psz_host, p_sys->p_url->i_port );    p += sprintf( p, "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=0:0,request-context=%d,max-duration=0\r\n",                  p_sys->i_request_context++ );    p += sprintf( p, "Pragma: xClientGUID={"GUID_FMT"}\r\n",                  GUID_PRINT( p_sys->guid ) );    p += sprintf( p, "Connection: Close\r\n\r\n" );    net_Write( p_input, p_sys->fd, p_sys->buffer,  p - p_sys->buffer );    if( NetFill ( p_input, p_sys, BUFFER_SIZE ) <= 0 )    {        msg_Err( p_input, "cannot read answer" );        goto exit_error;    }    net_Close( p_sys->fd ); p_sys->fd = -1;    p_ans = http_answer_parse( p_sys->buffer, p_sys->i_buffer );    if( !p_ans )    {        msg_Err( p_input, "cannot parse answer" );        goto exit_error;    }    if( p_ans->i_error >= 400 )    {        msg_Err( p_input, "error %d (server return=`%s')",                 p_ans->i_error, p_ans->psz_answer );        http_answer_free( p_ans );        goto exit_error;    }    else if( p_ans->i_error >= 300 )    {        msg_Err( p_input, "FIXME redirect unsuported %d (server return=`%s')",                 p_ans->i_error, p_ans->psz_answer );        http_answer_free( p_ans );        goto exit_error;    }    else if( p_ans->i_body <= 0 )    {        msg_Err( p_input, "empty answer" );        http_answer_free( p_ans );        goto exit_error;    }    /* now get features */    /* FIXME FIXME test Content-Type to see if it's a plain stream or an     * asx FIXME */    for( p_field = p_ans->p_fields;         p_field != NULL;         p_field = http_field_find( p_field->p_next, "Pragma" ) )    {        if( !strncasecmp( p_field->psz_value, "features", 8 ) )        {            if( strstr( p_field->psz_value, "broadcast" ) )            {                msg_Dbg( p_input, "stream type = broadcast" );                p_sys->b_broadcast = VLC_TRUE;            }            else if( strstr( p_field->psz_value, "seekable" ) )            {                msg_Dbg( p_input, "stream type = seekable" );                p_sys->b_broadcast = VLC_FALSE;            }            else            {                msg_Warn( p_input, "unknow stream types (%s)",                          p_field->psz_value );                p_sys->b_broadcast = VLC_FALSE;            }        }    }    /* gather header */    p_sys->i_header = 0;    p_sys->p_header = malloc( p_ans->i_body );    do    {        if( chunk_parse( &ck, p_ans->p_body, p_ans->i_body ) )        {            msg_Err( p_input, "invalid chunk answer" );            goto exit_error;        }        if( ck.i_type != 0x4824 )        {            msg_Err( p_input, "invalid chunk (0x%x)", ck.i_type );            break;        }        if( ck.i_data > 0 )        {            memcpy( &p_sys->p_header[p_sys->i_header],                    ck.p_data,                    ck.i_data );            p_sys->i_header += ck.i_data;        }        /* BEURK */        p_ans->p_body   += 12 + ck.i_data;        p_ans->i_body   -= 12 + ck.i_data;    } while( p_ans->i_body > 12 );    http_answer_free( p_ans );    msg_Dbg( p_input, "complete header size=%d", p_sys->i_header );    if( p_sys->i_header <= 0 )    {        msg_Err( p_input, "header size == 0" );        goto exit_error;    }    /* *** parse header and get stream and their id *** */    /* get all streams properties,     *     * TODO : stream bitrates properties(optional)     *        and bitrate mutual exclusion(optional) */    E_( asf_HeaderParse )( &p_sys->asfh,                           p_sys->p_header, p_sys->i_header );    msg_Dbg( p_input, "packet count=%lld packet size=%d",             p_sys->asfh.i_data_packets_count,             p_sys->asfh.i_min_data_packet_size );    E_( asf_StreamSelect)( &p_sys->asfh,                           config_GetInt( p_input, "mms-maxbitrate" ),                           config_GetInt( p_input, "mms-all" ),                           config_GetInt( p_input, "audio" ),                           config_GetInt( p_input, "video" ) );    if( mmsh_start( p_input, 0 ) )    {        msg_Err( p_input, "cannot start stream" );        goto exit_error;    }    /* *** set exported functions *** */    p_input->pf_read = Read;    p_input->pf_seek = Seek;    p_input->pf_set_program = input_SetProgram;    p_input->pf_set_area = NULL;    p_input->p_private = NULL;    p_input->i_mtu = 3 * p_sys->asfh.i_min_data_packet_size;    /* *** finished to set some variable *** */    vlc_mutex_lock( &p_input->stream.stream_lock );    p_input->stream.b_pace_control = 0;    if( p_sys->b_broadcast )    {        p_input->stream.p_selected_area->i_size = 0;        p_input->stream.b_seekable = 0;    }    else    {        p_input->stream.p_selected_area->i_size = p_sys->asfh.i_file_size;        p_input->stream.b_seekable = 1;    }    p_input->stream.p_selected_area->i_tell = 0;    p_input->stream.i_method = INPUT_METHOD_NETWORK;    vlc_mutex_unlock( &p_input->stream.stream_lock );    /* Update default_pts to a suitable value for mms access */    var_Get( p_input, "mms-caching", &val );    p_input->i_pts_delay = val.i_int * 1000;    return VLC_SUCCESS;exit_error:    E_( url_free )( p_sys->p_url );    if( p_sys->fd > 0 )    {        net_Close( p_sys->fd  );    }    free( p_sys );    return VLC_EGENERIC;}/***************************************************************************** * Close: free unused data structures *****************************************************************************/void E_( MMSHClose ) ( input_thread_t *p_input ){    access_sys_t    *p_sys   = p_input->p_access_data;    msg_Dbg( p_input, "stopping stream" );    mmsh_stop( p_input );    free( p_sys );}/***************************************************************************** * Seek: try to go at the right place *****************************************************************************/static void Seek( input_thread_t * p_input, off_t i_pos ){    access_sys_t *p_sys = p_input->p_access_data;    chunk_t      ck;    off_t        i_offset;    off_t        i_packet;    i_packet = ( i_pos - p_sys->i_header ) / p_sys->asfh.i_min_data_packet_size;    i_offset = ( i_pos - p_sys->i_header ) % p_sys->asfh.i_min_data_packet_size;    msg_Dbg( p_input, "seeking to "I64Fd, i_pos );    vlc_mutex_lock( &p_input->stream.stream_lock );    mmsh_stop( p_input );    mmsh_start( p_input, i_packet * p_sys->asfh.i_min_data_packet_size );    for( ;; )    {        if( mmsh_get_packet( p_input, &ck ) )        {            break;        }        /* skip headers */        if( ck.i_type != 0x4824 )        {            break;        }        msg_Warn( p_input, "skipping header" );    }    p_sys->i_pos = i_pos;    p_sys->i_packet_used += i_offset;    p_input->stream.p_selected_area->i_tell = i_pos;    vlc_mutex_unlock( &p_input->stream.stream_lock );}/***************************************************************************** * Read: *****************************************************************************/static ssize_t Read        ( input_thread_t * p_input, byte_t * p_buffer,                             size_t i_len ){    access_sys_t *p_sys = p_input->p_access_data;    size_t       i_copy;    size_t       i_data = 0;    while( i_data < i_len )    {        if( p_sys->i_packet_used < p_sys->i_packet_length )        {            i_copy = __MIN( p_sys->i_packet_length - p_sys->i_packet_used,                            i_len - i_data );            memcpy( &p_buffer[i_data],                    &p_sys->p_packet[p_sys->i_packet_used],                    i_copy );            i_data += i_copy;            p_sys->i_packet_used += i_copy;        }        else if( p_sys->i_pos + i_data > p_sys->i_header &&                 (int)p_sys->i_packet_used < p_sys->asfh.i_min_data_packet_size )        {            i_copy = __MIN( p_sys->asfh.i_min_data_packet_size - p_sys->i_packet_used,                            i_len - i_data );            memset( &p_buffer[i_data], 0, i_copy );            i_data += i_copy;            p_sys->i_packet_used += i_copy;        }        else        {            chunk_t ck;            /* get a new packet */            /* fill enought data (>12) */            msg_Dbg( p_input, "waiting data (buffer = %d bytes)",                     p_sys->i_buffer );            if( mmsh_get_packet( p_input, &ck ) )            {                return 0;            }        }    }    p_sys->i_pos += i_data;    return( i_data );}/***************************************************************************** * NetFill: *****************************************************************************/static ssize_t NetFill( input_thread_t *p_input, access_sys_t *p_sys, int i_size ){    int i_try   = 0;    int i_total = 0;    i_size = __MIN( i_size, BUFFER_SIZE - p_sys->i_buffer );    if( i_size <= 0 )    {        return 0;    }    for( ;; )    {        int i_read;        i_read = net_Read( p_input, p_sys->fd,                          &p_sys->buffer[p_sys->i_buffer], i_size, VLC_FALSE );        if( i_read == 0 )        {

⌨️ 快捷键说明

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