Merge "Allow application to set two more encoding paramters: video profile and level" into gingerbread
This commit is contained in:
@ -69,6 +69,10 @@ enum {
|
||||
kKeyDate = 'date', // cstring
|
||||
kKeyWriter = 'writ', // cstring
|
||||
|
||||
// video profile and level
|
||||
kKeyVideoProfile = 'vprf', // int32_t
|
||||
kKeyVideoLevel = 'vlev', // int32_t
|
||||
|
||||
// Set this key to enable authoring files in 64-bit offset
|
||||
kKey64BitFileOffset = 'fobt', // int32_t (bool)
|
||||
|
||||
|
@ -27,6 +27,7 @@ namespace android {
|
||||
|
||||
class MemoryDealer;
|
||||
struct OMXCodecObserver;
|
||||
struct CodecProfileLevel;
|
||||
|
||||
struct OMXCodec : public MediaSource,
|
||||
public MediaBufferObserver {
|
||||
@ -178,6 +179,12 @@ private:
|
||||
status_t setupMPEG4EncoderParameters(const sp<MetaData>& meta);
|
||||
status_t setupAVCEncoderParameters(const sp<MetaData>& meta);
|
||||
|
||||
// If profile/level is set in the meta data, its value in the meta
|
||||
// data will be used; otherwise, the default value will be used.
|
||||
status_t getVideoProfileLevel(const sp<MetaData>& meta,
|
||||
const CodecProfileLevel& defaultProfileLevel,
|
||||
CodecProfileLevel& profileLevel);
|
||||
|
||||
status_t setVideoOutputFormat(
|
||||
const char *mime, OMX_U32 width, OMX_U32 height);
|
||||
|
||||
|
@ -426,6 +426,24 @@ status_t StagefrightRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t StagefrightRecorder::setParamVideoEncoderProfile(int32_t profile) {
|
||||
LOGV("setParamVideoEncoderProfile: %d", profile);
|
||||
|
||||
// Additional check will be done later when we load the encoder.
|
||||
// For now, we are accepting values defined in OpenMAX IL.
|
||||
mVideoEncoderProfile = profile;
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t StagefrightRecorder::setParamVideoEncoderLevel(int32_t level) {
|
||||
LOGV("setParamVideoEncoderLevel: %d", level);
|
||||
|
||||
// Additional check will be done later when we load the encoder.
|
||||
// For now, we are accepting values defined in OpenMAX IL.
|
||||
mVideoEncoderLevel = level;
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t StagefrightRecorder::setParameter(
|
||||
const String8 &key, const String8 &value) {
|
||||
LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
|
||||
@ -484,6 +502,16 @@ status_t StagefrightRecorder::setParameter(
|
||||
if (safe_strtoi32(value.string(), &interval)) {
|
||||
return setParamVideoIFramesInterval(interval);
|
||||
}
|
||||
} else if (key == "video-param-encoder-profile") {
|
||||
int32_t profile;
|
||||
if (safe_strtoi32(value.string(), &profile)) {
|
||||
return setParamVideoEncoderProfile(profile);
|
||||
}
|
||||
} else if (key == "video-param-encoder-level") {
|
||||
int32_t level;
|
||||
if (safe_strtoi32(value.string(), &level)) {
|
||||
return setParamVideoEncoderLevel(level);
|
||||
}
|
||||
} else if (key == "video-param-camera-id") {
|
||||
int32_t cameraId;
|
||||
if (safe_strtoi32(value.string(), &cameraId)) {
|
||||
@ -851,6 +879,12 @@ status_t StagefrightRecorder::setupVideoEncoder(const sp<MediaWriter>& writer) {
|
||||
enc_meta->setInt32(kKeyIFramesInterval, mIFramesInterval);
|
||||
enc_meta->setInt32(kKeyStride, stride);
|
||||
enc_meta->setInt32(kKeySliceHeight, sliceHeight);
|
||||
if (mVideoEncoderProfile != -1) {
|
||||
enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
|
||||
}
|
||||
if (mVideoEncoderLevel != -1) {
|
||||
enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel);
|
||||
}
|
||||
|
||||
OMXClient client;
|
||||
CHECK_EQ(client.connect(), OK);
|
||||
@ -992,6 +1026,10 @@ status_t StagefrightRecorder::reset() {
|
||||
mAudioSourceNode = 0;
|
||||
mUse64BitFileOffset = false;
|
||||
mCameraId = 0;
|
||||
mVideoEncoderProfile = -1;
|
||||
mVideoEncoderLevel = -1;
|
||||
mMaxFileDurationUs = 0;
|
||||
mMaxFileSizeBytes = 0;
|
||||
mTrackEveryNumberOfFrames = 0;
|
||||
mTrackEveryTimeDurationUs = 0;
|
||||
mEncoderProfiles = MediaProfiles::getInstance();
|
||||
|
@ -82,6 +82,8 @@ private:
|
||||
int32_t mInterleaveDurationUs;
|
||||
int32_t mIFramesInterval;
|
||||
int32_t mCameraId;
|
||||
int32_t mVideoEncoderProfile;
|
||||
int32_t mVideoEncoderLevel;
|
||||
int64_t mMaxFileSizeBytes;
|
||||
int64_t mMaxFileDurationUs;
|
||||
int32_t mTrackEveryNumberOfFrames;
|
||||
@ -108,6 +110,8 @@ private:
|
||||
status_t setParamAudioSamplingRate(int32_t sampleRate);
|
||||
status_t setParamVideoEncodingBitRate(int32_t bitRate);
|
||||
status_t setParamVideoIFramesInterval(int32_t interval);
|
||||
status_t setParamVideoEncoderProfile(int32_t profile);
|
||||
status_t setParamVideoEncoderLevel(int32_t level);
|
||||
status_t setParamVideoCameraId(int32_t cameraId);
|
||||
status_t setParamTrackTimeStatus(int64_t timeDurationUs);
|
||||
status_t setParamTrackFrameStatus(int32_t nFrames);
|
||||
|
@ -831,7 +831,7 @@ void OMXCodec::setVideoInputFormat(
|
||||
|
||||
video_def->nFrameWidth = width;
|
||||
video_def->nFrameHeight = height;
|
||||
video_def->xFramerate = (frameRate << 16); // Q16 format
|
||||
video_def->xFramerate = 0; // No need for output port
|
||||
video_def->nBitrate = bitRate; // Q16 format
|
||||
video_def->eCompressionFormat = compressionFormat;
|
||||
video_def->eColorFormat = OMX_COLOR_FormatUnused;
|
||||
@ -918,6 +918,52 @@ status_t OMXCodec::setupBitRate(int32_t bitRate) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t OMXCodec::getVideoProfileLevel(
|
||||
const sp<MetaData>& meta,
|
||||
const CodecProfileLevel& defaultProfileLevel,
|
||||
CodecProfileLevel &profileLevel) {
|
||||
CODEC_LOGV("Default profile: %ld, level %ld",
|
||||
defaultProfileLevel.mProfile, defaultProfileLevel.mLevel);
|
||||
|
||||
// Are the default profile and level overwriten?
|
||||
int32_t profile, level;
|
||||
if (!meta->findInt32(kKeyVideoProfile, &profile)) {
|
||||
profile = defaultProfileLevel.mProfile;
|
||||
}
|
||||
if (!meta->findInt32(kKeyVideoLevel, &level)) {
|
||||
level = defaultProfileLevel.mLevel;
|
||||
}
|
||||
CODEC_LOGV("Target profile: %d, level: %d", profile, level);
|
||||
|
||||
// Are the target profile and level supported by the encoder?
|
||||
OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
|
||||
InitOMXParams(¶m);
|
||||
param.nPortIndex = kPortIndexOutput;
|
||||
for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
|
||||
status_t err = mOMX->getParameter(
|
||||
mNode, OMX_IndexParamVideoProfileLevelQuerySupported,
|
||||
¶m, sizeof(param));
|
||||
|
||||
if (err != OK) return err;
|
||||
|
||||
int32_t supportedProfile = static_cast<int32_t>(param.eProfile);
|
||||
int32_t supportedLevel = static_cast<int32_t>(param.eLevel);
|
||||
CODEC_LOGV("Supported profile: %ld, level %ld",
|
||||
supportedProfile, supportedLevel);
|
||||
|
||||
if (profile == supportedProfile &&
|
||||
level == supportedLevel) {
|
||||
profileLevel.mProfile = profile;
|
||||
profileLevel.mLevel = level;
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
CODEC_LOGE("Target profile (%d) and level (%d) is not supported",
|
||||
profile, level);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
status_t OMXCodec::setupH263EncoderParameters(const sp<MetaData>& meta) {
|
||||
int32_t iFramesInterval, frameRate, bitRate;
|
||||
bool success = meta->findInt32(kKeyBitRate, &bitRate);
|
||||
@ -941,8 +987,14 @@ status_t OMXCodec::setupH263EncoderParameters(const sp<MetaData>& meta) {
|
||||
}
|
||||
h263type.nBFrames = 0;
|
||||
|
||||
h263type.eProfile = OMX_VIDEO_H263ProfileBaseline;
|
||||
h263type.eLevel = OMX_VIDEO_H263Level45;
|
||||
// Check profile and level parameters
|
||||
CodecProfileLevel defaultProfileLevel, profileLevel;
|
||||
defaultProfileLevel.mProfile = OMX_VIDEO_H263ProfileBaseline;
|
||||
defaultProfileLevel.mLevel = OMX_VIDEO_H263Level45;
|
||||
err = getVideoProfileLevel(meta, defaultProfileLevel, profileLevel);
|
||||
if (err != OK) return err;
|
||||
h263type.eProfile = static_cast<OMX_VIDEO_H263PROFILETYPE>(profileLevel.mProfile);
|
||||
h263type.eLevel = static_cast<OMX_VIDEO_H263LEVELTYPE>(profileLevel.mLevel);
|
||||
|
||||
h263type.bPLUSPTYPEAllowed = OMX_FALSE;
|
||||
h263type.bForceRoundingTypeToZero = OMX_FALSE;
|
||||
@ -992,8 +1044,14 @@ status_t OMXCodec::setupMPEG4EncoderParameters(const sp<MetaData>& meta) {
|
||||
mpeg4type.nHeaderExtension = 0;
|
||||
mpeg4type.bReversibleVLC = OMX_FALSE;
|
||||
|
||||
mpeg4type.eProfile = OMX_VIDEO_MPEG4ProfileSimple;
|
||||
mpeg4type.eLevel = OMX_VIDEO_MPEG4Level2;
|
||||
// Check profile and level parameters
|
||||
CodecProfileLevel defaultProfileLevel, profileLevel;
|
||||
defaultProfileLevel.mProfile = OMX_VIDEO_MPEG4ProfileSimple;
|
||||
defaultProfileLevel.mLevel = OMX_VIDEO_MPEG4Level2;
|
||||
err = getVideoProfileLevel(meta, defaultProfileLevel, profileLevel);
|
||||
if (err != OK) return err;
|
||||
mpeg4type.eProfile = static_cast<OMX_VIDEO_MPEG4PROFILETYPE>(profileLevel.mProfile);
|
||||
mpeg4type.eLevel = static_cast<OMX_VIDEO_MPEG4LEVELTYPE>(profileLevel.mLevel);
|
||||
|
||||
err = mOMX->setParameter(
|
||||
mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type));
|
||||
@ -1029,22 +1087,39 @@ status_t OMXCodec::setupAVCEncoderParameters(const sp<MetaData>& meta) {
|
||||
if (h264type.nPFrames == 0) {
|
||||
h264type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
|
||||
}
|
||||
|
||||
// Check profile and level parameters
|
||||
CodecProfileLevel defaultProfileLevel, profileLevel;
|
||||
defaultProfileLevel.mProfile = h264type.eProfile;
|
||||
defaultProfileLevel.mLevel = h264type.eLevel;
|
||||
err = getVideoProfileLevel(meta, defaultProfileLevel, profileLevel);
|
||||
if (err != OK) return err;
|
||||
h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profileLevel.mProfile);
|
||||
h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(profileLevel.mLevel);
|
||||
|
||||
if (h264type.eProfile == OMX_VIDEO_AVCProfileBaseline) {
|
||||
h264type.bUseHadamard = OMX_TRUE;
|
||||
h264type.nRefFrames = 1;
|
||||
h264type.nRefIdx10ActiveMinus1 = 0;
|
||||
h264type.nRefIdx11ActiveMinus1 = 0;
|
||||
h264type.bEnableUEP = OMX_FALSE;
|
||||
h264type.bEnableFMO = OMX_FALSE;
|
||||
h264type.bEnableASO = OMX_FALSE;
|
||||
h264type.bEnableRS = OMX_FALSE;
|
||||
h264type.bFrameMBsOnly = OMX_TRUE;
|
||||
h264type.bMBAFF = OMX_FALSE;
|
||||
h264type.bEntropyCodingCABAC = OMX_FALSE;
|
||||
h264type.bWeightedPPrediction = OMX_FALSE;
|
||||
h264type.bconstIpred = OMX_FALSE;
|
||||
h264type.bDirect8x8Inference = OMX_FALSE;
|
||||
h264type.bDirectSpatialTemporal = OMX_FALSE;
|
||||
h264type.nCabacInitIdc = 0;
|
||||
}
|
||||
|
||||
if (h264type.nBFrames != 0) {
|
||||
h264type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB;
|
||||
}
|
||||
|
||||
h264type.bEnableUEP = OMX_FALSE;
|
||||
h264type.bEnableFMO = OMX_FALSE;
|
||||
h264type.bEnableASO = OMX_FALSE;
|
||||
h264type.bEnableRS = OMX_FALSE;
|
||||
h264type.bFrameMBsOnly = OMX_TRUE;
|
||||
h264type.bMBAFF = OMX_FALSE;
|
||||
h264type.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterEnable;
|
||||
|
||||
err = mOMX->setParameter(
|
||||
|
Reference in New Issue
Block a user