javacv слияние изображения и mp3 создает mp4 длиннее исходного mp3

Я использую следующий код для объединения mp3 и изображения

IplImage ipl = cvLoadImage(path2ImageFile);
int height = ipl.height();
int width = ipl.width();
if(height%2!=0) height = height+1;
if(width%2!=0) width = width+1;

OpenCVFrameConverter.ToIplImage grabberConverter = new OpenCVFrameConverter.ToIplImage();  
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(path2OutputFile,width,height); 
FrameGrabber audioFileGrabber = new FFmpegFrameGrabber(path2AudioFile);
try 
{  
    audioFileGrabber.start();

    recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264 );//AV_CODEC_ID_VORBIS
    recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);//AV_CODEC_ID_MP3 //AV_CODEC_ID_AAC

    recorder.setFormat("mp4");  
    recorder.setAudioChannels(2);
    recorder.start();  

    Frame frame = null;
    //audioFileGrabber.getFrameNumber()
    while ((frame = audioFileGrabber.grabFrame())!=null) 
    {   recorder.record(grabberConverter.convert(ipl));  
        recorder.record(frame);
    }

    recorder.stop();  
    audioFileGrabber.stop();
 }  

Это создает mp4, но это примерно на 1,5 минуты дольше.
Почему это происходит?
Можно ли это как-то исправить?


person Para    schedule 10.05.2020    source источник
comment
Что содержат эти дополнительные 1,5 минуты (например, любое изображение или звук)?   -  person VC.One    schedule 18.05.2020


Ответы (1)


Было приятно решить проблему. ИМО, проблемы, кажется, из-за двух причин

  • Частота кадров видео в этом случае должна быть такой же, как у аудио, чтобы не было увеличения времени.
  • Звуковые кадры при записи должны быть записаны с одной и той же меткой времени.

Ниже приведен окончательный код, который работает для меня

import org.bytedeco.ffmpeg.global.*;
import org.bytedeco.javacv.*;


public class AudioExample {
    public static void main(String[] args) {
        String path2ImageFile = "WhatsApp Image 2018-12-29 at 21.54.58.jpeg";
        String path2OutputFile = "test.mp4";
        String path2AudioFile = "GMV_M_Brice_English_Greeting-Menus.mp3";

        FFmpegFrameGrabber imageFileGrabber = new FFmpegFrameGrabber(path2ImageFile);
        FFmpegFrameGrabber audioFileGrabber = new FFmpegFrameGrabber(path2AudioFile);
        try {
            audioFileGrabber.start();
            imageFileGrabber.start();

            FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(path2OutputFile,
                    imageFileGrabber.getImageWidth(), imageFileGrabber.getImageHeight());

            recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);//AV_CODEC_ID_VORBIS
            recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);//AV_CODEC_ID_MP3 //AV_CODEC_ID_AAC
            recorder.setSampleRate(audioFileGrabber.getSampleRate());
            recorder.setFrameRate(audioFileGrabber.getAudioFrameRate());
            recorder.setVideoQuality(1);
            recorder.setFormat("mp4");
            recorder.setAudioChannels(2);
            recorder.start();

            Frame frame = null;

            Frame imageFrame = imageFileGrabber.grab();
            while ((frame = audioFileGrabber.grab()) != null) {
                recorder.setTimestamp(frame.timestamp);
                recorder.record(imageFrame);
                recorder.record(frame);
            }
            recorder.stop();
            audioFileGrabber.stop();
            imageFileGrabber.stop();
        } catch (FrameRecorder.Exception | FrameGrabber.Exception e) {
            e.printStackTrace();
        }
    }
}

Я удалил opencv для изображения, так как мы можем использовать другой фреймграббер, чтобы получить изображение в виде кадра. Также вы можете видеть, что сгенерированный звук имеет тот же размер, что и mp3.

Тот же размер

Попытка №2

Поскольку первая попытка использовала одинаковую частоту кадров для видео и аудио, что вызывало некоторые проблемы, я подумал о том, чтобы исправить частоту кадров, а затем чередовать звук сверху.

import org.bytedeco.ffmpeg.global.*;
import org.bytedeco.javacv.*;


