Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 39bd2319 authored by Sham Rathod's avatar Sham Rathod
Browse files

Update initialization data to CodecPrivate format for VP9

The CSD set for VP9 codec in MPEG4Extractor is vpcCBox.
But according to WebM documentation of VP9 the codec
specific data should be in CodecPrivate format.

Bug: 349992970
Test: atest CtsMediaMuxerTestCases
Change-Id: Icafc616a4596f8ed0815035879bb47ab916b9175
parent c6ca92e3
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -28,6 +28,10 @@ cc_defaults {
        "liblog",
        "liblog",
    ],
    ],


    static_libs: [
        "libstagefright_metadatautils",
    ],

    // extractors are expected to run on Q(29)
    // extractors are expected to run on Q(29)
    min_sdk_version: "29",
    min_sdk_version: "29",
    apex_available: [
    apex_available: [
@@ -56,6 +60,7 @@ cc_defaults {
                "libutils",
                "libutils",
                "libmediandk_format",
                "libmediandk_format",
                "libmedia_ndkformatpriv",
                "libmedia_ndkformatpriv",
                "libstagefright_metadatautils",
            ],
            ],
        },
        },
    },
    },
+1 −0
Original line number Original line Diff line number Diff line
@@ -131,6 +131,7 @@ cc_fuzz {
        "libstagefright_id3",
        "libstagefright_id3",
        "libstagefright_esds",
        "libstagefright_esds",
        "libmp4extractor",
        "libmp4extractor",
        "libstagefright_metadatautils",
    ],
    ],


    dictionary: "mp4_extractor_fuzzer.dict",
    dictionary: "mp4_extractor_fuzzer.dict",
+1 −1
Original line number Original line Diff line number Diff line
@@ -1787,7 +1787,7 @@ status_t MatroskaExtractor::synthesizeVP9(TrackInfo* trackInfo, size_t index) {
        return ERROR_MALFORMED;
        return ERROR_MALFORMED;
    }
    }


    if (!MakeVP9CodecSpecificData(trackInfo->mMeta, tmpData.get(), frame.len)) {
    if (!MakeVP9CodecSpecificDataFromFirstFrame(trackInfo->mMeta, tmpData.get(), frame.len)) {
        return ERROR_MALFORMED;
        return ERROR_MALFORMED;
    }
    }


+26 −1
Original line number Original line Diff line number Diff line
@@ -51,6 +51,7 @@
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaDataBase.h>
#include <media/stagefright/MetaDataBase.h>
#include <media/stagefright/MetaDataUtils.h>
#include <utils/String8.h>
#include <utils/String8.h>


#include <byteswap.h>
#include <byteswap.h>
@@ -2596,8 +2597,32 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
            *offset += chunk_size;
            *offset += chunk_size;
            break;
            break;
        }
        }

        case FOURCC("vpcC"):
        case FOURCC("vpcC"):
        {
            if (mLastTrack == NULL) {
                return ERROR_MALFORMED;
            }

            auto buffer = heapbuffer<uint8_t>(chunk_data_size);

            if (buffer.get() == NULL) {
                ALOGE("b/28471206");
                return NO_MEMORY;
            }

            if (mDataSource->readAt(data_offset, buffer.get(), chunk_data_size) < chunk_data_size) {
                return ERROR_IO;
            }

            if (!MakeVP9CodecPrivateFromVpcC(mLastTrack->meta, buffer.get(), chunk_data_size)) {
                ALOGE("Failed to create VP9 CodecPrivate from vpcC.");
                return ERROR_MALFORMED;
            }

            *offset += chunk_size;
            break;
        }

        case FOURCC("av1C"):
        case FOURCC("av1C"):
        {
        {
            auto buffer = heapbuffer<uint8_t>(chunk_data_size);
            auto buffer = heapbuffer<uint8_t>(chunk_data_size);
+64 −20
Original line number Original line Diff line number Diff line
@@ -134,10 +134,54 @@ static bool getVp9BitdepthChromaSubSampling(ABitReader &bits,
    }
    }
    return true;
    return true;
}
}

/**
 * Build VP9 Codec Feature Metadata (CodecPrivate) to set CSD for VP9 codec.
 * For reference:
 * https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate.
 *
 * @param meta          A pointer to AMediaFormat object.
 * @param profile       The profile value of the VP9 stream.
 * @param level         The VP9 codec level. If the level is unknown, pass -1 to this parameter.
 * @param bitDepth      The bit depth of the luma and color components of the VP9 stream.
 * @param chromaSubsampling  The chroma subsampling of the VP9 stream. If chromaSubsampling is
 *                           unknown, pass -1 to this parameter.
 * @return true if CodecPrivate is set as CSD of AMediaFormat object.
 *
 */
