前言
不知道怎么使用配置javacv的看上一篇文章----使用javacv中的ffmpeg实现录屏,结果连运行都失败了,现在终于解决了
这篇博客是上篇博客代码的改进,因为上篇博客的代码有很多bug。

思路
开启两个周期都为1帧时长的线程,通过Robot类进行抓屏,Sound API进行抓取音频,然后使用ffmpeg记录到mp4文件中。

代码实现:

package com;import java.awt.AWTException;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
import java.util.Scanner;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameRecorder.Exception;
import org.bytedeco.javacv.Java2DFrameConverter;public class VideoRecord {//线程池 screenTimer,录制视频private ScheduledThreadPoolExecutor screenTimer;//获取屏幕尺寸private final Rectangle rectangle = new Rectangle(Constant.WIDTH, Constant.HEIGHT); // 截屏的大小//视频类 FFmpegFrameRecorderprivate FFmpegFrameRecorder recorder;private Robot robot;//线程池 exec,录制音频private ScheduledThreadPoolExecutor exec;private TargetDataLine line;private AudioFormat audioFormat;private DataLine.Info dataLineInfo;///是否开启录音设备private boolean isHaveDevice = true;private long startTime = 0;private long videoTS = 0;private long pauseTimeStart = 0;//开始暂停的时间private long pauseTime = 0;//暂停的时长private double frameRate = 5;private String state="start";//录制状态:start正在录制,pause暂停录制,stop停止录制public String getState() {return state;}public VideoRecord(String fileName, boolean isHaveDevice) {// TODO Auto-generated constructor stubrecorder = new FFmpegFrameRecorder(fileName + ".mp4", Constant.WIDTH, Constant.HEIGHT);
//       recorder.setVideoCodec(avcodec.AV_CODEC_ID_H265); // 28recorder.setVideoCodec(avcodec.AV_CODEC_ID_MPEG4); // 13recorder.setFormat("mp4");// recorder.setFormat("mov,mp4,m4a,3gp,3g2,mj2,h264,ogg,MPEG4");recorder.setSampleRate(44100);recorder.setFrameRate(frameRate);recorder.setVideoQuality(0);recorder.setVideoOption("crf", "23");// 2000 kb/s, 720P视频的合理比特率范围recorder.setVideoBitrate(1000000);/*** 权衡quality(视频质量)和encode speed(编码速度) values(值): ultrafast(终极快),superfast(超级快),* veryfast(非常快), faster(很快), fast(快), medium(中等), slow(慢), slower(很慢),* veryslow(非常慢)* ultrafast(终极快)提供最少的压缩(低编码器CPU)和最大的视频流大小;而veryslow(非常慢)提供最佳的压缩(高编码器CPU)的同时降低视频流的大小* 参考:https://trac.ffmpeg.org/wiki/Encode/H.264 官方原文参考:-preset ultrafast as the* name implies provides for the fastest possible encoding. If some tradeoff* between quality and encode speed, go for the speed. This might be needed if* you are going to be transcoding multiple streams on one machine.*/recorder.setVideoOption("preset", "slow");recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P); // yuv420precorder.setAudioChannels(2);recorder.setAudioOption("crf", "0");// Highest qualityrecorder.setAudioQuality(0);recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);try {robot = new Robot();} catch (AWTException e) {// TODO Auto-generated catch blocke.printStackTrace();}try {recorder.start();} catch (Exception e) {// TODO 自动生成的 catch 块e.printStackTrace();}if(isHaveDevice) {/*** float sampleRate:采样率;每秒采样数 ;* int sampleSizeInBits:采样位数;每个样本中的位数 ;* int channels:音频通道数,1为mono,2为立体声;* boolean signed;* boolean bigEndian:是否为大端存储;指示单个样本的数据是否以大字节顺序存储*/audioFormat = new AudioFormat(44100.0F, 16, 2, true, false);dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat);try {line = (TargetDataLine) AudioSystem.getLine(dataLineInfo);} catch (LineUnavailableException e1) {// TODO Auto-generated catch blockSystem.out.println("未获得音频线路,"+e1);}}this.isHaveDevice = isHaveDevice;}/*** 开始录制*/public void start() {state="start";if (startTime == 0) {startTime = System.currentTimeMillis();}if(pauseTimeStart!=0) {//计算暂停的时长pauseTime=System.currentTimeMillis()-pauseTimeStart;pauseTimeStart=0;//归零}else {//没有暂停过,暂停时长为0pauseTime=0;}// 如果有录音设备则启动录音线程if (isHaveDevice) {new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubSoundCaputre();}}).start();}//录屏screenCaptrue();}//开启录屏的线程private void screenCaptrue() {// 录屏screenTimer = new ScheduledThreadPoolExecutor(1);/**** 参数:*   command - 要执行的任务 initialDelay - 延迟第一次执行的时间 ,延迟一帧的时间,我们设置的mp4的帧速为frameRate=每秒5帧,所以一帧的时间为 1秒/5period - 连续执行之间的时期 ,执行周期,为1帧的时间unit - initialDelay和period参数的时间单位,TimeUnit.MILLISECONDS为千分之一秒,就是1毫秒*/screenTimer.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {BufferedImage screenCapture = robot.createScreenCapture(rectangle); // 截屏BufferedImage videoImg = new BufferedImage(Constant.WIDTH, Constant.HEIGHT,BufferedImage.TYPE_3BYTE_BGR); // 声明一个BufferedImage用重绘截图Graphics2D videoGraphics = videoImg.createGraphics();// 创建videoImg的Graphics2DvideoGraphics.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);videoGraphics.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,RenderingHints.VALUE_COLOR_RENDER_SPEED);videoGraphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);videoGraphics.drawImage(screenCapture, 0, 0, null); // 重绘截图Java2DFrameConverter java2dConverter = new Java2DFrameConverter();Frame frame = java2dConverter.convert(videoImg);try {//计算总时长videoTS = 1000L*(System.currentTimeMillis()-startTime-pauseTime);// 检查偏移量if (videoTS > recorder.getTimestamp()) {recorder.setTimestamp(videoTS);}recorder.record(frame); // 录制视频} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}// 释放资源videoGraphics.dispose();videoGraphics = null;videoImg.flush();videoImg = null;java2dConverter = null;screenCapture.flush();screenCapture = null;}}, (int) (1000 / frameRate), (int) (1000 / frameRate), TimeUnit.MILLISECONDS);}/*** 开启抓取声音的线程*/public void SoundCaputre() {    try {if(!line.isRunning()){line.open(audioFormat);line.start();}} catch (LineUnavailableException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}final int sampleRate = (int) audioFormat.getSampleRate();final int numChannels = audioFormat.getChannels();int audioBufferSize = sampleRate * numChannels;final byte[] audioBytes = new byte[audioBufferSize];exec = new ScheduledThreadPoolExecutor(1);exec.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {try {int nBytesRead = line.read(audioBytes, 0, line.available());int nSamplesRead = nBytesRead / 2;short[] samples = new short[nSamplesRead];// Let's wrap our short[] into a ShortBuffer and// pass it to recordSamplesByteBuffer.wrap(audioBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(samples);ShortBuffer sBuff = ShortBuffer.wrap(samples, 0, nSamplesRead);// recorder is instance of// org.bytedeco.javacv.FFmpegFrameRecorderrecorder.recordSamples(sampleRate, numChannels, sBuff);// System.gc();} catch (org.bytedeco.javacv.FrameRecorder.Exception e) {e.printStackTrace();}}}, (int) (1000 / frameRate), (int) (1000 / frameRate), TimeUnit.MILLISECONDS);}/*** 暂停录制*/public void pause() {state="pause";screenTimer.shutdownNow();screenTimer = null;if (isHaveDevice) {exec.shutdownNow();exec = null;}pauseTimeStart = System.currentTimeMillis();}/*** 停止录制*/public void stop() {state="stop";if (null != screenTimer) {screenTimer.shutdownNow();}try {if (isHaveDevice) {if (null != exec) {exec.shutdownNow();}if (null != line) {line.stop();line.close();}dataLineInfo = null;audioFormat = null;}recorder.stop();recorder.release();recorder.close();screenTimer = null;// screenCapture = null;} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}public static void main(String[] args) {VideoRecord videoRecord = new VideoRecord("C:\\Users\\Administrator\\Desktop\\视频2", true);videoRecord.start();System.out.println("****start继续录制,pause暂停录制,stop停止录制****");while (true) {Scanner sc = new Scanner(System.in);if(sc.hasNext()) {String cmd=sc.next();if (cmd.equalsIgnoreCase("stop")) {videoRecord.stop();System.out.println("****已经停止录制****");break;}if (cmd.equalsIgnoreCase("pause")) {if(videoRecord.getState().equals("pause")) {System.out.println("*error:已经暂停,请勿重复操作pause*");continue;}videoRecord.pause();System.out.println("****已暂停,start继续录制,stop结束录制****");}if (cmd.equalsIgnoreCase("start")) {if(videoRecord.getState().equals("start")) {System.out.println("*error:请勿重复操作start*");continue;}videoRecord.start();System.out.println("****正在录制****");}}}}}class Constant{public final static int WIDTH=Toolkit.getDefaultToolkit().getScreenSize().width;public final static int HEIGHT=Toolkit.getDefaultToolkit().getScreenSize().height;}

javacv利用ffmpeg实现录屏和录音,输出为mp4文件相关推荐

  1. Android录屏并利用FFmpeg转换成gif(四) 将mp4文件转换成gif文件

    Android录屏并利用FFmpeg转换成gif(四) 写博客时经常会希望用一段动画来演示app的行为,目前大多数的做法是在电脑上开模拟器,然后用gif录制软件录制模拟器屏幕,对于非开发人员来讲这种方 ...

  2. FFmpeg windows 录屏(录像)录音 实测

    如何给对桌面录像录音? 免费的FFmpeg功能强大, 不输给任何收费的录像软件(如KK录像机) 首先下载 FFmpeg 解压到任意目录并设置一下环境变量 ffmpeg -version 能打印版本号即 ...

  3. 利用FFmpeg实现录屏、直播推流、音频视频格式转换、剪裁等功能

    一.FFmpeg简介. 二.FFmpeg常用参数及命令. 三.FFmpeg在Unity 3D中的使用. 1.FFmpeg 录屏. 2.FFmpeg 推流. 3.FFmpeg 其他功能简述. 一.FFm ...

  4. QT软件开发-基于FFMPEG设计录屏与rtsp、rtmp推流软件(支持桌面与摄像头)(一)

    QT软件开发-基于FFMPEG设计录屏与rtsp.rtmp推流软件(支持桌面与摄像头)(一) https://xiaolong.blog.csdn.net/article/details/126954 ...

  5. QT软件开发-基于FFMPEG设计录屏与rtsp、rtmp推流软件(支持桌面与摄像头)(四)

    QT软件开发-基于FFMPEG设计录屏与rtsp.rtmp推流软件(支持桌面与摄像头)(一) https://xiaolong.blog.csdn.net/article/details/126954 ...

  6. electron+ffmpeg+VUE3 录屏 推流

    录屏推流 webrtc播放 简化版obs推流 electron+ffmpeg+vue3 原创录屏推流源代码 npm install 安装成功后 npm run dev 就可以跑起来 功能 录屏推流,录 ...

  7. 前端使用html5、ffmpeg实现录屏摄像等功能

    前段时间做一个windows的桌面应用,vue + electron,涉及到录屏和摄像功能,网上相关的文档蛮少的给需要的人一些参考 如果文章描写有误或者还有更好的方法,请留言告诉我,笔芯 (´▽`ʃ♡ ...

  8. 通过ffmpeg进行录屏直播

    本来我是打算通过ffmpeg进行图片和成视频的,但是不知道什么原因编码出来后,都会只剩三秒,后来发现,可以直接通过ffmpeg进行录屏. 首先就是先下载ffmpeg.这里我将dll文件和exe文件放到 ...

  9. html5桌面录制,前端使用html5、ffmpeg实现录屏摄像等功能

    前段时间做一个windows的桌面应用,vue + electron,涉及到录屏和摄像功能,网上相关的文档蛮少的给需要的人一些参考 如果文章描写有误或者还有更好的方法,请留言告诉我,笔芯 (´▽`ʃ♡ ...

最新文章

  1. 【Android RTMP】RTMPDumb 源码导入 Android Studio ( 交叉编译 | 配置 CMakeList.txt 构建脚本 )
  2. CRM中间件里parent not ok的错误消息如何处理
  3. 《C++ Primer》13.1.4节练习
  4. article之api文档
  5. C语言程序设计孙家啸第一版,广东年月自考各专业课程使用教材.doc
  6. java 类型转换 安全_JAVA 类型转换指令
  7. [深度学习]生成对抗网络的实践例子
  8. Java进阶之路——从初级程序员到架构师,从小工到专家必会的技能
  9. 数字通信同步技术的matlab与fpga实现_数字通信电缆行业规模情况及趋势分析(附报告目录)...
  10. pcl之编译VTK时CMAKE中找不到Qt5X11Extras
  11. 自动化测试必备实用工具,帮你提高工作效率 | 码云周刊第 88 期
  12. Windows下让Tomcat6定时重启服务的方法
  13. 程序员修炼之道(第2版)
  14. python import 搜索包路径的机制,以及添加自定义python包的方法
  15. android 服务自动运行怎么办,Android服务开机自动运行
  16. 【情报分享1234】来自海莲花组织的道歉,然后再给你扔了个恶意文档
  17. ip地址与交换机工作原理
  18. 如何查看电脑ip地址
  19. 通过摄像机视频设备或者流媒体服务器SDK获取到数据转换成RTMP流实现网页手机微信播放
  20. 微信公众号最佳实践 ( 10.2)回复QQ表情和Emoji表情

热门文章

  1. C++整数除法保留小数
  2. POJ2676数独游戏题解
  3. FinOps实践,从降本增效说起
  4. [附源码]SSM计算机毕业设计基于的楼盘销售管理系统论文2022JAVA
  5. 首网推荐!自动化测试——频次最高的23道jmeter面试题及答案!
  6. 用three.js写一个小场景
  7. quartusⅡ的原理仿真及代码仿真
  8. 蓝牙耳机年终盘点:十大商城热卖高颜值蓝牙耳机排行榜
  9. 华为硬件工程师手册_浅析华为的元器件选型
  10. labelme解析为yolov5