CMAF Push Output
This commit is contained in:
parent
0af992d405
commit
e217f41f17
7 changed files with 509 additions and 26 deletions
161
lib/cmaf.cpp
161
lib/cmaf.cpp
|
@ -1,14 +1,20 @@
|
|||
#include "cmaf.h"
|
||||
|
||||
namespace CMAF{
|
||||
size_t payloadSize(const DTSC::Meta &M, size_t track, size_t fragment){
|
||||
/// Function to determine the payload size of a CMAF fragment.
|
||||
/// \parm isKeyIndex indicates whether we are sending DTSC Fragment or DTSC Key based CMAF fragments.
|
||||
size_t payloadSize(const DTSC::Meta &M, size_t track, size_t index, bool isKeyIndex){
|
||||
DTSC::Fragments fragments(M.fragments(track));
|
||||
DTSC::Keys keys(M.keys(track));
|
||||
DTSC::Parts parts(M.parts(track));
|
||||
|
||||
size_t firstKey = fragments.getFirstKey(fragment);
|
||||
size_t firstKey = (isKeyIndex ? index : fragments.getFirstKey(index));
|
||||
size_t endKey = keys.getEndValid();
|
||||
if (fragment + 1 < fragments.getEndValid()){endKey = fragments.getFirstKey(fragment + 1);}
|
||||
if (isKeyIndex) {
|
||||
if (index + 1 < keys.getEndValid()){endKey = index + 1;}
|
||||
} else {
|
||||
if (index + 1 < fragments.getEndValid()){endKey = fragments.getFirstKey(index + 1);}
|
||||
}
|
||||
|
||||
size_t firstPart = keys.getFirstPart(firstKey);
|
||||
size_t endPart = parts.getEndValid();
|
||||
|
@ -22,13 +28,13 @@ namespace CMAF{
|
|||
// EDTS Box needed? + 36
|
||||
size_t res = 36 + 8 + 108 + 8 + 92 + 8 + 32 + 33 + 44 + 8 + 20 + 16 + 16 + 16 + 40;
|
||||
|
||||
res += M.getTrackIdentifier(track).size();
|
||||
res += M.getType(track).size();
|
||||
|
||||
// Type-specific boxes
|
||||
std::string tType = M.getType(track);
|
||||
if (tType == "video"){res += 20 + 16 + 86 + 16 + 8 + M.getInit(track).size();}
|
||||
if (tType == "video"){res += 20 + 16 + 86 + 16 + 8 + M.getInit(track).size() + 20;}//20 for btrt box
|
||||
if (tType == "audio"){
|
||||
res += 16 + 16 + 36 + 35 + (M.getInit(track).size() ? 2 + M.getInit(track).size() : 0);
|
||||
res += 16 + 16 + 36 + 35 + (M.getInit(track).size() ? 2 + M.getInit(track).size() : 0) + 20;//20 for btrt box
|
||||
}
|
||||
if (tType == "meta"){res += 12 + 16 + 64;}
|
||||
|
||||
|
@ -36,8 +42,16 @@ namespace CMAF{
|
|||
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t simplifiedTrackId(const DTSC::Meta & M, size_t idx) {
|
||||
std::string type = M.getType(idx);
|
||||
if (type == "video") {return 1;}
|
||||
if (type == "audio") {return 2;}
|
||||
if (type == "meta") {return 3;}
|
||||
return idx;
|
||||
}
|
||||
|
||||
std::string trackHeader(const DTSC::Meta &M, size_t track){
|
||||
std::string trackHeader(const DTSC::Meta &M, size_t track, bool simplifyTrackIds){
|
||||
std::string tType = M.getType(track);
|
||||
|
||||
std::stringstream header;
|
||||
|
@ -53,12 +67,15 @@ namespace CMAF{
|
|||
MP4::MOOV moovBox;
|
||||
|
||||
MP4::MVHD mvhdBox(0);
|
||||
mvhdBox.setTrackID(track + 2); // This value needs to point to an unused trackid
|
||||
mvhdBox.setTrackID(0xFFFFFFFF); // This value needs to point to an unused trackid
|
||||
moovBox.setContent(mvhdBox, 0);
|
||||
|
||||
MP4::TRAK trakBox;
|
||||
|
||||
MP4::TKHD tkhdBox(M, track);
|
||||
if (simplifyTrackIds){
|
||||
tkhdBox.setTrackID(simplifiedTrackId(M, track));
|
||||
}
|
||||
tkhdBox.setDuration(0);
|
||||
trakBox.setContent(tkhdBox, 0);
|
||||
|
||||
|
@ -67,7 +84,7 @@ namespace CMAF{
|
|||
MP4::MDHD mdhdBox(0, M.getLang(track));
|
||||
mdiaBox.setContent(mdhdBox, 0);
|
||||
|
||||
MP4::HDLR hdlrBox(tType, M.getTrackIdentifier(track));
|
||||
MP4::HDLR hdlrBox(tType, M.getType(track));
|
||||
mdiaBox.setContent(hdlrBox, 1);
|
||||
|
||||
MP4::MINF minfBox;
|
||||
|
@ -95,9 +112,21 @@ namespace CMAF{
|
|||
MP4::STSD stsdBox(0);
|
||||
if (tType == "video"){
|
||||
MP4::VisualSampleEntry sampleEntry(M, track);
|
||||
MP4::BTRT btrtBox;
|
||||
btrtBox.setDecodingBufferSize(0xFFFFFFFFull);
|
||||
btrtBox.setAverageBitrate(M.getBps(track));
|
||||
btrtBox.setMaxBitrate(M.getMaxBps(track));
|
||||
|
||||
sampleEntry.setBoxEntry(sampleEntry.getBoxEntryCount(),btrtBox);
|
||||
stsdBox.setEntry(sampleEntry, 0);
|
||||
}else if (tType == "audio"){
|
||||
MP4::AudioSampleEntry sampleEntry(M, track);
|
||||
MP4::BTRT btrtBox;
|
||||
btrtBox.setDecodingBufferSize(0xFFFFFFFFull);
|
||||
btrtBox.setAverageBitrate(M.getBps(track));
|
||||
btrtBox.setMaxBitrate(M.getMaxBps(track));
|
||||
|
||||
sampleEntry.setBoxEntry(sampleEntry.getBoxEntryCount(),btrtBox);
|
||||
stsdBox.setEntry(sampleEntry, 0);
|
||||
}else if (tType == "meta"){
|
||||
MP4::TextSampleEntry sampleEntry(M, track);
|
||||
|
@ -132,6 +161,9 @@ namespace CMAF{
|
|||
}
|
||||
|
||||
MP4::TREX trexBox(track + 1);
|
||||
if (simplifyTrackIds){
|
||||
trexBox.setTrackID(simplifiedTrackId(M, track));
|
||||
}
|
||||
trexBox.setDefaultSampleDuration(1000);
|
||||
mvexBox.setContent(trexBox, M.getVod() ? 1 : 0);
|
||||
|
||||
|
@ -196,7 +228,7 @@ namespace CMAF{
|
|||
return tmpRes;
|
||||
}
|
||||
|
||||
std::string fragmentHeader(const DTSC::Meta &M, size_t track, size_t fragment){
|
||||
std::string fragmentHeader(const DTSC::Meta &M, size_t track, size_t fragment, bool simplifyTrackIds, bool UTCTime){
|
||||
|
||||
DTSC::Fragments fragments(M.fragments(track));
|
||||
DTSC::Keys keys(M.keys(track));
|
||||
|
@ -258,18 +290,21 @@ namespace CMAF{
|
|||
|
||||
tfhdBox.setFlags(MP4::tfhdSampleFlag | MP4::tfhdBaseIsMoof | MP4::tfhdSampleDesc);
|
||||
tfhdBox.setTrackID(track + 1);
|
||||
if (simplifyTrackIds){
|
||||
tfhdBox.setTrackID(simplifiedTrackId(M, track));
|
||||
}
|
||||
tfhdBox.setDefaultSampleDuration(444);
|
||||
tfhdBox.setDefaultSampleSize(444);
|
||||
tfhdBox.setDefaultSampleFlags((M.getType(track) == "video") ? (MP4::noIPicture | MP4::noKeySample)
|
||||
: (MP4::isIPicture | MP4::isKeySample));
|
||||
tfhdBox.setSampleDescriptionIndex(0);
|
||||
tfhdBox.setSampleDescriptionIndex(1);
|
||||
trafBox.setContent(tfhdBox, 0);
|
||||
|
||||
MP4::TFDT tfdtBox;
|
||||
if (M.getVod()){
|
||||
tfdtBox.setBaseMediaDecodeTime(M.getTimeForFragmentIndex(track, fragment) - M.getFirstms(track));
|
||||
}else{
|
||||
tfdtBox.setBaseMediaDecodeTime(M.getTimeForFragmentIndex(track, fragment));
|
||||
tfdtBox.setBaseMediaDecodeTime((UTCTime ? Util::epoch()*1000 : M.getTimeForFragmentIndex(track, fragment)));
|
||||
}
|
||||
trafBox.setContent(tfdtBox, 1);
|
||||
|
||||
|
@ -299,4 +334,106 @@ namespace CMAF{
|
|||
|
||||
return header.str();
|
||||
}
|
||||
|
||||
/// Calculates the full size of a 'moof' box for a DTSC::Key based fragment.
|
||||
/// Used when building the 'moof' box to calculate the relative data offsets.
|
||||
size_t keyHeaderSize(const DTSC::Meta &M, size_t track, size_t key){
|
||||
uint64_t tmpRes = 8 + 16 + 32 + 20;
|
||||
|
||||
DTSC::Keys keys(M.keys(track));
|
||||
DTSC::Parts parts(M.parts(track));
|
||||
|
||||
size_t firstPart = keys.getFirstPart(key);
|
||||
size_t endPart = parts.getEndValid();
|
||||
if (key + 1 < keys.getEndValid()){
|
||||
endPart = keys.getFirstPart(key + 1);
|
||||
}
|
||||
|
||||
tmpRes += 24 + ((endPart - firstPart) * 12);
|
||||
return tmpRes;
|
||||
}
|
||||
|
||||
/// Generates the 'moof' box for a DTSC::Key based CMAF fragment.
|
||||
std::string keyHeader(const DTSC::Meta &M, size_t track, size_t key, bool simplifyTrackIds, bool UTCTime){
|
||||
DTSC::Keys keys(M.keys(track));
|
||||
DTSC::Parts parts(M.parts(track));
|
||||
|
||||
size_t firstPart = keys.getFirstPart(key);
|
||||
size_t endPart = parts.getEndValid();
|
||||
if (key + 1 < keys.getEndValid()){
|
||||
endPart = keys.getFirstPart(key + 1);
|
||||
}
|
||||
|
||||
std::stringstream header;
|
||||
|
||||
MP4::MOOF moofBox;
|
||||
MP4::MFHD mfhdBox(key + 1);
|
||||
moofBox.setContent(mfhdBox, 0);
|
||||
|
||||
|
||||
std::set<sortPart> trunOrder;
|
||||
|
||||
//We use keyHeaderSize here to determine the relative offsets of the data in the 'mdat' box.
|
||||
uint64_t relativeOffset = keyHeaderSize(M, track, key) + 8;
|
||||
|
||||
sortPart temp;
|
||||
temp.time = keys.getTime(key);
|
||||
temp.partIndex = firstPart;
|
||||
temp.bytePos = relativeOffset;
|
||||
|
||||
for (size_t p = firstPart; p < endPart; p++){
|
||||
trunOrder.insert(temp);
|
||||
temp.time += parts.getDuration(p);
|
||||
temp.partIndex++;
|
||||
temp.bytePos += parts.getSize(p);
|
||||
}
|
||||
|
||||
MP4::TRAF trafBox;
|
||||
MP4::TFHD tfhdBox;
|
||||
|
||||
tfhdBox.setFlags(MP4::tfhdSampleFlag | MP4::tfhdBaseIsMoof | MP4::tfhdSampleDesc);
|
||||
tfhdBox.setTrackID(track + 1);
|
||||
if (simplifyTrackIds){
|
||||
tfhdBox.setTrackID(simplifiedTrackId(M, track));
|
||||
}
|
||||
tfhdBox.setDefaultSampleDuration(444);
|
||||
tfhdBox.setDefaultSampleSize(444);
|
||||
tfhdBox.setDefaultSampleFlags((M.getType(track) == "video") ? (MP4::noIPicture | MP4::noKeySample)
|
||||
: (MP4::isIPicture | MP4::isKeySample));
|
||||
tfhdBox.setSampleDescriptionIndex(1);
|
||||
trafBox.setContent(tfhdBox, 0);
|
||||
|
||||
MP4::TFDT tfdtBox;
|
||||
if (M.getVod()){
|
||||
tfdtBox.setBaseMediaDecodeTime(keys.getTime(key) - M.getFirstms(track));
|
||||
}else{
|
||||
tfdtBox.setBaseMediaDecodeTime((UTCTime ? Util::epoch()*1000 : keys.getTime(key) ));
|
||||
}
|
||||
trafBox.setContent(tfdtBox, 1);
|
||||
|
||||
MP4::TRUN trunBox;
|
||||
trunBox.setFlags(MP4::trundataOffset | MP4::trunfirstSampleFlags | MP4::trunsampleSize |
|
||||
MP4::trunsampleDuration | MP4::trunsampleOffsets);
|
||||
|
||||
trunBox.setDataOffset(trunOrder.begin()->bytePos);
|
||||
|
||||
trunBox.setFirstSampleFlags(MP4::isIPicture | MP4::isKeySample);
|
||||
|
||||
size_t trunOffset = 0;
|
||||
|
||||
for (std::set<sortPart>::iterator it = trunOrder.begin(); it != trunOrder.end(); it++){
|
||||
MP4::trunSampleInformation sampleInfo;
|
||||
sampleInfo.sampleSize = parts.getSize(it->partIndex);
|
||||
sampleInfo.sampleDuration = parts.getDuration(it->partIndex);
|
||||
sampleInfo.sampleOffset = parts.getOffset(it->partIndex);
|
||||
trunBox.setSampleInformation(sampleInfo, trunOffset++);
|
||||
}
|
||||
trafBox.setContent(trunBox, 2);
|
||||
|
||||
moofBox.setContent(trafBox, 1);
|
||||
|
||||
header.write(moofBox.asBox(), moofBox.boxedSize());
|
||||
|
||||
return header.str();
|
||||
}
|
||||
}// namespace CMAF
|
||||
|
|
|
@ -4,9 +4,11 @@
|
|||
#include <set>
|
||||
|
||||
namespace CMAF{
|
||||
size_t payloadSize(const DTSC::Meta &M, size_t track, size_t fragment);
|
||||
size_t payloadSize(const DTSC::Meta &M, size_t track, size_t index, bool isKeyIndex = false);
|
||||
size_t trackHeaderSize(const DTSC::Meta &M, size_t track);
|
||||
std::string trackHeader(const DTSC::Meta &M, size_t track);
|
||||
std::string trackHeader(const DTSC::Meta &M, size_t track, bool simplifyTrackIds = false);
|
||||
size_t fragmentHeaderSize(const DTSC::Meta &M, size_t track, size_t fragment);
|
||||
std::string fragmentHeader(const DTSC::Meta &M, size_t track, size_t fragment);
|
||||
std::string fragmentHeader(const DTSC::Meta &M, size_t track, size_t fragment, bool simplifyTrackIds = false, bool UTCTime = false);
|
||||
size_t keyHeaderSize(const DTSC::Meta &M, size_t track, size_t key);
|
||||
std::string keyHeader(const DTSC::Meta &M, size_t track, size_t key, bool simplifyTrackIds = false, bool UTCTime = false);
|
||||
}// namespace CMAF
|
||||
|
|
|
@ -308,6 +308,7 @@ namespace MP4{
|
|||
case 0x74656E63: return ((TENC *)this)->toPrettyString(indent); break;
|
||||
case 0x7361697A: return ((SAIZ *)this)->toPrettyString(indent); break;
|
||||
case 0x7361696F: return ((SAIO *)this)->toPrettyString(indent); break;
|
||||
case 0x62747274: return ((BTRT *)this)->toPrettyString(indent); break;
|
||||
/*LTS-END*/
|
||||
default: INFO_MSG("no code found: 0x%.8x", Bit::btohl(data + 4)); break;
|
||||
}
|
||||
|
|
|
@ -75,6 +75,38 @@ namespace MP4{
|
|||
return r.str();
|
||||
}
|
||||
|
||||
BTRT::BTRT() {
|
||||
memcpy(data + 4, "btrt", 4);
|
||||
}
|
||||
|
||||
uint32_t BTRT::getDecodingBufferSize(){
|
||||
return getInt32(0);
|
||||
}
|
||||
void BTRT::setDecodingBufferSize(uint32_t val){
|
||||
setInt32(val, 0);
|
||||
}
|
||||
uint32_t BTRT::getMaxBitrate(){
|
||||
return getInt32(4);
|
||||
}
|
||||
void BTRT::setMaxBitrate(uint32_t val){
|
||||
setInt32(val, 4);
|
||||
}
|
||||
uint32_t BTRT::getAverageBitrate(){
|
||||
return getInt32(8);
|
||||
}
|
||||
void BTRT::setAverageBitrate(uint32_t val){
|
||||
setInt32(val, 8);
|
||||
}
|
||||
|
||||
std::string BTRT::toPrettyString(uint32_t indent) {
|
||||
std::stringstream r;
|
||||
r << std::string(indent, ' ') << "[btrt] Bitrate Box (" << boxedSize() << ")" << std::endl;
|
||||
r << std::string(indent+2, ' ') << "DecodingBufferSize: " << getDecodingBufferSize() << std::endl;
|
||||
r << std::string(indent+2, ' ') << "Maximum Bitrate: " << getMaxBitrate() << std::endl;
|
||||
r << std::string(indent+2, ' ') << "Average Bitrate: " << getAverageBitrate() << std::endl;
|
||||
return r.str();
|
||||
}
|
||||
|
||||
TRUN::TRUN(){memcpy(data + 4, "trun", 4);}
|
||||
|
||||
void TRUN::setFlags(uint32_t newFlags){setInt24(newFlags, 1);}
|
||||
|
@ -1217,6 +1249,14 @@ namespace MP4{
|
|||
memcpy(data + payloadOffset + 4, newMinorVersion, 4);
|
||||
}
|
||||
|
||||
std::string FTYP::getMinorVersionHex(){
|
||||
static char zero[4] ={0, 0, 0, 0};
|
||||
if (memcmp(zero, data + payloadOffset + 4, 4) == 0){return "";}
|
||||
char val[20];
|
||||
snprintf(val, 20, "%.2X%.2X%.2X%.2X", data[payloadOffset + 4], data[payloadOffset + 5], data[payloadOffset + 6], data[payloadOffset + 7]);
|
||||
return std::string(val);
|
||||
}
|
||||
|
||||
std::string FTYP::getMinorVersion(){
|
||||
static char zero[4] ={0, 0, 0, 0};
|
||||
if (memcmp(zero, data + payloadOffset + 4, 4) == 0){return "";}
|
||||
|
@ -1241,7 +1281,7 @@ namespace MP4{
|
|||
std::stringstream r;
|
||||
r << std::string(indent, ' ') << "[ftyp] File Type (" << boxedSize() << ")" << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "MajorBrand: " << getMajorBrand() << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "MinorVersion: " << getMinorVersion() << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "MinorVersion: 0x" << getMinorVersionHex() << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "CompatibleBrands (" << getCompatibleBrandsCount()
|
||||
<< "):" << std::endl;
|
||||
for (unsigned int i = 0; i < getCompatibleBrandsCount(); i++){
|
||||
|
@ -1765,7 +1805,7 @@ namespace MP4{
|
|||
if (i != getMatrixCount() - 1){r << ", ";}
|
||||
}
|
||||
r << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "TrackID: " << getTrackID() << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "next_track_ID: " << getTrackID() << std::endl;
|
||||
return r.str();
|
||||
}
|
||||
|
||||
|
@ -2887,6 +2927,55 @@ namespace MP4{
|
|||
}
|
||||
/*LTS-END*/
|
||||
|
||||
size_t AudioSampleEntry::getBoxEntryCount(){
|
||||
if (payloadSize() < 36){// if the EntryBox is not big enough to hold any box
|
||||
return 0;
|
||||
}
|
||||
size_t count = 0;
|
||||
size_t offset = 28;
|
||||
while (offset < payloadSize()){
|
||||
offset += getBoxLen(offset);
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
Box &AudioSampleEntry::getBoxEntry(size_t index){
|
||||
static Box ret = Box((char *)"\000\000\000\010erro", false);
|
||||
if (index >= getBoxEntryCount()){return ret;}
|
||||
size_t count = 0;
|
||||
size_t offset = 28;
|
||||
while (offset < payloadSize()){
|
||||
if (count == index){return getBox(offset);}
|
||||
offset += getBoxLen(offset);
|
||||
count++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AudioSampleEntry::setBoxEntry(size_t index, Box &box){
|
||||
if (index > getBoxEntryCount()){
|
||||
index = getBoxEntryCount();
|
||||
WARN_MSG("This function can not leave empty spaces, appending at index %zu nstead!", index);
|
||||
}
|
||||
size_t count = 0;
|
||||
size_t offset = 28;
|
||||
while (offset < payloadSize()){
|
||||
if (count == index){
|
||||
setBox(box, offset);
|
||||
return;
|
||||
}
|
||||
offset += getBoxLen(offset);
|
||||
count++;
|
||||
}
|
||||
if (count == index){
|
||||
setBox(box, offset);
|
||||
}else{
|
||||
INFO_MSG("Should not be here! Index is %zu, count is %zu, offset is %zu, payloadSize is %zu",
|
||||
index, count, offset, payloadSize());
|
||||
}
|
||||
}
|
||||
|
||||
std::string AudioSampleEntry::toPrettyAudioString(uint32_t indent, std::string name){
|
||||
std::stringstream r;
|
||||
r << std::string(indent, ' ') << name << " (" << boxedSize() << ")" << std::endl;
|
||||
|
@ -2895,10 +2984,13 @@ namespace MP4{
|
|||
r << std::string(indent + 1, ' ') << "SampleSize: " << getSampleSize() << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "PreDefined: " << getPreDefined() << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "SampleRate: " << getSampleRate() << std::endl;
|
||||
r << getCodecBox().toPrettyString(indent + 1) << std::endl;
|
||||
/*LTS-START*/
|
||||
if (isType("enca")){r << getSINFBox().toPrettyString(indent + 1);}
|
||||
/*LTS-END*/
|
||||
size_t firstBox = 0;
|
||||
if (getBoxEntryCount() > firstBox){
|
||||
for (size_t index = firstBox; index < getBoxEntryCount(); ++index){
|
||||
MP4::Box tmpBox = getBoxEntry(index);
|
||||
r << tmpBox.toPrettyString(indent + 1);
|
||||
}
|
||||
}
|
||||
return r.str();
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,19 @@ namespace MP4{
|
|||
};
|
||||
// TRAF Box
|
||||
|
||||
struct trunSampleInformation{
|
||||
class BTRT: public Box {
|
||||
public:
|
||||
BTRT();
|
||||
uint32_t getDecodingBufferSize();
|
||||
void setDecodingBufferSize(uint32_t val);
|
||||
uint32_t getMaxBitrate();
|
||||
void setMaxBitrate(uint32_t val);
|
||||
uint32_t getAverageBitrate();
|
||||
void setAverageBitrate(uint32_t val);
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
struct trunSampleInformation {
|
||||
uint32_t sampleDuration;
|
||||
uint32_t sampleSize;
|
||||
uint32_t sampleFlags;
|
||||
|
@ -273,6 +285,7 @@ namespace MP4{
|
|||
void setMajorBrand(const char *newMajorBrand);
|
||||
std::string getMajorBrand();
|
||||
void setMinorVersion(const char *newMinorVersion);
|
||||
std::string getMinorVersionHex();
|
||||
std::string getMinorVersion();
|
||||
size_t getCompatibleBrandsCount();
|
||||
void setCompatibleBrands(const char *newCompatibleBrand, size_t index);
|
||||
|
@ -719,6 +732,11 @@ namespace MP4{
|
|||
void setCodecBox(Box &newBox);
|
||||
Box &getCodecBox();
|
||||
Box &getSINFBox(); /*LTS*/
|
||||
|
||||
size_t getBoxEntryCount();
|
||||
Box &getBoxEntry(size_t index);
|
||||
void setBoxEntry(size_t index, Box &box);
|
||||
|
||||
std::string toPrettyAudioString(uint32_t indent = 0, std::string name = "");
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue