From ffa655e28f5854bdf0e6782ea94a03f2277d2f36 Mon Sep 17 00:00:00 2001 From: James Stembridge Date: Sat, 4 Jun 2005 20:29:16 +0000 Subject: Bring AC3 demuxer in line with DTS, support raw, cd and wav sources CVS patchset: 7609 CVS date: 2005/06/04 20:29:16 --- src/demuxers/demux_ac3.c | 200 ++++++++++++++++++++++++++++++++++++--------- src/demuxers/demux_wav.c | 39 +-------- src/demuxers/group_audio.c | 4 +- 3 files changed, 164 insertions(+), 79 deletions(-) (limited to 'src') diff --git a/src/demuxers/demux_ac3.c b/src/demuxers/demux_ac3.c index 9590c4b58..3bf92a804 100644 --- a/src/demuxers/demux_ac3.c +++ b/src/demuxers/demux_ac3.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2003 the xine project + * Copyright (C) 2001-2005 the xine project * * This file is part of xine, a free video player. * @@ -23,7 +23,7 @@ * This demuxer detects raw AC3 data in a file and shovels AC3 data * directly to the AC3 decoder. * - * $Id: demux_ac3.c,v 1.17 2005/06/04 12:05:28 jstembridge Exp $ + * $Id: demux_ac3.c,v 1.18 2005/06/04 20:29:16 jstembridge Exp $ */ #ifdef HAVE_CONFIG_H @@ -37,6 +37,12 @@ #include #include +#define LOG_MODULE "demux_ac3" +#define LOG_VERBOSE +/* +#define LOG +*/ + #include "xine_internal.h" #include "xineutils.h" #include "demux.h" @@ -44,7 +50,8 @@ #include "bswap.h" #include "group_audio.h" -#define AC3_PREAMBLE_BYTES 5 +#define DATA_TAG 0x61746164 +#define PEAK_SIZE 7056 /* 3 raw cd frames */ typedef struct { demux_plugin_t demux_plugin; @@ -60,9 +67,10 @@ typedef struct { int frame_size; int running_time; - /* This hack indicates that 2 bytes (0x0B77) have already been consumed - * from a non-seekable stream during the detection phase. */ - int first_non_seekable_frame; + off_t data_start; + + uint32_t buf_type; + } demux_ac3_t; typedef struct { @@ -119,42 +127,144 @@ static const struct frmsize_s frmsizecod_tbl[64] = /* returns 1 if the AC3 file was opened successfully, 0 otherwise */ static int open_ac3_file(demux_ac3_t *this) { - unsigned char preamble[AC3_PREAMBLE_BYTES]; + int i; + int offset = 0; + int peak_size = 0; + int spdif_mode = 0; + uint32_t syncword = 0; + uint32_t blocksize; + uint8_t peak[PEAK_SIZE]; + + lprintf("open_ac3_file\n"); + + /* block based demuxer (i.e. cdda) will only allow reads in block + * sized pieces */ + blocksize = this->input->get_blocksize(this->input); + if (blocksize && INPUT_IS_SEEKABLE(this->input)) { + int read; + + this->input->seek(this->input, 0, SEEK_SET); + while (peak_size < PEAK_SIZE) { + read = this->input->read(this->input, &peak[peak_size], blocksize); + if (read) + peak_size += read; + else + break; + } + this->input->seek(this->input, 0, SEEK_SET); + } else { + peak_size = MAX_PREVIEW_SIZE; - /* check if the sync mark matches up */ - if (_x_demux_read_header(this->input, preamble, AC3_PREAMBLE_BYTES) != - AC3_PREAMBLE_BYTES) - return 0; + if (_x_demux_read_header(this->input, peak, peak_size) != peak_size) + return 0; + } - if ((preamble[0] != 0x0B) || - (preamble[1] != 0x77)) - return 0; + lprintf("peak size: %d\n", peak_size); + + /* Check for wav header, as we'll handle AC3 with a wav header shoved + * on the front for CD burning */ + if ((peak[0] == 'R') && (peak[1] == 'I') && (peak[2] == 'F') && + (peak[3] == 'F') && (peak[8] == 'W') && (peak[9] == 'A') && + (peak[10] == 'V') && (peak[11] == 'E') && (peak[12] == 'f') && + (peak[13] == 'm') && (peak[14] == 't') && (peak[15] == ' ')) { + /* Check this looks like a cd audio wav */ + unsigned int audio_type; + xine_waveformatex *wave = (xine_waveformatex *) &peak[20]; + + _x_waveformatex_le2me(wave); + audio_type = _x_formattag_to_buf_audio(wave->wFormatTag); + + if ((audio_type != BUF_AUDIO_LPCM_LE) || (wave->nChannels != 2) || + (wave->nSamplesPerSec != 44100) || (wave->wBitsPerSample != 16)) + return 0; + + lprintf("looks like a cd audio wav file\n"); + + /* Find the data chunk */ + offset = 20 + LE_32(&peak[16]); + while (offset < peak_size-8) { + unsigned int chunk_tag = LE_32(&peak[offset]); + unsigned int chunk_size = LE_32(&peak[offset+4]); + + if (chunk_tag == DATA_TAG) { + offset += 8; + lprintf("found the start of the data at offset %d\n", offset); + break; + } else + offset += chunk_size; + } + } - /* file is qualified; skip over the header bytes in the stream */ - this->input->seek(this->input, AC3_PREAMBLE_BYTES, SEEK_SET); + /* Look for a valid AC3 sync word */ + for (i=offset; idata_start = i-2; + lprintf("found AC3 syncword at offset %d\n", i-2); + break; + } - this->sample_rate = preamble[4] >> 6; - if (this->sample_rate > 2) - return 0; + if ((syncword == 0x72f81f4e) && (peak[i] == 0x01)) { + spdif_mode = 1; + this->data_start = i+4; + lprintf("found AC3 SPDIF header at offset %d\n", i-4); + break; + } + + syncword = (syncword << 8) | peak[i]; + } - this->frame_size = - frmsizecod_tbl[preamble[4] & 0x3F].frm_size[this->sample_rate] * 2; + if (i >= peak_size-2) + return 0; - /* convert the sample rate to a more useful number */ - if (this->sample_rate == 0) - this->sample_rate = 48000; - else if (this->sample_rate == 1) + if (spdif_mode) { this->sample_rate = 44100; - else - this->sample_rate = 32000; + this->frame_size = 256*6*4; + this->buf_type = BUF_AUDIO_DNET; + } else { + int fscod, frmsizecod; + + fscod = peak[this->data_start+4] >> 6; + frmsizecod = peak[this->data_start+4] & 0x3F; + + if ((fscod > 2) || (frmsizecod > 37)) + return 0; + + this->frame_size = frmsizecod_tbl[frmsizecod].frm_size[fscod] * 2; + + /* convert the sample rate to a more useful number */ + switch (fscod) { + case 0: + this->sample_rate = 48000; + break; + case 1: + this->sample_rate = 44100; + break; + default: + this->sample_rate = 32000; + break; + } + + /* Look for a second sync word */ + if ((this->data_start+this->frame_size+1 >= peak_size) || + (peak[this->data_start+this->frame_size] != 0x0b) || + (peak[this->data_start+this->frame_size + 1] != 0x77)) { + return 0; + } - this->running_time = this->input->get_length(this->input); + lprintf("found second AC3 sync word\n"); + + this->buf_type = BUF_AUDIO_A52; + } + + this->running_time = this->input->get_length(this->input) - + this->data_start; this->running_time /= this->frame_size; this->running_time *= (90000 / 1000) * (256 * 6); this->running_time /= this->sample_rate; - if (!INPUT_IS_SEEKABLE(this->input)) - this->first_non_seekable_frame = 1; + lprintf("sample rate: %d\n", this->sample_rate); + lprintf("frame size: %d\n", this->frame_size); + lprintf("running time: %d\n", this->running_time); return 1; } @@ -166,6 +276,7 @@ static int demux_ac3_send_chunk (demux_plugin_t *this_gen) { off_t current_stream_pos; int64_t audio_pts; int frame_number; + uint32_t blocksize; current_stream_pos = this->input->get_current_pos(this->input); frame_number = current_stream_pos / this->frame_size; @@ -188,15 +299,24 @@ static int demux_ac3_send_chunk (demux_plugin_t *this_gen) { this->seek_flag = 0; } - buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); - if (this->first_non_seekable_frame) { - this->first_non_seekable_frame = 0; - buf->content[0] = 0x0B; - buf->content[1] = 0x77; - buf->size = this->input->read(this->input, &buf->content[2], - this->frame_size); + blocksize = this->input->get_blocksize(this->input); + if (blocksize) { + buf = this->input->read_block(this->input, this->audio_fifo, + blocksize); + if (!buf) { + this->status = DEMUX_FINISHED; + return this->status; + } } else { - buf->size = this->input->read(this->input, buf->content, this->frame_size); + buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + buf->size = this->input->read(this->input, buf->content, + this->frame_size); + } + + if (buf->size == 0) { + buf->free_buffer(buf); + this->status = DEMUX_FINISHED; + return this->status; } if (buf->size == 0) { @@ -205,7 +325,7 @@ static int demux_ac3_send_chunk (demux_plugin_t *this_gen) { return this->status; } - buf->type = BUF_AUDIO_A52; + buf->type = this->buf_type; if( this->input->get_length (this->input) ) buf->extra_info->input_normpos = (int)( (double) current_stream_pos * 65535 / this->input->get_length (this->input) ); @@ -237,7 +357,7 @@ static void demux_ac3_send_headers(demux_plugin_t *this_gen) { /* send init info to decoders */ if (this->audio_fifo) { buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); - buf->type = BUF_AUDIO_A52; + buf->type = this->buf_type; buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_FRAME_END; buf->size = 0; this->audio_fifo->put (this->audio_fifo, buf); diff --git a/src/demuxers/demux_wav.c b/src/demuxers/demux_wav.c index 48074aa3c..e23f43aa5 100644 --- a/src/demuxers/demux_wav.c +++ b/src/demuxers/demux_wav.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2003 the xine project + * Copyright (C) 2001-2005 the xine project * * This file is part of xine, a free video player. * @@ -22,7 +22,7 @@ * MS WAV File Demuxer by Mike Melanson (melanson@pcisys.net) * based on WAV specs that are available far and wide * - * $Id: demux_wav.c,v 1.62 2005/05/28 09:34:53 jstembridge Exp $ + * $Id: demux_wav.c,v 1.63 2005/06/04 20:29:16 jstembridge Exp $ */ #ifdef HAVE_CONFIG_H @@ -146,31 +146,6 @@ static int open_wav_file(demux_wav_t *this) { this->input->seek(this->input, chunk_size, SEEK_CUR); } } - if (this->audio_type == BUF_AUDIO_LPCM_LE) { - if (this->input->read(this->input, chunk_preamble, 6) != 6 ) { - free (this->wave); - return 0; - } - /* rewind the amount we just read */ - this->input->seek(this->input, -6, SEEK_CUR); - - if (chunk_preamble[0] == 0x72 && - chunk_preamble[1] == 0xf8 && - chunk_preamble[2] == 0x1f && - chunk_preamble[3] == 0x4e ) { - this->audio_type = BUF_AUDIO_DNET; - } -#if 0 - printf("Preamble=%02x %02x %02x %02x %02x %02x\n", - chunk_preamble[0], - chunk_preamble[1], - chunk_preamble[2], - chunk_preamble[3], - chunk_preamble[4], - chunk_preamble[5]); -#endif - - } return 1; } @@ -235,16 +210,6 @@ static int demux_wav_send_chunk(demux_plugin_t *this_gen) { printf("\n"); #endif - if (this->audio_type == BUF_AUDIO_LPCM_LE) { - if (buf->content[0] == 0x72 && - buf->content[1] == 0xf8 && - buf->content[2] == 0x1f && - buf->content[3] == 0x4e ) { - this->audio_type = BUF_AUDIO_DNET; - } - } else if (this->audio_type == BUF_AUDIO_DNET) { - buf->pts=0; /* We don't need pts values for only audio streams. */ - } #if 0 for(n=0;n<20;n++) { printf("%x ",buf->content[n]); diff --git a/src/demuxers/group_audio.c b/src/demuxers/group_audio.c index 438b71554..cce736525 100644 --- a/src/demuxers/group_audio.c +++ b/src/demuxers/group_audio.c @@ -19,7 +19,7 @@ * * This file contains plugin entries for several demuxers used in games * - * $Id: group_audio.c,v 1.20 2005/05/29 19:20:48 jstembridge Exp $ + * $Id: group_audio.c,v 1.21 2005/06/04 20:29:16 jstembridge Exp $ */ #ifdef HAVE_CONFIG_H @@ -40,7 +40,7 @@ demuxer_info_t demux_info_aac = { }; demuxer_info_t demux_info_ac3 = { - 0 /* priority */ + 8 /* priority */ }; demuxer_info_t demux_info_aud = { -- cgit v1.2.3