am 5ca15ccf: Reconcile with jb-release
* commit '5ca15ccf7336d5aa5a7b563742757fa37092eb48':
Revert input buffer count for the SoftAAC* decoders back to 4.
diff --git a/libvideoeditor/lvpp/Android.mk b/libvideoeditor/lvpp/Android.mk
index c018d74..0ed7e6c 100755
--- a/libvideoeditor/lvpp/Android.mk
+++ b/libvideoeditor/lvpp/Android.mk
@@ -59,6 +59,7 @@
libstagefright \
libstagefright_foundation \
libstagefright_omx \
+ libsync \
libui \
libutils \
libvideoeditor_osal \
diff --git a/libvideoeditor/lvpp/NativeWindowRenderer.cpp b/libvideoeditor/lvpp/NativeWindowRenderer.cpp
index b2c2675..2e15ff9 100755
--- a/libvideoeditor/lvpp/NativeWindowRenderer.cpp
+++ b/libvideoeditor/lvpp/NativeWindowRenderer.cpp
@@ -22,9 +22,9 @@
#include <cutils/log.h>
#include <gui/SurfaceTexture.h>
#include <gui/SurfaceTextureClient.h>
-#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
+#include <media/stagefright/foundation/ADebug.h>
#include "VideoEditorTools.h"
#define CHECK_EGL_ERROR CHECK(EGL_SUCCESS == eglGetError())
@@ -382,7 +382,7 @@
int64_t timeUs;
CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
native_window_set_buffers_timestamp(anw, timeUs * 1000);
- status_t err = anw->queueBuffer(anw, buffer->graphicBuffer().get());
+ status_t err = anw->queueBuffer(anw, buffer->graphicBuffer().get(), -1);
if (err != 0) {
ALOGE("queueBuffer failed with error %s (%d)", strerror(-err), -err);
return;
@@ -399,18 +399,16 @@
native_window_set_usage(anw, GRALLOC_USAGE_SW_WRITE_OFTEN);
ANativeWindowBuffer* anb;
- anw->dequeueBuffer(anw, &anb);
+ CHECK(NO_ERROR == native_window_dequeue_buffer_and_wait(anw, &anb));
CHECK(anb != NULL);
- sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
- CHECK(NO_ERROR == anw->lockBuffer(anw, buf->getNativeBuffer()));
-
// Copy the buffer
uint8_t* img = NULL;
+ sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
copyI420Buffer(buffer, img, width, height, buf->getStride());
buf->unlock();
- CHECK(NO_ERROR == anw->queueBuffer(anw, buf->getNativeBuffer()));
+ CHECK(NO_ERROR == anw->queueBuffer(anw, buf->getNativeBuffer(), -1));
}
void NativeWindowRenderer::copyI420Buffer(MediaBuffer* src, uint8_t* dst,
diff --git a/libvideoeditor/lvpp/PreviewRenderer.cpp b/libvideoeditor/lvpp/PreviewRenderer.cpp
index 4aa4eb3..b1cfc8e 100755
--- a/libvideoeditor/lvpp/PreviewRenderer.cpp
+++ b/libvideoeditor/lvpp/PreviewRenderer.cpp
@@ -97,13 +97,12 @@
void PreviewRenderer::getBufferYV12(uint8_t **data, size_t *stride) {
int err = OK;
- if ((err = mSurface->ANativeWindow::dequeueBuffer(mSurface.get(), &mBuf)) != 0) {
- ALOGW("Surface::dequeueBuffer returned error %d", err);
+ if ((err = native_window_dequeue_buffer_and_wait(mSurface.get(),
+ &mBuf)) != 0) {
+ ALOGW("native_window_dequeue_buffer_and_wait returned error %d", err);
return;
}
- CHECK_EQ(0, mSurface->ANativeWindow::lockBuffer(mSurface.get(), mBuf));
-
GraphicBufferMapper &mapper = GraphicBufferMapper::get();
Rect bounds(mWidth, mHeight);
@@ -131,7 +130,7 @@
if (mBuf!= NULL) {
CHECK_EQ(0, mapper.unlock(mBuf->handle));
- if ((err = mSurface->ANativeWindow::queueBuffer(mSurface.get(), mBuf)) != 0) {
+ if ((err = mSurface->ANativeWindow::queueBuffer(mSurface.get(), mBuf, -1)) != 0) {
ALOGW("Surface::queueBuffer returned error %d", err);
}
}
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index c4743a1..b4894e9 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -595,7 +595,7 @@
// Dequeue buffers and send them to OMX
for (OMX_U32 i = 0; i < def.nBufferCountActual; i++) {
ANativeWindowBuffer *buf;
- err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
+ err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf);
if (err != 0) {
ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
break;
@@ -653,7 +653,7 @@
mComponentName.c_str(), info->mBufferID);
int err = mNativeWindow->cancelBuffer(
- mNativeWindow.get(), info->mGraphicBuffer.get());
+ mNativeWindow.get(), info->mGraphicBuffer.get(), -1);
CHECK_EQ(err, 0);
@@ -664,7 +664,8 @@
ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() {
ANativeWindowBuffer *buf;
- if (mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf) != 0) {
+ int fenceFd = -1;
+ if (native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf) != 0) {
ALOGE("dequeueBuffer failed.");
return NULL;
}
@@ -2188,7 +2189,8 @@
// on the screen and then been replaced, so an previous video frames are
// guaranteed NOT to be currently displayed.
for (int i = 0; i < numBufs + 1; i++) {
- err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &anb);
+ int fenceFd = -1;
+ err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &anb);
if (err != NO_ERROR) {
ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)",
strerror(-err), -err);
@@ -2196,13 +2198,6 @@
}
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
- err = mNativeWindow->lockBuffer(mNativeWindow.get(),
- buf->getNativeBuffer());
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: lockBuffer failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
// Fill the buffer with the a 1x1 checkerboard pattern ;)
uint32_t* img = NULL;
@@ -2223,7 +2218,7 @@
}
err = mNativeWindow->queueBuffer(mNativeWindow.get(),
- buf->getNativeBuffer());
+ buf->getNativeBuffer(), -1);
if (err != NO_ERROR) {
ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)",
strerror(-err), -err);
@@ -2238,7 +2233,7 @@
if (err != NO_ERROR) {
// Clean up after an error.
if (anb != NULL) {
- mNativeWindow->cancelBuffer(mNativeWindow.get(), anb);
+ mNativeWindow->cancelBuffer(mNativeWindow.get(), anb, -1);
}
native_window_api_disconnect(mNativeWindow.get(),
@@ -2751,7 +2746,7 @@
status_t err;
if ((err = mCodec->mNativeWindow->queueBuffer(
mCodec->mNativeWindow.get(),
- info->mGraphicBuffer.get())) == OK) {
+ info->mGraphicBuffer.get(), -1)) == OK) {
info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;
} else {
mCodec->signalError(OMX_ErrorUndefined, err);
@@ -3253,11 +3248,6 @@
if (info->mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) {
continue;
}
-
- status_t err = mCodec->mNativeWindow->lockBuffer(
- mCodec->mNativeWindow.get(),
- info->mGraphicBuffer.get());
- CHECK_EQ(err, (status_t)OK);
} else {
CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US);
}
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 8ad1cb9..e5b4d75 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -81,6 +81,7 @@
libssl \
libstagefright_omx \
libstagefright_yuv \
+ libsync \
libui \
libutils \
libvorbisidec \
@@ -97,12 +98,12 @@
libstagefright_id3 \
libFLAC \
-ifneq ($(TARGET_BUILD_PDK), true)
-LOCAL_STATIC_LIBRARIES += \
- libstagefright_chromium_http
-LOCAL_SHARED_LIBRARIES += \
- libchromium_net
+LOCAL_SRC_FILES += \
+ chromium_http_stub.cpp
LOCAL_CPPFLAGS += -DCHROMIUM_AVAILABLE=1
+
+ifneq ($(TARGET_BUILD_PDK), true)
+LOCAL_REQUIRED_MODULES := libstagefright_chromium_http
endif
LOCAL_SHARED_LIBRARIES += libstlport
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 0f346d8..2c68075 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -130,7 +130,7 @@
CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
native_window_set_buffers_timestamp(mNativeWindow.get(), timeUs * 1000);
status_t err = mNativeWindow->queueBuffer(
- mNativeWindow.get(), buffer->graphicBuffer().get());
+ mNativeWindow.get(), buffer->graphicBuffer().get(), -1);
if (err != 0) {
ALOGE("queueBuffer failed with error %s (%d)", strerror(-err),
-err);
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index c75f100..1de808e 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -17,7 +17,7 @@
#include "include/AMRExtractor.h"
#if CHROMIUM_AVAILABLE
-#include "include/DataUriSource.h"
+#include "include/chromium_http_stub.h"
#endif
#include "include/MP3Extractor.h"
@@ -173,7 +173,7 @@
# if CHROMIUM_AVAILABLE
} else if (!strncasecmp("data:", uri, 5)) {
- source = new DataUriSource(uri);
+ source = createDataUriSource(uri);
#endif
} else {
// Assume it's a filename.
diff --git a/media/libstagefright/FLACExtractor.cpp b/media/libstagefright/FLACExtractor.cpp
index 668d7f7..29bb056 100644
--- a/media/libstagefright/FLACExtractor.cpp
+++ b/media/libstagefright/FLACExtractor.cpp
@@ -350,7 +350,7 @@
for (FLAC__uint32 i = 0; i < vc->num_comments; ++i) {
FLAC__StreamMetadata_VorbisComment_Entry *vce;
vce = &vc->comments[i];
- if (mFileMetadata != 0) {
+ if (mFileMetadata != 0 && vce->entry != NULL) {
parseVorbisComment(mFileMetadata, (const char *) vce->entry,
vce->length);
}
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp
index d7eea3f..40bfc55 100644
--- a/media/libstagefright/HTTPBase.cpp
+++ b/media/libstagefright/HTTPBase.cpp
@@ -21,7 +21,7 @@
#include "include/HTTPBase.h"
#if CHROMIUM_AVAILABLE
-#include "include/ChromiumHTTPDataSource.h"
+#include "include/chromium_http_stub.h"
#endif
#include <media/stagefright/foundation/ADebug.h>
@@ -46,7 +46,10 @@
// static
sp<HTTPBase> HTTPBase::Create(uint32_t flags) {
#if CHROMIUM_AVAILABLE
- return new ChromiumHTTPDataSource(flags);
+ HTTPBase *dataSource = createChromiumHTTPDataSource(flags);
+ if (dataSource) {
+ return dataSource;
+ }
#endif
{
TRESPASS();
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index fde7ebf..1d4ab32 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1776,7 +1776,7 @@
// Dequeue buffers and send them to OMX
for (OMX_U32 i = 0; i < def.nBufferCountActual; i++) {
ANativeWindowBuffer* buf;
- err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
+ err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf);
if (err != 0) {
ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
break;
@@ -1832,7 +1832,7 @@
CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US);
CODEC_LOGV("Calling cancelBuffer on buffer %p", info->mBuffer);
int err = mNativeWindow->cancelBuffer(
- mNativeWindow.get(), info->mMediaBuffer->graphicBuffer().get());
+ mNativeWindow.get(), info->mMediaBuffer->graphicBuffer().get(), -1);
if (err != 0) {
CODEC_LOGE("cancelBuffer failed w/ error 0x%08x", err);
@@ -1846,7 +1846,8 @@
OMXCodec::BufferInfo* OMXCodec::dequeueBufferFromNativeWindow() {
// Dequeue the next buffer from the native window.
ANativeWindowBuffer* buf;
- int err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
+ int fenceFd = -1;
+ int err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf);
if (err != 0) {
CODEC_LOGE("dequeueBuffer failed w/ error 0x%08x", err);
@@ -1950,7 +1951,8 @@
// on the screen and then been replaced, so an previous video frames are
// guaranteed NOT to be currently displayed.
for (int i = 0; i < numBufs + 1; i++) {
- err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &anb);
+ int fenceFd = -1;
+ err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &anb);
if (err != NO_ERROR) {
ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)",
strerror(-err), -err);
@@ -1958,13 +1960,6 @@
}
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
- err = mNativeWindow->lockBuffer(mNativeWindow.get(),
- buf->getNativeBuffer());
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: lockBuffer failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
// Fill the buffer with the a 1x1 checkerboard pattern ;)
uint32_t* img = NULL;
@@ -1985,7 +1980,7 @@
}
err = mNativeWindow->queueBuffer(mNativeWindow.get(),
- buf->getNativeBuffer());
+ buf->getNativeBuffer(), -1);
if (err != NO_ERROR) {
ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)",
strerror(-err), -err);
@@ -2000,7 +1995,7 @@
if (err != NO_ERROR) {
// Clean up after an error.
if (anb != NULL) {
- mNativeWindow->cancelBuffer(mNativeWindow.get(), anb);
+ mNativeWindow->cancelBuffer(mNativeWindow.get(), anb, -1);
}
native_window_api_disconnect(mNativeWindow.get(),
@@ -3199,23 +3194,6 @@
return;
}
- if (info->mMediaBuffer != NULL) {
- sp<GraphicBuffer> graphicBuffer = info->mMediaBuffer->graphicBuffer();
- if (graphicBuffer != 0) {
- // When using a native buffer we need to lock the buffer before
- // giving it to OMX.
- CODEC_LOGV("Calling lockBuffer on %p", info->mBuffer);
- int err = mNativeWindow->lockBuffer(mNativeWindow.get(),
- graphicBuffer.get());
- if (err != 0) {
- CODEC_LOGE("lockBuffer failed w/ error 0x%08x", err);
-
- setState(ERROR);
- return;
- }
- }
- }
-
CODEC_LOGV("Calling fillBuffer on buffer %p", info->mBuffer);
status_t err = mOMX->fillBuffer(mNode, info->mBuffer);
diff --git a/media/libstagefright/chromium_http/Android.mk b/media/libstagefright/chromium_http/Android.mk
index 6ab2a00..2c6d84c 100644
--- a/media/libstagefright/chromium_http/Android.mk
+++ b/media/libstagefright/chromium_http/Android.mk
@@ -6,7 +6,8 @@
LOCAL_SRC_FILES:= \
DataUriSource.cpp \
ChromiumHTTPDataSource.cpp \
- support.cpp
+ support.cpp \
+ chromium_http_stub.cpp
LOCAL_C_INCLUDES:= \
$(TOP)/frameworks/av/media/libstagefright \
@@ -16,10 +17,20 @@
LOCAL_CFLAGS += -Wno-multichar
-LOCAL_SHARED_LIBRARIES += libstlport
+LOCAL_SHARED_LIBRARIES += \
+ libstlport \
+ libchromium_net \
+ libutils \
+ libcutils \
+ libstagefright_foundation \
+ libstagefright \
+ libdrmframework
+
include external/stlport/libstlport.mk
LOCAL_MODULE:= libstagefright_chromium_http
-include $(BUILD_STATIC_LIBRARY)
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
endif
diff --git a/media/libstagefright/chromium_http/chromium_http_stub.cpp b/media/libstagefright/chromium_http/chromium_http_stub.cpp
new file mode 100644
index 0000000..560a61f
--- /dev/null
+++ b/media/libstagefright/chromium_http/chromium_http_stub.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <dlfcn.h>
+
+#include <include/chromium_http_stub.h>
+#include <include/ChromiumHTTPDataSource.h>
+#include <include/DataUriSource.h>
+
+namespace android {
+
+HTTPBase *createChromiumHTTPDataSource(uint32_t flags) {
+ return new ChromiumHTTPDataSource(flags);
+}
+
+DataSource *createDataUriSource(const char *uri) {
+ return new DataUriSource(uri);
+}
+
+}
diff --git a/media/libstagefright/chromium_http_stub.cpp b/media/libstagefright/chromium_http_stub.cpp
new file mode 100644
index 0000000..cbd8796
--- /dev/null
+++ b/media/libstagefright/chromium_http_stub.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <dlfcn.h>
+
+#include <media/stagefright/DataSource.h>
+
+#include "include/chromium_http_stub.h"
+#include "include/HTTPBase.h"
+
+namespace android {
+
+static bool gFirst = true;
+static void *gHandle;
+static Mutex gLibMutex;
+
+HTTPBase *(*gLib_createChromiumHTTPDataSource)(uint32_t flags);
+DataSource *(*gLib_createDataUriSource)(const char *uri);
+
+static bool load_libstagefright_chromium_http() {
+ Mutex::Autolock autoLock(gLibMutex);
+ void *sym;
+
+ if (!gFirst) {
+ return (gHandle != NULL);
+ }
+
+ gFirst = false;
+
+ gHandle = dlopen("libstagefright_chromium_http.so", RTLD_NOW);
+ if (gHandle == NULL) {
+ return false;
+ }
+
+ sym = dlsym(gHandle, "createChromiumHTTPDataSource");
+ if (sym == NULL) {
+ gHandle = NULL;
+ return false;
+ }
+ gLib_createChromiumHTTPDataSource = (HTTPBase *(*)(uint32_t))sym;
+
+ sym = dlsym(gHandle, "createDataUriSource");
+ if (sym == NULL) {
+ gHandle = NULL;
+ return false;
+ }
+ gLib_createDataUriSource = (DataSource *(*)(const char *))sym;
+
+ return true;
+}
+
+HTTPBase *createChromiumHTTPDataSource(uint32_t flags) {
+ if (!load_libstagefright_chromium_http()) {
+ return NULL;
+ }
+
+ return gLib_createChromiumHTTPDataSource(flags);
+}
+
+DataSource *createDataUriSource(const char *uri) {
+ if (!load_libstagefright_chromium_http()) {
+ return NULL;
+ }
+
+ return gLib_createDataUriSource(uri);
+}
+
+}
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 8673bad..2704a37 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -141,13 +141,12 @@
const void *data, size_t size, void *platformPrivate) {
ANativeWindowBuffer *buf;
int err;
- if ((err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf)) != 0) {
+ if ((err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(),
+ &buf)) != 0) {
ALOGW("Surface::dequeueBuffer returned error %d", err);
return;
}
- CHECK_EQ(0, mNativeWindow->lockBuffer(mNativeWindow.get(), buf));
-
GraphicBufferMapper &mapper = GraphicBufferMapper::get();
Rect bounds(mCropWidth, mCropHeight);
@@ -231,7 +230,8 @@
CHECK_EQ(0, mapper.unlock(buf->handle));
- if ((err = mNativeWindow->queueBuffer(mNativeWindow.get(), buf)) != 0) {
+ if ((err = mNativeWindow->queueBuffer(mNativeWindow.get(), buf,
+ -1)) != 0) {
ALOGW("Surface::queueBuffer returned error %d", err);
}
buf = NULL;
diff --git a/media/libstagefright/include/chromium_http_stub.h b/media/libstagefright/include/chromium_http_stub.h
new file mode 100644
index 0000000..869d4ac
--- /dev/null
+++ b/media/libstagefright/include/chromium_http_stub.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012 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 CHROMIUM_HTTP_STUB_H_
+#define CHROMIUM_HTTP_STUB_H_
+
+#include <include/HTTPBase.h>
+#include <media/stagefright/DataSource.h>
+
+namespace android {
+extern "C" {
+HTTPBase *createChromiumHTTPDataSource(uint32_t flags);
+DataSource *createDataUriSource(const char *uri);
+}
+}
+
+#endif
diff --git a/media/libstagefright/tests/Android.mk b/media/libstagefright/tests/Android.mk
index a1e6be7..57fff0b 100644
--- a/media/libstagefright/tests/Android.mk
+++ b/media/libstagefright/tests/Android.mk
@@ -20,9 +20,10 @@
libgui \
libmedia \
libstagefright \
- libstagefright_omx \
libstagefright_foundation \
+ libstagefright_omx \
libstlport \
+ libsync \
libui \
libutils \
diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
index 466f521..cc2aca7 100644
--- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp
+++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
@@ -509,31 +509,31 @@
// cpu YV12 buffer
void SurfaceMediaSourceTest::oneBufferPass(int width, int height ) {
ANativeWindowBuffer* anb;
- ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
ASSERT_TRUE(anb != NULL);
- sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
- ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
// Fill the buffer with the a checkerboard pattern
uint8_t* img = NULL;
+ sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
SurfaceMediaSourceTest::fillYV12Buffer(img, width, height, buf->getStride());
buf->unlock();
- ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+ ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
+ -1));
}
// Dequeuing and queuing the buffer without really filling it in.
void SurfaceMediaSourceTest::oneBufferPassNoFill(int width, int height ) {
ANativeWindowBuffer* anb;
- ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
ASSERT_TRUE(anb != NULL);
- sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
- // ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
// We do not fill the buffer in. Just queue it back.
- ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+ sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+ ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
+ -1));
}
// Fill a YV12 buffer with a multi-colored checkerboard pattern
@@ -652,7 +652,7 @@
ANativeWindowBuffer* anb;
// Note: make sure we get an ERROR back when dequeuing!
- ASSERT_NE(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ ASSERT_NE(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
}
// pass multiple buffers from the native_window the SurfaceMediaSource
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 0d13970..c32fc6b 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -373,6 +373,7 @@
if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
return BAD_VALUE;
}
+ Mutex::Autolock _l(mLock);
mpAudioPolicy->init_stream_volume(mpAudioPolicy, stream, indexMin, indexMax);
return NO_ERROR;
}
@@ -390,7 +391,7 @@
if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
return BAD_VALUE;
}
-
+ Mutex::Autolock _l(mLock);
if (mpAudioPolicy->set_stream_volume_index_for_device) {
return mpAudioPolicy->set_stream_volume_index_for_device(mpAudioPolicy,
stream,
@@ -411,6 +412,7 @@
if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
return BAD_VALUE;
}
+ Mutex::Autolock _l(mLock);
if (mpAudioPolicy->get_stream_volume_index_for_device) {
return mpAudioPolicy->get_stream_volume_index_for_device(mpAudioPolicy,
stream,
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 3cae1f5..8cccf49 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -7,7 +7,10 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- CameraService.cpp
+ CameraService.cpp \
+ CameraClient.cpp \
+ Camera2Client.cpp \
+ Camera2Device.cpp
LOCAL_SHARED_LIBRARIES:= \
libui \
@@ -18,7 +21,12 @@
libmedia_native \
libcamera_client \
libgui \
- libhardware
+ libhardware \
+ libsync \
+ libcamera_metadata
+
+LOCAL_C_INCLUDES += \
+ system/media/camera/include
LOCAL_MODULE:= libcameraservice
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
new file mode 100644
index 0000000..c90f81a
--- /dev/null
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -0,0 +1,2730 @@
+/*
+ * Copyright (C) 2012 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 "Camera2Client"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include <cutils/properties.h>
+#include <gui/SurfaceTextureClient.h>
+#include <gui/Surface.h>
+
+#include <math.h>
+
+#include "Camera2Client.h"
+
+namespace android {
+
+#define ALOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
+#define ALOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__);
+
+static int getCallingPid() {
+ return IPCThreadState::self()->getCallingPid();
+}
+
+static int getCallingUid() {
+ return IPCThreadState::self()->getCallingUid();
+}
+
+// Interface used by CameraService
+
+Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
+ const sp<ICameraClient>& cameraClient,
+ int cameraId,
+ int cameraFacing,
+ int clientPid):
+ Client(cameraService, cameraClient,
+ cameraId, cameraFacing, clientPid),
+ mState(NOT_INITIALIZED),
+ mPreviewStreamId(NO_STREAM),
+ mPreviewRequest(NULL),
+ mCaptureStreamId(NO_STREAM),
+ mCaptureRequest(NULL)
+{
+ ATRACE_CALL();
+
+ mDevice = new Camera2Device(cameraId);
+}
+
+status_t Camera2Client::initialize(camera_module_t *module)
+{
+ ATRACE_CALL();
+ status_t res;
+
+ res = mDevice->initialize(module);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return NO_INIT;
+ }
+
+ res = buildDefaultParameters();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: unable to build defaults: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return NO_INIT;
+ }
+
+ if (gLogLevel >= 1) {
+ ALOGD("%s: Default parameters converted from camera %d:", __FUNCTION__,
+ mCameraId);
+ ALOGD("%s", mParamsFlattened.string());
+ }
+
+ mState = STOPPED;
+
+ return OK;
+}
+
+Camera2Client::~Camera2Client() {
+ ATRACE_CALL();
+ ALOGV("%s: Camera %d: Shutting down", __FUNCTION__, mCameraId);
+
+ mDestructionStarted = true;
+
+ disconnect();
+
+}
+
+status_t Camera2Client::dump(int fd, const Vector<String16>& args) {
+ String8 result;
+ result.appendFormat("Client2[%d] (%p) PID: %d, dump:\n",
+ mCameraId,
+ getCameraClient()->asBinder().get(),
+ mClientPid);
+ result.append(" State: ");
+#define CASE_APPEND_ENUM(x) case x: result.append(#x "\n"); break;
+
+ result.append(getStateName(mState));
+
+ result.append("\n Current parameters:\n");
+ result.appendFormat(" Preview size: %d x %d\n",
+ mParameters.previewWidth, mParameters.previewHeight);
+ result.appendFormat(" Preview FPS range: %d - %d\n",
+ mParameters.previewFpsRange[0], mParameters.previewFpsRange[1]);
+ result.appendFormat(" Preview HAL pixel format: 0x%x\n",
+ mParameters.previewFormat);
+ result.appendFormat(" Preview transform: %x\n",
+ mParameters.previewTransform);
+ result.appendFormat(" Picture size: %d x %d\n",
+ mParameters.pictureWidth, mParameters.pictureHeight);
+ result.appendFormat(" Jpeg thumbnail size: %d x %d\n",
+ mParameters.jpegThumbSize[0], mParameters.jpegThumbSize[1]);
+ result.appendFormat(" Jpeg quality: %d, thumbnail quality: %d\n",
+ mParameters.jpegQuality, mParameters.jpegThumbQuality);
+ result.appendFormat(" Jpeg rotation: %d\n", mParameters.jpegRotation);
+ result.appendFormat(" GPS tags %s\n",
+ mParameters.gpsEnabled ? "enabled" : "disabled");
+ if (mParameters.gpsEnabled) {
+ result.appendFormat(" GPS lat x long x alt: %f x %f x %f\n",
+ mParameters.gpsCoordinates[0], mParameters.gpsCoordinates[1],
+ mParameters.gpsCoordinates[2]);
+ result.appendFormat(" GPS timestamp: %lld\n",
+ mParameters.gpsTimestamp);
+ result.appendFormat(" GPS processing method: %s\n",
+ mParameters.gpsProcessingMethod.string());
+ }
+
+ result.append(" White balance mode: ");
+ switch (mParameters.wbMode) {
+ CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_AUTO)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_INCANDESCENT)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_FLUORESCENT)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_WARM_FLUORESCENT)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_DAYLIGHT)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_CLOUDY_DAYLIGHT)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_TWILIGHT)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_SHADE)
+ default: result.append("UNKNOWN\n");
+ }
+
+ result.append(" Effect mode: ");
+ switch (mParameters.effectMode) {
+ CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_OFF)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MONO)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_NEGATIVE)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_SOLARIZE)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_SEPIA)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_POSTERIZE)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_WHITEBOARD)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_BLACKBOARD)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_AQUA)
+ default: result.append("UNKNOWN\n");
+ }
+
+ result.append(" Antibanding mode: ");
+ switch (mParameters.antibandingMode) {
+ CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_AUTO)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_OFF)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_50HZ)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_60HZ)
+ default: result.append("UNKNOWN\n");
+ }
+
+ result.append(" Scene mode: ");
+ switch (mParameters.sceneMode) {
+ case ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED:
+ result.append("AUTO\n"); break;
+ CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_ACTION)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_PORTRAIT)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_LANDSCAPE)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_NIGHT)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_NIGHT_PORTRAIT)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_THEATRE)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_BEACH)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_SNOW)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_SUNSET)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_STEADYPHOTO)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_FIREWORKS)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_SPORTS)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_PARTY)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_BARCODE)
+ default: result.append("UNKNOWN\n");
+ }
+
+ result.append(" Flash mode: ");
+ switch (mParameters.flashMode) {
+ CASE_APPEND_ENUM(Parameters::FLASH_MODE_OFF)
+ CASE_APPEND_ENUM(Parameters::FLASH_MODE_AUTO)
+ CASE_APPEND_ENUM(Parameters::FLASH_MODE_ON)
+ CASE_APPEND_ENUM(Parameters::FLASH_MODE_TORCH)
+ CASE_APPEND_ENUM(Parameters::FLASH_MODE_RED_EYE)
+ CASE_APPEND_ENUM(Parameters::FLASH_MODE_INVALID)
+ default: result.append("UNKNOWN\n");
+ }
+
+ result.append(" Focus mode: ");
+ switch (mParameters.focusMode) {
+ CASE_APPEND_ENUM(Parameters::FOCUS_MODE_AUTO)
+ CASE_APPEND_ENUM(Parameters::FOCUS_MODE_MACRO)
+ CASE_APPEND_ENUM(Parameters::FOCUS_MODE_CONTINUOUS_VIDEO)
+ CASE_APPEND_ENUM(Parameters::FOCUS_MODE_CONTINUOUS_PICTURE)
+ CASE_APPEND_ENUM(Parameters::FOCUS_MODE_EDOF)
+ CASE_APPEND_ENUM(Parameters::FOCUS_MODE_INFINITY)
+ CASE_APPEND_ENUM(Parameters::FOCUS_MODE_FIXED)
+ CASE_APPEND_ENUM(Parameters::FOCUS_MODE_INVALID)
+ default: result.append("UNKNOWN\n");
+ }
+
+ result.append(" Focusing areas:\n");
+ for (size_t i = 0; i < mParameters.focusingAreas.size(); i++) {
+ result.appendFormat(" [ (%d, %d, %d, %d), weight %d ]\n",
+ mParameters.focusingAreas[i].left,
+ mParameters.focusingAreas[i].top,
+ mParameters.focusingAreas[i].right,
+ mParameters.focusingAreas[i].bottom,
+ mParameters.focusingAreas[i].weight);
+ }
+
+ result.appendFormat(" Exposure compensation index: %d\n",
+ mParameters.exposureCompensation);
+
+ result.appendFormat(" AE lock %s, AWB lock %s\n",
+ mParameters.autoExposureLock ? "enabled" : "disabled",
+ mParameters.autoWhiteBalanceLock ? "enabled" : "disabled" );
+
+ result.appendFormat(" Metering areas:\n");
+ for (size_t i = 0; i < mParameters.meteringAreas.size(); i++) {
+ result.appendFormat(" [ (%d, %d, %d, %d), weight %d ]\n",
+ mParameters.meteringAreas[i].left,
+ mParameters.meteringAreas[i].top,
+ mParameters.meteringAreas[i].right,
+ mParameters.meteringAreas[i].bottom,
+ mParameters.meteringAreas[i].weight);
+ }
+
+ result.appendFormat(" Zoom index: %d\n", mParameters.zoom);
+ result.appendFormat(" Video size: %d x %d\n", mParameters.videoWidth,
+ mParameters.videoHeight);
+
+ result.appendFormat(" Recording hint is %s\n",
+ mParameters.recordingHint ? "set" : "not set");
+
+ result.appendFormat(" Video stabilization is %s\n",
+ mParameters.videoStabilization ? "enabled" : "disabled");
+
+ result.append(" Current streams:\n");
+ result.appendFormat(" Preview stream ID: %d\n", mPreviewStreamId);
+ result.appendFormat(" Capture stream ID: %d\n", mCaptureStreamId);
+
+ result.append(" Current requests:\n");
+ if (mPreviewRequest != NULL) {
+ result.append(" Preview request:\n");
+ write(fd, result.string(), result.size());
+ dump_camera_metadata(mPreviewRequest, fd, 2);
+ } else {
+ result.append(" Preview request: undefined\n");
+ write(fd, result.string(), result.size());
+ }
+
+ if (mCaptureRequest != NULL) {
+ result = " Capture request:\n";
+ write(fd, result.string(), result.size());
+ dump_camera_metadata(mCaptureRequest, fd, 2);
+ } else {
+ result = " Capture request: undefined\n";
+ write(fd, result.string(), result.size());
+ }
+
+ result = " Device dump:\n";
+ write(fd, result.string(), result.size());
+
+ status_t res = mDevice->dump(fd, args);
+ if (res != OK) {
+ result = String8::format(" Error dumping device: %s (%d)",
+ strerror(-res), res);
+ write(fd, result.string(), result.size());
+ }
+
+#undef CASE_APPEND_ENUM
+ return NO_ERROR;
+}
+
+const char* Camera2Client::getStateName(State state) {
+#define CASE_ENUM_TO_CHAR(x) case x: return(#x); break;
+ switch(state) {
+ CASE_ENUM_TO_CHAR(NOT_INITIALIZED)
+ CASE_ENUM_TO_CHAR(STOPPED)
+ CASE_ENUM_TO_CHAR(WAITING_FOR_PREVIEW_WINDOW)
+ CASE_ENUM_TO_CHAR(PREVIEW)
+ CASE_ENUM_TO_CHAR(RECORD)
+ CASE_ENUM_TO_CHAR(STILL_CAPTURE)
+ CASE_ENUM_TO_CHAR(VIDEO_SNAPSHOT)
+ default:
+ return "Unknown state!";
+ break;
+ }
+#undef CASE_ENUM_TO_CHAR
+}
+
+// ICamera interface
+
+void Camera2Client::disconnect() {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+
+ if (mDevice == 0) return;
+
+ stopPreviewLocked();
+
+ mDevice->waitUntilDrained();
+
+ if (mPreviewStreamId != NO_STREAM) {
+ mDevice->deleteStream(mPreviewStreamId);
+ mPreviewStreamId = NO_STREAM;
+ }
+
+ if (mCaptureStreamId != NO_STREAM) {
+ mDevice->deleteStream(mCaptureStreamId);
+ mCaptureStreamId = NO_STREAM;
+ }
+
+ CameraService::Client::disconnect();
+}
+
+status_t Camera2Client::connect(const sp<ICameraClient>& client) {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+
+ return BAD_VALUE;
+}
+
+status_t Camera2Client::lock() {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+
+ return BAD_VALUE;
+}
+
+status_t Camera2Client::unlock() {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+
+ return BAD_VALUE;
+}
+
+status_t Camera2Client::setPreviewDisplay(
+ const sp<Surface>& surface) {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+
+ if (mState >= PREVIEW) return INVALID_OPERATION;
+
+ sp<IBinder> binder;
+ sp<ANativeWindow> window;
+ if (surface != 0) {
+ binder = surface->asBinder();
+ window = surface;
+ }
+
+ return setPreviewWindowLocked(binder,window);
+}
+
+status_t Camera2Client::setPreviewTexture(
+ const sp<ISurfaceTexture>& surfaceTexture) {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+
+ if (mState >= PREVIEW) return INVALID_OPERATION;
+
+ sp<IBinder> binder;
+ sp<ANativeWindow> window;
+ if (surfaceTexture != 0) {
+ binder = surfaceTexture->asBinder();
+ window = new SurfaceTextureClient(surfaceTexture);
+ }
+ return setPreviewWindowLocked(binder, window);
+}
+
+status_t Camera2Client::setPreviewWindowLocked(const sp<IBinder>& binder,
+ sp<ANativeWindow> window) {
+ ATRACE_CALL();
+ status_t res;
+
+ if (binder == mPreviewSurface) {
+ return NO_ERROR;
+ }
+
+ if (mPreviewStreamId != NO_STREAM) {
+ res = mDevice->waitUntilDrained();
+ if (res != OK) {
+ ALOGE("%s: Error waiting for preview to drain: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+ res = mDevice->deleteStream(mPreviewStreamId);
+ if (res != OK) {
+ ALOGE("%s: Unable to delete old preview stream: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+ mPreviewStreamId = NO_STREAM;
+ }
+
+ mPreviewSurface = binder;
+ mPreviewWindow = window;
+
+ if (mState == WAITING_FOR_PREVIEW_WINDOW) {
+ return startPreviewLocked();
+ }
+
+ return OK;
+}
+
+void Camera2Client::setPreviewCallbackFlag(int flag) {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+}
+
+status_t Camera2Client::startPreview() {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+ return startPreviewLocked();
+}
+
+status_t Camera2Client::startPreviewLocked() {
+ ATRACE_CALL();
+ status_t res;
+ if (mState >= PREVIEW) {
+ ALOGE("%s: Can't start preview in state %s",
+ __FUNCTION__, getStateName(mState));
+ return INVALID_OPERATION;
+ }
+
+ if (mPreviewWindow == 0) {
+ mState = WAITING_FOR_PREVIEW_WINDOW;
+ return OK;
+ }
+ mState = STOPPED;
+
+ res = updatePreviewStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update preview stream: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+
+ if (mPreviewRequest == NULL) {
+ res = updatePreviewRequest();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to create preview request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ }
+
+ res = updateEntry(mPreviewRequest,
+ ANDROID_REQUEST_OUTPUT_STREAMS,
+ &mPreviewStreamId, 1);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to set up preview request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ res = sort_camera_metadata(mPreviewRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error sorting preview request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+
+ res = mDevice->setStreamingRequest(mPreviewRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to set preview request to start preview: "
+ "%s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ mState = PREVIEW;
+
+ return OK;
+}
+
+void Camera2Client::stopPreview() {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+ stopPreviewLocked();
+}
+
+void Camera2Client::stopPreviewLocked() {
+ ATRACE_CALL();
+ switch (mState) {
+ case NOT_INITIALIZED:
+ ALOGE("%s: Camera %d: Call before initialized",
+ __FUNCTION__, mCameraId);
+ break;
+ case STOPPED:
+ break;
+ case STILL_CAPTURE:
+ ALOGE("%s: Camera %d: Cannot stop preview during still capture.",
+ __FUNCTION__, mCameraId);
+ break;
+ case RECORD:
+ // TODO: Handle record stop here
+ case PREVIEW:
+ mDevice->setStreamingRequest(NULL);
+ case WAITING_FOR_PREVIEW_WINDOW:
+ mState = STOPPED;
+ break;
+ default:
+ ALOGE("%s: Camera %d: Unknown state %d", __FUNCTION__, mCameraId,
+ mState);
+ }
+}
+
+bool Camera2Client::previewEnabled() {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+ return mState == PREVIEW;
+}
+
+status_t Camera2Client::storeMetaDataInBuffers(bool enabled) {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+ return BAD_VALUE;
+}
+
+status_t Camera2Client::startRecording() {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+ return BAD_VALUE;
+}
+
+void Camera2Client::stopRecording() {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+}
+
+bool Camera2Client::recordingEnabled() {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+ return BAD_VALUE;
+}
+
+void Camera2Client::releaseRecordingFrame(const sp<IMemory>& mem) {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+}
+
+status_t Camera2Client::autoFocus() {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+ return OK;
+}
+
+status_t Camera2Client::cancelAutoFocus() {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+ return OK;
+}
+
+status_t Camera2Client::takePicture(int msgType) {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+ status_t res;
+
+ switch (mState) {
+ case NOT_INITIALIZED:
+ case STOPPED:
+ case WAITING_FOR_PREVIEW_WINDOW:
+ ALOGE("%s: Camera %d: Cannot take picture without preview enabled",
+ __FUNCTION__, mCameraId);
+ return INVALID_OPERATION;
+ case PREVIEW:
+ case RECORD:
+ // Good to go for takePicture
+ break;
+ case STILL_CAPTURE:
+ case VIDEO_SNAPSHOT:
+ ALOGE("%s: Camera %d: Already taking a picture",
+ __FUNCTION__, mCameraId);
+ return INVALID_OPERATION;
+ }
+
+ Mutex::Autolock pl(mParamsLock);
+
+ res = updateCaptureStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't set up still image stream: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+
+ if (mCaptureRequest == NULL) {
+ res = updateCaptureRequest();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't create still image capture request: "
+ "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ }
+
+ // TODO: For video snapshot, will need 3 streams here
+ camera_metadata_entry_t outputStreams;
+ uint8_t streamIds[2] = { mPreviewStreamId, mCaptureStreamId };
+ res = updateEntry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS,
+ &streamIds, 2);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to set up still image capture request: "
+ "%s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ res = sort_camera_metadata(mCaptureRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to sort capture request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+
+ camera_metadata_t *captureCopy = clone_camera_metadata(mCaptureRequest);
+ if (captureCopy == NULL) {
+ ALOGE("%s: Camera %d: Unable to copy capture request for HAL device",
+ __FUNCTION__, mCameraId);
+ return NO_MEMORY;
+ }
+
+ if (mState == PREVIEW) {
+ res = mDevice->setStreamingRequest(NULL);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to stop preview for still capture: "
+ "%s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ }
+
+ res = mDevice->capture(captureCopy);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to submit still image capture request: "
+ "%s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+
+ switch (mState) {
+ case PREVIEW:
+ mState = STILL_CAPTURE;
+ break;
+ case RECORD:
+ mState = VIDEO_SNAPSHOT;
+ break;
+ default:
+ ALOGE("%s: Camera %d: Unknown state for still capture!",
+ __FUNCTION__, mCameraId);
+ return INVALID_OPERATION;
+ }
+
+ return OK;
+}
+
+status_t Camera2Client::setParameters(const String8& params) {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+ Mutex::Autolock pl(mParamsLock);
+ status_t res;
+
+ CameraParameters newParams(params);
+
+ // TODO: Currently ignoring any changes to supposedly read-only
+ // parameters such as supported preview sizes, etc. Should probably
+ // produce an error if they're changed.
+
+ /** Extract and verify new parameters */
+
+ size_t i;
+
+ // PREVIEW_SIZE
+ int previewWidth, previewHeight;
+ newParams.getPreviewSize(&previewWidth, &previewHeight);
+
+ if (previewWidth != mParameters.previewWidth ||
+ previewHeight != mParameters.previewHeight) {
+ if (mState >= PREVIEW) {
+ ALOGE("%s: Preview size cannot be updated when preview "
+ "is active!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ camera_metadata_entry_t availablePreviewSizes =
+ staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES);
+ for (i = 0; i < availablePreviewSizes.count; i += 2 ) {
+ if (availablePreviewSizes.data.i32[i] == previewWidth &&
+ availablePreviewSizes.data.i32[i+1] == previewHeight) break;
+ }
+ if (i == availablePreviewSizes.count) {
+ ALOGE("%s: Requested preview size %d x %d is not supported",
+ __FUNCTION__, previewWidth, previewHeight);
+ return BAD_VALUE;
+ }
+ }
+
+ // PREVIEW_FPS_RANGE
+ int previewFpsRange[2];
+ int previewFps = 0;
+ bool fpsRangeChanged = false;
+ newParams.getPreviewFpsRange(&previewFpsRange[0], &previewFpsRange[1]);
+ if (previewFpsRange[0] != mParameters.previewFpsRange[0] ||
+ previewFpsRange[1] != mParameters.previewFpsRange[1]) {
+ fpsRangeChanged = true;
+ camera_metadata_entry_t availablePreviewFpsRanges =
+ staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2);
+ for (i = 0; i < availablePreviewFpsRanges.count; i += 2) {
+ if ((availablePreviewFpsRanges.data.i32[i] ==
+ previewFpsRange[0]) &&
+ (availablePreviewFpsRanges.data.i32[i+1] ==
+ previewFpsRange[1]) ) {
+ break;
+ }
+ }
+ if (i == availablePreviewFpsRanges.count) {
+ ALOGE("%s: Requested preview FPS range %d - %d is not supported",
+ __FUNCTION__, previewFpsRange[0], previewFpsRange[1]);
+ return BAD_VALUE;
+ }
+ previewFps = previewFpsRange[0];
+ }
+
+ // PREVIEW_FORMAT
+ int previewFormat = formatStringToEnum(newParams.getPreviewFormat());
+ if (previewFormat != mParameters.previewFormat) {
+ if (mState >= PREVIEW) {
+ ALOGE("%s: Preview format cannot be updated when preview "
+ "is active!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ camera_metadata_entry_t availableFormats =
+ staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS);
+ for (i = 0; i < availableFormats.count; i++) {
+ if (availableFormats.data.i32[i] == previewFormat) break;
+ }
+ if (i == availableFormats.count) {
+ ALOGE("%s: Requested preview format %s (0x%x) is not supported",
+ __FUNCTION__, newParams.getPreviewFormat(), previewFormat);
+ return BAD_VALUE;
+ }
+ }
+
+ // PREVIEW_FRAME_RATE
+ // Deprecated, only use if the preview fps range is unchanged this time.
+ // The single-value FPS is the same as the minimum of the range.
+ if (!fpsRangeChanged) {
+ previewFps = newParams.getPreviewFrameRate();
+ if (previewFps != mParameters.previewFps) {
+ camera_metadata_entry_t availableFrameRates =
+ staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
+ for (i = 0; i < availableFrameRates.count; i+=2) {
+ if (availableFrameRates.data.i32[i] == previewFps) break;
+ }
+ if (i == availableFrameRates.count) {
+ ALOGE("%s: Requested preview frame rate %d is not supported",
+ __FUNCTION__, previewFps);
+ return BAD_VALUE;
+ }
+ previewFpsRange[0] = availableFrameRates.data.i32[i];
+ previewFpsRange[1] = availableFrameRates.data.i32[i+1];
+ }
+ }
+
+ // PICTURE_SIZE
+ int pictureWidth, pictureHeight;
+ newParams.getPictureSize(&pictureWidth, &pictureHeight);
+ if (pictureWidth == mParameters.pictureWidth ||
+ pictureHeight == mParameters.pictureHeight) {
+ camera_metadata_entry_t availablePictureSizes =
+ staticInfo(ANDROID_SCALER_AVAILABLE_JPEG_SIZES);
+ for (i = 0; i < availablePictureSizes.count; i+=2) {
+ if (availablePictureSizes.data.i32[i] == pictureWidth &&
+ availablePictureSizes.data.i32[i+1] == pictureHeight) break;
+ }
+ if (i == availablePictureSizes.count) {
+ ALOGE("%s: Requested picture size %d x %d is not supported",
+ __FUNCTION__, pictureWidth, pictureHeight);
+ return BAD_VALUE;
+ }
+ }
+
+ // JPEG_THUMBNAIL_WIDTH/HEIGHT
+ int jpegThumbSize[2];
+ jpegThumbSize[0] =
+ newParams.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH);
+ jpegThumbSize[1] =
+ newParams.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT);
+ if (jpegThumbSize[0] != mParameters.jpegThumbSize[0] ||
+ jpegThumbSize[1] != mParameters.jpegThumbSize[1]) {
+ camera_metadata_entry_t availableJpegThumbSizes =
+ staticInfo(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+ for (i = 0; i < availableJpegThumbSizes.count; i+=2) {
+ if (availableJpegThumbSizes.data.i32[i] == jpegThumbSize[0] &&
+ availableJpegThumbSizes.data.i32[i+1] == jpegThumbSize[1]) {
+ break;
+ }
+ }
+ if (i == availableJpegThumbSizes.count) {
+ ALOGE("%s: Requested JPEG thumbnail size %d x %d is not supported",
+ __FUNCTION__, jpegThumbSize[0], jpegThumbSize[1]);
+ return BAD_VALUE;
+ }
+ }
+
+ // JPEG_THUMBNAIL_QUALITY
+ int jpegThumbQuality =
+ newParams.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY);
+ if (jpegThumbQuality < 0 || jpegThumbQuality > 100) {
+ ALOGE("%s: Requested JPEG thumbnail quality %d is not supported",
+ __FUNCTION__, jpegThumbQuality);
+ return BAD_VALUE;
+ }
+
+ // JPEG_QUALITY
+ int jpegQuality =
+ newParams.getInt(CameraParameters::KEY_JPEG_QUALITY);
+ if (jpegQuality < 0 || jpegQuality > 100) {
+ ALOGE("%s: Requested JPEG quality %d is not supported",
+ __FUNCTION__, jpegQuality);
+ return BAD_VALUE;
+ }
+
+ // ROTATION
+ int jpegRotation =
+ newParams.getInt(CameraParameters::KEY_ROTATION);
+ if (jpegRotation != 0 &&
+ jpegRotation != 90 &&
+ jpegRotation != 180 &&
+ jpegRotation != 270) {
+ ALOGE("%s: Requested picture rotation angle %d is not supported",
+ __FUNCTION__, jpegRotation);
+ return BAD_VALUE;
+ }
+
+ // GPS
+ bool gpsEnabled = false;
+ double gpsCoordinates[3] = {0,0,0};
+ int64_t gpsTimestamp = 0;
+ String8 gpsProcessingMethod;
+ const char *gpsLatStr =
+ newParams.get(CameraParameters::KEY_GPS_LATITUDE);
+ if (gpsLatStr != NULL) {
+ const char *gpsLongStr =
+ newParams.get(CameraParameters::KEY_GPS_LONGITUDE);
+ const char *gpsAltitudeStr =
+ newParams.get(CameraParameters::KEY_GPS_ALTITUDE);
+ const char *gpsTimeStr =
+ newParams.get(CameraParameters::KEY_GPS_TIMESTAMP);
+ const char *gpsProcMethodStr =
+ newParams.get(CameraParameters::KEY_GPS_PROCESSING_METHOD);
+ if (gpsLongStr == NULL ||
+ gpsAltitudeStr == NULL ||
+ gpsTimeStr == NULL ||
+ gpsProcMethodStr == NULL) {
+ ALOGE("%s: Incomplete set of GPS parameters provided",
+ __FUNCTION__);
+ return BAD_VALUE;
+ }
+ char *endPtr;
+ errno = 0;
+ gpsCoordinates[0] = strtod(gpsLatStr, &endPtr);
+ if (errno || endPtr == gpsLatStr) {
+ ALOGE("%s: Malformed GPS latitude: %s", __FUNCTION__, gpsLatStr);
+ return BAD_VALUE;
+ }
+ errno = 0;
+ gpsCoordinates[1] = strtod(gpsLongStr, &endPtr);
+ if (errno || endPtr == gpsLongStr) {
+ ALOGE("%s: Malformed GPS longitude: %s", __FUNCTION__, gpsLongStr);
+ return BAD_VALUE;
+ }
+ errno = 0;
+ gpsCoordinates[2] = strtod(gpsAltitudeStr, &endPtr);
+ if (errno || endPtr == gpsAltitudeStr) {
+ ALOGE("%s: Malformed GPS altitude: %s", __FUNCTION__,
+ gpsAltitudeStr);
+ return BAD_VALUE;
+ }
+ errno = 0;
+ gpsTimestamp = strtoll(gpsTimeStr, &endPtr, 10);
+ if (errno || endPtr == gpsTimeStr) {
+ ALOGE("%s: Malformed GPS timestamp: %s", __FUNCTION__, gpsTimeStr);
+ return BAD_VALUE;
+ }
+ gpsProcessingMethod = gpsProcMethodStr;
+
+ gpsEnabled = true;
+ }
+
+ // WHITE_BALANCE
+ int wbMode = wbModeStringToEnum(
+ newParams.get(CameraParameters::KEY_WHITE_BALANCE) );
+ if (wbMode != mParameters.wbMode) {
+ camera_metadata_entry_t availableWbModes =
+ staticInfo(ANDROID_CONTROL_AWB_AVAILABLE_MODES);
+ for (i = 0; i < availableWbModes.count; i++) {
+ if (wbMode == availableWbModes.data.u8[i]) break;
+ }
+ if (i == availableWbModes.count) {
+ ALOGE("%s: Requested white balance mode %s is not supported",
+ __FUNCTION__,
+ newParams.get(CameraParameters::KEY_WHITE_BALANCE));
+ return BAD_VALUE;
+ }
+ }
+
+ // EFFECT
+ int effectMode = effectModeStringToEnum(
+ newParams.get(CameraParameters::KEY_EFFECT) );
+ if (effectMode != mParameters.effectMode) {
+ camera_metadata_entry_t availableEffectModes =
+ staticInfo(ANDROID_CONTROL_AVAILABLE_EFFECTS);
+ for (i = 0; i < availableEffectModes.count; i++) {
+ if (effectMode == availableEffectModes.data.u8[i]) break;
+ }
+ if (i == availableEffectModes.count) {
+ ALOGE("%s: Requested effect mode \"%s\" is not supported",
+ __FUNCTION__,
+ newParams.get(CameraParameters::KEY_EFFECT) );
+ return BAD_VALUE;
+ }
+ }
+
+ // ANTIBANDING
+ int antibandingMode = abModeStringToEnum(
+ newParams.get(CameraParameters::KEY_ANTIBANDING) );
+ if (antibandingMode != mParameters.antibandingMode) {
+ camera_metadata_entry_t availableAbModes =
+ staticInfo(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES);
+ for (i = 0; i < availableAbModes.count; i++) {
+ if (antibandingMode == availableAbModes.data.u8[i]) break;
+ }
+ if (i == availableAbModes.count) {
+ ALOGE("%s: Requested antibanding mode \"%s\" is not supported",
+ __FUNCTION__,
+ newParams.get(CameraParameters::KEY_ANTIBANDING));
+ return BAD_VALUE;
+ }
+ }
+
+ // SCENE_MODE
+ int sceneMode = sceneModeStringToEnum(
+ newParams.get(CameraParameters::KEY_SCENE_MODE) );
+ if (sceneMode != mParameters.sceneMode) {
+ camera_metadata_entry_t availableSceneModes =
+ staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
+ for (i = 0; i < availableSceneModes.count; i++) {
+ if (sceneMode == availableSceneModes.data.u8[i]) break;
+ }
+ if (i == availableSceneModes.count) {
+ ALOGE("%s: Requested scene mode \"%s\" is not supported",
+ __FUNCTION__,
+ newParams.get(CameraParameters::KEY_SCENE_MODE));
+ return BAD_VALUE;
+ }
+ }
+
+ // FLASH_MODE
+ Parameters::flashMode_t flashMode = flashModeStringToEnum(
+ newParams.get(CameraParameters::KEY_FLASH_MODE) );
+ if (flashMode != mParameters.flashMode) {
+ camera_metadata_entry_t flashAvailable =
+ staticInfo(ANDROID_FLASH_AVAILABLE, 1, 1);
+ if (!flashAvailable.data.u8[0] &&
+ flashMode != Parameters::FLASH_MODE_OFF) {
+ ALOGE("%s: Requested flash mode \"%s\" is not supported: "
+ "No flash on device", __FUNCTION__,
+ newParams.get(CameraParameters::KEY_FLASH_MODE));
+ return BAD_VALUE;
+ } else if (flashMode == Parameters::FLASH_MODE_RED_EYE) {
+ camera_metadata_entry_t availableAeModes =
+ staticInfo(ANDROID_CONTROL_AE_AVAILABLE_MODES);
+ for (i = 0; i < availableAeModes.count; i++) {
+ if (flashMode == availableAeModes.data.u8[i]) break;
+ }
+ if (i == availableAeModes.count) {
+ ALOGE("%s: Requested flash mode \"%s\" is not supported",
+ __FUNCTION__,
+ newParams.get(CameraParameters::KEY_FLASH_MODE));
+ return BAD_VALUE;
+ }
+ } else if (flashMode == -1) {
+ ALOGE("%s: Requested flash mode \"%s\" is unknown",
+ __FUNCTION__,
+ newParams.get(CameraParameters::KEY_FLASH_MODE));
+ return BAD_VALUE;
+ }
+ }
+
+ // FOCUS_MODE
+ Parameters::focusMode_t focusMode = focusModeStringToEnum(
+ newParams.get(CameraParameters::KEY_FOCUS_MODE));
+ if (focusMode != mParameters.focusMode) {
+ if (focusMode != Parameters::FOCUS_MODE_FIXED) {
+ camera_metadata_entry_t minFocusDistance =
+ staticInfo(ANDROID_LENS_MINIMUM_FOCUS_DISTANCE);
+ if (minFocusDistance.data.f[0] == 0) {
+ ALOGE("%s: Requested focus mode \"%s\" is not available: "
+ "fixed focus lens",
+ __FUNCTION__,
+ newParams.get(CameraParameters::KEY_FOCUS_MODE));
+ return BAD_VALUE;
+ } else if (focusMode != Parameters::FOCUS_MODE_INFINITY) {
+ camera_metadata_entry_t availableFocusModes =
+ staticInfo(ANDROID_CONTROL_AF_AVAILABLE_MODES);
+ for (i = 0; i < availableFocusModes.count; i++) {
+ if (focusMode == availableFocusModes.data.u8[i]) break;
+ }
+ if (i == availableFocusModes.count) {
+ ALOGE("%s: Requested focus mode \"%s\" is not supported",
+ __FUNCTION__,
+ newParams.get(CameraParameters::KEY_FOCUS_MODE));
+ return BAD_VALUE;
+ }
+ }
+ }
+ }
+
+ // FOCUS_AREAS
+ Vector<Parameters::Area> focusingAreas;
+ res = parseAreas(newParams.get(CameraParameters::KEY_FOCUS_AREAS),
+ &focusingAreas);
+ size_t max3aRegions =
+ (size_t)staticInfo(ANDROID_CONTROL_MAX_REGIONS, 1, 1).data.i32[0];
+ if (res == OK) res = validateAreas(focusingAreas, max3aRegions);
+ if (res != OK) {
+ ALOGE("%s: Requested focus areas are malformed: %s",
+ __FUNCTION__, newParams.get(CameraParameters::KEY_FOCUS_AREAS));
+ return BAD_VALUE;
+ }
+
+ // EXPOSURE_COMPENSATION
+ int exposureCompensation =
+ newParams.getInt(CameraParameters::KEY_EXPOSURE_COMPENSATION);
+ camera_metadata_entry_t exposureCompensationRange =
+ staticInfo(ANDROID_CONTROL_AE_EXP_COMPENSATION_RANGE);
+ if (exposureCompensation < exposureCompensationRange.data.i32[0] ||
+ exposureCompensation > exposureCompensationRange.data.i32[1]) {
+ ALOGE("%s: Requested exposure compensation index is out of bounds: %d",
+ __FUNCTION__, exposureCompensation);
+ return BAD_VALUE;
+ }
+
+ // AUTO_EXPOSURE_LOCK (always supported)
+ bool autoExposureLock = boolFromString(
+ newParams.get(CameraParameters::KEY_AUTO_EXPOSURE_LOCK));
+
+ // AUTO_WHITEBALANCE_LOCK (always supported)
+ bool autoWhiteBalanceLock = boolFromString(
+ newParams.get(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK));
+
+ // METERING_AREAS
+ Vector<Parameters::Area> meteringAreas;
+ res = parseAreas(newParams.get(CameraParameters::KEY_METERING_AREAS),
+ &meteringAreas);
+ if (res == OK) res = validateAreas(focusingAreas, max3aRegions);
+ if (res != OK) {
+ ALOGE("%s: Requested metering areas are malformed: %s",
+ __FUNCTION__,
+ newParams.get(CameraParameters::KEY_METERING_AREAS));
+ return BAD_VALUE;
+ }
+
+ // ZOOM
+ int zoom = newParams.getInt(CameraParameters::KEY_ZOOM);
+ if (zoom < 0 || zoom > (int)NUM_ZOOM_STEPS) {
+ ALOGE("%s: Requested zoom level %d is not supported",
+ __FUNCTION__, zoom);
+ return BAD_VALUE;
+ }
+
+ // VIDEO_SIZE
+ int videoWidth, videoHeight;
+ newParams.getVideoSize(&videoWidth, &videoHeight);
+ if (videoWidth != mParameters.videoWidth ||
+ videoHeight != mParameters.videoHeight) {
+ if (mState == RECORD) {
+ ALOGE("%s: Video size cannot be updated when recording is active!",
+ __FUNCTION__);
+ return BAD_VALUE;
+ }
+ camera_metadata_entry_t availableVideoSizes =
+ staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES);
+ for (i = 0; i < availableVideoSizes.count; i += 2 ) {
+ if (availableVideoSizes.data.i32[i] == videoWidth &&
+ availableVideoSizes.data.i32[i+1] == videoHeight) break;
+ }
+ if (i == availableVideoSizes.count) {
+ ALOGE("%s: Requested video size %d x %d is not supported",
+ __FUNCTION__, videoWidth, videoHeight);
+ return BAD_VALUE;
+ }
+ }
+
+ // RECORDING_HINT (always supported)
+ bool recordingHint = boolFromString(
+ newParams.get(CameraParameters::KEY_RECORDING_HINT) );
+
+ // VIDEO_STABILIZATION
+ bool videoStabilization = boolFromString(
+ newParams.get(CameraParameters::KEY_VIDEO_STABILIZATION) );
+ camera_metadata_entry_t availableVideoStabilizationModes =
+ staticInfo(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES);
+ if (videoStabilization && availableVideoStabilizationModes.count == 1) {
+ ALOGE("%s: Video stabilization not supported", __FUNCTION__);
+ }
+
+ /** Update internal parameters */
+ mParameters.previewWidth = previewWidth;
+ mParameters.previewHeight = previewHeight;
+ mParameters.previewFpsRange[0] = previewFpsRange[0];
+ mParameters.previewFpsRange[1] = previewFpsRange[1];
+ mParameters.previewFps = previewFps;
+ mParameters.previewFormat = previewFormat;
+
+ mParameters.pictureWidth = pictureWidth;
+ mParameters.pictureHeight = pictureHeight;
+
+ mParameters.jpegThumbSize[0] = jpegThumbSize[0];
+ mParameters.jpegThumbSize[1] = jpegThumbSize[1];
+ mParameters.jpegQuality = jpegQuality;
+ mParameters.jpegThumbQuality = jpegThumbQuality;
+
+ mParameters.gpsEnabled = gpsEnabled;
+ mParameters.gpsCoordinates[0] = gpsCoordinates[0];
+ mParameters.gpsCoordinates[1] = gpsCoordinates[1];
+ mParameters.gpsCoordinates[2] = gpsCoordinates[2];
+ mParameters.gpsTimestamp = gpsTimestamp;
+ mParameters.gpsProcessingMethod = gpsProcessingMethod;
+
+ mParameters.wbMode = wbMode;
+ mParameters.effectMode = effectMode;
+ mParameters.antibandingMode = antibandingMode;
+ mParameters.sceneMode = sceneMode;
+
+ mParameters.flashMode = flashMode;
+ mParameters.focusMode = focusMode;
+
+ mParameters.focusingAreas = focusingAreas;
+ mParameters.exposureCompensation = exposureCompensation;
+ mParameters.autoExposureLock = autoExposureLock;
+ mParameters.autoWhiteBalanceLock = autoWhiteBalanceLock;
+ mParameters.meteringAreas = meteringAreas;
+ mParameters.zoom = zoom;
+
+ mParameters.videoWidth = videoWidth;
+ mParameters.videoHeight = videoHeight;
+
+ mParameters.recordingHint = recordingHint;
+ mParameters.videoStabilization = videoStabilization;
+
+ res = updatePreviewRequest();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update preview request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ res = updateCaptureRequest();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update capture request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+
+ if (mState == PREVIEW) {
+ res = mDevice->setStreamingRequest(mPreviewRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error streaming new preview request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ }
+
+ return OK;
+}
+
+String8 Camera2Client::getParameters() const {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+
+ Mutex::Autolock pl(mParamsLock);
+
+ // TODO: Deal with focus distances
+ return mParamsFlattened;
+}
+
+status_t Camera2Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
+ ATRACE_CALL();
+ Mutex::Autolock icl(mICameraLock);
+
+ ALOGV("%s: Camera %d: Command %d (%d, %d)", __FUNCTION__, mCameraId,
+ cmd, arg1, arg2);
+
+ if (cmd == CAMERA_CMD_SET_DISPLAY_ORIENTATION) {
+ int transform = degToTransform(arg1,
+ mCameraFacing == CAMERA_FACING_FRONT);
+ if (transform == -1) {
+ ALOGE("%s: Camera %d: Error setting %d as display orientation value",
+ __FUNCTION__, mCameraId, arg1);
+ return BAD_VALUE;
+ }
+ if (transform != mParameters.previewTransform &&
+ mPreviewStreamId != NO_STREAM) {
+ mDevice->setStreamTransform(mPreviewStreamId, transform);
+ }
+ mParameters.previewTransform = transform;
+ return OK;
+ }
+
+ ALOGE("%s: Camera %d: Unimplemented command %d (%d, %d)", __FUNCTION__,
+ mCameraId, cmd, arg1, arg2);
+
+ return OK;
+}
+
+/** Device-related methods */
+
+void Camera2Client::onCaptureAvailable() {
+ ATRACE_CALL();
+ status_t res;
+ sp<ICameraClient> currentClient;
+ CpuConsumer::LockedBuffer imgBuffer;
+ {
+ Mutex::Autolock icl(mICameraLock);
+
+ // TODO: Signal errors here upstream
+ if (mState != STILL_CAPTURE && mState != VIDEO_SNAPSHOT) {
+ ALOGE("%s: Camera %d: Still image produced unexpectedly!",
+ __FUNCTION__, mCameraId);
+ return;
+ }
+
+ res = mCaptureConsumer->lockNextBuffer(&imgBuffer);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error receiving still image buffer: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return;
+ }
+
+ if (imgBuffer.format != HAL_PIXEL_FORMAT_BLOB) {
+ ALOGE("%s: Camera %d: Unexpected format for still image: "
+ "%x, expected %x", __FUNCTION__, mCameraId,
+ imgBuffer.format,
+ HAL_PIXEL_FORMAT_BLOB);
+ mCaptureConsumer->unlockBuffer(imgBuffer);
+ return;
+ }
+
+ // TODO: Optimize this to avoid memcopy
+ void* captureMemory = mCaptureHeap->getBase();
+ size_t size = mCaptureHeap->getSize();
+ memcpy(captureMemory, imgBuffer.data, size);
+
+ mCaptureConsumer->unlockBuffer(imgBuffer);
+
+ currentClient = mCameraClient;
+ switch (mState) {
+ case STILL_CAPTURE:
+ mState = STOPPED;
+ break;
+ case VIDEO_SNAPSHOT:
+ mState = RECORD;
+ break;
+ default:
+ ALOGE("%s: Camera %d: Unexpected state %d", __FUNCTION__,
+ mCameraId, mState);
+ break;
+ }
+ }
+ // Call outside mICameraLock to allow re-entrancy from notification
+ if (currentClient != 0) {
+ currentClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE,
+ mCaptureMemory, NULL);
+ }
+}
+
+camera_metadata_entry_t Camera2Client::staticInfo(uint32_t tag,
+ size_t minCount, size_t maxCount) {
+ status_t res;
+ camera_metadata_entry_t entry;
+ res = find_camera_metadata_entry(mDevice->info(),
+ tag,
+ &entry);
+ if (CC_UNLIKELY( res != OK )) {
+ const char* tagSection = get_camera_metadata_section_name(tag);
+ if (tagSection == NULL) tagSection = "<unknown>";
+ const char* tagName = get_camera_metadata_tag_name(tag);
+ if (tagName == NULL) tagName = "<unknown>";
+
+ ALOGE("Error finding static metadata entry '%s.%s' (%x): %s (%d)",
+ tagSection, tagName, tag, strerror(-res), res);
+ entry.count = 0;
+ entry.data.u8 = NULL;
+ } else if (CC_UNLIKELY(
+ (minCount != 0 && entry.count < minCount) ||
+ (maxCount != 0 && entry.count > maxCount) ) ) {
+ const char* tagSection = get_camera_metadata_section_name(tag);
+ if (tagSection == NULL) tagSection = "<unknown>";
+ const char* tagName = get_camera_metadata_tag_name(tag);
+ if (tagName == NULL) tagName = "<unknown>";
+ ALOGE("Malformed static metadata entry '%s.%s' (%x):"
+ "Expected between %d and %d values, but got %d values",
+ tagSection, tagName, tag, minCount, maxCount, entry.count);
+ entry.count = 0;
+ entry.data.u8 = NULL;
+ }
+
+ return entry;
+}
+
+/** Utility methods */
+
+
+status_t Camera2Client::buildDefaultParameters() {
+ ATRACE_CALL();
+ Mutex::Autolock pl(mParamsLock);
+
+ status_t res;
+ CameraParameters params;
+
+ camera_metadata_entry_t availableProcessedSizes =
+ staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, 2);
+ if (!availableProcessedSizes.count) return NO_INIT;
+
+ // TODO: Pick more intelligently
+ mParameters.previewWidth = availableProcessedSizes.data.i32[0];
+ mParameters.previewHeight = availableProcessedSizes.data.i32[1];
+ mParameters.videoWidth = mParameters.previewWidth;
+ mParameters.videoHeight = mParameters.previewHeight;
+
+ params.setPreviewSize(mParameters.previewWidth, mParameters.previewHeight);
+ params.setVideoSize(mParameters.videoWidth, mParameters.videoHeight);
+ params.set(CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO,
+ String8::format("%dx%d",
+ mParameters.previewWidth, mParameters.previewHeight));
+ {
+ String8 supportedPreviewSizes;
+ for (size_t i=0; i < availableProcessedSizes.count; i += 2) {
+ if (i != 0) supportedPreviewSizes += ",";
+ supportedPreviewSizes += String8::format("%dx%d",
+ availableProcessedSizes.data.i32[i],
+ availableProcessedSizes.data.i32[i+1]);
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES,
+ supportedPreviewSizes);
+ params.set(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES,
+ supportedPreviewSizes);
+ }
+
+ camera_metadata_entry_t availableFpsRanges =
+ staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2);
+ if (!availableFpsRanges.count) return NO_INIT;
+
+ mParameters.previewFpsRange[0] = availableFpsRanges.data.i32[0];
+ mParameters.previewFpsRange[1] = availableFpsRanges.data.i32[1];
+
+ params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE,
+ String8::format("%d,%d",
+ mParameters.previewFpsRange[0],
+ mParameters.previewFpsRange[1]));
+
+ {
+ String8 supportedPreviewFpsRange;
+ for (size_t i=0; i < availableFpsRanges.count; i += 2) {
+ if (i != 0) supportedPreviewFpsRange += ",";
+ supportedPreviewFpsRange += String8::format("(%d,%d)",
+ availableFpsRanges.data.i32[i],
+ availableFpsRanges.data.i32[i+1]);
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE,
+ supportedPreviewFpsRange);
+ }
+
+ mParameters.previewFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+ params.set(CameraParameters::KEY_PREVIEW_FORMAT,
+ formatEnumToString(mParameters.previewFormat)); // NV21
+
+ mParameters.previewTransform = degToTransform(0,
+ mCameraFacing == CAMERA_FACING_FRONT);
+
+ camera_metadata_entry_t availableFormats =
+ staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS);
+
+ {
+ String8 supportedPreviewFormats;
+ bool addComma = false;
+ for (size_t i=0; i < availableFormats.count; i++) {
+ if (addComma) supportedPreviewFormats += ",";
+ addComma = true;
+ switch (availableFormats.data.i32[i]) {
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ supportedPreviewFormats +=
+ CameraParameters::PIXEL_FORMAT_YUV422SP;
+ break;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ supportedPreviewFormats +=
+ CameraParameters::PIXEL_FORMAT_YUV420SP;
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ supportedPreviewFormats +=
+ CameraParameters::PIXEL_FORMAT_YUV422I;
+ break;
+ case HAL_PIXEL_FORMAT_YV12:
+ supportedPreviewFormats +=
+ CameraParameters::PIXEL_FORMAT_YUV420P;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ supportedPreviewFormats +=
+ CameraParameters::PIXEL_FORMAT_RGB565;
+ break;
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ supportedPreviewFormats +=
+ CameraParameters::PIXEL_FORMAT_RGBA8888;
+ break;
+ // Not advertizing JPEG, RAW_SENSOR, etc, for preview formats
+ case HAL_PIXEL_FORMAT_RAW_SENSOR:
+ case HAL_PIXEL_FORMAT_BLOB:
+ addComma = false;
+ break;
+
+ default:
+ ALOGW("%s: Camera %d: Unknown preview format: %x",
+ __FUNCTION__, mCameraId, availableFormats.data.i32[i]);
+ addComma = false;
+ break;
+ }
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS,
+ supportedPreviewFormats);
+ }
+
+ // PREVIEW_FRAME_RATE / SUPPORTED_PREVIEW_FRAME_RATES are deprecated, but
+ // still have to do something sane for them
+
+ params.set(CameraParameters::KEY_PREVIEW_FRAME_RATE,
+ mParameters.previewFpsRange[0]);
+
+ {
+ String8 supportedPreviewFrameRates;
+ for (size_t i=0; i < availableFpsRanges.count; i += 2) {
+ if (i != 0) supportedPreviewFrameRates += ",";
+ supportedPreviewFrameRates += String8::format("%d",
+ availableFpsRanges.data.i32[i]);
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES,
+ supportedPreviewFrameRates);
+ }
+
+ camera_metadata_entry_t availableJpegSizes =
+ staticInfo(ANDROID_SCALER_AVAILABLE_JPEG_SIZES, 2);
+ if (!availableJpegSizes.count) return NO_INIT;
+
+ // TODO: Pick maximum
+ mParameters.pictureWidth = availableJpegSizes.data.i32[0];
+ mParameters.pictureHeight = availableJpegSizes.data.i32[1];
+
+ params.setPictureSize(mParameters.pictureWidth,
+ mParameters.pictureHeight);
+
+ {
+ String8 supportedPictureSizes;
+ for (size_t i=0; i < availableJpegSizes.count; i += 2) {
+ if (i != 0) supportedPictureSizes += ",";
+ supportedPictureSizes += String8::format("%dx%d",
+ availableJpegSizes.data.i32[i],
+ availableJpegSizes.data.i32[i+1]);
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES,
+ supportedPictureSizes);
+ }
+
+ params.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);
+ params.set(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS,
+ CameraParameters::PIXEL_FORMAT_JPEG);
+
+ camera_metadata_entry_t availableJpegThumbnailSizes =
+ staticInfo(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, 2);
+ if (!availableJpegThumbnailSizes.count) return NO_INIT;
+
+ // TODO: Pick default thumbnail size sensibly
+ mParameters.jpegThumbSize[0] = availableJpegThumbnailSizes.data.i32[0];
+ mParameters.jpegThumbSize[1] = availableJpegThumbnailSizes.data.i32[1];
+
+ params.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH,
+ mParameters.jpegThumbSize[0]);
+ params.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT,
+ mParameters.jpegThumbSize[1]);
+
+ {
+ String8 supportedJpegThumbSizes;
+ for (size_t i=0; i < availableJpegThumbnailSizes.count; i += 2) {
+ if (i != 0) supportedJpegThumbSizes += ",";
+ supportedJpegThumbSizes += String8::format("%dx%d",
+ availableJpegThumbnailSizes.data.i32[i],
+ availableJpegThumbnailSizes.data.i32[i+1]);
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES,
+ supportedJpegThumbSizes);
+ }
+
+ mParameters.jpegThumbQuality = 90;
+ params.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY,
+ mParameters.jpegThumbQuality);
+ mParameters.jpegQuality = 90;
+ params.set(CameraParameters::KEY_JPEG_QUALITY,
+ mParameters.jpegQuality);
+ mParameters.jpegRotation = 0;
+ params.set(CameraParameters::KEY_ROTATION,
+ mParameters.jpegRotation);
+
+ mParameters.gpsEnabled = false;
+ mParameters.gpsProcessingMethod = "unknown";
+ // GPS fields in CameraParameters are not set by implementation
+
+ mParameters.wbMode = ANDROID_CONTROL_AWB_AUTO;
+ params.set(CameraParameters::KEY_WHITE_BALANCE,
+ CameraParameters::WHITE_BALANCE_AUTO);
+
+ camera_metadata_entry_t availableWhiteBalanceModes =
+ staticInfo(ANDROID_CONTROL_AWB_AVAILABLE_MODES);
+ {
+ String8 supportedWhiteBalance;
+ bool addComma = false;
+ for (size_t i=0; i < availableWhiteBalanceModes.count; i++) {
+ if (addComma) supportedWhiteBalance += ",";
+ addComma = true;
+ switch (availableWhiteBalanceModes.data.u8[i]) {
+ case ANDROID_CONTROL_AWB_AUTO:
+ supportedWhiteBalance +=
+ CameraParameters::WHITE_BALANCE_AUTO;
+ break;
+ case ANDROID_CONTROL_AWB_INCANDESCENT:
+ supportedWhiteBalance +=
+ CameraParameters::WHITE_BALANCE_INCANDESCENT;
+ break;
+ case ANDROID_CONTROL_AWB_FLUORESCENT:
+ supportedWhiteBalance +=
+ CameraParameters::WHITE_BALANCE_FLUORESCENT;
+ break;
+ case ANDROID_CONTROL_AWB_WARM_FLUORESCENT:
+ supportedWhiteBalance +=
+ CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT;
+ break;
+ case ANDROID_CONTROL_AWB_DAYLIGHT:
+ supportedWhiteBalance +=
+ CameraParameters::WHITE_BALANCE_DAYLIGHT;
+ break;
+ case ANDROID_CONTROL_AWB_CLOUDY_DAYLIGHT:
+ supportedWhiteBalance +=
+ CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT;
+ break;
+ case ANDROID_CONTROL_AWB_TWILIGHT:
+ supportedWhiteBalance +=
+ CameraParameters::WHITE_BALANCE_TWILIGHT;
+ break;
+ case ANDROID_CONTROL_AWB_SHADE:
+ supportedWhiteBalance +=
+ CameraParameters::WHITE_BALANCE_SHADE;
+ break;
+ // Skipping values not mappable to v1 API
+ case ANDROID_CONTROL_AWB_OFF:
+ addComma = false;
+ break;
+ default:
+ ALOGW("%s: Camera %d: Unknown white balance value: %d",
+ __FUNCTION__, mCameraId,
+ availableWhiteBalanceModes.data.u8[i]);
+ addComma = false;
+ break;
+ }
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE,
+ supportedWhiteBalance);
+ }
+
+ mParameters.effectMode = ANDROID_CONTROL_EFFECT_OFF;
+ params.set(CameraParameters::KEY_EFFECT,
+ CameraParameters::EFFECT_NONE);
+
+ camera_metadata_entry_t availableEffects =
+ staticInfo(ANDROID_CONTROL_AVAILABLE_EFFECTS);
+ if (!availableEffects.count) return NO_INIT;
+ {
+ String8 supportedEffects;
+ bool addComma = false;
+ for (size_t i=0; i < availableEffects.count; i++) {
+ if (addComma) supportedEffects += ",";
+ addComma = true;
+ switch (availableEffects.data.u8[i]) {
+ case ANDROID_CONTROL_EFFECT_OFF:
+ supportedEffects +=
+ CameraParameters::EFFECT_NONE;
+ break;
+ case ANDROID_CONTROL_EFFECT_MONO:
+ supportedEffects +=
+ CameraParameters::EFFECT_MONO;
+ break;
+ case ANDROID_CONTROL_EFFECT_NEGATIVE:
+ supportedEffects +=
+ CameraParameters::EFFECT_NEGATIVE;
+ break;
+ case ANDROID_CONTROL_EFFECT_SOLARIZE:
+ supportedEffects +=
+ CameraParameters::EFFECT_SOLARIZE;
+ break;
+ case ANDROID_CONTROL_EFFECT_SEPIA:
+ supportedEffects +=
+ CameraParameters::EFFECT_SEPIA;
+ break;
+ case ANDROID_CONTROL_EFFECT_POSTERIZE:
+ supportedEffects +=
+ CameraParameters::EFFECT_POSTERIZE;
+ break;
+ case ANDROID_CONTROL_EFFECT_WHITEBOARD:
+ supportedEffects +=
+ CameraParameters::EFFECT_WHITEBOARD;
+ break;
+ case ANDROID_CONTROL_EFFECT_BLACKBOARD:
+ supportedEffects +=
+ CameraParameters::EFFECT_BLACKBOARD;
+ break;
+ case ANDROID_CONTROL_EFFECT_AQUA:
+ supportedEffects +=
+ CameraParameters::EFFECT_AQUA;
+ break;
+ default:
+ ALOGW("%s: Camera %d: Unknown effect value: %d",
+ __FUNCTION__, mCameraId, availableEffects.data.u8[i]);
+ addComma = false;
+ break;
+ }
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_EFFECTS, supportedEffects);
+ }
+
+ mParameters.antibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_AUTO;
+ params.set(CameraParameters::KEY_ANTIBANDING,
+ CameraParameters::ANTIBANDING_AUTO);
+
+ camera_metadata_entry_t availableAntibandingModes =
+ staticInfo(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES);
+ if (!availableAntibandingModes.count) return NO_INIT;
+ {
+ String8 supportedAntibanding;
+ bool addComma = false;
+ for (size_t i=0; i < availableAntibandingModes.count; i++) {
+ if (addComma) supportedAntibanding += ",";
+ addComma = true;
+ switch (availableAntibandingModes.data.u8[i]) {
+ case ANDROID_CONTROL_AE_ANTIBANDING_OFF:
+ supportedAntibanding +=
+ CameraParameters::ANTIBANDING_OFF;
+ break;
+ case ANDROID_CONTROL_AE_ANTIBANDING_50HZ:
+ supportedAntibanding +=
+ CameraParameters::ANTIBANDING_50HZ;
+ break;
+ case ANDROID_CONTROL_AE_ANTIBANDING_60HZ:
+ supportedAntibanding +=
+ CameraParameters::ANTIBANDING_60HZ;
+ break;
+ case ANDROID_CONTROL_AE_ANTIBANDING_AUTO:
+ supportedAntibanding +=
+ CameraParameters::ANTIBANDING_AUTO;
+ break;
+ default:
+ ALOGW("%s: Camera %d: Unknown antibanding value: %d",
+ __FUNCTION__, mCameraId,
+ availableAntibandingModes.data.u8[i]);
+ addComma = false;
+ break;
+ }
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_ANTIBANDING,
+ supportedAntibanding);
+ }
+
+ mParameters.sceneMode = ANDROID_CONTROL_OFF;
+ params.set(CameraParameters::KEY_SCENE_MODE,
+ CameraParameters::SCENE_MODE_AUTO);
+
+ camera_metadata_entry_t availableSceneModes =
+ staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
+ if (!availableSceneModes.count) return NO_INIT;
+ {
+ String8 supportedSceneModes(CameraParameters::SCENE_MODE_AUTO);
+ bool addComma = true;
+ bool noSceneModes = false;
+ for (size_t i=0; i < availableSceneModes.count; i++) {
+ if (addComma) supportedSceneModes += ",";
+ addComma = true;
+ switch (availableSceneModes.data.u8[i]) {
+ case ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED:
+ noSceneModes = true;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY:
+ // Not in old API
+ addComma = false;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_ACTION:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_ACTION;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_PORTRAIT:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_PORTRAIT;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_LANDSCAPE:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_LANDSCAPE;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_NIGHT:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_NIGHT;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_NIGHT_PORTRAIT:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_NIGHT_PORTRAIT;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_THEATRE:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_THEATRE;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_BEACH:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_BEACH;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_SNOW:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_SNOW;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_SUNSET:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_SUNSET;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_STEADYPHOTO:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_STEADYPHOTO;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_FIREWORKS:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_FIREWORKS;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_SPORTS:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_SPORTS;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_PARTY:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_PARTY;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_CANDLELIGHT;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_BARCODE:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_BARCODE;
+ break;
+ default:
+ ALOGW("%s: Camera %d: Unknown scene mode value: %d",
+ __FUNCTION__, mCameraId,
+ availableSceneModes.data.u8[i]);
+ addComma = false;
+ break;
+ }
+ }
+ if (!noSceneModes) {
+ params.set(CameraParameters::KEY_SUPPORTED_SCENE_MODES,
+ supportedSceneModes);
+ }
+ }
+
+ camera_metadata_entry_t flashAvailable =
+ staticInfo(ANDROID_FLASH_AVAILABLE, 1, 1);
+ if (!flashAvailable.count) return NO_INIT;
+
+ camera_metadata_entry_t availableAeModes =
+ staticInfo(ANDROID_CONTROL_AE_AVAILABLE_MODES);
+ if (!availableAeModes.count) return NO_INIT;
+
+ if (flashAvailable.data.u8[0]) {
+ mParameters.flashMode = Parameters::FLASH_MODE_AUTO;
+ params.set(CameraParameters::KEY_FLASH_MODE,
+ CameraParameters::FLASH_MODE_AUTO);
+
+ String8 supportedFlashModes(CameraParameters::FLASH_MODE_OFF);
+ supportedFlashModes = supportedFlashModes +
+ "," + CameraParameters::FLASH_MODE_AUTO +
+ "," + CameraParameters::FLASH_MODE_ON +
+ "," + CameraParameters::FLASH_MODE_TORCH;
+ for (size_t i=0; i < availableAeModes.count; i++) {
+ if (availableAeModes.data.u8[i] ==
+ ANDROID_CONTROL_AE_ON_AUTO_FLASH_REDEYE) {
+ supportedFlashModes = supportedFlashModes + "," +
+ CameraParameters::FLASH_MODE_RED_EYE;
+ break;
+ }
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES,
+ supportedFlashModes);
+ } else {
+ mParameters.flashMode = Parameters::FLASH_MODE_OFF;
+ params.set(CameraParameters::KEY_FLASH_MODE,
+ CameraParameters::FLASH_MODE_OFF);
+ params.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES,
+ CameraParameters::FLASH_MODE_OFF);
+ }
+
+ camera_metadata_entry_t minFocusDistance =
+ staticInfo(ANDROID_LENS_MINIMUM_FOCUS_DISTANCE, 1, 1);
+ if (!minFocusDistance.count) return NO_INIT;
+
+ camera_metadata_entry_t availableAfModes =
+ staticInfo(ANDROID_CONTROL_AF_AVAILABLE_MODES);
+ if (!availableAfModes.count) return NO_INIT;
+
+ if (minFocusDistance.data.f[0] == 0) {
+ // Fixed-focus lens
+ mParameters.focusMode = Parameters::FOCUS_MODE_FIXED;
+ params.set(CameraParameters::KEY_FOCUS_MODE,
+ CameraParameters::FOCUS_MODE_FIXED);
+ params.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES,
+ CameraParameters::FOCUS_MODE_FIXED);
+ } else {
+ mParameters.focusMode = Parameters::FOCUS_MODE_AUTO;
+ params.set(CameraParameters::KEY_FOCUS_MODE,
+ CameraParameters::FOCUS_MODE_AUTO);
+ String8 supportedFocusModes(CameraParameters::FOCUS_MODE_FIXED);
+ supportedFocusModes = supportedFocusModes + "," +
+ CameraParameters::FOCUS_MODE_INFINITY;
+ bool addComma = true;
+
+ for (size_t i=0; i < availableAfModes.count; i++) {
+ if (addComma) supportedFocusModes += ",";
+ addComma = true;
+ switch (availableAfModes.data.u8[i]) {
+ case ANDROID_CONTROL_AF_AUTO:
+ supportedFocusModes +=
+ CameraParameters::FOCUS_MODE_AUTO;
+ break;
+ case ANDROID_CONTROL_AF_MACRO:
+ supportedFocusModes +=
+ CameraParameters::FOCUS_MODE_MACRO;
+ break;
+ case ANDROID_CONTROL_AF_CONTINUOUS_VIDEO:
+ supportedFocusModes +=
+ CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO;
+ break;
+ case ANDROID_CONTROL_AF_CONTINUOUS_PICTURE:
+ supportedFocusModes +=
+ CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE;
+ break;
+ case ANDROID_CONTROL_AF_EDOF:
+ supportedFocusModes +=
+ CameraParameters::FOCUS_MODE_EDOF;
+ break;
+ // Not supported in old API
+ case ANDROID_CONTROL_AF_OFF:
+ addComma = false;
+ break;
+ default:
+ ALOGW("%s: Camera %d: Unknown AF mode value: %d",
+ __FUNCTION__, mCameraId, availableAfModes.data.u8[i]);
+ addComma = false;
+ break;
+ }
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES,
+ supportedFocusModes);
+ }
+
+ camera_metadata_entry_t max3aRegions =
+ staticInfo(ANDROID_CONTROL_MAX_REGIONS, 1, 1);
+ if (!max3aRegions.count) return NO_INIT;
+
+ params.set(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS,
+ max3aRegions.data.i32[0]);
+ params.set(CameraParameters::KEY_FOCUS_AREAS,
+ "(0,0,0,0,0)");
+ mParameters.focusingAreas.clear();
+ mParameters.focusingAreas.add(Parameters::Area(0,0,0,0,0));
+
+ camera_metadata_entry_t availableFocalLengths =
+ staticInfo(ANDROID_LENS_AVAILABLE_FOCAL_LENGTHS);
+ if (!availableFocalLengths.count) return NO_INIT;
+
+ float minFocalLength = availableFocalLengths.data.f[0];
+ params.setFloat(CameraParameters::KEY_FOCAL_LENGTH, minFocalLength);
+
+ camera_metadata_entry_t sensorSize =
+ staticInfo(ANDROID_SENSOR_PHYSICAL_SIZE, 2, 2);
+ if (!sensorSize.count) return NO_INIT;
+
+ // The fields of view here assume infinity focus, maximum wide angle
+ float horizFov = 180 / M_PI *
+ 2 * atanf(sensorSize.data.f[0] / (2 * minFocalLength));
+ float vertFov = 180 / M_PI *
+ 2 * atanf(sensorSize.data.f[1] / (2 * minFocalLength));
+ params.setFloat(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, horizFov);
+ params.setFloat(CameraParameters::KEY_VERTICAL_VIEW_ANGLE, vertFov);
+
+ mParameters.exposureCompensation = 0;
+ params.set(CameraParameters::KEY_EXPOSURE_COMPENSATION,
+ mParameters.exposureCompensation);
+
+ camera_metadata_entry_t exposureCompensationRange =
+ staticInfo(ANDROID_CONTROL_AE_EXP_COMPENSATION_RANGE, 2, 2);
+ if (!exposureCompensationRange.count) return NO_INIT;
+
+ params.set(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION,
+ exposureCompensationRange.data.i32[1]);
+ params.set(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION,
+ exposureCompensationRange.data.i32[0]);
+
+ camera_metadata_entry_t exposureCompensationStep =
+ staticInfo(ANDROID_CONTROL_AE_EXP_COMPENSATION_STEP, 1, 1);
+ if (!exposureCompensationStep.count) return NO_INIT;
+
+ params.setFloat(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP,
+ exposureCompensationStep.data.r[0].numerator /
+ exposureCompensationStep.data.r[0].denominator);
+
+ mParameters.autoExposureLock = false;
+ params.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK,
+ CameraParameters::FALSE);
+ params.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED,
+ CameraParameters::TRUE);
+
+ mParameters.autoWhiteBalanceLock = false;
+ params.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK,
+ CameraParameters::FALSE);
+ params.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED,
+ CameraParameters::TRUE);
+
+ mParameters.meteringAreas.add(Parameters::Area(0, 0, 0, 0, 0));
+ params.set(CameraParameters::KEY_MAX_NUM_METERING_AREAS,
+ max3aRegions.data.i32[0]);
+ params.set(CameraParameters::KEY_METERING_AREAS,
+ "(0,0,0,0,0)");
+
+ mParameters.zoom = 0;
+ params.set(CameraParameters::KEY_ZOOM, mParameters.zoom);
+ params.set(CameraParameters::KEY_MAX_ZOOM, NUM_ZOOM_STEPS - 1);
+
+ camera_metadata_entry_t maxDigitalZoom =
+ staticInfo(ANDROID_SCALER_AVAILABLE_MAX_ZOOM, 1, 1);
+ if (!maxDigitalZoom.count) return NO_INIT;
+
+ {
+ String8 zoomRatios;
+ float zoom = 1.f;
+ float zoomIncrement = (maxDigitalZoom.data.f[0] - zoom) /
+ (NUM_ZOOM_STEPS-1);
+ bool addComma = false;
+ for (size_t i=0; i < NUM_ZOOM_STEPS; i++) {
+ if (addComma) zoomRatios += ",";
+ addComma = true;
+ zoomRatios += String8::format("%d", static_cast<int>(zoom * 100));
+ zoom += zoomIncrement;
+ }
+ params.set(CameraParameters::KEY_ZOOM_RATIOS, zoomRatios);
+ }
+
+ params.set(CameraParameters::KEY_ZOOM_SUPPORTED,
+ CameraParameters::TRUE);
+ params.set(CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED,
+ CameraParameters::TRUE);
+
+ params.set(CameraParameters::KEY_FOCUS_DISTANCES,
+ "Infinity,Infinity,Infinity");
+
+ camera_metadata_entry_t maxFacesDetected =
+ staticInfo(ANDROID_STATS_MAX_FACE_COUNT, 1, 1);
+ params.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW,
+ maxFacesDetected.data.i32[0]);
+ params.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW,
+ 0);
+
+ params.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT,
+ formatEnumToString(HAL_PIXEL_FORMAT_YCrCb_420_SP));
+
+ params.set(CameraParameters::KEY_RECORDING_HINT,
+ CameraParameters::FALSE);
+
+ params.set(CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED,
+ CameraParameters::TRUE);
+
+ params.set(CameraParameters::KEY_VIDEO_STABILIZATION,
+ CameraParameters::FALSE);
+
+ camera_metadata_entry_t availableVideoStabilizationModes =
+ staticInfo(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES);
+ if (!availableVideoStabilizationModes.count) return NO_INIT;
+
+ if (availableVideoStabilizationModes.count > 1) {
+ params.set(CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED,
+ CameraParameters::TRUE);
+ } else {
+ params.set(CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED,
+ CameraParameters::FALSE);
+ }
+
+ mParamsFlattened = params.flatten();
+
+ return OK;
+}
+
+status_t Camera2Client::updatePreviewStream() {
+ ATRACE_CALL();
+ status_t res;
+ if (mPreviewStreamId != NO_STREAM) {
+ // Check if stream parameters have to change
+ uint32_t currentWidth, currentHeight;
+ res = mDevice->getStreamInfo(mPreviewStreamId,
+ ¤tWidth, ¤tHeight, 0);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error querying preview stream info: "
+ "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ if (currentWidth != (uint32_t)mParameters.previewWidth ||
+ currentHeight != (uint32_t)mParameters.previewHeight) {
+ res = mDevice->waitUntilDrained();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error waiting for preview to drain: "
+ "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ res = mDevice->deleteStream(mPreviewStreamId);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to delete old output stream "
+ "for preview: %s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
+ return res;
+ }
+ mPreviewStreamId = NO_STREAM;
+ }
+ }
+
+ if (mPreviewStreamId == NO_STREAM) {
+ res = mDevice->createStream(mPreviewWindow,
+ mParameters.previewWidth, mParameters.previewHeight,
+ CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 0,
+ &mPreviewStreamId);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to create preview stream: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ }
+
+ res = mDevice->setStreamTransform(mPreviewStreamId,
+ mParameters.previewTransform);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to set preview stream transform: "
+ "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+
+ return OK;
+}
+
+status_t Camera2Client::updatePreviewRequest() {
+ ATRACE_CALL();
+ status_t res;
+ if (mPreviewRequest == NULL) {
+ res = mDevice->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
+ &mPreviewRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to create default preview request: "
+ "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ }
+
+ res = updateRequestCommon(mPreviewRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update common entries of preview "
+ "request: %s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
+ return res;
+ }
+
+ return OK;
+}
+
+status_t Camera2Client::updateCaptureStream() {
+ ATRACE_CALL();
+ status_t res;
+ // Find out buffer size for JPEG
+ camera_metadata_entry_t maxJpegSize =
+ staticInfo(ANDROID_JPEG_MAX_SIZE);
+ if (maxJpegSize.count == 0) {
+ ALOGE("%s: Camera %d: Can't find ANDROID_JPEG_MAX_SIZE!",
+ __FUNCTION__, mCameraId);
+ return INVALID_OPERATION;
+ }
+
+ if (mCaptureConsumer == 0) {
+ // Create CPU buffer queue endpoint
+ mCaptureConsumer = new CpuConsumer(1);
+ mCaptureConsumer->setFrameAvailableListener(new CaptureWaiter(this));
+ mCaptureConsumer->setName(String8("Camera2Client::CaptureConsumer"));
+ mCaptureWindow = new SurfaceTextureClient(
+ mCaptureConsumer->getProducerInterface());
+ // Create memory for API consumption
+ mCaptureHeap = new MemoryHeapBase(maxJpegSize.data.i32[0], 0,
+ "Camera2Client::CaptureHeap");
+ if (mCaptureHeap->getSize() == 0) {
+ ALOGE("%s: Camera %d: Unable to allocate memory for capture",
+ __FUNCTION__, mCameraId);
+ return NO_MEMORY;
+ }
+ mCaptureMemory = new MemoryBase(mCaptureHeap,
+ 0, maxJpegSize.data.i32[0]);
+ }
+
+ if (mCaptureStreamId != NO_STREAM) {
+ // Check if stream parameters have to change
+ uint32_t currentWidth, currentHeight;
+ res = mDevice->getStreamInfo(mCaptureStreamId,
+ ¤tWidth, ¤tHeight, 0);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error querying capture output stream info: "
+ "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ if (currentWidth != (uint32_t)mParameters.pictureWidth ||
+ currentHeight != (uint32_t)mParameters.pictureHeight) {
+ res = mDevice->deleteStream(mCaptureStreamId);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to delete old output stream "
+ "for capture: %s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
+ return res;
+ }
+ mCaptureStreamId = NO_STREAM;
+ }
+ }
+
+ if (mCaptureStreamId == NO_STREAM) {
+ // Create stream for HAL production
+ res = mDevice->createStream(mCaptureWindow,
+ mParameters.pictureWidth, mParameters.pictureHeight,
+ HAL_PIXEL_FORMAT_BLOB, maxJpegSize.data.i32[0],
+ &mCaptureStreamId);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't create output stream for capture: "
+ "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+
+ }
+ return OK;
+}
+
+status_t Camera2Client::updateCaptureRequest() {
+ ATRACE_CALL();
+ status_t res;
+ if (mCaptureRequest == NULL) {
+ res = mDevice->createDefaultRequest(CAMERA2_TEMPLATE_STILL_CAPTURE,
+ &mCaptureRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to create default still image request:"
+ " %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ }
+
+ res = updateRequestCommon(mCaptureRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update common entries of capture "
+ "request: %s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
+ return res;
+ }
+
+ res = updateEntry(mCaptureRequest,
+ ANDROID_JPEG_THUMBNAIL_SIZE,
+ mParameters.jpegThumbSize, 2);
+ if (res != OK) return res;
+ res = updateEntry(mCaptureRequest,
+ ANDROID_JPEG_THUMBNAIL_QUALITY,
+ &mParameters.jpegThumbQuality, 1);
+ if (res != OK) return res;
+ res = updateEntry(mCaptureRequest,
+ ANDROID_JPEG_QUALITY,
+ &mParameters.jpegQuality, 1);
+ if (res != OK) return res;
+ res = updateEntry(mCaptureRequest,
+ ANDROID_JPEG_ORIENTATION,
+ &mParameters.jpegRotation, 1);
+ if (res != OK) return res;
+
+ if (mParameters.gpsEnabled) {
+ res = updateEntry(mCaptureRequest,
+ ANDROID_JPEG_GPS_COORDINATES,
+ mParameters.gpsCoordinates, 3);
+ if (res != OK) return res;
+ res = updateEntry(mCaptureRequest,
+ ANDROID_JPEG_GPS_TIMESTAMP,
+ &mParameters.gpsTimestamp, 1);
+ if (res != OK) return res;
+ res = updateEntry(mCaptureRequest,
+ ANDROID_JPEG_GPS_PROCESSING_METHOD,
+ mParameters.gpsProcessingMethod.string(),
+ mParameters.gpsProcessingMethod.size());
+ if (res != OK) return res;
+ } else {
+ res = deleteEntry(mCaptureRequest,
+ ANDROID_JPEG_GPS_COORDINATES);
+ if (res != OK) return res;
+ res = deleteEntry(mCaptureRequest,
+ ANDROID_JPEG_GPS_TIMESTAMP);
+ if (res != OK) return res;
+ res = deleteEntry(mCaptureRequest,
+ ANDROID_JPEG_GPS_PROCESSING_METHOD);
+ if (res != OK) return res;
+ }
+
+ return OK;
+}
+
+status_t Camera2Client::updateRequestCommon(camera_metadata_t *request) {
+ ATRACE_CALL();
+ status_t res;
+ res = updateEntry(request,
+ ANDROID_CONTROL_AE_TARGET_FPS_RANGE, mParameters.previewFpsRange, 2);
+ if (res != OK) return res;
+
+ uint8_t wbMode = mParameters.autoWhiteBalanceLock ?
+ ANDROID_CONTROL_AWB_LOCKED : mParameters.wbMode;
+ res = updateEntry(request,
+ ANDROID_CONTROL_AWB_MODE, &wbMode, 1);
+ if (res != OK) return res;
+ res = updateEntry(request,
+ ANDROID_CONTROL_EFFECT_MODE, &mParameters.effectMode, 1);
+ if (res != OK) return res;
+ res = updateEntry(request,
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE,
+ &mParameters.antibandingMode, 1);
+ if (res != OK) return res;
+
+ uint8_t controlMode =
+ (mParameters.sceneMode == ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED) ?
+ ANDROID_CONTROL_AUTO : ANDROID_CONTROL_USE_SCENE_MODE;
+ res = updateEntry(request,
+ ANDROID_CONTROL_MODE, &controlMode, 1);
+ if (res != OK) return res;
+ if (controlMode == ANDROID_CONTROL_USE_SCENE_MODE) {
+ res = updateEntry(request,
+ ANDROID_CONTROL_SCENE_MODE,
+ &mParameters.sceneMode, 1);
+ if (res != OK) return res;
+ }
+
+ uint8_t flashMode = ANDROID_FLASH_OFF;
+ uint8_t aeMode;
+ switch (mParameters.flashMode) {
+ case Parameters::FLASH_MODE_OFF:
+ aeMode = ANDROID_CONTROL_AE_ON; break;
+ case Parameters::FLASH_MODE_AUTO:
+ aeMode = ANDROID_CONTROL_AE_ON_AUTO_FLASH; break;
+ case Parameters::FLASH_MODE_ON:
+ aeMode = ANDROID_CONTROL_AE_ON_ALWAYS_FLASH; break;
+ case Parameters::FLASH_MODE_TORCH:
+ aeMode = ANDROID_CONTROL_AE_ON;
+ flashMode = ANDROID_FLASH_TORCH;
+ break;
+ case Parameters::FLASH_MODE_RED_EYE:
+ aeMode = ANDROID_CONTROL_AE_ON_AUTO_FLASH_REDEYE; break;
+ default:
+ ALOGE("%s: Camera %d: Unknown flash mode %d", __FUNCTION__,
+ mCameraId, mParameters.flashMode);
+ return BAD_VALUE;
+ }
+ if (mParameters.autoExposureLock) aeMode = ANDROID_CONTROL_AE_LOCKED;
+
+ res = updateEntry(request,
+ ANDROID_FLASH_MODE, &flashMode, 1);
+ if (res != OK) return res;
+ res = updateEntry(request,
+ ANDROID_CONTROL_AE_MODE, &aeMode, 1);
+ if (res != OK) return res;
+
+ float focusDistance = 0; // infinity focus in diopters
+ uint8_t focusMode;
+ switch (mParameters.focusMode) {
+ case Parameters::FOCUS_MODE_AUTO:
+ case Parameters::FOCUS_MODE_MACRO:
+ case Parameters::FOCUS_MODE_CONTINUOUS_VIDEO:
+ case Parameters::FOCUS_MODE_CONTINUOUS_PICTURE:
+ case Parameters::FOCUS_MODE_EDOF:
+ focusMode = mParameters.focusMode;
+ break;
+ case Parameters::FOCUS_MODE_INFINITY:
+ case Parameters::FOCUS_MODE_FIXED:
+ focusMode = ANDROID_CONTROL_AF_OFF;
+ break;
+ default:
+ ALOGE("%s: Camera %d: Unknown focus mode %d", __FUNCTION__,
+ mCameraId, mParameters.focusMode);
+ return BAD_VALUE;
+ }
+ res = updateEntry(request,
+ ANDROID_LENS_FOCUS_DISTANCE, &focusDistance, 1);
+ if (res != OK) return res;
+ res = updateEntry(request,
+ ANDROID_CONTROL_AF_MODE, &focusMode, 1);
+ if (res != OK) return res;
+
+ size_t focusingAreasSize = mParameters.focusingAreas.size() * 5;
+ int32_t *focusingAreas = new int32_t[focusingAreasSize];
+ for (size_t i = 0; i < focusingAreasSize; i += 5) {
+ focusingAreas[i + 0] = mParameters.focusingAreas[i].left;
+ focusingAreas[i + 1] = mParameters.focusingAreas[i].top;
+ focusingAreas[i + 2] = mParameters.focusingAreas[i].right;
+ focusingAreas[i + 3] = mParameters.focusingAreas[i].bottom;
+ focusingAreas[i + 4] = mParameters.focusingAreas[i].weight;
+ }
+ res = updateEntry(request,
+ ANDROID_CONTROL_AF_REGIONS, focusingAreas,focusingAreasSize);
+ if (res != OK) return res;
+ delete[] focusingAreas;
+
+ res = updateEntry(request,
+ ANDROID_CONTROL_AE_EXP_COMPENSATION,
+ &mParameters.exposureCompensation, 1);
+ if (res != OK) return res;
+
+ size_t meteringAreasSize = mParameters.meteringAreas.size() * 5;
+ int32_t *meteringAreas = new int32_t[meteringAreasSize];
+ for (size_t i = 0; i < meteringAreasSize; i += 5) {
+ meteringAreas[i + 0] = mParameters.meteringAreas[i].left;
+ meteringAreas[i + 1] = mParameters.meteringAreas[i].top;
+ meteringAreas[i + 2] = mParameters.meteringAreas[i].right;
+ meteringAreas[i + 3] = mParameters.meteringAreas[i].bottom;
+ meteringAreas[i + 4] = mParameters.meteringAreas[i].weight;
+ }
+ res = updateEntry(request,
+ ANDROID_CONTROL_AE_REGIONS, meteringAreas, meteringAreasSize);
+ if (res != OK) return res;
+
+ res = updateEntry(request,
+ ANDROID_CONTROL_AWB_REGIONS, meteringAreas, meteringAreasSize);
+ if (res != OK) return res;
+ delete[] meteringAreas;
+
+ // Need to convert zoom index into a crop rectangle. The rectangle is
+ // chosen to maximize its area on the sensor
+
+ camera_metadata_entry_t maxDigitalZoom =
+ staticInfo(ANDROID_SCALER_AVAILABLE_MAX_ZOOM);
+ float zoomIncrement = (maxDigitalZoom.data.f[0] - 1) /
+ (NUM_ZOOM_STEPS-1);
+ float zoomRatio = 1 + zoomIncrement * mParameters.zoom;
+
+ camera_metadata_entry_t activePixelArraySize =
+ staticInfo(ANDROID_SENSOR_ACTIVE_ARRAY_SIZE, 2, 2);
+ int32_t arrayWidth = activePixelArraySize.data.i32[0];
+ int32_t arrayHeight = activePixelArraySize.data.i32[1];
+ float zoomLeft, zoomTop, zoomWidth, zoomHeight;
+ if (mParameters.previewWidth >= mParameters.previewHeight) {
+ zoomWidth = arrayWidth / zoomRatio;
+ zoomHeight = zoomWidth *
+ mParameters.previewHeight / mParameters.previewWidth;
+ } else {
+ zoomHeight = arrayHeight / zoomRatio;
+ zoomWidth = zoomHeight *
+ mParameters.previewWidth / mParameters.previewHeight;
+ }
+ zoomLeft = (arrayWidth - zoomWidth) / 2;
+ zoomTop = (arrayHeight - zoomHeight) / 2;
+
+ int32_t cropRegion[3] = { zoomLeft, zoomTop, zoomWidth };
+ res = updateEntry(request,
+ ANDROID_SCALER_CROP_REGION, cropRegion, 3);
+ if (res != OK) return res;
+
+ // TODO: Decide how to map recordingHint, or whether just to ignore it
+
+ uint8_t vstabMode = mParameters.videoStabilization ?
+ ANDROID_CONTROL_VIDEO_STABILIZATION_ON :
+ ANDROID_CONTROL_VIDEO_STABILIZATION_OFF;
+ res = updateEntry(request,
+ ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+ &vstabMode, 1);
+ if (res != OK) return res;
+
+ return OK;
+}
+
+status_t Camera2Client::updateEntry(camera_metadata_t *buffer,
+ uint32_t tag, const void *data, size_t data_count) {
+ camera_metadata_entry_t entry;
+ status_t res;
+ res = find_camera_metadata_entry(buffer, tag, &entry);
+ if (res == NAME_NOT_FOUND) {
+ res = add_camera_metadata_entry(buffer,
+ tag, data, data_count);
+ } else if (res == OK) {
+ res = update_camera_metadata_entry(buffer,
+ entry.index, data, data_count, NULL);
+ }
+
+ if (res != OK) {
+ ALOGE("%s: Unable to update metadata entry %s.%s (%x): %s (%d)",
+ __FUNCTION__, get_camera_metadata_section_name(tag),
+ get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
+ }
+ return res;
+}
+
+status_t Camera2Client::deleteEntry(camera_metadata_t *buffer, uint32_t tag) {
+ camera_metadata_entry_t entry;
+ status_t res;
+ res = find_camera_metadata_entry(buffer, tag, &entry);
+ if (res == NAME_NOT_FOUND) {
+ return OK;
+ } else if (res != OK) {
+ ALOGE("%s: Error looking for entry %s.%s (%x): %s %d",
+ __FUNCTION__,
+ get_camera_metadata_section_name(tag),
+ get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
+ return res;
+ }
+ res = delete_camera_metadata_entry(buffer, entry.index);
+ if (res != OK) {
+ ALOGE("%s: Error deleting entry %s.%s (%x): %s %d",
+ __FUNCTION__,
+ get_camera_metadata_section_name(tag),
+ get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
+ }
+ return res;
+}
+int Camera2Client::formatStringToEnum(const char *format) {
+ return
+ !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV422SP) ?
+ HAL_PIXEL_FORMAT_YCbCr_422_SP : // NV16
+ !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV420SP) ?
+ HAL_PIXEL_FORMAT_YCrCb_420_SP : // NV21
+ !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV422I) ?
+ HAL_PIXEL_FORMAT_YCbCr_422_I : // YUY2
+ !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV420P) ?
+ HAL_PIXEL_FORMAT_YV12 : // YV12
+ !strcmp(format, CameraParameters::PIXEL_FORMAT_RGB565) ?
+ HAL_PIXEL_FORMAT_RGB_565 : // RGB565
+ !strcmp(format, CameraParameters::PIXEL_FORMAT_RGBA8888) ?
+ HAL_PIXEL_FORMAT_RGBA_8888 : // RGB8888
+ !strcmp(format, CameraParameters::PIXEL_FORMAT_BAYER_RGGB) ?
+ HAL_PIXEL_FORMAT_RAW_SENSOR : // Raw sensor data
+ -1;
+}
+
+const char* Camera2Client::formatEnumToString(int format) {
+ const char *fmt;
+ switch(format) {
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP: // NV16
+ fmt = CameraParameters::PIXEL_FORMAT_YUV422SP;
+ break;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP: // NV21
+ fmt = CameraParameters::PIXEL_FORMAT_YUV420SP;
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_422_I: // YUY2
+ fmt = CameraParameters::PIXEL_FORMAT_YUV422I;
+ break;
+ case HAL_PIXEL_FORMAT_YV12: // YV12
+ fmt = CameraParameters::PIXEL_FORMAT_YUV420P;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565: // RGB565
+ fmt = CameraParameters::PIXEL_FORMAT_RGB565;
+ break;
+ case HAL_PIXEL_FORMAT_RGBA_8888: // RGBA8888
+ fmt = CameraParameters::PIXEL_FORMAT_RGBA8888;
+ break;
+ case HAL_PIXEL_FORMAT_RAW_SENSOR:
+ ALOGW("Raw sensor preview format requested.");
+ fmt = CameraParameters::PIXEL_FORMAT_BAYER_RGGB;
+ break;
+ default:
+ ALOGE("%s: Unknown preview format: %x",
+ __FUNCTION__, format);
+ fmt = NULL;
+ break;
+ }
+ return fmt;
+}
+
+int Camera2Client::wbModeStringToEnum(const char *wbMode) {
+ return
+ !strcmp(wbMode, CameraParameters::WHITE_BALANCE_AUTO) ?
+ ANDROID_CONTROL_AWB_AUTO :
+ !strcmp(wbMode, CameraParameters::WHITE_BALANCE_INCANDESCENT) ?
+ ANDROID_CONTROL_AWB_INCANDESCENT :
+ !strcmp(wbMode, CameraParameters::WHITE_BALANCE_FLUORESCENT) ?
+ ANDROID_CONTROL_AWB_FLUORESCENT :
+ !strcmp(wbMode, CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT) ?
+ ANDROID_CONTROL_AWB_WARM_FLUORESCENT :
+ !strcmp(wbMode, CameraParameters::WHITE_BALANCE_DAYLIGHT) ?
+ ANDROID_CONTROL_AWB_DAYLIGHT :
+ !strcmp(wbMode, CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT) ?
+ ANDROID_CONTROL_AWB_CLOUDY_DAYLIGHT :
+ !strcmp(wbMode, CameraParameters::WHITE_BALANCE_TWILIGHT) ?
+ ANDROID_CONTROL_AWB_TWILIGHT :
+ !strcmp(wbMode, CameraParameters::WHITE_BALANCE_SHADE) ?
+ ANDROID_CONTROL_AWB_SHADE :
+ -1;
+}
+
+int Camera2Client::effectModeStringToEnum(const char *effectMode) {
+ return
+ !strcmp(effectMode, CameraParameters::EFFECT_NONE) ?
+ ANDROID_CONTROL_EFFECT_OFF :
+ !strcmp(effectMode, CameraParameters::EFFECT_MONO) ?
+ ANDROID_CONTROL_EFFECT_MONO :
+ !strcmp(effectMode, CameraParameters::EFFECT_NEGATIVE) ?
+ ANDROID_CONTROL_EFFECT_NEGATIVE :
+ !strcmp(effectMode, CameraParameters::EFFECT_SOLARIZE) ?
+ ANDROID_CONTROL_EFFECT_SOLARIZE :
+ !strcmp(effectMode, CameraParameters::EFFECT_SEPIA) ?
+ ANDROID_CONTROL_EFFECT_SEPIA :
+ !strcmp(effectMode, CameraParameters::EFFECT_POSTERIZE) ?
+ ANDROID_CONTROL_EFFECT_POSTERIZE :
+ !strcmp(effectMode, CameraParameters::EFFECT_WHITEBOARD) ?
+ ANDROID_CONTROL_EFFECT_WHITEBOARD :
+ !strcmp(effectMode, CameraParameters::EFFECT_BLACKBOARD) ?
+ ANDROID_CONTROL_EFFECT_BLACKBOARD :
+ !strcmp(effectMode, CameraParameters::EFFECT_AQUA) ?
+ ANDROID_CONTROL_EFFECT_AQUA :
+ -1;
+}
+
+int Camera2Client::abModeStringToEnum(const char *abMode) {
+ return
+ !strcmp(abMode, CameraParameters::ANTIBANDING_AUTO) ?
+ ANDROID_CONTROL_AE_ANTIBANDING_AUTO :
+ !strcmp(abMode, CameraParameters::ANTIBANDING_OFF) ?
+ ANDROID_CONTROL_AE_ANTIBANDING_OFF :
+ !strcmp(abMode, CameraParameters::ANTIBANDING_50HZ) ?
+ ANDROID_CONTROL_AE_ANTIBANDING_50HZ :
+ !strcmp(abMode, CameraParameters::ANTIBANDING_60HZ) ?
+ ANDROID_CONTROL_AE_ANTIBANDING_60HZ :
+ -1;
+}
+
+int Camera2Client::sceneModeStringToEnum(const char *sceneMode) {
+ return
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_AUTO) ?
+ ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_ACTION) ?
+ ANDROID_CONTROL_SCENE_MODE_ACTION :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_PORTRAIT) ?
+ ANDROID_CONTROL_SCENE_MODE_PORTRAIT :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_LANDSCAPE) ?
+ ANDROID_CONTROL_SCENE_MODE_LANDSCAPE :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_NIGHT) ?
+ ANDROID_CONTROL_SCENE_MODE_NIGHT :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_NIGHT_PORTRAIT) ?
+ ANDROID_CONTROL_SCENE_MODE_NIGHT_PORTRAIT :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_THEATRE) ?
+ ANDROID_CONTROL_SCENE_MODE_THEATRE :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_BEACH) ?
+ ANDROID_CONTROL_SCENE_MODE_BEACH :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_SNOW) ?
+ ANDROID_CONTROL_SCENE_MODE_SNOW :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_SUNSET) ?
+ ANDROID_CONTROL_SCENE_MODE_SUNSET :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_STEADYPHOTO) ?
+ ANDROID_CONTROL_SCENE_MODE_STEADYPHOTO :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_FIREWORKS) ?
+ ANDROID_CONTROL_SCENE_MODE_FIREWORKS :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_SPORTS) ?
+ ANDROID_CONTROL_SCENE_MODE_SPORTS :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_PARTY) ?
+ ANDROID_CONTROL_SCENE_MODE_PARTY :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_CANDLELIGHT) ?
+ ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_BARCODE) ?
+ ANDROID_CONTROL_SCENE_MODE_BARCODE:
+ -1;
+}
+
+Camera2Client::Parameters::flashMode_t Camera2Client::flashModeStringToEnum(
+ const char *flashMode) {
+ return
+ !strcmp(flashMode, CameraParameters::FLASH_MODE_OFF) ?
+ Parameters::FLASH_MODE_OFF :
+ !strcmp(flashMode, CameraParameters::FLASH_MODE_AUTO) ?
+ Parameters::FLASH_MODE_AUTO :
+ !strcmp(flashMode, CameraParameters::FLASH_MODE_ON) ?
+ Parameters::FLASH_MODE_ON :
+ !strcmp(flashMode, CameraParameters::FLASH_MODE_RED_EYE) ?
+ Parameters::FLASH_MODE_RED_EYE :
+ !strcmp(flashMode, CameraParameters::FLASH_MODE_TORCH) ?
+ Parameters::FLASH_MODE_TORCH :
+ Parameters::FLASH_MODE_INVALID;
+}
+
+Camera2Client::Parameters::focusMode_t Camera2Client::focusModeStringToEnum(
+ const char *focusMode) {
+ return
+ !strcmp(focusMode, CameraParameters::FOCUS_MODE_AUTO) ?
+ Parameters::FOCUS_MODE_AUTO :
+ !strcmp(focusMode, CameraParameters::FOCUS_MODE_INFINITY) ?
+ Parameters::FOCUS_MODE_INFINITY :
+ !strcmp(focusMode, CameraParameters::FOCUS_MODE_MACRO) ?
+ Parameters::FOCUS_MODE_MACRO :
+ !strcmp(focusMode, CameraParameters::FOCUS_MODE_FIXED) ?
+ Parameters::FOCUS_MODE_FIXED :
+ !strcmp(focusMode, CameraParameters::FOCUS_MODE_EDOF) ?
+ Parameters::FOCUS_MODE_EDOF :
+ !strcmp(focusMode, CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO) ?
+ Parameters::FOCUS_MODE_CONTINUOUS_VIDEO :
+ !strcmp(focusMode, CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE) ?
+ Parameters::FOCUS_MODE_CONTINUOUS_PICTURE :
+ Parameters::FOCUS_MODE_INVALID;
+}
+
+status_t Camera2Client::parseAreas(const char *areasCStr,
+ Vector<Parameters::Area> *areas) {
+ static const size_t NUM_FIELDS = 5;
+ areas->clear();
+ if (areasCStr == NULL) {
+ // If no key exists, use default (0,0,0,0,0)
+ areas->push();
+ return OK;
+ }
+ String8 areasStr(areasCStr);
+ ssize_t areaStart = areasStr.find("(", 0) + 1;
+ while (areaStart != 0) {
+ const char* area = areasStr.string() + areaStart;
+ char *numEnd;
+ int vals[NUM_FIELDS];
+ for (size_t i = 0; i < NUM_FIELDS; i++) {
+ errno = 0;
+ vals[i] = strtol(area, &numEnd, 10);
+ if (errno || numEnd == area) return BAD_VALUE;
+ area = numEnd + 1;
+ }
+ areas->push(Parameters::Area(
+ vals[0], vals[1], vals[2], vals[3], vals[4]) );
+ areaStart = areasStr.find("(", areaStart) + 1;
+ }
+ return OK;
+}
+
+status_t Camera2Client::validateAreas(const Vector<Parameters::Area> &areas,
+ size_t maxRegions) {
+ // Definition of valid area can be found in
+ // include/camera/CameraParameters.h
+ if (areas.size() == 0) return BAD_VALUE;
+ if (areas.size() == 1) {
+ if (areas[0].left == 0 &&
+ areas[0].top == 0 &&
+ areas[0].right == 0 &&
+ areas[0].bottom == 0 &&
+ areas[0].weight == 0) {
+ // Single (0,0,0,0,0) entry is always valid (== driver decides)
+ return OK;
+ }
+ }
+ if (areas.size() > maxRegions) {
+ ALOGE("%s: Too many areas requested: %d",
+ __FUNCTION__, areas.size());
+ return BAD_VALUE;
+ }
+
+ for (Vector<Parameters::Area>::const_iterator a = areas.begin();
+ a != areas.end(); a++) {
+ if (a->weight < 1 || a->weight > 1000) return BAD_VALUE;
+ if (a->left < -1000 || a->left > 1000) return BAD_VALUE;
+ if (a->top < -1000 || a->top > 1000) return BAD_VALUE;
+ if (a->right < -1000 || a->right > 1000) return BAD_VALUE;
+ if (a->bottom < -1000 || a->bottom > 1000) return BAD_VALUE;
+ if (a->left >= a->right) return BAD_VALUE;
+ if (a->top >= a->bottom) return BAD_VALUE;
+ }
+ return OK;
+}
+
+bool Camera2Client::boolFromString(const char *boolStr) {
+ return !boolStr ? false :
+ !strcmp(boolStr, CameraParameters::TRUE) ? true :
+ false;
+}
+
+int Camera2Client::degToTransform(int degrees, bool mirror) {
+ if (!mirror) {
+ if (degrees == 0) return 0;
+ else if (degrees == 90) return HAL_TRANSFORM_ROT_90;
+ else if (degrees == 180) return HAL_TRANSFORM_ROT_180;
+ else if (degrees == 270) return HAL_TRANSFORM_ROT_270;
+ } else { // Do mirror (horizontal flip)
+ if (degrees == 0) { // FLIP_H and ROT_0
+ return HAL_TRANSFORM_FLIP_H;
+ } else if (degrees == 90) { // FLIP_H and ROT_90
+ return HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90;
+ } else if (degrees == 180) { // FLIP_H and ROT_180
+ return HAL_TRANSFORM_FLIP_V;
+ } else if (degrees == 270) { // FLIP_H and ROT_270
+ return HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90;
+ }
+ }
+ ALOGE("%s: Bad input: %d", __FUNCTION__, degrees);
+ return -1;
+}
+
+} // namespace android
diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h
new file mode 100644
index 0000000..2dc02bc
--- /dev/null
+++ b/services/camera/libcameraservice/Camera2Client.h
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2012 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_SERVERS_CAMERA_CAMERA2CLIENT_H
+#define ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_H
+
+#include "Camera2Device.h"
+#include "CameraService.h"
+#include "camera/CameraParameters.h"
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
+#include <gui/CpuConsumer.h>
+
+namespace android {
+
+/**
+ * Implements the android.hardware.camera API on top of
+ * camera device HAL version 2.
+ */
+class Camera2Client : public CameraService::Client
+{
+public:
+ // ICamera interface (see ICamera for details)
+ virtual void disconnect();
+ virtual status_t connect(const sp<ICameraClient>& client);
+ virtual status_t lock();
+ virtual status_t unlock();
+ virtual status_t setPreviewDisplay(const sp<Surface>& surface);
+ virtual status_t setPreviewTexture(
+ const sp<ISurfaceTexture>& surfaceTexture);
+ virtual void setPreviewCallbackFlag(int flag);
+ virtual status_t startPreview();
+ virtual void stopPreview();
+ virtual bool previewEnabled();
+ virtual status_t storeMetaDataInBuffers(bool enabled);
+ virtual status_t startRecording();
+ virtual void stopRecording();
+ virtual bool recordingEnabled();
+ virtual void releaseRecordingFrame(const sp<IMemory>& mem);
+ virtual status_t autoFocus();
+ virtual status_t cancelAutoFocus();
+ virtual status_t takePicture(int msgType);
+ virtual status_t setParameters(const String8& params);
+ virtual String8 getParameters() const;
+ virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
+
+ // Interface used by CameraService
+ Camera2Client(const sp<CameraService>& cameraService,
+ const sp<ICameraClient>& cameraClient,
+ int cameraId,
+ int cameraFacing,
+ int clientPid);
+ ~Camera2Client();
+
+ status_t initialize(camera_module_t *module);
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+private:
+ enum State {
+ NOT_INITIALIZED,
+ STOPPED,
+ WAITING_FOR_PREVIEW_WINDOW,
+ PREVIEW,
+ RECORD,
+ STILL_CAPTURE,
+ VIDEO_SNAPSHOT
+ } mState;
+
+ static const char *getStateName(State state);
+
+ /** ICamera interface-related private members */
+
+ // Mutex that must be locked by methods implementing the ICamera interface.
+ // Ensures serialization between incoming ICamera calls
+ mutable Mutex mICameraLock;
+
+ // The following must be called with mICamaeraLock already locked
+
+ status_t setPreviewWindowLocked(const sp<IBinder>& binder,
+ sp<ANativeWindow> window);
+
+ void stopPreviewLocked();
+ status_t startPreviewLocked();
+
+ // Mutex that must be locked before accessing mParameters, mParamsFlattened
+ mutable Mutex mParamsLock;
+ String8 mParamsFlattened;
+ // Current camera state; this is the contents of the CameraParameters object
+ // in a more-efficient format. The enum values are mostly based off the
+ // corresponding camera2 enums, not the camera1 strings. A few are defined
+ // here if they don't cleanly map to camera2 values.
+ struct Parameters {
+ int previewWidth, previewHeight;
+ int32_t previewFpsRange[2];
+ int previewFps; // deprecated, here only for tracking changes
+ int previewFormat;
+
+ int previewTransform; // set by CAMERA_CMD_SET_DISPLAY_ORIENTATION
+
+ int pictureWidth, pictureHeight;
+
+ int32_t jpegThumbSize[2];
+ int32_t jpegQuality, jpegThumbQuality;
+ int32_t jpegRotation;
+
+ bool gpsEnabled;
+ double gpsCoordinates[3];
+ int64_t gpsTimestamp;
+ String8 gpsProcessingMethod;
+
+ int wbMode;
+ int effectMode;
+ int antibandingMode;
+ int sceneMode;
+
+ enum flashMode_t {
+ FLASH_MODE_OFF = 0,
+ FLASH_MODE_AUTO,
+ FLASH_MODE_ON,
+ FLASH_MODE_TORCH,
+ FLASH_MODE_RED_EYE = ANDROID_CONTROL_AE_ON_AUTO_FLASH_REDEYE,
+ FLASH_MODE_INVALID = -1
+ } flashMode;
+
+ enum focusMode_t {
+ FOCUS_MODE_AUTO = ANDROID_CONTROL_AF_AUTO,
+ FOCUS_MODE_MACRO = ANDROID_CONTROL_AF_MACRO,
+ FOCUS_MODE_CONTINUOUS_VIDEO = ANDROID_CONTROL_AF_CONTINUOUS_VIDEO,
+ FOCUS_MODE_CONTINUOUS_PICTURE =
+ ANDROID_CONTROL_AF_CONTINUOUS_PICTURE,
+ FOCUS_MODE_EDOF = ANDROID_CONTROL_AF_EDOF,
+ FOCUS_MODE_INFINITY,
+ FOCUS_MODE_FIXED,
+ FOCUS_MODE_INVALID = -1
+ } focusMode;
+
+ struct Area {
+ int left, top, right, bottom;
+ int weight;
+ Area() {}
+ Area(int left, int top, int right, int bottom, int weight):
+ left(left), top(top), right(right), bottom(bottom),
+ weight(weight) {}
+ };
+ Vector<Area> focusingAreas;
+
+ int32_t exposureCompensation;
+ bool autoExposureLock;
+ bool autoWhiteBalanceLock;
+
+ Vector<Area> meteringAreas;
+
+ int zoom;
+
+ int videoWidth, videoHeight;
+
+ bool recordingHint;
+ bool videoStabilization;
+ } mParameters;
+
+ /** Camera device-related private members */
+
+ // Simple listener that forwards frame available notifications from
+ // a CPU consumer to the capture notification
+ class CaptureWaiter: public CpuConsumer::FrameAvailableListener {
+ public:
+ CaptureWaiter(Camera2Client *parent) : mParent(parent) {}
+ void onFrameAvailable() { mParent->onCaptureAvailable(); }
+ private:
+ Camera2Client *mParent;
+ };
+
+ void onCaptureAvailable();
+
+ // Number of zoom steps to simulate
+ static const unsigned int NUM_ZOOM_STEPS = 10;
+ // Used with mPreviewStreamId, mCaptureStreamId
+ static const int NO_STREAM = -1;
+
+ sp<IBinder> mPreviewSurface;
+ sp<ANativeWindow> mPreviewWindow;
+
+ int mPreviewStreamId;
+ camera_metadata_t *mPreviewRequest;
+
+ int mCaptureStreamId;
+ sp<CpuConsumer> mCaptureConsumer;
+ sp<ANativeWindow> mCaptureWindow;
+ sp<CaptureWaiter> mCaptureWaiter;
+ camera_metadata_t *mCaptureRequest;
+ sp<MemoryHeapBase> mCaptureHeap;
+ sp<MemoryBase> mCaptureMemory;
+
+ sp<Camera2Device> mDevice;
+
+
+ // Get values for static camera info entry. min/maxCount are used for error
+ // checking the number of values in the entry. 0 for max/minCount means to
+ // do no bounds check in that direction. In case of error, the entry data
+ // pointer is null and the count is 0.
+ camera_metadata_entry_t staticInfo(uint32_t tag,
+ size_t minCount=0, size_t maxCount=0);
+
+ /** Utility methods */
+
+ // Convert static camera info from a camera2 device to the
+ // old API parameter map.
+ status_t buildDefaultParameters();
+
+ // Update preview request based on mParameters
+ status_t updatePreviewRequest();
+ // Update preview stream based on mParameters
+ status_t updatePreviewStream();
+
+ // Update capture request based on mParameters
+ status_t updateCaptureRequest();
+ // Update capture stream based on mParameters
+ status_t updateCaptureStream();
+
+ // Update parameters all requests use, based on mParameters
+ status_t updateRequestCommon(camera_metadata_t *request);
+
+ // Update specific metadata entry with new values. Adds entry if it does not
+ // exist, which will invalidate sorting
+ static status_t updateEntry(camera_metadata_t *buffer,
+ uint32_t tag, const void *data, size_t data_count);
+
+ // Remove metadata entry. Will invalidate sorting. If entry does not exist,
+ // does nothing.
+ static status_t deleteEntry(camera_metadata_t *buffer,
+ uint32_t tag);
+
+ // Convert camera1 preview format string to camera2 enum
+ static int formatStringToEnum(const char *format);
+ static const char *formatEnumToString(int format);
+
+ static int wbModeStringToEnum(const char *wbMode);
+ static int effectModeStringToEnum(const char *effectMode);
+ static int abModeStringToEnum(const char *abMode);
+ static int sceneModeStringToEnum(const char *sceneMode);
+ static Parameters::flashMode_t flashModeStringToEnum(const char *flashMode);
+ static Parameters::focusMode_t focusModeStringToEnum(const char *focusMode);
+ static status_t parseAreas(const char *areasCStr,
+ Vector<Parameters::Area> *areas);
+ static status_t validateAreas(const Vector<Parameters::Area> &areas,
+ size_t maxRegions);
+ static bool boolFromString(const char *boolStr);
+
+ // Map from camera orientation + facing to gralloc transform enum
+ static int degToTransform(int degrees, bool mirror);
+};
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp
new file mode 100644
index 0000000..8d07eee
--- /dev/null
+++ b/services/camera/libcameraservice/Camera2Device.cpp
@@ -0,0 +1,941 @@
+/*
+ * Copyright (C) 2012 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 "Camera2Device"
+//#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0 // Per-frame verbose logging
+
+#ifdef LOG_NNDEBUG
+#define ALOGVV(...) ALOGV(__VA_ARGS__)
+#else
+#define ALOGVV(...) ((void)0)
+#endif
+
+#include <utils/Log.h>
+#include "Camera2Device.h"
+
+namespace android {
+
+Camera2Device::Camera2Device(int id):
+ mId(id),
+ mDevice(NULL)
+{
+ ALOGV("%s: E", __FUNCTION__);
+}
+
+Camera2Device::~Camera2Device()
+{
+ ALOGV("%s: E", __FUNCTION__);
+ if (mDevice) {
+ status_t res;
+ res = mDevice->common.close(&mDevice->common);
+ if (res != OK) {
+ ALOGE("%s: Could not close camera %d: %s (%d)",
+ __FUNCTION__,
+ mId, strerror(-res), res);
+ }
+ mDevice = NULL;
+ }
+}
+
+status_t Camera2Device::initialize(camera_module_t *module)
+{
+ ALOGV("%s: E", __FUNCTION__);
+
+ status_t res;
+ char name[10];
+ snprintf(name, sizeof(name), "%d", mId);
+
+ res = module->common.methods->open(&module->common, name,
+ reinterpret_cast<hw_device_t**>(&mDevice));
+
+ if (res != OK) {
+ ALOGE("%s: Could not open camera %d: %s (%d)", __FUNCTION__,
+ mId, strerror(-res), res);
+ return res;
+ }
+
+ if (mDevice->common.version != CAMERA_DEVICE_API_VERSION_2_0) {
+ ALOGE("%s: Could not open camera %d: "
+ "Camera device is not version %x, reports %x instead",
+ __FUNCTION__, mId, CAMERA_DEVICE_API_VERSION_2_0,
+ mDevice->common.version);
+ return BAD_VALUE;
+ }
+
+ camera_info info;
+ res = module->get_camera_info(mId, &info);
+ if (res != OK ) return res;
+
+ if (info.device_version != mDevice->common.version) {
+ ALOGE("%s: HAL reporting mismatched camera_info version (%x)"
+ " and device version (%x).", __FUNCTION__,
+ mDevice->common.version, info.device_version);
+ return BAD_VALUE;
+ }
+
+ mDeviceInfo = info.static_camera_characteristics;
+
+ res = mRequestQueue.setConsumerDevice(mDevice);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to connect request queue to device: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return res;
+ }
+ res = mFrameQueue.setProducerDevice(mDevice);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to connect frame queue to device: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return res;
+ }
+
+ res = mDevice->ops->get_metadata_vendor_tag_ops(mDevice, &mVendorTagOps);
+ if (res != OK ) {
+ ALOGE("%s: Camera %d: Unable to retrieve tag ops from device: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return res;
+ }
+
+ return OK;
+}
+
+status_t Camera2Device::dump(int fd, const Vector<String16>& args) {
+
+ String8 result;
+
+ result.appendFormat(" Camera2Device[%d] dump:\n", mId);
+
+ result.appendFormat(" Static camera information metadata:\n");
+ write(fd, result.string(), result.size());
+ dump_camera_metadata(mDeviceInfo, fd, 2);
+
+ result = " Request queue contents:\n";
+ write(fd, result.string(), result.size());
+ mRequestQueue.dump(fd, args);
+
+ result = " Frame queue contents:\n";
+ write(fd, result.string(), result.size());
+ mFrameQueue.dump(fd, args);
+
+ result = " Active streams:\n";
+ write(fd, result.string(), result.size());
+ for (StreamList::iterator s = mStreams.begin(); s != mStreams.end(); s++) {
+ (*s)->dump(fd, args);
+ }
+
+ result = " HAL device dump:\n";
+ write(fd, result.string(), result.size());
+
+ status_t res;
+ res = mDevice->ops->dump(mDevice, fd);
+
+ return res;
+}
+
+camera_metadata_t *Camera2Device::info() {
+ ALOGV("%s: E", __FUNCTION__);
+
+ return mDeviceInfo;
+}
+
+status_t Camera2Device::capture(camera_metadata_t* request) {
+ ALOGV("%s: E", __FUNCTION__);
+
+ mRequestQueue.enqueue(request);
+ return OK;
+}
+
+
+status_t Camera2Device::setStreamingRequest(camera_metadata_t* request) {
+ ALOGV("%s: E", __FUNCTION__);
+
+ mRequestQueue.setStreamSlot(request);
+ return OK;
+}
+
+status_t Camera2Device::createStream(sp<ANativeWindow> consumer,
+ uint32_t width, uint32_t height, int format, size_t size, int *id) {
+ status_t res;
+ ALOGV("%s: E", __FUNCTION__);
+
+ sp<StreamAdapter> stream = new StreamAdapter(mDevice);
+
+ res = stream->connectToDevice(consumer, width, height, format, size);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to create stream (%d x %d, format %x):"
+ "%s (%d)",
+ __FUNCTION__, mId, width, height, format, strerror(-res), res);
+ return res;
+ }
+
+ *id = stream->getId();
+
+ mStreams.push_back(stream);
+ return OK;
+}
+
+status_t Camera2Device::getStreamInfo(int id,
+ uint32_t *width, uint32_t *height, uint32_t *format) {
+ ALOGV("%s: E", __FUNCTION__);
+ bool found = false;
+ StreamList::iterator streamI;
+ for (streamI = mStreams.begin();
+ streamI != mStreams.end(); streamI++) {
+ if ((*streamI)->getId() == id) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ ALOGE("%s: Camera %d: Stream %d does not exist",
+ __FUNCTION__, mId, id);
+ return BAD_VALUE;
+ }
+
+ if (width) *width = (*streamI)->getWidth();
+ if (height) *height = (*streamI)->getHeight();
+ if (format) *format = (*streamI)->getFormat();
+
+ return OK;
+}
+
+status_t Camera2Device::setStreamTransform(int id,
+ int transform) {
+ ALOGV("%s: E", __FUNCTION__);
+ bool found = false;
+ StreamList::iterator streamI;
+ for (streamI = mStreams.begin();
+ streamI != mStreams.end(); streamI++) {
+ if ((*streamI)->getId() == id) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ ALOGE("%s: Camera %d: Stream %d does not exist",
+ __FUNCTION__, mId, id);
+ return BAD_VALUE;
+ }
+
+ return (*streamI)->setTransform(transform);
+}
+
+status_t Camera2Device::deleteStream(int id) {
+ ALOGV("%s: E", __FUNCTION__);
+ bool found = false;
+ for (StreamList::iterator streamI = mStreams.begin();
+ streamI != mStreams.end(); streamI++) {
+ if ((*streamI)->getId() == id) {
+ status_t res = (*streamI)->disconnect();
+ if (res != OK) {
+ ALOGE("%s: Unable to disconnect stream %d from HAL device: "
+ "%s (%d)", __FUNCTION__, id, strerror(-res), res);
+ return res;
+ }
+ mStreams.erase(streamI);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ ALOGE("%s: Camera %d: Unable to find stream %d to delete",
+ __FUNCTION__, mId, id);
+ return BAD_VALUE;
+ }
+ return OK;
+}
+
+status_t Camera2Device::createDefaultRequest(int templateId,
+ camera_metadata_t **request) {
+ ALOGV("%s: E", __FUNCTION__);
+ return mDevice->ops->construct_default_request(
+ mDevice, templateId, request);
+}
+
+status_t Camera2Device::waitUntilDrained() {
+ static const uint32_t kSleepTime = 50000; // 50 ms
+ static const uint32_t kMaxSleepTime = 10000000; // 10 s
+
+ if (mRequestQueue.getBufferCount() ==
+ CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS) return INVALID_OPERATION;
+
+ // TODO: Set up notifications from HAL, instead of sleeping here
+ uint32_t totalTime = 0;
+ while (mDevice->ops->get_in_progress_count(mDevice) > 0) {
+ usleep(kSleepTime);
+ totalTime += kSleepTime;
+ if (totalTime > kMaxSleepTime) {
+ ALOGE("%s: Waited %d us, requests still in flight", __FUNCTION__,
+ totalTime);
+ return TIMED_OUT;
+ }
+ }
+ return OK;
+}
+
+/**
+ * Camera2Device::MetadataQueue
+ */
+
+Camera2Device::MetadataQueue::MetadataQueue():
+ mDevice(NULL),
+ mFrameCount(0),
+ mCount(0),
+ mStreamSlotCount(0),
+ mSignalConsumer(true)
+{
+ camera2_request_queue_src_ops::dequeue_request = consumer_dequeue;
+ camera2_request_queue_src_ops::request_count = consumer_buffer_count;
+ camera2_request_queue_src_ops::free_request = consumer_free;
+
+ camera2_frame_queue_dst_ops::dequeue_frame = producer_dequeue;
+ camera2_frame_queue_dst_ops::cancel_frame = producer_cancel;
+ camera2_frame_queue_dst_ops::enqueue_frame = producer_enqueue;
+}
+
+Camera2Device::MetadataQueue::~MetadataQueue() {
+ Mutex::Autolock l(mMutex);
+ freeBuffers(mEntries.begin(), mEntries.end());
+ freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
+}
+
+// Connect to camera2 HAL as consumer (input requests/reprocessing)
+status_t Camera2Device::MetadataQueue::setConsumerDevice(camera2_device_t *d) {
+ status_t res;
+ res = d->ops->set_request_queue_src_ops(d,
+ this);
+ if (res != OK) return res;
+ mDevice = d;
+ return OK;
+}
+
+status_t Camera2Device::MetadataQueue::setProducerDevice(camera2_device_t *d) {
+ status_t res;
+ res = d->ops->set_frame_queue_dst_ops(d,
+ this);
+ return res;
+}
+
+// Real interfaces
+status_t Camera2Device::MetadataQueue::enqueue(camera_metadata_t *buf) {
+ ALOGVV("%s: E", __FUNCTION__);
+ Mutex::Autolock l(mMutex);
+
+ mCount++;
+ mEntries.push_back(buf);
+
+ return signalConsumerLocked();
+}
+
+int Camera2Device::MetadataQueue::getBufferCount() {
+ Mutex::Autolock l(mMutex);
+ if (mStreamSlotCount > 0) {
+ return CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS;
+ }
+ return mCount;
+}
+
+status_t Camera2Device::MetadataQueue::dequeue(camera_metadata_t **buf,
+ bool incrementCount)
+{
+ ALOGVV("%s: E", __FUNCTION__);
+ status_t res;
+ Mutex::Autolock l(mMutex);
+
+ if (mCount == 0) {
+ if (mStreamSlotCount == 0) {
+ ALOGVV("%s: Empty", __FUNCTION__);
+ *buf = NULL;
+ mSignalConsumer = true;
+ return OK;
+ }
+ ALOGVV("%s: Streaming %d frames to queue", __FUNCTION__,
+ mStreamSlotCount);
+
+ for (List<camera_metadata_t*>::iterator slotEntry = mStreamSlot.begin();
+ slotEntry != mStreamSlot.end();
+ slotEntry++ ) {
+ size_t entries = get_camera_metadata_entry_count(*slotEntry);
+ size_t dataBytes = get_camera_metadata_data_count(*slotEntry);
+
+ camera_metadata_t *copy =
+ allocate_camera_metadata(entries, dataBytes);
+ append_camera_metadata(copy, *slotEntry);
+ mEntries.push_back(copy);
+ }
+ mCount = mStreamSlotCount;
+ }
+ ALOGVV("MetadataQueue: deque (%d buffers)", mCount);
+ camera_metadata_t *b = *(mEntries.begin());
+ mEntries.erase(mEntries.begin());
+
+ if (incrementCount) {
+ camera_metadata_entry_t frameCount;
+ res = find_camera_metadata_entry(b,
+ ANDROID_REQUEST_FRAME_COUNT,
+ &frameCount);
+ if (res != OK) {
+ ALOGE("%s: Unable to add frame count: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ } else {
+ *frameCount.data.i32 = mFrameCount;
+ }
+ mFrameCount++;
+ }
+
+ *buf = b;
+ mCount--;
+
+ return OK;
+}
+
+status_t Camera2Device::MetadataQueue::waitForBuffer(nsecs_t timeout)
+{
+ Mutex::Autolock l(mMutex);
+ status_t res;
+ while (mCount == 0) {
+ res = notEmpty.waitRelative(mMutex,timeout);
+ if (res != OK) return res;
+ }
+ return OK;
+}
+
+status_t Camera2Device::MetadataQueue::setStreamSlot(camera_metadata_t *buf)
+{
+ ALOGV("%s: E", __FUNCTION__);
+ Mutex::Autolock l(mMutex);
+ if (buf == NULL) {
+ freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
+ mStreamSlotCount = 0;
+ return OK;
+ }
+ camera_metadata_t *buf2 = clone_camera_metadata(buf);
+ if (!buf2) {
+ ALOGE("%s: Unable to clone metadata buffer!", __FUNCTION__);
+ return NO_MEMORY;
+ }
+
+ if (mStreamSlotCount > 1) {
+ List<camera_metadata_t*>::iterator deleter = ++mStreamSlot.begin();
+ freeBuffers(++mStreamSlot.begin(), mStreamSlot.end());
+ mStreamSlotCount = 1;
+ }
+ if (mStreamSlotCount == 1) {
+ free_camera_metadata( *(mStreamSlot.begin()) );
+ *(mStreamSlot.begin()) = buf2;
+ } else {
+ mStreamSlot.push_front(buf2);
+ mStreamSlotCount = 1;
+ }
+ return signalConsumerLocked();
+}
+
+status_t Camera2Device::MetadataQueue::setStreamSlot(
+ const List<camera_metadata_t*> &bufs)
+{
+ ALOGV("%s: E", __FUNCTION__);
+ Mutex::Autolock l(mMutex);
+ status_t res;
+
+ if (mStreamSlotCount > 0) {
+ freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
+ }
+ mStreamSlotCount = 0;
+ for (List<camera_metadata_t*>::const_iterator r = bufs.begin();
+ r != bufs.end(); r++) {
+ camera_metadata_t *r2 = clone_camera_metadata(*r);
+ if (!r2) {
+ ALOGE("%s: Unable to clone metadata buffer!", __FUNCTION__);
+ return NO_MEMORY;
+ }
+ mStreamSlot.push_back(r2);
+ mStreamSlotCount++;
+ }
+ return signalConsumerLocked();
+}
+
+status_t Camera2Device::MetadataQueue::dump(int fd,
+ const Vector<String16>& args) {
+ String8 result;
+ status_t notLocked;
+ notLocked = mMutex.tryLock();
+ if (notLocked) {
+ result.append(" (Unable to lock queue mutex)\n");
+ }
+ result.appendFormat(" Current frame number: %d\n", mFrameCount);
+ if (mStreamSlotCount == 0) {
+ result.append(" Stream slot: Empty\n");
+ write(fd, result.string(), result.size());
+ } else {
+ result.appendFormat(" Stream slot: %d entries\n",
+ mStreamSlot.size());
+ int i = 0;
+ for (List<camera_metadata_t*>::iterator r = mStreamSlot.begin();
+ r != mStreamSlot.end(); r++) {
+ result = String8::format(" Stream slot buffer %d:\n", i);
+ write(fd, result.string(), result.size());
+ dump_camera_metadata(*r, fd, 2);
+ i++;
+ }
+ }
+ if (mEntries.size() == 0) {
+ result = " Main queue is empty\n";
+ write(fd, result.string(), result.size());
+ } else {
+ result = String8::format(" Main queue has %d entries:\n",
+ mEntries.size());
+ int i = 0;
+ for (List<camera_metadata_t*>::iterator r = mEntries.begin();
+ r != mEntries.end(); r++) {
+ result = String8::format(" Queue entry %d:\n", i);
+ write(fd, result.string(), result.size());
+ dump_camera_metadata(*r, fd, 2);
+ i++;
+ }
+ }
+
+ if (notLocked == 0) {
+ mMutex.unlock();
+ }
+
+ return OK;
+}
+
+status_t Camera2Device::MetadataQueue::signalConsumerLocked() {
+ status_t res = OK;
+ notEmpty.signal();
+ if (mSignalConsumer && mDevice != NULL) {
+ mSignalConsumer = false;
+
+ mMutex.unlock();
+ ALOGV("%s: Signaling consumer", __FUNCTION__);
+ res = mDevice->ops->notify_request_queue_not_empty(mDevice);
+ mMutex.lock();
+ }
+ return res;
+}
+
+status_t Camera2Device::MetadataQueue::freeBuffers(
+ List<camera_metadata_t*>::iterator start,
+ List<camera_metadata_t*>::iterator end)
+{
+ while (start != end) {
+ free_camera_metadata(*start);
+ start = mStreamSlot.erase(start);
+ }
+ return OK;
+}
+
+Camera2Device::MetadataQueue* Camera2Device::MetadataQueue::getInstance(
+ const camera2_request_queue_src_ops_t *q)
+{
+ const MetadataQueue* cmq = static_cast<const MetadataQueue*>(q);
+ return const_cast<MetadataQueue*>(cmq);
+}
+
+Camera2Device::MetadataQueue* Camera2Device::MetadataQueue::getInstance(
+ const camera2_frame_queue_dst_ops_t *q)
+{
+ const MetadataQueue* cmq = static_cast<const MetadataQueue*>(q);
+ return const_cast<MetadataQueue*>(cmq);
+}
+
+int Camera2Device::MetadataQueue::consumer_buffer_count(
+ const camera2_request_queue_src_ops_t *q)
+{
+ MetadataQueue *queue = getInstance(q);
+ return queue->getBufferCount();
+}
+
+int Camera2Device::MetadataQueue::consumer_dequeue(
+ const camera2_request_queue_src_ops_t *q,
+ camera_metadata_t **buffer)
+{
+ MetadataQueue *queue = getInstance(q);
+ return queue->dequeue(buffer, true);
+}
+
+int Camera2Device::MetadataQueue::consumer_free(
+ const camera2_request_queue_src_ops_t *q,
+ camera_metadata_t *old_buffer)
+{
+ MetadataQueue *queue = getInstance(q);
+ free_camera_metadata(old_buffer);
+ return OK;
+}
+
+int Camera2Device::MetadataQueue::producer_dequeue(
+ const camera2_frame_queue_dst_ops_t *q,
+ size_t entries, size_t bytes,
+ camera_metadata_t **buffer)
+{
+ camera_metadata_t *new_buffer =
+ allocate_camera_metadata(entries, bytes);
+ if (new_buffer == NULL) return NO_MEMORY;
+ *buffer = new_buffer;
+ return OK;
+}
+
+int Camera2Device::MetadataQueue::producer_cancel(
+ const camera2_frame_queue_dst_ops_t *q,
+ camera_metadata_t *old_buffer)
+{
+ free_camera_metadata(old_buffer);
+ return OK;
+}
+
+int Camera2Device::MetadataQueue::producer_enqueue(
+ const camera2_frame_queue_dst_ops_t *q,
+ camera_metadata_t *filled_buffer)
+{
+ MetadataQueue *queue = getInstance(q);
+ return queue->enqueue(filled_buffer);
+}
+
+/**
+ * Camera2Device::StreamAdapter
+ */
+
+#ifndef container_of
+#define container_of(ptr, type, member) \
+ (type *)((char*)(ptr) - offsetof(type, member))
+#endif
+
+Camera2Device::StreamAdapter::StreamAdapter(camera2_device_t *d):
+ mState(DISCONNECTED),
+ mDevice(d),
+ mId(-1),
+ mWidth(0), mHeight(0), mFormat(0), mSize(0), mUsage(0),
+ mMaxProducerBuffers(0), mMaxConsumerBuffers(0),
+ mTotalBuffers(0),
+ mFormatRequested(0),
+ mActiveBuffers(0),
+ mFrameCount(0),
+ mLastTimestamp(0)
+{
+ camera2_stream_ops::dequeue_buffer = dequeue_buffer;
+ camera2_stream_ops::enqueue_buffer = enqueue_buffer;
+ camera2_stream_ops::cancel_buffer = cancel_buffer;
+ camera2_stream_ops::set_crop = set_crop;
+}
+
+Camera2Device::StreamAdapter::~StreamAdapter() {
+ disconnect();
+}
+
+status_t Camera2Device::StreamAdapter::connectToDevice(
+ sp<ANativeWindow> consumer,
+ uint32_t width, uint32_t height, int format, size_t size) {
+ status_t res;
+
+ if (mState != DISCONNECTED) return INVALID_OPERATION;
+ if (consumer == NULL) {
+ ALOGE("%s: Null consumer passed to stream adapter", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ mConsumerInterface = consumer;
+ mWidth = width;
+ mHeight = height;
+ mSize = (format == HAL_PIXEL_FORMAT_BLOB) ? size : 0;
+ mFormatRequested = format;
+
+ // Allocate device-side stream interface
+
+ uint32_t id;
+ uint32_t formatActual;
+ uint32_t usage;
+ uint32_t maxBuffers = 2;
+ res = mDevice->ops->allocate_stream(mDevice,
+ mWidth, mHeight, mFormatRequested, getStreamOps(),
+ &id, &formatActual, &usage, &maxBuffers);
+ if (res != OK) {
+ ALOGE("%s: Device stream allocation failed: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ mId = id;
+ mFormat = formatActual;
+ mUsage = usage;
+ mMaxProducerBuffers = maxBuffers;
+
+ mState = ALLOCATED;
+
+ // Configure consumer-side ANativeWindow interface
+ res = native_window_api_connect(mConsumerInterface.get(),
+ NATIVE_WINDOW_API_CAMERA);
+ if (res != OK) {
+ ALOGE("%s: Unable to connect to native window for stream %d",
+ __FUNCTION__, mId);
+
+ return res;
+ }
+
+ mState = CONNECTED;
+
+ res = native_window_set_usage(mConsumerInterface.get(), mUsage);
+ if (res != OK) {
+ ALOGE("%s: Unable to configure usage %08x for stream %d",
+ __FUNCTION__, mUsage, mId);
+ return res;
+ }
+
+ res = native_window_set_scaling_mode(mConsumerInterface.get(),
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ if (res != OK) {
+ ALOGE("%s: Unable to configure stream scaling: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ res = setTransform(0);
+ if (res != OK) {
+ return res;
+ }
+
+ if (mFormat == HAL_PIXEL_FORMAT_BLOB) {
+ res = native_window_set_buffers_geometry(mConsumerInterface.get(),
+ mSize, 1, mFormat);
+ if (res != OK) {
+ ALOGE("%s: Unable to configure compressed stream buffer geometry"
+ " %d x %d, size %d for stream %d",
+ __FUNCTION__, mWidth, mHeight, mSize, mId);
+ return res;
+ }
+ } else {
+ res = native_window_set_buffers_geometry(mConsumerInterface.get(),
+ mWidth, mHeight, mFormat);
+ if (res != OK) {
+ ALOGE("%s: Unable to configure stream buffer geometry"
+ " %d x %d, format 0x%x for stream %d",
+ __FUNCTION__, mWidth, mHeight, mFormat, mId);
+ return res;
+ }
+ }
+
+ int maxConsumerBuffers;
+ res = mConsumerInterface->query(mConsumerInterface.get(),
+ NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
+ if (res != OK) {
+ ALOGE("%s: Unable to query consumer undequeued"
+ " buffer count for stream %d", __FUNCTION__, mId);
+ return res;
+ }
+ mMaxConsumerBuffers = maxConsumerBuffers;
+
+ ALOGV("%s: Producer wants %d buffers, consumer wants %d", __FUNCTION__,
+ mMaxProducerBuffers, mMaxConsumerBuffers);
+
+ mTotalBuffers = mMaxConsumerBuffers + mMaxProducerBuffers;
+ mActiveBuffers = 0;
+ mFrameCount = 0;
+ mLastTimestamp = 0;
+
+ res = native_window_set_buffer_count(mConsumerInterface.get(),
+ mTotalBuffers);
+ if (res != OK) {
+ ALOGE("%s: Unable to set buffer count for stream %d",
+ __FUNCTION__, mId);
+ return res;
+ }
+
+ // Register allocated buffers with HAL device
+ buffer_handle_t *buffers = new buffer_handle_t[mTotalBuffers];
+ ANativeWindowBuffer **anwBuffers = new ANativeWindowBuffer*[mTotalBuffers];
+ uint32_t bufferIdx = 0;
+ for (; bufferIdx < mTotalBuffers; bufferIdx++) {
+ res = native_window_dequeue_buffer_and_wait(mConsumerInterface.get(),
+ &anwBuffers[bufferIdx]);
+ if (res != OK) {
+ ALOGE("%s: Unable to dequeue buffer %d for initial registration for"
+ "stream %d", __FUNCTION__, bufferIdx, mId);
+ goto cleanUpBuffers;
+ }
+
+ buffers[bufferIdx] = anwBuffers[bufferIdx]->handle;
+ }
+
+ res = mDevice->ops->register_stream_buffers(mDevice,
+ mId,
+ mTotalBuffers,
+ buffers);
+ if (res != OK) {
+ ALOGE("%s: Unable to register buffers with HAL device for stream %d",
+ __FUNCTION__, mId);
+ } else {
+ mState = ACTIVE;
+ }
+
+cleanUpBuffers:
+ for (uint32_t i = 0; i < bufferIdx; i++) {
+ res = mConsumerInterface->cancelBuffer(mConsumerInterface.get(),
+ anwBuffers[i], -1);
+ if (res != OK) {
+ ALOGE("%s: Unable to cancel buffer %d after registration",
+ __FUNCTION__, i);
+ }
+ }
+ delete[] anwBuffers;
+ delete[] buffers;
+
+ return res;
+}
+
+status_t Camera2Device::StreamAdapter::disconnect() {
+ status_t res;
+ if (mState >= ALLOCATED) {
+ res = mDevice->ops->release_stream(mDevice, mId);
+ if (res != OK) {
+ ALOGE("%s: Unable to release stream %d",
+ __FUNCTION__, mId);
+ return res;
+ }
+ }
+ if (mState >= CONNECTED) {
+ res = native_window_api_disconnect(mConsumerInterface.get(),
+ NATIVE_WINDOW_API_CAMERA);
+ if (res != OK) {
+ ALOGE("%s: Unable to disconnect stream %d from native window",
+ __FUNCTION__, mId);
+ return res;
+ }
+ }
+ mId = -1;
+ mState = DISCONNECTED;
+ return OK;
+}
+
+status_t Camera2Device::StreamAdapter::setTransform(int transform) {
+ status_t res;
+ if (mState < CONNECTED) {
+ ALOGE("%s: Cannot set transform on unconnected stream", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ res = native_window_set_buffers_transform(mConsumerInterface.get(),
+ transform);
+ if (res != OK) {
+ ALOGE("%s: Unable to configure stream transform to %x: %s (%d)",
+ __FUNCTION__, transform, strerror(-res), res);
+ }
+ return res;
+}
+
+status_t Camera2Device::StreamAdapter::dump(int fd,
+ const Vector<String16>& args) {
+ String8 result = String8::format(" Stream %d: %d x %d, format 0x%x\n",
+ mId, mWidth, mHeight, mFormat);
+ result.appendFormat(" size %d, usage 0x%x, requested format 0x%x\n",
+ mSize, mUsage, mFormatRequested);
+ result.appendFormat(" total buffers: %d, dequeued buffers: %d\n",
+ mTotalBuffers, mActiveBuffers);
+ result.appendFormat(" frame count: %d, last timestamp %lld\n",
+ mFrameCount, mLastTimestamp);
+ write(fd, result.string(), result.size());
+ return OK;
+}
+
+const camera2_stream_ops *Camera2Device::StreamAdapter::getStreamOps() {
+ return static_cast<camera2_stream_ops *>(this);
+}
+
+ANativeWindow* Camera2Device::StreamAdapter::toANW(
+ const camera2_stream_ops_t *w) {
+ return static_cast<const StreamAdapter*>(w)->mConsumerInterface.get();
+}
+
+int Camera2Device::StreamAdapter::dequeue_buffer(const camera2_stream_ops_t *w,
+ buffer_handle_t** buffer) {
+ int res;
+ StreamAdapter* stream =
+ const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w));
+ if (stream->mState != ACTIVE) {
+ ALOGE("%s: Called when in bad state: %d", __FUNCTION__, stream->mState);
+ return INVALID_OPERATION;
+ }
+
+ ANativeWindow *a = toANW(w);
+ ANativeWindowBuffer* anb;
+ res = native_window_dequeue_buffer_and_wait(a, &anb);
+ if (res != OK) return res;
+
+ *buffer = &(anb->handle);
+ stream->mActiveBuffers++;
+
+ ALOGVV("%s: Buffer %p", __FUNCTION__, *buffer);
+ return res;
+}
+
+int Camera2Device::StreamAdapter::enqueue_buffer(const camera2_stream_ops_t* w,
+ int64_t timestamp,
+ buffer_handle_t* buffer) {
+ StreamAdapter *stream =
+ const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w));
+ ALOGVV("%s: Stream %d: Buffer %p captured at %lld ns",
+ __FUNCTION__, stream->mId, buffer, timestamp);
+ int state = stream->mState;
+ if (state != ACTIVE) {
+ ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
+ return INVALID_OPERATION;
+ }
+ ANativeWindow *a = toANW(w);
+ status_t err;
+ err = native_window_set_buffers_timestamp(a, timestamp);
+ if (err != OK) {
+ ALOGE("%s: Error setting timestamp on native window: %s (%d)",
+ __FUNCTION__, strerror(-err), err);
+ return err;
+ }
+ err = a->queueBuffer(a,
+ container_of(buffer, ANativeWindowBuffer, handle), -1);
+ if (err != OK) {
+ ALOGE("%s: Error queueing buffer to native window: %s (%d)",
+ __FUNCTION__, strerror(-err), err);
+ }
+ stream->mActiveBuffers--;
+ stream->mFrameCount++;
+ stream->mLastTimestamp = timestamp;
+ return err;
+}
+
+int Camera2Device::StreamAdapter::cancel_buffer(const camera2_stream_ops_t* w,
+ buffer_handle_t* buffer) {
+ StreamAdapter *stream =
+ const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w));
+ if (stream->mState != ACTIVE) {
+ ALOGE("%s: Called when in bad state: %d", __FUNCTION__, stream->mState);
+ return INVALID_OPERATION;
+ }
+ stream->mActiveBuffers--;
+ ANativeWindow *a = toANW(w);
+ return a->cancelBuffer(a,
+ container_of(buffer, ANativeWindowBuffer, handle), -1);
+}
+
+int Camera2Device::StreamAdapter::set_crop(const camera2_stream_ops_t* w,
+ int left, int top, int right, int bottom) {
+ int state = static_cast<const StreamAdapter*>(w)->mState;
+ if (state != ACTIVE) {
+ ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
+ return INVALID_OPERATION;
+ }
+ ANativeWindow *a = toANW(w);
+ android_native_rect_t crop = { left, top, right, bottom };
+ return native_window_set_crop(a, &crop);
+}
+
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/Camera2Device.h b/services/camera/libcameraservice/Camera2Device.h
new file mode 100644
index 0000000..1116be0
--- /dev/null
+++ b/services/camera/libcameraservice/Camera2Device.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2012 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_SERVERS_CAMERA_CAMERA2DEVICE_H
+#define ANDROID_SERVERS_CAMERA_CAMERA2DEVICE_H
+
+#include <utils/Condition.h>
+#include <utils/Errors.h>
+#include <utils/List.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+#include "hardware/camera2.h"
+
+namespace android {
+
+class Camera2Device : public virtual RefBase {
+ public:
+ Camera2Device(int id);
+
+ ~Camera2Device();
+
+ status_t initialize(camera_module_t *module);
+
+ status_t dump(int fd, const Vector<String16>& args);
+
+ /**
+ * Get a pointer to the device's static characteristics metadata buffer
+ */
+ camera_metadata_t* info();
+
+ /**
+ * Submit request for capture. The Camera2Device takes ownership of the
+ * passed-in buffer.
+ */
+ status_t capture(camera_metadata_t *request);
+
+ /**
+ * Submit request for streaming. The Camera2Device makes a copy of the
+ * passed-in buffer and the caller retains ownership.
+ */
+ status_t setStreamingRequest(camera_metadata_t *request);
+
+ /**
+ * Create an output stream of the requested size and format.
+ *
+ * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device selects
+ * an appropriate format; it can be queried with getStreamInfo.
+ *
+ * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must be
+ * equal to the size in bytes of the buffers to allocate for the stream. For
+ * other formats, the size parameter is ignored.
+ */
+ status_t createStream(sp<ANativeWindow> consumer,
+ uint32_t width, uint32_t height, int format, size_t size,
+ int *id);
+
+ /**
+ * Get information about a given stream.
+ */
+ status_t getStreamInfo(int id,
+ uint32_t *width, uint32_t *height, uint32_t *format);
+
+ /**
+ * Set stream gralloc buffer transform
+ */
+ status_t setStreamTransform(int id, int transform);
+
+ /**
+ * Delete stream. Must not be called if there are requests in flight which
+ * reference that stream.
+ */
+ status_t deleteStream(int id);
+
+ /**
+ * Create a metadata buffer with fields that the HAL device believes are
+ * best for the given use case
+ */
+ status_t createDefaultRequest(int templateId,
+ camera_metadata_t **request);
+
+ /**
+ * Wait until all requests have been processed. Returns INVALID_OPERATION if
+ * the streaming slot is not empty, or TIMED_OUT if the requests haven't
+ * finished processing in 10 seconds.
+ */
+ status_t waitUntilDrained();
+
+ private:
+
+ const int mId;
+ camera2_device_t *mDevice;
+
+ camera_metadata_t *mDeviceInfo;
+ vendor_tag_query_ops_t *mVendorTagOps;
+
+ /**
+ * Queue class for both sending requests to a camera2 device, and for
+ * receiving frames from a camera2 device.
+ */
+ class MetadataQueue: public camera2_request_queue_src_ops_t,
+ public camera2_frame_queue_dst_ops_t {
+ public:
+ MetadataQueue();
+ ~MetadataQueue();
+
+ // Interface to camera2 HAL device, either for requests (device is
+ // consumer) or for frames (device is producer)
+ const camera2_request_queue_src_ops_t* getToConsumerInterface();
+ void setFromConsumerInterface(camera2_device_t *d);
+
+ // Connect queue consumer endpoint to a camera2 device
+ status_t setConsumerDevice(camera2_device_t *d);
+ // Connect queue producer endpoint to a camera2 device
+ status_t setProducerDevice(camera2_device_t *d);
+
+ const camera2_frame_queue_dst_ops_t* getToProducerInterface();
+
+ // Real interfaces. On enqueue, queue takes ownership of buffer pointer
+ // On dequeue, user takes ownership of buffer pointer.
+ status_t enqueue(camera_metadata_t *buf);
+ status_t dequeue(camera_metadata_t **buf, bool incrementCount = true);
+ int getBufferCount();
+ status_t waitForBuffer(nsecs_t timeout);
+
+ // Set repeating buffer(s); if the queue is empty on a dequeue call, the
+ // queue copies the contents of the stream slot into the queue, and then
+ // dequeues the first new entry. The metadata buffers passed in are
+ // copied.
+ status_t setStreamSlot(camera_metadata_t *buf);
+ status_t setStreamSlot(const List<camera_metadata_t*> &bufs);
+
+ status_t dump(int fd, const Vector<String16>& args);
+
+ private:
+ status_t signalConsumerLocked();
+ status_t freeBuffers(List<camera_metadata_t*>::iterator start,
+ List<camera_metadata_t*>::iterator end);
+
+ camera2_device_t *mDevice;
+
+ Mutex mMutex;
+ Condition notEmpty;
+
+ int mFrameCount;
+
+ int mCount;
+ List<camera_metadata_t*> mEntries;
+ int mStreamSlotCount;
+ List<camera_metadata_t*> mStreamSlot;
+
+ bool mSignalConsumer;
+
+ static MetadataQueue* getInstance(
+ const camera2_frame_queue_dst_ops_t *q);
+ static MetadataQueue* getInstance(
+ const camera2_request_queue_src_ops_t *q);
+
+ static int consumer_buffer_count(
+ const camera2_request_queue_src_ops_t *q);
+
+ static int consumer_dequeue(const camera2_request_queue_src_ops_t *q,
+ camera_metadata_t **buffer);
+
+ static int consumer_free(const camera2_request_queue_src_ops_t *q,
+ camera_metadata_t *old_buffer);
+
+ static int producer_dequeue(const camera2_frame_queue_dst_ops_t *q,
+ size_t entries, size_t bytes,
+ camera_metadata_t **buffer);
+
+ static int producer_cancel(const camera2_frame_queue_dst_ops_t *q,
+ camera_metadata_t *old_buffer);
+
+ static int producer_enqueue(const camera2_frame_queue_dst_ops_t *q,
+ camera_metadata_t *filled_buffer);
+
+ }; // class MetadataQueue
+
+ MetadataQueue mRequestQueue;
+ MetadataQueue mFrameQueue;
+
+ /**
+ * Adapter from an ANativeWindow interface to camera2 device stream ops.
+ * Also takes care of allocating/deallocating stream in device interface
+ */
+ class StreamAdapter: public camera2_stream_ops, public virtual RefBase {
+ public:
+ StreamAdapter(camera2_device_t *d);
+
+ ~StreamAdapter();
+
+ /**
+ * Create a HAL device stream of the requested size and format.
+ *
+ * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device
+ * selects an appropriate format; it can be queried with getFormat.
+ *
+ * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must
+ * be equal to the size in bytes of the buffers to allocate for the
+ * stream. For other formats, the size parameter is ignored.
+ */
+ status_t connectToDevice(sp<ANativeWindow> consumer,
+ uint32_t width, uint32_t height, int format, size_t size);
+
+ status_t disconnect();
+
+ status_t setTransform(int transform);
+
+ // Get stream parameters.
+ // Only valid after a successful connectToDevice call.
+ int getId() const { return mId; }
+ uint32_t getWidth() const { return mWidth; }
+ uint32_t getHeight() const { return mHeight; }
+ uint32_t getFormat() const { return mFormat; }
+
+ // Dump stream information
+ status_t dump(int fd, const Vector<String16>& args);
+
+ private:
+ enum {
+ ERROR = -1,
+ DISCONNECTED = 0,
+ ALLOCATED,
+ CONNECTED,
+ ACTIVE
+ } mState;
+
+ sp<ANativeWindow> mConsumerInterface;
+ camera2_device_t *mDevice;
+
+ uint32_t mId;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint32_t mFormat;
+ size_t mSize;
+ uint32_t mUsage;
+ uint32_t mMaxProducerBuffers;
+ uint32_t mMaxConsumerBuffers;
+ uint32_t mTotalBuffers;
+ int mFormatRequested;
+
+ /** Debugging information */
+ uint32_t mActiveBuffers;
+ uint32_t mFrameCount;
+ int64_t mLastTimestamp;
+
+ const camera2_stream_ops *getStreamOps();
+
+ static ANativeWindow* toANW(const camera2_stream_ops_t *w);
+
+ static int dequeue_buffer(const camera2_stream_ops_t *w,
+ buffer_handle_t** buffer);
+
+ static int enqueue_buffer(const camera2_stream_ops_t* w,
+ int64_t timestamp,
+ buffer_handle_t* buffer);
+
+ static int cancel_buffer(const camera2_stream_ops_t* w,
+ buffer_handle_t* buffer);
+
+ static int set_crop(const camera2_stream_ops_t* w,
+ int left, int top, int right, int bottom);
+ }; // class StreamAdapter
+
+ typedef List<sp<StreamAdapter> > StreamList;
+ StreamList mStreams;
+
+}; // class Camera2Device
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/CameraClient.cpp b/services/camera/libcameraservice/CameraClient.cpp
new file mode 100644
index 0000000..80ccb43
--- /dev/null
+++ b/services/camera/libcameraservice/CameraClient.cpp
@@ -0,0 +1,958 @@
+/*
+ * Copyright (C) 2012 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 "CameraClient"
+//#define LOG_NDEBUG 0
+
+#include <cutils/properties.h>
+#include <gui/SurfaceTextureClient.h>
+#include <gui/Surface.h>
+
+#include "CameraClient.h"
+#include "CameraHardwareInterface.h"
+#include "CameraService.h"
+
+namespace android {
+
+#define LOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
+#define LOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__);
+
+static int getCallingPid() {
+ return IPCThreadState::self()->getCallingPid();
+}
+
+static int getCallingUid() {
+ return IPCThreadState::self()->getCallingUid();
+}
+
+CameraClient::CameraClient(const sp<CameraService>& cameraService,
+ const sp<ICameraClient>& cameraClient,
+ int cameraId, int cameraFacing, int clientPid):
+ Client(cameraService, cameraClient,
+ cameraId, cameraFacing, clientPid)
+{
+ int callingPid = getCallingPid();
+ LOG1("CameraClient::CameraClient E (pid %d, id %d)", callingPid, cameraId);
+
+ mHardware = NULL;
+ mMsgEnabled = 0;
+ mSurface = 0;
+ mPreviewWindow = 0;
+ mDestructionStarted = false;
+
+ // Callback is disabled by default
+ mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
+ mOrientation = getOrientation(0, mCameraFacing == CAMERA_FACING_FRONT);
+ mPlayShutterSound = true;
+ LOG1("CameraClient::CameraClient X (pid %d, id %d)", callingPid, cameraId);
+}
+
+status_t CameraClient::initialize(camera_module_t *module) {
+ int callingPid = getCallingPid();
+ LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);
+
+ char camera_device_name[10];
+ status_t res;
+ snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);
+
+ mHardware = new CameraHardwareInterface(camera_device_name);
+ res = mHardware->initialize(&module->common);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return NO_INIT;
+ }
+
+ mHardware->setCallbacks(notifyCallback,
+ dataCallback,
+ dataCallbackTimestamp,
+ (void *)mCameraId);
+
+ // Enable zoom, error, focus, and metadata messages by default
+ enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
+ CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);
+
+ LOG1("CameraClient::initialize X (pid %d, id %d)", callingPid, mCameraId);
+ return OK;
+}
+
+
+// tear down the client
+CameraClient::~CameraClient() {
+ // this lock should never be NULL
+ Mutex* lock = mCameraService->getClientLockById(mCameraId);
+ lock->lock();
+ mDestructionStarted = true;
+ // client will not be accessed from callback. should unlock to prevent dead-lock in disconnect
+ lock->unlock();
+ int callingPid = getCallingPid();
+ LOG1("CameraClient::~CameraClient E (pid %d, this %p)", callingPid, this);
+
+ // set mClientPid to let disconnet() tear down the hardware
+ mClientPid = callingPid;
+ disconnect();
+ LOG1("CameraClient::~CameraClient X (pid %d, this %p)", callingPid, this);
+}
+
+status_t CameraClient::dump(int fd, const Vector<String16>& args) {
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ size_t len = snprintf(buffer, SIZE, "Client[%d] (%p) PID: %d\n",
+ mCameraId,
+ getCameraClient()->asBinder().get(),
+ mClientPid);
+ len = (len > SIZE - 1) ? SIZE - 1 : len;
+ write(fd, buffer, len);
+ return mHardware->dump(fd, args);
+}
+
+// ----------------------------------------------------------------------------
+
+status_t CameraClient::checkPid() const {
+ int callingPid = getCallingPid();
+ if (callingPid == mClientPid) return NO_ERROR;
+
+ ALOGW("attempt to use a locked camera from a different process"
+ " (old pid %d, new pid %d)", mClientPid, callingPid);
+ return EBUSY;
+}
+
+status_t CameraClient::checkPidAndHardware() const {
+ status_t result = checkPid();
+ if (result != NO_ERROR) return result;
+ if (mHardware == 0) {
+ ALOGE("attempt to use a camera after disconnect() (pid %d)", getCallingPid());
+ return INVALID_OPERATION;
+ }
+ return NO_ERROR;
+}
+
+status_t CameraClient::lock() {
+ int callingPid = getCallingPid();
+ LOG1("lock (pid %d)", callingPid);
+ Mutex::Autolock lock(mLock);
+
+ // lock camera to this client if the the camera is unlocked
+ if (mClientPid == 0) {
+ mClientPid = callingPid;
+ return NO_ERROR;
+ }
+
+ // returns NO_ERROR if the client already owns the camera, EBUSY otherwise
+ return checkPid();
+}
+
+status_t CameraClient::unlock() {
+ int callingPid = getCallingPid();
+ LOG1("unlock (pid %d)", callingPid);
+ Mutex::Autolock lock(mLock);
+
+ // allow anyone to use camera (after they lock the camera)
+ status_t result = checkPid();
+ if (result == NO_ERROR) {
+ if (mHardware->recordingEnabled()) {
+ ALOGE("Not allowed to unlock camera during recording.");
+ return INVALID_OPERATION;
+ }
+ mClientPid = 0;
+ LOG1("clear mCameraClient (pid %d)", callingPid);
+ // we need to remove the reference to ICameraClient so that when the app
+ // goes away, the reference count goes to 0.
+ mCameraClient.clear();
+ }
+ return result;
+}
+
+// connect a new client to the camera
+status_t CameraClient::connect(const sp<ICameraClient>& client) {
+ int callingPid = getCallingPid();
+ LOG1("connect E (pid %d)", callingPid);
+ Mutex::Autolock lock(mLock);
+
+ if (mClientPid != 0 && checkPid() != NO_ERROR) {
+ ALOGW("Tried to connect to a locked camera (old pid %d, new pid %d)",
+ mClientPid, callingPid);
+ return EBUSY;
+ }
+
+ if (mCameraClient != 0 && (client->asBinder() == mCameraClient->asBinder())) {
+ LOG1("Connect to the same client");
+ return NO_ERROR;
+ }
+
+ mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
+ mClientPid = callingPid;
+ mCameraClient = client;
+
+ LOG1("connect X (pid %d)", callingPid);
+ return NO_ERROR;
+}
+
+static void disconnectWindow(const sp<ANativeWindow>& window) {
+ if (window != 0) {
+ status_t result = native_window_api_disconnect(window.get(),
+ NATIVE_WINDOW_API_CAMERA);
+ if (result != NO_ERROR) {
+ ALOGW("native_window_api_disconnect failed: %s (%d)", strerror(-result),
+ result);
+ }
+ }
+}
+
+void CameraClient::disconnect() {
+ int callingPid = getCallingPid();
+ LOG1("disconnect E (pid %d)", callingPid);
+ Mutex::Autolock lock(mLock);
+
+ if (checkPid() != NO_ERROR) {
+ ALOGW("different client - don't disconnect");
+ return;
+ }
+
+ if (mClientPid <= 0) {
+ LOG1("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);
+ return;
+ }
+
+ // Make sure disconnect() is done once and once only, whether it is called
+ // from the user directly, or called by the destructor.
+ if (mHardware == 0) return;
+
+ LOG1("hardware teardown");
+ // Before destroying mHardware, we must make sure it's in the
+ // idle state.
+ // Turn off all messages.
+ disableMsgType(CAMERA_MSG_ALL_MSGS);
+ mHardware->stopPreview();
+ mHardware->cancelPicture();
+ // Release the hardware resources.
+ mHardware->release();
+
+ // Release the held ANativeWindow resources.
+ if (mPreviewWindow != 0) {
+ disconnectWindow(mPreviewWindow);
+ mPreviewWindow = 0;
+ mHardware->setPreviewWindow(mPreviewWindow);
+ }
+ mHardware.clear();
+
+ CameraService::Client::disconnect();
+
+ LOG1("disconnect X (pid %d)", callingPid);
+}
+
+// ----------------------------------------------------------------------------
+
+status_t CameraClient::setPreviewWindow(const sp<IBinder>& binder,
+ const sp<ANativeWindow>& window) {
+ Mutex::Autolock lock(mLock);
+ status_t result = checkPidAndHardware();
+ if (result != NO_ERROR) return result;
+
+ // return if no change in surface.
+ if (binder == mSurface) {
+ return NO_ERROR;
+ }
+
+ if (window != 0) {
+ result = native_window_api_connect(window.get(), NATIVE_WINDOW_API_CAMERA);
+ if (result != NO_ERROR) {
+ ALOGE("native_window_api_connect failed: %s (%d)", strerror(-result),
+ result);
+ return result;
+ }
+ }
+
+ // If preview has been already started, register preview buffers now.
+ if (mHardware->previewEnabled()) {
+ if (window != 0) {
+ native_window_set_scaling_mode(window.get(),
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ native_window_set_buffers_transform(window.get(), mOrientation);
+ result = mHardware->setPreviewWindow(window);
+ }
+ }
+
+ if (result == NO_ERROR) {
+ // Everything has succeeded. Disconnect the old window and remember the
+ // new window.
+ disconnectWindow(mPreviewWindow);
+ mSurface = binder;
+ mPreviewWindow = window;
+ } else {
+ // Something went wrong after we connected to the new window, so
+ // disconnect here.
+ disconnectWindow(window);
+ }
+
+ return result;
+}
+
+// set the Surface that the preview will use
+status_t CameraClient::setPreviewDisplay(const sp<Surface>& surface) {
+ LOG1("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid());
+
+ sp<IBinder> binder(surface != 0 ? surface->asBinder() : 0);
+ sp<ANativeWindow> window(surface);
+ return setPreviewWindow(binder, window);
+}
+
+// set the SurfaceTexture that the preview will use
+status_t CameraClient::setPreviewTexture(
+ const sp<ISurfaceTexture>& surfaceTexture) {
+ LOG1("setPreviewTexture(%p) (pid %d)", surfaceTexture.get(),
+ getCallingPid());
+
+ sp<IBinder> binder;
+ sp<ANativeWindow> window;
+ if (surfaceTexture != 0) {
+ binder = surfaceTexture->asBinder();
+ window = new SurfaceTextureClient(surfaceTexture);
+ }
+ return setPreviewWindow(binder, window);
+}
+
+// set the preview callback flag to affect how the received frames from
+// preview are handled.
+void CameraClient::setPreviewCallbackFlag(int callback_flag) {
+ LOG1("setPreviewCallbackFlag(%d) (pid %d)", callback_flag, getCallingPid());
+ Mutex::Autolock lock(mLock);
+ if (checkPidAndHardware() != NO_ERROR) return;
+
+ mPreviewCallbackFlag = callback_flag;
+ if (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) {
+ enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+ } else {
+ disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+ }
+}
+
+// start preview mode
+status_t CameraClient::startPreview() {
+ LOG1("startPreview (pid %d)", getCallingPid());
+ return startCameraMode(CAMERA_PREVIEW_MODE);
+}
+
+// start recording mode
+status_t CameraClient::startRecording() {
+ LOG1("startRecording (pid %d)", getCallingPid());
+ return startCameraMode(CAMERA_RECORDING_MODE);
+}
+
+// start preview or recording
+status_t CameraClient::startCameraMode(camera_mode mode) {
+ LOG1("startCameraMode(%d)", mode);
+ Mutex::Autolock lock(mLock);
+ status_t result = checkPidAndHardware();
+ if (result != NO_ERROR) return result;
+
+ switch(mode) {
+ case CAMERA_PREVIEW_MODE:
+ if (mSurface == 0 && mPreviewWindow == 0) {
+ LOG1("mSurface is not set yet.");
+ // still able to start preview in this case.
+ }
+ return startPreviewMode();
+ case CAMERA_RECORDING_MODE:
+ if (mSurface == 0 && mPreviewWindow == 0) {
+ ALOGE("mSurface or mPreviewWindow must be set before startRecordingMode.");
+ return INVALID_OPERATION;
+ }
+ return startRecordingMode();
+ default:
+ return UNKNOWN_ERROR;
+ }
+}
+
+status_t CameraClient::startPreviewMode() {
+ LOG1("startPreviewMode");
+ status_t result = NO_ERROR;
+
+ // if preview has been enabled, nothing needs to be done
+ if (mHardware->previewEnabled()) {
+ return NO_ERROR;
+ }
+
+ if (mPreviewWindow != 0) {
+ native_window_set_scaling_mode(mPreviewWindow.get(),
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ native_window_set_buffers_transform(mPreviewWindow.get(),
+ mOrientation);
+ }
+ mHardware->setPreviewWindow(mPreviewWindow);
+ result = mHardware->startPreview();
+
+ return result;
+}
+
+status_t CameraClient::startRecordingMode() {
+ LOG1("startRecordingMode");
+ status_t result = NO_ERROR;
+
+ // if recording has been enabled, nothing needs to be done
+ if (mHardware->recordingEnabled()) {
+ return NO_ERROR;
+ }
+
+ // if preview has not been started, start preview first
+ if (!mHardware->previewEnabled()) {
+ result = startPreviewMode();
+ if (result != NO_ERROR) {
+ return result;
+ }
+ }
+
+ // start recording mode
+ enableMsgType(CAMERA_MSG_VIDEO_FRAME);
+ mCameraService->playSound(CameraService::SOUND_RECORDING);
+ result = mHardware->startRecording();
+ if (result != NO_ERROR) {
+ ALOGE("mHardware->startRecording() failed with status %d", result);
+ }
+ return result;
+}
+
+// stop preview mode
+void CameraClient::stopPreview() {
+ LOG1("stopPreview (pid %d)", getCallingPid());
+ Mutex::Autolock lock(mLock);
+ if (checkPidAndHardware() != NO_ERROR) return;
+
+
+ disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+ mHardware->stopPreview();
+
+ mPreviewBuffer.clear();
+}
+
+// stop recording mode
+void CameraClient::stopRecording() {
+ LOG1("stopRecording (pid %d)", getCallingPid());
+ Mutex::Autolock lock(mLock);
+ if (checkPidAndHardware() != NO_ERROR) return;
+
+ mCameraService->playSound(CameraService::SOUND_RECORDING);
+ disableMsgType(CAMERA_MSG_VIDEO_FRAME);
+ mHardware->stopRecording();
+
+ mPreviewBuffer.clear();
+}
+
+// release a recording frame
+void CameraClient::releaseRecordingFrame(const sp<IMemory>& mem) {
+ Mutex::Autolock lock(mLock);
+ if (checkPidAndHardware() != NO_ERROR) return;
+ mHardware->releaseRecordingFrame(mem);
+}
+
+status_t CameraClient::storeMetaDataInBuffers(bool enabled)
+{
+ LOG1("storeMetaDataInBuffers: %s", enabled? "true": "false");
+ Mutex::Autolock lock(mLock);
+ if (checkPidAndHardware() != NO_ERROR) {
+ return UNKNOWN_ERROR;
+ }
+ return mHardware->storeMetaDataInBuffers(enabled);
+}
+
+bool CameraClient::previewEnabled() {
+ LOG1("previewEnabled (pid %d)", getCallingPid());
+
+ Mutex::Autolock lock(mLock);
+ if (checkPidAndHardware() != NO_ERROR) return false;
+ return mHardware->previewEnabled();
+}
+
+bool CameraClient::recordingEnabled() {
+ LOG1("recordingEnabled (pid %d)", getCallingPid());
+
+ Mutex::Autolock lock(mLock);
+ if (checkPidAndHardware() != NO_ERROR) return false;
+ return mHardware->recordingEnabled();
+}
+
+status_t CameraClient::autoFocus() {
+ LOG1("autoFocus (pid %d)", getCallingPid());
+
+ Mutex::Autolock lock(mLock);
+ status_t result = checkPidAndHardware();
+ if (result != NO_ERROR) return result;
+
+ return mHardware->autoFocus();
+}
+
+status_t CameraClient::cancelAutoFocus() {
+ LOG1("cancelAutoFocus (pid %d)", getCallingPid());
+
+ Mutex::Autolock lock(mLock);
+ status_t result = checkPidAndHardware();
+ if (result != NO_ERROR) return result;
+
+ return mHardware->cancelAutoFocus();
+}
+
+// take a picture - image is returned in callback
+status_t CameraClient::takePicture(int msgType) {
+ LOG1("takePicture (pid %d): 0x%x", getCallingPid(), msgType);
+
+ Mutex::Autolock lock(mLock);
+ status_t result = checkPidAndHardware();
+ if (result != NO_ERROR) return result;
+
+ if ((msgType & CAMERA_MSG_RAW_IMAGE) &&
+ (msgType & CAMERA_MSG_RAW_IMAGE_NOTIFY)) {
+ ALOGE("CAMERA_MSG_RAW_IMAGE and CAMERA_MSG_RAW_IMAGE_NOTIFY"
+ " cannot be both enabled");
+ return BAD_VALUE;
+ }
+
+ // We only accept picture related message types
+ // and ignore other types of messages for takePicture().
+ int picMsgType = msgType
+ & (CAMERA_MSG_SHUTTER |
+ CAMERA_MSG_POSTVIEW_FRAME |
+ CAMERA_MSG_RAW_IMAGE |
+ CAMERA_MSG_RAW_IMAGE_NOTIFY |
+ CAMERA_MSG_COMPRESSED_IMAGE);
+
+ enableMsgType(picMsgType);
+
+ return mHardware->takePicture();
+}
+
+// set preview/capture parameters - key/value pairs
+status_t CameraClient::setParameters(const String8& params) {
+ LOG1("setParameters (pid %d) (%s)", getCallingPid(), params.string());
+
+ Mutex::Autolock lock(mLock);
+ status_t result = checkPidAndHardware();
+ if (result != NO_ERROR) return result;
+
+ CameraParameters p(params);
+ return mHardware->setParameters(p);
+}
+
+// get preview/capture parameters - key/value pairs
+String8 CameraClient::getParameters() const {
+ Mutex::Autolock lock(mLock);
+ if (checkPidAndHardware() != NO_ERROR) return String8();
+
+ String8 params(mHardware->getParameters().flatten());
+ LOG1("getParameters (pid %d) (%s)", getCallingPid(), params.string());
+ return params;
+}
+
+// enable shutter sound
+status_t CameraClient::enableShutterSound(bool enable) {
+ LOG1("enableShutterSound (pid %d)", getCallingPid());
+
+ status_t result = checkPidAndHardware();
+ if (result != NO_ERROR) return result;
+
+ if (enable) {
+ mPlayShutterSound = true;
+ return OK;
+ }
+
+ // Disabling shutter sound may not be allowed. In that case only
+ // allow the mediaserver process to disable the sound.
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.camera.sound.forced", value, "0");
+ if (strcmp(value, "0") != 0) {
+ // Disabling shutter sound is not allowed. Deny if the current
+ // process is not mediaserver.
+ if (getCallingPid() != getpid()) {
+ ALOGE("Failed to disable shutter sound. Permission denied (pid %d)", getCallingPid());
+ return PERMISSION_DENIED;
+ }
+ }
+
+ mPlayShutterSound = false;
+ return OK;
+}
+
+status_t CameraClient::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
+ LOG1("sendCommand (pid %d)", getCallingPid());
+ int orientation;
+ Mutex::Autolock lock(mLock);
+ status_t result = checkPidAndHardware();
+ if (result != NO_ERROR) return result;
+
+ if (cmd == CAMERA_CMD_SET_DISPLAY_ORIENTATION) {
+ // Mirror the preview if the camera is front-facing.
+ orientation = getOrientation(arg1, mCameraFacing == CAMERA_FACING_FRONT);
+ if (orientation == -1) return BAD_VALUE;
+
+ if (mOrientation != orientation) {
+ mOrientation = orientation;
+ if (mPreviewWindow != 0) {
+ native_window_set_buffers_transform(mPreviewWindow.get(),
+ mOrientation);
+ }
+ }
+ return OK;
+ } else if (cmd == CAMERA_CMD_ENABLE_SHUTTER_SOUND) {
+ switch (arg1) {
+ case 0:
+ enableShutterSound(false);
+ break;
+ case 1:
+ enableShutterSound(true);
+ break;
+ default:
+ return BAD_VALUE;
+ }
+ return OK;
+ } else if (cmd == CAMERA_CMD_PLAY_RECORDING_SOUND) {
+ mCameraService->playSound(CameraService::SOUND_RECORDING);
+ } else if (cmd == CAMERA_CMD_PING) {
+ // If mHardware is 0, checkPidAndHardware will return error.
+ return OK;
+ }
+
+ return mHardware->sendCommand(cmd, arg1, arg2);
+}
+
+// ----------------------------------------------------------------------------
+
+void CameraClient::enableMsgType(int32_t msgType) {
+ android_atomic_or(msgType, &mMsgEnabled);
+ mHardware->enableMsgType(msgType);
+}
+
+void CameraClient::disableMsgType(int32_t msgType) {
+ android_atomic_and(~msgType, &mMsgEnabled);
+ mHardware->disableMsgType(msgType);
+}
+
+#define CHECK_MESSAGE_INTERVAL 10 // 10ms
+bool CameraClient::lockIfMessageWanted(int32_t msgType) {
+ int sleepCount = 0;
+ while (mMsgEnabled & msgType) {
+ if (mLock.tryLock() == NO_ERROR) {
+ if (sleepCount > 0) {
+ LOG1("lockIfMessageWanted(%d): waited for %d ms",
+ msgType, sleepCount * CHECK_MESSAGE_INTERVAL);
+ }
+ return true;
+ }
+ if (sleepCount++ == 0) {
+ LOG1("lockIfMessageWanted(%d): enter sleep", msgType);
+ }
+ usleep(CHECK_MESSAGE_INTERVAL * 1000);
+ }
+ ALOGW("lockIfMessageWanted(%d): dropped unwanted message", msgType);
+ return false;
+}
+
+// Callback messages can be dispatched to internal handlers or pass to our
+// client's callback functions, depending on the message type.
+//
+// notifyCallback:
+// CAMERA_MSG_SHUTTER handleShutter
+// (others) c->notifyCallback
+// dataCallback:
+// CAMERA_MSG_PREVIEW_FRAME handlePreviewData
+// CAMERA_MSG_POSTVIEW_FRAME handlePostview
+// CAMERA_MSG_RAW_IMAGE handleRawPicture
+// CAMERA_MSG_COMPRESSED_IMAGE handleCompressedPicture
+// (others) c->dataCallback
+// dataCallbackTimestamp
+// (others) c->dataCallbackTimestamp
+//
+// NOTE: the *Callback functions grab mLock of the client before passing
+// control to handle* functions. So the handle* functions must release the
+// lock before calling the ICameraClient's callbacks, so those callbacks can
+// invoke methods in the Client class again (For example, the preview frame
+// callback may want to releaseRecordingFrame). The handle* functions must
+// release the lock after all accesses to member variables, so it must be
+// handled very carefully.
+
+void CameraClient::notifyCallback(int32_t msgType, int32_t ext1,
+ int32_t ext2, void* user) {
+ LOG2("notifyCallback(%d)", msgType);
+
+ Mutex* lock = getClientLockFromCookie(user);
+ if (lock == NULL) return;
+ Mutex::Autolock alock(*lock);
+
+ CameraClient* client =
+ static_cast<CameraClient*>(getClientFromCookie(user));
+ if (client == NULL) return;
+
+ if (!client->lockIfMessageWanted(msgType)) return;
+
+ switch (msgType) {
+ case CAMERA_MSG_SHUTTER:
+ // ext1 is the dimension of the yuv picture.
+ client->handleShutter();
+ break;
+ default:
+ client->handleGenericNotify(msgType, ext1, ext2);
+ break;
+ }
+}
+
+void CameraClient::dataCallback(int32_t msgType,
+ const sp<IMemory>& dataPtr, camera_frame_metadata_t *metadata, void* user) {
+ LOG2("dataCallback(%d)", msgType);
+
+ Mutex* lock = getClientLockFromCookie(user);
+ if (lock == NULL) return;
+ Mutex::Autolock alock(*lock);
+
+ CameraClient* client =
+ static_cast<CameraClient*>(getClientFromCookie(user));
+ if (client == NULL) return;
+
+ if (!client->lockIfMessageWanted(msgType)) return;
+ if (dataPtr == 0 && metadata == NULL) {
+ ALOGE("Null data returned in data callback");
+ client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
+ return;
+ }
+
+ switch (msgType & ~CAMERA_MSG_PREVIEW_METADATA) {
+ case CAMERA_MSG_PREVIEW_FRAME:
+ client->handlePreviewData(msgType, dataPtr, metadata);
+ break;
+ case CAMERA_MSG_POSTVIEW_FRAME:
+ client->handlePostview(dataPtr);
+ break;
+ case CAMERA_MSG_RAW_IMAGE:
+ client->handleRawPicture(dataPtr);
+ break;
+ case CAMERA_MSG_COMPRESSED_IMAGE:
+ client->handleCompressedPicture(dataPtr);
+ break;
+ default:
+ client->handleGenericData(msgType, dataPtr, metadata);
+ break;
+ }
+}
+
+void CameraClient::dataCallbackTimestamp(nsecs_t timestamp,
+ int32_t msgType, const sp<IMemory>& dataPtr, void* user) {
+ LOG2("dataCallbackTimestamp(%d)", msgType);
+
+ Mutex* lock = getClientLockFromCookie(user);
+ if (lock == NULL) return;
+ Mutex::Autolock alock(*lock);
+
+ CameraClient* client =
+ static_cast<CameraClient*>(getClientFromCookie(user));
+ if (client == NULL) return;
+
+ if (!client->lockIfMessageWanted(msgType)) return;
+
+ if (dataPtr == 0) {
+ ALOGE("Null data returned in data with timestamp callback");
+ client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
+ return;
+ }
+
+ client->handleGenericDataTimestamp(timestamp, msgType, dataPtr);
+}
+
+// snapshot taken callback
+void CameraClient::handleShutter(void) {
+ if (mPlayShutterSound) {
+ mCameraService->playSound(CameraService::SOUND_SHUTTER);
+ }
+
+ sp<ICameraClient> c = mCameraClient;
+ if (c != 0) {
+ mLock.unlock();
+ c->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
+ if (!lockIfMessageWanted(CAMERA_MSG_SHUTTER)) return;
+ }
+ disableMsgType(CAMERA_MSG_SHUTTER);
+
+ mLock.unlock();
+}
+
+// preview callback - frame buffer update
+void CameraClient::handlePreviewData(int32_t msgType,
+ const sp<IMemory>& mem,
+ camera_frame_metadata_t *metadata) {
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+
+ // local copy of the callback flags
+ int flags = mPreviewCallbackFlag;
+
+ // is callback enabled?
+ if (!(flags & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
+ // If the enable bit is off, the copy-out and one-shot bits are ignored
+ LOG2("frame callback is disabled");
+ mLock.unlock();
+ return;
+ }
+
+ // hold a strong pointer to the client
+ sp<ICameraClient> c = mCameraClient;
+
+ // clear callback flags if no client or one-shot mode
+ if (c == 0 || (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) {
+ LOG2("Disable preview callback");
+ mPreviewCallbackFlag &= ~(CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
+ CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
+ CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
+ disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+ }
+
+ if (c != 0) {
+ // Is the received frame copied out or not?
+ if (flags & CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
+ LOG2("frame is copied");
+ copyFrameAndPostCopiedFrame(msgType, c, heap, offset, size, metadata);
+ } else {
+ LOG2("frame is forwarded");
+ mLock.unlock();
+ c->dataCallback(msgType, mem, metadata);
+ }
+ } else {
+ mLock.unlock();
+ }
+}
+
+// picture callback - postview image ready
+void CameraClient::handlePostview(const sp<IMemory>& mem) {
+ disableMsgType(CAMERA_MSG_POSTVIEW_FRAME);
+
+ sp<ICameraClient> c = mCameraClient;
+ mLock.unlock();
+ if (c != 0) {
+ c->dataCallback(CAMERA_MSG_POSTVIEW_FRAME, mem, NULL);
+ }
+}
+
+// picture callback - raw image ready
+void CameraClient::handleRawPicture(const sp<IMemory>& mem) {
+ disableMsgType(CAMERA_MSG_RAW_IMAGE);
+
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+
+ sp<ICameraClient> c = mCameraClient;
+ mLock.unlock();
+ if (c != 0) {
+ c->dataCallback(CAMERA_MSG_RAW_IMAGE, mem, NULL);
+ }
+}
+
+// picture callback - compressed picture ready
+void CameraClient::handleCompressedPicture(const sp<IMemory>& mem) {
+ disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
+
+ sp<ICameraClient> c = mCameraClient;
+ mLock.unlock();
+ if (c != 0) {
+ c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem, NULL);
+ }
+}
+
+
+void CameraClient::handleGenericNotify(int32_t msgType,
+ int32_t ext1, int32_t ext2) {
+ sp<ICameraClient> c = mCameraClient;
+ mLock.unlock();
+ if (c != 0) {
+ c->notifyCallback(msgType, ext1, ext2);
+ }
+}
+
+void CameraClient::handleGenericData(int32_t msgType,
+ const sp<IMemory>& dataPtr, camera_frame_metadata_t *metadata) {
+ sp<ICameraClient> c = mCameraClient;
+ mLock.unlock();
+ if (c != 0) {
+ c->dataCallback(msgType, dataPtr, metadata);
+ }
+}
+
+void CameraClient::handleGenericDataTimestamp(nsecs_t timestamp,
+ int32_t msgType, const sp<IMemory>& dataPtr) {
+ sp<ICameraClient> c = mCameraClient;
+ mLock.unlock();
+ if (c != 0) {
+ c->dataCallbackTimestamp(timestamp, msgType, dataPtr);
+ }
+}
+
+void CameraClient::copyFrameAndPostCopiedFrame(
+ int32_t msgType, const sp<ICameraClient>& client,
+ const sp<IMemoryHeap>& heap, size_t offset, size_t size,
+ camera_frame_metadata_t *metadata) {
+ LOG2("copyFrameAndPostCopiedFrame");
+ // It is necessary to copy out of pmem before sending this to
+ // the callback. For efficiency, reuse the same MemoryHeapBase
+ // provided it's big enough. Don't allocate the memory or
+ // perform the copy if there's no callback.
+ // hold the preview lock while we grab a reference to the preview buffer
+ sp<MemoryHeapBase> previewBuffer;
+
+ if (mPreviewBuffer == 0) {
+ mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
+ } else if (size > mPreviewBuffer->virtualSize()) {
+ mPreviewBuffer.clear();
+ mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
+ }
+ if (mPreviewBuffer == 0) {
+ ALOGE("failed to allocate space for preview buffer");
+ mLock.unlock();
+ return;
+ }
+ previewBuffer = mPreviewBuffer;
+
+ memcpy(previewBuffer->base(), (uint8_t *)heap->base() + offset, size);
+
+ sp<MemoryBase> frame = new MemoryBase(previewBuffer, 0, size);
+ if (frame == 0) {
+ ALOGE("failed to allocate space for frame callback");
+ mLock.unlock();
+ return;
+ }
+
+ mLock.unlock();
+ client->dataCallback(msgType, frame, metadata);
+}
+
+int CameraClient::getOrientation(int degrees, bool mirror) {
+ if (!mirror) {
+ if (degrees == 0) return 0;
+ else if (degrees == 90) return HAL_TRANSFORM_ROT_90;
+ else if (degrees == 180) return HAL_TRANSFORM_ROT_180;
+ else if (degrees == 270) return HAL_TRANSFORM_ROT_270;
+ } else { // Do mirror (horizontal flip)
+ if (degrees == 0) { // FLIP_H and ROT_0
+ return HAL_TRANSFORM_FLIP_H;
+ } else if (degrees == 90) { // FLIP_H and ROT_90
+ return HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90;
+ } else if (degrees == 180) { // FLIP_H and ROT_180
+ return HAL_TRANSFORM_FLIP_V;
+ } else if (degrees == 270) { // FLIP_H and ROT_270
+ return HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90;
+ }
+ }
+ ALOGE("Invalid setDisplayOrientation degrees=%d", degrees);
+ return -1;
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/CameraClient.h b/services/camera/libcameraservice/CameraClient.h
new file mode 100644
index 0000000..256298d
--- /dev/null
+++ b/services/camera/libcameraservice/CameraClient.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2012 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_SERVERS_CAMERA_CAMERACLIENT_H
+#define ANDROID_SERVERS_CAMERA_CAMERACLIENT_H
+
+#include "CameraService.h"
+
+namespace android {
+
+class MemoryHeapBase;
+class CameraHardwareInterface;
+
+class CameraClient : public CameraService::Client
+{
+public:
+ // ICamera interface (see ICamera for details)
+ virtual void disconnect();
+ virtual status_t connect(const sp<ICameraClient>& client);
+ virtual status_t lock();
+ virtual status_t unlock();
+ virtual status_t setPreviewDisplay(const sp<Surface>& surface);
+ virtual status_t setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture);
+ virtual void setPreviewCallbackFlag(int flag);
+ virtual status_t startPreview();
+ virtual void stopPreview();
+ virtual bool previewEnabled();
+ virtual status_t storeMetaDataInBuffers(bool enabled);
+ virtual status_t startRecording();
+ virtual void stopRecording();
+ virtual bool recordingEnabled();
+ virtual void releaseRecordingFrame(const sp<IMemory>& mem);
+ virtual status_t autoFocus();
+ virtual status_t cancelAutoFocus();
+ virtual status_t takePicture(int msgType);
+ virtual status_t setParameters(const String8& params);
+ virtual String8 getParameters() const;
+ virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
+
+ // Interface used by CameraService
+ CameraClient(const sp<CameraService>& cameraService,
+ const sp<ICameraClient>& cameraClient,
+ int cameraId,
+ int cameraFacing,
+ int clientPid);
+ ~CameraClient();
+
+ status_t initialize(camera_module_t *module);
+
+ status_t dump(int fd, const Vector<String16>& args);
+
+private:
+
+ // check whether the calling process matches mClientPid.
+ status_t checkPid() const;
+ status_t checkPidAndHardware() const; // also check mHardware != 0
+
+ // these are internal functions used to set up preview buffers
+ status_t registerPreviewBuffers();
+
+ // camera operation mode
+ enum camera_mode {
+ CAMERA_PREVIEW_MODE = 0, // frame automatically released
+ CAMERA_RECORDING_MODE = 1, // frame has to be explicitly released by releaseRecordingFrame()
+ };
+ // these are internal functions used for preview/recording
+ status_t startCameraMode(camera_mode mode);
+ status_t startPreviewMode();
+ status_t startRecordingMode();
+
+ // internal function used by sendCommand to enable/disable shutter sound.
+ status_t enableShutterSound(bool enable);
+
+ // these are static callback functions
+ static void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user);
+ static void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
+ camera_frame_metadata_t *metadata, void* user);
+ static void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr, void* user);
+ // handlers for messages
+ void handleShutter(void);
+ void handlePreviewData(int32_t msgType, const sp<IMemory>& mem,
+ camera_frame_metadata_t *metadata);
+ void handlePostview(const sp<IMemory>& mem);
+ void handleRawPicture(const sp<IMemory>& mem);
+ void handleCompressedPicture(const sp<IMemory>& mem);
+ void handleGenericNotify(int32_t msgType, int32_t ext1, int32_t ext2);
+ void handleGenericData(int32_t msgType, const sp<IMemory>& dataPtr,
+ camera_frame_metadata_t *metadata);
+ void handleGenericDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
+
+ void copyFrameAndPostCopiedFrame(
+ int32_t msgType,
+ const sp<ICameraClient>& client,
+ const sp<IMemoryHeap>& heap,
+ size_t offset, size_t size,
+ camera_frame_metadata_t *metadata);
+
+ int getOrientation(int orientation, bool mirror);
+
+ status_t setPreviewWindow(
+ const sp<IBinder>& binder,
+ const sp<ANativeWindow>& window);
+
+
+ // these are initialized in the constructor.
+ sp<CameraHardwareInterface> mHardware; // cleared after disconnect()
+ int mPreviewCallbackFlag;
+ int mOrientation; // Current display orientation
+ bool mPlayShutterSound;
+
+ // Ensures atomicity among the public methods
+ mutable Mutex mLock;
+ // This is a binder of Surface or SurfaceTexture.
+ sp<IBinder> mSurface;
+ sp<ANativeWindow> mPreviewWindow;
+
+ // If the user want us to return a copy of the preview frame (instead
+ // of the original one), we allocate mPreviewBuffer and reuse it if possible.
+ sp<MemoryHeapBase> mPreviewBuffer;
+
+ // We need to avoid the deadlock when the incoming command thread and
+ // the CameraHardwareInterface callback thread both want to grab mLock.
+ // An extra flag is used to tell the callback thread that it should stop
+ // trying to deliver the callback messages if the client is not
+ // interested in it anymore. For example, if the client is calling
+ // stopPreview(), the preview frame messages do not need to be delivered
+ // anymore.
+
+ // This function takes the same parameter as the enableMsgType() and
+ // disableMsgType() functions in CameraHardwareInterface.
+ void enableMsgType(int32_t msgType);
+ void disableMsgType(int32_t msgType);
+ volatile int32_t mMsgEnabled;
+
+ // This function keeps trying to grab mLock, or give up if the message
+ // is found to be disabled. It returns true if mLock is grabbed.
+ bool lockIfMessageWanted(int32_t msgType);
+};
+
+}
+
+#endif
diff --git a/services/camera/libcameraservice/CameraHardwareInterface.h b/services/camera/libcameraservice/CameraHardwareInterface.h
index 87a0802..05ac9fa 100644
--- a/services/camera/libcameraservice/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/CameraHardwareInterface.h
@@ -569,7 +569,7 @@
int rc;
ANativeWindow *a = anw(w);
ANativeWindowBuffer* anb;
- rc = a->dequeueBuffer(a, &anb);
+ rc = native_window_dequeue_buffer_and_wait(a, &anb);
if (!rc) {
*buffer = &anb->handle;
*stride = anb->stride;
@@ -587,8 +587,7 @@
buffer_handle_t* buffer)
{
ANativeWindow *a = anw(w);
- return a->lockBuffer(a,
- container_of(buffer, ANativeWindowBuffer, handle));
+ return 0;
}
static int __enqueue_buffer(struct preview_stream_ops* w,
@@ -596,7 +595,7 @@
{
ANativeWindow *a = anw(w);
return a->queueBuffer(a,
- container_of(buffer, ANativeWindowBuffer, handle));
+ container_of(buffer, ANativeWindowBuffer, handle), -1);
}
static int __cancel_buffer(struct preview_stream_ops* w,
@@ -604,7 +603,7 @@
{
ANativeWindow *a = anw(w);
return a->cancelBuffer(a,
- container_of(buffer, ANativeWindowBuffer, handle));
+ container_of(buffer, ANativeWindowBuffer, handle), -1);
}
static int __set_buffer_count(struct preview_stream_ops* w, int count)
diff --git a/services/camera/libcameraservice/CameraHardwareStub.cpp b/services/camera/libcameraservice/CameraHardwareStub.cpp
deleted file mode 100644
index cdfb2f5..0000000
--- a/services/camera/libcameraservice/CameraHardwareStub.cpp
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
-**
-** Copyright 2008, 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 "CameraHardwareStub"
-#include <utils/Log.h>
-
-#include "CameraHardwareStub.h"
-#include <utils/threads.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-
-#include "CannedJpeg.h"
-
-namespace android {
-
-CameraHardwareStub::CameraHardwareStub()
- : mParameters(),
- mPreviewHeap(0),
- mRawHeap(0),
- mFakeCamera(0),
- mPreviewFrameSize(0),
- mNotifyCb(0),
- mDataCb(0),
- mDataCbTimestamp(0),
- mCallbackCookie(0),
- mMsgEnabled(0),
- mCurrentPreviewFrame(0)
-{
- initDefaultParameters();
-}
-
-void CameraHardwareStub::initDefaultParameters()
-{
- CameraParameters p;
-
- p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, "320x240");
- p.setPreviewSize(320, 240);
- p.setPreviewFrameRate(15);
- p.setPreviewFormat(CameraParameters::PIXEL_FORMAT_YUV420SP);
-
- p.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, "320x240");
- p.setPictureSize(320, 240);
- p.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);
-
- if (setParameters(p) != NO_ERROR) {
- ALOGE("Failed to set default parameters?!");
- }
-}
-
-void CameraHardwareStub::initHeapLocked()
-{
- // Create raw heap.
- int picture_width, picture_height;
- mParameters.getPictureSize(&picture_width, &picture_height);
- mRawHeap = new MemoryHeapBase(picture_width * picture_height * 3 / 2);
-
- int preview_width, preview_height;
- mParameters.getPreviewSize(&preview_width, &preview_height);
- ALOGD("initHeapLocked: preview size=%dx%d", preview_width, preview_height);
-
- // Note that we enforce yuv420sp in setParameters().
- int how_big = preview_width * preview_height * 3 / 2;
-
- // If we are being reinitialized to the same size as before, no
- // work needs to be done.
- if (how_big == mPreviewFrameSize)
- return;
-
- mPreviewFrameSize = how_big;
-
- // Make a new mmap'ed heap that can be shared across processes.
- // use code below to test with pmem
- mPreviewHeap = new MemoryHeapBase(mPreviewFrameSize * kBufferCount);
- // Make an IMemory for each frame so that we can reuse them in callbacks.
- for (int i = 0; i < kBufferCount; i++) {
- mBuffers[i] = new MemoryBase(mPreviewHeap, i * mPreviewFrameSize, mPreviewFrameSize);
- }
-
- // Recreate the fake camera to reflect the current size.
- delete mFakeCamera;
- mFakeCamera = new FakeCamera(preview_width, preview_height);
-}
-
-CameraHardwareStub::~CameraHardwareStub()
-{
- delete mFakeCamera;
- mFakeCamera = 0; // paranoia
-}
-
-status_t CameraHardwareStub::setPreviewWindow(const sp<ANativeWindow>& buf)
-{
- return NO_ERROR;
-}
-
-sp<IMemoryHeap> CameraHardwareStub::getRawHeap() const
-{
- return mRawHeap;
-}
-
-void CameraHardwareStub::setCallbacks(notify_callback notify_cb,
- data_callback data_cb,
- data_callback_timestamp data_cb_timestamp,
- void* user)
-{
- Mutex::Autolock lock(mLock);
- mNotifyCb = notify_cb;
- mDataCb = data_cb;
- mDataCbTimestamp = data_cb_timestamp;
- mCallbackCookie = user;
-}
-
-void CameraHardwareStub::enableMsgType(int32_t msgType)
-{
- Mutex::Autolock lock(mLock);
- mMsgEnabled |= msgType;
-}
-
-void CameraHardwareStub::disableMsgType(int32_t msgType)
-{
- Mutex::Autolock lock(mLock);
- mMsgEnabled &= ~msgType;
-}
-
-bool CameraHardwareStub::msgTypeEnabled(int32_t msgType)
-{
- Mutex::Autolock lock(mLock);
- return (mMsgEnabled & msgType);
-}
-
-// ---------------------------------------------------------------------------
-
-int CameraHardwareStub::previewThread()
-{
- mLock.lock();
- // the attributes below can change under our feet...
-
- int previewFrameRate = mParameters.getPreviewFrameRate();
-
- // Find the offset within the heap of the current buffer.
- ssize_t offset = mCurrentPreviewFrame * mPreviewFrameSize;
-
- sp<MemoryHeapBase> heap = mPreviewHeap;
-
- // this assumes the internal state of fake camera doesn't change
- // (or is thread safe)
- FakeCamera* fakeCamera = mFakeCamera;
-
- sp<MemoryBase> buffer = mBuffers[mCurrentPreviewFrame];
-
- mLock.unlock();
-
- // TODO: here check all the conditions that could go wrong
- if (buffer != 0) {
- // Calculate how long to wait between frames.
- int delay = (int)(1000000.0f / float(previewFrameRate));
-
- // This is always valid, even if the client died -- the memory
- // is still mapped in our process.
- void *base = heap->base();
-
- // Fill the current frame with the fake camera.
- uint8_t *frame = ((uint8_t *)base) + offset;
- fakeCamera->getNextFrameAsYuv420(frame);
-
- //ALOGV("previewThread: generated frame to buffer %d", mCurrentPreviewFrame);
-
- // Notify the client of a new frame.
- if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME)
- mDataCb(CAMERA_MSG_PREVIEW_FRAME, buffer, NULL, mCallbackCookie);
-
- // Advance the buffer pointer.
- mCurrentPreviewFrame = (mCurrentPreviewFrame + 1) % kBufferCount;
-
- // Wait for it...
- usleep(delay);
- }
-
- return NO_ERROR;
-}
-
-status_t CameraHardwareStub::startPreview()
-{
- Mutex::Autolock lock(mLock);
- if (mPreviewThread != 0) {
- // already running
- return INVALID_OPERATION;
- }
- mPreviewThread = new PreviewThread(this);
- return NO_ERROR;
-}
-
-void CameraHardwareStub::stopPreview()
-{
- sp<PreviewThread> previewThread;
-
- { // scope for the lock
- Mutex::Autolock lock(mLock);
- previewThread = mPreviewThread;
- }
-
- // don't hold the lock while waiting for the thread to quit
- if (previewThread != 0) {
- previewThread->requestExitAndWait();
- }
-
- Mutex::Autolock lock(mLock);
- mPreviewThread.clear();
-}
-
-bool CameraHardwareStub::previewEnabled() {
- return mPreviewThread != 0;
-}
-
-status_t CameraHardwareStub::startRecording()
-{
- return UNKNOWN_ERROR;
-}
-
-void CameraHardwareStub::stopRecording()
-{
-}
-
-bool CameraHardwareStub::recordingEnabled()
-{
- return false;
-}
-
-void CameraHardwareStub::releaseRecordingFrame(const sp<IMemory>& mem)
-{
-}
-
-// ---------------------------------------------------------------------------
-
-int CameraHardwareStub::beginAutoFocusThread(void *cookie)
-{
- CameraHardwareStub *c = (CameraHardwareStub *)cookie;
- return c->autoFocusThread();
-}
-
-int CameraHardwareStub::autoFocusThread()
-{
- if (mMsgEnabled & CAMERA_MSG_FOCUS)
- mNotifyCb(CAMERA_MSG_FOCUS, true, 0, mCallbackCookie);
- return NO_ERROR;
-}
-
-status_t CameraHardwareStub::autoFocus()
-{
- Mutex::Autolock lock(mLock);
- if (createThread(beginAutoFocusThread, this) == false)
- return UNKNOWN_ERROR;
- return NO_ERROR;
-}
-
-status_t CameraHardwareStub::cancelAutoFocus()
-{
- return NO_ERROR;
-}
-
-/*static*/ int CameraHardwareStub::beginPictureThread(void *cookie)
-{
- CameraHardwareStub *c = (CameraHardwareStub *)cookie;
- return c->pictureThread();
-}
-
-int CameraHardwareStub::pictureThread()
-{
- if (mMsgEnabled & CAMERA_MSG_SHUTTER)
- mNotifyCb(CAMERA_MSG_SHUTTER, 0, 0, mCallbackCookie);
-
- if (mMsgEnabled & CAMERA_MSG_RAW_IMAGE) {
- //FIXME: use a canned YUV image!
- // In the meantime just make another fake camera picture.
- int w, h;
- mParameters.getPictureSize(&w, &h);
- sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * h * 3 / 2);
- FakeCamera cam(w, h);
- cam.getNextFrameAsYuv420((uint8_t *)mRawHeap->base());
- mDataCb(CAMERA_MSG_RAW_IMAGE, mem, NULL, mCallbackCookie);
- }
-
- if (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) {
- sp<MemoryHeapBase> heap = new MemoryHeapBase(kCannedJpegSize);
- sp<MemoryBase> mem = new MemoryBase(heap, 0, kCannedJpegSize);
- memcpy(heap->base(), kCannedJpeg, kCannedJpegSize);
- mDataCb(CAMERA_MSG_COMPRESSED_IMAGE, mem, NULL, mCallbackCookie);
- }
- return NO_ERROR;
-}
-
-status_t CameraHardwareStub::takePicture()
-{
- stopPreview();
- if (createThread(beginPictureThread, this) == false)
- return UNKNOWN_ERROR;
- return NO_ERROR;
-}
-
-status_t CameraHardwareStub::cancelPicture()
-{
- return NO_ERROR;
-}
-
-status_t CameraHardwareStub::dump(int fd, const Vector<String16>& args) const
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- AutoMutex lock(&mLock);
- if (mFakeCamera != 0) {
- mFakeCamera->dump(fd);
- mParameters.dump(fd, args);
- snprintf(buffer, 255, " preview frame(%d), size (%d), running(%s)\n", mCurrentPreviewFrame, mPreviewFrameSize, mPreviewRunning?"true": "false");
- result.append(buffer);
- } else {
- result.append("No camera client yet.\n");
- }
- write(fd, result.string(), result.size());
- return NO_ERROR;
-}
-
-status_t CameraHardwareStub::setParameters(const CameraParameters& params)
-{
- Mutex::Autolock lock(mLock);
- // XXX verify params
-
- if (strcmp(params.getPreviewFormat(),
- CameraParameters::PIXEL_FORMAT_YUV420SP) != 0) {
- ALOGE("Only yuv420sp preview is supported");
- return -1;
- }
-
- if (strcmp(params.getPictureFormat(),
- CameraParameters::PIXEL_FORMAT_JPEG) != 0) {
- ALOGE("Only jpeg still pictures are supported");
- return -1;
- }
-
- int w, h;
- params.getPictureSize(&w, &h);
- if (w != kCannedJpegWidth && h != kCannedJpegHeight) {
- ALOGE("Still picture size must be size of canned JPEG (%dx%d)",
- kCannedJpegWidth, kCannedJpegHeight);
- return -1;
- }
-
- mParameters = params;
- initHeapLocked();
-
- return NO_ERROR;
-}
-
-CameraParameters CameraHardwareStub::getParameters() const
-{
- Mutex::Autolock lock(mLock);
- return mParameters;
-}
-
-status_t CameraHardwareStub::sendCommand(int32_t command, int32_t arg1,
- int32_t arg2)
-{
- return BAD_VALUE;
-}
-
-void CameraHardwareStub::release()
-{
-}
-
-sp<CameraHardwareInterface> CameraHardwareStub::createInstance()
-{
- return new CameraHardwareStub();
-}
-
-static CameraInfo sCameraInfo[] = {
- {
- CAMERA_FACING_BACK,
- 90, /* orientation */
- }
-};
-
-extern "C" int HAL_getNumberOfCameras()
-{
- return sizeof(sCameraInfo) / sizeof(sCameraInfo[0]);
-}
-
-extern "C" void HAL_getCameraInfo(int cameraId, struct CameraInfo* cameraInfo)
-{
- memcpy(cameraInfo, &sCameraInfo[cameraId], sizeof(CameraInfo));
-}
-
-extern "C" sp<CameraHardwareInterface> HAL_openCameraHardware(int cameraId)
-{
- return CameraHardwareStub::createInstance();
-}
-
-}; // namespace android
diff --git a/services/camera/libcameraservice/CameraHardwareStub.h b/services/camera/libcameraservice/CameraHardwareStub.h
deleted file mode 100644
index c6d8756..0000000
--- a/services/camera/libcameraservice/CameraHardwareStub.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
-**
-** Copyright 2008, 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_CAMERA_HARDWARE_STUB_H
-#define ANDROID_HARDWARE_CAMERA_HARDWARE_STUB_H
-
-#include "FakeCamera.h"
-#include <utils/threads.h>
-#include <camera/CameraHardwareInterface.h>
-#include <binder/MemoryBase.h>
-#include <binder/MemoryHeapBase.h>
-#include <utils/threads.h>
-
-namespace android {
-
-class CameraHardwareStub : public CameraHardwareInterface {
-public:
- virtual status_t setPreviewWindow(const sp<ANativeWindow>& buf);
- virtual sp<IMemoryHeap> getRawHeap() const;
-
- virtual void setCallbacks(notify_callback notify_cb,
- data_callback data_cb,
- data_callback_timestamp data_cb_timestamp,
- void* user);
-
- virtual void enableMsgType(int32_t msgType);
- virtual void disableMsgType(int32_t msgType);
- virtual bool msgTypeEnabled(int32_t msgType);
-
- virtual status_t startPreview();
- virtual void stopPreview();
- virtual bool previewEnabled();
-
- virtual status_t startRecording();
- virtual void stopRecording();
- virtual bool recordingEnabled();
- virtual void releaseRecordingFrame(const sp<IMemory>& mem);
-
- virtual status_t autoFocus();
- virtual status_t cancelAutoFocus();
- virtual status_t takePicture();
- virtual status_t cancelPicture();
- virtual status_t dump(int fd, const Vector<String16>& args) const;
- virtual status_t setParameters(const CameraParameters& params);
- virtual CameraParameters getParameters() const;
- virtual status_t sendCommand(int32_t command, int32_t arg1,
- int32_t arg2);
- virtual void release();
-
- static sp<CameraHardwareInterface> createInstance();
-
-private:
- CameraHardwareStub();
- virtual ~CameraHardwareStub();
-
- static const int kBufferCount = 4;
-
- class PreviewThread : public Thread {
- CameraHardwareStub* mHardware;
- public:
- PreviewThread(CameraHardwareStub* hw) :
- Thread(false), mHardware(hw) { }
- virtual void onFirstRef() {
- run("CameraPreviewThread", PRIORITY_URGENT_DISPLAY);
- }
- virtual bool threadLoop() {
- mHardware->previewThread();
- // loop until we need to quit
- return true;
- }
- };
-
- void initDefaultParameters();
- void initHeapLocked();
-
- int previewThread();
-
- static int beginAutoFocusThread(void *cookie);
- int autoFocusThread();
-
- static int beginPictureThread(void *cookie);
- int pictureThread();
-
- mutable Mutex mLock;
-
- CameraParameters mParameters;
-
- sp<MemoryHeapBase> mPreviewHeap;
- sp<MemoryHeapBase> mRawHeap;
- sp<MemoryBase> mBuffers[kBufferCount];
-
- FakeCamera *mFakeCamera;
- bool mPreviewRunning;
- int mPreviewFrameSize;
-
- // protected by mLock
- sp<PreviewThread> mPreviewThread;
-
- notify_callback mNotifyCb;
- data_callback mDataCb;
- data_callback_timestamp mDataCbTimestamp;
- void *mCallbackCookie;
-
- int32_t mMsgEnabled;
-
- // only used from PreviewThread
- int mCurrentPreviewFrame;
-};
-
-}; // namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index bf07f8b..912ee4a 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -38,14 +38,15 @@
#include <utils/String16.h>
#include "CameraService.h"
-#include "CameraHardwareInterface.h"
+#include "CameraClient.h"
+#include "Camera2Client.h"
namespace android {
// ----------------------------------------------------------------------------
// Logging support -- this is for debugging only
// Use "adb shell dumpsys media.camera -v 1" to change it.
-static volatile int32_t gLogLevel = 0;
+volatile int32_t gLogLevel = 0;
#define LOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
#define LOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__);
@@ -133,7 +134,6 @@
sp<ICamera> CameraService::connect(
const sp<ICameraClient>& cameraClient, int cameraId) {
int callingPid = getCallingPid();
- sp<CameraHardwareInterface> hardware = NULL;
LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId);
@@ -186,16 +186,31 @@
return NULL;
}
- char camera_device_name[10];
- snprintf(camera_device_name, sizeof(camera_device_name), "%d", cameraId);
+ int deviceVersion;
+ if (mModule->common.module_api_version == CAMERA_MODULE_API_VERSION_2_0) {
+ deviceVersion = info.device_version;
+ } else {
+ deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
+ }
- hardware = new CameraHardwareInterface(camera_device_name);
- if (hardware->initialize(&mModule->common) != OK) {
- hardware.clear();
+ switch(deviceVersion) {
+ case CAMERA_DEVICE_API_VERSION_1_0:
+ client = new CameraClient(this, cameraClient, cameraId,
+ info.facing, callingPid);
+ break;
+ case CAMERA_DEVICE_API_VERSION_2_0:
+ client = new Camera2Client(this, cameraClient, cameraId,
+ info.facing, callingPid);
+ break;
+ default:
+ ALOGE("Unknown camera device HAL version: %d", deviceVersion);
return NULL;
}
- client = new Client(this, cameraClient, hardware, cameraId, info.facing, callingPid);
+ if (client->initialize(mModule) != OK) {
+ return NULL;
+ }
+
mClient[cameraId] = client;
LOG1("CameraService::connect X (id %d)", cameraId);
return client;
@@ -335,34 +350,17 @@
CameraService::Client::Client(const sp<CameraService>& cameraService,
const sp<ICameraClient>& cameraClient,
- const sp<CameraHardwareInterface>& hardware,
int cameraId, int cameraFacing, int clientPid) {
int callingPid = getCallingPid();
LOG1("Client::Client E (pid %d, id %d)", callingPid, cameraId);
mCameraService = cameraService;
mCameraClient = cameraClient;
- mHardware = hardware;
mCameraId = cameraId;
mCameraFacing = cameraFacing;
mClientPid = clientPid;
- mMsgEnabled = 0;
- mSurface = 0;
- mPreviewWindow = 0;
mDestructionStarted = false;
- mHardware->setCallbacks(notifyCallback,
- dataCallback,
- dataCallbackTimestamp,
- (void *)cameraId);
- // Enable zoom, error, focus, and metadata messages by default
- enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
- CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);
-
- // Callback is disabled by default
- mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
- mOrientation = getOrientation(0, mCameraFacing == CAMERA_FACING_FRONT);
- mPlayShutterSound = true;
cameraService->setCameraBusy(cameraId);
cameraService->loadSound();
LOG1("Client::Client X (pid %d, id %d)", callingPid, cameraId);
@@ -370,582 +368,7 @@
// tear down the client
CameraService::Client::~Client() {
- // this lock should never be NULL
- Mutex* lock = mCameraService->getClientLockById(mCameraId);
- lock->lock();
- mDestructionStarted = true;
- // client will not be accessed from callback. should unlock to prevent dead-lock in disconnect
- lock->unlock();
- int callingPid = getCallingPid();
- LOG1("Client::~Client E (pid %d, this %p)", callingPid, this);
-
- // set mClientPid to let disconnet() tear down the hardware
- mClientPid = callingPid;
- disconnect();
mCameraService->releaseSound();
- LOG1("Client::~Client X (pid %d, this %p)", callingPid, this);
-}
-
-// ----------------------------------------------------------------------------
-
-status_t CameraService::Client::checkPid() const {
- int callingPid = getCallingPid();
- if (callingPid == mClientPid) return NO_ERROR;
-
- ALOGW("attempt to use a locked camera from a different process"
- " (old pid %d, new pid %d)", mClientPid, callingPid);
- return EBUSY;
-}
-
-status_t CameraService::Client::checkPidAndHardware() const {
- status_t result = checkPid();
- if (result != NO_ERROR) return result;
- if (mHardware == 0) {
- ALOGE("attempt to use a camera after disconnect() (pid %d)", getCallingPid());
- return INVALID_OPERATION;
- }
- return NO_ERROR;
-}
-
-status_t CameraService::Client::lock() {
- int callingPid = getCallingPid();
- LOG1("lock (pid %d)", callingPid);
- Mutex::Autolock ilock(mICameraLock);
- Mutex::Autolock lock(mLock);
-
- // lock camera to this client if the the camera is unlocked
- if (mClientPid == 0) {
- mClientPid = callingPid;
- return NO_ERROR;
- }
-
- // returns NO_ERROR if the client already owns the camera, EBUSY otherwise
- return checkPid();
-}
-
-status_t CameraService::Client::unlock() {
- int callingPid = getCallingPid();
- LOG1("unlock (pid %d)", callingPid);
- Mutex::Autolock iLock(mICameraLock);
- Mutex::Autolock lock(mLock);
-
- // allow anyone to use camera (after they lock the camera)
- status_t result = checkPid();
- if (result == NO_ERROR) {
- if (mHardware->recordingEnabled()) {
- ALOGE("Not allowed to unlock camera during recording.");
- return INVALID_OPERATION;
- }
- mClientPid = 0;
- LOG1("clear mCameraClient (pid %d)", callingPid);
- // we need to remove the reference to ICameraClient so that when the app
- // goes away, the reference count goes to 0.
- mCameraClient.clear();
- }
- return result;
-}
-
-// connect a new client to the camera
-status_t CameraService::Client::connect(const sp<ICameraClient>& client) {
- int callingPid = getCallingPid();
- LOG1("connect E (pid %d)", callingPid);
- Mutex::Autolock iLock(mICameraLock);
- Mutex::Autolock lock(mLock);
-
- if (mClientPid != 0 && checkPid() != NO_ERROR) {
- ALOGW("Tried to connect to a locked camera (old pid %d, new pid %d)",
- mClientPid, callingPid);
- return EBUSY;
- }
-
- if (mCameraClient != 0 && (client->asBinder() == mCameraClient->asBinder())) {
- LOG1("Connect to the same client");
- return NO_ERROR;
- }
-
- mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
- mClientPid = callingPid;
- mCameraClient = client;
-
- LOG1("connect X (pid %d)", callingPid);
- return NO_ERROR;
-}
-
-static void disconnectWindow(const sp<ANativeWindow>& window) {
- if (window != 0) {
- status_t result = native_window_api_disconnect(window.get(),
- NATIVE_WINDOW_API_CAMERA);
- if (result != NO_ERROR) {
- ALOGW("native_window_api_disconnect failed: %s (%d)", strerror(-result),
- result);
- }
- }
-}
-
-void CameraService::Client::disconnect() {
- int callingPid = getCallingPid();
- LOG1("disconnect E (pid %d)", callingPid);
- Mutex::Autolock iLock(mICameraLock);
- Mutex::Autolock lock(mLock);
-
- if (checkPid() != NO_ERROR) {
- ALOGW("different client - don't disconnect");
- return;
- }
-
- if (mClientPid <= 0) {
- LOG1("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);
- return;
- }
-
- // Make sure disconnect() is done once and once only, whether it is called
- // from the user directly, or called by the destructor.
- if (mHardware == 0) return;
-
- LOG1("hardware teardown");
- // Before destroying mHardware, we must make sure it's in the
- // idle state.
- // Turn off all messages.
- disableMsgType(CAMERA_MSG_ALL_MSGS);
- mHardware->stopPreview();
- mHardware->cancelPicture();
- // Release the hardware resources.
- mHardware->release();
-
- // Release the held ANativeWindow resources.
- if (mPreviewWindow != 0) {
- disconnectWindow(mPreviewWindow);
- mPreviewWindow = 0;
- mHardware->setPreviewWindow(mPreviewWindow);
- }
- mHardware.clear();
-
- mCameraService->removeClient(mCameraClient);
- mCameraService->setCameraFree(mCameraId);
-
- LOG1("disconnect X (pid %d)", callingPid);
-}
-
-// ----------------------------------------------------------------------------
-
-status_t CameraService::Client::setPreviewWindow(const sp<IBinder>& binder,
- const sp<ANativeWindow>& window) {
- Mutex::Autolock iLock(mICameraLock);
- Mutex::Autolock lock(mLock);
- status_t result = checkPidAndHardware();
- if (result != NO_ERROR) return result;
-
- // return if no change in surface.
- if (binder == mSurface) {
- return NO_ERROR;
- }
-
- if (window != 0) {
- result = native_window_api_connect(window.get(), NATIVE_WINDOW_API_CAMERA);
- if (result != NO_ERROR) {
- ALOGE("native_window_api_connect failed: %s (%d)", strerror(-result),
- result);
- return result;
- }
- }
-
- // If preview has been already started, register preview buffers now.
- if (mHardware->previewEnabled()) {
- if (window != 0) {
- native_window_set_scaling_mode(window.get(),
- NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- native_window_set_buffers_transform(window.get(), mOrientation);
- result = mHardware->setPreviewWindow(window);
- }
- }
-
- if (result == NO_ERROR) {
- // Everything has succeeded. Disconnect the old window and remember the
- // new window.
- disconnectWindow(mPreviewWindow);
- mSurface = binder;
- mPreviewWindow = window;
- } else {
- // Something went wrong after we connected to the new window, so
- // disconnect here.
- disconnectWindow(window);
- }
-
- return result;
-}
-
-// set the Surface that the preview will use
-status_t CameraService::Client::setPreviewDisplay(const sp<Surface>& surface) {
- LOG1("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid());
-
- sp<IBinder> binder(surface != 0 ? surface->asBinder() : 0);
- sp<ANativeWindow> window(surface);
- return setPreviewWindow(binder, window);
-}
-
-// set the SurfaceTexture that the preview will use
-status_t CameraService::Client::setPreviewTexture(
- const sp<ISurfaceTexture>& surfaceTexture) {
- LOG1("setPreviewTexture(%p) (pid %d)", surfaceTexture.get(),
- getCallingPid());
-
- sp<IBinder> binder;
- sp<ANativeWindow> window;
- if (surfaceTexture != 0) {
- binder = surfaceTexture->asBinder();
- window = new SurfaceTextureClient(surfaceTexture);
- }
- return setPreviewWindow(binder, window);
-}
-
-// set the preview callback flag to affect how the received frames from
-// preview are handled.
-void CameraService::Client::setPreviewCallbackFlag(int callback_flag) {
- LOG1("setPreviewCallbackFlag(%d) (pid %d)", callback_flag, getCallingPid());
- Mutex::Autolock iLock(mICameraLock);
- Mutex::Autolock lock(mLock);
- if (checkPidAndHardware() != NO_ERROR) return;
-
- mPreviewCallbackFlag = callback_flag;
- if (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) {
- enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
- } else {
- disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
- }
-}
-
-// start preview mode
-status_t CameraService::Client::startPreview() {
- LOG1("startPreview (pid %d)", getCallingPid());
- return startCameraMode(CAMERA_PREVIEW_MODE);
-}
-
-// start recording mode
-status_t CameraService::Client::startRecording() {
- LOG1("startRecording (pid %d)", getCallingPid());
- return startCameraMode(CAMERA_RECORDING_MODE);
-}
-
-// start preview or recording
-status_t CameraService::Client::startCameraMode(camera_mode mode) {
- LOG1("startCameraMode(%d)", mode);
- Mutex::Autolock iLock(mICameraLock);
- Mutex::Autolock lock(mLock);
- status_t result = checkPidAndHardware();
- if (result != NO_ERROR) return result;
-
- switch(mode) {
- case CAMERA_PREVIEW_MODE:
- if (mSurface == 0 && mPreviewWindow == 0) {
- LOG1("mSurface is not set yet.");
- // still able to start preview in this case.
- }
- return startPreviewMode();
- case CAMERA_RECORDING_MODE:
- if (mSurface == 0 && mPreviewWindow == 0) {
- ALOGE("mSurface or mPreviewWindow must be set before startRecordingMode.");
- return INVALID_OPERATION;
- }
- return startRecordingMode();
- default:
- return UNKNOWN_ERROR;
- }
-}
-
-status_t CameraService::Client::startPreviewMode() {
- LOG1("startPreviewMode");
- status_t result = NO_ERROR;
-
- // if preview has been enabled, nothing needs to be done
- if (mHardware->previewEnabled()) {
- return NO_ERROR;
- }
-
- if (mPreviewWindow != 0) {
- native_window_set_scaling_mode(mPreviewWindow.get(),
- NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- native_window_set_buffers_transform(mPreviewWindow.get(),
- mOrientation);
- }
- mHardware->setPreviewWindow(mPreviewWindow);
- result = mHardware->startPreview();
-
- return result;
-}
-
-status_t CameraService::Client::startRecordingMode() {
- LOG1("startRecordingMode");
- status_t result = NO_ERROR;
-
- // if recording has been enabled, nothing needs to be done
- if (mHardware->recordingEnabled()) {
- return NO_ERROR;
- }
-
- // if preview has not been started, start preview first
- if (!mHardware->previewEnabled()) {
- result = startPreviewMode();
- if (result != NO_ERROR) {
- return result;
- }
- }
-
- // start recording mode
- enableMsgType(CAMERA_MSG_VIDEO_FRAME);
- mCameraService->playSound(SOUND_RECORDING);
- result = mHardware->startRecording();
- if (result != NO_ERROR) {
- ALOGE("mHardware->startRecording() failed with status %d", result);
- }
- return result;
-}
-
-// stop preview mode
-void CameraService::Client::stopPreview() {
- LOG1("stopPreview (pid %d)", getCallingPid());
- Mutex::Autolock iLock(mICameraLock);
- Mutex::Autolock lock(mLock);
- if (checkPidAndHardware() != NO_ERROR) return;
-
-
- disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
- mHardware->stopPreview();
-
- mPreviewBuffer.clear();
-}
-
-// stop recording mode
-void CameraService::Client::stopRecording() {
- LOG1("stopRecording (pid %d)", getCallingPid());
- Mutex::Autolock iLock(mICameraLock);
- Mutex::Autolock lock(mLock);
- if (checkPidAndHardware() != NO_ERROR) return;
-
- mCameraService->playSound(SOUND_RECORDING);
- disableMsgType(CAMERA_MSG_VIDEO_FRAME);
- mHardware->stopRecording();
-
- mPreviewBuffer.clear();
-}
-
-// release a recording frame
-void CameraService::Client::releaseRecordingFrame(const sp<IMemory>& mem) {
- Mutex::Autolock iLock(mICameraLock);
- Mutex::Autolock lock(mLock);
- if (checkPidAndHardware() != NO_ERROR) return;
- mHardware->releaseRecordingFrame(mem);
-}
-
-status_t CameraService::Client::storeMetaDataInBuffers(bool enabled)
-{
- LOG1("storeMetaDataInBuffers: %s", enabled? "true": "false");
- Mutex::Autolock iLock(mICameraLock);
- Mutex::Autolock lock(mLock);
- if (checkPidAndHardware() != NO_ERROR) {
- return UNKNOWN_ERROR;
- }
- return mHardware->storeMetaDataInBuffers(enabled);
-}
-
-bool CameraService::Client::previewEnabled() {
- LOG1("previewEnabled (pid %d)", getCallingPid());
-
- Mutex::Autolock iLock(mICameraLock);
- Mutex::Autolock lock(mLock);
- if (checkPidAndHardware() != NO_ERROR) return false;
- return mHardware->previewEnabled();
-}
-
-bool CameraService::Client::recordingEnabled() {
- LOG1("recordingEnabled (pid %d)", getCallingPid());
-
- Mutex::Autolock iLock(mICameraLock);
- Mutex::Autolock lock(mLock);
- if (checkPidAndHardware() != NO_ERROR) return false;
- return mHardware->recordingEnabled();
-}
-
-status_t CameraService::Client::autoFocus() {
- LOG1("autoFocus (pid %d)", getCallingPid());
-
- Mutex::Autolock iLock(mICameraLock);
- Mutex::Autolock lock(mLock);
- status_t result = checkPidAndHardware();
- if (result != NO_ERROR) return result;
-
- return mHardware->autoFocus();
-}
-
-status_t CameraService::Client::cancelAutoFocus() {
- LOG1("cancelAutoFocus (pid %d)", getCallingPid());
-
- Mutex::Autolock iLock(mICameraLock);
- Mutex::Autolock lock(mLock);
- status_t result = checkPidAndHardware();
- if (result != NO_ERROR) return result;
-
- return mHardware->cancelAutoFocus();
-}
-
-// take a picture - image is returned in callback
-status_t CameraService::Client::takePicture(int msgType) {
- LOG1("takePicture (pid %d): 0x%x", getCallingPid(), msgType);
-
- Mutex::Autolock iLock(mICameraLock);
- int picMsgType = 0;
- { // scope for lock
- Mutex::Autolock lock(mLock);
- status_t result = checkPidAndHardware();
- if (result != NO_ERROR) return result;
-
- if ((msgType & CAMERA_MSG_RAW_IMAGE) &&
- (msgType & CAMERA_MSG_RAW_IMAGE_NOTIFY)) {
- ALOGE("CAMERA_MSG_RAW_IMAGE and CAMERA_MSG_RAW_IMAGE_NOTIFY"
- " cannot be both enabled");
- return BAD_VALUE;
- }
-
- // We only accept picture related message types
- // and ignore other types of messages for takePicture().
- picMsgType = msgType
- & (CAMERA_MSG_SHUTTER |
- CAMERA_MSG_POSTVIEW_FRAME |
- CAMERA_MSG_RAW_IMAGE |
- CAMERA_MSG_RAW_IMAGE_NOTIFY |
- CAMERA_MSG_COMPRESSED_IMAGE);
-
- }
- enableMsgType(picMsgType);
-
- return mHardware->takePicture();
-}
-
-// set preview/capture parameters - key/value pairs
-status_t CameraService::Client::setParameters(const String8& params) {
- LOG1("setParameters (pid %d) (%s)", getCallingPid(), params.string());
-
- Mutex::Autolock iLock(mICameraLock);
- Mutex::Autolock lock(mLock);
- status_t result = checkPidAndHardware();
- if (result != NO_ERROR) return result;
-
- CameraParameters p(params);
- return mHardware->setParameters(p);
-}
-
-// get preview/capture parameters - key/value pairs
-String8 CameraService::Client::getParameters() const {
- Mutex::Autolock iLock(mICameraLock);
- Mutex::Autolock lock(mLock);
- if (checkPidAndHardware() != NO_ERROR) return String8();
-
- String8 params(mHardware->getParameters().flatten());
- LOG1("getParameters (pid %d) (%s)", getCallingPid(), params.string());
- return params;
-}
-
-// enable shutter sound
-status_t CameraService::Client::enableShutterSound(bool enable) {
- LOG1("enableShutterSound (pid %d)", getCallingPid());
-
- status_t result = checkPidAndHardware();
- if (result != NO_ERROR) return result;
-
- if (enable) {
- mPlayShutterSound = true;
- return OK;
- }
-
- // Disabling shutter sound may not be allowed. In that case only
- // allow the mediaserver process to disable the sound.
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.camera.sound.forced", value, "0");
- if (strcmp(value, "0") != 0) {
- // Disabling shutter sound is not allowed. Deny if the current
- // process is not mediaserver.
- if (getCallingPid() != getpid()) {
- ALOGE("Failed to disable shutter sound. Permission denied (pid %d)", getCallingPid());
- return PERMISSION_DENIED;
- }
- }
-
- mPlayShutterSound = false;
- return OK;
-}
-
-status_t CameraService::Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
- LOG1("sendCommand (pid %d)", getCallingPid());
- int orientation;
- Mutex::Autolock iLock(mICameraLock);
- Mutex::Autolock lock(mLock);
- status_t result = checkPidAndHardware();
- if (result != NO_ERROR) return result;
-
- if (cmd == CAMERA_CMD_SET_DISPLAY_ORIENTATION) {
- // Mirror the preview if the camera is front-facing.
- orientation = getOrientation(arg1, mCameraFacing == CAMERA_FACING_FRONT);
- if (orientation == -1) return BAD_VALUE;
-
- if (mOrientation != orientation) {
- mOrientation = orientation;
- if (mPreviewWindow != 0) {
- native_window_set_buffers_transform(mPreviewWindow.get(),
- mOrientation);
- }
- }
- return OK;
- } else if (cmd == CAMERA_CMD_ENABLE_SHUTTER_SOUND) {
- switch (arg1) {
- case 0:
- enableShutterSound(false);
- break;
- case 1:
- enableShutterSound(true);
- break;
- default:
- return BAD_VALUE;
- }
- return OK;
- } else if (cmd == CAMERA_CMD_PLAY_RECORDING_SOUND) {
- mCameraService->playSound(SOUND_RECORDING);
- } else if (cmd == CAMERA_CMD_PING) {
- // If mHardware is 0, checkPidAndHardware will return error.
- return OK;
- }
-
- return mHardware->sendCommand(cmd, arg1, arg2);
-}
-
-// ----------------------------------------------------------------------------
-
-void CameraService::Client::enableMsgType(int32_t msgType) {
- android_atomic_or(msgType, &mMsgEnabled);
- mHardware->enableMsgType(msgType);
-}
-
-void CameraService::Client::disableMsgType(int32_t msgType) {
- android_atomic_and(~msgType, &mMsgEnabled);
- mHardware->disableMsgType(msgType);
-}
-
-#define CHECK_MESSAGE_INTERVAL 10 // 10ms
-bool CameraService::Client::lockIfMessageWanted(int32_t msgType) {
- int sleepCount = 0;
- while (mMsgEnabled & msgType) {
- if (mLock.tryLock() == NO_ERROR) {
- if (sleepCount > 0) {
- LOG1("lockIfMessageWanted(%d): waited for %d ms",
- msgType, sleepCount * CHECK_MESSAGE_INTERVAL);
- }
- return true;
- }
- if (sleepCount++ == 0) {
- LOG1("lockIfMessageWanted(%d): enter sleep", msgType);
- }
- usleep(CHECK_MESSAGE_INTERVAL * 1000);
- }
- ALOGW("lockIfMessageWanted(%d): dropped unwanted message", msgType);
- return false;
}
// ----------------------------------------------------------------------------
@@ -967,311 +390,12 @@
// destruction already started, so should not be accessed
if (client->mDestructionStarted) return NULL;
- // The checks below are not necessary and are for debugging only.
- if (client->mCameraService.get() != gCameraService) {
- ALOGE("mismatch service!");
- return NULL;
- }
-
- if (client->mHardware == 0) {
- ALOGE("mHardware == 0: callback after disconnect()?");
- return NULL;
- }
-
return client;
}
-// Callback messages can be dispatched to internal handlers or pass to our
-// client's callback functions, depending on the message type.
-//
-// notifyCallback:
-// CAMERA_MSG_SHUTTER handleShutter
-// (others) c->notifyCallback
-// dataCallback:
-// CAMERA_MSG_PREVIEW_FRAME handlePreviewData
-// CAMERA_MSG_POSTVIEW_FRAME handlePostview
-// CAMERA_MSG_RAW_IMAGE handleRawPicture
-// CAMERA_MSG_COMPRESSED_IMAGE handleCompressedPicture
-// (others) c->dataCallback
-// dataCallbackTimestamp
-// (others) c->dataCallbackTimestamp
-//
-// NOTE: the *Callback functions grab mLock of the client before passing
-// control to handle* functions. So the handle* functions must release the
-// lock before calling the ICameraClient's callbacks, so those callbacks can
-// invoke methods in the Client class again (For example, the preview frame
-// callback may want to releaseRecordingFrame). The handle* functions must
-// release the lock after all accesses to member variables, so it must be
-// handled very carefully.
-
-void CameraService::Client::notifyCallback(int32_t msgType, int32_t ext1,
- int32_t ext2, void* user) {
- LOG2("notifyCallback(%d)", msgType);
-
- Mutex* lock = getClientLockFromCookie(user);
- if (lock == NULL) return;
- Mutex::Autolock alock(*lock);
-
- Client* client = getClientFromCookie(user);
- if (client == NULL) return;
-
- if (!client->lockIfMessageWanted(msgType)) return;
-
- switch (msgType) {
- case CAMERA_MSG_SHUTTER:
- // ext1 is the dimension of the yuv picture.
- client->handleShutter();
- break;
- default:
- client->handleGenericNotify(msgType, ext1, ext2);
- break;
- }
-}
-
-void CameraService::Client::dataCallback(int32_t msgType,
- const sp<IMemory>& dataPtr, camera_frame_metadata_t *metadata, void* user) {
- LOG2("dataCallback(%d)", msgType);
-
- Mutex* lock = getClientLockFromCookie(user);
- if (lock == NULL) return;
- Mutex::Autolock alock(*lock);
-
- Client* client = getClientFromCookie(user);
- if (client == NULL) return;
-
- if (!client->lockIfMessageWanted(msgType)) return;
- if (dataPtr == 0 && metadata == NULL) {
- ALOGE("Null data returned in data callback");
- client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
- return;
- }
-
- switch (msgType & ~CAMERA_MSG_PREVIEW_METADATA) {
- case CAMERA_MSG_PREVIEW_FRAME:
- client->handlePreviewData(msgType, dataPtr, metadata);
- break;
- case CAMERA_MSG_POSTVIEW_FRAME:
- client->handlePostview(dataPtr);
- break;
- case CAMERA_MSG_RAW_IMAGE:
- client->handleRawPicture(dataPtr);
- break;
- case CAMERA_MSG_COMPRESSED_IMAGE:
- client->handleCompressedPicture(dataPtr);
- break;
- default:
- client->handleGenericData(msgType, dataPtr, metadata);
- break;
- }
-}
-
-void CameraService::Client::dataCallbackTimestamp(nsecs_t timestamp,
- int32_t msgType, const sp<IMemory>& dataPtr, void* user) {
- LOG2("dataCallbackTimestamp(%d)", msgType);
-
- Mutex* lock = getClientLockFromCookie(user);
- if (lock == NULL) return;
- Mutex::Autolock alock(*lock);
-
- Client* client = getClientFromCookie(user);
- if (client == NULL) return;
-
- if (!client->lockIfMessageWanted(msgType)) return;
-
- if (dataPtr == 0) {
- ALOGE("Null data returned in data with timestamp callback");
- client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
- return;
- }
-
- client->handleGenericDataTimestamp(timestamp, msgType, dataPtr);
-}
-
-// snapshot taken callback
-void CameraService::Client::handleShutter(void) {
- if (mPlayShutterSound) {
- mCameraService->playSound(SOUND_SHUTTER);
- }
-
- sp<ICameraClient> c = mCameraClient;
- if (c != 0) {
- mLock.unlock();
- c->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
- if (!lockIfMessageWanted(CAMERA_MSG_SHUTTER)) return;
- }
- disableMsgType(CAMERA_MSG_SHUTTER);
-
- mLock.unlock();
-}
-
-// preview callback - frame buffer update
-void CameraService::Client::handlePreviewData(int32_t msgType,
- const sp<IMemory>& mem,
- camera_frame_metadata_t *metadata) {
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
-
- // local copy of the callback flags
- int flags = mPreviewCallbackFlag;
-
- // is callback enabled?
- if (!(flags & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
- // If the enable bit is off, the copy-out and one-shot bits are ignored
- LOG2("frame callback is disabled");
- mLock.unlock();
- return;
- }
-
- // hold a strong pointer to the client
- sp<ICameraClient> c = mCameraClient;
-
- // clear callback flags if no client or one-shot mode
- if (c == 0 || (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) {
- LOG2("Disable preview callback");
- mPreviewCallbackFlag &= ~(CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
- CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
- CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
- disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
- }
-
- if (c != 0) {
- // Is the received frame copied out or not?
- if (flags & CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
- LOG2("frame is copied");
- copyFrameAndPostCopiedFrame(msgType, c, heap, offset, size, metadata);
- } else {
- LOG2("frame is forwarded");
- mLock.unlock();
- c->dataCallback(msgType, mem, metadata);
- }
- } else {
- mLock.unlock();
- }
-}
-
-// picture callback - postview image ready
-void CameraService::Client::handlePostview(const sp<IMemory>& mem) {
- disableMsgType(CAMERA_MSG_POSTVIEW_FRAME);
-
- sp<ICameraClient> c = mCameraClient;
- mLock.unlock();
- if (c != 0) {
- c->dataCallback(CAMERA_MSG_POSTVIEW_FRAME, mem, NULL);
- }
-}
-
-// picture callback - raw image ready
-void CameraService::Client::handleRawPicture(const sp<IMemory>& mem) {
- disableMsgType(CAMERA_MSG_RAW_IMAGE);
-
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
-
- sp<ICameraClient> c = mCameraClient;
- mLock.unlock();
- if (c != 0) {
- c->dataCallback(CAMERA_MSG_RAW_IMAGE, mem, NULL);
- }
-}
-
-// picture callback - compressed picture ready
-void CameraService::Client::handleCompressedPicture(const sp<IMemory>& mem) {
- disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
-
- sp<ICameraClient> c = mCameraClient;
- mLock.unlock();
- if (c != 0) {
- c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem, NULL);
- }
-}
-
-
-void CameraService::Client::handleGenericNotify(int32_t msgType,
- int32_t ext1, int32_t ext2) {
- sp<ICameraClient> c = mCameraClient;
- mLock.unlock();
- if (c != 0) {
- c->notifyCallback(msgType, ext1, ext2);
- }
-}
-
-void CameraService::Client::handleGenericData(int32_t msgType,
- const sp<IMemory>& dataPtr, camera_frame_metadata_t *metadata) {
- sp<ICameraClient> c = mCameraClient;
- mLock.unlock();
- if (c != 0) {
- c->dataCallback(msgType, dataPtr, metadata);
- }
-}
-
-void CameraService::Client::handleGenericDataTimestamp(nsecs_t timestamp,
- int32_t msgType, const sp<IMemory>& dataPtr) {
- sp<ICameraClient> c = mCameraClient;
- mLock.unlock();
- if (c != 0) {
- c->dataCallbackTimestamp(timestamp, msgType, dataPtr);
- }
-}
-
-void CameraService::Client::copyFrameAndPostCopiedFrame(
- int32_t msgType, const sp<ICameraClient>& client,
- const sp<IMemoryHeap>& heap, size_t offset, size_t size,
- camera_frame_metadata_t *metadata) {
- LOG2("copyFrameAndPostCopiedFrame");
- // It is necessary to copy out of pmem before sending this to
- // the callback. For efficiency, reuse the same MemoryHeapBase
- // provided it's big enough. Don't allocate the memory or
- // perform the copy if there's no callback.
- // hold the preview lock while we grab a reference to the preview buffer
- sp<MemoryHeapBase> previewBuffer;
-
- if (mPreviewBuffer == 0) {
- mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
- } else if (size > mPreviewBuffer->virtualSize()) {
- mPreviewBuffer.clear();
- mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
- }
- if (mPreviewBuffer == 0) {
- ALOGE("failed to allocate space for preview buffer");
- mLock.unlock();
- return;
- }
- previewBuffer = mPreviewBuffer;
-
- memcpy(previewBuffer->base(), (uint8_t *)heap->base() + offset, size);
-
- sp<MemoryBase> frame = new MemoryBase(previewBuffer, 0, size);
- if (frame == 0) {
- ALOGE("failed to allocate space for frame callback");
- mLock.unlock();
- return;
- }
-
- mLock.unlock();
- client->dataCallback(msgType, frame, metadata);
-}
-
-int CameraService::Client::getOrientation(int degrees, bool mirror) {
- if (!mirror) {
- if (degrees == 0) return 0;
- else if (degrees == 90) return HAL_TRANSFORM_ROT_90;
- else if (degrees == 180) return HAL_TRANSFORM_ROT_180;
- else if (degrees == 270) return HAL_TRANSFORM_ROT_270;
- } else { // Do mirror (horizontal flip)
- if (degrees == 0) { // FLIP_H and ROT_0
- return HAL_TRANSFORM_FLIP_H;
- } else if (degrees == 90) { // FLIP_H and ROT_90
- return HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90;
- } else if (degrees == 180) { // FLIP_H and ROT_180
- return HAL_TRANSFORM_FLIP_V;
- } else if (degrees == 270) { // FLIP_H and ROT_270
- return HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90;
- }
- }
- ALOGE("Invalid setDisplayOrientation degrees=%d", degrees);
- return -1;
+void CameraService::Client::disconnect() {
+ mCameraService->removeClient(mCameraClient);
+ mCameraService->setCameraFree(mCameraId);
}
// ----------------------------------------------------------------------------
@@ -1293,24 +417,18 @@
}
status_t CameraService::dump(int fd, const Vector<String16>& args) {
- static const char* kDeadlockedString = "CameraService may be deadlocked\n";
-
- const size_t SIZE = 256;
- char buffer[SIZE];
String8 result;
if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
- snprintf(buffer, SIZE, "Permission Denial: "
+ result.appendFormat("Permission Denial: "
"can't dump CameraService from pid=%d, uid=%d\n",
getCallingPid(),
getCallingUid());
- result.append(buffer);
write(fd, result.string(), result.size());
} else {
bool locked = tryLock(mServiceLock);
// failed to lock - CameraService is probably deadlocked
if (!locked) {
- String8 result(kDeadlockedString);
- write(fd, result.string(), result.size());
+ result.append("CameraService may be deadlocked\n");
}
bool hasClient = false;
@@ -1318,17 +436,10 @@
sp<Client> client = mClient[i].promote();
if (client == 0) continue;
hasClient = true;
- sprintf(buffer, "Client[%d] (%p) PID: %d\n",
- i,
- client->getCameraClient()->asBinder().get(),
- client->mClientPid);
- result.append(buffer);
- write(fd, result.string(), result.size());
- client->mHardware->dump(fd, args);
+ client->dump(fd, args);
}
if (!hasClient) {
- result.append("No camera client yet.\n");
- write(fd, result.string(), result.size());
+ result.append("No camera clients yet.\n");
}
if (locked) mServiceLock.unlock();
@@ -1336,14 +447,15 @@
// change logging level
int n = args.size();
for (int i = 0; i + 1 < n; i++) {
- if (args[i] == String16("-v")) {
+ String16 verboseOption("-v");
+ if (args[i] == verboseOption) {
String8 levelStr(args[i+1]);
int level = atoi(levelStr.string());
- sprintf(buffer, "Set Log Level to %d", level);
- result.append(buffer);
+ result.appendFormat("Setting log level to %d.\n", level);
setLogLevel(level);
}
}
+ write(fd, result.string(), result.size());
}
return NO_ERROR;
}
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 95ac197..630fca7 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -27,17 +27,18 @@
namespace android {
+extern volatile int32_t gLogLevel;
+
class MemoryHeapBase;
class MediaPlayer;
-class CameraHardwareInterface;
class CameraService :
public BinderService<CameraService>,
public BnCameraService
{
- class Client;
friend class BinderService<CameraService>;
public:
+ class Client;
static char const* getServiceName() { return "media.camera"; }
CameraService();
@@ -68,6 +69,68 @@
void playSound(sound_kind kind);
void releaseSound();
+ class Client : public BnCamera
+ {
+ public:
+ // ICamera interface (see ICamera for details)
+ virtual void disconnect();
+ virtual status_t connect(const sp<ICameraClient>& client) = 0;
+ virtual status_t lock() = 0;
+ virtual status_t unlock() = 0;
+ virtual status_t setPreviewDisplay(const sp<Surface>& surface) = 0;
+ virtual status_t setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture) = 0;
+ virtual void setPreviewCallbackFlag(int flag) = 0;
+ virtual status_t startPreview() = 0;
+ virtual void stopPreview() = 0;
+ virtual bool previewEnabled() = 0;
+ virtual status_t storeMetaDataInBuffers(bool enabled) = 0;
+ virtual status_t startRecording() = 0;
+ virtual void stopRecording() = 0;
+ virtual bool recordingEnabled() = 0;
+ virtual void releaseRecordingFrame(const sp<IMemory>& mem) = 0;
+ virtual status_t autoFocus() = 0;
+ virtual status_t cancelAutoFocus() = 0;
+ virtual status_t takePicture(int msgType) = 0;
+ virtual status_t setParameters(const String8& params) = 0;
+ virtual String8 getParameters() const = 0;
+ virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) = 0;
+
+ // Interface used by CameraService
+ Client(const sp<CameraService>& cameraService,
+ const sp<ICameraClient>& cameraClient,
+ int cameraId,
+ int cameraFacing,
+ int clientPid);
+ ~Client();
+
+ // return our camera client
+ const sp<ICameraClient>& getCameraClient() {
+ return mCameraClient;
+ }
+
+ virtual status_t initialize(camera_module_t *module) = 0;
+
+ virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+
+ protected:
+ static Mutex* getClientLockFromCookie(void* user);
+ // convert client from cookie. Client lock should be acquired before getting Client.
+ static Client* getClientFromCookie(void* user);
+
+ // the instance is in the middle of destruction. When this is set,
+ // the instance should not be accessed from callback.
+ // CameraService's mClientLock should be acquired to access this.
+ bool mDestructionStarted;
+
+ // these are initialized in the constructor.
+ sp<CameraService> mCameraService; // immutable after constructor
+ sp<ICameraClient> mCameraClient;
+ int mCameraId; // immutable after constructor
+ int mCameraFacing; // immutable after constructor
+ pid_t mClientPid;
+
+ };
+
private:
Mutex mServiceLock;
wp<Client> mClient[MAX_CAMERAS]; // protected by mServiceLock
@@ -86,147 +149,6 @@
sp<MediaPlayer> mSoundPlayer[NUM_SOUNDS];
int mSoundRef; // reference count (release all MediaPlayer when 0)
- class Client : public BnCamera
- {
- public:
- // ICamera interface (see ICamera for details)
- virtual void disconnect();
- virtual status_t connect(const sp<ICameraClient>& client);
- virtual status_t lock();
- virtual status_t unlock();
- virtual status_t setPreviewDisplay(const sp<Surface>& surface);
- virtual status_t setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture);
- virtual void setPreviewCallbackFlag(int flag);
- virtual status_t startPreview();
- virtual void stopPreview();
- virtual bool previewEnabled();
- virtual status_t storeMetaDataInBuffers(bool enabled);
- virtual status_t startRecording();
- virtual void stopRecording();
- virtual bool recordingEnabled();
- virtual void releaseRecordingFrame(const sp<IMemory>& mem);
- virtual status_t autoFocus();
- virtual status_t cancelAutoFocus();
- virtual status_t takePicture(int msgType);
- virtual status_t setParameters(const String8& params);
- virtual String8 getParameters() const;
- virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
- private:
- friend class CameraService;
- Client(const sp<CameraService>& cameraService,
- const sp<ICameraClient>& cameraClient,
- const sp<CameraHardwareInterface>& hardware,
- int cameraId,
- int cameraFacing,
- int clientPid);
- ~Client();
-
- // return our camera client
- const sp<ICameraClient>& getCameraClient() { return mCameraClient; }
-
- // check whether the calling process matches mClientPid.
- status_t checkPid() const;
- status_t checkPidAndHardware() const; // also check mHardware != 0
-
- // these are internal functions used to set up preview buffers
- status_t registerPreviewBuffers();
-
- // camera operation mode
- enum camera_mode {
- CAMERA_PREVIEW_MODE = 0, // frame automatically released
- CAMERA_RECORDING_MODE = 1, // frame has to be explicitly released by releaseRecordingFrame()
- };
- // these are internal functions used for preview/recording
- status_t startCameraMode(camera_mode mode);
- status_t startPreviewMode();
- status_t startRecordingMode();
-
- // internal function used by sendCommand to enable/disable shutter sound.
- status_t enableShutterSound(bool enable);
-
- // these are static callback functions
- static void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user);
- static void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
- camera_frame_metadata_t *metadata, void* user);
- static void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr, void* user);
- static Mutex* getClientLockFromCookie(void* user);
- // convert client from cookie. Client lock should be acquired before getting Client.
- static Client* getClientFromCookie(void* user);
- // handlers for messages
- void handleShutter(void);
- void handlePreviewData(int32_t msgType, const sp<IMemory>& mem,
- camera_frame_metadata_t *metadata);
- void handlePostview(const sp<IMemory>& mem);
- void handleRawPicture(const sp<IMemory>& mem);
- void handleCompressedPicture(const sp<IMemory>& mem);
- void handleGenericNotify(int32_t msgType, int32_t ext1, int32_t ext2);
- void handleGenericData(int32_t msgType, const sp<IMemory>& dataPtr,
- camera_frame_metadata_t *metadata);
- void handleGenericDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
-
- void copyFrameAndPostCopiedFrame(
- int32_t msgType,
- const sp<ICameraClient>& client,
- const sp<IMemoryHeap>& heap,
- size_t offset, size_t size,
- camera_frame_metadata_t *metadata);
-
- int getOrientation(int orientation, bool mirror);
-
- status_t setPreviewWindow(
- const sp<IBinder>& binder,
- const sp<ANativeWindow>& window);
-
- // these are initialized in the constructor.
- sp<CameraService> mCameraService; // immutable after constructor
- sp<ICameraClient> mCameraClient;
- int mCameraId; // immutable after constructor
- int mCameraFacing; // immutable after constructor
- pid_t mClientPid;
- sp<CameraHardwareInterface> mHardware; // cleared after disconnect()
- int mPreviewCallbackFlag;
- int mOrientation; // Current display orientation
- bool mPlayShutterSound;
-
- // Ensures atomicity among the public methods
- mutable Mutex mLock;
- // A lock to synchronize access through the ICamera binder
- // interface. The entire binder call should be done with mICameraLock
- // locked, to serialize ICamera access, even when mLock is disabled for
- // calls to the HAL.
- mutable Mutex mICameraLock;
- // This is a binder of Surface or SurfaceTexture.
- sp<IBinder> mSurface;
- sp<ANativeWindow> mPreviewWindow;
-
- // If the user want us to return a copy of the preview frame (instead
- // of the original one), we allocate mPreviewBuffer and reuse it if possible.
- sp<MemoryHeapBase> mPreviewBuffer;
-
- // the instance is in the middle of destruction. When this is set,
- // the instance should not be accessed from callback.
- // CameraService's mClientLock should be acquired to access this.
- bool mDestructionStarted;
-
- // We need to avoid the deadlock when the incoming command thread and
- // the CameraHardwareInterface callback thread both want to grab mLock.
- // An extra flag is used to tell the callback thread that it should stop
- // trying to deliver the callback messages if the client is not
- // interested in it anymore. For example, if the client is calling
- // stopPreview(), the preview frame messages do not need to be delivered
- // anymore.
-
- // This function takes the same parameter as the enableMsgType() and
- // disableMsgType() functions in CameraHardwareInterface.
- void enableMsgType(int32_t msgType);
- void disableMsgType(int32_t msgType);
- volatile int32_t mMsgEnabled;
-
- // This function keeps trying to grab mLock, or give up if the message
- // is found to be disabled. It returns true if mLock is grabbed.
- bool lockIfMessageWanted(int32_t msgType);
- };
-
camera_module_t *mModule;
};
diff --git a/services/camera/libcameraservice/CannedJpeg.h b/services/camera/libcameraservice/CannedJpeg.h
deleted file mode 100644
index 6dd99c1..0000000
--- a/services/camera/libcameraservice/CannedJpeg.h
+++ /dev/null
@@ -1,750 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-const int kCannedJpegWidth = 320;
-const int kCannedJpegHeight = 240;
-const int kCannedJpegSize = 8733;
-
-const char kCannedJpeg[] = {
- 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01,
- 0x01, 0x01, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0xff, 0xe1, 0x00, 0x66,
- 0x45, 0x78, 0x69, 0x66, 0x00, 0x00, 0x49, 0x49, 0x2a, 0x00, 0x08, 0x00,
- 0x00, 0x00, 0x04, 0x00, 0x1a, 0x01, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x3e, 0x00, 0x00, 0x00, 0x1b, 0x01, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x46, 0x00, 0x00, 0x00, 0x28, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x31, 0x01, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00,
- 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x50, 0x61, 0x69, 0x6e, 0x74, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x76, 0x33,
- 0x2e, 0x33, 0x36, 0x00, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02,
- 0x03, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x05,
- 0x08, 0x05, 0x05, 0x04, 0x04, 0x05, 0x0a, 0x07, 0x07, 0x06, 0x08, 0x0c,
- 0x0a, 0x0c, 0x0c, 0x0b, 0x0a, 0x0b, 0x0b, 0x0d, 0x0e, 0x12, 0x10, 0x0d,
- 0x0e, 0x11, 0x0e, 0x0b, 0x0b, 0x10, 0x16, 0x10, 0x11, 0x13, 0x14, 0x15,
- 0x15, 0x15, 0x0c, 0x0f, 0x17, 0x18, 0x16, 0x14, 0x18, 0x12, 0x14, 0x15,
- 0x14, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05,
- 0x09, 0x05, 0x05, 0x09, 0x14, 0x0d, 0x0b, 0x0d, 0x14, 0x14, 0x14, 0x14,
- 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
- 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
- 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
- 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xff, 0xc0,
- 0x00, 0x11, 0x08, 0x00, 0xf0, 0x01, 0x40, 0x03, 0x01, 0x22, 0x00, 0x02,
- 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x00, 0x1f, 0x00, 0x00, 0x01,
- 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
- 0x0a, 0x0b, 0xff, 0xc4, 0x00, 0xb5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03,
- 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01,
- 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13,
- 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23,
- 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82,
- 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29,
- 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46,
- 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
- 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76,
- 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
- 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4,
- 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
- 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,
- 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3,
- 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
- 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xc4, 0x00, 0x1f, 0x01, 0x00, 0x03,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
- 0x0a, 0x0b, 0xff, 0xc4, 0x00, 0xb5, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04,
- 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00,
- 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
- 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1,
- 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a,
- 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27,
- 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
- 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
- 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75,
- 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
- 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2,
- 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5,
- 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
- 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2,
- 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5,
- 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00,
- 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xf9, 0xd2, 0xa3, 0x95, 0xbb,
- 0x54, 0x84, 0xe0, 0x66, 0xa0, 0x27, 0x27, 0x35, 0xed, 0x9e, 0x50, 0x95,
- 0x2c, 0x4b, 0xc6, 0x6a, 0x35, 0x1b, 0x8e, 0x2a, 0x70, 0x30, 0x28, 0x00,
- 0xa8, 0xe5, 0x6e, 0x71, 0x52, 0x31, 0xda, 0x33, 0x50, 0x13, 0x93, 0x40,
- 0x09, 0x52, 0xc6, 0xb8, 0x19, 0xf5, 0xa6, 0x2a, 0xee, 0x6c, 0x54, 0xd4,
- 0x00, 0x54, 0x52, 0x36, 0x5b, 0x1e, 0x95, 0x23, 0xb6, 0xd5, 0xcd, 0x41,
- 0x40, 0x05, 0x4c, 0x8b, 0xb5, 0x7d, 0xea, 0x34, 0x5d, 0xcd, 0xed, 0x53,
- 0x50, 0x01, 0x50, 0xbb, 0x6e, 0x6f, 0x6a, 0x91, 0xdb, 0x6a, 0xfb, 0xd4,
- 0x34, 0x00, 0x54, 0xe8, 0xbb, 0x57, 0x15, 0x1c, 0x6b, 0x96, 0xcf, 0xa5,
- 0x4b, 0x40, 0x05, 0x42, 0xcd, 0xb9, 0xb3, 0x4f, 0x91, 0xb0, 0x31, 0xeb,
- 0x51, 0x50, 0x02, 0x81, 0x93, 0x53, 0xa8, 0xda, 0x31, 0x51, 0xc4, 0xbc,
- 0xe6, 0xa4, 0xa0, 0x00, 0x9c, 0x0a, 0x81, 0x8e, 0xe3, 0x9a, 0x92, 0x56,
- 0xe3, 0x15, 0x15, 0x00, 0x28, 0x19, 0x38, 0xa9, 0xc0, 0xc0, 0xc5, 0x47,
- 0x12, 0xf7, 0xa9, 0x28, 0x00, 0x27, 0x00, 0x9a, 0x80, 0x9c, 0x9c, 0xd3,
- 0xe5, 0x6e, 0xd5, 0x1d, 0x00, 0x2a, 0x8d, 0xc7, 0x15, 0x3d, 0x32, 0x35,
- 0xc0, 0xcf, 0xad, 0x3e, 0x80, 0x11, 0x8e, 0xd1, 0x9a, 0x82, 0x9f, 0x23,
- 0x64, 0xe3, 0xd2, 0x99, 0x40, 0x0e, 0x45, 0xdc, 0xde, 0xd5, 0x35, 0x36,
- 0x35, 0xc2, 0xfb, 0x9a, 0x75, 0x00, 0x35, 0xdb, 0x6a, 0xfb, 0xd4, 0x34,
- 0xe9, 0x1b, 0x73, 0x7b, 0x0a, 0x6d, 0x00, 0x3e, 0x35, 0xcb, 0x7b, 0x0a,
- 0x96, 0x91, 0x17, 0x6a, 0xd2, 0xd0, 0x03, 0x64, 0x6c, 0x2f, 0xb9, 0xa8,
- 0x69, 0xce, 0xdb, 0x9a, 0x9b, 0xd6, 0x80, 0x1f, 0x12, 0xe4, 0xe7, 0xd2,
- 0xa5, 0xa4, 0x51, 0xb4, 0x62, 0x97, 0xa5, 0x00, 0x67, 0xc9, 0xad, 0xd8,
- 0x91, 0x81, 0x72, 0x9f, 0x9d, 0x47, 0xfd, 0xb3, 0x65, 0xff, 0x00, 0x3f,
- 0x29, 0x5f, 0xa0, 0x1f, 0xf0, 0xe9, 0x6f, 0x09, 0x7f, 0xd0, 0xfb, 0xad,
- 0x7f, 0xe0, 0x24, 0x34, 0x7f, 0xc3, 0xa5, 0xbc, 0x25, 0xff, 0x00, 0x43,
- 0xee, 0xb5, 0xff, 0x00, 0x80, 0x90, 0xd7, 0x3f, 0xb7, 0x87, 0x73, 0x6f,
- 0x63, 0x33, 0xe0, 0x28, 0xf5, 0x9b, 0x11, 0xc9, 0xb9, 0x4c, 0xfd, 0x69,
- 0xff, 0x00, 0xdb, 0x96, 0x1f, 0xf3, 0xf5, 0x1f, 0xe7, 0x5f, 0x7d, 0x7f,
- 0xc3, 0xa5, 0xbc, 0x25, 0xff, 0x00, 0x43, 0xee, 0xb5, 0xff, 0x00, 0x80,
- 0x90, 0xd1, 0xff, 0x00, 0x0e, 0x96, 0xf0, 0x97, 0xfd, 0x0f, 0xba, 0xd7,
- 0xfe, 0x02, 0x43, 0x47, 0xb7, 0x87, 0x70, 0xf6, 0x33, 0x3e, 0x02, 0x93,
- 0x5b, 0xb1, 0x3c, 0x0b, 0x94, 0xc7, 0xd6, 0x99, 0xfd, 0xb3, 0x65, 0xff,
- 0x00, 0x3f, 0x29, 0xf9, 0xd7, 0xe8, 0x07, 0xfc, 0x3a, 0x5b, 0xc2, 0x5f,
- 0xf4, 0x3e, 0xeb, 0x5f, 0xf8, 0x09, 0x0d, 0x1f, 0xf0, 0xe9, 0x6f, 0x09,
- 0x7f, 0xd0, 0xfb, 0xad, 0x7f, 0xe0, 0x24, 0x34, 0xbd, 0xbc, 0x03, 0xd8,
- 0xcc, 0xf8, 0x0e, 0x3d, 0x6a, 0xc1, 0x47, 0x37, 0x29, 0x9f, 0xad, 0x3b,
- 0xfb, 0x72, 0xc3, 0xfe, 0x7e, 0xa3, 0xfc, 0xeb, 0xef, 0xaf, 0xf8, 0x74,
- 0xb7, 0x84, 0xbf, 0xe8, 0x7d, 0xd6, 0xbf, 0xf0, 0x12, 0x1a, 0x3f, 0xe1,
- 0xd2, 0xde, 0x12, 0xff, 0x00, 0xa1, 0xf7, 0x5a, 0xff, 0x00, 0xc0, 0x48,
- 0x69, 0xfb, 0x78, 0x77, 0x0f, 0x63, 0x33, 0xe0, 0x19, 0x35, 0xbb, 0x26,
- 0x3c, 0x5c, 0xa6, 0x3e, 0xb4, 0xdf, 0xed, 0x9b, 0x2f, 0xf9, 0xf9, 0x4a,
- 0xfd, 0x00, 0xff, 0x00, 0x87, 0x4b, 0x78, 0x4b, 0xfe, 0x87, 0xdd, 0x6b,
- 0xff, 0x00, 0x01, 0x21, 0xa3, 0xfe, 0x1d, 0x2d, 0xe1, 0x2f, 0xfa, 0x1f,
- 0x75, 0xaf, 0xfc, 0x04, 0x86, 0x97, 0xb7, 0x80, 0x7b, 0x19, 0x9f, 0x01,
- 0xa6, 0xb5, 0x60, 0xab, 0xff, 0x00, 0x1f, 0x51, 0xe7, 0xeb, 0x4e, 0xfe,
- 0xdc, 0xb0, 0xff, 0x00, 0x9f, 0xa8, 0xff, 0x00, 0x3a, 0xfb, 0xeb, 0xfe,
- 0x1d, 0x2d, 0xe1, 0x2f, 0xfa, 0x1f, 0x75, 0xaf, 0xfc, 0x04, 0x86, 0x8f,
- 0xf8, 0x74, 0xb7, 0x84, 0xbf, 0xe8, 0x7d, 0xd6, 0xbf, 0xf0, 0x12, 0x1a,
- 0x3d, 0xbc, 0x03, 0xd8, 0xcc, 0xf8, 0x05, 0xf5, 0xab, 0x26, 0x6f, 0xf8,
- 0xf9, 0x4c, 0x7d, 0x69, 0xbf, 0xdb, 0x36, 0x5f, 0xf3, 0xf2, 0x9f, 0x9d,
- 0x7e, 0x80, 0x7f, 0xc3, 0xa5, 0xbc, 0x25, 0xff, 0x00, 0x43, 0xee, 0xb5,
- 0xff, 0x00, 0x80, 0x90, 0xd1, 0xff, 0x00, 0x0e, 0x96, 0xf0, 0x97, 0xfd,
- 0x0f, 0xba, 0xd7, 0xfe, 0x02, 0x43, 0x47, 0xb7, 0x80, 0x7b, 0x19, 0x9f,
- 0x02, 0x26, 0xb5, 0x60, 0xab, 0x8f, 0xb5, 0x47, 0xf9, 0xd2, 0xff, 0x00,
- 0x6e, 0x58, 0x7f, 0xcf, 0xd4, 0x7f, 0x9d, 0x7d, 0xf5, 0xff, 0x00, 0x0e,
- 0x96, 0xf0, 0x97, 0xfd, 0x0f, 0xba, 0xd7, 0xfe, 0x02, 0x43, 0x47, 0xfc,
- 0x3a, 0x5b, 0xc2, 0x5f, 0xf4, 0x3e, 0xeb, 0x5f, 0xf8, 0x09, 0x0d, 0x1e,
- 0xde, 0x01, 0xec, 0x66, 0x7c, 0x00, 0xda, 0xd5, 0x93, 0x1c, 0xfd, 0xa5,
- 0x3f, 0x3a, 0x4f, 0xed, 0x8b, 0x2f, 0xf9, 0xf9, 0x4f, 0xce, 0xbf, 0x40,
- 0x3f, 0xe1, 0xd2, 0xde, 0x12, 0xff, 0x00, 0xa1, 0xf7, 0x5a, 0xff, 0x00,
- 0xc0, 0x48, 0x68, 0xff, 0x00, 0x87, 0x4b, 0x78, 0x4b, 0xfe, 0x87, 0xdd,
- 0x6b, 0xff, 0x00, 0x01, 0x21, 0xa7, 0xed, 0xe1, 0xdc, 0x3d, 0x8c, 0xcf,
- 0x81, 0x57, 0x5a, 0xb0, 0x51, 0x8f, 0xb5, 0x47, 0xf9, 0xd1, 0xfd, 0xb9,
- 0x61, 0xff, 0x00, 0x3f, 0x49, 0xf9, 0xd7, 0xdf, 0x5f, 0xf0, 0xe9, 0x6f,
- 0x09, 0x7f, 0xd0, 0xfb, 0xad, 0x7f, 0xe0, 0x24, 0x34, 0x7f, 0xc3, 0xa5,
- 0xbc, 0x25, 0xff, 0x00, 0x43, 0xee, 0xb5, 0xff, 0x00, 0x80, 0x90, 0xd2,
- 0xf6, 0xf0, 0x0f, 0x63, 0x33, 0xe0, 0x06, 0xd6, 0xac, 0x98, 0xe7, 0xed,
- 0x29, 0xf9, 0xd2, 0x0d, 0x62, 0xcb, 0xfe, 0x7e, 0x53, 0xf3, 0xaf, 0xd0,
- 0x0f, 0xf8, 0x74, 0xb7, 0x84, 0xbf, 0xe8, 0x7d, 0xd6, 0xbf, 0xf0, 0x12,
- 0x1a, 0x3f, 0xe1, 0xd2, 0xde, 0x12, 0xff, 0x00, 0xa1, 0xf7, 0x5a, 0xff,
- 0x00, 0xc0, 0x48, 0x69, 0xfb, 0x78, 0x77, 0x0f, 0x63, 0x33, 0xe0, 0x51,
- 0xad, 0xd8, 0x01, 0x8f, 0xb5, 0x47, 0xf9, 0xd0, 0x75, 0xcb, 0x0c, 0x7f,
- 0xc7, 0xca, 0x7e, 0x75, 0xf7, 0xd7, 0xfc, 0x3a, 0x5b, 0xc2, 0x5f, 0xf4,
- 0x3e, 0xeb, 0x5f, 0xf8, 0x09, 0x0d, 0x1f, 0xf0, 0xe9, 0x6f, 0x09, 0x7f,
- 0xd0, 0xfb, 0xad, 0x7f, 0xe0, 0x24, 0x34, 0x7b, 0x78, 0x77, 0x0f, 0x63,
- 0x33, 0xf3, 0xfc, 0xeb, 0x36, 0x44, 0xff, 0x00, 0xc7, 0xca, 0x7e, 0x74,
- 0xa3, 0x58, 0xb1, 0x24, 0x66, 0xe5, 0x31, 0xf5, 0xaf, 0xbf, 0xff, 0x00,
- 0xe1, 0xd2, 0xde, 0x12, 0xff, 0x00, 0xa1, 0xf7, 0x5a, 0xff, 0x00, 0xc0,
- 0x48, 0x68, 0xff, 0x00, 0x87, 0x4b, 0x78, 0x4b, 0xfe, 0x87, 0xdd, 0x6b,
- 0xff, 0x00, 0x01, 0x21, 0xa3, 0xdb, 0xc3, 0xb8, 0x7b, 0x19, 0x9f, 0x02,
- 0xff, 0x00, 0x6d, 0xd8, 0x7f, 0xcf, 0xd4, 0x7f, 0x9d, 0x07, 0x5c, 0xb1,
- 0x03, 0x8b, 0x94, 0xcf, 0xd6, 0xbe, 0xfa, 0xff, 0x00, 0x87, 0x4b, 0x78,
- 0x4b, 0xfe, 0x87, 0xdd, 0x6b, 0xff, 0x00, 0x01, 0x21, 0xa3, 0xfe, 0x1d,
- 0x2d, 0xe1, 0x2f, 0xfa, 0x1f, 0x75, 0xaf, 0xfc, 0x04, 0x86, 0x8f, 0x6f,
- 0x0e, 0xe1, 0xec, 0x66, 0x7e, 0x7f, 0xff, 0x00, 0x6c, 0xd9, 0x7f, 0xcf,
- 0xca, 0x7e, 0x74, 0xab, 0xac, 0x58, 0xe7, 0x9b, 0x94, 0xc7, 0xd6, 0xbe,
- 0xff, 0x00, 0xff, 0x00, 0x87, 0x4b, 0x78, 0x4b, 0xfe, 0x87, 0xdd, 0x6b,
- 0xff, 0x00, 0x01, 0x21, 0xa3, 0xfe, 0x1d, 0x2d, 0xe1, 0x2f, 0xfa, 0x1f,
- 0x75, 0xaf, 0xfc, 0x04, 0x86, 0x8f, 0x6f, 0x0e, 0xe1, 0xec, 0x66, 0x7c,
- 0x0b, 0xfd, 0xb9, 0x61, 0xff, 0x00, 0x3f, 0x51, 0xfe, 0x74, 0x8d, 0xae,
- 0x58, 0xed, 0x38, 0xb9, 0x4c, 0xfd, 0x6b, 0xef, 0xbf, 0xf8, 0x74, 0xb7,
- 0x84, 0xbf, 0xe8, 0x7d, 0xd6, 0xbf, 0xf0, 0x12, 0x1a, 0x3f, 0xe1, 0xd2,
- 0xde, 0x12, 0xff, 0x00, 0xa1, 0xf7, 0x5a, 0xff, 0x00, 0xc0, 0x48, 0x68,
- 0xf6, 0xf0, 0xee, 0x1e, 0xc6, 0x67, 0xe7, 0xff, 0x00, 0xf6, 0xc5, 0x97,
- 0xfc, 0xfc, 0xa7, 0xe7, 0x4e, 0x4d, 0x62, 0xc7, 0x77, 0x37, 0x29, 0xf9,
- 0xd7, 0xdf, 0xdf, 0xf0, 0xe9, 0x6f, 0x09, 0x7f, 0xd0, 0xfb, 0xad, 0x7f,
- 0xe0, 0x24, 0x34, 0x7f, 0xc3, 0xa5, 0xbc, 0x25, 0xff, 0x00, 0x43, 0xee,
- 0xb5, 0xff, 0x00, 0x80, 0x90, 0xd1, 0xed, 0xe1, 0xdc, 0x3d, 0x8c, 0xcf,
- 0x81, 0x7f, 0xb7, 0x2c, 0x3f, 0xe7, 0xea, 0x3f, 0xce, 0x91, 0xf5, 0xcb,
- 0x1c, 0x71, 0x72, 0x9f, 0x9d, 0x7d, 0xf7, 0xff, 0x00, 0x0e, 0x96, 0xf0,
- 0x97, 0xfd, 0x0f, 0xba, 0xd7, 0xfe, 0x02, 0x43, 0x47, 0xfc, 0x3a, 0x5b,
- 0xc2, 0x5f, 0xf4, 0x3e, 0xeb, 0x5f, 0xf8, 0x09, 0x0d, 0x1e, 0xde, 0x1d,
- 0xc3, 0xd8, 0xcc, 0xfc, 0xff, 0x00, 0xfe, 0xd9, 0xb2, 0xff, 0x00, 0x9f,
- 0x94, 0xfc, 0xe9, 0xd1, 0xeb, 0x36, 0x20, 0xe4, 0xdc, 0xa7, 0xe7, 0x5f,
- 0x7f, 0x7f, 0xc3, 0xa5, 0xbc, 0x25, 0xff, 0x00, 0x43, 0xee, 0xb5, 0xff,
- 0x00, 0x80, 0x90, 0xd1, 0xff, 0x00, 0x0e, 0x96, 0xf0, 0x97, 0xfd, 0x0f,
- 0xba, 0xd7, 0xfe, 0x02, 0x43, 0x47, 0xb7, 0x87, 0x70, 0xf6, 0x33, 0x3e,
- 0x05, 0xfe, 0xdc, 0xb0, 0xff, 0x00, 0x9f, 0xa8, 0xff, 0x00, 0x3a, 0x6c,
- 0x9a, 0xdd, 0x89, 0x18, 0x17, 0x29, 0xf9, 0xd7, 0xdf, 0x9f, 0xf0, 0xe9,
- 0x6f, 0x09, 0x7f, 0xd0, 0xfb, 0xad, 0x7f, 0xe0, 0x24, 0x34, 0x7f, 0xc3,
- 0xa5, 0xbc, 0x25, 0xff, 0x00, 0x43, 0xee, 0xb5, 0xff, 0x00, 0x80, 0x90,
- 0xd1, 0xed, 0xe1, 0xdc, 0x3d, 0x8c, 0xcf, 0xbc, 0xa8, 0xa2, 0x8a, 0xf3,
- 0x0e, 0xf0, 0xa2, 0x8a, 0x28, 0x00, 0xa2, 0x8a, 0x28, 0x00, 0xa2, 0x8a,
- 0x28, 0x00, 0xa2, 0x8a, 0x28, 0x00, 0xa2, 0x8a, 0x28, 0x00, 0xa2, 0x8a,
- 0x28, 0x00, 0xa2, 0x8a, 0x28, 0x00, 0xa2, 0xa0, 0xbb, 0xbd, 0xb7, 0xb0,
- 0x88, 0x49, 0x73, 0x3c, 0x56, 0xf1, 0x96, 0x0a, 0x1e, 0x57, 0x0a, 0x09,
- 0x3d, 0x06, 0x4f, 0x7a, 0x9e, 0x95, 0xd3, 0x76, 0xea, 0x01, 0x45, 0x14,
- 0x53, 0x00, 0xa2, 0x8a, 0x28, 0x00, 0xa2, 0x8a, 0x82, 0xda, 0xf6, 0xde,
- 0xf0, 0xca, 0x2d, 0xe7, 0x8a, 0x73, 0x13, 0x98, 0xe4, 0xf2, 0xdc, 0x36,
- 0xc6, 0x1d, 0x54, 0xe3, 0xa1, 0xf6, 0xa4, 0xda, 0x4e, 0xcc, 0x09, 0xe8,
- 0xa2, 0x8a, 0x60, 0x14, 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14,
- 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14,
- 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x02, 0xb8,
- 0x51, 0x45, 0x14, 0x05, 0xc2, 0x8a, 0x28, 0xa0, 0x2e, 0x14, 0x51, 0x45,
- 0x01, 0x70, 0xa2, 0x8a, 0x28, 0x18, 0x51, 0x45, 0x14, 0x0a, 0xe1, 0x45,
- 0x14, 0x50, 0x17, 0x0a, 0x28, 0xa2, 0x80, 0xb9, 0xca, 0xfc, 0x4a, 0xf0,
- 0x52, 0x78, 0xef, 0xc2, 0xb7, 0x1a, 0x76, 0xef, 0x2e, 0xe5, 0x4f, 0x9d,
- 0x6c, 0xe4, 0xe0, 0x09, 0x00, 0x38, 0xcf, 0xb1, 0xc9, 0x1f, 0x8e, 0x7b,
- 0x57, 0x3d, 0xf0, 0x5b, 0xc7, 0x53, 0x6b, 0xba, 0x6c, 0xda, 0x16, 0xaa,
- 0x5a, 0x3d, 0x73, 0x4a, 0xfd, 0xd4, 0x8b, 0x2f, 0xdf, 0x91, 0x01, 0xc0,
- 0x27, 0xdc, 0x1e, 0x0f, 0xe0, 0x7b, 0xd7, 0xa3, 0x5c, 0xdc, 0xc5, 0x67,
- 0x04, 0x93, 0xcf, 0x2a, 0x43, 0x0c, 0x60, 0xb3, 0xc9, 0x23, 0x05, 0x55,
- 0x1e, 0xa4, 0x9e, 0x95, 0xf3, 0x47, 0xc4, 0x8f, 0x1f, 0xe9, 0x36, 0xdf,
- 0x10, 0xed, 0x3c, 0x41, 0xe1, 0x39, 0x99, 0xaf, 0xa1, 0xe2, 0xea, 0x42,
- 0x98, 0x82, 0x72, 0x38, 0xe3, 0x90, 0x4e, 0x46, 0x41, 0xe9, 0x9c, 0x0c,
- 0x7a, 0xd7, 0xc4, 0x67, 0x98, 0x9a, 0x59, 0x3e, 0x26, 0x9e, 0x64, 0xa6,
- 0x93, 0x7e, 0xec, 0xe3, 0x7d, 0x65, 0x1e, 0xe9, 0x77, 0x8b, 0xd7, 0xd3,
- 0x4b, 0x99, 0x4d, 0xa8, 0xbe, 0x63, 0xe9, 0xca, 0x2b, 0xe4, 0x3d, 0x73,
- 0xe3, 0x3f, 0x8b, 0xb5, 0xc6, 0x6d, 0xfa, 0xb4, 0x96, 0x71, 0x9e, 0x91,
- 0x59, 0x0f, 0x28, 0x0f, 0xc4, 0x7c, 0xdf, 0x99, 0xae, 0x56, 0xe7, 0x5a,
- 0xd4, 0x6f, 0x18, 0xb5, 0xc5, 0xfd, 0xd4, 0xec, 0x7b, 0xc9, 0x33, 0x31,
- 0xfd, 0x4d, 0x78, 0x75, 0xf8, 0xfb, 0x0b, 0x07, 0x6a, 0x14, 0x65, 0x25,
- 0xe6, 0xd2, 0xff, 0x00, 0x32, 0x1d, 0x75, 0xd1, 0x1f, 0x73, 0x51, 0x5f,
- 0x0b, 0xdb, 0xea, 0xf7, 0xf6, 0xad, 0xba, 0x0b, 0xdb, 0x88, 0x58, 0x77,
- 0x8e, 0x56, 0x53, 0xfa, 0x1a, 0xe9, 0xf4, 0x5f, 0x8b, 0xfe, 0x2e, 0xd0,
- 0xd9, 0x7c, 0xad, 0x66, 0x7b, 0x84, 0x1f, 0xf2, 0xce, 0xec, 0xf9, 0xc0,
- 0xff, 0x00, 0xdf, 0x59, 0x23, 0xf0, 0x34, 0xa8, 0x71, 0xf6, 0x1a, 0x4e,
- 0xd5, 0xa8, 0x4a, 0x2b, 0xc9, 0xa7, 0xfe, 0x40, 0xab, 0xae, 0xa8, 0xfa,
- 0x13, 0xe2, 0xff, 0x00, 0x8f, 0xcf, 0x82, 0xfc, 0x3e, 0x21, 0xb3, 0x6d,
- 0xda, 0xcd, 0xfe, 0x62, 0xb5, 0x45, 0xe5, 0x97, 0xb1, 0x7c, 0x7b, 0x67,
- 0x8f, 0x72, 0x3d, 0xea, 0x5f, 0x84, 0x7e, 0x05, 0x6f, 0x04, 0x78, 0x60,
- 0x2d, 0xd1, 0x2d, 0xa9, 0xde, 0xb0, 0x9e, 0xe8, 0x93, 0x9d, 0xad, 0x8e,
- 0x17, 0xf0, 0x1d, 0x4f, 0xa9, 0x35, 0xe2, 0x5e, 0x13, 0xf8, 0x89, 0x61,
- 0xac, 0xfc, 0x49, 0x8f, 0xc4, 0x3e, 0x30, 0x76, 0xcc, 0x68, 0x16, 0xd8,
- 0x43, 0x19, 0x68, 0x61, 0x61, 0xd0, 0x91, 0x92, 0x40, 0x1c, 0x9e, 0x33,
- 0xc9, 0xcd, 0x7d, 0x3b, 0x63, 0x7f, 0x6d, 0xaa, 0x5a, 0x45, 0x75, 0x69,
- 0x3c, 0x77, 0x36, 0xd2, 0x8d, 0xc9, 0x2c, 0x4c, 0x19, 0x58, 0x7b, 0x11,
- 0x5e, 0xde, 0x4d, 0x8b, 0xa3, 0x9d, 0xe3, 0x2a, 0x66, 0x1c, 0xe9, 0xf2,
- 0x5e, 0x30, 0x8f, 0x58, 0xae, 0xb2, 0x6b, 0xbc, 0xbf, 0x05, 0xa1, 0x50,
- 0x6a, 0x6f, 0x98, 0xb1, 0x45, 0x14, 0x57, 0xdc, 0x9b, 0x5c, 0x28, 0xa2,
- 0x8a, 0x02, 0xe1, 0x45, 0x14, 0x50, 0x17, 0x0a, 0x28, 0xa2, 0x80, 0xb8,
- 0x51, 0x45, 0x14, 0x05, 0xc2, 0x8a, 0x28, 0xa0, 0x2e, 0x14, 0x51, 0x45,
- 0x01, 0x70, 0xa2, 0x8a, 0x28, 0x0b, 0x8d, 0xcd, 0x19, 0xa6, 0xe4, 0x51,
- 0x91, 0x55, 0x62, 0x47, 0x66, 0x8c, 0xd3, 0x72, 0x28, 0xc8, 0xa2, 0xc0,
- 0x3b, 0x34, 0x66, 0x9b, 0x91, 0x46, 0x45, 0x16, 0x01, 0xd9, 0xa3, 0x34,
- 0xdc, 0x8a, 0x32, 0x28, 0xb0, 0x0e, 0xcd, 0x19, 0xa6, 0xe4, 0x52, 0xe4,
- 0x51, 0x60, 0xb8, 0xb9, 0xa3, 0x34, 0xdc, 0x8a, 0x32, 0x28, 0xb0, 0x0e,
- 0xdd, 0x46, 0x69, 0xb9, 0x14, 0x64, 0x51, 0x60, 0x1d, 0x9a, 0xa7, 0xac,
- 0x6b, 0x16, 0x9a, 0x0e, 0x9b, 0x71, 0xa8, 0x5f, 0x4c, 0x20, 0xb5, 0x81,
- 0x37, 0xbb, 0x9e, 0xc3, 0xd0, 0x7a, 0x93, 0xd0, 0x0a, 0xb5, 0x91, 0x5f,
- 0x39, 0xfe, 0xd1, 0x1e, 0x37, 0x7d, 0x4b, 0x5a, 0x4f, 0x0f, 0x5b, 0x48,
- 0x45, 0xa5, 0x96, 0x1e, 0x70, 0xa7, 0xef, 0xca, 0x46, 0x40, 0x3f, 0xee,
- 0x83, 0xf9, 0x93, 0xe9, 0x5e, 0x06, 0x79, 0x9a, 0xc3, 0x27, 0xc1, 0x4b,
- 0x12, 0xd5, 0xe5, 0xb4, 0x57, 0x76, 0xff, 0x00, 0xab, 0xbf, 0x24, 0x44,
- 0xe5, 0xca, 0xae, 0x72, 0xbf, 0x12, 0xbe, 0x2a, 0xea, 0x3e, 0x3e, 0xbd,
- 0x78, 0xd5, 0x9e, 0xd3, 0x48, 0x46, 0xfd, 0xd5, 0xa2, 0x9f, 0xbd, 0xe8,
- 0xcf, 0xea, 0x7f, 0x41, 0xdb, 0xd4, 0xc3, 0xe0, 0x5f, 0x85, 0x1a, 0xd7,
- 0x8f, 0xed, 0xe6, 0xb9, 0xb1, 0xf2, 0x2d, 0xed, 0x22, 0x6d, 0x86, 0x7b,
- 0x96, 0x21, 0x59, 0xb1, 0x9c, 0x0c, 0x02, 0x4f, 0x51, 0xf9, 0xd7, 0x19,
- 0x5e, 0xcd, 0xf0, 0x73, 0xe3, 0x16, 0x97, 0xe1, 0x0d, 0x06, 0x4d, 0x23,
- 0x57, 0x49, 0x63, 0x44, 0x95, 0xa5, 0x86, 0x78, 0x53, 0x78, 0x21, 0xba,
- 0xab, 0x0e, 0xb9, 0xcf, 0x7f, 0x7f, 0x6a, 0xfc, 0x1b, 0x2e, 0xa9, 0x87,
- 0xcd, 0xb3, 0x2f, 0x69, 0x9c, 0xd5, 0x6a, 0x2e, 0xfa, 0xde, 0xda, 0xf4,
- 0x57, 0xe8, 0xbf, 0xe1, 0x8e, 0x48, 0xda, 0x52, 0xf7, 0x8f, 0x30, 0xf1,
- 0x57, 0x85, 0x75, 0x0f, 0x06, 0xeb, 0x12, 0x69, 0xba, 0x94, 0x42, 0x3b,
- 0x84, 0x01, 0x83, 0x21, 0xca, 0xba, 0x9e, 0x8c, 0xa7, 0xb8, 0xac, 0x8a,
- 0xed, 0x3e, 0x2c, 0xf8, 0xee, 0x1f, 0x1f, 0xf8, 0x9c, 0x5e, 0xda, 0xc2,
- 0xf0, 0xda, 0x41, 0x08, 0x82, 0x2f, 0x33, 0x01, 0xd8, 0x02, 0x49, 0x63,
- 0xe9, 0xc9, 0x3c, 0x57, 0x17, 0x5e, 0x26, 0x3e, 0x9e, 0x1e, 0x96, 0x2a,
- 0xa4, 0x30, 0xb2, 0xe6, 0xa6, 0x9b, 0xb3, 0xee, 0x88, 0x76, 0xbe, 0x81,
- 0x5a, 0x1a, 0x06, 0x83, 0x7b, 0xe2, 0x7d, 0x5e, 0xdf, 0x4d, 0xd3, 0xe2,
- 0xf3, 0xae, 0xa7, 0x38, 0x55, 0xce, 0x00, 0x00, 0x64, 0x92, 0x7b, 0x00,
- 0x39, 0xac, 0xfa, 0xea, 0x3e, 0x1b, 0x78, 0xc1, 0x7c, 0x0d, 0xe2, 0xcb,
- 0x5d, 0x52, 0x58, 0x4c, 0xf6, 0xe1, 0x5a, 0x39, 0x51, 0x3e, 0xf6, 0xd6,
- 0x18, 0x24, 0x7b, 0x8e, 0x0d, 0x67, 0x83, 0x85, 0x1a, 0x98, 0x8a, 0x70,
- 0xc4, 0x4b, 0x96, 0x0d, 0xae, 0x67, 0xd9, 0x5f, 0x50, 0x56, 0xbe, 0xa6,
- 0x97, 0x8d, 0x7e, 0x0e, 0xeb, 0xde, 0x06, 0xd3, 0x17, 0x50, 0xbb, 0x36,
- 0xf7, 0x56, 0x99, 0x0b, 0x24, 0x96, 0xae, 0x4f, 0x96, 0x4f, 0x4d, 0xc0,
- 0x81, 0xc1, 0x3c, 0x66, 0xa9, 0xfc, 0x3e, 0xf8, 0x93, 0xaa, 0x78, 0x03,
- 0x50, 0x0f, 0x6c, 0xe6, 0x7b, 0x07, 0x6f, 0xdf, 0xd9, 0x3b, 0x7c, 0x8e,
- 0x3d, 0x47, 0xa3, 0x7b, 0xfe, 0x79, 0xaf, 0x45, 0xf8, 0xad, 0xf1, 0xb3,
- 0x47, 0xf1, 0x27, 0x85, 0x26, 0xd2, 0x34, 0x84, 0x9a, 0x67, 0xbb, 0x2b,
- 0xe6, 0xcb, 0x34, 0x7b, 0x04, 0x6a, 0x18, 0x36, 0x07, 0xa9, 0xc8, 0x1e,
- 0xd5, 0xe1, 0x95, 0xf4, 0x39, 0xab, 0xc2, 0x65, 0x79, 0x84, 0x67, 0x93,
- 0x55, 0x6d, 0x24, 0x9d, 0xd3, 0xbd, 0x9f, 0x55, 0x7e, 0xaa, 0xd6, 0xbe,
- 0xfb, 0xd8, 0xb9, 0x5a, 0x32, 0xf7, 0x59, 0xf6, 0xef, 0x86, 0xbc, 0x49,
- 0x63, 0xe2, 0xbd, 0x1a, 0xdf, 0x53, 0xd3, 0xe5, 0xf3, 0x2d, 0xe6, 0x1d,
- 0xfe, 0xf2, 0x1e, 0xea, 0xc3, 0xb1, 0x15, 0xa9, 0x9a, 0xf9, 0x7b, 0xe0,
- 0x27, 0x8d, 0xe4, 0xf0, 0xef, 0x8a, 0x53, 0x4a, 0x9e, 0x43, 0xfd, 0x9f,
- 0xa9, 0x30, 0x8f, 0x69, 0x3c, 0x24, 0xdf, 0xc0, 0xc3, 0xeb, 0xf7, 0x7f,
- 0x11, 0xe9, 0x5f, 0x4f, 0xe4, 0x57, 0xee, 0x3c, 0x3f, 0x9b, 0xc7, 0x39,
- 0xc1, 0x2a, 0xed, 0x5a, 0x6b, 0x49, 0x2f, 0x3f, 0xf2, 0x7b, 0xfe, 0x1d,
- 0x0e, 0xb8, 0x4f, 0x99, 0x5c, 0x76, 0x4d, 0x19, 0xa6, 0xe4, 0x51, 0x91,
- 0x5f, 0x4b, 0x62, 0xc7, 0x64, 0xd1, 0x9a, 0x6e, 0x45, 0x19, 0x14, 0x58,
- 0x2e, 0x3b, 0x34, 0x66, 0x9b, 0x91, 0x46, 0x45, 0x16, 0x0b, 0x8e, 0xcd,
- 0x19, 0xa6, 0xe4, 0x51, 0x91, 0x45, 0x80, 0x76, 0x68, 0xcd, 0x37, 0x34,
- 0x64, 0x51, 0x60, 0xb8, 0xec, 0xd1, 0x9a, 0x6e, 0x45, 0x19, 0x14, 0x58,
- 0x07, 0x64, 0xd1, 0x9a, 0x6e, 0x45, 0x19, 0x14, 0x58, 0x06, 0x6e, 0xa3,
- 0x75, 0x37, 0x34, 0x66, 0xae, 0xc4, 0x5c, 0x76, 0xea, 0x37, 0x53, 0x73,
- 0x46, 0x68, 0xb0, 0x5c, 0x76, 0xea, 0x37, 0x53, 0x73, 0x46, 0x68, 0xb0,
- 0x5c, 0x76, 0xea, 0x37, 0x53, 0x72, 0x28, 0xcd, 0x16, 0x0b, 0x8e, 0xdd,
- 0x46, 0xea, 0x6e, 0x68, 0xcd, 0x16, 0x0b, 0x8e, 0xdd, 0x46, 0xea, 0x6e,
- 0x68, 0xcd, 0x16, 0x0b, 0x8e, 0xdd, 0x46, 0xea, 0xc4, 0xf1, 0x57, 0x8c,
- 0x34, 0xaf, 0x06, 0x69, 0xff, 0x00, 0x6b, 0xd5, 0x2e, 0x44, 0x28, 0xc7,
- 0x08, 0x8a, 0x37, 0x3c, 0x87, 0xd1, 0x47, 0x7f, 0xe5, 0x5c, 0x0d, 0x9f,
- 0xed, 0x1f, 0xe1, 0xcb, 0x8b, 0xc1, 0x14, 0xd6, 0x97, 0xf6, 0xb0, 0x93,
- 0x81, 0x3b, 0xa2, 0xb0, 0x1e, 0xe4, 0x06, 0x27, 0xf2, 0xcd, 0x78, 0xf8,
- 0xac, 0xdf, 0x2f, 0xc0, 0xd4, 0x54, 0x71, 0x35, 0xa3, 0x19, 0x3e, 0x8d,
- 0xfe, 0x7d, 0xbe, 0x64, 0xb9, 0x25, 0xb9, 0xeb, 0x05, 0xf6, 0x82, 0x4f,
- 0x41, 0x5f, 0x10, 0xeb, 0x7a, 0x93, 0xeb, 0x3a, 0xcd, 0xf5, 0xfc, 0x84,
- 0x97, 0xb9, 0x9d, 0xe6, 0x39, 0xff, 0x00, 0x69, 0x89, 0xfe, 0xb5, 0xf6,
- 0xad, 0x8e, 0xa1, 0x6b, 0xab, 0x58, 0xc5, 0x75, 0x69, 0x34, 0x77, 0x36,
- 0xb3, 0x2e, 0xe4, 0x91, 0x0e, 0x55, 0x85, 0x78, 0x5f, 0xfc, 0x2d, 0x5f,
- 0x87, 0x3f, 0xf4, 0x25, 0x27, 0xfe, 0x00, 0xdb, 0xff, 0x00, 0x8d, 0x7c,
- 0x67, 0x18, 0xe1, 0xa8, 0x63, 0x61, 0x87, 0x55, 0x31, 0x31, 0xa7, 0x1f,
- 0x79, 0xab, 0xdd, 0xf3, 0x7c, 0x3a, 0xab, 0x76, 0xfd, 0x4c, 0xea, 0x59,
- 0xdb, 0x53, 0xc4, 0x68, 0xaf, 0x6e, 0xff, 0x00, 0x85, 0xab, 0xf0, 0xe7,
- 0xfe, 0x84, 0xa4, 0xff, 0x00, 0xc0, 0x1b, 0x7f, 0xf1, 0xa3, 0xfe, 0x16,
- 0xaf, 0xc3, 0x9f, 0xfa, 0x12, 0x93, 0xff, 0x00, 0x00, 0x6d, 0xff, 0x00,
- 0xc6, 0xbf, 0x33, 0xfe, 0xc5, 0xc0, 0xff, 0x00, 0xd0, 0x7c, 0x3e, 0xe9,
- 0x7f, 0x91, 0x8f, 0x2a, 0xee, 0x78, 0x8d, 0x15, 0xed, 0xdf, 0xf0, 0xb5,
- 0x7e, 0x1c, 0xff, 0x00, 0xd0, 0x94, 0x9f, 0xf8, 0x03, 0x6f, 0xfe, 0x34,
- 0x7f, 0xc2, 0xd5, 0xf8, 0x73, 0xff, 0x00, 0x42, 0x52, 0x7f, 0xe0, 0x0d,
- 0xbf, 0xf8, 0xd1, 0xfd, 0x8b, 0x81, 0xff, 0x00, 0xa0, 0xf8, 0x7d, 0xd2,
- 0xff, 0x00, 0x20, 0xe5, 0x5d, 0xcf, 0x11, 0xa2, 0xbd, 0xbb, 0xfe, 0x16,
- 0xaf, 0xc3, 0x9f, 0xfa, 0x12, 0x93, 0xff, 0x00, 0x00, 0x6d, 0xff, 0x00,
- 0xc6, 0x8f, 0xf8, 0x5a, 0xbf, 0x0e, 0x7f, 0xe8, 0x4a, 0x4f, 0xfc, 0x01,
- 0xb7, 0xff, 0x00, 0x1a, 0x3f, 0xb1, 0x70, 0x3f, 0xf4, 0x1f, 0x0f, 0xba,
- 0x5f, 0xe4, 0x1c, 0xab, 0xb9, 0xe2, 0x34, 0x57, 0xb7, 0x7f, 0xc2, 0xd5,
- 0xf8, 0x73, 0xff, 0x00, 0x42, 0x52, 0x7f, 0xe0, 0x0d, 0xbf, 0xf8, 0xd1,
- 0xff, 0x00, 0x0b, 0x57, 0xe1, 0xcf, 0xfd, 0x09, 0x49, 0xff, 0x00, 0x80,
- 0x36, 0xff, 0x00, 0xe3, 0x47, 0xf6, 0x2e, 0x07, 0xfe, 0x83, 0xe1, 0xf7,
- 0x4b, 0xfc, 0x83, 0x95, 0x77, 0x3c, 0x52, 0x09, 0xde, 0xda, 0x78, 0xe6,
- 0x89, 0x8a, 0x49, 0x1b, 0x07, 0x56, 0x1d, 0x41, 0x07, 0x20, 0xd7, 0xdb,
- 0xfa, 0x5d, 0xf0, 0xd4, 0x74, 0xdb, 0x4b, 0xb0, 0x30, 0x27, 0x85, 0x25,
- 0x03, 0xfd, 0xe5, 0x07, 0xfa, 0xd7, 0x85, 0xff, 0x00, 0xc2, 0xd5, 0xf8,
- 0x73, 0xff, 0x00, 0x42, 0x52, 0x7f, 0xe0, 0x0d, 0xbf, 0xf8, 0xd7, 0xb6,
- 0x69, 0x1a, 0x95, 0xa5, 0xc7, 0x87, 0xec, 0xaf, 0xe1, 0x55, 0xb3, 0xb1,
- 0x7b, 0x54, 0x99, 0x11, 0xf0, 0x82, 0x28, 0xca, 0x02, 0x01, 0xec, 0x30,
- 0x3f, 0x0e, 0x2b, 0xf4, 0x7e, 0x0e, 0xc2, 0xd0, 0xc1, 0xce, 0xbc, 0x69,
- 0x62, 0x63, 0x51, 0x34, 0x9b, 0x4a, 0xfa, 0x5a, 0xfa, 0xeb, 0xea, 0x6d,
- 0x4e, 0xca, 0xfa, 0x9a, 0x5b, 0xa8, 0xdd, 0x5e, 0x57, 0xab, 0xfe, 0xd1,
- 0x3e, 0x1b, 0xd3, 0xaf, 0x1a, 0x0b, 0x68, 0x6e, 0xf5, 0x15, 0x53, 0x83,
- 0x34, 0x28, 0xaa, 0x87, 0xe9, 0xb8, 0x82, 0x7f, 0x2a, 0xeb, 0xbc, 0x1b,
- 0xf1, 0x07, 0x45, 0xf1, 0xcd, 0xbb, 0xbe, 0x99, 0x70, 0x7c, 0xe8, 0xc6,
- 0x64, 0xb6, 0x98, 0x6d, 0x91, 0x07, 0xa9, 0x1d, 0xc7, 0xb8, 0xc8, 0xaf,
- 0xb7, 0xc3, 0xe7, 0x19, 0x76, 0x2a, 0xb7, 0xd5, 0xe8, 0x56, 0x8c, 0xa7,
- 0xd9, 0x3f, 0xcb, 0xbf, 0xc8, 0xd1, 0x49, 0x3d, 0x2e, 0x74, 0xdb, 0xa8,
- 0xcd, 0x37, 0x34, 0x64, 0x57, 0xb2, 0x55, 0xc7, 0x6e, 0xa3, 0x75, 0x37,
- 0x34, 0x66, 0x8b, 0x05, 0xc7, 0x6e, 0xa3, 0x75, 0x37, 0x34, 0x66, 0x8b,
- 0x05, 0xc7, 0x6e, 0xa3, 0x75, 0x37, 0x34, 0x66, 0x8b, 0x05, 0xc7, 0x6e,
- 0xa3, 0x75, 0x37, 0x34, 0x64, 0x51, 0x60, 0xb8, 0xed, 0xd4, 0x6e, 0xa6,
- 0xe4, 0x51, 0x9a, 0x2c, 0x17, 0x1b, 0x9a, 0x33, 0x51, 0xee, 0xa3, 0x75,
- 0x55, 0x88, 0xb9, 0x26, 0x68, 0xcd, 0x47, 0xba, 0x8d, 0xd4, 0x58, 0x2e,
- 0x49, 0x9a, 0x33, 0x51, 0xee, 0xa3, 0x75, 0x16, 0x15, 0xc9, 0x32, 0x28,
- 0xa8, 0xf7, 0x51, 0xba, 0x8b, 0x0e, 0xe4, 0x99, 0xa3, 0x35, 0x1e, 0xea,
- 0x37, 0x51, 0x60, 0xb9, 0x26, 0x68, 0xcd, 0x47, 0xba, 0x8c, 0xd3, 0xb0,
- 0x5c, 0xf9, 0x7b, 0xe3, 0xb6, 0xaf, 0x3e, 0xa5, 0xf1, 0x0e, 0xf2, 0xde,
- 0x47, 0x26, 0x1b, 0x24, 0x48, 0x62, 0x4e, 0xc0, 0x15, 0x0c, 0x4f, 0xe2,
- 0x58, 0xfe, 0x95, 0xe7, 0x95, 0xda, 0x7c, 0x64, 0xff, 0x00, 0x92, 0x97,
- 0xad, 0xff, 0x00, 0xbf, 0x1f, 0xfe, 0x8a, 0x4a, 0xe2, 0xeb, 0xf9, 0x47,
- 0x3a, 0x9c, 0xaa, 0x66, 0x78, 0x99, 0x49, 0xdd, 0xf3, 0xcb, 0xf0, 0x6d,
- 0x23, 0x92, 0x5b, 0x9e, 0xf7, 0xfb, 0x34, 0xeb, 0x13, 0xcd, 0x67, 0xac,
- 0xe9, 0xb2, 0x39, 0x6b, 0x78, 0x1a, 0x39, 0xa2, 0x04, 0xfd, 0xd2, 0xdb,
- 0x83, 0x0f, 0xc7, 0x68, 0xfd, 0x6b, 0xc1, 0x2b, 0xda, 0xff, 0x00, 0x66,
- 0x73, 0x8b, 0xed, 0x7f, 0xfe, 0xb9, 0xc3, 0xfc, 0xde, 0xbc, 0x52, 0xbd,
- 0x8c, 0xd2, 0x72, 0x9e, 0x4b, 0x97, 0x39, 0x3b, 0xdb, 0xda, 0xaf, 0x92,
- 0x92, 0xb1, 0x4f, 0xe1, 0x41, 0x45, 0x14, 0x57, 0xc6, 0x90, 0x14, 0x51,
- 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x15, 0xef,
- 0x7f, 0x13, 0xf5, 0x89, 0xf4, 0xef, 0x82, 0xbe, 0x19, 0xb6, 0x81, 0xca,
- 0x0b, 0xc8, 0x2d, 0x62, 0x94, 0x83, 0xd5, 0x04, 0x3b, 0x88, 0xfc, 0x48,
- 0x15, 0xe0, 0x95, 0xed, 0x7f, 0x17, 0x0f, 0xfc, 0x5a, 0x5f, 0x05, 0xff,
- 0x00, 0xd7, 0x38, 0x3f, 0xf4, 0x45, 0x7d, 0x96, 0x47, 0x39, 0x43, 0x03,
- 0x98, 0x4a, 0x2e, 0xcf, 0x91, 0x7e, 0x32, 0xb3, 0xfc, 0x0a, 0x8e, 0xcc,
- 0xf1, 0x4a, 0xe9, 0xbe, 0x1a, 0x6a, 0xf3, 0xe8, 0xbe, 0x3a, 0xd1, 0x67,
- 0x81, 0xca, 0x99, 0x2e, 0x52, 0x07, 0x00, 0xfd, 0xe4, 0x76, 0x0a, 0xc0,
- 0xfe, 0x07, 0xf4, 0xae, 0x66, 0xb6, 0x3c, 0x1b, 0xff, 0x00, 0x23, 0x7e,
- 0x87, 0xff, 0x00, 0x5f, 0xd0, 0x7f, 0xe8, 0xc5, 0xaf, 0x9b, 0xc0, 0xce,
- 0x54, 0xf1, 0x54, 0xa7, 0x07, 0x66, 0xa4, 0xbf, 0x31, 0x2d, 0xcf, 0xb4,
- 0x33, 0x46, 0x6a, 0x3d, 0xd4, 0x6e, 0xaf, 0xeb, 0x9b, 0x1d, 0x57, 0x24,
- 0xcd, 0x19, 0xa8, 0xf7, 0x51, 0xba, 0x8b, 0x0e, 0xe4, 0x99, 0xa3, 0x35,
- 0x1e, 0xea, 0x37, 0x51, 0x60, 0xb9, 0x26, 0x68, 0xcd, 0x47, 0xba, 0x8d,
- 0xd4, 0x58, 0x2e, 0x49, 0x9a, 0x33, 0x51, 0xee, 0xa3, 0x75, 0x16, 0x15,
- 0xc9, 0x33, 0x46, 0x6a, 0x3d, 0xd4, 0x6e, 0xa2, 0xc3, 0xb8, 0xdd, 0xd4,
- 0x9b, 0xa9, 0xbb, 0xa8, 0xdd, 0x5a, 0x19, 0xdc, 0x7e, 0xea, 0x4d, 0xd4,
- 0xdd, 0xd4, 0x6e, 0xa0, 0x57, 0x1f, 0xba, 0x8d, 0xd4, 0xcd, 0xd4, 0x6e,
- 0xa0, 0x77, 0x1f, 0xba, 0x8d, 0xd4, 0xcd, 0xd4, 0x6e, 0xa4, 0x2b, 0x8f,
- 0xdd, 0x49, 0xba, 0x9b, 0xba, 0x8d, 0xd4, 0xc2, 0xe3, 0xb7, 0x52, 0xee,
- 0xa6, 0x6e, 0xa3, 0x75, 0x20, 0xb9, 0xf2, 0x9f, 0xc6, 0x3f, 0xf9, 0x29,
- 0x5a, 0xdf, 0xfb, 0xf1, 0xff, 0x00, 0xe8, 0xb4, 0xae, 0x32, 0xbb, 0x2f,
- 0x8c, 0x5c, 0xfc, 0x49, 0xd6, 0xff, 0x00, 0xdf, 0x8f, 0xff, 0x00, 0x45,
- 0xa5, 0x71, 0xb5, 0xfc, 0x99, 0x9c, 0x7f, 0xc8, 0xcb, 0x13, 0xfe, 0x39,
- 0xff, 0x00, 0xe9, 0x4c, 0xc1, 0xee, 0x7b, 0x57, 0xec, 0xd2, 0x71, 0x7d,
- 0xaf, 0x7f, 0xd7, 0x38, 0x7f, 0x9b, 0xd7, 0x8a, 0xd7, 0xb4, 0x7e, 0xcd,
- 0x67, 0x17, 0xda, 0xf7, 0xfd, 0x73, 0x87, 0xf9, 0xbd, 0x78, 0xbd, 0x7b,
- 0x19, 0x97, 0xfc, 0x89, 0x32, 0xef, 0xfb, 0x8b, 0xff, 0x00, 0xa5, 0x21,
- 0xbd, 0x90, 0x51, 0x45, 0x15, 0xf2, 0x02, 0x0a, 0x28, 0xa2, 0x80, 0x0a,
- 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0xf6, 0xaf, 0x8b, 0x47,
- 0x3f, 0x09, 0x7c, 0x17, 0xff, 0x00, 0x5c, 0xe0, 0xff, 0x00, 0xd1, 0x15,
- 0xe2, 0xb5, 0xed, 0x1f, 0x16, 0x4f, 0xfc, 0x5a, 0x6f, 0x06, 0x7f, 0xd7,
- 0x38, 0x3f, 0xf4, 0x45, 0x7d, 0x7e, 0x4d, 0xff, 0x00, 0x22, 0xfc, 0xc3,
- 0xfc, 0x11, 0xff, 0x00, 0xd2, 0x90, 0xd6, 0xcc, 0xf1, 0x7a, 0xd8, 0xf0,
- 0x67, 0xfc, 0x8e, 0x1a, 0x17, 0xfd, 0x7f, 0xc1, 0xff, 0x00, 0xa3, 0x16,
- 0xb1, 0xeb, 0x63, 0xc1, 0xdf, 0xf2, 0x37, 0x68, 0x7f, 0xf5, 0xfd, 0x07,
- 0xfe, 0x8c, 0x5a, 0xf9, 0xbc, 0x27, 0xfb, 0xcd, 0x3f, 0xf1, 0x2f, 0xcc,
- 0x48, 0xfb, 0x2b, 0x75, 0x1b, 0xa9, 0x9b, 0xa8, 0xdd, 0x5f, 0xd8, 0x16,
- 0x37, 0xb8, 0xfd, 0xd4, 0x6e, 0xa6, 0x6e, 0xa3, 0x75, 0x20, 0xb8, 0xed,
- 0xd4, 0xbb, 0xa9, 0x9b, 0xa8, 0xdd, 0x4c, 0x2e, 0x3f, 0x75, 0x26, 0xea,
- 0x6e, 0xea, 0x37, 0x52, 0x0b, 0x8f, 0xdd, 0x49, 0xba, 0x9b, 0xba, 0x8d,
- 0xd4, 0xec, 0x3b, 0x8f, 0xdd, 0x49, 0xba, 0x9b, 0xba, 0x8d, 0xd4, 0x0a,
- 0xe4, 0x74, 0x53, 0x33, 0x4b, 0x93, 0x57, 0x63, 0x3b, 0x8e, 0xa2, 0x9b,
- 0x9a, 0x4c, 0xd1, 0x60, 0xb8, 0xfa, 0x29, 0x99, 0xa3, 0x34, 0x58, 0x2e,
- 0x3f, 0x34, 0x53, 0x33, 0x4b, 0x93, 0x45, 0x82, 0xe3, 0xa8, 0xcd, 0x33,
- 0x34, 0x66, 0x8b, 0x05, 0xc7, 0xd1, 0x4d, 0xc9, 0xa3, 0x26, 0x8b, 0x05,
- 0xcf, 0x96, 0x3e, 0x30, 0x7f, 0xc9, 0x48, 0xd6, 0xbf, 0xdf, 0x8f, 0xff,
- 0x00, 0x45, 0xa5, 0x71, 0xb5, 0xdd, 0xfc, 0x6c, 0xd3, 0xa6, 0xb1, 0xf8,
- 0x85, 0x7f, 0x2c, 0x8a, 0x44, 0x77, 0x4b, 0x1c, 0xd1, 0xb7, 0x66, 0x1b,
- 0x02, 0x9f, 0xd5, 0x4d, 0x70, 0x95, 0xfc, 0x97, 0x9d, 0x42, 0x50, 0xcc,
- 0xf1, 0x31, 0x92, 0xb7, 0xbf, 0x2f, 0xfd, 0x29, 0x90, 0x7b, 0x3f, 0xec,
- 0xdb, 0xff, 0x00, 0x1f, 0xba, 0xef, 0xfd, 0x73, 0x87, 0xf9, 0xbd, 0x78,
- 0xc5, 0x7b, 0x87, 0xec, 0xe3, 0xa7, 0x4d, 0x1c, 0x3a, 0xd5, 0xf3, 0x29,
- 0x58, 0x24, 0x31, 0xc2, 0x8d, 0xfd, 0xe2, 0x37, 0x16, 0xfc, 0xb2, 0x3f,
- 0x3a, 0xf0, 0xfa, 0xf6, 0x73, 0x58, 0x4a, 0x19, 0x26, 0x5b, 0xcc, 0xad,
- 0x7f, 0x6a, 0xff, 0x00, 0xf2, 0x64, 0x01, 0x45, 0x14, 0x57, 0xc6, 0x00,
- 0x51, 0x45, 0x14, 0x00, 0x51, 0x45, 0x14, 0x00, 0x51, 0x45, 0x14, 0x00,
- 0x57, 0xb3, 0xfc, 0x57, 0xff, 0x00, 0x92, 0x51, 0xe0, 0xdf, 0xfa, 0xe7,
- 0x07, 0xfe, 0x88, 0xaf, 0x18, 0xaf, 0x70, 0xf8, 0x9b, 0xa7, 0x4d, 0x79,
- 0xf0, 0x77, 0xc3, 0x37, 0x11, 0x29, 0x74, 0xb5, 0x8a, 0xd9, 0xe4, 0xc7,
- 0x65, 0x30, 0xed, 0xcf, 0xe6, 0x40, 0xfc, 0x6b, 0xec, 0xf2, 0x38, 0x4a,
- 0x78, 0x0c, 0xc1, 0x45, 0x5f, 0xdc, 0x5f, 0x84, 0xae, 0xc0, 0xf0, 0xfa,
- 0xd8, 0xf0, 0x6f, 0xfc, 0x8d, 0xfa, 0x1f, 0xfd, 0x7f, 0x41, 0xff, 0x00,
- 0xa3, 0x16, 0xb1, 0xeb, 0xa2, 0xf8, 0x79, 0xa7, 0x4d, 0xaa, 0x78, 0xdf,
- 0x45, 0x86, 0x15, 0x2c, 0xcb, 0x75, 0x1c, 0xad, 0x8e, 0xca, 0x8c, 0x18,
- 0x9f, 0xc8, 0x57, 0xcd, 0x60, 0x61, 0x29, 0xe2, 0xe9, 0x46, 0x2a, 0xed,
- 0xca, 0x3f, 0x9a, 0x03, 0xeb, 0x9c, 0xd1, 0x4c, 0xcd, 0x2e, 0x4d, 0x7f,
- 0x60, 0x58, 0xbb, 0x8e, 0xa2, 0x99, 0x9a, 0x33, 0x45, 0x82, 0xe3, 0xe8,
- 0xa6, 0x66, 0x8c, 0xd1, 0x60, 0xb8, 0xfa, 0x29, 0x99, 0xa5, 0xc9, 0xa2,
- 0xc1, 0x71, 0xd9, 0xa2, 0x9b, 0x93, 0x49, 0x9a, 0x2c, 0x17, 0x1f, 0x45,
- 0x33, 0x34, 0x66, 0x8b, 0x05, 0xc6, 0x6e, 0xa3, 0x75, 0x30, 0x90, 0x3a,
- 0x9c, 0x51, 0x9a, 0xd2, 0xc6, 0x57, 0x1f, 0xba, 0x8d, 0xd4, 0xda, 0x4c,
- 0xd1, 0x60, 0xb8, 0xfd, 0xd4, 0x6e, 0xa6, 0x02, 0x0f, 0x43, 0x9a, 0x37,
- 0x01, 0xdf, 0x14, 0x58, 0x2e, 0x3f, 0x75, 0x1b, 0xa9, 0xb4, 0x94, 0x58,
- 0x2e, 0x3f, 0x75, 0x1b, 0xa9, 0xb4, 0x80, 0x83, 0xd0, 0xe6, 0x8b, 0x05,
- 0xc7, 0xee, 0xa3, 0x75, 0x30, 0x90, 0x3a, 0x9c, 0x51, 0x9a, 0x2c, 0x17,
- 0x31, 0x3c, 0x5d, 0xe0, 0xcd, 0x2f, 0xc6, 0xb6, 0x2b, 0x6f, 0xa8, 0xc4,
- 0x4b, 0x26, 0x4c, 0x53, 0xc6, 0x71, 0x24, 0x64, 0xf5, 0xc1, 0xfe, 0x87,
- 0x8a, 0xe0, 0x6d, 0x3f, 0x67, 0x7d, 0x32, 0x2b, 0xb0, 0xf7, 0x1a, 0xad,
- 0xcc, 0xf6, 0xe0, 0xe7, 0xca, 0x58, 0xd5, 0x09, 0x1e, 0x85, 0xb2, 0x7f,
- 0x95, 0x7a, 0xd5, 0x25, 0x78, 0x38, 0xcc, 0x87, 0x2c, 0xcc, 0x2b, 0x2a,
- 0xf8, 0x9a, 0x2a, 0x52, 0xef, 0xaa, 0xfb, 0xec, 0xd5, 0xfe, 0x77, 0x0b,
- 0x95, 0xf4, 0xad, 0x32, 0xd3, 0x44, 0xb0, 0x86, 0xca, 0xc6, 0x05, 0xb7,
- 0xb6, 0x88, 0x61, 0x23, 0x4e, 0x83, 0xfc, 0x4f, 0xbd, 0x7c, 0x6b, 0x5f,
- 0x69, 0x57, 0xc5, 0xb5, 0xf9, 0x8f, 0x88, 0xb0, 0x8d, 0x38, 0xe0, 0xe1,
- 0x05, 0x64, 0xb9, 0xec, 0x97, 0xfd, 0xb8, 0x34, 0x14, 0x51, 0x45, 0x7e,
- 0x32, 0x30, 0xa2, 0x8a, 0x28, 0x00, 0xa2, 0x8a, 0x28, 0x00, 0xa2, 0x8a,
- 0x28, 0x00, 0xaf, 0xad, 0xfc, 0x2b, 0x04, 0x57, 0x9e, 0x06, 0xd1, 0xad,
- 0xe7, 0x8d, 0x66, 0x86, 0x4d, 0x3a, 0x04, 0x78, 0xdc, 0x65, 0x58, 0x18,
- 0xd7, 0x20, 0x8a, 0xf9, 0x22, 0xbe, 0xba, 0xf0, 0x67, 0xfc, 0x89, 0xfa,
- 0x17, 0xfd, 0x78, 0x41, 0xff, 0x00, 0xa2, 0xd6, 0xbf, 0x5c, 0xf0, 0xee,
- 0x2a, 0x58, 0x9c, 0x42, 0x7b, 0x72, 0xaf, 0xcc, 0x47, 0x05, 0xab, 0x7e,
- 0xcf, 0x7a, 0x4d, 0xdd, 0xdb, 0x4b, 0x65, 0xa8, 0x4f, 0x63, 0x13, 0x1c,
- 0xf9, 0x25, 0x04, 0x80, 0x7b, 0x02, 0x48, 0x3f, 0x9e, 0x6b, 0xaf, 0xf0,
- 0x57, 0xc3, 0xcd, 0x27, 0xc0, 0xd1, 0xb9, 0xb3, 0x47, 0x9a, 0xee, 0x41,
- 0xb6, 0x4b, 0xa9, 0xb0, 0x5c, 0x8f, 0x41, 0xe8, 0x3d, 0x87, 0xe3, 0x5d,
- 0x36, 0x69, 0x6b, 0xf5, 0x7c, 0x37, 0x0f, 0xe5, 0x78, 0x3a, 0xff, 0x00,
- 0x59, 0xa1, 0x41, 0x46, 0x7d, 0xf5, 0xd3, 0xd1, 0x6c, 0xbe, 0x49, 0x0a,
- 0xe3, 0xb7, 0x51, 0xba, 0x99, 0x9a, 0x03, 0x03, 0xde, 0xbd, 0xfb, 0x05,
- 0xc7, 0xee, 0xa3, 0x75, 0x30, 0x90, 0x06, 0x4f, 0x14, 0x51, 0x60, 0xb8,
- 0xfd, 0xd4, 0x6e, 0xa6, 0xd1, 0x45, 0x82, 0xe3, 0xb7, 0x51, 0xba, 0x98,
- 0x08, 0x3d, 0x0e, 0x68, 0x24, 0x0e, 0xf4, 0x58, 0x2e, 0x3f, 0x75, 0x1b,
- 0xa9, 0x94, 0xb4, 0x58, 0x2e, 0x3b, 0x75, 0x1b, 0xa9, 0x99, 0xa0, 0x10,
- 0x7a, 0x1a, 0x2c, 0x17, 0x31, 0x62, 0xbd, 0x91, 0x46, 0xf7, 0x90, 0x3e,
- 0xd3, 0xf7, 0x1b, 0xa9, 0xad, 0x58, 0xa5, 0x13, 0x46, 0xae, 0xbd, 0x08,
- 0xac, 0x3f, 0x38, 0xff, 0x00, 0x71, 0x3f, 0xef, 0x91, 0x56, 0x52, 0xf1,
- 0xe3, 0x48, 0x55, 0x42, 0x80, 0x7a, 0x80, 0x3d, 0xeb, 0xb2, 0x70, 0xbe,
- 0xc7, 0x9d, 0x4e, 0xaf, 0x2e, 0xec, 0xd6, 0xcd, 0x36, 0x59, 0x44, 0x31,
- 0xb3, 0xb7, 0x41, 0x49, 0xba, 0xb3, 0x1e, 0xf2, 0x49, 0x12, 0x65, 0x60,
- 0x08, 0x1d, 0x01, 0x1e, 0xf5, 0x84, 0x61, 0xcc, 0x75, 0x4e, 0xa7, 0x22,
- 0x1b, 0x2d, 0xec, 0x8c, 0x0b, 0xa4, 0x81, 0x37, 0x1f, 0xb8, 0xbd, 0x7e,
- 0xb4, 0xb1, 0x5e, 0xc8, 0xa0, 0x3b, 0xb8, 0x7d, 0xa7, 0xee, 0x37, 0x5f,
- 0xad, 0x57, 0xf3, 0x8f, 0xf7, 0x13, 0xfe, 0xf9, 0x14, 0x79, 0xc7, 0xfb,
- 0x89, 0xff, 0x00, 0x7c, 0x8a, 0xeb, 0xe5, 0x56, 0xb5, 0x8e, 0x0e, 0x77,
- 0x7b, 0xdc, 0xdd, 0x8e, 0x41, 0x2a, 0x2b, 0xaf, 0x42, 0x33, 0x4e, 0xac,
- 0xa8, 0xef, 0x1d, 0x3c, 0x85, 0x00, 0x05, 0x3d, 0x40, 0x1e, 0xe6, 0xb4,
- 0x77, 0x57, 0x24, 0xa3, 0xca, 0x77, 0xc2, 0x7c, 0xe8, 0x74, 0x92, 0x08,
- 0xd1, 0x99, 0x8f, 0x00, 0x66, 0xb2, 0xa5, 0xbd, 0x91, 0x81, 0x74, 0x70,
- 0x99, 0x38, 0xd8, 0x3a, 0xfd, 0x69, 0xd2, 0x5e, 0x3b, 0xf9, 0xea, 0x40,
- 0x2a, 0x3a, 0x02, 0x3d, 0xc5, 0x55, 0xf3, 0x8f, 0xf7, 0x13, 0xfe, 0xf9,
- 0x15, 0xbc, 0x21, 0x6d, 0xce, 0x6a, 0x95, 0x6f, 0xa2, 0x64, 0xf1, 0x5e,
- 0x48, 0xa3, 0x7b, 0x48, 0x1f, 0x69, 0xfb, 0x8d, 0xd4, 0xd6, 0xac, 0x52,
- 0x89, 0xa3, 0x57, 0x5e, 0x86, 0xb0, 0xfc, 0xe3, 0xfd, 0xc4, 0xff, 0x00,
- 0xbe, 0x45, 0x59, 0x4b, 0xc7, 0x8d, 0x61, 0x0a, 0x14, 0x03, 0xd4, 0x01,
- 0xef, 0x44, 0xe1, 0x7d, 0x85, 0x4e, 0xaf, 0x2e, 0xec, 0xd6, 0xcd, 0x15,
- 0x1e, 0xea, 0x5d, 0xd5, 0xcd, 0x63, 0xba, 0xe3, 0xeb, 0xc0, 0xbc, 0x71,
- 0xf0, 0x57, 0x55, 0x83, 0x57, 0x9e, 0xe7, 0x44, 0x85, 0x6f, 0x6c, 0xa6,
- 0x72, 0xe2, 0x25, 0x70, 0xaf, 0x16, 0x4e, 0x76, 0xe0, 0x91, 0x91, 0xe9,
- 0x8a, 0xf7, 0xad, 0xd4, 0x66, 0xbe, 0x7f, 0x39, 0xc8, 0xf0, 0x99, 0xe5,
- 0x18, 0xd2, 0xc4, 0xdd, 0x72, 0xbb, 0xa6, 0xb7, 0x5d, 0xfb, 0xef, 0xe8,
- 0x17, 0xb1, 0xf2, 0xc5, 0xff, 0x00, 0xc3, 0x5f, 0x12, 0xe9, 0x96, 0x53,
- 0x5d, 0xdd, 0x69, 0x52, 0x43, 0x6f, 0x0a, 0x97, 0x92, 0x42, 0xe8, 0x42,
- 0x81, 0xd4, 0xf0, 0x6b, 0x99, 0xaf, 0xaa, 0xfe, 0x21, 0x9c, 0xf8, 0x1f,
- 0x5c, 0xff, 0x00, 0xaf, 0x47, 0xfe, 0x55, 0xf2, 0xa5, 0x7e, 0x01, 0xc5,
- 0x59, 0x1e, 0x1f, 0x22, 0xc4, 0x53, 0xa3, 0x87, 0x93, 0x92, 0x94, 0x6f,
- 0xef, 0x5b, 0xbd, 0xba, 0x24, 0x5a, 0x77, 0x0a, 0xe9, 0xec, 0xbe, 0x19,
- 0xf8, 0x9b, 0x51, 0xb3, 0x86, 0xea, 0xdb, 0x49, 0x92, 0x5b, 0x79, 0x90,
- 0x49, 0x1b, 0x87, 0x40, 0x19, 0x48, 0xc8, 0x3d, 0x6b, 0x98, 0xaf, 0xac,
- 0x3c, 0x08, 0x71, 0xe0, 0xad, 0x0b, 0xfe, 0xbc, 0xa1, 0xff, 0x00, 0xd0,
- 0x05, 0x57, 0x0a, 0xe4, 0x58, 0x7c, 0xf6, 0xbd, 0x5a, 0x58, 0x89, 0x4a,
- 0x2a, 0x2a, 0xfe, 0xed, 0xbb, 0xdb, 0xaa, 0x60, 0xdd, 0x8f, 0x9e, 0xdb,
- 0xe1, 0x4f, 0x8a, 0xd1, 0x4b, 0x1d, 0x1a, 0x50, 0x00, 0xc9, 0x3e, 0x62,
- 0x7f, 0xf1, 0x55, 0xc9, 0xd7, 0xd9, 0x17, 0x4d, 0xfe, 0x8d, 0x37, 0xfb,
- 0x87, 0xf9, 0x57, 0xc6, 0xf5, 0xd1, 0xc5, 0x9c, 0x3d, 0x86, 0xc8, 0x5d,
- 0x05, 0x87, 0x9c, 0xa5, 0xcf, 0xcd, 0x7e, 0x6b, 0x74, 0xb6, 0xd6, 0x4b,
- 0xb8, 0x27, 0x70, 0xae, 0x87, 0x47, 0xf0, 0x07, 0x88, 0x35, 0xfb, 0x04,
- 0xbd, 0xb0, 0xd3, 0x64, 0xb9, 0xb5, 0x72, 0x42, 0xc8, 0xae, 0xa0, 0x12,
- 0x0e, 0x0f, 0x53, 0xeb, 0x5c, 0xf5, 0x7d, 0x27, 0xf0, 0x54, 0xe3, 0xe1,
- 0xed, 0x8f, 0xfd, 0x74, 0x97, 0xff, 0x00, 0x43, 0x35, 0xe7, 0x70, 0xbe,
- 0x4f, 0x43, 0x3c, 0xc6, 0xcb, 0x0d, 0x5e, 0x4d, 0x25, 0x16, 0xf4, 0xb5,
- 0xee, 0x9a, 0x5d, 0x53, 0xee, 0x0d, 0xd8, 0xf3, 0x1f, 0x0d, 0x7c, 0x12,
- 0xd7, 0xb5, 0x3d, 0x42, 0x31, 0xa9, 0x40, 0x34, 0xdb, 0x20, 0xc0, 0xc8,
- 0xee, 0xea, 0xce, 0x47, 0x70, 0xa0, 0x13, 0xcf, 0xb9, 0xe2, 0xbe, 0x87,
- 0xb7, 0x82, 0x3b, 0x4b, 0x78, 0xa0, 0x89, 0x42, 0x45, 0x12, 0x84, 0x45,
- 0x1d, 0x80, 0x18, 0x02, 0x97, 0x34, 0x9b, 0xab, 0xfa, 0x07, 0x25, 0xe1,
- 0xfc, 0x1e, 0x45, 0x09, 0x47, 0x0d, 0x76, 0xe5, 0xbb, 0x7a, 0xbd, 0x36,
- 0x5a, 0x24, 0xad, 0xf2, 0x22, 0xf7, 0x24, 0xcd, 0x19, 0xa8, 0xf7, 0x51,
- 0xba, 0xbe, 0x96, 0xc1, 0x71, 0xd2, 0x48, 0x22, 0x46, 0x76, 0xe0, 0x0e,
- 0x6b, 0x2a, 0x5b, 0xd9, 0x18, 0x17, 0x47, 0x11, 0xe4, 0xe3, 0x60, 0xeb,
- 0xf5, 0xa7, 0x49, 0x78, 0xef, 0xe7, 0xa9, 0x00, 0xa8, 0xe8, 0x08, 0xf7,
- 0x02, 0xaa, 0xf9, 0xc7, 0xfb, 0x89, 0xff, 0x00, 0x7c, 0x8a, 0xe9, 0x84,
- 0x2d, 0xb9, 0xc5, 0x56, 0xaf, 0x36, 0x89, 0x93, 0xc5, 0x7b, 0x22, 0x8d,
- 0xef, 0x20, 0x7d, 0xa7, 0xee, 0x37, 0x53, 0x5a, 0xd1, 0x4a, 0x26, 0x8d,
- 0x5d, 0x7a, 0x1a, 0xc2, 0xf3, 0x8f, 0xf7, 0x13, 0xfe, 0xf9, 0x15, 0x65,
- 0x2f, 0x1e, 0x34, 0x84, 0x28, 0x50, 0x09, 0xe4, 0x01, 0xef, 0x44, 0xe1,
- 0x7d, 0x85, 0x4e, 0xaf, 0x2e, 0xec, 0xd6, 0xa6, 0xcb, 0x28, 0x86, 0x36,
- 0x76, 0xe8, 0x29, 0x37, 0x56, 0x63, 0xde, 0x3c, 0x89, 0x30, 0x60, 0xa4,
- 0x0e, 0x80, 0x8f, 0x7a, 0xc2, 0x30, 0xe6, 0x3a, 0xa7, 0x53, 0x91, 0x0d,
- 0x96, 0xf6, 0x46, 0x05, 0xd2, 0x40, 0x9b, 0x8f, 0xdc, 0x5e, 0xa3, 0xde,
- 0x96, 0x2b, 0xd9, 0x14, 0x07, 0x77, 0x0f, 0xb4, 0xfd, 0xc6, 0xeb, 0xf5,
- 0xaa, 0xfe, 0x71, 0xfe, 0xe2, 0x7f, 0xdf, 0x22, 0x8f, 0x38, 0xff, 0x00,
- 0x71, 0x3f, 0xef, 0x91, 0x5d, 0x7c, 0xaa, 0xd6, 0xb1, 0xc1, 0xce, 0xef,
- 0x7b, 0x9b, 0xb1, 0xc8, 0x25, 0x45, 0x75, 0xe8, 0x46, 0x69, 0xd5, 0x95,
- 0x1d, 0xe3, 0xa0, 0x81, 0x46, 0x02, 0x9e, 0xa0, 0x0f, 0x72, 0x2b, 0x4b,
- 0x35, 0xc9, 0x28, 0xf2, 0x9d, 0xf0, 0xa9, 0xce, 0x85, 0x92, 0x41, 0x1a,
- 0x33, 0xb7, 0x40, 0x32, 0x6b, 0x2a, 0x5b, 0xd9, 0x1c, 0x17, 0x47, 0x09,
- 0x93, 0x8d, 0x83, 0xaf, 0xd6, 0x9d, 0x25, 0xe3, 0xbf, 0x9e, 0xa4, 0x02,
- 0xa3, 0xa0, 0x23, 0xdc, 0x55, 0x5f, 0x38, 0xff, 0x00, 0x71, 0x3f, 0xef,
- 0x91, 0x5b, 0xc2, 0x16, 0xdc, 0xe6, 0xa9, 0x57, 0x9b, 0x44, 0xc8, 0xea,
- 0x70, 0xa4, 0x88, 0x30, 0x09, 0xff, 0x00, 0xf5, 0xd3, 0x4d, 0xbb, 0x09,
- 0x84, 0x59, 0x1b, 0xbd, 0x7b, 0x56, 0x95, 0xb4, 0x66, 0x18, 0x42, 0x13,
- 0x92, 0x3d, 0x2a, 0xe5, 0x2b, 0x23, 0x2a, 0x70, 0x72, 0x6d, 0x32, 0x7a,
- 0xc8, 0x2a, 0x40, 0x9f, 0x20, 0x8f, 0xff, 0x00, 0x5d, 0x6a, 0xe6, 0xa3,
- 0xb9, 0x8c, 0xcf, 0x09, 0x40, 0x40, 0x27, 0xd6, 0xb1, 0x83, 0xe5, 0x3a,
- 0x6a, 0x47, 0x99, 0x5c, 0xc7, 0xa2, 0xa5, 0x5b, 0x76, 0x69, 0x8c, 0x59,
- 0x1b, 0xbf, 0x4a, 0x3e, 0xce, 0xde, 0x7f, 0x95, 0x91, 0xbb, 0xd7, 0xb5,
- 0x74, 0xdd, 0x1c, 0x3c, 0xac, 0x7a, 0xa9, 0x2d, 0x6f, 0x80, 0x7f, 0xcb,
- 0x1a, 0xd6, 0xa8, 0x6d, 0xe3, 0x30, 0xc2, 0xa8, 0x48, 0x24, 0x77, 0x15,
- 0x26, 0x6b, 0x9a, 0x6f, 0x99, 0x9d, 0xf4, 0xe3, 0xca, 0x8c, 0xb6, 0x52,
- 0x1a, 0xe3, 0x20, 0xff, 0x00, 0x96, 0x15, 0x5e, 0xb6, 0x2e, 0x23, 0x33,
- 0x44, 0xc8, 0x08, 0x04, 0xd6, 0x67, 0xd9, 0xdb, 0xcf, 0xf2, 0xb2, 0x37,
- 0x7a, 0xf6, 0xad, 0xa1, 0x24, 0xd1, 0xcb, 0x52, 0x0e, 0x2d, 0x58, 0x8a,
- 0xa7, 0x0a, 0x48, 0x83, 0x00, 0x9f, 0xff, 0x00, 0x5d, 0x34, 0xdb, 0xb2,
- 0xcc, 0x22, 0xc8, 0xdd, 0xeb, 0xda, 0xb4, 0xad, 0xa3, 0x30, 0xc2, 0xaa,
- 0x4e, 0x48, 0xf4, 0xa2, 0x52, 0xb2, 0x0a, 0x70, 0x72, 0x6d, 0x32, 0x7a,
- 0x29, 0xa4, 0xd1, 0x9a, 0xe5, 0xb1, 0xde, 0x3a, 0x8a, 0x6e, 0x73, 0x41,
- 0x34, 0x58, 0x0e, 0x7f, 0xe2, 0x1f, 0xfc, 0x88, 0xfa, 0xe7, 0xfd, 0x7a,
- 0xbf, 0xf2, 0xaf, 0x95, 0xab, 0xeb, 0x2f, 0x18, 0x58, 0x4b, 0xaa, 0xf8,
- 0x57, 0x56, 0xb4, 0x80, 0x6e, 0x9a, 0x6b, 0x69, 0x15, 0x17, 0xd5, 0xb6,
- 0x9c, 0x0f, 0xce, 0xbe, 0x4e, 0x65, 0x2a, 0x48, 0x20, 0x82, 0x38, 0x20,
- 0xf6, 0xaf, 0xc1, 0x7c, 0x46, 0x84, 0x96, 0x32, 0x84, 0xed, 0xa3, 0x8b,
- 0x5f, 0x73, 0xff, 0x00, 0x82, 0x8d, 0x20, 0x25, 0x7d, 0x5d, 0xe0, 0x5f,
- 0xf9, 0x12, 0xf4, 0x2f, 0xfa, 0xf2, 0x87, 0xff, 0x00, 0x40, 0x15, 0xf2,
- 0x9a, 0x23, 0x48, 0xea, 0x88, 0xa5, 0x9d, 0x8e, 0x02, 0x81, 0x92, 0x4d,
- 0x7d, 0x69, 0xe1, 0x8b, 0x19, 0x34, 0xbf, 0x0d, 0xe9, 0x76, 0x73, 0x71,
- 0x2c, 0x16, 0xd1, 0xc6, 0xe3, 0xd0, 0x85, 0x00, 0xd5, 0x78, 0x73, 0x09,
- 0x3c, 0x56, 0x22, 0x76, 0xd1, 0x45, 0x2f, 0xc7, 0xfe, 0x00, 0x4c, 0xd0,
- 0xba, 0xff, 0x00, 0x8f, 0x69, 0xbf, 0xdc, 0x3f, 0xca, 0xbe, 0x39, 0xaf,
- 0xb1, 0xe5, 0x5f, 0x32, 0x27, 0x4c, 0xe3, 0x72, 0x91, 0x9a, 0xf9, 0x03,
- 0x50, 0xb1, 0x9b, 0x4c, 0xbe, 0xb8, 0xb4, 0x9d, 0x0a, 0x4d, 0x04, 0x86,
- 0x37, 0x53, 0xd8, 0x83, 0x8a, 0xed, 0xf1, 0x22, 0x12, 0xff, 0x00, 0x65,
- 0x9d, 0xb4, 0xf7, 0xd7, 0xfe, 0x92, 0x10, 0x2b, 0xd7, 0xd2, 0x5f, 0x05,
- 0xbf, 0xe4, 0x9f, 0x58, 0xff, 0x00, 0xd7, 0x49, 0x7f, 0xf4, 0x33, 0x5f,
- 0x36, 0xd7, 0xd3, 0x9f, 0x0a, 0x74, 0xe9, 0xb4, 0xbf, 0x01, 0xe9, 0x91,
- 0x4e, 0xa5, 0x24, 0x75, 0x69, 0x76, 0x9e, 0xa0, 0x33, 0x12, 0x3f, 0x42,
- 0x2b, 0xc3, 0xf0, 0xf6, 0x12, 0x96, 0x69, 0x52, 0x49, 0x68, 0xa0, 0xff,
- 0x00, 0x19, 0x44, 0x72, 0xd8, 0xeb, 0xe8, 0xa6, 0xe6, 0x8c, 0xd7, 0xf4,
- 0x3d, 0x8c, 0x87, 0x51, 0x4d, 0xcd, 0x19, 0xa2, 0xc0, 0x65, 0xb2, 0x90,
- 0xd7, 0x19, 0x04, 0x7f, 0xfb, 0x42, 0xab, 0xd6, 0xc5, 0xc4, 0x66, 0x68,
- 0x59, 0x07, 0x04, 0xfa, 0xd6, 0x67, 0xd9, 0xdb, 0xcf, 0xf2, 0xb2, 0x37,
- 0x7a, 0xf6, 0xae, 0xa8, 0x4a, 0xe8, 0xe0, 0xa9, 0x07, 0x16, 0xac, 0x45,
- 0x53, 0x85, 0x24, 0x41, 0x80, 0x4f, 0xff, 0x00, 0xae, 0x9a, 0x6d, 0xd9,
- 0x66, 0x11, 0x64, 0x6e, 0xf5, 0xed, 0x5a, 0x76, 0xd1, 0x98, 0x21, 0x0a,
- 0x48, 0x27, 0xda, 0x89, 0x4a, 0xc8, 0x29, 0xc1, 0xc9, 0xb4, 0xc9, 0xab,
- 0x20, 0xa9, 0x02, 0x7c, 0x82, 0x3f, 0xfd, 0x75, 0xab, 0x9a, 0x8a, 0xe6,
- 0x33, 0x34, 0x45, 0x41, 0xc1, 0xf7, 0xac, 0x60, 0xf9, 0x4e, 0x9a, 0x91,
- 0xe6, 0x46, 0x45, 0x15, 0x28, 0xb7, 0x66, 0x98, 0xc5, 0x91, 0xb8, 0x77,
- 0xed, 0x47, 0xd9, 0xdb, 0xcf, 0xf2, 0xb2, 0x37, 0x7a, 0xf6, 0xae, 0x9b,
- 0xa3, 0x87, 0x95, 0x8f, 0x55, 0x25, 0xad, 0xf0, 0x0f, 0xf9, 0x63, 0x5a,
- 0xd5, 0x0d, 0xba, 0x18, 0x61, 0x54, 0x24, 0x12, 0x3d, 0x2a, 0x4c, 0xd7,
- 0x34, 0xdf, 0x33, 0x3b, 0xe9, 0xc7, 0x95, 0x19, 0x6c, 0xa4, 0x35, 0xc6,
- 0x41, 0xff, 0x00, 0x2c, 0x2a, 0xbd, 0x6c, 0x5c, 0x46, 0x66, 0x85, 0x90,
- 0x1c, 0x13, 0xeb, 0x59, 0x9f, 0x67, 0x6f, 0x3f, 0xca, 0xc8, 0xdd, 0xfa,
- 0x56, 0xd0, 0x92, 0x68, 0xe5, 0xa9, 0x06, 0x9a, 0xb1, 0xa0, 0xd6, 0xc1,
- 0xae, 0x04, 0xb9, 0x39, 0x1d, 0xaa, 0x6a, 0x28, 0xae, 0x76, 0xdb, 0x3a,
- 0xd2, 0xb6, 0xc1, 0x45, 0x14, 0x52, 0x19, 0x0a, 0xdb, 0x05, 0xb8, 0x32,
- 0xe4, 0xe4, 0xf6, 0xa3, 0xec, 0xc3, 0xed, 0x1e, 0x6e, 0x4e, 0x7d, 0x2a,
- 0x6a, 0x2a, 0xb9, 0x99, 0x3c, 0xa8, 0x28, 0xa2, 0x8a, 0x92, 0x82, 0xa1,
- 0xfb, 0x30, 0xfb, 0x47, 0x9b, 0x93, 0x9f, 0x4a, 0x9a, 0x8a, 0x69, 0xd8,
- 0x4d, 0x5f, 0x72, 0x16, 0xb6, 0x0d, 0x70, 0x25, 0xc9, 0xc8, 0xed, 0x53,
- 0x51, 0x45, 0x0d, 0xb6, 0x09, 0x5b, 0x60, 0xa2, 0x8a, 0x29, 0x0c, 0x28,
- 0xa2, 0x8a, 0x00, 0x2b, 0x83, 0xf1, 0x57, 0xc1, 0xdd, 0x1b, 0xc4, 0xb7,
- 0xaf, 0x79, 0x1b, 0xcb, 0xa7, 0x5d, 0x48, 0x73, 0x21, 0x80, 0x02, 0x8e,
- 0x7d, 0x4a, 0x9e, 0xff, 0x00, 0x42, 0x2b, 0xbc, 0xa2, 0xbc, 0xfc, 0x76,
- 0x5f, 0x85, 0xcc, 0xa9, 0xfb, 0x1c, 0x5d, 0x35, 0x38, 0xf9, 0xfe, 0x8f,
- 0x75, 0xf2, 0x1a, 0x6d, 0x1c, 0x3f, 0x84, 0xbe, 0x11, 0xe8, 0xde, 0x16,
- 0xbb, 0x4b, 0xc2, 0xd2, 0x5f, 0xde, 0x27, 0x29, 0x24, 0xf8, 0xda, 0x87,
- 0xd5, 0x54, 0x77, 0xf7, 0x39, 0xae, 0xe2, 0x8a, 0x29, 0xe0, 0xb0, 0x18,
- 0x5c, 0xba, 0x97, 0xb1, 0xc2, 0x53, 0x50, 0x8f, 0x97, 0xeb, 0xd5, 0xfc,
- 0xc2, 0xed, 0x85, 0x71, 0xfe, 0x31, 0xf8, 0x5f, 0xa4, 0x78, 0xc6, 0x6f,
- 0xb4, 0xcd, 0xe6, 0x5a, 0x5e, 0xe3, 0x06, 0xe2, 0x0c, 0x65, 0xc7, 0x6d,
- 0xc0, 0xf5, 0xfe, 0x7e, 0xf5, 0xd8, 0x51, 0x55, 0x8c, 0xc1, 0x61, 0xf1,
- 0xf4, 0x9d, 0x0c, 0x54, 0x14, 0xe2, 0xfa, 0x3f, 0xeb, 0x46, 0x17, 0x68,
- 0xf3, 0xbf, 0x0f, 0x7c, 0x11, 0xd1, 0x74, 0x6b, 0xc4, 0xb9, 0xb9, 0x96,
- 0x5d, 0x49, 0xd0, 0xe5, 0x63, 0x94, 0x05, 0x8f, 0x3e, 0xa5, 0x47, 0x5f,
- 0xc4, 0xe3, 0xda, 0xbd, 0x13, 0xa5, 0x14, 0x56, 0x38, 0x1c, 0xb7, 0x07,
- 0x96, 0x41, 0xd3, 0xc1, 0xd3, 0x50, 0x4f, 0x7b, 0x75, 0xf5, 0x7b, 0xb0,
- 0x6d, 0xb0, 0xa2, 0x8a, 0x2b, 0xd3, 0x10, 0x51, 0x45, 0x14, 0x00, 0x54,
- 0x3f, 0x66, 0x1f, 0x68, 0xf3, 0x72, 0x73, 0xe9, 0x53, 0x51, 0x4d, 0x3b,
- 0x09, 0xab, 0xee, 0x42, 0xd6, 0xc1, 0xae, 0x04, 0xb9, 0x39, 0x1d, 0xaa,
- 0x6a, 0x28, 0xa1, 0xb6, 0xc1, 0x2b, 0x6c, 0x14, 0x51, 0x45, 0x21, 0x90,
- 0xad, 0xb0, 0x5b, 0x83, 0x2e, 0x4e, 0x4f, 0x6a, 0x3e, 0xcc, 0x3e, 0xd1,
- 0xe6, 0xe4, 0xe7, 0xd2, 0xa6, 0xa2, 0xab, 0x99, 0x93, 0xca, 0x82, 0x8a,
- 0x28, 0xa9, 0x28, 0x2a, 0x1f, 0xb3, 0x0f, 0xb4, 0x79, 0xb9, 0x39, 0xf4,
- 0xa9, 0xa8, 0xa6, 0x9d, 0x84, 0xd5, 0xf7, 0x3e, 0x20, 0xff, 0x00, 0x87,
- 0xa6, 0xf8, 0x5b, 0xfe, 0x84, 0x7d, 0x63, 0xff, 0x00, 0x02, 0xa2, 0xa3,
- 0xfe, 0x1e, 0x9b, 0xe1, 0x6f, 0xfa, 0x11, 0xf5, 0x8f, 0xfc, 0x0a, 0x8a,
- 0xbe, 0x17, 0xfe, 0xc6, 0xb2, 0xff, 0x00, 0x9f, 0x64, 0xa7, 0x47, 0xa2,
- 0x59, 0x31, 0xe6, 0xd9, 0x31, 0x45, 0x8e, 0x9e, 0x44, 0x7d, 0xcd, 0xff,
- 0x00, 0x0f, 0x4d, 0xf0, 0xb7, 0xfd, 0x08, 0xfa, 0xc7, 0xfe, 0x05, 0x45,
- 0x47, 0xfc, 0x3d, 0x37, 0xc2, 0xdf, 0xf4, 0x23, 0xeb, 0x1f, 0xf8, 0x15,
- 0x15, 0x7c, 0x3b, 0xfd, 0x87, 0x61, 0xff, 0x00, 0x3e, 0xb1, 0xfe, 0x54,
- 0xd9, 0x34, 0x6b, 0x05, 0x1c, 0x5b, 0x47, 0x9f, 0xa5, 0x16, 0x0e, 0x44,
- 0x7d, 0xc9, 0xff, 0x00, 0x0f, 0x4d, 0xf0, 0xb7, 0xfd, 0x08, 0xfa, 0xc7,
- 0xfe, 0x05, 0x45, 0x47, 0xfc, 0x3d, 0x37, 0xc2, 0xdf, 0xf4, 0x23, 0xeb,
- 0x1f, 0xf8, 0x15, 0x15, 0x7c, 0x2f, 0xfd, 0x8d, 0x65, 0xff, 0x00, 0x3e,
- 0xc9, 0xf9, 0x53, 0xe3, 0xd1, 0x2c, 0x4f, 0x26, 0xd9, 0x31, 0xf4, 0xa2,
- 0xc1, 0xc8, 0x8f, 0xb9, 0x7f, 0xe1, 0xe9, 0xbe, 0x16, 0xff, 0x00, 0xa1,
- 0x1f, 0x58, 0xff, 0x00, 0xc0, 0xa8, 0xa8, 0xff, 0x00, 0x87, 0xa6, 0xf8,
- 0x5b, 0xfe, 0x84, 0x7d, 0x63, 0xff, 0x00, 0x02, 0xa2, 0xaf, 0x87, 0x7f,
- 0xb0, 0xec, 0x3f, 0xe7, 0xd6, 0x3f, 0xca, 0x99, 0x26, 0x8d, 0x62, 0x38,
- 0x16, 0xc9, 0x9a, 0x2c, 0x1c, 0x88, 0xfb, 0x97, 0xfe, 0x1e, 0x9b, 0xe1,
- 0x6f, 0xfa, 0x11, 0xf5, 0x8f, 0xfc, 0x0a, 0x8a, 0x8f, 0xf8, 0x7a, 0x6f,
- 0x85, 0xbf, 0xe8, 0x47, 0xd6, 0x3f, 0xf0, 0x2a, 0x2a, 0xf8, 0x5f, 0xfb,
- 0x1a, 0xcb, 0xfe, 0x7d, 0x93, 0xf2, 0xa9, 0x23, 0xd1, 0x2c, 0x48, 0xc9,
- 0xb6, 0x4f, 0xca, 0x8b, 0x07, 0x22, 0x3e, 0xe4, 0xff, 0x00, 0x87, 0xa6,
- 0xf8, 0x5b, 0xfe, 0x84, 0x7d, 0x63, 0xff, 0x00, 0x02, 0xa2, 0xa3, 0xfe,
- 0x1e, 0x9b, 0xe1, 0x6f, 0xfa, 0x11, 0xf5, 0x8f, 0xfc, 0x0a, 0x8a, 0xbe,
- 0x1d, 0xfe, 0xc3, 0xb0, 0xff, 0x00, 0x9f, 0x58, 0xff, 0x00, 0x2a, 0x64,
- 0x9a, 0x35, 0x88, 0x38, 0x16, 0xc9, 0xf9, 0x51, 0x60, 0xe4, 0x47, 0xdc,
- 0xbf, 0xf0, 0xf4, 0xdf, 0x0b, 0x7f, 0xd0, 0x8f, 0xac, 0x7f, 0xe0, 0x54,
- 0x54, 0x7f, 0xc3, 0xd3, 0x7c, 0x2d, 0xff, 0x00, 0x42, 0x3e, 0xb1, 0xff,
- 0x00, 0x81, 0x51, 0x57, 0xc2, 0xff, 0x00, 0xd8, 0xd6, 0x5f, 0xf3, 0xec,
- 0x9f, 0x95, 0x48, 0x9a, 0x1d, 0x89, 0x19, 0x36, 0xc9, 0xf9, 0x51, 0x60,
- 0xe4, 0x47, 0xdc, 0x9f, 0xf0, 0xf4, 0xdf, 0x0b, 0x7f, 0xd0, 0x8f, 0xac,
- 0x7f, 0xe0, 0x54, 0x54, 0x7f, 0xc3, 0xd3, 0x7c, 0x2d, 0xff, 0x00, 0x42,
- 0x3e, 0xb1, 0xff, 0x00, 0x81, 0x51, 0x57, 0xc3, 0xbf, 0xd8, 0x76, 0x1f,
- 0xf3, 0xeb, 0x1f, 0xe5, 0x51, 0xbe, 0x8d, 0x63, 0x9c, 0x0b, 0x64, 0xfc,
- 0xa8, 0xb0, 0x72, 0x23, 0xee, 0x6f, 0xf8, 0x7a, 0x6f, 0x85, 0xbf, 0xe8,
- 0x47, 0xd6, 0x3f, 0xf0, 0x2a, 0x2a, 0x3f, 0xe1, 0xe9, 0xbe, 0x16, 0xff,
- 0x00, 0xa1, 0x1f, 0x58, 0xff, 0x00, 0xc0, 0xa8, 0xab, 0xe1, 0x7f, 0xec,
- 0x7b, 0x2f, 0xf9, 0xf6, 0x4f, 0xca, 0x9b, 0x2e, 0x9d, 0xa7, 0xdb, 0xed,
- 0x53, 0x67, 0xe6, 0xc8, 0xc0, 0x90, 0xb1, 0xae, 0x4e, 0x3d, 0x68, 0xb0,
- 0x72, 0x23, 0xee, 0xaf, 0xf8, 0x7a, 0x6f, 0x85, 0xbf, 0xe8, 0x47, 0xd6,
- 0x3f, 0xf0, 0x2a, 0x2a, 0x3f, 0xe1, 0xe9, 0xbe, 0x16, 0xff, 0x00, 0xa1,
- 0x1f, 0x58, 0xff, 0x00, 0xc0, 0xa8, 0xab, 0xe1, 0x1f, 0x23, 0x4b, 0xd8,
- 0x1b, 0xec, 0x44, 0x8d, 0xbb, 0x9b, 0x09, 0xf7, 0x06, 0x48, 0xc9, 0xe7,
- 0xd8, 0xfe, 0x54, 0x3d, 0x9e, 0x9e, 0x2e, 0x04, 0x66, 0xcb, 0x60, 0x27,
- 0x68, 0x72, 0xbf, 0x29, 0x3f, 0x5c, 0xd1, 0x60, 0xe4, 0x47, 0xdd, 0xdf,
- 0xf0, 0xf4, 0xdf, 0x0b, 0x7f, 0xd0, 0x8f, 0xac, 0x7f, 0xe0, 0x54, 0x54,
- 0x7f, 0xc3, 0xd3, 0x7c, 0x2d, 0xff, 0x00, 0x42, 0x3e, 0xb1, 0xff, 0x00,
- 0x81, 0x51, 0x57, 0xc1, 0x82, 0xdf, 0x4e, 0x1b, 0xb7, 0xd9, 0x98, 0x88,
- 0x19, 0xda, 0xeb, 0xc9, 0xe7, 0x1c, 0x73, 0xea, 0x45, 0x4d, 0x1d, 0x9e,
- 0x9a, 0x46, 0x0d, 0x91, 0x12, 0x02, 0x41, 0x8c, 0xaf, 0xcd, 0x9c, 0x67,
- 0xd7, 0xd2, 0x8b, 0x07, 0x22, 0x3e, 0xed, 0xff, 0x00, 0x87, 0xa6, 0xf8,
- 0x5b, 0xfe, 0x84, 0x7d, 0x63, 0xff, 0x00, 0x02, 0xa2, 0xa3, 0xfe, 0x1e,
- 0x9b, 0xe1, 0x6f, 0xfa, 0x11, 0xf5, 0x8f, 0xfc, 0x0a, 0x8a, 0xbe, 0x16,
- 0xb7, 0xd3, 0xf4, 0xeb, 0x86, 0x65, 0xfb, 0x1f, 0x96, 0xea, 0x01, 0x2b,
- 0x22, 0xe0, 0xe0, 0xf7, 0xa7, 0x36, 0x8f, 0x62, 0x49, 0xc5, 0xb2, 0x62,
- 0x8b, 0x07, 0x22, 0x3e, 0xe7, 0xff, 0x00, 0x87, 0xa6, 0xf8, 0x5b, 0xfe,
- 0x84, 0x7d, 0x63, 0xff, 0x00, 0x02, 0xa2, 0xa3, 0xfe, 0x1e, 0x9b, 0xe1,
- 0x6f, 0xfa, 0x11, 0xf5, 0x8f, 0xfc, 0x0a, 0x8a, 0xbe, 0x17, 0xfe, 0xc6,
- 0xb2, 0x3f, 0xf2, 0xec, 0x95, 0x30, 0xd0, 0xec, 0x40, 0xff, 0x00, 0x8f,
- 0x64, 0xa2, 0xc1, 0xc8, 0x8f, 0xb8, 0xbf, 0xe1, 0xe9, 0xbe, 0x16, 0xff,
- 0x00, 0xa1, 0x1f, 0x58, 0xff, 0x00, 0xc0, 0xa8, 0xa8, 0xff, 0x00, 0x87,
- 0xa6, 0xf8, 0x5b, 0xfe, 0x84, 0x7d, 0x63, 0xff, 0x00, 0x02, 0xa2, 0xaf,
- 0x87, 0x7f, 0xb1, 0x2c, 0x07, 0xfc, 0xba, 0xc7, 0xf9, 0x54, 0x27, 0x47,
- 0xb2, 0x27, 0xfe, 0x3d, 0x92, 0x8b, 0x07, 0x22, 0x3e, 0xe8, 0xff, 0x00,
- 0x87, 0xa6, 0xf8, 0x5b, 0xfe, 0x84, 0x7d, 0x63, 0xff, 0x00, 0x02, 0xa2,
- 0xa3, 0xfe, 0x1e, 0x9b, 0xe1, 0x6f, 0xfa, 0x11, 0xf5, 0x8f, 0xfc, 0x0a,
- 0x8a, 0xbe, 0x17, 0x1a, 0x2d, 0x91, 0x38, 0xfb, 0x32, 0x54, 0xdf, 0xd8,
- 0x76, 0x1f, 0xf3, 0xea, 0x9f, 0x95, 0x16, 0x0e, 0x44, 0x7d, 0xc5, 0xff,
- 0x00, 0x0f, 0x4d, 0xf0, 0xb7, 0xfd, 0x08, 0xfa, 0xc7, 0xfe, 0x05, 0x45,
- 0x47, 0xfc, 0x3d, 0x37, 0xc2, 0xdf, 0xf4, 0x23, 0xeb, 0x1f, 0xf8, 0x15,
- 0x15, 0x7c, 0x3a, 0x74, 0x4b, 0x00, 0x33, 0xf6, 0x58, 0xff, 0x00, 0x2a,
- 0x84, 0xe8, 0xd6, 0x5f, 0xf3, 0xec, 0x94, 0x58, 0x39, 0x11, 0xf7, 0x47,
- 0xfc, 0x3d, 0x37, 0xc2, 0xdf, 0xf4, 0x23, 0xeb, 0x1f, 0xf8, 0x15, 0x15,
- 0x1f, 0xf0, 0xf4, 0xdf, 0x0b, 0x7f, 0xd0, 0x8f, 0xac, 0x7f, 0xe0, 0x54,
- 0x55, 0xf0, 0xc2, 0xe8, 0xb6, 0x4c, 0x40, 0xfb, 0x32, 0x54, 0xbf, 0xd8,
- 0x76, 0x1f, 0xf3, 0xea, 0x94, 0x58, 0x39, 0x11, 0xf7, 0x17, 0xfc, 0x3d,
- 0x37, 0xc2, 0xdf, 0xf4, 0x23, 0xeb, 0x1f, 0xf8, 0x15, 0x15, 0x1f, 0xf0,
- 0xf4, 0xdf, 0x0b, 0x7f, 0xd0, 0x8f, 0xac, 0x7f, 0xe0, 0x54, 0x55, 0xf0,
- 0xe3, 0x68, 0xb6, 0x0a, 0x09, 0xfb, 0x2c, 0x7f, 0x95, 0x45, 0xfd, 0x8d,
- 0x65, 0xff, 0x00, 0x3e, 0xc9, 0x45, 0x83, 0x91, 0x1f, 0x74, 0x7f, 0xc3,
- 0xd3, 0x7c, 0x2d, 0xff, 0x00, 0x42, 0x3e, 0xb1, 0xff, 0x00, 0x81, 0x51,
- 0x51, 0xff, 0x00, 0x0f, 0x4d, 0xf0, 0xb7, 0xfd, 0x08, 0xfa, 0xc7, 0xfe,
- 0x05, 0x45, 0x5f, 0x0c, 0x26, 0x89, 0x64, 0xcd, 0xff, 0x00, 0x1e, 0xc9,
- 0x52, 0xff, 0x00, 0x61, 0xd8, 0x7f, 0xcf, 0xac, 0x7f, 0x95, 0x16, 0x0e,
- 0x44, 0x7d, 0xc5, 0xff, 0x00, 0x0f, 0x4d, 0xf0, 0xb7, 0xfd, 0x08, 0xfa,
- 0xc7, 0xfe, 0x05, 0x45, 0x47, 0xfc, 0x3d, 0x37, 0xc2, 0xdf, 0xf4, 0x23,
- 0xeb, 0x1f, 0xf8, 0x15, 0x15, 0x7c, 0x38, 0xfa, 0x2d, 0x82, 0xaf, 0xfc,
- 0x7a, 0xc7, 0xf9, 0x54, 0x5f, 0xd8, 0xd6, 0x5f, 0xf3, 0xec, 0x94, 0x58,
- 0x39, 0x11, 0x72, 0xa7, 0x45, 0xda, 0xb8, 0xa8, 0xe3, 0x5c, 0xb6, 0x7d,
- 0x2a, 0x5a, 0xa2, 0xc2, 0xa1, 0x66, 0xdc, 0xd9, 0xa7, 0xc8, 0xd8, 0x18,
- 0xf5, 0xa8, 0xa8, 0x01, 0x40, 0xc9, 0xa9, 0xd4, 0x6d, 0x18, 0xa8, 0xe2,
- 0x5e, 0x73, 0x52, 0x50, 0x00, 0x4e, 0x05, 0x40, 0xc7, 0x71, 0xcd, 0x49,
- 0x2b, 0x71, 0x8a, 0x8a, 0x80, 0x14, 0x0c, 0x9c, 0x54, 0xe0, 0x60, 0x62,
- 0xa3, 0x89, 0x7b, 0xd4, 0x94, 0x00, 0x13, 0x80, 0x4d, 0x40, 0x4e, 0x4e,
- 0x69, 0xf2, 0xb7, 0x6a, 0x8e, 0x80, 0x15, 0x46, 0xe3, 0x8a, 0x9e, 0x99,
- 0x1a, 0xe0, 0x67, 0xd6, 0x9f, 0x40, 0x08, 0xc7, 0x68, 0xcd, 0x41, 0x4f,
- 0x91, 0xb2, 0x71, 0xe9, 0x4c, 0xa0, 0x07, 0x22, 0xee, 0x6f, 0x6a, 0x27,
- 0xb5, 0x59, 0xa4, 0x49, 0x37, 0xbc, 0x6e, 0xbc, 0x06, 0x43, 0x8c, 0x8f,
- 0x43, 0xed, 0x52, 0x46, 0xb8, 0x5f, 0x73, 0x4e, 0xa0, 0x0a, 0xa6, 0xca,
- 0x38, 0xa2, 0x95, 0x41, 0x6f, 0xde, 0x2e, 0xc3, 0xcf, 0x6c, 0x93, 0xff,
- 0x00, 0xb3, 0x1a, 0x87, 0xec, 0x60, 0xca, 0xae, 0xd2, 0x48, 0xe1, 0x4e,
- 0x42, 0x12, 0x36, 0x83, 0xf9, 0x55, 0xa9, 0x1b, 0x73, 0x7b, 0x0a, 0x6d,
- 0x00, 0x57, 0x8b, 0x49, 0xb7, 0x0c, 0xfb, 0x53, 0xcb, 0x0c, 0x00, 0x21,
- 0x38, 0xe8, 0x72, 0x0f, 0xd6, 0xa6, 0x5d, 0x39, 0x17, 0x90, 0xf2, 0x79,
- 0x99, 0x2c, 0x64, 0x27, 0x2c, 0x4e, 0xdc, 0x7e, 0x82, 0xac, 0xa2, 0xed,
- 0x5a, 0x5a, 0x00, 0xad, 0x1d, 0xaa, 0xdb, 0x16, 0x6f, 0x31, 0xe5, 0x91,
- 0xc0, 0x05, 0xe4, 0x39, 0x38, 0x1d, 0xbf, 0x5a, 0x5a, 0x73, 0xb6, 0xe6,
- 0xa6, 0xf5, 0xa0, 0x07, 0xc4, 0xb9, 0x39, 0xf4, 0xa9, 0x69, 0x14, 0x6d,
- 0x18, 0xa5, 0xe9, 0x40, 0x0c, 0x95, 0xb0, 0x31, 0x51, 0x52, 0xb1, 0xdc,
- 0x49, 0xa0, 0x0c, 0x9c, 0x50, 0x03, 0xe2, 0x5e, 0xf5, 0x25, 0x00, 0x60,
- 0x62, 0x82, 0x70, 0x33, 0x40, 0x11, 0xca, 0xdd, 0xaa, 0x3a, 0x52, 0x72,
- 0x73, 0x42, 0x8d, 0xc4, 0x0a, 0x00, 0x92, 0x25, 0xc0, 0xcd, 0x3e, 0x8e,
- 0x94, 0x8c, 0x76, 0x82, 0x68, 0x02, 0x39, 0x5b, 0x27, 0x1e, 0x94, 0xca,
- 0x3a, 0xd3, 0x91, 0x77, 0x35, 0x00, 0x49, 0x1a, 0xe1, 0x7d, 0xcd, 0x3a,
- 0x8a, 0x47, 0x6d, 0xab, 0x40, 0x11, 0xc8, 0xd9, 0x6f, 0x61, 0x4c, 0xa2,
- 0x9d, 0x1a, 0xee, 0x6f, 0x61, 0x40, 0x1f, 0xff, 0xd9
-};
diff --git a/services/camera/libcameraservice/FakeCamera.cpp b/services/camera/libcameraservice/FakeCamera.cpp
deleted file mode 100644
index f3a6a67..0000000
--- a/services/camera/libcameraservice/FakeCamera.cpp
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
-**
-** Copyright 2008, 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 "FakeCamera"
-#include <utils/Log.h>
-
-#include <string.h>
-#include <stdlib.h>
-#include <utils/String8.h>
-
-#include "FakeCamera.h"
-
-
-namespace android {
-
-// TODO: All this rgb to yuv should probably be in a util class.
-
-// TODO: I think something is wrong in this class because the shadow is kBlue
-// and the square color should alternate between kRed and kGreen. However on the
-// emulator screen these are all shades of gray. Y seems ok but the U and V are
-// probably not.
-
-static int tables_initialized = 0;
-uint8_t *gYTable, *gCbTable, *gCrTable;
-
-static int
-clamp(int x)
-{
- if (x > 255) return 255;
- if (x < 0) return 0;
- return x;
-}
-
-/* the equation used by the video code to translate YUV to RGB looks like this
- *
- * Y = (Y0 - 16)*k0
- * Cb = Cb0 - 128
- * Cr = Cr0 - 128
- *
- * G = ( Y - k1*Cr - k2*Cb )
- * R = ( Y + k3*Cr )
- * B = ( Y + k4*Cb )
- *
- */
-
-static const double k0 = 1.164;
-static const double k1 = 0.813;
-static const double k2 = 0.391;
-static const double k3 = 1.596;
-static const double k4 = 2.018;
-
-/* let's try to extract the value of Y
- *
- * G + k1/k3*R + k2/k4*B = Y*( 1 + k1/k3 + k2/k4 )
- *
- * Y = ( G + k1/k3*R + k2/k4*B ) / (1 + k1/k3 + k2/k4)
- * Y0 = ( G0 + k1/k3*R0 + k2/k4*B0 ) / ((1 + k1/k3 + k2/k4)*k0) + 16
- *
- * let define:
- * kYr = k1/k3
- * kYb = k2/k4
- * kYy = k0 * ( 1 + kYr + kYb )
- *
- * we have:
- * Y = ( G + kYr*R + kYb*B )
- * Y0 = clamp[ Y/kYy + 16 ]
- */
-
-static const double kYr = k1/k3;
-static const double kYb = k2/k4;
-static const double kYy = k0*( 1. + kYr + kYb );
-
-static void
-initYtab( void )
-{
- const int imax = (int)( (kYr + kYb)*(31 << 2) + (61 << 3) + 0.1 );
- int i;
-
- gYTable = (uint8_t *)malloc(imax);
-
- for(i=0; i<imax; i++) {
- int x = (int)(i/kYy + 16.5);
- if (x < 16) x = 16;
- else if (x > 235) x = 235;
- gYTable[i] = (uint8_t) x;
- }
-}
-
-/*
- * the source is RGB565, so adjust for 8-bit range of input values:
- *
- * G = (pixels >> 3) & 0xFC;
- * R = (pixels >> 8) & 0xF8;
- * B = (pixels & 0x1f) << 3;
- *
- * R2 = (pixels >> 11) R = R2*8
- * B2 = (pixels & 0x1f) B = B2*8
- *
- * kYr*R = kYr2*R2 => kYr2 = kYr*8
- * kYb*B = kYb2*B2 => kYb2 = kYb*8
- *
- * we want to use integer multiplications:
- *
- * SHIFT1 = 9
- *
- * (ALPHA*R2) >> SHIFT1 == R*kYr => ALPHA = kYr*8*(1 << SHIFT1)
- *
- * ALPHA = kYr*(1 << (SHIFT1+3))
- * BETA = kYb*(1 << (SHIFT1+3))
- */
-
-static const int SHIFT1 = 9;
-static const int ALPHA = (int)( kYr*(1 << (SHIFT1+3)) + 0.5 );
-static const int BETA = (int)( kYb*(1 << (SHIFT1+3)) + 0.5 );
-
-/*
- * now let's try to get the values of Cb and Cr
- *
- * R-B = (k3*Cr - k4*Cb)
- *
- * k3*Cr = k4*Cb + (R-B)
- * k4*Cb = k3*Cr - (R-B)
- *
- * R-G = (k1+k3)*Cr + k2*Cb
- * = (k1+k3)*Cr + k2/k4*(k3*Cr - (R-B)/k0)
- * = (k1 + k3 + k2*k3/k4)*Cr - k2/k4*(R-B)
- *
- * kRr*Cr = (R-G) + kYb*(R-B)
- *
- * Cr = ((R-G) + kYb*(R-B))/kRr
- * Cr0 = clamp(Cr + 128)
- */
-
-static const double kRr = (k1 + k3 + k2*k3/k4);
-
-static void
-initCrtab( void )
-{
- uint8_t *pTable;
- int i;
-
- gCrTable = (uint8_t *)malloc(768*2);
-
- pTable = gCrTable + 384;
- for(i=-384; i<384; i++)
- pTable[i] = (uint8_t) clamp( i/kRr + 128.5 );
-}
-
-/*
- * B-G = (k2 + k4)*Cb + k1*Cr
- * = (k2 + k4)*Cb + k1/k3*(k4*Cb + (R-B))
- * = (k2 + k4 + k1*k4/k3)*Cb + k1/k3*(R-B)
- *
- * kBb*Cb = (B-G) - kYr*(R-B)
- *
- * Cb = ((B-G) - kYr*(R-B))/kBb
- * Cb0 = clamp(Cb + 128)
- *
- */
-
-static const double kBb = (k2 + k4 + k1*k4/k3);
-
-static void
-initCbtab( void )
-{
- uint8_t *pTable;
- int i;
-
- gCbTable = (uint8_t *)malloc(768*2);
-
- pTable = gCbTable + 384;
- for(i=-384; i<384; i++)
- pTable[i] = (uint8_t) clamp( i/kBb + 128.5 );
-}
-
-/*
- * SHIFT2 = 16
- *
- * DELTA = kYb*(1 << SHIFT2)
- * GAMMA = kYr*(1 << SHIFT2)
- */
-
-static const int SHIFT2 = 16;
-static const int DELTA = kYb*(1 << SHIFT2);
-static const int GAMMA = kYr*(1 << SHIFT2);
-
-int32_t ccrgb16toyuv_wo_colorkey(uint8_t *rgb16, uint8_t *yuv420,
- uint32_t *param, uint8_t *table[])
-{
- uint16_t *inputRGB = (uint16_t*)rgb16;
- uint8_t *outYUV = yuv420;
- int32_t width_dst = param[0];
- int32_t height_dst = param[1];
- int32_t pitch_dst = param[2];
- int32_t mheight_dst = param[3];
- int32_t pitch_src = param[4];
- uint8_t *y_tab = table[0];
- uint8_t *cb_tab = table[1];
- uint8_t *cr_tab = table[2];
-
- int32_t size16 = pitch_dst*mheight_dst;
- int32_t i,j,count;
- int32_t ilimit,jlimit;
- uint8_t *tempY,*tempU,*tempV;
- uint16_t pixels;
- int tmp;
-uint32_t temp;
-
- tempY = outYUV;
- tempU = outYUV + (height_dst * pitch_dst);
- tempV = tempU + 1;
-
- jlimit = height_dst;
- ilimit = width_dst;
-
- for(j=0; j<jlimit; j+=1)
- {
- for (i=0; i<ilimit; i+=2)
- {
- int32_t G_ds = 0, B_ds = 0, R_ds = 0;
- uint8_t y0, y1, u, v;
-
- pixels = inputRGB[i];
- temp = (BETA*(pixels & 0x001F) + ALPHA*(pixels>>11) );
- y0 = y_tab[(temp>>SHIFT1) + ((pixels>>3) & 0x00FC)];
-
- G_ds += (pixels>>1) & 0x03E0;
- B_ds += (pixels<<5) & 0x03E0;
- R_ds += (pixels>>6) & 0x03E0;
-
- pixels = inputRGB[i+1];
- temp = (BETA*(pixels & 0x001F) + ALPHA*(pixels>>11) );
- y1 = y_tab[(temp>>SHIFT1) + ((pixels>>3) & 0x00FC)];
-
- G_ds += (pixels>>1) & 0x03E0;
- B_ds += (pixels<<5) & 0x03E0;
- R_ds += (pixels>>6) & 0x03E0;
-
- R_ds >>= 1;
- B_ds >>= 1;
- G_ds >>= 1;
-
- tmp = R_ds - B_ds;
-
- u = cb_tab[(((B_ds-G_ds)<<SHIFT2) - GAMMA*tmp)>>(SHIFT2+2)];
- v = cr_tab[(((R_ds-G_ds)<<SHIFT2) + DELTA*tmp)>>(SHIFT2+2)];
-
- tempY[0] = y0;
- tempY[1] = y1;
- tempY += 2;
-
- if ((j&1) == 0) {
- tempU[0] = u;
- tempV[0] = v;
- tempU += 2;
- tempV += 2;
- }
- }
-
- inputRGB += pitch_src;
- }
-
- return 1;
-}
-
-#define min(a,b) ((a)<(b)?(a):(b))
-#define max(a,b) ((a)>(b)?(a):(b))
-
-static void convert_rgb16_to_yuv420(uint8_t *rgb, uint8_t *yuv, int width, int height)
-{
- if (!tables_initialized) {
- initYtab();
- initCrtab();
- initCbtab();
- tables_initialized = 1;
- }
-
- uint32_t param[6];
- param[0] = (uint32_t) width;
- param[1] = (uint32_t) height;
- param[2] = (uint32_t) width;
- param[3] = (uint32_t) height;
- param[4] = (uint32_t) width;
- param[5] = (uint32_t) 0;
-
- uint8_t *table[3];
- table[0] = gYTable;
- table[1] = gCbTable + 384;
- table[2] = gCrTable + 384;
-
- ccrgb16toyuv_wo_colorkey(rgb, yuv, param, table);
-}
-
-const int FakeCamera::kRed;
-const int FakeCamera::kGreen;
-const int FakeCamera::kBlue;
-
-FakeCamera::FakeCamera(int width, int height)
- : mTmpRgb16Buffer(0)
-{
- setSize(width, height);
-}
-
-FakeCamera::~FakeCamera()
-{
- delete[] mTmpRgb16Buffer;
-}
-
-void FakeCamera::setSize(int width, int height)
-{
- mWidth = width;
- mHeight = height;
- mCounter = 0;
- mCheckX = 0;
- mCheckY = 0;
-
- // This will cause it to be reallocated on the next call
- // to getNextFrameAsYuv420().
- delete[] mTmpRgb16Buffer;
- mTmpRgb16Buffer = 0;
-}
-
-void FakeCamera::getNextFrameAsRgb565(uint16_t *buffer)
-{
- int size = mWidth / 10;
-
- drawCheckerboard(buffer, size);
-
- int x = ((mCounter*3)&255);
- if(x>128) x = 255 - x;
- int y = ((mCounter*5)&255);
- if(y>128) y = 255 - y;
-
- drawSquare(buffer, x*size/32, y*size/32, (size*5)>>1, (mCounter&0x100)?kRed:kGreen, kBlue);
-
- mCounter++;
-}
-
-void FakeCamera::getNextFrameAsYuv420(uint8_t *buffer)
-{
- if (mTmpRgb16Buffer == 0)
- mTmpRgb16Buffer = new uint16_t[mWidth * mHeight];
-
- getNextFrameAsRgb565(mTmpRgb16Buffer);
- convert_rgb16_to_yuv420((uint8_t*)mTmpRgb16Buffer, buffer, mWidth, mHeight);
-}
-
-void FakeCamera::drawSquare(uint16_t *dst, int x, int y, int size, int color, int shadow)
-{
- int square_xstop, square_ystop, shadow_xstop, shadow_ystop;
-
- square_xstop = min(mWidth, x+size);
- square_ystop = min(mHeight, y+size);
- shadow_xstop = min(mWidth, x+size+(size/4));
- shadow_ystop = min(mHeight, y+size+(size/4));
-
- // Do the shadow.
- uint16_t *sh = &dst[(y+(size/4))*mWidth];
- for (int j = y + (size/4); j < shadow_ystop; j++) {
- for (int i = x + (size/4); i < shadow_xstop; i++) {
- sh[i] &= shadow;
- }
- sh += mWidth;
- }
-
- // Draw the square.
- uint16_t *sq = &dst[y*mWidth];
- for (int j = y; j < square_ystop; j++) {
- for (int i = x; i < square_xstop; i++) {
- sq[i] = color;
- }
- sq += mWidth;
- }
-}
-
-void FakeCamera::drawCheckerboard(uint16_t *dst, int size)
-{
- bool black = true;
-
- if((mCheckX/size)&1)
- black = false;
- if((mCheckY/size)&1)
- black = !black;
-
- int county = mCheckY%size;
- int checkxremainder = mCheckX%size;
-
- for(int y=0;y<mHeight;y++) {
- int countx = checkxremainder;
- bool current = black;
- for(int x=0;x<mWidth;x++) {
- dst[y*mWidth+x] = current?0:0xffff;
- if(countx++ >= size) {
- countx=0;
- current = !current;
- }
- }
- if(county++ >= size) {
- county=0;
- black = !black;
- }
- }
- mCheckX += 3;
- mCheckY++;
-}
-
-
-void FakeCamera::dump(int fd) const
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- snprintf(buffer, 255, " width x height (%d x %d), counter (%d), check x-y coordinate(%d, %d)\n", mWidth, mHeight, mCounter, mCheckX, mCheckY);
- result.append(buffer);
- ::write(fd, result.string(), result.size());
-}
-
-
-}; // namespace android
diff --git a/services/camera/libcameraservice/FakeCamera.h b/services/camera/libcameraservice/FakeCamera.h
deleted file mode 100644
index 724de20..0000000
--- a/services/camera/libcameraservice/FakeCamera.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
-**
-** Copyright 2008, 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_FAKECAMERA_H
-#define ANDROID_HARDWARE_FAKECAMERA_H
-
-#include <sys/types.h>
-#include <stdint.h>
-
-namespace android {
-
-/*
- * FakeCamera is used in the CameraHardwareStub to provide a fake video feed
- * when the system does not have a camera in hardware.
- * The fake video is a moving black and white checkerboard background with a
- * bouncing gray square in the foreground.
- * This class is not thread-safe.
- *
- * TODO: Since the major methods provides a raw/uncompressed video feed, rename
- * this class to RawVideoSource.
- */
-
-class FakeCamera {
-public:
- FakeCamera(int width, int height);
- ~FakeCamera();
-
- void setSize(int width, int height);
- void getNextFrameAsYuv420(uint8_t *buffer);
- // Write to the fd a string representing the current state.
- void dump(int fd) const;
-
-private:
- // TODO: remove the uint16_t buffer param everywhere since it is a field of
- // this class.
- void getNextFrameAsRgb565(uint16_t *buffer);
-
- void drawSquare(uint16_t *buffer, int x, int y, int size, int color, int shadow);
- void drawCheckerboard(uint16_t *buffer, int size);
-
- static const int kRed = 0xf800;
- static const int kGreen = 0x07c0;
- static const int kBlue = 0x003e;
-
- int mWidth, mHeight;
- int mCounter;
- int mCheckX, mCheckY;
- uint16_t *mTmpRgb16Buffer;
-};
-
-}; // namespace android
-
-#endif // ANDROID_HARDWARE_FAKECAMERA_H