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

Commit a1952145 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "AppendData:MPEG4Writer&Extractor,MediaAppender" into sc-dev

parents c1d928bc 4449e397
Loading
Loading
Loading
Loading
+24 −1
Original line number Diff line number Diff line
@@ -6266,6 +6266,18 @@ media_status_t MPEG4Source::read(
                    AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_IS_SYNC_FRAME, 1);
                }

                AMediaFormat_setInt64(
                        meta, "sample-file-offset" /*AMEDIAFORMAT_KEY_SAMPLE_FILE_OFFSET*/,
                        offset);

                if (mSampleTable != nullptr &&
                        mCurrentSampleIndex == mSampleTable->getLastSampleIndexInChunk()) {
                    AMediaFormat_setInt64(
                    meta,
                    "last-sample-index-in-chunk" /*AMEDIAFORMAT_KEY_LAST_SAMPLE_INDEX_IN_CHUNK*/,
                    mSampleTable->getLastSampleIndexInChunk());
                }

                ++mCurrentSampleIndex;
            }
        }
@@ -6415,6 +6427,17 @@ media_status_t MPEG4Source::read(
            AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_IS_SYNC_FRAME, 1);
        }

        AMediaFormat_setInt64(
                meta, "sample-file-offset" /*AMEDIAFORMAT_KEY_SAMPLE_FILE_OFFSET*/, offset);

        if (mSampleTable != nullptr &&
                mCurrentSampleIndex == mSampleTable->getLastSampleIndexInChunk()) {
            AMediaFormat_setInt64(
                    meta,
                    "last-sample-index-in-chunk" /*AMEDIAFORMAT_KEY_LAST_SAMPLE_INDEX_IN_CHUNK*/,
                    mSampleTable->getLastSampleIndexInChunk());
        }

        ++mCurrentSampleIndex;

        *out = mBuffer;
