基于librtmp,进行网络推流(264和flv)

一、RTMP传输(大部分借鉴雷神的RTMP传输)

1、简介

librtmp 这个开源库本身就是基于flv格式的数据进行传输,所以flv 上传会比较简单,

相关介绍可以看这个链接

https://blog.csdn.net/leixiaohua1020/article/details/14229543

 

2、rtmp 传输h.264视频的相关知识
想要深入理解的看一下:

https://blog.csdn.net/dqxiaoxiao/article/details/94820599

大致看了一下的意思是RTMP以前不支持264的直接传输,只能通过flv进行传输,
所以要传输的话,只能将264看起来来像flv的一种形式,再通过flv的流程去传输

 

以下开始介绍下代码:

3、publish_using_packet() 函数:

(1)在文件同级目录下放置“cuc_ieschool.flv”文件

fp=fopen("cuc_ieschool.flv","rb");

(2)通过RTMP_SetupURL接口设置将数据以rtmp协议的方式发送至“rtmp://xx.xx.xx.xx:1935/live/test”

RTMP_SetupURL(rtmp,"rtmp://xx.xx.xx.xx:1935/live/test")

(3)发送数据

RTMP_SendPacket(rtmp,packet,0)

int publish_using_packet()
{
	RTMP *rtmp=NULL;
	RTMPPacket *packet=NULL;
	uint32_t start_time=0;
	uint32_t now_time=0;
	//the timestamp of the previous frame
	long pre_frame_time=0;
	long lasttime=0;
	int bNextIsKey=1;
	uint32_t preTagsize=0;

	//packet attributes
	uint32_t type=0;
	uint32_t datalength=0;
	uint32_t timestamp=0;
	uint32_t streamid=0;

	FILE*fp=NULL;
	fp=fopen("cuc_ieschool.flv","rb");
	if (!fp){
		RTMP_LogPrintf("Open File Error.\n");
		CleanupSockets();
		return -1;
	}

	/* set log level */
	//RTMP_LogLevel loglvl=RTMP_LOGDEBUG;
	//RTMP_LogSetLevel(loglvl);

	if (!InitSockets()){
		RTMP_LogPrintf("Init Socket Err\n");
		return -1;
	}

	rtmp=RTMP_Alloc();
	RTMP_Init(rtmp);
	//set connection timeout,default 30s
	rtmp->Link.timeout=5;
	if(!RTMP_SetupURL(rtmp,"rtmp://xx.xx.xx.xx:1935/live/test"))
	{
		RTMP_Log(RTMP_LOGERROR,"SetupURL Err\n");
		RTMP_Free(rtmp);
		CleanupSockets();
		return -1;
	}

	//if unable,the AMF command would be 'play' instead of 'publish'
	RTMP_EnableWrite(rtmp);

	if (!RTMP_Connect(rtmp,NULL)){
		RTMP_Log(RTMP_LOGERROR,"Connect Err\n");
		RTMP_Free(rtmp);
		CleanupSockets();
		return -1;
	}

	if (!RTMP_ConnectStream(rtmp,0)){
		RTMP_Log(RTMP_LOGERROR,"ConnectStream Err\n");
		RTMP_Close(rtmp);
		RTMP_Free(rtmp);
		CleanupSockets();
		return -1;
	}

	packet=(RTMPPacket*)malloc(sizeof(RTMPPacket));
	RTMPPacket_Alloc(packet,1024*64);
	RTMPPacket_Reset(packet);

	packet->m_hasAbsTimestamp = 0;
	packet->m_nChannel = 0x04;
	packet->m_nInfoField2 = rtmp->m_stream_id;

	RTMP_LogPrintf("Start to send data ...\n");

	//jump over FLV Header
	fseek(fp,9,SEEK_SET);
	//jump over previousTagSizen
	fseek(fp,4,SEEK_CUR);
	start_time=RTMP_GetTime();
	while(1)
	{
		// 定时操作
		if((((now_time=RTMP_GetTime())-start_time)
			  <(pre_frame_time)) && bNextIsKey){
			//wait for 1 sec if the send process is too fast
			//this mechanism is not very good,need some improvement
			if(pre_frame_time>lasttime){
				RTMP_LogPrintf("TimeStamp:%8lu ms\n",pre_frame_time);
				lasttime=pre_frame_time;
			}
			usleep(1000000);
			continue;
		}

		//not quite the same as FLV spec
		if(!ReadU8(&type,fp))
			break;
		if(!ReadU24(&datalength,fp))
			break;
		if(!ReadTime(×tamp,fp))
			break;
		if(!ReadU24(&streamid,fp))
			break;

		if (type!=0x08&&type!=0x09){
			//jump over non_audio and non_video frame,
			//jump over next previousTagSizen at the same time
			fseek(fp,datalength+4,SEEK_CUR);
			continue;
		}

		if(fread(packet->m_body,1,datalength,fp)!=datalength)
			break;

		packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
		packet->m_nTimeStamp = timestamp;
		packet->m_packetType = type;
		packet->m_nBodySize  = datalength;
		pre_frame_time=timestamp;

		if (!RTMP_IsConnected(rtmp)){
			RTMP_Log(RTMP_LOGERROR,"rtmp is not connect\n");
			break;
		}
		int ret_size = RTMP_SendPacket(rtmp,packet,0);
		if (!ret_size){
			RTMP_Log(RTMP_LOGERROR,"Send Error\n");
			break;
		}
		else
		{
			printf("Send Size = %d \n",packet->m_nBodySize);
		}

		if(!ReadU32(&preTagsize,fp))
			break;

		if(!PeekU8(&type,fp))
			break;
		if(type==0x09){
			if(fseek(fp,11,SEEK_CUR)!=0)
				break;
			if(!PeekU8(&type,fp)){
				break;
			}
			if(type==0x17)
				bNextIsKey=1;
			else
				bNextIsKey=0;

			fseek(fp,-11,SEEK_CUR);
		}
	}

	RTMP_LogPrintf("\nSend Data Over\n");

	if(fp)
		fclose(fp);

	if (rtmp!=NULL){
		RTMP_Close(rtmp);
		RTMP_Free(rtmp);
		rtmp=NULL;
	}
	if (packet!=NULL){
		RTMPPacket_Free(packet);
		free(packet);
		packet=NULL;
	}

	CleanupSockets();
	return 0;
}

 

4、其他相关处理代码

(1)int ReadU8(uint32_t *u8,FILE*fp)

从文件中读出一个字节数据,其他16位24位32位大致如此

/**
 * Simplest Librtmp Send FLV
 *
 * 雷霄骅,张晖
 * [email protected]
 * [email protected]
 * 中国传媒大学/数字电视技术
 * Communication University of China / Digital TV Technology
 * http://blog.csdn.net/leixiaohua1020
 *
 * 本程序用于将FLV格式的视音频文件使用RTMP推送至RTMP流媒体服务器。
 * This program can send local flv file to net server as a rtmp live stream.
 */

#include 
#include 
#include 
#include 
#ifndef WIN32
#include 
#endif


#include "librtmp/include/rtmp_sys.h"
#include "librtmp/include/log.h"

#define HTON16(x)  ((x>>8&0xff)|(x<<8&0xff00))
#define HTON24(x)  ((x>>16&0xff)|(x<<16&0xff0000)|(x&0xff00))
#define HTON32(x)  ((x>>24&0xff)|(x>>8&0xff00)|\
	(x<<8&0xff0000)|(x<<24&0xff000000))
#define HTONTIME(x) ((x>>16&0xff)|(x<<16&0xff0000)|(x&0xff00)|(x&0xff000000))

/*read 1 byte*/
int ReadU8(uint32_t *u8,FILE*fp){
	if(fread(u8,1,1,fp)!=1)
		return 0;
	return 1;
}
/*read 2 byte*/
int ReadU16(uint32_t *u16,FILE*fp){
	if(fread(u16,2,1,fp)!=1)
		return 0;
	*u16=HTON16(*u16);
	return 1;
}
/*read 3 byte*/
int ReadU24(uint32_t *u24,FILE*fp){
	if(fread(u24,3,1,fp)!=1)
		return 0;
	*u24=HTON24(*u24);
	return 1;
}
/*read 4 byte*/
int ReadU32(uint32_t *u32,FILE*fp){
	if(fread(u32,4,1,fp)!=1)
		return 0;
	*u32=HTON32(*u32);
	return 1;
}
/*read 1 byte,and loopback 1 byte at once*/
int PeekU8(uint32_t *u8,FILE*fp){
	if(fread(u8,1,1,fp)!=1)
		return 0;
	fseek(fp,-1,SEEK_CUR);
	return 1;
}
/*read 4 byte and convert to time format*/
int ReadTime(uint32_t *utime,FILE*fp){
	if(fread(utime,4,1,fp)!=1)
		return 0;
	*utime=HTONTIME(*utime);
	return 1;
}

int InitSockets()
{
#if 0
	WORD version;
	WSADATA wsaData;
	version=MAKEWORD(2,2);
	return (WSAStartup(version, &wsaData) == 0);
#endif
}

void CleanupSockets()
{
#if 0
	WSACleanup();
#endif
}

参考建议:

整个工程下载地址

https://download.csdn.net/download/FDmitnick/12113323

雷神相关:

https://blog.csdn.net/leixiaohua1020/article/details/42104893

 

你可能感兴趣的:(网络传输)