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

Commit 95a497d0 authored by James Dong's avatar James Dong Committed by Android (Google) Code Review
Browse files

Merge "Reduce blocking time in file write"

parents fb4ff3d6 f6a2bff0
Loading
Loading
Loading
Loading
+8 −5
Original line number Diff line number Diff line
@@ -98,6 +98,8 @@ private:
        List<MediaBuffer *> mSamples;       // Sample data

        // Convenient constructor
        Chunk(): mTrack(NULL), mTimeStampUs(0) {}

        Chunk(Track *track, int64_t timeUs, List<MediaBuffer *> samples)
            : mTrack(track), mTimeStampUs(timeUs), mSamples(samples) {
        }
@@ -124,13 +126,14 @@ private:
    void bufferChunk(const Chunk& chunk);

    // Write all buffered chunks from all tracks
    void writeChunks();
    void writeAllChunks();

    // Write a chunk if there is one
    status_t writeOneChunk();
    // Retrieve the proper chunk to write if there is one
    // Return true if a chunk is found; otherwise, return false.
    bool findChunkToWrite(Chunk *chunk);

    // Write the first chunk from the given ChunkInfo.
    void writeFirstChunk(ChunkInfo* info);
    // Actually write the given chunk to the file.
    void writeChunkToFile(Chunk* chunk);

    // Adjust other track media clock (presumably wall clock)
    // based on audio track media clock with the drift time.
+49 −37
Original line number Diff line number Diff line
@@ -1122,42 +1122,42 @@ void MPEG4Writer::bufferChunk(const Chunk& chunk) {
    CHECK("Received a chunk for a unknown track" == 0);
}

void MPEG4Writer::writeFirstChunk(ChunkInfo* info) {
    LOGV("writeFirstChunk: %p", info->mTrack);
void MPEG4Writer::writeChunkToFile(Chunk* chunk) {
    LOGV("writeChunkToFile: %lld from %s track",
        chunk.mTimestampUs, chunk.mTrack->isAudio()? "audio": "video");

    List<Chunk>::iterator chunkIt = info->mChunks.begin();
    for (List<MediaBuffer *>::iterator it = chunkIt->mSamples.begin();
         it != chunkIt->mSamples.end(); ++it) {
    int32_t isFirstSample = true;
    while (!chunk->mSamples.empty()) {
        List<MediaBuffer *>::iterator it = chunk->mSamples.begin();

        off64_t offset = info->mTrack->isAvc()
        off64_t offset = chunk->mTrack->isAvc()
                                ? addLengthPrefixedSample_l(*it)
                                : addSample_l(*it);
        if (it == chunkIt->mSamples.begin()) {
            info->mTrack->addChunkOffset(offset);
        }

        if (isFirstSample) {
            chunk->mTrack->addChunkOffset(offset);
            isFirstSample = false;
        }

    // Done with the current chunk.
    // Release all the samples in this chunk.
    while (!chunkIt->mSamples.empty()) {
        List<MediaBuffer *>::iterator it = chunkIt->mSamples.begin();
        (*it)->release();
        (*it) = NULL;
        chunkIt->mSamples.erase(it);
        chunk->mSamples.erase(it);
    }
    chunkIt->mSamples.clear();
    info->mChunks.erase(chunkIt);
    chunk->mSamples.clear();
}

void MPEG4Writer::writeChunks() {
    LOGV("writeChunks");
void MPEG4Writer::writeAllChunks() {
    LOGV("writeAllChunks");
    size_t outstandingChunks = 0;
    while (!mChunkInfos.empty()) {
        List<ChunkInfo>::iterator it = mChunkInfos.begin();
        while (!it->mChunks.empty()) {
            CHECK_EQ(OK, writeOneChunk());
            Chunk chunk;
            if (findChunkToWrite(&chunk)) {
                writeChunkToFile(&chunk);
                ++outstandingChunks;
            }
        }
        it->mTrack = NULL;
        mChunkInfos.erase(it);
    }
@@ -1165,8 +1165,8 @@ void MPEG4Writer::writeChunks() {
    LOGD("%d chunks are written in the last batch", outstandingChunks);
}

status_t MPEG4Writer::writeOneChunk() {
    LOGV("writeOneChunk");
bool MPEG4Writer::findChunkToWrite(Chunk *chunk) {
    LOGV("findChunkToWrite");

    // Find the smallest timestamp, and write that chunk out
    // XXX: What if some track is just too slow?
@@ -1185,40 +1185,52 @@ status_t MPEG4Writer::writeOneChunk() {

    if (track == NULL) {
        LOGV("Nothing to be written after all");
        return OK;
        return false;
    }

    if (mIsFirstChunk) {
        mIsFirstChunk = false;
    }

    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
         it != mChunkInfos.end(); ++it) {
        if (it->mTrack == track) {
            writeFirstChunk(&(*it));
            *chunk = *(it->mChunks.begin());
            it->mChunks.erase(it->mChunks.begin());
            CHECK_EQ(chunk->mTrack, track);
            return true;
        }
    }
    return OK;

    return false;
}

void MPEG4Writer::threadFunc() {
    LOGV("threadFunc");

    prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0);

    Mutex::Autolock autoLock(mLock);
    while (!mDone) {
        {
            Mutex::Autolock autolock(mLock);
        Chunk chunk;
        bool chunkFound = false;

        while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) {
            mChunkReadyCondition.wait(mLock);
            CHECK_EQ(writeOneChunk(), OK);
        }
        }

    {
        // Write ALL samples
        Mutex::Autolock autolock(mLock);
        writeChunks();
        // Actual write without holding the lock in order to
        // reduce the blocking time for media track threads.
        if (chunkFound) {
            mLock.unlock();
            writeChunkToFile(&chunk);
            mLock.lock();
        }
    }

    writeAllChunks();
}

status_t MPEG4Writer::startWriterThread() {
    LOGV("startWriterThread");