Merge "Rotation support" into gingerbread

This commit is contained in:
James Dong
2010-11-05 16:58:51 -07:00
committed by Android (Google) Code Review
5 changed files with 86 additions and 19 deletions

View File

@ -154,6 +154,7 @@ private:
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 &);

View File

@ -90,6 +90,7 @@ enum {
// 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)

View File

@ -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;

View File

@ -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);

View File

@ -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);