blob: 9d2a06d44e8784dfb6fba341d932734c05aa91b0 [file] [log] [blame]
Adrien Beraud087d5592023-03-06 11:22:33 -05001/*
2 * Copyright (C) 2004-2023 Savoir-faire Linux Inc.
3 *
4 * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
5 * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
6 * Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#include "resampler.h"
24
25extern "C" {
26#include <libswresample/swresample.h>
27#include <libavutil/opt.h>
28}
29
30#include <new>
31#include <stdexcept>
32#include <iostream>
33
34namespace jami {
35
36Resampler::Resampler()
37 : swrCtx_(swr_alloc())
38 , initCount_(0)
39{}
40
41Resampler::~Resampler()
42{
43 swr_free(&swrCtx_);
44}
45
46void
47Resampler::reinit(const AVFrame* in, const AVFrame* out)
48{
49 // NOTE swr_set_matrix should be called on an uninitialized context
50 auto swrCtx = swr_alloc();
51 if (!swrCtx) {
52 throw std::bad_alloc();
53 }
54
55 av_opt_set_chlayout(swrCtx, "ichl", &in->ch_layout, 0);
56 av_opt_set_int(swrCtx, "isr", in->sample_rate, 0);
57 av_opt_set_sample_fmt(swrCtx, "isf", static_cast<AVSampleFormat>(in->format), 0);
58
59 av_opt_set_chlayout(swrCtx, "ochl", &out->ch_layout, 0);
60 av_opt_set_int(swrCtx, "osr", out->sample_rate, 0);
61 av_opt_set_sample_fmt(swrCtx, "osf", static_cast<AVSampleFormat>(out->format), 0);
62
63 /**
64 * Downmixing from 5.1 requires extra setup, since libswresample can't do it automatically
65 * (not yet implemented).
66 *
67 * Source: https://www.atsc.org/wp-content/uploads/2015/03/A52-201212-17.pdf
68 * Section 7.8.2 for the algorithm
69 * Tables 5.9 and 5.10 for the coefficients clev and slev
70 *
71 * LFE downmixing is optional, so any coefficient can be used, we use +6dB for mono and
72 * +0dB in each channel for stereo.
73 */
74 if (in->ch_layout.u.mask == AV_CH_LAYOUT_5POINT1
75 || in->ch_layout.u.mask == AV_CH_LAYOUT_5POINT1_BACK) {
76 // NOTE MSVC can't allocate dynamic size arrays on the stack
77 if (out->ch_layout.nb_channels == 2) {
78 double matrix[2][6];
79 // L = 1.0*FL + 0.707*FC + 0.707*BL + 1.0*LFE
80 matrix[0][0] = 1;
81 matrix[0][1] = 0;
82 matrix[0][2] = 0.707;
83 matrix[0][3] = 1;
84 matrix[0][4] = 0.707;
85 matrix[0][5] = 0;
86 // R = 1.0*FR + 0.707*FC + 0.707*BR + 1.0*LFE
87 matrix[1][0] = 0;
88 matrix[1][1] = 1;
89 matrix[1][2] = 0.707;
90 matrix[1][3] = 1;
91 matrix[1][4] = 0;
92 matrix[1][5] = 0.707;
93 swr_set_matrix(swrCtx, matrix[0], 6);
94 } else {
95 double matrix[1][6];
96 // M = 1.0*FL + 1.414*FC + 1.0*FR + 0.707*BL + 0.707*BR + 2.0*LFE
97 matrix[0][0] = 1;
98 matrix[0][1] = 1;
99 matrix[0][2] = 1.414;
100 matrix[0][3] = 2;
101 matrix[0][4] = 0.707;
102 matrix[0][5] = 0.707;
103 swr_set_matrix(swrCtx, matrix[0], 6);
104 }
105 }
106
107 if (swr_init(swrCtx) >= 0) {
108 std::swap(swrCtx_, swrCtx);
109 swr_free(&swrCtx);
110 ++initCount_;
111 } else {
112 throw std::runtime_error("Failed to initialize resampler context");
113 }
114}
115
116int
117Resampler::resample(const AVFrame* input, AVFrame* output)
118{
119 if (!initCount_)
120 reinit(input, output);
121
122 int ret = swr_convert_frame(swrCtx_, output, input);
123 if (ret & AVERROR_INPUT_CHANGED || ret & AVERROR_OUTPUT_CHANGED) {
124 // Under certain conditions, the resampler reinits itself in an infinite loop. This is
125 // indicative of an underlying problem in the code. This check is so the backtrace
126 // doesn't get mangled with a bunch of calls to Resampler::resample
127 if (initCount_ > 1) {
128 throw std::runtime_error("Infinite loop detected in audio resampler");
129 }
130 reinit(input, output);
131 return resample(input, output);
132 } else if (ret < 0) {
133 return -1;
134 }
135
136 // Resampling worked, reset count to 1 so reinit isn't called again
137 initCount_ = 1;
138 return 0;
139}
140} // namespace jami