Предварительная загрузка звука JavaCV FFmpegFrameGrabber

У меня есть приложение, которое передает видеоданные на RTMP-сервер с помощью javacv FFmpegFrameRecorder. Я хочу добавить в этот поток аудио из отдельного файла — короткий звуковой клип, который я хочу воспроизвести на повторе.

Учитывая, что звуковой клип очень короткий, я хочу предварительно загрузить аудиоданные в память и просто перебрать их, чтобы избежать чрезмерного ввода-вывода и т. д.

Я попытался добавить звук в поток, используя FFmpegFrameGrabber javacv, как указано в нескольких учебниках.

Добавление аудио работает отлично, если я не пытаюсь предварительно загрузить/кэшировать какие-либо аудиоданные, например:

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.

Может кто-нибудь объяснить, почему это не работает и/или как я могу добиться желаемого результата?


person James    schedule 01.07.2015    source источник


Ответы (1)


Я нашел решение в своем конкретном примере кода. ShortBuffer.duplicate() не выполняет глубокое копирование, поэтому это вызывает проблемы. Вместо этого мне пришлось создать новый ShortBuffer и скопировать содержимое.

person James    schedule 01.07.2015