Merge "Add HEVC decoder support to ACodec bug: 14571712"
diff --git a/cmds/screenrecord/FrameOutput.cpp b/cmds/screenrecord/FrameOutput.cpp
index 06b1f70..4da16bc 100644
--- a/cmds/screenrecord/FrameOutput.cpp
+++ b/cmds/screenrecord/FrameOutput.cpp
@@ -87,7 +87,7 @@
     return NO_ERROR;
 }
 
-status_t FrameOutput::copyFrame(FILE* fp, long timeoutUsec) {
+status_t FrameOutput::copyFrame(FILE* fp, long timeoutUsec, bool rawFrames) {
     Mutex::Autolock _l(mMutex);
     ALOGV("copyFrame %ld\n", timeoutUsec);
 
@@ -152,16 +152,20 @@
                 (endWhenNsec - pixWhenNsec) / 1000000.0);
     }
 
-    // Fill out the header.
-    size_t headerLen = sizeof(uint32_t) * 5;
     size_t rgbDataLen = width * height * kOutBytesPerPixel;
-    size_t packetLen = headerLen - sizeof(uint32_t) + rgbDataLen;
-    uint8_t header[headerLen];
-    setValueLE(&header[0], packetLen);
-    setValueLE(&header[4], width);
-    setValueLE(&header[8], height);
-    setValueLE(&header[12], width * kOutBytesPerPixel);
-    setValueLE(&header[16], HAL_PIXEL_FORMAT_RGB_888);
+
+    if (!rawFrames) {
+        // Fill out the header.
+        size_t headerLen = sizeof(uint32_t) * 5;
+        size_t packetLen = headerLen - sizeof(uint32_t) + rgbDataLen;
+        uint8_t header[headerLen];
+        setValueLE(&header[0], packetLen);
+        setValueLE(&header[4], width);
+        setValueLE(&header[8], height);
+        setValueLE(&header[12], width * kOutBytesPerPixel);
+        setValueLE(&header[16], HAL_PIXEL_FORMAT_RGB_888);
+        fwrite(header, 1, headerLen, fp);
+    }
 
     // Currently using buffered I/O rather than writev().  Not expecting it
     // to make much of a difference, but it might be worth a test for larger
@@ -169,7 +173,6 @@
     if (kShowTiming) {
         startWhenNsec = systemTime(CLOCK_MONOTONIC);
     }
-    fwrite(header, 1, headerLen, fp);
     fwrite(mPixelBuf, 1, rgbDataLen, fp);
     fflush(fp);
     if (kShowTiming) {
diff --git a/cmds/screenrecord/FrameOutput.h b/cmds/screenrecord/FrameOutput.h
index c1148d0..c49ec3b 100644
--- a/cmds/screenrecord/FrameOutput.h
+++ b/cmds/screenrecord/FrameOutput.h
@@ -45,7 +45,7 @@
     // specified number of microseconds.
     //
     // Returns ETIMEDOUT if the timeout expired before we found a frame.
-    status_t copyFrame(FILE* fp, long timeoutUsec);
+    status_t copyFrame(FILE* fp, long timeoutUsec, bool rawFrames);
 
     // Prepare to copy frames.  Makes the EGL context used by this object current.
     void prepareToCopy() {
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index a17fc51..02ed53a 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -65,7 +65,7 @@
 static bool gVerbose = false;           // chatty on stdout
 static bool gRotate = false;            // rotate 90 degrees
 static enum {
-    FORMAT_MP4, FORMAT_H264, FORMAT_FRAMES
+    FORMAT_MP4, FORMAT_H264, FORMAT_FRAMES, FORMAT_RAW_FRAMES
 } gOutputFormat = FORMAT_MP4;           // data format for output
 static bool gSizeSpecified = false;     // was size explicitly requested?
 static bool gWantInfoScreen = false;    // do we want initial info screen?
@@ -563,7 +563,7 @@
     sp<MediaCodec> encoder;
     sp<FrameOutput> frameOutput;
     sp<IGraphicBufferProducer> encoderInputSurface;
-    if (gOutputFormat != FORMAT_FRAMES) {
+    if (gOutputFormat != FORMAT_FRAMES && gOutputFormat != FORMAT_RAW_FRAMES) {
         err = prepareEncoder(mainDpyInfo.fps, &encoder, &encoderInputSurface);
 
         if (err != NO_ERROR && !gSizeSpecified) {
@@ -643,7 +643,8 @@
             break;
         }
         case FORMAT_H264:
-        case FORMAT_FRAMES: {
+        case FORMAT_FRAMES:
+        case FORMAT_RAW_FRAMES: {
             rawFp = prepareRawOutput(fileName);
             if (rawFp == NULL) {
                 if (encoder != NULL) encoder->release();
@@ -656,7 +657,7 @@
             abort();
     }
 
-    if (gOutputFormat == FORMAT_FRAMES) {
+    if (gOutputFormat == FORMAT_FRAMES || gOutputFormat == FORMAT_RAW_FRAMES) {
         // TODO: if we want to make this a proper feature, we should output
         //       an outer header with version info.  Right now we never change
         //       the frame size or format, so we could conceivably just send
@@ -676,7 +677,8 @@
             // stop was requested, but this will do for now.  (It almost
             // works because wait() wakes when a signal hits, but we
             // need to handle the edge cases.)
-            err = frameOutput->copyFrame(rawFp, 250000);
+            bool rawFrames = gOutputFormat == FORMAT_RAW_FRAMES;
+            err = frameOutput->copyFrame(rawFp, 250000, rawFrames);
             if (err == ETIMEDOUT) {
                 err = NO_ERROR;
             } else if (err != NO_ERROR) {
@@ -950,6 +952,8 @@
                 gOutputFormat = FORMAT_H264;
             } else if (strcmp(optarg, "frames") == 0) {
                 gOutputFormat = FORMAT_FRAMES;
+            } else if (strcmp(optarg, "raw-frames") == 0) {
+                gOutputFormat = FORMAT_RAW_FRAMES;
             } else {
                 fprintf(stderr, "Unknown format '%s'\n", optarg);
                 return 2;
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 176f72d..dd13fea 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -38,8 +38,8 @@
 public:
     DECLARE_META_INTERFACE(OMX);
 
-    typedef void *buffer_id;
-    typedef void *node_id;
+    typedef uint32_t buffer_id;
+    typedef uint32_t node_id;
 
     // Given a node_id and the calling process' pid, returns true iff
     // the implementation of the OMX interface lives in the same
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 39e57de..a1e32c9 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -185,7 +185,7 @@
     };
 
     struct BufferInfo {
-        void *mBufferID;
+        uint32_t mBufferID;
         sp<ABuffer> mData;
         sp<ABuffer> mEncryptedData;
         sp<AMessage> mNotify;
diff --git a/include/ndk/NdkMediaCodec.h b/include/ndk/NdkMediaCodec.h
index 28d121c..dd869f6 100644
--- a/include/ndk/NdkMediaCodec.h
+++ b/include/ndk/NdkMediaCodec.h
@@ -30,6 +30,7 @@
 #include <android/native_window.h>
 
 #include "NdkMediaCrypto.h"
+#include "NdkMediaError.h"
 #include "NdkMediaFormat.h"
 
 #ifdef __cplusplus
@@ -78,12 +79,12 @@
 /**
  * delete the codec and free its resources
  */
-int AMediaCodec_delete(AMediaCodec*);
+media_status_t AMediaCodec_delete(AMediaCodec*);
 
 /**
  * Configure the codec. For decoding you would typically get the format from an extractor.
  */
-int AMediaCodec_configure(
+media_status_t AMediaCodec_configure(
         AMediaCodec*,
         const AMediaFormat* format,
         ANativeWindow* surface,
@@ -94,18 +95,18 @@
  * Start the codec. A codec must be configured before it can be started, and must be started
  * before buffers can be sent to it.
  */
-int AMediaCodec_start(AMediaCodec*);
+media_status_t AMediaCodec_start(AMediaCodec*);
 
 /**
  * Stop the codec.
  */
-int AMediaCodec_stop(AMediaCodec*);
+media_status_t AMediaCodec_stop(AMediaCodec*);
 
 /*
  * Flush the codec's input and output. All indices previously returned from calls to
  * AMediaCodec_dequeueInputBuffer and AMediaCodec_dequeueOutputBuffer become invalid.
  */
-int AMediaCodec_flush(AMediaCodec*);
+media_status_t AMediaCodec_flush(AMediaCodec*);
 
 /**
  * Get an input buffer. The specified buffer index must have been previously obtained from
@@ -129,13 +130,13 @@
 /**
  * Send the specified buffer to the codec for processing.
  */
-int AMediaCodec_queueInputBuffer(AMediaCodec*,
+media_status_t AMediaCodec_queueInputBuffer(AMediaCodec*,
         size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags);
 
 /**
  * Send the specified buffer to the codec for processing.
  */
-int AMediaCodec_queueSecureInputBuffer(AMediaCodec*,
+media_status_t AMediaCodec_queueSecureInputBuffer(AMediaCodec*,
         size_t idx, off_t offset, AMediaCodecCryptoInfo*, uint64_t time, uint32_t flags);
 
 /**
@@ -147,7 +148,7 @@
 /**
  * Release and optionally render the specified buffer.
  */
-int AMediaCodec_releaseOutputBuffer(AMediaCodec*, size_t idx, bool render);
+media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec*, size_t idx, bool render);
 
 
 typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata);
@@ -158,7 +159,8 @@
  * Note that you cannot perform any operations on the mediacodec from within the callback.
  * If you need to perform mediacodec operations, you must do so on a different thread.
  */
-int AMediaCodec_setNotificationCallback(AMediaCodec*, OnCodecEvent callback, void *userdata);
+media_status_t AMediaCodec_setNotificationCallback(
+        AMediaCodec*, OnCodecEvent callback, void *userdata);
 
 
 enum {
@@ -182,14 +184,14 @@
  * delete an AMediaCodecCryptoInfo created previously with AMediaCodecCryptoInfo_new, or
  * obtained from AMediaExtractor
  */
-int AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo*);
+media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo*);
 
 size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo*);
-int AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo*, uint8_t *dst);
-int AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo*, uint8_t *dst);
+media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo*, uint8_t *dst);
+media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo*, uint8_t *dst);
 uint32_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo*);
-int AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo*, size_t *dst);
-int AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo*, size_t *dst);
+media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo*, size_t *dst);
+media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo*, size_t *dst);
 
 #ifdef __cplusplus
 } // extern "C"
diff --git a/include/ndk/NdkMediaDrm.h b/include/ndk/NdkMediaDrm.h
index 1322a9d..04c371c 100644
--- a/include/ndk/NdkMediaDrm.h
+++ b/include/ndk/NdkMediaDrm.h
@@ -27,6 +27,8 @@
 #ifndef _NDK_MEDIA_DRM_H
 #define _NDK_MEDIA_DRM_H
 
+#include <NdkMediaError.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -47,23 +49,6 @@
 typedef AMediaDrmByteArray AMediaDrmKeySetId;
 typedef AMediaDrmByteArray AMediaDrmSecureStop;
 
