使用Gstreamer+OpenCV实现两路图像数据混合拉流推流

这篇具有很好参考价值的文章主要介绍了使用Gstreamer+OpenCV实现两路图像数据混合拉流推流。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本示例看完后,可基本掌握以下内容
1、利用opencv+gstreamer拉流推流的基本步骤
2、可学习gstreamer,图像混合的一些插件用法
3、TX2 NX上的视频编解码与硬件加速,H264编码参数调整
4、linux下如何提高线程优先级

我需要实现的功能是在TX2 NX上,拉取摄像头数据,并在摄像头数据上与另一张图片混合
混合后推流到rtsp服务器。

由于混合的时候需要保留透明度,但是OpenCV不支持四通道的数据写入。硬件加速混合插件无法剔除透明度。当然可以用内存(不是显存,无法硬件加速)中剔除指定颜色的插件实现,但效率太低

所以只能利用VideoCapture先拉到摄像头数据,利用要混合的图片,手动计算叠加。

叠加后利用VideoWriter推流到rtsp 服务器

为提高推流效率,提高了推流线程优先级。

具体流程:
首先搭建rtsp服务端,可利用rtsp-simple-serve这个项目在局域网部署一套
 
 安装gstreamer后
 由于用到了rtspclientsink插件,所以需要安装rtsp插件
// sudo apt-get update
// sudo apt-get upgrade
// sudo apt install gstreamer1.0-rtsp

下面是利用VideoWriter推流的过程

//cpp 实现
#include "rtsp_push_stream.h"


static int get_thread_policy(pthread_attr_t& attr) {
    int policy;
    int rs = pthread_attr_getschedpolicy(&attr, &policy);
    assert(rs == 0);
    switch (policy) {
        case SCHED_FIFO:
            cout << "policy = SCHED_FIFO" << endl;
            break;

        case SCHED_RR:
            cout << "policy = SCHED_RR" << endl;
            break;

        case SCHED_OTHER:
            cout << "policy = SCHED_OTHER" << endl;
            break;

        default:
            cout << "policy = UNKNOWN" << endl;
            break;
    }

    return policy;
}

static void show_thread_priority(pthread_attr_t& attr, int policy) {
    int priority = sched_get_priority_max(policy);
    assert(priority != -1);
    cout << "max_priority = " << priority << endl;

    priority = sched_get_priority_min(policy);
    assert(priority != -1);
    cout << "min_priority = " << priority << endl;
}

static int get_thread_priority(pthread_attr_t& attr) {
    struct sched_param param;

    int rs = pthread_attr_getschedparam(&attr, &param);
    assert(rs == 0);
    cout << "priority = " << param.__sched_priority << endl;

    return param.__sched_priority;
}

static void set_thread_policy(pthread_attr_t& attr, int policy) {
    int rs = pthread_attr_setschedpolicy(&attr, policy);
    assert(rs == 0);
    get_thread_policy(attr);
}

RtspPushStream::RtspPushStream() : active_(true) {}

RtspPushStream::~RtspPushStream() {}
void RtspPushStream::start() {
 
    string appsrcpipeline =
        "appsrc ! video/x-raw, format=BGR ! queue ! videoconvert ! video/x-raw,format=RGBA ! nvvidconv ! nvv4l2h264enc "
        "! h264parse ! qtmux ! filesink location={filename}  sync=false";

    //使用 rtspclientsink 需要安装插件
    // sudo apt-get update
    // sudo apt-get upgrade
    // sudo apt install gstreamer1.0-rtsp

 
    std::string pipeline_useglvideomixer =
        "appsrc "
        "! video/x-raw, format=BGR "
        "! videoconvert "
        "! video/x-raw,format=(string)RGBA , width=(int)1024, height=(int)600"
        "! queue2"
        "! alpha method=blue "
        "! glvideomixer name = compos sink_0::zorder=1 sink_0::alpha=0.85 sink_1::alpha=1 sink_1::zorder=0 "
        "sink_1::width=1024 sink_1::height=600 "
        "! nvvidconv"
        "! video/x-raw(memory:NVMM), format=(string)I420, width=(int)1024, height=(int)600"
        "! nvv4l2h264enc "
        "! rtspclientsink location=rtsp://192.168.20.99:8554/my_pipeline"
        " nvarguscamerasrc"
        "! video/x-raw(memory:NVMM),format=(string)NV12, width=(int)1640, height=(int)1232, framerate=(fraction)25/1"
        "! queue2"
        "! nvvidconv left=0 right=1640 top=136 bottom=1096 "
        "! compos. ";

    // nvcompsositor 的两个输入必须是一样的图片格式和内存形式,需要将云图透明部分用白色(255,255,255)填充
    std::string pipeline_nvcompsositor =
        "appsrc "
        "! video/x-raw, format=BGR "
        "! videoconvert "
        "! video/x-raw,format=(string)RGBA, width=(int)1024, height=(int)600"
        "! nvvidconv "
        "! queue2"
        "! nvcompositor  name = compos sink_0::zorder=1 sink_0::alpha=0.5 "
        "sink_1::alpha=1 "
        "sink_1::zorder=0 sink_1::width=1024 sink_1::height=600 "
        "! nvvidconv "
        "! nvv4l2h264enc "
        "! rtspclientsink location=rtsp://192.168.20.99:8554/my_pipeline"
        " nvarguscamerasrc "
        "! video/x-raw(memory:NVMM), format=(string)NV12, width=(int)1640, height=(int)1232,framerate=(fraction)25/1 "
        "! nvvidconv  left=0 right=1640 top=136 bottom=1096 "
        "! video/x-raw,format=(string)RGBA, width=(int)1024, height=(int)600 "
        "! videobalance brightness=0.3 "
        "! nvvidconv "
        "! queue2"
        "! compos. ";

    video_writer_.open(pipeline_nvcompsositor, cv::CAP_GSTREAMER, 0, 25, cv::Size(1024, 600));
    mat_          = cv::imread("test.jpg");
    write_thread_ = make_shared<thread>(&RtspPushStream::run, this);
    write_thread_->join();
}

void RtspPushStream::run() {
    int id = 0;
    while (active_) {
        space_mat_ = cv::Mat(600, 1024, CV_8UC3, cv::Scalar(0, 0, 0));

        
        video_writer_.write(space_mat_);

        std::this_thread::sleep_for(std::chrono::milliseconds(3));
    }
}

void RtspPushStream::end() {
    active_ = false;
    //LOG::info("RtspPushStream::end()!");
}

void RtspPushStream::start_capture() {

    std::string pipeline_camear_capture =
        " nvarguscamerasrc "
        "! video/x-raw(memory:NVMM), format=(string)NV12, width=(int)1640, "
        "height=(int)1232,framerate=(fraction)30/1 "
        "! nvvidconv  left=0 right=1640 top=136 bottom=1096 "
        "! video/x-raw,format=(string)I420, width=(int)1024, height=(int)600 "
        "! videoconvert "
        "! video/x-raw,format=(string)BGR "
        "! appsink";

    video_capture_.open(pipeline_camear_capture, cv::CAP_GSTREAMER);
    if (!video_capture_.isOpened()) {
        //LOG::error("Failed to open VideoCapture");
        return;
    }
    mat_ = cv::imread("test.jpg");
    std::string pipeline_video_writer =
        "appsrc "
        "! video/x-raw, format=BGR "
        "! videoconvert "
        "! nvvidconv "
        "! nvv4l2h264enc iframeinterval=10 idrinterval=32 "  //这里增加H264 i帧与idr帧次数,降低webrtc拉流时卡顿的频率和时间
        "! rtspclientsink location=rtsp://192.168.20.99:8554/my_pipeline";

    video_writer_.open(pipeline_video_writer, cv::CAP_GSTREAMER, 0, 20, cv::Size(1024, 600));
    cap_thread_ = make_shared<thread>(&RtspPushStream::run_capture, this);
    cap_thread_->detach();
}

void RtspPushStream::run_capture() {
   pthread_attr_t     attr;
    struct sched_param sched;
    int                rs;

    rs = pthread_attr_init(&attr);
    assert(rs == 0);

    int policy = get_thread_policy(attr);

    cout << "Show current configuration of priority" << endl;
    show_thread_priority(attr, policy);

    cout << "Show priority of current thread" << endl;
    int priority = get_thread_priority(attr);

    set_thread_policy(attr, SCHED_FIFO); // SCHED_RR
    cout << "Restore current policy" << endl;
    // set_thread_policy(attr, policy);
    struct sched_param param_;
    param_.sched_priority = sched_get_priority_max(SCHED_FIFO); // SCHED_RR
    //这里设置线程优先级
    cout << "param_.sched_priority  = " << param_.sched_priority << endl;
    pthread_setschedparam(pthread_self(), SCHED_FIFO, &param_);
    cout << "pthread_setschedparam success" << endl;

    rs = pthread_attr_destroy(&attr);
    assert(rs == 0);
    cout << "start capture!!!!!!!!!" << endl;

    int     id = 0;
    cv::Mat src;
    while (active_) {
        //读取摄像头内容,也就是从摄像头拉流
        video_capture_ >> src;
        //在这里自定义融合算法就行了
        //blender
        // 两张图的透明度融合算法,取rgb像素进行融合
        // data1[add_col]     = data2[add_col] * 0.4 + data1[add_col] * 0.6;
        // data1[add_col + 1] = data2[add_col + 1] * 0.4 + data1[add_col + 1] * 0.6;
        // data1[add_col + 2] = data2[add_col + 2] * 0.4 + data1[add_col + 2] * 0.6;
 
        

        //融合后,可以利用opencv给src写入当前时间用来观察
auto              cur_time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    std::stringstream ss;
    ss << std::put_time(std::localtime(&cur_time), "%Y-%m-%d %H:%M:%S");
    std::string str_time = ss.str();
    cv::putText(src, str_time, cv::Point(830, 20), cv::HersheyFonts::FONT_ITALIC, 0.5, cv::Scalar(0, 0, 0), 1,
                4);
        video_writer_.write(src);
        src.release();
    }

    //LOG::info("RtspPushStream::run_capture() end!");
}

//头文件
#ifndef RTSHPUSHSTREAM_H
#define RTSHPUSHSTREAM_H
#include <chrono>
#include <iostream>
#include <memory>
#include <mutex>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/videoio/videoio.hpp>
#include <string>
#include <thread>
#include <vector>

 
using namespace std;
class RtspPushStream {
public:
    RtspPushStream();
    ~RtspPushStream();

    void start();
    void write_image(cv::Mat image);

    void run();
    void start_capture();
    void run_capture();
    void end();

private:
    mutex                mutex_;
    cv::VideoWriter      video_writer_;
    list<cv::Mat>        img_mats_;
    bool                 active_;
    cv::Mat              mat_;
    cv::Mat              space_mat_;
    shared_ptr<thread>   cap_thread_;
    shared_ptr<thread>   write_thread_;
    cv::VideoCapture     video_capture_;
    std::vector<cv::Mat> push_frames_;
    std::mutex           push_frames_lock_;
};
#endif


推流后用相关视频软件拉流就能看到效果,如PotPlayer 64 bit,VLC等等文章来源地址https://www.toymoban.com/news/detail-486266.html

