//
// Copyright (c) 2013-2025 The SRS Authors
//
// SPDX-License-Identifier: MIT
//

#ifndef SRS_KERNEL_TS_HPP
#define SRS_KERNEL_TS_HPP

#include <srs_core.hpp>

#include <string>
#include <map>
#include <vector>

#include <srs_kernel_codec.hpp>
#include <srs_kernel_file.hpp>

class SrsBuffer;
class SrsTsMessageCache;
class SrsTsContextWriter;
class ISrsStreamWriter;
class SrsFileReader;
class SrsFormat;
class SrsSimpleStream;
class SrsTsAdaptationField;
class SrsTsPayload;
class SrsTsMessage;
class SrsTsPacket;
class SrsTsContext;
class SrsPsPacket;

// Transport Stream packets are 188 bytes in length.
#define SRS_TS_PACKET_SIZE          188

// The aggregate pure audio for hls, in ts tbn(ms * 90).
#define SRS_CONSTS_HLS_PURE_AUDIO_AGGREGATE 720 * 90

// The pid of ts packet,
// Table 2-3 - PID table, hls-mpeg-ts-iso13818-1.pdf, page 37
// NOTE - The transport packets with PID values 0x0000, 0x0001, and 0x0010-0x1FFE are allowed to carry a PCR.
enum SrsTsPid
{
    // Program Association Table(see Table 2-25).
    SrsTsPidPAT = 0x00,
    // Conditional Access Table (see Table 2-27).
    SrsTsPidCAT = 0x01,
    // Transport Stream Description Table
    SrsTsPidTSDT = 0x02,
    // Reserved
    SrsTsPidReservedStart = 0x03,
    SrsTsPidReservedEnd = 0x0f,
    // May be assigned as network_PID, Program_map_PID, elementary_PID, or for other purposes
    SrsTsPidAppStart = 0x10,
    SrsTsPidAppEnd = 0x1ffe,
    // For null packets (see Table 2-3)
    SrsTsPidNULL = 0x01FFF,
};

// The transport_scrambling_control of ts packet,
// Table 2-4 - Scrambling control values, hls-mpeg-ts-iso13818-1.pdf, page 38
enum SrsTsScrambled
{
    // Not scrambled
    SrsTsScrambledDisabled = 0x00,
    // User-defined
    SrsTsScrambledUserDefined1 = 0x01,
    // User-defined
    SrsTsScrambledUserDefined2 = 0x02,
    // User-defined
    SrsTsScrambledUserDefined3 = 0x03,
};

// the adaption_field_control of ts packet,
// Table 2-5 - Adaptation field control values, hls-mpeg-ts-iso13818-1.pdf, page 38
enum SrsTsAdaptationFieldType
{
    // Reserved for future use by ISO/IEC
    SrsTsAdaptationFieldTypeReserved = 0x00,
    // No adaptation_field, payload only
    SrsTsAdaptationFieldTypePayloadOnly = 0x01,
    // Adaptation_field only, no payload
    SrsTsAdaptationFieldTypeAdaptionOnly = 0x02,
    // Adaptation_field followed by payload
    SrsTsAdaptationFieldTypeBoth = 0x03,
};

// the actually parsed ts pid,
// @see SrsTsPid, some pid, for example, PMT/Video/Audio is specified by PAT or other tables.
enum SrsTsPidApply
{
    SrsTsPidApplyReserved = 0, // TSPidTypeReserved, nothing parsed, used reserved.
    
    SrsTsPidApplyPAT, // Program associtate table for TS.
    SrsTsPidApplyPMT, // Program map table for TS.
    
    SrsTsPidApplyVideo, // for video
    SrsTsPidApplyAudio, // vor audio
};

// Table 2-29 - Stream type assignments, hls-mpeg-ts-iso13818-1.pdf, page 66
enum SrsTsStream
{
    // ITU-T | ISO/IEC Reserved
    SrsTsStreamReserved = 0x00,
    SrsTsStreamForbidden = 0xff,
    // ISO/IEC 11172 Video
    // ITU-T Rec. H.262 | ISO/IEC 13818-2 Video or ISO/IEC 11172-2 constrained parameter video stream
    // ISO/IEC 11172 Audio
    SrsTsStreamAudioMp3 = 0x03,
    // ISO/IEC 13818-3 Audio
    // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 private_sections
    // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 PES packets containing private data
    // ISO/IEC 13522 MHEG
    // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A DSM-CC
    // ITU-T Rec. H.222.1
    // ISO/IEC 13818-6 type A
    // ISO/IEC 13818-6 type B
    // ISO/IEC 13818-6 type C
    // ISO/IEC 13818-6 type D
    // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 auxiliary
    // ISO/IEC 13818-7 Audio with ADTS transport syntax
    SrsTsStreamAudioAAC = 0x0f,
    // ISO/IEC 14496-2 Visual
    SrsTsStreamVideoMpeg4 = 0x10,
    // ISO/IEC 14496-3 Audio with the LATM transport syntax as defined in ISO/IEC 14496-3 / AMD 1
    SrsTsStreamAudioMpeg4 = 0x11,
    // ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in PES packets
    // ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in ISO/IEC14496_sections.
    // ISO/IEC 13818-6 Synchronized Download Protocol
    // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Reserved
    // 0x15-0x7F
    SrsTsStreamVideoH264 = 0x1b,
    // For HEVC(H.265).
    SrsTsStreamVideoHEVC = 0x24,
    // User Private
    // 0x80-0xFF
    SrsTsStreamAudioAC3 = 0x81,
    SrsTsStreamAudioDTS = 0x8a,
};
std::string srs_ts_stream2string(SrsTsStream stream);

// The ts channel.
struct SrsTsChannel
{
    int pid;
    SrsTsPidApply apply;
    SrsTsStream stream;
    SrsTsMessage* msg;
    SrsTsContext* context;
    // for encoder.
    uint8_t continuity_counter;
    
    SrsTsChannel();
    virtual ~SrsTsChannel();
};

// The stream_id of PES payload of ts packet.
// Table 2-18 - Stream_id assignments, hls-mpeg-ts-iso13818-1.pdf, page 52.
enum SrsTsPESStreamId
{
    // program_stream_map
    SrsTsPESStreamIdProgramStreamMap = 0xbc, // 0b10111100
    // private_stream_1
    SrsTsPESStreamIdPrivateStream1 = 0xbd, // 0b10111101
    // padding_stream
    SrsTsPESStreamIdPaddingStream = 0xbe, // 0b10111110
    // private_stream_2
    SrsTsPESStreamIdPrivateStream2 = 0xbf, // 0b10111111
    
    // 110x xxxx
    // ISO/IEC 13818-3 or ISO/IEC 11172-3 or ISO/IEC 13818-7 or ISO/IEC
    // 14496-3 audio stream number x xxxx
    // ((sid >> 5) & 0x07) == SrsTsPESStreamIdAudio
    // @remark, use SrsTsPESStreamIdAudioCommon as actually audio, SrsTsPESStreamIdAudio to check whether audio.
    SrsTsPESStreamIdAudioChecker = 0x06, // 0b110
    SrsTsPESStreamIdAudioCommon = 0xc0,
    
    // 1110 xxxx
    // ITU-T Rec. H.262 | ISO/IEC 13818-2 or ISO/IEC 11172-2 or ISO/IEC
    // 14496-2 video stream number xxxx
    // ((stream_id >> 4) & 0x0f) == SrsTsPESStreamIdVideo
    // @remark, use SrsTsPESStreamIdVideoCommon as actually video, SrsTsPESStreamIdVideo to check whether video.
    SrsTsPESStreamIdVideoChecker = 0x0e, // 0b1110
    SrsTsPESStreamIdVideoCommon = 0xe0,
    
    // ECM_stream
    SrsTsPESStreamIdEcmStream = 0xf0, // 0b11110000
    // EMM_stream
    SrsTsPESStreamIdEmmStream = 0xf1, // 0b11110001
    // DSMCC_stream
    SrsTsPESStreamIdDsmccStream = 0xf2, // 0b11110010
    // 13522_stream
    SrsTsPESStreamId13522Stream = 0xf3, // 0b11110011
    // H_222_1_type_A
    SrsTsPESStreamIdH2221TypeA = 0xf4, // 0b11110100
    // H_222_1_type_B
    SrsTsPESStreamIdH2221TypeB = 0xf5, // 0b11110101
    // H_222_1_type_C
    SrsTsPESStreamIdH2221TypeC = 0xf6, // 0b11110110
    // H_222_1_type_D
    SrsTsPESStreamIdH2221TypeD = 0xf7, // 0b11110111
    // H_222_1_type_E
    SrsTsPESStreamIdH2221TypeE = 0xf8, // 0b11111000
    // ancillary_stream
    SrsTsPESStreamIdAncillaryStream = 0xf9, // 0b11111001
    // SL_packetized_stream
    SrsTsPESStreamIdSlPacketizedStream = 0xfa, // 0b11111010
    // FlexMux_stream
    SrsTsPESStreamIdFlexMuxStream = 0xfb, // 0b11111011
    // reserved data stream
    // 1111 1100 ... 1111 1110
    // program_stream_directory
    SrsTsPESStreamIdProgramStreamDirectory = 0xff, // 0b11111111
};

// The media audio/video message parsed from PES packet.
class SrsTsMessage
{
public:
    // For decoder only, the ts message does not use them, for user to get the channel and packet.
    SrsTsChannel* channel;
    SrsTsPacket* packet;
    // For decoder only, the ts message does not use them, to get the RTP packet source.
    void* ps_helper_;
public:
    // The audio cache buffer start pts, to flush audio if full.
    // @remark the pts is not the adjust one, it's the orignal pts.
    int64_t start_pts;
    // Whether this message with pcr info,
    // generally, the video IDR(I frame, the keyframe of h.264) carray the pcr info.
    bool write_pcr;
    // Whether got discontinuity ts, for example, sequence header changed.
    bool is_discontinuity;
public:
    // The chunk id of TS packet.
    uint8_t continuity_counter;
public:
    // The timestamp in 90khz
    int64_t dts;
    int64_t pts;
    // The id of pes stream to indicates the payload codec.
    // @remark use is_audio() and is_video() to check it, and stream_number() to finger it out.
    SrsTsPESStreamId sid;
    // The size of payload, 0 indicates the length() of payload.
    uint16_t PES_packet_length;
    // The payload bytes.
    SrsSimpleStream* payload;
public:
    SrsTsMessage(SrsTsChannel* c = NULL, SrsTsPacket* p = NULL);
    virtual ~SrsTsMessage();
// For decoder
public:
    // To dumps all bytes in stream to ts message.
	virtual srs_error_t dump(SrsBuffer* stream, int* pnb_bytes);
    // Whether ts message is completed to reap.
    // @param payload_unit_start_indicator whether new ts message start.
    //       PES_packet_length is 0, the payload_unit_start_indicator=1 to reap ts message.
    //       PES_packet_length > 0, the payload.length() == PES_packet_length to reap ts message.
    // @remark when PES_packet_length>0, the payload_unit_start_indicator should never be 1 when not completed.
    // @remark when fresh, the payload_unit_start_indicator should be 1.
    virtual bool completed(int8_t payload_unit_start_indicator);
    // Whether the message is fresh.
    virtual bool fresh();
public:
    // Whether the sid indicates the elementary stream audio.
    virtual bool is_audio();
    // Whether the sid indicates the elementary stream video.
    virtual bool is_video();
    // When audio or video, get the stream number which specifies the format of stream.
    // @return the stream number for audio/video; otherwise, -1.
    virtual int stream_number();
public:
    // Detach the ts message,
    // for user maybe need to parse the message by queue.
    // @remark we always use the payload of original message.
    virtual SrsTsMessage* detach();
};

// The ts message handler.
class ISrsTsHandler
{
public:
    ISrsTsHandler();
    virtual ~ISrsTsHandler();
public:
    // When ts context got message, use handler to process it.
    // @param msg the ts msg, user should never free it.
    // @return an int error code.
    virtual srs_error_t on_ts_message(SrsTsMessage* msg) = 0;
};

// The context of ts, to decode the ts stream.
class SrsTsContext
{
private:
    // Whether context is ready, failed if try to write data when not ready.
    // When PAT and PMT writen, the context is ready.
    // @see https://github.com/ossrs/srs/issues/834
    bool ready;
private:
    std::map<int, SrsTsChannel*> pids;
    bool pure_audio;
    int8_t sync_byte;
private:
    // when any codec changed, write the PAT/PMT.
    SrsVideoCodecId vcodec;
    SrsAudioCodecId acodec;
public:
    SrsTsContext();
    virtual ~SrsTsContext();
public:
    // Whether the hls stream is pure audio stream.
    // TODO: FIXME: merge with muxer codec detect.
    virtual bool is_pure_audio();
    // When PMT table parsed, we know some info about stream.
    virtual void on_pmt_parsed();
    // Reset the context for a new ts segment start.
    virtual void reset();
public:
    // Get the pid apply, the parsed pid.
    // @return the apply channel; NULL for invalid.
    virtual SrsTsChannel* get(int pid);
    // Set the pid apply, the parsed pid.
    virtual void set(int pid, SrsTsPidApply apply_pid, SrsTsStream stream = SrsTsStreamReserved);
public:
    // Feed with ts packets, decode as ts message, callback handler if got one ts message.
    //      A ts video message can be decoded to NALUs by SrsRawH264Stream::annexb_demux.
    //      A ts audio message can be decoded to RAW frame by SrsRawAacStream::adts_demux.
    // @param handler The ts message handler to process the msg.
    // @remark We will consume all bytes in stream.
    virtual srs_error_t decode(SrsBuffer* stream, ISrsTsHandler* handler);
public:
    // Encode ts video/audio messages to the PES packets, as PES stream.
    // @param msg The video/audio msg to write to ts.
    //      A ts video message is a frame with one or more NALUs, generally encoded by SrsTsMessageCache.cache_video.
    //      A ts audio message is an audio packet, encoded by SrsTsMessageCache.cache_audio to ADTS for AAC.
    // @param vc The video codec, write the PAT/PMT table when changed.
    // @param ac The audio codec, write the PAT/PMT table when changed.
    virtual srs_error_t encode(ISrsStreamWriter* writer, SrsTsMessage* msg, SrsVideoCodecId vc, SrsAudioCodecId ac);
private:
    virtual srs_error_t encode_pat_pmt(ISrsStreamWriter* writer, int16_t vpid, SrsTsStream vs, int16_t apid, SrsTsStream as);
    virtual srs_error_t encode_pes(ISrsStreamWriter* writer, SrsTsMessage* msg, int16_t pid, SrsTsStream sid, bool pure_audio);
};

// The packet in ts stream,
// 2.4.3.2 Transport Stream packet layer, hls-mpeg-ts-iso13818-1.pdf, page 36
// Transport Stream packets shall be 188 bytes long.
class SrsTsPacket
{
public:
    // 1B
    // The sync_byte is a fixed 8-bit field whose value is '0100 0111' (0x47). Sync_byte emulation in the choice of
    // values for other regularly occurring fields, such as PID, should be avoided.
    int8_t sync_byte; //8bits
    
    // 2B
    // The transport_error_indicator is a 1-bit flag. When set to '1' it indicates that at least
    // 1 uncorrectable bit error exists in the associated Transport Stream packet. This bit may be set to '1' by entities external to
    // the transport layer. When set to '1' this bit shall not be reset to '0' unless the bit value(s) in error have been corrected.
    int8_t transport_error_indicator; //1bit
    // The payload_unit_start_indicator is a 1-bit flag which has normative meaning for
    // Transport Stream packets that carry PES packets (refer to 2.4.3.6) or PSI data (refer to 2.4.4).
    //
    // When the payload of the Transport Stream packet contains PES packet data, the payload_unit_start_indicator has the
    // following significance: a '1' indicates that the payload of this Transport Stream packet will commence(start) with the first byte
    // of a PES packet and a '0' indicates no PES packet shall start in this Transport Stream packet. If the
    // payload_unit_start_indicator is set to '1', then one and only one PES packet starts in this Transport Stream packet. This
    // also applies to private streams of stream_type 6 (refer to Table 2-29).
    //
    // When the payload of the Transport Stream packet contains PSI data, the payload_unit_start_indicator has the following
    // significance: if the Transport Stream packet carries the first byte of a PSI section, the payload_unit_start_indicator value
    // shall be '1', indicating that the first byte of the payload of this Transport Stream packet carries the pointer_field. If the
    // Transport Stream packet does not carry the first byte of a PSI section, the payload_unit_start_indicator value shall be '0',
    // indicating that there is no pointer_field in the payload. Refer to 2.4.4.1 and 2.4.4.2. This also applies to private streams of
    // stream_type 5 (refer to Table 2-29).
    //
    // For null packets the payload_unit_start_indicator shall be set to '0'.
    //
    // The meaning of this bit for Transport Stream packets carrying only private data is not defined in this Specification.
    int8_t payload_unit_start_indicator; //1bit
    // The transport_priority is a 1-bit indicator. When set to '1' it indicates that the associated packet is
    // of greater priority than other packets having the same PID which do not have the bit set to '1'. The transport mechanism
    // can use this to prioritize its data within an elementary stream. Depending on the application the transport_priority field
    // may be coded regardless of the PID or within one PID only. This field may be changed by channel specific encoders or
    // decoders.
    int8_t transport_priority; //1bit
    // The PID is a 13-bit field, indicating the type of the data stored in the packet payload. PID value 0x0000 is
    // reserved for the Program Association Table (see Table 2-25). PID value 0x0001 is reserved for the Conditional Access
    // Table (see Table 2-27). PID values 0x0002 - 0x000F are reserved. PID value 0x1FFF is reserved for null packets (see
    // Table 2-3).
    SrsTsPid pid; //13bits
    
