嵌入式上gst rtsp server opencv mat

0 安装gstreamer

sudo apt install libgstreamer1.0-0 gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-gl gstreamer1.0-gtk3 gstreamer1.0-qt5 gstreamer1.0-pulseaudio

0.1 查看所有插件

gst-inspect-1.0 -a

0.2安装server

注意一定要加上dev

sudo apt install libgstreamer1.0-dev libgstrtspserver-1.0-dev
git clone https://github.com/GStreamer/gst-rtsp-server.git
cd gst-rtsp-server/
git checkout 1.18
cd examples/
gcc test-launch.c -o test-launch $(pkg-config --cflags --libs gstreamer-rtsp-server-1.0)

0.3查看库装在了何处

ldconfig -p | grep libgstrtspserver

0.4查看某个摄像头

gst-launch-1.0 v4l2src device=/dev/video0 ! video/x-raw, format=NV12, width=640, height=480, framerate=30/1 ! autovideosink

1 基础测试视频

#include <gst/gst.h>
#include <gst/rtsp-server/rtsp-server.h>

int main(int argc, char *argv[]) {
  // 初始化GStreamer
  gst_init(&argc, &argv);

  // 创建RTSP服务器实例
  GstRTSPServer *server = gst_rtsp_server_new();

  // 设置服务器监听端口
  gst_rtsp_server_set_service(server, "8554");

  // 创建媒体映射与工厂
  GstRTSPMountPoints *mounts = gst_rtsp_server_get_mount_points(server);
  GstRTSPMediaFactory *factory = gst_rtsp_media_factory_new();

  // 创建GStreamer管道
  gst_rtsp_media_factory_set_launch(factory,
                                    "( videotestsrc ! video/x-raw,format=(string)I420,width=640,height=480,framerate=(fraction)30/1 ! x264enc ! rtph264pay name=pay0 pt=96 )");

  // 将媒体工厂添加到媒体映射
  gst_rtsp_mount_points_add_factory(mounts, "/test", factory);
  g_object_unref(mounts);

  // 启动RTSP服务器
  gst_rtsp_server_attach(server, NULL);

  // 进入主循环
  GMainLoop *loop = g_main_loop_new(NULL, FALSE);
  g_main_loop_run(loop);

  // 清理资源
  g_main_loop_unref(loop);
  g_object_unref(server);

  return 0;
}

1.1 makefile

cmake_minimum_required(VERSION 3.0)
project(photo_get_project)
set(CMAKE_CXX_STANDARD 11)

#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread -O3 -DNDEBUG")

SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -Wall -g -ggdb")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall -DNDEBUG")
set(CMAKE_C_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall -DNDEBUG")

set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin)
# 设置代码构建级别为 Debug 方式 Debug Release
#set(CMAKE_BUILD_TYPE Release)
message(STATUS "yangshao: ${CMAKE_CXX_FLAGS}" )
message(STATUS "OpenCV Libraries: ${OpenCV_LIBS}")
find_package(OpenCV REQUIRED)

include_directories(/usr/local/opencv4.8/include/opencv4)
include_directories(/usr/include/gstreamer-1.0)
include_directories(/usr/include/glib-2.0)
include_directories(/usr/lib/aarch64-linux-gnu/glib-2.0/include/)
add_executable(test rtspserver.cpp)
target_link_libraries(test PRIVATE  -lgobject-2.0 glib-2.0 gstreamer-1.0 gstapp-1.0 gstrtspserver-1.0)

1.2 结果

打开两个vlc测试

在这里插入图片描述

2 发送到rtspserver

#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
#include <opencv2/opencv.hpp>

class VideoSource {
public:
    VideoSource(const char* pipeline_str) {
        pipeline = gst_parse_launch(pipeline_str, NULL);
        appsrc = GST_APP_SRC(gst_bin_get_by_name(GST_BIN(pipeline), "appsrc0"));

        // 设置appsrc属性
        g_object_set(appsrc, "is-live", TRUE, "format", GST_FORMAT_TIME, NULL);
        
        // 连接信号
        g_signal_connect(appsrc, "need-data", G_CALLBACK(OnNeedData), this);
        g_signal_connect(appsrc, "enough-data", G_CALLBACK(OnEnoughData), this);
    }

    ~VideoSource() {
        gst_object_unref(pipeline);
    }

    void Start() {
        gst_element_set_state(pipeline, GST_STATE_PLAYING);
    }

    void Stop() {
        gst_element_set_state(pipeline, GST_STATE_NULL);
    }

private:
    static gboolean OnNeedData(GstElement *element, guint unused_size, gpointer user_data) {
        VideoSource *self = static_cast<VideoSource*>(user_data);
        return self->PushFrame();
    }

    static gboolean OnEnoughData(GstElement *element, gpointer user_data) {
        VideoSource *self = static_cast<VideoSource*>(user_data);
        self->Stop();
        return TRUE;
    }

    gboolean PushFrame() {
        // 从cv::Mat中获取帧
        cv::Mat frame = GetNextFrame();

        // 将cv::Mat转换为GstBuffer
        GstBuffer *buffer = ConvertMatToGstBuffer(frame);

        // 将GstBuffer推送到appsrc
        gst_app_src_push_buffer(GST_APP_SRC(appsrc), buffer);

        // 如果没有更多的帧,停止管道
        if (!HasMoreFrames()) {
            Stop();
            return FALSE;
        }

        return TRUE;
    }

    cv::Mat GetNextFrame() {
        // 在这里实现获取下一帧的逻辑
        // 例如,从文件、网络流或摄像头读取
        // 返回一个cv::Mat对象
    }

    gboolean HasMoreFrames() {
        // 实现检查是否还有更多帧的逻辑
        // 如果没有更多帧,返回FALSE,否则返回TRUE
    }

    GstBuffer *ConvertMatToGstBuffer(cv::Mat &frame) {
        // 将cv::Mat转换为GstBuffer
        // 注意:这只是一个示例实现,你可能需要根据你的帧格式进行调整
        GstBuffer *buffer = gst_buffer_new_wrapped(frame.data, frame.total() * frame.elemSize(), 0, frame.total() * frame.elemSize());
        GstVideoInfo info;
        gst_video_info_set_format(&info, GST_VIDEO_FORMAT_RGBA, frame.cols, frame.rows, frame.step);
        gst_buffer_add_video_meta(buffer, &info, 0, frame.cols * frame.rows * frame.channels());

        return buffer;
    }

    GstElement *pipeline;
    GstElement *appsrc;
};

int main(int argc, char *argv[]) {
    gst_init(&argc, &argv);

    // RTSP Server的GStreamer管道描述
    const char* pipeline_str = 
        "appsrc name=appsrc0 is-live=true format=time "
        "! videoconvert "
        "! x264enc tune=zerolatency bitrate=500 speed-preset=superfast "
        "! rtph264pay config-interval=1 name=pay0 pt=96 "
        "! rtspclientsink location=\"rtsp://localhost:8554/test\"";

    VideoSource source(pipeline_str);
    source.Start();

    // 主循环
    GMainLoop *loop = g_main_loop_new(NULL, FALSE);
    g_main_loop_run(loop);

    g_main_loop_unref(loop);

    return 0;
}

3 需要cv::mat 作为输入源

#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
#include <opencv2/opencv.hpp>

class VideoSource {
public:
    VideoSource(const char* pipeline_str) {
        pipeline = gst_parse_launch(pipeline_str, NULL);
        appsrc = GST_APP_SRC(gst_bin_get_by_name(GST_BIN(pipeline), "appsrc0"));

        // 设置appsrc属性
        g_object_set(appsrc, "is-live", TRUE, "format", GST_FORMAT_TIME, NULL);
        
        // 连接信号
        g_signal_connect(appsrc, "need-data", G_CALLBACK(OnNeedData), this);
        g_signal_connect(appsrc, "enough-data", G_CALLBACK(OnEnoughData), this);
    }

    ~VideoSource() {
        gst_object_unref(pipeline);
    }

