diff options
24 files changed, 814 insertions, 129 deletions
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp index b86651f..79c33f9 100644 --- a/camera/ICameraService.cpp +++ b/camera/ICameraService.cpp @@ -18,6 +18,7 @@ #define LOG_TAG "BpCameraService" #include <utils/Log.h> #include <utils/Errors.h> +#include <utils/String16.h> #include <stdint.h> #include <sys/types.h> @@ -253,6 +254,41 @@ public: if (readExceptionCode(reply)) return -EPROTO; return reply.readInt32(); } + + virtual status_t getLegacyParameters(int cameraId, String16* parameters) { + if (parameters == NULL) { + ALOGE("%s: parameters must not be null", __FUNCTION__); + return BAD_VALUE; + } + + Parcel data, reply; + + data.writeInt32(cameraId); + remote()->transact(BnCameraService::GET_LEGACY_PARAMETERS, data, &reply); + if (readExceptionCode(reply)) return -EPROTO; + + status_t res = data.readInt32(); + int32_t length = data.readInt32(); // -1 means null + if (length > 0) { + *parameters = data.readString16(); + } else { + *parameters = String16(); + } + + return res; + } + + virtual status_t supportsCameraApi(int cameraId, int apiVersion) { + Parcel data, reply; + + data.writeInt32(cameraId); + data.writeInt32(apiVersion); + remote()->transact(BnCameraService::SUPPORTS_CAMERA_API, data, &reply); + if (readExceptionCode(reply)) return -EPROTO; + + status_t res = data.readInt32(); + return res; + } }; IMPLEMENT_META_INTERFACE(CameraService, "android.hardware.ICameraService"); @@ -387,6 +423,29 @@ status_t BnCameraService::onTransact( reply->writeInt32(removeListener(listener)); return NO_ERROR; } break; + case GET_LEGACY_PARAMETERS: { + CHECK_INTERFACE(ICameraService, data, reply); + int cameraId = data.readInt32(); + String16 parameters; + + reply->writeNoException(); + // return value + reply->writeInt32(getLegacyParameters(cameraId, ¶meters)); + // out parameters + reply->writeInt32(1); // parameters is always available + reply->writeString16(parameters); + return NO_ERROR; + } break; + case SUPPORTS_CAMERA_API: { + CHECK_INTERFACE(ICameraService, data, reply); + int cameraId = data.readInt32(); + int apiVersion = data.readInt32(); + + reply->writeNoException(); + // return value + reply->writeInt32(supportsCameraApi(cameraId, apiVersion)); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h index 6e48f22..d7e5dac 100644 --- a/include/camera/ICameraService.h +++ b/include/camera/ICameraService.h @@ -32,6 +32,7 @@ class ICameraDeviceUser; class ICameraDeviceCallbacks; class CameraMetadata; class VendorTagDescriptor; +class String16; class ICameraService : public IInterface { @@ -49,12 +50,19 @@ public: REMOVE_LISTENER, GET_CAMERA_CHARACTERISTICS, GET_CAMERA_VENDOR_TAG_DESCRIPTOR, + GET_LEGACY_PARAMETERS, + SUPPORTS_CAMERA_API, }; enum { USE_CALLING_UID = -1 }; + enum { + API_VERSION_1 = 1, + API_VERSION_2 = 2, + }; + public: DECLARE_META_INTERFACE(CameraService); @@ -105,6 +113,18 @@ public: int clientUid, /*out*/ sp<ICameraDeviceUser>& device) = 0; + + virtual status_t getLegacyParameters( + int cameraId, + /*out*/ + String16* parameters) = 0; + + /** + * Returns OK if device supports camera2 api, + * returns -EOPNOTSUPP if it doesn't. + */ + virtual status_t supportsCameraApi( + int cameraId, int apiVersion) = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h index 6fe0c7f..a4722cb 100644 --- a/include/media/AudioSystem.h +++ b/include/media/AudioSystem.h @@ -104,12 +104,10 @@ public: static status_t getOutputLatency(uint32_t* latency, audio_stream_type_t stream); static status_t getSamplingRate(audio_io_handle_t output, - audio_stream_type_t streamType, uint32_t* samplingRate); // returns the number of frames per audio HAL write buffer. Corresponds to // audio_stream->get_buffer_size()/audio_stream_frame_size() static status_t getFrameCount(audio_io_handle_t output, - audio_stream_type_t stream, size_t* frameCount); // returns the audio output stream latency in ms. Corresponds to // audio_stream_out->get_latency() diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h index 563c0b5..e67d4d5 100644 --- a/include/media/stagefright/MediaDefs.h +++ b/include/media/stagefright/MediaDefs.h @@ -60,6 +60,8 @@ extern const char *MEDIA_MIMETYPE_CONTAINER_WVM; extern const char *MEDIA_MIMETYPE_TEXT_3GPP; extern const char *MEDIA_MIMETYPE_TEXT_SUBRIP; +extern const char *MEDIA_MIMETYPE_TEXT_VTT; +extern const char *MEDIA_MIMETYPE_TEXT_CEA_608; } // namespace android diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index db61e85..50b444a 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -105,6 +105,8 @@ AudioRecord::~AudioRecord() } mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this); mAudioRecord.clear(); + mCblkMemory.clear(); + mBufferMemory.clear(); IPCThreadState::self()->flushCommands(); AudioSystem::releaseAudioSessionId(mSessionId, -1); } @@ -546,9 +548,10 @@ status_t AudioRecord::openRecord_l(size_t epoch) mDeathNotifier.clear(); } mAudioRecord = record; - mCblkMemory = iMem; mBufferMemory = bufferMem; + IPCThreadState::self()->flushCommands(); + mCblk = cblk; // note that temp is the (possibly revised) value of frameCount if (temp < frameCount || (frameCount == 0 && temp == 0)) { diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index eafb3ad..15b32ff 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -242,11 +242,10 @@ status_t AudioSystem::getOutputSamplingRate(uint32_t* samplingRate, audio_stream return PERMISSION_DENIED; } - return getSamplingRate(output, streamType, samplingRate); + return getSamplingRate(output, samplingRate); } status_t AudioSystem::getSamplingRate(audio_io_handle_t output, - audio_stream_type_t streamType, uint32_t* samplingRate) { OutputDescriptor *outputDesc; @@ -265,13 +264,11 @@ status_t AudioSystem::getSamplingRate(audio_io_handle_t output, gLock.unlock(); } if (*samplingRate == 0) { - ALOGE("AudioSystem::getSamplingRate failed for output %d stream type %d", - output, streamType); + ALOGE("AudioSystem::getSamplingRate failed for output %d", output); return BAD_VALUE; } - ALOGV("getSamplingRate() streamType %d, output %d, sampling rate %u", streamType, output, - *samplingRate); + ALOGV("getSamplingRate() output %d, sampling rate %u", output, *samplingRate); return NO_ERROR; } @@ -289,11 +286,10 @@ status_t AudioSystem::getOutputFrameCount(size_t* frameCount, audio_stream_type_ return PERMISSION_DENIED; } - return getFrameCount(output, streamType, frameCount); + return getFrameCount(output, frameCount); } status_t AudioSystem::getFrameCount(audio_io_handle_t output, - audio_stream_type_t streamType, size_t* frameCount) { OutputDescriptor *outputDesc; @@ -310,13 +306,11 @@ status_t AudioSystem::getFrameCount(audio_io_handle_t output, gLock.unlock(); } if (*frameCount == 0) { - ALOGE("AudioSystem::getFrameCount failed for output %d stream type %d", - output, streamType); + ALOGE("AudioSystem::getFrameCount failed for output %d", output); return BAD_VALUE; } - ALOGV("getFrameCount() streamType %d, output %d, frameCount %d", streamType, output, - *frameCount); + ALOGV("getFrameCount() output %d, frameCount %d", output, *frameCount); return NO_ERROR; } diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 7d3ecc5..e6827ee 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -174,6 +174,8 @@ AudioTrack::~AudioTrack() } mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this); mAudioTrack.clear(); + mCblkMemory.clear(); + mSharedBuffer.clear(); IPCThreadState::self()->flushCommands(); ALOGV("~AudioTrack, releasing session id from %d on behalf of %d", IPCThreadState::self()->getCallingPid(), mClientPid); @@ -647,7 +649,7 @@ uint32_t AudioTrack::getSampleRate() const if (isOffloaded_l()) { if (mOutput != AUDIO_IO_HANDLE_NONE) { uint32_t sampleRate = 0; - status_t status = AudioSystem::getSamplingRate(mOutput, mStreamType, &sampleRate); + status_t status = AudioSystem::getSamplingRate(mOutput, &sampleRate); if (status == NO_ERROR) { mSampleRate = sampleRate; } @@ -887,16 +889,16 @@ status_t AudioTrack::createTrack_l(size_t epoch) } size_t afFrameCount; - status = AudioSystem::getFrameCount(output, mStreamType, &afFrameCount); + status = AudioSystem::getFrameCount(output, &afFrameCount); if (status != NO_ERROR) { - ALOGE("getFrameCount(output=%d, streamType=%d) status %d", output, mStreamType, status); + ALOGE("getFrameCount(output=%d) status %d", output, status); goto release; } uint32_t afSampleRate; - status = AudioSystem::getSamplingRate(output, mStreamType, &afSampleRate); + status = AudioSystem::getSamplingRate(output, &afSampleRate); if (status != NO_ERROR) { - ALOGE("getSamplingRate(output=%d, streamType=%d) status %d", output, mStreamType, status); + ALOGE("getSamplingRate(output=%d) status %d", output, status); goto release; } @@ -1059,8 +1061,9 @@ status_t AudioTrack::createTrack_l(size_t epoch) mDeathNotifier.clear(); } mAudioTrack = track; - mCblkMemory = iMem; + IPCThreadState::self()->flushCommands(); + audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer); mCblk = cblk; // note that temp is the (possibly revised) value of frameCount diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp index cbedf5c..e8431e9 100644 --- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp +++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp @@ -120,8 +120,12 @@ status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) { return mLiveSession->getDuration(durationUs); } -status_t NuPlayer::HTTPLiveSource::getTrackInfo(Parcel *reply) const { - return mLiveSession->getTrackInfo(reply); +size_t NuPlayer::HTTPLiveSource::getTrackCount() const { + return mLiveSession->getTrackCount(); +} + +sp<AMessage> NuPlayer::HTTPLiveSource::getTrackInfo(size_t trackIndex) const { + return mLiveSession->getTrackInfo(trackIndex); } status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select) { diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h index 4d7251f..6b5f6af 100644 --- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h +++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h @@ -40,7 +40,8 @@ struct NuPlayer::HTTPLiveSource : public NuPlayer::Source { virtual status_t feedMoreTSData(); virtual status_t getDuration(int64_t *durationUs); - virtual status_t getTrackInfo(Parcel *reply) const; + virtual size_t getTrackCount() const; + virtual sp<AMessage> getTrackInfo(size_t trackIndex) const; virtual status_t selectTrack(size_t trackIndex, bool select); virtual status_t seekTo(int64_t seekTimeUs); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 857e703..b333043 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -305,6 +305,34 @@ bool NuPlayer::IsFlushingState(FlushStatus state, bool *needShutdown) { } } +void NuPlayer::writeTrackInfo( + Parcel* reply, const sp<AMessage> format) const { + int32_t trackType; + CHECK(format->findInt32("type", &trackType)); + + AString lang; + CHECK(format->findString("language", &lang)); + + reply->writeInt32(2); // write something non-zero + reply->writeInt32(trackType); + reply->writeString16(String16(lang.c_str())); + + if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { + AString mime; + CHECK(format->findString("mime", &mime)); + + int32_t isAuto, isDefault, isForced; + CHECK(format->findInt32("auto", &isAuto)); + CHECK(format->findInt32("default", &isDefault)); + CHECK(format->findInt32("forced", &isForced)); + + reply->writeString16(String16(mime.c_str())); + reply->writeInt32(isAuto); + reply->writeInt32(isDefault); + reply->writeInt32(isForced); + } +} + void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatSetDataSource: @@ -339,16 +367,33 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - status_t err = INVALID_OPERATION; + Parcel* reply; + CHECK(msg->findPointer("reply", (void**)&reply)); + + size_t inbandTracks = 0; if (mSource != NULL) { - Parcel* reply; - CHECK(msg->findPointer("reply", (void**)&reply)); - err = mSource->getTrackInfo(reply); + inbandTracks = mSource->getTrackCount(); } - sp<AMessage> response = new AMessage; - response->setInt32("err", err); + size_t ccTracks = 0; + if (mCCDecoder != NULL) { + ccTracks = mCCDecoder->getTrackCount(); + } + + // total track count + reply->writeInt32(inbandTracks + ccTracks); + + // write inband tracks + for (size_t i = 0; i < inbandTracks; ++i) { + writeTrackInfo(reply, mSource->getTrackInfo(i)); + } + // write CC track + for (size_t i = 0; i < ccTracks; ++i) { + writeTrackInfo(reply, mCCDecoder->getTrackInfo(i)); + } + + sp<AMessage> response = new AMessage; response->postReply(replyID); break; } @@ -358,13 +403,30 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); + size_t trackIndex; + int32_t select; + CHECK(msg->findSize("trackIndex", &trackIndex)); + CHECK(msg->findInt32("select", &select)); + status_t err = INVALID_OPERATION; + + size_t inbandTracks = 0; if (mSource != NULL) { - size_t trackIndex; - int32_t select; - CHECK(msg->findSize("trackIndex", &trackIndex)); - CHECK(msg->findInt32("select", &select)); + inbandTracks = mSource->getTrackCount(); + } + size_t ccTracks = 0; + if (mCCDecoder != NULL) { + ccTracks = mCCDecoder->getTrackCount(); + } + + if (trackIndex < inbandTracks) { err = mSource->selectTrack(trackIndex, select); + } else { + trackIndex -= inbandTracks; + + if (trackIndex < ccTracks) { + err = mCCDecoder->selectTrack(trackIndex, select); + } } sp<AMessage> response = new AMessage; @@ -828,6 +890,12 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { break; } + case kWhatClosedCaptionNotify: + { + onClosedCaptionNotify(msg); + break; + } + default: TRESPASS(); break; @@ -891,6 +959,9 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) { AString mime; CHECK(format->findString("mime", &mime)); mVideoIsAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str()); + + sp<AMessage> ccNotify = new AMessage(kWhatClosedCaptionNotify, id()); + mCCDecoder = new CCDecoder(ccNotify); } sp<AMessage> notify = @@ -1031,6 +1102,10 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) { mediaTimeUs / 1E6); #endif + if (!audio) { + mCCDecoder->decode(accessUnit); + } + reply->setBuffer("buffer", accessUnit); reply->post(); @@ -1059,14 +1134,15 @@ void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) { sp<ABuffer> buffer; CHECK(msg->findBuffer("buffer", &buffer)); + int64_t mediaTimeUs; + CHECK(buffer->meta()->findInt64("timeUs", &mediaTimeUs)); + int64_t &skipUntilMediaTimeUs = audio ? mSkipRenderingAudioUntilMediaTimeUs : mSkipRenderingVideoUntilMediaTimeUs; if (skipUntilMediaTimeUs >= 0) { - int64_t mediaTimeUs; - CHECK(buffer->meta()->findInt64("timeUs", &mediaTimeUs)); if (mediaTimeUs < skipUntilMediaTimeUs) { ALOGV("dropping %s buffer at time %lld as requested.", @@ -1080,6 +1156,10 @@ void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) { skipUntilMediaTimeUs = -1; } + if (!audio && mCCDecoder->isSelected()) { + mCCDecoder->display(mediaTimeUs); + } + mRenderer->queueBuffer(audio, buffer, reply); } @@ -1187,6 +1267,14 @@ status_t NuPlayer::selectTrack(size_t trackIndex, bool select) { sp<AMessage> response; status_t err = msg->postAndAwaitResponse(&response); + if (err != OK) { + return err; + } + + if (!response->findInt32("err", &err)) { + err = OK; + } + return err; } @@ -1438,21 +1526,7 @@ void NuPlayer::onSourceNotify(const sp<AMessage> &msg) { sp<ABuffer> buffer; CHECK(msg->findBuffer("buffer", &buffer)); - int32_t trackIndex; - int64_t timeUs, durationUs; - CHECK(buffer->meta()->findInt32("trackIndex", &trackIndex)); - CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); - CHECK(buffer->meta()->findInt64("durationUs", &durationUs)); - - Parcel in; - in.writeInt32(trackIndex); - in.writeInt64(timeUs); - in.writeInt64(durationUs); - in.writeInt32(buffer->size()); - in.writeInt32(buffer->size()); - in.write(buffer->data(), buffer->size()); - - notifyListener(MEDIA_SUBTITLE_DATA, 0, 0, &in); + sendSubtitleData(buffer, 0 /* baseIndex */); break; } @@ -1474,6 +1548,56 @@ void NuPlayer::onSourceNotify(const sp<AMessage> &msg) { } } +void NuPlayer::onClosedCaptionNotify(const sp<AMessage> &msg) { + int32_t what; + CHECK(msg->findInt32("what", &what)); + + switch (what) { + case NuPlayer::CCDecoder::kWhatClosedCaptionData: + { + sp<ABuffer> buffer; + CHECK(msg->findBuffer("buffer", &buffer)); + + size_t inbandTracks = 0; + if (mSource != NULL) { + inbandTracks = mSource->getTrackCount(); + } + + sendSubtitleData(buffer, inbandTracks); + break; + } + + case NuPlayer::CCDecoder::kWhatTrackAdded: + { + notifyListener(MEDIA_INFO, MEDIA_INFO_METADATA_UPDATE, 0); + + break; + } + + default: + TRESPASS(); + } + + +} + +void NuPlayer::sendSubtitleData(const sp<ABuffer> &buffer, int32_t baseIndex) { + int32_t trackIndex; + int64_t timeUs, durationUs; + CHECK(buffer->meta()->findInt32("trackIndex", &trackIndex)); + CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); + CHECK(buffer->meta()->findInt64("durationUs", &durationUs)); + + Parcel in; + in.writeInt32(trackIndex + baseIndex); + in.writeInt64(timeUs); + in.writeInt64(durationUs); + in.writeInt32(buffer->size()); + in.writeInt32(buffer->size()); + in.write(buffer->data(), buffer->size()); + + notifyListener(MEDIA_SUBTITLE_DATA, 0, 0, &in); +} //////////////////////////////////////////////////////////////////////////////// void NuPlayer::Source::notifyFlagsChanged(uint32_t flags) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index f1d3d55..5be71fb 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -24,6 +24,7 @@ namespace android { +struct ABuffer; struct MetaData; struct NuPlayerDriver; @@ -75,6 +76,7 @@ public: private: struct Decoder; + struct CCDecoder; struct GenericSource; struct HTTPLiveSource; struct Renderer; @@ -97,6 +99,7 @@ private: kWhatScanSources = 'scan', kWhatVideoNotify = 'vidN', kWhatAudioNotify = 'audN', + kWhatClosedCaptionNotify = 'capN', kWhatRendererNotify = 'renN', kWhatReset = 'rset', kWhatSeek = 'seek', @@ -118,6 +121,7 @@ private: sp<Decoder> mVideoDecoder; bool mVideoIsAVC; sp<Decoder> mAudioDecoder; + sp<CCDecoder> mCCDecoder; sp<Renderer> mRenderer; List<sp<Action> > mDeferredActions; @@ -185,10 +189,15 @@ private: void performSetSurface(const sp<NativeWindowWrapper> &wrapper); void onSourceNotify(const sp<AMessage> &msg); + void onClosedCaptionNotify(const sp<AMessage> &msg); void queueDecoderShutdown( bool audio, bool video, const sp<AMessage> &reply); + void sendSubtitleData(const sp<ABuffer> &buffer, int32_t baseIndex); + + void writeTrackInfo(Parcel* reply, const sp<AMessage> format) const; + DISALLOW_EVIL_CONSTRUCTORS(NuPlayer); }; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index cfbf282..5abfb71 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -22,6 +22,7 @@ #include "NuPlayerDecoder.h" #include <media/ICrypto.h> +#include <media/stagefright/foundation/ABitReader.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> @@ -535,5 +536,272 @@ bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetF return seamless; } +struct NuPlayer::CCDecoder::CCData { + CCData(uint8_t type, uint8_t data1, uint8_t data2) + : mType(type), mData1(data1), mData2(data2) { + } + + uint8_t mType; + uint8_t mData1; + uint8_t mData2; +}; + +NuPlayer::CCDecoder::CCDecoder(const sp<AMessage> ¬ify) + : mNotify(notify), + mTrackCount(0), + mSelectedTrack(-1) { +} + +size_t NuPlayer::CCDecoder::getTrackCount() const { + return mTrackCount; +} + +sp<AMessage> NuPlayer::CCDecoder::getTrackInfo(size_t index) const { + CHECK(index == 0); + + sp<AMessage> format = new AMessage(); + + format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE); + format->setString("language", "und"); + format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608); + format->setInt32("auto", 1); + format->setInt32("default", 1); + format->setInt32("forced", 0); + + return format; +} + +status_t NuPlayer::CCDecoder::selectTrack(size_t index, bool select) { + CHECK(index < mTrackCount); + + if (select) { + if (mSelectedTrack == (ssize_t)index) { + ALOGE("track %zu already selected", index); + return BAD_VALUE; + } + ALOGV("selected track %zu", index); + mSelectedTrack = index; + } else { + if (mSelectedTrack != (ssize_t)index) { + ALOGE("track %zu is not selected", index); + return BAD_VALUE; + } + ALOGV("unselected track %zu", index); + mSelectedTrack = -1; + } + + return OK; +} + +bool NuPlayer::CCDecoder::isSelected() const { + return mSelectedTrack >= 0 && mSelectedTrack < (int32_t)mTrackCount; +} + +bool NuPlayer::CCDecoder::isNullPad(CCData *cc) const { + return cc->mData1 < 0x10 && cc->mData2 < 0x10; +} + +void NuPlayer::CCDecoder::dumpBytePair(const sp<ABuffer> &ccBuf) const { + size_t offset = 0; + AString out; + + while (offset < ccBuf->size()) { + char tmp[128]; + + CCData *cc = (CCData *) (ccBuf->data() + offset); + + if (isNullPad(cc)) { + // 1 null pad or XDS metadata, ignore + offset += sizeof(CCData); + continue; + } + + if (cc->mData1 >= 0x20 && cc->mData1 <= 0x7f) { + // 2 basic chars + sprintf(tmp, "[%d]Basic: %c %c", cc->mType, cc->mData1, cc->mData2); + } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19) + && cc->mData2 >= 0x30 && cc->mData2 <= 0x3f) { + // 1 special char + sprintf(tmp, "[%d]Special: %02x %02x", cc->mType, cc->mData1, cc->mData2); + } else if ((cc->mData1 == 0x12 || cc->mData1 == 0x1A) + && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){ + // 1 Spanish/French char + sprintf(tmp, "[%d]Spanish: %02x %02x", cc->mType, cc->mData1, cc->mData2); + } else if ((cc->mData1 == 0x13 || cc->mData1 == 0x1B) + && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){ + // 1 Portuguese/German/Danish char + sprintf(tmp, "[%d]German: %02x %02x", cc->mType, cc->mData1, cc->mData2); + } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19) + && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f){ + // Mid-Row Codes (Table 69) + sprintf(tmp, "[%d]Mid-row: %02x %02x", cc->mType, cc->mData1, cc->mData2); + } else if (((cc->mData1 == 0x14 || cc->mData1 == 0x1c) + && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f) + || + ((cc->mData1 == 0x17 || cc->mData1 == 0x1f) + && cc->mData2 >= 0x21 && cc->mData2 <= 0x23)){ + // Misc Control Codes (Table 70) + sprintf(tmp, "[%d]Ctrl: %02x %02x", cc->mType, cc->mData1, cc->mData2); + } else if ((cc->mData1 & 0x70) == 0x10 + && (cc->mData2 & 0x40) == 0x40 + && ((cc->mData1 & 0x07) || !(cc->mData2 & 0x20)) ) { + // Preamble Address Codes (Table 71) + sprintf(tmp, "[%d]PAC: %02x %02x", cc->mType, cc->mData1, cc->mData2); + } else { + sprintf(tmp, "[%d]Invalid: %02x %02x", cc->mType, cc->mData1, cc->mData2); + } + + if (out.size() > 0) { + out.append(", "); + } + + out.append(tmp); + + offset += sizeof(CCData); + } + + ALOGI("%s", out.c_str()); +} + +bool NuPlayer::CCDecoder::extractFromSEI(const sp<ABuffer> &accessUnit) { + int64_t timeUs; + CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs)); + + sp<ABuffer> sei; + if (!accessUnit->meta()->findBuffer("sei", &sei) || sei == NULL) { + return false; + } + + bool hasCC = false; + + ABitReader br(sei->data() + 1, sei->size() - 1); + // sei_message() + while (br.numBitsLeft() >= 16) { // at least 16-bit for sei_message() + uint32_t payload_type = 0; + size_t payload_size = 0; + uint8_t last_byte; + + do { + last_byte = br.getBits(8); + payload_type += last_byte; + } while (last_byte == 0xFF); + + do { + last_byte = br.getBits(8); + payload_size += last_byte; + } while (last_byte == 0xFF); + + // sei_payload() + if (payload_type == 4) { + // user_data_registered_itu_t_t35() + + // ATSC A/72: 6.4.2 + uint8_t itu_t_t35_country_code = br.getBits(8); + uint16_t itu_t_t35_provider_code = br.getBits(16); + uint32_t user_identifier = br.getBits(32); + uint8_t user_data_type_code = br.getBits(8); + + payload_size -= 1 + 2 + 4 + 1; + + if (itu_t_t35_country_code == 0xB5 + && itu_t_t35_provider_code == 0x0031 + && user_identifier == 'GA94' + && user_data_type_code == 0x3) { + hasCC = true; + + // MPEG_cc_data() + // ATSC A/53 Part 4: 6.2.3.1 + br.skipBits(1); //process_em_data_flag + bool process_cc_data_flag = br.getBits(1); + br.skipBits(1); //additional_data_flag + size_t cc_count = br.getBits(5); + br.skipBits(8); // em_data; + payload_size -= 2; + + if (process_cc_data_flag) { + AString out; + + sp<ABuffer> ccBuf = new ABuffer(cc_count * sizeof(CCData)); + ccBuf->setRange(0, 0); + + for (size_t i = 0; i < cc_count; i++) { + uint8_t marker = br.getBits(5); + CHECK_EQ(marker, 0x1f); + + bool cc_valid = br.getBits(1); + uint8_t cc_type = br.getBits(2); + // remove odd parity bit + uint8_t cc_data_1 = br.getBits(8) & 0x7f; + uint8_t cc_data_2 = br.getBits(8) & 0x7f; + + if (cc_valid + && (cc_type == 0 || cc_type == 1)) { + CCData cc(cc_type, cc_data_1, cc_data_2); + if (!isNullPad(&cc)) { + memcpy(ccBuf->data() + ccBuf->size(), + (void *)&cc, sizeof(cc)); + ccBuf->setRange(0, ccBuf->size() + sizeof(CCData)); + } + } + } + payload_size -= cc_count * 3; + + mCCMap.add(timeUs, ccBuf); + break; + } + } else { + ALOGV("Malformed SEI payload type 4"); + } + } else { + ALOGV("Unsupported SEI payload type %d", payload_type); + } + + // skipping remaining bits of this payload + br.skipBits(payload_size * 8); + } + + return hasCC; +} + +void NuPlayer::CCDecoder::decode(const sp<ABuffer> &accessUnit) { + if (extractFromSEI(accessUnit) && mTrackCount == 0) { + mTrackCount++; + + ALOGI("Found CEA-608 track"); + sp<AMessage> msg = mNotify->dup(); + msg->setInt32("what", kWhatTrackAdded); + msg->post(); + } + // TODO: extract CC from other sources +} + +void NuPlayer::CCDecoder::display(int64_t timeUs) { + ssize_t index = mCCMap.indexOfKey(timeUs); + if (index < 0) { + ALOGV("cc for timestamp %" PRId64 " not found", timeUs); + return; + } + + sp<ABuffer> &ccBuf = mCCMap.editValueAt(index); + + if (ccBuf->size() > 0) { +#if 0 + dumpBytePair(ccBuf); +#endif + + ccBuf->meta()->setInt32("trackIndex", mSelectedTrack); + ccBuf->meta()->setInt64("timeUs", timeUs); + ccBuf->meta()->setInt64("durationUs", 0ll); + + sp<AMessage> msg = mNotify->dup(); + msg->setInt32("what", kWhatClosedCaptionData); + msg->setBuffer("buffer", ccBuf); + msg->post(); + } + + // remove all entries before timeUs + mCCMap.removeItemsAt(0, index + 1); +} + } // namespace android diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h index 2892584..1a4f4ab 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h @@ -101,6 +101,36 @@ private: DISALLOW_EVIL_CONSTRUCTORS(Decoder); }; +struct NuPlayer::CCDecoder : public RefBase { + enum { + kWhatClosedCaptionData, + kWhatTrackAdded, + }; + + CCDecoder(const sp<AMessage> ¬ify); + + size_t getTrackCount() const; + sp<AMessage> getTrackInfo(size_t index) const; + status_t selectTrack(size_t index, bool select); + bool isSelected() const; + void decode(const sp<ABuffer> &accessUnit); + void display(int64_t timeUs); + +private: + struct CCData; + + sp<AMessage> mNotify; + KeyedVector<int64_t, sp<ABuffer> > mCCMap; + size_t mTrackCount; + int32_t mSelectedTrack; + + bool isNullPad(CCData *cc) const; + void dumpBytePair(const sp<ABuffer> &ccBuf) const; + bool extractFromSEI(const sp<ABuffer> &accessUnit); + + DISALLOW_EVIL_CONSTRUCTORS(CCDecoder); +}; + } // namespace android #endif // NUPLAYER_DECODER_H_ diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h index 11279fc..f5a1d6d 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h @@ -72,8 +72,12 @@ struct NuPlayer::Source : public AHandler { return INVALID_OPERATION; } - virtual status_t getTrackInfo(Parcel* /* reply */) const { - return INVALID_OPERATION; + virtual size_t getTrackCount() const { + return 0; + } + + virtual sp<AMessage> getTrackInfo(size_t /* trackIndex */) const { + return NULL; } virtual status_t selectTrack(size_t /* trackIndex */, bool /* select */) { diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp index 8229e55..d48dd84 100644 --- a/media/libstagefright/MediaDefs.cpp +++ b/media/libstagefright/MediaDefs.cpp @@ -58,5 +58,7 @@ const char *MEDIA_MIMETYPE_CONTAINER_WVM = "video/wvm"; const char *MEDIA_MIMETYPE_TEXT_3GPP = "text/3gpp-tt"; const char *MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip"; +const char *MEDIA_MIMETYPE_TEXT_VTT = "text/vtt"; +const char *MEDIA_MIMETYPE_TEXT_CEA_608 = "text/cea-608"; } // namespace android diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 08a146f..10cdde2 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -926,8 +926,12 @@ bool LiveSession::hasDynamicDuration() const { return false; } -status_t LiveSession::getTrackInfo(Parcel *reply) const { - return mPlaylist->getTrackInfo(reply); +size_t LiveSession::getTrackCount() const { + return mPlaylist->getTrackCount(); +} + +sp<AMessage> LiveSession::getTrackInfo(size_t trackIndex) const { + return mPlaylist->getTrackInfo(trackIndex); } status_t LiveSession::selectTrack(size_t index, bool select) { diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index d7ed56f..ed3818f 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -70,7 +70,8 @@ struct LiveSession : public AHandler { status_t seekTo(int64_t timeUs); status_t getDuration(int64_t *durationUs) const; - status_t getTrackInfo(Parcel *reply) const; + size_t getTrackCount() const; + sp<AMessage> getTrackInfo(size_t trackIndex) const; status_t selectTrack(size_t index, bool select); bool isSeekable() const; diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index 785c515..281e0da 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -23,6 +23,7 @@ #include <cutils/properties.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> +#include <media/stagefright/MediaDefs.h> #include <media/stagefright/MediaErrors.h> #include <media/stagefright/Utils.h> #include <media/mediaplayer.h> @@ -58,8 +59,8 @@ struct M3UParser::MediaGroup : public RefBase { void pickRandomMediaItems(); status_t selectTrack(size_t index, bool select); - void getTrackInfo(Parcel* reply) const; size_t countTracks() const; + sp<AMessage> getTrackInfo(size_t index) const; protected: virtual ~MediaGroup(); @@ -184,35 +185,42 @@ status_t M3UParser::MediaGroup::selectTrack(size_t index, bool select) { return OK; } -void M3UParser::MediaGroup::getTrackInfo(Parcel* reply) const { - for (size_t i = 0; i < mMediaItems.size(); ++i) { - reply->writeInt32(2); // 2 fields - - if (mType == TYPE_AUDIO) { - reply->writeInt32(MEDIA_TRACK_TYPE_AUDIO); - } else if (mType == TYPE_VIDEO) { - reply->writeInt32(MEDIA_TRACK_TYPE_VIDEO); - } else if (mType == TYPE_SUBS) { - reply->writeInt32(MEDIA_TRACK_TYPE_SUBTITLE); - } else { - reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN); - } +size_t M3UParser::MediaGroup::countTracks() const { + return mMediaItems.size(); +} - const Media &item = mMediaItems.itemAt(i); - const char *lang = item.mLanguage.empty() ? "und" : item.mLanguage.c_str(); - reply->writeString16(String16(lang)); +sp<AMessage> M3UParser::MediaGroup::getTrackInfo(size_t index) const { + if (index >= mMediaItems.size()) { + return NULL; + } - if (mType == TYPE_SUBS) { - // TO-DO: pass in a MediaFormat instead - reply->writeInt32(!!(item.mFlags & MediaGroup::FLAG_AUTOSELECT)); - reply->writeInt32(!!(item.mFlags & MediaGroup::FLAG_DEFAULT)); - reply->writeInt32(!!(item.mFlags & MediaGroup::FLAG_FORCED)); - } + sp<AMessage> format = new AMessage(); + + int32_t trackType; + if (mType == TYPE_AUDIO) { + trackType = MEDIA_TRACK_TYPE_AUDIO; + } else if (mType == TYPE_VIDEO) { + trackType = MEDIA_TRACK_TYPE_VIDEO; + } else if (mType == TYPE_SUBS) { + trackType = MEDIA_TRACK_TYPE_SUBTITLE; + } else { + trackType = MEDIA_TRACK_TYPE_UNKNOWN; + } + format->setInt32("type", trackType); + + const Media &item = mMediaItems.itemAt(index); + const char *lang = item.mLanguage.empty() ? "und" : item.mLanguage.c_str(); + format->setString("language", lang); + + if (mType == TYPE_SUBS) { + // TO-DO: pass in a MediaFormat instead + format->setString("mime", MEDIA_MIMETYPE_TEXT_VTT); + format->setInt32("auto", !!(item.mFlags & MediaGroup::FLAG_AUTOSELECT)); + format->setInt32("default", !!(item.mFlags & MediaGroup::FLAG_DEFAULT)); + format->setInt32("forced", !!(item.mFlags & MediaGroup::FLAG_FORCED)); } -} -size_t M3UParser::MediaGroup::countTracks() const { - return mMediaItems.size(); + return format; } bool M3UParser::MediaGroup::getActiveURI(AString *uri) const { @@ -319,17 +327,24 @@ status_t M3UParser::selectTrack(size_t index, bool select) { return INVALID_OPERATION; } -status_t M3UParser::getTrackInfo(Parcel* reply) const { +size_t M3UParser::getTrackCount() const { size_t trackCount = 0; for (size_t i = 0; i < mMediaGroups.size(); ++i) { trackCount += mMediaGroups.valueAt(i)->countTracks(); } - reply->writeInt32(trackCount); + return trackCount; +} - for (size_t i = 0; i < mMediaGroups.size(); ++i) { - mMediaGroups.valueAt(i)->getTrackInfo(reply); +sp<AMessage> M3UParser::getTrackInfo(size_t index) const { + for (size_t i = 0, ii = index; i < mMediaGroups.size(); ++i) { + sp<MediaGroup> group = mMediaGroups.valueAt(i); + size_t tracks = group->countTracks(); + if (ii < tracks) { + return group->getTrackInfo(ii); + } + ii -= tracks; } - return OK; + return NULL; } ssize_t M3UParser::getSelectedIndex() const { diff --git a/media/libstagefright/httplive/M3UParser.h b/media/libstagefright/httplive/M3UParser.h index ccd6556..fe9fb9d 100644 --- a/media/libstagefright/httplive/M3UParser.h +++ b/media/libstagefright/httplive/M3UParser.h @@ -42,7 +42,8 @@ struct M3UParser : public RefBase { void pickRandomMediaItems(); status_t selectTrack(size_t index, bool select); - status_t getTrackInfo(Parcel* reply) const; + size_t getTrackCount() const; + sp<AMessage> getTrackInfo(size_t index) const; ssize_t getSelectedIndex() const; bool getTypeURI(size_t index, const char *key, AString *uri) const; diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp index f7abf01..3c8f03e 100644 --- a/media/libstagefright/mpeg2ts/ESQueue.cpp +++ b/media/libstagefright/mpeg2ts/ESQueue.cpp @@ -777,6 +777,12 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() { unsigned nalType = mBuffer->data()[pos.nalOffset] & 0x1f; + if (nalType == 6) { + sp<ABuffer> sei = new ABuffer(pos.nalSize); + memcpy(sei->data(), mBuffer->data() + pos.nalOffset, pos.nalSize); + accessUnit->meta()->setBuffer("sei", sei); + } + #if !LOG_NDEBUG char tmp[128]; sprintf(tmp, "0x%02x", nalType); diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index c0daa08..d6390b1 100755 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -5139,7 +5139,7 @@ reacquire_wakelock: sleepUs = kRecordThreadSleepUs; } if (framesRead <= 0) { - continue; + goto unlock; } ALOG_ASSERT(framesRead > 0); @@ -5147,10 +5147,12 @@ reacquire_wakelock: (void) mTeeSink->write(&mRsmpInBuffer[rear * mChannelCount], framesRead); } // If destination is non-contiguous, we now correct for reading past end of buffer. - size_t part1 = mRsmpInFramesP2 - rear; - if ((size_t) framesRead > part1) { - memcpy(mRsmpInBuffer, &mRsmpInBuffer[mRsmpInFramesP2 * mChannelCount], - (framesRead - part1) * mFrameSize); + { + size_t part1 = mRsmpInFramesP2 - rear; + if ((size_t) framesRead > part1) { + memcpy(mRsmpInBuffer, &mRsmpInBuffer[mRsmpInFramesP2 * mChannelCount], + (framesRead - part1) * mFrameSize); + } } rear = mRsmpInRear += framesRead; @@ -5358,6 +5360,7 @@ reacquire_wakelock: } +unlock: // enable changes in effect chain unlockEffectChains(effectChains); // effectChains doesn't need to be cleared, since it is cleared by destructor at scope end diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index 4e8a058..1e906ad 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -223,6 +223,8 @@ AudioFlinger::ThreadBase::TrackBase::~TrackBase() // relying on the automatic clear() at end of scope. mClient.clear(); } + // flush the binder command buffer + IPCThreadState::self()->flushCommands(); } // AudioBufferProvider interface @@ -432,8 +434,6 @@ AudioFlinger::PlaybackThread::Track::~Track() // This prevents that leak. if (mSharedBuffer != 0) { mSharedBuffer.clear(); - // flush the binder command buffer - IPCThreadState::self()->flushCommands(); } } diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 9fd35e1..73eccbf 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -261,32 +261,20 @@ status_t CameraService::generateShimMetadata(int cameraId, /*out*/CameraMetadata return ret; } - ssize_t index = -1; - { // Scope for service lock - Mutex::Autolock lock(mServiceLock); - index = mShimParams.indexOfKey(cameraId); - // Release service lock so initializeShimMetadata can be called correctly. - } - - if (index < 0) { - int64_t token = IPCThreadState::self()->clearCallingIdentity(); - ret = initializeShimMetadata(cameraId); - IPCThreadState::self()->restoreCallingIdentity(token); - if (ret != OK) { - return ret; - } + CameraParameters shimParams; + if ((ret = getLegacyParametersLazy(cameraId, /*out*/&shimParams)) != OK) { + // Error logged by callee + return ret; } Vector<Size> sizes; + Vector<Size> jpegSizes; Vector<int32_t> formats; const char* supportedPreviewFormats; - { // Scope for service lock - Mutex::Autolock lock(mServiceLock); - index = mShimParams.indexOfKey(cameraId); - - mShimParams[index].getSupportedPreviewSizes(/*out*/sizes); - - mShimParams[index].getSupportedPreviewFormats(/*out*/formats); + { + shimParams.getSupportedPreviewSizes(/*out*/sizes); + shimParams.getSupportedPreviewFormats(/*out*/formats); + shimParams.getSupportedPictureSizes(/*out*/jpegSizes); } // Always include IMPLEMENTATION_DEFINED @@ -295,21 +283,29 @@ status_t CameraService::generateShimMetadata(int cameraId, /*out*/CameraMetadata const size_t INTS_PER_CONFIG = 4; // Build available stream configurations metadata - size_t streamConfigSize = sizes.size() * formats.size() * INTS_PER_CONFIG; - int32_t streamConfigs[streamConfigSize]; - size_t configIndex = 0; + size_t streamConfigSize = (sizes.size() * formats.size() + jpegSizes.size()) * INTS_PER_CONFIG; + + Vector<int32_t> streamConfigs; + streamConfigs.setCapacity(streamConfigSize); + for (size_t i = 0; i < formats.size(); ++i) { for (size_t j = 0; j < sizes.size(); ++j) { - streamConfigs[configIndex++] = formats[i]; - streamConfigs[configIndex++] = sizes[j].width; - streamConfigs[configIndex++] = sizes[j].height; - streamConfigs[configIndex++] = - ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT; + streamConfigs.add(formats[i]); + streamConfigs.add(sizes[j].width); + streamConfigs.add(sizes[j].height); + streamConfigs.add(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT); } } + for (size_t i = 0; i < jpegSizes.size(); ++i) { + streamConfigs.add(HAL_PIXEL_FORMAT_BLOB); + streamConfigs.add(jpegSizes[i].width); + streamConfigs.add(jpegSizes[i].height); + streamConfigs.add(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT); + } + if ((ret = shimInfo.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, - streamConfigs, streamConfigSize)) != OK) { + streamConfigs.array(), streamConfigSize)) != OK) { return ret; } @@ -470,6 +466,7 @@ status_t CameraService::initializeShimMetadata(int cameraId) { int uid = getCallingUid(); status_t ret = validateConnect(cameraId, uid); if (ret != OK) { + // Error already logged by callee return ret; } @@ -492,6 +489,7 @@ status_t CameraService::initializeShimMetadata(int cameraId) { client); if (ret != OK) { + // Error already logged by callee return ret; } } @@ -513,6 +511,52 @@ status_t CameraService::initializeShimMetadata(int cameraId) { return OK; } +status_t CameraService::getLegacyParametersLazy(int cameraId, + /*out*/ + CameraParameters* parameters) { + + ALOGV("%s: for cameraId: %d", __FUNCTION__, cameraId); + + status_t ret = 0; + + if (parameters == NULL) { + ALOGE("%s: parameters must not be null", __FUNCTION__); + return BAD_VALUE; + } + + ssize_t index = -1; + { // Scope for service lock + Mutex::Autolock lock(mServiceLock); + index = mShimParams.indexOfKey(cameraId); + // Release service lock so initializeShimMetadata can be called correctly. + + if (index >= 0) { + *parameters = mShimParams[index]; + } + } + + if (index < 0) { + int64_t token = IPCThreadState::self()->clearCallingIdentity(); + ret = initializeShimMetadata(cameraId); + IPCThreadState::self()->restoreCallingIdentity(token); + if (ret != OK) { + // Error already logged by callee + return ret; + } + + { // Scope for service lock + Mutex::Autolock lock(mServiceLock); + index = mShimParams.indexOfKey(cameraId); + + LOG_ALWAYS_FATAL_IF(index < 0, "index should have been initialized"); + + *parameters = mShimParams[index]; + } + } + + return OK; +} + status_t CameraService::validateConnect(int cameraId, /*inout*/ int& clientUid) const { @@ -780,8 +824,8 @@ status_t CameraService::connectPro( case CAMERA_DEVICE_API_VERSION_3_0: case CAMERA_DEVICE_API_VERSION_3_1: case CAMERA_DEVICE_API_VERSION_3_2: - client = new ProCamera2Client(this, cameraCb, String16(), - cameraId, facing, callingPid, USE_CALLING_UID, getpid()); + client = new ProCamera2Client(this, cameraCb, clientPackageName, + cameraId, facing, callingPid, clientUid, getpid()); break; case -1: ALOGE("Invalid camera id %d", cameraId); @@ -860,8 +904,8 @@ status_t CameraService::connectDevice( case CAMERA_DEVICE_API_VERSION_3_0: case CAMERA_DEVICE_API_VERSION_3_1: case CAMERA_DEVICE_API_VERSION_3_2: - client = new CameraDeviceClient(this, cameraCb, String16(), - cameraId, facing, callingPid, USE_CALLING_UID, getpid()); + client = new CameraDeviceClient(this, cameraCb, clientPackageName, + cameraId, facing, callingPid, clientUid, getpid()); break; case -1: ALOGE("Invalid camera id %d", cameraId); @@ -950,6 +994,78 @@ status_t CameraService::removeListener( return BAD_VALUE; } +status_t CameraService::getLegacyParameters( + int cameraId, + /*out*/ + String16* parameters) { + ALOGV("%s: for camera ID = %d", __FUNCTION__, cameraId); + + if (parameters == NULL) { + ALOGE("%s: parameters must not be null", __FUNCTION__); + return BAD_VALUE; + } + + status_t ret = 0; + + CameraParameters shimParams; + if ((ret = getLegacyParametersLazy(cameraId, /*out*/&shimParams)) != OK) { + // Error logged by caller + return ret; + } + + String8 shimParamsString8 = shimParams.flatten(); + String16 shimParamsString16 = String16(shimParamsString8); + + *parameters = shimParamsString16; + + return OK; +} + +status_t CameraService::supportsCameraApi(int cameraId, int apiVersion) { + ALOGV("%s: for camera ID = %d", __FUNCTION__, cameraId); + + switch (apiVersion) { + case API_VERSION_1: + case API_VERSION_2: + break; + default: + ALOGE("%s: Bad API version %d", __FUNCTION__, apiVersion); + return BAD_VALUE; + } + + int facing = -1; + int deviceVersion = getDeviceVersion(cameraId, &facing); + + switch(deviceVersion) { + case CAMERA_DEVICE_API_VERSION_1_0: + case CAMERA_DEVICE_API_VERSION_2_0: + case CAMERA_DEVICE_API_VERSION_2_1: + case CAMERA_DEVICE_API_VERSION_3_0: + case CAMERA_DEVICE_API_VERSION_3_1: + if (apiVersion == API_VERSION_2) { + ALOGV("%s: Camera id %d uses HAL prior to HAL3.2, doesn't support api2 without shim", + __FUNCTION__, cameraId); + return -EOPNOTSUPP; + } else { // if (apiVersion == API_VERSION_1) { + ALOGV("%s: Camera id %d uses older HAL before 3.2, but api1 is always supported", + __FUNCTION__, cameraId); + return OK; + } + case CAMERA_DEVICE_API_VERSION_3_2: + ALOGV("%s: Camera id %d uses HAL3.2 or newer, supports api1/api2 directly", + __FUNCTION__, cameraId); + return OK; + case -1: + ALOGE("%s: Invalid camera id %d", __FUNCTION__, cameraId); + return BAD_VALUE; + default: + ALOGE("%s: Unknown camera device HAL version: %d", __FUNCTION__, deviceVersion); + return INVALID_OPERATION; + } + + return OK; +} + void CameraService::removeClientByRemote(const wp<IBinder>& remoteBinder) { int callingPid = getCallingPid(); LOG1("CameraService::removeClientByRemote E (pid %d)", callingPid); @@ -1079,6 +1195,7 @@ status_t CameraService::onTransact( switch (code) { case BnCameraService::CONNECT: case BnCameraService::CONNECT_PRO: + case BnCameraService::CONNECT_DEVICE: const int pid = getCallingPid(); const int self_pid = getpid(); if (pid != self_pid) { diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index ee39d52..b2b65b8 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -100,6 +100,15 @@ public: virtual status_t removeListener( const sp<ICameraServiceListener>& listener); + virtual status_t getLegacyParameters( + int cameraId, + /*out*/ + String16* parameters); + + // OK = supports api of that version, -EOPNOTSUPP = does not support + virtual status_t supportsCameraApi( + int cameraId, int apiVersion); + // Extra permissions checks virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); @@ -414,6 +423,14 @@ private: status_t initializeShimMetadata(int cameraId); /** + * Get the cached CameraParameters for the camera. If they haven't been + * cached yet, then initialize them for the first time. + * + * Returns OK on success, or a negative error code. + */ + status_t getLegacyParametersLazy(int cameraId, /*out*/CameraParameters* parameters); + + /** * Generate the CameraCharacteristics metadata required by the Camera2 API * from the available HAL1 CameraParameters and CameraInfo. * |