到了这里,关于使用Gstreamer+OpenCV实现两路图像数据混合拉流推流的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 详解cv2.addWeighted函数【使用 OpenCV 添加(混合)两个图像-Python版本】

    有的时候我们需要将两张图片在alpha通道进行混合,比如深度学习数据集增强方式MixUp。OpenCV的 addWeighted 提供了相关操作,此篇博客将详细介绍这个函数,并给出代码示例。🚀🚀 o u t p u t I m g = s a t u r a t e ( α ∗ i n p u t I m g 1 + β ∗ i n p u t I m g 2 + γ ) rm outputImg=saturate( al

    2024年02月06日
    浏览(98)
  • 05- OpenCV:图像操作和图像混合

    目录 一、图像操作 1、读写图像 2、读写像素 3、修改像素值 4、Vec3b与Vec3F 5、相关的代码演示 二、图像混合 1、理论-线性混合操作 2、相关API(addWeighted) 3、代码演示(完整的例子) 一、图像操作 1、读写图像 (1)imread 可以指定加载为灰度或者RGB图像 (2)Imwrite 保存图像文件

    2024年02月01日
    浏览(49)
  • OpenCV 图像叠加、混合

            本文是OpenCV图像视觉入门之路的第9篇文章,本文详细的在图像上面进行了图像叠加图像混合等操作。 OpenCV 图像叠加、混合目录 1 图像叠加 2  图像混合         图片叠加一般加入水印用的特别多,比如视频网站、图片素材网等等         图像的混合:将两

    2024年02月11日
    浏览(41)
  • Python Opencv实践 - 图像混合

               

    2024年02月13日
    浏览(54)
  • jetson nx 使用opencv和gstreamer 硬解码

    https://blog.csdn.net/jiexijihe945/article/details/125928135 RTSP: \\\"rtspsrc location=rtsp://stream.strba.sk:1935/strba/VYHLAD_JAZERO.stream latency=4000 ! rtph264depay ! h264parse ! omxh264dec ! nvvidconv !  video/x-raw, width=1280, height=720, format=BGRx ! videoconvert ! appsink\\\" 本地MP4: \\\"filesrc location=clip.mp4 ! qtdemux ! h264parse ! omxh264dec

    2024年02月08日
    浏览(45)
  • 【opencv-python Gstreamer支持】Jetson Agx Orin手动编译opencv4.5.1加入gstreamer库,实现opencv简洁驱动GMSL2 IMX390相机

    # opencv官网下载opencv4.5.1源代码 opencv下载网址 # libtiff官网下载libtiff4的包,解决opencv编译问题 libtiff4下载地址 # libtiff安装 下载对应的安装包 tiff-4.0.10.zip ,( tiff-4.0.x.zip 都可以),解压之后,然后编译安装: # 编译安装

    2024年02月10日
    浏览(50)
  • 5. QT环境下使用OPenCV(基于TCP实现摄像头图像数据的多线程传输)

    1. 说明 通常情况下对于图像数据的采集可以放在后端进行,采集到的图像数据如果有需要可以通过通信将数据传输到前端进行显示,这其中需要使用到TCP数据传输协议和QT下的多线程开发技术。 QT当中主线程一般是界面层次的,在主线程中执行耗时较长的数据操作,会引起界

    2024年02月11日
    浏览(63)
  • jetson使用opencv和gstreamer调用csi摄像头报错:[ WARN:0] | GStreamer warning: Cannot query video position:

    出现类似的warning基本都是一个问题 VideoCapture加个参数就好了

    2024年02月12日
    浏览(48)
  • FFmpeg/opencv + C++ 实现直播拉流和直播推流(对视频帧进行处理)

    本文主要使用C++ ffmpeg库实现对除去webrtc的视频流进行拉流,而后经过自身的处理,而后通过将处理后的视频帧进行编码,最后进行推流处理。详情请看代码 参考链接: https://blog.csdn.net/weixin_45807901/article/details/129086344 https://blog.csdn.net/T__zxt/article/details/126827167

    2024年02月16日
    浏览(56)
  • 【OpenCV实现图像:使用OpenCV进行图像处理之透视变换】

    透视变换(Perspective Transformation)是一种图像处理中常用的变换手段,它用于将图像从一个视角映射到另一个视角,常被称为投影映射。透视变换可以用于矫正图像中的透视畸变,使得图像中的物体在新的视平面上呈现更加规则的形状。 透视变换通常涉及到寻找图像中的特定

    2024年02月03日
    浏览(64)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包