QT 不使用ffmpeg将MPEG2-TS解封装为ES

不使用ffmpeg将只有视频流的MPEG2-TS解封装为ES,直接根据协议解。

解封装的同时还解码为YUV

此程序为验证功能,没有考虑效率和代码规范。

测试程序可用性:输入一个mpeg2-ts文件,输出一个.mpeg2和一个.yuv文件

最终结果如下:
在这里插入图片描述

头文件

#ifndef TS2H264_C_H
#define TS2H264_C_H

#include <QObject>
#include "ffmpegheader.h"
#include <vector>
class ts2H264_C
{
public:
    ts2H264_C();
    int _start();
    void insertVector(unsigned char *buff,int len);
    int decode();
    std::vector<unsigned char> vOneFullPacket;
};

#endif // TS2H264_C_H

CPP文件

#include "ts2h264_c.h"

ts2H264_C::ts2H264_C()
{
    vOneFullPacket.clear();
}
static int nCountFrame = 0;
static bool gif_I_Frame = false;//第一个I帧是否出现
static FILE *out_yuv = fopen("out.yuv","wb+");
typedef struct _TS_head
{
    unsigned char sync_byte                     :8;           //就是0x47,这是DVB TS规定的同步字节,固定是0x47.
    unsigned char transport_error_indicator     :1;           // 0 表示当前包没有发生传输错误.
    unsigned char payload_unit_start_indicator  :1;           // 含义参考ISO13818-1标准文档
    unsigned char transport_priority            :1;           //    表示当前包是低优先级.
    unsigned short PID                          :13;
    unsigned char transport_scrambling_control  :2;           //表示节目没有加密
    unsigned char adaptation_field_control      :2;           // 即0x01,具体含义请参考ISO13818-1
    unsigned char continuity_counte             :4;           //即0x02,表示当前传送的相同类型的包是第3个
}TS_head;
typedef struct TS_PAT_Program
{
    unsigned program_number                 :  16;  //节目号
    unsigned reserved_3                     :  3; // 保留位
    unsigned program_map_PID_network_PID    :  13; // 节目映射表的PID,节目号大于0时对应的PID,每个节目对应一个
}TS_PAT_Program;
typedef struct TS_PAT
{
    unsigned table_id                     : 8; //固定为0x00 ,标志是该表是PAT表
    unsigned section_syntax_indicator     : 1; //段语法标志位,固定为1
    unsigned zero                         : 1; //0
    unsigned reserved_1                   : 2; // 保留位
     unsigned section_length              : 12; //表示从下一个字段开始到CRC32(含)之间有用的字节数
    unsigned transport_stream_id          : 16; //该传输流的ID,区别于一个网络中其它多路复用的流
    unsigned reserved_2                   : 2;// 保留位
    unsigned version_number               : 5; //范围0-31,表示PAT的版本号
    unsigned current_next_indicator       : 1; //发送的PAT是当前有效还是下一个PAT有效
    unsigned section_number               : 8; //分段的号码。PAT可能分为多段传输,第一段为00,以后每个分段加1,最多可能有256个分段
    unsigned last_section_number          : 8;  //最后一个分段的号码
    std::vector<TS_PAT_Program> vProgram;
    //unsigned reserved_3                   : 3; // 保留位
    //unsigned network_PID                  : 13; //网络信息表(NIT)的PID,节目号为0时对应的PID为network_PID
    unsigned CRC_32                       : 32;  //CRC32校验码
} TS_PAT;
typedef struct TS_PMT_Stream
{
 unsigned stream_type                       : 8; //指示特定PID的节目元素包的类型。该处PID由elementary PID指定
 unsigned elementary_PID                    : 13; //该域指示TS包的PID值。这些TS包含有相关的节目元素
 unsigned ES_info_length                    : 12; //前两位bit为00。该域指示跟随其后的描述相关节目元素的byte数
 unsigned descriptor;
}TS_PMT_Stream;
static std::vector<TS_PAT_Program> g_vTS_program;
//PMT 表结构体
typedef struct TS_PMT
{
    unsigned table_id                        : 8; //固定为0x02, 表示PMT表
    unsigned section_syntax_indicator        : 1; //固定为0x01
    unsigned zero                            : 1; //0x01
    unsigned reserved_1                      : 2; //0x03
    unsigned section_length                  : 12;//首先两位bit置为00,它指示段的byte数,由段长度域开始,包含CRC。
    unsigned program_number                    : 16;// 指出该节目对应于可应用的Program map PID
    unsigned reserved_2                        : 2; //0x03
    unsigned version_number                    : 5; //指出TS流中Program map section的版本号
    unsigned current_next_indicator            : 1; //当该位置1时,当前传送的Program map section可用;
                                                     //当该位置0时,指示当前传送的Program map section不可用,下一个TS流的Program map section有效。
    unsigned section_number                    : 8; //固定为0x00
    unsigned last_section_number            : 8; //固定为0x00
    unsigned reserved_3                        : 3; //0x07
    unsigned PCR_PID                        : 13; //指明TS包的PID值,该TS包含有PCR域,
            //该PCR值对应于由节目号指定的对应节目。
            //如果对于私有数据流的节目定义与PCR无关,这个域的值将为0x1FFF。
    unsigned reserved_4                        : 4; //预留为0x0F
    unsigned program_info_length            : 12; //前两位bit为00。该域指出跟随其后对节目信息的描述的byte数。

    std::vector<TS_PMT_Stream> vPMT_Stream;  //每个元素包含8位, 指示特定PID的节目元素包的类型。该处PID由elementary PID指定
    unsigned reserved_5                        : 3; //0x07
    unsigned reserved_6                        : 4; //0x0F
    unsigned CRC_32                            : 32;
} TS_PMT;
static TS_PAT gPAT;
static TS_PMT gPMT;
static void get_ts_header(TS_head &ts_head,unsigned char *buff)
{
    ts_head.sync_byte = (unsigned char)buff[0];
    ts_head.transport_error_indicator = buff[1] >>7;
    ts_head.payload_unit_start_indicator =  buff[1] >>6 & 0x1;
    ts_head.transport_priority = buff[1] >>5 & 0x1;
    ts_head.PID = ((buff[1] & 0x1F)<< 8) | buff[2];
    ts_head.transport_scrambling_control = buff[3]>>6 & 0x3;
    ts_head.adaptation_field_control = buff[3]>>4 & 0x3;
    ts_head.continuity_counte =  buff[3] & 0xF;
}
static void adjust_PAT_table( TS_PAT * ts_pat, unsigned char * buffer)
{
    ts_pat->table_id                    = buffer[0];
    ts_pat->section_syntax_indicator    = buffer[1] >> 7;
    ts_pat->zero                        = buffer[1] >> 6 & 0x1;
    ts_pat->reserved_1                  = buffer[1] >> 4 & 0x3;
    ts_pat->section_length              = (buffer[1] & 0x0F) << 8 | buffer[2];
    ts_pat->transport_stream_id         = buffer[3] << 8 | buffer[4];
    ts_pat->reserved_2                  = buffer[5] >> 6;
    ts_pat->version_number              = buffer[5] >> 1 &  0x1F;
    ts_pat->current_next_indicator      = buffer[5] & 0x1;
    ts_pat->section_number              = buffer[6];
    ts_pat->last_section_number         = buffer[7];
    int len = 0;
    len = 3 + ts_pat->section_length;
    ts_pat->CRC_32   = (buffer[len-4] & 0x000000FF) << 24
                       | (buffer[len-3] & 0x000000FF) << 16
                       | (buffer[len-2] & 0x000000FF) << 8
                       | (buffer[len-1] & 0x000000FF);

    int n = 0;
    TS_PAT_Program PAT_program;
    for ( n = 0; n < ts_pat->section_length - 12; n += 4 )
    {
        unsigned  program_num = buffer[8 + n ] << 8 | buffer[9 + n ];
        //ts_pat->reserved_3 = buffer[10 + n ] >> 5;
        //ts_pat->network_PID = 0x00;
        PAT_program.reserved_3 = buffer[10 + n ] >> 5;
        if ( program_num == 0x00)
        {
            //ts_pat->network_PID = (buffer[10 + n ] & 0x1F) << 8 | buffer[11 + n ];
            PAT_program.program_map_PID_network_PID =  (buffer[10 + n ] & 0x1F) << 8 | buffer[11 + n ];
            PAT_program.program_number = program_num;
            //TS_network_Pid = packet->network_PID; //记录该TS流的网络PID
            g_vTS_program.push_back( PAT_program );//向全局PAT节目数组中添加PAT节目信息
            printf(" TS stream PID %0x \n\n", PAT_program.program_map_PID_network_PID  );
        }
        else
        {
           PAT_program.program_map_PID_network_PID = (buffer[10 + n] & 0x1F) << 8 | buffer[11 + n];
           PAT_program.program_number = program_num;
           ts_pat->vProgram.push_back( PAT_program );
           g_vTS_program.push_back( PAT_program );//向全局PAT节目数组中添加PAT节目信息
           printf(" TS programe PID %0x \n\n", PAT_program.program_map_PID_network_PID  );
        }
    }
}
static void adjust_PMT_table ( TS_PMT * ts_pmt, unsigned char * buffer )
{
    ts_pmt->table_id                            = buffer[0];
    ts_pmt->section_syntax_indicator            = buffer[1] >> 7;
    ts_pmt->zero                                = buffer[1] >> 6 & 0x01;
    ts_pmt->reserved_1                            = buffer[1] >> 4 & 0x03;
    ts_pmt->section_length                        = (buffer[1] & 0x0F) << 8 | buffer[2];
    ts_pmt->program_number                        = buffer[3] << 8 | buffer[4];
    ts_pmt->reserved_2                            = buffer[5] >> 6;
    ts_pmt->version_number                        = buffer[5] >> 1 & 0x1F;
    ts_pmt->current_next_indicator                = (buffer[5] << 7) >> 7;
    ts_pmt->section_number                        = buffer[6];
    ts_pmt->last_section_number                    = buffer[7];
    ts_pmt->reserved_3                            = buffer[8] >> 5;
    ts_pmt->PCR_PID                                = ((buffer[8] << 8) | buffer[9]) & 0x1FFF;

 //PCRID = packet->PCR_PID;

    ts_pmt->reserved_4                            = buffer[10] >> 4;
    ts_pmt->program_info_length                    = (buffer[10] & 0x0F) << 8 | buffer[11];
    // Get CRC_32
    int len = 0;
    len = ts_pmt->section_length + 3;
    ts_pmt->CRC_32 = (buffer[len-4] & 0x000000FF) << 24
                     | (buffer[len-3] & 0x000000FF) << 16
                     | (buffer[len-2] & 0x000000FF) << 8
                     | (buffer[len-1] & 0x000000FF);

    int pos = 12;
    // program info descriptor
    if ( ts_pmt->program_info_length != 0 )
        pos += ts_pmt->program_info_length;
    // Get stream type and PID
    for ( ; pos <= (ts_pmt->section_length + 2 ) -  4; )
    {
        TS_PMT_Stream pmt_stream;
        pmt_stream.stream_type =  buffer[pos];
        ts_pmt->reserved_5  =   buffer[pos+1] >> 5;
        pmt_stream.elementary_PID =  ((buffer[pos+1] << 8) | buffer[pos+2]) & 0x1FFF;
        ts_pmt->reserved_6     =   buffer[pos+3] >> 4;
        pmt_stream.ES_info_length =   (buffer[pos+3] & 0x0F) << 8 | buffer[pos+4];
        pmt_stream.descriptor = 0x00;
        if (pmt_stream.ES_info_length != 0)
        {
            pmt_stream.descriptor = buffer[pos + 5];

            for( int len = 2; len <= pmt_stream.ES_info_length; len ++ )
            {
                pmt_stream.descriptor = pmt_stream.descriptor<< 8 | buffer[pos + 4 + len];
            }
            pos += pmt_stream.ES_info_length;
        }
        pos += 5;
        ts_pmt->vPMT_Stream.push_back( pmt_stream );
        //TS_Stream_type.push_back( pmt_stream );
    }
}
static bool bPESHead = false;
static uint64_t size = 0;
static uint64_t size_count = 0;
static uint8_t *data = nullptr;
static bool bFlag_ifGetPMT = false;
static bool getPESHead(unsigned char * buffer)
{
    if( buffer[0] == 0x00
        && buffer[1] == 0x00
        && buffer[2] == 0x01 )
    {
        return true;
    }
    else
    {
        return false;
    }
}
static AVPacket pkt;
static AVFrame *frame = av_frame_alloc();
static AVCodecContext* gDecodeCtx = nullptr;
static AVCodec *gCodec = nullptr;
static AVCodecParserContext *parser = nullptr;
static int openDecoder()
{
    /* find the MPEG-1 video decoder *///AV_CODEC_ID_MPEG2VIDEO
    gCodec = avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO);
    if (!gCodec)
    {
        fprintf(stderr, "Codec not found\n");
        exit(1);
    }
    // 获取裸流的解析器 AVCodecParserContext(数据)  +  AVCodecParser(方法)
    parser = av_parser_init(gCodec->id);
    if (!parser) {
        fprintf(stderr, "Parser not found\n");
        exit(1);
    }
    gDecodeCtx = avcodec_alloc_context3(gCodec);
    if (!gDecodeCtx)
    {
        fprintf(stderr, "Could not allocate video codec context\n");
        exit(1);
    }
    if (avcodec_open2(gDecodeCtx, gCodec, nullptr) < 0)
    {
        fprintf(stderr, "Could not open codec\n");
        exit(1);
    }
}
int ts2H264_C::decode()
{
    //printf_hex(pkt.data,a);
    int nRet = avcodec_send_packet(gDecodeCtx, &pkt);
    while( 0 == nRet)
    {
        int got_picture =avcodec_receive_frame(gDecodeCtx, frame);
        if(0 == got_picture)//
        {
            //写入数据
            int picSize = frame->height *frame->width;
            int newSize = picSize * 1.5;
            //申请内存
            unsigned char *buf = new unsigned char[newSize];
            int a=0,i;
            for (i=0; i<frame->height; i++)
            {
                memcpy(buf+a,frame->data[0] + i * frame->linesize[0], frame->width);
                a+=frame->width;
            }
            for (i=0; i<frame->height/2; i++)
            {
                memcpy(buf+a,frame->data[1] + i * frame->linesize[1], frame->width/2);
                a+=frame->width/2;
            }
            for (i=0; i<frame->height/2; i++)
            {
                memcpy(buf+a,frame->data[2] + i * frame->linesize[2], frame->width/2);
                a+=frame->width/2;
            }
            fwrite(buf, 1, newSize, out_yuv);
            fflush(out_yuv);
            nCountFrame++;
            printf("yuv frame %d \n",nCountFrame);
        }
        else
        {
            break;
        }
    }
    av_packet_unref(&pkt);
    return 0;
}
void ts2H264_C::insertVector(unsigned char *buff,int len)
{
    for(int i = 0; i < len; i++)
    {
       vOneFullPacket.push_back(buff[i]);
    }
}
static bool first_I_frame(unsigned char* buff,int len)
{
    for (int i = 0; i < len; i++)
    {
        if( buff[i] == 0x00
            && buff[i+1] == 0x00
            && buff[i+2] == 0x01
            && buff[i+3] == 0x00)
        {
            if(0x1 == (buff[i+5]&0x38)>>3)//I帧
            {
                return true;
            }
        }
    }
    return false;
}
int ts2H264_C::_start()
{
    int nRet = 0;
    unsigned char temp[1316];
    FILE *in = fopen("in.ts","rb");
    FILE *out = fopen("out.mpeg2","wb+");
    openDecoder();
    //如果未到文件结尾
    int ret = 0;
    uint8_t *data_pkt = nullptr;
    uint8_t last_pes_head_len = 0;
    while (!feof(in))
    {
        if(size_count >= 4096)
        {
            unsigned char OneFullPacket[size_count];
            memset(OneFullPacket,0,size_count);
            memcpy(OneFullPacket,&vOneFullPacket[0],size_count);
            data_pkt = OneFullPacket;
            while(size_count > 0 )
            {
                frame = av_frame_alloc();
                ret = av_parser_parse2(parser, gDecodeCtx, &pkt.data, &pkt.size,
                                       data_pkt, size_count,
                                       AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
                if (ret < 0)
                {
                    fprintf(stderr, "Error while parsing\n");
                    exit(1);
                }
                data_pkt += ret;   // 跳过已经解析的数据
                size_count -= ret;   // 对应的缓存大小也做相应减小
                vOneFullPacket.erase(vOneFullPacket.begin(),vOneFullPacket.begin()+ret);
                if (pkt.size)
                {
                    decode();
                }
            }
        }
        memset(temp,0,sizeof (temp));
        fread(temp, 1, 1316, in);
        TS_head ts_head;
        //每次读7个TS包
        int nTsPacket = 0;
        while( nTsPacket < 7)
        {
            get_ts_header(ts_head,(unsigned char*)&temp[nTsPacket*188]);
            if(ts_head.sync_byte != 0x47)
            {
                printf("同步字节错误 \n");
                return 1;
            }
            if(ts_head.PID == 0x0000)//PAT
            {
                gPAT.vProgram.clear();
                adjust_PAT_table(&gPAT,(unsigned char*)&temp[5+nTsPacket*188]);
                if(bFlag_ifGetPMT == true)
                {
                    gPMT.vPMT_Stream.clear();
                    bFlag_ifGetPMT = false;
                }
            }
            else
            {
                if( false == bFlag_ifGetPMT )
                {
                    auto iter = gPAT.vProgram.begin();
                    for ( ;iter != gPAT.vProgram.end(); iter++)
                    {
                        if(0x0001 == (*iter).program_number //PMT
                                && ts_head.PID == (*iter).program_map_PID_network_PID) //PID一致
                        {
                            adjust_PMT_table( &gPMT, &temp[5+nTsPacket*188]);
                            bFlag_ifGetPMT = true;
                        }
                    }
                }
                else
                {
                    auto iter = gPMT.vPMT_Stream.begin();
                    for ( ;iter != gPMT.vPMT_Stream.end(); iter++)
                    {
                        if((*iter).elementary_PID == ts_head.PID)
                        {
                            if(0x1 == ts_head.payload_unit_start_indicator)//PES包头
                            {
                                if( ts_head.adaptation_field_control == 2
                                        || ts_head.adaptation_field_control == 3)//自适应字段
                                {
                                    if(bPESHead == false)
                                    {
                                        bPESHead = getPESHead(&temp[ nTsPacket*188+4 + 1 + temp[4+nTsPacket*188]]);
                                    }
                                    if(bPESHead == true)
                                    {
                                        last_pes_head_len = (uint8_t)temp[nTsPacket*188 + 4 + 1 + (uint8_t)temp[4+nTsPacket*188] + 9+1];
                                        last_pes_head_len = last_pes_head_len & 0x0f;
                                        size = 188-4-1-temp[4+nTsPacket*188]-9-last_pes_head_len;
                                        data = (uint8_t *)&temp[nTsPacket*188 + 4 + 1 + temp[4+nTsPacket*188] + 9+last_pes_head_len];
                                        if(gif_I_Frame == true)
                                        {
                                            fwrite(data,1,size,out);
                                            fflush(out);
                                            size_count+=size;
                                            insertVector(data,size);
                                        }
                                        else
                                        {
                                            gif_I_Frame = first_I_frame(data,size);//I帧
                                            if(gif_I_Frame == true)
                                            {
                                                fwrite(data,1,size,out);
                                                fflush(out);
                                                size_count+=size;
                                                insertVector(data,size);
                                            }
                                        }

                                     }
                                }
                                else
                                {
                                    if(bPESHead == false)
                                    {
                                        bPESHead = getPESHead(&temp[ nTsPacket*188+4 + 1 + temp[4+nTsPacket*188]]);
                                    }
                                    if(bPESHead == true)
                                    {
                                        last_pes_head_len = (uint8_t)temp[nTsPacket*188 + 4 + 1 + 9+1];
                                        last_pes_head_len = last_pes_head_len & 0x0f;
                                        size = 188-4-1-9-last_pes_head_len;
                                        data = (uint8_t *)&temp[nTsPacket*188+4 + 1 + 9+last_pes_head_len];
                                        if(gif_I_Frame == true)
                                        {
                                            fwrite(data,1,size,out);
                                            fflush(out);
                                            size_count+=size;
                                            insertVector(data,size);
                                        }
                                        else
                                        {
                                            gif_I_Frame = first_I_frame(data,size);
                                            if(gif_I_Frame == true)
                                            {
                                                fwrite(data,1,size,out);
                                                fflush(out);
                                                size_count+=size;
                                                insertVector(data,size);
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                if( ts_head.adaptation_field_control == 2
                                        || ts_head.adaptation_field_control == 3)
                                {
                                    if(bPESHead == false)
                                    {
                                        bPESHead = getPESHead(&temp[nTsPacket*188+4]);
                                    }
                                    if(bPESHead == true)
                                    {
                                        size = 188-4-1-temp[4+nTsPacket*188];
                                        data = (uint8_t *)&temp[nTsPacket*188 + 4 + 1 + temp[4+nTsPacket*188]];
                                        if(gif_I_Frame == true)
                                        {
                                            fwrite(data,1,size,out);
                                            fflush(out);
                                            size_count+=size;
                                            insertVector(data,size);
                                        }
                                        else
                                        {
                                            gif_I_Frame = first_I_frame(data,size);
                                            if(gif_I_Frame == true)
                                            {
                                                fwrite(data,1,size,out);
                                                fflush(out);
                                                size_count+=size;
                                                insertVector(data,size);
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    if(bPESHead == false)
                                    {
                                        bPESHead = getPESHead(&temp[nTsPacket*188+4]);
                                    }
                                    if(bPESHead == true)
                                    {
                                        size = 188-4;
                                        data = (uint8_t *)&temp[nTsPacket*188+4];
                                        if(gif_I_Frame == true)
                                        {
                                            fwrite(data,1,size,out);
                                            fflush(out);
                                            size_count+=size;
                                            insertVector(data,size);
                                        }
                                        else
                                        {
                                            gif_I_Frame = first_I_frame(data,size);
                                            if(gif_I_Frame == true)
                                            {
                                                fwrite(data,1,size,out);
                                                fflush(out);
                                                size_count+=size;
                                                insertVector(data,size);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            nTsPacket++;
        }
    }
    /* 冲刷解码器 */
    pkt.data = NULL;   // 让其进入drain mode
    pkt.size = 0;
    decode();
    return nRet;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值