From 1ed3e283abd9a79f19d607779921e03dbe5caaf7 Mon Sep 17 00:00:00 2001
From: winlin <winlin@vip.126.com>
Date: Sat, 14 Feb 2015 23:06:01 +0800
Subject: [PATCH] implements the pat/pmt write ts header.

---
 trunk/src/kernel/srs_kernel_ts.cpp | 785 +++++++++++++++++++++++++----
 trunk/src/kernel/srs_kernel_ts.hpp | 131 ++++-
 2 files changed, 802 insertions(+), 114 deletions(-)

diff --git a/trunk/src/kernel/srs_kernel_ts.cpp b/trunk/src/kernel/srs_kernel_ts.cpp
index 35c116dc2..9a8278c84 100644
--- a/trunk/src/kernel/srs_kernel_ts.cpp
+++ b/trunk/src/kernel/srs_kernel_ts.cpp
@@ -517,6 +517,8 @@ ISrsTsHandler::~ISrsTsHandler()
 
 SrsTsContext::SrsTsContext()
 {
+    vcodec = SrsCodecVideoReserved;
+    acodec = SrsCodecAudioReserved1;
 }
 
 SrsTsContext::~SrsTsContext()
@@ -529,6 +531,30 @@ SrsTsContext::~SrsTsContext()
     pids.clear();
 }
 
+SrsTsChannel* SrsTsContext::get(int pid)
+{
+    if (pids.find(pid) == pids.end()) {
+        return NULL;
+    }
+    return pids[pid];
+}
+
+void SrsTsContext::set(int pid, SrsTsPidApply apply_pid, SrsTsStream stream)
+{
+    SrsTsChannel* channel = NULL;
+
+    if (pids.find(pid) == pids.end()) {
+        channel = new SrsTsChannel();
+        pids[pid] = channel;
+    } else {
+        channel = pids[pid];
+    }
+
+    channel->pid = pid;
+    channel->apply = apply_pid;
+    channel->stream = stream;
+}
+
 int SrsTsContext::decode(SrsStream* stream, ISrsTsHandler* handler)
 {
     int ret = ERROR_SUCCESS;
@@ -559,28 +585,122 @@ int SrsTsContext::decode(SrsStream* stream, ISrsTsHandler* handler)
     return ret;
 }
 
