Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * QOA decoder | ||
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 "avcodec.h" | ||
22 | #include "codec_internal.h" | ||
23 | #include "decode.h" | ||
24 | #include "get_bits.h" | ||
25 | #include "bytestream.h" | ||
26 | #include "mathops.h" | ||
27 | |||
28 | #define QOA_SLICE_LEN 20 | ||
29 | #define QOA_LMS_LEN 4 | ||
30 | |||
31 | typedef struct QOAChannel { | ||
32 | int history[QOA_LMS_LEN]; | ||
33 | int weights[QOA_LMS_LEN]; | ||
34 | } QOAChannel; | ||
35 | |||
36 | typedef struct QOAContext { | ||
37 | QOAChannel ch[256]; | ||
38 | } QOAContext; | ||
39 | |||
40 | static const int16_t qoa_dequant_tab[16][8] = { | ||
41 | { 1, -1, 3, -3, 5, -5, 7, -7}, | ||
42 | { 5, -5, 18, -18, 32, -32, 49, -49}, | ||
43 | { 16, -16, 53, -53, 95, -95, 147, -147}, | ||
44 | { 34, -34, 113, -113, 203, -203, 315, -315}, | ||
45 | { 63, -63, 210, -210, 378, -378, 588, -588}, | ||
46 | { 104, -104, 345, -345, 621, -621, 966, -966}, | ||
47 | { 158, -158, 528, -528, 950, -950, 1477, -1477}, | ||
48 | { 228, -228, 760, -760, 1368, -1368, 2128, -2128}, | ||
49 | { 316, -316, 1053, -1053, 1895, -1895, 2947, -2947}, | ||
50 | { 422, -422, 1405, -1405, 2529, -2529, 3934, -3934}, | ||
51 | { 548, -548, 1828, -1828, 3290, -3290, 5117, -5117}, | ||
52 | { 696, -696, 2320, -2320, 4176, -4176, 6496, -6496}, | ||
53 | { 868, -868, 2893, -2893, 5207, -5207, 8099, -8099}, | ||
54 | {1064, -1064, 3548, -3548, 6386, -6386, 9933, -9933}, | ||
55 | {1286, -1286, 4288, -4288, 7718, -7718, 12005, -12005}, | ||
56 | {1536, -1536, 5120, -5120, 9216, -9216, 14336, -14336}, | ||
57 | }; | ||
58 | |||
59 | 6 | static av_cold int qoa_decode_init(AVCodecContext *avctx) | |
60 | { | ||
61 | 6 | avctx->sample_fmt = AV_SAMPLE_FMT_S16; | |
62 | |||
63 | 6 | return 0; | |
64 | } | ||
65 | |||
66 | 1689271 | static int qoa_lms_predict(QOAChannel *lms) | |
67 | { | ||
68 | 1689271 | int prediction = 0; | |
69 |
2/2✓ Branch 0 taken 6757084 times.
✓ Branch 1 taken 1689271 times.
|
8446355 | for (int i = 0; i < QOA_LMS_LEN; i++) |
70 | 6757084 | prediction += (unsigned)lms->weights[i] * lms->history[i]; | |
71 | 1689271 | return prediction >> 13; | |
72 | } | ||
73 | |||
74 | 1689271 | static void qoa_lms_update(QOAChannel *lms, int sample, int residual) | |
75 | { | ||
76 | 1689271 | int delta = residual >> 4; | |
77 |
2/2✓ Branch 0 taken 6757084 times.
✓ Branch 1 taken 1689271 times.
|
8446355 | for (int i = 0; i < QOA_LMS_LEN; i++) |
78 |
2/2✓ Branch 0 taken 2509109 times.
✓ Branch 1 taken 4247975 times.
|
6757084 | lms->weights[i] += lms->history[i] < 0 ? -delta : delta; |
79 |
2/2✓ Branch 0 taken 5067813 times.
✓ Branch 1 taken 1689271 times.
|
6757084 | for (int i = 0; i < QOA_LMS_LEN-1; i++) |
80 | 5067813 | lms->history[i] = lms->history[i+1]; | |
81 | 1689271 | lms->history[QOA_LMS_LEN-1] = sample; | |
82 | 1689271 | } | |
83 | |||
84 | 171 | static int qoa_decode_frame(AVCodecContext *avctx, AVFrame *frame, | |
85 | int *got_frame_ptr, AVPacket *avpkt) | ||
86 | { | ||
87 | 171 | QOAContext *s = avctx->priv_data; | |
88 | int ret, frame_size, nb_channels, sample_rate; | ||
89 | GetByteContext gb; | ||
90 | int16_t *samples; | ||
91 | |||
92 | 171 | bytestream2_init(&gb, avpkt->data, avpkt->size); | |
93 | |||
94 | 171 | nb_channels = bytestream2_get_byte(&gb); | |
95 | 171 | sample_rate = bytestream2_get_be24(&gb); | |
96 |
2/4✓ Branch 0 taken 171 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 171 times.
|
171 | if (!sample_rate || !nb_channels) |
97 | ✗ | return AVERROR_INVALIDDATA; | |
98 | |||
99 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 171 times.
|
171 | if (nb_channels != avctx->ch_layout.nb_channels) { |
100 | ✗ | av_channel_layout_uninit(&avctx->ch_layout); | |
101 | ✗ | av_channel_layout_default(&avctx->ch_layout, nb_channels); | |
102 | ✗ | if ((ret = av_channel_layout_copy(&frame->ch_layout, &avctx->ch_layout)) < 0) | |
103 | ✗ | return ret; | |
104 | } | ||
105 | |||
106 | 171 | frame->sample_rate = avctx->sample_rate = sample_rate; | |
107 | |||
108 | 171 | frame->nb_samples = bytestream2_get_be16(&gb); | |
109 | 171 | frame_size = bytestream2_get_be16(&gb); | |
110 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 171 times.
|
171 | if (frame_size > avpkt->size) |
111 | ✗ | return AVERROR_INVALIDDATA; | |
112 | |||
113 | 171 | if (avpkt->size < 8 + QOA_LMS_LEN * 4 * nb_channels + | |
114 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 171 times.
|
171 | 8LL * ((frame->nb_samples + QOA_SLICE_LEN - 1) / QOA_SLICE_LEN) * nb_channels) |
115 | ✗ | return AVERROR_INVALIDDATA; | |
116 | |||
117 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 171 times.
|
171 | if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) |
118 | ✗ | return ret; | |
119 | 171 | samples = (int16_t *)frame->data[0]; | |
120 | |||
121 |
2/2✓ Branch 0 taken 333 times.
✓ Branch 1 taken 171 times.
|
504 | for (int ch = 0; ch < nb_channels; ch++) { |
122 | 333 | QOAChannel *qch = &s->ch[ch]; | |
123 | |||
124 |
2/2✓ Branch 0 taken 1332 times.
✓ Branch 1 taken 333 times.
|
1665 | for (int n = 0; n < QOA_LMS_LEN; n++) |
125 | 1332 | qch->history[n] = sign_extend(bytestream2_get_be16u(&gb), 16); | |
126 |
2/2✓ Branch 0 taken 1332 times.
✓ Branch 1 taken 333 times.
|
1665 | for (int n = 0; n < QOA_LMS_LEN; n++) |
127 | 1332 | qch->weights[n] = sign_extend(bytestream2_get_be16u(&gb), 16); | |
128 | } | ||
129 | |||
130 |
2/2✓ Branch 0 taken 43346 times.
✓ Branch 1 taken 171 times.
|
43517 | for (int sample_index = 0; sample_index < frame->nb_samples; |
131 | 43346 | sample_index += QOA_SLICE_LEN) { | |
132 |
2/2✓ Branch 0 taken 84464 times.
✓ Branch 1 taken 43346 times.
|
127810 | for (int ch = 0; ch < nb_channels; ch++) { |
133 | 84464 | QOAChannel *lms = &s->ch[ch]; | |
134 | 84464 | uint64_t slice = bytestream2_get_be64u(&gb); | |
135 | 84464 | int scalefactor = (slice >> 60) & 0xf; | |
136 | 84464 | int slice_start = sample_index * nb_channels + ch; | |
137 | 84464 | int slice_end = av_clip(sample_index + QOA_SLICE_LEN, 0, frame->nb_samples) * nb_channels + ch; | |
138 | |||
139 |
2/2✓ Branch 0 taken 1689271 times.
✓ Branch 1 taken 84464 times.
|
1773735 | for (int si = slice_start; si < slice_end; si += nb_channels) { |
140 | 1689271 | int predicted = qoa_lms_predict(lms); | |
141 | 1689271 | int quantized = (slice >> 57) & 0x7; | |
142 | 1689271 | int dequantized = qoa_dequant_tab[scalefactor][quantized]; | |
143 | 1689271 | int reconstructed = av_clip_int16(predicted + dequantized); | |
144 | |||
145 | 1689271 | samples[si] = reconstructed; | |
146 | 1689271 | slice <<= 3; | |
147 | |||
148 | 1689271 | qoa_lms_update(lms, reconstructed, dequantized); | |
149 | } | ||
150 | } | ||
151 | } | ||
152 | |||
153 | 171 | *got_frame_ptr = 1; | |
154 | |||
155 | 171 | return avpkt->size; | |
156 | } | ||
157 | |||
158 | const FFCodec ff_qoa_decoder = { | ||
159 | .p.name = "qoa", | ||
160 | CODEC_LONG_NAME("QOA (Quite OK Audio)"), | ||
161 | .p.type = AVMEDIA_TYPE_AUDIO, | ||
162 | .p.id = AV_CODEC_ID_QOA, | ||
163 | .priv_data_size = sizeof(QOAContext), | ||
164 | .init = qoa_decode_init, | ||
165 | FF_CODEC_DECODE_CB(qoa_decode_frame), | ||
166 | .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | | ||
167 | AV_CODEC_CAP_DR1, | ||
168 | .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, | ||
169 | AV_SAMPLE_FMT_NONE }, | ||
170 | }; | ||
171 |