正确使用 swr_convert_frame() 通过 ffmpeg 进行音频重采样

发布于 2025-01-13 21:52:00 字数 1079 浏览 4 评论 0原文

是否有使用 swr_convert_frame() 来重新采样音频而不是 swr_convert() 的示例?我的代码目前看起来像(使用 cgo):

    if averr := C.swr_convert_frame(swrctx, outframe, inframe); averr < 0 {
        return av_err("swr_convert_frame", averr)
    }

    encodeFrame(outFrame)

    if delay := C.swr_get_delay(swrctx, C.int64_t(outframe.sample_rate)); delay > 0 {
        if averr := C.swr_convert_frame(swrctx, outframe, nil); averr < 0 {
            return av_err("swr_convert_frame", averr)
        }

        encodeFrame(outFrame)
    }

但是,输出帧的样本数量比编码器为 libopus 配置的 frame_size 更多。如果我缩小 AVFrame 上的最大 nb_samples ,那么它会通过编码器,但我必须手动设置 pts ,从而产生多个帧同样的pts,即使遵循此大纲,例如。

我尝试根据 out_pts = swr_next_pts(ctx, in_pts) 设置它,但这似乎无法正确计算 pts,并且 libopus 会产生一些不正确的 dts 数字。

是否有正确使用 swr_convert_frame 来正确设置编码器的 pts 的示例?根据提供的API,似乎它也会产生不完整的帧?

Are there any examples for using swr_convert_frame() to resample audio instead of swr_convert()? My code currently looks like (using cgo):

    if averr := C.swr_convert_frame(swrctx, outframe, inframe); averr < 0 {
        return av_err("swr_convert_frame", averr)
    }

    encodeFrame(outFrame)

    if delay := C.swr_get_delay(swrctx, C.int64_t(outframe.sample_rate)); delay > 0 {
        if averr := C.swr_convert_frame(swrctx, outframe, nil); averr < 0 {
            return av_err("swr_convert_frame", averr)
        }

        encodeFrame(outFrame)
    }

However the output frame has more samples than the encoder's configured frame_size for libopus. If I shrink the max nb_samples on the AVFrame, then it passes the encoder but I have to manually set the pts resulting in multiple frames with the same pts, even when following this outline, for example.

I tried setting it according to out_pts = swr_next_pts(ctx, in_pts) however this doesn't seem to correctly calculate the pts and libopus produces some incorrect dts numbers.

Is there an example for correctly using swr_convert_frame that correctly sets the pts for the encoder? Based on the API provided, it seems like it would also produce incomplete frames?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

提笔书几行 2025-01-20 21:52:00

如果有人偶然发现这个问题,我终于弄清楚了。您需要运行自己的 FIFO,swr_convert_frame 否则将无法正确生成完整帧。我在下面使用 bytes.Buffer 使用 cgo 执行此操作,但它 libswresample 提供了自己的 音频 FIFO

        delay := int(C.swr_get_delay(c.swrctx, 48000)) + c.resampleFIFO.Len()/int(bytesPerOutputSample) // delay in number of output samples.
        n := C.swr_convert(c.swrctx, (**C.uint8_t)(unsafe.Pointer(&c.resampleBuf)), 8192, &c.avframe.data[0], c.avframe.nb_samples)
        if n < 0 {
            return av_err("swr_convert", n)
        }
        size := C.av_samples_get_buffer_size(nil, 2, n, C.AV_SAMPLE_FMT_S16, 1)
        if size < 0 {
            return av_err("av_samples_get_buffer_size", size)
        }
        if n, err := c.resampleFIFO.Write((*[1 << 30]byte)(unsafe.Pointer(c.resampleBuf))[:size]); err != nil {
            return fmt.Errorf("failed to write to resample buffer: %w", err)
        } else if n != int(size) {
            return fmt.Errorf("failed to write to resample buffer: wrote %d bytes, expected %d", n, size)
        }

        samples := 960
        for i := 0; c.resampleFIFO.Len() >= samples*int(bytesPerOutputSample); i += samples {
            c.resampleFIFO.Next(samples * int(bytesPerOutputSample))
        }

If anyone stumbles upon this question, I finally figured it out. You need to run your own FIFO, swr_convert_frame otherwise won't produce full frames properly. I am doing this with cgo below with bytes.Buffer but it libswresample provides their own audio FIFO.

        delay := int(C.swr_get_delay(c.swrctx, 48000)) + c.resampleFIFO.Len()/int(bytesPerOutputSample) // delay in number of output samples.
        n := C.swr_convert(c.swrctx, (**C.uint8_t)(unsafe.Pointer(&c.resampleBuf)), 8192, &c.avframe.data[0], c.avframe.nb_samples)
        if n < 0 {
            return av_err("swr_convert", n)
        }
        size := C.av_samples_get_buffer_size(nil, 2, n, C.AV_SAMPLE_FMT_S16, 1)
        if size < 0 {
            return av_err("av_samples_get_buffer_size", size)
        }
        if n, err := c.resampleFIFO.Write((*[1 << 30]byte)(unsafe.Pointer(c.resampleBuf))[:size]); err != nil {
            return fmt.Errorf("failed to write to resample buffer: %w", err)
        } else if n != int(size) {
            return fmt.Errorf("failed to write to resample buffer: wrote %d bytes, expected %d", n, size)
        }

        samples := 960
        for i := 0; c.resampleFIFO.Len() >= samples*int(bytesPerOutputSample); i += samples {
            c.resampleFIFO.Next(samples * int(bytesPerOutputSample))
        }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文