-SrsTsChannel* SrsTsContext::get(int pid)
+int SrsTsContext::encode(SrsFileWriter* writer, SrsMpegtsFrame* frame, SrsSimpleBuffer* payload, SrsCodecVideo vc, SrsCodecAudio ac)
 {
-    if (pids.find(pid) == pids.end()) {
-        return NULL;
+    int ret = ERROR_SUCCESS;
+    
+    // when any codec changed, write PAT/PMT table.
+    if (vcodec != vc || acodec != ac) {
+        vcodec = vc;
+        acodec = ac;
+        if ((ret = encode_pat_pmt(writer, vc, ac)) != ERROR_SUCCESS) {
+            return ret;
+        }
     }
-    return pids[pid];
+
+    // encode the media frame to PES packets over TS.
+    return encode_pes(writer, frame, payload);
 }
 
-void SrsTsContext::set(int pid, SrsTsPidApply apply_pid, SrsTsStream stream)
+int SrsTsContext::encode_pat_pmt(SrsFileWriter* writer, SrsCodecVideo vc, SrsCodecAudio ac)
 {
-    SrsTsChannel* channel = NULL;
+    int ret = ERROR_SUCCESS;
 
-    if (pids.find(pid) == pids.end()) {
-        channel = new SrsTsChannel();
-        pids[pid] = channel;
-    } else {
-        channel = pids[pid];
+    SrsTsStream vs = SrsTsStreamReserved;
+    SrsTsStream as = SrsTsStreamReserved;
+    switch (vc) {
+        case SrsCodecVideoAVC: vs = SrsTsStreamVideoH264; break;
+        case SrsCodecVideoReserved:
+        case SrsCodecVideoReserved1:
+        case SrsCodecVideoReserved2:
+        case SrsCodecVideoSorensonH263:
+        case SrsCodecVideoScreenVideo:
+        case SrsCodecVideoOn2VP6:
+        case SrsCodecVideoOn2VP6WithAlphaChannel:
+        case SrsCodecVideoScreenVideoVersion2:
+            break;
+    }
+    switch (ac) {
+        case SrsCodecAudioAAC: as = SrsTsStreamAudioAAC; break;
+        case SrsCodecAudioMP3: as = SrsTsStreamAudioMp3; break;
+        case SrsCodecAudioReserved1:
+        case SrsCodecAudioLinearPCMPlatformEndian:
+        case SrsCodecAudioADPCM:
+        case SrsCodecAudioLinearPCMLittleEndian:
+        case SrsCodecAudioNellymoser16kHzMono:
+        case SrsCodecAudioNellymoser8kHzMono:
+        case SrsCodecAudioNellymoser:
+        case SrsCodecAudioReservedG711AlawLogarithmicPCM:
+        case SrsCodecAudioReservedG711MuLawLogarithmicPCM:
+        case SrsCodecAudioReserved:
+        case SrsCodecAudioSpeex:
+        case SrsCodecAudioReservedMP3_8kHz:
+        case SrsCodecAudioReservedDeviceSpecificSound:
+            break;
+    }
+
+    int16_t pmt_number = 1;
+    int16_t pmt_pid = 0x100;
+    if (true) {
+        SrsTsPacket* pkt = SrsTsPacket::create_pat(this, pmt_number, pmt_pid);
+        SrsAutoFree(SrsTsPacket, pkt);
+
+        char* buf = new char[SRS_TS_PACKET_SIZE];
+        SrsAutoFree(char, buf);
+
+        // set the left bytes with 0xFF.
+        int nb_buf = pkt->size();
+        srs_assert(nb_buf < SRS_TS_PACKET_SIZE);
+        memset(buf + nb_buf, 0xFF, SRS_TS_PACKET_SIZE - nb_buf);
+
+        SrsStream stream;
+        if ((ret = stream.initialize(buf, nb_buf)) != ERROR_SUCCESS) {
+            return ret;
+        }
+        if ((ret = pkt->encode(&stream)) != ERROR_SUCCESS) {
+            srs_error("ts encode ts packet failed. ret=%d", ret);
+            return ret;
+        }
+        if ((ret = writer->write(buf, SRS_TS_PACKET_SIZE, NULL)) != ERROR_SUCCESS) {
+            srs_error("ts write ts packet failed. ret=%d", ret);
+            return ret;
+        }
     }
+    int16_t video_pid = 0x101;
+    int16_t audio_pid = 0x102;
+    if (true) {
+        SrsTsPacket* pkt = SrsTsPacket::create_pmt(this, pmt_number, pmt_pid, video_pid, vs, audio_pid, as);
+        SrsAutoFree(SrsTsPacket, pkt);
 
-    channel->pid = pid;
-    channel->apply = apply_pid;
-    channel->stream = stream;
+        char* buf = new char[SRS_TS_PACKET_SIZE];
+        SrsAutoFree(char, buf);
+
+        // set the left bytes with 0xFF.
+        int nb_buf = pkt->size();
+        srs_assert(nb_buf < SRS_TS_PACKET_SIZE);
+        memset(buf + nb_buf, 0xFF, SRS_TS_PACKET_SIZE - nb_buf);
+
+        SrsStream stream;
+        if ((ret = stream.initialize(buf, nb_buf)) != ERROR_SUCCESS) {
+            return ret;
+        }
+        if ((ret = pkt->encode(&stream)) != ERROR_SUCCESS) {
+            srs_error("ts encode ts packet failed. ret=%d", ret);
+            return ret;
+        }
+        if ((ret = writer->write(buf, SRS_TS_PACKET_SIZE, NULL)) != ERROR_SUCCESS) {
+            srs_error("ts write ts packet failed. ret=%d", ret);
+            return ret;
+        }
+    }
+
+    return ret;
+}
+
+int SrsTsContext::encode_pes(SrsFileWriter* writer, SrsMpegtsFrame* frame, SrsSimpleBuffer* payload)
+{
+    int ret = ERROR_SUCCESS;
+    return ret;
 }
 
 SrsTsPacket::SrsTsPacket(SrsTsContext* c)
@@ -688,6 +808,126 @@ int SrsTsPacket::decode(SrsStream* stream, SrsTsMessage** ppmsg)
     return ret;
 }
 
+int SrsTsPacket::size()
+{
+    int sz = 4;
+    
+    sz += adaptation_field? adaptation_field->size() : 0;
+    sz += payload? payload->size() : 0;
+
+    return sz;
+}
+
+int SrsTsPacket::encode(SrsStream* stream)
+{
+    int ret = ERROR_SUCCESS;
+
+    // 4B ts packet header.
+    if (!stream->require(4)) {
+        ret = ERROR_STREAM_CASTER_TS_HEADER;
+        srs_error("ts: mux header failed. ret=%d", ret);
+        return ret;
+    }
+
+    stream->write_1bytes(sync_byte);
+
+    int16_t pidv = pid & 0x1FFF;
+    pidv |= (transport_priority << 13) & 0x2000;
+    pidv |= (transport_error_indicator << 15) & 0x8000;
+    pidv |= (payload_unit_start_indicator << 14) & 0x4000;
+    stream->write_2bytes(pidv);
+
+    int8_t ccv = continuity_counter & 0x0F;
+    ccv |= (transport_scrambling_control << 6) & 0xC0;
+    ccv |= (adaption_field_control << 4) & 0x30;
+    stream->write_1bytes(ccv);
+    
+    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 (adaptation_field) {
+        if ((ret = adaptation_field->encode(stream)) != ERROR_SUCCESS) {
+            srs_error("ts: mux af faield. ret=%d", ret);
+            return ret;
+        }
+        srs_verbose("ts: mux af ok.");
+    }
+
+    // optional: payload.
+    if (payload) {
+        if ((ret = payload->encode(stream)) != ERROR_SUCCESS) {
+            srs_error("ts: mux payload failed. ret=%d", ret);
+            return ret;
+        }
+        srs_verbose("ts: mux payload ok.");
+    }
+
+    return ret;
+}
+
+SrsTsPacket* SrsTsPacket::create_pat(SrsTsContext* context, int16_t pmt_number, int16_t pmt_pid)
+{
+    SrsTsPacket* pkt = new SrsTsPacket(context);
+    pkt->sync_byte = 0x47;
+    pkt->transport_error_indicator = 0;
+    pkt->payload_unit_start_indicator = 1;
+    pkt->transport_priority = 0;
+    pkt->pid = SrsTsPidPAT;
+    pkt->transport_scrambling_control = SrsTsScrambledDisabled;
+    pkt->adaption_field_control = SrsTsAdaptationFieldTypePayloadOnly;
+    pkt->continuity_counter = 0;
+    pkt->adaptation_field = NULL;
+    SrsTsPayloadPAT* pat = new SrsTsPayloadPAT(pkt);
+    pkt->payload = pat;
+
+    pat->pointer_field = 0;
+    pat->table_id = SrsTsPsiIdPas;
+    pat->section_syntax_indicator = 1;
+    pat->section_length = 0; // calc in size.
+    pat->transport_stream_id = 1;
+    pat->version_number = 0;
+    pat->current_next_indicator = 1;
+    pat->section_number = 0;
+    pat->last_section_number = 0;
+    pat->programs.push_back(new SrsTsPayloadPATProgram(pmt_number, pmt_pid));
+    pat->CRC_32 = 0; // calc in encode.
+    return pkt;
+}
+
+SrsTsPacket* SrsTsPacket::create_pmt(SrsTsContext* context, int16_t pmt_number, int16_t pmt_pid, int16_t vpid, SrsTsStream vs, int16_t apid, SrsTsStream as)
+{
+    SrsTsPacket* pkt = new SrsTsPacket(context);
+    pkt->sync_byte = 0x47;
+    pkt->transport_error_indicator = 0;
+    pkt->payload_unit_start_indicator = 1;
+    pkt->transport_priority = 0;
+    pkt->pid = (SrsTsPid)pmt_pid;
+    pkt->transport_scrambling_control = SrsTsScrambledDisabled;
+    pkt->adaption_field_control = SrsTsAdaptationFieldTypePayloadOnly;
+    pkt->continuity_counter = 0;
+    pkt->adaptation_field = NULL;
+    SrsTsPayloadPMT* pmt = new SrsTsPayloadPMT(pkt);
+    pkt->payload = pmt;
+
+    pmt->pointer_field = 0;
+    pmt->table_id = SrsTsPsiIdPms;
+    pmt->section_syntax_indicator = 1;
+    pmt->section_length = 0; // calc in size.
+    pmt->program_number = pmt_number;
+    pmt->version_number = 0;
+    pmt->current_next_indicator = 1;
+    pmt->section_number = 0;
+    pmt->last_section_number = 0;
+    pmt->PCR_PID = vpid;
+    pmt->program_info_length = 0;
+    pmt->infos.push_back(new SrsTsPayloadPMTESInfo(vs, vpid));
+    pmt->infos.push_back(new SrsTsPayloadPMTESInfo(as, apid));
+    pmt->CRC_32 = 0; // calc in encode.
+    return pkt;
+}
+
 SrsTsAdaptationField::SrsTsAdaptationField(SrsTsPacket* pkt)
 {
     packet = pkt;
@@ -929,6 +1169,27 @@ int SrsTsAdaptationField::decode(SrsStream* stream)
     return ret;
 }
 
+int SrsTsAdaptationField::size()
+{
+    int sz = 2;
+
+    sz += PCR_flag? 6 : 0;
+    sz += OPCR_flag? 6 : 0;
+    sz += splicing_point_flag? 1 : 0;
+    sz += transport_private_data_flag? 1 + transport_private_data_length : 0;
+    sz += adaptation_field_extension_flag? 2 + adaptation_field_extension_length : 0;
+    sz += nb_af_ext_reserved;
+    sz += nb_af_reserved;
+
+    return sz;
+}
+
+int SrsTsAdaptationField::encode(SrsStream* stream)
+{
+    int ret = ERROR_SUCCESS;
+    return ret;
+}
+
 SrsTsPayload::SrsTsPayload(SrsTsPacket* p)
 {
     packet = p;
@@ -1356,6 +1617,65 @@ int SrsTsPayloadPES::decode(SrsStream* stream, SrsTsMessage** ppmsg)
     return ret;
 }
 
+int SrsTsPayloadPES::size()
+{
+    int sz = 6;
+    
+    SrsTsPESStreamId sid = (SrsTsPESStreamId)stream_id;
+
+    if (sid != SrsTsPESStreamIdProgramStreamMap
+        && sid != SrsTsPESStreamIdPaddingStream
+        && sid != SrsTsPESStreamIdPrivateStream2
+        && sid != SrsTsPESStreamIdEcmStream
+        && sid != SrsTsPESStreamIdEmmStream
+        && sid != SrsTsPESStreamIdProgramStreamDirectory
+        && sid != SrsTsPESStreamIdDsmccStream
+        && sid != SrsTsPESStreamIdH2221TypeE
+    ) {
+        sz += 3;
+
+        sz += (PTS_DTS_flags == 0x2)? 5:0;
+        sz += (PTS_DTS_flags == 0x3)? 10:0;
+        sz += ESCR_flag? 6:0;
+        sz += ES_rate_flag? 3:0;
+        sz += DSM_trick_mode_flag? 1:0;
+        sz += additional_copy_info_flag? 1:0;
+        sz += PES_CRC_flag? 2:0;
+        sz += PES_extension_flag? 1:0;
+
+        if (PES_extension_flag) {
+            sz += PES_private_data_flag? 16:0;
+            sz += pack_header_field_flag? 1 + pack_field_length:0; // 1+x bytes.
+            sz += program_packet_sequence_counter_flag? 2:0;
+            sz += P_STD_buffer_flag? 2:0;
+            sz += PES_extension_flag_2? 1 + PES_extension_field_length:0; // 1+x bytes.
+        }
+
+        sz += nb_stuffings;
+
+        // packet bytes
+    } else if (sid == SrsTsPESStreamIdProgramStreamMap
+        || sid == SrsTsPESStreamIdPrivateStream2
+        || sid == SrsTsPESStreamIdEcmStream
+        || sid == SrsTsPESStreamIdEmmStream
+        || sid == SrsTsPESStreamIdProgramStreamDirectory
+        || sid == SrsTsPESStreamIdDsmccStream
+        || sid == SrsTsPESStreamIdH2221TypeE
+    ) {
+        // packet bytes
+    } else {
+        // nb_drop
+    }
+
+    return sz;
+}
+
+int SrsTsPayloadPES::encode(SrsStream* stream)
+{
+    int ret = ERROR_SUCCESS;
+    return ret;
+}
+
 int SrsTsPayloadPES::decode_33bits_dts_pts(SrsStream* stream, int64_t* pv)
 {
     int ret = ERROR_SUCCESS;
@@ -1420,6 +1740,8 @@ int SrsTsPayloadPES::decode_33bits_dts_pts(SrsStream* stream, int64_t* pv)
 SrsTsPayloadPSI::SrsTsPayloadPSI(SrsTsPacket* p) : SrsTsPayload(p)
 {
     pointer_field = 0;
+    const0_value = 0;
+    const1_value = 3;
     CRC_32 = 0;
 }
 
@@ -1462,11 +1784,12 @@ int SrsTsPayloadPSI::decode(SrsStream* stream, SrsTsMessage** /*ppmsg*/)
     table_id = (SrsTsPsiId)stream->read_1bytes();
     
     // 2B
-    section_length = stream->read_2bytes();
+    int16_t slv = stream->read_2bytes();
     
-    section_syntax_indicator = (section_length >> 15) & 0x01;
-    const0_value = (section_length >> 14) & 0x01;
-    section_length &= 0x0FFF;
+    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) {
@@ -1521,18 +1844,139 @@ int SrsTsPayloadPSI::decode(SrsStream* stream, SrsTsMessage** /*ppmsg*/)
     return ret;
 }
 
-SrsTsPayloadPATProgram::SrsTsPayloadPATProgram()
+int SrsTsPayloadPSI::size()
 {
-    number = 0;
-    pid = 0;
+    int sz = 0;
+
+    // section size is the sl plus the crc32
+    section_length = psi_size() + 4;
+
+     sz += packet->payload_unit_start_indicator? 1:0;
+     sz += 3;
+     sz += section_length;
+
+    return sz;
+}
+
+int SrsTsPayloadPSI::encode(SrsStream* stream)
+{
+    int ret = ERROR_SUCCESS;
+
+    if (packet->payload_unit_start_indicator) {
+        if (!stream->require(1)) {
+            ret = ERROR_STREAM_CASTER_TS_PSI;
+            srs_error("ts: mux PSI failed. ret=%d", ret);
+            return ret;
+        }
+        stream->write_1bytes(pointer_field);
+    }
+
+    // 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: mux PSI failed. ret=%d", ret);
+        return ret;
+    }
+    // 1B
+    stream->write_1bytes(table_id);
+    
+    // 2B
+    int16_t slv = section_length & 0x0FFF;
+    slv |= (section_syntax_indicator << 15) & 0x8000;
+    slv |= (const0_value << 14) & 0x4000;
+    slv |= (const1_value << 12) & 0x3000;
+    stream->write_2bytes(slv);
+
+    // no section, ignore.
+    if (section_length == 0) {
+        srs_warn("ts: mux PAT ignore empty section");
+        return ret;
+    }
+
+    if (!stream->require(section_length)) {
+        ret = ERROR_STREAM_CASTER_TS_PSI;
+        srs_error("ts: mux PAT section failed. ret=%d", ret);
+        return ret;
+    }
+
+    // call the virtual method of actual PSI.
+    if ((ret = psi_encode(stream)) != ERROR_SUCCESS) {
+        return ret;
+    }
+    
+    // 4B
+    if (!stream->require(4)) {
+        ret = ERROR_STREAM_CASTER_TS_PSI;
+        srs_error("ts: mux PSI crc32 failed. ret=%d", ret);
+        return ret;
+    }
+    CRC_32 = srs_crc32(ppat, stream->pos() - pat_pos);
+    stream->write_4bytes(CRC_32);
+
+    return ret;
+}
+
+SrsTsPayloadPATProgram::SrsTsPayloadPATProgram(int16_t n, int16_t p)
+{
+    number = n;
+    pid = p;
+    const1_value = 0x07;
 }
 
 SrsTsPayloadPATProgram::~SrsTsPayloadPATProgram()
 {
 }
 
