librtmp发送AVC,AAC数据包
2016-01-21 12:39
519 查看
1. libRTMP的包结构
packet->m_headerType: 可以定义如下:
packet->m_packetType: 音频、视频包类型
packet->m_hasAbsTimestamp: 是否使用绝对时间戳,一般定义为0。
packet->m_nChannel:音视频通道号码,音视频不要写错,
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包
在最开始发送一次即可。
3. 发送视频数据包
4. 发送音频头包
5. 发送音频包
6. 本地存储packet
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); }
相关文章推荐
- 225,常见的编程注意点
- HDOJ 2578 Dating with girls(1)
- 常用软件整理
- MFC消息解析说明
- iOS开发常用技巧
- 学习技术的几个境界
- hive表信息查询:查看表结构、表操作等
- 查看系统信息命令
- GEM5 在 Ubuntu 14.04中安装过程
- 拖拽以及常用的鼠标事件
- Adb shell常用命令及用法
- 打造Edge渲染内核的浏览器
- 50:Which two statements are true about alerts? (Choose two.) 选项 A.Clearing an alert sends the alert
- Devexpress Spreadsheet 中文教程(1)
- Spark SQL+Hive历险记
- 【HDU】 1171 Big Event in HDU
- CodeForces 609C Load Balancing
- 在tomcat6.0上部署项目 报错Tomcat version 6.0 only supports J2EE 1.2, 1.3, 1.4, and Java EE 5 Web modules
- 制度和人性
- MySQL性能优化总结