merge in jb-mr1-release history after reset to 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/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 26a25b0..34108b3 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -547,7 +547,7 @@
     status_t allocateTimedBuffer(size_t size, sp<IMemory>* buffer);
 
     /* queue a buffer obtained via allocateTimedBuffer for playback at the
-       given timestamp.  PTS units a microseconds on the media time timeline.
+       given timestamp.  PTS units are microseconds on the media time timeline.
        The media time transform (set with setMediaTimeTransform) set by the
        audio producer will handle converting from media time to local time
        (perhaps going through the common time timeline in the case of
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/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index dbcdf92..172975c 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -50,7 +50,11 @@
     virtual sp<IOMX>            getOMX() = 0;
     virtual sp<ICrypto>         makeCrypto() = 0;
 
-    virtual status_t enableRemoteDisplay(bool enable) = 0;
+    // If iface == NULL, disable remote display, otherwise
+    // iface should be of the form "x.x.x.x:y", i.e. ip address
+    // of the local interface to bind to and the port number
+    // to listen on.
+    virtual status_t enableRemoteDisplay(const char *iface) = 0;
 
     // codecs and audio devices usage tracking for the battery app
     enum BatteryDataBits {
diff --git a/include/media/IStreamSource.h b/include/media/IStreamSource.h
index 19646b0..61b9d5a 100644
--- a/include/media/IStreamSource.h
+++ b/include/media/IStreamSource.h
@@ -33,6 +33,12 @@
     virtual void setBuffers(const Vector<sp<IMemory> > &buffers) = 0;
 
     virtual void onBufferAvailable(size_t index) = 0;
+
+    enum {
+        // Video PES packets contain exactly one (aligned) access unit.
+        kFlagAlignedVideoData = 1,
+    };
+    virtual uint32_t flags() const { return 0; }
 };
 
 struct IStreamListener : public IInterface {
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/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h
index f5466e8..de7edf3 100644
--- a/include/media/stagefright/AudioSource.h
+++ b/include/media/stagefright/AudioSource.h
@@ -31,11 +31,12 @@
 class AudioRecord;
 
 struct AudioSource : public MediaSource, public MediaBufferObserver {
-    // Note that the "channels" parameter is _not_ the number of channels,
-    // but a bitmask of audio_channels_t constants.
+    // Note that the "channels" parameter _is_ the number of channels,
+    // _not_ a bitmask of audio_channels_t constants.
     AudioSource(
-            audio_source_t inputSource, uint32_t sampleRate,
-            uint32_t channels = AUDIO_CHANNEL_IN_MONO);
+            audio_source_t inputSource,
+            uint32_t sampleRate,
+            uint32_t channels = 1);
 
     status_t initCheck() const;
 
@@ -49,9 +50,15 @@
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL);
 
-    status_t dataCallbackTimestamp(const AudioRecord::Buffer& buffer, int64_t timeUs);
+    status_t dataCallback(const AudioRecord::Buffer& buffer);
     virtual void signalBufferReturned(MediaBuffer *buffer);
 
+    // If useLooperTime == true, buffers will carry absolute timestamps
+    // as returned by ALooper::GetNowUs(), otherwise systemTime() is used
+    // and buffers contain timestamps relative to start time.
+    // The default is to _not_ use looper time.
+    void setUseLooperTime(bool useLooperTime);
+
 protected:
     virtual ~AudioSource();
 
@@ -87,6 +94,8 @@
 
     List<MediaBuffer * > mBuffersReceived;
 
+    bool mUseLooperTime;
+
     void trackMaxAmplitude(int16_t *data, int nSamples);
 
     // This is used to raise the volume from mute to the
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/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 73d396e..362d022 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1144,7 +1144,7 @@
 
     // If the track is not invalid already, try to allocate a buffer.  alloc
     // fails indicating that the server is dead, flag the track as invalid so
-    // we can attempt to restore in in just a bit.
+    // we can attempt to restore in just a bit.
     if (!(mCblk->flags & CBLK_INVALID_MSK)) {
         result = mAudioTrack->allocateTimedBuffer(size, buffer);
         if (result == DEAD_OBJECT) {
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 41969b1..d3e2e19 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -121,10 +121,17 @@
         return interface_cast<ICrypto>(reply.readStrongBinder());
     }
 
-    virtual status_t enableRemoteDisplay(bool enable) {
+    virtual status_t enableRemoteDisplay(const char *iface) {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
-        data.writeInt32(enable);
+
+        if (iface != NULL) {
+            data.writeInt32(1);
+            data.writeCString(iface);
+        } else {
+            data.writeInt32(0);
+        }
+
         remote()->transact(ENABLE_REMOTE_DISPLAY, data, &reply);
         return reply.readInt32();
     }
@@ -217,8 +224,11 @@
         } break;
         case ENABLE_REMOTE_DISPLAY: {
             CHECK_INTERFACE(IMediaPlayerService, data, reply);
-            bool enable = data.readInt32();
-            reply->writeInt32(enableRemoteDisplay(enable));
+            const char *iface = NULL;
+            if (data.readInt32()) {
+                iface = data.readCString();
+            }
+            reply->writeInt32(enableRemoteDisplay(iface));
             return NO_ERROR;
         } break;
         case ADD_BATTERY_DATA: {
diff --git a/media/libmedia/IStreamSource.cpp b/media/libmedia/IStreamSource.cpp
index 078be94..78d810d 100644
--- a/media/libmedia/IStreamSource.cpp
+++ b/media/libmedia/IStreamSource.cpp
@@ -37,6 +37,7 @@
     SET_LISTENER = IBinder::FIRST_CALL_TRANSACTION,
     SET_BUFFERS,
     ON_BUFFER_AVAILABLE,
+    FLAGS,
 
     // IStreamListener
     QUEUE_BUFFER,
@@ -72,6 +73,14 @@
         remote()->transact(
                 ON_BUFFER_AVAILABLE, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual uint32_t flags() const {
+        Parcel data, reply;
+        data.writeInterfaceToken(IStreamSource::getInterfaceDescriptor());
+        remote()->transact(FLAGS, data, &reply);
+
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(StreamSource, "android.hardware.IStreamSource");
@@ -109,6 +118,13 @@
             break;
         }
 
+        case FLAGS:
+        {
+            CHECK_INTERFACE(IStreamSource, data, reply);
+            reply->writeInt32(this->flags());
+            break;
+        }
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 5fe446f..166bae9 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -279,13 +279,17 @@
     return new Crypto;
 }
 
-status_t MediaPlayerService::enableRemoteDisplay(bool enable) {
+status_t MediaPlayerService::enableRemoteDisplay(const char *iface) {
     Mutex::Autolock autoLock(mLock);
 
-    if (enable && mRemoteDisplay == NULL) {
+    if (iface != NULL) {
+        if (mRemoteDisplay != NULL) {
+            return INVALID_OPERATION;
+        }
+
         mRemoteDisplay = new RemoteDisplay;
 
-        status_t err = mRemoteDisplay->start();
+        status_t err = mRemoteDisplay->start(iface);
 
         if (err != OK) {
             mRemoteDisplay.clear();
@@ -293,7 +297,9 @@
         }
 
         return OK;
-    } else if (!enable && mRemoteDisplay != NULL) {
+    }
+
+    if (mRemoteDisplay != NULL) {
         mRemoteDisplay->stop();
         mRemoteDisplay.clear();
     }
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 8fbc5d5..2577c58 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -248,7 +248,7 @@
     virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat);
     virtual sp<IOMX>            getOMX();
     virtual sp<ICrypto>         makeCrypto();
-    virtual status_t            enableRemoteDisplay(bool enable);
+    virtual status_t            enableRemoteDisplay(const char *iface);
 
     virtual status_t            dump(int fd, const Vector<String16>& args);
 
diff --git a/media/libmediaplayerservice/RemoteDisplay.cpp b/media/libmediaplayerservice/RemoteDisplay.cpp
index 855824a..49f7278 100644
--- a/media/libmediaplayerservice/RemoteDisplay.cpp
+++ b/media/libmediaplayerservice/RemoteDisplay.cpp
@@ -32,13 +32,11 @@
 RemoteDisplay::~RemoteDisplay() {
 }
 
-status_t RemoteDisplay::start() {
+status_t RemoteDisplay::start(const char *iface) {
     mNetSession->start();
     mLooper->start();
 
-    // XXX replace with 8554 for bcom dongle (it doesn't respect the
-    // default port or the one advertised in the wfd IE).
-    mSource->start(WifiDisplaySource::kWifiDisplayDefaultPort);
+    mSource->start(iface);
 
     return OK;
 }
diff --git a/media/libmediaplayerservice/RemoteDisplay.h b/media/libmediaplayerservice/RemoteDisplay.h
index 6b37afb..3607d06 100644
--- a/media/libmediaplayerservice/RemoteDisplay.h
+++ b/media/libmediaplayerservice/RemoteDisplay.h
@@ -31,7 +31,7 @@
 struct RemoteDisplay : public RefBase {
     RemoteDisplay();
 
-    status_t start();
+    status_t start(const char *iface);
     status_t stop();
 
 protected:
diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk
index f469054..f946c1c 100644
--- a/media/libmediaplayerservice/nuplayer/Android.mk
+++ b/media/libmediaplayerservice/nuplayer/Android.mk
@@ -12,8 +12,6 @@
         RTSPSource.cpp                  \
         StreamingSource.cpp             \
         mp4/MP4Source.cpp               \
-        mp4/Parser.cpp                  \
-        mp4/TrackFragment.cpp           \
 
 LOCAL_C_INCLUDES := \
 	$(TOP)/frameworks/av/media/libstagefright/httplive            \
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 4a704e3..5a7a785 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -23,6 +23,7 @@
 #include "AnotherPacketSource.h"
 #include "MyHandler.h"
 
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 
 namespace android {
@@ -159,6 +160,13 @@
 }
 
 sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) {
+    if (mTSParser != NULL) {
+        sp<MediaSource> source = mTSParser->getSource(
+                audio ? ATSParser::AUDIO : ATSParser::VIDEO);
+
+        return static_cast<AnotherPacketSource *>(source.get());
+    }
+
     return audio ? mAudioTrack : mVideoTrack;
 }
 
@@ -255,7 +263,12 @@
         {
             size_t trackIndex;
             CHECK(msg->findSize("trackIndex", &trackIndex));
-            CHECK_LT(trackIndex, mTracks.size());
+
+            if (mTSParser == NULL) {
+                CHECK_LT(trackIndex, mTracks.size());
+            } else {
+                CHECK_EQ(trackIndex, 0u);
+            }
 
             sp<ABuffer> accessUnit;
             CHECK(msg->findBuffer("accessUnit", &accessUnit));
@@ -267,6 +280,37 @@
                 break;
             }
 
+            if (mTSParser != NULL) {
+                size_t offset = 0;
+                status_t err = OK;
+                while (offset + 188 <= accessUnit->size()) {
+                    err = mTSParser->feedTSPacket(
+                            accessUnit->data() + offset, 188);
+                    if (err != OK) {
+                        break;
+                    }
+
+                    offset += 188;
+                }
+
+                if (offset < accessUnit->size()) {
+                    err = ERROR_MALFORMED;
+                }
+
+                if (err != OK) {
+                    sp<AnotherPacketSource> source = getSource(false /* audio */);
+                    if (source != NULL) {
+                        source->signalEOS(err);
+                    }
+
+                    source = getSource(true /* audio */);
+                    if (source != NULL) {
+                        source->signalEOS(err);
+                    }
+                }
+                break;
+            }
+
             TrackInfo *info = &mTracks.editItemAt(trackIndex);
 
             sp<AnotherPacketSource> source = info->mSource;
@@ -296,14 +340,28 @@
 
         case MyHandler::kWhatEOS:
         {
-            size_t trackIndex;
-            CHECK(msg->findSize("trackIndex", &trackIndex));
-            CHECK_LT(trackIndex, mTracks.size());
-
             int32_t finalResult;
             CHECK(msg->findInt32("finalResult", &finalResult));
             CHECK_NE(finalResult, (status_t)OK);
 
+            if (mTSParser != NULL) {
+                sp<AnotherPacketSource> source = getSource(false /* audio */);
+                if (source != NULL) {
+                    source->signalEOS(finalResult);
+                }
+
+                source = getSource(true /* audio */);
+                if (source != NULL) {
+                    source->signalEOS(finalResult);
+                }
+
+                return;
+            }
+
+            size_t trackIndex;
+            CHECK(msg->findSize("trackIndex", &trackIndex));
+            CHECK_LT(trackIndex, mTracks.size());
+
             TrackInfo *info = &mTracks.editItemAt(trackIndex);
             sp<AnotherPacketSource> source = info->mSource;
             if (source != NULL) {
@@ -364,6 +422,14 @@
         const char *mime;
         CHECK(format->findCString(kKeyMIMEType, &mime));
 
+        if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
+            // Very special case for MPEG2 Transport Streams.
+            CHECK_EQ(numTracks, 1u);
+
+            mTSParser = new ATSParser;
+            return;
+        }
+
         bool isAudio = !strncasecmp(mime, "audio/", 6);
         bool isVideo = !strncasecmp(mime, "video/", 6);
 
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index c8409e5..f07c724 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -20,6 +20,8 @@
 
 #include "NuPlayerSource.h"
 
+#include "ATSParser.h"
+
 #include <media/stagefright/foundation/AHandlerReflector.h>
 
 namespace android {
@@ -99,6 +101,8 @@
     sp<AnotherPacketSource> mAudioTrack;
     sp<AnotherPacketSource> mVideoTrack;
 
+    sp<ATSParser> mTSParser;
+
     int32_t mSeekGeneration;
 
     sp<AnotherPacketSource> getSource(bool audio);
diff --git a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp
index 25c91e9..c80d13f 100644
--- a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp
+++ b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp
@@ -16,7 +16,7 @@
 
 #include "MP4Source.h"
 
-#include "Parser.h"
+#include "FragmentedMP4Parser.h"
 #include "../NuPlayerStreamListener.h"
 
 #include <media/IStreamSource.h>
@@ -26,7 +26,7 @@
 
 namespace android {
 
-struct StreamSource : public Parser::Source {
+struct StreamSource : public FragmentedMP4Parser::Source {
     StreamSource(const sp<IStreamSource> &source)
         : mListener(new NuPlayer::NuPlayerStreamListener(source, 0)),
           mPosition(0) {
@@ -103,7 +103,7 @@
 MP4Source::MP4Source(const sp<IStreamSource> &source)
     : mSource(source),
       mLooper(new ALooper),
-      mParser(new Parser),
+      mParser(new FragmentedMP4Parser),
       mEOS(false) {
     mLooper->registerHandler(mParser);
 }
diff --git a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h
index 57430aa..4e927af 100644
--- a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h
+++ b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h
@@ -21,7 +21,7 @@
 
 namespace android {
 
-struct Parser;
+struct FragmentedMP4Parser;
 
 struct MP4Source : public NuPlayer::Source {
     MP4Source(const sp<IStreamSource> &source);
@@ -41,7 +41,7 @@
 private:
     sp<IStreamSource> mSource;
     sp<ALooper> mLooper;
-    sp<Parser> mParser;
+    sp<FragmentedMP4Parser> mParser;
     bool mEOS;
 
     DISALLOW_EVIL_CONSTRUCTORS(MP4Source);
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/media/libnbaio/README.txt b/media/libnbaio/README.txt
new file mode 100644
index 0000000..8d74ab2
--- /dev/null
+++ b/media/libnbaio/README.txt
@@ -0,0 +1,40 @@
+libnbaio (for "Non-Blocking Audio I/O") was originally intended to
+be a purely non-blocking API.  It has evolved to now include
+a few blocking implementations of the interface.
+
+Note: as used here, "short transfer count" means the return value for
+read() or write() that indicates the actual number of successfully
+transferred frames is less than the requested number of frames.
+
+Pipe
+----
+supports 1 writer and N readers
+
+no mutexes, so safe to use between SCHED_NORMAL and SCHED_FIFO threads
+
+writes:
+  non-blocking
+  never return a short transfer count
+  overwrite data if not consumed quickly enough
+
+reads:
+  non-blocking
+  return a short transfer count if not enough data
+  will lose data if reader doesn't keep up
+
+MonoPipe
+--------
+supports 1 writer and 1 reader
+
+no mutexes, so safe to use between SCHED_NORMAL and SCHED_FIFO threads
+
+write are optionally blocking:
+  if configured to block, then will wait until space available before returning
+  if configured to not block, then will return a short transfer count
+    and will never overwrite data
+
+reads:
+  non-blocking
+  return a short transfer count if not enough data
+  never lose data
+
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/Android.mk b/media/libstagefright/Android.mk
index 3fd0f85..1522e75 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -53,6 +53,8 @@
         WVMExtractor.cpp                  \
         XINGSeeker.cpp                    \
         avc_utils.cpp                     \
+        mp4/FragmentedMP4Parser.cpp       \
+        mp4/TrackFragment.cpp             \
 
 LOCAL_C_INCLUDES:= \
         $(TOP)/frameworks/av/include/media/stagefright/timedtext \
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index ed142a4..3248dbc 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -24,6 +24,7 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
 #include <cutils/properties.h>
 #include <stdlib.h>
 
@@ -33,7 +34,7 @@
     AudioSource *source = (AudioSource *) user;
     switch (event) {
         case AudioRecord::EVENT_MORE_DATA: {
-            source->dataCallbackTimestamp(*((AudioRecord::Buffer *) info), systemTime() / 1000);
+            source->dataCallback(*((AudioRecord::Buffer *) info));
             break;
         }
         case AudioRecord::EVENT_OVERRUN: {
@@ -53,7 +54,8 @@
       mSampleRate(sampleRate),
       mPrevSampleTimeUs(0),
       mNumFramesReceived(0),
-      mNumClientOwnedBuffers(0) {
+      mNumClientOwnedBuffers(0),
+      mUseLooperTime(false) {
 
     ALOGV("sampleRate: %d, channelCount: %d", sampleRate, channelCount);
     CHECK(channelCount == 1 || channelCount == 2);
@@ -100,6 +102,12 @@
     return mInitCheck;
 }
 
+void AudioSource::setUseLooperTime(bool useLooperTime) {
+    CHECK(!mStarted);
+
+    mUseLooperTime = useLooperTime;
+}
+
 status_t AudioSource::start(MetaData *params) {
     Mutex::Autolock autoLock(mLock);
     if (mStarted) {
@@ -271,8 +279,10 @@
     return;
 }
 
-status_t AudioSource::dataCallbackTimestamp(
-        const AudioRecord::Buffer& audioBuffer, int64_t timeUs) {
+status_t AudioSource::dataCallback(const AudioRecord::Buffer& audioBuffer) {
+    int64_t timeUs =
+        mUseLooperTime ? ALooper::GetNowUs() : (systemTime() / 1000ll);
+
     ALOGV("dataCallbackTimestamp: %lld us", timeUs);
     Mutex::Autolock autoLock(mLock);
     if (!mStarted) {
@@ -290,12 +300,15 @@
     if (mNumFramesReceived == 0 && mPrevSampleTimeUs == 0) {
         mInitialReadTimeUs = timeUs;
         // Initial delay
-        if (mStartTimeUs > 0) {
+        if (mUseLooperTime) {
+            mStartTimeUs = timeUs;
+        } else if (mStartTimeUs > 0) {
             mStartTimeUs = timeUs - mStartTimeUs;
         } else {
             // Assume latency is constant.
             mStartTimeUs += mRecord->latency() * 1000;
         }
+
         mPrevSampleTimeUs = mStartTimeUs;
     }
 
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/media/libmediaplayerservice/nuplayer/mp4/Parser.h b/media/libstagefright/include/FragmentedMP4Parser.h
similarity index 95%
rename from media/libmediaplayerservice/nuplayer/mp4/Parser.h
rename to media/libstagefright/include/FragmentedMP4Parser.h
index 0d8d0f5..bd8fe32 100644
--- a/media/libmediaplayerservice/nuplayer/mp4/Parser.h
+++ b/media/libstagefright/include/FragmentedMP4Parser.h
@@ -25,7 +25,7 @@
 
 struct ABuffer;
 
-struct Parser : public AHandler {
+struct FragmentedMP4Parser : public AHandler {
     struct Source : public RefBase {
         Source() {}
 
@@ -38,7 +38,7 @@
         DISALLOW_EVIL_CONSTRUCTORS(Source);
     };
 
-    Parser();
+    FragmentedMP4Parser();
 
     void start(const char *filename);
     void start(const sp<Source> &source);
@@ -49,7 +49,7 @@
     virtual void onMessageReceived(const sp<AMessage> &msg);
 
 protected:
-    virtual ~Parser();
+    virtual ~FragmentedMP4Parser();
 
 private:
     enum {
@@ -67,7 +67,7 @@
     struct DispatchEntry {
         uint32_t mType;
         uint32_t mParentType;
-        status_t (Parser::*mHandler)(uint32_t, size_t, uint64_t);
+        status_t (FragmentedMP4Parser::*mHandler)(uint32_t, size_t, uint64_t);
     };
 
     struct Container {
@@ -246,7 +246,7 @@
             sp<ABuffer> *dst,
             size_t offset, uint64_t size, size_t extra = 0) const;
 
-    DISALLOW_EVIL_CONSTRUCTORS(Parser);
+    DISALLOW_EVIL_CONSTRUCTORS(FragmentedMP4Parser);
 };
 
 }  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/mp4/Parser.cpp b/media/libstagefright/mp4/FragmentedMP4Parser.cpp
similarity index 92%
rename from media/libmediaplayerservice/nuplayer/mp4/Parser.cpp
rename to media/libstagefright/mp4/FragmentedMP4Parser.cpp
index f664e92..e130a80 100644
--- a/media/libmediaplayerservice/nuplayer/mp4/Parser.cpp
+++ b/media/libstagefright/mp4/FragmentedMP4Parser.cpp
@@ -15,13 +15,13 @@
  */
 
 //#define LOG_NDEBUG 0
-#define LOG_TAG "Parser"
+#define LOG_TAG "FragmentedMP4Parser"
 #include <utils/Log.h>
 
-#include "Parser.h"
+#include "include/FragmentedMP4Parser.h"
+#include "include/ESDS.h"
 #include "TrackFragment.h"
 
-#include "ESDS.h"
 
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -31,8 +31,6 @@
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/Utils.h>
 
-#include "../NuPlayerStreamListener.h"
-
 namespace android {
 
 static const char *Fourcc2String(uint32_t fourcc) {
@@ -52,7 +50,7 @@
 }
 
 // static
-const Parser::DispatchEntry Parser::kDispatchTable[] = {
+const FragmentedMP4Parser::DispatchEntry FragmentedMP4Parser::kDispatchTable[] = {
     { FOURCC('m', 'o', 'o', 'v'), 0, NULL },
     { FOURCC('t', 'r', 'a', 'k'), FOURCC('m', 'o', 'o', 'v'), NULL },
     { FOURCC('u', 'd', 't', 'a'), FOURCC('t', 'r', 'a', 'k'), NULL },
@@ -61,24 +59,24 @@
     { FOURCC('i', 'l', 's', 't'), FOURCC('m', 'e', 't', 'a'), NULL },
 
     { FOURCC('t', 'k', 'h', 'd'), FOURCC('t', 'r', 'a', 'k'),
-        &Parser::parseTrackHeader
+        &FragmentedMP4Parser::parseTrackHeader
     },
 
     { FOURCC('m', 'v', 'e', 'x'), FOURCC('m', 'o', 'o', 'v'), NULL },
 
     { FOURCC('t', 'r', 'e', 'x'), FOURCC('m', 'v', 'e', 'x'),
-        &Parser::parseTrackExtends
+        &FragmentedMP4Parser::parseTrackExtends
     },
 
     { FOURCC('e', 'd', 't', 's'), FOURCC('t', 'r', 'a', 'k'), NULL },
     { FOURCC('m', 'd', 'i', 'a'), FOURCC('t', 'r', 'a', 'k'), NULL },
 
     { FOURCC('m', 'd', 'h', 'd'), FOURCC('m', 'd', 'i', 'a'),
-        &Parser::parseMediaHeader
+        &FragmentedMP4Parser::parseMediaHeader
     },
 
     { FOURCC('h', 'd', 'l', 'r'), FOURCC('m', 'd', 'i', 'a'),
-        &Parser::parseMediaHandler
+        &FragmentedMP4Parser::parseMediaHandler
     },
 
     { FOURCC('m', 'i', 'n', 'f'), FOURCC('m', 'd', 'i', 'a'), NULL },
@@ -87,45 +85,45 @@
     { FOURCC('s', 't', 's', 'd'), FOURCC('s', 't', 'b', 'l'), NULL },
 
     { FOURCC('s', 't', 's', 'z'), FOURCC('s', 't', 'b', 'l'),
-        &Parser::parseSampleSizes },
+        &FragmentedMP4Parser::parseSampleSizes },
 
     { FOURCC('s', 't', 'z', '2'), FOURCC('s', 't', 'b', 'l'),
-        &Parser::parseCompactSampleSizes },
+        &FragmentedMP4Parser::parseCompactSampleSizes },
 
     { FOURCC('s', 't', 's', 'c'), FOURCC('s', 't', 'b', 'l'),
-        &Parser::parseSampleToChunk },
+        &FragmentedMP4Parser::parseSampleToChunk },
 
     { FOURCC('s', 't', 'c', 'o'), FOURCC('s', 't', 'b', 'l'),
-        &Parser::parseChunkOffsets },
+        &FragmentedMP4Parser::parseChunkOffsets },
 
     { FOURCC('c', 'o', '6', '4'), FOURCC('s', 't', 'b', 'l'),
-        &Parser::parseChunkOffsets64 },
+        &FragmentedMP4Parser::parseChunkOffsets64 },
 
     { FOURCC('a', 'v', 'c', 'C'), FOURCC('a', 'v', 'c', '1'),
-        &Parser::parseAVCCodecSpecificData },
+        &FragmentedMP4Parser::parseAVCCodecSpecificData },
 
     { FOURCC('e', 's', 'd', 's'), FOURCC('m', 'p', '4', 'a'),
-        &Parser::parseESDSCodecSpecificData },
+        &FragmentedMP4Parser::parseESDSCodecSpecificData },
 
     { FOURCC('e', 's', 'd', 's'), FOURCC('m', 'p', '4', 'v'),
-        &Parser::parseESDSCodecSpecificData },
+        &FragmentedMP4Parser::parseESDSCodecSpecificData },
 
-    { FOURCC('m', 'd', 'a', 't'), 0, &Parser::parseMediaData },
+    { FOURCC('m', 'd', 'a', 't'), 0, &FragmentedMP4Parser::parseMediaData },
 
     { FOURCC('m', 'o', 'o', 'f'), 0, NULL },
     { FOURCC('t', 'r', 'a', 'f'), FOURCC('m', 'o', 'o', 'f'), NULL },
 
     { FOURCC('t', 'f', 'h', 'd'), FOURCC('t', 'r', 'a', 'f'),
-        &Parser::parseTrackFragmentHeader
+        &FragmentedMP4Parser::parseTrackFragmentHeader
     },
     { FOURCC('t', 'r', 'u', 'n'), FOURCC('t', 'r', 'a', 'f'),
-        &Parser::parseTrackFragmentRun
+        &FragmentedMP4Parser::parseTrackFragmentRun
     },
 
     { FOURCC('m', 'f', 'r', 'a'), 0, NULL },
 };
 
-struct FileSource : public Parser::Source {
+struct FileSource : public FragmentedMP4Parser::Source {
     FileSource(const char *filename)
         : mFile(fopen(filename, "rb")) {
             CHECK(mFile != NULL);
@@ -142,28 +140,28 @@
     DISALLOW_EVIL_CONSTRUCTORS(FileSource);
 };
 
-Parser::Parser()
+FragmentedMP4Parser::FragmentedMP4Parser()
     : mBufferPos(0),
       mSuspended(false),
       mFinalResult(OK) {
 }
 
-Parser::~Parser() {
+FragmentedMP4Parser::~FragmentedMP4Parser() {
 }
 
-void Parser::start(const char *filename) {
+void FragmentedMP4Parser::start(const char *filename) {
     sp<AMessage> msg = new AMessage(kWhatStart, id());
     msg->setObject("source", new FileSource(filename));
     msg->post();
 }
 
-void Parser::start(const sp<Source> &source) {
+void FragmentedMP4Parser::start(const sp<Source> &source) {
     sp<AMessage> msg = new AMessage(kWhatStart, id());
     msg->setObject("source", source);
     msg->post();
 }
 
-sp<AMessage> Parser::getFormat(bool audio) {
+sp<AMessage> FragmentedMP4Parser::getFormat(bool audio) {
     sp<AMessage> msg = new AMessage(kWhatGetFormat, id());
     msg->setInt32("audio", audio);
 
@@ -185,7 +183,7 @@
     return format;
 }
 
-status_t Parser::dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit) {
+status_t FragmentedMP4Parser::dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit) {
     sp<AMessage> msg = new AMessage(kWhatDequeueAccessUnit, id());
     msg->setInt32("audio", audio);
 
@@ -205,7 +203,7 @@
     return OK;
 }
 
-ssize_t Parser::findTrack(bool wantAudio) const {
+ssize_t FragmentedMP4Parser::findTrack(bool wantAudio) const {
     for (size_t i = 0; i < mTracks.size(); ++i) {
         const TrackInfo *info = &mTracks.valueAt(i);
 
@@ -227,7 +225,7 @@
     return -EWOULDBLOCK;
 }
 
-void Parser::onMessageReceived(const sp<AMessage> &msg) {
+void FragmentedMP4Parser::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
         case kWhatStart:
         {
@@ -373,7 +371,7 @@
     }
 }
 
-status_t Parser::onProceed() {
+status_t FragmentedMP4Parser::onProceed() {
     status_t err;
 
     if ((err = need(8)) != OK) {
@@ -565,7 +563,7 @@
 }
 
 // static
-int Parser::CompareSampleLocation(
+int FragmentedMP4Parser::CompareSampleLocation(
         const SampleInfo &sample, const MediaDataInfo &mdatInfo) {
     if (sample.mOffset + sample.mSize < mdatInfo.mOffset) {
         return -1;
@@ -586,7 +584,7 @@
     return 0;
 }
 
-void Parser::resumeIfNecessary() {
+void FragmentedMP4Parser::resumeIfNecessary() {
     if (!mSuspended) {
         return;
     }
@@ -597,7 +595,7 @@
     (new AMessage(kWhatProceed, id()))->post();
 }
 
-status_t Parser::getSample(
+status_t FragmentedMP4Parser::getSample(
         TrackInfo *info, sp<TrackFragment> *fragment, SampleInfo *sampleInfo) {
     for (;;) {
         if (info->mFragments.empty()) {
@@ -625,7 +623,7 @@
     }
 }
 
-status_t Parser::onDequeueAccessUnit(
+status_t FragmentedMP4Parser::onDequeueAccessUnit(
         size_t trackIndex, sp<ABuffer> *accessUnit) {
     TrackInfo *info = &mTracks.editValueAt(trackIndex);
 
@@ -730,7 +728,7 @@
     return 0;
 }
 
-status_t Parser::makeAccessUnit(
+status_t FragmentedMP4Parser::makeAccessUnit(
         TrackInfo *info,
         const SampleInfo &sample,
         const MediaDataInfo &mdatInfo,
@@ -801,7 +799,7 @@
     return OK;
 }
 
-status_t Parser::need(size_t size) {
+status_t FragmentedMP4Parser::need(size_t size) {
     if (!fitsContainer(size)) {
         return -EINVAL;
     }
@@ -819,7 +817,7 @@
     return -EAGAIN;
 }
 
-void Parser::enter(off64_t offset, uint32_t type, uint64_t size) {
+void FragmentedMP4Parser::enter(off64_t offset, uint32_t type, uint64_t size) {
     Container container;
     container.mOffset = offset;
     container.mType = type;
@@ -829,32 +827,32 @@
     mStack.push(container);
 }
 
-bool Parser::fitsContainer(uint64_t size) const {
+bool FragmentedMP4Parser::fitsContainer(uint64_t size) const {
     CHECK(!mStack.isEmpty());
     const Container &container = mStack.itemAt(mStack.size() - 1);
 
     return container.mExtendsToEOF || size <= container.mBytesRemaining;
 }
 
-uint16_t Parser::readU16(size_t offset) {
+uint16_t FragmentedMP4Parser::readU16(size_t offset) {
     CHECK_LE(offset + 2, mBuffer->size());
 
     const uint8_t *ptr = mBuffer->data() + offset;
     return (ptr[0] << 8) | ptr[1];
 }
 
-uint32_t Parser::readU32(size_t offset) {
+uint32_t FragmentedMP4Parser::readU32(size_t offset) {
     CHECK_LE(offset + 4, mBuffer->size());
 
     const uint8_t *ptr = mBuffer->data() + offset;
     return (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
 }
 
-uint64_t Parser::readU64(size_t offset) {
+uint64_t FragmentedMP4Parser::readU64(size_t offset) {
     return (((uint64_t)readU32(offset)) << 32) | readU32(offset + 4);
 }
 
-void Parser::skip(off_t distance) {
+void FragmentedMP4Parser::skip(off_t distance) {
     CHECK(!mStack.isEmpty());
     for (size_t i = mStack.size(); i-- > 0;) {
         Container *container = &mStack.editItemAt(i);
@@ -916,7 +914,7 @@
     mBufferPos += distance;
 }
 
-status_t Parser::parseTrackHeader(
+status_t FragmentedMP4Parser::parseTrackHeader(
         uint32_t type, size_t offset, uint64_t size) {
     if (offset + 4 > size) {
         return -EINVAL;
@@ -963,7 +961,7 @@
     return OK;
 }
 
-status_t Parser::parseMediaHeader(
+status_t FragmentedMP4Parser::parseMediaHeader(
         uint32_t type, size_t offset, uint64_t size) {
     if (offset + 4 > size) {
         return -EINVAL;
@@ -996,7 +994,7 @@
     return OK;
 }
 
-status_t Parser::parseMediaHandler(
+status_t FragmentedMP4Parser::parseMediaHandler(
         uint32_t type, size_t offset, uint64_t size) {
     if (offset + 12 > size) {
         return -EINVAL;
@@ -1024,7 +1022,7 @@
     return OK;
 }
 
-status_t Parser::parseVisualSampleEntry(
+status_t FragmentedMP4Parser::parseVisualSampleEntry(
         uint32_t type, size_t offset, uint64_t size) {
     if (offset + 78 > size) {
         return -EINVAL;
@@ -1067,7 +1065,7 @@
     return OK;
 }
 
-status_t Parser::parseAudioSampleEntry(
+status_t FragmentedMP4Parser::parseAudioSampleEntry(
         uint32_t type, size_t offset, uint64_t size) {
     if (offset + 28 > size) {
         return -EINVAL;
@@ -1133,37 +1131,37 @@
     format->setBuffer(StringPrintf("csd-%d", index).c_str(), csd);
 }
 
-status_t Parser::parseSampleSizes(
+status_t FragmentedMP4Parser::parseSampleSizes(
         uint32_t type, size_t offset, uint64_t size) {
     return editTrack(mCurrentTrackID)->mStaticFragment->parseSampleSizes(
             this, type, offset, size);
 }
 
-status_t Parser::parseCompactSampleSizes(
+status_t FragmentedMP4Parser::parseCompactSampleSizes(
         uint32_t type, size_t offset, uint64_t size) {
     return editTrack(mCurrentTrackID)->mStaticFragment->parseCompactSampleSizes(
             this, type, offset, size);
 }
 
-status_t Parser::parseSampleToChunk(
+status_t FragmentedMP4Parser::parseSampleToChunk(
         uint32_t type, size_t offset, uint64_t size) {
     return editTrack(mCurrentTrackID)->mStaticFragment->parseSampleToChunk(
             this, type, offset, size);
 }
 
-status_t Parser::parseChunkOffsets(
+status_t FragmentedMP4Parser::parseChunkOffsets(
         uint32_t type, size_t offset, uint64_t size) {
     return editTrack(mCurrentTrackID)->mStaticFragment->parseChunkOffsets(
             this, type, offset, size);
 }
 
-status_t Parser::parseChunkOffsets64(
+status_t FragmentedMP4Parser::parseChunkOffsets64(
         uint32_t type, size_t offset, uint64_t size) {
     return editTrack(mCurrentTrackID)->mStaticFragment->parseChunkOffsets64(
             this, type, offset, size);
 }
 
-status_t Parser::parseAVCCodecSpecificData(
+status_t FragmentedMP4Parser::parseAVCCodecSpecificData(
         uint32_t type, size_t offset, uint64_t size) {
     TrackInfo *trackInfo = editTrack(mCurrentTrackID);
 
@@ -1246,7 +1244,7 @@
     return OK;
 }
 
-status_t Parser::parseESDSCodecSpecificData(
+status_t FragmentedMP4Parser::parseESDSCodecSpecificData(
         uint32_t type, size_t offset, uint64_t size) {
     TrackInfo *trackInfo = editTrack(mCurrentTrackID);
 
@@ -1351,7 +1349,7 @@
     return OK;
 }
 
-status_t Parser::parseMediaData(
+status_t FragmentedMP4Parser::parseMediaData(
         uint32_t type, size_t offset, uint64_t size) {
     ALOGV("skipping 'mdat' chunk at offsets 0x%08lx-0x%08llx.",
           mBufferPos + offset, mBufferPos + size);
@@ -1372,7 +1370,7 @@
     return OK;
 }
 
-status_t Parser::parseTrackExtends(
+status_t FragmentedMP4Parser::parseTrackExtends(
         uint32_t type, size_t offset, uint64_t size) {
     if (offset + 24 > size) {
         return -EINVAL;
@@ -1393,7 +1391,7 @@
     return OK;
 }
 
-Parser::TrackInfo *Parser::editTrack(
+FragmentedMP4Parser::TrackInfo *FragmentedMP4Parser::editTrack(
         uint32_t trackID, bool createIfNecessary) {
     ssize_t i = mTracks.indexOfKey(trackID);
 
@@ -1422,7 +1420,7 @@
     return &mTracks.editValueAt(mTracks.indexOfKey(trackID));
 }
 
-status_t Parser::parseTrackFragmentHeader(
+status_t FragmentedMP4Parser::parseTrackFragmentHeader(
         uint32_t type, size_t offset, uint64_t size) {
     if (offset + 8 > size) {
         return -EINVAL;
@@ -1512,7 +1510,7 @@
     return OK;
 }
 
-status_t Parser::parseTrackFragmentRun(
+status_t FragmentedMP4Parser::parseTrackFragmentRun(
         uint32_t type, size_t offset, uint64_t size) {
     if (offset + 8 > size) {
         return -EINVAL;
@@ -1670,7 +1668,7 @@
     return OK;
 }
 
-void Parser::copyBuffer(
+void FragmentedMP4Parser::copyBuffer(
         sp<ABuffer> *dst, size_t offset, uint64_t size, size_t extra) const {
     sp<ABuffer> buf = new ABuffer(size + extra);
     memcpy(buf->data(), mBuffer->data() + offset, size);
diff --git a/media/libmediaplayerservice/nuplayer/mp4/TrackFragment.cpp b/media/libstagefright/mp4/TrackFragment.cpp
similarity index 82%
rename from media/libmediaplayerservice/nuplayer/mp4/TrackFragment.cpp
rename to media/libstagefright/mp4/TrackFragment.cpp
index a4c31ea..3699038 100644
--- a/media/libmediaplayerservice/nuplayer/mp4/TrackFragment.cpp
+++ b/media/libstagefright/mp4/TrackFragment.cpp
@@ -28,15 +28,15 @@
 
 namespace android {
 
-Parser::DynamicTrackFragment::DynamicTrackFragment()
+FragmentedMP4Parser::DynamicTrackFragment::DynamicTrackFragment()
     : mComplete(false),
       mSampleIndex(0) {
 }
 
-Parser::DynamicTrackFragment::~DynamicTrackFragment() {
+FragmentedMP4Parser::DynamicTrackFragment::~DynamicTrackFragment() {
 }
 
-status_t Parser::DynamicTrackFragment::getSample(SampleInfo *info) {
+status_t FragmentedMP4Parser::DynamicTrackFragment::getSample(SampleInfo *info) {
     if (mSampleIndex >= mSamples.size()) {
         return mComplete ? ERROR_END_OF_STREAM : -EWOULDBLOCK;
     }
@@ -46,11 +46,11 @@
     return OK;
 }
 
-void Parser::DynamicTrackFragment::advance() {
+void FragmentedMP4Parser::DynamicTrackFragment::advance() {
     ++mSampleIndex;
 }
 
-void Parser::DynamicTrackFragment::addSample(
+void FragmentedMP4Parser::DynamicTrackFragment::addSample(
         off64_t dataOffset, size_t sampleSize,
         uint32_t presentationTime,
         size_t sampleDescIndex,
@@ -65,19 +65,19 @@
     sampleInfo->mFlags = flags;
 }
 
-status_t Parser::DynamicTrackFragment::signalCompletion() {
+status_t FragmentedMP4Parser::DynamicTrackFragment::signalCompletion() {
     mComplete = true;
 
     return OK;
 }
 
-bool Parser::DynamicTrackFragment::complete() const {
+bool FragmentedMP4Parser::DynamicTrackFragment::complete() const {
     return mComplete;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
-Parser::StaticTrackFragment::StaticTrackFragment()
+FragmentedMP4Parser::StaticTrackFragment::StaticTrackFragment()
     : mSampleIndex(0),
       mSampleCount(0),
       mChunkIndex(0),
@@ -87,10 +87,10 @@
       mNextSampleOffset(0) {
 }
 
-Parser::StaticTrackFragment::~StaticTrackFragment() {
+FragmentedMP4Parser::StaticTrackFragment::~StaticTrackFragment() {
 }
 
-status_t Parser::StaticTrackFragment::getSample(SampleInfo *info) {
+status_t FragmentedMP4Parser::StaticTrackFragment::getSample(SampleInfo *info) {
     if (mSampleIndex >= mSampleCount) {
         return ERROR_END_OF_STREAM;
     }
@@ -104,7 +104,7 @@
     return OK;
 }
 
-void Parser::StaticTrackFragment::updateSampleInfo() {
+void FragmentedMP4Parser::StaticTrackFragment::updateSampleInfo() {
     if (mSampleIndex >= mSampleCount) {
         return;
     }
@@ -185,7 +185,7 @@
     mSampleInfo.mFlags = 0;
 }
 
-void Parser::StaticTrackFragment::advance() {
+void FragmentedMP4Parser::StaticTrackFragment::advance() {
     mNextSampleOffset += mSampleInfo.mSize;
 
     ++mSampleIndex;
@@ -223,7 +223,7 @@
     ptr[3] = x & 0xff;
 }
 
-status_t Parser::StaticTrackFragment::signalCompletion() {
+status_t FragmentedMP4Parser::StaticTrackFragment::signalCompletion() {
     mSampleToChunkIndex = 0;
 
     mSampleToChunkRemaining =
@@ -236,12 +236,12 @@
     return OK;
 }
 
-bool Parser::StaticTrackFragment::complete() const {
+bool FragmentedMP4Parser::StaticTrackFragment::complete() const {
     return true;
 }
 
-status_t Parser::StaticTrackFragment::parseSampleSizes(
-        Parser *parser, uint32_t type, size_t offset, uint64_t size) {
+status_t FragmentedMP4Parser::StaticTrackFragment::parseSampleSizes(
+        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
     if (offset + 12 > size) {
         return ERROR_MALFORMED;
     }
@@ -264,8 +264,8 @@
     return OK;
 }
 
-status_t Parser::StaticTrackFragment::parseCompactSampleSizes(
-        Parser *parser, uint32_t type, size_t offset, uint64_t size) {
+status_t FragmentedMP4Parser::StaticTrackFragment::parseCompactSampleSizes(
+        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
     if (offset + 12 > size) {
         return ERROR_MALFORMED;
     }
@@ -293,8 +293,8 @@
     return OK;
 }
 
-status_t Parser::StaticTrackFragment::parseSampleToChunk(
-        Parser *parser, uint32_t type, size_t offset, uint64_t size) {
+status_t FragmentedMP4Parser::StaticTrackFragment::parseSampleToChunk(
+        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
     if (offset + 8 > size) {
         return ERROR_MALFORMED;
     }
@@ -318,8 +318,8 @@
     return OK;
 }
 
-status_t Parser::StaticTrackFragment::parseChunkOffsets(
-        Parser *parser, uint32_t type, size_t offset, uint64_t size) {
+status_t FragmentedMP4Parser::StaticTrackFragment::parseChunkOffsets(
+        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
     if (offset + 8 > size) {
         return ERROR_MALFORMED;
     }
@@ -339,8 +339,8 @@
     return OK;
 }
 
-status_t Parser::StaticTrackFragment::parseChunkOffsets64(
-        Parser *parser, uint32_t type, size_t offset, uint64_t size) {
+status_t FragmentedMP4Parser::StaticTrackFragment::parseChunkOffsets64(
+        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
     if (offset + 8 > size) {
         return ERROR_MALFORMED;
     }
diff --git a/media/libmediaplayerservice/nuplayer/mp4/TrackFragment.h b/media/libstagefright/mp4/TrackFragment.h
similarity index 77%
rename from media/libmediaplayerservice/nuplayer/mp4/TrackFragment.h
rename to media/libstagefright/mp4/TrackFragment.h
index 1498aad..e1ad46e 100644
--- a/media/libmediaplayerservice/nuplayer/mp4/TrackFragment.h
+++ b/media/libstagefright/mp4/TrackFragment.h
@@ -18,11 +18,11 @@
 
 #define TRACK_FRAGMENT_H_
 
-#include "Parser.h"
+#include "include/FragmentedMP4Parser.h"
 
 namespace android {
 
-struct Parser::TrackFragment : public RefBase {
+struct FragmentedMP4Parser::TrackFragment : public RefBase {
     TrackFragment() {}
 
     virtual status_t getSample(SampleInfo *info) = 0;
@@ -38,7 +38,7 @@
     DISALLOW_EVIL_CONSTRUCTORS(TrackFragment);
 };
 
-struct Parser::DynamicTrackFragment : public Parser::TrackFragment {
+struct FragmentedMP4Parser::DynamicTrackFragment : public FragmentedMP4Parser::TrackFragment {
     DynamicTrackFragment();
 
     virtual status_t getSample(SampleInfo *info);
@@ -66,7 +66,7 @@
     DISALLOW_EVIL_CONSTRUCTORS(DynamicTrackFragment);
 };
 
-struct Parser::StaticTrackFragment : public Parser::TrackFragment {
+struct FragmentedMP4Parser::StaticTrackFragment : public FragmentedMP4Parser::TrackFragment {
     StaticTrackFragment();
 
     virtual status_t getSample(SampleInfo *info);
@@ -76,19 +76,19 @@
     virtual bool complete() const;
 
     status_t parseSampleSizes(
-            Parser *parser, uint32_t type, size_t offset, uint64_t size);
+            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
 
     status_t parseCompactSampleSizes(
-            Parser *parser, uint32_t type, size_t offset, uint64_t size);
+            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
 
     status_t parseSampleToChunk(
-            Parser *parser, uint32_t type, size_t offset, uint64_t size);
+            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
 
     status_t parseChunkOffsets(
-            Parser *parser, uint32_t type, size_t offset, uint64_t size);
+            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
 
     status_t parseChunkOffsets64(
-            Parser *parser, uint32_t type, size_t offset, uint64_t size);
+            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
 
 protected:
     virtual ~StaticTrackFragment();
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 1cab077..e58e9bf 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -33,8 +33,9 @@
 
 namespace android {
 
-ElementaryStreamQueue::ElementaryStreamQueue(Mode mode)
-    : mMode(mode) {
+ElementaryStreamQueue::ElementaryStreamQueue(Mode mode, uint32_t flags)
+    : mMode(mode),
+      mFlags(flags) {
 }
 
 sp<MetaData> ElementaryStreamQueue::getFormat() {
@@ -289,6 +290,31 @@
 }
 
 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
+    if ((mFlags & kFlag_AlignedData) && mMode == H264) {
+        if (mRangeInfos.empty()) {
+            return NULL;
+        }
+
+        RangeInfo info = *mRangeInfos.begin();
+        mRangeInfos.erase(mRangeInfos.begin());
+
+        sp<ABuffer> accessUnit = new ABuffer(info.mLength);
+        memcpy(accessUnit->data(), mBuffer->data(), info.mLength);
+        accessUnit->meta()->setInt64("timeUs", info.mTimestampUs);
+
+        memmove(mBuffer->data(),
+                mBuffer->data() + info.mLength,
+                mBuffer->size() - info.mLength);
+
+        mBuffer->setRange(0, mBuffer->size() - info.mLength);
+
+        if (mFormat == NULL) {
+            mFormat = MakeAVCCodecSpecificData(accessUnit);
+        }
+
+        return accessUnit;
+    }
+
     switch (mMode) {
         case H264:
             return dequeueAccessUnitH264();
@@ -436,8 +462,8 @@
 
 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() {
     const uint8_t *data = mBuffer->data();
-    size_t size = mBuffer->size();
 
+    size_t size = mBuffer->size();
     Vector<NALPosition> nals;
 
     size_t totalSize = 0;
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index 4035ed3..72aa2e7 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -36,7 +36,12 @@
         MPEG_VIDEO,
         MPEG4_VIDEO,
     };
-    ElementaryStreamQueue(Mode mode);
+
+    enum Flags {
+        // Data appended to the queue is always at access unit boundaries.
+        kFlag_AlignedData = 1,
+    };
+    ElementaryStreamQueue(Mode mode, uint32_t flags = 0);
 
     status_t appendData(const void *data, size_t size, int64_t timeUs);
     void clear(bool clearFormat);
@@ -52,6 +57,7 @@
     };
 
     Mode mMode;
+    uint32_t mFlags;
 
     sp<ABuffer> mBuffer;
     List<RangeInfo> mRangeInfos;
diff --git a/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp b/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp
new file mode 100644
index 0000000..4c9bf5b
--- /dev/null
+++ b/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp
@@ -0,0 +1,119 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "AMPEG2TSAssembler"
+#include <utils/Log.h>
+
+#include "AMPEG2TSAssembler.h"
+
+#include "ARTPSource.h"
+#include "ASessionDescription.h"
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+AMPEG2TSAssembler::AMPEG2TSAssembler(
+        const sp<AMessage> &notify, const char *desc, const AString &params)
+    : mNotifyMsg(notify),
+      mNextExpectedSeqNoValid(false),
+      mNextExpectedSeqNo(0) {
+}
+
+AMPEG2TSAssembler::~AMPEG2TSAssembler() {
+}
+
+ARTPAssembler::AssemblyStatus AMPEG2TSAssembler::assembleMore(
+        const sp<ARTPSource> &source) {
+    return addPacket(source);
+}
+
+ARTPAssembler::AssemblyStatus AMPEG2TSAssembler::addPacket(
+        const sp<ARTPSource> &source) {
+    List<sp<ABuffer> > *queue = source->queue();
+
+    if (queue->empty()) {
+        return NOT_ENOUGH_DATA;
+    }
+
+    if (mNextExpectedSeqNoValid) {
+        List<sp<ABuffer> >::iterator it = queue->begin();
+        while (it != queue->end()) {
+            if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) {
+                break;
+            }
+
+            it = queue->erase(it);
+        }
+
+        if (queue->empty()) {
+            return NOT_ENOUGH_DATA;
+        }
+    }
+
+    sp<ABuffer> buffer = *queue->begin();
+
+    if (!mNextExpectedSeqNoValid) {
+        mNextExpectedSeqNoValid = true;
+        mNextExpectedSeqNo = (uint32_t)buffer->int32Data();
+    } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) {
+        ALOGV("Not the sequence number I expected");
+
+        return WRONG_SEQUENCE_NUMBER;
+    }
+
+    // hexdump(buffer->data(), buffer->size());
+
+    if ((buffer->size() % 188) > 0) {
+        queue->erase(queue->begin());
+        ++mNextExpectedSeqNo;
+
+        ALOGV("Not a multiple of transport packet size.");
+
+        return MALFORMED_PACKET;
+    }
+
+    sp<AMessage> msg = mNotifyMsg->dup();
+    msg->setBuffer("access-unit", buffer);
+    msg->post();
+
+    queue->erase(queue->begin());
+    ++mNextExpectedSeqNo;
+
+    return OK;
+}
+
+void AMPEG2TSAssembler::packetLost() {
+    CHECK(mNextExpectedSeqNoValid);
+    ++mNextExpectedSeqNo;
+}
+
+void AMPEG2TSAssembler::onByeReceived() {
+    sp<AMessage> msg = mNotifyMsg->dup();
+    msg->setInt32("eos", true);
+    msg->post();
+}
+
+}  // namespace android
+
+
diff --git a/media/libstagefright/rtsp/AMPEG2TSAssembler.h b/media/libstagefright/rtsp/AMPEG2TSAssembler.h
new file mode 100644
index 0000000..712e18e
--- /dev/null
+++ b/media/libstagefright/rtsp/AMPEG2TSAssembler.h
@@ -0,0 +1,54 @@
+/*
+ * 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 A_MPEG2_TS_ASSEMBLER_H_
+
+#define A_MPEG2_TS_ASSEMBLER_H_
+
+#include "ARTPAssembler.h"
+
+namespace android {
+
+struct AMessage;
+struct AString;
+struct MetaData;
+
+struct AMPEG2TSAssembler : public ARTPAssembler {
+    AMPEG2TSAssembler(
+            const sp<AMessage> &notify,
+            const char *desc, const AString &params);
+
+protected:
+    virtual ~AMPEG2TSAssembler();
+
+    virtual AssemblyStatus assembleMore(const sp<ARTPSource> &source);
+    virtual void onByeReceived();
+    virtual void packetLost();
+
+private:
+    sp<AMessage> mNotifyMsg;
+    bool mNextExpectedSeqNoValid;
+    uint32_t mNextExpectedSeqNo;
+
+    AssemblyStatus addPacket(const sp<ARTPSource> &source);
+
+    DISALLOW_EVIL_CONSTRUCTORS(AMPEG2TSAssembler);
+};
+
+}  // namespace android
+
+#endif  // A_MPEG2_TS_ASSEMBLER_H_
+
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index ddd2f06..462c384 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -566,6 +566,8 @@
                 codecSpecificData->data(), codecSpecificData->size());
     } else if (ARawAudioAssembler::Supports(desc.c_str())) {
         ARawAudioAssembler::MakeFormat(desc.c_str(), mFormat);
+    } else if (!strncasecmp("MP2T/", desc.c_str(), 5)) {
+        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
     } else {
         mInitCheck = ERROR_UNSUPPORTED;
     }
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index ed68790..d7c3bd6 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -23,6 +23,7 @@
 #include "AAMRAssembler.h"
 #include "AAVCAssembler.h"
 #include "AH263Assembler.h"
+#include "AMPEG2TSAssembler.h"
 #include "AMPEG4AudioAssembler.h"
 #include "AMPEG4ElementaryAssembler.h"
 #include "ARawAudioAssembler.h"
@@ -73,6 +74,8 @@
         mIssueFIRRequests = true;
     } else if (ARawAudioAssembler::Supports(desc.c_str())) {
         mAssembler = new ARawAudioAssembler(notify, desc.c_str(), params);
+    } else if (!strncasecmp(desc.c_str(), "MP2T/", 5)) {
+        mAssembler = new AMPEG2TSAssembler(notify, desc.c_str(), params);
     } else {
         TRESPASS();
     }
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index d0f5259..49e2daf 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -6,6 +6,7 @@
         AAMRAssembler.cpp           \
         AAVCAssembler.cpp           \
         AH263Assembler.cpp          \
+        AMPEG2TSAssembler.cpp       \
         AMPEG4AudioAssembler.cpp    \
         AMPEG4ElementaryAssembler.cpp \
         APacketSource.cpp           \
diff --git a/media/libstagefright/wifi-display/ANetworkSession.cpp b/media/libstagefright/wifi-display/ANetworkSession.cpp
index ee0600c..4ddd778 100644
--- a/media/libstagefright/wifi-display/ANetworkSession.cpp
+++ b/media/libstagefright/wifi-display/ANetworkSession.cpp
@@ -537,6 +537,7 @@
         int32_t *sessionID) {
     return createClientOrServer(
             kModeCreateRTSPClient,
+            NULL /* addr */,
             0 /* port */,
             host,
             port,
@@ -545,9 +546,11 @@
 }
 
 status_t ANetworkSession::createRTSPServer(
-        unsigned port, const sp<AMessage> &notify, int32_t *sessionID) {
+        const struct in_addr &addr, unsigned port,
+        const sp<AMessage> &notify, int32_t *sessionID) {
     return createClientOrServer(
             kModeCreateRTSPServer,
+            &addr,
             port,
             NULL /* remoteHost */,
             0 /* remotePort */,
@@ -568,6 +571,7 @@
         int32_t *sessionID) {
     return createClientOrServer(
             kModeCreateUDPSession,
+            NULL /* addr */,
             localPort,
             remoteHost,
             remotePort,
@@ -608,6 +612,7 @@
 
 status_t ANetworkSession::createClientOrServer(
         Mode mode,
+        const struct in_addr *localAddr,
         unsigned port,
         const char *remoteHost,
         unsigned remotePort,
@@ -677,8 +682,11 @@
 
         addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
         addr.sin_port = htons(remotePort);
+    } else if (localAddr != NULL) {
+        addr.sin_addr = *localAddr;
+        addr.sin_port = htons(port);
     } else {
-        addr.sin_addr.s_addr = INADDR_ANY;
+        addr.sin_addr.s_addr = htonl(INADDR_ANY);
         addr.sin_port = htons(port);
     }
 
diff --git a/media/libstagefright/wifi-display/ANetworkSession.h b/media/libstagefright/wifi-display/ANetworkSession.h
index d4cd14f..8d961ee 100644
--- a/media/libstagefright/wifi-display/ANetworkSession.h
+++ b/media/libstagefright/wifi-display/ANetworkSession.h
@@ -23,6 +23,8 @@
 #include <utils/RefBase.h>
 #include <utils/Thread.h>
 
+#include <netinet/in.h>
+
 namespace android {
 
 struct AMessage;
@@ -40,7 +42,8 @@
             int32_t *sessionID);
 
     status_t createRTSPServer(
-            unsigned port, const sp<AMessage> &notify, int32_t *sessionID);
+            const struct in_addr &addr, unsigned port,
+            const sp<AMessage> &notify, int32_t *sessionID);
 
     status_t createUDPSession(
             unsigned localPort, const sp<AMessage> &notify, int32_t *sessionID);
@@ -92,6 +95,7 @@
     };
     status_t createClientOrServer(
             Mode mode,
+            const struct in_addr *addr,
             unsigned port,
             const char *remoteHost,
             unsigned remotePort,
diff --git a/media/libstagefright/wifi-display/source/Converter.cpp b/media/libstagefright/wifi-display/source/Converter.cpp
index 655fbae..ee05e45 100644
--- a/media/libstagefright/wifi-display/source/Converter.cpp
+++ b/media/libstagefright/wifi-display/source/Converter.cpp
@@ -86,8 +86,8 @@
     if (isAudio) {
         mOutputFormat->setInt32("bitrate", 64000);      // 64 kBit/sec
     } else {
-        mOutputFormat->setInt32("bitrate", 3000000);    // 3Mbit/sec
-        mOutputFormat->setInt32("frame-rate", 30);
+        mOutputFormat->setInt32("bitrate", 5000000);    // 5Mbit/sec
+        mOutputFormat->setInt32("frame-rate", 60);
         mOutputFormat->setInt32("i-frame-interval", 3);  // Iframes every 3 secs
     }
 
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index 96c9222..f9223d6 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -32,6 +32,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/AudioSource.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
@@ -132,8 +133,16 @@
       mNumSRsSent(0),
       mSendSRPending(false),
       mFirstPacketTimeUs(-1ll),
-      mHistoryLength(0) {
+      mHistoryLength(0)
+#if LOG_TRANSPORT_STREAM
+      ,mLogFile(NULL)
+#endif
+{
     mTSQueue->setRange(0, 12);
+
+#if LOG_TRANSPORT_STREAM
+    mLogFile = fopen("/system/etc/log.ts", "wb");
+#endif
 }
 
 status_t WifiDisplaySource::PlaybackSession::init(
@@ -215,6 +224,13 @@
 }
 
 WifiDisplaySource::PlaybackSession::~PlaybackSession() {
+#if LOG_TRANSPORT_STREAM
+    if (mLogFile != NULL) {
+        fclose(mLogFile);
+        mLogFile = NULL;
+    }
+#endif
+
     mTracks.clear();
 
     if (mCodecLooper != NULL) {
@@ -470,6 +486,12 @@
                                 true /* timeDiscontinuity */,
                                 lastTSPacket /* flush */);
                     }
+
+#if LOG_TRANSPORT_STREAM
+                    if (mLogFile != NULL) {
+                        fwrite(packets->data(), 1, packets->size(), mLogFile);
+                    }
+#endif
                 }
             } else if (what == Converter::kWhatEOS) {
                 CHECK_EQ(what, Converter::kWhatEOS);
@@ -628,6 +650,32 @@
     mTracks.add(index, new Track(converter));
 #endif
 
+#if 0
+    sp<AudioSource> audioSource = new AudioSource(
+            AUDIO_SOURCE_MIC,
+            48000 /* sampleRate */,
+            2 /* channelCount */);  // XXX AUDIO_CHANNEL_IN_STEREO?
+
+    CHECK_EQ((status_t)OK, audioSource->initCheck());
+
+    audioSource->setUseLooperTime(true);
+
+    index = mSerializer->addSource(audioSource);
+    CHECK_GE(index, 0);
+
+    sp<AMessage> audioFormat;
+    err = convertMetaDataToMessage(audioSource->getFormat(), &audioFormat);
+    CHECK_EQ(err, (status_t)OK);
+
+    sp<AMessage> audioNotify = new AMessage(kWhatConverterNotify, id());
+    audioNotify->setSize("trackIndex", index);
+
+    converter = new Converter(audioNotify, mCodecLooper, audioFormat);
+    looper()->registerHandler(converter);
+
+    mTracks.add(index, new Track(converter));
+#endif
+
     return OK;
 }
 
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.h b/media/libstagefright/wifi-display/source/PlaybackSession.h
index d256fc4..a6c9f27 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.h
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.h
@@ -26,6 +26,8 @@
 struct Serializer;
 struct TSPacketizer;
 
+#define LOG_TRANSPORT_STREAM    0
+
 // Encapsulates the state of an RTP/RTCP session in the context of wifi
 // display.
 struct WifiDisplaySource::PlaybackSession : public AHandler {
@@ -111,6 +113,10 @@
     List<sp<ABuffer> > mHistory;
     size_t mHistoryLength;
 
+#if LOG_TRANSPORT_STREAM
+    FILE *mLogFile;
+#endif
+
     void onSendSR();
     void addSR(const sp<ABuffer> &buffer);
     void addSDES(const sp<ABuffer> &buffer);
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index 3f75bc3..a998dcd 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -27,6 +27,9 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MediaErrors.h>
 
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
 namespace android {
 
 WifiDisplaySource::WifiDisplaySource(const sp<ANetworkSession> &netSession)
@@ -39,9 +42,9 @@
 WifiDisplaySource::~WifiDisplaySource() {
 }
 
-status_t WifiDisplaySource::start(int32_t port) {
+status_t WifiDisplaySource::start(const char *iface) {
     sp<AMessage> msg = new AMessage(kWhatStart, id());
-    msg->setInt32("port", port);
+    msg->setString("iface", iface);
 
     sp<AMessage> response;
     status_t err = msg->postAndAwaitResponse(&response);
@@ -81,13 +84,42 @@
             uint32_t replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
-            int32_t port;
-            CHECK(msg->findInt32("port", &port));
+            AString iface;
+            CHECK(msg->findString("iface", &iface));
 
-            sp<AMessage> notify = new AMessage(kWhatRTSPNotify, id());
+            status_t err = OK;
 
-            status_t err = mNetSession->createRTSPServer(
-                    port, notify, &mSessionID);
+            ssize_t colonPos = iface.find(":");
+
+            unsigned long port;
+
+            if (colonPos >= 0) {
+                const char *s = iface.c_str() + colonPos + 1;
+
+                char *end;
+                port = strtoul(s, &end, 10);
+
+                if (end == s || *end != '\0' || port > 65535) {
+                    err = -EINVAL;
+                } else {
+                    iface.erase(colonPos, iface.size() - colonPos);
+                }
+            } else {
+                port = kWifiDisplayDefaultPort;
+            }
+
+            struct in_addr addr;
+
+            if (err == OK) {
+                if (inet_aton(iface.c_str(), &addr) != 0) {
+                    sp<AMessage> notify = new AMessage(kWhatRTSPNotify, id());
+
+                    err = mNetSession->createRTSPServer(
+                            addr, port, notify, &mSessionID);
+                } else {
+                    err = -EINVAL;
+                }
+            }
 
             sp<AMessage> response = new AMessage;
             response->setInt32("err", err);
@@ -120,7 +152,7 @@
 
                     mNetSession->destroySession(sessionID);
 
-                    mClientIPs.removeItem(sessionID);
+                    mClientInfos.removeItem(sessionID);
                     break;
                 }
 
@@ -133,10 +165,11 @@
                     CHECK(msg->findString("client-ip", &info.mRemoteIP));
                     CHECK(msg->findString("server-ip", &info.mLocalIP));
                     CHECK(msg->findInt32("server-port", &info.mLocalPort));
+                    info.mPlaybackSessionID = -1;
 
                     ALOGI("We now have a client (%d) connected.", sessionID);
 
-                    mClientIPs.add(sessionID, info);
+                    mClientInfos.add(sessionID, info);
 
                     status_t err = sendM1(sessionID);
                     CHECK_EQ(err, (status_t)OK);
@@ -250,6 +283,20 @@
             break;
         }
 
+        case kWhatKeepAlive:
+        {
+            int32_t sessionID;
+            CHECK(msg->findInt32("sessionID", &sessionID));
+
+            if (mClientInfos.indexOfKey(sessionID) < 0) {
+                // Obsolete event, client is already gone.
+                break;
+            }
+
+            sendM16(sessionID);
+            break;
+        }
+
         default:
             TRESPASS();
     }
@@ -332,7 +379,7 @@
     //   max-hres (none or 2 byte)
     //   max-vres (none or 2 byte)
 
-    const ClientInfo &info = mClientIPs.valueFor(sessionID);
+    const ClientInfo &info = mClientInfos.valueFor(sessionID);
 
     AString body = StringPrintf(
         "wfd_video_formats: "
@@ -391,6 +438,31 @@
     return OK;
 }
 
+status_t WifiDisplaySource::sendM16(int32_t sessionID) {
+    AString request = "GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
+    AppendCommonResponse(&request, mNextCSeq);
+
+    const ClientInfo &info = mClientInfos.valueFor(sessionID);
+    request.append(StringPrintf("Session: %d\r\n", info.mPlaybackSessionID));
+
+    request.append("Content-Length: 0\r\n");
+    request.append("\r\n");
+
+    status_t err =
+        mNetSession->sendRequest(sessionID, request.c_str(), request.size());
+
+    if (err != OK) {
+        return err;
+    }
+
+    registerResponseHandler(
+            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM16Response);
+
+    ++mNextCSeq;
+
+    return OK;
+}
+
 status_t WifiDisplaySource::onReceiveM1Response(
         int32_t sessionID, const sp<ParsedMessage> &msg) {
     int32_t statusCode;
@@ -447,6 +519,22 @@
     return OK;
 }
 
+status_t WifiDisplaySource::onReceiveM16Response(
+        int32_t sessionID, const sp<ParsedMessage> &msg) {
+    // If only the response was required to include a "Session:" header...
+
+    const ClientInfo &info = mClientInfos.valueFor(sessionID);
+
+    ssize_t index = mPlaybackSessions.indexOfKey(info.mPlaybackSessionID);
+    if (index >= 0) {
+        mPlaybackSessions.valueAt(index)->updateLiveness();
+
+        scheduleKeepAlive(sessionID);
+    }
+
+    return OK;
+}
+
 void WifiDisplaySource::scheduleReaper() {
     if (mReaperPending) {
         return;
@@ -456,6 +544,16 @@
     (new AMessage(kWhatReapDeadClients, id()))->post(kReaperIntervalUs);
 }
 
+void WifiDisplaySource::scheduleKeepAlive(int32_t sessionID) {
+    // We need to send updates at least 5 secs before the timeout is set to
+    // expire, make sure the timeout is greater than 5 secs to begin with.
+    CHECK_GT(kPlaybackSessionTimeoutUs, 5000000ll);
+
+    sp<AMessage> msg = new AMessage(kWhatKeepAlive, id());
+    msg->setInt32("sessionID", sessionID);
+    msg->post(kPlaybackSessionTimeoutUs - 5000000ll);
+}
+
 void WifiDisplaySource::onReceiveClientData(const sp<AMessage> &msg) {
     int32_t sessionID;
     CHECK(msg->findInt32("sessionID", &sessionID));
@@ -603,6 +701,14 @@
         int32_t sessionID,
         int32_t cseq,
         const sp<ParsedMessage> &data) {
+    ClientInfo *info = &mClientInfos.editValueFor(sessionID);
+    if (info->mPlaybackSessionID != -1) {
+        // We only support a single playback session per client.
+        // This is due to the reversed keep-alive design in the wfd specs...
+        sendErrorResponse(sessionID, "400 Bad Request", cseq);
+        return;
+    }
+
     AString transport;
     if (!data->findString("transport", &transport)) {
         sendErrorResponse(sessionID, "400 Bad Request", cseq);
@@ -679,10 +785,8 @@
         return;
     }
 
-    const ClientInfo &info = mClientIPs.valueFor(sessionID);
-
     status_t err = playbackSession->init(
-            info.mRemoteIP.c_str(),
+            info->mRemoteIP.c_str(),
             clientRtp,
             clientRtcp,
             useInterleavedTCP);
@@ -705,6 +809,8 @@
 
     mPlaybackSessions.add(playbackSessionID, playbackSession);
 
+    info->mPlaybackSessionID = playbackSessionID;
+
     AString response = "RTSP/1.0 200 OK\r\n";
     AppendCommonResponse(&response, cseq, playbackSessionID);
 
@@ -736,10 +842,8 @@
     err = mNetSession->sendRequest(sessionID, response.c_str());
     CHECK_EQ(err, (status_t)OK);
 
-#if 0
-    // XXX the dongle does not currently send keep-alives.
     scheduleReaper();
-#endif
+    scheduleKeepAlive(sessionID);
 }
 
 void WifiDisplaySource::onPlayRequest(
@@ -915,6 +1019,11 @@
     for (;;) {
         int32_t playbackSessionID = rand();
 
+        if (playbackSessionID == -1) {
+            // reserved.
+            continue;
+        }
+
         for (size_t i = 0; i < mPlaybackSessions.size(); ++i) {
             if (mPlaybackSessions.keyAt(i) == playbackSessionID) {
                 continue;
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.h b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
index 95c3560..f56347d 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.h
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
@@ -33,7 +33,7 @@
 
     WifiDisplaySource(const sp<ANetworkSession> &netSession);
 
-    status_t start(int32_t port);
+    status_t start(const char *iface);
     status_t stop();
 
 protected:
@@ -49,6 +49,7 @@
         kWhatStop,
         kWhatReapDeadClients,
         kWhatPlaybackSessionNotify,
+        kWhatKeepAlive,
     };
 
     struct ResponseID {
@@ -79,8 +80,10 @@
         AString mRemoteIP;
         AString mLocalIP;
         int32_t mLocalPort;
+        int32_t mPlaybackSessionID;
     };
-    KeyedVector<int32_t, ClientInfo> mClientIPs;
+    // by sessionID.
+    KeyedVector<int32_t, ClientInfo> mClientInfos;
 
     bool mReaperPending;
 
@@ -94,6 +97,7 @@
     status_t sendM3(int32_t sessionID);
     status_t sendM4(int32_t sessionID);
     status_t sendM5(int32_t sessionID);
+    status_t sendM16(int32_t sessionID);
 
     status_t onReceiveM1Response(
             int32_t sessionID, const sp<ParsedMessage> &msg);
@@ -107,6 +111,9 @@
     status_t onReceiveM5Response(
             int32_t sessionID, const sp<ParsedMessage> &msg);
 
+    status_t onReceiveM16Response(
+            int32_t sessionID, const sp<ParsedMessage> &msg);
+
     void registerResponseHandler(
             int32_t sessionID, int32_t cseq, HandleRTSPResponseFunc func);
 
@@ -161,6 +168,7 @@
             AString *response, int32_t cseq, int32_t playbackSessionID = -1ll);
 
     void scheduleReaper();
+    void scheduleKeepAlive(int32_t sessionID);
 
     int32_t makeUniquePlaybackSessionID() const;
 
diff --git a/media/libstagefright/wifi-display/wfd.cpp b/media/libstagefright/wifi-display/wfd.cpp
index 32cdf3f..5e7d9fd 100644
--- a/media/libstagefright/wifi-display/wfd.cpp
+++ b/media/libstagefright/wifi-display/wfd.cpp
@@ -32,7 +32,7 @@
 
 namespace android {
 
-static void enableDisableRemoteDisplay(bool enable) {
+static void enableDisableRemoteDisplay(const char *iface) {
     sp<IServiceManager> sm = defaultServiceManager();
     sp<IBinder> binder = sm->getService(String16("media.player"));
 
@@ -41,7 +41,7 @@
 
     CHECK(service.get() != NULL);
 
-    service->enableRemoteDisplay(enable);
+    service->enableRemoteDisplay(iface);
 }
 
 }  // namespace android
@@ -53,7 +53,7 @@
             "           %s -c host[:port]\tconnect to wifi source\n"
             "           -u uri        \tconnect to an rtsp uri\n"
 #endif
-            "           -e            \tenable remote display\n"
+            "           -e ip[:port]       \tenable remote display\n"
             "           -d            \tdisable remote display\n",
             me);
 }
@@ -70,7 +70,7 @@
     AString uri;
 
     int res;
-    while ((res = getopt(argc, argv, "hc:l:u:ed")) >= 0) {
+    while ((res = getopt(argc, argv, "hc:l:u:e:d")) >= 0) {
         switch (res) {
 #if SUPPORT_SINK
             case 'c':
@@ -103,9 +103,15 @@
 #endif
 
             case 'e':
+            {
+                enableDisableRemoteDisplay(optarg);
+                exit(0);
+                break;
+            }
+
             case 'd':
             {
-                enableDisableRemoteDisplay(res == 'e');
+                enableDisableRemoteDisplay(NULL);
                 exit(0);
                 break;
             }
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..14f74b5 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"
 
@@ -169,8 +169,8 @@
 // for the track.  The client then sub-divides this into smaller buffers for its use.
 // Currently the client uses double-buffering by default, but doesn't tell us about that.
 // So for now we just assume that client is double-buffered.
-// FIXME It would be better for client to tell us whether it wants double-buffering or N-buffering,
-// so we could allocate the right amount of memory.
+// FIXME It would be better for client to tell AudioFlinger whether it wants double-buffering or
+// N-buffering, so AudioFlinger could allocate the right amount of memory.
 // See the client's minBufCount and mNotificationFramesAct calculations for details.
 static const int kFastTrackMultiplier = 2;
 
@@ -258,11 +258,11 @@
 AudioFlinger::~AudioFlinger()
 {
     while (!mRecordThreads.isEmpty()) {
-        // closeInput() will remove first entry from mRecordThreads
+        // closeInput_nonvirtual() will remove specified entry from mRecordThreads
         closeInput_nonvirtual(mRecordThreads.keyAt(0));
     }
     while (!mPlaybackThreads.isEmpty()) {
-        // closeOutput() will remove first entry from mPlaybackThreads
+        // closeOutput_nonvirtual() will remove specified entry from mPlaybackThreads
         closeOutput_nonvirtual(mPlaybackThreads.keyAt(0));
     }
 
@@ -1134,7 +1134,7 @@
 
 AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
         audio_devices_t device, type_t type)
-    :   Thread(false),
+    :   Thread(false /*canCallJava*/),
         mType(type),
         mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mNormalFrameCount(0),
         // mChannelMask
@@ -1142,6 +1142,7 @@
         mFrameSize(1), mFormat(AUDIO_FORMAT_INVALID),
         mParamStatus(NO_ERROR),
         mStandby(false), mDevice(device), mId(id),
+        // mName will be set by concrete (non-virtual) subclass
         mDeathRecipient(new PMDeathRecipient(this))
 {
 }
@@ -6097,7 +6098,7 @@
                     if (mChannelCount == 1 && mReqChannelCount == 1) {
                         framesOut >>= 1;
                     }
-                    mResampler->resample(mRsmpOutBuffer, framesOut, this);
+                    mResampler->resample(mRsmpOutBuffer, framesOut, this /* AudioBufferProvider* */);
                     // ditherAndClamp() works as long as all buffers returned by mActiveTrack->getNextBuffer()
                     // are 32 bit aligned which should be always true.
                     if (mChannelCount == 2 && mReqChannelCount == 1) {
@@ -6359,6 +6360,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 +6378,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..4723cd9 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>
@@ -454,8 +454,9 @@
             /*const*/ sp<Client> mClient;   // see explanation at ~TrackBase() why not const
             sp<IMemory>         mCblkMemory;
             audio_track_cblk_t* mCblk;
-            void*               mBuffer;
-            void*               mBufferEnd;
+            void*               mBuffer;    // start of track buffer, typically in shared memory
+            void*               mBufferEnd; // &mBuffer[mFrameCount * frameSize], where frameSize
+                                            //   is based on mChannelCount and 16-bit samples
             uint32_t            mFrameCount;
             // we don't really need a lock for these
             track_state         mState;
@@ -1364,6 +1365,7 @@
 
     // record thread
     class RecordThread : public ThreadBase, public AudioBufferProvider
+                            // derives from AudioBufferProvider interface for use by resampler
     {
     public:
 
@@ -1420,7 +1422,7 @@
         void        dumpInternals(int fd, const Vector<String16>& args);
         void        dumpTracks(int fd, const Vector<String16>& args);
 
-        // Thread
+        // Thread virtuals
         virtual bool        threadLoop();
         virtual status_t    readyToRun();
 
@@ -1968,9 +1970,10 @@
                 DefaultKeyedVector< audio_io_handle_t, sp<PlaybackThread> >  mPlaybackThreads;
                 stream_type_t                       mStreamTypes[AUDIO_STREAM_CNT];
 
-                // both are protected by mLock
+                // member variables below are protected by mLock
                 float                               mMasterVolume;
                 bool                                mMasterMute;
+                // end of variables protected by mLock
 
                 DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> >    mRecordThreads;
 
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 391c319..1370c62 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -12,7 +12,10 @@
     Camera2Client.cpp \
     Camera2Device.cpp \
     camera2/CameraMetadata.cpp \
-    camera2/Parameters.cpp
+    camera2/Parameters.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 9b6401b..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);
@@ -393,8 +396,8 @@
 
     mClientPid = getCallingPid();
 
-    Mutex::Autolock iccl(mICameraClientLock);
     mCameraClient = client;
+    mSharedCameraClient = client;
 
     SharedParameters::Lock l(mParameters);
     l.mParameters.state = Parameters::STOPPED;
@@ -433,10 +436,9 @@
     // TODO: Check for uninterruptable conditions
 
     if (mClientPid == getCallingPid()) {
-        Mutex::Autolock iccl(mICameraClientLock);
-
         mClientPid = 0;
         mCameraClient.clear();
+        mSharedCameraClient.clear();
         return OK;
     }
 
@@ -614,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);
@@ -633,7 +635,7 @@
 
     if (callbacksEnabled) {
         uint8_t outputStreams[2] =
-                { mPreviewStreamId, mCallbackStreamId };
+                { mPreviewStreamId, mCallbackProcessor->getStreamId() };
         res = mPreviewRequest.update(
                 ANDROID_REQUEST_OUTPUT_STREAMS,
                 outputStreams, 2);
@@ -797,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);
@@ -816,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);
@@ -1029,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);
@@ -1049,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;
@@ -1457,22 +1475,25 @@
             case Parameters::FOCUS_MODE_FIXED:
             default:
                 if (newState != ANDROID_CONTROL_AF_STATE_INACTIVE) {
-                    ALOGE("%s: Unexpected AF state change %d (ID %d) in focus mode %d",
-                          __FUNCTION__, newState, triggerId, l.mParameters.focusMode);
+                    ALOGE("%s: Unexpected AF state change %d "
+                            "(ID %d) in focus mode %d",
+                          __FUNCTION__, newState, triggerId,
+                            l.mParameters.focusMode);
                 }
         }
     }
     if (sendMovingMessage) {
-        Mutex::Autolock iccl(mICameraClientLock);
-        if (mCameraClient != 0) {
-            mCameraClient->notifyCallback(CAMERA_MSG_FOCUS_MOVE,
+        SharedCameraClient::Lock l(mSharedCameraClient);
+        if (l.mCameraClient != 0) {
+            l.mCameraClient->notifyCallback(CAMERA_MSG_FOCUS_MOVE,
                     afInMotion ? 1 : 0, 0);
         }
     }
     if (sendCompletedMessage) {
-        Mutex::Autolock iccl(mICameraClientLock);
-        if (mCameraClient != 0) {
-            mCameraClient->notifyCallback(CAMERA_MSG_FOCUS, success ? 1 : 0, 0);
+        SharedCameraClient::Lock l(mSharedCameraClient);
+        if (l.mCameraClient != 0) {
+            l.mCameraClient->notifyCallback(CAMERA_MSG_FOCUS,
+                    success ? 1 : 0, 0);
         }
     }
 }
@@ -1487,377 +1508,42 @@
             __FUNCTION__, newState, triggerId);
 }
 
-Camera2Client::FrameProcessor::FrameProcessor(wp<Camera2Client> client):
-        Thread(false), mClient(client) {
+int Camera2Client::getCameraId() {
+    return mCameraId;
 }
 
-Camera2Client::FrameProcessor::~FrameProcessor() {
-    ALOGV("%s: Exit", __FUNCTION__);
+const sp<Camera2Device>& Camera2Client::getCameraDevice() {
+    return mDevice;
 }
 
-void Camera2Client::FrameProcessor::dump(int fd, const Vector<String16>& args) {
-    String8 result("    Latest received frame:\n");
-    write(fd, result.string(), result.size());
-    mLastFrame.dump(fd, 2, 6);
+camera2::SharedParameters& Camera2Client::getParameters() {
+    return mParameters;
 }
 
-bool Camera2Client::FrameProcessor::threadLoop() {
-    status_t res;
-
-    sp<Camera2Device> device;
-    {
-        sp<Camera2Client> client = mClient.promote();
-        if (client == 0) return false;
-        device = client->mDevice;
-    }
-
-    res = device->waitForNextFrame(kWaitDuration);
-    if (res == OK) {
-        sp<Camera2Client> client = mClient.promote();
-        if (client == 0) return false;
-        processNewFrames(client);
-    } else if (res != TIMED_OUT) {
-        ALOGE("Camera2Client::FrameProcessor: Error waiting for new "
-                "frames: %s (%d)", strerror(-res), res);
-    }
-
-    return true;
+Camera2Client::SharedCameraClient::Lock::Lock(SharedCameraClient &client):
+        mCameraClient(client.mCameraClient),
+        mSharedClient(client) {
+    mSharedClient.mCameraClientLock.lock();
 }
 
-void Camera2Client::FrameProcessor::processNewFrames(sp<Camera2Client> &client) {
-    status_t res;
-    CameraMetadata frame;
-    while ( (res = client->mDevice->getNextFrame(&frame)) == OK) {
-        camera_metadata_entry_t entry;
-        entry = frame.find(ANDROID_REQUEST_FRAME_COUNT);
-        if (entry.count == 0) {
-            ALOGE("%s: Camera %d: Error reading frame number: %s (%d)",
-                    __FUNCTION__, client->mCameraId, strerror(-res), res);
-            break;
-        }
-
-        res = processFaceDetect(frame, client);
-        if (res != OK) break;
-
-        mLastFrame.acquire(frame);
-    }
-    if (res != NOT_ENOUGH_DATA) {
-        ALOGE("%s: Camera %d: Error getting next frame: %s (%d)",
-                __FUNCTION__, client->mCameraId, strerror(-res), res);
-        return;
-    }
-
-    return;
+Camera2Client::SharedCameraClient::Lock::~Lock() {
+    mSharedClient.mCameraClientLock.unlock();
 }
 
-status_t Camera2Client::FrameProcessor::processFaceDetect(
-    const CameraMetadata &frame, sp<Camera2Client> &client) {
-    status_t res;
-    camera_metadata_ro_entry_t entry;
-    bool enableFaceDetect;
-    int maxFaces;
-    {
-        SharedParameters::Lock l(client->mParameters);
-        enableFaceDetect = l.mParameters.enableFaceDetect;
-    }
-    entry = frame.find(ANDROID_STATS_FACE_DETECT_MODE);
-
-    // TODO: This should be an error once implementations are compliant
-    if (entry.count == 0) {
-        return OK;
-    }
-
-    uint8_t faceDetectMode = entry.data.u8[0];
-
-    camera_frame_metadata metadata;
-    Vector<camera_face_t> faces;
-    metadata.number_of_faces = 0;
-
-    if (enableFaceDetect && faceDetectMode != ANDROID_STATS_FACE_DETECTION_OFF) {
-        SharedParameters::Lock l(client->mParameters);
-        entry = frame.find(ANDROID_STATS_FACE_RECTANGLES);
-        if (entry.count == 0) {
-            ALOGE("%s: Camera %d: Unable to read face rectangles",
-                    __FUNCTION__, client->mCameraId);
-            return res;
-        }
-        metadata.number_of_faces = entry.count / 4;
-        if (metadata.number_of_faces >
-                l.mParameters.fastInfo.maxFaces) {
-            ALOGE("%s: Camera %d: More faces than expected! (Got %d, max %d)",
-                    __FUNCTION__, client->mCameraId,
-                    metadata.number_of_faces, l.mParameters.fastInfo.maxFaces);
-            return res;
-        }
-        const int32_t *faceRects = entry.data.i32;
-
-        entry = frame.find(ANDROID_STATS_FACE_SCORES);
-        if (entry.count == 0) {
-            ALOGE("%s: Camera %d: Unable to read face scores",
-                    __FUNCTION__, client->mCameraId);
-            return res;
-        }
-        const uint8_t *faceScores = entry.data.u8;
-
-        const int32_t *faceLandmarks = NULL;
-        const int32_t *faceIds = NULL;
-
-        if (faceDetectMode == ANDROID_STATS_FACE_DETECTION_FULL) {
-            entry = frame.find(ANDROID_STATS_FACE_LANDMARKS);
-            if (entry.count == 0) {
-                ALOGE("%s: Camera %d: Unable to read face landmarks",
-                        __FUNCTION__, client->mCameraId);
-                return res;
-            }
-            faceLandmarks = entry.data.i32;
-
-            entry = frame.find(ANDROID_STATS_FACE_IDS);
-
-            if (entry.count == 0) {
-                ALOGE("%s: Camera %d: Unable to read face IDs",
-                        __FUNCTION__, client->mCameraId);
-                return res;
-            }
-            faceIds = entry.data.i32;
-        }
-
-        faces.setCapacity(metadata.number_of_faces);
-
-        for (int i = 0; i < metadata.number_of_faces; i++) {
-            camera_face_t face;
-
-            face.rect[0] = l.mParameters.arrayXToNormalized(faceRects[i*4 + 0]);
-            face.rect[1] = l.mParameters.arrayYToNormalized(faceRects[i*4 + 1]);
-            face.rect[2] = l.mParameters.arrayXToNormalized(faceRects[i*4 + 2]);
-            face.rect[3] = l.mParameters.arrayYToNormalized(faceRects[i*4 + 3]);
-
-            face.score = faceScores[i];
-            if (faceDetectMode == ANDROID_STATS_FACE_DETECTION_FULL) {
-                face.id = faceIds[i];
-                face.left_eye[0] =
-                        l.mParameters.arrayXToNormalized(faceLandmarks[i*6 + 0]);
-                face.left_eye[1] =
-                        l.mParameters.arrayYToNormalized(faceLandmarks[i*6 + 1]);
-                face.right_eye[0] =
-                        l.mParameters.arrayXToNormalized(faceLandmarks[i*6 + 2]);
-                face.right_eye[1] =
-                        l.mParameters.arrayYToNormalized(faceLandmarks[i*6 + 3]);
-                face.mouth[0] =
-                        l.mParameters.arrayXToNormalized(faceLandmarks[i*6 + 4]);
-                face.mouth[1] =
-                        l.mParameters.arrayYToNormalized(faceLandmarks[i*6 + 5]);
-            } else {
-                face.id = 0;
-                face.left_eye[0] = face.left_eye[1] = -2000;
-                face.right_eye[0] = face.right_eye[1] = -2000;
-                face.mouth[0] = face.mouth[1] = -2000;
-            }
-            faces.push_back(face);
-        }
-
-        metadata.faces = faces.editArray();
-    }
-
-    if (metadata.number_of_faces != 0) {
-        Mutex::Autolock iccl(client->mICameraClientLock);
-        if (client->mCameraClient != NULL) {
-            client->mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_METADATA,
-                    NULL, &metadata);
-        }
-    }
-    return OK;
+Camera2Client::SharedCameraClient::SharedCameraClient(const sp<ICameraClient>&client):
+        mCameraClient(client) {
 }
 
-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
-    {
-        Mutex::Autolock iccl(mICameraClientLock);
-        if (mCameraClient != 0) {
-            ALOGV("%s: Camera %d: Invoking client data callback",
-                    __FUNCTION__, mCameraId);
-            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__);
+Camera2Client::SharedCameraClient& Camera2Client::SharedCameraClient::operator=(
+        const sp<ICameraClient>&client) {
+    Mutex::Autolock l(mCameraClientLock);
+    mCameraClient = client;
+    return *this;
 }
 
-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
-    Mutex::Autolock iccl(mICameraClientLock);
-    if (mCameraClient != 0) {
-        mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE,
-                captureHeap->mBuffers[0], NULL);
-    }
+void Camera2Client::SharedCameraClient::clear() {
+    Mutex::Autolock l(mCameraClientLock);
+    mCameraClient.clear();
 }
 
 void Camera2Client::onRecordingFrameAvailable() {
@@ -1951,9 +1637,9 @@
     }
 
     // Call outside locked parameters to allow re-entrancy from notification
-    Mutex::Autolock iccl(mICameraClientLock);
-    if (mCameraClient != 0) {
-        mCameraClient->dataCallbackTimestamp(timestamp,
+    SharedCameraClient::Lock l(mSharedCameraClient);
+    if (l.mCameraClient != 0) {
+        l.mCameraClient->dataCallbackTimestamp(timestamp,
                 CAMERA_MSG_VIDEO_FRAME,
                 recordingHeap->mBuffers[heapIdx]);
     }
@@ -2086,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 4023397..b2fd636 100644
--- a/services/camera/libcameraservice/Camera2Client.h
+++ b/services/camera/libcameraservice/Camera2Client.h
@@ -20,6 +20,9 @@
 #include "Camera2Device.h"
 #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>
@@ -36,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);
@@ -61,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,
@@ -74,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);
@@ -82,6 +91,38 @@
     virtual void notifyAutoExposure(uint8_t newState, int triggerId);
     virtual void notifyAutoWhitebalance(uint8_t newState, int triggerId);
 
+    /**
+     * Interface used by independent components of Camera2Client.
+     */
+
+    int getCameraId();
+    const sp<Camera2Device>& getCameraDevice();
+    camera2::SharedParameters& getParameters();
+
+    // Simple class to ensure that access to ICameraClient is serialized by
+    // requiring mCameraClientLock to be locked before access to mCameraClient
+    // is possible.
+    class SharedCameraClient {
+      public:
+        class Lock {
+          public:
+            Lock(SharedCameraClient &client);
+            ~Lock();
+            sp<ICameraClient> &mCameraClient;
+          private:
+            SharedCameraClient &mSharedClient;
+        };
+        SharedCameraClient(const sp<ICameraClient>& client);
+        SharedCameraClient& operator=(const sp<ICameraClient>& client);
+        void clear();
+      private:
+        sp<ICameraClient> mCameraClient;
+        mutable Mutex mCameraClientLock;
+    } mSharedCameraClient;
+
+    static size_t calculateBufferSize(int width, int height,
+            int format, int stride);
+
 private:
     /** ICamera interface-related private members */
 
@@ -91,11 +132,6 @@
     // they're called
     mutable Mutex mICameraLock;
 
-    // Mutex that must be locked by methods accessing the base Client's
-    // mCameraClient ICameraClient interface member, for sending notifications
-    // up to the camera user
-    mutable Mutex mICameraClientLock;
-
     typedef camera2::Parameters Parameters;
     typedef camera2::CameraMetadata CameraMetadata;
 
@@ -123,37 +159,13 @@
 
     /** Camera device-related private members */
 
-    class Camera2Heap;
-
     void     setPreviewCallbackFlagL(Parameters &params, int flag);
     status_t updateRequests(const Parameters &params);
 
     // Used with stream IDs
     static const int NO_STREAM = -1;
 
-    /* Output frame metadata processing thread.  This thread waits for new
-     * frames from the device, and analyzes them as necessary.
-     */
-    class FrameProcessor: public Thread {
-      public:
-        FrameProcessor(wp<Camera2Client> client);
-        ~FrameProcessor();
-
-        void dump(int fd, const Vector<String16>& args);
-      private:
-        static const nsecs_t kWaitDuration = 10000000; // 10 ms
-        wp<Camera2Client> mClient;
-
-        virtual bool threadLoop();
-
-        void processNewFrames(sp<Camera2Client> &client);
-        status_t processFaceDetect(const CameraMetadata &frame,
-                sp<Camera2Client> &client);
-
-        CameraMetadata mLastFrame;
-    };
-
-    sp<FrameProcessor> mFrameProcessor;
+    sp<camera2::FrameProcessor> mFrameProcessor;
 
     /* Preview related members */
 
@@ -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/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp
index 7cac025..f62c0a0 100644
--- a/services/camera/libcameraservice/Camera2Device.cpp
+++ b/services/camera/libcameraservice/Camera2Device.cpp
@@ -109,7 +109,12 @@
                 __FUNCTION__, mId, strerror(-res), res);
         return res;
     }
-
+    res = set_camera_metadata_vendor_tag_ops(mVendorTagOps);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to set tag ops: %s (%d)",
+            __FUNCTION__, mId, strerror(-res), res);
+        return res;
+    }
     setNotifyCallback(NULL);
 
     return OK;
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/FrameProcessor.cpp b/services/camera/libcameraservice/camera2/FrameProcessor.cpp
new file mode 100644
index 0000000..5059754
--- /dev/null
+++ b/services/camera/libcameraservice/camera2/FrameProcessor.cpp
@@ -0,0 +1,214 @@
+/*
+ * 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::FrameProcessor"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include "FrameProcessor.h"
+#include "../Camera2Device.h"
+#include "../Camera2Client.h"
+
+namespace android {
+namespace camera2 {
+
+FrameProcessor::FrameProcessor(wp<Camera2Client> client):
+        Thread(false), mClient(client) {
+}
+
+FrameProcessor::~FrameProcessor() {
+    ALOGV("%s: Exit", __FUNCTION__);
+}
+
+void FrameProcessor::dump(int fd, const Vector<String16>& args) {
+    String8 result("    Latest received frame:\n");
+    write(fd, result.string(), result.size());
+    mLastFrame.dump(fd, 2, 6);
+}
+
+bool FrameProcessor::threadLoop() {
+    status_t res;
+
+    sp<Camera2Device> device;
+    {
+        sp<Camera2Client> client = mClient.promote();
+        if (client == 0) return false;
+        device = client->getCameraDevice();
+    }
+
+    res = device->waitForNextFrame(kWaitDuration);
+    if (res == OK) {
+        sp<Camera2Client> client = mClient.promote();
+        if (client == 0) return false;
+        processNewFrames(client);
+    } else if (res != TIMED_OUT) {
+        ALOGE("Camera2Client::FrameProcessor: Error waiting for new "
+                "frames: %s (%d)", strerror(-res), res);
+    }
+
+    return true;
+}
+
+void FrameProcessor::processNewFrames(sp<Camera2Client> &client) {
+    status_t res;
+    CameraMetadata frame;
+    while ( (res = client->getCameraDevice()->getNextFrame(&frame)) == OK) {
+        camera_metadata_entry_t entry;
+        entry = frame.find(ANDROID_REQUEST_FRAME_COUNT);
+        if (entry.count == 0) {
+            ALOGE("%s: Camera %d: Error reading frame number: %s (%d)",
+                    __FUNCTION__, client->getCameraId(), strerror(-res), res);
+            break;
+        }
+
+        res = processFaceDetect(frame, client);
+        if (res != OK) break;
+
+        mLastFrame.acquire(frame);
+    }
+    if (res != NOT_ENOUGH_DATA) {
+        ALOGE("%s: Camera %d: Error getting next frame: %s (%d)",
+                __FUNCTION__, client->getCameraId(), strerror(-res), res);
+        return;
+    }
+
+    return;
+}
+
+status_t FrameProcessor::processFaceDetect(
+    const CameraMetadata &frame, sp<Camera2Client> &client) {
+    status_t res;
+    camera_metadata_ro_entry_t entry;
+    bool enableFaceDetect;
+    int maxFaces;
+    {
+        SharedParameters::Lock l(client->getParameters());
+        enableFaceDetect = l.mParameters.enableFaceDetect;
+    }
+    entry = frame.find(ANDROID_STATS_FACE_DETECT_MODE);
+
+    // TODO: This should be an error once implementations are compliant
+    if (entry.count == 0) {
+        return OK;
+    }
+
+    uint8_t faceDetectMode = entry.data.u8[0];
+
+    camera_frame_metadata metadata;
+    Vector<camera_face_t> faces;
+    metadata.number_of_faces = 0;
+
+    if (enableFaceDetect && faceDetectMode != ANDROID_STATS_FACE_DETECTION_OFF) {
+        SharedParameters::Lock l(client->getParameters());
+        entry = frame.find(ANDROID_STATS_FACE_RECTANGLES);
+        if (entry.count == 0) {
+            ALOGE("%s: Camera %d: Unable to read face rectangles",
+                    __FUNCTION__, client->getCameraId());
+            return res;
+        }
+        metadata.number_of_faces = entry.count / 4;
+        if (metadata.number_of_faces >
+                l.mParameters.fastInfo.maxFaces) {
+            ALOGE("%s: Camera %d: More faces than expected! (Got %d, max %d)",
+                    __FUNCTION__, client->getCameraId(),
+                    metadata.number_of_faces, l.mParameters.fastInfo.maxFaces);
+            return res;
+        }
+        const int32_t *faceRects = entry.data.i32;
+
+        entry = frame.find(ANDROID_STATS_FACE_SCORES);
+        if (entry.count == 0) {
+            ALOGE("%s: Camera %d: Unable to read face scores",
+                    __FUNCTION__, client->getCameraId());
+            return res;
+        }
+        const uint8_t *faceScores = entry.data.u8;
+
+        const int32_t *faceLandmarks = NULL;
+        const int32_t *faceIds = NULL;
+
+        if (faceDetectMode == ANDROID_STATS_FACE_DETECTION_FULL) {
+            entry = frame.find(ANDROID_STATS_FACE_LANDMARKS);
+            if (entry.count == 0) {
+                ALOGE("%s: Camera %d: Unable to read face landmarks",
+                        __FUNCTION__, client->getCameraId());
+                return res;
+            }
+            faceLandmarks = entry.data.i32;
+
+            entry = frame.find(ANDROID_STATS_FACE_IDS);
+
+            if (entry.count == 0) {
+                ALOGE("%s: Camera %d: Unable to read face IDs",
+                        __FUNCTION__, client->getCameraId());
+                return res;
+            }
+            faceIds = entry.data.i32;
+        }
+
+        faces.setCapacity(metadata.number_of_faces);
+
+        for (int i = 0; i < metadata.number_of_faces; i++) {
+            camera_face_t face;
+
+            face.rect[0] = l.mParameters.arrayXToNormalized(faceRects[i*4 + 0]);
+            face.rect[1] = l.mParameters.arrayYToNormalized(faceRects[i*4 + 1]);
+            face.rect[2] = l.mParameters.arrayXToNormalized(faceRects[i*4 + 2]);
+            face.rect[3] = l.mParameters.arrayYToNormalized(faceRects[i*4 + 3]);
+
+            face.score = faceScores[i];
+            if (faceDetectMode == ANDROID_STATS_FACE_DETECTION_FULL) {
+                face.id = faceIds[i];
+                face.left_eye[0] =
+                        l.mParameters.arrayXToNormalized(faceLandmarks[i*6 + 0]);
+                face.left_eye[1] =
+                        l.mParameters.arrayYToNormalized(faceLandmarks[i*6 + 1]);
+                face.right_eye[0] =
+                        l.mParameters.arrayXToNormalized(faceLandmarks[i*6 + 2]);
+                face.right_eye[1] =
+                        l.mParameters.arrayYToNormalized(faceLandmarks[i*6 + 3]);
+                face.mouth[0] =
+                        l.mParameters.arrayXToNormalized(faceLandmarks[i*6 + 4]);
+                face.mouth[1] =
+                        l.mParameters.arrayYToNormalized(faceLandmarks[i*6 + 5]);
+            } else {
+                face.id = 0;
+                face.left_eye[0] = face.left_eye[1] = -2000;
+                face.right_eye[0] = face.right_eye[1] = -2000;
+                face.mouth[0] = face.mouth[1] = -2000;
+            }
+            faces.push_back(face);
+        }
+
+        metadata.faces = faces.editArray();
+    }
+
+    if (metadata.number_of_faces != 0) {
+        Camera2Client::SharedCameraClient::Lock l(client->mSharedCameraClient);
+        if (l.mCameraClient != NULL) {
+            l.mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_METADATA,
+                    NULL, &metadata);
+        }
+    }
+    return OK;
+}
+
+
+}; // namespace camera2
+}; // namespace android
diff --git a/services/camera/libcameraservice/camera2/FrameProcessor.h b/services/camera/libcameraservice/camera2/FrameProcessor.h
new file mode 100644
index 0000000..2cdf7f0
--- /dev/null
+++ b/services/camera/libcameraservice/camera2/FrameProcessor.h
@@ -0,0 +1,57 @@
+/*
+ * 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_FRAMEPROCESSOR_H
+#define ANDROID_SERVERS_CAMERA_CAMERA2_FRAMEPROCESSOR_H
+
+#include <utils/Thread.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+#include "CameraMetadata.h"
+
+namespace android {
+
+class Camera2Client;
+
+namespace camera2 {
+
+/* Output frame metadata processing thread.  This thread waits for new
+ * frames from the device, and analyzes them as necessary.
+ */
+class FrameProcessor: public Thread {
+  public:
+    FrameProcessor(wp<Camera2Client> client);
+    ~FrameProcessor();
+
+    void dump(int fd, const Vector<String16>& args);
+  private:
+    static const nsecs_t kWaitDuration = 10000000; // 10 ms
+    wp<Camera2Client> mClient;
+
+    virtual bool threadLoop();
+
+    void processNewFrames(sp<Camera2Client> &client);
+    status_t processFaceDetect(const CameraMetadata &frame,
+            sp<Camera2Client> &client);
+
+    CameraMetadata mLastFrame;
+};
+
+
+}; //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