diff options
41 files changed, 1162 insertions, 725 deletions
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h index d7b5f97..3efa74c 100644 --- a/include/media/AudioTrack.h +++ b/include/media/AudioTrack.h @@ -59,9 +59,11 @@ public: // voluntary invalidation by mediaserver, or mediaserver crash. EVENT_STREAM_END = 7, // Sent after all the buffers queued in AF and HW are played // back (after stop is called) +#if 0 // FIXME not yet implemented EVENT_NEW_TIMESTAMP = 8, // Delivered periodically and when there's a significant change // in the mapping from frame position to presentation time. // See AudioTimestamp for the information included with event. +#endif }; /* Client should declare a Buffer and pass the address to obtainBuffer() diff --git a/include/media/IOMX.h b/include/media/IOMX.h index d33d142..26cc73e 100644 --- a/include/media/IOMX.h +++ b/include/media/IOMX.h @@ -25,6 +25,8 @@ #include <utils/List.h> #include <utils/String8.h> +#include <media/hardware/MetadataBufferType.h> + #include <OMX_Core.h> #include <OMX_Video.h> @@ -81,8 +83,10 @@ public: virtual status_t getState( node_id node, OMX_STATETYPE* state) = 0; + // This will set *type to previous metadata buffer type on OMX error (not on binder error), and + // new metadata buffer type on success. virtual status_t storeMetaDataInBuffers( - node_id node, OMX_U32 port_index, OMX_BOOL enable) = 0; + node_id node, OMX_U32 port_index, OMX_BOOL enable, MetadataBufferType *type = NULL) = 0; virtual status_t prepareForAdaptivePlayback( node_id node, OMX_U32 portIndex, OMX_BOOL enable, @@ -98,9 +102,10 @@ public: virtual status_t getGraphicBufferUsage( node_id node, OMX_U32 port_index, OMX_U32* usage) = 0; + // Use |params| as an OMX buffer, but limit the size of the OMX buffer to |allottedSize|. virtual status_t useBuffer( node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, - buffer_id *buffer) = 0; + buffer_id *buffer, OMX_U32 allottedSize) = 0; virtual status_t useGraphicBuffer( node_id node, OMX_U32 port_index, @@ -110,17 +115,23 @@ public: node_id node, OMX_U32 port_index, const sp<GraphicBuffer> &graphicBuffer, buffer_id buffer) = 0; + // This will set *type to resulting metadata buffer type on OMX error (not on binder error) as + // well as on success. virtual status_t createInputSurface( node_id node, OMX_U32 port_index, - sp<IGraphicBufferProducer> *bufferProducer) = 0; + sp<IGraphicBufferProducer> *bufferProducer, + MetadataBufferType *type = NULL) = 0; virtual status_t createPersistentInputSurface( sp<IGraphicBufferProducer> *bufferProducer, sp<IGraphicBufferConsumer> *bufferConsumer) = 0; + // This will set *type to resulting metadata buffer type on OMX error (not on binder error) as + // well as on success. virtual status_t setInputSurface( node_id node, OMX_U32 port_index, - const sp<IGraphicBufferConsumer> &bufferConsumer) = 0; + const sp<IGraphicBufferConsumer> &bufferConsumer, + MetadataBufferType *type) = 0; virtual status_t signalEndOfInputStream(node_id node) = 0; @@ -132,9 +143,11 @@ public: node_id node, OMX_U32 port_index, size_t size, buffer_id *buffer, void **buffer_data) = 0; + // Allocate an OMX buffer of size |allotedSize|. Use |params| as the backup buffer, which + // may be larger. virtual status_t allocateBufferWithBackup( node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, - buffer_id *buffer) = 0; + buffer_id *buffer, OMX_U32 allottedSize) = 0; virtual status_t freeBuffer( node_id node, OMX_U32 port_index, buffer_id buffer) = 0; @@ -233,4 +246,15 @@ struct CodecProfileLevel { } // namespace android +inline static const char *asString(android::MetadataBufferType i, const char *def = "??") { + using namespace android; + switch (i) { + case kMetadataBufferTypeCameraSource: return "CameraSource"; + case kMetadataBufferTypeGrallocSource: return "GrallocSource"; + case kMetadataBufferTypeANWBuffer: return "ANWBuffer"; + case kMetadataBufferTypeInvalid: return "Invalid"; + default: return def; + } +} + #endif // ANDROID_IOMX_H_ diff --git a/include/media/MediaProfiles.h b/include/media/MediaProfiles.h index f061d22..e02918f 100644 --- a/include/media/MediaProfiles.h +++ b/include/media/MediaProfiles.h @@ -58,24 +58,6 @@ enum camcorder_quality { CAMCORDER_QUALITY_HIGH_SPEED_LIST_END = 2005, }; -/** - * Set CIF as default maximum import and export resolution of video editor. - * The maximum import and export resolutions are platform specific, - * which should be defined in media_profiles.xml. - * Set default maximum prefetch YUV frames to 6, which means video editor can - * queue up to 6 YUV frames in the video encoder source. - * This value is used to limit the amount of memory used by video editor - * engine when the encoder consumes YUV frames at a lower speed - * than video editor engine produces. - */ -enum videoeditor_capability { - VIDEOEDITOR_DEFAULT_MAX_INPUT_FRAME_WIDTH = 352, - VIDEOEDITOR_DEFUALT_MAX_INPUT_FRAME_HEIGHT = 288, - VIDEOEDITOR_DEFAULT_MAX_OUTPUT_FRAME_WIDTH = 352, - VIDEOEDITOR_DEFUALT_MAX_OUTPUT_FRAME_HEIGHT = 288, - VIDEOEDITOR_DEFAULT_MAX_PREFETCH_YUV_FRAMES = 6 -}; - enum video_decoder { VIDEO_DECODER_WMV, }; @@ -148,32 +130,6 @@ public: int getVideoEncoderParamByName(const char *name, video_encoder codec) const; /** - * Returns the value for the given param name for the video editor cap - * param or -1 if error. - * Supported param name are: - * videoeditor.input.width.max - max input video frame width - * videoeditor.input.height.max - max input video frame height - * videoeditor.output.width.max - max output video frame width - * videoeditor.output.height.max - max output video frame height - * maxPrefetchYUVFrames - max prefetch YUV frames in video editor engine. This value is used - * to limit the memory consumption. - */ - int getVideoEditorCapParamByName(const char *name) const; - - /** - * Returns the value for the given param name for the video editor export codec format - * param or -1 if error. - * Supported param name are: - * videoeditor.export.profile - export video profile - * videoeditor.export.level - export video level - * Supported param codec are: - * 1 for h263 - * 2 for h264 - * 3 for mpeg4 - */ - int getVideoEditorExportParamByName(const char *name, int codec) const; - - /** * Returns the audio encoders supported. */ Vector<audio_encoder> getAudioEncoders() const; @@ -221,7 +177,7 @@ private: MediaProfiles& operator=(const MediaProfiles&); // Don't call me MediaProfiles(const MediaProfiles&); // Don't call me - MediaProfiles() { mVideoEditorCap = NULL; } // Dummy default constructor + MediaProfiles() {} // Dummy default constructor ~MediaProfiles(); // Don't delete me struct VideoCodec { @@ -366,31 +322,6 @@ private: int mCameraId; Vector<int> mLevels; }; - struct ExportVideoProfile { - ExportVideoProfile(int codec, int profile, int level) - :mCodec(codec),mProfile(profile),mLevel(level) {} - ~ExportVideoProfile() {} - int mCodec; - int mProfile; - int mLevel; - }; - struct VideoEditorCap { - VideoEditorCap(int inFrameWidth, int inFrameHeight, - int outFrameWidth, int outFrameHeight, int frames) - : mMaxInputFrameWidth(inFrameWidth), - mMaxInputFrameHeight(inFrameHeight), - mMaxOutputFrameWidth(outFrameWidth), - mMaxOutputFrameHeight(outFrameHeight), - mMaxPrefetchYUVFrames(frames) {} - - ~VideoEditorCap() {} - - int mMaxInputFrameWidth; - int mMaxInputFrameHeight; - int mMaxOutputFrameWidth; - int mMaxOutputFrameHeight; - int mMaxPrefetchYUVFrames; - }; int getCamcorderProfileIndex(int cameraId, camcorder_quality quality) const; void initRequiredProfileRefs(const Vector<int>& cameraIds); @@ -403,7 +334,6 @@ private: static void logAudioEncoderCap(const AudioEncoderCap& cap); static void logVideoDecoderCap(const VideoDecoderCap& cap); static void logAudioDecoderCap(const AudioDecoderCap& cap); - static void logVideoEditorCap(const VideoEditorCap& cap); // If the xml configuration file does exist, use the settings // from the xml @@ -415,9 +345,6 @@ private: static VideoDecoderCap* createVideoDecoderCap(const char **atts); static VideoEncoderCap* createVideoEncoderCap(const char **atts); static AudioEncoderCap* createAudioEncoderCap(const char **atts); - static VideoEditorCap* createVideoEditorCap( - const char **atts, MediaProfiles *profiles); - static ExportVideoProfile* createExportVideoProfile(const char **atts); static CamcorderProfile* createCamcorderProfile( int cameraId, const char **atts, Vector<int>& cameraIds); @@ -461,8 +388,6 @@ private: static void createDefaultEncoderOutputFileFormats(MediaProfiles *profiles); static void createDefaultImageEncodingQualityLevels(MediaProfiles *profiles); static void createDefaultImageDecodingMaxMemory(MediaProfiles *profiles); - static void createDefaultVideoEditorCap(MediaProfiles *profiles); - static void createDefaultExportVideoProfiles(MediaProfiles *profiles); static VideoEncoderCap* createDefaultH263VideoEncoderCap(); static VideoEncoderCap* createDefaultM4vVideoEncoderCap(); @@ -520,8 +445,6 @@ private: RequiredProfiles *mRequiredProfileRefs; Vector<int> mCameraIds; - VideoEditorCap* mVideoEditorCap; - Vector<ExportVideoProfile*> mVideoEditorExportProfiles; }; }; // namespace android diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h index 4ed97e5..bbecc80 100644 --- a/include/media/stagefright/ACodec.h +++ b/include/media/stagefright/ACodec.h @@ -20,6 +20,7 @@ #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> @@ -123,7 +124,7 @@ private: kWhatStart = 'star', kWhatRequestIDRFrame = 'ridr', kWhatSetParameters = 'setP', - kWhatSubmitOutputMetaDataBufferIfEOS = 'subm', + kWhatSubmitOutputMetadataBufferIfEOS = 'subm', kWhatOMXDied = 'OMXd', kWhatReleaseCodecInstance = 'relC', }; @@ -207,7 +208,6 @@ private: bool mSentFormat; bool mIsVideo; bool mIsEncoder; - bool mUseMetadataOnEncoderOutput; bool mShutdownInProgress; bool mExplicitShutdown; @@ -222,9 +222,10 @@ private: bool mChannelMaskPresent; int32_t mChannelMask; unsigned mDequeueCounter; - bool mStoreMetaDataInOutputBuffers; + MetadataBufferType mInputMetadataType; + MetadataBufferType mOutputMetadataType; bool mLegacyAdaptiveExperiment; - int32_t mMetaDataBuffersToSubmit; + int32_t mMetadataBuffersToSubmit; size_t mNumUndequeuedBuffers; int64_t mRepeatFrameDelayUs; @@ -249,14 +250,22 @@ private: 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); diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h index 6e14fc5..d62b35d 100644 --- a/include/media/stagefright/MediaCodec.h +++ b/include/media/stagefright/MediaCodec.h @@ -60,8 +60,6 @@ struct MediaCodec : public AHandler { CB_RESOURCE_RECLAIMED = 5, }; - struct BatteryNotifier; - static sp<MediaCodec> CreateByType( const sp<ALooper> &looper, const char *mime, bool encoder, status_t *err = NULL); diff --git a/include/media/stagefright/foundation/ADebug.h b/include/media/stagefright/foundation/ADebug.h index a97dd9b..24df85a 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 diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp index c14debf..cac2f7f 100644 --- a/media/libmedia/IOMX.cpp +++ b/media/libmedia/IOMX.cpp @@ -245,12 +245,13 @@ public: virtual status_t useBuffer( node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, - buffer_id *buffer) { + buffer_id *buffer, OMX_U32 allottedSize) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); data.writeInt32((int32_t)node); data.writeInt32(port_index); data.writeStrongBinder(IInterface::asBinder(params)); + data.writeInt32(allottedSize); remote()->transact(USE_BUFFER, data, &reply); status_t err = reply.readInt32(); @@ -305,7 +306,7 @@ public: virtual status_t createInputSurface( node_id node, OMX_U32 port_index, - sp<IGraphicBufferProducer> *bufferProducer) { + sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) { Parcel data, reply; status_t err; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); @@ -317,6 +318,12 @@ public: return err; } + // read type even if createInputSurface failed + int negotiatedType = reply.readInt32(); + if (type != NULL) { + *type = (MetadataBufferType)negotiatedType; + } + err = reply.readInt32(); if (err != OK) { return err; @@ -355,7 +362,7 @@ public: virtual status_t setInputSurface( node_id node, OMX_U32 port_index, - const sp<IGraphicBufferConsumer> &bufferConsumer) { + const sp<IGraphicBufferConsumer> &bufferConsumer, MetadataBufferType *type) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); status_t err; @@ -369,6 +376,13 @@ public: ALOGW("binder transaction failed: %d", err); return err; } + + // read type even if setInputSurface failed + int negotiatedType = reply.readInt32(); + if (type != NULL) { + *type = (MetadataBufferType)negotiatedType; + } + return reply.readInt32(); } @@ -387,7 +401,7 @@ public: } virtual status_t storeMetaDataInBuffers( - node_id node, OMX_U32 port_index, OMX_BOOL enable) { + node_id node, OMX_U32 port_index, OMX_BOOL enable, MetadataBufferType *type) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); data.writeInt32((int32_t)node); @@ -395,8 +409,13 @@ public: data.writeInt32((uint32_t)enable); remote()->transact(STORE_META_DATA_IN_BUFFERS, data, &reply); - status_t err = reply.readInt32(); - return err; + // read type even storeMetaDataInBuffers failed + int negotiatedType = reply.readInt32(); + if (type != NULL) { + *type = (MetadataBufferType)negotiatedType; + } + + return reply.readInt32(); } virtual status_t prepareForAdaptivePlayback( @@ -459,12 +478,13 @@ public: virtual status_t allocateBufferWithBackup( node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, - buffer_id *buffer) { + buffer_id *buffer, OMX_U32 allottedSize) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); data.writeInt32((int32_t)node); data.writeInt32(port_index); data.writeStrongBinder(IInterface::asBinder(params)); + data.writeInt32(allottedSize); remote()->transact(ALLOC_BUFFER_WITH_BACKUP, data, &reply); status_t err = reply.readInt32(); @@ -757,9 +777,10 @@ status_t BnOMX::onTransact( OMX_U32 port_index = data.readInt32(); sp<IMemory> params = interface_cast<IMemory>(data.readStrongBinder()); + OMX_U32 allottedSize = data.readInt32(); buffer_id buffer; - status_t err = useBuffer(node, port_index, params, &buffer); + status_t err = useBuffer(node, port_index, params, &buffer, allottedSize); reply->writeInt32(err); if (err == OK) { @@ -815,9 +836,10 @@ status_t BnOMX::onTransact( OMX_U32 port_index = data.readInt32(); sp<IGraphicBufferProducer> bufferProducer; - status_t err = createInputSurface(node, port_index, - &bufferProducer); + MetadataBufferType type; + status_t err = createInputSurface(node, port_index, &bufferProducer, &type); + reply->writeInt32(type); reply->writeInt32(err); if (err == OK) { @@ -856,8 +878,10 @@ status_t BnOMX::onTransact( sp<IGraphicBufferConsumer> bufferConsumer = interface_cast<IGraphicBufferConsumer>(data.readStrongBinder()); - status_t err = setInputSurface(node, port_index, bufferConsumer); + MetadataBufferType type; + status_t err = setInputSurface(node, port_index, bufferConsumer, &type); + reply->writeInt32(type); reply->writeInt32(err); return NO_ERROR; } @@ -882,7 +906,9 @@ status_t BnOMX::onTransact( OMX_U32 port_index = data.readInt32(); OMX_BOOL enable = (OMX_BOOL)data.readInt32(); - status_t err = storeMetaDataInBuffers(node, port_index, enable); + MetadataBufferType type; + status_t err = storeMetaDataInBuffers(node, port_index, enable, &type); + reply->writeInt32(type); reply->writeInt32(err); return NO_ERROR; @@ -953,10 +979,11 @@ status_t BnOMX::onTransact( OMX_U32 port_index = data.readInt32(); sp<IMemory> params = interface_cast<IMemory>(data.readStrongBinder()); + OMX_U32 allottedSize = data.readInt32(); buffer_id buffer; status_t err = allocateBufferWithBackup( - node, port_index, params, &buffer); + node, port_index, params, &buffer, allottedSize); reply->writeInt32(err); diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp index ae0061f..c5790fb 100644 --- a/media/libmedia/MediaProfiles.cpp +++ b/media/libmedia/MediaProfiles.cpp @@ -152,16 +152,6 @@ MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap UNUS ALOGV("codec = %d", cap.mCodec); } -/*static*/ void -MediaProfiles::logVideoEditorCap(const MediaProfiles::VideoEditorCap& cap UNUSED) -{ - ALOGV("videoeditor cap:"); - ALOGV("mMaxInputFrameWidth = %d", cap.mMaxInputFrameWidth); - ALOGV("mMaxInputFrameHeight = %d", cap.mMaxInputFrameHeight); - ALOGV("mMaxOutputFrameWidth = %d", cap.mMaxOutputFrameWidth); - ALOGV("mMaxOutputFrameHeight = %d", cap.mMaxOutputFrameHeight); -} - /*static*/ int MediaProfiles::findTagForName(const MediaProfiles::NameToTagMap *map, size_t nMappings, const char *name) @@ -398,42 +388,6 @@ void MediaProfiles::addStartTimeOffset(int cameraId, const char** atts) ALOGV("%s: cameraId=%d, offset=%d ms", __func__, cameraId, offsetTimeMs); mStartTimeOffsets.replaceValueFor(cameraId, offsetTimeMs); } -/*static*/ MediaProfiles::ExportVideoProfile* -MediaProfiles::createExportVideoProfile(const char **atts) -{ - CHECK(!strcmp("name", atts[0]) && - !strcmp("profile", atts[2]) && - !strcmp("level", atts[4])); - - const size_t nMappings = - sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]); - const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]); - CHECK(codec != -1); - - MediaProfiles::ExportVideoProfile *profile = - new MediaProfiles::ExportVideoProfile( - codec, atoi(atts[3]), atoi(atts[5])); - - return profile; -} -/*static*/ MediaProfiles::VideoEditorCap* -MediaProfiles::createVideoEditorCap(const char **atts, MediaProfiles *profiles) -{ - CHECK(!strcmp("maxInputFrameWidth", atts[0]) && - !strcmp("maxInputFrameHeight", atts[2]) && - !strcmp("maxOutputFrameWidth", atts[4]) && - !strcmp("maxOutputFrameHeight", atts[6]) && - !strcmp("maxPrefetchYUVFrames", atts[8])); - - MediaProfiles::VideoEditorCap *pVideoEditorCap = - new MediaProfiles::VideoEditorCap(atoi(atts[1]), atoi(atts[3]), - atoi(atts[5]), atoi(atts[7]), atoi(atts[9])); - - logVideoEditorCap(*pVideoEditorCap); - profiles->mVideoEditorCap = pVideoEditorCap; - - return pVideoEditorCap; -} /*static*/ void MediaProfiles::startElementHandler(void *userData, const char *name, const char **atts) @@ -465,10 +419,6 @@ MediaProfiles::startElementHandler(void *userData, const char *name, const char createCamcorderProfile(profiles->mCurrentCameraId, atts, profiles->mCameraIds)); } else if (strcmp("ImageEncoding", name) == 0) { profiles->addImageEncodingQualityLevel(profiles->mCurrentCameraId, atts); - } else if (strcmp("VideoEditorCap", name) == 0) { - createVideoEditorCap(atts, profiles); - } else if (strcmp("ExportVideoProfile", name) == 0) { - profiles->mVideoEditorExportProfiles.add(createExportVideoProfile(atts)); } } @@ -873,32 +823,6 @@ MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles) profiles->mImageEncodingQualityLevels.add(levels); } -/*static*/ void -MediaProfiles::createDefaultVideoEditorCap(MediaProfiles *profiles) -{ - profiles->mVideoEditorCap = - new MediaProfiles::VideoEditorCap( - VIDEOEDITOR_DEFAULT_MAX_INPUT_FRAME_WIDTH, - VIDEOEDITOR_DEFUALT_MAX_INPUT_FRAME_HEIGHT, - VIDEOEDITOR_DEFAULT_MAX_OUTPUT_FRAME_WIDTH, - VIDEOEDITOR_DEFUALT_MAX_OUTPUT_FRAME_HEIGHT, - VIDEOEDITOR_DEFAULT_MAX_PREFETCH_YUV_FRAMES); -} -/*static*/ void -MediaProfiles::createDefaultExportVideoProfiles(MediaProfiles *profiles) -{ - // Create default video export profiles - profiles->mVideoEditorExportProfiles.add( - new ExportVideoProfile(VIDEO_ENCODER_H263, - OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level10)); - profiles->mVideoEditorExportProfiles.add( - new ExportVideoProfile(VIDEO_ENCODER_MPEG_4_SP, - OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1)); - profiles->mVideoEditorExportProfiles.add( - new ExportVideoProfile(VIDEO_ENCODER_H264, - OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13)); -} - /*static*/ MediaProfiles* MediaProfiles::createDefaultInstance() { @@ -910,8 +834,6 @@ MediaProfiles::createDefaultInstance() createDefaultAudioDecoders(profiles); createDefaultEncoderOutputFileFormats(profiles); createDefaultImageEncodingQualityLevels(profiles); - createDefaultVideoEditorCap(profiles); - createDefaultExportVideoProfiles(profiles); return profiles; } @@ -1009,54 +931,6 @@ int MediaProfiles::getVideoEncoderParamByName(const char *name, video_encoder co ALOGE("The given video encoder param name %s is not found", name); return -1; } -int MediaProfiles::getVideoEditorExportParamByName( - const char *name, int codec) const -{ - ALOGV("getVideoEditorExportParamByName: name %s codec %d", name, codec); - ExportVideoProfile *exportProfile = NULL; - int index = -1; - for (size_t i =0; i < mVideoEditorExportProfiles.size(); i++) { - exportProfile = mVideoEditorExportProfiles[i]; - if (exportProfile->mCodec == codec) { - index = i; - break; - } - } - if (index == -1) { - ALOGE("The given video decoder %d is not found", codec); - return -1; - } - if (!strcmp("videoeditor.export.profile", name)) - return exportProfile->mProfile; - if (!strcmp("videoeditor.export.level", name)) - return exportProfile->mLevel; - - ALOGE("The given video editor export param name %s is not found", name); - return -1; -} -int MediaProfiles::getVideoEditorCapParamByName(const char *name) const -{ - ALOGV("getVideoEditorCapParamByName: %s", name); - - if (mVideoEditorCap == NULL) { - ALOGE("The mVideoEditorCap is not created, then create default cap."); - createDefaultVideoEditorCap(sInstance); - } - - if (!strcmp("videoeditor.input.width.max", name)) - return mVideoEditorCap->mMaxInputFrameWidth; - if (!strcmp("videoeditor.input.height.max", name)) - return mVideoEditorCap->mMaxInputFrameHeight; - if (!strcmp("videoeditor.output.width.max", name)) - return mVideoEditorCap->mMaxOutputFrameWidth; - if (!strcmp("videoeditor.output.height.max", name)) - return mVideoEditorCap->mMaxOutputFrameHeight; - if (!strcmp("maxPrefetchYUVFrames", name)) - return mVideoEditorCap->mMaxPrefetchYUVFrames; - - ALOGE("The given video editor param name %s is not found", name); - return -1; -} Vector<audio_encoder> MediaProfiles::getAudioEncoders() const { diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk index b52db97..7f0cca2 100644 --- a/media/libmediaplayerservice/Android.mk +++ b/media/libmediaplayerservice/Android.mk @@ -33,6 +33,7 @@ LOCAL_SHARED_LIBRARIES := \ libdl \ libgui \ libmedia \ + libmediautils \ libsonivox \ libstagefright \ libstagefright_foundation \ diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 9c0af4a..7c40121 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -34,7 +34,6 @@ #include <utils/misc.h> -#include <binder/IBatteryStats.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/MemoryHeapBase.h> @@ -60,6 +59,7 @@ #include <media/stagefright/AudioPlayer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/ALooperRoster.h> +#include <mediautils/BatteryNotifier.h> #include <system/audio.h> @@ -287,17 +287,9 @@ MediaPlayerService::MediaPlayerService() // reset battery stats // if the mediaserver has crashed, battery stats could be left // in bad state, reset the state upon service start. - 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->checkService(name)); - if (batteryStats != NULL) { - batteryStats->noteResetVideo(); - batteryStats->noteResetAudio(); - } - } + BatteryNotifier& notifier(BatteryNotifier::getInstance()); + notifier.noteResetVideo(); + notifier.noteResetAudio(); MediaPlayerFactory::registerBuiltinFactories(); } @@ -1884,6 +1876,15 @@ void MediaPlayerService::AudioOutput::CallbackWrapper( me->mCallbackCookie, CB_EVENT_TEAR_DOWN); break; + case AudioTrack::EVENT_UNDERRUN: + // This occurs when there is no data available, typically occurring + // when there is a failure to supply data to the AudioTrack. It can also + // occur in non-offloaded mode when the audio device comes out of standby. + // + // If you see this at the start of playback, there probably was a glitch. + ALOGI("callbackwrapper: EVENT_UNDERRUN (discarded)"); + break; + default: ALOGE("received unknown event type: %d inside CallbackWrapper !", event); } diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 70480a2..08045d1 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -413,7 +413,6 @@ ACodec::ACodec() mSentFormat(false), mIsVideo(false), mIsEncoder(false), - mUseMetadataOnEncoderOutput(false), mShutdownInProgress(false), mExplicitShutdown(false), mEncoderDelay(0), @@ -422,9 +421,10 @@ ACodec::ACodec() mChannelMaskPresent(false), mChannelMask(0), mDequeueCounter(0), - mStoreMetaDataInOutputBuffers(false), + mInputMetadataType(kMetadataBufferTypeInvalid), + mOutputMetadataType(kMetadataBufferTypeInvalid), mLegacyAdaptiveExperiment(false), - mMetaDataBuffersToSubmit(0), + mMetadataBuffersToSubmit(0), mRepeatFrameDelayUs(-1ll), mMaxPtsGapUs(-1ll), mMaxFps(-1), @@ -542,10 +542,10 @@ void ACodec::signalRequestIDRFrame() { // This causes a halt if we already signaled an EOS on the input // port. For now keep submitting an output buffer if there was an // EOS on the input port, but not yet on the output port. -void ACodec::signalSubmitOutputMetaDataBufferIfEOS_workaround() { +void ACodec::signalSubmitOutputMetadataBufferIfEOS_workaround() { if (mPortEOS[kPortIndexInput] && !mPortEOS[kPortIndexOutput] && - mMetaDataBuffersToSubmit > 0) { - (new AMessage(kWhatSubmitOutputMetaDataBufferIfEOS, this))->post(); + mMetadataBuffersToSubmit > 0) { + (new AMessage(kWhatSubmitOutputMetadataBufferIfEOS, this))->post(); } } @@ -620,7 +620,7 @@ status_t ACodec::handleSetSurface(const sp<Surface> &surface) { for (size_t i = 0; i < buffers.size(); ++i) { const BufferInfo &info = buffers[i]; // skip undequeued buffers for meta data mode - if (mStoreMetaDataInOutputBuffers + if (storingMetadataInDecodedBuffers() && !mLegacyAdaptiveExperiment && info.mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) { ALOGV("skipping buffer %p", info.mGraphicBuffer->getNativeBuffer()); @@ -638,7 +638,7 @@ status_t ACodec::handleSetSurface(const sp<Surface> &surface) { } // cancel undequeued buffers to new surface - if (!mStoreMetaDataInOutputBuffers || mLegacyAdaptiveExperiment) { + if (!storingMetadataInDecodedBuffers() || mLegacyAdaptiveExperiment) { for (size_t i = 0; i < buffers.size(); ++i) { const BufferInfo &info = buffers[i]; if (info.mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) { @@ -674,8 +674,8 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) { status_t err; if (mNativeWindow != NULL && portIndex == kPortIndexOutput) { - if (mStoreMetaDataInOutputBuffers) { - err = allocateOutputMetaDataBuffers(); + if (storingMetadataInDecodedBuffers()) { + err = allocateOutputMetadataBuffers(); } else { err = allocateOutputBuffersFromNativeWindow(); } @@ -688,16 +688,33 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) { mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); if (err == OK) { - ALOGV("[%s] Allocating %u buffers of size %u on %s port", + MetadataBufferType type = + portIndex == kPortIndexOutput ? mOutputMetadataType : mInputMetadataType; + int32_t bufSize = def.nBufferSize; + if (type == kMetadataBufferTypeGrallocSource) { + bufSize = sizeof(VideoGrallocMetadata); + } else if (type == kMetadataBufferTypeANWBuffer) { + bufSize = sizeof(VideoNativeMetadata); + } + + // If using gralloc or native source input metadata buffers, allocate largest + // metadata size as we prefer to generate native source metadata, but component + // may require gralloc source. + int32_t allottedSize = bufSize; + if (portIndex == kPortIndexInput && type > 0) { + bufSize = max(sizeof(VideoGrallocMetadata), sizeof(VideoNativeMetadata)); + } + + ALOGV("[%s] Allocating %u buffers of size %d/%d (from %u using %s) on %s port", mComponentName.c_str(), - def.nBufferCountActual, def.nBufferSize, + def.nBufferCountActual, bufSize, allottedSize, def.nBufferSize, asString(type), portIndex == kPortIndexInput ? "input" : "output"); - size_t totalSize = def.nBufferCountActual * def.nBufferSize; + size_t totalSize = def.nBufferCountActual * bufSize; mDealer[portIndex] = new MemoryDealer(totalSize, "ACodec"); - for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) { - sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize); + for (OMX_U32 i = 0; i < def.nBufferCountActual && err == OK; ++i) { + sp<IMemory> mem = mDealer[portIndex]->allocate(bufSize); if (mem == NULL || mem->pointer() == NULL) { return NO_MEMORY; } @@ -711,27 +728,27 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) { : OMXCodec::kRequiresAllocateBufferOnOutputPorts; if ((portIndex == kPortIndexInput && (mFlags & kFlagIsSecure)) - || mUseMetadataOnEncoderOutput) { + || (portIndex == kPortIndexOutput && usingMetadataOnEncoderOutput())) { mem.clear(); void *ptr; err = mOMX->allocateBuffer( - mNode, portIndex, def.nBufferSize, &info.mBufferID, + mNode, portIndex, bufSize, &info.mBufferID, &ptr); - int32_t bufSize = mUseMetadataOnEncoderOutput ? - (4 + sizeof(buffer_handle_t)) : def.nBufferSize; - info.mData = new ABuffer(ptr, bufSize); } else if (mQuirks & requiresAllocateBufferBit) { err = mOMX->allocateBufferWithBackup( - mNode, portIndex, mem, &info.mBufferID); + mNode, portIndex, mem, &info.mBufferID, allottedSize); } else { - err = mOMX->useBuffer(mNode, portIndex, mem, &info.mBufferID); + err = mOMX->useBuffer(mNode, portIndex, mem, &info.mBufferID, allottedSize); } if (mem != NULL) { - info.mData = new ABuffer(mem->pointer(), def.nBufferSize); + info.mData = new ABuffer(mem->pointer(), bufSize); + if (type == kMetadataBufferTypeANWBuffer) { + ((VideoNativeMetadata *)mem->pointer())->nFenceFd = -1; + } } mBuffers[portIndex].push(info); @@ -896,7 +913,7 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() { return err; mNumUndequeuedBuffers = minUndequeuedBuffers; - if (!mStoreMetaDataInOutputBuffers) { + if (!storingMetadataInDecodedBuffers()) { static_cast<Surface*>(mNativeWindow.get()) ->getIGraphicBufferProducer()->allowAllocation(true); } @@ -959,7 +976,7 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() { } } - if (!mStoreMetaDataInOutputBuffers) { + if (!storingMetadataInDecodedBuffers()) { static_cast<Surface*>(mNativeWindow.get()) ->getIGraphicBufferProducer()->allowAllocation(false); } @@ -967,7 +984,7 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() { return err; } -status_t ACodec::allocateOutputMetaDataBuffers() { +status_t ACodec::allocateOutputMetadataBuffers() { OMX_U32 bufferCount, bufferSize, minUndequeuedBuffers; status_t err = configureOutputBuffersFromNativeWindow( &bufferCount, &bufferSize, &minUndequeuedBuffers); @@ -978,7 +995,9 @@ status_t ACodec::allocateOutputMetaDataBuffers() { ALOGV("[%s] Allocating %u meta buffers on output port", mComponentName.c_str(), bufferCount); - size_t totalSize = bufferCount * 8; + size_t bufSize = mOutputMetadataType == kMetadataBufferTypeANWBuffer ? + sizeof(struct VideoNativeMetadata) : sizeof(struct VideoGrallocMetadata); + size_t totalSize = bufferCount * bufSize; mDealer[kPortIndexOutput] = new MemoryDealer(totalSize, "ACodec"); // Dequeue buffers and send them to OMX @@ -988,16 +1007,18 @@ status_t ACodec::allocateOutputMetaDataBuffers() { info.mGraphicBuffer = NULL; info.mDequeuedAt = mDequeueCounter; - sp<IMemory> mem = mDealer[kPortIndexOutput]->allocate( - sizeof(struct VideoDecoderOutputMetaData)); + sp<IMemory> mem = mDealer[kPortIndexOutput]->allocate(bufSize); if (mem == NULL || mem->pointer() == NULL) { return NO_MEMORY; } + if (mOutputMetadataType == kMetadataBufferTypeANWBuffer) { + ((VideoNativeMetadata *)mem->pointer())->nFenceFd = -1; + } info.mData = new ABuffer(mem->pointer(), mem->size()); // we use useBuffer for metadata regardless of quirks err = mOMX->useBuffer( - mNode, kPortIndexOutput, mem, &info.mBufferID); + mNode, kPortIndexOutput, mem, &info.mBufferID, mem->size()); mBuffers[kPortIndexOutput].push(info); @@ -1044,13 +1065,13 @@ status_t ACodec::allocateOutputMetaDataBuffers() { ->getIGraphicBufferProducer()->allowAllocation(false); } - mMetaDataBuffersToSubmit = bufferCount - minUndequeuedBuffers; + mMetadataBuffersToSubmit = bufferCount - minUndequeuedBuffers; return err; } -status_t ACodec::submitOutputMetaDataBuffer() { - CHECK(mStoreMetaDataInOutputBuffers); - if (mMetaDataBuffersToSubmit == 0) +status_t ACodec::submitOutputMetadataBuffer() { + CHECK(storingMetadataInDecodedBuffers()); + if (mMetadataBuffersToSubmit == 0) return OK; BufferInfo *info = dequeueBufferFromNativeWindow(); @@ -1061,7 +1082,7 @@ status_t ACodec::submitOutputMetaDataBuffer() { ALOGV("[%s] submitting output meta buffer ID %u for graphic buffer %p", mComponentName.c_str(), info->mBufferID, info->mGraphicBuffer.get()); - --mMetaDataBuffersToSubmit; + --mMetadataBuffersToSubmit; status_t err = mOMX->fillBuffer(mNode, info->mBufferID); if (err == OK) { info->mStatus = BufferInfo::OWNED_BY_COMPONENT; @@ -1159,7 +1180,7 @@ ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() { // same is possible in meta mode, in which case, it will be treated // as a normal buffer, which is not desirable. // TODO: fix this. - if (!stale && (!mStoreMetaDataInOutputBuffers || mLegacyAdaptiveExperiment)) { + if (!stale && (!storingMetadataInDecodedBuffers() || mLegacyAdaptiveExperiment)) { ALOGI("dequeued unrecognized (stale) buffer %p. discarding", buf); stale = true; } @@ -1187,7 +1208,7 @@ ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() { CHECK(oldest != NULL); // it is impossible to dequeue an unknown buffer in non-meta mode, as the // while loop above does not complete - CHECK(mStoreMetaDataInOutputBuffers); + CHECK(storingMetadataInDecodedBuffers()); // discard buffer in LRU info and replace with new buffer oldest->mGraphicBuffer = new GraphicBuffer(buf, false); @@ -1197,16 +1218,23 @@ ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() { mNode, kPortIndexOutput, oldest->mGraphicBuffer, oldest->mBufferID); - VideoDecoderOutputMetaData *metaData = - reinterpret_cast<VideoDecoderOutputMetaData *>( - oldest->mData->base()); - CHECK_EQ(metaData->eType, kMetadataBufferTypeGrallocSource); - - ALOGV("replaced oldest buffer #%u with age %u (%p/%p stored in %p)", - (unsigned)(oldest - &mBuffers[kPortIndexOutput][0]), - mDequeueCounter - oldest->mDequeuedAt, - metaData->pHandle, - oldest->mGraphicBuffer->handle, oldest->mData->base()); + if (mOutputMetadataType == kMetadataBufferTypeGrallocSource) { + VideoGrallocMetadata *grallocMeta = + reinterpret_cast<VideoGrallocMetadata *>(oldest->mData->base()); + ALOGV("replaced oldest buffer #%u with age %u (%p/%p stored in %p)", + (unsigned)(oldest - &mBuffers[kPortIndexOutput][0]), + mDequeueCounter - oldest->mDequeuedAt, + grallocMeta->hHandle, + oldest->mGraphicBuffer->handle, oldest->mData->base()); + } else if (mOutputMetadataType == kMetadataBufferTypeANWBuffer) { + VideoNativeMetadata *nativeMeta = + reinterpret_cast<VideoNativeMetadata *>(oldest->mData->base()); + ALOGV("replaced oldest buffer #%u with age %u (%p/%p stored in %p)", + (unsigned)(oldest - &mBuffers[kPortIndexOutput][0]), + mDequeueCounter - oldest->mDequeuedAt, + nativeMeta->pBuffer, + oldest->mGraphicBuffer->getNativeBuffer(), oldest->mData->base()); + } return oldest; } @@ -1398,6 +1426,8 @@ status_t ACodec::configureCodec( mIsEncoder = encoder; + mInputMetadataType = kMetadataBufferTypeInvalid; + mOutputMetadataType = kMetadataBufferTypeInvalid; status_t err = setComponentRole(encoder /* isEncoder */, mime); @@ -1416,15 +1446,19 @@ status_t ACodec::configureCodec( if (encoder && msg->findInt32("store-metadata-in-buffers", &storeMeta) && storeMeta != 0) { - err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexInput, OMX_TRUE); - + err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexInput, OMX_TRUE, &mInputMetadataType); if (err != OK) { - ALOGE("[%s] storeMetaDataInBuffers (input) failed w/ err %d", + ALOGE("[%s] storeMetaDataInBuffers (input) failed w/ err %d", mComponentName.c_str(), err); - return err; - } - } + return err; + } + // For this specific case we could be using camera source even if storeMetaDataInBuffers + // returns Gralloc source. Pretend that we are; this will force us to use nBufferSize. + if (mInputMetadataType == kMetadataBufferTypeGrallocSource) { + mInputMetadataType = kMetadataBufferTypeCameraSource; + } + } int32_t prependSPSPPS = 0; if (encoder @@ -1463,14 +1497,10 @@ status_t ACodec::configureCodec( && msg->findInt32("store-metadata-in-buffers-output", &storeMeta) && storeMeta != 0); - err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexOutput, enable); - + err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexOutput, enable, &mOutputMetadataType); if (err != OK) { ALOGE("[%s] storeMetaDataInBuffers (output) failed w/ err %d", mComponentName.c_str(), err); - mUseMetadataOnEncoderOutput = 0; - } else { - mUseMetadataOnEncoderOutput = enable; } if (!msg->findInt64( @@ -1502,7 +1532,6 @@ status_t ACodec::configureCodec( sp<RefBase> obj; bool haveNativeWindow = msg->findObject("native-window", &obj) && obj != NULL && video && !encoder; - mStoreMetaDataInOutputBuffers = false; mLegacyAdaptiveExperiment = false; if (video && !encoder) { inputFormat->setInt32("adaptive-playback", false); @@ -1588,7 +1617,7 @@ status_t ACodec::configureCodec( // Always try to enable dynamic output buffers on native surface err = mOMX->storeMetaDataInBuffers( - mNode, kPortIndexOutput, OMX_TRUE); + mNode, kPortIndexOutput, OMX_TRUE, &mOutputMetadataType); if (err != OK) { ALOGE("[%s] storeMetaDataInBuffers failed w/ err %d", mComponentName.c_str(), err); @@ -1640,7 +1669,7 @@ status_t ACodec::configureCodec( } else { ALOGV("[%s] storeMetaDataInBuffers succeeded", mComponentName.c_str()); - mStoreMetaDataInOutputBuffers = true; + CHECK(storingMetadataInDecodedBuffers()); mLegacyAdaptiveExperiment = ADebug::isExperimentEnabled( "legacy-adaptive", !msg->contains("no-experiments")); @@ -1717,9 +1746,10 @@ status_t ACodec::configureCodec( mNativeWindow.clear(); haveNativeWindow = false; usingSwRenderer = true; - if (mStoreMetaDataInOutputBuffers) { - err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexOutput, OMX_FALSE); - mStoreMetaDataInOutputBuffers = false; + if (storingMetadataInDecodedBuffers()) { + err = mOMX->storeMetaDataInBuffers( + mNode, kPortIndexOutput, OMX_FALSE, &mOutputMetadataType); + mOutputMetadataType = kMetadataBufferTypeInvalid; // just in case // TODO: implement adaptive-playback support for bytebuffer mode. // This is done by SW codecs, but most HW codecs don't support it. inputFormat->setInt32("adaptive-playback", false); @@ -3536,8 +3566,8 @@ void ACodec::waitUntilAllPossibleNativeWindowBuffersAreReturnedToUs() { while (countBuffersOwnedByNativeWindow() > mNumUndequeuedBuffers && dequeueBufferFromNativeWindow() != NULL) { // these buffers will be submitted as regular buffers; account for this - if (mStoreMetaDataInOutputBuffers && mMetaDataBuffersToSubmit > 0) { - --mMetaDataBuffersToSubmit; + if (storingMetadataInDecodedBuffers() && mMetadataBuffersToSubmit > 0) { + --mMetadataBuffersToSubmit; } } } @@ -4628,16 +4658,16 @@ void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) { mCodec->mBufferStats.add(timeUs, stats); #endif - if (mCodec->mStoreMetaDataInOutputBuffers) { + if (mCodec->storingMetadataInDecodedBuffers()) { // try to submit an output buffer for each input buffer PortMode outputMode = getPortMode(kPortIndexOutput); - ALOGV("MetaDataBuffersToSubmit=%u portMode=%s", - mCodec->mMetaDataBuffersToSubmit, + ALOGV("MetadataBuffersToSubmit=%u portMode=%s", + mCodec->mMetadataBuffersToSubmit, (outputMode == FREE_BUFFERS ? "FREE" : outputMode == KEEP_BUFFERS ? "KEEP" : "RESUBMIT")); if (outputMode == RESUBMIT_BUFFERS) { - mCodec->submitOutputMetaDataBuffer(); + mCodec->submitOutputMetadataBuffer(); } } status_t err2 = mCodec->mOMX->emptyBuffer( @@ -4799,10 +4829,17 @@ bool ACodec::BaseState::onOMXFillBufferDone( if (!mCodec->mSentFormat && rangeLength > 0) { mCodec->sendFormatChange(reply); } - - if (mCodec->mUseMetadataOnEncoderOutput) { - native_handle_t* handle = - *(native_handle_t**)(info->mData->data() + 4); + if (mCodec->usingMetadataOnEncoderOutput()) { + native_handle_t *handle = NULL; + VideoGrallocMetadata &grallocMeta = *(VideoGrallocMetadata *)info->mData->data(); + VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)info->mData->data(); + if (info->mData->size() >= sizeof(grallocMeta) + && grallocMeta.eType == kMetadataBufferTypeGrallocSource) { + handle = (native_handle_t *)grallocMeta.hHandle; + } else if (info->mData->size() >= sizeof(nativeMeta) + && nativeMeta.eType == kMetadataBufferTypeANWBuffer) { + handle = (native_handle_t *)nativeMeta.pBuffer->handle; + } info->mData->meta()->setPointer("handle", handle); info->mData->meta()->setInt32("rangeOffset", rangeOffset); info->mData->meta()->setInt32("rangeLength", rangeLength); @@ -4999,7 +5036,8 @@ void ACodec::UninitializedState::stateEntered() { mCodec->mOMX.clear(); mCodec->mQuirks = 0; mCodec->mFlags = 0; - mCodec->mUseMetadataOnEncoderOutput = 0; + mCodec->mInputMetadataType = kMetadataBufferTypeInvalid; + mCodec->mOutputMetadataType = kMetadataBufferTypeInvalid; mCodec->mComponentName.clear(); } @@ -5202,7 +5240,7 @@ void ACodec::LoadedState::stateEntered() { mCodec->mInputEOSResult = OK; mCodec->mDequeueCounter = 0; - mCodec->mMetaDataBuffersToSubmit = 0; + mCodec->mMetadataBuffersToSubmit = 0; mCodec->mRepeatFrameDelayUs = -1ll; mCodec->mInputFormat.clear(); mCodec->mOutputFormat.clear(); @@ -5431,7 +5469,7 @@ void ACodec::LoadedState::onCreateInputSurface( sp<IGraphicBufferProducer> bufferProducer; status_t err = mCodec->mOMX->createInputSurface( - mCodec->mNode, kPortIndexInput, &bufferProducer); + mCodec->mNode, kPortIndexInput, &bufferProducer, &mCodec->mInputMetadataType); if (err == OK) { err = setupInputSurface(); @@ -5463,7 +5501,8 @@ void ACodec::LoadedState::onSetInputSurface( sp<PersistentSurface> surface = static_cast<PersistentSurface *>(obj.get()); status_t err = mCodec->mOMX->setInputSurface( - mCodec->mNode, kPortIndexInput, surface->getBufferConsumer()); + mCodec->mNode, kPortIndexInput, surface->getBufferConsumer(), + &mCodec->mInputMetadataType); if (err == OK) { err = setupInputSurface(); @@ -5680,13 +5719,13 @@ void ACodec::ExecutingState::submitOutputMetaBuffers() { BufferInfo *info = &mCodec->mBuffers[kPortIndexInput].editItemAt(i); if (info->mStatus == BufferInfo::OWNED_BY_COMPONENT) { - if (mCodec->submitOutputMetaDataBuffer() != OK) + if (mCodec->submitOutputMetadataBuffer() != OK) break; } } // *** NOTE: THE FOLLOWING WORKAROUND WILL BE REMOVED *** - mCodec->signalSubmitOutputMetaDataBufferIfEOS_workaround(); + mCodec->signalSubmitOutputMetadataBufferIfEOS_workaround(); } void ACodec::ExecutingState::submitRegularOutputBuffers() { @@ -5731,7 +5770,7 @@ void ACodec::ExecutingState::submitRegularOutputBuffers() { void ACodec::ExecutingState::submitOutputBuffers() { submitRegularOutputBuffers(); - if (mCodec->mStoreMetaDataInOutputBuffers) { + if (mCodec->storingMetadataInDecodedBuffers()) { submitOutputMetaBuffers(); } } @@ -5863,13 +5902,13 @@ bool ACodec::ExecutingState::onMessageReceived(const sp<AMessage> &msg) { } // *** NOTE: THE FOLLOWING WORKAROUND WILL BE REMOVED *** - case kWhatSubmitOutputMetaDataBufferIfEOS: + case kWhatSubmitOutputMetadataBufferIfEOS: { if (mCodec->mPortEOS[kPortIndexInput] && !mCodec->mPortEOS[kPortIndexOutput]) { - status_t err = mCodec->submitOutputMetaDataBuffer(); + status_t err = mCodec->submitOutputMetadataBuffer(); if (err == OK) { - mCodec->signalSubmitOutputMetaDataBufferIfEOS_workaround(); + mCodec->signalSubmitOutputMetadataBufferIfEOS_workaround(); } } return true; @@ -5980,7 +6019,7 @@ bool ACodec::ExecutingState::onOMXEvent( CHECK_EQ(data1, (OMX_U32)kPortIndexOutput); if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) { - mCodec->mMetaDataBuffersToSubmit = 0; + mCodec->mMetadataBuffersToSubmit = 0; CHECK_EQ(mCodec->mOMX->sendCommand( mCodec->mNode, OMX_CommandPortDisable, kPortIndexOutput), diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 337068e..0dfa300 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -90,6 +90,7 @@ LOCAL_SHARED_LIBRARIES := \ libicuuc \ liblog \ libmedia \ + libmediautils \ libnetd_client \ libopus \ libsonivox \ diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 6f22e26..f918d2d 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -21,7 +21,6 @@ #include "include/avc_utils.h" #include "include/SoftwareRenderer.h" -#include <binder/IBatteryStats.h> #include <binder/IMemory.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> @@ -48,6 +47,7 @@ #include <media/stagefright/OMXCodec.h> #include <media/stagefright/PersistentSurface.h> #include <media/stagefright/SurfaceUtils.h> +#include <mediautils/BatteryNotifier.h> #include <private/android_filesystem_config.h> #include <utils/Log.h> #include <utils/Singleton.h> @@ -108,134 +108,6 @@ private: DISALLOW_EVIL_CONSTRUCTORS(ResourceManagerClient); }; -struct MediaCodec::BatteryNotifier : public Singleton<BatteryNotifier> { - BatteryNotifier(); - virtual ~BatteryNotifier(); - - void noteStartVideo(); - void noteStopVideo(); - void noteStartAudio(); - void noteStopAudio(); - void onBatteryStatServiceDied(); - -private: - struct DeathNotifier : public IBinder::DeathRecipient { - DeathNotifier() {} - virtual void binderDied(const wp<IBinder>& /*who*/) { - BatteryNotifier::getInstance().onBatteryStatServiceDied(); - } - }; - - Mutex mLock; - int32_t mVideoRefCount; - int32_t mAudioRefCount; - sp<IBatteryStats> mBatteryStatService; - sp<DeathNotifier> mDeathNotifier; - - sp<IBatteryStats> getBatteryService_l(); - - DISALLOW_EVIL_CONSTRUCTORS(BatteryNotifier); -}; - -ANDROID_SINGLETON_STATIC_INSTANCE(MediaCodec::BatteryNotifier) - -MediaCodec::BatteryNotifier::BatteryNotifier() : - mVideoRefCount(0), - mAudioRefCount(0) { -} - -sp<IBatteryStats> MediaCodec::BatteryNotifier::getBatteryService_l() { - if (mBatteryStatService != NULL) { - return mBatteryStatService; - } - // get battery service from service manager - const sp<IServiceManager> sm(defaultServiceManager()); - if (sm != NULL) { - const String16 name("batterystats"); - mBatteryStatService = - interface_cast<IBatteryStats>(sm->getService(name)); - if (mBatteryStatService == NULL) { - ALOGE("batterystats service unavailable!"); - return NULL; - } - mDeathNotifier = new DeathNotifier(); - IInterface::asBinder(mBatteryStatService)->linkToDeath(mDeathNotifier); - // notify start now if media already started - if (mVideoRefCount > 0) { - mBatteryStatService->noteStartVideo(AID_MEDIA); - } - if (mAudioRefCount > 0) { - mBatteryStatService->noteStartAudio(AID_MEDIA); - } - } - return mBatteryStatService; -} - -MediaCodec::BatteryNotifier::~BatteryNotifier() { - if (mDeathNotifier != NULL) { - IInterface::asBinder(mBatteryStatService)-> - unlinkToDeath(mDeathNotifier); - } -} - -void MediaCodec::BatteryNotifier::noteStartVideo() { - Mutex::Autolock _l(mLock); - sp<IBatteryStats> batteryService = getBatteryService_l(); - if (mVideoRefCount == 0 && batteryService != NULL) { - batteryService->noteStartVideo(AID_MEDIA); - } - mVideoRefCount++; -} - -void MediaCodec::BatteryNotifier::noteStopVideo() { - Mutex::Autolock _l(mLock); - if (mVideoRefCount == 0) { - ALOGW("BatteryNotifier::noteStop(): video refcount is broken!"); - return; - } - - sp<IBatteryStats> batteryService = getBatteryService_l(); - - mVideoRefCount--; - if (mVideoRefCount == 0 && batteryService != NULL) { - batteryService->noteStopVideo(AID_MEDIA); - } -} - -void MediaCodec::BatteryNotifier::noteStartAudio() { - Mutex::Autolock _l(mLock); - sp<IBatteryStats> batteryService = getBatteryService_l(); - if (mAudioRefCount == 0 && batteryService != NULL) { - batteryService->noteStartAudio(AID_MEDIA); - } - mAudioRefCount++; -} - -void MediaCodec::BatteryNotifier::noteStopAudio() { - Mutex::Autolock _l(mLock); - if (mAudioRefCount == 0) { - ALOGW("BatteryNotifier::noteStop(): audio refcount is broken!"); - return; - } - - sp<IBatteryStats> batteryService = getBatteryService_l(); - - mAudioRefCount--; - if (mAudioRefCount == 0 && batteryService != NULL) { - batteryService->noteStopAudio(AID_MEDIA); - } -} - -void MediaCodec::BatteryNotifier::onBatteryStatServiceDied() { - Mutex::Autolock _l(mLock); - mBatteryStatService.clear(); - mDeathNotifier.clear(); - // Do not reset mVideoRefCount and mAudioRefCount here. The ref - // counting is independent of the battery service availability. - // We need this if battery service becomes available after media - // started. -} - MediaCodec::ResourceManagerServiceProxy::ResourceManagerServiceProxy() { } diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp index 6708828..f366b1f 100644 --- a/media/libstagefright/MediaCodecList.cpp +++ b/media/libstagefright/MediaCodecList.cpp @@ -73,10 +73,24 @@ sp<IMediaCodecList> MediaCodecList::getLocalInstance() { if (gCodecList->initCheck() == OK) { sCodecList = gCodecList; - struct stat s; - if (stat(kProfilingResults, &s) == -1) { + FILE *resultsFile = fopen(kProfilingResults, "r"); + if (resultsFile) { + AString currentVersion = getProfilingVersionString(); + size_t currentVersionSize = currentVersion.size(); + char *versionString = new char[currentVersionSize]; + fgets(versionString, currentVersionSize, resultsFile); + if (strncmp(versionString, currentVersion.c_str(), currentVersionSize) != 0) { + // profiling result out of date + profilingNeeded = true; + } + fclose(resultsFile); + delete[] versionString; + } else { // profiling results doesn't existed profilingNeeded = true; + } + + if (profilingNeeded) { for (size_t i = 0; i < gCodecList->countCodecs(); ++i) { infos.push_back(gCodecList->getCodecInfo(i)); } diff --git a/media/libstagefright/MediaCodecListOverrides.cpp b/media/libstagefright/MediaCodecListOverrides.cpp index 006454d..a928163 100644 --- a/media/libstagefright/MediaCodecListOverrides.cpp +++ b/media/libstagefright/MediaCodecListOverrides.cpp @@ -20,6 +20,7 @@ #include "MediaCodecListOverrides.h" +#include <cutils/properties.h> #include <gui/Surface.h> #include <media/ICrypto.h> #include <media/IMediaCodecList.h> @@ -34,6 +35,15 @@ namespace android { const char *kProfilingResults = "/data/misc/media/media_codecs_profiling_results.xml"; +AString getProfilingVersionString() { + char val[PROPERTY_VALUE_MAX]; + if (property_get("ro.build.display.id", val, NULL) && (strlen(val) > 0)) { + return AStringPrintf("<!-- Profiled-with: %s -->", val); + } + + return "<!-- Profiled-with: UNKNOWN_BUILD_ID -->"; +} + // a limit to avoid allocating unreasonable number of codec instances in the measurement. // this should be in sync with the MAX_SUPPORTED_INSTANCES defined in MediaCodecInfo.java. static const int kMaxInstances = 32; @@ -375,6 +385,8 @@ void exportResultsToXML( } AString overrides; + overrides.append(getProfilingVersionString()); + overrides.append("\n"); overrides.append("<MediaCodecs>\n"); if (global_results.size() > 0) { overrides.append(" <Settings>\n"); diff --git a/media/libstagefright/MediaCodecListOverrides.h b/media/libstagefright/MediaCodecListOverrides.h index e350d2a..d4bb225 100644 --- a/media/libstagefright/MediaCodecListOverrides.h +++ b/media/libstagefright/MediaCodecListOverrides.h @@ -26,10 +26,13 @@ namespace android { +extern const char *kProfilingVersionString; extern const char *kProfilingResults; struct MediaCodecInfo; +AString getProfilingVersionString(); + bool splitString(const AString &s, const AString &delimiter, AString *s1, AString *s2); // profile codecs and save the result to xml file named kProfilingResults. diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp index f1ebea2..5d04628 100644 --- a/media/libstagefright/OMXClient.cpp +++ b/media/libstagefright/OMXClient.cpp @@ -72,7 +72,7 @@ struct MuxOMX : public IOMX { node_id node, OMX_STATETYPE* state); virtual status_t storeMetaDataInBuffers( - node_id node, OMX_U32 port_index, OMX_BOOL enable); + node_id node, OMX_U32 port_index, OMX_BOOL enable, MetadataBufferType *type); virtual status_t prepareForAdaptivePlayback( node_id node, OMX_U32 port_index, OMX_BOOL enable, @@ -90,7 +90,7 @@ struct MuxOMX : public IOMX { virtual status_t useBuffer( node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, - buffer_id *buffer); + buffer_id *buffer, OMX_U32 allottedSize); virtual status_t useGraphicBuffer( node_id node, OMX_U32 port_index, @@ -102,7 +102,7 @@ struct MuxOMX : public IOMX { virtual status_t createInputSurface( node_id node, OMX_U32 port_index, - sp<IGraphicBufferProducer> *bufferProducer); + sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type); virtual status_t createPersistentInputSurface( sp<IGraphicBufferProducer> *bufferProducer, @@ -110,7 +110,7 @@ struct MuxOMX : public IOMX { virtual status_t setInputSurface( node_id node, OMX_U32 port_index, - const sp<IGraphicBufferConsumer> &bufferConsumer); + const sp<IGraphicBufferConsumer> &bufferConsumer, MetadataBufferType *type); virtual status_t signalEndOfInputStream(node_id node); @@ -120,7 +120,7 @@ struct MuxOMX : public IOMX { virtual status_t allocateBufferWithBackup( node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, - buffer_id *buffer); + buffer_id *buffer, OMX_U32 allottedSize); virtual status_t freeBuffer( node_id node, OMX_U32 port_index, buffer_id buffer); @@ -292,8 +292,8 @@ status_t MuxOMX::getState( } status_t MuxOMX::storeMetaDataInBuffers( - node_id node, OMX_U32 port_index, OMX_BOOL enable) { - return getOMX(node)->storeMetaDataInBuffers(node, port_index, enable); + node_id node, OMX_U32 port_index, OMX_BOOL enable, MetadataBufferType *type) { + return getOMX(node)->storeMetaDataInBuffers(node, port_index, enable, type); } status_t MuxOMX::prepareForAdaptivePlayback( @@ -322,8 +322,8 @@ status_t MuxOMX::getGraphicBufferUsage( status_t MuxOMX::useBuffer( node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, - buffer_id *buffer) { - return getOMX(node)->useBuffer(node, port_index, params, buffer); + buffer_id *buffer, OMX_U32 allottedSize) { + return getOMX(node)->useBuffer(node, port_index, params, buffer, allottedSize); } status_t MuxOMX::useGraphicBuffer( @@ -342,9 +342,9 @@ status_t MuxOMX::updateGraphicBufferInMeta( status_t MuxOMX::createInputSurface( node_id node, OMX_U32 port_index, - sp<IGraphicBufferProducer> *bufferProducer) { + sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) { status_t err = getOMX(node)->createInputSurface( - node, port_index, bufferProducer); + node, port_index, bufferProducer, type); return err; } @@ -358,8 +358,8 @@ status_t MuxOMX::createPersistentInputSurface( status_t MuxOMX::setInputSurface( node_id node, OMX_U32 port_index, - const sp<IGraphicBufferConsumer> &bufferConsumer) { - return getOMX(node)->setInputSurface(node, port_index, bufferConsumer); + const sp<IGraphicBufferConsumer> &bufferConsumer, MetadataBufferType *type) { + return getOMX(node)->setInputSurface(node, port_index, bufferConsumer, type); } status_t MuxOMX::signalEndOfInputStream(node_id node) { @@ -375,9 +375,9 @@ status_t MuxOMX::allocateBuffer( status_t MuxOMX::allocateBufferWithBackup( node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, - buffer_id *buffer) { + buffer_id *buffer, OMX_U32 allottedSize) { return getOMX(node)->allocateBufferWithBackup( - node, port_index, params, buffer); + node, port_index, params, buffer, allottedSize); } status_t MuxOMX::freeBuffer( diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index aa6a7c0..927cc6c 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -1678,7 +1678,7 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) { &info.mData); } else { err = mOMX->allocateBufferWithBackup( - mNode, portIndex, mem, &buffer); + mNode, portIndex, mem, &buffer, mem->size()); } } else if (portIndex == kPortIndexOutput && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) { @@ -1690,10 +1690,10 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) { &info.mData); } else { err = mOMX->allocateBufferWithBackup( - mNode, portIndex, mem, &buffer); + mNode, portIndex, mem, &buffer, mem->size()); } } else { - err = mOMX->useBuffer(mNode, portIndex, mem, &buffer); + err = mOMX->useBuffer(mNode, portIndex, mem, &buffer, mem->size()); } if (err != OK) { diff --git a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp index d1b0f76..a9723ea 100644 --- a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp +++ b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp @@ -428,7 +428,15 @@ void SoftAMR::onQueueFilled(OMX_U32 /* portIndex */) { } } -void SoftAMR::onPortFlushCompleted(OMX_U32 /* portIndex */) { +void SoftAMR::onPortFlushCompleted(OMX_U32 portIndex) { + ALOGV("onPortFlushCompleted portindex %d, resetting frame ", portIndex); + if (portIndex == 0) { + if (mMode == MODE_NARROW) { + Speech_Decode_Frame_reset(mState); + } else { + pvDecoder_AmrWb_Reset(mState, 0 /* reset_all */); + } + } } void SoftAMR::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h index c183208..c34954b 100644 --- a/media/libstagefright/include/OMX.h +++ b/media/libstagefright/include/OMX.h @@ -69,7 +69,7 @@ public: node_id node, OMX_U32 port_index, OMX_U32* usage); virtual status_t storeMetaDataInBuffers( - node_id node, OMX_U32 port_index, OMX_BOOL enable); + node_id node, OMX_U32 port_index, OMX_BOOL enable, MetadataBufferType *type); virtual status_t prepareForAdaptivePlayback( node_id node, OMX_U32 portIndex, OMX_BOOL enable, @@ -81,7 +81,7 @@ public: virtual status_t useBuffer( node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, - buffer_id *buffer); + buffer_id *buffer, OMX_U32 allottedSize); virtual status_t useGraphicBuffer( node_id node, OMX_U32 port_index, @@ -93,7 +93,8 @@ public: virtual status_t createInputSurface( node_id node, OMX_U32 port_index, - sp<IGraphicBufferProducer> *bufferProducer); + sp<IGraphicBufferProducer> *bufferProducer, + MetadataBufferType *type); virtual status_t createPersistentInputSurface( sp<IGraphicBufferProducer> *bufferProducer, @@ -101,7 +102,8 @@ public: virtual status_t setInputSurface( node_id node, OMX_U32 port_index, - const sp<IGraphicBufferConsumer> &bufferConsumer); + const sp<IGraphicBufferConsumer> &bufferConsumer, + MetadataBufferType *type); virtual status_t signalEndOfInputStream(node_id node); @@ -111,7 +113,7 @@ public: virtual status_t allocateBufferWithBackup( node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, - buffer_id *buffer); + buffer_id *buffer, OMX_U32 allottedSize); virtual status_t freeBuffer( node_id node, OMX_U32 port_index, buffer_id buffer); diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h index 3c032f9..fe6dccd 100644 --- a/media/libstagefright/include/OMXNodeInstance.h +++ b/media/libstagefright/include/OMXNodeInstance.h @@ -58,7 +58,8 @@ struct OMXNodeInstance { status_t getGraphicBufferUsage(OMX_U32 portIndex, OMX_U32* usage); - status_t storeMetaDataInBuffers(OMX_U32 portIndex, OMX_BOOL enable); + status_t storeMetaDataInBuffers( + OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type); status_t prepareForAdaptivePlayback( OMX_U32 portIndex, OMX_BOOL enable, @@ -70,7 +71,7 @@ struct OMXNodeInstance { status_t useBuffer( OMX_U32 portIndex, const sp<IMemory> ¶ms, - OMX::buffer_id *buffer); + OMX::buffer_id *buffer, OMX_U32 allottedSize); status_t useGraphicBuffer( OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer, @@ -81,14 +82,16 @@ struct OMXNodeInstance { OMX::buffer_id buffer); status_t createInputSurface( - OMX_U32 portIndex, sp<IGraphicBufferProducer> *bufferProducer); + OMX_U32 portIndex, sp<IGraphicBufferProducer> *bufferProducer, + MetadataBufferType *type); static status_t createPersistentInputSurface( sp<IGraphicBufferProducer> *bufferProducer, sp<IGraphicBufferConsumer> *bufferConsumer); status_t setInputSurface( - OMX_U32 portIndex, const sp<IGraphicBufferConsumer> &bufferConsumer); + OMX_U32 portIndex, const sp<IGraphicBufferConsumer> &bufferConsumer, + MetadataBufferType *type); status_t signalEndOfInputStream(); @@ -98,7 +101,7 @@ struct OMXNodeInstance { status_t allocateBufferWithBackup( OMX_U32 portIndex, const sp<IMemory> ¶ms, - OMX::buffer_id *buffer); + OMX::buffer_id *buffer, OMX_U32 allottedSize); status_t freeBuffer(OMX_U32 portIndex, OMX::buffer_id buffer); @@ -109,9 +112,8 @@ struct OMXNodeInstance { OMX_U32 rangeOffset, OMX_U32 rangeLength, OMX_U32 flags, OMX_TICKS timestamp); - status_t emptyDirectBuffer( - OMX_BUFFERHEADERTYPE *header, - OMX_U32 rangeOffset, OMX_U32 rangeLength, + status_t emptyGraphicBuffer( + OMX_BUFFERHEADERTYPE *header, const sp<GraphicBuffer> &buffer, OMX_U32 flags, OMX_TICKS timestamp); status_t getExtensionIndex( @@ -156,6 +158,7 @@ private: uint32_t mBufferIDCount; KeyedVector<OMX::buffer_id, OMX_BUFFERHEADERTYPE *> mBufferIDToBufferHeader; KeyedVector<OMX_BUFFERHEADERTYPE *, OMX::buffer_id> mBufferHeaderToBufferID; + MetadataBufferType mMetadataType[2]; // For debug support char *mName; @@ -203,15 +206,19 @@ private: OMX_IN OMX_BUFFERHEADERTYPE *pBuffer); status_t storeMetaDataInBuffers_l( - OMX_U32 portIndex, OMX_BOOL enable, - OMX_BOOL useGraphicBuffer, OMX_BOOL *usingGraphicBufferInMeta); + OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type); status_t emptyBuffer_l( OMX_BUFFERHEADERTYPE *header, OMX_U32 flags, OMX_TICKS timestamp, intptr_t debugAddr); + status_t updateGraphicBufferInMeta_l( + OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer, + OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header); + status_t createGraphicBufferSource( - OMX_U32 portIndex, sp<IGraphicBufferConsumer> consumer = NULL); + OMX_U32 portIndex, sp<IGraphicBufferConsumer> consumer /* nullable */, + MetadataBufferType *type); sp<GraphicBufferSource> getGraphicBufferSource(); void setGraphicBufferSource(const sp<GraphicBufferSource>& bufferSource); diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp index e0ee87b..aae3e9f 100644 --- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp +++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp @@ -194,18 +194,19 @@ void MPEG2TSExtractor::init() { ATSParser::VIDEO).get() : (AnotherPacketSource *)mParser->getSource( ATSParser::AUDIO).get(); - int64_t prevBufferedDurationUs = 0; + size_t prevSyncSize = 1; int64_t durationUs = -1; List<int64_t> durations; // Estimate duration --- stabilize until you get <500ms deviation. - while (feedMore() == OK && ALooper::GetNowUs() - startTime <= 2000000ll) { - status_t err; - int64_t bufferedDurationUs = impl->getBufferedDurationUs(&err); - if (err != OK) { - break; - } - if (bufferedDurationUs != prevBufferedDurationUs) { - durationUs = size * bufferedDurationUs / mOffset; + while (feedMore() == OK + && ALooper::GetNowUs() - startTime <= 2000000ll) { + if (mSeekSyncPoints->size() > prevSyncSize) { + prevSyncSize = mSeekSyncPoints->size(); + int64_t diffUs = mSeekSyncPoints->keyAt(prevSyncSize - 1) + - mSeekSyncPoints->keyAt(0); + off64_t diffOffset = mSeekSyncPoints->valueAt(prevSyncSize - 1) + - mSeekSyncPoints->valueAt(0); + durationUs = size * diffUs / diffOffset; durations.push_back(durationUs); if (durations.size() > 5) { durations.erase(durations.begin()); @@ -225,9 +226,14 @@ void MPEG2TSExtractor::init() { break; } } - prevBufferedDurationUs = bufferedDurationUs; } } + status_t err; + int64_t bufferedDurationUs; + bufferedDurationUs = impl->getBufferedDurationUs(&err); + if (err == ERROR_END_OF_STREAM) { + durationUs = bufferedDurationUs; + } if (durationUs > 0) { const sp<MetaData> meta = impl->getFormat(); meta->setInt64(kKeyDuration, durationUs); diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index 01cd8f0..f797e63 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -29,6 +29,7 @@ #include <media/hardware/MetadataBufferType.h> #include <ui/GraphicBuffer.h> #include <gui/BufferItem.h> +#include <HardwareAPI.h> #include <inttypes.h> #include "FrameDropper.h" @@ -43,7 +44,6 @@ GraphicBufferSource::GraphicBufferSource( uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount, - bool useGraphicBufferInMeta, const sp<IGraphicBufferConsumer> &consumer) : mInitCheck(UNKNOWN_ERROR), mNodeInstance(nodeInstance), @@ -68,8 +68,7 @@ GraphicBufferSource::GraphicBufferSource( mTimePerCaptureUs(-1ll), mTimePerFrameUs(-1ll), mPrevCaptureUs(-1ll), - mPrevFrameUs(-1ll), - mUseGraphicBufferInMeta(useGraphicBufferInMeta) { + mPrevFrameUs(-1ll) { ALOGV("GraphicBufferSource w=%u h=%u c=%u", bufferWidth, bufferHeight, bufferCount); @@ -262,27 +261,27 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) { return; } - if (EXTRA_CHECK) { + if (EXTRA_CHECK && header->nAllocLen >= sizeof(MetadataBufferType)) { // Pull the graphic buffer handle back out of the buffer, and confirm // that it matches expectations. OMX_U8* data = header->pBuffer; MetadataBufferType type = *(MetadataBufferType *)data; - if (type == kMetadataBufferTypeGrallocSource) { - buffer_handle_t bufferHandle; - memcpy(&bufferHandle, data + 4, sizeof(buffer_handle_t)); - if (bufferHandle != codecBuffer.mGraphicBuffer->handle) { + if (type == kMetadataBufferTypeGrallocSource + && header->nAllocLen >= sizeof(VideoGrallocMetadata)) { + VideoGrallocMetadata &grallocMeta = *(VideoGrallocMetadata *)data; + if (grallocMeta.hHandle != codecBuffer.mGraphicBuffer->handle) { // should never happen ALOGE("codecBufferEmptied: buffer's handle is %p, expected %p", - bufferHandle, codecBuffer.mGraphicBuffer->handle); + grallocMeta.hHandle, codecBuffer.mGraphicBuffer->handle); CHECK(!"codecBufferEmptied: mismatched buffer"); } - } else if (type == kMetadataBufferTypeGraphicBuffer) { - GraphicBuffer *buffer; - memcpy(&buffer, data + 4, sizeof(buffer)); - if (buffer != codecBuffer.mGraphicBuffer.get()) { + } else if (type == kMetadataBufferTypeANWBuffer + && header->nAllocLen >= sizeof(VideoNativeMetadata)) { + VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)data; + if (nativeMeta.pBuffer != codecBuffer.mGraphicBuffer->getNativeBuffer()) { // should never happen ALOGE("codecBufferEmptied: buffer is %p, expected %p", - buffer, codecBuffer.mGraphicBuffer.get()); + nativeMeta.pBuffer, codecBuffer.mGraphicBuffer->getNativeBuffer()); CHECK(!"codecBufferEmptied: mismatched buffer"); } } @@ -703,36 +702,17 @@ status_t GraphicBufferSource::submitBuffer_l( codecBuffer.mFrameNumber = item.mFrameNumber; OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader; - CHECK(header->nAllocLen >= 4 + sizeof(buffer_handle_t)); - OMX_U8* data = header->pBuffer; - buffer_handle_t handle; - if (!mUseGraphicBufferInMeta) { - const OMX_U32 type = kMetadataBufferTypeGrallocSource; - handle = codecBuffer.mGraphicBuffer->handle; - memcpy(data, &type, 4); - memcpy(data + 4, &handle, sizeof(buffer_handle_t)); - } else { - // codecBuffer holds a reference to the GraphicBuffer, so - // it is valid while it is with the OMX component - const OMX_U32 type = kMetadataBufferTypeGraphicBuffer; - memcpy(data, &type, 4); - // passing a non-reference-counted graphicBuffer - GraphicBuffer *buffer = codecBuffer.mGraphicBuffer.get(); - handle = buffer->handle; - memcpy(data + 4, &buffer, sizeof(buffer)); - } - - status_t err = mNodeInstance->emptyDirectBuffer(header, 0, - 4 + sizeof(buffer_handle_t), OMX_BUFFERFLAG_ENDOFFRAME, - timeUs); + sp<GraphicBuffer> buffer = codecBuffer.mGraphicBuffer; + status_t err = mNodeInstance->emptyGraphicBuffer( + header, buffer, OMX_BUFFERFLAG_ENDOFFRAME, timeUs); if (err != OK) { - ALOGW("WARNING: emptyDirectBuffer failed: 0x%x", err); + ALOGW("WARNING: emptyNativeWindowBuffer failed: 0x%x", err); codecBuffer.mGraphicBuffer = NULL; return err; } - ALOGV("emptyDirectBuffer succeeded, h=%p p=%p bufhandle=%p", - header, header->pBuffer, handle); + ALOGV("emptyNativeWindowBuffer succeeded, h=%p p=%p buf=%p bufhandle=%p", + header, header->pBuffer, buffer->getNativeBuffer(), buffer->handle); return OK; } @@ -755,19 +735,9 @@ void GraphicBufferSource::submitEndOfInputStream_l() { CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi)); OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader; - if (EXTRA_CHECK) { - // Guard against implementations that don't check nFilledLen. - size_t fillLen = 4 + sizeof(buffer_handle_t); - CHECK(header->nAllocLen >= fillLen); - OMX_U8* data = header->pBuffer; - memset(data, 0xcd, fillLen); - } - - uint64_t timestamp = 0; // does this matter? - - status_t err = mNodeInstance->emptyDirectBuffer(header, /*offset*/ 0, - /*length*/ 0, OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS, - timestamp); + status_t err = mNodeInstance->emptyGraphicBuffer( + header, NULL /* buffer */, OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS, + 0 /* timestamp */); if (err != OK) { ALOGW("emptyDirectBuffer EOS failed: 0x%x", err); } else { diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h index 1047fb3..21ee96a 100644 --- a/media/libstagefright/omx/GraphicBufferSource.h +++ b/media/libstagefright/omx/GraphicBufferSource.h @@ -55,7 +55,6 @@ public: uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount, - bool useGraphicBufferInMeta = false, const sp<IGraphicBufferConsumer> &consumer = NULL ); @@ -286,7 +285,7 @@ private: int64_t mPrevCaptureUs; int64_t mPrevFrameUs; - bool mUseGraphicBufferInMeta; + MetadataBufferType mMetadataBufferType; void onMessageReceived(const sp<AMessage> &msg); diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index a1ceb2e..4ca827c 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -332,8 +332,8 @@ status_t OMX::getGraphicBufferUsage( } status_t OMX::storeMetaDataInBuffers( - node_id node, OMX_U32 port_index, OMX_BOOL enable) { - return findInstance(node)->storeMetaDataInBuffers(port_index, enable); + node_id node, OMX_U32 port_index, OMX_BOOL enable, MetadataBufferType *type) { + return findInstance(node)->storeMetaDataInBuffers(port_index, enable, type); } status_t OMX::prepareForAdaptivePlayback( @@ -352,9 +352,9 @@ status_t OMX::configureVideoTunnelMode( status_t OMX::useBuffer( node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, - buffer_id *buffer) { + buffer_id *buffer, OMX_U32 allottedSize) { return findInstance(node)->useBuffer( - port_index, params, buffer); + port_index, params, buffer, allottedSize); } status_t OMX::useGraphicBuffer( @@ -373,9 +373,9 @@ status_t OMX::updateGraphicBufferInMeta( status_t OMX::createInputSurface( node_id node, OMX_U32 port_index, - sp<IGraphicBufferProducer> *bufferProducer) { + sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) { return findInstance(node)->createInputSurface( - port_index, bufferProducer); + port_index, bufferProducer, type); } status_t OMX::createPersistentInputSurface( @@ -387,8 +387,8 @@ status_t OMX::createPersistentInputSurface( status_t OMX::setInputSurface( node_id node, OMX_U32 port_index, - const sp<IGraphicBufferConsumer> &bufferConsumer) { - return findInstance(node)->setInputSurface(port_index, bufferConsumer); + const sp<IGraphicBufferConsumer> &bufferConsumer, MetadataBufferType *type) { + return findInstance(node)->setInputSurface(port_index, bufferConsumer, type); } @@ -405,9 +405,9 @@ status_t OMX::allocateBuffer( status_t OMX::allocateBufferWithBackup( node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, - buffer_id *buffer) { + buffer_id *buffer, OMX_U32 allottedSize) { return findInstance(node)->allocateBufferWithBackup( - port_index, params, buffer); + port_index, params, buffer, allottedSize); } status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) { diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index 3dc1f7f..e4b2de4 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -32,6 +32,7 @@ #include <gui/BufferQueue.h> #include <HardwareAPI.h> #include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/MediaErrors.h> #include <utils/misc.h> @@ -135,6 +136,18 @@ struct BufferMeta { header->nFilledLen); } + // return either the codec or the backup buffer + sp<ABuffer> getBuffer(const OMX_BUFFERHEADERTYPE *header, bool backup) { + sp<ABuffer> buf; + if (backup && mMem != NULL) { + buf = new ABuffer(mMem->pointer(), mMem->size()); + } else { + buf = new ABuffer(header->pBuffer, header->nAllocLen); + } + buf->setRange(header->nOffset, header->nFilledLen); + return buf; + } + void setGraphicBuffer(const sp<GraphicBuffer> &graphicBuffer) { mGraphicBuffer = graphicBuffer; } @@ -180,6 +193,8 @@ OMXNodeInstance::OMXNodeInstance( mNumPortBuffers[1] = 0; mDebugLevelBumpPendingBuffers[0] = 0; mDebugLevelBumpPendingBuffers[1] = 0; + mMetadataType[0] = kMetadataBufferTypeInvalid; + mMetadataType[1] = kMetadataBufferTypeInvalid; } OMXNodeInstance::~OMXNodeInstance() { @@ -486,63 +501,73 @@ status_t OMXNodeInstance::getGraphicBufferUsage( } status_t OMXNodeInstance::storeMetaDataInBuffers( - OMX_U32 portIndex, - OMX_BOOL enable) { + OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type) { Mutex::Autolock autolock(mLock); CLOG_CONFIG(storeMetaDataInBuffers, "%s:%u en:%d", portString(portIndex), portIndex, enable); - return storeMetaDataInBuffers_l( - portIndex, enable, - OMX_FALSE /* useGraphicBuffer */, NULL /* usingGraphicBufferInMetadata */); + return storeMetaDataInBuffers_l(portIndex, enable, type); } status_t OMXNodeInstance::storeMetaDataInBuffers_l( - OMX_U32 portIndex, - OMX_BOOL enable, - OMX_BOOL useGraphicBuffer, - OMX_BOOL *usingGraphicBufferInMetadata) { + OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type) { + if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) { + return BAD_VALUE; + } + OMX_INDEXTYPE index; OMX_STRING name = const_cast<OMX_STRING>( "OMX.google.android.index.storeMetaDataInBuffers"); - OMX_STRING graphicBufferName = const_cast<OMX_STRING>( - "OMX.google.android.index.storeGraphicBufferInMetaData"); - if (usingGraphicBufferInMetadata == NULL) { - usingGraphicBufferInMetadata = &useGraphicBuffer; - } + OMX_STRING nativeBufferName = const_cast<OMX_STRING>( + "OMX.google.android.index.storeANWBufferInMetadata"); + MetadataBufferType negotiatedType; - OMX_ERRORTYPE err = - (useGraphicBuffer && portIndex == kPortIndexInput) - ? OMX_GetExtensionIndex(mHandle, graphicBufferName, &index) - : OMX_ErrorBadParameter; - if (err == OMX_ErrorNone) { - *usingGraphicBufferInMetadata = OMX_TRUE; - name = graphicBufferName; - } else { - err = OMX_GetExtensionIndex(mHandle, name, &index); - } + StoreMetaDataInBuffersParams params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + params.bStoreMetaData = enable; + OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, nativeBufferName, &index); OMX_ERRORTYPE xerr = err; if (err == OMX_ErrorNone) { - StoreMetaDataInBuffersParams params; - InitOMXParams(¶ms); - params.nPortIndex = portIndex; - params.bStoreMetaData = enable; - err = OMX_SetParameter(mHandle, index, ¶ms); + if (err == OMX_ErrorNone) { + name = nativeBufferName; // set name for debugging + negotiatedType = kMetadataBufferTypeANWBuffer; + } + } + if (err != OMX_ErrorNone) { + err = OMX_GetExtensionIndex(mHandle, name, &index); + xerr = err; + if (err == OMX_ErrorNone) { + negotiatedType = kMetadataBufferTypeGrallocSource; + err = OMX_SetParameter(mHandle, index, ¶ms); + } } // don't log loud error if component does not support metadata mode on the output if (err != OMX_ErrorNone) { - *usingGraphicBufferInMetadata = OMX_FALSE; if (err == OMX_ErrorUnsupportedIndex && portIndex == kPortIndexOutput) { CLOGW("component does not support metadata mode; using fallback"); } else if (xerr != OMX_ErrorNone) { CLOG_ERROR(getExtensionIndex, xerr, "%s", name); } else { - CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d GB=%d", name, index, - portString(portIndex), portIndex, enable, useGraphicBuffer); + CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d type=%d", name, index, + portString(portIndex), portIndex, enable, negotiatedType); + } + negotiatedType = mMetadataType[portIndex]; + } else { + if (!enable) { + negotiatedType = kMetadataBufferTypeInvalid; } + mMetadataType[portIndex] = negotiatedType; } + CLOG_CONFIG(storeMetaDataInBuffers, "%s:%u negotiated %s:%d", + portString(portIndex), portIndex, asString(negotiatedType), negotiatedType); + + if (type != NULL) { + *type = negotiatedType; + } + return StatusFromOMXError(err); } @@ -620,8 +645,11 @@ status_t OMXNodeInstance::configureVideoTunnelMode( status_t OMXNodeInstance::useBuffer( OMX_U32 portIndex, const sp<IMemory> ¶ms, - OMX::buffer_id *buffer) { + OMX::buffer_id *buffer, OMX_U32 allottedSize) { Mutex::Autolock autoLock(mLock); + if (allottedSize > params->size()) { + return BAD_VALUE; + } BufferMeta *buffer_meta = new BufferMeta(params); @@ -629,10 +657,11 @@ status_t OMXNodeInstance::useBuffer( OMX_ERRORTYPE err = OMX_UseBuffer( mHandle, &header, portIndex, buffer_meta, - params->size(), static_cast<OMX_U8 *>(params->pointer())); + allottedSize, static_cast<OMX_U8 *>(params->pointer())); if (err != OMX_ErrorNone) { - CLOG_ERROR(useBuffer, err, SIMPLE_BUFFER(portIndex, params->size(), params->pointer())); + CLOG_ERROR(useBuffer, err, SIMPLE_BUFFER( + portIndex, (size_t)allottedSize, params->pointer())); delete buffer_meta; buffer_meta = NULL; @@ -654,7 +683,7 @@ status_t OMXNodeInstance::useBuffer( } CLOG_BUFFER(useBuffer, NEW_BUFFER_FMT( - *buffer, portIndex, "%zu@%p", params->size(), params->pointer())); + *buffer, portIndex, "%u@%p", allottedSize, params->pointer())); return OK; } @@ -770,37 +799,59 @@ status_t OMXNodeInstance::useGraphicBuffer( return OK; } -status_t OMXNodeInstance::updateGraphicBufferInMeta( +status_t OMXNodeInstance::updateGraphicBufferInMeta_l( OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer, - OMX::buffer_id buffer) { - Mutex::Autolock autoLock(mLock); + OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header) { + if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) { + return BAD_VALUE; + } - OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer); - VideoDecoderOutputMetaData *metadata = - (VideoDecoderOutputMetaData *)(header->pBuffer); BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate); bufferMeta->setGraphicBuffer(graphicBuffer); - metadata->eType = kMetadataBufferTypeGrallocSource; - metadata->pHandle = graphicBuffer->handle; + if (mMetadataType[portIndex] == kMetadataBufferTypeGrallocSource + && header->nAllocLen >= sizeof(VideoGrallocMetadata)) { + VideoGrallocMetadata &metadata = *(VideoGrallocMetadata *)(header->pBuffer); + metadata.eType = kMetadataBufferTypeGrallocSource; + metadata.hHandle = graphicBuffer == NULL ? NULL : graphicBuffer->handle; + } else if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer + && header->nAllocLen >= sizeof(VideoNativeMetadata)) { + VideoNativeMetadata &metadata = *(VideoNativeMetadata *)(header->pBuffer); + metadata.eType = kMetadataBufferTypeANWBuffer; + metadata.pBuffer = graphicBuffer == NULL ? NULL : graphicBuffer->getNativeBuffer(); + metadata.nFenceFd = -1; + } else { + CLOG_BUFFER(updateGraphicBufferInMeta, "%s:%u, %#x bad type (%d) or size (%u)", + portString(portIndex), portIndex, buffer, mMetadataType[portIndex], header->nAllocLen); + return BAD_VALUE; + } + CLOG_BUFFER(updateGraphicBufferInMeta, "%s:%u, %#x := %p", portString(portIndex), portIndex, buffer, graphicBuffer->handle); return OK; } +status_t OMXNodeInstance::updateGraphicBufferInMeta( + OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer, + OMX::buffer_id buffer) { + Mutex::Autolock autoLock(mLock); + OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer); + return updateGraphicBufferInMeta_l(portIndex, graphicBuffer, buffer, header); +} + status_t OMXNodeInstance::createGraphicBufferSource( - OMX_U32 portIndex, sp<IGraphicBufferConsumer> bufferConsumer) { + OMX_U32 portIndex, sp<IGraphicBufferConsumer> bufferConsumer, MetadataBufferType *type) { status_t err; const sp<GraphicBufferSource>& surfaceCheck = getGraphicBufferSource(); if (surfaceCheck != NULL) { + if (portIndex < NELEM(mMetadataType) && type != NULL) { + *type = mMetadataType[portIndex]; + } return ALREADY_EXISTS; } - // Input buffers will hold meta-data (gralloc references). - OMX_BOOL usingGraphicBuffer = OMX_FALSE; - err = storeMetaDataInBuffers_l( - portIndex, OMX_TRUE, - OMX_TRUE /* useGraphicBuffer */, &usingGraphicBuffer); + // Input buffers will hold meta-data (ANativeWindowBuffer references). + err = storeMetaDataInBuffers_l(portIndex, OMX_TRUE, type); if (err != OK) { return err; } @@ -830,7 +881,6 @@ status_t OMXNodeInstance::createGraphicBufferSource( def.format.video.nFrameWidth, def.format.video.nFrameHeight, def.nBufferCountActual, - usingGraphicBuffer, bufferConsumer); if ((err = bufferSource->initCheck()) != OK) { @@ -842,9 +892,9 @@ status_t OMXNodeInstance::createGraphicBufferSource( } status_t OMXNodeInstance::createInputSurface( - OMX_U32 portIndex, sp<IGraphicBufferProducer> *bufferProducer) { + OMX_U32 portIndex, sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) { Mutex::Autolock autolock(mLock); - status_t err = createGraphicBufferSource(portIndex); + status_t err = createGraphicBufferSource(portIndex, NULL /* bufferConsumer */, type); if (err != OK) { return err; @@ -882,9 +932,10 @@ status_t OMXNodeInstance::createPersistentInputSurface( } status_t OMXNodeInstance::setInputSurface( - OMX_U32 portIndex, const sp<IGraphicBufferConsumer> &bufferConsumer) { + OMX_U32 portIndex, const sp<IGraphicBufferConsumer> &bufferConsumer, + MetadataBufferType *type) { Mutex::Autolock autolock(mLock); - return createGraphicBufferSource(portIndex, bufferConsumer); + return createGraphicBufferSource(portIndex, bufferConsumer, type); } status_t OMXNodeInstance::signalEndOfInputStream() { @@ -939,19 +990,21 @@ status_t OMXNodeInstance::allocateBuffer( status_t OMXNodeInstance::allocateBufferWithBackup( OMX_U32 portIndex, const sp<IMemory> ¶ms, - OMX::buffer_id *buffer) { + OMX::buffer_id *buffer, OMX_U32 allottedSize) { Mutex::Autolock autoLock(mLock); + if (allottedSize > params->size()) { + return BAD_VALUE; + } BufferMeta *buffer_meta = new BufferMeta(params, true); OMX_BUFFERHEADERTYPE *header; OMX_ERRORTYPE err = OMX_AllocateBuffer( - mHandle, &header, portIndex, buffer_meta, params->size()); - + mHandle, &header, portIndex, buffer_meta, allottedSize); if (err != OMX_ErrorNone) { CLOG_ERROR(allocateBufferWithBackup, err, - SIMPLE_BUFFER(portIndex, params->size(), params->pointer())); + SIMPLE_BUFFER(portIndex, (size_t)allottedSize, params->pointer())); delete buffer_meta; buffer_meta = NULL; @@ -971,8 +1024,8 @@ status_t OMXNodeInstance::allocateBufferWithBackup( bufferSource->addCodecBuffer(header); } - CLOG_BUFFER(allocateBufferWithBackup, NEW_BUFFER_FMT(*buffer, portIndex, "%zu@%p :> %p", - params->size(), params->pointer(), header->pBuffer)); + CLOG_BUFFER(allocateBufferWithBackup, NEW_BUFFER_FMT(*buffer, portIndex, "%u@%p :> %p", + allottedSize, params->pointer(), header->pBuffer)); return OK; } @@ -1038,7 +1091,24 @@ status_t OMXNodeInstance::emptyBuffer( BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate); - buffer_meta->CopyToOMX(header); + sp<ABuffer> backup = buffer_meta->getBuffer(header, true /* backup */); + sp<ABuffer> codec = buffer_meta->getBuffer(header, false /* backup */); + + // convert incoming ANW meta buffers if component is configured for gralloc metadata mode + if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource + && backup->capacity() >= sizeof(VideoNativeMetadata) + && codec->capacity() >= sizeof(VideoGrallocMetadata) + && ((VideoNativeMetadata *)backup->base())->eType + == kMetadataBufferTypeANWBuffer) { + VideoNativeMetadata &backupMeta = *(VideoNativeMetadata *)backup->base(); + VideoGrallocMetadata &codecMeta = *(VideoGrallocMetadata *)codec->base(); + ALOGV("converting ANWB %p to handle %p", backupMeta.pBuffer, backupMeta.pBuffer->handle); + codecMeta.hHandle = backupMeta.pBuffer->handle; + codecMeta.eType = kMetadataBufferTypeGrallocSource; + header->nFilledLen = sizeof(codecMeta); + } else { + buffer_meta->CopyToOMX(header); + } return emptyBuffer_l(header, flags, timestamp, (intptr_t)buffer); } @@ -1100,15 +1170,19 @@ status_t OMXNodeInstance::emptyBuffer_l( } // like emptyBuffer, but the data is already in header->pBuffer -status_t OMXNodeInstance::emptyDirectBuffer( - OMX_BUFFERHEADERTYPE *header, - OMX_U32 rangeOffset, OMX_U32 rangeLength, +status_t OMXNodeInstance::emptyGraphicBuffer( + OMX_BUFFERHEADERTYPE *header, const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags, OMX_TICKS timestamp) { Mutex::Autolock autoLock(mLock); + OMX::buffer_id buffer = findBufferID(header); + status_t err = updateGraphicBufferInMeta_l(kPortIndexInput, graphicBuffer, buffer, header); + if (err != OK) { + CLOG_ERROR(emptyGraphicBuffer, err, FULL_BUFFER((intptr_t)header->pBuffer, header)); + return err; + } - header->nFilledLen = rangeLength; - header->nOffset = rangeOffset; - + header->nOffset = 0; + header->nFilledLen = graphicBuffer == NULL ? 0 : header->nAllocLen; return emptyBuffer_l(header, flags, timestamp, (intptr_t)header->pBuffer); } diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp index d4d6217..5f80cbc 100644 --- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp +++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp @@ -155,7 +155,7 @@ void SoftVideoEncoderOMXComponent::updatePortParams() { uint32_t rawBufferSize = inDef->format.video.nStride * inDef->format.video.nSliceHeight * 3 / 2; if (inDef->format.video.eColorFormat == OMX_COLOR_FormatAndroidOpaque) { - inDef->nBufferSize = 4 + max(sizeof(buffer_handle_t), sizeof(GraphicBuffer *)); + inDef->nBufferSize = max(sizeof(VideoNativeMetadata), sizeof(VideoGrallocMetadata)); } else { inDef->nBufferSize = rawBufferSize; } @@ -482,8 +482,8 @@ const uint8_t *SoftVideoEncoderOMXComponent::extractGraphicBuffer( size_t dstVStride = height; MetadataBufferType bufferType = *(MetadataBufferType *)src; - bool usingGraphicBuffer = bufferType == kMetadataBufferTypeGraphicBuffer; - if (!usingGraphicBuffer && bufferType != kMetadataBufferTypeGrallocSource) { + bool usingANWBuffer = bufferType == kMetadataBufferTypeANWBuffer; + if (!usingANWBuffer && bufferType != kMetadataBufferTypeGrallocSource) { ALOGE("Unsupported metadata type (%d)", bufferType); return NULL; } @@ -499,13 +499,14 @@ const uint8_t *SoftVideoEncoderOMXComponent::extractGraphicBuffer( int format; size_t srcStride; size_t srcVStride; - if (usingGraphicBuffer) { - if (srcSize < sizeof(OMX_U32) + sizeof(GraphicBuffer *)) { - ALOGE("Metadata is too small (%zu vs %zu)", srcSize, sizeof(OMX_U32) + sizeof(GraphicBuffer *)); + if (usingANWBuffer) { + if (srcSize < sizeof(VideoNativeMetadata)) { + ALOGE("Metadata is too small (%zu vs %zu)", srcSize, sizeof(VideoNativeMetadata)); return NULL; } - GraphicBuffer *buffer = *(GraphicBuffer **)(src + sizeof(OMX_U32)); + VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)src; + ANativeWindowBuffer *buffer = nativeMeta.pBuffer; handle = buffer->handle; format = buffer->format; srcStride = buffer->stride; @@ -519,12 +520,13 @@ const uint8_t *SoftVideoEncoderOMXComponent::extractGraphicBuffer( } else { // TODO: remove this part. Check if anyone uses this. - if (srcSize < sizeof(OMX_U32) + sizeof(buffer_handle_t)) { - ALOGE("Metadata is too small (%zu vs %zu)", srcSize, sizeof(OMX_U32) + sizeof(buffer_handle_t)); + if (srcSize < sizeof(VideoGrallocMetadata)) { + ALOGE("Metadata is too small (%zu vs %zu)", srcSize, sizeof(VideoGrallocMetadata)); return NULL; } - handle = *(buffer_handle_t *)(src + sizeof(OMX_U32)); + VideoGrallocMetadata &grallocMeta = *(VideoGrallocMetadata *)(src); + handle = grallocMeta.hHandle; // assume HAL_PIXEL_FORMAT_RGBA_8888 // there is no way to get the src stride without the graphic buffer format = HAL_PIXEL_FORMAT_RGBA_8888; @@ -606,7 +608,7 @@ const uint8_t *SoftVideoEncoderOMXComponent::extractGraphicBuffer( OMX_ERRORTYPE SoftVideoEncoderOMXComponent::getExtensionIndex( const char *name, OMX_INDEXTYPE *index) { if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers") || - !strcmp(name, "OMX.google.android.index.storeGraphicBufferInMetaData")) { + !strcmp(name, "OMX.google.android.index.storeANWBufferInMetadata")) { *(int32_t*)index = kStoreMetaDataExtensionIndex; return OMX_ErrorNone; } diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp index 67ff145..294b2ed 100644 --- a/media/libstagefright/omx/tests/OMXHarness.cpp +++ b/media/libstagefright/omx/tests/OMXHarness.cpp @@ -193,7 +193,7 @@ status_t Harness::allocatePortBuffers( CHECK(buffer.mMemory != NULL); err = mOMX->allocateBufferWithBackup( - node, portIndex, buffer.mMemory, &buffer.mID); + node, portIndex, buffer.mMemory, &buffer.mID, buffer.mMemory->size()); EXPECT_SUCCESS(err, "allocateBuffer"); buffers->push(buffer); diff --git a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp index cee62a3..ab547be 100644 --- a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp +++ b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp @@ -150,7 +150,11 @@ TEST_F(MediaCodecListOverridesTest, exportTestResultsToXML) { fclose(f); free(buf); - EXPECT_TRUE(overrides == kTestOverridesStr); + AString expected; + expected.append(getProfilingVersionString()); + expected.append("\n"); + expected.append(kTestOverridesStr); + EXPECT_TRUE(overrides == expected); remove(fileName); } diff --git a/media/utils/Android.mk b/media/utils/Android.mk new file mode 100644 index 0000000..dfadbc8 --- /dev/null +++ b/media/utils/Android.mk @@ -0,0 +1,39 @@ +# 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + BatteryNotifier.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libcutils \ + liblog \ + libutils \ + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include + +LOCAL_CFLAGS += \ + -Wall \ + -Wextra \ + -Werror \ + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include + +LOCAL_MODULE := libmediautils + +include $(BUILD_SHARED_LIBRARY) diff --git a/media/utils/BatteryNotifier.cpp b/media/utils/BatteryNotifier.cpp new file mode 100644 index 0000000..7f9cd7a --- /dev/null +++ b/media/utils/BatteryNotifier.cpp @@ -0,0 +1,213 @@ +/* + * 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. + */ + +#include "include/mediautils/BatteryNotifier.h" + +#include <binder/IServiceManager.h> +#include <utils/Log.h> +#include <private/android_filesystem_config.h> + +namespace android { + +void BatteryNotifier::DeathNotifier::binderDied(const wp<IBinder>& /*who*/) { + BatteryNotifier::getInstance().onBatteryStatServiceDied(); +} + +BatteryNotifier::BatteryNotifier() : mVideoRefCount(0), mAudioRefCount(0) {} + +BatteryNotifier::~BatteryNotifier() { + Mutex::Autolock _l(mLock); + if (mDeathNotifier != nullptr) { + IInterface::asBinder(mBatteryStatService)->unlinkToDeath(mDeathNotifier); + } +} + +void BatteryNotifier::noteStartVideo() { + Mutex::Autolock _l(mLock); + sp<IBatteryStats> batteryService = getBatteryService_l(); + if (mVideoRefCount == 0 && batteryService != nullptr) { + batteryService->noteStartVideo(AID_MEDIA); + } + mVideoRefCount++; +} + +void BatteryNotifier::noteStopVideo() { + Mutex::Autolock _l(mLock); + if (mVideoRefCount == 0) { + ALOGW("%s: video refcount is broken.", __FUNCTION__); + return; + } + + sp<IBatteryStats> batteryService = getBatteryService_l(); + + mVideoRefCount--; + if (mVideoRefCount == 0 && batteryService != nullptr) { + batteryService->noteStopVideo(AID_MEDIA); + } +} + +void BatteryNotifier::noteResetVideo() { + Mutex::Autolock _l(mLock); + sp<IBatteryStats> batteryService = getBatteryService_l(); + mVideoRefCount = 0; + if (batteryService != nullptr) { + batteryService->noteResetAudio(); + } +} + +void BatteryNotifier::noteStartAudio() { + Mutex::Autolock _l(mLock); + sp<IBatteryStats> batteryService = getBatteryService_l(); + if (mAudioRefCount == 0 && batteryService != nullptr) { + batteryService->noteStartAudio(AID_MEDIA); + } + mAudioRefCount++; +} + +void BatteryNotifier::noteStopAudio() { + Mutex::Autolock _l(mLock); + if (mAudioRefCount == 0) { + ALOGW("%s: audio refcount is broken.", __FUNCTION__); + return; + } + + sp<IBatteryStats> batteryService = getBatteryService_l(); + + mAudioRefCount--; + if (mAudioRefCount == 0 && batteryService != nullptr) { + batteryService->noteStopAudio(AID_MEDIA); + } +} + +void BatteryNotifier::noteResetAudio() { + Mutex::Autolock _l(mLock); + sp<IBatteryStats> batteryService = getBatteryService_l(); + mAudioRefCount = 0; + if (batteryService != nullptr) { + batteryService->noteResetAudio(); + } +} + +void BatteryNotifier::noteFlashlightOn(const String8& id, int uid) { + Mutex::Autolock _l(mLock); + sp<IBatteryStats> batteryService = getBatteryService_l(); + + std::pair<String8, int> k = std::make_pair(id, uid); + if (!mFlashlightState[k]) { + mFlashlightState[k] = true; + if (batteryService != nullptr) { + batteryService->noteFlashlightOn(uid); + } + } +} + +void BatteryNotifier::noteFlashlightOff(const String8& id, int uid) { + Mutex::Autolock _l(mLock); + sp<IBatteryStats> batteryService = getBatteryService_l(); + + std::pair<String8, int> k = std::make_pair(id, uid); + if (mFlashlightState[k]) { + mFlashlightState[k] = false; + if (batteryService != nullptr) { + batteryService->noteFlashlightOff(uid); + } + } +} + +void BatteryNotifier::noteResetFlashlight() { + Mutex::Autolock _l(mLock); + sp<IBatteryStats> batteryService = getBatteryService_l(); + mFlashlightState.clear(); + if (batteryService != nullptr) { + batteryService->noteResetFlashlight(); + } +} + +void BatteryNotifier::noteStartCamera(const String8& id, int uid) { + Mutex::Autolock _l(mLock); + sp<IBatteryStats> batteryService = getBatteryService_l(); + std::pair<String8, int> k = std::make_pair(id, uid); + if (!mCameraState[k]) { + mCameraState[k] = true; + if (batteryService != nullptr) { + batteryService->noteStartCamera(uid); + } + } +} + +void BatteryNotifier::noteStopCamera(const String8& id, int uid) { + Mutex::Autolock _l(mLock); + sp<IBatteryStats> batteryService = getBatteryService_l(); + std::pair<String8, int> k = std::make_pair(id, uid); + if (mCameraState[k]) { + mCameraState[k] = false; + if (batteryService != nullptr) { + batteryService->noteStopCamera(uid); + } + } +} + +void BatteryNotifier::noteResetCamera() { + Mutex::Autolock _l(mLock); + sp<IBatteryStats> batteryService = getBatteryService_l(); + mCameraState.clear(); + if (batteryService != nullptr) { + batteryService->noteResetCamera(); + } +} + +void BatteryNotifier::onBatteryStatServiceDied() { + Mutex::Autolock _l(mLock); + mBatteryStatService.clear(); + mDeathNotifier.clear(); + // Do not reset mVideoRefCount and mAudioRefCount here. The ref + // counting is independent of the battery service availability. + // We need this if battery service becomes available after media + // started. + +} + +sp<IBatteryStats> BatteryNotifier::getBatteryService_l() { + if (mBatteryStatService != nullptr) { + return mBatteryStatService; + } + // Get battery service from service manager + const sp<IServiceManager> sm(defaultServiceManager()); + if (sm != nullptr) { + const String16 name("batterystats"); + mBatteryStatService = interface_cast<IBatteryStats>(sm->checkService(name)); + if (mBatteryStatService == nullptr) { + ALOGE("batterystats service unavailable!"); + return nullptr; + } + + mDeathNotifier = new DeathNotifier(); + IInterface::asBinder(mBatteryStatService)->linkToDeath(mDeathNotifier); + + // Notify start now if media already started + if (mVideoRefCount > 0) { + mBatteryStatService->noteStartVideo(AID_MEDIA); + } + if (mAudioRefCount > 0) { + mBatteryStatService->noteStartAudio(AID_MEDIA); + } + } + return mBatteryStatService; +} + +ANDROID_SINGLETON_STATIC_INSTANCE(BatteryNotifier); + +} // namespace android diff --git a/media/utils/README b/media/utils/README new file mode 100644 index 0000000..65ab0b8 --- /dev/null +++ b/media/utils/README @@ -0,0 +1,4 @@ +This is a common shared library for media utility classes. + +Consider adding your utility class/function here if it will +be used across several of the media libraries. diff --git a/media/utils/include/mediautils/BatteryNotifier.h b/media/utils/include/mediautils/BatteryNotifier.h new file mode 100644 index 0000000..4904804 --- /dev/null +++ b/media/utils/include/mediautils/BatteryNotifier.h @@ -0,0 +1,73 @@ +/* + * 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_BATTERY_NOTIFIER_H +#define MEDIA_BATTERY_NOTIFIER_H + +#include <binder/IBatteryStats.h> +#include <utils/Singleton.h> +#include <utils/String8.h> + +#include <map> +#include <utility> + +namespace android { + +/** + * Class used for logging battery life events in mediaserver. + */ +class BatteryNotifier : public Singleton<BatteryNotifier> { + + friend class Singleton<BatteryNotifier>; + BatteryNotifier(); + +public: + ~BatteryNotifier(); + + void noteStartVideo(); + void noteStopVideo(); + void noteResetVideo(); + void noteStartAudio(); + void noteStopAudio(); + void noteResetAudio(); + void noteFlashlightOn(const String8& id, int uid); + void noteFlashlightOff(const String8& id, int uid); + void noteResetFlashlight(); + void noteStartCamera(const String8& id, int uid); + void noteStopCamera(const String8& id, int uid); + void noteResetCamera(); + +private: + void onBatteryStatServiceDied(); + + class DeathNotifier : public IBinder::DeathRecipient { + virtual void binderDied(const wp<IBinder>& /*who*/); + }; + + Mutex mLock; + int mVideoRefCount; + int mAudioRefCount; + std::map<std::pair<String8, int>, bool> mFlashlightState; + std::map<std::pair<String8, int>, bool> mCameraState; + sp<IBatteryStats> mBatteryStatService; + sp<DeathNotifier> mDeathNotifier; + + sp<IBatteryStats> getBatteryService_l(); +}; + +} // namespace android + +#endif // MEDIA_BATTERY_NOTIFIER_H diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index 8bccb47..949c91d 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -335,13 +335,21 @@ status_t AudioFlinger::EffectModule::configure() // TODO: handle configuration of effects replacing track process channelMask = thread->channelMask(); + mConfig.outputCfg.channels = channelMask; if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_MONO; } else { mConfig.inputCfg.channels = channelMask; + // TODO: Update this logic when multichannel effects are implemented. + // For offloaded tracks consider mono output as stereo for proper effect initialization + if (channelMask == AUDIO_CHANNEL_OUT_MONO) { + mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; + ALOGV("Overriding effect input and output as STEREO"); + } } - mConfig.outputCfg.channels = channelMask; + mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; mConfig.inputCfg.samplingRate = thread->sampleRate(); diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 0593e1b..7809eff 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -356,13 +356,47 @@ String8 devicesToString(audio_devices_t devices) AUDIO_DEVICE_OUT_SPEAKER, "SPEAKER", AUDIO_DEVICE_OUT_WIRED_HEADSET, "WIRED_HEADSET", AUDIO_DEVICE_OUT_WIRED_HEADPHONE, "WIRED_HEADPHONE", + AUDIO_DEVICE_OUT_BLUETOOTH_SCO, "BLUETOOTH_SCO", + AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, "BLUETOOTH_SCO_HEADSET", + AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, "BLUETOOTH_SCO_CARKIT", + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "BLUETOOTH_A2DP", + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, "BLUETOOTH_A2DP_HEADPHONES", + AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, "BLUETOOTH_A2DP_SPEAKER", + AUDIO_DEVICE_OUT_AUX_DIGITAL, "AUX_DIGITAL", + AUDIO_DEVICE_OUT_HDMI, "HDMI", + AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET, "ANLG_DOCK_HEADSET", + AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, "DGTL_DOCK_HEADSET", + AUDIO_DEVICE_OUT_USB_ACCESSORY, "USB_ACCESSORY", + AUDIO_DEVICE_OUT_USB_DEVICE, "USB_DEVICE", AUDIO_DEVICE_OUT_TELEPHONY_TX, "TELEPHONY_TX", + AUDIO_DEVICE_OUT_LINE, "LINE", + AUDIO_DEVICE_OUT_HDMI_ARC, "HDMI_ARC", + AUDIO_DEVICE_OUT_SPDIF, "SPDIF", + AUDIO_DEVICE_OUT_FM, "FM", + AUDIO_DEVICE_OUT_AUX_LINE, "AUX_LINE", + AUDIO_DEVICE_OUT_SPEAKER_SAFE, "SPEAKER_SAFE", AUDIO_DEVICE_NONE, "NONE", // must be last }, mappingsIn[] = { + AUDIO_DEVICE_IN_COMMUNICATION, "COMMUNICATION", + AUDIO_DEVICE_IN_AMBIENT, "AMBIENT", AUDIO_DEVICE_IN_BUILTIN_MIC, "BUILTIN_MIC", + AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, "BLUETOOTH_SCO_HEADSET", AUDIO_DEVICE_IN_WIRED_HEADSET, "WIRED_HEADSET", + AUDIO_DEVICE_IN_AUX_DIGITAL, "AUX_DIGITAL", AUDIO_DEVICE_IN_VOICE_CALL, "VOICE_CALL", + AUDIO_DEVICE_IN_TELEPHONY_RX, "TELEPHONY_RX", + AUDIO_DEVICE_IN_BACK_MIC, "BACK_MIC", AUDIO_DEVICE_IN_REMOTE_SUBMIX, "REMOTE_SUBMIX", + AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET, "ANLG_DOCK_HEADSET", + AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET, "DGTL_DOCK_HEADSET", + AUDIO_DEVICE_IN_USB_ACCESSORY, "USB_ACCESSORY", + AUDIO_DEVICE_IN_USB_DEVICE, "USB_DEVICE", + AUDIO_DEVICE_IN_FM_TUNER, "FM_TUNER", + AUDIO_DEVICE_IN_TV_TUNER, "TV_TUNER", + AUDIO_DEVICE_IN_LINE, "LINE", + AUDIO_DEVICE_IN_SPDIF, "SPDIF", + AUDIO_DEVICE_IN_BLUETOOTH_A2DP, "BLUETOOTH_A2DP", + AUDIO_DEVICE_IN_LOOPBACK, "LOOPBACK", AUDIO_DEVICE_NONE, "NONE", // must be last }; String8 result; diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index 9c60911..cbead32 100644 --- a/services/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk @@ -62,6 +62,7 @@ LOCAL_SHARED_LIBRARIES:= \ libbinder \ libcutils \ libmedia \ + libmediautils \ libcamera_client \ libgui \ libhardware \ diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 79e73f9..6f073ed 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -41,6 +41,7 @@ #include <media/AudioSystem.h> #include <media/IMediaHTTPService.h> #include <media/mediaplayer.h> +#include <mediautils/BatteryNotifier.h> #include <utils/Errors.h> #include <utils/Log.h> #include <utils/String16.h> @@ -140,6 +141,11 @@ void CameraService::onFirstRef() BnCameraService::onFirstRef(); + // Update battery life tracking if service is restarting + BatteryNotifier& notifier(BatteryNotifier::getInstance()); + notifier.noteResetCamera(); + notifier.noteResetFlashlight(); + camera_module_t *rawModule; int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID, (const hw_module_t **)&rawModule); @@ -336,12 +342,39 @@ void CameraService::onTorchStatusChangedLocked(const String8& cameraId, res = setTorchStatusLocked(cameraId, newStatus); if (res) { - ALOGE("%s: Failed to set the torch status", __FUNCTION__, - (uint32_t)newStatus); + ALOGE("%s: Failed to set the torch status", __FUNCTION__, (uint32_t)newStatus); return; } { + // Update battery life logging for flashlight + Mutex::Autolock al(mTorchClientMapMutex); + auto iter = mTorchUidMap.find(cameraId); + if (iter != mTorchUidMap.end()) { + int oldUid = iter->second.second; + int newUid = iter->second.first; + BatteryNotifier& notifier(BatteryNotifier::getInstance()); + if (oldUid != newUid) { + // If the UID has changed, log the status and update current UID in mTorchUidMap + if (status == ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON) { + notifier.noteFlashlightOff(cameraId, oldUid); + } + if (newStatus == ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON) { + notifier.noteFlashlightOn(cameraId, newUid); + } + iter->second.second = newUid; + } else { + // If the UID has not changed, log the status + if (newStatus == ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON) { + notifier.noteFlashlightOn(cameraId, oldUid); + } else { + notifier.noteFlashlightOff(cameraId, oldUid); + } + } + } + } + + { Mutex::Autolock lock(mStatusListenerLock); for (auto& i : mListenerList) { i->onTorchStatusChanged(newStatus, String16{cameraId}); @@ -1154,12 +1187,13 @@ status_t CameraService::connectDevice( status_t CameraService::setTorchMode(const String16& cameraId, bool enabled, const sp<IBinder>& clientBinder) { - if (enabled && clientBinder == NULL) { + if (enabled && clientBinder == nullptr) { ALOGE("%s: torch client binder is NULL", __FUNCTION__); return -EINVAL; } String8 id = String8(cameraId.string()); + int uid = getCallingUid(); // verify id is valid. auto state = getCameraState(id); @@ -1198,7 +1232,21 @@ status_t CameraService::setTorchMode(const String16& cameraId, bool enabled, } } + { + // Update UID map - this is used in the torch status changed callbacks, so must be done + // before setTorchMode + Mutex::Autolock al(mTorchClientMapMutex); + if (mTorchUidMap.find(id) == mTorchUidMap.end()) { + mTorchUidMap[id].first = uid; + mTorchUidMap[id].second = uid; + } else { + // Set the pending UID + mTorchUidMap[id].first = uid; + } + } + status_t res = mFlashlight->setTorchMode(id, enabled); + if (res) { ALOGE("%s: setting torch mode of camera %s to %d failed. %s (%d)", __FUNCTION__, id.string(), enabled, strerror(-res), res); @@ -1209,19 +1257,17 @@ status_t CameraService::setTorchMode(const String16& cameraId, bool enabled, // update the link to client's death Mutex::Autolock al(mTorchClientMapMutex); ssize_t index = mTorchClientMap.indexOfKey(id); + BatteryNotifier& notifier(BatteryNotifier::getInstance()); if (enabled) { if (index == NAME_NOT_FOUND) { mTorchClientMap.add(id, clientBinder); } else { - const sp<IBinder> oldBinder = mTorchClientMap.valueAt(index); - oldBinder->unlinkToDeath(this); - + mTorchClientMap.valueAt(index)->unlinkToDeath(this); mTorchClientMap.replaceValueAt(index, clientBinder); } clientBinder->linkToDeath(this); } else if (index != NAME_NOT_FOUND) { - sp<IBinder> oldBinder = mTorchClientMap.valueAt(index); - oldBinder->unlinkToDeath(this); + mTorchClientMap.valueAt(index)->unlinkToDeath(this); } } @@ -1243,8 +1289,7 @@ void CameraService::notifySystemEvent(int32_t eventId, const int32_t* args, size } } -status_t CameraService::addListener( - const sp<ICameraServiceListener>& listener) { +status_t CameraService::addListener(const sp<ICameraServiceListener>& listener) { ALOGV("%s: Add listener %p", __FUNCTION__, listener.get()); if (listener == 0) { @@ -1965,9 +2010,40 @@ String8 CameraService::CameraState::getId() const { } // ---------------------------------------------------------------------------- +// ClientEventListener +// ---------------------------------------------------------------------------- + +void CameraService::ClientEventListener::onClientAdded( + const resource_policy::ClientDescriptor<String8, + sp<CameraService::BasicClient>>& descriptor) { + auto basicClient = descriptor.getValue(); + if (basicClient.get() != nullptr) { + BatteryNotifier& notifier(BatteryNotifier::getInstance()); + notifier.noteStartCamera(descriptor.getKey(), + static_cast<int>(basicClient->getClientUid())); + } +} + +void CameraService::ClientEventListener::onClientRemoved( + const resource_policy::ClientDescriptor<String8, + sp<CameraService::BasicClient>>& descriptor) { + auto basicClient = descriptor.getValue(); + if (basicClient.get() != nullptr) { + BatteryNotifier& notifier(BatteryNotifier::getInstance()); + notifier.noteStopCamera(descriptor.getKey(), + static_cast<int>(basicClient->getClientUid())); + } +} + + +// ---------------------------------------------------------------------------- // CameraClientManager // ---------------------------------------------------------------------------- +CameraService::CameraClientManager::CameraClientManager() { + setListener(std::make_shared<ClientEventListener>()); +} + CameraService::CameraClientManager::~CameraClientManager() {} sp<CameraService::BasicClient> CameraService::CameraClientManager::getCameraClient( diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index ce3cb44..3298772 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -46,6 +46,7 @@ #include <string> #include <map> #include <memory> +#include <utility> namespace android { @@ -327,6 +328,20 @@ public: }; // class Client + /** + * A listener class that implements the LISTENER interface for use with a ClientManager, and + * implements the following methods: + * void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor); + * void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor); + */ + class ClientEventListener { + public: + void onClientAdded(const resource_policy::ClientDescriptor<String8, + sp<CameraService::BasicClient>>& descriptor); + void onClientRemoved(const resource_policy::ClientDescriptor<String8, + sp<CameraService::BasicClient>>& descriptor); + }; // class ClientEventListener + typedef std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<CameraService::BasicClient>>> DescriptorPtr; @@ -338,9 +353,10 @@ public: * This class manages the eviction behavior for the camera clients. See the parent class * implementation in utils/ClientManager for the specifics of this behavior. */ - class CameraClientManager : - public resource_policy::ClientManager<String8, sp<CameraService::BasicClient>> { + class CameraClientManager : public resource_policy::ClientManager<String8, + sp<CameraService::BasicClient>, ClientEventListener> { public: + CameraClientManager(); virtual ~CameraClientManager(); /** @@ -624,13 +640,15 @@ private: sp<CameraFlashlight> mFlashlight; // guard mTorchStatusMap Mutex mTorchStatusMutex; - // guard mTorchClientMap + // guard mTorchClientMap, mTorchUidMap Mutex mTorchClientMapMutex; // camera id -> torch status KeyedVector<String8, ICameraServiceListener::TorchStatus> mTorchStatusMap; // camera id -> torch client binder // only store the last client that turns on each camera's torch mode - KeyedVector<String8, sp<IBinder> > mTorchClientMap; + KeyedVector<String8, sp<IBinder>> mTorchClientMap; + // camera id -> [incoming uid, current uid] pair + std::map<String8, std::pair<int, int>> mTorchUidMap; // check and handle if torch client's process has died void handleTorchClientBinderDied(const wp<IBinder> &who); diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 0bc8ed1..45d9421 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -2613,6 +2613,21 @@ status_t Camera3Device::RequestThread::clear( if (listener != NULL) { for (RequestList::iterator it = mRequestQueue.begin(); it != mRequestQueue.end(); ++it) { + // Abort the input buffers for reprocess requests. + if ((*it)->mInputStream != NULL) { + camera3_stream_buffer_t inputBuffer; + status_t res = (*it)->mInputStream->getInputBuffer(&inputBuffer); + if (res != OK) { + ALOGW("%s: %d: couldn't get input buffer while clearing the request " + "list: %s (%d)", __FUNCTION__, __LINE__, strerror(-res), res); + } else { + res = (*it)->mInputStream->returnInputBuffer(inputBuffer); + if (res != OK) { + ALOGE("%s: %d: couldn't return input buffer while clearing the request " + "list: %s (%d)", __FUNCTION__, __LINE__, strerror(-res), res); + } + } + } // Set the frame number this request would have had, if it // had been submitted; this frame number will not be reused. // The requestId and burstId fields were set when the request was @@ -2752,31 +2767,11 @@ bool Camera3Device::RequestThread::threadLoop() { __FUNCTION__); } - camera3_stream_buffer_t inputBuffer; uint32_t totalNumBuffers = 0; // Fill in buffers - if (nextRequest->mInputStream != NULL) { - res = nextRequest->mInputStream->getInputBuffer(&inputBuffer); - if (res != OK) { - // Can't get input buffer from gralloc queue - this could be due to - // disconnected queue or other producer misbehavior, so not a fatal - // error - ALOGE("RequestThread: Can't get input buffer, skipping request:" - " %s (%d)", strerror(-res), res); - { - Mutex::Autolock l(mRequestLock); - if (mListener != NULL) { - mListener->notifyError( - ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, - nextRequest->mResultExtras); - } - } - cleanUpFailedRequest(request, nextRequest, outputBuffers); - return true; - } - request.input_buffer = &inputBuffer; + request.input_buffer = &nextRequest->mInputBuffer; totalNumBuffers += 1; } else { request.input_buffer = NULL; @@ -2932,9 +2927,9 @@ void Camera3Device::RequestThread::cleanUpFailedRequest( if (request.settings != NULL) { nextRequest->mSettings.unlock(request.settings); } - if (request.input_buffer != NULL) { - request.input_buffer->status = CAMERA3_BUFFER_STATUS_ERROR; - nextRequest->mInputStream->returnInputBuffer(*(request.input_buffer)); + if (nextRequest->mInputStream != NULL) { + nextRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR; + nextRequest->mInputStream->returnInputBuffer(nextRequest->mInputBuffer); } for (size_t i = 0; i < request.num_output_buffers; i++) { outputBuffers.editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR; @@ -3026,6 +3021,25 @@ sp<Camera3Device::CaptureRequest> nextRequest->mResultExtras.frameNumber = mFrameNumber++; nextRequest->mResultExtras.afTriggerId = mCurrentAfTriggerId; nextRequest->mResultExtras.precaptureTriggerId = mCurrentPreCaptureTriggerId; + + // Since RequestThread::clear() removes buffers from the input stream, + // get the right buffer here before unlocking mRequestLock + if (nextRequest->mInputStream != NULL) { + res = nextRequest->mInputStream->getInputBuffer(&nextRequest->mInputBuffer); + if (res != OK) { + // Can't get input buffer from gralloc queue - this could be due to + // disconnected queue or other producer misbehavior, so not a fatal + // error + ALOGE("%s: Can't get input buffer, skipping request:" + " %s (%d)", __FUNCTION__, strerror(-res), res); + if (mListener != NULL) { + mListener->notifyError( + ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, + nextRequest->mResultExtras); + } + return NULL; + } + } } mNextRequest = nextRequest; diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index fcb5180..b9313fc 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -234,6 +234,7 @@ class Camera3Device : public: CameraMetadata mSettings; sp<camera3::Camera3Stream> mInputStream; + camera3_stream_buffer_t mInputBuffer; Vector<sp<camera3::Camera3OutputStreamInterface> > mOutputStreams; CaptureResultExtras mResultExtras; diff --git a/services/camera/libcameraservice/utils/ClientManager.h b/services/camera/libcameraservice/utils/ClientManager.h index 5afb7a3..7ae58d5 100644 --- a/services/camera/libcameraservice/utils/ClientManager.h +++ b/services/camera/libcameraservice/utils/ClientManager.h @@ -172,6 +172,26 @@ void ClientDescriptor<KEY, VALUE>::setPriority(int32_t priority) { // -------------------------------------------------------------------------------- /** + * A default class implementing the LISTENER interface used by ClientManager. + */ +template<class KEY, class VALUE> +class DefaultEventListener { +public: + void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor); + void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor); +}; + +template<class KEY, class VALUE> +void DefaultEventListener<KEY, VALUE>::onClientAdded( + const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {} + +template<class KEY, class VALUE> +void DefaultEventListener<KEY, VALUE>::onClientRemoved( + const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {} + +// -------------------------------------------------------------------------------- + +/** * The ClientManager class wraps an LRU-ordered list of active clients and implements eviction * behavior for handling shared resource access. * @@ -189,7 +209,7 @@ void ClientDescriptor<KEY, VALUE>::setPriority(int32_t priority) { * incoming descriptor has the highest priority. Otherwise, the incoming descriptor is * removed instead. */ -template<class KEY, class VALUE> +template<class KEY, class VALUE, class LISTENER=DefaultEventListener<KEY, VALUE>> class ClientManager { public: // The default maximum "cost" allowed before evicting @@ -275,6 +295,24 @@ public: status_t waitUntilRemoved(const std::shared_ptr<ClientDescriptor<KEY, VALUE>> client, nsecs_t timeout) const; + /** + * Set the current listener for client add/remove events. + * + * The listener instance must inherit from the LISTENER class and implement the following + * methods: + * void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor); + * void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor); + * + * These callback methods will be called with the ClientManager's lock held, and should + * not call any further ClientManager methods. + * + * The onClientRemoved method will be called when the client has been removed or evicted + * from the ClientManager that this event listener has been added to. The onClientAdded + * method will be called when the client has been added to the ClientManager that this + * event listener has been added to. + */ + void setListener(const std::shared_ptr<LISTENER>& listener); + protected: ~ClientManager(); @@ -300,36 +338,38 @@ private: int32_t mMaxCost; // LRU ordered, most recent at end std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> mClients; + std::shared_ptr<LISTENER> mListener; }; // class ClientManager -template<class KEY, class VALUE> -ClientManager<KEY, VALUE>::ClientManager() : +template<class KEY, class VALUE, class LISTENER> +ClientManager<KEY, VALUE, LISTENER>::ClientManager() : ClientManager(DEFAULT_MAX_COST) {} -template<class KEY, class VALUE> -ClientManager<KEY, VALUE>::ClientManager(int32_t totalCost) : mMaxCost(totalCost) {} +template<class KEY, class VALUE, class LISTENER> +ClientManager<KEY, VALUE, LISTENER>::ClientManager(int32_t totalCost) : mMaxCost(totalCost) {} -template<class KEY, class VALUE> -ClientManager<KEY, VALUE>::~ClientManager() {} +template<class KEY, class VALUE, class LISTENER> +ClientManager<KEY, VALUE, LISTENER>::~ClientManager() {} -template<class KEY, class VALUE> -std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> ClientManager<KEY, VALUE>::wouldEvict( +template<class KEY, class VALUE, class LISTENER> +std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> +ClientManager<KEY, VALUE, LISTENER>::wouldEvict( const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const { Mutex::Autolock lock(mLock); return wouldEvictLocked(client); } -template<class KEY, class VALUE> +template<class KEY, class VALUE, class LISTENER> std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> -ClientManager<KEY, VALUE>::getIncompatibleClients( +ClientManager<KEY, VALUE, LISTENER>::getIncompatibleClients( const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const { Mutex::Autolock lock(mLock); return wouldEvictLocked(client, /*returnIncompatibleClients*/true); } -template<class KEY, class VALUE> +template<class KEY, class VALUE, class LISTENER> std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> -ClientManager<KEY, VALUE>::wouldEvictLocked( +ClientManager<KEY, VALUE, LISTENER>::wouldEvictLocked( const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client, bool returnIncompatibleClients) const { @@ -420,8 +460,9 @@ ClientManager<KEY, VALUE>::wouldEvictLocked( } -template<class KEY, class VALUE> -std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> ClientManager<KEY, VALUE>::addAndEvict( +template<class KEY, class VALUE, class LISTENER> +std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> +ClientManager<KEY, VALUE, LISTENER>::addAndEvict( const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) { Mutex::Autolock lock(mLock); auto evicted = wouldEvictLocked(client); @@ -433,6 +474,9 @@ std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> ClientManager<KEY, VA auto iter = evicted.cbegin(); if (iter != evicted.cend()) { + + if (mListener != nullptr) mListener->onClientRemoved(**iter); + // Remove evicted clients from list mClients.erase(std::remove_if(mClients.begin(), mClients.end(), [&iter] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) { @@ -444,21 +488,22 @@ std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> ClientManager<KEY, VA }), mClients.end()); } + if (mListener != nullptr) mListener->onClientAdded(*client); mClients.push_back(client); mRemovedCondition.broadcast(); return evicted; } -template<class KEY, class VALUE> +template<class KEY, class VALUE, class LISTENER> std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> -ClientManager<KEY, VALUE>::getAll() const { +ClientManager<KEY, VALUE, LISTENER>::getAll() const { Mutex::Autolock lock(mLock); return mClients; } -template<class KEY, class VALUE> -std::vector<KEY> ClientManager<KEY, VALUE>::getAllKeys() const { +template<class KEY, class VALUE, class LISTENER> +std::vector<KEY> ClientManager<KEY, VALUE, LISTENER>::getAllKeys() const { Mutex::Autolock lock(mLock); std::vector<KEY> keys(mClients.size()); for (const auto& i : mClients) { @@ -467,8 +512,8 @@ std::vector<KEY> ClientManager<KEY, VALUE>::getAllKeys() const { return keys; } -template<class KEY, class VALUE> -std::vector<int32_t> ClientManager<KEY, VALUE>::getAllOwners() const { +template<class KEY, class VALUE, class LISTENER> +std::vector<int32_t> ClientManager<KEY, VALUE, LISTENER>::getAllOwners() const { Mutex::Autolock lock(mLock); std::set<int32_t> owners; for (const auto& i : mClients) { @@ -477,8 +522,8 @@ std::vector<int32_t> ClientManager<KEY, VALUE>::getAllOwners() const { return std::vector<int32_t>(owners.begin(), owners.end()); } -template<class KEY, class VALUE> -void ClientManager<KEY, VALUE>::updatePriorities( +template<class KEY, class VALUE, class LISTENER> +void ClientManager<KEY, VALUE, LISTENER>::updatePriorities( const std::map<int32_t,int32_t>& ownerPriorityList) { Mutex::Autolock lock(mLock); for (auto& i : mClients) { @@ -489,8 +534,8 @@ void ClientManager<KEY, VALUE>::updatePriorities( } } -template<class KEY, class VALUE> -std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE>::get( +template<class KEY, class VALUE, class LISTENER> +std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::get( const KEY& key) const { Mutex::Autolock lock(mLock); for (const auto& i : mClients) { @@ -499,23 +544,30 @@ std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE>::get( return std::shared_ptr<ClientDescriptor<KEY, VALUE>>(nullptr); } -template<class KEY, class VALUE> -void ClientManager<KEY, VALUE>::removeAll() { +template<class KEY, class VALUE, class LISTENER> +void ClientManager<KEY, VALUE, LISTENER>::removeAll() { Mutex::Autolock lock(mLock); + if (mListener != nullptr) { + for (const auto& i : mClients) { + mListener->onClientRemoved(*i); + } + } mClients.clear(); mRemovedCondition.broadcast(); } -template<class KEY, class VALUE> -std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE>::remove(const KEY& key) { +template<class KEY, class VALUE, class LISTENER> +std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::remove( + const KEY& key) { Mutex::Autolock lock(mLock); std::shared_ptr<ClientDescriptor<KEY, VALUE>> ret; // Remove evicted clients from list mClients.erase(std::remove_if(mClients.begin(), mClients.end(), - [&key, &ret] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) { + [this, &key, &ret] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) { if (curClientPtr->getKey() == key) { + if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr); ret = curClientPtr; return true; } @@ -526,8 +578,8 @@ std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE>::remove( return ret; } -template<class KEY, class VALUE> -status_t ClientManager<KEY, VALUE>::waitUntilRemoved( +template<class KEY, class VALUE, class LISTENER> +status_t ClientManager<KEY, VALUE, LISTENER>::waitUntilRemoved( const std::shared_ptr<ClientDescriptor<KEY, VALUE>> client, nsecs_t timeout) const { status_t ret = NO_ERROR; @@ -558,14 +610,21 @@ status_t ClientManager<KEY, VALUE>::waitUntilRemoved( return ret; } -template<class KEY, class VALUE> -void ClientManager<KEY, VALUE>::remove( +template<class KEY, class VALUE, class LISTENER> +void ClientManager<KEY, VALUE, LISTENER>::setListener(const std::shared_ptr<LISTENER>& listener) { + Mutex::Autolock lock(mLock); + mListener = listener; +} + +template<class KEY, class VALUE, class LISTENER> +void ClientManager<KEY, VALUE, LISTENER>::remove( const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& value) { Mutex::Autolock lock(mLock); // Remove evicted clients from list mClients.erase(std::remove_if(mClients.begin(), mClients.end(), - [&value] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) { + [this, &value] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) { if (curClientPtr == value) { + if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr); return true; } return false; @@ -573,8 +632,8 @@ void ClientManager<KEY, VALUE>::remove( mRemovedCondition.broadcast(); } -template<class KEY, class VALUE> -int64_t ClientManager<KEY, VALUE>::getCurrentCostLocked() const { +template<class KEY, class VALUE, class LISTENER> +int64_t ClientManager<KEY, VALUE, LISTENER>::getCurrentCostLocked() const { int64_t totalCost = 0; for (const auto& x : mClients) { totalCost += x->getCost(); |