    // 1B
    // This 2-bit field indicates the scrambling mode of the Transport Stream packet payload.
    // The Transport Stream packet header, and the adaptation field when present, shall not be scrambled. In the case of a null
    // packet the value of the transport_scrambling_control field shall be set to '00' (see Table 2-4).
    SrsTsScrambled transport_scrambling_control; //2bits
    // This 2-bit field indicates whether this Transport Stream packet header is followed by an
    // adaptation field and/or payload (see Table 2-5).
    //
    // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 decoders shall discard Transport Stream packets with the
    // adaptation_field_control field set to a value of '00'. In the case of a null packet the value of the adaptation_field_control
    // shall be set to '01'.
    SrsTsAdaptationFieldType adaption_field_control; //2bits
	// The continuity_counter is a 4-bit field incrementing with each Transport Stream packet with the
	// same PID. The continuity_counter wraps around to 0 after its maximum value. The continuity_counter shall not be
	// incremented when the adaptation_field_control of the packet equals '00'(reseverd) or '10'(adaptation field only).
	//
	// In Transport Streams, duplicate packets may be sent as two, and only two, consecutive Transport Stream packets of the
	// same PID. The duplicate packets shall have the same continuity_counter value as the original packet and the
	// adaptation_field_control field shall be equal to '01'(payload only) or '11'(both). In duplicate packets each byte of the original packet shall be
	// duplicated, with the exception that in the program clock reference fields, if present, a valid value shall be encoded.
	//
	// The continuity_counter in a particular Transport Stream packet is continuous when it differs by a positive value of one
	// from the continuity_counter value in the previous Transport Stream packet of the same PID, or when either of the nonincrementing
	// conditions (adaptation_field_control set to '00' or '10', or duplicate packets as described above) are met.
	// The continuity counter may be discontinuous when the discontinuity_indicator is set to '1' (refer to 2.4.3.4). In the case of
	// a null packet the value of the continuity_counter is undefined.
    uint8_t continuity_counter; //4bits
private:
    SrsTsAdaptationField* adaptation_field;
    SrsTsPayload* payload;
public:
    SrsTsContext* context;
public:
    SrsTsPacket(SrsTsContext* c);
    virtual ~SrsTsPacket();
public:
    virtual srs_error_t decode(SrsBuffer* stream, SrsTsMessage** ppmsg);
public:
    virtual int size();
    virtual srs_error_t encode(SrsBuffer* stream);
    virtual void padding(int nb_stuffings);
public:
    static SrsTsPacket* create_pat(SrsTsContext* context, int16_t pmt_number, int16_t pmt_pid);
    static SrsTsPacket* create_pmt(SrsTsContext* context, int16_t pmt_number, int16_t pmt_pid,
    int16_t vpid, SrsTsStream vs, int16_t apid, SrsTsStream as);
    static SrsTsPacket* create_pes_first(SrsTsContext* context, int16_t pid, SrsTsPESStreamId sid,
    uint8_t continuity_counter, bool discontinuity, int64_t pcr, int64_t dts, int64_t pts, int size);
    static SrsTsPacket* create_pes_continue(SrsTsContext* context,
    int16_t pid, SrsTsPESStreamId sid, uint8_t continuity_counter);
};

// The adaption field of ts packet.
// 2.4.3.5 Semantic definition of fields in adaptation field, hls-mpeg-ts-iso13818-1.pdf, page 39
// Table 2-6 - Transport Stream adaptation field, hls-mpeg-ts-iso13818-1.pdf, page 40
class SrsTsAdaptationField
{
public:
    // 1B
    // The adaptation_field_length is an 8-bit field specifying the number of bytes in the
    // adaptation_field immediately following the adaptation_field_length. The value 0 is for inserting a single stuffing byte in
    // a Transport Stream packet. When the adaptation_field_control value is '11', the value of the adaptation_field_length shall
    // be in the range 0 to 182. When the adaptation_field_control value is '10', the value of the adaptation_field_length shall
    // be 183. For Transport Stream packets carrying PES packets, stuffing is needed when there is insufficient PES packet data
    // to completely fill the Transport Stream packet payload bytes. Stuffing is accomplished by defining an adaptation field
    // longer than the sum of the lengths of the data elements in it, so that the payload bytes remaining after the adaptation field
    // exactly accommodates the available PES packet data. The extra space in the adaptation field is filled with stuffing bytes.
    //
    // This is the only method of stuffing allowed for Transport Stream packets carrying PES packets. For Transport Stream
    // packets carrying PSI, an alternative stuffing method is described in 2.4.4.
    uint8_t adaption_field_length; //8bits
    // 1B
    // This is a 1-bit field which when set to '1' indicates that the discontinuity state is true for the
    // current Transport Stream packet. When the discontinuity_indicator is set to '0' or is not present, the discontinuity state is
    // false. The discontinuity indicator is used to indicate two types of discontinuities, system time-base discontinuities and
    // continuity_counter discontinuities.
    //
    // A system time-base discontinuity is indicated by the use of the discontinuity_indicator in Transport Stream packets of a
    // PID designated as a PCR_PID (refer to 2.4.4.9). When the discontinuity state is true for a Transport Stream packet of a
    // PID designated as a PCR_PID, the next PCR in a Transport Stream packet with that same PID represents a sample of a
    // new system time clock for the associated program. The system time-base discontinuity point is defined to be the instant
    // in time when the first byte of a packet containing a PCR of a new system time-base arrives at the input of the T-STD.
    // The discontinuity_indicator shall be set to '1' in the packet in which the system time-base discontinuity occurs. The
    // discontinuity_indicator bit may also be set to '1' in Transport Stream packets of the same PCR_PID prior to the packet
    // which contains the new system time-base PCR. In this case, once the discontinuity_indicator has been set to '1', it shall
    // continue to be set to '1' in all Transport Stream packets of the same PCR_PID up to and including the Transport Stream
    // packet which contains the first PCR of the new system time-base. After the occurrence of a system time-base
    // discontinuity, no fewer than two PCRs for the new system time-base shall be received before another system time-base
    // discontinuity can occur. Further, except when trick mode status is true, data from no more than two system time-bases
    // shall be present in the set of T-STD buffers for one program at any time.
    //
    // Prior to the occurrence of a system time-base discontinuity, the first byte of a Transport Stream packet which contains a
    // PTS or DTS which refers to the new system time-base shall not arrive at the input of the T-STD. After the occurrence of
    // a system time-base discontinuity, the first byte of a Transport Stream packet which contains a PTS or DTS which refers
    // to the previous system time-base shall not arrive at the input of the T-STD.
    //
    // A continuity_counter discontinuity is indicated by the use of the discontinuity_indicator in any Transport Stream packet.
    // When the discontinuity state is true in any Transport Stream packet of a PID not designated as a PCR_PID, the
    // continuity_counter in that packet may be discontinuous with respect to the previous Transport Stream packet of the same
    // PID. When the discontinuity state is true in a Transport Stream packet of a PID that is designated as a PCR_PID, the
    // continuity_counter may only be discontinuous in the packet in which a system time-base discontinuity occurs. A
    // continuity counter discontinuity point occurs when the discontinuity state is true in a Transport Stream packet and the
    // continuity_counter in the same packet is discontinuous with respect to the previous Transport Stream packet of the same
    // PID. A continuity counter discontinuity point shall occur at most one time from the initiation of the discontinuity state
    // until the conclusion of the discontinuity state. Furthermore, for all PIDs that are not designated as PCR_PIDs, when the
    // discontinuity_indicator is set to '1' in a packet of a specific PID, the discontinuity_indicator may be set to '1' in the next
    // Transport Stream packet of that same PID, but shall not be set to '1' in three consecutive Transport Stream packet of that
    // same PID.
    //
    // For the purpose of this clause, an elementary stream access point is defined as follows:
    //       Video - The first byte of a video sequence header.
    //       Audio - The first byte of an audio frame.
    //
    // After a continuity counter discontinuity in a Transport packet which is designated as containing elementary stream data,
    // the first byte of elementary stream data in a Transport Stream packet of the same PID shall be the first byte of an
    // elementary stream access point or in the case of video, the first byte of an elementary stream access point or a
    // sequence_end_code followed by an access point. Each Transport Stream packet which contains elementary stream data
    // with a PID not designated as a PCR_PID, and in which a continuity counter discontinuity point occurs, and in which a
    // PTS or DTS occurs, shall arrive at the input of the T-STD after the system time-base discontinuity for the associated
    // program occurs. In the case where the discontinuity state is true, if two consecutive Transport Stream packets of the same
    // PID occur which have the same continuity_counter value and have adaptation_field_control values set to '01' or '11', the
    // second packet may be discarded. A Transport Stream shall not be constructed in such a way that discarding such a packet
    // will cause the loss of PES packet payload data or PSI data.
    //
    // After the occurrence of a discontinuity_indicator set to '1' in a Transport Stream packet which contains PSI information,
    // a single discontinuity in the version_number of PSI sections may occur. At the occurrence of such a discontinuity, a
    // version of the TS_program_map_sections of the appropriate program shall be sent with section_length = = 13 and the
    // current_next_indicator = = 1, such that there are no program_descriptors and no elementary streams described. This shall
    // then be followed by a version of the TS_program_map_section for each affected program with the version_number
    // incremented by one and the current_next_indicator = = 1, containing a complete program definition. This indicates a
    // version change in PSI data.
    int8_t discontinuity_indicator; //1bit
    // The random_access_indicator is a 1-bit field that indicates that the current Transport
    // Stream packet, and possibly subsequent Transport Stream packets with the same PID, contain some information to aid
    // random access at this point. Specifically, when the bit is set to '1', the next PES packet to start in the payload of Transport
    // Stream packets with the current PID shall contain the first byte of a video sequence header if the PES stream type (refer
    // to Table 2-29) is 1 or 2, or shall contain the first byte of an audio frame if the PES stream type is 3 or 4. In addition, in
    // the case of video, a presentation timestamp shall be present in the PES packet containing the first picture following the
    // sequence header. In the case of audio, the presentation timestamp shall be present in the PES packet containing the first
    // byte of the audio frame. In the PCR_PID the random_access_indicator may only be set to '1' in Transport Stream packet
    // containing the PCR fields.
    int8_t random_access_indicator; //1bit
    // The elementary_stream_priority_indicator is a 1-bit field. It indicates, among
    // packets with the same PID, the priority of the elementary stream data carried within the payload of this Transport Stream
    // packet. A '1' indicates that the payload has a higher priority than the payloads of other Transport Stream packets. In the
    // case of video, this field may be set to '1' only if the payload contains one or more bytes from an intra-coded slice. A
    // value of '0' indicates that the payload has the same priority as all other packets which do not have this bit set to '1'.
    int8_t elementary_stream_priority_indicator; //1bit
    // The PCR_flag is a 1-bit flag. A value of '1' indicates that the adaptation_field contains a PCR field coded in
    // two parts. A value of '0' indicates that the adaptation field does not contain any PCR field.
    int8_t PCR_flag; //1bit
    // The OPCR_flag is a 1-bit flag. A value of '1' indicates that the adaptation_field contains an OPCR field
    // coded in two parts. A value of '0' indicates that the adaptation field does not contain any OPCR field.
    int8_t OPCR_flag; //1bit
    // The splicing_point_flag is a 1-bit flag. When set to '1', it indicates that a splice_countdown field
    // shall be present in the associated adaptation field, specifying the occurrence of a splicing point. A value of '0' indicates
    // that a splice_countdown field is not present in the adaptation field.
    int8_t splicing_point_flag; //1bit
    // The transport_private_data_flag is a 1-bit flag. A value of '1' indicates that the
    // adaptation field contains one or more private_data bytes. A value of '0' indicates the adaptation field does not contain any
    // private_data bytes.
    int8_t transport_private_data_flag; //1bit
    // The adaptation_field_extension_flag is a 1-bit field which when set to '1' indicates
    // the presence of an adaptation field extension. A value of '0' indicates that an adaptation field extension is not present in
    // the adaptation field.
    int8_t adaptation_field_extension_flag; //1bit
    
