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(&sector[0x1C]);
99cabdff1aSopenharmony_ci                int sector_count   = AV_RL16(&sector[0x1E]);
100cabdff1aSopenharmony_ci                int frame_size = AV_RL32(&sector[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(&sector[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(&sector[0x1C]);
183cabdff1aSopenharmony_ci                int sector_count   = AV_RL16(&sector[0x1E]);
184cabdff1aSopenharmony_ci                int frame_size = AV_RL32(&sector[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(&sector[0x28]);
206cabdff1aSopenharmony_ci                    st->codecpar->height     = AV_RL16(&sector[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