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

Commit a007d502 authored by Chih-Chung Chang's avatar Chih-Chung Chang Committed by Android (Google) Code Review
Browse files

Merge "Fix 5123908: Native crash rewinding movie"

parents 5f9cd080 3d974e77
Loading
Loading
Loading
Loading
+0 −8
Original line number Diff line number Diff line
@@ -499,18 +499,10 @@ size_t VideoEditorAudioPlayer::fillBuffer(void *data, size_t size) {

                        bgFrame.m_dataAddress = (M4OSA_UInt16*)M4OSA_32bitAlignedMalloc( len, 1,
                                                       (M4OSA_Char*)"bgFrame");
                        if (NULL == bgFrame.m_dataAddress) {
                            LOGE("mBackgroundAudioSetting Malloc failed");
                        }

                        bgFrame.m_bufferSize = len;

                        mixFrame.m_dataAddress = (M4OSA_UInt16*)M4OSA_32bitAlignedMalloc(len, 1,
                                                    (M4OSA_Char*)"mixFrame");
                        if (NULL == mixFrame.m_dataAddress) {
                            LOGE("mBackgroundAudioSetting Malloc failed");
                        }

                        mixFrame.m_bufferSize = len;

                        LOGV("mix with bgm with size %lld", mBGAudioPCMFileLength);
+145 −239
Original line number Diff line number Diff line
@@ -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,96 +23,50 @@
#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;
    mFormatChanged = false;
    mSeekMode = ReadOptions::SEEK_PREVIOUS_SYNC;

    mOutputFormat = new MetaData;

    // 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) {
    // Set the metadata of the output after resampling.
    mOutputFormat = new MetaData;
    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


}

VideoEditorSRC::~VideoEditorSRC() {
    if (mStarted == true)
    LOGV("VideoEditorSRC::~VideoEditorSRC %p(%p)", this, mSource.get());
    stop();

    if(mOutputFormat != NULL) {
        mOutputFormat.clear();
        mOutputFormat = NULL;
    }

    if (mInterframeBuffer != NULL){
        delete mInterframeBuffer;
        mInterframeBuffer = NULL;
    }
}

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);

    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;
