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