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