• 使用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推流的过程

    1. //cpp 实现
    2. #include "rtsp_push_stream.h"
    3. static int get_thread_policy(pthread_attr_t& attr) {
    4. int policy;
    5. int rs = pthread_attr_getschedpolicy(&attr, &policy);
    6. assert(rs == 0);
    7. switch (policy) {
    8. case SCHED_FIFO:
    9. cout << "policy = SCHED_FIFO" << endl;
    10. break;
    11. case SCHED_RR:
    12. cout << "policy = SCHED_RR" << endl;
    13. break;
    14. case SCHED_OTHER:
    15. cout << "policy = SCHED_OTHER" << endl;
    16. break;
    17. default:
    18. cout << "policy = UNKNOWN" << endl;
    19. break;
    20. }
    21. return policy;
    22. }
    23. static void show_thread_priority(pthread_attr_t& attr, int policy) {
    24. int priority = sched_get_priority_max(policy);
    25. assert(priority != -1);
    26. cout << "max_priority = " << priority << endl;
    27. priority = sched_get_priority_min(policy);
    28. assert(priority != -1);
    29. cout << "min_priority = " << priority << endl;
    30. }
    31. static int get_thread_priority(pthread_attr_t& attr) {
    32. struct sched_param param;
    33. int rs = pthread_attr_getschedparam(&attr, ¶m);
    34. assert(rs == 0);
    35. cout << "priority = " << param.__sched_priority << endl;
    36. return param.__sched_priority;
    37. }
    38. static void set_thread_policy(pthread_attr_t& attr, int policy) {
    39. int rs = pthread_attr_setschedpolicy(&attr, policy);
    40. assert(rs == 0);
    41. get_thread_policy(attr);
    42. }
    43. RtspPushStream::RtspPushStream() : active_(true) {}
    44. RtspPushStream::~RtspPushStream() {}
    45. void RtspPushStream::start() {
    46. string appsrcpipeline =
    47. "appsrc ! video/x-raw, format=BGR ! queue ! videoconvert ! video/x-raw,format=RGBA ! nvvidconv ! nvv4l2h264enc "
    48. "! h264parse ! qtmux ! filesink location={filename} sync=false";
    49. //使用 rtspclientsink 需要安装插件
    50. // sudo apt-get update
    51. // sudo apt-get upgrade
    52. // sudo apt install gstreamer1.0-rtsp
    53. std::string pipeline_useglvideomixer =
    54. "appsrc "
    55. "! video/x-raw, format=BGR "
    56. "! videoconvert "
    57. "! video/x-raw,format=(string)RGBA , width=(int)1024, height=(int)600"
    58. "! queue2"
    59. "! alpha method=blue "
    60. "! glvideomixer name = compos sink_0::zorder=1 sink_0::alpha=0.85 sink_1::alpha=1 sink_1::zorder=0 "
    61. "sink_1::width=1024 sink_1::height=600 "
    62. "! nvvidconv"
    63. "! video/x-raw(memory:NVMM), format=(string)I420, width=(int)1024, height=(int)600"
    64. "! nvv4l2h264enc "
    65. "! rtspclientsink location=rtsp://192.168.20.99:8554/my_pipeline"
    66. " nvarguscamerasrc"
    67. "! video/x-raw(memory:NVMM),format=(string)NV12, width=(int)1640, height=(int)1232, framerate=(fraction)25/1"
    68. "! queue2"
    69. "! nvvidconv left=0 right=1640 top=136 bottom=1096 "
    70. "! compos. ";
    71. // nvcompsositor 的两个输入必须是一样的图片格式和内存形式,需要将云图透明部分用白色(255,255,255)填充
    72. std::string pipeline_nvcompsositor =
    73. "appsrc "
    74. "! video/x-raw, format=BGR "
    75. "! videoconvert "
    76. "! video/x-raw,format=(string)RGBA, width=(int)1024, height=(int)600"
    77. "! nvvidconv "
    78. "! queue2"
    79. "! nvcompositor name = compos sink_0::zorder=1 sink_0::alpha=0.5 "
    80. "sink_1::alpha=1 "
    81. "sink_1::zorder=0 sink_1::width=1024 sink_1::height=600 "
    82. "! nvvidconv "
    83. "! nvv4l2h264enc "
    84. "! rtspclientsink location=rtsp://192.168.20.99:8554/my_pipeline"
    85. " nvarguscamerasrc "
    86. "! video/x-raw(memory:NVMM), format=(string)NV12, width=(int)1640, height=(int)1232,framerate=(fraction)25/1 "
    87. "! nvvidconv left=0 right=1640 top=136 bottom=1096 "
    88. "! video/x-raw,format=(string)RGBA, width=(int)1024, height=(int)600 "
    89. "! videobalance brightness=0.3 "
    90. "! nvvidconv "
    91. "! queue2"
    92. "! compos. ";
    93. video_writer_.open(pipeline_nvcompsositor, cv::CAP_GSTREAMER, 0, 25, cv::Size(1024, 600));
    94. mat_ = cv::imread("test.jpg");
    95. write_thread_ = make_shared(&RtspPushStream::run, this);
    96. write_thread_->join();
    97. }
    98. void RtspPushStream::run() {
    99. int id = 0;
    100. while (active_) {
    101. space_mat_ = cv::Mat(600, 1024, CV_8UC3, cv::Scalar(0, 0, 0));
    102. video_writer_.write(space_mat_);
    103. std::this_thread::sleep_for(std::chrono::milliseconds(3));
    104. }
    105. }
    106. void RtspPushStream::end() {
    107. active_ = false;
    108. //LOG::info("RtspPushStream::end()!");
    109. }
    110. void RtspPushStream::start_capture() {
    111. std::string pipeline_camear_capture =
    112. " nvarguscamerasrc "
    113. "! video/x-raw(memory:NVMM), format=(string)NV12, width=(int)1640, "
    114. "height=(int)1232,framerate=(fraction)30/1 "
    115. "! nvvidconv left=0 right=1640 top=136 bottom=1096 "
    116. "! video/x-raw,format=(string)I420, width=(int)1024, height=(int)600 "
    117. "! videoconvert "
    118. "! video/x-raw,format=(string)BGR "
    119. "! appsink";
    120. video_capture_.open(pipeline_camear_capture, cv::CAP_GSTREAMER);
    121. if (!video_capture_.isOpened()) {
    122. //LOG::error("Failed to open VideoCapture");
    123. return;
    124. }
    125. mat_ = cv::imread("test.jpg");
    126. std::string pipeline_video_writer =
    127. "appsrc "
    128. "! video/x-raw, format=BGR "
    129. "! videoconvert "
    130. "! nvvidconv "
    131. "! nvv4l2h264enc iframeinterval=10 idrinterval=32 " //这里增加H264 i帧与idr帧次数,降低webrtc拉流时卡顿的频率和时间
    132. "! rtspclientsink location=rtsp://192.168.20.99:8554/my_pipeline";
    133. video_writer_.open(pipeline_video_writer, cv::CAP_GSTREAMER, 0, 20, cv::Size(1024, 600));
    134. cap_thread_ = make_shared(&RtspPushStream::run_capture, this);
    135. cap_thread_->detach();
    136. }
    137. void RtspPushStream::run_capture() {
    138. pthread_attr_t attr;
    139. struct sched_param sched;
    140. int rs;
    141. rs = pthread_attr_init(&attr);
    142. assert(rs == 0);
    143. int policy = get_thread_policy(attr);
    144. cout << "Show current configuration of priority" << endl;
    145. show_thread_priority(attr, policy);
    146. cout << "Show priority of current thread" << endl;
    147. int priority = get_thread_priority(attr);
    148. set_thread_policy(attr, SCHED_FIFO); // SCHED_RR
    149. cout << "Restore current policy" << endl;
    150. // set_thread_policy(attr, policy);
    151. struct sched_param param_;
    152. param_.sched_priority = sched_get_priority_max(SCHED_FIFO); // SCHED_RR
    153. //这里设置线程优先级
    154. cout << "param_.sched_priority = " << param_.sched_priority << endl;
    155. pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m_);
    156. cout << "pthread_setschedparam success" << endl;
    157. rs = pthread_attr_destroy(&attr);
    158. assert(rs == 0);
    159. cout << "start capture!!!!!!!!!" << endl;
    160. int id = 0;
    161. cv::Mat src;
    162. while (active_) {
    163. //读取摄像头内容,也就是从摄像头拉流
    164. video_capture_ >> src;
    165. //在这里自定义融合算法就行了
    166. //blender
    167. // 两张图的透明度融合算法,取rgb像素进行融合
    168. // data1[add_col] = data2[add_col] * 0.4 + data1[add_col] * 0.6;
    169. // data1[add_col + 1] = data2[add_col + 1] * 0.4 + data1[add_col + 1] * 0.6;
    170. // data1[add_col + 2] = data2[add_col + 2] * 0.4 + data1[add_col + 2] * 0.6;
    171. //融合后,可以利用opencv给src写入当前时间用来观察
    172. auto cur_time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    173. std::stringstream ss;
    174. ss << std::put_time(std::localtime(&cur_time), "%Y-%m-%d %H:%M:%S");
    175. std::string str_time = ss.str();
    176. cv::putText(src, str_time, cv::Point(830, 20), cv::HersheyFonts::FONT_ITALIC, 0.5, cv::Scalar(0, 0, 0), 1,
    177. 4);
    178. video_writer_.write(src);
    179. src.release();
    180. }
    181. //LOG::info("RtspPushStream::run_capture() end!");
    182. }
    1. //头文件
    2. #ifndef RTSHPUSHSTREAM_H
    3. #define RTSHPUSHSTREAM_H
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15.  
    16. using namespace std;
    17. class RtspPushStream {
    18. public:
    19.     RtspPushStream();
    20.     ~RtspPushStream();
    21.     void start();
    22.     void write_image(cv::Mat image);
    23.     void run();
    24.     void start_capture();
    25.     void run_capture();
    26.     void end();
    27. private:
    28.     mutex                mutex_;
    29.     cv::VideoWriter      video_writer_;
    30.     list        img_mats_;
    31.     bool                 active_;
    32.     cv::Mat              mat_;
    33.     cv::Mat              space_mat_;
    34.     shared_ptr   cap_thread_;
    35.     shared_ptr   write_thread_;
    36.     cv::VideoCapture     video_capture_;
    37.     std::vector push_frames_;
    38.     std::mutex           push_frames_lock_;
    39. };
    40. #endif


    推流后用相关视频软件拉流就能看到效果,如PotPlayer 64 bit,VLC等等

  • 相关阅读:
    基于springboot高考填报志愿综合参考系统设计与实现-计算机毕业设计源码+LW文档
    SOME/IP 协议介绍(三)参数和数据结构的序列化
    CSS 展开收起 样式
    用户考试分数大于单科科目平均分的查询
    工业信息物理系统攻击检测增强模型
    Vue——整理一些开源管理平台项目
    【C语言】模拟实现内存函数
    图像风格转换易语言代码
    前端设计模式和设计原则之设计模式
    SpringBoot-黑马程序员-学习笔记(六)
  • 原文地址:https://blog.csdn.net/zanglengyu/article/details/128130290