(二)ffmpeg的相关命令,以及JAVA操作ffmpeg

一、常用查看指令

1.查看FFmpeg支持的编码器
ffmpeg configure -encoders2.查看FFmpeg支持的编码器
ffmpeg configure -decoders3.查看ffmpeg支持的通信协议
ffmpeg configure -protocols4.查看FFmpeg所支持的音视频编码格式、文件封装格式与流媒体传输协议
ffmpeg configure --help

二、常用操作视频命令

        1.视频压缩
ffmpeg -i ahaha.mp4 -vcodec h264 -vf scale=640:-2 -threads 4 2020_conv.mp4ffmpeg -i ahaha.mp4 -strict -2 -vcodec h264 1579251906_output.mp4-i ahaha.mp4
输入文件,源文件xy_conv.mp4
输出文件,目标文件-vf scale=640:-2  
改变视频分辨率,缩放到640px宽,高度的-2是考虑到libx264要求高度是偶数,所以设置成-2,让软件自动计算得出一个接近等比例的偶数高-threads 4
4核运算相关参数-s 1280x720 
设置输出文件的分辨率,w*h。-b:v 
输出文件的码率,一般500k左右即可,人眼看不到明显的闪烁,这个是与视频大小最直接相关的。-preset
指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow。
与 veryslow相比,placebo以极高的编码时间为代价,只换取了大概1%的视频质量提升。这是一种收益递减准则:slow 与 medium相比提升了5%~10%;slower 与 slow相比提升了5%;veryslow 与 slower相比提升了3%。
针对特定类型的源内容(比如电影、动画等),还可以使用-tune参数进行特别的优化。-an
去除音频流。-vn
去除视频流。-c:a
指定音频编码器。-c:v
指定视频编码器,libx264,libx265,H.262,H.264,H.265。
libx264:最流行的开源 H.264 编码器。
NVENC:基于 NVIDIA GPU 的 H.264 编码器。
libx265:开源的 HEVC 编码器。
libvpx:谷歌的 VP8 和 VP9 编码器。
libaom:AV1 编码器。-vcodec copy
表示不重新编码,在格式未改变的情况采用。-re 
以源文件固有帧率发送数据。-minrate 964K -maxrate 3856K -bufsize 2000K 
指定码率最小为964K,最大为3856K,缓冲区大小为 2000K。-y
不经过确认,输出时直接覆盖同名文件。-crf
参数来控制转码,取值范围为 0~51,其中0为无损模式,18~28是一个合理的范围,数值越大,画质越差。
        2.视频拼接
1.将4个视频拼接成一个很长的视频(无声音)
ffmpeg -i 0.mp4 -i 1.mp4 -i 2.mp4 -i 3.mp4 -filter_complex '[0:0][1:0] [2:0][3:0] concat=n=4:v=1 [v]' -map '[v]' output.mp42.将4个视频拼接成一个很长的视频(有声音)
ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 -filter_complex '[0:0][0:1] [1:0][1:1] [2:0][2:1] concat=n=3:v=1:a=1 [v][a]' -map '[v]' -map '[a]’  output.mp4[0:0][0:1] [1:0][1:1] [2:0][2:1] 
分别表示第1个输入文件的视频、音频,第2个输入文件的视频、音频,第3个输入文件的视频、音频。concat=n=3:v=1:a=1 
表示有3个输入文件,输出一条视频流和一条音频流。[v][a] 
得到的视频流和音频流的名字,注意在 bash 等 shell 中需要用引号,防止通配符扩展。3.横向拼接视频2个ffmpeg -i 0.mp4 -i 1.mp4 -filter_complex "[0:v]pad=iw*2:ih*1[a];[a][1:v]overlay=w" out.mp4pad
将合成的视频宽高,这里iw代表第1个视频的宽,iw*2代表合成后的视频宽度加倍,ih为第1个视频的高,合成的两个视频最好分辨率一致。overlay
覆盖,[a][1:v]overlay=w,后面代表是覆盖位置w:0。4.竖向拼接视频2个
ffmpeg -i 0.mp4 -i 1.mp4 -filter_complex "[0:v]pad=iw:ih*2[a];[a][1:v]overlay=0:h" out_2.mp45.横向拼接视频3个ffmpeg -i 0.mp4 -i 1.mp4 -i 2.mp4 -filter_complex "[0:v]pad=iw*3:ih*1[a];[a][1:v]overlay=w[b];[b][2:v]overlay=2.0*w" out_v3.mp46.竖向拼接视频3个ffmpeg -i 0.mp4 -i 1.mp4 -i 2.mp4 -filter_complex "[0:v]pad=iw:ih*3[a];[a][1:v]overlay=0:h[b];[b][2:v]overlay=0:2.0*h" out_v4.mp47.竖向拼接视频4个品字形
ffmpeg -i 0.mp4 -i 1.mp4 -i 2.mp4 -i 3.mp4 -filter_complex "[0:v]pad=iw*2:ih*2[a];[a][1:v]overlay=w[b];[b][2:v]overlay=0:h[c];[c][3:v]overlay=w:h" out.mp4
       3.截取视频第一帧或者某一帧
