c - swr_convert 浮动平面到 S16
问题描述
如何使用 libav API 转换AV_SAMPLE_FMT_FLTP
为AV_SAMPLE_FMT_S16
我试图弄清楚如何将 PCM(从麦克风捕获)44.1KHz 重新采样和编码为 AAC 48.0KHz
那是我的重采样初始化器:
void initialize_resampler(SwrContext*& resamplerCtx, AVCodecContext* encoder, AVFrame*& rawResampledAudioFrame, AVStream* audioFormatStream)
{
int nb_samples = (encoder->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) ? encoder->sample_rate : encoder->frame_size;
int encoderFrameSize = encoder->channels * av_get_bytes_per_sample(encoder->sample_fmt) * encoder->frame_size;
rawResampledAudioFrame = allocate_audioframe(encoder->sample_fmt, encoder->channel_layout, encoder->sample_rate, nb_samples);
// Copy the stream parameters to the muxer
check(avcodec_parameters_from_context(audioFormatStream->codecpar, encoder));
// Create resampler context
resamplerCtx = swr_alloc();
if (resamplerCtx == nullptr)
throw std::runtime_error("Could not allocate resampler context");
// Set options
check(av_opt_set_int(resamplerCtx, "in_channel_count", 2, 0));
check(av_opt_set_int(resamplerCtx, "in_sample_rate", 44100, 0));
check(av_opt_set_sample_fmt(resamplerCtx, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0));
check(av_opt_set_int(resamplerCtx, "out_channel_count", encoder->channels, 0));
check(av_opt_set_int(resamplerCtx, "out_sample_rate", encoder->sample_rate, 0));
check(av_opt_set_sample_fmt(resamplerCtx, "out_sample_fmt", encoder->sample_fmt, 0));
// initialize the resampling context
check(swr_init(resamplerCtx));
}
对于重采样,我有以下代码:
AVPacket pkt{};
while (true)
{
AVPacket input_packet;
av_init_packet(&input_packet);
check(av_read_frame(inputContext, &input_packet));
check(avcodec_send_packet(decoderContext, &input_packet));
check(avcodec_receive_frame(decoderContext, decodedFrame));
// WHAT DO HERE swr_convert(resamplerContext, )
av_packet_unref(&input_packet);
av_init_packet(&pkt);
auto in_stream = inputContext->streams[pkt.stream_index];
auto out_stream = outputContext->streams[pkt.stream_index];
pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
pkt.pos = -1;
check(avcodec_send_frame(encoderContext, decodedFrame));
check(avcodec_receive_packet(encoderContext, &pkt));
check(av_interleaved_write_frame(outputContext, &pkt));
av_packet_unref(&pkt);
}
阅读文档我无法弄清楚我需要传递给函数的确切内容。我有这段代码将 PCM 编码为 MP2(输出为AV_SAMPLE_FMT_S16
)
const uint8_t* inPtr[] { const_cast<const uint8_t*>(&pcmData[0]), nullptr, nullptr,nullptr,nullptr,nullptr,nullptr,nullptr };
uint8_t* outPtr[] { &resampledAudioData[0], nullptr, nullptr,nullptr,nullptr,nullptr,nullptr,nullptr };
int resampledSamplesCount{ swr_convert(
resamplerCtx,
outPtr,
maxResampledSamplesCount,
inPtr,
inputSampleCount) };
// Negativo indica erro.
check(resampledSamplesCount);
pcmData 是来自输入AVPacket
(PCM)的原始数据
我在这里得到的是: MP2 不是平面的,因此它使用与 plannar 不同的相同 outPtr[0] ,后者需要两个指向相同可写数据的有效指针。但是,例如,我需要传递给 inPtr 什么?
当我尝试使用相同的代码时,ffmpeg 尝试在 outPtr[1] 上写入 nullptr。
解决方案
在这里做什么部分应该是这样的:
int out_samples = swr_convert(swr,
&audio_buf, /* out */
(int)out_count, /* out */
(const uint8_t**)decodedFrame->extended_data, /* in */
decodedFrame->nb_samples); /* in */
至于out_count
可以使用这样的东西(你可以改进它):
double frame_nb = 1.0 * encoder->sample_rate / audio_st->codec->sample_rate * decodedFrame->nb_samples;
out_count = floor(frame_nb);
audio_buf
是您预先分配的输出缓冲区(48000 * 4 是好的大小)。最后现在的问题是有多少数据写入缓冲区。这是公式:
int data_size = out_samples * av_get_bytes_per_sample(encoder->sample_fmt) * decodedFrame->channels;
希望这可以帮助。
推荐阅读
- powershell - 计算压缩文件中的内容
- react-native - React-native Webview 历史
- reactjs - react项目的bundle.js在哪里
- gatsby - 尝试为 Gatsby 安装 Sharp 时出错
- ansible - ansible-playbook 执行顺序
- android - 在 Unity 中连接 SQLite 数据库
- java - 使用相机拍照并将其保存到图库
- php - 在创建会话之前使用 Url 变量预填充 Woocommerce 结帐字段
- java - 运行 Spring Boot 应用程序时无法在 Spring Tool Suite 中选择 Tomcat 8.5
- xamarin - 单击多个本地通知时,Xamarin.Android 始终返回相同的通知 ID