diff options
author | Ricardo Cerqueira <ricardo@cyngn.com> | 2015-11-05 01:41:03 +0000 |
---|---|---|
committer | Ricardo Cerqueira <ricardo@cyngn.com> | 2015-11-05 15:12:16 +0000 |
commit | d5d618443b0166393389b422892ec033825e57ce (patch) | |
tree | ad66ae383f72046ed6805b570450ae78709df3aa | |
parent | 2848080cc0182847cb2130cba1a59282db88bce0 (diff) | |
parent | f733ab6e153fb89f045bfb1cb2746bd58399a0c2 (diff) | |
download | frameworks_av-d5d618443b0166393389b422892ec033825e57ce.zip frameworks_av-d5d618443b0166393389b422892ec033825e57ce.tar.gz frameworks_av-d5d618443b0166393389b422892ec033825e57ce.tar.bz2 |
Merge tag 'android-6.0.0_r26' into cm-13.0
Android 6.0.0 release 26
Change-Id: I8a57007bf6efcd8b95c3cebf5e0444345bdd4cda
75 files changed, 1297 insertions, 658 deletions
diff --git a/camera/ICameraServiceProxy.cpp b/camera/ICameraServiceProxy.cpp index 06a5afb..694e9c3 100644 --- a/camera/ICameraServiceProxy.cpp +++ b/camera/ICameraServiceProxy.cpp @@ -29,11 +29,21 @@ public: BpCameraServiceProxy(const sp<IBinder>& impl) : BpInterface<ICameraServiceProxy>(impl) {} virtual void pingForUserUpdate() { - Parcel data, reply; + Parcel data; data.writeInterfaceToken(ICameraServiceProxy::getInterfaceDescriptor()); - remote()->transact(BnCameraServiceProxy::PING_FOR_USER_UPDATE, data, &reply, + remote()->transact(BnCameraServiceProxy::PING_FOR_USER_UPDATE, data, nullptr, IBinder::FLAG_ONEWAY); } + + virtual void notifyCameraState(String16 cameraId, CameraState newCameraState) { + Parcel data; + data.writeInterfaceToken(ICameraServiceProxy::getInterfaceDescriptor()); + data.writeString16(cameraId); + data.writeInt32(newCameraState); + remote()->transact(BnCameraServiceProxy::NOTIFY_CAMERA_STATE, data, nullptr, + IBinder::FLAG_ONEWAY); + } + }; @@ -47,9 +57,16 @@ status_t BnCameraServiceProxy::onTransact(uint32_t code, const Parcel& data, Par pingForUserUpdate(); return NO_ERROR; } break; + case NOTIFY_CAMERA_STATE: { + CHECK_INTERFACE(ICameraServiceProxy, data, reply); + String16 cameraId = data.readString16(); + CameraState newCameraState = + static_cast<CameraState>(data.readInt32()); + notifyCameraState(cameraId, newCameraState); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } } }; // namespace android - diff --git a/camera/camera2/ICameraDeviceUser.cpp b/camera/camera2/ICameraDeviceUser.cpp index d2dc200..2a9fd2b 100644 --- a/camera/camera2/ICameraDeviceUser.cpp +++ b/camera/camera2/ICameraDeviceUser.cpp @@ -49,7 +49,8 @@ enum { WAIT_UNTIL_IDLE, FLUSH, PREPARE, - TEAR_DOWN + TEAR_DOWN, + PREPARE2 }; namespace { @@ -366,6 +367,21 @@ public: return reply.readInt32(); } + virtual status_t prepare2(int maxCount, int streamId) + { + ALOGV("prepare2"); + Parcel data, reply; + + data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); + data.writeInt32(maxCount); + data.writeInt32(streamId); + + remote()->transact(PREPARE2, data, &reply); + + reply.readExceptionCode(); + return reply.readInt32(); + } + virtual status_t tearDown(int streamId) { ALOGV("tearDown"); @@ -592,7 +608,14 @@ status_t BnCameraDeviceUser::onTransact( reply->writeInt32(tearDown(streamId)); return NO_ERROR; } break; - + case PREPARE2: { + CHECK_INTERFACE(ICameraDeviceUser, data, reply); + int maxCount = data.readInt32(); + int streamId = data.readInt32(); + reply->writeNoException(); + reply->writeInt32(prepare2(maxCount, streamId)); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/include/camera/ICameraServiceProxy.h b/include/camera/ICameraServiceProxy.h index 12a555f..2613c01 100644 --- a/include/camera/ICameraServiceProxy.h +++ b/include/camera/ICameraServiceProxy.h @@ -23,15 +23,30 @@ namespace android { +/** + * Interface from native camera service to managed-side camera service proxy. + * + * Keep in sync with frameworks/base/core/java/android/hardware/ICameraServiceProxy.aidl + * + */ class ICameraServiceProxy : public IInterface { public: enum { PING_FOR_USER_UPDATE = IBinder::FIRST_CALL_TRANSACTION, + NOTIFY_CAMERA_STATE + }; + + enum CameraState { + CAMERA_STATE_OPEN, + CAMERA_STATE_ACTIVE, + CAMERA_STATE_IDLE, + CAMERA_STATE_CLOSED }; DECLARE_META_INTERFACE(CameraServiceProxy); virtual void pingForUserUpdate() = 0; + virtual void notifyCameraState(String16 cameraId, CameraState newCameraState) = 0; }; class BnCameraServiceProxy: public BnInterface<ICameraServiceProxy> @@ -48,5 +63,3 @@ public: }; // namespace android #endif // ANDROID_HARDWARE_ICAMERASERVICEPROXY_H - - diff --git a/include/camera/camera2/ICameraDeviceUser.h b/include/camera/camera2/ICameraDeviceUser.h index a7bf8ab..4d8eb53 100644 --- a/include/camera/camera2/ICameraDeviceUser.h +++ b/include/camera/camera2/ICameraDeviceUser.h @@ -140,6 +140,11 @@ public: virtual status_t prepare(int streamId) = 0; /** + * Preallocate up to maxCount buffers for a given output stream asynchronously. + */ + virtual status_t prepare2(int maxCount, int streamId) = 0; + + /** * Free all unused buffers for a given output stream. */ virtual status_t tearDown(int streamId) = 0; diff --git a/include/media/IOMX.h b/include/media/IOMX.h index 3d29e4a..27ad694 100644 --- a/include/media/IOMX.h +++ b/include/media/IOMX.h @@ -249,6 +249,12 @@ public: virtual status_t onTransact( uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags = 0); + +protected: + // check if the codec is secure. + virtual bool isSecure(IOMX::node_id node) { + return false; + } }; class BnOMXObserver : public BnInterface<IOMXObserver> { diff --git a/media/img_utils/include/img_utils/DngUtils.h b/media/img_utils/include/img_utils/DngUtils.h index 3dcedc5..1d8df9c 100644 --- a/media/img_utils/include/img_utils/DngUtils.h +++ b/media/img_utils/include/img_utils/DngUtils.h @@ -138,6 +138,34 @@ class ANDROID_API OpcodeListBuilder : public LightRefBase<OpcodeListBuilder> { double opticalCenterY, const double* kCoeffs); + + /** + * Add FixBadPixelsList opcode for the given metadata parameters. + * + * Returns OK on success, or a negative error code. + */ + virtual status_t addBadPixelListForMetadata(const uint32_t* hotPixels, + uint32_t xyPairCount, + uint32_t colorFilterArrangement); + + /** + * Add FixBadPixelsList opcode. + * + * bayerPhase - 0=top-left of image is red, 1=top-left of image is green pixel in red row, + * 2=top-left of image is green pixel in blue row, 3=top-left of image is + * blue. + * badPointCount - number of (x,y) pairs of bad pixels are given in badPointRowColPairs. + * badRectCount - number of (top, left, bottom, right) tuples are given in + * badRectTopLeftBottomRightTuples + * + * Returns OK on success, or a negative error code. + */ + virtual status_t addBadPixelList(uint32_t bayerPhase, + uint32_t badPointCount, + uint32_t badRectCount, + const uint32_t* badPointRowColPairs, + const uint32_t* badRectTopLeftBottomRightTuples); + // TODO: Add other Opcode methods protected: static const uint32_t FLAG_OPTIONAL = 0x1u; @@ -146,6 +174,7 @@ class ANDROID_API OpcodeListBuilder : public LightRefBase<OpcodeListBuilder> { // Opcode IDs enum { WARP_RECTILINEAR_ID = 1, + FIX_BAD_PIXELS_LIST = 5, GAIN_MAP_ID = 9, }; @@ -161,6 +190,8 @@ class ANDROID_API OpcodeListBuilder : public LightRefBase<OpcodeListBuilder> { ByteArrayOutput mOpList; EndianOutput mEndianOut; + status_t addOpcodePreamble(uint32_t opcodeId); + }; } /*namespace img_utils*/ diff --git a/media/img_utils/src/DngUtils.cpp b/media/img_utils/src/DngUtils.cpp index b213403..9473dce 100644 --- a/media/img_utils/src/DngUtils.cpp +++ b/media/img_utils/src/DngUtils.cpp @@ -224,13 +224,7 @@ status_t OpcodeListBuilder::addGainMap(uint32_t top, uint32_t mapPlanes, const float* mapGains) { - uint32_t opcodeId = GAIN_MAP_ID; - - status_t err = mEndianOut.write(&opcodeId, 0, 1); - if (err != OK) return err; - - uint8_t version[] = {1, 3, 0, 0}; - err = mEndianOut.write(version, 0, NELEMS(version)); + status_t err = addOpcodePreamble(GAIN_MAP_ID); if (err != OK) return err; // Allow this opcode to be skipped if not supported @@ -334,13 +328,7 @@ status_t OpcodeListBuilder::addWarpRectilinear(uint32_t numPlanes, double opticalCenterY, const double* kCoeffs) { - uint32_t opcodeId = WARP_RECTILINEAR_ID; - - status_t err = mEndianOut.write(&opcodeId, 0, 1); - if (err != OK) return err; - - uint8_t version[] = {1, 3, 0, 0}; - err = mEndianOut.write(version, 0, NELEMS(version)); + status_t err = addOpcodePreamble(WARP_RECTILINEAR_ID); if (err != OK) return err; // Allow this opcode to be skipped if not supported @@ -373,5 +361,74 @@ status_t OpcodeListBuilder::addWarpRectilinear(uint32_t numPlanes, return OK; } +status_t OpcodeListBuilder::addBadPixelListForMetadata(const uint32_t* hotPixels, + uint32_t xyPairCount, + uint32_t colorFilterArrangement) { + if (colorFilterArrangement > 3) { + ALOGE("%s: Unknown color filter arrangement %" PRIu32, __FUNCTION__, + colorFilterArrangement); + return BAD_VALUE; + } + + return addBadPixelList(colorFilterArrangement, xyPairCount, 0, hotPixels, nullptr); +} + +status_t OpcodeListBuilder::addBadPixelList(uint32_t bayerPhase, + uint32_t badPointCount, + uint32_t badRectCount, + const uint32_t* badPointRowColPairs, + const uint32_t* badRectTopLeftBottomRightTuples) { + + status_t err = addOpcodePreamble(FIX_BAD_PIXELS_LIST); + if (err != OK) return err; + + // Allow this opcode to be skipped if not supported + uint32_t flags = FLAG_OPTIONAL; + + err = mEndianOut.write(&flags, 0, 1); + if (err != OK) return err; + + const uint32_t NUM_NON_VARLEN_FIELDS = 3; + const uint32_t SIZE_OF_POINT = 2; + const uint32_t SIZE_OF_RECT = 4; + + uint32_t totalSize = (NUM_NON_VARLEN_FIELDS + badPointCount * SIZE_OF_POINT + + badRectCount * SIZE_OF_RECT) * sizeof(uint32_t); + err = mEndianOut.write(&totalSize, 0, 1); + if (err != OK) return err; + + err = mEndianOut.write(&bayerPhase, 0, 1); + if (err != OK) return err; + + err = mEndianOut.write(&badPointCount, 0, 1); + if (err != OK) return err; + + err = mEndianOut.write(&badRectCount, 0, 1); + if (err != OK) return err; + + if (badPointCount > 0) { + err = mEndianOut.write(badPointRowColPairs, 0, SIZE_OF_POINT * badPointCount); + if (err != OK) return err; + } + + if (badRectCount > 0) { + err = mEndianOut.write(badRectTopLeftBottomRightTuples, 0, SIZE_OF_RECT * badRectCount); + if (err != OK) return err; + } + + mCount++; + return OK; +} + +status_t OpcodeListBuilder::addOpcodePreamble(uint32_t opcodeId) { + status_t err = mEndianOut.write(&opcodeId, 0, 1); + if (err != OK) return err; + + uint8_t version[] = {1, 3, 0, 0}; + err = mEndianOut.write(version, 0, NELEMS(version)); + if (err != OK) return err; + return OK; +} + } /*namespace img_utils*/ } /*namespace android*/ diff --git a/media/libavextensions/stagefright/AVFactory.cpp b/media/libavextensions/stagefright/AVFactory.cpp index 2a3810d..f6d5f53 100644 --- a/media/libavextensions/stagefright/AVFactory.cpp +++ b/media/libavextensions/stagefright/AVFactory.cpp @@ -72,7 +72,7 @@ sp<NuCachedSource2> AVFactory::createCachedSource( const sp<DataSource> &source, const char *cacheConfig, bool disconnectAtHighwatermark) { - return new NuCachedSource2(source, cacheConfig, disconnectAtHighwatermark); + return NuCachedSource2::Create(source, cacheConfig, disconnectAtHighwatermark); } MediaHTTP* AVFactory::createMediaHTTP( diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 5af70d3..946c118 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -528,6 +528,15 @@ status_t AudioTrack::start() mTimestampStartupGlitchReported = false; mRetrogradeMotionReported = false; + // If previousState == STATE_STOPPED, we reactivate markers (mMarkerPosition != 0) + // as the position is reset to 0. This is legacy behavior. This is not done + // in stop() to avoid a race condition where the last marker event is issued twice. + // Note: the if is technically unnecessary because previousState == STATE_FLUSHED + // is only for streaming tracks, and mMarkerReached is already set to false. + if (previousState == STATE_STOPPED) { + mMarkerReached = false; + } + // For offloaded tracks, we don't know if the hardware counters are really zero here, // since the flush is asynchronous and stop may not fully drain. // We save the time when the track is started to later verify whether @@ -603,9 +612,9 @@ void AudioTrack::stop() mProxy->interrupt(); mAudioTrack->stop(); - // the playback head position will reset to 0, so if a marker is set, we need - // to activate it again - mMarkerReached = false; + + // Note: legacy handling - stop does not clear playback marker + // and periodic update counter, but flush does for streaming tracks. if (mSharedBuffer != 0) { // clear buffer position and loop count. diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp index 53b105d..5d822cf 100644 --- a/media/libmedia/ICrypto.cpp +++ b/media/libmedia/ICrypto.cpp @@ -301,8 +301,7 @@ status_t BnCrypto::onTransact( secureBufferId = reinterpret_cast<void *>(static_cast<uintptr_t>(data.readInt64())); AVMediaUtils::get()->readCustomData(&data, &secureBufferId); } else { - dstPtr = malloc(totalSize); - CHECK(dstPtr != NULL); + dstPtr = calloc(1, totalSize); } AString errorDetailMsg; diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp index ac2e872..5356494 100644 --- a/media/libmedia/IOMX.cpp +++ b/media/libmedia/IOMX.cpp @@ -965,6 +965,12 @@ status_t BnOMX::onTransact( node_id node = (node_id)data.readInt32(); OMX_U32 port_index = data.readInt32(); + if (!isSecure(node) || port_index != 0 /* kPortIndexInput */) { + ALOGE("b/24310423"); + reply->writeInt32(INVALID_OPERATION); + return NO_ERROR; + } + size_t size = data.readInt64(); buffer_id buffer; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index b034459..490a0d2 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -120,6 +120,7 @@ NuPlayer::Renderer::Renderer( mNotifyCompleteVideo(false), mSyncQueues(false), mPaused(false), + mPauseDrainAudioAllowedUs(0), mVideoSampleReceived(false), mVideoRenderingStarted(false), mVideoRenderingStartGeneration(0), @@ -652,6 +653,14 @@ void NuPlayer::Renderer::postDrainAudioQueue_l(int64_t delayUs) { return; } + // FIXME: if paused, wait until AudioTrack stop() is complete before delivering data. + if (mPaused) { + const int64_t diffUs = mPauseDrainAudioAllowedUs - ALooper::GetNowUs(); + if (diffUs > delayUs) { + delayUs = diffUs; + } + } + mDrainAudioQueuePending = true; sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, this); msg->setInt32("drainGeneration", mAudioDrainGeneration); @@ -820,6 +829,10 @@ void NuPlayer::Renderer::drainAudioQueueUntilLastEOS() { } bool NuPlayer::Renderer::onDrainAudioQueue() { + // do not drain audio during teardown as queued buffers may be invalid. + if (mAudioTornDown) { + return false; + } // TODO: This call to getPosition checks if AudioTrack has been created // in AudioSink before draining audio. If AudioTrack doesn't exist, then // CHECKs on getPosition will fail. @@ -899,6 +912,8 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { ALOGV("AudioSink write would block when writing %zu bytes", copy); } else { ALOGE("AudioSink write error(%zd) when writing %zu bytes", written, copy); + // This can only happen when AudioSink was opened with doNotReconnect flag set to + // true, in which case the NuPlayer will handle the reconnect. notifyAudioTearDown(); } break; @@ -965,6 +980,10 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { int64_t NuPlayer::Renderer::getDurationUsIfPlayedAtSampleRate(uint32_t numFrames) { int32_t sampleRate = offloadingAudio() ? mCurrentOffloadInfo.sample_rate : mCurrentPcmInfo.mSampleRate; + if (sampleRate == 0) { + ALOGE("sampleRate is 0 in %s mode", offloadingAudio() ? "offload" : "non-offload"); + return 0; + } // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours. return (int64_t)((int32_t)numFrames * 1000000LL / sampleRate); } @@ -1368,8 +1387,16 @@ void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) { mAudioSink->flush(); // Call stop() to signal to the AudioSink to completely fill the // internal buffer before resuming playback. + // FIXME: this is ignored after flush(). mAudioSink->stop(); - if (!mPaused) { + if (mPaused) { + // Race condition: if renderer is paused and audio sink is stopped, + // we need to make sure that the audio track buffer fully drains + // before delivering data. + // FIXME: remove this if we can detect if stop() is complete. + const int delayUs = 2 * 50 * 1000; // (2 full mixer thread cycles at 50ms) + mPauseDrainAudioAllowedUs = ALooper::GetNowUs() + delayUs; + } else { mAudioSink->start(); } mNumFramesWritten = 0; @@ -1825,6 +1852,12 @@ status_t NuPlayer::Renderer::onOpenAudioSink( const uint32_t frameCount = (unsigned long long)sampleRate * getAudioSinkPcmMsSetting() / 1000; + // The doNotReconnect means AudioSink will signal back and let NuPlayer to re-construct + // AudioSink. We don't want this when there's video because it will cause a video seek to + // the previous I frame. But we do want this when there's only audio because it will give + // NuPlayer a chance to switch from non-offload mode to offload mode. + // So we only set doNotReconnect when there's no video. + const bool doNotReconnect = !hasVideo; status_t err = mAudioSink->open( sampleRate, numChannels, @@ -1835,13 +1868,14 @@ status_t NuPlayer::Renderer::onOpenAudioSink( mUseAudioCallback ? this : NULL, (audio_output_flags_t)pcmFlags, NULL, - true /* doNotReconnect */, + doNotReconnect, frameCount); if (err == OK) { err = mAudioSink->setPlaybackRate(mPlaybackSettings); } if (err != OK) { ALOGW("openAudioSink: non offloaded open failed status: %d", err); + mAudioSink->close(); mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER; return err; } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index 28ec16f..50bd0a9 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -173,6 +173,7 @@ protected: // modified on only renderer's thread. bool mPaused; + int64_t mPauseDrainAudioAllowedUs; // time when we can drain/deliver audio in pause mode. bool mVideoSampleReceived; bool mVideoRenderingStarted; diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp index 6d0e075..35567a5 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp @@ -139,7 +139,9 @@ void NuPlayer::RTSPSource::pause() { return; } } - mHandler->pause(); + if (mHandler != NULL) { + mHandler->pause(); + } } void NuPlayer::RTSPSource::resume() { diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index a15bca7..dc9c37b 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -292,6 +292,10 @@ void AudioSource::signalBufferReturned(MediaBuffer *buffer) { status_t AudioSource::dataCallback(const AudioRecord::Buffer& audioBuffer) { int64_t timeUs = systemTime() / 1000ll; + // Estimate the real sampling time of the 1st sample in this buffer + // from AudioRecord's latency. (Apply this adjustment first so that + // the start time logic is not affected.) + timeUs -= mRecord->latency() * 1000LL; ALOGV("dataCallbackTimestamp: %" PRId64 " us", timeUs); Mutex::Autolock autoLock(mLock); diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 4e6c2a6..3cd0b0e 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -2290,11 +2290,11 @@ status_t AwesomePlayer::finishSetDataSource_l() { // The widevine extractor does its own caching. #if 0 - mCachedSource = new NuCachedSource2( + mCachedSource = NuCachedSource2::Create( new ThrottledSource( mConnectingDataSource, 50 * 1024 /* bytes/sec */)); #else - mCachedSource = new NuCachedSource2( + mCachedSource = NuCachedSource2::Create( mConnectingDataSource, cacheConfig.isEmpty() ? NULL : cacheConfig.string(), disconnectAtHighwatermark); diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 39326c9..2df045f 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -326,7 +326,7 @@ sp<DataSource> DataSource::CreateFromURI( cacheConfig.isEmpty() ? NULL : cacheConfig.string(), disconnectAtHighwatermark); } else { - source = new NuCachedSource2( + source = NuCachedSource2::Create( httpSource, cacheConfig.isEmpty() ? NULL : cacheConfig.string(), disconnectAtHighwatermark); diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 107b4f6..eee13c7 100755 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -2583,6 +2583,12 @@ status_t MPEG4Extractor::parseITunesMetaData(off64_t offset, size_t size) { mLastCommentName.setTo((const char *)buffer + 4); break; case FOURCC('d', 'a', 't', 'a'): + if (size < 8) { + delete[] buffer; + buffer = NULL; + ALOGE("b/24346430"); + return ERROR_MALFORMED; + } mLastCommentData.setTo((const char *)buffer + 8); break; } @@ -4163,7 +4169,10 @@ status_t MPEG4Source::read( (const uint8_t *)mBuffer->data() + mBuffer->range_offset(); size_t nal_size = parseNALSize(src); - if (mBuffer->range_length() < mNALLengthSize + nal_size) { + if (mNALLengthSize > SIZE_MAX - nal_size) { + ALOGE("b/24441553, b/24445122"); + } + if (mBuffer->range_length() - mNALLengthSize < nal_size) { ALOGE("incomplete NAL unit."); mBuffer->release(); @@ -4450,7 +4459,11 @@ status_t MPEG4Source::fragmentedRead( (const uint8_t *)mBuffer->data() + mBuffer->range_offset(); size_t nal_size = parseNALSize(src); - if (mBuffer->range_length() < mNALLengthSize + nal_size) { + if (mNALLengthSize > SIZE_MAX - nal_size) { + ALOGE("b/24441553, b/24445122"); + } + + if (mBuffer->range_length() - mNALLengthSize < nal_size) { ALOGE("incomplete NAL unit."); mBuffer->release(); diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index b74836f..45e9a79 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -573,6 +573,7 @@ status_t MediaCodec::stop() { } status_t MediaCodec::reclaim() { + ALOGD("MediaCodec::reclaim(%p) %s", this, mInitName.c_str()); sp<AMessage> msg = new AMessage(kWhatRelease, this); msg->setInt32("reclaimed", 1); @@ -1159,8 +1160,10 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { resourceType = String8(kResourceNonSecureCodec); } - const char *subtype = mIsVideo ? kResourceVideoCodec : kResourceAudioCodec; - addResource(resourceType, String8(subtype), 1); + if (mIsVideo) { + // audio codec is currently ignored. + addResource(resourceType, String8(kResourceVideoCodec), 1); + } (new AMessage)->postReply(mReplyID); break; diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp index f82636b..d6255d6 100644 --- a/media/libstagefright/NuCachedSource2.cpp +++ b/media/libstagefright/NuCachedSource2.cpp @@ -224,9 +224,6 @@ NuCachedSource2::NuCachedSource2( // So whenever we call DataSource::readAt it may end up in a call to // IMediaHTTPConnection::readAt and therefore call back into JAVA. mLooper->start(false /* runOnCallingThread */, true /* canCallJava */); - - Mutex::Autolock autoLock(mLock); - (new AMessage(kWhatFetchMore, mReflector))->post(); } NuCachedSource2::~NuCachedSource2() { @@ -237,6 +234,18 @@ NuCachedSource2::~NuCachedSource2() { mCache = NULL; } +// static +sp<NuCachedSource2> NuCachedSource2::Create( + const sp<DataSource> &source, + const char *cacheConfig, + bool disconnectAtHighwatermark) { + sp<NuCachedSource2> instance = new NuCachedSource2( + source, cacheConfig, disconnectAtHighwatermark); + Mutex::Autolock autoLock(instance->mLock); + (new AMessage(kWhatFetchMore, instance->mReflector))->post(); + return instance; +} + status_t NuCachedSource2::getEstimatedBandwidthKbps(int32_t *kbps) { if (mSource->flags() & kIsHTTPBasedSource) { HTTPBase* source = static_cast<HTTPBase *>(mSource.get()); diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index e9b7b4f..6e4a1a4 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -202,7 +202,7 @@ status_t convertMetaDataToMessage( } int32_t fps; - if (meta->findInt32(kKeyFrameRate, &fps)) { + if (meta->findInt32(kKeyFrameRate, &fps) && fps > 0) { msg->setInt32("frame-rate", fps); } @@ -316,8 +316,8 @@ status_t convertMetaDataToMessage( } else if (meta->findData(kKeyHVCC, &type, &data, &size)) { const uint8_t *ptr = (const uint8_t *)data; - if (size < 23) { // configurationVersion == 1 - ALOGE("b/23680780 size=%zd ptr0=%x", size, ptr[0]); + if (size < 23 || ptr[0] != 1) { // configurationVersion == 1 + ALOGE("b/23680780"); return BAD_VALUE; } uint8_t profile __unused = ptr[1] & 31; @@ -684,7 +684,7 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) { } int32_t fps; - if (msg->findInt32("frame-rate", &fps)) { + if (msg->findInt32("frame-rate", &fps) && fps > 0) { meta->setInt32(kKeyFrameRate, fps); } diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk index 415702e..21109d9 100644 --- a/media/libstagefright/codecs/amrnb/dec/Android.mk +++ b/media/libstagefright/codecs/amrnb/dec/Android.mk @@ -99,7 +99,7 @@ LOCAL_STATIC_LIBRARIES := \ libstagefright_amrnbdec libsndfile LOCAL_SHARED_LIBRARIES := \ - libstagefright_amrnb_common libaudioutils + libstagefright_amrnb_common libaudioutils liblog LOCAL_MODULE := libstagefright_amrnbdec_test LOCAL_MODULE_TAGS := optional diff --git a/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp b/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp index fb7cff3..696d2da 100644 --- a/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp +++ b/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp @@ -59,6 +59,8 @@ terms listed above has been obtained from the copyright holder. /*---------------------------------------------------------------------------- ; INCLUDES ----------------------------------------------------------------------------*/ +#include <log/log.h> + #include "a_refl.h" #include "typedef.h" #include "cnst.h" @@ -291,7 +293,8 @@ void A_Refl( { refl[i] = 0; } - break; + ALOGE("b/23609206"); + return; } bState[j] = extract_l(L_temp); diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp index e083315..7c5093e 100644 --- a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp +++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp @@ -38,10 +38,10 @@ namespace android { /** Function and structure definitions to keep code similar for each codec */ #define ivdec_api_function ih264d_api_function -#define ivdext_init_ip_t ih264d_init_ip_t -#define ivdext_init_op_t ih264d_init_op_t -#define ivdext_fill_mem_rec_ip_t ih264d_fill_mem_rec_ip_t -#define ivdext_fill_mem_rec_op_t ih264d_fill_mem_rec_op_t +#define ivdext_create_ip_t ih264d_create_ip_t +#define ivdext_create_op_t ih264d_create_op_t +#define ivdext_delete_ip_t ih264d_delete_ip_t +#define ivdext_delete_op_t ih264d_delete_op_t #define ivdext_ctl_set_num_cores_ip_t ih264d_ctl_set_num_cores_ip_t #define ivdext_ctl_set_num_cores_op_t ih264d_ctl_set_num_cores_op_t @@ -115,15 +115,12 @@ SoftAVC::SoftAVC( 320 /* width */, 240 /* height */, callbacks, appData, component), mCodecCtx(NULL), - mMemRecords(NULL), mFlushOutBuffer(NULL), mOmxColorFormat(OMX_COLOR_FormatYUV420Planar), mIvColorFormat(IV_YUV_420P), - mNewWidth(mWidth), - mNewHeight(mHeight), - mNewLevel(0), mChangingResolution(false), - mSignalledError(false) { + mSignalledError(false), + mStride(mWidth){ initPorts( kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, CODEC_MIME_TYPE); @@ -132,14 +129,23 @@ SoftAVC::SoftAVC( // If input dump is enabled, then open create an empty file GENERATE_FILE_NAMES(); CREATE_DUMP_FILE(mInFile); - - CHECK_EQ(initDecoder(mWidth, mHeight), (status_t)OK); } SoftAVC::~SoftAVC() { CHECK_EQ(deInitDecoder(), (status_t)OK); } +static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) { + UNUSED(ctxt); + return memalign(alignment, size); +} + +static void ivd_aligned_free(void *ctxt, void *buf) { + UNUSED(ctxt); + free(buf); + return; +} + static size_t GetCPUCoreCount() { long cpuCoreCount = 1; #if defined(_SC_NPROCESSORS_ONLN) @@ -149,7 +155,7 @@ static size_t GetCPUCoreCount() { cpuCoreCount = sysconf(_SC_NPROC_ONLN); #endif CHECK(cpuCoreCount >= 1); - ALOGD("Number of CPU cores: %ld", cpuCoreCount); + ALOGV("Number of CPU cores: %ld", cpuCoreCount); return (size_t)cpuCoreCount; } @@ -235,12 +241,10 @@ status_t SoftAVC::resetDecoder() { } mSignalledError = false; - /* Set the run-time (dynamic) parameters */ - setParams(outputBufferWidth()); - /* Set number of cores/threads to be used by the codec */ setNumCores(); + mStride = 0; return OK; } @@ -287,160 +291,41 @@ status_t SoftAVC::setFlushMode() { return OK; } -status_t SoftAVC::initDecoder(uint32_t width, uint32_t height) { +status_t SoftAVC::initDecoder() { IV_API_CALL_STATUS_T status; - UWORD32 u4_num_reorder_frames; - UWORD32 u4_num_ref_frames; - UWORD32 u4_share_disp_buf; - WORD32 i4_level; - mNumCores = GetCPUCoreCount(); mCodecCtx = NULL; - /* Initialize number of ref and reorder modes (for H264) */ - u4_num_reorder_frames = 16; - u4_num_ref_frames = 16; - u4_share_disp_buf = 0; - - uint32_t displayStride = mIsAdaptive ? mAdaptiveMaxWidth : width; - uint32_t displayHeight = mIsAdaptive ? mAdaptiveMaxHeight : height; - uint32_t displaySizeY = displayStride * displayHeight; - - if(mNewLevel == 0){ - if (displaySizeY > (1920 * 1088)) { - i4_level = 50; - } else if (displaySizeY > (1280 * 720)) { - i4_level = 40; - } else if (displaySizeY > (720 * 576)) { - i4_level = 31; - } else if (displaySizeY > (624 * 320)) { - i4_level = 30; - } else if (displaySizeY > (352 * 288)) { - i4_level = 21; - } else { - i4_level = 20; - } - } else { - i4_level = mNewLevel; - } - - { - iv_num_mem_rec_ip_t s_num_mem_rec_ip; - iv_num_mem_rec_op_t s_num_mem_rec_op; - - s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip); - s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op); - s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC; - - ALOGV("Get number of mem records"); - status = ivdec_api_function( - mCodecCtx, (void *)&s_num_mem_rec_ip, (void *)&s_num_mem_rec_op); - if (IV_SUCCESS != status) { - ALOGE("Error in getting mem records: 0x%x", - s_num_mem_rec_op.u4_error_code); - return UNKNOWN_ERROR; - } - - mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec; - } - - mMemRecords = (iv_mem_rec_t *)ivd_aligned_malloc( - 128, mNumMemRecords * sizeof(iv_mem_rec_t)); - if (mMemRecords == NULL) { - ALOGE("Allocation failure"); - return NO_MEMORY; - } - - memset(mMemRecords, 0, mNumMemRecords * sizeof(iv_mem_rec_t)); - - { - size_t i; - ivdext_fill_mem_rec_ip_t s_fill_mem_ip; - ivdext_fill_mem_rec_op_t s_fill_mem_op; - iv_mem_rec_t *ps_mem_rec; - - s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size = - sizeof(ivdext_fill_mem_rec_ip_t); - s_fill_mem_ip.i4_level = i4_level; - s_fill_mem_ip.u4_num_reorder_frames = u4_num_reorder_frames; - s_fill_mem_ip.u4_num_ref_frames = u4_num_ref_frames; - s_fill_mem_ip.u4_share_disp_buf = u4_share_disp_buf; - s_fill_mem_ip.u4_num_extra_disp_buf = 0; - s_fill_mem_ip.e_output_format = mIvColorFormat; - - s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC; - s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords; - s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = displayStride; - s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = displayHeight; - s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size = - sizeof(ivdext_fill_mem_rec_op_t); - - ps_mem_rec = mMemRecords; - for (i = 0; i < mNumMemRecords; i++) { - ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t); - } - - status = ivdec_api_function( - mCodecCtx, (void *)&s_fill_mem_ip, (void *)&s_fill_mem_op); - - if (IV_SUCCESS != status) { - ALOGE("Error in filling mem records: 0x%x", - s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code); - return UNKNOWN_ERROR; - } - mNumMemRecords = - s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled; - - ps_mem_rec = mMemRecords; - - for (i = 0; i < mNumMemRecords; i++) { - ps_mem_rec->pv_base = ivd_aligned_malloc( - ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size); - if (ps_mem_rec->pv_base == NULL) { - ALOGE("Allocation failure for memory record #%zu of size %u", - i, ps_mem_rec->u4_mem_size); - status = IV_FAIL; - return NO_MEMORY; - } - - ps_mem_rec++; - } - } + mStride = outputBufferWidth(); /* Initialize the decoder */ { - ivdext_init_ip_t s_init_ip; - ivdext_init_op_t s_init_op; + ivdext_create_ip_t s_create_ip; + ivdext_create_op_t s_create_op; void *dec_fxns = (void *)ivdec_api_function; - s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t); - s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT; - s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords; - s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = displayStride; - s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = displayHeight; + s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t); + s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE; + s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0; + s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t); + s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorFormat; + s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc; + s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free; + s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL; - s_init_ip.i4_level = i4_level; - s_init_ip.u4_num_reorder_frames = u4_num_reorder_frames; - s_init_ip.u4_num_ref_frames = u4_num_ref_frames; - s_init_ip.u4_share_disp_buf = u4_share_disp_buf; - s_init_ip.u4_num_extra_disp_buf = 0; + status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op); - s_init_op.s_ivd_init_op_t.u4_size = sizeof(s_init_op); - - s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords; - s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorFormat; - - mCodecCtx = (iv_obj_t *)mMemRecords[0].pv_base; + mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle; mCodecCtx->pv_fxns = dec_fxns; mCodecCtx->u4_size = sizeof(iv_obj_t); - status = ivdec_api_function(mCodecCtx, (void *)&s_init_ip, (void *)&s_init_op); if (status != IV_SUCCESS) { + ALOGE("Error in create: 0x%x", + s_create_op.s_ivd_create_op_t.u4_error_code); + deInitDecoder(); mCodecCtx = NULL; - ALOGE("Error in init: 0x%x", - s_init_op.s_ivd_init_op_t.u4_error_code); return UNKNOWN_ERROR; } } @@ -449,7 +334,7 @@ status_t SoftAVC::initDecoder(uint32_t width, uint32_t height) { resetPlugin(); /* Set the run time (dynamic) parameters */ - setParams(displayStride); + setParams(mStride); /* Set number of cores/threads to be used by the codec */ setNumCores(); @@ -457,61 +342,37 @@ status_t SoftAVC::initDecoder(uint32_t width, uint32_t height) { /* Get codec version */ logVersion(); - /* Allocate internal picture buffer */ - uint32_t bufferSize = displaySizeY * 3 / 2; - mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, bufferSize); - if (NULL == mFlushOutBuffer) { - ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize); - return NO_MEMORY; - } - - mInitNeeded = false; mFlushNeeded = false; return OK; } status_t SoftAVC::deInitDecoder() { size_t i; + IV_API_CALL_STATUS_T status; - if (mMemRecords) { - iv_mem_rec_t *ps_mem_rec; + if (mCodecCtx) { + ivdext_delete_ip_t s_delete_ip; + ivdext_delete_op_t s_delete_op; - ps_mem_rec = mMemRecords; - for (i = 0; i < mNumMemRecords; i++) { - if (ps_mem_rec->pv_base) { - ivd_aligned_free(ps_mem_rec->pv_base); - } - ps_mem_rec++; + s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t); + s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE; + + s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t); + + status = ivdec_api_function(mCodecCtx, (void *)&s_delete_ip, (void *)&s_delete_op); + if (status != IV_SUCCESS) { + ALOGE("Error in delete: 0x%x", + s_delete_op.s_ivd_delete_op_t.u4_error_code); + return UNKNOWN_ERROR; } - ivd_aligned_free(mMemRecords); - mMemRecords = NULL; } - if (mFlushOutBuffer) { - ivd_aligned_free(mFlushOutBuffer); - mFlushOutBuffer = NULL; - } - mInitNeeded = true; mChangingResolution = false; return OK; } -status_t SoftAVC::reInitDecoder(uint32_t width, uint32_t height) { - status_t ret; - - deInitDecoder(); - - ret = initDecoder(width, height); - if (OK != ret) { - ALOGE("Create failure"); - deInitDecoder(); - return NO_MEMORY; - } - return OK; -} - void SoftAVC::onReset() { SoftVideoDecoderOMXComponent::onReset(); @@ -520,23 +381,6 @@ void SoftAVC::onReset() { resetPlugin(); } -OMX_ERRORTYPE SoftAVC::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) { - const uint32_t oldWidth = mWidth; - const uint32_t oldHeight = mHeight; - OMX_ERRORTYPE ret = SoftVideoDecoderOMXComponent::internalSetParameter(index, params); - if (mWidth != oldWidth || mHeight != oldHeight) { - mNewWidth = mWidth; - mNewHeight = mHeight; - status_t err = reInitDecoder(mNewWidth, mNewHeight); - if (err != OK) { - notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL); - mSignalledError = true; - return OMX_ErrorUnsupportedSetting; - } - } - return ret; -} - void SoftAVC::setDecodeArgs( ivd_video_decode_ip_t *ps_dec_ip, ivd_video_decode_op_t *ps_dec_op, @@ -587,6 +431,17 @@ void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) { if (kOutputPortIndex == portIndex) { setFlushMode(); + /* Allocate a picture buffer to flushed data */ + uint32_t displayStride = outputBufferWidth(); + uint32_t displayHeight = outputBufferHeight(); + + uint32_t bufferSize = displayStride * displayHeight * 3 / 2; + mFlushOutBuffer = (uint8_t *)memalign(128, bufferSize); + if (NULL == mFlushOutBuffer) { + ALOGE("Could not allocate flushOutputBuffer of size %zu", bufferSize); + return; + } + while (true) { ivd_video_decode_ip_t s_dec_ip; ivd_video_decode_op_t s_dec_op; @@ -601,6 +456,12 @@ void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) { break; } } + + if (mFlushOutBuffer) { + free(mFlushOutBuffer); + mFlushOutBuffer = NULL; + } + } } @@ -614,6 +475,17 @@ void SoftAVC::onQueueFilled(OMX_U32 portIndex) { return; } + if (NULL == mCodecCtx) { + if (OK != initDecoder()) { + return; + } + } + if (outputBufferWidth() != mStride) { + /* Set the run-time (dynamic) parameters */ + mStride = outputBufferWidth(); + setParams(mStride); + } + List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex); List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); @@ -676,22 +548,6 @@ void SoftAVC::onQueueFilled(OMX_U32 portIndex) { } } - // When there is an init required and the decoder is not in flush mode, - // update output port's definition and reinitialize decoder. - if (mInitNeeded && !mIsInFlush) { - bool portWillReset = false; - - status_t err = reInitDecoder(mNewWidth, mNewHeight); - if (err != OK) { - notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL); - mSignalledError = true; - return; - } - - handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight); - return; - } - /* Get a free slot in timestamp array to hold input timestamp */ { size_t i; @@ -726,10 +582,7 @@ void SoftAVC::onQueueFilled(OMX_U32 portIndex) { IV_API_CALL_STATUS_T status; status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); - bool unsupportedDimensions = - (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_dec_op.u4_error_code & 0xFF)); bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF)); - bool unsupportedLevel = (IH264D_UNSUPPORTED_LEVEL == (s_dec_op.u4_error_code & 0xFF)); GETTIME(&mTimeEnd, NULL); /* Compute time taken for decode() */ @@ -747,46 +600,6 @@ void SoftAVC::onQueueFilled(OMX_U32 portIndex) { mTimeStampsValid[timeStampIx] = false; } - - // This is needed to handle CTS DecoderTest testCodecResetsH264WithoutSurface, - // which is not sending SPS/PPS after port reconfiguration and flush to the codec. - if (unsupportedDimensions && !mFlushNeeded) { - bool portWillReset = false; - mNewWidth = s_dec_op.u4_pic_wd; - mNewHeight = s_dec_op.u4_pic_ht; - - status_t err = reInitDecoder(mNewWidth, mNewHeight); - if (err != OK) { - notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL); - mSignalledError = true; - return; - } - - handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight); - - setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx); - - ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); - return; - } - - if (unsupportedLevel && !mFlushNeeded) { - - mNewLevel = 51; - - status_t err = reInitDecoder(mNewWidth, mNewHeight); - if (err != OK) { - notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL); - mSignalledError = true; - return; - } - - setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx); - - ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); - return; - } - // If the decoder is in the changing resolution mode and there is no output present, // that means the switching is done and it's ready to reset the decoder and the plugin. if (mChangingResolution && !s_dec_op.u4_output_present) { @@ -796,28 +609,11 @@ void SoftAVC::onQueueFilled(OMX_U32 portIndex) { continue; } - if (unsupportedDimensions || resChanged) { + if (resChanged) { mChangingResolution = true; if (mFlushNeeded) { setFlushMode(); } - - if (unsupportedDimensions) { - mNewWidth = s_dec_op.u4_pic_wd; - mNewHeight = s_dec_op.u4_pic_ht; - mInitNeeded = true; - } - continue; - } - - if (unsupportedLevel) { - - if (mFlushNeeded) { - setFlushMode(); - } - - mNewLevel = 51; - mInitNeeded = true; continue; } diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.h b/media/libstagefright/codecs/avcdec/SoftAVCDec.h index 1ec8991..9dcabb4 100644 --- a/media/libstagefright/codecs/avcdec/SoftAVCDec.h +++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.h @@ -23,9 +23,6 @@ namespace android { -#define ivd_aligned_malloc(alignment, size) memalign(alignment, size) -#define ivd_aligned_free(buf) free(buf) - /** Number of entries in the time-stamp array */ #define MAX_TIME_STAMPS 64 @@ -62,7 +59,6 @@ protected: virtual void onQueueFilled(OMX_U32 portIndex); virtual void onPortFlushCompleted(OMX_U32 portIndex); virtual void onReset(); - virtual OMX_ERRORTYPE internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params); private: // Number of input and output buffers enum { @@ -70,8 +66,6 @@ private: }; iv_obj_t *mCodecCtx; // Codec context - iv_mem_rec_t *mMemRecords; // Memory records requested by the codec - size_t mNumMemRecords; // Number of memory records requested by the codec size_t mNumCores; // Number of cores to be uesd by the codec @@ -97,17 +91,15 @@ private: bool mIsInFlush; // codec is flush mode bool mReceivedEOS; // EOS is receieved on input port - bool mInitNeeded; - uint32_t mNewWidth; - uint32_t mNewHeight; - uint32_t mNewLevel; + // The input stream has changed to a different resolution, which is still supported by the // codec. So the codec is switching to decode the new resolution. bool mChangingResolution; bool mFlushNeeded; bool mSignalledError; + size_t mStride; - status_t initDecoder(uint32_t width, uint32_t height); + status_t initDecoder(); status_t deInitDecoder(); status_t setFlushMode(); status_t setParams(size_t stride); @@ -115,7 +107,7 @@ private: status_t setNumCores(); status_t resetDecoder(); status_t resetPlugin(); - status_t reInitDecoder(uint32_t width, uint32_t height); + void setDecodeArgs( ivd_video_decode_ip_t *ps_dec_ip, diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp index e9ead01..03e4119 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp +++ b/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp @@ -19,6 +19,7 @@ #include "vlc_decode.h" #include "bitstream.h" #include "scaling.h" +#include "log/log.h" /* ====================================================================== / Function : ConcealTexture_I() @@ -137,6 +138,10 @@ Modified: 6/04/2001 rewrote the function ****************************************************************************/ void CopyVopMB(Vop *curr, uint8 *prevFrame, int mbnum, int width_Y, int height) { + if (curr == NULL || prevFrame == NULL) { + ALOGE("b/24630158"); + return; + } int width_C = width_Y >> 1; int row = MB_SIZE; uint8 *y1, *y2, *u1, *u2, *v1, *v2; diff --git a/media/libstagefright/data/media_codecs_google_tv.xml b/media/libstagefright/data/media_codecs_google_tv.xml new file mode 100644 index 0000000..330c6fb --- /dev/null +++ b/media/libstagefright/data/media_codecs_google_tv.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!-- Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<Included> + <Decoders> + <MediaCodec name="OMX.google.mpeg2.decoder" type="video/mpeg2"> + <!-- profiles and levels: ProfileMain : LevelHL --> + <Limit name="size" min="16x16" max="1920x1088" /> + <Limit name="alignment" value="2x2" /> + <Limit name="block-size" value="16x16" /> + <Limit name="blocks-per-second" range="1-244800" /> + <Limit name="bitrate" range="1-20000000" /> + <Feature name="adaptive-playback" /> + </MediaCodec> + </Decoders> +</Included> diff --git a/media/libstagefright/data/media_codecs_google_video.xml b/media/libstagefright/data/media_codecs_google_video.xml index a83789c..07e26a2 100755..100644 --- a/media/libstagefright/data/media_codecs_google_video.xml +++ b/media/libstagefright/data/media_codecs_google_video.xml @@ -16,15 +16,6 @@ <Included> <Decoders> - <MediaCodec name="OMX.google.mpeg2.decoder" type="video/mpeg2"> - <!-- profiles and levels: ProfileMain : LevelHL --> - <Limit name="size" min="16x16" max="1920x1088" /> - <Limit name="alignment" value="2x2" /> - <Limit name="block-size" value="16x16" /> - <Limit name="blocks-per-second" range="1-244800" /> - <Limit name="bitrate" range="1-20000000" /> - <Feature name="adaptive-playback" /> - </MediaCodec> <MediaCodec name="OMX.google.mpeg4.decoder"> <Type name="video/mp4v-es" /> <!-- diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp index e549ff6..725a574 100644 --- a/media/libstagefright/foundation/AMessage.cpp +++ b/media/libstagefright/foundation/AMessage.cpp @@ -601,13 +601,24 @@ sp<AMessage> AMessage::FromParcel(const Parcel &parcel) { msg->setWhat(what); msg->mNumItems = static_cast<size_t>(parcel.readInt32()); + if (msg->mNumItems > kMaxNumItems) { + ALOGE("Too large number of items clipped."); + msg->mNumItems = kMaxNumItems; + } + for (size_t i = 0; i < msg->mNumItems; ++i) { Item *item = &msg->mItems[i]; const char *name = parcel.readCString(); - item->setName(name, strlen(name)); - item->mType = static_cast<Type>(parcel.readInt32()); + if (name == NULL) { + ALOGE("Failed reading name for an item. Parsing aborted."); + msg->mNumItems = i; + break; + } + item->mType = static_cast<Type>(parcel.readInt32()); + // setName() happens below so that we don't leak memory when parsing + // is aborted in the middle. switch (item->mType) { case kTypeInt32: { @@ -641,7 +652,16 @@ sp<AMessage> AMessage::FromParcel(const Parcel &parcel) { case kTypeString: { - item->u.stringValue = new AString(parcel.readCString()); + const char *stringValue = parcel.readCString(); + if (stringValue == NULL) { + ALOGE("Failed reading string value from a parcel. " + "Parsing aborted."); + msg->mNumItems = i; + continue; + // The loop will terminate subsequently. + } else { + item->u.stringValue = new AString(stringValue); + } break; } @@ -660,6 +680,8 @@ sp<AMessage> AMessage::FromParcel(const Parcel &parcel) { TRESPASS(); } } + + item->setName(name, strlen(name)); } return msg; diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp index d9a198d..76d65f0 100644 --- a/media/libstagefright/id3/ID3.cpp +++ b/media/libstagefright/id3/ID3.cpp @@ -194,6 +194,13 @@ struct id3_header { if (header.version_major == 4) { void *copy = malloc(size); + if (copy == NULL) { + free(mData); + mData = NULL; + ALOGE("b/24623447, no more memory"); + return false; + } + memcpy(copy, mData, size); bool success = removeUnsynchronizationV2_4(false /* iTunesHack */); @@ -234,7 +241,14 @@ struct id3_header { return false; } - size_t extendedHeaderSize = U32_AT(&mData[0]) + 4; + size_t extendedHeaderSize = U32_AT(&mData[0]); + if (extendedHeaderSize > SIZE_MAX - 4) { + free(mData); + mData = NULL; + ALOGE("b/24623447, extendedHeaderSize is too large"); + return false; + } + extendedHeaderSize += 4; if (extendedHeaderSize > mSize) { free(mData); @@ -252,7 +266,10 @@ struct id3_header { if (extendedHeaderSize >= 10) { size_t paddingSize = U32_AT(&mData[6]); - if (mFirstFrameOffset + paddingSize > mSize) { + if (paddingSize > SIZE_MAX - mFirstFrameOffset) { + ALOGE("b/24623447, paddingSize is too large"); + } + if (paddingSize > mSize - mFirstFrameOffset) { free(mData); mData = NULL; diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h index d36da6a..afa91ae 100644 --- a/media/libstagefright/include/NuCachedSource2.h +++ b/media/libstagefright/include/NuCachedSource2.h @@ -28,7 +28,7 @@ struct ALooper; struct PageCache; struct NuCachedSource2 : public DataSource { - NuCachedSource2( + static sp<NuCachedSource2> Create( const sp<DataSource> &source, const char *cacheConfig = NULL, bool disconnectAtHighwatermark = false); @@ -72,6 +72,11 @@ protected: protected: friend struct AHandlerReflector<NuCachedSource2>; + NuCachedSource2( + const sp<DataSource> &source, + const char *cacheConfig, + bool disconnectAtHighwatermark); + enum { kPageSize = 65536, kDefaultHighWaterThreshold = 20 * 1024 * 1024, diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h index d468dfc..e7c4f6d 100644 --- a/media/libstagefright/include/OMX.h +++ b/media/libstagefright/include/OMX.h @@ -140,6 +140,8 @@ public: virtual void binderDied(const wp<IBinder> &the_late_who); + virtual bool isSecure(IOMX::node_id node); + OMX_ERRORTYPE OnEvent( node_id node, OMX_IN OMX_EVENTTYPE eEvent, diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h index f68e0a9..e5fb45b 100644 --- a/media/libstagefright/include/OMXNodeInstance.h +++ b/media/libstagefright/include/OMXNodeInstance.h @@ -125,6 +125,10 @@ struct OMXNodeInstance { const void *data, size_t size); + bool isSecure() const { + return mIsSecure; + } + // handles messages and removes them from the list void onMessages(std::list<omx_message> &messages); void onMessage(const omx_message &msg); @@ -142,6 +146,7 @@ private: OMX_HANDLETYPE mHandle; sp<IOMXObserver> mObserver; bool mDying; + bool mIsSecure; // Lock only covers mGraphicBufferSource. We can't always use mLock // because of rare instances where we'd end up locking it recursively. diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index 2ef30e3..efb1a1c 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -194,6 +194,11 @@ void OMX::binderDied(const wp<IBinder> &the_late_who) { instance->onObserverDied(mMaster); } +bool OMX::isSecure(node_id node) { + OMXNodeInstance *instance = findInstance(node); + return (instance == NULL ? false : instance->isSecure()); +} + bool OMX::livesLocally(node_id /* node */, pid_t pid) { return pid == getpid(); } diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index bdd1039..4bcc732 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -206,6 +206,7 @@ OMXNodeInstance::OMXNodeInstance( mDebugLevelBumpPendingBuffers[1] = 0; mMetadataType[0] = kMetadataBufferTypeInvalid; mMetadataType[1] = kMetadataBufferTypeInvalid; + mIsSecure = AString(name).endsWith(".secure"); } OMXNodeInstance::~OMXNodeInstance() { diff --git a/media/utils/Android.mk b/media/utils/Android.mk index dfadbc8..54d22b1 100644 --- a/media/utils/Android.mk +++ b/media/utils/Android.mk @@ -18,6 +18,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ BatteryNotifier.cpp \ + ISchedulingPolicyService.cpp \ + SchedulingPolicyService.cpp LOCAL_SHARED_LIBRARIES := \ libbinder \ diff --git a/services/audioflinger/ISchedulingPolicyService.cpp b/media/utils/ISchedulingPolicyService.cpp index f55bc02..f55bc02 100644 --- a/services/audioflinger/ISchedulingPolicyService.cpp +++ b/media/utils/ISchedulingPolicyService.cpp diff --git a/services/audioflinger/ISchedulingPolicyService.h b/media/utils/ISchedulingPolicyService.h index b94b191..b94b191 100644 --- a/services/audioflinger/ISchedulingPolicyService.h +++ b/media/utils/ISchedulingPolicyService.h diff --git a/services/audioflinger/SchedulingPolicyService.cpp b/media/utils/SchedulingPolicyService.cpp index 70a3f1a..17ee9bc 100644 --- a/services/audioflinger/SchedulingPolicyService.cpp +++ b/media/utils/SchedulingPolicyService.cpp @@ -20,7 +20,7 @@ #include <binder/IServiceManager.h> #include <utils/Mutex.h> #include "ISchedulingPolicyService.h" -#include "SchedulingPolicyService.h" +#include "mediautils/SchedulingPolicyService.h" namespace android { diff --git a/services/audioflinger/SchedulingPolicyService.h b/media/utils/include/mediautils/SchedulingPolicyService.h index a9870d4..a9870d4 100644 --- a/services/audioflinger/SchedulingPolicyService.h +++ b/media/utils/include/mediautils/SchedulingPolicyService.h diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk index 4791ce4..474fb46 100644 --- a/services/audioflinger/Android.mk +++ b/services/audioflinger/Android.mk @@ -3,17 +3,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ - ISchedulingPolicyService.cpp \ - SchedulingPolicyService.cpp - -# FIXME Move this library to frameworks/native -LOCAL_MODULE := libscheduling_policy - -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ ServiceUtilities.cpp # FIXME Move this library to frameworks/native @@ -64,10 +53,10 @@ LOCAL_SHARED_LIBRARIES := \ libeffects \ libpowermanager \ libserviceutility \ - libsonic + libsonic \ + libmediautils LOCAL_STATIC_LIBRARIES := \ - libscheduling_policy \ libcpustats \ libmedia_helper diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 8dfdca6..cdf8b1e 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -60,7 +60,7 @@ #include "FastMixer.h" #include "FastCapture.h" #include "ServiceUtilities.h" -#include "SchedulingPolicyService.h" +#include "mediautils/SchedulingPolicyService.h" #ifdef ADD_BATTERY_DATA #include <media/IMediaPlayerService.h> @@ -3498,6 +3498,12 @@ ssize_t AudioFlinger::MixerThread::threadLoop_write() if (state->mCommand != FastMixerState::MIX_WRITE && (kUseFastMixer != FastMixer_Dynamic || state->mTrackMask > 1)) { if (state->mCommand == FastMixerState::COLD_IDLE) { + + // FIXME workaround for first HAL write being CPU bound on some devices + ATRACE_BEGIN("write"); + mOutput->write((char *)mSinkBuffer, 0); + ATRACE_END(); + int32_t old = android_atomic_inc(&mFastMixerFutex); if (old == -1) { (void) syscall(__NR_futex, &mFastMixerFutex, FUTEX_WAKE_PRIVATE, 1); diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index a45a6f8..98eb87f 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -433,7 +433,10 @@ AudioFlinger::PlaybackThread::Track::Track( } // only allocate a fast track index if we were able to allocate a normal track name if (flags & IAudioFlinger::TRACK_FAST) { - mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads(); + // FIXME: Not calling framesReadyIsCalledByMultipleThreads() exposes a potential + // race with setSyncEvent(). However, if we call it, we cannot properly start + // static fast tracks (SoundPool) immediately after stopping. + //mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads(); ALOG_ASSERT(thread->mFastTrackAvailMask != 0); int i = __builtin_ctz(thread->mFastTrackAvailMask); ALOG_ASSERT(0 < i && i < (int)FastMixerState::kMaxFastTracks); diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h index 18bcfdb..48d09ed 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h @@ -56,9 +56,21 @@ public: const struct audio_port_config *srcConfig = NULL) const; virtual sp<AudioPort> getAudioPort() const { return mProfile; } void toAudioPort(struct audio_port *port) const; + void setPreemptedSessions(const SortedVector<audio_session_t>& sessions); + SortedVector<audio_session_t> getPreemptedSessions() const; + bool hasPreemptedSession(audio_session_t session) const; + void clearPreemptedSessions(); private: audio_port_handle_t mId; + // Because a preemtible capture session can preempt another one, we end up in an endless loop + // situation were each session is allowed to restart after being preempted, + // thus preempting the other one which restarts and so on. + // To avoid this situation, we store which audio session was preempted when + // a particular input started and prevent preemption of this active input by this session. + // We also inherit sessions from the preempted input to avoid a 3 way preemption loop etc... + SortedVector<audio_session_t> mPreemptedSessions; + }; class AudioInputCollection : diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp index 937160b..626fdae 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp @@ -93,6 +93,26 @@ void AudioInputDescriptor::toAudioPort(struct audio_port *port) const port->ext.mix.latency_class = AUDIO_LATENCY_NORMAL; } +void AudioInputDescriptor::setPreemptedSessions(const SortedVector<audio_session_t>& sessions) +{ + mPreemptedSessions = sessions; +} + +SortedVector<audio_session_t> AudioInputDescriptor::getPreemptedSessions() const +{ + return mPreemptedSessions; +} + +bool AudioInputDescriptor::hasPreemptedSession(audio_session_t session) const +{ + return (mPreemptedSessions.indexOf(session) >= 0); +} + +void AudioInputDescriptor::clearPreemptedSessions() +{ + mPreemptedSessions.clear(); +} + status_t AudioInputDescriptor::dump(int fd) { const size_t SIZE = 256; diff --git a/services/audiopolicy/enginedefault/src/Gains.cpp b/services/audiopolicy/enginedefault/src/Gains.cpp index 78f2909..d06365c 100644 --- a/services/audiopolicy/enginedefault/src/Gains.cpp +++ b/services/audiopolicy/enginedefault/src/Gains.cpp @@ -171,10 +171,10 @@ const VolumeCurvePoint *Gains::sVolumeProfiles[AUDIO_STREAM_CNT] }, { // AUDIO_STREAM_TTS // "Transmitted Through Speaker": always silent except on DEVICE_CATEGORY_SPEAKER - Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_HEADSET - Gains::sLinearVolumeCurve, // DEVICE_CATEGORY_SPEAKER - Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_EARPIECE - Gains::sSilentVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA + Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_HEADSET + Gains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER + Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_EARPIECE + Gains::sSilentVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA }, { // AUDIO_STREAM_ACCESSIBILITY Gains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index 483855f..acdd23d 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -1074,7 +1074,7 @@ status_t AudioPolicyManager::startSource(sp<AudioOutputDescriptor> outputDesc, *delayMs = 0; if (stream == AUDIO_STREAM_TTS) { ALOGV("\t found BEACON stream"); - if (mOutputs.isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) { + if (!mTtsOutputAvailable && mOutputs.isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) { return INVALID_OPERATION; } else { beaconMuteLatency = handleEventForBeacon(STARTING_BEACON); @@ -1485,10 +1485,15 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input, // If the already active input uses AUDIO_SOURCE_HOTWORD then it is closed, // otherwise the active input continues and the new input cannot be started. sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput); - if (activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) { + if ((activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) && + !activeDesc->hasPreemptedSession(session)) { ALOGW("startInput(%d) preempting low-priority input %d", input, activeInput); - stopInput(activeInput, activeDesc->mSessions.itemAt(0)); - releaseInput(activeInput, activeDesc->mSessions.itemAt(0)); + audio_session_t activeSession = activeDesc->mSessions.itemAt(0); + SortedVector<audio_session_t> sessions = activeDesc->getPreemptedSessions(); + sessions.add(activeSession); + inputDesc->setPreemptedSessions(sessions); + stopInput(activeInput, activeSession); + releaseInput(activeInput, activeSession); } else { ALOGE("startInput(%d) failed: other input %d already started", input, activeInput); return INVALID_OPERATION; @@ -1592,6 +1597,7 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input, if (mInputs.activeInputsCount() == 0) { SoundTrigger::setCaptureState(false); } + inputDesc->clearPreemptedSessions(); } return NO_ERROR; } @@ -1718,7 +1724,9 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream, status = volStatus; } } - if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & accessibilityDevice) != 0)) { + if ((accessibilityDevice != AUDIO_DEVICE_NONE) && + ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & accessibilityDevice) != 0))) + { status_t volStatus = checkAndSetVolume(AUDIO_STREAM_ACCESSIBILITY, index, desc, curDevice); } @@ -2007,6 +2015,9 @@ status_t AudioPolicyManager::dump(int fd) snprintf(buffer, SIZE, " Force use for hdmi system audio %d\n", mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO)); result.append(buffer); + snprintf(buffer, SIZE, " TTS output %s\n", mTtsOutputAvailable ? "available" : "not available"); + result.append(buffer); + write(fd, result.string(), result.size()); mAvailableOutputDevices.dump(fd, String8("output")); @@ -2687,7 +2698,8 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa mAudioPortGeneration(1), mBeaconMuteRefCount(0), mBeaconPlayingRefCount(0), - mBeaconMuted(false) + mBeaconMuted(false), + mTtsOutputAvailable(false) { audio_policy::EngineInstance *engineInstance = audio_policy::EngineInstance::getInstance(); if (!engineInstance) { @@ -2744,6 +2756,9 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa ALOGW("Output profile contains no device on module %s", mHwModules[i]->mName); continue; } + if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_TTS) != 0) { + mTtsOutputAvailable = true; + } if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) { continue; @@ -4043,6 +4058,12 @@ void AudioPolicyManager::handleNotificationRoutingForStream(audio_stream_type_t } uint32_t AudioPolicyManager::handleEventForBeacon(int event) { + + // skip beacon mute management if a dedicated TTS output is available + if (mTtsOutputAvailable) { + return 0; + } + switch(event) { case STARTING_OUTPUT: mBeaconMuteRefCount++; diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h index 80c41c8..c40a435 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.h +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h @@ -548,6 +548,7 @@ protected: uint32_t mBeaconMuteRefCount; // ref count for stream that would mute beacon uint32_t mBeaconPlayingRefCount;// ref count for the playing beacon streams bool mBeaconMuted; // has STREAM_TTS been muted + bool mTtsOutputAvailable; // true if a dedicated output for TTS stream is available AudioPolicyMixCollection mPolicyMixes; // list of registered mixes diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index 793c26a..ca365a5 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -76,10 +76,14 @@ status_t AudioPolicyService::setPhoneState(audio_mode_t state) ALOGV("setPhoneState()"); + // acquire lock before calling setMode() so that setMode() + setPhoneState() are an atomic + // operation from policy manager standpoint (no other operation (e.g track start or stop) + // can be interleaved). + Mutex::Autolock _l(mLock); + // TODO: check if it is more appropriate to do it in platform specific policy manager AudioSystem::setMode(state); - Mutex::Autolock _l(mLock); mAudioPolicyManager->setPhoneState(state); mPhoneState = state; return NO_ERROR; diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp index d689065..41dd40c 100644 --- a/services/audiopolicy/service/AudioPolicyService.cpp +++ b/services/audiopolicy/service/AudioPolicyService.cpp @@ -577,22 +577,28 @@ bool AudioPolicyService::AudioCommandThread::threadLoop() } } waitTime = INT64_MAX; + // release mLock before releasing strong reference on the service as + // AudioPolicyService destructor calls AudioCommandThread::exit() which + // acquires mLock. + mLock.unlock(); + svc.clear(); + mLock.lock(); } else { waitTime = mAudioCommands[0]->mTime - curTime; break; } } - // release mLock before releasing strong reference on the service as - // AudioPolicyService destructor calls AudioCommandThread::exit() which acquires mLock. - mLock.unlock(); - svc.clear(); - mLock.lock(); - if (!exitPending() && (mAudioCommands.isEmpty() || waitTime != INT64_MAX)) { - // release delayed commands wake lock + + // release delayed commands wake lock if the queue is empty + if (mAudioCommands.isEmpty()) { release_wake_lock(mName.string()); + } + + // At this stage we have either an empty command queue or the first command in the queue + // has a finite delay. So unless we are exiting it is safe to wait. + if (!exitPending()) { ALOGV("AudioCommandThread() going to sleep"); mWaitWorkCV.waitRelative(mLock, waitTime); - ALOGV("AudioCommandThread() waking up"); } } // release delayed commands wake lock before quitting @@ -1005,6 +1011,8 @@ void AudioPolicyService::AudioCommandThread::exit() requestExit(); mWaitWorkCV.signal(); } + // Note that we can call it from the thread loop if all other references have been released + // but it will safely return WOULD_BLOCK in this case requestExitAndWait(); } diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index f3087d8..ab09cb3 100644 --- a/services/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk @@ -53,7 +53,7 @@ LOCAL_SRC_FILES:= \ device3/StatusTracker.cpp \ gui/RingBufferConsumer.cpp \ utils/CameraTraces.cpp \ - utils/AutoConditionLock.cpp \ + utils/AutoConditionLock.cpp LOCAL_SHARED_LIBRARIES:= \ libui \ diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 26c8007..db6272b 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -15,6 +15,7 @@ */ #define LOG_TAG "CameraService" +#define ATRACE_TAG ATRACE_TAG_CAMERA //#define LOG_NDEBUG 0 #include <algorithm> @@ -33,7 +34,6 @@ #include <binder/MemoryBase.h> #include <binder/MemoryHeapBase.h> #include <binder/ProcessInfoService.h> -#include <camera/ICameraServiceProxy.h> #include <cutils/atomic.h> #include <cutils/properties.h> #include <gui/Surface.h> @@ -157,7 +157,6 @@ void CameraService::onFirstRef() } mModule = new CameraModule(rawModule); - ALOGI("Loaded \"%s\" camera module", mModule->getModuleName()); err = mModule->init(); if (err != OK) { ALOGE("Could not initialize camera HAL module: %d (%s)", err, @@ -169,6 +168,7 @@ void CameraService::onFirstRef() mModule = nullptr; return; } + ALOGI("Loaded \"%s\" camera module", mModule->getModuleName()); mNumberOfCameras = mModule->getNumberOfCameras(); mNumberOfNormalCameras = mNumberOfCameras; @@ -250,13 +250,19 @@ void CameraService::onFirstRef() CameraService::pingCameraServiceProxy(); } -void CameraService::pingCameraServiceProxy() { +sp<ICameraServiceProxy> CameraService::getCameraServiceProxy() { sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder = sm->getService(String16("media.camera.proxy")); if (binder == nullptr) { - return; + return nullptr; } sp<ICameraServiceProxy> proxyBinder = interface_cast<ICameraServiceProxy>(binder); + return proxyBinder; +} + +void CameraService::pingCameraServiceProxy() { + sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy(); + if (proxyBinder == nullptr) return; proxyBinder->pingForUserUpdate(); } @@ -398,10 +404,12 @@ void CameraService::onTorchStatusChangedLocked(const String8& cameraId, } int32_t CameraService::getNumberOfCameras() { + ATRACE_CALL(); return getNumberOfCameras(CAMERA_TYPE_BACKWARD_COMPATIBLE); } int32_t CameraService::getNumberOfCameras(int type) { + ATRACE_CALL(); switch (type) { case CAMERA_TYPE_BACKWARD_COMPATIBLE: return mNumberOfNormalCameras; @@ -416,6 +424,7 @@ int32_t CameraService::getNumberOfCameras(int type) { status_t CameraService::getCameraInfo(int cameraId, struct CameraInfo* cameraInfo) { + ATRACE_CALL(); if (!mModule) { return -ENODEV; } @@ -443,6 +452,7 @@ int CameraService::cameraIdToInt(const String8& cameraId) { } status_t CameraService::generateShimMetadata(int cameraId, /*out*/CameraMetadata* cameraInfo) { + ATRACE_CALL(); status_t ret = OK; struct CameraInfo info; if ((ret = getCameraInfo(cameraId, &info)) != OK) { @@ -529,6 +539,7 @@ status_t CameraService::generateShimMetadata(int cameraId, /*out*/CameraMetadata status_t CameraService::getCameraCharacteristics(int cameraId, CameraMetadata* cameraInfo) { + ATRACE_CALL(); if (!cameraInfo) { ALOGE("%s: cameraInfo is NULL", __FUNCTION__); return BAD_VALUE; @@ -597,10 +608,16 @@ int CameraService::getCameraPriorityFromProcState(int procState) { procState); return -1; } + // Treat sleeping TOP processes the same as regular TOP processes, for + // access priority. This is important for lock-screen camera launch scenarios + if (procState == PROCESS_STATE_TOP_SLEEPING) { + procState = PROCESS_STATE_TOP; + } return INT_MAX - procState; } status_t CameraService::getCameraVendorTagDescriptor(/*out*/sp<VendorTagDescriptor>& desc) { + ATRACE_CALL(); if (!mModule) { ALOGE("%s: camera hardware module doesn't exist", __FUNCTION__); return -ENODEV; @@ -611,6 +628,7 @@ status_t CameraService::getCameraVendorTagDescriptor(/*out*/sp<VendorTagDescript } int CameraService::getDeviceVersion(int cameraId, int* facing) { + ATRACE_CALL(); struct camera_info info; if (mModule->getCameraInfo(cameraId, &info) != OK) { return -1; @@ -642,6 +660,7 @@ status_t CameraService::filterGetInfoErrorCode(status_t err) { } bool CameraService::setUpVendorTags() { + ATRACE_CALL(); vendor_tag_ops_t vOps = vendor_tag_ops_t(); // Check if vendor operations have been implemented @@ -650,9 +669,7 @@ bool CameraService::setUpVendorTags() { return false; } - ATRACE_BEGIN("camera3->get_metadata_vendor_tag_ops"); mModule->getVendorTagOps(&vOps); - ATRACE_END(); // Ensure all vendor operations are present if (vOps.get_tag_count == NULL || vOps.get_all_tags == NULL || @@ -935,6 +952,16 @@ void CameraService::finishConnectLocked(const sp<BasicClient>& client, LOG_ALWAYS_FATAL("%s: Invalid state for CameraService, clients not evicted properly", __FUNCTION__); } + + // And register a death notification for the client callback. Do + // this last to avoid Binder policy where a nested Binder + // transaction might be pre-empted to service the client death + // notification if the client process dies before linkToDeath is + // invoked. + sp<IBinder> remoteCallback = client->getRemote(); + if (remoteCallback != nullptr) { + remoteCallback->linkToDeath(this); + } } status_t CameraService::handleEvictionsLocked(const String8& cameraId, int clientPid, @@ -942,7 +969,7 @@ status_t CameraService::handleEvictionsLocked(const String8& cameraId, int clien /*out*/ sp<BasicClient>* client, std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>>* partial) { - + ATRACE_CALL(); status_t ret = NO_ERROR; std::vector<DescriptorPtr> evictedClients; DescriptorPtr clientDescriptor; @@ -1131,6 +1158,7 @@ status_t CameraService::connect( /*out*/ sp<ICamera>& device) { + ATRACE_CALL(); status_t ret = NO_ERROR; String8 id = String8::format("%d", cameraId); sp<Client> client = nullptr; @@ -1155,6 +1183,7 @@ status_t CameraService::connectLegacy( /*out*/ sp<ICamera>& device) { + ATRACE_CALL(); String8 id = String8::format("%d", cameraId); int apiVersion = mModule->getModuleApiVersion(); if (halVersion != CAMERA_HAL_API_VERSION_UNSPECIFIED && @@ -1195,6 +1224,7 @@ status_t CameraService::connectDevice( /*out*/ sp<ICameraDeviceUser>& device) { + ATRACE_CALL(); status_t ret = NO_ERROR; String8 id = String8::format("%d", cameraId); sp<CameraDeviceClient> client = nullptr; @@ -1214,6 +1244,8 @@ status_t CameraService::connectDevice( status_t CameraService::setTorchMode(const String16& cameraId, bool enabled, const sp<IBinder>& clientBinder) { + + ATRACE_CALL(); if (enabled && clientBinder == nullptr) { ALOGE("%s: torch client binder is NULL", __FUNCTION__); return -EINVAL; @@ -1302,6 +1334,8 @@ status_t CameraService::setTorchMode(const String16& cameraId, bool enabled, } void CameraService::notifySystemEvent(int32_t eventId, const int32_t* args, size_t length) { + ATRACE_CALL(); + switch(eventId) { case ICameraService::USER_SWITCHED: { doUserSwitch(/*newUserIds*/args, /*length*/length); @@ -1317,6 +1351,8 @@ void CameraService::notifySystemEvent(int32_t eventId, const int32_t* args, size } status_t CameraService::addListener(const sp<ICameraServiceListener>& listener) { + ATRACE_CALL(); + ALOGV("%s: Add listener %p", __FUNCTION__, listener.get()); if (listener == nullptr) { @@ -1365,6 +1401,8 @@ status_t CameraService::addListener(const sp<ICameraServiceListener>& listener) } status_t CameraService::removeListener(const sp<ICameraServiceListener>& listener) { + ATRACE_CALL(); + ALOGV("%s: Remove listener %p", __FUNCTION__, listener.get()); if (listener == 0) { @@ -1391,6 +1429,8 @@ status_t CameraService::removeListener(const sp<ICameraServiceListener>& listene } status_t CameraService::getLegacyParameters(int cameraId, /*out*/String16* parameters) { + + ATRACE_CALL(); ALOGV("%s: for camera ID = %d", __FUNCTION__, cameraId); if (parameters == NULL) { @@ -1415,6 +1455,8 @@ status_t CameraService::getLegacyParameters(int cameraId, /*out*/String16* param } status_t CameraService::supportsCameraApi(int cameraId, int apiVersion) { + ATRACE_CALL(); + ALOGV("%s: for camera ID = %d", __FUNCTION__, cameraId); switch (apiVersion) { @@ -1782,6 +1824,8 @@ MediaPlayer* CameraService::newMediaPlayer(const char *file) { } void CameraService::loadSound() { + ATRACE_CALL(); + Mutex::Autolock lock(mSoundLock); LOG1("CameraService::loadSound ref=%d", mSoundRef); if (mSoundRef++) return; @@ -1804,6 +1848,8 @@ void CameraService::releaseSound() { } void CameraService::playSound(sound_kind kind) { + ATRACE_CALL(); + LOG1("playSound(%d)", kind); Mutex::Autolock lock(mSoundLock); sp<MediaPlayer> player = mSoundPlayer[kind]; @@ -1874,11 +1920,9 @@ CameraService::BasicClient::~BasicClient() { void CameraService::BasicClient::disconnect() { if (mDisconnected) { - ALOGE("%s: Disconnect called on already disconnected client for device %d", __FUNCTION__, - mCameraId); return; } - mDisconnected = true;; + mDisconnected = true; mCameraService->removeByClient(this); mCameraService->logDisconnected(String8::format("%d", mCameraId), mClientPid, @@ -1915,6 +1959,8 @@ bool CameraService::BasicClient::canCastToApiClient(apiLevel level) const { } status_t CameraService::BasicClient::startCameraOps() { + ATRACE_CALL(); + int32_t res; // Notify app ops that the camera is not available mOpsCallback = new OpsCallback(this); @@ -1948,10 +1994,16 @@ status_t CameraService::BasicClient::startCameraOps() { mCameraService->updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE, String8::format("%d", mCameraId)); + // Transition device state to OPEN + mCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_OPEN, + String8::format("%d", mCameraId)); + return OK; } status_t CameraService::BasicClient::finishCameraOps() { + ATRACE_CALL(); + // Check if startCameraOps succeeded, and if so, finish the camera op if (mOpsActive) { // Notify app ops that the camera is available again @@ -1966,6 +2018,10 @@ status_t CameraService::BasicClient::finishCameraOps() { mCameraService->updateStatus(ICameraServiceListener::STATUS_PRESENT, String8::format("%d", mCameraId), rejected); + // Transition device state to CLOSED + mCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_CLOSED, + String8::format("%d", mCameraId)); + // Notify flashlight that a camera device is closed. mCameraService->mFlashlight->deviceClosed( String8::format("%d", mCameraId)); @@ -1980,6 +2036,8 @@ status_t CameraService::BasicClient::finishCameraOps() { } void CameraService::BasicClient::opChanged(int32_t op, const String16& packageName) { + ATRACE_CALL(); + String8 name(packageName); String8 myName(mClientPackageName); @@ -2207,9 +2265,11 @@ static bool tryLock(Mutex& mutex) } status_t CameraService::dump(int fd, const Vector<String16>& args) { + ATRACE_CALL(); + String8 result("Dump of the Camera Service:\n"); if (checkCallingPermission(String16("android.permission.DUMP")) == false) { - result.appendFormat("Permission Denial: " + result = result.format("Permission Denial: " "can't dump CameraService from pid=%d, uid=%d\n", getCallingPid(), getCallingUid()); @@ -2470,6 +2530,14 @@ void CameraService::updateStatus(ICameraServiceListener::Status status, const St }); } +void CameraService::updateProxyDeviceState(ICameraServiceProxy::CameraState newState, + const String8& cameraId) { + sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy(); + if (proxyBinder == nullptr) return; + String16 id(cameraId); + proxyBinder->notifyCameraState(id, newState); +} + status_t CameraService::getTorchStatusLocked( const String8& cameraId, ICameraServiceListener::TorchStatus *status) const { diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index b88434d..b3903d4 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -24,7 +24,8 @@ #include <binder/BinderService.h> #include <binder/IAppOpsCallback.h> #include <camera/ICameraService.h> -#include "hardware/camera.h" +#include <camera/ICameraServiceProxy.h> +#include <hardware/camera.h> #include <camera/ICamera.h> #include <camera/ICameraClient.h> @@ -78,6 +79,8 @@ public: // Process state (mirrors frameworks/base/core/java/android/app/ActivityManager.java) static const int PROCESS_STATE_NONEXISTENT = -1; + static const int PROCESS_STATE_TOP = 2; + static const int PROCESS_STATE_TOP_SLEEPING = 5; // 3 second busy timeout when other clients are connecting static const nsecs_t DEFAULT_CONNECT_TIMEOUT_NS = 3000000000; @@ -168,6 +171,14 @@ public: void playSound(sound_kind kind); void releaseSound(); + /** + * Update the state of a given camera device (open/close/active/idle) with + * the camera proxy service in the system service + */ + static void updateProxyDeviceState( + ICameraServiceProxy::CameraState newState, + const String8& cameraId); + ///////////////////////////////////////////////////////////////////// // CameraDeviceFactory functionality int getDeviceVersion(int cameraId, int* facing = NULL); @@ -734,6 +745,7 @@ private: static String8 toString(std::set<userid_t> intSet); + static sp<ICameraServiceProxy> getCameraServiceProxy(); static void pingCameraServiceProxy(); }; @@ -865,11 +877,6 @@ status_t CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String return ret; } - sp<IBinder> remoteCallback = client->getRemote(); - if (remoteCallback != nullptr) { - remoteCallback->linkToDeath(this); - } - // Update shim paremeters for legacy clients if (effectiveApiLevel == API_1) { // Assume we have always received a Client subclass for API1 diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp index 36e99dd..48b5a26 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.cpp +++ b/services/camera/libcameraservice/api1/Camera2Client.cpp @@ -1912,6 +1912,8 @@ void Camera2Client::notifyShutter(const CaptureResultExtras& resultExtras, ALOGV("%s: Shutter notification for request id %" PRId32 " at time %" PRId64, __FUNCTION__, resultExtras.requestId, timestamp); mCaptureSequencer->notifyShutter(resultExtras, timestamp); + + Camera2ClientBase::notifyShutter(resultExtras, timestamp); } camera2::SharedParameters& Camera2Client::getParameters() { diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp index b64c48c..1bb2910 100644 --- a/services/camera/libcameraservice/api1/CameraClient.cpp +++ b/services/camera/libcameraservice/api1/CameraClient.cpp @@ -254,6 +254,9 @@ void CameraClient::disconnect() { // Turn off all messages. disableMsgType(CAMERA_MSG_ALL_MSGS); mHardware->stopPreview(); + mCameraService->updateProxyDeviceState( + ICameraServiceProxy::CAMERA_STATE_IDLE, + String8::format("%d", mCameraId)); mHardware->cancelPicture(); // Release the hardware resources. mHardware->release(); @@ -413,7 +416,11 @@ status_t CameraClient::startPreviewMode() { } mHardware->setPreviewWindow(mPreviewWindow); result = mHardware->startPreview(); - + if (result == NO_ERROR) { + mCameraService->updateProxyDeviceState( + ICameraServiceProxy::CAMERA_STATE_ACTIVE, + String8::format("%d", mCameraId)); + } return result; } @@ -453,7 +460,9 @@ void CameraClient::stopPreview() { disableMsgType(CAMERA_MSG_PREVIEW_FRAME); mHardware->stopPreview(); - + mCameraService->updateProxyDeviceState( + ICameraServiceProxy::CAMERA_STATE_IDLE, + String8::format("%d", mCameraId)); mPreviewBuffer.clear(); } @@ -814,6 +823,12 @@ void CameraClient::handleShutter(void) { disableMsgType(CAMERA_MSG_SHUTTER); } + // Shutters only happen in response to takePicture, so mark device as + // idle now, until preview is restarted + mCameraService->updateProxyDeviceState( + ICameraServiceProxy::CAMERA_STATE_IDLE, + String8::format("%d", mCameraId)); + mLock.unlock(); } diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp index 442eb75..44447b4 100644 --- a/services/camera/libcameraservice/api1/client2/Parameters.cpp +++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp @@ -214,8 +214,8 @@ status_t Parameters::initialize(const CameraMetadata *info, int deviceVersion) { supportedPreviewFormats); } - previewFpsRange[0] = availableFpsRanges.data.i32[0]; - previewFpsRange[1] = availableFpsRanges.data.i32[1]; + previewFpsRange[0] = fastInfo.bestStillCaptureFpsRange[0]; + previewFpsRange[1] = fastInfo.bestStillCaptureFpsRange[1]; // PREVIEW_FRAME_RATE / SUPPORTED_PREVIEW_FRAME_RATES are deprecated, but // still have to do something sane for them diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp index c717a56..0c531c3 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp @@ -719,6 +719,43 @@ status_t CameraDeviceClient::prepare(int streamId) { return res; } +status_t CameraDeviceClient::prepare2(int maxCount, int streamId) { + ATRACE_CALL(); + ALOGV("%s", __FUNCTION__); + + status_t res = OK; + if ( (res = checkPid(__FUNCTION__) ) != OK) return res; + + Mutex::Autolock icl(mBinderSerializationLock); + + // Guard against trying to prepare non-created streams + ssize_t index = NAME_NOT_FOUND; + for (size_t i = 0; i < mStreamMap.size(); ++i) { + if (streamId == mStreamMap.valueAt(i)) { + index = i; + break; + } + } + + if (index == NAME_NOT_FOUND) { + ALOGW("%s: Camera %d: Invalid stream ID (%d) specified, no stream created yet", + __FUNCTION__, mCameraId, streamId); + return BAD_VALUE; + } + + if (maxCount <= 0) { + ALOGE("%s: Camera %d: Invalid maxCount (%d) specified, must be greater than 0.", + __FUNCTION__, mCameraId, maxCount); + return BAD_VALUE; + } + + // Also returns BAD_VALUE if stream ID was not valid, or stream already + // has been used + res = mDevice->prepare(maxCount, streamId); + + return res; +} + status_t CameraDeviceClient::tearDown(int streamId) { ATRACE_CALL(); ALOGV("%s", __FUNCTION__); @@ -799,6 +836,7 @@ void CameraDeviceClient::notifyIdle() { if (remoteCb != 0) { remoteCb->onDeviceIdle(); } + Camera2ClientBase::notifyIdle(); } void CameraDeviceClient::notifyShutter(const CaptureResultExtras& resultExtras, @@ -808,6 +846,7 @@ void CameraDeviceClient::notifyShutter(const CaptureResultExtras& resultExtras, if (remoteCb != 0) { remoteCb->onCaptureStarted(resultExtras, timestamp); } + Camera2ClientBase::notifyShutter(resultExtras, timestamp); } void CameraDeviceClient::notifyPrepared(int streamId) { diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h index 1f8b39d..d1e692c 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.h +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h @@ -114,6 +114,9 @@ public: // Tear down stream resources by freeing its unused buffers virtual status_t tearDown(int streamId); + // Prepare stream by preallocating up to maxCount of its buffers + virtual status_t prepare2(int maxCount, int streamId); + /** * Interface used by CameraService */ @@ -189,6 +192,7 @@ private: Vector<int> mStreamingRequestList; int32_t mRequestIdCounter; + }; }; // namespace android diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp index ba0b264..5732f80 100644 --- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp +++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp @@ -55,7 +55,8 @@ Camera2ClientBase<TClientBase>::Camera2ClientBase( TClientBase(cameraService, remoteCallback, clientPackageName, cameraId, cameraFacing, clientPid, clientUid, servicePid), mSharedCameraCallbacks(remoteCallback), - mDeviceVersion(cameraService->getDeviceVersion(cameraId)) + mDeviceVersion(cameraService->getDeviceVersion(cameraId)), + mDeviceActive(false) { ALOGI("Camera %d: Opened. Client: %s (PID %d, UID %d)", cameraId, String8(clientPackageName).string(), clientPid, clientUid); @@ -235,6 +236,13 @@ void Camera2ClientBase<TClientBase>::notifyError( template <typename TClientBase> void Camera2ClientBase<TClientBase>::notifyIdle() { + if (mDeviceActive) { + getCameraService()->updateProxyDeviceState( + ICameraServiceProxy::CAMERA_STATE_IDLE, + String8::format("%d", TClientBase::mCameraId)); + } + mDeviceActive = false; + ALOGV("Camera device is now idle"); } @@ -244,6 +252,13 @@ void Camera2ClientBase<TClientBase>::notifyShutter(const CaptureResultExtras& re (void)resultExtras; (void)timestamp; + if (!mDeviceActive) { + getCameraService()->updateProxyDeviceState( + ICameraServiceProxy::CAMERA_STATE_ACTIVE, + String8::format("%d", TClientBase::mCameraId)); + } + mDeviceActive = true; + ALOGV("%s: Shutter notification for request id %" PRId32 " at time %" PRId64, __FUNCTION__, resultExtras.requestId, timestamp); } diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h index f1cacdf..220c5ad 100644 --- a/services/camera/libcameraservice/common/Camera2ClientBase.h +++ b/services/camera/libcameraservice/common/Camera2ClientBase.h @@ -136,6 +136,8 @@ protected: status_t checkPid(const char *checkLocation) const; virtual void detachDevice(); + + bool mDeviceActive; }; }; // namespace android diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h index cd25949..7b083a3 100644 --- a/services/camera/libcameraservice/common/CameraDeviceBase.h +++ b/services/camera/libcameraservice/common/CameraDeviceBase.h @@ -294,6 +294,12 @@ class CameraDeviceBase : public virtual RefBase { virtual status_t tearDown(int streamId) = 0; /** + * Prepare stream by preallocating up to maxCount buffers for it asynchronously. + * Calls notifyPrepared() once allocation is complete. + */ + virtual status_t prepare(int maxCount, int streamId) = 0; + + /** * Get the HAL device version. */ virtual uint32_t getDeviceVersion() = 0; diff --git a/services/camera/libcameraservice/common/CameraModule.cpp b/services/camera/libcameraservice/common/CameraModule.cpp index 6a4dfe0..16b8aba 100644 --- a/services/camera/libcameraservice/common/CameraModule.cpp +++ b/services/camera/libcameraservice/common/CameraModule.cpp @@ -15,14 +15,18 @@ */ #define LOG_TAG "CameraModule" +#define ATRACE_TAG ATRACE_TAG_CAMERA //#define LOG_NDEBUG 0 +#include <utils/Trace.h> + #include "CameraModule.h" namespace android { void CameraModule::deriveCameraCharacteristicsKeys( uint32_t deviceVersion, CameraMetadata &chars) { + ATRACE_CALL(); // HAL1 devices should not reach here if (deviceVersion < CAMERA_DEVICE_API_VERSION_2_0) { ALOGV("%s: Cannot derive keys for HAL version < 2.0"); @@ -150,9 +154,7 @@ CameraModule::CameraModule(camera_module_t *module) { ALOGE("%s: camera hardware module must not be null", __FUNCTION__); assert(0); } - mModule = module; - mCameraInfoMap.setCapacity(getNumberOfCameras()); } CameraModule::~CameraModule() @@ -168,14 +170,20 @@ CameraModule::~CameraModule() } int CameraModule::init() { + ATRACE_CALL(); + int res = OK; if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 && mModule->init != NULL) { - return mModule->init(); + ATRACE_BEGIN("camera_module->init"); + res = mModule->init(); + ATRACE_END(); } - return OK; + mCameraInfoMap.setCapacity(getNumberOfCameras()); + return res; } int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) { + ATRACE_CALL(); Mutex::Autolock lock(mCameraInfoLock); if (cameraId < 0) { ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId); @@ -185,14 +193,20 @@ int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) { // Only override static_camera_characteristics for API2 devices int apiVersion = mModule->common.module_api_version; if (apiVersion < CAMERA_MODULE_API_VERSION_2_0) { - return mModule->get_camera_info(cameraId, info); + int ret; + ATRACE_BEGIN("camera_module->get_camera_info"); + ret = mModule->get_camera_info(cameraId, info); + ATRACE_END(); + return ret; } ssize_t index = mCameraInfoMap.indexOfKey(cameraId); if (index == NAME_NOT_FOUND) { // Get camera info from raw module and cache it camera_info rawInfo, cameraInfo; + ATRACE_BEGIN("camera_module->get_camera_info"); int ret = mModule->get_camera_info(cameraId, &rawInfo); + ATRACE_END(); if (ret != 0) { return ret; } @@ -217,20 +231,36 @@ int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) { } int CameraModule::open(const char* id, struct hw_device_t** device) { - return filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device)); + int res; + ATRACE_BEGIN("camera_module->open"); + res = filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device)); + ATRACE_END(); + return res; } int CameraModule::openLegacy( const char* id, uint32_t halVersion, struct hw_device_t** device) { - return mModule->open_legacy(&mModule->common, id, halVersion, device); + int res; + ATRACE_BEGIN("camera_module->open_legacy"); + res = mModule->open_legacy(&mModule->common, id, halVersion, device); + ATRACE_END(); + return res; } int CameraModule::getNumberOfCameras() { - return mModule->get_number_of_cameras(); + int numCameras; + ATRACE_BEGIN("camera_module->get_number_of_cameras"); + numCameras = mModule->get_number_of_cameras(); + ATRACE_END(); + return numCameras; } int CameraModule::setCallbacks(const camera_module_callbacks_t *callbacks) { - return mModule->set_callbacks(callbacks); + int res; + ATRACE_BEGIN("camera_module->set_callbacks"); + res = mModule->set_callbacks(callbacks); + ATRACE_END(); + return res; } bool CameraModule::isVendorTagDefined() { @@ -239,12 +269,18 @@ bool CameraModule::isVendorTagDefined() { void CameraModule::getVendorTagOps(vendor_tag_ops_t* ops) { if (mModule->get_vendor_tag_ops) { + ATRACE_BEGIN("camera_module->get_vendor_tag_ops"); mModule->get_vendor_tag_ops(ops); + ATRACE_END(); } } int CameraModule::setTorchMode(const char* camera_id, bool enable) { - return mModule->set_torch_mode(camera_id, enable); + int res; + ATRACE_BEGIN("camera_module->set_torch_mode"); + res = mModule->set_torch_mode(camera_id, enable); + ATRACE_END(); + return res; } status_t CameraModule::filterOpenErrorCode(status_t err) { diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp index c9c990c..d74f976 100644 --- a/services/camera/libcameraservice/device2/Camera2Device.cpp +++ b/services/camera/libcameraservice/device2/Camera2Device.cpp @@ -632,6 +632,12 @@ status_t Camera2Device::tearDown(int streamId) { return NO_INIT; } +status_t Camera2Device::prepare(int maxCount, int streamId) { + ATRACE_CALL(); + ALOGE("%s: Camera %d: unimplemented", __FUNCTION__, mId); + return NO_INIT; +} + uint32_t Camera2Device::getDeviceVersion() { ATRACE_CALL(); return mDeviceVersion; diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h index 34c1ded..b4d343c 100644 --- a/services/camera/libcameraservice/device2/Camera2Device.h +++ b/services/camera/libcameraservice/device2/Camera2Device.h @@ -88,6 +88,7 @@ class Camera2Device: public CameraDeviceBase { // Prepare and tearDown are no-ops virtual status_t prepare(int streamId); virtual status_t tearDown(int streamId); + virtual status_t prepare(int maxCount, int streamId); virtual uint32_t getDeviceVersion(); virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const; diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 0c941fb..50d9d75 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -44,6 +44,7 @@ #include <utils/Timers.h> #include "utils/CameraTraces.h" +#include "mediautils/SchedulingPolicyService.h" #include "device3/Camera3Device.h" #include "device3/Camera3OutputStream.h" #include "device3/Camera3InputStream.h" @@ -66,6 +67,7 @@ Camera3Device::Camera3Device(int id): mNextResultFrameNumber(0), mNextReprocessResultFrameNumber(0), mNextShutterFrameNumber(0), + mNextReprocessShutterFrameNumber(0), mListener(NULL) { ATRACE_CALL(); @@ -285,19 +287,27 @@ status_t Camera3Device::disconnect() { mStatusTracker->join(); } + camera3_device_t *hal3Device; { Mutex::Autolock l(mLock); mRequestThread.clear(); mStatusTracker.clear(); - if (mHal3Device != NULL) { - ATRACE_BEGIN("camera3->close"); - mHal3Device->common.close(&mHal3Device->common); - ATRACE_END(); - mHal3Device = NULL; - } + hal3Device = mHal3Device; + } + + // Call close without internal mutex held, as the HAL close may need to + // wait on assorted callbacks,etc, to complete before it can return. + if (hal3Device != NULL) { + ATRACE_BEGIN("camera3->close"); + hal3Device->common.close(&hal3Device->common); + ATRACE_END(); + } + { + Mutex::Autolock l(mLock); + mHal3Device = NULL; internalUpdateStatusLocked(STATUS_UNINITIALIZED); } @@ -557,6 +567,18 @@ status_t Camera3Device::convertMetadataListToRequestListLocked( ALOGV("%s: requestId = %" PRId32, __FUNCTION__, newRequest->mResultExtras.requestId); } + + // Setup batch size if this is a high speed video recording request. + if (mIsConstrainedHighSpeedConfiguration && requestList->size() > 0) { + auto firstRequest = requestList->begin(); + for (auto& outputStream : (*firstRequest)->mOutputStreams) { + if (outputStream->isVideoStream()) { + (*firstRequest)->mBatchSize = requestList->size(); + break; + } + } + } + return OK; } @@ -1398,7 +1420,7 @@ status_t Camera3Device::flush(int64_t *frameNumber) { status_t res; if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) { - res = mHal3Device->ops->flush(mHal3Device); + res = mRequestThread->flush(); } else { Mutex::Autolock l(mLock); res = waitUntilDrainedLocked(); @@ -1408,6 +1430,10 @@ status_t Camera3Device::flush(int64_t *frameNumber) { } status_t Camera3Device::prepare(int streamId) { + return prepare(camera3::Camera3StreamInterface::ALLOCATE_PIPELINE_MAX, streamId); +} + +status_t Camera3Device::prepare(int maxCount, int streamId) { ATRACE_CALL(); ALOGV("%s: Camera %d: Preparing stream %d", __FUNCTION__, mId, streamId); Mutex::Autolock il(mInterfaceLock); @@ -1432,7 +1458,7 @@ status_t Camera3Device::prepare(int streamId) { return BAD_VALUE; } - return mPreparerThread->prepare(stream); + return mPreparerThread->prepare(maxCount, stream); } status_t Camera3Device::tearDown(int streamId) { @@ -1583,6 +1609,7 @@ sp<Camera3Device::CaptureRequest> Camera3Device::createCaptureRequest( newRequest->mOutputStreams.push(stream); } newRequest->mSettings.erase(ANDROID_REQUEST_OUTPUT_STREAMS); + newRequest->mBatchSize = 1; return newRequest; } @@ -1741,6 +1768,21 @@ status_t Camera3Device::configureStreamsLocked() { // across configure_streams() calls mRequestThread->configurationComplete(); + // Boost priority of request thread for high speed recording to SCHED_FIFO + if (mIsConstrainedHighSpeedConfiguration) { + pid_t requestThreadTid = mRequestThread->getTid(); + res = requestPriority(getpid(), requestThreadTid, + kConstrainedHighSpeedThreadPriority, true); + if (res != OK) { + ALOGW("Can't set realtime priority for request processing thread: %s (%d)", + strerror(-res), res); + } else { + ALOGD("Set real time priority for request queue thread (tid %d)", requestThreadTid); + } + } else { + // TODO: Set/restore normal priority for normal use cases + } + // Update device state mNeedConfig = false; @@ -2493,18 +2535,6 @@ void Camera3Device::notifyError(const camera3_error_msg_t &msg, void Camera3Device::notifyShutter(const camera3_shutter_msg_t &msg, NotificationListener *listener) { ssize_t idx; - // Verify ordering of shutter notifications - { - Mutex::Autolock l(mOutputLock); - // TODO: need to track errors for tighter bounds on expected frame number. - if (msg.frame_number < mNextShutterFrameNumber) { - SET_ERR("Shutter notification out-of-order. Expected " - "notification for frame %d, got frame %d", - mNextShutterFrameNumber, msg.frame_number); - return; - } - mNextShutterFrameNumber = msg.frame_number + 1; - } // Set timestamp for the request in the in-flight tracking // and get the request ID to send upstream @@ -2514,6 +2544,29 @@ void Camera3Device::notifyShutter(const camera3_shutter_msg_t &msg, if (idx >= 0) { InFlightRequest &r = mInFlightMap.editValueAt(idx); + // Verify ordering of shutter notifications + { + Mutex::Autolock l(mOutputLock); + // TODO: need to track errors for tighter bounds on expected frame number. + if (r.hasInputBuffer) { + if (msg.frame_number < mNextReprocessShutterFrameNumber) { + SET_ERR("Shutter notification out-of-order. Expected " + "notification for frame %d, got frame %d", + mNextReprocessShutterFrameNumber, msg.frame_number); + return; + } + mNextReprocessShutterFrameNumber = msg.frame_number + 1; + } else { + if (msg.frame_number < mNextShutterFrameNumber) { + SET_ERR("Shutter notification out-of-order. Expected " + "notification for frame %d, got frame %d", + mNextShutterFrameNumber, msg.frame_number); + return; + } + mNextShutterFrameNumber = msg.frame_number + 1; + } + } + ALOGVV("Camera %d: %s: Shutter fired for frame %d (id %d) at %" PRId64, mId, __FUNCTION__, msg.frame_number, r.resultExtras.requestId, msg.timestamp); @@ -2754,6 +2807,17 @@ status_t Camera3Device::RequestThread::clear( return OK; } +status_t Camera3Device::RequestThread::flush() { + ATRACE_CALL(); + Mutex::Autolock l(mFlushLock); + + if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) { + return mHal3Device->ops->flush(mHal3Device); + } + + return -ENOTSUP; +} + void Camera3Device::RequestThread::setPaused(bool paused) { Mutex::Autolock l(mPauseLock); mDoPause = paused; @@ -2844,7 +2908,7 @@ void Camera3Device::overrideResultForPrecaptureCancel( } bool Camera3Device::RequestThread::threadLoop() { - + ATRACE_CALL(); status_t res; // Handle paused state. @@ -2852,203 +2916,240 @@ bool Camera3Device::RequestThread::threadLoop() { return true; } - // Get work to do - - sp<CaptureRequest> nextRequest = waitForNextRequest(); - if (nextRequest == NULL) { + // Wait for the next batch of requests. + waitForNextRequestBatch(); + if (mNextRequests.size() == 0) { return true; } - // Create request to HAL - camera3_capture_request_t request = camera3_capture_request_t(); - request.frame_number = nextRequest->mResultExtras.frameNumber; - Vector<camera3_stream_buffer_t> outputBuffers; - - // Get the request ID, if any - int requestId; - camera_metadata_entry_t requestIdEntry = - nextRequest->mSettings.find(ANDROID_REQUEST_ID); + // Get the latest request ID, if any + int latestRequestId; + camera_metadata_entry_t requestIdEntry = mNextRequests[mNextRequests.size() - 1]. + captureRequest->mSettings.find(ANDROID_REQUEST_ID); if (requestIdEntry.count > 0) { - requestId = requestIdEntry.data.i32[0]; + latestRequestId = requestIdEntry.data.i32[0]; } else { - ALOGW("%s: Did not have android.request.id set in the request", - __FUNCTION__); - requestId = NAME_NOT_FOUND; + ALOGW("%s: Did not have android.request.id set in the request.", __FUNCTION__); + latestRequestId = NAME_NOT_FOUND; } - // Insert any queued triggers (before metadata is locked) - int32_t triggerCount; - res = insertTriggers(nextRequest); - if (res < 0) { - SET_ERR("RequestThread: Unable to insert triggers " - "(capture request %d, HAL device: %s (%d)", - request.frame_number, strerror(-res), res); - cleanUpFailedRequest(request, nextRequest, outputBuffers); + // Prepare a batch of HAL requests and output buffers. + res = prepareHalRequests(); + if (res == TIMED_OUT) { + // Not a fatal error if getting output buffers time out. + cleanUpFailedRequests(/*sendRequestError*/ true); + return true; + } else if (res != OK) { + cleanUpFailedRequests(/*sendRequestError*/ false); return false; } - triggerCount = res; - bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0); + // Inform waitUntilRequestProcessed thread of a new request ID + { + Mutex::Autolock al(mLatestRequestMutex); + + mLatestRequestId = latestRequestId; + mLatestRequestSignal.signal(); + } + + // Submit a batch of requests to HAL. + // Use flush lock only when submitting multilple requests in a batch. + // TODO: The problem with flush lock is flush() will be blocked by process_capture_request() + // which may take a long time to finish so synchronizing flush() and + // process_capture_request() defeats the purpose of cancelling requests ASAP with flush(). + // For now, only synchronize for high speed recording and we should figure something out for + // removing the synchronization. + bool useFlushLock = mNextRequests.size() > 1; + + if (useFlushLock) { + mFlushLock.lock(); + } + + ALOGVV("%s: %d: submitting %d requests in a batch.", __FUNCTION__, __LINE__, + mNextRequests.size()); + for (auto& nextRequest : mNextRequests) { + // Submit request and block until ready for next one + ATRACE_ASYNC_BEGIN("frame capture", nextRequest.halRequest.frame_number); + ATRACE_BEGIN("camera3->process_capture_request"); + res = mHal3Device->ops->process_capture_request(mHal3Device, &nextRequest.halRequest); + ATRACE_END(); - // If the request is the same as last, or we had triggers last time - if (mPrevRequest != nextRequest || triggersMixedIn) { - /** - * HAL workaround: - * Insert a dummy trigger ID if a trigger is set but no trigger ID is - */ - res = addDummyTriggerIds(nextRequest); if (res != OK) { - SET_ERR("RequestThread: Unable to insert dummy trigger IDs " - "(capture request %d, HAL device: %s (%d)", - request.frame_number, strerror(-res), res); - cleanUpFailedRequest(request, nextRequest, outputBuffers); + // Should only get a failure here for malformed requests or device-level + // errors, so consider all errors fatal. Bad metadata failures should + // come through notify. + SET_ERR("RequestThread: Unable to submit capture request %d to HAL" + " device: %s (%d)", nextRequest.halRequest.frame_number, strerror(-res), + res); + cleanUpFailedRequests(/*sendRequestError*/ false); + if (useFlushLock) { + mFlushLock.unlock(); + } return false; } - /** - * The request should be presorted so accesses in HAL - * are O(logn). Sidenote, sorting a sorted metadata is nop. - */ - nextRequest->mSettings.sort(); - request.settings = nextRequest->mSettings.getAndLock(); - mPrevRequest = nextRequest; - ALOGVV("%s: Request settings are NEW", __FUNCTION__); - - IF_ALOGV() { - camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t(); - find_camera_metadata_ro_entry( - request.settings, - ANDROID_CONTROL_AF_TRIGGER, - &e - ); - if (e.count > 0) { - ALOGV("%s: Request (frame num %d) had AF trigger 0x%x", - __FUNCTION__, - request.frame_number, - e.data.u8[0]); - } - } - } else { - // leave request.settings NULL to indicate 'reuse latest given' - ALOGVV("%s: Request settings are REUSED", - __FUNCTION__); - } + // Mark that the request has be submitted successfully. + nextRequest.submitted = true; - uint32_t totalNumBuffers = 0; + // Update the latest request sent to HAL + if (nextRequest.halRequest.settings != NULL) { // Don't update if they were unchanged + Mutex::Autolock al(mLatestRequestMutex); - // Fill in buffers - if (nextRequest->mInputStream != NULL) { - request.input_buffer = &nextRequest->mInputBuffer; - totalNumBuffers += 1; - } else { - request.input_buffer = NULL; - } + camera_metadata_t* cloned = clone_camera_metadata(nextRequest.halRequest.settings); + mLatestRequest.acquire(cloned); + } - outputBuffers.insertAt(camera3_stream_buffer_t(), 0, - nextRequest->mOutputStreams.size()); - request.output_buffers = outputBuffers.array(); - for (size_t i = 0; i < nextRequest->mOutputStreams.size(); i++) { - res = nextRequest->mOutputStreams.editItemAt(i)-> - getBuffer(&outputBuffers.editItemAt(i)); + if (nextRequest.halRequest.settings != NULL) { + nextRequest.captureRequest->mSettings.unlock(nextRequest.halRequest.settings); + } + + // Remove any previously queued triggers (after unlock) + res = removeTriggers(mPrevRequest); if (res != OK) { - // Can't get output buffer from gralloc queue - this could be due to - // abandoned queue or other consumer misbehavior, so not a fatal - // error - ALOGE("RequestThread: Can't get output buffer, skipping request:" - " %s (%d)", strerror(-res), res); - { - Mutex::Autolock l(mRequestLock); - if (mListener != NULL) { - mListener->notifyError( - ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, - nextRequest->mResultExtras); - } + SET_ERR("RequestThread: Unable to remove triggers " + "(capture request %d, HAL device: %s (%d)", + nextRequest.halRequest.frame_number, strerror(-res), res); + cleanUpFailedRequests(/*sendRequestError*/ false); + if (useFlushLock) { + mFlushLock.unlock(); } - cleanUpFailedRequest(request, nextRequest, outputBuffers); - return true; + return false; } - request.num_output_buffers++; } - totalNumBuffers += request.num_output_buffers; - // Log request in the in-flight queue - sp<Camera3Device> parent = mParent.promote(); - if (parent == NULL) { - // Should not happen, and nowhere to send errors to, so just log it - CLOGE("RequestThread: Parent is gone"); - cleanUpFailedRequest(request, nextRequest, outputBuffers); - return false; + if (useFlushLock) { + mFlushLock.unlock(); } - res = parent->registerInFlight(request.frame_number, - totalNumBuffers, nextRequest->mResultExtras, - /*hasInput*/request.input_buffer != NULL, - nextRequest->mAeTriggerCancelOverride); - ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64 - ", burstId = %" PRId32 ".", - __FUNCTION__, - nextRequest->mResultExtras.requestId, nextRequest->mResultExtras.frameNumber, - nextRequest->mResultExtras.burstId); - if (res != OK) { - SET_ERR("RequestThread: Unable to register new in-flight request:" - " %s (%d)", strerror(-res), res); - cleanUpFailedRequest(request, nextRequest, outputBuffers); - return false; + // Unset as current request + { + Mutex::Autolock l(mRequestLock); + mNextRequests.clear(); } - // Inform waitUntilRequestProcessed thread of a new request ID - { - Mutex::Autolock al(mLatestRequestMutex); + return true; +} - mLatestRequestId = requestId; - mLatestRequestSignal.signal(); - } +status_t Camera3Device::RequestThread::prepareHalRequests() { + ATRACE_CALL(); - // Submit request and block until ready for next one - ATRACE_ASYNC_BEGIN("frame capture", request.frame_number); - ATRACE_BEGIN("camera3->process_capture_request"); - res = mHal3Device->ops->process_capture_request(mHal3Device, &request); - ATRACE_END(); + for (auto& nextRequest : mNextRequests) { + sp<CaptureRequest> captureRequest = nextRequest.captureRequest; + camera3_capture_request_t* halRequest = &nextRequest.halRequest; + Vector<camera3_stream_buffer_t>* outputBuffers = &nextRequest.outputBuffers; - if (res != OK) { - // Should only get a failure here for malformed requests or device-level - // errors, so consider all errors fatal. Bad metadata failures should - // come through notify. - SET_ERR("RequestThread: Unable to submit capture request %d to HAL" - " device: %s (%d)", request.frame_number, strerror(-res), res); - cleanUpFailedRequest(request, nextRequest, outputBuffers); - return false; - } + // Prepare a request to HAL + halRequest->frame_number = captureRequest->mResultExtras.frameNumber; - // Update the latest request sent to HAL - if (request.settings != NULL) { // Don't update them if they were unchanged - Mutex::Autolock al(mLatestRequestMutex); + // Insert any queued triggers (before metadata is locked) + status_t res = insertTriggers(captureRequest); - camera_metadata_t* cloned = clone_camera_metadata(request.settings); - mLatestRequest.acquire(cloned); - } + if (res < 0) { + SET_ERR("RequestThread: Unable to insert triggers " + "(capture request %d, HAL device: %s (%d)", + halRequest->frame_number, strerror(-res), res); + return INVALID_OPERATION; + } + int triggerCount = res; + bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0); + mPrevTriggers = triggerCount; - if (request.settings != NULL) { - nextRequest->mSettings.unlock(request.settings); - } + // If the request is the same as last, or we had triggers last time + if (mPrevRequest != captureRequest || triggersMixedIn) { + /** + * HAL workaround: + * Insert a dummy trigger ID if a trigger is set but no trigger ID is + */ + res = addDummyTriggerIds(captureRequest); + if (res != OK) { + SET_ERR("RequestThread: Unable to insert dummy trigger IDs " + "(capture request %d, HAL device: %s (%d)", + halRequest->frame_number, strerror(-res), res); + return INVALID_OPERATION; + } - // Unset as current request - { - Mutex::Autolock l(mRequestLock); - mNextRequest.clear(); - } + /** + * The request should be presorted so accesses in HAL + * are O(logn). Sidenote, sorting a sorted metadata is nop. + */ + captureRequest->mSettings.sort(); + halRequest->settings = captureRequest->mSettings.getAndLock(); + mPrevRequest = captureRequest; + ALOGVV("%s: Request settings are NEW", __FUNCTION__); + + IF_ALOGV() { + camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t(); + find_camera_metadata_ro_entry( + halRequest->settings, + ANDROID_CONTROL_AF_TRIGGER, + &e + ); + if (e.count > 0) { + ALOGV("%s: Request (frame num %d) had AF trigger 0x%x", + __FUNCTION__, + halRequest->frame_number, + e.data.u8[0]); + } + } + } else { + // leave request.settings NULL to indicate 'reuse latest given' + ALOGVV("%s: Request settings are REUSED", + __FUNCTION__); + } - // Remove any previously queued triggers (after unlock) - res = removeTriggers(mPrevRequest); - if (res != OK) { - SET_ERR("RequestThread: Unable to remove triggers " - "(capture request %d, HAL device: %s (%d)", - request.frame_number, strerror(-res), res); - return false; + uint32_t totalNumBuffers = 0; + + // Fill in buffers + if (captureRequest->mInputStream != NULL) { + halRequest->input_buffer = &captureRequest->mInputBuffer; + totalNumBuffers += 1; + } else { + halRequest->input_buffer = NULL; + } + + outputBuffers->insertAt(camera3_stream_buffer_t(), 0, + captureRequest->mOutputStreams.size()); + halRequest->output_buffers = outputBuffers->array(); + for (size_t i = 0; i < captureRequest->mOutputStreams.size(); i++) { + res = captureRequest->mOutputStreams.editItemAt(i)-> + getBuffer(&outputBuffers->editItemAt(i)); + if (res != OK) { + // Can't get output buffer from gralloc queue - this could be due to + // abandoned queue or other consumer misbehavior, so not a fatal + // error + ALOGE("RequestThread: Can't get output buffer, skipping request:" + " %s (%d)", strerror(-res), res); + + return TIMED_OUT; + } + halRequest->num_output_buffers++; + } + totalNumBuffers += halRequest->num_output_buffers; + + // Log request in the in-flight queue + sp<Camera3Device> parent = mParent.promote(); + if (parent == NULL) { + // Should not happen, and nowhere to send errors to, so just log it + CLOGE("RequestThread: Parent is gone"); + return INVALID_OPERATION; + } + res = parent->registerInFlight(halRequest->frame_number, + totalNumBuffers, captureRequest->mResultExtras, + /*hasInput*/halRequest->input_buffer != NULL, + captureRequest->mAeTriggerCancelOverride); + ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64 + ", burstId = %" PRId32 ".", + __FUNCTION__, + captureRequest->mResultExtras.requestId, captureRequest->mResultExtras.frameNumber, + captureRequest->mResultExtras.burstId); + if (res != OK) { + SET_ERR("RequestThread: Unable to register new in-flight request:" + " %s (%d)", strerror(-res), res); + return INVALID_OPERATION; + } } - mPrevTriggers = triggerCount; - return true; + return OK; } CameraMetadata Camera3Device::RequestThread::getLatestRequest() const { @@ -3063,11 +3164,13 @@ bool Camera3Device::RequestThread::isStreamPending( sp<Camera3StreamInterface>& stream) { Mutex::Autolock l(mRequestLock); - if (mNextRequest != nullptr) { - for (const auto& s : mNextRequest->mOutputStreams) { - if (stream == s) return true; + for (const auto& nextRequest : mNextRequests) { + if (!nextRequest.submitted) { + for (const auto& s : nextRequest.captureRequest->mOutputStreams) { + if (stream == s) return true; + } + if (stream == nextRequest.captureRequest->mInputStream) return true; } - if (stream == mNextRequest->mInputStream) return true; } for (const auto& request : mRequestQueue) { @@ -3087,37 +3190,95 @@ bool Camera3Device::RequestThread::isStreamPending( return false; } -void Camera3Device::RequestThread::cleanUpFailedRequest( - camera3_capture_request_t &request, - sp<CaptureRequest> &nextRequest, - Vector<camera3_stream_buffer_t> &outputBuffers) { +void Camera3Device::RequestThread::cleanUpFailedRequests(bool sendRequestError) { + if (mNextRequests.empty()) { + return; + } + + for (auto& nextRequest : mNextRequests) { + // Skip the ones that have been submitted successfully. + if (nextRequest.submitted) { + continue; + } - if (request.settings != NULL) { - nextRequest->mSettings.unlock(request.settings); + sp<CaptureRequest> captureRequest = nextRequest.captureRequest; + camera3_capture_request_t* halRequest = &nextRequest.halRequest; + Vector<camera3_stream_buffer_t>* outputBuffers = &nextRequest.outputBuffers; + + if (halRequest->settings != NULL) { + captureRequest->mSettings.unlock(halRequest->settings); + } + + if (captureRequest->mInputStream != NULL) { + captureRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR; + captureRequest->mInputStream->returnInputBuffer(captureRequest->mInputBuffer); + } + + for (size_t i = 0; i < halRequest->num_output_buffers; i++) { + outputBuffers->editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR; + captureRequest->mOutputStreams.editItemAt(i)->returnBuffer((*outputBuffers)[i], 0); + } + + if (sendRequestError) { + Mutex::Autolock l(mRequestLock); + if (mListener != NULL) { + mListener->notifyError( + ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, + captureRequest->mResultExtras); + } + } } - if (nextRequest->mInputStream != NULL) { - nextRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR; - nextRequest->mInputStream->returnInputBuffer(nextRequest->mInputBuffer); + + Mutex::Autolock l(mRequestLock); + mNextRequests.clear(); +} + +void Camera3Device::RequestThread::waitForNextRequestBatch() { + // Optimized a bit for the simple steady-state case (single repeating + // request), to avoid putting that request in the queue temporarily. + Mutex::Autolock l(mRequestLock); + + assert(mNextRequests.empty()); + + NextRequest nextRequest; + nextRequest.captureRequest = waitForNextRequestLocked(); + if (nextRequest.captureRequest == nullptr) { + return; + } + + nextRequest.halRequest = camera3_capture_request_t(); + nextRequest.submitted = false; + mNextRequests.add(nextRequest); + + // Wait for additional requests + const size_t batchSize = nextRequest.captureRequest->mBatchSize; + + for (size_t i = 1; i < batchSize; i++) { + NextRequest additionalRequest; + additionalRequest.captureRequest = waitForNextRequestLocked(); + if (additionalRequest.captureRequest == nullptr) { + break; + } + + additionalRequest.halRequest = camera3_capture_request_t(); + additionalRequest.submitted = false; + mNextRequests.add(additionalRequest); } - for (size_t i = 0; i < request.num_output_buffers; i++) { - outputBuffers.editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR; - nextRequest->mOutputStreams.editItemAt(i)->returnBuffer( - outputBuffers[i], 0); + + if (mNextRequests.size() < batchSize) { + ALOGE("RequestThread: only get %d out of %d requests. Skipping requests.", + mNextRequests.size(), batchSize); + cleanUpFailedRequests(/*sendRequestError*/true); } - Mutex::Autolock l(mRequestLock); - mNextRequest.clear(); + return; } sp<Camera3Device::CaptureRequest> - Camera3Device::RequestThread::waitForNextRequest() { + Camera3Device::RequestThread::waitForNextRequestLocked() { status_t res; sp<CaptureRequest> nextRequest; - // Optimized a bit for the simple steady-state case (single repeating - // request), to avoid putting that request in the queue temporarily. - Mutex::Autolock l(mRequestLock); - while (mRequestQueue.empty()) { if (!mRepeatingRequests.empty()) { // Always atomically enqueue all requests in a repeating request @@ -3212,8 +3373,6 @@ sp<Camera3Device::CaptureRequest> handleAePrecaptureCancelRequest(nextRequest); - mNextRequest = nextRequest; - return nextRequest; } @@ -3478,12 +3637,12 @@ Camera3Device::PreparerThread::~PreparerThread() { clear(); } -status_t Camera3Device::PreparerThread::prepare(sp<Camera3StreamInterface>& stream) { +status_t Camera3Device::PreparerThread::prepare(int maxCount, sp<Camera3StreamInterface>& stream) { status_t res; Mutex::Autolock l(mLock); - res = stream->startPrepare(); + res = stream->startPrepare(maxCount); if (res == OK) { // No preparation needed, fire listener right off ALOGV("%s: Stream %d already prepared", __FUNCTION__, stream->getId()); diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index 5287058..2cd5af3 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -62,6 +62,7 @@ class Camera3Device : public CameraDeviceBase, private camera3_callback_ops { public: + Camera3Device(int id); virtual ~Camera3Device(); @@ -143,6 +144,8 @@ class Camera3Device : virtual status_t tearDown(int streamId); + virtual status_t prepare(int maxCount, int streamId); + virtual uint32_t getDeviceVersion(); virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const; @@ -158,6 +161,8 @@ class Camera3Device : static const nsecs_t kActiveTimeout = 500000000; // 500 ms static const size_t kInFlightWarnLimit = 20; static const size_t kInFlightWarnLimitHighSpeed = 256; // batch size 32 * pipe depth 8 + // SCHED_FIFO priority for request submission thread in HFR mode + static const int kConstrainedHighSpeedThreadPriority = 1; struct RequestTrigger; // minimal jpeg buffer size: 256KB + blob header @@ -261,6 +266,11 @@ class Camera3Device : // Used to cancel AE precapture trigger for devices doesn't support // CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL AeTriggerCancelOverride_t mAeTriggerCancelOverride; + // The number of requests that should be submitted to HAL at a time. + // For example, if batch size is 8, this request and the following 7 + // requests will be submitted to HAL at a time. The batch size for + // the following 7 requests will be ignored by the request thread. + int mBatchSize; }; typedef List<sp<CaptureRequest> > RequestList; @@ -438,6 +448,11 @@ class Camera3Device : int64_t *lastFrameNumber = NULL); /** + * Flush all pending requests in HAL. + */ + status_t flush(); + + /** * Queue a trigger to be dispatched with the next outgoing * process_capture_request. The settings for that request only * will be temporarily rewritten to add the trigger tag/value. @@ -498,16 +513,30 @@ class Camera3Device : static const nsecs_t kRequestTimeout = 50e6; // 50 ms - // Waits for a request, or returns NULL if times out. - sp<CaptureRequest> waitForNextRequest(); + // Used to prepare a batch of requests. + struct NextRequest { + sp<CaptureRequest> captureRequest; + camera3_capture_request_t halRequest; + Vector<camera3_stream_buffer_t> outputBuffers; + bool submitted; + }; - // Return buffers, etc, for a request that couldn't be fully - // constructed. The buffers will be returned in the ERROR state - // to mark them as not having valid data. - // All arguments will be modified. - void cleanUpFailedRequest(camera3_capture_request_t &request, - sp<CaptureRequest> &nextRequest, - Vector<camera3_stream_buffer_t> &outputBuffers); + // Wait for the next batch of requests and put them in mNextRequests. mNextRequests will + // be empty if it times out. + void waitForNextRequestBatch(); + + // Waits for a request, or returns NULL if times out. Must be called with mRequestLock hold. + sp<CaptureRequest> waitForNextRequestLocked(); + + // Prepare HAL requests and output buffers in mNextRequests. Return TIMED_OUT if getting any + // output buffer timed out. If an error is returned, the caller should clean up the pending + // request batch. + status_t prepareHalRequests(); + + // Return buffers, etc, for requests in mNextRequests that couldn't be fully constructed and + // send request errors if sendRequestError is true. The buffers will be returned in the + // ERROR state to mark them as not having valid data. mNextRequests will be cleared. + void cleanUpFailedRequests(bool sendRequestError); // Pause handling bool waitIfPaused(); @@ -536,10 +565,13 @@ class Camera3Device : Condition mRequestSignal; RequestList mRequestQueue; RequestList mRepeatingRequests; - // The next request being prepped for submission to the HAL, no longer + // The next batch of requests being prepped for submission to the HAL, no longer // on the request queue. Read-only even with mRequestLock held, outside // of threadLoop - sp<const CaptureRequest> mNextRequest; + Vector<NextRequest> mNextRequests; + + // To protect flush() and sending a request batch to HAL. + Mutex mFlushLock; bool mReconfigured; @@ -698,10 +730,11 @@ class Camera3Device : void setNotificationListener(NotificationListener *listener); /** - * Queue up a stream to be prepared. Streams are processed by - * a background thread in FIFO order + * Queue up a stream to be prepared. Streams are processed by a background thread in FIFO + * order. Pre-allocate up to maxCount buffers for the stream, or the maximum number needed + * for the pipeline if maxCount is ALLOCATE_PIPELINE_MAX. */ - status_t prepare(sp<camera3::Camera3StreamInterface>& stream); + status_t prepare(int maxCount, sp<camera3::Camera3StreamInterface>& stream); /** * Cancel all current and pending stream preparation @@ -738,7 +771,10 @@ class Camera3Device : uint32_t mNextResultFrameNumber; // the minimal frame number of the next reprocess result uint32_t mNextReprocessResultFrameNumber; + // the minimal frame number of the next non-reprocess shutter uint32_t mNextShutterFrameNumber; + // the minimal frame number of the next reprocess shutter + uint32_t mNextReprocessShutterFrameNumber; List<CaptureResult> mResultQueue; Condition mResultSignal; NotificationListener *mListener; diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp index ecb8ac8..1d9d04f 100644 --- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp @@ -92,6 +92,10 @@ status_t Camera3DummyStream::getEndpointUsage(uint32_t *usage) const { return OK; } +bool Camera3DummyStream::isVideoStream() const { + return false; +} + }; // namespace camera3 }; // namespace android diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h index 3a3dbf4..97c0c96 100644 --- a/services/camera/libcameraservice/device3/Camera3DummyStream.h +++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h @@ -54,6 +54,11 @@ class Camera3DummyStream : status_t setTransform(int transform); + /** + * Return if this output stream is for video encoding. + */ + bool isVideoStream() const; + protected: /** diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp index 8c611d5..3f0a736 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp @@ -426,6 +426,17 @@ status_t Camera3OutputStream::getEndpointUsage(uint32_t *usage) const { return res; } +bool Camera3OutputStream::isVideoStream() const { + uint32_t usage = 0; + status_t res = getEndpointUsage(&usage); + if (res != OK) { + ALOGE("%s: getting end point usage failed: %s (%d).", __FUNCTION__, strerror(-res), res); + return false; + } + + return (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) != 0; +} + }; // namespace camera3 }; // namespace android diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h index 941d693..3c083ec 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputStream.h +++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h @@ -64,6 +64,11 @@ class Camera3OutputStream : */ status_t setTransform(int transform); + /** + * Return if this output stream is for video encoding. + */ + bool isVideoStream() const; + protected: Camera3OutputStream(int id, camera3_stream_type_t type, uint32_t width, uint32_t height, int format, diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h index aae72cf..df89b34 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h +++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h @@ -34,6 +34,11 @@ class Camera3OutputStreamInterface : public virtual Camera3StreamInterface { * HAL_TRANSFORM_* / NATIVE_WINDOW_TRANSFORM_* constants. */ virtual status_t setTransform(int transform) = 0; + + /** + * Return if this output stream is for video encoding. + */ + virtual bool isVideoStream() const = 0; }; } // namespace camera3 diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp index 2527fd6..96299b3 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp @@ -53,7 +53,8 @@ Camera3Stream::Camera3Stream(int id, mName(String8::format("Camera3Stream[%d]", id)), mMaxSize(maxSize), mState(STATE_CONSTRUCTED), - mStatusId(StatusTracker::NO_STATUS_ID) { + mStatusId(StatusTracker::NO_STATUS_ID), + mLastMaxCount(Camera3StreamInterface::ALLOCATE_PIPELINE_MAX) { camera3_stream::stream_type = type; camera3_stream::width = width; @@ -252,12 +253,18 @@ bool Camera3Stream::isUnpreparable() { return mStreamUnpreparable; } -status_t Camera3Stream::startPrepare() { +status_t Camera3Stream::startPrepare(int maxCount) { ATRACE_CALL(); Mutex::Autolock l(mLock); status_t res = OK; + if (maxCount < 0) { + ALOGE("%s: Stream %d: Can't prepare stream if max buffer count (%d) is < 0", + __FUNCTION__, mId, maxCount); + return BAD_VALUE; + } + // This function should be only called when the stream is configured already. if (mState != STATE_CONFIGURED) { ALOGE("%s: Stream %d: Can't prepare stream if stream is not in CONFIGURED " @@ -279,9 +286,19 @@ status_t Camera3Stream::startPrepare() { return INVALID_OPERATION; } + + + size_t pipelineMax = getBufferCountLocked(); + size_t clampedCount = (pipelineMax < static_cast<size_t>(maxCount)) ? + pipelineMax : static_cast<size_t>(maxCount); + size_t bufferCount = (maxCount == Camera3StreamInterface::ALLOCATE_PIPELINE_MAX) ? + pipelineMax : clampedCount; + + mPrepared = bufferCount <= mLastMaxCount; + if (mPrepared) return OK; - size_t bufferCount = getBufferCountLocked(); + mLastMaxCount = bufferCount; mPreparedBuffers.insertAt(camera3_stream_buffer_t(), /*index*/0, bufferCount); mPreparedBufferIdx = 0; @@ -438,8 +455,9 @@ status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer) { res = mOutputBufferReturnedSignal.waitRelative(mLock, kWaitForBufferDuration); if (res != OK) { if (res == TIMED_OUT) { - ALOGE("%s: wait for output buffer return timed out after %lldms", __FUNCTION__, - kWaitForBufferDuration / 1000000LL); + ALOGE("%s: wait for output buffer return timed out after %lldms (max_buffers %d)", + __FUNCTION__, kWaitForBufferDuration / 1000000LL, + camera3_stream::max_buffers); } return res; } @@ -469,9 +487,12 @@ status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer, status_t res = returnBufferLocked(buffer, timestamp); if (res == OK) { fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/true); - mOutputBufferReturnedSignal.signal(); } + // Even if returning the buffer failed, we still want to signal whoever is waiting for the + // buffer to be returned. + mOutputBufferReturnedSignal.signal(); + return res; } diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h index bab2177..753280b 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.h +++ b/services/camera/libcameraservice/device3/Camera3Stream.h @@ -188,7 +188,9 @@ class Camera3Stream : /** * Start stream preparation. May only be called in the CONFIGURED state, - * when no valid buffers have yet been returned to this stream. + * when no valid buffers have yet been returned to this stream. Prepares + * up to maxCount buffers, or the maximum number of buffers needed by the + * pipeline if maxCount is ALLOCATE_PIPELINE_MAX. * * If no prepartion is necessary, returns OK and does not transition to * PREPARING state. Otherwise, returns NOT_ENOUGH_DATA and transitions @@ -204,7 +206,7 @@ class Camera3Stream : * INVALID_OPERATION if called when not in CONFIGURED state, or a * valid buffer has already been returned to this stream. */ - status_t startPrepare(); + status_t startPrepare(int maxCount); /** * Check if the stream is mid-preparing. @@ -444,6 +446,9 @@ class Camera3Stream : Vector<camera3_stream_buffer_t> mPreparedBuffers; size_t mPreparedBufferIdx; + // Number of buffers allocated on last prepare call. + int mLastMaxCount; + }; // class Camera3Stream }; // namespace camera3 diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h index c086eaf..54009ae 100644 --- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h +++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h @@ -34,6 +34,11 @@ class StatusTracker; */ class Camera3StreamInterface : public virtual RefBase { public: + + enum { + ALLOCATE_PIPELINE_MAX = 0, // Allocate max buffers used by a given surface + }; + /** * Get the stream's ID */ @@ -98,7 +103,9 @@ class Camera3StreamInterface : public virtual RefBase { /** * Start stream preparation. May only be called in the CONFIGURED state, - * when no valid buffers have yet been returned to this stream. + * when no valid buffers have yet been returned to this stream. Prepares + * up to maxCount buffers, or the maximum number of buffers needed by the + * pipeline if maxCount is ALLOCATE_PIPELINE_MAX. * * If no prepartion is necessary, returns OK and does not transition to * PREPARING state. Otherwise, returns NOT_ENOUGH_DATA and transitions @@ -112,7 +119,7 @@ class Camera3StreamInterface : public virtual RefBase { * INVALID_OPERATION if called when not in CONFIGURED state, or a * valid buffer has already been returned to this stream. */ - virtual status_t startPrepare() = 0; + virtual status_t startPrepare(int maxCount) = 0; /** * Check if the stream is mid-preparing. diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp index e54cc5a..4790754 100644 --- a/services/mediaresourcemanager/ResourceManagerService.cpp +++ b/services/mediaresourcemanager/ResourceManagerService.cpp @@ -96,6 +96,15 @@ status_t ResourceManagerService::dump(int fd, const Vector<String16>& /* args */ const size_t SIZE = 256; char buffer[SIZE]; + if (checkCallingPermission(String16("android.permission.DUMP")) == false) { + result.format("Permission Denial: " + "can't dump ResourceManagerService from pid=%d, uid=%d\n", + IPCThreadState::self()->getCallingPid(), + IPCThreadState::self()->getCallingUid()); + write(fd, result.string(), result.size()); + return PERMISSION_DENIED; + } + snprintf(buffer, SIZE, "ResourceManagerService: %p\n", this); result.append(buffer); result.append(" Policies:\n"); |