首先说一下整体思路:
1.将h264和AAC数据分别编码NAL单元和ADTS帧
2.构建PES包,依次将每个NAL单元和ADTS帧添加到对应的PES包中,并加入头部信息
3.构建PS包,将所有的PES包按照一定的规则排序并加入头部信息。
分开实现H264的PES打包,AAC的PES打包,最终是整个PS包的打包,数据调用直接一步
int PackPS(const unsigned char *h264_data, int h264_len, const unsigned char *aac_data, int aac_len, unsigned char *ps_data)
填入h264数据和aac数据直接生成ps封包数据,之后再用于rtp over udp还是其他方式传输,读者可以自行填充。
上代码!!!!!!!!!!!!!
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define H264_HEADER_LENGTH 4
#define AAC_HEADER_LENGTH 4
using namespace std;
// 计算校验和
unsigned short checksum(const unsigned char *buf, int size) {
unsigned int cksum = 0;
for (int i = 0; i < size; i += 2) {
cksum += (buf[i] << 8) | buf[i+1];
}
while ((cksum >> 16) != 0) {
cksum = (cksum & 0xffff) + (cksum >> 16);
}
return (~cksum) & 0xffff;
}
// 打包H264数据
int PackH264(const unsigned char *h264_data, int h264_len, unsigned char *ps_buffer) {
// 初始化PS头部信息
PSHeader ps_header = {0};
ps_header.sync_byte = 0x47;
ps_header.id = 0x40;
ps_header.PES_start_flag = 1;
ps_header.PES_header_data_length = 0x0c;
// 用于存放PES数据的buffer
unsigned char pes_buffer[65536];
// 分离NAL单元
const unsigned char *ptr = h264_data;
while (ptr < h264_data + h264_len) {
// 查找下一个NAL单元的开始位置
while (*(unsigned int*)ptr != 0x00000001) {
++ptr;
if (ptr >= h264_data + h264_len - 3) {
// 剩余的数据不足一个NAL单元
break;
}
}
NALHeader *nal_header = (NALHeader*)(ptr + 1);
int nal_unit_type = nal_header->nal_unit_type;
// 构建PES包头部信息
PSHeader pes_header = ps_header;
pes_header.PES_scrambling_control = 0; // 不加密
pes_header.PES_header_data_length = 0x08; // 固定为8个字节
pes_header.packet_length = htons(0x08 + nal_unit_size);
pes_header.reserved_1 = 0x02; // PTS和DTS都存在
// 添加NAL单元到PES包中
int nal_unit_size = 0;
const unsigned char *nal_start = ptr + 4;
if (nal_unit_type == 7 || nal_unit_type == 8) {
nal_start = ptr + 2;
nal_unit_size = ptr + 2 - nal_start;
} else {
nal_unit_size = ptr + 4 - nal_start;
}
unsigned char *pes_packet = new unsigned char[0x08 + nal_unit_size];
memcpy(pes_packet, "\x00\x00\x01", 3); // 添加NAL单元的header标识
memcpy(pes_packet + 3, &pes_header.packet_length, 2);
memset(pes_packet + 5, 0xff, 1); // 固定为0xff
pes_packet[6] = 0xe0 | (nal_unit_type & 0x1f); // Streaming ID,固定为0xe0
memcpy(pes_packet + 7, &pts, 5); // PTS和DTS都设置为当前时间戳
memcpy(pes_packet + 12, nal_start, nal_unit_size);
// 计算校验和
unsigned short cksum = checksum(pes_packet, 0x08 + nal_unit_size);
// 添加PES包到PS包中
int packet_len = 0x08 + nal_unit_size + 2;
memcpy(ps_buffer, &ps_header, sizeof(ps_header));
memcpy(ps_buffer + sizeof(ps_header), pes_packet, 0x08 + nal_unit_size);
memcpy(ps_buffer + sizeof(ps_header) + 0x08 + nal_unit_size, &cksum, 2);
ps_buffer += sizeof(ps_header) + packet_len;
delete[] pes_packet;
ptr += nal_unit_size;
}
return ps_buffer - ps_buffer_start;
}
// 打包AAC数据
int PackAAC(const unsigned char *aac_data, int aac_len, unsigned char *ps_buffer) {
// 初始化PS头部信息
PSHeader ps_header = {0};
ps_header.sync_byte = 0x47;
ps_header.id = 0x40;
ps_header.PES_start_flag = 1;
ps_header.PES_header_data_length = 0x0c;
// 用于存放PES数据的buffer
unsigned char pes_buffer[65536];
// 分离ADTS帧
const unsigned char *ptr = aac_data;
while (ptr < aac_data + aac_len) {
if (*(unsigned int*)ptr == 0xfff00000) {
ADTSHeader *adts_header = (ADTSHeader*)ptr;
// 构建PES包头部信息
PSHeader pes_header = ps_header;
pes_header.PES_scrambling_control = 0; // 不加密
pes_header.PES_header_data_length = 0x05; // 固定为5个字节
pes_header.packet_length = htons(0x05 + adts_header->frame_length + 7);
pes_header.reserved_1 = 0x03; // PTS和DTS都存在
// 添加ADTS帧到PES包中
unsigned char *pes_packet = new unsigned char[0x05 + adts_header->frame_length];
memcpy(pes_packet, "\x00\x00\x01", 3); // 添加ADTS帧的header标识
memcpy(pes_packet + 3, &pes_header.packet_length, 2);
memset(pes_packet + 5, 0xff, 1); // 固定为0xff
pes_packet[6] = 0xc0; // Streaming ID,固定为0xc0
memcpy(pes_packet + 7, &pts, 5); // PTS和DTS都设置为当前时间戳
memcpy(pes_packet + 12, ptr, adts_header->frame_length);
// 计算校验和
unsigned short cksum = checksum(pes_packet, 0x05 + adts_header->frame_length);
// 添加PES包到PS包中
int packet_len = 0x05 + adts_header->frame_length + 2;
memcpy(ps_buffer, &ps_header, sizeof(ps_header));
memcpy(ps_buffer + sizeof(ps_header), pes_packet, 0x05 + adts_header->frame_length);
memcpy(ps_buffer + sizeof(ps_header) + 0x05 + adts_header->frame_length, &cksum, 2);
ps_buffer += sizeof(ps_header) + packet_len;
delete[] pes_packet;
ptr += adts_header->frame_length;
} else {
++ptr;
}
}
return ps_buffer - ps_buffer_start;
}
// 打包H264和AAC数据为PS(Program Stream)
int PackPS(const unsigned char *h264_data, int h264_len, const unsigned char *aac_data, int aac_len, unsigned char *ps_data) {
// 初始化PS头部信息
……
……
return sizeof(pat_header) + sizeof(pat_buffer) +
sizeof(pmt_header) + sizeof(pmt_buffer) +
h264_size + aac_size + sizeof(end_buffer);
}