Statistics
| Branch: | Revision:

ffmpeg / libavformat / psxstr.c @ 5aa0a644

History | View | Annotate | Download (10.8 KB)

1 3f16d933 Mike Melanson
/*
2
 * Sony Playstation (PSX) STR File Demuxer
3
 * Copyright (c) 2003 The ffmpeg Project
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 */
19
20
/**
21
 * @file psxstr.c
22
 * PSX STR file demuxer
23
 * by Mike Melanson (melanson@pcisys.net)
24
 * This module handles streams that have been ripped from Sony Playstation
25
 * CD games. This demuxer can handle either raw STR files (which are just
26
 * concatenations of raw compact disc sectors) or STR files with 0x2C-byte
27
 * RIFF headers, followed by CD sectors.
28
 */
29
30
#include "avformat.h"
31
32
//#define PRINTSTUFF
33
34
#define LE_16(x)  ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0])
35
#define LE_32(x)  ((((uint8_t*)(x))[3] << 24) | \
36
                   (((uint8_t*)(x))[2] << 16) | \
37
                   (((uint8_t*)(x))[1] << 8) | \
38
                    ((uint8_t*)(x))[0])
39
40
#define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \
41
        ( (long)(unsigned char)(ch0) | \
42
        ( (long)(unsigned char)(ch1) << 8 ) | \
43
        ( (long)(unsigned char)(ch2) << 16 ) | \
44
        ( (long)(unsigned char)(ch3) << 24 ) )
45
46
#define RIFF_TAG FOURCC_TAG('R', 'I', 'F', 'F')
47
#define CDXA_TAG FOURCC_TAG('C', 'D', 'X', 'A')
48
49
#define RAW_CD_SECTOR_SIZE 2352
50
#define RAW_CD_SECTOR_DATA_SIZE 2304
51
#define VIDEO_DATA_CHUNK_SIZE 0x7E0
52
#define VIDEO_DATA_HEADER_SIZE 0x38
53
#define RIFF_HEADER_SIZE 0x2C
54
55
#define CDXA_TYPE_MASK     0x0E
56
#define CDXA_TYPE_DATA     0x08
57
#define CDXA_TYPE_AUDIO    0x04
58
#define CDXA_TYPE_VIDEO    0x02
59
60
#define STR_MAGIC (0x80010160)
61
62
typedef struct StrChannel {
63
64
    int type;
65
#define STR_AUDIO 0
66
#define STR_VIDEO 1
67
68
    /* video parameters */
69
    int width;
70
    int height;
71
    int video_stream_index;
72
73
    /* audio parameters */
74
    int sample_rate;
75
    int channels;
76
    int bits;
77
    int audio_stream_index;
78
} StrChannel;
79
80
typedef struct StrDemuxContext {
81
82
    /* a STR file can contain up to 32 channels of data */
83
    StrChannel channels[32];
84
85
    /* only decode the first audio and video channels encountered */
86
    int video_channel;
87
    int audio_channel;
88
89
    int64_t pts;
90
91
    unsigned char *video_chunk;
92
} StrDemuxContext;
93
94
static int str_probe(AVProbeData *p)
95
{
96
    int start;
97
98
    /* need at least 0x38 bytes to validate */
99
    if (p->buf_size < 0x38)
100
        return 0;
101
102
    if ((LE_32(&p->buf[0]) == RIFF_TAG) &&
103
        (LE_32(&p->buf[8]) == CDXA_TAG)) {
104
105
        /* RIFF header seen; skip 0x2C bytes */
106
        start = RIFF_HEADER_SIZE;
107
    } else
108
        start = 0;
109
110
    /* look for CD sync header (00, 0xFF x 10, 00) */
111
    if ((p->buf[start + 0] != 0x00) || (p->buf[start + 1] != 0xFF) ||
112
        (p->buf[start + 2] != 0xFF) || (p->buf[start + 3] != 0xFF) ||
113
        (p->buf[start + 4] != 0xFF) || (p->buf[start + 5] != 0xFF) ||
114
        (p->buf[start + 6] != 0xFF) || (p->buf[start + 7] != 0xFF) ||
115
        (p->buf[start + 8] != 0xFF) || (p->buf[start + 9] != 0xFF) ||
116
        (p->buf[start + 10] != 0xFF) || (p->buf[start + 11] != 0x00))
117
        return 0;
118
119
    /* MPEG files (like those ripped from VCDs) can also look like this;
120
     * only return half certainty */
121
    return 50;
122
}
123
124
static int str_read_header(AVFormatContext *s,
125
                           AVFormatParameters *ap)
