C2SoftMpeg4Enc: add support for syncFramePeriod, profile and level information
Test: cts -m CtsMediaTestCases -t android.media.cts.VideoEncoderTest
Bug: 110265995
Change-Id: Ic01691039ef2c4c928a45731bc78ea3bcad8de37
diff --git a/media/codecs/mpeg4_h263/C2SoftMpeg4Enc.cpp b/media/codecs/mpeg4_h263/C2SoftMpeg4Enc.cpp
index ad97bad..4fca683 100644
--- a/media/codecs/mpeg4_h263/C2SoftMpeg4Enc.cpp
+++ b/media/codecs/mpeg4_h263/C2SoftMpeg4Enc.cpp
@@ -89,8 +89,13 @@
DefineParam(mSize, C2_NAME_STREAM_VIDEO_SIZE_SETTING)
.withDefault(new C2VideoSizeStreamTuning::input(0u, 176, 144))
.withFields({
+#ifdef MPEG4
C2F(mSize, width).inRange(16, 176, 16),
C2F(mSize, height).inRange(16, 144, 16),
+#else
+ C2F(mSize, width).inRange(176, 176, 16),
+ C2F(mSize, height).inRange(144, 144, 16),
+#endif
})
.withSetter(SizeSetter)
.build());
@@ -107,30 +112,109 @@
addParameter(
DefineParam(mBitrate, C2_NAME_STREAM_BITRATE_SETTING)
.withDefault(new C2BitrateTuning::output(0u, 64000))
- .withFields({C2F(mBitrate, value).inRange(1, 12000000)})
- .withSetter(
- Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps)
+ .withFields({C2F(mBitrate, value).inRange(4096, 12000000)})
+ .withSetter(BitrateSetter)
.build());
+
+ addParameter(
+ DefineParam(mSyncFramePeriod, C2_PARAMKEY_SYNC_FRAME_INTERVAL)
+ .withDefault(new C2StreamSyncFrameIntervalTuning::output(0u, 1000000))
+ .withFields({C2F(mSyncFramePeriod, value).any()})
+ .withSetter(Setter<decltype(*mSyncFramePeriod)>::StrictValueWithNoDeps)
+ .build());
+
+#ifdef MPEG4
+ addParameter(
+ DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
+ .withDefault(new C2StreamProfileLevelInfo::output(
+ 0u, PROFILE_MP4V_SIMPLE, LEVEL_MP4V_2))
+ .withFields({
+ C2F(mProfileLevel, profile).equalTo(
+ PROFILE_MP4V_SIMPLE),
+ C2F(mProfileLevel, level).oneOf({
+ C2Config::LEVEL_MP4V_0,
+ C2Config::LEVEL_MP4V_0B,
+ C2Config::LEVEL_MP4V_1,
+ C2Config::LEVEL_MP4V_2})
+ })
+ .withSetter(ProfileLevelSetter)
+ .build());
+#else
+ addParameter(
+ DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
+ .withDefault(new C2StreamProfileLevelInfo::output(
+ 0u, PROFILE_H263_BASELINE, LEVEL_H263_45))
+ .withFields({
+ C2F(mProfileLevel, profile).equalTo(
+ PROFILE_H263_BASELINE),
+ C2F(mProfileLevel, level).oneOf({
+ C2Config::LEVEL_H263_10,
+ C2Config::LEVEL_H263_20,
+ C2Config::LEVEL_H263_30,
+ C2Config::LEVEL_H263_40,
+ C2Config::LEVEL_H263_45})
+ })
+ .withSetter(ProfileLevelSetter)
+ .build());
+#endif
}
- static C2R SizeSetter(bool mayBlock,
- C2P<C2VideoSizeStreamTuning::input>& me) {
+ static C2R BitrateSetter(bool mayBlock, C2P<C2StreamBitrateInfo::output> &me) {
(void)mayBlock;
- // TODO: maybe apply block limit?
C2R res = C2R::Ok();
- if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
- res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
- }
- if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
- res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
+ if (me.v.value <= 4096) {
+ me.set().value = 4096;
}
return res;
}
- uint32_t getWidth() const { return mSize->width; }
- uint32_t getHeight() const { return mSize->height; }
- float getFrameRate() const { return mFrameRate->value; }
- uint32_t getBitrate() const { return mBitrate->value; }
+ static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::input> &oldMe,
+ C2P<C2StreamPictureSizeInfo::input> &me) {
+ (void)mayBlock;
+ C2R res = C2R::Ok();
+ if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
+ res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
+ me.set().width = oldMe.v.width;
+ }
+ if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
+ res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
+ me.set().height = oldMe.v.height;
+ }
+ return res;
+ }
+
+ static C2R ProfileLevelSetter(
+ bool mayBlock,
+ C2P<C2StreamProfileLevelInfo::output> &me) {
+ (void)mayBlock;
+ if (!me.F(me.v.profile).supportsAtAll(me.v.profile)) {
+#ifdef MPEG4
+ me.set().profile = PROFILE_MP4V_SIMPLE;
+#else
+ me.set().profile = PROFILE_H263_BASELINE;
+#endif
+ }
+ if (!me.F(me.v.level).supportsAtAll(me.v.level)) {
+#ifdef MPEG4
+ me.set().level = LEVEL_MP4V_2;
+#else
+ me.set().level = LEVEL_H263_45;
+#endif
+ }
+ return C2R::Ok();
+ }
+
+ // unsafe getters
+ std::shared_ptr<C2StreamPictureSizeInfo::input> getSize_l() const { return mSize; }
+ std::shared_ptr<C2StreamFrameRateInfo::output> getFrameRate_l() const { return mFrameRate; }
+ std::shared_ptr<C2StreamBitrateInfo::output> getBitrate_l() const { return mBitrate; }
+ uint32_t getSyncFramePeriod() const {
+ if (mSyncFramePeriod->value < 0 || mSyncFramePeriod->value == INT64_MAX) {
+ return 0;
+ }
+ double period = mSyncFramePeriod->value / 1e6 * mFrameRate->value;
+ return (uint32_t)c2_max(c2_min(period + 0.5, double(UINT32_MAX)), 1.);
+ }
private:
std::shared_ptr<C2StreamFormatConfig::input> mInputFormat;
@@ -141,6 +225,8 @@
std::shared_ptr<C2VideoSizeStreamTuning::input> mSize;
std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
std::shared_ptr<C2BitrateTuning::output> mBitrate;
+ std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
+ std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mSyncFramePeriod;
};
C2SoftMpeg4Enc::C2SoftMpeg4Enc(const char* name, c2_node_id_t id,
@@ -151,8 +237,7 @@
mHandle(nullptr),
mEncParams(nullptr),
mStarted(false),
- mOutBufferSize(524288),
- mKeyFrameInterval(10) {
+ mOutBufferSize(524288) {
}
C2SoftMpeg4Enc::~C2SoftMpeg4Enc() {
@@ -236,39 +321,38 @@
return C2_CORRUPTED;
}
- if (mIntf->getFrameRate() == 0) {
+ if (mFrameRate->value == 0) {
ALOGE("Framerate should not be 0");
return C2_BAD_VALUE;
}
mEncParams->encMode = mEncodeMode;
- mEncParams->encWidth[0] = mIntf->getWidth();
- mEncParams->encHeight[0] = mIntf->getHeight();
- mEncParams->encFrameRate[0] = mIntf->getFrameRate();
+ mEncParams->encWidth[0] = mSize->width;
+ mEncParams->encHeight[0] = mSize->height;
+ mEncParams->encFrameRate[0] = mFrameRate->value + 0.5;
mEncParams->rcType = VBR_1;
mEncParams->vbvDelay = 5.0f;
-
mEncParams->profile_level = CORE_PROFILE_LEVEL2;
mEncParams->packetSize = 32;
mEncParams->rvlcEnable = PV_OFF;
mEncParams->numLayers = 1;
mEncParams->timeIncRes = 1000;
- mEncParams->tickPerSrc = mEncParams->timeIncRes / mIntf->getFrameRate();
- mEncParams->bitRate[0] = mIntf->getBitrate();
+ mEncParams->tickPerSrc = mEncParams->timeIncRes / (mFrameRate->value + 0.5);
+ mEncParams->bitRate[0] = mBitrate->value;
mEncParams->iQuant[0] = 15;
mEncParams->pQuant[0] = 12;
mEncParams->quantType[0] = 0;
mEncParams->noFrameSkipped = PV_OFF;
// PV's MPEG4 encoder requires the video dimension of multiple
- if (mIntf->getWidth() % 16 != 0 || mIntf->getHeight() % 16 != 0) {
+ if (mSize->width % 16 != 0 || mSize->height % 16 != 0) {
ALOGE("Video frame size %dx%d must be a multiple of 16",
- mIntf->getWidth(), mIntf->getHeight());
+ mSize->width, mSize->height);
return C2_BAD_VALUE;
}
// Set IDR frame refresh interval
- mEncParams->intraPeriod = mKeyFrameInterval;
+ mEncParams->intraPeriod = mIntf->getSyncFramePeriod();
mEncParams->numIntraMB = 0;
mEncParams->sceneDetect = PV_ON;
mEncParams->searchRange = 16;
@@ -284,6 +368,12 @@
if (mStarted) {
return C2_OK;
}
+ {
+ IntfImpl::Lock lock = mIntf->lock();
+ mSize = mIntf->getSize_l();
+ mBitrate = mIntf->getBitrate_l();
+ mFrameRate = mIntf->getFrameRate_l();
+ }
c2_status_t err = initEncParams();
if (C2_OK != err) {
ALOGE("Failed to initialized encoder params");
@@ -379,11 +469,11 @@
uint64_t inputTimeStamp = work->input.ordinal.timestamp.peekull();
const C2ConstGraphicBlock inBuffer = inputBuffer->data().graphicBlocks().front();
- if (inBuffer.width() < mIntf->getWidth() ||
- inBuffer.height() < mIntf->getHeight()) {
+ if (inBuffer.width() < mSize->width ||
+ inBuffer.height() < mSize->height) {
/* Expect width height to be configured */
ALOGW("unexpected Capacity Aspect %d(%d) x %d(%d)", inBuffer.width(),
- mIntf->getWidth(), inBuffer.height(), mIntf->getHeight());
+ mSize->width, inBuffer.height(), mSize->height);
work->result = C2_BAD_VALUE;
return;
}
@@ -395,8 +485,8 @@
int32_t yStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
int32_t uStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
int32_t vStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
- uint32_t width = mIntf->getWidth();
- uint32_t height = mIntf->getHeight();
+ uint32_t width = mSize->width;
+ uint32_t height = mSize->height;
// width and height are always even (as block size is 16x16)
CHECK_EQ((width & 1u), 0u);
CHECK_EQ((height & 1u), 0u);
@@ -488,12 +578,12 @@
fillEmptyWork(work);
if (outputSize) {
std::shared_ptr<C2Buffer> buffer = createLinearBuffer(block, 0, outputSize);
- work->worklets.front()->output.buffers.push_back(buffer);
work->worklets.front()->output.ordinal.timestamp = inputTimeStamp;
if (hintTrack.CodeType == 0) {
buffer->setInfo(std::make_shared<C2StreamPictureTypeMaskInfo::output>(
0u /* stream id */, C2PictureTypeKeyFrame));
}
+ work->worklets.front()->output.buffers.push_back(buffer);
}
if (eos) {
mSignalledOutputEos = true;
diff --git a/media/codecs/mpeg4_h263/C2SoftMpeg4Enc.h b/media/codecs/mpeg4_h263/C2SoftMpeg4Enc.h
index 7631f30..43461fc 100644
--- a/media/codecs/mpeg4_h263/C2SoftMpeg4Enc.h
+++ b/media/codecs/mpeg4_h263/C2SoftMpeg4Enc.h
@@ -60,8 +60,12 @@
bool mSignalledError;
uint32_t mOutBufferSize;
- // 1: all I-frames, <0: infinite
- int32_t mKeyFrameInterval;
+ // configurations used by component in process
+ // (TODO: keep this in intf but make them internal only)
+ std::shared_ptr<C2StreamPictureSizeInfo::input> mSize;
+ std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
+ std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
+
int64_t mNumInputFrames;
MP4EncodingMode mEncodeMode;