summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camera/Android.mk1
-rw-r--r--camera/CaptureResult.cpp127
-rw-r--r--camera/camera2/ICameraDeviceCallbacks.cpp48
-rw-r--r--camera/camera2/ICameraDeviceUser.cpp136
-rw-r--r--cmds/stagefright/stagefright.cpp8
-rw-r--r--drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp39
-rw-r--r--drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h16
-rw-r--r--include/camera/CaptureResult.h90
-rw-r--r--include/camera/camera2/ICameraDeviceCallbacks.h12
-rw-r--r--include/camera/camera2/ICameraDeviceUser.h38
-rw-r--r--include/media/IDrm.h14
-rw-r--r--include/media/stagefright/ACodec.h1
-rw-r--r--include/media/stagefright/SurfaceMediaSource.h9
-rw-r--r--include/media/stagefright/Utils.h2
-rw-r--r--include/media/stagefright/foundation/AString.h3
-rw-r--r--media/common_time/utils.cpp2
-rw-r--r--media/libmedia/IDrm.cpp60
-rw-r--r--media/libmediaplayerservice/Drm.cpp46
-rw-r--r--media/libmediaplayerservice/Drm.h14
-rw-r--r--media/libstagefright/ACodec.cpp16
-rw-r--r--media/libstagefright/AwesomePlayer.cpp4
-rw-r--r--media/libstagefright/MediaCodec.cpp2
-rw-r--r--media/libstagefright/SurfaceMediaSource.cpp20
-rw-r--r--media/libstagefright/Utils.cpp36
-rw-r--r--media/libstagefright/codecs/aacdec/SoftAAC2.cpp4
-rw-r--r--media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp4
-rw-r--r--media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp4
-rw-r--r--media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp8
-rw-r--r--media/libstagefright/codecs/g711/dec/SoftG711.cpp2
-rw-r--r--media/libstagefright/codecs/gsm/dec/SoftGSM.cpp4
-rw-r--r--media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp4
-rw-r--r--media/libstagefright/foundation/AString.cpp8
-rw-r--r--media/libstagefright/httplive/LiveSession.cpp9
-rw-r--r--media/libstagefright/httplive/M3UParser.cpp3
-rw-r--r--media/libstagefright/matroska/Android.mk2
-rw-r--r--media/libstagefright/matroska/MatroskaExtractor.cpp18
-rw-r--r--media/libstagefright/omx/GraphicBufferSource.cpp36
-rw-r--r--media/libstagefright/omx/GraphicBufferSource.h9
-rw-r--r--media/libstagefright/rtsp/ARTSPConnection.cpp2
-rw-r--r--media/libstagefright/rtsp/SDPLoader.cpp7
-rw-r--r--media/libstagefright/tests/SurfaceMediaSource_test.cpp10
-rw-r--r--media/libstagefright/timedtext/Android.mk2
-rw-r--r--media/libstagefright/wifi-display/source/PlaybackSession.cpp4
-rw-r--r--media/libstagefright/wifi-display/source/PlaybackSession.h3
-rw-r--r--services/audioflinger/AudioMixer.cpp8
-rw-r--r--services/audioflinger/AudioResampler.cpp11
-rw-r--r--services/audioflinger/AudioResampler.h2
-rw-r--r--services/audioflinger/AudioResamplerDyn.cpp251
-rw-r--r--services/audioflinger/AudioResamplerDyn.h82
-rw-r--r--services/audioflinger/AudioResamplerFirGen.h5
-rw-r--r--services/audioflinger/AudioResamplerFirProcess.h247
-rw-r--r--services/audioflinger/FastMixer.cpp1
-rw-r--r--services/audioflinger/RecordTracks.h2
-rw-r--r--services/audioflinger/Threads.cpp12
-rw-r--r--services/audioflinger/test-resample.cpp182
-rw-r--r--services/camera/libcameraservice/CameraService.cpp9
-rw-r--r--services/camera/libcameraservice/CameraService.h11
-rw-r--r--services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp9
-rw-r--r--services/camera/libcameraservice/api1/client2/CaptureSequencer.h5
-rw-r--r--services/camera/libcameraservice/api1/client2/FrameProcessor.cpp8
-rw-r--r--services/camera/libcameraservice/api1/client2/FrameProcessor.h2
-rw-r--r--services/camera/libcameraservice/api1/client2/ZslProcessor.cpp9
-rw-r--r--services/camera/libcameraservice/api1/client2/ZslProcessor.h3
-rw-r--r--services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp9
-rw-r--r--services/camera/libcameraservice/api1/client2/ZslProcessor3.h4
-rw-r--r--services/camera/libcameraservice/api2/CameraDeviceClient.cpp141
-rw-r--r--services/camera/libcameraservice/api2/CameraDeviceClient.h23
-rw-r--r--services/camera/libcameraservice/api_pro/ProCamera2Client.cpp9
-rw-r--r--services/camera/libcameraservice/api_pro/ProCamera2Client.h5
-rw-r--r--services/camera/libcameraservice/common/Camera2ClientBase.cpp17
-rw-r--r--services/camera/libcameraservice/common/Camera2ClientBase.h7
-rw-r--r--services/camera/libcameraservice/common/CameraDeviceBase.h39
-rw-r--r--services/camera/libcameraservice/common/FrameProcessorBase.cpp47
-rw-r--r--services/camera/libcameraservice/common/FrameProcessorBase.h8
-rw-r--r--services/camera/libcameraservice/device2/Camera2Device.cpp36
-rw-r--r--services/camera/libcameraservice/device2/Camera2Device.h17
-rw-r--r--services/camera/libcameraservice/device3/Camera3Device.cpp225
-rw-r--r--services/camera/libcameraservice/device3/Camera3Device.h55
-rw-r--r--services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp14
-rw-r--r--services/camera/libcameraservice/device3/Camera3Stream.cpp49
-rw-r--r--services/camera/libcameraservice/device3/Camera3Stream.h17
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,