Coverage Report

Created: 2026-10-28 08:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavformat/mvdec.c
Line
Count
Source
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/intfloat.h"
30
#include "libavutil/intreadwrite.h"
31
#include "libavutil/mem.h"
32
#include "libavutil/rational.h"
33
34
#include "avformat.h"
35
#include "demux.h"
36
#include "internal.h"
37
38
typedef struct MvContext {
39
    int nb_video_tracks;
40
    int nb_audio_tracks;
41
42
    int eof_count;        ///< number of streams that have finished
43
    int stream_index;     ///< current stream index
44
    int frame[2];         ///< frame nb for current stream
45
46
    int acompression;     ///< compression level for audio stream
47
    int aformat;          ///< audio format
48
} MvContext;
49
50
/* these magic numbers are defined in moviefile.h on Silicon Graphics IRIX */
51
1.71k
#define MOVIE_SOUND  1
52
717
#define MOVIE_SILENT 2
53
54
1.94k
#define AUDIO_FORMAT_SIGNED 401
55
56
static int mv_probe(const AVProbeData *p)
57
963k
{
58
963k
    if (AV_RB32(p->buf) == MKBETAG('M', 'O', 'V', 'I') &&
59
571
        AV_RB16(p->buf + 4) < 3)
60
397
        return AVPROBE_SCORE_MAX;
61
962k
    return 0;
62
963k
}
63
64
static char *var_read_string(AVIOContext *pb, int size)
65
38.5k
{
66
38.5k
    int n;
67
38.5k
    char *str;
68
69
38.5k
    if (size < 0 || size == INT_MAX)
70
3.07k
        return NULL;
71
72
35.4k
    str = av_malloc(size + 1);
73
35.4k
    if (!str)
74
0
        return NULL;
75
35.4k
    n = avio_get_str(pb, size, str, size + 1);
76
35.4k
    if (n < size)
77
14.0k
        avio_skip(pb, size - n);
78
35.4k
    return str;
79
35.4k
}
80
81
static int var_read_int(AVIOContext *pb, int size)
82
17.7k
{
83
17.7k
    int v;
84
17.7k
    char *s = var_read_string(pb, size);
85
17.7k
    if (!s)
86
1.29k
        return 0;
87
16.4k
    v = strtol(s, NULL, 10);
88
16.4k
    av_free(s);
89
16.4k
    return v;
90
17.7k
}
91
92
static AVRational var_read_float(AVIOContext *pb, int size)
93
9.80k
{
94
9.80k
    AVRational v;
95
9.80k
    char *s = var_read_string(pb, size);
96
9.80k
    if (!s)
97
542
        return (AVRational) { 0, 0 };
98
9.26k
    v = av_d2q(av_strtod(s, NULL), INT_MAX);
99
9.26k
    av_free(s);
100
9.26k
    return v;
101
9.80k
}
102
103
static void var_read_metadata(AVFormatContext *avctx, const char *tag, int size)
104
8.20k
{
105
8.20k
    char *value = var_read_string(avctx->pb, size);
106
8.20k
    if (value)
107
7.20k
        av_dict_set(&avctx->metadata, tag, value, AV_DICT_DONT_STRDUP_VAL);
108
8.20k
}
109
110
static int set_channels(AVFormatContext *avctx, AVStream *st, int channels)
111
2.62k
{
112
2.62k
    if (channels <= 0) {
113
584
        av_log(avctx, AV_LOG_ERROR, "Channel count %d invalid.\n", channels);
114
584
        return AVERROR_INVALIDDATA;
115
584
    }
116
2.04k
    av_channel_layout_default(&st->codecpar->ch_layout, channels);
117
2.04k
    return 0;
118
2.62k
}
119
120
/**
121
 * Parse global variable
122
 * @return < 0 if unknown
123
 */
124
static int parse_global_var(AVFormatContext *avctx, AVStream *st,
125
                            const char *name, int size)
