1/* 2 * Sony Playstation (PSX) STR File Demuxer 3 * Copyright (c) 2003 The ffmpeg Project 4 * 5 * This file is part of Libav. 6 * 7 * Libav is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * Libav is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with Libav; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/** 23 * @file 24 * PSX STR file demuxer 25 * by Mike Melanson (melanson@pcisys.net) 26 * This module handles streams that have been ripped from Sony Playstation 27 * CD games. This demuxer can handle either raw STR files (which are just 28 * concatenations of raw compact disc sectors) or STR files with 0x2C-byte 29 * RIFF headers, followed by CD sectors. 30 */ 31 32#include "libavutil/intreadwrite.h" 33#include "avformat.h" 34#include "internal.h" 35 36#define RIFF_TAG MKTAG('R', 'I', 'F', 'F') 37#define CDXA_TAG MKTAG('C', 'D', 'X', 'A') 38 39#define RAW_CD_SECTOR_SIZE 2352 40#define RAW_CD_SECTOR_DATA_SIZE 2304 41#define VIDEO_DATA_CHUNK_SIZE 0x7E0 42#define VIDEO_DATA_HEADER_SIZE 0x38 43#define RIFF_HEADER_SIZE 0x2C 44 45#define CDXA_TYPE_MASK 0x0E 46#define CDXA_TYPE_DATA 0x08 47#define CDXA_TYPE_AUDIO 0x04 48#define CDXA_TYPE_VIDEO 0x02 49 50#define STR_MAGIC (0x80010160) 51 52typedef struct StrChannel { 53 /* video parameters */ 54 int video_stream_index; 55 AVPacket tmp_pkt; 56 57 /* audio parameters */ 58 int audio_stream_index; 59} StrChannel; 60 61typedef struct StrDemuxContext { 62 63 /* a STR file can contain up to 32 channels of data */ 64 StrChannel channels[32]; 65} StrDemuxContext; 66 67static const char sync_header[12] = {0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00}; 68 69static int str_probe(AVProbeData *p) 70{ 71 uint8_t *sector= p->buf; 72 73 if (p->buf_size < RAW_CD_SECTOR_SIZE) 74 return 0; 75 76 if ((AV_RL32(&p->buf[0]) == RIFF_TAG) && 77 (AV_RL32(&p->buf[8]) == CDXA_TAG)) { 78 79 /* RIFF header seen; skip 0x2C bytes */ 80 sector += RIFF_HEADER_SIZE; 81 } 82 83 /* look for CD sync header (00, 0xFF x 10, 00) */ 84 if (memcmp(sector,sync_header,sizeof(sync_header))) 85 return 0; 86 87 if(sector[0x11] >= 32) 88 return 0; 89 if( (sector[0x12] & CDXA_TYPE_MASK) != CDXA_TYPE_VIDEO 90 && (sector[0x12] & CDXA_TYPE_MASK) != CDXA_TYPE_AUDIO 91 && (sector[0x12] & CDXA_TYPE_MASK) != CDXA_TYPE_DATA) 92 return 0; 93 94 /* MPEG files (like those ripped from VCDs) can also look like this; 95 * only return half certainty */ 96 return 50; 97} 98 99static int str_read_header(AVFormatContext *s, 100 AVFormatParameters *ap) 101{ 102 AVIOContext *pb = s->pb; 103 StrDemuxContext *str = s->priv_data; 104 unsigned char sector[RAW_CD_SECTOR_SIZE]; 105 int start; 106 int i; 107 108 /* skip over any RIFF header */ 109 if (avio_read(pb, sector, RIFF_HEADER_SIZE) != RIFF_HEADER_SIZE) 110 return AVERROR(EIO); 111 if (AV_RL32(§or[0]) == RIFF_TAG) 112 start = RIFF_HEADER_SIZE; 113 else 114 start = 0; 115 116 avio_seek(pb, start, SEEK_SET); 117 118 for(i=0; i<32; i++){ 119 str->channels[i].video_stream_index= 120 str->channels[i].audio_stream_index= -1; 121 } 122 123 s->ctx_flags |= AVFMTCTX_NOHEADER; 124 125 return 0; 126} 127 128static int str_read_packet(AVFormatContext *s, 129 AVPacket *ret_pkt) 130{ 131 AVIOContext *pb = s->pb; 132 StrDemuxContext *str = s->priv_data; 133 unsigned char sector[RAW_CD_SECTOR_SIZE]; 134 int channel; 135 AVPacket *pkt; 136 AVStream *st; 137 138 while (1) { 139 140 if (avio_read(pb, sector, RAW_CD_SECTOR_SIZE) != RAW_CD_SECTOR_SIZE) 141 return AVERROR(EIO); 142 143 channel = sector[0x11]; 144 if (channel >= 32) 145 return AVERROR_INVALIDDATA; 146 147 switch (sector[0x12] & CDXA_TYPE_MASK) { 148 149 case CDXA_TYPE_DATA: 150 case CDXA_TYPE_VIDEO: 151 { 152 153 int current_sector = AV_RL16(§or[0x1C]); 154 int sector_count = AV_RL16(§or[0x1E]); 155 int frame_size = AV_RL32(§or[0x24]); 156 157 if(!( frame_size>=0 158 && current_sector < sector_count 159 && sector_count*VIDEO_DATA_CHUNK_SIZE >=frame_size)){ 160 av_log(s, AV_LOG_ERROR, "Invalid parameters %d %d %d\n", current_sector, sector_count, frame_size); 161 break; 162 } 163 164 if(str->channels[channel].video_stream_index < 0){ 165 /* allocate a new AVStream */ 166 st = avformat_new_stream(s, NULL); 167 if (!st) 168 return AVERROR(ENOMEM); 169 avpriv_set_pts_info(st, 64, 1, 15); 170 171 str->channels[channel].video_stream_index = st->index; 172 173 st->codec->codec_type = AVMEDIA_TYPE_VIDEO; 174 st->codec->codec_id = CODEC_ID_MDEC; 175 st->codec->codec_tag = 0; /* no fourcc */ 176 st->codec->width = AV_RL16(§or[0x28]); 177 st->codec->height = AV_RL16(§or[0x2A]); 178 } 179 180 /* if this is the first sector of the frame, allocate a pkt */ 181 pkt = &str->channels[channel].tmp_pkt; 182 183 if(pkt->size != sector_count*VIDEO_DATA_CHUNK_SIZE){ 184 if(pkt->data) 185 av_log(s, AV_LOG_ERROR, "missmatching sector_count\n"); 186 av_free_packet(pkt); 187 if (av_new_packet(pkt, sector_count*VIDEO_DATA_CHUNK_SIZE)) 188 return AVERROR(EIO); 189 190 pkt->pos= avio_tell(pb) - RAW_CD_SECTOR_SIZE; 191 pkt->stream_index = 192 str->channels[channel].video_stream_index; 193 } 194 195 memcpy(pkt->data + current_sector*VIDEO_DATA_CHUNK_SIZE, 196 sector + VIDEO_DATA_HEADER_SIZE, 197 VIDEO_DATA_CHUNK_SIZE); 198 199 if (current_sector == sector_count-1) { 200 pkt->size= frame_size; 201 *ret_pkt = *pkt; 202 pkt->data= NULL; 203 pkt->size= -1; 204 return 0; 205 } 206 207 } 208 break; 209 210 case CDXA_TYPE_AUDIO: 211 if(str->channels[channel].audio_stream_index < 0){ 212 int fmt = sector[0x13]; 213 /* allocate a new AVStream */ 214 st = avformat_new_stream(s, NULL); 215 if (!st) 216 return AVERROR(ENOMEM); 217 218 str->channels[channel].audio_stream_index = st->index; 219 220 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; 221 st->codec->codec_id = CODEC_ID_ADPCM_XA; 222 st->codec->codec_tag = 0; /* no fourcc */ 223 st->codec->channels = (fmt&1)?2:1; 224 st->codec->sample_rate = (fmt&4)?18900:37800; 225 // st->codec->bit_rate = 0; //FIXME; 226 st->codec->block_align = 128; 227 228 avpriv_set_pts_info(st, 64, 128, st->codec->sample_rate); 229 } 230 pkt = ret_pkt; 231 if (av_new_packet(pkt, 2304)) 232 return AVERROR(EIO); 233 memcpy(pkt->data,sector+24,2304); 234 235 pkt->stream_index = 236 str->channels[channel].audio_stream_index; 237 return 0; 238 default: 239 av_log(s, AV_LOG_WARNING, "Unknown sector type %02X\n", sector[0x12]); 240 /* drop the sector and move on */ 241 break; 242 } 243 244 if (pb->eof_reached) 245 return AVERROR(EIO); 246 } 247} 248 249static int str_read_close(AVFormatContext *s) 250{ 251 StrDemuxContext *str = s->priv_data; 252 int i; 253 for(i=0; i<32; i++){ 254 if(str->channels[i].tmp_pkt.data) 255 av_free_packet(&str->channels[i].tmp_pkt); 256 } 257 258 return 0; 259} 260 261AVInputFormat ff_str_demuxer = { 262 .name = "psxstr", 263 .long_name = NULL_IF_CONFIG_SMALL("Sony Playstation STR format"), 264 .priv_data_size = sizeof(StrDemuxContext), 265 .read_probe = str_probe, 266 .read_header = str_read_header, 267 .read_packet = str_read_packet, 268 .read_close = str_read_close, 269}; 270