    void Start() {
        gst_element_set_state(pipeline, GST_STATE_PLAYING);
    }

    void Stop() {
        gst_element_set_state(pipeline, GST_STATE_NULL);
    }

private:
    static gboolean OnNeedData(GstElement *element, guint unused_size, gpointer user_data) {
        VideoSource *self = static_cast<VideoSource*>(user_data);
        return self->PushFrame();
    }

    static gboolean OnEnoughData(GstElement *element, gpointer user_data) {
        VideoSource *self = static_cast<VideoSource*>(user_data);
        self->Stop();
        return TRUE;
    }

    gboolean PushFrame() {
        // 从cv::Mat中获取帧
        cv::Mat frame = GetNextFrame();

        // 将cv::Mat转换为GstBuffer
        GstBuffer *buffer = ConvertMatToGstBuffer(frame);

        // 将GstBuffer推送到appsrc
        gst_app_src_push_buffer(GST_APP_SRC(appsrc), buffer);

        // 如果没有更多的帧,停止管道
        if (!HasMoreFrames()) {
            Stop();
            return FALSE;
        }

        return TRUE;
    }

    cv::Mat GetNextFrame() {
        // 在这里实现获取下一帧的逻辑
        // 例如,从文件、网络流或摄像头读取
        // 返回一个cv::Mat对象
    }

    gboolean HasMoreFrames() {
        // 实现检查是否还有更多帧的逻辑
        // 如果没有更多帧,返回FALSE,否则返回TRUE
    }

    GstBuffer *ConvertMatToGstBuffer(cv::Mat &frame) {
        // 将cv::Mat转换为GstBuffer
        // 注意:这只是一个示例实现,你可能需要根据你的帧格式进行调整
        GstBuffer *buffer = gst_buffer_new_wrapped(frame.data, frame.total() * frame.elemSize(), 0, frame.total() * frame.elemSize());
        GstVideoInfo info;
        gst_video_info_set_format(&info, GST_VIDEO_FORMAT_RGBA, frame.cols, frame.rows, frame.step);
        gst_buffer_add_video_meta(buffer, &info, 0, frame.cols * frame.rows * frame.channels());

        return buffer;
    }

    GstElement *pipeline;
    GstElement *appsrc;
};

int main(int argc, char *argv[]) {
    gst_init(&argc, &argv);

    // RTSP Server的GStreamer管道描述
    const char* pipeline_str = 
        "appsrc name=appsrc0 is-live=true format=time "
        "! videoconvert "
        "! x264enc tune=zerolatency bitrate=500 speed-preset=superfast "
        "! rtph264pay config-interval=1 name=pay0 pt=96 "
        "! rtspclientsink location=\"rtsp://localhost:8554/test\"";

    VideoSource source(pipeline_str);
    source.Start();

    // 主循环
    GMainLoop *loop = g_main_loop_new(NULL, FALSE);
    g_main_loop_run(loop);

    g_main_loop_unref(loop);

    return 0;
}

4 自身需要作为rtspserver


#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
#include <gst/rtsp-server/gst-rtsp-server.h>
#include <opencv2/opencv.hpp>

