Allow for multiple SPS/PPS in AVCC Box

This commit is contained in:
Erik Zandvliet 2018-08-30 17:14:14 +02:00 committed by Thulinma
parent 4f7b902453
commit 373b9afd32
3 changed files with 115 additions and 61 deletions

View file

@ -558,89 +558,128 @@ namespace MP4 {
return getInt8(3); return getInt8(3);
} }
void AVCC::setSPSNumber(uint32_t newSPSNumber) { void AVCC::setSPSCount(uint32_t _count){
setInt8(newSPSNumber, 5); setInt8(_count | 0xE0, 5);
} }
uint32_t AVCC::getSPSNumber() { uint32_t AVCC::getSPSCount() {
return getInt8(5); return getInt8(5) & 0x1F;
} }
void AVCC::setSPS(std::string newSPS) { void AVCC::setSPS(std::string newSPS, size_t index) {
setInt16(newSPS.size(), 6); if (index >= getSPSCount()){
WARN_MSG("Cannot set entry at position %zu/%u: Out of bounds", index, getSPSCount());
}
size_t offset = 6;
for (size_t i = 0; i < index; i++){
offset += getInt16(offset) + 2;
}
setInt16(newSPS.size(), offset);
for (unsigned int i = 0; i < newSPS.size(); i++) { for (unsigned int i = 0; i < newSPS.size(); i++) {
setInt8(newSPS[i], 8 + i); setInt8(newSPS[i], offset + 2 + i);
} //not null-terminated } //not null-terminated
} }
uint32_t AVCC::getSPSLen() { uint32_t AVCC::getSPSLen(size_t index) {
uint16_t len = getInt16(6); if (index >= getSPSCount()){
if (len > payloadSize() - 8){
WARN_MSG("SPS length of %u is more than AVCC box size %lu", len, payloadSize());
return 0; return 0;
} }
return len; size_t offset = 6;
for (size_t i = 0; i < index; i++){
offset += getInt16(offset) + 2;
}
return getInt16(offset);
} }
char * AVCC::getSPS() { char * AVCC::getSPS(size_t index) {
return payload() + 8; if (index >= getSPSCount()){
return 0;
}
size_t offset = 6;
for (size_t i = 0; i < index; i++){
offset += getInt16(offset) + 2;
}
return payload() + offset + 2;
} }
std::string AVCC::hexSPS(){ std::string AVCC::hexSPS(size_t index){
if (index >= getPPSCount()){
return "INVALID INDEX";
}
std::stringstream res; std::stringstream res;
char * data = getSPS(); char * data = getSPS(index);
uint32_t len = getSPSLen(); uint32_t len = getSPSLen(index);
for (int i = 0; i < len; i++){ for (int i = 0; i < len; i++){
res << std::hex << std::setw(2) << std::setfill('0') << (int)data[i]; res << std::hex << std::setw(2) << std::setfill('0') << (int)data[i];
} }
return res.str(); return res.str();
} }
std::string AVCC::hexPPS(){ std::string AVCC::hexPPS(size_t index){
if (index >= getPPSCount()){
return "INVALID INDEX";
}
std::stringstream res; std::stringstream res;
char * data = getPPS(); char * data = getPPS(index);
uint32_t len = getPPSLen(); uint32_t len = getPPSLen(index);
for (int i = 0; i < len; i++){ for (int i = 0; i < len; i++){
res << std::hex << std::setw(2) << std::setfill('0') << (int)data[i]; res << std::hex << std::setw(2) << std::setfill('0') << (int)data[i];
} }
return res.str(); return res.str();
} }
void AVCC::setPPSNumber(uint32_t newPPSNumber) { size_t AVCC::PPSCountOffset() {
int offset = 8 + getSPSLen(); size_t offset = 6;
setInt8(newPPSNumber, offset); size_t spsCount = getSPSCount();
for (size_t i = 0; i < spsCount; i++){
offset += getInt16(offset) + 2;
}
return offset;
} }
uint32_t AVCC::getPPSNumber() { void AVCC::setPPSCount(uint32_t _count) {
int offset = 8 + getSPSLen(); setInt8(_count, PPSCountOffset());
return getInt8(offset);
} }
void AVCC::setPPS(std::string newPPS) { uint32_t AVCC::getPPSCount() {
int offset = 8 + getSPSLen() + 1; return getInt8(PPSCountOffset());
}
void AVCC::setPPS(std::string newPPS, size_t index) {
if (index >= getPPSCount()){
WARN_MSG("Cannot set entry at position %zu/%u: Out of bounds", index, getPPSCount());
}
int offset = PPSCountOffset() + 1;
for (size_t i = 0; i < index; i++){
offset += getInt16(offset) + 2;
}
setInt16(newPPS.size(), offset); setInt16(newPPS.size(), offset);
for (unsigned int i = 0; i < newPPS.size(); i++) { for (unsigned int i = 0; i < newPPS.size(); i++) {
setInt8(newPPS[i], offset + 2 + i); setInt8(newPPS[i], offset + 2 + i);
} //not null-terminated } //not null-terminated
} }
uint32_t AVCC::getPPSLen() { uint32_t AVCC::getPPSLen(size_t index) {
int offset = 8 + getSPSLen() + 1; if (index >= getPPSCount()){
if (offset > payloadSize() - 2){
WARN_MSG("Invalid PPS length offset! Aborting PPS read."); WARN_MSG("Invalid PPS length offset! Aborting PPS read.");
return 0; return 0;
} }
uint16_t len = getInt16(offset); int offset = PPSCountOffset() + 1;
if (len > payloadSize() - offset - 2){ for (size_t i = 0; i < index; i++){
WARN_MSG("PPS length of %u is more than AVCC box size %lu", len, payloadSize()); offset += getInt16(offset) + 2;
return 0;
} }
return len; return getInt16(offset);
} }
char * AVCC::getPPS() { char * AVCC::getPPS(size_t index) {
int offset = 8 + getSPSLen() + 3; if (index >= getPPSCount()){
return payload() + offset; return 0;
}
int offset = PPSCountOffset() + 1;
for (size_t i = 0; i < index; i++){
offset += getInt16(offset) + 2;
}
return payload() + offset + 2;
} }
std::string AVCC::toPrettyString(uint32_t indent) { std::string AVCC::toPrettyString(uint32_t indent) {
@ -650,19 +689,31 @@ namespace MP4 {
r << std::string(indent + 1, ' ') << "Profile: " << getProfile() << std::endl; r << std::string(indent + 1, ' ') << "Profile: " << getProfile() << std::endl;
r << std::string(indent + 1, ' ') << "Compatible Profiles: " << getCompatibleProfiles() << std::endl; r << std::string(indent + 1, ' ') << "Compatible Profiles: " << getCompatibleProfiles() << std::endl;
r << std::string(indent + 1, ' ') << "Level: " << getLevel() << std::endl; r << std::string(indent + 1, ' ') << "Level: " << getLevel() << std::endl;
r << std::string(indent + 1, ' ') << "SPS Number: " << getSPSNumber() << std::endl; size_t spsCount = getSPSCount();
r << std::string(indent + 2, ' ') << getSPSLen() << " of SPS data: " << hexSPS() << std::endl; r << std::string(indent + 1, ' ') << "SPS Count: " << spsCount << std::endl;
r << std::string(indent + 1, ' ') << "PPS Number: " << getPPSNumber() << std::endl; for (size_t i = 0; i < spsCount; i++){
r << std::string(indent + 2, ' ') << getPPSLen() << " of PPS data: " << hexPPS() << std::endl; r << std::string(indent + 2, ' ') << getSPSLen(i) << " bytes of SPS data: " << hexSPS(i) << std::endl;
}
size_t ppsCount = getPPSCount();
r << std::string(indent + 1, ' ') << "PPS Count: " << ppsCount << std::endl;
for (size_t i = 0; i < ppsCount; i++){
r << std::string(indent + 2, ' ') << getPPSLen(i) << " bytes of PPS data: " << hexPPS(i) << std::endl;
}
return r.str(); return r.str();
} }
std::string AVCC::asAnnexB() { std::string AVCC::asAnnexB() {
std::stringstream r; std::stringstream r;
r << (char)0x00 << (char)0x00 << (char)0x00 << (char)0x01; size_t count = getSPSCount();
r.write(getSPS(), getSPSLen()); for (size_t i = 0; i < count; ++i){
r << (char)0x00 << (char)0x00 << (char)0x00 << (char)0x01; r << (char)0x00 << (char)0x00 << (char)0x00 << (char)0x01;
r.write(getPPS(), getPPSLen()); r.write(getSPS(i), getSPSLen(i));
}
count = getPPSCount();
for (size_t i = 0; i < count; ++i){
r << (char)0x00 << (char)0x00 << (char)0x00 << (char)0x01;
r.write(getPPS(i), getPPSLen(i));
}
return r.str(); return r.str();
} }

View file

@ -107,18 +107,21 @@ namespace MP4 {
uint32_t getCompatibleProfiles(); uint32_t getCompatibleProfiles();
void setLevel(uint32_t newLevel); void setLevel(uint32_t newLevel);
uint32_t getLevel(); uint32_t getLevel();
void setSPSNumber(uint32_t newSPSNumber);
uint32_t getSPSNumber(); void setSPSCount(uint32_t _count);
void setSPS(std::string newSPS); uint32_t getSPSCount();
uint32_t getSPSLen(); void setSPS(std::string newSPS, size_t index = 0);
char * getSPS(); uint32_t getSPSLen(size_t index = 0);
std::string hexSPS(); char * getSPS(size_t index = 0);
void setPPSNumber(uint32_t newPPSNumber); std::string hexSPS(size_t index = 0);
uint32_t getPPSNumber();
void setPPS(std::string newPPS); size_t PPSCountOffset();
uint32_t getPPSLen(); void setPPSCount(uint32_t _count);
char * getPPS(); uint32_t getPPSCount();
std::string hexPPS(); void setPPS(std::string newPPS, size_t index = 0);
uint32_t getPPSLen(size_t index = 0);
char * getPPS(size_t index = 0);
std::string hexPPS(size_t index = 0);
std::string asAnnexB(); std::string asAnnexB();
void setPayload(std::string newPayload); void setPayload(std::string newPayload);
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);

View file

@ -104,9 +104,9 @@ namespace Mist{
avccBox.setProfile(spsInfo[1]); avccBox.setProfile(spsInfo[1]);
avccBox.setCompatibleProfiles(spsInfo[2]); avccBox.setCompatibleProfiles(spsInfo[2]);
avccBox.setLevel(spsInfo[3]); avccBox.setLevel(spsInfo[3]);
avccBox.setSPSNumber(1); avccBox.setSPSCount(1);
avccBox.setSPS(spsInfo); avccBox.setSPS(spsInfo);
avccBox.setPPSNumber(1); avccBox.setPPSCount(1);
avccBox.setPPS(ppsInfo); avccBox.setPPS(ppsInfo);
myMeta.tracks[1].init = std::string(avccBox.payload(), avccBox.payloadSize()); myMeta.tracks[1].init = std::string(avccBox.payload(), avccBox.payloadSize());
} }