2 * Sony Playstation (PSX) STR File Demuxer
3 * Copyright (c) 2003 The ffmpeg Project
5 * This file is part of FFmpeg.
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.
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.
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
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.
36 #define RIFF_TAG MKTAG('R', 'I', 'F', 'F')
37 #define CDXA_TAG MKTAG('C', 'D', 'X', 'A')
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
45 #define CDXA_TYPE_MASK 0x0E
46 #define CDXA_TYPE_DATA 0x08
47 #define CDXA_TYPE_AUDIO 0x04
48 #define CDXA_TYPE_VIDEO 0x02
50 #define STR_MAGIC (0x80010160)
52 typedef struct StrChannel
{
58 /* video parameters */
61 int video_stream_index
;
63 /* audio parameters */
67 int audio_stream_index
;
70 typedef struct StrDemuxContext
{
72 /* a STR file can contain up to 32 channels of data */
73 StrChannel channels
[32];
75 /* only decode the first audio and video channels encountered */
81 unsigned char *video_chunk
;
85 static const char sync_header
[12] = {0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00};
87 static int str_probe(AVProbeData
*p
)
91 /* need at least 0x38 bytes to validate */
92 if (p
->buf_size
< 0x38)
95 if ((AV_RL32(&p
->buf
[0]) == RIFF_TAG
) &&
96 (AV_RL32(&p
->buf
[8]) == CDXA_TAG
)) {
98 /* RIFF header seen; skip 0x2C bytes */
99 start
= RIFF_HEADER_SIZE
;
103 /* look for CD sync header (00, 0xFF x 10, 00) */
104 if (memcmp(p
->buf
+start
,sync_header
,sizeof(sync_header
)))
107 /* MPEG files (like those ripped from VCDs) can also look like this;
108 * only return half certainty */
113 static void dump(unsigned char *buf
,size_t len
)
117 if ((i
&15)==0) av_log(NULL
, AV_LOG_DEBUG
, "%04x ",i
);
118 av_log(NULL
, AV_LOG_DEBUG
, "%02x ",buf
[i
]);
119 if ((i
&15)==15) av_log(NULL
, AV_LOG_DEBUG
, "\n");
121 av_log(NULL
, AV_LOG_DEBUG
, "\n");
125 static int str_read_header(AVFormatContext
*s
,
126 AVFormatParameters
*ap
)
128 ByteIOContext
*pb
= s
->pb
;
129 StrDemuxContext
*str
= s
->priv_data
;
131 unsigned char sector
[RAW_CD_SECTOR_SIZE
];
136 /* initialize context members */
138 str
->audio_channel
= -1; /* assume to audio or video */
139 str
->video_channel
= -1;
140 str
->video_chunk
= NULL
;
143 /* skip over any RIFF header */
144 if (get_buffer(pb
, sector
, RIFF_HEADER_SIZE
) != RIFF_HEADER_SIZE
)
146 if (AV_RL32(§or
[0]) == RIFF_TAG
)
147 start
= RIFF_HEADER_SIZE
;
151 url_fseek(pb
, start
, SEEK_SET
);
153 /* check through the first 32 sectors for individual channels */
154 for (i
= 0; i
< 32; i
++) {
155 if (get_buffer(pb
, sector
, RAW_CD_SECTOR_SIZE
) != RAW_CD_SECTOR_SIZE
)
158 //printf("%02x %02x %02x %02x\n",sector[0x10],sector[0x11],sector[0x12],sector[0x13]);
160 channel
= sector
[0x11];
162 return AVERROR_INVALIDDATA
;
164 switch (sector
[0x12] & CDXA_TYPE_MASK
) {
167 case CDXA_TYPE_VIDEO
:
168 /* check if this channel gets to be the dominant video channel */
169 if (str
->video_channel
== -1) {
170 /* qualify the magic number */
171 if (AV_RL32(§or
[0x18]) != STR_MAGIC
)
173 str
->video_channel
= channel
;
174 str
->channels
[channel
].type
= STR_VIDEO
;
175 str
->channels
[channel
].width
= AV_RL16(§or
[0x28]);
176 str
->channels
[channel
].height
= AV_RL16(§or
[0x2A]);
178 /* allocate a new AVStream */
179 st
= av_new_stream(s
, 0);
181 return AVERROR(ENOMEM
);
182 av_set_pts_info(st
, 64, 1, 15);
184 str
->channels
[channel
].video_stream_index
= st
->index
;
186 st
->codec
->codec_type
= CODEC_TYPE_VIDEO
;
187 st
->codec
->codec_id
= CODEC_ID_MDEC
;
188 st
->codec
->codec_tag
= 0; /* no fourcc */
189 st
->codec
->width
= str
->channels
[channel
].width
;
190 st
->codec
->height
= str
->channels
[channel
].height
;
194 case CDXA_TYPE_AUDIO
:
195 /* check if this channel gets to be the dominant audio channel */
196 if (str
->audio_channel
== -1) {
198 str
->audio_channel
= channel
;
199 str
->channels
[channel
].type
= STR_AUDIO
;
200 str
->channels
[channel
].channels
=
201 (sector
[0x13] & 0x01) ? 2 : 1;
202 str
->channels
[channel
].sample_rate
=
203 (sector
[0x13] & 0x04) ? 18900 : 37800;
204 str
->channels
[channel
].bits
=
205 (sector
[0x13] & 0x10) ? 8 : 4;
207 /* allocate a new AVStream */
208 st
= av_new_stream(s
, 0);
210 return AVERROR(ENOMEM
);
211 av_set_pts_info(st
, 64, 128, str
->channels
[channel
].sample_rate
);
213 str
->channels
[channel
].audio_stream_index
= st
->index
;
216 st
->codec
->codec_type
= CODEC_TYPE_AUDIO
;
217 st
->codec
->codec_id
= CODEC_ID_ADPCM_XA
;
218 st
->codec
->codec_tag
= 0; /* no fourcc */
219 st
->codec
->channels
= (fmt
&1)?2:1;
220 st
->codec
->sample_rate
= (fmt
&4)?18900:37800;
221 // st->codec->bit_rate = 0; //FIXME;
222 st
->codec
->block_align
= 128;
232 if (str
->video_channel
!= -1)
233 av_log (s
, AV_LOG_DEBUG
, " video channel = %d, %d x %d %d\n", str
->video_channel
,
234 str
->channels
[str
->video_channel
].width
,
235 str
->channels
[str
->video_channel
].height
,str
->channels
[str
->video_channel
].video_stream_index
);
236 if (str
->audio_channel
!= -1)
237 av_log (s
, AV_LOG_DEBUG
, " audio channel = %d, %d Hz, %d channels, %d bits/sample %d\n",
239 str
->channels
[str
->audio_channel
].sample_rate
,
240 str
->channels
[str
->audio_channel
].channels
,
241 str
->channels
[str
->audio_channel
].bits
,str
->channels
[str
->audio_channel
].audio_stream_index
);
243 /* back to the start */
244 url_fseek(pb
, start
, SEEK_SET
);
249 static int str_read_packet(AVFormatContext
*s
,
252 ByteIOContext
*pb
= s
->pb
;
253 StrDemuxContext
*str
= s
->priv_data
;
254 unsigned char sector
[RAW_CD_SECTOR_SIZE
];
260 if (get_buffer(pb
, sector
, RAW_CD_SECTOR_SIZE
) != RAW_CD_SECTOR_SIZE
)
263 channel
= sector
[0x11];
265 return AVERROR_INVALIDDATA
;
267 switch (sector
[0x12] & CDXA_TYPE_MASK
) {
270 case CDXA_TYPE_VIDEO
:
271 /* check if this the video channel we care about */
272 if (channel
== str
->video_channel
) {
274 int current_sector
= AV_RL16(§or
[0x1C]);
275 int sector_count
= AV_RL16(§or
[0x1E]);
276 int frame_size
= AV_RL32(§or
[0x24]);
278 // printf("%d %d %d\n",current_sector,sector_count,frame_size);
279 /* if this is the first sector of the frame, allocate a pkt */
281 if (current_sector
== 0) {
282 if (av_new_packet(pkt
, frame_size
))
285 pkt
->pos
= url_ftell(pb
) - RAW_CD_SECTOR_SIZE
;
287 str
->channels
[channel
].video_stream_index
;
288 // pkt->pts = str->pts;
290 /* if there is no audio, adjust the pts after every video
291 * frame; assume 15 fps */
292 if (str
->audio_channel
!= -1)
293 str
->pts
+= (90000 / 15);
296 /* load all the constituent chunks in the video packet */
297 bytes_to_copy
= frame_size
- current_sector
*VIDEO_DATA_CHUNK_SIZE
;
298 if (bytes_to_copy
>0) {
299 if (bytes_to_copy
>VIDEO_DATA_CHUNK_SIZE
) bytes_to_copy
=VIDEO_DATA_CHUNK_SIZE
;
300 memcpy(pkt
->data
+ current_sector
*VIDEO_DATA_CHUNK_SIZE
,
301 sector
+ VIDEO_DATA_HEADER_SIZE
, bytes_to_copy
);
303 if (current_sector
== sector_count
-1) {
311 case CDXA_TYPE_AUDIO
:
313 printf (" dropping audio sector\n");
316 /* check if this the video channel we care about */
317 if (channel
== str
->audio_channel
) {
319 if (av_new_packet(pkt
, 2304))
321 memcpy(pkt
->data
,sector
+24,2304);
324 str
->channels
[channel
].audio_stream_index
;
325 //pkt->pts = str->pts;
331 /* drop the sector and move on */
333 printf (" dropping other sector\n");
343 static int str_read_close(AVFormatContext
*s
)
345 StrDemuxContext
*str
= s
->priv_data
;
347 av_free(str
->video_chunk
);
352 AVInputFormat str_demuxer
= {
354 NULL_IF_CONFIG_SMALL("Sony Playstation STR format"),
355 sizeof(StrDemuxContext
),