audio - JavaCV FFmpegFrameGrabber 预加载音频

标签 audio ffmpeg javacv preload

我有一个使用 javacv 的 FFmpegFrameRecorder 将视频数据流式传输到 RTMP 服务器的应用程序。我想从一个单独的文件中向这个流中添加一些音频——一个我想重复播放的简短的声音片段。

鉴于声音剪辑很短,我想将音频数据预加载到内存中并循环遍历它 - 这样我就可以避免过多的 IO 等。

我尝试使用 javacv 的 FFmpegFrameGrabber 将音频添加到流中,如多个教程中所述。

如果我不尝试预加载/缓存任何音频数据,则添加音频效果很好,例如:

private FFmpegFrameRecorder frameRecorder;
private FFmpegFrameGrabber frameGrabber;

...
//frameRecorder and frameGrabber setup during initialization
...

public void record(IplImage image) {
        try {
            frameRecorder.record(image);
            Frame frame = frameGrabber.grabFrame();
            if(frame == null) {
                frameGrabber = new FFmpegFrameGrabber("audioFileHere.wav");
                frameGrabber.start();
                frame = frameGrabber.grabFrame();
            }
            frameRecorder.record(frame);
        } catch (FrameRecorder.Exception e) {
            log.error(getMarker(FATAL), "Can't record frame!", e);
        } catch (FrameGrabber.Exception e) {
            log.error(getMarker(FATAL), "Can't record frame!", e);
        }
}

但是,如果我尝试预加载音频数据,则会播放垃圾声音:
private FFmpegFrameRecorder frameRecorder;
private List<FrameData> audioData;

private static final class FrameData {
    public final Buffer[] samples;
    public final Integer sampleRate;
    public final Integer audioChannels;

    //Constructors, getters and setters here
}

...
    //frameRecorder setup during initialization
    audioData = new ArrayList<>();
    FFmpegFrameGrabber audioGrabber = new FFmpegFrameGrabber("audioFileHere.wav");
    try {
        audioGrabber.start();
        Frame frame;
        while ((frame = audioGrabber.grabFrame()) != null) {
            Buffer[] buffers = frame.samples;
            Buffer[] copiedBuffers = new Buffer[buffers.length];
            for (int i = 0; i < buffers.length; i++) {
                copiedBuffers[i] = ((ShortBuffer) buffers[i]).duplicate();
            }
            FrameData frameData = new FrameData(copiedBuffers, frame.sampleRate, frame.audioChannels);
            audioData.add(frameData);
        }
    } catch (FrameGrabber.Exception e) {
        e.printStackTrace();
    }
...

private int frameCount = 0;

public void record(IplImage image) {
    frameCount++;
    try {
        FrameData frameData = audioData.get(frameCount % audioData.size());
        frameRecorder.record(image);
        frameRecorder.record(frameData.sampleRate, frameData.audioChannels, frameData.samples);
    } catch (FrameRecorder.Exception e) {
        log.error(getMarker(FATAL), "Can't record frame!", e);
    }
}

注意:我必须深度复制 Frame 对象,因为 FFmpegFrameGrabber.grabFrame() 回收单个 Frame 对象

有人可以解释为什么这不起作用和/或我如何才能达到预期的结果吗?

最佳答案

我在我的特定代码示例中找到了解决方案。 ShortBuffer.duplicate() 不会进行深度复制,因此会导致问题。相反,我必须创建一个新的 ShortBuffer 并复制内容。

关于audio - JavaCV FFmpegFrameGrabber 预加载音频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31165006/

相关文章:

windows - 如何使用 Windows API 从麦克风录制 wav 声音?

c# - C#中的和弦?

node.js - 无法让 FFMPEG buildpack 在 Heroku Node.js 服务器中工作(使用 Fluent-FFMPEG)

java - 使用 java cv 时在 android studio 上出现构建错误

java - AWT-EventQueue-0“java.lang.UnsatisfiedLinkError

javascript - JavaScript-播放GET返回的音频

android - 在android中播放立体声

FFmpeg (HLS) - 按大小而不是时间分割段(或限制段大小)

php - 使用 php 和 ffmpeg 转换视频

java - CvMatchShapes 返回什么?