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