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

Commit 3d70686c authored by Marco Nelissen's avatar Marco Nelissen Committed by Android (Google) Code Review
Browse files

Merge changes from topic "dolbyvision"

* changes:
  Enable Dolby Vision AV1 support in MPEG4 extractor
  Adding dolby-vision boxes to MPEG4Extractor
parents 4bebef8d 7a591bfa
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -521,6 +521,7 @@ enum C2Config::profile_t : uint32_t {
    PROFILE_DV_HE_07 = _C2_PL_DV_BASE + 7,      ///< Dolby Vision dvhe.07 profile
    PROFILE_DV_HE_08 = _C2_PL_DV_BASE + 8,      ///< Dolby Vision dvhe.08 profile
    PROFILE_DV_AV_09 = _C2_PL_DV_BASE + 9,      ///< Dolby Vision dvav.09 profile
    PROFILE_DV_AV1_10 = _C2_PL_DV_BASE + 10,    ///< Dolby Vision dav1.10 profile

    // AV1 profiles
    PROFILE_AV1_0 = _C2_PL_AV1_BASE,            ///< AV1 Profile 0 (4:2:0, 8 to 10 bit)
+1 −0
Original line number Diff line number Diff line
@@ -190,6 +190,7 @@ ALookup<C2Config::profile_t, int32_t> sDolbyVisionProfiles = {
    { C2Config::PROFILE_DV_HE_07, DolbyVisionProfileDvheDtb },
    { C2Config::PROFILE_DV_HE_08, DolbyVisionProfileDvheSt },
    { C2Config::PROFILE_DV_AV_09, DolbyVisionProfileDvavSe },
    { C2Config::PROFILE_DV_AV1_10, DolbyVisionProfileDvav110 },
};

ALookup<C2Config::level_t, int32_t> sH263Levels = {
+154 −4
Original line number Diff line number Diff line
@@ -133,6 +133,7 @@ private:

    bool mIsAVC;
    bool mIsHEVC;
    bool mIsDolbyVision;
    bool mIsAC4;
    bool mIsPcm;
    size_t mNALLengthSize;
@@ -337,6 +338,14 @@ static const char *FourCC2MIME(uint32_t fourcc) {
        case FOURCC("hvc1"):
        case FOURCC("hev1"):
            return MEDIA_MIMETYPE_VIDEO_HEVC;

        case FOURCC("dvav"):
        case FOURCC("dva1"):
        case FOURCC("dvhe"):
        case FOURCC("dvh1"):
        case FOURCC("dav1"):
            return MEDIA_MIMETYPE_VIDEO_DOLBY_VISION;

        case FOURCC("ac-4"):
            return MEDIA_MIMETYPE_AUDIO_AC4;
        case FOURCC("Opus"):
@@ -1062,6 +1071,62 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
                    mLastTrack->mTx3gBuffer = NULL;
                }

                const char *mime;
                AMediaFormat_getString(mLastTrack->meta, AMEDIAFORMAT_KEY_MIME, &mime);

                if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
                    void *data;
                    size_t size;

                    if (AMediaFormat_getBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_2, &data, &size)) {
                        const uint8_t *ptr = (const uint8_t *)data;
                        const uint8_t profile = ptr[2] >> 1;
                        const uint8_t bl_compatibility_id = (ptr[4]) >> 4;

                        if (4 == profile || 7 == profile ||
                                (profile >= 8 && profile < 11 && bl_compatibility_id)) {
                            // we need a backward compatible track
                            ALOGV("Adding new backward compatible track");
                            Track *track_b = new Track;

                            track_b->timescale = mLastTrack->timescale;
                            track_b->sampleTable = mLastTrack->sampleTable;
                            track_b->includes_expensive_metadata = mLastTrack->includes_expensive_metadata;
                            track_b->skipTrack = mLastTrack->skipTrack;
                            track_b->has_elst = mLastTrack->has_elst;
                            track_b->elst_media_time = mLastTrack->elst_media_time;
                            track_b->elst_segment_duration = mLastTrack->elst_segment_duration;
                            track_b->elstShiftStartTicks = mLastTrack->elstShiftStartTicks;
                            track_b->subsample_encryption = mLastTrack->subsample_encryption;

                            track_b->mTx3gBuffer = mLastTrack->mTx3gBuffer;
                            track_b->mTx3gSize = mLastTrack->mTx3gSize;
                            track_b->mTx3gFilled = mLastTrack->mTx3gFilled;

                            track_b->meta = AMediaFormat_new();
                            AMediaFormat_copy(track_b->meta, mLastTrack->meta);

                            mLastTrack->next = track_b;
                            track_b->next = NULL;

                            auto id = track_b->meta->mFormat->findEntryByName(AMEDIAFORMAT_KEY_CSD_2);
                            track_b->meta->mFormat->removeEntryAt(id);

                            if (4 == profile || 7 == profile || 8 == profile ) {
                                AMediaFormat_setString(track_b->meta,
                                        AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_HEVC);
                            } else if (9 == profile) {
                                AMediaFormat_setString(track_b->meta,
                                        AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AVC);
                            } else if (10 == profile) {
                                AMediaFormat_setString(track_b->meta,
                                        AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AV1);
                            } // Should never get to else part

                            mLastTrack = track_b;
                        }
                    }
                }
            } else if (chunk_type == FOURCC("moov")) {
                mInitCheck = OK;

@@ -1830,6 +1895,11 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
        case FOURCC("avc1"):
        case FOURCC("hvc1"):
        case FOURCC("hev1"):
        case FOURCC("dvav"):
        case FOURCC("dva1"):
        case FOURCC("dvhe"):
        case FOURCC("dvh1"):
        case FOURCC("dav1"):
        case FOURCC("av01"):
        {
            uint8_t buffer[78];
@@ -1984,7 +2054,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
                    // for audio, use 128KB
                    max_size = 1024 * 128;
                } else if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
                        || !strcmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
                        || !strcmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)
                        || !strcmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
                    // AVC & HEVC requires compression ratio of at least 2, and uses
                    // macroblocks
                    max_size = ((width + 15) / 16) * ((height + 15) / 16) * 192;
