diff options
81 files changed, 1682 insertions, 786 deletions
diff --git a/camera/Android.mk b/camera/Android.mk index 369d0c5..5774b6f 100644 --- a/camera/Android.mk +++ b/camera/Android.mk @@ -22,6 +22,7 @@ LOCAL_SRC_FILES:= \ Camera.cpp \ CameraMetadata.cpp \ CameraParameters.cpp \ + CaptureResult.cpp \ ICamera.cpp \ ICameraClient.cpp \ ICameraService.cpp \ diff --git a/camera/CaptureResult.cpp b/camera/CaptureResult.cpp new file mode 100644 index 0000000..c016e52 --- /dev/null +++ b/camera/CaptureResult.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Camera-CaptureResult" +#include <utils/Log.h> + +#include <camera/CaptureResult.h> +#include <binder/Parcel.h> + +namespace android { + +bool CaptureResultExtras::isValid() { + return requestId >= 0; +} + +status_t CaptureResultExtras::readFromParcel(Parcel *parcel) { + if (parcel == NULL) { + ALOGE("%s: Null parcel", __FUNCTION__); + return BAD_VALUE; + } + + parcel->readInt32(&requestId); + parcel->readInt32(&burstId); + parcel->readInt32(&afTriggerId); + parcel->readInt32(&precaptureTriggerId); + parcel->readInt64(&frameNumber); + + return OK; +} + +status_t CaptureResultExtras::writeToParcel(Parcel *parcel) const { + if (parcel == NULL) { + ALOGE("%s: Null parcel", __FUNCTION__); + return BAD_VALUE; + } + + parcel->writeInt32(requestId); + parcel->writeInt32(burstId); + parcel->writeInt32(afTriggerId); + parcel->writeInt32(precaptureTriggerId); + parcel->writeInt64(frameNumber); + + return OK; +} + +CaptureResult::CaptureResult() : + mMetadata(), mResultExtras() { +} + +CaptureResult::CaptureResult(const CaptureResult &otherResult) { + mResultExtras = otherResult.mResultExtras; + mMetadata = otherResult.mMetadata; +} + +status_t CaptureResult::readFromParcel(Parcel *parcel) { + + ALOGV("%s: parcel = %p", __FUNCTION__, parcel); + + if (parcel == NULL) { + ALOGE("%s: parcel is null", __FUNCTION__); + return BAD_VALUE; + } + + mMetadata.clear(); + + status_t res = OK; + res = mMetadata.readFromParcel(parcel); + if (res != OK) { + ALOGE("%s: Failed to read metadata from parcel.", + __FUNCTION__); + return res; + } + ALOGV("%s: Read metadata from parcel", __FUNCTION__); + + res = mResultExtras.readFromParcel(parcel); + if (res != OK) { + ALOGE("%s: Failed to read result extras from parcel.", + __FUNCTION__); + return res; + } + ALOGV("%s: Read result extras from parcel", __FUNCTION__); + + return OK; +} + +status_t CaptureResult::writeToParcel(Parcel *parcel) const { + + ALOGV("%s: parcel = %p", __FUNCTION__, parcel); + + if (parcel == NULL) { + ALOGE("%s: parcel is null", __FUNCTION__); + return BAD_VALUE; + } + + status_t res; + + res = mMetadata.writeToParcel(parcel); + if (res != OK) { + ALOGE("%s: Failed to write metadata to parcel", __FUNCTION__); + return res; + } + ALOGV("%s: Wrote metadata to parcel", __FUNCTION__); + + res = mResultExtras.writeToParcel(parcel); + if (res != OK) { + ALOGE("%s: Failed to write result extras to parcel", __FUNCTION__); + return res; + } + ALOGV("%s: Wrote result extras to parcel", __FUNCTION__); + + return OK; +} + +} diff --git a/camera/camera2/ICameraDeviceCallbacks.cpp b/camera/camera2/ICameraDeviceCallbacks.cpp index 613358a..4cc7b5d 100644 --- a/camera/camera2/ICameraDeviceCallbacks.cpp +++ b/camera/camera2/ICameraDeviceCallbacks.cpp @@ -28,6 +28,7 @@ #include <camera/camera2/ICameraDeviceCallbacks.h> #include "camera/CameraMetadata.h" +#include "camera/CaptureResult.h" namespace android { @@ -46,12 +47,14 @@ public: { } - void onDeviceError(CameraErrorCode errorCode) + void onDeviceError(CameraErrorCode errorCode, const CaptureResultExtras& resultExtras) { ALOGV("onDeviceError"); Parcel data, reply; data.writeInterfaceToken(ICameraDeviceCallbacks::getInterfaceDescriptor()); data.writeInt32(static_cast<int32_t>(errorCode)); + data.writeInt32(1); // to mark presence of CaptureResultExtras object + resultExtras.writeToParcel(&data); remote()->transact(CAMERA_ERROR, data, &reply, IBinder::FLAG_ONEWAY); data.writeNoException(); } @@ -65,25 +68,28 @@ public: data.writeNoException(); } - void onCaptureStarted(int32_t requestId, int64_t timestamp) + void onCaptureStarted(const CaptureResultExtras& result, int64_t timestamp) { ALOGV("onCaptureStarted"); Parcel data, reply; data.writeInterfaceToken(ICameraDeviceCallbacks::getInterfaceDescriptor()); - data.writeInt32(requestId); + data.writeInt32(1); // to mark presence of CaptureResultExtras object + result.writeToParcel(&data); data.writeInt64(timestamp); remote()->transact(CAPTURE_STARTED, data, &reply, IBinder::FLAG_ONEWAY); data.writeNoException(); } - void onResultReceived(int32_t requestId, const CameraMetadata& result) { + void onResultReceived(const CameraMetadata& metadata, + const CaptureResultExtras& resultExtras) { ALOGV("onResultReceived"); Parcel data, reply; data.writeInterfaceToken(ICameraDeviceCallbacks::getInterfaceDescriptor()); - data.writeInt32(requestId); data.writeInt32(1); // to mark presence of metadata object - result.writeToParcel(&data); + metadata.writeToParcel(&data); + data.writeInt32(1); // to mark presence of CaptureResult object + resultExtras.writeToParcel(&data); remote()->transact(RESULT_RECEIVED, data, &reply, IBinder::FLAG_ONEWAY); data.writeNoException(); } @@ -104,7 +110,13 @@ status_t BnCameraDeviceCallbacks::onTransact( CHECK_INTERFACE(ICameraDeviceCallbacks, data, reply); CameraErrorCode errorCode = static_cast<CameraErrorCode>(data.readInt32()); - onDeviceError(errorCode); + CaptureResultExtras resultExtras; + if (data.readInt32() != 0) { + resultExtras.readFromParcel(const_cast<Parcel*>(&data)); + } else { + ALOGE("No CaptureResultExtras object is present!"); + } + onDeviceError(errorCode, resultExtras); data.readExceptionCode(); return NO_ERROR; } break; @@ -118,23 +130,33 @@ status_t BnCameraDeviceCallbacks::onTransact( case CAPTURE_STARTED: { ALOGV("onCaptureStarted"); CHECK_INTERFACE(ICameraDeviceCallbacks, data, reply); - int32_t requestId = data.readInt32(); + CaptureResultExtras result; + if (data.readInt32() != 0) { + result.readFromParcel(const_cast<Parcel*>(&data)); + } else { + ALOGE("No CaptureResultExtras object is present in result!"); + } int64_t timestamp = data.readInt64(); - onCaptureStarted(requestId, timestamp); + onCaptureStarted(result, timestamp); data.readExceptionCode(); return NO_ERROR; } break; case RESULT_RECEIVED: { ALOGV("onResultReceived"); CHECK_INTERFACE(ICameraDeviceCallbacks, data, reply); - int32_t requestId = data.readInt32(); - CameraMetadata result; + CameraMetadata metadata; if (data.readInt32() != 0) { - result.readFromParcel(const_cast<Parcel*>(&data)); + metadata.readFromParcel(const_cast<Parcel*>(&data)); } else { ALOGW("No metadata object is present in result"); } - onResultReceived(requestId, result); + CaptureResultExtras resultExtras; + if (data.readInt32() != 0) { + resultExtras.readFromParcel(const_cast<Parcel*>(&data)); + } else { + ALOGW("No capture result extras object is present in result"); + } + onResultReceived(metadata, resultExtras); data.readExceptionCode(); return NO_ERROR; } break; diff --git a/camera/camera2/ICameraDeviceUser.cpp b/camera/camera2/ICameraDeviceUser.cpp index 1e5822f..ad65955 100644 --- a/camera/camera2/ICameraDeviceUser.cpp +++ b/camera/camera2/ICameraDeviceUser.cpp @@ -35,6 +35,7 @@ typedef Parcel::ReadableBlob ReadableBlob; enum { DISCONNECT = IBinder::FIRST_CALL_TRANSACTION, SUBMIT_REQUEST, + SUBMIT_REQUEST_LIST, CANCEL_REQUEST, DELETE_STREAM, CREATE_STREAM, @@ -75,7 +76,8 @@ public: reply.readExceptionCode(); } - virtual int submitRequest(sp<CaptureRequest> request, bool streaming) + virtual status_t submitRequest(sp<CaptureRequest> request, bool repeating, + int64_t *lastFrameNumber) { Parcel data, reply; data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); @@ -89,15 +91,67 @@ public: } // arg1 = streaming (bool) - data.writeInt32(streaming); + data.writeInt32(repeating); remote()->transact(SUBMIT_REQUEST, data, &reply); reply.readExceptionCode(); - return reply.readInt32(); + status_t res = reply.readInt32(); + + status_t resFrameNumber = BAD_VALUE; + if (reply.readInt32() != 0) { + if (lastFrameNumber != NULL) { + resFrameNumber = reply.readInt64(lastFrameNumber); + } + } + + if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) { + res = FAILED_TRANSACTION; + } + return res; } - virtual status_t cancelRequest(int requestId) + virtual status_t submitRequestList(List<sp<CaptureRequest> > requestList, bool repeating, + int64_t *lastFrameNumber) + { + Parcel data, reply; + data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); + + data.writeInt32(requestList.size()); + + for (List<sp<CaptureRequest> >::iterator it = requestList.begin(); + it != requestList.end(); ++it) { + sp<CaptureRequest> request = *it; + if (request != 0) { + data.writeInt32(1); + if (request->writeToParcel(&data) != OK) { + return BAD_VALUE; + } + } else { + data.writeInt32(0); + } + } + + data.writeInt32(repeating); + + remote()->transact(SUBMIT_REQUEST_LIST, data, &reply); + + reply.readExceptionCode(); + status_t res = reply.readInt32(); + + status_t resFrameNumber = BAD_VALUE; + if (reply.readInt32() != 0) { + if (lastFrameNumber != NULL) { + resFrameNumber = reply.readInt64(lastFrameNumber); + } + } + if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) { + res = FAILED_TRANSACTION; + } + return res; + } + + virtual status_t cancelRequest(int requestId, int64_t *lastFrameNumber) { Parcel data, reply; data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); @@ -106,7 +160,18 @@ public: remote()->transact(CANCEL_REQUEST, data, &reply); reply.readExceptionCode(); - return reply.readInt32(); + status_t res = reply.readInt32(); + + status_t resFrameNumber = BAD_VALUE; + if (reply.readInt32() != 0) { + if (lastFrameNumber != NULL) { + res = reply.readInt64(lastFrameNumber); + } + } + if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) { + res = FAILED_TRANSACTION; + } + return res; } virtual status_t deleteStream(int streamId) @@ -197,14 +262,25 @@ public: return reply.readInt32(); } - virtual status_t flush() + virtual status_t flush(int64_t *lastFrameNumber) { ALOGV("flush"); Parcel data, reply; data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); remote()->transact(FLUSH, data, &reply); reply.readExceptionCode(); - return reply.readInt32(); + status_t res = reply.readInt32(); + + status_t resFrameNumber = BAD_VALUE; + if (reply.readInt32() != 0) { + if (lastFrameNumber != NULL) { + res = reply.readInt64(lastFrameNumber); + } + } + if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) { + res = FAILED_TRANSACTION; + } + return res; } private: @@ -239,11 +315,43 @@ status_t BnCameraDeviceUser::onTransact( } // arg1 = streaming (bool) - bool streaming = data.readInt32(); + bool repeating = data.readInt32(); // return code: requestId (int32) reply->writeNoException(); - reply->writeInt32(submitRequest(request, streaming)); + int64_t lastFrameNumber = -1; + reply->writeInt32(submitRequest(request, repeating, &lastFrameNumber)); + reply->writeInt32(1); + reply->writeInt64(lastFrameNumber); + + return NO_ERROR; + } break; + case SUBMIT_REQUEST_LIST: { + CHECK_INTERFACE(ICameraDeviceUser, data, reply); + + List<sp<CaptureRequest> > requestList; + int requestListSize = data.readInt32(); + for (int i = 0; i < requestListSize; i++) { + if (data.readInt32() != 0) { + sp<CaptureRequest> request = new CaptureRequest(); + if (request->readFromParcel(const_cast<Parcel*>(&data)) != OK) { + return BAD_VALUE; + } + requestList.push_back(request); + } else { + sp<CaptureRequest> request = 0; + requestList.push_back(request); + ALOGE("A request is missing. Sending in null request."); + } + } + + bool repeating = data.readInt32(); + + reply->writeNoException(); + int64_t lastFrameNumber = -1; + reply->writeInt32(submitRequestList(requestList, repeating, &lastFrameNumber)); + reply->writeInt32(1); + reply->writeInt64(lastFrameNumber); return NO_ERROR; } break; @@ -251,7 +359,10 @@ status_t BnCameraDeviceUser::onTransact( CHECK_INTERFACE(ICameraDeviceUser, data, reply); int requestId = data.readInt32(); reply->writeNoException(); - reply->writeInt32(cancelRequest(requestId)); + int64_t lastFrameNumber = -1; + reply->writeInt32(cancelRequest(requestId, &lastFrameNumber)); + reply->writeInt32(1); + reply->writeInt64(lastFrameNumber); return NO_ERROR; } break; case DELETE_STREAM: { @@ -339,7 +450,10 @@ status_t BnCameraDeviceUser::onTransact( case FLUSH: { CHECK_INTERFACE(ICameraDeviceUser, data, reply); reply->writeNoException(); - reply->writeInt32(flush()); + int64_t lastFrameNumber = -1; + reply->writeInt32(flush(&lastFrameNumber)); + reply->writeInt32(1); + reply->writeInt64(lastFrameNumber); return NO_ERROR; } default: diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp index daaea27..6b41fd4 100644 --- a/cmds/stagefright/stagefright.cpp +++ b/cmds/stagefright/stagefright.cpp @@ -941,9 +941,11 @@ int main(int argc, char **argv) { } else { CHECK(useSurfaceTexAlloc); - sp<BufferQueue> bq = new BufferQueue(); - sp<GLConsumer> texture = new GLConsumer(bq, 0 /* tex */); - gSurface = new Surface(bq); + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + sp<GLConsumer> texture = new GLConsumer(consumer, 0 /* tex */); + gSurface = new Surface(producer); } CHECK_EQ((status_t)OK, diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp index 69fa7a0..6efc712 100644 --- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp +++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp @@ -45,7 +45,7 @@ namespace android { // MockDrmFactory bool MockDrmFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) { - return (!memcmp(uuid, mock_uuid, sizeof(uuid))); + return (!memcmp(uuid, mock_uuid, sizeof(mock_uuid))); } bool MockDrmFactory::isContentTypeSupported(const String8 &mimeType) @@ -65,7 +65,7 @@ namespace android { // MockCryptoFactory bool MockCryptoFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) const { - return (!memcmp(uuid, mock_uuid, sizeof(uuid))); + return (!memcmp(uuid, mock_uuid, sizeof(mock_uuid))); } status_t MockCryptoFactory::createPlugin(const uint8_t uuid[16], const void *data, @@ -254,7 +254,9 @@ namespace android { return OK; } - status_t MockDrmPlugin::getProvisionRequest(Vector<uint8_t> &request, + status_t MockDrmPlugin::getProvisionRequest(String8 const &certType, + String8 const &certAuthority, + Vector<uint8_t> &request, String8 &defaultUrl) { Mutex::Autolock lock(mLock); @@ -282,7 +284,9 @@ namespace android { return OK; } - status_t MockDrmPlugin::provideProvisionResponse(Vector<uint8_t> const &response) + status_t MockDrmPlugin::provideProvisionResponse(Vector<uint8_t> const &response, + Vector<uint8_t> &certificate, + Vector<uint8_t> &wrappedKey) { Mutex::Autolock lock(mLock); ALOGD("MockDrmPlugin::provideProvisionResponse(%s)", @@ -600,6 +604,33 @@ namespace android { return OK; } + status_t MockDrmPlugin::signRSA(Vector<uint8_t> const &sessionId, + String8 const &algorithm, + Vector<uint8_t> const &message, + Vector<uint8_t> const &wrappedKey, + Vector<uint8_t> &signature) + { + Mutex::Autolock lock(mLock); + ALOGD("MockDrmPlugin::signRSA(sessionId=%s, algorithm=%s, keyId=%s, " + "message=%s, signature=%s)", + vectorToString(sessionId).string(), + algorithm.string(), + vectorToString(message).string(), + vectorToString(wrappedKey).string(), + vectorToString(signature).string()); + + // Properties used in mock test, set by mock plugin and verifed cts test app + // byte[] wrappedKey -> mock-wrappedkey + // byte[] message -> mock-message + // byte[] signature -> mock-signature + mByteArrayProperties.add(String8("mock-sessionid"), sessionId); + mStringProperties.add(String8("mock-algorithm"), algorithm); + mByteArrayProperties.add(String8("mock-message"), message); + mByteArrayProperties.add(String8("mock-wrappedkey"), wrappedKey); + mByteArrayProperties.add(String8("mock-signature"), signature); + return OK; + } + ssize_t MockDrmPlugin::findSession(Vector<uint8_t> const &sessionId) const { ALOGD("findSession: nsessions=%d, size=%d", mSessions.size(), sessionId.size()); diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h index 2297f9b..97d7052 100644 --- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h +++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h @@ -76,10 +76,14 @@ namespace android { status_t queryKeyStatus(Vector<uint8_t> const &sessionId, KeyedVector<String8, String8> &infoMap) const; - status_t getProvisionRequest(Vector<uint8_t> &request, - String8 &defaultUrl); + status_t getProvisionRequest(String8 const &certType, + String8 const &certAuthority, + Vector<uint8_t> &request, + String8 &defaultUrl); - status_t provideProvisionResponse(Vector<uint8_t> const &response); + status_t provideProvisionResponse(Vector<uint8_t> const &response, + Vector<uint8_t> &certificate, + Vector<uint8_t> &wrappedKey); status_t getSecureStops(List<Vector<uint8_t> > &secureStops); status_t releaseSecureStops(Vector<uint8_t> const &ssRelease); @@ -122,6 +126,12 @@ namespace android { Vector<uint8_t> const &signature, bool &match); + status_t signRSA(Vector<uint8_t> const &sessionId, + String8 const &algorithm, + Vector<uint8_t> const &message, + Vector<uint8_t> const &wrappedKey, + Vector<uint8_t> &signature); + private: String8 vectorToString(Vector<uint8_t> const &vector) const; String8 arrayToString(uint8_t const *array, size_t len) const; diff --git a/include/camera/CaptureResult.h b/include/camera/CaptureResult.h new file mode 100644 index 0000000..6e47a16 --- /dev/null +++ b/include/camera/CaptureResult.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_CAPTURERESULT_H +#define ANDROID_HARDWARE_CAPTURERESULT_H + +#include <utils/RefBase.h> +#include <camera/CameraMetadata.h> + +namespace android { + +/** + * CaptureResultExtras is a structure to encapsulate various indices for a capture result. + * These indices are framework-internal and not sent to the HAL. + */ +struct CaptureResultExtras { + /** + * An integer to index the request sequence that this result belongs to. + */ + int32_t requestId; + + /** + * An integer to index this result inside a request sequence, starting from 0. + */ + int32_t burstId; + + /** + * TODO: Add documentation for this field. + */ + int32_t afTriggerId; + + /** + * TODO: Add documentation for this field. + */ + int32_t precaptureTriggerId; + + /** + * A 64bit integer to index the frame number associated with this result. + */ + int64_t frameNumber; + + /** + * Constructor initializes object as invalid by setting requestId to be -1. + */ + CaptureResultExtras() + : requestId(-1), + burstId(0), + afTriggerId(0), + precaptureTriggerId(0), + frameNumber(0) { + } + + /** + * This function returns true if it's a valid CaptureResultExtras object. + * Otherwise, returns false. It is valid only when requestId is non-negative. + */ + bool isValid(); + + status_t readFromParcel(Parcel* parcel); + status_t writeToParcel(Parcel* parcel) const; +}; + +struct CaptureResult : public virtual LightRefBase<CaptureResult> { + CameraMetadata mMetadata; + CaptureResultExtras mResultExtras; + + CaptureResult(); + + CaptureResult(const CaptureResult& otherResult); + + status_t readFromParcel(Parcel* parcel); + status_t writeToParcel(Parcel* parcel) const; +}; + +} + +#endif /* ANDROID_HARDWARE_CAPTURERESULT_H */ diff --git a/include/camera/camera2/ICameraDeviceCallbacks.h b/include/camera/camera2/ICameraDeviceCallbacks.h index 8dac4f2..f059b3d 100644 --- a/include/camera/camera2/ICameraDeviceCallbacks.h +++ b/include/camera/camera2/ICameraDeviceCallbacks.h @@ -24,9 +24,12 @@ #include <utils/Timers.h> #include <system/camera.h> +#include <camera/CaptureResult.h> + namespace android { class CameraMetadata; + class ICameraDeviceCallbacks : public IInterface { /** @@ -45,18 +48,19 @@ public: }; // One way - virtual void onDeviceError(CameraErrorCode errorCode) = 0; + virtual void onDeviceError(CameraErrorCode errorCode, + const CaptureResultExtras& resultExtras) = 0; // One way virtual void onDeviceIdle() = 0; // One way - virtual void onCaptureStarted(int32_t requestId, + virtual void onCaptureStarted(const CaptureResultExtras& resultExtras, int64_t timestamp) = 0; // One way - virtual void onResultReceived(int32_t requestId, - const CameraMetadata& result) = 0; + virtual void onResultReceived(const CameraMetadata& metadata, + const CaptureResultExtras& resultExtras) = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/camera/camera2/ICameraDeviceUser.h b/include/camera/camera2/ICameraDeviceUser.h index f71f302..49daf69 100644 --- a/include/camera/camera2/ICameraDeviceUser.h +++ b/include/camera/camera2/ICameraDeviceUser.h @@ -19,6 +19,7 @@ #include <binder/IInterface.h> #include <binder/Parcel.h> +#include <utils/List.h> struct camera_metadata; @@ -44,9 +45,34 @@ public: * Request Handling **/ + /** + * For streaming requests, output lastFrameNumber is the last frame number + * of the previous repeating request. + * For non-streaming requests, output lastFrameNumber is the expected last + * frame number of the current request. + */ virtual int submitRequest(sp<CaptureRequest> request, - bool streaming = false) = 0; - virtual status_t cancelRequest(int requestId) = 0; + bool streaming = false, + /*out*/ + int64_t* lastFrameNumber = NULL) = 0; + + /** + * For streaming requests, output lastFrameNumber is the last frame number + * of the previous repeating request. + * For non-streaming requests, output lastFrameNumber is the expected last + * frame number of the current request. + */ + virtual int submitRequestList(List<sp<CaptureRequest> > requestList, + bool streaming = false, + /*out*/ + int64_t* lastFrameNumber = NULL) = 0; + + /** + * Output lastFrameNumber is the last frame number of the previous repeating request. + */ + virtual status_t cancelRequest(int requestId, + /*out*/ + int64_t* lastFrameNumber = NULL) = 0; virtual status_t deleteStream(int streamId) = 0; virtual status_t createStream( @@ -64,8 +90,12 @@ public: // Wait until all the submitted requests have finished processing virtual status_t waitUntilIdle() = 0; - // Flush all pending and in-progress work as quickly as possible. - virtual status_t flush() = 0; + /** + * Flush all pending and in-progress work as quickly as possible. + * Output lastFrameNumber is the last frame number of the previous repeating request. + */ + virtual status_t flush(/*out*/ + int64_t* lastFrameNumber = NULL) = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/media/IDrm.h b/include/media/IDrm.h index 5ef26af..32ae28e 100644 --- a/include/media/IDrm.h +++ b/include/media/IDrm.h @@ -61,10 +61,14 @@ struct IDrm : public IInterface { virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId, KeyedVector<String8, String8> &infoMap) const = 0; - virtual status_t getProvisionRequest(Vector<uint8_t> &request, + virtual status_t getProvisionRequest(String8 const &certType, + String8 const &certAuthority, + Vector<uint8_t> &request, String8 &defaulUrl) = 0; - virtual status_t provideProvisionResponse(Vector<uint8_t> const &response) = 0; + virtual status_t provideProvisionResponse(Vector<uint8_t> const &response, + Vector<uint8_t> &certificate, + Vector<uint8_t> &wrappedKey) = 0; virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) = 0; @@ -107,6 +111,12 @@ struct IDrm : public IInterface { Vector<uint8_t> const &signature, bool &match) = 0; + virtual status_t signRSA(Vector<uint8_t> const &sessionId, + String8 const &algorithm, + Vector<uint8_t> const &message, + Vector<uint8_t> const &wrappedKey, + Vector<uint8_t> &signature) = 0; + virtual status_t setListener(const sp<IDrmClient>& listener) = 0; private: diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h index 863a7d5..8ec7f1c 100644 --- a/include/media/stagefright/ACodec.h +++ b/include/media/stagefright/ACodec.h @@ -189,6 +189,7 @@ private: bool mIsEncoder; bool mUseMetadataOnEncoderOutput; bool mShutdownInProgress; + bool mExplicitShutdown; // If "mKeepComponentAllocated" we only transition back to Loaded state // and do not release the component instance. diff --git a/include/media/stagefright/SurfaceMediaSource.h b/include/media/stagefright/SurfaceMediaSource.h index 59e83c2..43b75fd 100644 --- a/include/media/stagefright/SurfaceMediaSource.h +++ b/include/media/stagefright/SurfaceMediaSource.h @@ -111,7 +111,7 @@ public: // pass metadata through the buffers. Currently, it is force set to true bool isMetaDataStoredInVideoBuffers() const; - sp<BufferQueue> getBufferQueue() const { return mBufferQueue; } + sp<IGraphicBufferProducer> getProducer() const { return mProducer; } // To be called before start() status_t setMaxAcquiredBufferCount(size_t count); @@ -146,9 +146,10 @@ protected: static bool isExternalFormat(uint32_t format); private: - // mBufferQueue is the exchange point between the producer and - // this consumer - sp<BufferQueue> mBufferQueue; + // A BufferQueue, represented by these interfaces, is the exchange point + // between the producer and this consumer + sp<IGraphicBufferProducer> mProducer; + sp<IGraphicBufferConsumer> mConsumer; struct SlotData { sp<GraphicBuffer> mGraphicBuffer; diff --git a/include/media/stagefright/Utils.h b/include/media/stagefright/Utils.h index bbad271..c85368f 100644 --- a/include/media/stagefright/Utils.h +++ b/include/media/stagefright/Utils.h @@ -60,6 +60,8 @@ status_t sendMetaDataToHal(sp<MediaPlayerBase::AudioSink>& sink, const sp<MetaDa bool canOffloadStream(const sp<MetaData>& meta, bool hasVideo, bool isStreaming, audio_stream_type_t streamType); +AString uriDebugString(const AString &uri, bool incognito = false); + } // namespace android #endif // UTILS_H_ diff --git a/include/media/stagefright/foundation/AString.h b/include/media/stagefright/foundation/AString.h index 0f8f1e1..622028e 100644 --- a/include/media/stagefright/foundation/AString.h +++ b/include/media/stagefright/foundation/AString.h @@ -22,10 +22,13 @@ namespace android { +struct String8; + struct AString { AString(); AString(const char *s); AString(const char *s, size_t size); + AString(const String8 &from); AString(const AString &from); AString(const AString &from, size_t offset, size_t n); ~AString(); diff --git a/media/common_time/utils.cpp b/media/common_time/utils.cpp index 6539171..91cf2fd 100644 --- a/media/common_time/utils.cpp +++ b/media/common_time/utils.cpp @@ -59,7 +59,7 @@ void serializeSockaddr(Parcel* p, const struct sockaddr_storage* addr) { } void deserializeSockaddr(const Parcel* p, struct sockaddr_storage* addr) { - memset(addr, 0, sizeof(addr)); + memset(addr, 0, sizeof(*addr)); addr->ss_family = p->readInt32(); switch(addr->ss_family) { diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp index f7a9a75..f1a6a9f 100644 --- a/media/libmedia/IDrm.cpp +++ b/media/libmedia/IDrm.cpp @@ -51,6 +51,7 @@ enum { ENCRYPT, DECRYPT, SIGN, + SIGN_RSA, VERIFY, SET_LISTENER }; @@ -196,11 +197,15 @@ struct BpDrm : public BpInterface<IDrm> { return reply.readInt32(); } - virtual status_t getProvisionRequest(Vector<uint8_t> &request, + virtual status_t getProvisionRequest(String8 const &certType, + String8 const &certAuthority, + Vector<uint8_t> &request, String8 &defaultUrl) { Parcel data, reply; data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + data.writeString8(certType); + data.writeString8(certAuthority); remote()->transact(GET_PROVISION_REQUEST, data, &reply); readVector(reply, request); @@ -209,13 +214,18 @@ struct BpDrm : public BpInterface<IDrm> { return reply.readInt32(); } - virtual status_t provideProvisionResponse(Vector<uint8_t> const &response) { + virtual status_t provideProvisionResponse(Vector<uint8_t> const &response, + Vector<uint8_t> &certificate, + Vector<uint8_t> &wrappedKey) { Parcel data, reply; data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); writeVector(data, response); remote()->transact(PROVIDE_PROVISION_RESPONSE, data, &reply); + readVector(reply, certificate); + readVector(reply, wrappedKey); + return reply.readInt32(); } @@ -386,6 +396,25 @@ struct BpDrm : public BpInterface<IDrm> { return reply.readInt32(); } + virtual status_t signRSA(Vector<uint8_t> const &sessionId, + String8 const &algorithm, + Vector<uint8_t> const &message, + Vector<uint8_t> const &wrappedKey, + Vector<uint8_t> &signature) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + writeVector(data, sessionId); + data.writeString8(algorithm); + writeVector(data, message); + writeVector(data, wrappedKey); + + remote()->transact(SIGN_RSA, data, &reply); + readVector(reply, signature); + + return reply.readInt32(); + } + virtual status_t setListener(const sp<IDrmClient>& listener) { Parcel data, reply; data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); @@ -563,9 +592,13 @@ status_t BnDrm::onTransact( case GET_PROVISION_REQUEST: { CHECK_INTERFACE(IDrm, data, reply); + String8 certType = data.readString8(); + String8 certAuthority = data.readString8(); + Vector<uint8_t> request; String8 defaultUrl; - status_t result = getProvisionRequest(request, defaultUrl); + status_t result = getProvisionRequest(certType, certAuthority, + request, defaultUrl); writeVector(reply, request); reply->writeString8(defaultUrl); reply->writeInt32(result); @@ -576,8 +609,13 @@ status_t BnDrm::onTransact( { CHECK_INTERFACE(IDrm, data, reply); Vector<uint8_t> response; + Vector<uint8_t> certificate; + Vector<uint8_t> wrappedKey; readVector(data, response); - reply->writeInt32(provideProvisionResponse(response)); + status_t result = provideProvisionResponse(response, certificate, wrappedKey); + writeVector(reply, certificate); + writeVector(reply, wrappedKey); + reply->writeInt32(result); return OK; } @@ -725,6 +763,20 @@ status_t BnDrm::onTransact( return OK; } + case SIGN_RSA: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> sessionId, message, wrappedKey, signature; + readVector(data, sessionId); + String8 algorithm = data.readString8(); + readVector(data, message); + readVector(data, wrappedKey); + uint32_t result = signRSA(sessionId, algorithm, message, wrappedKey, signature); + writeVector(reply, signature); + reply->writeInt32(result); + return OK; + } + case SET_LISTENER: { CHECK_INTERFACE(IDrm, data, reply); sp<IDrmClient> listener = diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp index eebcb79..d50037f 100644 --- a/media/libmediaplayerservice/Drm.cpp +++ b/media/libmediaplayerservice/Drm.cpp @@ -28,9 +28,21 @@ #include <media/stagefright/foundation/AString.h> #include <media/stagefright/foundation/hexdump.h> #include <media/stagefright/MediaErrors.h> +#include <binder/IServiceManager.h> +#include <binder/IPCThreadState.h> namespace android { +static bool checkPermission(const char* permissionString) { +#ifndef HAVE_ANDROID_OS + return true; +#endif + if (getpid() == IPCThreadState::self()->getCallingPid()) return true; + bool ok = checkCallingPermission(String16(permissionString)); + if (!ok) ALOGE("Request requires %s", permissionString); + return ok; +} + KeyedVector<Vector<uint8_t>, String8> Drm::mUUIDToLibraryPathMap; KeyedVector<String8, wp<SharedLibrary> > Drm::mLibraryPathToOpenLibraryMap; Mutex Drm::mMapLock; @@ -373,7 +385,8 @@ status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId, return mPlugin->queryKeyStatus(sessionId, infoMap); } -status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) { +status_t Drm::getProvisionRequest(String8 const &certType, String8 const &certAuthority, + Vector<uint8_t> &request, String8 &defaultUrl) { Mutex::Autolock autoLock(mLock); if (mInitCheck != OK) { @@ -384,10 +397,13 @@ status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) return -EINVAL; } - return mPlugin->getProvisionRequest(request, defaultUrl); + return mPlugin->getProvisionRequest(certType, certAuthority, + request, defaultUrl); } -status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) { +status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response, + Vector<uint8_t> &certificate, + Vector<uint8_t> &wrappedKey) { Mutex::Autolock autoLock(mLock); if (mInitCheck != OK) { @@ -398,7 +414,7 @@ status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) { return -EINVAL; } - return mPlugin->provideProvisionResponse(response); + return mPlugin->provideProvisionResponse(response, certificate, wrappedKey); } @@ -589,6 +605,28 @@ status_t Drm::verify(Vector<uint8_t> const &sessionId, return mPlugin->verify(sessionId, keyId, message, signature, match); } +status_t Drm::signRSA(Vector<uint8_t> const &sessionId, + String8 const &algorithm, + Vector<uint8_t> const &message, + Vector<uint8_t> const &wrappedKey, + Vector<uint8_t> &signature) { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + if (!checkPermission("android.permission.ACCESS_DRM_CERTIFICATES")) { + return -EPERM; + } + + return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature); +} + void Drm::binderDied(const wp<IBinder> &the_late_who) { delete mPlugin; diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h index 119fd50..3d4b0fc 100644 --- a/media/libmediaplayerservice/Drm.h +++ b/media/libmediaplayerservice/Drm.h @@ -66,10 +66,14 @@ struct Drm : public BnDrm, virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId, KeyedVector<String8, String8> &infoMap) const; - virtual status_t getProvisionRequest(Vector<uint8_t> &request, + virtual status_t getProvisionRequest(String8 const &certType, + String8 const &certAuthority, + Vector<uint8_t> &request, String8 &defaulUrl); - virtual status_t provideProvisionResponse(Vector<uint8_t> const &response); + virtual status_t provideProvisionResponse(Vector<uint8_t> const &response, + Vector<uint8_t> &certificate, + Vector<uint8_t> &wrappedKey); virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops); @@ -111,6 +115,12 @@ struct Drm : public BnDrm, Vector<uint8_t> const &signature, bool &match); + virtual status_t signRSA(Vector<uint8_t> const &sessionId, + String8 const &algorithm, + Vector<uint8_t> const &message, + Vector<uint8_t> const &wrappedKey, + Vector<uint8_t> &signature); + virtual status_t setListener(const sp<IDrmClient>& listener); virtual void sendEvent(DrmPlugin::EventType eventType, int extra, diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index ac40568..4aecb80 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -365,6 +365,7 @@ ACodec::ACodec() mIsEncoder(false), mUseMetadataOnEncoderOutput(false), mShutdownInProgress(false), + mExplicitShutdown(false), mEncoderDelay(0), mEncoderPadding(0), mChannelMaskPresent(false), @@ -3722,7 +3723,8 @@ bool ACodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) { int32_t keepComponentAllocated; CHECK(msg->findInt32( "keepComponentAllocated", &keepComponentAllocated)); - CHECK(!keepComponentAllocated); + ALOGW_IF(keepComponentAllocated, + "cannot keep component allocated on shutdown in Uninitialized state"); sp<AMessage> notify = mCodec->mNotify->dup(); notify->setInt32("what", ACodec::kWhatShutdownCompleted); @@ -3895,6 +3897,7 @@ void ACodec::LoadedState::stateEntered() { onShutdown(keepComponentAllocated); } + mCodec->mExplicitShutdown = false; } void ACodec::LoadedState::onShutdown(bool keepComponentAllocated) { @@ -3904,9 +3907,12 @@ void ACodec::LoadedState::onShutdown(bool keepComponentAllocated) { mCodec->changeState(mCodec->mUninitializedState); } - sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatShutdownCompleted); - notify->post(); + if (mCodec->mExplicitShutdown) { + sp<AMessage> notify = mCodec->mNotify->dup(); + notify->setInt32("what", ACodec::kWhatShutdownCompleted); + notify->post(); + mCodec->mExplicitShutdown = false; + } } bool ACodec::LoadedState::onMessageReceived(const sp<AMessage> &msg) { @@ -3940,6 +3946,7 @@ bool ACodec::LoadedState::onMessageReceived(const sp<AMessage> &msg) { CHECK(msg->findInt32( "keepComponentAllocated", &keepComponentAllocated)); + mCodec->mExplicitShutdown = true; onShutdown(keepComponentAllocated); handled = true; @@ -4359,6 +4366,7 @@ bool ACodec::ExecutingState::onMessageReceived(const sp<AMessage> &msg) { "keepComponentAllocated", &keepComponentAllocated)); mCodec->mShutdownInProgress = true; + mCodec->mExplicitShutdown = true; mCodec->mKeepComponentAllocated = keepComponentAllocated; mActive = false; diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 4bad14b..e924076 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -310,7 +310,7 @@ status_t AwesomePlayer::setDataSource_l( } } - ALOGI("setDataSource_l(URL suppressed)"); + ALOGI("setDataSource_l(%s)", uriDebugString(mUri, mFlags & INCOGNITO).c_str()); // The actual work will be done during preparation in the call to // ::finishSetDataSource_l to avoid blocking the calling thread in @@ -2823,7 +2823,7 @@ status_t AwesomePlayer::dump( fprintf(out, " AwesomePlayer\n"); if (mStats.mFd < 0) { - fprintf(out, " URI(suppressed)"); + fprintf(out, " URI(%s)", uriDebugString(mUri, mFlags & INCOGNITO).c_str()); } else { fprintf(out, " fd(%d)", mStats.mFd); } diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index e0419ca..601dccf 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -603,6 +603,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { postActivityNotificationIfPossible(); cancelPendingDequeueOperations(); + setState(UNINITIALIZED); break; } @@ -612,6 +613,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { mFlags |= kFlagStickyError; postActivityNotificationIfPossible(); + setState(UNINITIALIZED); break; } } diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp index e7cc46d..62aea36 100644 --- a/media/libstagefright/SurfaceMediaSource.cpp +++ b/media/libstagefright/SurfaceMediaSource.cpp @@ -54,9 +54,9 @@ SurfaceMediaSource::SurfaceMediaSource(uint32_t bufferWidth, uint32_t bufferHeig ALOGE("Invalid dimensions %dx%d", bufferWidth, bufferHeight); } - mBufferQueue = new BufferQueue(); - mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight); - mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER | + BufferQueue::createBufferQueue(&mProducer, &mConsumer); + mConsumer->setDefaultBufferSize(bufferWidth, bufferHeight); + mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_HW_TEXTURE); sp<ISurfaceComposer> composer(ComposerService::getComposerService()); @@ -68,7 +68,7 @@ SurfaceMediaSource::SurfaceMediaSource(uint32_t bufferWidth, uint32_t bufferHeig wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this); sp<BufferQueue::ProxyConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener); - status_t err = mBufferQueue->consumerConnect(proxy, false); + status_t err = mConsumer->consumerConnect(proxy, false); if (err != NO_ERROR) { ALOGE("SurfaceMediaSource: error connecting to BufferQueue: %s (%d)", strerror(-err), err); @@ -108,7 +108,7 @@ void SurfaceMediaSource::dump( Mutex::Autolock lock(mMutex); result.append(buffer); - mBufferQueue->dump(result, ""); + mConsumer->dump(result, ""); } status_t SurfaceMediaSource::setFrameRate(int32_t fps) @@ -166,7 +166,7 @@ status_t SurfaceMediaSource::start(MetaData *params) CHECK_GT(mMaxAcquiredBufferCount, 1); status_t err = - mBufferQueue->setMaxAcquiredBufferCount(mMaxAcquiredBufferCount); + mConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBufferCount); if (err != OK) { return err; @@ -223,7 +223,7 @@ status_t SurfaceMediaSource::stop() mMediaBuffersAvailableCondition.signal(); - return mBufferQueue->consumerDisconnect(); + return mConsumer->consumerDisconnect(); } sp<MetaData> SurfaceMediaSource::getFormat() @@ -293,7 +293,7 @@ status_t SurfaceMediaSource::read( // wait here till the frames come in from the client side while (mStarted) { - status_t err = mBufferQueue->acquireBuffer(&item, 0); + status_t err = mConsumer->acquireBuffer(&item, 0); if (err == BufferQueue::NO_BUFFER_AVAILABLE) { // wait for a buffer to be queued mFrameAvailableCondition.wait(mMutex); @@ -316,7 +316,7 @@ status_t SurfaceMediaSource::read( if (mStartTimeNs > 0) { if (item.mTimestamp < mStartTimeNs) { // This frame predates start of record, discard - mBufferQueue->releaseBuffer( + mConsumer->releaseBuffer( item.mBuf, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); continue; @@ -416,7 +416,7 @@ void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) { ALOGV("Slot %d returned, matches handle = %p", id, mSlots[id].mGraphicBuffer->handle); - mBufferQueue->releaseBuffer(id, mSlots[id].mFrameNumber, + mConsumer->releaseBuffer(id, mSlots[id].mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 4ff805f..047fac7 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -17,6 +17,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "Utils" #include <utils/Log.h> +#include <ctype.h> #include "include/ESDS.h" @@ -628,5 +629,40 @@ bool canOffloadStream(const sp<MetaData>& meta, bool hasVideo, return AudioSystem::isOffloadSupported(info); } +AString uriDebugString(const AString &uri, bool incognito) { + if (incognito) { + return AString("<URI suppressed>"); + } + + char prop[PROPERTY_VALUE_MAX]; + if (property_get("media.stagefright.log-uri", prop, "false") && + (!strcmp(prop, "1") || !strcmp(prop, "true"))) { + return uri; + } + + // find scheme + AString scheme; + const char *chars = uri.c_str(); + for (size_t i = 0; i < uri.size(); i++) { + const char c = chars[i]; + if (!isascii(c)) { + break; + } else if (isalpha(c)) { + continue; + } else if (i == 0) { + // first character must be a letter + break; + } else if (isdigit(c) || c == '+' || c == '.' || c =='-') { + continue; + } else if (c != ':') { + break; + } + scheme = AString(uri, 0, i); + scheme.append("://<suppressed>"); + return scheme; + } + return AString("<no-scheme URI suppressed>"); +} + } // namespace android diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index 4ac8999..532e36f 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -387,7 +387,7 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { bool signalError = false; if (inHeader->nFilledLen < 7) { ALOGE("Audio data too short to contain even the ADTS header. " - "Got %ld bytes.", inHeader->nFilledLen); + "Got %d bytes.", inHeader->nFilledLen); hexdump(adtsHeader, inHeader->nFilledLen); signalError = true; } else { @@ -400,7 +400,7 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { if (inHeader->nFilledLen < aac_frame_length) { ALOGE("Not enough audio data for the complete frame. " - "Got %ld bytes, frame size according to the ADTS " + "Got %d bytes, frame size according to the ADTS " "header is %u bytes.", inHeader->nFilledLen, aac_frame_length); hexdump(adtsHeader, inHeader->nFilledLen); diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp index 9a91579..6093621 100644 --- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp +++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp @@ -308,7 +308,7 @@ status_t SoftAACEncoder2::setAudioParams() { // We call this whenever sample rate, number of channels or bitrate change // in reponse to setParameter calls. - ALOGV("setAudioParams: %lu Hz, %lu channels, %lu bps", + ALOGV("setAudioParams: %u Hz, %u channels, %u bps", mSampleRate, mNumChannels, mBitRate); if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_AOT, @@ -364,7 +364,7 @@ void SoftAACEncoder2::onQueueFilled(OMX_U32 /* portIndex */) { OMX_U32 actualBitRate = aacEncoder_GetParam(mAACEncoder, AACENC_BITRATE); if (mBitRate != actualBitRate) { - ALOGW("Requested bitrate %lu unsupported, using %lu", mBitRate, actualBitRate); + ALOGW("Requested bitrate %u unsupported, using %u", mBitRate, actualBitRate); } AACENC_InfoStruct encInfo; diff --git a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp index a15b040..0f4a00d 100644 --- a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp +++ b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp @@ -827,7 +827,7 @@ void SoftAVCEncoder::onQueueFilled(OMX_U32 /* portIndex */) { if (mStoreMetaDataInBuffers) { if (inHeader->nFilledLen != 8) { ALOGE("MetaData buffer is wrong size! " - "(got %lu bytes, expected 8)", inHeader->nFilledLen); + "(got %u bytes, expected 8)", inHeader->nFilledLen); mSignalledError = true; notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); return; @@ -988,7 +988,7 @@ uint8_t *SoftAVCEncoder::extractGrallocData(void *data, buffer_handle_t *buffer) status_t res; if (type != kMetadataBufferTypeGrallocSource) { ALOGE("Data passed in with metadata mode does not have type " - "kMetadataBufferTypeGrallocSource (%d), has type %ld instead", + "kMetadataBufferTypeGrallocSource (%d), has type %d instead", kMetadataBufferTypeGrallocSource, type); return NULL; } diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp index 0c62ec0..1301060 100644 --- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp +++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp @@ -210,7 +210,7 @@ OMX_ERRORTYPE SoftFlacEncoder::internalSetParameter( mNumChannels = pcmParams->nChannels; mSampleRate = pcmParams->nSamplingRate; - ALOGV("will encode %ld channels at %ldHz", mNumChannels, mSampleRate); + ALOGV("will encode %d channels at %dHz", mNumChannels, mSampleRate); return configureEncoder(); } @@ -264,7 +264,7 @@ OMX_ERRORTYPE SoftFlacEncoder::internalSetParameter( void SoftFlacEncoder::onQueueFilled(OMX_U32 portIndex) { UNUSED_UNLESS_VERBOSE(portIndex); - ALOGV("SoftFlacEncoder::onQueueFilled(portIndex=%ld)", portIndex); + ALOGV("SoftFlacEncoder::onQueueFilled(portIndex=%d)", portIndex); if (mSignalledError) { return; @@ -296,7 +296,7 @@ void SoftFlacEncoder::onQueueFilled(OMX_U32 portIndex) { } if (inHeader->nFilledLen > kMaxInputBufferSize) { - ALOGE("input buffer too large (%ld).", inHeader->nFilledLen); + ALOGE("input buffer too large (%d).", inHeader->nFilledLen); mSignalledError = true; notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); return; @@ -412,7 +412,7 @@ FLAC__StreamEncoderWriteStatus SoftFlacEncoder::onEncodedFlacAvailable( OMX_ERRORTYPE SoftFlacEncoder::configureEncoder() { - ALOGV("SoftFlacEncoder::configureEncoder() numChannel=%ld, sampleRate=%ld", + ALOGV("SoftFlacEncoder::configureEncoder() numChannel=%d, sampleRate=%d", mNumChannels, mSampleRate); if (mSignalledError || (mFlacStreamEncoder == NULL)) { diff --git a/media/libstagefright/codecs/g711/dec/SoftG711.cpp b/media/libstagefright/codecs/g711/dec/SoftG711.cpp index 160ada0..240c0c1 100644 --- a/media/libstagefright/codecs/g711/dec/SoftG711.cpp +++ b/media/libstagefright/codecs/g711/dec/SoftG711.cpp @@ -212,7 +212,7 @@ void SoftG711::onQueueFilled(OMX_U32 /* portIndex */) { } if (inHeader->nFilledLen > kMaxNumSamplesPerFrame) { - ALOGE("input buffer too large (%ld).", inHeader->nFilledLen); + ALOGE("input buffer too large (%d).", inHeader->nFilledLen); notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); mSignalledError = true; diff --git a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp index 18f7d29..4debc48 100644 --- a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp +++ b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp @@ -202,13 +202,13 @@ void SoftGSM::onQueueFilled(OMX_U32 /* portIndex */) { } if (inHeader->nFilledLen > kMaxNumSamplesPerFrame) { - ALOGE("input buffer too large (%ld).", inHeader->nFilledLen); + ALOGE("input buffer too large (%d).", inHeader->nFilledLen); notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); mSignalledError = true; } if(((inHeader->nFilledLen / 65) * 65) != inHeader->nFilledLen) { - ALOGE("input buffer not multiple of 65 (%ld).", inHeader->nFilledLen); + ALOGE("input buffer not multiple of 65 (%d).", inHeader->nFilledLen); notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); mSignalledError = true; } diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp index ee8dcf2..e25709d 100644 --- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp +++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp @@ -685,7 +685,7 @@ void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) { if (mStoreMetaDataInBuffers) { if (inHeader->nFilledLen != 8) { ALOGE("MetaData buffer is wrong size! " - "(got %lu bytes, expected 8)", inHeader->nFilledLen); + "(got %u bytes, expected 8)", inHeader->nFilledLen); mSignalledError = true; notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); return; @@ -773,7 +773,7 @@ uint8_t *SoftMPEG4Encoder::extractGrallocData(void *data, buffer_handle_t *buffe status_t res; if (type != kMetadataBufferTypeGrallocSource) { ALOGE("Data passed in with metadata mode does not have type " - "kMetadataBufferTypeGrallocSource (%d), has type %ld instead", + "kMetadataBufferTypeGrallocSource (%d), has type %d instead", kMetadataBufferTypeGrallocSource, type); return NULL; } diff --git a/media/libstagefright/foundation/AString.cpp b/media/libstagefright/foundation/AString.cpp index dee786d..fcd825f 100644 --- a/media/libstagefright/foundation/AString.cpp +++ b/media/libstagefright/foundation/AString.cpp @@ -20,6 +20,7 @@ #include <stdlib.h> #include <string.h> +#include <utils/String8.h> #include "ADebug.h" #include "AString.h" @@ -48,6 +49,13 @@ AString::AString(const char *s, size_t size) setTo(s, size); } +AString::AString(const String8 &from) + : mData(NULL), + mSize(0), + mAllocSize(1) { + setTo(from.string(), from.length()); +} + AString::AString(const AString &from) : mData(NULL), mSize(0), diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index fd42e77..08a146f 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -477,11 +477,8 @@ void LiveSession::onConnect(const sp<AMessage> &msg) { headers = NULL; } -#if 1 - ALOGI("onConnect <URL suppressed>"); -#else - ALOGI("onConnect %s", url.c_str()); -#endif + // TODO currently we don't know if we are coming here from incognito mode + ALOGI("onConnect %s", uriDebugString(url).c_str()); mMasterURL = url; @@ -489,7 +486,7 @@ void LiveSession::onConnect(const sp<AMessage> &msg) { mPlaylist = fetchPlaylist(url.c_str(), NULL /* curPlaylistHash */, &dummy); if (mPlaylist == NULL) { - ALOGE("unable to fetch master playlist <URL suppressed>."); + ALOGE("unable to fetch master playlist %s.", uriDebugString(url).c_str()); postPrepared(ERROR_IO); return; diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index f22d650..785c515 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -798,7 +798,8 @@ status_t M3UParser::parseCipherInfo( if (MakeURL(baseURI.c_str(), val.c_str(), &absURI)) { val = absURI; } else { - ALOGE("failed to make absolute url for <URL suppressed>."); + ALOGE("failed to make absolute url for %s.", + uriDebugString(baseURI).c_str()); } } diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk index 446ff8c..2d8c1e1 100644 --- a/media/libstagefright/matroska/Android.mk +++ b/media/libstagefright/matroska/Android.mk @@ -8,7 +8,7 @@ LOCAL_C_INCLUDES:= \ $(TOP)/external/libvpx/libwebm \ $(TOP)/frameworks/native/include/media/openmax \ -LOCAL_CFLAGS += -Wno-multichar -Werror +LOCAL_CFLAGS += -Wno-multichar LOCAL_MODULE:= libstagefright_matroska diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index d4a7c7f..d7bec59 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -657,14 +657,22 @@ MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source) return; } + // from mkvparser::Segment::Load(), but stop at first cluster ret = mSegment->ParseHeaders(); - CHECK_EQ(ret, 0); - - long len; - ret = mSegment->LoadCluster(pos, len); - CHECK_EQ(ret, 0); + if (ret == 0) { + long len; + ret = mSegment->LoadCluster(pos, len); + if (ret >= 1) { + // no more clusters + ret = 0; + } + } else if (ret > 0) { + ret = mkvparser::E_BUFFER_NOT_FULL; + } if (ret < 0) { + ALOGW("Corrupt %s source: %s", mIsWebm ? "webm" : "matroska", + uriDebugString(mDataSource->getUri()).c_str()); delete mSegment; mSegment = NULL; return; diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index 5bea7a6..1be76b3 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -68,13 +68,13 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, String8 name("GraphicBufferSource"); - mBufferQueue = new BufferQueue(); - mBufferQueue->setConsumerName(name); - mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight); - mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER | + BufferQueue::createBufferQueue(&mProducer, &mConsumer); + mConsumer->setConsumerName(name); + mConsumer->setDefaultBufferSize(bufferWidth, bufferHeight); + mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_HW_TEXTURE); - mInitCheck = mBufferQueue->setMaxAcquiredBufferCount(bufferCount); + mInitCheck = mConsumer->setMaxAcquiredBufferCount(bufferCount); if (mInitCheck != NO_ERROR) { ALOGE("Unable to set BQ max acquired buffer count to %u: %d", bufferCount, mInitCheck); @@ -88,7 +88,7 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, wp<BufferQueue::ConsumerListener> listener = static_cast<BufferQueue::ConsumerListener*>(this); sp<BufferQueue::ProxyConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener); - mInitCheck = mBufferQueue->consumerConnect(proxy, false); + mInitCheck = mConsumer->consumerConnect(proxy, false); if (mInitCheck != NO_ERROR) { ALOGE("Error connecting to BufferQueue: %s (%d)", strerror(-mInitCheck), mInitCheck); @@ -100,8 +100,8 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, GraphicBufferSource::~GraphicBufferSource() { ALOGV("~GraphicBufferSource"); - if (mBufferQueue != NULL) { - status_t err = mBufferQueue->consumerDisconnect(); + if (mConsumer != NULL) { + status_t err = mConsumer->consumerDisconnect(); if (err != NO_ERROR) { ALOGW("consumerDisconnect failed: %d", err); } @@ -273,7 +273,7 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) { if (id == mLatestSubmittedBufferId) { CHECK_GT(mLatestSubmittedBufferUseCount--, 0); } else { - mBufferQueue->releaseBuffer(id, codecBuffer.mFrameNumber, + mConsumer->releaseBuffer(id, codecBuffer.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); } } else { @@ -342,7 +342,7 @@ void GraphicBufferSource::suspend(bool suspend) { while (mNumFramesAvailable > 0) { BufferQueue::BufferItem item; - status_t err = mBufferQueue->acquireBuffer(&item, 0); + status_t err = mConsumer->acquireBuffer(&item, 0); if (err == BufferQueue::NO_BUFFER_AVAILABLE) { // shouldn't happen. @@ -355,7 +355,7 @@ void GraphicBufferSource::suspend(bool suspend) { --mNumFramesAvailable; - mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, + mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence); } return; @@ -392,7 +392,7 @@ bool GraphicBufferSource::fillCodecBuffer_l() { ALOGV("fillCodecBuffer_l: acquiring buffer, avail=%d", mNumFramesAvailable); BufferQueue::BufferItem item; - status_t err = mBufferQueue->acquireBuffer(&item, 0); + status_t err = mConsumer->acquireBuffer(&item, 0); if (err == BufferQueue::NO_BUFFER_AVAILABLE) { // shouldn't happen ALOGW("fillCodecBuffer_l: frame was not available"); @@ -433,7 +433,7 @@ bool GraphicBufferSource::fillCodecBuffer_l() { if (err != OK) { ALOGV("submitBuffer_l failed, releasing bq buf %d", item.mBuf); - mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, + mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); } else { ALOGV("buffer submitted (bq %d, cbi %d)", item.mBuf, cbi); @@ -456,7 +456,7 @@ bool GraphicBufferSource::repeatLatestSubmittedBuffer_l() { // // To be on the safe side we try to release the buffer. ALOGD("repeatLatestSubmittedBuffer_l: slot was NULL"); - mBufferQueue->releaseBuffer( + mConsumer->releaseBuffer( mLatestSubmittedBufferId, mLatestSubmittedBufferFrameNum, EGL_NO_DISPLAY, @@ -510,7 +510,7 @@ void GraphicBufferSource::setLatestSubmittedBuffer_l( if (mLatestSubmittedBufferId >= 0) { if (mLatestSubmittedBufferUseCount == 0) { - mBufferQueue->releaseBuffer( + mConsumer->releaseBuffer( mLatestSubmittedBufferId, mLatestSubmittedBufferFrameNum, EGL_NO_DISPLAY, @@ -733,7 +733,7 @@ void GraphicBufferSource::onFrameAvailable() { } BufferQueue::BufferItem item; - status_t err = mBufferQueue->acquireBuffer(&item, 0); + status_t err = mConsumer->acquireBuffer(&item, 0); if (err == OK) { // If this is the first time we're seeing this buffer, add it to our // slot table. @@ -741,7 +741,7 @@ void GraphicBufferSource::onFrameAvailable() { ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mBuf); mBufferSlot[item.mBuf] = item.mGraphicBuffer; } - mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, + mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence); } return; @@ -762,7 +762,7 @@ void GraphicBufferSource::onBuffersReleased() { Mutex::Autolock lock(mMutex); uint32_t slotMask; - if (mBufferQueue->getReleasedBuffers(&slotMask) != NO_ERROR) { + if (mConsumer->getReleasedBuffers(&slotMask) != NO_ERROR) { ALOGW("onBuffersReleased: unable to get released buffer set"); slotMask = 0xffffffff; } diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h index 757edc8..a70cc1a 100644 --- a/media/libstagefright/omx/GraphicBufferSource.h +++ b/media/libstagefright/omx/GraphicBufferSource.h @@ -61,7 +61,7 @@ public: // Returns the handle to the producer side of the BufferQueue. Buffers // queued on this will be received by GraphicBufferSource. sp<IGraphicBufferProducer> getIGraphicBufferProducer() const { - return mBufferQueue; + return mProducer; } // This is called when OMX transitions to OMX_StateExecuting, which means @@ -210,8 +210,11 @@ private: bool mSuspended; - // We consume graphic buffers from this. - sp<BufferQueue> mBufferQueue; + // Our BufferQueue interfaces. mProducer is passed to the producer through + // getIGraphicBufferProducer, and mConsumer is used internally to retrieve + // the buffers queued by the producer. + sp<IGraphicBufferProducer> mProducer; + sp<IGraphicBufferConsumer> mConsumer; // Number of frames pending in BufferQueue that haven't yet been // forwarded to the codec. diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp index cc3b63c..f25539c 100644 --- a/media/libstagefright/rtsp/ARTSPConnection.cpp +++ b/media/libstagefright/rtsp/ARTSPConnection.cpp @@ -239,7 +239,7 @@ void ARTSPConnection::onConnect(const sp<AMessage> &msg) { // right here, since we currently have no way of asking the user // for this information. - ALOGE("Malformed rtsp url <URL suppressed>"); + ALOGE("Malformed rtsp url %s", uriDebugString(url).c_str()); reply->setInt32("result", ERROR_MALFORMED); reply->post(); diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp index 09f7eee..424badf 100644 --- a/media/libstagefright/rtsp/SDPLoader.cpp +++ b/media/libstagefright/rtsp/SDPLoader.cpp @@ -27,6 +27,7 @@ #include <media/stagefright/MediaHTTP.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/Utils.h> #define DEFAULT_SDP_SIZE 100000 @@ -89,11 +90,7 @@ void SDPLoader::onLoad(const sp<AMessage> &msg) { KeyedVector<String8, String8> *headers = NULL; msg->findPointer("headers", (void **)&headers); - if (!(mFlags & kFlagIncognito)) { - ALOGV("onLoad '%s'", url.c_str()); - } else { - ALOGI("onLoad <URL suppressed>"); - } + ALOGV("onLoad %s", uriDebugString(url, mFlags & kFlagIncognito).c_str()); if (!mCancelled) { err = mHTTPDataSource->connect(url.c_str(), headers); diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp index a3093d0..fd889f9 100644 --- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp +++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp @@ -109,7 +109,7 @@ protected: } else { ALOGV("No actual display. Choosing EGLSurface based on SurfaceMediaSource"); sp<IGraphicBufferProducer> sms = (new SurfaceMediaSource( - getSurfaceWidth(), getSurfaceHeight()))->getBufferQueue(); + getSurfaceWidth(), getSurfaceHeight()))->getProducer(); sp<Surface> stc = new Surface(sms); sp<ANativeWindow> window = stc; @@ -360,9 +360,7 @@ protected: virtual void SetUp() { android::ProcessState::self()->startThreadPool(); mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight); - - // Manual cast is required to avoid constructor ambiguity - mSTC = new Surface(static_cast<sp<IGraphicBufferProducer> >( mSMS->getBufferQueue())); + mSTC = new Surface(mSMS->getProducer()); mANW = mSTC; } @@ -397,7 +395,7 @@ protected: ALOGV("SMS-GLTest::SetUp()"); android::ProcessState::self()->startThreadPool(); mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight); - mSTC = new Surface(static_cast<sp<IGraphicBufferProducer> >( mSMS->getBufferQueue())); + mSTC = new Surface(mSMS->getProducer()); mANW = mSTC; // Doing the setup related to the GL Side @@ -782,7 +780,7 @@ TEST_F(SurfaceMediaSourceGLTest, ChooseAndroidRecordableEGLConfigDummyWriter) { ALOGV("Verify creating a surface w/ right config + dummy writer*********"); mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight); - mSTC = new Surface(static_cast<sp<IGraphicBufferProducer> >( mSMS->getBufferQueue())); + mSTC = new Surface(mSMS->getProducer()); mANW = mSTC; DummyRecorder writer(mSMS); diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk index 6a8b9fc..c4cfa17 100644 --- a/media/libstagefright/timedtext/Android.mk +++ b/media/libstagefright/timedtext/Android.mk @@ -9,7 +9,7 @@ LOCAL_SRC_FILES:= \ TimedTextSRTSource.cpp \ TimedTextPlayer.cpp -LOCAL_CFLAGS += -Wno-multichar -Werror +LOCAL_CFLAGS += -Wno-multichar LOCAL_C_INCLUDES:= \ $(TOP)/frameworks/av/include/media/stagefright/timedtext \ diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp index 1a5acba..2cb4786 100644 --- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp +++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp @@ -1055,7 +1055,7 @@ status_t WifiDisplaySource::PlaybackSession::addVideoSource( err = source->setMaxAcquiredBufferCount(numInputBuffers); CHECK_EQ(err, (status_t)OK); - mBufferQueue = source->getBufferQueue(); + mProducer = source->getProducer(); return OK; } @@ -1079,7 +1079,7 @@ status_t WifiDisplaySource::PlaybackSession::addAudioSource(bool usePCMAudio) { } sp<IGraphicBufferProducer> WifiDisplaySource::PlaybackSession::getSurfaceTexture() { - return mBufferQueue; + return mProducer; } void WifiDisplaySource::PlaybackSession::requestIDRFrame() { diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.h b/media/libstagefright/wifi-display/source/PlaybackSession.h index 5c8ee94..2824143 100644 --- a/media/libstagefright/wifi-display/source/PlaybackSession.h +++ b/media/libstagefright/wifi-display/source/PlaybackSession.h @@ -25,7 +25,6 @@ namespace android { struct ABuffer; -struct BufferQueue; struct IHDCP; struct IGraphicBufferProducer; struct MediaPuller; @@ -111,7 +110,7 @@ private: int64_t mLastLifesignUs; - sp<BufferQueue> mBufferQueue; + sp<IGraphicBufferProducer> mProducer; KeyedVector<size_t, sp<Track> > mTracks; ssize_t mVideoTrackIndex; diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp index a1783fe..2d67efb 100644 --- a/services/audioflinger/AudioMixer.cpp +++ b/services/audioflinger/AudioMixer.cpp @@ -1181,7 +1181,7 @@ void AudioMixer::process__genericNoResampling(state_t* state, int64_t pts) } switch (t1.mMixerFormat) { case AUDIO_FORMAT_PCM_FLOAT: - memcpy_to_float_from_q19_12(reinterpret_cast<float *>(out), outTemp, BLOCKSIZE * 2); + memcpy_to_float_from_q4_27(reinterpret_cast<float *>(out), outTemp, BLOCKSIZE * 2); out += BLOCKSIZE * 2; // output is 2 floats/frame. break; case AUDIO_FORMAT_PCM_16_BIT: @@ -1274,7 +1274,7 @@ void AudioMixer::process__genericResampling(state_t* state, int64_t pts) } switch (t1.mMixerFormat) { case AUDIO_FORMAT_PCM_FLOAT: - memcpy_to_float_from_q19_12(reinterpret_cast<float*>(out), outTemp, numFrames*2); + memcpy_to_float_from_q4_27(reinterpret_cast<float*>(out), outTemp, numFrames*2); break; case AUDIO_FORMAT_PCM_16_BIT: ditherAndClamp(out, outTemp, numFrames); @@ -1330,8 +1330,8 @@ void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, in += 2; int32_t l = mulRL(1, rl, vrl); int32_t r = mulRL(0, rl, vrl); - *fout++ = float_from_q19_12(l); - *fout++ = float_from_q19_12(r); + *fout++ = float_from_q4_27(l); + *fout++ = float_from_q4_27(r); // Note: In case of later int16_t sink output, // conversion and clamping is done by memcpy_to_i16_from_float(). } while (--outFrames); diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp index ca98f16..562c4ea 100644 --- a/services/audioflinger/AudioResampler.cpp +++ b/services/audioflinger/AudioResampler.cpp @@ -234,7 +234,16 @@ AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount, case DYN_MED_QUALITY: case DYN_HIGH_QUALITY: ALOGV("Create dynamic Resampler = %d", quality); - resampler = new AudioResamplerDyn(bitDepth, inChannelCount, sampleRate, quality); + if (bitDepth == 32) { /* bitDepth == 32 signals float precision */ + resampler = new AudioResamplerDyn<float, float, float>(bitDepth, inChannelCount, + sampleRate, quality); + } else if (quality == DYN_HIGH_QUALITY) { + resampler = new AudioResamplerDyn<int32_t, int16_t, int32_t>(bitDepth, inChannelCount, + sampleRate, quality); + } else { + resampler = new AudioResamplerDyn<int16_t, int16_t, int32_t>(bitDepth, inChannelCount, + sampleRate, quality); + } break; } diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h index 0592855..b84567e 100644 --- a/services/audioflinger/AudioResampler.h +++ b/services/audioflinger/AudioResampler.h @@ -63,7 +63,7 @@ public: // A mono provider delivers a sequence of samples. // A stereo provider delivers a sequence of interleaved pairs of samples. // Multi-channel providers are not supported. - // In either case, 'out' holds interleaved pairs of fixed-point signed Q19.12. + // In either case, 'out' holds interleaved pairs of fixed-point Q4.27. // That is, for a mono provider, there is an implicit up-channeling. // Since this method accumulates, the caller is responsible for clearing 'out' initially. // FIXME assumes provider is always successful; it should return the actual frame count. diff --git a/services/audioflinger/AudioResamplerDyn.cpp b/services/audioflinger/AudioResamplerDyn.cpp index 7e4ca0c..3abe8fd 100644 --- a/services/audioflinger/AudioResamplerDyn.cpp +++ b/services/audioflinger/AudioResamplerDyn.cpp @@ -25,6 +25,7 @@ #include <cutils/compiler.h> #include <cutils/properties.h> +#include <utils/Debug.h> #include <utils/Log.h> #include "AudioResamplerFirOps.h" // USE_NEON and USE_INLINE_ASSEMBLY defined here @@ -38,9 +39,9 @@ namespace android { // generate a unique resample type compile-time constant (constexpr) -#define RESAMPLETYPE(CHANNELS, LOCKED, STRIDE, COEFTYPE) \ - ((((CHANNELS)-1)&1) | !!(LOCKED)<<1 | (COEFTYPE)<<2 \ - | ((STRIDE)==8 ? 1 : (STRIDE)==16 ? 2 : 0)<<3) +#define RESAMPLETYPE(CHANNELS, LOCKED, STRIDE) \ + ((((CHANNELS)-1)&1) | !!(LOCKED)<<1 \ + | ((STRIDE)==8 ? 1 : (STRIDE)==16 ? 2 : 0)<<2) /* * InBuffer is a type agnostic input buffer. @@ -58,42 +59,46 @@ namespace android { * r = extra space for implementing the ring buffer */ -template<typename TI> -AudioResamplerDyn::InBuffer<TI>::InBuffer() - : mState(NULL), mImpulse(NULL), mRingFull(NULL), mStateSize(0) { +template<typename TC, typename TI, typename TO> +AudioResamplerDyn<TC, TI, TO>::InBuffer::InBuffer() + : mState(NULL), mImpulse(NULL), mRingFull(NULL), mStateCount(0) +{ } -template<typename TI> -AudioResamplerDyn::InBuffer<TI>::~InBuffer() { +template<typename TC, typename TI, typename TO> +AudioResamplerDyn<TC, TI, TO>::InBuffer::~InBuffer() +{ init(); } -template<typename TI> -void AudioResamplerDyn::InBuffer<TI>::init() { +template<typename TC, typename TI, typename TO> +void AudioResamplerDyn<TC, TI, TO>::InBuffer::init() +{ free(mState); mState = NULL; mImpulse = NULL; mRingFull = NULL; - mStateSize = 0; + mStateCount = 0; } // resizes the state buffer to accommodate the appropriate filter length -template<typename TI> -void AudioResamplerDyn::InBuffer<TI>::resize(int CHANNELS, int halfNumCoefs) { +template<typename TC, typename TI, typename TO> +void AudioResamplerDyn<TC, TI, TO>::InBuffer::resize(int CHANNELS, int halfNumCoefs) +{ // calculate desired state size - int stateSize = halfNumCoefs * CHANNELS * 2 - * kStateSizeMultipleOfFilterLength; + int stateCount = halfNumCoefs * CHANNELS * 2 * kStateSizeMultipleOfFilterLength; // check if buffer needs resizing if (mState - && stateSize == mStateSize - && mRingFull-mState == mStateSize-halfNumCoefs*CHANNELS) { + && stateCount == mStateCount + && mRingFull-mState == mStateCount-halfNumCoefs*CHANNELS) { return; } // create new buffer - TI* state = (int16_t*)memalign(32, stateSize*sizeof(*state)); - memset(state, 0, stateSize*sizeof(*state)); + TI* state; + (void)posix_memalign(reinterpret_cast<void**>(&state), 32, stateCount*sizeof(*state)); + memset(state, 0, stateCount*sizeof(*state)); // attempt to preserve state if (mState) { @@ -105,8 +110,8 @@ void AudioResamplerDyn::InBuffer<TI>::resize(int CHANNELS, int halfNumCoefs) { dst += mState-srcLo; srcLo = mState; } - if (srcHi > mState + mStateSize) { - srcHi = mState + mStateSize; + if (srcHi > mState + mStateCount) { + srcHi = mState + mStateCount; } memcpy(dst, srcLo, (srcHi - srcLo) * sizeof(*srcLo)); free(mState); @@ -114,27 +119,29 @@ void AudioResamplerDyn::InBuffer<TI>::resize(int CHANNELS, int halfNumCoefs) { // set class member vars mState = state; - mStateSize = stateSize; - mImpulse = mState + halfNumCoefs*CHANNELS; // actually one sample greater than needed - mRingFull = mState + mStateSize - halfNumCoefs*CHANNELS; + mStateCount = stateCount; + mImpulse = state + halfNumCoefs*CHANNELS; // actually one sample greater than needed + mRingFull = state + mStateCount - halfNumCoefs*CHANNELS; } // copy in the input data into the head (impulse+halfNumCoefs) of the buffer. -template<typename TI> +template<typename TC, typename TI, typename TO> template<int CHANNELS> -void AudioResamplerDyn::InBuffer<TI>::readAgain(TI*& impulse, const int halfNumCoefs, - const TI* const in, const size_t inputIndex) { - int16_t* head = impulse + halfNumCoefs*CHANNELS; +void AudioResamplerDyn<TC, TI, TO>::InBuffer::readAgain(TI*& impulse, const int halfNumCoefs, + const TI* const in, const size_t inputIndex) +{ + TI* head = impulse + halfNumCoefs*CHANNELS; for (size_t i=0 ; i<CHANNELS ; i++) { head[i] = in[inputIndex*CHANNELS + i]; } } // advance the impulse pointer, and load in data into the head (impulse+halfNumCoefs) -template<typename TI> +template<typename TC, typename TI, typename TO> template<int CHANNELS> -void AudioResamplerDyn::InBuffer<TI>::readAdvance(TI*& impulse, const int halfNumCoefs, - const TI* const in, const size_t inputIndex) { +void AudioResamplerDyn<TC, TI, TO>::InBuffer::readAdvance(TI*& impulse, const int halfNumCoefs, + const TI* const in, const size_t inputIndex) +{ impulse += CHANNELS; if (CC_UNLIKELY(impulse >= mRingFull)) { @@ -145,7 +152,8 @@ void AudioResamplerDyn::InBuffer<TI>::readAdvance(TI*& impulse, const int halfNu readAgain<CHANNELS>(impulse, halfNumCoefs, in, inputIndex); } -void AudioResamplerDyn::Constants::set( +template<typename TC, typename TI, typename TO> +void AudioResamplerDyn<TC, TI, TO>::Constants::set( int L, int halfNumCoefs, int inSampleRate, int outSampleRate) { int bits = 0; @@ -158,10 +166,11 @@ void AudioResamplerDyn::Constants::set( mHalfNumCoefs = halfNumCoefs; } -AudioResamplerDyn::AudioResamplerDyn(int bitDepth, +template<typename TC, typename TI, typename TO> +AudioResamplerDyn<TC, TI, TO>::AudioResamplerDyn(int bitDepth, int inChannelCount, int32_t sampleRate, src_quality quality) : AudioResampler(bitDepth, inChannelCount, sampleRate, quality), - mResampleType(0), mFilterSampleRate(0), mFilterQuality(DEFAULT_QUALITY), + mResampleFunc(0), mFilterSampleRate(0), mFilterQuality(DEFAULT_QUALITY), mCoefBuffer(NULL) { mVolumeSimd[0] = mVolumeSimd[1] = 0; @@ -172,33 +181,48 @@ AudioResamplerDyn::AudioResamplerDyn(int bitDepth, mConstants.set(128, 8, mSampleRate, mSampleRate); // TODO: set better } -AudioResamplerDyn::~AudioResamplerDyn() { +template<typename TC, typename TI, typename TO> +AudioResamplerDyn<TC, TI, TO>::~AudioResamplerDyn() +{ free(mCoefBuffer); } -void AudioResamplerDyn::init() { +template<typename TC, typename TI, typename TO> +void AudioResamplerDyn<TC, TI, TO>::init() +{ mFilterSampleRate = 0; // always trigger new filter generation mInBuffer.init(); } -void AudioResamplerDyn::setVolume(int16_t left, int16_t right) { +template<typename TC, typename TI, typename TO> +void AudioResamplerDyn<TC, TI, TO>::setVolume(int16_t left, int16_t right) +{ AudioResampler::setVolume(left, right); - mVolumeSimd[0] = static_cast<int32_t>(left)<<16; - mVolumeSimd[1] = static_cast<int32_t>(right)<<16; + // volume is applied on the output type. + if (is_same<TO, float>::value || is_same<TO, double>::value) { + const TO scale = 1. / (1UL << 12); + mVolumeSimd[0] = static_cast<TO>(left) * scale; + mVolumeSimd[1] = static_cast<TO>(right) * scale; + } else { + mVolumeSimd[0] = static_cast<int32_t>(left) << 16; + mVolumeSimd[1] = static_cast<int32_t>(right) << 16; + } } -template <typename T> T max(T a, T b) {return a > b ? a : b;} +template<typename T> T max(T a, T b) {return a > b ? a : b;} -template <typename T> T absdiff(T a, T b) {return a > b ? a - b : b - a;} +template<typename T> T absdiff(T a, T b) {return a > b ? a - b : b - a;} -template<typename T> -void AudioResamplerDyn::createKaiserFir(Constants &c, double stopBandAtten, - int inSampleRate, int outSampleRate, double tbwCheat) { - T* buf = reinterpret_cast<T*>(memalign(32, (c.mL+1)*c.mHalfNumCoefs*sizeof(T))); +template<typename TC, typename TI, typename TO> +void AudioResamplerDyn<TC, TI, TO>::createKaiserFir(Constants &c, + double stopBandAtten, int inSampleRate, int outSampleRate, double tbwCheat) +{ + TC* buf; static const double atten = 0.9998; // to avoid ripple overflow double fcr; double tbw = firKaiserTbw(c.mHalfNumCoefs, stopBandAtten); + (void)posix_memalign(reinterpret_cast<void**>(&buf), 32, (c.mL+1)*c.mHalfNumCoefs*sizeof(TC)); if (inSampleRate < outSampleRate) { // upsample fcr = max(0.5*tbwCheat - tbw/2, tbw/2); } else { // downsample @@ -206,7 +230,7 @@ void AudioResamplerDyn::createKaiserFir(Constants &c, double stopBandAtten, } // create and set filter firKaiserGen(buf, c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, atten); - c.setBuf(buf); + c.mFirCoefs = buf; if (mCoefBuffer) { free(mCoefBuffer); } @@ -228,7 +252,8 @@ void AudioResamplerDyn::createKaiserFir(Constants &c, double stopBandAtten, } // recursive gcd. Using objdump, it appears the tail recursion is converted to a while loop. -static int gcd(int n, int m) { +static int gcd(int n, int m) +{ if (m == 0) { return n; } @@ -236,7 +261,8 @@ static int gcd(int n, int m) { } static bool isClose(int32_t newSampleRate, int32_t prevSampleRate, - int32_t filterSampleRate, int32_t outSampleRate) { + int32_t filterSampleRate, int32_t outSampleRate) +{ // different upsampling ratios do not need a filter change. if (filterSampleRate != 0 @@ -253,7 +279,9 @@ static bool isClose(int32_t newSampleRate, int32_t prevSampleRate, return pdiff < prevSampleRate>>4 && adiff < filterSampleRate>>3; } -void AudioResamplerDyn::setSampleRate(int32_t inSampleRate) { +template<typename TC, typename TI, typename TO> +void AudioResamplerDyn<TC, TI, TO>::setSampleRate(int32_t inSampleRate) +{ if (mInSampleRate == inSampleRate) { return; } @@ -357,13 +385,8 @@ void AudioResamplerDyn::setSampleRate(int32_t inSampleRate) { // create the filter mConstants.set(phases, halfLength, inSampleRate, mSampleRate); - if (useS32) { - createKaiserFir<int32_t>(mConstants, stopBandAtten, - inSampleRate, mSampleRate, tbwCheat); - } else { - createKaiserFir<int16_t>(mConstants, stopBandAtten, - inSampleRate, mSampleRate, tbwCheat); - } + createKaiserFir(mConstants, stopBandAtten, + inSampleRate, mSampleRate, tbwCheat); } // End Kaiser filter // update phase and state based on the new filter. @@ -385,7 +408,7 @@ void AudioResamplerDyn::setSampleRate(int32_t inSampleRate) { mPhaseFraction = mPhaseFraction >> c.mShift << c.mShift; // remove fractional phase } - mResampleType = RESAMPLETYPE(mChannelCount, locked, stride, !!useS32); + setResampler(RESAMPLETYPE(mChannelCount, locked, stride)); #ifdef DEBUG_RESAMPLER printf("channels:%d %s stride:%d %s coef:%d shift:%d\n", mChannelCount, locked ? "locked" : "interpolated", @@ -393,78 +416,45 @@ void AudioResamplerDyn::setSampleRate(int32_t inSampleRate) { #endif } -void AudioResamplerDyn::resample(int32_t* out, size_t outFrameCount, +template<typename TC, typename TI, typename TO> +void AudioResamplerDyn<TC, TI, TO>::resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider) { - // TODO: - // 24 cases - this perhaps can be reduced later, as testing might take too long - switch (mResampleType) { + (this->*mResampleFunc)(reinterpret_cast<TO*>(out), outFrameCount, provider); +} +template<typename TC, typename TI, typename TO> +void AudioResamplerDyn<TC, TI, TO>::setResampler(unsigned resampleType) +{ // stride 16 (falls back to stride 2 for machines that do not support NEON) - case RESAMPLETYPE(1, true, 16, 0): - return resample<1, true, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider); - case RESAMPLETYPE(2, true, 16, 0): - return resample<2, true, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider); - case RESAMPLETYPE(1, false, 16, 0): - return resample<1, false, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider); - case RESAMPLETYPE(2, false, 16, 0): - return resample<2, false, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider); - case RESAMPLETYPE(1, true, 16, 1): - return resample<1, true, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider); - case RESAMPLETYPE(2, true, 16, 1): - return resample<2, true, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider); - case RESAMPLETYPE(1, false, 16, 1): - return resample<1, false, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider); - case RESAMPLETYPE(2, false, 16, 1): - return resample<2, false, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider); -#if 0 - // TODO: Remove these? - // stride 8 - case RESAMPLETYPE(1, true, 8, 0): - return resample<1, true, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider); - case RESAMPLETYPE(2, true, 8, 0): - return resample<2, true, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider); - case RESAMPLETYPE(1, false, 8, 0): - return resample<1, false, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider); - case RESAMPLETYPE(2, false, 8, 0): - return resample<2, false, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider); - case RESAMPLETYPE(1, true, 8, 1): - return resample<1, true, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider); - case RESAMPLETYPE(2, true, 8, 1): - return resample<2, true, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider); - case RESAMPLETYPE(1, false, 8, 1): - return resample<1, false, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider); - case RESAMPLETYPE(2, false, 8, 1): - return resample<2, false, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider); - // stride 2 (can handle any filter length) - case RESAMPLETYPE(1, true, 2, 0): - return resample<1, true, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider); - case RESAMPLETYPE(2, true, 2, 0): - return resample<2, true, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider); - case RESAMPLETYPE(1, false, 2, 0): - return resample<1, false, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider); - case RESAMPLETYPE(2, false, 2, 0): - return resample<2, false, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider); - case RESAMPLETYPE(1, true, 2, 1): - return resample<1, true, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider); - case RESAMPLETYPE(2, true, 2, 1): - return resample<2, true, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider); - case RESAMPLETYPE(1, false, 2, 1): - return resample<1, false, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider); - case RESAMPLETYPE(2, false, 2, 1): - return resample<2, false, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider); -#endif + switch (resampleType) { + case RESAMPLETYPE(1, true, 16): + mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, true, 16>; + return; + case RESAMPLETYPE(2, true, 16): + mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, true, 16>; + return; + case RESAMPLETYPE(1, false, 16): + mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, false, 16>; + return; + case RESAMPLETYPE(2, false, 16): + mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, false, 16>; + return; default: - ; // error + LOG_ALWAYS_FATAL("Invalid resampler type: %u", resampleType); + mResampleFunc = NULL; + return; } } -template<int CHANNELS, bool LOCKED, int STRIDE, typename TC> -void AudioResamplerDyn::resample(int32_t* out, size_t outFrameCount, - const TC* const coefs, AudioBufferProvider* provider) +template<typename TC, typename TI, typename TO> +template<int CHANNELS, bool LOCKED, int STRIDE> +void AudioResamplerDyn<TC, TI, TO>::resample(TO* out, size_t outFrameCount, + AudioBufferProvider* provider) { const Constants& c(mConstants); - int16_t* impulse = mInBuffer.getImpulse(); + const TC* const coefs = mConstants.mFirCoefs; + TI* impulse = mInBuffer.getImpulse(); size_t inputIndex = mInputIndex; uint32_t phaseFraction = mPhaseFraction; const uint32_t phaseIncrement = mPhaseIncrement; @@ -490,8 +480,9 @@ void AudioResamplerDyn::resample(int32_t* out, size_t outFrameCount, goto resample_exit; } if (phaseFraction >= phaseWrapLimit) { // read in data - mInBuffer.readAdvance<CHANNELS>( - impulse, c.mHalfNumCoefs, mBuffer.i16, inputIndex); + mInBuffer.template readAdvance<CHANNELS>( + impulse, c.mHalfNumCoefs, + reinterpret_cast<TI*>(mBuffer.raw), inputIndex); phaseFraction -= phaseWrapLimit; while (phaseFraction >= phaseWrapLimit) { inputIndex++; @@ -500,20 +491,21 @@ void AudioResamplerDyn::resample(int32_t* out, size_t outFrameCount, provider->releaseBuffer(&mBuffer); break; } - mInBuffer.readAdvance<CHANNELS>( - impulse, c.mHalfNumCoefs, mBuffer.i16, inputIndex); + mInBuffer.template readAdvance<CHANNELS>( + impulse, c.mHalfNumCoefs, + reinterpret_cast<TI*>(mBuffer.raw), inputIndex); phaseFraction -= phaseWrapLimit; } } } - const int16_t* const in = mBuffer.i16; + const TI* const in = reinterpret_cast<const TI*>(mBuffer.raw); const size_t frameCount = mBuffer.frameCount; const int coefShift = c.mShift; const int halfNumCoefs = c.mHalfNumCoefs; - const int32_t* const volumeSimd = mVolumeSimd; + const TO* const volumeSimd = mVolumeSimd; // reread the last input in. - mInBuffer.readAgain<CHANNELS>(impulse, halfNumCoefs, in, inputIndex); + mInBuffer.template readAgain<CHANNELS>(impulse, halfNumCoefs, in, inputIndex); // main processing loop while (CC_LIKELY(outputIndex < outputSampleCount)) { @@ -536,7 +528,7 @@ void AudioResamplerDyn::resample(int32_t* out, size_t outFrameCount, if (inputIndex >= frameCount) { goto done; // need a new buffer } - mInBuffer.readAdvance<CHANNELS>(impulse, halfNumCoefs, in, inputIndex); + mInBuffer.template readAdvance<CHANNELS>(impulse, halfNumCoefs, in, inputIndex); phaseFraction -= phaseWrapLimit; } } @@ -555,5 +547,10 @@ resample_exit: mPhaseFraction = phaseFraction; } +/* instantiate templates used by AudioResampler::create */ +template class AudioResamplerDyn<float, float, float>; +template class AudioResamplerDyn<int16_t, int16_t, int32_t>; +template class AudioResamplerDyn<int32_t, int16_t, int32_t>; + // ---------------------------------------------------------------------------- }; // namespace android diff --git a/services/audioflinger/AudioResamplerDyn.h b/services/audioflinger/AudioResamplerDyn.h index df1fdbe..8c56319 100644 --- a/services/audioflinger/AudioResamplerDyn.h +++ b/services/audioflinger/AudioResamplerDyn.h @@ -25,10 +25,24 @@ namespace android { +/* AudioResamplerDyn + * + * This class template is used for floating point and integer resamplers. + * + * Type variables: + * TC = filter coefficient type (one of int16_t, int32_t, or float) + * TI = input data type (one of int16_t or float) + * TO = output data type (one of int32_t or float) + * + * For integer input data types TI, the coefficient type TC is either int16_t or int32_t. + * For float input data types TI, the coefficient type TC is float. + */ + +template<typename TC, typename TI, typename TO> class AudioResamplerDyn: public AudioResampler { public: - AudioResamplerDyn(int bitDepth, int inChannelCount, int32_t sampleRate, - src_quality quality); + AudioResamplerDyn(int bitDepth, int inChannelCount, + int32_t sampleRate, src_quality quality); virtual ~AudioResamplerDyn(); @@ -46,46 +60,38 @@ private: class Constants { // stores the filter constants. public: Constants() : - mL(0), mShift(0), mHalfNumCoefs(0), mFirCoefsS16(NULL) + mL(0), mShift(0), mHalfNumCoefs(0), mFirCoefs(NULL) {} void set(int L, int halfNumCoefs, int inSampleRate, int outSampleRate); - inline void setBuf(int16_t* buf) { - mFirCoefsS16 = buf; - } - inline void setBuf(int32_t* buf) { - mFirCoefsS32 = buf; - } - int mL; // interpolation phases in the filter. - int mShift; // right shift to get polyphase index + int mL; // interpolation phases in the filter. + int mShift; // right shift to get polyphase index unsigned int mHalfNumCoefs; // filter half #coefs - union { // polyphase filter bank - const int16_t* mFirCoefsS16; - const int32_t* mFirCoefsS32; - }; + const TC* mFirCoefs; // polyphase filter bank }; - // Input buffer management for a given input type TI, now (int16_t) - // Is agnostic of the actual type, can work with int32_t and float. - template<typename TI> - class InBuffer { + class InBuffer { // buffer management for input type TI public: InBuffer(); ~InBuffer(); void init(); + void resize(int CHANNELS, int halfNumCoefs); // used for direct management of the mImpulse pointer inline TI* getImpulse() { return mImpulse; } + inline void setImpulse(TI *impulse) { mImpulse = impulse; } + template<int CHANNELS> inline void readAgain(TI*& impulse, const int halfNumCoefs, const TI* const in, const size_t inputIndex); + template<int CHANNELS> inline void readAdvance(TI*& impulse, const int halfNumCoefs, const TI* const in, const size_t inputIndex); @@ -94,31 +100,35 @@ private: // tuning parameter guidelines: 2 <= multiple <= 8 static const int kStateSizeMultipleOfFilterLength = 4; - TI* mState; // base pointer for the input buffer storage - TI* mImpulse; // current location of the impulse response (centered) - TI* mRingFull; // mState <= mImpulse < mRingFull // in general, mRingFull = mState + mStateSize - halfNumCoefs*CHANNELS. - size_t mStateSize; // in units of TI. + TI* mState; // base pointer for the input buffer storage + TI* mImpulse; // current location of the impulse response (centered) + TI* mRingFull; // mState <= mImpulse < mRingFull + size_t mStateCount; // size of state in units of TI. }; - template<int CHANNELS, bool LOCKED, int STRIDE, typename TC> - void resample(int32_t* out, size_t outFrameCount, - const TC* const coefs, AudioBufferProvider* provider); - - template<typename T> void createKaiserFir(Constants &c, double stopBandAtten, int inSampleRate, int outSampleRate, double tbwCheat); - InBuffer<int16_t> mInBuffer; - Constants mConstants; // current set of coefficient parameters - int32_t __attribute__ ((aligned (8))) mVolumeSimd[2]; - int32_t mResampleType; // contains the resample type. - int32_t mFilterSampleRate; // designed filter sample rate. - src_quality mFilterQuality; // designed filter quality. - void* mCoefBuffer; // if a filter is created, this is not null + void setResampler(unsigned resampleType); + + template<int CHANNELS, bool LOCKED, int STRIDE> + void resample(TO* out, size_t outFrameCount, AudioBufferProvider* provider); + + // declare a pointer to member function for resample + typedef void (AudioResamplerDyn<TC, TI, TO>::*resample_ABP_t)(TO* out, + size_t outFrameCount, AudioBufferProvider* provider); + + // data - the contiguous storage and layout of these is important. + InBuffer mInBuffer; + Constants mConstants; // current set of coefficient parameters + TO __attribute__ ((aligned (8))) mVolumeSimd[2]; // must be aligned or NEON may crash + resample_ABP_t mResampleFunc; // called function for resampling + int32_t mFilterSampleRate; // designed filter sample rate. + src_quality mFilterQuality; // designed filter quality. + void* mCoefBuffer; // if a filter is created, this is not null }; -// ---------------------------------------------------------------------------- }; // namespace android #endif /*ANDROID_AUDIO_RESAMPLER_DYN_H*/ diff --git a/services/audioflinger/AudioResamplerFirGen.h b/services/audioflinger/AudioResamplerFirGen.h index 1f21c60..d024b2f 100644 --- a/services/audioflinger/AudioResamplerFirGen.h +++ b/services/audioflinger/AudioResamplerFirGen.h @@ -693,11 +693,12 @@ static inline void firKaiserGen(T* coef, int L, int halfNumCoef, sg.advance(); } - // (caution!) float version does not need rounding if (is_same<T, int16_t>::value) { // int16_t needs noise shaping *coef++ = static_cast<T>(toint(y, 1ULL<<(sizeof(T)*8-1), err)); - } else { + } else if (is_same<T, int32_t>::value) { *coef++ = static_cast<T>(toint(y, 1ULL<<(sizeof(T)*8-1))); + } else { // assumed float or double + *coef++ = static_cast<T>(y); } } } diff --git a/services/audioflinger/AudioResamplerFirProcess.h b/services/audioflinger/AudioResamplerFirProcess.h index 38e387c..76d2d66 100644 --- a/services/audioflinger/AudioResamplerFirProcess.h +++ b/services/audioflinger/AudioResamplerFirProcess.h @@ -21,47 +21,55 @@ namespace android { // depends on AudioResamplerFirOps.h -template<int CHANNELS, typename TC> +/* variant for input type TI = int16_t input samples */ +template<typename TC> static inline -void mac( - int32_t& l, int32_t& r, - const TC coef, - const int16_t* samples) +void mac(int32_t& l, int32_t& r, TC coef, const int16_t* samples) { - if (CHANNELS == 2) { - uint32_t rl = *reinterpret_cast<const uint32_t*>(samples); - l = mulAddRL(1, rl, coef, l); - r = mulAddRL(0, rl, coef, r); - } else { - r = l = mulAdd(samples[0], coef, l); - } + uint32_t rl = *reinterpret_cast<const uint32_t*>(samples); + l = mulAddRL(1, rl, coef, l); + r = mulAddRL(0, rl, coef, r); } -template<int CHANNELS, typename TC> +template<typename TC> static inline -void interpolate( - int32_t& l, int32_t& r, - const TC coef_0, const TC coef_1, - const int16_t lerp, const int16_t* samples) +void mac(int32_t& l, TC coef, const int16_t* samples) { - TC sinc; + l = mulAdd(samples[0], coef, l); +} - if (is_same<TC, int16_t>::value) { - sinc = (lerp * ((coef_1-coef_0)<<1)>>16) + coef_0; - } else { - sinc = mulAdd(lerp, (coef_1-coef_0)<<1, coef_0); - } - if (CHANNELS == 2) { - uint32_t rl = *reinterpret_cast<const uint32_t*>(samples); - l = mulAddRL(1, rl, sinc, l); - r = mulAddRL(0, rl, sinc, r); - } else { - r = l = mulAdd(samples[0], sinc, l); - } +/* variant for input type TI = float input samples */ +template<typename TC> +static inline +void mac(float& l, float& r, TC coef, const float* samples) +{ + l += *samples++ * coef; + r += *samples++ * coef; +} + +template<typename TC> +static inline +void mac(float& l, TC coef, const float* samples) +{ + l += *samples++ * coef; +} + +/* variant for output type TO = int32_t output samples */ +static inline +int32_t volumeAdjust(int32_t value, int32_t volume) +{ + return 2 * mulRL(0, value, volume); // Note: only use top 16b +} + +/* variant for output type TO = float output samples */ +static inline +float volumeAdjust(float value, float volume) +{ + return value * volume; } /* - * Calculates a single output sample (two stereo frames). + * Calculates a single output frame (two samples). * * This function computes both the positive half FIR dot product and * the negative half FIR dot product, accumulates, and then applies the volume. @@ -72,30 +80,43 @@ void interpolate( * filter bank. */ -template <int CHANNELS, int STRIDE, typename TC> +template <int CHANNELS, int STRIDE, typename TC, typename TI, typename TO> static inline -void ProcessL(int32_t* const out, +void ProcessL(TO* const out, int count, const TC* coefsP, const TC* coefsN, - const int16_t* sP, - const int16_t* sN, - const int32_t* const volumeLR) + const TI* sP, + const TI* sN, + const TO* const volumeLR) { - int32_t l = 0; - int32_t r = 0; - do { - mac<CHANNELS>(l, r, *coefsP++, sP); - sP -= CHANNELS; - mac<CHANNELS>(l, r, *coefsN++, sN); - sN += CHANNELS; - } while (--count > 0); - out[0] += 2 * mulRL(0, l, volumeLR[0]); // Note: only use top 16b - out[1] += 2 * mulRL(0, r, volumeLR[1]); // Note: only use top 16b + COMPILE_TIME_ASSERT_FUNCTION_SCOPE(CHANNELS >= 1 && CHANNELS <= 2) + if (CHANNELS == 2) { + TO l = 0; + TO r = 0; + do { + mac(l, r, *coefsP++, sP); + sP -= CHANNELS; + mac(l, r, *coefsN++, sN); + sN += CHANNELS; + } while (--count > 0); + out[0] += volumeAdjust(l, volumeLR[0]); + out[1] += volumeAdjust(r, volumeLR[1]); + } else { /* CHANNELS == 1 */ + TO l = 0; + do { + mac(l, *coefsP++, sP); + sP -= CHANNELS; + mac(l, *coefsN++, sN); + sN += CHANNELS; + } while (--count > 0); + out[0] += volumeAdjust(l, volumeLR[0]); + out[1] += volumeAdjust(l, volumeLR[1]); + } } /* - * Calculates a single output sample (two stereo frames) interpolating phase. + * Calculates a single output frame (two samples) interpolating phase. * * This function computes both the positive half FIR dot product and * the negative half FIR dot product, accumulates, and then applies the volume. @@ -106,47 +127,91 @@ void ProcessL(int32_t* const out, * filter bank. */ -template <int CHANNELS, int STRIDE, typename TC> +template<typename TC, typename T> +void adjustLerp(T& lerpP __unused) +{ +} + +template<int32_t, typename T> +void adjustLerp(T& lerpP) +{ + lerpP >>= 16; // lerpP is 32bit for NEON int32_t, but always 16 bit for non-NEON path +} + +template<typename TC, typename TINTERP> +static inline +TC interpolate(TC coef_0, TC coef_1, TINTERP lerp) +{ + return lerp * (coef_1 - coef_0) + coef_0; +} + +template<int16_t, uint32_t> +static inline +int16_t interpolate(int16_t coef_0, int16_t coef_1, uint32_t lerp) +{ + return (static_cast<int16_t>(lerp) * ((coef_1-coef_0)<<1)>>16) + coef_0; +} + +template<int32_t, uint32_t> +static inline +int32_t interpolate(int32_t coef_0, int32_t coef_1, uint32_t lerp) +{ + return mulAdd(static_cast<int16_t>(lerp), (coef_1-coef_0)<<1, coef_0); +} + +template <int CHANNELS, int STRIDE, typename TC, typename TI, typename TO, typename TINTERP> static inline -void Process(int32_t* const out, +void Process(TO* const out, int count, const TC* coefsP, const TC* coefsN, - const TC* coefsP1, - const TC* coefsN1, - const int16_t* sP, - const int16_t* sN, - uint32_t lerpP, - const int32_t* const volumeLR) + const TC* coefsP1 __unused, + const TC* coefsN1 __unused, + const TI* sP, + const TI* sN, + TINTERP lerpP, + const TO* const volumeLR) { - (void) coefsP1; // suppress unused parameter warning - (void) coefsN1; - if (sizeof(*coefsP)==4) { - lerpP >>= 16; // ensure lerpP is 16b - } - int32_t l = 0; - int32_t r = 0; - for (size_t i = 0; i < count; ++i) { - interpolate<CHANNELS>(l, r, coefsP[0], coefsP[count], lerpP, sP); - coefsP++; - sP -= CHANNELS; - interpolate<CHANNELS>(l, r, coefsN[count], coefsN[0], lerpP, sN); - coefsN++; - sN += CHANNELS; + COMPILE_TIME_ASSERT_FUNCTION_SCOPE(CHANNELS >= 1 && CHANNELS <= 2) + adjustLerp<TC, TINTERP>(lerpP); // coefficient type adjustment for interpolation + + if (CHANNELS == 2) { + TO l = 0; + TO r = 0; + for (size_t i = 0; i < count; ++i) { + mac(l, r, interpolate(coefsP[0], coefsP[count], lerpP), sP); + coefsP++; + sP -= CHANNELS; + mac(l, r, interpolate(coefsN[count], coefsN[0], lerpP), sN); + coefsN++; + sN += CHANNELS; + } + out[0] += volumeAdjust(l, volumeLR[0]); + out[1] += volumeAdjust(r, volumeLR[1]); + } else { /* CHANNELS == 1 */ + TO l = 0; + for (size_t i = 0; i < count; ++i) { + mac(l, interpolate(coefsP[0], coefsP[count], lerpP), sP); + coefsP++; + sP -= CHANNELS; + mac(l, interpolate(coefsN[count], coefsN[0], lerpP), sN); + coefsN++; + sN += CHANNELS; + } + out[0] += volumeAdjust(l, volumeLR[0]); + out[1] += volumeAdjust(l, volumeLR[1]); } - out[0] += 2 * mulRL(0, l, volumeLR[0]); // Note: only use top 16b - out[1] += 2 * mulRL(0, r, volumeLR[1]); // Note: only use top 16b } /* - * Calculates a single output sample (two stereo frames) from input sample pointer. + * Calculates a single output frame (two samples) from input sample pointer. * * This sets up the params for the accelerated Process() and ProcessL() * functions to do the appropriate dot products. * - * @param out should point to the output buffer with at least enough space for 2 output frames. + * @param out should point to the output buffer with space for at least one output frame. * - * @param phase is the fractional distance between input samples for interpolation: + * @param phase is the fractional distance between input frames for interpolation: * phase >= 0 && phase < phaseWrapLimit. It can be thought of as a rational fraction * of phase/phaseWrapLimit. * @@ -195,14 +260,17 @@ void Process(int32_t* const out, * lerpP = phase << sizeof(phase)*8 - coefShift * >> (sizeof(phase)-sizeof(*coefs))*8 + 1; * + * For floating point, lerpP is the fractional phase scaled to [0.0, 1.0): + * + * lerpP = (phase << 32 - coefShift) / (1 << 32); // floating point equivalent */ -template<int CHANNELS, bool LOCKED, int STRIDE, typename TC> +template<int CHANNELS, bool LOCKED, int STRIDE, typename TC, typename TI, typename TO> static inline -void fir(int32_t* const out, +void fir(TO* const out, const uint32_t phase, const uint32_t phaseWrapLimit, const int coefShift, const int halfNumCoefs, const TC* const coefs, - const int16_t* const samples, const int32_t* const volumeLR) + const TI* const samples, const TO* const volumeLR) { // NOTE: be very careful when modifying the code here. register // pressure is very high and a small change might cause the compiler @@ -216,8 +284,8 @@ void fir(int32_t* const out, uint32_t indexN = (phaseWrapLimit - phase) >> coefShift; const TC* coefsP = coefs + indexP*halfNumCoefs; const TC* coefsN = coefs + indexN*halfNumCoefs; - const int16_t* sP = samples; - const int16_t* sN = samples + CHANNELS; + const TI* sP = samples; + const TI* sN = samples + CHANNELS; // dot product filter. ProcessL<CHANNELS, STRIDE>(out, @@ -231,8 +299,8 @@ void fir(int32_t* const out, const TC* coefsN = coefs + indexN*halfNumCoefs; const TC* coefsP1 = coefsP + halfNumCoefs; const TC* coefsN1 = coefsN + halfNumCoefs; - const int16_t* sP = samples; - const int16_t* sN = samples + CHANNELS; + const TI* sP = samples; + const TI* sN = samples + CHANNELS; // Interpolation fraction lerpP derived by shifting all the way up and down // to clear the appropriate bits and align to the appropriate level @@ -242,12 +310,21 @@ void fir(int32_t* const out, // // interpolated[P] = index[P]*lerpP + index[P+1]*(1-lerpP) // interpolated[N] = index[N+1]*lerpP + index[N]*(1-lerpP) - uint32_t lerpP = phase << (sizeof(phase)*8 - coefShift) - >> ((sizeof(phase)-sizeof(*coefs))*8 + 1); // on-the-fly interpolated dot product filter - Process<CHANNELS, STRIDE>(out, - halfNumCoefs, coefsP, coefsN, coefsP1, coefsN1, sP, sN, lerpP, volumeLR); + if (is_same<TC, float>::value || is_same<TC, double>::value) { + static const TC scale = 1. / (65536. * 65536.); // scale phase bits to [0.0, 1.0) + TC lerpP = TC(phase << (sizeof(phase)*8 - coefShift)) * scale; + + Process<CHANNELS, STRIDE>(out, + halfNumCoefs, coefsP, coefsN, coefsP1, coefsN1, sP, sN, lerpP, volumeLR); + } else { + uint32_t lerpP = phase << (sizeof(phase)*8 - coefShift) + >> ((sizeof(phase)-sizeof(*coefs))*8 + 1); + + Process<CHANNELS, STRIDE>(out, + halfNumCoefs, coefsP, coefsN, coefsP1, coefsN1, sP, sN, lerpP, volumeLR); + } } } diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp index adb4aca..ca0d65e 100644 --- a/services/audioflinger/FastMixer.cpp +++ b/services/audioflinger/FastMixer.cpp @@ -236,6 +236,7 @@ bool FastMixer::threadLoop() sampleRate = Format_sampleRate(format); ALOG_ASSERT(Format_channelCount(format) == FCC_2); } + dumpState->mSampleRate = sampleRate; } if ((!Format_isEqual(format, previousFormat)) || (frameCount != previous->mFrameCount)) { diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h index 3ec9889..6fc06d8 100644 --- a/services/audioflinger/RecordTracks.h +++ b/services/audioflinger/RecordTracks.h @@ -66,7 +66,7 @@ private: // updated by RecordThread::readInputParameters_l() AudioResampler *mResampler; - // interleaved stereo pairs of fixed-point signed Q19.12 + // interleaved stereo pairs of fixed-point Q4.27 int32_t *mRsmpOutBuffer; // current allocated frame count for the above, which may be larger than needed size_t mRsmpOutFrameCount; diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 65e9eec..ae3dd8b 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -3951,6 +3951,16 @@ bool AudioFlinger::DirectOutputThread::checkForNewParameters_l() AudioParameter param = AudioParameter(keyValuePair); int value; + if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) { + // forward device change to effects that have requested to be + // aware of attached audio device. + if (value != AUDIO_DEVICE_NONE) { + mOutDevice = value; + for (size_t i = 0; i < mEffectChains.size(); i++) { + mEffectChains[i]->setDevice_l(mOutDevice); + } + } + } if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) { // do not accept frame count changes if tracks are open as the track buffer // size depends on frame count and correct behavior would not be garantied @@ -4954,7 +4964,7 @@ reacquire_wakelock: // ditherAndClamp() works as long as all buffers returned by // activeTrack->getNextBuffer() are 32 bit aligned which should be always true. if (activeTrack->mChannelCount == 1) { - // temporarily type pun mRsmpOutBuffer from Q19.12 to int16_t + // temporarily type pun mRsmpOutBuffer from Q4.27 to int16_t ditherAndClamp(activeTrack->mRsmpOutBuffer, activeTrack->mRsmpOutBuffer, framesOut); // the resampler always outputs stereo samples: diff --git a/services/audioflinger/test-resample.cpp b/services/audioflinger/test-resample.cpp index 3ab3ba9..e14b4ae 100644 --- a/services/audioflinger/test-resample.cpp +++ b/services/audioflinger/test-resample.cpp @@ -24,23 +24,28 @@ #include <sys/mman.h> #include <sys/stat.h> #include <errno.h> +#include <inttypes.h> #include <time.h> #include <math.h> +#include <audio_utils/primitives.h> #include <audio_utils/sndfile.h> #include <utils/Vector.h> using namespace android; -bool gVerbose = false; +static bool gVerbose = false; static int usage(const char* name) { - fprintf(stderr,"Usage: %s [-p] [-h] [-v] [-s] [-q {dq|lq|mq|hq|vhq|dlq|dmq|dhq}]" - " [-i input-sample-rate] [-o output-sample-rate] [-O csv] [-P csv] [<input-file>]" + fprintf(stderr,"Usage: %s [-p] [-f] [-F] [-v] [-c channels]" + " [-q {dq|lq|mq|hq|vhq|dlq|dmq|dhq}]" + " [-i input-sample-rate] [-o output-sample-rate]" + " [-O csv] [-P csv] [<input-file>]" " <output-file>\n", name); fprintf(stderr," -p enable profiling\n"); - fprintf(stderr," -h create wav file\n"); + fprintf(stderr," -f enable filter profiling\n"); + fprintf(stderr," -F enable floating point -q {dlq|dmq|dhq} only"); fprintf(stderr," -v verbose : log buffer provider calls\n"); - fprintf(stderr," -s stereo (ignored if input file is specified)\n"); + fprintf(stderr," -c # channels (1-2 for lq|mq|hq; 1-8 for dlq|dmq|dhq)\n"); fprintf(stderr," -q resampler quality\n"); fprintf(stderr," dq : default quality\n"); fprintf(stderr," lq : low quality\n"); @@ -97,11 +102,10 @@ int parseCSV(const char *string, Vector<int>& values) } int main(int argc, char* argv[]) { - const char* const progname = argv[0]; bool profileResample = false; bool profileFilter = false; - bool writeHeader = false; + bool useFloat = false; int channels = 1; int input_freq = 0; int output_freq = 0; @@ -110,7 +114,7 @@ int main(int argc, char* argv[]) { Vector<int> Pvalues; int ch; - while ((ch = getopt(argc, argv, "pfhvsq:i:o:O:P:")) != -1) { + while ((ch = getopt(argc, argv, "pfFvc:q:i:o:O:P:")) != -1) { switch (ch) { case 'p': profileResample = true; @@ -118,14 +122,14 @@ int main(int argc, char* argv[]) { case 'f': profileFilter = true; break; - case 'h': - writeHeader = true; + case 'F': + useFloat = true; break; case 'v': gVerbose = true; break; - case 's': - channels = 2; + case 'c': + channels = atoi(optarg); break; case 'q': if (!strcmp(optarg, "dq")) @@ -173,6 +177,17 @@ int main(int argc, char* argv[]) { return -1; } } + + if (channels < 1 + || channels > (quality < AudioResampler::DYN_LOW_QUALITY ? 2 : 8)) { + fprintf(stderr, "invalid number of audio channels %d\n", channels); + return -1; + } + if (useFloat && quality < AudioResampler::DYN_LOW_QUALITY) { + fprintf(stderr, "float processing is only possible for dynamic resamplers\n"); + return -1; + } + argc -= optind; argv += optind; @@ -219,27 +234,42 @@ int main(int argc, char* argv[]) { double t = double(i) / input_freq; double y = sin(M_PI * k * t * t); int16_t yi = floor(y * 32767.0 + 0.5); - for (size_t j=0 ; j<(size_t)channels ; j++) { - in[i*channels + j] = yi / (1+j); // right ch. 1/2 left ch. + for (int j = 0; j < channels; j++) { + in[i*channels + j] = yi / (1 + j); } } } + size_t input_framesize = channels * sizeof(int16_t); + size_t input_frames = input_size / input_framesize; + + // For float processing, convert input int16_t to float array + if (useFloat) { + void *new_vaddr; + + input_framesize = channels * sizeof(float); + input_size = input_frames * input_framesize; + new_vaddr = malloc(input_size); + memcpy_to_float_from_i16(reinterpret_cast<float*>(new_vaddr), + reinterpret_cast<int16_t*>(input_vaddr), input_frames * channels); + free(input_vaddr); + input_vaddr = new_vaddr; + } // ---------------------------------------------------------- class Provider: public AudioBufferProvider { - int16_t* const mAddr; // base address + const void* mAddr; // base address const size_t mNumFrames; // total frames - const int mChannels; + const size_t mFrameSize; // size of each frame in bytes size_t mNextFrame; // index of next frame to provide size_t mUnrel; // number of frames not yet released const Vector<int> mPvalues; // number of frames provided per call size_t mNextPidx; // index of next entry in mPvalues to use public: - Provider(const void* addr, size_t size, int channels, const Vector<int>& Pvalues) - : mAddr((int16_t*) addr), - mNumFrames(size / (channels*sizeof(int16_t))), - mChannels(channels), + Provider(const void* addr, size_t frames, size_t frameSize, const Vector<int>& Pvalues) + : mAddr(addr), + mNumFrames(frames), + mFrameSize(frameSize), mNextFrame(0), mUnrel(0), mPvalues(Pvalues), mNextPidx(0) { } virtual status_t getNextBuffer(Buffer* buffer, @@ -251,7 +281,7 @@ int main(int argc, char* argv[]) { } if (!mPvalues.isEmpty()) { size_t provided = mPvalues[mNextPidx++]; - printf("mPvalue[%d]=%u not %u\n", mNextPidx-1, provided, buffer->frameCount); + printf("mPvalue[%zu]=%zu not %zu\n", mNextPidx-1, provided, buffer->frameCount); if (provided < buffer->frameCount) { buffer->frameCount = provided; } @@ -260,47 +290,50 @@ int main(int argc, char* argv[]) { } } if (gVerbose) { - printf("getNextBuffer() requested %u frames out of %u frames available," - " and returned %u frames\n", - requestedFrames, mNumFrames - mNextFrame, buffer->frameCount); + printf("getNextBuffer() requested %zu frames out of %zu frames available," + " and returned %zu frames\n", + requestedFrames, (size_t) (mNumFrames - mNextFrame), buffer->frameCount); } mUnrel = buffer->frameCount; if (buffer->frameCount > 0) { - buffer->i16 = &mAddr[mChannels * mNextFrame]; + buffer->raw = (char *)mAddr + mFrameSize * mNextFrame; return NO_ERROR; } else { - buffer->i16 = NULL; + buffer->raw = NULL; return NOT_ENOUGH_DATA; } } virtual void releaseBuffer(Buffer* buffer) { if (buffer->frameCount > mUnrel) { - fprintf(stderr, "ERROR releaseBuffer() released %u frames but only %u available " + fprintf(stderr, "ERROR releaseBuffer() released %zu frames but only %zu available " "to release\n", buffer->frameCount, mUnrel); mNextFrame += mUnrel; mUnrel = 0; } else { if (gVerbose) { - printf("releaseBuffer() released %u frames out of %u frames available " + printf("releaseBuffer() released %zu frames out of %zu frames available " "to release\n", buffer->frameCount, mUnrel); } mNextFrame += buffer->frameCount; mUnrel -= buffer->frameCount; } buffer->frameCount = 0; - buffer->i16 = NULL; + buffer->raw = NULL; } void reset() { mNextFrame = 0; } - } provider(input_vaddr, input_size, channels, Pvalues); + } provider(input_vaddr, input_frames, input_framesize, Pvalues); - size_t input_frames = input_size / (channels * sizeof(int16_t)); if (gVerbose) { - printf("%u input frames\n", input_frames); + printf("%zu input frames\n", input_frames); } - size_t output_size = 2 * 4 * ((int64_t) input_frames * output_freq) / input_freq; - output_size &= ~7; // always stereo, 32-bits + + int bit_depth = useFloat ? 32 : 16; + int output_channels = channels > 2 ? channels : 2; // output is at least stereo samples + size_t output_framesize = output_channels * (useFloat ? sizeof(float) : sizeof(int32_t)); + size_t output_frames = ((int64_t) input_frames * output_freq) / input_freq; + size_t output_size = output_frames * output_framesize; if (profileFilter) { // Check how fast sample rate changes are that require filter changes. @@ -309,7 +342,7 @@ int main(int argc, char* argv[]) { // // On fast devices, filters should be generated between 0.1ms - 1ms. // (single threaded). - AudioResampler* resampler = AudioResampler::create(16, channels, + AudioResampler* resampler = AudioResampler::create(bit_depth, channels, 8000, quality); int looplimit = 100; timespec start, end; @@ -347,13 +380,14 @@ int main(int argc, char* argv[]) { } void* output_vaddr = malloc(output_size); - AudioResampler* resampler = AudioResampler::create(16, channels, + AudioResampler* resampler = AudioResampler::create(bit_depth, channels, output_freq, quality); - size_t out_frames = output_size/8; + /* set volume precision to 12 bits, so the volume scale is 1<<12. - * This means the "integer" part fits in the Q19.12 precision - * representation of output int32_t. + * The output int32_t is represented as Q4.27, with 4 bits of guard + * followed by the int16_t Q.15 portion, and then 12 trailing bits of + * additional precision. * * Generally 0 < volumePrecision <= 14 (due to the limits of * int16_t values for Volume). volumePrecision cannot be 0 due @@ -385,12 +419,12 @@ int main(int argc, char* argv[]) { const int trials = 4; const int looplimit = 4; timespec start, end; - int64_t time; + int64_t time = 0; for (int n = 0; n < trials; ++n) { clock_gettime(CLOCK_MONOTONIC, &start); for (int i = 0; i < looplimit; ++i) { - resampler->resample((int*) output_vaddr, out_frames, &provider); + resampler->resample((int*) output_vaddr, output_frames, &provider); provider.reset(); // during benchmarking reset only the provider } clock_gettime(CLOCK_MONOTONIC, &end); @@ -402,27 +436,27 @@ int main(int argc, char* argv[]) { } } // Mfrms/s is "Millions of output frames per second". - printf("quality: %d channels: %d msec: %lld Mfrms/s: %.2lf\n", - quality, channels, time/1000000, out_frames * looplimit / (time / 1e9) / 1e6); + printf("quality: %d channels: %d msec: %" PRId64 " Mfrms/s: %.2lf\n", + quality, channels, time/1000000, output_frames * looplimit / (time / 1e9) / 1e6); resampler->reset(); } memset(output_vaddr, 0, output_size); if (gVerbose) { - printf("resample() %u output frames\n", out_frames); + printf("resample() %zu output frames\n", output_frames); } if (Ovalues.isEmpty()) { - Ovalues.push(out_frames); + Ovalues.push(output_frames); } - for (size_t i = 0, j = 0; i < out_frames; ) { + for (size_t i = 0, j = 0; i < output_frames; ) { size_t thisFrames = Ovalues[j++]; if (j >= Ovalues.size()) { j = 0; } - if (thisFrames == 0 || thisFrames > out_frames - i) { - thisFrames = out_frames - i; + if (thisFrames == 0 || thisFrames > output_frames - i) { + thisFrames = output_frames - i; } - resampler->resample((int*) output_vaddr + 2*i, thisFrames, &provider); + resampler->resample((int*) output_vaddr + output_channels*i, thisFrames, &provider); i += thisFrames; } if (gVerbose) { @@ -435,17 +469,24 @@ int main(int argc, char* argv[]) { delete resampler; resampler = NULL; - // mono takes left channel only - // stereo right channel is half amplitude of stereo left channel (due to input creation) + // For float processing, convert output format from float to Q4.27, + // which is then converted to int16_t for final storage. + if (useFloat) { + memcpy_to_q4_27_from_float(reinterpret_cast<int32_t*>(output_vaddr), + reinterpret_cast<float*>(output_vaddr), output_frames * output_channels); + } + + // mono takes left channel only (out of stereo output pair) + // stereo and multichannel preserve all channels. int32_t* out = (int32_t*) output_vaddr; - int16_t* convert = (int16_t*) malloc(out_frames * channels * sizeof(int16_t)); + int16_t* convert = (int16_t*) malloc(output_frames * channels * sizeof(int16_t)); // round to half towards zero and saturate at int16 (non-dithered) const int roundVal = (1<<(volumePrecision-1)) - 1; // volumePrecision > 0 - for (size_t i = 0; i < out_frames; i++) { + for (size_t i = 0; i < output_frames; i++) { for (int j = 0; j < channels; j++) { - int32_t s = out[i * 2 + j] + roundVal; // add offset here + int32_t s = out[i * output_channels + j] + roundVal; // add offset here if (s < 0) { s = (s + 1) >> volumePrecision; // round to 0 if (s < -32768) { @@ -462,29 +503,18 @@ int main(int argc, char* argv[]) { } // write output to disk - if (writeHeader) { - SF_INFO info; - info.frames = 0; - info.samplerate = output_freq; - info.channels = channels; - info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; - SNDFILE *sf = sf_open(file_out, SFM_WRITE, &info); - if (sf == NULL) { - perror(file_out); - return EXIT_FAILURE; - } - (void) sf_writef_short(sf, convert, out_frames); - sf_close(sf); - } else { - int output_fd = open(file_out, O_WRONLY | O_CREAT | O_TRUNC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - if (output_fd < 0) { - perror(file_out); - return EXIT_FAILURE; - } - write(output_fd, convert, out_frames * channels * sizeof(int16_t)); - close(output_fd); + SF_INFO info; + info.frames = 0; + info.samplerate = output_freq; + info.channels = channels; + info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; + SNDFILE *sf = sf_open(file_out, SFM_WRITE, &info); + if (sf == NULL) { + perror(file_out); + return EXIT_FAILURE; } + (void) sf_writef_short(sf, convert, output_frames); + sf_close(sf); return EXIT_SUCCESS; } diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 5c6f653..02bca1f 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -1116,7 +1116,8 @@ void CameraService::BasicClient::opChanged(int32_t op, const String16& packageNa // Reset the client PID to allow server-initiated disconnect, // and to prevent further calls by client. mClientPid = getCallingPid(); - notifyError(); + CaptureResultExtras resultExtras; // a dummy result (invalid) + notifyError(ICameraDeviceCallbacks::ERROR_CAMERA_SERVICE, resultExtras); disconnect(); } } @@ -1145,7 +1146,8 @@ CameraService::Client* CameraService::Client::getClientFromCookie(void* user) { return client; } -void CameraService::Client::notifyError() { +void CameraService::Client::notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode, + const CaptureResultExtras& resultExtras) { mRemoteCallback->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0); } @@ -1199,7 +1201,8 @@ CameraService::ProClient::ProClient(const sp<CameraService>& cameraService, CameraService::ProClient::~ProClient() { } -void CameraService::ProClient::notifyError() { +void CameraService::ProClient::notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode, + const CaptureResultExtras& resultExtras) { mRemoteCallback->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0); } diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 8853e48..76ea7be 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -31,6 +31,7 @@ #include <camera/camera2/ICameraDeviceUser.h> #include <camera/camera2/ICameraDeviceCallbacks.h> #include <camera/VendorTagDescriptor.h> +#include <camera/CaptureResult.h> #include <camera/ICameraServiceListener.h> @@ -182,7 +183,9 @@ public: status_t finishCameraOps(); // Notify client about a fatal error - virtual void notifyError() = 0; + virtual void notifyError( + ICameraDeviceCallbacks::CameraErrorCode errorCode, + const CaptureResultExtras& resultExtras) = 0; private: AppOpsManager mAppOpsManager; @@ -259,7 +262,8 @@ public: // convert client from cookie. Client lock should be acquired before getting Client. static Client* getClientFromCookie(void* user); - virtual void notifyError(); + virtual void notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode, + const CaptureResultExtras& resultExtras); // Initialized in constructor @@ -307,7 +311,8 @@ public: virtual void onExclusiveLockStolen() = 0; protected: - virtual void notifyError(); + virtual void notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode, + const CaptureResultExtras& resultExtras); sp<IProCameraCallbacks> mRemoteCallback; }; // class ProClient diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp index f5c28ed..e5f5064 100644 --- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp +++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp @@ -106,13 +106,12 @@ void CaptureSequencer::notifyAutoExposure(uint8_t newState, int triggerId) { } } -void CaptureSequencer::onFrameAvailable(int32_t requestId, - const CameraMetadata &frame) { - ALOGV("%s: Listener found new frame", __FUNCTION__); +void CaptureSequencer::onResultAvailable(const CaptureResult &result) { ATRACE_CALL(); + ALOGV("%s: New result available.", __FUNCTION__); Mutex::Autolock l(mInputMutex); - mNewFrameId = requestId; - mNewFrame = frame; + mNewFrameId = result.mResultExtras.requestId; + mNewFrame = result.mMetadata; if (!mNewFrameReceived) { mNewFrameReceived = true; mNewFrameSignal.signal(); diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h index 9fb4ee7..d42ab13 100644 --- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h +++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h @@ -24,6 +24,7 @@ #include <utils/Mutex.h> #include <utils/Condition.h> #include "camera/CameraMetadata.h" +#include "camera/CaptureResult.h" #include "Parameters.h" #include "FrameProcessor.h" @@ -61,8 +62,8 @@ class CaptureSequencer: // Notifications about AE state changes void notifyAutoExposure(uint8_t newState, int triggerId); - // Notifications from the frame processor - virtual void onFrameAvailable(int32_t requestId, const CameraMetadata &frame); + // Notification from the frame processor + virtual void onResultAvailable(const CaptureResult &result); // Notifications from the JPEG processor void onCaptureAvailable(nsecs_t timestamp, sp<MemoryBase> captureBuffer); diff --git a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp index dd5b27c..69bea24 100644 --- a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp +++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp @@ -55,7 +55,7 @@ FrameProcessor::FrameProcessor(wp<CameraDeviceBase> device, FrameProcessor::~FrameProcessor() { } -bool FrameProcessor::processSingleFrame(CameraMetadata &frame, +bool FrameProcessor::processSingleFrame(CaptureResult &frame, const sp<CameraDeviceBase> &device) { sp<Camera2Client> client = mClient.promote(); @@ -66,19 +66,19 @@ bool FrameProcessor::processSingleFrame(CameraMetadata &frame, bool partialResult = false; if (mUsePartialQuirk) { camera_metadata_entry_t entry; - entry = frame.find(ANDROID_QUIRKS_PARTIAL_RESULT); + entry = frame.mMetadata.find(ANDROID_QUIRKS_PARTIAL_RESULT); if (entry.count > 0 && entry.data.u8[0] == ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL) { partialResult = true; } } - if (!partialResult && processFaceDetect(frame, client) != OK) { + if (!partialResult && processFaceDetect(frame.mMetadata, client) != OK) { return false; } if (mSynthesize3ANotify) { - process3aState(frame, client); + process3aState(frame.mMetadata, client); } return FrameProcessorBase::processSingleFrame(frame, device); diff --git a/services/camera/libcameraservice/api1/client2/FrameProcessor.h b/services/camera/libcameraservice/api1/client2/FrameProcessor.h index 856ad32..514bd1a 100644 --- a/services/camera/libcameraservice/api1/client2/FrameProcessor.h +++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.h @@ -51,7 +51,7 @@ class FrameProcessor : public FrameProcessorBase { void processNewFrames(const sp<Camera2Client> &client); - virtual bool processSingleFrame(CameraMetadata &frame, + virtual bool processSingleFrame(CaptureResult &frame, const sp<CameraDeviceBase> &device); status_t processFaceDetect(const CameraMetadata &frame, diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp index 6ab9e1a..2a2a5af 100644 --- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp +++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp @@ -73,18 +73,19 @@ void ZslProcessor::onFrameAvailable() { } } -void ZslProcessor::onFrameAvailable(int32_t /*requestId*/, - const CameraMetadata &frame) { +void ZslProcessor::onResultAvailable(const CaptureResult &result) { + ATRACE_CALL(); + ALOGV("%s:", __FUNCTION__); Mutex::Autolock l(mInputMutex); camera_metadata_ro_entry_t entry; - entry = frame.find(ANDROID_SENSOR_TIMESTAMP); + entry = result.mMetadata.find(ANDROID_SENSOR_TIMESTAMP); nsecs_t timestamp = entry.data.i64[0]; (void)timestamp; ALOGVV("Got preview frame for timestamp %" PRId64, timestamp); if (mState != RUNNING) return; - mFrameList.editItemAt(mFrameListHead) = frame; + mFrameList.editItemAt(mFrameListHead) = result.mMetadata; mFrameListHead = (mFrameListHead + 1) % kFrameListDepth; findMatchesLocked(); diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.h b/services/camera/libcameraservice/api1/client2/ZslProcessor.h index 6d3cb85..f4cf0c8 100644 --- a/services/camera/libcameraservice/api1/client2/ZslProcessor.h +++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.h @@ -24,6 +24,7 @@ #include <utils/Condition.h> #include <gui/BufferItemConsumer.h> #include <camera/CameraMetadata.h> +#include <camera/CaptureResult.h> #include "common/CameraDeviceBase.h" #include "api1/client2/ZslProcessorInterface.h" @@ -54,7 +55,7 @@ class ZslProcessor: // From mZslConsumer virtual void onFrameAvailable(); // From FrameProcessor - virtual void onFrameAvailable(int32_t requestId, const CameraMetadata &frame); + virtual void onResultAvailable(const CaptureResult &result); virtual void onBufferReleased(buffer_handle_t *handle); diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp index 3949b90..1dcb718 100644 --- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp +++ b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp @@ -63,18 +63,19 @@ ZslProcessor3::~ZslProcessor3() { deleteStream(); } -void ZslProcessor3::onFrameAvailable(int32_t /*requestId*/, - const CameraMetadata &frame) { +void ZslProcessor3::onResultAvailable(const CaptureResult &result) { + ATRACE_CALL(); + ALOGV("%s:", __FUNCTION__); Mutex::Autolock l(mInputMutex); camera_metadata_ro_entry_t entry; - entry = frame.find(ANDROID_SENSOR_TIMESTAMP); + entry = result.mMetadata.find(ANDROID_SENSOR_TIMESTAMP); nsecs_t timestamp = entry.data.i64[0]; (void)timestamp; ALOGVV("Got preview metadata for timestamp %" PRId64, timestamp); if (mState != RUNNING) return; - mFrameList.editItemAt(mFrameListHead) = frame; + mFrameList.editItemAt(mFrameListHead) = result.mMetadata; mFrameListHead = (mFrameListHead + 1) % kFrameListDepth; } diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.h b/services/camera/libcameraservice/api1/client2/ZslProcessor3.h index d2f8322..4c52a64 100644 --- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.h +++ b/services/camera/libcameraservice/api1/client2/ZslProcessor3.h @@ -50,8 +50,8 @@ class ZslProcessor3 : ZslProcessor3(sp<Camera2Client> client, wp<CaptureSequencer> sequencer); ~ZslProcessor3(); - // From FrameProcessor - virtual void onFrameAvailable(int32_t requestId, const CameraMetadata &frame); + // From FrameProcessor::FilteredListener + virtual void onResultAvailable(const CaptureResult &result); /** **************************************** diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp index 1c9a342..3d85e90 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp @@ -16,7 +16,7 @@ #define LOG_TAG "CameraDeviceClient" #define ATRACE_TAG ATRACE_TAG_CAMERA -// #define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #include <cutils/properties.h> #include <utils/Log.h> @@ -91,105 +91,18 @@ CameraDeviceClient::~CameraDeviceClient() { } status_t CameraDeviceClient::submitRequest(sp<CaptureRequest> request, - bool streaming) { - ATRACE_CALL(); - ALOGV("%s", __FUNCTION__); - - status_t res; - - if ( (res = checkPid(__FUNCTION__) ) != OK) return res; - - Mutex::Autolock icl(mBinderSerializationLock); - - if (!mDevice.get()) return DEAD_OBJECT; - - if (request == 0) { - ALOGE("%s: Camera %d: Sent null request. Rejecting request.", - __FUNCTION__, mCameraId); - return BAD_VALUE; - } - - CameraMetadata metadata(request->mMetadata); - - if (metadata.isEmpty()) { - ALOGE("%s: Camera %d: Sent empty metadata packet. Rejecting request.", - __FUNCTION__, mCameraId); - return BAD_VALUE; - } else if (request->mSurfaceList.size() == 0) { - ALOGE("%s: Camera %d: Requests must have at least one surface target. " - "Rejecting request.", __FUNCTION__, mCameraId); - return BAD_VALUE; - } - - if (!enforceRequestPermissions(metadata)) { - // Callee logs - return PERMISSION_DENIED; - } - - /** - * Write in the output stream IDs which we calculate from - * the capture request's list of surface targets - */ - Vector<int32_t> outputStreamIds; - outputStreamIds.setCapacity(request->mSurfaceList.size()); - for (size_t i = 0; i < request->mSurfaceList.size(); ++i) { - sp<Surface> surface = request->mSurfaceList[i]; - - if (surface == 0) continue; - - sp<IGraphicBufferProducer> gbp = surface->getIGraphicBufferProducer(); - int idx = mStreamMap.indexOfKey(gbp->asBinder()); - - // Trying to submit request with surface that wasn't created - if (idx == NAME_NOT_FOUND) { - ALOGE("%s: Camera %d: Tried to submit a request with a surface that" - " we have not called createStream on", - __FUNCTION__, mCameraId); - return BAD_VALUE; - } - - int streamId = mStreamMap.valueAt(idx); - outputStreamIds.push_back(streamId); - ALOGV("%s: Camera %d: Appending output stream %d to request", - __FUNCTION__, mCameraId, streamId); - } - - metadata.update(ANDROID_REQUEST_OUTPUT_STREAMS, &outputStreamIds[0], - outputStreamIds.size()); - - int32_t requestId = mRequestIdCounter++; - metadata.update(ANDROID_REQUEST_ID, &requestId, /*size*/1); - ALOGV("%s: Camera %d: Creating request with ID %d", - __FUNCTION__, mCameraId, requestId); - - if (streaming) { - res = mDevice->setStreamingRequest(metadata); - if (res != OK) { - ALOGE("%s: Camera %d: Got error %d after trying to set streaming " - "request", __FUNCTION__, mCameraId, res); - } else { - mStreamingRequestList.push_back(requestId); - } - } else { - res = mDevice->capture(metadata); - if (res != OK) { - ALOGE("%s: Camera %d: Got error %d after trying to set capture", - __FUNCTION__, mCameraId, res); - } - } - - ALOGV("%s: Camera %d: End of function", __FUNCTION__, mCameraId); - if (res == OK) { - return requestId; - } - - return res; + bool streaming, + /*out*/ + int64_t* lastFrameNumber) { + List<sp<CaptureRequest> > requestList; + requestList.push_back(request); + return submitRequestList(requestList, streaming, lastFrameNumber); } status_t CameraDeviceClient::submitRequestList(List<sp<CaptureRequest> > requests, - bool streaming) { + bool streaming, int64_t* lastFrameNumber) { ATRACE_CALL(); - ALOGV("%s-start of function", __FUNCTION__); + ALOGV("%s-start of function. Request list size %d", __FUNCTION__, requests.size()); status_t res; if ( (res = checkPid(__FUNCTION__) ) != OK) return res; @@ -238,9 +151,8 @@ status_t CameraDeviceClient::submitRequestList(List<sp<CaptureRequest> > request */ Vector<int32_t> outputStreamIds; outputStreamIds.setCapacity(request->mSurfaceList.size()); - for (Vector<sp<Surface> >::iterator surfaceIt = 0; - surfaceIt != request->mSurfaceList.end(); ++surfaceIt) { - sp<Surface> surface = *surfaceIt; + for (size_t i = 0; i < request->mSurfaceList.size(); ++i) { + sp<Surface> surface = request->mSurfaceList[i]; if (surface == 0) continue; sp<IGraphicBufferProducer> gbp = surface->getIGraphicBufferProducer(); @@ -273,7 +185,7 @@ status_t CameraDeviceClient::submitRequestList(List<sp<CaptureRequest> > request mRequestIdCounter++; if (streaming) { - res = mDevice->setStreamingRequestList(metadataRequestList); + res = mDevice->setStreamingRequestList(metadataRequestList, lastFrameNumber); if (res != OK) { ALOGE("%s: Camera %d: Got error %d after trying to set streaming " "request", __FUNCTION__, mCameraId, res); @@ -281,11 +193,12 @@ status_t CameraDeviceClient::submitRequestList(List<sp<CaptureRequest> > request mStreamingRequestList.push_back(requestId); } } else { - res = mDevice->captureList(metadataRequestList); + res = mDevice->captureList(metadataRequestList, lastFrameNumber); if (res != OK) { ALOGE("%s: Camera %d: Got error %d after trying to set capture", __FUNCTION__, mCameraId, res); } + ALOGV("%s: requestId = %d ", __FUNCTION__, requestId); } ALOGV("%s: Camera %d: End of function", __FUNCTION__, mCameraId); @@ -296,7 +209,7 @@ status_t CameraDeviceClient::submitRequestList(List<sp<CaptureRequest> > request return res; } -status_t CameraDeviceClient::cancelRequest(int requestId) { +status_t CameraDeviceClient::cancelRequest(int requestId, int64_t* lastFrameNumber) { ATRACE_CALL(); ALOGV("%s, requestId = %d", __FUNCTION__, requestId); @@ -322,7 +235,7 @@ status_t CameraDeviceClient::cancelRequest(int requestId) { return BAD_VALUE; } - res = mDevice->clearStreamingRequest(); + res = mDevice->clearStreamingRequest(lastFrameNumber); if (res == OK) { ALOGV("%s: Camera %d: Successfully cleared streaming request", @@ -369,8 +282,6 @@ status_t CameraDeviceClient::deleteStream(int streamId) { } else if (res == OK) { mStreamMap.removeItemsAt(index); - ALOGV("%s: Camera %d: Successfully deleted stream ID (%d)", - __FUNCTION__, mCameraId, streamId); } return res; @@ -575,7 +486,7 @@ status_t CameraDeviceClient::waitUntilIdle() return res; } -status_t CameraDeviceClient::flush() { +status_t CameraDeviceClient::flush(int64_t* lastFrameNumber) { ATRACE_CALL(); ALOGV("%s", __FUNCTION__); @@ -586,7 +497,7 @@ status_t CameraDeviceClient::flush() { if (!mDevice.get()) return DEAD_OBJECT; - return mDevice->flush(); + return mDevice->flush(lastFrameNumber); } status_t CameraDeviceClient::dump(int fd, const Vector<String16>& args) { @@ -603,13 +514,13 @@ status_t CameraDeviceClient::dump(int fd, const Vector<String16>& args) { return dumpDevice(fd, args); } - -void CameraDeviceClient::notifyError() { +void CameraDeviceClient::notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode, + const CaptureResultExtras& resultExtras) { // Thread safe. Don't bother locking. sp<ICameraDeviceCallbacks> remoteCb = getRemoteCallback(); if (remoteCb != 0) { - remoteCb->onDeviceError(ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE); + remoteCb->onDeviceError(errorCode, resultExtras); } } @@ -622,12 +533,12 @@ void CameraDeviceClient::notifyIdle() { } } -void CameraDeviceClient::notifyShutter(int requestId, +void CameraDeviceClient::notifyShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp) { // Thread safe. Don't bother locking. sp<ICameraDeviceCallbacks> remoteCb = getRemoteCallback(); if (remoteCb != 0) { - remoteCb->onCaptureStarted(requestId, timestamp); + remoteCb->onCaptureStarted(resultExtras, timestamp); } } @@ -662,16 +573,14 @@ void CameraDeviceClient::detachDevice() { } /** Device-related methods */ -void CameraDeviceClient::onFrameAvailable(int32_t requestId, - const CameraMetadata& frame) { +void CameraDeviceClient::onResultAvailable(const CaptureResult& result) { ATRACE_CALL(); ALOGV("%s", __FUNCTION__); // Thread-safe. No lock necessary. sp<ICameraDeviceCallbacks> remoteCb = mRemoteCallback; if (remoteCb != NULL) { - ALOGV("%s: frame = %p ", __FUNCTION__, &frame); - remoteCb->onResultReceived(requestId, frame); + remoteCb->onResultReceived(result.mMetadata, result.mResultExtras); } } diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h index e96e1ae..0b37784 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.h +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h @@ -64,11 +64,17 @@ public: // Note that the callee gets a copy of the metadata. virtual status_t submitRequest(sp<CaptureRequest> request, - bool streaming = false); + bool streaming = false, + /*out*/ + int64_t* lastFrameNumber = NULL); // List of requests are copied. virtual status_t submitRequestList(List<sp<CaptureRequest> > requests, - bool streaming = false); - virtual status_t cancelRequest(int requestId); + bool streaming = false, + /*out*/ + int64_t* lastFrameNumber = NULL); + virtual status_t cancelRequest(int requestId, + /*out*/ + int64_t* lastFrameNumber = NULL); // Returns -EBUSY if device is not idle virtual status_t deleteStream(int streamId); @@ -92,7 +98,8 @@ public: virtual status_t waitUntilIdle(); // Flush all active and pending requests as fast as possible - virtual status_t flush(); + virtual status_t flush(/*out*/ + int64_t* lastFrameNumber = NULL); /** * Interface used by CameraService @@ -117,16 +124,16 @@ public: */ virtual void notifyIdle(); - virtual void notifyError(); - virtual void notifyShutter(int requestId, nsecs_t timestamp); + virtual void notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode, + const CaptureResultExtras& resultExtras); + virtual void notifyShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp); /** * Interface used by independent components of CameraDeviceClient. */ protected: /** FilteredListener implementation **/ - virtual void onFrameAvailable(int32_t requestId, - const CameraMetadata& frame); + virtual void onResultAvailable(const CaptureResult& result); virtual void detachDevice(); // Calculate the ANativeWindow transform from android.sensor.orientation diff --git a/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp b/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp index 1a7a7a7..0f6d278 100644 --- a/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp +++ b/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp @@ -373,9 +373,7 @@ void ProCamera2Client::detachDevice() { Camera2ClientBase::detachDevice(); } -/** Device-related methods */ -void ProCamera2Client::onFrameAvailable(int32_t requestId, - const CameraMetadata& frame) { +void ProCamera2Client::onResultAvailable(const CaptureResult& result) { ATRACE_CALL(); ALOGV("%s", __FUNCTION__); @@ -383,13 +381,12 @@ void ProCamera2Client::onFrameAvailable(int32_t requestId, SharedCameraCallbacks::Lock l(mSharedCameraCallbacks); if (mRemoteCallback != NULL) { - CameraMetadata tmp(frame); + CameraMetadata tmp(result.mMetadata); camera_metadata_t* meta = tmp.release(); ALOGV("%s: meta = %p ", __FUNCTION__, meta); - mRemoteCallback->onResultReceived(requestId, meta); + mRemoteCallback->onResultReceived(result.mResultExtras.requestId, meta); tmp.acquire(meta); } - } bool ProCamera2Client::enforceRequestPermissions(CameraMetadata& metadata) { diff --git a/services/camera/libcameraservice/api_pro/ProCamera2Client.h b/services/camera/libcameraservice/api_pro/ProCamera2Client.h index 8a0f547..9d83122 100644 --- a/services/camera/libcameraservice/api_pro/ProCamera2Client.h +++ b/services/camera/libcameraservice/api_pro/ProCamera2Client.h @@ -21,6 +21,7 @@ #include "common/FrameProcessorBase.h" #include "common/Camera2ClientBase.h" #include "device2/Camera2Device.h" +#include "camera/CaptureResult.h" namespace android { @@ -97,8 +98,8 @@ public: protected: /** FilteredListener implementation **/ - virtual void onFrameAvailable(int32_t requestId, - const CameraMetadata& frame); + virtual void onResultAvailable(const CaptureResult& result); + virtual void detachDevice(); private: diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp index 6a88c87..19efd30 100644 --- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp +++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp @@ -221,10 +221,11 @@ status_t Camera2ClientBase<TClientBase>::connect( /** Device-related methods */ template <typename TClientBase> -void Camera2ClientBase<TClientBase>::notifyError(int errorCode, int arg1, - int arg2) { - ALOGE("Error condition %d reported by HAL, arguments %d, %d", errorCode, - arg1, arg2); +void Camera2ClientBase<TClientBase>::notifyError( + ICameraDeviceCallbacks::CameraErrorCode errorCode, + const CaptureResultExtras& resultExtras) { + ALOGE("Error condition %d reported by HAL, requestId %" PRId32, errorCode, + resultExtras.requestId); } template <typename TClientBase> @@ -233,13 +234,13 @@ void Camera2ClientBase<TClientBase>::notifyIdle() { } template <typename TClientBase> -void Camera2ClientBase<TClientBase>::notifyShutter(int requestId, +void Camera2ClientBase<TClientBase>::notifyShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp) { - (void)requestId; + (void)resultExtras; (void)timestamp; - ALOGV("%s: Shutter notification for request id %d at time %" PRId64, - __FUNCTION__, requestId, timestamp); + ALOGV("%s: Shutter notification for request id %" PRId32 " at time %" PRId64, + __FUNCTION__, resultExtras.requestId, timestamp); } template <typename TClientBase> diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h index 61e44f0..9feca93 100644 --- a/services/camera/libcameraservice/common/Camera2ClientBase.h +++ b/services/camera/libcameraservice/common/Camera2ClientBase.h @@ -18,6 +18,7 @@ #define ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_BASE_H #include "common/CameraDeviceBase.h" +#include "camera/CaptureResult.h" namespace android { @@ -61,9 +62,11 @@ public: * CameraDeviceBase::NotificationListener implementation */ - virtual void notifyError(int errorCode, int arg1, int arg2); + virtual void notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode, + const CaptureResultExtras& resultExtras); virtual void notifyIdle(); - virtual void notifyShutter(int requestId, nsecs_t timestamp); + virtual void notifyShutter(const CaptureResultExtras& resultExtras, + nsecs_t timestamp); virtual void notifyAutoFocus(uint8_t newState, int triggerId); virtual void notifyAutoExposure(uint8_t newState, int triggerId); virtual void notifyAutoWhitebalance(uint8_t newState, diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h index a4ae179..7597b10 100644 --- a/services/camera/libcameraservice/common/CameraDeviceBase.h +++ b/services/camera/libcameraservice/common/CameraDeviceBase.h @@ -24,8 +24,10 @@ #include <utils/Timers.h> #include <utils/List.h> +#include <camera/camera2/ICameraDeviceCallbacks.h> #include "hardware/camera2.h" #include "camera/CameraMetadata.h" +#include "camera/CaptureResult.h" namespace android { @@ -45,7 +47,7 @@ class CameraDeviceBase : public virtual RefBase { virtual status_t initialize(camera_module_t *module) = 0; virtual status_t disconnect() = 0; - virtual status_t dump(int fd, const Vector<String16>& args) = 0; + virtual status_t dump(int fd, const Vector<String16> &args) = 0; /** * The device's static characteristics metadata buffer @@ -55,29 +57,37 @@ class CameraDeviceBase : public virtual RefBase { /** * Submit request for capture. The CameraDevice takes ownership of the * passed-in buffer. + * Output lastFrameNumber is the expected frame number of this request. */ - virtual status_t capture(CameraMetadata &request) = 0; + virtual status_t capture(CameraMetadata &request, int64_t *lastFrameNumber = NULL) = 0; /** * Submit a list of requests. + * Output lastFrameNumber is the expected last frame number of the list of requests. */ - virtual status_t captureList(const List<const CameraMetadata> &requests) = 0; + virtual status_t captureList(const List<const CameraMetadata> &requests, + int64_t *lastFrameNumber = NULL) = 0; /** * Submit request for streaming. The CameraDevice makes a copy of the * passed-in buffer and the caller retains ownership. + * Output lastFrameNumber is the last frame number of the previous streaming request. */ - virtual status_t setStreamingRequest(const CameraMetadata &request) = 0; + virtual status_t setStreamingRequest(const CameraMetadata &request, + int64_t *lastFrameNumber = NULL) = 0; /** * Submit a list of requests for streaming. + * Output lastFrameNumber is the last frame number of the previous streaming request. */ - virtual status_t setStreamingRequestList(const List<const CameraMetadata> &requests) = 0; + virtual status_t setStreamingRequestList(const List<const CameraMetadata> &requests, + int64_t *lastFrameNumber = NULL) = 0; /** * Clear the streaming request slot. + * Output lastFrameNumber is the last frame number of the previous streaming request. */ - virtual status_t clearStreamingRequest() = 0; + virtual status_t clearStreamingRequest(int64_t *lastFrameNumber = NULL) = 0; /** * Wait until a request with the given ID has been dequeued by the @@ -153,11 +163,12 @@ class CameraDeviceBase : public virtual RefBase { // API1 and API2. // Required for API 1 and 2 - virtual void notifyError(int errorCode, int arg1, int arg2) = 0; + virtual void notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode, + const CaptureResultExtras &resultExtras) = 0; // Required only for API2 virtual void notifyIdle() = 0; - virtual void notifyShutter(int requestId, + virtual void notifyShutter(const CaptureResultExtras &resultExtras, nsecs_t timestamp) = 0; // Required only for API1 @@ -190,11 +201,12 @@ class CameraDeviceBase : public virtual RefBase { virtual status_t waitForNextFrame(nsecs_t timeout) = 0; /** - * Get next metadata frame from the frame queue. Returns NULL if the queue - * is empty; caller takes ownership of the metadata buffer. - * May be called concurrently to most methods, except for waitForNextFrame + * Get next capture result frame from the result queue. Returns NOT_ENOUGH_DATA + * if the queue is empty; caller takes ownership of the metadata buffer inside + * the capture result object's metadata field. + * May be called concurrently to most methods, except for waitForNextFrame. */ - virtual status_t getNextFrame(CameraMetadata *frame) = 0; + virtual status_t getNextResult(CaptureResult *frame) = 0; /** * Trigger auto-focus. The latest ID used in a trigger autofocus or cancel @@ -235,8 +247,9 @@ class CameraDeviceBase : public virtual RefBase { /** * Flush all pending and in-flight requests. Blocks until flush is * complete. + * Output lastFrameNumber is the last frame number of the previous streaming request. */ - virtual status_t flush() = 0; + virtual status_t flush(int64_t *lastFrameNumber = NULL) = 0; }; diff --git a/services/camera/libcameraservice/common/FrameProcessorBase.cpp b/services/camera/libcameraservice/common/FrameProcessorBase.cpp index 4d31667..f6a971a 100644 --- a/services/camera/libcameraservice/common/FrameProcessorBase.cpp +++ b/services/camera/libcameraservice/common/FrameProcessorBase.cpp @@ -99,15 +99,17 @@ bool FrameProcessorBase::threadLoop() { void FrameProcessorBase::processNewFrames(const sp<CameraDeviceBase> &device) { status_t res; ATRACE_CALL(); - CameraMetadata frame; + CaptureResult result; ALOGV("%s: Camera %d: Process new frames", __FUNCTION__, device->getId()); - while ( (res = device->getNextFrame(&frame)) == OK) { + while ( (res = device->getNextResult(&result)) == OK) { + // TODO: instead of getting frame number from metadata, we should read + // this from result.mResultExtras when CameraDeviceBase interface is fixed. camera_metadata_entry_t entry; - entry = frame.find(ANDROID_REQUEST_FRAME_COUNT); + entry = result.mMetadata.find(ANDROID_REQUEST_FRAME_COUNT); if (entry.count == 0) { ALOGE("%s: Camera %d: Error reading frame number", __FUNCTION__, device->getId()); @@ -115,13 +117,13 @@ void FrameProcessorBase::processNewFrames(const sp<CameraDeviceBase> &device) { } ATRACE_INT("cam2_frame", entry.data.i32[0]); - if (!processSingleFrame(frame, device)) { + if (!processSingleFrame(result, device)) { break; } - if (!frame.isEmpty()) { + if (!result.mMetadata.isEmpty()) { Mutex::Autolock al(mLastFrameMutex); - mLastFrame.acquire(frame); + mLastFrame.acquire(result.mMetadata); } } if (res != NOT_ENOUGH_DATA) { @@ -133,21 +135,22 @@ void FrameProcessorBase::processNewFrames(const sp<CameraDeviceBase> &device) { return; } -bool FrameProcessorBase::processSingleFrame(CameraMetadata &frame, - const sp<CameraDeviceBase> &device) { +bool FrameProcessorBase::processSingleFrame(CaptureResult &result, + const sp<CameraDeviceBase> &device) { ALOGV("%s: Camera %d: Process single frame (is empty? %d)", - __FUNCTION__, device->getId(), frame.isEmpty()); - return processListeners(frame, device) == OK; + __FUNCTION__, device->getId(), result.mMetadata.isEmpty()); + return processListeners(result, device) == OK; } -status_t FrameProcessorBase::processListeners(const CameraMetadata &frame, +status_t FrameProcessorBase::processListeners(const CaptureResult &result, const sp<CameraDeviceBase> &device) { ATRACE_CALL(); + camera_metadata_ro_entry_t entry; // Quirks: Don't deliver partial results to listeners that don't want them bool quirkIsPartial = false; - entry = frame.find(ANDROID_QUIRKS_PARTIAL_RESULT); + entry = result.mMetadata.find(ANDROID_QUIRKS_PARTIAL_RESULT); if (entry.count != 0 && entry.data.u8[0] == ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL) { ALOGV("%s: Camera %d: Not forwarding partial result to listeners", @@ -155,10 +158,13 @@ status_t FrameProcessorBase::processListeners(const CameraMetadata &frame, quirkIsPartial = true; } - entry = frame.find(ANDROID_REQUEST_ID); + // TODO: instead of getting requestID from CameraMetadata, we should get it + // from CaptureResultExtras. This will require changing Camera2Device. + // Currently Camera2Device uses MetadataQueue to store results, which does not + // include CaptureResultExtras. + entry = result.mMetadata.find(ANDROID_REQUEST_ID); if (entry.count == 0) { - ALOGE("%s: Camera %d: Error reading frame id", - __FUNCTION__, device->getId()); + ALOGE("%s: Camera %d: Error reading frame id", __FUNCTION__, device->getId()); return BAD_VALUE; } int32_t requestId = entry.data.i32[0]; @@ -169,9 +175,8 @@ status_t FrameProcessorBase::processListeners(const CameraMetadata &frame, List<RangeListener>::iterator item = mRangeListeners.begin(); while (item != mRangeListeners.end()) { - if (requestId >= item->minId && - requestId < item->maxId && - (!quirkIsPartial || item->quirkSendPartials) ) { + if (requestId >= item->minId && requestId < item->maxId && + (!quirkIsPartial || item->quirkSendPartials)) { sp<FilteredListener> listener = item->listener.promote(); if (listener == 0) { item = mRangeListeners.erase(item); @@ -183,10 +188,12 @@ status_t FrameProcessorBase::processListeners(const CameraMetadata &frame, item++; } } - ALOGV("Got %zu range listeners out of %zu", listeners.size(), mRangeListeners.size()); + ALOGV("%s: Camera %d: Got %zu range listeners out of %zu", __FUNCTION__, + device->getId(), listeners.size(), mRangeListeners.size()); + List<sp<FilteredListener> >::iterator item = listeners.begin(); for (; item != listeners.end(); item++) { - (*item)->onFrameAvailable(requestId, frame); + (*item)->onResultAvailable(result); } return OK; } diff --git a/services/camera/libcameraservice/common/FrameProcessorBase.h b/services/camera/libcameraservice/common/FrameProcessorBase.h index 89b608a..15a014e 100644 --- a/services/camera/libcameraservice/common/FrameProcessorBase.h +++ b/services/camera/libcameraservice/common/FrameProcessorBase.h @@ -23,6 +23,7 @@ #include <utils/KeyedVector.h> #include <utils/List.h> #include <camera/CameraMetadata.h> +#include <camera/CaptureResult.h> namespace android { @@ -39,8 +40,7 @@ class FrameProcessorBase: public Thread { virtual ~FrameProcessorBase(); struct FilteredListener: virtual public RefBase { - virtual void onFrameAvailable(int32_t requestId, - const CameraMetadata &frame) = 0; + virtual void onResultAvailable(const CaptureResult &result) = 0; }; // Register a listener for a range of IDs [minId, maxId). Multiple listeners @@ -72,10 +72,10 @@ class FrameProcessorBase: public Thread { void processNewFrames(const sp<CameraDeviceBase> &device); - virtual bool processSingleFrame(CameraMetadata &frame, + virtual bool processSingleFrame(CaptureResult &result, const sp<CameraDeviceBase> &device); - status_t processListeners(const CameraMetadata &frame, + status_t processListeners(const CaptureResult &result, const sp<CameraDeviceBase> &device); CameraMetadata mLastFrame; diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp index 0cc3a04..c33c166 100644 --- a/services/camera/libcameraservice/device2/Camera2Device.cpp +++ b/services/camera/libcameraservice/device2/Camera2Device.cpp @@ -199,7 +199,7 @@ const CameraMetadata& Camera2Device::info() const { return mDeviceInfo; } -status_t Camera2Device::capture(CameraMetadata &request) { +status_t Camera2Device::capture(CameraMetadata &request, int64_t* /*lastFrameNumber*/) { ATRACE_CALL(); ALOGV("%s: E", __FUNCTION__); @@ -207,27 +207,29 @@ status_t Camera2Device::capture(CameraMetadata &request) { return OK; } -status_t Camera2Device::captureList(const List<const CameraMetadata> &requests) { +status_t Camera2Device::captureList(const List<const CameraMetadata> &requests, + int64_t* /*lastFrameNumber*/) { ATRACE_CALL(); ALOGE("%s: Camera2Device burst capture not implemented", __FUNCTION__); return INVALID_OPERATION; } - -status_t Camera2Device::setStreamingRequest(const CameraMetadata &request) { +status_t Camera2Device::setStreamingRequest(const CameraMetadata &request, + int64_t* /*lastFrameNumber*/) { ATRACE_CALL(); ALOGV("%s: E", __FUNCTION__); CameraMetadata streamRequest(request); return mRequestQueue.setStreamSlot(streamRequest.release()); } -status_t Camera2Device::setStreamingRequestList(const List<const CameraMetadata> &requests) { +status_t Camera2Device::setStreamingRequestList(const List<const CameraMetadata> &requests, + int64_t* /*lastFrameNumber*/) { ATRACE_CALL(); ALOGE("%s, Camera2Device streaming burst not implemented", __FUNCTION__); return INVALID_OPERATION; } -status_t Camera2Device::clearStreamingRequest() { +status_t Camera2Device::clearStreamingRequest(int64_t* /*lastFrameNumber*/) { ATRACE_CALL(); return mRequestQueue.setStreamSlot(NULL); } @@ -460,7 +462,13 @@ void Camera2Device::notificationCallback(int32_t msg_type, if (listener != NULL) { switch (msg_type) { case CAMERA2_MSG_ERROR: - listener->notifyError(ext1, ext2, ext3); + // TODO: This needs to be fixed. ext2 and ext3 need to be considered. + listener->notifyError( + ((ext1 == CAMERA2_MSG_ERROR_DEVICE) + || (ext1 == CAMERA2_MSG_ERROR_HARDWARE)) ? + ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE : + ICameraDeviceCallbacks::ERROR_CAMERA_SERVICE, + CaptureResultExtras()); break; case CAMERA2_MSG_SHUTTER: { // TODO: Only needed for camera2 API, which is unsupported @@ -489,16 +497,22 @@ status_t Camera2Device::waitForNextFrame(nsecs_t timeout) { return mFrameQueue.waitForBuffer(timeout); } -status_t Camera2Device::getNextFrame(CameraMetadata *frame) { +status_t Camera2Device::getNextResult(CaptureResult *result) { ATRACE_CALL(); + ALOGV("%s: get CaptureResult", __FUNCTION__); + if (result == NULL) { + ALOGE("%s: result pointer is NULL", __FUNCTION__); + return BAD_VALUE; + } status_t res; camera_metadata_t *rawFrame; res = mFrameQueue.dequeue(&rawFrame); - if (rawFrame == NULL) { + if (rawFrame == NULL) { return NOT_ENOUGH_DATA; } else if (res == OK) { - frame->acquire(rawFrame); + result->mMetadata.acquire(rawFrame); } + return res; } @@ -568,7 +582,7 @@ status_t Camera2Device::pushReprocessBuffer(int reprocessStreamId, return res; } -status_t Camera2Device::flush() { +status_t Camera2Device::flush(int64_t* /*lastFrameNumber*/) { ATRACE_CALL(); mRequestQueue.clear(); diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h index 61bfd1a..22a13ac 100644 --- a/services/camera/libcameraservice/device2/Camera2Device.h +++ b/services/camera/libcameraservice/device2/Camera2Device.h @@ -47,11 +47,14 @@ class Camera2Device: public CameraDeviceBase { virtual status_t disconnect(); virtual status_t dump(int fd, const Vector<String16>& args); virtual const CameraMetadata& info() const; - virtual status_t capture(CameraMetadata &request); - virtual status_t captureList(const List<const CameraMetadata> &requests); - virtual status_t setStreamingRequest(const CameraMetadata &request); - virtual status_t setStreamingRequestList(const List<const CameraMetadata> &requests); - virtual status_t clearStreamingRequest(); + virtual status_t capture(CameraMetadata &request, int64_t *lastFrameNumber = NULL); + virtual status_t captureList(const List<const CameraMetadata> &requests, + int64_t *lastFrameNumber = NULL); + virtual status_t setStreamingRequest(const CameraMetadata &request, + int64_t *lastFrameNumber = NULL); + virtual status_t setStreamingRequestList(const List<const CameraMetadata> &requests, + int64_t *lastFrameNumber = NULL); + virtual status_t clearStreamingRequest(int64_t *lastFrameNumber = NULL); virtual status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout); virtual status_t createStream(sp<ANativeWindow> consumer, uint32_t width, uint32_t height, int format, size_t size, @@ -67,14 +70,14 @@ class Camera2Device: public CameraDeviceBase { virtual status_t setNotifyCallback(NotificationListener *listener); virtual bool willNotify3A(); virtual status_t waitForNextFrame(nsecs_t timeout); - virtual status_t getNextFrame(CameraMetadata *frame); + virtual status_t getNextResult(CaptureResult *frame); virtual status_t triggerAutofocus(uint32_t id); virtual status_t triggerCancelAutofocus(uint32_t id); virtual status_t triggerPrecaptureMetering(uint32_t id); virtual status_t pushReprocessBuffer(int reprocessStreamId, buffer_handle_t *buffer, wp<BufferReleasedListener> listener); // Flush implemented as just a wait - virtual status_t flush(); + virtual status_t flush(int64_t *lastFrameNumber = NULL); private: const int mId; camera2_device_t *mHal2Device; diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index f586e75..a64917d 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -399,6 +399,7 @@ status_t Camera3Device::convertMetadataListToRequestListLocked( return BAD_VALUE; } + int32_t burstId = 0; for (List<const CameraMetadata>::const_iterator it = metadataList.begin(); it != metadataList.end(); ++it) { sp<CaptureRequest> newRequest = setUpRequestLocked(*it); @@ -406,12 +407,29 @@ status_t Camera3Device::convertMetadataListToRequestListLocked( CLOGE("Can't create capture request"); return BAD_VALUE; } + + // Setup burst Id and request Id + newRequest->mResultExtras.burstId = burstId++; + if (it->exists(ANDROID_REQUEST_ID)) { + if (it->find(ANDROID_REQUEST_ID).count == 0) { + CLOGE("RequestID entry exists; but must not be empty in metadata"); + return BAD_VALUE; + } + newRequest->mResultExtras.requestId = it->find(ANDROID_REQUEST_ID).data.i32[0]; + } else { + CLOGE("RequestID does not exist in metadata"); + return BAD_VALUE; + } + requestList->push_back(newRequest); + if (newRequest->mResultExtras.requestId > 0) { + ALOGV("%s: requestId = %" PRId32, __FUNCTION__, newRequest->mResultExtras.requestId); + } } return OK; } -status_t Camera3Device::capture(CameraMetadata &request) { +status_t Camera3Device::capture(CameraMetadata &request, int64_t* /*lastFrameNumber*/) { ATRACE_CALL(); status_t res; Mutex::Autolock il(mInterfaceLock); @@ -459,7 +477,7 @@ status_t Camera3Device::capture(CameraMetadata &request) { } status_t Camera3Device::submitRequestsHelper( - const List<const CameraMetadata> &requests, bool repeating) { + const List<const CameraMetadata> &requests, bool repeating, int64_t *lastFrameNumber) { ATRACE_CALL(); Mutex::Autolock il(mInterfaceLock); Mutex::Autolock l(mLock); @@ -479,9 +497,15 @@ status_t Camera3Device::submitRequestsHelper( } if (repeating) { + if (lastFrameNumber != NULL) { + *lastFrameNumber = mRequestThread->getLastFrameNumber(); + } res = mRequestThread->setRepeatingRequests(requestList); } else { res = mRequestThread->queueRequestList(requestList); + if (lastFrameNumber != NULL) { + *lastFrameNumber = mRequestThread->getLastFrameNumber(); + } } if (res == OK) { @@ -499,13 +523,15 @@ status_t Camera3Device::submitRequestsHelper( return res; } -status_t Camera3Device::captureList(const List<const CameraMetadata> &requests) { +status_t Camera3Device::captureList(const List<const CameraMetadata> &requests, + int64_t *lastFrameNumber) { ATRACE_CALL(); - return submitRequestsHelper(requests, /*repeating*/false); + return submitRequestsHelper(requests, /*repeating*/false, lastFrameNumber); } -status_t Camera3Device::setStreamingRequest(const CameraMetadata &request) { +status_t Camera3Device::setStreamingRequest(const CameraMetadata &request, + int64_t* /*lastFrameNumber*/) { ATRACE_CALL(); status_t res; Mutex::Autolock il(mInterfaceLock); @@ -550,10 +576,11 @@ status_t Camera3Device::setStreamingRequest(const CameraMetadata &request) { return res; } -status_t Camera3Device::setStreamingRequestList(const List<const CameraMetadata> &requests) { +status_t Camera3Device::setStreamingRequestList(const List<const CameraMetadata> &requests, + int64_t *lastFrameNumber) { ATRACE_CALL(); - return submitRequestsHelper(requests, /*repeating*/true); + return submitRequestsHelper(requests, /*repeating*/true, lastFrameNumber); } sp<Camera3Device::CaptureRequest> Camera3Device::setUpRequestLocked( @@ -576,7 +603,7 @@ sp<Camera3Device::CaptureRequest> Camera3Device::setUpRequestLocked( return newRequest; } -status_t Camera3Device::clearStreamingRequest() { +status_t Camera3Device::clearStreamingRequest(int64_t *lastFrameNumber) { ATRACE_CALL(); Mutex::Autolock il(mInterfaceLock); Mutex::Autolock l(mLock); @@ -598,6 +625,13 @@ status_t Camera3Device::clearStreamingRequest() { return INVALID_OPERATION; } ALOGV("Camera %d: Clearing repeating request", mId); + + if (lastFrameNumber != NULL) { + *lastFrameNumber = mRequestThread->getLastFrameNumber(); + ALOGV("%s: lastFrameNumber address %p, value %" PRId64, __FUNCTION__, lastFrameNumber, + *lastFrameNumber); + } + return mRequestThread->clearRepeatingRequests(); } @@ -1115,7 +1149,7 @@ status_t Camera3Device::waitForNextFrame(nsecs_t timeout) { return OK; } -status_t Camera3Device::getNextFrame(CameraMetadata *frame) { +status_t Camera3Device::getNextResult(CaptureResult *frame) { ATRACE_CALL(); Mutex::Autolock l(mOutputLock); @@ -1123,8 +1157,14 @@ status_t Camera3Device::getNextFrame(CameraMetadata *frame) { return NOT_ENOUGH_DATA; } - CameraMetadata &result = *(mResultQueue.begin()); - frame->acquire(result); + if (frame == NULL) { + ALOGE("%s: argument cannot be NULL", __FUNCTION__); + return BAD_VALUE; + } + + CaptureResult &result = *(mResultQueue.begin()); + frame->mResultExtras = result.mResultExtras; + frame->mMetadata.acquire(result.mMetadata); mResultQueue.erase(mResultQueue.begin()); return OK; @@ -1202,12 +1242,16 @@ status_t Camera3Device::pushReprocessBuffer(int reprocessStreamId, return INVALID_OPERATION; } -status_t Camera3Device::flush() { +status_t Camera3Device::flush(int64_t *frameNumber) { ATRACE_CALL(); ALOGV("%s: Camera %d: Flushing all requests", __FUNCTION__, mId); Mutex::Autolock il(mInterfaceLock); Mutex::Autolock l(mLock); + if (frameNumber != NULL) { + *frameNumber = mRequestThread->getLastFrameNumber(); + } + mRequestThread->clear(); status_t res; if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) { @@ -1484,13 +1528,13 @@ void Camera3Device::setErrorStateLockedV(const char *fmt, va_list args) { * In-flight request management */ -status_t Camera3Device::registerInFlight(int32_t frameNumber, - int32_t requestId, int32_t numBuffers) { +status_t Camera3Device::registerInFlight(uint32_t frameNumber, + int32_t numBuffers, CaptureResultExtras resultExtras) { ATRACE_CALL(); Mutex::Autolock l(mInFlightLock); ssize_t res; - res = mInFlightMap.add(frameNumber, InFlightRequest(requestId, numBuffers)); + res = mInFlightMap.add(frameNumber, InFlightRequest(numBuffers, resultExtras)); if (res < 0) return res; return OK; @@ -1502,8 +1546,8 @@ status_t Camera3Device::registerInFlight(int32_t frameNumber, * to the output frame queue */ bool Camera3Device::processPartial3AQuirk( - int32_t frameNumber, int32_t requestId, - const CameraMetadata& partial) { + uint32_t frameNumber, + const CameraMetadata& partial, const CaptureResultExtras& resultExtras) { // Check if all 3A states are present // The full list of fields is @@ -1567,58 +1611,63 @@ bool Camera3Device::processPartial3AQuirk( Mutex::Autolock l(mOutputLock); - CameraMetadata& min3AResult = - *mResultQueue.insert( - mResultQueue.end(), - CameraMetadata(kMinimal3AResultEntries, /*dataCapacity*/ 0)); - - if (!insert3AResult(min3AResult, ANDROID_REQUEST_FRAME_COUNT, - &frameNumber, frameNumber)) { + CaptureResult captureResult; + captureResult.mResultExtras = resultExtras; + captureResult.mMetadata = CameraMetadata(kMinimal3AResultEntries, /*dataCapacity*/ 0); + // TODO: change this to sp<CaptureResult>. This will need other changes, including, + // but not limited to CameraDeviceBase::getNextResult + CaptureResult& min3AResult = + *mResultQueue.insert(mResultQueue.end(), captureResult); + + if (!insert3AResult(min3AResult.mMetadata, ANDROID_REQUEST_FRAME_COUNT, + // TODO: This is problematic casting. Need to fix CameraMetadata. + reinterpret_cast<int32_t*>(&frameNumber), frameNumber)) { return false; } - if (!insert3AResult(min3AResult, ANDROID_REQUEST_ID, + int32_t requestId = resultExtras.requestId; + if (!insert3AResult(min3AResult.mMetadata, ANDROID_REQUEST_ID, &requestId, frameNumber)) { return false; } static const uint8_t partialResult = ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL; - if (!insert3AResult(min3AResult, ANDROID_QUIRKS_PARTIAL_RESULT, + if (!insert3AResult(min3AResult.mMetadata, ANDROID_QUIRKS_PARTIAL_RESULT, &partialResult, frameNumber)) { return false; } - if (!insert3AResult(min3AResult, ANDROID_CONTROL_AF_MODE, + if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AF_MODE, &afMode, frameNumber)) { return false; } - if (!insert3AResult(min3AResult, ANDROID_CONTROL_AWB_MODE, + if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AWB_MODE, &awbMode, frameNumber)) { return false; } - if (!insert3AResult(min3AResult, ANDROID_CONTROL_AE_STATE, + if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AE_STATE, &aeState, frameNumber)) { return false; } - if (!insert3AResult(min3AResult, ANDROID_CONTROL_AF_STATE, + if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AF_STATE, &afState, frameNumber)) { return false; } - if (!insert3AResult(min3AResult, ANDROID_CONTROL_AWB_STATE, + if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AWB_STATE, &awbState, frameNumber)) { return false; } - if (!insert3AResult(min3AResult, ANDROID_CONTROL_AF_TRIGGER_ID, + if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AF_TRIGGER_ID, &afTriggerId, frameNumber)) { return false; } - if (!insert3AResult(min3AResult, ANDROID_CONTROL_AE_PRECAPTURE_ID, + if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AE_PRECAPTURE_ID, &aeTriggerId, frameNumber)) { return false; } @@ -1630,7 +1679,7 @@ bool Camera3Device::processPartial3AQuirk( template<typename T> bool Camera3Device::get3AResult(const CameraMetadata& result, int32_t tag, - T* value, int32_t frameNumber) { + T* value, uint32_t frameNumber) { (void) frameNumber; camera_metadata_ro_entry_t entry; @@ -1655,7 +1704,7 @@ bool Camera3Device::get3AResult(const CameraMetadata& result, int32_t tag, template<typename T> bool Camera3Device::insert3AResult(CameraMetadata& result, int32_t tag, - const T* value, int32_t frameNumber) { + const T* value, uint32_t frameNumber) { if (result.update(tag, value, 1) != NO_ERROR) { mResultQueue.erase(--mResultQueue.end(), mResultQueue.end()); SET_ERR("Frame %d: Failed to set %s in partial metadata", @@ -1682,11 +1731,12 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { } bool partialResultQuirk = false; CameraMetadata collectedQuirkResult; + CaptureResultExtras resultExtras; - // Get capture timestamp from list of in-flight requests, where it was added - // by the shutter notification for this frame. Then update the in-flight - // status and remove the in-flight entry if all result data has been - // received. + // Get capture timestamp and resultExtras from list of in-flight requests, + // where it was added by the shutter notification for this frame. + // Then update the in-flight status and remove the in-flight entry if + // all result data has been received. nsecs_t timestamp = 0; { Mutex::Autolock l(mInFlightLock); @@ -1697,6 +1747,10 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { return; } InFlightRequest &request = mInFlightMap.editValueAt(idx); + ALOGVV("%s: got InFlightRequest requestId = %" PRId32 ", frameNumber = %" PRId64 + ", burstId = %" PRId32, + __FUNCTION__, request.resultExtras.requestId, request.resultExtras.frameNumber, + request.resultExtras.burstId); // Check if this result carries only partial metadata if (mUsePartialResultQuirk && result->result != NULL) { @@ -1718,13 +1772,17 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { if (!request.partialResultQuirk.haveSent3A) { request.partialResultQuirk.haveSent3A = processPartial3AQuirk(frameNumber, - request.requestId, - request.partialResultQuirk.collectedResult); + request.partialResultQuirk.collectedResult, + request.resultExtras); } } } timestamp = request.captureTimestamp; + resultExtras = request.resultExtras; + ALOGVV("%s: after checking partial burstId = %d, frameNumber %lld", __FUNCTION__, + request.resultExtras.burstId, request.resultExtras.frameNumber); + /** * One of the following must happen before it's legal to call process_capture_result, * unless partial metadata is being provided: @@ -1791,11 +1849,12 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { } mNextResultFrameNumber++; - CameraMetadata captureResult; - captureResult = result->result; + CaptureResult captureResult; + captureResult.mResultExtras = resultExtras; + captureResult.mMetadata = result->result; - if (captureResult.update(ANDROID_REQUEST_FRAME_COUNT, - (int32_t*)&frameNumber, 1) != OK) { + if (captureResult.mMetadata.update(ANDROID_REQUEST_FRAME_COUNT, + (int32_t*)&frameNumber, 1) != OK) { SET_ERR("Failed to set frame# in metadata (%d)", frameNumber); gotResult = false; @@ -1806,15 +1865,15 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { // Append any previous partials to form a complete result if (mUsePartialResultQuirk && !collectedQuirkResult.isEmpty()) { - captureResult.append(collectedQuirkResult); + captureResult.mMetadata.append(collectedQuirkResult); } - captureResult.sort(); + captureResult.mMetadata.sort(); // Check that there's a timestamp in the result metadata camera_metadata_entry entry = - captureResult.find(ANDROID_SENSOR_TIMESTAMP); + captureResult.mMetadata.find(ANDROID_SENSOR_TIMESTAMP); if (entry.count == 0) { SET_ERR("No timestamp provided by HAL for frame %d!", frameNumber); @@ -1828,9 +1887,13 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { if (gotResult) { // Valid result, insert into queue - CameraMetadata& queuedResult = - *mResultQueue.insert(mResultQueue.end(), CameraMetadata()); - queuedResult.swap(captureResult); + List<CaptureResult>::iterator queuedResult = + mResultQueue.insert(mResultQueue.end(), CaptureResult(captureResult)); + ALOGVV("%s: result requestId = %" PRId32 ", frameNumber = %" PRId64 + ", burstId = %" PRId32, __FUNCTION__, + queuedResult->mResultExtras.requestId, + queuedResult->mResultExtras.frameNumber, + queuedResult->mResultExtras.burstId); } } // scope for mOutputLock @@ -1856,8 +1919,6 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) { } - - void Camera3Device::notify(const camera3_notify_msg *msg) { ATRACE_CALL(); NotificationListener *listener; @@ -1884,18 +1945,32 @@ void Camera3Device::notify(const camera3_notify_msg *msg) { mId, __FUNCTION__, msg->message.error.frame_number, streamId, msg->message.error.error_code); + CaptureResultExtras resultExtras; // Set request error status for the request in the in-flight tracking { Mutex::Autolock l(mInFlightLock); ssize_t idx = mInFlightMap.indexOfKey(msg->message.error.frame_number); if (idx >= 0) { - mInFlightMap.editValueAt(idx).requestStatus = msg->message.error.error_code; + InFlightRequest &r = mInFlightMap.editValueAt(idx); + r.requestStatus = msg->message.error.error_code; + resultExtras = r.resultExtras; + } else { + resultExtras.frameNumber = msg->message.error.frame_number; + ALOGE("Camera %d: %s: cannot find in-flight request on frame %" PRId64 + " error", mId, __FUNCTION__, resultExtras.frameNumber); } } if (listener != NULL) { - listener->notifyError(msg->message.error.error_code, - msg->message.error.frame_number, streamId); + if (msg->message.error.error_code == CAMERA3_MSG_ERROR_DEVICE) { + listener->notifyError(ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE, + resultExtras); + } else { + listener->notifyError(ICameraDeviceCallbacks::ERROR_CAMERA_SERVICE, + resultExtras); + } + } else { + ALOGE("Camera %d: %s: no listener available", mId, __FUNCTION__); } break; } @@ -1915,7 +1990,7 @@ void Camera3Device::notify(const camera3_notify_msg *msg) { mNextShutterFrameNumber++; } - int32_t requestId = -1; + CaptureResultExtras resultExtras; // Set timestamp for the request in the in-flight tracking // and get the request ID to send upstream @@ -1925,7 +2000,7 @@ void Camera3Device::notify(const camera3_notify_msg *msg) { if (idx >= 0) { InFlightRequest &r = mInFlightMap.editValueAt(idx); r.captureTimestamp = timestamp; - requestId = r.requestId; + resultExtras = r.resultExtras; } } if (idx < 0) { @@ -1934,10 +2009,10 @@ void Camera3Device::notify(const camera3_notify_msg *msg) { break; } ALOGVV("Camera %d: %s: Shutter fired for frame %d (id %d) at %" PRId64, - mId, __FUNCTION__, frameNumber, requestId, timestamp); + mId, __FUNCTION__, frameNumber, resultExtras.requestId, timestamp); // Call listener, if any if (listener != NULL) { - listener->notifyShutter(requestId, timestamp); + listener->notifyShutter(resultExtras, timestamp); } break; } @@ -1959,6 +2034,7 @@ CameraMetadata Camera3Device::getLatestRequestLocked() { return retVal; } + /** * RequestThread inner class methods */ @@ -1975,7 +2051,8 @@ Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent, mDoPause(false), mPaused(true), mFrameNumber(0), - mLatestRequestId(NAME_NOT_FOUND) { + mLatestRequestId(NAME_NOT_FOUND), + mLastFrameNumber(-1) { mStatusId = statusTracker->addComponent(); } @@ -1989,6 +2066,8 @@ status_t Camera3Device::RequestThread::queueRequest( Mutex::Autolock l(mRequestLock); mRequestQueue.push_back(request); + mLastFrameNumber++; + unpauseForNewRequests(); return OK; @@ -2002,6 +2081,8 @@ status_t Camera3Device::RequestThread::queueRequestList( mRequestQueue.push_back(*it); } + mLastFrameNumber += requests.size(); + unpauseForNewRequests(); return OK; @@ -2086,6 +2167,7 @@ status_t Camera3Device::RequestThread::clear() { mRepeatingRequests.clear(); mRequestQueue.clear(); mTriggerMap.clear(); + // Question: no need to reset frame number? return OK; } @@ -2242,6 +2324,8 @@ bool Camera3Device::RequestThread::threadLoop() { } request.frame_number = mFrameNumber++; + // Update frameNumber of CaptureResultExtras + nextRequest->mResultExtras.frameNumber = request.frame_number; // Log request in the in-flight queue sp<Camera3Device> parent = mParent.promote(); @@ -2251,8 +2335,12 @@ bool Camera3Device::RequestThread::threadLoop() { return false; } - res = parent->registerInFlight(request.frame_number, requestId, - request.num_output_buffers); + res = parent->registerInFlight(request.frame_number, + request.num_output_buffers, nextRequest->mResultExtras); + ALOGVV("%s: registered in flight requestId = %d, frameNumber = %lld, burstId = %d ", + __FUNCTION__, + nextRequest->mResultExtras.requestId, nextRequest->mResultExtras.frameNumber, + nextRequest->mResultExtras.burstId); if (res != OK) { SET_ERR("RequestThread: Unable to register new in-flight request:" " %s (%d)", strerror(-res), res); @@ -2329,6 +2417,14 @@ CameraMetadata Camera3Device::RequestThread::getLatestRequest() const { return mLatestRequest; } +int64_t Camera3Device::RequestThread::getLastFrameNumber() { + Mutex::Autolock al(mRequestLock); + + ALOGV("RequestThread::%s", __FUNCTION__); + + return mLastFrameNumber; +} + void Camera3Device::RequestThread::cleanUpFailedRequest( camera3_capture_request_t &request, sp<CaptureRequest> &nextRequest, @@ -2370,6 +2466,9 @@ sp<Camera3Device::CaptureRequest> ++firstRequest, requests.end()); // No need to wait any longer + + mLastFrameNumber += requests.size(); + break; } diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index ed58246..b1ea5ed 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -24,6 +24,7 @@ #include <utils/Thread.h> #include <utils/KeyedVector.h> #include <hardware/camera3.h> +#include <camera/CaptureResult.h> #include "common/CameraDeviceBase.h" #include "device3/StatusTracker.h" @@ -78,11 +79,14 @@ class Camera3Device : // Capture and setStreamingRequest will configure streams if currently in // idle state - virtual status_t capture(CameraMetadata &request); - virtual status_t captureList(const List<const CameraMetadata> &requests); - virtual status_t setStreamingRequest(const CameraMetadata &request); - virtual status_t setStreamingRequestList(const List<const CameraMetadata> &requests); - virtual status_t clearStreamingRequest(); + virtual status_t capture(CameraMetadata &request, int64_t *lastFrameNumber = NULL); + virtual status_t captureList(const List<const CameraMetadata> &requests, + int64_t *lastFrameNumber = NULL); + virtual status_t setStreamingRequest(const CameraMetadata &request, + int64_t *lastFrameNumber = NULL); + virtual status_t setStreamingRequestList(const List<const CameraMetadata> &requests, + int64_t *lastFrameNumber = NULL); + virtual status_t clearStreamingRequest(int64_t *lastFrameNumber = NULL); virtual status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout); @@ -118,7 +122,7 @@ class Camera3Device : virtual status_t setNotifyCallback(NotificationListener *listener); virtual bool willNotify3A(); virtual status_t waitForNextFrame(nsecs_t timeout); - virtual status_t getNextFrame(CameraMetadata *frame); + virtual status_t getNextResult(CaptureResult *frame); virtual status_t triggerAutofocus(uint32_t id); virtual status_t triggerCancelAutofocus(uint32_t id); @@ -127,7 +131,7 @@ class Camera3Device : virtual status_t pushReprocessBuffer(int reprocessStreamId, buffer_handle_t *buffer, wp<BufferReleasedListener> listener); - virtual status_t flush(); + virtual status_t flush(int64_t *lastFrameNumber = NULL); // Methods called by subclasses void notifyStatus(bool idle); // updates from StatusTracker @@ -200,6 +204,7 @@ class Camera3Device : sp<camera3::Camera3Stream> mInputStream; Vector<sp<camera3::Camera3OutputStreamInterface> > mOutputStreams; + CaptureResultExtras mResultExtras; }; typedef List<sp<CaptureRequest> > RequestList; @@ -209,7 +214,8 @@ class Camera3Device : const List<const CameraMetadata> &metadataList, /*out*/RequestList *requestList); - status_t submitRequestsHelper(const List<const CameraMetadata> &requests, bool repeating); + status_t submitRequestsHelper(const List<const CameraMetadata> &requests, bool repeating, + int64_t *lastFrameNumber = NULL); /** * Get the last request submitted to the hal by the request thread. @@ -371,6 +377,8 @@ class Camera3Device : */ CameraMetadata getLatestRequest() const; + int64_t getLastFrameNumber(); + protected: virtual bool threadLoop(); @@ -447,6 +455,8 @@ class Camera3Device : TriggerMap mTriggerMap; TriggerMap mTriggerRemovedMap; TriggerMap mTriggerReplacedMap; + + int64_t mLastFrameNumber; }; sp<RequestThread> mRequestThread; @@ -455,8 +465,6 @@ class Camera3Device : */ struct InFlightRequest { - // android.request.id for the request - int requestId; // Set by notify() SHUTTER call. nsecs_t captureTimestamp; int requestStatus; @@ -465,6 +473,7 @@ class Camera3Device : // Decremented by calls to process_capture_result with valid output // buffers int numBuffersLeft; + CaptureResultExtras resultExtras; // Fields used by the partial result quirk only struct PartialResultQuirkInFlight { @@ -480,20 +489,26 @@ class Camera3Device : // Default constructor needed by KeyedVector InFlightRequest() : - requestId(0), captureTimestamp(0), requestStatus(OK), haveResultMetadata(false), numBuffersLeft(0) { } - InFlightRequest(int id, int numBuffers) : - requestId(id), + InFlightRequest(int numBuffers) : captureTimestamp(0), requestStatus(OK), haveResultMetadata(false), numBuffersLeft(numBuffers) { } + + InFlightRequest(int numBuffers, CaptureResultExtras extras) : + captureTimestamp(0), + requestStatus(OK), + haveResultMetadata(false), + numBuffersLeft(numBuffers), + resultExtras(extras) { + } }; // Map from frame number to the in-flight request state typedef KeyedVector<uint32_t, InFlightRequest> InFlightMap; @@ -501,25 +516,25 @@ class Camera3Device : Mutex mInFlightLock; // Protects mInFlightMap InFlightMap mInFlightMap; - status_t registerInFlight(int32_t frameNumber, int32_t requestId, - int32_t numBuffers); + status_t registerInFlight(uint32_t frameNumber, + int32_t numBuffers, CaptureResultExtras resultExtras); /** * For the partial result quirk, check if all 3A state fields are available * and if so, queue up 3A-only result to the client. Returns true if 3A * is sent. */ - bool processPartial3AQuirk(int32_t frameNumber, int32_t requestId, - const CameraMetadata& partial); + bool processPartial3AQuirk(uint32_t frameNumber, + const CameraMetadata& partial, const CaptureResultExtras& resultExtras); // Helpers for reading and writing 3A metadata into to/from partial results template<typename T> bool get3AResult(const CameraMetadata& result, int32_t tag, - T* value, int32_t frameNumber); + T* value, uint32_t frameNumber); template<typename T> bool insert3AResult(CameraMetadata &result, int32_t tag, const T* value, - int32_t frameNumber); + uint32_t frameNumber); /** * Tracking for idle detection */ @@ -536,7 +551,7 @@ class Camera3Device : uint32_t mNextResultFrameNumber; uint32_t mNextShutterFrameNumber; - List<CameraMetadata> mResultQueue; + List<CaptureResult> mResultQueue; Condition mResultSignal; NotificationListener *mListener; diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp index d662cc2..2257682 100644 --- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp +++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp @@ -146,6 +146,13 @@ void Camera3IOStreamBase::handoutBufferLocked(camera3_stream_buffer &buffer, // Inform tracker about becoming busy if (mDequeuedBufferCount == 0 && mState != STATE_IN_CONFIG && mState != STATE_IN_RECONFIG) { + /** + * Avoid a spurious IDLE->ACTIVE->IDLE transition when using buffers + * before/after register_stream_buffers during initial configuration + * or re-configuration. + * + * TODO: IN_CONFIG and IN_RECONFIG checks only make sense for <HAL3.2 + */ sp<StatusTracker> statusTracker = mStatusTracker.promote(); if (statusTracker != 0) { statusTracker->markComponentActive(mStatusId); @@ -224,6 +231,13 @@ status_t Camera3IOStreamBase::returnAnyBufferLocked( mDequeuedBufferCount--; if (mDequeuedBufferCount == 0 && mState != STATE_IN_CONFIG && mState != STATE_IN_RECONFIG) { + /** + * Avoid a spurious IDLE->ACTIVE->IDLE transition when using buffers + * before/after register_stream_buffers during initial configuration + * or re-configuration. + * + * TODO: IN_CONFIG and IN_RECONFIG checks only make sense for <HAL3.2 + */ ALOGV("%s: Stream %d: All buffers returned; now idle", __FUNCTION__, mId); sp<StatusTracker> statusTracker = mStatusTracker.promote(); diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp index 70406f1..646f286 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp @@ -23,6 +23,8 @@ #include "device3/Camera3Stream.h" #include "device3/StatusTracker.h" +#include <cutils/properties.h> + namespace android { namespace camera3 { @@ -137,6 +139,7 @@ camera3_stream* Camera3Stream::startConfiguration() { if (mState == STATE_CONSTRUCTED) { mState = STATE_IN_CONFIG; } else { // mState == STATE_CONFIGURED + LOG_ALWAYS_FATAL_IF(mState != STATE_CONFIGURED, "Invalid state: 0x%x", mState); mState = STATE_IN_RECONFIG; } @@ -223,6 +226,14 @@ status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer, ATRACE_CALL(); Mutex::Autolock l(mLock); + /** + * TODO: Check that the state is valid first. + * + * <HAL3.2 IN_CONFIG and IN_RECONFIG in addition to CONFIGURED. + * >= HAL3.2 CONFIGURED only + * + * Do this for getBuffer as well. + */ status_t res = returnBufferLocked(buffer, timestamp); if (res == OK) { fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/true); @@ -314,12 +325,46 @@ status_t Camera3Stream::disconnect() { status_t Camera3Stream::registerBuffersLocked(camera3_device *hal3Device) { ATRACE_CALL(); + + /** + * >= CAMERA_DEVICE_API_VERSION_3_2: + * + * camera3_device_t->ops->register_stream_buffers() is not called and must + * be NULL. + */ + if (hal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_2) { + ALOGV("%s: register_stream_buffers unused as of HAL3.2", __FUNCTION__); + + /** + * Skip the NULL check if camera.dev.register_stream is 1. + * + * For development-validation purposes only. + * + * TODO: Remove the property check before shipping L (b/13914251). + */ + char value[PROPERTY_VALUE_MAX] = { '\0', }; + property_get("camera.dev.register_stream", value, "0"); + int propInt = atoi(value); + + if (propInt == 0 && hal3Device->ops->register_stream_buffers != NULL) { + ALOGE("%s: register_stream_buffers is deprecated in HAL3.2; " + "must be set to NULL in camera3_device::ops", __FUNCTION__); + return INVALID_OPERATION; + } else { + ALOGD("%s: Skipping NULL check for deprecated register_stream_buffers"); + } + + return OK; + } else { + ALOGV("%s: register_stream_buffers using deprecated code path", __FUNCTION__); + } + status_t res; size_t bufferCount = getBufferCountLocked(); Vector<buffer_handle_t*> buffers; - buffers.insertAt(NULL, 0, bufferCount); + buffers.insertAt(/*prototype_item*/NULL, /*index*/0, bufferCount); camera3_stream_buffer_set bufferSet = camera3_stream_buffer_set(); bufferSet.stream = this; @@ -327,7 +372,7 @@ status_t Camera3Stream::registerBuffersLocked(camera3_device *hal3Device) { bufferSet.buffers = buffers.editArray(); Vector<camera3_stream_buffer_t> streamBuffers; - streamBuffers.insertAt(camera3_stream_buffer_t(), 0, bufferCount); + streamBuffers.insertAt(camera3_stream_buffer_t(), /*index*/0, bufferCount); // Register all buffers with the HAL. This means getting all the buffers // from the stream, providing them to the HAL with the diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h index 6eeb721..766b772 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.h +++ b/services/camera/libcameraservice/device3/Camera3Stream.h @@ -82,6 +82,23 @@ namespace camera3 { * STATE_CONFIGURED => STATE_CONSTRUCTED: * When disconnect() is called after making sure stream is idle with * waitUntilIdle(). + * + * Status Tracking: + * Each stream is tracked by StatusTracker as a separate component, + * depending on the handed out buffer count. The state must be STATE_CONFIGURED + * in order for the component to be marked. + * + * It's marked in one of two ways: + * + * - ACTIVE: One or more buffers have been handed out (with #getBuffer). + * - IDLE: All buffers have been returned (with #returnBuffer), and their + * respective release_fence(s) have been signaled. + * + * A typical use case is output streams. When the HAL has any buffers + * dequeued, the stream is marked ACTIVE. When the HAL returns all buffers + * (e.g. if no capture requests are active), the stream is marked IDLE. + * In this use case, the app consumer does not affect the component status. + * */ class Camera3Stream : protected camera3_stream, |