• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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