diff options
-rw-r--r-- | include/media/stagefright/OMXCodec.h | 3 | ||||
-rw-r--r-- | include/media/stagefright/SkipCutBuffer.h | 58 | ||||
-rw-r--r-- | media/libstagefright/Android.mk | 1 | ||||
-rwxr-xr-x | media/libstagefright/OMXCodec.cpp | 40 | ||||
-rwxr-xr-x | media/libstagefright/SkipCutBuffer.cpp | 130 | ||||
-rw-r--r-- | media/libstagefright/codecs/mp3dec/SoftMP3.cpp | 20 | ||||
-rw-r--r-- | media/libstagefright/codecs/mp3dec/SoftMP3.h | 6 |
7 files changed, 252 insertions, 6 deletions
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h index 392ea87..7c612ba 100644 --- a/include/media/stagefright/OMXCodec.h +++ b/include/media/stagefright/OMXCodec.h @@ -30,6 +30,7 @@ struct MediaCodecList; class MemoryDealer; struct OMXCodecObserver; struct CodecProfileLevel; +class SkipCutBuffer; struct OMXCodec : public MediaSource, public MediaBufferObserver { @@ -201,6 +202,7 @@ private: ReadOptions::SeekMode mSeekMode; int64_t mTargetTimeUs; bool mOutputPortSettingsChangedPending; + SkipCutBuffer *mSkipCutBuffer; MediaBuffer *mLeftOverBuffer; @@ -378,6 +380,7 @@ status_t QueryCodecs( const char *mimeType, bool queryDecoders, Vector<CodecCapabilities> *results); + } // namespace android #endif // OMX_CODEC_H_ diff --git a/include/media/stagefright/SkipCutBuffer.h b/include/media/stagefright/SkipCutBuffer.h new file mode 100644 index 0000000..5c7cd47 --- /dev/null +++ b/include/media/stagefright/SkipCutBuffer.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012 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 SKIP_CUT_BUFFER_H_ + +#define SKIP_CUT_BUFFER_H_ + +#include <media/stagefright/MediaBuffer.h> + +namespace android { + +/** + * utility class to cut the start and end off a stream of data in MediaBuffers + * + */ +class SkipCutBuffer { + public: + // 'skip' is the number of bytes to skip from the beginning + // 'cut' is the number of bytes to cut from the end + // 'output_size' is the size in bytes of the MediaBuffers that will be used + SkipCutBuffer(int32_t skip, int32_t cut, int32_t output_size); + virtual ~SkipCutBuffer(); + + // Submit one MediaBuffer for skipping and cutting. This may consume all or + // some of the data in the buffer, or it may add data to it. + // After this, the caller should continue processing the buffer as usual. + void submit(MediaBuffer *buffer); + void clear(); + size_t size(); // how many bytes are currently stored in the buffer + + private: + void write(const char *src, size_t num); + size_t read(char *dst, size_t num); + int32_t mFrontPadding; + int32_t mBackPadding; + int32_t mWriteHead; + int32_t mReadHead; + int32_t mCapacity; + char* mCutBuffer; + DISALLOW_EVIL_CONSTRUCTORS(SkipCutBuffer); +}; + +} // namespace android + +#endif // OMX_CODEC_H_ diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 77714f3..7d7bd7d 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -42,6 +42,7 @@ LOCAL_SRC_FILES:= \ OggExtractor.cpp \ SampleIterator.cpp \ SampleTable.cpp \ + SkipCutBuffer.cpp \ StagefrightMediaScanner.cpp \ StagefrightMetadataRetriever.cpp \ SurfaceMediaSource.cpp \ diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index d5e6bec..8b6e9d5 100755 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -38,6 +38,7 @@ #include <media/stagefright/MetaData.h> #include <media/stagefright/OMXCodec.h> #include <media/stagefright/Utils.h> +#include <media/stagefright/SkipCutBuffer.h> #include <utils/Vector.h> #include <OMX_Audio.h> @@ -1303,6 +1304,7 @@ OMXCodec::OMXCodec( mSeekMode(ReadOptions::SEEK_CLOSEST_SYNC), mTargetTimeUs(-1), mOutputPortSettingsChangedPending(false), + mSkipCutBuffer(NULL), mLeftOverBuffer(NULL), mPaused(false), mNativeWindow( @@ -1413,6 +1415,9 @@ OMXCodec::~OMXCodec() { free(mMIME); mMIME = NULL; + + delete mSkipCutBuffer; + mSkipCutBuffer = NULL; } status_t OMXCodec::init() { @@ -1573,6 +1578,34 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) { portIndex == kPortIndexInput ? "input" : "output"); } + if (portIndex == kPortIndexOutput) { + + sp<MetaData> meta = mSource->getFormat(); + int32_t delay = 0; + if (!meta->findInt32(kKeyEncoderDelay, &delay)) { + delay = 0; + } + int32_t padding = 0; + if (!meta->findInt32(kKeyEncoderPadding, &padding)) { + padding = 0; + } + int32_t numchannels = 0; + if (delay + padding) { + if (meta->findInt32(kKeyChannelCount, &numchannels)) { + size_t frameSize = numchannels * sizeof(int16_t); + if (mSkipCutBuffer) { + size_t prevbuffersize = mSkipCutBuffer->size(); + if (prevbuffersize != 0) { + ALOGW("Replacing SkipCutBuffer holding %d bytes", prevbuffersize); + } + delete mSkipCutBuffer; + } + mSkipCutBuffer = new SkipCutBuffer(delay * frameSize, padding * frameSize, + def.nBufferSize); + } + } + } + // dumpPortStatus(portIndex); if (portIndex == kPortIndexInput && (mFlags & kUseSecureInputBuffers)) { @@ -2490,6 +2523,10 @@ void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) { CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]), mPortBuffers[portIndex].size()); + if (mSkipCutBuffer && mPortStatus[kPortIndexOutput] == ENABLED) { + mSkipCutBuffer->clear(); + } + if (mState == RECONFIGURING) { CHECK_EQ(portIndex, (OMX_U32)kPortIndexOutput); @@ -3800,6 +3837,9 @@ status_t OMXCodec::read( info->mStatus = OWNED_BY_CLIENT; info->mMediaBuffer->add_ref(); + if (mSkipCutBuffer) { + mSkipCutBuffer->submit(info->mMediaBuffer); + } *buffer = info->mMediaBuffer; return OK; diff --git a/media/libstagefright/SkipCutBuffer.cpp b/media/libstagefright/SkipCutBuffer.cpp new file mode 100755 index 0000000..6d331b0 --- /dev/null +++ b/media/libstagefright/SkipCutBuffer.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2012 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 "SkipCutBuffer" +#include <utils/Log.h> + +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/MediaBuffer.h> +#include <media/stagefright/SkipCutBuffer.h> + +namespace android { + +SkipCutBuffer::SkipCutBuffer(int32_t skip, int32_t cut, int32_t output_size) { + mFrontPadding = skip; + mBackPadding = cut; + mWriteHead = 0; + mReadHead = 0; + mCapacity = cut + output_size; + mCutBuffer = new char[mCapacity]; + ALOGV("skipcutbuffer %d %d %d", skip, cut, mCapacity); +} + +SkipCutBuffer::~SkipCutBuffer() { + delete[] mCutBuffer; +} + +void SkipCutBuffer::submit(MediaBuffer *buffer) { + int32_t offset = buffer->range_offset(); + int32_t buflen = buffer->range_length(); + + // drop the initial data from the buffer if needed + if (mFrontPadding > 0) { + // still data left to drop + int32_t to_drop = (buflen < mFrontPadding) ? buflen : mFrontPadding; + offset += to_drop; + buflen -= to_drop; + buffer->set_range(offset, buflen); + mFrontPadding -= to_drop; + } + + + // append data to cutbuffer + char *src = ((char*) buffer->data()) + offset; + write(src, buflen); + + + // the mediabuffer is now empty. Fill it from cutbuffer, always leaving + // at least mBackPadding bytes in the cutbuffer + char *dst = (char*) buffer->data(); + size_t copied = read(dst, buffer->size()); + buffer->set_range(0, copied); +} + +void SkipCutBuffer::clear() { + mWriteHead = mReadHead = 0; +} + +void SkipCutBuffer::write(const char *src, size_t num) { + int32_t sizeused = (mWriteHead - mReadHead); + if (sizeused < 0) sizeused += mCapacity; + + // everything must fit + CHECK_GE((mCapacity - size_t(sizeused)), num); + + size_t copyfirst = (mCapacity - mWriteHead); + if (copyfirst > num) copyfirst = num; + if (copyfirst) { + memcpy(mCutBuffer + mWriteHead, src, copyfirst); + num -= copyfirst; + src += copyfirst; + mWriteHead += copyfirst; + CHECK_LE(mWriteHead, mCapacity); + if (mWriteHead == mCapacity) mWriteHead = 0; + if (num) { + memcpy(mCutBuffer, src, num); + mWriteHead += num; + } + } +} + +size_t SkipCutBuffer::read(char *dst, size_t num) { + int32_t available = (mWriteHead - mReadHead); + if (available < 0) available += mCapacity; + + available -= mBackPadding; + if (available <=0) { + return 0; + } + if (available < num) { + num = available; + } + + size_t copyfirst = (mCapacity - mReadHead); + if (copyfirst > num) copyfirst = num; + if (copyfirst) { + memcpy(dst, mCutBuffer + mReadHead, copyfirst); + num -= copyfirst; + dst += copyfirst; + mReadHead += copyfirst; + CHECK_LE(mReadHead, mCapacity); + if (mReadHead == mCapacity) mReadHead = 0; + if (num) { + memcpy(dst, mCutBuffer, num); + mReadHead += num; + } + } + return available; +} + +size_t SkipCutBuffer::size() { + int32_t available = (mWriteHead - mReadHead); + if (available < 0) available += mCapacity; + return available; +} + +} // namespace android diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp index ad55295..92009ee 100644 --- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp +++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp @@ -115,6 +115,7 @@ void SoftMP3::initDecoder() { mDecoderBuf = malloc(memRequirements); pvmp3_InitDecoder(mConfig, mDecoderBuf); + mIsFirst = true; } OMX_ERRORTYPE SoftMP3::internalGetParameter( @@ -190,7 +191,10 @@ void SoftMP3::onQueueFilled(OMX_U32 portIndex) { inInfo->mOwnedByUs = false; notifyEmptyBufferDone(inHeader); - outHeader->nFilledLen = 0; + // pad the end of the stream with 529 samples, since that many samples + // were trimmed off the beginning when decoding started + outHeader->nFilledLen = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t); + memset(outHeader->pBuffer, 0, outHeader->nFilledLen); outHeader->nFlags = OMX_BUFFERFLAG_EOS; outQueue.erase(outQueue.begin()); @@ -251,8 +255,17 @@ void SoftMP3::onQueueFilled(OMX_U32 portIndex) { return; } - outHeader->nOffset = 0; - outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t); + if (mIsFirst) { + mIsFirst = false; + // The decoder delay is 529 samples, so trim that many samples off + // the start of the first output buffer. This essentially makes this + // decoder have zero delay, which the rest of the pipeline assumes. + outHeader->nOffset = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t); + outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t) - outHeader->nOffset; + } else { + outHeader->nOffset = 0; + outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t); + } outHeader->nTimeStamp = mAnchorTimeUs @@ -288,6 +301,7 @@ void SoftMP3::onPortFlushCompleted(OMX_U32 portIndex) { // Make sure that the next buffer output does not still // depend on fragments from the last one decoded. pvmp3_InitDecoder(mConfig, mDecoderBuf); + mIsFirst = true; } } diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.h b/media/libstagefright/codecs/mp3dec/SoftMP3.h index 70d0682..3a05466 100644 --- a/media/libstagefright/codecs/mp3dec/SoftMP3.h +++ b/media/libstagefright/codecs/mp3dec/SoftMP3.h @@ -46,7 +46,8 @@ protected: private: enum { kNumBuffers = 4, - kOutputBufferSize = 4608 * 2 + kOutputBufferSize = 4608 * 2, + kPVMP3DecoderDelay = 529 // frames }; tPVMP3DecoderExternal *mConfig; @@ -57,8 +58,7 @@ private: int32_t mNumChannels; int32_t mSamplingRate; - bool mConfigured; - + bool mIsFirst; bool mSignalledError; enum { |