FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/moflex.c
Date: 2022-11-26 13:19:19
Exec Total Coverage
Lines: 5 221 2.3%
Branches: 1 125 0.8%

Line Branch Exec Source
1 /*
2 * MOFLEX demuxer
3 * Copyright (c) 2015-2016 Florian Nouwt
4 * Copyright (c) 2017 Adib Surani
5 * Copyright (c) 2020 Paul B Mahol
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include "libavcodec/bytestream.h"
25
26 #include "avformat.h"
27 #include "internal.h"
28
29 typedef struct BitReader {
30 unsigned last;
31 unsigned pos;
32 } BitReader;
33
34 typedef struct MOFLEXDemuxContext {
35 unsigned size;
36 int64_t pos;
37 int64_t ts;
38 int flags;
39 int in_block;
40
41 BitReader br;
42 } MOFLEXDemuxContext;
43
44 static int pop(BitReader *br, AVIOContext *pb)
45 {
46 if (avio_feof(pb))
47 return AVERROR_EOF;
48
49 if ((br->pos & 7) == 0)
50 br->last = (unsigned)avio_r8(pb) << 24U;
51 else
52 br->last <<= 1;
53
54 br->pos++;
55 return !!(br->last & 0x80000000);
56 }
57
58 static int pop_int(BitReader *br, AVIOContext *pb, int n)
59 {
60 int value = 0;
61
62 for (int i = 0; i < n; i++) {
63 int ret = pop(br, pb);
64
65 if (ret < 0)
66 return ret;
67 if (ret > INT_MAX - value - value)
68 return AVERROR_INVALIDDATA;
69 value = 2 * value + ret;
70 }
71
72 return value;
73 }
74
75 static int pop_length(BitReader *br, AVIOContext *pb)
76 {
77 int ret, n = 1;
78
79 while ((ret = pop(br, pb)) == 0)
80 n++;
81
82 if (ret < 0)
83 return ret;
84 return n;
85 }
86
87 static int read_var_byte(AVFormatContext *s, unsigned *out)
88 {
89 AVIOContext *pb = s->pb;
90 unsigned value = 0, data;
91
92 data = avio_r8(pb);
93 if (!(data & 0x80)) {
94 *out = data;
95 return 0;
96 }
97
98 value = (data & 0x7F) << 7;
99 data = avio_r8(pb);
100 if (!(data & 0x80)) {
101 value |= data;
102 *out = value;
103 return 0;
104 }
105
106 value = ((data & 0x7F) | value) << 7;
107 data = avio_r8(pb);
108 if (!(data & 0x80)) {
109 value |= data;
110 *out = value;
111 return 0;
112 }
113
114 value = (((data & 0x7F) | value) << 7) | avio_r8(pb);
115 *out = value;
116
117 return 0;
118 }
119
120 6780 static int moflex_probe(const AVProbeData *p)
121 {
122 GetByteContext gb;
123 6780 int score = 0;
124
125 6780 bytestream2_init(&gb, p->buf, p->buf_size);
126
127
1/2
✓ Branch 1 taken 6780 times.
✗ Branch 2 not taken.
6780 if (bytestream2_get_be16(&gb) != 0x4C32)
128 6780 return 0;
129 score += 10;
130
131 bytestream2_skip(&gb, 10);
132 if (bytestream2_get_be16(&gb) == 0)
133 return 0;
134 score += 5;
135
136 while (bytestream2_get_bytes_left(&gb) > 0) {
137 int type = bytestream2_get_byte(&gb);
138 int size = bytestream2_get_byte(&gb);
139
140 if (type == 0) {
141 score += 5 * (size == 0);
142 break;
143 }
144 if ((type == 1 && size == 12) ||
145 (type == 2 && size == 6) ||
146 (type == 3 && size == 13) ||
147 (type == 4 && size == 2))
148 score += 20;
149 bytestream2_skip(&gb, size);
150 }
151
152 return FFMIN(AVPROBE_SCORE_MAX, score);
153 }
154
155 static int moflex_read_sync(AVFormatContext *s)
156 {
157 MOFLEXDemuxContext *m = s->priv_data;
158 AVIOContext *pb = s->pb;
159
160 if (avio_rb16(pb) != 0x4C32) {
161 if (avio_feof(pb))
162 return AVERROR_EOF;
163 avio_seek(pb, -2, SEEK_CUR);
164 return 1;
165 }
166
167 avio_skip(pb, 2);
168 m->ts = avio_rb64(pb);
169 m->size = avio_rb16(pb) + 1;
170
171 while (!avio_feof(pb)) {
172 unsigned type, ssize, codec_id = 0;
173 unsigned codec_type, width = 0, height = 0, sample_rate = 0, channels = 0;
174 int stream_index = -1;
175 AVRational tb = av_make_q(0, 1);
176
177 read_var_byte(s, &type);
178 read_var_byte(s, &ssize);
179
180 switch (type) {
181 case 0:
182 if (ssize > 0)
183 avio_skip(pb, ssize);
184 return 0;
185 case 2:
186 codec_type = AVMEDIA_TYPE_AUDIO;
187 stream_index = avio_r8(pb);
188 codec_id = avio_r8(pb);
189 switch (codec_id) {
190 case 0: codec_id = AV_CODEC_ID_FASTAUDIO; break;
191 case 1: codec_id = AV_CODEC_ID_ADPCM_IMA_MOFLEX; break;
192 case 2: codec_id = AV_CODEC_ID_PCM_S16LE; break;
193 default:
194 av_log(s, AV_LOG_ERROR, "Unsupported audio codec: %d\n", codec_id);
195 return AVERROR_PATCHWELCOME;
196 }
197 sample_rate = avio_rb24(pb) + 1;
198 tb = av_make_q(1, sample_rate);
199 channels = avio_r8(pb) + 1;
200 break;
201 case 1:
202 case 3:
203 codec_type = AVMEDIA_TYPE_VIDEO;
204 stream_index = avio_r8(pb);
205 codec_id = avio_r8(pb);
206 switch (codec_id) {
207 case 0: codec_id = AV_CODEC_ID_MOBICLIP; break;
208 default:
209 av_log(s, AV_LOG_ERROR, "Unsupported video codec: %d\n", codec_id);
210 return AVERROR_PATCHWELCOME;
211 }
212 tb.den = avio_rb16(pb);
213 tb.num = avio_rb16(pb);
214 width = avio_rb16(pb);
215 height = avio_rb16(pb);
216 avio_skip(pb, type == 3 ? 3 : 2);
217 break;
218 case 4:
219 codec_type = AVMEDIA_TYPE_DATA;
220 stream_index = avio_r8(pb);
221 avio_skip(pb, 1);
222 break;
223 }
224
225 if (stream_index == s->nb_streams) {
226 AVStream *st = avformat_new_stream(s, NULL);
227
228 if (!st)
229 return AVERROR(ENOMEM);
230
231 st->codecpar->codec_type = codec_type;
232 st->codecpar->codec_id = codec_id;
233 st->codecpar->width = width;
234 st->codecpar->height = height;
235 st->codecpar->sample_rate= sample_rate;
236 st->codecpar->ch_layout.nb_channels = channels;
237 st->priv_data = av_packet_alloc();
238 if (!st->priv_data)
239 return AVERROR(ENOMEM);
240
241 if (tb.num)
242 avpriv_set_pts_info(st, 63, tb.num, tb.den);
243 }
244 }
245
246 return 0;
247 }
248
249 static int moflex_read_header(AVFormatContext *s)
250 {
251 int ret;
252
253 ret = moflex_read_sync(s);
254 if (ret < 0)
255 return ret;
256
257 s->ctx_flags |= AVFMTCTX_NOHEADER;
258 avio_seek(s->pb, 0, SEEK_SET);
259
260 return 0;
261 }
262
263 static int moflex_read_packet(AVFormatContext *s, AVPacket *pkt)
264 {
265 MOFLEXDemuxContext *m = s->priv_data;
266 AVIOContext *pb = s->pb;
267 BitReader *br = &m->br;
268 int ret;
269
270 while (!avio_feof(pb)) {
271 if (!m->in_block) {
272 m->pos = avio_tell(pb);
273
274 ret = moflex_read_sync(s);
275 if (ret < 0)
276 return ret;
277
278 m->flags = avio_r8(pb);
279 if (m->flags & 2)
280 avio_skip(pb, 2);
281 }
282
283 while ((avio_tell(pb) < m->pos + m->size) && !avio_feof(pb) && avio_r8(pb)) {
284 int stream_index, bits, pkt_size, endframe;
285 AVPacket *packet;
286
287 m->in_block = 1;
288
289 avio_seek(pb, -1, SEEK_CUR);
290 br->pos = br->last = 0;
291
292 bits = pop_length(br, pb);
293 if (bits < 0)
294 return bits;
295 stream_index = pop_int(br, pb, bits);
296 if (stream_index < 0)
297 return stream_index;
298 if (stream_index >= s->nb_streams)
299 return AVERROR_INVALIDDATA;
300
301 endframe = pop(br, pb);
302 if (endframe < 0)
303 return endframe;
304 if (endframe) {
305 bits = pop_length(br, pb);
306 if (bits < 0)
307 return bits;
308 pop_int(br, pb, bits);
309 pop(br, pb);
310 bits = pop_length(br, pb);
311 if (bits < 0)
312 return bits;
313 pop_int(br, pb, bits * 2 + 26);
314 }
315
316 pkt_size = pop_int(br, pb, 13) + 1;
317 if (pkt_size > m->size)
318 return AVERROR_INVALIDDATA;
319 packet = s->streams[stream_index]->priv_data;
320 if (!packet) {
321 avio_skip(pb, pkt_size);
322 continue;
323 }
324
325 ret = av_append_packet(pb, packet, pkt_size);
326 if (ret < 0)
327 return ret;
328 if (endframe && packet->size > 0) {
329 av_packet_move_ref(pkt, packet);
330 pkt->pos = m->pos;
331 pkt->stream_index = stream_index;
332 if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
333 pkt->duration = 1;
334 if (pkt->data[0] & 0x80)
335 pkt->flags |= AV_PKT_FLAG_KEY;
336 } else {
337 pkt->flags |= AV_PKT_FLAG_KEY;
338 }
339 return ret;
340 }
341 }
342
343 m->in_block = 0;
344
345 if (m->flags % 2 == 0) {
346 if (m->size <= 0)
347 return AVERROR_INVALIDDATA;
348 avio_seek(pb, m->pos + m->size, SEEK_SET);
349 }
350 }
351
352 return AVERROR_EOF;
353 }
354
355 static int moflex_read_seek(AVFormatContext *s, int stream_index,
356 int64_t pts, int flags)
357 {
358 MOFLEXDemuxContext *m = s->priv_data;
359
360 m->in_block = 0;
361
362 return -1;
363 }
364
365 static int moflex_read_close(AVFormatContext *s)
366 {
367 for (int i = 0; i < s->nb_streams; i++) {
368 av_packet_free((AVPacket **)&s->streams[i]->priv_data);
369 }
370
371 return 0;
372 }
373
374 const AVInputFormat ff_moflex_demuxer = {
375 .name = "moflex",
376 .long_name = NULL_IF_CONFIG_SMALL("MobiClip MOFLEX"),
377 .priv_data_size = sizeof(MOFLEXDemuxContext),
378 .read_probe = moflex_probe,
379 .read_header = moflex_read_header,
380 .read_packet = moflex_read_packet,
381 .read_seek = moflex_read_seek,
382 .read_close = moflex_read_close,
383 .extensions = "moflex",
384 .flags = AVFMT_GENERIC_INDEX,
385 .flags_internal = FF_FMT_INIT_CLEANUP,
386 };
387