From 01937cd481480ffee312631e57f52dd3236840b5 Mon Sep 17 00:00:00 2001 From: Mike Melanson Date: Fri, 14 Feb 2003 04:32:27 +0000 Subject: PSX STR demuxer improvements and XA ADPCM decoder courtesy of Stuart Caie CVS patchset: 4153 CVS date: 2003/02/14 04:32:27 --- src/demuxers/demux_str.c | 497 +++++++++++++++++++++++++++++++++++++---------- src/libxineadec/adpcm.c | 244 ++++++++++++++++++++++- 2 files changed, 634 insertions(+), 107 deletions(-) (limited to 'src') diff --git a/src/demuxers/demux_str.c b/src/demuxers/demux_str.c index 8a9c2ac15..76a96d3c7 100644 --- a/src/demuxers/demux_str.c +++ b/src/demuxers/demux_str.c @@ -18,10 +18,92 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * STR File Demuxer by Mike Melanson (melanson@pcisys.net) + * and Stuart Caie (kyzer@4u.net) * This demuxer handles either raw STR files (which are just a concatenation * of raw compact disc sectors) or STR files with RIFF headers. * - * $Id: demux_str.c,v 1.4 2003/01/26 15:56:21 tmmm Exp $ + * $Id: demux_str.c,v 1.5 2003/02/14 04:32:28 tmmm Exp $ + */ + +/* CD-XA format: + * + * - the format is a series of 2352 byte CD sectors + * - 0x000: 12 bytes: sync header (00 FF FF FF FF FF FF FF FF FF FF 00) + * - 0x00C: 4 bytes: timecode (mm ss ff 02; BCD, not decimal!) + * - 0x010: 4 bytes: sector parameters + * - 0x10 file_num + * - 0x11 channel_num + * - 0x12 subcode + * - 0x13 coding_info + * - 0x014: 4 bytes: copy of parameters (should be identical) + * - 0x018: 2324 bytes: sector data + * - 0x92C: 4 bytes: EDC error correction code + * - 0x930: SIZEOF + * + * - file_num is purely to distinguish where a 'file' ends and a new + * 'file' begins among the sectors. It's usually 1. + * - channel_num is a sub-channel in this 'file'. Video, audio and data + * sectors can be mixed into the same channel or can be on seperate + * channels. Usually used for multiple audio tracks (e.g. 5 different + * songs in the same 'file', on channels 0, 1, 2, 3 and 4) + * - subcode is a set of bits + * - bit 7: eof_marker -- 0, or 1 if this sector is the end of the 'file' + * - bit 6: real_time -- unimportant (always set in PSX STR streams) + * - bit 5: form -- unimportant + * - bit 4: trigger -- for use by reader application (unimportant) + * - bit 3: DATA -- set to 1 to indicate DATA sector, otherwise 0 + * - bit 2: AUDIO -- set to 1 to indicate AUDIO sector, otherwise 0 + * - bit 1: VIDEO -- set to 1 to indicate VIDEO sector, otherwise 0 + * - bit 0: end_audio -- end of audio frame (never set in PSX STR streams) + * - bits 1, 2 and 3 are mutually exclusive + * - coding_info is a set of bits, interpretation is dependant on the + * DATA/AUDIO/VIDEO bits setting of subcode. + * - For AUDIO: + * - bit 7: reserved -- should always be 0 + * - bit 6: emphasis -- boost audio volume (ignored by us) + * - bit 5: bitssamp -- must always be 0 + * - bit 4: bitssamp -- 0 for mode B/C (4 bits/sample, 8 sound sectors) + * 1 for mode A (8 bits/sample, 4 sound sectors) + * - bit 3: samprate -- must always be 0 + * - bit 2: samprate -- 0 for 37.8kHz playback, 1 for 18.9kHz playback + * - bit 1: stereo -- must always be 0 + * - bit 0: stereo -- 0 for mono sound, 1 for stereo sound + * - For DATA or VIDEO: + * - always seems to be 0 in PSX STR files + * + * Format of sector data in AUDIO sectors: + * - 18 "sound groups" of 128 byte structures + * - 20 unused bytes + * - we pass these 18*128 bytes to the XA_ADPCM audio decoder + * + * Format of sector data in DATA or VIDEO sectors: + * - all values are little-endian + * - 0x00: 32 bits; unknown -- usually 0x80010160 for a video frame. + * according to PSX hardware guide, this value is written + * to mdec0 register: + * - bit 27: 1 for 16-bit colour, 0 for 24-bit colour depth + * - bit 24: if 16-bit colour, 1/0=set/clear transparency bit + * - all other bits unknown + * - if not set to this value, it's not a video sector. + * - 0x04: 16 bits; 'chunk number' of this video frame (0 to numchunks-1) + * - 0x06: 16 bits; number of chunks in this frame + * - 0x08: 32 bits; frame number (1 to ...) + * - 0x0C: 32 bits; seemingly random number. frame duration? + * - 0x10: 16 bits; width of frame in pixels + * - 0x12: 16 bits; height of frame in pixels + * - remainder of data (up to 2304 bytes): compressed MDEC stream + * - 32 bits: (0x3800 << 16) | size of data (in bytes) following this header + * - any number of macroblocks (which each represent a 16x16 pixel area) + * - a macroblock is 6 blocks (Cb, Cr, Y0, Y1, Y2 and Y3) + * - a block is a DCT setting then an RLE data stream + * - 16 bits: DCT (bits 15-10: quantisation factor (unsigned) + * bits 9-0: Direct Current reference (signed)) + * - then follows 16-bit RLE data until the EOD + * - RLE format: bits 15-10: # of 0s preceding this value (unsigned) + * bits 9-0: this value (signed) + * - e.g. 3 bytes (2,10)(0,20)(3,30) -> 0 0 10 20 0 0 0 30 + * - 16 bits: EOD (0xFE00) + * - 16 bits: 0xFE00 end-of-data footer */ #ifdef HAVE_CONFIG_H @@ -40,11 +122,25 @@ #include "demux.h" #include "bswap.h" -/* 68 bytes is adequate for empirically determining if a file conforms */ -#define STR_CHECK_BYTES 0x68 +/* There may be a RIFF/CDXA header at the beginning of the file, which + * accounts for 0x2C bytes. We need at most 0x30 bytes of the sector to + * verify whether it's a CDXA/MDEC file + */ + +#define STR_CHECK_BYTES (0x2C + 0x30) #define CD_RAW_SECTOR_SIZE 2352 +#define STR_MAX_CHANNELS 32 + +#define STR_MAGIC (0x80010160) + +#define CDXA_TYPE_MASK 0x0E +#define CDXA_TYPE_DATA 0x08 +#define CDXA_TYPE_AUDIO 0x04 +#define CDXA_TYPE_VIDEO 0x02 +#define CDXA_SUBMODE_EOF 0x80 /* set if EOF */ + #define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \ ( (long)(unsigned char)(ch3) | \ ( (long)(unsigned char)(ch2) << 8 ) | \ @@ -54,8 +150,7 @@ #define RIFF_TAG FOURCC_TAG('R', 'I', 'F', 'F') #define CDXA_TAG FOURCC_TAG('C', 'D', 'X', 'A') -/* this is a temporary measure; hopefully there is a more accurate method - * for finding frame duration */ +/* FIXME */ #define FRAME_DURATION 45000 typedef struct { @@ -78,13 +173,18 @@ typedef struct { off_t data_start; off_t data_size; + off_t current_pos; int status; - xine_bmiheader bih; - int audio_samplerate; + xine_bmiheader bih[STR_MAX_CHANNELS]; + unsigned char audio_info[STR_MAX_CHANNELS]; + unsigned char channel_type[STR_MAX_CHANNELS]; + int64_t audio_pts[STR_MAX_CHANNELS]; - char last_mrl[1024]; + int seek_flag; + int default_video_channel; + char last_mrl[1024]; } demux_str_t; typedef struct { @@ -100,148 +200,324 @@ typedef struct { /* returns 1 if the STR file was opened successfully, 0 otherwise */ static int open_str_file(demux_str_t *this) { - unsigned char check_bytes[STR_CHECK_BYTES]; + int local_offset, sector, channel; - this->bih.biWidth = this->bih.biHeight = 0; + for (channel = 0; channel < STR_MAX_CHANNELS; channel++) { + this->channel_type[channel] = 0; + } this->input->seek(this->input, 0, SEEK_SET); if (this->input->read(this->input, check_bytes, STR_CHECK_BYTES) != - STR_CHECK_BYTES) + STR_CHECK_BYTES) { +#ifdef LOG + printf("PSX STR: read error\n"); +#endif return 0; + } /* check for STR with a RIFF header */ if ((BE_32(&check_bytes[0]) == RIFF_TAG) && (BE_32(&check_bytes[8]) == CDXA_TAG)) - this->data_start = 0x2C; + local_offset = 0x2C; else - this->data_start = 0; - - /* now that we have the theoretical start of the first sector, check - * if it really is a raw CD sector; first step: check for 12-byte - * sync marker */ - if ((BE_32(&check_bytes[this->data_start + 0]) != 0x00FFFFFF) || - (BE_32(&check_bytes[this->data_start + 4]) != 0xFFFFFFFF) || - (BE_32(&check_bytes[this->data_start + 8]) != 0xFFFFFF00)) - return 0; + local_offset = 0; - /* the 32 bits starting at 0x10 and at 0x14 should be the same */ - if (BE_32(&check_bytes[this->data_start + 0x10]) != - BE_32(&check_bytes[this->data_start + 0x14])) - return 0; + this->data_start = (off_t) local_offset; - /* check if this an audio or video sector (bit 1 = video, bit 2 = - * audio) */ - if ((check_bytes[this->data_start + 0x12] & 0x06) == 0x2) { + /* we need to check up to 32 sectors for up to 32 audio/video channels */ + for (sector = 0; sector < STR_MAX_CHANNELS; sector++) { - /* video is suspected */ +#ifdef LOG + printf("PSX STR: file=%d channel=%-2d submode=%02x coding_info=%02x\n", + check_bytes[local_offset + 0x10], + check_bytes[local_offset + 0x11], + check_bytes[local_offset + 0x12], + check_bytes[local_offset + 0x13]); +#endif - this->bih.biWidth = LE_16(&check_bytes[this->data_start + 0x28]); - this->bih.biHeight = LE_16(&check_bytes[this->data_start + 0x2A]); + /* check for 12-byte sync marker */ + if ((BE_32(&check_bytes[local_offset + 0]) != 0x00FFFFFF) || + (BE_32(&check_bytes[local_offset + 4]) != 0xFFFFFFFF) || + (BE_32(&check_bytes[local_offset + 8]) != 0xFFFFFF00)) { +#ifdef LOG + printf("PSX STR: sector %d sync error\n", sector); +#endif + return 0; + } - /* sanity check for the width and height */ - if ((this->bih.biWidth <= 0) || - (this->bih.biWidth > 320) || - (this->bih.biHeight <= 0) || - (this->bih.biHeight > 240)) + /* the 32 bits starting at 0x10 and at 0x14 should be the same */ + if (BE_32(&check_bytes[local_offset + 0x10]) != + BE_32(&check_bytes[local_offset + 0x14])) { +#ifdef LOG + printf("PSX STR: sector %d control bits copy error\n", sector); +#endif return 0; + } - } else if ((check_bytes[this->data_start + 0x12] & 0x06) == 0x4) { + /* channel should be from 0 to 31 */ + channel = check_bytes[local_offset + 0x11]; + if (channel >= STR_MAX_CHANNELS) { +#ifdef LOG + printf("PSX STR: sector %d channel %d error\n", sector, channel); +#endif + return 0; + } - /* audio is suspected */ + /* switch on the sector type */ + switch(check_bytes[local_offset + 0x12] & CDXA_TYPE_MASK) { - } else - return 0; + case CDXA_TYPE_DATA: + case CDXA_TYPE_VIDEO: + /* first time we have seen video/data in this channel? */ + if ((!(this->channel_type[channel] & CDXA_TYPE_DATA)) && + (LE_32(&check_bytes[local_offset + 0x18]) == STR_MAGIC)) { + + /* mark this channel as having video data */ + this->channel_type[channel] |= CDXA_TYPE_VIDEO; + + this->bih[channel].biWidth = + LE_16(&check_bytes[local_offset + 0x18 + 0x10]); + this->bih[channel].biHeight = + LE_16(&check_bytes[local_offset + 0x18 + 0x12]); + } + break; + + case CDXA_TYPE_AUDIO: + /* first time we have seen audio in this channel? */ + if (!(this->channel_type[channel] & CDXA_TYPE_AUDIO)) { + + /* mark this channel as having audio data */ + this->channel_type[channel] |= CDXA_TYPE_AUDIO; + + this->audio_info[channel] = check_bytes[local_offset + 0x13]; + } + break; + default: +#ifdef LOG + printf("PSX STR: sector %d channel %d unknown type error\n", + sector, channel); +#endif + /* several films (e.g. 37xa16.xap in Strider 1) have empty + * sectors with 0 as the type, despite having plenty of + * video/audio sectors + */ + /*return 0;*/ + } + + /* seek to the next sector and read in the header */ + local_offset = 0; + this->input->seek(this->input, this->data_start + + ((sector+1) * CD_RAW_SECTOR_SIZE), SEEK_SET); + if (this->input->read(this->input, check_bytes, 0x30) != 0x30) { +#ifdef LOG + printf("PSX STR: sector %d read error\n", sector); +#endif + return 0; + } + } + + /* acceptable STR file */ this->data_size = this->input->get_length(this->input) - this->data_start; +#ifdef LOG + for (channel = 0; channel < STR_MAX_CHANNELS; channel++) { + char vidinfo[22]; /* "Video (XXXXX x XXXXX)" */ + char audinfo[33]; /* "Audio (XX.XkHz XXXXXX, mode XXX)" */ + if (this->channel_type[channel]) { + if (this->channel_type[channel] & CDXA_TYPE_VIDEO) { + snprintf(vidinfo, 22, "Video (%d x %d)", + this->bih[channel].biWidth, + this->bih[channel].biHeight); + } + else { + strcpy(vidinfo, "No video"); + } + if (this->channel_type[channel] & CDXA_TYPE_AUDIO) { + snprintf(audinfo, 33, "Audio (%skHz %s, mode %s)", + this->audio_info[channel] & 0x04 ? "18.9" : "37.8", + this->audio_info[channel] & 0x01 ? "stereo" : "mono", + this->audio_info[channel] & 0x10 ? "A" : "B/C"); + } + else { + strcpy(audinfo, "No audio"); + } + printf("PSX STR: channel %-2d %-22s%s\n", channel, vidinfo, audinfo); + } + } +#endif + return 1; } static int demux_str_send_chunk(demux_plugin_t *this_gen) { - demux_str_t *this = (demux_str_t *) this_gen; - unsigned char sector[CD_RAW_SECTOR_SIZE]; - unsigned int frame_number; + unsigned char sector[CD_RAW_SECTOR_SIZE], channel; + uint32_t frame_number; buf_element_t *buf; + off_t current_pos; + current_pos = this->current_pos; + this->current_pos += CD_RAW_SECTOR_SIZE; if (this->input->read(this->input, sector, CD_RAW_SECTOR_SIZE) != - CD_RAW_SECTOR_SIZE) { + CD_RAW_SECTOR_SIZE) { this->status = DEMUX_FINISHED; return this->status; } - if ((sector[0x12] & 0x06) == 0x2) { + channel = sector[0x11]; + if (channel >= STR_MAX_CHANNELS) return 0; + switch (sector[0x12] & CDXA_TYPE_MASK) { + case CDXA_TYPE_VIDEO: + case CDXA_TYPE_DATA: /* video chunk */ - frame_number = LE_32(§or[0x20]); + + if (LE_32(§or[0x18]) != STR_MAGIC || + channel != this->default_video_channel) { + return 0; + } + + frame_number = LE_32(§or[0x18 + 0x08]); buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); - buf->type = BUF_VIDEO_PSX_MDEC; - buf->extra_info->input_pos = - this->data_start + frame_number * CD_RAW_SECTOR_SIZE; - buf->extra_info->input_length = this->data_size; buf->pts = frame_number * FRAME_DURATION; - buf->extra_info->input_time = buf->pts / 90; + + if (this->seek_flag) { + xine_demux_control_newpts(this->stream, buf->pts, 0); + this->seek_flag = 0; + } + + /* first chunk of frame? sync forthcoming audio packets */ + /* FIXME */ + /*if (LE_16(§or[0x18+0x04]) == 0) { + * int i; + * for (i = 0; i < STR_MAX_CHANNELS; i++) this->audio_pts[i] = buf->pts; + *} + */ + + buf->extra_info->input_pos = current_pos; + buf->extra_info->input_length = this->data_size; + buf->extra_info->input_time = (current_pos*1000)/(CD_RAW_SECTOR_SIZE*75); /* constant size chunk */ - buf->size = 2048; - memcpy(buf->content, §or[0x38], 2048); + buf->size = 2304; + xine_fast_memcpy(buf->content, §or[0x18+0x14], 2304); /* entirely intracoded */ buf->decoder_flags |= BUF_FLAG_KEYFRAME; /* if the current chunk is 1 less than the chunk count, this is the * last chunk of the frame */ - if ((LE_16(§or[0x1C]) + 1) == LE_16(§or[0x1E])) + if ((LE_16(§or[0x18+0x04]) + 1) == LE_16(§or[0x18+0x06])) buf->decoder_flags |= BUF_FLAG_FRAME_END; + buf->type = BUF_VIDEO_PSX_MDEC | channel; this->video_fifo->put(this->video_fifo, buf); + break; - } else if ((sector[0x12] & 0x06) == 0x4) { + case CDXA_TYPE_AUDIO: + /* audio frame */ + + if (this->audio_fifo) { + buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + + buf->pts = this->audio_pts[channel]; + this->audio_pts[channel] += + (((sector[0x13] & 0x10) ? 2016 : 4032) * + ((sector[0x13] & 0x01) ? 45000 : 90000)) / + ((sector[0x13] & 0x04) ? 18900 : 37800); + + if (this->seek_flag) { + xine_demux_control_newpts(this->stream, buf->pts, 0); + this->seek_flag = 0; + } + + buf->extra_info->input_pos = current_pos; + buf->extra_info->input_length = this->data_size; + buf->extra_info->input_time = (current_pos*1000)/(CD_RAW_SECTOR_SIZE*75); + + buf->size = 2304; + xine_fast_memcpy(buf->content, §or[0x18], 2304); + + buf->type = BUF_AUDIO_XA_ADPCM | channel; + buf->decoder_flags |= BUF_FLAG_FRAME_END; + this->audio_fifo->put (this->audio_fifo, buf); + } + break; } return this->status; } static void demux_str_send_headers(demux_plugin_t *this_gen) { - demux_str_t *this = (demux_str_t *) this_gen; buf_element_t *buf; + char audio_info; + int channel, video_channel = -1; this->video_fifo = this->stream->video_fifo; this->audio_fifo = this->stream->audio_fifo; this->status = DEMUX_OK; - /* load stream information */ - this->stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO] = 1; - this->stream->stream_info[XINE_STREAM_INFO_HAS_AUDIO] = 1; - this->stream->stream_info[XINE_STREAM_INFO_VIDEO_WIDTH] = this->bih.biWidth; - this->stream->stream_info[XINE_STREAM_INFO_VIDEO_HEIGHT] = this->bih.biHeight; - /* send start buffers */ xine_demux_control_start(this->stream); - /* send init info to video decoder */ - buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); - buf->decoder_flags = BUF_FLAG_HEADER; - buf->decoder_info[0] = 0; - buf->decoder_info[1] = FRAME_DURATION; /* initial video_step */ - memcpy(buf->content, &this->bih, sizeof(this->bih)); - buf->size = sizeof(this->bih); - buf->type = BUF_VIDEO_PSX_MDEC; - this->video_fifo->put (this->video_fifo, buf); - - /* send init info to the audio decoder */ - if (this->audio_fifo) { - buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); - buf->type = BUF_AUDIO_XA_ADPCM; - buf->decoder_flags = BUF_FLAG_HEADER; - buf->decoder_info[0] = 0; - buf->decoder_info[1] = 37800; - buf->decoder_info[2] = 16; - buf->decoder_info[3] = 1; - this->audio_fifo->put (this->audio_fifo, buf); + /* load stream information */ + this->stream->stream_info[XINE_STREAM_INFO_SEEKABLE] = 1; + this->stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO] = 0; + this->stream->stream_info[XINE_STREAM_INFO_HAS_AUDIO] = 0; + + for (channel = 0; channel < STR_MAX_CHANNELS; channel++) { + if (this->channel_type[channel] & CDXA_TYPE_VIDEO) { + if (video_channel == -1) { + /* FIXME: until I figure out how to comfortably let the user + * pick a video channel, just pick a single video channel */ + video_channel = this->default_video_channel = channel; + this->stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO] = 1; + + this->stream->stream_info[XINE_STREAM_INFO_VIDEO_WIDTH] = + this->bih[channel].biWidth; + this->stream->stream_info[XINE_STREAM_INFO_VIDEO_HEIGHT] = + this->bih[channel].biHeight; + + /* send init info to video decoder */ + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + buf->decoder_flags = BUF_FLAG_HEADER; + buf->decoder_info[0] = 0; + buf->decoder_info[1] = FRAME_DURATION; /* initial video_step */ + buf->size = sizeof(xine_bmiheader); + memcpy(buf->content, &this->bih[channel], buf->size); + buf->type = BUF_VIDEO_PSX_MDEC; + this->video_fifo->put (this->video_fifo, buf); + } + } + + if (this->channel_type[channel] & CDXA_TYPE_AUDIO) { + this->stream->stream_info[XINE_STREAM_INFO_HAS_AUDIO] = 1; + + audio_info = this->audio_info[channel]; + this->stream->stream_info[XINE_STREAM_INFO_AUDIO_CHANNELS] = + (audio_info & 0x01) ? 2 : 1; + this->stream->stream_info[XINE_STREAM_INFO_AUDIO_SAMPLERATE] = + (audio_info & 0x04) ? 18900 : 37800; + this->stream->stream_info[XINE_STREAM_INFO_AUDIO_BITS] = 16; + + /* send init info to the audio decoder */ + if (this->audio_fifo) { + buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + buf->type = BUF_AUDIO_XA_ADPCM | channel; + buf->decoder_flags = BUF_FLAG_HEADER; + buf->decoder_info[0] = 0; + buf->decoder_info[1] = (audio_info & 0x04) ? 18900 : 37800; + buf->decoder_info[2] = (audio_info & 0x10) ? 1 : 0; + buf->decoder_info[3] = (audio_info & 0x01) ? 2 : 1; + this->audio_fifo->put (this->audio_fifo, buf); + + this->audio_pts[channel] = 0; + } + } } } @@ -250,18 +526,21 @@ static int demux_str_seek (demux_plugin_t *this_gen, demux_str_t *this = (demux_str_t *) this_gen; - /* if thread is not running, initialize demuxer */ - if( !this->stream->demux_thread_running ) { - - /* send new pts */ - xine_demux_control_newpts(this->stream, 0, 0); - - this->status = DEMUX_OK; + xine_demux_flush_engine (this->stream); + /* round to ensure we start on a sector */ + start_pos /= CD_RAW_SECTOR_SIZE; +#ifdef LOG + printf("PSX STR: seeking to sector %d (%02d:%02d)\n", + (int)start_pos, (int)start_pos / (60*75), + ((int)start_pos / 75)%60); +#endif - /* reposition at the start of the sectors */ - this->input->seek(this->input, this->data_start, SEEK_SET); - } + /* reposition at the chosen sector */ + this->current_pos = start_pos * CD_RAW_SECTOR_SIZE; + this->input->seek(this->input, this->data_start+this->current_pos, SEEK_SET); + this->seek_flag = 1; + this->status = DEMUX_OK; return this->status; } @@ -278,6 +557,10 @@ static int demux_str_get_status (demux_plugin_t *this_gen) { } static int demux_str_get_stream_length (demux_plugin_t *this_gen) { + demux_str_t *this = (demux_str_t *) this_gen; + + return (int)((int64_t) this->input->get_length(this->input) + * 1000 / (CD_RAW_SECTOR_SIZE * 75)); return 0; } @@ -291,6 +574,11 @@ static int demux_str_get_optional_data(demux_plugin_t *this_gen, return DEMUX_OPTIONAL_UNSUPPORTED; } +static char *get_extensions (demux_class_t *this_gen) { + /* also .mov, but we don't want to hijack that extension */ + return "str iki ik2 dps dat xa xa1 xa2 xas xap"; +} + static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *stream, input_plugin_t *input_gen) { @@ -298,7 +586,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str demux_str_t *this; if (! (input->get_capabilities(input) & INPUT_CAP_SEEKABLE)) { - printf(_("demux_str.c: input not seekable, can not handle!\n")); + printf(_("PSX STR: input not seekable, can not handle!\n")); return NULL; } @@ -332,18 +620,28 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str break; case METHOD_BY_EXTENSION: { - char *ending, *mrl; + char *ending, *mrl, i, *extn; mrl = input->get_mrl (input); ending = strrchr(mrl, '.'); if (!ending) { - free (this); + free(this); return NULL; } - if (strncasecmp (ending, ".str", 4)) { + /* find if any of the extensions match */ + extn = get_extensions((demux_class_t *) this); + for (i = 0; *extn; extn++) { + if (*extn == ' ') { + if (ending[i+1] == '\0') break; + } + else { + if (*extn == ending[i+1]) i++; else i = 0; + } + } + if (ending[i+1] != '\0') { free (this); return NULL; } @@ -354,7 +652,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str } } - break; default: @@ -375,18 +672,12 @@ static char *get_identifier (demux_class_t *this_gen) { return "PSX STR"; } -static char *get_extensions (demux_class_t *this_gen) { - return "str"; -} - static char *get_mimetypes (demux_class_t *this_gen) { return NULL; } static void class_dispose (demux_class_t *this_gen) { - demux_str_class_t *this = (demux_str_class_t *) this_gen; - free (this); } diff --git a/src/libxineadec/adpcm.c b/src/libxineadec/adpcm.c index 12ac4c6da..87b03b4dd 100644 --- a/src/libxineadec/adpcm.c +++ b/src/libxineadec/adpcm.c @@ -23,8 +23,15 @@ * formats that various entities have created. Details about the data * formats can be found here: * http://www.pcisys.net/~melanson/codecs/ + * CD-ROM/XA ADPCM decoder by Stuart Caie (kyzer@4u.net) + * - based on information in the USENET post by Jac Goudsmit (jac@codim.nl) + * <01bbc34c$dbf64020$f9c8a8c0@cray.codim.nl> + * - tested for correctness using Jon Atkins's CDXA software: + * http://jonatkins.org/cdxa/ + * this is also useful for extracting streams from Playstation discs * - * $Id: adpcm.c,v 1.28 2003/02/14 00:55:52 miguelfreitas Exp $ + * + * $Id: adpcm.c,v 1.29 2003/02/14 04:32:28 tmmm Exp $ */ #include @@ -83,6 +90,10 @@ static int ea_adpcm_table[] = { 3, 4, 7, 8, 10, 11, 0, -1, -3, -4 }; +static int xa_adpcm_table[] = { + 0, 240, 460, 392, 0, 0, -208, -220 +}; + #define QT_IMA_ADPCM_PREAMBLE_SIZE 2 #define QT_IMA_ADPCM_BLOCK_SIZE 0x22 #define QT_IMA_ADPCM_SAMPLES_PER_BLOCK \ @@ -134,6 +145,12 @@ typedef struct adpcm_decoder_s { unsigned int in_block_size; unsigned int out_block_size; /* size in samples (2 bytes/sample) */ + int xa_mode; /* 1 for mode A, 0 for mode B or mode C */ + int xa_p_l; /* previous sample, left/mono channel */ + int xa_p_r; /* previous sample, right channel */ + int xa_pp_l; /* 2nd-previous sample, left/mono channel */ + int xa_pp_r; /* 2nd-previous sample, right channel */ + } adpcm_decoder_t; /* @@ -1147,6 +1164,202 @@ static void dialogic_ima_decode_block(adpcm_decoder_t *this, buf_element_t *buf) this->size = 0; } + +static void xa_adpcm_decode_block(adpcm_decoder_t *this, buf_element_t *buf) { + int32_t p_l, pp_l, coeff_p_l, coeff_pp_l, range_l; + int32_t p_r, pp_r, coeff_p_r, coeff_pp_r, range_r; + int32_t snd_group, snd_unit, snd_data, samp, i, j; + uint8_t *inp; + + /* restore decoding history */ + p_l = this->xa_p_l; pp_l = this->xa_pp_l; + p_r = this->xa_p_r; pp_r = this->xa_pp_r; + + inp = &this->buf[0]; + j = 0; + + if (this->xa_mode) { + if (this->channels == 2) { + /* mode A (8 bits per sample / 4 sound units) stereo + * - sound units 0,2 are left channel, 1,3 are right channel + * - sound data (8 bits) is shifted left to 16-bit border, then + * shifted right by the range parameter, therefore it's shifted + * (8-range) bits left. + * - two coefficients tables (4 entries each) are merged into one + * - coefficients are multiples of 1/256, so '>> 8' is applied + * after multiplication to get correct answer. + */ + for (snd_group = 0; snd_group < 18; snd_group++, inp += 128) { + for (snd_unit = 0; snd_unit < 4; snd_unit += 2) { + /* get left channel coeffs and range */ + coeff_p_l = xa_adpcm_table[((inp[snd_unit] >> 4) & 0x3)]; + coeff_pp_l = xa_adpcm_table[((inp[snd_unit] >> 4) & 0x3) + 4]; + range_l = 8 - (inp[snd_unit] & 0xF); + + /* get right channel coeffs and range */ + coeff_p_r = xa_adpcm_table[((inp[snd_unit+1] >> 4) & 0x3)]; + coeff_pp_r = xa_adpcm_table[((inp[snd_unit+1] >> 4) & 0x3) + 4]; + range_r = 8 - (inp[snd_unit+1] & 0xF); + + for (snd_data = 0; snd_data < 28; snd_data++) { + /* left channel */ + samp = ((signed char *)inp)[16 + (snd_data << 2) + snd_unit]; + samp <<= range_l; + samp += (coeff_p_l * p_l + coeff_pp_l * pp_l) >> 8; + CLAMP_S16(samp); + pp_l = p_l; + p_l = samp; + this->decode_buffer[j++] = (unsigned short) samp; + + /* right channel */ + samp = ((signed char *)inp)[16 + (snd_data << 2) + snd_unit+1]; + samp <<= range_r; + samp += (coeff_p_r * p_r + coeff_pp_r * pp_r) >> 8; + CLAMP_S16(samp); + pp_r = p_r; + p_r = samp; + this->decode_buffer[j++] = (unsigned short) samp; + } + } + } + } + else { + /* mode A (8 bits per sample / 4 sound units) mono + * - other details as before + */ + for (snd_group = 0; snd_group < 18; snd_group++, inp += 128) { + for (snd_unit = 0; snd_unit < 4; snd_unit++) { + /* get coeffs and range */ + coeff_p_l = xa_adpcm_table[((inp[snd_unit] >> 4) & 0x3)]; + coeff_pp_l = xa_adpcm_table[((inp[snd_unit] >> 4) & 0x3) + 4]; + range_l = 8 - (inp[snd_unit] & 0xF); + + for (snd_data = 0; snd_data < 28; snd_data++) { + samp = ((signed char *)inp)[16 + (snd_data << 2) + snd_unit]; + samp <<= range_l; + samp += (coeff_p_l * p_l + coeff_pp_l * pp_l) >> 8; + CLAMP_S16(samp); + pp_l = p_l; p_l = samp; + this->decode_buffer[j++] = (unsigned short) samp; + } + } + } + } + } + else { + if (this->channels == 2) { + /* mode B/C (4 bits per sample / 8 sound units) stereo + * - sound units 0,2,4,6 are left channel, 1,3,5,7 are right channel + * - sound parameters 0-7 are stored as 16 bytes in the order + * "0123012345674567", so inp[x+4] gives sound parameter x while + * inp[x] doesn't. + * - sound data (4 bits) is shifted left to 16-bit border, then + * shifted right by the range parameter, therefore it's shifted + * (12-range) bits left. + * - other details as before + */ + for (snd_group = 0; snd_group < 18; snd_group++, inp += 128) { + for (snd_unit = 0; snd_unit < 8; snd_unit += 2) { + /* get left channel coeffs and range */ + coeff_p_l = xa_adpcm_table[((inp[snd_unit+4] >> 4) & 0x3)]; + coeff_pp_l = xa_adpcm_table[((inp[snd_unit+4] >> 4) & 0x3) + 4]; + range_l = 12 - (inp[snd_unit+4] & 0xF); + + /* get right channel coeffs and range */ + coeff_p_r = xa_adpcm_table[((inp[snd_unit+5] >> 4) & 0x3)]; + coeff_pp_r = xa_adpcm_table[((inp[snd_unit+5] >> 4) & 0x3) + 4]; + range_r = 12 - (inp[snd_unit+5] & 0xF); + + for (snd_data = 0; snd_data < 28; snd_data++) { + /* left channel */ + samp = (inp[16 + (snd_data << 2) + (snd_unit >> 1)]) & 0xF; + SE_4BIT(samp); + samp <<= range_l; + samp += (coeff_p_l * p_l + coeff_pp_l * pp_l) >> 8; + CLAMP_S16(samp); + pp_l = p_l; + p_l = samp; + this->decode_buffer[j++] = (unsigned short) samp; + + /* right channel */ + samp = (inp[16 + (snd_data << 2) + (snd_unit >> 1)] >> 4) & 0xF; + SE_4BIT(samp); + samp <<= range_r; + samp += (coeff_p_r * p_r + coeff_pp_r * pp_r) >> 8; + CLAMP_S16(samp); + pp_r = p_r; + p_r = samp; + this->decode_buffer[j++] = (unsigned short) samp; + } + } + } + } + else { + /* mode B or C (4 bits per sample / 8 sound units) mono + * - other details as before + */ + for (snd_group = 0; snd_group < 18; snd_group++, inp += 128) { + for (snd_unit = 0; snd_unit < 8; snd_unit++) { + /* get coeffs and range */ + coeff_p_l = xa_adpcm_table[((inp[snd_unit+4] >> 4) & 0x3)]; + coeff_pp_l = xa_adpcm_table[((inp[snd_unit+4] >> 4) & 0x3) + 4]; + range_l = 12 - (inp[snd_unit+4] & 0xF); + + for (snd_data = 0; snd_data < 28; snd_data++) { + samp = inp[16 + (snd_data << 2) + (snd_unit >> 1)]; + if (snd_unit & 1) samp >>= 4; samp &= 0xF; + SE_4BIT(samp); + samp <<= range_l; + samp += (coeff_p_l * p_l + coeff_pp_l * pp_l) >> 8; + CLAMP_S16(samp); + pp_l = p_l; + p_l = samp; + this->decode_buffer[j++] = (unsigned short) samp; + } + } + } + } + } + + /* store decoding history */ + this->xa_p_l = p_l; this->xa_pp_l = pp_l; + this->xa_p_r = p_r; this->xa_pp_r = pp_r; + + /* despatch the decoded audio */ + i = 0; + while (i < j) { + audio_buffer_t *audio_buffer; + int bytes_to_send; + + audio_buffer= this->stream->audio_out->get_buffer(this->stream->audio_out); + if (audio_buffer->mem_size == 0) { + printf ("adpcm: Help! Allocated audio buffer with nothing in it!\n"); + return; + } + + if (((j - i) * 2) > audio_buffer->mem_size) { + bytes_to_send = audio_buffer->mem_size; + } + else { + bytes_to_send = (j - i) * 2; + } + + xine_fast_memcpy(audio_buffer->mem, &this->decode_buffer[i], + bytes_to_send); + + audio_buffer->num_frames = bytes_to_send / (2 * this->channels); + audio_buffer->vpts = buf->pts; + buf->pts = 0; + this->stream->audio_out->put_buffer(this->stream->audio_out, + audio_buffer, this->stream); + + i += bytes_to_send / 2; + } + + /* reset input buffer */ + this->size = 0; +} + static void adpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { adpcm_decoder_t *this = (adpcm_decoder_t *) this_gen; @@ -1163,7 +1376,7 @@ static void adpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { this->size = 0; /* load the stream information */ - switch (buf->type) { + switch (buf->type & 0xFFFF0000) { case BUF_AUDIO_MSADPCM: this->stream->meta_info[XINE_META_INFO_AUDIOCODEC] = @@ -1210,6 +1423,11 @@ static void adpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { strdup("Dialogic IMA ADPCM"); break; + case BUF_AUDIO_XA_ADPCM: + this->stream->meta_info[XINE_META_INFO_AUDIOCODEC] = + strdup("CD-ROM/XA ADPCM"); + break; + } /* if the data was transported in an MS-type file (packet size will be @@ -1274,6 +1492,20 @@ static void adpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { this->decode_buffer = xine_xmalloc(this->out_block_size * 2); } + /* XA blocks are always 2304 bytes of input data. For output, there + * are 18 sound groups. These sound groups have 4 sound units (mode A) + * or 8 sound units (mode B or mode C). The sound units have 28 sound + * data samples. So, either 18*4*28=2016 or 18*8*28=4032 samples per + * sector. 2 bytes per sample means 4032 or 8064 bytes per sector. + */ + if ((buf->type & 0xFFFF0000) == BUF_AUDIO_XA_ADPCM) { + /* initialise decoder state */ + this->xa_mode = buf->decoder_info[2]; + this->xa_p_l = this->xa_pp_l = this->xa_p_r = this->xa_pp_r = 0; + /* allocate 2 bytes per sample */ + this->decode_buffer = xine_xmalloc((this->xa_mode) ? 4032 : 8064); + } + return; } @@ -1302,7 +1534,7 @@ static void adpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { /* time to decode a frame */ if (buf->decoder_flags & BUF_FLAG_FRAME_END) { - switch(buf->type) { + switch(buf->type & 0xFFFF0000) { case BUF_AUDIO_MSADPCM: ms_adpcm_decode_block(this, buf); @@ -1339,6 +1571,10 @@ static void adpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { case BUF_AUDIO_DIALOGIC_IMA: dialogic_ima_decode_block(this, buf); break; + + case BUF_AUDIO_XA_ADPCM: + xa_adpcm_decode_block(this, buf); + break; } } } @@ -1428,7 +1664,7 @@ static uint32_t audio_types[] = { BUF_AUDIO_QTIMAADPCM, BUF_AUDIO_DK3ADPCM, BUF_AUDIO_DK4ADPCM, BUF_AUDIO_SMJPEG_IMA, BUF_AUDIO_VQA_IMA, BUF_AUDIO_EA_ADPCM, - BUF_AUDIO_DIALOGIC_IMA, + BUF_AUDIO_DIALOGIC_IMA, BUF_AUDIO_XA_ADPCM, 0 }; -- cgit v1.2.3