嵌入式上gst rtsp server opencv mat

news2024/11/20 7:25:22

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.coloradmin.cn/o/1896138.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何用手机拍出高级感黑白色调照片?华为Pura70系列XMAGE演绎黑白艺术

在影像的世界里&#xff0c;色彩可以让画面更丰富&#xff0c;更具有表现力&#xff0c;往往也能带来更多的视觉冲击。但有时候&#xff0c;黑白却有着一种独特的魅力。华为Pura 70系列XMAGE黑白风格&#xff0c;则给我们了一把通过纯粹艺术大门的钥匙。 XMAGE黑白并非简单的色…

水利行业的智慧化转型实践:结合具体案例,探讨智慧水利在提升水资源利用效率、改善水生态环境方面的实际效果

目录 一、引言 二、智慧水利的定义与意义 三、智慧水利在提升水资源利用效率方面的实践 1. 智慧灌溉系统 2. 智慧供水系统 3. 智慧水务管理平台 四、智慧水利在改善水生态环境方面的实践 1. 智慧水质监测系统 2. 智慧水生态修复系统 3. 智慧防洪减灾系统 五、具体案例…

利用YOLOv8识别自定义模型

一、背景介绍 最近项目需要识别自定义物品&#xff0c;于是学习利用YOLOv8算法&#xff0c;实现物品识别。由于物体类别不再常规模型中&#xff0c;因此需要自己训练相应的模型&#xff0c;特此记录模型训练的过程。 二、训练模型的步骤 1.拍照获取训练图片&#xff08;训练图…

ubuntu软件源的两种格式和环境变量

1. ubuntu的/etc是什么目录&#xff1f; 在Ubuntu操作系统中&#xff0c;/etc/是一个特殊的目录&#xff0c;它包含系统的配置文件。这些配置文件用于设置各种系统和应用程序的参数和选项。 一般来说&#xff0c;用户可以在这个目录下找到各种重要的配置文件&#xff0c;如网络…

Os-hackNos

下载地址 https://download.vulnhub.com/hacknos/Os-hackNos-1.ova 环境配置如果出现&#xff0c;扫描不到IP的情况&#xff0c;可以尝试vulnhub靶机检测不到IP地址解决办法_vulnhub靶机扫描不到ip-CSDN博客 信息收集 确定靶机地址&#xff1a; 探测到存活主机192.168.111.…

背包问题(一)

一.P3985 不开心的金明(01背包变式) 解析: 一开始没有看数据范围,直接当01背包直接写了,结果最后4个测试点RE,一看到数据范围就老实了,1e9的数据,数组直接炸,所以不能直接使用一维的01背包.看了一下题解,部分人是通过极差对数据进行分类,按照300进行分开,使用贪心和dp一起做. …

JavaScript 原型链那些事

在讲原型之前我们先来了解一下函数。 在JS中&#xff0c;函数的本质就是对象&#xff0c;它与其他对象不同的是&#xff0c;创建它的构造函数与创建其他对象的构造函数不一样。那产生函数对象的构造函数是什么呢&#xff1f;是一个叫做Function的特殊函数&#xff0c;通过newFu…

HarmonyOS - 通过.p7b文件获取fingerprint

1、查询工程所对应的 .p7b 文件 通常新工程运行按照需要通过 DevEco Studio 的 Project Structure 勾选 Automatically generate signature 自动生成签名文件&#xff0c;自动生成的 .p7b 文件通常默认在系统用户目录下. 如&#xff1a;C:/Users/zhangsan/.ohos/config/default…

vue3中svg图标的封装与使用

组件封装&#xff1a; <template><svg :class"svgClass" :style"{ width: size px, height: size px, color: color, verticalAlign:deviationem}" aria-hidden"true"><use :xlink:href"#icon-${name}" /></s…

LT86101UXE 国产原装 HDMI2.0 / DVI中继器方案 分辨率 4Kx2K 用于多显示器 DVI/HDMI电缆扩展模块

1. 描述 Lontium LT86101UXE HDMI2.0 / DVI中继器特性高速中继器符合HDMI2.0/1.4规范,最大6 gbps高速数据率、自适应均衡RX输入和pre-emphasized TX输出支持长电缆应用程序,没有晶体在船上保存BOM成本,内部灵活的PCB TX巷交换路由。 LT86101UXE HDMI2.0/DVI中继器自动检测线缆损…

