diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/demuxers/demux_asf.c | 295 |
1 files changed, 165 insertions, 130 deletions
diff --git a/src/demuxers/demux_asf.c b/src/demuxers/demux_asf.c index 5eb771e31..631d6f942 100644 --- a/src/demuxers/demux_asf.c +++ b/src/demuxers/demux_asf.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: demux_asf.c,v 1.50 2002/07/14 22:27:25 miguelfreitas Exp $ + * $Id: demux_asf.c,v 1.51 2002/08/27 22:22:15 tmattern Exp $ * * demultiplexer for asf streams * @@ -70,6 +70,7 @@ typedef struct { fifo_buffer_t *fifo; uint8_t *buffer; + uint32_t bitrate; } asf_stream_t; typedef struct demux_asf_s { @@ -91,9 +92,14 @@ typedef struct demux_asf_s { int packet_flags; asf_stream_t streams[MAX_NUM_STREAMS]; + uint32_t bitrates[MAX_NUM_STREAMS]; int num_streams; int num_audio_streams; int num_video_streams; + int audio_stream; + int video_stream; + int audio_stream_id; + int video_stream_id; uint16_t wavex[1024]; int wavex_size; @@ -207,6 +213,10 @@ static const GUID head2_guid = { 0xabd3d211, 0xa9ba, 0x11cf, { 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 }, }; +static const GUID stream_group_guid = { + 0x7bf875ce, 0x468d, 0x11d1, { 0x8d, 0x82, 0x00, 0x60, 0x97, 0xc9, 0xa2, 0xb2 }, +}; + /* I am not a number !!! This GUID is the one found on the PC used to generate the stream */ static const GUID my_guid = { @@ -294,9 +304,15 @@ static void get_guid (demux_asf_t *this, GUID *g) { g->v1 = get_le32(this); g->v2 = get_le16(this); g->v3 = get_le16(this); - for(i=0;i<8;i++) + for(i=0;i<8;i++) { g->v4[i] = get_byte(this); - + } +#ifdef LOG + printf ("demux_asf: GUID: 0x%x, 0x%x, 0x%x, " + "{ 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx }\n", + g->v1, g->v2, g->v3, + g->v4[0], g->v4[1], g->v4[2], g->v4[3], g->v4[4], g->v4[5], g->v4[6], g->v4[7]); +#endif } static void get_str16_nolen(demux_asf_t *this, int len, @@ -315,7 +331,7 @@ static void get_str16_nolen(demux_asf_t *this, int len, *q = '\0'; } -static void asf_send_audio_header (demux_asf_t *this, int stream_id) { +static void asf_send_audio_header (demux_asf_t *this, int stream) { buf_element_t *buf; xine_waveformatex *wavex = (xine_waveformatex *) this->wavex ; @@ -323,93 +339,62 @@ static void asf_send_audio_header (demux_asf_t *this, int stream_id) { if (!this->audio_fifo) return; - this->streams[this->num_streams].buf_type = - formattag_to_buf_audio ( wavex->wFormatTag ); - - if ( !this->streams[this->num_streams].buf_type ) { - printf ("demux_asf: unknown audio type 0x%x\n", wavex->wFormatTag); - xine_report_codec( this->xine, XINE_CODEC_AUDIO, wavex->wFormatTag, 0, 0); - this->streams[this->num_streams].buf_type = BUF_CONTROL_NOP; - } else - xine_log (this->xine, XINE_LOG_FORMAT, - _("demux_asf: audio format : %s (wFormatTag 0x%x)\n"), - buf_audio_name(this->streams[this->num_streams].buf_type), - wavex->wFormatTag); - - this->streams[this->num_streams].buf_type |= this->num_audio_streams; - this->streams[this->num_streams].fifo = this->audio_fifo; - this->streams[this->num_streams].stream_id = stream_id; - this->streams[this->num_streams].frag_offset = 0; - this->streams[this->num_streams].seq = 0; - if (this->reorder_h > 1 && this->reorder_w > 1 ) { - if( !this->streams[this->num_streams].buffer ) - this->streams[this->num_streams].buffer = malloc( DEFRAG_BUFSIZE ); - this->streams[this->num_streams].defrag = 1; - } else - this->streams[this->num_streams].defrag = 0; - buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); memcpy (buf->content, this->wavex, this->wavex_size); #ifdef LOG printf ("demux_asf: wavex header is %d bytes long\n", this->wavex_size); #endif + if ( !this->streams[stream].buf_type ) { + printf ("demux_asf: unknown audio type 0x%x\n", wavex->wFormatTag); + xine_report_codec( this->xine, XINE_CODEC_AUDIO, wavex->wFormatTag, 0, 0); + this->streams[stream].buf_type = BUF_CONTROL_NOP; + } else + xine_log (this->xine, XINE_LOG_FORMAT, + _("demux_asf: audio format : %s (wFormatTag 0x%x)\n"), + buf_audio_name(this->streams[stream].buf_type), + wavex->wFormatTag); buf->size = this->wavex_size; - buf->type = this->streams[this->num_streams].buf_type; + buf->type = this->streams[stream].buf_type; buf->decoder_flags = BUF_FLAG_HEADER; buf->decoder_info[1] = wavex->nSamplesPerSec; buf->decoder_info[2] = wavex->wBitsPerSample; buf->decoder_info[3] = wavex->nChannels; - this->audio_fifo->put (this->audio_fifo, buf); - this->num_streams++; - this->num_audio_streams++; + this->audio_fifo->put (this->audio_fifo, buf); } static unsigned long str2ulong(unsigned char *str) { return ( str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24) ); } -static void asf_send_video_header (demux_asf_t *this, int stream_id) { +static void asf_send_video_header (demux_asf_t *this, int stream) { buf_element_t *buf; xine_bmiheader *bih = (xine_bmiheader *) this->bih; - this->streams[this->num_streams].buf_type = - fourcc_to_buf_video(bih->biCompression); - - if( !this->streams[this->num_streams].buf_type ) { + if( !this->streams[stream].buf_type ) { printf ("demux_asf: unknown video format %.4s\n", - (char*)&bih->biCompression); - + (char*)&bih->biCompression); + xine_log (this->xine, XINE_LOG_FORMAT, + _("demux_asf: video format : %s\n"), + buf_video_name(this->streams[stream].buf_type)); xine_report_codec( this->xine, XINE_CODEC_VIDEO, bih->biCompression, 0, 0); this->status = DEMUX_FINISHED; return; } - - this->streams[this->num_streams].buf_type |= this->num_video_streams; - this->streams[this->num_streams].fifo = this->video_fifo; - this->streams[this->num_streams].stream_id = stream_id; - this->streams[this->num_streams].frag_offset = 0; - this->streams[this->num_streams].defrag = 0; - - xine_log (this->xine, XINE_LOG_FORMAT, - _("demux_asf: video format : %s\n"), - buf_video_name(this->streams[this->num_streams].buf_type)); buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->decoder_flags = BUF_FLAG_HEADER; buf->decoder_info[1] = 3000; /* FIXME ? */ memcpy (buf->content, &this->bih, this->bih_size); buf->size = this->bih_size; - buf->type = this->streams[this->num_streams].buf_type ; + buf->type = this->streams[stream].buf_type ; + this->video_fifo->put (this->video_fifo, buf); - this->num_streams++; - this->num_video_streams++; - } static int asf_read_header (demux_asf_t *this) { @@ -448,13 +433,13 @@ static int asf_read_header (demux_asf_t *this) { this->length = get_le64(this) / 10000000; if (this->length) - this->rate = this->input->get_length (this->input) / this->length; + this->rate = this->input->get_length (this->input) / this->length; else - this->rate = 0; + this->rate = 0; xine_log (this->xine, XINE_LOG_FORMAT, - _("demux_asf: stream length is %d sec, rate is %d bytes/sec\n"), - this->length, this->rate); + _("demux_asf: stream length is %d sec, rate is %d bytes/sec\n"), + this->length, this->rate); start_time = get_le32(this); /* start timestamp in 1/1000 s*/ @@ -468,16 +453,18 @@ static int asf_read_header (demux_asf_t *this) { int type, total_size, stream_data_size, stream_id; uint64_t pos1, pos2; + xine_bmiheader *bih = (xine_bmiheader *) this->bih; + xine_waveformatex *wavex = (xine_waveformatex *) this->wavex ; pos1 = this->input->get_current_pos (this->input); get_guid(this, &g); if (!memcmp(&g, &audio_stream, sizeof(GUID))) { - type = CODEC_TYPE_AUDIO; + type = CODEC_TYPE_AUDIO; } else if (!memcmp(&g, &video_stream, sizeof(GUID))) { - type = CODEC_TYPE_VIDEO; + type = CODEC_TYPE_VIDEO; } else { - goto fail; + goto fail; } get_guid(this, &g); get_le64(this); @@ -489,56 +476,80 @@ static int asf_read_header (demux_asf_t *this) { if (type == CODEC_TYPE_AUDIO) { uint8_t buffer[6]; - this->input->read (this->input, (uint8_t *) this->wavex, total_size); - xine_waveformatex_le2me( (xine_waveformatex *) this->wavex ); - + this->input->read (this->input, (uint8_t *) this->wavex, total_size); + xine_waveformatex_le2me( (xine_waveformatex *) this->wavex ); + /* - printf ("total size: %d bytes\n", total_size); - */ + printf ("total size: %d bytes\n", total_size); + */ - /* - this->input->read (this->input, (uint8_t *) &this->wavex[9], this->wavex[8]); - */ + /* + this->input->read (this->input, (uint8_t *) &this->wavex[9], this->wavex[8]); + */ if (!memcmp(&g, &audio_conceal_interleave, sizeof(GUID))) { - this->input->read (this->input, buffer, 6); - this->reorder_h=buffer[0]; - this->reorder_w=(buffer[2]<<8)|buffer[1]; - this->reorder_b=(buffer[4]<<8)|buffer[3]; - this->reorder_w/=this->reorder_b; + this->input->read (this->input, buffer, 6); + this->reorder_h = buffer[0]; + this->reorder_w = (buffer[2]<<8)|buffer[1]; + this->reorder_b = (buffer[4]<<8)|buffer[3]; + this->reorder_w /= this->reorder_b; printf ("demux_asf: audio conceal interleave detected (%d x %d x %d)\n", - this->reorder_w, this->reorder_h, this->reorder_b ); - } else { - this->reorder_b=this->reorder_h=this->reorder_w=1; + this->reorder_w, this->reorder_h, this->reorder_b ); + } else { + this->reorder_b=this->reorder_h=this->reorder_w=1; } - this->wavex_size = total_size; /* 18 + this->wavex[8]; */ - - asf_send_audio_header (this, stream_id); + this->wavex_size = total_size; /* 18 + this->wavex[8]; */ + + this->streams[this->num_streams].buf_type = + formattag_to_buf_audio ( wavex->wFormatTag ); + + this->streams[this->num_streams].fifo = this->audio_fifo; + this->streams[this->num_streams].stream_id = stream_id; + this->streams[this->num_streams].frag_offset = 0; + this->streams[this->num_streams].seq = 0; + if (this->reorder_h > 1 && this->reorder_w > 1 ) { + if( !this->streams[this->num_streams].buffer ) + this->streams[this->num_streams].buffer = malloc( DEFRAG_BUFSIZE ); + this->streams[this->num_streams].defrag = 1; + } else + this->streams[this->num_streams].defrag = 0; + // #ifdef LOG printf ("demux_asf: found a_stream id=%d \n", stream_id); #endif + this->num_audio_streams++; } else { - int i; + int i; - get_le32(this); /* width */ - get_le32(this); /* height */ - get_byte(this); - - i = get_le16(this); /* size */ - if( i > 0 && i < sizeof(this->bih) ) { - this->bih_size = i; - this->input->read (this->input, (uint8_t *) this->bih, this->bih_size); - xine_bmiheader_le2me( (xine_bmiheader *) this->bih ); + get_le32(this); /* width */ + get_le32(this); /* height */ + get_byte(this); + + i = get_le16(this); /* size */ + if( i > 0 && i < sizeof(this->bih) ) { + this->bih_size = i; + this->input->read (this->input, (uint8_t *) this->bih, this->bih_size); + xine_bmiheader_le2me( (xine_bmiheader *) this->bih ); + + this->streams[this->num_streams].buf_type = + fourcc_to_buf_video(bih->biCompression); + + this->streams[this->num_streams].fifo = this->video_fifo; + this->streams[this->num_streams].stream_id = stream_id; + this->streams[this->num_streams].frag_offset = 0; + this->streams[this->num_streams].defrag = 0; + + } else + printf ("demux_asf: invalid bih_size received (%d), v_stream ignored.\n", i ); - asf_send_video_header (this, stream_id); - } - else - printf ("demux_asf: invalid bih_size received (%d), v_stream ignored.\n", i ); #ifdef LOG - printf ("demux_asf: found v_stream id=%d \n", stream_id); + printf ("demux_asf: found v_stream id=%d \n", stream_id); #endif + this->num_video_streams++; } + + this->num_streams++; pos2 = this->input->get_current_pos (this->input); this->input->seek (this->input, gsize - (pos2 - pos1 + 24), SEEK_CUR); @@ -562,6 +573,18 @@ static int asf_read_header (demux_asf_t *this) { } else if (url_feof(this)) { goto fail; */ + } else if (!memcmp(&g, &stream_group_guid, sizeof(GUID))) { + printf("demux_asf: GUID stream group\n"); + int streams; + int stream_id; + int i; + + streams = get_le16(this); + for(i = 0; i < streams; i++) { + stream_id = get_le16(this); + this->bitrates[stream_id] = get_le32(this); + } + } else { this->input->seek (this->input, gsize - 24, SEEK_CUR); } @@ -891,31 +914,6 @@ static void asf_read_packet(demux_asf_t *this) { int raw_id, stream_id, seq, frag_offset, payload_size, frag_len; int timestamp, flags, i; asf_stream_t *stream; - static int nb_all_p=0; - static int nb_p_c=0; - static int num_stream_c=0; - int id; - - if ( !num_stream_c ){ - if(this->num_streams > 0){ - num_stream_c= this->num_streams ; - id=this->streams[num_stream_c-1].stream_id; - } - else - return ; - - } - else - id = this->streams[num_stream_c-1].stream_id;; - - if (this->num_streams > 0 && nb_p_c < nb_all_p /this->num_streams -10){ - if ( num_stream_c > 2 ){ /* still have at least one video stream except this*/ - printf ("changing a videoo stream \n"); - num_stream_c--; - id= this->streams[num_stream_c-1].stream_id; - } - nb_p_c = nb_all_p =0; - } if ((this->packet_size_left < FRAME_HEADER_SIZE) || (this->packet_size_left <= this->packet_padsize) || @@ -942,19 +940,17 @@ static void asf_read_packet(demux_asf_t *this) { stream_id = raw_id & 0x7f; stream = NULL; - nb_all_p++; if ( (raw_id & 0x80) || this->keyframe_found || (this->num_video_streams==0)) { -#if LOG +#ifdef LOG printf ("asf_demuxer: got stream =%d \n", stream_id); #endif - for (i=0; i<this->num_streams; i++){ - if (this->streams[i].stream_id == stream_id && (stream_id==1 - || stream_id==id)) { - stream = &this->streams[i]; - nb_p_c++; - - if( raw_id & 0x80 ) - this->keyframe_found = 1; + for (i = 0; i < this->num_streams; i++){ + if (this->streams[i].stream_id == stream_id && + (stream_id == this->audio_stream_id || stream_id == this->video_stream_id)) { + stream = &this->streams[i]; + + if( raw_id & 0x80 ) + this->keyframe_found = 1; } } } @@ -1209,6 +1205,9 @@ static int demux_asf_start (demux_plugin_t *this_gen, demux_asf_t *this = (demux_asf_t *) this_gen; int err; int status; + int i; + int stream_id; + uint32_t buf_type, bitrate, max_vrate, max_arate; pthread_mutex_lock( &this->mutex ); @@ -1230,6 +1229,10 @@ static int demux_asf_start (demux_plugin_t *this_gen, this->num_streams = 0; this->num_audio_streams = 0; this->num_video_streams = 0; + this->audio_stream = 0; + this->video_stream = 0; + this->audio_stream_id = 0; + this->video_stream_id = 0; this->packet_size = 0; this->seqno = 0; this->frame_duration = 3000; @@ -1251,6 +1254,38 @@ static int demux_asf_start (demux_plugin_t *this_gen, _("demux_asf: copyright : %s\n"), this->copyright); xine_log (this->xine, XINE_LOG_FORMAT, _("demux_asf: comment : %s\n"), this->comment); + + + /* Choose the best audio and the best video stream. + * Use the bitrate to do the choice. + */ + max_vrate = 0; + max_arate = 0; + for(i = 0; i < this->num_streams; i++) { + buf_type = (this->streams[i].buf_type & BUF_MAJOR_MASK); + stream_id = this->streams[i].stream_id; + bitrate = this->bitrates[stream_id]; + + printf("demux_asf: stream: %d, bitrate %d bps, ", stream_id, bitrate); + if ((buf_type == BUF_VIDEO_BASE) && + (bitrate > max_vrate || this->video_stream_id == 0)) { + printf("video\n"); + max_vrate = bitrate; + this->video_stream = i; + this->video_stream_id = stream_id; + } else if ((buf_type == BUF_AUDIO_BASE) && + (bitrate > max_arate || this->audio_stream_id == 0)) { + printf("audio\n"); + max_arate = bitrate; + this->audio_stream = i; + this->audio_stream_id = stream_id; + } + } + printf("demux_asf: video stream_id: %d, audio stream_id: %d\n", + this->video_stream_id, this->audio_stream_id); + + asf_send_audio_header(this, this->audio_stream); + asf_send_video_header(this, this->video_stream); } } else { |