static bool MakeVP9CodecPrivate(AMediaFormat* meta, int32_t profile, int32_t level,
                                int32_t bitDepth, int32_t chromaSubsampling) {
    if (meta == nullptr) {
        return false;
    }

    std::vector<uint8_t> codecPrivate;
    // Construct CodecPrivate in WebM format (ID | Length | Data).
    // Helper lambda to add a field to the codec private data
    auto addField = [&codecPrivate](uint8_t id, uint8_t value) {
        codecPrivate.push_back(id);
        codecPrivate.push_back(0x01);  // Length is always 1
        codecPrivate.push_back(value);
    };

    // Add fields
    addField(0x01, static_cast<uint8_t>(profile));
    if (level >= 0) {
        addField(0x02, static_cast<uint8_t>(level));
    }
    addField(0x03, static_cast<uint8_t>(bitDepth));
    if (chromaSubsampling >= 0) {
        addField(0x04, static_cast<uint8_t>(chromaSubsampling));
    }
    // Set CSD in the meta format
    AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, codecPrivate.data(), codecPrivate.size());
    return true;
}

// The param data contains the first frame data, starting with the uncompressed frame
// The param data contains the first frame data, starting with the uncompressed frame
// header. This uncompressed header (refer section 6.2 of the VP9 bitstream spec) is
// header. This uncompressed header (refer section 6.2 of the VP9 bitstream spec) is
// used to parse profile, bitdepth and subsampling.
// used to parse profile, bitdepth and subsampling.
bool MakeVP9CodecSpecificData(AMediaFormat* meta, const uint8_t* data, size_t size) {
bool MakeVP9CodecSpecificDataFromFirstFrame(AMediaFormat* meta, const uint8_t* data, size_t size) {
    if (meta == nullptr || data == nullptr || size == 0) {
    if (meta == nullptr || data == nullptr || size == 0) {
        return false;
        return false;
    }
    }
@@ -227,29 +271,29 @@ bool MakeVP9CodecSpecificData(AMediaFormat* meta, const uint8_t* data, size_t si
    if (chromaSubsampling != -1) {
    if (chromaSubsampling != -1) {
        csdSize += 3;
        csdSize += 3;
    }
    }
    // As level is not present in first frame build CodecPrivate without it.
    return MakeVP9CodecPrivate(meta, profile, -1, bitDepth, chromaSubsampling);
}


    // Create VP9 Codec Feature Metadata (CodecPrivate) that can be parsed
bool MakeVP9CodecPrivateFromVpcC(AMediaFormat* meta, const uint8_t* csdData, size_t size) {
    // https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate
    if (meta == nullptr || csdData == nullptr || size < 12) {
    sp<ABuffer> csd = sp<ABuffer>::make(csdSize);
        return false;
    uint8_t* csdData = csd->data();
    }

    *csdData++ = 0x01 /* FEATURE PROFILE */;
    *csdData++ = 0x01 /* length */;
    *csdData++ = profile;

    *csdData++ = 0x03 /* FEATURE BITDEPTH */;
    *csdData++ = 0x01 /* length */;
    *csdData++ = bitDepth;


    // csdSize more than 6 means chroma subsampling data was found.
    // Check the first 4 bytes (VersionAndFlags) if they match the required value.
    if (csdSize > 6) {
    if (csdData[0] != 0x01 || csdData[1] != 0x00 || csdData[2] != 0x00 || csdData[3] != 0x00) {
        *csdData++ = 0x04 /* FEATURE SUBSAMPLING */;
        return false;
        *csdData++ = 0x01 /* length */;
        *csdData++ = chromaSubsampling;
    }
    }


    AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, csd->data(), csd->size());
    // Create VP9 Codec Feature Metadata (CodecPrivate) that can be parsed.
    return true;
    // https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate
    const uint8_t* vpcCData = csdData + 4;  // Skip the first 4 bytes (VersionAndFlags)

    int32_t profile = vpcCData[0];
    int32_t level = vpcCData[1];
    int32_t bitDepth = (vpcCData[2] >> 4) & 0x0F;           // Bit Depth (4 bits).
    int32_t chromaSubsampling = (vpcCData[2] >> 1) & 0x07;  // Chroma Subsampling (3 bits).
    return MakeVP9CodecPrivate(meta, profile, level, bitDepth, chromaSubsampling);
}
}


bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
Loading