H264和AAC打包PS包代码

        段老师的干货时间又到咯,下面代码实现的是将 AAC 和 H264 数据打包成 PS 包的流程,其中包括了 PES 头、PSI 表头、MPEG-TS 头、AAC/H264 数据打包等多个步骤。此外,还包含 CRC32 校验等校验码的计算。需要注意的是,此代码示例仅供参考,具体实现需要根据实际需求进行调整和修改。

#include <iostream>
#include <fstream>
#include <vector>

using namespace std;

// 同步字节
const unsigned char SYNC_BYTE = 0x47;

int main() {
    ofstream out_file("output.ps", ios::out | ios::binary);
    vector<unsigned short> pid_list;

    // 打包 PAT(Program Association Table)
    PSITableHeader pat_header = {0};
    pat_header.m_table_id = 0x00;
    pat_header.m_section_syntax_indicator = true;
    pat_header.m_section_length = 13;
    out_file.write((const char*)&SYNC_BYTE, 1);
    out_file.write((const char*)&pat_header, sizeof(pat_header));

    unsigned short transport_stream_id = 1;
    unsigned short program_number = 1;
    unsigned short program_map_PID = 100;

    unsigned char section_number = 0;
    unsigned char last_section_number = 0;

    out_file.write((const char*)&transport_stream_id, 2);
    out_file.write((const char*)&section_number, 1);
    out_file.write((const char*)&last_section_number, 1);
    out_file.write((const char*)&program_number, 2);
    out_file.write("", 3);  // 预留为 "111"
    out_file.write((const char*)&program_map_PID, 2);
    out_file.write("", 4);  // 预留为 CRC32 校验码

    PATSection pat_section = {0};
    pat_section.m_program_number = program_number;
    pat_section.m_PID = program_map_PID;

    // 打包 PMT(Program Map Table)
    PSITableHeader pmt_header = {0};
    pmt_header.m_table_id = 0x02;
    pmt_header.m_section_syntax_indicator = true;
    pmt_header.m_section_length = 13;
    out_file.write((const char*)&SYNC_BYTE, 1);
    out_file.write((const char*)&pmt_header, sizeof(pmt_header));

    unsigned char pcr_pid = 100;
    unsigned char program_info_length = 0;

    section_number = 0;
    last_section_number = 0;

    out_file.write((const char*)&program_number, 2);
    out_file.write("", 3);  // 预留为 "111"
    out_file.write((const char*)&pcr_pid, 2);
    out_file.write("", 2);  // 预留为 "1111"
    out_file.write(&program_info_length, 1);

    PMTSection pmt_section = {0};
    pmt_section.m_program_number = program_number;
    pmt_section.m_program_map_PID = program_map_PID;
    pmt_section.m_stream_types.push_back(0x1B);  // 音频类型
    pmt_section.m_stream_types.push_back(0x1B);  // 视频类型
    pmt_section.m_elementary_PIDs.push_back(0xc0);  // 音频 PID
    pmt_section.m_elementary_PIDs.push_back(0xe0);  // 视频 PID

    // 按照顺序将 PES 包和 MPEG-TS 头打包成 PS 包
    const int AAC_PACKET_SIZE = 188 - sizeof(TSHeader);  // AAC 数据包大小
    const int H264_PACKET_SIZE = 188 - sizeof(TSHeader);  // H264 数据包大小
    unsigned char aac_packet[AAC_PACKET_SIZE];
    unsigned char h264_packet[H264_PACKET_SIZE];
    int aac_packet_len = 0, h264_packet_len = 0;

    ifstream aac_file("audio.aac", ios::in | ios::binary);
    ifstream h264_file("video.h264", ios::in | ios::binary);

    while (true) {
        // 处理 AAC 数据
        aac_file.read((char*)aac_packet, AAC_PACKET_SIZE);
        aac_packet_len = aac_file.gcount();

        if (aac_packet_len == 0) {
            break;
        }

        PackAACData(aac_packet, aac_packet_len, out_file);

        // 处理 H264 数据
        h264_file.read((char*)h264_packet, H264_PACKET_SIZE);
        h264_packet_len = h264_file.gcount();

        if (h264_packet_len == 0) {
            break;
        }

        PackH264Data(h264_packet, h264_packet_len, out_file, pid_list);
    }

    aac_file.close();
    h264_file.close();

    // 打包 PAT 表的 CRC32 校验码
    out_file.seekp(sizeof(SYNC_BYTE) + sizeof(pat_header) + pat_header.m_section_length - 4, ios::beg);
    unsigned int crc32 = 0xffffffff;

    for (int i = 0; i < sizeof(pat_section); i++) {
        crc32 ^= ((unsigned char*)(&pat_section))[i] << 24;

        for (int j = 0; j < 8; j++) {
            if (crc32 & 0x80000000) {
                crc32 = (crc32 << 1) ^ 0x04c11db7;
            } else {
                crc32 <<= 1;
            }
        }
    }

    crc32 = ~crc32;
    out_file.write((const char*)&crc32, 4);

    // 打包 PMT 表的 CRC32 校验码
    out_file.seekp(sizeof(SYNC_BYTE) + sizeof(pmt_header) + pmt_header.m_section_length - 4, ios::beg);
    crc32 = 0xffffffff;

    for (int i = 0; i < sizeof(pmt_section); i++) {
        crc32 ^= ((unsigned char*)(&pmt_section))[i] << 24;

        for (int j = 0; j < 8; j++) {
            if (crc32 & 0x80000000) {
                crc32 = (crc32 << 1) ^ 0x04c11db7;
            } else {
                crc32 <<= 1;
            }
        }
    }

    crc32 = ~crc32;
    out_file.write((const char*)&crc32, 4);

    // 打包 MPEG-TS 头和数据成 TS 包
    const int TS_PACKET_SIZE = 188;  // TS 数据包大小
    unsigned char ts_packet[TS_PACKET_SIZE];
    int ts_packet_len = 0;

    ifstream in_file("output.ps", ios::in | ios::binary);
    in_file.read((char*)ts_packet, 4);  // 跳过前面的 SYNC_BYTE 和 PAT 表头
    in_file.read((char*)ts_packet, TS_PACKET_SIZE);

    while (in_file.gcount() == TS_PACKET_SIZE) {
        ts_packet_len = TS_PACKET_SIZE;

        for (int i = 0; i < pid_list.size(); i++) {
            unsigned short pid = pid_list[i];

            if (ts_packet[1] >> 4 == 0x01 && (ts_packet[1] & 0x0f) == pid) {
                TSHeader* ts_header = (TSHeader*)ts_packet;
                ts_header->m_pid = program_map_PID;

                if (ts_header->m_adaptation_field_control == 0x02 || ts_header->m_adaptation_field_control == 0x03) {
                    int padding = TS_PACKET_SIZE - ts_packet_len - 1;
                    unsigned char* adaptation_field = ts_packet + ts_packet_len;
                    *adaptation_field++ = padding - 1;
                    memset(adaptation_field, 0xff, padding);
                    ts_packet_len += padding + 1;
                }

                out_file.write((const char*)ts_packet, ts_packet_len);
                break;
            }
        }

        in_file.read((char*)ts_packet, TS_PACKET_SIZE);
    }

    in_file.close();
    out_file.close();

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_1015787417

Show you code

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值