【问题标题】:Playing sound from a video using FFmpeg and SDL_QueueAudio results in high pitched audio使用 FFmpeg 和 SDL_QueueAudio 播放视频中的声音会产生高音调的音频
【发布时间】:2019-03-31 07:19:59
【问题描述】:

我正在尝试使用 SDL2 和 FFmpeg 播放 mp4 文件中的音频,而使用 SDL_QueueAudio 似乎比设置回调要容易得多。

我发现的所有解决方案,无论是在此处还是在 dranger tutorials 中,都已弃用或使用回调。我尝试使用 ffmpeg 和 sdl 标签(没有很多)浏览所有问题,但无济于事。我尝试将 dranger 教程转换为使用未弃用的调用,但遇到了同样的问题。我正在使用 C、FFmpeg 4.1 和 SDL 2.0.9。

这是 AVCodecContext 和 AVCodec 的设置:

    int audioStream = -1;
    for (i = 0; i < formatContext->nb_streams; i++) {
        if (audioStream < 0 && formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
            audioStream = i;
        }
    }

    AVCodecParameters *audioParams = formatContext->streams[audioStream]->codecpar;

    AVCodec *audioCodec = avcodec_find_decoder(audioParams->codec_id);

    AVCodecContext *audioCodecCtx = avcodec_alloc_context3(NULL);
    avcodec_open2(audioCodecCtx, audioCodec, NULL);

    SDL_Init(SDL_INIT_AUDIO)

    SDL_AudioSpec desired, obtained;
    SDL_zero(desired);
    SDL_zero(obtained);
    desired.freq = audioCodecCtx->sample_rate;
    desired.format = AUDIO_F32SYS;
    desired.channels = audioCodecCtx->channels;
    desired.silence = 0;
    desired.samples = AUDIO_BUFFER_SIZE;

    SDL_AudioDeviceID audioDevice = SDL_OpenAudioDevice(NULL, 0, &desired, &obtained, SDL_AUDIO_ALLOW_ANY_CHANGE);

这是主要的数据包解码循环:

    while (av_read_frame(formatContext, &packet) >= 0) {
        if (packet.stream_index == audioStream) {
            if (!avcodec_send_packet(audioCodecCtx, &packet)) {
                avcodec_receive_frame(audioCodecCtx, audioFrame);
                SDL_QueueAudio(audioDevice, audioFrame->data[0], audioFrame->linesize[0]);
            }
        }
    }

音频以正确的速度播放,但音调比实际高得多。我希望它听起来与任何媒体播放器中的声音相同。
编辑:我刚刚意识到测试视频有立体声音频,但我只是在排队audioFrame.data[0],我认为这意味着我只播放一个频道。我尝试排队 audioFrame.data[1] 也有数据,但它没有解决问题。我是否正确,如果正确,我该如何播放两个频道?

【问题讨论】:

  • 您检查过obtained 结构中的值(主要是频率)吗?
  • 对于我的测试视频,obtained.freq 是 44100,与 VLC 报告的相同。

标签: ffmpeg sdl sdl-2


【解决方案1】:

回答这个问题可能为时已晚,但我遇到了同样的问题,现在我找到了适合我的解决方案,所以我发布了这个。
这里的问题可能是,由 FFmpeg 解码的音频格式是 AV_SAMPLE_FMT_FLTP(浮动平面)格式,其中通道分别存储,如 frame-&gt;data[0]frame-&gt;data[1]
我们需要使用 swr_convert() 将其转换为将这些通道打包成一个数组的格式
这是我的解决方案。

  1. SwrContext 设置
SwrContext *resampler = swr_alloc_set_opts(NULL, 
                                           audioCodecCtx->channel_layout,
                                           AV_SAMPLE_FMT_S16,
                                           44100,
                                           audioCodecCtx->channel_layout,
                                           audioCodecCtx->sample_fmt,
                                           audioCodecCtx->sample_rate,
                                           0, 
                                           NULL);
swr_init(resampler);
  1. SDL 音频设置
SDL_AudioDeviceID dev;
SDL_AudioSpec want, have;
SDL_zero(want);
SDL_zero(have);
want.freq = 44100;
want.channels = audioCodecCtx->channels;
want.format = AUDIO_S16SYS;
dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
SDL_PauseAudioDevice(dev, 0);

最后是解码循环

int ret = 0;
AVPacket *packet = av_packet_alloc();
AVFrame *frame = av_frame_alloc();
AVFrame *audioframe = av_frame_alloc();
while (true){
    ret = av_read_frame(formatContext, packet);
    if (ret < 0) break;
    AVStream *stream = formatContext->streams[packet->stream_index];
    if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO){
        ret = avcodec_send_packet(audioCodecCtx, packet);
        while (ret >= 0){
            ret = avcodec_receive_frame(audioCodecCtx, frame);
            if (ret >= 0){
                int dst_samples = frame->channels * av_rescale_rnd(
                                   swr_get_delay(resampler, frame->sample_rate)
                                   + frame->nb_samples,
                                   44100,
                                   frame->sample_rate,               
                                   AV_ROUND_UP);
                uint8_t *audiobuf = NULL;
                ret = av_samples_alloc(&audiobuf, 
                                       NULL, 
                                       1, 
                                       dst_samples,
                                       AV_SAMPLE_FMT_S16, 
                                       1);
                dst_samples = frame->channels * swr_convert(
                                                 resampler, 
                                                 &audiobuf, 
                                                 dst_samples,
                                                 (const uint8_t**) frame->data, 
                                                 frame->nb_samples);
                ret = av_samples_fill_arrays(audioframe->data, 
                                             audioframe->linesize, 
                                             audiobuf,
                                             1, 
                                             dst_samples, 
                                             AV_SAMPLE_FMT_S16, 
                                             1);
                SDL_QueueAudio(dev, 
                               audioframe->data[0], 
                               audioframe->linesize[0]); 
            }
        }
    }
}

【讨论】:

    【解决方案2】:

    对我有用的是调整频率。尝试将频率更改为类似audioCodecCtx-&gt;sample_rate * 0.5

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-26
      • 2011-06-27
      • 2022-08-21
      • 2020-09-02
      • 2016-05-13
      • 1970-01-01
      相关资源
      最近更新 更多