@@ -125,9 +77,12 @@ status_t VideoEditorSRC::start (MetaData *params) {
}

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;
@@ -137,99 +92,85 @@ status_t VideoEditorSRC::stop() {
    mInitialTimeStampUs = -1;
    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(
        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,27 +180,14 @@ status_t VideoEditorSRC::read (
}

status_t VideoEditorSRC::getNextBuffer(AudioBufferProvider::Buffer *pBuffer) {
    LOGV("Requesting        %d", pBuffer->frameCount);
    uint32_t availableFrames;
    bool lastBuffer = false;
    MediaBuffer *aBuffer;

    //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)) {
    LOGV("Requesting %d, chan = %d", pBuffer->frameCount, mChannelCnt);
    uint32_t done = 0;
    uint32_t want = pBuffer->frameCount * mChannelCnt * 2;
    pBuffer->raw = malloc(want);

    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) {
@@ -267,138 +195,116 @@ status_t VideoEditorSRC::getNextBuffer(AudioBufferProvider::Buffer *pBuffer) {
                ReadOptions::SeekMode mode = mSeekMode;
                options.setSeekTo(mSeekTimeUs, mode);
                mSeekTimeUs = -1;
                mInitialTimeStampUs = -1;
                mAccuOutBufferSize = 0;
            }
        /* 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);

            status_t err = mSource->read(&mBuffer, &options);

            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");
            // Change resampler if required
            status_t err1 = checkAndSetResampler();
            if (err1 != OK) {
                LOGE("checkAndSetResampler() returned error %d", err1);
                return err1;
            }
            // 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;
            }
                // 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;
            }
        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);
            // EOS or some other error
            if (err != OK) {
                LOGV("EOS or some err: %d", err);
                stop();
                return err;
            }

            // Get the time stamp of the first buffer
            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);
        }

    if (lastBuffer) {
        pBuffer->frameCount = availableFrames;
        // Now copy data to the destination
        uint32_t todo = mLeftover;
        if (todo > want) {
            todo = want;
        }

    //update the input buffer
    pBuffer->raw        = (void*)(mInterframeBuffer);
        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;

    // 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);
        // Release MediaBuffer as soon as possible.
        if (mLeftover == 0) {
            mBuffer->release();
            mBuffer = NULL;
        }
    }

    pBuffer->frameCount = done / (mChannelCnt * 2);
    LOGV("getNextBuffer done %d", pBuffer->frameCount);
    return OK;
}


void VideoEditorSRC::releaseBuffer(AudioBufferProvider::Buffer *pBuffer) {
    if(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);

    int32_t numChannels;
    success = format->findInt32(kKeyChannelCount, &mChannelCnt);
    CHECK(success);
    CHECK(format->findInt32(kKeySampleRate, &mSampleRate));
    CHECK(format->findInt32(kKeyChannelCount, &mChannelCnt));

    // 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);
    // Clear previous buffer
    if (mBuffer) {
        mBuffer->release();
        mBuffer = NULL;
    }

    if (mSampleRate != mOutputSampleRate || mChannelCnt != 2) {
        LOGV("Resampling required (in rate %d, out rate %d, in channel %d)",
            mSampleRate, mOutputSampleRate, mChannelCnt);

        mResampler = AudioResampler::create(
                        mBitDepth, mChannelCnt, mOutputSampleRate, AudioResampler::DEFAULT);

        if (mResampler == NULL) {
            return NO_MEMORY;
        }
        LOGV("Set input rate %d", mSampleRate);
                        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);
        mIsResamplingRequired = false;
        if (mChannelCnt != 2) {
            // we always make sure to provide stereo
            LOGV("Only Channel convertion required");
            mIsChannelConvertionRequired = true;
        }
    }

    return OK;

}

} //namespce android
+4 −14
Original line number Diff line number Diff line
@@ -43,8 +43,6 @@ class VideoEditorSRC : public MediaSource , public AudioBufferProvider {
        virtual status_t getNextBuffer(Buffer* buffer);
        virtual void releaseBuffer(Buffer* buffer);

        void setResampling(int32_t sampleRate=kFreq32000Hz);

    enum { //Sampling freq
        kFreq8000Hz = 8000,
        kFreq11025Hz = 11025,
@@ -58,7 +56,7 @@ class VideoEditorSRC : public MediaSource , public AudioBufferProvider {
    };

    static const uint16_t UNITY_GAIN = 0x1000;
    static const int32_t DEFAULT_SAMPLING_FREQ = (int32_t)kFreq32000Hz; // kFreq44100;
    static const int32_t DEFAULT_SAMPLING_FREQ = (int32_t)kFreq32000Hz;

    protected :
        virtual ~VideoEditorSRC();
@@ -67,33 +65,25 @@ class VideoEditorSRC : public MediaSource , public AudioBufferProvider {
        VideoEditorSRC();
        VideoEditorSRC &operator=(const VideoEditorSRC &);

        status_t checkAndSetResampler();
        void checkAndSetResampler();

        AudioResampler        *mResampler;
        sp<MediaSource>      mSource;
        MediaBuffer      *mCopyBuffer;
        int mBitDepth;
        int mChannelCnt;
        int mSampleRate;
        int32_t mOutputSampleRate;
        bool mStarted;
        bool mIsResamplingRequired;
        bool mIsChannelConvertionRequired; // for mono to stereo
        sp<MetaData> mOutputFormat;
        Mutex mLock;

        uint8_t* mInterframeBuffer;
        int32_t mInterframeBufferPosition;
        MediaBuffer* mBuffer;
        int32_t mLeftover;
        int32_t mLastReadSize ;
        bool mFormatChanged;

        int64_t mInitialTimeStampUs;
        int64_t mAccuOutBufferSize;

        int64_t mSeekTimeUs;
        ReadOptions::SeekMode mSeekMode;
        int16_t *mReSampledBuffer;

};

} //namespce android