📄 mmsh.c
字号:
asf_stream_t *p_new = &p_sys->asfh.stream[i]; if( p_old->i_cat != p_new->i_cat || p_old->i_selected != p_new->i_selected ) break; } if( i < 128 ) { msg_Warn( p_access, "incompatible asf header, restart" ); return Restart( p_access ); } /* */ p_sys->i_packet_used = 0; p_sys->i_packet_length = 0; return VLC_SUCCESS;}static int OpenConnection( access_t *p_access ){ access_sys_t *p_sys = p_access->p_sys; vlc_url_t srv = p_sys->b_proxy ? p_sys->proxy : p_sys->url; if( ( p_sys->fd = net_ConnectTCP( p_access, srv.psz_host, srv.i_port ) ) < 0 ) { msg_Err( p_access, "cannot connect to %s:%d", srv.psz_host, srv.i_port ); return VLC_EGENERIC; } if( p_sys->b_proxy ) { net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL, "GET http://%s:%d%s HTTP/1.0\r\n", p_sys->url.psz_host, p_sys->url.i_port, ( (p_sys->url.psz_path == NULL) || (*p_sys->url.psz_path == '\0') ) ? "/" : p_sys->url.psz_path ); /* Proxy Authentication */ if( p_sys->proxy.psz_username && *p_sys->proxy.psz_username ) { char *buf; char *b64; if( asprintf( &buf, "%s:%s", p_sys->proxy.psz_username, p_sys->proxy.psz_password ? p_sys->proxy.psz_password : "" ) == -1 ) return VLC_ENOMEM; b64 = vlc_b64_encode( buf ); free( buf ); net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL, "Proxy-Authorization: Basic %s\r\n", b64 ); free( b64 ); } } else { net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL, "GET %s HTTP/1.0\r\n" "Host: %s:%d\r\n", ( (p_sys->url.psz_path == NULL) || (*p_sys->url.psz_path == '\0') ) ? "/" : p_sys->url.psz_path, p_sys->url.psz_host, p_sys->url.i_port ); } return VLC_SUCCESS;}/***************************************************************************** * Describe: *****************************************************************************/static int Describe( access_t *p_access, char **ppsz_location ){ access_sys_t *p_sys = p_access->p_sys; char *psz_location = NULL; char *psz; int i_code; /* Reinit context */ p_sys->b_broadcast = true; p_sys->i_request_context = 1; p_sys->i_packet_sequence = 0; p_sys->i_packet_used = 0; p_sys->i_packet_length = 0; p_sys->p_packet = NULL; GenerateGuid ( &p_sys->guid ); if( OpenConnection( p_access ) ) return VLC_EGENERIC; net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL, "Accept: */*\r\n" "User-Agent: "MMSH_USER_AGENT"\r\n" "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=0:0,request-context=%d,max-duration=0\r\n" "Pragma: xClientGUID={"GUID_FMT"}\r\n" "Connection: Close\r\n", p_sys->i_request_context++, GUID_PRINT( p_sys->guid ) ); if( net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL, "\r\n" ) < 0 ) { msg_Err( p_access, "failed to send request" ); goto error; } /* Receive the http header */ if( ( psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd, NULL ) ) == NULL ) { msg_Err( p_access, "failed to read answer" ); goto error; } if( strncmp( psz, "HTTP/1.", 7 ) ) { msg_Err( p_access, "invalid HTTP reply '%s'", psz ); free( psz ); goto error; } i_code = atoi( &psz[9] ); if( i_code >= 400 ) { msg_Err( p_access, "error: %s", psz ); free( psz ); goto error; } msg_Dbg( p_access, "HTTP reply '%s'", psz ); free( psz ); for( ;; ) { char *psz = net_Gets( p_access, p_sys->fd, NULL ); char *p; if( psz == NULL ) { msg_Err( p_access, "failed to read answer" ); goto error; } if( *psz == '\0' ) { free( psz ); break; } if( ( p = strchr( psz, ':' ) ) == NULL ) { msg_Err( p_access, "malformed header line: %s", psz ); free( psz ); goto error; } *p++ = '\0'; while( *p == ' ' ) p++; /* FIXME FIXME test Content-Type to see if it's a plain stream or an * asx FIXME */ if( !strcasecmp( psz, "Pragma" ) ) { if( strstr( p, "features" ) ) { /* FIXME, it is a bit badly done here ..... */ if( strstr( p, "broadcast" ) ) { msg_Dbg( p_access, "stream type = broadcast" ); p_sys->b_broadcast = true; } else if( strstr( p, "seekable" ) ) { msg_Dbg( p_access, "stream type = seekable" ); p_sys->b_broadcast = false; } else { msg_Warn( p_access, "unknow stream types (%s)", p ); p_sys->b_broadcast = false; } } } else if( !strcasecmp( psz, "Location" ) ) { psz_location = strdup( p ); } free( psz ); } /* Handle the redirection */ if( ( (i_code == 301) || (i_code == 302) || (i_code == 303) || (i_code == 307) ) && psz_location && *psz_location ) { msg_Dbg( p_access, "redirection to %s", psz_location ); net_Close( p_sys->fd ); p_sys->fd = -1; *ppsz_location = psz_location; return VLC_SUCCESS; } /* Read the asf header */ GetHeader( p_access ); if( p_sys->i_header <= 0 ) { msg_Err( p_access, "header size == 0" ); goto error; } /* close this connection */ net_Close( p_sys->fd ); p_sys->fd = -1; /* *** parse header and get stream and their id *** */ /* get all streams properties, * * TODO : stream bitrates properties(optional) * and bitrate mutual exclusion(optional) */ 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" ) ); return VLC_SUCCESS;error: if( p_sys->fd > 0 ) { net_Close( p_sys->fd ); p_sys->fd = -1; } return VLC_EGENERIC;}static void GetHeader( access_t *p_access ){ access_sys_t *p_sys = p_access->p_sys; /* Read the asf header */ p_sys->i_header = 0; free( p_sys->p_header ); p_sys->p_header = NULL; for( ;; ) { chunk_t ck; if( GetPacket( p_access, &ck ) || ck.i_type != 0x4824 ) break; if( ck.i_data > 0 ) { p_sys->i_header += ck.i_data; p_sys->p_header = realloc( p_sys->p_header, p_sys->i_header ); memcpy( &p_sys->p_header[p_sys->i_header - ck.i_data], ck.p_data, ck.i_data ); } } msg_Dbg( p_access, "complete header size=%d", p_sys->i_header );}/***************************************************************************** * Start stream ****************************************************************************/static int Start( access_t *p_access, int64_t i_pos ){ access_sys_t *p_sys = p_access->p_sys; int i_streams = 0; int i_streams_selected = 0; int i; char *psz = NULL; msg_Dbg( p_access, "starting stream" ); for( i = 1; i < 128; i++ ) { if( p_sys->asfh.stream[i].i_cat == ASF_STREAM_UNKNOWN ) continue; i_streams++; if( p_sys->asfh.stream[i].i_selected ) i_streams_selected++; } if( i_streams_selected <= 0 ) { msg_Err( p_access, "no stream selected" ); return VLC_EGENERIC; } if( OpenConnection( p_access ) ) return VLC_EGENERIC; net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL, "Accept: */*\r\n" "User-Agent: "MMSH_USER_AGENT"\r\n" ); if( p_sys->b_broadcast ) { net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL, "Pragma: no-cache,rate=1.000000,request-context=%d\r\n", p_sys->i_request_context++ ); } else { net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL, "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=%u:%u,request-context=%d,max-duration=0\r\n", (uint32_t)((i_pos >> 32)&0xffffffff), (uint32_t)(i_pos&0xffffffff), p_sys->i_request_context++ ); } net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL, "Pragma: xPlayStrm=1\r\n" "Pragma: xClientGUID={"GUID_FMT"}\r\n" "Pragma: stream-switch-count=%d\r\n" "Pragma: stream-switch-entry=", GUID_PRINT( p_sys->guid ), i_streams); for( i = 1; i < 128; i++ ) { if( p_sys->asfh.stream[i].i_cat != ASF_STREAM_UNKNOWN ) { int i_select = 2; if( p_sys->asfh.stream[i].i_selected ) { i_select = 0; } net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL, "ffff:%d:%d ", i, i_select ); } } net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL, "\r\n" ); net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL, "Connection: Close\r\n" ); if( net_Printf( VLC_OBJECT(p_access), p_sys->fd, NULL, "\r\n" ) < 0 ) { msg_Err( p_access, "failed to send request" ); return VLC_EGENERIC; } psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd, NULL ); if( psz == NULL ) { msg_Err( p_access, "cannot read data 0" ); return VLC_EGENERIC; } if( atoi( &psz[9] ) >= 400 ) { msg_Err( p_access, "error: %s", psz ); free( psz ); return VLC_EGENERIC; } msg_Dbg( p_access, "HTTP reply '%s'", psz ); free( psz ); /* FIXME check HTTP code */ for( ;; ) { char *psz = net_Gets( p_access, p_sys->fd, NULL ); if( psz == NULL ) { msg_Err( p_access, "cannot read data 1" ); return VLC_EGENERIC; } if( *psz == '\0' ) { free( psz ); break; } msg_Dbg( p_access, "%s", psz ); free( psz ); } p_sys->i_packet_used = 0; p_sys->i_packet_length = 0; return VLC_SUCCESS;}/***************************************************************************** * closing stream *****************************************************************************/static void Stop( access_t *p_access ){ access_sys_t *p_sys = p_access->p_sys; msg_Dbg( p_access, "closing stream" ); if( p_sys->fd > 0 ) { net_Close( p_sys->fd ); p_sys->fd = -1; }}/***************************************************************************** * get packet *****************************************************************************/static int GetPacket( access_t * p_access, chunk_t *p_ck ){ access_sys_t *p_sys = p_access->p_sys; int restsize; /* chunk_t */ memset( p_ck, 0, sizeof( chunk_t ) ); /* Read the chunk header */ /* Some headers are short, like 0x4324. Reading 12 bytes will cause us * to lose synchronization with the stream. Just read to the length * (4 bytes), decode and then read up to 8 additional bytes to get the * entire header. */ if( net_Read( p_access, p_sys->fd, NULL, p_sys->buffer, 4, true ) < 4 ) { msg_Err( p_access, "cannot read data 2" ); return VLC_EGENERIC; } p_ck->i_type = GetWLE( p_sys->buffer); p_ck->i_size = GetWLE( p_sys->buffer + 2); restsize = p_ck->i_size; if( restsize > 8 ) restsize = 8; if( net_Read( p_access, p_sys->fd, NULL, p_sys->buffer + 4, restsize, true ) < restsize ) { msg_Err( p_access, "cannot read data 3" ); return VLC_EGENERIC; } p_ck->i_sequence = GetDWLE( p_sys->buffer + 4); p_ck->i_unknown = GetWLE( p_sys->buffer + 8); /* Set i_size2 to 8 if this header was short, since a real value won't be * present in the buffer. Using 8 avoid reading additional data for the * packet. */ if( restsize < 8 ) p_ck->i_size2 = 8; else p_ck->i_size2 = GetWLE( p_sys->buffer + 10); p_ck->p_data = p_sys->buffer + 12; p_ck->i_data = p_ck->i_size2 - 8; if( p_ck->i_type == 0x4524 ) // Transfer complete { if( p_ck->i_sequence == 0 ) { msg_Warn( p_access, "EOF" ); return VLC_EGENERIC; } else { msg_Warn( p_access, "next stream following" ); return VLC_EGENERIC; } } else if( p_ck->i_type == 0x4324 ) { /* 0x4324 is CHUNK_TYPE_RESET: a new stream will follow with a sequence of 0 */ msg_Warn( p_access, "next stream following (reset) seq=%d", p_ck->i_sequence ); return VLC_EGENERIC; } else if( (p_ck->i_type != 0x4824) && (p_ck->i_type != 0x4424) ) { msg_Err( p_access, "invalid chunk FATAL (0x%x)", p_ck->i_type ); return VLC_EGENERIC; } if( (p_ck->i_data > 0) && (net_Read( p_access, p_sys->fd, NULL, &p_sys->buffer[12], p_ck->i_data, true ) < p_ck->i_data) ) { msg_Err( p_access, "cannot read data 4" ); return VLC_EGENERIC; }#if 0 if( (p_sys->i_packet_sequence != 0) && (p_ck->i_sequence != p_sys->i_packet_sequence) ) { msg_Warn( p_access, "packet lost ? (%d != %d)", p_ck->i_sequence, p_sys->i_packet_sequence ); }#endif p_sys->i_packet_sequence = p_ck->i_sequence + 1; p_sys->i_packet_used = 0; p_sys->i_packet_length = p_ck->i_data; p_sys->p_packet = p_ck->p_data; return VLC_SUCCESS;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -