FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/avs.c
Date: 2024-04-17 23:49:55
Exec Total Coverage
Lines: 100 114 87.7%
Functions: 5 5 100.0%
Branches: 40 56 71.4%

Line Branch Exec 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 "demux.h"
30 #include "voc.h"
31
32
33 typedef struct avs_format {
34 VocDecContext voc;
35 AVStream *st_video;
36 AVStream *st_audio;
37 int width;
38 int height;
39 int bits_per_sample;
40 int fps;
41 int nb_frames;
42 int remaining_frame_size;
43 int remaining_audio_size;
44 } AvsFormat;
45
46 typedef enum avs_block_type {
47 AVS_NONE = 0x00,
48 AVS_VIDEO = 0x01,
49 AVS_AUDIO = 0x02,
50 AVS_PALETTE = 0x03,
51 AVS_GAME_DATA = 0x04,
52 } AvsBlockType;
53
54 7125 static int avs_probe(const AVProbeData * p)
55 {
56 const uint8_t *d;
57
58 7125 d = p->buf;
59
6/8
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 7090 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 34 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
7125 if (d[0] == 'w' && d[1] == 'W' && d[2] == 0x10 && d[3] == 0)
60 /* Ensure the buffer probe scores higher than the extension probe.
61 * This avoids problems with misdetection as AviSynth scripts. */
62 1 return AVPROBE_SCORE_EXTENSION + 5;
63
64 7124 return 0;
65 }
66
67 1 static int avs_read_header(AVFormatContext * s)
68 {
69 1 AvsFormat *avs = s->priv_data;
70
71 1 s->ctx_flags |= AVFMTCTX_NOHEADER;
72
73 1 avio_skip(s->pb, 4);
74 1 avs->width = avio_rl16(s->pb);
75 1 avs->height = avio_rl16(s->pb);
76 1 avs->bits_per_sample = avio_rl16(s->pb);
77 1 avs->fps = avio_rl16(s->pb);
78 1 avs->nb_frames = avio_rl32(s->pb);
79 1 avs->remaining_frame_size = 0;
80 1 avs->remaining_audio_size = 0;
81
82 1 avs->st_video = avs->st_audio = NULL;
83
84
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (avs->width != 318 || avs->height != 198)
85 av_log(s, AV_LOG_ERROR, "This avs pretend to be %dx%d "
86 "when the avs format is supposed to be 318x198 only.\n",
87 avs->width, avs->height);
88
89 1 return 0;
90 }
91
92 static int
93 56 avs_read_video_packet(AVFormatContext * s, AVPacket * pkt,
94 AvsBlockType type, int sub_type, int size,
95 uint8_t * palette, int palette_size)
96 {
97 56 AvsFormat *avs = s->priv_data;
98 int ret;
99
100 56 ret = av_new_packet(pkt, size + palette_size);
101
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (ret < 0)
102 return ret;
103
104
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 55 times.
56 if (palette_size) {
105 1 pkt->data[0] = 0x00;
106 1 pkt->data[1] = 0x03;
107 1 pkt->data[2] = palette_size & 0xFF;
108 1 pkt->data[3] = (palette_size >> 8) & 0xFF;
109 1 memcpy(pkt->data + 4, palette, palette_size - 4);
110 }
111
112 56 pkt->data[palette_size + 0] = sub_type;
113 56 pkt->data[palette_size + 1] = type;
114 56 pkt->data[palette_size + 2] = size & 0xFF;
115 56 pkt->data[palette_size + 3] = (size >> 8) & 0xFF;
116 56 ret = avio_read(s->pb, pkt->data + palette_size + 4, size - 4) + 4;
117
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (ret < size) {
118 return AVERROR(EIO);
119 }
120
121 56 pkt->size = ret + palette_size;
122 56 pkt->stream_index = avs->st_video->index;
123
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 51 times.
56 if (sub_type == 0)
124 5 pkt->flags |= AV_PKT_FLAG_KEY;
125
126 56 return 0;
127 }
128
129 37 static int avs_read_audio_packet(AVFormatContext * s, AVPacket * pkt)
130 {
131 37 AvsFormat *avs = s->priv_data;
132 int ret;
133 int64_t size;
134
135 37 size = avio_tell(s->pb);
136 37 ret = ff_voc_get_packet(s, pkt, avs->st_audio, avs->remaining_audio_size);
137 37 size = avio_tell(s->pb) - size;
138 37 avs->remaining_audio_size -= size;
139
140
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 if (ret == AVERROR(EIO))
141 return 0; /* this indicate EOS */
142
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 36 times.
37 if (ret < 0)
143 1 return ret;
144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 if (size != (int)size) {
145 av_packet_unref(pkt);
146 return AVERROR(EDOM);
147 }
148
149 36 pkt->stream_index = avs->st_audio->index;
150 36 pkt->flags |= AV_PKT_FLAG_KEY;
151
152 36 return size;
153 }
154
155 94 static int avs_read_packet(AVFormatContext * s, AVPacket * pkt)
156 {
157 94 AvsFormat *avs = s->priv_data;
158 94 int sub_type = 0, size = 0;
159 94 AvsBlockType type = AVS_NONE;
160 94 int palette_size = 0;
161 uint8_t palette[4 + 3 * 256];
162 int ret;
163
164
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 10 times.
94 if (avs->remaining_audio_size > 0)
165
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 9 times.
10 if (avs_read_audio_packet(s, pkt) > 0)
166 9 return 0;
167
168 while (1) {
169
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 27 times.
85 if (avs->remaining_frame_size <= 0) {
170
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 56 times.
58 if (!avio_rl16(s->pb)) /* found EOF */
171 2 return AVERROR(EIO);
172 56 avs->remaining_frame_size = avio_rl16(s->pb) - 4;
173 }
174
175
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
84 while (avs->remaining_frame_size > 0) {
176 84 sub_type = avio_r8(s->pb);
177 84 type = avio_r8(s->pb);
178 84 size = avio_rl16(s->pb);
179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 if (size < 4)
180 return AVERROR_INVALIDDATA;
181 84 avs->remaining_frame_size -= size;
182
183
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 56 times.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
84 switch (type) {
184 1 case AVS_PALETTE:
185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (size - 4 > sizeof(palette))
186 return AVERROR_INVALIDDATA;
187 1 ret = avio_read(s->pb, palette, size - 4);
188
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < size - 4)
189 return AVERROR(EIO);
190 1 palette_size = size;
191 1 break;
192
193 56 case AVS_VIDEO:
194
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 55 times.
56 if (!avs->st_video) {
195 1 avs->st_video = avformat_new_stream(s, NULL);
196
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!avs->st_video)
197 return AVERROR(ENOMEM);
198 1 avs->st_video->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
199 1 avs->st_video->codecpar->codec_id = AV_CODEC_ID_AVS;
200 1 avs->st_video->codecpar->width = avs->width;
201 1 avs->st_video->codecpar->height = avs->height;
202 1 avs->st_video->codecpar->bits_per_coded_sample=avs->bits_per_sample;
203 1 avs->st_video->nb_frames = avs->nb_frames;
204 #if FF_API_R_FRAME_RATE
205 1 avs->st_video->r_frame_rate =
206 #endif
207 1 avs->st_video->avg_frame_rate = (AVRational){avs->fps, 1};
208 }
209 56 return avs_read_video_packet(s, pkt, type, sub_type, size,
210 palette, palette_size);
211
212 27 case AVS_AUDIO:
213
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 26 times.
27 if (!avs->st_audio) {
214 1 avs->st_audio = avformat_new_stream(s, NULL);
215
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!avs->st_audio)
216 return AVERROR(ENOMEM);
217 1 avs->st_audio->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
218 }
219 27 avs->remaining_audio_size = size - 4;
220 27 size = avs_read_audio_packet(s, pkt);
221
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 if (size != 0)
222 27 return size;
223 break;
224
225 default:
226 avio_skip(s->pb, size - 4);
227 }
228 }
229 }
230 }
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 };
240