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