diff --git a/CMakeLists.txt b/CMakeLists.txt old mode 100755 new mode 100644 index 538dab2..cb200fe --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,8 +122,10 @@ set(SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/src/3gp.cpp ${CMAKE_CURRENT_LIST_DIR}/src/atom_ac3.cpp ${CMAKE_CURRENT_LIST_DIR}/src/atom_amr.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/atom_av1C.cpp ${CMAKE_CURRENT_LIST_DIR}/src/atom_avc1.cpp ${CMAKE_CURRENT_LIST_DIR}/src/atom_avcC.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/atom_avxx.cpp ${CMAKE_CURRENT_LIST_DIR}/src/atom_chpl.cpp ${CMAKE_CURRENT_LIST_DIR}/src/atom_colr.cpp ${CMAKE_CURRENT_LIST_DIR}/src/atom_d263.cpp diff --git a/GNUmakefile.am b/GNUmakefile.am index 5f95307..4bf55a6 100644 --- a/GNUmakefile.am +++ b/GNUmakefile.am @@ -14,8 +14,10 @@ libmp4v2_la_SOURCES = \ src/3gp.cpp \ src/atom_ac3.cpp \ src/atom_amr.cpp \ + src/atom_av1C.cpp \ src/atom_avc1.cpp \ src/atom_avcC.cpp \ + src/atom_avxx.cpp \ src/atom_vpxx.cpp \ src/atom_vpcC.cpp \ src/atom_opus.cpp \ diff --git a/include/mp4v2/general.h b/include/mp4v2/general.h index 76e0572..9d0caa2 100644 --- a/include/mp4v2/general.h +++ b/include/mp4v2/general.h @@ -187,6 +187,7 @@ typedef uint32_t (*encryptFunc_t)( uint32_t, uint32_t, uint8_t*, uint32_t*, uint #define MP4_H261_VIDEO_TYPE 0xF3 /* a private definition */ #define MP4_VP8_VIDEO_TYPE 0xF4 /* a private definition */ #define MP4_VP9_VIDEO_TYPE 0xF5 /* a private definition */ +#define MP4_AV1_VIDEO_TYPE 0xF6 /* a private definition */ /* MP4 Video type utilities */ #define MP4_IS_MPEG1_VIDEO_TYPE(type) \ diff --git a/include/mp4v2/track.h b/include/mp4v2/track.h index c1285fb..80b0bd3 100644 --- a/include/mp4v2/track.h +++ b/include/mp4v2/track.h @@ -253,6 +253,14 @@ MP4TrackId MP4AddVideoTrack( uint16_t height, uint8_t videoType DEFAULT(MP4_MPEG4_VIDEO_TYPE) ); +MP4V2_EXPORT +MP4TrackId MP4AddAV1VideoTrack( + MP4FileHandle hFile, + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height); + MP4V2_EXPORT MP4TrackId MP4AddVP8VideoTrack( MP4FileHandle hFile, @@ -295,6 +303,14 @@ void MP4AddH264PictureParameterSet( const uint8_t* pPict, uint16_t pictLen ); +MP4V2_EXPORT +void MP4SetAv1SequenceObu( + MP4FileHandle hFile, + MP4TrackId trackId, + const uint8_t* pSequence, + uint16_t sequenceLen); + + MP4V2_EXPORT void MP4SetH263Vendor( MP4FileHandle hFile, diff --git a/src/atom_av1C.cpp b/src/atom_av1C.cpp new file mode 100644 index 0000000..1050750 --- /dev/null +++ b/src/atom_av1C.cpp @@ -0,0 +1,71 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2004. All Rights Reserved. + * + * Contributor(s): + * Bill May wmay@cisco.com + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4Av1CAtom::MP4Av1CAtom(MP4File &file) + : MP4Atom(file, "av1C") +{ + AddProperty( new MP4BitfieldProperty(*this, "marker", 1)); /* 0 */ + AddProperty( new MP4BitfieldProperty(*this, "version", 7)); /* 1 */ + AddProperty( new MP4BitfieldProperty(*this, "seq_profile", 3)); /* 2 */ + AddProperty( new MP4BitfieldProperty(*this, "seq_level_idx_0", 5)); /* 3 */ + AddProperty( new MP4BitfieldProperty(*this, "seq_tier_0", 1)); /* 4 */ + AddProperty( new MP4BitfieldProperty(*this, "high_bitdepth", 1)); /* 5 */ + AddProperty( new MP4BitfieldProperty(*this, "twelve_bit", 1)); /* 6 */ + AddProperty( new MP4BitfieldProperty(*this, "monochrome", 1)); /* 7 */ + AddProperty( new MP4BitfieldProperty(*this, "chroma_subsampling_x", 1)); /* 8 */ + AddProperty( new MP4BitfieldProperty(*this, "chroma_subsampling_y", 1)); /* 9 */ + AddProperty( new MP4BitfieldProperty(*this, "chroma_sample_position", 2)); /* 10 */ + AddProperty( new MP4BitfieldProperty(*this, "reserved ", 3)); /* 11 */ + AddProperty( new MP4BitfieldProperty(*this, "initial_presentation_delay_present", 1)); /* 12 */ + AddProperty( new MP4BitfieldProperty(*this, "initial_presentation_delay_minus_one_or_reserved", 4)); /* 13 */ + AddProperty( new MP4BytesProperty(*this, "configOBUs", 0)); /* 14 */ +} + + +void MP4Av1CAtom::Generate() +{ + MP4Atom::Generate(); + ((MP4BitfieldProperty*)m_pProperties[0])->SetValue(1); + ((MP4BitfieldProperty*)m_pProperties[1])->SetValue(1); + ((MP4BitfieldProperty*)m_pProperties[2])->SetValue(0); + ((MP4BitfieldProperty*)m_pProperties[3])->SetValue(0); + ((MP4BitfieldProperty*)m_pProperties[4])->SetValue(0); + ((MP4BitfieldProperty*)m_pProperties[5])->SetValue(0); + ((MP4BitfieldProperty*)m_pProperties[6])->SetValue(0); + ((MP4BitfieldProperty*)m_pProperties[7])->SetValue(0); + ((MP4BitfieldProperty*)m_pProperties[8])->SetValue(0); + ((MP4BitfieldProperty*)m_pProperties[9])->SetValue(0); + ((MP4BitfieldProperty*)m_pProperties[10])->SetValue(0); + ((MP4BitfieldProperty*)m_pProperties[11])->SetValue(0); + ((MP4BitfieldProperty*)m_pProperties[12])->SetValue(0); + ((MP4BitfieldProperty*)m_pProperties[13])->SetValue(0); +} +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/src/atom_avxx.cpp b/src/atom_avxx.cpp new file mode 100644 index 0000000..77936b3 --- /dev/null +++ b/src/atom_avxx.cpp @@ -0,0 +1,89 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2004. All Rights Reserved. + * + * Contributor(s): + * Bill May wmay@cisco.com + */ + +#include "src/impl.h" + +namespace mp4v2 { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// + +MP4Av01Atom::MP4Av01Atom(MP4File& file) + : MP4Atom(file, "av01") +{ + AddReserved(*this, "reserved1", 6); /* 0 */ + + AddProperty( /* 1 */ + new MP4Integer16Property(*this, "dataReferenceIndex")); + + AddReserved(*this, "reserved2", 16); /* 2 */ + + AddProperty( /* 3 */ + new MP4Integer16Property(*this, "width")); + AddProperty( /* 4 */ + new MP4Integer16Property(*this, "height")); + + AddReserved(*this, "reserved3", 14); /* 5 */ + + MP4StringProperty* pProp = + new MP4StringProperty(*this, "compressorName"); + pProp->SetFixedLength(32); + pProp->SetCountedFormat(true); + pProp->SetValue("AV1 Coding"); + AddProperty(pProp); /* 6 */ + + AddReserved(*this, "reserved4", 4); /* 7 */ + + ExpectChildAtom("av1C", Required, OnlyOne); +} + +void MP4Av01Atom::Generate() +{ + MP4Atom::Generate(); + + ((MP4Integer16Property*)m_pProperties[1])->SetValue(1); + + // property reserved3 has non-zero fixed values + static uint8_t reserved3[14] = { + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, + }; + m_pProperties[5]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[5])-> + SetValue(reserved3, sizeof(reserved3)); + m_pProperties[5]->SetReadOnly(true); + + // property reserved4 has non-zero fixed values + static uint8_t reserved4[4] = { + 0x00, 0x18, 0xFF, 0xFF, + }; + m_pProperties[7]->SetReadOnly(false); + ((MP4BytesProperty*)m_pProperties[7])-> + SetValue(reserved4, sizeof(reserved4)); + m_pProperties[7]->SetReadOnly(true); +} + +/////////////////////////////////////////////////////////////////////////////// + +} +} // namespace mp4v2::impl diff --git a/src/atoms.h b/src/atoms.h index 9e58782..9fd106b 100644 --- a/src/atoms.h +++ b/src/atoms.h @@ -200,6 +200,29 @@ class MP4DOpsAtom : public MP4Atom { MP4DOpsAtom &operator= ( const MP4DOpsAtom &src ); }; +// https://aomediacodec.github.io/av1-isobmff/ + +class MP4Av01Atom : public MP4Atom { +public: + MP4Av01Atom(MP4File& file); + void Generate(); +private: + MP4Av01Atom(); + MP4Av01Atom(const MP4Av01Atom& src); + MP4Av01Atom& operator= (const MP4Av01Atom& src); +}; + +class MP4Av1CAtom : public MP4Atom { +public: + MP4Av1CAtom(MP4File& file); + void Generate(); +private: + MP4Av1CAtom(); + MP4Av1CAtom(const MP4Av1CAtom& src); + MP4Av1CAtom& operator= (const MP4Av1CAtom& src); +}; + + // VPXX atoms https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp-codec-iso-media-file-format-binding-20160516-draft.pdf class MP4Vp08Atom : public MP4Atom { diff --git a/src/mp4.cpp b/src/mp4.cpp index 81aadb1..ab3b34a 100644 --- a/src/mp4.cpp +++ b/src/mp4.cpp @@ -1211,6 +1211,32 @@ MP4FileHandle MP4ReadProvider( const char* fileName, const MP4FileProvider* file return MP4_INVALID_TRACK_ID; } + MP4TrackId MP4AddAV1VideoTrack(MP4FileHandle hFile, + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + MP4File* pFile = (MP4File*)hFile; + + return pFile->AddAV1VideoTrack(timeScale, + sampleDuration, + width, + height); + } + catch (Exception* x) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch (...) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__); + } + } + return MP4_INVALID_TRACK_ID; + } + MP4TrackId MP4AddVP8VideoTrack(MP4FileHandle hFile, uint32_t timeScale, MP4Duration sampleDuration, @@ -1388,6 +1414,31 @@ MP4FileHandle MP4ReadProvider( const char* fileName, const MP4FileProvider* file } return; } + void MP4SetAv1SequenceObu( + MP4FileHandle hFile, + MP4TrackId trackId, + const uint8_t* pSequence, + uint16_t sequenceLen) + { + if (MP4_IS_VALID_FILE_HANDLE(hFile)) { + try { + MP4File* pFile = (MP4File*)hFile; + + pFile->SetAv1SequenceObu(trackId, + pSequence, + sequenceLen); + return; + } + catch (Exception* x) { + mp4v2::impl::log.errorf(*x); + delete x; + } + catch (...) { + mp4v2::impl::log.errorf("%s: failed", __FUNCTION__); + } + } + return; + } MP4TrackId MP4AddH263VideoTrack( MP4FileHandle hFile, diff --git a/src/mp4atom.cpp b/src/mp4atom.cpp index a8b43d4..59231c1 100644 --- a/src/mp4atom.cpp +++ b/src/mp4atom.cpp @@ -823,6 +823,10 @@ MP4Atom::factory( MP4File &file, MP4Atom* parent, const char* type ) break; case 'a': + if (ATOMID(type) == ATOMID("av01")) + return new MP4Av01Atom(file); + if (ATOMID(type) == ATOMID("av1C")) + return new MP4Av1CAtom(file); if( ATOMID(type) == ATOMID("avc1") ) return new MP4Avc1Atom(file); if( ATOMID(type) == ATOMID("ac-3") ) diff --git a/src/mp4file.cpp b/src/mp4file.cpp index 48df4d4..d023716 100644 --- a/src/mp4file.cpp +++ b/src/mp4file.cpp @@ -1875,6 +1875,26 @@ MP4TrackId MP4File::AddH264VideoTrack( return trackId; } +MP4TrackId MP4File::AddAV1VideoTrack( + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height) +{ + MP4TrackId trackId = AddVideoTrackDefault(timeScale, + sampleDuration, + width, + height, + "av01"); + + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.av01.width", width); + SetTrackIntegerProperty(trackId, + "mdia.minf.stbl.stsd.av01.height", height); + + return trackId; +} + MP4TrackId MP4File::AddVP8VideoTrack( uint32_t timeScale, MP4Duration sampleDuration, @@ -2085,6 +2105,27 @@ void MP4File::AddH264PictureParameterSet (MP4TrackId trackId, return; } + +void MP4File::SetAv1SequenceObu(MP4TrackId trackId, + const uint8_t* pSequence, + uint16_t sequenceLen) +{ + MP4Atom* av1CAtom = + FindAtom(MakeTrackName(trackId, + "mdia.minf.stbl.stsd.av01.av1C")); + MP4BytesProperty* pUnit; + if (av1CAtom->FindProperty("av1C.configOBUs", + (MP4Property**)&pUnit) == false) { + log.errorf("%s: \"%s\": Could not find av1C configOBUs properties", + __FUNCTION__, GetFilename().c_str()); + return; + } + + pUnit->SetValue(pSequence, sequenceLen); + + return; +} + void MP4File::SetH263Vendor( MP4TrackId trackId, uint32_t vendor) diff --git a/src/mp4file.h b/src/mp4file.h index bf67111..168fbeb 100644 --- a/src/mp4file.h +++ b/src/mp4file.h @@ -342,7 +342,13 @@ class MP4File uint8_t h263Profile, uint32_t avgBitrate, uint32_t maxBitrate); - + + MP4TrackId AddAV1VideoTrack( + uint32_t timeScale, + MP4Duration sampleDuration, + uint16_t width, + uint16_t height); + MP4TrackId AddVP8VideoTrack( uint32_t timeScale, MP4Duration sampleDuration, @@ -379,6 +385,9 @@ class MP4File void AddH264PictureParameterSet(MP4TrackId trackId, const uint8_t *pPicture, uint16_t pictureLen); + void SetAv1SequenceObu(MP4TrackId trackId, + const uint8_t* pSequence, + uint16_t sequenceLen); MP4TrackId AddHintTrack(MP4TrackId refTrackId); MP4TrackId AddTextTrack(MP4TrackId refTrackId); diff --git a/src/mp4info.cpp b/src/mp4info.cpp index cf434dd..5c1d2ff 100644 --- a/src/mp4info.cpp +++ b/src/mp4info.cpp @@ -289,6 +289,7 @@ static char* PrintVideoInfo( MP4_H261_VIDEO_TYPE, MP4_VP8_VIDEO_TYPE, MP4_VP9_VIDEO_TYPE, + MP4_AV1_VIDEO_TYPE, }; static const char* mpegVideoNames[] = { "MPEG-2 Simple", @@ -304,6 +305,7 @@ static char* PrintVideoInfo( "H.261", "VP8", "VP9", + "AV1", }; uint8_t numMpegVideoTypes = sizeof(mpegVideoTypes) / sizeof(uint8_t);