Imported Debian version 2.4.3~trusty1
[deb_ffmpeg.git] / ffmpeg / libavformat / mvdec.c
CommitLineData
2ba45a60
DM
1/*
2 * Silicon Graphics Movie demuxer
3 * Copyright (c) 2012 Peter Ross
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 * Silicon Graphics Movie demuxer
25 */
26
27#include "libavutil/channel_layout.h"
28#include "libavutil/eval.h"
29#include "libavutil/intreadwrite.h"
30#include "libavutil/rational.h"
31
32#include "avformat.h"
33#include "internal.h"
34
35typedef struct MvContext {
36 int nb_video_tracks;
37 int nb_audio_tracks;
38
39 int eof_count; ///< number of streams that have finished
40 int stream_index; ///< current stream index
41 int frame[2]; ///< frame nb for current stream
42
43 int acompression; ///< compression level for audio stream
44 int aformat; ///< audio format
45} MvContext;
46
47#define AUDIO_FORMAT_SIGNED 401
48
49static int mv_probe(AVProbeData *p)
50{
51 if (AV_RB32(p->buf) == MKBETAG('M', 'O', 'V', 'I') &&
52 AV_RB16(p->buf + 4) < 3)
53 return AVPROBE_SCORE_MAX;
54 return 0;
55}
56
57static char *var_read_string(AVIOContext *pb, int size)
58{
59 int n;
60 char *str = av_malloc(size + 1);
61 if (!str)
62 return NULL;
63 n = avio_get_str(pb, size, str, size + 1);
64 if (n < size)
65 avio_skip(pb, size - n);
66 return str;
67}
68
69static int var_read_int(AVIOContext *pb, int size)
70{
71 int v;
72 char *s = var_read_string(pb, size);
73 if (!s)
74 return 0;
75 v = strtol(s, NULL, 10);
76 av_free(s);
77 return v;
78}
79
80static AVRational var_read_float(AVIOContext *pb, int size)
81{
82 AVRational v;
83 char *s = var_read_string(pb, size);
84 if (!s)
85 return (AVRational) { 0, 0 };
86 v = av_d2q(av_strtod(s, NULL), INT_MAX);
87 av_free(s);
88 return v;
89}
90
91static void var_read_metadata(AVFormatContext *avctx, const char *tag, int size)
92{
93 char *value = var_read_string(avctx->pb, size);
94 if (value)
95 av_dict_set(&avctx->metadata, tag, value, AV_DICT_DONT_STRDUP_VAL);
96}
97
98static int set_channels(AVFormatContext *avctx, AVStream *st, int channels)
99{
100 if (channels <= 0) {
101 av_log(avctx, AV_LOG_ERROR, "Channel count %d invalid.\n", channels);
102 return AVERROR_INVALIDDATA;
103 }
104 st->codec->channels = channels;
105 st->codec->channel_layout = (st->codec->channels == 1) ? AV_CH_LAYOUT_MONO
106 : AV_CH_LAYOUT_STEREO;
107 return 0;
108}
109
110/**
111 * Parse global variable
112 * @return < 0 if unknown
113 */
114static int parse_global_var(AVFormatContext *avctx, AVStream *st,
115 const char *name, int size)
116{
117 MvContext *mv = avctx->priv_data;
118 AVIOContext *pb = avctx->pb;
119 if (!strcmp(name, "__NUM_I_TRACKS")) {
120 mv->nb_video_tracks = var_read_int(pb, size);
121 } else if (!strcmp(name, "__NUM_A_TRACKS")) {
122 mv->nb_audio_tracks = var_read_int(pb, size);
123 } else if (!strcmp(name, "COMMENT") || !strcmp(name, "TITLE")) {
124 var_read_metadata(avctx, name, size);
125 } else if (!strcmp(name, "LOOP_MODE") || !strcmp(name, "NUM_LOOPS") ||
126 !strcmp(name, "OPTIMIZED")) {
127 avio_skip(pb, size); // ignore
128 } else
129 return AVERROR_INVALIDDATA;
130
131 return 0;
132}
133
134/**
135 * Parse audio variable
136 * @return < 0 if unknown
137 */
138static int parse_audio_var(AVFormatContext *avctx, AVStream *st,
139 const char *name, int size)
140{
141 MvContext *mv = avctx->priv_data;
142 AVIOContext *pb = avctx->pb;
143 if (!strcmp(name, "__DIR_COUNT")) {
144 st->nb_frames = var_read_int(pb, size);
145 } else if (!strcmp(name, "AUDIO_FORMAT")) {
146 mv->aformat = var_read_int(pb, size);
147 } else if (!strcmp(name, "COMPRESSION")) {
148 mv->acompression = var_read_int(pb, size);
149 } else if (!strcmp(name, "DEFAULT_VOL")) {
150 var_read_metadata(avctx, name, size);
151 } else if (!strcmp(name, "NUM_CHANNELS")) {
152 return set_channels(avctx, st, var_read_int(pb, size));
153 } else if (!strcmp(name, "SAMPLE_RATE")) {
154 st->codec->sample_rate = var_read_int(pb, size);
155 avpriv_set_pts_info(st, 33, 1, st->codec->sample_rate);
156 } else if (!strcmp(name, "SAMPLE_WIDTH")) {
157 st->codec->bits_per_coded_sample = var_read_int(pb, size) * 8;
158 } else
159 return AVERROR_INVALIDDATA;
160
161 return 0;
162}
163
164/**
165 * Parse video variable
166 * @return < 0 if unknown
167 */
168static int parse_video_var(AVFormatContext *avctx, AVStream *st,
169 const char *name, int size)
170{
171 AVIOContext *pb = avctx->pb;
172 if (!strcmp(name, "__DIR_COUNT")) {
173 st->nb_frames = st->duration = var_read_int(pb, size);
174 } else if (!strcmp(name, "COMPRESSION")) {
175 char *str = var_read_string(pb, size);
176 if (!str)
177 return AVERROR_INVALIDDATA;
178 if (!strcmp(str, "1")) {
179 st->codec->codec_id = AV_CODEC_ID_MVC1;
180 } else if (!strcmp(str, "2")) {
181 st->codec->pix_fmt = AV_PIX_FMT_ABGR;
182 st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
183 } else if (!strcmp(str, "3")) {
184 st->codec->codec_id = AV_CODEC_ID_SGIRLE;
185 } else if (!strcmp(str, "10")) {
186 st->codec->codec_id = AV_CODEC_ID_MJPEG;
187 } else if (!strcmp(str, "MVC2")) {
188 st->codec->codec_id = AV_CODEC_ID_MVC2;
189 } else {
190 avpriv_request_sample(avctx, "Video compression %s", str);
191 }
192 av_free(str);
193 } else if (!strcmp(name, "FPS")) {
194 AVRational fps = var_read_float(pb, size);
195 avpriv_set_pts_info(st, 64, fps.den, fps.num);
196 st->avg_frame_rate = fps;
197 } else if (!strcmp(name, "HEIGHT")) {
198 st->codec->height = var_read_int(pb, size);
199 } else if (!strcmp(name, "PIXEL_ASPECT")) {
200 st->sample_aspect_ratio = var_read_float(pb, size);
201 av_reduce(&st->sample_aspect_ratio.num, &st->sample_aspect_ratio.den,
202 st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
203 INT_MAX);
204 } else if (!strcmp(name, "WIDTH")) {
205 st->codec->width = var_read_int(pb, size);
206 } else if (!strcmp(name, "ORIENTATION")) {
207 if (var_read_int(pb, size) == 1101) {
208 st->codec->extradata = av_strdup("BottomUp");
209 st->codec->extradata_size = 9;
210 }
211 } else if (!strcmp(name, "Q_SPATIAL") || !strcmp(name, "Q_TEMPORAL")) {
212 var_read_metadata(avctx, name, size);
213 } else if (!strcmp(name, "INTERLACING") || !strcmp(name, "PACKING")) {
214 avio_skip(pb, size); // ignore
215 } else
216 return AVERROR_INVALIDDATA;
217
218 return 0;
219}
220
221static void read_table(AVFormatContext *avctx, AVStream *st,
222 int (*parse)(AVFormatContext *avctx, AVStream *st,
223 const char *name, int size))
224{
225 int count, i;
226 AVIOContext *pb = avctx->pb;
227 avio_skip(pb, 4);
228 count = avio_rb32(pb);
229 avio_skip(pb, 4);
230 for (i = 0; i < count; i++) {
231 char name[17];
232 int size;
233 avio_read(pb, name, 16);
234 name[sizeof(name) - 1] = 0;
235 size = avio_rb32(pb);
236 if (parse(avctx, st, name, size) < 0) {
237 avpriv_request_sample(avctx, "Variable %s", name);
238 avio_skip(pb, size);
239 }
240 }
241}
242
243static void read_index(AVIOContext *pb, AVStream *st)
244{
245 uint64_t timestamp = 0;
246 int i;
247 for (i = 0; i < st->nb_frames; i++) {
248 uint32_t pos = avio_rb32(pb);
249 uint32_t size = avio_rb32(pb);
250 avio_skip(pb, 8);
251 av_add_index_entry(st, pos, timestamp, size, 0, AVINDEX_KEYFRAME);
252 if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
253 timestamp += size / (st->codec->channels * 2);
254 } else {
255 timestamp++;
256 }
257 }
258}
259
260static int mv_read_header(AVFormatContext *avctx)
261{
262 MvContext *mv = avctx->priv_data;
263 AVIOContext *pb = avctx->pb;
264 AVStream *ast = NULL, *vst = NULL; //initialization to suppress warning
265 int version, i;
266
267 avio_skip(pb, 4);
268
269 version = avio_rb16(pb);
270 if (version == 2) {
271 uint64_t timestamp;
272 int v;
273 avio_skip(pb, 22);
274
275 /* allocate audio track first to prevent unnecessary seeking
276 * (audio packet always precede video packet for a given frame) */
277 ast = avformat_new_stream(avctx, NULL);
278 if (!ast)
279 return AVERROR(ENOMEM);
280
281 vst = avformat_new_stream(avctx, NULL);
282 if (!vst)
283 return AVERROR(ENOMEM);
284 avpriv_set_pts_info(vst, 64, 1, 15);
285 vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
286 vst->avg_frame_rate = av_inv_q(vst->time_base);
287 vst->nb_frames = avio_rb32(pb);
288 v = avio_rb32(pb);
289 switch (v) {
290 case 1:
291 vst->codec->codec_id = AV_CODEC_ID_MVC1;
292 break;
293 case 2:
294 vst->codec->pix_fmt = AV_PIX_FMT_ARGB;
295 vst->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
296 break;
297 default:
298 avpriv_request_sample(avctx, "Video compression %i", v);
299 break;
300 }
301 vst->codec->codec_tag = 0;
302 vst->codec->width = avio_rb32(pb);
303 vst->codec->height = avio_rb32(pb);
304 avio_skip(pb, 12);
305
306 ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
307 ast->nb_frames = vst->nb_frames;
308 ast->codec->sample_rate = avio_rb32(pb);
309 avpriv_set_pts_info(ast, 33, 1, ast->codec->sample_rate);
310 if (set_channels(avctx, ast, avio_rb32(pb)) < 0)
311 return AVERROR_INVALIDDATA;
312
313 v = avio_rb32(pb);
314 if (v == AUDIO_FORMAT_SIGNED) {
315 ast->codec->codec_id = AV_CODEC_ID_PCM_S16BE;
316 } else {
317 avpriv_request_sample(avctx, "Audio compression (format %i)", v);
318 }
319
320 avio_skip(pb, 12);
321 var_read_metadata(avctx, "title", 0x80);
322 var_read_metadata(avctx, "comment", 0x100);
323 avio_skip(pb, 0x80);
324
325 timestamp = 0;
326 for (i = 0; i < vst->nb_frames; i++) {
327 uint32_t pos = avio_rb32(pb);
328 uint32_t asize = avio_rb32(pb);
329 uint32_t vsize = avio_rb32(pb);
330 avio_skip(pb, 8);
331 av_add_index_entry(ast, pos, timestamp, asize, 0, AVINDEX_KEYFRAME);
332 av_add_index_entry(vst, pos + asize, i, vsize, 0, AVINDEX_KEYFRAME);
333 timestamp += asize / (ast->codec->channels * 2);
334 }
335 } else if (!version && avio_rb16(pb) == 3) {
336 avio_skip(pb, 4);
337
338 read_table(avctx, NULL, parse_global_var);
339
340 if (mv->nb_audio_tracks > 1) {
341 avpriv_request_sample(avctx, "Multiple audio streams support");
342 return AVERROR_PATCHWELCOME;
343 } else if (mv->nb_audio_tracks) {
344 ast = avformat_new_stream(avctx, NULL);
345 if (!ast)
346 return AVERROR(ENOMEM);
347 ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
348 read_table(avctx, ast, parse_audio_var);
349 if (mv->acompression == 100 &&
350 mv->aformat == AUDIO_FORMAT_SIGNED &&
351 ast->codec->bits_per_coded_sample == 16) {
352 ast->codec->codec_id = AV_CODEC_ID_PCM_S16BE;
353 } else {
354 avpriv_request_sample(avctx,
355 "Audio compression %i (format %i, sr %i)",
356 mv->acompression, mv->aformat,
357 ast->codec->bits_per_coded_sample);
358 ast->codec->codec_id = AV_CODEC_ID_NONE;
359 }
360 if (ast->codec->channels <= 0) {
361 av_log(avctx, AV_LOG_ERROR, "No valid channel count found.\n");
362 return AVERROR_INVALIDDATA;
363 }
364 }
365
366 if (mv->nb_video_tracks > 1) {
367 avpriv_request_sample(avctx, "Multiple video streams support");
368 return AVERROR_PATCHWELCOME;
369 } else if (mv->nb_video_tracks) {
370 vst = avformat_new_stream(avctx, NULL);
371 if (!vst)
372 return AVERROR(ENOMEM);
373 vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
374 read_table(avctx, vst, parse_video_var);
375 }
376
377 if (mv->nb_audio_tracks)
378 read_index(pb, ast);
379
380 if (mv->nb_video_tracks)
381 read_index(pb, vst);
382 } else {
383 avpriv_request_sample(avctx, "Version %i", version);
384 return AVERROR_PATCHWELCOME;
385 }
386
387 return 0;
388}
389
390static int mv_read_packet(AVFormatContext *avctx, AVPacket *pkt)
391{
392 MvContext *mv = avctx->priv_data;
393 AVIOContext *pb = avctx->pb;
394 AVStream *st = avctx->streams[mv->stream_index];
395 const AVIndexEntry *index;
396 int frame = mv->frame[mv->stream_index];
397 int ret;
398 uint64_t pos;
399
400 if (frame < st->nb_index_entries) {
401 index = &st->index_entries[frame];
402 pos = avio_tell(pb);
403 if (index->pos > pos)
404 avio_skip(pb, index->pos - pos);
405 else if (index->pos < pos) {
406 if (!pb->seekable)
407 return AVERROR(EIO);
408 ret = avio_seek(pb, index->pos, SEEK_SET);
409 if (ret < 0)
410 return ret;
411 }
412 ret = av_get_packet(pb, pkt, index->size);
413 if (ret < 0)
414 return ret;
415
416 pkt->stream_index = mv->stream_index;
417 pkt->pts = index->timestamp;
418 pkt->flags |= AV_PKT_FLAG_KEY;
419
420 mv->frame[mv->stream_index]++;
421 mv->eof_count = 0;
422 } else {
423 mv->eof_count++;
424 if (mv->eof_count >= avctx->nb_streams)
425 return AVERROR_EOF;
426
427 // avoid returning 0 without a packet
428 return AVERROR(EAGAIN);
429 }
430
431 mv->stream_index++;
432 if (mv->stream_index >= avctx->nb_streams)
433 mv->stream_index = 0;
434
435 return 0;
436}
437
438static int mv_read_seek(AVFormatContext *avctx, int stream_index,
439 int64_t timestamp, int flags)
440{
441 MvContext *mv = avctx->priv_data;
442 AVStream *st = avctx->streams[stream_index];
443 int frame, i;
444
445 if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE))
446 return AVERROR(ENOSYS);
447
448 if (!avctx->pb->seekable)
449 return AVERROR(EIO);
450
451 frame = av_index_search_timestamp(st, timestamp, flags);
452 if (frame < 0)
453 return AVERROR_INVALIDDATA;
454
455 for (i = 0; i < avctx->nb_streams; i++)
456 mv->frame[i] = frame;
457 return 0;
458}
459
460AVInputFormat ff_mv_demuxer = {
461 .name = "mv",
462 .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Movie"),
463 .priv_data_size = sizeof(MvContext),
464 .read_probe = mv_probe,
465 .read_header = mv_read_header,
466 .read_packet = mv_read_packet,
467 .read_seek = mv_read_seek,
468};