/src/ffmpeg/libavformat/segafilm.c
Line | Count | Source |
1 | | /* |
2 | | * Sega FILM Format (CPK) Demuxer |
3 | | * Copyright (c) 2003 The FFmpeg project |
4 | | * |
5 | | * This file is part of FFmpeg. |
6 | | * |
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. |
11 | | * |
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. |
16 | | * |
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 |
20 | | */ |
21 | | |
22 | | /** |
23 | | * @file |
24 | | * Sega FILM (.cpk) file demuxer |
25 | | * by Mike Melanson (melanson@pcisys.net) |
26 | | * For more information regarding the Sega FILM file format, visit: |
27 | | * http://www.pcisys.net/~melanson/codecs/ |
28 | | */ |
29 | | |
30 | | #include "libavutil/intreadwrite.h" |
31 | | #include "libavutil/mem.h" |
32 | | #include "avformat.h" |
33 | | #include "demux.h" |
34 | | #include "internal.h" |
35 | | |
36 | 964k | #define FILM_TAG MKBETAG('F', 'I', 'L', 'M') |
37 | 3.23k | #define FDSC_TAG MKBETAG('F', 'D', 'S', 'C') |
38 | 2.73k | #define STAB_TAG MKBETAG('S', 'T', 'A', 'B') |
39 | 2.84k | #define CVID_TAG MKBETAG('c', 'v', 'i', 'd') |
40 | 875 | #define RAW_TAG MKBETAG('r', 'a', 'w', ' ') |
41 | | |
42 | | typedef struct film_sample { |
43 | | int stream; |
44 | | unsigned int sample_size; |
45 | | int64_t sample_offset; |
46 | | int64_t pts; |
47 | | int keyframe; |
48 | | } film_sample; |
49 | | |
50 | | typedef struct FilmDemuxContext { |
51 | | int video_stream_index; |
52 | | int audio_stream_index; |
53 | | |
54 | | enum AVCodecID audio_type; |
55 | | unsigned int audio_samplerate; |
56 | | unsigned int audio_bits; |
57 | | unsigned int audio_channels; |
58 | | |
59 | | enum AVCodecID video_type; |
60 | | unsigned int sample_count; |
61 | | film_sample *sample_table; |
62 | | unsigned int current_sample; |
63 | | |
64 | | unsigned int base_clock; |
65 | | unsigned int version; |
66 | | } FilmDemuxContext; |
67 | | |
68 | | static int film_probe(const AVProbeData *p) |
69 | 964k | { |
70 | 964k | if (AV_RB32(&p->buf[0]) != FILM_TAG) |
71 | 964k | return 0; |
72 | | |
73 | 292 | if (AV_RB32(&p->buf[16]) != FDSC_TAG) |
74 | 182 | return 0; |
75 | | |
76 | 110 | return AVPROBE_SCORE_MAX; |
77 | 292 | } |
78 | | |
79 | | static int film_read_close(AVFormatContext *s) |
80 | 3.12k | { |
81 | 3.12k | FilmDemuxContext *film = s->priv_data; |
82 | | |
83 | 3.12k | av_freep(&film->sample_table); |
84 | | |
85 | 3.12k | return 0; |
86 | 3.12k | } |
87 | | |
88 | | static int film_read_header(AVFormatContext *s) |
89 | 3.12k | { |
90 | 3.12k | FilmDemuxContext *film = s->priv_data; |
91 | 3.12k | AVIOContext *pb = s->pb; |
92 | 3.12k | AVStream *st; |
93 | 3.12k | unsigned char scratch[256]; |
94 | 3.12k | int i; |
95 | 3.12k | unsigned int data_offset; |
96 | 3.12k | unsigned int audio_frame_counter; |
97 | 3.12k | unsigned int video_frame_counter; |
98 | | |
99 | 3.12k | film->sample_table = NULL; |
100 | | |
101 | | /* load the main FILM header */ |
102 | 3.12k | if (avio_read(pb, scratch, 16) != 16) |
103 | 101 | return AVERROR(EIO); |
104 | 3.02k | data_offset = AV_RB32(&scratch[4]); |
105 | 3.02k | film->version = AV_RB32(&scratch[8]); |
106 | | |
107 | | /* load the FDSC chunk */ |
108 | 3.02k | if (film->version == 0) { |
109 | | /* special case for Lemmings .film files; 20-byte header */ |
110 | 2.37k | if (avio_read(pb, scratch, 20) != 20) |
111 | 16 | return AVERROR(EIO); |
112 | | /* make some assumptions about the audio parameters */ |
113 | 2.36k | film->audio_type = AV_CODEC_ID_PCM_S8; |
114 | 2.36k | film->audio_samplerate = 22050; |
115 | 2.36k | film->audio_channels = 1; |
116 | 2.36k | film->audio_bits = 8; |
117 | 2.36k | } else { |
118 | | /* normal Saturn .cpk files; 32-byte header */ |
119 | 644 | if (avio_read(pb, scratch, 32) != 32) |
120 | 68 | return AVERROR(EIO); |
121 | 576 | film->audio_samplerate = AV_RB16(&scratch[24]); |
122 | 576 | film->audio_channels = scratch[21]; |
123 | 576 | film->audio_bits = scratch[22]; |
124 | 576 | if (scratch[23] == 2 && film->audio_channels > 0) |
125 | 254 | film->audio_type = AV_CODEC_ID_ADPCM_ADX; |
126 | 322 | else if (film->audio_channels > 0) { |
127 | 304 | if (film->audio_bits == 8) |
128 | 77 | film->audio_type = AV_CODEC_ID_PCM_S8_PLANAR; |
129 | 227 | else if (film->audio_bits == 16) |
130 | 119 | film->audio_type = AV_CODEC_ID_PCM_S16BE_PLANAR; |
131 | 108 | else |
132 | 108 | film->audio_type = AV_CODEC_ID_NONE; |
133 | 304 | } else |
134 | 18 | film->audio_type = AV_CODEC_ID_NONE; |
135 | 576 | } |
136 | | |
137 | 2.93k | if (AV_RB32(&scratch[0]) != FDSC_TAG) |
138 | 89 | return AVERROR_INVALIDDATA; |
139 | | |
140 | 2.84k | if (AV_RB32(&scratch[8]) == CVID_TAG) { |
141 | 1.97k | film->video_type = AV_CODEC_ID_CINEPAK; |
142 | 1.97k | } else if (AV_RB32(&scratch[8]) == RAW_TAG) { |
143 | 142 | film->video_type = AV_CODEC_ID_RAWVIDEO; |
144 | 733 | } else { |
145 | 733 | film->video_type = AV_CODEC_ID_NONE; |
146 | 733 | } |
147 | | |
148 | 2.84k | if (film->video_type == AV_CODEC_ID_NONE && film->audio_type == AV_CODEC_ID_NONE) |
149 | 12 | return AVERROR_INVALIDDATA; |
150 | | |
151 | | /* initialize the decoder streams */ |
152 | 2.83k | if (film->video_type != AV_CODEC_ID_NONE) { |
153 | 2.11k | st = avformat_new_stream(s, NULL); |
154 | 2.11k | if (!st) |
155 | 0 | return AVERROR(ENOMEM); |
156 | 2.11k | film->video_stream_index = st->index; |
157 | 2.11k | st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; |
158 | 2.11k | st->codecpar->codec_id = film->video_type; |
159 | 2.11k | st->codecpar->codec_tag = 0; /* no fourcc */ |
160 | 2.11k | st->codecpar->width = AV_RB32(&scratch[16]); |
161 | 2.11k | st->codecpar->height = AV_RB32(&scratch[12]); |
162 | | |
163 | 2.11k | if (film->video_type == AV_CODEC_ID_RAWVIDEO) { |
164 | 142 | if (scratch[20] == 24) { |
165 | 131 | st->codecpar->format = AV_PIX_FMT_RGB24; |
166 | 131 | } else { |
167 | 11 | av_log(s, AV_LOG_ERROR, "raw video is using unhandled %dbpp\n", scratch[20]); |
168 | 11 | return -1; |
169 | 11 | } |
170 | 142 | } |
171 | 2.11k | } |
172 | | |
173 | 2.82k | if (film->audio_type != AV_CODEC_ID_NONE) { |
174 | 2.74k | st = avformat_new_stream(s, NULL); |
175 | 2.74k | if (!st) |
176 | 0 | return AVERROR(ENOMEM); |
177 | 2.74k | film->audio_stream_index = st->index; |
178 | 2.74k | st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; |
179 | 2.74k | st->codecpar->codec_id = film->audio_type; |
180 | 2.74k | st->codecpar->codec_tag = 1; |
181 | 2.74k | st->codecpar->ch_layout.nb_channels = film->audio_channels; |
182 | 2.74k | st->codecpar->sample_rate = film->audio_samplerate; |
183 | | |
184 | 2.74k | if (film->audio_type == AV_CODEC_ID_ADPCM_ADX) { |
185 | 249 | st->codecpar->bits_per_coded_sample = 18 * 8 / 32; |
186 | 249 | st->codecpar->block_align = film->audio_channels * 18; |
187 | 249 | ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL; |
188 | 2.50k | } else { |
189 | 2.50k | st->codecpar->bits_per_coded_sample = film->audio_bits; |
190 | 2.50k | st->codecpar->block_align = film->audio_channels * |
191 | 2.50k | st->codecpar->bits_per_coded_sample / 8; |
192 | 2.50k | } |
193 | | |
194 | 2.74k | st->codecpar->bit_rate = film->audio_channels * st->codecpar->sample_rate * |
195 | 2.74k | st->codecpar->bits_per_coded_sample; |
196 | 2.74k | } |
197 | | |
198 | | /* load the sample table */ |
199 | 2.82k | if (avio_read(pb, scratch, 16) != 16) |
200 | 88 | return AVERROR(EIO); |
201 | 2.73k | if (AV_RB32(&scratch[0]) != STAB_TAG) |
202 | 48 | return AVERROR_INVALIDDATA; |
203 | 2.69k | film->base_clock = AV_RB32(&scratch[8]); |
204 | 2.69k | film->sample_count = AV_RB32(&scratch[12]); |
205 | 2.69k | film->sample_table = av_malloc_array(film->sample_count, sizeof(film_sample)); |
206 | 2.69k | if (!film->sample_table) |
207 | 38 | return AVERROR(ENOMEM); |
208 | | |
209 | 7.28k | for (i = 0; i < s->nb_streams; i++) { |
210 | 4.63k | st = s->streams[i]; |
211 | 4.63k | if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) |
212 | 2.05k | avpriv_set_pts_info(st, 33, 1, film->base_clock); |
213 | 2.57k | else |
214 | 2.57k | avpriv_set_pts_info(st, 64, 1, film->audio_samplerate); |
215 | 4.63k | } |
216 | | |
217 | 2.65k | audio_frame_counter = video_frame_counter = 0; |
218 | 134k | for (i = 0; i < film->sample_count; i++) { |
219 | | /* load the next sample record and transfer it to an internal struct */ |
220 | 132k | if (avio_read(pb, scratch, 16) != 16) |
221 | 169 | return AVERROR(EIO); |
222 | 132k | film->sample_table[i].sample_offset = |
223 | 132k | data_offset + AV_RB32(&scratch[0]); |
224 | 132k | film->sample_table[i].sample_size = AV_RB32(&scratch[4]); |
225 | 132k | if (film->sample_table[i].sample_size > INT_MAX / 4) |
226 | 33 | return AVERROR_INVALIDDATA; |
227 | 132k | if (AV_RB32(&scratch[8]) == 0xFFFFFFFF) { |
228 | 7.16k | film->sample_table[i].stream = film->audio_stream_index; |
229 | 7.16k | film->sample_table[i].pts = audio_frame_counter; |
230 | | |
231 | 7.16k | if (film->audio_type == AV_CODEC_ID_ADPCM_ADX) |
232 | 5.64k | audio_frame_counter += (film->sample_table[i].sample_size * 32 / |
233 | 5.64k | (18 * film->audio_channels)); |
234 | 1.52k | else if (film->audio_type != AV_CODEC_ID_NONE) |
235 | 1.03k | audio_frame_counter += (film->sample_table[i].sample_size / |
236 | 1.03k | (film->audio_channels * film->audio_bits / 8)); |
237 | 7.16k | film->sample_table[i].keyframe = 1; |
238 | 124k | } else { |
239 | 124k | film->sample_table[i].stream = film->video_stream_index; |
240 | 124k | film->sample_table[i].pts = AV_RB32(&scratch[8]) & 0x7FFFFFFF; |
241 | 124k | film->sample_table[i].keyframe = (scratch[8] & 0x80) ? 0 : AVINDEX_KEYFRAME; |
242 | 124k | video_frame_counter++; |
243 | 124k | if (film->video_type != AV_CODEC_ID_NONE) |
244 | 118k | av_add_index_entry(s->streams[film->video_stream_index], |
245 | 118k | film->sample_table[i].sample_offset, |
246 | 118k | film->sample_table[i].pts, |
247 | 118k | film->sample_table[i].sample_size, 0, |
248 | 118k | film->sample_table[i].keyframe); |
249 | 124k | } |
250 | 132k | } |
251 | | |
252 | 2.45k | if (film->audio_type != AV_CODEC_ID_NONE) |
253 | 2.39k | s->streams[film->audio_stream_index]->duration = audio_frame_counter; |
254 | | |
255 | 2.45k | if (film->video_type != AV_CODEC_ID_NONE) |
256 | 1.88k | s->streams[film->video_stream_index]->duration = video_frame_counter; |
257 | | |
258 | 2.45k | film->current_sample = 0; |
259 | | |
260 | 2.45k | return 0; |
261 | 2.65k | } |
262 | | |
263 | | static int film_read_packet(AVFormatContext *s, |
264 | | AVPacket *pkt) |
265 | 46.1k | { |
266 | 46.1k | FilmDemuxContext *film = s->priv_data; |
267 | 46.1k | AVIOContext *pb = s->pb; |
268 | 46.1k | film_sample *sample; |
269 | 46.1k | film_sample *next_sample = NULL; |
270 | 46.1k | int next_sample_id; |
271 | 46.1k | int ret = 0; |
272 | | |
273 | 46.1k | if (film->current_sample >= film->sample_count) |
274 | 2.55k | return AVERROR_EOF; |
275 | | |
276 | 43.6k | sample = &film->sample_table[film->current_sample]; |
277 | | |
278 | | /* Find the next sample from the same stream, assuming there is one; |
279 | | * this is used to calculate the duration below */ |
280 | 43.6k | next_sample_id = film->current_sample + 1; |
281 | 93.5k | while (next_sample == NULL) { |
282 | 52.0k | if (next_sample_id >= film->sample_count) |
283 | 2.21k | break; |
284 | | |
285 | 49.8k | next_sample = &film->sample_table[next_sample_id]; |
286 | 49.8k | if (next_sample->stream != sample->stream) { |
287 | 8.44k | next_sample = NULL; |
288 | 8.44k | next_sample_id++; |
289 | 8.44k | } |
290 | 49.8k | } |
291 | | |
292 | | /* position the stream (will probably be there anyway) */ |
293 | 43.6k | avio_seek(pb, sample->sample_offset, SEEK_SET); |
294 | | |
295 | 43.6k | ret = av_get_packet(pb, pkt, sample->sample_size); |
296 | 43.6k | if (ret != sample->sample_size) |
297 | 1.96k | ret = AVERROR(EIO); |
298 | | |
299 | 43.6k | pkt->stream_index = sample->stream; |
300 | 43.6k | pkt->dts = sample->pts; |
301 | 43.6k | pkt->pts = sample->pts; |
302 | 43.6k | pkt->flags |= sample->keyframe ? AV_PKT_FLAG_KEY : 0; |
303 | 43.6k | if (next_sample != NULL) |
304 | 41.4k | pkt->duration = next_sample->pts - sample->pts; |
305 | | |
306 | 43.6k | film->current_sample++; |
307 | | |
308 | 43.6k | return ret; |
309 | 46.1k | } |
310 | | |
311 | | static int film_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) |
312 | 0 | { |
313 | 0 | FilmDemuxContext *film = s->priv_data; |
314 | 0 | AVStream *st = s->streams[stream_index]; |
315 | 0 | int64_t pos; |
316 | 0 | int ret = av_index_search_timestamp(st, timestamp, flags); |
317 | 0 | if (ret < 0) |
318 | 0 | return ret; |
319 | | |
320 | 0 | pos = avio_seek(s->pb, ffstream(st)->index_entries[ret].pos, SEEK_SET); |
321 | 0 | if (pos < 0) |
322 | 0 | return pos; |
323 | | |
324 | 0 | film->current_sample = ret; |
325 | |
|
326 | 0 | return 0; |
327 | 0 | } |
328 | | |
329 | | const FFInputFormat ff_segafilm_demuxer = { |
330 | | .p.name = "film_cpk", |
331 | | .p.long_name = NULL_IF_CONFIG_SMALL("Sega FILM / CPK"), |
332 | | .priv_data_size = sizeof(FilmDemuxContext), |
333 | | .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP, |
334 | | .read_probe = film_probe, |
335 | | .read_header = film_read_header, |
336 | | .read_packet = film_read_packet, |
337 | | .read_close = film_read_close, |
338 | | .read_seek = film_read_seek, |
339 | | }; |