前言
查看了相关文章然后一笔一笔打代码再调试成功出结果,
eguid的博客
不保证代码能够原封不动就能运行,
这里做一下记录。
ps:代码内容有改动,原版的可以看原作者的。
代码内容
package net.w2p.JCVStudio.zhiboStudy;
import javafx.embed.swing.SwingFXUtils;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.*;
import org.bytedeco.javacv.Frame;
import org.bytedeco.opencv.global.opencv_core;
import org.bytedeco.opencv.global.opencv_imgproc;
import org.bytedeco.opencv.opencv_core.CvScalar;
import org.bytedeco.opencv.opencv_core.IplImage;
import org.bytedeco.opencv.opencv_core.Point;
import org.bytedeco.opencv.opencv_core.Scalar;
import org.bytedeco.opencv.opencv_imgproc.CvFont;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.util.concurrent.ConcurrentHashMap;
import static org.bytedeco.opencv.global.opencv_core.IPL_DEPTH_8U;
import static org.bytedeco.opencv.global.opencv_imgproc.*;
/***
* 收流器实现,录制流媒体服务器的rtsp/rtmp视频文件(基于javaCV-FFMPEG)
* https://blog.csdn.net/eguid_1/article/details/52680802
* 顺便操作画面,进行文字打水印。
* **/
public class Lesson03 {
private ConcurrentHashMap<String,Object> mapParas=new ConcurrentHashMap<>(55);
/**
* 按帧录制视频
*
* @param inputFile-该地址可以是网络直播/录播地址,也可以是远程/本地文件路径
* @param outputFile -该地址只能是文件地址,如果使用该方法推送流媒体服务器会报错,原因是没有设置编码格式
* @throws FrameGrabber.Exception
* @throws FrameRecorder.Exception
* @throws org.bytedeco.javacv.FrameRecorder.Exception
*/
public void frameRecord(String inputFile, String outputFile, int audioChannel)
throws Exception {
boolean isStart=true;//该变量建议设置为全局控制变量,用于控制录制结束
// 获取视频源
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile);
// 流媒体输出地址,分辨率(长,高),是否录制音频(0:不录制/1:录制)
FFmpegFrameRecorder recorder=new FFmpegFrameRecorder(outputFile,1280,720,audioChannel);
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // avcodec.AV_CODEC_ID_H264,编码
// recorder.setFormat("flv");
recorder.setFormat("flv");//封装格式,如果是推送到rtmp就必须是flv封装格式
recorder.setPixelFormat(0);
recorder.setFrameRate(25);
recorder.setVideoOption("preset", "ultrafast");
recorder.setVideoOption("tune", "zerolatency");
recorder.setVideoOption("fflags", "nobuffer");
recorder.setVideoOption("analyzeduration", "0");
// 开始取视频源
mapParas.put("s",true);
recordByFrame(grabber, recorder);
}
public static Mat bufferedImageToMat(BufferedImage bi) {
Mat mat = new Mat(bi.getHeight(), bi.getWidth(), CvType.CV_8UC3);
byte[] data = ((DataBufferByte) bi.getRaster().getDataBuffer()).getData();
mat.put(0, 0, data);
return mat;
}
public void recordByFrame(FFmpegFrameGrabber grabber,FFmpegFrameRecorder recorder) throws Exception{
//javacv提供的转换器,方便mat转换为Frame
OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
final Java2DFrameConverter frameConverter = new Java2DFrameConverter(); try{
grabber.start();
recorder.start();
Frame frame=null;
boolean status=(Boolean) mapParas.get("s");
int index=0;
//--在帧上面添加文字。
CvFont font = new CvFont();
cvInitFont(font, CV_FONT_HERSHEY_PLAIN, 2.0, 2.0, 2, 2, CV_AA);
String logoText="我打了水印";//水印文字
// 水印文字位置
org.bytedeco.opencv.opencv_core.Point point = new Point(10, 50);
// 颜色,使用黄色
Scalar scalar = new Scalar(0, 255, 255, 0);
OpenCVFrameConverter.ToIplImage iplConverter = new OpenCVFrameConverter.ToIplImage();
Java2DFrameConverter java2dConverter = new Java2DFrameConverter();
while(status&&(frame=grabber.grab())!=null&&!Thread.interrupted()){
final BufferedImage bufferedImage = frameConverter.convert(frame);
//--画面合成
if(bufferedImage!=null){
mark(bufferedImage,logoText,Color.RED,40,50);
IplImage iplImage = iplConverter.convert(java2dConverter.convert(bufferedImage));
// cvPutText(iplImage/*IplImage*/, logoText, opencv_core.cvPoint(10,50),
// font,
// CvScalar.RED);
/***
* bufferedImage 转换为 mat 以便进行图形操作
* **/
// Mat newMat = bufferedImageToMat(bufferedImage);
/**添加文字上去**/
// IplImage bgrImage = IplImage.create(frame.imageWidth, frame.imageHeight,IPL_DEPTH_8U, 3);;
index++;
System.out.println("第几帧了:"+index);
if(iplImage!=null){
//--录入画面
recorder.record(converter.convert(iplImage));
}
}
if(frame.samples!=null){
//--录入声音
recorder.recordSamples(frame.samples);
}
//--如果不需要对画面和声音做合成,直接用record(frame)即可。
}
System.out.println("结束了,进行相关收尾。");
grabber.stop();
grabber.release();
recorder.stop();
recorder.release();
}
catch (Exception ed){
ed.printStackTrace();
}
finally {
if(grabber!=null){
grabber.stop();
grabber.release();
}
if(recorder!=null){
recorder.stop();
recorder.release();
}
}
}
// 加文字水印
public void mark(BufferedImage bufImg, Image img, String text, Font font, Color color, int x, int y) {
Graphics2D g = bufImg.createGraphics();
g.drawImage(img, 0, 0, bufImg.getWidth(), bufImg.getHeight(), null);
g.setColor(color);
g.setFont(font);
g.drawString(text, x, y);
g.dispose();
}
// 加文字水印
public void mark(BufferedImage bufImg, String text, Color color, int x, int y) {
Graphics2D g = bufImg.createGraphics();
Font currentFont = g.getFont();
Font newFont = currentFont.deriveFont(currentFont.getSize() * 2F);
g.setFont(newFont);
g.setColor(color);
g.drawString(text, x, y);
g.dispose();
}
public static void main(String[] args) throws Exception {
/**
* 本次内容实现了,普通视频-》推送到直播流
* 直播流-》保存到本地
* 直播流-》转推其他直播流
* **/
Lesson03 test=new Lesson03();
final String inputFile="/home/too-white/temp/a02.mp4";
final String outFile="/home/too-white/temp/lesson03_output.flv";
final String rtmpUrl="rtmp://localhost/live/livestream";
/**
* 推荐使用的rtmp直播平台
* https://blog.csdn.net/zhichaosong/article/details/89053009
* **/
final String rtmpOnlineUrl="rtmp://202.69.69.180:443/webcast/bshdlive-pc";
// test.frameRecord(inputFile,outFile,1);
// test.frameRecord(inputFile,rtmpUrl,1);
// test.frameRecord(rtmpOnlineUrl,outFile,1);
test.frameRecord(rtmpOnlineUrl,rtmpUrl,1);
}
}