亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringBoot使用JavaCV處理rtsp流的示例代碼

 更新時間:2024年02月28日 10:57:06   作者:陸慢慢  
這篇文章主要為大家詳細(xì)介紹了SpringBoot使用JavaCV處理rtsp流,文中的示例代碼講解詳細(xì),具有一定的參考價值,感興趣的小伙伴可以跟隨小編一起了解一下

為什么寫這篇文章?

起因是項目中會用到rtsp流,用于分析視頻,和語音口令,還有就是控制攝像頭和做監(jiān)控時候做云端存儲功能。在網(wǎng)上找了一大圈發(fā)現(xiàn)這方面資料很少,資料中大部分人還是FFmpeg的安裝程序加代碼的方式實現(xiàn)。

其實JAVACV和OPENCV是非常強大的。當(dāng)然我了解的也不多(因為源碼沒有什么注釋!!理解起來很困難)。這篇文章最主要是針對于目前GPT和通義前問中提供的代碼進行糾錯和改正(特別是從rtsp中只取出音頻)。

部分代碼是他人提供,所以看起來會有差異,不過我會進行說明。

pom

<dependency>
	<groupId>org.bytedeco</groupId>
	<artifactId>javacv-platform</artifactId>
	<version>1.5.9</version>
</dependency>     

取出視頻保存為mp4代碼

    /**
     * 拉取指定時長的視頻-保存為mp4
     *
     * @param rtspUrl    流地址
     * @param duration   時長(秒)(TimeUnit Seconds)
     * @param outputFile 輸出位置
     */
    public static void videoPuller(String rtspUrl, int duration, String outputFile) {
        // 創(chuàng)建抓取器
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(rtspUrl);
        try {
            grabber.start();
            // 創(chuàng)建錄制器-設(shè)置的文件保存位置以及視頻畫面的寬度和高度
            FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, grabber.getImageWidth(), grabber.getImageHeight());
            recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // 設(shè)置視頻編解碼器
            recorder.setFormat("mp4"); // 設(shè)置視頻輸出格式

            // 設(shè)置音頻相關(guān)參數(shù)
            recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
            //這里直接寫2以及后續(xù)寫固定值也可以,當(dāng)然我們可以從grabber對象中g(shù)et出來
            //grabber.getAudioChannels();
            // recorder.setAudioChannels(grabber.getAudioChannels());
            recorder.setAudioChannels(2);
            //grabber.getSampleRate();
            recorder.setSampleRate(44100);
             //grabber.getAudioBitrate();
            recorder.setAudioBitrate(192000);
            recorder.start();

            Frame frame;
            long startTime = System.currentTimeMillis();
            long endTime = startTime + (duration * 1000);

            while ((frame = grabber.grabFrame()) != null && System.currentTimeMillis() <= endTime) {
                recorder.record(frame);
            }
            recorder.stop();
            grabber.stop();
            recorder.close();
            grabber.close();
        } catch (FrameGrabber.Exception | FrameRecorder.Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
		videoPuller("rtsp流地址",60, "D:\\va\\a.mp4");
    }

只保存音頻

import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.*;

/**
 * @author by Guoshun
 * @version 1.0.0
 * @description 提取音頻測試
 * @date 2024/2/26 16:57
 */

public class AudioExtractor {
    public static void extractAudioFromRtsp(String rtspUrl, String outputPath, int maxDurationSeconds) throws Exception {
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(rtspUrl);
        grabber.start();

        //1.從視頻流中取出讀取到的參數(shù)
        int audioChannels = grabber.getAudioChannels();//音頻通道
        int sampleRate = grabber.getSampleRate();
        int audioBitrate = grabber.getAudioBitrate();

        //創(chuàng)建recorder對象,設(shè)置編碼器和解碼器
        //這里也是所有AI都回答錯誤的地方
        //通義和GPT會回答為這樣
        //FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputPath, audioChannels, sampleRate);
        //上面這種錯誤傳參方式導(dǎo)致,audioChannels變?yōu)闉閷?,sampleRate為高
        FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputPath, audioChannels);
        recorder.setSampleRate(sampleRate);
        recorder.setAudioBitrate(audioBitrate);
        recorder.setAudioCodec(avcodec.AV_CODEC_ID_PCM_S16LE); // 使用PCM 16位小端模式編碼
        recorder.start();

        long startTime = System.currentTimeMillis();
        Frame frame;
        while ((frame = grabber.grabSamples()) != null && (System.currentTimeMillis() - startTime) / 1000 < maxDurationSeconds) {
            recorder.record(frame, 0);
        }

