/* * 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 0 #define LOG_TAG "VideoEditorSRC" #include "VideoEditorSRC.h" #include <media/stagefright/MetaData.h> #include <media/stagefright/MediaDebug.h> #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::VideoEditorSRC %p(%p)", this, source.get()); mSource = source; mResampler = NULL; mChannelCnt = 0; mSampleRate = 0; mOutputSampleRate = DEFAULT_SAMPLING_FREQ; mStarted = false; mInitialTimeStampUs = -1; mAccuOutBufferSize = 0; mSeekTimeUs = -1; mBuffer = NULL; mLeftover = 0; mFormatChanged = false; mSeekMode = ReadOptions::SEEK_PREVIOUS_SYNC; // Input Source validation sp<MetaData> format = mSource->getFormat(); const char *mime; CHECK(format->findCString(kKeyMIMEType, &mime)); CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)); // 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() { LOGV("VideoEditorSRC::~VideoEditorSRC %p(%p)", this, mSource.get()); stop(); } status_t VideoEditorSRC::start(MetaData *params) { CHECK(!mStarted); LOGV("VideoEditorSRC:start %p(%p)", this, mSource.get()); // Set resampler if required checkAndSetResampler(); mSeekTimeUs = -1; mSeekMode = ReadOptions::SEEK_PREVIOUS_SYNC; mStarted = true; mSource->start(); return OK; } status_t 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; mResampler = NULL; } mStarted = false; mInitialTimeStampUs = -1; mAccuOutBufferSize = 0; mLeftover = 0; return OK; } sp<MetaData> VideoEditorSRC::getFormat() { LOGV("VideoEditorSRC::getFormat"); return mOutputFormat; } status_t VideoEditorSRC::read( MediaBuffer **buffer_out, const ReadOptions *options) { LOGV("VideoEditorSRC::read %p(%p)", this, mSource.get()); *buffer_out = NULL; if (!mStarted) { return ERROR_END_OF_STREAM; } 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); mSeekTimeUs = seekTimeUs; mSeekMode = mode; } // We ask for 1024 frames in output 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); // Change resampler and retry if format change happened if (mFormatChanged) { mFormatChanged = false; checkAndSetResampler(); free(pTmpBuffer); return read(buffer_out, NULL); } // Create a new MediaBuffer int32_t outBufferSize = outFrameCnt * 2 * sizeof(int16_t); MediaBuffer* outBuffer = new MediaBuffer(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 = outBuffer->meta_data(); int64_t totalOutDurationUs = (mAccuOutBufferSize * 1000000) / (mOutputSampleRate * 2 * 2); int64_t timeUs = mInitialTimeStampUs + totalOutDurationUs; to->setInt64(kKeyTime, timeUs); // update the accumulate size mAccuOutBufferSize += outBufferSize; *buffer_out = outBuffer; } else { // Resampling not required. Read and pass-through. MediaBuffer *aBuffer; status_t err = mSource->read(&aBuffer, options); 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; return err; } *buffer_out = aBuffer; } return OK; } status_t VideoEditorSRC::getNextBuffer(AudioBufferProvider::Buffer *pBuffer) { 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) { LOGV("%p cacheMore_l Seek requested = %lld", this, mSeekTimeUs); ReadOptions::SeekMode mode = mSeekMode; options.setSeekTo(mSeekTimeUs, mode); mSeekTimeUs = -1; mInitialTimeStampUs = -1; mAccuOutBufferSize = 0; } 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"); // 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 = mBuffer->meta_data(); from->findInt64(kKeyTime, &curTS); LOGV("setting mInitialTimeStampUs to %lld", mInitialTimeStampUs); mInitialTimeStampUs = curTS; } } // 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; } } pBuffer->frameCount = done / (mChannelCnt * 2); LOGV("getNextBuffer done %d", pBuffer->frameCount); return OK; } void VideoEditorSRC::releaseBuffer(AudioBufferProvider::Buffer *pBuffer) { free(pBuffer->raw); pBuffer->raw = NULL; pBuffer->frameCount = 0; } void VideoEditorSRC::checkAndSetResampler() { LOGV("checkAndSetResampler"); sp<MetaData> format = mSource->getFormat(); const char *mime; CHECK(format->findCString(kKeyMIMEType, &mime)); CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)); CHECK(format->findInt32(kKeySampleRate, &mSampleRate)); CHECK(format->findInt32(kKeyChannelCount, &mChannelCnt)); // If a resampler exists, delete it first if (mResampler != NULL) { delete mResampler; mResampler = NULL; } // 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( 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