+1 −0
Original line number Diff line number Diff line
@@ -274,6 +274,7 @@ cc_library {
        "MPEG2TSWriter.cpp",
        "MPEG4Writer.cpp",
        "MediaAdapter.cpp",
        "MediaAppender.cpp",
        "MediaClock.cpp",
        "MediaCodec.cpp",
        "MediaCodecList.cpp",
+72 −10
Original line number Diff line number Diff line
@@ -519,12 +519,12 @@ void MPEG4Writer::initInternal(int fd, bool isFirstSession) {
    mSendNotify = false;
    mWriteSeekErr = false;
    mFallocateErr = false;

    // Reset following variables for all the sessions and they will be
    // initialized in start(MetaData *param).
    mIsRealTimeRecording = true;
    mUse4ByteNalLength = true;
    mOffset = 0;
    mMaxOffsetAppend = 0;
    mPreAllocateFileEndOffset = 0;
    mMdatOffset = 0;
    mMdatEndOffset = 0;
@@ -992,6 +992,19 @@ status_t MPEG4Writer::start(MetaData *param) {
        seekOrPostError(mFd, mFreeBoxOffset, SEEK_SET);
        writeInt32(mInMemoryCacheSize);
        write("free", 4);
        if (mInMemoryCacheSize >= 8) {
            off64_t bufSize = mInMemoryCacheSize - 8;
            char* zeroBuffer = new (std::nothrow) char[bufSize];
            if (zeroBuffer) {
                std::fill_n(zeroBuffer, bufSize, '0');
                writeOrPostError(mFd, zeroBuffer, bufSize);
                delete [] zeroBuffer;
            } else {
                ALOGW("freebox in file isn't initialized to 0");
            }
        } else {
            ALOGW("freebox size is less than 8:%" PRId64, mInMemoryCacheSize);
        }
        mMdatOffset = mFreeBoxOffset + mInMemoryCacheSize;
    } else {
        mMdatOffset = mOffset;
@@ -1541,6 +1554,26 @@ off64_t MPEG4Writer::addSample_l(
        MediaBuffer *buffer, bool usePrefix,
        uint32_t tiffHdrOffset, size_t *bytesWritten) {
    off64_t old_offset = mOffset;
    int64_t offset;
    ALOGV("buffer->range_length:%lld", (long long)buffer->range_length());
    if (buffer->meta_data().findInt64(kKeySampleFileOffset, &offset)) {
        ALOGV("offset:%lld, old_offset:%lld", (long long)offset, (long long)old_offset);
        if (old_offset == offset) {
            mOffset += buffer->range_length();
        } else {
            ALOGV("offset and old_offset are not equal! diff:%lld", (long long)offset - old_offset);
            mOffset = offset + buffer->range_length();
            // mOffset += buffer->range_length() + offset - old_offset;
        }
        *bytesWritten = buffer->range_length();
        ALOGV("mOffset:%lld, mMaxOffsetAppend:%lld, bytesWritten:%lld", (long long)mOffset,
                  (long long)mMaxOffsetAppend, (long long)*bytesWritten);
        mMaxOffsetAppend = std::max(mOffset, mMaxOffsetAppend);
        seekOrPostError(mFd, mMaxOffsetAppend, SEEK_SET);
        return offset;
    }

    ALOGV("mOffset:%lld, mMaxOffsetAppend:%lld", (long long)mOffset, (long long)mMaxOffsetAppend);

    if (usePrefix) {
        addMultipleLengthPrefixedSamples_l(buffer);
@@ -1557,6 +1590,10 @@ off64_t MPEG4Writer::addSample_l(
        mOffset += buffer->range_length();
    }
    *bytesWritten = mOffset - old_offset;

    ALOGV("mOffset:%lld, old_offset:%lld, bytesWritten:%lld", (long long)mOffset,
          (long long)old_offset, (long long)*bytesWritten);

    return old_offset;
}

@@ -1569,6 +1606,7 @@ static void StripStartcode(MediaBuffer *buffer) {
        (const uint8_t *)buffer->data() + buffer->range_offset();

    if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
        ALOGV("stripping start code");
        buffer->set_range(
                buffer->range_offset() + 4, buffer->range_length() - 4);
    }
@@ -1599,8 +1637,10 @@ void MPEG4Writer::addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer) {
}

void MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
    ALOGV("alp:buffer->range_length:%lld", (long long)buffer->range_length());
    size_t length = buffer->range_length();
    if (mUse4ByteNalLength) {
        ALOGV("mUse4ByteNalLength");
        uint8_t x[4];
        x[0] = length >> 24;
        x[1] = (length >> 16) & 0xff;
@@ -1610,6 +1650,7 @@ void MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
        writeOrPostError(mFd, (const uint8_t*)buffer->data() + buffer->range_offset(), length);
        mOffset += length + 4;
    } else {
        ALOGV("mUse2ByteNalLength");
        CHECK_LT(length, 65536u);

        uint8_t x[2];
@@ -2762,6 +2803,9 @@ void MPEG4Writer::threadFunc() {
    }

    writeAllChunks();
    ALOGV("threadFunc mOffset:%lld, mMaxOffsetAppend:%lld", (long long)mOffset,
          (long long)mMaxOffsetAppend);
    mOffset = std::max(mOffset, mMaxOffsetAppend);
}

status_t MPEG4Writer::startWriterThread() {
@@ -3323,6 +3367,7 @@ status_t MPEG4Writer::Track::threadEntry() {
    uint32_t lastSamplesPerChunk = 0;
    int64_t lastSampleDurationUs = -1;      // Duration calculated from EOS buffer and its timestamp
    int64_t lastSampleDurationTicks = -1;   // Timescale based ticks
    int64_t sampleFileOffset = -1;

    if (mIsAudio) {
        prctl(PR_SET_NAME, (unsigned long)"MP4WtrAudTrkThread", 0, 0, 0);
@@ -3342,6 +3387,7 @@ status_t MPEG4Writer::Track::threadEntry() {
    MediaBufferBase *buffer;
    const char *trackName = getTrackType();
    while (!mDone && (err = mSource->read(&buffer)) == OK) {
        ALOGV("read:buffer->range_length:%lld", (long long)buffer->range_length());
        int32_t isEOS = false;
        if (buffer->range_length() == 0) {
            if (buffer->meta_data().findInt32(kKeyIsEndOfStream, &isEOS) && isEOS) {
@@ -3448,6 +3494,14 @@ status_t MPEG4Writer::Track::threadEntry() {
                continue;
            }
        }
        if (!buffer->meta_data().findInt64(kKeySampleFileOffset, &sampleFileOffset)) {
            sampleFileOffset = -1;
        }
        int64_t lastSample = -1;
        if (!buffer->meta_data().findInt64(kKeyLastSampleIndexInChunk, &lastSample)) {
            lastSample = -1;
        }
        ALOGV("sampleFileOffset:%lld", (long long)sampleFileOffset);

        /*
         * Reserve space in the file for the current sample + to be written MOOV box. If reservation
@@ -3455,7 +3509,7 @@ status_t MPEG4Writer::Track::threadEntry() {
         * write MOOV box successfully as space for the same was reserved in the prior call.
         * Release the current buffer/sample here.
         */
        if (!mOwner->preAllocate(buffer->range_length())) {
        if (sampleFileOffset == -1 && !mOwner->preAllocate(buffer->range_length())) {
            buffer->release();
            buffer = nullptr;
            break;
@@ -3466,9 +3520,14 @@ status_t MPEG4Writer::Track::threadEntry() {
        // Make a deep copy of the MediaBuffer and Metadata and release
        // the original as soon as we can
        MediaBuffer *copy = new MediaBuffer(buffer->range_length());
        if (sampleFileOffset != -1) {
            copy->meta_data().setInt64(kKeySampleFileOffset, sampleFileOffset);
        } else {
            memcpy(copy->data(), (uint8_t*)buffer->data() + buffer->range_offset(),
                   buffer->range_length());
        }
        copy->set_range(0, buffer->range_length());

        meta_data = new MetaData(buffer->meta_data());
        buffer->release();
        buffer = NULL;
@@ -3476,14 +3535,16 @@ status_t MPEG4Writer::Track::threadEntry() {
            copy->meta_data().setInt32(kKeyExifTiffOffset, tiffHdrOffset);
        }
        bool usePrefix = this->usePrefix() && !isExif;

        if (usePrefix) StripStartcode(copy);

        if (sampleFileOffset == -1 && usePrefix) {
            StripStartcode(copy);
        }
        size_t sampleSize = copy->range_length();
        if (usePrefix) {
        if (sampleFileOffset == -1 && usePrefix) {
            if (mOwner->useNalLengthFour()) {
                ALOGV("nallength4");
                sampleSize += 4;
            } else {
                ALOGV("nallength2");
                sampleSize += 2;
            }
        }
@@ -3778,7 +3839,8 @@ status_t MPEG4Writer::Track::threadEntry() {
                chunkTimestampUs = timestampUs;
            } else {
                int64_t chunkDurationUs = timestampUs - chunkTimestampUs;
                if (chunkDurationUs > interleaveDurationUs) {
                if (chunkDurationUs > interleaveDurationUs || lastSample > 1) {
                    ALOGV("lastSample:%lld", (long long)lastSample);
                    if (chunkDurationUs > mMaxChunkDurationUs) {
                        mMaxChunkDurationUs = chunkDurationUs;
                    }
+425 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "MediaAppender"

#include <media/stagefright/MediaAppender.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <utils/Log.h>
// TODO : check if this works for NDK apps without JVM
// #include <media/ndk/NdkJavaVMHelperPriv.h>

namespace android {

struct MediaAppender::sampleDataInfo {
    size_t size;
    int64_t time;
    size_t exTrackIndex;
    sp<MetaData> meta;
};

sp<MediaAppender> MediaAppender::create(int fd, AppendMode mode) {
    if (fd < 0) {
        ALOGE("invalid file descriptor");
        return nullptr;
    }
    if (!(mode >= APPEND_MODE_FIRST && mode <= APPEND_MODE_LAST)) {
        ALOGE("invalid mode %d", mode);
        return nullptr;
    }
    sp<MediaAppender> ma = new (std::nothrow) MediaAppender(fd, mode);
    if (ma->init() != OK) {
        return nullptr;
    }
    return ma;
}

// TODO: inject mediamuxer and mediaextractor objects.
// TODO: @format is not required as an input if we can sniff the file and find the format of
//       the existing content.
// TODO: Code it to the interface(MediaAppender), and have a separate MediaAppender NDK
MediaAppender::MediaAppender(int fd, AppendMode mode)
    : mFd(fd),
      mMode(mode),
      // TODO : check if this works for NDK apps without JVM
      // mExtractor(new NuMediaExtractor(NdkJavaVMHelper::getJNIEnv() != nullptr
      //           ? NuMediaExtractor::EntryPoint::NDK_WITH_JVM
      //           : NuMediaExtractor::EntryPoint::NDK_NO_JVM)),
      mExtractor(new (std::nothrow) NuMediaExtractor(NuMediaExtractor::EntryPoint::NDK_WITH_JVM)),
      mTrackCount(0),
      mState(UNINITIALIZED) {
          ALOGV("MediaAppender::MediaAppender mode:%d", mode);
      }

status_t MediaAppender::init() {
    std::scoped_lock lock(mMutex);
    ALOGV("MediaAppender::init");
    status_t status = mExtractor->setDataSource(mFd, 0, lseek(mFd, 0, SEEK_END));
    if (status != OK) {
        ALOGE("extractor_setDataSource failed, status :%d", status);
        return status;
    }

    if (strcmp("MPEG4Extractor", mExtractor->getName()) == 0) {
        mFormat = MediaMuxer::OUTPUT_FORMAT_MPEG_4;
    } else {
        ALOGE("Unsupported format, extractor name:%s", mExtractor->getName());
        return ERROR_UNSUPPORTED;
    }

    mTrackCount = mExtractor->countTracks();
    ALOGV("mTrackCount:%zu", mTrackCount);
    if (mTrackCount == 0) {
        ALOGE("no tracks are present");
        return ERROR_MALFORMED;
    }
    size_t exTrackIndex = 0;
    ssize_t audioTrackIndex = -1, videoTrackIndex = -1;
    bool audioSyncSampleTimeSet = false;

    while (exTrackIndex < mTrackCount) {
        sp<AMessage> fmt;
        status = mExtractor->getTrackFormat(exTrackIndex, &fmt, 0);
        if (status != OK) {
            ALOGE("getTrackFormat failed for trackIndex:%zu, status:%d", exTrackIndex, status);
            return status;
        }
        AString mime;
        if (fmt->findString("mime", &mime)) {
            if (!strncasecmp(mime.c_str(), "video/", 6)) {
                ALOGV("VideoTrack");
                if (videoTrackIndex != -1) {
                    ALOGE("Not more than one video track is supported");
                    return ERROR_UNSUPPORTED;
                }
                videoTrackIndex = exTrackIndex;
            } else if (!strncasecmp(mime.c_str(), "audio/", 6)) {
                ALOGV("AudioTrack");
                if (audioTrackIndex != -1) {
                    ALOGE("Not more than one audio track is supported");
                }
                audioTrackIndex = exTrackIndex;
            } else {
                ALOGV("Neither Video nor Audio track");
            }
        }
        mFmtIndexMap.emplace(exTrackIndex, fmt);
        mSampleCountVect.emplace_back(0);
        mMaxTimestampVect.emplace_back(0);
        mLastSyncSampleTimeVect.emplace_back(0);
        status = mExtractor->selectTrack(exTrackIndex);
        if (status != OK) {
            ALOGE("selectTrack failed for trackIndex:%zu, status:%d", exTrackIndex, status);
            return status;
        }
        ++exTrackIndex;
    }

    ALOGV("AudioTrackIndex:%zu, VideoTrackIndex:%zu", audioTrackIndex, videoTrackIndex);

    do {
        sampleDataInfo tmpSDI;
        // TODO: read info into members of the struct sampleDataInfo directly
        size_t sampleSize;
        status = mExtractor->getSampleSize(&sampleSize);
        if (status != OK) {
            ALOGE("getSampleSize failed, status:%d", status);
            return status;
        }
        mSampleSizeVect.emplace_back(sampleSize);
        tmpSDI.size = sampleSize;
        int64_t sampleTime = 0;
        status = mExtractor->getSampleTime(&sampleTime);
        if (status != OK) {
            ALOGE("getSampleTime failed, status:%d", status);
            return status;
        }
        mSampleTimeVect.emplace_back(sampleTime);
        tmpSDI.time = sampleTime;
        status = mExtractor->getSampleTrackIndex(&exTrackIndex);
        if (status != OK) {
            ALOGE("getSampleTrackIndex failed, status:%d", status);
            return status;
        }
        mSampleIndexVect.emplace_back(exTrackIndex);
        tmpSDI.exTrackIndex = exTrackIndex;
        ++mSampleCountVect[exTrackIndex];
        mMaxTimestampVect[exTrackIndex] = std::max(mMaxTimestampVect[exTrackIndex], sampleTime);
        sp<MetaData> sampleMeta;
        status = mExtractor->getSampleMeta(&sampleMeta);
        if (status != OK) {
            ALOGE("getSampleMeta failed, status:%d", status);
            return status;
        }
        mSampleMetaVect.emplace_back(sampleMeta);
        int32_t val = 0;
        if (sampleMeta->findInt32(kKeyIsSyncFrame, &val) && val != 0) {
            mLastSyncSampleTimeVect[exTrackIndex] = sampleTime;
        }
        tmpSDI.meta = sampleMeta;
        mSDI.emplace_back(tmpSDI);
    } while (mExtractor->advance() == OK);

    mExtractor.clear();

    std::sort(mSDI.begin(), mSDI.end(), [](sampleDataInfo& a, sampleDataInfo& b) {
        int64_t aOffset, bOffset;
        a.meta->findInt64(kKeySampleFileOffset, &aOffset);
        b.meta->findInt64(kKeySampleFileOffset, &bOffset);
        return aOffset < bOffset;
    });
    for (int64_t syncSampleTime : mLastSyncSampleTimeVect) {
        ALOGV("before ignoring frames, mLastSyncSampleTimeVect:%lld", (long long)syncSampleTime);
    }
    ALOGV("mMode:%u", mMode);
    if (mMode == APPEND_MODE_IGNORE_LAST_VIDEO_GOP && videoTrackIndex != -1 ) {
        ALOGV("Video track is present");
        bool lastVideoIframe = false;
        size_t lastVideoIframeOffset = 0;
        int64_t lastVideoSampleTime = -1;
        for (auto rItr = mSDI.rbegin(); rItr != mSDI.rend(); ++rItr) {
            if (rItr->exTrackIndex != videoTrackIndex) {
                continue;
            }
            if (lastVideoSampleTime == -1) {
                lastVideoSampleTime = rItr->time;
            }
            int64_t offset = 0;
            if (!rItr->meta->findInt64(kKeySampleFileOffset, &offset) || offset == 0) {
                ALOGE("Missing offset");
                return ERROR_MALFORMED;
            }
            ALOGV("offset:%lld", (long long)offset);
            int32_t val = 0;
            if (rItr->meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) {
                ALOGV("sampleTime:%lld", (long long)rItr->time);
                ALOGV("lastVideoSampleTime:%lld", (long long)lastVideoSampleTime);
                if (lastVideoIframe == false && (lastVideoSampleTime - rItr->time) >
                                1000000/* Track interleaving duration in MPEG4Writer*/) {
                    ALOGV("lastVideoIframe got chosen");
                    lastVideoIframe = true;
                    mLastSyncSampleTimeVect[videoTrackIndex] = rItr->time;
                    lastVideoIframeOffset = offset;
                    ALOGV("lastVideoIframeOffset:%lld", (long long)offset);
                    break;
                }
            }
        }
        if (lastVideoIframe == false) {
            ALOGV("Need to rewrite all samples");
            mLastSyncSampleTimeVect[videoTrackIndex] = 0;
            lastVideoIframeOffset = 0;
        }
        unsigned int framesIgnoredCount = 0;
        for (auto itr = mSDI.begin(); itr != mSDI.end();) {
            int64_t offset = 0;
            ALOGV("trackIndex:%zu, %" PRId64 "", itr->exTrackIndex, itr->time);
            if (itr->meta->findInt64(kKeySampleFileOffset, &offset) &&
                                        offset >= lastVideoIframeOffset) {
                ALOGV("offset:%lld", (long long)offset);
                if (!audioSyncSampleTimeSet && audioTrackIndex != -1 &&
                                            audioTrackIndex == itr->exTrackIndex) {
                    mLastSyncSampleTimeVect[audioTrackIndex] = itr->time;
                    audioSyncSampleTimeSet = true;
                }
                itr = mSDI.erase(itr);
                ++framesIgnoredCount;
            } else {
                ++itr;
            }
        }
        ALOGV("framesIgnoredCount:%u", framesIgnoredCount);
    }

    if (mMode == APPEND_MODE_IGNORE_LAST_VIDEO_GOP && videoTrackIndex == -1 &&
                            audioTrackIndex != -1) {
        ALOGV("Only AudioTrack is present");
        for (auto rItr = mSDI.rbegin(); rItr != mSDI.rend();  ++rItr) {
            int32_t val = 0;
            if (rItr->meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) {
                    mLastSyncSampleTimeVect[audioTrackIndex] = rItr->time;
                    break;
            }
        }
        unsigned int framesIgnoredCount = 0;
        for (auto itr = mSDI.begin(); itr != mSDI.end();) {
            if (itr->time >= mLastSyncSampleTimeVect[audioTrackIndex]) {
                itr = mSDI.erase(itr);
                ++framesIgnoredCount;
            } else {
                ++itr;
            }
        }
        ALOGV("framesIgnoredCount :%u", framesIgnoredCount);
    }

    for (size_t i = 0; i < mLastSyncSampleTimeVect.size(); ++i) {
        ALOGV("mLastSyncSampleTimeVect[%zu]:%lld", i, (long long)mLastSyncSampleTimeVect[i]);
        mFmtIndexMap[i]->setInt64(
                "sample-time-before-append" /*AMEDIAFORMAT_KEY_SAMPLE_TIME_BEFORE_APPEND*/,
                mLastSyncSampleTimeVect[i]);
    }
    for (size_t i = 0; i < mMaxTimestampVect.size(); ++i) {
        ALOGV("mMaxTimestamp[%zu]:%lld", i, (long long)mMaxTimestampVect[i]);
    }
    for (size_t i = 0; i < mSampleCountVect.size(); ++i) {
        ALOGV("SampleCountVect[%zu]:%zu", i, mSampleCountVect[i]);
    }
    mState = INITIALIZED;
    return OK;
}

MediaAppender::~MediaAppender() {
    ALOGV("MediaAppender::~MediaAppender");
    mMuxer.clear();
    mExtractor.clear();
}

status_t MediaAppender::start() {
    std::scoped_lock lock(mMutex);
    ALOGV("MediaAppender::start");
    if (mState != INITIALIZED) {
        ALOGE("MediaAppender::start() is called in invalid state %d", mState);
        return INVALID_OPERATION;
    }
    mMuxer = new (std::nothrow) MediaMuxer(mFd, mFormat);
    for (const auto& n : mFmtIndexMap) {
        ssize_t muxIndex = mMuxer->addTrack(n.second);
        if (muxIndex < 0) {
            ALOGE("addTrack failed");
            return UNKNOWN_ERROR;
        }
        mTrackIndexMap.emplace(n.first, muxIndex);
    }
    ALOGV("trackIndexmap size:%zu", mTrackIndexMap.size());

    status_t status = mMuxer->start();
    if (status != OK) {
        ALOGE("muxer start failed:%d", status);
        return status;
    }

    ALOGV("Sorting samples based on their offsets");
    for (int i = 0; i < mSDI.size(); ++i) {
        ALOGV("i:%d", i + 1);
        /* TODO : Allocate a single allocation of the max size, and reuse it across ABuffers if
         * using new ABuffer(void *, size_t).
         */
        sp<ABuffer> data = new (std::nothrow) ABuffer(mSDI[i].size);
        if (data == nullptr) {
            ALOGE("memory allocation failed");
            return NO_MEMORY;
        }
        data->setRange(0, mSDI[i].size);
        int32_t val = 0;
        int sampleFlags = 0;
        if (mSDI[i].meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) {
            sampleFlags |= MediaCodec::BUFFER_FLAG_SYNCFRAME;
        }

        int64_t val64;
        if (mSDI[i].meta->findInt64(kKeySampleFileOffset, &val64)) {
            ALOGV("SampleFileOffset Found :%zu:%lld:%lld", mSDI[i].exTrackIndex,
                  (long long)mSampleCountVect[mSDI[i].exTrackIndex], (long long)val64);
            sp<AMessage> bufMeta = data->meta();
            bufMeta->setInt64("sample-file-offset" /*AMEDIAFORMAT_KEY_SAMPLE_TIME_BEFORE_APPEND*/,
                              val64);
        }
        if (mSDI[i].meta->findInt64(kKeyLastSampleIndexInChunk, &val64)) {
            ALOGV("kKeyLastSampleIndexInChunk Found %lld:%lld",
                  (long long)mSampleCountVect[mSDI[i].exTrackIndex], (long long)val64);
            sp<AMessage> bufMeta = data->meta();
            bufMeta->setInt64(
                    "last-sample-index-in-chunk" /*AMEDIAFORMAT_KEY_LAST_SAMPLE_INDEX_IN_CHUNK*/,
                    val64);
        }
        status = mMuxer->writeSampleData(data, mTrackIndexMap[mSDI[i].exTrackIndex], mSDI[i].time,
                                         sampleFlags);
        if (status != OK) {
            ALOGE("muxer writeSampleData failed:%d", status);
            return status;
        }
    }
    mState = STARTED;
    return OK;
}

status_t MediaAppender::stop() {
    std::scoped_lock lock(mMutex);
    ALOGV("MediaAppender::stop");
    if (mState == STARTED) {
        status_t status = mMuxer->stop();
        if (status != OK) {
            mState = ERROR;
        } else {
            mState = STOPPED;
        }
        return status;
    } else {
        ALOGE("stop() is called in invalid state %d", mState);
        return INVALID_OPERATION;
    }
}

ssize_t MediaAppender::getTrackCount() {
    std::scoped_lock lock(mMutex);
    ALOGV("MediaAppender::getTrackCount");
    if (mState != INITIALIZED && mState != STARTED) {
        ALOGE("getTrackCount() is called in invalid state %d", mState);
        return -1;
    }
    return mTrackCount;
}

sp<AMessage> MediaAppender::getTrackFormat(size_t idx) {
    std::scoped_lock lock(mMutex);
    ALOGV("MediaAppender::getTrackFormat");
    if (mState != INITIALIZED && mState != STARTED) {
        ALOGE("getTrackFormat() is called in invalid state %d", mState);
        return nullptr;
    }
    if (idx < 0 || idx >= mTrackCount) {
        ALOGE("getTrackFormat() idx is out of range");
        return nullptr;
    }
    return mFmtIndexMap[idx];
}

status_t MediaAppender::writeSampleData(const sp<ABuffer>& buffer, size_t trackIndex,
                                        int64_t timeUs, uint32_t flags) {
    std::scoped_lock lock(mMutex);
    ALOGV("writeSampleData:trackIndex:%zu, time:%" PRId64 "", trackIndex, timeUs);
    return mMuxer->writeSampleData(buffer, trackIndex, timeUs, flags);
}

status_t MediaAppender::setOrientationHint([[maybe_unused]] int degrees) {
    ALOGE("setOrientationHint not supported. Has to be called prior to start on initial muxer");
    return ERROR_UNSUPPORTED;
};

status_t MediaAppender::setLocation([[maybe_unused]] int latit, [[maybe_unused]] int longit) {
    ALOGE("setLocation not supported. Has to be called prior to start on initial muxer");
    return ERROR_UNSUPPORTED;
}

ssize_t MediaAppender::addTrack([[maybe_unused]] const sp<AMessage> &format) {
    ALOGE("addTrack not supported");
    return ERROR_UNSUPPORTED;
}

}  // namespace android
+36 −0

File changed.

Preview size limit exceeded, changes collapsed.

Loading