SRS 代码分析【mpeg-ts解析】

来源:互联网 发布:北京网络维护公司 编辑:程序博客网 时间:2024/06/04 23:33

SRS 代码分析【mpeg-ts解析】

1.SrsTsContext的decode接口定义如下:

int SrsTsContext::decode(SrsBuffer* stream, ISrsTsHandler* handler){    int ret = ERROR_SUCCESS;        // parse util EOF of stream.    // for example, parse multiple times for the PES_packet_length(0) packet.    while (!stream->empty()) {        SrsTsPacket* packet = new SrsTsPacket(this);        SrsAutoFree(SrsTsPacket, packet);                SrsTsMessage* msg = NULL;        if ((ret = packet->decode(stream, &msg)) != ERROR_SUCCESS) {            srs_error("mpegts: decode ts packet failed. ret=%d", ret);            return ret;        }                if (!msg) {            continue;        }        SrsAutoFree(SrsTsMessage, msg);                if ((ret = handler->on_ts_message(msg)) != ERROR_SUCCESS) {            srs_error("mpegts: handler ts message failed. ret=%d", ret);            return ret;        }    }        return ret;}

首先创建SrsTsPacket,接着调用packet->decode().

SrsTsPacket的定义

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; //4bitsprivate:    SrsTsAdaptationField* adaptation_field;    SrsTsPayload* payload;......}
字段的说明

字段

Value

bits

 

sync_byte

0x47

8

bslbf

transport_error_indicator

如果这个流中包含了一个无法修复的错误,由解调器设置,以告诉多路解调器,该包存在一个无法纠正的错误

1

bslbf

payload_unit_start_indicator

1 表示是 PES 数据或 PSI数据的开始部分,否则为零.

1

bslbf

transport_priority

1 意思是在相同 PID 的数据包中含有更高的优先权.

1

bslbf

PID

PID 为13 比特字段,指示包有效载荷中存储的数据类型,也就是包的标识号。

13

uimsbf

transport_scrambling_control

此2 比特字段指示传输流包有效载荷的加扰方式。

2

bslbf

adaptation_field_control

此2 比特字段指示此传输流包头是否后随自适应字段和/或有效载荷

2

bslbf

continuity_counter

包递增计数器,continuity_counter 为4 比特字段,随着具有相同PID 的每个传输流包而增加

4

uimsbf

  

 

这里最主要关系的是payload_unit_start_indicator,PID,adaptation_field_control,continuity_counter

payload_unit_start_indicator

这个位标志为1,指的是一个包的启示,因为ts包只有188个字节,对于一个PES包的话往往大于188字节,因此一个PES包往往要拆成多个TS包,为了识别收到的TS包属于另一个PES包,起始位表示新的一个PES包或者PSI包等到来了。

2.SrsTsPacket的decode接口定义如下:

int SrsTsPacket::decode(SrsBuffer* stream, SrsTsMessage** ppmsg){    int ret = ERROR_SUCCESS;        int pos = stream->pos();        // 4B ts packet header.    if (!stream->require(4)) {        ret = ERROR_STREAM_CASTER_TS_HEADER;        srs_error("ts: demux header failed. ret=%d", ret);        return ret;    }        sync_byte = stream->read_1bytes();    if (sync_byte != 0x47) {        ret = ERROR_STREAM_CASTER_TS_SYNC_BYTE;        srs_error("ts: sync_bytes must be 0x47, actual=%#x. ret=%d", sync_byte, ret);        return ret;    }        int16_t pidv = stream->read_2bytes();    transport_error_indicator = (pidv >> 15) & 0x01;    payload_unit_start_indicator = (pidv >> 14) & 0x01;    transport_priority = (pidv >> 13) & 0x01;    pid = (SrsTsPid)(pidv & 0x1FFF);        int8_t ccv = stream->read_1bytes();    transport_scrambling_control = (SrsTsScrambled)((ccv >> 6) & 0x03);    adaption_field_control = (SrsTsAdaptationFieldType)((ccv >> 4) & 0x03);    continuity_counter = ccv & 0x0F;        // TODO: FIXME: create pids map when got new pid.        srs_info("ts: header sync=%#x error=%d unit_start=%d priotiry=%d pid=%d scrambling=%d adaption=%d counter=%d",             sync_byte, transport_error_indicator, payload_unit_start_indicator, transport_priority, pid,             transport_scrambling_control, adaption_field_control, continuity_counter);        // optional: adaptation field    if (adaption_field_control == SrsTsAdaptationFieldTypeAdaptionOnly || adaption_field_control == SrsTsAdaptationFieldTypeBoth) {        srs_freep(adaptation_field);        adaptation_field = new SrsTsAdaptationField(this);                if ((ret = adaptation_field->decode(stream)) != ERROR_SUCCESS) {            srs_error("ts: demux af faield. ret=%d", ret);            return ret;        }        srs_verbose("ts: demux af ok.");    }        // calc the user defined data size for payload.    int nb_payload = SRS_TS_PACKET_SIZE - (stream->pos() - pos);        // optional: payload.    if (adaption_field_control == SrsTsAdaptationFieldTypePayloadOnly || adaption_field_control == SrsTsAdaptationFieldTypeBoth) {        if (pid == SrsTsPidPAT) {            // 2.4.4.3 Program association Table            srs_freep(payload);            payload = new SrsTsPayloadPAT(this);        } else {            SrsTsChannel* channel = context->get(pid);            if (channel && channel->apply == SrsTsPidApplyPMT) {                // 2.4.4.8 Program Map Table                srs_freep(payload);                payload = new SrsTsPayloadPMT(this);            } else if (channel && (channel->apply == SrsTsPidApplyVideo || channel->apply == SrsTsPidApplyAudio)) {                // 2.4.3.6 PES packet                srs_freep(payload);                payload = new SrsTsPayloadPES(this);            } else {                // left bytes as reserved.                stream->skip(nb_payload);            }        }                if (payload && (ret = payload->decode(stream, ppmsg)) != ERROR_SUCCESS) {            srs_error("ts: demux payload failed. ret=%d", ret);            return ret;        }    }        return ret;}
首先该函数完成payload_unit_start_indicator,PID,adaptation_field_control,continuity_counter等字段的解析。

然后根据adaption_field_control字段判断有没有payload,adaptionfield

adaption_field_control字段的说明如下:

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,};

adaptation_field_control的值如下表描述



存在adaption自适应字段的场合,会接着创建SrsTsAdaptionField,并调用该类decode方法去解析各个字段。

if (adaption_field_control == SrsTsAdaptationFieldTypeAdaptionOnly || adaption_field_control == SrsTsAdaptationFieldTypeBoth)

自适应字段我们主要关注的是adaptation  field length和PCR,这里重点讲解他们的主要用处:

adaptationfield length指的是自适应字段的长度,也就是,从discontinuity indicator 到adaptation field最后的长度,也就是从第6字节(包含第6字节)开始算到最后。

 

PCR

这个值是系统的时间戳,在PES层时间戳是PTS与DTS,这里要注意与PCR,PTS,DTS的概念,可能会让人模糊。PCR是TS层的时间戳,PTS与DTS是PES的时间戳,PCR在PES层相当于DTS,TS不需要考虑PTS。为啥不需要,这里就要讲下,PTS的具体概念。详细的在ISO-13818-1上有,详细到可以看到你吐。其实实际中不需要考虑这么多。我简单的讲吧。在ES流中,依次组成图像帧序为I1P4B2B3P7B5B6I10B8B9的,这里,I、P、B分别指I帧,P帧,B帧。具体意义可以参考H264的相关基本概念,对于I、P帧而言,PES的图像帧序为I1P4B2B3P7B5B6I10B8B9,应该P4比B2、B3在先,但显示时P4一定 要比B2、B3在后,这就必须重新排序。在PTS/DTS时间标志指引下,将P4提前插入数据流,经过缓存器重新排序,重建视频帧序 I1B2B3P4B5B6P7B8B9I10。显然,PTS/DTS是表明确定事件或确定信息,并以专用时标形态确定事件或信息的开始时刻。说到这里,PTS,与DTS的概念应该明白了。但是为啥TS层不需要呢,因为TS层只是负责传输,你知道解码的时间在什么位置,确保传输的TS包不是延迟太久就可以了,具体的显示细节交给PES层去做。



存在payload的场合,会接着根据pid类型判断包的类型,有PAT,PMT,PES,以及Resolved

if (adaption_field_control == SrsTsAdaptationFieldTypePayloadOnly || adaption_field_control == SrsTsAdaptationFieldTypeBoth)


下面是pid类型定义的枚举

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,    // null packets (see Table 2-3)    SrsTsPidNULL = 0x01FFF,};
类型说明

PID program id

节目标示符,一个13位的无符号整数。作用如下表描述。

3.PAT包的处理,PAT包的pid为0x00

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> program;
    unsigned reserved_3                        : 3; // 保留位
    unsigned network_PID                    : 13; //网络信息表(NIT)的PID,节目号为0时对应的PID为network_PID

    unsigned CRC_32                            : 32;  //CRC32校验码


解析PAT包对应的类为SrsTsPayloadPAT,该类继承自SrsTsPayloadPSI

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;......}

