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

Commit 8a454611 authored by Lajos Molnar's avatar Lajos Molnar Committed by Android (Google) Code Review
Browse files

Merge "stagefright: added support, and SoftOMX decoder, for HEVC" into lmp-preview-dev

parents 270facca 3b5a6b9f
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ enum {
    kKeyESDS              = 'esds',  // raw data
    kKeyAACProfile        = 'aacp',  // int32_t
    kKeyAVCC              = 'avcc',  // raw data
    kKeyHVCC              = 'hvcc',  // raw data
    kKeyD263              = 'd263',  // raw data
    kKeyVorbisInfo        = 'vinf',  // raw data
    kKeyVorbisBooks       = 'vboo',  // raw data
@@ -170,6 +171,7 @@ enum {
enum {
    kTypeESDS        = 'esds',
    kTypeAVCC        = 'avcc',
    kTypeHVCC        = 'hvcc',
    kTypeD263        = 'd263',
};

+3 −0
Original line number Diff line number Diff line
@@ -352,6 +352,9 @@ private:

    int64_t getDecodingTimeUs();

    status_t parseHEVCCodecSpecificData(
            const void *data, size_t size,
            unsigned *profile, unsigned *level);
    status_t parseAVCCodecSpecificData(
            const void *data, size_t size,
            unsigned *profile, unsigned *level);
+46 −4
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ private:
    uint64_t* mCurrentSampleInfoOffsets;

    bool mIsAVC;
    bool mIsHEVC;
    size_t mNALLengthSize;

    bool mStarted;
@@ -317,6 +318,9 @@ static const char *FourCC2MIME(uint32_t fourcc) {
        case FOURCC('a', 'v', 'c', '1'):
            return MEDIA_MIMETYPE_VIDEO_AVC;

        case FOURCC('h', 'v', 'c', '1'):
        case FOURCC('h', 'e', 'v', '1'):
            return MEDIA_MIMETYPE_VIDEO_HEVC;
        default:
            CHECK(!"should not be here.");
            return NULL;
@@ -1288,6 +1292,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
        case FOURCC('H', '2', '6', '3'):
        case FOURCC('h', '2', '6', '3'):
        case FOURCC('a', 'v', 'c', '1'):
        case FOURCC('h', 'v', 'c', '1'):
        case FOURCC('h', 'e', 'v', '1'):
        {
            mHasVideo = true;

@@ -1580,6 +1586,21 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {

            break;
        }
        case FOURCC('h', 'v', 'c', 'C'):
        {
            sp<ABuffer> buffer = new ABuffer(chunk_data_size);

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

            mLastTrack->meta->setData(
                    kKeyHVCC, kTypeHVCC, buffer->data(), chunk_data_size);

            *offset += chunk_size;
            break;
        }

        case FOURCC('d', '2', '6', '3'):
        {
@@ -2452,6 +2473,11 @@ status_t MPEG4Extractor::verifyTrack(Track *track) {
                || type != kTypeAVCC) {
            return ERROR_MALFORMED;
        }
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
        if (!track->meta->findData(kKeyHVCC, &type, &data, &size)
                    || type != kTypeHVCC) {
            return ERROR_MALFORMED;
        }
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
        if (!track->meta->findData(kKeyESDS, &type, &data, &size)
@@ -2776,6 +2802,7 @@ MPEG4Source::MPEG4Source(
      mCurrentSampleInfoOffsetsAllocSize(0),
      mCurrentSampleInfoOffsets(NULL),
      mIsAVC(false),
      mIsHEVC(false),
      mNALLengthSize(0),
      mStarted(false),
      mGroup(NULL),
@@ -2800,6 +2827,7 @@ MPEG4Source::MPEG4Source(
    CHECK(success);

    mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
    mIsHEVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);

    if (mIsAVC) {
        uint32_t type;
@@ -2814,6 +2842,18 @@ MPEG4Source::MPEG4Source(

        // The number of bytes used to encode the length of a NAL unit.
        mNALLengthSize = 1 + (ptr[4] & 3);
    } else if (mIsHEVC) {
        uint32_t type;
        const void *data;
        size_t size;
        CHECK(format->findData(kKeyHVCC, &type, &data, &size));

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

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

        mNALLengthSize = 1 + (ptr[14 + 7] & 3);
    }

    CHECK(format->findInt32(kKeyTrackID, &mTrackId));
@@ -3562,7 +3602,7 @@ status_t MPEG4Source::read(
        }
    }

    if (!mIsAVC || mWantsNALFragments) {
    if ((!mIsAVC && !mIsHEVC) || mWantsNALFragments) {
        if (newBuffer) {
            ssize_t num_bytes_read =
                mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
@@ -3594,7 +3634,7 @@ status_t MPEG4Source::read(
            ++mCurrentSampleIndex;
        }

        if (!mIsAVC) {
        if (!mIsAVC && !mIsHEVC) {
            *out = mBuffer;
            mBuffer = NULL;

@@ -3837,7 +3877,7 @@ status_t MPEG4Source::fragmentedRead(
        bufmeta->setData(kKeyCryptoKey, 0, mCryptoKey, 16);
    }

    if (!mIsAVC || mWantsNALFragments) {
    if ((!mIsAVC && !mIsHEVC)|| mWantsNALFragments) {
        if (newBuffer) {
            ssize_t num_bytes_read =
                mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
@@ -3869,7 +3909,7 @@ status_t MPEG4Source::fragmentedRead(
            ++mCurrentSampleIndex;
        }

        if (!mIsAVC) {
        if (!mIsAVC && !mIsHEVC) {
            *out = mBuffer;
            mBuffer = NULL;

@@ -4043,6 +4083,8 @@ static bool isCompatibleBrand(uint32_t fourcc) {
        FOURCC('i', 's', 'o', 'm'),
        FOURCC('i', 's', 'o', '2'),
        FOURCC('a', 'v', 'c', '1'),
        FOURCC('h', 'v', 'c', '1'),
        FOURCC('h', 'e', 'v', '1'),
        FOURCC('3', 'g', 'p', '4'),
        FOURCC('m', 'p', '4', '1'),
        FOURCC('m', 'p', '4', '2'),
+73 −1
Original line number Diff line number Diff line
@@ -381,6 +381,57 @@ sp<MediaSource> OMXCodec::Create(
    return NULL;
}

status_t OMXCodec::parseHEVCCodecSpecificData(
        const void *data, size_t size,
        unsigned *profile, unsigned *level) {
    const uint8_t *ptr = (const uint8_t *)data;

    // verify minimum size and configurationVersion == 1.
    if (size < 7 || ptr[0] != 1) {
        return ERROR_MALFORMED;
    }

    *profile = (ptr[1] & 31);
    *level = ptr[12];

    ptr += 22;
    size -= 22;

    size_t numofArrays = (char)ptr[0];
    ptr += 1;
    size -= 1;
    size_t j = 0, i = 0;
    for (i = 0; i < numofArrays; i++) {
        ptr += 1;
        size -= 1;

        // Num of nals
        size_t numofNals = U16_AT(ptr);
        ptr += 2;
        size -= 2;

        for (j = 0;j < numofNals;j++) {
            if (size < 2) {
                return ERROR_MALFORMED;
            }

            size_t length = U16_AT(ptr);

            ptr += 2;
            size -= 2;

            if (size < length) {
                return ERROR_MALFORMED;
            }
            addCodecSpecificData(ptr, length);

            ptr += length;
            size -= length;
        }
    }
    return OK;
}

status_t OMXCodec::parseAVCCodecSpecificData(
        const void *data, size_t size,
        unsigned *profile, unsigned *level) {
@@ -493,6 +544,20 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta) {
            CODEC_LOGI(
                    "AVC profile = %u (%s), level = %u",
                    profile, AVCProfileToString(profile), level);
        } else if (meta->findData(kKeyHVCC, &type, &data, &size)) {
            // Parse the HEVCDecoderConfigurationRecord

            unsigned profile, level;
            status_t err;
            if ((err = parseHEVCCodecSpecificData(
                            data, size, &profile, &level)) != OK) {
                ALOGE("Malformed HEVC codec specific data.");
                return err;
            }

            CODEC_LOGI(
                    "HEVC profile = %u , level = %u",
                    profile, level);
        } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) {
            addCodecSpecificData(data, size);

@@ -822,6 +887,8 @@ void OMXCodec::setVideoInputFormat(
    OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
        compressionFormat = OMX_VIDEO_CodingAVC;
    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
        compressionFormat = OMX_VIDEO_CodingHEVC;
    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
        compressionFormat = OMX_VIDEO_CodingMPEG4;
    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
@@ -1217,6 +1284,8 @@ status_t OMXCodec::setVideoOutputFormat(
        compressionFormat = OMX_VIDEO_CodingAVC;
    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
        compressionFormat = OMX_VIDEO_CodingMPEG4;
    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
        compressionFormat = OMX_VIDEO_CodingHEVC;
    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
        compressionFormat = OMX_VIDEO_CodingH263;
    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_VP8, mime)) {
@@ -1411,6 +1480,8 @@ void OMXCodec::setComponentRole(
            "audio_decoder.g711alaw", "audio_encoder.g711alaw" },
        { MEDIA_MIMETYPE_VIDEO_AVC,
            "video_decoder.avc", "video_encoder.avc" },
        { MEDIA_MIMETYPE_VIDEO_HEVC,
            "video_decoder.hevc", "video_encoder.hevc" },
        { MEDIA_MIMETYPE_VIDEO_MPEG4,
            "video_decoder.mpeg4", "video_encoder.mpeg4" },
        { MEDIA_MIMETYPE_VIDEO_H263,
@@ -3009,7 +3080,8 @@ bool OMXCodec::drainInputBuffer(BufferInfo *info) {

        size_t size = specific->mSize;

        if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mMIME)
        if ((!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mMIME) ||
             !strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mMIME))
                && !(mQuirks & kWantsNALFragments)) {
            static const uint8_t kNALStartCode[4] =
                    { 0x00, 0x00, 0x00, 0x01 };
+50 −0
Original line number Diff line number Diff line
@@ -217,6 +217,56 @@ status_t convertMetaDataToMessage(
        buffer->meta()->setInt32("csd", true);
        buffer->meta()->setInt64("timeUs", 0);
        msg->setBuffer("csd-1", buffer);
    } else if (meta->findData(kKeyHVCC, &type, &data, &size)) {
        const uint8_t *ptr = (const uint8_t *)data;

        CHECK(size >= 7);
        CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
        uint8_t profile = ptr[1] & 31;
        uint8_t level = ptr[12];
        ptr += 22;
        size -= 22;


        size_t numofArrays = (char)ptr[0];
        ptr += 1;
        size -= 1;
        size_t j = 0, i = 0;

        sp<ABuffer> buffer = new ABuffer(1024);
        buffer->setRange(0, 0);

        for (i = 0; i < numofArrays; i++) {
            ptr += 1;
            size -= 1;

            //Num of nals
            size_t numofNals = U16_AT(ptr);

            ptr += 2;
            size -= 2;

            for (j = 0; j < numofNals; j++) {
                CHECK(size >= 2);
                size_t length = U16_AT(ptr);

                ptr += 2;
                size -= 2;

                CHECK(size >= length);

                memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4);
                memcpy(buffer->data() + buffer->size() + 4, ptr, length);
                buffer->setRange(0, buffer->size() + 4 + length);

                ptr += length;
                size -= length;
            }
        }
        buffer->meta()->setInt32("csd", true);
        buffer->meta()->setInt64("timeUs", 0);
        msg->setBuffer("csd-0", buffer);

    } else if (meta->findData(kKeyESDS, &type, &data, &size)) {
        ESDS esds((const char *)data, size);
        CHECK_EQ(esds.InitCheck(), (status_t)OK);
Loading