我对auido重采样不熟悉。我试图从两个视频中重新采样auido流。第一个输出接近原始输出,但有噪音,另一个几乎充满噪音。
第一个信息
128 kb / s,48.0kHz,2通道,AACLC
第二个信息
384 kb / s,48.0 kHz,6通道,AACLC
我发现,当我将样本量设置为16 时,第一个样本工作良好,但仍然带有噪音。另一个工作得很糟糕,但仍然有声音。什么以及如何确定输出样本大小?尽管我使用channels * av_get_bytes_per_sample((AVSampleFormat)output_fmt)
作为输出样本大小是因为我希望它与原始样本相同,但它根本没有声音。
MyResampling.cpp
bool MyResample::open(AVCodecParameters* par) {
if (!par) {
std::cout << "par is null" << std::endl;
return false;
}
audio_context = swr_alloc_set_opts(
audio_context, av_get_default_channel_layout(2), (AVSampleFormat)output_fmt,
par->sample_rate, av_get_default_channel_layout(par->channels), (AVSampleFormat)par->format, par->sample_rate,
0, 0);
avcodec_parameters_free(&par);
int ret = swr_init(audio_context);
if (ret != 0) {
std::cout << "failed to open audio codec" << std::endl;
}
return true;
}
int MyResample::resample(AVFrame* frame, unsigned char* output)
{
if (!frame)
return 0;
if (!output)
av_frame_free(&frame);
uint8_t* data[2] = { 0 };
data[0] = output;
int ret = swr_convert(audio_context, data, frame->nb_samples, (const uint8_t**)frame->data, frame->nb_samples);
//int size = ret * frame->channels * av_get_bytes_per_sample((AVSampleFormat)output_fmt);
int size = av_samples_get_buffer_size(nullptr, frame->channels, frame->nb_samples, (AVSampleFormat)output_fmt, 1);
if (ret < 0)
return ret;
return size;
}
MyAudioPlayer.cpp
bool open()
{
close();
QAudioFormat fmt;
fmt.setSampleRate(sample_rate); // from audioStream->codecpar->sample_rate
fmt.setSampleSize(16); //
fmt.setChannelCount(channels); // from audioStream->codecpar->channels
fmt.setCodec("audio/pcm");
fmt.setByteOrder(QAudioFormat::LittleEndian);
fmt.setSampleType(QAudioFormat::UnSignedInt);
output = new QAudioOutput(fmt);
io = output->start();
if (io)
return true;
return false;
}
bool write(const unsigned char* data, int data_size)
{
if (!data || data_size <= 0)
return false;
if (!output || !io)
{
return false;
}
int size = io->write((char*)data, data_size);
if (data_size != size)
return false;
return true;
}
main.cpp
MyAudioPlayer::open();
unsigned char* pcm = new unsigned char[1024 * 1024];
if (demux.get_media_type() == 1) { // audio
audio_decode.sendPacket(pkt);
AVFrame* frame = audio_decode.receiveFrame();
int len = resample.resample(frame, pcm);
while (len > 0) {
if (MyAudioPlayer::check_space() >= len) {
MyAudioPlayer::write(pcm, len);
break;
}
msleep(1);
}
}
答案 0 :(得分:0)
如果您对最终质量和噪音有疑问,可能是您误解了执行重新采样的正确方法,或者配置中存在错误。
看看这个例子:libswresample-example。
我不熟悉FFmpeg API,因为要进行重采样,我倾向于使用libsamplerate。
关于旧示例,这些是使用FFMPEG执行基本重采样的步骤:
//Set up resampling context
SwrContext *swr = swr_alloc();
av_opt_set_channel_layout(swr, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_channel_layout(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_int(swr, "in_sample_rate", 44100, 0);
av_opt_set_int(swr, "out_sample_rate", 22050, 0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
swr_init(swr);
取决于输入数据类型和期望作为输出的格式,您将需要指定正确的格式。这是C++ standard中的等效项:
----------------------------------------
| *AV_SAMPLE_FMT_S16* | `std::int16_t` |
| *AV_SAMPLE_FMT_S32* | `std::int32_t` |
| *AV_SAMPLE_FMT_FLT* | `float` |
| *AV_SAMPLE_FMT_DBL | `double` |
| *AV_SAMPLE_FMT_U8P* | `std::uint8_t` |
| ... | |
之后,您可以按照几个步骤执行重新采样:
uint8_t* out_samples;
int out_num_samples = av_rescale_rnd(swr_get_delay(swr, in_samplerate) + in_num_samples, out_samplerate, in_samplerate, AV_ROUND_UP);
av_samples_alloc(&out_samples, NULL, out_num_channels, out_num_samples, AV_SAMPLE_FMT_FLT, 0);
out_num_samples = swr_convert(swr, &out_samples, out_num_samples, &in_samples, in_num_samples);
av_freep(&out_samples);
swr_free(&swr);
如果有噪音,则可能是输入格式和输出格式不正确,或者重采样质量很低。
例如,如果您获得的样本少于预期的数量,请不要惊慌。由于过滤的方式,这是常见的行为。要获取剩余的尾随,您可以将NULL作为输入执行步骤5,这将刷新内部数据。