使用Librtmp进行的简单推流

一、整体流程

1、建立Rtmp连接

2、发送Audio Header 和Video Header

3、发送Audio和Video数据包

二、时间戳处理

需要注意的是,无论是发送视频数据包还是音频数据包,时间戳一定要是递增的,否则会出现音频卡顿,视频闪烁一类的异常情况。

下面是packet时间戳的伪代码:

double m_TimeStamp = 0;
void Send_Audio()
{
    if(m_TimeStamp == 0)    m_TimeStamp = GetTickCount64();
    double TimeStamp = GetTickCount64() - m_TimeStamp;
    SendAudioPacket(TimeStamp);
}
void Send_Video()
{
    if(m_TimeStamp == 0)    m_TimeStamp = GetTickCount64();
    double TimeStamp = GetTickCount64() - m_TimeStamp;
    SendVideoPacket(TimeStamp);
}

下面是构造数据包的代码示例:

    if(nPacketType == RTMP_PACKET_TYPE_AUDIO)
	{
		packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
		packet.m_packetType = RTMP_PACKET_TYPE_AUDIO;
		packet.m_hasAbsTimestamp = 0;
		packet.m_nChannel = STREAM_CHANNEL_AUDIO;
		packet.m_nTimeStamp = nTimestamp;
		packet.m_nInfoField2 = m_pRtmp->m_stream_id;
		packet.m_nBodySize = size;
	}
	else if(nPacketType == RTMP_PACKET_TYPE_VIDEO)
	{
		packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
		packet.m_packetType = nPacketType;
		packet.m_hasAbsTimestamp = 0;
		packet.m_nChannel = STREAM_CHANNEL_VIDEO;
		packet.m_nTimeStamp = nTimestamp;
		packet.m_nInfoField2 = m_pRtmp->m_stream_id;
		packet.m_nBodySize = size;
	}

下面是Audio Header部分的代码示例及解析

int RtmpStream::rtmp_audio_header(RtmpMetadata &pMetaData)
{
	RTMPPacket packet;
	RTMPPacket_Reset(&packet);
	RTMPPacket_Alloc(&packet, 4);

	//前4位 |1010| 代表音频数据编码类型为 AAC
	//接下来 2 位 |11| 表示采样率为 44kHz
	//接下来 1 位 |1| 表示采样点位数 16bit
	//最低 1 位 |1| 表示双声道。
	//(10101111)B = (AF)H
	packet.m_body[0] = 0xAF;
	//0x00表示传输的音频数据为Audio Sequence Header
	//如果是0x01表示发送的数据为音频data数据。
	packet.m_body[1] = 0x00;
	//AudioSpecificType			5bit	AAC-LC=2	00010
	//samplingFrequencyIndex	4bit	48000=3		0011	44100=4		0100
	//channelConfiguration		4bit	单声道=1	0001	双声道=2	0010
	//frameL.engthFlag			1bit	标志位, 用于表明IMDCT窗口长度, 0
	//dependsOnCoreCoder		1bit	标志位, 表明是否依赖于corecoder, 0
	//extensionFlag				1bit	选择了AAC - LC, 这里必须为0
	//(00010 0011 0010 000)B = (1190)H
	/*
	//48000
	packet.m_body[2] = 0x11;
	packet.m_body[3] = 0x90;
	//44100
	packet.m_body[2] = 0x12;
	packet.m_body[3] = 0x10;
	*/
	packet.m_body[2] |= (1 << 4);
    //自适应单通道或双通道
	if (pMetaData.nAudioChannels == 1)
		packet.m_body[3] |= (1 << 3);
	else if (pMetaData.nAudioChannels == 2)
		packet.m_body[3] |= (1 << 4);

    //自适应采样频率32000、44100、48000
	if (pMetaData.nAudioSampleSize == 48000)
	{
		packet.m_body[2] |= (1);
		packet.m_body[3] |= (1 << 7);
	}
	else if (pMetaData.nAudioSampleSize == 44100)
	{
		packet.m_body[2] |= (1 << 1);
	}
	else if (pMetaData.nAudioSampleSize == 32000)
	{
		packet.m_body[2] |= (1 << 1);
		packet.m_body[3] |= (1 << 7);
	}

	packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
	packet.m_packetType = RTMP_PACKET_TYPE_AUDIO;
	packet.m_hasAbsTimestamp = 0;
	packet.m_nChannel = STREAM_CHANNEL_AUDIO;
	packet.m_nTimeStamp = 0;
	packet.m_nInfoField2 = m_pRtmp->m_stream_id;
	packet.m_nBodySize = 4;

	//调用发送接口
	int nRet;
	{
		std::lock_guard<std::mutex> lck(m_mtxRtmp);
		nRet = RTMP_SendPacket(m_pRtmp, &packet, TRUE);
	}
	RTMPPacket_Free(&packet);//释放内存  
	return nRet;
}