126
{
127
    ByteIOContext *pb = &s->pb;
128
    StrDemuxContext *str = (StrDemuxContext *)s->priv_data;
129
    AVStream *st;
130
    unsigned char sector[RAW_CD_SECTOR_SIZE];
131
    int start;
132
    int i;
133
    int channel;
134
135
    /* initialize context members */
136
    str->pts = 0;
137
    str->audio_channel = -1;  /* assume to audio or video */
138
    str->video_channel = -1;
139
    str->video_chunk = NULL;
140
141
    /* set the pts reference (1 pts = 1/90000) */
142
    s->pts_num = 1;
143
    s->pts_den = 90000;
144
145
    /* skip over any RIFF header */
146
    if (get_buffer(pb, sector, RIFF_HEADER_SIZE) != RIFF_HEADER_SIZE)
147
        return AVERROR_IO;
148
    if (LE_32(&sector[0]) == RIFF_TAG)
149
        start = RIFF_HEADER_SIZE;
150
    else
151
        start = 0;
152
153
    url_fseek(pb, start, SEEK_SET);
154
155
    /* check through the first 32 sectors for individual channels */
156
    for (i = 0; i < 32; i++) {
157
        if (get_buffer(pb, sector, RAW_CD_SECTOR_SIZE) != RAW_CD_SECTOR_SIZE)
158
            return AVERROR_IO;
159
160
        channel = sector[0x11];
161
        if (channel >= 32)
162
            return AVERROR_INVALIDDATA;
163
164
        switch (sector[0x12] & CDXA_TYPE_MASK) {
165
166
        case CDXA_TYPE_DATA:
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 (LE_32(&sector[0x18]) != STR_MAGIC)
172
                    break;
173
                str->video_channel = channel;
174
                str->channels[channel].type = STR_VIDEO;
175
                str->channels[channel].width = LE_16(&sector[0x28]);
176
                str->channels[channel].height = LE_16(&sector[0x2A]);
177
178
                /* allocate a new AVStream */
179
                st = av_new_stream(s, 0);
180
                if (!st)
181
                    return AVERROR_NOMEM;
182
183
                str->channels[channel].video_stream_index = st->index;
184
185
                st->codec.codec_type = CODEC_TYPE_VIDEO;
186
                st->codec.codec_id = CODEC_ID_MDEC; 
187
                st->codec.codec_tag = 0;  /* no fourcc */
188
                st->codec.width = str->channels[channel].width;
189
                st->codec.height = str->channels[channel].height;
190
            }
191
            break;
192
193
        case CDXA_TYPE_AUDIO:
194
            /* check if this channel gets to be the dominant audio channel */
195
            if (str->audio_channel == -1) {
196
                str->audio_channel = channel;
197
                str->channels[channel].type = STR_AUDIO;
198
                str->channels[channel].channels = 
199
                    (sector[0x13] & 0x01) ? 2 : 1;
200
                str->channels[channel].sample_rate = 
201
                    (sector[0x13] & 0x04) ? 18900 : 37800;
202
                str->channels[channel].bits = 
203
                    (sector[0x13] & 0x10) ? 8 : 4;
204
            }
205
            break;
206
207
        default:
208
            /* ignore */
209
            break;
210
        }
211
    }
212
213
if (str->video_channel != -1)
214
  printf (" video channel = %d, %d x %d\n", str->video_channel,
215
    str->channels[str->video_channel].width,
216
    str->channels[str->video_channel].height);
217
if (str->audio_channel != -1)
218
  printf (" audio channel = %d, %d Hz, %d channels, %d bits/sample\n", 
219
    str->video_channel,
220
    str->channels[str->video_channel].sample_rate,
221
    str->channels[str->video_channel].channels,
222
    str->channels[str->video_channel].bits);
223
224
    /* back to the start */
225
    url_fseek(pb, start, SEEK_SET);
226
227
    return 0;
228
}
229
230
static int str_read_packet(AVFormatContext *s,
231
                           AVPacket *pkt)
