Merge "libstagefright: Add support for parsing profile and level from CSD for AV1" into qt-dev
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index ab76edc..b1eb301 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -1993,6 +1993,12 @@
}
} else if (!strcmp("V_AV1", codecID)) {
AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AV1);
+ if (codecPrivateSize > 0) {
+ // 'csd-0' for AV1 is the Blob of Codec Private data as
+ // specified in https://aomediacodec.github.io/av1-isobmff/.
+ AMediaFormat_setBuffer(
+ meta, AMEDIAFORMAT_KEY_CSD_0, codecPrivate, codecPrivateSize);
+ }
} else if (!strcmp("V_MPEG2", codecID) || !strcmp("V_MPEG1", codecID)) {
AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME,
MEDIA_MIMETYPE_VIDEO_MPEG2);
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 3de934f..135151f 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -39,6 +39,7 @@
#include <media/stagefright/foundation/ByteUtils.h>
#include <media/stagefright/foundation/OpusHeader.h>
#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/MediaDefs.h>
#include <media/AudioSystem.h>
#include <media/MediaPlayerInterface.h>
@@ -573,6 +574,68 @@
}
}
+static void parseAV1ProfileLevelFromCsd(const sp<ABuffer> &csd, sp<AMessage> &format) {
+ // Parse CSD structure to extract profile level information
+ // https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox
+ const uint8_t *data = csd->data();
+ size_t remaining = csd->size();
+ if (remaining < 4 || data[0] != 0x81) { // configurationVersion == 1
+ return;
+ }
+ uint8_t profileData = (data[1] & 0xE0) >> 5;
+ uint8_t levelData = data[1] & 0x1F;
+ uint8_t highBitDepth = (data[2] & 0x40) >> 6;
+
+ const static ALookup<std::pair<uint8_t, uint8_t>, int32_t> profiles {
+ { { 0, 0 }, AV1ProfileMain8 },
+ { { 1, 0 }, AV1ProfileMain10 },
+ };
+
+ int32_t profile;
+ if (profiles.map(std::make_pair(highBitDepth, profileData), &profile)) {
+ // bump to HDR profile
+ if (isHdr(format) && profile == AV1ProfileMain10) {
+ if (format->contains("hdr10-plus-info")) {
+ profile = AV1ProfileMain10HDR10Plus;
+ } else {
+ profile = AV1ProfileMain10HDR10;
+ }
+ }
+ format->setInt32("profile", profile);
+ }
+ const static ALookup<uint8_t, int32_t> levels {
+ { 0, AV1Level2 },
+ { 1, AV1Level21 },
+ { 2, AV1Level22 },
+ { 3, AV1Level23 },
+ { 4, AV1Level3 },
+ { 5, AV1Level31 },
+ { 6, AV1Level32 },
+ { 7, AV1Level33 },
+ { 8, AV1Level4 },
+ { 9, AV1Level41 },
+ { 10, AV1Level42 },
+ { 11, AV1Level43 },
+ { 12, AV1Level5 },
+ { 13, AV1Level51 },
+ { 14, AV1Level52 },
+ { 15, AV1Level53 },
+ { 16, AV1Level6 },
+ { 17, AV1Level61 },
+ { 18, AV1Level62 },
+ { 19, AV1Level63 },
+ { 20, AV1Level7 },
+ { 21, AV1Level71 },
+ { 22, AV1Level72 },
+ { 23, AV1Level73 },
+ };
+
+ int32_t level;
+ if (levels.map(levelData, &level)) {
+ format->setInt32("level", level);
+ }
+}
+
static std::vector<std::pair<const char *, uint32_t>> stringMappings {
{
@@ -1234,6 +1297,7 @@
buffer->meta()->setInt32("csd", true);
buffer->meta()->setInt64("timeUs", 0);
msg->setBuffer("csd-0", buffer);
+ parseAV1ProfileLevelFromCsd(buffer, msg);
} else if (meta->findData(kKeyESDS, &type, &data, &size)) {
ESDS esds((const char *)data, size);
if (esds.InitCheck() != (status_t)OK) {