本博客的目的是手写一个程序DEMO,它的作用是将一段TS封装格式的视频解析为一段包含H264编码的ES视频流。
一,DEMO前期准备。
1.1 知识准备。TS全称transport stream,是基于MPEG-2的封装格式(所以也叫MPEG-TS),通常后缀为.ts,.mpg,.mpeg。TS封装格式如今广泛应用于数字电视,在即时通讯传输业务上大方光彩。具体相关的知识讲解可以看我的另一篇博客:https://blog.youkuaiyun.com/qq_41786131/article/details/90405715。有必要了解PAT,PMT,TS层,PES层的各个重要的句法都代表什么含义。
1.2 工具准备。TS封装格式解析工具,我推荐EasyICE,具体工具和相关ts视频素材我上传了,如果想要更多素材也可以私我哦:https://download.youkuaiyun.com/download/qq_41786131/11191889
二,代码编写。
要解析es视频流,我们必须知道这个视频流的PID,视频流的PID只存在于PMT表中,PMT表也存在自己的PID,它的PID由PAT表指出。可以看出,PAT表是我们分析ts视频的起始,不论干什么都要先找到它。而PAT表的PID值是固定的0x00,所以我们只需要遍历到它就可以开始我们的分析啦。
具体代码结构如下:
pat.class存储了pat表的句法信息,同理pes.class,pmt.class,tsheader.class都存储着各自的句法信息。我们知道PMT表的最后包含着一个节目信息的循环体,PMT最后是一个数据流类型的循环体,我在这里把它俩放到section.class里。调整字段我们暂时用不上,就不做分析(这些类中好多数据都用不上)。我们在analysis.class分析处理ts视频,主要分为三步,第一步获取包长和有效包起始位置,第二部获取ts文件的视频流PID和音频流PID,第三部读取ts文件,将pes,es数据分别存储到demo.pes,demo.es中。大致的流程图如下:
关于PAT,PMT,PES,TSHEADER的句法解析就不列出来了,具体网上很多,也可以参考我在博客尾部留下的完整工程。section字段的代码如下:
class PROGRAM_INFO{
public:
PROGRAM_INFO(char* data);
~PROGRAM_INFO();
public:
unsigned int program_number; //16b
// unsigned int reserved; //3b
unsigned int PMT_PID; //13b
};
class STREAM_TYPE{
public:
STREAM_TYPE(char* data);
~STREAM_TYPE();
public:
unsigned int stream_type; //8b
// unsigned int reserved1; //3b
unsigned int elementry_PID; //13b
// unsigned int reserved2; //4b
unsigned int ES_info_length; //12b
};
可以看出PROGRAM_INFO结构是为了适配PAT最后的节目信息映射表(PMT),STREAM_TYPE结构是为了适配每一个PMT表的流信息(一般为视音频流),这里就不再多说了。
然后就是analysis.class的结构,它主要有三个功能(获取包长,读取PID信息,存储es文件)。它的整体结构如下:
class ANALYSIS{
public:
ANALYSIS(char* file);
~ANALYSIS();
//判断TS包长是否是188字节
unsigned int get_packet_length(FILE* fp);
//获取节目信息到map里面
bool get_infos();
//获取pes文件,es文件
void g