/* * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "audio_format.h" #include "pcm_convert.h" #include #include #include #include #include #include #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "pcm" void pcm_convert_init(struct pcm_convert_state *state) { memset(state, 0, sizeof(*state)); } void pcm_convert_deinit(struct pcm_convert_state *state) { avresample_free(&state->avr); } void pcm_convert_reset(struct pcm_convert_state *state) { avresample_free(&state->avr); } AVFrame *pcm_convert(struct pcm_convert_state *state, const struct audio_format *src_format, const struct audio_format *dest_format, const AVFrame *src) { AVFrame *dst; int ret, need_reinit = 0; #define CHECK_PARAM(name, val) \ do { \ int64_t val; \ av_opt_get_int(state->avr, name, 0, &val); \ if (val != src->val) \ need_reinit = 1; \ } while (0) if (state->avr) { CHECK_PARAM("in_sample_rate", sample_rate); CHECK_PARAM("in_sample_fmt", format); CHECK_PARAM("in_channel_layout", channel_layout); } if (need_reinit || !state->avr) { char in_layout[128], out_layout[128]; avresample_free(&state->avr); state->avr = avresample_alloc_context(); if (!state->avr) return NULL; state->dst_channel_layout = av_get_default_channel_layout(dest_format->channels); state->dst_samplerate = dest_format->sample_rate; state->dst_format = dest_format->format; av_opt_set_int(state->avr, "in_channel_layout", src->channel_layout, 0); av_opt_set_int(state->avr, "out_channel_layout", state->dst_channel_layout, 0); av_opt_set_int(state->avr, "in_sample_rate", src->sample_rate, 0); av_opt_set_int(state->avr, "out_sample_rate", state->dst_samplerate, 0); av_opt_set_int(state->avr, "in_sample_fmt", src->format, 0); av_opt_set_int(state->avr, "out_sample_fmt", state->dst_format, 0); av_get_channel_layout_string(in_layout, sizeof(in_layout), -1, src->channel_layout); av_get_channel_layout_string(out_layout, sizeof(out_layout), -1, state->dst_channel_layout); g_debug("Opening resampling context %s:%d:%s -> %s:%d:%s\n", av_get_sample_fmt_name(src->format), src->sample_rate, in_layout, av_get_sample_fmt_name(state->dst_format), state->dst_samplerate, out_layout); ret = avresample_open(state->avr); if (ret < 0) { g_warning("Error initializing format conversion.\n"); avresample_free(&state->avr); return NULL; } } dst = av_frame_alloc(); if (!dst) return NULL; dst->format = state->dst_format; dst->channel_layout = state->dst_channel_layout; dst->sample_rate = state->dst_samplerate; dst->nb_samples = avresample_get_out_samples(state->avr, src->nb_samples); ret = av_frame_get_buffer(dst, 32); if (ret < 0) { g_warning("Error allocating a buffer for format conversion.\n"); av_frame_free(&dst); return NULL; } ret = avresample_convert(state->avr, dst->extended_data, dst->linesize[0], dst->nb_samples, src->extended_data, src->linesize[0], src->nb_samples); if (ret < 0) { g_warning("Error during format conversion.\n"); av_frame_free(&dst); return NULL; } dst->nb_samples = ret; return dst; }