summaryrefslogtreecommitdiffstats
path: root/media/libstagefright
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2010-11-04 11:50:27 -0700
committerJames Dong <jdong@google.com>2010-11-05 17:03:17 -0700
commit85d9b4225d024bb0d602b48bd6d5219cbebd7b8e (patch)
tree4d9ebf6a8b1ecfe51c312d7f2cfa7b2eda6fe5cf /media/libstagefright
parentaca1fe35480ae76dd6bae167ade40adc955e2d0d (diff)
downloadframeworks_av-85d9b4225d024bb0d602b48bd6d5219cbebd7b8e.zip
frameworks_av-85d9b4225d024bb0d602b48bd6d5219cbebd7b8e.tar.gz
frameworks_av-85d9b4225d024bb0d602b48bd6d5219cbebd7b8e.tar.bz2
Support post-decode video rotation.
Change-Id: Ia371316e73a57e44610de86adce3eaa560afbf84
Diffstat (limited to 'media/libstagefright')
-rw-r--r--media/libstagefright/AwesomePlayer.cpp88
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp140
-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
7 files changed, 214 insertions, 83 deletions
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/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;