class RtspsServerApp {
public:
    RtspsServerApp() {
        gst_init(NULL, NULL);
        pipeline = gst_pipeline_new("pipeline");

        appsrc = gst_element_factory_make("appsrc", "appsrc0");
        g_object_set(appsrc, "is-live", TRUE, "format", GST_FORMAT_TIME, NULL);
        g_signal_connect(appsrc, "need-data", G_CALLBACK(OnNeedData), this);
        g_signal_connect(appsrc, "enough-data", G_CALLBACK(OnEnoughData), this);

        videoconvert = gst_element_factory_make("videoconvert", "videoconvert");
        x264enc = gst_element_factory_make("x264enc", "x264enc");
        rtph264pay = gst_element_factory_make("rtph264pay", "rtph264pay");
        queue = gst_element_factory_make("queue", "queue");

        gst_bin_add_many(GST_BIN(pipeline), appsrc, videoconvert, x264enc, rtph264pay, queue, NULL);
        gst_element_link_many(appsrc, videoconvert, x264enc, rtph264pay, queue, NULL);

        // Create the RTSP server and mount points
        server = gst_rtsp_server_new();
        mounts = gst_rtsp_server_get_mount_points(server);
        factory = gst_rtsp_media_factory_new();
        g_object_set(factory, "media-type", "video", NULL);
        g_object_set(factory, "caps", gst_pad_get_pad_template_caps(GST_ELEMENT(queue)->sinkpad), NULL);

        // Set up the launch string for the factory
        gchar *launch = g_strdup_printf("( appsrc name=source ! videoconvert ! x264enc ! rtph264pay name=pay0 pt=96 )");
        gst_rtsp_media_factory_set_launch(factory, launch);
        g_free(launch);

        gst_rtsp_mount_points_add_factory(mounts, "/stream", factory);

        // Attach the server
        gst_rtsp_server_attach(server, NULL);
    }

    ~RtspsServerApp() {
        gst_rtsp_server_detach(server);
        gst_object_unref(mounts);
        gst_object_unref(factory);
        gst_object_unref(server);
        gst_object_unref(pipeline);
    }

    void Start() {
        gst_element_set_state(pipeline, GST_STATE_PLAYING);
    }

    void Stop() {
        gst_element_set_state(pipeline, GST_STATE_NULL);
    }

private:
    static gboolean OnNeedData(GstElement *element, guint unused_size, gpointer user_data) {
        RtspsServerApp *self = static_cast<RtspsServerApp*>(user_data);
        return self->PushFrame();
    }

    static gboolean OnEnoughData(GstElement *element, gpointer user_data) {
        RtspsServerApp *self = static_cast<RtspsServerApp*>(user_data);
        self->Stop();
        return TRUE;
    }

    gboolean PushFrame() {
        // 假设这里你已经有了一个cv::Mat对象
        cv::Mat frame = GetNextFrame();

        // 将cv::Mat转换为GstBuffer
        GstBuffer *buffer = ConvertMatToGstBuffer(frame);

        // 将GstBuffer推送到appsrc
        gst_app_src_push_buffer(GST_APP_SRC(appsrc), buffer);

        return TRUE;
    }

    cv::Mat GetNextFrame() {
        // 实现获取下一帧的逻辑
        // 返回一个cv::Mat对象
    }

    GstBuffer *ConvertMatToGstBuffer(cv::Mat &frame) {
        // 将cv::Mat转换为GstBuffer
        // 注意:这只是一个示例实现,你可能需要根据你的帧格式进行调整
        GstBuffer *buffer = gst_buffer_new_wrapped(frame.data, frame.total() * frame.elemSize(), 0, frame.total() * frame.elemSize());
        GstVideoInfo info;
        gst_video_info_set_format(&info, GST_VIDEO_FORMAT_I420, frame.cols, frame.rows, frame.step);
        gst_buffer_add_video_meta(buffer, &info, 0, frame.cols * frame.rows * frame.channels());

        return buffer;
    }

    GstElement *pipeline;
    GstElement *appsrc;
    GstElement *videoconvert;
    GstElement *x264enc;
    GstElement *rtph264pay;
    GstElement *queue;

    GstRTSPServer *server;
    GstRTSPMountPoints *mounts;
    GstRTSPMediaFactory *factory;
};