https://www.adobe.com/content/dam/acom/en/devnet/flv/video_file_format_spec_v10.pdf

### 回答1: librtmp是一个用于从媒体服务器中拉取或向媒体服务器的库。它的使用相对复杂,需要掌握一些基本操作和概念。下面是一个使用librtmp的实例: 1. 首先,我们需要创建一个RTMP对象,并与媒体服务器建立连接: RTMP* rtmp = RTMP_Alloc(); RTMP_Init(rtmp); RTMP_SetupURL(rtmp, "rtmp://server.com/stream"); RTMP_EnableWrite(rtmp); if(!RTMP_Connect(rtmp, NULL) || !RTMP_ConnectStream(rtmp, 0)) { // 连接失败,需要进行错误处理 return; } 2. 接下来,我们可以向服务器,例如: RTMPPacket* packet = RTMP_AllocPacket(1024); RTMPPacket_Reset(packet); packet->m_packetType = RTMP_PACKET_TYPE_AUDIO; packet->m_nChannel = RTMP_STREAM_CHANNEL_AUDIO; packet->m_nTimeStamp = RTMP_GetTime(); packet->m_body = ... // 将待送的音频数据填充到packet的m_body中 packet->m_nBodySize = ... // 记录音频数据的大小 if(!RTMP_SendPacket(rtmp, packet, TRUE)) { // 送失败,需要进行错误处理 } RTMP_FreePacket(packet); 3. 拉取服务器的也类似,我们可以使用RTMP_Read方法从服务器读取数据: RTMPPacket* packet = RTMP_AllocPacket(1024); while(RTMP_Read(rtmp, packet) > 0) { // 处理packet数据 } RTMP_FreePacket(packet); 以上是一个简单librtmp使用实例,实际使用时需要根据具体需求进行修改和扩展。同时,需要注意librtmp本身存在一些稳定性和性能问题,需要谨慎使用。 ### 回答2: librtmp是一个使用C语言编写的开源软件库,主要用于RTMP协议的数据传输。librtmp使用示例中,可以使用它来发送和接收媒体数据,这里简单介绍一下librtmp使用实例: 1.打开URL:使用RTMP_Open()函数打开一个RTMP媒体连接,需要传入一个URL字符串参数,这个URL可以是本地文件或者是远程主机。 2.设置元数据:使用RTMP_SetMetadata()函数,设置元数据,这些元数据包括视频宽度,高度,帧速率和音频的采样率。 3.建立:使用RTMP_AllocStream()函数,建立一个并返回ID,在使用RTMP_SendPacket()函数发送数据之前,首先要通过RTMP_AllocStream()函数建立一个ID。 4.发送数据:使用RTMP_SendPacket()函数发送音频或视频数据包,通过ID确定数据发送到哪个。 5.接收数据:使用RTMP_ReadPacket()函数从中读取数据包,该函数会一直等待数据包,直到有数据包可用或者连接被关闭才返回。 6.关闭连接:使用RTMP_Close()函数关闭连接。 需要注意的是,使用librtmp时需要安装librtmp库,另外需要在编译选项中加入-lrtmp参数,具体实现过程中还需注意一些细节问题,如何正确的打开媒体连接、如何正确读取数据进行解码等等。 总的来说,librtmp使用实例较为繁琐,但是通过掌握这些细节问题,可以更深入的了解到媒体传输的过程,进而更好的实现媒体数据的传输和解码。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值