JAVA使用JAVACV實現圖片合成短視頻,並給視頻添加音頻!!!

玩抖音的時候,發現可以根據圖片生成視頻,並添加音頻,同時剛好在項目當中也遇到需要利用多張圖片生成視頻的操作,特此記錄下實現的過程!!!

JAVA來實現圖片合成視頻這個需求,想想還是非常少見的,在網上找了很久資料,基本只找到一個開源庫:JAVACV 可以進行操作。並且在網上查找資料的時候也是發現,這方面的資料也是非常少的。有點難受哎!!!

什麼是JAVACV?

JavaCV 是一款開源的視覺處理庫,基於Apache License Version 2.0協議和GPLv2兩種協議 [1] ,對各種常用計算機視覺庫封裝後的一組jar包,封裝了OpenCV、libdc1394、OpenKinect、videoInput和ARToolKitPlus等計算機視覺編程人員常用庫的接口。
JavaCV通過其中的utility類方便的在包括Android在內的Java平臺上調用這些接口。

GITHUB項目地址:https://github.com/bytedeco/javacv
GITEE地址:https://gitee.com/hjljy/javacv (非官方,自己fork的一份)
最重要的是這個項目現在還在維護當中:無論是GITHUB地址,還是Maven倉庫,都可以看到代碼或者JAR包近期有過更新!!!
Maven倉庫地址:https://mvnrepository.com/search?q=javacv

相關JAR包

下載這個jar非常耗時。難受!!! 建議切換到阿里雲倉庫,下載要快很多

<dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv</artifactId>
            <version>1.5.2</version>
</dependency>
<dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv-platform</artifactId>
            <version>1.5.2</version>
</dependency>

圖片合成視頻

視頻都是一張一張圖片組成的,每秒的視頻都是由25張以上的圖片組成的,這個在視頻術語裏面叫做幀!!! 具體的合成代碼如下:

package cn.hjljy.javacv;

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

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 海加爾金鷹 www.hjljy.cn
 * @version V1.0
 * @email [email protected]
 * @description: 圖片合成MP4
 * @since 2020/5/16 18:00
 **/
public class Image2Mp4 {
    public static void main(String[] args) throws Exception {
        //合成的MP4
        String mp4SavePath = "D:\\javacv\\mp4\\img.mp4";
        //圖片地址 這裏面放了22張圖片
        String img = "D:\\javacv\\img";
        int width = 1600;
        int height = 900;
        //讀取所有圖片
        File file = new File(img);
        File[] files = file.listFiles();
        Map<Integer, File> imgMap = new HashMap<Integer, File>();
        int num = 0;
        for (File imgFile : files) {
            imgMap.put(num, imgFile);
            num++;
        }
        createMp4(mp4SavePath, imgMap, width, height);
    }

    private static void createMp4(String mp4SavePath, Map<Integer, File> imgMap, int width, int height) throws FrameRecorder.Exception {
        //視頻寬高最好是按照常見的視頻的寬高  16:9  或者 9:16
        FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(mp4SavePath, width, height);
        //設置視頻編碼層模式
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
        //設置視頻爲25幀每秒
        recorder.setFrameRate(25);
        //設置視頻圖像數據格式
        recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
        recorder.setFormat("mp4");
        try {
            recorder.start();
            Java2DFrameConverter converter = new Java2DFrameConverter();
            //錄製一個22秒的視頻
            for (int i = 0; i < 22; i++) {
                BufferedImage read = ImageIO.read(imgMap.get(i));
                //一秒是25幀 所以要記錄25次
                for (int j = 0; j < 25; j++) {
                    recorder.record(converter.getFrame(read));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //最後一定要結束並釋放資源
            recorder.stop();
            recorder.release();
        }
    }
}

在合成完畢之後,正常打開可以看到一個22秒的視頻,可以正常播放,裏面的畫面也是圖片文件夾裏面的圖片。
幾個需要注意的點:
1 建議合成的圖片寬高要一致,並且視頻的寬高還是要符合一定比例,不然會合成失敗!!!
2 一定要釋放資源,這個非常佔內存
3 H264和YUV420P 都是視頻的一些屬性,具體作用百度一下你就知道。反正我不是很清楚!!!
4 合成完畢後,會打印合成信息,裏面有合成的視頻的詳細信息,可以仔細看看!!!

視頻融合音頻

上面合成的視頻沒有聲音,需要將音頻融合到視頻裏面。形成一個完整的視頻!!!

public static boolean mergeAudioAndVideo(String videoPath, String audioPath, String outPut) throws Exception {
        boolean isCreated = true;
        File file = new File(videoPath);
        if (!file.exists()) {
            return false;
        }
        FrameRecorder recorder = null;
        FrameGrabber grabber1 = null;
        FrameGrabber grabber2 = null;
        try {
            //抓取視頻幀
            grabber1 = new FFmpegFrameGrabber(videoPath);
            //抓取音頻幀
            grabber2 = new FFmpegFrameGrabber(audioPath);
            grabber1.start();
            grabber2.start();
            //創建錄製
            recorder = new FFmpegFrameRecorder(outPut,
                    grabber1.getImageWidth(), grabber1.getImageHeight(),
                    grabber2.getAudioChannels());

            recorder.setFormat("mp4");
            recorder.setFrameRate(grabber1.getFrameRate());
            recorder.setSampleRate(grabber2.getSampleRate());
            recorder.start();

            Frame frame1;
            Frame frame2 ;
            //先錄入視頻
            while ((frame1 = grabber1.grabFrame()) != null ){
                recorder.record(frame1);
            }
            //然後錄入音頻
            while ((frame2 = grabber2.grabFrame()) != null) {
                recorder.record(frame2);
            }
            grabber1.stop();
            grabber2.stop();
            recorder.stop();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (recorder != null) {
                    recorder.release();
                }
                if (grabber1 != null) {
                    grabber1.release();
                }
                if (grabber2 != null) {
                    grabber2.release();
                }
            } catch (FrameRecorder.Exception e) {
                e.printStackTrace();
            }
        }
        return isCreated;

    }

到這裏一個完整的視頻就合成出來了!!!。但是在視頻融合音頻的過程當中還是有一些比較需要注意的點:
1 視頻長度和音頻長度儘量保持一致,如果不一致,合成的視頻長度會以最長的爲準,音頻短,後面就自然缺失音頻,視頻短,後面的視頻會呈現視頻的最後一幀。
2 不建議錄一幀視頻然後錄一幀音頻,音頻的後半段會丟失,比例差不多是1:1.6!!!

最後總結

這個功能是非常耗時與耗內存的一個操作,所以一定要注意服務器的內存問題。
推薦一些其他人的操作文章:
音頻與視頻合成技術
javaCV入門指南:序章
javacv opencv 多圖片合成視頻 並加入mp3的音頻 控制視頻秒數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章