📄 mmstu.c
字号:
/***************************************************************************** * mms.c: MMS access plug-in ***************************************************************************** * Copyright (C) 2001, 2002 the VideoLAN team * $Id: 72c817e1a0f1944f56146dcbb9dd9882c589334d $ * * 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 <errno.h>#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#ifdef HAVE_FCNTL_H# include <fcntl.h>#endif#ifdef HAVE_SYS_TIME_H# include <sys/time.h>#endif#ifdef HAVE_SYS_TYPES_H# include <sys/types.h>#endif#ifdef HAVE_SYS_STAT_H# include <sys/stat.h>#endif#ifdef HAVE_POLL# include <poll.h>#endif#include <vlc_network.h>#include "vlc_url.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 MMSTUOpen ( access_t * );void MMSTUClose ( access_t * );static ssize_t Read( access_t *, uint8_t *, size_t );static int Seek( access_t *, int64_t );static int Control( access_t *, int, va_list );static int MMSOpen ( access_t *, vlc_url_t *, int );static int MMSStart( access_t *, uint32_t );static int MMSStop ( access_t * );static void MMSClose( access_t * );static int mms_CommandRead( access_t *p_access, int i_command1, int i_command2 );static int mms_CommandSend( access_t *, int, uint32_t, uint32_t, uint8_t *, int );static int mms_HeaderMediaRead( access_t *, int );static int mms_ReceivePacket( access_t * );static void* KeepAliveThread( vlc_object_t *p_this );int MMSTUOpen( access_t *p_access ){ access_sys_t *p_sys; int i_proto; int i_status; /* 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_timeout = var_CreateGetInteger( p_access, "mms-timeout" ); vlc_mutex_init( &p_sys->lock_netwrite ); /* *** Parse URL and get server addr/port and path *** */ 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 server name" ); vlc_UrlClean( &p_sys->url ); vlc_mutex_destroy( &p_sys->lock_netwrite ); free( p_sys ); return VLC_EGENERIC; } if( p_sys->url.i_port <= 0 ) { p_sys->url.i_port = 1755; } /* *** connect to this server *** */ /* look at requested protocol (udp/tcp) */ i_proto = MMS_PROTO_AUTO; if( *p_access->psz_access ) { if( !strncmp( p_access->psz_access, "mmsu", 4 ) ) { i_proto = MMS_PROTO_UDP; } else if( !strncmp( p_access->psz_access, "mmst", 4 ) ) { i_proto = MMS_PROTO_TCP; } } /* connect */ if( i_proto == MMS_PROTO_AUTO ) { /* first try with TCP and then UDP*/ if( ( i_status = MMSOpen( p_access, &p_sys->url, MMS_PROTO_TCP ) ) ) { i_status = MMSOpen( p_access, &p_sys->url, MMS_PROTO_UDP ); } } else { i_status = MMSOpen( p_access, &p_sys->url, i_proto ); } if( i_status ) { msg_Err( p_access, "cannot connect to server" ); vlc_UrlClean( &p_sys->url ); vlc_mutex_destroy( &p_sys->lock_netwrite ); free( p_sys ); return VLC_EGENERIC; } msg_Dbg( p_access, "connected to %s:%d", p_sys->url.psz_host, p_sys->url.i_port ); /* * 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_sys->b_seekable = false; } else { p_sys->b_seekable = true; p_access->info.i_size = (uint64_t)p_sys->i_header + (uint64_t)p_sys->i_packet_count * (uint64_t)p_sys->i_packet_length; } /* *** Start stream *** */ if( MMSStart( p_access, 0xffffffff ) < 0 ) { msg_Err( p_access, "cannot start stream" ); MMSTUClose ( p_access ); return VLC_EGENERIC; } /* Keep the connection alive when paused */ p_sys->p_keepalive_thread = vlc_object_create( p_access, sizeof( mmstu_keepalive_thread_t ) ); p_sys->p_keepalive_thread->p_access = p_access; p_sys->p_keepalive_thread->b_paused = false; p_sys->p_keepalive_thread->b_thread_error = false; if( vlc_thread_create( p_sys->p_keepalive_thread, "mmstu keepalive thread", KeepAliveThread, VLC_THREAD_PRIORITY_LOW, false) ) p_sys->p_keepalive_thread->b_thread_error = true; return VLC_SUCCESS;}/***************************************************************************** * Close: free unused data structures *****************************************************************************/void MMSTUClose( access_t *p_access ){ access_sys_t *p_sys = p_access->p_sys; if( p_sys->p_keepalive_thread ) { vlc_object_kill( p_sys->p_keepalive_thread ); if( !p_sys->p_keepalive_thread->b_thread_error ) vlc_thread_join( p_sys->p_keepalive_thread ); vlc_object_release( p_sys->p_keepalive_thread ); } /* close connection with server */ MMSClose( p_access ); /* free memory */ vlc_UrlClean( &p_sys->url ); vlc_mutex_destroy( &p_sys->lock_netwrite ); 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; vlc_value_t val; switch( i_query ) { /* */ case ACCESS_CAN_SEEK: pb_bool = (bool*)va_arg( args, bool* ); *pb_bool = p_sys->b_seekable; break; case ACCESS_CAN_FASTSEEK: pb_bool = (bool*)va_arg( args, bool* ); *pb_bool = false; break; case ACCESS_CAN_PAUSE: pb_bool = (bool*)va_arg( args, bool* ); *pb_bool = true; break; case ACCESS_CAN_CONTROL_PACE: pb_bool = (bool*)va_arg( args, bool* );#if 0 /* Disable for now until we have a clock synchro algo * which works with something else than MPEG over UDP */ *pb_bool = false;#endif *pb_bool = true; break; /* */ case ACCESS_GET_MTU: pi_int = (int*)va_arg( args, int * ); *pi_int = 3 * p_sys->i_packet_length; break; case ACCESS_GET_PTS_DELAY: pi_64 = (int64_t*)va_arg( args, int64_t * ); var_Get( p_access, "mms-caching", &val ); *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 ) { MMSStop( p_access ); vlc_object_lock( p_sys->p_keepalive_thread ); p_sys->p_keepalive_thread->b_paused = true; vlc_object_unlock( p_sys->p_keepalive_thread ); } else { Seek( p_access, p_access->info.i_pos ); vlc_object_lock( p_sys->p_keepalive_thread ); p_sys->p_keepalive_thread->b_paused = false; vlc_object_unlock( p_sys->p_keepalive_thread ); } 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; uint32_t i_packet; uint32_t i_offset; var_buffer_t buffer; if( i_pos < 0 ) return VLC_EGENERIC; if( i_pos < p_sys->i_header) { if( p_access->info.i_pos < p_sys->i_header ) { /* no need to restart stream, it was already one * or no stream was yet read */ p_access->info.i_pos = i_pos; return VLC_SUCCESS; } 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_access, "seeking to %"PRId64 " (packet:%d)", i_pos, i_packet ); MMSStop( p_access ); msg_Dbg( p_access, "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_access, 0x07, p_sys->i_command_level, 0x0001ffff, buffer.p_data, buffer.i_data ); var_buffer_free( &buffer ); while( vlc_object_alive (p_access) ) { if( mms_HeaderMediaRead( p_access, MMS_PACKET_CMD ) < 0 ) { p_access->info.b_eof = true; return VLC_EGENERIC; } if( p_sys->i_command == 0x1e ) { msg_Dbg( p_access, "received 0x1e (seek)" ); break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -