Merge "Initial checkin for pause and resume control" into kraken
diff --git a/include/media/stagefright/AMRWriter.h b/include/media/stagefright/AMRWriter.h
index dd11809..b0eaba4 100644
--- a/include/media/stagefright/AMRWriter.h
+++ b/include/media/stagefright/AMRWriter.h
@@ -37,6 +37,7 @@
     virtual bool reachedEOS();
     virtual status_t start();
     virtual void stop();
+    virtual void pause();
 
 protected:
     virtual ~AMRWriter();
@@ -46,6 +47,8 @@
     status_t mInitCheck;
     sp<MediaSource> mSource;
     bool mStarted;
+    volatile bool mPaused;
+    volatile bool mResumed;
     volatile bool mDone;
     volatile bool mReachedEOS;
     pthread_t mThread;
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 3c85eca..3d90434 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -39,6 +39,7 @@
     virtual status_t start();
     virtual bool reachedEOS();
     virtual void stop();
+    virtual void pause();
 
     void beginBox(const char *fourcc);
     void writeInt8(int8_t x);
@@ -59,6 +60,8 @@
     class Track;
 
     FILE *mFile;
+    bool mPaused;
+    bool mStarted;
     off_t mOffset;
     off_t mMdatOffset;
     uint8_t *mMoovBoxBuffer;
@@ -77,6 +80,7 @@
 
     void setStartTimestamp(int64_t timeUs);
     int64_t getStartTimestamp();  // Not const
+    status_t startTracks();
 
     void lock();
     void unlock();
diff --git a/include/media/stagefright/MediaWriter.h b/include/media/stagefright/MediaWriter.h
index b15f69c..8528203 100644
--- a/include/media/stagefright/MediaWriter.h
+++ b/include/media/stagefright/MediaWriter.h
@@ -32,6 +32,7 @@
     virtual bool reachedEOS() = 0;
     virtual status_t start() = 0;
     virtual void stop() = 0;
+    virtual void pause() = 0;
     virtual void setMaxFileSize(int64_t bytes) { mMaxFileSizeLimitBytes = bytes; }
     virtual void setMaxFileDuration(int64_t durationUs) { mMaxFileDurationLimitUs = durationUs; }
     virtual void setListener(const sp<IMediaPlayerClient>& listener) {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 2f3b075..a7ccce4 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -692,6 +692,14 @@
     return OK;
 }
 
+status_t StagefrightRecorder::pause() {
+    if (mWriter == NULL) {
+        return UNKNOWN_ERROR;
+    }
+    mWriter->pause();
+    return OK;
+}
+
 status_t StagefrightRecorder::stop() {
     if (mWriter == NULL) {
         return UNKNOWN_ERROR;
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index b491e9f..baf33cf 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -47,6 +47,7 @@
     virtual status_t setListener(const sp<IMediaPlayerClient>& listener);
     virtual status_t prepare();
     virtual status_t start();
+    virtual status_t pause();
     virtual status_t stop();
     virtual status_t close();
     virtual status_t reset();
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index aec7394..8951f5b 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -29,13 +29,17 @@
 AMRWriter::AMRWriter(const char *filename)
     : mFile(fopen(filename, "wb")),
       mInitCheck(mFile != NULL ? OK : NO_INIT),
-      mStarted(false) {
+      mStarted(false),
+      mPaused(false),
+      mResumed(false) {
 }
 
 AMRWriter::AMRWriter(int fd)
     : mFile(fdopen(fd, "wb")),
       mInitCheck(mFile != NULL ? OK : NO_INIT),
-      mStarted(false) {
+      mStarted(false),
+      mPaused(false),
+      mResumed(false) {
 }
 
 AMRWriter::~AMRWriter() {
@@ -98,10 +102,19 @@
         return mInitCheck;
     }
 
-    if (mStarted || mSource == NULL) {
+    if (mSource == NULL) {
         return UNKNOWN_ERROR;
     }
 
+    if (mStarted && mPaused) {
+        mPaused = false;
+        mResumed = true;
+        return OK;
+    } else if (mStarted) {
+        // Already started, does nothing
+        return OK;
+    }
+
     status_t err = mSource->start();
 
     if (err != OK) {
@@ -123,6 +136,13 @@
     return OK;
 }
 
+void AMRWriter::pause() {
+    if (!mStarted) {
+        return;
+    }
+    mPaused = true;
+}
+
 void AMRWriter::stop() {
     if (!mStarted) {
         return;
@@ -163,6 +183,9 @@
     mEstimatedDurationUs = 0;
     mEstimatedSizeBytes = 0;
     bool stoppedPrematurely = true;
+    int64_t previousPausedDurationUs = 0;
+    int64_t maxTimestampUs = 0;
+
     while (!mDone) {
         MediaBuffer *buffer;
         status_t err = mSource->read(&buffer);
@@ -171,6 +194,12 @@
             break;
         }
 
+        if (mPaused) {
+            buffer->release();
+            buffer = NULL;
+            continue;
+        }
+
         mEstimatedSizeBytes += buffer->range_length();
         if (exceedsFileSizeLimit()) {
             buffer->release();
@@ -184,6 +213,17 @@
         if (timestampUs > mEstimatedDurationUs) {
             mEstimatedDurationUs = timestampUs;
         }
+        if (mResumed) {
+            previousPausedDurationUs += (timestampUs - maxTimestampUs - 20000);
+            mResumed = false;
+        }
+        timestampUs -= previousPausedDurationUs;
+        LOGV("time stamp: %lld, previous paused duration: %lld",
+                timestampUs, previousPausedDurationUs);
+        if (timestampUs > maxTimestampUs) {
+            maxTimestampUs = timestampUs;
+        }
+
         if (exceedsFileDurationLimit()) {
             buffer->release();
             buffer = NULL;
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 326e8dc..9717aa6 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -121,11 +121,13 @@
 
     uint32_t numFramesRecorded;
     mRecord->getPosition(&numFramesRecorded);
+    int64_t latency = mRecord->latency() * 1000;
+    uint32_t sampleRate = mRecord->getSampleRate();
+    int64_t timestampUs = (1000000LL * numFramesRecorded) / sampleRate - latency;
+    LOGV("latency: %lld, sample rate: %d, timestamp: %lld",
+            latency, sampleRate, timestampUs);
 
-    buffer->meta_data()->setInt64(
-            kKeyTime,
-            (1000000ll * numFramesRecorded) / mRecord->getSampleRate()
-            - mRecord->latency() * 1000);
+    buffer->meta_data()->setInt64(kKeyTime, timestampUs);
 
     ssize_t n = 0;
     if (mCollectStats) {
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index db60078..af11032 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -43,6 +43,7 @@
 
     status_t start();
     void stop();
+    void pause();
     bool reachedEOS();
 
     int64_t getDurationUs() const;
@@ -54,6 +55,8 @@
     sp<MetaData> mMeta;
     sp<MediaSource> mSource;
     volatile bool mDone;
+    volatile bool mPaused;
+    volatile bool mResumed;
     int64_t mMaxTimeStampUs;
     int64_t mEstimatedTrackSizeBytes;
 
@@ -120,6 +123,8 @@
 
 MPEG4Writer::MPEG4Writer(const char *filename)
     : mFile(fopen(filename, "wb")),
+      mPaused(false),
+      mStarted(false),
       mOffset(0),
       mMdatOffset(0),
       mEstimatedMoovBoxSize(0),
@@ -129,6 +134,8 @@
 
 MPEG4Writer::MPEG4Writer(int fd)
     : mFile(fdopen(fd, "wb")),
+      mPaused(false),
+      mStarted(false),
       mOffset(0),
       mMdatOffset(0),
       mEstimatedMoovBoxSize(0),
@@ -153,11 +160,36 @@
     return OK;
 }
 
+status_t MPEG4Writer::startTracks() {
+    for (List<Track *>::iterator it = mTracks.begin();
+         it != mTracks.end(); ++it) {
+        status_t err = (*it)->start();
+
+        if (err != OK) {
+            for (List<Track *>::iterator it2 = mTracks.begin();
+                 it2 != it; ++it2) {
+                (*it2)->stop();
+            }
+
+            return err;
+        }
+    }
+    return OK;
+}
+
 status_t MPEG4Writer::start() {
     if (mFile == NULL) {
         return UNKNOWN_ERROR;
     }
 
+    if (mStarted) {
+        if (mPaused) {
+            mPaused = false;
+            return startTracks();
+        }
+        return OK;
+    }
+
     mStartTimestampUs = 0;
     mStreamableFile = true;
     mWriteMoovBoxToMemory = false;
@@ -186,21 +218,24 @@
     mOffset = mMdatOffset;
     fseeko(mFile, mMdatOffset, SEEK_SET);
     write("\x00\x00\x00\x01mdat????????", 16);
+
+    status_t err = startTracks();
+    if (err != OK) {
+        return err;
+    }
+    mStarted = true;
+    return OK;
+}
+
+void MPEG4Writer::pause() {
+    if (mFile == NULL) {
+        return;
+    }
+    mPaused = true;
     for (List<Track *>::iterator it = mTracks.begin();
          it != mTracks.end(); ++it) {
-        status_t err = (*it)->start();
-
-        if (err != OK) {
-            for (List<Track *>::iterator it2 = mTracks.begin();
-                 it2 != it; ++it2) {
-                (*it2)->stop();
-            }
-
-            return err;
-        }
+        (*it)->pause();
     }
-
-    return OK;
 }
 
 void MPEG4Writer::stop() {
@@ -298,6 +333,7 @@
     fflush(mFile);
     fclose(mFile);
     mFile = NULL;
+    mStarted = false;
 }
 
 status_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) {
@@ -528,6 +564,8 @@
       mMeta(source->getFormat()),
       mSource(source),
       mDone(false),
+      mPaused(false),
+      mResumed(false),
       mMaxTimeStampUs(0),
       mEstimatedTrackSizeBytes(0),
       mSamplesHaveSameSize(true),
@@ -547,6 +585,11 @@
 }
 
 status_t MPEG4Writer::Track::start() {
+    if (!mDone && mPaused) {
+        mPaused = false;
+        mResumed = true;
+        return OK;
+    }
     status_t err = mSource->start();
 
     if (err != OK) {
@@ -569,6 +612,10 @@
     return OK;
 }
 
+void MPEG4Writer::Track::pause() {
+    mPaused = true;
+}
+
 void MPEG4Writer::Track::stop() {
     if (mDone) {
         return;
@@ -710,6 +757,7 @@
     int64_t lastDuration = 0;   // Time spacing between the previous two samples
     int32_t sampleCount = 1;    // Sample count in the current stts table entry
     uint32_t previousSampleSize = 0;  // Size of the previous sample
+    int64_t previousPausedDurationUs = 0;
     sp<MetaData> meta_data;
 
     MediaBuffer *buffer;
@@ -721,6 +769,15 @@
             continue;
         }
 
+        // If the codec specific data has not been received yet, delay pause.
+        // After the codec specific data is received, discard what we received
+        // when the track is to be paused.
+        if (mPaused && !mResumed) {
+            buffer->release();
+            buffer = NULL;
+            continue;
+        }
+
         ++count;
 
         int32_t isCodecConfig;
@@ -831,6 +888,10 @@
             continue;
         }
 
+        if (!mGotAllCodecSpecificData) {
+            mGotAllCodecSpecificData = true;
+        }
+
         // 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());
@@ -876,6 +937,14 @@
             mStartTimestampUs = (timestampUs - mOwner->getStartTimestamp());
         }
 
+        if (mResumed) {
+            previousPausedDurationUs += (timestampUs - mMaxTimeStampUs - 1000 * lastDuration);
+            mResumed = false;
+        }
+
+        timestampUs -= previousPausedDurationUs;
+        LOGV("time stamp: %lld and previous paused duration %lld",
+                timestampUs, previousPausedDurationUs);
         if (timestampUs > mMaxTimeStampUs) {
             mMaxTimeStampUs = timestampUs;
         }
diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
index d222cd9..282a10b 100644
--- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
@@ -205,13 +205,15 @@
         buffer->set_range(0, 2);
         buffer->meta_data()->setInt32(kKeyIsCodecConfig, true);
         *out = buffer;
-        ++mFrameCount;
         mInputBuffer = NULL;
+        ++mFrameCount;
         return OK;
-    } else {
+    } else if (mFrameCount == 1) {
         buffer->meta_data()->setInt32(kKeyIsCodecConfig, false);
     }
 
+    // XXX: We assume that the input buffer contains at least
+    // (actually, exactly) 1024 PCM samples. This needs to be fixed.
     if (mInputBuffer == NULL) {
         if (mSource->read(&mInputBuffer, options) != OK) {
             LOGE("failed to read from input audio source");
@@ -252,9 +254,10 @@
     }
 
     buffer->set_range(0, outputLength);
-    ++mFrameCount;
-    int64_t timestampUs = (mFrameCount * 1000000LL * 1024) / mSampleRate;
 
+    // Each output frame compresses 1024 input PCM samples.
+    int64_t timestampUs = ((mFrameCount - 1) * 1000000LL * 1024) / mSampleRate;
+    ++mFrameCount;
     buffer->meta_data()->setInt64(kKeyTime, timestampUs);
 
     *out = buffer;