由于PAT表和PMT表的读取过程存在相同的处理,相同的部分被封装到基类SrsTsPayloadPSI的decode函数中;基类SrsTsPayloadPSI中有纯虚函数psi_decode,不同的部分在子类的psi_decode中去实现。

SrsTsPayloadPSI的头文件定义如下

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; //12bitspublic:    // 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......}

SrsTsPayloadPAT没有重写decode方法,实际还是调用父类SrsTsPayloadPSI的decode方法,定义如下


int SrsTsPayloadPSI::decode(SrsBuffer* stream, SrsTsMessage** /*ppmsg*/){    int ret = ERROR_SUCCESS;        /**     * 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).     */    if (packet->payload_unit_start_indicator) {        if (!stream->require(1)) {            ret = ERROR_STREAM_CASTER_TS_PSI;            srs_error("ts: demux PSI failed. ret=%d", ret);            return ret;        }        pointer_field = stream->read_1bytes();    }        // to calc the crc32    char* ppat = stream->data() + stream->pos();    int pat_pos = stream->pos();        // atleast 3B for all psi.    if (!stream->require(3)) {        ret = ERROR_STREAM_CASTER_TS_PSI;        srs_error("ts: demux PSI failed. ret=%d", ret);        return ret;    }    // 1B    table_id = (SrsTsPsiId)stream->read_1bytes();        // 2B    int16_t slv = stream->read_2bytes();        section_syntax_indicator = (slv >> 15) & 0x01;    const0_value = (slv >> 14) & 0x01;    const1_value = (slv >> 12) & 0x03;    section_length = slv & 0x0FFF;        // no section, ignore.    if (section_length == 0) {        srs_warn("ts: demux PAT ignore empty section");        return ret;    }        if (!stream->require(section_length)) {        ret = ERROR_STREAM_CASTER_TS_PSI;        srs_error("ts: demux PAT section failed. ret=%d", ret);        return ret;    }        // call the virtual method of actual PSI.    if ((ret = psi_decode(stream)) != ERROR_SUCCESS) {        return ret;    }        // 4B    if (!stream->require(4)) {        ret = ERROR_STREAM_CASTER_TS_PSI;        srs_error("ts: demux PSI crc32 failed. ret=%d", ret);        return ret;    }    CRC_32 = stream->read_4bytes();        // verify crc32.    int32_t crc32 = srs_crc32_mpegts(ppat, stream->pos() - pat_pos - 4);    if (crc32 != CRC_32) {        ret = ERROR_STREAM_CASTER_TS_CRC32;        srs_error("ts: verify PSI crc32 failed. ret=%d", ret);        return ret;    }        // consume left stuffings    if (!stream->empty()) {        int nb_stuffings = stream->size() - stream->pos();        char* stuffing = stream->data() + stream->pos();                // all stuffing must be 0xff.        // TODO: FIXME: maybe need to remove the following.        for (int i = 0; i < nb_stuffings; i++) {            if ((uint8_t)stuffing[i] != 0xff) {                srs_warn("ts: stuff is not 0xff, actual=%#x", stuffing[i]);                break;            }        }                stream->skip(nb_stuffings);    }        return ret;}
关于pointfiled的说明:当TS包带有PSI数据并且payload_unit_start_indicator为1时,表示TS包带有PSI部分的第一个字节,即第一个字节带有指针pointer_field,为0表示TS包不带有一个PSI部分的第一个字节,即在有效净荷中没有指针pointer_field。

SrsTsPayloadPSI的decode函数会调用子类的psi_decode函数,这里调用的是SrsTsPayloadPAT的psi_decode函数,定义如下:

int SrsTsPayloadPAT::psi_decode(SrsBuffer* stream){    int ret = ERROR_SUCCESS;        // atleast 5B for PAT specified    if (!stream->require(5)) {        ret = ERROR_STREAM_CASTER_TS_PAT;        srs_error("ts: demux PAT failed. ret=%d", ret);        return ret;    }        int pos = stream->pos();        // 2B    transport_stream_id = stream->read_2bytes();        // 1B    int8_t cniv = stream->read_1bytes();        const3_value = (cniv >> 6) & 0x03;    version_number = (cniv >> 1) & 0x1F;    current_next_indicator = cniv & 0x01;        // TODO: FIXME: check the indicator.        // 1B    section_number = stream->read_1bytes();    // 1B    last_section_number = stream->read_1bytes();        // multiple 4B program data.    int program_bytes = section_length - 4 - (stream->pos() - pos);    for (int i = 0; i < program_bytes; i += 4) {        SrsTsPayloadPATProgram* program = new SrsTsPayloadPATProgram();                if ((ret = program->decode(stream)) != ERROR_SUCCESS) {            return ret;        }                // update the apply pid table.        packet->context->set(program->pid, SrsTsPidApplyPMT);                programs.push_back(program);    }        // update the apply pid table.    packet->context->set(packet->pid, SrsTsPidApplyPAT);    packet->context->on_pmt_parsed();        return ret;}


psi_decode函数将解析的节目信息存放在SrsTsPayloadPATProgram,该类定义如下:

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......}
字段说明

 unsigned number    :16; //节目号
 unsigned program_map_PID   :13;   //节目映射表的PID,每个节目对应一个


SrsTsPayloadPAT::psi_decode函数中每解析一个SrsTsPayloadPATProgram都会调用SrsTsContext::set方法更新节目映射表。后面在解析PMT数据时会用到更新的pid。

packet->context->set(program->pid, SrsTsPidApplyPMT)
void SrsTsContext::set(int pid, SrsTsPidApply apply_pid, SrsTsStream stream){    SrsTsChannel* channel = NULL;        if (pids.find(pid) == pids.end()) {        channel = new SrsTsChannel();        channel->context = this;        pids[pid] = channel;    } else {        channel = pids[pid];    }        channel->pid = pid;    channel->apply = apply_pid;    channel->stream = stream;}

4.PMT包的处理,PMT包的pid在解析PAT表时通过SrsTsContext::set进行了记录。
SrsTsPacket::decode中调用下面的方法去判断包中数据是否为PMT

            SrsTsChannel* channel = context->get(pid);            if (channel && channel->apply == SrsTsPidApplyPMT) {                // 2.4.4.8 Program Map Table                srs_freep(payload);                payload = new SrsTsPayloadPMT(this);            }


PMT表的描述  

 如果一个TS流中含有多个频道,那么就会包含多个PID不同的PMT表。

  PMT表中包含的数据如下:

(1) 当前频道中包含的所有Video数据的PID

(2) 当前频道中包含的所有Audio数据的PID

(3) 和当前频道关联在一起的其他数据的PID(如数字广播,数据通讯等使用的PID)

只要我们处理了PMT,那么我们就可以获取频道中所有的PID信息,如当前频道包含多少个Video、共多少个Audio和其他数据还能知道每种数据对应的PID分别是什么。这样如果我们要选择其中一个VideoAudio收看,那么只需要把要收看的节目的Video PIDAudio PID保存起来,在处理Packet的时候进行过滤即可实现。

PMT表字段说明如下:

  1.     unsigned table_id                        : 8; //固定为0x02, 表示PMT表  
  2.     unsigned section_syntax_indicator        : 1; //固定为0x01  
  3.     unsigned zero                            : 1; //0x01  
  4.     unsigned reserved_1                      : 2; //0x03  
  5.     unsigned section_length                  : 12;//首先两位bit置为00,它指示段的byte数,由段长度域开始,包含CRC。  
  6.      unsigned program_number                    : 16;// 指出该节目对应于可应用的Program map PID  
  7.     unsigned reserved_2                        : 2; //0x03  
  8.     unsigned version_number                    : 5; //指出TS流中Program map section的版本号  
  9.      unsigned current_next_indicator            : 1; //当该位置1时,当前传送的Program map section可用;  
  10.                                                      //当该位置0时,指示当前传送的Program map section不可用,下一个TS流的Program map section有效。  
  11.      unsigned section_number                    : 8; //固定为0x00  
  12.     unsigned last_section_number            : 8; //固定为0x00  
  13.     unsigned reserved_3                        : 3; //0x07  
  14.     unsigned PCR_PID                        : 13; //指明TS包的PID值,该TS包含有PCR域,  
  15.             //该PCR值对应于由节目号指定的对应节目。  
  16.             //如果对于私有数据流的节目定义与PCR无关,这个域的值将为0x1FFF。  
  17.     unsigned reserved_4                        : 4; //预留为0x0F  
  18.     unsigned program_info_length            : 12; //前两位bit为00。该域指出跟随其后对节目信息的描述的byte数。  
  19.       
  20.     std::vector<TS_PMT_Stream> PMT_Stream;  //每个元素包含8位, 指示特定PID的节目元素包的类型。该处PID由elementary PID指定  
  21.     unsigned reserved_5                        : 3; //0x07  
  22.     unsigned reserved_6                        : 4; //0x0F  
  23.     unsigned CRC_32                            : 32;  


解析PMT包对应的类为SrsTsPayloadPMT,该类也是继承自SrsTsPayloadPSI


/** * 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;......}

SrsTsPayloadPMT也实现了基类的纯虚函数psi_decode用来解析PMT数据,定义如下:

int SrsTsPayloadPMT::psi_decode(SrsBuffer* stream){    int ret = ERROR_SUCCESS;        // atleast 9B for PMT specified    if (!stream->require(9)) {        ret = ERROR_STREAM_CASTER_TS_PMT;        srs_error("ts: demux PMT failed. ret=%d", ret);        return ret;    }        // 2B    program_number = stream->read_2bytes();        // 1B    int8_t cniv = stream->read_1bytes();        const1_value0 = (cniv >> 6) & 0x03;    version_number = (cniv >> 1) & 0x1F;    current_next_indicator = cniv & 0x01;        // 1B    section_number = stream->read_1bytes();        // 1B    last_section_number = stream->read_1bytes();        // 2B    int16_t ppv = stream->read_2bytes();    const1_value1 = (ppv >> 13) & 0x07;    PCR_PID = ppv & 0x1FFF;        // 2B    int16_t pilv = stream->read_2bytes();    const1_value2 = (pilv >> 12) & 0x0F;    /**     * 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.     */    uint16_t program_info_length = pilv & 0xFFF;        if (program_info_length > 0) {        if (!stream->require(program_info_length)) {            ret = ERROR_STREAM_CASTER_TS_PMT;            srs_error("ts: demux PMT program info failed. ret=%d", ret);            return ret;        }                program_info_desc.resize(program_info_length);        stream->read_bytes(&program_info_desc[0], program_info_length);    }        // [section_length] - 4(CRC) - 9B - [program_info_length]    int ES_EOF_pos = stream->pos() + section_length - 4 - 9 - program_info_length;    while (stream->pos() < ES_EOF_pos) {        SrsTsPayloadPMTESInfo* info = new SrsTsPayloadPMTESInfo();        infos.push_back(info);                if ((ret = info->decode(stream)) != ERROR_SUCCESS) {            return ret;        }                // update the apply pid table        switch (info->stream_type) {            case SrsTsStreamVideoH264:            case SrsTsStreamVideoMpeg4:                packet->context->set(info->elementary_PID, SrsTsPidApplyVideo, info->stream_type);                break;            case SrsTsStreamAudioAAC:            case SrsTsStreamAudioAC3:            case SrsTsStreamAudioDTS:            case SrsTsStreamAudioMp3:                packet->context->set(info->elementary_PID, SrsTsPidApplyAudio, info->stream_type);                break;            default:                srs_warn("ts: drop pid=%#x, stream=%#x", info->elementary_PID, info->stream_type);                break;        }    }        // update the apply pid table.    packet->context->set(packet->pid, SrsTsPidApplyPMT);        return ret;}
psi_decode函数将解析的媒体流信息存放在SrsTsPayloadPMTESInfo,该类定义如下:
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.......}

字段说明


  1. unsigned stream_type                       : 8; //指示特定PID的节目元素包的类型。音视频编码格式。
  2.  unsigned elementary_PID                    : 13; //该域指示TS包的PID值。这些TS包含有相关的节目元素    
  3.  unsigned ES_info_length                    : 12; //前两位bit为00。该域指示跟随其后的描述相关节目元素的byte数    
  4.  unsigned descriptor;    


媒体节目信息的解析如下:

int SrsTsPayloadPMTESInfo::decode(SrsBuffer* stream){    int ret = ERROR_SUCCESS;        // 5B    if (!stream->require(5)) {        ret = ERROR_STREAM_CASTER_TS_PMT;        srs_error("ts: demux PMT es info failed. ret=%d", ret);        return ret;    }        stream_type = (SrsTsStream)stream->read_1bytes();        int16_t epv = stream->read_2bytes();    const1_value0 = (epv >> 13) & 0x07;    elementary_PID = epv & 0x1FFF;        int16_t eilv = stream->read_2bytes();    const1_value1 = (eilv >> 12) & 0x0f;    /**     * 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 of the associated program element immediately following the ES_info_length field.     */    int16_t ES_info_length = eilv & 0x0FFF;        if (ES_info_length > 0) {        if (!stream->require(ES_info_length)) {            ret = ERROR_STREAM_CASTER_TS_PMT;            srs_error("ts: demux PMT es info data failed. ret=%d", ret);            return ret;        }        ES_info.resize(ES_info_length);        stream->read_bytes(&ES_info[0], ES_info_length);    }        return ret;}

4.PES包的处理,PES包的pid在解析PMT表时通过SrsTsContext::set进行了记录。
SrsTsPacket::decode中调用下面的方法去判断包中数据是否为PES

            if (channel && (channel->apply == SrsTsPidApplyVideo || channel->apply == SrsTsPidApplyAudio)) {                // 2.4.3.6 PES packet                srs_freep(payload);                payload = new SrsTsPayloadPES(this);            }


解析PES包对应的类为SrsTsPayloadPES,该类头文件中定义了PES包中的字段。

class SrsTsPayloadPES : public SrsTsPayload{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;......}
PES各个字段说明请参照:http://blog.csdn.net/cabbage2008/article/details/49848937

SrsTsPayloadPES的decode函数会解析上述字段。定义如下:

int SrsTsPayloadPES::decode(SrsBuffer* stream, SrsTsMessage** ppmsg){    int ret = ERROR_SUCCESS;        // find the channel from chunk.    SrsTsChannel* channel = packet->context->get(packet->pid);    if (!channel) {        ret = ERROR_STREAM_CASTER_TS_PSE;        srs_error("ts: demux PES no channel for pid=%#x. ret=%d", packet->pid, ret);        return ret;    }        // init msg.    SrsTsMessage* msg = channel->msg;    if (!msg) {        msg = new SrsTsMessage(channel, packet);        channel->msg = msg;    }        // we must cache the fresh state of msg,    // for the PES_packet_length is 0, the first payload_unit_start_indicator always 1,    // so should check for the fresh and not completed it.    bool is_fresh_msg = msg->fresh();        // check when fresh, the payload_unit_start_indicator    // should be 1 for the fresh msg.    if (is_fresh_msg && !packet->payload_unit_start_indicator) {        ret = ERROR_STREAM_CASTER_TS_PSE;        srs_error("ts: PES fresh packet length=%d, us=%d, cc=%d. ret=%d",                  msg->PES_packet_length, packet->payload_unit_start_indicator, packet->continuity_counter,                  ret);        return ret;    }        // check when not fresh and PES_packet_length>0,    // the payload_unit_start_indicator should never be 1 when not completed.    if (!is_fresh_msg && msg->PES_packet_length > 0        && !msg->completed(packet->payload_unit_start_indicator)        && packet->payload_unit_start_indicator        ) {        ret = ERROR_STREAM_CASTER_TS_PSE;        srs_error("ts: PES packet length=%d, payload=%d, us=%d, cc=%d. ret=%d",                  msg->PES_packet_length, msg->payload->length(), packet->payload_unit_start_indicator,                  packet->continuity_counter, ret);                // reparse current msg.        stream->skip(stream->pos() * -1);        srs_freep(msg);        channel->msg = NULL;        return ERROR_SUCCESS;    }        // check the continuity counter    if (!is_fresh_msg) {        // late-incoming or duplicated continuity, drop message.        // @remark check overflow, the counter plus 1 should greater when invalid.        if (msg->continuity_counter >= packet->continuity_counter            && ((msg->continuity_counter + 1) & 0x0f) > packet->continuity_counter            ) {            srs_warn("ts: drop PES %dB for duplicated cc=%#x", msg->continuity_counter);            stream->skip(stream->size() - stream->pos());            return ret;        }                // when got partially message, the continous count must be continuous, or drop it.        if (((msg->continuity_counter + 1) & 0x0f) != packet->continuity_counter) {            ret = ERROR_STREAM_CASTER_TS_PSE;            srs_error("ts: continuity must be continous, msg=%#x, packet=%#x. ret=%d",                      msg->continuity_counter, packet->continuity_counter, ret);                        // reparse current msg.            stream->skip(stream->pos() * -1);            srs_freep(msg);            channel->msg = NULL;            return ERROR_SUCCESS;        }    }    msg->continuity_counter = packet->continuity_counter;        // for the PES_packet_length(0), reap when completed.    if (!is_fresh_msg && msg->completed(packet->payload_unit_start_indicator)) {        // reap previous PES packet.        *ppmsg = msg;        channel->msg = NULL;                // reparse current msg.        stream->skip(stream->pos() * -1);        return ret;    }        // contious packet, append bytes for unit start is 0    if (!packet->payload_unit_start_indicator) {        if ((ret = msg->dump(stream, &nb_bytes)) != ERROR_SUCCESS) {            return ret;        }    }        // when unit start, parse the fresh msg.    if (packet->payload_unit_start_indicator) {        // 6B fixed header.        if (!stream->require(6)) {            ret = ERROR_STREAM_CASTER_TS_PSE;            srs_error("ts: demux PSE failed. ret=%d", ret);            return ret;        }        // 3B        packet_start_code_prefix = stream->read_3bytes();        // 1B        stream_id = stream->read_1bytes();        // 2B        PES_packet_length = stream->read_2bytes();                // check the packet start prefix.        packet_start_code_prefix &= 0xFFFFFF;        if (packet_start_code_prefix != 0x01) {            ret = ERROR_STREAM_CASTER_TS_PSE;            srs_error("ts: demux PES start code failed, expect=0x01, actual=%#x. ret=%d", packet_start_code_prefix, ret);            return ret;        }        int pos_packet = stream->pos();                // @remark the sid indicates the elementary stream format.        //      the SrsTsPESStreamIdAudio and SrsTsPESStreamIdVideo is start by 0b110 or 0b1110        SrsTsPESStreamId sid = (SrsTsPESStreamId)stream_id;        msg->sid = sid;                if (sid != SrsTsPESStreamIdProgramStreamMap            && sid != SrsTsPESStreamIdPaddingStream            && sid != SrsTsPESStreamIdPrivateStream2            && sid != SrsTsPESStreamIdEcmStream            && sid != SrsTsPESStreamIdEmmStream            && sid != SrsTsPESStreamIdProgramStreamDirectory            && sid != SrsTsPESStreamIdDsmccStream            && sid != SrsTsPESStreamIdH2221TypeE            ) {            // 3B flags.            if (!stream->require(3)) {                ret = ERROR_STREAM_CASTER_TS_PSE;                srs_error("ts: demux PES flags failed. ret=%d", ret);                return ret;            }            // 1B            int8_t oocv = stream->read_1bytes();            // 1B            int8_t pefv = stream->read_1bytes();            // 1B            PES_header_data_length = stream->read_1bytes();            // position of header start.            int pos_header = stream->pos();                        const2bits = (oocv >> 6) & 0x03;            PES_scrambling_control = (oocv >> 4) & 0x03;            PES_priority = (oocv >> 3) & 0x01;            data_alignment_indicator = (oocv >> 2) & 0x01;            copyright = (oocv >> 1) & 0x01;            original_or_copy = oocv & 0x01;                        PTS_DTS_flags = (pefv >> 6) & 0x03;            ESCR_flag = (pefv >> 5) & 0x01;            ES_rate_flag = (pefv >> 4) & 0x01;            DSM_trick_mode_flag = (pefv >> 3) & 0x01;            additional_copy_info_flag = (pefv >> 2) & 0x01;            PES_CRC_flag = (pefv >> 1) & 0x01;            PES_extension_flag = pefv & 0x01;                        // check required together.            int nb_required = 0;            nb_required += (PTS_DTS_flags == 0x2)? 5:0;            nb_required += (PTS_DTS_flags == 0x3)? 10:0;            nb_required += ESCR_flag? 6:0;            nb_required += ES_rate_flag? 3:0;            nb_required += DSM_trick_mode_flag? 1:0;            nb_required += additional_copy_info_flag? 1:0;            nb_required += PES_CRC_flag? 2:0;            nb_required += PES_extension_flag? 1:0;            if (!stream->require(nb_required)) {                ret = ERROR_STREAM_CASTER_TS_PSE;                srs_error("ts: demux PES payload failed. ret=%d", ret);                return ret;            }                        // 5B            if (PTS_DTS_flags == 0x2) {                if ((ret = decode_33bits_dts_pts(stream, &pts)) != ERROR_SUCCESS) {                    return ret;                }                dts = pts;                                // update the dts and pts of message.                msg->dts = dts;                msg->pts = pts;            }                        // 10B            if (PTS_DTS_flags == 0x3) {                if ((ret = decode_33bits_dts_pts(stream, &pts)) != ERROR_SUCCESS) {                    return ret;                }                if ((ret = decode_33bits_dts_pts(stream, &dts)) != ERROR_SUCCESS) {                    return ret;                }                                // check sync, the diff of dts and pts should never greater than 1s.                if (dts - pts > 90000 || pts - dts > 90000) {                    srs_warn("ts: sync dts=%" PRId64 ", pts=%" PRId64, dts, pts);                }                                // update the dts and pts of message.                msg->dts = dts;                msg->pts = pts;            }                        // 6B            if (ESCR_flag) {                ESCR_extension = 0;                ESCR_base = 0;                                stream->skip(6);                srs_warn("ts: demux PES, ignore the escr.");            }                        // 3B            if (ES_rate_flag) {                ES_rate = stream->read_3bytes();                                ES_rate = ES_rate >> 1;                ES_rate &= 0x3FFFFF;            }                        // 1B            if (DSM_trick_mode_flag) {                trick_mode_control = stream->read_1bytes();                                trick_mode_value = trick_mode_control & 0x1f;                trick_mode_control = (trick_mode_control >> 5) & 0x03;            }                        // 1B            if (additional_copy_info_flag) {                additional_copy_info = stream->read_1bytes();                                additional_copy_info &= 0x7f;            }                        // 2B            if (PES_CRC_flag) {                previous_PES_packet_CRC = stream->read_2bytes();            }                        // 1B            if (PES_extension_flag) {                int8_t efv = stream->read_1bytes();                                PES_private_data_flag = (efv >> 7) & 0x01;                pack_header_field_flag = (efv >> 6) & 0x01;                program_packet_sequence_counter_flag = (efv >> 5) & 0x01;                P_STD_buffer_flag = (efv >> 4) & 0x01;                const1_value0 = (efv >> 1) & 0x07;                PES_extension_flag_2 = efv & 0x01;                                nb_required = 0;                nb_required += PES_private_data_flag? 16:0;                nb_required += pack_header_field_flag? 1:0; // 1+x bytes.                nb_required += program_packet_sequence_counter_flag? 2:0;                nb_required += P_STD_buffer_flag? 2:0;                nb_required += PES_extension_flag_2? 1:0; // 1+x bytes.                if (!stream->require(nb_required)) {                    ret = ERROR_STREAM_CASTER_TS_PSE;                    srs_error("ts: demux PSE ext payload failed. ret=%d", ret);                    return ret;                }                                // 16B                if (PES_private_data_flag) {                    PES_private_data.resize(16);                    stream->read_bytes(&PES_private_data[0], 16);                }                                // (1+x)B                if (pack_header_field_flag) {                    // This is an 8-bit field which indicates the length, in bytes, of the pack_header_field()                    uint8_t pack_field_length = stream->read_1bytes();                    if (pack_field_length > 0) {                        // the adjust required bytes.                        nb_required = nb_required - 16 - 1 + pack_field_length;                        if (!stream->require(nb_required)) {                            ret = ERROR_STREAM_CASTER_TS_PSE;                            srs_error("ts: demux PSE ext pack failed. ret=%d", ret);                            return ret;                        }                        pack_field.resize(pack_field_length);                        stream->read_bytes(&pack_field[0], pack_field_length);                    }                }                                // 2B                if (program_packet_sequence_counter_flag) {                    program_packet_sequence_counter = stream->read_1bytes();                    program_packet_sequence_counter &= 0x7f;                                        original_stuff_length = stream->read_1bytes();                    MPEG1_MPEG2_identifier = (original_stuff_length >> 6) & 0x01;                    original_stuff_length &= 0x3f;                }                                // 2B                if (P_STD_buffer_flag) {                    P_STD_buffer_size = stream->read_2bytes();                                        // '01'                    //int8_t const2bits = (P_STD_buffer_scale >>14) & 0x03;                                        P_STD_buffer_scale = (P_STD_buffer_scale >>13) & 0x01;                    P_STD_buffer_size &= 0x1FFF;                }                                // (1+x)B                if (PES_extension_flag_2) {                    /**                     * This is a 7-bit field which specifies the length, in bytes, of the data following this field in                     * the PES extension field up to and including any reserved bytes.                     */                    uint8_t PES_extension_field_length = stream->read_1bytes();                    PES_extension_field_length &= 0x7F;                                        if (PES_extension_field_length > 0) {                        if (!stream->require(PES_extension_field_length)) {                            ret = ERROR_STREAM_CASTER_TS_PSE;                            srs_error("ts: demux PSE ext field failed. ret=%d", ret);                            return ret;                        }                        PES_extension_field.resize(PES_extension_field_length);                        stream->read_bytes(&PES_extension_field[0], PES_extension_field_length);                    }                }            }                        // stuffing_byte            nb_stuffings = PES_header_data_length - (stream->pos() - pos_header);            if (nb_stuffings > 0) {                if (!stream->require(nb_stuffings)) {                    ret = ERROR_STREAM_CASTER_TS_PSE;                    srs_error("ts: demux PSE stuffings failed. ret=%d", ret);                    return ret;                }                stream->skip(nb_stuffings);            }                        // PES_packet_data_byte, page58.            // the packet size contains the header size.            // 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.            /**             * when actual packet length > 0xffff(65535),             * which exceed the max uint16_t packet length,             * use 0 packet length, the next unit start indicates the end of packet.             */            if (PES_packet_length > 0) {                int nb_packet = PES_packet_length - (stream->pos() - pos_packet);                msg->PES_packet_length = srs_max(0, nb_packet);            }                        // xB            if ((ret = msg->dump(stream, &nb_bytes)) != ERROR_SUCCESS) {                return ret;            }        } else if (sid == SrsTsPESStreamIdProgramStreamMap                   || sid == SrsTsPESStreamIdPrivateStream2                   || sid == SrsTsPESStreamIdEcmStream                   || sid == SrsTsPESStreamIdEmmStream                   || sid == SrsTsPESStreamIdProgramStreamDirectory                   || sid == SrsTsPESStreamIdDsmccStream                   || sid == SrsTsPESStreamIdH2221TypeE                   ) {            // for (i = 0; i < PES_packet_length; i++) {            //         PES_packet_data_byte            // }                        // xB            if ((ret = msg->dump(stream, &nb_bytes)) != ERROR_SUCCESS) {                return ret;            }        } else if (sid == SrsTsPESStreamIdPaddingStream) {            // for (i = 0; i < PES_packet_length; i++) {            //         padding_byte            // }            nb_paddings = stream->size() - stream->pos();            stream->skip(nb_paddings);            srs_info("ts: drop %dB padding bytes", nb_paddings);        } else {            int nb_drop = stream->size() - stream->pos();            stream->skip(nb_drop);            srs_warn("ts: drop the pes packet %dB for stream_id=%#x", nb_drop, stream_id);        }    }        // when fresh and the PES_packet_length is 0,    // the payload_unit_start_indicator always be 1,    // the message should never EOF for the first packet.    if (is_fresh_msg && msg->PES_packet_length == 0) {        return ret;    }        // check msg, reap when completed.    if (msg->completed(packet->payload_unit_start_indicator)) {        *ppmsg = msg;        channel->msg = NULL;        srs_info("ts: reap msg for completed.");    }        return ret;}
该函数通过SrsTsContext::get函数获取记录的SrsTsChannel,解析后的数据就放在SrsTsChannel::msg中。

pts,dts也会被解析记录到msg中。

发送视频时帧会超过188字节,因此一帧数据会被拆成多个PES包发送,因此接收到PES包的数据时就需要根据continuity_counter将解析后的数据重新组装成一个视频帧。






































if (adaption_field_control == SrsTsAdaptationFieldTypeAdaptionOnly || adaption_field_control == SrsTsAdaptationFieldTypeBoth)

原创粉丝点击