您的位置:首页 > 其它

librtmp发送AVC,AAC数据包

2016-01-21 12:39 519 查看
1. libRTMP的包结构

typedef struct RTMPPacket
{
uint8_t  m_headerType;
uint8_t  m_packetType;
uint8_t  m_hasAbsTimestamp;
int      m_nChannel;
uint32_t m_nTimeStamp;
int32_t  m_nInfoField2;
uint32_t m_nBodySize;
uint32_t m_nBytesRead;
RTMPChunk *m_chunk;
char    *m_body;
} RTMPPacket;


packet->m_headerType: 可以定义如下:

#define RTMP_PACKET_SIZE_LARGE    0
#define RTMP_PACKET_SIZE_MEDIUM   1
#define RTMP_PACKET_SIZE_SMALL    2
#define RTMP_PACKET_SIZE_MINIMUM  3
一般定位为 RTMP_PACKET_SIZE_MEDIUM

packet->m_packetType: 音频、视频包类型

#define RTMP_PACKET_TYPE_AUDIO    0x08
#define RTMP_PACKET_TYPE_VIDEO    0x09
#define RTMP_PACKET_TYPE_INFO     0x12
还有其他更多类型,但一般都是 音频或视频

packet->m_hasAbsTimestamp: 是否使用绝对时间戳,一般定义为0。

packet->m_nChannel:音视频通道号码,音视频不要写错,

#define STREAM_CHANNEL_METADATA  0x03
#define STREAM_CHANNEL_VIDEO     0x04
#define STREAM_CHANNEL_AUDIO     0x05


packet->m_nTimeStamp:时间戳

一般视频时间戳可以从0开始计算,每帧时间戳 + 1000/fps (25fps每帧递增25;30fps递增33)

音频时间戳也可以从0开始计算,48K采样每帧递增21;44.1K采样每帧递增23。

packet->m_nInfoField2 = rtmp->m_stream_id

packet->m_nBodySize:数据包长度 = NALU包长度 + 包头长度

packet->m_nBytesRead:不用管

packet->m_chunk: 不用管

packet->m_body:包头数据 + NALU数据,其长度为packet->m_nBodySize。

2. 发送视频SPS,PPS包

int rtmp_write_video_header(RTMP *rtmp) {
int size = 10 + 3 + sps_pps.sps_length + 3 + sps_pps.pps_length;

RTMPPacket packet;
RTMPPacket_Reset(&packet);
RTMPPacket_Alloc(&packet, size);
unsigned char *body = packet.m_body;

int i = 0;
body[i++] = 0x17;
body[i++] = 0x00;

body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = 0x00;

//AVCDecoderConfigurationRecord
body[i++] = 0x01;
body[i++] = sps_pps.sps_data[1];
body[i++] = sps_pps.sps_data[2];
body[i++] = sps_pps.sps_data[3];
body[i++] = 0xFF;

//sps
body[i++] = 0xE1;
body[i++] = (sps_pps.sps_length >> 8) & 0xFF;
body[i++] =  sps_pps.sps_length       & 0xFF;
memcpy(&body[i], sps_pps.sps_data, sps_pps.sps_length);  // 复制sps数据
i +=  sps_pps.sps_length;

// pps
body[i++] = 0x01;
body[i++] = (sps_pps.pps_length >> 8) & 0xFF;
body[i++] =  sps_pps.pps_length       & 0xFF;
memcpy(&body[i], sps_pps.pps_data, sps_pps.pps_length);  // 复制pps数据
i +=  sps_pps.pps_length;

packet->m_headerType  = RTMP_PACKET_SIZE_MEDIUM;
packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
packet->m_hasAbsTimestamp = 0;
packet->m_nChannel   = STREAM_CHANNEL_VIDEO;
packet->m_nTimeStamp = 0;
packet->m_nInfoField2 = rtmp->m_stream_id;
packet->m_nBodySize  = size;

//调用发送接口
int nRet = RTMP_SendPacket(rtmp, packet, TRUE);
RTMPPacket_Free(&packet);
return nRet;
}


在最开始发送一次即可。

