1 /*
2 * ARMovie/RPL demuxer
3 * Copyright (c) 2007 Christian Ohm, 2008 Eli Friedman
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
26 #include <stdlib.h>
27
28 #define RPL_SIGNATURE "ARMovie\x0A"
29 #define RPL_SIGNATURE_SIZE 8
30
31 /** 256 is arbitrary, but should be big enough for any reasonable file. */
32 #define RPL_LINE_LENGTH 256
33
35 {
37 return 0;
38
40 }
41
43 // RPL header data
45
46 // Stream position data
51
53 {
54 int i;
55 for (i = 0; i < bufsize - 1; i++) {
57 if (b == 0)
58 break;
59 if (b == '\n') {
60 line[i] = '0円';
62 }
64 }
65 line[i] = '0円';
66 return -1;
67 }
68
70 {
71 unsigned long result = 0;
72 for (; *line>='0' && *line<='9'; line++) {
73 if (result > (0x7FFFFFFF - 9) / 10)
74 *error = -1;
75 result = 10 * result + *line - '0';
76 }
77 *endptr = line;
78 return result;
79 }
80
82 {
84 const char *endptr;
85 *error |=
read_line(pb, line,
sizeof(line));
86 return read_int(line, &endptr, error);
87 }
88
89 /** Parsing for fps, which can be a fraction. Unfortunately,
90 * the spec for the header leaves out a lot of details,
91 * so this is mostly guessing.
92 */
94 {
95 int64_t num, den = 1;
98 if (*line == '.')
99 line++;
100 for (; *line>='0' && *line<='9'; line++) {
101 // Truncate any numerator too large to fit into an int64_t
102 if (num > (INT64_MAX - 9) / 10 || den > INT64_MAX / 10)
103 break;
104 num = 10 * num + *line - '0';
105 den *= 10;
106 }
107 if (!num)
108 *error = -1;
110 return result;
111 }
112
114 {
118 int total_audio_size;
119 int error = 0;
120
121 uint32_t i;
122
123 int32_t audio_format, chunk_catalog_offset, number_of_chunks;
125
127
128 // The header for RPL/ARMovie files is 21 lines of text
129 // containing the various header fields. The fields are always
130 // in the same order, and other text besides the first
131 // number usually isn't important.
132 // (The spec says that there exists some significance
133 // for the text in a few cases; samples needed.)
134 error |=
read_line(pb, line,
sizeof(line));
// ARMovie
135 error |=
read_line(pb, line,
sizeof(line));
// movie name
137 error |=
read_line(pb, line,
sizeof(line));
// date/copyright
139 error |=
read_line(pb, line,
sizeof(line));
// author and other
141
142 // video headers
144 if (!vst)
151 error |=
read_line(pb, line,
sizeof(line));
// video frames per second
154
155 // Figure out the video codec
157 #if 0
158 case 122:
160 break;
161 #endif
162 case 124:
164 // The header is wrong here, at least sometimes
166 break;
167 case 130:
169 break;
170 default:
172 "RPL video format %i not supported yet!\n",
175 }
176
177 // Audio headers
178
179 // ARMovie supports multiple audio tracks; I don't have any
180 // samples, though. This code will ignore additional tracks.
182 if (audio_format) {
184 if (!ast)
187 ast->codec->codec_tag = audio_format;
189 ast->codec->channels =
read_line_and_int(pb, &error);
// number of audio channels
190 ast->codec->bits_per_coded_sample =
read_line_and_int(pb, &error);
// audio bits per sample
191 // At least one sample uses 0 for ADPCM, which is really 4 bits
192 // per sample.
193 if (ast->codec->bits_per_coded_sample == 0)
194 ast->codec->bits_per_coded_sample = 4;
195
196 ast->codec->bit_rate = ast->codec->sample_rate *
197 ast->codec->bits_per_coded_sample *
198 ast->codec->channels;
199
201 switch (audio_format) {
202 case 1:
203 if (ast->codec->bits_per_coded_sample == 16) {
204 // 16-bit audio is always signed
206 break;
207 }
208 // There are some other formats listed as legal per the spec;
209 // samples needed.
210 break;
211 case 101:
212 if (ast->codec->bits_per_coded_sample == 8) {
213 // The samples with this kind of audio that I have
214 // are all unsigned.
216 break;
217 } else if (ast->codec->bits_per_coded_sample == 4) {
219 break;
220 }
221 break;
222 }
225 "RPL audio format %i not supported yet!\n",
226 audio_format);
227 }
229 } else {
230 for (i = 0; i < 3; i++)
231 error |=
read_line(pb, line,
sizeof(line));
232 }
233
237 "Don't know how to split frames for video format %i. "
239
240 number_of_chunks =
read_line_and_int(pb, &error);
// number of chunks in the file
241 // The number in the header is actually the index of the last chunk.
242 number_of_chunks++;
243
244 error |=
read_line(pb, line,
sizeof(line));
// "even" chunk size in bytes
245 error |=
read_line(pb, line,
sizeof(line));
// "odd" chunk size in bytes
246 chunk_catalog_offset = // offset of the "chunk catalog"
248 error |=
read_line(pb, line,
sizeof(line));
// offset to "helpful" sprite
249 error |=
read_line(pb, line,
sizeof(line));
// size of "helpful" sprite
250 error |=
read_line(pb, line,
sizeof(line));
// offset to key frame list
251
252 // Read the index
253 avio_seek(pb, chunk_catalog_offset, SEEK_SET);
254 total_audio_size = 0;
255 for (i = 0; !error && i < number_of_chunks; i++) {
257 error |=
read_line(pb, line,
sizeof(line));
258 if (3 != sscanf(line, "%"PRId64" , %"PRId64" ; %"PRId64,
259 &offset, &video_size, &audio_size))
260 error = -1;
263 if (ast)
265 audio_size, audio_size * 8, 0);
266 total_audio_size += audio_size * 8;
267 }
268
269 if (error)
return AVERROR(EIO);
270
271 return 0;
272 }
273
275 {
280 uint32_t ret;
281
285 }
286
288
291
293
297
300 // We have to split Escape 124 frames because there are
301 // multiple frames per chunk in Escape 124 samples.
303
308
310 if (ret != frame_size) {
313 }
317
322 }
323 } else {
325 if (ret != index_entry->
size) {
328 }
329
331 // frames_per_chunk should always be one here; the header
332 // parsing will warn if it isn't.
334 } else {
335 // All the audio codecs supported in this container
336 // (at least so far) are constant-bitrate.
338 }
342 }
343
344 // None of the Escape formats have keyframes, and the ADPCM
345 // format used doesn't have keyframes.
348
349 return ret;
350 }
351
359 };