Coverage Report

Created: 2026-02-14 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libswresample/dither.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2012-2013 Michael Niedermayer (michaelni@gmx.at)
3
 *
4
 * This file is part of libswresample
5
 *
6
 * libswresample 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
 * libswresample 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 libswresample; 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/avassert.h"
22
#include "libavutil/mem.h"
23
#include "swresample_internal.h"
24
25
#include "noise_shaping_data.c"
26
27
0
int swri_get_dither(SwrContext *s, void *dst, int len, unsigned seed, enum AVSampleFormat noise_fmt) {
28
0
    double scale = s->dither.noise_scale;
29
0
#define TMP_EXTRA 2
30
0
    double *tmp = av_malloc_array(len + TMP_EXTRA, sizeof(double));
31
0
    int i;
32
33
0
    if (!tmp)
34
0
        return AVERROR(ENOMEM);
35
36
0
    for(i=0; i<len + TMP_EXTRA; i++){
37
0
        double v;
38
0
        seed = seed* 1664525 + 1013904223;
39
40
0
        switch(s->dither.method){
41
0
            case SWR_DITHER_RECTANGULAR: v= ((double)seed) / UINT_MAX - 0.5; break;
42
0
            default:
43
0
                av_assert0(s->dither.method < SWR_DITHER_NB);
44
0
                v = ((double)seed) / UINT_MAX;
45
0
                seed = seed*1664525 + 1013904223;
46
0
                v-= ((double)seed) / UINT_MAX;
47
0
                break;
48
0
        }
49
0
        tmp[i] = v;
50
0
    }
51
52
0
    for(i=0; i<len; i++){
53
0
        double v;
54
55
0
        switch(s->dither.method){
56
0
            default:
57
0
                av_assert0(s->dither.method < SWR_DITHER_NB);
58
0
                v = tmp[i];
59
0
                break;
60
0
            case SWR_DITHER_TRIANGULAR_HIGHPASS :
61
0
                v = (- tmp[i] + 2*tmp[i+1] - tmp[i+2]) / sqrt(6);
62
0
                break;
63
0
        }
64
65
0
        v*= scale;
66
67
0
        switch(noise_fmt){
68
0
            case AV_SAMPLE_FMT_S16P: ((int16_t*)dst)[i] = v; break;
69
0
            case AV_SAMPLE_FMT_S32P: ((int32_t*)dst)[i] = v; break;
70
0
            case AV_SAMPLE_FMT_FLTP: ((float  *)dst)[i] = v; break;
71
0
            case AV_SAMPLE_FMT_DBLP: ((double *)dst)[i] = v; break;
72
0
            default: av_assert0(0);
73
0
        }
74
0
    }
75
76
0
    av_free(tmp);
77
0
    return 0;
78
0
}
79
80
av_cold int swri_dither_init(SwrContext *s, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt)
81
115k
{
82
115k
    int i;
83
115k
    double scale = 0;
84
85
115k
    if (s->dither.method > SWR_DITHER_TRIANGULAR_HIGHPASS && s->dither.method <= SWR_DITHER_NS)
86
0
        return AVERROR(EINVAL);
87
88
115k
    out_fmt = av_get_packed_sample_fmt(out_fmt);
89
115k
    in_fmt  = av_get_packed_sample_fmt( in_fmt);
90
91
115k
    if(in_fmt == AV_SAMPLE_FMT_FLT || in_fmt == AV_SAMPLE_FMT_DBL){
92
113k
        if(out_fmt == AV_SAMPLE_FMT_S32) scale = 1.0/(1LL<<31);
93
113k
        if(out_fmt == AV_SAMPLE_FMT_S16) scale = 1.0/(1LL<<15);
94
113k
        if(out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1.0/(1LL<< 7);
95
113k
    }
96
115k
    if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_S32 && (s->dither.output_sample_bits&31)) scale = 1;
97
115k
    if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_S16) scale = 1<<16;
98
115k
    if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1<<24;
99
115k
    if(in_fmt == AV_SAMPLE_FMT_S16 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1<<8;
100
101
115k
    scale *= s->dither.scale;
102
103
115k
    if (out_fmt == AV_SAMPLE_FMT_S32 && s->dither.output_sample_bits)
104
0
        scale *= 1<<(32-s->dither.output_sample_bits);
105
106
115k
    if (scale == 0) {
107
111k
        s->dither.method = 0;
108
111k
        return 0;
109
111k
    }
110
111
3.08k
    s->dither.ns_pos = 0;
112
3.08k
    s->dither.noise_scale=   scale;
113
3.08k
    s->dither.ns_scale   =   scale;
114
3.08k
    s->dither.ns_scale_1 = scale ? 1/scale : 0;
115
3.08k
    memset(s->dither.ns_errors, 0, sizeof(s->dither.ns_errors));
116
49.4k
    for (i=0; filters[i].coefs; i++) {
117
46.3k
        const filter_t *f = &filters[i];
118
46.3k
        if (llabs(s->out_sample_rate - f->rate)*20 <= f->rate && f->name == s->dither.method) {
119
0
            int j;
120
0
            s->dither.ns_taps = f->len;
121
0
            for (j=0; j<f->len; j++)
122
0
                s->dither.ns_coeffs[j] = f->coefs[j];
123
0
            s->dither.ns_scale_1 *= 1 - exp(f->gain_cB * M_LN10 * 0.005) * 2 / (1<<(8*av_get_bytes_per_sample(out_fmt)));
124
0
            break;
125
0
        }
126
46.3k
    }
127
3.08k
    if (!filters[i].coefs && s->dither.method > SWR_DITHER_NS) {
128
0
        av_log(s, AV_LOG_WARNING, "Requested noise shaping dither not available at this sampling rate, using triangular hp dither\n");
129
0
        s->dither.method = SWR_DITHER_TRIANGULAR_HIGHPASS;
130
0
    }
131
132
3.08k
    return 0;
133
115k
}
134
135
#define TEMPLATE_DITHER_S16
136
#include "dither_template.c"
137
#undef TEMPLATE_DITHER_S16
138
139
#define TEMPLATE_DITHER_S32
140
#include "dither_template.c"
141
#undef TEMPLATE_DITHER_S32
142
143
#define TEMPLATE_DITHER_FLT
144
#include "dither_template.c"
145
#undef TEMPLATE_DITHER_FLT
146
147
#define TEMPLATE_DITHER_DBL
148
#include "dither_template.c"
149
#undef TEMPLATE_DITHER_DBL