From 1ed3e283abd9a79f19d607779921e03dbe5caaf7 Mon Sep 17 00:00:00 2001 From: winlin 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; } - channel->pid = pid; - channel->apply = apply_pid; - channel->stream = stream; + 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); + + 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 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: