FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/binka.c
Date: 2026-09-26 05:01:43
Exec Total Coverage
Lines: 63 73 86.3%
Functions: 3 3 100.0%
Branches: 25 48 52.1%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2021 Paul B Mahol
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "libavutil/intreadwrite.h"
22 #include "avformat.h"
23 #include "avio_internal.h"
24 #include "demux.h"
25 #include "internal.h"
26
27 typedef struct BinkaDemuxContext {
28 int is_ueba;
29 } BinkaDemuxContext;
30
31 8066 static int binka_probe(const AVProbeData *p)
32 {
33
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8066 times.
8066 if (AV_RB32(p->buf) == MKBETAG('1', 'F', 'C', 'B') &&
34 ✗ (p->buf[4] == 1 || p->buf[4] == 2))
35 ✗ return AVPROBE_SCORE_MAX;
36
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8065 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
8066 if (AV_RL32(p->buf) == MKBETAG('U','E','B','A') && p->buf[4] == 1 &&
37
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 (p->buf[5] == 1 || p->buf[5] == 2) && AV_RL32(p->buf + 8))
38 1 return AVPROBE_SCORE_MAX;
39 8065 return 0;
40 }
41
42 1 static int binka_read_header(AVFormatContext *s)
43 {
44 1 BinkaDemuxContext *binka = s->priv_data;
45 1 AVIOContext *pb = s->pb;
46 AVStream *st;
47 int entries, offset;
48
49 1 st = avformat_new_stream(s, NULL);
50
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!st)
51 ✗ return AVERROR(ENOMEM);
52
53 1 binka->is_ueba = avio_rl32(pb) == MKBETAG('U','E','B','A');
54
55 1 avio_skip(pb, 1);
56
57 1 st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
58 1 st->codecpar->codec_id = AV_CODEC_ID_BINKAUDIO_DCT;
59 1 st->codecpar->ch_layout.nb_channels = avio_r8(pb);
60
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (binka->is_ueba) {
61 1 avio_skip(pb, 2);
62 1 st->codecpar->sample_rate = avio_rl32(pb);
63
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (st->codecpar->sample_rate <= 0)
64 ✗ return AVERROR_INVALIDDATA;
65 } else
66 ✗ st->codecpar->sample_rate = avio_rl16(pb);
67 1 st->duration = avio_rl32(pb);
68
69 1 avio_skip(pb, 8);
70 1 entries = avio_rl16(pb);
71
72 1 offset = entries * 2 + 2;
73 1 avio_skip(pb, offset);
74
75 1 avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
76
77
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (binka->is_ueba) {
78 1 int ret = ff_alloc_extradata(st->codecpar, 1);
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
80 ✗ return ret;
81 1 st->codecpar->extradata[0] = '2';
82 }
83
84 1 return 0;
85 }
86
87 9 static int binka_read_packet(AVFormatContext *s, AVPacket *pkt)
88 {
89 9 BinkaDemuxContext *binka = s->priv_data;
90 9 AVIOContext *pb = s->pb;
91 9 AVStream *st = s->streams[0];
92 int64_t pos, duration;
93 int pkt_size;
94 9 int discard_padding = 0;
95 int ret;
96
97 9 pos = avio_tell(pb);
98 9 avio_skip(pb, 2);
99
100
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 8 times.
9 if (avio_feof(pb))
101 1 return AVERROR_EOF;
102
103 8 pkt_size = avio_rl16(pb);
104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!pkt_size)
105 ✗ return AVERROR_INVALIDDATA;
106
107
3/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 7 times.
8 if (binka->is_ueba && pkt_size == 0xFFFF) {
108 1 pkt_size = avio_rl16(pb);
109 1 duration = avio_rl16(pb);
110
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (duration > 0) {
111 /* Match the decoded DCT block size, excluding overlap. */
112
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
2 int frame_samples = st->codecpar->sample_rate < 22050 ? 480 :
113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 st->codecpar->sample_rate < 44100 ? 960 : 1920;
114 1 discard_padding = FFMAX(0, frame_samples - duration);
115 }
116 } else
117 7 duration = av_get_audio_frame_duration2(st->codecpar, 0);
118
119 8 ret = av_new_packet(pkt, pkt_size + 4);
120
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (ret < 0)
121 ✗ return ret;
122
123 8 ret = ffio_read_size(pb, pkt->data + 4, pkt_size);
124
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (ret < 0)
125 ✗ return ret;
126 8 AV_WL32(pkt->data, pkt_size);
127
128
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 if (discard_padding) {
129 1 uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10);
130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!side_data)
131 ✗ return AVERROR(ENOMEM);
132 1 AV_WL32(side_data + 4, discard_padding);
133 }
134
135 8 pkt->pos = pos;
136 8 pkt->stream_index = 0;
137 8 pkt->duration = duration;
138
139 8 return 0;
140 }
141
142 const FFInputFormat ff_binka_demuxer = {
143 .p.name = "binka",
144 .p.long_name = NULL_IF_CONFIG_SMALL("Bink Audio"),
145 .p.flags = AVFMT_GENERIC_INDEX | AVFMT_NOTIMESTAMPS,
146 .p.extensions = "binka",
147 .priv_data_size = sizeof(BinkaDemuxContext),
148 .read_probe = binka_probe,
149 .read_header = binka_read_header,
150 .read_packet = binka_read_packet,
151 };
152