diff options
91 files changed, 994 insertions, 780 deletions
diff --git a/camera/camera2/ICameraDeviceUser.cpp b/camera/camera2/ICameraDeviceUser.cpp index 277b5db..d1d63d5 100644 --- a/camera/camera2/ICameraDeviceUser.cpp +++ b/camera/camera2/ICameraDeviceUser.cpp @@ -208,14 +208,11 @@ public: return reply.readInt32(); } - virtual status_t createStream(int width, int height, int format, + virtual status_t createStream( const sp<IGraphicBufferProducer>& bufferProducer) { Parcel data, reply; data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); - data.writeInt32(width); - data.writeInt32(height); - data.writeInt32(format); data.writeInt32(1); // marker that bufferProducer is not null data.writeString16(String16("unknown_name")); // name of surface @@ -396,14 +393,6 @@ status_t BnCameraDeviceUser::onTransact( } break; case CREATE_STREAM: { CHECK_INTERFACE(ICameraDeviceUser, data, reply); - int width, height, format; - - width = data.readInt32(); - ALOGV("%s: CREATE_STREAM: width = %d", __FUNCTION__, width); - height = data.readInt32(); - ALOGV("%s: CREATE_STREAM: height = %d", __FUNCTION__, height); - format = data.readInt32(); - ALOGV("%s: CREATE_STREAM: format = %d", __FUNCTION__, format); sp<IGraphicBufferProducer> bp; if (data.readInt32() != 0) { @@ -419,7 +408,7 @@ status_t BnCameraDeviceUser::onTransact( } status_t ret; - ret = createStream(width, height, format, bp); + ret = createStream(bp); reply->writeNoException(); ALOGV("%s: CREATE_STREAM: write noException", __FUNCTION__); diff --git a/cmds/stagefright/SimplePlayer.cpp b/cmds/stagefright/SimplePlayer.cpp index 40762e5..ac1a547 100644 --- a/cmds/stagefright/SimplePlayer.cpp +++ b/cmds/stagefright/SimplePlayer.cpp @@ -116,7 +116,7 @@ void SimplePlayer::onMessageReceived(const sp<AMessage> &msg) { mState = UNPREPARED; } - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); sp<AMessage> response = new AMessage; @@ -139,7 +139,7 @@ void SimplePlayer::onMessageReceived(const sp<AMessage> &msg) { err = OK; } - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); sp<AMessage> response = new AMessage; @@ -161,7 +161,7 @@ void SimplePlayer::onMessageReceived(const sp<AMessage> &msg) { } } - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); sp<AMessage> response = new AMessage; @@ -194,7 +194,7 @@ void SimplePlayer::onMessageReceived(const sp<AMessage> &msg) { } } - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); sp<AMessage> response = new AMessage; @@ -217,7 +217,7 @@ void SimplePlayer::onMessageReceived(const sp<AMessage> &msg) { } } - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); sp<AMessage> response = new AMessage; @@ -240,7 +240,7 @@ void SimplePlayer::onMessageReceived(const sp<AMessage> &msg) { mState = UNINITIALIZED; } - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); sp<AMessage> response = new AMessage; diff --git a/include/camera/camera2/ICameraDeviceUser.h b/include/camera/camera2/ICameraDeviceUser.h index 35488bb..bfc2aa0 100644 --- a/include/camera/camera2/ICameraDeviceUser.h +++ b/include/camera/camera2/ICameraDeviceUser.h @@ -101,7 +101,6 @@ public: virtual status_t deleteStream(int streamId) = 0; virtual status_t createStream( - int width, int height, int format, const sp<IGraphicBufferProducer>& bufferProducer) = 0; // Create a request object from a template. diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h index 2e1ed6c..3de0774 100644 --- a/include/media/AudioTrack.h +++ b/include/media/AudioTrack.h @@ -63,7 +63,7 @@ public: // See AudioTimestamp for the information included with event. }; - /* Client should declare Buffer on the stack and pass address to obtainBuffer() + /* Client should declare a Buffer and pass the address to obtainBuffer() * and releaseBuffer(). See also callback_t for EVENT_MORE_DATA. */ @@ -72,14 +72,20 @@ public: public: // FIXME use m prefix size_t frameCount; // number of sample frames corresponding to size; - // on input it is the number of frames desired, - // on output is the number of frames actually filled - // (currently ignored, but will make the primary field in future) + // on input to obtainBuffer() it is the number of frames desired, + // on output from obtainBuffer() it is the number of available + // [empty slots for] frames to be filled + // on input to releaseBuffer() it is currently ignored size_t size; // input/output in bytes == frameCount * frameSize - // on input it is unused - // on output is the number of bytes actually filled - // FIXME this is redundant with respect to frameCount. + // on input to obtainBuffer() it is ignored + // on output from obtainBuffer() it is the number of available + // [empty slots for] bytes to be filled, + // which is frameCount * frameSize + // on input to releaseBuffer() it is the number of bytes to + // release + // FIXME This is redundant with respect to frameCount. Consider + // removing size and making frameCount the primary field. union { void* raw; @@ -484,10 +490,18 @@ public: */ status_t attachAuxEffect(int effectId); - /* Obtains a buffer of up to "audioBuffer->frameCount" empty slots for frames. + /* Public API for TRANSFER_OBTAIN mode. + * Obtains a buffer of up to "audioBuffer->frameCount" empty slots for frames. * After filling these slots with data, the caller should release them with releaseBuffer(). * If the track buffer is not full, obtainBuffer() returns as many contiguous * [empty slots for] frames as are available immediately. + * + * If nonContig is non-NULL, it is an output parameter that will be set to the number of + * additional non-contiguous frames that are predicted to be available immediately, + * if the client were to release the first frames and then call obtainBuffer() again. + * This value is only a prediction, and needs to be confirmed. + * It will be set to zero for an error return. + * * If the track buffer is full and track is stopped, obtainBuffer() returns WOULD_BLOCK * regardless of the value of waitCount. * If the track buffer is full and track is not stopped, obtainBuffer() blocks with a @@ -496,7 +510,6 @@ public: * is exhausted, at which point obtainBuffer() will either block * or return WOULD_BLOCK depending on the value of the "waitCount" * parameter. - * Each sample is 16-bit signed PCM. * * obtainBuffer() and releaseBuffer() are deprecated for direct use by applications, * which should use write() or callback EVENT_MORE_DATA instead. @@ -508,24 +521,29 @@ public: * * Buffer fields * On entry: - * frameCount number of frames requested + * frameCount number of [empty slots for] frames requested + * size ignored + * raw ignored * After error return: * frameCount 0 * size 0 * raw undefined * After successful return: - * frameCount actual number of frames available, <= number requested + * frameCount actual number of [empty slots for] frames available, <= number requested * size actual number of bytes available * raw pointer to the buffer */ - /* FIXME Deprecated public API for TRANSFER_OBTAIN mode */ - status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount) + status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount, + size_t *nonContig = NULL) __attribute__((__deprecated__)); private: /* If nonContig is non-NULL, it is an output parameter that will be set to the number of - * additional non-contiguous frames that are available immediately. + * additional non-contiguous frames that are predicted to be available immediately, + * if the client were to release the first frames and then call obtainBuffer() again. + * This value is only a prediction, and needs to be confirmed. + * It will be set to zero for an error return. * FIXME We could pass an array of Buffers instead of only one Buffer to obtainBuffer(), * in case the requested amount of frames is in two or more non-contiguous regions. * FIXME requested and elapsed are both relative times. Consider changing to absolute time. @@ -534,9 +552,17 @@ private: struct timespec *elapsed = NULL, size_t *nonContig = NULL); public: - /* Release a filled buffer of "audioBuffer->frameCount" frames for AudioFlinger to process. */ + /* Public API for TRANSFER_OBTAIN mode. + * Release a filled buffer of frames for AudioFlinger to process. + * + * Buffer fields: + * frameCount currently ignored but recommend to set to actual number of frames filled + * size actual number of bytes filled, must be multiple of frameSize + * raw ignored + * + */ // FIXME make private when obtainBuffer() for TRANSFER_OBTAIN is removed - void releaseBuffer(Buffer* audioBuffer); + void releaseBuffer(const Buffer* audioBuffer); /* As a convenience we provide a write() interface to the audio buffer. * Input parameter 'size' is in byte units. diff --git a/include/media/stagefright/BufferProducerWrapper.h b/include/media/stagefright/BufferProducerWrapper.h index d8acf30..4caa2c6 100644 --- a/include/media/stagefright/BufferProducerWrapper.h +++ b/include/media/stagefright/BufferProducerWrapper.h @@ -19,6 +19,7 @@ #define BUFFER_PRODUCER_WRAPPER_H_ #include <gui/IGraphicBufferProducer.h> +#include <media/stagefright/foundation/ABase.h> namespace android { diff --git a/media/libmediaplayerservice/nuplayer/MediaClock.h b/include/media/stagefright/MediaClock.h index 660764f..660764f 100644 --- a/media/libmediaplayerservice/nuplayer/MediaClock.h +++ b/include/media/stagefright/MediaClock.h diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h index d448097..8241e19 100644 --- a/include/media/stagefright/MediaCodec.h +++ b/include/media/stagefright/MediaCodec.h @@ -27,6 +27,7 @@ namespace android { struct ABuffer; struct AMessage; +struct AReplyToken; struct AString; struct CodecBase; struct ICrypto; @@ -222,7 +223,7 @@ private: sp<ALooper> mCodecLooper; sp<CodecBase> mCodec; AString mComponentName; - uint32_t mReplyID; + sp<AReplyToken> mReplyID; uint32_t mFlags; status_t mStickyError; sp<Surface> mNativeWindow; @@ -249,10 +250,10 @@ private: Vector<BufferInfo> mPortBuffers[2]; int32_t mDequeueInputTimeoutGeneration; - uint32_t mDequeueInputReplyID; + sp<AReplyToken> mDequeueInputReplyID; int32_t mDequeueOutputTimeoutGeneration; - uint32_t mDequeueOutputReplyID; + sp<AReplyToken> mDequeueOutputReplyID; sp<ICrypto> mCrypto; @@ -267,7 +268,7 @@ private: static status_t PostAndAwaitResponse( const sp<AMessage> &msg, sp<AMessage> *response); - static void PostReplyWithError(int32_t replyID, int32_t err); + static void PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err); status_t init(const AString &name, bool nameIsType, bool encoder); @@ -283,8 +284,8 @@ private: size_t portIndex, size_t index, sp<ABuffer> *buffer, sp<AMessage> *format); - bool handleDequeueInputBuffer(uint32_t replyID, bool newRequest = false); - bool handleDequeueOutputBuffer(uint32_t replyID, bool newRequest = false); + bool handleDequeueInputBuffer(const sp<AReplyToken> &replyID, bool newRequest = false); + bool handleDequeueOutputBuffer(const sp<AReplyToken> &replyID, bool newRequest = false); void cancelPendingDequeueOperations(); void extractCSD(const sp<AMessage> &format); diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h index 0970b2b..7b8f59d 100644 --- a/include/media/stagefright/MediaCodecSource.h +++ b/include/media/stagefright/MediaCodecSource.h @@ -25,6 +25,7 @@ namespace android { class ALooper; class AMessage; +struct AReplyToken; class IGraphicBufferProducer; class MediaCodec; class MetaData; @@ -99,7 +100,7 @@ private: sp<Puller> mPuller; sp<MediaCodec> mEncoder; uint32_t mFlags; - List<uint32_t> mStopReplyIDQueue; + List<sp<AReplyToken>> mStopReplyIDQueue; bool mIsVideo; bool mStarted; bool mStopping; diff --git a/include/media/stagefright/foundation/ABase.h b/include/media/stagefright/foundation/ABase.h index 72e3d87..ef1e010 100644 --- a/include/media/stagefright/foundation/ABase.h +++ b/include/media/stagefright/foundation/ABase.h @@ -18,7 +18,9 @@ #define A_BASE_H_ +#ifndef ARRAY_SIZE #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) +#endif #define DISALLOW_EVIL_CONSTRUCTORS(name) \ name(const name &); \ diff --git a/include/media/stagefright/foundation/ALooper.h b/include/media/stagefright/foundation/ALooper.h index 150cdba..09c469b 100644 --- a/include/media/stagefright/foundation/ALooper.h +++ b/include/media/stagefright/foundation/ALooper.h @@ -30,6 +30,7 @@ namespace android { struct AHandler; struct AMessage; +struct AReplyToken; struct ALooper : public RefBase { typedef int32_t event_id; @@ -79,7 +80,27 @@ private: sp<LooperThread> mThread; bool mRunningLocally; + // use a separate lock for reply handling, as it is always on another thread + // use a central lock, however, to avoid creating a mutex for each reply + Mutex mRepliesLock; + Condition mRepliesCondition; + + // START --- methods used only by AMessage + + // posts a message on this looper with the given timeout void post(const sp<AMessage> &msg, int64_t delayUs); + + // creates a reply token to be used with this looper + sp<AReplyToken> createReplyToken(); + // waits for a response for the reply token. If status is OK, the response + // is stored into the supplied variable. Otherwise, it is unchanged. + status_t awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response); + // posts a reply for a reply token. If the reply could be successfully posted, + // it returns OK. Otherwise, it returns an error value. + status_t postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &msg); + + // END --- methods used only by AMessage + bool loop(); DISALLOW_EVIL_CONSTRUCTORS(ALooper); diff --git a/include/media/stagefright/foundation/ALooperRoster.h b/include/media/stagefright/foundation/ALooperRoster.h index 96bce6b..9912455 100644 --- a/include/media/stagefright/foundation/ALooperRoster.h +++ b/include/media/stagefright/foundation/ALooperRoster.h @@ -33,11 +33,6 @@ struct ALooperRoster { void unregisterHandler(ALooper::handler_id handlerID); void unregisterStaleHandlers(); - status_t postAndAwaitResponse( - const sp<AMessage> &msg, sp<AMessage> *response); - - void postReply(uint32_t replyID, const sp<AMessage> &reply); - void dump(int fd, const Vector<String16>& args); private: @@ -49,10 +44,6 @@ private: Mutex mLock; KeyedVector<ALooper::handler_id, HandlerInfo> mHandlers; ALooper::handler_id mNextHandlerID; - uint32_t mNextReplyID; - Condition mRepliesCondition; - - KeyedVector<uint32_t, sp<AMessage> > mReplies; DISALLOW_EVIL_CONSTRUCTORS(ALooperRoster); }; diff --git a/include/media/stagefright/foundation/AMessage.h b/include/media/stagefright/foundation/AMessage.h index ab3279d..4c6bd21 100644 --- a/include/media/stagefright/foundation/AMessage.h +++ b/include/media/stagefright/foundation/AMessage.h @@ -30,6 +30,34 @@ struct AHandler; struct AString; struct Parcel; +struct AReplyToken : public RefBase { + AReplyToken(const sp<ALooper> &looper) + : mLooper(looper), + mReplied(false) { + } + +private: + friend struct AMessage; + friend struct ALooper; + wp<ALooper> mLooper; + sp<AMessage> mReply; + bool mReplied; + + sp<ALooper> getLooper() const { + return mLooper.promote(); + } + // if reply is not set, returns false; otherwise, it retrieves the reply and returns true + bool retrieveReply(sp<AMessage> *reply) { + if (mReplied) { + *reply = mReply; + mReply.clear(); + } + return mReplied; + } + // sets the reply for this token. returns OK or error + status_t setReply(const sp<AMessage> &reply); +}; + struct AMessage : public RefBase { AMessage(); AMessage(uint32_t what, const sp<const AHandler> &handler); @@ -84,11 +112,15 @@ struct AMessage : public RefBase { status_t postAndAwaitResponse(sp<AMessage> *response); // If this returns true, the sender of this message is synchronously - // awaiting a response, the "replyID" can be used to send the response - // via "postReply" below. - bool senderAwaitsResponse(uint32_t *replyID) const; - - void postReply(uint32_t replyID); + // awaiting a response and the reply token is consumed from the message + // and stored into replyID. The reply token must be used to send the response + // using "postReply" below. + bool senderAwaitsResponse(sp<AReplyToken> *replyID); + + // Posts the message as a response to a reply token. A reply token can + // only be used once. Returns OK if the response could be posted; otherwise, + // an error. + status_t postReply(const sp<AReplyToken> &replyID); // Performs a deep-copy of "this", contained messages are in turn "dup'ed". // Warning: RefBase items, i.e. "objects" are _not_ copied but only have diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 1d5fc95..c775e7b 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -299,6 +299,9 @@ status_t AudioTrack::set( ALOGV("Building AudioTrack with attributes: usage=%d content=%d flags=0x%x tags=[%s]", mAttributes.usage, mAttributes.content_type, mAttributes.flags, mAttributes.tags); mStreamType = AUDIO_STREAM_DEFAULT; + if ((mAttributes.flags & AUDIO_FLAG_HW_AV_SYNC) != 0) { + flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC); + } } // these below should probably come from the audioFlinger too... @@ -1002,7 +1005,9 @@ status_t AudioTrack::createTrack_l() // use case 1: shared buffer (mSharedBuffer != 0) || // use case 2: callback transfer mode - (mTransfer == TRANSFER_CALLBACK)) && + (mTransfer == TRANSFER_CALLBACK) || + // use case 3: obtain/release mode + (mTransfer == TRANSFER_OBTAIN)) && // matching sample rate (mSampleRate == afSampleRate))) { ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client"); @@ -1236,7 +1241,7 @@ release: return status; } -status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) +status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount, size_t *nonContig) { if (audioBuffer == NULL) { return BAD_VALUE; @@ -1263,7 +1268,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) ALOGE("%s invalid waitCount %d", __func__, waitCount); requested = NULL; } - return obtainBuffer(audioBuffer, requested); + return obtainBuffer(audioBuffer, requested, NULL /*elapsed*/, nonContig); } status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, const struct timespec *requested, @@ -1338,8 +1343,9 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, const struct timespec *re return status; } -void AudioTrack::releaseBuffer(Buffer* audioBuffer) +void AudioTrack::releaseBuffer(const Buffer* audioBuffer) { + // FIXME add error checking on mode, by adding an internal version if (mTransfer == TRANSFER_SHARED) { return; } diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp index 73f1a2a..d4f6fab 100644 --- a/media/libmediaplayerservice/Drm.cpp +++ b/media/libmediaplayerservice/Drm.cpp @@ -23,6 +23,8 @@ #include "Drm.h" +#include "DrmSessionClientInterface.h" +#include "DrmSessionManager.h" #include <media/drm/DrmAPI.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AString.h> @@ -33,6 +35,10 @@ namespace android { +static inline int getCallingPid() { + return IPCThreadState::self()->getCallingPid(); +} + static bool checkPermission(const char* permissionString) { #ifndef HAVE_ANDROID_OS return true; @@ -57,14 +63,41 @@ static bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) { return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0; } +struct DrmSessionClient : public DrmSessionClientInterface { + DrmSessionClient(Drm* drm) : mDrm(drm) {} + + virtual bool reclaimSession(const Vector<uint8_t>& sessionId) { + sp<Drm> drm = mDrm.promote(); + if (drm == NULL) { + return true; + } + status_t err = drm->closeSession(sessionId); + if (err != OK) { + return false; + } + drm->sendEvent(DrmPlugin::kDrmPluginEventSessionReclaimed, 0, &sessionId, NULL); + return true; + } + +protected: + virtual ~DrmSessionClient() {} + +private: + wp<Drm> mDrm; + + DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient); +}; + Drm::Drm() : mInitCheck(NO_INIT), + mDrmSessionClient(new DrmSessionClient(this)), mListener(NULL), mFactory(NULL), mPlugin(NULL) { } Drm::~Drm() { + DrmSessionManager::Instance()->removeDrm(mDrmSessionClient); delete mPlugin; mPlugin = NULL; closeFactory(); @@ -289,7 +322,18 @@ status_t Drm::openSession(Vector<uint8_t> &sessionId) { return -EINVAL; } - return mPlugin->openSession(sessionId); + status_t err = mPlugin->openSession(sessionId); + if (err == ERROR_DRM_RESOURCE_BUSY) { + bool retry = false; + retry = DrmSessionManager::Instance()->reclaimSession(getCallingPid()); + if (retry) { + err = mPlugin->openSession(sessionId); + } + } + if (err == OK) { + DrmSessionManager::Instance()->addSession(getCallingPid(), mDrmSessionClient, sessionId); + } + return err; } status_t Drm::closeSession(Vector<uint8_t> const &sessionId) { @@ -303,7 +347,11 @@ status_t Drm::closeSession(Vector<uint8_t> const &sessionId) { return -EINVAL; } - return mPlugin->closeSession(sessionId); + status_t err = mPlugin->closeSession(sessionId); + if (err == OK) { + DrmSessionManager::Instance()->removeSession(sessionId); + } + return err; } status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId, @@ -321,6 +369,8 @@ status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType, optionalParameters, request, defaultUrl); } @@ -338,6 +388,8 @@ status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->provideKeyResponse(sessionId, response, keySetId); } @@ -367,6 +419,8 @@ status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->restoreKeys(sessionId, keySetId); } @@ -382,6 +436,8 @@ status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->queryKeyStatus(sessionId, infoMap); } @@ -561,6 +617,8 @@ status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->setCipherAlgorithm(sessionId, algorithm); } @@ -576,6 +634,8 @@ status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->setMacAlgorithm(sessionId, algorithm); } @@ -594,6 +654,8 @@ status_t Drm::encrypt(Vector<uint8_t> const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->encrypt(sessionId, keyId, input, iv, output); } @@ -612,6 +674,8 @@ status_t Drm::decrypt(Vector<uint8_t> const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->decrypt(sessionId, keyId, input, iv, output); } @@ -629,6 +693,8 @@ status_t Drm::sign(Vector<uint8_t> const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->sign(sessionId, keyId, message, signature); } @@ -647,6 +713,8 @@ status_t Drm::verify(Vector<uint8_t> const &sessionId, return -EINVAL; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->verify(sessionId, keyId, message, signature, match); } @@ -669,6 +737,8 @@ status_t Drm::signRSA(Vector<uint8_t> const &sessionId, return -EPERM; } + DrmSessionManager::Instance()->useSession(sessionId); + return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature); } diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h index 0e1eb2c..0cea639 100644 --- a/media/libmediaplayerservice/Drm.h +++ b/media/libmediaplayerservice/Drm.h @@ -28,6 +28,7 @@ namespace android { struct DrmFactory; struct DrmPlugin; +struct DrmSessionClientInterface; struct Drm : public BnDrm, public IBinder::DeathRecipient, @@ -138,6 +139,8 @@ private: status_t mInitCheck; + sp<DrmSessionClientInterface> mDrmSessionClient; + sp<IDrmClient> mListener; mutable Mutex mEventLock; mutable Mutex mNotifyLock; diff --git a/media/libmediaplayerservice/DrmSessionManager.cpp b/media/libmediaplayerservice/DrmSessionManager.cpp index 43346e0..6e17eb1 100644 --- a/media/libmediaplayerservice/DrmSessionManager.cpp +++ b/media/libmediaplayerservice/DrmSessionManager.cpp @@ -23,6 +23,8 @@ #include "DrmSessionClientInterface.h" #include "ProcessInfoInterface.h" #include <binder/IPCThreadState.h> +#include <binder/IProcessInfoService.h> +#include <binder/IServiceManager.h> #include <unistd.h> #include <utils/String8.h> @@ -39,12 +41,25 @@ static String8 GetSessionIdString(const Vector<uint8_t> &sessionId) { struct ProcessInfo : public ProcessInfoInterface { ProcessInfo() {} - virtual int getPriority(int pid) { - // TODO: implement - // Get process state to determine priority. - // According to the define of PROCESS_STATE_***, higher the value lower - // the priority. So we will do a converting from state to priority here. - return -1; + virtual bool getPriority(int pid, int* priority) { + sp<IBinder> binder = defaultServiceManager()->getService(String16("processinfo")); + sp<IProcessInfoService> service = interface_cast<IProcessInfoService>(binder); + + size_t length = 1; + int32_t states; + status_t err = service->getProcessStatesFromPids(length, &pid, &states); + if (err != OK) { + ALOGE("getProcessStatesFromPids failed"); + return false; + } + ALOGV("pid %d states %d", pid, states); + if (states < 0) { + return false; + } + + // Use process state as the priority. Lower the value, higher the priority. + *priority = states; + return true; } protected: @@ -66,6 +81,11 @@ bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> & return true; } +sp<DrmSessionManager> DrmSessionManager::Instance() { + static sp<DrmSessionManager> drmSessionManager = new DrmSessionManager(); + return drmSessionManager; +} + DrmSessionManager::DrmSessionManager() : mProcessInfo(new ProcessInfo()), mTime(0) {} @@ -155,15 +175,18 @@ bool DrmSessionManager::reclaimSession(int callingPid) { sp<DrmSessionClientInterface> drm; Vector<uint8_t> sessionId; + int lowestPriorityPid; + int lowestPriority; { Mutex::Autolock lock(mLock); - int callingPriority = mProcessInfo->getPriority(callingPid); - int lowestPriorityPid; - int lowestPriority; + int callingPriority; + if (!mProcessInfo->getPriority(callingPid, &callingPriority)) { + return false; + } if (!getLowestPriority_l(&lowestPriorityPid, &lowestPriority)) { return false; } - if (lowestPriority >= callingPriority) { + if (lowestPriority <= callingPriority) { return false; } @@ -176,6 +199,9 @@ bool DrmSessionManager::reclaimSession(int callingPid) { return false; } + ALOGV("reclaim session(%s) opened by pid %d", + GetSessionIdString(sessionId).string(), lowestPriorityPid); + return drm->reclaimSession(sessionId); } @@ -185,19 +211,23 @@ int64_t DrmSessionManager::getTime_l() { bool DrmSessionManager::getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority) { int pid = -1; - int priority = INT_MAX; + int priority = -1; for (size_t i = 0; i < mSessionMap.size(); ++i) { if (mSessionMap.valueAt(i).size() == 0) { // no opened session by this process. continue; } int tempPid = mSessionMap.keyAt(i); - int tempPriority = mProcessInfo->getPriority(tempPid); + int tempPriority; + if (!mProcessInfo->getPriority(tempPid, &tempPriority)) { + // shouldn't happen. + return false; + } if (pid == -1) { pid = tempPid; priority = tempPriority; } else { - if (tempPriority < priority) { + if (tempPriority > priority) { pid = tempPid; priority = tempPriority; } diff --git a/media/libmediaplayerservice/DrmSessionManager.h b/media/libmediaplayerservice/DrmSessionManager.h index 1d0ed43..ba5c268 100644 --- a/media/libmediaplayerservice/DrmSessionManager.h +++ b/media/libmediaplayerservice/DrmSessionManager.h @@ -42,6 +42,8 @@ typedef Vector<SessionInfo > SessionInfos; typedef KeyedVector<int, SessionInfos > PidSessionInfosMap; struct DrmSessionManager : public RefBase { + static sp<DrmSessionManager> Instance(); + DrmSessionManager(); DrmSessionManager(sp<ProcessInfoInterface> processInfo); diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 5e5d099..f113e21 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -290,8 +290,9 @@ MediaPlayerService::MediaPlayerService() const sp<IServiceManager> sm(defaultServiceManager()); if (sm != NULL) { const String16 name("batterystats"); + // use checkService() to avoid blocking if service is not up yet sp<IBatteryStats> batteryStats = - interface_cast<IBatteryStats>(sm->getService(name)); + interface_cast<IBatteryStats>(sm->checkService(name)); if (batteryStats != NULL) { batteryStats->noteResetVideo(); batteryStats->noteResetAudio(); @@ -441,6 +442,9 @@ status_t MediaPlayerService::dump(int fd, const Vector<String16>& args) const size_t SIZE = 256; char buffer[SIZE]; String8 result; + SortedVector< sp<Client> > clients; //to serialise the mutex unlock & client destruction. + SortedVector< sp<MediaRecorderClient> > mediaRecorderClients; + if (checkCallingPermission(String16("android.permission.DUMP")) == false) { snprintf(buffer, SIZE, "Permission Denial: " "can't dump MediaPlayerService from pid=%d, uid=%d\n", @@ -452,6 +456,7 @@ status_t MediaPlayerService::dump(int fd, const Vector<String16>& args) for (int i = 0, n = mClients.size(); i < n; ++i) { sp<Client> c = mClients[i].promote(); if (c != 0) c->dump(fd, args); + clients.add(c); } if (mMediaRecorderClients.size() == 0) { result.append(" No media recorder client\n\n"); @@ -464,6 +469,7 @@ status_t MediaPlayerService::dump(int fd, const Vector<String16>& args) write(fd, result.string(), result.size()); result = "\n"; c->dump(fd, args); + mediaRecorderClients.add(c); } } } diff --git a/media/libmediaplayerservice/ProcessInfoInterface.h b/media/libmediaplayerservice/ProcessInfoInterface.h index bdcc1da..222f92d 100644 --- a/media/libmediaplayerservice/ProcessInfoInterface.h +++ b/media/libmediaplayerservice/ProcessInfoInterface.h @@ -22,7 +22,7 @@ namespace android { struct ProcessInfoInterface : public RefBase { - virtual int getPriority(int pid) = 0; + virtual bool getPriority(int pid, int* priority) = 0; protected: virtual ~ProcessInfoInterface() {} diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk index e2c72ed..6609874 100644 --- a/media/libmediaplayerservice/nuplayer/Android.mk +++ b/media/libmediaplayerservice/nuplayer/Android.mk @@ -4,7 +4,6 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ GenericSource.cpp \ HTTPLiveSource.cpp \ - MediaClock.cpp \ NuPlayer.cpp \ NuPlayerCCDecoder.cpp \ NuPlayerDecoder.cpp \ diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 24163e8..a040343 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -65,12 +65,12 @@ NuPlayer::GenericSource::GenericSource( mUID(uid), mFd(-1), mDrmManagerClient(NULL), - mMetaDataSize(-1ll), mBitrate(-1ll), mPollBufferingGeneration(0), mPendingReadBufferTypes(0), mBuffering(false), - mPrepareBuffering(false) { + mPrepareBuffering(false), + mPrevBufferPercentage(-1) { resetDataSource(); DataSource::RegisterDefaultSniffers(); } @@ -147,14 +147,11 @@ status_t NuPlayer::GenericSource::initFromDataSource() { return UNKNOWN_ERROR; } } else if (mIsStreaming) { - if (mSniffedMIME.empty()) { - if (!mDataSource->sniff(&mimeType, &confidence, &dummy)) { - return UNKNOWN_ERROR; - } - mSniffedMIME = mimeType.string(); + if (!mDataSource->sniff(&mimeType, &confidence, &dummy)) { + return UNKNOWN_ERROR; } isWidevineStreaming = !strcasecmp( - mSniffedMIME.c_str(), MEDIA_MIMETYPE_CONTAINER_WVM); + mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM); } if (isWidevineStreaming) { @@ -169,7 +166,7 @@ status_t NuPlayer::GenericSource::initFromDataSource() { extractor = mWVMExtractor; } else { extractor = MediaExtractor::Create(mDataSource, - mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str()); + mimeType.isEmpty() ? NULL : mimeType.string()); } if (extractor == NULL) { @@ -347,6 +344,7 @@ void NuPlayer::GenericSource::onPrepareAsync() { if (!mUri.empty()) { const char* uri = mUri.c_str(); + String8 contentType; mIsWidevine = !strncasecmp(uri, "widevine://", 11); if (!strncasecmp("http://", uri, 7) @@ -361,7 +359,7 @@ void NuPlayer::GenericSource::onPrepareAsync() { } mDataSource = DataSource::CreateFromURI( - mHTTPService, uri, &mUriHeaders, &mContentType, + mHTTPService, uri, &mUriHeaders, &contentType, static_cast<HTTPBase *>(mHttpSource.get())); } else { mIsWidevine = false; @@ -389,20 +387,8 @@ void NuPlayer::GenericSource::onPrepareAsync() { mIsStreaming = (mIsWidevine || mCachedSource != NULL); } - // check initial caching status - status_t err = prefillCacheIfNecessary(); - if (err != OK) { - if (err == -EAGAIN) { - (new AMessage(kWhatPrepareAsync, this))->post(200000); - } else { - ALOGE("Failed to prefill data cache!"); - notifyPreparedAndCleanup(UNKNOWN_ERROR); - } - return; - } - - // init extrator from data source - err = initFromDataSource(); + // init extractor from data source + status_t err = initFromDataSource(); if (err != OK) { ALOGE("Failed to init from data source!"); @@ -441,9 +427,6 @@ void NuPlayer::GenericSource::onPrepareAsync() { void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) { if (err != OK) { - mMetaDataSize = -1ll; - mContentType = ""; - mSniffedMIME = ""; mDataSource.clear(); mCachedSource.clear(); mHttpSource.clear(); @@ -453,76 +436,6 @@ void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) { notifyPrepared(err); } -status_t NuPlayer::GenericSource::prefillCacheIfNecessary() { - CHECK(mDataSource != NULL); - - if (mCachedSource == NULL) { - // no prefill if the data source is not cached - return OK; - } - - // We're not doing this for streams that appear to be audio-only - // streams to ensure that even low bandwidth streams start - // playing back fairly instantly. - if (!strncasecmp(mContentType.string(), "audio/", 6)) { - return OK; - } - - // We're going to prefill the cache before trying to instantiate - // the extractor below, as the latter is an operation that otherwise - // could block on the datasource for a significant amount of time. - // During that time we'd be unable to abort the preparation phase - // without this prefill. - - // Initially make sure we have at least 192 KB for the sniff - // to complete without blocking. - static const size_t kMinBytesForSniffing = 192 * 1024; - static const size_t kDefaultMetaSize = 200000; - - status_t finalStatus; - - size_t cachedDataRemaining = - mCachedSource->approxDataRemaining(&finalStatus); - - if (finalStatus != OK || (mMetaDataSize >= 0 - && (off64_t)cachedDataRemaining >= mMetaDataSize)) { - ALOGV("stop caching, status %d, " - "metaDataSize %lld, cachedDataRemaining %zu", - finalStatus, mMetaDataSize, cachedDataRemaining); - return OK; - } - - ALOGV("now cached %zu bytes of data", cachedDataRemaining); - - if (mMetaDataSize < 0 - && cachedDataRemaining >= kMinBytesForSniffing) { - String8 tmp; - float confidence; - sp<AMessage> meta; - if (!mCachedSource->sniff(&tmp, &confidence, &meta)) { - return UNKNOWN_ERROR; - } - - // We successfully identified the file's extractor to - // be, remember this mime type so we don't have to - // sniff it again when we call MediaExtractor::Create() - mSniffedMIME = tmp.string(); - - if (meta == NULL - || !meta->findInt64("meta-data-size", - reinterpret_cast<int64_t*>(&mMetaDataSize))) { - mMetaDataSize = kDefaultMetaSize; - } - - if (mMetaDataSize < 0ll) { - ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize); - return UNKNOWN_ERROR; - } - } - - return -EAGAIN; -} - void NuPlayer::GenericSource::start() { ALOGI("start"); @@ -599,6 +512,7 @@ void NuPlayer::GenericSource::schedulePollBuffering() { void NuPlayer::GenericSource::cancelPollBuffering() { mBuffering = false; ++mPollBufferingGeneration; + mPrevBufferPercentage = -1; } void NuPlayer::GenericSource::restartPollBuffering() { @@ -608,7 +522,19 @@ void NuPlayer::GenericSource::restartPollBuffering() { } } -void NuPlayer::GenericSource::notifyBufferingUpdate(int percentage) { +void NuPlayer::GenericSource::notifyBufferingUpdate(int32_t percentage) { + // Buffering percent could go backward as it's estimated from remaining + // data and last access time. This could cause the buffering position + // drawn on media control to jitter slightly. Remember previously reported + // percentage and don't allow it to go backward. + if (percentage < mPrevBufferPercentage) { + percentage = mPrevBufferPercentage; + } else if (percentage > 100) { + percentage = 100; + } + + mPrevBufferPercentage = percentage; + ALOGV("notifyBufferingUpdate: buffering %d%%", percentage); sp<AMessage> msg = dupNotify(); @@ -888,7 +814,7 @@ void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) { mVideoTrack.mPackets->clear(); } sp<AMessage> response = new AMessage; - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); response->postReply(replyID); break; @@ -990,7 +916,7 @@ void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const { sp<MetaData> format = doGetFormatMeta(audio); response->setPointer("format", format.get()); - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); response->postReply(replyID); } @@ -1153,7 +1079,7 @@ void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const { ssize_t index = doGetSelectedTrack(type); response->setInt32("index", index); - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); response->postReply(replyID); } @@ -1211,7 +1137,7 @@ void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) { status_t err = doSelectTrack(trackIndex, select, timeUs); response->setInt32("err", err); - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); response->postReply(replyID); } @@ -1324,7 +1250,7 @@ void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) { status_t err = doSeek(seekTimeUs); response->setInt32("err", err); - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); response->postReply(replyID); } diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 385d73a..5fc41ec 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -139,14 +139,13 @@ private: sp<DecryptHandle> mDecryptHandle; bool mStarted; bool mStopRead; - String8 mContentType; - AString mSniffedMIME; - off64_t mMetaDataSize; int64_t mBitrate; int32_t mPollBufferingGeneration; uint32_t mPendingReadBufferTypes; bool mBuffering; bool mPrepareBuffering; + int32_t mPrevBufferPercentage; + mutable Mutex mReadBufferLock; sp<ALooper> mLooper; @@ -158,8 +157,6 @@ private: int64_t getLastReadPosition(); void setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position); - status_t prefillCacheIfNecessary(); - void notifyPreparedAndCleanup(status_t err); void onGetFormatMeta(sp<AMessage> msg) const; @@ -200,7 +197,7 @@ private: void cancelPollBuffering(); void restartPollBuffering(); void onPollBuffering(); - void notifyBufferingUpdate(int percentage); + void notifyBufferingUpdate(int32_t percentage); void startBufferingIfNecessary(); void stopBufferingIfNecessary(); void sendCacheStats(); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 007fbb9..f4d3794 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -408,7 +408,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { case kWhatGetTrackInfo: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); Parcel* reply; @@ -461,7 +461,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { sp<AMessage> response = new AMessage; response->setInt32("err", err); - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); response->postReply(replyID); break; @@ -469,7 +469,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { case kWhatSelectTrack: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); size_t trackIndex; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 8e59b75..04ac699 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -56,6 +56,7 @@ NuPlayer::Decoder::Decoder( mIsVideoAVC(false), mIsSecure(false), mFormatChangePending(false), + mTimeChangePending(false), mPaused(true), mResumePending(false), mComponentName("decoder") { @@ -121,6 +122,7 @@ void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) { CHECK(mCodec == NULL); mFormatChangePending = false; + mTimeChangePending = false; ++mBufferGeneration; @@ -235,7 +237,7 @@ void NuPlayer::Decoder::onResume(bool notifyComplete) { } } -void NuPlayer::Decoder::onFlush(bool notifyComplete) { +void NuPlayer::Decoder::doFlush(bool notifyComplete) { if (mCCDecoder != NULL) { mCCDecoder->flush(); } @@ -259,13 +261,22 @@ void NuPlayer::Decoder::onFlush(bool notifyComplete) { // we attempt to release the buffers even if flush fails. } releaseAndResetMediaBuffers(); +} - if (notifyComplete) { - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", kWhatFlushCompleted); - notify->post(); - mPaused = true; +void NuPlayer::Decoder::onFlush() { + doFlush(true); + + if (isDiscontinuityPending()) { + // This could happen if the client starts seeking/shutdown + // after we queued an EOS for discontinuities. + // We can consider discontinuity handled. + finishHandleDiscontinuity(false /* flushOnTimeChange */); } + + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kWhatFlushCompleted); + notify->post(); + mPaused = true; } void NuPlayer::Decoder::onShutdown(bool notifyComplete) { @@ -309,16 +320,17 @@ void NuPlayer::Decoder::onShutdown(bool notifyComplete) { } void NuPlayer::Decoder::doRequestBuffers() { - if (mFormatChangePending) { + if (isDiscontinuityPending()) { return; } status_t err = OK; - while (!mDequeuedInputBuffers.empty()) { + while (err == OK && !mDequeuedInputBuffers.empty()) { size_t bufferIx = *mDequeuedInputBuffers.begin(); sp<AMessage> msg = new AMessage(); msg->setSize("buffer-ix", bufferIx); err = fetchInputData(msg); - if (err != OK) { + if (err != OK && err != ERROR_END_OF_STREAM) { + // if EOS, need to queue EOS buffer break; } mDequeuedInputBuffers.erase(mDequeuedInputBuffers.begin()); @@ -336,7 +348,7 @@ void NuPlayer::Decoder::doRequestBuffers() { } bool NuPlayer::Decoder::handleAnInputBuffer() { - if (mFormatChangePending) { + if (isDiscontinuityPending()) { return false; } size_t bufferIx = -1; @@ -391,9 +403,6 @@ bool NuPlayer::Decoder::handleAnInputBuffer() { } bool NuPlayer::Decoder::handleAnOutputBuffer() { - if (mFormatChangePending) { - return false; - } size_t bufferIx = -1; size_t offset; size_t size; @@ -474,17 +483,20 @@ bool NuPlayer::Decoder::handleAnOutputBuffer() { buffer->setRange(offset, size); buffer->meta()->clear(); buffer->meta()->setInt64("timeUs", timeUs); - if (flags & MediaCodec::BUFFER_FLAG_EOS) { - buffer->meta()->setInt32("eos", true); - notifyResumeCompleteIfNecessary(); - } + + bool eos = flags & MediaCodec::BUFFER_FLAG_EOS; // we do not expect CODECCONFIG or SYNCFRAME for decoder sp<AMessage> reply = new AMessage(kWhatRenderBuffer, this); reply->setSize("buffer-ix", bufferIx); reply->setInt32("generation", mBufferGeneration); - if (mSkipRenderingUntilMediaTimeUs >= 0) { + if (eos) { + ALOGI("[%s] saw output EOS", mIsAudio ? "audio" : "video"); + + buffer->meta()->setInt32("eos", true); + reply->setInt32("eos", true); + } else if (mSkipRenderingUntilMediaTimeUs >= 0) { if (timeUs < mSkipRenderingUntilMediaTimeUs) { ALOGV("[%s] dropping buffer at time %lld as requested.", mComponentName.c_str(), (long long)timeUs); @@ -502,7 +514,7 @@ bool NuPlayer::Decoder::handleAnOutputBuffer() { if (mRenderer != NULL) { // send the buffer to renderer. mRenderer->queueBuffer(mIsAudio, buffer, reply); - if (flags & MediaCodec::BUFFER_FLAG_EOS) { + if (eos && !isDiscontinuityPending()) { mRenderer->queueEOS(mIsAudio, ERROR_END_OF_STREAM); } } @@ -533,9 +545,6 @@ void NuPlayer::Decoder::releaseAndResetMediaBuffers() { } void NuPlayer::Decoder::requestCodecNotification() { - if (mFormatChangePending) { - return; - } if (mCodec != NULL) { sp<AMessage> reply = new AMessage(kWhatCodecNotify, this); reply->setInt32("generation", mBufferGeneration); @@ -582,39 +591,31 @@ status_t NuPlayer::Decoder::fetchInputData(sp<AMessage> &reply) { formatChange = !seamlessFormatChange; } - if (formatChange || timeChange) { - sp<AMessage> msg = mNotify->dup(); - msg->setInt32("what", kWhatInputDiscontinuity); - msg->setInt32("formatChange", formatChange); - msg->post(); - } - + // For format or time change, return EOS to queue EOS input, + // then wait for EOS on output. if (formatChange /* not seamless */) { - // must change decoder - // return EOS and wait to be killed mFormatChangePending = true; - return ERROR_END_OF_STREAM; + err = ERROR_END_OF_STREAM; } else if (timeChange) { - // need to flush - // TODO: Ideally we shouldn't need a flush upon time - // discontinuity, flushing will cause loss of frames. - // We probably should queue a time change marker to the - // output queue, and handles it in renderer instead. rememberCodecSpecificData(newFormat); - onFlush(false /* notifyComplete */); - err = OK; + mTimeChangePending = true; + err = ERROR_END_OF_STREAM; } else if (seamlessFormatChange) { // reuse existing decoder and don't flush rememberCodecSpecificData(newFormat); - err = OK; + continue; } else { // This stream is unaffected by the discontinuity return -EWOULDBLOCK; } } + // reply should only be returned without a buffer set + // when there is an error (including EOS) + CHECK(err != OK); + reply->setInt32("err", err); - return OK; + return ERROR_END_OF_STREAM; } if (!mIsAudio) { @@ -636,7 +637,7 @@ status_t NuPlayer::Decoder::fetchInputData(sp<AMessage> &reply) { #if 0 int64_t mediaTimeUs; CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs)); - ALOGV("feeding %s input buffer at media time %.2f secs", + ALOGV("[%s] feeding input buffer at media time %" PRId64, mIsAudio ? "audio" : "video", mediaTimeUs / 1E6); #endif @@ -696,10 +697,7 @@ bool NuPlayer::Decoder::onInputBufferFetched(const sp<AMessage> &msg) { int32_t streamErr = ERROR_END_OF_STREAM; CHECK(msg->findInt32("err", &streamErr) || !hasBuffer); - if (streamErr == OK) { - /* buffers are returned to hold on to */ - return true; - } + CHECK(streamErr != OK); // attempt to queue EOS status_t err = mCodec->queueInputBuffer( @@ -781,6 +779,7 @@ void NuPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) { status_t err; int32_t render; size_t bufferIx; + int32_t eos; CHECK(msg->findSize("buffer-ix", &bufferIx)); if (!mIsAudio) { @@ -805,6 +804,42 @@ void NuPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) { mComponentName.c_str(), err); handleError(err); } + if (msg->findInt32("eos", &eos) && eos + && isDiscontinuityPending()) { + finishHandleDiscontinuity(true /* flushOnTimeChange */); + } +} + +bool NuPlayer::Decoder::isDiscontinuityPending() const { + return mFormatChangePending || mTimeChangePending; +} + +void NuPlayer::Decoder::finishHandleDiscontinuity(bool flushOnTimeChange) { + ALOGV("finishHandleDiscontinuity: format %d, time %d, flush %d", + mFormatChangePending, mTimeChangePending, flushOnTimeChange); + + // If we have format change, pause and wait to be killed; + // If we have time change only, flush and restart fetching. + + if (mFormatChangePending) { + mPaused = true; + } else if (mTimeChangePending) { + if (flushOnTimeChange) { + doFlush(false /*notifyComplete*/); + } + + // restart fetching input + scheduleRequestBuffers(); + } + + // Notify NuPlayer to either shutdown decoder, or rescan sources + sp<AMessage> msg = mNotify->dup(); + msg->setInt32("what", kWhatInputDiscontinuity); + msg->setInt32("formatChange", mFormatChangePending); + msg->post(); + + mFormatChangePending = false; + mTimeChangePending = false; } bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange( diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h index 1bfa94f..4aab2c6 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h @@ -43,7 +43,7 @@ protected: virtual void onSetRenderer(const sp<Renderer> &renderer); virtual void onGetInputBuffers(Vector<sp<ABuffer> > *dstBuffers); virtual void onResume(bool notifyComplete); - virtual void onFlush(bool notifyComplete); + virtual void onFlush(); virtual void onShutdown(bool notifyComplete); virtual void doRequestBuffers(); @@ -81,6 +81,7 @@ private: bool mIsVideoAVC; bool mIsSecure; bool mFormatChangePending; + bool mTimeChangePending; bool mPaused; bool mResumePending; @@ -93,6 +94,7 @@ private: void requestCodecNotification(); bool isStaleReply(const sp<AMessage> &msg); + void doFlush(bool notifyComplete); status_t fetchInputData(sp<AMessage> &reply); bool onInputBufferFetched(const sp<AMessage> &msg); void onRenderBuffer(const sp<AMessage> &msg); @@ -100,6 +102,8 @@ private: bool supportsSeamlessFormatChange(const sp<AMessage> &to) const; bool supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const; void rememberCodecSpecificData(const sp<AMessage> &format); + bool isDiscontinuityPending() const; + void finishHandleDiscontinuity(bool flushOnTimeChange); void notifyResumeCompleteIfNecessary(); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp index 72e7b0d..4636f0a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp @@ -136,7 +136,7 @@ void NuPlayer::DecoderBase::onMessageReceived(const sp<AMessage> &msg) { case kWhatGetInputBuffers: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); Vector<sp<ABuffer> > *dstBuffers; @@ -157,7 +157,7 @@ void NuPlayer::DecoderBase::onMessageReceived(const sp<AMessage> &msg) { case kWhatFlush: { - onFlush(true); + onFlush(); break; } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h index 6732ff4..97e9269 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h @@ -65,7 +65,7 @@ protected: virtual void onSetRenderer(const sp<Renderer> &renderer) = 0; virtual void onGetInputBuffers(Vector<sp<ABuffer> > *dstBuffers) = 0; virtual void onResume(bool notifyComplete) = 0; - virtual void onFlush(bool notifyComplete) = 0; + virtual void onFlush() = 0; virtual void onShutdown(bool notifyComplete) = 0; void onRequestInputBuffers(); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp index 479eba1..29b4c26 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp @@ -247,7 +247,7 @@ status_t NuPlayer::DecoderPassThrough::fetchInputData(sp<AMessage> &reply) { } if (timeChange) { - onFlush(false /* notifyComplete */); + doFlush(false /* notifyComplete */); err = OK; } else if (formatChange) { // do seamless format change @@ -364,7 +364,7 @@ void NuPlayer::DecoderPassThrough::onResume(bool notifyComplete) { } } -void NuPlayer::DecoderPassThrough::onFlush(bool notifyComplete) { +void NuPlayer::DecoderPassThrough::doFlush(bool notifyComplete) { ++mBufferGeneration; mSkipRenderingUntilMediaTimeUs = -1; mPendingAudioAccessUnit.clear(); @@ -376,18 +376,21 @@ void NuPlayer::DecoderPassThrough::onFlush(bool notifyComplete) { mRenderer->signalTimeDiscontinuity(); } - if (notifyComplete) { - mPaused = true; - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", kWhatFlushCompleted); - notify->post(); - } - mPendingBuffersToDrain = 0; mCachedBytes = 0; mReachedEOS = false; } +void NuPlayer::DecoderPassThrough::onFlush() { + doFlush(true /* notifyComplete */); + + mPaused = true; + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kWhatFlushCompleted); + notify->post(); + +} + void NuPlayer::DecoderPassThrough::onShutdown(bool notifyComplete) { ++mBufferGeneration; mSkipRenderingUntilMediaTimeUs = -1; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h index a6e1faf..173cfbd 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h @@ -43,7 +43,7 @@ protected: virtual void onSetRenderer(const sp<Renderer> &renderer); virtual void onGetInputBuffers(Vector<sp<ABuffer> > *dstBuffers); virtual void onResume(bool notifyComplete); - virtual void onFlush(bool notifyComplete); + virtual void onFlush(); virtual void onShutdown(bool notifyComplete); virtual void doRequestBuffers(); @@ -77,6 +77,7 @@ private: status_t dequeueAccessUnit(sp<ABuffer> *accessUnit); sp<ABuffer> aggregateBuffer(const sp<ABuffer> &accessUnit); status_t fetchInputData(sp<AMessage> &reply); + void doFlush(bool notifyComplete); void onInputBufferFetched(const sp<AMessage> &msg); void onBufferConsumed(int32_t size); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 337f7b1..4bccfa8 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -20,13 +20,12 @@ #include "NuPlayerRenderer.h" -#include "MediaClock.h" - #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/foundation/AUtils.h> #include <media/stagefright/foundation/AWakeLock.h> +#include <media/stagefright/MediaClock.h> #include <media/stagefright/MediaErrors.h> #include <media/stagefright/MetaData.h> #include <media/stagefright/Utils.h> @@ -265,7 +264,7 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) { response->setInt32("err", err); response->setInt32("offload", offloadingAudio()); - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); response->postReply(replyID); @@ -274,7 +273,7 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) { case kWhatCloseAudioSink: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); onCloseAudioSink(); @@ -716,6 +715,7 @@ void NuPlayer::Renderer::onNewAudioMediaTime(int64_t mediaTimeUs) { int64_t nowUs = ALooper::GetNowUs(); int64_t nowMediaUs = mediaTimeUs - getPendingAudioPlayoutDurationUs(nowUs); mMediaClock->updateAnchor(nowMediaUs, nowUs, mediaTimeUs); + mAnchorNumFramesWritten = mNumFramesWritten; mAnchorTimeMediaUs = mediaTimeUs; } diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp index 57d9ab2..5210fc8 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp @@ -311,7 +311,7 @@ void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) { void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) { if (msg->what() == kWhatDisconnect) { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); mDisconnectReplyID = replyID; diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h index ac3299a..5f2cf33 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.h +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h @@ -25,6 +25,7 @@ namespace android { struct ALooper; +struct AReplyToken; struct AnotherPacketSource; struct MyHandler; struct SDPLoader; @@ -96,7 +97,7 @@ private: bool mIsSDP; State mState; status_t mFinalResult; - uint32_t mDisconnectReplyID; + sp<AReplyToken> mDisconnectReplyID; Mutex mBufferingLock; bool mBuffering; diff --git a/media/libmediaplayerservice/tests/Android.mk b/media/libmediaplayerservice/tests/Android.mk index 69d4ad1..7bc78ff 100644 --- a/media/libmediaplayerservice/tests/Android.mk +++ b/media/libmediaplayerservice/tests/Android.mk @@ -1,7 +1,6 @@ # Build the unit tests. LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := DrmSessionManager_test @@ -19,13 +18,7 @@ LOCAL_C_INCLUDES := \ frameworks/av/include \ frameworks/av/media/libmediaplayerservice \ -include $(BUILD_NATIVE_TEST) +LOCAL_32_BIT_ONLY := true -# Include subdirectory makefiles -# ============================================================ +include $(BUILD_NATIVE_TEST) -# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework -# team really wants is to build the stuff defined by this makefile. -ifeq (,$(ONE_SHOT_MAKEFILE)) -include $(call first-makefiles-under,$(LOCAL_PATH)) -endif diff --git a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp index a199ee1..27b482b 100644 --- a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp +++ b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp @@ -32,7 +32,12 @@ struct FakeProcessInfo : public ProcessInfoInterface { FakeProcessInfo() {} virtual ~FakeProcessInfo() {} - virtual int getPriority(int pid) { return pid; } + virtual bool getPriority(int pid, int* priority) { + // For testing, use pid as priority. + // Lower the value higher the priority. + *priority = pid; + return true; + } private: DISALLOW_EVIL_CONSTRUCTORS(FakeProcessInfo); @@ -57,7 +62,7 @@ private: DISALLOW_EVIL_CONSTRUCTORS(FakeDrm); }; -static const int kTestPid1 = 10; +static const int kTestPid1 = 30; static const int kTestPid2 = 20; static const uint8_t kTestSessionId1[] = {1, 2, 3}; static const uint8_t kTestSessionId2[] = {4, 5, 6, 7, 8}; @@ -122,7 +127,9 @@ protected: EXPECT_EQ(kTestPid1, pid); FakeProcessInfo processInfo; - EXPECT_EQ(processInfo.getPriority(kTestPid1), priority); + int priority1; + processInfo.getPriority(kTestPid1, &priority1); + EXPECT_EQ(priority1, priority); } void testGetLeastUsedSession() { @@ -210,9 +217,9 @@ TEST_F(DrmSessionManagerTest, reclaimSession) { addSession(); // calling pid priority is too low - EXPECT_FALSE(mDrmSessionManager->reclaimSession(5)); + EXPECT_FALSE(mDrmSessionManager->reclaimSession(50)); - EXPECT_TRUE(mDrmSessionManager->reclaimSession(30)); + EXPECT_TRUE(mDrmSessionManager->reclaimSession(10)); EXPECT_EQ(1, mTestDrm1->reclaimedSessions().size()); EXPECT_TRUE(isEqualSessionId(mSessionId1, mTestDrm1->reclaimedSessions()[0])); @@ -220,12 +227,12 @@ TEST_F(DrmSessionManagerTest, reclaimSession) { // add a session from a higher priority process. sp<FakeDrm> drm = new FakeDrm; - const uint8_t ids[] = {456, 7890, 123}; + const uint8_t ids[] = {1, 3, 5}; Vector<uint8_t> sessionId; GetSessionId(ids, ARRAY_SIZE(ids), &sessionId); - mDrmSessionManager->addSession(30, drm, sessionId); + mDrmSessionManager->addSession(15, drm, sessionId); - EXPECT_TRUE(mDrmSessionManager->reclaimSession(40)); + EXPECT_TRUE(mDrmSessionManager->reclaimSession(18)); EXPECT_EQ(1, mTestDrm2->reclaimedSessions().size()); // mSessionId2 is reclaimed. EXPECT_TRUE(isEqualSessionId(mSessionId2, mTestDrm2->reclaimedSessions()[0])); diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 6d9bbae..38f2e34 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -31,6 +31,7 @@ LOCAL_SRC_FILES:= \ MediaAdapter.cpp \ MediaBuffer.cpp \ MediaBufferGroup.cpp \ + MediaClock.cpp \ MediaCodec.cpp \ MediaCodecList.cpp \ MediaCodecSource.cpp \ diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp index 0c2ff15..77a652a 100644 --- a/media/libstagefright/HTTPBase.cpp +++ b/media/libstagefright/HTTPBase.cpp @@ -75,7 +75,11 @@ void HTTPBase::addBandwidthMeasurement( bool HTTPBase::estimateBandwidth(int32_t *bandwidth_bps) { Mutex::Autolock autoLock(mLock); - if (mNumBandwidthHistoryItems < 2) { + // Do not do bandwidth estimation if we don't have enough samples, or + // total bytes download are too small (<64K). + // Bandwidth estimation from these samples can often shoot up and cause + // unwanted bw adaption behaviors. + if (mNumBandwidthHistoryItems < 2 || mTotalTransferBytes < 65536) { return false; } diff --git a/media/libmediaplayerservice/nuplayer/MediaClock.cpp b/media/libstagefright/MediaClock.cpp index 9152da1..38db5e4 100644 --- a/media/libmediaplayerservice/nuplayer/MediaClock.cpp +++ b/media/libstagefright/MediaClock.cpp @@ -18,7 +18,7 @@ #define LOG_TAG "MediaClock" #include <utils/Log.h> -#include "MediaClock.h" +#include <media/stagefright/MediaClock.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/ALooper.h> diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 6282813..0597f1d 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -174,7 +174,7 @@ status_t MediaCodec::PostAndAwaitResponse( } // static -void MediaCodec::PostReplyWithError(int32_t replyID, int32_t err) { +void MediaCodec::PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err) { sp<AMessage> response = new AMessage; response->setInt32("err", err); response->postReply(replyID); @@ -650,7 +650,7 @@ void MediaCodec::cancelPendingDequeueOperations() { } } -bool MediaCodec::handleDequeueInputBuffer(uint32_t replyID, bool newRequest) { +bool MediaCodec::handleDequeueInputBuffer(const sp<AReplyToken> &replyID, bool newRequest) { if (!isExecuting() || (mFlags & kFlagIsAsync) || (newRequest && (mFlags & kFlagDequeueInputPending))) { PostReplyWithError(replyID, INVALID_OPERATION); @@ -674,7 +674,7 @@ bool MediaCodec::handleDequeueInputBuffer(uint32_t replyID, bool newRequest) { return true; } -bool MediaCodec::handleDequeueOutputBuffer(uint32_t replyID, bool newRequest) { +bool MediaCodec::handleDequeueOutputBuffer(const sp<AReplyToken> &replyID, bool newRequest) { sp<AMessage> response = new AMessage; if (!isExecuting() || (mFlags & kFlagIsAsync) @@ -1198,7 +1198,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatInit: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); if (mState != UNINITIALIZED) { @@ -1234,7 +1234,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatSetCallback: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); if (mState == UNINITIALIZED @@ -1266,7 +1266,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatConfigure: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); if (mState != INITIALIZED) { @@ -1323,7 +1323,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatCreateInputSurface: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); // Must be configured, but can't have been started yet. @@ -1339,7 +1339,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatStart: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); if (mState == FLUSHED) { @@ -1365,7 +1365,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { State targetState = (msg->what() == kWhatStop) ? INITIALIZED : UNINITIALIZED; - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); if (!((mFlags & kFlagIsComponentAllocated) && targetState == UNINITIALIZED) // See 1 @@ -1413,7 +1413,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatDequeueInputBuffer: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); if (mFlags & kFlagIsAsync) { @@ -1474,7 +1474,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatQueueInputBuffer: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); if (!isExecuting()) { @@ -1493,7 +1493,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatDequeueOutputBuffer: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); if (mFlags & kFlagIsAsync) { @@ -1548,7 +1548,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatReleaseOutputBuffer: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); if (!isExecuting()) { @@ -1567,7 +1567,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatSignalEndOfInputStream: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); if (!isExecuting()) { @@ -1585,7 +1585,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatGetBuffers: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); if (!isExecuting() || (mFlags & kFlagIsAsync)) { @@ -1619,7 +1619,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatFlush: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); if (!isExecuting()) { @@ -1645,7 +1645,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { sp<AMessage> format = (msg->what() == kWhatGetOutputFormat ? mOutputFormat : mInputFormat); - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); if ((mState != CONFIGURED && mState != STARTING && @@ -1682,7 +1682,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatGetName: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); if (mComponentName.empty()) { @@ -1698,7 +1698,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case kWhatSetParameters: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); sp<AMessage> params; diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp index 1ef4170..b6fa810 100644 --- a/media/libstagefright/MediaCodecSource.cpp +++ b/media/libstagefright/MediaCodecSource.cpp @@ -182,7 +182,7 @@ void MediaCodecSource::Puller::onMessageReceived(const sp<AMessage> &msg) { sp<AMessage> response = new AMessage; response->setInt32("err", err); - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); response->postReply(replyID); break; @@ -491,7 +491,7 @@ void MediaCodecSource::signalEOS(status_t err) { if (mStopping && mEncoderReachedEOS) { ALOGI("encoder (%s) stopped", mIsVideo ? "video" : "audio"); // posting reply to everyone that's waiting - List<uint32_t>::iterator it; + List<sp<AReplyToken>>::iterator it; for (it = mStopReplyIDQueue.begin(); it != mStopReplyIDQueue.end(); it++) { (new AMessage)->postReply(*it); @@ -766,7 +766,7 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) { } case kWhatStart: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); sp<RefBase> obj; @@ -782,7 +782,7 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) { { ALOGI("encoder (%s) stopping", mIsVideo ? "video" : "audio"); - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); if (mEncoderReachedEOS) { diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp index 530383b..e8abf48 100644 --- a/media/libstagefright/SurfaceMediaSource.cpp +++ b/media/libstagefright/SurfaceMediaSource.cpp @@ -26,6 +26,7 @@ #include <media/hardware/MetadataBufferType.h> #include <ui/GraphicBuffer.h> +#include <gui/BufferItem.h> #include <gui/ISurfaceComposer.h> #include <gui/IGraphicBufferAlloc.h> #include <OMX_Component.h> @@ -290,7 +291,7 @@ status_t SurfaceMediaSource::read( // TODO: mCurrentSlot can be made a bufferstate since there // can be more than one "current" slots. - BufferQueue::BufferItem item; + BufferItem item; // If the recording has started and the queue is empty, then just // wait here till the frames come in from the client side while (mStarted) { diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp index 5ec3438..8ef2dca 100644 --- a/media/libstagefright/avc_utils.cpp +++ b/media/libstagefright/avc_utils.cpp @@ -26,6 +26,7 @@ #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MediaErrors.h> #include <media/stagefright/MetaData.h> +#include <utils/misc.h> namespace android { @@ -186,17 +187,31 @@ void FindAVCDimensions( if (aspect_ratio_idc == 255 /* extendedSAR */) { sar_width = br.getBits(16); sar_height = br.getBits(16); - } else if (aspect_ratio_idc > 0 && aspect_ratio_idc < 14) { - static const int32_t kFixedSARWidth[] = { - 1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160 + } else { + static const struct { unsigned width, height; } kFixedSARs[] = { + { 0, 0 }, // Invalid + { 1, 1 }, + { 12, 11 }, + { 10, 11 }, + { 16, 11 }, + { 40, 33 }, + { 24, 11 }, + { 20, 11 }, + { 32, 11 }, + { 80, 33 }, + { 18, 11 }, + { 15, 11 }, + { 64, 33 }, + { 160, 99 }, + { 4, 3 }, + { 3, 2 }, + { 2, 1 }, }; - static const int32_t kFixedSARHeight[] = { - 1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99 - }; - - sar_width = kFixedSARWidth[aspect_ratio_idc - 1]; - sar_height = kFixedSARHeight[aspect_ratio_idc - 1]; + if (aspect_ratio_idc > 0 && aspect_ratio_idc < NELEM(kFixedSARs)) { + sar_width = kFixedSARs[aspect_ratio_idc].width; + sar_height = kFixedSARs[aspect_ratio_idc].height; + } } } diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index 1505f08..10937ec 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -975,6 +975,7 @@ void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) { mBufferSizes.clear(); mDecodedSizes.clear(); mLastInHeader = NULL; + mEndOfInput = false; } else { int avail; while ((avail = outputDelayRingBufferSamplesAvailable()) > 0) { @@ -989,6 +990,7 @@ void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) { mOutputBufferCount++; } mOutputDelayRingBufferReadPos = mOutputDelayRingBufferWritePos; + mEndOfOutput = false; } } diff --git a/media/libstagefright/filters/GraphicBufferListener.cpp b/media/libstagefright/filters/GraphicBufferListener.cpp index fa38192..66374ba 100644 --- a/media/libstagefright/filters/GraphicBufferListener.cpp +++ b/media/libstagefright/filters/GraphicBufferListener.cpp @@ -21,6 +21,8 @@ #include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/MediaErrors.h> +#include <gui/BufferItem.h> + #include "GraphicBufferListener.h" namespace android { @@ -83,8 +85,8 @@ void GraphicBufferListener::onSidebandStreamChanged() { // nothing to do } -BufferQueue::BufferItem GraphicBufferListener::getBufferItem() { - BufferQueue::BufferItem item; +BufferItem GraphicBufferListener::getBufferItem() { + BufferItem item; { Mutex::Autolock autoLock(mMutex); @@ -124,8 +126,7 @@ BufferQueue::BufferItem GraphicBufferListener::getBufferItem() { return item; } -sp<GraphicBuffer> GraphicBufferListener::getBuffer( - BufferQueue::BufferItem item) { +sp<GraphicBuffer> GraphicBufferListener::getBuffer(BufferItem item) { sp<GraphicBuffer> buf; if (item.mBuf < 0 || item.mBuf >= BufferQueue::NUM_BUFFER_SLOTS) { ALOGE("getBuffer() received invalid BufferItem: mBuf==%d", item.mBuf); @@ -138,8 +139,7 @@ sp<GraphicBuffer> GraphicBufferListener::getBuffer( return buf; } -status_t GraphicBufferListener::releaseBuffer( - BufferQueue::BufferItem item) { +status_t GraphicBufferListener::releaseBuffer(BufferItem item) { if (item.mBuf < 0 || item.mBuf >= BufferQueue::NUM_BUFFER_SLOTS) { ALOGE("getBuffer() received invalid BufferItem: mBuf==%d", item.mBuf); return ERROR_OUT_OF_RANGE; diff --git a/media/libstagefright/filters/GraphicBufferListener.h b/media/libstagefright/filters/GraphicBufferListener.h index b3e0ee3..586bf65 100644 --- a/media/libstagefright/filters/GraphicBufferListener.h +++ b/media/libstagefright/filters/GraphicBufferListener.h @@ -41,9 +41,9 @@ public: return mProducer; } - BufferQueue::BufferItem getBufferItem(); - sp<GraphicBuffer> getBuffer(BufferQueue::BufferItem item); - status_t releaseBuffer(BufferQueue::BufferItem item); + BufferItem getBufferItem(); + sp<GraphicBuffer> getBuffer(BufferItem item); + status_t releaseBuffer(BufferItem item); enum { kWhatFrameAvailable = 'frav', diff --git a/media/libstagefright/filters/MediaFilter.cpp b/media/libstagefright/filters/MediaFilter.cpp index d2f662d..0a09575 100644 --- a/media/libstagefright/filters/MediaFilter.cpp +++ b/media/libstagefright/filters/MediaFilter.cpp @@ -31,6 +31,8 @@ #include <media/stagefright/MediaErrors.h> #include <media/stagefright/MediaFilter.h> +#include <gui/BufferItem.h> + #include "ColorConvert.h" #include "GraphicBufferListener.h" #include "IntrinsicBlurFilter.h" @@ -749,7 +751,7 @@ void MediaFilter::onCreateInputSurface() { } void MediaFilter::onInputFrameAvailable() { - BufferQueue::BufferItem item = mGraphicBufferListener->getBufferItem(); + BufferItem item = mGraphicBufferListener->getBufferItem(); sp<GraphicBuffer> buf = mGraphicBufferListener->getBuffer(item); // get pointer to graphic buffer diff --git a/media/libstagefright/foundation/ALooper.cpp b/media/libstagefright/foundation/ALooper.cpp index 617d32b..90b5f68 100644 --- a/media/libstagefright/foundation/ALooper.cpp +++ b/media/libstagefright/foundation/ALooper.cpp @@ -16,6 +16,9 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "ALooper" + +#include <media/stagefright/foundation/ADebug.h> + #include <utils/Log.h> #include <sys/time.h> @@ -220,4 +223,29 @@ bool ALooper::loop() { return true; } +// to be called by AMessage::postAndAwaitResponse only +sp<AReplyToken> ALooper::createReplyToken() { + return new AReplyToken(this); +} + +// to be called by AMessage::postAndAwaitResponse only +status_t ALooper::awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response) { + // return status in case we want to handle an interrupted wait + Mutex::Autolock autoLock(mRepliesLock); + CHECK(replyToken != NULL); + while (!replyToken->retrieveReply(response)) { + mRepliesCondition.wait(mRepliesLock); + } + return OK; +} + +status_t ALooper::postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &reply) { + Mutex::Autolock autoLock(mRepliesLock); + status_t err = replyToken->setReply(reply); + if (err == OK) { + mRepliesCondition.broadcast(); + } + return err; +} + } // namespace android diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp index c4e6788..473ce1b 100644 --- a/media/libstagefright/foundation/ALooperRoster.cpp +++ b/media/libstagefright/foundation/ALooperRoster.cpp @@ -30,8 +30,7 @@ namespace android { static bool verboseStats = false; ALooperRoster::ALooperRoster() - : mNextHandlerID(1), - mNextReplyID(1) { + : mNextHandlerID(1) { } ALooper::handler_id ALooperRoster::registerHandler( @@ -100,39 +99,6 @@ void ALooperRoster::unregisterStaleHandlers() { } } -status_t ALooperRoster::postAndAwaitResponse( - const sp<AMessage> &msg, sp<AMessage> *response) { - Mutex::Autolock autoLock(mLock); - - uint32_t replyID = mNextReplyID++; - - msg->setInt32("replyID", replyID); - - status_t err = msg->post(0 /* delayUs */); - if (err != OK) { - response->clear(); - return err; - } - - ssize_t index; - while ((index = mReplies.indexOfKey(replyID)) < 0) { - mRepliesCondition.wait(mLock); - } - - *response = mReplies.valueAt(index); - mReplies.removeItemsAt(index); - - return OK; -} - -void ALooperRoster::postReply(uint32_t replyID, const sp<AMessage> &reply) { - Mutex::Autolock autoLock(mLock); - - CHECK(mReplies.indexOfKey(replyID) < 0); - mReplies.add(replyID, reply); - mRepliesCondition.broadcast(); -} - static void makeFourCC(uint32_t fourcc, char *s) { s[0] = (fourcc >> 24) & 0xff; if (s[0]) { diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp index d4add15..e549ff6 100644 --- a/media/libstagefright/foundation/AMessage.cpp +++ b/media/libstagefright/foundation/AMessage.cpp @@ -37,6 +37,17 @@ namespace android { extern ALooperRoster gLooperRoster; +status_t AReplyToken::setReply(const sp<AMessage> &reply) { + if (mReplied) { + ALOGE("trying to post a duplicate reply"); + return -EBUSY; + } + CHECK(mReply == NULL); + mReply = reply; + mReplied = true; + return OK; +} + AMessage::AMessage(void) : mWhat(0), mTarget(0), @@ -355,24 +366,50 @@ status_t AMessage::post(int64_t delayUs) { } status_t AMessage::postAndAwaitResponse(sp<AMessage> *response) { - return gLooperRoster.postAndAwaitResponse(this, response); + sp<ALooper> looper = mLooper.promote(); + if (looper == NULL) { + ALOGW("failed to post message as target looper for handler %d is gone.", mTarget); + return -ENOENT; + } + + sp<AReplyToken> token = looper->createReplyToken(); + if (token == NULL) { + ALOGE("failed to create reply token"); + return -ENOMEM; + } + setObject("replyID", token); + + looper->post(this, 0 /* delayUs */); + return looper->awaitResponse(token, response); } -void AMessage::postReply(uint32_t replyID) { - gLooperRoster.postReply(replyID, this); +status_t AMessage::postReply(const sp<AReplyToken> &replyToken) { + if (replyToken == NULL) { + ALOGW("failed to post reply to a NULL token"); + return -ENOENT; + } + sp<ALooper> looper = replyToken->getLooper(); + if (looper == NULL) { + ALOGW("failed to post reply as target looper is gone."); + return -ENOENT; + } + return looper->postReply(replyToken, this); } -bool AMessage::senderAwaitsResponse(uint32_t *replyID) const { - int32_t tmp; - bool found = findInt32("replyID", &tmp); +bool AMessage::senderAwaitsResponse(sp<AReplyToken> *replyToken) { + sp<RefBase> tmp; + bool found = findObject("replyID", &tmp); if (!found) { return false; } - *replyID = static_cast<uint32_t>(tmp); + *replyToken = static_cast<AReplyToken *>(tmp.get()); + tmp.clear(); + setObject("replyID", tmp); + // TODO: delete Object instead of setting it to NULL - return true; + return *replyToken != NULL; } sp<AMessage> AMessage::dup() const { diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index dcac765..a8f60a8 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -49,8 +49,13 @@ namespace android { +// static // Number of recently-read bytes to use for bandwidth estimation const size_t LiveSession::kBandwidthHistoryBytes = 200 * 1024; +// High water mark to start up switch or report prepared) +const int64_t LiveSession::kHighWaterMark = 8000000ll; +const int64_t LiveSession::kMidWaterMark = 5000000ll; +const int64_t LiveSession::kLowWaterMark = 3000000ll; LiveSession::LiveSession( const sp<AMessage> ¬ify, uint32_t flags, @@ -75,14 +80,14 @@ LiveSession::LiveSession( mSeekReplyID(0), mFirstTimeUsValid(false), mFirstTimeUs(0), - mLastSeekTimeUs(0) { + mLastSeekTimeUs(0), + mPollBufferingGeneration(0) { mStreams[kAudioIndex] = StreamItem("audio"); mStreams[kVideoIndex] = StreamItem("video"); mStreams[kSubtitleIndex] = StreamItem("subtitles"); for (size_t i = 0; i < kMaxStreams; ++i) { - mDiscontinuities.add(indexToType(i), new AnotherPacketSource(NULL /* meta */)); mPacketSources.add(indexToType(i), new AnotherPacketSource(NULL /* meta */)); mPacketSources2.add(indexToType(i), new AnotherPacketSource(NULL /* meta */)); mBuffering[i] = false; @@ -97,6 +102,9 @@ LiveSession::LiveSession( } LiveSession::~LiveSession() { + if (mFetcherLooper != NULL) { + mFetcherLooper->stop(); + } } sp<ABuffer> LiveSession::createFormatChangeBuffer(bool swap) { @@ -125,24 +133,7 @@ status_t LiveSession::dequeueAccessUnit( return -EWOULDBLOCK; } - status_t finalResult; - sp<AnotherPacketSource> discontinuityQueue = mDiscontinuities.valueFor(stream); - if (discontinuityQueue->hasBufferAvailable(&finalResult)) { - discontinuityQueue->dequeueAccessUnit(accessUnit); - // seeking, track switching - sp<AMessage> extra; - int64_t timeUs; - if ((*accessUnit)->meta()->findMessage("extra", &extra) - && extra != NULL - && extra->findInt64("timeUs", &timeUs)) { - // seeking only - mLastSeekTimeUs = timeUs; - mDiscontinuityOffsetTimesUs.clear(); - mDiscontinuityAbsStartTimesUs.clear(); - } - return INFO_DISCONTINUITY; - } - + status_t finalResult = OK; sp<AnotherPacketSource> packetSource = mPacketSources.valueFor(stream); ssize_t idx = typeToIndex(stream); @@ -172,7 +163,7 @@ status_t LiveSession::dequeueAccessUnit( if (mBuffering[idx]) { if (mSwitchInProgress || packetSource->isFinished(0) - || packetSource->getEstimatedDurationUs() > targetDurationUs) { + || packetSource->hasBufferAvailable(&finalResult)) { mBuffering[idx] = false; } } @@ -402,7 +393,7 @@ void LiveSession::onMessageReceived(const sp<AMessage> &msg) { case kWhatSeek: { - uint32_t seekReplyID; + sp<AReplyToken> seekReplyID; CHECK(msg->senderAwaitsResponse(&seekReplyID)); mSeekReplyID = seekReplyID; mSeekReply = new AMessage; @@ -429,11 +420,16 @@ void LiveSession::onMessageReceived(const sp<AMessage> &msg) { if (what == PlaylistFetcher::kWhatStopped) { AString uri; CHECK(msg->findString("uri", &uri)); - if (mFetcherInfos.removeItem(uri) < 0) { + ssize_t index = mFetcherInfos.indexOfKey(uri); + if (index < 0) { // ignore duplicated kWhatStopped messages. break; } + mFetcherLooper->unregisterHandler( + mFetcherInfos[index].mFetcher->id()); + mFetcherInfos.removeItemsAt(index); + if (mSwitchInProgress) { tryToFinishBandwidthSwitch(); } @@ -443,14 +439,6 @@ void LiveSession::onMessageReceived(const sp<AMessage> &msg) { CHECK_GT(mContinuationCounter, 0); if (--mContinuationCounter == 0) { mContinuation->post(); - - if (mSeekReplyID != 0) { - CHECK(mSeekReply != NULL); - mSeekReply->setInt32("err", OK); - mSeekReply->postReply(mSeekReplyID); - mSeekReplyID = 0; - mSeekReply.clear(); - } } } break; @@ -464,8 +452,11 @@ void LiveSession::onMessageReceived(const sp<AMessage> &msg) { int64_t durationUs; CHECK(msg->findInt64("durationUs", &durationUs)); - FetcherInfo *info = &mFetcherInfos.editValueFor(uri); - info->mDurationUs = durationUs; + ssize_t index = mFetcherInfos.indexOfKey(uri); + if (index >= 0) { + FetcherInfo *info = &mFetcherInfos.editValueFor(uri); + info->mDurationUs = durationUs; + } break; } @@ -513,34 +504,6 @@ void LiveSession::onMessageReceived(const sp<AMessage> &msg) { break; } - case PlaylistFetcher::kWhatTemporarilyDoneFetching: - { - AString uri; - CHECK(msg->findString("uri", &uri)); - - if (mFetcherInfos.indexOfKey(uri) < 0) { - ALOGE("couldn't find uri"); - break; - } - FetcherInfo *info = &mFetcherInfos.editValueFor(uri); - info->mIsPrepared = true; - - if (mInPreparationPhase) { - bool allFetchersPrepared = true; - for (size_t i = 0; i < mFetcherInfos.size(); ++i) { - if (!mFetcherInfos.valueAt(i).mIsPrepared) { - allFetchersPrepared = false; - break; - } - } - - if (allFetchersPrepared) { - postPrepared(OK); - } - } - break; - } - case PlaylistFetcher::kWhatStartedAt: { int32_t switchGeneration; @@ -569,19 +532,6 @@ void LiveSession::onMessageReceived(const sp<AMessage> &msg) { break; } - case kWhatCheckBandwidth: - { - int32_t generation; - CHECK(msg->findInt32("generation", &generation)); - - if (generation != mCheckBandwidthGeneration) { - break; - } - - onCheckBandwidth(msg); - break; - } - case kWhatChangeConfiguration: { onChangeConfiguration(msg); @@ -612,15 +562,13 @@ void LiveSession::onMessageReceived(const sp<AMessage> &msg) { break; } - case kWhatCheckSwitchDown: + case kWhatPollBuffering: { - onCheckSwitchDown(); - break; - } - - case kWhatSwitchDown: - { - onSwitchDown(); + int32_t generation; + CHECK(msg->findInt32("generation", &generation)); + if (generation == mPollBufferingGeneration) { + onPollBuffering(); + } break; } @@ -691,6 +639,14 @@ void LiveSession::onConnect(const sp<AMessage> &msg) { return; } + // create looper for fetchers + if (mFetcherLooper == NULL) { + mFetcherLooper = new ALooper(); + + mFetcherLooper->setName("Fetcher"); + mFetcherLooper->start(false, false); + } + // We trust the content provider to make a reasonable choice of preferred // initial bandwidth by listing it first in the variant playlist. // At startup we really don't have a good estimate on the available @@ -739,19 +695,20 @@ void LiveSession::onConnect(const sp<AMessage> &msg) { mPlaylist->pickRandomMediaItems(); changeConfiguration( 0ll /* timeUs */, initialBandwidthIndex, false /* pickTrack */); + + schedulePollBuffering(); } void LiveSession::finishDisconnect() { // No reconfiguration is currently pending, make sure none will trigger // during disconnection either. - cancelCheckBandwidthEvent(); // Protect mPacketSources from a swapPacketSource race condition through disconnect. // (finishDisconnect, onFinishDisconnect2) cancelBandwidthSwitch(); - // cancel switch down monitor - mSwitchDownMonitor.clear(); + // cancel buffer polling + cancelPollBuffering(); for (size_t i = 0; i < mFetcherInfos.size(); ++i) { mFetcherInfos.valueAt(i).mFetcher->stopAsync(); @@ -799,7 +756,7 @@ sp<PlaylistFetcher> LiveSession::addFetcher(const char *uri) { info.mDurationUs = -1ll; info.mIsPrepared = false; info.mToBeRemoved = false; - looper()->registerHandler(info.mFetcher); + mFetcherLooper->registerHandler(info.mFetcher); mFetcherInfos.add(uri, info); @@ -1201,19 +1158,6 @@ ssize_t LiveSession::getSelectedTrack(media_track_type type) const { } } -bool LiveSession::canSwitchUp() { - // Allow upwards bandwidth switch when a stream has buffered at least 10 seconds. - status_t err = OK; - for (size_t i = 0; i < mPacketSources.size(); ++i) { - sp<AnotherPacketSource> source = mPacketSources.valueAt(i); - int64_t dur = source->getBufferedDurationUs(&err); - if (err == OK && dur > 10000000) { - return true; - } - } - return false; -} - void LiveSession::changeConfiguration( int64_t timeUs, size_t bandwidthIndex, bool pickTrack) { // Protect mPacketSources from a swapPacketSource race condition through reconfiguration. @@ -1296,14 +1240,6 @@ void LiveSession::changeConfiguration( if (mContinuationCounter == 0) { msg->post(); - - if (mSeekReplyID != 0) { - CHECK(mSeekReply != NULL); - mSeekReply->setInt32("err", OK); - mSeekReply->postReply(mSeekReplyID); - mSeekReplyID = 0; - mSeekReply.clear(); - } } } @@ -1323,6 +1259,30 @@ void LiveSession::onChangeConfiguration2(const sp<AMessage> &msg) { // All fetchers are either suspended or have been removed now. + // If we're seeking, clear all packet sources before we report + // seek complete, to prevent decoder from pulling stale data. + int64_t timeUs; + CHECK(msg->findInt64("timeUs", &timeUs)); + + if (timeUs >= 0) { + mLastSeekTimeUs = timeUs; + + for (size_t i = 0; i < mPacketSources.size(); i++) { + mPacketSources.editValueAt(i)->clear(); + } + + mDiscontinuityOffsetTimesUs.clear(); + mDiscontinuityAbsStartTimesUs.clear(); + + if (mSeekReplyID != 0) { + CHECK(mSeekReply != NULL); + mSeekReply->setInt32("err", OK); + mSeekReply->postReply(mSeekReplyID); + mSeekReplyID = 0; + mSeekReply.clear(); + } + } + uint32_t streamMask, resumeMask; CHECK(msg->findInt32("streamMask", (int32_t *)&streamMask)); CHECK(msg->findInt32("resumeMask", (int32_t *)&resumeMask)); @@ -1428,19 +1388,8 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { for (size_t j = 0; j < kMaxStreams; ++j) { if ((resumeMask & indexToType(j)) && uri == mStreams[j].mUri) { sources[j] = mPacketSources.valueFor(indexToType(j)); - - if (j != kSubtitleIndex) { - ALOGV("queueing dummy discontinuity for stream type %d", indexToType(j)); - sp<AnotherPacketSource> discontinuityQueue; - discontinuityQueue = mDiscontinuities.valueFor(indexToType(j)); - discontinuityQueue->queueDiscontinuity( - ATSParser::DISCONTINUITY_NONE, - NULL, - true); - } } } - FetcherInfo &info = mFetcherInfos.editValueAt(i); if (sources[kAudioIndex] != NULL || sources[kVideoIndex] != NULL || sources[kSubtitleIndex] != NULL) { @@ -1486,15 +1435,7 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { sources[j] = mPacketSources.valueFor(indexToType(j)); if (timeUs >= 0) { - sources[j]->clear(); startTimeUs = timeUs; - - sp<AnotherPacketSource> discontinuityQueue; - sp<AMessage> extra = new AMessage; - extra->setInt64("timeUs", timeUs); - discontinuityQueue = mDiscontinuities.valueFor(indexToType(j)); - discontinuityQueue->queueDiscontinuity( - ATSParser::DISCONTINUITY_TIME, extra, true); } else { int32_t type; sp<AMessage> meta; @@ -1532,9 +1473,10 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { if (j == kSubtitleIndex) { break; } - sp<AnotherPacketSource> discontinuityQueue; - discontinuityQueue = mDiscontinuities.valueFor(indexToType(j)); - discontinuityQueue->queueDiscontinuity( + + ALOGV("stream[%d]: queue format change", j); + + sources[j]->queueDiscontinuity( ATSParser::DISCONTINUITY_FORMATCHANGE, NULL, true); } else { // adapting, queue discontinuities after resume @@ -1564,9 +1506,6 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { // All fetchers have now been started, the configuration change // has completed. - cancelCheckBandwidthEvent(); - scheduleCheckBandwidthEvent(); - ALOGV("XXX configuration change completed."); mReconfigurationInProgress = false; if (switching) { @@ -1623,47 +1562,35 @@ void LiveSession::onSwapped(const sp<AMessage> &msg) { tryToFinishBandwidthSwitch(); } -void LiveSession::onCheckSwitchDown() { - if (mSwitchDownMonitor == NULL) { - return; - } - - if (mSwitchInProgress || mReconfigurationInProgress) { - ALOGV("Switch/Reconfig in progress, defer switch down"); - mSwitchDownMonitor->post(1000000ll); - return; - } +void LiveSession::schedulePollBuffering() { + sp<AMessage> msg = new AMessage(kWhatPollBuffering, this); + msg->setInt32("generation", mPollBufferingGeneration); + msg->post(1000000ll); +} - for (size_t i = 0; i < kMaxStreams; ++i) { - int32_t targetDuration; - sp<AnotherPacketSource> packetSource = mPacketSources.valueFor(indexToType(i)); - sp<AMessage> meta = packetSource->getLatestDequeuedMeta(); +void LiveSession::cancelPollBuffering() { + ++mPollBufferingGeneration; +} - if (meta != NULL && meta->findInt32("targetDuration", &targetDuration) ) { - int64_t bufferedDurationUs = packetSource->getEstimatedDurationUs(); - int64_t targetDurationUs = targetDuration * 1000000ll; +void LiveSession::onPollBuffering() { + ALOGV("onPollBuffering: mSwitchInProgress %d, mReconfigurationInProgress %d, " + "mInPreparationPhase %d, mStreamMask 0x%x", + mSwitchInProgress, mReconfigurationInProgress, + mInPreparationPhase, mStreamMask); - if (bufferedDurationUs < targetDurationUs / 3) { - (new AMessage(kWhatSwitchDown, this))->post(); - break; - } + bool low, mid, high; + if (checkBuffering(low, mid, high)) { + if (mInPreparationPhase && mid) { + postPrepared(OK); } - } - - mSwitchDownMonitor->post(1000000ll); -} - -void LiveSession::onSwitchDown() { - if (mReconfigurationInProgress || mSwitchInProgress || mCurBandwidthIndex == 0) { - return; - } - ssize_t bandwidthIndex = getBandwidthIndex(); - if (bandwidthIndex < mCurBandwidthIndex) { - changeConfiguration(-1, bandwidthIndex, false); - return; + // don't switch before we report prepared + if (!mInPreparationPhase && (low || high)) { + switchBandwidthIfNeeded(high); + } } + schedulePollBuffering(); } // Mark switch done when: @@ -1688,16 +1615,6 @@ void LiveSession::tryToFinishBandwidthSwitch() { } } -void LiveSession::scheduleCheckBandwidthEvent() { - sp<AMessage> msg = new AMessage(kWhatCheckBandwidth, this); - msg->setInt32("generation", mCheckBandwidthGeneration); - msg->post(10000000ll); -} - -void LiveSession::cancelCheckBandwidthEvent() { - ++mCheckBandwidthGeneration; -} - void LiveSession::cancelBandwidthSwitch() { Mutex::Autolock lock(mSwapMutex); mSwitchGeneration++; @@ -1727,33 +1644,69 @@ void LiveSession::cancelBandwidthSwitch() { } } -bool LiveSession::canSwitchBandwidthTo(size_t bandwidthIndex) { - if (mReconfigurationInProgress || mSwitchInProgress) { +bool LiveSession::checkBuffering(bool &low, bool &mid, bool &high) { + low = mid = high = false; + + if (mSwitchInProgress || mReconfigurationInProgress) { + ALOGV("Switch/Reconfig in progress, defer buffer polling"); return false; } - if (mCurBandwidthIndex < 0) { - return true; + // TODO: Fine tune low/high mark. + // We also need to pause playback if buffering is too low. + // Currently during underflow, we depend on decoder to starve + // to pause, but A/V could have different buffering left, + // they're not paused together. + // TODO: Report buffering level to NuPlayer for BUFFERING_UPDATE + + // Switch down if any of the fetchers are below low mark; + // Switch up if all of the fetchers are over high mark. + size_t activeCount, lowCount, midCount, highCount; + activeCount = lowCount = midCount = highCount = 0; + for (size_t i = 0; i < mPacketSources.size(); ++i) { + // we don't check subtitles for buffering level + if (!(mStreamMask & mPacketSources.keyAt(i) + & (STREAMTYPE_AUDIO | STREAMTYPE_VIDEO))) { + continue; + } + // ignore streams that never had any packet queued. + // (it's possible that the variant only has audio or video) + sp<AMessage> meta = mPacketSources[i]->getLatestEnqueuedMeta(); + if (meta == NULL) { + continue; + } + + ++activeCount; + int64_t bufferedDurationUs = + mPacketSources[i]->getEstimatedDurationUs(); + ALOGV("source[%d]: buffered %lld us", i, bufferedDurationUs); + if (bufferedDurationUs < kLowWaterMark) { + ++lowCount; + break; + } else if (bufferedDurationUs > kHighWaterMark) { + ++midCount; + ++highCount; + } else if (bufferedDurationUs > kMidWaterMark) { + ++midCount; + } } - if (bandwidthIndex == (size_t)mCurBandwidthIndex) { - return false; - } else if (bandwidthIndex > (size_t)mCurBandwidthIndex) { - return canSwitchUp(); - } else { + if (activeCount > 0) { + high = (highCount == activeCount); + mid = (midCount == activeCount); + low = (lowCount > 0); return true; } + + return false; } -void LiveSession::onCheckBandwidth(const sp<AMessage> &msg) { - size_t bandwidthIndex = getBandwidthIndex(); - if (canSwitchBandwidthTo(bandwidthIndex)) { - changeConfiguration(-1ll /* timeUs */, bandwidthIndex); - } else { - // Come back and check again 10 seconds later in case there is nothing to do now. - // If we DO change configuration, once that completes it'll schedule a new - // check bandwidth event with an incremented mCheckBandwidthGeneration. - msg->post(10000000ll); +void LiveSession::switchBandwidthIfNeeded(bool canSwitchUp) { + ssize_t bandwidthIndex = getBandwidthIndex(); + + if ((canSwitchUp && bandwidthIndex > mCurBandwidthIndex) + || (!canSwitchUp && bandwidthIndex < mCurBandwidthIndex)) { + changeConfiguration(-1, bandwidthIndex, false); } } @@ -1771,10 +1724,8 @@ void LiveSession::postPrepared(status_t err) { notify->post(); mInPreparationPhase = false; - - mSwitchDownMonitor = new AMessage(kWhatCheckSwitchDown, this); - mSwitchDownMonitor->post(); } + } // namespace android diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index 2d3a25a..3b0a9a4 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -26,6 +26,7 @@ namespace android { struct ABuffer; +struct AReplyToken; struct AnotherPacketSource; struct DataSource; struct HTTPBase; @@ -39,10 +40,6 @@ struct LiveSession : public AHandler { // Don't log any URLs. kFlagIncognito = 1, }; - LiveSession( - const sp<AMessage> ¬ify, - uint32_t flags, - const sp<IMediaHTTPService> &httpService); enum StreamIndex { kAudioIndex = 0, @@ -56,6 +53,12 @@ struct LiveSession : public AHandler { STREAMTYPE_VIDEO = 1 << kVideoIndex, STREAMTYPE_SUBTITLES = 1 << kSubtitleIndex, }; + + LiveSession( + const sp<AMessage> ¬ify, + uint32_t flags, + const sp<IMediaHTTPService> &httpService); + status_t dequeueAccessUnit(StreamType stream, sp<ABuffer> *accessUnit); status_t getStreamFormat(StreamType stream, sp<AMessage> *format); @@ -109,11 +112,13 @@ private: kWhatChangeConfiguration3 = 'chC3', kWhatFinishDisconnect2 = 'fin2', kWhatSwapped = 'swap', - kWhatCheckSwitchDown = 'ckSD', - kWhatSwitchDown = 'sDwn', + kWhatPollBuffering = 'poll', }; static const size_t kBandwidthHistoryBytes; + static const int64_t kHighWaterMark; + static const int64_t kMidWaterMark; + static const int64_t kLowWaterMark; struct BandwidthItem { size_t mPlaylistIndex; @@ -168,6 +173,7 @@ private: sp<M3UParser> mPlaylist; + sp<ALooper> mFetcherLooper; KeyedVector<AString, FetcherInfo> mFetcherInfos; uint32_t mStreamMask; @@ -180,7 +186,6 @@ private: // we use this to track reconfiguration progress. uint32_t mSwapMask; - KeyedVector<StreamType, sp<AnotherPacketSource> > mDiscontinuities; KeyedVector<StreamType, sp<AnotherPacketSource> > mPacketSources; // A second set of packet sources that buffer content for the variant we're switching to. KeyedVector<StreamType, sp<AnotherPacketSource> > mPacketSources2; @@ -203,16 +208,17 @@ private: bool mReconfigurationInProgress; bool mSwitchInProgress; - uint32_t mDisconnectReplyID; - uint32_t mSeekReplyID; + sp<AReplyToken> mDisconnectReplyID; + sp<AReplyToken> mSeekReplyID; bool mFirstTimeUsValid; int64_t mFirstTimeUs; int64_t mLastSeekTimeUs; - sp<AMessage> mSwitchDownMonitor; KeyedVector<size_t, int64_t> mDiscontinuityAbsStartTimesUs; KeyedVector<size_t, int64_t> mDiscontinuityOffsetTimesUs; + int32_t mPollBufferingGeneration; + sp<PlaylistFetcher> addFetcher(const char *uri); void onConnect(const sp<AMessage> &msg); @@ -256,27 +262,24 @@ private: void onChangeConfiguration2(const sp<AMessage> &msg); void onChangeConfiguration3(const sp<AMessage> &msg); void onSwapped(const sp<AMessage> &msg); - void onCheckSwitchDown(); - void onSwitchDown(); void tryToFinishBandwidthSwitch(); - void scheduleCheckBandwidthEvent(); - void cancelCheckBandwidthEvent(); - // cancelBandwidthSwitch is atomic wrt swapPacketSource; call it to prevent packet sources // from being swapped out on stale discontinuities while manipulating // mPacketSources/mPacketSources2. void cancelBandwidthSwitch(); - bool canSwitchBandwidthTo(size_t bandwidthIndex); - void onCheckBandwidth(const sp<AMessage> &msg); + void schedulePollBuffering(); + void cancelPollBuffering(); + void onPollBuffering(); + bool checkBuffering(bool &low, bool &mid, bool &high); + void switchBandwidthIfNeeded(bool canSwitchUp); void finishDisconnect(); void postPrepared(status_t err); void swapPacketSource(StreamType stream); - bool canSwitchUp(); DISALLOW_EVIL_CONSTRUCTORS(LiveSession); }; diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 4ccbf76..3710686 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -49,6 +49,7 @@ namespace android { // static const int64_t PlaylistFetcher::kMinBufferedDurationUs = 10000000ll; const int64_t PlaylistFetcher::kMaxMonitorDelayUs = 3000000ll; +const int64_t PlaylistFetcher::kFetcherResumeThreshold = 100000ll; // LCM of 188 (size of a TS packet) & 1k works well const int32_t PlaylistFetcher::kDownloadBlockSize = 47 * 1024; const int32_t PlaylistFetcher::kNumSkipFrames = 5; @@ -535,12 +536,19 @@ status_t PlaylistFetcher::onResumeUntil(const sp<AMessage> &msg) { sp<AMessage> params; CHECK(msg->findMessage("params", ¶ms)); - bool stop = false; + size_t stopCount = 0; for (size_t i = 0; i < mPacketSources.size(); i++) { sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i); const char *stopKey; int streamType = mPacketSources.keyAt(i); + + if (streamType == LiveSession::STREAMTYPE_SUBTITLES) { + // the subtitle track can always be stopped + ++stopCount; + continue; + } + switch (streamType) { case LiveSession::STREAMTYPE_VIDEO: stopKey = "timeUsVideo"; @@ -550,15 +558,11 @@ status_t PlaylistFetcher::onResumeUntil(const sp<AMessage> &msg) { stopKey = "timeUsAudio"; break; - case LiveSession::STREAMTYPE_SUBTITLES: - stopKey = "timeUsSubtitle"; - break; - default: TRESPASS(); } - // Don't resume if we would stop within a resume threshold. + // check if this stream has too little data left to be resumed int32_t discontinuitySeq; int64_t latestTimeUs = 0, stopTimeUs = 0; sp<AMessage> latestMeta = packetSource->getLatestEnqueuedMeta(); @@ -567,12 +571,13 @@ status_t PlaylistFetcher::onResumeUntil(const sp<AMessage> &msg) { && discontinuitySeq == mDiscontinuitySeq && latestMeta->findInt64("timeUs", &latestTimeUs) && params->findInt64(stopKey, &stopTimeUs) - && stopTimeUs - latestTimeUs < resumeThreshold(latestMeta)) { - stop = true; + && stopTimeUs - latestTimeUs < kFetcherResumeThreshold) { + ++stopCount; } } - if (stop) { + // Don't resume if all streams are within a resume threshold + if (stopCount == mPacketSources.size()) { for (size_t i = 0; i < mPacketSources.size(); i++) { mPacketSources.valueAt(i)->queueAccessUnit(mSession->createFormatChangeBuffer()); } @@ -581,7 +586,7 @@ status_t PlaylistFetcher::onResumeUntil(const sp<AMessage> &msg) { } mStopParams = params; - postMonitorQueue(); + onDownloadNext(); return OK; } @@ -660,9 +665,6 @@ void PlaylistFetcher::onMonitorQueue() { ALOGV("prepared, buffered=%" PRId64 " > %" PRId64 "", bufferedDurationUs, targetDurationUs); - sp<AMessage> msg = mNotify->dup(); - msg->setInt32("what", kWhatTemporarilyDoneFetching); - msg->post(); } if (finalResult == OK && downloadMore) { @@ -676,11 +678,6 @@ void PlaylistFetcher::onMonitorQueue() { msg->post(1000l); } else { // Nothing to do yet, try again in a second. - - sp<AMessage> msg = mNotify->dup(); - msg->setInt32("what", kWhatTemporarilyDoneFetching); - msg->post(); - int64_t delayUs = mPrepared ? kMaxMonitorDelayUs : targetDurationUs / 2; ALOGV("pausing for %" PRId64 ", buffered=%" PRId64 " > %" PRId64 "", delayUs, bufferedDurationUs, durationToBufferUs); @@ -1687,33 +1684,4 @@ void PlaylistFetcher::updateDuration() { msg->post(); } -int64_t PlaylistFetcher::resumeThreshold(const sp<AMessage> &msg) { - int64_t durationUs; - if (msg->findInt64("durationUs", &durationUs) && durationUs > 0) { - return kNumSkipFrames * durationUs; - } - - sp<RefBase> obj; - msg->findObject("format", &obj); - MetaData *format = static_cast<MetaData *>(obj.get()); - - const char *mime; - CHECK(format->findCString(kKeyMIMEType, &mime)); - bool audio = !strncasecmp(mime, "audio/", 6); - if (audio) { - // Assumes 1000 samples per frame. - int32_t sampleRate; - CHECK(format->findInt32(kKeySampleRate, &sampleRate)); - return kNumSkipFrames /* frames */ * 1000 /* samples */ - * (1000000 / sampleRate) /* sample duration (us) */; - } else { - int32_t frameRate; - if (format->findInt32(kKeyFrameRate, &frameRate) && frameRate > 0) { - return kNumSkipFrames * (1000000 / frameRate); - } - } - - return 500000ll; -} - } // namespace android diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h index 4e15f85..2f11949 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.h +++ b/media/libstagefright/httplive/PlaylistFetcher.h @@ -36,6 +36,7 @@ class String8; struct PlaylistFetcher : public AHandler { static const int64_t kMinBufferedDurationUs; static const int32_t kDownloadBlockSize; + static const int64_t kFetcherResumeThreshold; enum { kWhatStarted, @@ -43,7 +44,6 @@ struct PlaylistFetcher : public AHandler { kWhatStopped, kWhatError, kWhatDurationUpdate, - kWhatTemporarilyDoneFetching, kWhatPrepared, kWhatPreparationFailed, kWhatStartedAt, @@ -212,10 +212,6 @@ private: void updateDuration(); - // Before resuming a fetcher in onResume, check the remaining duration is longer than that - // returned by resumeThreshold. - int64_t resumeThreshold(const sp<AMessage> &msg); - DISALLOW_EVIL_CONSTRUCTORS(PlaylistFetcher); }; diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index 934e2e5..6786506 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -35,6 +35,7 @@ #include <media/stagefright/Utils.h> #include <media/IStreamSource.h> #include <utils/KeyedVector.h> +#include <utils/Vector.h> #include <inttypes.h> @@ -86,6 +87,11 @@ struct ATSParser::Program : public RefBase { } private: + struct StreamInfo { + unsigned mType; + unsigned mPID; + }; + ATSParser *mParser; unsigned mProgramNumber; unsigned mProgramMapPID; @@ -96,6 +102,7 @@ private: status_t parseProgramMap(ABitReader *br); int64_t recoverPTS(uint64_t PTS_33bit); + bool switchPIDs(const Vector<StreamInfo> &infos); DISALLOW_EVIL_CONSTRUCTORS(Program); }; @@ -185,7 +192,7 @@ ATSParser::Program::Program( mProgramMapPID(programMapPID), mFirstPTSValid(false), mFirstPTS(0), - mLastRecoveredPTS(0) { + mLastRecoveredPTS(-1ll) { ALOGV("new program number %u", programNumber); } @@ -240,10 +247,71 @@ void ATSParser::Program::signalEOS(status_t finalResult) { } } -struct StreamInfo { - unsigned mType; - unsigned mPID; -}; +bool ATSParser::Program::switchPIDs(const Vector<StreamInfo> &infos) { + bool success = false; + + if (mStreams.size() == infos.size()) { + // build type->PIDs map for old and new mapping + size_t i; + KeyedVector<int32_t, Vector<int32_t> > oldType2PIDs, newType2PIDs; + for (i = 0; i < mStreams.size(); ++i) { + ssize_t index = oldType2PIDs.indexOfKey(mStreams[i]->type()); + if (index < 0) { + oldType2PIDs.add(mStreams[i]->type(), Vector<int32_t>()); + } + oldType2PIDs.editValueFor(mStreams[i]->type()).push_back(mStreams[i]->pid()); + } + for (i = 0; i < infos.size(); ++i) { + ssize_t index = newType2PIDs.indexOfKey(infos[i].mType); + if (index < 0) { + newType2PIDs.add(infos[i].mType, Vector<int32_t>()); + } + newType2PIDs.editValueFor(infos[i].mType).push_back(infos[i].mPID); + } + + // we can recover if the number of streams for each type hasn't changed + if (oldType2PIDs.size() == newType2PIDs.size()) { + success = true; + for (i = 0; i < oldType2PIDs.size(); ++i) { + // KeyedVector is sorted, we just compare key and size of each index + if (oldType2PIDs.keyAt(i) != newType2PIDs.keyAt(i) + || oldType2PIDs[i].size() != newType2PIDs[i].size()) { + success = false; + break; + } + } + } + + if (success) { + // save current streams to temp + KeyedVector<int32_t, sp<Stream> > temp; + for (i = 0; i < mStreams.size(); ++i) { + temp.add(mStreams.keyAt(i), mStreams.editValueAt(i)); + } + + mStreams.clear(); + for (i = 0; i < temp.size(); ++i) { + // The two checks below shouldn't happen, + // we already checked above the stream count matches + ssize_t index = newType2PIDs.indexOfKey(temp[i]->type()); + CHECK(index >= 0); + Vector<int32_t> &newPIDs = newType2PIDs.editValueAt(index); + CHECK(newPIDs.size() > 0); + + // get the next PID for temp[i]->type() in the new PID map + Vector<int32_t>::iterator it = newPIDs.begin(); + + // change the PID of the stream, and add it back + temp.editValueAt(i)->setPID(*it); + mStreams.add(temp[i]->pid(), temp.editValueAt(i)); + + // removed the used PID + newPIDs.erase(it); + } + } + } + return success; +} status_t ATSParser::Program::parseProgramMap(ABitReader *br) { unsigned table_id = br->getBits(8); @@ -372,39 +440,8 @@ status_t ATSParser::Program::parseProgramMap(ABitReader *br) { } #endif - // The only case we can recover from is if we have two streams - // and they switched PIDs. - - bool success = false; - - if (mStreams.size() == 2 && infos.size() == 2) { - const StreamInfo &info1 = infos.itemAt(0); - const StreamInfo &info2 = infos.itemAt(1); - - sp<Stream> s1 = mStreams.editValueAt(0); - sp<Stream> s2 = mStreams.editValueAt(1); - - bool caseA = - info1.mPID == s1->pid() && info1.mType == s2->type() - && info2.mPID == s2->pid() && info2.mType == s1->type(); - - bool caseB = - info1.mPID == s2->pid() && info1.mType == s1->type() - && info2.mPID == s1->pid() && info2.mType == s2->type(); - - if (caseA || caseB) { - unsigned pid1 = s1->pid(); - unsigned pid2 = s2->pid(); - s1->setPID(pid2); - s2->setPID(pid1); - - mStreams.clear(); - mStreams.add(s1->pid(), s1); - mStreams.add(s2->pid(), s2); - - success = true; - } - } + // we can recover if number of streams for each type remain the same + bool success = switchPIDs(infos); if (!success) { ALOGI("Stream PIDs changed and we cannot recover."); @@ -433,14 +470,25 @@ int64_t ATSParser::Program::recoverPTS(uint64_t PTS_33bit) { // reasonable amount of time. To handle the wrap-around, use fancy math // to get an extended PTS that is within [-0xffffffff, 0xffffffff] // of the latest recovered PTS. - mLastRecoveredPTS = static_cast<int64_t>( - ((mLastRecoveredPTS - PTS_33bit + 0x100000000ll) - & 0xfffffffe00000000ull) | PTS_33bit); - - // We start from 0, but recovered PTS could be slightly below 0. - // Clamp it to 0 as rest of the pipeline doesn't take negative pts. - // (eg. video is read first and starts at 0, but audio starts at 0xfffffff0) - return mLastRecoveredPTS < 0ll ? 0ll : mLastRecoveredPTS; + if (mLastRecoveredPTS < 0ll) { + // Use the original 33bit number for 1st frame, the reason is that + // if 1st frame wraps to negative that's far away from 0, we could + // never start. Only start wrapping around from 2nd frame. + mLastRecoveredPTS = static_cast<int64_t>(PTS_33bit); + } else { + mLastRecoveredPTS = static_cast<int64_t>( + ((mLastRecoveredPTS - PTS_33bit + 0x100000000ll) + & 0xfffffffe00000000ull) | PTS_33bit); + // We start from 0, but recovered PTS could be slightly below 0. + // Clamp it to 0 as rest of the pipeline doesn't take negative pts. + // (eg. video is read first and starts at 0, but audio starts at 0xfffffff0) + if (mLastRecoveredPTS < 0ll) { + ALOGI("Clamping negative recovered PTS (%" PRId64 ") to 0", mLastRecoveredPTS); + mLastRecoveredPTS = 0ll; + } + } + + return mLastRecoveredPTS; } sp<MediaSource> ATSParser::Program::getSource(SourceType type) { @@ -1118,7 +1166,8 @@ status_t ATSParser::parsePID( if (payload_unit_start_indicator) { if (!section->isEmpty()) { - return ERROR_UNSUPPORTED; + ALOGW("parsePID encounters payload_unit_start_indicator when section is not empty"); + section->clear(); } unsigned skip = br->getBits(8); diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index f266fe7..bb05417 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -91,13 +91,11 @@ sp<MetaData> AnotherPacketSource::getFormat() { while (it != mBuffers.end()) { sp<ABuffer> buffer = *it; int32_t discontinuity; - if (buffer->meta()->findInt32("discontinuity", &discontinuity)) { - break; - } - - sp<RefBase> object; - if (buffer->meta()->findObject("format", &object)) { - return mFormat = static_cast<MetaData*>(object.get()); + if (!buffer->meta()->findInt32("discontinuity", &discontinuity)) { + sp<RefBase> object; + if (buffer->meta()->findObject("format", &object)) { + return mFormat = static_cast<MetaData*>(object.get()); + } } ++it; diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index d81da3f..477cfc6 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -28,6 +28,7 @@ #include <media/hardware/MetadataBufferType.h> #include <ui/GraphicBuffer.h> +#include <gui/BufferItem.h> #include <inttypes.h> #include "FrameDropper.h" @@ -360,7 +361,7 @@ void GraphicBufferSource::suspend(bool suspend) { mSuspended = true; while (mNumFramesAvailable > 0) { - BufferQueue::BufferItem item; + BufferItem item; status_t err = mConsumer->acquireBuffer(&item, 0); if (err == BufferQueue::NO_BUFFER_AVAILABLE) { @@ -410,7 +411,7 @@ bool GraphicBufferSource::fillCodecBuffer_l() { ALOGV("fillCodecBuffer_l: acquiring buffer, avail=%zu", mNumFramesAvailable); - BufferQueue::BufferItem item; + BufferItem item; status_t err = mConsumer->acquireBuffer(&item, 0); if (err == BufferQueue::NO_BUFFER_AVAILABLE) { // shouldn't happen @@ -503,7 +504,7 @@ bool GraphicBufferSource::repeatLatestBuffer_l() { return false; } - BufferQueue::BufferItem item; + BufferItem item; item.mBuf = mLatestBufferId; item.mFrameNumber = mLatestBufferFrameNum; item.mTimestamp = mRepeatLastFrameTimestamp; @@ -534,7 +535,7 @@ bool GraphicBufferSource::repeatLatestBuffer_l() { } void GraphicBufferSource::setLatestBuffer_l( - const BufferQueue::BufferItem &item, bool dropped) { + const BufferItem &item, bool dropped) { ALOGV("setLatestBuffer_l"); if (mLatestBufferId >= 0) { @@ -590,7 +591,7 @@ status_t GraphicBufferSource::signalEndOfInputStream() { return OK; } -int64_t GraphicBufferSource::getTimestamp(const BufferQueue::BufferItem &item) { +int64_t GraphicBufferSource::getTimestamp(const BufferItem &item) { int64_t timeUs = item.mTimestamp / 1000; if (mTimePerCaptureUs > 0ll) { @@ -651,7 +652,7 @@ int64_t GraphicBufferSource::getTimestamp(const BufferQueue::BufferItem &item) { } status_t GraphicBufferSource::submitBuffer_l( - const BufferQueue::BufferItem &item, int cbi) { + const BufferItem &item, int cbi) { ALOGV("submitBuffer_l cbi=%d", cbi); int64_t timeUs = getTimestamp(item); @@ -777,7 +778,7 @@ void GraphicBufferSource::onFrameAvailable(const BufferItem& /*item*/) { ALOGV("onFrameAvailable: suspended, ignoring frame"); } - BufferQueue::BufferItem item; + BufferItem item; status_t err = mConsumer->acquireBuffer(&item, 0); if (err == OK) { // If this is the first time we're seeing this buffer, add it to our diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h index ce3881e..1067472 100644 --- a/media/libstagefright/omx/GraphicBufferSource.h +++ b/media/libstagefright/omx/GraphicBufferSource.h @@ -192,15 +192,15 @@ private: // Marks the mCodecBuffers entry as in-use, copies the GraphicBuffer // reference into the codec buffer, and submits the data to the codec. - status_t submitBuffer_l(const BufferQueue::BufferItem &item, int cbi); + status_t submitBuffer_l(const BufferItem &item, int cbi); // Submits an empty buffer, with the EOS flag set. Returns without // doing anything if we don't have a codec buffer available. void submitEndOfInputStream_l(); - void setLatestBuffer_l(const BufferQueue::BufferItem &item, bool dropped); + void setLatestBuffer_l(const BufferItem &item, bool dropped); bool repeatLatestBuffer_l(); - int64_t getTimestamp(const BufferQueue::BufferItem &item); + int64_t getTimestamp(const BufferItem &item); // Lock, covers all member variables. mutable Mutex mMutex; diff --git a/media/libstagefright/wifi-display/source/MediaPuller.cpp b/media/libstagefright/wifi-display/source/MediaPuller.cpp index 927a53c..ce07a4e 100644 --- a/media/libstagefright/wifi-display/source/MediaPuller.cpp +++ b/media/libstagefright/wifi-display/source/MediaPuller.cpp @@ -105,7 +105,7 @@ void MediaPuller::onMessageReceived(const sp<AMessage> &msg) { sp<AMessage> response = new AMessage; response->setInt32("err", err); - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); response->postReply(replyID); break; diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp index 210914e..14d0951 100644 --- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp +++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp @@ -57,7 +57,7 @@ WifiDisplaySource::WifiDisplaySource( mNetSession(netSession), mClient(client), mSessionID(0), - mStopReplyID(0), + mStopReplyID(NULL), mChosenRTPPort(-1), mUsingPCMAudio(false), mClientSessionID(0), @@ -138,7 +138,7 @@ void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatStart: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); AString iface; @@ -325,7 +325,7 @@ void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) { case kWhatPause: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); status_t err = OK; @@ -345,7 +345,7 @@ void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) { case kWhatResume: { - uint32_t replyID; + sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); status_t err = OK; @@ -492,7 +492,7 @@ void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) { if (mState == AWAITING_CLIENT_TEARDOWN) { ALOGI("TEARDOWN trigger timed out, forcing disconnection."); - CHECK_NE(mStopReplyID, 0); + CHECK(mStopReplyID != NULL); finishStop(); break; } @@ -1470,7 +1470,7 @@ status_t WifiDisplaySource::onTeardownRequest( mNetSession->sendRequest(sessionID, response.c_str()); if (mState == AWAITING_CLIENT_TEARDOWN) { - CHECK_NE(mStopReplyID, 0); + CHECK(mStopReplyID != NULL); finishStop(); } else { mClient->onDisplayError(IRemoteDisplayClient::kDisplayErrorUnknown); diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.h b/media/libstagefright/wifi-display/source/WifiDisplaySource.h index 750265f..0f779e4 100644 --- a/media/libstagefright/wifi-display/source/WifiDisplaySource.h +++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.h @@ -27,6 +27,7 @@ namespace android { +struct AReplyToken; struct IHDCP; struct IRemoteDisplayClient; struct ParsedMessage; @@ -121,7 +122,7 @@ private: struct in_addr mInterfaceAddr; int32_t mSessionID; - uint32_t mStopReplyID; + sp<AReplyToken> mStopReplyID; AString mWfdClientRtpPorts; int32_t mChosenRTPPort; // extracted from "wfd_client_rtp_ports" diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp index 46757bc..80c1c2f 100644 --- a/media/ndk/NdkMediaCodec.cpp +++ b/media/ndk/NdkMediaCodec.cpp @@ -116,7 +116,7 @@ void CodecHandler::onMessageReceived(const sp<AMessage> &msg) { case kWhatStopActivityNotifications: { - uint32_t replyID; + sp<AReplyToken> replyID; msg->senderAwaitsResponse(&replyID); mCodec->mGeneration++; diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 3474f24..c1da6bc 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -741,6 +741,7 @@ void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args __u dprintf(fd, "thread %p may be deadlocked\n", this); } + dprintf(fd, " Thread name: %s\n", mThreadName); dprintf(fd, " I/O handle: %d\n", mId); dprintf(fd, " TID: %d\n", getTid()); dprintf(fd, " Standby: %s\n", mStandby ? "yes" : "no"); @@ -764,6 +765,9 @@ void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args __u } else { dprintf(fd, " none\n"); } + dprintf(fd, " Output device: %#x (%s)\n", mOutDevice, devicesToString(mOutDevice).string()); + dprintf(fd, " Input device: %#x (%s)\n", mInDevice, devicesToString(mInDevice).string()); + dprintf(fd, " Audio source: %d (%s)\n", mAudioSource, sourceToString(mAudioSource)); if (locked) { mLock.unlock(); @@ -1479,6 +1483,9 @@ void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& ar void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args) { dprintf(fd, "\nOutput thread %p type %d (%s):\n", this, type(), threadTypeToString(type())); + + dumpBase(fd, args); + dprintf(fd, " Normal frame count: %zu\n", mNormalFrameCount); dprintf(fd, " Last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime)); dprintf(fd, " Total writes: %d\n", mNumWrites); @@ -1493,8 +1500,6 @@ void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& audio_output_flags_t flags = output != NULL ? output->flags : AUDIO_OUTPUT_FLAG_NONE; String8 flagsAsString = outputFlagsToString(flags); dprintf(fd, " AudioStreamOut: %p flags %#x (%s)\n", output, flags, flagsAsString.string()); - - dumpBase(fd, args); } // Thread virtuals @@ -1545,9 +1550,10 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac ( (sharedBuffer != 0) ) || - // use case 2: callback handler and frame count is default or at least as large as HAL + // use case 2: frame count is default or at least as large as HAL ( - (tid != -1) && + // we formerly checked for a callback handler (non-0 tid), + // but that is no longer required for TRANSFER_OBTAIN mode ((frameCount == 0) || (frameCount >= mFrameCount)) ) @@ -6151,15 +6157,13 @@ void AudioFlinger::RecordThread::dumpInternals(int fd, const Vector<String16>& a { dprintf(fd, "\nInput thread %p:\n", this); - if (mActiveTracks.size() > 0) { - dprintf(fd, " Buffer size: %zu bytes\n", mBufferSize); - } else { + dumpBase(fd, args); + + if (mActiveTracks.size() == 0) { dprintf(fd, " No active record clients\n"); } dprintf(fd, " Fast capture thread: %s\n", hasFastCapture() ? "yes" : "no"); dprintf(fd, " Fast track available: %s\n", mFastTrackAvail ? "yes" : "no"); - - dumpBase(fd, args); } void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args __unused) diff --git a/services/audiopolicy/managerdefault/ConfigParsingUtils.h b/services/audiopolicy/managerdefault/ConfigParsingUtils.h index 7969661..b2d9763 100644 --- a/services/audiopolicy/managerdefault/ConfigParsingUtils.h +++ b/services/audiopolicy/managerdefault/ConfigParsingUtils.h @@ -26,7 +26,9 @@ struct StringToEnum { }; #define STRING_TO_ENUM(string) { #string, string } +#ifndef ARRAY_SIZE #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif const StringToEnum sDeviceNameToEnumTable[] = { STRING_TO_ENUM(AUDIO_DEVICE_OUT_EARPIECE), diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp index 8e894cd..7a79750 100644 --- a/services/camera/libcameraservice/CameraFlashlight.cpp +++ b/services/camera/libcameraservice/CameraFlashlight.cpp @@ -388,7 +388,8 @@ status_t CameraDeviceClientFlashControl::initializeSurface( if (mAnw == NULL) { return NO_MEMORY; } - res = device->createStream(mAnw, width, height, format, &mStreamId); + res = device->createStream(mAnw, width, height, format, + HAL_DATASPACE_UNKNOWN, &mStreamId); if (res) { return res; } diff --git a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp index eadaa00..fd4e714 100644 --- a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp +++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp @@ -155,7 +155,7 @@ status_t CallbackProcessor::updateStream(const Parameters ¶ms) { callbackFormat, params.previewFormat); res = device->createStream(mCallbackWindow, params.previewWidth, params.previewHeight, - callbackFormat, &mCallbackStreamId); + callbackFormat, HAL_DATASPACE_JFIF, &mCallbackStreamId); if (res != OK) { ALOGE("%s: Camera %d: Can't create output stream for callbacks: " "%s (%d)", __FUNCTION__, mId, diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp index 2772267..5b387f9 100644 --- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp +++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp @@ -145,7 +145,8 @@ status_t JpegProcessor::updateStream(const Parameters ¶ms) { // Create stream for HAL production res = device->createStream(mCaptureWindow, params.pictureWidth, params.pictureHeight, - HAL_PIXEL_FORMAT_BLOB, &mCaptureStreamId); + HAL_PIXEL_FORMAT_BLOB, HAL_DATASPACE_JFIF, + &mCaptureStreamId); if (res != OK) { ALOGE("%s: Camera %d: Can't create output stream for capture: " "%s (%d)", __FUNCTION__, mId, diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp index 470624b..a5a2fec 100644 --- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp +++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp @@ -27,6 +27,7 @@ #include <utils/Log.h> #include <utils/Trace.h> +#include <gui/BufferItem.h> #include <gui/Surface.h> #include <media/hardware/MetadataBufferType.h> @@ -181,7 +182,8 @@ status_t StreamingProcessor::updatePreviewStream(const Parameters ¶ms) { if (mPreviewStreamId == NO_STREAM) { res = device->createStream(mPreviewWindow, params.previewWidth, params.previewHeight, - CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, &mPreviewStreamId); + CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, HAL_DATASPACE_UNKNOWN, + &mPreviewStreamId); if (res != OK) { ALOGE("%s: Camera %d: Unable to create preview stream: %s (%d)", __FUNCTION__, mId, strerror(-res), res); @@ -420,9 +422,12 @@ status_t StreamingProcessor::updateRecordingStream(const Parameters ¶ms) { if (mRecordingStreamId == NO_STREAM) { mRecordingFrameCount = 0; + // Selecting BT.709 colorspace by default + // TODO: Wire this in from encoder side res = device->createStream(mRecordingWindow, params.videoWidth, params.videoHeight, - CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, &mRecordingStreamId); + CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, + HAL_DATASPACE_BT709, &mRecordingStreamId); if (res != OK) { ALOGE("%s: Camera %d: Can't create output stream for recording: " "%s (%d)", __FUNCTION__, mId, @@ -675,7 +680,7 @@ status_t StreamingProcessor::processRecordingFrame() { sp<Camera2Client> client = mClient.promote(); if (client == 0) { // Discard frames during shutdown - BufferItemConsumer::BufferItem imgBuffer; + BufferItem imgBuffer; res = mRecordingConsumer->acquireBuffer(&imgBuffer, 0); if (res != OK) { if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) { @@ -693,7 +698,7 @@ status_t StreamingProcessor::processRecordingFrame() { with Camera2Client code calling into StreamingProcessor */ SharedParameters::Lock l(client->getParameters()); Mutex::Autolock m(mMutex); - BufferItemConsumer::BufferItem imgBuffer; + BufferItem imgBuffer; res = mRecordingConsumer->acquireBuffer(&imgBuffer, 0); if (res != OK) { if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) { @@ -819,8 +824,7 @@ void StreamingProcessor::releaseRecordingFrame(const sp<IMemory>& mem) { size_t itemIndex; for (itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) { - const BufferItemConsumer::BufferItem item = - mRecordingBuffers[itemIndex]; + const BufferItem item = mRecordingBuffers[itemIndex]; if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT && item.mGraphicBuffer->handle == imgHandle) { break; @@ -864,8 +868,7 @@ void StreamingProcessor::releaseAllRecordingFramesLocked() { size_t releasedCount = 0; for (size_t itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) { - const BufferItemConsumer::BufferItem item = - mRecordingBuffers[itemIndex]; + const BufferItem item = mRecordingBuffers[itemIndex]; if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT) { res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]); if (res != OK) { diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h index 1d679a4..2474062 100644 --- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h +++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h @@ -124,7 +124,7 @@ class StreamingProcessor: static const size_t kDefaultRecordingHeapCount = 8; size_t mRecordingHeapCount; - Vector<BufferItemConsumer::BufferItem> mRecordingBuffers; + Vector<BufferItem> mRecordingBuffers; size_t mRecordingHeapHead, mRecordingHeapFree; virtual bool threadLoop(); diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp index 8b7e4b4..68aca2d 100644 --- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp +++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp @@ -186,7 +186,7 @@ status_t ZslProcessor::updateStream(const Parameters ¶ms) { (int)HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; res = device->createStream(mZslWindow, params.fastInfo.arrayWidth, params.fastInfo.arrayHeight, - streamType, &mZslStreamId); + streamType, HAL_DATASPACE_UNKNOWN, &mZslStreamId); if (res != OK) { ALOGE("%s: Camera %d: Can't create output stream for ZSL: " "%s (%d)", __FUNCTION__, mId, @@ -440,7 +440,7 @@ status_t ZslProcessor::processNewZslBuffer() { zslConsumer = mZslConsumer; } ALOGVV("Trying to get next buffer"); - BufferItemConsumer::BufferItem item; + BufferItem item; res = zslConsumer->acquireBuffer(&item, 0); if (res != OK) { if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) { diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.h b/services/camera/libcameraservice/api1/client2/ZslProcessor.h index 2099c38..5f50d7b 100644 --- a/services/camera/libcameraservice/api1/client2/ZslProcessor.h +++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.h @@ -22,6 +22,7 @@ #include <utils/Vector.h> #include <utils/Mutex.h> #include <utils/Condition.h> +#include <gui/BufferItem.h> #include <gui/BufferItemConsumer.h> #include <camera/CameraMetadata.h> #include <camera/CaptureResult.h> @@ -103,7 +104,7 @@ class ZslProcessor: sp<ANativeWindow> mZslWindow; struct ZslPair { - BufferItemConsumer::BufferItem buffer; + BufferItem buffer; CameraMetadata frame; }; diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.h b/services/camera/libcameraservice/api1/client2/ZslProcessor3.h index fc9f70c..2960478 100644 --- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.h +++ b/services/camera/libcameraservice/api1/client2/ZslProcessor3.h @@ -22,6 +22,7 @@ #include <utils/Vector.h> #include <utils/Mutex.h> #include <utils/Condition.h> +#include <gui/BufferItem.h> #include <gui/BufferItemConsumer.h> #include <camera/CameraMetadata.h> @@ -104,7 +105,7 @@ class ZslProcessor3 : sp<camera3::Camera3ZslStream> mZslStream; struct ZslPair { - BufferItemConsumer::BufferItem buffer; + BufferItem buffer; CameraMetadata frame; }; diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp index acc092c..dde1779 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp @@ -314,11 +314,10 @@ status_t CameraDeviceClient::deleteStream(int streamId) { return res; } -status_t CameraDeviceClient::createStream(int width, int height, int format, +status_t CameraDeviceClient::createStream( const sp<IGraphicBufferProducer>& bufferProducer) { ATRACE_CALL(); - ALOGV("%s (w = %d, h = %d, f = 0x%x)", __FUNCTION__, width, height, format); status_t res; if ( (res = checkPid(__FUNCTION__) ) != OK) return res; @@ -370,7 +369,8 @@ status_t CameraDeviceClient::createStream(int width, int height, int format, sp<IBinder> binder = IInterface::asBinder(bufferProducer); sp<ANativeWindow> anw = new Surface(bufferProducer, useAsync); - // TODO: remove w,h,f since we are ignoring them + int width, height, format; + android_dataspace dataSpace; if ((res = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, &width)) != OK) { ALOGE("%s: Camera %d: Failed to query Surface width", __FUNCTION__, @@ -387,6 +387,12 @@ status_t CameraDeviceClient::createStream(int width, int height, int format, mCameraId); return res; } + if ((res = anw->query(anw.get(), NATIVE_WINDOW_DEFAULT_DATASPACE, + reinterpret_cast<int*>(&dataSpace))) != OK) { + ALOGE("%s: Camera %d: Failed to query Surface dataSpace", __FUNCTION__, + mCameraId); + return res; + } // FIXME: remove this override since the default format should be // IMPLEMENTATION_DEFINED. b/9487482 @@ -399,14 +405,15 @@ status_t CameraDeviceClient::createStream(int width, int height, int format, // Round dimensions to the nearest dimensions available for this format if (flexibleConsumer && !CameraDeviceClient::roundBufferDimensionNearest(width, height, - format, mDevice->info(), /*out*/&width, /*out*/&height)) { + format, dataSpace, mDevice->info(), /*out*/&width, /*out*/&height)) { ALOGE("%s: No stream configurations with the format %#x defined, failed to create stream.", __FUNCTION__, format); return BAD_VALUE; } int streamId = -1; - res = mDevice->createStream(anw, width, height, format, &streamId); + res = mDevice->createStream(anw, width, height, format, dataSpace, + &streamId); if (res == OK) { mStreamMap.add(binder, streamId); @@ -441,10 +448,12 @@ status_t CameraDeviceClient::createStream(int width, int height, int format, bool CameraDeviceClient::roundBufferDimensionNearest(int32_t width, int32_t height, - int32_t format, const CameraMetadata& info, + int32_t format, android_dataspace dataSpace, const CameraMetadata& info, /*out*/int32_t* outWidth, /*out*/int32_t* outHeight) { camera_metadata_ro_entry streamConfigs = + (dataSpace == HAL_DATASPACE_DEPTH) ? + info.find(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS) : info.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS); int32_t bestWidth = -1; diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h index e687175..c89c269 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.h +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h @@ -84,9 +84,6 @@ public: virtual status_t deleteStream(int streamId); virtual status_t createStream( - int width, - int height, - int format, const sp<IGraphicBufferProducer>& bufferProducer); // Create a request object from a template. @@ -161,7 +158,8 @@ private: // a width <= ROUNDING_WIDTH_CAP static const int32_t ROUNDING_WIDTH_CAP = 1080; static bool roundBufferDimensionNearest(int32_t width, int32_t height, int32_t format, - const CameraMetadata& info, /*out*/int32_t* outWidth, /*out*/int32_t* outHeight); + android_dataspace dataSpace, const CameraMetadata& info, + /*out*/int32_t* outWidth, /*out*/int32_t* outHeight); // IGraphicsBufferProducer binder -> Stream ID KeyedVector<sp<IBinder>, int> mStreamMap; diff --git a/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp b/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp index 30a89c2..ba93554 100644 --- a/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp +++ b/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp @@ -281,7 +281,7 @@ status_t ProCamera2Client::createStream(int width, int height, int format, } return mDevice->createStream(window, width, height, format, - streamId); + HAL_DATASPACE_UNKNOWN, streamId); } // Create a request object from a template. diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h index 06615f6..8764504 100644 --- a/services/camera/libcameraservice/common/CameraDeviceBase.h +++ b/services/camera/libcameraservice/common/CameraDeviceBase.h @@ -100,17 +100,14 @@ class CameraDeviceBase : public virtual RefBase { nsecs_t timeout) = 0; /** - * Create an output stream of the requested size and format. + * Create an output stream of the requested size, format, and dataspace * - * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device selects - * an appropriate format; it can be queried with getStreamInfo. - * - * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must be - * equal to the size in bytes of the buffers to allocate for the stream. For - * other formats, the size parameter is ignored. + * For HAL_PIXEL_FORMAT_BLOB formats, the width and height should be the + * logical dimensions of the buffer, not the number of bytes. */ virtual status_t createStream(sp<ANativeWindow> consumer, - uint32_t width, uint32_t height, int format, int *id) = 0; + uint32_t width, uint32_t height, int format, + android_dataspace dataSpace, int *id) = 0; /** * Create an input reprocess stream that uses buffers from an existing diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp index 43c8307..ee862a2 100644 --- a/services/camera/libcameraservice/device2/Camera2Device.cpp +++ b/services/camera/libcameraservice/device2/Camera2Device.cpp @@ -241,7 +241,8 @@ status_t Camera2Device::waitUntilRequestReceived(int32_t requestId, nsecs_t time } status_t Camera2Device::createStream(sp<ANativeWindow> consumer, - uint32_t width, uint32_t height, int format, int *id) { + uint32_t width, uint32_t height, int format, + android_dataspace /*dataSpace*/, int *id) { ATRACE_CALL(); status_t res; ALOGV("%s: E", __FUNCTION__); diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h index 1cc5482..e4c2856 100644 --- a/services/camera/libcameraservice/device2/Camera2Device.h +++ b/services/camera/libcameraservice/device2/Camera2Device.h @@ -57,7 +57,8 @@ class Camera2Device: public CameraDeviceBase { virtual status_t clearStreamingRequest(int64_t *lastFrameNumber = NULL); virtual status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout); virtual status_t createStream(sp<ANativeWindow> consumer, - uint32_t width, uint32_t height, int format, int *id); + uint32_t width, uint32_t height, int format, + android_dataspace dataSpace, int *id); virtual status_t createReprocessStreamFromStream(int outputId, int *id); virtual status_t getStreamInfo(int id, uint32_t *width, uint32_t *height, uint32_t *format); diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index bca9bfd..529d249 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -801,12 +801,13 @@ status_t Camera3Device::createZslStream( } status_t Camera3Device::createStream(sp<ANativeWindow> consumer, - uint32_t width, uint32_t height, int format, int *id) { + uint32_t width, uint32_t height, int format, android_dataspace dataSpace, + int *id) { ATRACE_CALL(); Mutex::Autolock il(mInterfaceLock); Mutex::Autolock l(mLock); - ALOGV("Camera %d: Creating new stream %d: %d x %d, format %d", - mId, mNextStreamId, width, height, format); + ALOGV("Camera %d: Creating new stream %d: %d x %d, format %d, dataspace %d", + mId, mNextStreamId, width, height, format, dataSpace); status_t res; bool wasActive = false; @@ -846,10 +847,10 @@ status_t Camera3Device::createStream(sp<ANativeWindow> consumer, } newStream = new Camera3OutputStream(mNextStreamId, consumer, - width, height, jpegBufferSize, format); + width, height, jpegBufferSize, format, dataSpace); } else { newStream = new Camera3OutputStream(mNextStreamId, consumer, - width, height, format); + width, height, format, dataSpace); } newStream->setStatusTracker(mStatusTracker); diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index de10cfe..e2ad1fa 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -95,7 +95,8 @@ class Camera3Device : // If adding streams while actively capturing, will pause device before adding // stream, reconfiguring device, and unpausing. virtual status_t createStream(sp<ANativeWindow> consumer, - uint32_t width, uint32_t height, int format, int *id); + uint32_t width, uint32_t height, int format, + android_dataspace dataSpace, int *id); virtual status_t createInputStream( uint32_t width, uint32_t height, int format, int *id); diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp index 6656b09..6201484 100644 --- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp @@ -28,7 +28,7 @@ namespace camera3 { Camera3DummyStream::Camera3DummyStream(int id) : Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, DUMMY_WIDTH, DUMMY_HEIGHT, - /*maxSize*/0, DUMMY_FORMAT) { + /*maxSize*/0, DUMMY_FORMAT, DUMMY_DATASPACE) { } diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h index 3e42623..7f52d84 100644 --- a/services/camera/libcameraservice/device3/Camera3DummyStream.h +++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h @@ -75,6 +75,7 @@ class Camera3DummyStream : static const int DUMMY_WIDTH = 320; static const int DUMMY_HEIGHT = 240; static const int DUMMY_FORMAT = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; + static const android_dataspace DUMMY_DATASPACE = HAL_DATASPACE_UNKNOWN; static const uint32_t DUMMY_USAGE = GRALLOC_USAGE_HW_COMPOSER; /** diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp index cc66459..ff0acbb 100644 --- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp +++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp @@ -30,9 +30,10 @@ namespace android { namespace camera3 { Camera3IOStreamBase::Camera3IOStreamBase(int id, camera3_stream_type_t type, - uint32_t width, uint32_t height, size_t maxSize, int format) : + uint32_t width, uint32_t height, size_t maxSize, int format, + android_dataspace dataSpace) : Camera3Stream(id, type, - width, height, maxSize, format), + width, height, maxSize, format, dataSpace), mTotalBufferCount(0), mHandoutTotalBufferCount(0), mHandoutOutputBufferCount(0), diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h index a35c290..83d4350 100644 --- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h +++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h @@ -33,7 +33,8 @@ class Camera3IOStreamBase : public Camera3Stream { protected: Camera3IOStreamBase(int id, camera3_stream_type_t type, - uint32_t width, uint32_t height, size_t maxSize, int format); + uint32_t width, uint32_t height, size_t maxSize, int format, + android_dataspace dataSpace); public: diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp index 319be1d..87907bf 100644 --- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp @@ -18,6 +18,7 @@ #define ATRACE_TAG ATRACE_TAG_CAMERA //#define LOG_NDEBUG 0 +#include <gui/BufferItem.h> #include <utils/Log.h> #include <utils/Trace.h> #include "Camera3InputStream.h" @@ -29,7 +30,7 @@ namespace camera3 { Camera3InputStream::Camera3InputStream(int id, uint32_t width, uint32_t height, int format) : Camera3IOStreamBase(id, CAMERA3_STREAM_INPUT, width, height, - /*maxSize*/0, format) { + /*maxSize*/0, format, HAL_DATASPACE_UNKNOWN) { if (format == HAL_PIXEL_FORMAT_BLOB) { ALOGE("%s: Bad format, BLOB not supported", __FUNCTION__); diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.h b/services/camera/libcameraservice/device3/Camera3InputStream.h index ae49467..fd17f4f 100644 --- a/services/camera/libcameraservice/device3/Camera3InputStream.h +++ b/services/camera/libcameraservice/device3/Camera3InputStream.h @@ -48,8 +48,6 @@ class Camera3InputStream : public Camera3IOStreamBase { private: - typedef BufferItemConsumer::BufferItem BufferItem; - sp<BufferItemConsumer> mConsumer; Vector<BufferItem> mBuffersInFlight; diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp index 77ad503..103d90b 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp @@ -33,9 +33,10 @@ namespace camera3 { Camera3OutputStream::Camera3OutputStream(int id, sp<ANativeWindow> consumer, - uint32_t width, uint32_t height, int format) : + uint32_t width, uint32_t height, int format, + android_dataspace dataSpace) : Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height, - /*maxSize*/0, format), + /*maxSize*/0, format, dataSpace), mConsumer(consumer), mTransform(0), mTraceFirstBuffer(true) { @@ -48,9 +49,10 @@ Camera3OutputStream::Camera3OutputStream(int id, Camera3OutputStream::Camera3OutputStream(int id, sp<ANativeWindow> consumer, - uint32_t width, uint32_t height, size_t maxSize, int format) : + uint32_t width, uint32_t height, size_t maxSize, int format, + android_dataspace dataSpace) : Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height, maxSize, - format), + format, dataSpace), mConsumer(consumer), mTransform(0), mTraceFirstBuffer(true) { @@ -69,10 +71,11 @@ Camera3OutputStream::Camera3OutputStream(int id, Camera3OutputStream::Camera3OutputStream(int id, camera3_stream_type_t type, uint32_t width, uint32_t height, - int format) : + int format, + android_dataspace dataSpace) : Camera3IOStreamBase(id, type, width, height, /*maxSize*/0, - format), + format, dataSpace), mTransform(0) { // Subclasses expected to initialize mConsumer themselves @@ -323,6 +326,14 @@ status_t Camera3OutputStream::configureQueueLocked() { return res; } + res = native_window_set_buffers_data_space(mConsumer.get(), + camera3_stream::data_space); + if (res != OK) { + ALOGE("%s: Unable to configure stream dataspace %#x for stream %d", + __FUNCTION__, camera3_stream::data_space, mId); + return res; + } + int maxConsumerBuffers; res = mConsumer->query(mConsumer.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers); diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h index be278c5..f016d60 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputStream.h +++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h @@ -39,14 +39,16 @@ class Camera3OutputStream : * Set up a stream for formats that have 2 dimensions, such as RAW and YUV. */ Camera3OutputStream(int id, sp<ANativeWindow> consumer, - uint32_t width, uint32_t height, int format); + uint32_t width, uint32_t height, int format, + android_dataspace dataSpace); /** * Set up a stream for formats that have a variable buffer size for the same * dimensions, such as compressed JPEG. */ Camera3OutputStream(int id, sp<ANativeWindow> consumer, - uint32_t width, uint32_t height, size_t maxSize, int format); + uint32_t width, uint32_t height, size_t maxSize, int format, + android_dataspace dataSpace); virtual ~Camera3OutputStream(); @@ -64,7 +66,8 @@ class Camera3OutputStream : protected: Camera3OutputStream(int id, camera3_stream_type_t type, - uint32_t width, uint32_t height, int format); + uint32_t width, uint32_t height, int format, + android_dataspace dataSpace); /** * Note that we release the lock briefly in this function diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp index 3c0e908..f829741 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp @@ -46,7 +46,8 @@ const Camera3Stream* Camera3Stream::cast(const camera3_stream *stream) { Camera3Stream::Camera3Stream(int id, camera3_stream_type type, - uint32_t width, uint32_t height, size_t maxSize, int format) : + uint32_t width, uint32_t height, size_t maxSize, int format, + android_dataspace dataSpace) : camera3_stream(), mId(id), mName(String8::format("Camera3Stream[%d]", id)), @@ -58,6 +59,7 @@ Camera3Stream::Camera3Stream(int id, camera3_stream::width = width; camera3_stream::height = height; camera3_stream::format = format; + camera3_stream::data_space = dataSpace; camera3_stream::usage = 0; camera3_stream::max_buffers = 0; camera3_stream::priv = NULL; @@ -84,6 +86,10 @@ int Camera3Stream::getFormat() const { return camera3_stream::format; } +android_dataspace Camera3Stream::getDataSpace() const { + return camera3_stream::data_space; +} + camera3_stream* Camera3Stream::startConfiguration() { ATRACE_CALL(); Mutex::Autolock l(mLock); diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h index d0e1337..72f3ee9 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.h +++ b/services/camera/libcameraservice/device3/Camera3Stream.h @@ -119,9 +119,10 @@ class Camera3Stream : /** * Get the stream's dimensions and format */ - uint32_t getWidth() const; - uint32_t getHeight() const; - int getFormat() const; + uint32_t getWidth() const; + uint32_t getHeight() const; + int getFormat() const; + android_dataspace getDataSpace() const; /** * Start the stream configuration process. Returns a handle to the stream's @@ -264,7 +265,8 @@ class Camera3Stream : mutable Mutex mLock; Camera3Stream(int id, camera3_stream_type type, - uint32_t width, uint32_t height, size_t maxSize, int format); + uint32_t width, uint32_t height, size_t maxSize, int format, + android_dataspace dataSpace); /** * Interface to be implemented by derived classes diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp index 81330ea..5bf7a4c 100644 --- a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp @@ -114,7 +114,8 @@ Camera3ZslStream::Camera3ZslStream(int id, uint32_t width, uint32_t height, int bufferCount) : Camera3OutputStream(id, CAMERA3_STREAM_BIDIRECTIONAL, width, height, - HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED), + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, + HAL_DATASPACE_UNKNOWN), mDepth(bufferCount) { sp<IGraphicBufferProducer> producer; diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp index d0f29de..8cd6800 100644 --- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp +++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp @@ -268,7 +268,7 @@ status_t RingBufferConsumer::releaseOldestBufferLocked(size_t* pinnedFrames) { return OK; } -void RingBufferConsumer::onFrameAvailable(const android::BufferItem& item) { +void RingBufferConsumer::onFrameAvailable(const BufferItem& item) { status_t err; { diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.h b/services/camera/libcameraservice/gui/RingBufferConsumer.h index 90fd734..83e7298 100644 --- a/services/camera/libcameraservice/gui/RingBufferConsumer.h +++ b/services/camera/libcameraservice/gui/RingBufferConsumer.h @@ -17,6 +17,7 @@ #ifndef ANDROID_GUI_RINGBUFFERCONSUMER_H #define ANDROID_GUI_RINGBUFFERCONSUMER_H +#include <gui/BufferItem.h> #include <gui/ConsumerBase.h> #include <ui/GraphicBuffer.h> @@ -54,8 +55,6 @@ class RingBufferConsumer : public ConsumerBase, public: typedef ConsumerBase::FrameAvailableListener FrameAvailableListener; - typedef BufferQueue::BufferItem BufferItem; - enum { INVALID_BUFFER_SLOT = BufferQueue::INVALID_BUFFER_SLOT }; enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE }; @@ -165,7 +164,7 @@ class RingBufferConsumer : public ConsumerBase, private: // Override ConsumerBase::onFrameAvailable - virtual void onFrameAvailable(const android::BufferItem& item); + virtual void onFrameAvailable(const BufferItem& item); void pinBufferLocked(const BufferItem& item); void unpinBuffer(const BufferItem& item); |