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

Commit 5f3004c1 authored by Andreas Huber's avatar Andreas Huber Committed by Android Git Automerger
Browse files

am 779b9b82: am f7617d36: Merge "Support for thumbnail extraction in the...

am 779b9b82: am f7617d36: Merge "Support for thumbnail extraction in the Matroska extractor." into kraken
parents 2bdc3e1a 779b9b82
Loading
Loading
Loading
Loading
+131 −41
Original line number Diff line number Diff line
@@ -121,6 +121,29 @@ static void hexdump(const void *_data, size_t size) {
    }
}

struct BlockIterator {
    BlockIterator(mkvparser::Segment *segment, unsigned long trackNum);

    bool eos() const;

    void advance();
    void reset();
    void seek(int64_t seekTimeUs);

    const mkvparser::Block *block() const;
    int64_t blockTimeUs() const;

private:
    mkvparser::Segment *mSegment;
    unsigned long mTrackNum;

    mkvparser::Cluster *mCluster;
    const mkvparser::BlockEntry *mBlockEntry;

    BlockIterator(const BlockIterator &);
    BlockIterator &operator=(const BlockIterator &);
};

struct MatroskaSource : public MediaSource {
    MatroskaSource(
            const sp<MatroskaExtractor> &extractor, size_t index);
@@ -142,10 +165,8 @@ private:

    sp<MatroskaExtractor> mExtractor;
    size_t mTrackIndex;
    unsigned long mTrackNum;
    Type mType;
    mkvparser::Cluster *mCluster;
    const mkvparser::BlockEntry *mBlockEntry;
    BlockIterator mBlockIter;

    status_t advance();

@@ -158,10 +179,8 @@ MatroskaSource::MatroskaSource(
    : mExtractor(extractor),
      mTrackIndex(index),
      mType(OTHER),
      mCluster(NULL),
      mBlockEntry(NULL) {
    mTrackNum = mExtractor->mTracks.itemAt(index).mTrackNum;

      mBlockIter(mExtractor->mSegment,
                 mExtractor->mTracks.itemAt(index).mTrackNum) {
    const char *mime;
    CHECK(mExtractor->mTracks.itemAt(index).mMeta->
            findCString(kKeyMIMEType, &mime));
@@ -174,8 +193,7 @@ MatroskaSource::MatroskaSource(
}

status_t MatroskaSource::start(MetaData *params) {
    mCluster = NULL;
    mBlockEntry = NULL;
    mBlockIter.reset();

    return OK;
}
@@ -188,60 +206,95 @@ sp<MetaData> MatroskaSource::getFormat() {
    return mExtractor->mTracks.itemAt(mTrackIndex).mMeta;
}

status_t MatroskaSource::advance() {
    for (;;) {
        if (mBlockEntry == NULL || mBlockEntry->EOS()) {
            if (mCluster == NULL) {
                mCluster = mExtractor->mSegment->GetFirst();
            } else {
                mCluster = mExtractor->mSegment->GetNext(mCluster);
            }
            if (mCluster == NULL || mCluster->EOS()) {
                return ERROR_END_OF_STREAM;
////////////////////////////////////////////////////////////////////////////////

BlockIterator::BlockIterator(
        mkvparser::Segment *segment, unsigned long trackNum)
    : mSegment(segment),
      mTrackNum(trackNum),
      mCluster(NULL),
      mBlockEntry(NULL) {
    reset();
}
            mBlockEntry = mCluster->GetFirst();

bool BlockIterator::eos() const {
    return mCluster == NULL || mCluster->EOS();
}

        if (mBlockEntry->GetBlock()->GetTrackNumber() != mTrackNum) {
void BlockIterator::advance() {
    while (!eos()) {
        if (mBlockEntry != NULL) {
            mBlockEntry = mCluster->GetNext(mBlockEntry);
            continue;
        } else if (mCluster != NULL) {
            mCluster = mSegment->GetNext(mCluster);

            if (eos()) {
                break;
            }

            mBlockEntry = mCluster->GetFirst();
        }

        if (mBlockEntry != NULL
                && mBlockEntry->GetBlock()->GetTrackNumber() == mTrackNum) {
            break;
        }
    }
}

    return OK;
void BlockIterator::reset() {
    mCluster = mSegment->GetFirst();
    mBlockEntry = mCluster->GetFirst();

    while (!eos() && block()->GetTrackNumber() != mTrackNum) {
        advance();
    }
}

void BlockIterator::seek(int64_t seekTimeUs) {
    mCluster = mSegment->GetCluster(seekTimeUs * 1000ll);
    mBlockEntry = mCluster != NULL ? mCluster->GetFirst() : NULL;

    while (!eos() && block()->GetTrackNumber() != mTrackNum) {
        advance();
    }

    while (!eos() && !mBlockEntry->GetBlock()->IsKey()) {
        advance();
    }
}

const mkvparser::Block *BlockIterator::block() const {
    CHECK(!eos());

    return mBlockEntry->GetBlock();
}

int64_t BlockIterator::blockTimeUs() const {
    return (mBlockEntry->GetBlock()->GetTime(mCluster) + 500ll) / 1000ll;
}

////////////////////////////////////////////////////////////////////////////////

status_t MatroskaSource::read(
        MediaBuffer **out, const ReadOptions *options) {
    *out = NULL;

    int64_t seekTimeUs;
    if (options && options->getSeekTo(&seekTimeUs)) {
        mBlockEntry = NULL;
        mCluster = mExtractor->mSegment->GetCluster(seekTimeUs * 1000ll);

        status_t err;
        while ((err = advance()) == OK && !mBlockEntry->GetBlock()->IsKey()) {
            mBlockEntry = mCluster->GetNext(mBlockEntry);
        mBlockIter.seek(seekTimeUs);
    }

        if (err != OK) {
    if (mBlockIter.eos()) {
        return ERROR_END_OF_STREAM;
    }
    }

    if (advance() != OK) {
        return ERROR_END_OF_STREAM;
    }

    const mkvparser::Block *block = mBlockEntry->GetBlock();
    const mkvparser::Block *block = mBlockIter.block();
    size_t size = block->GetSize();
    long long timeNs = block->GetTime(mCluster);
    int64_t timeUs = mBlockIter.blockTimeUs();

    MediaBuffer *buffer = new MediaBuffer(size + 2);
    buffer->meta_data()->setInt64(kKeyTime, (timeNs + 500) / 1000);
    buffer->meta_data()->setInt64(kKeyTime, timeUs);

    long res = block->Read(
            mExtractor->mReader, (unsigned char *)buffer->data() + 2);
@@ -280,7 +333,7 @@ status_t MatroskaSource::read(
            buffer->range_length());
#endif

    mBlockEntry = mCluster->GetNext(mBlockEntry);
    mBlockIter.advance();

    return OK;
}
@@ -290,7 +343,8 @@ status_t MatroskaSource::read(
MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source)
    : mDataSource(source),
      mReader(new DataSourceReader(mDataSource)),
      mSegment(NULL) {
      mSegment(NULL),
      mExtractedThumbnails(false) {
    mkvparser::EBMLHeader ebmlHeader;
    long long pos;
    if (ebmlHeader.Parse(mReader, pos) < 0) {
@@ -342,6 +396,11 @@ sp<MetaData> MatroskaExtractor::getTrackMetaData(
        return NULL;
    }

    if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails) {
        findThumbnails();
        mExtractedThumbnails = true;
    }

    return mTracks.itemAt(index).mMeta;
}

@@ -479,6 +538,37 @@ void MatroskaExtractor::addTracks() {
    }
}

void MatroskaExtractor::findThumbnails() {
    for (size_t i = 0; i < mTracks.size(); ++i) {
        TrackInfo *info = &mTracks.editItemAt(i);

        const char *mime;
        CHECK(info->mMeta->findCString(kKeyMIMEType, &mime));

        if (strncasecmp(mime, "video/", 6)) {
            continue;
        }

        BlockIterator iter(mSegment, info->mTrackNum);
        int32_t i = 0;
        int64_t thumbnailTimeUs = 0;
        size_t maxBlockSize = 0;
        while (!iter.eos() && i < 20) {
            if (iter.block()->IsKey()) {
                ++i;

                size_t blockSize = iter.block()->GetSize();
                if (blockSize > maxBlockSize) {
                    maxBlockSize = blockSize;
                    thumbnailTimeUs = iter.blockTimeUs();
                }
            }
            iter.advance();
        }
        info->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
    }
}

sp<MetaData> MatroskaExtractor::getMetaData() {
    sp<MetaData> meta = new MetaData;
    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MATROSKA);
+2 −0
Original line number Diff line number Diff line
@@ -59,8 +59,10 @@ private:
    sp<DataSource> mDataSource;
    DataSourceReader *mReader;
    mkvparser::Segment *mSegment;
    bool mExtractedThumbnails;

    void addTracks();
    void findThumbnails();

    MatroskaExtractor(const MatroskaExtractor &);
    MatroskaExtractor &operator=(const MatroskaExtractor &);