Merge branch 'development' into LTS_development
# Conflicts: # src/output/output_progressive_mp4.cpp
This commit is contained in:
commit
4bcfb5191a
9 changed files with 205 additions and 23 deletions
|
@ -325,6 +325,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;
|
||||
|
|
|
@ -1124,6 +1124,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();
|
||||
|
@ -1178,6 +1181,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();
|
||||
|
@ -1468,6 +1474,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;
|
||||
|
@ -1552,6 +1561,9 @@ namespace DTSC {
|
|||
result << width << "x" << height << "_";
|
||||
result << (double)fpks / 1000 << "fps";
|
||||
}
|
||||
if (lang.size() && lang != "und"){
|
||||
result << "_" << lang;
|
||||
}
|
||||
return result.str();
|
||||
}
|
||||
|
||||
|
@ -1576,6 +1588,9 @@ namespace DTSC {
|
|||
result += parts.size() * 9 + 12;
|
||||
result += (ivecs.size() * 8) + 12; /*LTS*/
|
||||
}
|
||||
if (lang.size() && lang != "und"){
|
||||
result += 11 + lang.size();
|
||||
}
|
||||
if (type == "audio") {
|
||||
result += 49;
|
||||
} else if (type == "video") {
|
||||
|
@ -1666,6 +1681,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);
|
||||
|
@ -1745,6 +1765,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);
|
||||
|
@ -1879,6 +1904,9 @@ namespace DTSC {
|
|||
/*LTS-END*/
|
||||
}
|
||||
result["init"] = init;
|
||||
if (lang.size() && lang != "und"){
|
||||
result["lang"] = lang;
|
||||
}
|
||||
result["trackid"] = trackID;
|
||||
result["firstms"] = (long long)firstms;
|
||||
result["lastms"] = (long long)lastms;
|
||||
|
|
|
@ -2476,20 +2476,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;
|
||||
|
@ -2498,7 +2521,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();
|
||||
}
|
||||
|
||||
|
|
|
@ -515,9 +515,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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -959,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<entry.getESInfoLength(); ++i){
|
||||
output << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << (int)entry.getESInfo()[i] << std::dec;
|
||||
}
|
||||
output << std::endl;
|
||||
output << "Stream " << entry.getElementaryPid() << ": " << stream_pids[entry.getElementaryPid()] << " (" << entry.getStreamType() << ")" << std::endl;
|
||||
output << ProgramDescriptors(entry.getESInfo(), entry.getESInfoLength()).toPrettyString(indent+6);
|
||||
entry.advance();
|
||||
}
|
||||
output << std::string(indent + 2, ' ') << "CRC32: " << std::hex << std::setw(8) << std::setfill('0') << std::uppercase << getCRC() << std::dec << std::endl;
|
||||
return output.str();
|
||||
}
|
||||
|
||||
ProgramDescriptors::ProgramDescriptors(const char * data, const uint32_t len) : p_data(data), p_len(len){
|
||||
}
|
||||
|
||||
///Returns the ISO-629 language code, or "und" if unknown.
|
||||
std::string ProgramDescriptors::getLanguage() const{
|
||||
for (uint32_t p = 0; p + 1 < p_len; p += p_data[p+1]+2){
|
||||
if (p_data[p] == 0x0A){//language tag
|
||||
//We assume the first one is the only interesting one
|
||||
return std::string(p_data+p+2, 3);
|
||||
}
|
||||
}
|
||||
//No tag found! Undetermined by default.
|
||||
return "und";
|
||||
}
|
||||
|
||||
///Prints all descriptors we understand in a readable format, the others in raw hex.
|
||||
std::string ProgramDescriptors::toPrettyString(size_t indent) const{
|
||||
std::stringstream output;
|
||||
for (uint32_t p = 0; p + 1 < p_len; p += p_data[p+1]+2){
|
||||
switch (p_data[p]){
|
||||
case 0x0A:{//ISO 639-2 language tag (ISO 13818-1)
|
||||
uint32_t offset = 0;
|
||||
while (offset < p_data[p+1]){//single language
|
||||
output << std::string(indent, ' ') << "Language: " << std::string(p_data+p+2+offset,3);
|
||||
switch (p_data[p+5+offset]){
|
||||
case 1: output << ", clean effects";
|
||||
}
|
||||
output << std::endl;
|
||||
offset += 4;
|
||||
}
|
||||
} break;
|
||||
case 0x7C:{//AAC descriptor (EN 300 468)
|
||||
if (p_data[p+1] < 2 || p+2+p_data[p+1] > 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<p_data[p+1]+2; ++i){
|
||||
output << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << (int)p_data[p+i] << std::dec;
|
||||
}
|
||||
output << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
return output.str();
|
||||
}
|
||||
|
||||
/// Construct a PMT (special 188B ts packet) from a set of selected tracks and metadata.
|
||||
/// This function is not part of the packet class, but it is in the TS namespace.
|
||||
|
@ -988,6 +1086,12 @@ namespace TS {
|
|||
if (myMeta.tracks[*it].codec == "ID3"){
|
||||
sectionLen += myMeta.tracks[*it].init.size();
|
||||
}
|
||||
if (myMeta.tracks[*it].codec == "AAC"){
|
||||
sectionLen += 4;//aac descriptor
|
||||
if (myMeta.tracks[*it].lang.size() == 3 && myMeta.tracks[*it].lang != "und"){
|
||||
sectionLen += 6;//language descriptor
|
||||
}
|
||||
}
|
||||
}
|
||||
PMT.setSectionLength(0xB00D + sectionLen);
|
||||
PMT.setProgramNumber(1);
|
||||
|
@ -1019,6 +1123,14 @@ namespace TS {
|
|||
entry.setStreamType(0x24);
|
||||
}else if (myMeta.tracks[*it].codec == "AAC"){
|
||||
entry.setStreamType(0x0F);
|
||||
std::string aac_info("\174\002\121\000", 4);//AAC descriptor: AAC Level 2. Hardcoded, because... what are AAC levels, anyway?
|
||||
//language code ddescriptor
|
||||
if (myMeta.tracks[*it].lang.size() == 3 && myMeta.tracks[*it].lang != "und"){
|
||||
aac_info.append("\012\004", 2);
|
||||
aac_info.append(myMeta.tracks[*it].lang);
|
||||
aac_info.append("\000", 1);
|
||||
}
|
||||
entry.setESInfo(aac_info);
|
||||
}else if (myMeta.tracks[*it].codec == "MP3"){
|
||||
entry.setStreamType(0x03);
|
||||
}else if (myMeta.tracks[*it].codec == "AC3"){
|
||||
|
|
|
@ -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;
|
||||
|
@ -101,6 +102,16 @@ namespace TS {
|
|||
std::string toPrettyString(size_t indent) const;
|
||||
};
|
||||
|
||||
class ProgramDescriptors {
|
||||
public:
|
||||
ProgramDescriptors(const char * data, const uint32_t len);
|
||||
std::string getLanguage() const;
|
||||
std::string toPrettyString(size_t indent) const;
|
||||
private:
|
||||
const char * p_data;
|
||||
const uint32_t p_len;
|
||||
};
|
||||
|
||||
class ProgramMappingEntry {
|
||||
public:
|
||||
ProgramMappingEntry(char * begin, char * end);
|
||||
|
|
|
@ -159,6 +159,7 @@ namespace Mist {
|
|||
|
||||
//Add the mandatory MDHD and HDLR boxes to the MDIA
|
||||
MP4::MDHD mdhdBox(thisTrack.lastms - thisTrack.firstms);
|
||||
mdhdBox.setLanguage(thisTrack.lang);
|
||||
mdiaBox.setContent(mdhdBox, mdiaOffset++);
|
||||
MP4::HDLR hdlrBox(thisTrack.type, thisTrack.getIdentifier());
|
||||
mdiaBox.setContent(hdlrBox, mdiaOffset++);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -40,7 +40,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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue