diff options
Diffstat (limited to 'include/media/stagefright')
40 files changed, 1424 insertions, 134 deletions
diff --git a/include/media/stagefright/AACWriter.h b/include/media/stagefright/AACWriter.h index d22707a..aa60a19 100644 --- a/include/media/stagefright/AACWriter.h +++ b/include/media/stagefright/AACWriter.h @@ -24,10 +24,9 @@ namespace android { struct MediaSource; -struct MetaData; +class MetaData; struct AACWriter : public MediaWriter { - AACWriter(const char *filename); AACWriter(int fd); status_t initCheck() const; diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h index 7825508..8b5b862 100644 --- a/include/media/stagefright/ACodec.h +++ b/include/media/stagefright/ACodec.h @@ -20,9 +20,11 @@ #include <stdint.h> #include <android/native_window.h> +#include <media/hardware/MetadataBufferType.h> #include <media/IOMX.h> #include <media/stagefright/foundation/AHierarchicalStateMachine.h> #include <media/stagefright/CodecBase.h> +#include <media/stagefright/FrameRenderTracker.h> #include <media/stagefright/SkipCutBuffer.h> #include <OMX_Audio.h> @@ -44,9 +46,12 @@ struct ACodec : public AHierarchicalStateMachine, public CodecBase { virtual void initiateAllocateComponent(const sp<AMessage> &msg); virtual void initiateConfigureComponent(const sp<AMessage> &msg); virtual void initiateCreateInputSurface(); + virtual void initiateSetInputSurface(const sp<PersistentSurface> &surface); virtual void initiateStart(); virtual void initiateShutdown(bool keepComponentAllocated = false); + virtual status_t setSurface(const sp<Surface> &surface); + virtual void signalFlush(); virtual void signalResume(); @@ -105,6 +110,10 @@ private: enum { kWhatSetup = 'setu', kWhatOMXMessage = 'omx ', + // same as kWhatOMXMessage - but only used with + // handleMessage during OMX message-list handling + kWhatOMXMessageItem = 'omxI', + kWhatOMXMessageList = 'omxL', kWhatInputBufferFilled = 'inpF', kWhatOutputBufferDrained = 'outD', kWhatShutdown = 'shut', @@ -113,12 +122,14 @@ private: kWhatDrainDeferredMessages = 'drai', kWhatAllocateComponent = 'allo', kWhatConfigureComponent = 'conf', + kWhatSetSurface = 'setS', kWhatCreateInputSurface = 'cisf', + kWhatSetInputSurface = 'sisf', kWhatSignalEndOfInputStream = 'eois', kWhatStart = 'star', kWhatRequestIDRFrame = 'ridr', kWhatSetParameters = 'setP', - kWhatSubmitOutputMetaDataBufferIfEOS = 'subm', + kWhatSubmitOutputMetadataBufferIfEOS = 'subm', kWhatOMXDied = 'OMXd', kWhatReleaseCodecInstance = 'relC', }; @@ -134,6 +145,12 @@ private: kFlagIsGrallocUsageProtected = 4, }; + enum { + kVideoGrallocUsage = (GRALLOC_USAGE_HW_TEXTURE + | GRALLOC_USAGE_HW_COMPOSER + | GRALLOC_USAGE_EXTERNAL_DISP), + }; + struct BufferInfo { enum Status { OWNED_BY_US, @@ -141,16 +158,39 @@ private: OWNED_BY_UPSTREAM, OWNED_BY_DOWNSTREAM, OWNED_BY_NATIVE_WINDOW, + UNRECOGNIZED, // not a tracked buffer }; + static inline Status getSafeStatus(BufferInfo *info) { + return info == NULL ? UNRECOGNIZED : info->mStatus; + } + IOMX::buffer_id mBufferID; Status mStatus; unsigned mDequeuedAt; sp<ABuffer> mData; sp<GraphicBuffer> mGraphicBuffer; + int mFenceFd; + FrameRenderTracker::Info *mRenderInfo; + + // The following field and 4 methods are used for debugging only + bool mIsReadFence; + // Store |fenceFd| and set read/write flag. Log error, if there is already a fence stored. + void setReadFence(int fenceFd, const char *dbg); + void setWriteFence(int fenceFd, const char *dbg); + // Log error, if the current fence is not a read/write fence. + void checkReadFence(const char *dbg); + void checkWriteFence(const char *dbg); }; + static const char *_asString(BufferInfo::Status s); + void dumpBuffers(OMX_U32 portIndex); + + // If |fd| is non-negative, waits for fence with |fd| and logs an error if it fails. Returns + // the error code or OK on success. If |fd| is negative, it returns OK + status_t waitForFence(int fd, const char *dbg); + #if TRACK_BUFFER_TIMING struct BufferStats { int64_t mEmptyBufferTimeUs; @@ -181,10 +221,12 @@ private: sp<MemoryDealer> mDealer[2]; sp<ANativeWindow> mNativeWindow; + int mNativeWindowUsageBits; sp<AMessage> mInputFormat; sp<AMessage> mOutputFormat; sp<AMessage> mBaseOutputFormat; + FrameRenderTracker mRenderTracker; // render information for buffers rendered by ACodec Vector<BufferInfo> mBuffers[2]; bool mPortEOS[2]; status_t mInputEOSResult; @@ -192,8 +234,8 @@ private: List<sp<AMessage> > mDeferredQueue; bool mSentFormat; + bool mIsVideo; bool mIsEncoder; - bool mUseMetadataOnEncoderOutput; bool mFatalError; bool mShutdownInProgress; bool mExplicitShutdown; @@ -209,12 +251,15 @@ private: bool mChannelMaskPresent; int32_t mChannelMask; unsigned mDequeueCounter; - bool mStoreMetaDataInOutputBuffers; - int32_t mMetaDataBuffersToSubmit; + MetadataBufferType mInputMetadataType; + MetadataBufferType mOutputMetadataType; + bool mLegacyAdaptiveExperiment; + int32_t mMetadataBuffersToSubmit; size_t mNumUndequeuedBuffers; int64_t mRepeatFrameDelayUs; int64_t mMaxPtsGapUs; + float mMaxFps; int64_t mTimePerFrameUs; int64_t mTimePerCaptureUs; @@ -228,17 +273,29 @@ private: status_t freeBuffersOnPort(OMX_U32 portIndex); status_t freeBuffer(OMX_U32 portIndex, size_t i); + status_t handleSetSurface(const sp<Surface> &surface); + status_t setupNativeWindowSizeFormatAndUsage( + ANativeWindow *nativeWindow /* nonnull */, int *finalUsage /* nonnull */); + status_t configureOutputBuffersFromNativeWindow( OMX_U32 *nBufferCount, OMX_U32 *nBufferSize, OMX_U32 *nMinUndequeuedBuffers); - status_t allocateOutputMetaDataBuffers(); - status_t submitOutputMetaDataBuffer(); - void signalSubmitOutputMetaDataBufferIfEOS_workaround(); + status_t allocateOutputMetadataBuffers(); + status_t submitOutputMetadataBuffer(); + void signalSubmitOutputMetadataBufferIfEOS_workaround(); status_t allocateOutputBuffersFromNativeWindow(); status_t cancelBufferToNativeWindow(BufferInfo *info); status_t freeOutputBuffersNotOwnedByComponent(); BufferInfo *dequeueBufferFromNativeWindow(); + inline bool storingMetadataInDecodedBuffers() { + return mOutputMetadataType >= 0 && !mIsEncoder; + } + + inline bool usingMetadataOnEncoderOutput() { + return mOutputMetadataType >= 0 && mIsEncoder; + } + BufferInfo *findBufferByID( uint32_t portIndex, IOMX::buffer_id bufferID, ssize_t *index = NULL); @@ -299,6 +356,9 @@ private: status_t setupRawAudioFormat( OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels); + status_t setPriority(int32_t priority); + status_t setOperatingRate(float rateFloat, bool isVideo); + status_t setMinBufferSize(OMX_U32 portIndex, size_t size); status_t setupMPEG4EncoderParameters(const sp<AMessage> &msg); @@ -316,8 +376,6 @@ private: status_t initNativeWindow(); - status_t pushBlankBuffersToNativeWindow(); - // Returns true iff all buffers on the given port have status // OWNED_BY_US or OWNED_BY_NATIVE_WINDOW. bool allYourBuffersAreBelongToUs(OMX_U32 portIndex); @@ -332,6 +390,23 @@ private: void deferMessage(const sp<AMessage> &msg); void processDeferredMessages(); + void onFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano); + // called when we have dequeued a buffer |buf| from the native window to track render info. + // |fenceFd| is the dequeue fence, and |info| points to the buffer info where this buffer is + // stored. + void updateRenderInfoForDequeuedBuffer( + ANativeWindowBuffer *buf, int fenceFd, BufferInfo *info); + + // Checks to see if any frames have rendered up until |until|, and to notify client + // (MediaCodec) of rendered frames up-until the frame pointed to by |until| or the first + // unrendered frame. These frames are removed from the render queue. + // If |dropIncomplete| is true, unrendered frames up-until |until| will be dropped from the + // queue, allowing all rendered framed up till then to be notified of. + // (This will effectively clear the render queue up-until (and including) |until|.) + // If |until| is NULL, or is not in the rendered queue, this method will check all frames. + void notifyOfRenderedFrames( + bool dropIncomplete = false, FrameRenderTracker::Info *until = NULL); + void sendFormatChange(const sp<AMessage> &reply); status_t getPortFormat(OMX_U32 portIndex, sp<AMessage> ¬ify); diff --git a/include/media/stagefright/AMRWriter.h b/include/media/stagefright/AMRWriter.h index 392f968..b38be55 100644 --- a/include/media/stagefright/AMRWriter.h +++ b/include/media/stagefright/AMRWriter.h @@ -26,10 +26,9 @@ namespace android { struct MediaSource; -struct MetaData; +class MetaData; struct AMRWriter : public MediaWriter { - AMRWriter(const char *filename); AMRWriter(int fd); status_t initCheck() const; diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h index 14afb85..e0cd965 100644 --- a/include/media/stagefright/AudioPlayer.h +++ b/include/media/stagefright/AudioPlayer.h @@ -25,9 +25,10 @@ namespace android { -class MediaSource; +struct AudioPlaybackRate; class AudioTrack; -class AwesomePlayer; +struct AwesomePlayer; +class MediaSource; class AudioPlayer : public TimeSource { public: @@ -73,7 +74,8 @@ public: bool isSeeking(); bool reachedEOS(status_t *finalStatus); - status_t setPlaybackRatePermille(int32_t ratePermille); + status_t setPlaybackRate(const AudioPlaybackRate &rate); + status_t getPlaybackRate(AudioPlaybackRate *rate /* nonnull */); void notifyAudioEOS(); diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h index 4c9aaad..3074910 100644 --- a/include/media/stagefright/AudioSource.h +++ b/include/media/stagefright/AudioSource.h @@ -35,8 +35,10 @@ struct AudioSource : public MediaSource, public MediaBufferObserver { // _not_ a bitmask of audio_channels_t constants. AudioSource( audio_source_t inputSource, + const String16 &opPackageName, uint32_t sampleRate, - uint32_t channels = 1); + uint32_t channels, + uint32_t outSampleRate = 0); status_t initCheck() const; @@ -77,11 +79,13 @@ private: status_t mInitCheck; bool mStarted; int32_t mSampleRate; + int32_t mOutSampleRate; bool mTrackMaxAmplitude; int64_t mStartTimeUs; int16_t mMaxAmplitude; int64_t mPrevSampleTimeUs; + int64_t mFirstSampleTimeUs; int64_t mInitialReadTimeUs; int64_t mNumFramesReceived; int64_t mNumClientOwnedBuffers; 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/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h index dd0a106..069e897 100644 --- a/include/media/stagefright/CameraSource.h +++ b/include/media/stagefright/CameraSource.h @@ -83,7 +83,7 @@ public: Size videoSize, int32_t frameRate, const sp<IGraphicBufferProducer>& surface, - bool storeMetaDataInVideoBuffers = false); + bool storeMetaDataInVideoBuffers = true); virtual ~CameraSource(); @@ -149,6 +149,8 @@ protected: int32_t mNumInputBuffers; int32_t mVideoFrameRate; int32_t mColorFormat; + int32_t mEncoderFormat; + int32_t mEncoderDataSpace; status_t mInitCheck; sp<Camera> mCamera; @@ -188,7 +190,7 @@ protected: void releaseCamera(); private: - friend class CameraSourceListener; + friend struct CameraSourceListener; Mutex mLock; Condition mFrameAvailableCondition; diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h index 1bf27a6..bb36052 100644 --- a/include/media/stagefright/CodecBase.h +++ b/include/media/stagefright/CodecBase.h @@ -26,6 +26,7 @@ namespace android { struct ABuffer; +struct PersistentSurface; struct CodecBase : public AHandler { enum { @@ -39,8 +40,10 @@ struct CodecBase : public AHandler { kWhatComponentAllocated = 'cAll', kWhatComponentConfigured = 'cCon', kWhatInputSurfaceCreated = 'isfc', + kWhatInputSurfaceAccepted = 'isfa', kWhatSignaledInputEOS = 'seos', kWhatBuffersAllocated = 'allc', + kWhatOutputFramesRendered = 'outR', }; virtual void setNotificationMessage(const sp<AMessage> &msg) = 0; @@ -48,12 +51,16 @@ struct CodecBase : public AHandler { virtual void initiateAllocateComponent(const sp<AMessage> &msg) = 0; virtual void initiateConfigureComponent(const sp<AMessage> &msg) = 0; virtual void initiateCreateInputSurface() = 0; + virtual void initiateSetInputSurface( + const sp<PersistentSurface> &surface) = 0; virtual void initiateStart() = 0; virtual void initiateShutdown(bool keepComponentAllocated = false) = 0; // require an explicit message handler virtual void onMessageReceived(const sp<AMessage> &msg) = 0; + virtual status_t setSurface(const sp<Surface> &surface) { return INVALID_OPERATION; } + virtual void signalFlush() = 0; virtual void signalResume() = 0; diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h index 3630263..dcde36f 100644 --- a/include/media/stagefright/DataSource.h +++ b/include/media/stagefright/DataSource.h @@ -32,6 +32,7 @@ namespace android { struct AMessage; struct AString; +class IDataSource; struct IMediaHTTPService; class String8; struct HTTPBase; @@ -53,11 +54,15 @@ public: HTTPBase *httpSource = NULL); static sp<DataSource> CreateMediaHTTP(const sp<IMediaHTTPService> &httpService); + static sp<DataSource> CreateFromIDataSource(const sp<IDataSource> &source); DataSource() {} virtual status_t initCheck() const = 0; + // Returns the number of bytes read, or -1 on failure. It's not an error if + // this returns zero; it just means the given offset is equal to, or + // beyond, the end of the source. virtual ssize_t readAt(off64_t offset, void *data, size_t size) = 0; // Convenience methods: diff --git a/include/media/stagefright/FrameRenderTracker.h b/include/media/stagefright/FrameRenderTracker.h new file mode 100644 index 0000000..9333e8f --- /dev/null +++ b/include/media/stagefright/FrameRenderTracker.h @@ -0,0 +1,143 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FRAME_RENDER_TRACKER_H_ + +#define FRAME_RENDER_TRACKER_H_ + +#include <utils/RefBase.h> +#include <utils/Timers.h> +#include <system/window.h> + +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/AString.h> + +#include <list> + +namespace android { + +class Fence; +class GraphicBuffer; + +struct FrameRenderTracker : public RefBase { + // Tracks the render information about a frame. Frames go through several states while + // the render information is tracked: + // + // 1. queued frame: mMediaTime and mGraphicBuffer are set for the frame. mFence is the + // queue fence (read fence). mIndex is negative, and mRenderTimeNs is invalid. + // Key characteristics: mFence is not NULL and mIndex is negative. + // + // 2. dequeued frame: mFence is updated with the dequeue fence (write fence). mIndex is set. + // Key characteristics: mFence is not NULL and mIndex is non-negative. mRenderTime is still + // invalid. + // + // 3. rendered frame or frame: mFence is cleared, mRenderTimeNs is set. + // Key characteristics: mFence is NULL. + // + struct Info { + // set by client during onFrameQueued or onFrameRendered + int64_t getMediaTimeUs() const { return mMediaTimeUs; } + + // -1 if frame is not yet rendered + nsecs_t getRenderTimeNs() const { return mRenderTimeNs; } + + // set by client during updateRenderInfoForDequeuedBuffer; -1 otherwise + ssize_t getIndex() const { return mIndex; } + + // creates information for a queued frame + Info(int64_t mediaTimeUs, const sp<GraphicBuffer> &graphicBuffer, const sp<Fence> &fence) + : mMediaTimeUs(mediaTimeUs), + mRenderTimeNs(-1), + mIndex(-1), + mGraphicBuffer(graphicBuffer), + mFence(fence) { + } + + // creates information for a frame rendered on a tunneled surface + Info(int64_t mediaTimeUs, nsecs_t renderTimeNs) + : mMediaTimeUs(mediaTimeUs), + mRenderTimeNs(renderTimeNs), + mIndex(-1), + mGraphicBuffer(NULL), + mFence(NULL) { + } + + private: + int64_t mMediaTimeUs; + nsecs_t mRenderTimeNs; + ssize_t mIndex; // to be used by client + sp<GraphicBuffer> mGraphicBuffer; + sp<Fence> mFence; + + friend class FrameRenderTracker; + }; + + FrameRenderTracker(); + + void setComponentName(const AString &componentName); + + // clears all tracked frames, and resets last render time + void clear(nsecs_t lastRenderTimeNs); + + // called when |graphicBuffer| corresponding to |mediaTimeUs| is + // queued to the output surface using |fence|. + void onFrameQueued( + int64_t mediaTimeUs, const sp<GraphicBuffer> &graphicBuffer, const sp<Fence> &fence); + + // Called when we have dequeued a buffer |buf| from the native window to track render info. + // |fenceFd| is the dequeue fence, and |index| is a positive buffer ID to be usable by the + // client to track this render info among the dequeued buffers. + // Returns pointer to the tracked info, or NULL if buffer is not tracked or if |index| + // is negative. + Info *updateInfoForDequeuedBuffer(ANativeWindowBuffer *buf, int fenceFd, int index); + + // called when tunneled codec signals frame rendered event + // returns BAD_VALUE if systemNano is not monotonic. Otherwise, returns OK. + status_t onFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano); + + // Checks to see if any frames have rendered up until |until|. If |until| is NULL or not a + // tracked info, this method searches the entire render queue. + // Returns list of rendered frames up-until the frame pointed to by |until| or the first + // unrendered frame, as well as any dropped frames (those with invalid fence) up-until |until|. + // These frames are removed from the render queue. + // If |dropIncomplete| is true, unrendered frames up-until |until| will also be dropped from the + // queue, allowing all rendered framed up till then to be notified of. + // (This will effectively clear the render queue up-until (and including) |until|.) + std::list<Info> checkFencesAndGetRenderedFrames(const Info *until, bool dropIncomplete); + + // Stop tracking a queued frame (e.g. if the frame has been discarded). If |info| is NULL or is + // not tracked, this method is a no-op. If |index| is specified, all indices larger that |index| + // are decremented. This is useful if the untracked frame is deleted from the frame vector. + void untrackFrame(const Info *info, ssize_t index = SSIZE_MAX); + + void dumpRenderQueue() const; + + virtual ~FrameRenderTracker(); + +private: + + // Render information for buffers. Regular surface buffers are queued in the order of + // rendering. Tunneled buffers are queued in the order of receipt. + std::list<Info> mRenderQueue; + nsecs_t mLastRenderTimeNs; + AString mComponentName; + + DISALLOW_EVIL_CONSTRUCTORS(FrameRenderTracker); +}; + +} // namespace android + +#endif // FRAME_RENDER_TRACKER_H_ diff --git a/include/media/stagefright/MPEG2TSWriter.h b/include/media/stagefright/MPEG2TSWriter.h index 2e2922e..3d7960b 100644 --- a/include/media/stagefright/MPEG2TSWriter.h +++ b/include/media/stagefright/MPEG2TSWriter.h @@ -29,7 +29,6 @@ struct ABuffer; struct MPEG2TSWriter : public MediaWriter { MPEG2TSWriter(int fd); - MPEG2TSWriter(const char *filename); MPEG2TSWriter( void *cookie, diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h index 26ce5f9..a195fe8 100644 --- a/include/media/stagefright/MPEG4Writer.h +++ b/include/media/stagefright/MPEG4Writer.h @@ -26,13 +26,13 @@ namespace android { +class AMessage; class MediaBuffer; class MediaSource; class MetaData; class MPEG4Writer : public MediaWriter { public: - MPEG4Writer(const char *filename); MPEG4Writer(int fd); // Limitations @@ -49,6 +49,7 @@ public: virtual status_t dump(int fd, const Vector<String16>& args); void beginBox(const char *fourcc); + void beginBox(uint32_t id); void writeInt8(int8_t x); void writeInt16(int16_t x); void writeInt32(int32_t x); @@ -63,6 +64,7 @@ public: int32_t getTimeScale() const { return mTimeScale; } status_t setGeoData(int latitudex10000, int longitudex10000); + status_t setCaptureRate(float captureFps); virtual void setStartTimeOffsetMs(int ms) { mStartTimeOffsetMs = ms; } virtual int32_t getStartTimeOffsetMs() const { return mStartTimeOffsetMs; } @@ -89,6 +91,7 @@ private: off64_t mFreeBoxOffset; bool mStreamableFile; off64_t mEstimatedMoovBoxSize; + off64_t mMoovExtraSize; uint32_t mInterleaveDurationUs; int32_t mTimeScale; int64_t mStartTimestampUs; @@ -103,6 +106,8 @@ private: List<off64_t> mBoxes; + sp<AMessage> mMetaKeys; + void setStartTimestampUs(int64_t timeUs); int64_t getStartTimestampUs(); // Not const status_t startTracks(MetaData *params); @@ -196,6 +201,12 @@ private: void writeGeoDataBox(); void writeLatitude(int degreex10000); void writeLongitude(int degreex10000); + + void addDeviceMeta(); + void writeHdlr(); + void writeKeys(); + void writeIlst(); + void writeMetaBox(); void sendSessionSummary(); void release(); status_t reset(); diff --git a/include/media/stagefright/MediaClock.h b/include/media/stagefright/MediaClock.h new file mode 100644 index 0000000..dd1a809 --- /dev/null +++ b/include/media/stagefright/MediaClock.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MEDIA_CLOCK_H_ + +#define MEDIA_CLOCK_H_ + +#include <media/stagefright/foundation/ABase.h> +#include <utils/Mutex.h> +#include <utils/RefBase.h> + +namespace android { + +struct AMessage; + +struct MediaClock : public RefBase { + MediaClock(); + + void setStartingTimeMedia(int64_t startingTimeMediaUs); + + void clearAnchor(); + // It's required to use timestamp of just rendered frame as + // anchor time in paused state. + void updateAnchor( + int64_t anchorTimeMediaUs, + int64_t anchorTimeRealUs, + int64_t maxTimeMediaUs = INT64_MAX); + + void updateMaxTimeMedia(int64_t maxTimeMediaUs); + + void setPlaybackRate(float rate); + float getPlaybackRate() const; + + // query media time corresponding to real time |realUs|, and save the + // result in |outMediaUs|. + status_t getMediaTime( + int64_t realUs, + int64_t *outMediaUs, + bool allowPastMaxTime = false) const; + // query real time corresponding to media time |targetMediaUs|. + // The result is saved in |outRealUs|. + status_t getRealTimeFor(int64_t targetMediaUs, int64_t *outRealUs) const; + +protected: + virtual ~MediaClock(); + +private: + status_t getMediaTime_l( + int64_t realUs, + int64_t *outMediaUs, + bool allowPastMaxTime) const; + + mutable Mutex mLock; + + int64_t mAnchorTimeMediaUs; + int64_t mAnchorTimeRealUs; + int64_t mMaxTimeMediaUs; + int64_t mStartingTimeMediaUs; + + float mPlaybackRate; + + DISALLOW_EVIL_CONSTRUCTORS(MediaClock); +}; + +} // namespace android + +#endif // MEDIA_CLOCK_H_ diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h index d448097..c10963d 100644 --- a/include/media/stagefright/MediaCodec.h +++ b/include/media/stagefright/MediaCodec.h @@ -20,17 +20,25 @@ #include <gui/IGraphicBufferProducer.h> #include <media/hardware/CryptoAPI.h> +#include <media/MediaResource.h> #include <media/stagefright/foundation/AHandler.h> +#include <media/stagefright/FrameRenderTracker.h> #include <utils/Vector.h> namespace android { struct ABuffer; struct AMessage; +struct AReplyToken; struct AString; struct CodecBase; -struct ICrypto; struct IBatteryStats; +struct ICrypto; +class IMemory; +struct MemoryDealer; +class IResourceManagerClient; +class IResourceManagerService; +struct PersistentSurface; struct SoftwareRenderer; struct Surface; @@ -50,15 +58,20 @@ struct MediaCodec : public AHandler { CB_OUTPUT_AVAILABLE = 2, CB_ERROR = 3, CB_OUTPUT_FORMAT_CHANGED = 4, + CB_RESOURCE_RECLAIMED = 5, }; - struct BatteryNotifier; + static const pid_t kNoPid = -1; static sp<MediaCodec> CreateByType( - const sp<ALooper> &looper, const char *mime, bool encoder, status_t *err = NULL); + const sp<ALooper> &looper, const char *mime, bool encoder, status_t *err = NULL, + pid_t pid = kNoPid); static sp<MediaCodec> CreateByComponentName( - const sp<ALooper> &looper, const char *name, status_t *err = NULL); + const sp<ALooper> &looper, const char *name, status_t *err = NULL, + pid_t pid = kNoPid); + + static sp<PersistentSurface> CreatePersistentInputSurface(); status_t configure( const sp<AMessage> &format, @@ -68,8 +81,12 @@ struct MediaCodec : public AHandler { status_t setCallback(const sp<AMessage> &callback); + status_t setOnFrameRenderedNotification(const sp<AMessage> ¬ify); + status_t createInputSurface(sp<IGraphicBufferProducer>* bufferProducer); + status_t setInputSurface(const sp<PersistentSurface> &surface); + status_t start(); // Returns to a state in which the component remains allocated but @@ -125,6 +142,8 @@ struct MediaCodec : public AHandler { status_t getOutputFormat(sp<AMessage> *format) const; status_t getInputFormat(sp<AMessage> *format) const; + status_t getWidevineLegacyBuffers(Vector<sp<ABuffer> > *buffers) const; + status_t getInputBuffers(Vector<sp<ABuffer> > *buffers) const; status_t getOutputBuffers(Vector<sp<ABuffer> > *buffers) const; @@ -132,6 +151,8 @@ struct MediaCodec : public AHandler { status_t getOutputFormat(size_t index, sp<AMessage> *format); status_t getInputBuffer(size_t index, sp<ABuffer> *buffer); + status_t setSurface(const sp<Surface> &nativeWindow); + status_t requestIDRFrame(); // Notification will be posted once there "is something to do", i.e. @@ -143,11 +164,22 @@ struct MediaCodec : public AHandler { status_t setParameters(const sp<AMessage> ¶ms); + // Create a MediaCodec notification message from a list of rendered or dropped render infos + // by adding rendered frame information to a base notification message. Returns the number + // of frames that were rendered. + static size_t CreateFramesRenderedMessage( + std::list<FrameRenderTracker::Info> done, sp<AMessage> &msg); + protected: virtual ~MediaCodec(); virtual void onMessageReceived(const sp<AMessage> &msg); private: + // used by ResourceManagerClient + status_t reclaim(); + friend struct ResourceManagerClient; + +private: enum State { UNINITIALIZED, INITIALIZING, @@ -170,7 +202,9 @@ private: enum { kWhatInit = 'init', kWhatConfigure = 'conf', + kWhatSetSurface = 'sSur', kWhatCreateInputSurface = 'cisf', + kWhatSetInputSurface = 'sisf', kWhatStart = 'strt', kWhatStop = 'stop', kWhatRelease = 'rele', @@ -191,6 +225,7 @@ private: kWhatGetName = 'getN', kWhatSetParameters = 'setP', kWhatSetCallback = 'setC', + kWhatSetNotification = 'setN', }; enum { @@ -206,39 +241,78 @@ private: kFlagGatherCodecSpecificData = 512, kFlagIsAsync = 1024, kFlagIsComponentAllocated = 2048, + kFlagPushBlankBuffersOnShutdown = 4096, }; struct BufferInfo { uint32_t mBufferID; sp<ABuffer> mData; sp<ABuffer> mEncryptedData; + sp<IMemory> mSharedEncryptedBuffer; sp<AMessage> mNotify; sp<AMessage> mFormat; bool mOwnedByClient; }; + struct ResourceManagerServiceProxy : public IBinder::DeathRecipient { + ResourceManagerServiceProxy(pid_t pid); + ~ResourceManagerServiceProxy(); + + void init(); + + // implements DeathRecipient + virtual void binderDied(const wp<IBinder>& /*who*/); + + void addResource( + int64_t clientId, + const sp<IResourceManagerClient> client, + const Vector<MediaResource> &resources); + + void removeResource(int64_t clientId); + + bool reclaimResource(const Vector<MediaResource> &resources); + + private: + Mutex mLock; + sp<IResourceManagerService> mService; + pid_t mPid; + }; + State mState; + bool mReleasedByResourceManager; sp<ALooper> mLooper; sp<ALooper> mCodecLooper; sp<CodecBase> mCodec; AString mComponentName; - uint32_t mReplyID; + sp<AReplyToken> mReplyID; uint32_t mFlags; status_t mStickyError; - sp<Surface> mNativeWindow; + sp<Surface> mSurface; SoftwareRenderer *mSoftRenderer; + sp<AMessage> mOutputFormat; sp<AMessage> mInputFormat; sp<AMessage> mCallback; + sp<AMessage> mOnFrameRenderedNotification; + sp<MemoryDealer> mDealer; + + sp<IResourceManagerClient> mResourceManagerClient; + sp<ResourceManagerServiceProxy> mResourceManagerService; bool mBatteryStatNotified; bool mIsVideo; + int32_t mVideoWidth; + int32_t mVideoHeight; + int32_t mRotationDegrees; // initial create parameters AString mInitName; bool mInitNameIsType; bool mInitIsEncoder; + // configure parameter + sp<AMessage> mConfigureMsg; + // Used only to synchronize asynchronous getBufferAndFormat // across all the other (synchronous) buffer state change // operations, such as de/queueIn/OutputBuffer, start and @@ -249,10 +323,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; @@ -261,13 +335,14 @@ private: sp<AMessage> mActivityNotify; bool mHaveInputSurface; + bool mHavePendingInputBuffers; - MediaCodec(const sp<ALooper> &looper); + MediaCodec(const sp<ALooper> &looper, pid_t pid); static status_t PostAndAwaitResponse( const sp<AMessage> &msg, sp<AMessage> *response); - static void PostReplyWithError(int32_t replyID, int32_t err); + void PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err); status_t init(const AString &name, bool nameIsType, bool encoder); @@ -283,15 +358,16 @@ 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); status_t queueCSDInputBuffer(size_t bufferIndex); - status_t setNativeWindow( - const sp<Surface> &surface); + status_t handleSetSurface(const sp<Surface> &surface); + status_t connectToSurface(const sp<Surface> &surface); + status_t disconnectFromSurface(); void postActivityNotificationIfPossible(); @@ -306,6 +382,9 @@ private: void updateBatteryStat(); bool isExecuting() const; + uint64_t getGraphicBufferSize(); + void addResource(const String8 &type, const String8 &subtype, uint64_t value); + /* called to get the last codec error when the sticky flag is set. * if no such codec error is found, returns UNKNOWN_ERROR. */ diff --git a/include/media/stagefright/MediaCodecList.h b/include/media/stagefright/MediaCodecList.h index ac7b053..bf4db87 100644 --- a/include/media/stagefright/MediaCodecList.h +++ b/include/media/stagefright/MediaCodecList.h @@ -32,6 +32,8 @@ namespace android { +extern const char *kMaxEncoderInputBuffers; + struct AMessage; struct MediaCodecList : public BnMediaCodecList { @@ -52,9 +54,17 @@ struct MediaCodecList : public BnMediaCodecList { return mCodecInfos.itemAt(index); } + virtual const sp<AMessage> getGlobalSettings() const; + // to be used by MediaPlayerService alone static sp<IMediaCodecList> getLocalInstance(); + // only to be used by getLocalInstance + static void *profilerThreadWrapper(void * /*arg*/); + + // only to be used by MediaPlayerService + void parseTopLevelXMLFile(const char *path, bool ignore_errors = false); + private: class BinderDeathObserver : public IBinder::DeathRecipient { void binderDied(const wp<IBinder> &the_late_who __unused); @@ -64,6 +74,7 @@ private: enum Section { SECTION_TOPLEVEL, + SECTION_SETTINGS, SECTION_DECODERS, SECTION_DECODER, SECTION_DECODER_TYPE, @@ -78,10 +89,14 @@ private: status_t mInitCheck; Section mCurrentSection; + bool mUpdate; Vector<Section> mPastSections; int32_t mDepth; AString mHrefBase; + sp<AMessage> mGlobalSettings; + KeyedVector<AString, CodecSettings> mOverrides; + Vector<sp<MediaCodecInfo> > mCodecInfos; sp<MediaCodecInfo> mCurrentInfo; sp<IOMX> mOMX; @@ -91,7 +106,6 @@ private: status_t initCheck() const; void parseXMLFile(const char *path); - void parseTopLevelXMLFile(const char *path); static void StartElementHandlerWrapper( void *me, const char *name, const char **attrs); @@ -102,9 +116,12 @@ private: void endElementHandler(const char *name); status_t includeXMLFile(const char **attrs); + status_t addSettingFromAttributes(const char **attrs); status_t addMediaCodecFromAttributes(bool encoder, const char **attrs); void addMediaCodec(bool encoder, const char *name, const char *type = NULL); + void setCurrentCodecInfo(bool encoder, const char *name, const char *type); + status_t addQuirk(const char **attrs); status_t addTypeFromAttributes(const char **attrs); status_t addLimit(const char **attrs); diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h index 0970b2b..71f58a9 100644 --- a/include/media/stagefright/MediaCodecSource.h +++ b/include/media/stagefright/MediaCodecSource.h @@ -23,9 +23,11 @@ namespace android { -class ALooper; +struct ALooper; class AMessage; +struct AReplyToken; class IGraphicBufferProducer; +class IGraphicBufferConsumer; class MediaCodec; class MetaData; @@ -40,6 +42,7 @@ struct MediaCodecSource : public MediaSource, const sp<ALooper> &looper, const sp<AMessage> &format, const sp<MediaSource> &source, + const sp<IGraphicBufferConsumer> &consumer = NULL, uint32_t flags = 0); bool isVideo() const { return mIsVideo; } @@ -78,6 +81,7 @@ private: const sp<ALooper> &looper, const sp<AMessage> &outputFormat, const sp<MediaSource> &source, + const sp<IGraphicBufferConsumer> &consumer, uint32_t flags = 0); status_t onStart(MetaData *params); @@ -99,13 +103,17 @@ private: sp<Puller> mPuller; sp<MediaCodec> mEncoder; uint32_t mFlags; - List<uint32_t> mStopReplyIDQueue; + List<sp<AReplyToken>> mStopReplyIDQueue; bool mIsVideo; bool mStarted; bool mStopping; bool mDoMoreWorkPending; + bool mSetEncoderFormat; + int mEncoderFormat; + int mEncoderDataSpace; sp<AMessage> mEncoderActivityNotify; sp<IGraphicBufferProducer> mGraphicBufferProducer; + sp<IGraphicBufferConsumer> mGraphicBufferConsumer; List<MediaBuffer *> mInputBufferQueue; List<size_t> mAvailEncoderInputIndices; List<int64_t> mDecodingTimeQueue; // decoding time (us) for video diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h index a0036e0..21eb04a 100644 --- a/include/media/stagefright/MediaDefs.h +++ b/include/media/stagefright/MediaDefs.h @@ -64,6 +64,7 @@ extern const char *MEDIA_MIMETYPE_TEXT_3GPP; extern const char *MEDIA_MIMETYPE_TEXT_SUBRIP; extern const char *MEDIA_MIMETYPE_TEXT_VTT; extern const char *MEDIA_MIMETYPE_TEXT_CEA_608; +extern const char *MEDIA_MIMETYPE_DATA_TIMED_ID3; } // namespace android diff --git a/include/media/stagefright/MediaFilter.h b/include/media/stagefright/MediaFilter.h new file mode 100644 index 0000000..d0a572c --- /dev/null +++ b/include/media/stagefright/MediaFilter.h @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MEDIA_FILTER_H_ +#define MEDIA_FILTER_H_ + +#include <media/stagefright/CodecBase.h> + +namespace android { + +struct ABuffer; +struct GraphicBufferListener; +struct MemoryDealer; +struct SimpleFilter; + +struct MediaFilter : public CodecBase { + MediaFilter(); + + virtual void setNotificationMessage(const sp<AMessage> &msg); + + virtual void initiateAllocateComponent(const sp<AMessage> &msg); + virtual void initiateConfigureComponent(const sp<AMessage> &msg); + virtual void initiateCreateInputSurface(); + virtual void initiateSetInputSurface(const sp<PersistentSurface> &surface); + + virtual void initiateStart(); + virtual void initiateShutdown(bool keepComponentAllocated = false); + + virtual void signalFlush(); + virtual void signalResume(); + + virtual void signalRequestIDRFrame(); + virtual void signalSetParameters(const sp<AMessage> &msg); + virtual void signalEndOfInputStream(); + + virtual void onMessageReceived(const sp<AMessage> &msg); + + struct PortDescription : public CodecBase::PortDescription { + virtual size_t countBuffers(); + virtual IOMX::buffer_id bufferIDAt(size_t index) const; + virtual sp<ABuffer> bufferAt(size_t index) const; + + protected: + PortDescription(); + + private: + friend struct MediaFilter; + + Vector<IOMX::buffer_id> mBufferIDs; + Vector<sp<ABuffer> > mBuffers; + + void addBuffer(IOMX::buffer_id id, const sp<ABuffer> &buffer); + + DISALLOW_EVIL_CONSTRUCTORS(PortDescription); + }; + +protected: + virtual ~MediaFilter(); + +private: + struct BufferInfo { + enum Status { + OWNED_BY_US, + OWNED_BY_UPSTREAM, + }; + + IOMX::buffer_id mBufferID; + int32_t mGeneration; + int32_t mOutputFlags; + Status mStatus; + + sp<ABuffer> mData; + }; + + enum State { + UNINITIALIZED, + INITIALIZED, + CONFIGURED, + STARTED, + }; + + enum { + kWhatInputBufferFilled = 'inpF', + kWhatOutputBufferDrained = 'outD', + kWhatShutdown = 'shut', + kWhatFlush = 'flus', + kWhatResume = 'resm', + kWhatAllocateComponent = 'allo', + kWhatConfigureComponent = 'conf', + kWhatCreateInputSurface = 'cisf', + kWhatSignalEndOfInputStream = 'eois', + kWhatStart = 'star', + kWhatSetParameters = 'setP', + kWhatProcessBuffers = 'proc', + }; + + enum { + kPortIndexInput = 0, + kPortIndexOutput = 1 + }; + + // member variables + AString mComponentName; + State mState; + status_t mInputEOSResult; + int32_t mWidth, mHeight; + int32_t mStride, mSliceHeight; + int32_t mColorFormatIn, mColorFormatOut; + size_t mMaxInputSize, mMaxOutputSize; + int32_t mGeneration; + sp<AMessage> mNotify; + sp<AMessage> mInputFormat; + sp<AMessage> mOutputFormat; + + sp<MemoryDealer> mDealer[2]; + Vector<BufferInfo> mBuffers[2]; + Vector<BufferInfo*> mAvailableInputBuffers; + Vector<BufferInfo*> mAvailableOutputBuffers; + bool mPortEOS[2]; + + sp<SimpleFilter> mFilter; + sp<GraphicBufferListener> mGraphicBufferListener; + + // helper functions + void signalProcessBuffers(); + void signalError(status_t error); + + status_t allocateBuffersOnPort(OMX_U32 portIndex); + BufferInfo *findBufferByID( + uint32_t portIndex, IOMX::buffer_id bufferID, + ssize_t *index = NULL); + void postFillThisBuffer(BufferInfo *info); + void postDrainThisBuffer(BufferInfo *info); + void postEOS(); + void sendFormatChange(); + void requestFillEmptyInput(); + void processBuffers(); + + void onAllocateComponent(const sp<AMessage> &msg); + void onConfigureComponent(const sp<AMessage> &msg); + void onStart(); + void onInputBufferFilled(const sp<AMessage> &msg); + void onOutputBufferDrained(const sp<AMessage> &msg); + void onShutdown(const sp<AMessage> &msg); + void onFlush(); + void onSetParameters(const sp<AMessage> &msg); + void onCreateInputSurface(); + void onInputFrameAvailable(); + void onSignalEndOfInputStream(); + + DISALLOW_EVIL_CONSTRUCTORS(MediaFilter); +}; + +} // namespace android + +#endif // MEDIA_FILTER_H_ diff --git a/include/media/stagefright/MediaMuxer.h b/include/media/stagefright/MediaMuxer.h index 9da98d9..fa855a8 100644 --- a/include/media/stagefright/MediaMuxer.h +++ b/include/media/stagefright/MediaMuxer.h @@ -29,9 +29,9 @@ namespace android { struct ABuffer; struct AMessage; struct MediaAdapter; -struct MediaBuffer; +class MediaBuffer; struct MediaSource; -struct MetaData; +class MetaData; struct MediaWriter; // MediaMuxer is used to mux multiple tracks into a video. Currently, we only @@ -50,9 +50,6 @@ public: OUTPUT_FORMAT_LIST_END // must be last - used to validate format type }; - // Construct the muxer with the output file path. - MediaMuxer(const char *path, OutputFormat format); - // Construct the muxer with the file descriptor. Note that the MediaMuxer // will close this file at stop(). MediaMuxer(int fd, OutputFormat format); diff --git a/include/media/stagefright/MediaSync.h b/include/media/stagefright/MediaSync.h new file mode 100644 index 0000000..ef8cb23 --- /dev/null +++ b/include/media/stagefright/MediaSync.h @@ -0,0 +1,291 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MEDIA_SYNC_H +#define MEDIA_SYNC_H + +#include <gui/IConsumerListener.h> +#include <gui/IProducerListener.h> + +#include <media/AudioResamplerPublic.h> +#include <media/AVSyncSettings.h> +#include <media/stagefright/foundation/AHandler.h> + +#include <utils/Condition.h> +#include <utils/KeyedVector.h> +#include <utils/Mutex.h> + +namespace android { + +class AudioTrack; +class BufferItem; +class Fence; +class GraphicBuffer; +class IGraphicBufferConsumer; +class IGraphicBufferProducer; +struct MediaClock; +struct VideoFrameScheduler; + +// MediaSync manages media playback and its synchronization to a media clock +// source. It can be also used for video-only playback. +// +// For video playback, it requires an output surface and provides an input +// surface. It then controls the rendering of input buffers (buffer queued to +// the input surface) on the output surface to happen at the appropriate time. +// +// For audio playback, it requires an audio track and takes updates of +// information of rendered audio data to maintain media clock when audio track +// serves as media clock source. (TODO: move audio rendering from JAVA to +// native code). +// +// It can use the audio or video track as media clock source, as well as an +// external clock. (TODO: actually support external clock as media clock +// sources; use video track as media clock source for audio-and-video stream). +// +// In video-only mode, MediaSync will playback every video frame even though +// a video frame arrives late based on its timestamp and last frame's. +// +// The client needs to configure surface (for output video rendering) and audio +// track (for querying information of audio rendering) for MediaSync. +// +// Then the client needs to obtain a surface from MediaSync and render video +// frames onto that surface. Internally, the MediaSync will receive those video +// frames and render them onto the output surface at the appropriate time. +// +// The client needs to call updateQueuedAudioData() immediately after it writes +// audio data to the audio track. Such information will be used to update media +// clock. +// +class MediaSync : public AHandler { +public: + // Create an instance of MediaSync. + static sp<MediaSync> create(); + + // Called when MediaSync is used to render video. It should be called + // before createInputSurface(). + status_t setSurface(const sp<IGraphicBufferProducer> &output); + + // Called when audio track is used as media clock source. It should be + // called before updateQueuedAudioData(). + status_t setAudioTrack(const sp<AudioTrack> &audioTrack); + + // Create a surface for client to render video frames. This is the surface + // on which the client should render video frames. Those video frames will + // be internally directed to output surface for rendering at appropriate + // time. + status_t createInputSurface(sp<IGraphicBufferProducer> *outBufferProducer); + + // Update just-rendered audio data size and the presentation timestamp of + // the first frame of that audio data. It should be called immediately + // after the client write audio data into AudioTrack. + // This function assumes continous audio stream. + // TODO: support gap or backwards updates. + status_t updateQueuedAudioData( + size_t sizeInBytes, int64_t presentationTimeUs); + + // Set the consumer name of the input queue. + void setName(const AString &name); + + // Get the media clock used by the MediaSync so that the client can obtain + // corresponding media time or real time via + // MediaClock::getMediaTime() and MediaClock::getRealTimeFor(). + sp<const MediaClock> getMediaClock(); + + // Flush mediasync + void flush(); + + // Set the video frame rate hint - this is used by the video FrameScheduler + status_t setVideoFrameRateHint(float rate); + + // Get the video frame rate measurement from the FrameScheduler + // returns -1 if there is no measurement + float getVideoFrameRate(); + + // Set the sync settings parameters. + status_t setSyncSettings(const AVSyncSettings &syncSettings); + + // Gets the sync settings parameters. + void getSyncSettings(AVSyncSettings *syncSettings /* nonnull */); + + // Sets the playback rate using playback settings. + // This method can be called any time. + status_t setPlaybackSettings(const AudioPlaybackRate &rate); + + // Gets the playback rate (playback settings parameters). + void getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */); + + // Get the play time for pending audio frames in audio sink. + status_t getPlayTimeForPendingAudioFrames(int64_t *outTimeUs); + +protected: + virtual void onMessageReceived(const sp<AMessage> &msg); + +private: + enum { + kWhatDrainVideo = 'dVid', + }; + + // This is a thin wrapper class that lets us listen to + // IConsumerListener::onFrameAvailable from mInput. + class InputListener : public BnConsumerListener, + public IBinder::DeathRecipient { + public: + InputListener(const sp<MediaSync> &sync); + virtual ~InputListener(); + + // From IConsumerListener + virtual void onFrameAvailable(const BufferItem &item); + + // From IConsumerListener + // We don't care about released buffers because we detach each buffer as + // soon as we acquire it. See the comment for onBufferReleased below for + // some clarifying notes about the name. + virtual void onBuffersReleased() {} + + // From IConsumerListener + // We don't care about sideband streams, since we won't relay them. + virtual void onSidebandStreamChanged(); + + // From IBinder::DeathRecipient + virtual void binderDied(const wp<IBinder> &who); + + private: + sp<MediaSync> mSync; + }; + + // This is a thin wrapper class that lets us listen to + // IProducerListener::onBufferReleased from mOutput. + class OutputListener : public BnProducerListener, + public IBinder::DeathRecipient { + public: + OutputListener(const sp<MediaSync> &sync, const sp<IGraphicBufferProducer> &output); + virtual ~OutputListener(); + + // From IProducerListener + virtual void onBufferReleased(); + + // From IBinder::DeathRecipient + virtual void binderDied(const wp<IBinder> &who); + + private: + sp<MediaSync> mSync; + sp<IGraphicBufferProducer> mOutput; + }; + + // mIsAbandoned is set to true when the input or output dies. + // Once the MediaSync has been abandoned by one side, it will disconnect + // from the other side and not attempt to communicate with it further. + bool mIsAbandoned; + + mutable Mutex mMutex; + Condition mReleaseCondition; + size_t mNumOutstandingBuffers; + sp<IGraphicBufferConsumer> mInput; + sp<IGraphicBufferProducer> mOutput; + int mUsageFlagsFromOutput; + uint32_t mMaxAcquiredBufferCount; // max acquired buffer count + bool mReturnPendingInputFrame; // set while we are pending before acquiring an input frame + + sp<AudioTrack> mAudioTrack; + uint32_t mNativeSampleRateInHz; + int64_t mNumFramesWritten; + bool mHasAudio; + + int64_t mNextBufferItemMediaUs; + List<BufferItem> mBufferItems; + sp<VideoFrameScheduler> mFrameScheduler; + + // Keep track of buffers received from |mInput|. This is needed because + // it's possible the consumer of |mOutput| could return a different + // GraphicBuffer::handle (e.g., due to passing buffers through IPC), + // and that could cause problem if the producer of |mInput| only + // supports pre-registered buffers. + KeyedVector<uint64_t, sp<GraphicBuffer> > mBuffersFromInput; + + // Keep track of buffers sent to |mOutput|. When a new output surface comes + // in, those buffers will be returned to input and old output surface will + // be disconnected immediately. + KeyedVector<uint64_t, sp<GraphicBuffer> > mBuffersSentToOutput; + + sp<ALooper> mLooper; + float mPlaybackRate; + + AudioPlaybackRate mPlaybackSettings; + AVSyncSettings mSyncSettings; + + sp<MediaClock> mMediaClock; + + MediaSync(); + + // Must be accessed through RefBase + virtual ~MediaSync(); + + int64_t getRealTime(int64_t mediaTimeUs, int64_t nowUs); + int64_t getDurationIfPlayedAtNativeSampleRate_l(int64_t numFrames); + int64_t getPlayedOutAudioDurationMedia_l(int64_t nowUs); + + void onDrainVideo_l(); + + // This implements the onFrameAvailable callback from IConsumerListener. + // It gets called from an InputListener. + // During this callback, we detach the buffer from the input, and queue + // it for rendering on the output. This call can block if there are too + // many outstanding buffers. If it blocks, it will resume when + // onBufferReleasedByOutput releases a buffer back to the input. + void onFrameAvailableFromInput(); + + // Send |bufferItem| to the output for rendering. + void renderOneBufferItem_l(const BufferItem &bufferItem); + + // This implements the onBufferReleased callback from IProducerListener. + // It gets called from an OutputListener. + // During this callback, we detach the buffer from the output, and release + // it to the input. A blocked onFrameAvailable call will be allowed to proceed. + void onBufferReleasedByOutput(sp<IGraphicBufferProducer> &output); + + // Return |buffer| back to the input. + void returnBufferToInput_l(const sp<GraphicBuffer> &buffer, const sp<Fence> &fence); + + // When this is called, the MediaSync disconnects from (i.e., abandons) its + // input or output, and signals any waiting onFrameAvailable calls to wake + // up. This must be called with mMutex locked. + void onAbandoned_l(bool isInput); + + // Set the playback in a desired speed. + // This method can be called any time. + // |rate| is the ratio between desired speed and the normal one, and should + // be non-negative. The meaning of rate values: + // 1.0 -- normal playback + // 0.0 -- stop or pause + // larger than 1.0 -- faster than normal speed + // between 0.0 and 1.0 -- slower than normal speed + void updatePlaybackRate_l(float rate); + + // apply new sync settings + void resync_l(); + + // apply playback settings only - without resyncing or updating playback rate + status_t setPlaybackSettings_l(const AudioPlaybackRate &rate); + + // helper. + bool isPlaying() { return mPlaybackRate != 0.0; } + + DISALLOW_EVIL_CONSTRUCTORS(MediaSync); +}; + +} // namespace android + +#endif diff --git a/include/media/stagefright/MediaWriter.h b/include/media/stagefright/MediaWriter.h index e27ea1d..8e02506 100644 --- a/include/media/stagefright/MediaWriter.h +++ b/include/media/stagefright/MediaWriter.h @@ -24,7 +24,7 @@ namespace android { struct MediaSource; -struct MetaData; +class MetaData; struct MediaWriter : public RefBase { MediaWriter() diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h index 3f42790..8d4e15a 100644 --- a/include/media/stagefright/MetaData.h +++ b/include/media/stagefright/MetaData.h @@ -70,11 +70,15 @@ enum { kKeyDriftTime = 'dftT', // int64_t (usecs) kKeyAnchorTime = 'ancT', // int64_t (usecs) kKeyDuration = 'dura', // int64_t (usecs) - kKeyColorFormat = 'colf', + kKeyPixelFormat = 'pixf', // int32_t + kKeyColorFormat = 'colf', // int32_t + kKeyColorSpace = 'cols', // int32_t kKeyPlatformPrivate = 'priv', // pointer kKeyDecoderComponent = 'decC', // cstring kKeyBufferID = 'bfID', kKeyMaxInputSize = 'inpS', + kKeyMaxWidth = 'maxW', + kKeyMaxHeight = 'maxH', kKeyThumbnailTime = 'thbT', // int64_t (usecs) kKeyTrackID = 'trID', kKeyIsDRM = 'idrm', // int32_t (bool) @@ -98,6 +102,7 @@ enum { kKeyCompilation = 'cpil', // cstring kKeyLocation = 'loc ', // cstring kKeyTimeScale = 'tmsl', // int32_t + kKeyCaptureFramerate = 'capF', // float (capture fps) // video profile and level kKeyVideoProfile = 'vprf', // int32_t @@ -173,6 +178,9 @@ enum { kKeyTrackIsDefault = 'dflt', // bool (int32_t) // Similar to MediaFormat.KEY_IS_FORCED_SUBTITLE but pertains to av tracks as well. kKeyTrackIsForced = 'frcd', // bool (int32_t) + + // H264 supplemental enhancement information offsets/sizes + kKeySEI = 'sei ', // raw data }; enum { diff --git a/include/media/stagefright/NativeWindowWrapper.h b/include/media/stagefright/NativeWindowWrapper.h deleted file mode 100644 index cfeec22..0000000 --- a/include/media/stagefright/NativeWindowWrapper.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef NATIVE_WINDOW_WRAPPER_H_ - -#define NATIVE_WINDOW_WRAPPER_H_ - -#include <gui/Surface.h> - -namespace android { - -// Surface derives from ANativeWindow which derives from multiple -// base classes, in order to carry it in AMessages, we'll temporarily wrap it -// into a NativeWindowWrapper. - -struct NativeWindowWrapper : RefBase { - NativeWindowWrapper( - const sp<Surface> &surfaceTextureClient) : - mSurfaceTextureClient(surfaceTextureClient) { } - - sp<ANativeWindow> getNativeWindow() const { - return mSurfaceTextureClient; - } - - sp<Surface> getSurfaceTextureClient() const { - return mSurfaceTextureClient; - } - -private: - const sp<Surface> mSurfaceTextureClient; - - DISALLOW_EVIL_CONSTRUCTORS(NativeWindowWrapper); -}; - -} // namespace android - -#endif // NATIVE_WINDOW_WRAPPER_H_ diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h index 402e7f8..fd74452 100644 --- a/include/media/stagefright/NuMediaExtractor.h +++ b/include/media/stagefright/NuMediaExtractor.h @@ -30,12 +30,12 @@ namespace android { struct ABuffer; struct AMessage; -struct DataSource; +class DataSource; struct IMediaHTTPService; -struct MediaBuffer; +class MediaBuffer; struct MediaExtractor; struct MediaSource; -struct MetaData; +class MetaData; struct NuMediaExtractor : public RefBase { enum SampleFlags { diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h index 84b1b1a..7fabcb3 100644 --- a/include/media/stagefright/OMXCodec.h +++ b/include/media/stagefright/OMXCodec.h @@ -298,7 +298,6 @@ private: status_t queueBufferToNativeWindow(BufferInfo *info); status_t cancelBufferToNativeWindow(BufferInfo *info); BufferInfo* dequeueBufferFromNativeWindow(); - status_t pushBlankBuffersToNativeWindow(); status_t freeBuffersOnPort( OMX_U32 portIndex, bool onlyThoseWeOwn = false); @@ -347,7 +346,6 @@ private: status_t configureCodec(const sp<MetaData> &meta); - status_t applyRotation(); status_t waitForBufferFilled_l(); int64_t getDecodingTimeUs(); diff --git a/include/media/stagefright/PersistentSurface.h b/include/media/stagefright/PersistentSurface.h new file mode 100644 index 0000000..a35b9f1 --- /dev/null +++ b/include/media/stagefright/PersistentSurface.h @@ -0,0 +1,51 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PERSISTENT_SURFACE_H_ + +#define PERSISTENT_SURFACE_H_ + +#include <gui/IGraphicBufferProducer.h> +#include <gui/IGraphicBufferConsumer.h> +#include <media/stagefright/foundation/ABase.h> + +namespace android { + +struct PersistentSurface : public RefBase { + PersistentSurface( + const sp<IGraphicBufferProducer>& bufferProducer, + const sp<IGraphicBufferConsumer>& bufferConsumer) : + mBufferProducer(bufferProducer), + mBufferConsumer(bufferConsumer) { } + + sp<IGraphicBufferProducer> getBufferProducer() const { + return mBufferProducer; + } + + sp<IGraphicBufferConsumer> getBufferConsumer() const { + return mBufferConsumer; + } + +private: + const sp<IGraphicBufferProducer> mBufferProducer; + const sp<IGraphicBufferConsumer> mBufferConsumer; + + DISALLOW_EVIL_CONSTRUCTORS(PersistentSurface); +}; + +} // namespace android + +#endif // PERSISTENT_SURFACE_H_ diff --git a/include/media/stagefright/ProcessInfo.h b/include/media/stagefright/ProcessInfo.h new file mode 100644 index 0000000..ec0cdff --- /dev/null +++ b/include/media/stagefright/ProcessInfo.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PROCESS_INFO_H_ + +#define PROCESS_INFO_H_ + +#include <media/stagefright/foundation/ABase.h> +#include <media/stagefright/ProcessInfoInterface.h> + +namespace android { + +struct ProcessInfo : public ProcessInfoInterface { + ProcessInfo(); + + virtual bool getPriority(int pid, int* priority); + +protected: + virtual ~ProcessInfo(); + +private: + DISALLOW_EVIL_CONSTRUCTORS(ProcessInfo); +}; + +} // namespace android + +#endif // PROCESS_INFO_H_ diff --git a/include/media/stagefright/ProcessInfoInterface.h b/include/media/stagefright/ProcessInfoInterface.h new file mode 100644 index 0000000..222f92d --- /dev/null +++ b/include/media/stagefright/ProcessInfoInterface.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PROCESS_INFO_INTERFACE_H_ +#define PROCESS_INFO_INTERFACE_H_ + +#include <utils/RefBase.h> + +namespace android { + +struct ProcessInfoInterface : public RefBase { + virtual bool getPriority(int pid, int* priority) = 0; + +protected: + virtual ~ProcessInfoInterface() {} +}; + +} // namespace android + +#endif // PROCESS_INFO_INTERFACE_H_ diff --git a/include/media/stagefright/RenderScriptWrapper.h b/include/media/stagefright/RenderScriptWrapper.h new file mode 100644 index 0000000..b42649e --- /dev/null +++ b/include/media/stagefright/RenderScriptWrapper.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RENDERSCRIPT_WRAPPER_H_ +#define RENDERSCRIPT_WRAPPER_H_ + +#include <RenderScript.h> + +namespace android { + +struct RenderScriptWrapper : public RefBase { +public: + struct RSFilterCallback : public RefBase { + public: + // called by RSFilter to process each input buffer + virtual status_t processBuffers( + RSC::Allocation* inBuffer, + RSC::Allocation* outBuffer) = 0; + + virtual status_t handleSetParameters(const sp<AMessage> &msg) = 0; + }; + + sp<RSFilterCallback> mCallback; + RSC::sp<RSC::RS> mContext; +}; + +} // namespace android + +#endif // RENDERSCRIPT_WRAPPER_H_ diff --git a/include/media/stagefright/SurfaceUtils.h b/include/media/stagefright/SurfaceUtils.h new file mode 100644 index 0000000..c1a9c0a --- /dev/null +++ b/include/media/stagefright/SurfaceUtils.h @@ -0,0 +1,34 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SURFACE_UTILS_H_ + +#define SURFACE_UTILS_H_ + +#include <utils/Errors.h> + +struct ANativeWindow; + +namespace android { + +status_t setNativeWindowSizeFormatAndUsage( + ANativeWindow *nativeWindow /* nonnull */, + int width, int height, int format, int rotation, int usage); +status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */); + +} // namespace android + +#endif // SURFACE_UTILS_H_ diff --git a/include/media/stagefright/Utils.h b/include/media/stagefright/Utils.h index a795c80..5e9d7d4 100644 --- a/include/media/stagefright/Utils.h +++ b/include/media/stagefright/Utils.h @@ -41,7 +41,7 @@ uint64_t U64LE_AT(const uint8_t *ptr); uint64_t ntoh64(uint64_t x); uint64_t hton64(uint64_t x); -struct MetaData; +class MetaData; struct AMessage; status_t convertMetaDataToMessage( const sp<MetaData> &meta, sp<AMessage> *format); @@ -65,6 +65,26 @@ bool canOffloadStream(const sp<MetaData>& meta, bool hasVideo, AString uriDebugString(const AString &uri, bool incognito = false); +struct HLSTime { + int32_t mSeq; + int64_t mTimeUs; + sp<AMessage> mMeta; + + HLSTime(const sp<AMessage> &meta = NULL); + int64_t getSegmentTimeUs() const; +}; + +bool operator <(const HLSTime &t0, const HLSTime &t1); + +// read and write various object to/from AMessage + +void writeToAMessage(sp<AMessage> msg, const AudioPlaybackRate &rate); +void readFromAMessage(const sp<AMessage> &msg, AudioPlaybackRate *rate /* nonnull */); + +void writeToAMessage(sp<AMessage> msg, const AVSyncSettings &sync, float videoFpsHint); +void readFromAMessage( + const sp<AMessage> &msg, AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */); + } // namespace android #endif // UTILS_H_ diff --git a/include/media/stagefright/VideoFrameScheduler.h b/include/media/stagefright/VideoFrameScheduler.h new file mode 100644 index 0000000..9d97dfd --- /dev/null +++ b/include/media/stagefright/VideoFrameScheduler.h @@ -0,0 +1,103 @@ +/* + * Copyright 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef VIDEO_FRAME_SCHEDULER_H_ +#define VIDEO_FRAME_SCHEDULER_H_ + +#include <utils/RefBase.h> +#include <utils/Timers.h> + +#include <media/stagefright/foundation/ABase.h> + +namespace android { + +class ISurfaceComposer; + +struct VideoFrameScheduler : public RefBase { + VideoFrameScheduler(); + + // (re)initialize scheduler + void init(float videoFps = -1); + // use in case of video render-time discontinuity, e.g. seek + void restart(); + // get adjusted nanotime for a video frame render at renderTime + nsecs_t schedule(nsecs_t renderTime); + + // returns the vsync period for the main display + nsecs_t getVsyncPeriod(); + + // returns the current frames-per-second, or 0.f if not primed + float getFrameRate(); + + void release(); + + static const size_t kHistorySize = 8; + +protected: + virtual ~VideoFrameScheduler(); + +private: + struct PLL { + PLL(); + + // reset PLL to new PLL + void reset(float fps = -1); + // keep current estimate, but restart phase + void restart(); + // returns period or 0 if not yet primed + nsecs_t addSample(nsecs_t time); + nsecs_t getPeriod() const; + + private: + nsecs_t mPeriod; + nsecs_t mPhase; + + bool mPrimed; // have an estimate for the period + size_t mSamplesUsedForPriming; + + nsecs_t mLastTime; // last input time + nsecs_t mRefitAt; // next input time to fit at + + size_t mNumSamples; // can go past kHistorySize + nsecs_t mTimes[kHistorySize]; + + void test(); + // returns whether fit was successful + bool fit(nsecs_t phase, nsecs_t period, size_t numSamples, + int64_t *a, int64_t *b, int64_t *err); + void prime(size_t numSamples); + }; + + void updateVsync(); + + nsecs_t mVsyncTime; // vsync timing from display + nsecs_t mVsyncPeriod; + nsecs_t mVsyncRefreshAt; // next time to refresh timing info + + nsecs_t mLastVsyncTime; // estimated vsync time for last frame + nsecs_t mTimeCorrection; // running adjustment + + PLL mPll; // PLL for video frame rate based on render time + + sp<ISurfaceComposer> mComposer; + + DISALLOW_EVIL_CONSTRUCTORS(VideoFrameScheduler); +}; + +} // namespace android + +#endif // VIDEO_FRAME_SCHEDULER_H_ + 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/ADebug.h b/include/media/stagefright/foundation/ADebug.h index 1d0e2cb..65f415a 100644 --- a/include/media/stagefright/foundation/ADebug.h +++ b/include/media/stagefright/foundation/ADebug.h @@ -24,6 +24,31 @@ #include <media/stagefright/foundation/AString.h> #include <utils/Log.h> +inline static const char *asString(android::status_t i, const char *def = "??") { + using namespace android; + switch (i) { + case NO_ERROR: return "NO_ERROR"; + case UNKNOWN_ERROR: return "UNKNOWN_ERROR"; + case NO_MEMORY: return "NO_MEMORY"; + case INVALID_OPERATION: return "INVALID_OPERATION"; + case BAD_VALUE: return "BAD_VALUE"; + case BAD_TYPE: return "BAD_TYPE"; + case NAME_NOT_FOUND: return "NAME_NOT_FOUND"; + case PERMISSION_DENIED: return "PERMISSION_DENIED"; + case NO_INIT: return "NO_INIT"; + case ALREADY_EXISTS: return "ALREADY_EXISTS"; + case DEAD_OBJECT: return "DEAD_OBJECT"; + case FAILED_TRANSACTION: return "FAILED_TRANSACTION"; + case BAD_INDEX: return "BAD_INDEX"; + case NOT_ENOUGH_DATA: return "NOT_ENOUGH_DATA"; + case WOULD_BLOCK: return "WOULD_BLOCK"; + case TIMED_OUT: return "TIMED_OUT"; + case UNKNOWN_TRANSACTION: return "UNKNOWN_TRANSACTION"; + case FDS_NOT_ALLOWED: return "FDS_NOT_ALLOWED"; + default: return def; + } +} + namespace android { #define LITERAL_TO_STRING_INTERNAL(x) #x @@ -92,7 +117,7 @@ struct ADebug { }; - // parse the property or string to get the debug level for a component name + // parse the property or string to get a long-type level for a component name // string format is: // <level>[:<glob>][,<level>[:<glob>]...] // - <level> is 0-5 corresponding to ADebug::Level @@ -100,14 +125,38 @@ struct ADebug { // matches all components // - string is read left-to-right, and the last matching level is returned, or // the def if no terms matched + static long GetLevelFromSettingsString( + const char *name, const char *value, long def); + static long GetLevelFromProperty( + const char *name, const char *value, long def); + + // same for ADebug::Level - performs clamping to valid debug ranges static Level GetDebugLevelFromProperty( const char *name, const char *propertyName, Level def = kDebugNone); - static Level GetDebugLevelFromString( - const char *name, const char *value, Level def = kDebugNone); // remove redundant segments of a codec name, and return a newly allocated // string suitable for debugging static char *GetDebugName(const char *name); + + inline static bool isExperimentEnabled( + const char *name __unused /* nonnull */, bool allow __unused = true) { +#ifdef ENABLE_STAGEFRIGHT_EXPERIMENTS + if (!strcmp(name, "legacy-adaptive")) { + return getExperimentFlag(allow, name, 2, 1); // every other day + } else if (!strcmp(name, "legacy-setsurface")) { + return getExperimentFlag(allow, name, 3, 1); // every third day + } else { + ALOGE("unknown experiment '%s' (disabled)", name); + } +#endif + return false; + } + +private: + // pass in allow, so we can print in the log if the experiment is disabled + static bool getExperimentFlag( + bool allow, const char *name, uint64_t modulo, uint64_t limit, + uint64_t plus = 0, uint64_t timeDivisor = 24 * 60 * 60 /* 1 day */); }; } // namespace android diff --git a/include/media/stagefright/foundation/AHandler.h b/include/media/stagefright/foundation/AHandler.h index 41ade77..fe02a86 100644 --- a/include/media/stagefright/foundation/AHandler.h +++ b/include/media/stagefright/foundation/AHandler.h @@ -29,6 +29,7 @@ struct AMessage; struct AHandler : public RefBase { AHandler() : mID(0), + mVerboseStats(false), mMessageCounter(0) { } @@ -36,23 +37,40 @@ struct AHandler : public RefBase { return mID; } - sp<ALooper> looper(); + sp<ALooper> looper() const { + return mLooper.promote(); + } + + wp<ALooper> getLooper() const { + return mLooper; + } + + wp<AHandler> getHandler() const { + // allow getting a weak reference to a const handler + return const_cast<AHandler *>(this); + } protected: virtual void onMessageReceived(const sp<AMessage> &msg) = 0; private: - friend struct ALooperRoster; + friend struct AMessage; // deliverMessage() + friend struct ALooperRoster; // setID() ALooper::handler_id mID; + wp<ALooper> mLooper; - void setID(ALooper::handler_id id) { + inline void setID(ALooper::handler_id id, wp<ALooper> looper) { mID = id; + mLooper = looper; } + bool mVerboseStats; uint32_t mMessageCounter; KeyedVector<uint32_t, uint32_t> mMessages; + void deliverMessage(const sp<AMessage> &msg); + DISALLOW_EVIL_CONSTRUCTORS(AHandler); }; diff --git a/include/media/stagefright/foundation/ALooper.h b/include/media/stagefright/foundation/ALooper.h index 70e0c5e..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; @@ -53,11 +54,15 @@ struct ALooper : public RefBase { static int64_t GetNowUs(); + const char *getName() const { + return mName.c_str(); + } + protected: virtual ~ALooper(); private: - friend struct ALooperRoster; + friend struct AMessage; // post() struct Event { int64_t mWhenUs; @@ -75,12 +80,32 @@ 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); }; -} // namespace android +} // namespace android #endif // A_LOOPER_H_ diff --git a/include/media/stagefright/foundation/ALooperRoster.h b/include/media/stagefright/foundation/ALooperRoster.h index a0be8eb..9912455 100644 --- a/include/media/stagefright/foundation/ALooperRoster.h +++ b/include/media/stagefright/foundation/ALooperRoster.h @@ -33,16 +33,6 @@ struct ALooperRoster { void unregisterHandler(ALooper::handler_id handlerID); void unregisterStaleHandlers(); - status_t postMessage(const sp<AMessage> &msg, int64_t delayUs = 0); - void deliverMessage(const sp<AMessage> &msg); - - status_t postAndAwaitResponse( - const sp<AMessage> &msg, sp<AMessage> *response); - - void postReply(uint32_t replyID, const sp<AMessage> &reply); - - sp<ALooper> findLooper(ALooper::handler_id handlerID); - void dump(int fd, const Vector<String16>& args); private: @@ -54,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 a9e235b..83b9444 100644 --- a/include/media/stagefright/foundation/AMessage.h +++ b/include/media/stagefright/foundation/AMessage.h @@ -26,11 +26,41 @@ namespace android { struct ABuffer; +struct AHandler; struct AString; -struct Parcel; +class 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(uint32_t what = 0, ALooper::handler_id target = 0); + AMessage(); + AMessage(uint32_t what, const sp<const AHandler> &handler); static sp<AMessage> FromParcel(const Parcel &parcel); void writeToParcel(Parcel *parcel) const; @@ -38,8 +68,7 @@ struct AMessage : public RefBase { void setWhat(uint32_t what); uint32_t what() const; - void setTarget(ALooper::handler_id target); - ALooper::handler_id target() const; + void setTarget(const sp<const AHandler> &handler); void clear(); @@ -76,18 +105,22 @@ struct AMessage : public RefBase { const char *name, int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const; - void post(int64_t delayUs = 0); + status_t post(int64_t delayUs = 0); // Posts the message to its target and waits for a response (or error) // before returning. 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; + // 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); - void postReply(uint32_t 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 @@ -117,9 +150,16 @@ protected: virtual ~AMessage(); private: + friend struct ALooper; // deliver() + uint32_t mWhat; + + // used only for debugging ALooper::handler_id mTarget; + wp<AHandler> mHandler; + wp<ALooper> mLooper; + struct Rect { int32_t mLeft, mTop, mRight, mBottom; }; @@ -157,6 +197,8 @@ private: size_t findItemIndex(const char *name, size_t len) const; + void deliver(); + DISALLOW_EVIL_CONSTRUCTORS(AMessage); }; diff --git a/include/media/stagefright/foundation/AString.h b/include/media/stagefright/foundation/AString.h index 822dbb3..2f6d532 100644 --- a/include/media/stagefright/foundation/AString.h +++ b/include/media/stagefright/foundation/AString.h @@ -24,7 +24,7 @@ namespace android { class String8; -struct Parcel; +class Parcel; struct AString { AString(); diff --git a/include/media/stagefright/timedtext/TimedTextDriver.h b/include/media/stagefright/timedtext/TimedTextDriver.h index 37ef674..6f7c693 100644 --- a/include/media/stagefright/timedtext/TimedTextDriver.h +++ b/include/media/stagefright/timedtext/TimedTextDriver.h @@ -24,7 +24,7 @@ namespace android { -class ALooper; +struct ALooper; struct IMediaHTTPService; class MediaPlayerBase; class MediaSource; |