前言
javacv对ffmpeg、opencv等c/c++库(具体哪些库参考源码地址)进行了封装,提供了友好的基于java的访问接口。下面来看下这些接口:
Frame 数据帧
对音频帧、视频帧和数据帧的抽象,有三种类型的数据帧:
public static enum Type {
VIDEO,
AUDIO,
DATA
}
Frame是音视频数据的容器,可以通过FrameConverter<F>
转换到其他平台的数据结构类。
FrameConverter 帧转换器
帧数据转换器,用于各种平台数据类之间的转换。它的实现有:
可以转成Android的Bitmap、Java的BufferedImage、JavaFX的Image、OpenCV的IplImage&Mat&org.opencv.core.Mat等。可以看出这个库可用于Android和Java两个平台。
FrameGrabber 帧抓取器
帧抓取器从从音视频源中抓取帧(视频帧,音频帧,数据帧等)数据,是数据提取过程。它的实现根据平台的不同也是多种多样,版本1.5.3如下:
根据具体场景(设备,文件,流等)的不同,可以选择最合适的帧抓取器。
常用的模版代码是一个循环不断拉取帧,然后进行处理,下面展示用ffmpeg帧抓取器获取视频文件的代码如下:
public static <T> List<T> videoFrameMap(String videoFile, BiFunction<Integer, Frame, T> f) {
return Try.ofCallable(new Callable<List<T>>() {
@Override
public List<T> call() throws Exception {
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(new File(videoFile));
grabber.start();
int frameCount = grabber.getLengthInVideoFrames();
List<T> res = new ArrayList<>();
int i = 0;
while (i < frameCount) {
Frame frame = grabber.grabImage();
if (frame != null) {
res.add(f.apply(i, frame.clone()));
}
++i;
}
grabber.stop();
return res;
}
}).get();
}
FrameRecorder 帧记录器
帧记录器把帧数据记录到文件和流中。版本1.5.3的实现有两个:
下面演示从一个视频文件中读取视频流,然后进行灰度处理,最后推到rtmp服务器上:
public static void videoFrameRedirect(String src, String dst, Function<Frame, Frame> f) {
Try.ofCallable(new Callable<Object>() {
@Override
public Object call() throws Exception {
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(src);//使用ffmpeg抓取器
grabber.start();//开启抓取器
int width = grabber.getImageWidth();
int height = grabber.getImageHeight();
FrameRecorder recorder = FrameRecorder.createDefault(dst, width, height);
//设置视频编码和格式
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // avcodec.AV_CODEC_ID_H264,编码
recorder.setFormat("flv");//封装格式,如果是推送到rtmp就必须是flv封装格式
recorder.setFrameRate(grabber.getFrameRate());
recorder.start();//开启记录器
while (true) {
Frame frame = grabber.grabImage();
if (frame == null) {
break;
}
System.err.println(frame.timestamp);
recorder.setTimestamp(frame.timestamp);
//进行图片处理
if (f != null) {
frame = f.apply(frame);
}
recorder.record(frame);
}
recorder.stop();
recorder.release();
grabber.stop();
grabber.release();
return null;
}
}).get();
}
使用groovy测试:
import org.bytedeco.javacv.Frame
import org.bytedeco.javacv.Java2DFrameUtils
import org.bytedeco.opencv.opencv_core.Mat
import static org.bytedeco.opencv.global.opencv_imgproc.COLOR_BGR2GRAY
import static org.bytedeco.opencv.global.opencv_imgproc.cvtColor
void testVideoRedirect() {
VideoFrameRedirect.videoFrameRedirect("D:\\pet.mp4", "rtmp://localhost:1935/live/abc", new Function<Frame, Frame>() {
@Override
Frame apply(Frame frame) {
Mat dst = new Mat()
cvtColor(Java2DFrameUtils.toMat(frame), dst, COLOR_BGR2GRAY)
return Java2DFrameUtils.toFrame(dst)
}
})
}