📄 asf_streaming.c
字号:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <limits.h>#include "config.h"#ifndef HAVE_WINSOCK2#define closesocket close#else#include <winsock2.h>#endif#include "url.h"#include "http.h"#include "asf.h"#include "stream.h"#include "demuxer.h"#include "network.h"#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 verbose;int asf_http_streaming_start( stream_t *stream, int *demuxer_type );int asf_mmst_streaming_start( stream_t *stream );// 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 failed.// * 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.intasf_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 even valid mms,mmsu,mmst,http,http_proxy? if (!(!strncasecmp(proto, "mmst", 4) || !strncasecmp(proto, "mmsu", 4) || !strncasecmp(proto, "http_proxy", 10) || !strncasecmp(proto, "mms", 3) || !strncasecmp(proto, "http", 4))) { mp_msg(MSGT_NETWORK,MSGL_ERR,"Unknown protocol: %s\n", proto ); return -1; } // Is protocol mms or mmsu? if (!strncasecmp(proto, "mmsu", 4) || !strncasecmp(proto, "mms", 3)) { 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 (!strncasecmp(proto, "mmst", 4) || !strncasecmp(proto, "mms", 3)) { 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 (!strncasecmp(proto, "http_proxy", 10) || !strncasecmp(proto, "http", 4) || !strncasecmp(proto, "mms", 3)) { 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;}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,"Ahhhh, stream_chunck size is too small: %d\n", stream_chunck->size); return -1; } if( stream_chunck->size!=stream_chunck->size_confirm ) { mp_msg(MSGT_NETWORK,MSGL_ERR,"size_confirm mismatch!: %d %d\n", 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 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 intasf_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,"Warning : drop header ????\n"); if(size < 0){ mp_msg(MSGT_NETWORK,MSGL_ERR,"Error while parsing chunk header\n"); return -1; } if (chunk.type != ASF_STREAMING_HEADER) { mp_msg(MSGT_NETWORK,MSGL_ERR,"Don't got a header as first chunk !!!!\n"); return -1; } buffer = (char*) malloc(size+buffer_size); if(buffer == NULL) { mp_msg(MSGT_NETWORK,MSGL_FATAL,"Error can't allocate %d bytes buffer\n",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,"Error while reading network stream\n"); return -1; } r += i; } if( chunk_size2read==0 ) { if(size < (int)sizeof(asfh)) { mp_msg(MSGT_NETWORK,MSGL_ERR,"Error chunk is too small\n"); 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,"Error sub chunks number is invalid\n"); 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 = (int*)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 = (int*)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, "bandwidth too small, " "file cannot be played!\n"); 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, "bandwidth too small, " "deselected audio stream\n"); 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, "bandwidth too small, " "deselected video stream\n"); video_id = -2; } return 1;len_err_out: mp_msg(MSGT_NETWORK, MSGL_FATAL, "Invalid length in ASF header!\n"); if (buffer) free(buffer); if (v_rates) free(v_rates); if (a_rates) free(a_rates); return -1;}intasf_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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -