From ddcc4a66d848deef6fb4689e64e30cd9bd2684fe Mon Sep 17 00:00:00 2001 From: James Dong Date: Tue, 8 Jun 2010 11:58:53 -0700 Subject: Remove some hard-coded encoding parameters Change-Id: I7a8ccd5d57891a6a585c8da2ee53acb094955913 --- include/media/stagefright/MetaData.h | 11 +-- include/media/stagefright/OMXCodec.h | 7 +- .../libmediaplayerservice/StagefrightRecorder.cpp | 33 ++++++++- media/libmediaplayerservice/StagefrightRecorder.h | 2 + media/libstagefright/CameraSource.cpp | 10 ++- media/libstagefright/OMXCodec.cpp | 81 +++++++++++++++------- 6 files changed, 109 insertions(+), 35 deletions(-) diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h index dc2bd502..6a206027 100644 --- a/include/media/stagefright/MetaData.h +++ b/include/media/stagefright/MetaData.h @@ -30,10 +30,13 @@ namespace android { // The following keys map to int32_t data unless indicated otherwise. enum { kKeyMIMEType = 'mime', // cstring - kKeyWidth = 'widt', - kKeyHeight = 'heig', - kKeyChannelCount = '#chn', - kKeySampleRate = 'srte', + kKeyWidth = 'widt', // int32_t + kKeyHeight = 'heig', // int32_t + kKeyIFramesInterval = 'ifiv', // int32_t + kKeyStride = 'strd', // int32_t + kKeySliceHeight = 'slht', // int32_t + kKeyChannelCount = '#chn', // int32_t + kKeySampleRate = 'srte', // int32_t kKeyBitRate = 'brte', // int32_t (bps) kKeyESDS = 'esds', // raw data kKeyAVCC = 'avcc', // raw data diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h index aceeab8b..3fbb4697 100644 --- a/include/media/stagefright/OMXCodec.h +++ b/include/media/stagefright/OMXCodec.h @@ -166,11 +166,10 @@ private: OMX_COLOR_FORMATTYPE colorFormat); void setVideoInputFormat( - const char *mime, OMX_U32 width, OMX_U32 height, - OMX_U32 frameRate, OMX_U32 bitRate); + const char *mime, const sp& meta); - status_t setupMPEG4EncoderParameters(); - status_t setupAVCEncoderParameters(); + status_t setupMPEG4EncoderParameters(const sp& meta); + status_t setupAVCEncoderParameters(const sp& meta); status_t setVideoOutputFormat( const char *mime, OMX_U32 width, OMX_U32 height); diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 572389f2..1a684a96 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -287,14 +287,32 @@ status_t StagefrightRecorder::setParamMaxDurationOrFileSize(int64_t limit, status_t StagefrightRecorder::setParamInterleaveDuration(int32_t durationUs) { LOGV("setParamInterleaveDuration: %d", durationUs); - if (durationUs <= 20000) { // XXX: 20 ms + if (durationUs <= 500000) { // 500 ms + // If interleave duration is too small, it is very inefficient to do + // interleaving since the metadata overhead will count for a significant + // portion of the saved contents LOGE("Audio/video interleave duration is too small: %d us", durationUs); return BAD_VALUE; + } else if (durationUs >= 10000000) { // 10 seconds + // If interleaving duration is too large, it can cause the recording + // session to use too much memory since we have to save the output + // data before we write them out + LOGE("Audio/video interleave duration is too large: %d us", durationUs); + return BAD_VALUE; } mInterleaveDurationUs = durationUs; return OK; } +// If interval < 0, only the first frame is I frame, and rest are all P frames +// If interval == 0, all frames are encoded as I frames. No P frames +// If interval > 0, it is the time spacing between 2 neighboring I frames +status_t StagefrightRecorder::setParamIFramesInterval(int32_t interval) { + LOGV("setParamIFramesInterval: %d seconds", interval); + mIFramesInterval = interval; + return OK; +} + status_t StagefrightRecorder::setParameter( const String8 &key, const String8 &value) { LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string()); @@ -335,6 +353,11 @@ status_t StagefrightRecorder::setParameter( if (safe_strtoi32(value.string(), &durationUs)) { return setParamInterleaveDuration(durationUs); } + } else if (key == "param-i-frames-interval") { + int32_t interval; + if (safe_strtoi32(value.string(), &interval)) { + return setParamIFramesInterval(interval); + } } else { LOGE("setParameter: failed to find key %s", key.string()); } @@ -619,12 +642,17 @@ status_t StagefrightRecorder::startMPEG4Recording() { sp meta = cameraSource->getFormat(); - int32_t width, height; + int32_t width, height, stride, sliceHeight; CHECK(meta->findInt32(kKeyWidth, &width)); CHECK(meta->findInt32(kKeyHeight, &height)); + CHECK(meta->findInt32(kKeyStride, &stride)); + CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight)); enc_meta->setInt32(kKeyWidth, width); enc_meta->setInt32(kKeyHeight, height); + enc_meta->setInt32(kKeyIFramesInterval, mIFramesInterval); + enc_meta->setInt32(kKeyStride, stride); + enc_meta->setInt32(kKeySliceHeight, sliceHeight); OMXClient client; CHECK_EQ(client.connect(), OK); @@ -702,6 +730,7 @@ status_t StagefrightRecorder::reset() { mAudioChannels = 1; mAudioBitRate = 12200; mInterleaveDurationUs = 0; + mIFramesInterval = 1; mOutputFd = -1; mFlags = 0; diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index b7d554b5..b491e9fb 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -75,6 +75,7 @@ private: int32_t mAudioChannels; int32_t mSampleRate; int32_t mInterleaveDurationUs; + int32_t mIFramesInterval; int64_t mMaxFileSizeBytes; int64_t mMaxFileDurationUs; @@ -92,6 +93,7 @@ private: status_t setParamAudioNumberOfChannels(int32_t channles); status_t setParamAudioSamplingRate(int32_t sampleRate); status_t setParamInterleaveDuration(int32_t durationUs); + status_t setParamIFramesInterval(int32_t interval); status_t setParamMaxDurationOrFileSize(int64_t limit, bool limit_is_duration); StagefrightRecorder(const StagefrightRecorder &); diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index 416b75ca..67759c05 100644 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -128,7 +128,7 @@ CameraSource::CameraSource(const sp &camera) String8 s = mCamera->getParameters(); printf("params: \"%s\"\n", s.string()); - int32_t width, height; + int32_t width, height, stride, sliceHeight; CameraParameters params(s); params.getPreviewSize(&width, &height); @@ -136,11 +136,19 @@ CameraSource::CameraSource(const sp &camera) CHECK(colorFormatStr != NULL); int32_t colorFormat = getColorFormat(colorFormatStr); + // XXX: query camera for the stride and slice height + // when the capability becomes available. + stride = width; + sliceHeight = height; + mMeta = new MetaData; mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); mMeta->setInt32(kKeyColorFormat, colorFormat); mMeta->setInt32(kKeyWidth, width); mMeta->setInt32(kKeyHeight, height); + mMeta->setInt32(kKeyStride, stride); + mMeta->setInt32(kKeySliceHeight, sliceHeight); + } CameraSource::~CameraSource() { diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 7c3df310..ba357486 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -571,17 +571,14 @@ status_t OMXCodec::configureCodec(const sp &meta) { } if (!strncasecmp(mMIME, "video/", 6)) { - int32_t width, height; - bool success = meta->findInt32(kKeyWidth, &width); - success = success && meta->findInt32(kKeyHeight, &height); - CHECK(success); if (mIsEncoder) { - int32_t frameRate = 25; // XXX - int32_t bitRate = 3000000; // bit rate - //success = success && meta->findInt32(kKeySampleRate, &frameRate); - setVideoInputFormat(mMIME, width, height, frameRate, bitRate); + setVideoInputFormat(mMIME, meta); } else { + int32_t width, height; + bool success = meta->findInt32(kKeyWidth, &width); + success = success && meta->findInt32(kKeyHeight, &height); + CHECK(success); status_t err = setVideoOutputFormat( mMIME, width, height); @@ -745,9 +742,17 @@ static size_t getFrameSize( } void OMXCodec::setVideoInputFormat( - const char *mime, OMX_U32 width, OMX_U32 height, - OMX_U32 frameRate, OMX_U32 bitRate) { - CODEC_LOGV("setVideoInputFormat width=%ld, height=%ld", width, height); + const char *mime, const sp& meta) { + + int32_t width, height, frameRate, bitRate, stride, sliceHeight; + bool success = meta->findInt32(kKeyWidth, &width); + success = success && meta->findInt32(kKeyHeight, &height); + success = success && meta->findInt32(kKeySampleRate, &frameRate); + success = success && meta->findInt32(kKeyBitRate, &bitRate); + success = success && meta->findInt32(kKeyStride, &stride); + success = success && meta->findInt32(kKeySliceHeight, &sliceHeight); + CHECK(success); + CHECK(stride != 0); OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused; if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { @@ -766,8 +771,6 @@ void OMXCodec::setVideoInputFormat( colorFormat = OMX_COLOR_FormatYCbYCr; } - - status_t err; OMX_PARAM_PORTDEFINITIONTYPE def; OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video; @@ -784,12 +787,15 @@ void OMXCodec::setVideoInputFormat( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); CHECK_EQ(err, OK); - def.nBufferSize = getFrameSize(colorFormat, width, height); + def.nBufferSize = getFrameSize(colorFormat, + stride > 0? stride: -stride, sliceHeight); CHECK_EQ(def.eDomain, OMX_PortDomainVideo); video_def->nFrameWidth = width; video_def->nFrameHeight = height; + video_def->nStride = stride; + video_def->nSliceHeight = sliceHeight; video_def->xFramerate = (frameRate << 16); // Q16 format video_def->eCompressionFormat = OMX_VIDEO_CodingUnused; video_def->eColorFormat = colorFormat; @@ -826,7 +832,7 @@ void OMXCodec::setVideoInputFormat( switch (compressionFormat) { case OMX_VIDEO_CodingMPEG4: { - CHECK_EQ(setupMPEG4EncoderParameters(), OK); + CHECK_EQ(setupMPEG4EncoderParameters(meta), OK); break; } @@ -835,7 +841,7 @@ void OMXCodec::setVideoInputFormat( case OMX_VIDEO_CodingAVC: { - CHECK_EQ(setupAVCEncoderParameters(), OK); + CHECK_EQ(setupAVCEncoderParameters(meta), OK); break; } @@ -845,7 +851,23 @@ void OMXCodec::setVideoInputFormat( } } -status_t OMXCodec::setupMPEG4EncoderParameters() { +static OMX_U32 setPFramesSpacing(int32_t iFramesInterval, int32_t frameRate) { + if (iFramesInterval < 0) { + return 0xFFFFFFFF; + } else if (iFramesInterval == 0) { + return 0; + } + OMX_U32 ret = frameRate * iFramesInterval; + CHECK(ret > 1); + return ret; +} + +status_t OMXCodec::setupMPEG4EncoderParameters(const sp& meta) { + int32_t iFramesInterval, frameRate, bitRate; + bool success = meta->findInt32(kKeyBitRate, &bitRate); + success = success && meta->findInt32(kKeySampleRate, &frameRate); + success = success && meta->findInt32(kKeyIFramesInterval, &iFramesInterval); + CHECK(success); OMX_VIDEO_PARAM_MPEG4TYPE mpeg4type; InitOMXParams(&mpeg4type); mpeg4type.nPortIndex = kPortIndexOutput; @@ -861,9 +883,11 @@ status_t OMXCodec::setupMPEG4EncoderParameters() { mpeg4type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP; - mpeg4type.nPFrames = 23; + mpeg4type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate); + if (mpeg4type.nPFrames == 0) { + mpeg4type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI; + } mpeg4type.nBFrames = 0; - mpeg4type.nIDCVLCThreshold = 0; mpeg4type.bACPred = OMX_TRUE; mpeg4type.nMaxPacketSize = 256; @@ -890,7 +914,7 @@ status_t OMXCodec::setupMPEG4EncoderParameters() { CHECK_EQ(err, OK); bitrateType.eControlRate = OMX_Video_ControlRateVariable; - bitrateType.nTargetBitrate = 1000000; + bitrateType.nTargetBitrate = bitRate; err = mOMX->setParameter( mNode, OMX_IndexParamVideoBitrate, @@ -922,7 +946,13 @@ status_t OMXCodec::setupMPEG4EncoderParameters() { return OK; } -status_t OMXCodec::setupAVCEncoderParameters() { +status_t OMXCodec::setupAVCEncoderParameters(const sp& meta) { + int32_t iFramesInterval, frameRate, bitRate; + bool success = meta->findInt32(kKeyBitRate, &bitRate); + success = success && meta->findInt32(kKeySampleRate, &frameRate); + success = success && meta->findInt32(kKeyIFramesInterval, &iFramesInterval); + CHECK(success); + OMX_VIDEO_PARAM_AVCTYPE h264type; InitOMXParams(&h264type); h264type.nPortIndex = kPortIndexOutput; @@ -935,8 +965,11 @@ status_t OMXCodec::setupAVCEncoderParameters() { OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP; h264type.nSliceHeaderSpacing = 0; - h264type.nBFrames = 0; - h264type.nPFrames = 24; // XXX + h264type.nBFrames = 0; // No B frames support yet + h264type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate); + if (h264type.nPFrames == 0) { + h264type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI; + } h264type.bUseHadamard = OMX_TRUE; h264type.nRefFrames = 1; h264type.nRefIdx10ActiveMinus1 = 0; @@ -969,7 +1002,7 @@ status_t OMXCodec::setupAVCEncoderParameters() { CHECK_EQ(err, OK); bitrateType.eControlRate = OMX_Video_ControlRateVariable; - bitrateType.nTargetBitrate = 3000000; // XXX + bitrateType.nTargetBitrate = bitRate; err = mOMX->setParameter( mNode, OMX_IndexParamVideoBitrate, -- cgit v1.2.3