diff options
Diffstat (limited to 'media/libmedia')
-rw-r--r-- | media/libmedia/Android.mk | 12 | ||||
-rw-r--r-- | media/libmedia/AudioParameter.cpp | 1 | ||||
-rw-r--r-- | media/libmedia/AudioRecord.cpp | 3 | ||||
-rw-r--r-- | media/libmedia/AudioTrack.cpp | 165 | ||||
-rw-r--r-- | media/libmedia/AudioTrackShared.cpp | 4 | ||||
-rw-r--r-- | media/libmedia/ICrypto.cpp | 6 | ||||
-rw-r--r-- | media/libmedia/IEffectClient.cpp | 4 | ||||
-rw-r--r-- | media/libmedia/IMediaHTTPConnection.cpp | 8 | ||||
-rw-r--r-- | media/libmedia/IMediaPlayer.cpp | 30 | ||||
-rw-r--r-- | media/libmedia/IMediaRecorder.cpp | 16 | ||||
-rw-r--r-- | media/libmedia/IOMX.cpp | 3 | ||||
-rwxr-xr-x[-rw-r--r--] | media/libmedia/MediaProfiles.cpp | 67 | ||||
-rw-r--r-- | media/libmedia/MediaScanner.cpp | 4 | ||||
-rw-r--r-- | media/libmedia/ToneGenerator.cpp | 14 | ||||
-rw-r--r-- | media/libmedia/Visualizer.cpp | 8 | ||||
-rw-r--r-- | media/libmedia/mediaplayer.cpp | 64 | ||||
-rwxr-xr-x[-rw-r--r--] | media/libmedia/mediarecorder.cpp | 28 |
17 files changed, 363 insertions, 74 deletions
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index a3c3d3c..74e4eb1 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -69,12 +69,21 @@ LOCAL_SRC_FILES:= \ StringArray.cpp \ AudioPolicy.cpp + +#QTI Resampler +ifeq ($(call is-vendor-board-platform,QCOM), true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXTN_RESAMPLER)), true) +LOCAL_CFLAGS += -DQTI_RESAMPLER +endif +endif +#QTI Resampler + LOCAL_SHARED_LIBRARIES := \ libui liblog libcutils libutils libbinder libsonivox libicuuc libicui18n libexpat \ libcamera_client libstagefright_foundation \ libgui libdl libaudioutils libnbaio -LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper +LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper libavmediaextentions LOCAL_MODULE:= libmedia @@ -84,6 +93,7 @@ LOCAL_C_INCLUDES := \ $(TOP)/frameworks/native/include/media/openmax \ $(TOP)/frameworks/av/include/media/ \ $(TOP)/frameworks/av/media/libstagefright \ + $(TOP)/frameworks/av/media/libavextensions \ $(call include-path-for, audio-effects) \ $(call include-path-for, audio-utils) diff --git a/media/libmedia/AudioParameter.cpp b/media/libmedia/AudioParameter.cpp index 8c8cf45..535f459 100644 --- a/media/libmedia/AudioParameter.cpp +++ b/media/libmedia/AudioParameter.cpp @@ -32,6 +32,7 @@ const char * const AudioParameter::keyChannels = AUDIO_PARAMETER_STREAM_CHANNELS const char * const AudioParameter::keyFrameCount = AUDIO_PARAMETER_STREAM_FRAME_COUNT; const char * const AudioParameter::keyInputSource = AUDIO_PARAMETER_STREAM_INPUT_SOURCE; const char * const AudioParameter::keyScreenState = AUDIO_PARAMETER_KEY_SCREEN_STATE; +const char * const AudioParameter::keyDevShutdown = AUDIO_PARAMETER_KEY_DEV_SHUTDOWN; AudioParameter::AudioParameter(const String8& keyValuePairs) { diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 011b31f..6dc52cd 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -26,6 +26,7 @@ #include <utils/Log.h> #include <private/media/AudioTrackShared.h> #include <media/IAudioFlinger.h> +#include "SeempLog.h" #define WAIT_PERIOD_MS 10 @@ -293,6 +294,7 @@ status_t AudioRecord::set( status_t AudioRecord::start(AudioSystem::sync_event_t event, int triggerSession) { ALOGV("start, sync event %d trigger session %d", event, triggerSession); + SEEMPLOG_RECORD(89,""); AutoMutex lock(mLock); if (mActive) { @@ -340,6 +342,7 @@ status_t AudioRecord::start(AudioSystem::sync_event_t event, int triggerSession) void AudioRecord::stop() { + SEEMPLOG_RECORD(90,""); AutoMutex lock(mLock); if (!mActive) { return; diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index ff5fe1d..ff57b44 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -30,6 +30,8 @@ #include <media/IAudioFlinger.h> #include <media/AudioPolicyHelper.h> #include <media/AudioResamplerPublic.h> +#include "media/AVMediaExtensions.h" +#include <cutils/properties.h> #define WAIT_PERIOD_MS 10 #define WAIT_STREAM_END_TIMEOUT_SEC 120 @@ -167,7 +169,8 @@ AudioTrack::AudioTrack() mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mPausedPosition(0), - mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE) + mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), + mPlaybackRateSet(false) { mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN; mAttributes.usage = AUDIO_USAGE_UNKNOWN; @@ -197,7 +200,8 @@ AudioTrack::AudioTrack( mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mPausedPosition(0), - mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE) + mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), + mPlaybackRateSet(false) { mStatus = set(streamType, sampleRate, format, channelMask, frameCount, flags, cbf, user, notificationFrames, @@ -227,7 +231,8 @@ AudioTrack::AudioTrack( mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mPausedPosition(0), - mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE) + mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), + mPlaybackRateSet(false) { mStatus = set(streamType, sampleRate, format, channelMask, 0 /*frameCount*/, flags, cbf, user, notificationFrames, @@ -541,6 +546,12 @@ status_t AudioTrack::start() // force refresh of remaining frames by processAudioBuffer() as last // write before stop could be partial. mRefreshRemaining = true; + + // for static track, clear the old flags when start from stopped state + if (mSharedBuffer != 0) + android_atomic_and( + ~(CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL | CBLK_BUFFER_END), + &mCblk->mFlags); } mNewPosition = mPosition + mUpdatePeriod; int32_t flags = android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags); @@ -706,7 +717,7 @@ status_t AudioTrack::setVolume(float left, float right) mProxy->setVolumeLR(gain_minifloat_pack(gain_from_float(left), gain_from_float(right))); - if (isOffloaded_l()) { + if (isOffloaded_l() && mAudioTrack != NULL) { mAudioTrack->signal(); } return NO_ERROR; @@ -831,13 +842,13 @@ status_t AudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) } // Check resampler ratios are within bounds - if (effectiveRate > mSampleRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) { + if ((uint64_t)effectiveRate > (uint64_t)mSampleRate * (uint64_t)AUDIO_RESAMPLER_DOWN_RATIO_MAX) { ALOGV("setPlaybackRate(%f, %f) failed. Resample rate exceeds max accepted value", playbackRate.mSpeed, playbackRate.mPitch); return BAD_VALUE; } - if (effectiveRate * AUDIO_RESAMPLER_UP_RATIO_MAX < mSampleRate) { + if ((uint64_t)effectiveRate * (uint64_t)AUDIO_RESAMPLER_UP_RATIO_MAX < (uint64_t)mSampleRate) { ALOGV("setPlaybackRate(%f, %f) failed. Resample rate below min accepted value", playbackRate.mSpeed, playbackRate.mPitch); return BAD_VALUE; @@ -846,6 +857,14 @@ status_t AudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) //set effective rates mProxy->setPlaybackRate(playbackRateTemp); mProxy->setSampleRate(effectiveRate); // FIXME: not quite "atomic" with setPlaybackRate + + // fallback out of Direct PCM if setPlaybackRate is called on a track offloaded + // session. Do this by setting mPlaybackRateSet to true + if (mTrackOffloaded) { + mPlaybackRateSet = true; + android_atomic_or(CBLK_INVALID, &mCblk->mFlags); + } + return NO_ERROR; } @@ -1001,10 +1020,18 @@ status_t AudioTrack::getPosition(uint32_t *position) return NO_ERROR; } + if (AVMediaUtils::get()->AudioTrackIsPcmOffloaded(mFormat) && + AVMediaUtils::get()->AudioTrackGetPosition(this, position) == NO_ERROR) { + return NO_ERROR; + } + if (mOutput != AUDIO_IO_HANDLE_NONE) { uint32_t halFrames; // actually unused - (void) AudioSystem::getRenderPosition(mOutput, &halFrames, &dspFrames); - // FIXME: on getRenderPosition() error, we return OK with frame position 0. + status_t status = AudioSystem::getRenderPosition(mOutput, &halFrames, &dspFrames); + if (status != NO_ERROR) { + ALOGW("failed to getRenderPosition for offload session status %d", status); + return INVALID_OPERATION; + } } // FIXME: dspFrames may not be zero in (mState == STATE_STOPPED || mState == STATE_FLUSHED) // due to hardware latency. We leave this behavior for now. @@ -1129,11 +1156,16 @@ status_t AudioTrack::createTrack_l() audio_stream_type_t streamType = mStreamType; audio_attributes_t *attr = (mStreamType == AUDIO_STREAM_DEFAULT) ? &mAttributes : NULL; - status_t status; - status = AudioSystem::getOutputForAttr(attr, &output, + audio_offload_info_t tOffloadInfo = AUDIO_INFO_INITIALIZER; + if (mPlaybackRateSet == true && mOffloadInfo == NULL && mFormat == AUDIO_FORMAT_PCM_16_BIT) { + mOffloadInfo = &tOffloadInfo; + } + status_t status = AudioSystem::getOutputForAttr(attr, &output, (audio_session_t)mSessionId, &streamType, mClientUid, mSampleRate, mFormat, mChannelMask, mFlags, mSelectedDeviceId, mOffloadInfo); + //reset offload info if forced + mOffloadInfo = (mOffloadInfo == &tOffloadInfo) ? NULL : mOffloadInfo; if (status != NO_ERROR || output == AUDIO_IO_HANDLE_NONE) { ALOGE("Could not get audio output for session %d, stream type %d, usage %d, sample rate %u, format %#x," @@ -1141,6 +1173,7 @@ status_t AudioTrack::createTrack_l() mSessionId, streamType, mAttributes.usage, mSampleRate, mFormat, mChannelMask, mFlags); return BAD_VALUE; } + mTrackOffloaded = AVMediaUtils::get()->AudioTrackIsTrackOffloaded(output); { // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger, // we must release it ourselves if anything goes wrong. @@ -1203,6 +1236,7 @@ status_t AudioTrack::createTrack_l() frameCount = mSharedBuffer->size(); } else if (frameCount == 0) { frameCount = mAfFrameCount; + frameCount = AVMediaUtils::get()->AudioTrackGetOffloadFrameCount(frameCount); } if (mNotificationFramesAct != frameCount) { mNotificationFramesAct = frameCount; @@ -1838,6 +1872,36 @@ nsecs_t AudioTrack::processAudioBuffer() // get anchor time to account for callbacks. const nsecs_t timeBeforeCallbacks = systemTime(); + // perform callbacks while unlocked + if (newUnderrun) { + mCbf(EVENT_UNDERRUN, mUserData, NULL); + } + while (loopCountNotifications > 0) { + mCbf(EVENT_LOOP_END, mUserData, NULL); + --loopCountNotifications; + } + if (flags & CBLK_BUFFER_END) { + mCbf(EVENT_BUFFER_END, mUserData, NULL); + } + if (markerReached) { + mCbf(EVENT_MARKER, mUserData, &markerPosition); + } + while (newPosCount > 0) { + size_t temp = newPosition; + mCbf(EVENT_NEW_POS, mUserData, &temp); + newPosition += updatePeriod; + newPosCount--; + } + + if (mObservedSequence != sequence) { + mObservedSequence = sequence; + mCbf(EVENT_NEW_IAUDIOTRACK, mUserData, NULL); + // for offloaded tracks, just wait for the upper layers to recreate the track + if (isOffloadedOrDirect()) { + return NS_INACTIVE; + } + } + if (waitStreamEnd) { // FIXME: Instead of blocking in proxy->waitStreamEndDone(), Callback thread // should wait on proxy futex and handle CBLK_STREAM_END_DONE within this function @@ -1852,6 +1916,12 @@ nsecs_t AudioTrack::processAudioBuffer() case NO_ERROR: case DEAD_OBJECT: case TIMED_OUT: + if (isOffloaded_l()) { + if (mCblk->mFlags & (CBLK_INVALID)){ + // will trigger EVENT_STREAM_END in next iteration + return 0; + } + } if (status != DEAD_OBJECT) { // for DEAD_OBJECT, we do not send a EVENT_STREAM_END after stop(); // instead, the application should handle the EVENT_NEW_IAUDIOTRACK. @@ -1876,36 +1946,6 @@ nsecs_t AudioTrack::processAudioBuffer() return 0; } - // perform callbacks while unlocked - if (newUnderrun) { - mCbf(EVENT_UNDERRUN, mUserData, NULL); - } - while (loopCountNotifications > 0) { - mCbf(EVENT_LOOP_END, mUserData, NULL); - --loopCountNotifications; - } - if (flags & CBLK_BUFFER_END) { - mCbf(EVENT_BUFFER_END, mUserData, NULL); - } - if (markerReached) { - mCbf(EVENT_MARKER, mUserData, &markerPosition); - } - while (newPosCount > 0) { - size_t temp = newPosition; - mCbf(EVENT_NEW_POS, mUserData, &temp); - newPosition += updatePeriod; - newPosCount--; - } - - if (mObservedSequence != sequence) { - mObservedSequence = sequence; - mCbf(EVENT_NEW_IAUDIOTRACK, mUserData, NULL); - // for offloaded tracks, just wait for the upper layers to recreate the track - if (isOffloadedOrDirect()) { - return NS_INACTIVE; - } - } - // if inactive, then don't run me again until re-started if (!active) { return NS_INACTIVE; @@ -2161,8 +2201,7 @@ uint32_t AudioTrack::updateAndGetPosition_l() { // This is the sole place to read server consumed frames uint32_t newServer = mProxy->getPosition(); - int32_t delta = newServer - mServer; - mServer = newServer; + uint32_t delta = newServer > mServer ? newServer - mServer : 0; // TODO There is controversy about whether there can be "negative jitter" in server position. // This should be investigated further, and if possible, it should be addressed. // A more definite failure mode is infrequent polling by client. @@ -2171,11 +2210,12 @@ uint32_t AudioTrack::updateAndGetPosition_l() // That should ensure delta never goes negative for infrequent polling // unless the server has more than 2^31 frames in its buffer, // in which case the use of uint32_t for these counters has bigger issues. - if (delta < 0) { - ALOGE("detected illegal retrograde motion by the server: mServer advanced by %d", delta); - delta = 0; + if (newServer < mServer) { + ALOGE("detected illegal retrograde motion by the server: mServer advanced by %d", + (int32_t) newServer - mServer); } - return mPosition += (uint32_t) delta; + mServer = newServer; + return mPosition += delta; } bool AudioTrack::isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const @@ -2237,14 +2277,22 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) } } - // The presented frame count must always lag behind the consumed frame count. - // To avoid a race, read the presented frames first. This ensures that presented <= consumed. - status_t status = mAudioTrack->getTimestamp(timestamp); - if (status != NO_ERROR) { - ALOGV_IF(status != WOULD_BLOCK, "getTimestamp error:%#x", status); - return status; + status_t status = UNKNOWN_ERROR; + //call Timestamp only if its NOT PCM offloaded and NOT Track Offloaded + if (!AVMediaUtils::get()->AudioTrackIsPcmOffloaded(mFormat) && !mTrackOffloaded) { + // The presented frame count must always lag behind the consumed frame count. + // To avoid a race, read the presented frames first. This ensures that presented <= consumed. + + status = mAudioTrack->getTimestamp(timestamp); + if (status != NO_ERROR) { + ALOGV_IF(status != WOULD_BLOCK, "getTimestamp error:%#x", status); + return status; + } + } - if (isOffloadedOrDirect_l()) { + + if (isOffloadedOrDirect_l() && !AVMediaUtils::get()->AudioTrackIsPcmOffloaded(mFormat) + && !mTrackOffloaded) { if (isOffloaded_l() && (mState == STATE_PAUSED || mState == STATE_PAUSED_STOPPING)) { // use cached paused position in case another offloaded track is running. timestamp.mPosition = mPausedPosition; @@ -2302,6 +2350,11 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) } } else { // Update the mapping between local consumed (mPosition) and server consumed (mServer) + + if (AVMediaUtils::get()->AudioTrackGetTimestamp(this, ×tamp) == NO_ERROR) { + return NO_ERROR; + } + (void) updateAndGetPosition_l(); // Server consumed (mServer) and presented both use the same server time base, // and server consumed is always >= presented. @@ -2315,9 +2368,9 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) // Convert timestamp position from server time base to client time base. // TODO The following code should work OK now because timestamp.mPosition is 32-bit. // But if we change it to 64-bit then this could fail. - // If (mPosition - mServer) can be negative then should use: - // (int32_t)(mPosition - mServer) - timestamp.mPosition += mPosition - mServer; + // Split this out instead of using += to prevent unsigned overflow + // checks in the outer sum. + timestamp.mPosition = timestamp.mPosition + static_cast<int32_t>(mPosition) - mServer; // Immediately after a call to getPosition_l(), mPosition and // mServer both represent the same frame position. mPosition is // in client's point of view, and mServer is in server's point of diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp index caa84fb..7148743 100644 --- a/media/libmedia/AudioTrackShared.cpp +++ b/media/libmedia/AudioTrackShared.cpp @@ -38,7 +38,7 @@ size_t clampToSize(T x) { // In general, this means (new_self) returned is max(self, other) + 1. static uint32_t incrementSequence(uint32_t self, uint32_t other) { - int32_t diff = self - other; + int32_t diff = (int32_t) self - (int32_t) other; if (diff >= 0 && diff < INT32_MAX) { return self + 1; // we're already ahead of other. } @@ -893,7 +893,7 @@ ssize_t StaticAudioTrackServerProxy::pollPosition() if (mObserver.poll(state)) { StaticAudioTrackState trystate = mState; bool result; - const int32_t diffSeq = state.mLoopSequence - state.mPositionSequence; + const int32_t diffSeq = (int32_t) state.mLoopSequence - (int32_t) state.mPositionSequence; if (diffSeq < 0) { result = updateStateWithLoop(&trystate, state) == OK && diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp index a398ff7..5d822cf 100644 --- a/media/libmedia/ICrypto.cpp +++ b/media/libmedia/ICrypto.cpp @@ -24,6 +24,7 @@ #include <media/stagefright/MediaErrors.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AString.h> +#include <media/AVMediaExtensions.h> namespace android { @@ -136,6 +137,7 @@ struct BpCrypto : public BpInterface<ICrypto> { if (secure) { data.writeInt64(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(dstPtr))); + AVMediaUtils::get()->writeCustomData(&data, dstPtr); } remote()->transact(DECRYPT, data, &reply); @@ -235,6 +237,7 @@ status_t BnCrypto::onTransact( if (opaqueSize > 0) { opaqueData = malloc(opaqueSize); + CHECK(opaqueData != NULL); data.read(opaqueData, opaqueSize); } @@ -296,6 +299,7 @@ status_t BnCrypto::onTransact( void *secureBufferId, *dstPtr; if (secure) { secureBufferId = reinterpret_cast<void *>(static_cast<uintptr_t>(data.readInt64())); + AVMediaUtils::get()->readCustomData(&data, &secureBufferId); } else { dstPtr = calloc(1, totalSize); } @@ -348,6 +352,8 @@ status_t BnCrypto::onTransact( } free(dstPtr); dstPtr = NULL; + } else { + AVMediaUtils::get()->closeFileDescriptor(secureBufferId); } delete[] subSamples; diff --git a/media/libmedia/IEffectClient.cpp b/media/libmedia/IEffectClient.cpp index 1322e72..531f767 100644 --- a/media/libmedia/IEffectClient.cpp +++ b/media/libmedia/IEffectClient.cpp @@ -22,6 +22,8 @@ #include <sys/types.h> #include <media/IEffectClient.h> +#include <media/stagefright/foundation/ADebug.h> + namespace android { enum { @@ -117,12 +119,14 @@ status_t BnEffectClient::onTransact( char *cmd = NULL; if (cmdSize) { cmd = (char *)malloc(cmdSize); + CHECK(cmd != NULL); data.read(cmd, cmdSize); } uint32_t replySize = data.readInt32(); char *resp = NULL; if (replySize) { resp = (char *)malloc(replySize); + CHECK(resp != NULL); data.read(resp, replySize); } commandExecuted(cmdCode, cmdSize, cmd, replySize, resp); diff --git a/media/libmedia/IMediaHTTPConnection.cpp b/media/libmedia/IMediaHTTPConnection.cpp index 0dda0be..23fa084 100644 --- a/media/libmedia/IMediaHTTPConnection.cpp +++ b/media/libmedia/IMediaHTTPConnection.cpp @@ -124,6 +124,14 @@ struct BpMediaHTTPConnection : public BpInterface<IMediaHTTPConnection> { ALOGE("got %zu, but memory has %zu", len, mMemory->size()); return ERROR_OUT_OF_RANGE; } + if(buffer == NULL) { + ALOGE("readAt got a NULL buffer"); + return UNKNOWN_ERROR; + } + if (mMemory->pointer() == NULL) { + ALOGE("readAt got a NULL mMemory->pointer()"); + return UNKNOWN_ERROR; + } memcpy(buffer, mMemory->pointer(), len); diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp index 942aec3..bad84b7 100644 --- a/media/libmedia/IMediaPlayer.cpp +++ b/media/libmedia/IMediaPlayer.cpp @@ -67,6 +67,8 @@ enum { SET_RETRANSMIT_ENDPOINT, GET_RETRANSMIT_ENDPOINT, SET_NEXT_PLAYER, + SUSPEND, + RESUME, }; class BpMediaPlayer: public BpInterface<IMediaPlayer> @@ -419,6 +421,22 @@ public: return err; } + + status_t suspend() + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + remote()->transact(SUSPEND, data, &reply); + return reply.readInt32(); + } + + status_t resume() + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + remote()->transact(RESUME, data, &reply); + return reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer"); @@ -682,6 +700,18 @@ status_t BnMediaPlayer::onTransact( return NO_ERROR; } break; + case SUSPEND: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + status_t ret = suspend(); + reply->writeInt32(ret); + return NO_ERROR; + } break; + case RESUME: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + status_t ret = resume(); + reply->writeInt32(ret); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp index ee3b584..4711c1b 100644 --- a/media/libmedia/IMediaRecorder.cpp +++ b/media/libmedia/IMediaRecorder.cpp @@ -39,6 +39,7 @@ enum { QUERY_SURFACE_MEDIASOURCE, RESET, STOP, + PAUSE, START, PREPARE, GET_MAX_AMPLITUDE, @@ -258,6 +259,15 @@ public: return reply.readInt32(); } + status_t pause() + { + ALOGV("pause"); + Parcel data, reply; + data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); + remote()->transact(PAUSE, data, &reply); + return reply.readInt32(); + } + status_t stop() { ALOGV("stop"); @@ -334,6 +344,12 @@ status_t BnMediaRecorder::onTransact( reply->writeInt32(stop()); return NO_ERROR; } break; + case PAUSE: { + ALOGV("PAUSE"); + CHECK_INTERFACE(IMediaRecorder, data, reply); + reply->writeInt32(pause()); + return NO_ERROR; + } break; case START: { ALOGV("START"); CHECK_INTERFACE(IMediaRecorder, data, reply); diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp index 5423c2a..5356494 100644 --- a/media/libmedia/IOMX.cpp +++ b/media/libmedia/IOMX.cpp @@ -22,6 +22,7 @@ #include <binder/Parcel.h> #include <media/IOMX.h> #include <media/stagefright/foundation/ADebug.h> +#include <media/AVMediaExtensions.h> namespace android { @@ -472,6 +473,7 @@ public: *buffer = (buffer_id)reply.readInt32(); *buffer_data = (void *)reply.readInt64(); + AVMediaUtils::get()->readCustomData(&reply, buffer_data); return err; } @@ -980,6 +982,7 @@ status_t BnOMX::onTransact( if (err == OK) { reply->writeInt32((int32_t)buffer); reply->writeInt64((uintptr_t)buffer_data); + AVMediaUtils::get()->writeCustomData(reply, buffer_data); } return NO_ERROR; diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp index c5790fb..52da7ed 100644..100755 --- a/media/libmedia/MediaProfiles.cpp +++ b/media/libmedia/MediaProfiles.cpp @@ -1,4 +1,6 @@ /* +** Copyright (c) 2014, The Linux Foundation. All rights reserved. +** Not a Contribution. ** ** Copyright 2010, The Android Open Source Project ** @@ -37,7 +39,8 @@ MediaProfiles *MediaProfiles::sInstance = NULL; const MediaProfiles::NameToTagMap MediaProfiles::sVideoEncoderNameMap[] = { {"h263", VIDEO_ENCODER_H263}, {"h264", VIDEO_ENCODER_H264}, - {"m4v", VIDEO_ENCODER_MPEG_4_SP} + {"m4v", VIDEO_ENCODER_MPEG_4_SP}, + {"h265", VIDEO_ENCODER_H265} }; const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = { @@ -45,7 +48,8 @@ const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = { {"amrwb", AUDIO_ENCODER_AMR_WB}, {"aac", AUDIO_ENCODER_AAC}, {"heaac", AUDIO_ENCODER_HE_AAC}, - {"aaceld", AUDIO_ENCODER_AAC_ELD} + {"aaceld", AUDIO_ENCODER_AAC_ELD}, + {"lpcm", AUDIO_ENCODER_LPCM}, }; const MediaProfiles::NameToTagMap MediaProfiles::sFileFormatMap[] = { @@ -88,6 +92,19 @@ const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = { {"highspeed720p", CAMCORDER_QUALITY_HIGH_SPEED_720P}, {"highspeed1080p", CAMCORDER_QUALITY_HIGH_SPEED_1080P}, {"highspeed2160p", CAMCORDER_QUALITY_HIGH_SPEED_2160P}, + + // Vendor-specific profiles + {"vga", CAMCORDER_QUALITY_VGA}, + {"4kdci", CAMCORDER_QUALITY_4KDCI}, + {"timelapsevga", CAMCORDER_QUALITY_TIME_LAPSE_VGA}, + {"timelapse4kdci", CAMCORDER_QUALITY_TIME_LAPSE_4KDCI}, + {"highspeedcif", CAMCORDER_QUALITY_HIGH_SPEED_CIF}, + {"highspeedvga", CAMCORDER_QUALITY_HIGH_SPEED_VGA}, + {"highspeed4kdci", CAMCORDER_QUALITY_HIGH_SPEED_4KDCI}, + {"qhd", CAMCORDER_QUALITY_QHD}, + {"2k", CAMCORDER_QUALITY_2k}, + {"timelapseqhd", CAMCORDER_QUALITY_TIME_LAPSE_QHD}, + {"timelapse2k", CAMCORDER_QUALITY_TIME_LAPSE_2k}, }; #if LOG_NDEBUG @@ -126,6 +143,8 @@ MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap UNUS ALOGV("frame width: min = %d and max = %d", cap.mMinFrameWidth, cap.mMaxFrameWidth); ALOGV("frame height: min = %d and max = %d", cap.mMinFrameHeight, cap.mMaxFrameHeight); ALOGV("frame rate: min = %d and max = %d", cap.mMinFrameRate, cap.mMaxFrameRate); + ALOGV("max HFR width: = %d max HFR height: = %d", cap.mMaxHFRFrameWidth, cap.mMaxHFRFrameHeight); + ALOGV("max HFR mode: = %d", cap.mMaxHFRMode); } /*static*/ void @@ -261,10 +280,23 @@ MediaProfiles::createVideoEncoderCap(const char **atts) const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]); CHECK(codec != -1); + int maxHFRWidth = 0, maxHFRHeight = 0, maxHFRMode = 0; + // Check if there are enough (start through end) attributes in the + // 0-terminated list, to include our additional HFR params. Then check + // if each of those match the expected names. + if (atts[20] && atts[21] && !strcmp("maxHFRFrameWidth", atts[20]) && + atts[22] && atts[23] && !strcmp("maxHFRFrameHeight", atts[22]) && + atts[24] && atts[25] && !strcmp("maxHFRMode", atts[24])) { + maxHFRWidth = atoi(atts[21]); + maxHFRHeight = atoi(atts[23]); + maxHFRMode = atoi(atts[25]); + } + MediaProfiles::VideoEncoderCap *cap = new MediaProfiles::VideoEncoderCap(static_cast<video_encoder>(codec), atoi(atts[5]), atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]), - atoi(atts[15]), atoi(atts[17]), atoi(atts[19])); + atoi(atts[15]), atoi(atts[17]), atoi(atts[19]), + maxHFRWidth, maxHFRHeight, maxHFRMode); logVideoEncoderCap(*cap); return cap; } @@ -423,8 +455,10 @@ MediaProfiles::startElementHandler(void *userData, const char *name, const char } static bool isCamcorderProfile(camcorder_quality quality) { - return quality >= CAMCORDER_QUALITY_LIST_START && - quality <= CAMCORDER_QUALITY_LIST_END; + return (quality >= CAMCORDER_QUALITY_LIST_START && + quality <= CAMCORDER_QUALITY_LIST_END) || + (quality >= CAMCORDER_QUALITY_VENDOR_START && + quality <= CAMCORDER_QUALITY_VENDOR_END); } static bool isTimelapseProfile(camcorder_quality quality) { @@ -616,14 +650,14 @@ MediaProfiles::getInstance() MediaProfiles::createDefaultH263VideoEncoderCap() { return new MediaProfiles::VideoEncoderCap( - VIDEO_ENCODER_H263, 192000, 420000, 176, 352, 144, 288, 1, 20); + VIDEO_ENCODER_H263, 192000, 420000, 176, 352, 144, 288, 1, 20, 0, 0, 0); } /*static*/ MediaProfiles::VideoEncoderCap* MediaProfiles::createDefaultM4vVideoEncoderCap() { return new MediaProfiles::VideoEncoderCap( - VIDEO_ENCODER_MPEG_4_SP, 192000, 420000, 176, 352, 144, 288, 1, 20); + VIDEO_ENCODER_MPEG_4_SP, 192000, 420000, 176, 352, 144, 288, 1, 20, 0, 0, 0); } @@ -778,6 +812,8 @@ MediaProfiles::createDefaultCamcorderProfiles(MediaProfiles *profiles) MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles) { profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap()); + profiles->mAudioEncoders.add(createDefaultAacEncoderCap()); + profiles->mAudioEncoders.add(createDefaultLpcmEncoderCap()); } /*static*/ void @@ -812,6 +848,20 @@ MediaProfiles::createDefaultAmrNBEncoderCap() AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1); } +/*static*/ MediaProfiles::AudioEncoderCap* +MediaProfiles::createDefaultAacEncoderCap() +{ + return new MediaProfiles::AudioEncoderCap( + AUDIO_ENCODER_AAC, 64000, 156000, 8000, 48000, 1, 2); +} + +/*static*/ MediaProfiles::AudioEncoderCap* +MediaProfiles::createDefaultLpcmEncoderCap() +{ + return new MediaProfiles::AudioEncoderCap( + AUDIO_ENCODER_LPCM, 768000, 4608000, 8000, 48000, 1, 6); +} + /*static*/ void MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles) { @@ -927,6 +977,9 @@ int MediaProfiles::getVideoEncoderParamByName(const char *name, video_encoder co if (!strcmp("enc.vid.bps.max", name)) return mVideoEncoders[index]->mMaxBitRate; if (!strcmp("enc.vid.fps.min", name)) return mVideoEncoders[index]->mMinFrameRate; if (!strcmp("enc.vid.fps.max", name)) return mVideoEncoders[index]->mMaxFrameRate; + if (!strcmp("enc.vid.hfr.width.max", name)) return mVideoEncoders[index]->mMaxHFRFrameWidth; + if (!strcmp("enc.vid.hfr.height.max", name)) return mVideoEncoders[index]->mMaxHFRFrameHeight; + if (!strcmp("enc.vid.hfr.mode.max", name)) return mVideoEncoders[index]->mMaxHFRMode; ALOGE("The given video encoder param name %s is not found", name); return -1; diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp index dcbb769..dac0a9e 100644 --- a/media/libmedia/MediaScanner.cpp +++ b/media/libmedia/MediaScanner.cpp @@ -24,6 +24,8 @@ #include <sys/stat.h> #include <dirent.h> +#include <media/stagefright/foundation/ADebug.h> + namespace android { MediaScanner::MediaScanner() @@ -240,6 +242,7 @@ MediaScanResult MediaScanner::doProcessDirectoryEntry( MediaAlbumArt *MediaAlbumArt::clone() { size_t byte_size = this->size() + sizeof(MediaAlbumArt); MediaAlbumArt *result = reinterpret_cast<MediaAlbumArt *>(malloc(byte_size)); + CHECK(result != NULL); result->mSize = this->size(); memcpy(&result->mData[0], &this->mData[0], this->size()); return result; @@ -253,6 +256,7 @@ void MediaAlbumArt::init(MediaAlbumArt *instance, int32_t dataSize, const void * MediaAlbumArt *MediaAlbumArt::fromData(int32_t dataSize, const void* data) { size_t byte_size = sizeof(MediaAlbumArt) + dataSize; MediaAlbumArt *result = reinterpret_cast<MediaAlbumArt *>(malloc(byte_size)); + CHECK(result != NULL); init(result, dataSize, data); return result; } diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp index 6da5348..d738ea7 100644 --- a/media/libmedia/ToneGenerator.cpp +++ b/media/libmedia/ToneGenerator.cpp @@ -804,6 +804,12 @@ ToneGenerator::ToneGenerator(audio_stream_type_t streamType, float volume, bool ALOGE("Unable to marshal AudioFlinger"); return; } + + if (mSamplingRate > 48000) { + ALOGW("mSamplingRate %d . limit to 48k", mSamplingRate); + mSamplingRate = 48000; + } + mThreadCanCallJava = threadCanCallJava; mStreamType = streamType; mVolume = volume; @@ -1046,7 +1052,7 @@ bool ToneGenerator::initAudioTrack() { ALOGV("Create Track: %p", mpAudioTrack.get()); mpAudioTrack->set(mStreamType, - 0, // sampleRate + mSamplingRate, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_MONO, 0, // frameCount @@ -1580,7 +1586,8 @@ void ToneGenerator::WaveGenerator::getSamples(short *outBuffer, } long dec = lAmplitude/count; // loop generation - while (count--) { + while (count) { + count--; Sample = ((lA1 * lS1) >> S_Q14) - lS2; // shift delay lS2 = lS1; @@ -1591,7 +1598,8 @@ void ToneGenerator::WaveGenerator::getSamples(short *outBuffer, } } else { // loop generation - while (count--) { + while (count) { + count--; Sample = ((lA1 * lS1) >> S_Q14) - lS2; // shift delay lS2 = lS1; diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp index f5c1b1f..8d83c1b 100644 --- a/media/libmedia/Visualizer.cpp +++ b/media/libmedia/Visualizer.cpp @@ -94,6 +94,14 @@ status_t Visualizer::setEnabled(bool enabled) return status; } +void Visualizer::cancelCaptureCallBack() +{ + sp<CaptureThread> t = mCaptureThread; + if (t != 0) { + t->requestExitAndWait(); + } +} + status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate, bool force) { diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 502ab2d..3c6bef3 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -333,6 +333,9 @@ status_t MediaPlayer::start() ALOGV("playback completed immediately following start()"); } } + } else if ( (mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_SUSPENDED) ) { + ALOGV("start while suspended, so ignore this start"); + ret = NO_ERROR; } else { ALOGE("start called in state %d", mCurrentState); ret = INVALID_OPERATION; @@ -395,6 +398,10 @@ bool MediaPlayer::isPlaying() ALOGE("internal/external state mismatch corrected"); mCurrentState = MEDIA_PLAYER_STARTED; } + if ((mCurrentState & MEDIA_PLAYER_PLAYBACK_COMPLETE) && temp) { + ALOGE("internal/external state mismatch corrected"); + mCurrentState = MEDIA_PLAYER_STARTED; + } return temp; } ALOGV("isPlaying: no active player"); @@ -484,7 +491,8 @@ status_t MediaPlayer::getDuration_l(int *msec) { ALOGV("getDuration_l"); bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | - MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE)); + MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE | + MEDIA_PLAYER_SUSPENDED)); if (mPlayer != 0 && isValidState) { int durationMs; status_t ret = mPlayer->getDuration(&durationMs); @@ -514,7 +522,7 @@ status_t MediaPlayer::seekTo_l(int msec) { ALOGV("seekTo %d", msec); if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | - MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) { + MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_SUSPENDED) ) ) { if ( msec < 0 ) { ALOGW("Attempt to seek to invalid position: %d", msec); msec = 0; @@ -935,4 +943,54 @@ status_t MediaPlayer::setNextMediaPlayer(const sp<MediaPlayer>& next) { return mPlayer->setNextPlayer(next == NULL ? NULL : next->mPlayer); } -} // namespace android +status_t MediaPlayer::suspend() { + ALOGV("MediaPlayer::suspend()"); + Mutex::Autolock _l(mLock); + if (mPlayer == NULL) { + ALOGE("mPlayer = NULL"); + return NO_INIT; + } + + bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_SUSPENDED)); + + if (!isValidState) { + ALOGE("suspend while in a invalid state = %d", mCurrentState); + return UNKNOWN_ERROR; + } + + status_t ret = mPlayer->suspend(); + + if (OK != ret) { + ALOGE("MediaPlayer::suspend() return with error ret = %d", ret); + return ret; + } + mCurrentState = MEDIA_PLAYER_SUSPENDED; + return OK; +} + +status_t MediaPlayer::resume() { + ALOGV("MediaPlayer::resume()"); + Mutex::Autolock _l(mLock); + if (mPlayer == NULL) { + ALOGE("mPlayer == NULL"); + return NO_INIT; + } + + bool isValidState = (mCurrentState == MEDIA_PLAYER_SUSPENDED); + + if (!isValidState) { + ALOGE("resume while in a invalid state = %d", mCurrentState); + return UNKNOWN_ERROR; + } + + status_t ret = mPlayer->resume(); + + if (OK != ret) { + ALOGE("MediaPlayer::resume() return with error ret = %d", ret); + return ret; + } + mCurrentState = MEDIA_PLAYER_PREPARED; + return OK; +} + +}; // namespace android diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp index 8bbd8f1..8b7b171 100644..100755 --- a/media/libmedia/mediarecorder.cpp +++ b/media/libmedia/mediarecorder.cpp @@ -482,7 +482,7 @@ status_t MediaRecorder::start() ALOGE("media recorder is not initialized yet"); return INVALID_OPERATION; } - if (!(mCurrentState & MEDIA_RECORDER_PREPARED)) { + if (!(mCurrentState & (MEDIA_RECORDER_PREPARED | MEDIA_RECORDER_PAUSED))) { ALOGE("start called in an invalid state: %d", mCurrentState); return INVALID_OPERATION; } @@ -497,6 +497,29 @@ status_t MediaRecorder::start() return ret; } +status_t MediaRecorder::pause() +{ + ALOGV("pause"); + if (mMediaRecorder == NULL) { + ALOGE("media recorder is not initialized yet"); + return INVALID_OPERATION; + } + if (!(mCurrentState & MEDIA_RECORDER_RECORDING)) { + ALOGE("pause called in an invalid state: %d", mCurrentState); + return INVALID_OPERATION; + } + + status_t ret = mMediaRecorder->pause(); + if (OK != ret) { + ALOGE("pause failed: %d", ret); + mCurrentState = MEDIA_RECORDER_ERROR; + return ret; + } + + mCurrentState = MEDIA_RECORDER_PAUSED; + return ret; +} + status_t MediaRecorder::stop() { ALOGV("stop"); @@ -504,7 +527,7 @@ status_t MediaRecorder::stop() ALOGE("media recorder is not initialized yet"); return INVALID_OPERATION; } - if (!(mCurrentState & MEDIA_RECORDER_RECORDING)) { + if (!(mCurrentState & (MEDIA_RECORDER_RECORDING | MEDIA_RECORDER_PAUSED))) { ALOGE("stop called in an invalid state: %d", mCurrentState); return INVALID_OPERATION; } @@ -540,6 +563,7 @@ status_t MediaRecorder::reset() ret = OK; break; + case MEDIA_RECORDER_PAUSED: case MEDIA_RECORDER_RECORDING: case MEDIA_RECORDER_DATASOURCE_CONFIGURED: case MEDIA_RECORDER_PREPARED: |