http://blog.youkuaiyun.com/huibailingyu/article/details/50554315
版权声明:本文为博主原创文章,未经博主允许不得转载。
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
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;
- }
在最开始发送一次即可。
- <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[n].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[n].slice_length;
- int_to_bytes(len, &body[i], 4);
- i+=4;
- memcpy(&body[i], nalu_data + slice[n].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);
- }
-
顶
- 0
-
踩
- 0