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 + -
显示快捷键?