3. 发送视频数据包
<pre name="code" class="cpp">int rtmp_write_video_frame(RTMP *rtmp, const BYTE *nalu_data, int slice_count, int nTimestamp){
int n;
int nRet =0;
int size = 0;
for(n=0; n<slice_count; n++)
size += (slice
.slice_length + 4);  // 每个slice数据前要加4字节的slice长度

size += 5;                                // 5字节头
RTMPPacket packet;
RTMPPacket_Reset(&packet);
RTMPPacket_Alloc(&packet, size);
unsigned char *body = packet.m_body;

// NALU size
int i=0;
body[0] = ((slice[0].slice_type&0x1F) == 0x5) ? 0x17 : 0x27;
body[1] = 0x01;  // AVC NALU
body[2] = 0x00;
body[3] = 0x00;
body[4] = 0x00;
i=5;

//包体内存
packet.m_headerType  = RTMP_PACKET_SIZE_LARGE;
packet.m_packetType = RTMP_PACKET_TYPE_VIDEO;
packet.m_hasAbsTimestamp = 0;
packet.m_nChannel   = STREAM_CHANNEL_VIDEO;
packet.m_nTimeStamp = nTimestamp;
packet.m_nInfoField2 = rtmp->m_stream_id;
packet.m_nBodySize  = size;

for(n=0; n<slice_count; n++) {
int len = slice
.slice_length;
int_to_bytes(len, &body[i], 4);
i+=4;
memcpy(&body[i], nalu_data + slice
.start_address, len);
i += len;
}

//发送
if (RTMP_IsConnected(rtmp)){
nRet = RTMP_SendPacket(rtmp, &packet, TRUE); //TRUE为放进发送队列,FALSE是不放进发送队列,直接发送
if(nRet <= 0) {
printf("RTMP_SendPacket Error\n");
}
}

//释放内存
RTMPPacket_Free(&packet);
return nRet;
}




4. 发送音频头包

int rtmp_write_audio_header(RTMP *rtmp){
RTMPPacket packet;
RTMPPacket_Reset(&packet);
RTMPPacket_Alloc(&packet, 4);

packet.m_body[0] = 0xAF;  // MP3 AAC format 48000Hz
packet.m_body[1] = 0x00;
packet.m_body[2] = 0x11;
packet.m_body[3] = 0x90;//0x10修改为0x90,2016-1-19

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 = 0;
packet.m_nInfoField2 = rtmp->m_stream_id;
packet.m_nBodySize  = 4;

//调用发送接口
int nRet = RTMP_SendPacket(rtmp, &packet, TRUE);
RTMPPacket_Free(&packet);//释放内存
return nRet;
}
在最开始发送一次即可。

5. 发送音频包

int rtmp_write_audio_data(RTMP *rtmp, const BYTE *nalu_data, int nalu_size, int audio_TimeStamp){
//rtmp包结构
int size = nalu_size + 2;
RTMPPacket packet;
RTMPPacket_Reset(&packet);
RTMPPacket_Alloc(&packet, size);

int i=0;
// MP3 AAC format 48000Hz
packet.m_body[i++] = 0xAF;
packet.m_body[i++] = 0x01;
memcpy(&packet.m_body[i], nalu_data, nalu_size);

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 = audio_TimeStamp;
packet.m_nInfoField2 = rtmp->m_stream_id;
packet.m_nBodySize  = size;

//调用发送接口
int nRet = RTMP_SendPacket(rtmp, &packet, TRUE);
RTMPPacket_Free(&packet);//释放内存
return nRet;
}


6. 本地存储packet

int RTMP_SendPacket_wrap(RTMP_ *rtmp, RTMPPacket *packet, int queue){
#if OUTPUT_FLV
uint8_t data[] = {0x09,
0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00 };
if(packet->m_packetType == RTMP_PACKET_TYPE_VIDEO){
data[0] = 0x09;
} else if(packet->m_packetType == RTMP_PACKET_TYPE_AUDIO){
data[0] = 0x08;
}
int len = 0;
int_to_bytes(packet->m_nBodySize,  &data[1], 3);  // 3字节 包内容长度
int_to_bytes(packet->m_nTimeStamp, &data[4], 3);  // 3字节 时间戳,没用第4字节,太长的文件会溢出
len += fwrite(data, 1, 11, flv_fp);               // 写入包头11字节
len += fwrite(packet->m_body, 1, packet->m_nBodySize, flv_fp); // 写入数据包体
int_to_bytes(len, &data[0], 4);                   // 写入的总字节长度
fwrite(data, 1, 4, flv_fp);                       // 等于前Tag总长度
#endif
return RTMP_SendPacket(rtmp, packet, queue);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: