【开发经验】通过ffmpeg进行视频剪辑


前言

突然发现抖音有有一些人发布电视剧的精彩片段,并且还获得了很多的点赞。突然发现,原来这样也可以这么多赞。
在这里插入图片描述
发现这种视频可以通过工具直接生成。花不多说,上代码。


一、视频剪辑

1.1 生成标题

通过java生成文字图片,加外描边会更加好看。
示例:

 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);
    }

输出图片:
在这里插入图片描述

2. 文字和背景图叠加

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

通过ffmpeg工具即可很轻松的实现文字和背景图的叠加效果

  • -y 如果输出文件存在, 则覆盖。
  • -i 后面跟源文件地址 两个源文件进行叠加。
  • -filter_complex overlay 后面跟的数字是叠加时的位置。
  • 最后是输出文件的位置。

如此可实现:1-1是java生成的,加一个自己喜欢的背景图。叠加即可。
在这里插入图片描述

3、视频切割

将视频按照自己的想法分段。

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 开始时间
  • -i 视频地址
  • -to 截止长度,意为开始时间向后切7分钟。
  • 最后是输出位置。

4、视频和背景图叠加

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

视频和背景图叠加和图片叠加一样, 只需要自己控制叠加位置即可。

结果演示

最后即可生成这种按照视频分段后可以上传抖音的短视频。
在这里插入图片描述

java执行cmd指令

另外,使用ffmpeg工具的话,是通过cmd指令调用的。附加cmd调用工具类,直接复制调用即可。
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;
	}
}

更多ffmepg指令

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);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_30285985/article/details/111599075
今日推荐