+int SrsTsPayloadPATProgram::decode(SrsStream* stream)
+{
+    int ret = ERROR_SUCCESS;
+
+    // atleast 4B for PAT program specified
+    if (!stream->require(4)) {
+        ret = ERROR_STREAM_CASTER_TS_PAT;
+        srs_error("ts: demux PAT failed. ret=%d", ret);
+        return ret;
+    }
+
+    int tmpv = stream->read_4bytes();
+    number = (int16_t)((tmpv >> 16) & 0xFFFF);
+    const1_value = (int16_t)((tmpv >> 13) & 0x07);
+    pid = (int16_t)(tmpv & 0x1FFF);
+
+    return ret;
+}
+
+int SrsTsPayloadPATProgram::size()
+{
+    return 4;
+}
+
+int SrsTsPayloadPATProgram::encode(SrsStream* stream)
+{
+    int ret = ERROR_SUCCESS;
+
+    // atleast 4B for PAT program specified
+    if (!stream->require(4)) {
+        ret = ERROR_STREAM_CASTER_TS_PAT;
+        srs_error("ts: mux PAT failed. ret=%d", ret);
+        return ret;
+    }
+
+    int tmpv = pid & 0x1FFF;
+    tmpv |= (number << 16) & 0xFFFF0000;
+    tmpv |= (const1_value << 13) & 0xE000;
+    stream->write_4bytes(tmpv);
+
+    return ret;
+}
+
 SrsTsPayloadPAT::SrsTsPayloadPAT(SrsTsPacket* p) : SrsTsPayloadPSI(p)
 {
+    const1_value = 3;
 }
 
 SrsTsPayloadPAT::~SrsTsPayloadPAT()
@@ -1562,10 +2006,11 @@ int SrsTsPayloadPAT::psi_decode(SrsStream* stream)
     transport_stream_id = stream->read_2bytes();
     
     // 1B
-    current_next_indicator = stream->read_1bytes();
+    int8_t cniv = stream->read_1bytes();
     
-    version_number = (current_next_indicator >> 1) & 0x1F;
-    current_next_indicator &= 0x01;
+    const1_value = (cniv >> 6) & 0x03;
+    version_number = (cniv >> 1) & 0x1F;
+    current_next_indicator = cniv & 0x01;
 
     // TODO: FIXME: check the indicator.
     
@@ -1579,9 +2024,9 @@ int SrsTsPayloadPAT::psi_decode(SrsStream* stream)
     for (int i = 0; i < program_bytes; i += 4) {
         SrsTsPayloadPATProgram* program = new SrsTsPayloadPATProgram();
 
-        int tmpv = stream->read_4bytes();
-        program->number = (int16_t)((tmpv >> 16) & 0xFFFF);
-        program->pid = (int16_t)(tmpv & 0x1FFF);
+        if ((ret = program->decode(stream)) != ERROR_SUCCESS) {
+            return ret;
+        }
 
         // update the apply pid table.
         packet->context->set(program->pid, SrsTsPidApplyPMT);
@@ -1595,8 +2040,59 @@ int SrsTsPayloadPAT::psi_decode(SrsStream* stream)
     return ret;
 }
 
