static void mpegts_write_pes(AVFormatContext *s, AVStream *st,

                             const uint8_t *payload, int payload_size,

                             int64_t pts, int64_t dts, int key, int stream_id)

{

    MpegTSWriteStream *ts_st = st->priv_data;

    MpegTSWrite *ts = s->priv_data;

    uint8_t buf[TS_PACKET_SIZE];

    uint8_t *q;

    int val, is_start, len, header_len, write_pcr, is_dvb_subtitle, is_dvb_teletext, flags;

    int afc_len, stuffing_len;

    int64_t pcr = -1; 

    int64_t delay = av_rescale(s->max_delay, 90000, AV_TIME_BASE);

    int force_pat = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && key && !ts_st->prev_payload_key;



    av_assert0(ts_st->payload != buf || st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO);

    if (ts->flags & MPEGTS_FLAG_PAT_PMT_AT_FRAMES && st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {

        force_pat = 1;




    is_start = 1;

    while (payload_size > 0) {

        retransmit_si_info(s, force_pat, dts);

        force_pat = 0;



        write_pcr = 0;

        if (ts_st->pid == ts_st->service->pcr_pid) {

            if (ts->mux_rate > 1 || is_start) 

                ts_st->service->pcr_packet_count++;

            if (ts_st->service->pcr_packet_count >=

                ts_st->service->pcr_packet_period) {

                ts_st->service->pcr_packet_count = 0;

                write_pcr = 1;





        if (ts->mux_rate > 1 && dts != AV_NOPTS_VALUE &&

            (dts - get_pcr(ts, s->pb) / 300) > delay) {

            

            if (write_pcr)

                mpegts_insert_pcr_only(s, st);

            else

                mpegts_insert_null_packet(s);

            

            continue;




        

        q    = buf;

        *q++ = 0x47;

        val  = ts_st->pid >> 8;

        if (is_start)

            val |= 0x40;

        *q++      = val;

        *q++      = ts_st->pid;

        ts_st->cc = ts_st->cc + 1 & 0xf;

        *q++      = 0x10 | ts_st->cc; 






        if (key && is_start && pts != AV_NOPTS_VALUE) {

            

            if (ts_st->pid == ts_st->service->pcr_pid)

                write_pcr = 1;

            set_af_flag(buf, 0x40);



        if (write_pcr) {

            set_af_flag(buf, 0x10);


            

            if (ts->mux_rate > 1)

                pcr = get_pcr(ts, s->pb);

            else

                pcr = (dts - delay) * 300;

            if (dts != AV_NOPTS_VALUE && dts < pcr / 300)

                av_log(s, AV_LOG_WARNING, "dts < pcr, TS is invalid\n");

            extend_af(buf, write_pcr_bits(q, pcr));



        if (is_start) {

            int pes_extension = 0;

            int pes_header_stuffing_bytes = 0;

            

            *q++ = 0x00;

            *q++ = 0x00;

            *q++ = 0x01;

            is_dvb_subtitle = 0;

            is_dvb_teletext = 0;

            if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {

                if (st->codecpar->codec_id == AV_CODEC_ID_DIRAC)

                    *q++ = 0xfd;

                else

                    *q++ = 0xe0;

            } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&

                       (st->codecpar->codec_id == AV_CODEC_ID_MP2 ||

                        st->codecpar->codec_id == AV_CODEC_ID_MP3 ||

                        st->codecpar->codec_id == AV_CODEC_ID_AAC)) {

                *q++ = 0xc0;

            } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&

                        st->codecpar->codec_id == AV_CODEC_ID_AC3 &&

                        ts->m2ts_mode) {

                *q++ = 0xfd;

            } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA &&

                       st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {

                *q++ = 0xbd;

            } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {

                *q++ = stream_id != -1 ? stream_id : 0xfc;



                if (stream_id == 0xbd) 

                    pts = dts = AV_NOPTS_VALUE;

            } else {

                *q++ = 0xbd;

                if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {

                    if (st->codecpar->codec_id == AV_CODEC_ID_DVB_SUBTITLE) {

                        is_dvb_subtitle = 1;

                    } else if (st->codecpar->codec_id == AV_CODEC_ID_DVB_TELETEXT) {

                        is_dvb_teletext = 1;




            header_len = 0;

            flags      = 0;

            if (pts != AV_NOPTS_VALUE) {

                header_len += 5;

                flags      |= 0x80;


            if (dts != AV_NOPTS_VALUE && pts != AV_NOPTS_VALUE && dts != pts) {

                header_len += 5;

                flags      |= 0x40;


            if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&

                st->codecpar->codec_id == AV_CODEC_ID_DIRAC) {

                

                pes_extension = 1;

                flags        |= 0x01;



                





                header_len += 3;


            





            if (ts->m2ts_mode &&

                st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&

                st->codecpar->codec_id == AV_CODEC_ID_AC3) {

                        

                        pes_extension = 1;

                        flags |= 0x01;

                        header_len += 3;


            if (is_dvb_teletext) {

                pes_header_stuffing_bytes = 0x24 - header_len;

                header_len = 0x24;


            len = payload_size + header_len + 3;

            

            if (is_dvb_subtitle) {

                len += 3;

                payload_size++;


            if (len > 0xffff)

                len = 0;

            if (ts->omit_video_pes_length && st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {

                len = 0;


            *q++ = len >> 8;

            *q++ = len;

            val  = 0x80;

            

            if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE || st->codecpar->codec_type == AVMEDIA_TYPE_DATA)

                val |= 0x04;

            *q++ = val;

            *q++ = flags;

            *q++ = header_len;

            if (pts != AV_NOPTS_VALUE) {

                write_pts(q, flags >> 6, pts);

                q += 5;


            if (dts != AV_NOPTS_VALUE && pts != AV_NOPTS_VALUE && dts != pts) {

                write_pts(q, 1, dts);

                q += 5;


            if (pes_extension && st->codecpar->codec_id == AV_CODEC_ID_DIRAC) {

                flags = 0x01;  

                *q++  = flags;

                *q++  = 0x80 | 0x01; 

                



                *q++ = 0x00 | 0x60;


            

          if (ts->m2ts_mode &&

              pes_extension &&

              st->codecpar->codec_id == AV_CODEC_ID_AC3) {

                      flags = 0x01; 

                      *q++ = flags;

                      *q++ = 0x80 | 0x01; 

                      *q++ = 0x00 | 0x71; 






            if (is_dvb_subtitle) {

                





                *q++ = 0x20;

                *q++ = 0x00;


            if (is_dvb_teletext) {

                memset(q, 0xff, pes_header_stuffing_bytes);

                q += pes_header_stuffing_bytes;


            is_start = 0;


        

        header_len = q - buf;

        

        len = TS_PACKET_SIZE - header_len;

        if (len > payload_size)

            len = payload_size;

        stuffing_len = TS_PACKET_SIZE - header_len - len;

        if (stuffing_len > 0) {

            

            if (buf[3] & 0x20) {

                

                afc_len = buf[4] + 1;

                memmove(buf + 4 + afc_len + stuffing_len,

                        buf + 4 + afc_len,

                        header_len - (4 + afc_len));

                buf[4] += stuffing_len;

                memset(buf + 4 + afc_len, 0xff, stuffing_len);

            } else {

                

                memmove(buf + 4 + stuffing_len, buf + 4, header_len - 4);

                buf[3] |= 0x20;

                buf[4]  = stuffing_len - 1;

                if (stuffing_len >= 2) {

                    buf[5] = 0x00;

                    memset(buf + 6, 0xff, stuffing_len - 2);






        if (is_dvb_subtitle && payload_size == len) {

            memcpy(buf + TS_PACKET_SIZE - len, payload, len - 1);

            buf[TS_PACKET_SIZE - 1] = 0xff; 

        } else {

            memcpy(buf + TS_PACKET_SIZE - len, payload, len);




        payload      += len;

        payload_size -= len;

        mpegts_prefix_m2ts_header(s);

        avio_write(s->pb, buf, TS_PACKET_SIZE);


    ts_st->prev_payload_key = key;
