C++ FFmpeg 音高问题

C++ FFmpeg pitch issue

本文关键字:问题 高问题 FFmpeg C++      更新时间:2023-10-16

我正在使用swr_convert来降低/提高传入音频的音调并将其存储在.mp3中。为了改变音高,我将输出采样率除以一个因子。但是,当此因子不是 1 时,生成的音频会略微失真。这是我的转换代码:

...
// Set up resample context
swrContext = swr_alloc();
if (!swrContext)
    throw -15;
av_opt_set_int(swrContext, "in_channel_count", codecContext->channels, 0);
av_opt_set_int(swrContext, "in_channel_layout", codecContext->channel_layout, 0);
av_opt_set_int(swrContext, "in_sample_rate", codecContext->sample_rate, 0);
av_opt_set_sample_fmt(swrContext, "in_sample_fmt", codecContext->sample_fmt, 0);
av_opt_set_int(swrContext, "out_channel_count", STREAM_AUDIO_CHANNELS, 0);
av_opt_set_int(swrContext, "out_channel_layout", STREAM_AUDIO_CHANNEL_LAYOUT, 0);
av_opt_set_int(swrContext, "out_sample_rate", STREAM_AUDIO_SAMPLE_RATE / pitch, 0);
av_opt_set_sample_fmt(swrContext, "out_sample_fmt", STREAM_AUDIO_SAMPLE_FORMAT_GM, 0);
if (swr_init(swrContext))
    throw -16;
// Allocate re-usable frame
frameDecoded = av_frame_alloc();
if (!frameDecoded)
    throw -17;
frameDecoded->format = codecContext->sample_fmt;
frameDecoded->channel_layout = codecContext->channel_layout;
frameDecoded->channels = codecContext->channels;
frameDecoded->sample_rate = codecContext->sample_rate;
// Load frames
inPacket.data = NULL;
inPacket.size = 0;
int gotFrame, samples = 0;
while (av_read_frame(formatContext, &inPacket) >= 0) {
    if (inPacket.stream_index != streamId) 
        continue;
    if (avcodec_decode_audio4(codecContext, frameDecoded, &gotFrame, &inPacket) < 0)
        throw -18;
    if (!gotFrame)
        continue;
    // Begin conversion
    if (swr_convert(swrContext, NULL, 0, (const uint8_t **)frameDecoded->data, frameDecoded->nb_samples) < 0)
        throw -19;
    while (swr_get_out_samples(swrContext, 0) >= RAW_AUDIO_FRAME_SIZE) {
        // Allocate data
        uint8_t **convertedData = NULL;
        if (av_samples_alloc_array_and_samples(&convertedData, NULL, STREAM_AUDIO_CHANNELS, RAW_AUDIO_FRAME_SIZE, STREAM_AUDIO_SAMPLE_FORMAT_GM, 0) < 0)
            throw -20;
        // Convert
        if (swr_convert(swrContext, convertedData, RAW_AUDIO_FRAME_SIZE, NULL, 0) < 0)
            throw -21;
        // Calculate buffer size
        size_t bufferSize = av_samples_get_buffer_size(NULL, STREAM_AUDIO_CHANNELS, RAW_AUDIO_FRAME_SIZE, STREAM_AUDIO_SAMPLE_FORMAT_GM, 0);
        if (bufferSize < 0)
            throw -22;
        fwrite(convertedData[0], 1, bufferSize, outStream);
        av_free(convertedData);
    }
}
...

STREAM_AUDIO_SAMPLE_RATE定义为 44100。如果有帮助,这是整个程序: http://pastebin.com/5akEwNg4

该程序生成一个带有 25 个音符的音.mp3,音高降低。下面是失真的示例: http://www.stuffbydavid.com/dl/30256478.mp3

你能发现我的转换有任何不正确的地方,或者我改变音高的方法不正确吗?还有别的办法吗?

您以 NULL 作为输入的 swr_convert() 调用会刷新内部队列,并且(间接)导致失真(因为在刷新后提交新输入)。您需要在循环中使用有效的输入输出缓冲区(均为非 NULL)调用swr_convert,直到文件完成解码,然后才在最后使用 NULL 输入刷新队列。