Added track language support to TS and DTSC internals
This commit is contained in:
parent
a73f97e065
commit
3844dac4fd
4 changed files with 127 additions and 6 deletions
|
@ -301,6 +301,7 @@ namespace DTSC {
|
||||||
std::string init;
|
std::string init;
|
||||||
std::string codec;
|
std::string codec;
|
||||||
std::string type;
|
std::string type;
|
||||||
|
std::string lang;///< ISO 639-2 Language of track, empty or und if unknown.
|
||||||
//audio only
|
//audio only
|
||||||
int rate;
|
int rate;
|
||||||
int size;
|
int size;
|
||||||
|
|
|
@ -1088,6 +1088,9 @@ namespace DTSC {
|
||||||
codec = trackRef["codec"].asStringRef();
|
codec = trackRef["codec"].asStringRef();
|
||||||
type = trackRef["type"].asStringRef();
|
type = trackRef["type"].asStringRef();
|
||||||
init = trackRef["init"].asStringRef();
|
init = trackRef["init"].asStringRef();
|
||||||
|
if (trackRef.isMember("lang") && trackRef["lang"].asStringRef().size()){
|
||||||
|
lang = trackRef["lang"].asStringRef();
|
||||||
|
}
|
||||||
if (type == "audio") {
|
if (type == "audio") {
|
||||||
rate = trackRef["rate"].asInt();
|
rate = trackRef["rate"].asInt();
|
||||||
size = trackRef["size"].asInt();
|
size = trackRef["size"].asInt();
|
||||||
|
@ -1134,6 +1137,9 @@ namespace DTSC {
|
||||||
codec = trackRef.getMember("codec").asString();
|
codec = trackRef.getMember("codec").asString();
|
||||||
type = trackRef.getMember("type").asString();
|
type = trackRef.getMember("type").asString();
|
||||||
init = trackRef.getMember("init").asString();
|
init = trackRef.getMember("init").asString();
|
||||||
|
if (trackRef.getMember("lang")){
|
||||||
|
lang = trackRef.getMember("lang").asString();
|
||||||
|
}
|
||||||
if (type == "audio") {
|
if (type == "audio") {
|
||||||
rate = trackRef.getMember("rate").asInt();
|
rate = trackRef.getMember("rate").asInt();
|
||||||
size = trackRef.getMember("size").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::hex << std::setw(2) << std::setfill('0') << (int)init[i];
|
||||||
}
|
}
|
||||||
str << std::dec << std::endl;
|
str << std::dec << std::endl;
|
||||||
|
if (lang.size()){
|
||||||
|
str << std::string(indent + 2, ' ') << "Language: " << lang << std::endl;
|
||||||
|
}
|
||||||
if (type == "audio") {
|
if (type == "audio") {
|
||||||
str << std::string(indent + 2, ' ') << "Rate: " << rate << std::endl;
|
str << std::string(indent + 2, ' ') << "Rate: " << rate << std::endl;
|
||||||
str << std::string(indent + 2, ' ') << "Size: " << size << std::endl;
|
str << std::string(indent + 2, ' ') << "Size: " << size << std::endl;
|
||||||
|
@ -1482,6 +1491,9 @@ namespace DTSC {
|
||||||
result << width << "x" << height << "_";
|
result << width << "x" << height << "_";
|
||||||
result << (double)fpks / 1000 << "fps";
|
result << (double)fpks / 1000 << "fps";
|
||||||
}
|
}
|
||||||
|
if (lang.size() && lang != "und"){
|
||||||
|
result << "_" << lang;
|
||||||
|
}
|
||||||
return result.str();
|
return result.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1505,6 +1517,9 @@ namespace DTSC {
|
||||||
}
|
}
|
||||||
result += parts.size() * 9 + 12;
|
result += parts.size() * 9 + 12;
|
||||||
}
|
}
|
||||||
|
if (lang.size() && lang != "und"){
|
||||||
|
result += 11 + lang.size();
|
||||||
|
}
|
||||||
if (type == "audio") {
|
if (type == "audio") {
|
||||||
result += 49;
|
result += 49;
|
||||||
} else if (type == "video") {
|
} else if (type == "video") {
|
||||||
|
@ -1588,6 +1603,11 @@ namespace DTSC {
|
||||||
writePointer(p, "\000\004type\002", 7);
|
writePointer(p, "\000\004type\002", 7);
|
||||||
writePointer(p, convertInt(type.size()), 4);
|
writePointer(p, convertInt(type.size()), 4);
|
||||||
writePointer(p, type);
|
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") {
|
if (type == "audio") {
|
||||||
writePointer(p, "\000\004rate\001", 7);
|
writePointer(p, "\000\004rate\001", 7);
|
||||||
writePointer(p, convertLongLong(rate), 8);
|
writePointer(p, convertLongLong(rate), 8);
|
||||||
|
@ -1660,6 +1680,11 @@ namespace DTSC {
|
||||||
conn.SendNow("\000\004type\002", 7);
|
conn.SendNow("\000\004type\002", 7);
|
||||||
conn.SendNow(convertInt(type.size()), 4);
|
conn.SendNow(convertInt(type.size()), 4);
|
||||||
conn.SendNow(type);
|
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") {
|
if (type == "audio") {
|
||||||
conn.SendNow("\000\004rate\001", 7);
|
conn.SendNow("\000\004rate\001", 7);
|
||||||
conn.SendNow(convertLongLong(rate), 8);
|
conn.SendNow(convertLongLong(rate), 8);
|
||||||
|
@ -1786,6 +1811,9 @@ namespace DTSC {
|
||||||
result["parts"] = tmp;
|
result["parts"] = tmp;
|
||||||
}
|
}
|
||||||
result["init"] = init;
|
result["init"] = init;
|
||||||
|
if (lang.size() && lang != "und"){
|
||||||
|
result["lang"] = lang;
|
||||||
|
}
|
||||||
result["trackid"] = trackID;
|
result["trackid"] = trackID;
|
||||||
result["firstms"] = (long long)firstms;
|
result["firstms"] = (long long)firstms;
|
||||||
result["lastms"] = (long long)lastms;
|
result["lastms"] = (long long)lastms;
|
||||||
|
|
|
@ -989,17 +989,85 @@ namespace TS {
|
||||||
while (entry) {
|
while (entry) {
|
||||||
output << std::string(indent + 4, ' ');
|
output << std::string(indent + 4, ' ');
|
||||||
stream_pids[entry.getElementaryPid()] = entry.getCodec() + std::string(" ") + entry.getStreamTypeString();
|
stream_pids[entry.getElementaryPid()] = entry.getCodec() + std::string(" ") + entry.getStreamTypeString();
|
||||||
output << "Stream " << entry.getElementaryPid() << ": " << stream_pids[entry.getElementaryPid()] << " (" << entry.getStreamType() << "), Info (" << entry.getESInfoLength() << ") = ";
|
output << "Stream " << entry.getElementaryPid() << ": " << stream_pids[entry.getElementaryPid()] << " (" << entry.getStreamType() << ")" << std::endl;
|
||||||
for (unsigned int i = 0; i<entry.getESInfoLength(); ++i){
|
output << ProgramDescriptors(entry.getESInfo(), entry.getESInfoLength()).toPrettyString(indent+6);
|
||||||
output << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << (int)entry.getESInfo()[i] << std::dec;
|
|
||||||
}
|
|
||||||
output << std::endl;
|
|
||||||
entry.advance();
|
entry.advance();
|
||||||
}
|
}
|
||||||
output << std::string(indent + 2, ' ') << "CRC32: " << std::hex << std::setw(8) << std::setfill('0') << std::uppercase << getCRC() << std::dec << std::endl;
|
output << std::string(indent + 2, ' ') << "CRC32: " << std::hex << std::setw(8) << std::setfill('0') << std::uppercase << getCRC() << std::dec << std::endl;
|
||||||
return output.str();
|
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.
|
/// 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.
|
/// This function is not part of the packet class, but it is in the TS namespace.
|
||||||
|
@ -1018,6 +1086,12 @@ namespace TS {
|
||||||
if (myMeta.tracks[*it].codec == "ID3"){
|
if (myMeta.tracks[*it].codec == "ID3"){
|
||||||
sectionLen += myMeta.tracks[*it].init.size();
|
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.setSectionLength(0xB00D + sectionLen);
|
||||||
PMT.setProgramNumber(1);
|
PMT.setProgramNumber(1);
|
||||||
|
@ -1047,6 +1121,14 @@ namespace TS {
|
||||||
entry.setStreamType(0x1B);
|
entry.setStreamType(0x1B);
|
||||||
}else if (myMeta.tracks[*it].codec == "AAC"){
|
}else if (myMeta.tracks[*it].codec == "AAC"){
|
||||||
entry.setStreamType(0x0F);
|
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"){
|
}else if (myMeta.tracks[*it].codec == "MP3"){
|
||||||
entry.setStreamType(0x03);
|
entry.setStreamType(0x03);
|
||||||
}else if (myMeta.tracks[*it].codec == "ID3"){
|
}else if (myMeta.tracks[*it].codec == "ID3"){
|
||||||
|
|
|
@ -102,6 +102,16 @@ namespace TS {
|
||||||
std::string toPrettyString(size_t indent) const;
|
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 {
|
class ProgramMappingEntry {
|
||||||
public:
|
public:
|
||||||
ProgramMappingEntry(char * begin, char * end);
|
ProgramMappingEntry(char * begin, char * end);
|
||||||
|
|
Loading…
Add table
Reference in a new issue