1/* 2 * Sony Playstation (PSX) STR File Demuxer 3 * Copyright (c) 2003 The ffmpeg Project 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg 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 * FFmpeg 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 FFmpeg; 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 libavformat/psxstr.c 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 35#define RIFF_TAG MKTAG('R', 'I', 'F', 'F') 36#define CDXA_TAG MKTAG('C', 'D', 'X', 'A') 37 38#define RAW_CD_SECTOR_SIZE 2352 39#define RAW_CD_SECTOR_DATA_SIZE 2304 40#define VIDEO_DATA_CHUNK_SIZE 0x7E0 41#define VIDEO_DATA_HEADER_SIZE 0x38 42#define RIFF_HEADER_SIZE 0x2C 43 44#define CDXA_TYPE_MASK 0x0E 45#define CDXA_TYPE_DATA 0x08 46#define CDXA_TYPE_AUDIO 0x04 47#define CDXA_TYPE_VIDEO 0x02 48 49#define STR_MAGIC (0x80010160) 50 51typedef struct StrChannel { 52 /* video parameters */ 53 int video_stream_index; 54 AVPacket tmp_pkt; 55 56 /* audio parameters */ 57 int audio_stream_index; 58} StrChannel; 59 60typedef struct StrDemuxContext { 61 62 /* a STR file can contain up to 32 channels of data */ 63 StrChannel channels[32]; 64} StrDemuxContext; 65 66static const char sync_header[12] = {0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00}; 67 68static int str_probe(AVProbeData *p) 69{ 70 uint8_t *sector= p->buf; 71 72 if (p->buf_size < RAW_CD_SECTOR_SIZE) 73 return 0; 74 75 if ((AV_RL32(&p->buf[0]) == RIFF_TAG) && 76 (AV_RL32(&p->buf[8]) == CDXA_TAG)) { 77 78 /* RIFF header seen; skip 0x2C bytes */ 79 sector += RIFF_HEADER_SIZE; 80 } 81 82 /* look for CD sync header (00, 0xFF x 10, 00) */ 83 if (memcmp(sector,sync_header,sizeof(sync_header))) 84 return 0; 85 86 if(sector[0x11] >= 32) 87 return 0; 88 if( (sector[0x12] & CDXA_TYPE_MASK) != CDXA_TYPE_VIDEO 89 && (sector[0x12] & CDXA_TYPE_MASK) != CDXA_TYPE_AUDIO 90 && (sector[0x12] & CDXA_TYPE_MASK) != CDXA_TYPE_DATA) 91 return 0; 92 93 /* MPEG files (like those ripped from VCDs) can also look like this; 94 * only return half certainty */ 95 return 50; 96} 97 98static int str_read_header(AVFormatContext *s, 99 AVFormatParameters *ap) 100{ 101 ByteIOContext *pb = s->pb; 102 StrDemuxContext *str = s->priv_data; 103 unsigned char sector[RAW_CD_SECTOR_SIZE]; 104 int start; 105 int i; 106 107 /* skip over any RIFF header */ 108 if (get_buffer(pb, sector, RIFF_HEADER_SIZE) != RIFF_HEADER_SIZE) 109 return AVERROR(EIO); 110 if (AV_RL32(§or[0]) == RIFF_TAG) 111 start = RIFF_HEADER_SIZE; 112 else 113 start = 0; 114 115 url_fseek(pb, start, SEEK_SET); 116 117 for(i=0; i<32; i++){ 118 str->channels[i].video_stream_index= 119 str->channels[i].audio_stream_index= -1; 120 } 121 122 s->ctx_flags |= AVFMTCTX_NOHEADER; 123 124 return 0; 125} 126 127static int str_read_packet(AVFormatContext *s, 128 AVPacket *ret_pkt) 129{ 130 ByteIOContext *pb = s->pb; 131 StrDemuxContext *str = s->priv_data; 132 unsigned char sector[RAW_CD_SECTOR_SIZE]; 133 int channel; 134 AVPacket *pkt; 135 AVStream *st; 136 137 while (1) { 138 139 if (get_buffer(pb, sector, RAW_CD_SECTOR_SIZE) != RAW_CD_SECTOR_SIZE) 140 return AVERROR(EIO); 141 142 channel = sector[0x11]; 143 if (channel >= 32) 144 return AVERROR_INVALIDDATA; 145 146 switch (sector[0x12] & CDXA_TYPE_MASK) { 147 148 case CDXA_TYPE_DATA: 149 case CDXA_TYPE_VIDEO: 150 { 151 152 int current_sector = AV_RL16(§or[0x1C]); 153 int sector_count = AV_RL16(§or[0x1E]); 154 int frame_size = AV_RL32(§or[0x24]); 155 156 if(!( frame_size>=0 157 && current_sector < sector_count 158 && sector_count*VIDEO_DATA_CHUNK_SIZE >=frame_size)){ 159 av_log(s, AV_LOG_ERROR, "Invalid parameters %d %d %d\n", current_sector, sector_count, frame_size); 160 break; 161 } 162 163 if(str->channels[channel].video_stream_index < 0){ 164 /* allocate a new AVStream */ 165 st = av_new_stream(s, 0); 166 if (!st) 167 return AVERROR(ENOMEM); 168 av_set_pts_info(st, 64, 1, 15); 169 170 str->channels[channel].video_stream_index = st->index; 171 172 st->codec->codec_type = CODEC_TYPE_VIDEO; 173 st->codec->codec_id = CODEC_ID_MDEC; 174 st->codec->codec_tag = 0; /* no fourcc */ 175 st->codec->width = AV_RL16(§or[0x28]); 176 st->codec->height = AV_RL16(§or[0x2A]); 177 } 178 179 /* if this is the first sector of the frame, allocate a pkt */ 180 pkt = &str->channels[channel].tmp_pkt; 181 182 if(pkt->size != sector_count*VIDEO_DATA_CHUNK_SIZE){ 183 if(pkt->data) 184 av_log(s, AV_LOG_ERROR, "missmatching sector_count\n"); 185 av_free_packet(pkt); 186 if (av_new_packet(pkt, sector_count*VIDEO_DATA_CHUNK_SIZE)) 187 return AVERROR(EIO); 188 189 pkt->pos= url_ftell(pb) - RAW_CD_SECTOR_SIZE; 190 pkt->stream_index = 191 str->channels[channel].video_stream_index; 192 } 193 194 memcpy(pkt->data + current_sector*VIDEO_DATA_CHUNK_SIZE, 195 sector + VIDEO_DATA_HEADER_SIZE, 196 VIDEO_DATA_CHUNK_SIZE); 197 198 if (current_sector == sector_count-1) { 199 pkt->size= frame_size; 200 *ret_pkt = *pkt; 201 pkt->data= NULL; 202 pkt->size= -1; 203 return 0; 204 } 205 206 } 207 break; 208 209 case CDXA_TYPE_AUDIO: 210 if(str->channels[channel].audio_stream_index < 0){ 211 int fmt = sector[0x13]; 212 /* allocate a new AVStream */ 213 st = av_new_stream(s, 0); 214 if (!st) 215 return AVERROR(ENOMEM); 216 217 str->channels[channel].audio_stream_index = st->index; 218 219 st->codec->codec_type = CODEC_TYPE_AUDIO; 220 st->codec->codec_id = CODEC_ID_ADPCM_XA; 221 st->codec->codec_tag = 0; /* no fourcc */ 222 st->codec->channels = (fmt&1)?2:1; 223 st->codec->sample_rate = (fmt&4)?18900:37800; 224 // st->codec->bit_rate = 0; //FIXME; 225 st->codec->block_align = 128; 226 227 av_set_pts_info(st, 64, 128, st->codec->sample_rate); 228 } 229 pkt = ret_pkt; 230 if (av_new_packet(pkt, 2304)) 231 return AVERROR(EIO); 232 memcpy(pkt->data,sector+24,2304); 233 234 pkt->stream_index = 235 str->channels[channel].audio_stream_index; 236 return 0; 237 break; 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 (url_feof(pb)) 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 str_demuxer = { 262 "psxstr", 263 NULL_IF_CONFIG_SMALL("Sony Playstation STR format"), 264 sizeof(StrDemuxContext), 265 str_probe, 266 str_read_header, 267 str_read_packet, 268 str_read_close, 269}; 270