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", ×tampNs)) {
- 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", ×tampNs)) {
- 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) {