h264和aac数据打包ps包之二

news/2024/11/20 21:44:00/

        首先说一下整体思路:

        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);
}
 


http://www.ppmy.cn/news/82791.html

相关文章

机器学习基础

文章目录 机器学习的概念机器学习是什么 机器学习的分类有监督学习无监督学习强化学习图谱 监督学习深入介绍监督学习三要素实现步骤模型评估策略训练集和测试集损失函数经验风险训练误差和测试误差过拟合和欠拟合欠拟合过拟合 模型的选择正则化交叉验证 分类和回归分类问题回归…

吲哚菁绿ICG-Amine/NH2荧光标记和成像1686147-55-6

ICG-Amine是一种荧光染料&#xff0c;ICG-Amine具有良好的荧光性能&#xff0c;可用于生物医学研究中的荧光标记和成像。ICG-Amine的物理性质如下&#xff1a;化学式&#xff1a;C47H56N4O4S&#xff0c;分子量为773.04&#xff0c;外观&#xff1a;深绿色粉末溶解性&#xff1…

低功耗红外测距感应模块 引领皂液机的革新应用方案WTU201F2 B004

作为现代社会卫生意识的提升&#xff0c;智能洗手设备在公共场所的普及变得越来越重要。为了满足市场需求&#xff0c;唯创知音推出了全新的WTU201F2 B004红外测距模块&#xff0c;作为皂液机红外感应模块&#xff0c;凭借其低功耗和小体积的特点&#xff0c;这款模组将成为开发…

MySQL:数据库的约束

目录 1.数据库约束 1.1 非空&#xff1a;not null 1.2 唯一&#xff1a;unique ​​​​​​​ 1.3 默认值&#xff1a;default 1.4 列描述&#xff1a;comment 1.5 主键约束&#xff1a;primary key 1.6 外键约束 1.7 综合案例 2.插入查询结果 3.聚合函数 4.group by…

BiFormer 实验记录

代码来自文中地址 目录 一、前向传播过程 1、Path Embedding 2、BiFormer Block BRA模块 网络结构 一、前向传播过程 1、Path Embedding 见网络结构部分&#xff0c;4倍下采样 2、BiFormer Block 对应 x x self.pos_embed(x) 对应 x x self.drop_path(self.attn(…

【DolphinScheduler 安装部署】DolphinScheduler调度系统如何安装部署?

要安装DolphinScheduler&#xff08;以下简称DS&#xff09;调度系统&#xff0c;请按照以下步骤进行操作&#xff1a; 系统要求&#xff1a; 确保您的计算机满足DS的最低系统要求&#xff0c;例如操作系统版本、内存和处理器要求等。DS通常在Linux系统上运行良好。 下载DS安装…

现代 CMake 模块化项目管理指南

文章目录 一、基于CMake&#xff0c;对文件/目录组织规范1.推荐的目录组织方式2.划分子项目3.根项目的 CMakeLists.txt 配置4.子项目的 CMakeLists.txt 配置5.子项目的头文件6.子项目的源文件补充&#xff1a;GLOB 和 GLOB_RECRUSE 的区别7.头文件和源文件的一一对应关系8.只有…

ubuntu22.04切换回Xorg使用flameshot截图的问题

在ubuntu20.04时使用flameshot一切正常. 升级到ubuntu22.04之后,发现flameshot不能使用快捷键区域截图了,这个就很不方便. 在网上找了一圈后先是修改文件 /etc/gdm3/custom.conf将里面的 #WaylandEnableflase改成 WaylandEnablefalse即配置为不使用Wayland.然后重启系统,后…