public class AudioExample {
    public static void main(String[] args) {
        String path2ImageFile = "/Users/tarunlalwani/Downloads/WhatsApp Image 2018-12-29 at 21.54.58.jpeg";
        String path2OutputFile = "/Users/tarunlalwani/Downloads/test.mp4";
        String path2AudioFile = "/Users/tarunlalwani/Downloads/GMV_M_Brice_English_Greeting-Menus.mp3";

        FFmpegFrameGrabber imageFileGrabber = new FFmpegFrameGrabber(path2ImageFile);
        FFmpegFrameGrabber audioFileGrabber = new FFmpegFrameGrabber(path2AudioFile);
        try {
            audioFileGrabber.start();
            imageFileGrabber.start();

            FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(path2OutputFile,
                    imageFileGrabber.getImageWidth(), imageFileGrabber.getImageHeight());

            recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);//AV_CODEC_ID_VORBIS
            recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);//AV_CODEC_ID_MP3 //AV_CODEC_ID_AAC
            recorder.setSampleRate(audioFileGrabber.getSampleRate());
            int frameRate = 30;
            recorder.setFrameRate(frameRate);
            recorder.setFormat("mp4");
            recorder.setAudioChannels(2);
            recorder.start();

            Frame frame = null;

            Frame imageFrame = imageFileGrabber.grab();
            int frames = (int)((audioFileGrabber.getLengthInTime() / 1000000f) * frameRate) + 1;
            int i = 0;

            //create video using fixed images and framerate
            while (i ++ <frames) {
                recorder.record(imageFrame);
            }

            // Add audio to given timestamps
            while ((frame = audioFileGrabber.grabFrame()) != null) {
                recorder.setTimestamp(frame.timestamp);
                recorder.record(frame);
            }

            recorder.stop();
            audioFileGrabber.stop();
            imageFileGrabber.stop();
        } catch (FrameRecorder.Exception | FrameGrabber.Exception e) {
            e.printStackTrace();
        }
    }
}
person Tarun Lalwani    schedule 19.05.2020
comment
Спасибо. В VLC работает, а в стандартном проигрывателе windows media звук слышно, но экран черный. Я использую виндовс 10. - person Para; 21.05.2020
comment
У меня нет окон, чтобы проверить. Может быть, это как-то связано с выбранным видеокодеком? - person Tarun Lalwani; 21.05.2020
comment
на форуме javacv говорят, что это может иметь какое-то отношение к тому, что я записываю слишком мало или слишком много кадров. Я должен записывать столько кадров, сколько составляет максимальная частота кадров, и, по-видимому, функция setFrameRate устанавливает максимальную частоту кадров. Фактическая частота кадров устанавливается, когда вы фактически используете setTimestamp для установки кадра. groups.google.com/forum/#!topic/javacv/Wr28ZNq2se0 Я до сих пор с трудом во всем этом разбираюсь к сожалению :( Сгенерированные видео... работают и не работают в зависимости от... не знаю от чего именно... :( - person Para; 21.05.2020
comment
Если я загружаю видео на YouTube, я работаю несколько секунд, а затем вижу, что видео недоступно. Тут явно что-то не так :( - person Para; 21.05.2020
comment
изменение рекордера.setVideoQuality(); от 0 до 1, кажется, сработало. Не понимаю, почему именно. - person Para; 21.05.2020
comment
Многое неясно, потому что нет документации, в которой говорится, что в идеале вы должны делать то или иное. Это скорее обучение путем удара и испытания - person Tarun Lalwani; 21.05.2020
comment
Ты можешь сказать это снова! - person Para; 21.05.2020
comment
@Para, см. обновленный ответ. Я надеюсь, что новый код поможет вам. Вы можете использовать фиксированную частоту кадров в этом - person Tarun Lalwani; 21.05.2020
comment
немного изменил его, чтобы учесть тот факт, что я использую более одного изображения, но в остальном работает как шарм. Большое спасибо за всю помощь. Я понятия не имел, что вы можете писать видео и звук отдельно. - person Para; 22.05.2020
comment
у кого-нибудь есть эта ошибка? org.bytedeco.javacv.FFmpegFrameGrabber$Exception: avformat_open_input() error -22: Could not open input "‪C:\Users\Developper\sounds\sound.mp3" - person Amine ABBAOUI; 01.04.2021