summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/libmedia/IOMX.cpp20
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.cpp2
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp20
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.h2
-rw-r--r--media/libstagefright/AwesomePlayer.cpp88
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp140
-rw-r--r--media/libstagefright/MPEG4Writer.cpp81
-rw-r--r--media/libstagefright/OMXCodec.cpp32
-rw-r--r--media/libstagefright/StagefrightMetadataRetriever.cpp6
-rw-r--r--media/libstagefright/colorconversion/SoftwareRenderer.cpp13
-rw-r--r--media/libstagefright/include/MPEG4Extractor.h2
-rw-r--r--media/libstagefright/include/OMX.h3
-rw-r--r--media/libstagefright/include/SoftwareRenderer.h3
-rw-r--r--media/libstagefright/omx/OMX.cpp48
14 files changed, 349 insertions, 111 deletions
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 @@ sp<IOMXRenderer> IOMX::createRenderer(
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 @@ sp<IOMXRenderer> IOMX::createRendererFromJavaSurface(
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 @@ sp<IOMXRenderer> IOMX::createRendererFromJavaSurface(
return createRenderer(
surface, componentName, colorFormat, encodedWidth,
- encodedHeight, displayWidth, displayHeight);
+ encodedHeight, displayWidth, displayHeight,
+ rotationDegrees);
}
class BpOMX : public BpInterface<IOMX> {
@@ -349,7 +353,8 @@ public:
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 @@ public:
data.writeInt32(encodedHeight);
data.writeInt32(displayWidth);
data.writeInt32(displayHeight);
+ data.writeInt32(rotationDegrees);
remote()->transact(CREATE_RENDERER, data, &reply);
@@ -682,11 +688,13 @@ status_t BnOMX::onTransact(
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 @@ sp<IMemory> MetadataRetrieverClient::captureFrame()
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 @@ status_t StagefrightRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
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 @@ status_t StagefrightRecorder::setParameter(
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(), &degrees)) {
+ return setParamVideoRotation(degrees);
+ }
} else if (key == "video-param-i-frames-interval") {
int32_t seconds;
if (safe_strtoi32(value.string(), &seconds)) {
@@ -1105,6 +1121,9 @@ status_t StagefrightRecorder::startMPEG4Recording() {
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 @@ status_t StagefrightRecorder::reset() {
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 @@ private:
int64_t mMaxFileSizeBytes;
int64_t mMaxFileDurationUs;
int64_t mTrackEveryTimeDurationUs;
+ int32_t mRotationDegrees; // Clockwise
String8 mParams;
int mOutputFd;
@@ -120,6 +121,7 @@ private:
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 @@ struct AwesomeLocalRenderer : public AwesomeRenderer {
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 @@ private:
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 @@ void AwesomeLocalRenderer::init(
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 @@ void AwesomeLocalRenderer::init(
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 @@ void AwesomeLocalRenderer::init(
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 @@ void AwesomeLocalRenderer::init(
if (mTarget == NULL) {
mTarget = new SoftwareRenderer(
colorFormat, surface, displayWidth, displayHeight,
- decodedWidth, decodedHeight);
+ decodedWidth, decodedHeight, rotationDegrees);
}
}
@@ -785,6 +816,12 @@ void AwesomePlayer::initRenderer_l() {
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 @@ void AwesomePlayer::initRenderer_l() {
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 @@ void AwesomePlayer::initRenderer_l() {
(OMX_COLOR_FORMATTYPE)format,
mISurface,
mVideoWidth, mVideoHeight,
- decodedWidth, decodedHeight);
+ decodedWidth, decodedHeight, rotationDegrees);
}
}
}
@@ -1625,7 +1663,22 @@ void AwesomePlayer::finishAsyncPrepare_l() {
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 @@ status_t AwesomePlayer::resume() {
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 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
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 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
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 @@ MPEG4Source::MPEG4Source(
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 @@ status_t MPEG4Source::read(
}
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 @@ status_t MPEG4Source::read(
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 @@ private:
// 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 @@ void MPEG4Writer::stopWriterThread() {
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 @@ status_t MPEG4Writer::stop() {
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 @@ MPEG4Writer::Track::Track(
mCodecSpecificData(NULL),
mCodecSpecificDataSize(0),
mGotAllCodecSpecificData(false),
- mReachedEOS(false) {
+ mReachedEOS(false),
+ mRotation(0) {
getCodecSpecificDataFromInputFormatIfPossible();
const char *mime;
@@ -1178,6 +1224,11 @@ status_t MPEG4Writer::Track::start(MetaData *params) {
startTimeUs = 0;
}
+ int32_t rotationDegrees;
+ if (!mIsAudio && params && params->findInt32(kKeyRotationDegree, &rotationDegrees)) {
+ mRotation = rotationDegrees;
+ }
+
mIsRealTimeRecording = true;
{
int32_t isNotRealTime;
@@ -2071,15 +2122,7 @@ void MPEG4Writer::Track::writeTrackHeader(
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 @@ uint32_t OMXCodec::getComponentQuirks(
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 @@ void OMXCodec::on_message(const omx_message &msg) {
"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 @@ status_t OMXCodec::freeBuffersOnPort(
CHECK_EQ(info->mMediaBuffer->refcount(), 0);
info->mMediaBuffer->release();
+ info->mMediaBuffer = NULL;
}
buffers->removeAt(i);
@@ -2434,11 +2450,19 @@ void OMXCodec::drainInputBuffer(BufferInfo *info) {
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 @@ void OMXCodec::drainInputBuffer(BufferInfo *info) {
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 @@ static VideoFrame *extractVideoFrameWithCodecFlags(
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 @@ static VideoFrame *extractVideoFrameWithCodecFlags(
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 @@ SoftwareRenderer::SoftwareRenderer(
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 @@ SoftwareRenderer::SoftwareRenderer(
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 @@ private:
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 @@ public:
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 @@ public:
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 @@ sp<IOMXRenderer> OMX::createRenderer(
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 @@ sp<IOMXRenderer> OMX::createRenderer(
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 @@ sp<IOMXRenderer> OMX::createRenderer(
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");
-
- if (func) {
- impl = (*func)(surface, componentName, colorFormat,
- displayWidth, displayHeight, encodedWidth, encodedHeight);
-
- if (impl) {
- impl = new SharedVideoRenderer(libHandle, impl);
- libHandle = NULL;
+ "_Z26createRendererWithRotationRKN7android2spINS_8"
+ "ISurfaceEEEPKc20OMX_COLOR_FORMATTYPEjjjji");
+
+ if (funcWithRotation) {
+ impl = (*funcWithRotation)(
+ surface, componentName, colorFormat,
+ displayWidth, displayHeight, encodedWidth, encodedHeight,
+ rotationDegrees);
+ } else {
+ CreateRendererFunc func =
+ (CreateRendererFunc)dlsym(
+ libHandle,
+ "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
+ "OMX_COLOR_FORMATTYPEjjjj");
+
+ 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;