OSDN Git Service

Camera2: fix 4K recording
authorYin-Chia Yeh <yinchiayeh@google.com>
Fri, 12 Sep 2014 21:50:27 +0000 (14:50 -0700)
committerYin-Chia Yeh <yinchiayeh@google.com>
Sat, 13 Sep 2014 18:54:18 +0000 (11:54 -0700)
Bug: 17484683
Change-Id: I09bb12698057555329286c777102b9b310452fb3

services/camera/libcameraservice/api1/Camera2Client.cpp
services/camera/libcameraservice/api1/Camera2Client.h
services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
services/camera/libcameraservice/api1/client2/StreamingProcessor.h

index 6f4a507..10038c5 100644 (file)
@@ -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 &params, 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 &params) {
+    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";
 
index f5c3a30..d68bb29 100644 (file)
@@ -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 &params);
 };
 
 }; // namespace android
index ab0af0d..9e7fff8 100644 (file)
@@ -318,6 +318,44 @@ status_t StreamingProcessor::updateRecordingRequest(const Parameters &params) {
     return OK;
 }
 
+status_t StreamingProcessor::recordingStreamNeedsUpdate(
+        const Parameters &params, 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,
+            &currentWidth, &currentHeight, 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 &params) {
     ATRACE_CALL();
     status_t res;
index 833bb8f..8466af4 100644 (file)
@@ -54,6 +54,9 @@ class StreamingProcessor:
 
     status_t setRecordingBufferCount(size_t count);
     status_t updateRecordingRequest(const Parameters &params);
+    // If needsUpdate is set to true, a updateRecordingStream call with params will recreate
+    // recording stream
+    status_t recordingStreamNeedsUpdate(const Parameters &params, bool *needsUpdate);
     status_t updateRecordingStream(const Parameters &params);
     status_t deleteRecordingStream();
     int getRecordingStreamId() const;