关于RTMPdump的使用介绍,很多的都是在Windows平台的应用,雷神有做一个系列的分析,但是雷神的也主要是以Windows平台为主。本文主要的工作是将雷神《最简单的基于librtmp的示例:发布H.264(H.264通过RTMP发布)》中的工程移植到linux系统,同时修复一些问题并且添加一部分说明。

在使用该工程之前,应该有搭建好一个RTMP服务器,同时对H264数据格式有一个较好的了解。可以参考:

    nginx 搭建rtmp流媒体服务器

    H264语法结构及编码原理

整个软件的流程图如下:

    仔细分析RTMP264_Send 函数

/**
 * 将内存中的一段H.264编码的视频数据利用RTMP协议发送到服务器
 *
 * @param read_buffer 回调函数,当数据不足的时候,系统会自动调用该函数获取输入数据。
 *					2个参数功能:
 *					uint8_t *buf:外部数据送至该地址
 *					int buf_size:外部数据大小
 *					返回值:成功读取的内存大小
 * @成功则返回1 , 失败则返回0
 */ 
int RTMP264_Send(int (*read_buffer)(unsigned char *buf, int buf_size))  
{    
	int ret;
	uint32_t now,last_update;
	  
	memset(&metaData,0,sizeof(RTMPMetadata));
	memset(m_pFileBuf,0,BUFFER_SIZE);
	if((ret=read_buffer(m_pFileBuf,m_nFileBufSize))<0)
	{
		return FALSE;
	}

	NaluUnit naluUnit;  
	// 读取SPS帧   
	ReadFirstNaluFromBuf(naluUnit,read_buffer);  
	metaData.nSpsLen = naluUnit.size;  
	metaData.Sps=NULL;
	metaData.Sps=(unsigned char*)malloc(naluUnit.size);
	memcpy(metaData.Sps,naluUnit.data,naluUnit.size);

	// 读取PPS帧   
	ReadOneNaluFromBuf(naluUnit,read_buffer);  
	metaData.nPpsLen = naluUnit.size; 
	metaData.Pps=NULL;
	metaData.Pps=(unsigned char*)malloc(naluUnit.size);
	memcpy(metaData.Pps,naluUnit.data,naluUnit.size);
	
	// 解码SPS,获取视频图像宽、高信息   
	int width = 0,height = 0, fps=0;  
	h264_decode_sps(metaData.Sps,metaData.nSpsLen,width,height,fps);  
	//metaData.nWidth = width;  
	//metaData.nHeight = height;  
	if(fps)
		metaData.nFrameRate = fps; 
	else
		metaData.nFrameRate = 25;

	//发送PPS,SPS
	//ret=SendVideoSpsPps(metaData.Pps,metaData.nPpsLen,metaData.Sps,metaData.nSpsLen);
	//if(ret!=1)
	//	return FALSE;

	unsigned int tick = 0;  
	unsigned int tick_gap = 1000/metaData.nFrameRate; 
	//printf(" nFrameRate = %d \n ",metaData.nFrameRate);
	ReadOneNaluFromBuf(naluUnit,read_buffer);
	int bKeyframe  = (naluUnit.type == 0x05) ? TRUE : FALSE;
	while(SendH264Packet(naluUnit.data,naluUnit.size,bKeyframe,tick))  
	{    
got_sps_pps:
		//if(naluUnit.size==8581)
			printf("NALU size:%8d\n",naluUnit.size);
		last_update=RTMP_GetTime();
		if(!ReadOneNaluFromBuf(naluUnit,read_buffer))
				goto end;
		if(naluUnit.type == 0x07 || naluUnit.type == 0x08)
			goto got_sps_pps;
		bKeyframe  = (naluUnit.type == 0x05) ? TRUE : FALSE;
		tick +=tick_gap;
		now=RTMP_GetTime();
		//msleep(tick_gap-now+last_update);
		//printf("now = %d, last_update = %d, now - last_update = %d \n",now,last_update,now - last_update);  
		msleep(tick_gap);
	}  
	end:
	free(metaData.Sps);
	free(metaData.Pps);
	return TRUE;  
}  

    在开始循环获取数据之前,先读取h264文件的SPS和PPS。SPS是序列参数集,PPS是图像参数集。在SPS序列参数集中可以解析出图像的宽,高和帧率等信息。而在h264文件中,最开始的两帧数据就是SPS和PPS,这个h264文件只存在一个SPS帧和一个PPS帧。在做RTMP 传输的时候,它需要在每次发送H264的I帧之前,发送SPS序列参数集帧和PPS图像参数集帧。在我们这里的处理方式是,先提取出SPS和PPS帧,然后保存起来,然后每次发送I帧之前都发送一次SPS和PPS帧。SPS帧和PPS帧如下:

    工程文件如下:
lcb@ubuntu:~/test/RTMP/rtmp_push_h264$ tree
.
├── cuc_ieschool.h264
├── include
│   ├── librtmp
│   │   ├── amf.h
│   │   ├── bytes.h
│   │   ├── dhgroups.h
│   │   ├── dh.h
│   │   ├── handshake.h
│   │   ├── http.h
│   │   ├── log.h
│   │   ├── rtmp.h
│   │   └── rtmp_sys.h
│   ├── librtmp_send264.h
│   └── sps_decode.h
├── lib
│   ├── librtmp.a
│   ├── librtmp.so
│   └── librtmp.so.0
├── librtmp_send264.cpp
├── Makefile
├── simplest_librtmp_send264.cpp
└── src
    完整的工程下载地址: RTMPdump(libRTMP) 通过RTMP 发布H264数据

 

GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