Merge branch 'development' into LTS_development
# Conflicts: # src/output/output_httpts.cpp # src/output/output_ts_base.h
This commit is contained in:
commit
aebeeabd2b
27 changed files with 41179 additions and 385 deletions
|
@ -8,6 +8,7 @@
|
|||
#include <map>
|
||||
#include "ts_packet.h"
|
||||
#include "defines.h"
|
||||
#include "bitfields.h"
|
||||
|
||||
#ifndef FILLER_DATA
|
||||
#define FILLER_DATA "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent commodo vulputate urna eu commodo. Cras tempor velit nec nulla placerat volutpat. Proin eleifend blandit quam sit amet suscipit. Pellentesque vitae tristique lorem. Maecenas facilisis consequat neque, vitae iaculis eros vulputate ut. Suspendisse ut arcu non eros vestibulum pulvinar id sed erat. Nam dictum tellus vel tellus rhoncus ut mollis tellus fermentum. Fusce volutpat consectetur ante, in mollis nisi euismod vulputate. Curabitur vitae facilisis ligula. Sed sed gravida dolor. Integer eu eros a dolor lobortis ullamcorper. Mauris interdum elit non neque interdum dictum. Suspendisse imperdiet eros sed sapien cursus pulvinar. Vestibulum ut dolor lectus, id commodo elit. Cras convallis varius leo eu porta. Duis luctus sapien nec dui adipiscing quis interdum nunc congue. Morbi pharetra aliquet mauris vitae tristique. Etiam feugiat sapien quis augue elementum id ultricies magna vulputate. Phasellus luctus, leo id egestas consequat, eros tortor commodo neque, vitae hendrerit nunc sem ut odio."
|
||||
|
@ -224,6 +225,7 @@ namespace TS {
|
|||
}
|
||||
|
||||
/// Prints a packet to stdout, for analyser purposes.
|
||||
/// If detail level contains bitmask 64, prints raw bytes after packet.
|
||||
std::string Packet::toPrettyString(size_t indent, int detailLevel) const{
|
||||
if (!(*this)){
|
||||
return "[Invalid packet - no sync byte]";
|
||||
|
@ -234,12 +236,13 @@ namespace TS {
|
|||
case 0: output << "PAT"; break;
|
||||
case 1: output << "CAT"; break;
|
||||
case 2: output << "TSDT"; break;
|
||||
case 17: output << "SDT"; break;
|
||||
case 0x1FFF: output << "Null"; break;
|
||||
default:
|
||||
if (pmt_pids.count(getPID())){
|
||||
if (isPMT()){
|
||||
output << "PMT";
|
||||
}else{
|
||||
if (stream_pids.count(getPID())){
|
||||
if (isStream()){
|
||||
output << stream_pids[getPID()];
|
||||
}else{
|
||||
output << "Unknown";
|
||||
|
@ -271,25 +274,23 @@ namespace TS {
|
|||
output << std::endl;
|
||||
if (!getPID()) {
|
||||
//PAT
|
||||
if (detailLevel >= 2){
|
||||
output << ((ProgramAssociationTable *)this)->toPrettyString(indent + 2);
|
||||
}else{
|
||||
((ProgramAssociationTable *)this)->toPrettyString(indent + 2);
|
||||
}
|
||||
output << ((ProgramAssociationTable *)this)->toPrettyString(indent + 2);
|
||||
return output.str();
|
||||
}
|
||||
|
||||
|
||||
if (pmt_pids.count(getPID())){
|
||||
//PMT
|
||||
if (detailLevel >= 2){
|
||||
output << ((ProgramMappingTable *)this)->toPrettyString(indent + 2);
|
||||
}else{
|
||||
((ProgramMappingTable *)this)->toPrettyString(indent + 2);
|
||||
}
|
||||
output << ((ProgramMappingTable *)this)->toPrettyString(indent + 2);
|
||||
return output.str();
|
||||
}
|
||||
|
||||
if (detailLevel >= 10){
|
||||
if (getPID() == 17){
|
||||
//SDT
|
||||
output << ((ServiceDescriptionTable *)this)->toPrettyString(indent + 2);
|
||||
return output.str();
|
||||
}
|
||||
|
||||
if (detailLevel & 64){
|
||||
output << std::string(indent+2, ' ') << "Raw data bytes:";
|
||||
unsigned int size = getDataSize();
|
||||
|
||||
|
@ -313,11 +314,17 @@ namespace TS {
|
|||
}
|
||||
|
||||
/// Returns true if this PID contains a PMT.
|
||||
/// Important caveat: only works if the corresponding PAT has been pretty-printed earlier!
|
||||
/// Important caveat: only works if the corresponding PAT has been pretty-printed or had parsePIDs() called on it!
|
||||
bool Packet::isPMT() const{
|
||||
return pmt_pids.count(getPID());
|
||||
}
|
||||
|
||||
/// Returns true if this PID contains a stream known from a PMT.
|
||||
/// Important caveat: only works if the corresponding PMT was pretty-printed or had parseStreams() called on it!
|
||||
bool Packet::isStream() const{
|
||||
return stream_pids.count(getPID());
|
||||
}
|
||||
|
||||
/// Sets the start of a new unit in this Packet.
|
||||
/// \param NewVal The new value for the start of a unit.
|
||||
void Packet::setUnitStart(bool NewVal) {
|
||||
|
@ -480,8 +487,13 @@ namespace TS {
|
|||
/// Prepends the lead-in to variable toSend, assumes toSend's length is all other data.
|
||||
/// \param len The length of this frame.
|
||||
/// \param PTS The timestamp of the frame.
|
||||
std::string & Packet::getPESVideoLeadIn(unsigned int len, unsigned long long PTS, unsigned long long offset, bool isAligned) {
|
||||
std::string & Packet::getPESVideoLeadIn(unsigned int len, unsigned long long PTS, unsigned long long offset, bool isAligned, uint64_t bps) {
|
||||
len += (offset ? 13 : 8);
|
||||
if (bps >= 50){
|
||||
len += 3;
|
||||
}else{
|
||||
bps = 0;
|
||||
}
|
||||
static std::string tmpStr;
|
||||
tmpStr.clear();
|
||||
tmpStr.reserve(25);
|
||||
|
@ -493,12 +505,17 @@ namespace TS {
|
|||
}else{
|
||||
tmpStr.append("\200", 1);
|
||||
}
|
||||
tmpStr += (char)(offset ? 0xC0 : 0x80) ; //PTS/DTS + Flags
|
||||
tmpStr += (char)(offset ? 0x0A : 0x05); //PESHeaderDataLength
|
||||
tmpStr += (char)((offset ? 0xC0 : 0x80) | (bps?0x10:0)) ; //PTS/DTS + Flags
|
||||
tmpStr += (char)((offset ? 10 : 5) + (bps?3:0)); //PESHeaderDataLength
|
||||
encodePESTimestamp(tmpStr, (offset ? 0x30 : 0x20), PTS + offset);
|
||||
if (offset){
|
||||
encodePESTimestamp(tmpStr, 0x10, PTS);
|
||||
}
|
||||
if (bps){
|
||||
char rate_buf[3];
|
||||
Bit::htob24(rate_buf, (bps/50) | 0x800001);
|
||||
tmpStr.append(rate_buf, 3);
|
||||
}
|
||||
return tmpStr;
|
||||
}
|
||||
|
||||
|
@ -506,16 +523,28 @@ namespace TS {
|
|||
/// Prepends the lead-in to variable toSend, assumes toSend's length is all other data.
|
||||
/// \param len The length of this frame.
|
||||
/// \param PTS The timestamp of the frame.
|
||||
std::string & Packet::getPESAudioLeadIn(unsigned int len, unsigned long long PTS) {
|
||||
std::string & Packet::getPESAudioLeadIn(unsigned int len, unsigned long long PTS, uint64_t bps) {
|
||||
if (bps >= 50){
|
||||
len += 3;
|
||||
}else{
|
||||
bps = 0;
|
||||
}
|
||||
static std::string tmpStr;
|
||||
tmpStr.clear();
|
||||
tmpStr.reserve(14);
|
||||
tmpStr.reserve(20);
|
||||
len += 8;
|
||||
tmpStr.append("\000\000\001\300", 4);
|
||||
tmpStr += (char)((len & 0xFF00) >> 8); //PES PacketLength
|
||||
tmpStr += (char)(len & 0x00FF); //PES PacketLength (Cont)
|
||||
tmpStr.append("\204\200\005", 3);
|
||||
tmpStr += (char)0x84;//isAligned
|
||||
tmpStr += (char)(0x80 | (bps?0x10:0)) ; //PTS/DTS + Flags
|
||||
tmpStr += (char)(5 + (bps?3:0)); //PESHeaderDataLength
|
||||
encodePESTimestamp(tmpStr, 0x20, PTS);
|
||||
if (bps){
|
||||
char rate_buf[3];
|
||||
Bit::htob24(rate_buf, (bps/50) | 0x800001);
|
||||
tmpStr.append(rate_buf, 3);
|
||||
}
|
||||
return tmpStr;
|
||||
}
|
||||
//END PES FUNCTIONS
|
||||
|
@ -641,7 +670,7 @@ namespace TS {
|
|||
///Retrieves the "current/next" indicator
|
||||
bool ProgramAssociationTable::getCurrentNextIndicator() const{
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 6;
|
||||
return (strBuf[loc] >> 1) & 0x01;
|
||||
return strBuf[loc] & 0x01;
|
||||
}
|
||||
|
||||
///Retrieves the section number
|
||||
|
@ -809,7 +838,7 @@ namespace TS {
|
|||
data += 5 + getESInfoLength();
|
||||
}
|
||||
|
||||
ProgramMappingTable::ProgramMappingTable(){
|
||||
ProgramMappingTable::ProgramMappingTable(){
|
||||
strBuf[0] = 0x47;
|
||||
strBuf[1] = 0x50;
|
||||
strBuf[2] = 0x00;
|
||||
|
@ -876,20 +905,20 @@ namespace TS {
|
|||
void ProgramMappingTable::setVersionNumber(char newVal) {
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 6;
|
||||
updPos(loc+1);
|
||||
strBuf[loc] = ((newVal & 0x1F) << 1) | 0xC1;
|
||||
strBuf[loc] = ((newVal & 0x1F) << 1) | (strBuf[loc] & 0xC1);
|
||||
}
|
||||
|
||||
///Retrieves the "current/next" indicator
|
||||
bool ProgramMappingTable::getCurrentNextIndicator() const{
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 6;
|
||||
return (strBuf[loc] >> 1) & 0x01;
|
||||
return strBuf[loc] & 0x01;
|
||||
}
|
||||
|
||||
///Sets the "current/next" indicator
|
||||
void ProgramMappingTable::setCurrentNextIndicator(bool newVal) {
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 6;
|
||||
updPos(loc+1);
|
||||
strBuf[loc] = (((char)newVal) << 1) | (strBuf[loc] & 0xFD) | 0xC1;
|
||||
strBuf[loc] = (newVal?1:0) | (strBuf[loc] & 0xFE);
|
||||
}
|
||||
|
||||
///Retrieves the section number
|
||||
|
@ -969,6 +998,15 @@ namespace TS {
|
|||
memset((void*)(strBuf + loc + 4), 0xFF, 184 - loc);
|
||||
}
|
||||
|
||||
/// Parses the PMT for streams, keeping track of their PIDs to make the Packet::isStream() function work
|
||||
void ProgramMappingTable::parseStreams(){
|
||||
ProgramMappingEntry entry = getEntry(0);
|
||||
while (entry) {
|
||||
stream_pids[entry.getElementaryPid()] = entry.getCodec() + std::string(" ") + entry.getStreamTypeString();
|
||||
entry.advance();
|
||||
}
|
||||
}
|
||||
|
||||
///Print all PMT values in a human readable format
|
||||
///\param indent The indentation of the string printed as wanted by the user
|
||||
///\return The string with human readable data from a PMT table
|
||||
|
@ -1028,6 +1066,22 @@ namespace TS {
|
|||
offset += 4;
|
||||
}
|
||||
} break;
|
||||
case 0x48:{//DVB service descriptor
|
||||
output << std::string(indent, ' ') << "DVB service: ";
|
||||
uint32_t offset = p+2;
|
||||
switch (p_data[offset]){
|
||||
case 0x01: output << "digital TV"; break;
|
||||
case 0x02: output << "digital radio"; break;
|
||||
case 0x10: output << "DVB MHP"; break;
|
||||
default: output << "NOT IMPLEMENTED"; break;
|
||||
}
|
||||
offset++;//move to provider len
|
||||
uint8_t len = p_data[offset];
|
||||
output << ", Provider: " << std::string(p_data+offset+1, len);
|
||||
offset += 1+len;//move to service len
|
||||
len = p_data[offset];
|
||||
output << ", Service: " << std::string(p_data+offset+1, len) << std::endl;
|
||||
} 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: ";
|
||||
|
@ -1057,6 +1111,9 @@ namespace TS {
|
|||
}
|
||||
}
|
||||
} break;
|
||||
case 0x52:{//DVB stream identifier
|
||||
output << std::string(indent, ' ') << "Stream identifier: Tag #" << (int)p_data[p+2] << std::endl;
|
||||
} break;
|
||||
default:{
|
||||
output << std::string(indent, ' ') << "Undecoded descriptor: ";
|
||||
for (uint32_t i = 0; i<p_data[p+1]+2; ++i){
|
||||
|
@ -1096,7 +1153,7 @@ namespace TS {
|
|||
PMT.setSectionLength(0xB00D + sectionLen);
|
||||
PMT.setProgramNumber(1);
|
||||
PMT.setVersionNumber(0);
|
||||
PMT.setCurrentNextIndicator(0);
|
||||
PMT.setCurrentNextIndicator(1);
|
||||
PMT.setSectionNumber(0);
|
||||
PMT.setLastSectionNumber(0);
|
||||
PMT.setContinuityCounter(contCounter);
|
||||
|
@ -1145,6 +1202,297 @@ namespace TS {
|
|||
return PMT.checkAndGetBuffer();
|
||||
}
|
||||
|
||||
|
||||
ServiceDescriptionEntry::ServiceDescriptionEntry(char * begin, char * end){
|
||||
data = begin;
|
||||
boundary = end;
|
||||
}
|
||||
|
||||
ServiceDescriptionEntry::operator bool() const {
|
||||
return data && (data < boundary);
|
||||
}
|
||||
|
||||
uint16_t ServiceDescriptionEntry::getServiceID() const{
|
||||
return Bit::btohs(data);
|
||||
}
|
||||
|
||||
void ServiceDescriptionEntry::setServiceID(uint16_t val){
|
||||
Bit::htobs(data, val);
|
||||
}
|
||||
|
||||
bool ServiceDescriptionEntry::getEITSchedule() const{
|
||||
return data[2] & 2;
|
||||
}
|
||||
|
||||
void ServiceDescriptionEntry::setEITSchedule(bool val){
|
||||
data[2] |= 2;
|
||||
}
|
||||
|
||||
bool ServiceDescriptionEntry::getEITPresentFollowing() const{
|
||||
return data[2] & 1;
|
||||
}
|
||||
|
||||
void ServiceDescriptionEntry::setEITPresentFollowing(bool val){
|
||||
data[2] |= 1;
|
||||
}
|
||||
|
||||
uint8_t ServiceDescriptionEntry::getRunningStatus() const{
|
||||
return (data[3] & 0xE0) >> 5;
|
||||
}
|
||||
|
||||
void ServiceDescriptionEntry::setRunningStatus(uint8_t val){
|
||||
data[3] = (data[3] & 0x1F) | (val << 5);
|
||||
}
|
||||
|
||||
bool ServiceDescriptionEntry::getFreeCAM() const{
|
||||
return data[3] & 0x10;
|
||||
}
|
||||
|
||||
void ServiceDescriptionEntry::setFreeCAM(bool val){
|
||||
data[3] = (data[3] & 0xEF) | (val?0x10:0);
|
||||
}
|
||||
|
||||
int ServiceDescriptionEntry::getESInfoLength() const{
|
||||
return ((data[3] << 8) | data[4]) & 0x0FFF;
|
||||
}
|
||||
|
||||
const char * ServiceDescriptionEntry::getESInfo() const{
|
||||
return data + 5;
|
||||
}
|
||||
|
||||
void ServiceDescriptionEntry::setESInfo(const std::string & newInfo){
|
||||
data[3] = ((newInfo.size() >> 8) & 0x0F) | (data[3] & 0xF0);
|
||||
data[4] = newInfo.size() & 0xFF;
|
||||
memcpy(data + 5, newInfo.data(), newInfo.size());
|
||||
}
|
||||
|
||||
void ServiceDescriptionEntry::advance(){
|
||||
if (!(*this)) {
|
||||
return;
|
||||
}
|
||||
data += 5 + getESInfoLength();
|
||||
}
|
||||
|
||||
ServiceDescriptionTable::ServiceDescriptionTable(){
|
||||
strBuf[0] = 0x47;
|
||||
strBuf[1] = 0x50;
|
||||
strBuf[2] = 0x00;
|
||||
strBuf[3] = 0x10;
|
||||
pos=4;
|
||||
}
|
||||
|
||||
ServiceDescriptionTable & ServiceDescriptionTable::operator = (const Packet & rhs) {
|
||||
memcpy(strBuf, rhs.checkAndGetBuffer(), 188);
|
||||
pos = 188;
|
||||
return *this;
|
||||
}
|
||||
|
||||
char ServiceDescriptionTable::getOffset() const{
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0);
|
||||
return strBuf[loc];
|
||||
}
|
||||
|
||||
void ServiceDescriptionTable::setOffset(char newVal) {
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0);
|
||||
strBuf[loc] = newVal;
|
||||
}
|
||||
|
||||
char ServiceDescriptionTable::getTableId() const{
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 1;
|
||||
return strBuf[loc];
|
||||
}
|
||||
|
||||
void ServiceDescriptionTable::setTableId(char newVal) {
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 1;
|
||||
updPos(loc+1);
|
||||
strBuf[loc] = newVal;
|
||||
}
|
||||
|
||||
short ServiceDescriptionTable::getSectionLength() const{
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 2;
|
||||
return (((short)strBuf[loc] & 0x0F) << 8) | strBuf[loc + 1];
|
||||
}
|
||||
|
||||
void ServiceDescriptionTable::setSectionLength(short newVal) {
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 2;
|
||||
updPos(loc+2);
|
||||
strBuf[loc] = (char)(newVal >> 8);
|
||||
strBuf[loc+1] = (char)newVal;
|
||||
}
|
||||
|
||||
uint16_t ServiceDescriptionTable::getTSStreamID() const{
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 4;
|
||||
return (((short)strBuf[loc]) << 8) | strBuf[loc + 1];
|
||||
}
|
||||
|
||||
void ServiceDescriptionTable::setTSStreamID(uint16_t newVal) {
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 4;
|
||||
updPos(loc+2);
|
||||
strBuf[loc] = (char)(newVal >> 8);
|
||||
strBuf[loc+1] = (char)newVal;
|
||||
}
|
||||
|
||||
uint8_t ServiceDescriptionTable::getVersionNumber() const{
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 6;
|
||||
return (strBuf[loc] >> 1) & 0x1F;
|
||||
}
|
||||
|
||||
void ServiceDescriptionTable::setVersionNumber(uint8_t newVal) {
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 6;
|
||||
updPos(loc+1);
|
||||
strBuf[loc] = ((newVal & 0x1F) << 1) | (strBuf[loc] & 0xC1);
|
||||
}
|
||||
|
||||
///Retrieves the "current/next" indicator
|
||||
bool ServiceDescriptionTable::getCurrentNextIndicator() const{
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 6;
|
||||
return strBuf[loc] & 0x01;
|
||||
}
|
||||
|
||||
///Sets the "current/next" indicator
|
||||
void ServiceDescriptionTable::setCurrentNextIndicator(bool newVal) {
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 6;
|
||||
updPos(loc+1);
|
||||
strBuf[loc] = (newVal?1:0) | (strBuf[loc] & 0xFE);
|
||||
}
|
||||
|
||||
///Retrieves the section number
|
||||
uint8_t ServiceDescriptionTable::getSectionNumber() const{
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 7;
|
||||
return strBuf[loc];
|
||||
}
|
||||
|
||||
///Sets the section number
|
||||
void ServiceDescriptionTable::setSectionNumber(uint8_t newVal) {
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 7;
|
||||
updPos(loc+1);
|
||||
strBuf[loc] = newVal;
|
||||
}
|
||||
|
||||
///Retrieves the last section number
|
||||
uint8_t ServiceDescriptionTable::getLastSectionNumber() const{
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 8;
|
||||
return strBuf[loc];
|
||||
}
|
||||
|
||||
///Sets the last section number
|
||||
void ServiceDescriptionTable::setLastSectionNumber(uint8_t newVal) {
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 8;
|
||||
updPos(loc+1);
|
||||
strBuf[loc] = newVal;
|
||||
}
|
||||
|
||||
uint16_t ServiceDescriptionTable::getOrigID() const{
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 9;
|
||||
return (((short)strBuf[loc] & 0x1F) << 8) | strBuf[loc + 1];
|
||||
}
|
||||
|
||||
void ServiceDescriptionTable::setOrigID(uint16_t newVal) {
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 9;
|
||||
updPos(loc+2);
|
||||
strBuf[loc] = (char)((newVal >> 8) & 0x1F) | 0xE0;//Note: here we set reserved bits on 1
|
||||
strBuf[loc+1] = (char)newVal;
|
||||
}
|
||||
|
||||
ServiceDescriptionEntry ServiceDescriptionTable::getEntry(int index) const{
|
||||
int dataOffset = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset();
|
||||
ServiceDescriptionEntry res((char*)(strBuf + dataOffset + 12), (char*)(strBuf + dataOffset + getSectionLength()) );
|
||||
for (int i = 0; i < index; i++){
|
||||
res.advance();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int ServiceDescriptionTable::getCRC() const{
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + getSectionLength();
|
||||
return ((int)(strBuf[loc]) << 24) | ((int)(strBuf[loc + 1]) << 16) | ((int)(strBuf[loc + 2]) << 8) | strBuf[loc + 3];
|
||||
}
|
||||
|
||||
void ServiceDescriptionTable::calcCRC() {
|
||||
unsigned int loc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + getSectionLength();
|
||||
unsigned int newVal;//this will hold the CRC32 value;
|
||||
unsigned int pidLoc = 4 + (getAdaptationField() > 1 ? getAdaptationFieldLen() + 1 : 0) + getOffset() + 1;
|
||||
newVal = checksum::crc32(-1, strBuf + pidLoc, loc - pidLoc);//calculating checksum over all the fields from table ID to the last stream element
|
||||
updPos(188);
|
||||
strBuf[loc + 3] = (newVal >> 24) & 0xFF;
|
||||
strBuf[loc + 2] = (newVal >> 16) & 0xFF;
|
||||
strBuf[loc + 1] = (newVal >> 8) & 0xFF;
|
||||
strBuf[loc] = newVal & 0xFF;
|
||||
memset((void*)(strBuf + loc + 4), 0xFF, 184 - loc);
|
||||
}
|
||||
|
||||
///Print all SDT values in a human readable format
|
||||
///\param indent The indentation of the string printed as wanted by the user
|
||||
///\return The string with human readable data from a SDT table
|
||||
std::string ServiceDescriptionTable::toPrettyString(size_t indent) const{
|
||||
std::stringstream output;
|
||||
output << std::string(indent, ' ') << "[Service Description Table]" << std::endl;
|
||||
output << std::string(indent + 2, ' ') << "Pointer Field: " << (int)getOffset() << std::endl;
|
||||
output << std::string(indent + 2, ' ') << "Table ID: " << (int)getTableId() << std::endl;
|
||||
output << std::string(indent + 2, ' ') << "Section Length: " << getSectionLength() << std::endl;
|
||||
output << std::string(indent + 2, ' ') << "TS Stream ID: " << getTSStreamID() << std::endl;
|
||||
output << std::string(indent + 2, ' ') << "Version number: " << (int)getVersionNumber() << std::endl;
|
||||
output << std::string(indent + 2, ' ') << "Current next indicator: " << (int)getCurrentNextIndicator() << std::endl;
|
||||
output << std::string(indent + 2, ' ') << "Section number: " << (int)getSectionNumber() << std::endl;
|
||||
output << std::string(indent + 2, ' ') << "Last Section number: " << (int)getLastSectionNumber() << std::endl;
|
||||
output << std::string(indent + 2, ' ') << "Original Network ID: " << getOrigID() << std::endl;
|
||||
ServiceDescriptionEntry entry = getEntry(0);
|
||||
while (entry) {
|
||||
output << std::string(indent + 4, ' ');
|
||||
output << "Service " << entry.getServiceID() << ":";
|
||||
|
||||
if (entry.getEITSchedule()){output << " EIT";}
|
||||
if (entry.getEITPresentFollowing()){output << " EITPF";}
|
||||
if (entry.getFreeCAM()){output << " Free";}
|
||||
switch (entry.getRunningStatus()){
|
||||
case 0: output << " Undefined"; break;
|
||||
case 1: output << " NotRunning"; break;
|
||||
case 2: output << " StartSoon"; break;
|
||||
case 3: output << " Pausing"; break;
|
||||
case 4: output << " Running"; break;
|
||||
case 5: output << " OffAir"; break;
|
||||
default: output << " UNIMPL?" << (int)entry.getRunningStatus(); break;
|
||||
}
|
||||
output << 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();
|
||||
}
|
||||
|
||||
/// Construct a SDT from a set of selected tracks and metadata.
|
||||
/// This function is not part of the packet class, but it is in the TS namespace.
|
||||
/// It uses an internal static TS packet for SDT storage.
|
||||
///\returns character pointer to a static 188B TS packet
|
||||
const char * createSDT(const std::string & streamName, int contCounter){
|
||||
static ServiceDescriptionTable SDT;
|
||||
SDT.setPID(0x11);
|
||||
SDT.setTableId(0x42);
|
||||
SDT.setSectionLength(0x8020 + streamName.size());
|
||||
SDT.setTSStreamID(1);
|
||||
SDT.setVersionNumber(0);
|
||||
SDT.setCurrentNextIndicator(1);
|
||||
SDT.setSectionNumber(0);
|
||||
SDT.setLastSectionNumber(0);
|
||||
SDT.setOrigID(1);
|
||||
ServiceDescriptionEntry entry = SDT.getEntry(0);
|
||||
entry.setServiceID(1);//Same as ProgramNumber in PMT
|
||||
entry.setRunningStatus(4);//Running
|
||||
entry.setFreeCAM(true);//Not conditional access
|
||||
std::string sdti;
|
||||
sdti += (char)0x48;
|
||||
sdti += (char)(15+streamName.size());//length
|
||||
sdti += (char)1;//digital television service
|
||||
sdti.append("\012MistServer");
|
||||
sdti += (char)streamName.size();
|
||||
sdti.append(streamName);
|
||||
entry.setESInfo(sdti);
|
||||
SDT.setContinuityCounter(contCounter);
|
||||
SDT.calcCRC();
|
||||
return SDT.checkAndGetBuffer();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ namespace TS {
|
|||
//Helper functions
|
||||
operator bool() const;
|
||||
bool isPMT() const;
|
||||
bool isStream() const;
|
||||
void clear();
|
||||
void setDefaultPAT();
|
||||
unsigned int getDataSize() const;
|
||||
|
@ -69,8 +70,8 @@ namespace TS {
|
|||
void updPos(unsigned int newPos);
|
||||
|
||||
//PES helpers
|
||||
static std::string & getPESVideoLeadIn(unsigned int len, unsigned long long PTS, unsigned long long offset, bool isAligned);
|
||||
static std::string & getPESAudioLeadIn(unsigned int len, unsigned long long PTS);
|
||||
static std::string & getPESVideoLeadIn(unsigned int len, unsigned long long PTS, unsigned long long offset, bool isAligned, uint64_t bps=0);
|
||||
static std::string & getPESAudioLeadIn(unsigned int len, unsigned long long PTS, uint64_t bps=0);
|
||||
|
||||
//Printers and writers
|
||||
std::string toPrettyString(size_t indent = 0, int detailLevel = 3) const;
|
||||
|
@ -157,7 +158,61 @@ namespace TS {
|
|||
void setPCRPID(short newVal);
|
||||
short getProgramInfoLength() const;
|
||||
void setProgramInfoLength(short newVal);
|
||||
ProgramMappingEntry getEntry(int index) const;
|
||||
void parseStreams();
|
||||
ProgramMappingEntry getEntry(int index) const;
|
||||
int getCRC() const;
|
||||
void calcCRC();
|
||||
std::string toPrettyString(size_t indent) const;
|
||||
};
|
||||
|
||||
class ServiceDescriptionEntry {
|
||||
public:
|
||||
ServiceDescriptionEntry(char * begin, char * end);
|
||||
operator bool() const;
|
||||
uint16_t getServiceID() const;
|
||||
void setServiceID(uint16_t newType);
|
||||
bool getEITSchedule() const;
|
||||
void setEITSchedule(bool val);
|
||||
bool getEITPresentFollowing() const;
|
||||
void setEITPresentFollowing(bool val);
|
||||
uint8_t getRunningStatus() const;
|
||||
void setRunningStatus(uint8_t val);
|
||||
bool getFreeCAM() const;
|
||||
void setFreeCAM(bool val);
|
||||
int getESInfoLength() const;
|
||||
const char * getESInfo() const;
|
||||
void setESInfo(const std::string & newInfo);
|
||||
void advance();
|
||||
private:
|
||||
char* data;
|
||||
char* boundary;
|
||||
};
|
||||
|
||||
class ServiceDescriptionTable : public Packet {
|
||||
public:
|
||||
ServiceDescriptionTable();
|
||||
ServiceDescriptionTable & operator = (const Packet & rhs);
|
||||
char getOffset() const;
|
||||
void setOffset(char newVal);
|
||||
|
||||
char getTableId() const;
|
||||
void setTableId(char newVal);
|
||||
short getSectionLength() const;
|
||||
void setSectionLength(short newVal);
|
||||
|
||||
uint16_t getTSStreamID() const;
|
||||
void setTSStreamID(uint16_t newVal);
|
||||
uint8_t getVersionNumber() const;
|
||||
void setVersionNumber(uint8_t newVal);
|
||||
bool getCurrentNextIndicator() const;
|
||||
void setCurrentNextIndicator(bool newVal);
|
||||
uint8_t getSectionNumber() const;
|
||||
void setSectionNumber(uint8_t newVal);
|
||||
uint8_t getLastSectionNumber() const;
|
||||
void setLastSectionNumber(uint8_t newVal);
|
||||
uint16_t getOrigID() const;
|
||||
void setOrigID(uint16_t newVal);
|
||||
ServiceDescriptionEntry getEntry(int index) const;
|
||||
int getCRC() const;
|
||||
void calcCRC();
|
||||
std::string toPrettyString(size_t indent) const;
|
||||
|
@ -208,6 +263,7 @@ namespace TS {
|
|||
};
|
||||
|
||||
const char * createPMT(std::set<unsigned long>& selectedTracks, DTSC::Meta& myMeta, int contCounter=0);
|
||||
const char * createSDT(const std::string & streamName, int contCounter=0);
|
||||
|
||||
} //TS namespace
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue