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