    // If PCR_flag, 6B
    // The program_clock_reference (PCR) is a
    // 42-bit field coded in two parts. The first part, program_clock_reference_base, is a 33-bit field whose value is given by
    // PCR_base(i), as given in equation 2-2. The second part, program_clock_reference_extension, is a 9-bit field whose value
    // is given by PCR_ext(i), as given in equation 2-3. The PCR indicates the intended time of arrival of the byte containing
    // the last bit of the program_clock_reference_base at the input of the system target decoder.
    int64_t program_clock_reference_base; //33bits
    // 6bits reserved, must be '1'
    int8_t const1_value0; // 6bits
    int16_t program_clock_reference_extension; //9bits
    
    // If OPCR_flag, 6B
    // The optional original
    // program reference (OPCR) is a 42-bit field coded in two parts. These two parts, the base and the extension, are coded
    // identically to the two corresponding parts of the PCR field. The presence of the OPCR is indicated by the OPCR_flag.
    // The OPCR field shall be coded only in Transport Stream packets in which the PCR field is present. OPCRs are permitted
    // in both single program and multiple program Transport Streams.
    //
    // OPCR assists in the reconstruction of a single program Transport Stream from another Transport Stream. When
    // reconstructing the original single program Transport Stream, the OPCR may be copied to the PCR field. The resulting
    // PCR value is valid only if the original single program Transport Stream is reconstructed exactly in its entirety. This
    // would include at least any PSI and private data packets which were present in the original Transport Stream and would
    // possibly require other private arrangements. It also means that the OPCR must be an identical copy of its associated PCR
    // in the original single program Transport Stream.
    int64_t original_program_clock_reference_base; //33bits
    // 6bits reserved, must be '1'
    int8_t const1_value2; // 6bits
    int16_t original_program_clock_reference_extension; //9bits
    
    // If splicing_point_flag, 1B
    // The splice_countdown is an 8-bit field, representing a value which may be positive or negative. A
    // positive value specifies the remaining number of Transport Stream packets, of the same PID, following the associated
    // Transport Stream packet until a splicing point is reached. Duplicate Transport Stream packets and Transport Stream
    // packets which only contain adaptation fields are excluded. The splicing point is located immediately after the last byte of
    // the Transport Stream packet in which the associated splice_countdown field reaches zero. In the Transport Stream packet
    // where the splice_countdown reaches zero, the last data byte of the Transport Stream packet payload shall be the last byte
    // of a coded audio frame or a coded picture. In the case of video, the corresponding access unit may or may not be
    // terminated by a sequence_end_code. Transport Stream packets with the same PID, which follow, may contain data from
    // a different elementary stream of the same type.
    //
    // The payload of the next Transport Stream packet of the same PID (duplicate packets and packets without payload being
    // excluded) shall commence with the first byte of a PES packet.In the case of audio, the PES packet payload shall
    // commence with an access point. In the case of video, the PES packet payload shall commence with an access point, or
    // with a sequence_end_code, followed by an access point. Thus, the previous coded audio frame or coded picture aligns
    // with the packet boundary, or is padded to make this so. Subsequent to the splicing point, the countdown field may also
    // be present. When the splice_countdown is a negative number whose value is minus n(-n), it indicates that the associated
    // Transport Stream packet is the n-th packet following the splicing point (duplicate packets and packets without payload
    // being excluded).
    //
    // For the purposes of this subclause, an access point is defined as follows:
    //       Video - The first byte of a video_sequence_header.
    //       Audio - The first byte of an audio frame.
    int8_t splice_countdown; //8bits
    
    // If transport_private_data_flag, 1+p[0] B
    std::vector<char> transport_private_data; //[transport_private_data_length]bytes
    