@@ -2315,6 +2386,30 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
            *offset += chunk_size;
            break;
        }
        case FOURCC("dvcC"):
        case FOURCC("dvvC"): {
            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 (mLastTrack == NULL)
                return ERROR_MALFORMED;

            AMediaFormat_setBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_2,
                                   buffer.get(), chunk_data_size);
            AMediaFormat_setString(mLastTrack->meta, AMEDIAFORMAT_KEY_MIME,
                                   MEDIA_MIMETYPE_VIDEO_DOLBY_VISION);

            *offset += chunk_size;
            break;
        }
        case FOURCC("d263"):
        {
            *offset += chunk_size;
@@ -4127,6 +4222,19 @@ MediaTrackHelper *MPEG4Extractor::getTrack(size_t index) {
        if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
            itemTable = mItemTable;
        }
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
        void *data;
        size_t size;
        if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_2, &data, &size)) {
            return NULL;
        }

        const uint8_t *ptr = (const uint8_t *)data;

        // dv_major.dv_minor Should be 1.0 or 2.1
        if (size != 24 || ((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1))) {
            return NULL;
        }
   } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)) {
        void *data;
        size_t size;
@@ -4172,6 +4280,10 @@ status_t MPEG4Extractor::verifyTrack(Track *track) {
        if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_HEVC, &data, &size)) {
            return ERROR_MALFORMED;
        }
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
        if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_2, &data, &size)) {
            return ERROR_MALFORMED;
        }
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)) {
        if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_0, &data, &size)) {
            return ERROR_MALFORMED;
@@ -4659,6 +4771,7 @@ MPEG4Source::MPEG4Source(
      mCurrentSampleInfoOffsets(NULL),
      mIsAVC(false),
      mIsHEVC(false),
      mIsDolbyVision(false),
      mIsAC4(false),
      mIsPcm(false),
      mNALLengthSize(0),
@@ -4698,6 +4811,7 @@ MPEG4Source::MPEG4Source(
    mIsHEVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) ||
              !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
    mIsAC4 = !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC4);
    mIsDolbyVision = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION);

    if (mIsAVC) {
        void *data;
@@ -4722,6 +4836,42 @@ MPEG4Source::MPEG4Source(
        CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1

        mNALLengthSize = 1 + (ptr[14 + 7] & 3);
    } else if (mIsDolbyVision) {
        ALOGV("%s DolbyVision stream detected", __FUNCTION__);
        void *data;
        size_t size;
        CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_2, &data, &size));

        const uint8_t *ptr = (const uint8_t *)data;

        CHECK(size == 24);

        // dv_major.dv_minor Should be 1.0 or 2.1
        CHECK(!((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1)));

        const uint8_t profile = ptr[2] >> 1;
        // profile == (unknown,1,9) --> AVC; profile = (2,3,4,5,6,7,8) --> HEVC;
        // profile == (10) --> AV1
        if (profile > 1 && profile < 9) {
            CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_HEVC, &data, &size));

            const uint8_t *ptr = (const uint8_t *)data;

            CHECK(size >= 22);
            CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1

            mNALLengthSize = 1 + (ptr[14 + 7] & 3);
        } else if (10 == profile) {
            /* AV1 profile nothing to do */
        } else {
            CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_AVC, &data, &size));
            const uint8_t *ptr = (const uint8_t *)data;

            CHECK(size >= 7);
            CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
            // The number of bytes used to encode the length of a NAL unit.
            mNALLengthSize = 1 + (ptr[4] & 3);
        }
    }

    mIsPcm = !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW);
@@ -5789,7 +5939,7 @@ media_status_t MPEG4Source::read(
        }
    }

    if (!mIsAVC && !mIsHEVC && !mIsAC4) {
    if (!mIsAVC && !mIsHEVC && !(mIsDolbyVision && mNALLengthSize) && !mIsAC4) {
        if (newBuffer) {
            if (mIsPcm) {
                // The twos' PCM block reader assumes that all samples has the same size.
@@ -6179,7 +6329,7 @@ media_status_t MPEG4Source::fragmentedRead(
        AMediaFormat_setBuffer(bufmeta, AMEDIAFORMAT_KEY_CRYPTO_IV, iv, ivlength);
    }

    if (!mIsAVC && !mIsHEVC) {
    if (!mIsAVC && !mIsHEVC && !(mIsDolbyVision && mNALLengthSize)) {
        if (newBuffer) {
            if (!isInRange((size_t)0u, mBuffer->size(), size)) {
                mBuffer->release();
+4 −2
Original line number Diff line number Diff line
@@ -2213,8 +2213,10 @@ void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) ||
               !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
        mMeta->findData(kKeyHVCC, &type, &data, &size);
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
        mMeta->findData(kKeyDVCC, &type, &data, &size);
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
               !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
        if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
            ESDS esds(data, size);
            if (esds.getCodecSpecificInfo(&data, &size) == OK &&
+105 −1
Original line number Diff line number Diff line
@@ -227,6 +227,68 @@ static void parseAvcProfileLevelFromAvcc(const uint8_t *ptr, size_t size, sp<AMe
    }
}

static void parseDolbyVisionProfileLevelFromDvcc(const uint8_t *ptr, size_t size, sp<AMessage> &format) {
    // dv_major.dv_minor Should be 1.0 or 2.1
    if (size != 24 || ((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1))) {
        ALOGV("Size %zu, dv_major %d, dv_minor %d", size, ptr[0], ptr[1]);
        return;
    }

    const uint8_t profile = ptr[2] >> 1;
    const uint8_t level = ((ptr[2] & 0x1) << 5) | ((ptr[3] >> 3) & 0x1f);
    const uint8_t rpu_present_flag = (ptr[3] >> 2) & 0x01;
    const uint8_t el_present_flag = (ptr[3] >> 1) & 0x01;
    const uint8_t bl_present_flag = (ptr[3] & 0x01);
    const int32_t bl_compatibility_id = (int32_t)(ptr[4] >> 4);

    ALOGV("profile-level-compatibility value in dv(c|v)c box %d-%d-%d",
          profile, level, bl_compatibility_id);

    // All Dolby Profiles will have profile and level info in MediaFormat
    // Profile 8 and 9 will have bl_compatibility_id too.
    const static ALookup<uint8_t, OMX_VIDEO_DOLBYVISIONPROFILETYPE> profiles{
        {1, OMX_VIDEO_DolbyVisionProfileDvavPen},
        {3, OMX_VIDEO_DolbyVisionProfileDvheDen},
        {4, OMX_VIDEO_DolbyVisionProfileDvheDtr},
        {5, OMX_VIDEO_DolbyVisionProfileDvheStn},
        {6, OMX_VIDEO_DolbyVisionProfileDvheDth},
        {7, OMX_VIDEO_DolbyVisionProfileDvheDtb},
        {8, OMX_VIDEO_DolbyVisionProfileDvheSt},
        {9, OMX_VIDEO_DolbyVisionProfileDvavSe},
        {10, OMX_VIDEO_DolbyVisionProfileDvav110},
    };

    const static ALookup<uint8_t, OMX_VIDEO_DOLBYVISIONLEVELTYPE> levels{
        {0, OMX_VIDEO_DolbyVisionLevelUnknown},
        {1, OMX_VIDEO_DolbyVisionLevelHd24},
        {2, OMX_VIDEO_DolbyVisionLevelHd30},
        {3, OMX_VIDEO_DolbyVisionLevelFhd24},
        {4, OMX_VIDEO_DolbyVisionLevelFhd30},
        {5, OMX_VIDEO_DolbyVisionLevelFhd60},
        {6, OMX_VIDEO_DolbyVisionLevelUhd24},
        {7, OMX_VIDEO_DolbyVisionLevelUhd30},
        {8, OMX_VIDEO_DolbyVisionLevelUhd48},
        {9, OMX_VIDEO_DolbyVisionLevelUhd60},
    };
    // set rpuAssoc
    if (rpu_present_flag && el_present_flag && !bl_present_flag) {
        format->setInt32("rpuAssoc", 1);
    }
    // set profile & level if they are recognized
    OMX_VIDEO_DOLBYVISIONPROFILETYPE codecProfile;
    OMX_VIDEO_DOLBYVISIONLEVELTYPE codecLevel;
    if (profiles.map(profile, &codecProfile)) {
        format->setInt32("profile", codecProfile);
        if (codecProfile == OMX_VIDEO_DolbyVisionProfileDvheSt ||
            codecProfile == OMX_VIDEO_DolbyVisionProfileDvavSe) {
            format->setInt32("bl_compatibility_id", bl_compatibility_id);
        }
        if (levels.map(level, &codecLevel)) {
            format->setInt32("level", codecLevel);
        }
    }
}

static void parseH263ProfileLevelFromD263(const uint8_t *ptr, size_t size, sp<AMessage> &format) {
    if (size < 7) {
        return;
@@ -1411,6 +1473,12 @@ status_t convertMetaDataToMessage(
        msg->setBuffer("csd-0", buffer);
    }

    if (meta->findData(kKeyDVCC, &type, &data, &size)) {
        const uint8_t *ptr = (const uint8_t *)data;
        ALOGV("DV: calling parseDolbyVisionProfileLevelFromDvcc with data size %zu", size);
        parseDolbyVisionProfileLevelFromDvcc(ptr, size, msg);
    }

    *format = msg;

    return OK;
@@ -1839,6 +1907,32 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) {
            meta->setData(kKeyHVCC, kTypeHVCC, hvcc.data(), outsize);
        } else if (mime == MEDIA_MIMETYPE_VIDEO_AV1) {
            meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
        } else if (mime == MEDIA_MIMETYPE_VIDEO_DOLBY_VISION) {
            if (msg->findBuffer("csd-2", &csd2)) {
                meta->setData(kKeyDVCC, kTypeDVCC, csd2->data(), csd2->size());

                size_t dvcc_size = 1024;
                uint8_t dvcc[dvcc_size];
                memcpy(dvcc, csd2->data(), dvcc_size);
                const uint8_t profile = dvcc[2] >> 1;

                if (profile > 1 && profile < 9) {
                    std::vector<uint8_t> hvcc(csd0size + 1024);
                    size_t outsize = reassembleHVCC(csd0, hvcc.data(), hvcc.size(), 4);
                    meta->setData(kKeyHVCC, kTypeHVCC, hvcc.data(), outsize);
                } else if (DolbyVisionProfileDvav110 == profile) {
                    meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
                } else {
                    sp<ABuffer> csd1;
                    if (msg->findBuffer("csd-1", &csd1)) {
                        std::vector<char> avcc(csd0size + csd1->size() + 1024);
                        size_t outsize = reassembleAVCC(csd0, csd1, avcc.data());
                        meta->setData(kKeyAVCC, kTypeAVCC, avcc.data(), outsize);
                    }
                }
            } else {
                ALOGW("We need csd-2!!. %s", msg->debugString().c_str());
            }
        } else if (mime == MEDIA_MIMETYPE_VIDEO_VP9) {
            meta->setData(kKeyVp9CodecPrivate, 0, csd0->data(), csd0->size());
        } else if (mime == MEDIA_MIMETYPE_AUDIO_OPUS) {
@@ -1885,8 +1979,18 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) {
        meta->setData(kKeyStreamHeader, 'mdat', csd0->data(), csd0->size());
    } else if (msg->findBuffer("d263", &csd0)) {
        meta->setData(kKeyD263, kTypeD263, csd0->data(), csd0->size());
    }
    } else if (mime == MEDIA_MIMETYPE_VIDEO_DOLBY_VISION && msg->findBuffer("csd-2", &csd2)) {
        meta->setData(kKeyDVCC, kTypeDVCC, csd2->data(), csd2->size());

        // Remove CSD-2 from the data here to avoid duplicate data in meta
        meta->remove(kKeyOpaqueCSD2);

        if (msg->findBuffer("csd-avc", &csd0)) {
            meta->setData(kKeyAVCC, kTypeAVCC, csd0->data(), csd0->size());
        } else if (msg->findBuffer("csd-hevc", &csd0)) {
            meta->setData(kKeyHVCC, kTypeHVCC, csd0->data(), csd0->size());
        }
    }
    // XXX TODO add whatever other keys there are

#if 0
Loading