-SrsTsPayloadPMTESInfo::SrsTsPayloadPMTESInfo()
+int SrsTsPayloadPAT::psi_size()
 {
+    int sz = 5;
+    for (int i = 0; i < (int)programs.size(); i ++) {
+        SrsTsPayloadPATProgram* program = programs.at(i);
+        sz += program->size();
+    }
+    return sz;
+}
+
+int SrsTsPayloadPAT::psi_encode(SrsStream* stream)
+{
+    int ret = ERROR_SUCCESS;
+
+    // atleast 5B for PAT specified
+    if (!stream->require(5)) {
+        ret = ERROR_STREAM_CASTER_TS_PAT;
+        srs_error("ts: mux PAT failed. ret=%d", ret);
+        return ret;
+    }
+
+    // 2B
+    stream->write_2bytes(transport_stream_id);
+    
+    // 1B
+    int8_t cniv = current_next_indicator & 0x01;
+    cniv |= (version_number << 1) & 0x3E;
+    cniv |= (const1_value << 6) & 0xC0;
+    stream->write_1bytes(cniv);
+    
+    // 1B
+    stream->write_1bytes(section_number);
+    // 1B
+    stream->write_1bytes(last_section_number);
+
+    // multiple 4B program data.
+    for (int i = 0; i < (int)programs.size(); i ++) {
+        SrsTsPayloadPATProgram* program = programs.at(i);
+        if ((ret = program->encode(stream)) != ERROR_SUCCESS) {
+            return ret;
+        }
+    }
+
+    return ret;
+}
+
+SrsTsPayloadPMTESInfo::SrsTsPayloadPMTESInfo(SrsTsStream st, int16_t epid)
+{
+    stream_type = st;
+    elementary_PID = epid;
+
+    const1_value0 = 7;
+    const1_value1 = 0x0f;
     ES_info_length = 0;
     ES_info = NULL;
 }
@@ -1606,8 +2102,84 @@ SrsTsPayloadPMTESInfo::~SrsTsPayloadPMTESInfo()
     srs_freep(ES_info);
 }
 
+int SrsTsPayloadPMTESInfo::decode(SrsStream* 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 = (epv >> 12) & 0x0f;
+    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;
+        }
+        srs_freep(ES_info);
+        ES_info = new char[ES_info_length];
+        stream->read_bytes(ES_info, ES_info_length);
+    }
+
+    return ret;
+}
+
+int SrsTsPayloadPMTESInfo::size()
+{
+    return 5 + ES_info_length;
+}
+
+int SrsTsPayloadPMTESInfo::encode(SrsStream* stream)
+{
+    int ret = ERROR_SUCCESS;
+
+    // 5B
+    if (!stream->require(5)) {
+        ret = ERROR_STREAM_CASTER_TS_PMT;
+        srs_error("ts: mux PMT es info failed. ret=%d", ret);
+        return ret;
+    }
+
+    stream->write_1bytes(stream_type);
+
+    int16_t epv = elementary_PID & 0x1FFF;
+    epv |= (const1_value0 << 13) & 0xE000;
+    stream->write_2bytes(epv);
+    
+    int16_t eilv = ES_info_length & 0x0FFF;
+    eilv |= (const1_value1 << 12) & 0xF000;
+    stream->write_2bytes(eilv);
+
+    if (ES_info_length > 0) {
+        if (!stream->require(ES_info_length)) {
+            ret = ERROR_STREAM_CASTER_TS_PMT;
+            srs_error("ts: mux PMT es info data failed. ret=%d", ret);
+            return ret;
+        }
+        stream->write_bytes(ES_info, ES_info_length);
+    }
+
+    return ret;
+}
+
 SrsTsPayloadPMT::SrsTsPayloadPMT(SrsTsPacket* p) : SrsTsPayloadPSI(p)
 {
+    const1_value0 = 3;
+    const1_value1 = 7;
+    const1_value2 = 0x0f;
     program_info_length = 0;
     program_info_desc = NULL;
 }
