Coverage Report

Created: 2026-05-23 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavformat/avs.c
Line
Count
Source
1
/*
2
 * AVS demuxer.
3
 * Copyright (c) 2006  Aurelien Jacobs <aurel@gnuage.org>
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
 * Argonaut Games' Creature Shock demuxer
25
 * @see http://wiki.multimedia.cx/index.php?title=AVS
26
 */
27
28
#include "avformat.h"
29
#include "avio_internal.h"
30
#include "demux.h"
31
#include "voc.h"
32
33
34
typedef struct avs_format {
35
    VocDecContext voc;
36
    AVStream *st_video;
37
    AVStream *st_audio;
38
    int width;
39
    int height;
40
    int bits_per_sample;
41
    int fps;
42
    int nb_frames;
43
    int remaining_frame_size;
44
    int remaining_audio_size;
45
} AvsFormat;
46
47
typedef enum avs_block_type {
48
    AVS_NONE      = 0x00,
49
    AVS_VIDEO     = 0x01,
50
    AVS_AUDIO     = 0x02,
51
    AVS_PALETTE   = 0x03,
52
    AVS_GAME_DATA = 0x04,
53
} AvsBlockType;
54
55
static int avs_probe(const AVProbeData * p)
56
958k
{
57
958k
    const uint8_t *d;
58
59
958k
    d = p->buf;
60
958k
    if (d[0] == 'w' && d[1] == 'W' && d[2] == 0x10 && d[3] == 0)
61
        /* Ensure the buffer probe scores higher than the extension probe.
62
         * This avoids problems with misdetection as AviSynth scripts. */
63
273
        return AVPROBE_SCORE_EXTENSION + 5;
64
65
958k
    return 0;
66
958k
}
67
68
static int avs_read_header(AVFormatContext * s)
69
3.95k
{
70
3.95k
    AvsFormat *avs = s->priv_data;
71
72
3.95k
    s->ctx_flags |= AVFMTCTX_NOHEADER;
73
74
3.95k
    avio_skip(s->pb, 4);
75
3.95k
    avs->width = avio_rl16(s->pb);
76
3.95k
    avs->height = avio_rl16(s->pb);
77
3.95k
    avs->bits_per_sample = avio_rl16(s->pb);
78
3.95k
    avs->fps = avio_rl16(s->pb);
79
3.95k
    avs->nb_frames = avio_rl32(s->pb);
80
3.95k
    avs->remaining_frame_size = 0;
81
3.95k
    avs->remaining_audio_size = 0;
82
83
3.95k
    avs->st_video = avs->st_audio = NULL;
84
85
3.95k
    if (avs->width != 318 || avs->height != 198)
86
3.92k
        av_log(s, AV_LOG_ERROR, "This avs pretend to be %dx%d "
87
3.92k
               "when the avs format is supposed to be 318x198 only.\n",
88
3.92k
               avs->width, avs->height);
89
90
3.95k
    return 0;
91
3.95k
}
92
93
static int
94
avs_read_video_packet(AVFormatContext * s, AVPacket * pkt,
95
                      AvsBlockType type, int sub_type, int size,
96
                      uint8_t * palette, int palette_size)
97
774k
{
98
774k
    AvsFormat *avs = s->priv_data;
99
774k
    int ret;
100
101
774k
    ret = av_new_packet(pkt, size + palette_size);
102
774k
    if (ret < 0)
103
0
        return ret;
104
105
774k
    if (palette_size) {
106
333
        pkt->data[0] = 0x00;
107
333
        pkt->data[1] = 0x03;
108
333
        pkt->data[2] = palette_size & 0xFF;
109
333
        pkt->data[3] = (palette_size >> 8) & 0xFF;
110
333
        memcpy(pkt->data + 4, palette, palette_size - 4);
111
333
    }
112
113
774k
    pkt->data[palette_size + 0] = sub_type;
114
774k
    pkt->data[palette_size + 1] = type;
115
774k
    pkt->data[palette_size + 2] = size & 0xFF;
116
774k
    pkt->data[palette_size + 3] = (size >> 8) & 0xFF;
117
774k
    ret = ffio_read_size(s->pb, pkt->data + palette_size + 4, size - 4) + 4;
118
774k
    if (ret < 0)
119
214
        return ret;
120
121
774k
    pkt->size = ret + palette_size;
122
774k
    pkt->stream_index = avs->st_video->index;
123
774k
    if (sub_type == 0)
124
345k
        pkt->flags |= AV_PKT_FLAG_KEY;
125
126
774k
    return 0;
127
774k
}
128
129
static int avs_read_audio_packet(AVFormatContext * s, AVPacket * pkt)
130
92.6k
{
131
92.6k
    AvsFormat *avs = s->priv_data;
132
92.6k
    int ret;
133
92.6k
    int64_t size;
134
135
92.6k
    size = avio_tell(s->pb);
136
92.6k
    ret = ff_voc_get_packet(s, pkt, avs->st_audio, avs->remaining_audio_size);
137
92.6k
    size = avio_tell(s->pb) - size;
138
92.6k
    avs->remaining_audio_size -= size;
139
140
92.6k
    if (ret == AVERROR(EIO))
141
0
        return 0;    /* this indicate EOS */
142
92.6k
    if (ret < 0)
143
8.59k
        return ret;
144
84.0k
    if (size != (int)size) {
145
128
        av_packet_unref(pkt);
146
128
        return AVERROR(EDOM);
147
128
    }
148
149
83.9k
    pkt->stream_index = avs->st_audio->index;
150
83.9k
    pkt->flags |= AV_PKT_FLAG_KEY;
151
152
83.9k
    return size;
153
84.0k
}
154
155
static int avs_read_packet(AVFormatContext * s, AVPacket * pkt)
156
865k
{
157
865k
    AvsFormat *avs = s->priv_data;
158
865k
    int sub_type = 0, size = 0;
159
865k
    AvsBlockType type = AVS_NONE;
160
865k
    int palette_size = 0;
161
865k
    uint8_t palette[4 + 3 * 256];
162
865k
    int ret;
163
164
865k
    if (avs->remaining_audio_size > 0)
165
89.0k
        if (avs_read_audio_packet(s, pkt) > 0)
166
81.9k
            return 0;
167
168
860k
    while (1) {
169
860k
        if (avs->remaining_frame_size <= 0) {
170
88.2k
            if (!avio_rl16(s->pb))    /* found EOF */
171
2.90k
                return AVERROR_INVALIDDATA;
172
85.3k
            avs->remaining_frame_size = avio_rl16(s->pb) - 4;
173
85.3k
        }
174
175
883k
        while (avs->remaining_frame_size > 0) {
176
806k
            sub_type = avio_r8(s->pb);
177
806k
            type = avio_r8(s->pb);
178
806k
            size = avio_rl16(s->pb);
179
806k
            if (size < 4)
180
2.88k
                return AVERROR_INVALIDDATA;
181
803k
            avs->remaining_frame_size -= size;
182
183
803k
            switch (type) {
184
525
            case AVS_PALETTE:
185
525
                if (size - 4 > sizeof(palette))
186
22
                    return AVERROR_INVALIDDATA;
187
503
                ret = ffio_read_size(s->pb, palette, size - 4);
188
503
                if (ret < 0)
189
32
                    return ret;
190
471
                palette_size = size;
191
471
                break;
192
193
774k
            case AVS_VIDEO:
194
774k
                if (!avs->st_video) {
195
992
                    avs->st_video = avformat_new_stream(s, NULL);
196
992
                    if (!avs->st_video)
197
0
                        return AVERROR(ENOMEM);
198
992
                    avs->st_video->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
199
992
                    avs->st_video->codecpar->codec_id = AV_CODEC_ID_AVS;
200
992
                    avs->st_video->codecpar->width = avs->width;
201
992
                    avs->st_video->codecpar->height = avs->height;
202
992
                    avs->st_video->codecpar->bits_per_coded_sample=avs->bits_per_sample;
203
992
                    avs->st_video->nb_frames = avs->nb_frames;
204
992
#if FF_API_R_FRAME_RATE
205
992
                    avs->st_video->r_frame_rate =
206
992
#endif
207
992
                    avs->st_video->avg_frame_rate = (AVRational){avs->fps, 1};
208
992
                }
209
774k
                return avs_read_video_packet(s, pkt, type, sub_type, size,
210
774k
                                             palette, palette_size);
211
212
3.63k
            case AVS_AUDIO:
213
3.63k
                if (!avs->st_audio) {
214
2.92k
                    avs->st_audio = avformat_new_stream(s, NULL);
215
2.92k
                    if (!avs->st_audio)
216
0
                        return AVERROR(ENOMEM);
217
2.92k
                    avs->st_audio->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
218
2.92k
                }
219
3.63k
                avs->remaining_audio_size = size - 4;
220
3.63k
                size = avs_read_audio_packet(s, pkt);
221
3.63k
                if (size != 0)
222
3.63k
                    return size;
223
0
                break;
224
225
25.3k
            default:
226
25.3k
                avio_skip(s->pb, size - 4);
227
803k
            }
228
803k
        }
229
857k
    }
230
783k
}
231
232
const FFInputFormat ff_avs_demuxer = {
233
    .p.name         = "avs",
234
    .p.long_name    = NULL_IF_CONFIG_SMALL("Argonaut Games Creature Shock"),
235
    .priv_data_size = sizeof(AvsFormat),
236
    .read_probe     = avs_probe,
237
    .read_header    = avs_read_header,
238
    .read_packet    = avs_read_packet,
239
};