[Development experience] Video editing through ffmpeg


Preface

Suddenly I found that some people on Douyin had released highlights of TV series, and they also got a lot of likes. Suddenly, I realized that this can also be so much praise.
Insert picture description here
It is found that this kind of video can be directly generated by the tool. Not much to say, code.


1. Video editing

1.1 Generate title

Generate text images through java, and add strokes to make them look more beautiful.
Example:

 public static void createImage2(String str, Font font, File outFile,
                                   Integer width, Integer height) throws Exception {
    
    
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        BufferedImageGraphicsConfig config = BufferedImageGraphicsConfig.getConfig(bufferedImage);
        bufferedImage =config.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
        Graphics g = bufferedImage.getGraphics();
        Graphics2D g2 = (Graphics2D) g;
        FontRenderContext frc = g2.getFontRenderContext();
        TextLayout tl = new TextLayout(str, font, frc);
        //字在页面的位置
        Shape sha = tl.getOutline(AffineTransform.getTranslateInstance(0,250));
        //白边的范围
        g2.setStroke(new BasicStroke(8));
        g2.setColor(Color.RED);
        ((Graphics2D) g).draw(sha);
        g2.setColor(Color.WHITE);
        g2.fill(sha);
        // 输出png图片
        ImageIO.write(bufferedImage, "png", outFile);
    }
  public static void main(String[] args) throws Exception {
    
    
        String name= "hello java";
                    createImage2(name, new Font("楷体", Font.BOLD, 150), new File(
                    "E:\\a.png"), 800, 600);
    }

Output picture:
Insert picture description here

2. Text and background image overlay

D: \ tools \ ffmpeg \ ffmpeg-N-99816-g3da35b7cc7-win64-gpl-shared-vulkan \ bin \ ffmpeg.exe
-y
-i E: \ video \ guanlangaoshou \ external seal 3.jpg
-i E: \ video \ guanlangaoshou \ bigFont \ 1-1.png
-filter_complex overlay = 220: 400
E: \ video \ guanlangaoshou \ fontSize \ 1-1.png

The overlay effect of text and background image can be easily achieved through the ffmpeg tool

  • -y If the output file exists, it is overwritten.
  • -i Two source files are superimposed following the source file address.
  • -filter_complex overlay The number following is the position when superimposed.
  • The last is the location of the output file.

So it can be realized: it 1-1is generated by java, add a background image you like. Just superimpose.
Insert picture description here

3. Video cutting

Segment the video according to your own ideas.

D:\tools\ffmpeg\ffmpeg-N-99816-g3da35b7cc7-win64-gpl-shared-vulkan\bin\ffmpeg.exe
-y
-ss 00:01:44 -i E:\video\guanlangaoshou\videodeal\13. mp4 -to 00:07:00 E:\video\guanlangaoshou\videosplit\13-1.mp4

  • -ss Starting time
  • -i Video address
  • -to Cut-off length means that the start time is cut back 7 minutes.
  • The last is the output location.

4. Video and background image overlay

D:\tools\ffmpeg\ffmpeg-N-99816-g3da35b7cc7-win64-gpl-shared-vulkan\bin\ffmpeg.exe -y -i E:\video\guanlangaoshou\videoimage\13-1.png -i E: \video\guanlangaoshou\videosplit\13-1.mp4 -filter_complex overlay=-80:500 E:\video\guanlangaoshou\success\13-1.mp4

Video and background image overlay is the same as picture overlay, you only need to control the overlay position yourself.

Result presentation

Finally, you can generate this short video that can be uploaded to Douyin after segmenting the video.
Insert picture description here

java execute cmd command

In addition, if you use the ffmpeg tool, it is called through the cmd command. Attach cmd to call the tool class, just copy and call it directly.
CmdUtil.java:

public class CmdUtil {
    
    

