JavaCV录屏,云游戏串流的一个模块
dshow采集音频,因为暂时不会别的更好的方法,gdigrab采集视频也是因为效果比dshow好但是不会更好的,
采用多线程可以避免出现缓冲溢出的情况
[dshow @ 000001c47844cf80] real-time buffer [virtual-audio-capturer] [audio input] too full or near too full (87% of size: 3041280 [rtbufsize parameter])! frame dropped!
dshow录屏插件下载地址:
下载运行安装即可,可以全屏录制视频也可录制音频
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
public class AV_Thread {
public static void main(String[] args) throws FFmpegFrameGrabber.Exception, FFmpegFrameRecorder.Exception {
//初始化
FFmpegFrameGrabber a_grabber = new FFmpegFrameGrabber("audio=virtual-audio-capturer");
a_grabber.setFormat("dshow");
a_grabber.start();
System.out.println("音频抓取器初始化完成");
FFmpegFrameGrabber v_grabber = new FFmpegFrameGrabber("desktop");
v_grabber.setFormat("gdigrab");
v_grabber.setFrameRate(30);
v_grabber.start();
System.out.println("视频抓取器初始化完成");
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder("src/main/resources/video/AV_Thread.flv",
v_grabber.getImageWidth(),
v_grabber.getImageHeight());
recorder.setPixelFormat(avutil.AV_PIX_FMT_NV12);//intel核显编码仅支持nv12和p010le
recorder.setVideoCodecName("h264_qsv");//硬件编码h264
recorder.setVideoBitrate(2000 * 1000);//码率,这里是2000kb/s
recorder.setMaxBFrames(0);//禁用B帧,降低延迟
recorder.setFormat("flv");//封装格式
recorder.setGopSize(30 * 3);//关键帧间距
recorder.setFrameRate(30);//帧率
recorder.setInterleaved(true);
recorder.setVideoOption("tune", "zerolatency");//设置预设,zerolatency表示零延迟,适用于实时视频会议
//ultrafast,superfast,veryfast,faster,fast,medium,slow,slower,veryslow
recorder.setVideoOption("preset", "veryfast");//编码速度,gpu编码最快是veryfast
recorder.setVideoOption("crf", "28");//动态码率,取值范围0-51,建议17-28,17或18即可获得视觉上与无损无区别的画面,但算法上经过有损压缩
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);//编码格式
recorder.setAudioBitrate(320 * 1000);//固定码率
recorder.setAudioOption("vbr", "1");//可变比特率,1-5,1最低,5最高
recorder.setAudioChannels(2);//声道
recorder.setSampleRate(48000);//采样率
recorder.start();
System.out.println("录制器初始化完成");
//创建两个线程
Thread v_Record = new Thread(() -> {
System.out.println("视频线程启动");
Frame a_frame = null;
while (true) {
try {
if ((a_frame = a_grabber.grabSamples()) != null) {
recorder.recordSamples(48000, 2, a_frame.samples);
} else {
break;
}
} catch (FFmpegFrameGrabber.Exception e) {
throw new RuntimeException(e);
} catch (FFmpegFrameRecorder.Exception e) {
throw new RuntimeException(e);
}
}
});
Thread a_Record = new Thread(() -> {
System.out.println("音频线程启动");
Frame v_frame = null;
while (true) {
try {
if ((v_frame = v_grabber.grabImage()) != null) {
recorder.recordImage(v_frame.imageWidth,
v_frame.imageHeight,
v_frame.imageDepth,
v_frame.imageChannels,
v_frame.imageStride,
v_grabber.getPixelFormat(),
v_frame.image);
} else {
break;
}
} catch (FFmpegFrameGrabber.Exception e) {
throw new RuntimeException(e);
} catch (FFmpegFrameRecorder.Exception e) {
throw new RuntimeException(e);
}
}
});
//启动执行
a_Record.start();
v_Record.start();
}
}