Loading media/codec2/components/mpeg4_h263/C2SoftMpeg4Enc.cpp +98 −7 Original line number Diff line number Diff line Loading @@ -49,6 +49,8 @@ constexpr char COMPONENT_NAME[] = "c2.android.h263.encoder"; const char *MEDIA_MIMETYPE_VIDEO = MEDIA_MIMETYPE_VIDEO_H263; #endif constexpr float VBV_DELAY = 5.0f; } // namepsace class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams { Loading Loading @@ -131,7 +133,7 @@ class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams { C2Config::LEVEL_MP4V_1, C2Config::LEVEL_MP4V_2}) }) .withSetter(ProfileLevelSetter) .withSetter(ProfileLevelSetter, mSize, mFrameRate, mBitrate) .build()); #else addParameter( Loading @@ -148,7 +150,7 @@ class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams { C2Config::LEVEL_H263_40, C2Config::LEVEL_H263_45}) }) .withSetter(ProfileLevelSetter) .withSetter(ProfileLevelSetter, mSize, mFrameRate, mBitrate) .build()); #endif } Loading Loading @@ -179,7 +181,10 @@ class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams { static C2R ProfileLevelSetter( bool mayBlock, C2P<C2StreamProfileLevelInfo::output> &me) { C2P<C2StreamProfileLevelInfo::output> &me, const C2P<C2StreamPictureSizeInfo::input> &size, const C2P<C2StreamFrameRateInfo::output> &frameRate, const C2P<C2StreamBitrateInfo::output> &bitrate) { (void)mayBlock; if (!me.F(me.v.profile).supportsAtAll(me.v.profile)) { #ifdef MPEG4 Loading @@ -188,11 +193,84 @@ class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams { me.set().profile = PROFILE_H263_BASELINE; #endif } if (!me.F(me.v.level).supportsAtAll(me.v.level)) { struct LevelLimits { C2Config::level_t level; uint32_t sampleRate; uint32_t width; uint32_t height; uint32_t frameRate; uint32_t bitrate; uint32_t vbvSize; }; constexpr LevelLimits kLimits[] = { #ifdef MPEG4 { LEVEL_MP4V_0, 380160, 176, 144, 15, 64000, 163840 }, // { LEVEL_MP4V_0B, 380160, 176, 144, 15, 128000, 163840 }, { LEVEL_MP4V_1, 380160, 176, 144, 30, 64000, 163840 }, { LEVEL_MP4V_2, 1520640, 352, 288, 30, 128000, 655360 }, #else // HRD Buffer Size = (B + BPPmaxKb * 1024 bits) // where, (BPPmaxKb * 1024) is maximum number of bits per picture // that has been negotiated for use in the bitstream Sec 3.6 of T-Rec-H.263 // and B = 4 * Rmax / PCF. Rmax is max bit rate and PCF is picture // clock frequency { LEVEL_H263_10, 380160, 176, 144, 15, 64000, 74077 }, { LEVEL_H263_45, 380160, 176, 144, 15, 128000, 82619 }, { LEVEL_H263_20, 1520640, 352, 288, 30, 128000, 279227 }, { LEVEL_H263_30, 3041280, 352, 288, 30, 384000, 313395 }, { LEVEL_H263_40, 3041280, 352, 288, 30, 2048000, 535483 }, // { LEVEL_H263_50, 5068800, 352, 288, 60, 4096000, 808823 }, #endif }; auto mbs = ((size.v.width + 15) / 16) * ((size.v.height + 15) / 16); auto sampleRate = mbs * frameRate.v.value * 16 * 16; auto vbvSize = bitrate.v.value * VBV_DELAY; // Check if the supplied level meets the MB / bitrate requirements. If // not, update the level with the lowest level meeting the requirements. bool found = false; // By default needsUpdate = false in case the supplied level does meet // the requirements. bool needsUpdate = false; #ifdef MPEG4 // For Level 0b, we want to update the level anyway, as library does not // seem to accept this value. if (me.v.level == LEVEL_MP4V_0B) { needsUpdate = true; } #endif for (const LevelLimits &limit : kLimits) { if (sampleRate <= limit.sampleRate && size.v.width <= limit.width && vbvSize <= limit.vbvSize && size.v.height <= limit.height && bitrate.v.value <= limit.bitrate && frameRate.v.value <= limit.frameRate) { // This is the lowest level that meets the requirements, and if // we haven't seen the supplied level yet, that means we don't // need the update. if (needsUpdate) { ALOGD("Given level %x does not cover current configuration: " "adjusting to %x", me.v.level, limit.level); me.set().level = limit.level; } found = true; break; } if (me.v.level == limit.level) { // We break out of the loop when the lowest feasible level is // found. The fact that we're here means that our level doesn't // meet the requirement and needs to be updated. needsUpdate = true; } } // If not found, set to the highest supported level. if (!found) { #ifdef MPEG4 me.set().level = LEVEL_MP4V_2; #else me.set().level = LEVEL_H263_45; me.set().level = LEVEL_H263_40; #endif } return C2R::Ok(); Loading @@ -210,6 +288,18 @@ class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams { return (uint32_t)c2_max(c2_min(period + 0.5, double(UINT32_MAX)), 1.); } ProfileLevelType getProfileLevel_l() const { #ifdef MPEG4 if (mProfileLevel->level == LEVEL_MP4V_0) return SIMPLE_PROFILE_LEVEL0; else if (mProfileLevel->level == LEVEL_MP4V_1) return SIMPLE_PROFILE_LEVEL1; return SIMPLE_PROFILE_LEVEL2; // level == LEVEL_MP4V_2 #else // library does not export h263 specific levels. No way to map C2 enums to // library specific constants. Return max supported level. return CORE_PROFILE_LEVEL2; #endif } private: std::shared_ptr<C2StreamUsageTuning::input> mUsage; std::shared_ptr<C2StreamPictureSizeInfo::input> mSize; Loading Loading @@ -325,8 +415,8 @@ c2_status_t C2SoftMpeg4Enc::initEncParams() { 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->vbvDelay = VBV_DELAY; mEncParams->profile_level = mProfileLevel; mEncParams->packetSize = 32; mEncParams->rvlcEnable = PV_OFF; mEncParams->numLayers = 1; Loading Loading @@ -367,6 +457,7 @@ c2_status_t C2SoftMpeg4Enc::initEncoder() { mSize = mIntf->getSize_l(); mBitrate = mIntf->getBitrate_l(); mFrameRate = mIntf->getFrameRate_l(); mProfileLevel = mIntf->getProfileLevel_l(); } c2_status_t err = initEncParams(); if (C2_OK != err) { Loading media/codec2/components/mpeg4_h263/C2SoftMpeg4Enc.h +1 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ private: std::shared_ptr<C2StreamPictureSizeInfo::input> mSize; std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate; std::shared_ptr<C2StreamBitrateInfo::output> mBitrate; ProfileLevelType mProfileLevel; int64_t mNumInputFrames; MP4EncodingMode mEncodeMode; Loading Loading
media/codec2/components/mpeg4_h263/C2SoftMpeg4Enc.cpp +98 −7 Original line number Diff line number Diff line Loading @@ -49,6 +49,8 @@ constexpr char COMPONENT_NAME[] = "c2.android.h263.encoder"; const char *MEDIA_MIMETYPE_VIDEO = MEDIA_MIMETYPE_VIDEO_H263; #endif constexpr float VBV_DELAY = 5.0f; } // namepsace class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams { Loading Loading @@ -131,7 +133,7 @@ class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams { C2Config::LEVEL_MP4V_1, C2Config::LEVEL_MP4V_2}) }) .withSetter(ProfileLevelSetter) .withSetter(ProfileLevelSetter, mSize, mFrameRate, mBitrate) .build()); #else addParameter( Loading @@ -148,7 +150,7 @@ class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams { C2Config::LEVEL_H263_40, C2Config::LEVEL_H263_45}) }) .withSetter(ProfileLevelSetter) .withSetter(ProfileLevelSetter, mSize, mFrameRate, mBitrate) .build()); #endif } Loading Loading @@ -179,7 +181,10 @@ class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams { static C2R ProfileLevelSetter( bool mayBlock, C2P<C2StreamProfileLevelInfo::output> &me) { C2P<C2StreamProfileLevelInfo::output> &me, const C2P<C2StreamPictureSizeInfo::input> &size, const C2P<C2StreamFrameRateInfo::output> &frameRate, const C2P<C2StreamBitrateInfo::output> &bitrate) { (void)mayBlock; if (!me.F(me.v.profile).supportsAtAll(me.v.profile)) { #ifdef MPEG4 Loading @@ -188,11 +193,84 @@ class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams { me.set().profile = PROFILE_H263_BASELINE; #endif } if (!me.F(me.v.level).supportsAtAll(me.v.level)) { struct LevelLimits { C2Config::level_t level; uint32_t sampleRate; uint32_t width; uint32_t height; uint32_t frameRate; uint32_t bitrate; uint32_t vbvSize; }; constexpr LevelLimits kLimits[] = { #ifdef MPEG4 { LEVEL_MP4V_0, 380160, 176, 144, 15, 64000, 163840 }, // { LEVEL_MP4V_0B, 380160, 176, 144, 15, 128000, 163840 }, { LEVEL_MP4V_1, 380160, 176, 144, 30, 64000, 163840 }, { LEVEL_MP4V_2, 1520640, 352, 288, 30, 128000, 655360 }, #else // HRD Buffer Size = (B + BPPmaxKb * 1024 bits) // where, (BPPmaxKb * 1024) is maximum number of bits per picture // that has been negotiated for use in the bitstream Sec 3.6 of T-Rec-H.263 // and B = 4 * Rmax / PCF. Rmax is max bit rate and PCF is picture // clock frequency { LEVEL_H263_10, 380160, 176, 144, 15, 64000, 74077 }, { LEVEL_H263_45, 380160, 176, 144, 15, 128000, 82619 }, { LEVEL_H263_20, 1520640, 352, 288, 30, 128000, 279227 }, { LEVEL_H263_30, 3041280, 352, 288, 30, 384000, 313395 }, { LEVEL_H263_40, 3041280, 352, 288, 30, 2048000, 535483 }, // { LEVEL_H263_50, 5068800, 352, 288, 60, 4096000, 808823 }, #endif }; auto mbs = ((size.v.width + 15) / 16) * ((size.v.height + 15) / 16); auto sampleRate = mbs * frameRate.v.value * 16 * 16; auto vbvSize = bitrate.v.value * VBV_DELAY; // Check if the supplied level meets the MB / bitrate requirements. If // not, update the level with the lowest level meeting the requirements. bool found = false; // By default needsUpdate = false in case the supplied level does meet // the requirements. bool needsUpdate = false; #ifdef MPEG4 // For Level 0b, we want to update the level anyway, as library does not // seem to accept this value. if (me.v.level == LEVEL_MP4V_0B) { needsUpdate = true; } #endif for (const LevelLimits &limit : kLimits) { if (sampleRate <= limit.sampleRate && size.v.width <= limit.width && vbvSize <= limit.vbvSize && size.v.height <= limit.height && bitrate.v.value <= limit.bitrate && frameRate.v.value <= limit.frameRate) { // This is the lowest level that meets the requirements, and if // we haven't seen the supplied level yet, that means we don't // need the update. if (needsUpdate) { ALOGD("Given level %x does not cover current configuration: " "adjusting to %x", me.v.level, limit.level); me.set().level = limit.level; } found = true; break; } if (me.v.level == limit.level) { // We break out of the loop when the lowest feasible level is // found. The fact that we're here means that our level doesn't // meet the requirement and needs to be updated. needsUpdate = true; } } // If not found, set to the highest supported level. if (!found) { #ifdef MPEG4 me.set().level = LEVEL_MP4V_2; #else me.set().level = LEVEL_H263_45; me.set().level = LEVEL_H263_40; #endif } return C2R::Ok(); Loading @@ -210,6 +288,18 @@ class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams { return (uint32_t)c2_max(c2_min(period + 0.5, double(UINT32_MAX)), 1.); } ProfileLevelType getProfileLevel_l() const { #ifdef MPEG4 if (mProfileLevel->level == LEVEL_MP4V_0) return SIMPLE_PROFILE_LEVEL0; else if (mProfileLevel->level == LEVEL_MP4V_1) return SIMPLE_PROFILE_LEVEL1; return SIMPLE_PROFILE_LEVEL2; // level == LEVEL_MP4V_2 #else // library does not export h263 specific levels. No way to map C2 enums to // library specific constants. Return max supported level. return CORE_PROFILE_LEVEL2; #endif } private: std::shared_ptr<C2StreamUsageTuning::input> mUsage; std::shared_ptr<C2StreamPictureSizeInfo::input> mSize; Loading Loading @@ -325,8 +415,8 @@ c2_status_t C2SoftMpeg4Enc::initEncParams() { 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->vbvDelay = VBV_DELAY; mEncParams->profile_level = mProfileLevel; mEncParams->packetSize = 32; mEncParams->rvlcEnable = PV_OFF; mEncParams->numLayers = 1; Loading Loading @@ -367,6 +457,7 @@ c2_status_t C2SoftMpeg4Enc::initEncoder() { mSize = mIntf->getSize_l(); mBitrate = mIntf->getBitrate_l(); mFrameRate = mIntf->getFrameRate_l(); mProfileLevel = mIntf->getProfileLevel_l(); } c2_status_t err = initEncParams(); if (C2_OK != err) { Loading
media/codec2/components/mpeg4_h263/C2SoftMpeg4Enc.h +1 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ private: std::shared_ptr<C2StreamPictureSizeInfo::input> mSize; std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate; std::shared_ptr<C2StreamBitrateInfo::output> mBitrate; ProfileLevelType mProfileLevel; int64_t mNumInputFrames; MP4EncodingMode mEncodeMode; Loading