Mercurial > libavformat.hg
annotate rpl.c @ 3754:8d267b43eaba libavformat
Move malloc() down until after all initializations, so that the resource is
only allocated if initialization worked. This means that on failure, we
don't have to deallocate it.
author | rbultje |
---|---|
date | Sat, 23 Aug 2008 18:46:30 +0000 |
parents | 7a0230981402 |
children | 1d3d17de20ba |
rev | line source |
---|---|
3197 | 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 | |
3286 | 22 #include "libavutil/avstring.h" |
3197 | 23 #include "avformat.h" |
24 #include <stdlib.h> | |
25 | |
26 #define RPL_SIGNATURE "ARMovie\x0A" | |
27 #define RPL_SIGNATURE_SIZE 8 | |
28 | |
29 /** 256 is arbitrary, but should be big enough for any reasonable file. */ | |
30 #define RPL_LINE_LENGTH 256 | |
31 | |
32 static int rpl_probe(AVProbeData *p) | |
33 { | |
34 if (memcmp(p->buf, RPL_SIGNATURE, RPL_SIGNATURE_SIZE)) | |
35 return 0; | |
36 | |
37 return AVPROBE_SCORE_MAX; | |
38 } | |
39 | |
40 typedef struct RPLContext { | |
41 // RPL header data | |
42 int32_t frames_per_chunk; | |
43 | |
44 // Stream position data | |
45 uint32_t chunk_number; | |
46 uint32_t chunk_part; | |
47 uint32_t frame_in_part; | |
48 } RPLContext; | |
49 | |
50 static int read_line(ByteIOContext * pb, char* line, int bufsize) | |
51 { | |
52 int i; | |
53 for (i = 0; i < bufsize - 1; i++) { | |
54 int b = get_byte(pb); | |
55 if (b == 0) | |
56 break; | |
57 if (b == '\n') { | |
58 line[i] = '\0'; | |
59 return 0; | |
60 } | |
61 line[i] = b; | |
62 } | |
63 line[i] = '\0'; | |
64 return -1; | |
65 } | |
66 | |
67 static int32_t read_int(const char* line, const char** endptr, int* error) | |
68 { | |
69 unsigned long result = 0; | |
70 for (; *line>='0' && *line<='9'; line++) { | |
71 if (result > (0x7FFFFFFF - 9) / 10) | |
72 *error = -1; | |
73 result = 10 * result + *line - '0'; | |
74 } | |
75 *endptr = line; | |
76 return result; | |
77 } | |
78 | |
79 static int32_t read_line_and_int(ByteIOContext * pb, int* error) | |
80 { | |
81 char line[RPL_LINE_LENGTH]; | |
82 const char *endptr; | |
83 *error |= read_line(pb, line, sizeof(line)); | |
84 return read_int(line, &endptr, error); | |
85 } | |
86 | |
87 /** Parsing for fps, which can be a fraction. Unfortunately, | |
88 * the spec for the header leaves out a lot of details, | |
89 * so this is mostly guessing. | |
90 */ | |
91 static AVRational read_fps(const char* line, int* error) | |
92 { | |
93 int64_t num, den = 1; | |
94 AVRational result; | |
95 num = read_int(line, &line, error); | |
96 if (*line == '.') | |
97 line++; | |
98 for (; *line>='0' && *line<='9'; line++) { | |
99 // Truncate any numerator too large to fit into an int64_t | |
100 if (num > (INT64_MAX - 9) / 10 || den > INT64_MAX / 10) | |
101 break; | |
102 num = 10 * num + *line - '0'; | |
103 den *= 10; | |
104 } | |
105 if (!num) | |
106 *error = -1; | |
107 av_reduce(&result.num, &result.den, num, den, 0x7FFFFFFF); | |
108 return result; | |
109 } | |
110 | |
111 static int rpl_read_header(AVFormatContext *s, AVFormatParameters *ap) | |
112 { | |
113 ByteIOContext *pb = s->pb; | |
114 RPLContext *rpl = s->priv_data; | |
115 AVStream *vst = NULL, *ast = NULL; | |
116 int total_audio_size; | |
117 int error = 0; | |
118 | |
119 uint32_t i; | |
120 | |
121 int32_t audio_format, chunk_catalog_offset, number_of_chunks; | |
122 AVRational fps; | |
123 | |
124 char line[RPL_LINE_LENGTH]; | |
125 | |
126 // The header for RPL/ARMovie files is 21 lines of text | |
127 // containing the various header fields. The fields are always | |
128 // in the same order, and other text besides the first | |
129 // number usually isn't important. | |
130 // (The spec says that there exists some significance | |
131 // for the text in a few cases; samples needed.) | |
132 error |= read_line(pb, line , sizeof(line )); // ARMovie | |
133 error |= read_line(pb, s->title , sizeof(s->title )); // movie name | |
134 error |= read_line(pb, s->copyright, sizeof(s->copyright)); // date/copyright | |
135 error |= read_line(pb, s->author , sizeof(s->author )); // author and other | |
136 | |
137 // video headers | |
138 vst = av_new_stream(s, 0); | |
139 if (!vst) | |
140 return AVERROR(ENOMEM); | |
141 vst->codec->codec_type = CODEC_TYPE_VIDEO; | |
142 vst->codec->codec_tag = read_line_and_int(pb, &error); // video format | |
143 vst->codec->width = read_line_and_int(pb, &error); // video width | |
144 vst->codec->height = read_line_and_int(pb, &error); // video height | |
145 vst->codec->bits_per_sample = read_line_and_int(pb, &error); // video bits per sample | |
146 error |= read_line(pb, line, sizeof(line)); // video frames per second | |
147 fps = read_fps(line, &error); | |
148 av_set_pts_info(vst, 32, fps.den, fps.num); | |
149 | |
150 // Figure out the video codec | |
151 switch (vst->codec->codec_tag) { | |
152 #if 0 | |
153 case 122: | |
154 vst->codec->codec_id = CODEC_ID_ESCAPE122; | |
155 break; | |
156 #endif | |
157 case 124: | |
158 vst->codec->codec_id = CODEC_ID_ESCAPE124; | |
159 // The header is wrong here, at least sometimes | |
160 vst->codec->bits_per_sample = 16; | |
161 break; | |
162 #if 0 | |
163 case 130: | |
164 vst->codec->codec_id = CODEC_ID_ESCAPE130; | |
165 break; | |
166 #endif | |
167 default: | |
168 av_log(s, AV_LOG_WARNING, | |
169 "RPL video format %i not supported yet!\n", | |
170 vst->codec->codec_tag); | |
171 vst->codec->codec_id = CODEC_ID_NONE; | |
172 } | |
173 | |
174 // Audio headers | |
175 | |
176 // ARMovie supports multiple audio tracks; I don't have any | |
177 // samples, though. This code will ignore additional tracks. | |
178 audio_format = read_line_and_int(pb, &error); // audio format ID | |
179 if (audio_format) { | |
180 ast = av_new_stream(s, 0); | |
181 if (!ast) | |
182 return AVERROR(ENOMEM); | |
183 ast->codec->codec_type = CODEC_TYPE_AUDIO; | |
184 ast->codec->codec_tag = audio_format; | |
185 ast->codec->sample_rate = read_line_and_int(pb, &error); // audio bitrate | |
186 ast->codec->channels = read_line_and_int(pb, &error); // number of audio channels | |
187 ast->codec->bits_per_sample = read_line_and_int(pb, &error); // audio bits per sample | |
188 // At least one sample uses 0 for ADPCM, which is really 4 bits | |
189 // per sample. | |
190 if (ast->codec->bits_per_sample == 0) | |
191 ast->codec->bits_per_sample = 4; | |
192 | |
193 ast->codec->bit_rate = ast->codec->sample_rate * | |
194 ast->codec->bits_per_sample * | |
195 ast->codec->channels; | |
196 | |
197 ast->codec->codec_id = CODEC_ID_NONE; | |
198 switch (audio_format) { | |
199 case 1: | |
200 if (ast->codec->bits_per_sample == 16) { | |
201 // 16-bit audio is always signed | |
202 ast->codec->codec_id = CODEC_ID_PCM_S16LE; | |
203 break; | |
204 } | |
205 // There are some other formats listed as legal per the spec; | |
206 // samples needed. | |
207 break; | |
208 case 101: | |
209 if (ast->codec->bits_per_sample == 8) { | |
210 // The samples with this kind of audio that I have | |
211 // are all unsigned. | |
212 ast->codec->codec_id = CODEC_ID_PCM_U8; | |
213 break; | |
214 } else if (ast->codec->bits_per_sample == 4) { | |
215 ast->codec->codec_id = CODEC_ID_ADPCM_IMA_EA_SEAD; | |
216 break; | |
217 } | |
218 break; | |
219 } | |
220 if (ast->codec->codec_id == CODEC_ID_NONE) { | |
221 av_log(s, AV_LOG_WARNING, | |
222 "RPL audio format %i not supported yet!\n", | |
223 audio_format); | |
224 } | |
225 av_set_pts_info(ast, 32, 1, ast->codec->bit_rate); | |
226 } else { | |
227 for (i = 0; i < 3; i++) | |
228 error |= read_line(pb, line, sizeof(line)); | |
229 } | |
230 | |
231 rpl->frames_per_chunk = read_line_and_int(pb, &error); // video frames per chunk | |
232 if (rpl->frames_per_chunk > 1 && vst->codec->codec_tag != 124) | |
233 av_log(s, AV_LOG_WARNING, | |
234 "Don't know how to split frames for video format %i. " | |
235 "Video stream will be broken!\n", vst->codec->codec_tag); | |
236 | |
237 number_of_chunks = read_line_and_int(pb, &error); // number of chunks in the file | |
238 // The number in the header is actually the index of the last chunk. | |
239 number_of_chunks++; | |
240 | |
241 error |= read_line(pb, line, sizeof(line)); // "even" chunk size in bytes | |
242 error |= read_line(pb, line, sizeof(line)); // "odd" chunk size in bytes | |
243 chunk_catalog_offset = // offset of the "chunk catalog" | |
244 read_line_and_int(pb, &error); // (file index) | |
245 error |= read_line(pb, line, sizeof(line)); // offset to "helpful" sprite | |
246 error |= read_line(pb, line, sizeof(line)); // size of "helpful" sprite | |
247 error |= read_line(pb, line, sizeof(line)); // offset to key frame list | |
248 | |
249 // Read the index | |
250 url_fseek(pb, chunk_catalog_offset, SEEK_SET); | |
251 total_audio_size = 0; | |
252 for (i = 0; i < number_of_chunks; i++) { | |
253 int64_t offset, video_size, audio_size; | |
254 error |= read_line(pb, line, sizeof(line)); | |
255 if (3 != sscanf(line, "%"PRId64" , %"PRId64" ; %"PRId64, | |
256 &offset, &video_size, &audio_size)) | |
257 error = -1; | |
258 av_add_index_entry(vst, offset, i * rpl->frames_per_chunk, | |
259 video_size, rpl->frames_per_chunk, 0); | |
260 if (ast) | |
261 av_add_index_entry(ast, offset + video_size, total_audio_size, | |
262 audio_size, audio_size * 8, 0); | |
263 total_audio_size += audio_size * 8; | |
264 } | |
265 | |
266 if (error) return AVERROR(EIO); | |
267 | |
268 return 0; | |
269 } | |
270 | |
271 static int rpl_read_packet(AVFormatContext *s, AVPacket *pkt) | |
272 { | |
273 RPLContext *rpl = s->priv_data; | |
274 ByteIOContext *pb = s->pb; | |
275 AVStream* stream; | |
276 AVIndexEntry* index_entry; | |
277 uint32_t ret; | |
278 | |
279 if (rpl->chunk_part == s->nb_streams) { | |
280 rpl->chunk_number++; | |
281 rpl->chunk_part = 0; | |
282 } | |
283 | |
284 stream = s->streams[rpl->chunk_part]; | |
285 | |
286 if (rpl->chunk_number >= stream->nb_index_entries) | |
287 return -1; | |
288 | |
289 index_entry = &stream->index_entries[rpl->chunk_number]; | |
290 | |
291 if (rpl->frame_in_part == 0) | |
292 if (url_fseek(pb, index_entry->pos, SEEK_SET) < 0) | |
293 return AVERROR(EIO); | |
294 | |
295 if (stream->codec->codec_type == CODEC_TYPE_VIDEO && | |
296 stream->codec->codec_tag == 124) { | |
297 // We have to split Escape 124 frames because there are | |
298 // multiple frames per chunk in Escape 124 samples. | |
299 uint32_t frame_size, frame_flags; | |
300 | |
301 frame_flags = get_le32(pb); | |
302 frame_size = get_le32(pb); | |
303 if (url_fseek(pb, -8, SEEK_CUR) < 0) | |
304 return AVERROR(EIO); | |
305 | |
306 ret = av_get_packet(pb, pkt, frame_size); | |
307 if (ret != frame_size) { | |
308 av_free_packet(pkt); | |
309 return AVERROR(EIO); | |
310 } | |
311 pkt->duration = 1; | |
312 pkt->pts = index_entry->timestamp + rpl->frame_in_part; | |
313 pkt->stream_index = rpl->chunk_part; | |
314 | |
315 rpl->frame_in_part++; | |
316 if (rpl->frame_in_part == rpl->frames_per_chunk) { | |
317 rpl->frame_in_part = 0; | |
318 rpl->chunk_part++; | |
319 } | |
320 } else { | |
321 ret = av_get_packet(pb, pkt, index_entry->size); | |
322 if (ret != index_entry->size) { | |
323 av_free_packet(pkt); | |
324 return AVERROR(EIO); | |
325 } | |
326 | |
327 if (stream->codec->codec_type == CODEC_TYPE_VIDEO) { | |
328 // frames_per_chunk should always be one here; the header | |
329 // parsing will warn if it isn't. | |
330 pkt->duration = rpl->frames_per_chunk; | |
331 } else { | |
332 // All the audio codecs supported in this container | |
333 // (at least so far) are constant-bitrate. | |
334 pkt->duration = ret * 8; | |
335 } | |
336 pkt->pts = index_entry->timestamp; | |
337 pkt->stream_index = rpl->chunk_part; | |
338 rpl->chunk_part++; | |
339 } | |
340 | |
341 // None of the Escape formats have keyframes, and the ADPCM | |
342 // format used doesn't have keyframes. | |
343 if (rpl->chunk_number == 0 && rpl->frame_in_part == 0) | |
344 pkt->flags |= PKT_FLAG_KEY; | |
345 | |
346 return ret; | |
347 } | |
348 | |
349 AVInputFormat rpl_demuxer = { | |
350 "rpl", | |
3424
7a0230981402
Make long_names in lavf/lavdev optional depending on CONFIG_SMALL.
diego
parents:
3286
diff
changeset
|
351 NULL_IF_CONFIG_SMALL("RPL/ARMovie format"), |
3197 | 352 sizeof(RPLContext), |
353 rpl_probe, | |
354 rpl_read_header, | |
355 rpl_read_packet, | |
356 }; |