    // If adaptation_field_extension_flag, 2+x B
    // The adaptation_field_extension_length is an 8-bit field. It indicates the number of
    // bytes of the extended adaptation field data immediately following this field, including reserved bytes if present.
    uint8_t adaptation_field_extension_length; //8bits
    // This is a 1-bit field which when set to '1' indicates the presence of the ltw_offset
    // field.
    int8_t ltw_flag; //1bit
    // This is a 1-bit field which when set to '1' indicates the presence of the piecewise_rate field.
    int8_t piecewise_rate_flag; //1bit
    // This is a 1-bit flag which when set to '1' indicates that the splice_type and DTS_next_AU fields
    // are present. A value of '0' indicates that neither splice_type nor DTS_next_AU fields are present. This field shall not be
    // set to '1' in Transport Stream packets in which the splicing_point_flag is not set to '1'. Once it is set to '1' in a Transport
    // Stream packet in which the splice_countdown is positive, it shall be set to '1' in all the subsequent Transport Stream
    // packets of the same PID that have the splicing_point_flag set to '1', until the packet in which the splice_countdown
    // reaches zero (including this packet). When this flag is set, if the elementary stream carried in this PID is an audio stream,
    // the splice_type field shall be set to '0000'. If the elementary stream carried in this PID is a video stream, it shall fulfil the
    // constraints indicated by the splice_type value.
    int8_t seamless_splice_flag; //1bit
    // reserved 5bits, must be '1'
    int8_t const1_value1; //5bits
    // if ltw_flag, 2B
    // (legal time window_valid_flag) - This is a 1-bit field which when set to '1' indicates that the value of the
    // ltw_offset shall be valid. A value of '0' indicates that the value in the ltw_offset field is undefined.
    int8_t ltw_valid_flag; //1bit
    // (legal time window offset) - This is a 15-bit field, the value of which is defined only if the ltw_valid flag has
    // a value of '1'. When defined, the legal time window offset is in units of (300/fs) seconds, where fs is the system clock
    // frequency of the program that this PID belongs to, and fulfils:
    //       offset = t1(i) - t(i)
    //       ltw_offset = offset//1
    // where i is the index of the first byte of this Transport Stream packet, offset is the value encoded in this field, t(i) is the
    // arrival time of byte i in the T-STD, and t1(i) is the upper bound in time of a time interval called the Legal Time Window
    // which is associated with this Transport Stream packet.
    int16_t ltw_offset; //15bits
    // if piecewise_rate_flag, 3B
    //2bits reserved
    // The meaning of this 22-bit field is only defined when both the ltw_flag and the ltw_valid_flag are set
    // to '1'. When defined, it is a positive integer specifying a hypothetical bitrate R which is used to define the end times of
    // the Legal Time Windows of Transport Stream packets of the same PID that follow this packet but do not include the
    // legal_time_window_offset field.
    int32_t piecewise_rate; //22bits
    // if seamless_splice_flag, 5B
    // This is a 4-bit field. From the first occurrence of this field onwards, it shall have the same value in all the
    // subsequent Transport Stream packets of the same PID in which it is present, until the packet in which the
    // splice_countdown reaches zero (including this packet). If the elementary stream carried in that PID is an audio stream,
    // this field shall have the value '0000'. If the elementary stream carried in that PID is a video stream, this field indicates the
    // conditions that shall be respected by this elementary stream for splicing purposes. These conditions are defined as a
    // function of profile, level and splice_type in Table 2-7 through Table 2-16.
    int8_t splice_type; //4bits
    // (decoding time stamp next access unit) - This is a 33-bit field, coded in three parts. In the case of
    // continuous and periodic decoding through this splicing point it indicates the decoding time of the first access unit
    // following the splicing point. This decoding time is expressed in the time base which is valid in the Transport Stream
    // packet in which the splice_countdown reaches zero. From the first occurrence of this field onwards, it shall have the
    // same value in all the subsequent Transport Stream packets of the same PID in which it is present, until the packet in
    // which the splice_countdown reaches zero (including this packet).
    int8_t DTS_next_AU0; //3bits
    int8_t marker_bit0; //1bit
    int16_t DTS_next_AU1; //15bits
    int8_t marker_bit1; //1bit
    int16_t DTS_next_AU2; //15bits
    int8_t marker_bit2; //1bit
    // left bytes.
    // This is a fixed 8-bit value equal to '1111 1111' that can be inserted by the encoder. It is discarded by the
    // decoder.
    int nb_af_ext_reserved;
    
    // left bytes.
    // This is a fixed 8-bit value equal to '1111 1111' that can be inserted by the encoder. It is discarded by the
    // decoder.
    int nb_af_reserved;
private:
    SrsTsPacket* packet;
public:
    SrsTsAdaptationField(SrsTsPacket* pkt);
    virtual ~SrsTsAdaptationField();
public:
    virtual srs_error_t decode(SrsBuffer* stream);
public:
    virtual int size();
    virtual srs_error_t encode(SrsBuffer* stream);
};

// 2.4.4.4 Table_id assignments, hls-mpeg-ts-iso13818-1.pdf, page 62
// The table_id field identifies the contents of a Transport Stream PSI section as shown in Table 2-26.
enum SrsTsPsiId
{
    // program_association_section
    SrsTsPsiIdPas = 0x00,
    // conditional_access_section (CA_section)
    SrsTsPsiIdCas = 0x01,
    // TS_program_map_section
    SrsTsPsiIdPms = 0x02,
    // TS_description_section
    SrsTsPsiIdDs = 0x03,
    // ISO_IEC_14496_scene_description_section
    SrsTsPsiIdSds = 0x04,
    // ISO_IEC_14496_object_descriptor_section
    SrsTsPsiIdOds = 0x05,
    // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 reserved
    SrsTsPsiIdIso138181Start = 0x06,
    SrsTsPsiIdIso138181End = 0x37,
    // Defined in ISO/IEC 13818-6
    SrsTsPsiIdIso138186Start = 0x38,
    SrsTsPsiIdIso138186End = 0x3F,
    // User private
    SrsTsPsiIdUserStart = 0x40,
    SrsTsPsiIdUserEnd = 0xFE,
    // forbidden
    SrsTsPsiIdForbidden = 0xFF,
};

// The payload of ts packet, can be PES or PSI payload.
class SrsTsPayload
{
protected:
    SrsTsPacket* packet;
public:
    SrsTsPayload(SrsTsPacket* p);
    virtual ~SrsTsPayload();
public:
    virtual srs_error_t decode(SrsBuffer* stream, SrsTsMessage** ppmsg) = 0;
public:
    virtual int size() = 0;
    virtual srs_error_t encode(SrsBuffer* stream) = 0;
};

// Common MPEG PES packet for both TS and PS.
class SrsMpegPES
{
public:
    // 3B
    // The packet_start_code_prefix is a 24-bit code. Together with the stream_id that follows it
    // constitutes a packet start code that identifies the beginning of a packet. The packet_start_code_prefix is the bit string
    // '0000 0000 0000 0000 0000 0001' (0x000001).
    int32_t packet_start_code_prefix; //24bits
    // 1B
    // In Program Streams, the stream_id specifies the type and number of the elementary stream as defined by the
    // stream_id Table 2-18. In Transport Streams, the stream_id may be set to any valid value which correctly describes the
    // elementary stream type as defined in Table 2-18. In Transport Streams, the elementary stream type is specified in the
    // Program Specific Information as specified in 2.4.4.
    // @see SrsTsPESStreamId, value can be SrsTsPESStreamIdAudioCommon or SrsTsPESStreamIdVideoCommon.
    uint8_t stream_id; //8bits
    // 2B
    // A 16-bit field specifying the number of bytes in the PES packet following the last byte of the
    // field. A value of 0 indicates that the PES packet length is neither specified nor bounded and is allowed only in
    // PES packets whose payload consists of bytes from a video elementary stream contained in Transport Stream packets.
    uint16_t PES_packet_length; //16bits

    // 1B
    // 2bits const '10'
    int8_t const2bits; //2bits
    // The 2-bit PES_scrambling_control field indicates the scrambling mode of the PES packet
    // payload. When scrambling is performed at the PES level, the PES packet header, including the optional fields when
    // present, shall not be scrambled (see Table 2-19).
    int8_t PES_scrambling_control; //2bits
    // This is a 1-bit field indicating the priority of the payload in this PES packet. A '1' indicates a higher
    // priority of the payload of the PES packet payload than a PES packet payload with this field set to '0'. A multiplexor can
    // use the PES_priority bit to prioritize its data within an elementary stream. This field shall not be changed by the transport
    // mechanism.
    int8_t PES_priority; //1bit
    // This is a 1-bit flag. When set to a value of '1' it indicates that the PES packet header is
    // immediately followed by the video start code or audio syncword indicated in the data_stream_alignment_descriptor
    // in 2.6.10 if this descriptor is present. If set to a value of '1' and the descriptor is not present, alignment as indicated in
    // alignment_type '01' in Table 2-47 and Table 2-48 is required. When set to a value of '0' it is not defined whether any such
    // alignment occurs or not.
    int8_t data_alignment_indicator; //1bit
    // This is a 1-bit field. When set to '1' it indicates that the material of the associated PES packet payload is
    // protected by copyright. When set to '0' it is not defined whether the material is protected by copyright. A copyright
    // descriptor described in 2.6.24 is associated with the elementary stream which contains this PES packet and the copyright
    // flag is set to '1' if the descriptor applies to the material contained in this PES packet
    int8_t copyright; //1bit
    // This is a 1-bit field. When set to '1' the contents of the associated PES packet payload is an original.
    // When set to '0' it indicates that the contents of the associated PES packet payload is a copy.
    int8_t original_or_copy; //1bit

    // 1B
    // This is a 2-bit field. When the PTS_DTS_flags field is set to '10', the PTS fields shall be present in
    // the PES packet header. When the PTS_DTS_flags field is set to '11', both the PTS fields and DTS fields shall be present
    // in the PES packet header. When the PTS_DTS_flags field is set to '00' no PTS or DTS fields shall be present in the PES
    // packet header. The value '01' is forbidden.
    int8_t PTS_DTS_flags; //2bits
    // A 1-bit flag, which when set to '1' indicates that ESCR base and extension fields are present in the PES
    // packet header. When set to '0' it indicates that no ESCR fields are present.
    int8_t ESCR_flag; //1bit
    // A 1-bit flag, which when set to '1' indicates that the ES_rate field is present in the PES packet header.
    // When set to '0' it indicates that no ES_rate field is present.
    int8_t ES_rate_flag; //1bit
    // A 1-bit flag, which when set to '1' it indicates the presence of an 8-bit trick mode field. When
    // set to '0' it indicates that this field is not present.
    int8_t DSM_trick_mode_flag; //1bit
    // A 1-bit flag, which when set to '1' indicates the presence of the additional_copy_info field.
    // When set to '0' it indicates that this field is not present.
    int8_t additional_copy_info_flag; //1bit
    // A 1-bit flag, which when set to '1' indicates that a CRC field is present in the PES packet. When set to
    // '0' it indicates that this field is not present.
    int8_t PES_CRC_flag; //1bit
    // A 1-bit flag, which when set to '1' indicates that an extension field exists in this PES packet
    // header. When set to '0' it indicates that this field is not present.
    int8_t PES_extension_flag; //1bit

    // 1B
    // An 8-bit field specifying the total number of bytes occupied by the optional fields and any
    // stuffing bytes contained in this PES packet header. The presence of optional fields is indicated in the byte that precedes
    // the PES_header_data_length field.
    uint8_t PES_header_data_length; //8bits

    // 5B
    // Presentation times shall be related to decoding times as follows: The PTS is a 33-bit
    // number coded in three separate fields. It indicates the time of presentation, tp n (k), in the system target decoder of a
    // presentation unit k of elementary stream n. The value of PTS is specified in units of the period of the system clock
    // frequency divided by 300 (yielding 90 kHz). The presentation time is derived from the PTS according to equation 2-11
    // below. Refer to 2.7.4 for constraints on the frequency of coding presentation timestamps.
    // --------------1B
    // 4bits const
    // 3bits PTS [32..30]
    // 1bit const '1'
    // --------------2B
    // 15bits PTS [29..15]
    // 1bit const '1'
    // --------------2B
    // 15bits PTS [14..0]
    // 1bit const '1'
    int64_t pts; // 33bits

    // 5B
    // The DTS is a 33-bit number coded in three separate fields. It indicates the decoding time,
    // td n (j), in the system target decoder of an access unit j of elementary stream n. The value of DTS is specified in units of
    // the period of the system clock frequency divided by 300 (yielding 90 kHz).
    // --------------1B
    // 4bits const
    // 3bits DTS [32..30]
    // 1bit const '1'
    // --------------2B
    // 15bits DTS [29..15]
    // 1bit const '1'
    // --------------2B
    // 15bits DTS [14..0]
    // 1bit const '1'
    int64_t dts; // 33bits

    // 6B
    // The elementary stream clock reference is a 42-bit field coded in two parts. The first
    // part, ESCR_base, is a 33-bit field whose value is given by ESCR_base(i), as given in equation 2-14. The second part,
    // ESCR_ext, is a 9-bit field whose value is given by ESCR_ext(i), as given in equation 2-15. The ESCR field indicates the
    // intended time of arrival of the byte containing the last bit of the ESCR_base at the input of the PES-STD for PES streams
    // (refer to 2.5.2.4).
    // 2bits reserved
    // 3bits ESCR_base[32..30]
    // 1bit const '1'
    // 15bits ESCR_base[29..15]
    // 1bit const '1'
    // 15bits ESCR_base[14..0]
    // 1bit const '1'
    // 9bits ESCR_extension
    // 1bit const '1'
    int64_t ESCR_base; //33bits
    int16_t ESCR_extension; //9bits

    // 3B
    // The ES_rate field is a 22-bit unsigned integer specifying the rate at which the
    // system target decoder receives bytes of the PES packet in the case of a PES stream. The ES_rate is valid in the PES
    // packet in which it is included and in subsequent PES packets of the same PES stream until a new ES_rate field is
    // encountered. The value of the ES_rate is measured in units of 50 bytes/second. The value 0 is forbidden. The value of the
    // ES_rate is used to define the time of arrival of bytes at the input of a P-STD for PES streams defined in 2.5.2.4. The
    // value encoded in the ES_rate field may vary from PES_packet to PES_packet.
    // 1bit const '1'
    // 22bits ES_rate
    // 1bit const '1'
    int32_t ES_rate; //22bits

    // 1B
    // A 3-bit field that indicates which trick mode is applied to the associated video stream. In cases of
    // other types of elementary streams, the meanings of this field and those defined by the following five bits are undefined.
    // For the definition of trick_mode status, refer to the trick mode section of 2.4.2.3.
    int8_t trick_mode_control; //3bits
    int8_t trick_mode_value; //5bits

    // 1B
    // 1bit const '1'
    // This 7-bit field contains private data relating to copyright information.
    int8_t additional_copy_info; //7bits

    // 2B
    // The previous_PES_packet_CRC is a 16-bit field that contains the CRC value that yields
    // a zero output of the 16 registers in the decoder similar to the one defined in Annex A,
    int16_t previous_PES_packet_CRC; //16bits

    // 1B
    // A 1-bit flag which when set to '1' indicates that the PES packet header contains private data.
    // When set to a value of '0' it indicates that private data is not present in the PES header.
    int8_t PES_private_data_flag; //1bit
    // A 1-bit flag which when set to '1' indicates that an ISO/IEC 11172-1 pack header or a
    // Program Stream pack header is stored in this PES packet header. If this field is in a PES packet that is contained in a
    // Program Stream, then this field shall be set to '0'. In a Transport Stream, when set to the value '0' it indicates that no pack
    // header is present in the PES header.
    int8_t pack_header_field_flag; //1bit
    // A 1-bit flag which when set to '1' indicates that the
    // program_packet_sequence_counter, MPEG1_MPEG2_identifier, and original_stuff_length fields are present in this
    // PES packet. When set to a value of '0' it indicates that these fields are not present in the PES header.
    int8_t program_packet_sequence_counter_flag; //1bit
    // A 1-bit flag which when set to '1' indicates that the P-STD_buffer_scale and P-STD_buffer_size
    // are present in the PES packet header. When set to a value of '0' it indicates that these fields are not present in the
    // PES header.
    int8_t P_STD_buffer_flag; //1bit
    // reverved value, must be '1'
    int8_t const1_value0; //3bits
    // A 1-bit field which when set to '1' indicates the presence of the PES_extension_field_length
    // field and associated fields. When set to a value of '0' this indicates that the PES_extension_field_length field and any
    // associated fields are not present.
    int8_t PES_extension_flag_2; //1bit

    // 16B
    // This is a 16-byte field which contains private data. This data, combined with the fields before and
    // after, shall not emulate the packet_start_code_prefix (0x000001).
    std::vector<char> PES_private_data; //128bits

    // (1+x)B
    std::vector<char> pack_field; //[pack_field_length] bytes

    // 2B
    // 1bit const '1'
    // The program_packet_sequence_counter field is a 7-bit field. It is an optional
    // counter that increments with each successive PES packet from a Program Stream or from an ISO/IEC 11172-1 Stream or
    // the PES packets associated with a single program definition in a Transport Stream, providing functionality similar to a
    // continuity counter (refer to 2.4.3.2). This allows an application to retrieve the original PES packet sequence of a Program
    // Stream or the original packet sequence of the original ISO/IEC 11172-1 stream. The counter will wrap around to 0 after
    // its maximum value. Repetition of PES packets shall not occur. Consequently, no two consecutive PES packets in the
    // program multiplex shall have identical program_packet_sequence_counter values.
    int8_t program_packet_sequence_counter; //7bits
    // 1bit const '1'
    // A 1-bit flag which when set to '1' indicates that this PES packet carries information from
    // an ISO/IEC 11172-1 stream. When set to '0' it indicates that this PES packet carries information from a Program Stream.
    int8_t MPEG1_MPEG2_identifier; //1bit
    // This 6-bit field specifies the number of stuffing bytes used in the original ITU-T
    // Rec. H.222.0 | ISO/IEC 13818-1 PES packet header or in the original ISO/IEC 11172-1 packet header.
    int8_t original_stuff_length; //6bits

    // 2B
    // 2bits const '01'
    // The P-STD_buffer_scale is a 1-bit field, the meaning of which is only defined if this PES packet
    // is contained in a Program Stream. It indicates the scaling factor used to interpret the subsequent P-STD_buffer_size field.
    // If the preceding stream_id indicates an audio stream, P-STD_buffer_scale shall have the value '0'. If the preceding
    // stream_id indicates a video stream, P-STD_buffer_scale shall have the value '1'. For all other stream types, the value
    // may be either '1' or '0'.
    int8_t P_STD_buffer_scale; //1bit
    // The P-STD_buffer_size is a 13-bit unsigned integer, the meaning of which is only defined if this
    // PES packet is contained in a Program Stream. It defines the size of the input buffer, BS n , in the P-STD. If
    // P-STD_buffer_scale has the value '0', then the P-STD_buffer_size measures the buffer size in units of 128 bytes. If
    // P-STD_buffer_scale has the value '1', then the P-STD_buffer_size measures the buffer size in units of 1024 bytes.
    int16_t P_STD_buffer_size; //13bits

    // (1+x)B
    // 1bit const '1'
    std::vector<char> PES_extension_field; //[PES_extension_field_length] bytes

    // NB
    // This is a fixed 8-bit value equal to '1111 1111' that can be inserted by the encoder, for example to meet
    // the requirements of the channel. It is discarded by the decoder. No more than 32 stuffing bytes shall be present in one
    // PES packet header.
    int nb_stuffings;

    // NB
    // PES_packet_data_bytes shall be contiguous bytes of data from the elementary stream
    // indicated by the packet's stream_id or PID. When the elementary stream data conforms to ITU-T
    // Rec. H.262 | ISO/IEC 13818-2 or ISO/IEC 13818-3, the PES_packet_data_bytes shall be byte aligned to the bytes of this
    // Recommendation | International Standard. The byte-order of the elementary stream shall be preserved. The number of
    // PES_packet_data_bytes, N, is specified by the PES_packet_length field. N shall be equal to the value indicated in the
    // PES_packet_length minus the number of bytes between the last byte of the PES_packet_length field and the first
    // PES_packet_data_byte.
    //
    // In the case of a private_stream_1, private_stream_2, ECM_stream, or EMM_stream, the contents of the
    // PES_packet_data_byte field are user definable and will not be specified by ITU-T | ISO/IEC in the future.
    int nb_bytes;

    // NB
    // This is a fixed 8-bit value equal to '1111 1111'. It is discarded by the decoder.
    int nb_paddings;
public:
    // Whether contains payload to dump to message.
    bool has_payload_;
    int nb_payload_;
public:
    SrsMpegPES();
    virtual ~SrsMpegPES();
public:
    virtual srs_error_t decode(SrsBuffer* stream);
public:
    virtual int size();
    virtual srs_error_t encode(SrsBuffer* stream);
private:
    virtual srs_error_t decode_33bits_dts_pts(SrsBuffer* stream, int64_t* pv);
    virtual srs_error_t encode_33bits_dts_pts(SrsBuffer* stream, uint8_t fb, int64_t v);
};

// The PES payload of ts packet.
// 2.4.3.6 PES packet, hls-mpeg-ts-iso13818-1.pdf, page 49
class SrsTsPayloadPES : public SrsTsPayload
{
public:
    SrsMpegPES pes;
public:
    SrsTsPayloadPES(SrsTsPacket* p);
    virtual ~SrsTsPayloadPES();
public:
    virtual srs_error_t decode(SrsBuffer* stream, SrsTsMessage** ppmsg);
public:
    virtual int size();
    virtual srs_error_t encode(SrsBuffer* stream);
};

// The PSI payload of ts packet.
// 2.4.4 Program specific information, hls-mpeg-ts-iso13818-1.pdf, page 59
class SrsTsPayloadPSI : public SrsTsPayload
{
public:
    // 1B
    // This is an 8-bit field whose value shall be the number of bytes, immediately following the pointer_field
    // until the first byte of the first section that is present in the payload of the Transport Stream packet (so a value of 0x00 in
    // The pointer_field indicates that the section starts immediately after the pointer_field). When at least one section begins in
    // a given Transport Stream packet, then the payload_unit_start_indicator (refer to 2.4.3.2) shall be set to 1 and the first
    // byte of the payload of that Transport Stream packet shall contain the pointer. When no section begins in a given
    // Transport Stream packet, then the payload_unit_start_indicator shall be set to 0 and no pointer shall be sent in the
    // payload of that packet.
    int8_t pointer_field;
public:
    // 1B
    // This is an 8-bit field, which shall be set to 0x00 as shown in Table 2-26.
    SrsTsPsiId table_id; //8bits
    
    // 2B
    // The section_syntax_indicator is a 1-bit field which shall be set to '1'.
    int8_t section_syntax_indicator; //1bit
    // const value, must be '0'
    int8_t const0_value; //1bit
    // reverved value, must be '1'
    int8_t const1_value; //2bits
    // This is a 12-bit field, the first two bits of which shall be '00'. The remaining 10 bits specify the number
    // of bytes of the section, starting immediately following the section_length field, and including the CRC. The value in this
    // field shall not exceed 1021 (0x3FD).
    uint16_t section_length; //12bits
public:
    // the specified psi info, for example, PAT fields.
public:
    // 4B
    // This is a 32-bit field that contains the CRC value that gives a zero output of the registers in the decoder
    // defined in Annex A after processing the entire section.
    // @remark crc32(bytes without pointer field, before crc32 field)
    int32_t CRC_32; //32bits
public:
    SrsTsPayloadPSI(SrsTsPacket* p);
    virtual ~SrsTsPayloadPSI();
public:
    virtual srs_error_t decode(SrsBuffer* stream, SrsTsMessage** ppmsg);
public:
    virtual int size();
    virtual srs_error_t encode(SrsBuffer* stream);
protected:
    virtual int psi_size() = 0;
    virtual srs_error_t psi_encode(SrsBuffer* stream) = 0;
    virtual srs_error_t psi_decode(SrsBuffer* stream) = 0;
};

// The program of PAT of PSI ts packet.
class SrsTsPayloadPATProgram
{
public:
    // 4B
    // Program_number is a 16-bit field. It specifies the program to which the program_map_PID is
    // applicable. When set to 0x0000, then the following PID reference shall be the network PID. For all other cases the value
    // of this field is user defined. This field shall not take any single value more than once within one version of the Program
    // Association Table.
    int16_t number; // 16bits
    // reverved value, must be '1'
    int8_t const1_value; //3bits
    // program_map_PID/network_PID 13bits
    // network_PID - The network_PID is a 13-bit field, which is used only in conjunction with the value of the
    // program_number set to 0x0000, specifies the PID of the Transport Stream packets which shall contain the Network
    // Information Table. The value of the network_PID field is defined by the user, but shall only take values as specified in
    // Table 2-3. The presence of the network_PID is optional.
    int16_t pid; //13bits
public:
    SrsTsPayloadPATProgram(int16_t n = 0, int16_t p = 0);
    virtual ~SrsTsPayloadPATProgram();
public:
    virtual srs_error_t decode(SrsBuffer* stream);
public:
    virtual int size();
    virtual srs_error_t encode(SrsBuffer* stream);
};

// The PAT payload of PSI ts packet.
// 2.4.4.3 Program association Table, hls-mpeg-ts-iso13818-1.pdf, page 61
// The Program Association Table provides the correspondence between a program_number and the PID value of the
// Transport Stream packets which carry the program definition. The program_number is the numeric label associated with
// a program.
class SrsTsPayloadPAT : public SrsTsPayloadPSI
{
public:
    // 2B
    // This is a 16-bit field which serves as a label to identify this Transport Stream from any other
    // multiplex within a network. Its value is defined by the user.
    uint16_t transport_stream_id; //16bits
    
    // 1B
    // reverved value, must be '1'
    int8_t const3_value; //2bits
    // This 5-bit field is the version number of the whole Program Association Table. The version number
    // shall be incremented by 1 modulo 32 whenever the definition of the Program Association Table changes. When the
    // current_next_indicator is set to '1', then the version_number shall be that of the currently applicable Program Association
    // Table. When the current_next_indicator is set to '0', then the version_number shall be that of the next applicable Program
    // Association Table.
    int8_t version_number; //5bits
    // A 1-bit indicator, which when set to '1' indicates that the Program Association Table sent is
    // currently applicable. When the bit is set to '0', it indicates that the table sent is not yet applicable and shall be the next
    // table to become valid.
    int8_t current_next_indicator; //1bit
    
    // 1B
    // This 8-bit field gives the number of this section. The section_number of the first section in the
    // Program Association Table shall be 0x00. It shall be incremented by 1 with each additional section in the Program
    // Association Table.
    uint8_t section_number; //8bits
    
