Merge "Update the test output path." into jb-mr2-dev
diff --git a/camera/Android.mk b/camera/Android.mk
index e33fb50..fa518ff 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -22,6 +22,7 @@
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
 	libutils \
+	liblog \
 	libbinder \
 	libhardware \
 	libui \
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index d583e65..3844487 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -9,7 +9,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	libstagefright libmedia libutils libbinder libstagefright_foundation \
-        libjpeg libgui libcutils
+        libjpeg libgui libcutils liblog
 
 LOCAL_C_INCLUDES:= \
 	frameworks/av/media/libstagefright \
@@ -187,4 +187,3 @@
 LOCAL_MODULE:= muxer
 
 include $(BUILD_EXECUTABLE)
-
diff --git a/drm/drmserver/Android.mk b/drm/drmserver/Android.mk
index 96205a1..dc973da 100644
--- a/drm/drmserver/Android.mk
+++ b/drm/drmserver/Android.mk
@@ -24,6 +24,7 @@
 LOCAL_SHARED_LIBRARIES := \
     libmedia \
     libutils \
+    liblog \
     libbinder \
     libdl
 
diff --git a/drm/libdrmframework/Android.mk b/drm/libdrmframework/Android.mk
index 9e07fe3..49c4f9b 100644
--- a/drm/libdrmframework/Android.mk
+++ b/drm/libdrmframework/Android.mk
@@ -25,6 +25,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
     libutils \
+    liblog \
     libbinder \
     libdl
 
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
index 205b9a5..e251f82 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
@@ -36,6 +36,7 @@
     libicui18n \
     libicuuc \
     libutils \
+    liblog \
     libdl \
     libcrypto \
     libssl \
diff --git a/drm/libdrmframework/plugins/passthru/Android.mk b/drm/libdrmframework/plugins/passthru/Android.mk
index d170d49..cb3a2e2 100644
--- a/drm/libdrmframework/plugins/passthru/Android.mk
+++ b/drm/libdrmframework/plugins/passthru/Android.mk
@@ -25,6 +25,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
     libutils \
+    liblog \
     libdl
 
 
diff --git a/drm/mediadrm/plugins/mock/Android.mk b/drm/mediadrm/plugins/mock/Android.mk
index a056cd8..ada23a2 100644
--- a/drm/mediadrm/plugins/mock/Android.mk
+++ b/drm/mediadrm/plugins/mock/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_SHARED_LIBRARIES)/mediadrm
 
 LOCAL_SHARED_LIBRARIES := \
-    libutils
+    libutils liblog
 
 LOCAL_C_INCLUDES += \
     $(TOP)/frameworks/av/include \
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 96baf34..5cfe5bc 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -46,6 +46,7 @@
         kWhatInputSurfaceCreated = 'isfc',
         kWhatSignaledInputEOS    = 'seos',
         kWhatBuffersAllocated    = 'allc',
+        kWhatOMXDied             = 'OMXd',
     };
 
     ACodec();
@@ -97,6 +98,7 @@
     struct ExecutingToIdleState;
     struct IdleToLoadedState;
     struct FlushingState;
+    struct DeathNotifier;
 
     enum {
         kWhatSetup                   = 'setu',
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index b0c1b34..742bc0e 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -54,6 +54,7 @@
 
     // Convenience methods:
     bool getUInt16(off64_t offset, uint16_t *x);
+    bool getUInt24(off64_t offset, uint32_t *x); // 3 byte int, returned as a 32-bit int
     bool getUInt32(off64_t offset, uint32_t *x);
     bool getUInt64(off64_t offset, uint64_t *x);
 
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index be08c19..9ab3edc 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -157,6 +157,10 @@
     kKeyCryptoKey         = 'cryK',  // uint8_t[16]
     kKeyCryptoIV          = 'cryI',  // uint8_t[16]
     kKeyCryptoMode        = 'cryM',  // int32_t
+
+    kKeyCryptoDefaultIVSize = 'cryS',  // int32_t
+
+    kKeyPssh              = 'pssh',  // raw data
 };
 
 enum {
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index 0833110..5ae6f6b 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -55,6 +55,8 @@
     size_t countTracks() const;
     status_t getTrackFormat(size_t index, sp<AMessage> *format) const;
 
+    status_t getFileFormat(sp<AMessage> *format) const;
+
     status_t selectTrack(size_t index);
     status_t unselectTrack(size_t index);
 
diff --git a/libvideoeditor/lvpp/Android.mk b/libvideoeditor/lvpp/Android.mk
index 778c5ac..2286827 100755
--- a/libvideoeditor/lvpp/Android.mk
+++ b/libvideoeditor/lvpp/Android.mk
@@ -50,6 +50,7 @@
     libaudioutils             \
     libbinder                 \
     libcutils                 \
+    liblog                    \
     libEGL                    \
     libGLESv2                 \
     libgui                    \
diff --git a/libvideoeditor/osal/src/Android.mk b/libvideoeditor/osal/src/Android.mk
index b73b9ae..4f38b0c 100755
--- a/libvideoeditor/osal/src/Android.mk
+++ b/libvideoeditor/osal/src/Android.mk
@@ -41,7 +41,7 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SHARED_LIBRARIES := libcutils libutils
+LOCAL_SHARED_LIBRARIES := libcutils libutils liblog
 
 LOCAL_C_INCLUDES += \
     $(TOP)/frameworks/av/libvideoeditor/osal/inc \
@@ -64,4 +64,3 @@
     -DUSE_STAGEFRIGHT_3GPP_READER
 
 include $(BUILD_SHARED_LIBRARY)
-
diff --git a/libvideoeditor/vss/src/Android.mk b/libvideoeditor/vss/src/Android.mk
index cda7a83..0caa15b 100755
--- a/libvideoeditor/vss/src/Android.mk
+++ b/libvideoeditor/vss/src/Android.mk
@@ -57,6 +57,7 @@
     libaudioutils               \
     libbinder                   \
     libcutils                   \
+    liblog                      \
     libmedia                    \
     libstagefright              \
     libstagefright_foundation   \
@@ -96,4 +97,3 @@
     -DDECODE_GIF_ON_SAVING
 
 include $(BUILD_SHARED_LIBRARY)
-
diff --git a/media/common_time/Android.mk b/media/common_time/Android.mk
index 526f17b..632acbc 100644
--- a/media/common_time/Android.mk
+++ b/media/common_time/Android.mk
@@ -16,6 +16,7 @@
                    utils.cpp
 LOCAL_SHARED_LIBRARIES := libbinder \
                           libhardware \
-                          libutils
+                          libutils \
+                          liblog
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/downmix/Android.mk b/media/libeffects/downmix/Android.mk
index 3052ad9..5d0a87c 100644
--- a/media/libeffects/downmix/Android.mk
+++ b/media/libeffects/downmix/Android.mk
@@ -7,7 +7,7 @@
 	EffectDownmix.c
 
 LOCAL_SHARED_LIBRARIES := \
-	libcutils
+	libcutils liblog
 
 LOCAL_MODULE:= libdownmix
 
diff --git a/media/libeffects/factory/Android.mk b/media/libeffects/factory/Android.mk
index 6e69151..60a6ce5 100644
--- a/media/libeffects/factory/Android.mk
+++ b/media/libeffects/factory/Android.mk
@@ -7,7 +7,7 @@
 	EffectsFactory.c
 
 LOCAL_SHARED_LIBRARIES := \
-	libcutils
+	libcutils liblog
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
 LOCAL_MODULE:= libeffects
diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk
index dfa1711..c344352 100644
--- a/media/libeffects/preprocessing/Android.mk
+++ b/media/libeffects/preprocessing/Android.mk
@@ -21,7 +21,8 @@
 LOCAL_SHARED_LIBRARIES := \
     libwebrtc_audio_preprocessing \
     libspeexresampler \
-    libutils
+    libutils \
+    liblog
 
 ifeq ($(TARGET_SIMULATOR),true)
 LOCAL_LDLIBS += -ldl
diff --git a/media/libeffects/visualizer/Android.mk b/media/libeffects/visualizer/Android.mk
index 49cf4fa..e196eb2 100644
--- a/media/libeffects/visualizer/Android.mk
+++ b/media/libeffects/visualizer/Android.mk
@@ -10,6 +10,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
+	liblog \
 	libdl
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index fbe71ad..2c0c3a5 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -63,7 +63,7 @@
 LOCAL_CFLAGS += -DSINGLE_STATE_QUEUE_INSTANTIATIONS='"SingleStateQueueInstantiations.cpp"'
 
 LOCAL_SHARED_LIBRARIES := \
-	libui libcutils libutils libbinder libsonivox libicuuc libexpat \
+	libui liblog libcutils libutils libbinder libsonivox libicuuc libexpat \
         libcamera_client libstagefright_foundation \
         libgui libdl libaudioutils
 
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 2a6f3c7..d87bc7f 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -27,6 +27,7 @@
     libbinder                   \
     libcamera_client            \
     libcutils                   \
+    liblog                      \
     libdl                       \
     libgui                      \
     libmedia                    \
diff --git a/media/libnbaio/Android.mk b/media/libnbaio/Android.mk
index d372d20..5d00d15 100644
--- a/media/libnbaio/Android.mk
+++ b/media/libnbaio/Android.mk
@@ -30,6 +30,7 @@
     libbinder \
     libcommon_time_client \
     libcutils \
-    libutils
+    libutils \
+    liblog
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index ff72b71..ee49033 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -166,6 +166,24 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+struct ACodec::DeathNotifier : public IBinder::DeathRecipient {
+    DeathNotifier(const sp<AMessage> &notify)
+        : mNotify(notify) {
+    }
+
+    virtual void binderDied(const wp<IBinder> &) {
+        mNotify->post();
+    }
+
+protected:
+    virtual ~DeathNotifier() {}
+
+private:
+    sp<AMessage> mNotify;
+
+    DISALLOW_EVIL_CONSTRUCTORS(DeathNotifier);
+};
+
 struct ACodec::UninitializedState : public ACodec::BaseState {
     UninitializedState(ACodec *codec);
 
@@ -177,6 +195,8 @@
     void onSetup(const sp<AMessage> &msg);
     bool onAllocateComponent(const sp<AMessage> &msg);
 
+    sp<DeathNotifier> mDeathNotifier;
+
     DISALLOW_EVIL_CONSTRUCTORS(UninitializedState);
 };
 
@@ -1432,14 +1452,6 @@
     CHECK_EQ(err, (status_t)OK);
     CHECK_EQ((int)format.eCompressionFormat, (int)OMX_VIDEO_CodingUnused);
 
-    CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
-           || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
-           || format.eColorFormat == OMX_COLOR_FormatCbYCrY
-           || format.eColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar
-           || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
-           || format.eColorFormat == OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka
-           || format.eColorFormat == OMX_SEC_COLOR_FormatNV12Tiled);
-
     return mOMX->setParameter(
             mNode, OMX_IndexParamVideoPortFormat,
             &format, sizeof(format));
@@ -2487,6 +2499,13 @@
             return true;
         }
 
+        case ACodec::kWhatOMXDied:
+        {
+            ALOGE("OMX/mediaserver died, signalling error!");
+            mCodec->signalError(OMX_ErrorResourcesLost, DEAD_OBJECT);
+            break;
+        }
+
         default:
             return false;
     }
@@ -3035,6 +3054,18 @@
 
 void ACodec::UninitializedState::stateEntered() {
     ALOGV("Now uninitialized");
+
+    if (mDeathNotifier != NULL) {
+        mCodec->mOMX->asBinder()->unlinkToDeath(mDeathNotifier);
+        mDeathNotifier.clear();
+    }
+
+    mCodec->mNativeWindow.clear();
+    mCodec->mNode = NULL;
+    mCodec->mOMX.clear();
+    mCodec->mQuirks = 0;
+    mCodec->mFlags = 0;
+    mCodec->mComponentName.clear();
 }
 
 bool ACodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) {
@@ -3106,6 +3137,15 @@
 
     sp<IOMX> omx = client.interface();
 
+    sp<AMessage> notify = new AMessage(kWhatOMXDied, mCodec->id());
+
+    mDeathNotifier = new DeathNotifier(notify);
+    if (omx->asBinder()->linkToDeath(mDeathNotifier) != OK) {
+        // This was a local binder, if it dies so do we, we won't care
+        // about any notifications in the afterlife.
+        mDeathNotifier.clear();
+    }
+
     Vector<OMXCodec::CodecNameAndQuirks> matchingCodecs;
 
     AString mime;
@@ -3170,7 +3210,7 @@
         return false;
     }
 
-    sp<AMessage> notify = new AMessage(kWhatOMXMessage, mCodec->id());
+    notify = new AMessage(kWhatOMXMessage, mCodec->id());
     observer->setNotificationMessage(notify);
 
     mCodec->mComponentName = componentName;
@@ -3224,13 +3264,6 @@
     if (!keepComponentAllocated) {
         CHECK_EQ(mCodec->mOMX->freeNode(mCodec->mNode), (status_t)OK);
 
-        mCodec->mNativeWindow.clear();
-        mCodec->mNode = NULL;
-        mCodec->mOMX.clear();
-        mCodec->mQuirks = 0;
-        mCodec->mFlags = 0;
-        mCodec->mComponentName.clear();
-
         mCodec->changeState(mCodec->mUninitializedState);
     }
 
@@ -3626,7 +3659,6 @@
                      (status_t)OK);
 
             mCodec->changeState(mCodec->mFlushingState);
-
             handled = true;
             break;
         }
@@ -4141,6 +4173,10 @@
 
         mCodec->mInputEOSResult = OK;
 
+        if (mCodec->mSkipCutBuffer != NULL) {
+            mCodec->mSkipCutBuffer->clear();
+        }
+
         mCodec->changeState(mCodec->mExecutingState);
     }
 }
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 19b38ee..fc6fd9c 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -58,6 +58,19 @@
     return true;
 }
 
