Fix 5123908: Native crash rewinding movie

Simplify the VideoEditorSRC code and fix some bugs.

Change-Id: I6bcf3a5cea21a2eec4b51f167560c4b0d3a04a29
diff --git a/libvideoeditor/lvpp/VideoEditorSRC.cpp b/libvideoeditor/lvpp/VideoEditorSRC.cpp
index 71411ab..1ea32ef 100755
--- a/libvideoeditor/lvpp/VideoEditorSRC.cpp
+++ b/libvideoeditor/lvpp/VideoEditorSRC.cpp
@@ -14,10 +14,8 @@
  * limitations under the License.
  */
 
-#define LOG_NDEBUG 1
-#define LOG_TAG "VEAudioSource"
-#include <utils/Log.h>
-
+//#define LOG_NDEBUG 0
+#define LOG_TAG "VideoEditorSRC"
 
 #include "VideoEditorSRC.h"
 #include <media/stagefright/MetaData.h>
@@ -25,99 +23,53 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include "AudioMixer.h"
-
+#include <utils/Log.h>
 
 namespace android {
 
-VideoEditorSRC::VideoEditorSRC(
-        const sp<MediaSource> &source) {
-
-    LOGV("VideoEditorSRC::Create");
+VideoEditorSRC::VideoEditorSRC(const sp<MediaSource> &source) {
+    LOGV("VideoEditorSRC::VideoEditorSRC %p(%p)", this, source.get());
     mSource = source;
     mResampler = NULL;
-    mBitDepth = 16;
     mChannelCnt = 0;
     mSampleRate = 0;
     mOutputSampleRate = DEFAULT_SAMPLING_FREQ;
     mStarted = false;
-    mIsResamplingRequired = false;
-    mIsChannelConvertionRequired = false;
     mInitialTimeStampUs = -1;
     mAccuOutBufferSize  = 0;
     mSeekTimeUs = -1;
+    mBuffer = NULL;
     mLeftover = 0;
-    mLastReadSize = 0;
-    mReSampledBuffer = NULL;
-    mSeekMode =  ReadOptions::SEEK_PREVIOUS_SYNC;
-
-    mOutputFormat = new MetaData;
+    mFormatChanged = false;
+    mSeekMode = ReadOptions::SEEK_PREVIOUS_SYNC;
 
     // Input Source validation
     sp<MetaData> format = mSource->getFormat();
     const char *mime;
-    bool success = format->findCString(kKeyMIMEType, &mime);
-    CHECK(success);
+    CHECK(format->findCString(kKeyMIMEType, &mime));
     CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW));
 
-    //set the meta data of the output after convertion.
-    if(mOutputFormat != NULL) {
-        mOutputFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
-        mOutputFormat->setInt32(kKeySampleRate, DEFAULT_SAMPLING_FREQ);
-
-        //by default we convert all data to stereo
-        mOutputFormat->setInt32(kKeyChannelCount, 2);
-    } else {
-        LOGE("Meta data was not allocated.");
-    }
-
-    // Allocate a  1 sec buffer (test only, to be refined)
-    mInterframeBufferPosition = 0;
-    mInterframeBuffer = new uint8_t[DEFAULT_SAMPLING_FREQ * 2 * 2]; //stereo=2 * bytespersample=2
-
-
+    // Set the metadata of the output after resampling.
+    mOutputFormat = new MetaData;
+    mOutputFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+    mOutputFormat->setInt32(kKeySampleRate, DEFAULT_SAMPLING_FREQ);
+    mOutputFormat->setInt32(kKeyChannelCount, 2);
 }
 
-VideoEditorSRC::~VideoEditorSRC(){
-    if (mStarted == true)
-        stop();
-
-    if(mOutputFormat != NULL) {
-        mOutputFormat.clear();
-        mOutputFormat = NULL;
-    }
-
-    if (mInterframeBuffer != NULL){
-        delete mInterframeBuffer;
-        mInterframeBuffer = NULL;
-    }
+VideoEditorSRC::~VideoEditorSRC() {
+    LOGV("VideoEditorSRC::~VideoEditorSRC %p(%p)", this, mSource.get());
+    stop();
 }
 
-void VideoEditorSRC::setResampling(int32_t sampleRate) {
-    Mutex::Autolock autoLock(mLock);
-    LOGV("VideoEditorSRC::setResampling called with samplreRate = %d", sampleRate);
-    if(sampleRate != DEFAULT_SAMPLING_FREQ) { //default case
-        LOGV("VideoEditor Audio resampler, freq set is other than default");
-        CHECK(mOutputFormat->setInt32(kKeySampleRate, DEFAULT_SAMPLING_FREQ));
-    }
-    mOutputSampleRate = sampleRate;
-    return;
-}
-
-status_t  VideoEditorSRC::start (MetaData *params) {
-    Mutex::Autolock autoLock(mLock);
-
+status_t VideoEditorSRC::start(MetaData *params) {
     CHECK(!mStarted);
-    LOGV(" VideoEditorSRC:start() called");
+    LOGV("VideoEditorSRC:start %p(%p)", this, mSource.get());
 
     // Set resampler if required
-    status_t err = checkAndSetResampler();
-    if (err != OK) {
-        LOGE("checkAndSetResampler() returned error %d", err);
-        return err;
-    }
+    checkAndSetResampler();
 
     mSeekTimeUs = -1;
-    mSeekMode =  ReadOptions::SEEK_PREVIOUS_SYNC;
+    mSeekMode = ReadOptions::SEEK_PREVIOUS_SYNC;
     mStarted = true;
     mSource->start();
 
@@ -125,9 +77,12 @@
 }
 
 status_t VideoEditorSRC::stop() {
-
-    Mutex::Autolock autoLock(mLock);
-    LOGV("VideoEditorSRC::stop()");
+    LOGV("VideoEditorSRC::stop %p(%p)", this, mSource.get());
+    if (!mStarted) return OK;
+    if (mBuffer) {
+        mBuffer->release();
+        mBuffer = NULL;
+    }
     mSource->stop();
     if(mResampler != NULL) {
         delete mResampler;
@@ -135,101 +90,87 @@
     }
     mStarted = false;
     mInitialTimeStampUs = -1;
-    mAccuOutBufferSize  = 0;
+    mAccuOutBufferSize = 0;
     mLeftover = 0;
-    mLastReadSize = 0;
-    if (mReSampledBuffer != NULL) {
-        free(mReSampledBuffer);
-        mReSampledBuffer = NULL;
-    }
 
     return OK;
 }
 
 sp<MetaData> VideoEditorSRC::getFormat() {
-    LOGV("AudioSRC getFormat");
-    //Mutex::Autolock autoLock(mLock);
+    LOGV("VideoEditorSRC::getFormat");
     return mOutputFormat;
 }
 
-status_t VideoEditorSRC::read (
+status_t VideoEditorSRC::read(
         MediaBuffer **buffer_out, const ReadOptions *options) {
-    Mutex::Autolock autoLock(mLock);
+    LOGV("VideoEditorSRC::read %p(%p)", this, mSource.get());
     *buffer_out = NULL;
-    int32_t leftover = 0;
-
-    LOGV("VideoEditorSRC::read");
 
     if (!mStarted) {
         return ERROR_END_OF_STREAM;
     }
 
-    if(mIsResamplingRequired == true) {
-
-        LOGV("mIsResamplingRequired = true");
-
+    if (mResampler) {
         // Store the seek parameters
         int64_t seekTimeUs;
         ReadOptions::SeekMode mode = ReadOptions::SEEK_PREVIOUS_SYNC;
         if (options && options->getSeekTo(&seekTimeUs, &mode)) {
             LOGV("read Seek %lld", seekTimeUs);
-            mInitialTimeStampUs = -1;
             mSeekTimeUs = seekTimeUs;
             mSeekMode = mode;
         }
 
         // We ask for 1024 frames in output
-        size_t outFrameCnt = 1024;
-        int32_t outBufferSize = (outFrameCnt) * 2 * sizeof(int16_t); //out is always 2 channels & 16 bits
-        int64_t outDurationUs = (outBufferSize * 1000000) /(mOutputSampleRate * 2 * sizeof(int16_t)); //2 channels out * 2 bytes per sample
-        LOGV("outBufferSize            %d", outBufferSize);
-        LOGV("outFrameCnt              %d", outFrameCnt);
-
-        int32_t *pTmpBuffer = (int32_t*)malloc(outFrameCnt * 2 * sizeof(int32_t)); //out is always 2 channels and resampler out is 32 bits
-        memset(pTmpBuffer, 0x00, outFrameCnt * 2 * sizeof(int32_t));
+        const size_t outFrameCnt = 1024;
+        // resampler output is always 2 channels and 32 bits
+        int32_t *pTmpBuffer = (int32_t *)calloc(1, outFrameCnt * 2 * sizeof(int32_t));
         // Resample to target quality
         mResampler->resample(pTmpBuffer, outFrameCnt, this);
 
-        // Free previous allocation
-        if (mReSampledBuffer != NULL) {
-            free(mReSampledBuffer);
-            mReSampledBuffer = NULL;
+        // Change resampler and retry if format change happened
+        if (mFormatChanged) {
+            mFormatChanged = false;
+            checkAndSetResampler();
+            free(pTmpBuffer);
+            return read(buffer_out, NULL);
         }
-        mReSampledBuffer = (int16_t*)malloc(outBufferSize);
-        memset(mReSampledBuffer, 0x00, outBufferSize);
 
-        // Convert back to 16 bits
-        AudioMixer::ditherAndClamp((int32_t*)mReSampledBuffer, pTmpBuffer, outFrameCnt);
-        LOGV("Resampled buffer size %d", outFrameCnt* 2 * sizeof(int16_t));
+        // Create a new MediaBuffer
+        int32_t outBufferSize = outFrameCnt * 2 * sizeof(int16_t);
+        MediaBuffer* outBuffer = new MediaBuffer(outBufferSize);
 
-        // Create new MediaBuffer
-        mCopyBuffer = new MediaBuffer((void*)mReSampledBuffer, outBufferSize);
+        // Convert back to 2 channels and 16 bits
+        AudioMixer::ditherAndClamp(
+                (int32_t *)((uint8_t*)outBuffer->data() + outBuffer->range_offset()),
+                pTmpBuffer, outFrameCnt);
+        free(pTmpBuffer);
 
         // Compute and set the new timestamp
-        sp<MetaData> to = mCopyBuffer->meta_data();
-        int64_t totalOutDurationUs = (mAccuOutBufferSize * 1000000) /(mOutputSampleRate * 2 * 2); //2 channels out * 2 bytes per sample
+        sp<MetaData> to = outBuffer->meta_data();
+        int64_t totalOutDurationUs = (mAccuOutBufferSize * 1000000) / (mOutputSampleRate * 2 * 2);
         int64_t timeUs = mInitialTimeStampUs + totalOutDurationUs;
         to->setInt64(kKeyTime, timeUs);
-        LOGV("buffer duration %lld   timestamp %lld   init %lld", outDurationUs, timeUs, mInitialTimeStampUs);
 
         // update the accumulate size
         mAccuOutBufferSize += outBufferSize;
-
-        mCopyBuffer->set_range(0, outBufferSize);
-        *buffer_out = mCopyBuffer;
-
-        free(pTmpBuffer);
-
-    } else if(mIsChannelConvertionRequired == true) {
-        //TODO convert to stereo here.
+        *buffer_out = outBuffer;
     } else {
-        //LOGI("Resampling not required");
+        // Resampling not required. Read and pass-through.
         MediaBuffer *aBuffer;
         status_t err = mSource->read(&aBuffer, options);
-        LOGV("mSource->read returned %d", err);
+        if (err != OK) {
+            LOGV("read returns err = %d", err);
+        }
+
+        if (err == INFO_FORMAT_CHANGED) {
+            checkAndSetResampler();
+            return read(buffer_out, NULL);
+        }
+
+        // EOS or some other error
         if(err != OK) {
+            stop();
             *buffer_out = NULL;
-            mStarted = false;
             return err;
         }
         *buffer_out = aBuffer;
@@ -239,166 +180,131 @@
 }
 
 status_t VideoEditorSRC::getNextBuffer(AudioBufferProvider::Buffer *pBuffer) {
-    LOGV("Requesting        %d", pBuffer->frameCount);
-    uint32_t availableFrames;
-    bool lastBuffer = false;
-    MediaBuffer *aBuffer;
+    LOGV("Requesting %d, chan = %d", pBuffer->frameCount, mChannelCnt);
+    uint32_t done = 0;
+    uint32_t want = pBuffer->frameCount * mChannelCnt * 2;
+    pBuffer->raw = malloc(want);
 
-    //update the internal buffer
-    // Store the leftover at the beginning of the local buffer
-    if (mLeftover > 0) {
-        LOGV("Moving mLeftover =%d  from  %d", mLeftover, mLastReadSize);
-        if (mLastReadSize > 0) {
-            memcpy(mInterframeBuffer, (uint8_t*) (mInterframeBuffer + mLastReadSize), mLeftover);
-        }
-        mInterframeBufferPosition = mLeftover;
-    }
-    else {
-        mInterframeBufferPosition = 0;
-    }
-
-    availableFrames = mInterframeBufferPosition / (mChannelCnt*2);
-
-    while ((availableFrames < pBuffer->frameCount)&&(mStarted)) {
-        // if we seek, reset the initial time stamp and accumulated time
-        ReadOptions options;
-        if (mSeekTimeUs >= 0) {
-            LOGV("%p cacheMore_l Seek requested = %lld", this, mSeekTimeUs);
-            ReadOptions::SeekMode mode = mSeekMode;
-            options.setSeekTo(mSeekTimeUs, mode);
-            mSeekTimeUs = -1;
-        }
-        /* The first call to read() will require to buffer twice as much data */
-        /* This will be needed by the resampler */
-        status_t err = mSource->read(&aBuffer, &options);
-        LOGV("mSource->read returned %d", err);
-        if (err == INFO_FORMAT_CHANGED) {
-            LOGV("getNextBuffer: source read returned INFO_FORMAT_CHANGED");
-            // Change resampler if required
-            status_t err1 = checkAndSetResampler();
-            if (err1 != OK) {
-                LOGE("checkAndSetResampler() returned error %d", err1);
-                return err1;
+    while (mStarted && want > 0) {
+        // If we don't have any data left, read a new buffer.
+        if (!mBuffer) {
+            // if we seek, reset the initial time stamp and accumulated time
+            ReadOptions options;
+            if (mSeekTimeUs >= 0) {
+                LOGV("%p cacheMore_l Seek requested = %lld", this, mSeekTimeUs);
+                ReadOptions::SeekMode mode = mSeekMode;
+                options.setSeekTo(mSeekTimeUs, mode);
+                mSeekTimeUs = -1;
+                mInitialTimeStampUs = -1;
+                mAccuOutBufferSize = 0;
             }
-            // Update availableFrames with new channel count
-            availableFrames = mInterframeBufferPosition / (mChannelCnt*2);
-            continue;
-        } else if (err != OK) {
-            if (mInterframeBufferPosition == 0) {
-                mStarted = false;
-            }
-            //Empty the internal buffer if there is no more data left in the source
-            else {
-                lastBuffer = true;
-                //clear the end of the buffer, just in case
-                memset(mInterframeBuffer+mInterframeBufferPosition, 0x00, DEFAULT_SAMPLING_FREQ * 2 * 2 - mInterframeBufferPosition);
-                mStarted = false;
-            }
-        }
-        else {
-            //copy the buffer
-            memcpy(((uint8_t*) mInterframeBuffer) + mInterframeBufferPosition,
-                    ((uint8_t*) aBuffer->data()) + aBuffer->range_offset(),
-                    aBuffer->range_length());
-            LOGV("Read from buffer  %d", aBuffer->range_length());
 
-            mInterframeBufferPosition += aBuffer->range_length();
-            LOGV("Stored            %d", mInterframeBufferPosition);
+            status_t err = mSource->read(&mBuffer, &options);
 
-            // Get the time stamp of the first buffer
+            if (err != OK) {
+                free(pBuffer->raw);
+                pBuffer->raw = NULL;
+                pBuffer->frameCount = 0;
+            }
+
+            if (err == INFO_FORMAT_CHANGED) {
+                LOGV("getNextBuffer: source read returned INFO_FORMAT_CHANGED");
+                // At this point we cannot switch to a new AudioResampler because
+                // we are in a callback called by the AudioResampler itself. So
+                // just remember the fact that the format has changed, and let
+                // read() handles this.
+                mFormatChanged = true;
+                return err;
+            }
+
+            // EOS or some other error
+            if (err != OK) {
+                LOGV("EOS or some err: %d", err);
+                stop();
+                return err;
+            }
+
+            CHECK(mBuffer);
+            mLeftover = mBuffer->range_length();
             if (mInitialTimeStampUs == -1) {
                 int64_t curTS;
-                sp<MetaData> from = aBuffer->meta_data();
+                sp<MetaData> from = mBuffer->meta_data();
                 from->findInt64(kKeyTime, &curTS);
                 LOGV("setting mInitialTimeStampUs to %lld", mInitialTimeStampUs);
                 mInitialTimeStampUs = curTS;
             }
-
-            // release the buffer
-            aBuffer->release();
         }
-        availableFrames = mInterframeBufferPosition / (mChannelCnt*2);
-        LOGV("availableFrames   %d", availableFrames);
+
+        // Now copy data to the destination
+        uint32_t todo = mLeftover;
+        if (todo > want) {
+            todo = want;
+        }
+
+        uint8_t* end = (uint8_t*)mBuffer->data() + mBuffer->range_offset()
+                + mBuffer->range_length();
+        memcpy((uint8_t*)pBuffer->raw + done, end - mLeftover, todo);
+        done += todo;
+        want -= todo;
+        mLeftover -= todo;
+
+        // Release MediaBuffer as soon as possible.
+        if (mLeftover == 0) {
+            mBuffer->release();
+            mBuffer = NULL;
+        }
     }
 
-    if (lastBuffer) {
-        pBuffer->frameCount = availableFrames;
-    }
-
-    //update the input buffer
-    pBuffer->raw        = (void*)(mInterframeBuffer);
-
-    // Update how many bytes are left
-    // (actualReadSize is updated in getNextBuffer() called from resample())
-    int32_t actualReadSize = pBuffer->frameCount * mChannelCnt * 2;
-    mLeftover = mInterframeBufferPosition - actualReadSize;
-    LOGV("mLeftover         %d", mLeftover);
-
-    mLastReadSize = actualReadSize;
-
-    LOGV("inFrameCount     %d", pBuffer->frameCount);
-
+    pBuffer->frameCount = done / (mChannelCnt * 2);
+    LOGV("getNextBuffer done %d", pBuffer->frameCount);
     return OK;
 }
 
 
 void VideoEditorSRC::releaseBuffer(AudioBufferProvider::Buffer *pBuffer) {
-    if(pBuffer->raw != NULL) {
-        pBuffer->raw = NULL;
-    }
+    free(pBuffer->raw);
+    pBuffer->raw = NULL;
     pBuffer->frameCount = 0;
 }
 
-status_t VideoEditorSRC::checkAndSetResampler() {
-
+void VideoEditorSRC::checkAndSetResampler() {
     LOGV("checkAndSetResampler");
 
     sp<MetaData> format = mSource->getFormat();
     const char *mime;
-    bool success = format->findCString(kKeyMIMEType, &mime);
-    CHECK(success);
+    CHECK(format->findCString(kKeyMIMEType, &mime));
     CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW));
 
-    success = format->findInt32(kKeySampleRate, &mSampleRate);
-    CHECK(success);
+    CHECK(format->findInt32(kKeySampleRate, &mSampleRate));
+    CHECK(format->findInt32(kKeyChannelCount, &mChannelCnt));
 
-    int32_t numChannels;
-    success = format->findInt32(kKeyChannelCount, &mChannelCnt);
-    CHECK(success);
-
-    // If Resampler exists, delete it first
+    // If a resampler exists, delete it first
     if (mResampler != NULL) {
         delete mResampler;
         mResampler = NULL;
     }
 
-    if (mSampleRate != mOutputSampleRate) {
-        LOGV("Resampling required (%d != %d)", mSampleRate, mOutputSampleRate);
-        mIsResamplingRequired = true;
-        LOGV("Create resampler %d %d %d", mBitDepth, mChannelCnt, mOutputSampleRate);
-
-        mResampler = AudioResampler::create(
-                        mBitDepth, mChannelCnt, mOutputSampleRate, AudioResampler::DEFAULT);
-
-        if (mResampler == NULL) {
-            return NO_MEMORY;
-        }
-        LOGV("Set input rate %d", mSampleRate);
-        mResampler->setSampleRate(mSampleRate);
-        mResampler->setVolume(UNITY_GAIN, UNITY_GAIN);
-
-    } else {
-        LOGV("Resampling not required (%d = %d)", mSampleRate, mOutputSampleRate);
-        mIsResamplingRequired = false;
-        if (mChannelCnt != 2) {
-            // we always make sure to provide stereo
-            LOGV("Only Channel convertion required");
-            mIsChannelConvertionRequired = true;
-        }
+    // Clear previous buffer
+    if (mBuffer) {
+        mBuffer->release();
+        mBuffer = NULL;
     }
 
-    return OK;
+    if (mSampleRate != mOutputSampleRate || mChannelCnt != 2) {
+        LOGV("Resampling required (in rate %d, out rate %d, in channel %d)",
+            mSampleRate, mOutputSampleRate, mChannelCnt);
 
+        mResampler = AudioResampler::create(
+                        16 /* bit depth */,
+                        mChannelCnt,
+                        mOutputSampleRate,
+                        AudioResampler::DEFAULT);
+        CHECK(mResampler);
+        mResampler->setSampleRate(mSampleRate);
+        mResampler->setVolume(UNITY_GAIN, UNITY_GAIN);
+    } else {
+        LOGV("Resampling not required (%d = %d)", mSampleRate, mOutputSampleRate);
+    }
 }
 
 } //namespce android