diff options
-rw-r--r-- | src/demuxers/demux_ogg.c | 353 | ||||
-rw-r--r-- | src/libvorbis/xine_decoder.c | 136 |
2 files changed, 273 insertions, 216 deletions
diff --git a/src/demuxers/demux_ogg.c b/src/demuxers/demux_ogg.c index 865908526..607a3f20d 100644 --- a/src/demuxers/demux_ogg.c +++ b/src/demuxers/demux_ogg.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_ogg.c,v 1.33 2002/08/18 14:13:08 guenter Exp $ + * $Id: demux_ogg.c,v 1.34 2002/08/19 22:12:52 guenter Exp $ * * demultiplexer for ogg streams * @@ -118,6 +118,9 @@ typedef struct demux_ogg_s { int samplerate[MAX_STREAMS]; int num_streams; + int num_audio_streams; + int num_video_streams; + int avg_bitrate; } demux_ogg_t ; @@ -153,6 +156,131 @@ static void hex_dump (uint8_t *p, int length) { } +/* + * utility function to pack one ogg_packet into a xine + * buffer, fill out all needed fields + * and send it to the right fifo + */ + +static void send_ogg_buf (demux_ogg_t *this, + ogg_packet *op, + int stream_num, + uint32_t decoder_flags) { + + if ( this->audio_fifo + && (this->buf_types[stream_num] & 0xFF000000) == BUF_AUDIO_BASE) { + buf_element_t *buf; + + buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + + if ((this->buf_types[stream_num] & 0xFFFF0000) == BUF_AUDIO_VORBIS) { + int op_size = sizeof(ogg_packet); + ogg_packet *og_ghost; + op_size += (4 - (op_size % 4)); + +#ifdef LOG + printf ("demux_ogg: special treatment for vorbis package\n"); + hex_dump (op->packet, op->bytes); +#endif + + /* nasty hack to pack op as well as (vorbis) content + in one xine buffer */ + memcpy (buf->content + op_size, op->packet, op->bytes); + memcpy (buf->content, op, op_size); + og_ghost = (ogg_packet *) buf->content; + og_ghost->packet = buf->content + op_size; + + buf->size = op->bytes; + } else { + int hdrlen; + + hdrlen = (*op->packet & PACKET_LEN_BITS01) >> 6; + hdrlen |= (*op->packet & PACKET_LEN_BITS2) << 1; + +#ifdef LOG + printf ("demux_ogg: headerlen %d\n",hdrlen); +#endif + + memcpy (buf->content, op->packet+1+hdrlen, op->bytes-1-hdrlen); + buf->size = op->bytes-1-hdrlen; + } + +#ifdef LOG + printf ("demux_ogg: audio buf_size %d\n", buf->size); +#endif + + if (op->granulepos>0) + buf->pts = 90000 * op->granulepos / this->samplerate[stream_num]; + else + buf->pts = 0; + +#ifdef LOG + printf ("demux_ogg: audio granulepos %lld => pts %lld\n", + op->granulepos, buf->pts); +#endif + + buf->input_pos = this->input->get_current_pos (this->input); + buf->input_time = buf->input_pos * 8 / this->avg_bitrate; + buf->type = this->buf_types[stream_num] ; + buf->decoder_flags = decoder_flags; + + this->audio_fifo->put (this->audio_fifo, buf); + + } else if ((this->buf_types[stream_num] & 0xFF000000) == BUF_VIDEO_BASE) { + + buf_element_t *buf; + int todo, done, hdrlen; + +#ifdef LOG + printf ("demux_ogg: video buffer, type=%08x\n", this->buf_types[stream_num]); +#endif + + hdrlen = (*op->packet & PACKET_LEN_BITS01) >> 6; + hdrlen |= (*op->packet & PACKET_LEN_BITS2) << 1; + +#ifdef LOG + printf ("demux_ogg: headerlen %d\n",hdrlen); +#endif + + todo = op->bytes-1-hdrlen; + done = 0; + while (done<todo) { + + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + + if ( (todo-done)>(buf->max_size-1)) { + buf->size = buf->max_size-1; + buf->decoder_flags = decoder_flags; + } else { + buf->size = todo-done; + buf->decoder_flags = BUF_FLAG_FRAME_END | decoder_flags; + } + + /* + printf ("demux_ogg: done %d todo %d doing %d\n", done, todo, buf->size); + */ + memcpy (buf->content, op->packet+done, buf->size); + + if (op->granulepos>0) + buf->pts = op->granulepos * this->frame_duration; + else + buf->pts = 0; +#ifdef LOG + printf ("demux_ogg: video granulepos %lld, pts %lld\n", op->granulepos, buf->pts); +#endif + + buf->input_pos = this->input->get_current_pos (this->input); + buf->input_time = 0; + buf->type = this->buf_types[stream_num] ; + + done += buf->size; + + this->video_fifo->put (this->video_fifo, buf); + + } + } +} + /* * interpret strea start packages, send headers */ @@ -164,16 +292,18 @@ static void demux_ogg_send_header (demux_ogg_t *this) { char *buffer; long bytes; - ogg_packet op; - - while (1) { + int num_preview_buffers = 50; - int ret = ogg_sync_pageout(&this->oy,&this->og); + ogg_packet op; #ifdef LOG - printf ("demux_ogg: send header...\n"); + printf ("demux_ogg: detecting stream types...\n"); #endif + while (num_preview_buffers>0) { + + int ret = ogg_sync_pageout(&this->oy,&this->og); + if (ret == 0) { buffer = ogg_sync_buffer(&this->oy, CHUNKSIZE); bytes = this->input->read(this->input, buffer, CHUNKSIZE); @@ -189,25 +319,38 @@ static void demux_ogg_send_header (demux_ogg_t *this) { cur_serno = ogg_page_serialno (&this->og); - if (!ogg_page_bos(&this->og)) { -#ifdef LOG - printf ("demux_ogg: beginning of content found\n"); -#endif - return; - } + stream_num = -1; + + if (ogg_page_bos(&this->og)) { - printf ("demux_ogg: beginning of stream\ndemux_ogg: serial number %d\n", - cur_serno); + printf ("demux_ogg: beginning of stream\ndemux_ogg: serial number %d\n", + cur_serno); - ogg_stream_init(&this->oss[this->num_streams], cur_serno); - stream_num = this->num_streams; - this->buf_types[stream_num] = 0; - this->num_streams++; + ogg_stream_init(&this->oss[this->num_streams], cur_serno); + stream_num = this->num_streams; + this->buf_types[stream_num] = 0; + this->num_streams++; + } else { + int i; + + for (i = 0; i<this->num_streams; i++) { + if (this->oss[i].serialno == cur_serno) { + stream_num = i; + break; + } + } + if (stream_num == -1) { + printf ("demux_ogg: help, stream with no beginning!\n"); + abort(); + } + } ogg_stream_pagein(&this->oss[stream_num], &this->og); while (ogg_stream_packetout(&this->oss[stream_num], &op) == 1) { + printf ("demux_ogg: packet of stream %d found\n", cur_serno); + if (!this->buf_types[stream_num]) { /* detect buftype */ if (!strncmp (&op.packet[1], "vorbis", 6)) { @@ -215,7 +358,8 @@ static void demux_ogg_send_header (demux_ogg_t *this) { vorbis_info vi; vorbis_comment vc; - this->buf_types[stream_num] = BUF_AUDIO_VORBIS; + this->buf_types[stream_num] = BUF_AUDIO_VORBIS + +this->num_audio_streams++; xine_log (this->xine, XINE_LOG_FORMAT, _("ogg: vorbis audio stream detected\n")); @@ -230,7 +374,10 @@ static void demux_ogg_send_header (demux_ogg_t *this) { this->samplerate[stream_num] = vi.rate; - this->avg_bitrate += vi.bitrate_nominal; + if (vi.bitrate_nominal<1) + this->avg_bitrate += 100000; /* assume 100 kbit */ + else + this->avg_bitrate += vi.bitrate_nominal; } else { this->samplerate[stream_num] = 44100; @@ -243,6 +390,7 @@ static void demux_ogg_send_header (demux_ogg_t *this) { dsogg_header_t *oggh; buf_element_t *buf; xine_bmiheader bih; + int channel; #ifdef LOG printf ("demux_ogg: direct show filter created stream detected, hexdump:\n"); @@ -251,7 +399,9 @@ static void demux_ogg_send_header (demux_ogg_t *this) { oggh = (dsogg_header_t *) &op.packet[1]; - this->buf_types[stream_num] = fourcc_to_buf_video (oggh->subtype); + channel = this->num_video_streams++; + + this->buf_types[stream_num] = fourcc_to_buf_video (oggh->subtype) | channel; #ifdef LOG printf ("demux_ogg: subtype %.4s\n", &oggh->subtype); @@ -292,6 +442,7 @@ static void demux_ogg_send_header (demux_ogg_t *this) { buf_element_t *buf; int codec; char str[5]; + int channel; printf ("demux_ogg: direct show filter created audio stream detected, hexdump:\n"); hex_dump (op.packet, op.bytes); @@ -302,21 +453,23 @@ static void demux_ogg_send_header (demux_ogg_t *this) { str[4] = 0; codec = atoi(str); + channel= this->num_audio_streams++; + switch (codec) { case 0x01: - this->buf_types[stream_num] = BUF_AUDIO_LPCM_LE; + this->buf_types[stream_num] = BUF_AUDIO_LPCM_LE | channel; break; case 55: case 0x55: - this->buf_types[stream_num] = BUF_AUDIO_MPEG; + this->buf_types[stream_num] = BUF_AUDIO_MPEG | channel; break; case 0x2000: - this->buf_types[stream_num] = BUF_AUDIO_A52; + this->buf_types[stream_num] = BUF_AUDIO_A52 | channel; break; default: printf ("demux_ogg: unknown audio codec type 0x%x\n", codec); - this->buf_types[stream_num] = 0; + this->buf_types[stream_num] = BUF_CONTROL_NOP; break; } @@ -355,12 +508,27 @@ static void demux_ogg_send_header (demux_ogg_t *this) { this->buf_types[stream_num] = BUF_CONTROL_NOP; } } + + /* + * send preview buffer + */ + +#ifdef LOG + printf ("demux_ogg: sending preview buffer of stream type %08x\n", + this->buf_types[stream_num]); +#endif + + send_ogg_buf (this, &op, stream_num, BUF_FLAG_PREVIEW); + + if (!ogg_page_bos(&this->og)) + num_preview_buffers --; + } } } } -static void demux_ogg_send_package (demux_ogg_t *this) { +static void demux_ogg_send_content (demux_ogg_t *this) { int i; int stream_num = -1; @@ -421,130 +589,15 @@ static void demux_ogg_send_package (demux_ogg_t *this) { while (ogg_stream_packetout(&this->oss[stream_num], &op) == 1) { /* printf("demux_ogg: packet: %.8s\n", op.packet); */ /* printf("demux_ogg: got a packet\n"); */ - - if ( this->audio_fifo - && (this->buf_types[stream_num] & 0xFF000000) == BUF_AUDIO_BASE) { - buf_element_t *buf; - - buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); - - if (this->buf_types[stream_num] == BUF_AUDIO_VORBIS) { - int op_size = sizeof(op); - ogg_packet *og_ghost; - op_size += (4 - (op_size % 4)); - - /* nasty hack to pack op as well as (vorbis) content - in one xine buffer */ - memcpy (buf->content + op_size, op.packet, op.bytes); - memcpy (buf->content, &op, sizeof(op)); - og_ghost = (ogg_packet *) buf->content; - og_ghost->packet = buf->content + op_size; - - buf->size = op.bytes; - } else { - int hdrlen; - if (*op.packet & PACKET_TYPE_HEADER) { -#ifdef LOG - printf ("demux_ogg: header\n"); -#endif - buf->free_buffer(buf); - continue; - } - - hdrlen = (*op.packet & PACKET_LEN_BITS01) >> 6; - hdrlen |= (*op.packet & PACKET_LEN_BITS2) << 1; - -#ifdef LOG - printf ("demux_ogg: headerlen %d\n",hdrlen); -#endif - - memcpy (buf->content, op.packet+1+hdrlen, op.bytes-1-hdrlen); - buf->size = op.bytes-1-hdrlen; - } - -#ifdef LOG - printf ("demux_ogg: audio buf_size %d\n", buf->size); -#endif - - if (op.granulepos>0) - buf->pts = 90000 * op.granulepos / this->samplerate[stream_num]; - else - buf->pts = 0; - -#ifdef LOG - printf ("demux_ogg: audio granulepos %lld => pts %lld\n", - op.granulepos, buf->pts); -#endif - - buf->input_pos = this->input->get_current_pos (this->input); - buf->input_time = buf->input_pos * 8 / this->avg_bitrate; - - buf->type = this->buf_types[stream_num]; - - this->audio_fifo->put (this->audio_fifo, buf); - } else if ((this->buf_types[stream_num] & 0xFF000000) == BUF_VIDEO_BASE) { - - buf_element_t *buf; - int todo, done, hdrlen; - -#ifdef LOG - printf ("demux_ogg: video buffer, type=%08x\n", this->buf_types[stream_num]); -#endif - - if (*op.packet & PACKET_TYPE_HEADER) { + if (*op.packet & PACKET_TYPE_HEADER) { #ifdef LOG - printf ("demux_ogg: header\n"); + printf ("demux_ogg: header => discard\n"); #endif - continue; - } - - hdrlen = (*op.packet & PACKET_LEN_BITS01) >> 6; - hdrlen |= (*op.packet & PACKET_LEN_BITS2) << 1; - -#ifdef LOG - printf ("demux_ogg: headerlen %d\n",hdrlen); -#endif - - todo = op.bytes-1-hdrlen; - done = 0; - while (done<todo) { - - buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); - - if ( (todo-done)>(buf->max_size-1)) { - buf->size = buf->max_size-1; - buf->decoder_flags = 0; - } else { - buf->size = todo-done; - buf->decoder_flags = BUF_FLAG_FRAME_END; - } - - /* - printf ("demux_ogg: done %d todo %d doing %d\n", done, todo, buf->size); - */ - memcpy (buf->content, op.packet+done, buf->size); - - if (op.granulepos>0) - buf->pts = op.granulepos * this->frame_duration; - else - buf->pts = 0; -#ifdef LOG - printf ("demux_ogg: video granulepos %lld, pts %lld\n", op.granulepos, buf->pts); -#endif - /* buf->pts = 0; */ - - buf->input_pos = this->input->get_current_pos (this->input); - buf->input_time = 0; - - buf->type = this->buf_types[stream_num]; - - done += buf->size; - - this->video_fifo->put (this->video_fifo, buf); - - } + continue; } + + send_ogg_buf (this, &op, stream_num, 0); } } } @@ -563,7 +616,7 @@ static void *demux_ogg_loop (void *this_gen) { /* main demuxer loop */ while(this->status == DEMUX_OK) { - demux_ogg_send_package (this); + demux_ogg_send_content (this); /* someone may want to interrupt us */ pthread_mutex_unlock( &this->mutex ); @@ -663,8 +716,10 @@ static int demux_ogg_start (demux_plugin_t *this_gen, */ ogg_sync_init(&this->oy); - this->num_streams = 0; - this->avg_bitrate = 1; + this->num_streams = 0; + this->num_audio_streams = 0; + this->num_video_streams = 0; + this->avg_bitrate = 1; this->input->seek (this->input, 0, SEEK_SET); diff --git a/src/libvorbis/xine_decoder.c b/src/libvorbis/xine_decoder.c index 5e6d1d00a..5cda59cdd 100644 --- a/src/libvorbis/xine_decoder.c +++ b/src/libvorbis/xine_decoder.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: xine_decoder.c,v 1.14 2002/07/05 17:32:04 mroi Exp $ + * $Id: xine_decoder.c,v 1.15 2002/08/19 22:12:54 guenter Exp $ * * (ogg/)vorbis audio decoder plugin (libvorbis wrapper) for xine */ @@ -38,6 +38,10 @@ #define MAX_NUM_SAMPLES 4096 +/* +#define LOG +*/ + typedef struct vorbis_decoder_s { audio_decoder_t audio_decoder; @@ -86,8 +90,9 @@ static void vorbis_init (audio_decoder_t *this_gen, ao_instance_t *audio_out) { vorbis_info_init(&this->vi); vorbis_comment_init(&this->vc); - +#ifdef LOG printf ("libvorbis: init\n"); +#endif } @@ -96,84 +101,81 @@ static void vorbis_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen; ogg_packet *op = (ogg_packet *) buf->content; - /* - printf ("vorbisdecoder: before buf=%08x content=%08x op=%08x packet=%08x\n", - buf, buf->content, op, op->packet); - */ +#ifdef LOG + printf ("libvorbis: decode buf=%08x content=%08x op=%08x packet=%08x flags=%08x\n", + buf, buf->content, op, op->packet, buf->decoder_flags); +#endif - if (buf->decoder_flags & BUF_FLAG_PREVIEW) - return; - - /* if (buf->decoder_info[0] >0) { */ - - - if (this->header_count) { + if (buf->decoder_flags & BUF_FLAG_PREVIEW) { +#ifdef LOG + printf ("libvorbis: preview buffer\n"); +#endif + if (this->header_count) { - if(vorbis_synthesis_headerin(&this->vi,&this->vc,op)<0){ - /* error case; not a vorbis header */ - printf("libvorbis: this bitstream does not contain Vorbis " - "audio data.\n"); - /* FIXME: handle error */ - } + if(vorbis_synthesis_headerin(&this->vi,&this->vc,op)<0){ + /* error case; not a vorbis header */ + printf("libvorbis: this bitstream does not contain vorbis audio data.\n"); + return; + } - this->header_count--; + this->header_count--; - if (!this->header_count) { + if (!this->header_count) { - int mode = AO_CAP_MODE_MONO; - - { - char **ptr=this->vc.user_comments; - while(*ptr){ - printf("libvorbis: %s\n",*ptr); - ++ptr; + int mode = AO_CAP_MODE_MONO; + + { + char **ptr=this->vc.user_comments; + while(*ptr){ + printf("libvorbis: %s\n",*ptr); + ++ptr; + } + printf ("\nlibvorbis: bitstream is %d channel(s), %ldHz\n", + this->vi.channels, this->vi.rate); + printf("libvorbis: encoded by: %s\n\n",this->vc.vendor); } - printf ("\nlibvorbis: bitstream is %d channel, %ldHz\n", - this->vi.channels, this->vi.rate); - printf("libvorbis: encoded by: %s\n\n",this->vc.vendor); - } - - switch (this->vi.channels) { - case 1: - mode = AO_CAP_MODE_MONO; - break; - case 2: - mode = AO_CAP_MODE_STEREO; - break; - case 4: - mode = AO_CAP_MODE_4CHANNEL; - break; - case 5: - mode = AO_CAP_MODE_5CHANNEL; - break; - case 6: - mode = AO_CAP_MODE_5_1CHANNEL; - break; - default: - printf ("libvorbis: help, %d channels ?!\n", - this->vi.channels); - /* FIXME: handle error */ - } - - this->convsize=MAX_NUM_SAMPLES/this->vi.channels; - - if (!this->output_open) { - this->output_open = this->audio_out->open(this->audio_out, - 16, - this->vi.rate, - mode) ; + + switch (this->vi.channels) { + case 1: + mode = AO_CAP_MODE_MONO; + break; + case 2: + mode = AO_CAP_MODE_STEREO; + break; + case 4: + mode = AO_CAP_MODE_4CHANNEL; + break; + case 5: + mode = AO_CAP_MODE_5CHANNEL; + break; + case 6: + mode = AO_CAP_MODE_5_1CHANNEL; + break; + default: + printf ("libvorbis: help, %d channels ?!\n", + this->vi.channels); + /* FIXME: handle error */ + } + + this->convsize=MAX_NUM_SAMPLES/this->vi.channels; + + if (!this->output_open) { + this->output_open = this->audio_out->open(this->audio_out, + 16, + this->vi.rate, + mode) ; + } + + vorbis_synthesis_init(&this->vd,&this->vi); + vorbis_block_init(&this->vd,&this->vb); } - - vorbis_synthesis_init(&this->vd,&this->vi); - vorbis_block_init(&this->vd,&this->vb); - } + } else if (this->output_open) { float **pcm; int samples; - if(vorbis_synthesis(&this->vb,op)==0) vorbis_synthesis_blockin(&this->vd,&this->vb); |