Loading media/libmediaformatshaper/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -36,6 +36,7 @@ cc_defaults { name: "libmediaformatshaper_defaults", name: "libmediaformatshaper_defaults", srcs: [ srcs: [ "CodecProperties.cpp", "CodecProperties.cpp", "CodecSeeding.cpp", "FormatShaper.cpp", "FormatShaper.cpp", "ManageShapingCodecs.cpp", "ManageShapingCodecs.cpp", "VideoShaper.cpp", "VideoShaper.cpp", Loading media/libmediaformatshaper/CodecProperties.cpp +33 −0 Original line number Original line Diff line number Diff line Loading @@ -26,6 +26,7 @@ namespace android { namespace mediaformatshaper { namespace mediaformatshaper { CodecProperties::CodecProperties(std::string name, std::string mediaType) { CodecProperties::CodecProperties(std::string name, std::string mediaType) { ALOGV("CodecProperties(%s, %s)", name.c_str(), mediaType.c_str()); mName = name; mName = name; mMediaType = mediaType; mMediaType = mediaType; } } Loading Loading @@ -58,6 +59,38 @@ int CodecProperties::supportedApi() { return mApi; return mApi; } } void CodecProperties::setFeatureValue(std::string key, int32_t value) { ALOGD("setFeatureValue(%s,%d)", key.c_str(), value); mFeatures.insert({key, value}); if (!strcmp(key.c_str(), "vq-minimum-quality")) { setSupportedMinimumQuality(value); } else if (!strcmp(key.c_str(), "vq-supports-qp")) { // key from prototyping setSupportsQp(1); } else if (!strcmp(key.c_str(), "qp-bounds")) { // official key setSupportsQp(1); } else if (!strcmp(key.c_str(), "vq-target-qpmax")) { setTargetQpMax(value); } else if (!strcmp(key.c_str(), "vq-target-bppx100")) { double bpp = value / 100.0; setBpp(bpp); } } bool CodecProperties::getFeatureValue(std::string key, int32_t *valuep) { ALOGV("getFeatureValue(%s)", key.c_str()); if (valuep == nullptr) { return false; } auto mapped = mFeatures.find(key); if (mapped != mFeatures.end()) { *valuep = mapped->second; return true; } return false; } std::string CodecProperties::getMapping(std::string key, std::string kind) { std::string CodecProperties::getMapping(std::string key, std::string kind) { ALOGV("getMapping(key %s, kind %s )", key.c_str(), kind.c_str()); ALOGV("getMapping(key %s, kind %s )", key.c_str(), kind.c_str()); //play with mMappings //play with mMappings Loading media/libmediaformatshaper/CodecSeeding.cpp 0 → 100644 +127 −0 Original line number Original line Diff line number Diff line /* * Copyright 2021, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //#define LOG_NDEBUG 0 #define LOG_TAG "CodecSeeding" #include <utils/Log.h> #include <string> #include <media/formatshaper/CodecProperties.h> namespace android { namespace mediaformatshaper { /* * a block of pre-loads; things the library seeds into the codecproperties based * on the mediaType. * XXX: parsing from a file is likely better than embedding in code. */ typedef struct { const char *key; int32_t value; } preloadFeature_t; typedef struct { const char *mediaType; preloadFeature_t *features; } preloadProperties_t; /* * 240 = 2.4 bits per pixel-per-second == 5mbps@1080, 2.3mbps@720p, which is about where * we want our initial floor for now. */ static preloadFeature_t featuresAvc[] = { {"vq-target-bppx100", 240}, {nullptr, 0} }; static preloadFeature_t featuresHevc[] = { {"vq-target-bppx100", 240}, {nullptr, 0} }; static preloadFeature_t featuresGenericVideo[] = { {"vq-target-bppx100", 240}, {nullptr, 0} }; static preloadProperties_t preloadProperties[] = { { "video/avc", featuresAvc}, { "video/hevc", &featuresHevc[0]}, // wildcard for any video format not already captured { "video/*", &featuresGenericVideo[0]}, { nullptr, nullptr} }; void CodecProperties::Seed() { ALOGV("Seed: for codec %s, mediatype %s", mName.c_str(), mMediaType.c_str()); // load me up with initial configuration data int count = 0; for (int i=0;; i++) { preloadProperties_t *p = &preloadProperties[i]; if (p->mediaType == nullptr) { break; } bool found = false; if (strcmp(p->mediaType, mMediaType.c_str()) == 0) { found = true; } const char *r; if (!found && (r = strchr(p->mediaType, '*')) != NULL) { // wildcard; check the prefix size_t len = r - p->mediaType; if (strncmp(p->mediaType, mMediaType.c_str(), len) == 0) { found = true; } } if (!found) { continue; } ALOGV("seeding from mediaType '%s'", p->mediaType); // walk through, filling things if (p->features != nullptr) { for (int j=0;; j++) { preloadFeature_t *q = &p->features[j]; if (q->key == nullptr) { break; } setFeatureValue(q->key, q->value); count++; } break; } } ALOGV("loaded %d preset values", count); } // a chance, as we register the codec and accept no further updates, to // override any poor configuration that arrived from the device's XML files. // void CodecProperties::Finish() { ALOGV("Finish: for codec %s, mediatype %s", mName.c_str(), mMediaType.c_str()); // currently a no-op } } // namespace mediaformatshaper } // namespace android media/libmediaformatshaper/FormatShaper.cpp +12 −13 Original line number Original line Diff line number Diff line Loading @@ -93,19 +93,9 @@ int setFeature(shaperHandle_t shaper, const char *feature, int value) { return -1; return -1; } } if (!strcmp(feature, "vq-minimum-quality")) { // save a map of all features codec->setSupportedMinimumQuality(value); codec->setFeatureValue(feature, value); } else if (!strcmp(feature, "vq-supports-qp")) { codec->setSupportsQp(value != 0); } else if (!strcmp(feature, "vq-target-qpmax")) { codec->setTargetQpMax(value); } else if (!strcmp(feature, "vq-target-bppx100")) { double bpp = value / 100.0; codec->setBpp(bpp); } else { // changed nothing, don't mark as configured return 0; } return 0; return 0; } } Loading @@ -120,6 +110,9 @@ shaperHandle_t findShaper(const char *codecName, const char *mediaType) { shaperHandle_t createShaper(const char *codecName, const char *mediaType) { shaperHandle_t createShaper(const char *codecName, const char *mediaType) { CodecProperties *codec = new CodecProperties(codecName, mediaType); CodecProperties *codec = new CodecProperties(codecName, mediaType); if (codec != nullptr) { codec->Seed(); } return (shaperHandle_t) codec; return (shaperHandle_t) codec; } } Loading @@ -134,6 +127,12 @@ shaperHandle_t registerShaper(shaperHandle_t shaper, const char *codecName, cons return nullptr; return nullptr; } } // any final cleanup for the parameters. This allows us to override // bad parameters from a devices XML file. codec->Finish(); // may return a different codec, if we lost a race. // if so, registerCodec() reclaims the one we tried to register for us. codec = registerCodec(codec, codecName, mediaType); codec = registerCodec(codec, codecName, mediaType); return (shaperHandle_t) codec; return (shaperHandle_t) codec; } } Loading media/libmediaformatshaper/VQApply.cpp +43 −25 Original line number Original line Diff line number Diff line Loading @@ -44,42 +44,60 @@ namespace mediaformatshaper { #define AMEDIAFORMAT_VIDEO_QP_P_MAX "video-qp-p-max" #define AMEDIAFORMAT_VIDEO_QP_P_MAX "video-qp-p-max" #define AMEDIAFORMAT_VIDEO_QP_P_MIN "video-qp-p-min" #define AMEDIAFORMAT_VIDEO_QP_P_MIN "video-qp-p-min" // defined in the SDK, but not in the NDK // static const int BITRATE_MODE_VBR = 1; // // // Caller retains ownership of and responsibility for inFormat // Caller retains ownership of and responsibility for inFormat // // int VQApply(CodecProperties *codec, vqOps_t *info, AMediaFormat* inFormat, int flags) { int VQApply(CodecProperties *codec, vqOps_t *info, AMediaFormat* inFormat, int flags) { ALOGV("codecName %s inFormat %p flags x%x", codec->getName().c_str(), inFormat, flags); ALOGV("codecName %s inFormat %p flags x%x", codec->getName().c_str(), inFormat, flags); int32_t bitRateMode = -1; if (AMediaFormat_getInt32(inFormat, AMEDIAFORMAT_KEY_BITRATE_MODE, &bitRateMode) && bitRateMode != BITRATE_MODE_VBR) { ALOGD("minquality: applies only to VBR encoding"); return 0; } if (codec->supportedMinimumQuality() > 0) { if (codec->supportedMinimumQuality() > 0) { // allow the codec provided minimum quality behavior to work at it // allow the codec provided minimum quality behavior to work at it ALOGD("minquality(codec): codec says %d", codec->supportedMinimumQuality()); ALOGD("minquality: codec claims to implement minquality=%d", codec->supportedMinimumQuality()); return 0; return 0; } } ALOGD("considering other ways to improve quality..."); // // // apply any and all tools that we have. // apply any and all tools that we have. // -- qp // -- qp // -- minimum bits-per-pixel // -- minimum bits-per-pixel // // if (codec->supportsQp()) { if (!codec->supportsQp()) { ALOGD("minquality: no qp bounding in codec %s", codec->getName().c_str()); } else { // use a (configurable) QP value to force better quality // use a (configurable) QP value to force better quality // // // XXX: augment this so that we don't lower an existing QP setting int32_t qpmax = codec->targetQpMax(); // (e.g. if user set it to 40, we don't want to set it back to 45) int32_t qpmaxUser = INT32_MAX; int qpmax = codec->targetQpMax(); if (hasQp(inFormat)) { if (qpmax <= 0) { (void) AMediaFormat_getInt32(inFormat, AMEDIAFORMAT_VIDEO_QP_MAX, &qpmaxUser); qpmax = 45; ALOGD("minquality by QP: format already sets QP"); ALOGD("use default substitute QpMax == %d", qpmax); } // if the system didn't do one, use what the user provided if (qpmax == 0 && qpmaxUser != INT32_MAX) { qpmax = qpmaxUser; } } // XXX: if both said something, how do we want to reconcile that if (qpmax > 0) { ALOGD("minquality by QP: inject %s=%d", AMEDIAFORMAT_VIDEO_QP_MAX, qpmax); ALOGD("minquality by QP: inject %s=%d", AMEDIAFORMAT_VIDEO_QP_MAX, qpmax); AMediaFormat_setInt32(inFormat, AMEDIAFORMAT_VIDEO_QP_MAX, qpmax); AMediaFormat_setInt32(inFormat, AMEDIAFORMAT_VIDEO_QP_MAX, qpmax); // force spreading the QP across frame types, since we imposing a value // force spreading the QP across frame types, since we imposing a value qpSpreadMaxPerFrameType(inFormat, info->qpDelta, info->qpMax, /* override */ true); qpSpreadMaxPerFrameType(inFormat, info->qpDelta, info->qpMax, /* override */ true); } else { } ALOGD("codec %s: no qp bounding", codec->getName().c_str()); } } double bpp = codec->getBpp(); double bpp = codec->getBpp(); Loading Loading @@ -108,7 +126,7 @@ int VQApply(CodecProperties *codec, vqOps_t *info, AMediaFormat* inFormat, int f bitrateConfigured, bitrateFloor, codec->getBpp(), height, width); bitrateConfigured, bitrateFloor, codec->getBpp(), height, width); if (bitrateConfigured < bitrateFloor) { if (bitrateConfigured < bitrateFloor) { ALOGD("minquality/target bitrate raised from %d to %" PRId64 " to maintain quality", ALOGD("minquality/target bitrate raised from %d to %" PRId64 " bps", bitrateConfigured, bitrateFloor); bitrateConfigured, bitrateFloor); AMediaFormat_setInt32(inFormat, AMEDIAFORMAT_KEY_BIT_RATE, (int32_t)bitrateFloor); AMediaFormat_setInt32(inFormat, AMEDIAFORMAT_KEY_BIT_RATE, (int32_t)bitrateFloor); } } Loading @@ -121,16 +139,16 @@ int VQApply(CodecProperties *codec, vqOps_t *info, AMediaFormat* inFormat, int f bool hasQpPerFrameType(AMediaFormat *format) { bool hasQpPerFrameType(AMediaFormat *format) { int32_t value; int32_t value; if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MAX, &value) if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MAX, &value) || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MIN, &value)) { || AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MIN, &value)) { return true; return true; } } if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MAX, &value) if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MAX, &value) || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MIN, &value)) { || AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MIN, &value)) { return true; return true; } } if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MAX, &value) if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MAX, &value) || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MIN, &value)) { || AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MIN, &value)) { return true; return true; } } return false; return false; Loading @@ -138,8 +156,8 @@ bool hasQpPerFrameType(AMediaFormat *format) { bool hasQp(AMediaFormat *format) { bool hasQp(AMediaFormat *format) { int32_t value; int32_t value; if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MAX, &value) if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MAX, &value) || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MIN, &value)) { || AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MIN, &value)) { return true; return true; } } return hasQpPerFrameType(format); return hasQpPerFrameType(format); Loading Loading
media/libmediaformatshaper/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -36,6 +36,7 @@ cc_defaults { name: "libmediaformatshaper_defaults", name: "libmediaformatshaper_defaults", srcs: [ srcs: [ "CodecProperties.cpp", "CodecProperties.cpp", "CodecSeeding.cpp", "FormatShaper.cpp", "FormatShaper.cpp", "ManageShapingCodecs.cpp", "ManageShapingCodecs.cpp", "VideoShaper.cpp", "VideoShaper.cpp", Loading
media/libmediaformatshaper/CodecProperties.cpp +33 −0 Original line number Original line Diff line number Diff line Loading @@ -26,6 +26,7 @@ namespace android { namespace mediaformatshaper { namespace mediaformatshaper { CodecProperties::CodecProperties(std::string name, std::string mediaType) { CodecProperties::CodecProperties(std::string name, std::string mediaType) { ALOGV("CodecProperties(%s, %s)", name.c_str(), mediaType.c_str()); mName = name; mName = name; mMediaType = mediaType; mMediaType = mediaType; } } Loading Loading @@ -58,6 +59,38 @@ int CodecProperties::supportedApi() { return mApi; return mApi; } } void CodecProperties::setFeatureValue(std::string key, int32_t value) { ALOGD("setFeatureValue(%s,%d)", key.c_str(), value); mFeatures.insert({key, value}); if (!strcmp(key.c_str(), "vq-minimum-quality")) { setSupportedMinimumQuality(value); } else if (!strcmp(key.c_str(), "vq-supports-qp")) { // key from prototyping setSupportsQp(1); } else if (!strcmp(key.c_str(), "qp-bounds")) { // official key setSupportsQp(1); } else if (!strcmp(key.c_str(), "vq-target-qpmax")) { setTargetQpMax(value); } else if (!strcmp(key.c_str(), "vq-target-bppx100")) { double bpp = value / 100.0; setBpp(bpp); } } bool CodecProperties::getFeatureValue(std::string key, int32_t *valuep) { ALOGV("getFeatureValue(%s)", key.c_str()); if (valuep == nullptr) { return false; } auto mapped = mFeatures.find(key); if (mapped != mFeatures.end()) { *valuep = mapped->second; return true; } return false; } std::string CodecProperties::getMapping(std::string key, std::string kind) { std::string CodecProperties::getMapping(std::string key, std::string kind) { ALOGV("getMapping(key %s, kind %s )", key.c_str(), kind.c_str()); ALOGV("getMapping(key %s, kind %s )", key.c_str(), kind.c_str()); //play with mMappings //play with mMappings Loading
media/libmediaformatshaper/CodecSeeding.cpp 0 → 100644 +127 −0 Original line number Original line Diff line number Diff line /* * Copyright 2021, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //#define LOG_NDEBUG 0 #define LOG_TAG "CodecSeeding" #include <utils/Log.h> #include <string> #include <media/formatshaper/CodecProperties.h> namespace android { namespace mediaformatshaper { /* * a block of pre-loads; things the library seeds into the codecproperties based * on the mediaType. * XXX: parsing from a file is likely better than embedding in code. */ typedef struct { const char *key; int32_t value; } preloadFeature_t; typedef struct { const char *mediaType; preloadFeature_t *features; } preloadProperties_t; /* * 240 = 2.4 bits per pixel-per-second == 5mbps@1080, 2.3mbps@720p, which is about where * we want our initial floor for now. */ static preloadFeature_t featuresAvc[] = { {"vq-target-bppx100", 240}, {nullptr, 0} }; static preloadFeature_t featuresHevc[] = { {"vq-target-bppx100", 240}, {nullptr, 0} }; static preloadFeature_t featuresGenericVideo[] = { {"vq-target-bppx100", 240}, {nullptr, 0} }; static preloadProperties_t preloadProperties[] = { { "video/avc", featuresAvc}, { "video/hevc", &featuresHevc[0]}, // wildcard for any video format not already captured { "video/*", &featuresGenericVideo[0]}, { nullptr, nullptr} }; void CodecProperties::Seed() { ALOGV("Seed: for codec %s, mediatype %s", mName.c_str(), mMediaType.c_str()); // load me up with initial configuration data int count = 0; for (int i=0;; i++) { preloadProperties_t *p = &preloadProperties[i]; if (p->mediaType == nullptr) { break; } bool found = false; if (strcmp(p->mediaType, mMediaType.c_str()) == 0) { found = true; } const char *r; if (!found && (r = strchr(p->mediaType, '*')) != NULL) { // wildcard; check the prefix size_t len = r - p->mediaType; if (strncmp(p->mediaType, mMediaType.c_str(), len) == 0) { found = true; } } if (!found) { continue; } ALOGV("seeding from mediaType '%s'", p->mediaType); // walk through, filling things if (p->features != nullptr) { for (int j=0;; j++) { preloadFeature_t *q = &p->features[j]; if (q->key == nullptr) { break; } setFeatureValue(q->key, q->value); count++; } break; } } ALOGV("loaded %d preset values", count); } // a chance, as we register the codec and accept no further updates, to // override any poor configuration that arrived from the device's XML files. // void CodecProperties::Finish() { ALOGV("Finish: for codec %s, mediatype %s", mName.c_str(), mMediaType.c_str()); // currently a no-op } } // namespace mediaformatshaper } // namespace android
media/libmediaformatshaper/FormatShaper.cpp +12 −13 Original line number Original line Diff line number Diff line Loading @@ -93,19 +93,9 @@ int setFeature(shaperHandle_t shaper, const char *feature, int value) { return -1; return -1; } } if (!strcmp(feature, "vq-minimum-quality")) { // save a map of all features codec->setSupportedMinimumQuality(value); codec->setFeatureValue(feature, value); } else if (!strcmp(feature, "vq-supports-qp")) { codec->setSupportsQp(value != 0); } else if (!strcmp(feature, "vq-target-qpmax")) { codec->setTargetQpMax(value); } else if (!strcmp(feature, "vq-target-bppx100")) { double bpp = value / 100.0; codec->setBpp(bpp); } else { // changed nothing, don't mark as configured return 0; } return 0; return 0; } } Loading @@ -120,6 +110,9 @@ shaperHandle_t findShaper(const char *codecName, const char *mediaType) { shaperHandle_t createShaper(const char *codecName, const char *mediaType) { shaperHandle_t createShaper(const char *codecName, const char *mediaType) { CodecProperties *codec = new CodecProperties(codecName, mediaType); CodecProperties *codec = new CodecProperties(codecName, mediaType); if (codec != nullptr) { codec->Seed(); } return (shaperHandle_t) codec; return (shaperHandle_t) codec; } } Loading @@ -134,6 +127,12 @@ shaperHandle_t registerShaper(shaperHandle_t shaper, const char *codecName, cons return nullptr; return nullptr; } } // any final cleanup for the parameters. This allows us to override // bad parameters from a devices XML file. codec->Finish(); // may return a different codec, if we lost a race. // if so, registerCodec() reclaims the one we tried to register for us. codec = registerCodec(codec, codecName, mediaType); codec = registerCodec(codec, codecName, mediaType); return (shaperHandle_t) codec; return (shaperHandle_t) codec; } } Loading
media/libmediaformatshaper/VQApply.cpp +43 −25 Original line number Original line Diff line number Diff line Loading @@ -44,42 +44,60 @@ namespace mediaformatshaper { #define AMEDIAFORMAT_VIDEO_QP_P_MAX "video-qp-p-max" #define AMEDIAFORMAT_VIDEO_QP_P_MAX "video-qp-p-max" #define AMEDIAFORMAT_VIDEO_QP_P_MIN "video-qp-p-min" #define AMEDIAFORMAT_VIDEO_QP_P_MIN "video-qp-p-min" // defined in the SDK, but not in the NDK // static const int BITRATE_MODE_VBR = 1; // // // Caller retains ownership of and responsibility for inFormat // Caller retains ownership of and responsibility for inFormat // // int VQApply(CodecProperties *codec, vqOps_t *info, AMediaFormat* inFormat, int flags) { int VQApply(CodecProperties *codec, vqOps_t *info, AMediaFormat* inFormat, int flags) { ALOGV("codecName %s inFormat %p flags x%x", codec->getName().c_str(), inFormat, flags); ALOGV("codecName %s inFormat %p flags x%x", codec->getName().c_str(), inFormat, flags); int32_t bitRateMode = -1; if (AMediaFormat_getInt32(inFormat, AMEDIAFORMAT_KEY_BITRATE_MODE, &bitRateMode) && bitRateMode != BITRATE_MODE_VBR) { ALOGD("minquality: applies only to VBR encoding"); return 0; } if (codec->supportedMinimumQuality() > 0) { if (codec->supportedMinimumQuality() > 0) { // allow the codec provided minimum quality behavior to work at it // allow the codec provided minimum quality behavior to work at it ALOGD("minquality(codec): codec says %d", codec->supportedMinimumQuality()); ALOGD("minquality: codec claims to implement minquality=%d", codec->supportedMinimumQuality()); return 0; return 0; } } ALOGD("considering other ways to improve quality..."); // // // apply any and all tools that we have. // apply any and all tools that we have. // -- qp // -- qp // -- minimum bits-per-pixel // -- minimum bits-per-pixel // // if (codec->supportsQp()) { if (!codec->supportsQp()) { ALOGD("minquality: no qp bounding in codec %s", codec->getName().c_str()); } else { // use a (configurable) QP value to force better quality // use a (configurable) QP value to force better quality // // // XXX: augment this so that we don't lower an existing QP setting int32_t qpmax = codec->targetQpMax(); // (e.g. if user set it to 40, we don't want to set it back to 45) int32_t qpmaxUser = INT32_MAX; int qpmax = codec->targetQpMax(); if (hasQp(inFormat)) { if (qpmax <= 0) { (void) AMediaFormat_getInt32(inFormat, AMEDIAFORMAT_VIDEO_QP_MAX, &qpmaxUser); qpmax = 45; ALOGD("minquality by QP: format already sets QP"); ALOGD("use default substitute QpMax == %d", qpmax); } // if the system didn't do one, use what the user provided if (qpmax == 0 && qpmaxUser != INT32_MAX) { qpmax = qpmaxUser; } } // XXX: if both said something, how do we want to reconcile that if (qpmax > 0) { ALOGD("minquality by QP: inject %s=%d", AMEDIAFORMAT_VIDEO_QP_MAX, qpmax); ALOGD("minquality by QP: inject %s=%d", AMEDIAFORMAT_VIDEO_QP_MAX, qpmax); AMediaFormat_setInt32(inFormat, AMEDIAFORMAT_VIDEO_QP_MAX, qpmax); AMediaFormat_setInt32(inFormat, AMEDIAFORMAT_VIDEO_QP_MAX, qpmax); // force spreading the QP across frame types, since we imposing a value // force spreading the QP across frame types, since we imposing a value qpSpreadMaxPerFrameType(inFormat, info->qpDelta, info->qpMax, /* override */ true); qpSpreadMaxPerFrameType(inFormat, info->qpDelta, info->qpMax, /* override */ true); } else { } ALOGD("codec %s: no qp bounding", codec->getName().c_str()); } } double bpp = codec->getBpp(); double bpp = codec->getBpp(); Loading Loading @@ -108,7 +126,7 @@ int VQApply(CodecProperties *codec, vqOps_t *info, AMediaFormat* inFormat, int f bitrateConfigured, bitrateFloor, codec->getBpp(), height, width); bitrateConfigured, bitrateFloor, codec->getBpp(), height, width); if (bitrateConfigured < bitrateFloor) { if (bitrateConfigured < bitrateFloor) { ALOGD("minquality/target bitrate raised from %d to %" PRId64 " to maintain quality", ALOGD("minquality/target bitrate raised from %d to %" PRId64 " bps", bitrateConfigured, bitrateFloor); bitrateConfigured, bitrateFloor); AMediaFormat_setInt32(inFormat, AMEDIAFORMAT_KEY_BIT_RATE, (int32_t)bitrateFloor); AMediaFormat_setInt32(inFormat, AMEDIAFORMAT_KEY_BIT_RATE, (int32_t)bitrateFloor); } } Loading @@ -121,16 +139,16 @@ int VQApply(CodecProperties *codec, vqOps_t *info, AMediaFormat* inFormat, int f bool hasQpPerFrameType(AMediaFormat *format) { bool hasQpPerFrameType(AMediaFormat *format) { int32_t value; int32_t value; if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MAX, &value) if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MAX, &value) || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MIN, &value)) { || AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MIN, &value)) { return true; return true; } } if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MAX, &value) if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MAX, &value) || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MIN, &value)) { || AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MIN, &value)) { return true; return true; } } if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MAX, &value) if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MAX, &value) || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MIN, &value)) { || AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MIN, &value)) { return true; return true; } } return false; return false; Loading @@ -138,8 +156,8 @@ bool hasQpPerFrameType(AMediaFormat *format) { bool hasQp(AMediaFormat *format) { bool hasQp(AMediaFormat *format) { int32_t value; int32_t value; if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MAX, &value) if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MAX, &value) || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MIN, &value)) { || AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MIN, &value)) { return true; return true; } } return hasQpPerFrameType(format); return hasQpPerFrameType(format); Loading