mmstu.c

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

C
1,527
字号
/***************************************************************************** * mms.c: MMS access plug-in ***************************************************************************** * Copyright (C) 2001, 2002 VideoLAN * $Id: mmstu.c,v 1.9 2004/02/12 20:09:38 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>#include <sys/time.h>#include <sys/types.h>#include <sys/stat.h>#include <string.h>#include <errno.h>#include <fcntl.h>#include <vlc/vlc.h>#include <vlc/input.h>#ifdef HAVE_UNISTD_H#   include <unistd.h>#endif#ifdef WIN32#   include <winsock2.h>#   include <ws2tcpip.h>#   ifndef IN_MULTICAST#       define IN_MULTICAST(a) IN_CLASSD(a)#   endif#else#   include <sys/socket.h>#   include <netinet/in.h>#   if HAVE_ARPA_INET_H#      include <arpa/inet.h>#   elif defined( SYS_BEOS )#      include <net/netdb.h>#   endif#endif#include "network.h"#include "asf.h"#include "buffer.h"#include "mms.h"#include "mmstu.h"#undef MMS_DEBUG/**************************************************************************** * NOTES: *  MMSProtocole documentation found at http://get.to/sdp ****************************************************************************//***************************************************************************** * Local prototypes *****************************************************************************/int  E_( MMSTUOpen )  ( input_thread_t * );void E_( MMSTUClose ) ( input_thread_t * );static ssize_t Read( input_thread_t *, byte_t *, size_t );static void    Seek( input_thread_t *, off_t );static int  MMSOpen ( input_thread_t *, url_t *, int );static int  MMSStart( input_thread_t *, uint32_t );static int  MMSStop ( input_thread_t * );static void MMSClose( input_thread_t * );static int  mms_CommandRead( input_thread_t *p_input, int i_command1, int i_command2 );static int  mms_CommandSend( input_thread_t *, int, uint32_t, uint32_t, uint8_t *, int );static int  mms_HeaderMediaRead( input_thread_t *, int );static int  mms_ReceivePacket( input_thread_t * );/* * XXX DON'T FREE MY MEMORY !!! XXX * non mais :P *//* * Ok, ok, j'le ferai plus... *//* * Merci :)) *//* * Vous pourriez signer vos commentaires (m阭e si on voit bien qui peut * 閏rire ce genre de trucs :p), et 閏rire en anglais, bordel de * merde :p. */int  E_(MMSTUOpen)( input_thread_t *p_input ){    access_sys_t   *p_sys;    int             i_proto;    int             i_status;    vlc_value_t val;    /* *** allocate p_sys_data *** */    p_input->p_access_data = p_sys = malloc( sizeof( access_sys_t ) );    memset( p_sys, 0, sizeof( access_sys_t ) );    /* *** Parse URL and get server addr/port and path *** */    p_sys->p_url = E_( url_new )( p_input->psz_name );    if( *p_sys->p_url->psz_host == '\0' )    {        E_( url_free )( p_sys->p_url );        msg_Err( p_input, "invalid server name" );        return VLC_EGENERIC;    }    if( p_sys->p_url->i_port <= 0 )    {        p_sys->p_url->i_port = 1755;    }    /* *** connect to this server *** */    /* look at  requested protocol (udp/tcp) */    i_proto = MMS_PROTO_AUTO;    if( *p_input->psz_access )    {        if( !strncmp( p_input->psz_access, "mmsu", 4 ) )        {            i_proto = MMS_PROTO_UDP;        }        else if( !strncmp( p_input->psz_access, "mmst", 4 ) )        {            i_proto = MMS_PROTO_TCP;        }    }    /* connect */    if( i_proto == MMS_PROTO_AUTO )    {   /* first try with TCP */        if( ( i_status = MMSOpen( p_input, p_sys->p_url, MMS_PROTO_TCP ) ) )        {   /* then with UDP */            i_status = MMSOpen( p_input, p_sys->p_url, MMS_PROTO_UDP );        }    }    else    {        i_status = MMSOpen( p_input, p_sys->p_url, i_proto );    }    if( i_status )    {        msg_Err( p_input, "cannot connect to server" );        E_( url_free )( p_sys->p_url );        return VLC_EGENERIC;    }    msg_Dbg( p_input, "connected to %s:%d", p_sys->p_url->psz_host, p_sys->p_url->i_port );    /* *** 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;    /* *** finished to set some variable *** */    vlc_mutex_lock( &p_input->stream.stream_lock );    p_input->stream.b_pace_control = 0;    p_input->stream.p_selected_area->i_tell = 0;    /*     * i_flags_broadcast     *  yy xx ?? ??     *  broadcast    yy=0x02, xx= 0x00     *  pre-recorded yy=0x01, xx= 0x80 if video, 0x00 no video     */    if( p_sys->i_packet_count <= 0 && p_sys->asfh.i_data_packets_count > 0 )    {        p_sys->i_packet_count = p_sys->asfh.i_data_packets_count;    }    if( p_sys->i_packet_count <= 0 || ( p_sys->i_flags_broadcast >> 24 ) == 0x02 )    {        p_input->stream.b_seekable = 0;        p_input->stream.p_selected_area->i_size = 0;    }    else    {        p_input->stream.b_seekable = 1;        p_input->stream.p_selected_area->i_size =            p_sys->i_header +            p_sys->i_packet_count * p_sys->i_packet_length;    }    p_input->stream.i_method = INPUT_METHOD_NETWORK;    vlc_mutex_unlock( &p_input->stream.stream_lock );    /* *** Start stream *** */    if( MMSStart( p_input, 0xffffffff ) < 0 )    {        msg_Err( p_input, "cannot start stream" );        MMSClose( p_input );        E_( url_free )( p_sys->p_url );        return VLC_EGENERIC;    }    /* 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;}/***************************************************************************** * Close: free unused data structures *****************************************************************************/void E_(MMSTUClose)( input_thread_t *p_input ){    access_sys_t    *p_sys = p_input->p_access_data;    /* close connection with server */    MMSClose( p_input );    /* free memory */    E_( url_free )( p_sys->p_url );    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;    uint32_t    i_packet;    uint32_t    i_offset;    var_buffer_t    buffer;    if( i_pos < 0 )    {        return;    }    vlc_mutex_lock( &p_input->stream.stream_lock );    if( i_pos < p_sys->i_header)    {        if( p_sys->i_pos < p_sys->i_header )        {            /* no need to restart stream, it was already one             * or no stream was yet read */            p_sys->i_pos = i_pos;            return;        }        else        {            i_packet = 0xffffffff;            i_offset = 0;        }    }    else    {        i_packet = ( i_pos - p_sys->i_header ) / p_sys->i_packet_length;        i_offset = ( i_pos - p_sys->i_header ) % p_sys->i_packet_length;    }    msg_Dbg( p_input, "seeking to "I64Fd " (packet:%d)", i_pos, i_packet );    MMSStop( p_input );    msg_Dbg( p_input, "stream stopped (seek)" );    /* *** restart stream *** */    var_buffer_initwrite( &buffer, 0 );    var_buffer_add64( &buffer, 0 ); /* seek point in second */    var_buffer_add32( &buffer, 0xffffffff );    var_buffer_add32( &buffer, i_packet ); // begin from start    var_buffer_add8( &buffer, 0xff ); // stream time limit    var_buffer_add8( &buffer, 0xff ); //  on 3bytes ...    var_buffer_add8( &buffer, 0xff ); //    var_buffer_add8( &buffer, 0x00 ); // don't use limit    var_buffer_add32( &buffer, p_sys->i_media_packet_id_type );    mms_CommandSend( p_input, 0x07, p_sys->i_command_level, 0x0001ffff,                     buffer.p_data, buffer.i_data );    var_buffer_free( &buffer );    for( ;; )    {        mms_HeaderMediaRead( p_input, MMS_PACKET_CMD );        if( p_sys->i_command == 0x1e )        {            msg_Dbg( p_input, "received 0x1e (seek)" );            break;        }    }    for( ;; )    {        mms_HeaderMediaRead( p_input, MMS_PACKET_CMD );        if( p_sys->i_command == 0x05 )        {            msg_Dbg( p_input, "received 0x05 (seek)" );            break;        }    }    /* get a packet */    mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA );    msg_Dbg( p_input, "Streaming restarted" );    p_sys->i_media_used += i_offset;    p_sys->i_pos = i_pos;    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_data;    size_t      i_copy;    i_data = 0;    /* *** send header if needed ** */    if( p_sys->i_pos < p_sys->i_header )    {        i_copy = __MIN( i_len, p_sys->i_header - p_sys->i_pos );        if( i_copy > 0 )        {            memcpy( p_buffer,                    p_sys->p_header + p_sys->i_pos,                    i_copy );        }        i_data += i_copy;    }    /* *** now send data if needed *** */    while( i_data < i_len )    {        if( p_sys->i_media_used < p_sys->i_media )        {            i_copy = __MIN( i_len - i_data ,                            p_sys->i_media - p_sys->i_media_used );            memcpy( p_buffer + i_data,                    p_sys->p_media + p_sys->i_media_used,                    i_copy );            i_data += i_copy;            p_sys->i_media_used += i_copy;        }        else if( p_sys->p_media != NULL &&                 p_sys->i_media_used < p_sys->i_packet_length )        {            i_copy = __MIN( i_len - i_data,                            p_sys->i_packet_length - p_sys->i_media_used);            memset( p_buffer + i_data, 0, i_copy );            i_data += i_copy;            p_sys->i_media_used += i_copy;        }        else        {            if( p_sys->i_eos                 || mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA ) < 0 )            {                p_sys->i_pos += i_data;                return( i_data );            }        }    }    p_sys->i_pos += i_data;    return( i_data );}/**************************************************************************** * MMSOpen : Open a connection with the server over mmst or mmsu ****************************************************************************/static int MMSOpen( input_thread_t  *p_input, url_t *p_url, int  i_proto ){    access_sys_t    *p_sys = p_input->p_access_data;    int             b_udp = ( i_proto == MMS_PROTO_UDP ) ? 1 : 0;    var_buffer_t buffer;    char         tmp[4096];    uint16_t     *p;    int          i_server_version;    int          i_tool_version;    int          i_update_player_url;    int          i_encryption_type;    int          i;    int          i_streams;    int          i_first;    /* *** Open a TCP connection with server *** */    msg_Dbg( p_input, "waiting for connection..." );    p_sys->socket_tcp.i_handle = net_OpenTCP( p_input, p_url->psz_host, p_url->i_port );    if( p_sys->socket_tcp.i_handle < 0 )    {        msg_Err( p_input, "failed to open a connection (tcp)" );        return VLC_EGENERIC;    }    p_input->i_mtu = 0;    msg_Dbg( p_input,             "connection(tcp) with \"%s:%d\" successful",             p_url->psz_host,             p_url->i_port );    /* *** Bind port if UDP protocol is selected *** */    if( b_udp )    {        struct sockaddr_in name;        socklen_t i_namelen = sizeof( struct sockaddr_in );        if( getsockname( p_sys->socket_tcp.i_handle,                         (struct sockaddr*)&name, &i_namelen ) < 0 )        {            msg_Err( p_input, "for udp you have to provide bind address (mms://<server_addr>@<bind_addr/<path> (FIXME)" );            net_Close( p_sys->socket_tcp.i_handle );            return VLC_EGENERIC;        }        p_sys->psz_bind_addr = inet_ntoa( name.sin_addr );        p_sys->socket_udp.i_handle = net_OpenUDP( p_input, p_sys->psz_bind_addr, 7000, "", 0 );        if( p_sys->socket_udp.i_handle < 0 )        {            msg_Err( p_input, "failed to open a connection (udp)" );            net_Close( p_sys->socket_tcp.i_handle );            return VLC_EGENERIC;        }        msg_Dbg( p_input,                 "connection(udp) at \"%s:%d\" successful",                 p_sys->psz_bind_addr, 7000 );    }    else    {        p_sys->psz_bind_addr = NULL;    }    /* *** Init context for mms prototcol *** */    E_( GenerateGuid )( &p_sys->guid );    /* used to identify client by server */    msg_Dbg( p_input,             "generated guid: "GUID_FMT,             GUID_PRINT( p_sys->guid ) );    p_sys->i_command_level = 1;          /* updated after 0x1A command */    p_sys->i_seq_num = 0;    p_sys->i_media_packet_id_type  = 0x04;    p_sys->i_header_packet_id_type = 0x02;    p_sys->i_proto = i_proto;    p_sys->i_packet_seq_num = 0;    p_sys->p_header = NULL;    p_sys->i_header = 0;    p_sys->p_media = NULL;    p_sys->i_media = 0;    p_sys->i_media_used = 0;    p_sys->i_pos = 0;    p_sys->i_buffer_tcp = 0;    p_sys->i_buffer_udp = 0;    p_sys->p_cmd = NULL;    p_sys->i_cmd = 0;    p_sys->i_eos = 0;    /* *** send command 1 : connection request *** */    var_buffer_initwrite( &buffer, 0 );    var_buffer_add16( &buffer, 0x001c );    var_buffer_add16( &buffer, 0x0003 );    sprintf( tmp,             "NSPlayer/7.0.0.1956; {"GUID_FMT"}; Host: %s",             GUID_PRINT( p_sys->guid ),             p_url->psz_host );    var_buffer_addUTF16( &buffer, tmp );    mms_CommandSend( p_input,                     0x01,          /* connexion request */                     0x00000000,    /* flags, FIXME */                     0x0004000b,    /* ???? */                     buffer.p_data,                     buffer.i_data );    if( mms_CommandRead( p_input, 0x01, 0 ) < 0 )    {        var_buffer_free( &buffer );        MMSClose( p_input );

⌨️ 快捷键说明

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