# input seeking
ffmpeg -ss 00:1:05 -i gemfield.mp4 -frames:v 1 out.jpg# output seeking
ffmpeg -i gemfield.mp4 -ss 00:1:05 -frames:v 1 out1.jpg-frame:v 1,在video stream上截取1帧。
input seeking使用的是key frames,所以速度很快;而output seeking是逐帧decode,直到1分05秒,所以速度很慢。ffmpeg截取视频帧有2种 seeking 方式,对应有2种 coding 模式:transcoding 和 stream copying(ffmpeg -c copy)。transcoding 模式:需要 decoding + encoding 的模式,即先 decoding 再encoding。stream copying 模式:不需要decoding + encoding的模式,由命令行选项-codec加上参数copy来指定(-c:v copy )。在这种模式下,ffmpeg在video stream上就会忽略 decoding 和 encoding步骤。查看视频总帧数
ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=nb_frames -of default=nokey=1:noprint_wrappers=1 gemfield.mp4

       4.图片转视频

ffmpeg -f image2 -i 'in%6d.jpg' -vcodec libx264 -r 25 -b 200k test.mp4
-r 25 表示每秒播放25帧
-b 200k 指定码率为200k图片的文件名为"in000000.jpg",从0开始依次递增。

       4.图片格式转化

1.webp转换成jpg
ffmpeg -i in.webp out.jpg2.webp转换成png
ffmpeg -i in.webp out.png3.jpg转换成png
ffmpeg -i in.jpg out.png4.jpg转换成webp
ffmpeg -i in.jpg out.webp5.png转换成webp
ffmpeg -i in.png out.webp6.png转换成jpg
ffmpeg -i in.png out.jpg

三、java操作ffmpeg录制视频

        1.相关代码