int main(int argc, char *argv[]) {
    RtspsServerApp app;
    app.Start();

    // 主循环
    GMainLoop *loop = g_main_loop_new(NULL, FALSE);
    g_main_loop_run(loop);

    g_main_loop_unref(loop);

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/770356.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PhysioLLM 个性化健康洞察:手表可穿戴设备实时数据 + 大模型

个性化健康洞察&#xff1a;可穿戴设备实时数据 大模型 提出背景PhysioLLM 图PhysioLLM 实现数据准备用户模型和洞察生成个性化数据总结和洞察是如何生成的&#xff1f; 解析分析 提出背景 论文&#xff1a;https://arxiv.org/pdf/2406.19283 虽然当前的可穿戴设备伴随应用&…

uniapp应用如何实现传感器数据采集和分析

UniApp是一种跨平台的应用开发框架&#xff0c;它支持在同一份代码中同时开发iOS、Android、H5等多个平台的应用。在UniApp中实现传感器数据采集和分析的过程可以分为以下几个步骤&#xff1a; 引入相关插件或库 UniApp通过插件或库的形式扩展功能。对于传感器数据采集和分析&…

【APK】SDKManager运行后闪退

本地JDK已安装&#xff0c;且配置了环境变量&#xff0c;未安装 android studiio 问题描述&#xff1a;右键以管理员身份运行 SDKManager&#xff0c;终端窗口闪退 问题原因&#xff1a;未找到正确的Java路径 解决办法&#xff1a; 1.修改tools目录下的 android.bat 文件&am…

数字人直播源码开发全攻略揭秘:如何搭建自己的数字人直播平台?

当前&#xff0c;数字人直播逐渐成为众多中小型企业线上带货和品牌宣传的不二之选&#xff0c;而艾媒研究数据也显示&#xff0c;超五成以上的被调查群体的企业使用过虚拟人技术&#xff0c;超三成被调查群体的企业计划使用虚拟人技术。在此背景下&#xff0c;越来越多的创业者…

10计算机视觉—物体检测算法

目录 1.R-CNN(区域卷积神经网络)2014兴趣区域(RoI)池化层Fast RCNN 2015Faster R-CNN 2015Mask R-CNN 2017总结2. SSD(单发多框检测)2016SSD模型总结3.YOLO(你只看一次)快!很重要4.目标检测算法性能对比5.SSD代码实现 使用很少,比不上yolo多尺度锚框实现SSD代码实现训练…

DOM 中包含哪些重要方法

1. alert 带有指定消息的警告框 alert("hello world"); 2. confirm 带有确定和取消的对话框&#xff0c;点击确定返回 true&#xff0c;点击取消返回 false confirm("你好吗"); 3. prompt 显示一个提示框&#xff0c;允许用户输入文本&#xff0c;点击…

数据恢复篇:5 款最佳 Mac 数据恢复软件

说到保护我们的数字生活&#xff0c;数据恢复软件的重要性怎么强调都不为过。无论您是意外删除了假期照片的普通用户&#xff0c;还是面临硬盘损坏的专业人士&#xff0c;随之而来的恐慌都是普遍存在的。幸运的是&#xff0c;数据恢复工具可以缓解这些压力。在Mac用户可用的众多…

零障碍入门:SSH免密登录与Hadoop生态系统的完美搭档【实训Day02】

一、 SSH免密登录配置 1 生成公钥和秘钥(在hadoop101上) # su star # cd /home/star/.ssh # ssh-keygen -t rsa 2 公钥和私钥 公钥id_rsa.pub 私钥id_rsa 3 将公钥拷贝到目标机器上(在hadoop101上) # ssh-copy-id hadoop101 # ssh-copy-id hadoop102 # ssh-co…

翔云发票查验接口状态码说明,哪种情况扣次数那种情况不扣次数呢

翔云发票查验API&#xff0c;实时联网&#xff0c;可以实现发票信息真伪的快速核验&#xff0c;帮助企业财务摆脱繁琐的发票真伪查验工作。那么知道了发票查验接口的作用&#xff0c;对于开发者而言&#xff0c;接口返回的状态码又分别代表什么含义呢&#xff1f;下面就翔云发票…

【Elasticsearch】Elasticsearch索引创建与管理详解

文章目录 &#x1f4d1;引言一、Elasticsearch 索引的基础概念二、创建索引2.1 使用默认设置创建索引2.2 自定义设置创建索引2.3 创建索引并设置映射 三、索引模板3.1 创建索引模板3.2 使用索引模板创建索引 四、管理索引4.1 查看索引4.2 更新索引设置4.3 删除索引 五、索引别名…

掌握高效实用的VS调试技巧

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 1.编程常见的错误 1.1编译型错误 编程编译型错误是指在编译代码时发现的错误。编译器在编译过程中会检查代码是否符合语法规范和语义要求&#xff0c;如果发现错误会产生编译错误。 直接看错误提示信息&#xff08;双击&#…

超声波气象站的工作原理

TH-CQX5超声波气象站中的超声波技术是其核心工作原理之一&#xff0c;以下是关于超声波气象站中超声波的详细解释&#xff1a;超声波是一种频率高于人耳能听到的声音频率范围的声波&#xff0c;通常指频率在20kHz以上的声波。超声波具有较短的波长和强的穿透能力&#xff0c;能…

相机,手机,行车记录仪及监控视频修复软件: Stellar Repair for Video

天津鸿萌科贸发展有限公司是 Stellar 系列数据恢复软件的授权代理商。 Stellar Repair for Video 是一款强大的工具&#xff0c;用于修复从主流相机品牌&#xff08;如佳能、尼康、索尼&#xff09;、行车记录仪、监控录像机、手机和其他视频设备拍摄的无法访问和损坏的视频。…

zabbix 配置企业微信告警

1、申请一个企业微信&#xff0c; 官网链接 2、群内申请一个机器人 下载电脑版企业微信&#xff0c;登录后&#xff0c;在要接收群消息的群里&#xff0c;点击右上角三个点&#xff0c;添加机器人后&#xff0c;保存机器人的webhook地址 上传应用logo&#xff0c;填写应用名称…

MySQL—创建和修改数据表结构

创建表 实例&#xff1a; CREATE TABLE user (id INT,name VARCHAR(255),password VARCHAR(255),birthday DATE) CHARACTER SET utf8 COLLATE utf8_bin ENGINE INNODB; 显示数据库中的表 show tables from hsp; 显示表结构 desc dept; 修改表 实例&#xff1a; 代码&…

Vue85-Vuex的求和案例

一、需求 二、开发 2-1、index.js中vuex的代码 注意&#xff1a; 书写格式&#xff1a;actions中的函数名用小写&#xff01;mutations中的函数名&#xff0c;用大写。 注意&#xff1a; 2-2、组件count.vue中的代码 2-3、代码优化 三、actions中的context参数 此写法的后…

网安小贴士(6)TCP/IP分层

一、前言 1983年&#xff0c;美国国防部决定将TCP/IP作为所有计算机网络的标准协议&#xff0c;这标志着TCP/IP正式成为互联网的基础协议。随着个人计算机的普及和网络技术的发展&#xff0c;TCP/IP模型被广泛应用于各种网络环境中&#xff0c;包括局域网&#xff08;LAN&#…

天行健咨询|六西格玛绿带培训是投资未来,还是金钱的“黑洞”?

六西格玛绿带培训&#xff0c;作为一种被众多企业推崇的培训课程&#xff0c;自然成为了众多职场人士关注的焦点。然而&#xff0c;面对培训的高昂费用和时间成本&#xff0c;很多人开始质疑&#xff1a;参加六西格玛绿带培训&#xff0c;到底是投资还是浪费钱&#xff1f;深圳…

前端重点之:Vue+websocket通信详细用法和websocket心跳机制的使用,websocket断开实时监测,websocket实时通信

今年年初找工作,好多gou面试官总喜欢问关于websocket通信的使用方式,此次又用到了,在此做个总结:主要包含websocket的具体使用方法,和重点:(心跳机制的使用),就是主要是前端实时监测websocket是否有断连和数据的处理 在前端开发中,WebSocket 是一种常见的技术,用于…

安华金和—可信数据空间助力公共数据授权运营安全有序开展的实践探索

伴随数字化、网络化和智能化的快速发展&#xff0c;数字经济与实体经济深度融合&#xff0c;数据已然成为经济发展赖以依托的基础性、战略性资源&#xff0c;对社会生产、分配、流通、消费和社会服务管理等各环节产生深刻影响。我国高度重视数字经济发展&#xff0c;将数据列入…
最新文章