diff options
8 files changed, 197 insertions, 32 deletions
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 5f566ca..3720085 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -1286,12 +1286,6 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { CHECK(msg->findInt32("streamMask", (int32_t *)&streamMask)); CHECK(msg->findInt32("resumeMask", (int32_t *)&resumeMask)); - for (size_t i = 0; i < kMaxStreams; ++i) { - if (streamMask & indexToType(i)) { - CHECK(msg->findString(mStreams[i].uriKey().c_str(), &mStreams[i].mUri)); - } - } - int64_t timeUs; int32_t pickTrack; bool switching = false; @@ -1307,7 +1301,20 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { mRealTimeBaseUs = ALooper::GetNowUs() - timeUs; } + for (size_t i = 0; i < kMaxStreams; ++i) { + if (streamMask & indexToType(i)) { + if (switching) { + CHECK(msg->findString(mStreams[i].uriKey().c_str(), &mStreams[i].mNewUri)); + } else { + CHECK(msg->findString(mStreams[i].uriKey().c_str(), &mStreams[i].mUri)); + } + } + } + mNewStreamMask = streamMask | resumeMask; + if (switching) { + mSwapMask = mStreamMask & ~resumeMask; + } // Of all existing fetchers: // * Resume fetchers that are still needed and assign them original packet sources. @@ -1357,7 +1364,7 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { } AString uri; - uri = mStreams[i].mUri; + uri = switching ? mStreams[i].mNewUri : mStreams[i].mUri; sp<PlaylistFetcher> fetcher = addFetcher(uri.c_str()); CHECK(fetcher != NULL); @@ -1370,7 +1377,8 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { // TRICKY: looping from i as earlier streams are already removed from streamMask for (size_t j = i; j < kMaxStreams; ++j) { - if ((streamMask & indexToType(j)) && uri == mStreams[j].mUri) { + const AString &streamUri = switching ? mStreams[j].mNewUri : mStreams[j].mUri; + if ((streamMask & indexToType(j)) && uri == streamUri) { sources[j] = mPacketSources.valueFor(indexToType(j)); if (timeUs >= 0) { @@ -1459,7 +1467,6 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { mReconfigurationInProgress = false; if (switching) { mSwitchInProgress = true; - mSwapMask = streamMask; } else { mStreamMask = mNewStreamMask; } @@ -1478,6 +1485,15 @@ void LiveSession::onSwapped(const sp<AMessage> &msg) { int32_t stream; CHECK(msg->findInt32("stream", &stream)); + + ssize_t idx = typeToIndex(stream); + CHECK(idx >= 0); + if ((mNewStreamMask & stream) && mStreams[idx].mNewUri.empty()) { + ALOGW("swapping stream type %d %s to empty stream", stream, mStreams[idx].mUri.c_str()); + } + mStreams[idx].mUri = mStreams[idx].mNewUri; + mStreams[idx].mNewUri.clear(); + mSwapMask &= ~stream; if (mSwapMask != 0) { return; @@ -1489,6 +1505,15 @@ void LiveSession::onSwapped(const sp<AMessage> &msg) { StreamType extraStream = (StreamType) (extraStreams & ~(extraStreams - 1)); swapPacketSource(extraStream); extraStreams &= ~extraStream; + + idx = typeToIndex(extraStream); + CHECK(idx >= 0); + if (mStreams[idx].mNewUri.empty()) { + ALOGW("swapping extra stream type %d %s to empty stream", + extraStream, mStreams[idx].mUri.c_str()); + } + mStreams[idx].mUri = mStreams[idx].mNewUri; + mStreams[idx].mNewUri.clear(); } tryToFinishBandwidthSwitch(); @@ -1569,6 +1594,28 @@ void LiveSession::cancelBandwidthSwitch() { mSwitchGeneration++; mSwitchInProgress = false; mSwapMask = 0; + + for (size_t i = 0; i < mFetcherInfos.size(); ++i) { + FetcherInfo& info = mFetcherInfos.editValueAt(i); + if (info.mToBeRemoved) { + info.mToBeRemoved = false; + } + } + + for (size_t i = 0; i < kMaxStreams; ++i) { + if (!mStreams[i].mNewUri.empty()) { + ssize_t j = mFetcherInfos.indexOfKey(mStreams[i].mNewUri); + if (j < 0) { + mStreams[i].mNewUri.clear(); + continue; + } + + const FetcherInfo &info = mFetcherInfos.valueAt(j); + info.mFetcher->stopAsync(); + mFetcherInfos.removeItemsAt(j); + mStreams[i].mNewUri.clear(); + } + } } bool LiveSession::canSwitchBandwidthTo(size_t bandwidthIndex) { diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index 26df543..6be86cf 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -126,7 +126,7 @@ private: struct StreamItem { const char *mType; - AString mUri; + AString mUri, mNewUri; size_t mCurDiscontinuitySeq; int64_t mLastDequeuedTimeUs; int64_t mLastSampleDurationUs; diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp index 6f4a507..10038c5 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.cpp +++ b/services/camera/libcameraservice/api1/Camera2Client.cpp @@ -921,6 +921,13 @@ void Camera2Client::stopPreviewL() { "stop preview: %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); } + { + // Ideally we should recover the override after recording stopped, but + // right now recording stream will live until here, so we are forced to + // recover here. TODO: find a better way to handle that (b/17495165) + SharedParameters::Lock l(mParameters); + l.mParameters.recoverOverriddenJpegSize(); + } // no break case Parameters::WAITING_FOR_PREVIEW_WINDOW: { SharedParameters::Lock l(mParameters); @@ -1075,34 +1082,65 @@ status_t Camera2Client::startRecordingL(Parameters ¶ms, bool restart) { // and we can't fail record start without stagefright asserting. params.previewCallbackFlags = 0; - res = updateProcessorStream< - StreamingProcessor, - &StreamingProcessor::updateRecordingStream>(mStreamingProcessor, - params); + bool recordingStreamNeedsUpdate; + res = mStreamingProcessor->recordingStreamNeedsUpdate(params, &recordingStreamNeedsUpdate); if (res != OK) { - ALOGE("%s: Camera %d: Unable to update recording stream: %s (%d)", - __FUNCTION__, mCameraId, strerror(-res), res); + ALOGE("%s: Camera %d: Can't query recording stream", + __FUNCTION__, mCameraId); return res; } + if (recordingStreamNeedsUpdate) { + // Need to stop stream here in case updateRecordingStream fails + // Right now camera device cannot handle configureStream failure gracefully + // when device is streaming + res = mStreamingProcessor->stopStream(); + if (res != OK) { + ALOGE("%s: Camera %d: Can't stop streaming to update record stream", + __FUNCTION__, mCameraId); + return res; + } + res = mDevice->waitUntilDrained(); + if (res != OK) { + ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + } + res = updateProcessorStream< + StreamingProcessor, + &StreamingProcessor::updateRecordingStream>(mStreamingProcessor, + params); + + // updateRecordingStream might trigger a configureStream call and device might fail + // configureStream due to jpeg size > video size. Try again with jpeg size overridden + // to video size. + // TODO: This may not be needed after we add stop streaming above. Remove that if + // it's the case. + if (res == BAD_VALUE) { + overrideVideoSnapshotSize(params); + res = updateProcessorStream< + StreamingProcessor, + &StreamingProcessor::updateRecordingStream>(mStreamingProcessor, + params); + } + if (res != OK) { + ALOGE("%s: Camera %d: Unable to update recording stream: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + return res; + } + } + Vector<int32_t> outputStreams; outputStreams.push(getPreviewStreamId()); outputStreams.push(getRecordingStreamId()); res = mStreamingProcessor->startStream(StreamingProcessor::RECORD, outputStreams); - // try to reconfigure jpeg to video size if configureStreams failed - if (res == BAD_VALUE) { - ALOGV("%s: Camera %d: configure still size to video size before recording" - , __FUNCTION__, mCameraId); - params.overrideJpegSizeByVideoSize(); - res = updateProcessorStream(mJpegProcessor, params); - if (res != OK) { - ALOGE("%s: Camera %d: Can't configure still image size to video size: %s (%d)", - __FUNCTION__, mCameraId, strerror(-res), res); - return res; - } + // startStream might trigger a configureStream call and device might fail + // configureStream due to jpeg size > video size. Try again with jpeg size overridden + // to video size. + if (res == BAD_VALUE) { + overrideVideoSnapshotSize(params); res = mStreamingProcessor->startStream(StreamingProcessor::RECORD, outputStreams); } @@ -1146,7 +1184,6 @@ void Camera2Client::stopRecording() { mCameraService->playSound(CameraService::SOUND_RECORDING); - l.mParameters.recoverOverriddenJpegSize(); res = startPreviewL(l.mParameters, true); if (res != OK) { ALOGE("%s: Camera %d: Unable to return to preview", @@ -1923,6 +1960,18 @@ status_t Camera2Client::updateProcessorStream(sp<ProcessorT> processor, return res; } +status_t Camera2Client::overrideVideoSnapshotSize(Parameters ¶ms) { + ALOGV("%s: Camera %d: configure still size to video size before recording" + , __FUNCTION__, mCameraId); + params.overrideJpegSizeByVideoSize(); + status_t res = updateProcessorStream(mJpegProcessor, params); + if (res != OK) { + ALOGE("%s: Camera %d: Can't override video snapshot size to video size: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + } + return res; +} + const char* Camera2Client::kAutofocusLabel = "autofocus"; const char* Camera2Client::kTakepictureLabel = "take_picture"; diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h index f5c3a30..d68bb29 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.h +++ b/services/camera/libcameraservice/api1/Camera2Client.h @@ -208,6 +208,9 @@ private: // Wait until the camera device has received the latest control settings status_t syncWithDevice(); + + // Video snapshot jpeg size overriding helper function + status_t overrideVideoSnapshotSize(Parameters ¶ms); }; }; // namespace android diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp index 8d00590..ed9137f 100644 --- a/services/camera/libcameraservice/api1/client2/Parameters.cpp +++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp @@ -76,9 +76,29 @@ status_t Parameters::initialize(const CameraMetadata *info, int deviceVersion) { res = getFilteredSizes(MAX_VIDEO_SIZE, &availableVideoSizes); if (res != OK) return res; - // TODO: Pick more intelligently - previewWidth = availablePreviewSizes[0].width; - previewHeight = availablePreviewSizes[0].height; + // Select initial preview and video size that's under the initial bound and + // on the list of both preview and recording sizes + previewWidth = 0; + previewHeight = 0; + for (size_t i = 0 ; i < availablePreviewSizes.size(); i++) { + int newWidth = availablePreviewSizes[i].width; + int newHeight = availablePreviewSizes[i].height; + if (newWidth >= previewWidth && newHeight >= previewHeight && + newWidth <= MAX_INITIAL_PREVIEW_WIDTH && + newHeight <= MAX_INITIAL_PREVIEW_HEIGHT) { + for (size_t j = 0; j < availableVideoSizes.size(); j++) { + if (availableVideoSizes[j].width == newWidth && + availableVideoSizes[j].height == newHeight) { + previewWidth = newWidth; + previewHeight = newHeight; + } + } + } + } + if (previewWidth == 0) { + ALOGE("%s: No initial preview size can be found!", __FUNCTION__); + return BAD_VALUE; + } videoWidth = previewWidth; videoHeight = previewHeight; diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h index 5e6e6ab..815cc55 100644 --- a/services/camera/libcameraservice/api1/client2/Parameters.h +++ b/services/camera/libcameraservice/api1/client2/Parameters.h @@ -179,8 +179,13 @@ struct Parameters { // Number of zoom steps to simulate static const unsigned int NUM_ZOOM_STEPS = 100; // Max preview size allowed + // This is set to a 1:1 value to allow for any aspect ratio that has + // a max long side of 1920 pixels static const unsigned int MAX_PREVIEW_WIDTH = 1920; - static const unsigned int MAX_PREVIEW_HEIGHT = 1080; + static const unsigned int MAX_PREVIEW_HEIGHT = 1920; + // Initial max preview/recording size bound + static const int MAX_INITIAL_PREVIEW_WIDTH = 1920; + static const int MAX_INITIAL_PREVIEW_HEIGHT = 1080; // Aspect ratio tolerance static const float ASPECT_RATIO_TOLERANCE = 0.001; diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp index ab0af0d..9e7fff8 100644 --- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp +++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp @@ -318,6 +318,44 @@ status_t StreamingProcessor::updateRecordingRequest(const Parameters ¶ms) { return OK; } +status_t StreamingProcessor::recordingStreamNeedsUpdate( + const Parameters ¶ms, bool *needsUpdate) { + status_t res; + + if (needsUpdate == 0) { + ALOGE("%s: Camera %d: invalid argument", __FUNCTION__, mId); + return INVALID_OPERATION; + } + + if (mRecordingStreamId == NO_STREAM) { + *needsUpdate = true; + return OK; + } + + sp<CameraDeviceBase> device = mDevice.promote(); + if (device == 0) { + ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId); + return INVALID_OPERATION; + } + + uint32_t currentWidth, currentHeight; + res = device->getStreamInfo(mRecordingStreamId, + ¤tWidth, ¤tHeight, 0); + if (res != OK) { + ALOGE("%s: Camera %d: Error querying recording output stream info: " + "%s (%d)", __FUNCTION__, mId, + strerror(-res), res); + return res; + } + + if (mRecordingConsumer == 0 || currentWidth != (uint32_t)params.videoWidth || + currentHeight != (uint32_t)params.videoHeight) { + *needsUpdate = true; + } + *needsUpdate = false; + return res; +} + status_t StreamingProcessor::updateRecordingStream(const Parameters ¶ms) { ATRACE_CALL(); status_t res; diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h index 833bb8f..8466af4 100644 --- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h +++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h @@ -54,6 +54,9 @@ class StreamingProcessor: status_t setRecordingBufferCount(size_t count); status_t updateRecordingRequest(const Parameters ¶ms); + // If needsUpdate is set to true, a updateRecordingStream call with params will recreate + // recording stream + status_t recordingStreamNeedsUpdate(const Parameters ¶ms, bool *needsUpdate); status_t updateRecordingStream(const Parameters ¶ms); status_t deleteRecordingStream(); int getRecordingStreamId() const; |