📄 mmsh.c
字号:
/***************************************************************************** * mmsh.c: ***************************************************************************** * Copyright (C) 2001, 2002 the VideoLAN team * $Id: 87bb09b4382ddddb8dd460d6f029338c874523f5 $ * * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include <vlc_access.h>#include "vlc_strings.h"#include "vlc_input.h"#include <vlc_network.h>#include "vlc_url.h"#include "asf.h"#include "buffer.h"#include "mms.h"#include "mmsh.h"/* TODO: * - authentication *//***************************************************************************** * Local prototypes *****************************************************************************/int MMSHOpen ( access_t * );void MMSHClose ( access_t * );static ssize_t Read( access_t *, uint8_t *, size_t );static ssize_t ReadRedirect( access_t *, uint8_t *, size_t );static int Seek( access_t *, int64_t );static int Control( access_t *, int, va_list );static int Describe( access_t *, char **ppsz_location );static int Start( access_t *, int64_t );static void Stop( access_t * );static int GetPacket( access_t *, chunk_t * );static void GetHeader( access_t *p_access );static int Restart( access_t * );static int Reset( access_t * );//#define MMSH_USER_AGENT "NSPlayer/4.1.0.3856"#define MMSH_USER_AGENT "NSPlayer/7.10.0.3059"/**************************************************************************** * Open: connect to ftp server and ask for file ****************************************************************************/int MMSHOpen( access_t *p_access ){ access_sys_t *p_sys; char *psz_location = NULL; char *psz_proxy; /* init p_sys */ /* Set up p_access */ p_access->pf_read = Read; p_access->pf_block = NULL; p_access->pf_control = Control; p_access->pf_seek = Seek; p_access->info.i_update = 0; p_access->info.i_size = 0; p_access->info.i_pos = 0; p_access->info.b_eof = false; p_access->info.i_title = 0; p_access->info.i_seekpoint = 0; p_access->p_sys = p_sys = malloc( sizeof( access_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; memset( p_sys, 0, sizeof( access_sys_t ) ); p_sys->i_proto= MMS_PROTO_HTTP; p_sys->fd = -1; p_sys->i_start= 0; /* Handle proxy */ p_sys->b_proxy = false; memset( &p_sys->proxy, 0, sizeof(p_sys->proxy) ); /* Check proxy */ /* TODO reuse instead http-proxy from http access ? */ psz_proxy = var_CreateGetString( p_access, "mmsh-proxy" ); if( !*psz_proxy ) { char *psz_http_proxy = config_GetPsz( p_access, "http-proxy" ); if( psz_http_proxy && *psz_http_proxy ) { free( psz_proxy ); psz_proxy = psz_http_proxy; var_SetString( p_access, "mmsh-proxy", psz_proxy ); } else { free( psz_http_proxy ); } } if( *psz_proxy ) { p_sys->b_proxy = true; vlc_UrlParse( &p_sys->proxy, psz_proxy, 0 ); }#ifdef HAVE_GETENV else { char *psz_proxy = getenv( "http_proxy" ); if( psz_proxy && *psz_proxy ) { p_sys->b_proxy = true; vlc_UrlParse( &p_sys->proxy, psz_proxy, 0 ); } }#endif free( psz_proxy ); if( p_sys->b_proxy ) { if( ( p_sys->proxy.psz_host == NULL ) || ( *p_sys->proxy.psz_host == '\0' ) ) { msg_Warn( p_access, "invalid proxy host" ); vlc_UrlClean( &p_sys->proxy ); free( p_sys ); return VLC_EGENERIC; } if( p_sys->proxy.i_port <= 0 ) p_sys->proxy.i_port = 80; msg_Dbg( p_access, "Using http proxy %s:%d", p_sys->proxy.psz_host, p_sys->proxy.i_port ); } /* open a tcp connection */ vlc_UrlParse( &p_sys->url, p_access->psz_path, 0 ); if( ( p_sys->url.psz_host == NULL ) || ( *p_sys->url.psz_host == '\0' ) ) { msg_Err( p_access, "invalid host" ); vlc_UrlClean( &p_sys->proxy ); vlc_UrlClean( &p_sys->url ); free( p_sys ); return VLC_EGENERIC; } if( p_sys->url.i_port <= 0 ) p_sys->url.i_port = 80; if( Describe( p_access, &psz_location ) ) { vlc_UrlClean( &p_sys->proxy ); vlc_UrlClean( &p_sys->url ); free( p_sys ); return VLC_EGENERIC; } /* Handle redirection */ if( psz_location && *psz_location ) { msg_Dbg( p_access, "redirection to %s", psz_location ); input_thread_t * p_input = vlc_object_find( p_access, VLC_OBJECT_INPUT, FIND_PARENT ); input_item_t * p_new_loc; if( !p_input ) return VLC_EGENERIC; /** \bug we do not autodelete here */ p_new_loc = input_item_New( p_access, psz_location, psz_location ); input_item_AddSubItem( input_GetItem( p_input ), p_new_loc ); vlc_gc_decref( p_new_loc ); vlc_object_release( p_input ); free( psz_location ); p_access->pf_read = ReadRedirect; return VLC_SUCCESS; } /* Start playing */ if( Start( p_access, 0 ) ) { msg_Err( p_access, "cannot start stream" ); free( p_sys->p_header ); vlc_UrlClean( &p_sys->proxy ); vlc_UrlClean( &p_sys->url ); free( p_sys ); return VLC_EGENERIC; } if( !p_sys->b_broadcast ) { p_access->info.i_size = p_sys->asfh.i_file_size; } return VLC_SUCCESS;}/***************************************************************************** * Close: free unused data structures *****************************************************************************/void MMSHClose ( access_t *p_access ){ access_sys_t *p_sys = p_access->p_sys; Stop( p_access ); free( p_sys->p_header ); vlc_UrlClean( &p_sys->proxy ); vlc_UrlClean( &p_sys->url ); free( p_sys );}/***************************************************************************** * Control: *****************************************************************************/static int Control( access_t *p_access, int i_query, va_list args ){ access_sys_t *p_sys = p_access->p_sys; bool *pb_bool; bool b_bool; int *pi_int; int64_t *pi_64; int i_int; switch( i_query ) { /* */ case ACCESS_CAN_SEEK: pb_bool = (bool*)va_arg( args, bool* ); *pb_bool = !p_sys->b_broadcast; break; case ACCESS_CAN_FASTSEEK: pb_bool = (bool*)va_arg( args, bool* ); *pb_bool = false; break; case ACCESS_CAN_PAUSE: case ACCESS_CAN_CONTROL_PACE: pb_bool = (bool*)va_arg( args, bool* ); *pb_bool = true; break; /* */ case ACCESS_GET_MTU: pi_int = (int*)va_arg( args, int * ); *pi_int = 3 * p_sys->asfh.i_min_data_packet_size; break; case ACCESS_GET_PTS_DELAY: pi_64 = (int64_t*)va_arg( args, int64_t * ); *pi_64 = (int64_t)var_GetInteger( p_access, "mms-caching" ) * INT64_C(1000); break; case ACCESS_GET_PRIVATE_ID_STATE: i_int = (int)va_arg( args, int ); pb_bool = (bool *)va_arg( args, bool * ); if( (i_int < 0) || (i_int > 127) ) return VLC_EGENERIC; *pb_bool = p_sys->asfh.stream[i_int].i_selected ? true : false; break; /* */ case ACCESS_SET_PAUSE_STATE: b_bool = (bool)va_arg( args, int ); if( b_bool ) Stop( p_access ); else Seek( p_access, p_access->info.i_pos ); break; case ACCESS_GET_TITLE_INFO: case ACCESS_SET_TITLE: case ACCESS_SET_SEEKPOINT: case ACCESS_SET_PRIVATE_ID_STATE: case ACCESS_GET_CONTENT_TYPE: return VLC_EGENERIC; default: msg_Warn( p_access, "unimplemented query in control" ); return VLC_EGENERIC; } return VLC_SUCCESS;}/***************************************************************************** * Seek: try to go at the right place *****************************************************************************/static int Seek( access_t *p_access, int64_t i_pos ){ access_sys_t *p_sys = p_access->p_sys; chunk_t ck; off_t i_offset; off_t i_packet; msg_Dbg( p_access, "seeking to %"PRId64, i_pos ); 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; Stop( p_access ); Start( p_access, i_packet * p_sys->asfh.i_min_data_packet_size ); while( vlc_object_alive (p_access) ) { if( GetPacket( p_access, &ck ) ) break; /* skip headers */ if( ck.i_type != 0x4824 ) break; msg_Warn( p_access, "skipping header" ); } p_access->info.i_pos = i_pos; p_access->info.b_eof = false; p_sys->i_packet_used += i_offset; return VLC_SUCCESS;}/***************************************************************************** * Read: *****************************************************************************/static ssize_t ReadRedirect( access_t *p_access, uint8_t *p, size_t i_len ){ return 0;}/***************************************************************************** * Read: *****************************************************************************/static ssize_t Read( access_t *p_access, uint8_t *p_buffer, size_t i_len ){ access_sys_t *p_sys = p_access->p_sys; size_t i_copy; size_t i_data = 0; if( p_access->info.b_eof ) return 0; while( i_data < (size_t) i_len ) { if( p_access->info.i_pos < (p_sys->i_start + p_sys->i_header) ) { int i_offset = p_access->info.i_pos - p_sys->i_start; i_copy = __MIN( p_sys->i_header - i_offset, (int)((size_t)i_len - i_data) ); memcpy( &p_buffer[i_data], &p_sys->p_header[i_offset], i_copy ); i_data += i_copy; p_access->info.i_pos += i_copy; } else 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; p_access->info.i_pos += i_copy; } else if( (p_sys->i_packet_length > 0) && ((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; p_access->info.i_pos += i_copy; } else { chunk_t ck; if( GetPacket( p_access, &ck ) ) { int i_ret = -1; if( p_sys->b_broadcast ) { if( (ck.i_type == 0x4524) && (ck.i_sequence != 0) ) i_ret = Restart( p_access ); else if( ck.i_type == 0x4324 ) i_ret = Reset( p_access ); } if( i_ret ) { p_access->info.b_eof = true; return 0; } } if( ck.i_type != 0x4424 ) { p_sys->i_packet_used = 0; p_sys->i_packet_length = 0; } } } return( i_data );}/* */static int Restart( access_t *p_access ){ access_sys_t *p_sys = p_access->p_sys; char *psz_location = NULL; msg_Dbg( p_access, "Restart the stream" ); p_sys->i_start = p_access->info.i_pos; /* */ msg_Dbg( p_access, "stoping the stream" ); Stop( p_access ); /* */ msg_Dbg( p_access, "describe the stream" ); if( Describe( p_access, &psz_location ) ) { msg_Err( p_access, "describe failed" ); return VLC_EGENERIC; } /* */ if( Start( p_access, 0 ) ) { msg_Err( p_access, "Start failed" ); return VLC_EGENERIC; } return VLC_SUCCESS;}static int Reset( access_t *p_access ){ access_sys_t *p_sys = p_access->p_sys; asf_header_t old_asfh = p_sys->asfh; int i; msg_Dbg( p_access, "Reset the stream" ); p_sys->i_start = p_access->info.i_pos; /* */ p_sys->i_packet_sequence = 0; p_sys->i_packet_used = 0; p_sys->i_packet_length = 0; p_sys->p_packet = NULL; /* Get the next header FIXME memory loss ? */ GetHeader( p_access ); if( p_sys->i_header <= 0 ) return VLC_EGENERIC; asf_HeaderParse ( &p_sys->asfh, p_sys->p_header, p_sys->i_header ); msg_Dbg( p_access, "packet count=%"PRId64" packet size=%d", p_sys->asfh.i_data_packets_count, p_sys->asfh.i_min_data_packet_size ); asf_StreamSelect( &p_sys->asfh, var_CreateGetInteger( p_access, "mms-maxbitrate" ), var_CreateGetInteger( p_access, "mms-all" ), var_CreateGetInteger( p_access, "audio" ), var_CreateGetInteger( p_access, "video" ) ); /* Check we have comptible asfh */ for( i = 1; i < 128; i++ )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -