Merge "Visualizer: Fix the conversion from 8-bit sample to 16-bit sample." into gingerbread
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index e6d84ba..e734c38 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -105,8 +105,8 @@
};
enum {
- CAMERA_FACING_BACK = 0,
- CAMERA_FACING_FRONT = 1 /* The camera faces to the user */
+ CAMERA_FACING_BACK = 0, /* The facing of the camera is opposite to that of the screen. */
+ CAMERA_FACING_FRONT = 1 /* The facing of the camera is the same as that of the screen. */
};
struct CameraInfo {
@@ -122,10 +122,12 @@
* camera image needs to be rotated clockwise so it shows correctly on
* the display in its natural orientation. It should be 0, 90, 180, or 270.
*
- * For example, suppose a device has a naturally tall screen, but the camera
- * sensor is mounted in landscape. If the top side of the camera sensor is
- * aligned with the right edge of the display in natural orientation, the
- * value should be 90.
+ * For example, suppose a device has a naturally tall screen. The
+ * back-facing camera sensor is mounted in landscape. You are looking at
+ * the screen. If the top side of the camera sensor is aligned with the
+ * right edge of the screen in natural orientation, the value should be
+ * 90. If the top side of a front-facing camera sensor is aligned with
+ * the right of the screen, the value should be 270.
*/
int orientation;
};
diff --git a/include/camera/CameraHardwareInterface.h b/include/camera/CameraHardwareInterface.h
index 6a66e3c..35c5aa1 100644
--- a/include/camera/CameraHardwareInterface.h
+++ b/include/camera/CameraHardwareInterface.h
@@ -190,7 +190,9 @@
*/
virtual status_t cancelPicture() = 0;
- /** Set the camera parameters. */
+ /**
+ * Set the camera parameters. This returns BAD_VALUE if any parameter is
+ * invalid or not supported. */
virtual status_t setParameters(const CameraParameters& params) = 0;
/** Return the camera parameters. */
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 53039a0..4e770fd 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -142,16 +142,23 @@
// the best.
// Example value: "90". Read/write.
static const char KEY_JPEG_QUALITY[];
- // The orientation of the device in degrees. For example, suppose the
- // natural position of the device is landscape. If the user takes a picture
- // in landscape mode in 2048x1536 resolution, the rotation will be set to
- // "0". If the user rotates the phone 90 degrees clockwise, the rotation
- // should be set to "90".
- // The camera driver can set orientation in the EXIF header without rotating
- // the picture. Or the driver can rotate the picture and the EXIF thumbnail.
- // If the Jpeg picture is rotated, the orientation in the EXIF header should
- // be missing or 1 (row #0 is top and column #0 is left side). The driver
- // should not set default value for this parameter.
+ // The rotation angle in degrees relative to the orientation of the camera.
+ // This affects the pictures returned from CAMERA_MSG_COMPRESSED_IMAGE. The
+ // camera driver may set orientation in the EXIF header without rotating the
+ // picture. Or the driver may rotate the picture and the EXIF thumbnail. If
+ // the Jpeg picture is rotated, the orientation in the EXIF header will be
+ // missing or 1 (row #0 is top and column #0 is left side).
+ //
+ // Note that the JPEG pictures of front-facing cameras are not mirrored
+ // as in preview display.
+ //
+ // For example, suppose the natural orientation of the device is portrait.
+ // The device is rotated 270 degrees clockwise, so the device orientation is
+ // 270. Suppose a back-facing camera sensor is mounted in landscape and the
+ // top side of the camera sensor is aligned with the right edge of the
+ // display in natural orientation. So the camera orientation is 90. The
+ // rotation should be set to 0 (270 + 90).
+ //
// Example value: "0" or "90" or "180" or "270". Write only.
static const char KEY_ROTATION[];
// GPS latitude coordinate. GPSLatitude and GPSLatitudeRef will be stored in
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 2f61cbe..f794766 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -115,7 +115,8 @@
const char *componentName,
OMX_COLOR_FORMATTYPE colorFormat,
size_t encodedWidth, size_t encodedHeight,
- size_t displayWidth, size_t displayHeight) = 0;
+ size_t displayWidth, size_t displayHeight,
+ int32_t rotationDegrees) = 0;
// Note: These methods are _not_ virtual, it exists as a wrapper around
// the virtual "createRenderer" method above facilitating extraction
@@ -125,14 +126,16 @@
const char *componentName,
OMX_COLOR_FORMATTYPE colorFormat,
size_t encodedWidth, size_t encodedHeight,
- size_t displayWidth, size_t displayHeight);
+ size_t displayWidth, size_t displayHeight,
+ int32_t rotationDegrees);
sp<IOMXRenderer> createRendererFromJavaSurface(
JNIEnv *env, jobject javaSurface,
const char *componentName,
OMX_COLOR_FORMATTYPE colorFormat,
size_t encodedWidth, size_t encodedHeight,
- size_t displayWidth, size_t displayHeight);
+ size_t displayWidth, size_t displayHeight,
+ int32_t rotationDegrees);
};
struct omx_message {
diff --git a/include/media/stagefright/HardwareAPI.h b/include/media/stagefright/HardwareAPI.h
index 221c679..63f11d1 100644
--- a/include/media/stagefright/HardwareAPI.h
+++ b/include/media/stagefright/HardwareAPI.h
@@ -32,6 +32,14 @@
size_t displayWidth, size_t displayHeight,
size_t decodedWidth, size_t decodedHeight);
+extern android::VideoRenderer *createRendererWithRotation(
+ const android::sp<android::ISurface> &surface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight,
+ int32_t rotationDegrees);
+
extern android::OMXPluginBase *createOMXPlugin();
#endif // HARDWARE_API_H_
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index bb469e5..7bf07eb 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -154,6 +154,7 @@
bool exceedsFileDurationLimit();
bool isFileStreamable() const;
void trackProgressStatus(const Track* track, int64_t timeUs, status_t err = OK);
+ void writeCompositionMatrix(int32_t degrees);
MPEG4Writer(const MPEG4Writer &);
MPEG4Writer &operator=(const MPEG4Writer &);
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index d2bd9f2..29bfc4a 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -32,6 +32,7 @@
kKeyMIMEType = 'mime', // cstring
kKeyWidth = 'widt', // int32_t
kKeyHeight = 'heig', // int32_t
+ kKeyRotation = 'rotA', // int32_t (angle in degrees)
kKeyIFramesInterval = 'ifiv', // int32_t
kKeyStride = 'strd', // int32_t
kKeySliceHeight = 'slht', // int32_t
@@ -90,6 +91,7 @@
// Track authoring progress status
// kKeyTrackTimeStatus is used to track progress in elapsed time
kKeyTrackTimeStatus = 'tktm', // int64_t
+ kKeyRotationDegree = 'rdge', // int32_t (clockwise, in degree)
kKeyNotRealTime = 'ntrt', // bool (int32_t)
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 1d94160..fed6761 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -109,6 +109,7 @@
kAvoidMemcopyInputRecordingFrames = 2048,
kRequiresLargerEncoderOutputBuffer = 4096,
kOutputBuffersAreUnreadable = 8192,
+ kStoreMetaDataInInputVideoBuffers = 16384,
};
struct BufferInfo {
diff --git a/include/private/media/VideoFrame.h b/include/private/media/VideoFrame.h
index 9c35274..3aff0c6 100644
--- a/include/private/media/VideoFrame.h
+++ b/include/private/media/VideoFrame.h
@@ -120,6 +120,7 @@
uint32_t mDisplayHeight;
uint32_t mSize; // Number of bytes in mData
uint8_t* mData; // Actual binary data
+ int32_t mRotationAngle; // rotation angle, clockwise
};
}; // namespace android
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index f3804b8..ae6c2bf 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -38,11 +38,13 @@
const char *componentName,
OMX_COLOR_FORMATTYPE colorFormat,
size_t encodedWidth, size_t encodedHeight,
- size_t displayWidth, size_t displayHeight) {
+ size_t displayWidth, size_t displayHeight,
+ int32_t rotationDegrees) {
return createRenderer(
surface->getISurface(),
componentName, colorFormat, encodedWidth, encodedHeight,
- displayWidth, displayHeight);
+ displayWidth, displayHeight,
+ rotationDegrees);
}
sp<IOMXRenderer> IOMX::createRendererFromJavaSurface(
@@ -50,7 +52,8 @@
const char *componentName,
OMX_COLOR_FORMATTYPE colorFormat,
size_t encodedWidth, size_t encodedHeight,
- size_t displayWidth, size_t displayHeight) {
+ size_t displayWidth, size_t displayHeight,
+ int32_t rotationDegrees) {
jclass surfaceClass = env->FindClass("android/view/Surface");
if (surfaceClass == NULL) {
LOGE("Can't find android/view/Surface");
@@ -67,7 +70,8 @@
return createRenderer(
surface, componentName, colorFormat, encodedWidth,
- encodedHeight, displayWidth, displayHeight);
+ encodedHeight, displayWidth, displayHeight,
+ rotationDegrees);
}
class BpOMX : public BpInterface<IOMX> {
@@ -349,7 +353,8 @@
const char *componentName,
OMX_COLOR_FORMATTYPE colorFormat,
size_t encodedWidth, size_t encodedHeight,
- size_t displayWidth, size_t displayHeight) {
+ size_t displayWidth, size_t displayHeight,
+ int32_t rotationDegrees) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
@@ -360,6 +365,7 @@
data.writeInt32(encodedHeight);
data.writeInt32(displayWidth);
data.writeInt32(displayHeight);
+ data.writeInt32(rotationDegrees);
remote()->transact(CREATE_RENDERER, data, &reply);
@@ -682,11 +688,13 @@
size_t encodedHeight = (size_t)data.readInt32();
size_t displayWidth = (size_t)data.readInt32();
size_t displayHeight = (size_t)data.readInt32();
+ int32_t rotationDegrees = data.readInt32();
sp<IOMXRenderer> renderer =
createRenderer(isurface, componentName, colorFormat,
encodedWidth, encodedHeight,
- displayWidth, displayHeight);
+ displayWidth, displayHeight,
+ rotationDegrees);
reply->writeStrongBinder(renderer->asBinder());
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index ca229fa..39fce81 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -253,6 +253,8 @@
frameCopy->mDisplayWidth = frame->mDisplayWidth;
frameCopy->mDisplayHeight = frame->mDisplayHeight;
frameCopy->mSize = frame->mSize;
+ frameCopy->mRotationAngle = frame->mRotationAngle;
+ LOGV("rotation: %d", frameCopy->mRotationAngle);
frameCopy->mData = (uint8_t *)frameCopy + sizeof(VideoFrame);
memcpy(frameCopy->mData, frame->mData, frame->mSize);
delete frame; // Fix memory leakage
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index d37d83d..553648d 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -340,6 +340,17 @@
return OK;
}
+// Always rotate clockwise, and only support 0, 90, 180 and 270 for now.
+status_t StagefrightRecorder::setParamVideoRotation(int32_t degrees) {
+ LOGV("setParamVideoRotation: %d", degrees);
+ if (degrees < 0 || degrees % 90 != 0) {
+ LOGE("Unsupported video rotation angle: %d", degrees);
+ return BAD_VALUE;
+ }
+ mRotationDegrees = degrees % 360;
+ return OK;
+}
+
status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
if (timeUs <= 0) {
@@ -532,6 +543,11 @@
if (safe_strtoi32(value.string(), &video_bitrate)) {
return setParamVideoEncodingBitRate(video_bitrate);
}
+ } else if (key == "video-param-rotation-angle-degrees") {
+ int32_t degrees;
+ if (safe_strtoi32(value.string(), °rees)) {
+ return setParamVideoRotation(degrees);
+ }
} else if (key == "video-param-i-frames-interval") {
int32_t seconds;
if (safe_strtoi32(value.string(), &seconds)) {
@@ -1105,6 +1121,9 @@
if (mTrackEveryTimeDurationUs > 0) {
meta->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
}
+ if (mRotationDegrees != 0) {
+ meta->setInt32(kKeyRotationDegree, mRotationDegrees);
+ }
writer->setListener(mListener);
mWriter = writer;
return mWriter->start(meta.get());
@@ -1187,6 +1206,7 @@
mMaxFileDurationUs = 0;
mMaxFileSizeBytes = 0;
mTrackEveryTimeDurationUs = 0;
+ mRotationDegrees = 0;
mEncoderProfiles = MediaProfiles::getInstance();
mOutputFd = -1;
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index ad0dfa0..e42df2e 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -91,6 +91,7 @@
int64_t mMaxFileSizeBytes;
int64_t mMaxFileDurationUs;
int64_t mTrackEveryTimeDurationUs;
+ int32_t mRotationDegrees; // Clockwise
String8 mParams;
int mOutputFd;
@@ -120,6 +121,7 @@
status_t setParamVideoEncoderLevel(int32_t level);
status_t setParamVideoCameraId(int32_t cameraId);
status_t setParamVideoTimeScale(int32_t timeScale);
+ status_t setParamVideoRotation(int32_t degrees);
status_t setParamTrackTimeStatus(int64_t timeDurationUs);
status_t setParamInterleaveDuration(int32_t durationUs);
status_t setParam64BitFileOffset(bool use64BitFileOffset);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 064a00c..66eb7ee 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -103,12 +103,14 @@
OMX_COLOR_FORMATTYPE colorFormat,
const sp<ISurface> &surface,
size_t displayWidth, size_t displayHeight,
- size_t decodedWidth, size_t decodedHeight)
+ size_t decodedWidth, size_t decodedHeight,
+ int32_t rotationDegrees)
: mTarget(NULL),
mLibHandle(NULL) {
init(previewOnly, componentName,
colorFormat, surface, displayWidth,
- displayHeight, decodedWidth, decodedHeight);
+ displayHeight, decodedWidth, decodedHeight,
+ rotationDegrees);
}
virtual void render(MediaBuffer *buffer) {
@@ -141,7 +143,8 @@
OMX_COLOR_FORMATTYPE colorFormat,
const sp<ISurface> &surface,
size_t displayWidth, size_t displayHeight,
- size_t decodedWidth, size_t decodedHeight);
+ size_t decodedWidth, size_t decodedHeight,
+ int32_t rotationDegrees);
AwesomeLocalRenderer(const AwesomeLocalRenderer &);
AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
@@ -153,7 +156,8 @@
OMX_COLOR_FORMATTYPE colorFormat,
const sp<ISurface> &surface,
size_t displayWidth, size_t displayHeight,
- size_t decodedWidth, size_t decodedHeight) {
+ size_t decodedWidth, size_t decodedHeight,
+ int32_t rotationDegrees) {
if (!previewOnly) {
// We will stick to the vanilla software-color-converting renderer
// for "previewOnly" mode, to avoid unneccessarily switching overlays
@@ -162,6 +166,14 @@
mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
if (mLibHandle) {
+ typedef VideoRenderer *(*CreateRendererWithRotationFunc)(
+ const sp<ISurface> &surface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight,
+ int32_t rotationDegrees);
+
typedef VideoRenderer *(*CreateRendererFunc)(
const sp<ISurface> &surface,
const char *componentName,
@@ -169,17 +181,36 @@
size_t displayWidth, size_t displayHeight,
size_t decodedWidth, size_t decodedHeight);
- CreateRendererFunc func =
- (CreateRendererFunc)dlsym(
+ CreateRendererWithRotationFunc funcWithRotation =
+ (CreateRendererWithRotationFunc)dlsym(
mLibHandle,
- "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
- "OMX_COLOR_FORMATTYPEjjjj");
+ "_Z26createRendererWithRotationRKN7android2spINS_8"
+ "ISurfaceEEEPKc20OMX_COLOR_FORMATTYPEjjjji");
- if (func) {
+ if (funcWithRotation) {
mTarget =
- (*func)(surface, componentName, colorFormat,
- displayWidth, displayHeight,
- decodedWidth, decodedHeight);
+ (*funcWithRotation)(
+ surface, componentName, colorFormat,
+ displayWidth, displayHeight,
+ decodedWidth, decodedHeight,
+ rotationDegrees);
+ } else {
+ if (rotationDegrees != 0) {
+ LOGW("renderer does not support rotation.");
+ }
+
+ CreateRendererFunc func =
+ (CreateRendererFunc)dlsym(
+ mLibHandle,
+ "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
+ "OMX_COLOR_FORMATTYPEjjjj");
+
+ if (func) {
+ mTarget =
+ (*func)(surface, componentName, colorFormat,
+ displayWidth, displayHeight,
+ decodedWidth, decodedHeight);
+ }
}
}
}
@@ -187,7 +218,7 @@
if (mTarget == NULL) {
mTarget = new SoftwareRenderer(
colorFormat, surface, displayWidth, displayHeight,
- decodedWidth, decodedHeight);
+ decodedWidth, decodedHeight, rotationDegrees);
}
}
@@ -785,6 +816,12 @@
CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
+ int32_t rotationDegrees;
+ if (!mVideoTrack->getFormat()->findInt32(
+ kKeyRotation, &rotationDegrees)) {
+ rotationDegrees = 0;
+ }
+
mVideoRenderer.clear();
// Must ensure that mVideoRenderer's destructor is actually executed
@@ -800,7 +837,8 @@
mISurface, component,
(OMX_COLOR_FORMATTYPE)format,
decodedWidth, decodedHeight,
- mVideoWidth, mVideoHeight));
+ mVideoWidth, mVideoHeight,
+ rotationDegrees));
} else {
// Other decoders are instantiated locally and as a consequence
// allocate their buffers in local address space.
@@ -810,7 +848,7 @@
(OMX_COLOR_FORMATTYPE)format,
mISurface,
mVideoWidth, mVideoHeight,
- decodedWidth, decodedHeight);
+ decodedWidth, decodedHeight, rotationDegrees);
}
}
}
@@ -1625,7 +1663,22 @@
if (mVideoWidth < 0 || mVideoHeight < 0) {
notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
} else {
- notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
+ int32_t rotationDegrees;
+ if (!mVideoTrack->getFormat()->findInt32(
+ kKeyRotation, &rotationDegrees)) {
+ rotationDegrees = 0;
+ }
+
+#if 1
+ if (rotationDegrees == 90 || rotationDegrees == 270) {
+ notifyListener_l(
+ MEDIA_SET_VIDEO_SIZE, mVideoHeight, mVideoWidth);
+ } else
+#endif
+ {
+ notifyListener_l(
+ MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
+ }
}
notifyListener_l(MEDIA_PREPARED);
@@ -1757,7 +1810,8 @@
state->mVideoWidth,
state->mVideoHeight,
state->mDecodedWidth,
- state->mDecodedHeight);
+ state->mDecodedHeight,
+ 0);
mVideoRendererIsPreview = true;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index f404708..2154f2f 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -27,11 +27,11 @@
#include <stdlib.h>
#include <string.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include "include/ESDS.h"
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
@@ -579,52 +579,9 @@
case FOURCC('t', 'k', 'h', 'd'):
{
- if (chunk_data_size < 4) {
- return ERROR_MALFORMED;
- }
-
- uint8_t version;
- if (mDataSource->readAt(data_offset, &version, 1) < 1) {
- return ERROR_IO;
- }
-
- uint64_t ctime, mtime, duration;
- int32_t id;
- uint32_t width, height;
-
- if (version == 1) {
- if (chunk_data_size != 36 + 60) {
- return ERROR_MALFORMED;
- }
-
- uint8_t buffer[36 + 60];
- if (mDataSource->readAt(
- data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
- return ERROR_IO;
- }
-
- ctime = U64_AT(&buffer[4]);
- mtime = U64_AT(&buffer[12]);
- id = U32_AT(&buffer[20]);
- duration = U64_AT(&buffer[28]);
- width = U32_AT(&buffer[88]);
- height = U32_AT(&buffer[92]);
- } else if (version == 0) {
- if (chunk_data_size != 24 + 60) {
- return ERROR_MALFORMED;
- }
-
- uint8_t buffer[24 + 60];
- if (mDataSource->readAt(
- data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
- return ERROR_IO;
- }
- ctime = U32_AT(&buffer[4]);
- mtime = U32_AT(&buffer[8]);
- id = U32_AT(&buffer[12]);
- duration = U32_AT(&buffer[20]);
- width = U32_AT(&buffer[76]);
- height = U32_AT(&buffer[80]);
+ status_t err;
+ if ((err = parseTrackHeader(data_offset, chunk_data_size)) != OK) {
+ return err;
}
*offset += chunk_size;
@@ -1073,6 +1030,89 @@
return OK;
}
+status_t MPEG4Extractor::parseTrackHeader(
+ off_t data_offset, off_t data_size) {
+ if (data_size < 4) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t version;
+ if (mDataSource->readAt(data_offset, &version, 1) < 1) {
+ return ERROR_IO;
+ }
+
+ size_t dynSize = (version == 1) ? 36 : 24;
+
+ uint8_t buffer[36 + 60];
+
+ if (data_size != (off_t)dynSize + 60) {
+ return ERROR_MALFORMED;
+ }
+
+ if (mDataSource->readAt(
+ data_offset, buffer, data_size) < (ssize_t)data_size) {
+ return ERROR_IO;
+ }
+
+ uint64_t ctime, mtime, duration;
+ int32_t id;
+
+ if (version == 1) {
+ ctime = U64_AT(&buffer[4]);
+ mtime = U64_AT(&buffer[12]);
+ id = U32_AT(&buffer[20]);
+ duration = U64_AT(&buffer[28]);
+ } else if (version == 0) {
+ ctime = U32_AT(&buffer[4]);
+ mtime = U32_AT(&buffer[8]);
+ id = U32_AT(&buffer[12]);
+ duration = U32_AT(&buffer[20]);
+ }
+
+ size_t matrixOffset = dynSize + 16;
+ int32_t a00 = U32_AT(&buffer[matrixOffset]);
+ int32_t a01 = U32_AT(&buffer[matrixOffset + 4]);
+ int32_t dx = U32_AT(&buffer[matrixOffset + 8]);
+ int32_t a10 = U32_AT(&buffer[matrixOffset + 12]);
+ int32_t a11 = U32_AT(&buffer[matrixOffset + 16]);
+ int32_t dy = U32_AT(&buffer[matrixOffset + 20]);
+
+#if 0
+ LOGI("x' = %.2f * x + %.2f * y + %.2f",
+ a00 / 65536.0f, a01 / 65536.0f, dx / 65536.0f);
+ LOGI("y' = %.2f * x + %.2f * y + %.2f",
+ a10 / 65536.0f, a11 / 65536.0f, dy / 65536.0f);
+#endif
+
+ uint32_t rotationDegrees;
+
+ static const int32_t kFixedOne = 0x10000;
+ if (a00 == kFixedOne && a01 == 0 && a10 == 0 && a11 == kFixedOne) {
+ // Identity, no rotation
+ rotationDegrees = 0;
+ } else if (a00 == 0 && a01 == kFixedOne && a10 == -kFixedOne && a11 == 0) {
+ rotationDegrees = 90;
+ } else if (a00 == 0 && a01 == -kFixedOne && a10 == kFixedOne && a11 == 0) {
+ rotationDegrees = 270;
+ } else if (a00 == -kFixedOne && a01 == 0 && a10 == 0 && a11 == -kFixedOne) {
+ rotationDegrees = 180;
+ } else {
+ LOGW("We only support 0,90,180,270 degree rotation matrices");
+ rotationDegrees = 0;
+ }
+
+ if (rotationDegrees != 0) {
+ mLastTrack->meta->setInt32(kKeyRotation, rotationDegrees);
+ }
+
+#if 0
+ uint32_t width = U32_AT(&buffer[dynSize + 52]);
+ uint32_t height = U32_AT(&buffer[dynSize + 56]);
+#endif
+
+ return OK;
+}
+
status_t MPEG4Extractor::parseMetaData(off_t offset, size_t size) {
if (size < 4) {
return ERROR_MALFORMED;
@@ -1386,7 +1426,7 @@
const uint8_t *ptr = (const uint8_t *)data;
CHECK(size >= 7);
- CHECK_EQ(ptr[0], 1); // configurationVersion == 1
+ CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
// The number of bytes used to encode the length of a NAL unit.
mNALLengthSize = 1 + (ptr[4] & 3);
@@ -1534,7 +1574,7 @@
}
uint32_t sampleTime;
- CHECK_EQ(OK, mSampleTable->getMetaDataForSample(
+ CHECK_EQ((status_t)OK, mSampleTable->getMetaDataForSample(
sampleIndex, NULL, NULL, &sampleTime));
if (mode == ReadOptions::SEEK_CLOSEST) {
@@ -1581,7 +1621,7 @@
err = mGroup->acquire_buffer(&mBuffer);
if (err != OK) {
- CHECK_EQ(mBuffer, NULL);
+ CHECK(mBuffer == NULL);
return err;
}
}
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index a15c274..cbb1604 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -202,6 +202,7 @@
// Simple validation on the codec specific data
status_t checkCodecSpecificData() const;
+ int32_t mRotation;
void updateTrackSizeEstimate();
void addOneStscTableEntry(size_t chunkId, size_t sampleId);
@@ -519,6 +520,58 @@
pthread_join(mThread, &dummy);
}
+/*
+ * MP4 file standard defines a composition matrix:
+ * | a b u |
+ * | c d v |
+ * | x y w |
+ *
+ * the element in the matrix is stored in the following
+ * order: {a, b, u, c, d, v, x, y, w},
+ * where a, b, c, d, x, and y is in 16.16 format, while
+ * u, v and w is in 2.30 format.
+ */
+void MPEG4Writer::writeCompositionMatrix(int degrees) {
+ LOGV("writeCompositionMatrix");
+ uint32_t a = 0x00010000;
+ uint32_t b = 0;
+ uint32_t c = 0;
+ uint32_t d = 0x00010000;
+ switch (degrees) {
+ case 0:
+ break;
+ case 90:
+ a = 0;
+ b = 0x00010000;
+ c = 0xFFFF0000;
+ d = 0;
+ break;
+ case 180:
+ a = 0xFFFF0000;
+ d = 0xFFFF0000;
+ break;
+ case 270:
+ a = 0;
+ b = 0xFFFF0000;
+ c = 0x00010000;
+ d = 0;
+ break;
+ default:
+ CHECK(!"Should never reach this unknown rotation");
+ break;
+ }
+
+ writeInt32(a); // a
+ writeInt32(b); // b
+ writeInt32(0); // u
+ writeInt32(c); // c
+ writeInt32(d); // d
+ writeInt32(0); // v
+ writeInt32(0); // x
+ writeInt32(0); // y
+ writeInt32(0x40000000); // w
+}
+
status_t MPEG4Writer::stop() {
if (mFile == NULL) {
return OK;
@@ -584,15 +637,7 @@
writeInt16(0); // reserved
writeInt32(0); // reserved
writeInt32(0); // reserved
- writeInt32(0x10000); // matrix
- writeInt32(0);
- writeInt32(0);
- writeInt32(0);
- writeInt32(0x10000);
- writeInt32(0);
- writeInt32(0);
- writeInt32(0);
- writeInt32(0x40000000);
+ writeCompositionMatrix(0);
writeInt32(0); // predefined
writeInt32(0); // predefined
writeInt32(0); // predefined
@@ -885,7 +930,8 @@
mCodecSpecificData(NULL),
mCodecSpecificDataSize(0),
mGotAllCodecSpecificData(false),
- mReachedEOS(false) {
+ mReachedEOS(false),
+ mRotation(0) {
getCodecSpecificDataFromInputFormatIfPossible();
const char *mime;
@@ -1178,6 +1224,11 @@
startTimeUs = 0;
}
+ int32_t rotationDegrees;
+ if (!mIsAudio && params && params->findInt32(kKeyRotationDegree, &rotationDegrees)) {
+ mRotation = rotationDegrees;
+ }
+
mIsRealTimeRecording = true;
{
int32_t isNotRealTime;
@@ -2071,15 +2122,7 @@
mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume
mOwner->writeInt16(0); // reserved
- mOwner->writeInt32(0x10000); // matrix
- mOwner->writeInt32(0);
- mOwner->writeInt32(0);
- mOwner->writeInt32(0);
- mOwner->writeInt32(0x10000);
- mOwner->writeInt32(0);
- mOwner->writeInt32(0);
- mOwner->writeInt32(0);
- mOwner->writeInt32(0x40000000);
+ mOwner->writeCompositionMatrix(mRotation);
if (mIsAudio) {
mOwner->writeInt32(0);
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 9a49a9b..980da77 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -412,6 +412,13 @@
quirks |= kOutputBuffersAreUnreadable;
}
+ if (!strncmp(componentName, "OMX.SEC.", 8) && isEncoder) {
+ // These input buffers contain meta data (for instance,
+ // information helps locate the actual YUV data, or
+ // the physical address of the YUV data).
+ quirks |= kStoreMetaDataInInputVideoBuffers;
+ }
+
return quirks;
}
@@ -1695,7 +1702,15 @@
"an EMPTY_BUFFER_DONE.", buffer);
}
- buffers->editItemAt(i).mOwnedByComponent = false;
+ {
+ BufferInfo *info = &buffers->editItemAt(i);
+ info->mOwnedByComponent = false;
+ if (info->mMediaBuffer != NULL) {
+ // It is time to release the media buffers storing meta data
+ info->mMediaBuffer->release();
+ info->mMediaBuffer = NULL;
+ }
+ }
if (mPortStatus[kPortIndexInput] == DISABLING) {
CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
@@ -2202,6 +2217,7 @@
CHECK_EQ(info->mMediaBuffer->refcount(), 0);
info->mMediaBuffer->release();
+ info->mMediaBuffer = NULL;
}
buffers->removeAt(i);
@@ -2434,11 +2450,19 @@
break;
}
+ // Do not release the media buffer if it stores meta data
+ // instead of YUV data. The release is delayed until
+ // EMPTY_BUFFER_DONE callback is received.
+ bool releaseBuffer = true;
if (mIsEncoder && (mQuirks & kAvoidMemcopyInputRecordingFrames)) {
CHECK(mOMXLivesLocally && offset == 0);
OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *) info->mBuffer;
header->pBuffer = (OMX_U8 *) srcBuffer->data() + srcBuffer->range_offset();
} else {
+ if (mQuirks & kStoreMetaDataInInputVideoBuffers) {
+ releaseBuffer = false;
+ info->mMediaBuffer = srcBuffer;
+ }
memcpy((uint8_t *)info->mData + offset,
(const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
srcBuffer->range_length());
@@ -2454,8 +2478,10 @@
offset += srcBuffer->range_length();
- srcBuffer->release();
- srcBuffer = NULL;
+ if (releaseBuffer) {
+ srcBuffer->release();
+ srcBuffer = NULL;
+ }
++n;
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index a800a93..9b2dec9 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -191,6 +191,11 @@
CHECK(meta->findInt32(kKeyWidth, &width));
CHECK(meta->findInt32(kKeyHeight, &height));
+ int32_t rotationAngle;
+ if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
+ rotationAngle = 0; // By default, no rotation
+ }
+
VideoFrame *frame = new VideoFrame;
frame->mWidth = width;
frame->mHeight = height;
@@ -198,6 +203,7 @@
frame->mDisplayHeight = height;
frame->mSize = width * height * 2;
frame->mData = new uint8_t[frame->mSize];
+ frame->mRotationAngle = rotationAngle;
int32_t srcFormat;
CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index a6dbf69..86ad85b 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -30,7 +30,8 @@
OMX_COLOR_FORMATTYPE colorFormat,
const sp<ISurface> &surface,
size_t displayWidth, size_t displayHeight,
- size_t decodedWidth, size_t decodedHeight)
+ size_t decodedWidth, size_t decodedHeight,
+ int32_t rotationDegrees)
: mColorFormat(colorFormat),
mConverter(colorFormat, OMX_COLOR_Format16bitRGB565),
mISurface(surface),
@@ -56,10 +57,20 @@
CHECK(mMemoryHeap->heapID() >= 0);
CHECK(mConverter.isValid());
+ uint32_t orientation;
+ switch (rotationDegrees) {
+ case 0: orientation = ISurface::BufferHeap::ROT_0; break;
+ case 90: orientation = ISurface::BufferHeap::ROT_90; break;
+ case 180: orientation = ISurface::BufferHeap::ROT_180; break;
+ case 270: orientation = ISurface::BufferHeap::ROT_270; break;
+ default: orientation = ISurface::BufferHeap::ROT_0; break;
+ }
+
ISurface::BufferHeap bufferHeap(
mDisplayWidth, mDisplayHeight,
mDecodedWidth, mDecodedHeight,
PIXEL_FORMAT_RGB_565,
+ orientation, 0,
mMemoryHeap);
status_t err = mISurface->registerBuffers(bufferHeap);
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index 1c9cc7e..2610b0e 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -71,6 +71,8 @@
static status_t verifyTrack(Track *track);
+ status_t parseTrackHeader(off_t data_offset, off_t data_size);
+
MPEG4Extractor(const MPEG4Extractor &);
MPEG4Extractor &operator=(const MPEG4Extractor &);
};
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index c99da59..72ab5aa 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -92,7 +92,8 @@
const char *componentName,
OMX_COLOR_FORMATTYPE colorFormat,
size_t encodedWidth, size_t encodedHeight,
- size_t displayWidth, size_t displayHeight);
+ size_t displayWidth, size_t displayHeight,
+ int32_t rotationDegrees);
virtual void binderDied(const wp<IBinder> &the_late_who);
diff --git a/media/libstagefright/include/SoftwareRenderer.h b/media/libstagefright/include/SoftwareRenderer.h
index 9eed089..25c9df7 100644
--- a/media/libstagefright/include/SoftwareRenderer.h
+++ b/media/libstagefright/include/SoftwareRenderer.h
@@ -33,7 +33,8 @@
OMX_COLOR_FORMATTYPE colorFormat,
const sp<ISurface> &surface,
size_t displayWidth, size_t displayHeight,
- size_t decodedWidth, size_t decodedHeight);
+ size_t decodedWidth, size_t decodedHeight,
+ int32_t rotationDegrees = 0);
virtual ~SoftwareRenderer();
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index c927da1..63af26a 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -459,7 +459,8 @@
const char *componentName,
OMX_COLOR_FORMATTYPE colorFormat,
size_t encodedWidth, size_t encodedHeight,
- size_t displayWidth, size_t displayHeight) {
+ size_t displayWidth, size_t displayHeight,
+ int32_t rotationDegrees) {
Mutex::Autolock autoLock(mLock);
VideoRenderer *impl = NULL;
@@ -467,6 +468,14 @@
void *libHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
if (libHandle) {
+ typedef VideoRenderer *(*CreateRendererWithRotationFunc)(
+ const sp<ISurface> &surface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight,
+ int32_t rotationDegrees);
+
typedef VideoRenderer *(*CreateRendererFunc)(
const sp<ISurface> &surface,
const char *componentName,
@@ -474,22 +483,35 @@
size_t displayWidth, size_t displayHeight,
size_t decodedWidth, size_t decodedHeight);
- CreateRendererFunc func =
- (CreateRendererFunc)dlsym(
+ CreateRendererWithRotationFunc funcWithRotation =
+ (CreateRendererWithRotationFunc)dlsym(
libHandle,
- "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
- "OMX_COLOR_FORMATTYPEjjjj");
+ "_Z26createRendererWithRotationRKN7android2spINS_8"
+ "ISurfaceEEEPKc20OMX_COLOR_FORMATTYPEjjjji");
- if (func) {
- impl = (*func)(surface, componentName, colorFormat,
- displayWidth, displayHeight, encodedWidth, encodedHeight);
+ if (funcWithRotation) {
+ impl = (*funcWithRotation)(
+ surface, componentName, colorFormat,
+ displayWidth, displayHeight, encodedWidth, encodedHeight,
+ rotationDegrees);
+ } else {
+ CreateRendererFunc func =
+ (CreateRendererFunc)dlsym(
+ libHandle,
+ "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
+ "OMX_COLOR_FORMATTYPEjjjj");
- if (impl) {
- impl = new SharedVideoRenderer(libHandle, impl);
- libHandle = NULL;
+ if (func) {
+ impl = (*func)(surface, componentName, colorFormat,
+ displayWidth, displayHeight, encodedWidth, encodedHeight);
}
}
+ if (impl) {
+ impl = new SharedVideoRenderer(libHandle, impl);
+ libHandle = NULL;
+ }
+
if (libHandle) {
dlclose(libHandle);
libHandle = NULL;