专栏首页EasyNVREasyRTMP推流助力EasyNVR安防摄像机互联网化,实现核心的RTSP流转RTMP/HLS(m3u8)/HTTP-FLV流功能

EasyRTMP推流助力EasyNVR安防摄像机互联网化,实现核心的RTSP流转RTMP/HLS(m3u8)/HTTP-FLV流功能

我们在常用的安防监控、互联网视频直播等系统服务中,常常最主要的就那么几个环节:

  • 视频获取:RTSP源、SDK源、GB28181源;
  • 视频输出:RTMP推流、SDK推流、GB28181 PS over RTP输出;
  • 视频转换:Demux、Mux、Codec、Snap、Info等等;

今天,我们着重讲解的是视频输出中的RTMP推流功能,这也是我们EasyNVR功能组件中,最为重要的一个组成部分! EasyRTMP是一套封装了基础的RTMP推流协议,并提供了一套非常简单易用调用接口的功能组件,在Github上有多个基于EasyRTMP SDK的Demo。Github地址:https://github.com/EasyDSS/EasyRTMP, Demo中EasyRTMP_RTSP项目是将RTSP流获取到本地进行RTMP推送,可进行RTMP直播。

RTSP视频源进行RTMP直播:EasyRTMP_RTSP

目前市面上的安防设备,现有的以及未来的,基本都是RTSP协议输出格式,且为被动拉流才能从设备获取到音视频流,更不用说直接推流到RTMP流媒体服务器或者CDN了。

在:https://github.com/EasyDSS/EasyRTMP EasyRTMP_RTSP Demo中通过libEasyRTSPClient库将RTSP数据流获取回调,再将获取来的音视频数据送给libEasyRTMP进行RTMP推送。如果获取来的数据不是AAC格式,而是G711、G726、PCM等格式,使用EasyDarwin团队提供的开源的EasyAACEncoder将音频数据转换成AAC格式再推送。这样可以实现将RTSP视频源实时的进行RTMP协议直播。

/* EasyRTSPClient获取数据后回调给上层 */
int Easy_APICALL __RTSPSourceCallBack( int _chid, void *_chPtr, int _mediatype, char *pbuf, RTSP_FRAME_INFO *frameinfo)
{
	if (NULL != frameinfo)
	{
		if (frameinfo->height==1088)		frameinfo->height=1080;
		else if (frameinfo->height==544)	frameinfo->height=540;
	}
	Easy_Bool bRet = 0;
	int iRet = 0;

	//目前只处理视频
	if (_mediatype == EASY_SDK_VIDEO_FRAME_FLAG)
	{
		if(frameinfo && frameinfo->length)
		{
			if( frameinfo->type == EASY_SDK_VIDEO_FRAME_I)
			{
				if(g_rtmpPusher.rtmpHandle == 0)
				{
					g_rtmpPusher.rtmpHandle = EasyRTMP_Create();

					bRet = EasyRTMP_Connect(g_rtmpPusher.rtmpHandle, SRTMP);
					if (!bRet)
					{
						printf("Fail to EasyRTMP_Connect ...\n");
					}

					EASY_MEDIA_INFO_T mediaInfo;
					memset(&mediaInfo, 0, sizeof(EASY_MEDIA_INFO_T));
					mediaInfo.u32VideoFps = 25;
					mediaInfo.u32AudioSamplerate = 8000;
					iRet = EasyRTMP_InitMetadata(g_rtmpPusher.rtmpHandle, &mediaInfo, 1024);
					if (iRet < 0)
					{
						printf("Fail to InitMetadata ...\n");
					}
				}

				EASY_AV_Frame avFrame;
				memset(&avFrame, 0, sizeof(EASY_AV_Frame));
				avFrame.u32AVFrameFlag = EASY_SDK_VIDEO_FRAME_FLAG;
				avFrame.u32AVFrameLen = frameinfo->length;
				avFrame.pBuffer = (unsigned char*)pbuf;
				avFrame.u32VFrameType = EASY_SDK_VIDEO_FRAME_I;
				avFrame.u32TimestampSec = frameinfo->timestamp_sec;
				avFrame.u32TimestampUsec = frameinfo->timestamp_usec;
				
				iRet = EasyRTMP_SendPacket(g_rtmpPusher.rtmpHandle, &avFrame);
				if (iRet < 0)
				{
					printf("Fail to EasyRTMP_SendH264Packet(I-frame) ...\n");
				}
				else
				{
					printf("I");
				}
			}
			else
			{
				if(g_rtmpPusher.rtmpHandle)
				{
					EASY_AV_Frame avFrame;
					memset(&avFrame, 0, sizeof(EASY_AV_Frame));
					avFrame.u32AVFrameFlag = EASY_SDK_VIDEO_FRAME_FLAG;
					avFrame.u32AVFrameLen = frameinfo->length-4;
					avFrame.pBuffer = (unsigned char*)pbuf+4;
					avFrame.u32VFrameType = EASY_SDK_VIDEO_FRAME_P;
					avFrame.u32TimestampSec = frameinfo->timestamp_sec;
					avFrame.u32TimestampUsec = frameinfo->timestamp_usec;
					iRet = EasyRTMP_SendPacket(g_rtmpPusher.rtmpHandle, &avFrame);
					if (iRet < 0)
					{
						printf("Fail to EasyRTMP_SendH264Packet(P-frame) ...\n");
					}
					else
					{
						printf("P");
					}
				}
			}				
		}	
	}
	else if (_mediatype == EASY_SDK_AUDIO_FRAME_FLAG)
	{
		EASY_AV_Frame	avFrame;
		memset(&avFrame, 0x00, sizeof(EASY_AV_Frame));
		avFrame.u32AVFrameFlag = EASY_SDK_AUDIO_FRAME_FLAG;
		avFrame.u32TimestampSec = frameinfo->timestamp_sec;
		avFrame.u32TimestampUsec = frameinfo->timestamp_usec;

		if(frameinfo->codec == EASY_SDK_AUDIO_CODEC_AAC)
		{
			avFrame.pBuffer = (Easy_U8*)(pbuf);
			avFrame.u32AVFrameLen  = frameinfo->length;	
			printf("*");
			iRet = EasyRTMP_SendPacket(g_rtmpPusher.rtmpHandle, &avFrame);
		}
		else if ((frameinfo->codec == EASY_SDK_AUDIO_CODEC_G711A) || (frameinfo->codec == EASY_SDK_AUDIO_CODEC_G711U) || (frameinfo->codec == EASY_SDK_AUDIO_CODEC_G726))
		{
			if(EasyInitAACEncoder(frameinfo) == 0)
			{
				memset(g_rtmpPusher.m_pAACEncBufer, 0, 64*1024);
				unsigned int iAACBufferLen = 0;

				if(Easy_AACEncoder_Encode(g_rtmpPusher.m_pAACEncoderHandle, (unsigned char*)pbuf,  frameinfo->length, g_rtmpPusher.m_pAACEncBufer, &iAACBufferLen) > 0)
				{
					printf("*");
					avFrame.pBuffer = (Easy_U8*)(g_rtmpPusher.m_pAACEncBufer);
					avFrame.u32AVFrameLen  = iAACBufferLen;	
					iRet = EasyRTMP_SendPacket(g_rtmpPusher.rtmpHandle, &avFrame);
				}
			}
		}
	}

	return 0;
}

接收RTMP推流并进行RTMP/FLV/HLS/RTSP同步输出:EasyDSS

通常情况下,EasyRTMP推流到标准的RTMP流媒体服务器就能实现基础的RTMP、HLS(m3u8)直播功能,但,如果需要得到一个更好的直播输出效果,我们通常选择的是EasyDSS流媒体服务器,EasyDSS流媒体服务器解决方案是一套集流媒体点播、转码与管理、直播、录像、检索、时移回看于一体的一套完整的商用流媒体服务器解决方案,EasyDSS高性能RTMP流媒体服务器支持RTMP推流,同步输出HTTP、RTMP、HLS、HTTP-FLV、RTSP,支持推流分发/拉流分发,支持秒开、GOP缓冲、录像、检索、回放、录像下载、网页管理等多种功能,是目前市面上最合理的一款流媒体服务器!

Copyright © EasyNVR.com 2016-2019

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 安防互联网直播在高速公路通讯中的应用

    其实安防互联网直播发展到现在这个阶段,已经不仅仅是单一的视频监控接入的功能了,可以更多使用在交通、教育方面。我以前就为大家介绍过https接入我们国标流媒体服务...

    EasyNVR
  • 新版视频流媒体服务器首页界面版本号显示异常问题解决

    EasyNVR核心在于摄像机的音视频流的获取、转换、转码与高性能分发,同时同步完成对实时直播流的录像存储,在客户端(PC浏览器、Android、iOS、微信)进...

    EasyNVR
  • 编译企业视频通话EasyRTC报You must install libavformat错误解决方案

    很多集团化的公司由于在不同城市甚至不同国家有很多分站点,因此远程会议和办公对这些企业来说是十分必要的,EasyRTC恰好适应了这些需求,成为远程会议和通话的不二...

    EasyNVR
  • springboot应用-shiro增强权限管理

    此部分主要是基于mybatis-plus,来实现相关的entity、mapper和service:

    技术路漫漫
  • dispatchTouchEvent事件分发浅析(三)点击执行顺序

    上一篇,我们大体理解了分发的过程 理解了在 dispatchTouchEvent 和 onTouchEvent 的过程中 对应的顺序 还有 View 和 V...

    dodo_lihao
  • [简约webAPI]php连接MSsql server的五种方法总结

    参考了下php官方手册总结了五种PHP连接MSsql server的方法,mssql_系列函数,sqlsrv_系列函数,odbc方式连接sqlserver,PD...

    landv
  • AndroidStudio制作个人资料界面模块以及SQLite数据库的使用

    大家好,我是 Vic,今天给大家带来AndroidStudio制作个人资料界面模块以及SQLite数据库的使用的概述,希望你们喜欢

    达达前端
  • OpenCV实战应用必备技能 | 模块裁剪

    OpenCV是一个大而全的完整的计算机视觉库,有时候我们项目只是用到了一些基础功能,并没有必要用OPenCV的官方编译好的版本,那个对我们来说太大啦,这个时候其...

    OpenCV学堂
  • 腾讯社招iOS面试记录

    毕业好几年了,上周发送了简历给腾讯,参加了腾讯面试。具体部门这边就不说了。这次面试还是收获到了很多。

    iOSSir
  • 可视化概率密度函数及分布的随机样本

    WolframChina

扫码关注云+社区

领取腾讯云代金券