	public static String execCmd(String cmd){
    
    
		BufferedReader bReader=null;
		InputStreamReader sReader=null;
		try
		{
    
    
			String str = BaseConstant.FFMPEG_PATH+" "+cmd;
			System.out.println (str);
			Process p = Runtime.getRuntime ().exec (str);//启动两个线程,一个线程负责读标准输出流,另一个负责读标准错误流
			//获取进程的标准输入流
			final InputStream is1 = p.getInputStream();
			//获取进城的错误流
			final InputStream is2 = p.getErrorStream();
			new Thread() {
    
    
				public void run() {
    
    
					BufferedReader br1 = new BufferedReader(new InputStreamReader(is1));
					try {
    
    
						String line1 = null;
						while ((line1 = br1.readLine()) != null) {
    
    
							if (line1 != null){
    
    }
						}
					} catch (IOException e) {
    
    
						e.printStackTrace();
					}
					finally{
    
    
						try {
    
    
							is1.close();
						} catch (IOException e) {
    
    
							e.printStackTrace();
						}
					}
				}
			}.start();

			new Thread() {
    
    
				public void  run() {
    
    
					BufferedReader br2 = new  BufferedReader(new  InputStreamReader(is2));
					try {
    
    
						String line2 = null ;
						while ((line2 = br2.readLine()) !=  null ) {
    
    
							if (line2 != null){
    
    }
						}
					} catch (IOException e) {
    
    
						e.printStackTrace();
					}
					finally{
    
    
						try {
    
    
							is2.close();
						} catch (IOException e) {
    
    
							e.printStackTrace();
						}
					}
				}
			}.start();
			try
			{
    
    
				p.waitFor ();
				p.destroy();
			}
			catch (InterruptedException e)
			{
    
    
				e.printStackTrace ();
			}
			return null;
		}
		catch (IOException e)
		{
    
    
			e.printStackTrace ();
		}
		return null;
	}
}

More ffmepg instructions

FFmpegCmd.java:

public class FFmpegCmd {
    
    
	/**
	 * 扩大分辨率
	 * -y 覆盖输入
	 * -i 视频文件地址
	 */
	private static final String EXPAND_BOUNDARY="  -y -i  %s -vf  scale=%s:%s %s";
	private static final Integer AUTO=-2;

	/**
	 * 设置封面
	 *
	 * -i %s -map 1 -map 0 -c copy -disposition:v:1 attached_pic -y %s
	 *
	 *  ffmpeg  -i 第一集-妖雾重回-1.mp4 -i E:\video\huluwa\cover3.jpg -map 0 -map 1 -c copy -c:v:1 png  -disposition:v:1 attached_pic E:\video\huluwa\success
	 */
	private static final String SETTING_COVER="  -i %s -i %s -map 0 -map 1 -c copy -c:v:1 png  -disposition:v:1 attached_pic %s";
	private static final String VIDEO_INFO="  -i %s ";
	/**
	 * 封面  font 输入路径
	 */
	private static final String Image_OverLay=" -y  -i %s -i %s    -filter_complex overlay=%s:%s    %s";
	/**
	 * 图片截取
	 *  文件源 宽:高:start:end 输出路径
	 */
	private static final String Image_SPLIT=" -y  -i %s     -vf crop=%s:%s:%s:%s    %s";
	/**
	 * 视频分段
	 *  开始时间00:00:00  视频路径 截取时长 输出路径
	 */
	private static final String Video_SPLIT="-y -ss %s -i %s    -to %s        %s";
	/**
	 * 视频转换
	 */
	private static final String Video_COVERT=" -i %s -c:v copy -c:a copy %s";

	/**
	 * image to video
	 */
	private static final String Image_TO_VIdeo=" -f image2 -r 1 -i %s  -vcodec h264  %s";


	private static final String Video_TS=" -i %s -c copy -bsf:v h264_mp4toannexb -f mpegts  %s";

	private static final String Concat="  -i \"concat:%s|%s\" -c copy -bsf:a aac_adtstoasc -movflags +faststart %s";