/**** @Author: xy丶* @create: 2021/8/27 16:11*/
@Component
public class RtspToMP4 {public class In implements Runnable{private InputStream inputStream;public In(InputStream inputStream) {this.inputStream = inputStream;}@Overridepublic void run() {try {//转成字符输入流InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");int len = -1;char[] c = new char[1024];//读取进程输入流中的内容while ((len = inputStreamReader.read(c)) != -1) {String s = new String(c, 0, len);System.out.print(s);}}catch (Exception e) {e.printStackTrace();}}}public Process startRecord(String ffmpegPath,String streamUrl, String FilePath){ProcessBuilder processBuilder = new ProcessBuilder();//定义命令内容List<String> command = new ArrayList<>();command.add(ffmpegPath);command.add("-rtsp_transport");command.add("tcp");command.add("-y");command.add("-i");command.add(streamUrl);command.add("-c");command.add("copy");command.add("-f");command.add("mp4");command.add(FilePath);processBuilder.command(command);System.out.println("脚本:" + command.toString());//将标准输入流和错误输入流合并,通过标准输入流读取信息processBuilder.redirectErrorStream(true);try {//启动进程Process process = processBuilder.start();System.out.println("开始时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(System.currentTimeMillis())));//获取输入流InputStream inputStream = process.getInputStream();Thread inThread = new Thread(new In(inputStream));inThread.start();return process;} catch (Exception e) {e.printStackTrace();}return null;}/*** 停止录制* @param process* @return*/public boolean stopRecord(Process process) {try {OutputStream os = process.getOutputStream();os.write("q".getBytes());// 一定要刷新os.flush();os.close();} catch (Exception err) {err.printStackTrace();return false;}return true;}/*** 音视频合并,视频结束,音频结束 -- (cmd(windows): ffmpeg.exe -i test2.mp3 -i test1.mp4 -t 10 -y newVideo.mp4)** @param ffmpegPath      ffmpeg.exe文件路径,可在rest或者admin中进行配置,使用配置文件进行读取* @param audioInputPath  音频文件路径(输入)* @param videoInputPath  视频文件路径(输入)* @param time            文件时长* @param videoOutputPath 转换完成的文件路径(输出)* @throws IOException*/public static void audioVideoMerge(String ffmpegPath, String audioInputPath, String videoInputPath, double time, String videoOutputPath) throws IOException {// 构建命令List<String> command = Lists.newArrayList();command.add(ffmpegPath);command.add("-i");command.add(audioInputPath);command.add("-i");command.add(videoInputPath);command.add("-t");command.add(String.valueOf(time));command.add("-y");command.add(videoOutputPath);// 执行操作ProcessBuilder builder = new ProcessBuilder(command);Process process = builder.start();InputStream errorStream = process.getErrorStream();InputStreamReader isr = new InputStreamReader(errorStream);BufferedReader br = new BufferedReader(isr);String line = "";while ((line = br.readLine()) != null) {}if (br != null) {br.close();}if (isr != null) {isr.close();}if (errorStream != null) {errorStream.close();}}/*    public void testAudioVideoMerge() {FfmpegProperties ffmpegProperties = SpringContextHolder.getBean(FfmpegProperties.class);try {FfmpegUtil.audioVideoMerge(ffmpegProperties.getFfmpegFile(), "D:\\tools\\ffmpeg\\bin\\test2.mp3", "D:\\tools\\ffmpeg\\bin\\test1.mp4", 10, "D:\\tools\\ffmpeg\\bin\\newVideo.mp4");} catch (IOException e) {e.printStackTrace();}}*/}
        2.开始录制
   private Map<Integer,Process> map=new HashMap<>();/*** 开始录制* @param id* @param FileName* @return*/@GetMapping(value = "/startRecord")public Result<Object> Start(Integer id, String FileName) {String ffmpegPath="E:\\install\\ffmpeg\\bin\\ffmpeg.exe";//rtsp://127.0.0.1:554/rtp/34020000001110000001_34020000001320000002   rtsp://127.0.0.1:554/rtp/44010200492000000001_34020000001320000001String streamUrl="rtsp://127.0.0.1:554/rtp/44010200492000000001_34020000001320000001";String FilePath="E:\\ffmp4\\"+FileName;Process process = rtspToMP4.startRecord(ffmpegPath, streamUrl, FilePath);if(null!=process){map.put(id,process);boolean interceptPhoto = VedioUtils.interceptPhoto(ffmpegPath, streamUrl, "E:\\ffmp4\\rtsp新脚本.jpg");if (!interceptPhoto){return Results.newFailedResult(ErrorCodeEnum.UNKNOWN);}return Results.newSuccessResult("操作成功");}return Results.newFailedResult(ErrorCodeEnum.UNKNOWN);}
        3.结束录制
    /*** 结束录制* @param id* @return*/@GetMapping(value = "/stop")public Result<Object> stop(Integer id) {if(map.containsKey(id)){Process process = map.get(id);if(null!=process){rtspToMP4.stopRecord(process);return Results.newSuccessResult("操作成功");}}return Results.newFailedResult(ErrorCodeEnum.UNKNOWN);}
        4.合并视频
    /*** @Description:合并视频* @Author: xy丶*/@GetMapping("/mergeVideo")public void mergeVideo( HttpServletResponse response){List<String> paths = Lists.newArrayList();paths.add("E:\\excel\\test.mp4");paths.add("E:\\excel\\test1.mp4");paths.add("E:\\excel\\test2.mp4");paths.add("E:\\excel\\test3.mp4");CMDExecteUtil excutor = new CMDExecteUtil();//String cmd = VedioUtils.mergeCmd[paths.size() - 1];String cmd = "ffmpeg %s -filter_complex \"nullsrc=size=640x480[base];[0:v]setpts=PTS-STARTPTS,scale=320x240[1];[1:v]setpts=PTS-STARTPTS,scale=320x240[2];[2:v]setpts=PTS-STARTPTS,scale=320x240[3];[3:v]setpts=PTS-STARTPTS,scale=320x240[4];[base][1]overlay=shortest=1[tmp1];[tmp1][2]overlay=shortest=1:x=320[tmp2];[tmp2][3]overlay=shortest=1:y=240[tmp3];[tmp3][4]overlay=shortest=1:x=320:y=240\" %s";StringBuilder sb = new StringBuilder();for (String s : paths) {if (StringUtils.isEmpty(sb)) {sb.append("-i ").append(s);} else {sb.append(" ").append("-i ").append(s);}}// "ffmpeg %s -filter_complex \"nullsrc=size=640x480[base];[0:v]setpts=PTS-STARTPTS,scale=320x240[1];[1:v]setpts=PTS-STARTPTS,scale=320x240[2];[2:v]setpts=PTS-STARTPTS,scale=320x240[3];[3:v]setpts=PTS-STARTPTS,scale=320x240[4];[base][1]overlay=shortest=1[tmp1];[tmp1][2]overlay=shortest=1:x=320[tmp2];[tmp2][3]overlay=shortest=1:y=240[tmp3];[tmp3][4]overlay=shortest=1:x=320:y=240\" %s",String tmpCMD = String.format(cmd, sb.toString(), "E:\\excel\\mergeVideo.mp4");excutor.exec(tmpCMD);}
public class CMDExecteUtil {Logger logger = LoggerFactory.getLogger(CMDExecteUtil.class);/*** 执行命令* @param command 命令语句* @return*/public String exec(String command) {try {//创建子进程执行命令语句Process p = Runtime.getRuntime().exec(command);StreamCaptureThread errorStream = new StreamCaptureThread(p.getErrorStream());StreamCaptureThread outputStream = new StreamCaptureThread(p.getInputStream());new Thread(errorStream).start();new Thread(outputStream).start();//等待执行完毕p.waitFor();String result = command + "\n" + outputStream.output.toString() + errorStream.output.toString();logger.info(result);if (!StringUtils.isEmpty(errorStream.output.toString())) {return errorStream.output.toString();}} catch (Exception e) {logger.error(e.getMessage());}return null;}private class StreamCaptureThread implements Runnable {InputStream stream;StringBuilder output;public StreamCaptureThread(InputStream stream) {this.stream = stream;this.output = new StringBuilder();}@Overridepublic void run() {try {try {BufferedReader br = new BufferedReader(new InputStreamReader(this.stream));String line = br.readLine();while (line != null) {if (line.trim().length() > 0) {output.append(line).append("\n");}line = br.readLine();}} finally {if (stream != null) {stream.close();}}} catch (IOException ex) {ex.printStackTrace(System.err);}}}
}
       5.其他操作

/*** @author xy丶* @date 2023/10/11*/
@Service
@Slf4j
public class FFmpegServiceImpl {//九宫格命令private String[] mergeCmd = {"ffmpeg %s -filter_complex \"nullsrc=size=640x480[base];[0:v]setpts=PTS-STARTPTS,scale=640x480[1];[base][1]overlay=shortest=1\" %s","ffmpeg -i 1.mp4 -i 2.mp4 -filter_complex \"nullsrc=size=640x480[base];[0:v]setpts=PTS-STARTPTS,scale=320x480[1];[1:v]setpts=PTS-STARTPTS,scale=320x480[2];[base][1]overlay=shortest=1[tmp1];[tmp1][2]overlay=shortest=1:x=320\" mergeOut.mp4","ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 -filter_complex \"nullsrc=size=640x480[base];[0:v]setpts=PTS-STARTPTS,scale=320x240[1];[1:v]setpts=PTS-STARTPTS,scale=320x240[2];[2:v]setpts=PTS-STARTPTS,scale=320x240[3];[base][1]overlay=shortest=1[tmp1];[tmp1][2]overlay=shortest=1:y=240[tmp2];[tmp2][3]overlay=shortest=1:x=320\" mergeOut.mp4","ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 -i 3.mp4 -i 3.mp4 -filter_complex \"nullsrc=size=640x480[base];[0:v]setpts=PTS-STARTPTS,scale=320x240[1];[1:v]setpts=PTS-STARTPTS,scale=320x240[2];[2:v]setpts=PTS-STARTPTS,scale=320x240[3];[3:v]setpts=PTS-STARTPTS,scale=320x240[4];[base][1]overlay=shortest=1[tmp1];[tmp1][2]overlay=shortest=1:x=320[tmp2];[tmp2][3]overlay=shortest=1:y=240[tmp3];[tmp3][4]overlay=shortest=1:x=320:y=240\" mergeOut.mp4","ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 -i 4.mp4 -i 5.mp4 -filter_complex \"nullsrc=size=690x480[base];[0:v]setpts=PTS-STARTPTS,scale=230x240[1];[1:v]setpts=PTS-STARTPTS,scale=230x240[2];[2:v]setpts=PTS-STARTPTS,scale=230x240[3];[3:v]setpts=PTS-STARTPTS,scale=230x240[4];[4:v]setpts=PTS-STARTPTS,scale=230x240[5];[base][1]overlay=shortest=1[tmp1];[tmp1][2]overlay=shortest=1:x=230[tmp2];[tmp2][3]overlay=shortest=1:x=460[tmp3];[tmp3][4]overlay=shortest=1:y=240[tmp4];[tmp4][5]overlay=shortest=1:x=230:y=240\" mergeOut.mp4","ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 -i 4.mp4 -i 5.mp4 -i 6.mp4 -filter_complex \"nullsrc=size=690x480[base];[0:v]setpts=PTS-STARTPTS,scale=230x240[1];[1:v]setpts=PTS-STARTPTS,scale=230x240[2];[2:v]setpts=PTS-STARTPTS,scale=230x240[3];[3:v]setpts=PTS-STARTPTS,scale=230x240[4];[4:v]setpts=PTS-STARTPTS,scale=230x240[5];[5:v]setpts=PTS-STARTPTS,scale=230x240[6];[base][1]overlay=shortest=1[tmp1];[tmp1][2]overlay=shortest=1:x=230[tmp2];[tmp2][3]overlay=shortest=1:x=460[tmp3];[tmp3][4]overlay=shortest=1:y=240[tmp4];[tmp4][5]overlay=shortest=1:x=230:y=240[tmp5];[tmp5][6]overlay=shortest=1:x=460:y=240\" mergeOut.mp4","ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 -i 4.mp4 -i 5.mp4 -i 6.mp4 -i 7.mp4 -filter_complex \"nullsrc=size=690x480[base];[0:v]setpts=PTS-STARTPTS,scale=230x160[1];[1:v]setpts=PTS-STARTPTS,scale=230x160[2];[2:v]setpts=PTS-STARTPTS,scale=230x160[3];[3:v]setpts=PTS-STARTPTS,scale=230x160[4];[4:v]setpts=PTS-STARTPTS,scale=230x160[5];[5:v]setpts=PTS-STARTPTS,scale=230x160[6];[6:v]setpts=PTS-STARTPTS,scale=230x160[7];[base][1]overlay=shortest=1[tmp1];[tmp1][2]overlay=shortest=1:x=230[tmp2];[tmp2][3]overlay=shortest=1:x=460[tmp3];[tmp3][4]overlay=shortest=1:y=160[tmp4];[tmp4][5]overlay=shortest=1:x=230:y=160[tmp5];[tmp5][6]overlay=shortest=1:x=460:y=160[tmp6];[tmp6][7]overlay=shortest=1:y=320\" mergeOut.mp4","ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 -i 4.mp4 -i 5.mp4 -i 6.mp4 -i 7.mp4  -i 8.mp4 -filter_complex \"nullsrc=size=690x480[base];[0:v]setpts=PTS-STARTPTS,scale=230x160[1];[1:v]setpts=PTS-STARTPTS,scale=230x160[2];[2:v]setpts=PTS-STARTPTS,scale=230x160[3];[3:v]setpts=PTS-STARTPTS,scale=230x160[4];[4:v]setpts=PTS-STARTPTS,scale=230x160[5];[5:v]setpts=PTS-STARTPTS,scale=230x160[6];[6:v]setpts=PTS-STARTPTS,scale=230x160[7];[7:v]setpts=PTS-STARTPTS,scale=230x160[8];[base][1]overlay=shortest=1[tmp1];[tmp1][2]overlay=shortest=1:x=230[tmp2];[tmp2][3]overlay=shortest=1:x=460[tmp3];[tmp3][4]overlay=shortest=1:y=160[tmp4];[tmp4][5]overlay=shortest=1:x=230:y=160[tmp5];[tmp5][6]overlay=shortest=1:x=460:y=160[tmp6];[tmp6][7]overlay=shortest=1:y=320[tmp7];[tmp7][8]overlay=shortest=1:x=230:y=320\" mergeOut.mp4","ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 -i 4.mp4 -i 5.mp4 -i 6.mp4 -i 7.mp4  -i 8.mp4 -i 9.mp4 -filter_complex \"nullsrc=size=690x480[base];[0:v]setpts=PTS-STARTPTS,scale=230x160[1];[1:v]setpts=PTS-STARTPTS,scale=230x160[2];[2:v]setpts=PTS-STARTPTS,scale=230x160[3];[3:v]setpts=PTS-STARTPTS,scale=230x160[4];[4:v]setpts=PTS-STARTPTS,scale=230x160[5];[5:v]setpts=PTS-STARTPTS,scale=230x160[6];[6:v]setpts=PTS-STARTPTS,scale=230x160[7];[7:v]setpts=PTS-STARTPTS,scale=230x160[8];[8:v]setpts=PTS-STARTPTS,scale=230x160[9];[base][1]overlay=shortest=1[tmp1];[tmp1][2]overlay=shortest=1:x=230[tmp2];[tmp2][3]overlay=shortest=1:x=460[tmp3];[tmp3][4]overlay=shortest=1:y=160[tmp4];[tmp4][5]overlay=shortest=1:x=230:y=160[tmp5];[tmp5][6]overlay=shortest=1:x=460:y=160[tmp6];[tmp6][7]overlay=shortest=1:y=320[tmp7];[tmp7][8]overlay=shortest=1:x=230:y=320[tmp8];[tmp8][9]overlay=shortest=1:x=460:y=320\" mergeOut.mp4",};//剪切命令private String shearCmd = "ffmpeg -i %s -ss 0 -c copy -t %s  -codec copy %s";//拼接命令private String jointCmd = "ffmpeg -f concat -safe 0 -i %s -c copy %s";//提取一帧转为图片private String cropCmd ="ffmpeg -i %s -frames:v 1 %s";//剪辑固定时长视频public void shearVideo(String source, Long dur, String outputName) {dur = dur / 1000;outputName = outputName.replace(":", "");String outputPath = source + outputName;String tmpCMD = String.format(shearCmd, source + "tmp.mp4", dur, outputPath);CMDExecteUtil excutor = new CMDExecteUtil();excutor.exec(tmpCMD);}//拼接多个视频public void jointVideo(String filePath, String outPath) {String tmpCMD = String.format(jointCmd, filePath, outPath);CMDExecteUtil excutor = new CMDExecteUtil();excutor.exec(tmpCMD);}//合并多个视频public void mergeVideo(List<String> paths, String outPutPath) {String cmd = mergeCmd[paths.size() - 1];String viPath = "";StringBuilder sb = new StringBuilder();for (String s : paths) {if (StringUtils.isEmpty(sb)) {sb.append("-i ").append(s);} else {sb.append(" ").append("-i ").append(s);}}String tmpCMD = String.format(cmd, sb.toString(), outPutPath + "merge.mp4");CMDExecteUtil excutor = new CMDExecteUtil();excutor.exec(tmpCMD);}//截取一帧public void cropImage(String streamPath,String outPath){String tmpCMD = String.format(cropCmd, streamPath, outPath);log.info("FFMPEG---"+tmpCMD);CMDExecteUtil excutor = new CMDExecteUtil();excutor.exec(tmpCMD);}
}

结尾:干活满满,喜欢就点个赞收藏吧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/757136.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙实战开发:【浏览器制作】

浏览器 介绍 本示例使用[ohos.systemparameter]接口和[Web组件]展示了一个浏览器的基本功能,展示网页&#xff0c;根据页面历史栈前进回退等。 效果预览 首页打开网址 使用说明: 连接Wifi&#xff0c;启动应用&#xff0c;展示默认页面内容;点击默认页面的图标跳转到对应…

C语言经典算法-7

文章目录 其他经典例题跳转链接36.排序法 - 改良的选择排序37.快速排序法&#xff08;一&#xff09;38.快速排序法&#xff08;二&#xff09;39.快速排序法&#xff08;三&#xff09;40.合并排序法 其他经典例题跳转链接 C语言经典算法-1 1.汉若塔 2. 费式数列 3. 巴斯卡三…

AnyGo for Mac最新激活版:位置模拟软件打破地域限制

AnyGo for Mac&#xff0c;一款专为Mac用户打造的位置模拟软件&#xff0c;让您能够轻松打破地域限制&#xff0c;畅享无限可能。 软件下载&#xff1a;AnyGo for Mac v7.0.0最新激活版 通过AnyGo&#xff0c;您可以随时随地模拟出任何地理位置&#xff0c;无论是国内热门景点还…

(三)pulsar可视化消息管理工具

官网&#xff1a;https://pulsar.apache.org/docs/3.2.x/administration-pulsar-manager/ 版本: 3.2.x 安装和配置 拉取容器 docker pull apachepulsar/pulsar-manager:v0.3.0运行容器&#xff1a; # pulsar消息管理工具 CURRENT_DIR$(cd dirname $0; pwd) BASE_DIR$(cd $(…

【07】进阶html5

HTML5 包含两个部分的更新,分别是文档和web api 文档 HTML5 元素表 元素语义化 元素语义化是指每个 HTML 元素都代表着某种含义,在开发中应该根据元素含义选择元素 元素语义化的好处: 利于 SEO(搜索引擎优化)利于无障碍访问利于浏览器的插件分析网页新增元素 多媒体…

手撕算法-判断是不是完全二叉树

描述&#xff1a;思路&#xff1a;采用层序遍历&#xff0c;找到一个为空的标记&#xff0c;如果后面还有值&#xff0c;就代表不是完全二叉树。代码&#xff1a; public boolean isCompleteTree (TreeNode root) {// write code hereif(root null) return true;Queue<Tree…

Go语言学习13-常见软件架构的实现

Go语言学习13-常见软件架构的实现 架构模式 An architectural pattern is a general, reusable solution to a commonly occurring problem in software architectural within a given context. ——wikipedia Pipe-Filter 架构 Pipe-Filter 模式 非常适合于数据处理及数据分…

[Qt学习笔记]Qt下使用Halcon实现采图时自动对焦的功能(Brenner梯度法)

目录 1、介绍2、实现方法2.1 算法实现过程2.2 模拟采集流程 3、总结4、代码展示 1、介绍 在机器视觉的开发中&#xff0c;现在有很多通过电机去做相机的聚焦调节&#xff0c;对比手工调节&#xff0c;自动调节效果更好&#xff0c;而且其也能满足设备自动的需求&#xff0c;尤…

HCIA ——VLAN实验

一 、 实验需求 1.PC1和PC3所在接口为access接口&#xff1b;属于vlan 2 PC2-4-5-6处于同一网段&#xff1b;其中PC2可以访问PC4-5-6 PC4可以访问PC5不能访问PC6 PC5不能访问PC6 3.PC1-PC3与PC2-4-5-6不在同一个网段 4.所有PC均使用DHCP获取IP地址&#xff0c;且PC1可以正常访问…

mysql之基本概念与安装

一 数据库的基本概念 1.1 数据 记录个体的信息 1.2 表 存放信息的集合&#xff0c;行于与列 1.3 数据库 数据库就是表的集合。它是以一定的组织方式存储的相互有关的数据集合 1.4 数据库管理系统 数据库管理系统&#xff08;DatabaseManagementSystem&#xff0c;DBMS&…

音视频实战--音视频编码

1、查找所需的编码器–avcodec_find_encoder或avcodec_find_encoder_by_name 音频编码和视频编码流程基本相同&#xff0c;使用音频编码器则可以编码音频数据&#xff0c;使用视频编码器则可以编码视频数据。 /* 指定的编码器 ID 查找对应的编码器。可以通过这个函数来获取特…

Flutter 初始WidgetState 简单应用案例分析

本系列文章主要整理Flutter的知识汇总&#xff0c;由浅入深&#xff0c;从Widget的搭建到其中的原理。本文还是围绕Widget在开发中应用和理解。 关于Flutter环境配置和首次创建可以参考前面文章。链接如下&#xff1a; Flutter 安装部署与认识Dart语言 Flutter 使用AndroidS…

MySQL 搭建双主复制服务 并 通过 HAProxy 负载均衡

一、MySQL 搭建双主复制高可用服务 在数据库管理中&#xff0c;数据的备份和同步是至关重要的环节&#xff0c;而双主复制&#xff08;Dual Master Replication&#xff09;作为一种高可用性和数据同步的解决方案&#xff0c;通过让两个数据库实例同时充当主服务器和从服务器&…

Tomcat(Win+Linux)安装教程

Windows环境安装 Tomcat安装及配置教程主要分为四步&#xff1a; 步骤一&#xff1a;确认自己是否已 安装JDK&#x1f50d; 步骤二&#xff1a;下载安装Tomcat 步骤三&#xff1a;Tomcat配置环境变量 步骤四&#xff1a;验证Tomcat配置是否成功 OK&#xff0c;我们开始&#x…

python 中 float 和 decimal 的区别

decimal --- 十进制定点和浮点运算 — Python 3.11.8 文档请参考官方说明文档&#xff1a; decimal --- 十进制定点和浮点运算 — Python 3.11.8 文档 举例&#xff1a; # 使用 Decimal 类型进行计算 from decimal import Decimaltotal_float 0.1 0.2 total_decimal Decim…

CMU 10-414/714: Deep Learning Systems --hw3

实现功能 在ndarray.py文件中完成一些python array操作 我们实现的NDArray底层存储就是一个一维向量&#xff0c;只不过会有一些额外的属性&#xff08;如shape、strides&#xff09;来表明这个flat array在维度上的分布。底层运算&#xff08;如加法、矩阵乘法&#xff09;都…

[LeetCode][LCR170]交易逆序对的总数

题目 LCR 170. 交易逆序对的总数 在股票交易中&#xff0c;如果前一天的股价高于后一天的股价&#xff0c;则可以认为存在一个「交易逆序对」。请设计一个程序&#xff0c;输入一段时间内的股票交易记录 record&#xff0c;返回其中存在的「交易逆序对」总数。 示例 1&#xf…

【VUE】前端阿里云OSS断点续传,分片上传

什么是OSS&#xff1a; 数据以对象&#xff08;Object&#xff09;的形式存储在OSS的存储空间&#xff08;Bucket &#xff09;中。如果要使用OSS存储数据&#xff0c;您需要先创建Bucket&#xff0c;并指定Bucket的地域、访问权限、存储类型等属性。创建Bucket后&#xff0c;您…

React - 实现菜单栏滚动

简介 本文将会基于react实现滚动菜单栏功能。 技术实现 实现效果 点击菜单&#xff0c;内容区域会自动滚动到对应卡片。内容区域滑动&#xff0c;指定菜单栏会被选中。 ScrollMenu.js import {useRef, useState} from "react"; import ./ScrollMenu.css;export co…

线程和进程的区别和联系

一、什么是进程 进程(Process), 是一个具有独立功能的程序关于某个数据集合的一次运行活动&#xff0c;是系统进行 【资源分配和调度】 的一个独立单位。 进程是【程序】的【一次执行】(是计算机中程序的执行过程&#xff0c;而不是计算机中的程序)进程是系统进行【资源分配和…