Merge "Better tuning hooks for mediaformatshaper" into sc-dev
diff --git a/media/libmediaformatshaper/CodecProperties.cpp b/media/libmediaformatshaper/CodecProperties.cpp
index d733c57..961f676 100644
--- a/media/libmediaformatshaper/CodecProperties.cpp
+++ b/media/libmediaformatshaper/CodecProperties.cpp
@@ -19,6 +19,7 @@
#include <utils/Log.h>
#include <string>
+#include <stdlib.h>
#include <media/formatshaper/CodecProperties.h>
@@ -63,17 +64,12 @@
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
+ if (!strcmp(key.c_str(), "qp-bounds")) { // official key
setSupportsQp(1);
- } else if (!strcmp(key.c_str(), "qp-bounds")) { // official key
+ } else if (!strcmp(key.c_str(), "vq-supports-qp")) { // key from prototyping
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);
+ } else if (!strcmp(key.c_str(), "vq-minimum-quality")) {
+ setSupportedMinimumQuality(1);
}
}
@@ -90,6 +86,63 @@
return false;
}
+// Tuning values (which differ from Features)
+// this is where we set up things like target bitrates and QP ranges
+// NB the tuning values arrive as a string, allowing us to convert it into an appropriate
+// format (int, float, ranges, other combinations)
+//
+void CodecProperties::setTuningValue(std::string key, std::string value) {
+ ALOGD("setTuningValue(%s,%s)", key.c_str(), value.c_str());
+ mTunings.insert({key, value});
+
+ bool legal = false;
+ // NB: old school strtol() because std::stoi() throws exceptions
+ if (!strcmp(key.c_str(), "vq-target-qpmax")) {
+ const char *p = value.c_str();
+ char *q;
+ int32_t iValue = strtol(p, &q, 0);
+ if (q != p) {
+ setTargetQpMax(iValue);
+ legal = true;
+ }
+ } else if (!strcmp(key.c_str(), "vq-target-bpp")) {
+ const char *p = value.c_str();
+ char *q;
+ double bpp = strtod(p, &q);
+ if (q != p) {
+ setBpp(bpp);
+ legal = true;
+ }
+ } else if (!strcmp(key.c_str(), "vq-target-bppx100")) {
+ const char *p = value.c_str();
+ char *q;
+ int32_t iValue = strtol(p, &q, 0);
+ if (q != p) {
+ double bpp = iValue / 100.0;
+ setBpp(bpp);
+ legal = true;
+ }
+ } else {
+ legal = true;
+ }
+
+ if (!legal) {
+ ALOGW("setTuningValue() unable to apply tuning '%s' with value '%s'",
+ key.c_str(), value.c_str());
+ }
+ return;
+}
+
+bool CodecProperties::getTuningValue(std::string key, std::string &value) {
+ ALOGV("getTuningValue(%s)", key.c_str());
+ auto mapped = mFeatures.find(key);
+ if (mapped != mFeatures.end()) {
+ value = mapped->second;
+ return true;
+ }
+ return false;
+}
+
std::string CodecProperties::getMapping(std::string key, std::string kind) {
ALOGV("getMapping(key %s, kind %s )", key.c_str(), kind.c_str());
diff --git a/media/libmediaformatshaper/CodecSeeding.cpp b/media/libmediaformatshaper/CodecSeeding.cpp
index 629b405..fde7833 100644
--- a/media/libmediaformatshaper/CodecSeeding.cpp
+++ b/media/libmediaformatshaper/CodecSeeding.cpp
@@ -26,56 +26,63 @@
namespace mediaformatshaper {
/*
- * a block of pre-loads; things the library seeds into the codecproperties based
+ * a block of pre-loaded tunings for codecs.
+ *
+ * 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 {
+ bool overrideable;
const char *key;
- int32_t value;
-} preloadFeature_t;
+ const char *value;
+} preloadTuning_t;
typedef struct {
const char *mediaType;
- preloadFeature_t *features;
-} preloadProperties_t;
+ preloadTuning_t *features;
+} preloadTunings_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 preloadTuning_t featuresAvc[] = {
+ {true, "vq-target-bpp", "2.45"},
+ {true, "vq-target-qpmax", "41"},
+ {true, nullptr, 0}
};
-static preloadFeature_t featuresHevc[] = {
- {"vq-target-bppx100", 240},
- {nullptr, 0}
+static preloadTuning_t featuresHevc[] = {
+ {true, "vq-target-bpp", "2.30"},
+ {true, "vq-target-qpmax", "42"}, // nop, since hevc codecs don't declare qp support
+ {true, nullptr, 0}
};
-static preloadFeature_t featuresGenericVideo[] = {
- {"vq-target-bppx100", 240},
- {nullptr, 0}
+static preloadTuning_t featuresGenericVideo[] = {
+ {true, "vq-target-bpp", "2.40"},
+ {true, nullptr, 0}
};
-static preloadProperties_t preloadProperties[] = {
+static preloadTunings_t preloadTunings[] = {
{ "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());
+void CodecProperties::addMediaDefaults(bool overrideable) {
+ ALOGD("Seed: codec %s, mediatype %s, overrideable %d",
+ mName.c_str(), mMediaType.c_str(), overrideable);
// load me up with initial configuration data
int count = 0;
- for (int i=0;; i++) {
- preloadProperties_t *p = &preloadProperties[i];
+ for (int i = 0; ; i++) {
+ preloadTunings_t *p = &preloadTunings[i];
if (p->mediaType == nullptr) {
break;
}
@@ -100,11 +107,14 @@
// walk through, filling things
if (p->features != nullptr) {
for (int j=0;; j++) {
- preloadFeature_t *q = &p->features[j];
+ preloadTuning_t *q = &p->features[j];
if (q->key == nullptr) {
break;
}
- setFeatureValue(q->key, q->value);
+ if (q->overrideable != overrideable) {
+ continue;
+ }
+ setTuningValue(q->key, q->value);
count++;
}
break;
@@ -113,13 +123,18 @@
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.
+// a chance, as we create the codec to inject any default behaviors we want.
+// XXX: consider whether we need pre/post or just post. it affects what can be
+// overridden by way of the codec XML
//
+void CodecProperties::Seed() {
+ ALOGV("Seed: for codec %s, mediatype %s", mName.c_str(), mMediaType.c_str());
+ addMediaDefaults(true);
+}
+
void CodecProperties::Finish() {
ALOGV("Finish: for codec %s, mediatype %s", mName.c_str(), mMediaType.c_str());
-
- // currently a no-op
+ addMediaDefaults(false);
}
} // namespace mediaformatshaper
diff --git a/media/libmediaformatshaper/FormatShaper.cpp b/media/libmediaformatshaper/FormatShaper.cpp
index a52edc2..42502e0 100644
--- a/media/libmediaformatshaper/FormatShaper.cpp
+++ b/media/libmediaformatshaper/FormatShaper.cpp
@@ -99,6 +99,23 @@
return 0;
}
+int setTuning(shaperHandle_t shaper, const char *tuning, const char *value) {
+ ALOGV("setTuning: tuning %s value %s", tuning, value);
+ CodecProperties *codec = (CodecProperties*) shaper;
+ if (codec == nullptr) {
+ return -1;
+ }
+ // must not yet be registered
+ if (codec->isRegistered()) {
+ return -1;
+ }
+
+ // save a map of all features
+ codec->setTuningValue(tuning, value);
+
+ return 0;
+}
+
/*
* The routines that manage finding, creating, and registering the shapers.
*/
@@ -176,6 +193,8 @@
.shapeFormat = shapeFormat,
.getMappings = getMappings,
.getReverseMappings = getReverseMappings,
+
+ .setTuning = setTuning,
};
} // namespace mediaformatshaper
diff --git a/media/libmediaformatshaper/include/media/formatshaper/CodecProperties.h b/media/libmediaformatshaper/include/media/formatshaper/CodecProperties.h
index e5cc9cf..84268b9 100644
--- a/media/libmediaformatshaper/include/media/formatshaper/CodecProperties.h
+++ b/media/libmediaformatshaper/include/media/formatshaper/CodecProperties.h
@@ -56,6 +56,10 @@
void setFeatureValue(std::string key, int32_t value);
bool getFeatureValue(std::string key, int32_t *valuep);
+ // keep a map of all tunings and their parameters
+ void setTuningValue(std::string key, std::string value);
+ bool getTuningValue(std::string key, std::string &value);
+
// does the codec support the Android S minimum quality rules
void setSupportedMinimumQuality(int vmaf);
int supportedMinimumQuality();
@@ -97,6 +101,10 @@
std::map<std::string, std::string> mMappings /*GUARDED_BY(mMappingLock)*/ ;
std::map<std::string, int32_t> mFeatures /*GUARDED_BY(mMappingLock)*/ ;
+ std::map<std::string, std::string> mTunings /*GUARDED_BY(mMappingLock)*/ ;
+
+ // Seed() and Finish() use this as the underlying implementation
+ void addMediaDefaults(bool overrideable);
bool mIsRegistered = false;
diff --git a/media/libmediaformatshaper/include/media/formatshaper/FormatShaper.h b/media/libmediaformatshaper/include/media/formatshaper/FormatShaper.h
index 8ad81cd..a1747cc 100644
--- a/media/libmediaformatshaper/include/media/formatshaper/FormatShaper.h
+++ b/media/libmediaformatshaper/include/media/formatshaper/FormatShaper.h
@@ -84,6 +84,12 @@
typedef int (*setFeature_t)(shaperHandle_t shaper, const char *feature, int value);
/*
+ * establishes that codec "codecName" encoding for "mediaType" supports the indicated
+ * tuning at the indicated value
+ */
+typedef int (*setTuning_t)(shaperHandle_t shaper, const char *feature, const char * value);
+
+/*
* The expectation is that the client will implement a flow similar to the following when
* setting up an encoding.
*
@@ -118,6 +124,10 @@
shapeFormat_t shapeFormat;
getMappings_t getMappings;
getMappings_t getReverseMappings;
+
+ setTuning_t setTuning;
+
+ // additions happen at the end of the structure
} FormatShaperOps_t;
// versioninf information
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 26cdec8..16cd5ca 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -109,6 +109,7 @@
static const char *kCodecLevel = "android.media.mediacodec.level"; /* 0..n */
static const char *kCodecBitrateMode = "android.media.mediacodec.bitrate_mode"; /* CQ/VBR/CBR */
static const char *kCodecBitrate = "android.media.mediacodec.bitrate"; /* 0..n */
+static const char *kCodecOriginalBitrate = "android.media.mediacodec.original.bitrate"; /* 0..n */
static const char *kCodecMaxWidth = "android.media.mediacodec.maxwidth"; /* 0..n */
static const char *kCodecMaxHeight = "android.media.mediacodec.maxheight"; /* 0..n */
static const char *kCodecError = "android.media.mediacodec.errcode";
@@ -139,6 +140,8 @@
static const char *kCodecRecentLatencyCount = "android.media.mediacodec.recent.n";
static const char *kCodecRecentLatencyHist = "android.media.mediacodec.recent.hist"; /* in us */
+static const char *kCodecShapingEnhanced = "android.media.mediacodec.shaped"; /* 0/1 */
+
// XXX suppress until we get our representation right
static bool kEmitHistogram = false;
@@ -1556,18 +1559,7 @@
static bool connectFormatShaper() {
static std::once_flag sCheckOnce;
-#if 0
- // an early return if the property says disabled means we skip loading.
- // that saves memory.
-
- // apply framework level modifications to the mediaformat for encoding
- // XXX: default off for a while during dogfooding
- int8_t enableShaping = property_get_bool(enableMediaFormatShapingProperty, 0);
-
- if (!enableShaping) {
- return true;
- }
-#endif
+ ALOGV("connectFormatShaper...");
std::call_once(sCheckOnce, [&](){
@@ -1672,6 +1664,8 @@
//
static const char *featurePrefix = "feature-";
static const int featurePrefixLen = strlen(featurePrefix);
+ static const char *tuningPrefix = "tuning-";
+ static const int tuningPrefixLen = strlen(tuningPrefix);
static const char *mappingPrefix = "mapping-";
static const int mappingPrefixLen = strlen(mappingPrefix);
@@ -1685,6 +1679,14 @@
intValue);
}
continue;
+ } else if (!strncmp(mapSrc, tuningPrefix, tuningPrefixLen)) {
+ AString value;
+ if (details->findString(mapSrc, &value)) {
+ ALOGV("-- tuning '%s' -> '%s'", mapSrc, value.c_str());
+ (void)(sShaperOps->setTuning)(shaperHandle, &mapSrc[tuningPrefixLen],
+ value.c_str());
+ }
+ continue;
} else if (!strncmp(mapSrc, mappingPrefix, mappingPrefixLen)) {
AString target;
if (details->findString(mapSrc, &target)) {
@@ -1801,10 +1803,20 @@
AMediaFormat_getFormat(updatedNdkFormat, &updatedFormat);
sp<AMessage> deltas = updatedFormat->changesFrom(format, false /* deep */);
- ALOGD("shapeMediaFormat: deltas: %s", deltas->debugString(2).c_str());
-
- // note that this means that for anything in both, the copy in deltas wins
- format->extend(deltas);
+ size_t changeCount = deltas->countEntries();
+ ALOGD("shapeMediaFormat: deltas(%zu): %s", changeCount, deltas->debugString(2).c_str());
+ if (changeCount > 0) {
+ if (mMetricsHandle != 0) {
+ mediametrics_setInt32(mMetricsHandle, kCodecShapingEnhanced, changeCount);
+ // save some old properties before we fold in the new ones
+ int32_t bitrate;
+ if (format->findInt32(KEY_BIT_RATE, &bitrate)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecOriginalBitrate, bitrate);
+ }
+ }
+ // NB: for any field in both format and deltas, the deltas copy wins
+ format->extend(deltas);
+ }
}
AMediaFormat_delete(updatedNdkFormat);
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index 5a9760d..67c6102 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -146,7 +146,10 @@
};
static std::vector<std::string> names = {
prefixes[0] + variants[0] + ".xml",
- prefixes[1] + variants[1] + ".xml"
+ prefixes[1] + variants[1] + ".xml",
+
+ // shaping information is not currently variant specific.
+ "media_codecs_shaping.xml"
};
return names;
}
@@ -347,6 +350,7 @@
status_t addFeature(const char **attrs);
status_t addLimit(const char **attrs);
status_t addMapping(const char **attrs);
+ status_t addTuning(const char **attrs);
status_t addQuirk(const char **attrs, const char *prefix = nullptr);
status_t addSetting(const char **attrs, const char *prefix = nullptr);
status_t enterMediaCodec(const char **attrs, bool encoder);
@@ -429,7 +433,7 @@
if (findFileInDirs(searchDirs, fileName, &path)) {
err = parseXmlPath(path);
} else {
- ALOGD("Cannot find %s in search path", fileName.c_str());
+ ALOGI("Did not find %s in search path", fileName.c_str());
}
res = combineStatus(res, err);
}
@@ -439,7 +443,7 @@
status_t MediaCodecsXmlParser::Impl::parseXmlPath(const std::string &path) {
std::lock_guard<std::mutex> guard(mLock);
if (!fileExists(path)) {
- ALOGD("Cannot find %s", path.c_str());
+ ALOGV("Cannot find %s", path.c_str());
mParsingStatus = combineStatus(mParsingStatus, NAME_NOT_FOUND);
return NAME_NOT_FOUND;
}
@@ -743,7 +747,8 @@
// ignore limits and features specified outside of type
if (!mState->inType()
&& (strEq(name, "Limit") || strEq(name, "Feature")
- || strEq(name, "Variant") || strEq(name, "Mapping"))) {
+ || strEq(name, "Variant") || strEq(name, "Mapping")
+ || strEq(name, "Tuning"))) {
PLOGD("ignoring %s specified outside of a Type", name);
return;
} else if (strEq(name, "Limit")) {
@@ -752,6 +757,8 @@
err = addFeature(attrs);
} else if (strEq(name, "Mapping")) {
err = addMapping(attrs);
+ } else if (strEq(name, "Tuning")) {
+ err = addTuning(attrs);
} else if (strEq(name, "Variant") && section != SECTION_VARIANT) {
err = limitVariants(attrs);
mState->enterSection(err == OK ? SECTION_VARIANT : SECTION_UNKNOWN);
@@ -1445,6 +1452,45 @@
return OK;
}
+status_t MediaCodecsXmlParser::Impl::Parser::addTuning(const char **attrs) {
+ CHECK(mState->inType());
+ size_t i = 0;
+ const char *a_name = nullptr;
+ const char *a_value = nullptr;
+
+ while (attrs[i] != nullptr) {
+ CHECK((i & 1) == 0);
+ if (attrs[i + 1] == nullptr) {
+ PLOGD("Mapping: attribute '%s' is null", attrs[i]);
+ return BAD_VALUE;
+ }
+
+ if (strEq(attrs[i], "name")) {
+ a_name = attrs[++i];
+ } else if (strEq(attrs[i], "value")) {
+ a_value = attrs[++i];
+ } else {
+ PLOGD("Tuning: ignoring unrecognized attribute '%s'", attrs[i]);
+ ++i;
+ }
+ ++i;
+ }
+
+ // Every tuning must have both fields
+ if (a_name == nullptr) {
+ PLOGD("Tuning with no 'name' attribute");
+ return BAD_VALUE;
+ }
+
+ if (a_value == nullptr) {
+ PLOGD("Tuning with no 'value' attribute");
+ return BAD_VALUE;
+ }
+
+ mState->addDetail(std::string("tuning-") + a_name, a_value);
+ return OK;
+}
+
status_t MediaCodecsXmlParser::Impl::Parser::addAlias(const char **attrs) {
CHECK(mState->inCodec());
size_t i = 0;
diff --git a/media/libstagefright/xmlparser/api/current.txt b/media/libstagefright/xmlparser/api/current.txt
index 6f55dc0..ecfd85e 100644
--- a/media/libstagefright/xmlparser/api/current.txt
+++ b/media/libstagefright/xmlparser/api/current.txt
@@ -87,6 +87,7 @@
method public String getName();
method public java.util.List<media.codecs.Quirk> getQuirk_optional();
method public String getRank();
+ method public java.util.List<media.codecs.Tuning> getTuning_optional();
method public String getType();
method public java.util.List<media.codecs.Type> getType_optional();
method public String getUpdate();
@@ -136,6 +137,14 @@
method public java.util.List<media.codecs.Setting> getVariant_optional();
}
+ public class Tuning {
+ ctor public Tuning();
+ method public String getName();
+ method public String getValue();
+ method public void setName(String);
+ method public void setValue(String);
+ }
+
public class Type {
ctor public Type();
method public java.util.List<media.codecs.Alias> getAlias();
diff --git a/media/libstagefright/xmlparser/media_codecs.xsd b/media/libstagefright/xmlparser/media_codecs.xsd
index 30974f6..c9a7efc 100644
--- a/media/libstagefright/xmlparser/media_codecs.xsd
+++ b/media/libstagefright/xmlparser/media_codecs.xsd
@@ -64,6 +64,7 @@
<xs:element name="Limit" type="Limit" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="Feature" type="Feature" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="Mapping" type="Mapping" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="Tuning" type="Tuning" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="Variant" type="Variant" minOccurs="0" maxOccurs="unbounded"/>
</xs:choice>
<xs:attribute name="name" type="xs:string"/>
@@ -128,6 +129,10 @@
<xs:attribute name="kind" type="xs:string"/>
<xs:attribute name="value" type="xs:string"/>
</xs:complexType>
+ <xs:complexType name="Tuning">
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="value" type="xs:string"/>
+ </xs:complexType>
<xs:complexType name="Include">
<xs:attribute name="href" type="xs:string"/>
</xs:complexType>
diff --git a/media/libstagefright/xmlparser/test/XMLParserTest.cpp b/media/libstagefright/xmlparser/test/XMLParserTest.cpp
index c411c8d..7629d97 100644
--- a/media/libstagefright/xmlparser/test/XMLParserTest.cpp
+++ b/media/libstagefright/xmlparser/test/XMLParserTest.cpp
@@ -138,6 +138,12 @@
pair<string, string>("mapping-fire-from", "to"),
},
{}, "");
+ setCodecProperties("test11.encoder", true, 11, {}, {}, {}, "video/av01",
+ {
+ pair<string, string>("tuning-hungry", "yes"),
+ pair<string, string>("tuning-pi", "3.1415"),
+ },
+ {}, "");
setRoleProperties("audio_decoder.mp3", false, 1, "audio/mpeg", "test1.decoder",
{pair<string, string>("attribute::disabled", "present"),
@@ -180,6 +186,11 @@
setRoleProperties("video_encoder.hevc", true, 10, "video/hevc", "test10.encoder",
{ pair<string, string>("mapping-fire-from", "to")});
+ setRoleProperties("video_encoder.av01", true, 11, "video/av01", "test11.encoder",
+ {pair<string, string>("tuning-hungry", "yes"),
+ pair<string, string>("tuning-pi", "3.1415")
+ });
+
setServiceAttribute(
{pair<string, string>("domain-telephony", "0"), pair<string, string>("domain-tv", "0"),
pair<string, string>("setting2", "0"), pair<string, string>("variant-variant1", "0")});
diff --git a/media/libstagefright/xmlparser/test/testdata/media_codecs_unit_test.xml b/media/libstagefright/xmlparser/test/testdata/media_codecs_unit_test.xml
index c8913e5..8cae423 100644
--- a/media/libstagefright/xmlparser/test/testdata/media_codecs_unit_test.xml
+++ b/media/libstagefright/xmlparser/test/testdata/media_codecs_unit_test.xml
@@ -83,5 +83,10 @@
<MediaCodec name="test10.encoder" type="video/hevc" >
<Mapping kind="fire" name="from" value="to"/>
</MediaCodec>
+ <!-- entry for testing Tuning -->
+ <MediaCodec name="test11.encoder" type="video/av01" >
+ <Tuning name="hungry" value="yes"/>
+ <Tuning name="pi" value="3.1415"/>
+ </MediaCodec>
</Encoders>
</Included>