Merge "Rotation support" into gingerbread
This commit is contained in:
@ -154,6 +154,7 @@ private:
|
|||||||
bool exceedsFileDurationLimit();
|
bool exceedsFileDurationLimit();
|
||||||
bool isFileStreamable() const;
|
bool isFileStreamable() const;
|
||||||
void trackProgressStatus(const Track* track, int64_t timeUs, status_t err = OK);
|
void trackProgressStatus(const Track* track, int64_t timeUs, status_t err = OK);
|
||||||
|
void writeCompositionMatrix(int32_t degrees);
|
||||||
|
|
||||||
MPEG4Writer(const MPEG4Writer &);
|
MPEG4Writer(const MPEG4Writer &);
|
||||||
MPEG4Writer &operator=(const MPEG4Writer &);
|
MPEG4Writer &operator=(const MPEG4Writer &);
|
||||||
|
@ -90,6 +90,7 @@ enum {
|
|||||||
// Track authoring progress status
|
// Track authoring progress status
|
||||||
// kKeyTrackTimeStatus is used to track progress in elapsed time
|
// kKeyTrackTimeStatus is used to track progress in elapsed time
|
||||||
kKeyTrackTimeStatus = 'tktm', // int64_t
|
kKeyTrackTimeStatus = 'tktm', // int64_t
|
||||||
|
kKeyRotationDegree = 'rdge', // int32_t (clockwise, in degree)
|
||||||
|
|
||||||
kKeyNotRealTime = 'ntrt', // bool (int32_t)
|
kKeyNotRealTime = 'ntrt', // bool (int32_t)
|
||||||
|
|
||||||
|
@ -340,6 +340,17 @@ status_t StagefrightRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
|
|||||||
return OK;
|
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) {
|
status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
|
||||||
LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
|
LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
|
||||||
if (timeUs <= 0) {
|
if (timeUs <= 0) {
|
||||||
@ -532,6 +543,11 @@ status_t StagefrightRecorder::setParameter(
|
|||||||
if (safe_strtoi32(value.string(), &video_bitrate)) {
|
if (safe_strtoi32(value.string(), &video_bitrate)) {
|
||||||
return setParamVideoEncodingBitRate(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") {
|
} else if (key == "video-param-i-frames-interval") {
|
||||||
int32_t seconds;
|
int32_t seconds;
|
||||||
if (safe_strtoi32(value.string(), &seconds)) {
|
if (safe_strtoi32(value.string(), &seconds)) {
|
||||||
@ -1105,6 +1121,9 @@ status_t StagefrightRecorder::startMPEG4Recording() {
|
|||||||
if (mTrackEveryTimeDurationUs > 0) {
|
if (mTrackEveryTimeDurationUs > 0) {
|
||||||
meta->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
|
meta->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
|
||||||
}
|
}
|
||||||
|
if (mRotationDegrees != 0) {
|
||||||
|
meta->setInt32(kKeyRotationDegree, mRotationDegrees);
|
||||||
|
}
|
||||||
writer->setListener(mListener);
|
writer->setListener(mListener);
|
||||||
mWriter = writer;
|
mWriter = writer;
|
||||||
return mWriter->start(meta.get());
|
return mWriter->start(meta.get());
|
||||||
@ -1187,6 +1206,7 @@ status_t StagefrightRecorder::reset() {
|
|||||||
mMaxFileDurationUs = 0;
|
mMaxFileDurationUs = 0;
|
||||||
mMaxFileSizeBytes = 0;
|
mMaxFileSizeBytes = 0;
|
||||||
mTrackEveryTimeDurationUs = 0;
|
mTrackEveryTimeDurationUs = 0;
|
||||||
|
mRotationDegrees = 0;
|
||||||
mEncoderProfiles = MediaProfiles::getInstance();
|
mEncoderProfiles = MediaProfiles::getInstance();
|
||||||
|
|
||||||
mOutputFd = -1;
|
mOutputFd = -1;
|
||||||
|
@ -91,6 +91,7 @@ private:
|
|||||||
int64_t mMaxFileSizeBytes;
|
int64_t mMaxFileSizeBytes;
|
||||||
int64_t mMaxFileDurationUs;
|
int64_t mMaxFileDurationUs;
|
||||||
int64_t mTrackEveryTimeDurationUs;
|
int64_t mTrackEveryTimeDurationUs;
|
||||||
|
int32_t mRotationDegrees; // Clockwise
|
||||||
|
|
||||||
String8 mParams;
|
String8 mParams;
|
||||||
int mOutputFd;
|
int mOutputFd;
|
||||||
@ -120,6 +121,7 @@ private:
|
|||||||
status_t setParamVideoEncoderLevel(int32_t level);
|
status_t setParamVideoEncoderLevel(int32_t level);
|
||||||
status_t setParamVideoCameraId(int32_t cameraId);
|
status_t setParamVideoCameraId(int32_t cameraId);
|
||||||
status_t setParamVideoTimeScale(int32_t timeScale);
|
status_t setParamVideoTimeScale(int32_t timeScale);
|
||||||
|
status_t setParamVideoRotation(int32_t degrees);
|
||||||
status_t setParamTrackTimeStatus(int64_t timeDurationUs);
|
status_t setParamTrackTimeStatus(int64_t timeDurationUs);
|
||||||
status_t setParamInterleaveDuration(int32_t durationUs);
|
status_t setParamInterleaveDuration(int32_t durationUs);
|
||||||
status_t setParam64BitFileOffset(bool use64BitFileOffset);
|
status_t setParam64BitFileOffset(bool use64BitFileOffset);
|
||||||
|
@ -202,6 +202,7 @@ private:
|
|||||||
|
|
||||||
// Simple validation on the codec specific data
|
// Simple validation on the codec specific data
|
||||||
status_t checkCodecSpecificData() const;
|
status_t checkCodecSpecificData() const;
|
||||||
|
int32_t mRotation;
|
||||||
|
|
||||||
void updateTrackSizeEstimate();
|
void updateTrackSizeEstimate();
|
||||||
void addOneStscTableEntry(size_t chunkId, size_t sampleId);
|
void addOneStscTableEntry(size_t chunkId, size_t sampleId);
|
||||||
@ -519,6 +520,58 @@ void MPEG4Writer::stopWriterThread() {
|
|||||||
pthread_join(mThread, &dummy);
|
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() {
|
status_t MPEG4Writer::stop() {
|
||||||
if (mFile == NULL) {
|
if (mFile == NULL) {
|
||||||
return OK;
|
return OK;
|
||||||
@ -584,15 +637,7 @@ status_t MPEG4Writer::stop() {
|
|||||||
writeInt16(0); // reserved
|
writeInt16(0); // reserved
|
||||||
writeInt32(0); // reserved
|
writeInt32(0); // reserved
|
||||||
writeInt32(0); // reserved
|
writeInt32(0); // reserved
|
||||||
writeInt32(0x10000); // matrix
|
writeCompositionMatrix(0);
|
||||||
writeInt32(0);
|
|
||||||
writeInt32(0);
|
|
||||||
writeInt32(0);
|
|
||||||
writeInt32(0x10000);
|
|
||||||
writeInt32(0);
|
|
||||||
writeInt32(0);
|
|
||||||
writeInt32(0);
|
|
||||||
writeInt32(0x40000000);
|
|
||||||
writeInt32(0); // predefined
|
writeInt32(0); // predefined
|
||||||
writeInt32(0); // predefined
|
writeInt32(0); // predefined
|
||||||
writeInt32(0); // predefined
|
writeInt32(0); // predefined
|
||||||
@ -885,7 +930,8 @@ MPEG4Writer::Track::Track(
|
|||||||
mCodecSpecificData(NULL),
|
mCodecSpecificData(NULL),
|
||||||
mCodecSpecificDataSize(0),
|
mCodecSpecificDataSize(0),
|
||||||
mGotAllCodecSpecificData(false),
|
mGotAllCodecSpecificData(false),
|
||||||
mReachedEOS(false) {
|
mReachedEOS(false),
|
||||||
|
mRotation(0) {
|
||||||
getCodecSpecificDataFromInputFormatIfPossible();
|
getCodecSpecificDataFromInputFormatIfPossible();
|
||||||
|
|
||||||
const char *mime;
|
const char *mime;
|
||||||
@ -1178,6 +1224,11 @@ status_t MPEG4Writer::Track::start(MetaData *params) {
|
|||||||
startTimeUs = 0;
|
startTimeUs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t rotationDegrees;
|
||||||
|
if (!mIsAudio && params && params->findInt32(kKeyRotationDegree, &rotationDegrees)) {
|
||||||
|
mRotation = rotationDegrees;
|
||||||
|
}
|
||||||
|
|
||||||
mIsRealTimeRecording = true;
|
mIsRealTimeRecording = true;
|
||||||
{
|
{
|
||||||
int32_t isNotRealTime;
|
int32_t isNotRealTime;
|
||||||
@ -2071,15 +2122,7 @@ void MPEG4Writer::Track::writeTrackHeader(
|
|||||||
mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume
|
mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume
|
||||||
mOwner->writeInt16(0); // reserved
|
mOwner->writeInt16(0); // reserved
|
||||||
|
|
||||||
mOwner->writeInt32(0x10000); // matrix
|
mOwner->writeCompositionMatrix(mRotation);
|
||||||
mOwner->writeInt32(0);
|
|
||||||
mOwner->writeInt32(0);
|
|
||||||
mOwner->writeInt32(0);
|
|
||||||
mOwner->writeInt32(0x10000);
|
|
||||||
mOwner->writeInt32(0);
|
|
||||||
mOwner->writeInt32(0);
|
|
||||||
mOwner->writeInt32(0);
|
|
||||||
mOwner->writeInt32(0x40000000);
|
|
||||||
|
|
||||||
if (mIsAudio) {
|
if (mIsAudio) {
|
||||||
mOwner->writeInt32(0);
|
mOwner->writeInt32(0);
|
||||||
|
Reference in New Issue
Block a user