Spring Boot
引入 JavaCV
作視頻圖像處理,固然首選FFmpeg
了,內心碎碎念,開源的東西就是好用。因而啪啦啪啦編碼一成天,實現了RTMP流媒體推送
、每間隔時間截取幀圖片
、流媒體轉MP4保存後用於回放
三個主要功能。html
打完Jar包後一看,560M大小,天呢!!! 一會 exclusions
一下。java
碎碎念!!!bash
運行了一下,兩路RTSP流,很輕鬆!CPU佔用不到10%,內存1.1G,能夠接受。服務器
因而,果斷髮往服務器,而後啓動……兩路RTSP流,CPU果斷飄升到260%……完蛋!!!異步
因而開始調優,視頻解碼真心消耗資源,無奈中……ide
網上各種這種文章,這裏很少作介紹,通常就是兩步,首先尋找CPU高的線程;而後找到線程的記錄,看看有啥問題。學習
JavaCV
會對流媒體進行解析,這就很耗資源,無解的難題。測試
因而,最好的解決方案就是,不解析視頻。 FFmpeg
支持 codec copy
,而 JavaCV也能夠經過 AVPacket
實現。ui
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.bytedeco.javacv.*;
import org.bytedeco.ffmpeg.avcodec.AVPacket;
public class PacketRecorderTest {
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd__hhmmSSS");
private static final int RECORD_LENGTH = 5000;
private static final boolean AUDIO_ENABLED = false;
public static void main(String[] args) throws FrameRecorder.Exception, FrameGrabber.Exception {
String inputFile = "/home/usr/videos/VIDEO_FILE_NAME.mp4";
// Decodes-encodes
String outputFile = "/tmp/" + DATE_FORMAT.format(new Date()) + "_frameRecord.mp4";
PacketRecorderTest.frameRecord(inputFile, outputFile);
// copies codec (no need to re-encode)
outputFile = "/tmp/" + DATE_FORMAT.format(new Date()) + "_packetRecord.mp4";
PacketRecorderTest.packetRecord(inputFile, outputFile);
}
public static void frameRecord(String inputFile, String outputFile) throws FrameGrabber.Exception, FrameRecorder.Exception {
int audioChannel = AUDIO_ENABLED ? 1 : 0;
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile);
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, 1280, 720, audioChannel);
grabber.start();
recorder.start();
Frame frame;
long t1 = System.currentTimeMillis();
while ((frame = grabber.grabFrame(AUDIO_ENABLED, true, true, false)) != null) {
recorder.record(frame);
if ((System.currentTimeMillis() - t1) > RECORD_LENGTH) {
break;
}
}
recorder.stop();
grabber.stop();
}
public static void packetRecord(String inputFile, String outputFile) throws FrameGrabber.Exception, FrameRecorder.Exception {
int audioChannel = AUDIO_ENABLED ? 1 : 0;
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile);
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, 1280, 720, audioChannel);
grabber.start();
recorder.start(grabber.getFormatContext());
AVPacket packet;
long t1 = System.currentTimeMillis();
while ((packet = grabber.grabPacket()) != null) {
recorder.recordPacket(packet);
if ((System.currentTimeMillis() - t1) > RECORD_LENGTH) {
break;
}
}
recorder.stop();
grabber.stop();
}
}
複製代碼
感覺一下,仍是好用的。可是在進行流媒體的轉換時,總會出現各類問題。編碼
碎碎念!!!
仍是直接使用 Process
調用 FFmpeg
吧!
import org.bytedeco.javacpp.Loader;
import java.io.IOException;
public class CommondTest {
public static void main(String[] args) throws IOException, InterruptedException {
String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class);
String from = "rtsp://*************";
String to = "rtmp://********************";
ProcessBuilder pb = new ProcessBuilder(ffmpeg,
"-i", from, "-codec", "copy", "-f", "flv", "-y", to);
Process process = pb.inheritIO().start();
process.waitFor();
}
}
複製代碼
測試了一下,仍是好用的,那麼能夠開始改造了!
學習知識的最好途徑永遠是官網,由於權威
ffmpeg Documentation
在用java調用的時候,要設置好輸出,防止由於命令行的輸出流沒有被讀取而形成堵塞!
因此,仍是把ffmpeg的日誌級別設置一下吧,-loglevel quiet
終於下來了!
技術問題解決後,剩下的截圖,調用某度雲的故障識別接口並實時報警……
碎碎念!!!某度雲提供了5個圖片故障識別的接口,每張截圖得分別調用5個接口……,看來必然要使用異步了……
4 Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GHz
複製代碼
MemTotal: 8008500 kB
複製代碼
1
複製代碼
cpu cores : 2
複製代碼
4
複製代碼
top - 18:14:33 up 17 days, 7 min, 1 user, load average: 1.03, 0.92, 0.80
Tasks: 105 total, 1 running, 104 sleeping, 0 stopped, 0 zombie
%Cpu(s): 20.3 us, 0.6 sy, 0.0 ni, 78.7 id, 0.0 wa, 0.0 hi, 0.3 si, 0.1 st
KiB Mem : 8008500 total, 120588 free, 1940580 used, 5947332 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 5368844 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
28360 root 20 0 6307744 1.3g 24644 S 83.4 16.4 42:04.91 java
複製代碼
RX packets 234768965 bytes 315037366631 (293.4 GiB)
TX packets 224227493 bytes 113722298707 (105.9 GiB)
複製代碼