/* * Copyright (C) 2011 NXP Software * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_NDEBUG 1 #define LOG_TAG "VEAudioSource" #include #include "VideoEditorSRC.h" #include #include #include "AudioMixer.h" namespace android { VideoEditorSRC::VideoEditorSRC( const sp &source) { LOGV("VideoEditorSRC::Create"); 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; mLeftover = 0; mLastReadSize = 0; mReSampledBuffer = NULL; #ifndef FROYO mSeekMode = ReadOptions::SEEK_PREVIOUS_SYNC; #endif mOutputFormat = new MetaData; // Input Source validation sp format = mSource->getFormat(); const char *mime; bool success = format->findCString(kKeyMIMEType, &mime); CHECK(success); 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; pInterframeBuffer = new uint8_t[DEFAULT_SAMPLING_FREQ * 2 * 2]; //stereo=2 * bytespersample=2 } VideoEditorSRC::~VideoEditorSRC(){ if (mStarted == true) stop(); if(mOutputFormat != NULL) { mOutputFormat.clear(); mOutputFormat = NULL; } if (pInterframeBuffer != NULL){ delete pInterframeBuffer; pInterframeBuffer = 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"); sp format = mSource->getFormat(); const char *mime; bool success = format->findCString(kKeyMIMEType, &mime); CHECK(success); CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)); success = format->findInt32(kKeySampleRate, &mSampleRate); CHECK(success); int32_t numChannels; success = format->findInt32(kKeyChannelCount, &mChannelCnt); CHECK(success); mInputFrameSize = mChannelCnt * 2; //2 is the byte depth 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 { if(mChannelCnt != 2) { //we always make sure to provide stereo LOGV("Only Channel convertion required"); mIsChannelConvertionRequired = true; } } mSeekTimeUs = -1; #ifndef FROYO mSeekMode = ReadOptions::SEEK_PREVIOUS_SYNC; #endif mStarted = true; mSource->start(); return OK; } status_t VideoEditorSRC::stop() { Mutex::Autolock autoLock(mLock); LOGV("VideoEditorSRC::stop()"); mSource->stop(); if(mResampler != NULL) { delete mResampler; mResampler = NULL; } mStarted = false; mInitialTimeStampUs = -1; mAccuOutBufferSize = 0; mLeftover = 0; mLastReadSize = 0; if (mReSampledBuffer != NULL) { free(mReSampledBuffer); mReSampledBuffer = NULL; } return OK; } sp VideoEditorSRC::getFormat() { LOGV("AudioSRC getFormat"); //Mutex::Autolock autoLock(mLock); return mOutputFormat; } status_t VideoEditorSRC::read ( MediaBuffer **buffer_out, const ReadOptions *options) { Mutex::Autolock autoLock(mLock); *buffer_out = NULL; int32_t leftover = 0; LOGV("VideoEditorSRC::read"); if (!mStarted) { return ERROR_END_OF_STREAM; } if(mIsResamplingRequired == true) { LOGV("mIsResamplingRequired = true"); // Store the seek parameters int64_t seekTimeUs; #ifndef FROYO ReadOptions::SeekMode mode = ReadOptions::SEEK_PREVIOUS_SYNC; if (options && options->getSeekTo(&seekTimeUs, &mode)) { #else if (options && options->getSeekTo(&seekTimeUs)) { #endif LOGV("read Seek %lld", seekTimeUs); mInitialTimeStampUs = -1; mSeekTimeUs = seekTimeUs; #ifndef FROYO mSeekMode = mode; #else mReadOptions = *options; #endif } // 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); 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)); // Resample to target quality mResampler->resample(pTmpBuffer, outFrameCnt, this); // Free previous allocation if (mReSampledBuffer != NULL) { free(mReSampledBuffer); mReSampledBuffer = 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 new MediaBuffer mCopyBuffer = new MediaBuffer((void*)mReSampledBuffer, outBufferSize); // Compute and set the new timestamp sp to = mCopyBuffer->meta_data(); int64_t totalOutDurationUs = (mAccuOutBufferSize * 1000000) /(mOutputSampleRate * 2 * 2); //2 channels out * 2 bytes per sample 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. } else { //LOGI("Resampling not required"); MediaBuffer *aBuffer; status_t err = mSource->read(&aBuffer, options); LOGV("mSource->read returned %d", err); if(err != OK) { *buffer_out = NULL; mStarted = false; return err; } *buffer_out = aBuffer; } return OK; } 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(pInterframeBuffer, (uint8_t*) (pInterframeBuffer + 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 #ifndef FROYO ReadOptions options; if (mSeekTimeUs >= 0) { LOGV("%p cacheMore_l Seek requested = %lld", this, mSeekTimeUs); ReadOptions::SeekMode mode = mSeekMode; options.setSeekTo(mSeekTimeUs, mode); mSeekTimeUs = -1; } #else ReadOptions options; if (mSeekTimeUs >= 0) { LOGV("%p cacheMore_l Seek requested = %lld", this, mSeekTimeUs); options = mReadOptions; mSeekTimeUs = -1; } #endif /* 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 != OK) { if (mInterframeBufferPosition == 0) { mStarted = false; } //Empty the internal buffer if there is no more data left in the source else { lastBuffer = true; mInputByteBuffer = pInterframeBuffer; //clear the end of the buffer, just in case memset(pInterframeBuffer+mInterframeBufferPosition, 0x00, DEFAULT_SAMPLING_FREQ * 2 * 2 - mInterframeBufferPosition); mStarted = false; } } else { //copy the buffer memcpy(((uint8_t*) pInterframeBuffer) + 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); // Get the time stamp of the first buffer if (mInitialTimeStampUs == -1) { int64_t curTS; sp from = aBuffer->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; } //update the input buffer pBuffer->raw = (void*)(pInterframeBuffer); // 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); return OK; } void VideoEditorSRC::releaseBuffer(AudioBufferProvider::Buffer *pBuffer) { if(pBuffer->raw != NULL) { pBuffer->raw = NULL; } pBuffer->frameCount = 0; } } //namespce android