@@ -1639,10 +2211,11 @@ int SrsTsPayloadPMT::psi_decode(SrsStream* stream)
     program_number = stream->read_2bytes();
     
     // 1B
-    current_next_indicator = stream->read_1bytes();
+    int8_t cniv = stream->read_1bytes();
     
-    version_number = (current_next_indicator >> 1) & 0x1F;
-    current_next_indicator &= 0x01;
+    const1_value0 = (cniv >> 6) & 0x03;
+    version_number = (cniv >> 1) & 0x1F;
+    current_next_indicator = cniv & 0x01;
     
     // 1B
     section_number = stream->read_1bytes();
@@ -1651,15 +2224,15 @@ int SrsTsPayloadPMT::psi_decode(SrsStream* stream)
     last_section_number = stream->read_1bytes();
 
     // 2B
-    PCR_PID = stream->read_2bytes();
-    
-    PCR_PID &= 0x1FFF;
+    int16_t ppv = stream->read_2bytes();
+    const1_value1 = (ppv >> 13) & 0x07;
+    PCR_PID = ppv & 0x1FFF;
     
     // 2B
-    program_info_length = stream->read_2bytes();
+    int16_t pilv = stream->read_2bytes();
+    const1_value2 = (pilv >> 12) & 0x0F;
+    program_info_length = pilv & 0xFFF;
 