C语言_指针初阶(进阶还在更新中)

指针是什么 指针是内存中一个最小单元的编号&#xff0c;也就是地址平时口语中说的指针&#xff0c;通常指的是指针变量&#xff0c;是用来存放内存地址的变量指针就是地址&#xff0c;口语中说的指针通常指的是指针变量。我们可以通过&&#xff08;取地址操作符&#xff…

EasyBoss ERP移动端上线数据分析模块,随时查Shopee/TikTok本土店数据

前段时间&#xff0c;EasyBoss ERP出了个超酷炫的数字大屏功能&#xff0c;广受好评。 但是也有老板说&#xff0c;电脑端看数据不够方便啊&#xff0c;你们EasyBoss有本事上个手机就能看数据的功能啊&#xff01; 说干就干&#xff0c;直接满足你们的需求&#xff01; 于是在…

推荐一款Win11主题WPF UI框架

最近在微软商店&#xff0c;官方上架了新款Win11风格的WPF版UI框架【WPF Gallery Preview 1.0.0.0】,这款应用引入了前沿的Fluent Design UI设计&#xff0c;为用户带来全新的视觉体验。 WPF Gallery简介 做为一关注前沿资讯的开发人员&#xff0c;首先关注的是应用WPF Gallery…

Centos7 安装老版本的chrome

查看自己linux是哪个centos版本 使用以下命令&#xff1a; cat /etc/centos-release我这里是centOS 7。然后在安装最新版的google-chrome时&#xff0c;总是会报错显示存在依赖环境的问题&#xff0c;使得无法安装成功chrome。 Package: google-chrome-stable (/google-chro…

HttpServer内存马

HttpServer内存马 基础知识 一些基础的方法和类 HttpServer&#xff1a;HttpServer主要是通过带参的create方法来创建&#xff0c;第一个参数InetSocketAddress表示绑定的ip地址和端口号。第二个参数为int类型&#xff0c;表示允许排队的最大TCP连接数&#xff0c;如果该值小…

无线传感器网络(物联网通信技术)期末考试2024年真题

目录 WSN期末复习资料 第一章&#xff1a;概述 第二章MAC协议 第三章路由协议 第四章时间同步技术 第五章定位技术 第六章安全技术 第七章拓扑控制 补充TPSN、HRTS公式推导 2024年期末考试考点 一、简述 二、考试真题回忆 WSN期末复习资料 第一章&#xff1a;概述 …

JVM的五大内存区域

JVM的五大内存区域 JVM内存区域最粗略的划分可以分为 堆 和 栈 &#xff0c;当然&#xff0c;按照虚拟机规范&#xff0c;可以划分为以下几个区域&#xff1a; JVM内存分为线程独享区和线程共享区&#xff0c; 其中 方法区 和 堆 是线程共享区&#xff0c; 虚拟机栈, 本地方法…

使用香橙派AIpro做目标检测

使用香橙派AIpro做目标检测 文章目录 使用香橙派AIpro做目标检测香橙派AIpro开发板介绍香橙派AIpro应用体验识别图像识别视频摄像头 香橙派AIpro AI应用场景总结 香橙派AIpro开发板介绍 ​ OrangePi AIpro(8-12T)是一款集成昇腾AI技术的开发板&#xff0c;搭载4核64位CPU和AI处…

Windows安装Visual Studio Code(VS Code) (配图超详细!)

一、下载 官方网站&#xff1a;https://code.visualstudio.com/download 二、安装 1、安装之前先在目的安装路径中新建文件夹存放待会要安装的程序&#xff08;因为在安装过程中选择安装路径时无法现场新建文件夹&#xff09;。 2、在下载目录中找到安装包并双击运行&#xf…

Java经典面试题将一个字符串数组进行分组输出,每组中的字符串都由相同的字符组成

Java经典面试题将一个字符串数组进行分组输出&#xff0c;每组中的字符串都由相同的字符组成 题目&#xff1a; 将一个字符串数组进行分组输出&#xff0c;每组中的字符串都由相同的字符组成 举个例子&#xff1a;输入[“eat”,“tea”,“tan”,“ate”,“nat”,“bat”] 输出…