From a73f97e0656ef5cbbfff0f8b30a79f5e0411b690 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Mon, 18 Jul 2016 10:08:28 +0200 Subject: [PATCH 1/4] Implemented ES priority flag in accordance with HBBTV spec --- lib/ts_packet.cpp | 44 +++++++++++++++++++++++++++++------ lib/ts_packet.h | 3 ++- src/output/output_ts_base.cpp | 3 ++- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/lib/ts_packet.cpp b/lib/ts_packet.cpp index 40ca8d33..85c8e4e5 100644 --- a/lib/ts_packet.cpp +++ b/lib/ts_packet.cpp @@ -258,6 +258,9 @@ namespace TS { if (getRandomAccess()){ output << " [RandomXS]"; } + if (getESPriority()){ + output << " [ESPriority]"; + } if (hasPCR()) { output << " [PCR " << (double)getPCR() / 27000000 << "s]"; } @@ -286,7 +289,7 @@ namespace TS { return output.str(); } - if (detailLevel >= 3){ + if (detailLevel >= 10){ output << std::string(indent+2, ' ') << "Raw data bytes:"; unsigned int size = getDataSize(); @@ -325,12 +328,6 @@ namespace TS { } } -/// Gets the elementary stream priority indicator of a Packet -/// \return The elementary stream priority indicator of a Packet - bool Packet::hasESpriority() const{ - return strBuf[5] & 0x20; - } - bool Packet::hasDiscontinuity() const{ return strBuf[5] & 0x80; } @@ -366,6 +363,15 @@ namespace TS { return strBuf[5] & 0x40; } +/// Gets whether this Packet has the priority bit set +/// \return Whether or not this Packet has the priority bit set + bool Packet::getESPriority() const{ + if (getAdaptationField() < 2) { + return false; + } + return strBuf[5] & 0x20; + } + ///Gets the value of the PCR flag ///\return true if there is a PCR, false otherwise bool Packet::hasPCR() const{ @@ -408,6 +414,30 @@ namespace TS { } } +///Gets the value of the ES priority flag +///\return the value of the ES priority flag + void Packet::setESPriority(bool NewVal) { + updPos(6); + if (getAdaptationField() == 3) { + if (!strBuf[4]) { + strBuf[4] = 1; + } + if (NewVal) { + strBuf[5] |= 0x20; + } else { + strBuf[5] &= 0xDF; + } + } else { + setAdaptationField(3); + strBuf[4] = 1; + if (NewVal) { + strBuf[5] = 0x20; + } else { + strBuf[5] = 0x00; + } + } + } + /// Transforms the Packet into a standard Program Association Table void Packet::setDefaultPAT() { static int MyCntr = 0; diff --git a/lib/ts_packet.h b/lib/ts_packet.h index 3cdfce36..74937859 100644 --- a/lib/ts_packet.h +++ b/lib/ts_packet.h @@ -45,6 +45,8 @@ namespace TS { bool getUnitStart() const; void setRandomAccess(bool newVal); bool getRandomAccess() const; + void setESPriority(bool newVal); + bool getESPriority() const; void setDiscontinuity(bool newVal); bool hasDiscontinuity() const; @@ -53,7 +55,6 @@ namespace TS { bool hasSplicingPoint() const; bool hasTransportError() const; bool hasPriority() const; - bool hasESpriority() const; //Helper functions operator bool() const; diff --git a/src/output/output_ts_base.cpp b/src/output/output_ts_base.cpp index ee771c35..ca7a2a67 100644 --- a/src/output/output_ts_base.cpp +++ b/src/output/output_ts_base.cpp @@ -39,7 +39,8 @@ namespace Mist { packData.setDiscontinuity(true); if (myMeta.tracks[thisPacket.getTrackId()].type == "video"){ if (thisPacket.getInt("keyframe")){ - packData.setRandomAccess(1); + packData.setRandomAccess(true); + packData.setESPriority(true); } packData.setPCR(thisPacket.getTime() * 27000); } From 3844dac4fdc905c74f7cd1099a49fd4771ef8c04 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Wed, 13 Jul 2016 11:43:41 +0200 Subject: [PATCH 2/4] Added track language support to TS and DTSC internals --- lib/dtsc.h | 1 + lib/dtscmeta.cpp | 28 ++++++++++++++ lib/ts_packet.cpp | 94 ++++++++++++++++++++++++++++++++++++++++++++--- lib/ts_packet.h | 10 +++++ 4 files changed, 127 insertions(+), 6 deletions(-) diff --git a/lib/dtsc.h b/lib/dtsc.h index 8cfb40ed..ae387a7c 100644 --- a/lib/dtsc.h +++ b/lib/dtsc.h @@ -301,6 +301,7 @@ namespace DTSC { std::string init; std::string codec; std::string type; + std::string lang;///< ISO 639-2 Language of track, empty or und if unknown. //audio only int rate; int size; diff --git a/lib/dtscmeta.cpp b/lib/dtscmeta.cpp index 318eec71..5072136e 100644 --- a/lib/dtscmeta.cpp +++ b/lib/dtscmeta.cpp @@ -1088,6 +1088,9 @@ namespace DTSC { codec = trackRef["codec"].asStringRef(); type = trackRef["type"].asStringRef(); init = trackRef["init"].asStringRef(); + if (trackRef.isMember("lang") && trackRef["lang"].asStringRef().size()){ + lang = trackRef["lang"].asStringRef(); + } if (type == "audio") { rate = trackRef["rate"].asInt(); size = trackRef["size"].asInt(); @@ -1134,6 +1137,9 @@ namespace DTSC { codec = trackRef.getMember("codec").asString(); type = trackRef.getMember("type").asString(); init = trackRef.getMember("init").asString(); + if (trackRef.getMember("lang")){ + lang = trackRef.getMember("lang").asString(); + } if (type == "audio") { rate = trackRef.getMember("rate").asInt(); size = trackRef.getMember("size").asInt(); @@ -1398,6 +1404,9 @@ namespace DTSC { str << std::hex << std::setw(2) << std::setfill('0') << (int)init[i]; } str << std::dec << std::endl; + if (lang.size()){ + str << std::string(indent + 2, ' ') << "Language: " << lang << std::endl; + } if (type == "audio") { str << std::string(indent + 2, ' ') << "Rate: " << rate << std::endl; str << std::string(indent + 2, ' ') << "Size: " << size << std::endl; @@ -1482,6 +1491,9 @@ namespace DTSC { result << width << "x" << height << "_"; result << (double)fpks / 1000 << "fps"; } + if (lang.size() && lang != "und"){ + result << "_" << lang; + } return result.str(); } @@ -1505,6 +1517,9 @@ namespace DTSC { } result += parts.size() * 9 + 12; } + if (lang.size() && lang != "und"){ + result += 11 + lang.size(); + } if (type == "audio") { result += 49; } else if (type == "video") { @@ -1588,6 +1603,11 @@ namespace DTSC { writePointer(p, "\000\004type\002", 7); writePointer(p, convertInt(type.size()), 4); writePointer(p, type); + if (lang.size() && lang != "und"){ + writePointer(p, "\000\004lang\002", 7); + writePointer(p, convertInt(lang.size()), 4); + writePointer(p, lang); + } if (type == "audio") { writePointer(p, "\000\004rate\001", 7); writePointer(p, convertLongLong(rate), 8); @@ -1660,6 +1680,11 @@ namespace DTSC { conn.SendNow("\000\004type\002", 7); conn.SendNow(convertInt(type.size()), 4); conn.SendNow(type); + if (lang.size() && lang != "und"){ + conn.SendNow("\000\004lang\002", 7); + conn.SendNow(convertInt(lang.size()), 4); + conn.SendNow(lang); + } if (type == "audio") { conn.SendNow("\000\004rate\001", 7); conn.SendNow(convertLongLong(rate), 8); @@ -1786,6 +1811,9 @@ namespace DTSC { result["parts"] = tmp; } result["init"] = init; + if (lang.size() && lang != "und"){ + result["lang"] = lang; + } result["trackid"] = trackID; result["firstms"] = (long long)firstms; result["lastms"] = (long long)lastms; diff --git a/lib/ts_packet.cpp b/lib/ts_packet.cpp index 85c8e4e5..e7673818 100644 --- a/lib/ts_packet.cpp +++ b/lib/ts_packet.cpp @@ -989,17 +989,85 @@ namespace TS { while (entry) { output << std::string(indent + 4, ' '); stream_pids[entry.getElementaryPid()] = entry.getCodec() + std::string(" ") + entry.getStreamTypeString(); - output << "Stream " << entry.getElementaryPid() << ": " << stream_pids[entry.getElementaryPid()] << " (" << entry.getStreamType() << "), Info (" << entry.getESInfoLength() << ") = "; - for (unsigned int i = 0; i p_len){continue;}//skip broken data + output << std::string(indent, ' ') << "AAC profile: "; + switch (p_data[p+2]){ + case 0x50: output << "AAC, level 1"; break; + case 0x51: output << "AAC, level 2"; break; + case 0x52: output << "AAC, level 4"; break; + case 0x53: output << "AAC, level 5"; break; + case 0x58: output << "AAC-HE, level 2"; break; + case 0x59: output << "AAC-HE, level 3"; break; + case 0x5A: output << "AAC-HE, level 4"; break; + case 0x5B: output << "AAC-HE, level 5"; break; + case 0x60: output << "AAC-HEv2, level 2"; break; + case 0x61: output << "AAC-HEv2, level 3"; break; + case 0x62: output << "AAC-HEv2, level 4"; break; + case 0x63: output << "AAC-HEv2, level 5"; break; + default: output << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << (int)p_data[p+2] << std::dec; + } + if (p_data[p+3] & 0x80){ + output << ", type: " << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << (int)p_data[p+3] << std::dec; + } + output << std::endl; + if (p_data[p+1] > 2){ + output << std::string(indent+2, ' ') << "Extra data: "; + for (uint32_t offset = 2; p+2+offset < p_data[p+1]; ++offset){ + output << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << (int)p_data[p+2+offset] << std::dec; + } + } + } break; + default:{ + output << std::string(indent, ' ') << "Undecoded descriptor: "; + for (uint32_t i = 0; i Date: Mon, 18 Jul 2016 10:38:26 +0200 Subject: [PATCH 3/4] Language support for MP4 --- lib/mp4_generic.cpp | 35 ++++++++++++++++++++++----- lib/mp4_generic.h | 5 ++-- src/output/output_progressive_mp4.cpp | 1 + 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/lib/mp4_generic.cpp b/lib/mp4_generic.cpp index 0c9c8591..8c67fe61 100644 --- a/lib/mp4_generic.cpp +++ b/lib/mp4_generic.cpp @@ -2241,20 +2241,43 @@ namespace MP4 { void MDHD::setLanguage(uint16_t newLanguage) { if (getVersion() == 0) { - setInt16(newLanguage & 0x7F, 20); + setInt16(newLanguage & 0x7FFF, 20); } else { - setInt16(newLanguage & 0x7F, 32); + setInt16(newLanguage & 0x7FFF, 32); } } - uint16_t MDHD::getLanguage() { + uint16_t MDHD::getLanguageInt() { if (getVersion() == 0) { - return getInt16(20) & 0x7F; + return getInt16(20) & 0x7FFF; } else { - return getInt16(32) & 0x7F; + return getInt16(32) & 0x7FFF; } } + void MDHD::setLanguage(const std::string & newLanguage) { + if (newLanguage.size() != 3){ + setLanguage("und"); + return; + } + uint16_t newLang = 0; + newLang += (newLanguage[0] - 0x60) & 0x1F; + newLang <<= 5; + newLang += (newLanguage[1] - 0x60) & 0x1F; + newLang <<= 5; + newLang += (newLanguage[2] - 0x60) & 0x1F; + setLanguage(newLang); + } + + std::string MDHD::getLanguage() { + uint16_t lInt = getLanguageInt(); + std::string ret; + ret += (char)(((lInt & 0x7C00) >> 10) + 0x60); + ret += (char)(((lInt & 0x3E0) >> 5) + 0x60); + ret += (char)((lInt & 0x1F) + 0x60); + return ret; + } + std::string MDHD::toPrettyString(uint32_t indent) { std::stringstream r; r << std::string(indent, ' ') << "[mdhd] Media Header Box (" << boxedSize() << ")" << std::endl; @@ -2263,7 +2286,7 @@ namespace MP4 { r << std::string(indent + 1, ' ') << "ModificationTime: " << getModificationTime() << std::endl; r << std::string(indent + 1, ' ') << "TimeScale: " << getTimeScale() << std::endl; r << std::string(indent + 1, ' ') << "Duration: " << getDuration() << std::endl; - r << std::string(indent + 1, ' ') << "Language: 0x" << std::hex << getLanguage() << std::dec << std::endl; + r << std::string(indent + 1, ' ') << "Language: " << getLanguage() << std::endl; return r.str(); } diff --git a/lib/mp4_generic.h b/lib/mp4_generic.h index 1f760f5e..82c798b7 100644 --- a/lib/mp4_generic.h +++ b/lib/mp4_generic.h @@ -463,9 +463,10 @@ namespace MP4 { uint32_t getTimeScale(); void setDuration(uint64_t newDuration); uint64_t getDuration(); - ///\todo return language properly void setLanguage(uint16_t newLanguage); - uint16_t getLanguage(); + uint16_t getLanguageInt(); + void setLanguage(const std::string & newLanguage); + std::string getLanguage(); std::string toPrettyString(uint32_t indent = 0); }; diff --git a/src/output/output_progressive_mp4.cpp b/src/output/output_progressive_mp4.cpp index b3652cc5..60af00ed 100644 --- a/src/output/output_progressive_mp4.cpp +++ b/src/output/output_progressive_mp4.cpp @@ -70,6 +70,7 @@ namespace Mist { unsigned int mdiaOffset = 0; { MP4::MDHD mdhdBox(thisTrack.lastms - thisTrack.firstms); + mdhdBox.setLanguage(thisTrack.lang); mdiaBox.setContent(mdhdBox, mdiaOffset++); }//MDHD box { From 1187b6045453c3e6097f0bf4e13764ad1fe493de Mon Sep 17 00:00:00 2001 From: Thulinma Date: Mon, 18 Jul 2016 10:13:02 +0200 Subject: [PATCH 4/4] Rudimentary support for SRT output with TTXT codec --- src/output/output_srt.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/output/output_srt.cpp b/src/output/output_srt.cpp index ad5d6f3d..31ba5e03 100644 --- a/src/output/output_srt.cpp +++ b/src/output/output_srt.cpp @@ -17,6 +17,7 @@ namespace Mist { capa["url_handler"] = "http"; capa["url_type"] = "subtitle"; capa["codecs"][0u][0u].append("srt"); + capa["codecs"][0u][0u].append("TTXT"); capa["methods"][0u]["handler"] = "http"; capa["methods"][0u]["type"] = "html5/text/plain"; capa["methods"][0u]["priority"] = 8ll; @@ -36,6 +37,9 @@ namespace Mist { tmp.write(tmpBuf, tmpLen); tmp << " --> "; time += thisPacket.getInt("duration"); + if (time == thisPacket.getTime()){ + time += len * 100 + 1000; + } tmpLen = sprintf(tmpBuf, "%.2llu:%.2llu:%.2llu,%.3llu", (time / 3600000), ((time % 3600000) / 60000), (((time % 3600000) % 60000) / 1000), time % 1000); tmp.write(tmpBuf, tmpLen); tmp << std::endl;