126
20.7k
{
127
20.7k
    MvContext *mv = avctx->priv_data;
128
20.7k
    AVIOContext *pb = avctx->pb;
129
20.7k
    if (!strcmp(name, "__NUM_I_TRACKS")) {
130
3.00k
        mv->nb_video_tracks = var_read_int(pb, size);
131
17.6k
    } else if (!strcmp(name, "__NUM_A_TRACKS")) {
132
1.80k
        mv->nb_audio_tracks = var_read_int(pb, size);
133
15.8k
    } else if (!strcmp(name, "COMMENT") || !strcmp(name, "TITLE")) {
134
2.29k
        var_read_metadata(avctx, name, size);
135
13.5k
    } else if (!strcmp(name, "LOOP_MODE") || !strcmp(name, "NUM_LOOPS") ||
136
12.5k
               !strcmp(name, "OPTIMIZED")) {
137
1.82k
        avio_skip(pb, size); // ignore
138
1.82k
    } else
139
11.7k
        return AVERROR_INVALIDDATA;
140
141
8.93k
    return 0;
142
20.7k
}
143
144
/**
145
 * Parse audio variable
146
 * @return < 0 if unknown
147
 */
148
static int parse_audio_var(AVFormatContext *avctx, AVStream *st,
149
                           const char *name, int size)
150
24.7k
{
151
24.7k
    MvContext *mv = avctx->priv_data;
152
24.7k
    AVIOContext *pb = avctx->pb;
153
24.7k
    if (!strcmp(name, "__DIR_COUNT")) {
154
1.75k
        st->nb_frames = var_read_int(pb, size);
155
22.9k
    } else if (!strcmp(name, "AUDIO_FORMAT")) {
156
967
        mv->aformat = var_read_int(pb, size);
157
21.9k
    } else if (!strcmp(name, "COMPRESSION")) {
158
1.22k
        mv->acompression = var_read_int(pb, size);
159
20.7k
    } else if (!strcmp(name, "DEFAULT_VOL")) {
160
960
        var_read_metadata(avctx, name, size);
161
19.8k
    } else if (!strcmp(name, "NUM_CHANNELS")) {
162
1.67k
        return set_channels(avctx, st, var_read_int(pb, size));
163
18.1k
    } else if (!strcmp(name, "SAMPLE_RATE")) {
164
1.01k
        int sample_rate = var_read_int(pb, size);
165
1.01k
        if (sample_rate <= 0)
166
372
            return AVERROR_INVALIDDATA;
167
646
        st->codecpar->sample_rate = sample_rate;
168
646
        avpriv_set_pts_info(st, 33, 1, st->codecpar->sample_rate);
169
17.1k
    } else if (!strcmp(name, "SAMPLE_WIDTH")) {
170
1.13k
        uint64_t bpc = var_read_int(pb, size) * (uint64_t)8;
171
1.13k
        if (bpc > 16)
172
569
            return AVERROR_INVALIDDATA;
173
568
        st->codecpar->bits_per_coded_sample = bpc;
174
568
    } else
175
15.9k
        return AVERROR_INVALIDDATA;
176
177
6.11k
    return 0;
178
24.7k
}
179
180
/**
181
 * Parse video variable
182
 * @return < 0 if unknown
183
 */
184
static int parse_video_var(AVFormatContext *avctx, AVStream *st,
185
                           const char *name, int size)
