1.在学会构建之前你需要了解avpacket存储的是什么类型的数据
2.rtmppackt需要的是什么类型的数据
avpacket存储的是h264数据startcode+nalu
需要将avpacket进行分离 分离代码如下
- (void)separation_avpacket_with_avpacket:(AVPacket *)av_packet{
memset(encode_pkt, 0, av_packet->size);
memcpy(encode_pkt, av_packet->data, av_packet->size);
[self.seppkt_array removeAllObjects];
SepPkt *beforpkt;
SepPkt *lastpakt;
for (int i = 0; i < av_packet->size - 4; i = i + 1) {
uint8_t num = *encode_pkt;
uint8_t num_1 = *(encode_pkt+1);
uint8_t num_2 = *(encode_pkt+2);
uint8_t num_3 = *(encode_pkt+3);
encode_pkt = encode_pkt + 1;
if ((num == '\x00' && num_1 == '\x00' && num_2 == '\x00' && num_3 == '\x01') || (num =='\x00' && num_1 == '\x00' && num_2 == '\x01')) {
if (num == '\x00' && num_1 == '\x00' && num_2 == '\x00' && num_3 == '\x01') {
SepPkt *seppkt = [[SepPkt alloc]init];
seppkt.index = i;
seppkt.seplen = 4;
if (beforpkt) {
beforpkt.length = seppkt.index - beforpkt.index;
}
beforpkt = seppkt;
[self.seppkt_array addObject:seppkt];
encode_pkt = encode_pkt + 4;
}else if(num =='\x00' && num_1 == '\x00' && num_2 == '\x01'){
SepPkt *seppkt = [[SepPkt alloc]init];
seppkt.index = i;
seppkt.seplen = 3;
if (beforpkt) {
beforpkt.length = seppkt.index - beforpkt.index;
}
beforpkt = seppkt;
[self.seppkt_array addObject:seppkt];
encode_pkt = encode_pkt + 3;
}
}
}
}
当数据分离成功后 即可构建rtmppacket
rtmppacket的构建需要对照flv格式表 rtmppacket同flv格式相类似
这个方法是构建sps以及pps
-(void)sendSpsPps:(uint8_t *)sps and_pps:(uint8_t *)pps and_spslen:(int)sps_len and_ppslen:(int)pps_len{
XCQueueObj *obj = [[XCQueueObj alloc]init];
obj->rtmp_packet = (RTMPPacket *)malloc(sizeof(RTMPPacket));
int bodysize = 13 + sps_len + 3 + pps_len;
RTMPPacket_Alloc(obj->rtmp_packet, bodysize);
int i = 0;
obj->rtmp_packet->m_body[i++] = 0x17;
obj->rtmp_packet->m_body[i++] = 0x00;
obj->rtmp_packet->m_body[i++] = 0x00;
obj->rtmp_packet->m_body[i++] = 0x00;
obj->rtmp_packet->m_body[i++] = 0x00;
obj->rtmp_packet->m_body[i++] = 0x01;
obj->rtmp_packet->m_body[i++] = sps[1];
obj->rtmp_packet->m_body[i++] = sps[2];
obj->rtmp_packet->m_body[i++] = sps[3];
obj->rtmp_packet->m_body[i++] = 0xFF;
obj->rtmp_packet->m_body[i++] = 0xE1;
obj->rtmp_packet->m_body[i++] = (sps_len >> 8) & 0xff;
obj->rtmp_packet->m_body[i++] = sps_len & 0xff;
memcpy(&obj->rtmp_packet->m_body[i], sps, sps_len);
i += sps_len;
obj->rtmp_packet->m_body[i++] = 0x01;
obj->rtmp_packet->m_body[i++] = (pps_len >> 8) & 0xff;
obj->rtmp_packet->m_body[i++] = (pps_len) & 0xff;
memcpy(&obj->rtmp_packet->m_body[i], pps, pps_len);
obj->rtmp_packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
obj->rtmp_packet->m_nBodySize = bodysize;
obj->rtmp_packet->m_nChannel = 10;
obj->rtmp_packet->m_nTimeStamp = 0;
obj->rtmp_packet->m_hasAbsTimestamp = 0;
obj->rtmp_packet->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
self.callback(obj);
}
下面是构建关键帧以及非关键帧
-(void)sendFrame:(uint8_t)type and_payload:(int)payload and_p_payload:(uint8_t *)p_payload{
XCQueueObj *obj = [[XCQueueObj alloc]init];
if (p_payload[2] == 0x00){
payload -= 4;
p_payload += 4;
} else if(p_payload[2] == 0x01){
payload -= 3;
p_payload += 3;
}
obj->rtmp_packet = (RTMPPacket*)malloc(sizeof(RTMPPacket));
int bodysize = 9 + payload;
RTMPPacket_Alloc( obj->rtmp_packet, bodysize);
RTMPPacket_Reset( obj->rtmp_packet);
obj->rtmp_packet->m_body[0] = 0x27;
if (type == '\x65') {//关键帧
obj->rtmp_packet->m_body[0] = 0x17;
}
obj->rtmp_packet->m_body[1] = 0x01;
obj->rtmp_packet->m_body[2] = 0x00;
obj->rtmp_packet->m_body[3] = 0x00;
obj->rtmp_packet->m_body[4] = 0x00;
obj->rtmp_packet->m_body[5] = (payload >> 24) & 0xff;
obj->rtmp_packet->m_body[6] = (payload >> 16) & 0xff;
obj->rtmp_packet->m_body[7] = (payload >> 8) & 0xff;
obj->rtmp_packet->m_body[8] = (payload) & 0xff;
memcpy(& obj->rtmp_packet->m_body[9],p_payload, payload);
obj->rtmp_packet->m_hasAbsTimestamp = 0;
obj->rtmp_packet->m_nBodySize = bodysize;
obj->rtmp_packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
obj->rtmp_packet->m_nChannel = 0x10;
obj->rtmp_packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
self.callback(obj);
}
构建后的数据使用callback返回到上一层然后进行推流或写入本地文件的操作