1 /*
2 * Copyright (c) 2014 Luca Barbato <lu_zero@gentoo.org>
3 * Copyright (c) 2014 Michael Niedermayer <michaelni@gmx.at>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "swresample_internal.h"
23 #include "libavutil/channel_layout.h"
24 #include "libavutil/frame.h"
25 #include "libavutil/opt.h"
26
swr_config_frame(SwrContext * s,const AVFrame * out,const AVFrame * in)27 int swr_config_frame(SwrContext *s, const AVFrame *out, const AVFrame *in)
28 {
29 AVChannelLayout ch_layout = { 0 };
30 int ret;
31
32 swr_close(s);
33
34 if (in) {
35 #if FF_API_OLD_CHANNEL_LAYOUT
36 FF_DISABLE_DEPRECATION_WARNINGS
37 // if the old/new fields are set inconsistently, prefer the old ones
38 if ((in->channel_layout && (in->ch_layout.order != AV_CHANNEL_ORDER_NATIVE ||
39 in->ch_layout.u.mask != in->channel_layout))) {
40 av_channel_layout_from_mask(&ch_layout, in->channel_layout);
41 FF_ENABLE_DEPRECATION_WARNINGS
42 } else
43 #endif
44 if ((ret = av_channel_layout_copy(&ch_layout, &in->ch_layout)) < 0)
45 goto fail;
46 if ((ret = av_opt_set_chlayout(s, "ichl", &ch_layout, 0)) < 0)
47 goto fail;
48 if ((ret = av_opt_set_int(s, "isf", in->format, 0)) < 0)
49 goto fail;
50 if ((ret = av_opt_set_int(s, "isr", in->sample_rate, 0)) < 0)
51 goto fail;
52 }
53
54 if (out) {
55 #if FF_API_OLD_CHANNEL_LAYOUT
56 FF_DISABLE_DEPRECATION_WARNINGS
57 // if the old/new fields are set inconsistently, prefer the old ones
58 if ((out->channel_layout && (out->ch_layout.order != AV_CHANNEL_ORDER_NATIVE ||
59 out->ch_layout.u.mask != out->channel_layout))) {
60 av_channel_layout_uninit(&ch_layout);
61 av_channel_layout_from_mask(&ch_layout, out->channel_layout);
62 FF_ENABLE_DEPRECATION_WARNINGS
63 } else
64 #endif
65 if ((ret = av_channel_layout_copy(&ch_layout, &out->ch_layout)) < 0)
66 goto fail;
67 if ((ret = av_opt_set_chlayout(s, "ochl", &ch_layout, 0)) < 0)
68 goto fail;
69 if ((ret = av_opt_set_int(s, "osf", out->format, 0)) < 0)
70 goto fail;
71 if ((ret = av_opt_set_int(s, "osr", out->sample_rate, 0)) < 0)
72 goto fail;
73 }
74
75 ret = 0;
76 fail:
77 if (ret < 0)
78 av_log(s, AV_LOG_ERROR, "Failed to set option\n");
79 av_channel_layout_uninit(&ch_layout);
80 return ret;
81 }
82
config_changed(SwrContext * s,const AVFrame * out,const AVFrame * in)83 static int config_changed(SwrContext *s,
84 const AVFrame *out, const AVFrame *in)
85 {
86 AVChannelLayout ch_layout = { 0 };
87 int ret = 0;
88
89 if (in) {
90 #if FF_API_OLD_CHANNEL_LAYOUT
91 FF_DISABLE_DEPRECATION_WARNINGS
92 // if the old/new fields are set inconsistently, prefer the old ones
93 if ((in->channel_layout && (in->ch_layout.order != AV_CHANNEL_ORDER_NATIVE ||
94 in->ch_layout.u.mask != in->channel_layout))) {
95 av_channel_layout_from_mask(&ch_layout, in->channel_layout);
96 FF_ENABLE_DEPRECATION_WARNINGS
97 } else
98 #endif
99 if ((ret = av_channel_layout_copy(&ch_layout, &in->ch_layout)) < 0)
100 return ret;
101 if (av_channel_layout_compare(&s->in_ch_layout, &ch_layout) ||
102 s->in_sample_rate != in->sample_rate ||
103 s->in_sample_fmt != in->format) {
104 ret |= AVERROR_INPUT_CHANGED;
105 }
106 }
107
108 if (out) {
109 #if FF_API_OLD_CHANNEL_LAYOUT
110 FF_DISABLE_DEPRECATION_WARNINGS
111 // if the old/new fields are set inconsistently, prefer the old ones
112 if ((out->channel_layout && (out->ch_layout.order != AV_CHANNEL_ORDER_NATIVE ||
113 out->ch_layout.u.mask != out->channel_layout))) {
114 av_channel_layout_uninit(&ch_layout);
115 av_channel_layout_from_mask(&ch_layout, out->channel_layout);
116 FF_ENABLE_DEPRECATION_WARNINGS
117 } else
118 #endif
119 if ((ret = av_channel_layout_copy(&ch_layout, &out->ch_layout)) < 0)
120 return ret;
121 if (av_channel_layout_compare(&s->out_ch_layout, &ch_layout) ||
122 s->out_sample_rate != out->sample_rate ||
123 s->out_sample_fmt != out->format) {
124 ret |= AVERROR_OUTPUT_CHANGED;
125 }
126 }
127 av_channel_layout_uninit(&ch_layout);
128
129 return ret;
130 }
131
convert_frame(SwrContext * s,AVFrame * out,const AVFrame * in)132 static inline int convert_frame(SwrContext *s,
133 AVFrame *out, const AVFrame *in)
134 {
135 int ret;
136 uint8_t **out_data = NULL;
137 const uint8_t **in_data = NULL;
138 int out_nb_samples = 0, in_nb_samples = 0;
139
140 if (out) {
141 out_data = out->extended_data;
142 out_nb_samples = out->nb_samples;
143 }
144
145 if (in) {
146 in_data = (const uint8_t **)in->extended_data;
147 in_nb_samples = in->nb_samples;
148 }
149
150 ret = swr_convert(s, out_data, out_nb_samples, in_data, in_nb_samples);
151
152 if (ret < 0) {
153 if (out)
154 out->nb_samples = 0;
155 return ret;
156 }
157
158 if (out)
159 out->nb_samples = ret;
160
161 return 0;
162 }
163
available_samples(AVFrame * out)164 static inline int available_samples(AVFrame *out)
165 {
166 int bytes_per_sample = av_get_bytes_per_sample(out->format);
167 int samples = out->linesize[0] / bytes_per_sample;
168
169 if (av_sample_fmt_is_planar(out->format)) {
170 return samples;
171 } else {
172 int channels;
173 #if FF_API_OLD_CHANNEL_LAYOUT
174 FF_DISABLE_DEPRECATION_WARNINGS
175 channels = av_get_channel_layout_nb_channels(out->channel_layout);
176 FF_ENABLE_DEPRECATION_WARNINGS
177 if (!channels)
178 #endif
179 channels = out->ch_layout.nb_channels;
180 return samples / channels;
181 }
182 }
183
swr_convert_frame(SwrContext * s,AVFrame * out,const AVFrame * in)184 int swr_convert_frame(SwrContext *s,
185 AVFrame *out, const AVFrame *in)
186 {
187 int ret, setup = 0;
188
189 if (!swr_is_initialized(s)) {
190 if ((ret = swr_config_frame(s, out, in)) < 0)
191 return ret;
192 if ((ret = swr_init(s)) < 0)
193 return ret;
194 setup = 1;
195 } else {
196 // return as is or reconfigure for input changes?
197 if ((ret = config_changed(s, out, in)))
198 return ret;
199 }
200
201 if (out) {
202 if (!out->linesize[0]) {
203 out->nb_samples = swr_get_delay(s, s->out_sample_rate) + 3;
204 if (in) {
205 out->nb_samples += in->nb_samples*(int64_t)s->out_sample_rate / s->in_sample_rate;
206 }
207 if ((ret = av_frame_get_buffer(out, 0)) < 0) {
208 if (setup)
209 swr_close(s);
210 return ret;
211 }
212 } else {
213 if (!out->nb_samples)
214 out->nb_samples = available_samples(out);
215 }
216 }
217
218 return convert_frame(s, out, in);
219 }
220
221