186
84.9k
{
187
84.9k
    AVIOContext *pb = avctx->pb;
188
84.9k
    if (!strcmp(name, "__DIR_COUNT")) {
189
2.55k
        st->nb_frames = st->duration = var_read_int(pb, size);
190
82.3k
    } else if (!strcmp(name, "COMPRESSION")) {
191
2.79k
        char *str = var_read_string(pb, size);
192
2.79k
        if (!str)
193
240
            return AVERROR_INVALIDDATA;
194
2.55k
        if (!strcmp(str, "1")) {
195
280
            st->codecpar->codec_id = AV_CODEC_ID_MVC1;
196
2.27k
        } else if (!strcmp(str, "2")) {
197
315
            st->codecpar->format = AV_PIX_FMT_ABGR;
198
315
            st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO;
199
1.96k
        } else if (!strcmp(str, "3")) {
200
201
            st->codecpar->codec_id = AV_CODEC_ID_SGIRLE;
201
1.76k
        } else if (!strcmp(str, "10")) {
202
212
            st->codecpar->codec_id = AV_CODEC_ID_MJPEG;
203
1.54k
        } else if (!strcmp(str, "MVC2")) {
204
720
            st->codecpar->codec_id = AV_CODEC_ID_MVC2;
205
829
        } else {
206
829
            avpriv_request_sample(avctx, "Video compression %s", str);
207
829
        }
208
2.55k
        av_free(str);
209
79.5k
    } else if (!strcmp(name, "FPS")) {
210
7.97k
        AVRational fps = var_read_float(pb, size);
211
7.97k
        avpriv_set_pts_info(st, 64, fps.den, fps.num);
212
7.97k
        st->avg_frame_rate = fps;
213
71.5k
    } else if (!strcmp(name, "HEIGHT")) {
214
1.14k
        st->codecpar->height = var_read_int(pb, size);
215
70.4k
    } else if (!strcmp(name, "PIXEL_ASPECT")) {
216
1.83k
        st->sample_aspect_ratio = var_read_float(pb, size);
217
1.83k
        av_reduce(&st->sample_aspect_ratio.num, &st->sample_aspect_ratio.den,
218
1.83k
                  st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
219
1.83k
                  INT_MAX);
220
68.6k
    } else if (!strcmp(name, "WIDTH")) {
221
404
        st->codecpar->width = var_read_int(pb, size);
222
68.2k
    } else if (!strcmp(name, "ORIENTATION")) {
223
1.08k
        if (var_read_int(pb, size) == 1101) {
224
575
            if (!st->codecpar->extradata) {
225
81
                st->codecpar->extradata = av_strdup("BottomUp");
226
81
                if (!st->codecpar->extradata)
227
0
                    return AVERROR(ENOMEM);
228
81
                st->codecpar->extradata_size = 9;
229
81
            }
230
575
        }
231
67.1k
    } else if (!strcmp(name, "Q_SPATIAL") || !strcmp(name, "Q_TEMPORAL")) {
232
2.57k
        var_read_metadata(avctx, name, size);
233
64.5k
    } else if (!strcmp(name, "INTERLACING") || !strcmp(name, "PACKING")) {
234
507
        avio_skip(pb, size); // ignore
235
507
    } else
236
64.0k
        return AVERROR_INVALIDDATA;
237
238
20.6k
    return 0;
239
84.9k
}
240
241
static int read_table(AVFormatContext *avctx, AVStream *st,
242
                       int (*parse)(AVFormatContext *avctx, AVStream *st,
243
                                    const char *name, int size))
244
7.39k
{
245
7.39k
    unsigned count;
246
7.39k
    int i;
247
248
7.39k
    AVIOContext *pb = avctx->pb;
249
7.39k
    avio_skip(pb, 4);
250
7.39k
    count = avio_rb32(pb);
251
7.39k
    avio_skip(pb, 4);
252
137k
    for (i = 0; i < count; i++) {
253
132k
        char name[17];
254
132k
        int size;
255
256
132k
        if (avio_feof(pb))
257
1.38k
            return AVERROR_EOF;
258
259
130k
        if (avio_read(pb, name, 16) != 16)
260
257
            return AVERROR_INVALIDDATA;
261
130k
        name[sizeof(name) - 1] = 0;
262
130k
        size = avio_rb32(pb);
263
130k
        if (size < 0) {
264
82
            av_log(avctx, AV_LOG_ERROR, "entry size %d is invalid\n", size);
265
82
            return AVERROR_INVALIDDATA;
266
82
        }
267
130k
        if (parse(avctx, st, name, size) < 0) {
268
93.5k
            avpriv_request_sample(avctx, "Variable %s", name);
269
93.5k
            avio_skip(pb, size);
270
93.5k
        }
271
130k
    }
272
5.67k
    return 0;
273
7.39k
}
274
275
static void read_index(AVIOContext *pb, AVStream *st)
276
2.17k
{
277
2.17k
    uint64_t timestamp = 0;
278
2.17k
    int i;
279
1.81M
    for (i = 0; i < st->nb_frames; i++) {
280
1.81M
        uint32_t pos  = avio_rb32(pb);
281
1.81M
        uint32_t size = avio_rb32(pb);
282
1.81M
        avio_skip(pb, 8);
283
1.81M
        if (avio_feof(pb))
284
1.15k
            return ;
285
1.81M
        av_add_index_entry(st, pos, timestamp, size, 0, AVINDEX_KEYFRAME);
286
1.81M
        if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
287
43.8k
            timestamp += size / (st->codecpar->ch_layout.nb_channels * 2LL);
288
1.77M
        } else {
289
1.77M
            timestamp++;
290
1.77M
        }
291
1.81M
    }