+bool DataSource::getUInt24(off64_t offset, uint32_t *x) {
+    *x = 0;
+
+    uint8_t byte[3];
+    if (readAt(offset, byte, 3) != 3) {
+        return false;
+    }
+
+    *x = (byte[0] << 16) | (byte[1] << 8) | byte[2];
+
+    return true;
+}
+
 bool DataSource::getUInt32(off64_t offset, uint32_t *x) {
     *x = 0;
 
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 56fad60..3503aaf 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -78,6 +78,19 @@
     int32_t mLastParsedTrackId;
     int32_t mTrackId;
 
+    int32_t mCryptoMode;    // passed in from extractor
+    int32_t mDefaultIVSize; // passed in from extractor
+    uint8_t mCryptoKey[16]; // passed in from extractor
+    uint32_t mCurrentAuxInfoType;
+    uint32_t mCurrentAuxInfoTypeParameter;
+    uint32_t mCurrentDefaultSampleInfoSize;
+    uint32_t mCurrentSampleInfoCount;
+    uint32_t mCurrentSampleInfoAllocSize;
+    uint8_t* mCurrentSampleInfoSizes;
+    uint32_t mCurrentSampleInfoOffsetCount;
+    uint32_t mCurrentSampleInfoOffsetsAllocSize;
+    uint64_t* mCurrentSampleInfoOffsets;
+
     bool mIsAVC;
     size_t mNALLengthSize;
 
@@ -95,6 +108,8 @@
     status_t parseChunk(off64_t *offset);
     status_t parseTrackFragmentHeader(off64_t offset, off64_t size);
     status_t parseTrackFragmentRun(off64_t offset, off64_t size);
+    status_t parseSampleAuxiliaryInformationSizes(off64_t offset, off64_t size);
+    status_t parseSampleAuxiliaryInformationOffsets(off64_t offset, off64_t size);
 
     struct TrackFragmentHeaderInfo {
         enum Flags {
@@ -122,6 +137,9 @@
         off64_t offset;
         size_t size;
         uint32_t duration;
+        uint8_t iv[16];
+        Vector<size_t> clearsizes;
+        Vector<size_t> encryptedsizes;
     };
     Vector<Sample> mCurrentSamples;
 
@@ -333,6 +351,10 @@
         sinf = next;
     }
     mFirstSINF = NULL;
+
+    for (size_t i = 0; i < mPssh.size(); i++) {
+        delete [] mPssh[i].data;
+    }
 }
 
 uint32_t MPEG4Extractor::flags() const {
@@ -353,6 +375,7 @@
 size_t MPEG4Extractor::countTracks() {
     status_t err;
     if ((err = readMetaData()) != OK) {
+        ALOGV("MPEG4Extractor::countTracks: no tracks");
         return 0;
     }
 
@@ -363,6 +386,7 @@
         track = track->next;
     }
 
+    ALOGV("MPEG4Extractor::countTracks: %d tracks", n);
     return n;
 }
 
@@ -461,6 +485,23 @@
     }
 
     CHECK_NE(err, (status_t)NO_INIT);
+
+    // copy pssh data into file metadata
+    int psshsize = 0;
+    for (size_t i = 0; i < mPssh.size(); i++) {
+        psshsize += 20 + mPssh[i].datalen;
+    }
+    if (psshsize) {
+        char *buf = (char*)malloc(psshsize);
+        char *ptr = buf;
+        for (size_t i = 0; i < mPssh.size(); i++) {
+            memcpy(ptr, mPssh[i].uuid, 20); // uuid + length
+            memcpy(ptr + 20, mPssh[i].data, mPssh[i].datalen);
+            ptr += (20 + mPssh[i].datalen);
+        }
+        mFileMetaData->setData(kKeyPssh, 'pssh', buf, psshsize);
+        free(buf);
+    }
     return mInitCheck;
 }
 
@@ -759,6 +800,8 @@
         case FOURCC('m', 'f', 'r', 'a'):
         case FOURCC('u', 'd', 't', 'a'):
         case FOURCC('i', 'l', 's', 't'):
+        case FOURCC('s', 'i', 'n', 'f'):
+        case FOURCC('s', 'c', 'h', 'i'):
         {
             if (chunk_type == FOURCC('s', 't', 'b', 'l')) {
                 ALOGV("sampleTable chunk is %d bytes long.", (size_t)chunk_size);
@@ -846,6 +889,69 @@
             break;
         }
 
+        case FOURCC('f', 'r', 'm', 'a'):
+        {
+            int32_t original_fourcc;
+            if (mDataSource->readAt(data_offset, &original_fourcc, 4) < 4) {
+                return ERROR_IO;
+            }
+            original_fourcc = ntohl(original_fourcc);
+            ALOGV("read original format: %d", original_fourcc);
+            mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(original_fourcc));
+            *offset += chunk_size;
+            break;
+        }
+
+        case FOURCC('t', 'e', 'n', 'c'):
+        {
+            if (chunk_size < 32) {
+                return ERROR_MALFORMED;
+            }
+
+            // tenc box contains 1 byte version, 3 byte flags, 3 byte default algorithm id, one byte
+            // default IV size, 16 bytes default KeyID
+            // (ISO 23001-7)
+            char buf[4];
+            memset(buf, 0, 4);
+            if (mDataSource->readAt(data_offset + 4, buf + 1, 3) < 3) {
+                return ERROR_IO;
+            }
+            uint32_t defaultAlgorithmId = ntohl(*((int32_t*)buf));
+            if (defaultAlgorithmId > 1) {
+                // only 0 (clear) and 1 (AES-128) are valid
+                return ERROR_MALFORMED;
+            }
+
+            memset(buf, 0, 4);
+            if (mDataSource->readAt(data_offset + 7, buf + 3, 1) < 1) {
+                return ERROR_IO;
+            }
+            uint32_t defaultIVSize = ntohl(*((int32_t*)buf));
+
+            if ((defaultAlgorithmId == 0 && defaultIVSize != 0) ||
+                    (defaultAlgorithmId != 0 && defaultIVSize == 0)) {
+                // only unencrypted data must have 0 IV size
+                return ERROR_MALFORMED;
+            } else if (defaultIVSize != 0 &&
+                    defaultIVSize != 8 &&
+                    defaultIVSize != 16) {
+                // only supported sizes are 0, 8 and 16
+                return ERROR_MALFORMED;
+            }
+
+            uint8_t defaultKeyId[16];
+
+            if (mDataSource->readAt(data_offset + 8, &defaultKeyId, 16) < 16) {
+                return ERROR_IO;
+            }
+
+            mLastTrack->meta->setInt32(kKeyCryptoMode, defaultAlgorithmId);
+            mLastTrack->meta->setInt32(kKeyCryptoDefaultIVSize, defaultIVSize);
+            mLastTrack->meta->setData(kKeyCryptoKey, 'tenc', defaultKeyId, 16);
+            *offset += chunk_size;
+            break;
+        }
+
         case FOURCC('t', 'k', 'h', 'd'):
         {
             status_t err;
@@ -857,6 +963,37 @@
             break;
         }
 
+        case FOURCC('p', 's', 's', 'h'):
+        {
+            PsshInfo pssh;
+
+            if (mDataSource->readAt(data_offset + 4, &pssh.uuid, 16) < 16) {
+                return ERROR_IO;
+            }
+
+            uint32_t psshdatalen = 0;
+            if (mDataSource->readAt(data_offset + 20, &psshdatalen, 4) < 4) {
+                return ERROR_IO;
+            }
+            pssh.datalen = ntohl(psshdatalen);
+            ALOGV("pssh data size: %d", pssh.datalen);
+            if (pssh.datalen + 20 > chunk_size) {
+                // pssh data length exceeds size of containing box
+                return ERROR_MALFORMED;
+            }
+
+            pssh.data = new uint8_t[pssh.datalen];
+            ALOGV("allocated pssh @ %p", pssh.data);
+            ssize_t requested = (ssize_t) pssh.datalen;
+            if (mDataSource->readAt(data_offset + 24, pssh.data, requested) < requested) {
+                return ERROR_IO;
+            }
+            mPssh.push_back(pssh);
+
+            *offset += chunk_size;
+            break;
+        }
+
         case FOURCC('m', 'd', 'h', 'd'):
         {
             if (chunk_data_size < 4) {
@@ -970,16 +1107,17 @@
                 // For 3GPP timed text, there could be multiple tx3g boxes contain
                 // multiple text display formats. These formats will be used to
                 // display the timed text.
+                // For encrypted files, there may also be more than one entry.
                 const char *mime;
                 CHECK(mLastTrack->meta->findCString(kKeyMIMEType, &mime));
-                if (strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
+                if (strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) &&
+                        strcasecmp(mime, "application/octet-stream")) {
                     // For now we only support a single type of media per track.
                     mLastTrack->skipTrack = true;
                     *offset += chunk_size;
                     break;
                 }
             }
-
             off64_t stop_offset = *offset + chunk_size;
             *offset = data_offset + 8;
             for (uint32_t i = 0; i < entry_count; ++i) {
@@ -1053,6 +1191,7 @@
         }
 
         case FOURCC('m', 'p', '4', 'v'):
+        case FOURCC('e', 'n', 'c', 'v'):
         case FOURCC('s', '2', '6', '3'):
         case FOURCC('H', '2', '6', '3'):
         case FOURCC('h', '2', '6', '3'):
@@ -1075,7 +1214,7 @@
             uint16_t width = U16_AT(&buffer[6 + 18]);
             uint16_t height = U16_AT(&buffer[6 + 20]);
 
-            // The video sample is not stand-compliant if it has invalid dimension.
+            // The video sample is not standard-compliant if it has invalid dimension.
             // Use some default width and height value, and
             // let the decoder figure out the actual width and height (and thus
             // be prepared for INFO_FOMRAT_CHANGED event).
@@ -1085,7 +1224,10 @@
             // printf("*** coding='%s' width=%d height=%d\n",
             //        chunk, width, height);
 
-            mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
+            if (chunk_type != FOURCC('e', 'n', 'c', 'v')) {
+                // if the chunk type is encv, we'll get the type from the sinf/frma box later
+                mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
+            }
             mLastTrack->meta->setInt32(kKeyWidth, width);
             mLastTrack->meta->setInt32(kKeyHeight, height);
 
@@ -1442,6 +1584,7 @@
 
         case FOURCC('m', 'd', 'a', 't'):
         {
+            ALOGV("mdat chunk, drm: %d", mIsDrm);
             if (!mIsDrm) {
                 *offset += chunk_size;
                 break;
@@ -1968,6 +2111,8 @@
         return NULL;
     }
 
+    ALOGV("getTrack called, pssh: %d", mPssh.size());
+
     return new MPEG4Source(
             track->meta, mDataSource, track->timescale, track->sampleTable,
             mSidxEntries, mMoofOffset);
@@ -2139,6 +2284,10 @@
       mFirstMoofOffset(firstMoofOffset),
       mCurrentMoofOffset(firstMoofOffset),
       mCurrentTime(0),
+      mCurrentSampleInfoAllocSize(0),
+      mCurrentSampleInfoSizes(NULL),
+      mCurrentSampleInfoOffsetsAllocSize(0),
+      mCurrentSampleInfoOffsets(NULL),
       mIsAVC(false),
       mNALLengthSize(0),
       mStarted(false),
@@ -2146,6 +2295,18 @@
       mBuffer(NULL),
       mWantsNALFragments(false),
       mSrcBuffer(NULL) {
+
+    mFormat->findInt32(kKeyCryptoMode, &mCryptoMode);
+    mFormat->findInt32(kKeyCryptoDefaultIVSize, &mDefaultIVSize);
+    uint32_t keytype;
+    const void *key;
+    size_t keysize;
+    if (mFormat->findData(kKeyCryptoKey, &keytype, &key, &keysize)) {
+        CHECK(keysize <= 16);
+        memset(mCryptoKey, 0, 16);
+        memcpy(mCryptoKey, key, keysize);
+    }
+
     const char *mime;
     bool success = mFormat->findCString(kKeyMIMEType, &mime);
     CHECK(success);
@@ -2179,6 +2340,8 @@
     if (mStarted) {
         stop();
     }
+    free(mCurrentSampleInfoSizes);
+    free(mCurrentSampleInfoOffsets);
 }
 
 status_t MPEG4Source::start(MetaData *params) {
@@ -2274,7 +2437,7 @@
                 }
             }
             if (chunk_type == FOURCC('m', 'o', 'o', 'f')) {
-                // *offset points to then mdat box following this moof
+                // *offset points to the mdat box following this moof
                 parseChunk(offset); // doesn't actually parse it, just updates offset
                 mNextMoofOffset = *offset;
             }
@@ -2302,6 +2465,31 @@
                 break;
         }
 
+        case FOURCC('s', 'a', 'i', 'z'): {
+            status_t err;
+            if ((err = parseSampleAuxiliaryInformationSizes(data_offset, chunk_data_size)) != OK) {
+                return err;
+            }
+            *offset += chunk_size;
+            break;
+        }
+        case FOURCC('s', 'a', 'i', 'o'): {
+            status_t err;
+            if ((err = parseSampleAuxiliaryInformationOffsets(data_offset, chunk_data_size)) != OK) {
+                return err;
+            }
+            *offset += chunk_size;
+            break;
+        }
+
+        case FOURCC('m', 'd', 'a', 't'): {
+            // parse DRM info if present
+            ALOGV("MPEG4Source::parseChunk mdat");
+            // if saiz/saoi was previously observed, do something with the sampleinfos
+            *offset += chunk_size;
+            break;
+        }
+
         default: {
             *offset += chunk_size;
             break;
@@ -2310,6 +2498,152 @@
     return OK;
 }
 
