前言
查看了相關文章然後一筆一筆打代碼再調試成功出結果,
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);
}
}