diff options
15 files changed, 503 insertions, 114 deletions
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index a7eec57..ff8cc3e 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -15,6 +15,7 @@ */ #define LOG_TAG "SoftAAC2" +//#define LOG_NDEBUG 0 #include <utils/Log.h> #include "SoftAAC2.h" @@ -26,8 +27,13 @@ #define FILEREAD_MAX_LAYERS 2 -#define DRC_DEFAULT_REF_LEVEL 108 /* 108*0.25dB = -27 dB below full scale (typical for movies) */ -#define MAX_CHANNEL_COUNT 6 /* maximum number of audio channels that can be decoded */ +#define DRC_DEFAULT_MOBILE_REF_LEVEL 48 /* 48*-0.25dB = -12 dB below full scale for mobile conf */ +#define DRC_DEFAULT_MOBILE_DRC_CUT 127 /* maximum compression of dynamic range for mobile conf */ +#define MAX_CHANNEL_COUNT 6 /* maximum number of audio channels that can be decoded */ +// names of properties that can be used to override the default DRC settings +#define PROP_DRC_OVERRIDE_REF_LEVEL "aac_drc_reference_level" +#define PROP_DRC_OVERRIDE_CUT "aac_drc_cut" +#define PROP_DRC_OVERRIDE_BOOST "aac_drc_boost" namespace android { @@ -113,9 +119,35 @@ status_t SoftAAC2::initDecoder() { } } mIsFirst = true; - // the decoder will bypass all DRC processing during decode unless any of the DRC parameters - // is set, so here we just reset the DRC reference level to its default value. - aacDecoder_SetParam(mAACDecoder, AAC_DRC_REFERENCE_LEVEL, DRC_DEFAULT_REF_LEVEL); + + // for streams that contain metadata, use the mobile profile DRC settings unless overridden + // by platform properties: + char value[PROPERTY_VALUE_MAX]; + // * AAC_DRC_REFERENCE_LEVEL + if (property_get(PROP_DRC_OVERRIDE_REF_LEVEL, value, NULL)) { + unsigned refLevel = atoi(value); + ALOGV("AAC decoder using AAC_DRC_REFERENCE_LEVEL of %d instead of %d", + refLevel, DRC_DEFAULT_MOBILE_REF_LEVEL); + aacDecoder_SetParam(mAACDecoder, AAC_DRC_REFERENCE_LEVEL, refLevel); + } else { + aacDecoder_SetParam(mAACDecoder, AAC_DRC_REFERENCE_LEVEL, DRC_DEFAULT_MOBILE_REF_LEVEL); + } + // * AAC_DRC_ATTENUATION_FACTOR + if (property_get(PROP_DRC_OVERRIDE_CUT, value, NULL)) { + unsigned cut = atoi(value); + ALOGV("AAC decoder using AAC_DRC_ATTENUATION_FACTOR of %d instead of %d", + cut, DRC_DEFAULT_MOBILE_DRC_CUT); + aacDecoder_SetParam(mAACDecoder, AAC_DRC_ATTENUATION_FACTOR, cut); + } else { + aacDecoder_SetParam(mAACDecoder, AAC_DRC_ATTENUATION_FACTOR, DRC_DEFAULT_MOBILE_DRC_CUT); + } + // * AAC_DRC_BOOST_FACTOR (note: no default, using cut) + if (property_get(PROP_DRC_OVERRIDE_BOOST, value, NULL)) { + unsigned boost = atoi(value); + ALOGV("AAC decoder using AAC_DRC_BOOST_FACTOR of %d", boost); + aacDecoder_SetParam(mAACDecoder, AAC_DRC_BOOST_FACTOR, boost); + } + return status; } diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index d988356..27c7bf4 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -592,6 +592,8 @@ bool ATSParser::Stream::isAudio() const { void ATSParser::Stream::signalDiscontinuity( DiscontinuityType type, const sp<AMessage> &extra) { + mExpectedContinuityCounter = -1; + if (mQueue == NULL) { return; } diff --git a/media/libstagefright/wifi-display/source/Converter.cpp b/media/libstagefright/wifi-display/source/Converter.cpp index 60cca69..6f336c7 100644 --- a/media/libstagefright/wifi-display/source/Converter.cpp +++ b/media/libstagefright/wifi-display/source/Converter.cpp @@ -44,7 +44,12 @@ Converter::Converter( mCodecLooper(codecLooper), mInputFormat(format), mIsVideo(false), - mDoMoreWorkPending(false) { + mDoMoreWorkPending(false) +#if ENABLE_SILENCE_DETECTION + ,mFirstSilentFrameUs(-1ll) + ,mInSilentMode(false) +#endif + { AString mime; CHECK(mInputFormat->findString("mime", &mime)); @@ -132,9 +137,9 @@ status_t Converter::initEncoder() { mOutputFormat->setInt32("bitrate", audioBitrate); } else { mOutputFormat->setInt32("bitrate", videoBitrate); - mOutputFormat->setInt32("frame-rate", 60); + mOutputFormat->setInt32("frame-rate", 30); mOutputFormat->setInt32("i-frame-interval", 1); // Iframes every 1 secs - // mOutputFormat->setInt32("prepend-sps-pps-to-idr-frames", 1); + mOutputFormat->setInt32("prepend-sps-pps-to-idr-frames", 1); } ALOGV("output format is '%s'", mOutputFormat->debugString(0).c_str()); @@ -171,6 +176,20 @@ void Converter::notifyError(status_t err) { notify->post(); } +// static +bool Converter::IsSilence(const sp<ABuffer> &accessUnit) { + const uint8_t *ptr = accessUnit->data(); + const uint8_t *end = ptr + accessUnit->size(); + while (ptr < end) { + if (*ptr != 0) { + return false; + } + ++ptr; + } + + return true; +} + void Converter::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatMediaPullerNotify: @@ -220,6 +239,30 @@ void Converter::onMessageReceived(const sp<AMessage> &msg) { } #endif +#if ENABLE_SILENCE_DETECTION + if (!mIsVideo) { + if (IsSilence(accessUnit)) { + if (!mInSilentMode) { + int64_t nowUs = ALooper::GetNowUs(); + + if (mFirstSilentFrameUs < 0ll) { + mFirstSilentFrameUs = nowUs; + } else if (nowUs >= mFirstSilentFrameUs + 1000000ll) { + mInSilentMode = true; + ALOGI("audio in silent mode now."); + break; + } + } + } else { + if (mInSilentMode) { + ALOGI("audio no longer in silent mode."); + } + mInSilentMode = false; + mFirstSilentFrameUs = -1ll; + } + } +#endif + mInputBufferQueue.push_back(accessUnit); feedEncoderInputBuffers(); @@ -283,7 +326,7 @@ void Converter::scheduleDoMoreWork() { } mDoMoreWorkPending = true; - (new AMessage(kWhatDoMoreWork, id()))->post(1000ll); + (new AMessage(kWhatDoMoreWork, id()))->post(mIsVideo ? 10000ll : 5000ll); } status_t Converter::feedEncoderInputBuffers() { @@ -338,14 +381,21 @@ status_t Converter::doMoreWork() { feedEncoderInputBuffers(); } - size_t offset; - size_t size; - int64_t timeUs; - uint32_t flags; - err = mEncoder->dequeueOutputBuffer( - &bufferIndex, &offset, &size, &timeUs, &flags); + for (;;) { + size_t offset; + size_t size; + int64_t timeUs; + uint32_t flags; + err = mEncoder->dequeueOutputBuffer( + &bufferIndex, &offset, &size, &timeUs, &flags); + + if (err != OK) { + if (err == -EAGAIN) { + err = OK; + } + break; + } - if (err == OK) { if (flags & MediaCodec::BUFFER_FLAG_EOS) { sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatEOS); @@ -354,6 +404,10 @@ status_t Converter::doMoreWork() { sp<ABuffer> buffer = new ABuffer(size); buffer->meta()->setInt64("timeUs", timeUs); + if (!mIsVideo) { + ALOGV("audio time %lld us (%.2f secs)", timeUs, timeUs / 1E6); + } + memcpy(buffer->data(), mEncoderOutputBuffers.itemAt(bufferIndex)->base() + offset, size); @@ -368,9 +422,11 @@ status_t Converter::doMoreWork() { } } - err = mEncoder->releaseOutputBuffer(bufferIndex); - } else if (err == -EAGAIN) { - err = OK; + mEncoder->releaseOutputBuffer(bufferIndex); + + if (flags & MediaCodec::BUFFER_FLAG_EOS) { + break; + } } return err; diff --git a/media/libstagefright/wifi-display/source/Converter.h b/media/libstagefright/wifi-display/source/Converter.h index 9f54523..93ff72f 100644 --- a/media/libstagefright/wifi-display/source/Converter.h +++ b/media/libstagefright/wifi-display/source/Converter.h @@ -25,6 +25,8 @@ namespace android { struct ABuffer; struct MediaCodec; +#define ENABLE_SILENCE_DETECTION 1 + // Utility class that receives media access units and converts them into // media access unit of a different format. // Right now this'll convert raw video into H.264 and raw audio into AAC. @@ -83,6 +85,11 @@ private: bool mDoMoreWorkPending; +#if ENABLE_SILENCE_DETECTION + int64_t mFirstSilentFrameUs; + bool mInSilentMode; +#endif + status_t initEncoder(); status_t feedEncoderInputBuffers(); @@ -92,6 +99,8 @@ private: void notifyError(status_t err); + static bool IsSilence(const sp<ABuffer> &accessUnit); + DISALLOW_EVIL_CONSTRUCTORS(Converter); }; diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp index 7de607c..c91b4c8 100644 --- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp +++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp @@ -64,6 +64,8 @@ struct WifiDisplaySource::PlaybackSession::Track : public AHandler { const sp<MediaPuller> &mediaPuller, const sp<Converter> &converter); + void setRepeaterSource(const sp<RepeaterSource> &source); + sp<AMessage> getFormat(); bool isAudio() const; @@ -78,6 +80,8 @@ struct WifiDisplaySource::PlaybackSession::Track : public AHandler { void queueAccessUnit(const sp<ABuffer> &accessUnit); sp<ABuffer> dequeueAccessUnit(); + void requestIDRFrame(); + protected: virtual void onMessageReceived(const sp<AMessage> &msg); virtual ~Track(); @@ -96,6 +100,7 @@ private: ssize_t mPacketizerTrackIndex; bool mIsAudio; List<sp<ABuffer> > mQueuedAccessUnits; + sp<RepeaterSource> mRepeaterSource; static bool IsAudioFormat(const sp<AMessage> &format); @@ -178,6 +183,11 @@ void WifiDisplaySource::PlaybackSession::Track::stopAsync() { sp<AMessage> msg = new AMessage(kWhatMediaPullerStopped, id()); if (mStarted && mMediaPuller != NULL) { + if (mRepeaterSource != NULL) { + // Let's unblock MediaPuller's MediaSource::read(). + mRepeaterSource->wakeUp(); + } + mMediaPuller->stopAsync(msg); } else { msg->post(); @@ -224,6 +234,23 @@ sp<ABuffer> WifiDisplaySource::PlaybackSession::Track::dequeueAccessUnit() { return accessUnit; } +void WifiDisplaySource::PlaybackSession::Track::setRepeaterSource( + const sp<RepeaterSource> &source) { + mRepeaterSource = source; +} + +void WifiDisplaySource::PlaybackSession::Track::requestIDRFrame() { + if (mIsAudio) { + return; + } + + if (mRepeaterSource != NULL) { + mRepeaterSource->wakeUp(); + } + + mConverter->requestIDRFrame(); +} + //////////////////////////////////////////////////////////////////////////////// WifiDisplaySource::PlaybackSession::PlaybackSession( @@ -264,8 +291,10 @@ WifiDisplaySource::PlaybackSession::PlaybackSession( mNumRTPSent(0), mNumRTPOctetsSent(0), mNumSRsSent(0), - mSendSRPending(false), - mHistoryLength(0) + mSendSRPending(false) +#if ENABLE_RETRANSMISSION + ,mHistoryLength(0) +#endif #if TRACK_BANDWIDTH ,mFirstPacketTimeUs(-1ll) ,mTotalBytesSent(0ll) @@ -807,7 +836,8 @@ status_t WifiDisplaySource::PlaybackSession::setupPacketizer() { } status_t WifiDisplaySource::PlaybackSession::addSource( - bool isVideo, const sp<MediaSource> &source, size_t *numInputBuffers) { + bool isVideo, const sp<MediaSource> &source, bool isRepeaterSource, + size_t *numInputBuffers) { sp<ALooper> pullLooper = new ALooper; pullLooper->setName("pull_looper"); @@ -869,6 +899,10 @@ status_t WifiDisplaySource::PlaybackSession::addSource( sp<Track> track = new Track( notify, pullLooper, codecLooper, puller, converter); + if (isRepeaterSource) { + track->setRepeaterSource(static_cast<RepeaterSource *>(source.get())); + } + looper()->registerHandler(track); mTracks.add(trackIndex, track); @@ -885,8 +919,13 @@ status_t WifiDisplaySource::PlaybackSession::addVideoSource() { source->setUseAbsoluteTimestamps(); + sp<RepeaterSource> videoSource = + new RepeaterSource(source, 30.0 /* rateHz */); + size_t numInputBuffers; - status_t err = addSource(true /* isVideo */, source, &numInputBuffers); + status_t err = addSource( + true /* isVideo */, videoSource, true /* isRepeaterSource */, + &numInputBuffers); if (err != OK) { return err; @@ -908,7 +947,8 @@ status_t WifiDisplaySource::PlaybackSession::addAudioSource() { if (audioSource->initCheck() == OK) { return addSource( - false /* isVideo */, audioSource, NULL /* numInputBuffers */); + false /* isVideo */, audioSource, false /* isRepeaterSource */, + NULL /* numInputBuffers */); } ALOGW("Unable to instantiate audio source"); @@ -1126,7 +1166,9 @@ ssize_t WifiDisplaySource::PlaybackSession::appendTSData( #endif } +#if ENABLE_RETRANSMISSION mTSQueue->setInt32Data(mRTPSeqNo - 1); + mHistory.push_back(mTSQueue); ++mHistoryLength; @@ -1138,6 +1180,7 @@ ssize_t WifiDisplaySource::PlaybackSession::appendTSData( } else { mTSQueue = new ABuffer(12 + kMaxNumTSPacketsPerRTPPacket * 188); } +#endif mTSQueue->setRange(0, 12); } @@ -1295,7 +1338,7 @@ void WifiDisplaySource::PlaybackSession::requestIDRFrame() { for (size_t i = 0; i < mTracks.size(); ++i) { const sp<Track> &track = mTracks.valueAt(i); - track->converter()->requestIDRFrame(); + track->requestIDRFrame(); } } @@ -1321,7 +1364,7 @@ bool WifiDisplaySource::PlaybackSession::allTracksHavePacketizerIndex() { } status_t WifiDisplaySource::PlaybackSession::packetizeAccessUnit( - size_t trackIndex, sp<ABuffer> accessUnit) { + size_t trackIndex, const sp<ABuffer> &accessUnit) { const sp<Track> &track = mTracks.valueFor(trackIndex); uint32_t flags = 0; @@ -1332,12 +1375,6 @@ status_t WifiDisplaySource::PlaybackSession::packetizeAccessUnit( if (mHDCP != NULL && !track->isAudio()) { isHDCPEncrypted = true; - if (IsIDR(accessUnit)) { - // XXX remove this once the encoder takes care of this. - accessUnit = mPacketizer->prependCSD( - track->packetizerTrackIndex(), accessUnit); - } - status_t err = mHDCP->encrypt( accessUnit->data(), accessUnit->size(), trackIndex /* streamCTR */, diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.h b/media/libstagefright/wifi-display/source/PlaybackSession.h index 8d88648..5d4bde8 100644 --- a/media/libstagefright/wifi-display/source/PlaybackSession.h +++ b/media/libstagefright/wifi-display/source/PlaybackSession.h @@ -161,8 +161,10 @@ private: bool mSendSRPending; +#if ENABLE_RETRANSMISSION List<sp<ABuffer> > mHistory; size_t mHistoryLength; +#endif #if TRACK_BANDWIDTH int64_t mFirstPacketTimeUs; @@ -183,6 +185,7 @@ private: status_t addSource( bool isVideo, const sp<MediaSource> &source, + bool isRepeaterSource, size_t *numInputBuffers); status_t addVideoSource(); @@ -206,7 +209,7 @@ private: bool allTracksHavePacketizerIndex(); status_t packetizeAccessUnit( - size_t trackIndex, sp<ABuffer> accessUnit); + size_t trackIndex, const sp<ABuffer> &accessUnit); status_t packetizeQueuedAccessUnits(); diff --git a/media/libstagefright/wifi-display/source/RepeaterSource.cpp b/media/libstagefright/wifi-display/source/RepeaterSource.cpp index dc216e8..641e63f 100644 --- a/media/libstagefright/wifi-display/source/RepeaterSource.cpp +++ b/media/libstagefright/wifi-display/source/RepeaterSource.cpp @@ -18,6 +18,7 @@ RepeaterSource::RepeaterSource(const sp<MediaSource> &source, double rateHz) mRateHz(rateHz), mBuffer(NULL), mResult(OK), + mLastBufferUpdateUs(-1ll), mStartTimeUs(-1ll), mFrameCount(0) { } @@ -91,38 +92,59 @@ status_t RepeaterSource::read( ReadOptions::SeekMode seekMode; CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &seekMode)); - int64_t bufferTimeUs = -1ll; + for (;;) { + int64_t bufferTimeUs = -1ll; - if (mStartTimeUs < 0ll) { - Mutex::Autolock autoLock(mLock); - while (mBuffer == NULL && mResult == OK) { - mCondition.wait(mLock); - } + if (mStartTimeUs < 0ll) { + Mutex::Autolock autoLock(mLock); + while ((mLastBufferUpdateUs < 0ll || mBuffer == NULL) + && mResult == OK) { + mCondition.wait(mLock); + } - mStartTimeUs = ALooper::GetNowUs(); - bufferTimeUs = mStartTimeUs; - } else { - bufferTimeUs = mStartTimeUs + (mFrameCount * 1000000ll) / mRateHz; + ALOGV("now resuming."); + mStartTimeUs = ALooper::GetNowUs(); + bufferTimeUs = mStartTimeUs; + } else { + bufferTimeUs = mStartTimeUs + (mFrameCount * 1000000ll) / mRateHz; - int64_t nowUs = ALooper::GetNowUs(); - int64_t delayUs = bufferTimeUs - nowUs; + int64_t nowUs = ALooper::GetNowUs(); + int64_t delayUs = bufferTimeUs - nowUs; - if (delayUs > 0ll) { - usleep(delayUs); + if (delayUs > 0ll) { + usleep(delayUs); + } } - } - Mutex::Autolock autoLock(mLock); - if (mResult != OK) { - CHECK(mBuffer == NULL); - return mResult; - } + bool stale = false; - mBuffer->add_ref(); - *buffer = mBuffer; - (*buffer)->meta_data()->setInt64(kKeyTime, bufferTimeUs); + { + Mutex::Autolock autoLock(mLock); + if (mResult != OK) { + CHECK(mBuffer == NULL); + return mResult; + } - ++mFrameCount; + int64_t nowUs = ALooper::GetNowUs(); + if (nowUs - mLastBufferUpdateUs > 1000000ll) { + mLastBufferUpdateUs = -1ll; + stale = true; + } else { + mBuffer->add_ref(); + *buffer = mBuffer; + (*buffer)->meta_data()->setInt64(kKeyTime, bufferTimeUs); + ++mFrameCount; + } + } + + if (!stale) { + break; + } + + mStartTimeUs = -1ll; + mFrameCount = 0; + ALOGV("now dormant"); + } return OK; } @@ -147,6 +169,7 @@ void RepeaterSource::onMessageReceived(const sp<AMessage> &msg) { } mBuffer = buffer; mResult = err; + mLastBufferUpdateUs = ALooper::GetNowUs(); mCondition.broadcast(); @@ -161,4 +184,13 @@ void RepeaterSource::onMessageReceived(const sp<AMessage> &msg) { } } +void RepeaterSource::wakeUp() { + ALOGV("wakeUp"); + Mutex::Autolock autoLock(mLock); + if (mLastBufferUpdateUs < 0ll && mBuffer != NULL) { + mLastBufferUpdateUs = ALooper::GetNowUs(); + mCondition.broadcast(); + } +} + } // namespace android diff --git a/media/libstagefright/wifi-display/source/RepeaterSource.h b/media/libstagefright/wifi-display/source/RepeaterSource.h index 3049362..e4aa2b6 100644 --- a/media/libstagefright/wifi-display/source/RepeaterSource.h +++ b/media/libstagefright/wifi-display/source/RepeaterSource.h @@ -22,6 +22,10 @@ struct RepeaterSource : public MediaSource { void onMessageReceived(const sp<AMessage> &msg); + // If RepeaterSource is currently dormant, because SurfaceFlinger didn't + // send updates in a while, this is its wakeup call. + void wakeUp(); + protected: virtual ~RepeaterSource(); @@ -43,6 +47,7 @@ private: MediaBuffer *mBuffer; status_t mResult; + int64_t mLastBufferUpdateUs; int64_t mStartTimeUs; int32_t mFrameCount; diff --git a/media/libstagefright/wifi-display/source/TSPacketizer.cpp b/media/libstagefright/wifi-display/source/TSPacketizer.cpp index dd18998..e5abd57 100644 --- a/media/libstagefright/wifi-display/source/TSPacketizer.cpp +++ b/media/libstagefright/wifi-display/source/TSPacketizer.cpp @@ -294,12 +294,11 @@ status_t TSPacketizer::packetize( const sp<Track> &track = mTracks.itemAt(trackIndex); - if (track->isH264() && !(flags & IS_ENCRYPTED)) { - if (IsIDR(accessUnit)) { - // prepend codec specific data, i.e. SPS and PPS. - accessUnit = track->prependCSD(accessUnit); - } - } else if (track->lacksADTSHeader()) { + if (track->isH264() && (flags & PREPEND_SPS_PPS_TO_IDR_FRAMES) + && IsIDR(accessUnit)) { + // prepend codec specific data, i.e. SPS and PPS. + accessUnit = track->prependCSD(accessUnit); + } else if (track->isAudio() && track->lacksADTSHeader()) { CHECK(!(flags & IS_ENCRYPTED)); accessUnit = track->prependADTSHeader(accessUnit); } diff --git a/media/libstagefright/wifi-display/source/TSPacketizer.h b/media/libstagefright/wifi-display/source/TSPacketizer.h index 01f174a..0733c06 100644 --- a/media/libstagefright/wifi-display/source/TSPacketizer.h +++ b/media/libstagefright/wifi-display/source/TSPacketizer.h @@ -38,9 +38,10 @@ struct TSPacketizer : public RefBase { ssize_t addTrack(const sp<AMessage> &format); enum { - EMIT_PAT_AND_PMT = 1, - EMIT_PCR = 2, - IS_ENCRYPTED = 4, + EMIT_PAT_AND_PMT = 1, + EMIT_PCR = 2, + IS_ENCRYPTED = 4, + PREPEND_SPS_PPS_TO_IDR_FRAMES = 8, }; status_t packetize( size_t trackIndex, const sp<ABuffer> &accessUnit, diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp index 1083a80..b0aaf3b 100644 --- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp +++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp @@ -539,7 +539,7 @@ status_t WifiDisplaySource::sendM4(int32_t sessionID) { // use "78 00 02 02 00008000 00000000 00000000 00 0000 0000 00 none none\r\n" AString body = StringPrintf( "wfd_video_formats: " - "30 00 02 02 00000040 00000000 00000000 00 0000 0000 00 none none\r\n" + "28 00 02 02 00000020 00000000 00000000 00 0000 0000 00 none none\r\n" "wfd_audio_codecs: AAC 00000001 00\r\n" // 2 ch AAC 48kHz "wfd_presentation_URL: rtsp://%s/wfd1.0/streamid=0 none\r\n" "wfd_client_rtp_ports: RTP/AVP/%s;unicast 19000 0 mode=play\r\n", diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp index 33e0b56..1c650f6 100644 --- a/services/camera/libcameraservice/Camera2Client.cpp +++ b/services/camera/libcameraservice/Camera2Client.cpp @@ -913,6 +913,7 @@ void Camera2Client::releaseRecordingFrame(const sp<IMemory>& mem) { status_t Camera2Client::autoFocus() { ATRACE_CALL(); Mutex::Autolock icl(mICameraLock); + ALOGV("%s: Camera %d", __FUNCTION__, mCameraId); status_t res; if ( (res = checkPid(__FUNCTION__) ) != OK) return res; @@ -931,6 +932,7 @@ status_t Camera2Client::autoFocus() { status_t Camera2Client::cancelAutoFocus() { ATRACE_CALL(); Mutex::Autolock icl(mICameraLock); + ALOGV("%s: Camera %d", __FUNCTION__, mCameraId); status_t res; if ( (res = checkPid(__FUNCTION__) ) != OK) return res; @@ -1000,7 +1002,7 @@ status_t Camera2Client::takePicture(int msgType) { status_t Camera2Client::setParameters(const String8& params) { ATRACE_CALL(); - ALOGV("%s: E", __FUNCTION__); + ALOGV("%s: Camera %d", __FUNCTION__, mCameraId); Mutex::Autolock icl(mICameraLock); status_t res; if ( (res = checkPid(__FUNCTION__) ) != OK) return res; @@ -1017,13 +1019,13 @@ status_t Camera2Client::setParameters(const String8& params) { String8 Camera2Client::getParameters() const { ATRACE_CALL(); + ALOGV("%s: Camera %d", __FUNCTION__, mCameraId); Mutex::Autolock icl(mICameraLock); if ( checkPid(__FUNCTION__) != OK) return String8(); SharedParameters::ReadLock l(mParameters); - // TODO: Deal with focus distances - return l.mParameters.paramsFlattened; + return l.mParameters.get(); } status_t Camera2Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) { diff --git a/services/camera/libcameraservice/camera2/BurstCapture.cpp b/services/camera/libcameraservice/camera2/BurstCapture.cpp index f4a2aa1..f56c50c 100644 --- a/services/camera/libcameraservice/camera2/BurstCapture.cpp +++ b/services/camera/libcameraservice/camera2/BurstCapture.cpp @@ -22,8 +22,8 @@ #include "BurstCapture.h" -#include "JpegCompressor.h" #include "../Camera2Client.h" +#include "JpegCompressor.h" namespace android { namespace camera2 { diff --git a/services/camera/libcameraservice/camera2/Parameters.cpp b/services/camera/libcameraservice/camera2/Parameters.cpp index 8ae390d..fd44a3e 100644 --- a/services/camera/libcameraservice/camera2/Parameters.cpp +++ b/services/camera/libcameraservice/camera2/Parameters.cpp @@ -27,7 +27,6 @@ #include "Parameters.h" #include "system/camera.h" -#include "camera/CameraParameters.h" namespace android { namespace camera2 { @@ -54,8 +53,6 @@ status_t Parameters::initialize(const CameraMetadata *info) { res = buildFastInfo(); if (res != OK) return res; - CameraParameters params; - camera_metadata_ro_entry_t availableProcessedSizes = staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, 2); if (!availableProcessedSizes.count) return NO_INIT; @@ -171,6 +168,7 @@ status_t Parameters::initialize(const CameraMetadata *info) { // still have to do something sane for them // NOTE: Not scaled like FPS range values are. + previewFps = previewFpsRange[0]; params.set(CameraParameters::KEY_PREVIEW_FRAME_RATE, previewFpsRange[0]); @@ -414,7 +412,7 @@ status_t Parameters::initialize(const CameraMetadata *info) { supportedAntibanding); } - sceneMode = ANDROID_CONTROL_OFF; + sceneMode = ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED; params.set(CameraParameters::KEY_SCENE_MODE, CameraParameters::SCENE_MODE_AUTO); @@ -768,6 +766,10 @@ status_t Parameters::initialize(const CameraMetadata *info) { return OK; } +String8 Parameters::get() const { + return paramsFlattened; +} + status_t Parameters::buildFastInfo() { camera_metadata_ro_entry_t activeArraySize = @@ -811,6 +813,77 @@ status_t Parameters::buildFastInfo() { int32_t maxFaces = maxFacesDetected.data.i32[0]; + camera_metadata_ro_entry_t availableSceneModes = + staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES); + camera_metadata_ro_entry_t sceneModeOverrides = + staticInfo(ANDROID_CONTROL_SCENE_MODE_OVERRIDES); + camera_metadata_ro_entry_t minFocusDistance = + staticInfo(ANDROID_LENS_MINIMUM_FOCUS_DISTANCE); + bool fixedLens = (minFocusDistance.data.f[0] == 0); + + if (sceneModeOverrides.count > 0) { + // sceneModeOverrides is defined to have 3 entries for each scene mode, + // which are AE, AWB, and AF override modes the HAL wants for that scene + // mode. + const size_t kModesPerSceneMode = 3; + if (sceneModeOverrides.count != + availableSceneModes.count * kModesPerSceneMode) { + ALOGE("%s: Camera %d: Scene mode override list is an " + "unexpected size: %d (expected %d)", __FUNCTION__, + cameraId, sceneModeOverrides.count, + availableSceneModes.count); + return NO_INIT; + } + for (size_t i = 0; i < availableSceneModes.count; i++) { + DeviceInfo::OverrideModes modes; + uint8_t aeMode = + sceneModeOverrides.data.u8[i * kModesPerSceneMode + 0]; + switch(aeMode) { + case ANDROID_CONTROL_AE_ON: + modes.flashMode = FLASH_MODE_OFF; + break; + case ANDROID_CONTROL_AE_ON_AUTO_FLASH: + modes.flashMode = FLASH_MODE_AUTO; + break; + case ANDROID_CONTROL_AE_ON_ALWAYS_FLASH: + modes.flashMode = FLASH_MODE_ON; + break; + case ANDROID_CONTROL_AE_ON_AUTO_FLASH_REDEYE: + modes.flashMode = FLASH_MODE_RED_EYE; + break; + default: + ALOGE("%s: Unknown override AE mode: %d", __FUNCTION__, + aeMode); + modes.flashMode = FLASH_MODE_INVALID; + break; + } + modes.wbMode = + sceneModeOverrides.data.u8[i * kModesPerSceneMode + 1]; + uint8_t afMode = + sceneModeOverrides.data.u8[i * kModesPerSceneMode + 2]; + switch(afMode) { + case ANDROID_CONTROL_AF_OFF: + modes.focusMode = fixedLens ? + FOCUS_MODE_FIXED : FOCUS_MODE_INFINITY; + break; + case ANDROID_CONTROL_AF_AUTO: + case ANDROID_CONTROL_AF_MACRO: + case ANDROID_CONTROL_AF_CONTINUOUS_VIDEO: + case ANDROID_CONTROL_AF_CONTINUOUS_PICTURE: + case ANDROID_CONTROL_AF_EDOF: + modes.focusMode = static_cast<focusMode_t>(afMode); + break; + default: + ALOGE("%s: Unknown override AF mode: %d", __FUNCTION__, + afMode); + modes.focusMode = FOCUS_MODE_INVALID; + break; + } + fastInfo.sceneModeOverrides.add(availableSceneModes.data.u8[i], + modes); + } + } + fastInfo.arrayWidth = arrayWidth; fastInfo.arrayHeight = arrayHeight; fastInfo.bestFaceDetectMode = bestFaceDetectMode; @@ -846,10 +919,10 @@ camera_metadata_ro_entry_t Parameters::staticInfo(uint32_t tag, return entry; } -status_t Parameters::set(const String8& params) { +status_t Parameters::set(const String8& paramString) { status_t res; - CameraParameters newParams(params); + CameraParameters newParams(paramString); // TODO: Currently ignoring any changes to supposedly read-only parameters // such as supported preview sizes, etc. Should probably produce an error if @@ -918,6 +991,7 @@ status_t Parameters::set(const String8& params) { return BAD_VALUE; } validatedParams.previewFps = validatedParams.previewFpsRange[0]; + newParams.setPreviewFrameRate(validatedParams.previewFps); } // PREVIEW_FORMAT @@ -1096,23 +1170,6 @@ status_t Parameters::set(const String8& params) { validatedParams.gpsEnabled = false; } - // WHITE_BALANCE - validatedParams.wbMode = wbModeStringToEnum( - newParams.get(CameraParameters::KEY_WHITE_BALANCE) ); - if (validatedParams.wbMode != wbMode) { - camera_metadata_ro_entry_t availableWbModes = - staticInfo(ANDROID_CONTROL_AWB_AVAILABLE_MODES); - for (i = 0; i < availableWbModes.count; i++) { - if (validatedParams.wbMode == availableWbModes.data.u8[i]) break; - } - if (i == availableWbModes.count) { - ALOGE("%s: Requested white balance mode %s is not supported", - __FUNCTION__, - newParams.get(CameraParameters::KEY_WHITE_BALANCE)); - return BAD_VALUE; - } - } - // EFFECT validatedParams.effectMode = effectModeStringToEnum( newParams.get(CameraParameters::KEY_EFFECT) ); @@ -1167,10 +1224,22 @@ status_t Parameters::set(const String8& params) { return BAD_VALUE; } } + bool sceneModeSet = + validatedParams.sceneMode != ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED; // FLASH_MODE - validatedParams.flashMode = flashModeStringToEnum( - newParams.get(CameraParameters::KEY_FLASH_MODE) ); + if (sceneModeSet) { + validatedParams.flashMode = + fastInfo.sceneModeOverrides. + valueFor(validatedParams.sceneMode).flashMode; + } else { + validatedParams.flashMode = FLASH_MODE_INVALID; + } + if (validatedParams.flashMode == FLASH_MODE_INVALID) { + validatedParams.flashMode = flashModeStringToEnum( + newParams.get(CameraParameters::KEY_FLASH_MODE) ); + } + if (validatedParams.flashMode != flashMode) { camera_metadata_ro_entry_t flashAvailable = staticInfo(ANDROID_FLASH_AVAILABLE, 1, 1); @@ -1199,11 +1268,52 @@ status_t Parameters::set(const String8& params) { newParams.get(CameraParameters::KEY_FLASH_MODE)); return BAD_VALUE; } + // Update in case of override + newParams.set(CameraParameters::KEY_FLASH_MODE, + flashModeEnumToString(validatedParams.flashMode)); + } + + // WHITE_BALANCE + if (sceneModeSet) { + validatedParams.wbMode = + fastInfo.sceneModeOverrides. + valueFor(validatedParams.sceneMode).wbMode; + } else { + validatedParams.wbMode = ANDROID_CONTROL_AWB_OFF; + } + if (validatedParams.wbMode == ANDROID_CONTROL_AWB_OFF) { + validatedParams.wbMode = wbModeStringToEnum( + newParams.get(CameraParameters::KEY_WHITE_BALANCE) ); + } + if (validatedParams.wbMode != wbMode) { + camera_metadata_ro_entry_t availableWbModes = + staticInfo(ANDROID_CONTROL_AWB_AVAILABLE_MODES); + for (i = 0; i < availableWbModes.count; i++) { + if (validatedParams.wbMode == availableWbModes.data.u8[i]) break; + } + if (i == availableWbModes.count) { + ALOGE("%s: Requested white balance mode %s is not supported", + __FUNCTION__, + newParams.get(CameraParameters::KEY_WHITE_BALANCE)); + return BAD_VALUE; + } + // Update in case of override + newParams.set(CameraParameters::KEY_WHITE_BALANCE, + wbModeEnumToString(validatedParams.wbMode)); } // FOCUS_MODE - validatedParams.focusMode = focusModeStringToEnum( - newParams.get(CameraParameters::KEY_FOCUS_MODE)); + if (sceneModeSet) { + validatedParams.focusMode = + fastInfo.sceneModeOverrides. + valueFor(validatedParams.sceneMode).focusMode; + } else { + validatedParams.focusMode = FOCUS_MODE_INVALID; + } + if (validatedParams.focusMode == FOCUS_MODE_INVALID) { + validatedParams.focusMode = focusModeStringToEnum( + newParams.get(CameraParameters::KEY_FOCUS_MODE) ); + } if (validatedParams.focusMode != focusMode) { validatedParams.currentAfTriggerId = -1; if (validatedParams.focusMode != Parameters::FOCUS_MODE_FIXED) { @@ -1231,6 +1341,9 @@ status_t Parameters::set(const String8& params) { } } } + // Update in case of override + newParams.set(CameraParameters::KEY_FOCUS_MODE, + focusModeEnumToString(validatedParams.focusMode)); } else { validatedParams.currentAfTriggerId = currentAfTriggerId; } @@ -1333,9 +1446,12 @@ status_t Parameters::set(const String8& params) { /** Update internal parameters */ - validatedParams.paramsFlattened = params; *this = validatedParams; + // Need to flatten again in case of overrides + paramsFlattened = newParams.flatten(); + params = newParams; + return OK; } @@ -1352,10 +1468,6 @@ status_t Parameters::updateRequest(CameraMetadata *request) const { previewFpsRange, 2); if (res != OK) return res; - res = request->update(ANDROID_CONTROL_AWB_MODE, - &wbMode, 1); - if (res != OK) return res; - uint8_t reqWbLock = autoWhiteBalanceLock ? ANDROID_CONTROL_AWB_LOCK_ON : ANDROID_CONTROL_AWB_LOCK_OFF; res = request->update(ANDROID_CONTROL_AWB_LOCK, @@ -1372,8 +1484,10 @@ status_t Parameters::updateRequest(CameraMetadata *request) const { // camera is in a face-priority mode. HAL2 splits this into separate parts // (face detection statistics and face priority scene mode). Map from other // to the other. + bool sceneModeActive = + sceneMode != (uint8_t)ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED; uint8_t reqControlMode = ANDROID_CONTROL_AUTO; - if (enableFaceDetect || sceneMode != ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED) { + if (enableFaceDetect || sceneModeActive) { reqControlMode = ANDROID_CONTROL_USE_SCENE_MODE; } res = request->update(ANDROID_CONTROL_MODE, @@ -1381,8 +1495,7 @@ status_t Parameters::updateRequest(CameraMetadata *request) const { if (res != OK) return res; uint8_t reqSceneMode = - (sceneMode != - (uint8_t)ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED) ? sceneMode : + sceneModeActive ? sceneMode : enableFaceDetect ? (uint8_t)ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY : (uint8_t)ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED; res = request->update(ANDROID_CONTROL_SCENE_MODE, @@ -1390,7 +1503,7 @@ status_t Parameters::updateRequest(CameraMetadata *request) const { if (res != OK) return res; uint8_t reqFlashMode = ANDROID_FLASH_OFF; - uint8_t reqAeMode; + uint8_t reqAeMode = ANDROID_CONTROL_AE_OFF; switch (flashMode) { case Parameters::FLASH_MODE_OFF: reqAeMode = ANDROID_CONTROL_AE_ON; break; @@ -1407,7 +1520,7 @@ status_t Parameters::updateRequest(CameraMetadata *request) const { default: ALOGE("%s: Camera %d: Unknown flash mode %d", __FUNCTION__, cameraId, flashMode); - return BAD_VALUE; + return BAD_VALUE; } res = request->update(ANDROID_FLASH_MODE, &reqFlashMode, 1); @@ -1420,9 +1533,14 @@ status_t Parameters::updateRequest(CameraMetadata *request) const { ANDROID_CONTROL_AE_LOCK_ON : ANDROID_CONTROL_AE_LOCK_OFF; res = request->update(ANDROID_CONTROL_AE_LOCK, &reqAeLock, 1); + if (res != OK) return res; + + res = request->update(ANDROID_CONTROL_AWB_MODE, + &wbMode, 1); + if (res != OK) return res; float reqFocusDistance = 0; // infinity focus in diopters - uint8_t reqFocusMode; + uint8_t reqFocusMode = ANDROID_CONTROL_AF_OFF; switch (focusMode) { case Parameters::FOCUS_MODE_AUTO: case Parameters::FOCUS_MODE_MACRO: @@ -1436,9 +1554,9 @@ status_t Parameters::updateRequest(CameraMetadata *request) const { reqFocusMode = ANDROID_CONTROL_AF_OFF; break; default: - ALOGE("%s: Camera %d: Unknown focus mode %d", __FUNCTION__, - cameraId, focusMode); - return BAD_VALUE; + ALOGE("%s: Camera %d: Unknown focus mode %d", __FUNCTION__, + cameraId, focusMode); + return BAD_VALUE; } res = request->update(ANDROID_LENS_FOCUS_DISTANCE, &reqFocusDistance, 1); @@ -1623,6 +1741,31 @@ int Parameters::wbModeStringToEnum(const char *wbMode) { -1; } +const char* Parameters::wbModeEnumToString(uint8_t wbMode) { + switch (wbMode) { + case ANDROID_CONTROL_AWB_AUTO: + return CameraParameters::WHITE_BALANCE_AUTO; + case ANDROID_CONTROL_AWB_INCANDESCENT: + return CameraParameters::WHITE_BALANCE_INCANDESCENT; + case ANDROID_CONTROL_AWB_FLUORESCENT: + return CameraParameters::WHITE_BALANCE_FLUORESCENT; + case ANDROID_CONTROL_AWB_WARM_FLUORESCENT: + return CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT; + case ANDROID_CONTROL_AWB_DAYLIGHT: + return CameraParameters::WHITE_BALANCE_DAYLIGHT; + case ANDROID_CONTROL_AWB_CLOUDY_DAYLIGHT: + return CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT; + case ANDROID_CONTROL_AWB_TWILIGHT: + return CameraParameters::WHITE_BALANCE_TWILIGHT; + case ANDROID_CONTROL_AWB_SHADE: + return CameraParameters::WHITE_BALANCE_SHADE; + default: + ALOGE("%s: Unknown AWB mode enum: %d", + __FUNCTION__, wbMode); + return "unknown"; + } +} + int Parameters::effectModeStringToEnum(const char *effectMode) { return !effectMode ? @@ -1720,6 +1863,25 @@ Parameters::Parameters::flashMode_t Parameters::flashModeStringToEnum( Parameters::FLASH_MODE_INVALID; } +const char *Parameters::flashModeEnumToString(flashMode_t flashMode) { + switch (flashMode) { + case FLASH_MODE_OFF: + return CameraParameters::FLASH_MODE_OFF; + case FLASH_MODE_AUTO: + return CameraParameters::FLASH_MODE_AUTO; + case FLASH_MODE_ON: + return CameraParameters::FLASH_MODE_ON; + case FLASH_MODE_RED_EYE: + return CameraParameters::FLASH_MODE_RED_EYE; + case FLASH_MODE_TORCH: + return CameraParameters::FLASH_MODE_TORCH; + default: + ALOGE("%s: Unknown flash mode enum %d", + __FUNCTION__, flashMode); + return "unknown"; + } +} + Parameters::Parameters::focusMode_t Parameters::focusModeStringToEnum( const char *focusMode) { return @@ -1742,6 +1904,29 @@ Parameters::Parameters::focusMode_t Parameters::focusModeStringToEnum( Parameters::FOCUS_MODE_INVALID; } +const char *Parameters::focusModeEnumToString(focusMode_t focusMode) { + switch (focusMode) { + case FOCUS_MODE_AUTO: + return CameraParameters::FOCUS_MODE_AUTO; + case FOCUS_MODE_MACRO: + return CameraParameters::FOCUS_MODE_MACRO; + case FOCUS_MODE_CONTINUOUS_VIDEO: + return CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO; + case FOCUS_MODE_CONTINUOUS_PICTURE: + return CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE; + case FOCUS_MODE_EDOF: + return CameraParameters::FOCUS_MODE_EDOF; + case FOCUS_MODE_INFINITY: + return CameraParameters::FOCUS_MODE_INFINITY; + case FOCUS_MODE_FIXED: + return CameraParameters::FOCUS_MODE_FIXED; + default: + ALOGE("%s: Unknown focus mode enum: %d", + __FUNCTION__, focusMode); + return "unknown"; + } +} + status_t Parameters::parseAreas(const char *areasCStr, Vector<Parameters::Area> *areas) { static const size_t NUM_FIELDS = 5; diff --git a/services/camera/libcameraservice/camera2/Parameters.h b/services/camera/libcameraservice/camera2/Parameters.h index f830e21..c587ca5 100644 --- a/services/camera/libcameraservice/camera2/Parameters.h +++ b/services/camera/libcameraservice/camera2/Parameters.h @@ -23,6 +23,8 @@ #include <utils/Mutex.h> #include <utils/String8.h> #include <utils/Vector.h> +#include <utils/KeyedVector.h> +#include <camera/CameraParameters.h> #include "CameraMetadata.h" @@ -115,6 +117,7 @@ struct Parameters { LIGHTFX_HDR } lightFx; + CameraParameters params; String8 paramsFlattened; // These parameters are also part of the camera API-visible state, but not @@ -162,8 +165,26 @@ struct Parameters { int32_t arrayHeight; uint8_t bestFaceDetectMode; int32_t maxFaces; + struct OverrideModes { + flashMode_t flashMode; + uint8_t wbMode; + focusMode_t focusMode; + OverrideModes(): + flashMode(FLASH_MODE_INVALID), + wbMode(ANDROID_CONTROL_AWB_OFF), + focusMode(FOCUS_MODE_INVALID) { + } + }; + DefaultKeyedVector<uint8_t, OverrideModes> sceneModeOverrides; } fastInfo; + // Quirks information; these are short-lived flags to enable workarounds for + // incomplete HAL implementations + struct Quirks { + bool triggerAfWithAuto; + bool useZslFormat; + } quirks; + /** * Parameter manipulation and setup methods */ @@ -185,7 +206,10 @@ struct Parameters { size_t minCount=0, size_t maxCount=0) const; // Validate and update camera parameters based on new settings - status_t set(const String8 ¶ms); + status_t set(const String8 ¶mString); + + // Retrieve the current settings + String8 get() const; // Update passed-in request for common parameters status_t updateRequest(CameraMetadata *request) const; @@ -208,11 +232,14 @@ struct Parameters { static const char *formatEnumToString(int format); static int wbModeStringToEnum(const char *wbMode); + static const char* wbModeEnumToString(uint8_t wbMode); static int effectModeStringToEnum(const char *effectMode); static int abModeStringToEnum(const char *abMode); static int sceneModeStringToEnum(const char *sceneMode); static flashMode_t flashModeStringToEnum(const char *flashMode); + static const char* flashModeEnumToString(flashMode_t flashMode); static focusMode_t focusModeStringToEnum(const char *focusMode); + static const char* focusModeEnumToString(focusMode_t focusMode); static status_t parseAreas(const char *areasCStr, Vector<Area> *areas); static status_t validateAreas(const Vector<Area> &areas, @@ -232,7 +259,6 @@ struct Parameters { int arrayYToNormalized(int height) const; int normalizedXToArray(int x) const; int normalizedYToArray(int y) const; - }; // This class encapsulates the Parameters class so that it can only be accessed |