-    program_info_length &= 0xFFF;
-    
     if (program_info_length > 0) {
         if (!stream->require(program_info_length)) {
             ret = ERROR_STREAM_CASTER_TS_PMT;
@@ -1678,31 +2251,10 @@ int SrsTsPayloadPMT::psi_decode(SrsStream* stream)
         SrsTsPayloadPMTESInfo* info = new SrsTsPayloadPMTESInfo();
         infos.push_back(info);
 
-        // 5B
-        if (!stream->require(5)) {
-            ret = ERROR_STREAM_CASTER_TS_PMT;
-            srs_error("ts: demux PMT es info failed. ret=%d", ret);
+        if ((ret = info->decode(stream)) != ERROR_SUCCESS) {
             return ret;
         }
 
-        info->stream_type = (SrsTsStream)stream->read_1bytes();
-        info->elementary_PID = stream->read_2bytes();
-        info->ES_info_length = stream->read_2bytes();
-
-        info->elementary_PID &= 0x1FFF;
-        info->ES_info_length &= 0x0FFF;
-
-        if (info->ES_info_length > 0) {
-            if (!stream->require(info->ES_info_length)) {
-                ret = ERROR_STREAM_CASTER_TS_PMT;
-                srs_error("ts: demux PMT es info data failed. ret=%d", ret);
-                return ret;
-            }
-            srs_freep(info->ES_info);
-            info->ES_info = new char[info->ES_info_length];
-            stream->read_bytes(info->ES_info, info->ES_info_length);
-        }
-
         // update the apply pid table
         switch (info->stream_type) {
             case SrsTsStreamVideoH264:
@@ -1727,14 +2279,82 @@ int SrsTsPayloadPMT::psi_decode(SrsStream* stream)
     return ret;
 }
 
+int SrsTsPayloadPMT::psi_size()
+{
+    int sz = 9;
+    sz += program_info_length;
+    for (int i = 0; i < (int)infos.size(); i ++) {
+        SrsTsPayloadPMTESInfo* info = infos.at(i);
+        sz += info->size();
+    }
+    return sz;
+}
+
+int SrsTsPayloadPMT::psi_encode(SrsStream* stream)
+{
+    int ret = ERROR_SUCCESS;
+
+    // atleast 9B for PMT specified
+    if (!stream->require(9)) {
+        ret = ERROR_STREAM_CASTER_TS_PMT;
+        srs_error("ts: mux PMT failed. ret=%d", ret);
+        return ret;
+    }
+
+    // 2B
+    stream->write_2bytes(program_number);
+    
+    // 1B
+    int8_t cniv = current_next_indicator & 0x01;
+    cniv |= (const1_value0 << 6) & 0xC0;
+    cniv |= (version_number << 1) & 0xFE;
+    stream->write_1bytes(cniv);
+    
+    // 1B
+    stream->write_1bytes(section_number);
+    
+    // 1B
+    stream->write_1bytes(last_section_number);
+
+    // 2B
+    int16_t ppv = PCR_PID & 0x1FFF;
+    ppv |= (const1_value1 << 13) & 0xE000;
+    stream->write_2bytes(ppv);
+    
+    // 2B
+    int16_t pilv = program_info_length & 0xFFF;
+    pilv |= (const1_value2 << 12) & 0xF000;
+    stream->write_2bytes(pilv);
+
+    if (program_info_length > 0) {
+        if (!stream->require(program_info_length)) {
+            ret = ERROR_STREAM_CASTER_TS_PMT;
+            srs_error("ts: mux PMT program info failed. ret=%d", ret);
+            return ret;
+        }
+
+        stream->write_bytes(program_info_desc, program_info_length);
+    }
+
+    for (int i = 0; i < (int)infos.size(); i ++) {
+        SrsTsPayloadPMTESInfo* info = infos.at(i);
+        if ((ret = info->encode(stream)) != ERROR_SUCCESS) {
+            return ret;
+        }
+    }
+
+    return ret;
+}
+
 SrsTSMuxer::SrsTSMuxer(SrsFileWriter* w)
 {
     writer = w;
+    context = NULL;
 
-    // reserved is not written.
-    previous = SrsCodecAudioReserved1;
-    // current default to aac.
-    current = SrsCodecAudioAAC;
+    // default to aac.
+    acodec = SrsCodecAudioAAC;
+    // default to avc(h.264)
+    vcodec = SrsCodecVideoAVC;
 }
 
 SrsTSMuxer::~SrsTSMuxer()
@@ -1749,6 +2369,10 @@ int SrsTSMuxer::open(string _path)
     path = _path;
     
     close();
+
+    // use context to write ts file.
+    srs_freep(context);
+    context = new SrsTsContext();
     
     if ((ret = writer->open(path)) != ERROR_SUCCESS) {
         return ret;
@@ -1759,31 +2383,19 @@ int SrsTSMuxer::open(string _path)
 
 int SrsTSMuxer::update_acodec(SrsCodecAudio ac)
 {
-    int ret = ERROR_SUCCESS;
-
-    if (current == ac) {
-        return ret;
-    }
-    current = ac;
-
-    return ret;
+    acodec = ac;
+    return ERROR_SUCCESS;
 }
 
 int SrsTSMuxer::write_audio(SrsMpegtsFrame* af, SrsSimpleBuffer* ab)
 {
     int ret = ERROR_SUCCESS;
     
-    // when acodec changed, write header.
-    if (current != previous) {
-        previous = current;
-        if ((ret = SrsMpegtsWriter::write_header(writer, previous)) != ERROR_SUCCESS) {
-            return ret;
-        }
-    }
-    
-    if ((ret = SrsMpegtsWriter::write_frame(writer, af, ab)) != ERROR_SUCCESS) {
+    if ((ret = context->encode(writer, af, ab, vcodec, acodec)) != ERROR_SUCCESS) {
+        srs_error("hls encode audio failed. ret=%d", ret);
         return ret;
     }
+    srs_info("hls encode audio ok");
     
     return ret;
 }
@@ -1792,23 +2404,18 @@ int SrsTSMuxer::write_video(SrsMpegtsFrame* vf, SrsSimpleBuffer* vb)
 {
     int ret = ERROR_SUCCESS;
     
-    // when acodec changed, write header.
-    if (current != previous) {
-        previous = current;
-        if ((ret = SrsMpegtsWriter::write_header(writer, previous)) != ERROR_SUCCESS) {
-            return ret;
-        }
-    }
-    
-    if ((ret = SrsMpegtsWriter::write_frame(writer, vf, vb)) != ERROR_SUCCESS) {
+    if ((ret = context->encode(writer, vf, vb, vcodec, acodec)) != ERROR_SUCCESS) {
+        srs_error("hls encode video failed. ret=%d", ret);
         return ret;
     }
+    srs_info("hls encode video ok");
     
     return ret;
 }
 
 void SrsTSMuxer::close()
 {
+    srs_freep(context);
     writer->close();
 }
 
diff --git a/trunk/src/kernel/srs_kernel_ts.hpp b/trunk/src/kernel/srs_kernel_ts.hpp
index 62a45808e..e23c28e5f 100644
--- a/trunk/src/kernel/srs_kernel_ts.hpp
+++ b/trunk/src/kernel/srs_kernel_ts.hpp
@@ -59,7 +59,7 @@ public:
     int64_t         dts;
     int             pid;
     int             sid;
-    int             cc;
+    int             cc; // continuity_counter
     bool            write_pcr;
     
     SrsMpegtsFrame();
@@ -327,18 +327,18 @@ public:
 */
 class SrsTsContext
 {
+// codec
 private:
     std::map<int, SrsTsChannel*> pids;
+// encoder
+private:
+    // when any codec changed, write the PAT/PMT.
+    SrsCodecVideo vcodec;
+    SrsCodecAudio acodec;
 public:
     SrsTsContext();
     virtual ~SrsTsContext();
-public:
-    /**
-    * the stream contains only one ts packet.
-    * @param handler the ts message handler to process the msg.
-    * @remark we will consume all bytes in stream.
-    */
-    virtual int decode(SrsStream* stream, ISrsTsHandler* handler);
+// codec
 public:
     /**
     * get the pid apply, the parsed pid.
@@ -349,6 +349,27 @@ public:
     * set the pid apply, the parsed pid.
     */
     virtual void set(int pid, SrsTsPidApply apply_pid, SrsTsStream stream = SrsTsStreamReserved);
+// decode methods
+public:
+    /**
+    * the stream contains only one ts packet.
+    * @param handler the ts message handler to process the msg.
+    * @remark we will consume all bytes in stream.
+    */
+    virtual int decode(SrsStream* stream, ISrsTsHandler* handler);
+// encode methods
+public:
+    /**
+    * write the PES packet, the video/audio stream.
+    * @param frame the video/audio frame info.
+    * @param payload the video/audio payload bytes.
+    * @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 int encode(SrsFileWriter* writer, SrsMpegtsFrame* frame, SrsSimpleBuffer* payload, SrsCodecVideo vc, SrsCodecAudio ac);
+private:
+    virtual int encode_pat_pmt(SrsFileWriter* writer, SrsCodecVideo vcodec, SrsCodecAudio acodec);
+    virtual int encode_pes(SrsFileWriter* writer, SrsMpegtsFrame* frame, SrsSimpleBuffer* payload);
 };
 
 /**
@@ -454,6 +475,12 @@ public:
     virtual ~SrsTsPacket();
 public:
     virtual int decode(SrsStream* stream, SrsTsMessage** ppmsg);
+public:
+    virtual int size();
+    virtual int encode(SrsStream* stream);
+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);
 };
 
 /**
@@ -755,6 +782,9 @@ public:
     virtual ~SrsTsAdaptationField();
 public:
     virtual int decode(SrsStream* stream);
+public:
+    virtual int size();
+    virtual int encode(SrsStream* stream);
 };
 
 /**
@@ -800,6 +830,9 @@ public:
     virtual ~SrsTsPayload();
 public:
     virtual int decode(SrsStream* stream, SrsTsMessage** ppmsg) = 0;
+public:
+    virtual int size() = 0;
+    virtual int encode(SrsStream* stream) = 0;
 };
 
 /**
@@ -1141,6 +1174,9 @@ public:
     virtual ~SrsTsPayloadPES();
 public:
     virtual int decode(SrsStream* stream, SrsTsMessage** ppmsg);
+public:
+    virtual int size();
+    virtual int encode(SrsStream* stream);
 private:
     virtual int decode_33bits_dts_pts(SrsStream* stream, int64_t* pv);
 };
@@ -1179,13 +1215,18 @@ public:
     * const value, must be '0'
     */
     int8_t const0_value; //1bit
-    // 2bits reserved. 
+    /**
+    * 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).
     */
     u_int16_t section_length; //12bits
+public:
+    // the specified psi info, for example, PAT fields.
 public:
     // 4B
     /**
@@ -1199,7 +1240,12 @@ public:
     virtual ~SrsTsPayloadPSI();
 public:
     virtual int decode(SrsStream* stream, SrsTsMessage** ppmsg);
+public:
+    virtual int size();
+    virtual int encode(SrsStream* stream);
 protected:
+    virtual int psi_size() = 0;
+    virtual int psi_encode(SrsStream* stream) = 0;
     virtual int psi_decode(SrsStream* stream) = 0;
 };
 
@@ -1217,7 +1263,10 @@ public:
     * Association Table.
     */
     int16_t number; // 16bits
-    // reserved 3bits
+    /**
+    * 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
@@ -1225,10 +1274,15 @@ public:
     * 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;
+    int16_t pid; //13bits
 public:
-    SrsTsPayloadPATProgram();
+    SrsTsPayloadPATProgram(int16_t n = 0, int16_t p = 0);
     virtual ~SrsTsPayloadPATProgram();
+public:
+    virtual int decode(SrsStream* stream);
+public:
+    virtual int size();
+    virtual int encode(SrsStream* stream);
 };
 
 /**
@@ -1249,7 +1303,10 @@ public:
     u_int16_t transport_stream_id; //16bits
     
     // 1B
-    // 2bits reerverd.
+    /**
+    * reverved value, must be '1'
+    */
+    int8_t const1_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
@@ -1285,8 +1342,11 @@ public:
 public:
     SrsTsPayloadPAT(SrsTsPacket* p);
     virtual ~SrsTsPayloadPAT();
-public:
+protected:
     virtual int psi_decode(SrsStream* stream);
+protected:
+    virtual int psi_size();
+    virtual int psi_encode(SrsStream* stream);
 };
 
 /**
@@ -1303,15 +1363,21 @@ public:
     SrsTsStream stream_type; //8bits
     
     // 2B
-    // 3bits reserved
+    /**
+    * 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
     
-    // 2B
-    // 4bits reserved
+    // (2+x)B
+    /**
+    * reverved value, must be '1'
+    */
+    int8_t const1_value1; //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 of the associated program element immediately following the ES_info_length field.
@@ -1319,8 +1385,13 @@ public:
     int16_t ES_info_length; //12bits
     char* ES_info; //[ES_info_length] bytes.
 public:
-    SrsTsPayloadPMTESInfo();
+    SrsTsPayloadPMTESInfo(SrsTsStream st = SrsTsStreamReserved, int16_t epid = 0);
     virtual ~SrsTsPayloadPMTESInfo();
+public:
+    virtual int decode(SrsStream* stream);
+public:
+    virtual int size();
+    virtual int encode(SrsStream* stream);
 };
 
 /**
@@ -1349,7 +1420,10 @@ public:
     u_int16_t program_number; //16bits
     
     // 1B
-    // 2bits reerverd.
+    /**
+    * 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
@@ -1378,17 +1452,20 @@ public:
     u_int8_t last_section_number; //8bits
     
     // 2B
-    // 2bits reserved.
+    /**
+    * 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; //16bits
+    int16_t PCR_PID; //13bits
     
     // 2B
-    // 4bits reserved.
+    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.
@@ -1401,8 +1478,11 @@ public:
 public:
     SrsTsPayloadPMT(SrsTsPacket* p);
     virtual ~SrsTsPayloadPMT();
-public:
+protected:
     virtual int psi_decode(SrsStream* stream);
+protected:
+    virtual int psi_size();
+    virtual int psi_encode(SrsStream* stream);
 };
 
 /**
@@ -1412,9 +1492,10 @@ public:
 class SrsTSMuxer
 {
 private:
-    SrsCodecAudio previous;
-    SrsCodecAudio current;
+    SrsCodecVideo vcodec;
+    SrsCodecAudio acodec;
 private:
+    SrsTsContext* context;
     SrsFileWriter* writer;
     std::string path;
 public: