📄 asf_streaming.c
字号:
#include <mplaylib.h>#include <mplaylib.h>#include <mplaylib.h>#include <mplaylib.h>#include <errno.h>#include "config.h"#include "mp_msg.h"#include "help_mp.h"#ifndef HAVE_WINSOCK2#define closesocket close#else#include <winsock2.h>#endif#include "url.h"#include "http.h"#include "libmpdemux/asf.h"#include "stream.h"#include "libmpdemux/demuxer.h"#include "network.h"#include "tcp.h"#undef memcpy#define memcpy uc_memcpy#ifdef ARCH_X86#define ASF_LOAD_GUID_PREFIX(guid) (*(uint32_t *)(guid))#else#define ASF_LOAD_GUID_PREFIX(guid) \ ((guid)[3] << 24 | (guid)[2] << 16 | (guid)[1] << 8 | (guid)[0])#endifextern int network_bandwidth;int asf_mmst_streaming_start( stream_t *stream );static int asf_http_streaming_start(stream_t *stream, int *demuxer_type);// We can try several protocol for asf streaming// * first the UDP protcol, if there is a firewall, UDP// packets will not come back, so the mmsu will fail.// * Then we can try TCP, but if there is a proxy for// internet connection, the TCP connection will not get// through// * Then we can try HTTP.// // Note: Using WMP sequence MMSU then MMST and then HTTP.static int asf_streaming_start( stream_t *stream, int *demuxer_type) { char *proto = stream->streaming_ctrl->url->protocol; int fd = -1; int port = stream->streaming_ctrl->url->port; // Is protocol mms or mmsu? if (!strcasecmp(proto, "mmsu") || !strcasecmp(proto, "mms")) { mp_msg(MSGT_NETWORK,MSGL_V,"Trying ASF/UDP...\n"); //fd = asf_mmsu_streaming_start( stream ); if( fd>-1 ) return fd; //mmsu support is not implemented yet - using this code mp_msg(MSGT_NETWORK,MSGL_V," ===> ASF/UDP failed\n"); if( fd==-2 ) return -1; } //Is protocol mms or mmst? if (!strcasecmp(proto, "mmst") || !strcasecmp(proto, "mms")) { mp_msg(MSGT_NETWORK,MSGL_V,"Trying ASF/TCP...\n"); fd = asf_mmst_streaming_start( stream ); stream->streaming_ctrl->url->port = port; if( fd>-1 ) return fd; mp_msg(MSGT_NETWORK,MSGL_V," ===> ASF/TCP failed\n"); if( fd==-2 ) return -1; } //Is protocol http, http_proxy, or mms? if (!strcasecmp(proto, "http_proxy") || !strcasecmp(proto, "http") || !strcasecmp(proto, "mms") || !strcasecmp(proto, "mmshttp")) { mp_msg(MSGT_NETWORK,MSGL_V,"Trying ASF/HTTP...\n"); fd = asf_http_streaming_start( stream, demuxer_type ); stream->streaming_ctrl->url->port = port; if( fd>-1 ) return fd; mp_msg(MSGT_NETWORK,MSGL_V," ===> ASF/HTTP failed\n"); if( fd==-2 ) return -1; } //everything failed return -1;}static int asf_streaming(ASF_stream_chunck_t *stream_chunck, int *drop_packet ) {/* printf("ASF stream chunck size=%d\n", stream_chunck->size);printf("length: %d\n", length );printf("0x%02X\n", stream_chunck->type );*/ if( drop_packet!=NULL ) *drop_packet = 0; if( stream_chunck->size<8 ) { mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_StreamChunkSize2Small, stream_chunck->size); return -1; } if( stream_chunck->size!=stream_chunck->size_confirm ) { mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_SizeConfirmMismatch, stream_chunck->size, stream_chunck->size_confirm); return -1; }/* printf(" type: 0x%02X\n", stream_chunck->type ); printf(" size: %d (0x%02X)\n", stream_chunck->size, stream_chunck->size ); printf(" sequence_number: 0x%04X\n", stream_chunck->sequence_number ); printf(" unknown: 0x%02X\n", stream_chunck->unknown ); printf(" size_confirm: 0x%02X\n", stream_chunck->size_confirm );*/ switch(stream_chunck->type) { case ASF_STREAMING_CLEAR: // $C Clear ASF configuration mp_msg(MSGT_NETWORK,MSGL_V,"=====> Clearing ASF stream configuration!\n"); if( drop_packet!=NULL ) *drop_packet = 1; return stream_chunck->size; break; case ASF_STREAMING_DATA: // $D Data follows// printf("=====> Data follows\n"); break; case ASF_STREAMING_END_TRANS: // $E Transfer complete mp_msg(MSGT_NETWORK,MSGL_V,"=====> Transfer complete\n"); if( drop_packet!=NULL ) *drop_packet = 1; return stream_chunck->size; break; case ASF_STREAMING_HEADER: // $H ASF header chunk follows mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF header chunk follows\n"); break; default: mp_msg(MSGT_NETWORK,MSGL_V,"=====> Unknown stream type 0x%x\n", stream_chunck->type ); } return stream_chunck->size+4;}extern int find_asf_guid(char *buf, const char *guid, int cur_pos, int buf_len);extern const char asf_file_header_guid[];extern const char asf_stream_header_guid[];extern const char asf_stream_group_guid[];extern int audio_id;extern int video_id;static void close_s(stream_t *stream) { close(stream->fd); stream->fd=-1;}static int max_idx(int s_count, int *s_rates, int bound) { int i, best = -1, rate = -1; for (i = 0; i < s_count; i++) { if (s_rates[i] > rate && s_rates[i] <= bound) { rate = s_rates[i]; best = i; } } return best;}static int asf_streaming_parse_header(int fd, streaming_ctrl_t* streaming_ctrl) { ASF_header_t asfh; ASF_stream_chunck_t chunk; asf_http_streaming_ctrl_t* asf_ctrl = (asf_http_streaming_ctrl_t*) streaming_ctrl->data; char* buffer=NULL, *chunk_buffer=NULL; int i,r,size,pos = 0; int start; int buffer_size = 0; int chunk_size2read = 0; int bw = streaming_ctrl->bandwidth; int *v_rates = NULL, *a_rates = NULL; int v_rate = 0, a_rate = 0, a_idx = -1, v_idx = -1; if(asf_ctrl == NULL) return -1; // The ASF header can be in several network chunks. For example if the content description // is big, the ASF header will be split in 2 network chunk. // So we need to retrieve all the chunk before starting to parse the header. do { for( r=0; r < (int)sizeof(ASF_stream_chunck_t) ; ) { i = nop_streaming_read(fd,((char*)&chunk)+r,sizeof(ASF_stream_chunck_t) - r,streaming_ctrl); if(i <= 0) return -1; r += i; } // Endian handling of the stream chunk le2me_ASF_stream_chunck_t(&chunk); size = asf_streaming( &chunk, &r) - sizeof(ASF_stream_chunck_t); if(r) mp_msg(MSGT_NETWORK,MSGL_WARN,MSGTR_MPDEMUX_ASF_WarnDropHeader); if(size < 0){ mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrorParsingChunkHeader); return -1; } if (chunk.type != ASF_STREAMING_HEADER) { mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_NoHeaderAtFirstChunk); return -1; } // audit: do not overflow buffer_size if (size > SIZE_MAX - buffer_size) return -1; buffer = (char*) malloc(size+buffer_size); if(buffer == NULL) { mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MPDEMUX_ASF_BufferMallocFailed,size+buffer_size); return -1; } if( chunk_buffer!=NULL ) { memcpy( buffer, chunk_buffer, buffer_size ); free( chunk_buffer ); } chunk_buffer = buffer; buffer += buffer_size; buffer_size += size; for(r = 0; r < size;) { i = nop_streaming_read(fd,buffer+r,size-r,streaming_ctrl); if(i < 0) { mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrReadingNetworkStream); return -1; } r += i; } if( chunk_size2read==0 ) { if(size < (int)sizeof(asfh)) { mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrChunk2Small); return -1; } else mp_msg(MSGT_NETWORK,MSGL_DBG2,"Got chunk\n"); memcpy(&asfh,buffer,sizeof(asfh)); le2me_ASF_header_t(&asfh); chunk_size2read = asfh.objh.size; mp_msg(MSGT_NETWORK,MSGL_DBG2,"Size 2 read=%d\n", chunk_size2read); } } while( buffer_size<chunk_size2read); buffer = chunk_buffer; size = buffer_size; if(asfh.cno > 256) { mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrSubChunkNumberInvalid); return -1; } start = sizeof(asfh); pos = find_asf_guid(buffer, asf_file_header_guid, start, size); if (pos >= 0) { ASF_file_header_t *fileh = (ASF_file_header_t *) &buffer[pos]; pos += sizeof(ASF_file_header_t); if (pos > size) goto len_err_out; le2me_ASF_file_header_t(fileh);/* if(fileh.packetsize != fileh.packetsize2) { printf("Error packetsize check don't match\n"); return -1; }*/ asf_ctrl->packet_size = fileh->max_packet_size; // before playing. // preroll: time in ms to bufferize before playing streaming_ctrl->prebuffer_size = (unsigned int)(((double)fileh->preroll/1000.0)*((double)fileh->max_bitrate/8.0)); } pos = start; while ((pos = find_asf_guid(buffer, asf_stream_header_guid, pos, size)) >= 0) { ASF_stream_header_t *streamh = (ASF_stream_header_t *)&buffer[pos]; pos += sizeof(ASF_stream_header_t); if (pos > size) goto len_err_out; le2me_ASF_stream_header_t(streamh); switch(ASF_LOAD_GUID_PREFIX(streamh->type)) { case 0xF8699E40 : // audio stream if(asf_ctrl->audio_streams == NULL){ asf_ctrl->audio_streams = malloc(sizeof(int)); asf_ctrl->n_audio = 1; } else { asf_ctrl->n_audio++; asf_ctrl->audio_streams = (int*)realloc(asf_ctrl->audio_streams, asf_ctrl->n_audio*sizeof(int)); } asf_ctrl->audio_streams[asf_ctrl->n_audio-1] = streamh->stream_no; break; case 0xBC19EFC0 : // video stream if(asf_ctrl->video_streams == NULL){ asf_ctrl->video_streams = malloc(sizeof(int)); asf_ctrl->n_video = 1; } else { asf_ctrl->n_video++; asf_ctrl->video_streams = (int*)realloc(asf_ctrl->video_streams, asf_ctrl->n_video*sizeof(int)); } asf_ctrl->video_streams[asf_ctrl->n_video-1] = streamh->stream_no; break; } } // always allocate to avoid lots of ifs later v_rates = calloc(asf_ctrl->n_video, sizeof(int)); a_rates = calloc(asf_ctrl->n_audio, sizeof(int)); pos = find_asf_guid(buffer, asf_stream_group_guid, start, size); if (pos >= 0) { // stream bitrate properties object int stream_count; char *ptr = &buffer[pos]; mp_msg(MSGT_NETWORK, MSGL_V, "Stream bitrate properties object\n"); stream_count = le2me_16(*(uint16_t*)ptr); ptr += sizeof(uint16_t); if (ptr > &buffer[size]) goto len_err_out; mp_msg(MSGT_NETWORK, MSGL_V, " stream count=[0x%x][%u]\n", stream_count, stream_count ); for( i=0 ; i<stream_count ; i++ ) { uint32_t rate; int id; int j; id = le2me_16(*(uint16_t*)ptr); ptr += sizeof(uint16_t); if (ptr > &buffer[size]) goto len_err_out; memcpy(&rate, ptr, sizeof(uint32_t));// workaround unaligment bug on sparc ptr += sizeof(uint32_t); if (ptr > &buffer[size]) goto len_err_out; rate = le2me_32(rate); mp_msg(MSGT_NETWORK, MSGL_V, " stream id=[0x%x][%u]\n", id, id); mp_msg(MSGT_NETWORK, MSGL_V, " max bitrate=[0x%x][%u]\n", rate, rate); for (j = 0; j < asf_ctrl->n_video; j++) { if (id == asf_ctrl->video_streams[j]) { mp_msg(MSGT_NETWORK, MSGL_V, " is video stream\n"); v_rates[j] = rate; break; } } for (j = 0; j < asf_ctrl->n_audio; j++) { if (id == asf_ctrl->audio_streams[j]) { mp_msg(MSGT_NETWORK, MSGL_V, " is audio stream\n"); a_rates[j] = rate; break; } } } } free(buffer); // automatic stream selection based on bandwidth if (bw == 0) bw = INT_MAX; mp_msg(MSGT_NETWORK, MSGL_V, "Max bandwidth set to %d\n", bw); if (asf_ctrl->n_audio) { // find lowest-bitrate audio stream a_rate = a_rates[0]; a_idx = 0; for (i = 0; i < asf_ctrl->n_audio; i++) { if (a_rates[i] < a_rate) { a_rate = a_rates[i]; a_idx = i; } } if (max_idx(asf_ctrl->n_video, v_rates, bw - a_rate) < 0) { // both audio and video are not possible, try video only next a_idx = -1; a_rate = 0; } } // find best video stream v_idx = max_idx(asf_ctrl->n_video, v_rates, bw - a_rate); if (v_idx >= 0) v_rate = v_rates[v_idx]; // find best audio stream a_idx = max_idx(asf_ctrl->n_audio, a_rates, bw - v_rate); free(v_rates); free(a_rates); if (a_idx < 0 && v_idx < 0) { mp_msg(MSGT_NETWORK, MSGL_FATAL, MSGTR_MPDEMUX_ASF_Bandwidth2SmallCannotPlay); return -1; } if (audio_id > 0) // a audio stream was forced asf_ctrl->audio_id = audio_id; else if (a_idx >= 0) asf_ctrl->audio_id = asf_ctrl->audio_streams[a_idx]; else if (asf_ctrl->n_audio) { mp_msg(MSGT_NETWORK, MSGL_WARN, MSGTR_MPDEMUX_ASF_Bandwidth2SmallDeselectedAudio); audio_id = -2; } if (video_id > 0) // a video stream was forced asf_ctrl->video_id = video_id; else if (v_idx >= 0) asf_ctrl->video_id = asf_ctrl->video_streams[v_idx]; else if (asf_ctrl->n_video) { mp_msg(MSGT_NETWORK, MSGL_WARN, MSGTR_MPDEMUX_ASF_Bandwidth2SmallDeselectedVideo); video_id = -2; } return 1;len_err_out: mp_msg(MSGT_NETWORK, MSGL_FATAL, MSGTR_MPDEMUX_ASF_InvalidLenInHeader); if (buffer) free(buffer); if (v_rates) free(v_rates); if (a_rates) free(a_rates); return -1;}static int asf_http_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *streaming_ctrl ) { static ASF_stream_chunck_t chunk; int read,chunk_size = 0; static int rest = 0, drop_chunk = 0, waiting = 0; asf_http_streaming_ctrl_t *asf_http_ctrl = (asf_http_streaming_ctrl_t*)streaming_ctrl->data; while(1) { if (rest == 0 && waiting == 0) { read = 0; while(read < (int)sizeof(ASF_stream_chunck_t)){ int r = nop_streaming_read( fd, ((char*)&chunk) + read, sizeof(ASF_stream_chunck_t)-read, streaming_ctrl ); if(r <= 0){ if( r < 0) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrReadingChunkHeader); return -1; } read += r; } // Endian handling of the stream chunk le2me_ASF_stream_chunck_t(&chunk); chunk_size = asf_streaming( &chunk, &drop_chunk ); if(chunk_size < 0) { mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrorParsingChunkHeader); return -1; } chunk_size -= sizeof(ASF_stream_chunck_t); if(chunk.type != ASF_STREAMING_HEADER && (!drop_chunk)) { if (asf_http_ctrl->packet_size < chunk_size) { mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrChunkBiggerThanPacket); return -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -