RTP 接发ps流工具改进(二)

RTP ps

上一次写了RTP工具发送RTP包,这次改进了发送和接收,真正能接收和发送图像,这次修改,使得RTP发送接收和PS流RTP发送接收都已经成功。延时在300毫秒左右。代码地址在上一篇的文章里面。
RTP 接发ps流工具改进(二)_第1张图片
下面是接收,这次使用udp 异步接收,发送到解析线程解码显示,和主界面通信使用回调函数。里面也包含了存储h264的代码,每次500帧,这些以后都将使用配置进行,现在还不完善。
RTP 接发ps流工具改进(二)_第2张图片
主要接收的改进在于使用了异步接收,同步接收依然保留,后面会做个开关去打开和关闭,发送和接收在界面上没有很好的做配置,以前是RTP 打包发送和接收,这次是PS流的打包发送和接收。读者暂时需要自己改动代码去使用。

UDPserver

这次使用的是boost的asio, 后面考虑单独使用c++20,和asio配合。

#pragma once

#include 
#include 
#include 
#include 
#include 
#include 
#include "c_rtp.h"
#include "c_thread.h"
using namespace boost;
using boost::asio::ip::udp;

typedef void(*rtp_callback_data)(void* puser, void* pkt,int len, int w, int h, uint32_t ssrc);
typedef void(*rtp_callback_log)(void* puser, const char* log,...);
#define DEFINE_EC \
boost::system::error_code ec;


class IO_Thread;
class c_udpserver:public c_thread
{
	//asio::strand v_strand;
	asio::io_context v_context;
	asio::ip::udp::socket v_socket;
	//ssrc rtpcontext
	std::unordered_map<uint32_t, s_rtp_context*> v_ctxs;

	s_rtp_context * getctx(uint32_t ssrc)
	{
		auto it = v_ctxs.find(ssrc);
		if (it != v_ctxs.end())
			return it->second;
		else
		{
			s_rtp_context *sc = new s_rtp_context();
			v_ctxs[ssrc] = sc;
			return sc;
		}
	}
	void data_call(s_rtp_context *ctx);

	int live_rtp_unpack_h264(s_rtp_context *ctx, uint8_t *data, int inlen);

	int live_rtp_unpack_ps(s_rtp_context *ctx, 
		uint8_t *data, 
		int inlen, uint32_t ssrc
	);

public:
	
	c_udpserver(short port):
		//v_strand(io_context.get_executor()),
		v_socket(v_context)
	{
		udp::endpoint ep(udp::v4(), port);
		v_socket.open(ep.protocol());
		v_socket.set_option(boost::asio::ip::udp::socket::reuse_address(true));
		boost::asio::socket_base::receive_buffer_size recv_option(2*1024*1024);
		v_socket.set_option(recv_option);
		v_socket.bind(ep);
	}
	
	~c_udpserver()
	{
		//v_context_maps.clear();
	}
	void Run();
	
	//to flv server
	void do_receive_rtp_head();
	void do_receive();


	void set_callback(void *puser, rtp_callback_data cb, rtp_callback_log cblog)
	{
		v_callback_data = cb;
		v_callback_log = cblog;
		v_user = puser;
	}
	void do_send(std::size_t length);
	
	void do_judge_spspps(s_rtp_context *ctx);
private:
	udp::endpoint sender_endpoint_;
	enum { max_length = 1500};
	char data_[max_length] = {0};
public:
	rtp_callback_data v_callback_data = NULL;
	rtp_callback_log  v_callback_log = NULL;
	void* v_user = NULL;
public:
	void Stop();
	//给线程发送信息
	void postmessage(uint32_t ssrc, int number);
	void postmessage_2interface(char* strFmt, ...);
	void postmessage_2show(void* pkt,int payload);

};

如代码所示,和界面通信主要是靠两个回调函数
rtp_callback_data v_callback_data = NULL;
rtp_callback_log v_callback_log = NULL;

其中v_user就是主界面,用空类型表示。

展示

为了不使用更多的库,先使用了GDI显示,里面也包含了SDL显示,读者可以自行修改。

class c_drawrgb24
{
public:
	c_drawrgb24(void);
	~c_drawrgb24(void);
protected:



    void CreateDoubleBuffer(HDC hdc1, int cxClient1 ,int cyClient1,HDC hdc2,int cxClient2,int cyClient2);


public:


    void Draw2(HWND hWnd,HWND hWnd2, unsigned char * buffer, int SrcW, int SrcH);
	void DrawSDL(HWND hWnd, unsigned char * buffer, int SrcW, int SrcH);
	//void DrawPInP(HWND hWnd 
public:
//图像翻转
	void SetVertial();
private:
	LPBITMAPINFO m_lpBmpInfo;
	
	bool     m_bInit;

    HBITMAP _hBm1;
	HDC _hdc_buffer1;
	HBITMAP _hBm2;
	HDC _hdc_buffer2;
	SDLDraw _sdldraw;
};
#ifdef _WIN32
#include 
#endif

#include "c_drawrgb24.h"

c_drawrgb24::c_drawrgb24(void):
	m_bInit(false),
	m_lpBmpInfo(NULL),
	_hBm1(NULL),
	_hdc_buffer1(NULL),
	_hBm2(NULL),
	_hdc_buffer2(NULL)
{
}

c_drawrgb24::~c_drawrgb24(void)
{
	if(m_lpBmpInfo)
		delete m_lpBmpInfo;
}


void c_drawrgb24::SetVertial()
{
	if(m_lpBmpInfo!=NULL)
		m_lpBmpInfo->bmiHeader.biHeight = 0-m_lpBmpInfo->bmiHeader.biHeight;
}


void c_drawrgb24::CreateDoubleBuffer(HDC hdc1, int cxClient1 ,int cyClient1,HDC hdc2,int cxClient2,int cyClient2)
{
	//创建虚拟位图
	if(hdc1!=NULL)
	{
		_hBm1 = CreateCompatibleBitmap(hdc1,cxClient1,cyClient1);     
		//创建和hdc兼容的设备
		_hdc_buffer1 = CreateCompatibleDC(hdc1);                                    
		SelectObject(_hdc_buffer1,_hBm1);		
	}
	if(hdc2!=NULL)
	{
		_hBm2 = CreateCompatibleBitmap(hdc2,cxClient2,cyClient2);     
		//创建和hdc兼容的设备
		_hdc_buffer1 = CreateCompatibleDC(hdc2);                                    
		SelectObject(_hdc_buffer2,_hBm2);		
	}
}






void c_drawrgb24::Draw2(HWND hWnd, HWND hWnd2,unsigned char * buffer, int SrcW, int SrcH)
{
	HDC hDCDst1 = NULL;
	HDC hDCDst2 = NULL;
	RECT destRect1;
	RECT destRect2;
	if(hWnd!=NULL)
	{
		hDCDst1 = GetDC(hWnd);
		GetClientRect(hWnd,&destRect1);
	}
	if(hWnd2!=NULL)
	{
		hDCDst2 = GetDC(hWnd2);
		GetClientRect(hWnd2,&destRect2);
	}

	if(!m_bInit)
	{
		m_bInit = true;
		m_lpBmpInfo=new BITMAPINFO;
		m_lpBmpInfo->bmiHeader.biSize  = sizeof(BITMAPINFOHEADER);
		m_lpBmpInfo->bmiHeader.biWidth =   SrcW;
		m_lpBmpInfo->bmiHeader.biHeight=   -SrcH;
		m_lpBmpInfo->bmiHeader.biPlanes= 1;
		m_lpBmpInfo->bmiHeader.biBitCount      = 24;
		m_lpBmpInfo->bmiHeader.biCompression   = 0;
		m_lpBmpInfo->bmiHeader.biSizeImage     = 0;
		m_lpBmpInfo->bmiHeader.biXPelsPerMeter = 0;
		m_lpBmpInfo->bmiHeader.biYPelsPerMeter = 0;
		m_lpBmpInfo->bmiHeader.biClrUsed=0;
		m_lpBmpInfo->bmiHeader.biClrImportant  = 0;

		//CDC * dc =  CDC::FromHandle(hDCDst);
		//m_pMemDC = new CMemDC(*dc,DestRect);
	}

	if(hDCDst1!=NULL)
	{
		int DstWidth  = destRect1.right-destRect1.left;
		int DstHeight = destRect1.bottom- destRect1.top;
		SetStretchBltMode(hDCDst1,STRETCH_HALFTONE);
		::StretchDIBits(
			//m_pMemDC->GetDC().GetSafeHdc(),
			hDCDst1,
			0, 0, DstWidth, DstHeight,
			0, 0, SrcW, SrcH,
			buffer, m_lpBmpInfo, DIB_RGB_COLORS, SRCCOPY );
		ReleaseDC(hWnd,hDCDst1);
	}
	if(hDCDst2!=NULL)
	{
		int DstWidth  = destRect2.right-destRect2.left;
		int DstHeight = destRect2.bottom- destRect2.top;
		SetStretchBltMode(hDCDst2,STRETCH_HALFTONE);
		::StretchDIBits(
			//m_pMemDC->GetDC().GetSafeHdc(),
			hDCDst2,
			0, 0, DstWidth, DstHeight,
			0, 0, SrcW, SrcH,
			buffer, m_lpBmpInfo, DIB_RGB_COLORS, SRCCOPY );
		ReleaseDC(hWnd2,hDCDst2);
	}

}

void c_drawrgb24::DrawSDL(HWND hWnd, unsigned char * buffer, int SrcW, int SrcH)
{
	_sdldraw.draw_init(hWnd, SrcW, SrcH);
	_sdldraw.draw(buffer, SrcW, SrcH);
}

新的代码已经提交,读者可以从我的第一篇文章中找到开源地址。

你可能感兴趣的:(c++高级技巧,c++,音视频和c++,java,物联网,RTP,PS,UDP,asio,异步)