+status_t MPEG4Source::parseSampleAuxiliaryInformationSizes(off64_t offset, off64_t size) {
+    ALOGV("parseSampleAuxiliaryInformationSizes");
+    // 14496-12 8.7.12
+    uint8_t version;
+    if (mDataSource->readAt(
+            offset, &version, sizeof(version))
+            < (ssize_t)sizeof(version)) {
+        return ERROR_IO;
+    }
+
+    if (version != 0) {
+        return ERROR_UNSUPPORTED;
+    }
+    offset++;
+
+    uint32_t flags;
+    if (!mDataSource->getUInt24(offset, &flags)) {
+        return ERROR_IO;
+    }
+    offset += 3;
+
+    if (flags & 1) {
+        uint32_t tmp;
+        if (!mDataSource->getUInt32(offset, &tmp)) {
+            return ERROR_MALFORMED;
+        }
+        mCurrentAuxInfoType = tmp;
+        offset += 4;
+        if (!mDataSource->getUInt32(offset, &tmp)) {
+            return ERROR_MALFORMED;
+        }
+        mCurrentAuxInfoTypeParameter = tmp;
+        offset += 4;
+    }
+
+    uint8_t defsize;
+    if (mDataSource->readAt(offset, &defsize, 1) != 1) {
+        return ERROR_MALFORMED;
+    }
+    mCurrentDefaultSampleInfoSize = defsize;
+    offset++;
+
+    uint32_t smplcnt;
+    if (!mDataSource->getUInt32(offset, &smplcnt)) {
+        return ERROR_MALFORMED;
+    }
+    offset += 4;
+
+    if (smplcnt > mCurrentSampleInfoAllocSize) {
+        mCurrentSampleInfoSizes = (uint8_t*) realloc(mCurrentSampleInfoSizes, smplcnt);
+        mCurrentSampleInfoAllocSize = smplcnt;
+    }
+    mCurrentSampleInfoCount = smplcnt;
+
+    mDataSource->readAt(offset, mCurrentSampleInfoSizes, smplcnt);
+    return OK;
+}
+
+status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(off64_t offset, off64_t size) {
+    ALOGV("parseSampleAuxiliaryInformationOffsets");
+    // 14496-12 8.7.13
+    uint8_t version;
+    if (mDataSource->readAt(offset, &version, sizeof(version)) != 1) {
+        return ERROR_IO;
+    }
+    offset++;
+
+    uint32_t flags;
+    if (!mDataSource->getUInt24(offset, &flags)) {
+        return ERROR_IO;
+    }
+    offset += 3;
+
+    uint32_t entrycount;
+    if (!mDataSource->getUInt32(offset, &entrycount)) {
+        return ERROR_IO;
+    }
+    offset += 4;
+
+    if (entrycount > mCurrentSampleInfoOffsetsAllocSize) {
+        mCurrentSampleInfoOffsets = (uint64_t*) realloc(mCurrentSampleInfoOffsets, entrycount * 8);
+        mCurrentSampleInfoOffsetsAllocSize = entrycount;
+    }
+    mCurrentSampleInfoOffsetCount = entrycount;
+
+    for (size_t i = 0; i < entrycount; i++) {
+        if (version == 0) {
+            uint32_t tmp;
+            if (!mDataSource->getUInt32(offset, &tmp)) {
+                return ERROR_IO;
+            }
+            mCurrentSampleInfoOffsets[i] = tmp;
+            offset += 4;
+        } else {
+            uint64_t tmp;
+            if (!mDataSource->getUInt64(offset, &tmp)) {
+                return ERROR_IO;
+            }
+            mCurrentSampleInfoOffsets[i] = tmp;
+            offset += 8;
+        }
+    }
+
+    // parse clear/encrypted data
+
+    off64_t drmoffset = mCurrentSampleInfoOffsets[0]; // from moof
+
+    drmoffset += mCurrentMoofOffset;
+    int ivlength;
+    CHECK(mFormat->findInt32(kKeyCryptoDefaultIVSize, &ivlength));
+    int foo = 1;
+    for (size_t i = 0; i < mCurrentSampleInfoCount; i++) {
+        Sample *smpl = &mCurrentSamples.editItemAt(i);
+
+        memset(smpl->iv, 0, 16);
+        if (mDataSource->readAt(drmoffset, smpl->iv, ivlength) != ivlength) {
+            return ERROR_IO;
+        }
+
+        drmoffset += ivlength;
+
+        uint16_t numsubsamples;
+        if (!mDataSource->getUInt16(drmoffset, &numsubsamples)) {
+            return ERROR_IO;
+        }
+        drmoffset += 2;
+        for (size_t j = 0; j < numsubsamples; j++) {
+            uint16_t numclear;
+            uint32_t numencrypted;
+            if (!mDataSource->getUInt16(drmoffset, &numclear)) {
+                return ERROR_IO;
+            }
+            drmoffset += 2;
+            if (!mDataSource->getUInt32(drmoffset, &numencrypted)) {
+                return ERROR_IO;
+            }
+            drmoffset += 4;
+            smpl->clearsizes.add(numclear);
+            smpl->encryptedsizes.add(numencrypted);
+        }
+    }
+
+
+    return OK;
+}
+
 status_t MPEG4Source::parseTrackFragmentHeader(off64_t offset, off64_t size) {
 
     if (size < 8) {
@@ -2317,7 +2651,7 @@
     }
 
     uint32_t flags;
-    if (!mDataSource->getUInt32(offset, &flags)) {
+    if (!mDataSource->getUInt32(offset, &flags)) { // actually version + flags
         return ERROR_MALFORMED;
     }
 
@@ -2550,8 +2884,8 @@
             offset += 4;
         }
 
-        ALOGV("adding sample at offset 0x%08llx, size %u, duration %u, "
-              " flags 0x%08x",
+        ALOGV("adding sample %d at offset 0x%08llx, size %u, duration %u, "
+              " flags 0x%08x", i + 1,
                 dataOffset, sampleSize, sampleDuration,
                 (flags & kFirstSampleFlagsPresent) && i == 0
                     ? firstSampleFlags : sampleFlags);
@@ -3111,6 +3445,20 @@
             mBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
         }
 
+        const Sample *smpl = &mCurrentSamples[mCurrentSampleIndex];
+        if (smpl->encryptedsizes.size()) {
+            // store clear/encrypted lengths in metadata
+            sp<MetaData> bufmeta = mBuffer->meta_data();
+            bufmeta->setData(kKeyPlainSizes, 0,
+                    smpl->clearsizes.array(), smpl->clearsizes.size() * 4);
+            bufmeta->setData(kKeyEncryptedSizes, 0,
+                    smpl->encryptedsizes.array(), smpl->encryptedsizes.size() * 4);
+            bufmeta->setData(kKeyCryptoIV, 0, smpl->iv, 16); // use 16 or the actual size?
+            bufmeta->setInt32(kKeyCryptoDefaultIVSize, mDefaultIVSize);
+            bufmeta->setInt32(kKeyCryptoMode, mCryptoMode);
+            bufmeta->setData(kKeyCryptoKey, 0, mCryptoKey, 16);
+        }
+
         ++mCurrentSampleIndex;
 
         *out = mBuffer;
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 404fa94..7bc7da2 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -228,6 +228,34 @@
     return convertMetaDataToMessage(meta, format);
 }
 
+status_t NuMediaExtractor::getFileFormat(sp<AMessage> *format) const {
+    Mutex::Autolock autoLock(mLock);
+
+    *format = NULL;
+
+    if (mImpl == NULL) {
+        return -EINVAL;
+    }
+
+    sp<MetaData> meta = mImpl->getMetaData();
+
+    const char *mime;
+    CHECK(meta->findCString(kKeyMIMEType, &mime));
+    *format = new AMessage();
+    (*format)->setString("mime", mime);
+
+    uint32_t type;
+    const void *pssh;
+    size_t psshsize;
+    if (meta->findData(kKeyPssh, &type, &pssh, &psshsize)) {
+        sp<ABuffer> buf = new ABuffer(psshsize);
+        memcpy(buf->data(), pssh, psshsize);
+        (*format)->setBuffer("pssh", buf);
+    }
+
+    return OK;
+}
+
 status_t NuMediaExtractor::selectTrack(size_t index) {
     Mutex::Autolock autoLock(mLock);
 
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index ff72e0e..1822f07 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -32,7 +32,7 @@
     MuxOMX(const sp<IOMX> &remoteOMX);
     virtual ~MuxOMX();
 
-    virtual IBinder *onAsBinder() { return NULL; }
+    virtual IBinder *onAsBinder() { return mRemoteOMX->asBinder().get(); }
 
     virtual bool livesLocally(node_id node, pid_t pid);
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 22aefcc..6c0779d 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1213,13 +1213,6 @@
         CHECK_EQ(err, (status_t)OK);
         CHECK_EQ((int)format.eCompressionFormat, (int)OMX_VIDEO_CodingUnused);
 
-        CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
-               || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
-               || format.eColorFormat == OMX_COLOR_FormatCbYCrY
-               || format.eColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar
-               || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
-               || format.eColorFormat == OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka);
-
         int32_t colorFormat;
         if (meta->findInt32(kKeyColorFormat, &colorFormat)
                 && colorFormat != OMX_COLOR_FormatUnused
diff --git a/media/libstagefright/chromium_http/Android.mk b/media/libstagefright/chromium_http/Android.mk
index 2c6d84c..f26f386 100644
--- a/media/libstagefright/chromium_http/Android.mk
+++ b/media/libstagefright/chromium_http/Android.mk
@@ -22,6 +22,7 @@
         libchromium_net \
         libutils \
         libcutils \
+        liblog \
         libstagefright_foundation \
         libstagefright \
         libdrmframework
diff --git a/media/libstagefright/codecs/aacdec/Android.mk b/media/libstagefright/codecs/aacdec/Android.mk
index 4dc38a8..ffa64f9 100644
--- a/media/libstagefright/codecs/aacdec/Android.mk
+++ b/media/libstagefright/codecs/aacdec/Android.mk
@@ -20,7 +20,7 @@
 LOCAL_STATIC_LIBRARIES := libFraunhoferAAC
 
 LOCAL_SHARED_LIBRARIES := \
-      libstagefright_omx libstagefright_foundation libutils libcutils
+      libstagefright_omx libstagefright_foundation libutils libcutils liblog
 
 LOCAL_MODULE := libstagefright_soft_aacdec
 LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index a8ab2ac..8ba2afb 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -118,7 +118,7 @@
             status = OK;
         }
     }
-    mIsFirst = true;
+    mDecoderHasData = false;
 
     // for streams that contain metadata, use the mobile profile DRC settings unless overridden
     // by platform properties:
@@ -327,6 +327,7 @@
             notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
             return;
         }
+
         inQueue.erase(inQueue.begin());
         info->mOwnedByUs = false;
         notifyEmptyBufferDone(header);
@@ -358,7 +359,7 @@
             inInfo->mOwnedByUs = false;
             notifyEmptyBufferDone(inHeader);
 
-            if (!mIsFirst) {
+            if (mDecoderHasData) {
                 // flush out the decoder's delayed data by calling DecodeFrame
                 // one more time, with the AACDEC_FLUSH flag set
                 INT_PCM *outBuffer =
@@ -370,6 +371,7 @@
                                            outBuffer,
                                            outHeader->nAllocLen,
                                            AACDEC_FLUSH);
+                mDecoderHasData = false;
 
                 if (decoderErr != AAC_DEC_OK) {
                     mSignalledError = true;
@@ -385,9 +387,7 @@
                             * sizeof(int16_t)
                             * mStreamInfo->numChannels;
             } else {
-                // Since we never discarded frames from the start, we won't have
-                // to add any padding at the end either.
-
+                // we never submitted any data to the decoder, so there's nothing to flush out
                 outHeader->nFilledLen = 0;
             }
 
@@ -473,6 +473,7 @@
                             inBuffer,
                             inBufferLength,
                             bytesValid);
+            mDecoderHasData = true;
 
             decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
                                                 outBuffer,
@@ -484,45 +485,6 @@
             }
         }
 
-        /*
-         * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
-         * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
-         * rate system and the sampling rate in the final output is actually
-         * doubled compared with the core AAC decoder sampling rate.
-         *
-         * Explicit signalling is done by explicitly defining SBR audio object
-         * type in the bitstream. Implicit signalling is done by embedding
-         * SBR content in AAC extension payload specific to SBR, and hence
-         * requires an AAC decoder to perform pre-checks on actual audio frames.
-         *
-         * Thus, we could not say for sure whether a stream is
-         * AAC+/eAAC+ until the first data frame is decoded.
-         */
-        if (mInputBufferCount <= 2) {
-            if (mStreamInfo->sampleRate != prevSampleRate ||
-                mStreamInfo->numChannels != prevNumChannels) {
-                maybeConfigureDownmix();
-                ALOGI("Reconfiguring decoder: %d Hz, %d channels",
-                      mStreamInfo->sampleRate,
-                      mStreamInfo->numChannels);
-
-                // We're going to want to revisit this input buffer, but
-                // may have already advanced the offset. Undo that if
-                // necessary.
-                inHeader->nOffset -= adtsHeaderSize;
-                inHeader->nFilledLen += adtsHeaderSize;
-
-                notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
-                mOutputPortSettingsChange = AWAITING_DISABLED;
-                return;
-            }
-        } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) {
-            ALOGW("Invalid AAC stream");
-            mSignalledError = true;
-            notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
-            return;
-        }
-
         size_t numOutBytes =
             mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
 
@@ -544,17 +506,51 @@
             // fall through
         }
 
+        if (inHeader->nFilledLen == 0) {
+            inInfo->mOwnedByUs = false;
+            inQueue.erase(inQueue.begin());
+            inInfo = NULL;
+            notifyEmptyBufferDone(inHeader);
+            inHeader = NULL;
+        }
+
+        /*
+         * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
+         * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
+         * rate system and the sampling rate in the final output is actually
+         * doubled compared with the core AAC decoder sampling rate.
+         *
+         * Explicit signalling is done by explicitly defining SBR audio object
+         * type in the bitstream. Implicit signalling is done by embedding
+         * SBR content in AAC extension payload specific to SBR, and hence
+         * requires an AAC decoder to perform pre-checks on actual audio frames.
+         *
+         * Thus, we could not say for sure whether a stream is
+         * AAC+/eAAC+ until the first data frame is decoded.
+         */
+        if (mInputBufferCount <= 2) {
+            if (mStreamInfo->sampleRate != prevSampleRate ||
+                mStreamInfo->numChannels != prevNumChannels) {
+                maybeConfigureDownmix();
+                ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels",
+                      prevSampleRate, mStreamInfo->sampleRate,
+                      prevNumChannels, mStreamInfo->numChannels);
+
+                notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+                mOutputPortSettingsChange = AWAITING_DISABLED;
+                return;
+            }
+        } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) {
+            ALOGW("Invalid AAC stream");
+            mSignalledError = true;
+            notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+            return;
+        }
+
         if (decoderErr == AAC_DEC_OK || mNumSamplesOutput > 0) {
             // We'll only output data if we successfully decoded it or
             // we've previously decoded valid data, in the latter case
             // (decode failed) we'll output a silent frame.
-            if (mIsFirst) {
-                mIsFirst = false;
-                // the first decoded frame should be discarded to account
-                // for decoder delay
-                numOutBytes = 0;
-            }
-
             outHeader->nFilledLen = numOutBytes;
             outHeader->nFlags = 0;
 
@@ -571,14 +567,6 @@
             outHeader = NULL;
         }
 
-        if (inHeader->nFilledLen == 0) {
-            inInfo->mOwnedByUs = false;
-            inQueue.erase(inQueue.begin());
-            inInfo = NULL;
-            notifyEmptyBufferDone(inHeader);
-            inHeader = NULL;
-        }
-
         if (decoderErr == AAC_DEC_OK) {
             ++mInputBufferCount;
         }
@@ -589,14 +577,21 @@
     if (portIndex == 0) {
         // Make sure that the next buffer output does not still
         // depend on fragments from the last one decoded.
-        aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
-        mIsFirst = true;
+        // drain all existing data
+        drainDecoder();
     }
 }
 
-void SoftAAC2::onReset() {
+void SoftAAC2::drainDecoder() {
+    short buf [2048];
+    aacDecoder_DecodeFrame(mAACDecoder, buf, 4096, AACDEC_FLUSH | AACDEC_CLRHIST | AACDEC_INTR);
+    aacDecoder_DecodeFrame(mAACDecoder, buf, 4096, AACDEC_FLUSH | AACDEC_CLRHIST | AACDEC_INTR);
     aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
-    mIsFirst = true;
+    mDecoderHasData = false;
+}
+
+void SoftAAC2::onReset() {
+    drainDecoder();
 }
 
 void SoftAAC2::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h
index 6957ade..2d960ab 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.h
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h
@@ -52,7 +52,7 @@
     HANDLE_AACDECODER mAACDecoder;
     CStreamInfo *mStreamInfo;
     bool mIsADTS;
-    bool mIsFirst;
+    bool mDecoderHasData;
     size_t mInputBufferCount;
     bool mSignalledError;
     int64_t mAnchorTimeUs;
@@ -68,6 +68,7 @@
     status_t initDecoder();
     bool isConfigured() const;
     void maybeConfigureDownmix() const;
+    void drainDecoder();
 
     DISALLOW_EVIL_CONSTRUCTORS(SoftAAC2);
 };
diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk
index 820734d..057c69b 100644
--- a/media/libstagefright/codecs/aacenc/Android.mk
+++ b/media/libstagefright/codecs/aacenc/Android.mk
@@ -109,7 +109,7 @@
   LOCAL_STATIC_LIBRARIES := libFraunhoferAAC
 
   LOCAL_SHARED_LIBRARIES := \
-          libstagefright_omx libstagefright_foundation libutils
+          libstagefright_omx libstagefright_foundation libutils liblog
 
   LOCAL_MODULE := libstagefright_soft_aacenc
   LOCAL_MODULE_TAGS := optional
@@ -132,7 +132,7 @@
           libstagefright_aacenc
 
   LOCAL_SHARED_LIBRARIES := \
-          libstagefright_omx libstagefright_foundation libutils \
+          libstagefright_omx libstagefright_foundation libutils liblog \
           libstagefright_enc_common
 
   LOCAL_MODULE := libstagefright_soft_aacenc
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk
index b48a459..8d6c6f8 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.mk
+++ b/media/libstagefright/codecs/amrnb/dec/Android.mk
@@ -72,7 +72,7 @@
         libstagefright_amrnbdec libstagefright_amrwbdec
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright_omx libstagefright_foundation libutils \
+        libstagefright_omx libstagefright_foundation libutils liblog \
         libstagefright_amrnb_common
 
 LOCAL_MODULE := libstagefright_soft_amrdec
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.mk b/media/libstagefright/codecs/amrnb/enc/Android.mk
index 457656a..f4e467a 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.mk
+++ b/media/libstagefright/codecs/amrnb/enc/Android.mk
@@ -92,7 +92,7 @@
         libstagefright_amrnbenc
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright_omx libstagefright_foundation libutils \
+        libstagefright_omx libstagefright_foundation libutils liblog \
         libstagefright_amrnb_common
 
 LOCAL_MODULE := libstagefright_soft_amrnbenc
diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk
index edfd7b7..c5b8e0c 100644
--- a/media/libstagefright/codecs/amrwbenc/Android.mk
+++ b/media/libstagefright/codecs/amrwbenc/Android.mk
@@ -130,7 +130,7 @@
         libstagefright_amrwbenc
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright_omx libstagefright_foundation libutils \
+        libstagefright_omx libstagefright_foundation libutils liblog \
         libstagefright_enc_common
 
 LOCAL_MODULE := libstagefright_soft_amrwbenc
diff --git a/media/libstagefright/codecs/avc/enc/Android.mk b/media/libstagefright/codecs/avc/enc/Android.mk
index cffe469..7d17c2a 100644
--- a/media/libstagefright/codecs/avc/enc/Android.mk
+++ b/media/libstagefright/codecs/avc/enc/Android.mk
@@ -62,6 +62,7 @@
         libstagefright_foundation \
         libstagefright_omx \
         libutils \
+        liblog \
         libui
 
 
diff --git a/media/libstagefright/codecs/flac/enc/Android.mk b/media/libstagefright/codecs/flac/enc/Android.mk
index 546a357..f01d605 100644
--- a/media/libstagefright/codecs/flac/enc/Android.mk
+++ b/media/libstagefright/codecs/flac/enc/Android.mk
@@ -10,7 +10,7 @@
         external/flac/include
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libstagefright_omx libstagefright_foundation libutils
+        libstagefright libstagefright_omx libstagefright_foundation libutils liblog
 
 LOCAL_STATIC_LIBRARIES := \
         libFLAC \
diff --git a/media/libstagefright/codecs/g711/dec/Android.mk b/media/libstagefright/codecs/g711/dec/Android.mk
index 28be646..4c80da6 100644
--- a/media/libstagefright/codecs/g711/dec/Android.mk
+++ b/media/libstagefright/codecs/g711/dec/Android.mk
@@ -9,7 +9,7 @@
         frameworks/native/include/media/openmax
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libstagefright_omx libstagefright_foundation libutils
+        libstagefright libstagefright_omx libstagefright_foundation libutils liblog
 
 LOCAL_MODULE := libstagefright_soft_g711dec
 LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/gsm/dec/Android.mk b/media/libstagefright/codecs/gsm/dec/Android.mk
index 9c0c6ae..71613d2 100644
--- a/media/libstagefright/codecs/gsm/dec/Android.mk
+++ b/media/libstagefright/codecs/gsm/dec/Android.mk
@@ -10,7 +10,7 @@
         external/libgsm/inc
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libstagefright_omx libstagefright_foundation libutils
+        libstagefright libstagefright_omx libstagefright_foundation libutils liblog
 
 LOCAL_STATIC_LIBRARIES := \
         libgsm
diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.mk b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
index a6b1edc..a3d5779 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/Android.mk
+++ b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
@@ -67,7 +67,7 @@
         libstagefright_m4vh263dec
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libstagefright_omx libstagefright_foundation libutils
+        libstagefright libstagefright_omx libstagefright_foundation libutils liblog
 
 LOCAL_MODULE := libstagefright_soft_mpeg4dec
 LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.mk b/media/libstagefright/codecs/m4v_h263/enc/Android.mk
index 865cc9c..83a2dd2 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/Android.mk
+++ b/media/libstagefright/codecs/m4v_h263/enc/Android.mk
@@ -65,6 +65,7 @@
         libstagefright_foundation \
         libstagefright_omx \
         libutils \
+        liblog \
         libui
 
 
diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk
index ec8d7ec..135c715 100644
--- a/media/libstagefright/codecs/mp3dec/Android.mk
+++ b/media/libstagefright/codecs/mp3dec/Android.mk
@@ -70,7 +70,7 @@
         $(LOCAL_PATH)/include
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libstagefright_omx libstagefright_foundation libutils
+        libstagefright libstagefright_omx libstagefright_foundation libutils liblog
 
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_mp3dec
diff --git a/media/libstagefright/codecs/on2/dec/Android.mk b/media/libstagefright/codecs/on2/dec/Android.mk
index 0082d7c..7f2c46d 100644
--- a/media/libstagefright/codecs/on2/dec/Android.mk
+++ b/media/libstagefright/codecs/on2/dec/Android.mk
@@ -15,7 +15,7 @@
         libvpx
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libstagefright_omx libstagefright_foundation libutils
+        libstagefright libstagefright_omx libstagefright_foundation libutils liblog
 
 LOCAL_MODULE := libstagefright_soft_vpxdec
 LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/on2/enc/Android.mk b/media/libstagefright/codecs/on2/enc/Android.mk
index 5d3317c..a92d376 100644
--- a/media/libstagefright/codecs/on2/enc/Android.mk
+++ b/media/libstagefright/codecs/on2/enc/Android.mk
@@ -16,7 +16,7 @@
         libvpx
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libstagefright_omx libstagefright_foundation libutils \
+        libstagefright libstagefright_omx libstagefright_foundation libutils liblog \
 
 LOCAL_MODULE := libstagefright_soft_vpxenc
 LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/on2/h264dec/Android.mk b/media/libstagefright/codecs/on2/h264dec/Android.mk
index 772fd60..2539f98 100644
--- a/media/libstagefright/codecs/on2/h264dec/Android.mk
+++ b/media/libstagefright/codecs/on2/h264dec/Android.mk
@@ -97,7 +97,7 @@
 endif
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright libstagefright_omx libstagefright_foundation libutils \
+	libstagefright libstagefright_omx libstagefright_foundation libutils liblog \
 
 LOCAL_MODULE := libstagefright_soft_h264dec
 
@@ -124,4 +124,3 @@
 LOCAL_MODULE := decoder
 
 include $(BUILD_EXECUTABLE)
-
diff --git a/media/libstagefright/codecs/raw/Android.mk b/media/libstagefright/codecs/raw/Android.mk
index 285c747..fe90a03 100644
--- a/media/libstagefright/codecs/raw/Android.mk
+++ b/media/libstagefright/codecs/raw/Android.mk
@@ -9,7 +9,7 @@
         frameworks/native/include/media/openmax
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright_omx libstagefright_foundation libutils
+        libstagefright_omx libstagefright_foundation libutils liblog
 
 LOCAL_MODULE := libstagefright_soft_rawdec
 LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/vorbis/dec/Android.mk b/media/libstagefright/codecs/vorbis/dec/Android.mk
index 395dd6b..2232353 100644
--- a/media/libstagefright/codecs/vorbis/dec/Android.mk
+++ b/media/libstagefright/codecs/vorbis/dec/Android.mk
@@ -11,10 +11,9 @@
 
 LOCAL_SHARED_LIBRARIES := \
         libvorbisidec libstagefright libstagefright_omx \
-        libstagefright_foundation libutils
+        libstagefright_foundation libutils liblog
 
 LOCAL_MODULE := libstagefright_soft_vorbisdec
 LOCAL_MODULE_TAGS := optional
 
 include $(BUILD_SHARED_LIBRARY)
-
diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk
index b7577d6..d65e213 100644
--- a/media/libstagefright/foundation/Android.mk
+++ b/media/libstagefright/foundation/Android.mk
@@ -20,6 +20,7 @@
 LOCAL_SHARED_LIBRARIES := \
         libbinder         \
         libutils          \
+        liblog
 
 LOCAL_CFLAGS += -Wno-multichar
 
diff --git a/media/libstagefright/id3/Android.mk b/media/libstagefright/id3/Android.mk
index ff35d4a..80a1a3a 100644
--- a/media/libstagefright/id3/Android.mk
+++ b/media/libstagefright/id3/Android.mk
@@ -16,7 +16,7 @@
 	testid3.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright libutils libbinder libstagefright_foundation
+	libstagefright libutils liblog libbinder libstagefright_foundation
 
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_id3
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index c68623a..35eff96 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -59,6 +59,11 @@
 
 private:
 
+    struct PsshInfo {
+        uint8_t uuid[16];
+        uint32_t datalen;
+        uint8_t *data;
+    };
     struct Track {
         Track *next;
         sp<MetaData> meta;
@@ -72,6 +77,8 @@
     uint64_t mSidxDuration;
     off64_t mMoofOffset;
 
+    Vector<PsshInfo> mPssh;
+
     sp<DataSource> mDataSource;
     status_t mInitCheck;
     bool mHasVideo;
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 9129f08..a8b4939 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -19,6 +19,7 @@
         libbinder                       \
         libmedia                        \
         libutils                        \
+        liblog                          \
         libui                           \
         libgui                          \
         libcutils                       \
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 46ff22f..971875f 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -292,15 +292,14 @@
 status_t OMXNodeInstance::enableGraphicBuffers(
         OMX_U32 portIndex, OMX_BOOL enable) {
     Mutex::Autolock autoLock(mLock);
+    OMX_STRING name = const_cast<OMX_STRING>(
+            "OMX.google.android.index.enableAndroidNativeBuffers");
 
     OMX_INDEXTYPE index;
-    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
-            mHandle,
-            const_cast<OMX_STRING>("OMX.google.android.index.enableAndroidNativeBuffers"),
-            &index);
+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
 
     if (err != OMX_ErrorNone) {
-        ALOGE("OMX_GetExtensionIndex failed");
+        ALOGE("OMX_GetExtensionIndex %s failed", name);
 
         return StatusFromOMXError(err);
     }
@@ -331,14 +330,12 @@
     Mutex::Autolock autoLock(mLock);
 
     OMX_INDEXTYPE index;
-    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
-            mHandle,
-            const_cast<OMX_STRING>(
-                    "OMX.google.android.index.getAndroidNativeBufferUsage"),
-            &index);
+    OMX_STRING name = const_cast<OMX_STRING>(
+            "OMX.google.android.index.getAndroidNativeBufferUsage");
+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
 
     if (err != OMX_ErrorNone) {
-        ALOGE("OMX_GetExtensionIndex failed");
+        ALOGE("OMX_GetExtensionIndex %s failed", name);
 
         return StatusFromOMXError(err);
     }
@@ -381,7 +378,9 @@
 
     OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
     if (err != OMX_ErrorNone) {
-        ALOGE("OMX_GetExtensionIndex %s failed", name);
+        if (enable) {
+            ALOGE("OMX_GetExtensionIndex %s failed", name);
+        }
         return StatusFromOMXError(err);
     }
 
@@ -507,13 +506,12 @@
         return useGraphicBuffer2_l(portIndex, graphicBuffer, buffer);
     }
 
-    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
-            mHandle,
-            const_cast<OMX_STRING>("OMX.google.android.index.useAndroidNativeBuffer"),
-            &index);
+    OMX_STRING name = const_cast<OMX_STRING>(
+        "OMX.google.android.index.useAndroidNativeBuffer");
+    OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
 
     if (err != OMX_ErrorNone) {
-        ALOGE("OMX_GetExtensionIndex failed");
+        ALOGE("OMX_GetExtensionIndex %s failed", name);
 
         return StatusFromOMXError(err);
     }
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index 04441ca..1061c39 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -5,7 +5,7 @@
 	OMXHarness.cpp  \
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright libbinder libmedia libutils libstagefright_foundation
+	libstagefright libbinder libmedia libutils liblog libstagefright_foundation
 
 LOCAL_C_INCLUDES := \
 	$(TOP)/frameworks/av/media/libstagefright \
diff --git a/media/libstagefright/tests/Android.mk b/media/libstagefright/tests/Android.mk
index 57fff0b..06ce16b 100644
--- a/media/libstagefright/tests/Android.mk
+++ b/media/libstagefright/tests/Android.mk
@@ -26,6 +26,7 @@
 	libsync \
 	libui \
 	libutils \
+	liblog
 
 LOCAL_STATIC_LIBRARIES := \
 	libgtest \
diff --git a/media/libstagefright/wifi-display/Android.mk b/media/libstagefright/wifi-display/Android.mk
index 1578c21..f99ef60 100644
--- a/media/libstagefright/wifi-display/Android.mk
+++ b/media/libstagefright/wifi-display/Android.mk
@@ -31,6 +31,7 @@
 LOCAL_SHARED_LIBRARIES:= \
         libbinder                       \
         libcutils                       \
+        liblog                          \
         libgui                          \
         libmedia                        \
         libstagefright                  \
@@ -59,6 +60,7 @@
         libstagefright_foundation       \
         libstagefright_wfd              \
         libutils                        \
+        liblog                          \
 
 LOCAL_MODULE:= wfd
 
@@ -81,6 +83,7 @@
         libstagefright_foundation       \
         libstagefright_wfd              \
         libutils                        \
+        liblog                          \
 
 LOCAL_MODULE:= udptest
 
@@ -103,6 +106,7 @@
         libstagefright_foundation       \
         libstagefright_wfd              \
         libutils                        \
+        liblog                          \
 
 LOCAL_MODULE:= rtptest
 
@@ -125,6 +129,7 @@
         libstagefright_foundation       \
         libstagefright_wfd              \
         libutils                        \
+        liblog                          \
 
 LOCAL_MODULE:= nettest
 
diff --git a/media/libstagefright/yuv/Android.mk b/media/libstagefright/yuv/Android.mk
index a4253f6..b3f7b1b 100644
--- a/media/libstagefright/yuv/Android.mk
+++ b/media/libstagefright/yuv/Android.mk
@@ -6,7 +6,8 @@
         YUVCanvas.cpp
 
 LOCAL_SHARED_LIBRARIES :=       \
-        libcutils
+        libcutils \
+        liblog
 
 LOCAL_MODULE:= libstagefright_yuv
 
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index a485646..1ac647a 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -22,6 +22,7 @@
 	libmedia \
 	libmediaplayerservice \
 	libutils \
+	liblog \
 	libbinder
 
 LOCAL_STATIC_LIBRARIES := \
diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk
index bee28d4..ac608a1 100644
--- a/media/mtp/Android.mk
+++ b/media/mtp/Android.mk
@@ -42,6 +42,6 @@
 # Needed for <bionic_time.h>
 LOCAL_C_INCLUDES := bionic/libc/private
 
-LOCAL_SHARED_LIBRARIES := libutils libcutils libusbhost libbinder
+LOCAL_SHARED_LIBRARIES := libutils libcutils liblog libusbhost libbinder
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 7806f48..061a079 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -22,7 +22,7 @@
     AudioResampler.cpp.arm      \
     AudioPolicyService.cpp      \
     ServiceUtilities.cpp        \
-	AudioResamplerCubic.cpp.arm \
+    AudioResamplerCubic.cpp.arm \
     AudioResamplerSinc.cpp.arm
 
 LOCAL_SRC_FILES += StateQueue.cpp
@@ -39,6 +39,7 @@
     libcommon_time_client \
     libcutils \
     libutils \
+    liblog \
     libbinder \
     libmedia \
     libnbaio \
@@ -94,9 +95,10 @@
     AudioResamplerSinc.cpp.arm
 
 LOCAL_SHARED_LIBRARIES := \
-	libdl \
+    libdl \
     libcutils \
-    libutils
+    libutils \
+    liblog
 
 LOCAL_MODULE:= test-resample
 
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 6847bf8..3c84703 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -32,6 +32,7 @@
 
 LOCAL_SHARED_LIBRARIES:= \
     libui \
+    liblog \
     libutils \
     libbinder \
     libcutils \
diff --git a/services/camera/libcameraservice/Camera3Device.cpp b/services/camera/libcameraservice/Camera3Device.cpp
index f2c8c04..08aef83 100644
--- a/services/camera/libcameraservice/Camera3Device.cpp
+++ b/services/camera/libcameraservice/Camera3Device.cpp
@@ -25,6 +25,18 @@
 #define ALOGVV(...) ((void)0)
 #endif
 
+// Convenience macro for transient errors
+#define CLOGE(fmt, ...) ALOGE("Camera %d: %s: " fmt, mId, __FUNCTION__, \
+            ##__VA_ARGS__)
+
+// Convenience macros for transitioning to the error state
+#define SET_ERR(fmt, ...) setErrorState(   \
+    "%s: " fmt, __FUNCTION__,              \
+    ##__VA_ARGS__)
+#define SET_ERR_L(fmt, ...) setErrorStateLocked( \
+    "%s: " fmt, __FUNCTION__,                    \
+    ##__VA_ARGS__)
+
 #include <utils/Log.h>
 #include <utils/Trace.h>
 #include <utils/Timers.h>
@@ -69,7 +81,7 @@
 
     ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mId);
     if (mStatus != STATUS_UNINITIALIZED) {
-        ALOGE("%s: Already initialized!", __FUNCTION__);
+        CLOGE("Already initialized!");
         return INVALID_OPERATION;
     }
 
@@ -84,21 +96,18 @@
             reinterpret_cast<hw_device_t**>(&device));
 
     if (res != OK) {
-        ALOGE("%s: Could not open camera %d: %s (%d)", __FUNCTION__,
-                mId, strerror(-res), res);
-        mStatus = STATUS_ERROR;
+        SET_ERR_L("Could not open camera: %s (%d)", strerror(-res), res);
         return res;
     }
 
     /** Cross-check device version */
 
     if (device->common.version != CAMERA_DEVICE_API_VERSION_3_0) {
-        ALOGE("%s: Could not open camera %d: "
+        SET_ERR_L("Could not open camera: "
                 "Camera device is not version %x, reports %x instead",
-                __FUNCTION__, mId, CAMERA_DEVICE_API_VERSION_3_0,
+                CAMERA_DEVICE_API_VERSION_3_0,
                 device->common.version);
         device->common.close(&device->common);
-        mStatus = STATUS_ERROR;
         return BAD_VALUE;
     }
 
@@ -107,11 +116,10 @@
     if (res != OK) return res;
 
     if (info.device_version != device->common.version) {
-        ALOGE("%s: HAL reporting mismatched camera_info version (%x)"
-                " and device version (%x).", __FUNCTION__,
+        SET_ERR_L("HAL reporting mismatched camera_info version (%x)"
+                " and device version (%x).",
                 device->common.version, info.device_version);
         device->common.close(&device->common);
-        mStatus = STATUS_ERROR;
         return BAD_VALUE;
     }
 
@@ -119,10 +127,9 @@
 
     res = device->ops->initialize(device, this);
     if (res != OK) {
-        ALOGE("%s: Camera %d: Unable to initialize HAL device: %s (%d)",
-                __FUNCTION__, mId, strerror(-res), res);
+        SET_ERR_L("Unable to initialize HAL device: %s (%d)",
+                strerror(-res), res);
         device->common.close(&device->common);
-        mStatus = STATUS_ERROR;
         return BAD_VALUE;
     }
 
@@ -135,10 +142,9 @@
     if (mVendorTagOps.get_camera_vendor_section_name != NULL) {
         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);
+            SET_ERR_L("Unable to set tag ops: %s (%d)",
+                    strerror(-res), res);
             device->common.close(&device->common);
-            mStatus = STATUS_ERROR;
             return res;
         }
     }
@@ -148,11 +154,10 @@
     mRequestThread = new RequestThread(this, device);
     res = mRequestThread->run(String8::format("C3Dev-%d-ReqQueue", mId).string());
     if (res != OK) {
-        ALOGE("%s: Camera %d: Unable to start request queue thread: %s (%d)",
-                __FUNCTION__, mId, strerror(-res), res);
+        SET_ERR_L("Unable to start request queue thread: %s (%d)",
+                strerror(-res), res);
         device->common.close(&device->common);
         mRequestThread.clear();
-        mStatus = STATUS_ERROR;
         return res;
     }
 
@@ -179,12 +184,12 @@
             (mStatus == STATUS_ERROR && mRequestThread != NULL)) {
         res = mRequestThread->clearRepeatingRequests();
         if (res != OK) {
-            ALOGE("%s: Can't stop streaming", __FUNCTION__);
+            SET_ERR_L("Can't stop streaming");
             return res;
         }
         res = waitUntilDrainedLocked();
         if (res != OK) {
-            ALOGE("%s: Timeout waiting for HAL to drain", __FUNCTION__);
+            SET_ERR_L("Timeout waiting for HAL to drain");
             return res;
         }
     }
@@ -225,6 +230,9 @@
             mStatus == STATUS_ACTIVE        ? "ACTIVE" :
             "Unknown";
     lines.appendFormat("    Device status: %s\n", status);
+    if (mStatus == STATUS_ERROR) {
+        lines.appendFormat("    Error cause: %s\n", mErrorCause.string());
+    }
     lines.appendFormat("    Stream configuration:\n");
 
     if (mInputStream != NULL) {
@@ -251,7 +259,7 @@
     ALOGVV("%s: E", __FUNCTION__);
     if (CC_UNLIKELY(mStatus == STATUS_UNINITIALIZED ||
                     mStatus == STATUS_ERROR)) {
-        ALOGE("%s: Access to static info %s!", __FUNCTION__,
+        ALOGW("%s: Access to static info %s!", __FUNCTION__,
                 mStatus == STATUS_ERROR ?
                 "when in error state" : "before init");
     }
@@ -262,25 +270,27 @@
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
 
+    // TODO: take ownership of the request
+
     switch (mStatus) {
         case STATUS_ERROR:
-            ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+            CLOGE("Device has encountered a serious error");
             return INVALID_OPERATION;
         case STATUS_UNINITIALIZED:
-            ALOGE("%s: Device not initialized", __FUNCTION__);
+            CLOGE("Device not initialized");
             return INVALID_OPERATION;
         case STATUS_IDLE:
         case STATUS_ACTIVE:
             // OK
             break;
         default:
-            ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+            SET_ERR_L("Unexpected status: %d", mStatus);
             return INVALID_OPERATION;
     }
 
     sp<CaptureRequest> newRequest = setUpRequestLocked(request);
     if (newRequest == NULL) {
-        ALOGE("%s: Can't create capture request", __FUNCTION__);
+        CLOGE("Can't create capture request");
         return BAD_VALUE;
     }
 
@@ -294,23 +304,23 @@
 
     switch (mStatus) {
         case STATUS_ERROR:
-            ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+            CLOGE("Device has encountered a serious error");
             return INVALID_OPERATION;
         case STATUS_UNINITIALIZED:
-            ALOGE("%s: Device not initialized", __FUNCTION__);
+            CLOGE("Device not initialized");
             return INVALID_OPERATION;
         case STATUS_IDLE:
         case STATUS_ACTIVE:
             // OK
             break;
         default:
-            ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+            SET_ERR_L("Unexpected status: %d", mStatus);
             return INVALID_OPERATION;
     }
 
     sp<CaptureRequest> newRepeatingRequest = setUpRequestLocked(request);
     if (newRepeatingRequest == NULL) {
-        ALOGE("%s: Can't create repeating request", __FUNCTION__);
+        CLOGE("Can't create repeating request");
         return BAD_VALUE;
     }
 
@@ -328,8 +338,7 @@
     if (mStatus == STATUS_IDLE) {
         res = configureStreamsLocked();
         if (res != OK) {
-            ALOGE("%s: Can't set up streams: %s (%d)",
-                    __FUNCTION__, strerror(-res), res);
+            SET_ERR_L("Can't set up streams: %s (%d)", strerror(-res), res);
             return NULL;
         }
     }
@@ -344,17 +353,17 @@
 
     switch (mStatus) {
         case STATUS_ERROR:
-            ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+            CLOGE("Device has encountered a serious error");
             return INVALID_OPERATION;
         case STATUS_UNINITIALIZED:
-            ALOGE("%s: Device not initialized", __FUNCTION__);
+            CLOGE("Device not initialized");
             return INVALID_OPERATION;
         case STATUS_IDLE:
         case STATUS_ACTIVE:
             // OK
             break;
         default:
-            ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+            SET_ERR_L("Unexpected status: %d", mStatus);
             return INVALID_OPERATION;
     }
 
@@ -363,10 +372,8 @@
 
 status_t Camera3Device::waitUntilRequestReceived(int32_t requestId, nsecs_t timeout) {
     ATRACE_CALL();
-    (void)requestId; (void)timeout;
 
-    ALOGE("%s: Unimplemented", __FUNCTION__);
-    return INVALID_OPERATION;
+    return mRequestThread->waitUntilRequestProcessed(requestId, timeout);
 }
 
 status_t Camera3Device::createStream(sp<ANativeWindow> consumer,
@@ -379,10 +386,10 @@
 
     switch (mStatus) {
         case STATUS_ERROR:
-            ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+            CLOGE("Device has encountered a serious error");
             return INVALID_OPERATION;
         case STATUS_UNINITIALIZED:
-            ALOGE("%s: Device not initialized", __FUNCTION__);
+            CLOGE("Device not initialized");
             return INVALID_OPERATION;
         case STATUS_IDLE:
             // OK
@@ -394,13 +401,12 @@
             if (res != OK) {
                 ALOGE("%s: Can't pause captures to reconfigure streams!",
                         __FUNCTION__);
-                mStatus = STATUS_ERROR;
                 return res;
             }
             wasActive = true;
             break;
         default:
-            ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+            SET_ERR_L("Unexpected status: %d", mStatus);
             return INVALID_OPERATION;
     }
     assert(mStatus == STATUS_IDLE);
@@ -416,8 +422,7 @@
 
     res = mOutputStreams.add(mNextStreamId, newStream);
     if (res < 0) {
-        ALOGE("%s: Can't add new stream to set: %s (%d)",
-                __FUNCTION__, strerror(-res), res);
+        SET_ERR_L("Can't add new stream to set: %s (%d)", strerror(-res), res);
         return res;
     }
 
@@ -428,8 +433,8 @@
         ALOGV("%s: Restarting activity to reconfigure streams", __FUNCTION__);
         res = configureStreamsLocked();
         if (res != OK) {
-            ALOGE("%s: Can't reconfigure device for new stream %d: %s (%d)",
-                    __FUNCTION__, mNextStreamId, strerror(-res), res);
+            CLOGE("Can't reconfigure device for new stream %d: %s (%d)",
+                    mNextStreamId, strerror(-res), res);
             return res;
         }
         mRequestThread->setPaused(false);
@@ -442,7 +447,7 @@
     ATRACE_CALL();
     (void)outputId; (void)id;
 
-    ALOGE("%s: Unimplemented", __FUNCTION__);
+    CLOGE("Unimplemented");
     return INVALID_OPERATION;
 }
 
@@ -454,23 +459,23 @@
 
     switch (mStatus) {
         case STATUS_ERROR:
-            ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+            CLOGE("Device has encountered a serious error");
             return INVALID_OPERATION;
         case STATUS_UNINITIALIZED:
-            ALOGE("%s: Device not initialized!", __FUNCTION__);
+            CLOGE("Device not initialized!");
             return INVALID_OPERATION;
         case STATUS_IDLE:
         case STATUS_ACTIVE:
             // OK
             break;
         default:
-            ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+            SET_ERR_L("Unexpected status: %d", mStatus);
             return INVALID_OPERATION;
     }
 
     ssize_t idx = mOutputStreams.indexOfKey(id);
     if (idx == NAME_NOT_FOUND) {
-        ALOGE("%s: Stream %d is unknown", __FUNCTION__, id);
+        CLOGE("Stream %d is unknown", id);
         return idx;
     }
 
@@ -488,24 +493,24 @@
 
     switch (mStatus) {
         case STATUS_ERROR:
-            ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+            CLOGE("Device has encountered a serious error");
             return INVALID_OPERATION;
         case STATUS_UNINITIALIZED:
-            ALOGE("%s: Device not initialized", __FUNCTION__);
+            CLOGE("Device not initialized");
             return INVALID_OPERATION;
         case STATUS_IDLE:
         case STATUS_ACTIVE:
             // OK
             break;
         default:
-            ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+            SET_ERR_L("Unexpected status: %d", mStatus);
             return INVALID_OPERATION;
     }
 
     ssize_t idx = mOutputStreams.indexOfKey(id);
     if (idx == NAME_NOT_FOUND) {
-        ALOGE("%s: Stream %d does not exist",
-                __FUNCTION__, id);
+        CLOGE("Stream %d does not exist",
+                id);
         return BAD_VALUE;
     }
 
@@ -520,7 +525,7 @@
     // CameraDevice semantics require device to already be idle before
     // deleteStream is called, unlike for createStream.
     if (mStatus != STATUS_IDLE) {
-        ALOGE("%s: Device not idle", __FUNCTION__);
+        CLOGE("Device not idle");
         return INVALID_OPERATION;
     }
 
@@ -531,8 +536,7 @@
     } else {
         ssize_t idx = mOutputStreams.indexOfKey(id);
         if (idx == NAME_NOT_FOUND) {
-            ALOGE("%s: Stream %d does not exist",
-                    __FUNCTION__, id);
+            CLOGE("Stream %d does not exist", id);
             return BAD_VALUE;
         }
         deletedStream = mOutputStreams.editValueAt(idx);
@@ -542,7 +546,7 @@
     // Free up the stream endpoint so that it can be used by some other stream
     res = deletedStream->disconnect();
     if (res != OK) {
-        ALOGE("%s: Can't disconnect deleted stream", __FUNCTION__);
+        SET_ERR_L("Can't disconnect deleted stream %d", id);
         // fall through since we want to still list the stream as deleted.
     }
     mDeletedStreams.add(deletedStream);
@@ -554,7 +558,7 @@
     ATRACE_CALL();
     (void)id;
 
-    ALOGE("%s: Unimplemented", __FUNCTION__);
+    CLOGE("Unimplemented");
     return INVALID_OPERATION;
 }
 
@@ -567,24 +571,28 @@
 
     switch (mStatus) {
         case STATUS_ERROR:
-            ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+            CLOGE("Device has encountered a serious error");
             return INVALID_OPERATION;
         case STATUS_UNINITIALIZED:
-            ALOGE("%s: Device is not initialized!", __FUNCTION__);
+            CLOGE("Device is not initialized!");
             return INVALID_OPERATION;
         case STATUS_IDLE:
         case STATUS_ACTIVE:
             // OK
             break;
         default:
-            ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+            SET_ERR_L("Unexpected status: %d", mStatus);
             return INVALID_OPERATION;
     }
 
     const camera_metadata_t *rawRequest;
     rawRequest = mHal3Device->ops->construct_default_request_settings(
         mHal3Device, templateId);
-    if (rawRequest == NULL) return DEAD_OBJECT;
+    if (rawRequest == NULL) {
+        SET_ERR_L("HAL is unable to construct default settings for template %d",
+                templateId);
+        return DEAD_OBJECT;
+    }
     *request = rawRequest;
 
     return OK;
@@ -611,35 +619,31 @@
             // Need to shut down
             break;
         default:
-            ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+            SET_ERR_L("Unexpected status: %d",mStatus);
             return INVALID_OPERATION;
     }
 
     if (mRequestThread != NULL) {
         res = mRequestThread->waitUntilPaused(kShutdownTimeout);
         if (res != OK) {
-            ALOGE("%s: Can't stop request thread in %f seconds!",
-                    __FUNCTION__, kShutdownTimeout/1e9);
-            mStatus = STATUS_ERROR;
+            SET_ERR_L("Can't stop request thread in %f seconds!",
+                    kShutdownTimeout/1e9);
             return res;
         }
     }
     if (mInputStream != NULL) {
         res = mInputStream->waitUntilIdle(kShutdownTimeout);
         if (res != OK) {
-            ALOGE("%s: Can't idle input stream %d in %f seconds!",
-                    __FUNCTION__, mInputStream->getId(), kShutdownTimeout/1e9);
-            mStatus = STATUS_ERROR;
+            SET_ERR_L("Can't idle input stream %d in %f seconds!",
+                    mInputStream->getId(), kShutdownTimeout/1e9);
             return res;
         }
     }
     for (size_t i = 0; i < mOutputStreams.size(); i++) {
         res = mOutputStreams.editValueAt(i)->waitUntilIdle(kShutdownTimeout);
         if (res != OK) {
-            ALOGE("%s: Can't idle output stream %d in %f seconds!",
-                    __FUNCTION__, mOutputStreams.keyAt(i),
-                    kShutdownTimeout/1e9);
-            mStatus = STATUS_ERROR;
+            SET_ERR_L("Can't idle output stream %d in %f seconds!",
+                    mOutputStreams.keyAt(i), kShutdownTimeout/1e9);
             return res;
         }
     }
@@ -673,8 +677,8 @@
         if (res == TIMED_OUT) {
             return res;
         } else if (res != OK) {
-            ALOGE("%s: Camera %d: Error waiting for frame: %s (%d)",
-                    __FUNCTION__, mId, strerror(-res), res);
+            ALOGW("%s: Camera %d: No frame in %lld ns: %s (%d)",
+                    __FUNCTION__, mId, timeout, strerror(-res), res);
             return res;
         }
     }
@@ -698,28 +702,62 @@
 
 status_t Camera3Device::triggerAutofocus(uint32_t id) {
     ATRACE_CALL();
-    (void)id;
 
-    ALOGE("%s: Unimplemented", __FUNCTION__);
-    return INVALID_OPERATION;
+    ALOGV("%s: Triggering autofocus, id %d", __FUNCTION__, id);
+    // Mix-in this trigger into the next request and only the next request.
+    RequestTrigger trigger[] = {
+        {
+            ANDROID_CONTROL_AF_TRIGGER,
+            ANDROID_CONTROL_AF_TRIGGER_START
+        },
+        {
+            ANDROID_CONTROL_AF_TRIGGER_ID,
+            static_cast<int32_t>(id)
+        },
+    };
+
+    return mRequestThread->queueTrigger(trigger,
+                                        sizeof(trigger)/sizeof(trigger[0]));
 }
 
 status_t Camera3Device::triggerCancelAutofocus(uint32_t id) {
     ATRACE_CALL();
-    (void)id;
 
-    ALOGE("%s: Unimplemented", __FUNCTION__);
-    return INVALID_OPERATION;
+    ALOGV("%s: Triggering cancel autofocus, id %d", __FUNCTION__, id);
+    // Mix-in this trigger into the next request and only the next request.
+    RequestTrigger trigger[] = {
+        {
+            ANDROID_CONTROL_AF_TRIGGER,
+            ANDROID_CONTROL_AF_TRIGGER_CANCEL
+        },
+        {
+            ANDROID_CONTROL_AF_TRIGGER_ID,
+            static_cast<int32_t>(id)
+        },
+    };
 
+    return mRequestThread->queueTrigger(trigger,
+                                        sizeof(trigger)/sizeof(trigger[0]));
 }
 
 status_t Camera3Device::triggerPrecaptureMetering(uint32_t id) {
     ATRACE_CALL();
-    (void)id;
 
-    ALOGE("%s: Unimplemented", __FUNCTION__);
-    return INVALID_OPERATION;
+    ALOGV("%s: Triggering precapture metering, id %d", __FUNCTION__, id);
+    // Mix-in this trigger into the next request and only the next request.
+    RequestTrigger trigger[] = {
+        {
+            ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
+            ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_START
+        },
+        {
+            ANDROID_CONTROL_AE_PRECAPTURE_ID,
+            static_cast<int32_t>(id)
+        },
+    };
 
+    return mRequestThread->queueTrigger(trigger,
+                                        sizeof(trigger)/sizeof(trigger[0]));
 }
 
 status_t Camera3Device::pushReprocessBuffer(int reprocessStreamId,
@@ -727,7 +765,7 @@
     ATRACE_CALL();
     (void)reprocessStreamId; (void)buffer; (void)listener;
 
-    ALOGE("%s: Unimplemented", __FUNCTION__);
+    CLOGE("Unimplemented");
     return INVALID_OPERATION;
 }
 
@@ -748,8 +786,8 @@
     if (inputStreams.count > 0) {
         if (mInputStream == NULL ||
                 mInputStream->getId() != inputStreams.data.u8[0]) {
-            ALOGE("%s: Request references unknown input stream %d",
-                    __FUNCTION__, inputStreams.data.u8[0]);
+            CLOGE("Request references unknown input stream %d",
+                    inputStreams.data.u8[0]);
             return NULL;
         }
         // Lazy completion of stream configuration (allocation/registration)
@@ -757,10 +795,9 @@
         if (mInputStream->isConfiguring()) {
             res = mInputStream->finishConfiguration(mHal3Device);
             if (res != OK) {
-                ALOGE("%s: Unable to finish configuring input stream %d:"
+                SET_ERR_L("Unable to finish configuring input stream %d:"
                         " %s (%d)",
-                        __FUNCTION__, mInputStream->getId(),
-                        strerror(-res), res);
+                        mInputStream->getId(), strerror(-res), res);
                 return NULL;
             }
         }
@@ -772,15 +809,15 @@
     camera_metadata_entry_t streams =
             newRequest->mSettings.find(ANDROID_REQUEST_OUTPUT_STREAMS);
     if (streams.count == 0) {
-        ALOGE("%s: Zero output streams specified!", __FUNCTION__);
+        CLOGE("Zero output streams specified!");
         return NULL;
     }
 
     for (size_t i = 0; i < streams.count; i++) {
         int idx = mOutputStreams.indexOfKey(streams.data.u8[i]);
         if (idx == NAME_NOT_FOUND) {
-            ALOGE("%s: Request references unknown stream %d",
-                    __FUNCTION__, streams.data.u8[i]);
+            CLOGE("Request references unknown stream %d",
+                    streams.data.u8[i]);
             return NULL;
         }
         sp<Camera3OutputStream> stream = mOutputStreams.editValueAt(idx);
@@ -790,8 +827,8 @@
         if (stream->isConfiguring()) {
             res = stream->finishConfiguration(mHal3Device);
             if (res != OK) {
-                ALOGE("%s: Unable to finish configuring stream %d: %s (%d)",
-                        __FUNCTION__, stream->getId(), strerror(-res), res);
+                SET_ERR_L("Unable to finish configuring stream %d: %s (%d)",
+                        stream->getId(), strerror(-res), res);
                 return NULL;
             }
         }
@@ -808,7 +845,7 @@
     status_t res;
 
     if (mStatus != STATUS_IDLE) {
-        ALOGE("%s: Not idle", __FUNCTION__);
+        CLOGE("Not idle");
         return INVALID_OPERATION;
     }
 
@@ -825,9 +862,7 @@
         camera3_stream_t *inputStream;
         inputStream = mInputStream->startConfiguration();
         if (inputStream == NULL) {
-            ALOGE("%s: Can't start input stream configuration",
-                    __FUNCTION__);
-            // TODO: Make sure the error flow here is correct
+            SET_ERR_L("Can't start input stream configuration");
             return INVALID_OPERATION;
         }
         streams.add(inputStream);
@@ -837,9 +872,7 @@
         camera3_stream_t *outputStream;
         outputStream = mOutputStreams.editValueAt(i)->startConfiguration();
         if (outputStream == NULL) {
-            ALOGE("%s: Can't start output stream configuration",
-                    __FUNCTION__);
-            // TODO: Make sure the error flow here is correct
+            SET_ERR_L("Can't start output stream configuration");
             return INVALID_OPERATION;
         }
         streams.add(outputStream);
@@ -853,8 +886,8 @@
     res = mHal3Device->ops->configure_streams(mHal3Device, &config);
 
     if (res != OK) {
-        ALOGE("%s: Unable to configure streams with HAL: %s (%d)",
-                __FUNCTION__, strerror(-res), res);
+        SET_ERR_L("Unable to configure streams with HAL: %s (%d)",
+                strerror(-res), res);
         return res;
     }
 
@@ -869,6 +902,38 @@
     return OK;
 }
 
+void Camera3Device::setErrorState(const char *fmt, ...) {
+    Mutex::Autolock l(mLock);
+    va_list args;
+    va_start(args, fmt);
+
+    setErrorStateLockedV(fmt, args);
+
+    va_end(args);
+}
+
+void Camera3Device::setErrorStateV(const char *fmt, va_list args) {
+    Mutex::Autolock l(mLock);
+    setErrorStateLockedV(fmt, args);
+}
+
+void Camera3Device::setErrorStateLocked(const char *fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+
+    setErrorStateLockedV(fmt, args);
+
+    va_end(args);
+}
+
+void Camera3Device::setErrorStateLockedV(const char *fmt, va_list args) {
+    // Only accept the first failure cause
+    if (mStatus == STATUS_ERROR) return;
+
+    mErrorCause = String8::formatV(fmt, args);
+    ALOGE("Camera %d: %s", mId, mErrorCause.string());
+    mStatus = STATUS_ERROR;
+}
 
 /**
  * Camera HAL device callback methods
@@ -880,8 +945,7 @@
     status_t res;
 
     if (result->result == NULL) {
-        // TODO: Report error upstream
-        ALOGW("%s: No metadata for frame %d", __FUNCTION__,
+        SET_ERR("No metadata provided by HAL for frame %d",
                 result->frame_number);
         return;
     }
@@ -904,13 +968,12 @@
 
         captureResult = result->result;
         if (captureResult.update(ANDROID_REQUEST_FRAME_COUNT,
-                (int32_t*)&result->frame_number, 1) != OK) {
-            ALOGE("%s: Camera %d: Failed to set frame# in metadata (%d)",
-                  __FUNCTION__, mId, result->frame_number);
-            // TODO: Report error upstream
+                        (int32_t*)&result->frame_number, 1) != OK) {
+            SET_ERR("Failed to set frame# in metadata (%d)",
+                    result->frame_number);
         } else {
             ALOGVV("%s: Camera %d: Set frame# in metadata (%d)",
-                  __FUNCTION__, mId, result->frame_number);
+                    __FUNCTION__, mId, result->frame_number);
         }
 
         // Get timestamp from result metadata
@@ -918,9 +981,8 @@
         camera_metadata_entry entry =
                 captureResult.find(ANDROID_SENSOR_TIMESTAMP);
         if (entry.count == 0) {
-            ALOGE("%s: Camera %d: No timestamp provided by HAL for frame %d!",
-                    __FUNCTION__, mId, result->frame_number);
-            // TODO: Report error upstream
+            SET_ERR("No timestamp provided by HAL for frame %d!",
+                    result->frame_number);
         } else {
             timestamp = entry.data.i64[0];
         }
@@ -929,8 +991,8 @@
 
         entry = captureResult.find(ANDROID_CONTROL_AE_STATE);
         if (entry.count == 0) {
-            ALOGE("%s: Camera %d: No AE state provided by HAL for frame %d!",
-                    __FUNCTION__, mId, result->frame_number);
+            CLOGE("No AE state provided by HAL for frame %d!",
+                    result->frame_number);
         } else {
             new3aState.aeState =
                     static_cast<camera_metadata_enum_android_control_ae_state>(
@@ -939,8 +1001,8 @@
 
         entry = captureResult.find(ANDROID_CONTROL_AF_STATE);
         if (entry.count == 0) {
-            ALOGE("%s: Camera %d: No AF state provided by HAL for frame %d!",
-                    __FUNCTION__, mId, result->frame_number);
+            CLOGE("No AF state provided by HAL for frame %d!",
+                    result->frame_number);
         } else {
             new3aState.afState =
                     static_cast<camera_metadata_enum_android_control_af_state>(
@@ -949,8 +1011,8 @@
 
         entry = captureResult.find(ANDROID_CONTROL_AWB_STATE);
         if (entry.count == 0) {
-            ALOGE("%s: Camera %d: No AWB state provided by HAL for frame %d!",
-                    __FUNCTION__, mId, result->frame_number);
+            CLOGE("No AWB state provided by HAL for frame %d!",
+                    result->frame_number);
         } else {
             new3aState.awbState =
                     static_cast<camera_metadata_enum_android_control_awb_state>(
@@ -959,16 +1021,16 @@
 
         entry = captureResult.find(ANDROID_CONTROL_AF_TRIGGER_ID);
         if (entry.count == 0) {
-            ALOGE("%s: Camera %d: No AF trigger ID provided by HAL for frame %d!",
-                    __FUNCTION__, mId, result->frame_number);
+            CLOGE("No AF trigger ID provided by HAL for frame %d!",
+                    result->frame_number);
         } else {
             afTriggerId = entry.data.i32[0];
         }
 
         entry = captureResult.find(ANDROID_CONTROL_AE_PRECAPTURE_ID);
         if (entry.count == 0) {
-            ALOGE("%s: Camera %d: No AE precapture trigger ID provided by HAL"
-                    " for frame %d!", __FUNCTION__, mId, result->frame_number);
+            CLOGE("No AE precapture trigger ID provided by HAL"
+                    " for frame %d!", result->frame_number);
         } else {
             aeTriggerId = entry.data.i32[0];
         }
@@ -987,19 +1049,21 @@
         // Note: stream may be deallocated at this point, if this buffer was the
         // last reference to it.
         if (res != OK) {
-            ALOGE("%s: Camera %d: Can't return buffer %d for frame %d to its"
-                    "  stream:%s (%d)",  __FUNCTION__, mId, i,
-                    result->frame_number, strerror(-res), res);
-            // TODO: Report error upstream
+            SET_ERR("Can't return buffer %d for frame %d to its stream: "
+                    " %s (%d)", i, result->frame_number, strerror(-res), res);
         }
     }
 
     // Dispatch any 3A change events to listeners
     if (listener != NULL) {
         if (new3aState.aeState != cur3aState.aeState) {
+            ALOGVV("%s: AE state changed from 0x%x to 0x%x",
+                   __FUNCTION__, cur3aState.aeState, new3aState.aeState);
             listener->notifyAutoExposure(new3aState.aeState, aeTriggerId);
         }
         if (new3aState.afState != cur3aState.afState) {
+            ALOGVV("%s: AF state changed from 0x%x to 0x%x",
+                   __FUNCTION__, cur3aState.afState, new3aState.afState);
             listener->notifyAutoFocus(new3aState.afState, afTriggerId);
         }
         if (new3aState.awbState != cur3aState.awbState) {
@@ -1018,8 +1082,7 @@
     }
 
     if (msg == NULL) {
-        ALOGE("%s: Camera %d: HAL sent NULL notify message!",
-                __FUNCTION__, mId);
+        SET_ERR_L("HAL sent NULL notify message!");
         return;
     }
 
@@ -1042,8 +1105,8 @@
             break;
         }
         default:
-            ALOGE("%s: Camera %d: Unknown notify message from HAL: %d",
-                    __FUNCTION__, mId, msg->type);
+            SET_ERR_L("Unknown notify message from HAL: %d",
+                    msg->type);
     }
 }
 
@@ -1059,7 +1122,8 @@
         mReconfigured(false),
         mDoPause(false),
         mPaused(true),
-        mFrameNumber(0) {
+        mFrameNumber(0),
+        mLatestRequestId(NAME_NOT_FOUND) {
 }
 
 void Camera3Device::RequestThread::configurationComplete() {
@@ -1075,6 +1139,57 @@
     return OK;
 }
 
+
+status_t Camera3Device::RequestThread::queueTrigger(
+        RequestTrigger trigger[],
+        size_t count) {
+
+    Mutex::Autolock l(mTriggerMutex);
+    status_t ret;
+
+    for (size_t i = 0; i < count; ++i) {
+        ret = queueTriggerLocked(trigger[i]);
+
+        if (ret != OK) {
+            return ret;
+        }
+    }
+
+    return OK;
+}
+
+status_t Camera3Device::RequestThread::queueTriggerLocked(
+        RequestTrigger trigger) {
+
+    uint32_t tag = trigger.metadataTag;
+    ssize_t index = mTriggerMap.indexOfKey(tag);
+
+    switch (trigger.getTagType()) {
+        case TYPE_BYTE:
+        // fall-through
+        case TYPE_INT32:
+            break;
+        default:
+            ALOGE("%s: Type not supported: 0x%x",
+                  __FUNCTION__,
+                  trigger.getTagType());
+            return INVALID_OPERATION;
+    }
+
+    /**
+     * Collect only the latest trigger, since we only have 1 field
+     * in the request settings per trigger tag, and can't send more than 1
+     * trigger per request.
+     */
+    if (index != NAME_NOT_FOUND) {
+        mTriggerMap.editValueAt(index) = trigger;
+    } else {
+        mTriggerMap.add(tag, trigger);
+    }
+
+    return OK;
+}
+
 status_t Camera3Device::RequestThread::setRepeatingRequests(
         const RequestList &requests) {
     Mutex::Autolock l(mRequestLock);
@@ -1108,6 +1223,24 @@
     return OK;
 }
 
+status_t Camera3Device::RequestThread::waitUntilRequestProcessed(
+        int32_t requestId, nsecs_t timeout) {
+    Mutex::Autolock l(mLatestRequestMutex);
+    status_t res;
+    while (mLatestRequestId != requestId) {
+        nsecs_t startTime = systemTime();
+
+        res = mLatestRequestSignal.waitRelative(mLatestRequestMutex, timeout);
+        if (res != OK) return res;
+
+        timeout -= (systemTime() - startTime);
+    }
+
+    return OK;
+}
+
+
+
 bool Camera3Device::RequestThread::threadLoop() {
 
     status_t res;
@@ -1125,16 +1258,55 @@
     }
 
     // Create request to HAL
-
     camera3_capture_request_t request = camera3_capture_request_t();
+    Vector<camera3_stream_buffer_t> outputBuffers;
 
-    if (mPrevRequest != nextRequest) {
+    // Insert any queued triggers (before metadata is locked)
+    int32_t triggerCount;
+    res = insertTriggers(nextRequest);
+    if (res < 0) {
+        SET_ERR("RequestThread: Unable to insert triggers "
+                "(capture request %d, HAL device: %s (%d)",
+                (mFrameNumber+1), strerror(-res), res);
+        cleanUpFailedRequest(request, nextRequest, outputBuffers);
+        return false;
+    }
+    triggerCount = res;
+
+    bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0);
+
+    // If the request is the same as last, or we had triggers last time
+    if (mPrevRequest != nextRequest || triggersMixedIn) {
+        /**
+         * The request should be presorted so accesses in HAL
+         *   are O(logn). Sidenote, sorting a sorted metadata is nop.
+         */
+        nextRequest->mSettings.sort();
         request.settings = nextRequest->mSettings.getAndLock();
         mPrevRequest = nextRequest;
-    } // else leave request.settings NULL to indicate 'reuse latest given'
+        ALOGVV("%s: Request settings are NEW", __FUNCTION__);
+
+        IF_ALOGV() {
+            camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t();
+            find_camera_metadata_ro_entry(
+                    request.settings,
+                    ANDROID_CONTROL_AF_TRIGGER,
+                    &e
+            );
+            if (e.count > 0) {
+                ALOGV("%s: Request (frame num %d) had AF trigger 0x%x",
+                      __FUNCTION__,
+                      mFrameNumber+1,
+                      e.data.u8[0]);
+            }
+        }
+    } else {
+        // leave request.settings NULL to indicate 'reuse latest given'
+        ALOGVV("%s: Request settings are REUSED",
+               __FUNCTION__);
+    }
 
     camera3_stream_buffer_t inputBuffer;
-    Vector<camera3_stream_buffer_t> outputBuffers;
 
     // Fill in buffers
 