	/**
	 * 修改分辨率
	 * @param videoPath 文件路径
	 * @param outPath 输出路径
	 * @param width 修改宽度
	 * @param height 修改高度
	 */
	public static void expandBoundaryMethod(String videoPath,String outPath,Integer width,Integer height){
    
    
		width = width==null?AUTO:width;
		height = height==null?AUTO:height;
		String cmd = String.format (EXPAND_BOUNDARY,videoPath,width,height,outPath);
		CmdUtil.execCmd (cmd);
	}

	/**
	 * 设置封面
	 * @param videoPath 文件路径
	 * @param imgPath 图片路径
	 * @param outPath 输出路径
	 */
	public static void settingCoverMethod(String videoPath,String imgPath,String outPath){
    
    
		String cmd = String.format (SETTING_COVER,videoPath,imgPath,outPath);
		String s = CmdUtil.execCmd (cmd);
		System.out.println (s);
	}

	public static VideoEntity getVideoInfo(String videoPath){
    
    

		String cmd = String.format (VIDEO_INFO,videoPath);
		String s = CmdUtil.execCmd (cmd);
		String regexDuration = "Duration: (.*?), start: (.*?), bitrate: (\\d*) kb\\/s";
		Pattern pattern = Pattern.compile(regexDuration);
		Matcher m = pattern.matcher(s.toString());
		VideoEntity videoEntity = new VideoEntity (videoPath);
		if (m.find()) {
    
    
			int time = getTimelen(m.group(1));
			System.out.println("视频时长:" + time + "s , 开始时间:" + m.group(2) + ", 比特率:" + m.group(3) + "kb/s");
			videoEntity.setDuration (time);
		}
		return videoEntity;

	}
	private static int getTimelen(String timelen) {
    
    
		int min = 0;
		String strs[] = timelen.split(":");
		if (strs[0].compareTo("0") > 0) {
    
    
			// 秒
			min += Integer.valueOf(strs[0]) * 60 * 60;
		}
		if (strs[1].compareTo("0") > 0) {
    
    
			min += Integer.valueOf(strs[1]) * 60;
		}
		if (strs[2].compareTo("0") > 0) {
    
    
			min += Math.round(Float.valueOf(strs[2]));
		}
		return min;
	}
	public static void imageOverlayMethod(String coverImage,String fontImage,Integer width,Integer height,String output){
    
    
		String cmd = String.format (Image_OverLay,coverImage,fontImage,width,height,output);
		CmdUtil.execCmd (cmd);
	}
	public static void ImageSplitMethod(String imagePath,Integer width,Integer height,Integer sw,Integer sh,String output ){
    
    
		String cmd = String.format (Image_SPLIT,imagePath,width,height,sw,sh,output);
		CmdUtil.execCmd (cmd);
	}
	public static void VideoSplitMethod(String videoPath,String start,String length,String output ){
    
    
		String cmd = String.format (Video_SPLIT,start,videoPath,length,output);
		CmdUtil.execCmd (cmd);
	}

    public static void videoConvert(String path,String outPath) {
    
    
		String cmd = String.format(Video_COVERT,path,outPath);
		CmdUtil.execCmd(cmd);
    }

	public static void ImageToVodeoMethod(String path, String outPutPath) {
    
    
		String cmd = String.format(Image_TO_VIdeo,path,outPutPath);
		CmdUtil.execCmd(cmd);
	}

	public static void toVideoTs(String path, String s) {
    
    
		String cmd = String.format(Video_TS,path,s);
		CmdUtil.execCmd(cmd);
	}

	public static void ConcatMethod(String imgPath, String vPath, String outPut) {
    
    
		String cmd = String.format(Concat,imgPath,vPath,outPut);
		CmdUtil.execCmd(cmd);
	}
}

Guess you like

Origin blog.csdn.net/qq_30285985/article/details/111599075