        recorder.stop();
        recorder.release();
        grabber.stop();
        grabber.release();
    }

    public static void main(String[] args) {
        try {
            extractAudioFromRtsp("rtsp://admin:12345qaz@192.168.20.164:554", "D:\\va\\audio.wav", 60);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

完整代碼,并行執(zhí)行

import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.*;
import org.bytedeco.opencv.opencv_core.Mat;

import javax.validation.constraints.NotNull;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static org.bytedeco.opencv.global.opencv_imgcodecs.imwrite;

/**
 * @author by Guoshun
 * @version 1.0.0
 * @description RTSP流處理
 * 流地址格式 rtsp://賬戶:密碼@ip地址
 * @date 2024/2/27 10:21
 */
public class RtspUtils {

    /**
     * 判斷流地址是否在線
     * @param rtspUrl 流地址
     * @return
     */
    public static Boolean isOnline(String rtspUrl) {
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(rtspUrl);
        try {
            grabber.setTimeout(3000);
            grabber.start();
            return true;
        } catch (FrameGrabber.Exception e) {
            e.printStackTrace();
        } finally {
            if (grabber != null) {
                close(grabber);
            }
        }
        return false;
    }

    /**
     * 關(guān)閉grabber
     *
     * @param grabber
     * @return
     */
    private static boolean close(@NotNull FFmpegFrameGrabber grabber) {
        try {
            grabber.close();
            return true;
        } catch (FrameGrabber.Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 拉取指定時長的視頻-保存為mp4
     * @param rtspUrl    流地址
     * @param duration   時長(秒)(TimeUnit Seconds)
     * @param outputFile 輸出位置
     */
    public static void videoPuller(String rtspUrl, int duration, String outputFile) {
        // 創(chuàng)建抓取器
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(rtspUrl);
        try {
            grabber.start();
            // 創(chuàng)建錄制器
            FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, grabber.getImageWidth(), grabber.getImageHeight());
            recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // 設(shè)置視頻編解碼器
            recorder.setFormat("mp4"); // 設(shè)置視頻輸出格式
            // 設(shè)置音頻相關(guān)參數(shù)
            recorder.setAudioChannels(2);
            recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
            recorder.setSampleRate(44100);
            recorder.setAudioBitrate(192000);
            recorder.start();
            Frame frame;
            long startTime = System.currentTimeMillis();
            long endTime = startTime + (duration * 1000);
            while ((frame = grabber.grabFrame()) != null && System.currentTimeMillis() <= endTime) {
                recorder.record(frame);
            }
            recorder.stop();
            grabber.stop();
            recorder.close();
            grabber.close();
        } catch (FrameGrabber.Exception | FrameRecorder.Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 提取音頻
     *
     * @param rtspUrl
     * @param outputPath
     * @param maxDurationSeconds
     */
    public static void extractAudioFromRtsp(String rtspUrl, String outputPath, int maxDurationSeconds) {
        try(
            FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(rtspUrl);
            FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputPath, 0,0)
        ){
            grabber.setOption("map", "0:a:0");
            grabber.start();
            //1.從視頻流中取出讀取到的參數(shù)
            int audioChannels = grabber.getAudioChannels();//音頻通道
            int sampleRate = grabber.getSampleRate();
            int audioBitrate = grabber.getAudioBitrate();
            //創(chuàng)建recorder對象,設(shè)置編碼器和解碼器
            recorder.setAudioChannels(audioChannels);
            recorder.setSampleRate(sampleRate);
            recorder.setAudioBitrate(audioBitrate);
            recorder.setAudioCodec(avcodec.AV_CODEC_ID_PCM_S16LE); // 使用PCM 16位小端模式編碼
            recorder.start();
            long startTime = System.currentTimeMillis();
            Frame frame;
            while ((frame = grabber.grabSamples()) != null && (System.currentTimeMillis() - startTime) / 1000 < maxDurationSeconds) {
                recorder.record(frame, 0);
            }
            recorder.stop();
            recorder.release();
            grabber.stop();
            grabber.release();
        }catch (FrameGrabber.Exception | FrameRecorder.Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 保存圖片
     * @param rtspUrl
     * @param outputDir
     * @param maxDurationSeconds 時長范圍
     */
    public static void savePicture(String rtspUrl, String outputDir, int maxDurationSeconds) {
        try(
            FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(rtspUrl);
            OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat()
        ){
            grabber.start();
            long startTime = System.currentTimeMillis();
            Frame frame;
            int i = 0;
            while ((frame = grabber.grab()) != null && (System.currentTimeMillis() - startTime) / 1000 < maxDurationSeconds) {
                // 將Frame轉(zhuǎn)換為OpenCV Mat
                Mat mat = converter.convert(frame);
                if (mat != null && i % 100 == 0) {
                    // 保存幀到磁盤
                    //String fileName = "frame_" + i + ".jpg";
                    //imwrite(outputDir + fileName, mat);
                    imwrite(outputDir + "frame_" + i + ".jpg", mat);
                }
                i++;
            }
        } catch (FrameGrabber.Exception e) {
            e.printStackTrace();
        }
    }

    private static String DEFAULT_RTSP_URL = "rtsp://賬戶:密碼@ip地址";

    public static void main(String[] args) throws Exception {

        ExecutorService executor = Executors.newFixedThreadPool(4); // 創(chuàng)建線程池

        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> videoPuller(DEFAULT_RTSP_URL, 60, "D:\\va\\a.mp4"), executor);

        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> savePicture(DEFAULT_RTSP_URL, "D:\\va\\", 60), executor);

        CompletableFuture<Void> future3 = CompletableFuture.runAsync(() ->
                extractAudioFromRtsp(DEFAULT_RTSP_URL, "D:\\va\\audio.wav", 60), executor);

        CompletableFuture.allOf(future1, future2, future3).thenRun(() -> System.out.println("所有任務(wù)都已完成"));

        // 在應(yīng)用結(jié)束前關(guān)閉線程池
        CompletableFuture.supplyAsync(() -> {
                    return true;
                }, executor)
                .thenAccept((v) -> executor.shutdown());
    }



}

到此這篇關(guān)于SpringBoot使用JavaCV處理rtsp流的示例代碼的文章就介紹到這了,更多相關(guān)SpringBoot JavaCV處理rtsp內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java線程池隊列LinkedBlockingDeque

    Java線程池隊列LinkedBlockingDeque

    這篇文章主要為大家介紹了Java線程池隊列LinkedBlockingDeque示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • Java static方法用法實戰(zhàn)案例總結(jié)

    Java static方法用法實戰(zhàn)案例總結(jié)

    這篇文章主要介紹了Java static方法用法,結(jié)合具體案例形式總結(jié)分析了java static方法功能、使用方法及相關(guān)操作注意事項,需要的朋友可以參考下
    2019-09-09
  • 一文搞懂Spring中的Bean作用域

    一文搞懂Spring中的Bean作用域

    scope用來聲明容器中的對象所應(yīng)該處的限定場景或者說該對象的存活時間,即容器在對象進入其 相應(yīng)的scope之前,生成并裝配這些對象,在該對象不再處于這些scope的限定之后,容器通常會銷毀這些對象,這篇文章主要介紹了Spring中的Bean作用域,需要的朋友可以參考下
    2022-06-06
  • Java模擬死鎖發(fā)生之演繹哲學(xué)家進餐問題案例詳解

    Java模擬死鎖發(fā)生之演繹哲學(xué)家進餐問題案例詳解

    這篇文章主要介紹了Java模擬死鎖發(fā)生之演繹哲學(xué)家進餐問題,結(jié)合具體演繹哲學(xué)家進餐問題的案例形式詳細(xì)分析了死鎖機制與原理,需要的朋友可以參考下
    2019-10-10
  • Java Spring事務(wù)的隔離級別詳解

    Java Spring事務(wù)的隔離級別詳解

    這篇文章主要介紹了Java Spring事務(wù)的隔離級別,分享了相關(guān)代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下
    2021-10-10
  • 圖解Java排序算法之3種簡單排序

    圖解Java排序算法之3種簡單排序

    這篇文章主要為大家詳細(xì)介紹了Java排序算法之3種簡單排序,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • SpringBoot+Tess4j實現(xiàn)牛的OCR識別工具的示例代碼

    SpringBoot+Tess4j實現(xiàn)牛的OCR識別工具的示例代碼

    這篇文章主要介紹了SpringBoot+Tess4j實現(xiàn)牛的OCR識別工具的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • 深入解析Java的Struts框架中的控制器DispatchAction

    深入解析Java的Struts框架中的控制器DispatchAction

    這篇文章主要介紹了深入解析Java的Struts框架中的控制器DispatchAction,Struts是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下
    2015-12-12
  • MybatisPlus使用@TableId主鍵id自增長無效的解決

    MybatisPlus使用@TableId主鍵id自增長無效的解決

    本文主要介紹了MybatisPlus使用@TableId主鍵id自增長無效的解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Spring注入Map集合實現(xiàn)策略模式詳解

    Spring注入Map集合實現(xiàn)策略模式詳解

    這篇文章主要介紹了Spring注入Map集合實現(xiàn)策略模式詳解,Spring提供通過@Resource注解將相同類型的對象注入到Map集合,并將對象的名字作為key,對象作為value封裝進入Map,需要的朋友可以參考下
    2023-11-11

最新評論