TSMaker.h 13.4 KB
Newer Older
xiongziliang committed
1
/*
xiongziliang committed
2
 * MIT License
xzl committed
3
 *
xiongziliang committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 * Copyright (c) 2016 xiongziliang <771730766@qq.com>
 *
 * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
xzl committed
25 26 27 28 29
 */

#ifndef TSMAKER_H_
#define TSMAKER_H_

30
#include "crc32.h"
xzl committed
31 32 33
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
xiongzilaing committed
34 35
#include <string>
#include <iostream>
xzl committed
36 37
#include "Util/File.h"
using namespace std;
xiongziliang committed
38
using namespace toolkit;
xzl committed
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267

#define TS_PACKET_SIZE                 188
#define TS_PACKET_HEADER               4
#define TS_SYNC_BYTE                   0x47
#define TS_PAT_PID                     0x00
#define TS_PMT_PID                     0xFFF
#define TS_H264_PID                    0x100
#define TS_AAC_PID                     0x101
#define TS_H264_STREAM_ID              0xE0
#define TS_AAC_STREAM_ID               0xC0
#define PMT_STREAM_TYPE_VIDEO          0x1B
#define PMT_STREAM_TYPE_AUDIO          0x0F

//#define ES_BUF_SIZE 256*1024

//ts 包头
typedef struct Tag_PacketHeader {
	unsigned char sync_byte :8;         //同步字节, 固定为0x47,表示后面的是一个TS分组
	unsigned char tras_error :1;        //传输误码指示符
	unsigned char play_init :1;         //有效荷载单元起始指示符
	unsigned char tras_prio :1;         //传输优先, 1表示高优先级,传输机制可能用到,解码用不着
	unsigned int PID :13;         		//PID
	unsigned char tras_scramb :2;       //传输加扰控制
	unsigned char ada_field_C :2; //自适应控制 01仅含有效负载,10仅含调整字段,11含有调整字段和有效负载,先调整字段然后有效负载。为00解码器不进行处理
	unsigned char conti_cter :4;        //连续计数器 一个4bit的计数器,范围0-15
} TsPacketHeader;

//连续性计数器,也就是说 有多少个 pat包,几个pmt包 ,几个MP3 包,几个 h264包,0x00 - 0x0f ,然后折回到0x00
typedef struct Tag_Continuity_Counter {
	unsigned char continuity_counter_pat;
	unsigned char continuity_counter_pmt;
	unsigned char continuity_counter_video;
	unsigned char continuity_counter_audio;
} Continuity_Counter;

//自适应段标志
typedef struct Tag_Ts_Adaptation_field {
	unsigned char discontinuty_indicator :1;       //1表明当前传送流分组的不连续状态为真
	unsigned char random_access_indicator :1; //表明下一个有相同PID的PES分组应该含有PTS字段和一个原始流访问点
	unsigned char elementary_stream_priority_indicator :1;  //优先级
	unsigned char PCR_flag :1;                              //包含pcr字段
	unsigned char OPCR_flag :1;                             //包含opcr字段
	unsigned char splicing_point_flag :1;                   //拼接点标志
	unsigned char transport_private_data_flag :1;           //私用字节
	unsigned char adaptation_field_extension_flag :1;       //调整字段有扩展

	unsigned char adaptation_field_length;                 //自适应段长度
	unsigned long long pcr;                               //自适应段中用到的的pcr
	unsigned long long opcr;                              //自适应段中用到的的opcr
	unsigned char splice_countdown;
	unsigned char private_data_len;
	unsigned char private_data[256];
} Ts_Adaptation_field;

//PAT结构体:节目相关表
typedef struct Tag_TsPat {
	unsigned char table_id :8;                  //固定为0x00 ,标志是该表是PAT
	unsigned char section_syntax_indicator :1;   //段语法标志位,固定为1
	unsigned char zero :1;                      //0
	unsigned char reserved_1 :2;                //保留位
	unsigned int section_length :12;           //表示这个字节后面有用的字节数,包括CRC32
	unsigned int transport_stream_id :16;      //该传输流的ID,区别于一个网络中其它多路复用的流
	unsigned char reserved_2 :2;                //保留位
	unsigned char version_number :5;           //范围0-31,表示PAT的版本号
	unsigned char current_next_indicator :1;   //发送的PAT是当前有效还是下一个PAT有效
	unsigned char section_number :8; //分段的号码。PAT可能分为多段传输,第一段为00,以后每个分段加1,最多可能有256个分段
	unsigned char last_section_number :8;      //最后一个分段的号码
	unsigned int program_number :16;          //节目号
	unsigned char reserved_3 :3;             //保留位
	//unsigned int network_PID :13 ;             //网络信息表(NIT)的PID,节目号为0时对应的PID为network_PID,本例中不含有 networke_pid
	unsigned int program_map_PID :13;         //节目映射表的PID,节目号大于0时对应的PID,每个节目对应一个
	unsigned long long CRC_32 :32;             //CRC32校验码
} TsPat;

//PMT结构体:节目映射表
typedef struct Tag_TsPmt {
	unsigned char table_id :8;                 //固定为0x02, 表示PMT表
	unsigned char section_syntax_indicator :1;  //固定为0x01
	unsigned char zero :1;                       //0x00
	unsigned char reserved_1 :2;                //0x03
	unsigned int section_length :12;     //首先两位bit置为00,它指示段的byte数,由段长度域开始,包含CRC。
	unsigned int program_number :16;            // 指出该节目对应于可应用的Program map PID
	unsigned char reserved_2 :2;                 //0x03
	unsigned char version_number :5;             //指出TS流中Program map section的版本号
	unsigned char current_next_indicator :1; //当该位置1时,当前传送的Program map section可用;当该位置0时,指示当前传送的Program map section不可用,下一个TS流的Program map section有效。
	unsigned char section_number :8;            //固定为0x00
	unsigned char last_section_number :8;        //固定为0x00
	unsigned char reserved_3 :3;                //0x07
	unsigned int PCR_PID :13; //指明TS包的PID值,该TS包含有PCR域,该PCR值对应于由节目号指定的对应节目。如果对于私有数据流的节目定义与PCR无关,这个域的值将为0x1FFF。
	unsigned char reserved_4 :4;                //预留为0x0F
	unsigned int program_info_length :12;    //前两位bit为00。该域指出跟随其后对节目信息的描述的byte数。
	unsigned char stream_type_video :8; //指示特定PID的节目元素包的类型。该处PID由elementary PID指定
	unsigned char reserved_5_video :3;           //0x07
	unsigned int elementary_PID_video :13;       //该域指示TS包的PID值。这些TS包含有相关的节目元素
	unsigned char reserved_6_video :4;          //0x0F
	unsigned int ES_info_length_video :12;   //前两位bit为00。该域指示跟随其后的描述相关节目元素的byte数
	unsigned char stream_type_audio :8; //指示特定PID的节目元素包的类型。该处PID由elementary PID指定
	unsigned char reserved_5_audio :3;           //0x07
	unsigned int elementary_PID_audio :13;       //该域指示TS包的PID值。这些TS包含有相关的节目元素
	unsigned char reserved_6_audio :4;          //0x0F
	unsigned int ES_info_length_audio :12;   //前两位bit为00。该域指示跟随其后的描述相关节目元素的byte数
	unsigned long long CRC_32 :32;                    //CRC32校验码
} TsPmt;

//PTS_DTS结构体:本程序设置都有 “11”
typedef struct Tag_TsPtsDts {
	unsigned char reserved_1 :4;
	unsigned char pts_32_30 :3;                //显示时间戳
	unsigned char marker_bit1 :1;
	unsigned int pts_29_15 :15;
	unsigned char marker_bit2 :1;
	unsigned int pts_14_0 :15;
	unsigned char marker_bit3 :1;
	unsigned char reserved_2 :4;
	unsigned char dts_32_30 :3;                  //解码时间戳
	unsigned char marker_bit4 :1;
	unsigned int dts_29_15 :15;
	unsigned char marker_bit5 :1;
	unsigned int dts_14_0 :15;
	unsigned char marker_bit6 :1;
} TsPtsDts;

//PES包结构体,包括PES包头和ES数据 ,头 19 个字节
typedef struct Tag_TsPes {
	unsigned int packet_start_code_prefix :24;                  //起始:0x000001
	unsigned char stream_id :8;                //基本流的类型和编号
	unsigned int PES_packet_length :16; //包长度,就是帧数据的长度,可能为0,要自己算,做多16位,如果超出则需要自己算
	unsigned char marker_bit :2;                 //必须是:'10'
	unsigned char PES_scrambling_control :2;     //pes包有效载荷的加扰方式
	unsigned char PES_priority :1;               //有效负载的优先级
	unsigned char data_alignment_indicator :1; //如果设置为1表明PES包的头后面紧跟着视频或音频syncword开始的代码。
	unsigned char copyright :1;                  //1:靠版权保护,0:不靠
	unsigned char original_or_copy :1;           //1;有效负载是原始的,0:有效负载时拷贝的
	unsigned char PTS_DTS_flags :2; //'10':PTS字段存在,‘11’:PTD和DTS都存在,‘00’:都没有,‘01’:禁用。
	unsigned char ESCR_flag :1;         //1:escr基准字段 和 escr扩展字段均存在,0:无任何escr字段存在
	unsigned char ES_rate_flag :1;               //1:es_rate字段存在,0 :不存在
	unsigned char DSM_trick_mode_flag :1;        //1;8比特特接方式字段存在,0 :不存在
	unsigned char additional_copy_info_flag :1; //1:additional_copy_info存在,0: 不存在
	unsigned char PES_CRC_flag :1;               //1:crc字段存在,0:不存在
	unsigned char PES_extension_flag :1;         //1:扩展字段存在,0:不存在
	unsigned char PES_header_data_length :8;    //后面数据的长度,
	//TsPtsDts tsptsdts;                     //ptsdts结构体对象,10个字节
	char *ES;
	unsigned long ESlen;
} TsPes;

/*//H264一帧数据的结构体
 typedef struct Tag_NALU_t {
 unsigned char forbidden_bit;           //! Should always be FALSE
 unsigned char nal_reference_idc;       //! NALU_PRIORITY_xxxx
 unsigned char nal_unit_type;           //! NALU_TYPE_xxxx
 unsigned int startcodeprefix_len;      //! 前缀字节数
 unsigned int len;            //! 包含nal 头的nal 长度,从第一个00000001到下一个000000001的长度
 unsigned int max_size;                 //! 做多一个nal 的长度
 unsigned char * buf;                   //! 包含nal 头的nal 数据
 unsigned int lost_packets;             //! 预留
 } NALU_t;*/

//nal类型
typedef enum {
	NALU_TYPE_SLICE = 1,
	NALU_TYPE_DPA = 2,
	NALU_TYPE_DPB = 3,
	NALU_TYPE_DPC = 4,
	NALU_TYPE_IDR = 5,
	NALU_TYPE_SEI = 6,
	NALU_TYPE_SPS = 7,
	NALU_TYPE_PPS = 8,
	NALU_TYPE_AUD = 9,
	NALU_TYPE_EOSEQ = 10,
	NALU_TYPE_EOSTREAM = 11,
	NALU_TYPE_FILL = 12,
#if (MVC_EXTENSION_ENABLE)
NALU_TYPE_PREFIX = 14,
NALU_TYPE_SUB_SPS = 15,
NALU_TYPE_SLC_EXT = 20,
NALU_TYPE_VDRD = 24  // View and Dependency Representation Delimiter NAL Unit
#endif
} NaluType;

/*//MP3头结构体
 typedef struct Tag_Mp3_Header {
 unsigned int sync :11;                  //同步信息
 unsigned char version :2;                //版本
 unsigned char layer :2;                  //层
 unsigned char error_protection :1;        //CRC校验
 unsigned char bitrate_index :4;          //位率
 unsigned char sampling_frequency :2;     //采样频率
 unsigned char padding :1;                //帧长调节
 unsigned char private_t :1;              //保留字
 unsigned char mode :2;                   //声道模式
 unsigned char mode_extension :2;         //扩展模式
 unsigned char copyright :1;              //版权
 unsigned char original :1;               //原版标志
 unsigned char emphasis :2;               //强调模式
 } Mp3_Header;*/


class TSMaker {
public:
	TSMaker();
	virtual ~TSMaker();
	bool init(const string &strFilename, uint32_t ui32BufSize);
	int inputH264(const char *pcData, uint32_t ui32Len, uint64_t ui64Time);
	int inputAAC(const char *pcData, uint32_t ui32Len, uint64_t ui64Time);
	void clear();
private:
	string m_strFilename;
	FILE *m_pOutVideoTs;
	Continuity_Counter m_continuityCounter;
	TsPes *m_pVideo_pes;
	TsPes *m_pAudio_pes;
	unsigned int m_uiWritePacketNum;
	char *m_pcFileBuf;

	void flush();
	void CreateTsHeader(TsPacketHeader * pTsHeader, unsigned int uiPID, unsigned char ucPlayInit, unsigned char ucAdaFieldC);
	void TsHeader2buffer(TsPacketHeader * pTsHeader, unsigned char *pucBuffer);
	void CreatePAT();
	void CreatePMT();

	void WriteAdaptive_flags_Head(Ts_Adaptation_field * pAdaptationField, uint64_t ui64VideoPts);
	void WriteAdaptive_flags_Tail(Ts_Adaptation_field * pAdaptationField); //填写自适应段标志帧尾的

	void PES2TS(TsPes * pPes, unsigned int uiPID, Ts_Adaptation_field * pAdaptationField, uint64_t ui64Pts);
	void CreateAdaptive_Ts(Ts_Adaptation_field * pAdaptationField, unsigned char * pcTs, unsigned int uiAdaptiveLength);
};

#endif /* TSMAKER_H_ */