/* *TODO: broken sample rate(AAC), see mplayer */ bool AudioResamplerFF::prepare() { DPTR_D(AudioResamplerFF); if (!d.in_format.isValid()) { qWarning("src audio parameters 'channel layout(or channels), sample rate and sample format must be set before initialize resampler"); return false; } //TODO: also in do this statistics if (!d.in_format.channels()) { if (!d.in_format.channelLayoutFFmpeg()) { //FIXME: already return d.in_format.setChannels(2); d.in_format.setChannelLayoutFFmpeg(av_get_default_channel_layout(d.in_format.channels())); //from mplayer2 qWarning("both channels and channel layout are not available, assume channels=%d, channel layout=%lld", d.in_format.channels(), d.in_format.channelLayoutFFmpeg()); } else { d.in_format.setChannels(av_get_channel_layout_nb_channels(d.in_format.channelLayoutFFmpeg())); } } if (!d.in_format.channels()) d.in_format.setChannels(2); //TODO: why av_get_channel_layout_nb_channels() may return 0? if (!d.in_format.channelLayoutFFmpeg()) { qWarning("channel layout not available, use default layout"); d.in_format.setChannelLayoutFFmpeg(av_get_default_channel_layout(d.in_format.channels())); } if (!d.out_format.channels()) { if (d.out_format.channelLayoutFFmpeg()) { d.out_format.setChannels(av_get_channel_layout_nb_channels(d.out_format.channelLayoutFFmpeg())); } else { d.out_format.setChannels(d.in_format.channels()); d.out_format.setChannelLayoutFFmpeg(d.in_format.channelLayoutFFmpeg()); } } if (d.out_format.channelLayout() == AudioFormat::ChannelLayout_Unsupported) { d.out_format.setChannels(d.in_format.channels()); d.out_format.setChannelLayoutFFmpeg(d.in_format.channelLayoutFFmpeg()); } //now we have out channels if (!d.out_format.channelLayoutFFmpeg()) d.out_format.setChannelLayoutFFmpeg(av_get_default_channel_layout(d.out_format.channels())); if (!d.out_format.sampleRate()) d.out_format.setSampleRate(inAudioFormat().sampleRate()); if (d.speed <= 0) d.speed = 1.0; //DO NOT set sample rate here, we should keep the original and multiply 1/speed when needed //if (d.speed != 1.0) // d.out_format.setSampleRate(int(qreal(d.out_format.sampleFormat())/d.speed)); qDebug("swr speed=%.2f", d.speed); //d.in_planes = av_sample_fmt_is_planar((enum AVSampleFormat)d.in_sample_format) ? d.in_channels : 1; //d.out_planes = av_sample_fmt_is_planar((enum AVSampleFormat)d.out_sample_format) ? d.out_channels : 1; if (d.context) swr_free(&d.context); //TODO: if no free(of cause free is required), why channel mapping and layout not work if change from left to stero? //If use swr_alloc() need to set the parameters (av_opt_set_xxx() manually or with swr_alloc_set_opts()) before calling swr_init() d.context = swr_alloc_set_opts(d.context , d.out_format.channelLayoutFFmpeg() , (enum AVSampleFormat)outAudioFormat().sampleFormatFFmpeg() , qreal(outAudioFormat().sampleRate())/d.speed , d.in_format.channelLayoutFFmpeg() , (enum AVSampleFormat)inAudioFormat().sampleFormatFFmpeg() , inAudioFormat().sampleRate() , 0 /*log_offset*/, 0 /*log_ctx*/); /* av_opt_set_int(d.context, "in_channel_layout", d.in_channel_layout, 0); av_opt_set_int(d.context, "in_sample_rate", d.in_format.sampleRate(), 0); av_opt_set_sample_fmt(d.context, "in_sample_fmt", (enum AVSampleFormat)in_format.sampleFormatFFmpeg(), 0); av_opt_set_int(d.context, "out_channel_layout", d.out_channel_layout, 0); av_opt_set_int(d.context, "out_sample_rate", d.out_format.sampleRate(), 0); av_opt_set_sample_fmt(d.context, "out_sample_fmt", (enum AVSampleFormat)out_format.sampleFormatFFmpeg(), 0); */ qDebug("out: {cl: %lld, fmt: %s, freq: %d}" , d.out_format.channelLayoutFFmpeg() , qPrintable(d.out_format.sampleFormatName()) , d.out_format.sampleRate()); qDebug("in {cl: %lld, fmt: %s, freq: %d}" , d.in_format.channelLayoutFFmpeg() , qPrintable(d.in_format.sampleFormatName()) , d.in_format.sampleRate()); if (!d.context) { qWarning("Allocat swr context failed!"); return false; } //avresample 0.0.2(FFmpeg 0.11)~1.0.1(FFmpeg 1.1) has no channel mapping. but has remix matrix, so does swresample //TODO: why crash if use channel mapping for L or R? #if QTAV_HAVE(SWR_AVR_MAP) //LIBAVRESAMPLE_VERSION_INT < AV_VERSION_INT(1, 1, 0) bool remix = false; int in_c = d.in_format.channels(); int out_c = d.out_format.channels(); /* * matrix[i + stride * o] is the weight of input channel i in output channel o. */ double *matrix = 0; if (d.out_format.channelLayout() == AudioFormat::ChannelLayout_Left) { remix = true; matrix = (double*)calloc(in_c*out_c, sizeof(double)); for (int o = 0; o < out_c; ++o) { matrix[0 + in_c * o] = 1; } } if (d.out_format.channelLayout() == AudioFormat::ChannelLayout_Right) { remix = true; matrix = (double*)calloc(in_c*out_c, sizeof(double)); for (int o = 0; o < out_c; ++o) { matrix[1 + in_c * o] = 1; } } if (!remix && in_c < out_c) { remix = true; //double matrix[in_c*out_c]; //C99, VLA matrix = (double*)calloc(in_c*out_c, sizeof(double)); for (int i = 0, o = 0; o < out_c; ++o) { matrix[i + in_c * o] = 1; i = (i + i)%in_c; } } if (remix && matrix) { avresample_set_matrix(d.context, matrix, in_c); free(matrix); } #else bool use_channel_map = false; if (d.out_format.channelLayout() == AudioFormat::ChannelLayout_Left) { use_channel_map = true; memset(d.channel_map, 0, sizeof(d.channel_map)); for (int i = 0; i < d.out_format.channels(); ++i) { d.channel_map[i] = 0; } } if (d.out_format.channelLayout() == AudioFormat::ChannelLayout_Right) { use_channel_map = true; memset(d.channel_map, 0, sizeof(d.channel_map)); for (int i = 0; i < d.out_format.channels(); ++i) { d.channel_map[i] = 1; } } if (!use_channel_map && d.in_format.channels() < d.out_format.channels()) { use_channel_map = true; memset(d.channel_map, 0, sizeof(d.channel_map)); for (int i = 0; i < d.out_format.channels(); ++i) { d.channel_map[i] = i % d.in_format.channels(); } } if (use_channel_map) { av_opt_set_int(d.context, "icl", d.out_format.channelLayoutFFmpeg(), 0); //TODO: why crash if layout is mono and set uch(i.e. always the next line) av_opt_set_int(d.context, "uch", d.out_format.channels(), 0); swr_set_channel_mapping(d.context, d.channel_map); } #endif //QTAV_HAVE(SWR_AVR_MAP) int ret = swr_init(d.context); if (ret < 0) { qWarning("swr_init failed: %s", av_err2str(ret)); swr_free(&d.context); return false; } return true; }
/* *TODO: broken sample rate(AAC), see mplayer */ bool AudioResamplerFF::prepare() { DPTR_D(AudioResamplerFF); if (!d.in_format.isValid()) { qWarning("src audio parameters 'channel layout(or channels), sample rate and sample format must be set before initialize resampler"); return false; } //TODO: also in do this statistics if (!d.in_format.channels()) { if (!d.in_format.channelLayoutFFmpeg()) { //FIXME: already return d.in_format.setChannels(2); d.in_format.setChannelLayoutFFmpeg(av_get_default_channel_layout(d.in_format.channels())); //from mplayer2 qWarning("both channels and channel layout are not available, assume channels=%d, channel layout=%lld", d.in_format.channels(), d.in_format.channelLayoutFFmpeg()); } else { d.in_format.setChannels(av_get_channel_layout_nb_channels(d.in_format.channelLayoutFFmpeg())); } } if (!d.in_format.channels()) d.in_format.setChannels(2); //TODO: why av_get_channel_layout_nb_channels() may return 0? if (!d.in_format.channelLayoutFFmpeg()) { qWarning("channel layout not available, use default layout"); d.in_format.setChannelLayoutFFmpeg(av_get_default_channel_layout(d.in_format.channels())); } if (!d.out_format.channels()) { if (d.out_format.channelLayoutFFmpeg()) { d.out_format.setChannels(av_get_channel_layout_nb_channels(d.out_format.channelLayoutFFmpeg())); } else { d.out_format.setChannels(d.in_format.channels()); d.out_format.setChannelLayoutFFmpeg(d.in_format.channelLayoutFFmpeg()); } } if (d.out_format.channelLayout() == AudioFormat::ChannelLayout_Unsupported) { d.out_format.setChannels(d.in_format.channels()); d.out_format.setChannelLayoutFFmpeg(d.in_format.channelLayoutFFmpeg()); } //now we have out channels if (!d.out_format.channelLayoutFFmpeg()) d.out_format.setChannelLayoutFFmpeg(av_get_default_channel_layout(d.out_format.channels())); if (!d.out_format.sampleRate()) d.out_format.setSampleRate(inAudioFormat().sampleRate()); if (d.speed <= 0) d.speed = 1.0; //DO NOT set sample rate here, we should keep the original and multiply 1/speed when needed //if (d.speed != 1.0) // d.out_format.setSampleRate(int(qreal(d.out_format.sampleFormat())/d.speed)); qDebug("swr speed=%.2f", d.speed); //d.in_planes = av_sample_fmt_is_planar((enum AVSampleFormat)d.in_sample_format) ? d.in_channels : 1; //d.out_planes = av_sample_fmt_is_planar((enum AVSampleFormat)d.out_sample_format) ? d.out_channels : 1; swr_free(&d.context); //TODO: if no free(of cause free is required), why channel mapping and layout not work if change from left to stero? //If use swr_alloc() need to set the parameters (av_opt_set_xxx() manually or with swr_alloc_set_opts()) before calling swr_init() d.context = swr_alloc_set_opts(d.context , d.out_format.channelLayoutFFmpeg() , (enum AVSampleFormat)outAudioFormat().sampleFormatFFmpeg() , qreal(outAudioFormat().sampleRate())/d.speed , d.in_format.channelLayoutFFmpeg() , (enum AVSampleFormat)inAudioFormat().sampleFormatFFmpeg() , inAudioFormat().sampleRate() , 0 /*log_offset*/, 0 /*log_ctx*/); /* av_opt_set_int(d.context, "in_channel_layout", d.in_channel_layout, 0); av_opt_set_int(d.context, "in_sample_rate", d.in_format.sampleRate(), 0); av_opt_set_sample_fmt(d.context, "in_sample_fmt", (enum AVSampleFormat)in_format.sampleFormatFFmpeg(), 0); av_opt_set_int(d.context, "out_channel_layout", d.out_channel_layout, 0); av_opt_set_int(d.context, "out_sample_rate", d.out_format.sampleRate(), 0); av_opt_set_sample_fmt(d.context, "out_sample_fmt", (enum AVSampleFormat)out_format.sampleFormatFFmpeg(), 0); */ qDebug("out: {cl: %lld, fmt: %s, freq: %d}" , d.out_format.channelLayoutFFmpeg() , qPrintable(d.out_format.sampleFormatName()) , d.out_format.sampleRate()); qDebug("in {cl: %lld, fmt: %s, freq: %d}" , d.in_format.channelLayoutFFmpeg() , qPrintable(d.in_format.sampleFormatName()) , d.in_format.sampleRate()); if (!d.context) { qWarning("Allocat swr context failed!"); return false; } bool use_channel_map = false; if (d.out_format.channelLayout() == AudioFormat::ChannelLayout_Left) { use_channel_map = true; memset(d.channel_map, 0, sizeof(d.channel_map)); for (int i = 0; i < d.out_format.channels(); ++i) { d.channel_map[i] = 0; } } if (d.out_format.channelLayout() == AudioFormat::ChannelLayout_Right) { use_channel_map = true; memset(d.channel_map, 0, sizeof(d.channel_map)); for (int i = 0; i < d.out_format.channels(); ++i) { d.channel_map[i] = 1; } } if (!use_channel_map && d.in_format.channels() < d.out_format.channels()) { use_channel_map = true; memset(d.channel_map, 0, sizeof(d.channel_map)); for (int i = 0; i < d.out_format.channels(); ++i) { d.channel_map[i] = i % d.in_format.channels(); } } if (use_channel_map) { av_opt_set_int(d.context, "icl", d.out_format.channelLayoutFFmpeg(), 0); //TODO: why crash if layout is mono and set uch(i.e. always the next line) av_opt_set_int(d.context, "uch", d.out_format.channels(), 0); swr_set_channel_mapping(d.context, d.channel_map); } int ret = swr_init(d.context); if (ret < 0) { qWarning("swr_init failed: %s", av_err2str(ret)); swr_free(&d.context); return false; } return true; }