Support for AV1 MP4 input and output
This commit is contained in:
parent
8b8a28c4ec
commit
a9abfa531e
12 changed files with 154 additions and 22 deletions
|
@ -5,8 +5,9 @@
|
|||
#include "defines.h"
|
||||
#include "dtsc.h"
|
||||
#include "encode.h"
|
||||
#include "lib/shared_memory.h"
|
||||
#include "lib/util.h"
|
||||
#include "shared_memory.h"
|
||||
#include "util.h"
|
||||
#include "stream.h"
|
||||
#include <arpa/inet.h> //for htonl/ntohl
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
@ -2710,6 +2711,7 @@ namespace DTSC{
|
|||
std::string type = getType(*it);
|
||||
|
||||
trackJSON["codec"] = getCodec(*it);
|
||||
trackJSON["codecstring"] = Util::codecString(getCodec(*it), getInit(*it));
|
||||
trackJSON["type"] = type;
|
||||
trackJSON["idx"] = (uint64_t)*it;
|
||||
trackJSON["trackid"] = (uint64_t)getID(*it);
|
||||
|
|
|
@ -270,6 +270,8 @@ namespace MP4{
|
|||
case 0x61616320: return ((AAC *)this)->toPrettyString(indent); break;
|
||||
case 0x68766331:
|
||||
case 0x68657631: return ((HEV1 *)this)->toPrettyString(indent); break;
|
||||
case 0x61763031: return ((AV01 *)this)->toPrettyString(indent); break;
|
||||
case 0x61763143: return ((AV1C *)this)->toPrettyString(indent); break;
|
||||
case 0x61766331:
|
||||
case 0x656E6376: // encv
|
||||
return ((AVC1 *)this)->toPrettyString(indent);
|
||||
|
|
|
@ -799,6 +799,70 @@ namespace MP4{
|
|||
return r.str();
|
||||
}
|
||||
|
||||
|
||||
AV1C::AV1C(){
|
||||
memcpy(data + 4, "av1C", 4);
|
||||
setInt8(0b10000001, 0); // Marker 1, version 1: 0b10000001
|
||||
}
|
||||
|
||||
std::string AV1C::toPrettyString(uint32_t indent){
|
||||
std::stringstream r;
|
||||
r << std::string(indent, ' ') << "[av1C] AV1 Init Data (" << boxedSize() << ")" << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "Marker: " << (int)((getInt8(0) & 0b10000000) >> 7) << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "Version: " << (int)(getInt8(0) & 0b01111111) << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "Profile: " << (int)((getInt8(1) & 0b11100000) >> 5) << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "Level: " << (int)(getInt8(1) & 0b00011111) << std::endl;
|
||||
|
||||
r << std::string(indent + 1, ' ') << "Tier: " << (int)((getInt8(2) & 0b10000000) >> 7) << std::endl;
|
||||
|
||||
|
||||
r << std::string(indent + 1, ' ') << "Bit depth: ";
|
||||
switch ((getInt8(2) & 0b01100000)){
|
||||
case 0b00000000: r << "8"; break;
|
||||
case 0b01000000: r << "10"; break;
|
||||
case 0b01100000: r << "12"; break;
|
||||
case 0b00100000: r << "Unknown"; break;
|
||||
}
|
||||
r << std::endl;
|
||||
|
||||
r << std::string(indent + 1, ' ') << "Subsampling format: ";
|
||||
switch ((getInt8(2) & 0b00011100)){
|
||||
case 0b00000000: r << "YUV 4:4:4"; break;
|
||||
case 0b00001000: r << "YUV 4:2:2"; break;
|
||||
case 0b00001100: r << "YUV 4:2:0"; break;
|
||||
case 0b00011100: r << "Monochrome 4:0:0"; break;
|
||||
default: r << "Unknown";
|
||||
}
|
||||
r << std::endl;
|
||||
|
||||
r << std::string(indent + 1, ' ') << "Subsampling position: ";
|
||||
switch ((getInt8(2) & 0b00000011)){
|
||||
case 0: r << "Unknown"; break;
|
||||
case 1: r << "Vertical"; break;
|
||||
case 2: r << "Co-located"; break;
|
||||
case 3: r << "Reserved"; break;
|
||||
}
|
||||
r << std::endl;
|
||||
|
||||
if (getInt8(3) & 0b00010000){
|
||||
r << std::string(indent + 1, ' ') << "Initial presentation delay: " << (int)(getInt8(3) & 0b00001111) + 1 << std::endl;
|
||||
}else{
|
||||
r << std::string(indent + 1, ' ') << "Initial presentation delay: 0" << std::endl;
|
||||
}
|
||||
|
||||
r << std::string(indent + 1, ' ') << (payloadSize() - 4) << "b of OBU initialization data" << std::endl;
|
||||
|
||||
return r.str();
|
||||
}
|
||||
|
||||
void AV1C::setPayload(std::string newPayload){
|
||||
if (!reserve(0, payloadSize(), newPayload.size())){
|
||||
ERROR_MSG("Cannot allocate enough memory for payload");
|
||||
return;
|
||||
}
|
||||
memcpy((char *)payload(), (char *)newPayload.c_str(), newPayload.size());
|
||||
}
|
||||
|
||||
Descriptor::Descriptor(){
|
||||
data = (char *)malloc(2);
|
||||
data[0] = 0;
|
||||
|
@ -2692,22 +2756,26 @@ namespace MP4{
|
|||
avccBox.setPayload(M.getInit(idx));
|
||||
setCLAP(avccBox);
|
||||
}
|
||||
/*LTS-START*/
|
||||
if (tCodec == "HEVC"){
|
||||
setCodec("hev1");
|
||||
MP4::HVCC hvccBox;
|
||||
hvccBox.setPayload(M.getInit(idx));
|
||||
setCLAP(hvccBox);
|
||||
}
|
||||
/*LTS-END*/
|
||||
if (tCodec == "AV1"){
|
||||
setCodec("av01");
|
||||
MP4::AV1C av1cBox;
|
||||
av1cBox.setPayload(M.getInit(idx));
|
||||
setCLAP(av1cBox);
|
||||
}
|
||||
MP4::PASP paspBox;
|
||||
setPASP(paspBox);
|
||||
}
|
||||
|
||||
void VisualSampleEntry::initialize(){
|
||||
memcpy(data + 4, "erro", 4);
|
||||
setHorizResolution(0x00480000);
|
||||
setVertResolution(0x00480000);
|
||||
setHorizResolution(72);
|
||||
setVertResolution(72);
|
||||
setFrameCount(1);
|
||||
setCompressorName("");
|
||||
setDepth(0x0018);
|
||||
|
@ -2726,17 +2794,17 @@ namespace MP4{
|
|||
|
||||
uint16_t VisualSampleEntry::getHeight(){return getInt16(26);}
|
||||
|
||||
void VisualSampleEntry::setHorizResolution(uint32_t newHorizResolution){
|
||||
setInt32(newHorizResolution, 28);
|
||||
void VisualSampleEntry::setHorizResolution(double newHorizResolution){
|
||||
setInt32(newHorizResolution * 65536.0, 28);
|
||||
}
|
||||
|
||||
uint32_t VisualSampleEntry::getHorizResolution(){return getInt32(28);}
|
||||
double VisualSampleEntry::getHorizResolution(){return getInt32(28) / 65536.0;}
|
||||
|
||||
void VisualSampleEntry::setVertResolution(uint32_t newVertResolution){
|
||||
setInt32(newVertResolution, 32);
|
||||
void VisualSampleEntry::setVertResolution(double newVertResolution){
|
||||
setInt32(newVertResolution * 65536.0, 32);
|
||||
}
|
||||
|
||||
uint32_t VisualSampleEntry::getVertResolution(){return getInt32(32);}
|
||||
double VisualSampleEntry::getVertResolution(){return getInt32(32) / 65536.0;}
|
||||
|
||||
void VisualSampleEntry::setFrameCount(uint16_t newFrameCount){setInt16(newFrameCount, 40);}
|
||||
|
||||
|
@ -2839,8 +2907,8 @@ namespace MP4{
|
|||
r << toPrettySampleString(indent);
|
||||
r << std::string(indent + 1, ' ') << "Width: " << getWidth() << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "Height: " << getHeight() << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "HorizResolution: " << getHorizResolution() << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "VertResolution: " << getVertResolution() << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "HorizResolution: " << getHorizResolution() << " DPI" << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "VertResolution: " << getVertResolution() << " DPI" << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "FrameCount: " << getFrameCount() << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "CompressorName: " << getCompressorName() << std::endl;
|
||||
r << std::string(indent + 1, ' ') << "Depth: " << getDepth() << std::endl;
|
||||
|
@ -3249,6 +3317,12 @@ namespace MP4{
|
|||
return toPrettyVisualString(indent, "[h264] H.264/MPEG-4 AVC");
|
||||
}
|
||||
|
||||
AV01::AV01(){memcpy(data + 4, "av01", 4);}
|
||||
|
||||
std::string AV01::toPrettyString(uint32_t indent){
|
||||
return toPrettyVisualString(indent, "[av01] AV1 Video");
|
||||
}
|
||||
|
||||
FIEL::FIEL(){memcpy(data + 4, "fiel", 4);}
|
||||
|
||||
void FIEL::setTotal(char newTotal){setInt8(newTotal, 0);}
|
||||
|
|
|
@ -200,6 +200,13 @@ namespace MP4{
|
|||
h265::metaInfo getMetaInfo();
|
||||
};
|
||||
|
||||
class AV1C : public Box{
|
||||
public:
|
||||
AV1C();
|
||||
void setPayload(std::string newPayload);
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class Descriptor{
|
||||
public:
|
||||
Descriptor();
|
||||
|
@ -694,10 +701,10 @@ namespace MP4{
|
|||
uint16_t getWidth();
|
||||
void setHeight(uint16_t newHeight);
|
||||
uint16_t getHeight();
|
||||
void setHorizResolution(uint32_t newHorizResolution);
|
||||
uint32_t getHorizResolution();
|
||||
void setVertResolution(uint32_t newVertResolution);
|
||||
uint32_t getVertResolution();
|
||||
void setHorizResolution(double newHorizResolution);
|
||||
double getHorizResolution();
|
||||
void setVertResolution(double newVertResolution);
|
||||
double getVertResolution();
|
||||
void setFrameCount(uint16_t newFrameCount);
|
||||
uint16_t getFrameCount();
|
||||
void setCompressorName(std::string newCompressorName);
|
||||
|
@ -851,6 +858,12 @@ namespace MP4{
|
|||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class AV01 : public VisualSampleEntry{
|
||||
public:
|
||||
AV01();
|
||||
std::string toPrettyString(uint32_t indent = 0);
|
||||
};
|
||||
|
||||
class FIEL : public Box{
|
||||
public:
|
||||
FIEL();
|
||||
|
|
|
@ -105,6 +105,26 @@ std::string Util::codecString(const std::string &codec, const std::string &initD
|
|||
if (codec == "AAC"){return "mp4a.40.2";}
|
||||
if (codec == "MP3"){return "mp4a.40.34";}
|
||||
if (codec == "AC3"){return "mp4a.a5";}
|
||||
if (codec == "AV1"){
|
||||
if (initData.size() < 4){return "av01";}// Can't determine properties. :-(
|
||||
std::stringstream r;
|
||||
r << "av01.";
|
||||
r << (int)((initData[1] & 0b11100000) >> 5); //profile
|
||||
r << ".";
|
||||
r << std::setw(2) << std::setfill('0') << (int)(initData[1] & 0b00011111); //level
|
||||
r << ((initData[2] & 0b10000000)?"H":"M"); //tier
|
||||
r << ".";
|
||||
switch (initData[2] & 0b01100000){
|
||||
case 0b00000000: r << "08"; break;
|
||||
case 0b01000000: r << "10"; break;
|
||||
case 0b01100000: r << "12"; break;
|
||||
case 0b00100000: r << "??"; break;
|
||||
}
|
||||
/// \TODO Implement the full descriptor as in https://aomediacodec.github.io/av1-isobmff/#codecsparam
|
||||
/// Init data follows this format:
|
||||
/// https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox-syntax
|
||||
return r.str();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue