Merge "Implement the source->sink(!) keep alive the wfd specs mandate..." into jb-mr1-dev
diff --git a/services/audioflinger/AudioBufferProvider.h b/include/media/AudioBufferProvider.h
similarity index 100%
rename from services/audioflinger/AudioBufferProvider.h
rename to include/media/AudioBufferProvider.h
diff --git a/services/audioflinger/ExtendedAudioBufferProvider.h b/include/media/ExtendedAudioBufferProvider.h
similarity index 95%
rename from services/audioflinger/ExtendedAudioBufferProvider.h
rename to include/media/ExtendedAudioBufferProvider.h
index 88279b4..00c4444 100644
--- a/services/audioflinger/ExtendedAudioBufferProvider.h
+++ b/include/media/ExtendedAudioBufferProvider.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_EXTENDED_AUDIO_BUFFER_PROVIDER_H
 #define ANDROID_EXTENDED_AUDIO_BUFFER_PROVIDER_H
 
-#include "AudioBufferProvider.h"
+#include <media/AudioBufferProvider.h>
 
 namespace android {
 
diff --git a/services/audioflinger/AudioBufferProviderSource.h b/include/media/nbaio/AudioBufferProviderSource.h
similarity index 97%
rename from services/audioflinger/AudioBufferProviderSource.h
rename to include/media/nbaio/AudioBufferProviderSource.h
index 1435a84..2c4aaff 100644
--- a/services/audioflinger/AudioBufferProviderSource.h
+++ b/include/media/nbaio/AudioBufferProviderSource.h
@@ -20,7 +20,7 @@
 #define ANDROID_AUDIO_BUFFER_PROVIDER_SOURCE_H
 
 #include "NBAIO.h"
-#include "AudioBufferProvider.h"
+#include <media/AudioBufferProvider.h>
 
 namespace android {
 
diff --git a/services/audioflinger/AudioStreamInSource.h b/include/media/nbaio/AudioStreamInSource.h
similarity index 100%
rename from services/audioflinger/AudioStreamInSource.h
rename to include/media/nbaio/AudioStreamInSource.h
diff --git a/services/audioflinger/AudioStreamOutSink.h b/include/media/nbaio/AudioStreamOutSink.h
similarity index 100%
rename from services/audioflinger/AudioStreamOutSink.h
rename to include/media/nbaio/AudioStreamOutSink.h
diff --git a/services/audioflinger/LibsndfileSink.h b/include/media/nbaio/LibsndfileSink.h
similarity index 100%
rename from services/audioflinger/LibsndfileSink.h
rename to include/media/nbaio/LibsndfileSink.h
diff --git a/services/audioflinger/LibsndfileSource.h b/include/media/nbaio/LibsndfileSource.h
similarity index 100%
rename from services/audioflinger/LibsndfileSource.h
rename to include/media/nbaio/LibsndfileSource.h
diff --git a/services/audioflinger/MonoPipe.h b/include/media/nbaio/MonoPipe.h
similarity index 100%
rename from services/audioflinger/MonoPipe.h
rename to include/media/nbaio/MonoPipe.h
diff --git a/services/audioflinger/MonoPipeReader.h b/include/media/nbaio/MonoPipeReader.h
similarity index 100%
rename from services/audioflinger/MonoPipeReader.h
rename to include/media/nbaio/MonoPipeReader.h
diff --git a/services/audioflinger/NBAIO.h b/include/media/nbaio/NBAIO.h
similarity index 100%
rename from services/audioflinger/NBAIO.h
rename to include/media/nbaio/NBAIO.h
diff --git a/services/audioflinger/Pipe.h b/include/media/nbaio/Pipe.h
similarity index 100%
rename from services/audioflinger/Pipe.h
rename to include/media/nbaio/Pipe.h
diff --git a/services/audioflinger/PipeReader.h b/include/media/nbaio/PipeReader.h
similarity index 100%
rename from services/audioflinger/PipeReader.h
rename to include/media/nbaio/PipeReader.h
diff --git a/services/audioflinger/SourceAudioBufferProvider.h b/include/media/nbaio/SourceAudioBufferProvider.h
similarity index 97%
rename from services/audioflinger/SourceAudioBufferProvider.h
rename to include/media/nbaio/SourceAudioBufferProvider.h
index 85ccbb2..c08331b 100644
--- a/services/audioflinger/SourceAudioBufferProvider.h
+++ b/include/media/nbaio/SourceAudioBufferProvider.h
@@ -20,7 +20,7 @@
 #define ANDROID_SOURCE_AUDIO_BUFFER_PROVIDER_H
 
 #include "NBAIO.h"
-#include "ExtendedAudioBufferProvider.h"
+#include <media/ExtendedAudioBufferProvider.h>
 
 namespace android {
 
diff --git a/services/audioflinger/roundup.h b/include/media/nbaio/roundup.h
similarity index 100%
rename from services/audioflinger/roundup.h
rename to include/media/nbaio/roundup.h
diff --git a/libvideoeditor/lvpp/VideoEditorSRC.h b/libvideoeditor/lvpp/VideoEditorSRC.h
index 2b7e9b6..1707d4d 100755
--- a/libvideoeditor/lvpp/VideoEditorSRC.h
+++ b/libvideoeditor/lvpp/VideoEditorSRC.h
@@ -17,7 +17,7 @@
 
 #include <stdint.h>
 #include <media/stagefright/MediaSource.h>
-#include "AudioBufferProvider.h"
+#include <media/AudioBufferProvider.h>
 #include "AudioResampler.h"
 
 namespace android {
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 32ee89e..d4be9fa 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -1011,6 +1011,8 @@
         LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "Effect_setConfig")
         if(LvmStatus != LVM_SUCCESS) return -EINVAL;
 
+        ActiveParams.SampleRate = SampleRate;
+
         LvmStatus = LVM_SetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams);
 
         LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "Effect_setConfig")
diff --git a/media/libnbaio/Android.mk b/media/libnbaio/Android.mk
new file mode 100644
index 0000000..757272f
--- /dev/null
+++ b/media/libnbaio/Android.mk
@@ -0,0 +1,32 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    AudioBufferProviderSource.cpp   \
+    AudioStreamOutSink.cpp          \
+    AudioStreamInSource.cpp         \
+    NBAIO.cpp                       \
+    MonoPipe.cpp                    \
+    MonoPipeReader.cpp              \
+    Pipe.cpp                        \
+    PipeReader.cpp                  \
+    roundup.c                       \
+    SourceAudioBufferProvider.cpp
+
+# libsndfile license is incompatible; uncomment to use for local debug only
+#LOCAL_SRC_FILES += LibsndfileSink.cpp LibsndfileSource.cpp
+#LOCAL_C_INCLUDES += path/to/libsndfile/src
+#LOCAL_STATIC_LIBRARIES += libsndfile
+
+# uncomment for systrace
+# LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_AUDIO
+
+LOCAL_MODULE := libnbaio
+
+LOCAL_SHARED_LIBRARIES := \
+    libcommon_time_client \
+    libcutils \
+    libutils
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audioflinger/AudioBufferProviderSource.cpp b/media/libnbaio/AudioBufferProviderSource.cpp
similarity index 98%
rename from services/audioflinger/AudioBufferProviderSource.cpp
rename to media/libnbaio/AudioBufferProviderSource.cpp
index 613e924..74a6fdb 100644
--- a/services/audioflinger/AudioBufferProviderSource.cpp
+++ b/media/libnbaio/AudioBufferProviderSource.cpp
@@ -19,7 +19,7 @@
 
 #include <cutils/compiler.h>
 #include <utils/Log.h>
-#include "AudioBufferProviderSource.h"
+#include <media/nbaio/AudioBufferProviderSource.h>
 
 namespace android {
 
diff --git a/services/audioflinger/AudioStreamInSource.cpp b/media/libnbaio/AudioStreamInSource.cpp
similarity index 97%
rename from services/audioflinger/AudioStreamInSource.cpp
rename to media/libnbaio/AudioStreamInSource.cpp
index 8b4bebf..05273f6 100644
--- a/services/audioflinger/AudioStreamInSource.cpp
+++ b/media/libnbaio/AudioStreamInSource.cpp
@@ -19,7 +19,7 @@
 
 #include <cutils/compiler.h>
 #include <utils/Log.h>
-#include "AudioStreamInSource.h"
+#include <media/nbaio/AudioStreamInSource.h>
 
 namespace android {
 
diff --git a/services/audioflinger/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp
similarity index 97%
rename from services/audioflinger/AudioStreamOutSink.cpp
rename to media/libnbaio/AudioStreamOutSink.cpp
index bc2d15b..6f525e5 100644
--- a/services/audioflinger/AudioStreamOutSink.cpp
+++ b/media/libnbaio/AudioStreamOutSink.cpp
@@ -18,7 +18,7 @@
 //#define LOG_NDEBUG 0
 
 #include <utils/Log.h>
-#include "AudioStreamOutSink.h"
+#include <media/nbaio/AudioStreamOutSink.h>
 
 namespace android {
 
diff --git a/services/audioflinger/LibsndfileSink.cpp b/media/libnbaio/LibsndfileSink.cpp
similarity index 96%
rename from services/audioflinger/LibsndfileSink.cpp
rename to media/libnbaio/LibsndfileSink.cpp
index efc1c8f..77debc0 100644
--- a/services/audioflinger/LibsndfileSink.cpp
+++ b/media/libnbaio/LibsndfileSink.cpp
@@ -19,7 +19,7 @@
 
 #include <utils/Errors.h>
 #include <utils/Log.h>
-#include "LibsndfileSink.h"
+#include <media/nbaio/LibsndfileSink.h>
 
 namespace android {
 
diff --git a/services/audioflinger/LibsndfileSource.cpp b/media/libnbaio/LibsndfileSource.cpp
similarity index 97%
rename from services/audioflinger/LibsndfileSource.cpp
rename to media/libnbaio/LibsndfileSource.cpp
index 28317d6..98610e0 100644
--- a/services/audioflinger/LibsndfileSource.cpp
+++ b/media/libnbaio/LibsndfileSource.cpp
@@ -19,7 +19,7 @@
 
 #include <utils/Errors.h>
 #include <utils/Log.h>
-#include "LibsndfileSource.h"
+#include <media/nbaio/LibsndfileSource.h>
 
 namespace android {
 
diff --git a/services/audioflinger/MonoPipe.cpp b/media/libnbaio/MonoPipe.cpp
similarity index 98%
rename from services/audioflinger/MonoPipe.cpp
rename to media/libnbaio/MonoPipe.cpp
index bd876b4..c426efb 100644
--- a/services/audioflinger/MonoPipe.cpp
+++ b/media/libnbaio/MonoPipe.cpp
@@ -23,9 +23,9 @@
 #include <utils/LinearTransform.h>
 #include <utils/Log.h>
 #include <utils/Trace.h>
-#include "AudioBufferProvider.h"
-#include "MonoPipe.h"
-#include "roundup.h"
+#include <media/AudioBufferProvider.h>
+#include <media/nbaio/MonoPipe.h>
+#include <media/nbaio/roundup.h>
 
 
 namespace android {
diff --git a/services/audioflinger/MonoPipeReader.cpp b/media/libnbaio/MonoPipeReader.cpp
similarity index 98%
rename from services/audioflinger/MonoPipeReader.cpp
rename to media/libnbaio/MonoPipeReader.cpp
index 39a07de..394f6ac 100644
--- a/services/audioflinger/MonoPipeReader.cpp
+++ b/media/libnbaio/MonoPipeReader.cpp
@@ -19,7 +19,7 @@
 
 #include <cutils/compiler.h>
 #include <utils/Log.h>
-#include "MonoPipeReader.h"
+#include <media/nbaio/MonoPipeReader.h>
 
 namespace android {
 
diff --git a/services/audioflinger/NBAIO.cpp b/media/libnbaio/NBAIO.cpp
similarity index 98%
rename from services/audioflinger/NBAIO.cpp
rename to media/libnbaio/NBAIO.cpp
index 2c07ebf..00d2017 100644
--- a/services/audioflinger/NBAIO.cpp
+++ b/media/libnbaio/NBAIO.cpp
@@ -18,7 +18,7 @@
 //#define LOG_NDEBUG 0
 
 #include <utils/Log.h>
-#include "NBAIO.h"
+#include <media/nbaio/NBAIO.h>
 
 namespace android {
 
diff --git a/services/audioflinger/Pipe.cpp b/media/libnbaio/Pipe.cpp
similarity index 96%
rename from services/audioflinger/Pipe.cpp
rename to media/libnbaio/Pipe.cpp
index e5b3561..1c21f9c 100644
--- a/services/audioflinger/Pipe.cpp
+++ b/media/libnbaio/Pipe.cpp
@@ -20,8 +20,8 @@
 #include <cutils/atomic.h>
 #include <cutils/compiler.h>
 #include <utils/Log.h>
-#include "Pipe.h"
-#include "roundup.h"
+#include <media/nbaio/Pipe.h>
+#include <media/nbaio/roundup.h>
 
 namespace android {
 
diff --git a/services/audioflinger/PipeReader.cpp b/media/libnbaio/PipeReader.cpp
similarity index 98%
rename from services/audioflinger/PipeReader.cpp
rename to media/libnbaio/PipeReader.cpp
index 529d478..d786b84 100644
--- a/services/audioflinger/PipeReader.cpp
+++ b/media/libnbaio/PipeReader.cpp
@@ -19,7 +19,7 @@
 
 #include <cutils/compiler.h>
 #include <utils/Log.h>
-#include "PipeReader.h"
+#include <media/nbaio/PipeReader.h>
 
 namespace android {
 
diff --git a/services/audioflinger/SourceAudioBufferProvider.cpp b/media/libnbaio/SourceAudioBufferProvider.cpp
similarity index 98%
rename from services/audioflinger/SourceAudioBufferProvider.cpp
rename to media/libnbaio/SourceAudioBufferProvider.cpp
index 3343b53..d11a86c 100644
--- a/services/audioflinger/SourceAudioBufferProvider.cpp
+++ b/media/libnbaio/SourceAudioBufferProvider.cpp
@@ -18,7 +18,7 @@
 //#define LOG_NDEBUG 0
 
 #include <utils/Log.h>
-#include "SourceAudioBufferProvider.h"
+#include <media/nbaio/SourceAudioBufferProvider.h>
 
 namespace android {
 
diff --git a/services/audioflinger/roundup.c b/media/libnbaio/roundup.c
similarity index 96%
rename from services/audioflinger/roundup.c
rename to media/libnbaio/roundup.c
index 4f9af6a..1d552d1 100644
--- a/services/audioflinger/roundup.c
+++ b/media/libnbaio/roundup.c
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "roundup.h"
+#include <media/nbaio/roundup.h>
 
 unsigned roundup(unsigned v)
 {
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index f5c8c93..c478b28 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -52,7 +52,7 @@
         ALOGE("Invalid dimensions %dx%d", bufferWidth, bufferHeight);
     }
 
-    mBufferQueue = new BufferQueue(true, MIN_UNDEQUEUED_BUFFERS);
+    mBufferQueue = new BufferQueue(true);
     mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight);
     mBufferQueue->setSynchronousMode(true);
     mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER |
@@ -136,10 +136,32 @@
 {
     ALOGV("start");
 
+    Mutex::Autolock lock(mMutex);
+
     mStartTimeNs = 0;
     int64_t startTimeUs;
-    if (params && params->findInt64(kKeyTime, &startTimeUs)) {
-        mStartTimeNs = startTimeUs * 1000;
+    int32_t bufferCount = 0;
+    if (params) {
+        if (params->findInt64(kKeyTime, &startTimeUs)) {
+            mStartTimeNs = startTimeUs * 1000;
+        }
+
+        if (!params->findInt32(kKeyNumBuffers, &bufferCount)) {
+            ALOGE("Failed to find the advertised buffer count");
+            return UNKNOWN_ERROR;
+        }
+
+        if (bufferCount <= 1) {
+            ALOGE("bufferCount %d is too small", bufferCount);
+            return BAD_VALUE;
+        }
+    }
+
+    if (bufferCount != 0) {
+        status_t err = mBufferQueue->setMaxAcquiredBufferCount(bufferCount);
+        if (err != OK) {
+            return err;
+        }
     }
 
     return OK;
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index c2d2790..66759d1 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -13,32 +13,6 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := \
-    AudioBufferProviderSource.cpp   \
-    AudioStreamOutSink.cpp          \
-    AudioStreamInSource.cpp         \
-    NBAIO.cpp                       \
-    MonoPipe.cpp                    \
-    MonoPipeReader.cpp              \
-    Pipe.cpp                        \
-    PipeReader.cpp                  \
-    roundup.c                       \
-    SourceAudioBufferProvider.cpp
-
-# libsndfile license is incompatible; uncomment to use for local debug only
-#LOCAL_SRC_FILES += LibsndfileSink.cpp LibsndfileSource.cpp
-#LOCAL_C_INCLUDES += path/to/libsndfile/src
-#LOCAL_STATIC_LIBRARIES += libsndfile
-
-# uncomment for systrace
-# LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_AUDIO
-
-LOCAL_MODULE := libnbaio
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
 LOCAL_SRC_FILES:=               \
     AudioFlinger.cpp            \
     AudioMixer.cpp.arm          \
@@ -66,6 +40,7 @@
     libbinder \
     libmedia \
     libmedia_native \
+    libnbaio \
     libhardware \
     libhardware_legacy \
     libeffects \
@@ -74,7 +49,6 @@
 
 LOCAL_STATIC_LIBRARIES := \
     libscheduling_policy \
-    libnbaio \
     libcpustats \
     libmedia_helper
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 7126006..1a37f4f 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -76,12 +76,12 @@
 #include "FastMixer.h"
 
 // NBAIO implementations
-#include "AudioStreamOutSink.h"
-#include "MonoPipe.h"
-#include "MonoPipeReader.h"
-#include "Pipe.h"
-#include "PipeReader.h"
-#include "SourceAudioBufferProvider.h"
+#include <media/nbaio/AudioStreamOutSink.h>
+#include <media/nbaio/MonoPipe.h>
+#include <media/nbaio/MonoPipeReader.h>
+#include <media/nbaio/Pipe.h>
+#include <media/nbaio/PipeReader.h>
+#include <media/nbaio/SourceAudioBufferProvider.h>
 
 #include "SchedulingPolicyService.h"
 
@@ -6359,6 +6359,7 @@
 
 status_t AudioFlinger::RecordThread::setSyncEvent(const sp<SyncEvent>& event)
 {
+#if 0   // This branch is currently dead code, but is preserved in case it will be needed in future
     if (!isValidSyncEvent(event)) {
         return BAD_VALUE;
     }
@@ -6376,6 +6377,9 @@
         }
     }
     return ret;
+#else
+    return BAD_VALUE;
+#endif
 }
 
 void AudioFlinger::RecordThread::RecordTrack::destroy()
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 682d61d..b4aefc1 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -45,10 +45,10 @@
 #include <hardware/audio.h>
 #include <hardware/audio_policy.h>
 
-#include "AudioBufferProvider.h"
-#include "ExtendedAudioBufferProvider.h"
+#include <media/AudioBufferProvider.h>
+#include <media/ExtendedAudioBufferProvider.h>
 #include "FastMixer.h"
-#include "NBAIO.h"
+#include <media/nbaio/NBAIO.h>
 #include "AudioWatchdog.h"
 
 #include <powermanager/IPowerManager.h>
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 46deae7..6e34cd1 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -23,7 +23,7 @@
 
 #include <utils/threads.h>
 
-#include "AudioBufferProvider.h"
+#include <media/AudioBufferProvider.h>
 #include "AudioResampler.h"
 
 #include <audio_effects/effect_downmix.h>
diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h
index 1610e00..dc696d8 100644
--- a/services/audioflinger/AudioResampler.h
+++ b/services/audioflinger/AudioResampler.h
@@ -20,7 +20,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include "AudioBufferProvider.h"
+#include <media/AudioBufferProvider.h>
 
 namespace android {
 // ----------------------------------------------------------------------------
diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h
index bc69c9c..6e53f21 100644
--- a/services/audioflinger/FastMixerState.h
+++ b/services/audioflinger/FastMixerState.h
@@ -18,8 +18,8 @@
 #define ANDROID_AUDIO_FAST_MIXER_STATE_H
 
 #include <system/audio.h>
-#include "ExtendedAudioBufferProvider.h"
-#include "NBAIO.h"
+#include <media/ExtendedAudioBufferProvider.h>
+#include <media/nbaio/NBAIO.h>
 
 namespace android {
 
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index eac6163..1370c62 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -13,7 +13,9 @@
     Camera2Device.cpp \
     camera2/CameraMetadata.cpp \
     camera2/Parameters.cpp \
-    camera2/FrameProcessor.cpp
+    camera2/FrameProcessor.cpp \
+    camera2/CaptureProcessor.cpp \
+    camera2/CallbackProcessor.cpp
 
 LOCAL_SHARED_LIBRARIES:= \
     libui \
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index 4edb49f..acd290d 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -52,11 +52,9 @@
         int clientPid):
         Client(cameraService, cameraClient,
                 cameraId, cameraFacing, clientPid),
+        mSharedCameraClient(cameraClient),
         mParameters(cameraId, cameraFacing),
         mPreviewStreamId(NO_STREAM),
-        mCallbackStreamId(NO_STREAM),
-        mCallbackHeapId(0),
-        mCaptureStreamId(NO_STREAM),
         mRecordingStreamId(NO_STREAM),
         mRecordingHeapCount(kDefaultRecordingHeapCount)
 {
@@ -84,11 +82,6 @@
     ALOGV("%s: Initializing client for camera %d", __FUNCTION__, mCameraId);
     status_t res;
 
-    mFrameProcessor = new FrameProcessor(this);
-    String8 frameThreadName = String8::format("Camera2Client[%d]::FrameProcessor",
-            mCameraId);
-    mFrameProcessor->run(frameThreadName.string());
-
     res = mDevice->initialize(module);
     if (res != OK) {
         ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
@@ -107,6 +100,21 @@
         return NO_INIT;
     }
 
+    mFrameProcessor = new FrameProcessor(this);
+    String8 frameThreadName = String8::format("Camera2Client[%d]::FrameProcessor",
+            mCameraId);
+    mFrameProcessor->run(frameThreadName.string());
+
+    mCaptureProcessor = new CaptureProcessor(this);
+    String8 captureThreadName =
+            String8::format("Camera2Client[%d]::CaptureProcessor", mCameraId);
+    mCaptureProcessor->run(captureThreadName.string());
+
+    mCallbackProcessor = new CallbackProcessor(this);
+    String8 callbackThreadName =
+            String8::format("Camera2Client[%d]::CallbackProcessor", mCameraId);
+    mCallbackProcessor->run(callbackThreadName.string());
+
     if (gLogLevel >= 1) {
         ALOGD("%s: Default parameters converted from camera %d:", __FUNCTION__,
               mCameraId);
@@ -292,7 +300,8 @@
 
     result.append("  Current streams:\n");
     result.appendFormat("    Preview stream ID: %d\n", mPreviewStreamId);
-    result.appendFormat("    Capture stream ID: %d\n", mCaptureStreamId);
+    result.appendFormat("    Capture stream ID: %d\n",
+            mCaptureProcessor->getStreamId());
     result.appendFormat("    Recording stream ID: %d\n", mRecordingStreamId);
 
     result.append("  Current requests:\n");
@@ -357,20 +366,14 @@
         mPreviewStreamId = NO_STREAM;
     }
 
-    if (mCaptureStreamId != NO_STREAM) {
-        mDevice->deleteStream(mCaptureStreamId);
-        mCaptureStreamId = NO_STREAM;
-    }
+    mCaptureProcessor->deleteStream();
 
     if (mRecordingStreamId != NO_STREAM) {
         mDevice->deleteStream(mRecordingStreamId);
         mRecordingStreamId = NO_STREAM;
     }
 
-    if (mCallbackStreamId != NO_STREAM) {
-        mDevice->deleteStream(mCallbackStreamId);
-        mCallbackStreamId = NO_STREAM;
-    }
+    mCallbackProcessor->deleteStream();
 
     mDevice.clear();
     SharedParameters::Lock l(mParameters);
@@ -613,7 +616,7 @@
     bool callbacksEnabled = params.previewCallbackFlags &
         CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK;
     if (callbacksEnabled) {
-        res = updateCallbackStream(params);
+        res = mCallbackProcessor->updateStream(params);
         if (res != OK) {
             ALOGE("%s: Camera %d: Unable to update callback stream: %s (%d)",
                     __FUNCTION__, mCameraId, strerror(-res), res);
@@ -632,7 +635,7 @@
 
     if (callbacksEnabled) {
         uint8_t outputStreams[2] =
-                { mPreviewStreamId, mCallbackStreamId };
+                { mPreviewStreamId, mCallbackProcessor->getStreamId() };
         res = mPreviewRequest.update(
                 ANDROID_REQUEST_OUTPUT_STREAMS,
                 outputStreams, 2);
@@ -796,7 +799,7 @@
     bool callbacksEnabled = params.previewCallbackFlags &
         CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK;
     if (callbacksEnabled) {
-        res = updateCallbackStream(params);
+        res = mCallbackProcessor->updateStream(params);
         if (res != OK) {
             ALOGE("%s: Camera %d: Unable to update callback stream: %s (%d)",
                     __FUNCTION__, mCameraId, strerror(-res), res);
@@ -815,7 +818,8 @@
 
     if (callbacksEnabled) {
         uint8_t outputStreams[3] =
-                { mPreviewStreamId, mRecordingStreamId, mCallbackStreamId };
+                { mPreviewStreamId, mRecordingStreamId,
+                  mCallbackProcessor->getStreamId() };
         res = mRecordingRequest.update(
                 ANDROID_REQUEST_OUTPUT_STREAMS,
                 outputStreams, 3);
@@ -1028,7 +1032,7 @@
 
     ALOGV("%s: Camera %d: Starting picture capture", __FUNCTION__, mCameraId);
 
-    res = updateCaptureStream(l.mParameters);
+    res = mCaptureProcessor->updateStream(l.mParameters);
     if (res != OK) {
         ALOGE("%s: Camera %d: Can't set up still image stream: %s (%d)",
                 __FUNCTION__, mCameraId, strerror(-res), res);
@@ -1048,32 +1052,47 @@
             CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK;
     bool recordingEnabled = (l.mParameters.state == Parameters::RECORD);
 
+    int captureStreamId = mCaptureProcessor->getStreamId();
+
     int streamSwitch = (callbacksEnabled ? 0x2 : 0x0) +
             (recordingEnabled ? 0x1 : 0x0);
     switch ( streamSwitch ) {
         case 0: { // No recording, callbacks
-            uint8_t streamIds[2] = { mPreviewStreamId, mCaptureStreamId };
+            uint8_t streamIds[2] = {
+                mPreviewStreamId,
+                captureStreamId
+            };
             res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
                     streamIds, 2);
             break;
         }
         case 1: { // Recording
-            uint8_t streamIds[3] = { mPreviewStreamId, mRecordingStreamId,
-                                     mCaptureStreamId };
+            uint8_t streamIds[3] = {
+                mPreviewStreamId,
+                mRecordingStreamId,
+                captureStreamId
+            };
             res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
                     streamIds, 3);
             break;
         }
         case 2: { // Callbacks
-            uint8_t streamIds[3] = { mPreviewStreamId, mCallbackStreamId,
-                                     mCaptureStreamId };
+            uint8_t streamIds[3] = {
+                mPreviewStreamId,
+                mCallbackProcessor->getStreamId(),
+                captureStreamId
+            };
             res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
                     streamIds, 3);
             break;
         }
         case 3: { // Both
-            uint8_t streamIds[4] = { mPreviewStreamId, mCallbackStreamId,
-                                     mRecordingStreamId, mCaptureStreamId };
+            uint8_t streamIds[4] = {
+                mPreviewStreamId,
+                mCallbackProcessor->getStreamId(),
+                mRecordingStreamId,
+                captureStreamId
+            };
             res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
                     streamIds, 4);
             break;
@@ -1511,6 +1530,10 @@
     mSharedClient.mCameraClientLock.unlock();
 }
 
+Camera2Client::SharedCameraClient::SharedCameraClient(const sp<ICameraClient>&client):
+        mCameraClient(client) {
+}
+
 Camera2Client::SharedCameraClient& Camera2Client::SharedCameraClient::operator=(
         const sp<ICameraClient>&client) {
     Mutex::Autolock l(mCameraClientLock);
@@ -1523,198 +1546,6 @@
     mCameraClient.clear();
 }
 
-void Camera2Client::onCallbackAvailable() {
-    ATRACE_CALL();
-    status_t res;
-    ALOGV("%s: Camera %d: Preview callback available", __FUNCTION__, mCameraId);
-
-    int callbackHeapId;
-    sp<Camera2Heap> callbackHeap;
-    size_t heapIdx;
-
-    CpuConsumer::LockedBuffer imgBuffer;
-    ALOGV("%s: Getting buffer", __FUNCTION__);
-    res = mCallbackConsumer->lockNextBuffer(&imgBuffer);
-    if (res != OK) {
-        ALOGE("%s: Camera %d: Error receiving next callback buffer: "
-                "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
-        return;
-    }
-
-    {
-        SharedParameters::Lock l(mParameters);
-
-        if ( l.mParameters.state != Parameters::PREVIEW
-                && l.mParameters.state != Parameters::RECORD
-                && l.mParameters.state != Parameters::VIDEO_SNAPSHOT) {
-            ALOGV("%s: Camera %d: No longer streaming",
-                    __FUNCTION__, mCameraId);
-            mCallbackConsumer->unlockBuffer(imgBuffer);
-            return;
-        }
-
-        if (! (l.mParameters.previewCallbackFlags &
-                CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) ) {
-            ALOGV("%s: No longer enabled, dropping", __FUNCTION__);
-            mCallbackConsumer->unlockBuffer(imgBuffer);
-            return;
-        }
-        if ((l.mParameters.previewCallbackFlags &
-                        CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) &&
-                !l.mParameters.previewCallbackOneShot) {
-            ALOGV("%s: One shot mode, already sent, dropping", __FUNCTION__);
-            mCallbackConsumer->unlockBuffer(imgBuffer);
-            return;
-        }
-
-        if (imgBuffer.format != l.mParameters.previewFormat) {
-            ALOGE("%s: Camera %d: Unexpected format for callback: "
-                    "%x, expected %x", __FUNCTION__, mCameraId,
-                    imgBuffer.format, l.mParameters.previewFormat);
-            mCallbackConsumer->unlockBuffer(imgBuffer);
-            return;
-        }
-
-        size_t bufferSize = calculateBufferSize(imgBuffer.width, imgBuffer.height,
-                imgBuffer.format, imgBuffer.stride);
-        size_t currentBufferSize = (mCallbackHeap == 0) ?
-                0 : (mCallbackHeap->mHeap->getSize() / kCallbackHeapCount);
-        if (bufferSize != currentBufferSize) {
-            mCallbackHeap.clear();
-            mCallbackHeap = new Camera2Heap(bufferSize, kCallbackHeapCount,
-                    "Camera2Client::CallbackHeap");
-            if (mCallbackHeap->mHeap->getSize() == 0) {
-                ALOGE("%s: Camera %d: Unable to allocate memory for callbacks",
-                        __FUNCTION__, mCameraId);
-                mCallbackConsumer->unlockBuffer(imgBuffer);
-                return;
-            }
-
-            mCallbackHeapHead = 0;
-            mCallbackHeapFree = kCallbackHeapCount;
-            mCallbackHeapId++;
-        }
-
-        if (mCallbackHeapFree == 0) {
-            ALOGE("%s: Camera %d: No free callback buffers, dropping frame",
-                    __FUNCTION__, mCameraId);
-            mCallbackConsumer->unlockBuffer(imgBuffer);
-            return;
-        }
-        heapIdx = mCallbackHeapHead;
-        callbackHeap = mCallbackHeap;
-        callbackHeapId = mCallbackHeapId;
-
-        mCallbackHeapHead = (mCallbackHeapHead + 1) & kCallbackHeapCount;
-        mCallbackHeapFree--;
-
-        // TODO: Get rid of this memcpy by passing the gralloc queue all the way
-        // to app
-
-        ssize_t offset;
-        size_t size;
-        sp<IMemoryHeap> heap =
-            mCallbackHeap->mBuffers[heapIdx]->getMemory(&offset,
-                    &size);
-        uint8_t *data = (uint8_t*)heap->getBase() + offset;
-        memcpy(data, imgBuffer.data, bufferSize);
-
-        ALOGV("%s: Freeing buffer", __FUNCTION__);
-        mCallbackConsumer->unlockBuffer(imgBuffer);
-
-        // In one-shot mode, stop sending callbacks after the first one
-        if (l.mParameters.previewCallbackFlags &
-                CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) {
-            ALOGV("%s: clearing oneshot", __FUNCTION__);
-            l.mParameters.previewCallbackOneShot = false;
-        }
-    }
-
-    // Call outside parameter lock to allow re-entrancy from notification
-    {
-        SharedCameraClient::Lock l(mSharedCameraClient);
-        if (l.mCameraClient != 0) {
-            ALOGV("%s: Camera %d: Invoking client data callback",
-                    __FUNCTION__, mCameraId);
-            l.mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME,
-                    callbackHeap->mBuffers[heapIdx], NULL);
-        }
-    }
-
-    SharedParameters::Lock l(mParameters);
-    // Only increment free if we're still using the same heap
-    if (mCallbackHeapId == callbackHeapId) {
-        mCallbackHeapFree++;
-    }
-
-    ALOGV("%s: exit", __FUNCTION__);
-}
-
-void Camera2Client::onCaptureAvailable() {
-    ATRACE_CALL();
-    status_t res;
-    sp<Camera2Heap> captureHeap;
-    ALOGV("%s: Camera %d: Still capture available", __FUNCTION__, mCameraId);
-
-    {
-        SharedParameters::Lock l(mParameters);
-        CpuConsumer::LockedBuffer imgBuffer;
-
-        res = mCaptureConsumer->lockNextBuffer(&imgBuffer);
-        if (res != OK) {
-            ALOGE("%s: Camera %d: Error receiving still image buffer: %s (%d)",
-                    __FUNCTION__, mCameraId, strerror(-res), res);
-            return;
-        }
-
-        // TODO: Signal errors here upstream
-        if (l.mParameters.state != Parameters::STILL_CAPTURE &&
-                l.mParameters.state != Parameters::VIDEO_SNAPSHOT) {
-            ALOGE("%s: Camera %d: Still image produced unexpectedly!",
-                    __FUNCTION__, mCameraId);
-            mCaptureConsumer->unlockBuffer(imgBuffer);
-            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->mHeap->getBase();
-        size_t size = mCaptureHeap->mHeap->getSize();
-        memcpy(captureMemory, imgBuffer.data, size);
-
-        mCaptureConsumer->unlockBuffer(imgBuffer);
-
-        switch (l.mParameters.state) {
-            case Parameters::STILL_CAPTURE:
-                l.mParameters.state = Parameters::STOPPED;
-                break;
-            case Parameters::VIDEO_SNAPSHOT:
-                l.mParameters.state = Parameters::RECORD;
-                break;
-            default:
-                ALOGE("%s: Camera %d: Unexpected state %d", __FUNCTION__,
-                        mCameraId, l.mParameters.state);
-                break;
-        }
-
-        captureHeap = mCaptureHeap;
-    }
-    // Call outside parameter locks to allow re-entrancy from notification
-    SharedCameraClient::Lock l(mSharedCameraClient);
-    if (l.mCameraClient != 0) {
-        l.mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE,
-                captureHeap->mBuffers[0], NULL);
-    }
-}
-
 void Camera2Client::onRecordingFrameAvailable() {
     ATRACE_CALL();
     status_t res;
@@ -1941,132 +1772,6 @@
     return OK;
 }
 
-status_t Camera2Client::updateCallbackStream(const Parameters &params) {
-    status_t res;
-
-    if (mCallbackConsumer == 0) {
-        // Create CPU buffer queue endpoint
-        mCallbackConsumer = new CpuConsumer(kCallbackHeapCount);
-        mCallbackWaiter = new CallbackWaiter(this);
-        mCallbackConsumer->setFrameAvailableListener(mCallbackWaiter);
-        mCallbackConsumer->setName(String8("Camera2Client::CallbackConsumer"));
-        mCallbackWindow = new SurfaceTextureClient(
-            mCallbackConsumer->getProducerInterface());
-    }
-
-    if (mCallbackStreamId != NO_STREAM) {
-        // Check if stream parameters have to change
-        uint32_t currentWidth, currentHeight, currentFormat;
-        res = mDevice->getStreamInfo(mCallbackStreamId,
-                &currentWidth, &currentHeight, &currentFormat);
-        if (res != OK) {
-            ALOGE("%s: Camera %d: Error querying callback output stream info: "
-                    "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
-            return res;
-        }
-        if (currentWidth != (uint32_t)params.previewWidth ||
-                currentHeight != (uint32_t)params.previewHeight ||
-                currentFormat != (uint32_t)params.previewFormat) {
-            // Since size should only change while preview is not running,
-            // assuming that all existing use of old callback stream is
-            // completed.
-            res = mDevice->deleteStream(mCallbackStreamId);
-            if (res != OK) {
-                ALOGE("%s: Camera %d: Unable to delete old output stream "
-                        "for callbacks: %s (%d)", __FUNCTION__, mCameraId,
-                        strerror(-res), res);
-                return res;
-            }
-            mCallbackStreamId = NO_STREAM;
-        }
-    }
-
-    if (mCallbackStreamId == NO_STREAM) {
-        ALOGV("Creating callback stream: %d %d format 0x%x",
-                params.previewWidth, params.previewHeight,
-                params.previewFormat);
-        res = mDevice->createStream(mCallbackWindow,
-                params.previewWidth, params.previewHeight,
-                params.previewFormat, 0, &mCallbackStreamId);
-        if (res != OK) {
-            ALOGE("%s: Camera %d: Can't create output stream for callbacks: "
-                    "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
-            return res;
-        }
-    }
-
-    return OK;
-}
-
-
-status_t Camera2Client::updateCaptureStream(const Parameters &params) {
-    ATRACE_CALL();
-    status_t res;
-    // Find out buffer size for JPEG
-    camera_metadata_ro_entry_t maxJpegSize =
-            mParameters.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 Camera2Heap(maxJpegSize.data.i32[0], 1,
-                                       "Camera2Client::CaptureHeap");
-        if (mCaptureHeap->mHeap->getSize() == 0) {
-            ALOGE("%s: Camera %d: Unable to allocate memory for capture",
-                    __FUNCTION__, mCameraId);
-            return NO_MEMORY;
-        }
-    }
-
-    if (mCaptureStreamId != NO_STREAM) {
-        // Check if stream parameters have to change
-        uint32_t currentWidth, currentHeight;
-        res = mDevice->getStreamInfo(mCaptureStreamId,
-                &currentWidth, &currentHeight, 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)params.pictureWidth ||
-                currentHeight != (uint32_t)params.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,
-                params.pictureWidth, params.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(const Parameters &params) {
     ATRACE_CALL();
     status_t res;
diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h
index 3195f94..b2fd636 100644
--- a/services/camera/libcameraservice/Camera2Client.h
+++ b/services/camera/libcameraservice/Camera2Client.h
@@ -21,6 +21,8 @@
 #include "CameraService.h"
 #include "camera2/Parameters.h"
 #include "camera2/FrameProcessor.h"
+#include "camera2/CaptureProcessor.h"
+#include "camera2/CallbackProcessor.h"
 #include <binder/MemoryBase.h>
 #include <binder/MemoryHeapBase.h>
 #include <gui/CpuConsumer.h>
@@ -37,7 +39,9 @@
         public Camera2Device::NotificationListener
 {
 public:
-    // ICamera interface (see ICamera for details)
+    /**
+     * ICamera interface (see ICamera for details)
+     */
 
     virtual void            disconnect();
     virtual status_t        connect(const sp<ICameraClient>& client);
@@ -62,7 +66,9 @@
     virtual String8         getParameters() const;
     virtual status_t        sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
 
-    // Interface used by CameraService
+    /**
+     * Interface used by CameraService
+     */
 
     Camera2Client(const sp<CameraService>& cameraService,
             const sp<ICameraClient>& cameraClient,
@@ -75,7 +81,9 @@
 
     virtual status_t dump(int fd, const Vector<String16>& args);
 
-    // Interface used by CameraDevice
+    /**
+     * Interface used by Camera2Device
+     */
 
     virtual void notifyError(int errorCode, int arg1, int arg2);
     virtual void notifyShutter(int frameNumber, nsecs_t timestamp);
@@ -83,7 +91,9 @@
     virtual void notifyAutoExposure(uint8_t newState, int triggerId);
     virtual void notifyAutoWhitebalance(uint8_t newState, int triggerId);
 
-    // Interface used by independent components of Camera2Client.
+    /**
+     * Interface used by independent components of Camera2Client.
+     */
 
     int getCameraId();
     const sp<Camera2Device>& getCameraDevice();
@@ -102,6 +112,7 @@
           private:
             SharedCameraClient &mSharedClient;
         };
+        SharedCameraClient(const sp<ICameraClient>& client);
         SharedCameraClient& operator=(const sp<ICameraClient>& client);
         void clear();
       private:
@@ -109,6 +120,9 @@
         mutable Mutex mCameraClientLock;
     } mSharedCameraClient;
 
+    static size_t calculateBufferSize(int width, int height,
+            int format, int stride);
+
 private:
     /** ICamera interface-related private members */
 
@@ -145,8 +159,6 @@
 
     /** Camera device-related private members */
 
-    class Camera2Heap;
-
     void     setPreviewCallbackFlagL(Parameters &params, int flag);
     status_t updateRequests(const Parameters &params);
 
@@ -167,50 +179,13 @@
 
     /** Preview callback related members */
 
-    int mCallbackStreamId;
-    static const size_t kCallbackHeapCount = 6;
-    sp<CpuConsumer>    mCallbackConsumer;
-    sp<ANativeWindow>  mCallbackWindow;
-    // Simple listener that forwards frame available notifications from
-    // a CPU consumer to the callback notification
-    class CallbackWaiter: public CpuConsumer::FrameAvailableListener {
-      public:
-        CallbackWaiter(Camera2Client *parent) : mParent(parent) {}
-        void onFrameAvailable() { mParent->onCallbackAvailable(); }
-      private:
-        Camera2Client *mParent;
-    };
-    sp<CallbackWaiter>  mCallbackWaiter;
-    sp<Camera2Heap>     mCallbackHeap;
-    int mCallbackHeapId;
-    size_t mCallbackHeapHead, mCallbackHeapFree;
-    // Handle callback image buffers
-    void onCallbackAvailable();
-
-    status_t updateCallbackStream(const Parameters &params);
+    sp<camera2::CallbackProcessor> mCallbackProcessor;
 
     /* Still image capture related members */
 
-    int mCaptureStreamId;
-    sp<CpuConsumer>    mCaptureConsumer;
-    sp<ANativeWindow>  mCaptureWindow;
-    // 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;
-    };
-    sp<CaptureWaiter>  mCaptureWaiter;
+    sp<camera2::CaptureProcessor> mCaptureProcessor;
     CameraMetadata mCaptureRequest;
-    sp<Camera2Heap>    mCaptureHeap;
-    // Handle captured image buffers
-    void onCaptureAvailable();
-
     status_t updateCaptureRequest(const Parameters &params);
-    status_t updateCaptureStream(const Parameters &params);
 
     /* Recording related members */
 
@@ -229,7 +204,7 @@
     };
     sp<RecordingWaiter>  mRecordingWaiter;
     CameraMetadata mRecordingRequest;
-    sp<Camera2Heap> mRecordingHeap;
+    sp<camera2::Camera2Heap> mRecordingHeap;
 
     static const size_t kDefaultRecordingHeapCount = 8;
     size_t mRecordingHeapCount;
@@ -254,32 +229,6 @@
     // Verify that caller is the owner of the camera
     status_t checkPid(const char *checkLocation) const;
 
-    // Utility class for managing a set of IMemory blocks
-    class Camera2Heap : public RefBase {
-    public:
-        Camera2Heap(size_t buf_size, uint_t num_buffers = 1,
-                const char *name = NULL) :
-                         mBufSize(buf_size),
-                         mNumBufs(num_buffers) {
-            mHeap = new MemoryHeapBase(buf_size * num_buffers, 0, name);
-            mBuffers = new sp<MemoryBase>[mNumBufs];
-            for (uint_t i = 0; i < mNumBufs; i++)
-                mBuffers[i] = new MemoryBase(mHeap,
-                                             i * mBufSize,
-                                             mBufSize);
-        }
-
-        virtual ~Camera2Heap()
-        {
-            delete [] mBuffers;
-        }
-
-        size_t mBufSize;
-        uint_t mNumBufs;
-        sp<MemoryHeapBase> mHeap;
-        sp<MemoryBase> *mBuffers;
-    };
-
     // Update parameters all requests use, based on mParameters
     status_t updateRequestCommon(CameraMetadata *request, const Parameters &params) const;
 
@@ -291,9 +240,6 @@
     int arrayXToNormalized(int width) const;
     int arrayYToNormalized(int height) const;
 
-
-    static size_t calculateBufferSize(int width, int height,
-            int format, int stride);
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/camera2/CallbackProcessor.cpp b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
new file mode 100644
index 0000000..854b890
--- /dev/null
+++ b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
@@ -0,0 +1,293 @@
+/*
+ * 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::CallbackProcessor"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include "CallbackProcessor.h"
+#include <gui/SurfaceTextureClient.h>
+#include "../Camera2Device.h"
+#include "../Camera2Client.h"
+
+
+namespace android {
+namespace camera2 {
+
+CallbackProcessor::CallbackProcessor(wp<Camera2Client> client):
+        Thread(false),
+        mClient(client),
+        mCallbackAvailable(false),
+        mCallbackStreamId(NO_STREAM) {
+}
+
+CallbackProcessor::~CallbackProcessor() {
+    ALOGV("%s: Exit", __FUNCTION__);
+}
+
+void CallbackProcessor::onFrameAvailable() {
+    Mutex::Autolock l(mInputMutex);
+    if (!mCallbackAvailable) {
+        mCallbackAvailable = true;
+        mCallbackAvailableSignal.signal();
+    }
+}
+
+status_t CallbackProcessor::updateStream(const Parameters &params) {
+    ATRACE_CALL();
+    status_t res;
+
+    Mutex::Autolock l(mInputMutex);
+
+    sp<Camera2Client> client = mClient.promote();
+    if (client == 0) return OK;
+    sp<Camera2Device> device = client->getCameraDevice();
+
+    if (mCallbackConsumer == 0) {
+        // Create CPU buffer queue endpoint
+        mCallbackConsumer = new CpuConsumer(kCallbackHeapCount);
+        mCallbackConsumer->setFrameAvailableListener(this);
+        mCallbackConsumer->setName(String8("Camera2Client::CallbackConsumer"));
+        mCallbackWindow = new SurfaceTextureClient(
+            mCallbackConsumer->getProducerInterface());
+    }
+
+    if (mCallbackStreamId != NO_STREAM) {
+        // Check if stream parameters have to change
+        uint32_t currentWidth, currentHeight, currentFormat;
+        res = device->getStreamInfo(mCallbackStreamId,
+                &currentWidth, &currentHeight, &currentFormat);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Error querying callback output stream info: "
+                    "%s (%d)", __FUNCTION__, client->getCameraId(),
+                    strerror(-res), res);
+            return res;
+        }
+        if (currentWidth != (uint32_t)params.previewWidth ||
+                currentHeight != (uint32_t)params.previewHeight ||
+                currentFormat != (uint32_t)params.previewFormat) {
+            // Since size should only change while preview is not running,
+            // assuming that all existing use of old callback stream is
+            // completed.
+            res = device->deleteStream(mCallbackStreamId);
+            if (res != OK) {
+                ALOGE("%s: Camera %d: Unable to delete old output stream "
+                        "for callbacks: %s (%d)", __FUNCTION__, client->getCameraId(),
+                        strerror(-res), res);
+                return res;
+            }
+            mCallbackStreamId = NO_STREAM;
+        }
+    }
+
+    if (mCallbackStreamId == NO_STREAM) {
+        ALOGV("Creating callback stream: %d %d format 0x%x",
+                params.previewWidth, params.previewHeight,
+                params.previewFormat);
+        res = device->createStream(mCallbackWindow,
+                params.previewWidth, params.previewHeight,
+                params.previewFormat, 0, &mCallbackStreamId);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Can't create output stream for callbacks: "
+                    "%s (%d)", __FUNCTION__, client->getCameraId(),
+                    strerror(-res), res);
+            return res;
+        }
+    }
+
+    return OK;
+}
+
+status_t CallbackProcessor::deleteStream() {
+    ATRACE_CALL();
+    status_t res;
+
+    Mutex::Autolock l(mInputMutex);
+
+    if (mCallbackStreamId != NO_STREAM) {
+        sp<Camera2Client> client = mClient.promote();
+        if (client == 0) return OK;
+        sp<Camera2Device> device = client->getCameraDevice();
+
+        device->deleteStream(mCallbackStreamId);
+        mCallbackStreamId = NO_STREAM;
+    }
+    return OK;
+}
+
+int CallbackProcessor::getStreamId() const {
+    Mutex::Autolock l(mInputMutex);
+    return mCallbackStreamId;
+}
+
+void CallbackProcessor::dump(int fd, const Vector<String16>& args) {
+}
+
+bool CallbackProcessor::threadLoop() {
+    status_t res;
+
+    {
+        Mutex::Autolock l(mInputMutex);
+        while (!mCallbackAvailable) {
+            res = mCallbackAvailableSignal.waitRelative(mInputMutex,
+                    kWaitDuration);
+            if (res == TIMED_OUT) return true;
+        }
+        mCallbackAvailable = false;
+    }
+
+    do {
+        sp<Camera2Client> client = mClient.promote();
+        if (client == 0) return false;
+        res = processNewCallback(client);
+    } while (res == OK);
+
+    return true;
+}
+
+status_t CallbackProcessor::processNewCallback(sp<Camera2Client> &client) {
+    ATRACE_CALL();
+    status_t res;
+
+    int callbackHeapId;
+    sp<Camera2Heap> callbackHeap;
+    size_t heapIdx;
+
+    CpuConsumer::LockedBuffer imgBuffer;
+    ALOGV("%s: Getting buffer", __FUNCTION__);
+    res = mCallbackConsumer->lockNextBuffer(&imgBuffer);
+    if (res != OK) {
+        if (res != BAD_VALUE) {
+            ALOGE("%s: Camera %d: Error receiving next callback buffer: "
+                    "%s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res);
+        }
+        return res;
+    }
+    ALOGV("%s: Camera %d: Preview callback available", __FUNCTION__,
+            client->getCameraId());
+
+    {
+        SharedParameters::Lock l(client->getParameters());
+
+        if ( l.mParameters.state != Parameters::PREVIEW
+                && l.mParameters.state != Parameters::RECORD
+                && l.mParameters.state != Parameters::VIDEO_SNAPSHOT) {
+            ALOGV("%s: Camera %d: No longer streaming",
+                    __FUNCTION__, client->getCameraId());
+            mCallbackConsumer->unlockBuffer(imgBuffer);
+            return OK;
+        }
+
+        if (! (l.mParameters.previewCallbackFlags &
+                CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) ) {
+            ALOGV("%s: No longer enabled, dropping", __FUNCTION__);
+            mCallbackConsumer->unlockBuffer(imgBuffer);
+            return OK;
+        }
+        if ((l.mParameters.previewCallbackFlags &
+                        CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) &&
+                !l.mParameters.previewCallbackOneShot) {
+            ALOGV("%s: One shot mode, already sent, dropping", __FUNCTION__);
+            mCallbackConsumer->unlockBuffer(imgBuffer);
+            return OK;
+        }
+
+        if (imgBuffer.format != l.mParameters.previewFormat) {
+            ALOGE("%s: Camera %d: Unexpected format for callback: "
+                    "%x, expected %x", __FUNCTION__, client->getCameraId(),
+                    imgBuffer.format, l.mParameters.previewFormat);
+            mCallbackConsumer->unlockBuffer(imgBuffer);
+            return INVALID_OPERATION;
+        }
+
+        // In one-shot mode, stop sending callbacks after the first one
+        if (l.mParameters.previewCallbackFlags &
+                CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) {
+            ALOGV("%s: clearing oneshot", __FUNCTION__);
+            l.mParameters.previewCallbackOneShot = false;
+        }
+    }
+
+    size_t bufferSize = Camera2Client::calculateBufferSize(
+            imgBuffer.width, imgBuffer.height,
+            imgBuffer.format, imgBuffer.stride);
+    size_t currentBufferSize = (mCallbackHeap == 0) ?
+            0 : (mCallbackHeap->mHeap->getSize() / kCallbackHeapCount);
+    if (bufferSize != currentBufferSize) {
+        mCallbackHeap.clear();
+        mCallbackHeap = new Camera2Heap(bufferSize, kCallbackHeapCount,
+                "Camera2Client::CallbackHeap");
+        if (mCallbackHeap->mHeap->getSize() == 0) {
+            ALOGE("%s: Camera %d: Unable to allocate memory for callbacks",
+                    __FUNCTION__, client->getCameraId());
+            mCallbackConsumer->unlockBuffer(imgBuffer);
+            return INVALID_OPERATION;
+        }
+
+        mCallbackHeapHead = 0;
+        mCallbackHeapFree = kCallbackHeapCount;
+    }
+
+    if (mCallbackHeapFree == 0) {
+        ALOGE("%s: Camera %d: No free callback buffers, dropping frame",
+                __FUNCTION__, client->getCameraId());
+        mCallbackConsumer->unlockBuffer(imgBuffer);
+        return OK;
+    }
+
+    heapIdx = mCallbackHeapHead;
+
+    mCallbackHeapHead = (mCallbackHeapHead + 1) & kCallbackHeapCount;
+    mCallbackHeapFree--;
+
+    // TODO: Get rid of this memcpy by passing the gralloc queue all the way
+    // to app
+
+    ssize_t offset;
+    size_t size;
+    sp<IMemoryHeap> heap =
+            mCallbackHeap->mBuffers[heapIdx]->getMemory(&offset,
+                    &size);
+    uint8_t *data = (uint8_t*)heap->getBase() + offset;
+    memcpy(data, imgBuffer.data, bufferSize);
+
+    ALOGV("%s: Freeing buffer", __FUNCTION__);
+    mCallbackConsumer->unlockBuffer(imgBuffer);
+
+    // Call outside parameter lock to allow re-entrancy from notification
+    {
+        Camera2Client::SharedCameraClient::Lock l(client->mSharedCameraClient);
+        if (l.mCameraClient != 0) {
+            ALOGV("%s: Camera %d: Invoking client data callback",
+                    __FUNCTION__, client->getCameraId());
+            l.mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME,
+                    mCallbackHeap->mBuffers[heapIdx], NULL);
+        }
+    }
+
+    // Only increment free if we're still using the same heap
+    mCallbackHeapFree++;
+
+    ALOGV("%s: exit", __FUNCTION__);
+
+    return OK;
+}
+
+}; // namespace camera2
+}; // namespace android
diff --git a/services/camera/libcameraservice/camera2/CallbackProcessor.h b/services/camera/libcameraservice/camera2/CallbackProcessor.h
new file mode 100644
index 0000000..36c51a3
--- /dev/null
+++ b/services/camera/libcameraservice/camera2/CallbackProcessor.h
@@ -0,0 +1,82 @@
+/*
+ * 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_CAMERA2_CALLBACKPROCESSOR_H
+#define ANDROID_SERVERS_CAMERA_CAMERA2_CALLBACKPROCESSOR_H
+
+#include <utils/Thread.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+#include <utils/Mutex.h>
+#include <utils/Condition.h>
+#include <gui/CpuConsumer.h>
+#include "Parameters.h"
+#include "CameraMetadata.h"
+#include "Camera2Heap.h"
+
+namespace android {
+
+class Camera2Client;
+
+namespace camera2 {
+
+/***
+ * Still image capture output image processing
+ */
+class CallbackProcessor:
+            public Thread, public CpuConsumer::FrameAvailableListener {
+  public:
+    CallbackProcessor(wp<Camera2Client> client);
+    ~CallbackProcessor();
+
+    void onFrameAvailable();
+
+    status_t updateStream(const Parameters &params);
+    status_t deleteStream();
+    int getStreamId() const;
+
+    void dump(int fd, const Vector<String16>& args);
+  private:
+    static const nsecs_t kWaitDuration = 10000000; // 10 ms
+    wp<Camera2Client> mClient;
+
+    mutable Mutex mInputMutex;
+    bool mCallbackAvailable;
+    Condition mCallbackAvailableSignal;
+
+    enum {
+        NO_STREAM = -1
+    };
+
+    int mCallbackStreamId;
+    static const size_t kCallbackHeapCount = 6;
+    sp<CpuConsumer>    mCallbackConsumer;
+    sp<ANativeWindow>  mCallbackWindow;
+    sp<Camera2Heap>    mCallbackHeap;
+    int mCallbackHeapId;
+    size_t mCallbackHeapHead, mCallbackHeapFree;
+
+    virtual bool threadLoop();
+
+    status_t processNewCallback(sp<Camera2Client> &client);
+
+};
+
+
+}; //namespace camera2
+}; //namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/camera2/Camera2Heap.h b/services/camera/libcameraservice/camera2/Camera2Heap.h
new file mode 100644
index 0000000..9c72d76
--- /dev/null
+++ b/services/camera/libcameraservice/camera2/Camera2Heap.h
@@ -0,0 +1,55 @@
+/*
+ * 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_CAMERA2HEAP_H
+#define ANDROiD_SERVERS_CAMERA_CAMERA2HEAP_H
+
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
+
+namespace android {
+namespace camera2 {
+
+// Utility class for managing a set of IMemory blocks
+class Camera2Heap : public RefBase {
+  public:
+    Camera2Heap(size_t buf_size, uint_t num_buffers = 1,
+            const char *name = NULL) :
+            mBufSize(buf_size),
+            mNumBufs(num_buffers) {
+        mHeap = new MemoryHeapBase(buf_size * num_buffers, 0, name);
+        mBuffers = new sp<MemoryBase>[mNumBufs];
+        for (uint_t i = 0; i < mNumBufs; i++)
+            mBuffers[i] = new MemoryBase(mHeap,
+                    i * mBufSize,
+                    mBufSize);
+    }
+
+    virtual ~Camera2Heap()
+    {
+        delete [] mBuffers;
+    }
+
+    size_t mBufSize;
+    uint_t mNumBufs;
+    sp<MemoryHeapBase> mHeap;
+    sp<MemoryBase> *mBuffers;
+};
+
+}; // namespace camera2
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/camera2/CaptureProcessor.cpp b/services/camera/libcameraservice/camera2/CaptureProcessor.cpp
new file mode 100644
index 0000000..b17f9d2
--- /dev/null
+++ b/services/camera/libcameraservice/camera2/CaptureProcessor.cpp
@@ -0,0 +1,248 @@
+/*
+ * 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::CaptureProcessor"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include "CaptureProcessor.h"
+#include <gui/SurfaceTextureClient.h>
+#include "../Camera2Device.h"
+#include "../Camera2Client.h"
+
+
+namespace android {
+namespace camera2 {
+
+CaptureProcessor::CaptureProcessor(wp<Camera2Client> client):
+        Thread(false),
+        mClient(client),
+        mCaptureAvailable(false),
+        mCaptureStreamId(NO_STREAM) {
+}
+
+CaptureProcessor::~CaptureProcessor() {
+    ALOGV("%s: Exit", __FUNCTION__);
+}
+
+void CaptureProcessor::onFrameAvailable() {
+    Mutex::Autolock l(mInputMutex);
+    if (!mCaptureAvailable) {
+        mCaptureAvailable = true;
+        mCaptureAvailableSignal.signal();
+    }
+}
+
+status_t CaptureProcessor::updateStream(const Parameters &params) {
+    ATRACE_CALL();
+    ALOGV("%s", __FUNCTION__);
+    status_t res;
+
+    Mutex::Autolock l(mInputMutex);
+
+    sp<Camera2Client> client = mClient.promote();
+    if (client == 0) return OK;
+    sp<Camera2Device> device = client->getCameraDevice();
+
+    // Find out buffer size for JPEG
+    camera_metadata_ro_entry_t maxJpegSize =
+            params.staticInfo(ANDROID_JPEG_MAX_SIZE);
+    if (maxJpegSize.count == 0) {
+        ALOGE("%s: Camera %d: Can't find ANDROID_JPEG_MAX_SIZE!",
+                __FUNCTION__, client->getCameraId());
+        return INVALID_OPERATION;
+    }
+
+    if (mCaptureConsumer == 0) {
+        // Create CPU buffer queue endpoint
+        mCaptureConsumer = new CpuConsumer(1);
+        mCaptureConsumer->setFrameAvailableListener(this);
+        mCaptureConsumer->setName(String8("Camera2Client::CaptureConsumer"));
+        mCaptureWindow = new SurfaceTextureClient(
+            mCaptureConsumer->getProducerInterface());
+        // Create memory for API consumption
+        mCaptureHeap = new Camera2Heap(maxJpegSize.data.i32[0], 1,
+                                       "Camera2Client::CaptureHeap");
+        if (mCaptureHeap->mHeap->getSize() == 0) {
+            ALOGE("%s: Camera %d: Unable to allocate memory for capture",
+                    __FUNCTION__, client->getCameraId());
+            return NO_MEMORY;
+        }
+    }
+
+    if (mCaptureStreamId != NO_STREAM) {
+        // Check if stream parameters have to change
+        uint32_t currentWidth, currentHeight;
+        res = device->getStreamInfo(mCaptureStreamId,
+                &currentWidth, &currentHeight, 0);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Error querying capture output stream info: "
+                    "%s (%d)", __FUNCTION__,
+                    client->getCameraId(), strerror(-res), res);
+            return res;
+        }
+        if (currentWidth != (uint32_t)params.pictureWidth ||
+                currentHeight != (uint32_t)params.pictureHeight) {
+            res = device->deleteStream(mCaptureStreamId);
+            if (res != OK) {
+                ALOGE("%s: Camera %d: Unable to delete old output stream "
+                        "for capture: %s (%d)", __FUNCTION__,
+                        client->getCameraId(), strerror(-res), res);
+                return res;
+            }
+            mCaptureStreamId = NO_STREAM;
+        }
+    }
+
+    if (mCaptureStreamId == NO_STREAM) {
+        // Create stream for HAL production
+        res = device->createStream(mCaptureWindow,
+                params.pictureWidth, params.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__, client->getCameraId(),
+                    strerror(-res), res);
+            return res;
+        }
+
+    }
+    return OK;
+}
+
+status_t CaptureProcessor::deleteStream() {
+    ATRACE_CALL();
+    status_t res;
+
+    Mutex::Autolock l(mInputMutex);
+
+    if (mCaptureStreamId != NO_STREAM) {
+        sp<Camera2Client> client = mClient.promote();
+        if (client == 0) return OK;
+        sp<Camera2Device> device = client->getCameraDevice();
+
+        device->deleteStream(mCaptureStreamId);
+        mCaptureStreamId = NO_STREAM;
+    }
+    return OK;
+}
+
+int CaptureProcessor::getStreamId() const {
+    Mutex::Autolock l(mInputMutex);
+    return mCaptureStreamId;
+}
+
+void CaptureProcessor::dump(int fd, const Vector<String16>& args) {
+}
+
+bool CaptureProcessor::threadLoop() {
+    status_t res;
+
+    {
+        Mutex::Autolock l(mInputMutex);
+        while (!mCaptureAvailable) {
+            res = mCaptureAvailableSignal.waitRelative(mInputMutex,
+                    kWaitDuration);
+            if (res == TIMED_OUT) return true;
+        }
+        mCaptureAvailable = false;
+    }
+
+    do {
+        sp<Camera2Client> client = mClient.promote();
+        if (client == 0) return false;
+        res = processNewCapture(client);
+    } while (res == OK);
+
+    return true;
+}
+
+status_t CaptureProcessor::processNewCapture(sp<Camera2Client> &client) {
+    ATRACE_CALL();
+    status_t res;
+    sp<Camera2Heap> captureHeap;
+
+    CpuConsumer::LockedBuffer imgBuffer;
+
+    res = mCaptureConsumer->lockNextBuffer(&imgBuffer);
+    if (res != OK) {
+        if (res != BAD_VALUE) {
+            ALOGE("%s: Camera %d: Error receiving still image buffer: "
+                    "%s (%d)", __FUNCTION__,
+                    client->getCameraId(), strerror(-res), res);
+        }
+        return res;
+    }
+
+    ALOGV("%s: Camera %d: Still capture available", __FUNCTION__,
+            client->getCameraId());
+
+    // TODO: Signal errors here upstream
+    {
+        SharedParameters::Lock l(client->getParameters());
+
+        switch (l.mParameters.state) {
+            case Parameters::STILL_CAPTURE:
+                l.mParameters.state = Parameters::STOPPED;
+                break;
+            case Parameters::VIDEO_SNAPSHOT:
+                l.mParameters.state = Parameters::RECORD;
+                break;
+            default:
+                ALOGE("%s: Camera %d: Still image produced unexpectedly "
+                        "in state %s!",
+                        __FUNCTION__, client->getCameraId(),
+                        Parameters::getStateName(l.mParameters.state));
+                mCaptureConsumer->unlockBuffer(imgBuffer);
+                return BAD_VALUE;
+        }
+    }
+
+    if (imgBuffer.format != HAL_PIXEL_FORMAT_BLOB) {
+        ALOGE("%s: Camera %d: Unexpected format for still image: "
+                "%x, expected %x", __FUNCTION__, client->getCameraId(),
+                imgBuffer.format,
+                HAL_PIXEL_FORMAT_BLOB);
+        mCaptureConsumer->unlockBuffer(imgBuffer);
+        return OK;
+    }
+
+    // TODO: Optimize this to avoid memcopy
+    void* captureMemory = mCaptureHeap->mHeap->getBase();
+    size_t size = mCaptureHeap->mHeap->getSize();
+    memcpy(captureMemory, imgBuffer.data, size);
+
+    mCaptureConsumer->unlockBuffer(imgBuffer);
+
+    captureHeap = mCaptureHeap;
+
+    Camera2Client::SharedCameraClient::Lock l(client->mSharedCameraClient);
+    ALOGV("%s: Sending still image to client", __FUNCTION__);
+    if (l.mCameraClient != 0) {
+        l.mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE,
+                captureHeap->mBuffers[0], NULL);
+    } else {
+        ALOGV("%s: No client!", __FUNCTION__);
+    }
+    return OK;
+}
+
+}; // namespace camera2
+}; // namespace android
diff --git a/services/camera/libcameraservice/camera2/CaptureProcessor.h b/services/camera/libcameraservice/camera2/CaptureProcessor.h
new file mode 100644
index 0000000..8e35739
--- /dev/null
+++ b/services/camera/libcameraservice/camera2/CaptureProcessor.h
@@ -0,0 +1,79 @@
+/*
+ * 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_CAMERA2_CAPTUREPROCESSOR_H
+#define ANDROID_SERVERS_CAMERA_CAMERA2_CAPTUREPROCESSOR_H
+
+#include <utils/Thread.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+#include <utils/Mutex.h>
+#include <utils/Condition.h>
+#include <gui/CpuConsumer.h>
+#include "Parameters.h"
+#include "CameraMetadata.h"
+#include "Camera2Heap.h"
+
+namespace android {
+
+class Camera2Client;
+
+namespace camera2 {
+
+/***
+ * Still image capture output image processing
+ */
+class CaptureProcessor:
+            public Thread, public CpuConsumer::FrameAvailableListener {
+  public:
+    CaptureProcessor(wp<Camera2Client> client);
+    ~CaptureProcessor();
+
+    void onFrameAvailable();
+
+    status_t updateStream(const Parameters &params);
+    status_t deleteStream();
+    int getStreamId() const;
+
+    void dump(int fd, const Vector<String16>& args);
+  private:
+    static const nsecs_t kWaitDuration = 10000000; // 10 ms
+    wp<Camera2Client> mClient;
+
+    mutable Mutex mInputMutex;
+    bool mCaptureAvailable;
+    Condition mCaptureAvailableSignal;
+
+    enum {
+        NO_STREAM = -1
+    };
+
+    int mCaptureStreamId;
+    sp<CpuConsumer>    mCaptureConsumer;
+    sp<ANativeWindow>  mCaptureWindow;
+    sp<Camera2Heap>    mCaptureHeap;
+
+    virtual bool threadLoop();
+
+    status_t processNewCapture(sp<Camera2Client> &client);
+
+};
+
+
+}; //namespace camera2
+}; //namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/camera2/Parameters.cpp b/services/camera/libcameraservice/camera2/Parameters.cpp
index 91c5141..2f7d023 100644
--- a/services/camera/libcameraservice/camera2/Parameters.cpp
+++ b/services/camera/libcameraservice/camera2/Parameters.cpp
@@ -208,7 +208,7 @@
             CameraParameters::PIXEL_FORMAT_JPEG);
 
     camera_metadata_ro_entry_t availableJpegThumbnailSizes =
-        staticInfo(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, 2);
+        staticInfo(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, 4);
     if (!availableJpegThumbnailSizes.count) return NO_INIT;
 
     // TODO: Pick default thumbnail size sensibly