232
{
233
    ByteIOContext *pb = &s->pb;
234
    StrDemuxContext *str = (StrDemuxContext *)s->priv_data;
235
    unsigned char sector[RAW_CD_SECTOR_SIZE];
236
    int channel;
237
    int packet_read = 0;
238
    int video_sector_count = 0;
239
    int current_video_sector = 0;
240
    int video_frame_size = 0;
241
    int video_frame_index = 0;
242
    int bytes_to_copy;
243
    int ret = 0;
244
245
    while (!packet_read) {
246
247
        if (get_buffer(pb, sector, RAW_CD_SECTOR_SIZE) != RAW_CD_SECTOR_SIZE)
248
            return -EIO;
249
250
        channel = sector[0x11];
251
        if (channel >= 32)
252
            return AVERROR_INVALIDDATA;
253
254
        switch (sector[0x12] & CDXA_TYPE_MASK) {
255
256
        case CDXA_TYPE_DATA:
257
        case CDXA_TYPE_VIDEO:
258
            /* check if this the video channel we care about */
259
            if (channel == str->video_channel) {
260
261
                /* if this is the first sector of the frame, allocate a pkt */
262
                if (current_video_sector == 0) {
263
                    video_frame_size = LE_32(&sector[0x24]);
264
                    video_sector_count = LE_16(&sector[0x1E]);
265
                    if (av_new_packet(pkt, video_frame_size))
266
                        return -EIO;
267
268
                    pkt->stream_index = 
269
                        str->channels[channel].video_stream_index;
270
                    pkt->pts = str->pts;
271
272
                    /* if there is no audio, adjust the pts after every video
273
                     * frame; assume 15 fps */
274
                   if (str->audio_channel != -1)
275
                       str->pts += (90000 / 15);
276
                }
277
278
                /* load all the constituent chunks in the video packet */
279
                if (video_frame_size - video_frame_index < VIDEO_DATA_CHUNK_SIZE)
280
                    bytes_to_copy = video_frame_size - video_frame_index;
281
                else
282
                    bytes_to_copy = VIDEO_DATA_CHUNK_SIZE;
283
                if (video_frame_index < video_frame_size)
284
                    memcpy(&pkt->data[video_frame_index],
285
                        &sector[VIDEO_DATA_HEADER_SIZE], bytes_to_copy);
286
287
#ifdef PRINTSTUFF
288
printf ("  chunk %d/%d (bytes %d/%d), first 6 bytes = %02X %02X %02X %02X %02X %02X\n",
289
  current_video_sector, video_sector_count,
290
  video_frame_index, video_frame_size,
291
  pkt->data[current_video_sector * VIDEO_DATA_CHUNK_SIZE + 0],
292
  pkt->data[current_video_sector * VIDEO_DATA_CHUNK_SIZE + 1],
293
  pkt->data[current_video_sector * VIDEO_DATA_CHUNK_SIZE + 2],
294
  pkt->data[current_video_sector * VIDEO_DATA_CHUNK_SIZE + 3],
295
  pkt->data[current_video_sector * VIDEO_DATA_CHUNK_SIZE + 4],
296
  pkt->data[current_video_sector * VIDEO_DATA_CHUNK_SIZE + 5]);
297
#endif
298
299
                video_frame_index += bytes_to_copy;
300
                /* must keep reading sectors until all current video sectors
301
                 * are consumed */
302
                current_video_sector++;
303
                if (current_video_sector >= video_sector_count)
304
                    packet_read = 1;
305
306
            }
307
            break;
308
309
        case CDXA_TYPE_AUDIO:
310
#ifdef PRINTSTUFF
311
printf (" dropping audio sector\n");
312
#endif
313
        break;
314
        default:
315
            /* drop the sector and move on */
316
#ifdef PRINTSTUFF
317
printf (" dropping other sector\n");
318
#endif
319
            break;
320
        }
321
322
        if (url_feof(pb))
323
            return -EIO;
324
    }
325
326
    return ret;
327
}
328
329
static int str_read_close(AVFormatContext *s)
330
{
331
    StrDemuxContext *str = (StrDemuxContext *)s->priv_data;
332
333
    av_free(str->video_chunk);
334
335
    return 0;
336
}
337
338
static AVInputFormat str_iformat = {
339
    "psxstr",
340
    "Sony Playstation STR format",
341
    sizeof(StrDemuxContext),
342
    str_probe,
343
    str_read_header,
344
    str_read_packet,
345
    str_read_close,
346
};
347
348
int str_init(void)
349
{
350
    av_register_input_format(&str_iformat);
351
    return 0;
352
}