@@ -1142,7 +1314,7 @@
         request.input_buffer = &inputBuffer;
         res = nextRequest->mInputStream->getBuffer(&inputBuffer);
         if (res != OK) {
-            ALOGE("RequestThread: Can't get input buffer, skipping request:"
+            SET_ERR("RequestThread: Can't get input buffer, skipping request:"
                     " %s (%d)", strerror(-res), res);
             cleanUpFailedRequest(request, nextRequest, outputBuffers);
             return true;
@@ -1158,7 +1330,7 @@
         res = nextRequest->mOutputStreams.editItemAt(i)->
                 getBuffer(&outputBuffers.editItemAt(i));
         if (res != OK) {
-            ALOGE("RequestThread: Can't get output buffer, skipping request:"
+            SET_ERR("RequestThread: Can't get output buffer, skipping request:"
                     "%s (%d)", strerror(-res), res);
             cleanUpFailedRequest(request, nextRequest, outputBuffers);
             return true;
@@ -1168,11 +1340,12 @@
 
     request.frame_number = mFrameNumber++;
 
+
     // Submit request and block until ready for next one
 
     res = mHal3Device->ops->process_capture_request(mHal3Device, &request);
     if (res != OK) {
-        ALOGE("RequestThread: Unable to submit capture request %d to HAL"
+        SET_ERR("RequestThread: Unable to submit capture request %d to HAL"
                 " device: %s (%d)", request.frame_number, strerror(-res), res);
         cleanUpFailedRequest(request, nextRequest, outputBuffers);
         return false;
@@ -1181,6 +1354,35 @@
     if (request.settings != NULL) {
         nextRequest->mSettings.unlock(request.settings);
     }
+
+    // Remove any previously queued triggers (after unlock)
+    res = removeTriggers(mPrevRequest);
+    if (res != OK) {
+        SET_ERR("RequestThread: Unable to remove triggers "
+              "(capture request %d, HAL device: %s (%d)",
+              request.frame_number, strerror(-res), res);
+        return false;
+    }
+    mPrevTriggers = triggerCount;
+
+    // Read android.request.id from the request settings metadata
+    // - inform waitUntilRequestProcessed thread of a new request ID
+    {
+        Mutex::Autolock al(mLatestRequestMutex);
+
+        camera_metadata_entry_t requestIdEntry =
+                nextRequest->mSettings.find(ANDROID_REQUEST_ID);
+        if (requestIdEntry.count > 0) {
+            mLatestRequestId = requestIdEntry.data.i32[0];
+        } else {
+            ALOGW("%s: Did not have android.request.id set in the request",
+                  __FUNCTION__);
+            mLatestRequestId = NAME_NOT_FOUND;
+        }
+
+        mLatestRequestSignal.signal();
+    }
+
     return true;
 }
 
@@ -1201,7 +1403,6 @@
         nextRequest->mOutputStreams.editItemAt(i)->returnBuffer(
             outputBuffers[i], 0);
     }
-    // TODO: Report error upstream
 }
 
 sp<Camera3Device::CaptureRequest>
@@ -1285,6 +1486,153 @@
     return false;
 }
 
+void Camera3Device::RequestThread::setErrorState(const char *fmt, ...) {
+    sp<Camera3Device> parent = mParent.promote();
+    if (parent != NULL) {
+        va_list args;
+        va_start(args, fmt);
+
+        parent->setErrorStateV(fmt, args);
+
+        va_end(args);
+    }
+}
+
+status_t Camera3Device::RequestThread::insertTriggers(
+        const sp<CaptureRequest> &request) {
+
+    Mutex::Autolock al(mTriggerMutex);
+
+    CameraMetadata &metadata = request->mSettings;
+    size_t count = mTriggerMap.size();
+
+    for (size_t i = 0; i < count; ++i) {
+        RequestTrigger trigger = mTriggerMap.valueAt(i);
+
+        uint32_t tag = trigger.metadataTag;
+        camera_metadata_entry entry = metadata.find(tag);
+
+        if (entry.count > 0) {
+            /**
+             * Already has an entry for this trigger in the request.
+             * Rewrite it with our requested trigger value.
+             */
+            RequestTrigger oldTrigger = trigger;
+
+            oldTrigger.entryValue = entry.data.u8[0];
+
+            mTriggerReplacedMap.add(tag, oldTrigger);
+        } else {
+            /**
+             * More typical, no trigger entry, so we just add it
+             */
+            mTriggerRemovedMap.add(tag, trigger);
+        }
+
+        status_t res;
+
+        switch (trigger.getTagType()) {
+            case TYPE_BYTE: {
+                uint8_t entryValue = static_cast<uint8_t>(trigger.entryValue);
+                res = metadata.update(tag,
+                                      &entryValue,
+                                      /*count*/1);
+                break;
+            }
+            case TYPE_INT32:
+                res = metadata.update(tag,
+                                      &trigger.entryValue,
+                                      /*count*/1);
+                break;
+            default:
+                ALOGE("%s: Type not supported: 0x%x",
+                      __FUNCTION__,
+                      trigger.getTagType());
+                return INVALID_OPERATION;
+        }
+
+        if (res != OK) {
+            ALOGE("%s: Failed to update request metadata with trigger tag %s"
+                  ", value %d", __FUNCTION__, trigger.getTagName(),
+                  trigger.entryValue);
+            return res;
+        }
+
+        ALOGV("%s: Mixed in trigger %s, value %d", __FUNCTION__,
+              trigger.getTagName(),
+              trigger.entryValue);
+    }
+
+    mTriggerMap.clear();
+
+    return count;
+}
+
+status_t Camera3Device::RequestThread::removeTriggers(
+        const sp<CaptureRequest> &request) {
+    Mutex::Autolock al(mTriggerMutex);
+
+    CameraMetadata &metadata = request->mSettings;
+
+    /**
+     * Replace all old entries with their old values.
+     */
+    for (size_t i = 0; i < mTriggerReplacedMap.size(); ++i) {
+        RequestTrigger trigger = mTriggerReplacedMap.valueAt(i);
+
+        status_t res;
+
+        uint32_t tag = trigger.metadataTag;
+        switch (trigger.getTagType()) {
+            case TYPE_BYTE: {
+                uint8_t entryValue = static_cast<uint8_t>(trigger.entryValue);
+                res = metadata.update(tag,
+                                      &entryValue,
+                                      /*count*/1);
+                break;
+            }
+            case TYPE_INT32:
+                res = metadata.update(tag,
+                                      &trigger.entryValue,
+                                      /*count*/1);
+                break;
+            default:
+                ALOGE("%s: Type not supported: 0x%x",
+                      __FUNCTION__,
+                      trigger.getTagType());
+                return INVALID_OPERATION;
+        }
+
+        if (res != OK) {
+            ALOGE("%s: Failed to restore request metadata with trigger tag %s"
+                  ", trigger value %d", __FUNCTION__,
+                  trigger.getTagName(), trigger.entryValue);
+            return res;
+        }
+    }
+    mTriggerReplacedMap.clear();
+
+    /**
+     * Remove all new entries.
+     */
+    for (size_t i = 0; i < mTriggerRemovedMap.size(); ++i) {
+        RequestTrigger trigger = mTriggerRemovedMap.valueAt(i);
+        status_t res = metadata.erase(trigger.metadataTag);
+
+        if (res != OK) {
+            ALOGE("%s: Failed to erase metadata with trigger tag %s"
+                  ", trigger value %d", __FUNCTION__,
+                  trigger.getTagName(), trigger.entryValue);
+            return res;
+        }
+    }
+    mTriggerRemovedMap.clear();
+
+    return OK;
+}
+
+
+
 /**
  * Static callback forwarding methods from HAL to instance
  */
diff --git a/services/camera/libcameraservice/Camera3Device.h b/services/camera/libcameraservice/Camera3Device.h
index 8600c6c..2e4a303 100644
--- a/services/camera/libcameraservice/Camera3Device.h
+++ b/services/camera/libcameraservice/Camera3Device.h
@@ -109,7 +109,7 @@
 
   private:
     static const nsecs_t       kShutdownTimeout = 5000000000; // 5 sec
-
+    struct                     RequestTrigger;
 
     Mutex                      mLock;
 
@@ -128,6 +128,9 @@
         STATUS_ACTIVE
     }                          mStatus;
 
+    // Tracking cause of fatal errors when in STATUS_ERROR
+    String8                    mErrorCause;
+
     // Mapping of stream IDs to stream instances
     typedef KeyedVector<int, sp<camera3::Camera3OutputStream> > StreamSet;
 
@@ -173,6 +176,33 @@
     status_t           configureStreamsLocked();
 
     /**
+     * Set device into an error state due to some fatal failure, and set an
+     * error message to indicate why. Only the first call's message will be
+     * used. The message is also sent to the log.
+     */
+    void               setErrorState(const char *fmt, ...);
+    void               setErrorStateV(const char *fmt, va_list args);
+    void               setErrorStateLocked(const char *fmt, ...);
+    void               setErrorStateLockedV(const char *fmt, va_list args);
+
+    struct RequestTrigger {
+        // Metadata tag number, e.g. android.control.aePrecaptureTrigger
+        uint32_t metadataTag;
+        // Metadata value, e.g. 'START' or the trigger ID
+        int32_t entryValue;
+
+        // The last part of the fully qualified path, e.g. afTrigger
+        const char *getTagName() const {
+            return get_camera_metadata_tag_name(metadataTag) ?: "NULL";
+        }
+
+        // e.g. TYPE_BYTE, TYPE_INT32, etc.
+        int getTagType() const {
+            return get_camera_metadata_tag_type(metadataTag);
+        }
+    };
+
+    /**
      * Thread for managing capture request submission to HAL device.
      */
     class RequestThread : public Thread {
@@ -198,6 +228,14 @@
         status_t queueRequest(sp<CaptureRequest> request);
 
         /**
+         * Queue a trigger to be dispatched with the next outgoing
+         * process_capture_request. The settings for that request only
+         * will be temporarily rewritten to add the trigger tag/value.
+         * Subsequent requests will not be rewritten (for this tag).
+         */
+        status_t queueTrigger(RequestTrigger trigger[], size_t count);
+
+        /**
          * Pause/unpause the capture thread. Doesn't block, so use
          * waitUntilPaused to wait until the thread is paused.
          */
@@ -210,11 +248,27 @@
          */
         status_t waitUntilPaused(nsecs_t timeout);
 
+        /**
+         * Wait until thread processes the capture request with settings'
+         * android.request.id == requestId.
+         *
+         * Returns TIMED_OUT in case the thread does not process the request
+         * within the timeout.
+         */
+        status_t waitUntilRequestProcessed(int32_t requestId, nsecs_t timeout);
+
       protected:
 
         virtual bool threadLoop();
 
       private:
+        status_t           queueTriggerLocked(RequestTrigger trigger);
+        // Mix-in queued triggers into this request
+        int32_t            insertTriggers(const sp<CaptureRequest> &request);
+        // Purge the queued triggers from this request,
+        //  restoring the old field values for those tags.
+        status_t           removeTriggers(const sp<CaptureRequest> &request);
+
         static const nsecs_t kRequestTimeout = 50e6; // 50 ms
 
         // Waits for a request, or returns NULL if times out.
@@ -231,6 +285,9 @@
         // Pause handling
         bool               waitIfPaused();
 
+        // Relay error to parent device object setErrorState
+        void               setErrorState(const char *fmt, ...);
+
         wp<Camera3Device>  mParent;
         camera3_device_t  *mHal3Device;
 
@@ -249,8 +306,20 @@
         Condition          mPausedSignal;
 
         sp<CaptureRequest> mPrevRequest;
+        int32_t            mPrevTriggers;
 
         int32_t            mFrameNumber;
+
+        Mutex              mLatestRequestMutex;
+        Condition          mLatestRequestSignal;
+        // android.request.id for latest process_capture_request
+        int32_t            mLatestRequestId;
+
+        typedef KeyedVector<uint32_t/*tag*/, RequestTrigger> TriggerMap;
+        Mutex              mTriggerMutex;
+        TriggerMap         mTriggerMap;
+        TriggerMap         mTriggerRemovedMap;
+        TriggerMap         mTriggerReplacedMap;
     };
     sp<RequestThread> mRequestThread;
 
diff --git a/services/camera/libcameraservice/camera2/CaptureSequencer.cpp b/services/camera/libcameraservice/camera2/CaptureSequencer.cpp
index 1880912..ee03329 100644
--- a/services/camera/libcameraservice/camera2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/camera2/CaptureSequencer.cpp
@@ -270,6 +270,9 @@
         processor->clearZslQueue();
     }
 
+    /**
+     * Fire the jpegCallback in Camera#takePicture(..., jpegCallback)
+     */
     if (mCaptureBuffer != 0 && res == OK) {
         Camera2Client::SharedCameraCallbacks::Lock
             l(client->mSharedCameraCallbacks);
@@ -367,6 +370,8 @@
 CaptureSequencer::CaptureState CaptureSequencer::manageStandardStart(
         sp<Camera2Client> &client) {
     ATRACE_CALL();
+
+    // Get the onFrameAvailable callback when the requestID == mCaptureId
     client->registerFrameListener(mCaptureId, mCaptureId + 1,
             this);
     {
@@ -426,6 +431,13 @@
     SharedParameters::Lock l(client->getParameters());
     Vector<uint8_t> outputStreams;
 
+    /**
+     * Set up output streams in the request
+     *  - preview
+     *  - capture/jpeg
+     *  - callback (if preview callbacks enabled)
+     *  - recording (if recording enabled)
+     */
     outputStreams.push(client->getPreviewStreamId());
     outputStreams.push(client->getCaptureStreamId());
 
@@ -454,6 +466,7 @@
         return DONE;
     }
 
+    // Create a capture copy since CameraDeviceBase#capture takes ownership
     CameraMetadata captureCopy = mCaptureRequest;
     if (captureCopy.entryCount() == 0) {
         ALOGE("%s: Camera %d: Unable to copy capture request for HAL device",
@@ -461,7 +474,12 @@
         return DONE;
     }
 
+    /**
+     * Clear the streaming request for still-capture pictures
+     *   (as opposed to i.e. video snapshots)
+     */
     if (l.mParameters.state == Parameters::STILL_CAPTURE) {
+        // API definition of takePicture() - stop preview before taking pic
         res = client->stopStream();
         if (res != OK) {
             ALOGE("%s: Camera %d: Unable to stop preview for still capture: "
@@ -488,6 +506,8 @@
     status_t res;
     ATRACE_CALL();
     Mutex::Autolock l(mInputMutex);
+
+    // Wait for new metadata result (mNewFrame)
     while (!mNewFrameReceived) {
         res = mNewFrameSignal.waitRelative(mInputMutex, kWaitDuration);
         if (res == TIMED_OUT) {
@@ -495,12 +515,17 @@
             break;
         }
     }
+
+    // Approximation of the shutter being closed
+    // - TODO: use the hal3 exposure callback in Camera3Device instead
     if (mNewFrameReceived && !mShutterNotified) {
         SharedParameters::Lock l(client->getParameters());
         /* warning: this also locks a SharedCameraCallbacks */
         shutterNotifyLocked(l.mParameters, client, mMsgType);
         mShutterNotified = true;
     }
+
+    // Wait until jpeg was captured by JpegProcessor
     while (mNewFrameReceived && !mNewCaptureReceived) {
         res = mNewCaptureSignal.waitRelative(mInputMutex, kWaitDuration);
         if (res == TIMED_OUT) {
@@ -524,7 +549,9 @@
         }
         if (entry.data.i64[0] != mCaptureTimestamp) {
             ALOGW("Mismatched capture timestamps: Metadata frame %lld,"
-                    " captured buffer %lld", entry.data.i64[0], mCaptureTimestamp);
+                    " captured buffer %lld",
+                    entry.data.i64[0],
+                    mCaptureTimestamp);
         }
         client->removeFrameListener(mCaptureId, mCaptureId + 1, this);
 
diff --git a/services/camera/libcameraservice/camera2/JpegProcessor.h b/services/camera/libcameraservice/camera2/JpegProcessor.h
index 2283f28..74f4738 100644
--- a/services/camera/libcameraservice/camera2/JpegProcessor.h
+++ b/services/camera/libcameraservice/camera2/JpegProcessor.h
@@ -44,6 +44,7 @@
     JpegProcessor(wp<Camera2Client> client, wp<CaptureSequencer> sequencer);
     ~JpegProcessor();
 
+    // CpuConsumer listener implementation
     void onFrameAvailable();
 
     status_t updateStream(const Parameters &params);
diff --git a/services/medialog/Android.mk b/services/medialog/Android.mk
index 559b1ed..08006c8 100644
--- a/services/medialog/Android.mk
+++ b/services/medialog/Android.mk
@@ -4,7 +4,7 @@
 
 LOCAL_SRC_FILES := MediaLogService.cpp
 
-LOCAL_SHARED_LIBRARIES := libmedia libbinder libutils libnbaio
+LOCAL_SHARED_LIBRARIES := libmedia libbinder libutils liblog libnbaio
 
 LOCAL_MODULE:= libmedialogservice