292
2.17k
}
293
294
static int mv_read_header(AVFormatContext *avctx)
295
5.74k
{
296
5.74k
    MvContext *mv = avctx->priv_data;
297
5.74k
    AVIOContext *pb = avctx->pb;
298
5.74k
    AVStream *ast = NULL, *vst = NULL; //initialization to suppress warning
299
5.74k
    int version, i;
300
5.74k
    int ret;
301
302
5.74k
    avio_skip(pb, 4);
303
304
5.74k
    version = avio_rb16(pb);
305
5.74k
    if (version == 2) {
306
1.71k
        uint64_t timestamp;
307
1.71k
        int v;
308
1.71k
        uint32_t bytes_per_sample;
309
1.71k
        AVRational fps;
310
311
1.71k
        avio_skip(pb, 10);
312
313
1.71k
        fps = av_d2q(av_int2double(avio_rb64(pb)), INT_MAX);
314
315
        /* allocate audio track first to prevent unnecessary seeking
316
         * (audio packet always precede video packet for a given frame) */
317
1.71k
        v = avio_rb16(pb);
318
1.71k
        if (v == MOVIE_SOUND) {
319
            /* movie has sound so allocate an audio stream */
320
995
            ast = avformat_new_stream(avctx, NULL);
321
995
            if (!ast)
322
0
                return AVERROR(ENOMEM);
323
995
        } else if (v != MOVIE_SILENT)
324
407
            return AVERROR_INVALIDDATA;
325
326
1.30k
        avio_skip(pb, 2);
327
328
1.30k
        vst = avformat_new_stream(avctx, NULL);
329
1.30k
        if (!vst)
330
0
            return AVERROR(ENOMEM);
331
1.30k
        avpriv_set_pts_info(vst, 64, fps.den, fps.num);
332
1.30k
        vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
333
1.30k
        vst->avg_frame_rate = fps;
334
1.30k
        vst->duration = vst->nb_frames = avio_rb32(pb);
335
1.30k
        v = avio_rb32(pb);
336
1.30k
        switch (v) {
337
68
        case 1:
338
68
            vst->codecpar->codec_id = AV_CODEC_ID_MVC1;
339
68
            break;
340
136
        case 2:
341
136
            vst->codecpar->format = AV_PIX_FMT_ARGB;
342
136
            vst->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO;
343
136
            break;
344
1.10k
        default:
345
1.10k
            avpriv_request_sample(avctx, "Video compression %i", v);
346
1.10k
            break;
347
1.30k
        }
348
1.30k
        vst->codecpar->codec_tag = 0;
349
1.30k
        vst->codecpar->width     = avio_rb32(pb);
350
1.30k
        vst->codecpar->height    = avio_rb32(pb);
351
1.30k
        avio_skip(pb, 12);
352
353
1.30k
        if (ast) {
354
995
            ast->codecpar->codec_type  = AVMEDIA_TYPE_AUDIO;
355
995
            ast->nb_frames = vst->nb_frames;
356
995
            ast->codecpar->sample_rate = avio_rb32(pb);
357
995
            if (ast->codecpar->sample_rate <= 0) {
358
42
                av_log(avctx, AV_LOG_ERROR, "Invalid sample rate %d\n", ast->codecpar->sample_rate);
359
42
                return AVERROR_INVALIDDATA;
360
42
            }
361
953
            avpriv_set_pts_info(ast, 33, 1, ast->codecpar->sample_rate);
362
363
953
            bytes_per_sample = avio_rb32(pb);
364
365
953
            v = avio_rb32(pb);
366
953
            if (v == AUDIO_FORMAT_SIGNED) {
367
543
                switch (bytes_per_sample) {
368
525
                case 1:
369
525
                    ast->codecpar->codec_id = AV_CODEC_ID_PCM_S8;
370
525
                    break;
371
8
                case 2:
372
8
                    ast->codecpar->codec_id = AV_CODEC_ID_PCM_S16BE;
373
8
                    break;
374
10
                default:
375
10
                    avpriv_request_sample(avctx, "Audio sample size %i bytes", bytes_per_sample);
376
10
                    break;
377
543
                }
378
543
            } else {
379
410
                avpriv_request_sample(avctx, "Audio compression (format %i)", v);
380
410
            }
381
382
953
            if (bytes_per_sample == 0)
383
3
                return AVERROR_INVALIDDATA;
384
385
950
            if (set_channels(avctx, ast, avio_rb32(pb)) < 0)
386
72
                return AVERROR_INVALIDDATA;
387
388
878
            avio_skip(pb, 8);
389
878
        } else
390
310
            avio_skip(pb, 24); /* skip meaningless audio metadata */
391
392
1.18k
        var_read_metadata(avctx, "title", 0x80);
393
1.18k
        var_read_metadata(avctx, "comment", 0x100);
394
1.18k
        avio_skip(pb, 0x80);
395
396
1.18k
        timestamp = 0;
397
1.16M
        for (i = 0; i < vst->nb_frames; i++) {
398
1.16M
            uint32_t pos   = avio_rb32(pb);
399
1.16M
            uint32_t asize = avio_rb32(pb);
400
1.16M
            uint32_t vsize = avio_rb32(pb);
401
1.16M
            if (avio_feof(pb))
402
121
                return AVERROR_INVALIDDATA;
403
1.16M
            avio_skip(pb, 8);
404
1.16M
            if (ast) {
405
1.16M
                av_add_index_entry(ast, pos, timestamp, asize, 0, AVINDEX_KEYFRAME);
406
1.16M
                timestamp += asize / (ast->codecpar->ch_layout.nb_channels * (uint64_t)bytes_per_sample);
407
1.16M
            }
408
1.16M
            av_add_index_entry(vst, pos + asize, i, vsize, 0, AVINDEX_KEYFRAME);
409
1.16M
        }
410
4.03k
    } else if (!version && avio_rb16(pb) == 3) {
411
3.90k
        avio_skip(pb, 4);
412
413
3.90k
        if ((ret = read_table(avctx, NULL, parse_global_var)) < 0)
414
516
            return ret;
415
416
3.38k
        if (mv->nb_audio_tracks < 0  || mv->nb_video_tracks < 0 ||
417
3.36k
           (mv->nb_audio_tracks == 0 && mv->nb_video_tracks == 0)) {
418
106
            av_log(avctx, AV_LOG_ERROR, "Stream count is invalid.\n");
419
106
            return AVERROR_INVALIDDATA;
420
106
        }
421
422
3.28k
        if (mv->nb_audio_tracks > 1) {
423
34
            avpriv_request_sample(avctx, "Multiple audio streams support");
424
34
            return AVERROR_PATCHWELCOME;
425
3.24k
        } else if (mv->nb_audio_tracks) {
426
1.22k
            ast = avformat_new_stream(avctx, NULL);
427
1.22k
            if (!ast)
428
0
                return AVERROR(ENOMEM);
429
1.22k
            ast->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
430
1.22k
            if ((ret = read_table(avctx, ast, parse_audio_var)) < 0)
431
458
                return ret;
432
767
            if (mv->acompression == 100 &&
433
226
                mv->aformat == AUDIO_FORMAT_SIGNED &&
434
178
                ast->codecpar->bits_per_coded_sample == 16) {
435
158
                ast->codecpar->codec_id = AV_CODEC_ID_PCM_S16BE;
436
609
            } else {
437
609
                avpriv_request_sample(avctx,
438
609
                                      "Audio compression %i (format %i, sr %i)",
439
609
                                      mv->acompression, mv->aformat,
440
609
                                      ast->codecpar->bits_per_coded_sample);
441
609
                ast->codecpar->codec_id = AV_CODEC_ID_NONE;
442
609
            }
443
767
            if (ast->codecpar->ch_layout.nb_channels <= 0) {
444
76
                av_log(avctx, AV_LOG_ERROR, "No valid channel count found.\n");
445
76
                return AVERROR_INVALIDDATA;
446
76
            }
447
767
        }
448
449
2.71k
        if (mv->nb_video_tracks > 1) {
450
34
            avpriv_request_sample(avctx, "Multiple video streams support");
451
34
            return AVERROR_PATCHWELCOME;
452
2.68k
        } else if (mv->nb_video_tracks) {
453
2.26k
            vst = avformat_new_stream(avctx, NULL);
454
2.26k
            if (!vst)
455
0
                return AVERROR(ENOMEM);
456
2.26k
            vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
457
2.26k
            if ((ret = read_table(avctx, vst, parse_video_var))<0)
458
745
                return ret;
459
2.26k
        }
460
461
1.93k
        if (mv->nb_audio_tracks)
462
657
            read_index(pb, ast);
463
464
1.93k
        if (mv->nb_video_tracks)
465
1.52k
            read_index(pb, vst);
466
1.93k
    } else {
467
126
        avpriv_request_sample(avctx, "Version %i", version);
468
126
        return AVERROR_PATCHWELCOME;
469
126
    }
470
471
3.00k
    return 0;
472
5.74k
}
473
474
static int mv_read_packet(AVFormatContext *avctx, AVPacket *pkt)
475
399k
{
476
399k
    MvContext *mv = avctx->priv_data;
477
399k
    AVIOContext *pb = avctx->pb;
478
399k
    AVStream *st = avctx->streams[mv->stream_index];
479
399k
    FFStream *const sti = ffstream(st);
480
399k
    const AVIndexEntry *index;
481
399k
    int frame = mv->frame[mv->stream_index];
482
399k
    int64_t ret;
483
399k
    uint64_t pos;
484
485
399k
    if (frame < sti->nb_index_entries) {
486
396k
        index = &sti->index_entries[frame];
487
396k
        pos   = avio_tell(pb);
488
396k
        if (index->pos > pos)
489
14.3k
            avio_skip(pb, index->pos - pos);
490
381k
        else if (index->pos < pos) {
491
11.9k
            if (!(pb->seekable & AVIO_SEEKABLE_NORMAL))
492
342
                return AVERROR(ENOSYS);
493
11.6k
            ret = avio_seek(pb, index->pos, SEEK_SET);
494
11.6k
            if (ret < 0)
495
19
                return ret;
496
11.6k
        }
497
395k
        ret = av_get_packet(pb, pkt, index->size);
498
395k
        if (ret < 0)
499
1.99k
            return ret;
500
501
393k
        pkt->stream_index = mv->stream_index;
502
393k
        pkt->pts          = index->timestamp;
503
393k
        pkt->flags       |= AV_PKT_FLAG_KEY;
504
505
393k
        mv->frame[mv->stream_index]++;
506
393k
        mv->eof_count = 0;
507
393k
    } else {
508
3.62k
        mv->eof_count++;
509
3.62k
        if (mv->eof_count >= avctx->nb_streams)
510
3.18k
            return AVERROR_EOF;
511
512
        // avoid returning 0 without a packet
513
438
        return AVERROR(EAGAIN);
514
3.62k
    }
515
516
393k
    mv->stream_index++;
517
393k
    if (mv->stream_index >= avctx->nb_streams)
518
386k
        mv->stream_index = 0;
519
520
393k
    return 0;
521
399k
}
522
523
static int mv_read_seek(AVFormatContext *avctx, int stream_index,
524
                        int64_t timestamp, int flags)
525
0
{
526
0
    MvContext *mv = avctx->priv_data;
527
0
    AVStream *st = avctx->streams[stream_index];
528
0
    int frame, i;
529
530
0
    if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE))
531
0
        return AVERROR(ENOSYS);
532
533
0
    if (!(avctx->pb->seekable & AVIO_SEEKABLE_NORMAL))
534
0
        return AVERROR(ENOSYS);
535
536
0
    frame = av_index_search_timestamp(st, timestamp, flags);
537
0
    if (frame < 0)
538
0
        return AVERROR_INVALIDDATA;
539
540
0
    for (i = 0; i < avctx->nb_streams; i++)
541
0
        mv->frame[i] = frame;
542
0
    return 0;
543
0
}
544
545
const FFInputFormat ff_mv_demuxer = {
546
    .p.name         = "mv",
547
    .p.long_name    = NULL_IF_CONFIG_SMALL("Silicon Graphics Movie"),
548
    .priv_data_size = sizeof(MvContext),
549
    .read_probe     = mv_probe,
550
    .read_header    = mv_read_header,
551
    .read_packet    = mv_read_packet,
552
    .read_seek      = mv_read_seek,
553
};