diff options
Diffstat (limited to 'services')
22 files changed, 401 insertions, 43 deletions
diff --git a/services/audioflinger/AudioStreamOut.cpp b/services/audioflinger/AudioStreamOut.cpp index f953cc8..b6d1be7 100644 --- a/services/audioflinger/AudioStreamOut.cpp +++ b/services/audioflinger/AudioStreamOut.cpp @@ -143,9 +143,19 @@ status_t AudioStreamOut::open(      return status;  } -size_t AudioStreamOut::getFrameSize() +audio_format_t AudioStreamOut::getFormat() const  { -    return mHalFrameSize; +    return stream->common.get_format(&stream->common); +} + +uint32_t AudioStreamOut::getSampleRate() const +{ +    return stream->common.get_sample_rate(&stream->common); +} + +audio_channel_mask_t AudioStreamOut::getChannelMask() const +{ +    return stream->common.get_channels(&stream->common);  }  int AudioStreamOut::flush() @@ -165,7 +175,6 @@ int AudioStreamOut::standby()      ALOG_ASSERT(stream != NULL);      mRenderPosition = 0;      mFramesWrittenAtStandby = mFramesWritten; -    ALOGI("AudioStreamOut::standby(), mFramesWrittenAtStandby = %llu", mFramesWrittenAtStandby);      return stream->common.standby(&stream->common);  } diff --git a/services/audioflinger/AudioStreamOut.h b/services/audioflinger/AudioStreamOut.h index 761e771..06a2277 100644 --- a/services/audioflinger/AudioStreamOut.h +++ b/services/audioflinger/AudioStreamOut.h @@ -75,7 +75,28 @@ public:      */      virtual ssize_t write(const void *buffer, size_t bytes); -    virtual size_t getFrameSize(); +    /** +     * @return frame size from the perspective of the application and the AudioFlinger. +     */ +    virtual size_t getFrameSize() const { return mHalFrameSize; } + +    /** +     * @return format from the perspective of the application and the AudioFlinger. +     */ +    virtual audio_format_t getFormat() const; + +    /** +     * The HAL may be running at a higher sample rate if, for example, playing wrapped EAC3. +     * @return sample rate from the perspective of the application and the AudioFlinger. +     */ +    virtual uint32_t getSampleRate() const; + +    /** +     * The HAL is in stereo mode when playing multi-channel compressed audio over HDMI. +     * @return channel mask from the perspective of the application and the AudioFlinger. +     */ +    virtual audio_channel_mask_t getChannelMask() const; +      virtual status_t flush();      virtual status_t standby(); diff --git a/services/audioflinger/SpdifStreamOut.cpp b/services/audioflinger/SpdifStreamOut.cpp index 6af7bce..6b6f5db 100644 --- a/services/audioflinger/SpdifStreamOut.cpp +++ b/services/audioflinger/SpdifStreamOut.cpp @@ -37,6 +37,9 @@ SpdifStreamOut::SpdifStreamOut(AudioHwDevice *dev,              audio_format_t format)          : AudioStreamOut(dev,flags)          , mSpdifEncoder(this, format) +        , mApplicationFormat(AUDIO_FORMAT_DEFAULT) +        , mApplicationSampleRate(0) +        , mApplicationChannelMask(0)  {  } @@ -48,6 +51,10 @@ status_t SpdifStreamOut::open(  {      struct audio_config customConfig = *config; +    mApplicationFormat = config->format; +    mApplicationSampleRate = config->sample_rate; +    mApplicationChannelMask = config->channel_mask; +      // Some data bursts run at a higher sample rate.      // TODO Move this into the audio_utils as a static method.      switch(config->format) { @@ -106,20 +113,15 @@ int SpdifStreamOut::standby()      return AudioStreamOut::standby();  } -size_t SpdifStreamOut::getFrameSize() -{ -    return sizeof(int8_t); -} -  ssize_t SpdifStreamOut::writeDataBurst(const void* buffer, size_t bytes)  {      return AudioStreamOut::write(buffer, bytes);  } -ssize_t SpdifStreamOut::write(const void* buffer, size_t bytes) +ssize_t SpdifStreamOut::write(const void* buffer, size_t numBytes)  {      // Write to SPDIF wrapper. It will call back to writeDataBurst(). -    return mSpdifEncoder.write(buffer, bytes); +    return mSpdifEncoder.write(buffer, numBytes);  }  } // namespace android diff --git a/services/audioflinger/SpdifStreamOut.h b/services/audioflinger/SpdifStreamOut.h index a61a7bd..c870250 100644 --- a/services/audioflinger/SpdifStreamOut.h +++ b/services/audioflinger/SpdifStreamOut.h @@ -64,7 +64,27 @@ public:      */      virtual ssize_t write(const void* buffer, size_t bytes); -    virtual size_t getFrameSize(); +    /** +     * @return frame size from the perspective of the application and the AudioFlinger. +     */ +    virtual size_t getFrameSize() const { return sizeof(int8_t); } + +    /** +     * @return format from the perspective of the application and the AudioFlinger. +     */ +    virtual audio_format_t getFormat() const { return mApplicationFormat; } + +    /** +     * The HAL may be running at a higher sample rate if, for example, playing wrapped EAC3. +     * @return sample rate from the perspective of the application and the AudioFlinger. +     */ +    virtual uint32_t getSampleRate() const { return mApplicationSampleRate; } + +    /** +     * The HAL is in stereo mode when playing multi-channel compressed audio over HDMI. +     * @return channel mask from the perspective of the application and the AudioFlinger. +     */ +    virtual audio_channel_mask_t getChannelMask() const { return mApplicationChannelMask; }      virtual status_t flush();      virtual status_t standby(); @@ -89,6 +109,9 @@ private:      };      MySPDIFEncoder       mSpdifEncoder; +    audio_format_t       mApplicationFormat; +    uint32_t             mApplicationSampleRate; +    audio_channel_mask_t mApplicationChannelMask;      ssize_t  writeDataBurst(const void* data, size_t bytes);      ssize_t  writeInternal(const void* buffer, size_t bytes); diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index d9f1a83..c360051 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -2081,8 +2081,8 @@ int AudioFlinger::PlaybackThread::asyncCallback(stream_callback_event_t event,  void AudioFlinger::PlaybackThread::readOutputParameters_l()  {      // unfortunately we have no way of recovering from errors here, hence the LOG_ALWAYS_FATAL -    mSampleRate = mOutput->stream->common.get_sample_rate(&mOutput->stream->common); -    mChannelMask = mOutput->stream->common.get_channels(&mOutput->stream->common); +    mSampleRate = mOutput->getSampleRate(); +    mChannelMask = mOutput->getChannelMask();      if (!audio_is_output_channel(mChannelMask)) {          LOG_ALWAYS_FATAL("HAL channel mask %#x not valid for output", mChannelMask);      } @@ -2092,8 +2092,12 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l()                  mChannelMask);      }      mChannelCount = audio_channel_count_from_out_mask(mChannelMask); + +    // Get actual HAL format.      mHALFormat = mOutput->stream->common.get_format(&mOutput->stream->common); -    mFormat = mHALFormat; +    // Get format from the shim, which will be different than the HAL format +    // if playing compressed audio over HDMI passthrough. +    mFormat = mOutput->getFormat();      if (!audio_is_valid_format(mFormat)) {          LOG_ALWAYS_FATAL("HAL format %#x not valid for output", mFormat);      } @@ -4559,9 +4563,10 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep          // app does not call stop() and relies on underrun to stop:          // hence the test on (track->mRetryCount > 1).          // If retryCount<=1 then track is about to underrun and be removed. +        // Do not use a high threshold for compressed audio.          uint32_t minFrames;          if ((track->sharedBuffer() == 0) && !track->isStopping_1() && !track->isPausing() -            && (track->mRetryCount > 1)) { +            && (track->mRetryCount > 1) && audio_is_linear_pcm(mFormat)) {              minFrames = mNormalFrameCount;          } else {              minFrames = 1; @@ -4650,6 +4655,9 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep                      // it will then automatically call start() when data is available                      android_atomic_or(CBLK_DISABLED, &cblk->mFlags);                  } else if (last) { +                    ALOGW("pause because of UNDERRUN, framesReady = %zu," +                            "minFrames = %u, mFormat = %#x", +                            track->framesReady(), minFrames, mFormat);                      mixerStatus = MIXER_TRACKS_ENABLED;                      if (mHwSupportsPause && !mHwPaused && !mStandby) {                          doHwPause = true; diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk index 46b2725..a523656 100755 --- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk +++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk @@ -26,13 +26,8 @@ LOCAL_C_INCLUDES := \  LOCAL_SHARED_LIBRARIES := \      libaudiopolicyengineconfigurable  \      libparameter \ -    libicuuc \ -    liblog \ - -LOCAL_STATIC_LIBRARIES := \      libxmlserializer \ -    libpfw_utility \ -    libxml2 \ +    liblog \  LOCAL_MODULE_TAGS := optional  LOCAL_MODULE := libpolicy-subsystem diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp index e109595..36e99dd 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.cpp +++ b/services/camera/libcameraservice/api1/Camera2Client.cpp @@ -764,16 +764,22 @@ status_t Camera2Client::startPreviewL(Parameters ¶ms, bool restart) {      // first capture latency on HAL3 devices, and potentially on some HAL2      // devices. So create it unconditionally at preview start. As a drawback,      // this increases gralloc memory consumption for applications that don't -    // ever take a picture. +    // ever take a picture. Do not enter this mode when jpeg stream will slow +    // down preview.      // TODO: Find a better compromise, though this likely would involve HAL      // changes.      int lastJpegStreamId = mJpegProcessor->getStreamId(); -    res = updateProcessorStream(mJpegProcessor, params); -    if (res != OK) { -        ALOGE("%s: Camera %d: Can't pre-configure still image " -                "stream: %s (%d)", -                __FUNCTION__, mCameraId, strerror(-res), res); -        return res; +    // If jpeg stream will slow down preview, make sure we remove it before starting preview +    if (params.slowJpegMode) { +        mJpegProcessor->deleteStream(); +    } else { +        res = updateProcessorStream(mJpegProcessor, params); +        if (res != OK) { +            ALOGE("%s: Camera %d: Can't pre-configure still image " +                    "stream: %s (%d)", +                    __FUNCTION__, mCameraId, strerror(-res), res); +            return res; +        }      }      bool jpegStreamChanged = mJpegProcessor->getStreamId() != lastJpegStreamId; @@ -1453,9 +1459,12 @@ status_t Camera2Client::takePicture(int msgType) {          }          ALOGV("%s: Camera %d: Starting picture capture", __FUNCTION__, mCameraId); -          int lastJpegStreamId = mJpegProcessor->getStreamId(); -        res = updateProcessorStream(mJpegProcessor, l.mParameters); +        // slowJpegMode will create jpeg stream in CaptureSequencer before capturing +        if (!l.mParameters.slowJpegMode) { +            res = updateProcessorStream(mJpegProcessor, l.mParameters); +        } +          // If video snapshot fail to configureStream, try override video snapshot size to          // video size          if (res == BAD_VALUE && l.mParameters.state == Parameters::VIDEO_SNAPSHOT) { @@ -1943,6 +1952,39 @@ status_t Camera2Client::stopStream() {      return mStreamingProcessor->stopStream();  } +status_t Camera2Client::createJpegStreamL(Parameters ¶ms) { +    status_t res = OK; +    int lastJpegStreamId = mJpegProcessor->getStreamId(); +    if (lastJpegStreamId != NO_STREAM) { +        return INVALID_OPERATION; +    } + +    res = mStreamingProcessor->togglePauseStream(/*pause*/true); +    if (res != OK) { +        ALOGE("%s: Camera %d: Can't pause streaming: %s (%d)", +                __FUNCTION__, mCameraId, strerror(-res), res); +        return res; +    } + +    res = mDevice->flush(); +    if (res != OK) { +        ALOGE("%s: Camera %d: Unable flush device: %s (%d)", +                __FUNCTION__, mCameraId, strerror(-res), res); +        return res; +    } + +    // Ideally we don't need this, but current camera device +    // status tracking mechanism demands it. +    res = mDevice->waitUntilDrained(); +    if (res != OK) { +        ALOGE("%s: Camera %d: Waiting device drain failed: %s (%d)", +                __FUNCTION__, mCameraId, strerror(-res), res); +    } + +    res = updateProcessorStream(mJpegProcessor, params); +    return res; +} +  const int32_t Camera2Client::kPreviewRequestIdStart;  const int32_t Camera2Client::kPreviewRequestIdEnd;  const int32_t Camera2Client::kRecordingRequestIdStart; diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h index c288313..d50bf63 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.h +++ b/services/camera/libcameraservice/api1/Camera2Client.h @@ -129,6 +129,9 @@ public:      status_t stopStream(); +    // For the slowJpegMode to create jpeg stream when precapture sequence is done +    status_t createJpegStreamL(camera2::Parameters ¶ms); +      static size_t calculateBufferSize(int width, int height,              int format, int stride); @@ -145,6 +148,9 @@ public:      static const char* kAutofocusLabel;      static const char* kTakepictureLabel; +    // Used with stream IDs +    static const int NO_STREAM = -1; +  private:      /** ICamera interface-related private members */      typedef camera2::Parameters Parameters; @@ -177,9 +183,6 @@ private:      void     setPreviewCallbackFlagL(Parameters ¶ms, int flag);      status_t updateRequests(Parameters ¶ms); -    // Used with stream IDs -    static const int NO_STREAM = -1; -      template <typename ProcessorT>      status_t updateProcessorStream(sp<ProcessorT> processor, Parameters params);      template <typename ProcessorT, diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp index d847e0f..5f7fd74 100644 --- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp +++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp @@ -504,6 +504,17 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCapture(       *  - recording (if recording enabled)       */      outputStreams.push(client->getPreviewStreamId()); + +    int captureStreamId = client->getCaptureStreamId(); +    if (captureStreamId == Camera2Client::NO_STREAM) { +        res = client->createJpegStreamL(l.mParameters); +        if (res != OK || client->getCaptureStreamId() == Camera2Client::NO_STREAM) { +            ALOGE("%s: Camera %d: cannot create jpeg stream for slowJpeg mode: %s (%d)", +                  __FUNCTION__, client->getCameraId(), strerror(-res), res); +            return DONE; +        } +    } +      outputStreams.push(client->getCaptureStreamId());      if (l.mParameters.previewCallbackFlags & diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp index c3a6842..442eb75 100644 --- a/services/camera/libcameraservice/api1/client2/Parameters.cpp +++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp @@ -889,15 +889,30 @@ status_t Parameters::initialize(const CameraMetadata *info, int deviceVersion) {      previewCallbackOneShot = false;      previewCallbackSurface = false; +    Size maxJpegSize = getMaxSize(getAvailableJpegSizes()); +    int64_t minFrameDurationNs = getJpegStreamMinFrameDurationNs(maxJpegSize); + +    slowJpegMode = false; +    if (minFrameDurationNs > kSlowJpegModeThreshold) { +        slowJpegMode = true; +        // Slow jpeg devices does not support video snapshot without +        // slowing down preview. +        // TODO: support video size video snapshot only? +        params.set(CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED, +            CameraParameters::FALSE); +    } +      char value[PROPERTY_VALUE_MAX];      property_get("camera.disable_zsl_mode", value, "0"); -    if (!strcmp(value,"1")) { +    if (!strcmp(value,"1") || slowJpegMode) {          ALOGI("Camera %d: Disabling ZSL mode", cameraId);          zslMode = false;      } else {          zslMode = true;      } +    ALOGI("%s: zslMode: %d slowJpegMode %d", __FUNCTION__, zslMode, slowJpegMode); +      lightFx = LIGHTFX_NONE;      state = STOPPED; @@ -2778,6 +2793,17 @@ Parameters::Size Parameters::getMaxSizeForRatio(      return maxSize;  } +Parameters::Size Parameters::getMaxSize(const Vector<Parameters::Size> &sizes) { +    Size maxSize = {-1, -1}; +    for (size_t i = 0; i < sizes.size(); i++) { +        if (sizes[i].width > maxSize.width || +                (sizes[i].width == maxSize.width && sizes[i].height > maxSize.height )) { +            maxSize = sizes[i]; +        } +    } +    return maxSize; +} +  Vector<Parameters::StreamConfiguration> Parameters::getStreamConfigurations() {      const int STREAM_CONFIGURATION_SIZE = 4;      const int STREAM_FORMAT_OFFSET = 0; @@ -2792,7 +2818,7 @@ Vector<Parameters::StreamConfiguration> Parameters::getStreamConfigurations() {      camera_metadata_ro_entry_t availableStreamConfigs =                  staticInfo(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS); -    for (size_t i=0; i < availableStreamConfigs.count; i+= STREAM_CONFIGURATION_SIZE) { +    for (size_t i = 0; i < availableStreamConfigs.count; i+= STREAM_CONFIGURATION_SIZE) {          int32_t format = availableStreamConfigs.data.i32[i + STREAM_FORMAT_OFFSET];          int32_t width = availableStreamConfigs.data.i32[i + STREAM_WIDTH_OFFSET];          int32_t height = availableStreamConfigs.data.i32[i + STREAM_HEIGHT_OFFSET]; @@ -2803,11 +2829,52 @@ Vector<Parameters::StreamConfiguration> Parameters::getStreamConfigurations() {      return scs;  } +int64_t Parameters::getJpegStreamMinFrameDurationNs(Parameters::Size size) { +    if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) { +        const int STREAM_DURATION_SIZE = 4; +        const int STREAM_FORMAT_OFFSET = 0; +        const int STREAM_WIDTH_OFFSET = 1; +        const int STREAM_HEIGHT_OFFSET = 2; +        const int STREAM_DURATION_OFFSET = 3; +        camera_metadata_ro_entry_t availableStreamMinDurations = +                    staticInfo(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS); +        for (size_t i = 0; i < availableStreamMinDurations.count; i+= STREAM_DURATION_SIZE) { +            int64_t format = availableStreamMinDurations.data.i64[i + STREAM_FORMAT_OFFSET]; +            int64_t width = availableStreamMinDurations.data.i64[i + STREAM_WIDTH_OFFSET]; +            int64_t height = availableStreamMinDurations.data.i64[i + STREAM_HEIGHT_OFFSET]; +            int64_t duration = availableStreamMinDurations.data.i64[i + STREAM_DURATION_OFFSET]; +            if (format == HAL_PIXEL_FORMAT_BLOB && width == size.width && height == size.height) { +                return duration; +            } +        } +    } else { +        Vector<Size> availableJpegSizes = getAvailableJpegSizes(); +        size_t streamIdx = availableJpegSizes.size(); +        for (size_t i = 0; i < availableJpegSizes.size(); i++) { +            if (availableJpegSizes[i].width == size.width && +                    availableJpegSizes[i].height == size.height) { +                streamIdx = i; +                break; +            } +        } +        if (streamIdx != availableJpegSizes.size()) { +            camera_metadata_ro_entry_t jpegMinDurations = +                    staticInfo(ANDROID_SCALER_AVAILABLE_JPEG_MIN_DURATIONS); +            if (streamIdx < jpegMinDurations.count) { +                return jpegMinDurations.data.i64[streamIdx]; +            } +        } +    } +    ALOGE("%s: cannot find min frame duration for jpeg size %dx%d", +            __FUNCTION__, size.width, size.height); +    return -1; +} +  SortedVector<int32_t> Parameters::getAvailableOutputFormats() {      SortedVector<int32_t> outputFormats; // Non-duplicated output formats      if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {          Vector<StreamConfiguration> scs = getStreamConfigurations(); -        for (size_t i=0; i < scs.size(); i++) { +        for (size_t i = 0; i < scs.size(); i++) {              const StreamConfiguration &sc = scs[i];              if (sc.isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) {                  outputFormats.add(sc.format); @@ -2815,7 +2882,7 @@ SortedVector<int32_t> Parameters::getAvailableOutputFormats() {          }      } else {          camera_metadata_ro_entry_t availableFormats = staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS); -        for (size_t i=0; i < availableFormats.count; i++) { +        for (size_t i = 0; i < availableFormats.count; i++) {              outputFormats.add(availableFormats.data.i32[i]);          }      } @@ -2826,7 +2893,7 @@ Vector<Parameters::Size> Parameters::getAvailableJpegSizes() {      Vector<Parameters::Size> jpegSizes;      if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {          Vector<StreamConfiguration> scs = getStreamConfigurations(); -        for (size_t i=0; i < scs.size(); i++) { +        for (size_t i = 0; i < scs.size(); i++) {              const StreamConfiguration &sc = scs[i];              if (sc.isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&                      sc.format == HAL_PIXEL_FORMAT_BLOB) { @@ -2840,7 +2907,7 @@ Vector<Parameters::Size> Parameters::getAvailableJpegSizes() {          const int HEIGHT_OFFSET = 1;          camera_metadata_ro_entry_t availableJpegSizes =              staticInfo(ANDROID_SCALER_AVAILABLE_JPEG_SIZES); -        for (size_t i=0; i < availableJpegSizes.count; i+= JPEG_SIZE_ENTRY_COUNT) { +        for (size_t i = 0; i < availableJpegSizes.count; i+= JPEG_SIZE_ENTRY_COUNT) {              int width = availableJpegSizes.data.i32[i + WIDTH_OFFSET];              int height = availableJpegSizes.data.i32[i + HEIGHT_OFFSET];              Size sz = {width, height}; diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h index 46d48bc..972d007 100644 --- a/services/camera/libcameraservice/api1/client2/Parameters.h +++ b/services/camera/libcameraservice/api1/client2/Parameters.h @@ -166,6 +166,9 @@ struct Parameters {      bool previewCallbackSurface;      bool zslMode; +    // Whether the jpeg stream is slower than 30FPS and can slow down preview. +    // When slowJpegMode is true, zslMode must be false to avoid slowing down preview. +    bool slowJpegMode;      // Overall camera state      enum State { @@ -190,6 +193,8 @@ struct Parameters {      static const int MAX_INITIAL_PREVIEW_HEIGHT = 1080;      // Aspect ratio tolerance      static const CONSTEXPR float ASPECT_RATIO_TOLERANCE = 0.001; +    // Threshold for slow jpeg mode +    static const int64_t kSlowJpegModeThreshold = 33400000LL; // 33.4 ms      // Full static camera info, object owned by someone else, such as      // Camera2Device. @@ -377,15 +382,23 @@ private:          int32_t height;          int32_t isInput;      }; +      // Helper function extract available stream configuration      // Only valid since device HAL version 3.2      // returns an empty Vector if device HAL version does support it      Vector<StreamConfiguration> getStreamConfigurations(); +    // Helper function to get minimum frame duration for a jpeg size +    // return -1 if input jpeg size cannot be found in supported size list +    int64_t getJpegStreamMinFrameDurationNs(Parameters::Size size); +      // Helper function to get non-duplicated available output formats      SortedVector<int32_t> getAvailableOutputFormats();      // Helper function to get available output jpeg sizes      Vector<Size> getAvailableJpegSizes(); +    // Helper function to get maximum size in input Size vector. +    // The maximum size is defined by comparing width first, when width ties comparing height. +    Size getMaxSize(const Vector<Size>& sizes);      int mDeviceVersion;  }; diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp index 3b83f63..c717a56 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp @@ -719,6 +719,38 @@ status_t CameraDeviceClient::prepare(int streamId) {      return res;  } +status_t CameraDeviceClient::tearDown(int streamId) { +    ATRACE_CALL(); +    ALOGV("%s", __FUNCTION__); + +    status_t res = OK; +    if ( (res = checkPid(__FUNCTION__) ) != OK) return res; + +    Mutex::Autolock icl(mBinderSerializationLock); + +    // Guard against trying to prepare non-created streams +    ssize_t index = NAME_NOT_FOUND; +    for (size_t i = 0; i < mStreamMap.size(); ++i) { +        if (streamId == mStreamMap.valueAt(i)) { +            index = i; +            break; +        } +    } + +    if (index == NAME_NOT_FOUND) { +        ALOGW("%s: Camera %d: Invalid stream ID (%d) specified, no stream " +              "created yet", __FUNCTION__, mCameraId, streamId); +        return BAD_VALUE; +    } + +    // Also returns BAD_VALUE if stream ID was not valid or if the stream is in +    // use +    res = mDevice->tearDown(streamId); + +    return res; +} + +  status_t CameraDeviceClient::dump(int fd, const Vector<String16>& args) {      String8 result;      result.appendFormat("CameraDeviceClient[%d] (%p) dump:\n", diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h index 0f485ca..1f8b39d 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.h +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h @@ -111,6 +111,9 @@ public:      // Prepare stream by preallocating its buffers      virtual status_t      prepare(int streamId); +    // Tear down stream resources by freeing its unused buffers +    virtual status_t      tearDown(int streamId); +      /**       * Interface used by CameraService       */ diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h index 06177e3..cd25949 100644 --- a/services/camera/libcameraservice/common/CameraDeviceBase.h +++ b/services/camera/libcameraservice/common/CameraDeviceBase.h @@ -289,6 +289,11 @@ class CameraDeviceBase : public virtual RefBase {      virtual status_t prepare(int streamId) = 0;      /** +     * Free stream resources by dumping its unused gralloc buffers. +     */ +    virtual status_t tearDown(int streamId) = 0; + +    /**       * Get the HAL device version.       */      virtual uint32_t getDeviceVersion() = 0; diff --git a/services/camera/libcameraservice/common/CameraModule.cpp b/services/camera/libcameraservice/common/CameraModule.cpp index 1ae01ae..6a4dfe0 100644 --- a/services/camera/libcameraservice/common/CameraModule.cpp +++ b/services/camera/libcameraservice/common/CameraModule.cpp @@ -136,9 +136,10 @@ void CameraModule::deriveCameraCharacteristicsKeys(      // Always add a default for the pre-correction active array if the vendor chooses to omit this      camera_metadata_entry entry = chars.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);      if (entry.count == 0) { +        Vector<int32_t> preCorrectionArray;          entry = chars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE); -        chars.update(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, entry.data.i32, -                entry.count); +        preCorrectionArray.appendArray(entry.data.i32, entry.count); +        chars.update(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, preCorrectionArray);      }      return; diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp index dfe5565..c9c990c 100644 --- a/services/camera/libcameraservice/device2/Camera2Device.cpp +++ b/services/camera/libcameraservice/device2/Camera2Device.cpp @@ -626,6 +626,12 @@ status_t Camera2Device::prepare(int streamId) {      return NO_INIT;  } +status_t Camera2Device::tearDown(int streamId) { +    ATRACE_CALL(); +    ALOGE("%s: Camera %d: unimplemented", __FUNCTION__, mId); +    return NO_INIT; +} +  uint32_t Camera2Device::getDeviceVersion() {      ATRACE_CALL();      return mDeviceVersion; diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h index c9f3a2c..34c1ded 100644 --- a/services/camera/libcameraservice/device2/Camera2Device.h +++ b/services/camera/libcameraservice/device2/Camera2Device.h @@ -85,8 +85,9 @@ class Camera2Device: public CameraDeviceBase {              buffer_handle_t *buffer, wp<BufferReleasedListener> listener);      // Flush implemented as just a wait      virtual status_t flush(int64_t *lastFrameNumber = NULL); -    // Prepare is a no-op +    // Prepare and tearDown are no-ops      virtual status_t prepare(int streamId); +    virtual status_t tearDown(int streamId);      virtual uint32_t getDeviceVersion();      virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const; diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 9e73b5c..3afbd89 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -1384,6 +1384,37 @@ status_t Camera3Device::prepare(int streamId) {      return mPreparerThread->prepare(stream);  } +status_t Camera3Device::tearDown(int streamId) { +    ATRACE_CALL(); +    ALOGV("%s: Camera %d: Tearing down stream %d", __FUNCTION__, mId, streamId); +    Mutex::Autolock il(mInterfaceLock); +    Mutex::Autolock l(mLock); + +    // Teardown can only be accomplished on devices that don't require register_stream_buffers, +    // since we cannot call register_stream_buffers except right after configure_streams. +    if (mHal3Device->common.version < CAMERA_DEVICE_API_VERSION_3_2) { +        ALOGE("%s: Unable to tear down streams on device HAL v%x", +                __FUNCTION__, mHal3Device->common.version); +        return NO_INIT; +    } + +    sp<Camera3StreamInterface> stream; +    ssize_t outputStreamIdx = mOutputStreams.indexOfKey(streamId); +    if (outputStreamIdx == NAME_NOT_FOUND) { +        CLOGE("Stream %d does not exist", streamId); +        return BAD_VALUE; +    } + +    stream = mOutputStreams.editValueAt(outputStreamIdx); + +    if (stream->hasOutstandingBuffers() || mRequestThread->isStreamPending(stream)) { +        CLOGE("Stream %d is a target of a in-progress request", streamId); +        return BAD_VALUE; +    } + +    return stream->tearDown(); +} +  uint32_t Camera3Device::getDeviceVersion() {      ATRACE_CALL();      Mutex::Autolock il(mInterfaceLock); diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index 31b6132..140da98 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -141,6 +141,8 @@ class Camera3Device :      virtual status_t prepare(int streamId); +    virtual status_t tearDown(int streamId); +      virtual uint32_t getDeviceVersion();      virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const; diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp index 4c40bb6..2527fd6 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp @@ -364,6 +364,61 @@ status_t Camera3Stream::cancelPrepareLocked() {      return res;  } +status_t Camera3Stream::tearDown() { +    ATRACE_CALL(); +    Mutex::Autolock l(mLock); + +    status_t res = OK; + +    // This function should be only called when the stream is configured. +    if (mState != STATE_CONFIGURED) { +        ALOGE("%s: Stream %d: Can't tear down stream if stream is not in " +                "CONFIGURED state %d", __FUNCTION__, mId, mState); +        return INVALID_OPERATION; +    } + +    // If any buffers have been handed to the HAL, the stream cannot be torn down. +    if (getHandoutOutputBufferCountLocked() > 0) { +        ALOGE("%s: Stream %d: Can't tear down a stream that has outstanding buffers", +                __FUNCTION__, mId); +        return INVALID_OPERATION; +    } + +    // Free buffers by disconnecting and then reconnecting to the buffer queue +    // Only unused buffers will be dropped immediately; buffers that have been filled +    // and are waiting to be acquired by the consumer and buffers that are currently +    // acquired will be freed once they are released by the consumer. + +    res = disconnectLocked(); +    if (res != OK) { +        if (res == -ENOTCONN) { +            // queue has been disconnected, nothing left to do, so exit with success +            return OK; +        } +        ALOGE("%s: Stream %d: Unable to disconnect to tear down buffers: %s (%d)", +                __FUNCTION__, mId, strerror(-res), res); +        return res; +    } + +    mState = STATE_IN_CONFIG; + +    res = configureQueueLocked(); +    if (res != OK) { +        ALOGE("%s: Unable to configure stream %d queue: %s (%d)", +                __FUNCTION__, mId, strerror(-res), res); +        mState = STATE_ERROR; +        return res; +    } + +    // Reset prepared state, since we've reconnected to the queue and can prepare again. +    mPrepared = false; +    mStreamUnpreparable = false; + +    mState = STATE_CONFIGURED; + +    return OK; +} +  status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer) {      ATRACE_CALL();      Mutex::Autolock l(mLock); diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h index 0543c66..bab2177 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.h +++ b/services/camera/libcameraservice/device3/Camera3Stream.h @@ -247,6 +247,20 @@ class Camera3Stream :      status_t        cancelPrepare();      /** +     * Tear down memory for this stream. This frees all unused gralloc buffers +     * allocated for this stream, but leaves it ready for operation afterward. +     * +     * May only be called in the CONFIGURED state, and keeps the stream in +     * the CONFIGURED state. +     * +     * Returns: +     *    OK if teardown succeeded. +     *    INVALID_OPERATION if not in the CONFIGURED state +     *    NO_INIT in case of a serious error from the HAL device +     */ +    status_t       tearDown(); + +    /**       * Fill in the camera3_stream_buffer with the next valid buffer for this       * stream, to hand over to the HAL.       * diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h index 6c87a45..c086eaf 100644 --- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h +++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h @@ -152,6 +152,20 @@ class Camera3StreamInterface : public virtual RefBase {      virtual status_t cancelPrepare() = 0;      /** +     * Tear down memory for this stream. This frees all unused gralloc buffers +     * allocated for this stream, but leaves it ready for operation afterward. +     * +     * May only be called in the CONFIGURED state, and keeps the stream in +     * the CONFIGURED state. +     * +     * Returns: +     *    OK if teardown succeeded. +     *    INVALID_OPERATION if not in the CONFIGURED state +     *    NO_INIT in case of a serious error from the HAL device +     */ +    virtual status_t tearDown() = 0; + +    /**       * Fill in the camera3_stream_buffer with the next valid buffer for this       * stream, to hand over to the HAL.       *  | 
