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

Commit f0f0311e authored by Gopalakrishnan Nallasamy's avatar Gopalakrishnan Nallasamy
Browse files

Mpeg4Writer/MediaMuxer:allow empty tracks

1) Don't count tracks with no samples as malformed for MediaMuxer, but
keep the old behavior as it is for MediaRecorder.
2) When there are no samples to be written in a track, skip that one, but
compose mpeg4 file with all other tracks in it.
3) Allow notifications in MediaMuxer during stop() process.

Bug: 144108285
Bug: 146423844
Bug: 148754639

Test: 1) Unit tested by adding a video and an audio track, once leaving
      audio track with no samples and once leaving video with no
      samples.  Mpeg4 file with expected track was created both the times
      and played well.
      2) android.mediav2.cts.MuxerUnitTest$TestApi#testSimpleStartStopMuxer
      3) android.media.cts.MediaMuxerTest
      4) android.media.cts.MediaRecorderTest

Change-Id: If76a1f3b60d09836d53bce6f6e759e6a751f5538
Merged-In: If76a1f3b60d09836d53bce6f6e759e6a751f5538
(cherry picked from commit afc9f272)
parent c42069ac
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -2009,6 +2009,9 @@ void StagefrightRecorder::setupMPEG4orWEBMMetaData(sp<MetaData> *meta) {
            (*meta)->setInt32(kKeyRotation, mRotationDegrees);
        }
    }
    if (mOutputFormat == OUTPUT_FORMAT_MPEG_4 || mOutputFormat == OUTPUT_FORMAT_THREE_GPP) {
        (*meta)->setInt32(kKeyEmptyTrackMalFormed, true);
    }
}

status_t StagefrightRecorder::pause() {
+85 −67
Original line number Diff line number Diff line
@@ -1131,8 +1131,8 @@ status_t MPEG4Writer::reset(bool stopSource) {
        err = writerErr;
    }

    // Do not write out movie header on error.
    if (err != OK) {
    // Do not write out movie header on error except malformed track.
    if (err != OK && err != ERROR_MALFORMED) {
        release();
        return err;
    }
@@ -2687,7 +2687,7 @@ status_t MPEG4Writer::Track::pause() {
status_t MPEG4Writer::Track::stop(bool stopSource) {
    ALOGD("%s track stopping. %s source", getTrackType(), stopSource ? "Stop" : "Not Stop");
    if (!mStarted) {
        ALOGE("Stop() called but track is not started");
        ALOGE("Stop() called but track is not started or stopped");
        return ERROR_END_OF_STREAM;
    }

@@ -2711,6 +2711,7 @@ status_t MPEG4Writer::Track::stop(bool stopSource) {
    err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
    WARN_UNLESS(err == 0, "%s track stopped. Status :%d. %s source", getTrackType(), err,
                stopSource ? "Stop" : "Not Stop");
    mStarted = false;
    return err;
}

@@ -3586,12 +3587,15 @@ status_t MPEG4Writer::Track::threadEntry() {
        }
    }
    if (isTrackMalFormed()) {
        mIsMalformed = true;
        dumpTimeStamps();
        err = ERROR_MALFORMED;
    }

    mOwner->trackProgressStatus(mTrackId, -1, err);

    // Add final entries only for non-empty tracks.
    if (mStszTableEntries->count() > 0) {
        if (mIsHeic) {
            if (!mChunkSamples.empty()) {
                bufferChunk(0);
@@ -3638,6 +3642,7 @@ status_t MPEG4Writer::Track::threadEntry() {
                mTrackDurationUs += lastDurationUs;
            }
        }
    }
    mReachedEOS = true;

    sendTrackSummary(hasMultipleTracks);
@@ -3659,15 +3664,25 @@ bool MPEG4Writer::Track::isTrackMalFormed() const {
        return true;
    }

    int32_t emptyTrackMalformed = false;
    if (mOwner->mStartMeta &&
        mOwner->mStartMeta->findInt32(kKeyEmptyTrackMalFormed, &emptyTrackMalformed) &&
        emptyTrackMalformed) {
        if (!mIsHeic && mStszTableEntries->count() == 0) {  // no samples written
            ALOGE("The number of recorded samples is 0");
            return true;
        }

        if (mIsVideo && mStssTableEntries->count() == 0) {  // no sync frames for video
            ALOGE("There are no sync frames for video track");
            return true;
        }
    } else {
        // No sync frames for video.
        if (mIsVideo && mStszTableEntries->count() > 0 && mStssTableEntries->count() == 0) {
            ALOGE("There are no sync frames for video track");
            return true;
        }
    }

    if (OK != checkCodecSpecificData()) {         // no codec specific data
        return true;
@@ -3915,6 +3930,8 @@ int64_t MPEG4Writer::Track::getMinCttsOffsetTimeUs() {

void MPEG4Writer::Track::writeStblBox() {
    mOwner->beginBox("stbl");
    // Add subboxes only for non-empty tracks.
    if (mStszTableEntries->count() > 0) {
        mOwner->beginBox("stsd");
        mOwner->writeInt32(0);               // version=0, flags=0
        mOwner->writeInt32(1);               // entry count
@@ -3934,6 +3951,7 @@ void MPEG4Writer::Track::writeStblBox() {
        writeStszBox();
        writeStscBox();
        writeCo64Box();
    }
    mOwner->endBox();  // stbl
}

+3 −1
Original line number Diff line number Diff line
@@ -157,7 +157,6 @@ status_t MediaMuxer::start() {

status_t MediaMuxer::stop() {
    Mutex::Autolock autoLock(mMuxerLock);

    if (mState == STARTED || mState == ERROR) {
        mState = STOPPED;
        for (size_t i = 0; i < mTrackList.size(); i++) {
@@ -165,7 +164,10 @@ status_t MediaMuxer::stop() {
                return INVALID_OPERATION;
            }
        }
        // Unlock this mutex to allow notify to be called during stop process.
        mMuxerLock.unlock();
        status_t err = mWriter->stop();
        mMuxerLock.lock();
        if (err != OK || mError != OK) {
            ALOGE("stop err: %d, mError:%d", err, mError);
        }
+3 −0
Original line number Diff line number Diff line
@@ -238,6 +238,9 @@ enum {
    kKeyOpaqueCSD2       = 'csd2',

    kKeyHapticChannelCount = 'hapC',

    // Treat empty track as malformed for MediaRecorder.
    kKeyEmptyTrackMalFormed = 'nemt', // bool (int32_t)
};

enum {