diff options
Diffstat (limited to 'libvideoeditor')
-rwxr-xr-x | libvideoeditor/lvpp/Android.mk | 1 | ||||
-rw-r--r-- | libvideoeditor/lvpp/AudioPlayerBase.cpp | 510 | ||||
-rw-r--r-- | libvideoeditor/lvpp/AudioPlayerBase.h | 119 | ||||
-rwxr-xr-x | libvideoeditor/lvpp/PreviewPlayer.cpp | 51 | ||||
-rwxr-xr-x | libvideoeditor/lvpp/PreviewPlayer.h | 6 | ||||
-rwxr-xr-x | libvideoeditor/lvpp/VideoEditorAudioPlayer.cpp | 247 | ||||
-rwxr-xr-x | libvideoeditor/lvpp/VideoEditorAudioPlayer.h | 63 |
7 files changed, 294 insertions, 703 deletions
diff --git a/libvideoeditor/lvpp/Android.mk b/libvideoeditor/lvpp/Android.mk index db6cb48..1ea02a3 100755 --- a/libvideoeditor/lvpp/Android.mk +++ b/libvideoeditor/lvpp/Android.mk @@ -34,7 +34,6 @@ LOCAL_SRC_FILES:= \ DummyAudioSource.cpp \ DummyVideoSource.cpp \ VideoEditorBGAudioProcessing.cpp \ - AudioPlayerBase.cpp \ PreviewRenderer.cpp \ I420ColorConverter.cpp \ NativeWindowRenderer.cpp diff --git a/libvideoeditor/lvpp/AudioPlayerBase.cpp b/libvideoeditor/lvpp/AudioPlayerBase.cpp deleted file mode 100644 index 67ea43c..0000000 --- a/libvideoeditor/lvpp/AudioPlayerBase.cpp +++ /dev/null @@ -1,510 +0,0 @@ -/* - * 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 "AudioPlayerBase" -#include <utils/Log.h> - -#include <binder/IPCThreadState.h> -#include <media/AudioTrack.h> -#include <media/stagefright/MediaDebug.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MediaErrors.h> -#include <media/stagefright/MediaSource.h> -#include <media/stagefright/MetaData.h> - -#include "AudioPlayerBase.h" -#include "PreviewPlayer.h" - -namespace android { - -AudioPlayerBase::AudioPlayerBase( - const sp<MediaPlayerBase::AudioSink> &audioSink, - PreviewPlayer *observer) - : mAudioTrack(NULL), - mInputBuffer(NULL), - mSampleRate(0), - mLatencyUs(0), - mFrameSize(0), - mNumFramesPlayed(0), - mPositionTimeMediaUs(-1), - mPositionTimeRealUs(-1), - mSeeking(false), - mReachedEOS(false), - mFinalStatus(OK), - mStarted(false), - mIsFirstBuffer(false), - mFirstBufferResult(OK), - mFirstBuffer(NULL), - mAudioSink(audioSink), - mObserver(observer) { -} - -AudioPlayerBase::~AudioPlayerBase() { - if (mStarted) { - reset(); - } -} - -void AudioPlayerBase::setSource(const sp<MediaSource> &source) { - CHECK_EQ(mSource, NULL); - mSource = source; -} - -status_t AudioPlayerBase::start(bool sourceAlreadyStarted) { - CHECK(!mStarted); - CHECK(mSource != NULL); - - status_t err; - if (!sourceAlreadyStarted) { - err = mSource->start(); - - if (err != OK) { - return err; - } - } - - // We allow an optional INFO_FORMAT_CHANGED at the very beginning - // of playback, if there is one, getFormat below will retrieve the - // updated format, if there isn't, we'll stash away the valid buffer - // of data to be used on the first audio callback. - - CHECK(mFirstBuffer == NULL); - - mFirstBufferResult = mSource->read(&mFirstBuffer); - if (mFirstBufferResult == INFO_FORMAT_CHANGED) { - ALOGV("INFO_FORMAT_CHANGED!!!"); - - CHECK(mFirstBuffer == NULL); - mFirstBufferResult = OK; - mIsFirstBuffer = false; - } else { - mIsFirstBuffer = true; - } - - sp<MetaData> 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, &numChannels); - CHECK(success); - - if (mAudioSink.get() != NULL) { - status_t err = mAudioSink->open( - mSampleRate, numChannels, AUDIO_FORMAT_PCM_16_BIT, - DEFAULT_AUDIOSINK_BUFFERCOUNT, - &AudioPlayerBase::AudioSinkCallback, this); - if (err != OK) { - if (mFirstBuffer != NULL) { - mFirstBuffer->release(); - mFirstBuffer = NULL; - } - - if (!sourceAlreadyStarted) { - mSource->stop(); - } - - return err; - } - - mLatencyUs = (int64_t)mAudioSink->latency() * 1000; - mFrameSize = mAudioSink->frameSize(); - - mAudioSink->start(); - } else { - mAudioTrack = new AudioTrack( - AUDIO_STREAM_MUSIC, mSampleRate, AUDIO_FORMAT_PCM_16_BIT, - (numChannels == 2) - ? AUDIO_CHANNEL_OUT_STEREO - : AUDIO_CHANNEL_OUT_MONO, - 0, 0, &AudioCallback, this, 0); - - if ((err = mAudioTrack->initCheck()) != OK) { - delete mAudioTrack; - mAudioTrack = NULL; - - if (mFirstBuffer != NULL) { - mFirstBuffer->release(); - mFirstBuffer = NULL; - } - - if (!sourceAlreadyStarted) { - mSource->stop(); - } - - return err; - } - - mLatencyUs = (int64_t)mAudioTrack->latency() * 1000; - mFrameSize = mAudioTrack->frameSize(); - - mAudioTrack->start(); - } - - mStarted = true; - - return OK; -} - -void AudioPlayerBase::pause(bool playPendingSamples) { - CHECK(mStarted); - - if (playPendingSamples) { - if (mAudioSink.get() != NULL) { - mAudioSink->stop(); - } else { - mAudioTrack->stop(); - } - } else { - if (mAudioSink.get() != NULL) { - mAudioSink->pause(); - } else { - mAudioTrack->pause(); - } - } -} - -void AudioPlayerBase::resume() { - CHECK(mStarted); - - if (mAudioSink.get() != NULL) { - mAudioSink->start(); - } else { - mAudioTrack->start(); - } -} - -void AudioPlayerBase::reset() { - CHECK(mStarted); - - if (mAudioSink.get() != NULL) { - mAudioSink->stop(); - mAudioSink->close(); - } else { - mAudioTrack->stop(); - - delete mAudioTrack; - mAudioTrack = NULL; - } - - // Make sure to release any buffer we hold onto so that the - // source is able to stop(). - - if (mFirstBuffer != NULL) { - mFirstBuffer->release(); - mFirstBuffer = NULL; - } - - if (mInputBuffer != NULL) { - ALOGV("AudioPlayerBase releasing input buffer."); - - mInputBuffer->release(); - mInputBuffer = NULL; - } - - mSource->stop(); - - // The following hack is necessary to ensure that the OMX - // component is completely released by the time we may try - // to instantiate it again. - wp<MediaSource> tmp = mSource; - mSource.clear(); - while (tmp.promote() != NULL) { - usleep(1000); - } - IPCThreadState::self()->flushCommands(); - - mNumFramesPlayed = 0; - mPositionTimeMediaUs = -1; - mPositionTimeRealUs = -1; - mSeeking = false; - mReachedEOS = false; - mFinalStatus = OK; - mStarted = false; -} - -// static -void AudioPlayerBase::AudioCallback(int event, void *user, void *info) { - static_cast<AudioPlayerBase *>(user)->AudioCallback(event, info); -} - -bool AudioPlayerBase::isSeeking() { - Mutex::Autolock autoLock(mLock); - return mSeeking; -} - -bool AudioPlayerBase::reachedEOS(status_t *finalStatus) { - *finalStatus = OK; - - Mutex::Autolock autoLock(mLock); - *finalStatus = mFinalStatus; - return mReachedEOS; -} - -// static -size_t AudioPlayerBase::AudioSinkCallback( - MediaPlayerBase::AudioSink *audioSink, - void *buffer, size_t size, void *cookie) { - AudioPlayerBase *me = (AudioPlayerBase *)cookie; - - return me->fillBuffer(buffer, size); -} - -void AudioPlayerBase::AudioCallback(int event, void *info) { - if (event != AudioTrack::EVENT_MORE_DATA) { - return; - } - - AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info; - size_t numBytesWritten = fillBuffer(buffer->raw, buffer->size); - - buffer->size = numBytesWritten; -} - -uint32_t AudioPlayerBase::getNumFramesPendingPlayout() const { - uint32_t numFramesPlayedOut; - status_t err; - - if (mAudioSink != NULL) { - err = mAudioSink->getPosition(&numFramesPlayedOut); - } else { - err = mAudioTrack->getPosition(&numFramesPlayedOut); - } - - if (err != OK || mNumFramesPlayed < numFramesPlayedOut) { - return 0; - } - - // mNumFramesPlayed is the number of frames submitted - // to the audio sink for playback, but not all of them - // may have played out by now. - return mNumFramesPlayed - numFramesPlayedOut; -} - -size_t AudioPlayerBase::fillBuffer(void *data, size_t size) { - if (mNumFramesPlayed == 0) { - ALOGV("AudioCallback"); - } - - if (mReachedEOS) { - return 0; - } - - bool postSeekComplete = false; - bool postEOS = false; - int64_t postEOSDelayUs = 0; - - size_t size_done = 0; - size_t size_remaining = size; - while (size_remaining > 0) { - MediaSource::ReadOptions options; - - { - Mutex::Autolock autoLock(mLock); - - if (mSeeking) { - if (mIsFirstBuffer) { - if (mFirstBuffer != NULL) { - mFirstBuffer->release(); - mFirstBuffer = NULL; - } - mIsFirstBuffer = false; - } - - options.setSeekTo(mSeekTimeUs); - - if (mInputBuffer != NULL) { - mInputBuffer->release(); - mInputBuffer = NULL; - } - - mSeeking = false; - if (mObserver) { - postSeekComplete = true; - } - } - } - - if (mInputBuffer == NULL) { - status_t err; - - if (mIsFirstBuffer) { - mInputBuffer = mFirstBuffer; - mFirstBuffer = NULL; - err = mFirstBufferResult; - - mIsFirstBuffer = false; - } else { - err = mSource->read(&mInputBuffer, &options); - } - - CHECK((err == OK && mInputBuffer != NULL) - || (err != OK && mInputBuffer == NULL)); - - Mutex::Autolock autoLock(mLock); - - if (err != OK) { - if (mObserver && !mReachedEOS) { - // We don't want to post EOS right away but only - // after all frames have actually been played out. - - // These are the number of frames submitted to the - // AudioTrack that you haven't heard yet. - uint32_t numFramesPendingPlayout = - getNumFramesPendingPlayout(); - - // These are the number of frames we're going to - // submit to the AudioTrack by returning from this - // callback. - uint32_t numAdditionalFrames = size_done / mFrameSize; - - numFramesPendingPlayout += numAdditionalFrames; - - int64_t timeToCompletionUs = - (1000000ll * numFramesPendingPlayout) / mSampleRate; - - ALOGV("total number of frames played: %lld (%lld us)", - (mNumFramesPlayed + numAdditionalFrames), - 1000000ll * (mNumFramesPlayed + numAdditionalFrames) - / mSampleRate); - - ALOGV("%d frames left to play, %lld us (%.2f secs)", - numFramesPendingPlayout, - timeToCompletionUs, timeToCompletionUs / 1E6); - - postEOS = true; - postEOSDelayUs = timeToCompletionUs + mLatencyUs; - } - - mReachedEOS = true; - mFinalStatus = err; - break; - } - - CHECK(mInputBuffer->meta_data()->findInt64( - kKeyTime, &mPositionTimeMediaUs)); - - mPositionTimeRealUs = - ((mNumFramesPlayed + size_done / mFrameSize) * 1000000) - / mSampleRate; - - ALOGV("buffer->size() = %d, " - "mPositionTimeMediaUs=%.2f mPositionTimeRealUs=%.2f", - mInputBuffer->range_length(), - mPositionTimeMediaUs / 1E6, mPositionTimeRealUs / 1E6); - } - - if (mInputBuffer->range_length() == 0) { - mInputBuffer->release(); - mInputBuffer = NULL; - - continue; - } - - size_t copy = size_remaining; - if (copy > mInputBuffer->range_length()) { - copy = mInputBuffer->range_length(); - } - - memcpy((char *)data + size_done, - (const char *)mInputBuffer->data() + mInputBuffer->range_offset(), - copy); - - mInputBuffer->set_range(mInputBuffer->range_offset() + copy, - mInputBuffer->range_length() - copy); - - size_done += copy; - size_remaining -= copy; - } - - { - Mutex::Autolock autoLock(mLock); - mNumFramesPlayed += size_done / mFrameSize; - } - - if (postEOS) { - mObserver->postAudioEOS(postEOSDelayUs); - } - - if (postSeekComplete) { - mObserver->postAudioSeekComplete(); - } - - return size_done; -} - -int64_t AudioPlayerBase::getRealTimeUs() { - Mutex::Autolock autoLock(mLock); - return getRealTimeUsLocked(); -} - -int64_t AudioPlayerBase::getRealTimeUsLocked() const { - return -mLatencyUs + (mNumFramesPlayed * 1000000) / mSampleRate; -} - -int64_t AudioPlayerBase::getMediaTimeUs() { - Mutex::Autolock autoLock(mLock); - - if (mPositionTimeMediaUs < 0 || mPositionTimeRealUs < 0) { - if (mSeeking) { - return mSeekTimeUs; - } - - return 0; - } - - int64_t realTimeOffset = getRealTimeUsLocked() - mPositionTimeRealUs; - if (realTimeOffset < 0) { - realTimeOffset = 0; - } - - return mPositionTimeMediaUs + realTimeOffset; -} - -bool AudioPlayerBase::getMediaTimeMapping( - int64_t *realtime_us, int64_t *mediatime_us) { - Mutex::Autolock autoLock(mLock); - - *realtime_us = mPositionTimeRealUs; - *mediatime_us = mPositionTimeMediaUs; - - return mPositionTimeRealUs != -1 && mPositionTimeMediaUs != -1; -} - -status_t AudioPlayerBase::seekTo(int64_t time_us) { - Mutex::Autolock autoLock(mLock); - - mSeeking = true; - mPositionTimeRealUs = mPositionTimeMediaUs = -1; - mReachedEOS = false; - mSeekTimeUs = time_us; - - if (mAudioSink != NULL) { - mAudioSink->flush(); - } else { - mAudioTrack->flush(); - } - - return OK; -} - -} diff --git a/libvideoeditor/lvpp/AudioPlayerBase.h b/libvideoeditor/lvpp/AudioPlayerBase.h deleted file mode 100644 index b39d4a2..0000000 --- a/libvideoeditor/lvpp/AudioPlayerBase.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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. - */ - -#ifndef AUDIO_PLAYER_BASE_H_ - -#define AUDIO_PLAYER_BASE_H_ - -#include <media/MediaPlayerInterface.h> -#include <media/stagefright/MediaBuffer.h> -#include <media/stagefright/TimeSource.h> -#include <utils/threads.h> - -namespace android { - -class MediaSource; -class AudioTrack; -class PreviewPlayer; - -class AudioPlayerBase : public TimeSource { -public: - enum { - REACHED_EOS, - SEEK_COMPLETE - }; - - AudioPlayerBase(const sp<MediaPlayerBase::AudioSink> &audioSink, - PreviewPlayer *audioObserver = NULL); - - virtual ~AudioPlayerBase(); - - // Caller retains ownership of "source". - void setSource(const sp<MediaSource> &source); - - // Return time in us. - virtual int64_t getRealTimeUs(); - - status_t start(bool sourceAlreadyStarted = false); - - void pause(bool playPendingSamples = false); - void resume(); - - // Returns the timestamp of the last buffer played (in us). - int64_t getMediaTimeUs(); - - // Returns true iff a mapping is established, i.e. the AudioPlayerBase - // has played at least one frame of audio. - bool getMediaTimeMapping(int64_t *realtime_us, int64_t *mediatime_us); - - status_t seekTo(int64_t time_us); - - bool isSeeking(); - bool reachedEOS(status_t *finalStatus); - -private: - friend class VideoEditorAudioPlayer; - sp<MediaSource> mSource; - AudioTrack *mAudioTrack; - - MediaBuffer *mInputBuffer; - - int mSampleRate; - int64_t mLatencyUs; - size_t mFrameSize; - - Mutex mLock; - int64_t mNumFramesPlayed; - - int64_t mPositionTimeMediaUs; - int64_t mPositionTimeRealUs; - - bool mSeeking; - bool mReachedEOS; - status_t mFinalStatus; - int64_t mSeekTimeUs; - - bool mStarted; - - bool mIsFirstBuffer; - status_t mFirstBufferResult; - MediaBuffer *mFirstBuffer; - - sp<MediaPlayerBase::AudioSink> mAudioSink; - PreviewPlayer *mObserver; - - static void AudioCallback(int event, void *user, void *info); - void AudioCallback(int event, void *info); - - static size_t AudioSinkCallback( - MediaPlayerBase::AudioSink *audioSink, - void *data, size_t size, void *me); - - size_t fillBuffer(void *data, size_t size); - - int64_t getRealTimeUsLocked() const; - - void reset(); - - uint32_t getNumFramesPendingPlayout() const; - - AudioPlayerBase(const AudioPlayerBase &); - AudioPlayerBase &operator=(const AudioPlayerBase &); -}; - -} // namespace android - -#endif // AUDIO_PLAYER_BASE_H_ diff --git a/libvideoeditor/lvpp/PreviewPlayer.cpp b/libvideoeditor/lvpp/PreviewPlayer.cpp index 77c70a5..80eee4b 100755 --- a/libvideoeditor/lvpp/PreviewPlayer.cpp +++ b/libvideoeditor/lvpp/PreviewPlayer.cpp @@ -36,7 +36,6 @@ #include <surfaceflinger/ISurfaceComposer.h> #include "VideoEditorPreviewController.h" -#include "AudioPlayerBase.h" #include "DummyAudioSource.h" #include "DummyVideoSource.h" #include "VideoEditorSRC.h" @@ -99,7 +98,7 @@ PreviewPlayer::PreviewPlayer(NativeWindowRenderer* renderer) mVideoRenderer = NULL; mEffectsSettings = NULL; - mVeAudioPlayer = NULL; + mAudioPlayer = NULL; mAudioMixStoryBoardTS = 0; mCurrentMediaBeginCutTime = 0; mCurrentMediaVolumeValue = 0; @@ -368,7 +367,7 @@ status_t PreviewPlayer::startAudioPlayer_l() { // We've already started the MediaSource in order to enable // the prefetcher to read its data. - status_t err = mVeAudioPlayer->start( + status_t err = mAudioPlayer->start( true /* sourceAlreadyStarted */); if (err != OK) { @@ -376,7 +375,7 @@ status_t PreviewPlayer::startAudioPlayer_l() { return err; } } else { - mVeAudioPlayer->resume(); + mAudioPlayer->resume(); } mFlags |= AUDIO_RUNNING; @@ -386,7 +385,7 @@ status_t PreviewPlayer::startAudioPlayer_l() { return OK; } -status_t PreviewPlayer::setAudioPlayer(AudioPlayerBase *audioPlayer) { +status_t PreviewPlayer::setAudioPlayer(VideoEditorAudioPlayer *audioPlayer) { ALOGV("setAudioPlayer"); Mutex::Autolock autoLock(mLock); CHECK(!(mFlags & PLAYING)); @@ -394,11 +393,9 @@ status_t PreviewPlayer::setAudioPlayer(AudioPlayerBase *audioPlayer) { ALOGV("SetAudioPlayer"); mIsChangeSourceRequired = true; - mVeAudioPlayer = - (VideoEditorAudioPlayer*)mAudioPlayer; // check if the new and old source are dummy - sp<MediaSource> anAudioSource = mVeAudioPlayer->getSource(); + sp<MediaSource> anAudioSource = mAudioPlayer->getSource(); if (anAudioSource == NULL) { // Audio player does not have any source set. ALOGV("setAudioPlayer: Audio player does not have any source set"); @@ -546,25 +543,22 @@ status_t PreviewPlayer::play_l() { if (mAudioSink != NULL) { mAudioPlayer = new VideoEditorAudioPlayer(mAudioSink, this); - mVeAudioPlayer = - (VideoEditorAudioPlayer*)mAudioPlayer; - mAudioPlayer->setSource(mAudioSource); - mVeAudioPlayer->setAudioMixSettings( + mAudioPlayer->setAudioMixSettings( mPreviewPlayerAudioMixSettings); - mVeAudioPlayer->setAudioMixPCMFileHandle( + mAudioPlayer->setAudioMixPCMFileHandle( mAudioMixPCMFileHandle); - mVeAudioPlayer->setAudioMixStoryBoardSkimTimeStamp( + mAudioPlayer->setAudioMixStoryBoardSkimTimeStamp( mAudioMixStoryBoardTS, mCurrentMediaBeginCutTime, mCurrentMediaVolumeValue); mFlags |= AUDIOPLAYER_STARTED; // We've already started the MediaSource in order to enable // the prefetcher to read its data. - status_t err = mVeAudioPlayer->start( + status_t err = mAudioPlayer->start( true /* sourceAlreadyStarted */); if (err != OK) { @@ -575,41 +569,40 @@ status_t PreviewPlayer::play_l() { return err; } - mTimeSource = mVeAudioPlayer; + mTimeSource = mAudioPlayer; mFlags |= AUDIO_RUNNING; deferredAudioSeek = true; mWatchForAudioSeekComplete = false; mWatchForAudioEOS = true; } } else { - mVeAudioPlayer = (VideoEditorAudioPlayer*)mAudioPlayer; - bool isAudioPlayerStarted = mVeAudioPlayer->isStarted(); + bool isAudioPlayerStarted = mAudioPlayer->isStarted(); if (mIsChangeSourceRequired == true) { ALOGV("play_l: Change audio source required"); if (isAudioPlayerStarted == true) { - mVeAudioPlayer->pause(); + mAudioPlayer->pause(); } - mVeAudioPlayer->setSource(mAudioSource); - mVeAudioPlayer->setObserver(this); + mAudioPlayer->setSource(mAudioSource); + mAudioPlayer->setObserver(this); - mVeAudioPlayer->setAudioMixSettings( + mAudioPlayer->setAudioMixSettings( mPreviewPlayerAudioMixSettings); - mVeAudioPlayer->setAudioMixStoryBoardSkimTimeStamp( + mAudioPlayer->setAudioMixStoryBoardSkimTimeStamp( mAudioMixStoryBoardTS, mCurrentMediaBeginCutTime, mCurrentMediaVolumeValue); if (isAudioPlayerStarted == true) { - mVeAudioPlayer->resume(); + mAudioPlayer->resume(); } else { status_t err = OK; - err = mVeAudioPlayer->start(true); + err = mAudioPlayer->start(true); if (err != OK) { mAudioPlayer = NULL; - mVeAudioPlayer = NULL; + mAudioPlayer = NULL; mFlags &= ~(PLAYING | FIRST_FRAME); return err; @@ -617,16 +610,16 @@ status_t PreviewPlayer::play_l() { } } else { ALOGV("play_l: No Source change required"); - mVeAudioPlayer->setAudioMixStoryBoardSkimTimeStamp( + mAudioPlayer->setAudioMixStoryBoardSkimTimeStamp( mAudioMixStoryBoardTS, mCurrentMediaBeginCutTime, mCurrentMediaVolumeValue); - mVeAudioPlayer->resume(); + mAudioPlayer->resume(); } mFlags |= AUDIOPLAYER_STARTED; mFlags |= AUDIO_RUNNING; - mTimeSource = mVeAudioPlayer; + mTimeSource = mAudioPlayer; deferredAudioSeek = true; mWatchForAudioSeekComplete = false; mWatchForAudioEOS = true; diff --git a/libvideoeditor/lvpp/PreviewPlayer.h b/libvideoeditor/lvpp/PreviewPlayer.h index 45f3fc2..177853f 100755 --- a/libvideoeditor/lvpp/PreviewPlayer.h +++ b/libvideoeditor/lvpp/PreviewPlayer.h @@ -30,7 +30,6 @@ namespace android { struct VideoEditorAudioPlayer; -struct AudioPlayerBase; struct MediaExtractor; struct PreviewPlayer { @@ -89,7 +88,7 @@ struct PreviewPlayer { status_t setImageClipProperties(uint32_t width, uint32_t height); status_t readFirstVideoFrame(); status_t getLastRenderedTimeMs(uint32_t *lastRenderedTimeMs); - status_t setAudioPlayer(AudioPlayerBase *audioPlayer); + status_t setAudioPlayer(VideoEditorAudioPlayer *audioPlayer); private: enum { @@ -143,7 +142,7 @@ private: sp<MediaSource> mAudioTrack; sp<MediaSource> mAudioSource; - AudioPlayerBase *mAudioPlayer; + VideoEditorAudioPlayer *mAudioPlayer; int64_t mDurationUs; int32_t mDisplayWidth; @@ -235,7 +234,6 @@ private: M4VIFI_UInt8* mFrameRGBBuffer; M4VIFI_UInt8* mFrameYUVBuffer; - VideoEditorAudioPlayer *mVeAudioPlayer; void cancelPlayerEvents_l(bool updateProgressCb = false); status_t setDataSource_l(const sp<MediaExtractor> &extractor); diff --git a/libvideoeditor/lvpp/VideoEditorAudioPlayer.cpp b/libvideoeditor/lvpp/VideoEditorAudioPlayer.cpp index 0b642ac..17ad482 100755 --- a/libvideoeditor/lvpp/VideoEditorAudioPlayer.cpp +++ b/libvideoeditor/lvpp/VideoEditorAudioPlayer.cpp @@ -35,9 +35,25 @@ namespace android { VideoEditorAudioPlayer::VideoEditorAudioPlayer( const sp<MediaPlayerBase::AudioSink> &audioSink, PreviewPlayer *observer) - : AudioPlayerBase(audioSink, observer) { - - ALOGV("VideoEditorAudioPlayer"); + : mAudioTrack(NULL), + mInputBuffer(NULL), + mSampleRate(0), + mLatencyUs(0), + mFrameSize(0), + mNumFramesPlayed(0), + mPositionTimeMediaUs(-1), + mPositionTimeRealUs(-1), + mSeeking(false), + mReachedEOS(false), + mFinalStatus(OK), + mStarted(false), + mIsFirstBuffer(false), + mFirstBufferResult(OK), + mFirstBuffer(NULL), + mAudioSink(audioSink), + mObserver(observer) { + + ALOGV("Constructor"); mBGAudioPCMFileHandle = NULL; mAudioProcess = NULL; mBGAudioPCMFileLength = 0; @@ -54,7 +70,7 @@ VideoEditorAudioPlayer::VideoEditorAudioPlayer( VideoEditorAudioPlayer::~VideoEditorAudioPlayer() { - ALOGV("~VideoEditorAudioPlayer"); + ALOGV("Destructor"); if (mStarted) { reset(); } @@ -63,6 +79,184 @@ VideoEditorAudioPlayer::~VideoEditorAudioPlayer() { mAudioProcess = NULL; } } + +void VideoEditorAudioPlayer::pause(bool playPendingSamples) { + ALOGV("pause: playPendingSamples=%d", playPendingSamples); + CHECK(mStarted); + + if (playPendingSamples) { + if (mAudioSink.get() != NULL) { + mAudioSink->stop(); + } else { + mAudioTrack->stop(); + } + } else { + if (mAudioSink.get() != NULL) { + mAudioSink->pause(); + } else { + mAudioTrack->pause(); + } + } +} + +void VideoEditorAudioPlayer::clear() { + ALOGV("clear"); + if (!mStarted) { + return; + } + + if (mAudioSink.get() != NULL) { + mAudioSink->stop(); + mAudioSink->close(); + } else { + mAudioTrack->stop(); + + delete mAudioTrack; + mAudioTrack = NULL; + } + + // Make sure to release any buffer we hold onto so that the + // source is able to stop(). + + if (mFirstBuffer != NULL) { + mFirstBuffer->release(); + mFirstBuffer = NULL; + } + + if (mInputBuffer != NULL) { + ALOGV("AudioPlayerBase releasing input buffer."); + + mInputBuffer->release(); + mInputBuffer = NULL; + } + + mSource->stop(); + + // The following hack is necessary to ensure that the OMX + // component is completely released by the time we may try + // to instantiate it again. + wp<MediaSource> tmp = mSource; + mSource.clear(); + while (tmp.promote() != NULL) { + usleep(1000); + } + IPCThreadState::self()->flushCommands(); + + mNumFramesPlayed = 0; + mPositionTimeMediaUs = -1; + mPositionTimeRealUs = -1; + mSeeking = false; + mReachedEOS = false; + mFinalStatus = OK; + mStarted = false; +} + +void VideoEditorAudioPlayer::resume() { + ALOGV("resume"); + + veAudMixSettings audioMixSettings; + + // Single audio player is used; + // Pass on the audio ducking parameters + // which might have changed with new audio source + audioMixSettings.lvInDucking_threshold = + mAudioMixSettings->uiInDucking_threshold; + audioMixSettings.lvInDucking_lowVolume = + ((M4OSA_Float)mAudioMixSettings->uiInDucking_lowVolume) / 100.0; + audioMixSettings.lvInDucking_enable = + mAudioMixSettings->bInDucking_enable; + audioMixSettings.lvPTVolLevel = + ((M4OSA_Float)mBGAudioStoryBoardCurrentMediaVolumeVal) / 100.0; + audioMixSettings.lvBTVolLevel = + ((M4OSA_Float)mAudioMixSettings->uiAddVolume) / 100.0; + audioMixSettings.lvBTChannelCount = mAudioMixSettings->uiBTChannelCount; + audioMixSettings.lvPTChannelCount = mAudioMixSettings->uiNbChannels; + + // Call to Audio mix param setting + mAudioProcess->veSetAudioProcessingParams(audioMixSettings); + + CHECK(mStarted); + + if (mAudioSink.get() != NULL) { + mAudioSink->start(); + } else { + mAudioTrack->start(); + } +} + +status_t VideoEditorAudioPlayer::seekTo(int64_t time_us) { + ALOGV("seekTo: %lld", time_us); + Mutex::Autolock autoLock(mLock); + + mSeeking = true; + mPositionTimeRealUs = mPositionTimeMediaUs = -1; + mReachedEOS = false; + mSeekTimeUs = time_us; + + if (mAudioSink != NULL) { + mAudioSink->flush(); + } else { + mAudioTrack->flush(); + } + + return OK; +} + +bool VideoEditorAudioPlayer::isSeeking() { + Mutex::Autolock lock(mLock); + ALOGV("isSeeking: mSeeking=%d", mSeeking); + return mSeeking; +} + +bool VideoEditorAudioPlayer::reachedEOS(status_t *finalStatus) { + ALOGV("reachedEOS: status=%d", mFinalStatus); + *finalStatus = OK; + + Mutex::Autolock autoLock(mLock); + *finalStatus = mFinalStatus; + return mReachedEOS; +} + +int64_t VideoEditorAudioPlayer::getRealTimeUs() { + Mutex::Autolock autoLock(mLock); + return getRealTimeUs_l(); +} + +int64_t VideoEditorAudioPlayer::getRealTimeUs_l() { + return -mLatencyUs + (mNumFramesPlayed * 1000000) / mSampleRate; +} + +int64_t VideoEditorAudioPlayer::getMediaTimeUs() { + ALOGV("getMediaTimeUs"); + Mutex::Autolock autoLock(mLock); + + if (mPositionTimeMediaUs < 0 || mPositionTimeRealUs < 0) { + if (mSeeking) { + return mSeekTimeUs; + } + + return 0; + } + + int64_t realTimeOffset = getRealTimeUs_l() - mPositionTimeRealUs; + if (realTimeOffset < 0) { + realTimeOffset = 0; + } + + return mPositionTimeMediaUs + realTimeOffset; +} + +bool VideoEditorAudioPlayer::getMediaTimeMapping( + int64_t *realtime_us, int64_t *mediatime_us) { + ALOGV("getMediaTimeMapping"); + Mutex::Autolock autoLock(mLock); + + *realtime_us = mPositionTimeRealUs; + *mediatime_us = mPositionTimeMediaUs; + + return mPositionTimeRealUs != -1 && mPositionTimeMediaUs != -1; +} + void VideoEditorAudioPlayer::setSource(const sp<MediaSource> &source) { Mutex::Autolock autoLock(mLock); @@ -106,6 +300,23 @@ bool VideoEditorAudioPlayer::isStarted() { return mStarted; } +// static +void VideoEditorAudioPlayer::AudioCallback(int event, void *user, void *info) { + static_cast<VideoEditorAudioPlayer *>(user)->AudioCallback(event, info); +} + + +void VideoEditorAudioPlayer::AudioCallback(int event, void *info) { + if (event != AudioTrack::EVENT_MORE_DATA) { + return; + } + + AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info; + size_t numBytesWritten = fillBuffer(buffer->raw, buffer->size); + + buffer->size = numBytesWritten; +} + status_t VideoEditorAudioPlayer::start(bool sourceAlreadyStarted) { Mutex::Autolock autoLock(mLock); CHECK(!mStarted); @@ -355,37 +566,11 @@ status_t VideoEditorAudioPlayer::start(bool sourceAlreadyStarted) { return OK; } -void VideoEditorAudioPlayer::resume() { - - veAudMixSettings audioMixSettings; - - // Single audio player is used; - // Pass on the audio ducking parameters - // which might have changed with new audio source - audioMixSettings.lvInDucking_threshold = - mAudioMixSettings->uiInDucking_threshold; - audioMixSettings.lvInDucking_lowVolume = - ((M4OSA_Float)mAudioMixSettings->uiInDucking_lowVolume) / 100.0; - audioMixSettings.lvInDucking_enable = - mAudioMixSettings->bInDucking_enable; - audioMixSettings.lvPTVolLevel = - ((M4OSA_Float)mBGAudioStoryBoardCurrentMediaVolumeVal) / 100.0; - audioMixSettings.lvBTVolLevel = - ((M4OSA_Float)mAudioMixSettings->uiAddVolume) / 100.0; - audioMixSettings.lvBTChannelCount = mAudioMixSettings->uiBTChannelCount; - audioMixSettings.lvPTChannelCount = mAudioMixSettings->uiNbChannels; - - // Call to Audio mix param setting - mAudioProcess->veSetAudioProcessingParams(audioMixSettings); - - //Call the base class - AudioPlayerBase::resume(); -} void VideoEditorAudioPlayer::reset() { ALOGV("reset"); - AudioPlayerBase::reset(); + clear(); // Capture the current seek point mBGAudioPCMFileSeekPoint = 0; diff --git a/libvideoeditor/lvpp/VideoEditorAudioPlayer.h b/libvideoeditor/lvpp/VideoEditorAudioPlayer.h index 2eab4c5..626df39 100755 --- a/libvideoeditor/lvpp/VideoEditorAudioPlayer.h +++ b/libvideoeditor/lvpp/VideoEditorAudioPlayer.h @@ -15,19 +15,18 @@ */ #ifndef VE_AUDIO_PLAYER_H_ - #define VE_AUDIO_PLAYER_H_ #include <media/MediaPlayerInterface.h> #include <media/stagefright/MediaBuffer.h> #include <media/stagefright/TimeSource.h> #include <utils/threads.h> + #include "M4xVSS_API.h" #include "VideoEditorMain.h" #include "M4OSA_FileReader.h" #include "VideoEditorBGAudioProcessing.h" -#include "AudioPlayerBase.h" -#include "PreviewPlayer.h" + namespace android { @@ -35,8 +34,7 @@ class MediaSource; class AudioTrack; class PreviewPlayer; - -class VideoEditorAudioPlayer : public AudioPlayerBase { +class VideoEditorAudioPlayer : public TimeSource { public: enum { REACHED_EOS, @@ -46,10 +44,24 @@ public: VideoEditorAudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink, PreviewPlayer *audioObserver = NULL); - virtual ~VideoEditorAudioPlayer(); + ~VideoEditorAudioPlayer(); + + // Return time in us. + int64_t getRealTimeUs(); + + // Returns the timestamp of the last buffer played (in us). + int64_t getMediaTimeUs(); + + // Returns true iff a mapping is established, i.e. the AudioPlayerBase + // has played at least one frame of audio. + bool getMediaTimeMapping(int64_t *realtime_us, int64_t *mediatime_us); status_t start(bool sourceAlreadyStarted = false); + void pause(bool playPendingSamples = false); void resume(); + status_t seekTo(int64_t time_us); + bool isSeeking(); + bool reachedEOS(status_t *finalStatus); void setAudioMixSettings(M4xVSS_AudioMixingSettings* pAudioMixSettings); void setAudioMixPCMFileHandle(M4OSA_Context pBGAudioPCMFileHandle); @@ -78,15 +90,48 @@ private: int64_t mBGAudioStoryBoardCurrentMediaBeginCutTS; int64_t mBGAudioStoryBoardCurrentMediaVolumeVal; - size_t fillBuffer(void *data, size_t size); + sp<MediaSource> mSource; + AudioTrack *mAudioTrack; - void reset(); - void setPrimaryTrackVolume(M4OSA_Int16 *data, M4OSA_UInt32 size, M4OSA_Float volLevel); + MediaBuffer *mInputBuffer; + + int mSampleRate; + int64_t mLatencyUs; + size_t mFrameSize; + Mutex mLock; + int64_t mNumFramesPlayed; + + int64_t mPositionTimeMediaUs; + int64_t mPositionTimeRealUs; + + bool mSeeking; + bool mReachedEOS; + status_t mFinalStatus; + int64_t mSeekTimeUs; + + bool mStarted; + + bool mIsFirstBuffer; + status_t mFirstBufferResult; + MediaBuffer *mFirstBuffer; + + sp<MediaPlayerBase::AudioSink> mAudioSink; + PreviewPlayer *mObserver; + + static void AudioCallback(int event, void *user, void *info); + void AudioCallback(int event, void *info); + size_t fillBuffer(void *data, size_t size); static size_t AudioSinkCallback( MediaPlayerBase::AudioSink *audioSink, void *data, size_t size, void *me); + void reset(); + void clear(); + int64_t getRealTimeUs_l(); + void setPrimaryTrackVolume( + M4OSA_Int16 *data, M4OSA_UInt32 size, M4OSA_Float volLevel); + VideoEditorAudioPlayer(const VideoEditorAudioPlayer &); VideoEditorAudioPlayer &operator=(const VideoEditorAudioPlayer &); }; |