/* 2004.02.01 first released source code for IOMP */ /* * Copyright (C) 2000-2003 the xine project * * This file is part of xine, a free video player. * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * 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.2 2003/11/25 04:25:45 georgedon 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 #include "config.h" #endif #include #include #include #include #include /********** logging **********/ #define LOG_MODULE "demux_str" /* #define LOG_VERBOSE */ /* #define LOG */ #include "xine_internal.h" #include "xineutils.h" #include "compat.h" #include "demux.h" #include "bswap.h" #include "group_games.h" /* 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 ) | \ ( (long)(unsigned char)(ch1) << 16 ) | \ ( (long)(unsigned char)(ch0) << 24 ) ) #define RIFF_TAG FOURCC_TAG('R', 'I', 'F', 'F') #define CDXA_TAG FOURCC_TAG('C', 'D', 'X', 'A') /* FIXME */ #define FRAME_DURATION 45000 typedef struct { demux_plugin_t demux_plugin; xine_stream_t *stream; fifo_buffer_t *video_fifo; fifo_buffer_t *audio_fifo; input_plugin_t *input; int status; off_t data_start; off_t data_size; off_t current_pos; 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]; int seek_flag; int default_video_channel; } demux_str_t; typedef struct { demux_class_t demux_class; } demux_str_class_t; /* 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; 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) { lprintf("read error\n"); return 0; } /* check for STR with a RIFF header */ if ((BE_32(&check_bytes[0]) == RIFF_TAG) && (BE_32(&check_bytes[8]) == CDXA_TAG)) local_offset = 0x2C; else local_offset = 0; this->data_start = (off_t) local_offset; /* we need to check up to 32 sectors for up to 32 audio/video channels */ for (sector = 0; sector < STR_MAX_CHANNELS; sector++) { lprintf("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]); /* 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)) { lprintf("sector %d sync error\n", sector); return 0; } /* 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])) { lprintf("sector %d control bits copy error\n", sector); return 0; } /* channel should be from 0 to 31 */ channel = check_bytes[local_offset + 0x11]; if (channel >= STR_MAX_CHANNELS) { lprintf("sector %d channel %d error\n", sector, channel); return 0; } /* switch on the sector type */ switch(check_bytes[local_offset + 0x12] & CDXA_TYPE_MASK) { 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: lprintf("sector %d channel %d unknown type error\n", sector, channel); /* 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) { lprintf("sector %d read error\n", sector); return 0; } } if(this->channel_type[0] == 0) 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"); } lprintf("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], 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) { this->status = DEMUX_FINISHED; return this->status; } 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 */ 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->pts = frame_number * FRAME_DURATION; 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 = 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[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; 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; /* send start buffers */ xine_demux_control_start(this->stream); /* 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; } } } } static int demux_str_seek (demux_plugin_t *this_gen, off_t start_pos, int start_time) { demux_str_t *this = (demux_str_t *) this_gen; xine_demux_flush_engine (this->stream); /* round to ensure we start on a sector */ start_pos /= CD_RAW_SECTOR_SIZE; lprintf("seeking to sector %d (%02d:%02d)\n", (int)start_pos, (int)start_pos / (60*75), ((int)start_pos / 75)%60); /* 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; } static void demux_str_dispose (demux_plugin_t *this) { free(this); } static int demux_str_get_status (demux_plugin_t *this_gen) { demux_str_t *this = (demux_str_t *) this_gen; return this->status; } 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)); } static uint32_t demux_str_get_capabilities(demux_plugin_t *this_gen) { return DEMUX_CAP_NOCAP; } static int demux_str_get_optional_data(demux_plugin_t *this_gen, void *data, int data_type) { return DEMUX_OPTIONAL_UNSUPPORTED; } static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *stream, input_plugin_t *input) { demux_str_t *this; if (!INPUT_IS_SEEKABLE(input)) { xprintf(stream->xine, XINE_VERBOSITY_DEBUG, _("input not seekable, can not handle!\n")); return NULL; } this = xine_xmalloc (sizeof (demux_str_t)); this->stream = stream; this->input = input; this->demux_plugin.send_headers = demux_str_send_headers; this->demux_plugin.send_chunk = demux_str_send_chunk; this->demux_plugin.seek = demux_str_seek; this->demux_plugin.dispose = demux_str_dispose; this->demux_plugin.get_status = demux_str_get_status; this->demux_plugin.get_stream_length = demux_str_get_stream_length; this->demux_plugin.get_video_frame = NULL; this->demux_plugin.got_video_frame_cb= NULL; this->demux_plugin.get_capabilities = demux_str_get_capabilities; this->demux_plugin.get_optional_data = demux_str_get_optional_data; this->demux_plugin.demux_class = class_gen; this->status = DEMUX_FINISHED; switch (stream->content_detection_method) { case METHOD_BY_EXTENSION: { char *extensions, *mrl; mrl = input->get_mrl (input); extensions = class_gen->get_extensions (class_gen); if (!xine_demux_check_extension (mrl, extensions)) { free (this); return NULL; } } /* falling through is intended */ case METHOD_BY_CONTENT: case METHOD_EXPLICIT: if (!open_str_file(this)) { free (this); return NULL; } break; default: free (this); return NULL; } return &this->demux_plugin; } static char *get_description (demux_class_t *this_gen) { return "Sony Playstation STR file demux plugin"; } static char *get_identifier (demux_class_t *this_gen) { return "PSX STR"; } 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 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); } void *demux_str_init_plugin (xine_t *xine, void *data) { demux_str_class_t *this; this = xine_xmalloc (sizeof (demux_str_class_t)); this->demux_class.open_plugin = open_plugin; this->demux_class.get_description = get_description; this->demux_class.get_identifier = get_identifier; this->demux_class.get_mimetypes = get_mimetypes; this->demux_class.get_extensions = get_extensions; this->demux_class.dispose = class_dispose; return this; }