    // 1B
    // This 8-bit field specifies the number of the last section (that is, the section with the highest
    // section_number) of the complete Program Association Table.
    uint8_t last_section_number; //8bits
    
    // multiple 4B program data.
    std::vector<SrsTsPayloadPATProgram*> programs;
public:
    SrsTsPayloadPAT(SrsTsPacket* p);
    virtual ~SrsTsPayloadPAT();
protected:
    virtual srs_error_t psi_decode(SrsBuffer* stream);
protected:
    virtual int psi_size();
    virtual srs_error_t psi_encode(SrsBuffer* stream);
};

// The esinfo for PMT program.
class SrsTsPayloadPMTESInfo
{
public:
    // 1B
    // This is an 8-bit field specifying the type of program element carried within the packets with the PID
    // whose value is specified by the elementary_PID. The values of stream_type are specified in Table 2-29.
    SrsTsStream stream_type; //8bits
    
    // 2B
    // reverved value, must be '1'
    int8_t const1_value0; //3bits
    // This is a 13-bit field specifying the PID of the Transport Stream packets which carry the associated
    // program element.
    int16_t elementary_PID; //13bits
    
    // (2+x)B
    // reverved value, must be '1'
    int8_t const1_value1; //4bits
    std::vector<char> ES_info; //[ES_info_length] bytes.
public:
    SrsTsPayloadPMTESInfo(SrsTsStream st = SrsTsStreamReserved, int16_t epid = 0);
    virtual ~SrsTsPayloadPMTESInfo();
public:
    virtual srs_error_t decode(SrsBuffer* stream);
public:
    virtual int size();
    virtual srs_error_t encode(SrsBuffer* stream);
};

// The PMT payload of PSI ts packet.
// 2.4.4.8 Program Map Table, hls-mpeg-ts-iso13818-1.pdf, page 64
// The Program Map Table provides the mappings between program numbers and the program elements that comprise
// Them. A single instance of such a mapping is referred to as a "program definition". The program map table is the
// complete collection of all program definitions for a Transport Stream. This table shall be transmitted in packets, the PID
// values of which are selected by the encoder. More than one PID value may be used, if desired. The table is contained in
// one or more sections with the following syntax. It may be segmented to occupy multiple sections. In each section, the
// section number field shall be set to zero. Sections are identified by the program_number field.
class SrsTsPayloadPMT : public SrsTsPayloadPSI
{
public:
    // 2B
    // program_number is a 16-bit field. It specifies the program to which the program_map_PID is
    // applicable. One program definition shall be carried within only one TS_program_map_section. This implies that a
    // program definition is never longer than 1016 (0x3F8). See Informative Annex C for ways to deal with the cases when
    // that length is not sufficient. The program_number may be used as a designation for a broadcast channel, for example. By
    // describing the different program elements belonging to a program, data from different sources (e.g. sequential events)
    // can be concatenated together to form a continuous set of streams using a program_number. For examples of applications
    // refer to Annex C.
    uint16_t program_number; //16bits
    
    // 1B
    // reverved value, must be '1'
    int8_t const1_value0; //2bits
    // This 5-bit field is the version number of the TS_program_map_section. The version number shall be
    // incremented by 1 modulo 32 when a change in the information carried within the section occurs. Version number refers
    // to the definition of a single program, and therefore to a single section. When the current_next_indicator is set to '1', then
    // The version_number shall be that of the currently applicable TS_program_map_section. When the current_next_indicator
    // is set to '0', then the version_number shall be that of the next applicable TS_program_map_section.
    int8_t version_number; //5bits
    // A 1-bit field, which when set to '1' indicates that the TS_program_map_section sent is
    // currently applicable. When the bit is set to '0', it indicates that the TS_program_map_section sent is not yet applicable
    // and shall be the next TS_program_map_section to become valid.
    int8_t current_next_indicator; //1bit
    
    // 1B
    // The value of this 8-bit field shall be 0x00.
    uint8_t section_number; //8bits
    
    // 1B
    // The value of this 8-bit field shall be 0x00.
    uint8_t last_section_number; //8bits
    
    // 2B
    // reverved value, must be '1'
    int8_t const1_value1; //3bits
    // This is a 13-bit field indicating the PID of the Transport Stream packets which shall contain the PCR fields
    // valid for the program specified by program_number. If no PCR is associated with a program definition for private
    // streams, then this field shall take the value of 0x1FFF. Refer to the semantic definition of PCR in 2.4.3.5 and Table 2-3
    // for restrictions on the choice of PCR_PID value.
    int16_t PCR_PID; //13bits
    
    // 2B
    int8_t const1_value2; //4bits
    // This is a 12-bit field, the first two bits of which shall be '00'. The remaining 10 bits specify the
    // number of bytes of the descriptors immediately following the program_info_length field.
    std::vector<char> program_info_desc; //[program_info_length]bytes
    
    // array of TSPMTESInfo.
    std::vector<SrsTsPayloadPMTESInfo*> infos;
public:
    SrsTsPayloadPMT(SrsTsPacket* p);
    virtual ~SrsTsPayloadPMT();
protected:
    virtual srs_error_t psi_decode(SrsBuffer* stream);
protected:
    virtual int psi_size();
    virtual srs_error_t psi_encode(SrsBuffer* stream);
};

// Write the TS message to TS context.
class SrsTsContextWriter
{
private:
    // User must config the codec in right way.
    SrsVideoCodecId vcodec_;
    SrsAudioCodecId acodec_;
private:
    SrsTsContext* context;
    ISrsStreamWriter* writer;
    std::string path;
public:
    SrsTsContextWriter(ISrsStreamWriter* w, SrsTsContext* c, SrsAudioCodecId ac, SrsVideoCodecId vc);
    virtual ~SrsTsContextWriter();
public:
    // Write an audio frame to ts,
    virtual srs_error_t write_audio(SrsTsMessage* audio);
    // Write a video frame to ts,
    virtual srs_error_t write_video(SrsTsMessage* video);
public:
    // Get or update the video codec of ts muxer.
    virtual SrsVideoCodecId vcodec();
    virtual void set_vcodec(SrsVideoCodecId v);
public:
    // Get and set the audio codec.
    SrsAudioCodecId acodec();
    void set_acodec(SrsAudioCodecId v);
};

// Used for HLS Encryption
class SrsEncFileWriter: public SrsFileWriter
{
public:
    SrsEncFileWriter();
    virtual ~SrsEncFileWriter();
public:
    virtual srs_error_t write(void* data, size_t count, ssize_t* pnwrite);
    virtual void close();
public:
    srs_error_t config_cipher(unsigned char* key, unsigned char* iv);
private:
    unsigned char* key;
    unsigned char iv[16];
private:
    char* buf;
    int nb_buf;
};

// TS messages cache, to group frames to TS message,
// for example, we may write multiple AAC RAW frames to a TS message.
class SrsTsMessageCache
{
public:
    // The current ts message.
    SrsTsMessage* audio;
    SrsTsMessage* video;
public:
    SrsTsMessageCache();
    virtual ~SrsTsMessageCache();
public:
    // Write audio to cache
    virtual srs_error_t cache_audio(SrsAudioFrame* frame, int64_t dts);
    // Write video to muxer.
    virtual srs_error_t cache_video(SrsVideoFrame* frame, int64_t dts);
private:
    virtual srs_error_t do_cache_mp3(SrsAudioFrame* frame);
    virtual srs_error_t do_cache_aac(SrsAudioFrame* frame);
    virtual srs_error_t do_cache_avc(SrsVideoFrame* frame);
#ifdef SRS_H265
    virtual srs_error_t do_cache_hevc(SrsVideoFrame* frame);
#endif
};

// Transmux the RTMP stream to HTTP-TS stream.
class SrsTsTransmuxer
{
private:
    ISrsStreamWriter* writer;
    bool has_audio_;
    bool has_video_;
    bool guess_has_av_;
private:
    SrsFormat* format;
    SrsTsMessageCache* tsmc;
    SrsTsContextWriter* tscw;
    SrsTsContext* context;
public:
    SrsTsTransmuxer();
    virtual ~SrsTsTransmuxer();
public:
    void set_has_audio(bool v);
    void set_has_video(bool v);
    void set_guess_has_av(bool v);
public:
    // Initialize the underlayer file stream.
    // @param fw the writer to use for ts encoder, user must free it.
    virtual srs_error_t initialize(ISrsStreamWriter* fw);
public:
    // Write audio/video packet.
    // @remark assert data is not NULL.
    virtual srs_error_t write_audio(int64_t timestamp, char* data, int size);
    virtual srs_error_t write_video(int64_t timestamp, char* data, int size);
private:
    virtual srs_error_t flush_audio();
    virtual srs_error_t flush_video();
};

#endif