-#define MEDIADRM_ERROR_BASE -2000
-
-typedef enum {
-    MEDIADRM_OK = 0,
-    MEDIADRM_NOT_PROVISIONED_ERROR    = MEDIADRM_ERROR_BASE - 1,
-    MEDIADRM_RESOURCE_BUSY_ERROR      = MEDIADRM_ERROR_BASE - 2,
-    MEDIADRM_DEVICE_REVOKED_ERROR     = MEDIADRM_ERROR_BASE - 3,
-    MEDIADRM_SHORT_BUFFER             = MEDIADRM_ERROR_BASE - 4,
-    MEDIADRM_INVALID_OBJECT_ERROR     = MEDIADRM_ERROR_BASE - 5,
-    MEDIADRM_INVALID_PARAMETER_ERROR  = MEDIADRM_ERROR_BASE - 6,
-    MEDIADRM_SESSION_NOT_OPENED_ERROR = MEDIADRM_ERROR_BASE - 7,
-    MEDIADRM_TAMPER_DETECTED_ERROR    = MEDIADRM_ERROR_BASE - 8,
-    MEDIADRM_VERIFY_FAILED            = MEDIADRM_ERROR_BASE - 9,
-    MEDIADRM_NEED_KEY_ERROR           = MEDIADRM_ERROR_BASE - 10,
-    MEDIADRM_LICENSE_EXPIRED_ERROR    = MEDIADRM_ERROR_BASE - 11,
-    MEDIADRM_UNKNOWN_ERROR            = MEDIADRM_ERROR_BASE - 12,
-} mediadrm_status_t;
 
 typedef enum AMediaDrmEventType {
     /**
@@ -122,7 +107,7 @@
  *
  * listener is the callback that will be invoked on event
  */
-void AMediaDrm_setOnEventListener(AMediaDrm *, AMediaDrmEventListener listener);
+media_status_t AMediaDrm_setOnEventListener(AMediaDrm *, AMediaDrmEventListener listener);
 
 /**
  * Open a new session with the MediaDrm object.  A session ID is returned.
@@ -130,13 +115,13 @@
  * returns MEDIADRM_NOT_PROVISIONED_ERROR if provisioning is needed
  * returns MEDIADRM_RESOURCE_BUSY_ERROR if required resources are in use
  */
-mediadrm_status_t AMediaDrm_openSession(AMediaDrm *, AMediaDrmSessionId &sessionId);
+media_status_t AMediaDrm_openSession(AMediaDrm *, AMediaDrmSessionId &sessionId);
 
 /**
  * Close a session on the MediaDrm object that was previously opened
  * with AMediaDrm_openSession.
  */
-mediadrm_status_t AMediaDrm_closeSession(AMediaDrm *, const AMediaDrmSessionId &sessionId);
+media_status_t AMediaDrm_closeSession(AMediaDrm *, const AMediaDrmSessionId &sessionId);
 
 typedef enum AMediaDrmKeyType {
     /**
@@ -213,7 +198,7 @@
  * returns MEDIADRM_NOT_PROVISIONED_ERROR if reprovisioning is needed, due to a
  * problem with the device certificate.
 */
-mediadrm_status_t AMediaDrm_getKeyRequest(AMediaDrm *, const AMediaDrmScope &scope,
+media_status_t AMediaDrm_getKeyRequest(AMediaDrm *, const AMediaDrmScope &scope,
         const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
         const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
         const uint8_t *&keyRequest, size_t &keyRequestSize);
@@ -235,7 +220,7 @@
  * responseSize should be set to the size of the response in bytes
  */
 
-mediadrm_status_t AMediaDrm_provideKeyResponse(AMediaDrm *, const AMediaDrmScope &scope,
+media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *, const AMediaDrmScope &scope,
         const uint8_t *response, size_t responseSize, AMediaDrmKeySetId &keySetId);
 
 /**
@@ -245,7 +230,7 @@
  * sessionId is the session ID for the DRM session
  * keySetId identifies the saved key set to restore
  */
-mediadrm_status_t AMediaDrm_restoreKeys(AMediaDrm *, const AMediaDrmSessionId &sessionId,
+media_status_t AMediaDrm_restoreKeys(AMediaDrm *, const AMediaDrmSessionId &sessionId,
         const AMediaDrmKeySetId &keySetId);
 
 /**
@@ -253,7 +238,7 @@
  *
  * keySetId identifies keys to remove
  */
-mediadrm_status_t AMediaDrm_removeKeys(AMediaDrm *, const AMediaDrmSessionId &keySetId);
+media_status_t AMediaDrm_removeKeys(AMediaDrm *, const AMediaDrmSessionId &keySetId);
 
 /**
  * Request an informative description of the key status for the session.  The status is
@@ -268,7 +253,7 @@
  * to be returned is greater than *numPairs, MEDIADRM_SHORT_BUFFER will be returned
  * and numPairs will be set to the number of pairs available.
  */
-mediadrm_status_t AMediaDrm_queryKeyStatus(AMediaDrm *, const AMediaDrmSessionId &sessionId,
+media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *, const AMediaDrmSessionId &sessionId,
         AMediaDrmKeyValue *keyValuePairs, size_t &numPairs);
 
 
@@ -287,7 +272,7 @@
  *       the provisioning request should be sent to.  It will remain accessible until
  *       the next call to getProvisionRequest.
  */
-mediadrm_status_t AMediaDrm_getProvisionRequest(AMediaDrm *, const uint8_t *&provisionRequest,
+media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *, const uint8_t *&provisionRequest,
         size_t &provisionRequestSize, const char *&serverUrl);
 
 
@@ -302,7 +287,7 @@
  * returns MEDIADRM_DEVICE_REVOKED_ERROR if the response indicates that the
  * server rejected the request
  */
-mediadrm_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *,
+media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *,
         const uint8_t *response, size_t responseSize);
 
 
@@ -327,7 +312,7 @@
  * MEDIADRM_SHORT_BUFFER will be returned and *numSecureStops will be set to the
  * number required.
  */
-mediadrm_status_t AMediaDrm_getSecureStops(AMediaDrm *,
+media_status_t AMediaDrm_getSecureStops(AMediaDrm *,
         AMediaDrmSecureStop *secureStops, size_t &numSecureStops);
 
 /**
@@ -336,7 +321,7 @@
  *
  * ssRelease is the server response indicating which secure stops to release
  */
-mediadrm_status_t AMediaDrm_releaseSecureStops(AMediaDrm *,
+media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *,
         const AMediaDrmSecureStop &ssRelease);
 
 /**
@@ -369,7 +354,7 @@
  * memory that the value resides in is owned by the NDK MediaDrm API and
  * will remain valid until the next call to AMediaDrm_getPropertyString.
  */
-mediadrm_status_t AMediaDrm_getPropertyString(AMediaDrm *, const char *propertyName,
+media_status_t AMediaDrm_getPropertyString(AMediaDrm *, const char *propertyName,
         const char *&propertyValue);
 
 /**
@@ -384,19 +369,19 @@
  * memory that the value resides in is owned by the NDK MediaDrm API and
  * will remain valid until the next call to AMediaDrm_getPropertyByteArray.
  */
-mediadrm_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *, const char *propertyName,
+media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *, const char *propertyName,
         AMediaDrmByteArray &propertyValue);
 
 /**
  * Set a DRM engine plugin String property value.
  */
-mediadrm_status_t AMediaDrm_setPropertyString(AMediaDrm *, const char *propertyName,
+media_status_t AMediaDrm_setPropertyString(AMediaDrm *, const char *propertyName,
         const char *value);
 
 /**
  * Set a DRM engine plugin byte array property value.
  */
-mediadrm_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *, const char *propertyName,
+media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *, const char *propertyName,
         const uint8_t *value, size_t valueSize);
 
 /**
@@ -424,7 +409,7 @@
  * to use is identified by the 16 byte keyId.  The key must have been loaded into
  * the session using provideKeyResponse.
  */
-mediadrm_status_t AMediaDrm_encrypt(AMediaDrm *, const AMediaDrmSessionId &sessionId,
+media_status_t AMediaDrm_encrypt(AMediaDrm *, const AMediaDrmSessionId &sessionId,
         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
         const uint8_t *input, uint8_t *output, size_t dataSize);
 
@@ -435,7 +420,7 @@
  * to use is identified by the 16 byte keyId.  The key must have been loaded into
  * the session using provideKeyResponse.
  */
-mediadrm_status_t AMediaDrm_decrypt(AMediaDrm *, const AMediaDrmSessionId &sessionId,
+media_status_t AMediaDrm_decrypt(AMediaDrm *, const AMediaDrmSessionId &sessionId,
         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
         const uint8_t *input, uint8_t *output, size_t dataSize);
 
@@ -448,7 +433,7 @@
  * by the 16 byte keyId.  The key must have been loaded into the session using
  * provideKeyResponse.
  */
-mediadrm_status_t AMediaDrm_sign(AMediaDrm *, const AMediaDrmSessionId &sessionId,
+media_status_t AMediaDrm_sign(AMediaDrm *, const AMediaDrmSessionId &sessionId,
         const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
         uint8_t *signature, size_t *signatureSize);
 
@@ -459,7 +444,7 @@
  * use is identified by the 16 byte keyId.  The key must have been loaded into the
  * session using provideKeyResponse.
  */
-mediadrm_status_t AMediaDrm_verify(AMediaDrm *, const AMediaDrmSessionId &sessionId,
+media_status_t AMediaDrm_verify(AMediaDrm *, const AMediaDrmSessionId &sessionId,
         const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
         const uint8_t *signature, size_t signatureSize);
 
diff --git a/include/ndk/NdkMediaError.h b/include/ndk/NdkMediaError.h
index b89a10e..12613eb 100644
--- a/include/ndk/NdkMediaError.h
+++ b/include/ndk/NdkMediaError.h
@@ -32,13 +32,28 @@
 extern "C" {
 #endif
 
-enum {
-    AMEDIAERROR_BASE = -10000,
+typedef enum {
+    AMEDIA_OK = 0,
 
-    AMEDIAERROR_GENERIC     = AMEDIAERROR_BASE,
-    AMEDIAERROR_MALFORMED   = AMEDIAERROR_BASE - 1,
-    AMEDIAERROR_UNSUPPORTED = AMEDIAERROR_BASE - 2
-};
+    AMEDIA_ERROR_BASE                  = -10000,
+    AMEDIA_ERROR_UNKNOWN               = AMEDIA_ERROR_BASE,
+    AMEDIA_ERROR_MALFORMED             = AMEDIA_ERROR_BASE - 1,
+    AMEDIA_ERROR_UNSUPPORTED           = AMEDIA_ERROR_BASE - 2,
+    AMEDIA_ERROR_INVALID_OBJECT        = AMEDIA_ERROR_BASE - 3,
+    AMEDIA_ERROR_INVALID_PARAMETER     = AMEDIA_ERROR_BASE - 4,
+
+    AMEDIA_DRM_ERROR_BASE              = -20000,
+    AMEDIA_DRM_NOT_PROVISIONED         = AMEDIA_DRM_ERROR_BASE - 1,
+    AMEDIA_DRM_RESOURCE_BUSY           = AMEDIA_DRM_ERROR_BASE - 2,
+    AMEDIA_DRM_DEVICE_REVOKED          = AMEDIA_DRM_ERROR_BASE - 3,
+    AMEDIA_DRM_SHORT_BUFFER            = AMEDIA_DRM_ERROR_BASE - 4,
+    AMEDIA_DRM_SESSION_NOT_OPENED      = AMEDIA_DRM_ERROR_BASE - 5,
+    AMEDIA_DRM_TAMPER_DETECTED         = AMEDIA_DRM_ERROR_BASE - 6,
+    AMEDIA_DRM_VERIFY_FAILED           = AMEDIA_DRM_ERROR_BASE - 7,
+    AMEDIA_DRM_NEED_KEY                = AMEDIA_DRM_ERROR_BASE - 8,
+    AMEDIA_DRM_LICENSE_EXPIRED         = AMEDIA_DRM_ERROR_BASE - 9,
+
+} media_status_t;
 
 
 #ifdef __cplusplus
diff --git a/include/ndk/NdkMediaExtractor.h b/include/ndk/NdkMediaExtractor.h
index 9e50ec0..2ba69fb 100644
--- a/include/ndk/NdkMediaExtractor.h
+++ b/include/ndk/NdkMediaExtractor.h
@@ -50,22 +50,22 @@
 /**
  * Delete a previously created media extractor
  */
-int AMediaExtractor_delete(AMediaExtractor*);
+media_status_t AMediaExtractor_delete(AMediaExtractor*);
 
 /**
  *  Set the file descriptor from which the extractor will read.
  */
-int AMediaExtractor_setDataSourceFd(AMediaExtractor*, int fd, off64_t offset, off64_t length);
+media_status_t AMediaExtractor_setDataSourceFd(AMediaExtractor*, int fd, off64_t offset, off64_t length);
 
 /**
  * Set the URI from which the extractor will read.
  */
-int AMediaExtractor_setDataSource(AMediaExtractor*, const char *location); // TODO support headers
+media_status_t AMediaExtractor_setDataSource(AMediaExtractor*, const char *location); // TODO support headers
 
 /**
  * Return the number of tracks in the previously specified media file
  */
-int AMediaExtractor_getTrackCount(AMediaExtractor*);
+size_t AMediaExtractor_getTrackCount(AMediaExtractor*);
 
 /**
  * Return the format of the specified track. The caller must free the returned format
@@ -78,23 +78,23 @@
  * Selecting the same track multiple times has no effect, the track is
  * only selected once.
  */
-int AMediaExtractor_selectTrack(AMediaExtractor*, size_t idx);
+media_status_t AMediaExtractor_selectTrack(AMediaExtractor*, size_t idx);
 
 /**
  * Unselect the specified track. Subsequent calls to readSampleData, getSampleTrackIndex and
  * getSampleTime only retrieve information for the subset of tracks selected..
  */
-int AMediaExtractor_unselectTrack(AMediaExtractor*, size_t idx);
+media_status_t AMediaExtractor_unselectTrack(AMediaExtractor*, size_t idx);
 
 /**
  * Read the current sample.
  */
-int AMediaExtractor_readSampleData(AMediaExtractor*, uint8_t *buffer, size_t capacity);
+ssize_t AMediaExtractor_readSampleData(AMediaExtractor*, uint8_t *buffer, size_t capacity);
 
 /**
  * Read the current sample's flags.
  */
-int AMediaExtractor_getSampleFlags(AMediaExtractor*); // see definitions below
+uint32_t AMediaExtractor_getSampleFlags(AMediaExtractor*); // see definitions below
 
 /**
  * Returns the track index the current sample originates from (or -1
diff --git a/include/ndk/NdkMediaFormat.h b/include/ndk/NdkMediaFormat.h
index e0caeab..ab29791 100644
--- a/include/ndk/NdkMediaFormat.h
+++ b/include/ndk/NdkMediaFormat.h
@@ -29,6 +29,8 @@
 
 #include <sys/types.h>
 
+#include "NdkMediaError.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -37,7 +39,7 @@
 typedef struct AMediaFormat AMediaFormat;
 
 AMediaFormat *AMediaFormat_new();
-int AMediaFormat_delete(AMediaFormat*);
+media_status_t AMediaFormat_delete(AMediaFormat*);
 
 /**
  * Human readable representation of the format. The returned string is owned by the format,
diff --git a/include/ndk/NdkMediaMuxer.h b/include/ndk/NdkMediaMuxer.h
index deb150d..db183e9 100644
--- a/include/ndk/NdkMediaMuxer.h
+++ b/include/ndk/NdkMediaMuxer.h
@@ -30,8 +30,9 @@
 
 #include <sys/types.h>
 
-#include "NdkMediaFormat.h"
 #include "NdkMediaCodec.h"
+#include "NdkMediaError.h"
+#include "NdkMediaFormat.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -53,19 +54,19 @@
 /**
  * Delete a previously created media muxer
  */
-int AMediaMuxer_delete(AMediaMuxer*);
+media_status_t AMediaMuxer_delete(AMediaMuxer*);
 
-int AMediaMuxer_setLocation(AMediaMuxer*, float latitude, float longtitude);
+media_status_t AMediaMuxer_setLocation(AMediaMuxer*, float latitude, float longtitude);
 
-int AMediaMuxer_setOrientationHint(AMediaMuxer*, int degrees);
+media_status_t AMediaMuxer_setOrientationHint(AMediaMuxer*, int degrees);
 
 ssize_t AMediaMuxer_addTrack(AMediaMuxer*, const AMediaFormat* format);
 
-int AMediaMuxer_start(AMediaMuxer*);
+media_status_t AMediaMuxer_start(AMediaMuxer*);
 
-int AMediaMuxer_stop(AMediaMuxer*);
+media_status_t AMediaMuxer_stop(AMediaMuxer*);
 
-int AMediaMuxer_writeSampleData(AMediaMuxer *muxer,
+media_status_t AMediaMuxer_writeSampleData(AMediaMuxer *muxer,
         size_t trackIdx, const uint8_t *data, const AMediaCodecBufferInfo &info);
 
 #ifdef __cplusplus
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 3901e79..5116d1e 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <audio_utils/minifloat.h>
 #include <utils/threads.h>
 #include <utils/Log.h>
 #include <utils/RefBase.h>
@@ -110,11 +111,8 @@
                 // force to 32-bit.  The client and server may have different typedefs for size_t.
                 uint32_t    mMinimum;       // server wakes up client if available >= mMinimum
 
-                // Channel volumes are fixed point U4.12, so 0x1000 means 1.0.
-                // Left channel is in [0:15], right channel is in [16:31].
-                // Always read and write the combined pair atomically.
-                // For AudioTrack only, not used by AudioRecord.
-                uint32_t    mVolumeLR;
+                // Stereo gains for AudioTrack only, not used by AudioRecord.
+                gain_minifloat_packed_t mVolumeLR;
 
                 uint32_t    mSampleRate;    // AudioTrack only: client's requested sample rate in Hz
                                             // or 0 == default. Write-only client, read-only server.
@@ -285,8 +283,8 @@
         mCblk->mSendLevel = uint16_t(sendLevel * 0x1000);
     }
 
-    // caller must limit to 0 <= volumeLR <= 0x10001000
-    void        setVolumeLR(uint32_t volumeLR) {
+    // set stereo gains
+    void        setVolumeLR(gain_minifloat_packed_t volumeLR) {
         mCblk->mVolumeLR = volumeLR;
     }
 
@@ -405,7 +403,7 @@
     // return value of these methods must be validated by the caller
     uint32_t    getSampleRate() const { return mCblk->mSampleRate; }
     uint16_t    getSendLevel_U4_12() const { return mCblk->mSendLevel; }
-    uint32_t    getVolumeLR() const { return mCblk->mVolumeLR; }
+    gain_minifloat_packed_t getVolumeLR() const { return mCblk->mVolumeLR; }
 
     // estimated total number of filled frames available to server to read,
     // which may include non-contiguous frames
diff --git a/media/img_utils/Android.mk b/media/img_utils/Android.mk
new file mode 100644
index 0000000..1cd00bd
--- /dev/null
+++ b/media/img_utils/Android.mk
@@ -0,0 +1,15 @@
+# Copyright 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+include $(call all-subdir-makefiles)
diff --git a/media/img_utils/include/img_utils/ByteArrayOutput.h b/media/img_utils/include/img_utils/ByteArrayOutput.h
new file mode 100644
index 0000000..ba73977
--- /dev/null
+++ b/media/img_utils/include/img_utils/ByteArrayOutput.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMG_UTILS_BYTE_ARRAY_OUTPUT_H
+#define IMG_UTILS_BYTE_ARRAY_OUTPUT_H
+
+#include <img_utils/Output.h>
+
+#include <utils/Errors.h>
+#include <utils/Vector.h>
+
+#include <cutils/compiler.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * Utility class that accumulates written bytes into a buffer.
+ */
+class ANDROID_API ByteArrayOutput : public Output {
+    public:
+
+        ByteArrayOutput();
+
+        virtual ~ByteArrayOutput();
+
+        /**
+         * Open this ByteArrayOutput.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t open();
+
+        /**
+         * Write bytes from the given buffer.  The number of bytes given in the count
+         * argument will be written.  Bytes will be written from the given buffer starting
+         * at the index given in the offset argument.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t write(const uint8_t* buf, size_t offset, size_t count);
+
+        /**
+         * Close this ByteArrayOutput.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t close();
+
+        /**
+         * Get current size of the array of bytes written.
+         */
+        virtual size_t getSize() const;
+
+        /**
+         * Get pointer to array of bytes written.  It is not valid to use this pointer if
+         * open, write, or close is called after this method.
+         */
+        virtual const uint8_t* getArray() const;
+
+    protected:
+        Vector<uint8_t> mByteArray;
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_BYTE_ARRAY_OUTPUT_H*/
diff --git a/media/img_utils/include/img_utils/DngUtils.h b/media/img_utils/include/img_utils/DngUtils.h
new file mode 100644
index 0000000..4389b02
--- /dev/null
+++ b/media/img_utils/include/img_utils/DngUtils.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMG_UTILS_DNG_UTILS_H
+#define IMG_UTILS_DNG_UTILS_H
+
+#include <img_utils/ByteArrayOutput.h>
+#include <img_utils/EndianUtils.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+
+#include <cutils/compiler.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+#define NELEMS(x) ((int) (sizeof(x) / sizeof((x)[0])))
+
+/**
+ * Utility class for building values for the OpcodeList tags specified
+ * in the Adobe DNG 1.4 spec.
+ */
+class ANDROID_API OpcodeListBuilder : public LightRefBase<OpcodeListBuilder> {
+    public:
+        enum CfaLayout {
+            CFA_RGGB = 0,
+            CFA_GRBG,
+            CFA_GBRG,
+            CFA_BGGR,
+        };
+
+        OpcodeListBuilder();
+        virtual ~OpcodeListBuilder();
+
+        /**
+         * Get the total size of this opcode list in bytes.
+         */
+        virtual size_t getSize() const;
+
+        /**
+         * Get the number of opcodes defined in this list.
+         */
+        virtual uint32_t getCount() const;
+
+        /**
+         * Write the opcode list into the given buffer.  This buffer
+         * must be able to hold at least as many elements as returned
+         * by calling the getSize() method.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t buildOpList(/*out*/ uint8_t* buf) const;
+
+        /**
+         * Add GainMap opcode(s) for the given metadata parameters.  The given
+         * CFA layout must match the layout of the shading map passed into the
+         * lensShadingMap parameter.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t addGainMapsForMetadata(uint32_t lsmWidth,
+                                                uint32_t lsmHeight,
+                                                uint32_t activeAreaTop,
+                                                uint32_t activeAreaLeft,
+                                                uint32_t activeAreaBottom,
+                                                uint32_t activeAreaRight,
+                                                CfaLayout cfa,
+                                                const float* lensShadingMap);
+
+
+        /**
+         * Add a GainMap opcode with the given fields.  The mapGains array
+         * must have mapPointsV * mapPointsH * mapPlanes elements.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t addGainMap(uint32_t top,
+                                    uint32_t left,
+                                    uint32_t bottom,
+                                    uint32_t right,
+                                    uint32_t plane,
+                                    uint32_t planes,
+                                    uint32_t rowPitch,
+                                    uint32_t colPitch,
+                                    uint32_t mapPointsV,
+                                    uint32_t mapPointsH,
+                                    double mapSpacingV,
+                                    double mapSpacingH,
+                                    double mapOriginV,
+                                    double mapOriginH,
+                                    uint32_t mapPlanes,
+                                    const float* mapGains);
+
+        // TODO: Add other Opcode methods
+    protected:
+        static const uint32_t FLAG_OPTIONAL = 0x1u;
+        static const uint32_t FLAG_OPTIONAL_FOR_PREVIEW = 0x2u;
+
+        enum {
+            GAIN_MAP_ID = 9,
+            LSM_R_IND = 0,
+            LSM_GE_IND = 1,
+            LSM_GO_IND = 2,
+            LSM_B_IND = 3,
+        };
+
+        uint32_t mCount;
+        ByteArrayOutput mOpList;
+        EndianOutput mEndianOut;
+
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_DNG_UTILS_H*/
diff --git a/media/img_utils/include/img_utils/EndianUtils.h b/media/img_utils/include/img_utils/EndianUtils.h
new file mode 100644
index 0000000..e99be1a
--- /dev/null
+++ b/media/img_utils/include/img_utils/EndianUtils.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMG_UTILS_ENDIAN_UTILS
+#define IMG_UTILS_ENDIAN_UTILS
+
+#include <img_utils/Output.h>
+
+#include <cutils/compiler.h>
+#include <utils/Errors.h>
+#include <stdint.h>
+#include <endian.h>
+#include <assert.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * Endianness types supported.
+ */
+enum ANDROID_API Endianness {
+    UNDEFINED_ENDIAN, // Default endianness will be used.
+    BIG,
+    LITTLE
+};
+
+/**
+ * Convert from the native device endianness to big endian.
+ */
+template<typename T>
+T convertToBigEndian(T in);
+
+/**
+ * Convert from the native device endianness to little endian.
+ */
+template<typename T>
+T convertToLittleEndian(T in);
+
+/**
+ * A utility class for writing to an Output with the given endianness.
+ */
+class ANDROID_API EndianOutput : public Output {
+    public:
+        /**
+         * Wrap the given Output.  Calling write methods will result in
+         * writes to this output.
+         */
+        EndianOutput(Output* out, Endianness end=LITTLE);
+
+        virtual ~EndianOutput();
+
+        /**
+         * Call open on the wrapped output.
+         */
+        virtual status_t open();
+
+        /**
+         * Call close on the wrapped output.
+         */
+        virtual status_t close();
+
+        /**
+         * Set the endianness to use when writing.
+         */
+        virtual void setEndianness(Endianness end);
+
+        /**
+         * Get the currently configured endianness.
+         */
+        virtual Endianness getEndianness() const;
+
+        /**
+         * Get the current number of bytes written by this EndianOutput.
+         */
+        virtual uint32_t getCurrentOffset() const;
+
+
+        // TODO: switch write methods to uint32_t instead of size_t,
+        // the max size of a TIFF files is bounded
+
+        /**
+         * The following methods will write elements from given input buffer to the output.
+         * Count elements in the buffer will be written with the endianness set for this
+         * EndianOutput.  If the given offset is greater than zero, that many elements will
+         * be skipped in the buffer before writing.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t write(const uint8_t* buf, size_t offset, size_t count);
+
+        virtual status_t write(const int8_t* buf, size_t offset, size_t count);
+
+        virtual status_t write(const uint16_t* buf, size_t offset, size_t count);
+
+        virtual status_t write(const int16_t* buf, size_t offset, size_t count);
+
+        virtual status_t write(const uint32_t* buf, size_t offset, size_t count);
+
+        virtual status_t write(const int32_t* buf, size_t offset, size_t count);
+
+        virtual status_t write(const uint64_t* buf, size_t offset, size_t count);
+
+        virtual status_t write(const int64_t* buf, size_t offset, size_t count);
+
+        virtual status_t write(const float* buf, size_t offset, size_t count);
+
+        virtual status_t write(const double* buf, size_t offset, size_t count);
+
+    protected:
+        template<typename T>
+        inline status_t writeHelper(const T* buf, size_t offset, size_t count);
+
+        uint32_t mOffset;
+        Output* mOutput;
+        Endianness mEndian;
+};
+
+template<typename T>
+inline status_t EndianOutput::writeHelper(const T* buf, size_t offset, size_t count) {
+    assert(offset <= count);
+    status_t res = OK;
+    size_t size = sizeof(T);
+    switch(mEndian) {
+        case BIG: {
+            for (size_t i = offset; i < count; ++i) {
+                T tmp = convertToBigEndian<T>(buf[offset + i]);
+                if ((res = mOutput->write(reinterpret_cast<uint8_t*>(&tmp), 0, size))
+                        != OK) {
+                    return res;
+                }
+                mOffset += size;
+            }
+            break;
+        }
+        case LITTLE: {
+            for (size_t i = offset; i < count; ++i) {
+                T tmp = convertToLittleEndian<T>(buf[offset + i]);
+                if ((res = mOutput->write(reinterpret_cast<uint8_t*>(&tmp), 0, size))
+                        != OK) {
+                    return res;
+                }
+                mOffset += size;
+            }
+            break;
+        }
+        default: {
+            return BAD_VALUE;
+        }
+    }
+    return res;
+}
+
+template<>
+inline uint8_t convertToBigEndian(uint8_t in) {
+    return in;
+}
+
+template<>
+inline int8_t convertToBigEndian(int8_t in) {
+    return in;
+}
+
+template<>
+inline uint16_t convertToBigEndian(uint16_t in) {
+    return htobe16(in);
+}
+
+template<>
+inline int16_t convertToBigEndian(int16_t in) {
+    return htobe16(in);
+}
+
+template<>
+inline uint32_t convertToBigEndian(uint32_t in) {
+    return htobe32(in);
+}
+
+template<>
+inline int32_t convertToBigEndian(int32_t in) {
+    return htobe32(in);
+}
+
+template<>
+inline uint64_t convertToBigEndian(uint64_t in) {
+    return htobe64(in);
+}
+
+template<>
+inline int64_t convertToBigEndian(int64_t in) {
+    return htobe64(in);
+}
+
+template<>
+inline uint8_t convertToLittleEndian(uint8_t in) {
+    return in;
+}
+
+template<>
+inline int8_t convertToLittleEndian(int8_t in) {
+    return in;
+}
+
+template<>
+inline uint16_t convertToLittleEndian(uint16_t in) {
+    return htole16(in);
+}
+
+template<>
+inline int16_t convertToLittleEndian(int16_t in) {
+    return htole16(in);
+}
+
+template<>
+inline uint32_t convertToLittleEndian(uint32_t in) {
+    return htole32(in);
+}
+
+template<>
+inline int32_t convertToLittleEndian(int32_t in) {
+    return htole32(in);
+}
+
+template<>
+inline uint64_t convertToLittleEndian(uint64_t in) {
+    return htole64(in);
+}
+
+template<>
+inline int64_t convertToLittleEndian(int64_t in) {
+    return htole64(in);
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_ENDIAN_UTILS*/
+
diff --git a/media/img_utils/include/img_utils/FileInput.h b/media/img_utils/include/img_utils/FileInput.h
new file mode 100644
index 0000000..d3c5ec1
--- /dev/null
+++ b/media/img_utils/include/img_utils/FileInput.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMG_UTILS_FILE_INPUT_H
+#define IMG_UTILS_FILE_INPUT_H
+
+#include <img_utils/Input.h>
+
+#include <cutils/compiler.h>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <stdio.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * Utility class for reading from a file.
+ */
+class ANDROID_API FileInput : public Input {
+    public:
+        /**
+         * Create a file input for the given path.
+         */
+        FileInput(String8 path);
+
+        virtual ~FileInput();
+
+        /**
+         * Open a file descriptor to the path given in the constructor.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t open();
+
+        /**
+         * Read bytes from the file into the given buffer.  At most, the number
+         * of bytes given in the count argument will be read.  Bytes will be written
+         * into the given buffer starting at the index given in the offset argument.
+         *
+         * Returns the number of bytes read.  If an error has occurred, the value pointed
+         * to by the given status_t pointer will be set to a negative error code.
+         */
+        virtual size_t read(uint8_t* buf, size_t offset, size_t count, status_t* err);
+
+        /**
+         * Close the file descriptor to the path given in the constructor.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t close();
+    private:
+        FILE *mFp;
+        String8 mPath;
+        bool mOpen;
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+
+#endif /*IMG_UTILS_INPUT_H*/
diff --git a/media/img_utils/include/img_utils/FileOutput.h b/media/img_utils/include/img_utils/FileOutput.h
new file mode 100644
index 0000000..fd5be27
--- /dev/null
+++ b/media/img_utils/include/img_utils/FileOutput.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMG_UTILS_FILE_OUTPUT_H
+#define IMG_UTILS_FILE_OUTPUT_H
+
+#include <img_utils/Output.h>
+#include <cutils/compiler.h>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <stdio.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+class ANDROID_API FileOutput : public Output {
+    public:
+        FileOutput(String8 path);
+        virtual ~FileOutput();
+        virtual status_t open();
+        virtual status_t write(const uint8_t* buf, size_t offset, size_t count);
+        virtual status_t close();
+    private:
+        FILE *mFp;
+        String8 mPath;
+        bool mOpen;
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_FILE_OUTPUT_H*/
diff --git a/media/img_utils/include/img_utils/Input.h b/media/img_utils/include/img_utils/Input.h
new file mode 100644
index 0000000..2166601
--- /dev/null
+++ b/media/img_utils/include/img_utils/Input.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMG_UTILS_INPUT_H
+#define IMG_UTILS_INPUT_H
+
+#include <cutils/compiler.h>
+#include <utils/Errors.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * Utility class used as a source of bytes.
+ */
+class ANDROID_API Input {
+    public:
+        virtual ~Input();
+
+        /**
+         * Open this Input.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t open();
+
+        /**
+         * Read bytes into the given buffer.  At most, the number of bytes given in the
+         * count argument will be read.  Bytes will be written into the given buffer starting
+         * at the index given in the offset argument.
+         *
+         * Returns the number of bytes read.  If an error has occurred, the value pointed
+         * to by the given status_t pointer will be set to a negative error code.
+         */
+        virtual size_t read(uint8_t* buf, size_t offset, size_t count, status_t* err) = 0;
+
+        /**
+         * Close the Input.  It is not valid to call open on a previously closed Input.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t close();
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+
+#endif /*IMG_UTILS_INPUT_H*/
diff --git a/media/img_utils/include/img_utils/Orderable.h b/media/img_utils/include/img_utils/Orderable.h
new file mode 100644
index 0000000..87253a4
--- /dev/null
+++ b/media/img_utils/include/img_utils/Orderable.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMG_UTILS_ORDERABLE
+#define IMG_UTILS_ORDERABLE
+
+#include <cutils/compiler.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+#define COMPARE_DEF(op) \
+inline bool operator op (const Orderable& orderable) const;
+
+/**
+ * Subclasses of Orderable can be compared and sorted.  This is
+ * intended to be used to create sorted arrays of TIFF entries
+ * and IFDs.
+ */
+class ANDROID_API Orderable  {
+    public:
+        virtual ~Orderable();
+
+        /**
+         * Comparison operatotors are based on the value returned
+         * from this method.
+         */
+        virtual uint32_t getComparableValue() const = 0;
+
+        COMPARE_DEF(>)
+        COMPARE_DEF(<)
+        COMPARE_DEF(>=)
+        COMPARE_DEF(<=)
+        COMPARE_DEF(==)
+        COMPARE_DEF(!=)
+};
+
+#undef COMPARE_DEF
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_ORDERABLE*/
diff --git a/media/img_utils/include/img_utils/Output.h b/media/img_utils/include/img_utils/Output.h
new file mode 100644
index 0000000..35fae23
--- /dev/null
+++ b/media/img_utils/include/img_utils/Output.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMG_UTILS_OUTPUT_H
+#define IMG_UTILS_OUTPUT_H
+
+#include <cutils/compiler.h>
+#include <utils/Errors.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * Utility class used to output bytes.
+ */
+class ANDROID_API Output {
+    public:
+        virtual ~Output();
+
+        /**
+         * Open this Output.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t open();
+
+        /**
+         * Write bytes from the given buffer.  The number of bytes given in the count
+         * argument will be written.  Bytes will be written from the given buffer starting
+         * at the index given in the offset argument.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t write(const uint8_t* buf, size_t offset, size_t count) = 0;
+
+        /**
+         * Close this Output.  It is not valid to call open on a previously closed Output.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t close();
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_OUTPUT_H*/
diff --git a/media/img_utils/include/img_utils/Pair.h b/media/img_utils/include/img_utils/Pair.h
new file mode 100644
index 0000000..d651cac
--- /dev/null
+++ b/media/img_utils/include/img_utils/Pair.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMG_UTILS_PAIR_H
+#define IMG_UTILS_PAIR_H
+
+#include <cutils/compiler.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * Generic pair utility class.  Nothing special here.
+ */
+template<typename F, typename S>
+class ANDROID_API Pair {
+    public:
+        F first;
+        S second;
+
+        Pair() {}
+
+        Pair(const Pair& o) : first(o.first), second(o.second) {}
+
+        Pair(const F& f, const S& s) : first(f), second(s) {}
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_PAIR_H*/
diff --git a/media/img_utils/include/img_utils/SortedEntryVector.h b/media/img_utils/include/img_utils/SortedEntryVector.h
new file mode 100644
index 0000000..f059a82
--- /dev/null
+++ b/media/img_utils/include/img_utils/SortedEntryVector.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMG_UTILS_SORTED_ENTRY_VECTOR_H
+#define IMG_UTILS_SORTED_ENTRY_VECTOR_H
+
+#include <img_utils/TiffEntry.h>
+
+#include <utils/StrongPointer.h>
+#include <utils/SortedVector.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * Subclass of SortedVector that has been extended to
+ * do comparisons/lookups based on the tag ID of the entries.
+ */
+class SortedEntryVector : public SortedVector<sp<TiffEntry> > {
+    public:
+        virtual ~SortedEntryVector();
+
+        /**
+         * Returns the index of the entry with the given tag ID, or
+         * -1 if none exists.
+         */
+        ssize_t indexOfTag(uint16_t tag) const;
+
+    protected:
+        /**
+         * Compare tag ID.
+         */
+        virtual int do_compare(const void* lhs, const void* rhs) const;
+};
+
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_SORTED_ENTRY_VECTOR_H*/
diff --git a/media/img_utils/include/img_utils/TagDefinitions.h b/media/img_utils/include/img_utils/TagDefinitions.h
new file mode 100644
index 0000000..9232e58
--- /dev/null
+++ b/media/img_utils/include/img_utils/TagDefinitions.h
@@ -0,0 +1,1139 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMG_UTILS_TIFF_TAG_DEFINITION_H
+#define IMG_UTILS_TIFF_TAG_DEFINITION_H
+
+#include <img_utils/TiffEntry.h>
+#include <img_utils/Output.h>
+#include <img_utils/TiffHelpers.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * Tag definitions contain information about standard TIFF compatible tags.
+ */
+typedef struct TagDefinition {
+    // The specified tag ID.
+    uint16_t tagId;
+    // The default type for this tag.  This must be a valid TIFF type.
+    TagType defaultType;
+    // The default Image File Directory (IFD) for this tag.
+    uint32_t defaultIfd;
+    // The valid count for this tag, or 0 if the count is not fixed.
+    uint32_t fixedCount;
+    // The endianness of the tag value, or UNDEFINED_ENDIAN if there is no fixed endian
+    Endianness fixedEndian;
+} TagDefinition_t;
+
+/**
+ * Convenience defines for tag ids.
+ */
+enum {
+    TAG_RAWTOPREVIEWGAIN = 0xC7A8u,
+    TAG_NEWRAWIMAGEDIGEST = 0xC7A7u,
+    TAG_ORIGINALDEFAULTCROPSIZE = 0xC793u,
+    TAG_ORIGINALBESTQUALITYFINALSIZE = 0xC792u,
+    TAG_ORIGINALDEFAULTFINALSIZE = 0xC791u,
+    TAG_PROFILEHUESATMAPENCODING = 0xC7A3u,
+    TAG_PROFILELOOKTABLEENCODING = 0xC7A4u,
+    TAG_BASELINEEXPOSUREOFFSET = 0xC7A5u,
+    TAG_DEFAULTBLACKRENDER = 0xC7A6u,
+    TAG_DEFAULTUSERCROP = 0xC7B5u,
+    TAG_NOISEPROFILE = 0xC761u,
+    TAG_OPCODELIST3 = 0xC74Eu,
+    TAG_OPCODELIST2 = 0xC741u,
+    TAG_OPCODELIST1 = 0xC740u,
+    TAG_PROFILELOOKTABLEDATA = 0xC726u,
+    TAG_PROFILELOOKTABLEDIMS = 0xC725u,
+    TAG_ROWINTERLEAVEFACTOR = 0xC71Fu,
+    TAG_SUBTILEBLOCKSIZE = 0xC71Eu,
+    TAG_ORIGINALRAWFILEDIGEST = 0xC71Du,
+    TAG_RAWIMAGEDIGEST = 0xC71Cu,
+    TAG_PREVIEWDATETIME = 0xC71Bu,
+    TAG_PREVIEWCOLORSPACE = 0xC71Au,
+    TAG_PREVIEWSETTINGSDIGEST = 0xC719u,
+    TAG_PREVIEWSETTINGSNAME = 0xC718u,
+    TAG_PREVIEWAPPLICATIONVERSION = 0xC717u,
+    TAG_PREVIEWAPPLICATIONNAME = 0xC716u,
+    TAG_FORWARDMATRIX2 = 0xC715u,
+    TAG_FORWARDMATRIX1 = 0xC714u,
+    TAG_PROFILECOPYRIGHT = 0xC6FEu,
+    TAG_PROFILEEMBEDPOLICY = 0xC6FDu,
+    TAG_PROFILETONECURVE = 0xC6FCu,
+    TAG_PROFILEHUESATMAPDATA2 = 0xC6FBu,
+    TAG_PROFILEHUESATMAPDATA1 = 0xC6FAu,
+    TAG_PROFILEHUESATMAPDIMS = 0xC6F9u,
+    TAG_PROFILENAME = 0xC6F8u,
+    TAG_NOISEREDUCTIONAPPLIED = 0xC6F7u,
+    TAG_ASSHOTPROFILENAME = 0xC6F6u,
+    TAG_EXTRACAMERAPROFILES = 0xC6F5u,
+    TAG_PROFILECALIBRATIONSIGNATURE = 0xC6F4u,
+    TAG_CAMERACALIBRATIONSIGNATURE = 0xC6F3u,
+    TAG_COLORIMETRICREFERENCE = 0xC6BFu,
+    TAG_CURRENTPREPROFILEMATRIX = 0xC692u,
+    TAG_CURRENTICCPROFILE = 0xC691u,
+    TAG_ASSHOTPREPROFILEMATRIX = 0xC690u,
+    TAG_ASSHOTICCPROFILE = 0xC68Fu,
+    TAG_MASKEDAREAS = 0xC68Eu,
+    TAG_ACTIVEAREA = 0xC68Du,
+    TAG_ORIGINALRAWFILEDATA = 0xC68Cu,
+    TAG_ORIGINALRAWFILENAME = 0xC68Bu,
+    TAG_RAWDATAUNIQUEID = 0xC65Du,
+    TAG_MAKERNOTESAFETY = 0xC635u,
+    TAG_DNGPRIVATEDATA = 0xC634u,
+    TAG_SHADOWSCALE = 0xC633u,
+    TAG_ANTIALIASSTRENGTH = 0xC632u,
+    TAG_CHROMABLURRADIUS = 0xC631u,
+    TAG_LENSINFO = 0xC630u,
+    TAG_CAMERASERIALNUMBER = 0xC62Fu,
+    TAG_LINEARRESPONSELIMIT = 0xC62Eu,
+    TAG_BAYERGREENSPLIT = 0xC62Du,
+    TAG_BASELINESHARPNESS = 0xC62Cu,
+    TAG_BASELINENOISE = 0xC62Bu,
+    TAG_BASELINEEXPOSURE = 0xC62Au,
+    TAG_ASSHOTWHITEXY = 0xC629u,
+    TAG_ASSHOTNEUTRAL = 0xC628u,
+    TAG_ANALOGBALANCE = 0xC627u,
+    TAG_REDUCTIONMATRIX2 = 0xC626u,
+    TAG_REDUCTIONMATRIX1 = 0xC625u,
+    TAG_CAMERACALIBRATION2 = 0xC624u,
+    TAG_CAMERACALIBRATION1 = 0xC623u,
+    TAG_COLORMATRIX2 = 0xC622u,
+    TAG_COLORMATRIX1 = 0xC621u,
+    TAG_CALIBRATIONILLUMINANT2 = 0xC65Bu,
+    TAG_CALIBRATIONILLUMINANT1 = 0xC65Au,
+    TAG_DEFAULTCROPSIZE = 0xC620u,
+    TAG_DEFAULTCROPORIGIN = 0xC61Fu,
+    TAG_BESTQUALITYSCALE = 0xC65Cu,
+    TAG_DEFAULTSCALE = 0xC61Eu,
+    TAG_WHITELEVEL = 0xC61Du,
+    TAG_BLACKLEVELDELTAV = 0xC61Cu,
+    TAG_BLACKLEVELDELTAH = 0xC61Bu,
+    TAG_BLACKLEVEL = 0xC61Au,
+    TAG_BLACKLEVELREPEATDIM = 0xC619u,
+    TAG_LINEARIZATIONTABLE = 0xC618u,
+    TAG_CFALAYOUT = 0xC617u,
+    TAG_CFAPLANECOLOR = 0xC616u,
+    TAG_LOCALIZEDCAMERAMODEL = 0xC615u,
+    TAG_UNIQUECAMERAMODEL = 0xC614u,
+    TAG_DNGBACKWARDVERSION = 0xC613u,
+    TAG_DNGVERSION = 0xC612u,
+    TAG_SUBFILETYPE = 0x00FFu,
+    TAG_YRESOLUTION = 0x011Bu,
+    TAG_XRESOLUTION = 0x011Au,
+    TAG_THRESHHOLDING = 0x0107u,
+    TAG_STRIPOFFSETS = 0x0111u,
+    TAG_STRIPBYTECOUNTS = 0x0117u,
+    TAG_SOFTWARE = 0x0131u,
+    TAG_SAMPLESPERPIXEL = 0x0115u,
+    TAG_ROWSPERSTRIP = 0x0116u,
+    TAG_RESOLUTIONUNIT = 0x0128u,
+    TAG_PLANARCONFIGURATION = 0x011Cu,
+    TAG_PHOTOMETRICINTERPRETATION = 0x0106u,
+    TAG_ORIENTATION = 0x0112u,
+    TAG_NEWSUBFILETYPE = 0x00FEu,
+    TAG_MODEL = 0x0110u,
+    TAG_MINSAMPLEVALUE = 0x0118u,
+    TAG_MAXSAMPLEVALUE = 0x0119u,
+    TAG_MAKE = 0x010Fu,
+    TAG_IMAGEWIDTH = 0x0100u,
+    TAG_IMAGELENGTH = 0x0101u,
+    TAG_IMAGEDESCRIPTION = 0x010Eu,
+    TAG_HOSTCOMPUTER = 0x013Cu,
+    TAG_GRAYRESPONSEUNIT = 0x0122u,
+    TAG_GRAYRESPONSECURVE = 0x0123u,
+    TAG_FREEOFFSETS = 0x0120u,
+    TAG_FREEBYTECOUNTS = 0x0121u,
+    TAG_FILLORDER = 0x010Au,
+    TAG_EXTRASAMPLES = 0x0152u,
+    TAG_DATETIME = 0x0132u,
+    TAG_COPYRIGHT = 0x8298u,
+    TAG_COMPRESSION = 0x0103u,
+    TAG_COLORMAP = 0x0140u,
+    TAG_CELLWIDTH = 0x0108u,
+    TAG_CELLLENGTH = 0x0109u,
+    TAG_BITSPERSAMPLE = 0x0102u,
+    TAG_ARTIST = 0x013Bu,
+    TAG_EXIFVERSION = 0x9000u,
+    TAG_CFAREPEATPATTERNDIM = 0x828Du,
+    TAG_CFAPATTERN = 0x828Eu,
+    TAG_SUBIFDS = 0x014Au,
+};
+
+/**
+ * TIFF_EP_TAG_DEFINITIONS contains tags defined in the TIFF EP spec
+ */
+const TagDefinition_t TIFF_EP_TAG_DEFINITIONS[] =  {
+    { // PhotometricInterpretation
+        0x0106u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // SubIfds
+        0x014Au,
+        LONG,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CFAPattern
+        0x828Eu,
+        BYTE,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CFARepeatPatternDim
+        0x828Du,
+        SHORT,
+        IFD_0,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    /*TODO: Remaining TIFF EP tags*/
+};
+
+/**
+ * EXIF_2_3_TAG_DEFINITIONS contains tags defined in the Jeita EXIF 2.3 spec
+ */
+const TagDefinition_t EXIF_2_3_TAG_DEFINITIONS[] = {
+    { // ExifVersion
+        0x9000u,
+        UNDEFINED,
+        IFD_0,
+        4,
+        UNDEFINED_ENDIAN
+    },
+    /*TODO: Remaining EXIF 2.3 tags*/
+};
+
+/**
+ * TIFF_6_TAG_DEFINITIONS contains tags defined in the TIFF 6.0 spec
+ */
+const TagDefinition_t TIFF_6_TAG_DEFINITIONS[] = {
+    { // SubFileType
+        0x00FFu,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // Artist
+        0x013Bu,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // BitsPerSample
+        0x0102u,
+        SHORT,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CellLength
+        0x0109u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // CellWidth
+        0x0108u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ColorMap
+        0x0140u,
+        SHORT,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // Compression
+        0x0103u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // Copyright
+        0x8298u,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // DateTime
+        0x0132u,
+        ASCII,
+        IFD_0,
+        20,
+        UNDEFINED_ENDIAN
+    },
+    { // ExtraSamples
+        0x0152u,
+        SHORT,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // FillOrder
+        0x010Au,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // FreeByteCounts
+        0x0121u,
+        LONG,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // FreeOffsets
+        0x0120u,
+        LONG,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // GrayResponseCurve
+        0x0123u,
+        SHORT,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // GrayResponseUnit
+        0x0122u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // HostComputer
+        0x013Cu,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ImageDescription
+        0x010Eu,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ImageLength
+        0x0101u,
+        LONG,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ImageWidth
+        0x0100u,
+        LONG,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // Make
+        0x010Fu,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // MaxSampleValue
+        0x0119u,
+        SHORT,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // MinSampleValue
+        0x0118u,
+        SHORT,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // Model
+        0x0110u,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // NewSubfileType
+        0x00FEu,
+        LONG,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // Orientation
+        0x0112u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // PhotoMetricInterpretation
+        0x0106u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // PlanarConfiguration
+        0x011Cu,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ResolutionUnit
+        0x0128u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // RowsPerStrip
+        0x0116u,
+        LONG,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // SamplesPerPixel
+        0x0115u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // Software
+        0x0131u,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // StripByteCounts
+        0x0117u,
+        LONG,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // StripOffsets
+        0x0111u,
+        LONG,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // SubfileType
+        0x00FFu,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // Threshholding
+        0x0107u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // XResolution
+        0x011Au,
+        RATIONAL,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // YResolution
+        0x011Bu,
+        RATIONAL,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // YResolution
+        0x011Bu,
+        RATIONAL,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    }
+};
+
+/**
+ * DNG_TAG_DEFINITIONS contains tags defined in the DNG 1.4 spec
+ */
+const TagDefinition_t DNG_TAG_DEFINITIONS[] = {
+    { // DNGVersion
+        0xC612u,
+        BYTE,
+        IFD_0,
+        4,
+        UNDEFINED_ENDIAN
+    },
+    { // DNGBackwardVersion
+        0xC613u,
+        BYTE,
+        IFD_0,
+        4,
+        UNDEFINED_ENDIAN
+    },
+    { // UniqueCameraModel
+        0xC614u,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // LocalizedCameraModel
+        0xC615u,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CFAPlaneColor
+        0xC616u,
+        BYTE,
+        RAW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CFALayout
+        0xC617u,
+        SHORT,
+        RAW_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // LinearizationTable
+        0xC618u,
+        SHORT,
+        RAW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // BlackLevelRepeatDim
+        0xC619u,
+        SHORT,
+        RAW_IFD,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    { // BlackLevel
+        0xC61Au,
+        LONG,
+        RAW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // BlackLevelDeltaH
+        0xC61Bu,
+        SRATIONAL,
+        RAW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // BlackLevelDeltaV
+        0xC61Cu,
+        SRATIONAL,
+        RAW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // WhiteLevel
+        0xC61Du,
+        LONG,
+        RAW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // DefaultScale
+        0xC61Eu,
+        RATIONAL,
+        RAW_IFD,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    { // BestQualityScale
+        0xC65Cu,
+        RATIONAL,
+        RAW_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // DefaultCropOrigin
+        0xC61Fu,
+        LONG,
+        RAW_IFD,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    { // DefaultCropSize
+        0xC620u,
+        LONG,
+        RAW_IFD,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    { // CalibrationIlluminant1
+        0xC65Au,
+        SHORT,
+        PROFILE_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // CalibrationIlluminant2
+        0xC65Bu,
+        SHORT,
+        PROFILE_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ColorMatrix1
+        0xC621u,
+        SRATIONAL,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ColorMatrix2
+        0xC622u,
+        SRATIONAL,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CameraCalibration1
+        0xC623u,
+        SRATIONAL,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CameraCalibration2
+        0xC624u,
+        SRATIONAL,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ReductionMatrix1
+        0xC625u,
+        SRATIONAL,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ReductionMatrix2
+        0xC626u,
+        SRATIONAL,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // AnalogBalance
+        0xC627u,
+        RATIONAL,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // AsShotNeutral
+        0xC628u,
+        RATIONAL,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // AsShotWhiteXY
+        0xC629u,
+        RATIONAL,
+        IFD_0,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    { // BaselineExposure
+        0xC62Au,
+        SRATIONAL,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // BaselineNoise
+        0xC62Bu,
+        RATIONAL,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // BaselineSharpness
+        0xC62Cu,
+        RATIONAL,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // BayerGreenSplit
+        0xC62Du,
+        LONG,
+        RAW_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // LinearResponseLimit
+        0xC62Eu,
+        RATIONAL,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // CameraSerialNumber
+        0xC62Fu,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // LensInfo
+        0xC630u,
+        RATIONAL,
+        IFD_0,
+        4,
+        UNDEFINED_ENDIAN
+    },
+    { // ChromaBlurRadius
+        0xC631u,
+        RATIONAL,
+        RAW_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // AntiAliasStrength
+        0xC632u,
+        RATIONAL,
+        RAW_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ShadowScale
+        0xC633u,
+        RATIONAL,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // DNGPrivateData
+        0xC634u,
+        BYTE,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // MakerNoteSafety
+        0xC635u,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // RawDataUniqueID
+        0xC65Du,
+        BYTE,
+        IFD_0,
+        16,
+        UNDEFINED_ENDIAN
+    },
+    { // OriginalRawFileName
+        0xC68Bu,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // OriginalRawFileData
+        0xC68Cu,
+        UNDEFINED,
+        IFD_0,
+        0,
+        BIG
+    },
+    { // ActiveArea
+        0xC68Du,
+        LONG,
+        RAW_IFD,
+        4,
+        UNDEFINED_ENDIAN
+    },
+    { // MaskedAreas
+        0xC68Eu,
+        LONG,
+        RAW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // AsShotICCProfile
+        0xC68Fu,
+        UNDEFINED,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // AsShotPreProfileMatrix
+        0xC690u,
+        SRATIONAL,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CurrentICCProfile
+        0xC691u,
+        UNDEFINED,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CurrentICCProfile
+        0xC691u,
+        UNDEFINED,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // CurrentPreProfileMatrix
+        0xC692u,
+        SRATIONAL,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ColorimetricReference
+        0xC6BFu,
+        SHORT,
+        IFD_0,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // CameraCalibrationSignature
+        0xC6F3u,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileCalibrationSignature
+        0xC6F4u,
+        ASCII,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ExtraCameraProfiles
+        0xC6F5u,
+        LONG,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // AsShotProfileName
+        0xC6F6u,
+        ASCII,
+        IFD_0,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // NoiseReductionApplied
+        0xC6F7u,
+        RATIONAL,
+        RAW_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileName
+        0xC6F8u,
+        ASCII,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileHueSatMapDims
+        0xC6F9u,
+        LONG,
+        PROFILE_IFD,
+        3,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileHueSatMapData1
+        0xC6FAu,
+        FLOAT,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileHueSatMapData2
+        0xC6FBu,
+        FLOAT,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileToneCurve
+        0xC6FCu,
+        FLOAT,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileEmbedPolicy
+        0xC6FDu,
+        LONG,
+        PROFILE_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileCopyright
+        0xC6FEu,
+        ASCII,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ForwardMatrix1
+        0xC714u,
+        SRATIONAL,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // ForwardMatrix2
+        0xC715u,
+        SRATIONAL,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // PreviewApplicationName
+        0xC716u,
+        ASCII,
+        PREVIEW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // PreviewApplicationVersion
+        0xC717u,
+        ASCII,
+        PREVIEW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // PreviewSettingsName
+        0xC718u,
+        ASCII,
+        PREVIEW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // PreviewSettingsDigest
+        0xC719u,
+        BYTE,
+        PREVIEW_IFD,
+        16,
+        UNDEFINED_ENDIAN
+    },
+    { // PreviewColorSpace
+        0xC71Au,
+        LONG,
+        PREVIEW_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // PreviewDateTime
+        0xC71Bu,
+        ASCII,
+        PREVIEW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // RawImageDigest
+        0xC71Cu,
+        BYTE,
+        IFD_0,
+        16,
+        UNDEFINED_ENDIAN
+    },
+    { // OriginalRawFileDigest
+        0xC71Du,
+        BYTE,
+        IFD_0,
+        16,
+        UNDEFINED_ENDIAN
+    },
+    { // SubTileBlockSize
+        0xC71Eu,
+        LONG,
+        RAW_IFD,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    { // RowInterleaveFactor
+        0xC71Fu,
+        LONG,
+        RAW_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileLookTableDims
+        0xC725u,
+        LONG,
+        PROFILE_IFD,
+        3,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileLookTableData
+        0xC726u,
+        FLOAT,
+        PROFILE_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // OpcodeList1
+        0xC740u,
+        UNDEFINED,
+        RAW_IFD,
+        0,
+        BIG
+    },
+    { // OpcodeList2
+        0xC741u,
+        UNDEFINED,
+        RAW_IFD,
+        0,
+        BIG
+    },
+    { // OpcodeList3
+        0xC74Eu,
+        UNDEFINED,
+        RAW_IFD,
+        0,
+        BIG
+    },
+    { // NoiseProfile
+        0xC761u,
+        DOUBLE,
+        RAW_IFD,
+        0,
+        UNDEFINED_ENDIAN
+    },
+    { // DefaultUserCrop
+        0xC7B5u,
+        RATIONAL,
+        RAW_IFD,
+        4,
+        UNDEFINED_ENDIAN
+    },
+    { // DefaultBlackRender
+        0xC7A6u,
+        LONG,
+        PROFILE_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // BaselineExposureOffset
+        0xC7A5u,
+        RATIONAL,
+        PROFILE_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileLookTableEncoding
+        0xC7A4u,
+        LONG,
+        PROFILE_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // ProfileHueSatMapEncoding
+        0xC7A3u,
+        LONG,
+        PROFILE_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+    { // OriginalDefaultFinalSize
+        0xC791u,
+        LONG,
+        IFD_0,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    { // OriginalBestQualityFinalSize
+        0xC792u,
+        LONG,
+        IFD_0,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    { // OriginalDefaultCropSize
+        0xC793u,
+        LONG,
+        IFD_0,
+        2,
+        UNDEFINED_ENDIAN
+    },
+    { // NewRawImageDigest
+        0xC7A7u,
+        BYTE,
+        IFD_0,
+        16,
+        UNDEFINED_ENDIAN
+    },
+    { // RawToPreviewGain
+        0xC7A8u,
+        DOUBLE,
+        PREVIEW_IFD,
+        1,
+        UNDEFINED_ENDIAN
+    },
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_TIFF_TAG_DEFINITION_H*/
diff --git a/media/img_utils/include/img_utils/TiffEntry.h b/media/img_utils/include/img_utils/TiffEntry.h
new file mode 100644
index 0000000..cd01640
--- /dev/null
+++ b/media/img_utils/include/img_utils/TiffEntry.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMG_UTILS_TIFF_ENTRY
+#define IMG_UTILS_TIFF_ENTRY
+
+#include <img_utils/TiffWritable.h>
+#include <img_utils/TiffHelpers.h>
+#include <img_utils/EndianUtils.h>
+
+#include <cutils/compiler.h>
+#include <utils/String8.h>
+#include <utils/Errors.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+#define COMPARE_DEF(op) \
+inline bool operator op (const TiffEntry& entry) const;
+
+/**
+ * This class holds a single TIFF IFD entry.
+ */
+class ANDROID_API TiffEntry : public TiffWritable {
+    public:
+        // TODO: Copy constructor/equals here.
+        virtual ~TiffEntry();
+
+        /**
+         * Write the 12-byte IFD entry to the output. The given offset will be
+         * set as the tag value if the size of the tag value exceeds the max
+         * size for the TIFF Value field (4 bytes), and should be word aligned.
+         *
+         * Returns OK on success, or a negative error code on failure.
+         */
+        virtual status_t writeTagInfo(uint32_t offset, /*out*/EndianOutput* out) const = 0;
+
+        /**
+         * Get the count set for this entry. This corresponds to the TIFF Count
+         * field.
+         */
+        virtual uint32_t getCount() const = 0;
+
+        /**
+         * Get the tag id set for this entry. This corresponds to the TIFF Tag
+         * field.
+         */
+        virtual uint16_t getTag() const = 0;
+
+        /**
+         * Get the type set for this entry.  This corresponds to the TIFF Type
+         * field.
+         */
+        virtual TagType getType() const = 0;
+
+        /**
+         * Get the defined endianness for this entry.  If this is defined,
+         * the tag value will be written with the given byte order.
+         */
+        virtual Endianness getEndianness() const = 0;
+
+        /**
+         * Get the value for this entry.  This corresponds to the TIFF Value
+         * field.
+         *
+         * Returns NULL if the value is NULL, or if the type used does not
+         * match the type of this tag.
+         */
+        template<typename T>
+        const T* getData() const;
+
+        String8 toString() const;
+
+        /**
+         * Force the type used here to be a valid TIFF type.
+         *
+         * Returns NULL if the given value is NULL, or if the type given does
+         * not match the type of the value given.
+         */
+        template<typename T>
+        static const T* forceValidType(TagType type, const T* value);
+
+        virtual const void* getDataHelper() const = 0;
+
+        COMPARE_DEF(>)
+        COMPARE_DEF(<)
+
+        protected:
+            enum {
+                MAX_PRINT_STRING_LENGTH = 256
+            };
+};
+
+#define COMPARE(op) \
+bool TiffEntry::operator op (const TiffEntry& entry) const { \
+    return getComparableValue() op entry.getComparableValue(); \
+}
+
+COMPARE(>)
+COMPARE(<)
+
+
+template<typename T>
+const T* TiffEntry::getData() const {
+    const T* value = reinterpret_cast<const T*>(getDataHelper());
+    return forceValidType<T>(getType(), value);
+}
+
+#undef COMPARE
+#undef COMPARE_DEF
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_TIFF_ENTRY*/
diff --git a/media/img_utils/include/img_utils/TiffEntryImpl.h b/media/img_utils/include/img_utils/TiffEntryImpl.h
new file mode 100644
index 0000000..cbe0e9a
--- /dev/null
+++ b/media/img_utils/include/img_utils/TiffEntryImpl.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMG_UTILS_TIFF_ENTRY_IMPL
+#define IMG_UTILS_TIFF_ENTRY_IMPL
+
+#include <img_utils/TiffEntry.h>
+#include <img_utils/TiffHelpers.h>
+#include <img_utils/Output.h>
+#include <img_utils/EndianUtils.h>
+
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+template<typename T>
+class TiffEntryImpl : public TiffEntry {
+    public:
+        // TODO: Copy constructor/equals here.
+        TiffEntryImpl(uint16_t tag, TagType type, uint32_t count, Endianness end, const T* data);
+        virtual ~TiffEntryImpl();
+
+        status_t writeData(uint32_t offset, /*out*/EndianOutput* out) const;
+        status_t writeTagInfo(uint32_t offset, /*out*/EndianOutput* out) const;
+
+        uint32_t getCount() const;
+        uint16_t getTag() const;
+        TagType getType() const;
+        Endianness getEndianness() const;
+        size_t getSize() const;
+        uint32_t getComparableValue() const;
+
+    protected:
+        const void* getDataHelper() const;
+        uint32_t getActualSize() const;
+
+        uint16_t mTag;
+        uint16_t mType;
+        uint32_t mCount;
+        Endianness mEnd;
+        T* mData;
+
+};
+
+template<typename T>
+TiffEntryImpl<T>::TiffEntryImpl(uint16_t tag, TagType type, uint32_t count, Endianness end,
+        const T* data)
+        : mTag(tag), mType(static_cast<uint16_t>(type)), mCount(count), mEnd(end) {
+    count = (type == RATIONAL || type == SRATIONAL) ? count * 2 : count;
+    mData = new T[count]();
+    for (uint32_t i = 0; i < count; ++i) {
+        mData[i] = data[i];
+    }
+}
+
+template<typename T>
+TiffEntryImpl<T>::~TiffEntryImpl() {
+    if (mData) {
+        delete[] mData;
+    }
+}
+
+template<typename T>
+uint32_t TiffEntryImpl<T>::getCount() const {
+    return mCount;
+}
+
+template<typename T>
+uint16_t TiffEntryImpl<T>::getTag() const {
+    return mTag;
+}
+
+template<typename T>
+TagType TiffEntryImpl<T>::getType() const {
+    return static_cast<TagType>(mType);
+}
+
+template<typename T>
+const void* TiffEntryImpl<T>::getDataHelper() const {
+    return reinterpret_cast<const void*>(mData);
+}
+
+template<typename T>
+size_t TiffEntryImpl<T>::getSize() const {
+    uint32_t total = getActualSize();
+    WORD_ALIGN(total)
+    return (total <= OFFSET_SIZE) ? 0 : total;
+}
+
+template<typename T>
+uint32_t TiffEntryImpl<T>::getActualSize() const {
+    uint32_t total = sizeof(T) * mCount;
+    if (getType() == RATIONAL || getType() == SRATIONAL) {
+        // 2 ints stored for each rational, multiply by 2
+        total <<= 1;
+    }
+    return total;
+}
+
+template<typename T>
+Endianness TiffEntryImpl<T>::getEndianness() const {
+    return mEnd;
+}
+
+template<typename T>
+uint32_t TiffEntryImpl<T>::getComparableValue() const {
+    return mTag;
+}
+
+template<typename T>
+status_t TiffEntryImpl<T>::writeTagInfo(uint32_t offset, /*out*/EndianOutput* out) const {
+    assert((offset % TIFF_WORD_SIZE) == 0);
+    status_t ret = OK;
+    BAIL_ON_FAIL(out->write(&mTag, 0, 1), ret);
+    BAIL_ON_FAIL(out->write(&mType, 0, 1), ret);
+    BAIL_ON_FAIL(out->write(&mCount, 0, 1), ret);
+
+    uint32_t dataSize = getActualSize();
+    if (dataSize > OFFSET_SIZE) {
+        BAIL_ON_FAIL(out->write(&offset, 0, 1), ret);
+    } else {
+        uint32_t count = mCount;
+        if (getType() == RATIONAL || getType() == SRATIONAL) {
+            /**
+             * Rationals are stored as an array of ints.  Each
+             * rational is represented by 2 ints.  To recover the
+             * size of the array here, multiply the count by 2.
+             */
+            count <<= 1;
+        }
+        BAIL_ON_FAIL(out->write(mData, 0, count), ret);
+        ZERO_TILL_WORD(out, dataSize, ret);
+    }
+    return ret;
+}
+
+template<typename T>
+status_t TiffEntryImpl<T>::writeData(uint32_t offset, EndianOutput* out) const {
+    status_t ret = OK;
+
+    // Some tags have fixed-endian value output
+    Endianness tmp = UNDEFINED_ENDIAN;
+    if (mEnd != UNDEFINED_ENDIAN) {
+        tmp = out->getEndianness();
+        out->setEndianness(mEnd);
+    }
+
+    uint32_t count = mCount;
+    if (getType() == RATIONAL || getType() == SRATIONAL) {
+        /**
+         * Rationals are stored as an array of ints.  Each
+         * rational is represented by 2 ints.  To recover the
+         * size of the array here, multiply the count by 2.
+         */
+        count <<= 1;
+    }
+
+    BAIL_ON_FAIL(out->write(mData, 0, count), ret);
+
+    if (mEnd != UNDEFINED_ENDIAN) {
+        out->setEndianness(tmp);
+    }
+
+    // Write to next word alignment
+    ZERO_TILL_WORD(out, sizeof(T) * count, ret);
+    return ret;
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_TIFF_ENTRY_IMPL*/
+
+
diff --git a/media/img_utils/include/img_utils/TiffHelpers.h b/media/img_utils/include/img_utils/TiffHelpers.h
new file mode 100644
index 0000000..fd0ea7a
--- /dev/null
+++ b/media/img_utils/include/img_utils/TiffHelpers.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMG_UTILS_TIFF_HELPERS_H
+#define IMG_UTILS_TIFF_HELPERS_H
+
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+const uint8_t ZERO_WORD[] = {0, 0, 0, 0};
+
+#define BAIL_ON_FAIL(x, flag) \
+    if ((flag = (x)) != OK) return flag;
+
+#define BYTES_TILL_WORD(index) \
+    ((TIFF_WORD_SIZE - ((index) % TIFF_WORD_SIZE)) % TIFF_WORD_SIZE)
+
+#define WORD_ALIGN(count) \
+    count += BYTES_TILL_WORD(count);
+
+#define ZERO_TILL_WORD(output, index, ret) \
+    { \
+        size_t remaining = BYTES_TILL_WORD(index); \
+        if (remaining > 0) { \
+            BAIL_ON_FAIL(output->write(ZERO_WORD, 0, remaining), ret); \
+        } \
+    }
+
+/**
+ * Basic TIFF header constants.
+ */
+enum {
+    BAD_OFFSET = 0,
+    TIFF_WORD_SIZE = 4, // Size in bytes
+    IFD_HEADER_SIZE = 2, // Size in bytes
+    IFD_FOOTER_SIZE = 4, // Size in bytes
+    TIFF_ENTRY_SIZE = 12, // Size in bytes
+    MAX_IFD_ENTRIES = UINT16_MAX,
+    FILE_HEADER_SIZE = 8, // Size in bytes
+    ENDIAN_MARKER_SIZE = 2, // Size in bytes
+    TIFF_MARKER_SIZE = 2, // Size in bytes
+    OFFSET_MARKER_SIZE = 4, // Size in bytes
+    TIFF_FILE_MARKER = 42,
+    BIG_ENDIAN_MARKER = 0x4D4Du,
+    LITTLE_ENDIAN_MARKER = 0x4949u
+};
+
+/**
+ * Constants for the TIFF tag types.
+ */
+enum TagType {
+    UNKNOWN_TAGTYPE = 0,
+    BYTE=1,
+    ASCII,
+    SHORT,
+    LONG,
+    RATIONAL,
+    SBYTE,
+    UNDEFINED,
+    SSHORT,
+    SLONG,
+    SRATIONAL,
+    FLOAT,
+    DOUBLE
+};
+
+/**
+ * Sizes of the TIFF entry fields (in bytes).
+ */
+enum {
+    TAG_SIZE = 2,
+    TYPE_SIZE = 2,
+    COUNT_SIZE = 4,
+    OFFSET_SIZE = 4
+};
+
+/**
+ * Convenience IFD id constants.
+ */
+enum {
+    IFD_0 = 0,
+    RAW_IFD,
+    PROFILE_IFD,
+    PREVIEW_IFD
+};
+
+inline size_t getTypeSize(TagType type) {
+    switch(type) {
+        case UNDEFINED:
+        case ASCII:
+        case BYTE:
+        case SBYTE:
+            return 1;
+        case SHORT:
+        case SSHORT:
+            return 2;
+        case LONG:
+        case SLONG:
+        case FLOAT:
+            return 4;
+        case RATIONAL:
+        case SRATIONAL:
+        case DOUBLE:
+            return 8;
+        default:
+            return 0;
+    }
+}
+
+inline uint32_t calculateIfdSize(size_t numberOfEntries) {
+    return IFD_HEADER_SIZE + IFD_FOOTER_SIZE + TIFF_ENTRY_SIZE * numberOfEntries;
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_TIFF_HELPERS_H*/
diff --git a/media/img_utils/include/img_utils/TiffIfd.h b/media/img_utils/include/img_utils/TiffIfd.h
new file mode 100644
index 0000000..9400456
--- /dev/null
+++ b/media/img_utils/include/img_utils/TiffIfd.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMG_UTILS_TIFF_IFD_H
+#define IMG_UTILS_TIFF_IFD_H
+
+#include <img_utils/TiffWritable.h>
+#include <img_utils/TiffEntry.h>
+#include <img_utils/Output.h>
+#include <img_utils/SortedEntryVector.h>
+
+#include <cutils/compiler.h>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/SortedVector.h>
+#include <utils/StrongPointer.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * This class holds a single TIFF Image File Directory (IFD) structure.
+ *
+ * This maps to the TIFF IFD structure that is logically composed of:
+ * - A 2-byte field listing the number of entries.
+ * - A list of 12-byte TIFF entries.
+ * - A 4-byte offset to the next IFD.
+ */
+class ANDROID_API TiffIfd : public TiffWritable {
+    public:
+        // TODO: Copy constructor/equals here - needed for SubIfds.
+        TiffIfd(uint32_t ifdId);
+        virtual ~TiffIfd();
+
+        /**
+         * Add a TiffEntry to this IFD or replace an existing entry with the
+         * same tag ID.  No validation is done.
+         *
+         * Returns OK on success, or a negative error code on failure.
+         */
+        virtual status_t addEntry(const sp<TiffEntry>& entry);
+
+        /**
+         * Set the pointer to the next IFD.  This is used to create a linked
+         * list of IFDs as defined by the TIFF 6.0 spec., and is not included
+         * when calculating the size of IFD and entries for the getSize()
+         * method (unlike SubIFDs).
+         */
+        virtual void setNextIfd(const sp<TiffIfd>& ifd);
+
+        /**
+         * Get the pointer to the next IFD, or NULL if none exists.
+         */
+        virtual sp<TiffIfd> getNextIfd() const;
+
+        /**
+         * Write the IFD data.  This includes the IFD header, entries, footer,
+         * and the corresponding values for each entry (recursively including
+         * sub-IFDs).  The written amount should end on a word boundary, and
+         * the given offset should be word aligned.
+         *
+         * Returns OK on success, or a negative error code on failure.
+         */
+        virtual status_t writeData(uint32_t offset, /*out*/EndianOutput* out) const;
+
+        /**
+         * Get the size of the IFD. This includes the IFD header, entries, footer,
+         * and the corresponding values for each entry (recursively including
+         * any sub-IFDs).
+         */
+        virtual size_t getSize() const;
+
+        /**
+         * Get the id of this IFD.
+         */
+        virtual uint32_t getId() const;
+
+        /**
+         * Get an entry with the given tag ID.
+         *
+         * Returns a strong pointer to the entry if it exists, or an empty strong
+         * pointer.
+         */
+        virtual sp<TiffEntry> getEntry(uint16_t tag) const;
+
+        /**
+         * Get a formatted string representing this IFD.
+         */
+        String8 toString() const;
+
+        /**
+         * Print a formatted string representing this IFD to logcat.
+         */
+        void log() const;
+
+        /**
+         * Get value used to determine sort order.
+         */
+        virtual uint32_t getComparableValue() const;
+    protected:
+        virtual uint32_t checkAndGetOffset(uint32_t offset) const;
+        SortedEntryVector mEntries;
+        sp<TiffIfd> mNextIfd;
+        uint32_t mIfdId;
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_TIFF_IFD_H*/
diff --git a/media/img_utils/include/img_utils/TiffWritable.h b/media/img_utils/include/img_utils/TiffWritable.h
new file mode 100644
index 0000000..a72cecc
--- /dev/null
+++ b/media/img_utils/include/img_utils/TiffWritable.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMG_UTILS_TIFF_WRITABLE
+#define IMG_UTILS_TIFF_WRITABLE
+
+#include <img_utils/Orderable.h>
+#include <img_utils/EndianUtils.h>
+#include <img_utils/Output.h>
+
+#include <cutils/compiler.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+/**
+ * TiffWritable subclasses represent TIFF metadata objects that can be written
+ * to an EndianOutput object.  This is used for TIFF entries and IFDs.
+ */
+class ANDROID_API TiffWritable : public Orderable, public LightRefBase<TiffWritable> {
+    public:
+        TiffWritable();
+        virtual ~TiffWritable();
+
+        /**
+         * Write the data to the output. The given offset is used to calculate
+         * the header offset for values written.  The offset is defined
+         * relative to the beginning of the TIFF header, and is word aligned.
+         *
+         * Returns OK on success, or a negative error code on failure.
+         */
+        virtual status_t writeData(uint32_t offset, /*out*/EndianOutput* out) const = 0;
+
+        /**
+         * Get the size of the data to write.
+         */
+        virtual size_t getSize() const = 0;
+
+};
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+#endif /*IMG_UTILS_TIFF_WRITABLE*/
diff --git a/media/img_utils/include/img_utils/TiffWriter.h b/media/img_utils/include/img_utils/TiffWriter.h
new file mode 100644
index 0000000..ec27fc3
--- /dev/null
+++ b/media/img_utils/include/img_utils/TiffWriter.h
@@ -0,0 +1,267 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMG_UTILS_TIFF_WRITER_H
+#define IMG_UTILS_TIFF_WRITER_H
+
+#include <img_utils/EndianUtils.h>
+#include <img_utils/TiffEntryImpl.h>
+#include <img_utils/TagDefinitions.h>
+
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/KeyedVector.h>
+#include <utils/Vector.h>
+
+#include <cutils/compiler.h>
+#include <stdint.h>
+
+namespace android {
+namespace img_utils {
+
+class TiffEntry;
+class TiffIfd;
+class Output;
+
+/**
+ * This class holds a collection of TIFF IFDs that can be written as a
+ * complete DNG file header.
+ *
+ * This maps to the TIFF header structure that is logically composed of:
+ * - An 8-byte file header containing an endianness indicator, the TIFF
+ *   file marker, and the offset to the first IFD.
+ * - A list of TIFF IFD structures.
+ */
+class ANDROID_API TiffWriter : public LightRefBase<TiffWriter> {
+    public:
+
+        /**
+         * Constructs a TiffWriter with the default tag mappings. This enables
+         * all of the tags defined in TagDefinitions.h, and uses the following
+         * mapping precedence to resolve collisions:
+         * (highest precedence) TIFF/EP > DNG > EXIF 2.3 > TIFF 6.0
+         */
+        TiffWriter();
+
+        /**
+         * Constructs a TiffWriter with the given tag mappings.  The mapping
+         * precedence will be in the order that the definition maps are given,
+         * where the lower index map gets precedence.
+         *
+         * This can be used with user-defined definitions, or definitions form
+         * TagDefinitions.h
+         *
+         * The enabledDefinitions mapping object is owned by the caller, and must
+         * stay alive for the lifespan of the constructed TiffWriter object.
+         */
+        TiffWriter(KeyedVector<uint16_t, const TagDefinition_t*>* enabledDefinitions,
+                size_t length);
+
+        virtual ~TiffWriter();
+
+        /**
+         * Write a TIFF header containing each IFD set.  This will recursively
+         * write all SubIFDs and tags.
+         *
+         * Returns OK on success, or a negative error code on failure.
+         */
+        virtual status_t write(Output* out, Endianness end = LITTLE);
+
+        /**
+         * Get the total size in bytes of the TIFF header.  This includes all
+         * IFDs, tags, and values set for this TiffWriter.
+         */
+        virtual uint32_t getTotalSize() const;
+
+        /**
+         * Add the given entry to its default IFD.  If that IFD does not
+         * exist, it will be created.
+         */
+        virtual status_t addEntry(const sp<TiffEntry>& entry);
+
+        /**
+         * Build an entry for a known tag.  This tag must be one of the tags
+         * defined in one of the definition vectors this TIFF writer was constructed
+         * with. The count and type are validated. If this succeeds, the resulting
+         * entry will be placed in the outEntry pointer.
+         *
+         * Returns OK on success, or a negative error code on failure. Valid
+         * error codes for this method are:
+         * - BAD_INDEX - The given tag doesn't exist.
+         * - BAD_VALUE - The given count doesn't match the required count for
+         *               this tag.
+         * - BAD_TYPE  - The type of the given data isn't compatible with the
+         *               type required for this tag.
+         */
+        template<typename T>
+        status_t buildEntry(uint16_t tag, uint32_t count, const T* data,
+                  /*out*/sp<TiffEntry>* outEntry) const;
+
+         /**
+         * Build an entry for a known tag and add it to the IFD with the given ID.
+         * This tag must be defined in one of the definition vectors this TIFF writer
+         * was constructed with. The count and type are validated. If this succeeds,
+         * the resulting entry will be placed in the outEntry pointer.
+         *
+         * Returns OK on success, or a negative error code on failure. Valid
+         * error codes for this method are:
+         * - BAD_INDEX - The given tag doesn't exist.
+         * - BAD_VALUE - The given count doesn't match the required count for
+         *               this tag.
+         * - BAD_TYPE  - The type of the given data isn't compatible with the
+         *               type required for this tag.
+         * - NAME_NOT_FOUND - No ifd exists with the given ID.
+         */
+        template<typename T>
+        status_t addEntry(uint16_t tag, uint32_t count, const T* data, uint32_t ifd);
+
+        /**
+         * Return the TIFF entry with the given tag ID in the IFD with the given ID,
+         * or an empty pointer if none exists.
+         */
+        virtual sp<TiffEntry> getEntry(uint16_t tag, uint32_t ifd) const;
+
+        /**
+         * Add the given IFD to the end of the top-level IFD chain. No
+         * validation is done.
+         *
+         * Returns OK on success, or a negative error code on failure.
+         */
+        virtual status_t uncheckedAddIfd(const sp<TiffIfd>& ifd);
+
+        /**
+         * Create an empty IFD with the given ID and add it to the end of the
+         * list of IFDs.
+         */
+        virtual status_t addIfd(uint32_t ifd);
+
+        /**
+         * Build an entry.  No validation is done.
+         *
+         * WARNING: Using this method can result in creating poorly formatted
+         * TIFF files.
+         *
+         * Returns a TiffEntry with the given tag, type, count, endianness,
+         * and data.
+         */
+        template<typename T>
+        static sp<TiffEntry> uncheckedBuildEntry(uint16_t tag, TagType type,
+                  uint32_t count, Endianness end, const T* data);
+
+        /**
+         * Utility function to build atag-to-definition mapping from a given
+         * array of tag definitions.
+         */
+        static KeyedVector<uint16_t, const TagDefinition_t*> buildTagMap(
+                  const TagDefinition_t* definitions, size_t length);
+
+        /**
+         * Returns the default type for the given tag ID.
+         */
+        virtual TagType getDefaultType(uint16_t tag) const;
+
+        /**
+         * Returns the default count for a given tag ID, or 0 if this
+         * tag normally has a variable count.
+         */
+        virtual uint32_t getDefaultCount(uint16_t tag) const;
+
+        /**
+         * Returns true if a definition exist for the given tag ID.
+         */
+        virtual bool checkIfDefined(uint16_t tag) const;
+
+        /**
+         * Print the currently configured IFDs and entries to logcat.
+         */
+        virtual void log() const;
+
+    protected:
+        enum {
+            DEFAULT_NUM_TAG_MAPS = 4,
+        };
+
+        sp<TiffIfd> findLastIfd();
+        status_t writeFileHeader(EndianOutput& out);
+        const TagDefinition_t* lookupDefinition(uint16_t tag) const;
+        status_t calculateOffsets();
+
+        sp<TiffIfd> mIfd;
+        KeyedVector<uint32_t, sp<TiffIfd> > mNamedIfds;
+        KeyedVector<uint16_t, const TagDefinition_t*>* mTagMaps;
+        size_t mNumTagMaps;
+
+        static KeyedVector<uint16_t, const TagDefinition_t*> sTagMaps[];
+};
+
+template<typename T>
+status_t TiffWriter::buildEntry(uint16_t tag, uint32_t count, const T* data,
+                  /*out*/sp<TiffEntry>* outEntry) const {
+    const TagDefinition_t* definition = lookupDefinition(tag);
+
+    if (definition == NULL) {
+        ALOGE("%s: No such tag exists for id %x.", __FUNCTION__, tag);
+        return BAD_INDEX;
+    }
+
+    uint32_t fixedCount = definition->fixedCount;
+    if (fixedCount > 0 && fixedCount != count) {
+        ALOGE("%s: Invalid count %d for tag %x (expects %d).", __FUNCTION__, count, tag,
+                fixedCount);
+        return BAD_VALUE;
+    }
+
+    TagType fixedType = definition->defaultType;
+    if (TiffEntry::forceValidType(fixedType, data) == NULL) {
+        ALOGE("%s: Invalid type used for tag value for tag %x.", __FUNCTION__, tag);
+        return BAD_TYPE;
+    }
+
+    *outEntry = new TiffEntryImpl<T>(tag, fixedType, count,
+        definition->fixedEndian, data);
+
+    return OK;
+}
+
+template<typename T>
+status_t TiffWriter::addEntry(uint16_t tag, uint32_t count, const T* data, uint32_t ifd) {
+    sp<TiffEntry> outEntry;
+    status_t ret = buildEntry<T>(tag, count, data, &outEntry);
+    if (ret != OK) {
+        ALOGE("%s: Could not build entry for tag %x.", __FUNCTION__, tag);
+        return ret;
+    }
+    ssize_t index = mNamedIfds.indexOfKey(ifd);
+    if (index < 0) {
+        ALOGE("%s: No IFD %d set for this writer.", __FUNCTION__, ifd);
+        return NAME_NOT_FOUND;
+    }
+    return mNamedIfds[index]->addEntry(outEntry);
+}
+
+template<typename T>
+sp<TiffEntry> TiffWriter::uncheckedBuildEntry(uint16_t tag, TagType type, uint32_t count,
+        Endianness end, const T* data) {
+    TiffEntryImpl<T>* entry = new TiffEntryImpl<T>(tag, type, count, end, data);
+    return sp<TiffEntry>(entry);
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
+
+#endif /*IMG_UTILS_TIFF_WRITER_H*/
diff --git a/media/img_utils/src/Android.mk b/media/img_utils/src/Android.mk
new file mode 100644
index 0000000..80893be
--- /dev/null
+++ b/media/img_utils/src/Android.mk
@@ -0,0 +1,61 @@
+# Copyright 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+  EndianUtils.cpp \
+  FileInput.cpp \
+  FileOutput.cpp \
+  SortedEntryVector.cpp \
+  Input.cpp \
+  Output.cpp \
+  Orderable.cpp \
+  TiffIfd.cpp \
+  TiffWritable.cpp \
+  TiffWriter.cpp \
+  TiffEntry.cpp \
+  TiffEntryImpl.cpp \
+  ByteArrayOutput.cpp \
+  DngUtils.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+  libexpat \
+  libutils \
+  libcutils \
+  libcamera_metadata \
+  libcamera_client
+
+LOCAL_C_INCLUDES += \
+  $(LOCAL_PATH)/../include \
+  system/media/camera/include
+
+LOCAL_CFLAGS += \
+  -Wall \
+  -Wextra \
+  -Werror \
+  -fvisibility=hidden
+
+ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),)
+    # Enable assert() in eng builds
+    LOCAL_CFLAGS += -UNDEBUG -DLOG_NDEBUG=1
+endif
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../include
+
+LOCAL_MODULE := libimg_utils
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/img_utils/src/ByteArrayOutput.cpp b/media/img_utils/src/ByteArrayOutput.cpp
new file mode 100644
index 0000000..db2d248
--- /dev/null
+++ b/media/img_utils/src/ByteArrayOutput.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <img_utils/ByteArrayOutput.h>
+
+#include <utils/Log.h>
+
+namespace android {
+namespace img_utils {
+
+ByteArrayOutput::ByteArrayOutput() {}
+
+ByteArrayOutput::~ByteArrayOutput() {}
+
+status_t ByteArrayOutput::open() {
+    return OK;
+}
+
+status_t ByteArrayOutput::write(const uint8_t* buf, size_t offset, size_t count) {
+    if (mByteArray.appendArray(buf + offset, count) < 0) {
+        ALOGE("%s: Failed to write to ByteArrayOutput.", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    return OK;
+}
+
+status_t ByteArrayOutput::close() {
+    mByteArray.clear();
+    return OK;
+}
+
+size_t ByteArrayOutput::getSize() const {
+    return mByteArray.size();
+}
+
+const uint8_t* ByteArrayOutput::getArray() const {
+    return mByteArray.array();
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/DngUtils.cpp b/media/img_utils/src/DngUtils.cpp
new file mode 100644
index 0000000..788dfc8
--- /dev/null
+++ b/media/img_utils/src/DngUtils.cpp
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <img_utils/DngUtils.h>
+
+namespace android {
+namespace img_utils {
+
+OpcodeListBuilder::OpcodeListBuilder() : mOpList(), mEndianOut(&mOpList, BIG) {
+    if(mEndianOut.open() != OK) {
+        ALOGE("%s: Open failed.", __FUNCTION__);
+    }
+}
+
+OpcodeListBuilder::~OpcodeListBuilder() {
+    if(mEndianOut.close() != OK) {
+        ALOGE("%s: Close failed.", __FUNCTION__);
+    }
+}
+
+size_t OpcodeListBuilder::getSize() const {
+    return mOpList.getSize() + sizeof(mCount);
+}
+
+uint32_t OpcodeListBuilder::getCount() const {
+    return mCount;
+}
+
+status_t OpcodeListBuilder::buildOpList(uint8_t* buf) const {
+    uint32_t count = convertToBigEndian(mCount);
+    memcpy(buf, &count, sizeof(count));
+    memcpy(buf + sizeof(count), mOpList.getArray(), mOpList.getSize());
+    return OK;
+}
+
+status_t OpcodeListBuilder::addGainMapsForMetadata(uint32_t lsmWidth,
+                                                   uint32_t lsmHeight,
+                                                   uint32_t activeAreaTop,
+                                                   uint32_t activeAreaLeft,
+                                                   uint32_t activeAreaBottom,
+                                                   uint32_t activeAreaRight,
+                                                   CfaLayout cfa,
+                                                   const float* lensShadingMap) {
+    uint32_t activeAreaWidth = activeAreaRight - activeAreaLeft;
+    uint32_t activeAreaHeight = activeAreaBottom - activeAreaTop;
+    double spacingV = 1.0 / lsmHeight;
+    double spacingH = 1.0 / lsmWidth;
+
+    float redMap[lsmWidth * lsmHeight];
+    float greenEvenMap[lsmWidth * lsmHeight];
+    float greenOddMap[lsmWidth * lsmHeight];
+    float blueMap[lsmWidth * lsmHeight];
+
+    size_t lsmMapSize = lsmWidth * lsmHeight * 4;
+
+    // Split lens shading map channels into separate arrays
+    size_t j = 0;
+    for (size_t i = 0; i < lsmMapSize; i += 4, ++j) {
+        redMap[j] = lensShadingMap[i + LSM_R_IND];
+        greenEvenMap[j] = lensShadingMap[i + LSM_GE_IND];
+        greenOddMap[j] = lensShadingMap[i + LSM_GO_IND];
+        blueMap[j] = lensShadingMap[i + LSM_B_IND];
+    }
+
+    uint32_t redTop = 0;
+    uint32_t redLeft = 0;
+    uint32_t greenEvenTop = 0;
+    uint32_t greenEvenLeft = 1;
+    uint32_t greenOddTop = 1;
+    uint32_t greenOddLeft = 0;
+    uint32_t blueTop = 1;
+    uint32_t blueLeft = 1;
+
+    switch(cfa) {
+        case CFA_RGGB:
+            redTop = 0;
+            redLeft = 0;
+            greenEvenTop = 0;
+            greenEvenLeft = 1;
+            greenOddTop = 1;
+            greenOddLeft = 0;
+            blueTop = 1;
+            blueLeft = 1;
+            break;
+        case CFA_GRBG:
+            redTop = 0;
+            redLeft = 1;
+            greenEvenTop = 0;
+            greenEvenLeft = 0;
+            greenOddTop = 1;
+            greenOddLeft = 1;
+            blueTop = 1;
+            blueLeft = 0;
+            break;
+        case CFA_GBRG:
+            redTop = 1;
+            redLeft = 0;
+            greenEvenTop = 0;
+            greenEvenLeft = 0;
+            greenOddTop = 1;
+            greenOddLeft = 1;
+            blueTop = 0;
+            blueLeft = 1;
+            break;
+        case CFA_BGGR:
+            redTop = 1;
+            redLeft = 1;
+            greenEvenTop = 0;
+            greenEvenLeft = 1;
+            greenOddTop = 1;
+            greenOddLeft = 0;
+            blueTop = 0;
+            blueLeft = 0;
+            break;
+        default:
+            ALOGE("%s: Unknown CFA layout %d", __FUNCTION__, cfa);
+            return BAD_VALUE;
+    }
+
+    status_t err = addGainMap(/*top*/redTop,
+                              /*left*/redLeft,
+                              /*bottom*/activeAreaHeight - 1,
+                              /*right*/activeAreaWidth - 1,
+                              /*plane*/0,
+                              /*planes*/1,
+                              /*rowPitch*/2,
+                              /*colPitch*/2,
+                              /*mapPointsV*/lsmHeight,
+                              /*mapPointsH*/lsmWidth,
+                              /*mapSpacingV*/spacingV,
+                              /*mapSpacingH*/spacingH,
+                              /*mapOriginV*/0,
+                              /*mapOriginH*/0,
+                              /*mapPlanes*/1,
+                              /*mapGains*/redMap);
+    if (err != OK) return err;
+
+    err = addGainMap(/*top*/greenEvenTop,
+                     /*left*/greenEvenLeft,
+                     /*bottom*/activeAreaHeight - 1,
+                     /*right*/activeAreaWidth - 1,
+                     /*plane*/0,
+                     /*planes*/1,
+                     /*rowPitch*/2,
+                     /*colPitch*/2,
+                     /*mapPointsV*/lsmHeight,
+                     /*mapPointsH*/lsmWidth,
+                     /*mapSpacingV*/spacingV,
+                     /*mapSpacingH*/spacingH,
+                     /*mapOriginV*/0,
+                     /*mapOriginH*/0,
+                     /*mapPlanes*/1,
+                     /*mapGains*/greenEvenMap);
+    if (err != OK) return err;
+
+    err = addGainMap(/*top*/greenOddTop,
+                     /*left*/greenOddLeft,
+                     /*bottom*/activeAreaHeight - 1,
+                     /*right*/activeAreaWidth - 1,
+                     /*plane*/0,
+                     /*planes*/1,
+                     /*rowPitch*/2,
+                     /*colPitch*/2,
+                     /*mapPointsV*/lsmHeight,
+                     /*mapPointsH*/lsmWidth,
+                     /*mapSpacingV*/spacingV,
+                     /*mapSpacingH*/spacingH,
+                     /*mapOriginV*/0,
+                     /*mapOriginH*/0,
+                     /*mapPlanes*/1,
+                     /*mapGains*/greenOddMap);
+    if (err != OK) return err;
+
+    err = addGainMap(/*top*/blueTop,
+                     /*left*/blueLeft,
+                     /*bottom*/activeAreaHeight - 1,
+                     /*right*/activeAreaWidth - 1,
+                     /*plane*/0,
+                     /*planes*/1,
+                     /*rowPitch*/2,
+                     /*colPitch*/2,
+                     /*mapPointsV*/lsmHeight,
+                     /*mapPointsH*/lsmWidth,
+                     /*mapSpacingV*/spacingV,
+                     /*mapSpacingH*/spacingH,
+                     /*mapOriginV*/0,
+                     /*mapOriginH*/0,
+                     /*mapPlanes*/1,
+                     /*mapGains*/blueMap);
+    return err;
+}
+
+status_t OpcodeListBuilder::addGainMap(uint32_t top,
+                                       uint32_t left,
+                                       uint32_t bottom,
+                                       uint32_t right,
+                                       uint32_t plane,
+                                       uint32_t planes,
+                                       uint32_t rowPitch,
+                                       uint32_t colPitch,
+                                       uint32_t mapPointsV,
+                                       uint32_t mapPointsH,
+                                       double mapSpacingV,
+                                       double mapSpacingH,
+                                       double mapOriginV,
+                                       double mapOriginH,
+                                       uint32_t mapPlanes,
+                                       const float* mapGains) {
+
+    uint32_t opcodeId = GAIN_MAP_ID;
+
+    status_t err = mEndianOut.write(&opcodeId, 0, 1);
+    if (err != OK) return err;
+
+    uint8_t version[] = {1, 3, 0, 0};
+    err = mEndianOut.write(version, 0, NELEMS(version));
+    if (err != OK) return err;
+
+    uint32_t flags = FLAG_OPTIONAL | FLAG_OPTIONAL_FOR_PREVIEW;
+    err = mEndianOut.write(&flags, 0, 1);
+    if (err != OK) return err;
+
+    const uint32_t NUMBER_INT_ARGS = 11;
+    const uint32_t NUMBER_DOUBLE_ARGS = 4;
+
+    uint32_t totalSize = NUMBER_INT_ARGS * sizeof(uint32_t) + NUMBER_DOUBLE_ARGS * sizeof(double) +
+            mapPointsV * mapPointsH * mapPlanes * sizeof(float);
+
+    err = mEndianOut.write(&totalSize, 0, 1);
+    if (err != OK) return err;
+
+    // Batch writes as much as possible
+    uint32_t settings1[] = { top,
+                            left,
+                            bottom,
+                            right,
+                            plane,
+                            planes,
+                            rowPitch,
+                            colPitch,
+                            mapPointsV,
+                            mapPointsH };
+
+    err = mEndianOut.write(settings1, 0, NELEMS(settings1));
+    if (err != OK) return err;
+
+    double settings2[] = { mapSpacingV,
+                          mapSpacingH,
+                          mapOriginV,
+                          mapOriginH };
+
+    err = mEndianOut.write(settings2, 0, NELEMS(settings2));
+    if (err != OK) return err;
+
+    err = mEndianOut.write(&mapPlanes, 0, 1);
+    if (err != OK) return err;
+
+    err = mEndianOut.write(mapGains, 0, mapPointsV * mapPointsH * mapPlanes);
+    if (err != OK) return err;
+
+    mCount++;
+
+    return OK;
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/EndianUtils.cpp b/media/img_utils/src/EndianUtils.cpp
new file mode 100644
index 0000000..8681cbe
--- /dev/null
+++ b/media/img_utils/src/EndianUtils.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <img_utils/EndianUtils.h>
+
+namespace android {
+namespace img_utils {
+
+EndianOutput::EndianOutput(Output* out, Endianness end)
+        : mOffset(0), mOutput(out), mEndian(end) {}
+
+EndianOutput::~EndianOutput() {}
+
+status_t EndianOutput::open() {
+    mOffset = 0;
+    return mOutput->open();
+}
+
+status_t EndianOutput::close() {
+    return mOutput->close();
+}
+
+void EndianOutput::setEndianness(Endianness end) {
+    mEndian = end;
+}
+
+uint32_t EndianOutput::getCurrentOffset() const {
+    return mOffset;
+}
+
+Endianness EndianOutput::getEndianness() const {
+    return mEndian;
+}
+
+status_t EndianOutput::write(const uint8_t* buf, size_t offset, size_t count) {
+    status_t res = OK;
+    if((res = mOutput->write(buf, offset, count)) == OK) {
+        mOffset += count;
+    }
+    return res;
+}
+
+status_t EndianOutput::write(const int8_t* buf, size_t offset, size_t count) {
+    return write(reinterpret_cast<const uint8_t*>(buf), offset, count);
+}
+
+#define DEFINE_WRITE(_type_) \
+status_t EndianOutput::write(const _type_* buf, size_t offset, size_t count) { \
+    return writeHelper<_type_>(buf, offset, count); \
+}
+
+DEFINE_WRITE(uint16_t)
+DEFINE_WRITE(int16_t)
+DEFINE_WRITE(uint32_t)
+DEFINE_WRITE(int32_t)
+DEFINE_WRITE(uint64_t)
+DEFINE_WRITE(int64_t)
+
+status_t EndianOutput::write(const float* buf, size_t offset, size_t count) {
+    assert(sizeof(float) == sizeof(uint32_t));
+    return writeHelper<uint32_t>(reinterpret_cast<const uint32_t*>(buf), offset, count);
+}
+
+status_t EndianOutput::write(const double* buf, size_t offset, size_t count) {
+    assert(sizeof(double) == sizeof(uint64_t));
+    return writeHelper<uint64_t>(reinterpret_cast<const uint64_t*>(buf), offset, count);
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/FileInput.cpp b/media/img_utils/src/FileInput.cpp
new file mode 100644
index 0000000..e43fd53
--- /dev/null
+++ b/media/img_utils/src/FileInput.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <img_utils/FileInput.h>
+
+#include <utils/Log.h>
+
+namespace android {
+namespace img_utils {
+
+FileInput::FileInput(String8 path) : mFp(NULL), mPath(path), mOpen(false) {}
+
+FileInput::~FileInput() {
+    if (mOpen) {
+        ALOGE("%s: FileInput destroyed without calling close!", __FUNCTION__);
+        close();
+    }
+
+}
+
+status_t FileInput::open() {
+    if (mOpen) {
+        ALOGW("%s: Open called when file %s already open.", __FUNCTION__, mPath.string());
+        return OK;
+    }
+    mFp = ::fopen(mPath, "rb");
+    if (!mFp) {
+        ALOGE("%s: Could not open file %s", __FUNCTION__, mPath.string());
+        return BAD_VALUE;
+    }
+    mOpen = true;
+    return OK;
+}
+
+size_t FileInput::read(uint8_t* buf, size_t offset, size_t count, status_t* err) {
+    if (!mOpen) {
+        ALOGE("%s: Could not read file %s, file not open.", __FUNCTION__, mPath.string());
+        if (err != NULL) *err = BAD_VALUE;
+        return 0;
+    }
+
+    size_t bytesRead = ::fread(buf + offset, sizeof(uint8_t), count, mFp);
+    int error = ::ferror(mFp);
+    if (error != 0) {
+        ALOGE("%s: Error %d occurred while reading file %s.", __FUNCTION__, error, mPath.string());
+        if (err != NULL) *err = BAD_VALUE;
+    }
+    return bytesRead;
+}
+
+status_t FileInput::close() {
+    if(!mOpen) {
+        ALOGW("%s: Close called when file %s already close.", __FUNCTION__, mPath.string());
+        return OK;
+    }
+
+    status_t ret = OK;
+    if(::fclose(mFp) != 0) {
+        ALOGE("%s: Failed to close file %s.", __FUNCTION__, mPath.string());
+        ret = BAD_VALUE;
+    }
+    mOpen = false;
+    return OK;
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/FileOutput.cpp b/media/img_utils/src/FileOutput.cpp
new file mode 100644
index 0000000..ce763ff
--- /dev/null
+++ b/media/img_utils/src/FileOutput.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <img_utils/FileOutput.h>
+
+#include <utils/Log.h>
+
+namespace android {
+namespace img_utils {
+
+FileOutput::FileOutput(String8 path) : mFp(NULL), mPath(path), mOpen(false) {}
+
+FileOutput::~FileOutput() {
+    if (mOpen) {
+        ALOGW("%s: Destructor called with %s still open.", __FUNCTION__, mPath.string());
+        close();
+    }
+}
+
+status_t FileOutput::open() {
+    if (mOpen) {
+        ALOGW("%s: Open called when file %s already open.", __FUNCTION__, mPath.string());
+        return OK;
+    }
+    mFp = ::fopen(mPath, "wb");
+    if (!mFp) {
+        ALOGE("%s: Could not open file %s", __FUNCTION__, mPath.string());
+        return BAD_VALUE;
+    }
+    mOpen = true;
+    return OK;
+}
+
+status_t FileOutput::write(const uint8_t* buf, size_t offset, size_t count) {
+    if (!mOpen) {
+        ALOGE("%s: Could not write file %s, file not open.", __FUNCTION__, mPath.string());
+        return BAD_VALUE;
+    }
+
+    ::fwrite(buf + offset, sizeof(uint8_t), count, mFp);
+
+    int error = ::ferror(mFp);
+    if (error != 0) {
+        ALOGE("%s: Error %d occurred while writing file %s.", __FUNCTION__, error, mPath.string());
+        return BAD_VALUE;
+    }
+    return OK;
+}
+
+status_t FileOutput::close() {
+    if(!mOpen) {
+        ALOGW("%s: Close called when file %s already close.", __FUNCTION__, mPath.string());
+        return OK;
+    }
+
+    status_t ret = OK;
+    if(::fclose(mFp) != 0) {
+        ALOGE("%s: Failed to close file %s.", __FUNCTION__, mPath.string());
+        ret = BAD_VALUE;
+    }
+    mOpen = false;
+    return OK;
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/Input.cpp b/media/img_utils/src/Input.cpp
new file mode 100644
index 0000000..1e51e10
--- /dev/null
+++ b/media/img_utils/src/Input.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <img_utils/Input.h>
+
+namespace android {
+namespace img_utils {
+
+Input::~Input() {}
+status_t Input::open() { return OK; }
+status_t Input::close() { return OK; }
+
+
+} /*namespace img_utils*/
+} /*namespace android*/
+
diff --git a/media/img_utils/src/Orderable.cpp b/media/img_utils/src/Orderable.cpp
new file mode 100644
index 0000000..300f122
--- /dev/null
+++ b/media/img_utils/src/Orderable.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <img_utils/Orderable.h>
+
+#include <utils/Log.h>
+
+namespace android {
+namespace img_utils {
+
+#define COMPARE(op) \
+bool Orderable::operator op (const Orderable& orderable) const { \
+    return getComparableValue() op orderable.getComparableValue(); \
+}
+
+COMPARE(>)
+COMPARE(<)
+COMPARE(>=)
+COMPARE(<=)
+COMPARE(==)
+COMPARE(!=)
+
+Orderable::~Orderable() {}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/Output.cpp b/media/img_utils/src/Output.cpp
new file mode 100644
index 0000000..0e395b9
--- /dev/null
+++ b/media/img_utils/src/Output.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <img_utils/Output.h>
+
+namespace android {
+namespace img_utils {
+
+Output::~Output() {}
+status_t Output::open() { return OK; }
+status_t Output::close() { return OK; }
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/SortedEntryVector.cpp b/media/img_utils/src/SortedEntryVector.cpp
new file mode 100644
index 0000000..f0e1fa1
--- /dev/null
+++ b/media/img_utils/src/SortedEntryVector.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <img_utils/SortedEntryVector.h>
+
+#include <utils/TypeHelpers.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace img_utils {
+
+SortedEntryVector::~SortedEntryVector() {}
+
+ssize_t SortedEntryVector::indexOfTag(uint16_t tag) const {
+    // TODO: Use binary search here.
+    for (size_t i = 0; i < size(); ++i) {
+        if (itemAt(i)->getTag() == tag) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+int SortedEntryVector::do_compare(const void* lhs, const void* rhs) const {
+    const sp<TiffEntry>* lEntry = reinterpret_cast<const sp<TiffEntry>*>(lhs);
+    const sp<TiffEntry>* rEntry = reinterpret_cast<const sp<TiffEntry>*>(rhs);
+    return compare_type(**lEntry, **rEntry);
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/TiffEntry.cpp b/media/img_utils/src/TiffEntry.cpp
new file mode 100644
index 0000000..e028827
--- /dev/null
+++ b/media/img_utils/src/TiffEntry.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <img_utils/TiffIfd.h>
+#include <img_utils/TiffHelpers.h>
+#include <img_utils/TiffEntry.h>
+
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace img_utils {
+
+TiffEntry::~TiffEntry() {}
+
+/**
+ * Specialize for each valid type, including sub-IFDs.
+ *
+ * Values with types other than the ones given here should not compile.
+ */
+template<>
+const Vector<sp<TiffIfd> >* TiffEntry::forceValidType<Vector<sp<TiffIfd> > >(TagType type,
+          const Vector<sp<TiffIfd> >* value) {
+    if (type == LONG) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'ifd vector' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+template<>
+const sp<TiffIfd>* TiffEntry::forceValidType<sp<TiffIfd> >(TagType type, const sp<TiffIfd>* value) {
+    if (type == LONG) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'ifd' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+template<>
+const uint8_t* TiffEntry::forceValidType<uint8_t>(TagType type, const uint8_t* value) {
+    if (type == BYTE || type == ASCII || type == UNDEFINED) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'uint8_t' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+template<>
+const int8_t* TiffEntry::forceValidType<int8_t>(TagType type, const int8_t* value) {
+    if (type == SBYTE || type == ASCII || type == UNDEFINED) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'int8_t' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+template<>
+const uint16_t* TiffEntry::forceValidType<uint16_t>(TagType type, const uint16_t* value) {
+    if (type == SHORT) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'uint16_t' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+template<>
+const int16_t* TiffEntry::forceValidType<int16_t>(TagType type, const int16_t* value) {
+    if (type == SSHORT) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'int16_t' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+template<>
+const uint32_t* TiffEntry::forceValidType<uint32_t>(TagType type, const uint32_t* value) {
+    if (type == LONG || type == RATIONAL) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'uint32_t' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+template<>
+const int32_t* TiffEntry::forceValidType<int32_t>(TagType type, const int32_t* value) {
+    if (type == SLONG || type == SRATIONAL) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'int32_t' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+template<>
+const double* TiffEntry::forceValidType<double>(TagType type, const double* value) {
+    if (type == DOUBLE) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'double' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+template<>
+const float* TiffEntry::forceValidType<float>(TagType type, const float* value) {
+    if (type == FLOAT) {
+        return value;
+    }
+    ALOGE("%s: Value of type 'float' is not valid for tag with TIFF type %d.",
+            __FUNCTION__, type);
+    return NULL;
+}
+
+String8 TiffEntry::toString() const {
+    String8 output;
+    uint32_t count = getCount();
+    output.appendFormat("[id: %x, type: %d, count: %u, value: '", getTag(), getType(), count);
+
+    size_t cappedCount = count;
+    if (count > MAX_PRINT_STRING_LENGTH) {
+        cappedCount = MAX_PRINT_STRING_LENGTH;
+    }
+
+    TagType type = getType();
+    switch (type) {
+        case UNDEFINED:
+        case BYTE: {
+            const uint8_t* typed_data = getData<uint8_t>();
+            for (size_t i = 0; i < cappedCount; ++i) {
+                output.appendFormat("%u ", typed_data[i]);
+            }
+            break;
+        }
+        case ASCII: {
+            const char* typed_data = reinterpret_cast<const char*>(getData<uint8_t>());
+            size_t len = count;
+            if (count > MAX_PRINT_STRING_LENGTH) {
+                 len = MAX_PRINT_STRING_LENGTH;
+            }
+            output.append(typed_data, len);
+            break;
+        }
+        case SHORT: {
+            const uint16_t* typed_data = getData<uint16_t>();
+            for (size_t i = 0; i < cappedCount; ++i) {
+                output.appendFormat("%u ", typed_data[i]);
+            }
+            break;
+        }
+        case LONG: {
+            const uint32_t* typed_data = getData<uint32_t>();
+            for (size_t i = 0; i < cappedCount; ++i) {
+                output.appendFormat("%u ", typed_data[i]);
+            }
+            break;
+        }
+        case RATIONAL: {
+            const uint32_t* typed_data = getData<uint32_t>();
+            cappedCount <<= 1;
+            for (size_t i = 0; i < cappedCount; i+=2) {
+                output.appendFormat("%u/%u ", typed_data[i], typed_data[i + 1]);
+            }
+            break;
+        }
+        case SBYTE: {
+            const int8_t* typed_data = getData<int8_t>();
+            for (size_t i = 0; i < cappedCount; ++i) {
+                output.appendFormat("%d ", typed_data[i]);
+            }
+            break;
+        }
+        case SSHORT: {
+            const int16_t* typed_data = getData<int16_t>();
+            for (size_t i = 0; i < cappedCount; ++i) {
+                output.appendFormat("%d ", typed_data[i]);
+            }
+            break;
+        }
+        case SLONG: {
+            const int32_t* typed_data = getData<int32_t>();
+            for (size_t i = 0; i < cappedCount; ++i) {
+                output.appendFormat("%d ", typed_data[i]);
+            }
+            break;
+        }
+        case SRATIONAL: {
+            const int32_t* typed_data = getData<int32_t>();
+            cappedCount <<= 1;
+            for (size_t i = 0; i < cappedCount; i+=2) {
+                output.appendFormat("%d/%d ", typed_data[i], typed_data[i + 1]);
+            }
+            break;
+        }
+        case FLOAT:
+        case DOUBLE: {
+            const float* typed_data = getData<float>();
+            for (size_t i = 0; i < cappedCount; ++i) {
+                output.appendFormat("%f ", typed_data[i]);
+            }
+            break;
+        }
+        default: {
+            output.append("unknown type ");
+            break;
+        }
+    }
+
+    if (count > MAX_PRINT_STRING_LENGTH) {
+        output.append("...");
+    }
+    output.append("']");
+    return output;
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/TiffEntryImpl.cpp b/media/img_utils/src/TiffEntryImpl.cpp
new file mode 100644
index 0000000..6efa458
--- /dev/null
+++ b/media/img_utils/src/TiffEntryImpl.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <img_utils/TiffEntryImpl.h>
+#include <img_utils/TiffIfd.h>
+
+#include <utils/Vector.h>
+
+namespace android {
+namespace img_utils {
+
+template<>
+size_t TiffEntryImpl<TiffIfd>::getSize() const {
+    uint32_t total = 0;
+    for (uint32_t i = 0; i < mCount; ++i) {
+        total += mData[i].getSize();
+    }
+    return total;
+}
+
+template<>
+status_t TiffEntryImpl<TiffIfd>::writeData(uint32_t offset, EndianOutput* out) const {
+    status_t ret = OK;
+    for (uint32_t i = 0; i < mCount; ++i) {
+        BAIL_ON_FAIL(mData[i].writeData(offset, out), ret);
+    }
+    return ret;
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/TiffIfd.cpp b/media/img_utils/src/TiffIfd.cpp
new file mode 100644
index 0000000..1b3b40d
--- /dev/null
+++ b/media/img_utils/src/TiffIfd.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <img_utils/TiffIfd.h>
+#include <img_utils/TiffHelpers.h>
+
+#include <utils/Log.h>
+
+namespace android {
+namespace img_utils {
+
+TiffIfd::TiffIfd(uint32_t ifdId)
+        : mNextIfd(), mIfdId(ifdId) {}
+
+TiffIfd::~TiffIfd() {}
+
+status_t TiffIfd::addEntry(const sp<TiffEntry>& entry) {
+    size_t size = mEntries.size();
+    if (size >= MAX_IFD_ENTRIES) {
+        ALOGW("%s: Failed to add entry for tag 0x%x to IFD %u, too many entries in IFD!",
+                __FUNCTION__, entry->getTag(), mIfdId);
+        return BAD_INDEX;
+    }
+
+    if (mEntries.add(entry) < 0) {
+        ALOGW("%s: Failed to add entry for tag 0x%x to ifd %u.", __FUNCTION__, entry->getTag(),
+                mIfdId);
+        return BAD_INDEX;
+    }
+    return OK;
+}
+
+sp<TiffEntry> TiffIfd::getEntry(uint16_t tag) const {
+    ssize_t index = mEntries.indexOfTag(tag);
+    if (index < 0) {
+        ALOGW("%s: No entry for tag 0x%x in ifd %u.", __FUNCTION__, tag, mIfdId);
+        return NULL;
+    }
+    return mEntries[index];
+}
+
+void TiffIfd::setNextIfd(const sp<TiffIfd>& ifd) {
+    mNextIfd = ifd;
+}
+
+sp<TiffIfd> TiffIfd::getNextIfd() const {
+    return mNextIfd;
+}
+
+uint32_t TiffIfd::checkAndGetOffset(uint32_t offset) const {
+    size_t size = mEntries.size();
+
+    if (size > MAX_IFD_ENTRIES) {
+        ALOGW("%s: Could not calculate IFD offsets, IFD %u contains too many entries.",
+                __FUNCTION__, mIfdId);
+        return BAD_OFFSET;
+    }
+
+    if (size <= 0) {
+        ALOGW("%s: Could not calculate IFD offsets, IFD %u contains no entries.", __FUNCTION__,
+                mIfdId);
+        return BAD_OFFSET;
+    }
+
+    if (offset == BAD_OFFSET) {
+        ALOGW("%s: Could not calculate IFD offsets, IFD %u had a bad initial offset.",
+                __FUNCTION__, mIfdId);
+        return BAD_OFFSET;
+    }
+
+    uint32_t ifdSize = calculateIfdSize(size);
+    WORD_ALIGN(ifdSize);
+    return offset + ifdSize;
+}
+
+status_t TiffIfd::writeData(uint32_t offset, /*out*/EndianOutput* out) const {
+    assert((offset % TIFF_WORD_SIZE) == 0);
+    status_t ret = OK;
+
+    ALOGV("%s: IFD %u written to offset %u", __FUNCTION__, mIfdId, offset );
+    uint32_t valueOffset = checkAndGetOffset(offset);
+    if (valueOffset == 0) {
+        return BAD_VALUE;
+    }
+
+    size_t size = mEntries.size();
+
+    // Writer IFD header (2 bytes, number of entries).
+    uint16_t header = static_cast<uint16_t>(size);
+    BAIL_ON_FAIL(out->write(&header, 0, 1), ret);
+
+    // Write tag entries
+    for (size_t i = 0; i < size; ++i) {
+        BAIL_ON_FAIL(mEntries[i]->writeTagInfo(valueOffset, out), ret);
+        valueOffset += mEntries[i]->getSize();
+    }
+
+    // Writer IFD footer (4 bytes, offset to next IFD).
+    uint32_t footer = (mNextIfd != NULL) ? offset + getSize() : 0;
+    BAIL_ON_FAIL(out->write(&footer, 0, 1), ret);
+
+    assert(out->getCurrentOffset() == offset + calculateIfdSize(size));
+
+    // Write zeroes till word aligned
+    ZERO_TILL_WORD(out, calculateIfdSize(size), ret);
+
+    // Write values for each tag entry
+    for (size_t i = 0; i < size; ++i) {
+        size_t last = out->getCurrentOffset();
+        // Only write values that are too large to fit in the 12-byte TIFF entry
+        if (mEntries[i]->getSize() > OFFSET_SIZE) {
+            BAIL_ON_FAIL(mEntries[i]->writeData(out->getCurrentOffset(), out), ret);
+        }
+        size_t next = out->getCurrentOffset();
+        size_t diff = (next - last);
+        size_t actual = mEntries[i]->getSize();
+        if (diff != actual) {
+            ALOGW("Sizes do not match for tag %x. Expected %zu, received %zu",
+                    mEntries[i]->getTag(), actual, diff);
+        }
+    }
+
+    assert(out->getCurrentOffset() == offset + getSize());
+
+    return ret;
+}
+
+size_t TiffIfd::getSize() const {
+    size_t size = mEntries.size();
+    uint32_t total = calculateIfdSize(size);
+    WORD_ALIGN(total);
+    for (size_t i = 0; i < size; ++i) {
+        total += mEntries[i]->getSize();
+    }
+    return total;
+}
+
+uint32_t TiffIfd::getId() const {
+    return mIfdId;
+}
+
+uint32_t TiffIfd::getComparableValue() const {
+    return mIfdId;
+}
+
+String8 TiffIfd::toString() const {
+    size_t s = mEntries.size();
+    String8 output;
+    output.appendFormat("[ifd: %x, num_entries: %zu, entries:\n", getId(), s);
+    for(size_t i = 0; i < mEntries.size(); ++i) {
+        output.append("\t");
+        output.append(mEntries[i]->toString());
+        output.append("\n");
+    }
+    output.append(", next_ifd: %x]", ((mNextIfd != NULL) ? mNextIfd->getId() : 0));
+    return output;
+}
+
+void TiffIfd::log() const {
+    size_t s = mEntries.size();
+    ALOGI("[ifd: %x, num_entries: %zu, entries:\n", getId(), s);
+    for(size_t i = 0; i < s; ++i) {
+        ALOGI("\t%s", mEntries[i]->toString().string());
+    }
+    ALOGI(", next_ifd: %x]", ((mNextIfd != NULL) ? mNextIfd->getId() : 0));
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/TiffWritable.cpp b/media/img_utils/src/TiffWritable.cpp
new file mode 100644
index 0000000..f8d7de7
--- /dev/null
+++ b/media/img_utils/src/TiffWritable.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <img_utils/TiffWritable.h>
+#include <img_utils/TiffHelpers.h>
+
+#include <assert.h>
+
+namespace android {
+namespace img_utils {
+
+TiffWritable::TiffWritable() {}
+
+TiffWritable::~TiffWritable() {}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/img_utils/src/TiffWriter.cpp b/media/img_utils/src/TiffWriter.cpp
new file mode 100644
index 0000000..2439033
--- /dev/null
+++ b/media/img_utils/src/TiffWriter.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <img_utils/TiffIfd.h>
+#include <img_utils/TiffHelpers.h>
+#include <img_utils/TiffWriter.h>
+#include <img_utils/TagDefinitions.h>
+
+#include <assert.h>
+
+namespace android {
+namespace img_utils {
+
+KeyedVector<uint16_t, const TagDefinition_t*> TiffWriter::buildTagMap(
+            const TagDefinition_t* definitions, size_t length) {
+    KeyedVector<uint16_t, const TagDefinition_t*> map;
+    for(size_t i = 0; i < length; ++i) {
+        map.add(definitions[i].tagId, definitions + i);
+    }
+    return map;
+}
+
+#define COMPARE(op) \
+bool Orderable::operator op (const Orderable& orderable) const { \
+    return getComparableValue() op orderable.getComparableValue(); \
+}
+
+#define ARRAY_SIZE(array) \
+    (sizeof(array) / sizeof(array[0]))
+
+KeyedVector<uint16_t, const TagDefinition_t*> TiffWriter::sTagMaps[] = {
+    buildTagMap(TIFF_EP_TAG_DEFINITIONS, ARRAY_SIZE(TIFF_EP_TAG_DEFINITIONS)),
+    buildTagMap(DNG_TAG_DEFINITIONS, ARRAY_SIZE(DNG_TAG_DEFINITIONS)),
+    buildTagMap(EXIF_2_3_TAG_DEFINITIONS, ARRAY_SIZE(EXIF_2_3_TAG_DEFINITIONS)),
+    buildTagMap(TIFF_6_TAG_DEFINITIONS, ARRAY_SIZE(TIFF_6_TAG_DEFINITIONS))
+};
+
+TiffWriter::TiffWriter() : mTagMaps(sTagMaps), mNumTagMaps(DEFAULT_NUM_TAG_MAPS) {}
+
+TiffWriter::TiffWriter(KeyedVector<uint16_t, const TagDefinition_t*>* enabledDefinitions,
+        size_t length) : mTagMaps(enabledDefinitions), mNumTagMaps(length) {}
+
+TiffWriter::~TiffWriter() {}
+
+status_t TiffWriter::write(Output* out, Endianness end) {
+    status_t ret = OK;
+    EndianOutput endOut(out, end);
+
+    if (mIfd == NULL) {
+        ALOGE("%s: Tiff header is empty.", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    BAIL_ON_FAIL(writeFileHeader(endOut), ret);
+
+    uint32_t offset = FILE_HEADER_SIZE;
+    sp<TiffIfd> ifd = mIfd;
+    while(ifd != NULL) {
+        BAIL_ON_FAIL(ifd->writeData(offset, &endOut), ret);
+        offset += ifd->getSize();
+        ifd = ifd->getNextIfd();
+    }
+    return ret;
+}
+
+
+const TagDefinition_t* TiffWriter::lookupDefinition(uint16_t tag) const {
+    const TagDefinition_t* definition = NULL;
+    for (size_t i = 0; i < mNumTagMaps; ++i) {
+        ssize_t index = mTagMaps[i].indexOfKey(tag);
+        if (index >= 0) {
+            definition = mTagMaps[i][index];
+            break;
+        }
+    }
+
+    if (definition == NULL) {
+        ALOGE("%s: No definition exists for tag with id %x.", __FUNCTION__, tag);
+    }
+    return definition;
+}
+
+sp<TiffEntry> TiffWriter::getEntry(uint16_t tag, uint32_t ifd) const {
+    ssize_t index = mNamedIfds.indexOfKey(ifd);
+    if (index < 0) {
+        ALOGE("%s: No IFD %d set for this writer.", __FUNCTION__, ifd);
+        return NULL;
+    }
+    return mNamedIfds[index]->getEntry(tag);
+}
+
+
+// TODO: Fix this to handle IFD position in chain/sub-IFD tree
+status_t TiffWriter::addEntry(const sp<TiffEntry>& entry) {
+    uint16_t tag = entry->getTag();
+
+    const TagDefinition_t* definition = lookupDefinition(tag);
+
+    if (definition == NULL) {
+        return BAD_INDEX;
+    }
+    uint32_t ifdId = 0;  // TODO: all in IFD0 for now.
+
+    ssize_t index = mNamedIfds.indexOfKey(ifdId);
+
+    // Add a new IFD if necessary
+    if (index < 0) {
+        sp<TiffIfd> ifdEntry = new TiffIfd(ifdId);
+        if (mIfd == NULL) {
+            mIfd = ifdEntry;
+        }
+        index = mNamedIfds.add(ifdId, ifdEntry);
+        assert(index >= 0);
+    }
+
+    sp<TiffIfd> selectedIfd  = mNamedIfds[index];
+    return selectedIfd->addEntry(entry);
+}
+
+status_t TiffWriter::uncheckedAddIfd(const sp<TiffIfd>& ifd) {
+    mNamedIfds.add(ifd->getId(), ifd);
+    sp<TiffIfd> last = findLastIfd();
+    if (last == NULL) {
+        mIfd = ifd;
+    } else {
+        last->setNextIfd(ifd);
+    }
+    last = ifd->getNextIfd();
+    while (last != NULL) {
+        mNamedIfds.add(last->getId(), last);
+        last = last->getNextIfd();
+    }
+    return OK;
+}
+
+status_t TiffWriter::addIfd(uint32_t ifd) {
+    ssize_t index = mNamedIfds.indexOfKey(ifd);
+    if (index >= 0) {
+        ALOGE("%s: Ifd with ID 0x%x already exists.", __FUNCTION__, ifd);
+        return BAD_VALUE;
+    }
+    sp<TiffIfd> newIfd = new TiffIfd(ifd);
+    if (mIfd == NULL) {
+        mIfd = newIfd;
+    } else {
+        sp<TiffIfd> last = findLastIfd();
+        last->setNextIfd(newIfd);
+    }
+    mNamedIfds.add(ifd, newIfd);
+    return OK;
+}
+
+TagType TiffWriter::getDefaultType(uint16_t tag) const {
+    const TagDefinition_t* definition = lookupDefinition(tag);
+    if (definition == NULL) {
+        ALOGE("%s: Could not find definition for tag %x", __FUNCTION__, tag);
+        return UNKNOWN_TAGTYPE;
+    }
+    return definition->defaultType;
+}
+
+uint32_t TiffWriter::getDefaultCount(uint16_t tag) const {
+    const TagDefinition_t* definition = lookupDefinition(tag);
+    if (definition == NULL) {
+        ALOGE("%s: Could not find definition for tag %x", __FUNCTION__, tag);
+        return 0;
+    }
+    return definition->fixedCount;
+}
+
+bool TiffWriter::checkIfDefined(uint16_t tag) const {
+    return lookupDefinition(tag) != NULL;
+}
+
+sp<TiffIfd> TiffWriter::findLastIfd() {
+    sp<TiffIfd> ifd = mIfd;
+    while(ifd != NULL) {
+        sp<TiffIfd> nextIfd = ifd->getNextIfd();
+        if (nextIfd == NULL) {
+            break;
+        }
+        ifd = nextIfd;
+    }
+    return ifd;
+}
+
+status_t TiffWriter::writeFileHeader(EndianOutput& out) {
+    status_t ret = OK;
+    uint16_t endMarker = (out.getEndianness() == BIG) ? BIG_ENDIAN_MARKER : LITTLE_ENDIAN_MARKER;
+    BAIL_ON_FAIL(out.write(&endMarker, 0, 1), ret);
+
+    uint16_t tiffMarker = TIFF_FILE_MARKER;
+    BAIL_ON_FAIL(out.write(&tiffMarker, 0, 1), ret);
+
+    uint32_t offsetMarker = FILE_HEADER_SIZE;
+    BAIL_ON_FAIL(out.write(&offsetMarker, 0, 1), ret);
+    return ret;
+}
+
+uint32_t TiffWriter::getTotalSize() const {
+    uint32_t totalSize = FILE_HEADER_SIZE;
+    sp<TiffIfd> ifd = mIfd;
+    while(ifd != NULL) {
+        totalSize += ifd->getSize();
+        ifd = ifd->getNextIfd();
+    }
+    return totalSize;
+}
+
+void TiffWriter::log() const {
+    ALOGI("%s: TiffWriter:", __FUNCTION__);
+    sp<TiffIfd> ifd = mIfd;
+    while(ifd != NULL) {
+        ifd->log();
+        ifd = ifd->getNextIfd();
+    }
+}
+
+} /*namespace img_utils*/
+} /*namespace android*/
diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.c
index 661fde9..6686f27 100644
--- a/media/libeffects/downmix/EffectDownmix.c
+++ b/media/libeffects/downmix/EffectDownmix.c
@@ -118,7 +118,7 @@
         hasBacks = true;
     }
 
-    const int numChan = popcount(mask);
+    const int numChan = audio_channel_count_from_out_mask(mask);
     const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER);
     const bool hasLFE =
             ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY);
@@ -629,7 +629,8 @@
             ALOGE("Downmix_Configure error: input channel mask can't be 0");
             return -EINVAL;
         }
-        pDownmixer->input_channel_count = popcount(pConfig->inputCfg.channels);
+        pDownmixer->input_channel_count =
+                audio_channel_count_from_out_mask(pConfig->inputCfg.channels);
     }
 
     Downmix_Reset(pDownmixer, init);
@@ -997,7 +998,7 @@
         hasBacks = true;
     }
 
-    const int numChan = popcount(mask);
+    const int numChan = audio_channel_count_from_out_mask(mask);
     const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER);
     const bool hasLFE =
             ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY);
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index a96a703..cf98f56 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -879,8 +879,8 @@
 int Session_SetConfig(preproc_session_t *session, effect_config_t *config)
 {
     uint32_t sr;
-    uint32_t inCnl = popcount(config->inputCfg.channels);
-    uint32_t outCnl = popcount(config->outputCfg.channels);
+    uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels);
+    uint32_t outCnl = audio_channel_count_from_out_mask(config->outputCfg.channels);
 
     if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
         config->inputCfg.format != config->outputCfg.format ||
@@ -1035,7 +1035,7 @@
             config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
         return -EINVAL;
     }
-    uint32_t inCnl = popcount(config->inputCfg.channels);
+    uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels);
     int status = session->apm->set_num_reverse_channels(inCnl);
     if (status < 0) {
         return -EINVAL;
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 47cab62..e5089da 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -207,7 +207,8 @@
     pContext->mScalingMode = VISUALIZER_SCALING_MODE_NORMALIZED;
 
     // measurement initialization
-    pContext->mChannelCount = popcount(pContext->mConfig.inputCfg.channels);
+    pContext->mChannelCount =
+            audio_channel_count_from_out_mask(pContext->mConfig.inputCfg.channels);
     pContext->mMeasurementMode = MEASUREMENT_MODE_NONE;
     pContext->mMeasurementWindowSizeInBuffers = MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS;
     pContext->mMeasurementBufferIdx = 0;
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 97ab8f8..1c808d0 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -51,7 +51,8 @@
 
     // We double the size of input buffer for ping pong use of record buffer.
     // Assumes audio_is_linear_pcm(format)
-    if ((*frameCount = (size * 2) / (popcount(channelMask) * audio_bytes_per_sample(format))) == 0) {
+    if ((*frameCount = (size * 2) / (audio_channel_count_from_in_mask(channelMask) *
+            audio_bytes_per_sample(format))) == 0) {
         ALOGE("Unsupported configuration: sampleRate %u, format %#x, channelMask %#x",
             sampleRate, format, channelMask);
         return BAD_VALUE;
@@ -193,7 +194,7 @@
         return BAD_VALUE;
     }
     mChannelMask = channelMask;
-    uint32_t channelCount = popcount(channelMask);
+    uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
     mChannelCount = channelCount;
 
     if (audio_is_linear_pcm(format)) {
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index aaaa3f1..7d3ecc5 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -19,6 +19,7 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "AudioTrack"
 
+#include <math.h>
 #include <sys/resource.h>
 #include <audio_utils/primitives.h>
 #include <binder/IPCThreadState.h>
@@ -290,7 +291,7 @@
         return BAD_VALUE;
     }
     mChannelMask = channelMask;
-    uint32_t channelCount = popcount(channelMask);
+    uint32_t channelCount = audio_channel_count_from_out_mask(channelMask);
     mChannelCount = channelCount;
 
     // AudioFlinger does not currently support 8-bit data in shared memory
@@ -566,7 +567,9 @@
 
 status_t AudioTrack::setVolume(float left, float right)
 {
-    if (left < 0.0f || left > 1.0f || right < 0.0f || right > 1.0f) {
+    // This duplicates a test by AudioTrack JNI, but that is not the only caller
+    if (isnanf(left) || left < GAIN_FLOAT_ZERO || left > GAIN_FLOAT_UNITY ||
+            isnanf(right) || right < GAIN_FLOAT_ZERO || right > GAIN_FLOAT_UNITY) {
         return BAD_VALUE;
     }
 
@@ -574,7 +577,7 @@
     mVolume[AUDIO_INTERLEAVE_LEFT] = left;
     mVolume[AUDIO_INTERLEAVE_RIGHT] = right;
 
-    mProxy->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000));
+    mProxy->setVolumeLR(gain_minifloat_pack(gain_from_float(left), gain_from_float(right)));
 
     if (isOffloaded_l()) {
         mAudioTrack->signal();
@@ -589,7 +592,8 @@
 
 status_t AudioTrack::setAuxEffectSendLevel(float level)
 {
-    if (level < 0.0f || level > 1.0f) {
+    // This duplicates a test by AudioTrack JNI, but that is not the only caller
+    if (isnanf(level) || level < GAIN_FLOAT_ZERO || level > GAIN_FLOAT_UNITY) {
         return BAD_VALUE;
     }
 
@@ -1137,8 +1141,7 @@
         mStaticProxy = new StaticAudioTrackClientProxy(cblk, buffers, frameCount, mFrameSizeAF);
         mProxy = mStaticProxy;
     }
-    mProxy->setVolumeLR((uint32_t(uint16_t(mVolume[AUDIO_INTERLEAVE_RIGHT] * 0x1000)) << 16) |
-            uint16_t(mVolume[AUDIO_INTERLEAVE_LEFT] * 0x1000));
+    mProxy->setVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY);
     mProxy->setSendLevel(mSendLevel);
     mProxy->setSampleRate(mSampleRate);
     mProxy->setEpoch(epoch);
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 323b675..27a3718 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -27,7 +27,7 @@
 
 audio_track_cblk_t::audio_track_cblk_t()
     : mServer(0), mFutex(0), mMinimum(0),
-    mVolumeLR(0x10001000), mSampleRate(0), mSendLevel(0), mFlags(0)
+    mVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY), mSampleRate(0), mSendLevel(0), mFlags(0)
 {
     memset(&u, 0, sizeof(u));
 }
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 9c13848..5df232f 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -65,7 +65,7 @@
     virtual bool livesLocally(node_id node, pid_t pid) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeInt32(pid);
         remote()->transact(LIVES_LOCALLY, data, &reply);
 
@@ -104,7 +104,7 @@
 
         status_t err = reply.readInt32();
         if (err == OK) {
-            *node = (void*)reply.readIntPtr();
+            *node = (node_id)reply.readInt32();
         } else {
             *node = 0;
         }
@@ -115,7 +115,7 @@
     virtual status_t freeNode(node_id node) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         remote()->transact(FREE_NODE, data, &reply);
 
         return reply.readInt32();
@@ -125,7 +125,7 @@
             node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeInt32(cmd);
         data.writeInt32(param);
         remote()->transact(SEND_COMMAND, data, &reply);
@@ -138,7 +138,7 @@
             void *params, size_t size) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeInt32(index);
         data.writeInt64(size);
         data.write(params, size);
@@ -159,7 +159,7 @@
             const void *params, size_t size) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeInt32(index);
         data.writeInt64(size);
         data.write(params, size);
@@ -173,7 +173,7 @@
             void *params, size_t size) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeInt32(index);
         data.writeInt64(size);
         data.write(params, size);
@@ -194,7 +194,7 @@
             const void *params, size_t size) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeInt32(index);
         data.writeInt64(size);
         data.write(params, size);
@@ -207,7 +207,7 @@
             node_id node, OMX_STATETYPE* state) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         remote()->transact(GET_STATE, data, &reply);
 
         *state = static_cast<OMX_STATETYPE>(reply.readInt32());
@@ -218,7 +218,7 @@
             node_id node, OMX_U32 port_index, OMX_BOOL enable) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeInt32(port_index);
         data.writeInt32((uint32_t)enable);
         remote()->transact(ENABLE_GRAPHIC_BUFFERS, data, &reply);
@@ -231,7 +231,7 @@
             node_id node, OMX_U32 port_index, OMX_U32* usage) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeInt32(port_index);
         remote()->transact(GET_GRAPHIC_BUFFER_USAGE, data, &reply);
 
@@ -245,7 +245,7 @@
             buffer_id *buffer) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeInt32(port_index);
         data.writeStrongBinder(params->asBinder());
         remote()->transact(USE_BUFFER, data, &reply);
@@ -257,7 +257,7 @@
             return err;
         }
 
-        *buffer = (void*)reply.readIntPtr();
+        *buffer = (buffer_id)reply.readInt32();
 
         return err;
     }
@@ -268,7 +268,7 @@
             const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeInt32(port_index);
         data.write(*graphicBuffer);
         remote()->transact(USE_GRAPHIC_BUFFER, data, &reply);
@@ -280,7 +280,7 @@
             return err;
         }
 
-        *buffer = (void*)reply.readIntPtr();
+        *buffer = (buffer_id)reply.readInt32();
 
         return err;
     }
@@ -290,10 +290,10 @@
             const sp<GraphicBuffer> &graphicBuffer, buffer_id buffer) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeInt32(port_index);
         data.write(*graphicBuffer);
-        data.writeIntPtr((intptr_t)buffer);
+        data.writeInt32((int32_t)buffer);
         remote()->transact(UPDATE_GRAPHIC_BUFFER_IN_META, data, &reply);
 
         status_t err = reply.readInt32();
@@ -306,7 +306,7 @@
         Parcel data, reply;
         status_t err;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeInt32(port_index);
         err = remote()->transact(CREATE_INPUT_SURFACE, data, &reply);
         if (err != OK) {
@@ -329,7 +329,7 @@
         Parcel data, reply;
         status_t err;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         err = remote()->transact(SIGNAL_END_OF_INPUT_STREAM, data, &reply);
         if (err != OK) {
             ALOGW("binder transaction failed: %d", err);
@@ -343,7 +343,7 @@
             node_id node, OMX_U32 port_index, OMX_BOOL enable) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeInt32(port_index);
         data.writeInt32((uint32_t)enable);
         remote()->transact(STORE_META_DATA_IN_BUFFERS, data, &reply);
@@ -357,7 +357,7 @@
             OMX_U32 max_width, OMX_U32 max_height) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeInt32(port_index);
         data.writeInt32((int32_t)enable);
         data.writeInt32(max_width);
@@ -373,7 +373,7 @@
             buffer_id *buffer, void **buffer_data) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeInt32(port_index);
         data.writeInt64(size);
         remote()->transact(ALLOC_BUFFER, data, &reply);
@@ -385,8 +385,8 @@
             return err;
         }
 
-        *buffer = (void *)reply.readIntPtr();
-        *buffer_data = (void *)reply.readIntPtr();
+        *buffer = (buffer_id)reply.readInt32();
+        *buffer_data = (void *)reply.readInt64();
 
         return err;
     }
@@ -396,7 +396,7 @@
             buffer_id *buffer) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeInt32(port_index);
         data.writeStrongBinder(params->asBinder());
         remote()->transact(ALLOC_BUFFER_WITH_BACKUP, data, &reply);
@@ -408,7 +408,7 @@
             return err;
         }
 
-        *buffer = (void*)reply.readIntPtr();
+        *buffer = (buffer_id)reply.readInt32();
 
         return err;
     }
@@ -417,9 +417,9 @@
             node_id node, OMX_U32 port_index, buffer_id buffer) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeInt32(port_index);
-        data.writeIntPtr((intptr_t)buffer);
+        data.writeInt32((int32_t)buffer);
         remote()->transact(FREE_BUFFER, data, &reply);
 
         return reply.readInt32();
@@ -428,8 +428,8 @@
     virtual status_t fillBuffer(node_id node, buffer_id buffer) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
-        data.writeIntPtr((intptr_t)buffer);
+        data.writeInt32((int32_t)node);
+        data.writeInt32((int32_t)buffer);
         remote()->transact(FILL_BUFFER, data, &reply);
 
         return reply.readInt32();
@@ -442,8 +442,8 @@
             OMX_U32 flags, OMX_TICKS timestamp) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
-        data.writeIntPtr((intptr_t)buffer);
+        data.writeInt32((int32_t)node);
+        data.writeInt32((int32_t)buffer);
         data.writeInt32(range_offset);
         data.writeInt32(range_length);
         data.writeInt32(flags);
@@ -459,7 +459,7 @@
             OMX_INDEXTYPE *index) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeCString(parameter_name);
 
         remote()->transact(GET_EXTENSION_INDEX, data, &reply);
@@ -482,7 +482,7 @@
             size_t size) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeIntPtr((intptr_t)node);
+        data.writeInt32((int32_t)node);
         data.writeInt32(port_index);
         data.writeInt64(size);
         data.write(optionData, size);
@@ -509,7 +509,7 @@
         case LIVES_LOCALLY:
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
-            node_id node = (void *)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
             pid_t pid = (pid_t)data.readInt32();
             reply->writeInt32(livesLocally(node, pid));
 
@@ -553,7 +553,7 @@
             status_t err = allocateNode(name, observer, &node);
             reply->writeInt32(err);
             if (err == OK) {
-                reply->writeIntPtr((intptr_t)node);
+                reply->writeInt32((int32_t)node);
             }
 
             return NO_ERROR;
@@ -563,7 +563,7 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
 
             reply->writeInt32(freeNode(node));
 
@@ -574,7 +574,7 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
 
             OMX_COMMANDTYPE cmd =
                 static_cast<OMX_COMMANDTYPE>(data.readInt32());
@@ -593,7 +593,7 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
             OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
 
             size_t size = data.readInt64();
@@ -644,7 +644,7 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
             OMX_STATETYPE state = OMX_StateInvalid;
 
             status_t err = getState(node, &state);
@@ -658,7 +658,7 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
             OMX_U32 port_index = data.readInt32();
             OMX_BOOL enable = (OMX_BOOL)data.readInt32();
 
@@ -672,7 +672,7 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
             OMX_U32 port_index = data.readInt32();
 
             OMX_U32 usage = 0;
@@ -687,7 +687,7 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
             OMX_U32 port_index = data.readInt32();
             sp<IMemory> params =
                 interface_cast<IMemory>(data.readStrongBinder());
@@ -697,7 +697,7 @@
             reply->writeInt32(err);
 
             if (err == OK) {
-                reply->writeIntPtr((intptr_t)buffer);
+                reply->writeInt32((int32_t)buffer);
             }
 
             return NO_ERROR;
@@ -707,7 +707,7 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
             OMX_U32 port_index = data.readInt32();
             sp<GraphicBuffer> graphicBuffer = new GraphicBuffer();
             data.read(*graphicBuffer);
@@ -718,7 +718,7 @@
             reply->writeInt32(err);
 
             if (err == OK) {
-                reply->writeIntPtr((intptr_t)buffer);
+                reply->writeInt32((int32_t)buffer);
             }
 
             return NO_ERROR;
@@ -728,11 +728,11 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
             OMX_U32 port_index = data.readInt32();
             sp<GraphicBuffer> graphicBuffer = new GraphicBuffer();
             data.read(*graphicBuffer);
-            buffer_id buffer = (void*)data.readIntPtr();
+            buffer_id buffer = (buffer_id)data.readInt32();
 
             status_t err = updateGraphicBufferInMeta(
                     node, port_index, graphicBuffer, buffer);
@@ -745,7 +745,7 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
             OMX_U32 port_index = data.readInt32();
 
             sp<IGraphicBufferProducer> bufferProducer;
@@ -765,7 +765,7 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
 
             status_t err = signalEndOfInputStream(node);
             reply->writeInt32(err);
@@ -777,7 +777,7 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
             OMX_U32 port_index = data.readInt32();
             OMX_BOOL enable = (OMX_BOOL)data.readInt32();
 
@@ -791,7 +791,7 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
             OMX_U32 port_index = data.readInt32();
             OMX_BOOL enable = (OMX_BOOL)data.readInt32();
             OMX_U32 max_width = data.readInt32();
@@ -808,7 +808,7 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
             OMX_U32 port_index = data.readInt32();
             size_t size = data.readInt64();
 
@@ -819,8 +819,8 @@
             reply->writeInt32(err);
 
             if (err == OK) {
-                reply->writeIntPtr((intptr_t)buffer);
-                reply->writeIntPtr((intptr_t)buffer_data);
+                reply->writeInt32((int32_t)buffer);
+                reply->writeInt64((uintptr_t)buffer_data);
             }
 
             return NO_ERROR;
@@ -830,7 +830,7 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
             OMX_U32 port_index = data.readInt32();
             sp<IMemory> params =
                 interface_cast<IMemory>(data.readStrongBinder());
@@ -842,7 +842,7 @@
             reply->writeInt32(err);
 
             if (err == OK) {
-                reply->writeIntPtr((intptr_t)buffer);
+                reply->writeInt32((int32_t)buffer);
             }
 
             return NO_ERROR;
@@ -852,9 +852,9 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
             OMX_U32 port_index = data.readInt32();
-            buffer_id buffer = (void*)data.readIntPtr();
+            buffer_id buffer = (buffer_id)data.readInt32();
             reply->writeInt32(freeBuffer(node, port_index, buffer));
 
             return NO_ERROR;
@@ -864,8 +864,8 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
-            buffer_id buffer = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
+            buffer_id buffer = (buffer_id)data.readInt32();
             reply->writeInt32(fillBuffer(node, buffer));
 
             return NO_ERROR;
@@ -875,8 +875,8 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
-            buffer_id buffer = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
+            buffer_id buffer = (buffer_id)data.readInt32();
             OMX_U32 range_offset = data.readInt32();
             OMX_U32 range_length = data.readInt32();
             OMX_U32 flags = data.readInt32();
@@ -894,7 +894,7 @@
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
-            node_id node = (void*)data.readIntPtr();
+            node_id node = (node_id)data.readInt32();
             const char *parameter_name = data.readCString();
 
             OMX_INDEXTYPE index;
@@ -927,6 +927,8 @@
         data.writeInterfaceToken(IOMXObserver::getInterfaceDescriptor());
         data.write(&msg, sizeof(msg));
 
+        ALOGV("onMessage writing message %d, size %zu", msg.type, sizeof(msg));
+
         remote()->transact(OBSERVER_ON_MSG, data, &reply, IBinder::FLAG_ONEWAY);
     }
 };
@@ -943,6 +945,8 @@
             omx_message msg;
             data.read(&msg, sizeof(msg));
 
+            ALOGV("onTransact reading message %d, size %zu", msg.type, sizeof(msg));
+
             // XXX Could use readInplace maybe?
             onMessage(msg);
 
diff --git a/media/libnbaio/AudioStreamInSource.cpp b/media/libnbaio/AudioStreamInSource.cpp
index af8f365..6aab48a 100644
--- a/media/libnbaio/AudioStreamInSource.cpp
+++ b/media/libnbaio/AudioStreamInSource.cpp
@@ -46,7 +46,8 @@
         uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common);
         audio_channel_mask_t channelMask =
                 (audio_channel_mask_t) mStream->common.get_channels(&mStream->common);
-        mFormat = Format_from_SR_C(sampleRate, popcount(channelMask), streamFormat);
+        mFormat = Format_from_SR_C(sampleRate,
+                audio_channel_count_from_in_mask(channelMask), streamFormat);
         mFrameSize = Format_frameSize(mFormat);
     }
     return NBAIO_Source::negotiate(offers, numOffers, counterOffers, numCounterOffers);
diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp
index c28d34d..0d5f935 100644
--- a/media/libnbaio/AudioStreamOutSink.cpp
+++ b/media/libnbaio/AudioStreamOutSink.cpp
@@ -43,7 +43,8 @@
         uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common);
         audio_channel_mask_t channelMask =
                 (audio_channel_mask_t) mStream->common.get_channels(&mStream->common);
-        mFormat = Format_from_SR_C(sampleRate, popcount(channelMask), streamFormat);
+        mFormat = Format_from_SR_C(sampleRate,
+                audio_channel_count_from_out_mask(channelMask), streamFormat);
         mFrameSize = Format_frameSize(mFormat);
     }
     return NBAIO_Sink::negotiate(offers, numOffers, counterOffers, numCounterOffers);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index b6db00c..8f154be 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -17,6 +17,11 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "ACodec"
 
+#ifdef __LP64__
+#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+#endif
+
+#include <inttypes.h>
 #include <utils/Trace.h>
 
 #include <media/stagefright/ACodec.h>
@@ -67,7 +72,7 @@
         sp<AMessage> msg = mNotify->dup();
 
         msg->setInt32("type", omx_msg.type);
-        msg->setPointer("node", omx_msg.node);
+        msg->setInt32("node", omx_msg.node);
 
         switch (omx_msg.type) {
             case omx_message::EVENT:
@@ -80,13 +85,13 @@
 
             case omx_message::EMPTY_BUFFER_DONE:
             {
-                msg->setPointer("buffer", omx_msg.u.buffer_data.buffer);
+                msg->setInt32("buffer", omx_msg.u.buffer_data.buffer);
                 break;
             }
 
             case omx_message::FILL_BUFFER_DONE:
             {
-                msg->setPointer(
+                msg->setInt32(
                         "buffer", omx_msg.u.extended_buffer_data.buffer);
                 msg->setInt32(
                         "range_offset",
@@ -355,7 +360,7 @@
 
 ACodec::ACodec()
     : mQuirks(0),
-      mNode(NULL),
+      mNode(0),
       mSentFormat(false),
       mIsEncoder(false),
       mUseMetadataOnEncoderOutput(false),
@@ -370,8 +375,8 @@
       mMetaDataBuffersToSubmit(0),
       mRepeatFrameDelayUs(-1ll),
       mMaxPtsGapUs(-1ll),
-      mTimePerCaptureUs(-1ll),
       mTimePerFrameUs(-1ll),
+      mTimePerCaptureUs(-1ll),
       mCreateInputBuffersSuspended(false) {
     mUninitializedState = new UninitializedState(this);
     mLoadedState = new LoadedState(this);
@@ -488,7 +493,7 @@
                 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
 
         if (err == OK) {
-            ALOGV("[%s] Allocating %lu buffers of size %lu on %s port",
+            ALOGV("[%s] Allocating %u buffers of size %u on %s port",
                     mComponentName.c_str(),
                     def.nBufferCountActual, def.nBufferSize,
                     portIndex == kPortIndexInput ? "input" : "output");
@@ -662,7 +667,7 @@
             break;
         }
 
-        ALOGW("[%s] setting nBufferCountActual to %lu failed: %d",
+        ALOGW("[%s] setting nBufferCountActual to %u failed: %d",
                 mComponentName.c_str(), newBufferCount, err);
         /* exit condition */
         if (extraBuffers == 0) {
@@ -692,7 +697,7 @@
         return err;
     mNumUndequeuedBuffers = minUndequeuedBuffers;
 
-    ALOGV("[%s] Allocating %lu buffers from a native window of size %lu on "
+    ALOGV("[%s] Allocating %u buffers from a native window of size %u on "
          "output port",
          mComponentName.c_str(), bufferCount, bufferSize);
 
@@ -716,14 +721,14 @@
         err = mOMX->useGraphicBuffer(mNode, kPortIndexOutput, graphicBuffer,
                 &bufferId);
         if (err != 0) {
-            ALOGE("registering GraphicBuffer %lu with OMX IL component failed: "
+            ALOGE("registering GraphicBuffer %u with OMX IL component failed: "
                  "%d", i, err);
             break;
         }
 
         mBuffers[kPortIndexOutput].editItemAt(i).mBufferID = bufferId;
 
-        ALOGV("[%s] Registered graphic buffer with ID %p (pointer = %p)",
+        ALOGV("[%s] Registered graphic buffer with ID %u (pointer = %p)",
              mComponentName.c_str(),
              bufferId, graphicBuffer.get());
     }
@@ -758,7 +763,7 @@
         return err;
     mNumUndequeuedBuffers = minUndequeuedBuffers;
 
-    ALOGV("[%s] Allocating %lu meta buffers on output port",
+    ALOGV("[%s] Allocating %u meta buffers on output port",
          mComponentName.c_str(), bufferCount);
 
     size_t totalSize = bufferCount * 8;
@@ -782,7 +787,7 @@
 
         mBuffers[kPortIndexOutput].push(info);
 
-        ALOGV("[%s] allocated meta buffer with ID %p (pointer = %p)",
+        ALOGV("[%s] allocated meta buffer with ID %u (pointer = %p)",
              mComponentName.c_str(), info.mBufferID, mem->pointer());
     }
 
@@ -799,7 +804,7 @@
     if (info == NULL)
         return ERROR_IO;
 
-    ALOGV("[%s] submitting output meta buffer ID %p for graphic buffer %p",
+    ALOGV("[%s] submitting output meta buffer ID %u for graphic buffer %p",
           mComponentName.c_str(), info->mBufferID, info->mGraphicBuffer.get());
 
     --mMetaDataBuffersToSubmit;
@@ -813,7 +818,7 @@
 status_t ACodec::cancelBufferToNativeWindow(BufferInfo *info) {
     CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US);
 
-    ALOGV("[%s] Calling cancelBuffer on buffer %p",
+    ALOGV("[%s] Calling cancelBuffer on buffer %u",
          mComponentName.c_str(), info->mBufferID);
 
     int err = mNativeWindow->cancelBuffer(
@@ -2614,7 +2619,7 @@
 
         if (info->mStatus != BufferInfo::OWNED_BY_US
                 && info->mStatus != BufferInfo::OWNED_BY_NATIVE_WINDOW) {
-            ALOGV("[%s] Buffer %p on port %ld still has status %d",
+            ALOGV("[%s] Buffer %u on port %u still has status %d",
                     mComponentName.c_str(),
                     info->mBufferID, portIndex, info->mStatus);
             return false;
@@ -3180,7 +3185,7 @@
     }
 
     IOMX::node_id nodeID;
-    CHECK(msg->findPointer("node", &nodeID));
+    CHECK(msg->findInt32("node", (int32_t*)&nodeID));
     CHECK_EQ(nodeID, mCodec->mNode);
 
     switch (type) {
@@ -3211,7 +3216,7 @@
         case omx_message::EMPTY_BUFFER_DONE:
         {
             IOMX::buffer_id bufferID;
-            CHECK(msg->findPointer("buffer", &bufferID));
+            CHECK(msg->findInt32("buffer", (int32_t*)&bufferID));
 
             return onOMXEmptyBufferDone(bufferID);
         }
@@ -3219,7 +3224,7 @@
         case omx_message::FILL_BUFFER_DONE:
         {
             IOMX::buffer_id bufferID;
-            CHECK(msg->findPointer("buffer", &bufferID));
+            CHECK(msg->findInt32("buffer", (int32_t*)&bufferID));
 
             int32_t rangeOffset, rangeLength, flags;
             int64_t timeUs;
@@ -3316,13 +3321,13 @@
 
     sp<AMessage> notify = mCodec->mNotify->dup();
     notify->setInt32("what", ACodec::kWhatFillThisBuffer);
-    notify->setPointer("buffer-id", info->mBufferID);
+    notify->setInt32("buffer-id", info->mBufferID);
 
     info->mData->meta()->clear();
     notify->setBuffer("buffer", info->mData);
 
     sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, mCodec->id());
-    reply->setPointer("buffer-id", info->mBufferID);
+    reply->setInt32("buffer-id", info->mBufferID);
 
     notify->setMessage("reply", reply);
 
@@ -3333,8 +3338,7 @@
 
 void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {
     IOMX::buffer_id bufferID;
-    CHECK(msg->findPointer("buffer-id", &bufferID));
-
+    CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
     sp<ABuffer> buffer;
     int32_t err = OK;
     bool eos = false;
@@ -3533,7 +3537,7 @@
         size_t rangeOffset, size_t rangeLength,
         OMX_U32 flags,
         int64_t timeUs) {
-    ALOGV("[%s] onOMXFillBufferDone %p time %lld us, flags = 0x%08lx",
+    ALOGV("[%s] onOMXFillBufferDone %u time %" PRId64 " us, flags = 0x%08x",
          mCodec->mComponentName.c_str(), bufferID, timeUs, flags);
 
     ssize_t index;
@@ -3570,7 +3574,7 @@
         case RESUBMIT_BUFFERS:
         {
             if (rangeLength == 0 && !(flags & OMX_BUFFERFLAG_EOS)) {
-                ALOGV("[%s] calling fillBuffer %p",
+                ALOGV("[%s] calling fillBuffer %u",
                      mCodec->mComponentName.c_str(), info->mBufferID);
 
                 CHECK_EQ(mCodec->mOMX->fillBuffer(
@@ -3612,11 +3616,11 @@
 
             sp<AMessage> notify = mCodec->mNotify->dup();
             notify->setInt32("what", ACodec::kWhatDrainThisBuffer);
-            notify->setPointer("buffer-id", info->mBufferID);
+            notify->setInt32("buffer-id", info->mBufferID);
             notify->setBuffer("buffer", info->mData);
             notify->setInt32("flags", flags);
 
-            reply->setPointer("buffer-id", info->mBufferID);
+            reply->setInt32("buffer-id", info->mBufferID);
 
             notify->setMessage("reply", reply);
 
@@ -3652,8 +3656,7 @@
 
 void ACodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) {
     IOMX::buffer_id bufferID;
-    CHECK(msg->findPointer("buffer-id", &bufferID));
-
+    CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
     ssize_t index;
     BufferInfo *info =
         mCodec->findBufferByID(kPortIndexOutput, bufferID, &index);
@@ -3681,7 +3684,7 @@
             // API 20.  Perhaps check for target SDK version.
 #if 0
             if (info->mData->meta()->findInt64("timeUs", &timestampNs)) {
-                ALOGI("using buffer PTS of %" PRId64, timestampNs);
+                ALOGV("using buffer PTS of %" PRId64, timestampNs);
                 timestampNs *= 1000;
             }
 #endif
@@ -3691,8 +3694,6 @@
         err = native_window_set_buffers_timestamp(mCodec->mNativeWindow.get(), timestampNs);
         if (err != OK) {
             ALOGW("failed to set buffer timestamp: %d", err);
-        } else {
-            ALOGI("set PTS to %" PRId64, timestampNs);
         }
 
         if ((err = mCodec->mNativeWindow->queueBuffer(
@@ -3738,7 +3739,7 @@
                 }
 
                 if (info != NULL) {
-                    ALOGV("[%s] calling fillBuffer %p",
+                    ALOGV("[%s] calling fillBuffer %u",
                          mCodec->mComponentName.c_str(), info->mBufferID);
 
                     CHECK_EQ(mCodec->mOMX->fillBuffer(mCodec->mNode, info->mBufferID),
@@ -5011,7 +5012,7 @@
         {
             sp<AMessage> msg = new AMessage(kWhatOMXMessage, mCodec->id());
             msg->setInt32("type", omx_message::EVENT);
-            msg->setPointer("node", mCodec->mNode);
+            msg->setInt32("node", mCodec->mNode);
             msg->setInt32("event", event);
             msg->setInt32("data1", data1);
             msg->setInt32("data2", data2);
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 5b525f2..b9c5904 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1555,8 +1555,8 @@
         int32_t portIndex, const sp<AMessage> &msg) {
     CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
 
-    void *bufferID;
-    CHECK(msg->findPointer("buffer-id", &bufferID));
+    uint32_t bufferID;
+    CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
 
     Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
 
@@ -1728,7 +1728,7 @@
             // API 20.  Perhaps check for target SDK version.
 #if 0
             if (info->mData->meta()->findInt64("timeUs", &timestampNs)) {
-                ALOGI("using buffer PTS of %" PRId64, timestampNs);
+                ALOGV("using buffer PTS of %" PRId64, timestampNs);
                 timestampNs *= 1000;
             }
 #endif
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index 9f9352d..aca21cf 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -16,6 +16,11 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "OMXClient"
+
+#ifdef __LP64__
+#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+#endif
+
 #include <utils/Log.h>
 
 #include <binder/IServiceManager.h>
@@ -141,7 +146,7 @@
     const sp<IOMX> &getOMX(node_id node) const;
     const sp<IOMX> &getOMX_l(node_id node) const;
 
-    static bool IsSoftwareComponent(const char *name);
+    static bool CanLiveLocally(const char *name);
 
     DISALLOW_EVIL_CONSTRUCTORS(MuxOMX);
 };
@@ -164,8 +169,15 @@
 }
 
 // static
-bool MuxOMX::IsSoftwareComponent(const char *name) {
+bool MuxOMX::CanLiveLocally(const char *name) {
+#ifdef __LP64__
+    (void)name; // disable unused parameter warning
+    // 64 bit processes always run OMX remote on MediaServer
+    return false;
+#else
+    // 32 bit processes run only OMX.google.* components locally
     return !strncasecmp(name, "OMX.google.", 11);
+#endif
 }
 
 const sp<IOMX> &MuxOMX::getOMX(node_id node) const {
@@ -197,7 +209,7 @@
 
     sp<IOMX> omx;
 
-    if (IsSoftwareComponent(name)) {
+    if (CanLiveLocally(name)) {
         if (mLocalOMX == NULL) {
             mLocalOMX = new OMX;
         }
@@ -382,7 +394,7 @@
     mOMX = service->getOMX();
     CHECK(mOMX.get() != NULL);
 
-    if (!mOMX->livesLocally(NULL /* node */, getpid())) {
+    if (!mOMX->livesLocally(0 /* node */, getpid())) {
         ALOGI("Using client-side OMX mux.");
         mOMX = new MuxOMX(mOMX);
     }
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 9a7f3db..c028dbf 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -18,6 +18,11 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "OMXCodec"
+
+#ifdef __LP64__
+#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+#endif
+
 #include <utils/Log.h>
 
 #include "include/AACEncoder.h"
@@ -130,6 +135,7 @@
 
 template<class T>
 static void InitOMXParams(T *params) {
+    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(sizeof(OMX_PTR) == 4); // check OMX_PTR is 4 bytes.
     params->nSize = sizeof(T);
     params->nVersion.s.nVersionMajor = 1;
     params->nVersion.s.nVersionMinor = 0;
@@ -689,7 +695,7 @@
         // CHECK_EQ(format.nIndex, index);
 
 #if 1
-        CODEC_LOGV("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
+        CODEC_LOGV("portIndex: %u, index: %u, eCompressionFormat=%d eColorFormat=%d",
              portIndex,
              index, format.eCompressionFormat, format.eColorFormat);
 #endif
@@ -791,7 +797,7 @@
         portFormat.nIndex = index;
 
         if (index >= kMaxColorFormatSupported) {
-            CODEC_LOGE("More than %ld color formats are supported???", index);
+            CODEC_LOGE("More than %u color formats are supported???", index);
             break;
         }
     }
@@ -1833,7 +1839,7 @@
             break;
         }
 
-        CODEC_LOGW("setting nBufferCountActual to %lu failed: %d",
+        CODEC_LOGW("setting nBufferCountActual to %u failed: %d",
                 newBufferCount, err);
         /* exit condition */
         if (extraBuffers == 0) {
@@ -1851,7 +1857,7 @@
         return err;
     }
 
-    CODEC_LOGV("allocating %lu buffers from a native window of size %lu on "
+    CODEC_LOGV("allocating %u buffers from a native window of size %u on "
             "output port", def.nBufferCountActual, def.nBufferSize);
 
     // Dequeue buffers and send them to OMX
@@ -1884,7 +1890,7 @@
 
         mPortBuffers[kPortIndexOutput].editItemAt(i).mBuffer = bufferId;
 
-        CODEC_LOGV("registered graphic buffer with ID %p (pointer = %p)",
+        CODEC_LOGV("registered graphic buffer with ID %u (pointer = %p)",
                 bufferId, graphicBuffer.get());
     }
 
@@ -1911,7 +1917,7 @@
 
 status_t OMXCodec::cancelBufferToNativeWindow(BufferInfo *info) {
     CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US);
-    CODEC_LOGV("Calling cancelBuffer on buffer %p", info->mBuffer);
+    CODEC_LOGV("Calling cancelBuffer on buffer %u", info->mBuffer);
     int err = mNativeWindow->cancelBuffer(
         mNativeWindow.get(), info->mMediaBuffer->graphicBuffer().get(), -1);
     if (err != 0) {
@@ -2149,7 +2155,7 @@
         {
             IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
 
-            CODEC_LOGV("EMPTY_BUFFER_DONE(buffer: %p)", buffer);
+            CODEC_LOGV("EMPTY_BUFFER_DONE(buffer: %u)", buffer);
 
             Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
             size_t i = 0;
@@ -2159,7 +2165,7 @@
 
             CHECK(i < buffers->size());
             if ((*buffers)[i].mStatus != OWNED_BY_COMPONENT) {
-                ALOGW("We already own input buffer %p, yet received "
+                ALOGW("We already own input buffer %u, yet received "
                      "an EMPTY_BUFFER_DONE.", buffer);
             }
 
@@ -2173,7 +2179,7 @@
             }
 
             if (mPortStatus[kPortIndexInput] == DISABLING) {
-                CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
+                CODEC_LOGV("Port is disabled, freeing buffer %u", buffer);
 
                 status_t err = freeBuffer(kPortIndexInput, i);
                 CHECK_EQ(err, (status_t)OK);
@@ -2195,7 +2201,7 @@
             IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
             OMX_U32 flags = msg.u.extended_buffer_data.flags;
 
-            CODEC_LOGV("FILL_BUFFER_DONE(buffer: %p, size: %ld, flags: 0x%08lx, timestamp: %lld us (%.2f secs))",
+            CODEC_LOGV("FILL_BUFFER_DONE(buffer: %u, size: %u, flags: 0x%08x, timestamp: %lld us (%.2f secs))",
                  buffer,
                  msg.u.extended_buffer_data.range_length,
                  flags,
@@ -2212,14 +2218,14 @@
             BufferInfo *info = &buffers->editItemAt(i);
 
             if (info->mStatus != OWNED_BY_COMPONENT) {
-                ALOGW("We already own output buffer %p, yet received "
+                ALOGW("We already own output buffer %u, yet received "
                      "a FILL_BUFFER_DONE.", buffer);
             }
 
             info->mStatus = OWNED_BY_US;
 
             if (mPortStatus[kPortIndexOutput] == DISABLING) {
-                CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
+                CODEC_LOGV("Port is disabled, freeing buffer %u", buffer);
 
                 status_t err = freeBuffer(kPortIndexOutput, i);
                 CHECK_EQ(err, (status_t)OK);
@@ -2268,7 +2274,7 @@
                     buffer->meta_data()->setInt32(kKeyIsUnreadable, true);
                 }
 
-                buffer->meta_data()->setPointer(
+                buffer->meta_data()->setInt32(
                         kKeyBufferID,
                         msg.u.extended_buffer_data.buffer);
 
@@ -2410,7 +2416,7 @@
 
         case OMX_EventError:
         {
-            CODEC_LOGE("ERROR(0x%08lx, %ld)", data1, data2);
+            CODEC_LOGE("OMX_EventError(0x%08x, %u)", data1, data2);
 
             setState(ERROR);
             break;
@@ -2418,7 +2424,7 @@
 
         case OMX_EventPortSettingsChanged:
         {
-            CODEC_LOGV("OMX_EventPortSettingsChanged(port=%ld, data2=0x%08lx)",
+            CODEC_LOGV("OMX_EventPortSettingsChanged(port=%u, data2=0x%08x)",
                        data1, data2);
 
             if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
@@ -2458,7 +2464,7 @@
                         // The scale is in 16.16 format.
                         // scale 1.0 = 0x010000. When there is no
                         // need to change the display, skip it.
-                        ALOGV("Get OMX_IndexConfigScale: 0x%lx/0x%lx",
+                        ALOGV("Get OMX_IndexConfigScale: 0x%x/0x%x",
                                 scale.xWidth, scale.xHeight);
 
                         if (scale.xWidth != 0x010000) {
@@ -2492,7 +2498,7 @@
 
         default:
         {
-            CODEC_LOGV("EVENT(%d, %ld, %ld)", event, data1, data2);
+            CODEC_LOGV("EVENT(%d, %u, %u)", event, data1, data2);
             break;
         }
     }
@@ -2509,7 +2515,7 @@
         case OMX_CommandPortDisable:
         {
             OMX_U32 portIndex = data;
-            CODEC_LOGV("PORT_DISABLED(%ld)", portIndex);
+            CODEC_LOGV("PORT_DISABLED(%u)", portIndex);
 
             CHECK(mState == EXECUTING || mState == RECONFIGURING);
             CHECK_EQ((int)mPortStatus[portIndex], (int)DISABLING);
@@ -2533,7 +2539,7 @@
 
                 status_t err = enablePortAsync(portIndex);
                 if (err != OK) {
-                    CODEC_LOGE("enablePortAsync(%ld) failed (err = %d)", portIndex, err);
+                    CODEC_LOGE("enablePortAsync(%u) failed (err = %d)", portIndex, err);
                     setState(ERROR);
                 } else {
                     err = allocateBuffersOnPort(portIndex);
@@ -2554,7 +2560,7 @@
         case OMX_CommandPortEnable:
         {
             OMX_U32 portIndex = data;
-            CODEC_LOGV("PORT_ENABLED(%ld)", portIndex);
+            CODEC_LOGV("PORT_ENABLED(%u)", portIndex);
 
             CHECK(mState == EXECUTING || mState == RECONFIGURING);
             CHECK_EQ((int)mPortStatus[portIndex], (int)ENABLING);
@@ -2575,7 +2581,7 @@
         {
             OMX_U32 portIndex = data;
 
-            CODEC_LOGV("FLUSH_DONE(%ld)", portIndex);
+            CODEC_LOGV("FLUSH_DONE(%u)", portIndex);
 
             CHECK_EQ((int)mPortStatus[portIndex], (int)SHUTTING_DOWN);
             mPortStatus[portIndex] = ENABLED;
@@ -3893,7 +3899,7 @@
             return UNKNOWN_ERROR;
         }
 
-        CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
+        CODEC_LOGV("seeking to %" PRId64 " us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
 
         mSignalledEOS = false;
 
diff --git a/media/libstagefright/foundation/ANetworkSession.cpp b/media/libstagefright/foundation/ANetworkSession.cpp
index af5be70..4504c2b 100644
--- a/media/libstagefright/foundation/ANetworkSession.cpp
+++ b/media/libstagefright/foundation/ANetworkSession.cpp
@@ -623,7 +623,7 @@
     CHECK_EQ(mState, CONNECTED);
     CHECK(!mOutFragments.empty());
 
-    ssize_t n;
+    ssize_t n = -1;
     while (!mOutFragments.empty()) {
         const Fragment &frag = *mOutFragments.begin();
 
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index 31a5077..cd51bbf 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -134,10 +134,10 @@
             OMX_IN OMX_PTR pEventData);
 
     OMX_ERRORTYPE OnEmptyBufferDone(
-            node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
+            node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
 
     OMX_ERRORTYPE OnFillBufferDone(
-            node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
+            node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
 
     void invalidateNodeID(node_id node);
 
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index 339179e..3967dc6 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -138,12 +138,25 @@
         OMX::buffer_id mID;
     };
     Vector<ActiveBuffer> mActiveBuffers;
+#ifdef __LP64__
+    Mutex mBufferIDLock;
+    uint32_t mBufferIDCount;
+    KeyedVector<OMX::buffer_id, OMX_BUFFERHEADERTYPE *> mBufferIDToBufferHeader;
+    KeyedVector<OMX_BUFFERHEADERTYPE *, OMX::buffer_id> mBufferHeaderToBufferID;
+#endif
 
     ~OMXNodeInstance();
 
     void addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id);
     void removeActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id);
     void freeActiveBuffers();
+
+    // For buffer id management
+    OMX::buffer_id makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader);
+    OMX_BUFFERHEADERTYPE *findBufferHeader(OMX::buffer_id buffer);
+    OMX::buffer_id findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader);
+    void invalidateBufferID(OMX::buffer_id buffer);
+
     status_t useGraphicBuffer2_l(
             OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
             OMX::buffer_id *buffer);
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index b62d5f5..22b12d9 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -287,6 +287,7 @@
 status_t OMX::getParameter(
         node_id node, OMX_INDEXTYPE index,
         void *params, size_t size) {
+    ALOGV("getParameter(%u %#x %p %zd)", node, index, params, size);
     return findInstance(node)->getParameter(
             index, params, size);
 }
@@ -294,6 +295,7 @@
 status_t OMX::setParameter(
         node_id node, OMX_INDEXTYPE index,
         const void *params, size_t size) {
+    ALOGV("setParameter(%u %#x %p %zd)", node, index, params, size);
     return findInstance(node)->setParameter(
             index, params, size);
 }
@@ -445,13 +447,13 @@
 }
 
 OMX_ERRORTYPE OMX::OnEmptyBufferDone(
-        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
+        node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
     ALOGV("OnEmptyBufferDone buffer=%p", pBuffer);
 
     omx_message msg;
     msg.type = omx_message::EMPTY_BUFFER_DONE;
     msg.node = node;
-    msg.u.buffer_data.buffer = pBuffer;
+    msg.u.buffer_data.buffer = buffer;
 
     findDispatcher(node)->post(msg);
 
@@ -459,13 +461,13 @@
 }
 
 OMX_ERRORTYPE OMX::OnFillBufferDone(
-        node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
+        node_id node, buffer_id buffer, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
     ALOGV("OnFillBufferDone buffer=%p", pBuffer);
 
     omx_message msg;
     msg.type = omx_message::FILL_BUFFER_DONE;
     msg.node = node;
-    msg.u.extended_buffer_data.buffer = pBuffer;
+    msg.u.extended_buffer_data.buffer = buffer;
     msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
     msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
     msg.u.extended_buffer_data.flags = pBuffer->nFlags;
@@ -479,7 +481,7 @@
 OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
     // mLock is already held.
 
-    node_id node = (node_id)(uintptr_t)++mNodeCounter;
+    node_id node = (node_id)++mNodeCounter;
     mNodeIDToInstance.add(node, instance);
 
     return node;
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 0fb38fa..d6ab109 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -92,10 +92,14 @@
 OMXNodeInstance::OMXNodeInstance(
         OMX *owner, const sp<IOMXObserver> &observer)
     : mOwner(owner),
-      mNodeID(NULL),
+      mNodeID(0),
       mHandle(NULL),
       mObserver(observer),
-      mDying(false) {
+      mDying(false)
+#ifdef __LP64__
+      , mBufferIDCount(0)
+#endif
+{
 }
 
 OMXNodeInstance::~OMXNodeInstance() {
@@ -232,7 +236,7 @@
     }
 
     mOwner->invalidateNodeID(mNodeID);
-    mNodeID = NULL;
+    mNodeID = 0;
 
     ALOGV("OMXNodeInstance going away.");
     delete this;
@@ -270,7 +274,7 @@
     Mutex::Autolock autoLock(mLock);
 
     OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
-
+    ALOGE_IF(err != OMX_ErrorNone, "getParameter(%d) ERROR: %#x", index, err);
     return StatusFromOMXError(err);
 }
 
@@ -280,7 +284,7 @@
 
     OMX_ERRORTYPE err = OMX_SetParameter(
             mHandle, index, const_cast<void *>(params));
-
+    ALOGE_IF(err != OMX_ErrorNone, "setParameter(%d) ERROR: %#x", index, err);
     return StatusFromOMXError(err);
 }
 
@@ -482,7 +486,7 @@
 
     CHECK_EQ(header->pAppPrivate, buffer_meta);
 
-    *buffer = header;
+    *buffer = makeBufferID(header);
 
     addActiveBuffer(portIndex, *buffer);
 
@@ -538,7 +542,7 @@
     CHECK_EQ(header->pBuffer, bufferHandle);
     CHECK_EQ(header->pAppPrivate, bufferMeta);
 
-    *buffer = header;
+    *buffer = makeBufferID(header);
 
     addActiveBuffer(portIndex, *buffer);
 
@@ -602,7 +606,7 @@
 
     CHECK_EQ(header->pAppPrivate, bufferMeta);
 
-    *buffer = header;
+    *buffer = makeBufferID(header);
 
     addActiveBuffer(portIndex, *buffer);
 
@@ -614,7 +618,7 @@
         OMX::buffer_id buffer) {
     Mutex::Autolock autoLock(mLock);
 
-    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)(buffer);
+    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);
     VideoDecoderOutputMetaData *metadata =
         (VideoDecoderOutputMetaData *)(header->pBuffer);
     BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate);
@@ -710,7 +714,7 @@
 
     CHECK_EQ(header->pAppPrivate, buffer_meta);
 
-    *buffer = header;
+    *buffer = makeBufferID(header);
     *buffer_data = header->pBuffer;
 
     addActiveBuffer(portIndex, *buffer);
@@ -748,7 +752,7 @@
 
     CHECK_EQ(header->pAppPrivate, buffer_meta);
 
-    *buffer = header;
+    *buffer = makeBufferID(header);
 
     addActiveBuffer(portIndex, *buffer);
 
@@ -766,13 +770,14 @@
 
     removeActiveBuffer(portIndex, buffer);
 
-    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);
     BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
 
     OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
 
     delete buffer_meta;
     buffer_meta = NULL;
+    invalidateBufferID(buffer);
 
     return StatusFromOMXError(err);
 }
@@ -780,7 +785,7 @@
 status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {
     Mutex::Autolock autoLock(mLock);
 
-    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);
     header->nFilledLen = 0;
     header->nOffset = 0;
     header->nFlags = 0;
@@ -796,7 +801,7 @@
         OMX_U32 flags, OMX_TICKS timestamp) {
     Mutex::Autolock autoLock(mLock);
 
-    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);
     header->nFilledLen = rangeLength;
     header->nOffset = rangeOffset;
     header->nFlags = flags;
@@ -914,8 +919,7 @@
 
     if (msg.type == omx_message::FILL_BUFFER_DONE) {
         OMX_BUFFERHEADERTYPE *buffer =
-            static_cast<OMX_BUFFERHEADERTYPE *>(
-                    msg.u.extended_buffer_data.buffer);
+            findBufferHeader(msg.u.extended_buffer_data.buffer);
 
         BufferMeta *buffer_meta =
             static_cast<BufferMeta *>(buffer->pAppPrivate);
@@ -940,8 +944,7 @@
             // be very confused.
 
             OMX_BUFFERHEADERTYPE *buffer =
-                static_cast<OMX_BUFFERHEADERTYPE *>(
-                        msg.u.buffer_data.buffer);
+                findBufferHeader(msg.u.buffer_data.buffer);
 
             bufferSource->codecBufferEmptied(buffer);
             return;
@@ -1001,7 +1004,8 @@
     if (instance->mDying) {
         return OMX_ErrorNone;
     }
-    return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer);
+    return instance->owner()->OnEmptyBufferDone(instance->nodeID(),
+            instance->findBufferID(pBuffer), pBuffer);
 }
 
 // static
@@ -1013,7 +1017,8 @@
     if (instance->mDying) {
         return OMX_ErrorNone;
     }
-    return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer);
+    return instance->owner()->OnFillBufferDone(instance->nodeID(),
+            instance->findBufferID(pBuffer), pBuffer);
 }
 
 void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) {
@@ -1048,4 +1053,67 @@
     }
 }
 
+#ifdef __LP64__
+
+OMX::buffer_id OMXNodeInstance::makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
+    if (bufferHeader == NULL) {
+        return 0;
+    }
+    Mutex::Autolock autoLock(mBufferIDLock);
+    OMX::buffer_id buffer;
+    do { // handle the very unlikely case of ID overflow
+        if (++mBufferIDCount == 0) {
+           ++mBufferIDCount;
+        }
+        buffer = (OMX::buffer_id)mBufferIDCount;
+    } while (mBufferIDToBufferHeader.indexOfKey(buffer) >= 0);
+    mBufferIDToBufferHeader.add(buffer, bufferHeader);
+    mBufferHeaderToBufferID.add(bufferHeader, buffer);
+    return buffer;
+}
+
+OMX_BUFFERHEADERTYPE *OMXNodeInstance::findBufferHeader(OMX::buffer_id buffer) {
+    if (buffer == 0) {
+        return NULL;
+    }
+    Mutex::Autolock autoLock(mBufferIDLock);
+    return mBufferIDToBufferHeader.valueFor(buffer);
+}
+
+OMX::buffer_id OMXNodeInstance::findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
+    if (bufferHeader == NULL) {
+        return 0;
+    }
+    Mutex::Autolock autoLock(mBufferIDLock);
+    return mBufferHeaderToBufferID.valueFor(bufferHeader);
+}
+
+void OMXNodeInstance::invalidateBufferID(OMX::buffer_id buffer) {
+    if (buffer == 0) {
+        return;
+    }
+    Mutex::Autolock autoLock(mBufferIDLock);
+    mBufferHeaderToBufferID.removeItem(mBufferIDToBufferHeader.valueFor(buffer));
+    mBufferIDToBufferHeader.removeItem(buffer);
+}
+
+#else
+
+OMX::buffer_id OMXNodeInstance::makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
+    return (OMX::buffer_id)bufferHeader;
+}
+
+OMX_BUFFERHEADERTYPE *OMXNodeInstance::findBufferHeader(OMX::buffer_id buffer) {
+    return (OMX_BUFFERHEADERTYPE *)buffer;
+}
+
+OMX::buffer_id OMXNodeInstance::findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
+    return (OMX::buffer_id)bufferHeader;
+}
+
+void OMXNodeInstance::invalidateBufferID(OMX::buffer_id buffer __unused) {
+}
+
+#endif
+
 }  // namespace android
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index d3e546a..5bc3f2f 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -35,7 +35,8 @@
     frameworks/av/services/medialog \
     frameworks/av/services/audioflinger \
     frameworks/av/services/audiopolicy \
-    frameworks/av/services/camera/libcameraservice
+    frameworks/av/services/camera/libcameraservice \
+    $(call include-path-for, audio-utils)
 
 LOCAL_MODULE:= mediaserver
 LOCAL_32_BIT_ONLY := true
diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk
index 1f155f3..8f795cd 100644
--- a/media/ndk/Android.mk
+++ b/media/ndk/Android.mk
@@ -35,6 +35,8 @@
     frameworks/base/core/jni \
     frameworks/av/include/ndk
 
+LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))'
+
 LOCAL_SHARED_LIBRARIES := \
     libbinder \
     libmedia \
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index ac05920..9e2aa67 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -36,14 +36,14 @@
 using namespace android;
 
 
-static int translate_error(status_t err) {
+static media_status_t translate_error(status_t err) {
     if (err == OK) {
-        return OK;
+        return AMEDIA_OK;
     } else if (err == -EAGAIN) {
-        return AMEDIACODEC_INFO_TRY_AGAIN_LATER;
+        return (media_status_t) AMEDIACODEC_INFO_TRY_AGAIN_LATER;
     }
     ALOGE("sf error code: %d", err);
-    return AMEDIAERROR_GENERIC;
+    return AMEDIA_ERROR_UNKNOWN;
 }
 
 enum {
@@ -159,20 +159,23 @@
     return mData;
 }
 
-
+EXPORT
 AMediaCodec* AMediaCodec_createCodecByName(const char *name) {
     return createAMediaCodec(name, false, false);
 }
 
+EXPORT
 AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) {
     return createAMediaCodec(mime_type, true, false);
 }
 
+EXPORT
 AMediaCodec* AMediaCodec_createEncoderByType(const char *name) {
     return createAMediaCodec(name, true, true);
 }
 
-int AMediaCodec_delete(AMediaCodec *mData) {
+EXPORT
+media_status_t AMediaCodec_delete(AMediaCodec *mData) {
     if (mData->mCodec != NULL) {
         mData->mCodec->release();
         mData->mCodec.clear();
@@ -184,10 +187,11 @@
         mData->mLooper.clear();
     }
     delete mData;
-    return OK;
+    return AMEDIA_OK;
 }
 
-int AMediaCodec_configure(
+EXPORT
+media_status_t AMediaCodec_configure(
         AMediaCodec *mData,
         const AMediaFormat* format,
         ANativeWindow* window,
@@ -205,7 +209,8 @@
             crypto ? crypto->mCrypto : NULL, flags));
 }
 
-int AMediaCodec_start(AMediaCodec *mData) {
+EXPORT
+media_status_t AMediaCodec_start(AMediaCodec *mData) {
     status_t ret =  mData->mCodec->start();
     if (ret != OK) {
         return translate_error(ret);
@@ -213,11 +218,12 @@
     mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler->id());
     mData->mActivityNotification->setInt32("generation", mData->mGeneration);
     requestActivityNotification(mData);
-    return OK;
+    return AMEDIA_OK;
 }
 
-int AMediaCodec_stop(AMediaCodec *mData) {
-    int ret = translate_error(mData->mCodec->stop());
+EXPORT
+media_status_t AMediaCodec_stop(AMediaCodec *mData) {
+    media_status_t ret = translate_error(mData->mCodec->stop());
 
     sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler->id());
     sp<AMessage> response;
@@ -227,10 +233,12 @@
     return ret;
 }
 
-int AMediaCodec_flush(AMediaCodec *mData) {
+EXPORT
+media_status_t AMediaCodec_flush(AMediaCodec *mData) {
     return translate_error(mData->mCodec->flush());
 }
 
+EXPORT
 ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) {
     size_t idx;
     status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs);
@@ -241,6 +249,7 @@
     return translate_error(ret);
 }
 
+EXPORT
 uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
     android::Vector<android::sp<android::ABuffer> > abufs;
     if (mData->mCodec->getInputBuffers(&abufs) == 0) {
@@ -258,6 +267,7 @@
     return NULL;
 }
 
+EXPORT
 uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
     android::Vector<android::sp<android::ABuffer> > abufs;
     if (mData->mCodec->getOutputBuffers(&abufs) == 0) {
@@ -275,7 +285,8 @@
     return NULL;
 }
 
-int AMediaCodec_queueInputBuffer(AMediaCodec *mData,
+EXPORT
+media_status_t AMediaCodec_queueInputBuffer(AMediaCodec *mData,
         size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) {
 
     AString errorMsg;
@@ -283,6 +294,7 @@
     return translate_error(ret);
 }
 
+EXPORT
 ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData,
         AMediaCodecBufferInfo *info, int64_t timeoutUs) {
     size_t idx;
@@ -312,13 +324,15 @@
     return translate_error(ret);
 }
 
+EXPORT
 AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) {
     sp<AMessage> format;
     mData->mCodec->getOutputFormat(&format);
     return AMediaFormat_fromMsg(&format);
 }
 
-int AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) {
+EXPORT
+media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) {
     if (render) {
         return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx));
     } else {
@@ -326,10 +340,11 @@
     }
 }
 
-int AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) {
+EXPORT
+media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) {
     mData->mCallback = callback;
     mData->mCallbackUserData = userdata;
-    return OK;
+    return AMEDIA_OK;
 }
 
 typedef struct AMediaCodecCryptoInfo {
@@ -341,7 +356,8 @@
         size_t *encryptedbytes;
 } AMediaCodecCryptoInfo;
 
-int AMediaCodec_queueSecureInputBuffer(
+EXPORT
+media_status_t AMediaCodec_queueSecureInputBuffer(
         AMediaCodec* codec,
         size_t idx,
         off_t offset,
@@ -375,6 +391,7 @@
 
 
 
+EXPORT
 AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
         int numsubsamples,
         uint8_t key[16],
@@ -406,52 +423,71 @@
 }
 
 
-int AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
+EXPORT
+media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
     free(info);
-    return OK;
+    return AMEDIA_OK;
 }
 
+EXPORT
 size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) {
     return ci->numsubsamples;
 }
 
-int AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
-    if (!dst || !ci) {
-        return AMEDIAERROR_UNSUPPORTED;
+EXPORT
+media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
+    if (!ci) {
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+    if (!dst) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
     }
     memcpy(dst, ci->key, 16);
-    return OK;
+    return AMEDIA_OK;
 }
 
-int AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
-    if (!dst || !ci) {
-        return AMEDIAERROR_UNSUPPORTED;
+EXPORT
+media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
+    if (!ci) {
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+    if (!dst) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
     }
     memcpy(dst, ci->iv, 16);
-    return OK;
+    return AMEDIA_OK;
 }
 
+EXPORT
 uint32_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) {
     if (!ci) {
-        return AMEDIAERROR_UNSUPPORTED;
+        return AMEDIA_ERROR_INVALID_OBJECT;
     }
     return ci->mode;
 }
 
-int AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
-    if (!dst || !ci) {
-        return AMEDIAERROR_UNSUPPORTED;
+EXPORT
+media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
+    if (!ci) {
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+    if (!dst) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
     }
     memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples);
-    return OK;
+    return AMEDIA_OK;
 }
 
-int AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
-    if (!dst || !ci) {
-        return AMEDIAERROR_UNSUPPORTED;
+EXPORT
+media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
+    if (!ci) {
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+    if (!dst) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
     }
     memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples);
-    return OK;
+    return AMEDIA_OK;
 }
 
 } // extern "C"
diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp
index d57f42b..cbadea5 100644
--- a/media/ndk/NdkMediaCrypto.cpp
+++ b/media/ndk/NdkMediaCrypto.cpp
@@ -35,12 +35,12 @@
 
 using namespace android;
 
-static int translate_error(status_t err) {
+static media_status_t translate_error(status_t err) {
     if (err == OK) {
-        return OK;
+        return AMEDIA_OK;
     }
     ALOGE("sf error code: %d", err);
-    return -1000;
+    return AMEDIA_ERROR_UNKNOWN;
 }
 
 
@@ -74,6 +74,7 @@
 extern "C" {
 
 
+EXPORT
 bool AMediaCrypto_isCryptoSchemeSupported(const AMediaUUID uuid) {
     sp<ICrypto> crypto = makeCrypto();
     if (crypto == NULL) {
@@ -82,6 +83,7 @@
     return crypto->isCryptoSchemeSupported(uuid);
 }
 
+EXPORT
 bool AMediaCrypto_requiresSecureDecoderComponent(const char *mime) {
     sp<ICrypto> crypto = makeCrypto();
     if (crypto == NULL) {
@@ -90,6 +92,7 @@
     return crypto->requiresSecureDecoderComponent(mime);
 }
 
+EXPORT
 AMediaCrypto* AMediaCrypto_new(const AMediaUUID uuid, const void *data, size_t datasize) {
 
     sp<ICrypto> tmp = makeCrypto();
@@ -107,6 +110,7 @@
     return crypto;
 }
 
+EXPORT
 void AMediaCrypto_delete(AMediaCrypto* crypto) {
     delete crypto;
 }
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index c55cba2..f982275 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -35,10 +35,20 @@
 
 typedef Vector<uint8_t> idvec_t;
 
+struct DrmListener: virtual public BnDrmClient
+{
+private:
+    AMediaDrm *mObj;
+    AMediaDrmEventListener mListener;
+
+public:
+    DrmListener(AMediaDrm *obj, AMediaDrmEventListener listener) : mObj(obj), mListener(listener) {}
+    void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj);
+};
+
 struct AMediaDrm {
     sp<IDrm> mDrm;
     sp<IDrmClient> mDrmClient;
-    AMediaDrmEventListener mListener;
     List<idvec_t> mIds;
     KeyedVector<String8, String8> mQueryResults;
     Vector<uint8_t> mKeyRequest;
@@ -47,42 +57,90 @@
     String8 mPropertyString;
     Vector<uint8_t> mPropertyByteArray;
     List<Vector<uint8_t> > mSecureStops;
+    sp<DrmListener> mListener;
 };
 
+void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
+    if (!mListener) {
+        return;
+    }
+
+    AMediaDrmSessionId sessionId = {NULL, 0};
+    int32_t sessionIdSize = obj->readInt32();
+    if (sessionIdSize) {
+        uint8_t *sessionIdData = new uint8_t[sessionIdSize];
+        sessionId.ptr = sessionIdData;
+        sessionId.length = sessionIdSize;
+        obj->read(sessionIdData, sessionId.length);
+    }
+
+    int32_t dataSize = obj->readInt32();
+    uint8_t *data = NULL;
+    if (dataSize) {
+        data = new uint8_t[dataSize];
+        obj->read(data, dataSize);
+    }
+
+    // translate DrmPlugin event types into their NDK equivalents
+    AMediaDrmEventType ndkEventType;
+    switch(eventType) {
+        case DrmPlugin::kDrmPluginEventProvisionRequired:
+            ndkEventType = EVENT_PROVISION_REQUIRED;
+            break;
+        case DrmPlugin::kDrmPluginEventKeyNeeded:
+            ndkEventType = EVENT_KEY_REQUIRED;
+            break;
+        case DrmPlugin::kDrmPluginEventKeyExpired:
+            ndkEventType = EVENT_KEY_EXPIRED;
+            break;
+        case DrmPlugin::kDrmPluginEventVendorDefined:
+            ndkEventType = EVENT_VENDOR_DEFINED;
+            break;
+        default:
+            ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
+            return;
+    }
+
+    (*mListener)(mObj, sessionId, ndkEventType, extra, data, dataSize);
+
+    delete [] sessionId.ptr;
+    delete [] data;
+}
+
+
 extern "C" {
 
-static mediadrm_status_t translateStatus(status_t status) {
-    mediadrm_status_t result = MEDIADRM_UNKNOWN_ERROR;
+static media_status_t translateStatus(status_t status) {
+    media_status_t result = AMEDIA_ERROR_UNKNOWN;
     switch (status) {
         case OK:
-            result = MEDIADRM_OK;
+            result = AMEDIA_OK;
             break;
         case android::ERROR_DRM_NOT_PROVISIONED:
-            result = MEDIADRM_NOT_PROVISIONED_ERROR;
+            result = AMEDIA_DRM_NOT_PROVISIONED;
             break;
         case android::ERROR_DRM_RESOURCE_BUSY:
-            result = MEDIADRM_RESOURCE_BUSY_ERROR;
+            result = AMEDIA_DRM_RESOURCE_BUSY;
             break;
         case android::ERROR_DRM_DEVICE_REVOKED:
-            result = MEDIADRM_DEVICE_REVOKED_ERROR;
+            result = AMEDIA_DRM_DEVICE_REVOKED;
             break;
         case android::ERROR_DRM_CANNOT_HANDLE:
-            result = MEDIADRM_INVALID_PARAMETER_ERROR;
+            result = AMEDIA_ERROR_INVALID_PARAMETER;
             break;
         case android::ERROR_DRM_TAMPER_DETECTED:
-            result = MEDIADRM_TAMPER_DETECTED_ERROR;
+            result = AMEDIA_DRM_TAMPER_DETECTED;
             break;
         case android::ERROR_DRM_SESSION_NOT_OPENED:
-            result = MEDIADRM_SESSION_NOT_OPENED_ERROR;
+            result = AMEDIA_DRM_SESSION_NOT_OPENED;
             break;
         case android::ERROR_DRM_NO_LICENSE:
-            result = MEDIADRM_NEED_KEY_ERROR;
+            result = AMEDIA_DRM_NEED_KEY;
             break;
         case android::ERROR_DRM_LICENSE_EXPIRED:
-            result = MEDIADRM_LICENSE_EXPIRED_ERROR;
+            result = AMEDIA_DRM_LICENSE_EXPIRED;
             break;
         default:
-            result = MEDIADRM_UNKNOWN_ERROR;
             break;
     }
     return result;
@@ -127,6 +185,7 @@
     return drm;
 }
 
+EXPORT
 bool AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid, const char *mimeType) {
     sp<IDrm> drm = CreateDrm();
 
@@ -138,12 +197,14 @@
     return drm->isCryptoSchemeSupported(uuid, mimeStr);
 }
 
+EXPORT
 AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) {
     AMediaDrm *mObj = new AMediaDrm();
     mObj->mDrm = CreateDrmFromUUID(uuid);
     return mObj;
 }
 
+EXPORT
 void AMediaDrm_release(AMediaDrm *mObj) {
     if (mObj->mDrm != NULL) {
         mObj->mDrm->setListener(NULL);
@@ -153,11 +214,15 @@
     delete mObj;
 }
 
-#if 0
-void AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) {
-    mObj->mListener = listener;
+EXPORT
+media_status_t AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) {
+    if (!mObj || mObj->mDrm == NULL) {
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+    mObj->mListener = new DrmListener(mObj, listener);
+    mObj->mDrm->setListener(mObj->mListener);
+    return AMEDIA_OK;
 }
-#endif
 
 
 static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) {
@@ -170,9 +235,10 @@
     return false;
 }
 
-mediadrm_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId &sessionId) {
+EXPORT
+media_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId &sessionId) {
     if (!mObj || mObj->mDrm == NULL) {
-        return MEDIADRM_INVALID_OBJECT_ERROR;
+        return AMEDIA_ERROR_INVALID_OBJECT;
     }
     Vector<uint8_t> session;
     status_t status = mObj->mDrm->openSession(session);
@@ -182,38 +248,40 @@
         sessionId.ptr = iter->array();
         sessionId.length = iter->size();
     }
-    return MEDIADRM_OK;
+    return AMEDIA_OK;
 }
 
-mediadrm_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId) {
+EXPORT
+media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId) {
     if (!mObj || mObj->mDrm == NULL) {
-        return MEDIADRM_INVALID_OBJECT_ERROR;
+        return AMEDIA_ERROR_INVALID_OBJECT;
     }
 
     List<idvec_t>::iterator iter;
     if (!findId(mObj, sessionId, iter)) {
-        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
+        return AMEDIA_DRM_SESSION_NOT_OPENED;
     }
     mObj->mDrm->closeSession(*iter);
     mObj->mIds.erase(iter);
-    return MEDIADRM_OK;
+    return AMEDIA_OK;
 }
 
-mediadrm_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope &scope,
+EXPORT
+media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope &scope,
         const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
         const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
         const uint8_t *&keyRequest, size_t &keyRequestSize) {
 
     if (!mObj || mObj->mDrm == NULL) {
-        return MEDIADRM_INVALID_OBJECT_ERROR;
+        return AMEDIA_ERROR_INVALID_OBJECT;
     }
     if (!mimeType) {
-        return MEDIADRM_INVALID_PARAMETER_ERROR;
+        return AMEDIA_ERROR_INVALID_PARAMETER;
     }
 
     List<idvec_t>::iterator iter;
     if (!findId(mObj, scope, iter)) {
-        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
+        return AMEDIA_DRM_SESSION_NOT_OPENED;
     }
 
     Vector<uint8_t> mdInit;
@@ -230,7 +298,7 @@
             mdKeyType = DrmPlugin::kKeyType_Release;
             break;
         default:
-            return MEDIADRM_INVALID_PARAMETER_ERROR;
+            return AMEDIA_ERROR_INVALID_PARAMETER;
     }
     KeyedVector<String8, String8> mdOptionalParameters;
     for (size_t i = 0; i < numOptionalParameters; i++) {
@@ -246,22 +314,23 @@
         keyRequest = mObj->mKeyRequest.array();
         keyRequestSize = mObj->mKeyRequest.size();
     }
-    return MEDIADRM_OK;
+    return AMEDIA_OK;
 }
 
-mediadrm_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope &scope,
+EXPORT
+media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope &scope,
         const uint8_t *response, size_t responseSize, AMediaDrmKeySetId &keySetId) {
 
     if (!mObj || mObj->mDrm == NULL) {
-        return MEDIADRM_INVALID_OBJECT_ERROR;
+        return AMEDIA_ERROR_INVALID_OBJECT;
     }
     if (!response || !responseSize) {
-        return MEDIADRM_INVALID_PARAMETER_ERROR;
+        return AMEDIA_ERROR_INVALID_PARAMETER;
     }
 
     List<idvec_t>::iterator iter;
     if (!findId(mObj, scope, iter)) {
-        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
+        return AMEDIA_DRM_SESSION_NOT_OPENED;
     }
     Vector<uint8_t> mdResponse;
     mdResponse.appendArray(response, responseSize);
@@ -277,27 +346,29 @@
         keySetId.ptr = NULL;
         keySetId.length = 0;
     }
-    return MEDIADRM_OK;
+    return AMEDIA_OK;
 }
 
-mediadrm_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
+EXPORT
+media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
         const AMediaDrmKeySetId &keySetId) {
 
     if (!mObj || mObj->mDrm == NULL) {
-        return MEDIADRM_INVALID_OBJECT_ERROR;
+        return AMEDIA_ERROR_INVALID_OBJECT;
     }
     List<idvec_t>::iterator iter;
     if (!findId(mObj, sessionId, iter)) {
-        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
+        return AMEDIA_DRM_SESSION_NOT_OPENED;
     }
     Vector<uint8_t> keySet;
     keySet.appendArray(keySetId.ptr, keySetId.length);
     return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet));
 }
 
-mediadrm_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId &keySetId) {
+EXPORT
+media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId &keySetId) {
     if (!mObj || mObj->mDrm == NULL) {
-        return MEDIADRM_INVALID_OBJECT_ERROR;
+        return AMEDIA_ERROR_INVALID_OBJECT;
     }
     List<idvec_t>::iterator iter;
     status_t status;
@@ -312,15 +383,16 @@
     return translateStatus(status);
 }
 
-mediadrm_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
+EXPORT
+media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
         AMediaDrmKeyValue *keyValuePairs, size_t &numPairs) {
 
     if (!mObj || mObj->mDrm == NULL) {
-        return MEDIADRM_INVALID_OBJECT_ERROR;
+        return AMEDIA_ERROR_INVALID_OBJECT;
     }
     List<idvec_t>::iterator iter;
     if (!findId(mObj, sessionId, iter)) {
-        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
+        return AMEDIA_DRM_SESSION_NOT_OPENED;
     }
 
     status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults);
@@ -331,7 +403,7 @@
 
     if (mObj->mQueryResults.size() > numPairs) {
         numPairs = mObj->mQueryResults.size();
-        return MEDIADRM_SHORT_BUFFER;
+        return AMEDIA_DRM_SHORT_BUFFER;
     }
 
     for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
@@ -339,16 +411,17 @@
         keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string();
     }
     numPairs = mObj->mQueryResults.size();
-    return MEDIADRM_OK;
+    return AMEDIA_OK;
 }
 
-mediadrm_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t *&provisionRequest,
+EXPORT
+media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t *&provisionRequest,
         size_t &provisionRequestSize, const char *&serverUrl) {
     if (!mObj || mObj->mDrm == NULL) {
-        return MEDIADRM_INVALID_OBJECT_ERROR;
+        return AMEDIA_ERROR_INVALID_OBJECT;
     }
     if (!provisionRequestSize || !serverUrl) {
-        return MEDIADRM_INVALID_PARAMETER_ERROR;
+        return AMEDIA_ERROR_INVALID_PARAMETER;
     }
 
     status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""),
@@ -360,16 +433,17 @@
         provisionRequestSize = mObj->mProvisionRequest.size();
         serverUrl = mObj->mProvisionUrl.string();
     }
-    return MEDIADRM_OK;
+    return AMEDIA_OK;
 }
 
-mediadrm_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj,
+EXPORT
+media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj,
         const uint8_t *response, size_t responseSize) {
     if (!mObj || mObj->mDrm == NULL) {
-        return MEDIADRM_INVALID_OBJECT_ERROR;
+        return AMEDIA_ERROR_INVALID_OBJECT;
     }
     if (!response || !responseSize) {
-        return MEDIADRM_INVALID_PARAMETER_ERROR;
+        return AMEDIA_ERROR_INVALID_PARAMETER;
     }
 
     Vector<uint8_t> mdResponse;
@@ -379,11 +453,12 @@
     return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused));
 }
 
-mediadrm_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj,
+EXPORT
+media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj,
         AMediaDrmSecureStop *secureStops, size_t &numSecureStops) {
 
     if (!mObj || mObj->mDrm == NULL) {
-        return MEDIADRM_INVALID_OBJECT_ERROR;
+        return AMEDIA_ERROR_INVALID_OBJECT;
     }
     status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops);
     if (status != OK) {
@@ -391,7 +466,7 @@
         return translateStatus(status);
     }
     if (numSecureStops < mObj->mSecureStops.size()) {
-        return MEDIADRM_SHORT_BUFFER;
+        return AMEDIA_DRM_SHORT_BUFFER;
     }
     List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin();
     size_t i = 0;
@@ -402,14 +477,15 @@
         ++i;
     }
     numSecureStops = mObj->mSecureStops.size();
-    return MEDIADRM_OK;
+    return AMEDIA_OK;
 }
 
-mediadrm_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj,
+EXPORT
+media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj,
         const AMediaDrmSecureStop &ssRelease) {
 
     if (!mObj || mObj->mDrm == NULL) {
-        return MEDIADRM_INVALID_OBJECT_ERROR;
+        return AMEDIA_ERROR_INVALID_OBJECT;
     }
 
     Vector<uint8_t> release;
@@ -418,11 +494,12 @@
 }
 
 
-mediadrm_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName,
+EXPORT
+media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName,
         const char *&propertyValue) {
 
     if (!mObj || mObj->mDrm == NULL) {
-        return MEDIADRM_INVALID_OBJECT_ERROR;
+        return AMEDIA_ERROR_INVALID_OBJECT;
     }
 
     status_t status = mObj->mDrm->getPropertyString(String8(propertyName),
@@ -436,10 +513,11 @@
     return translateStatus(status);
 }
 
-mediadrm_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj,
+EXPORT
+media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj,
         const char *propertyName, AMediaDrmByteArray &propertyValue) {
     if (!mObj || mObj->mDrm == NULL) {
-        return MEDIADRM_INVALID_OBJECT_ERROR;
+        return AMEDIA_ERROR_INVALID_OBJECT;
     }
 
     status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName),
@@ -455,17 +533,19 @@
     return translateStatus(status);
 }
 
-mediadrm_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj,
+EXPORT
+media_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj,
         const char *propertyName, const char *value) {
     if (!mObj || mObj->mDrm == NULL) {
-        return MEDIADRM_INVALID_OBJECT_ERROR;
+        return AMEDIA_ERROR_INVALID_OBJECT;
     }
 
     return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName),
                     String8(value)));
 }
 
-mediadrm_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj,
+EXPORT
+media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj,
         const char *propertyName, const uint8_t *value, size_t valueSize) {
 
     Vector<uint8_t> byteArray;
@@ -476,17 +556,17 @@
 }
 
 
-static mediadrm_status_t encrypt_decrypt_common(AMediaDrm *mObj,
+static media_status_t encrypt_decrypt_common(AMediaDrm *mObj,
         const AMediaDrmSessionId &sessionId,
         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
         const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) {
 
     if (!mObj || mObj->mDrm == NULL) {
-        return MEDIADRM_INVALID_OBJECT_ERROR;
+        return AMEDIA_ERROR_INVALID_OBJECT;
     }
     List<idvec_t>::iterator iter;
     if (!findId(mObj, sessionId, iter)) {
-        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
+        return AMEDIA_DRM_SESSION_NOT_OPENED;
     }
 
     status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm));
@@ -517,30 +597,33 @@
     return translateStatus(status);
 }
 
-mediadrm_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
+EXPORT
+media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
         const uint8_t *input, uint8_t *output, size_t dataSize) {
     return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv,
             input, output, dataSize, true);
 }
 
-mediadrm_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
+EXPORT
+media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
         const uint8_t *input, uint8_t *output, size_t dataSize) {
     return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv,
             input, output, dataSize, false);
 }
 
-mediadrm_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
+EXPORT
+media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
         const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
         uint8_t *signature, size_t *signatureSize) {
 
     if (!mObj || mObj->mDrm == NULL) {
-        return MEDIADRM_INVALID_OBJECT_ERROR;
+        return AMEDIA_ERROR_INVALID_OBJECT;
     }
     List<idvec_t>::iterator iter;
     if (!findId(mObj, sessionId, iter)) {
-        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
+        return AMEDIA_DRM_SESSION_NOT_OPENED;
     }
 
     status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
@@ -558,7 +641,7 @@
     Vector<uint8_t> signatureVec;
     status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec);
     if (signatureVec.size() > *signatureSize) {
-        return MEDIADRM_SHORT_BUFFER;
+        return AMEDIA_DRM_SHORT_BUFFER;
     }
     if (status == OK) {
         memcpy(signature, signatureVec.array(), signatureVec.size());
@@ -566,16 +649,17 @@
     return translateStatus(status);
 }
 
-mediadrm_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
+EXPORT
+media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
         const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
         const uint8_t *signature, size_t signatureSize) {
 
     if (!mObj || mObj->mDrm == NULL) {
-        return MEDIADRM_INVALID_OBJECT_ERROR;
+        return AMEDIA_ERROR_INVALID_OBJECT;
     }
     List<idvec_t>::iterator iter;
     if (!findId(mObj, sessionId, iter)) {
-        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
+        return AMEDIA_DRM_SESSION_NOT_OPENED;
     }
 
     status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
@@ -596,7 +680,7 @@
     bool match;
     status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match);
     if (status == OK) {
-        return match ? MEDIADRM_OK : MEDIADRM_VERIFY_FAILED;
+        return match ? AMEDIA_OK : AMEDIA_DRM_VERIFY_FAILED;
     }
     return translateStatus(status);
 }
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index 0a66988..563358f 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -38,12 +38,12 @@
 
 using namespace android;
 
-static int translate_error(status_t err) {
+static media_status_t translate_error(status_t err) {
     if (err == OK) {
-        return OK;
+        return AMEDIA_OK;
     }
     ALOGE("sf error code: %d", err);
-    return AMEDIAERROR_GENERIC;
+    return AMEDIA_ERROR_UNKNOWN;
 }
 
 struct AMediaExtractor {
@@ -54,6 +54,7 @@
 
 extern "C" {
 
+EXPORT
 AMediaExtractor* AMediaExtractor_new() {
     ALOGV("ctor");
     AMediaExtractor *mData = new AMediaExtractor();
@@ -61,19 +62,21 @@
     return mData;
 }
 
-int AMediaExtractor_delete(AMediaExtractor *mData) {
+EXPORT
+media_status_t AMediaExtractor_delete(AMediaExtractor *mData) {
     ALOGV("dtor");
     delete mData;
-    return OK;
+    return AMEDIA_OK;
 }
 
-int AMediaExtractor_setDataSourceFd(AMediaExtractor *mData, int fd, off64_t offset, off64_t length) {
+EXPORT
+media_status_t AMediaExtractor_setDataSourceFd(AMediaExtractor *mData, int fd, off64_t offset, off64_t length) {
     ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
-    mData->mImpl->setDataSource(fd, offset, length);
-    return 0;
+    return translate_error(mData->mImpl->setDataSource(fd, offset, length));
 }
 
-int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) {
+EXPORT
+media_status_t AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) {
     ALOGV("setDataSource(%s)", location);
     // TODO: add header support
 
@@ -82,14 +85,14 @@
     if (env == NULL) {
         ALOGE("setDataSource(path) must be called from Java thread");
         env->ExceptionClear();
-        return AMEDIAERROR_UNSUPPORTED;
+        return AMEDIA_ERROR_UNSUPPORTED;
     }
 
     jclass mediahttpclass = env->FindClass("android/media/MediaHTTPService");
     if (mediahttpclass == NULL) {
         ALOGE("can't find MediaHttpService");
         env->ExceptionClear();
-        return AMEDIAERROR_UNSUPPORTED;
+        return AMEDIA_ERROR_UNSUPPORTED;
     }
 
     jmethodID mediaHttpCreateMethod = env->GetStaticMethodID(mediahttpclass,
@@ -97,7 +100,7 @@
     if (mediaHttpCreateMethod == NULL) {
         ALOGE("can't find method");
         env->ExceptionClear();
-        return AMEDIAERROR_UNSUPPORTED;
+        return AMEDIA_ERROR_UNSUPPORTED;
     }
 
     jstring jloc = env->NewStringUTF(location);
@@ -111,37 +114,43 @@
         httpService = interface_cast<IMediaHTTPService>(binder);
     }
 
-    mData->mImpl->setDataSource(httpService, location, NULL);
+    status_t err = mData->mImpl->setDataSource(httpService, location, NULL);
     env->ExceptionClear();
-    return OK;
+    return translate_error(err);
 }
 
-int AMediaExtractor_getTrackCount(AMediaExtractor *mData) {
+EXPORT
+size_t AMediaExtractor_getTrackCount(AMediaExtractor *mData) {
     return mData->mImpl->countTracks();
 }
 
+EXPORT
 AMediaFormat* AMediaExtractor_getTrackFormat(AMediaExtractor *mData, size_t idx) {
     sp<AMessage> format;
     mData->mImpl->getTrackFormat(idx, &format);
     return AMediaFormat_fromMsg(&format);
 }
 
-int AMediaExtractor_selectTrack(AMediaExtractor *mData, size_t idx) {
+EXPORT
+media_status_t AMediaExtractor_selectTrack(AMediaExtractor *mData, size_t idx) {
     ALOGV("selectTrack(%z)", idx);
     return translate_error(mData->mImpl->selectTrack(idx));
 }
 
-int AMediaExtractor_unselectTrack(AMediaExtractor *mData, size_t idx) {
+EXPORT
+media_status_t AMediaExtractor_unselectTrack(AMediaExtractor *mData, size_t idx) {
     ALOGV("unselectTrack(%z)", idx);
     return translate_error(mData->mImpl->unselectTrack(idx));
 }
 
+EXPORT
 bool AMediaExtractor_advance(AMediaExtractor *mData) {
     //ALOGV("advance");
     return mData->mImpl->advance();
 }
 
-int AMediaExtractor_readSampleData(AMediaExtractor *mData, uint8_t *buffer, size_t capacity) {
+EXPORT
+ssize_t AMediaExtractor_readSampleData(AMediaExtractor *mData, uint8_t *buffer, size_t capacity) {
     //ALOGV("readSampleData");
     sp<ABuffer> tmp = new ABuffer(buffer, capacity);
     if (mData->mImpl->readSampleData(tmp) == OK) {
@@ -150,7 +159,8 @@
     return -1;
 }
 
-int AMediaExtractor_getSampleFlags(AMediaExtractor *mData) {
+EXPORT
+uint32_t AMediaExtractor_getSampleFlags(AMediaExtractor *mData) {
     int sampleFlags = 0;
     sp<MetaData> meta;
     status_t err = mData->mImpl->getSampleMeta(&meta);
@@ -159,18 +169,19 @@
     }
     int32_t val;
     if (meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) {
-        sampleFlags |= NuMediaExtractor::SAMPLE_FLAG_SYNC;
+        sampleFlags |= AMEDIAEXTRACTOR_SAMPLE_FLAG_SYNC;
     }
 
     uint32_t type;
     const void *data;
     size_t size;
     if (meta->findData(kKeyEncryptedSizes, &type, &data, &size)) {
-        sampleFlags |= NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED;
+        sampleFlags |= AMEDIAEXTRACTOR_SAMPLE_FLAG_ENCRYPTED;
     }
     return sampleFlags;
 }
 
+EXPORT
 int AMediaExtractor_getSampleTrackIndex(AMediaExtractor *mData) {
     size_t idx;
     if (mData->mImpl->getSampleTrackIndex(&idx) != OK) {
@@ -179,6 +190,7 @@
     return idx;
 }
 
+EXPORT
 int64_t AMediaExtractor_getSampletime(AMediaExtractor *mData) {
     int64_t time;
     if (mData->mImpl->getSampleTime(&time) != OK) {
@@ -187,6 +199,7 @@
     return time;
 }
 
+EXPORT
 PsshInfo* AMediaExtractor_getPsshInfo(AMediaExtractor *ex) {
 
     if (ex->mPsshBuf != NULL) {
@@ -267,6 +280,7 @@
     return (PsshInfo*) ex->mPsshBuf->data();
 }
 
+EXPORT
 AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *ex) {
     sp<MetaData> meta;
     if(ex->mImpl->getSampleMeta(&meta) != 0) {
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index c08814f..77018ec 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -56,19 +56,22 @@
 /*
  * public function follow
  */
+EXPORT
 AMediaFormat *AMediaFormat_new() {
     ALOGV("ctor");
     sp<AMessage> msg = new AMessage();
     return AMediaFormat_fromMsg(&msg);
 }
 
-int AMediaFormat_delete(AMediaFormat *mData) {
+EXPORT
+media_status_t AMediaFormat_delete(AMediaFormat *mData) {
     ALOGV("dtor");
     delete mData;
-    return OK;
+    return AMEDIA_OK;
 }
 
 
+EXPORT
 const char* AMediaFormat_toString(AMediaFormat *mData) {
     sp<AMessage> f = mData->mFormat;
     String8 ret;
@@ -141,22 +144,27 @@
     return mData->mDebug.string();
 }
 
+EXPORT
 bool AMediaFormat_getInt32(AMediaFormat* format, const char *name, int32_t *out) {
     return format->mFormat->findInt32(name, out);
 }
 
+EXPORT
 bool AMediaFormat_getInt64(AMediaFormat* format, const char *name, int64_t *out) {
     return format->mFormat->findInt64(name, out);
 }
 
+EXPORT
 bool AMediaFormat_getFloat(AMediaFormat* format, const char *name, float *out) {
     return format->mFormat->findFloat(name, out);
 }
 
+EXPORT
 bool AMediaFormat_getSize(AMediaFormat* format, const char *name, size_t *out) {
     return format->mFormat->findSize(name, out);
 }
 
+EXPORT
 bool AMediaFormat_getBuffer(AMediaFormat* format, const char *name, void** data, size_t *outsize) {
     sp<ABuffer> buf;
     if (format->mFormat->findBuffer(name, &buf)) {
@@ -167,6 +175,7 @@
     return false;
 }
 
+EXPORT
 bool AMediaFormat_getString(AMediaFormat* mData, const char *name, const char **out) {
 
     for (size_t i = 0; i < mData->mStringCache.size(); i++) {
@@ -186,23 +195,28 @@
     return false;
 }
 
+EXPORT
 void AMediaFormat_setInt32(AMediaFormat* format, const char *name, int32_t value) {
     format->mFormat->setInt32(name, value);
 }
 
+EXPORT
 void AMediaFormat_setInt64(AMediaFormat* format, const char *name, int64_t value) {
     format->mFormat->setInt64(name, value);
 }
 
+EXPORT
 void AMediaFormat_setFloat(AMediaFormat* format, const char* name, float value) {
     format->mFormat->setFloat(name, value);
 }
 
+EXPORT
 void AMediaFormat_setString(AMediaFormat* format, const char* name, const char* value) {
     // AMessage::setString() makes a copy of the string
     format->mFormat->setString(name, value, strlen(value));
 }
 
+EXPORT
 void AMediaFormat_setBuffer(AMediaFormat* format, const char* name, void* data, size_t size) {
     // the ABuffer(void*, size_t) constructor doesn't take ownership of the data, so create
     // a new buffer and copy the data into it
@@ -214,30 +228,30 @@
 }
 
 
-const char* AMEDIAFORMAT_KEY_AAC_PROFILE = "aac-profile";
-const char* AMEDIAFORMAT_KEY_BIT_RATE = "bitrate";
-const char* AMEDIAFORMAT_KEY_CHANNEL_COUNT = "channel-count";
-const char* AMEDIAFORMAT_KEY_CHANNEL_MASK = "channel-mask";
-const char* AMEDIAFORMAT_KEY_COLOR_FORMAT = "color-format";
-const char* AMEDIAFORMAT_KEY_DURATION = "durationUs";
-const char* AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
-const char* AMEDIAFORMAT_KEY_FRAME_RATE = "frame-rate";
-const char* AMEDIAFORMAT_KEY_HEIGHT = "height";
-const char* AMEDIAFORMAT_KEY_IS_ADTS = "is-adts";
-const char* AMEDIAFORMAT_KEY_IS_AUTOSELECT = "is-autoselect";
-const char* AMEDIAFORMAT_KEY_IS_DEFAULT = "is-default";
-const char* AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
-const char* AMEDIAFORMAT_KEY_I_FRAME_INTERVAL = "i-frame-interval";
-const char* AMEDIAFORMAT_KEY_LANGUAGE = "language";
-const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height";
-const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size";
-const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width";
-const char* AMEDIAFORMAT_KEY_MIME = "mime";
-const char* AMEDIAFORMAT_KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown";
-const char* AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after";
-const char* AMEDIAFORMAT_KEY_SAMPLE_RATE = "sample-rate";
-const char* AMEDIAFORMAT_KEY_WIDTH = "width";
-const char* AMEDIAFORMAT_KEY_STRIDE = "stride";
+EXPORT const char* AMEDIAFORMAT_KEY_AAC_PROFILE = "aac-profile";
+EXPORT const char* AMEDIAFORMAT_KEY_BIT_RATE = "bitrate";
+EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_COUNT = "channel-count";
+EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_MASK = "channel-mask";
+EXPORT const char* AMEDIAFORMAT_KEY_COLOR_FORMAT = "color-format";
+EXPORT const char* AMEDIAFORMAT_KEY_DURATION = "durationUs";
+EXPORT const char* AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
+EXPORT const char* AMEDIAFORMAT_KEY_FRAME_RATE = "frame-rate";
+EXPORT const char* AMEDIAFORMAT_KEY_HEIGHT = "height";
+EXPORT const char* AMEDIAFORMAT_KEY_IS_ADTS = "is-adts";
+EXPORT const char* AMEDIAFORMAT_KEY_IS_AUTOSELECT = "is-autoselect";
+EXPORT const char* AMEDIAFORMAT_KEY_IS_DEFAULT = "is-default";
+EXPORT const char* AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
+EXPORT const char* AMEDIAFORMAT_KEY_I_FRAME_INTERVAL = "i-frame-interval";
+EXPORT const char* AMEDIAFORMAT_KEY_LANGUAGE = "language";
+EXPORT const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height";
+EXPORT const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size";
+EXPORT const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width";
+EXPORT const char* AMEDIAFORMAT_KEY_MIME = "mime";
+EXPORT const char* AMEDIAFORMAT_KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown";
+EXPORT const char* AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after";
+EXPORT const char* AMEDIAFORMAT_KEY_SAMPLE_RATE = "sample-rate";
+EXPORT const char* AMEDIAFORMAT_KEY_WIDTH = "width";
+EXPORT const char* AMEDIAFORMAT_KEY_STRIDE = "stride";
 
 
 } // extern "C"
diff --git a/media/ndk/NdkMediaMuxer.cpp b/media/ndk/NdkMediaMuxer.cpp
index 98129cb..19b9fc4 100644
--- a/media/ndk/NdkMediaMuxer.cpp
+++ b/media/ndk/NdkMediaMuxer.cpp
@@ -37,12 +37,12 @@
 
 using namespace android;
 
-static int translate_error(status_t err) {
+static media_status_t translate_error(status_t err) {
     if (err == OK) {
-        return OK;
+        return AMEDIA_OK;
     }
     ALOGE("sf error code: %d", err);
-    return -1000;
+    return AMEDIA_ERROR_UNKNOWN;
 }
 
 struct AMediaMuxer {
@@ -52,6 +52,7 @@
 
 extern "C" {
 
+EXPORT
 AMediaMuxer* AMediaMuxer_new(int fd, OutputFormat format) {
     ALOGV("ctor");
     AMediaMuxer *mData = new AMediaMuxer();
@@ -59,35 +60,42 @@
     return mData;
 }
 
-int AMediaMuxer_delete(AMediaMuxer *muxer) {
+EXPORT
+media_status_t AMediaMuxer_delete(AMediaMuxer *muxer) {
     ALOGV("dtor");
     delete muxer;
-    return OK;
+    return AMEDIA_OK;
 }
 
-int AMediaMuxer_setLocation(AMediaMuxer *muxer, float latitude, float longtitude) {
+EXPORT
+media_status_t AMediaMuxer_setLocation(AMediaMuxer *muxer, float latitude, float longtitude) {
     return translate_error(muxer->mImpl->setLocation(latitude * 10000, longtitude * 10000));
 }
 
-int AMediaMuxer_setOrientationHint(AMediaMuxer *muxer, int degrees) {
+EXPORT
+media_status_t AMediaMuxer_setOrientationHint(AMediaMuxer *muxer, int degrees) {
     return translate_error(muxer->mImpl->setOrientationHint(degrees));
 }
 
+EXPORT
 ssize_t AMediaMuxer_addTrack(AMediaMuxer *muxer, const AMediaFormat *format) {
     sp<AMessage> msg;
     AMediaFormat_getFormat(format, &msg);
     return translate_error(muxer->mImpl->addTrack(msg));
 }
 
-int AMediaMuxer_start(AMediaMuxer *muxer) {
+EXPORT
+media_status_t AMediaMuxer_start(AMediaMuxer *muxer) {
     return translate_error(muxer->mImpl->start());
 }
 
-int AMediaMuxer_stop(AMediaMuxer *muxer) {
+EXPORT
+media_status_t AMediaMuxer_stop(AMediaMuxer *muxer) {
     return translate_error(muxer->mImpl->stop());
 }
 
-int AMediaMuxer_writeSampleData(AMediaMuxer *muxer,
+EXPORT
+media_status_t AMediaMuxer_writeSampleData(AMediaMuxer *muxer,
         size_t trackIdx, const uint8_t *data, const AMediaCodecBufferInfo &info) {
     sp<ABuffer> buf = new ABuffer((void*)(data + info.offset), info.size);
     return translate_error(
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 11170c2..45e17f8 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1837,7 +1837,8 @@
     if (status == BAD_VALUE &&
         reqFormat == config.format && config.format == AUDIO_FORMAT_PCM_16_BIT &&
         (config.sample_rate <= 2 * reqSamplingRate) &&
-        (popcount(config.channel_mask) <= FCC_2) && (popcount(reqChannelMask) <= FCC_2)) {
+        (audio_channel_count_from_in_mask(config.channel_mask) <= FCC_2) &&
+        (audio_channel_count_from_in_mask(reqChannelMask) <= FCC_2)) {
         // FIXME describe the change proposed by HAL (save old values so we can log them here)
         ALOGV("openInput() reopening with proposed sampling rate and channel mask");
         inStream = NULL;
@@ -1857,7 +1858,8 @@
             TEE_SINK_OLD,   // copy input using an existing pipe
         } kind;
         NBAIO_Format format = Format_from_SR_C(inStream->common.get_sample_rate(&inStream->common),
-                                        popcount(inStream->common.get_channels(&inStream->common)));
+                audio_channel_count_from_in_mask(
+                        inStream->common.get_channels(&inStream->common)));
         if (!mTeeSinkInputEnabled) {
             kind = TEE_SINK_NO;
         } else if (!Format_isValid(format)) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index d69d6a2..d2ded9a 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -82,9 +82,6 @@
 
 static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3);
 
-#define MAX_GAIN 4096.0f
-#define MAX_GAIN_INT 0x1000
-
 #define INCLUDING_FROM_AUDIOFLINGER_H
 
 class AudioFlinger :
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 2d67efb..d32f4d1 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -215,7 +215,7 @@
 
 status_t AudioMixer::initTrackDownmix(track_t* pTrack, int trackNum, audio_channel_mask_t mask)
 {
-    uint32_t channelCount = popcount(mask);
+    uint32_t channelCount = audio_channel_count_from_out_mask(mask);
     ALOG_ASSERT((channelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX) && channelCount);
     status_t status = OK;
     if (channelCount > MAX_NUM_CHANNELS) {
@@ -410,7 +410,7 @@
             audio_channel_mask_t mask =
                 static_cast<audio_channel_mask_t>(reinterpret_cast<uintptr_t>(value));
             if (track.channelMask != mask) {
-                uint32_t channelCount = popcount(mask);
+                uint32_t channelCount = audio_channel_count_from_out_mask(mask);
                 ALOG_ASSERT((channelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX) && channelCount);
                 track.channelMask = mask;
                 track.channelCount = channelCount;
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index e5e120c..09e63a6 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -30,6 +30,9 @@
 #include <system/audio.h>
 #include <media/nbaio/NBLog.h>
 
+// FIXME This is actually unity gain, which might not be max in future, expressed in U.12
+#define MAX_GAIN_INT AudioMixer::UNITY_GAIN
+
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -91,6 +94,7 @@
         REMOVE          = 0x4102, // Remove the sample rate converter on this track name;
                                   // the track is restored to the mix sample rate.
         // for target RAMP_VOLUME and VOLUME (8 channels max)
+        // FIXME use float for these 3 to improve the dynamic range
         VOLUME0         = 0x4200,
         VOLUME1         = 0x4201,
         AUXLEVEL        = 0x4210,
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index ccc4825..4170fd4 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -270,6 +270,7 @@
     sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor);
     sp<EffectModule> getEffectFromId_l(int id);
     sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type);
+    // FIXME use float to improve the dynamic range
     bool setVolume_l(uint32_t *left, uint32_t *right);
     void setDevice_l(audio_devices_t device);
     void setMode_l(audio_mode_t mode);
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 5cb42cc..42ba791 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -257,9 +257,9 @@
                     mixer->setBufferProvider(name, bufferProvider);
                     if (fastTrack->mVolumeProvider == NULL) {
                         mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0,
-                                (void *)0x1000);
+                                (void *) MAX_GAIN_INT);
                         mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1,
-                                (void *)0x1000);
+                                (void *) MAX_GAIN_INT);
                     }
                     mixer->setParameter(name, AudioMixer::RESAMPLE,
                             AudioMixer::REMOVE, NULL);
@@ -312,11 +312,13 @@
             int name = fastTrackNames[i];
             ALOG_ASSERT(name >= 0);
             if (fastTrack->mVolumeProvider != NULL) {
-                uint32_t vlr = fastTrack->mVolumeProvider->getVolumeLR();
+                gain_minifloat_packed_t vlr = fastTrack->mVolumeProvider->getVolumeLR();
                 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0,
-                        (void *)(uintptr_t)(vlr & 0xFFFF));
+                        (void *) (uintptr_t)
+                            (float_from_gain(gain_minifloat_unpack_left(vlr)) * MAX_GAIN_INT));
                 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1,
-                        (void *)(uintptr_t)(vlr >> 16));
+                        (void *) (uintptr_t)
+                            (float_from_gain(gain_minifloat_unpack_right(vlr)) * MAX_GAIN_INT));
             }
             // FIXME The current implementation of framesReady() for fast tracks
             // takes a tryLock, which can block
diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h
index be1a376..e388fb3 100644
--- a/services/audioflinger/FastMixerState.h
+++ b/services/audioflinger/FastMixerState.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_AUDIO_FAST_MIXER_STATE_H
 #define ANDROID_AUDIO_FAST_MIXER_STATE_H
 
+#include <audio_utils/minifloat.h>
 #include <system/audio.h>
 #include <media/ExtendedAudioBufferProvider.h>
 #include <media/nbaio/NBAIO.h>
@@ -29,9 +30,8 @@
 
 class VolumeProvider {
 public:
-    // Return the track volume in U4_12 format: left in lower half, right in upper half. The
-    // provider implementation is responsible for validating that the return value is in range.
-    virtual uint32_t getVolumeLR() = 0;
+    // The provider implementation is responsible for validating that the return value is in range.
+    virtual gain_minifloat_packed_t getVolumeLR() = 0;
 protected:
     VolumeProvider() { }
     virtual ~VolumeProvider() { }
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 08b1728..6f1f293 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -65,7 +65,7 @@
             void        signal();
 
 // implement FastMixerState::VolumeProvider interface
-    virtual uint32_t    getVolumeLR();
+    virtual gain_minifloat_packed_t getVolumeLR();
 
     virtual status_t    setSyncEvent(const sp<SyncEvent>& event);
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 2d4e025..ce08ff1 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -35,6 +35,7 @@
 #include <audio_effects/effect_aec.h>
 #include <audio_utils/primitives.h>
 #include <audio_utils/format.h>
+#include <audio_utils/minifloat.h>
 
 // NBAIO implementations
 #include <media/nbaio/AudioStreamOutSink.h>
@@ -1730,7 +1731,7 @@
         LOG_ALWAYS_FATAL("HAL channel mask %#x not supported for mixed output; "
                 "must be AUDIO_CHANNEL_OUT_STEREO", mChannelMask);
     }
-    mChannelCount = popcount(mChannelMask);
+    mChannelCount = audio_channel_count_from_out_mask(mChannelMask);
     mFormat = mOutput->stream->common.get_format(&mOutput->stream->common);
     if (!audio_is_valid_format(mFormat)) {
         LOG_ALWAYS_FATAL("HAL format %#x not valid for output", mFormat);
@@ -3255,21 +3256,23 @@
                 float typeVolume = mStreamTypes[track->streamType()].volume;
                 float v = masterVolume * typeVolume;
                 AudioTrackServerProxy *proxy = track->mAudioTrackServerProxy;
-                uint32_t vlr = proxy->getVolumeLR();
-                vl = vlr & 0xFFFF;
-                vr = vlr >> 16;
+                gain_minifloat_packed_t vlr = proxy->getVolumeLR();
+                float vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
+                float vrf = float_from_gain(gain_minifloat_unpack_right(vlr));
                 // track volumes come from shared memory, so can't be trusted and must be clamped
-                if (vl > MAX_GAIN_INT) {
-                    ALOGV("Track left volume out of range: %04X", vl);
-                    vl = MAX_GAIN_INT;
+                if (vlf > GAIN_FLOAT_UNITY) {
+                    ALOGV("Track left volume out of range: %.3g", vlf);
+                    vlf = GAIN_FLOAT_UNITY;
                 }
-                if (vr > MAX_GAIN_INT) {
-                    ALOGV("Track right volume out of range: %04X", vr);
-                    vr = MAX_GAIN_INT;
+                if (vrf > GAIN_FLOAT_UNITY) {
+                    ALOGV("Track right volume out of range: %.3g", vrf);
+                    vrf = GAIN_FLOAT_UNITY;
                 }
                 // now apply the master volume and stream type volume
-                vl = (uint32_t)(v * vl) << 12;
-                vr = (uint32_t)(v * vr) << 12;
+                // FIXME we're losing the wonderful dynamic range in the minifloat representation
+                float v8_24 = v * (MAX_GAIN_INT * MAX_GAIN_INT);
+                vl = (uint32_t) (v8_24 * vlf);
+                vr = (uint32_t) (v8_24 * vrf);
                 // assuming master volume and stream type volume each go up to 1.0,
                 // vl and vr are now in 8.24 format
 
@@ -3296,6 +3299,7 @@
                 track->mHasVolumeController = false;
             }
 
+            // FIXME Use float
             // Convert volumes from 8.24 to 4.12 format
             // This additional clamping is needed in case chain->setVolume_l() overshot
             vl = (vl + (1 << 11)) >> 12;
@@ -3750,13 +3754,17 @@
         float typeVolume = mStreamTypes[track->streamType()].volume;
         float v = mMasterVolume * typeVolume;
         AudioTrackServerProxy *proxy = track->mAudioTrackServerProxy;
-        uint32_t vlr = proxy->getVolumeLR();
-        float v_clamped = v * (vlr & 0xFFFF);
-        if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
-        left = v_clamped/MAX_GAIN;
-        v_clamped = v * (vlr >> 16);
-        if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
-        right = v_clamped/MAX_GAIN;
+        gain_minifloat_packed_t vlr = proxy->getVolumeLR();
+        left = float_from_gain(gain_minifloat_unpack_left(vlr));
+        if (left > GAIN_FLOAT_UNITY) {
+            left = GAIN_FLOAT_UNITY;
+        }
+        left *= v;
+        right = float_from_gain(gain_minifloat_unpack_right(vlr));
+        if (right > GAIN_FLOAT_UNITY) {
+            right = GAIN_FLOAT_UNITY;
+        }
+        right *= v;
     }
 
     if (lastTrack) {
@@ -4152,7 +4160,10 @@
         mMixerStatus = MIXER_DRAIN_ALL;
         threadLoop_drain();
     }
-    mCallbackThread->exit();
+    if (mUseAsyncWrite) {
+        ALOG_ASSERT(mCallbackThread != 0);
+        mCallbackThread->exit();
+    }
     PlaybackThread::threadLoop_exit();
 }
 
@@ -5564,8 +5575,8 @@
                 reqFormat == AUDIO_FORMAT_PCM_16_BIT &&
                 (mInput->stream->common.get_sample_rate(&mInput->stream->common)
                         <= (2 * samplingRate)) &&
-                popcount(mInput->stream->common.get_channels(&mInput->stream->common))
-                        <= FCC_2 &&
+                audio_channel_count_from_in_mask(
+                        mInput->stream->common.get_channels(&mInput->stream->common)) <= FCC_2 &&
                 (channelMask == AUDIO_CHANNEL_IN_MONO ||
                         channelMask == AUDIO_CHANNEL_IN_STEREO)) {
                 status = NO_ERROR;
@@ -5619,7 +5630,7 @@
 {
     mSampleRate = mInput->stream->common.get_sample_rate(&mInput->stream->common);
     mChannelMask = mInput->stream->common.get_channels(&mInput->stream->common);
-    mChannelCount = popcount(mChannelMask);
+    mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
     mFormat = mInput->stream->common.get_format(&mInput->stream->common);
     if (mFormat != AUDIO_FORMAT_PCM_16_BIT) {
         ALOGE("HAL format %#x not supported; must be AUDIO_FORMAT_PCM_16_BIT", mFormat);
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 6dc7f30..de1782d 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -34,6 +34,7 @@
 
 #include <media/nbaio/Pipe.h>
 #include <media/nbaio/PipeReader.h>
+#include <audio_utils/minifloat.h>
 
 // ----------------------------------------------------------------------------
 
@@ -81,7 +82,9 @@
         mSampleRate(sampleRate),
         mFormat(format),
         mChannelMask(channelMask),
-        mChannelCount(popcount(channelMask)),
+        mChannelCount(isOut ?
+                audio_channel_count_from_out_mask(channelMask) :
+                audio_channel_count_from_in_mask(channelMask)),
         mFrameSize(audio_is_linear_pcm(format) ?
                 mChannelCount * audio_bytes_per_sample(format) : sizeof(int8_t)),
         mFrameCount(frameCount),
@@ -459,7 +462,7 @@
 
 void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size, bool active)
 {
-    uint32_t vlr = mAudioTrackServerProxy->getVolumeLR();
+    gain_minifloat_packed_t vlr = mAudioTrackServerProxy->getVolumeLR();
     if (isFastTrack()) {
         sprintf(buffer, "    F %2d", mFastIndex);
     } else if (mName >= AudioMixer::TRACK0) {
@@ -532,8 +535,8 @@
             stateChar,
             mFillingUpStatus,
             mAudioTrackServerProxy->getSampleRate(),
-            20.0 * log10((vlr & 0xFFFF) / 4096.0),
-            20.0 * log10((vlr >> 16) / 4096.0),
+            20.0 * log10(float_from_gain(gain_minifloat_unpack_left(vlr))),
+            20.0 * log10(float_from_gain(gain_minifloat_unpack_right(vlr))),
             mCblk->mServer,
             mMainBuffer,
             mAuxBuffer,
@@ -959,27 +962,27 @@
 
 // implement VolumeBufferProvider interface
 
-uint32_t AudioFlinger::PlaybackThread::Track::getVolumeLR()
+gain_minifloat_packed_t AudioFlinger::PlaybackThread::Track::getVolumeLR()
 {
     // called by FastMixer, so not allowed to take any locks, block, or do I/O including logs
     ALOG_ASSERT(isFastTrack() && (mCblk != NULL));
-    uint32_t vlr = mAudioTrackServerProxy->getVolumeLR();
-    uint32_t vl = vlr & 0xFFFF;
-    uint32_t vr = vlr >> 16;
+    gain_minifloat_packed_t vlr = mAudioTrackServerProxy->getVolumeLR();
+    float vl = float_from_gain(gain_minifloat_unpack_left(vlr));
+    float vr = float_from_gain(gain_minifloat_unpack_right(vlr));
     // track volumes come from shared memory, so can't be trusted and must be clamped
-    if (vl > MAX_GAIN_INT) {
-        vl = MAX_GAIN_INT;
+    if (vl > GAIN_FLOAT_UNITY) {
+        vl = GAIN_FLOAT_UNITY;
     }
-    if (vr > MAX_GAIN_INT) {
-        vr = MAX_GAIN_INT;
+    if (vr > GAIN_FLOAT_UNITY) {
+        vr = GAIN_FLOAT_UNITY;
     }
     // now apply the cached master volume and stream type volume;
     // this is trusted but lacks any synchronization or barrier so may be stale
     float v = mCachedVolume;
     vl *= v;
     vr *= v;
-    // re-combine into U4.16
-    vlr = (vr << 16) | (vl & 0xFFFF);
+    // re-combine into packed minifloat
+    vlr = gain_minifloat_pack(gain_from_float(vl), gain_from_float(vr));
     // FIXME look at mute, pause, and stop flags
     return vlr;
 }
@@ -1590,7 +1593,7 @@
         // since client and server are in the same process,
         // the buffer has the same virtual address on both sides
         mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize);
-        mClientProxy->setVolumeLR((uint32_t(uint16_t(0x1000)) << 16) | uint16_t(0x1000));
+        mClientProxy->setVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY);
         mClientProxy->setSendLevel(0.0);
         mClientProxy->setSampleRate(sampleRate);
         mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize,
@@ -1849,7 +1852,7 @@
 
     mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount, mFrameSize);
 
-    uint32_t channelCount = popcount(channelMask);
+    uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
     // FIXME I don't understand either of the channel count checks
     if (thread->mSampleRate != sampleRate && thread->mChannelCount <= FCC_2 &&
             channelCount <= FCC_2) {