• GB28181学习(六)——实时视音频点播(数据传输部分)


    GB28181系列文章:

    总述:https://blog.csdn.net/www_dong/article/details/132515446

    注册与注销:https://blog.csdn.net/www_dong/article/details/132654525

    心跳保活:https://blog.csdn.net/www_dong/article/details/132796612

    网络设备信息查询:https://blog.csdn.net/www_dong/article/details/132912085

    视音频点播(信令传输部分):https://blog.csdn.net/www_dong/article/details/132950064

    媒体服务器

    提供媒体流的转发、媒体存储、历史媒体信息的检索和点播服务的服务器。

    设计方案

    • jrtplib+jthread:监听、视频数据接收与转发;
    • libmpeg:对ps流解复用;
    • ffmpeg:数据解码;
    • Qt(QOpenGLWidget):视频播放;

    数据接收

    jrtplib

    jrtplib是一个面向对象的RTP封装库。

    特点:

    • 该库使用户能够发送和接收数据使用RTP,无需担心SSRC冲突、调度和传输RTCP数据等。用户只需提供库通过发送有效负载数据,库为用户提供访问权限输入RTP和RTCP数据;
    • 该库提供了几个类,这些类有助于创建RTP应用程序。大多数用户可能只需要RTPSession类来构建应用程序,或者从RTPSecureSession派生一个类来支持SRTP。这些类提供了发送RTP数据的必要功能,并在内部处理RTCP部分;

    jthread

    jrtplib的使用依赖于jthread,使用方式用两种:

    1. 用 jthread 库提供的线程自动在后台执行对数据的接收;
    2. 用户自己调用 RTPSession 中的 Poll 方法;

    下载

    下载地址:https://research.edm.uhasselt.be/jori/page/Cs/JrtplibOld.html 。

    该项目目前使用的是jrtplib-3.11.2.zip+jthread-1.3.3.zip。下载完成后使用cmake生成windows下.sln工程编译生成静态库使用。

    流程

    • 数据接收流程,该流程目前在线程中处理。
    uint8_t payload;
    while (m_running)
    {
    	Poll();
    	BeginDataAccess();
    
    	if (GotoFirstSourceWithData())
    	{
    		do
    		{
    			RTPPacket* packet = nullptr;
    			while (nullptr != (packet = GetNextPacket()))
    			{
    				payload = packet->GetPayloadType();
    				if (0 == payload)
    				{
    					DeletePacket(packet);
    					continue;
    				}
    
    				// ...
    				// rtp载荷数据处理流程
    
    				DeletePacket(packet);
    			}
    
    		} while (GotoNextSourceWithData());
    	}
    
    	EndDataAccess();
    	Sleep(30);
    }
    
    Destroy();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    数据解复用

    该流程使用的是libmpeg库,下载地址:https://github.com/ireader/media-server.git

    由于国标流是ps封装,故需要将ps流解复用获取原始数据。

    解复用代码流程:

    static void* Alloc(void* /*param*/, size_t bytes)
    {
    	return malloc(bytes);
    }
    
    static void Free(void* /*param*/, void* packet)
    {
    	free(packet);
    }
    
    static int Write(void* param, int avtype, void* pes, size_t bytes)
    {
    	assert(param);
    	CPSParse* parse = (CPSParse*)param;
    	return parse->Package(avtype, pes, bytes);
    }
    
    CPSParse::CPSParse()
    {
    	struct ps_muxer_func_t func;
    	func.alloc = Alloc;
    	func.free = Free;
    	func.write = Write;
    	m_ps = ps_muxer_create(&func, this);
    	m_ps_stream = ps_muxer_add_stream(m_ps, STREAM_VIDEO_H264, nullptr, 0);
    }
    
    CPSParse::~CPSParse()
    {
    	if (m_ps)
    		ps_muxer_destroy(m_ps);
    }
    
    int CPSParse::InputData(void* data, int len)
    {
    	if (nullptr == m_ps || nullptr == data || len <= 0)
    		return -1;
    
    	uint64_t clock = time64_now();
    	if (0 == m_ps_clock)
    		m_ps_clock = clock;
    	ps_muxer_input(m_ps, m_ps_stream, 0, (clock - m_ps_clock) * 90, (clock - m_ps_clock) * 90, data, len);
    	return 0;
    }
    
    int CPSParse::Package(int avtype, void* payload, size_t bytes)
    {
    	// 数据处理
        
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    数据解码

    通过对ps数据流解复用获取原始数据,本项目通过ffmpeg对原始数据进行解码获取yuv数据。

    关于ffmpeg的使用,可以查看:

    音视频播放器设计(一)——环境配置:https://blog.csdn.net/www_dong/article/details/124459467

    音视频播放器设计(二)——ffmpeg视频处理流程:https://blog.csdn.net/www_dong/article/details/124561444

    音视频播放器设计(三)——OpenGL绘制视频:https://blog.csdn.net/www_dong/article/details/124638515

    音视频播放器设计(四)——ffmpeg音频处理流程:https://blog.csdn.net/www_dong/article/details/125323635

    视频播放

    通过ffmpeg解码获取yuv数据,本项目通过qt的QOpenGLWidget对yuv数据进行渲染达到播放的目的。

    • 使用方法:
      • 新建一个PlayWidget类继承于QOpenGLWidget;
      • 将ffmpeg解码后的yuv数据传入PlayWidget类,保存并调用update函数;
      • update()被调用后,QOpenGLWidget::paintGL()会自动被调用,在里面进行显示;
      • 使用QOpenGLFunctions::glTexImage2D传入一帧数据进行显示;
    #include 
    #include 
    #include 
    
    class PlayWidget : public QOpenGLWidget, protected QOpenGLFunctions
    {
        public:
    	PlayWidget(QWidget *parent = nullptr);
    	virtual ~PlayWidget();
        
        // ...
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    效果展示

    在这里插入图片描述

  • 相关阅读:
    C++ 不知树系列之二叉排序树(递归和非递归遍历、删除、插入……)
    【Hack The Box】linux练习-- SolidState
    Windows 安装DotNet Core运行时库
    非零基础自学Java (老师:韩顺平) 第10章 面向对象编程(高级部分) 10.4 单例设计模式
    网络编程06-服务器编程非阻塞IO、多路复用
    数智随行 | 机器学习与图像技术:库存管理的下一个前沿
    日均请求量1.6万亿次背后,DNSPod的秘密-国密DoH篇
    不要错过,Hadoop、Spark 核心技术栈讲解
    (四) MdbCluster分布式内存数据库——业务消息处理
    【GNN报告】加拿大蒙特利尔学习算法研究所 (Mila)博后研究员张文涛: 大规模图机器学习
  • 原文地址:https://blog.csdn.net/www_dong/article/details/133581370