Merge "apexes: set maxSdk to 29 (Q)" into qt-dev
diff --git a/apex/Android.bp b/apex/Android.bp
index ec0efe6..42a620b 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -12,22 +12,30 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-com_android_media_extractors = [
- "libaacextractor",
- "libamrextractor",
- "libflacextractor",
- "libmidiextractor",
- "libmkvextractor",
- "libmp3extractor",
- "libmp4extractor",
- "libmpeg2extractor",
- "liboggextractor",
- "libwavextractor",
-]
-
apex_defaults {
name: "com.android.media-defaults",
java_libs: ["updatable-media"],
+ multilib: {
+ first: {
+ // Extractor process runs only with the primary ABI.
+ native_shared_libs: [
+ // Extractor plugins
+ "libaacextractor",
+ "libamrextractor",
+ "libflacextractor",
+ "libmidiextractor",
+ "libmkvextractor",
+ "libmp3extractor",
+ "libmp4extractor",
+ "libmpeg2extractor",
+ "liboggextractor",
+ "libwavextractor",
+ ],
+ },
+ },
+ prebuilts: [
+ "mediaextractor.policy",
+ ],
key: "com.android.media.key",
certificate: ":com.android.media.certificate",
@@ -39,12 +47,6 @@
name: "com.android.media",
manifest: "manifest.json",
defaults: ["com.android.media-defaults"],
- multilib: {
- first: {
- // Extractor process runs only with the primary ABI.
- native_shared_libs: com_android_media_extractors,
- },
- },
}
filegroup {
@@ -66,6 +68,7 @@
"com.android.media.swcodec-mediaswcodec.rc",
"com.android.media.swcodec-ld.config.txt",
"mediaswcodec.policy",
+ "mediaswcodec.xml",
],
use_vendor: true,
key: "com.android.media.swcodec.key",
diff --git a/apex/manifest.json b/apex/manifest.json
index cee94e2..03b9dd0 100644
--- a/apex/manifest.json
+++ b/apex/manifest.json
@@ -1,4 +1,4 @@
{
"name": "com.android.media",
- "version": 210000000
+ "version": 220000000
}
diff --git a/apex/manifest_codec.json b/apex/manifest_codec.json
index b83e65a..58ce868 100644
--- a/apex/manifest_codec.json
+++ b/apex/manifest_codec.json
@@ -1,4 +1,4 @@
{
"name": "com.android.media.swcodec",
- "version": 210000000
+ "version": 220000000
}
diff --git a/apex/testing/Android.bp b/apex/testing/Android.bp
index 297d864..701ced7 100644
--- a/apex/testing/Android.bp
+++ b/apex/testing/Android.bp
@@ -17,13 +17,6 @@
manifest: "test_manifest.json",
file_contexts: "com.android.media",
defaults: ["com.android.media-defaults"],
- multilib: {
- both: {
- // for test apex, built for both ABIs
- native_shared_libs: com_android_media_extractors,
- },
- },
- compile_multilib: "both",
installable: false,
}
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index 4dda5d7..d62ccd6 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -301,7 +301,7 @@
ssize_t offset;
size_t size;
- if (memory == NULL && buffer == NULL) {
+ if (memory == NULL || buffer == NULL) {
return UNEXPECTED_NULL;
}
diff --git a/media/bufferpool/1.0/Connection.cpp b/media/bufferpool/1.0/Connection.cpp
index e58f595..be89701 100644
--- a/media/bufferpool/1.0/Connection.cpp
+++ b/media/bufferpool/1.0/Connection.cpp
@@ -32,14 +32,22 @@
status = mAccessor->fetch(
mConnectionId, transactionId, bufferId, &handle);
if (status == ResultStatus::OK) {
- _hidl_cb(status, Buffer{bufferId, handle});
+ Buffer buffer = {};
+ buffer.id = bufferId;
+ buffer.buffer = handle;
+ _hidl_cb(status, buffer);
return Void();
}
} else {
mAccessor->cleanUp(false);
}
}
- _hidl_cb(status, Buffer{0, nullptr});
+
+ Buffer buffer = {};
+ buffer.id = 0;
+ buffer.buffer = nullptr;
+
+ _hidl_cb(status, buffer);
return Void();
}
diff --git a/media/bufferpool/2.0/Connection.cpp b/media/bufferpool/2.0/Connection.cpp
index 6bd0e79..57d0c7e 100644
--- a/media/bufferpool/2.0/Connection.cpp
+++ b/media/bufferpool/2.0/Connection.cpp
@@ -32,14 +32,22 @@
status = mAccessor->fetch(
mConnectionId, transactionId, bufferId, &handle);
if (status == ResultStatus::OK) {
- _hidl_cb(status, Buffer{bufferId, handle});
+ Buffer buffer = {};
+ buffer.id = bufferId;
+ buffer.buffer = handle;
+ _hidl_cb(status, buffer);
return Void();
}
} else {
mAccessor->cleanUp(false);
}
}
- _hidl_cb(status, Buffer{0, nullptr});
+
+ Buffer buffer = {};
+ buffer.id = 0;
+ buffer.buffer = nullptr;
+
+ _hidl_cb(status, buffer);
return Void();
}
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index ead0a9b..1919597 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -212,6 +212,76 @@
}
}
+class Switch {
+ enum Flags : uint8_t {
+ // flags
+ IS_ENABLED = (1 << 0),
+ BY_DEFAULT = (1 << 1),
+ };
+
+ constexpr Switch(uint8_t flags) : mFlags(flags) {}
+
+ uint8_t mFlags;
+
+public:
+ // have to create class due to this bool conversion operator...
+ constexpr operator bool() const {
+ return mFlags & IS_ENABLED;
+ }
+
+ constexpr Switch operator!() const {
+ return Switch(mFlags ^ IS_ENABLED);
+ }
+
+ static constexpr Switch DISABLED() { return 0; };
+ static constexpr Switch ENABLED() { return IS_ENABLED; };
+ static constexpr Switch DISABLED_BY_DEFAULT() { return BY_DEFAULT; };
+ static constexpr Switch ENABLED_BY_DEFAULT() { return IS_ENABLED | BY_DEFAULT; };
+
+ const char *toString(const char *def = "??") const {
+ switch (mFlags) {
+ case 0: return "0";
+ case IS_ENABLED: return "1";
+ case BY_DEFAULT: return "(0)";
+ case IS_ENABLED | BY_DEFAULT: return "(1)";
+ default: return def;
+ }
+ }
+
+};
+
+const char *asString(const Switch &s, const char *def = "??") {
+ return s.toString(def);
+}
+
+Switch isSettingEnabled(
+ std::string setting, const MediaCodecsXmlParser::AttributeMap &settings,
+ Switch def = Switch::DISABLED_BY_DEFAULT()) {
+ const auto enablement = settings.find(setting);
+ if (enablement == settings.end()) {
+ return def;
+ }
+ return enablement->second == "1" ? Switch::ENABLED() : Switch::DISABLED();
+}
+
+Switch isVariantEnabled(
+ std::string variant, const MediaCodecsXmlParser::AttributeMap &settings) {
+ return isSettingEnabled("variant-" + variant, settings);
+}
+
+Switch isVariantExpressionEnabled(
+ std::string exp, const MediaCodecsXmlParser::AttributeMap &settings) {
+ if (!exp.empty() && exp.at(0) == '!') {
+ return !isVariantEnabled(exp.substr(1, exp.size() - 1), settings);
+ }
+ return isVariantEnabled(exp, settings);
+}
+
+Switch isDomainEnabled(
+ std::string domain, const MediaCodecsXmlParser::AttributeMap &settings) {
+ return isSettingEnabled("domain-" + domain, settings);
+}
+
} // unnamed namespace
status_t Codec2InfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
@@ -248,15 +318,33 @@
// Obtain Codec2Client
std::vector<Traits> traits = Codec2Client::ListComponents();
- MediaCodecsXmlParser parser(
- MediaCodecsXmlParser::defaultSearchDirs,
- "media_codecs_c2.xml",
- "media_codecs_performance_c2.xml");
+ // parse APEX XML first, followed by vendor XML
+ MediaCodecsXmlParser parser;
+ parser.parseXmlFilesInSearchDirs(
+ parser.getDefaultXmlNames(),
+ { "/apex/com.android.media.swcodec/etc" });
+
+ // TODO: remove these c2-specific files once product moved to default file names
+ parser.parseXmlFilesInSearchDirs(
+ { "media_codecs_c2.xml", "media_codecs_performance_c2.xml" });
+
+ // parse default XML files
+ parser.parseXmlFilesInSearchDirs();
+
if (parser.getParsingStatus() != OK) {
ALOGD("XML parser no good");
return OK;
}
+ MediaCodecsXmlParser::AttributeMap settings = parser.getServiceAttributeMap();
+ for (const auto &v : settings) {
+ if (!hasPrefix(v.first, "media-type-")
+ && !hasPrefix(v.first, "domain-")
+ && !hasPrefix(v.first, "variant-")) {
+ writer->addGlobalSetting(v.first.c_str(), v.second.c_str());
+ }
+ }
+
for (const Traits& trait : traits) {
C2Component::rank_t rank = trait.rank;
@@ -341,12 +429,42 @@
break;
}
+ const MediaCodecsXmlParser::CodecProperties &codec =
+ parser.getCodecMap().at(nameOrAlias);
+
+ // verify that either the codec is explicitly enabled, or one of its domains is
+ bool codecEnabled = codec.quirkSet.find("attribute::disabled") == codec.quirkSet.end();
+ if (!codecEnabled) {
+ for (const std::string &domain : codec.domainSet) {
+ const Switch enabled = isDomainEnabled(domain, settings);
+ ALOGV("codec entry '%s' is in domain '%s' that is '%s'",
+ nameOrAlias.c_str(), domain.c_str(), asString(enabled));
+ if (enabled) {
+ codecEnabled = true;
+ break;
+ }
+ }
+ }
+ // if codec has variants, also check that at least one of them is enabled
+ bool variantEnabled = codec.variantSet.empty();
+ for (const std::string &variant : codec.variantSet) {
+ const Switch enabled = isVariantExpressionEnabled(variant, settings);
+ ALOGV("codec entry '%s' has a variant '%s' that is '%s'",
+ nameOrAlias.c_str(), variant.c_str(), asString(enabled));
+ if (enabled) {
+ variantEnabled = true;
+ break;
+ }
+ }
+ if (!codecEnabled || !variantEnabled) {
+ ALOGD("codec entry for '%s' is disabled", nameOrAlias.c_str());
+ continue;
+ }
+
ALOGV("adding codec entry for '%s'", nameOrAlias.c_str());
std::unique_ptr<MediaCodecInfoWriter> codecInfo = writer->addMediaCodecInfo();
codecInfo->setName(nameOrAlias.c_str());
codecInfo->setOwner(("codec2::" + trait.owner).c_str());
- const MediaCodecsXmlParser::CodecProperties &codec =
- parser.getCodecMap().at(nameOrAlias);
bool encoder = trait.kind == C2Component::KIND_ENCODER;
typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs = 0;
@@ -373,6 +491,7 @@
rank = xmlRank;
}
}
+ ALOGV("rank: %u", (unsigned)rank);
codecInfo->setRank(rank);
for (const std::string &alias : codec.aliases) {
@@ -382,12 +501,39 @@
for (auto typeIt = codec.typeMap.begin(); typeIt != codec.typeMap.end(); ++typeIt) {
const std::string &mediaType = typeIt->first;
+ const Switch typeEnabled = isSettingEnabled(
+ "media-type-" + mediaType, settings, Switch::ENABLED_BY_DEFAULT());
+ const Switch domainTypeEnabled = isSettingEnabled(
+ "media-type-" + mediaType + (encoder ? "-encoder" : "-decoder"),
+ settings, Switch::ENABLED_BY_DEFAULT());
+ ALOGV("type '%s-%s' is '%s/%s'",
+ mediaType.c_str(), (encoder ? "encoder" : "decoder"),
+ asString(typeEnabled), asString(domainTypeEnabled));
+ if (!typeEnabled || !domainTypeEnabled) {
+ ALOGD("media type '%s' for codec entry '%s' is disabled", mediaType.c_str(),
+ nameOrAlias.c_str());
+ continue;
+ }
+
+ ALOGI("adding type '%s'", typeIt->first.c_str());
const MediaCodecsXmlParser::AttributeMap &attrMap = typeIt->second;
std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
codecInfo->addMediaType(mediaType.c_str());
- for (auto attrIt = attrMap.begin(); attrIt != attrMap.end(); ++attrIt) {
- std::string key, value;
- std::tie(key, value) = *attrIt;
+ for (const auto &v : attrMap) {
+ std::string key = v.first;
+ std::string value = v.second;
+
+ size_t variantSep = key.find(":::");
+ if (variantSep != std::string::npos) {
+ std::string variant = key.substr(0, variantSep);
+ const Switch enabled = isVariantExpressionEnabled(variant, settings);
+ ALOGV("variant '%s' is '%s'", variant.c_str(), asString(enabled));
+ if (!enabled) {
+ continue;
+ }
+ key = key.substr(variantSep + 3);
+ }
+
if (key.find("feature-") == 0 && key.find("feature-bitrate-modes") != 0) {
int32_t intValue = 0;
// Ignore trailing bad characters and default to 0.
diff --git a/media/extractors/aac/Android.bp b/media/extractors/aac/Android.bp
index 6fe5970..a58167a 100644
--- a/media/extractors/aac/Android.bp
+++ b/media/extractors/aac/Android.bp
@@ -20,7 +20,7 @@
name: "libaacextractor",
relative_install_path: "extractors",
- compile_multilib: "both",
+ compile_multilib: "first",
cflags: [
"-Werror",
diff --git a/media/extractors/amr/Android.bp b/media/extractors/amr/Android.bp
index b26b2d8..4bd933d 100644
--- a/media/extractors/amr/Android.bp
+++ b/media/extractors/amr/Android.bp
@@ -18,7 +18,7 @@
name: "libamrextractor",
relative_install_path: "extractors",
- compile_multilib: "both",
+ compile_multilib: "first",
cflags: [
"-Werror",
diff --git a/media/extractors/flac/Android.bp b/media/extractors/flac/Android.bp
index 3e83090..3a3d051 100644
--- a/media/extractors/flac/Android.bp
+++ b/media/extractors/flac/Android.bp
@@ -24,7 +24,7 @@
name: "libflacextractor",
relative_install_path: "extractors",
- compile_multilib: "both",
+ compile_multilib: "first",
cflags: [
"-Werror",
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index 6790dd6..7d42e70 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -19,7 +19,7 @@
name: "libmidiextractor",
relative_install_path: "extractors",
- compile_multilib: "both",
+ compile_multilib: "first",
cflags: [
"-Werror",
diff --git a/media/extractors/mkv/Android.bp b/media/extractors/mkv/Android.bp
index 7c94149..1744d3d 100644
--- a/media/extractors/mkv/Android.bp
+++ b/media/extractors/mkv/Android.bp
@@ -25,7 +25,7 @@
name: "libmkvextractor",
relative_install_path: "extractors",
- compile_multilib: "both",
+ compile_multilib: "first",
cflags: [
"-Werror",
diff --git a/media/extractors/mp3/Android.bp b/media/extractors/mp3/Android.bp
index 168ef68..4e2f248 100644
--- a/media/extractors/mp3/Android.bp
+++ b/media/extractors/mp3/Android.bp
@@ -24,7 +24,7 @@
name: "libmp3extractor",
relative_install_path: "extractors",
- compile_multilib: "both",
+ compile_multilib: "first",
cflags: [
"-Werror",
diff --git a/media/extractors/mp4/Android.bp b/media/extractors/mp4/Android.bp
index 9b9c931..1b308aa 100644
--- a/media/extractors/mp4/Android.bp
+++ b/media/extractors/mp4/Android.bp
@@ -32,7 +32,7 @@
],
version_script: "exports.lds",
relative_install_path: "extractors",
- compile_multilib: "both",
+ compile_multilib: "first",
}
cc_library_shared {
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
index 14f49ae..0f0c72c 100644
--- a/media/extractors/mpeg2/Android.bp
+++ b/media/extractors/mpeg2/Android.bp
@@ -40,7 +40,7 @@
name: "libmpeg2extractor",
relative_install_path: "extractors",
- compile_multilib: "both",
+ compile_multilib: "first",
cflags: [
"-Werror",
diff --git a/media/extractors/ogg/Android.bp b/media/extractors/ogg/Android.bp
index fd03f64..604ec59 100644
--- a/media/extractors/ogg/Android.bp
+++ b/media/extractors/ogg/Android.bp
@@ -26,7 +26,7 @@
name: "liboggextractor",
relative_install_path: "extractors",
- compile_multilib: "both",
+ compile_multilib: "first",
cflags: [
"-Werror",
diff --git a/media/extractors/wav/Android.bp b/media/extractors/wav/Android.bp
index 15fd796..7e89271 100644
--- a/media/extractors/wav/Android.bp
+++ b/media/extractors/wav/Android.bp
@@ -21,7 +21,7 @@
name: "libwavextractor",
relative_install_path: "extractors",
- compile_multilib: "both",
+ compile_multilib: "first",
cflags: [
"-Werror",
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 4a65fc9..71efc30 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -63,7 +63,9 @@
// TODO Support UNSPECIFIED in AudioRecord. For now, use stereo if unspecified.
int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
? 2 : getSamplesPerFrame();
- audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(samplesPerFrame);
+ audio_channel_mask_t channelMask = samplesPerFrame <= 2 ?
+ audio_channel_in_mask_from_count(samplesPerFrame) :
+ audio_channel_mask_for_index_assignment_from_count(samplesPerFrame);
size_t frameCount = (builder.getBufferCapacity() == AAUDIO_UNSPECIFIED) ? 0
: builder.getBufferCapacity();
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index d628bf7..094cdd1 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -66,7 +66,9 @@
// Use stereo if unspecified.
int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
? 2 : getSamplesPerFrame();
- audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(samplesPerFrame);
+ audio_channel_mask_t channelMask = samplesPerFrame <= 2 ?
+ audio_channel_out_mask_from_count(samplesPerFrame) :
+ audio_channel_mask_for_index_assignment_from_count(samplesPerFrame);
audio_output_flags_t flags;
aaudio_performance_mode_t perfMode = getPerformanceMode();
diff --git a/media/libstagefright/codecs/amrwb/src/deemphasis_32.cpp b/media/libstagefright/codecs/amrwb/src/deemphasis_32.cpp
index b80555b..c0e4c51 100644
--- a/media/libstagefright/codecs/amrwb/src/deemphasis_32.cpp
+++ b/media/libstagefright/codecs/amrwb/src/deemphasis_32.cpp
@@ -131,7 +131,7 @@
int16 lo, hi;
L_tmp = ((int32)x_hi[0]) << 16;
- L_tmp += ((int32)x_lo[0]) << 4;
+ L_tmp += (((int32)x_lo[0]) << 4) & 0xFFFF;
L_tmp = shl_int32(L_tmp, 3);
L_tmp = fxp_mac_16by16(*mem, mu, L_tmp),
@@ -144,7 +144,7 @@
for (i = 1; i < L - 1; i++)
{
L_tmp = ((int32)hi) << 16;
- L_tmp += ((int32)lo) << 4;
+ L_tmp += (((int32)lo) << 4) & 0xFFFF;
L_tmp = shl_int32(L_tmp, 3);
L_tmp = fxp_mac_16by16(y[i - 1], mu, L_tmp),
L_tmp = shl_int32(L_tmp, 1); /* saturation can occur here */
@@ -153,7 +153,7 @@
hi = x_hi[i+1];
}
L_tmp = ((int32)hi) << 16;
- L_tmp += ((int32)lo) << 4;
+ L_tmp += (((int32)lo) << 4) & 0xFFFF;
L_tmp = shl_int32(L_tmp, 3);
L_tmp = fxp_mac_16by16(y[i - 1], mu, L_tmp),
L_tmp = shl_int32(L_tmp, 1); /* saturation can occur here */
diff --git a/media/libstagefright/data/Android.bp b/media/libstagefright/data/Android.bp
new file mode 100644
index 0000000..616b4b3
--- /dev/null
+++ b/media/libstagefright/data/Android.bp
@@ -0,0 +1,6 @@
+prebuilt_etc {
+ name: "mediaswcodec.xml",
+ src: "media_codecs_sw.xml",
+ filename: "media_codecs.xml",
+ installable: false,
+}
diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml
new file mode 100644
index 0000000..7ee1f4d
--- /dev/null
+++ b/media/libstagefright/data/media_codecs_sw.xml
@@ -0,0 +1,321 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<MediaCodecs>
+ <Settings>
+ <!-- disable TV and telephony domains by default. These must be opted in by OEMs -->
+ <Domain name="telephony" enabled="false" />
+ <Domain name="tv" enabled="false" />
+ <Variant name="slow-cpu" enabled="false" />
+ </Settings>
+ <Decoders>
+ <MediaCodec name="c2.android.mp3.decoder" type="audio/mpeg">
+ <Alias name="OMX.google.mp3.decoder" />
+ <Limit name="channel-count" max="2" />
+ <Limit name="sample-rate" ranges="8000,11025,12000,16000,22050,24000,32000,44100,48000" />
+ <Limit name="bitrate" range="8000-320000" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.amrnb.decoder" type="audio/3gpp">
+ <Alias name="OMX.google.amrnb.decoder" />
+ <Limit name="channel-count" max="1" />
+ <Limit name="sample-rate" ranges="8000" />
+ <Limit name="bitrate" range="4750-12200" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.amrwb.decoder" type="audio/amr-wb">
+ <Alias name="OMX.google.amrwb.decoder" />
+ <Limit name="channel-count" max="1" />
+ <Limit name="sample-rate" ranges="16000" />
+ <Limit name="bitrate" range="6600-23850" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.aac.decoder" type="audio/mp4a-latm">
+ <Alias name="OMX.google.aac.decoder" />
+ <Limit name="channel-count" max="8" />
+ <Limit name="sample-rate" ranges="7350,8000,11025,12000,16000,22050,24000,32000,44100,48000" />
+ <Limit name="bitrate" range="8000-960000" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.g711.alaw.decoder" type="audio/g711-alaw">
+ <Alias name="OMX.google.g711.alaw.decoder" />
+ <Limit name="channel-count" max="1" />
+ <Limit name="sample-rate" ranges="8000-48000" />
+ <Limit name="bitrate" range="64000" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.g711.mlaw.decoder" type="audio/g711-mlaw">
+ <Alias name="OMX.google.g711.mlaw.decoder" />
+ <Limit name="channel-count" max="1" />
+ <Limit name="sample-rate" ranges="8000-48000" />
+ <Limit name="bitrate" range="64000" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.vorbis.decoder" type="audio/vorbis">
+ <Alias name="OMX.google.vorbis.decoder" />
+ <Limit name="channel-count" max="8" />
+ <Limit name="sample-rate" ranges="8000-96000" />
+ <Limit name="bitrate" range="32000-500000" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.opus.decoder" type="audio/opus">
+ <Alias name="OMX.google.opus.decoder" />
+ <Limit name="channel-count" max="8" />
+ <Limit name="sample-rate" ranges="48000" />
+ <Limit name="bitrate" range="6000-510000" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.raw.decoder" type="audio/raw">
+ <Alias name="OMX.google.raw.decoder" />
+ <Limit name="channel-count" max="8" />
+ <Limit name="sample-rate" ranges="8000-96000" />
+ <Limit name="bitrate" range="1-10000000" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.flac.decoder" type="audio/flac">
+ <Alias name="OMX.google.flac.decoder" />
+ <Limit name="channel-count" max="8" />
+ <Limit name="sample-rate" ranges="1-655350" />
+ <Limit name="bitrate" range="1-21000000" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.gsm.decoder" type="audio/gsm" domain="telephony">
+ <Alias name="OMX.google.gsm.decoder" />
+ <Limit name="channel-count" max="1" />
+ <Limit name="sample-rate" ranges="8000" />
+ <Limit name="bitrate" range="13000" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.mpeg4.decoder" type="video/mp4v-es">
+ <Alias name="OMX.google.mpeg4.decoder" />
+ <!-- profiles and levels: ProfileSimple : Level3 -->
+ <Limit name="size" min="2x2" max="352x288" />
+ <Limit name="alignment" value="2x2" />
+ <Limit name="block-size" value="16x16" />
+ <Limit name="blocks-per-second" range="12-11880" />
+ <Limit name="bitrate" range="1-384000" />
+ <Feature name="adaptive-playback" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.h263.decoder" type="video/3gpp">
+ <Alias name="OMX.google.h263.decoder" />
+ <!-- profiles and levels: ProfileBaseline : Level30, ProfileBaseline : Level45
+ ProfileISWV2 : Level30, ProfileISWV2 : Level45 -->
+ <Limit name="size" min="2x2" max="352x288" />
+ <Limit name="alignment" value="2x2" />
+ <Limit name="bitrate" range="1-384000" />
+ <Feature name="adaptive-playback" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.avc.decoder" type="video/avc" variant="slow-cpu,!slow-cpu">
+ <Alias name="OMX.google.h264.decoder" />
+ <Limit name="alignment" value="2x2" />
+ <Limit name="block-size" value="16x16" />
+ <Variant name="!slow-cpu">
+ <Limit name="size" min="2x2" max="4080x4080" />
+ <!-- profiles and levels: ProfileHigh : Level52 -->
+ <Limit name="block-count" range="1-32768" /> <!-- max 4096x2048 equivalent -->
+ <Limit name="blocks-per-second" range="1-1966080" />
+ <Limit name="bitrate" range="1-48000000" />
+ </Variant>
+ <Variant name="slow-cpu">
+ <Limit name="size" min="2x2" max="2048x2048" />
+ <!-- profiles and levels: ProfileHigh : Level51 -->
+ <Limit name="block-count" range="1-16384" />
+ <Limit name="blocks-per-second" range="1-491520" />
+ <Limit name="bitrate" range="1-40000000" />
+ </Variant>
+ <Feature name="adaptive-playback" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.hevc.decoder" type="video/hevc" variant="slow-cpu,!slow-cpu">
+ <Alias name="OMX.google.hevc.decoder" />
+ <Limit name="alignment" value="2x2" />
+ <Limit name="block-size" value="8x8" />
+ <Variant name="!slow-cpu">
+ <Limit name="size" min="2x2" max="4096x4096" />
+ <!-- profiles and levels: ProfileMain : MainTierLevel51 -->
+ <Limit name="block-count" range="1-196608" /> <!-- max 4096x3072 -->
+ <Limit name="blocks-per-second" range="1-2000000" />
+ <Limit name="bitrate" range="1-10000000" />
+ </Variant>
+ <Variant name="slow-cpu">
+ <Limit name="size" min="2x2" max="2048x2048" />
+ <!-- profiles and levels: ProfileMain : MainTierLevel51 -->
+ <Limit name="block-count" range="1-65536" />
+ <Limit name="blocks-per-second" range="1-491520" />
+ <Limit name="bitrate" range="1-5000000" />
+ </Variant>
+ <Feature name="adaptive-playback" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.vp8.decoder" type="video/x-vnd.on2.vp8" variant="slow-cpu,!slow-cpu">
+ <Alias name="OMX.google.vp8.decoder" />
+ <Limit name="size" min="2x2" max="2048x2048" />
+ <Limit name="alignment" value="2x2" />
+ <Limit name="block-size" value="16x16" />
+ <Variant name="!slow-cpu">
+ <Limit name="block-count" range="1-16384" />
+ <Limit name="blocks-per-second" range="1-1000000" />
+ <Limit name="bitrate" range="1-40000000" />
+ </Variant>
+ <Variant name="slow-cpu">
+ <Limit name="block-count" range="1-8192" /> <!-- max 2048x1024 -->
+ <Limit name="blocks-per-second" range="1-1000000" />
+ <Limit name="bitrate" range="1-40000000" />
+ </Variant>
+ <Feature name="adaptive-playback" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.vp9.decoder" type="video/x-vnd.on2.vp9" variant="slow-cpu,!slow-cpu">
+ <Alias name="OMX.google.vp9.decoder" />
+ <Limit name="alignment" value="2x2" />
+ <Limit name="block-size" value="16x16" />
+ <Variant name="!slow-cpu">
+ <Limit name="size" min="2x2" max="2048x2048" />
+ <Limit name="block-count" range="1-16384" />
+ <Limit name="blocks-per-second" range="1-500000" />
+ <Limit name="bitrate" range="1-40000000" />
+ </Variant>
+ <Variant name="slow-cpu">
+ <Limit name="size" min="2x2" max="1280x1280" />
+ <Limit name="block-count" range="1-3600" /> <!-- max 1280x720 -->
+ <Limit name="blocks-per-second" range="1-108000" />
+ <Limit name="bitrate" range="1-5000000" />
+ </Variant>
+ <Feature name="adaptive-playback" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.av1.decoder" type="video/av01" variant="!slow-cpu">
+ <Limit name="size" min="2x2" max="1920x1080" />
+ <Limit name="alignment" value="2x2" />
+ <Limit name="block-size" value="16x16" />
+ <Limit name="block-count" range="1-16384" />
+ <Limit name="blocks-per-second" range="1-2073600" />
+ <Limit name="bitrate" range="1-120000000" />
+ <Feature name="adaptive-playback" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.mpeg2.decoder" type="video/mpeg2" domain="tv">
+ <Alias name="OMX.google.mpeg2.decoder" />
+ <!-- profiles and levels: ProfileMain : LevelHL -->
+ <Limit name="size" min="16x16" max="1920x1088" />
+ <Limit name="alignment" value="2x2" />
+ <Limit name="block-size" value="16x16" />
+ <Limit name="blocks-per-second" range="1-244800" />
+ <Limit name="bitrate" range="1-20000000" />
+ <Feature name="adaptive-playback" />
+ </MediaCodec>
+ </Decoders>
+ <Encoders>
+ <MediaCodec name="c2.android.aac.encoder" type="audio/mp4a-latm">
+ <Alias name="OMX.google.aac.encoder" />
+ <Limit name="channel-count" max="6" />
+ <Limit name="sample-rate" ranges="8000,11025,12000,16000,22050,24000,32000,44100,48000" />
+ <!-- also may support 64000, 88200 and 96000 Hz -->
+ <Limit name="bitrate" range="8000-960000" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.amrnb.encoder" type="audio/3gpp">
+ <Alias name="OMX.google.amrnb.encoder" />
+ <Limit name="channel-count" max="1" />
+ <Limit name="sample-rate" ranges="8000" />
+ <Limit name="bitrate" range="4750-12200" />
+ <Feature name="bitrate-modes" value="CBR" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.amrwb.encoder" type="audio/amr-wb">
+ <Alias name="OMX.google.amrwb.encoder" />
+ <Limit name="channel-count" max="1" />
+ <Limit name="sample-rate" ranges="16000" />
+ <Limit name="bitrate" range="6600-23850" />
+ <Feature name="bitrate-modes" value="CBR" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.flac.encoder" type="audio/flac">
+ <Alias name="OMX.google.flac.encoder" />
+ <Limit name="channel-count" max="2" />
+ <Limit name="sample-rate" ranges="1-655350" />
+ <Limit name="bitrate" range="1-21000000" />
+ <Limit name="complexity" range="0-8" default="5" />
+ <Feature name="bitrate-modes" value="CQ" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.opus.encoder" type="audio/opus">
+ <Limit name="channel-count" max="2" />
+ <Limit name="sample-rate" ranges="8000,12000,16000,24000,48000" />
+ <Limit name="bitrate" range="500-512000" />
+ <Limit name="complexity" range="0-10" default="5" />
+ <Feature name="bitrate-modes" value="CQ" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.h263.encoder" type="video/3gpp">
+ <Alias name="OMX.google.h263.encoder" />
+ <!-- profiles and levels: ProfileBaseline : Level45 -->
+ <Limit name="size" min="176x144" max="176x144" />
+ <Limit name="alignment" value="16x16" />
+ <Limit name="bitrate" range="1-128000" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.mpeg4.encoder" type="video/mp4v-es">
+ <Alias name="OMX.google.mpeg4.encoder" />
+ <!-- profiles and levels: ProfileCore : Level2 -->
+ <Limit name="size" min="16x16" max="176x144" />
+ <Limit name="alignment" value="16x16" />
+ <Limit name="block-size" value="16x16" />
+ <Limit name="blocks-per-second" range="12-1485" />
+ <Limit name="bitrate" range="1-64000" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.avc.encoder" type="video/avc" variant="slow-cpu,!slow-cpu">
+ <Alias name="OMX.google.h264.encoder" />
+ <Limit name="alignment" value="2x2" />
+ <Limit name="block-size" value="16x16" />
+ <Variant name="!slow-cpu">
+ <Limit name="size" min="16x16" max="2048x2048" />
+ <!-- profiles and levels: ProfileBaseline : Level41 -->
+ <Limit name="block-count" range="1-8192" /> <!-- max 2048x1024 -->
+ <Limit name="blocks-per-second" range="1-245760" />
+ <Limit name="bitrate" range="1-12000000" />
+ </Variant>
+ <Variant name="slow-cpu">
+ <Limit name="size" min="16x16" max="1808x1808" />
+ <!-- profiles and levels: ProfileBaseline : Level3 -->
+ <Limit name="block-count" range="1-1620" />
+ <Limit name="blocks-per-second" range="1-40500" />
+ <Limit name="bitrate" range="1-2000000" />
+ </Variant>
+ <Feature name="intra-refresh" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.vp8.encoder" type="video/x-vnd.on2.vp8" variant="slow-cpu,!slow-cpu">
+ <Alias name="OMX.google.vp8.encoder" />
+ <Limit name="alignment" value="2x2" />
+ <Limit name="block-size" value="16x16" />
+ <Variant name="!slow-cpu">
+ <Limit name="size" min="2x2" max="2048x2048" />
+ <!-- profiles and levels: ProfileMain : Level_Version0-3 -->
+ <!-- 2016 devices can encode at about 10fps at this block count -->
+ <Limit name="block-count" range="1-16384" />
+ <Limit name="bitrate" range="1-40000000" />
+ </Variant>
+ <Variant name="slow-cpu">
+ <Limit name="size" min="2x2" max="1280x1280" />
+ <!-- profiles and levels: ProfileMain : Level_Version0-3 -->
+ <Limit name="block-count" range="1-3600" /> <!-- max 1280x720 -->
+ <Limit name="bitrate" range="1-20000000" />
+ </Variant>
+ <Feature name="bitrate-modes" value="VBR,CBR" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.hevc.encoder" type="video/hevc" variant="!slow-cpu">
+ <!-- profiles and levels: ProfileMain : MainTierLevel51 -->
+ <Limit name="size" min="320x128" max="512x512" />
+ <Limit name="alignment" value="2x2" />
+ <Limit name="block-size" value="8x8" />
+ <Limit name="block-count" range="1-4096" /> <!-- max 512x512 -->
+ <Limit name="blocks-per-second" range="1-122880" />
+ <Limit name="bitrate" range="1-10000000" />
+ <Limit name="complexity" range="0-10" default="0" />
+ <Limit name="quality" range="0-100" default="80" />
+ <Feature name="bitrate-modes" value="VBR,CBR,CQ" />
+ </MediaCodec>
+ <MediaCodec name="c2.android.vp9.encoder" type="video/x-vnd.on2.vp9" variant="!slow-cpu">
+ <Alias name="OMX.google.vp9.encoder" />
+ <!-- profiles and levels: ProfileMain : Level_Version0-3 -->
+ <Limit name="size" min="2x2" max="2048x2048" />
+ <Limit name="alignment" value="2x2" />
+ <Limit name="block-size" value="16x16" />
+ <!-- 2016 devices can encode at about 8fps at this block count -->
+ <Limit name="block-count" range="1-3600" /> <!-- max 1280x720 -->
+ <Limit name="bitrate" range="1-40000000" />
+ <Feature name="bitrate-modes" value="VBR,CBR" />
+ </MediaCodec>
+ </Encoders>
+</MediaCodecs>
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/ADebug.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ADebug.h
index 180694b..37388a0 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/ADebug.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/ADebug.h
@@ -53,9 +53,11 @@
#define LITERAL_TO_STRING_INTERNAL(x) #x
#define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x)
-#ifdef CHECK
-#undef CHECK
-#endif
+// allow to use CHECK_OP from android-base/logging.h
+// TODO: longterm replace this with android-base/logging.h, but there are some nuances, e.g.
+// android-base CHECK_OP requires a copy constructor, whereas we don't.
+#ifndef CHECK_OP
+
#define CHECK(condition) \
LOG_ALWAYS_FATAL_IF( \
!(condition), \
@@ -63,10 +65,6 @@
__FILE__ ":" LITERAL_TO_STRING(__LINE__) \
" CHECK(" #condition ") failed.")
-#ifdef CHECK_OP
-#undef CHECK_OP
-#endif
-
#define CHECK_OP(x,y,suffix,op) \
do { \
const auto &a = x; \
@@ -82,15 +80,6 @@
} \
} while (false)
-#ifdef CHECK_EQ
-#undef CHECK_EQ
-#undef CHECK_NE
-#undef CHECK_LE
-#undef CHECK_LT
-#undef CHECK_GE
-#undef CHECK_GT
-#endif
-
#define CHECK_EQ(x,y) CHECK_OP(x,y,EQ,==)
#define CHECK_NE(x,y) CHECK_OP(x,y,NE,!=)
#define CHECK_LE(x,y) CHECK_OP(x,y,LE,<=)
@@ -98,6 +87,8 @@
#define CHECK_GE(x,y) CHECK_OP(x,y,GE,>=)
#define CHECK_GT(x,y) CHECK_OP(x,y,GT,>)
+#endif
+
#define TRESPASS(...) \
LOG_ALWAYS_FATAL( \
__FILE__ ":" LITERAL_TO_STRING(__LINE__) \
diff --git a/media/libstagefright/omx/1.0/Omx.cpp b/media/libstagefright/omx/1.0/Omx.cpp
index bb79f54..eef9ce3 100644
--- a/media/libstagefright/omx/1.0/Omx.cpp
+++ b/media/libstagefright/omx/1.0/Omx.cpp
@@ -43,6 +43,8 @@
Omx::Omx() :
mMaster(new OMXMaster()),
mParser() {
+ (void)mParser.parseXmlFilesInSearchDirs();
+ (void)mParser.parseXmlPath(mParser.defaultProfilingResultsXmlPath);
}
Omx::~Omx() {
diff --git a/media/libstagefright/omx/1.0/OmxStore.cpp b/media/libstagefright/omx/1.0/OmxStore.cpp
index 2e041e3..67f478e 100644
--- a/media/libstagefright/omx/1.0/OmxStore.cpp
+++ b/media/libstagefright/omx/1.0/OmxStore.cpp
@@ -17,6 +17,8 @@
#include <ios>
#include <list>
+#define LOG_TAG "OmxStore"
+
#include <android-base/logging.h>
#include <media/stagefright/omx/1.0/Conversion.h>
@@ -30,16 +32,33 @@
namespace V1_0 {
namespace implementation {
+using ::android::hardware::media::omx::V1_0::Status;
+using ::android::hardware::media::omx::V1_0::IOmx;
+
OmxStore::OmxStore(
+ const sp<IOmx> &omx,
const char* owner,
- const char* const* searchDirs,
- const char* mainXmlName,
- const char* performanceXmlName,
+ const std::vector<std::string> &searchDirs,
+ const std::vector<std::string> &xmlNames,
const char* profilingResultsXmlPath) {
- MediaCodecsXmlParser parser(searchDirs,
- mainXmlName,
- performanceXmlName,
- profilingResultsXmlPath);
+ // retrieve list of omx nodes
+ std::set<std::string> nodes;
+ if (omx != nullptr) {
+ omx->listNodes([&nodes](const Status &status,
+ const hidl_vec<IOmx::ComponentInfo> &nodeList) {
+ if (status == Status::OK) {
+ for (const IOmx::ComponentInfo& info : nodeList) {
+ nodes.emplace(info.mName.c_str());
+ }
+ }
+ });
+ }
+
+ MediaCodecsXmlParser parser;
+ parser.parseXmlFilesInSearchDirs(xmlNames, searchDirs);
+ if (profilingResultsXmlPath != nullptr) {
+ parser.parseXmlPath(profilingResultsXmlPath);
+ }
mParsingStatus = toStatus(parser.getParsingStatus());
const auto& serviceAttributeMap = parser.getServiceAttributeMap();
@@ -66,6 +85,13 @@
nodeList.resize(rolePair.second.nodeList.size());
size_t j = 0;
for (const auto& nodePair : rolePair.second.nodeList) {
+ if (!nodes.count(nodePair.second.name)) {
+ // not supported by this OMX instance
+ if (!strncasecmp(nodePair.second.name.c_str(), "omx.", 4)) {
+ LOG(INFO) << "node [" << nodePair.second.name.c_str() << "] not found in IOmx";
+ }
+ continue;
+ }
NodeInfo node;
node.name = nodePair.second.name;
node.owner = owner;
@@ -82,6 +108,7 @@
nodeList[j] = std::move(node);
++j;
}
+ nodeList.resize(j);
mRoleList[i] = std::move(role);
++i;
}
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index 0c50752..e260cae 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -41,7 +41,6 @@
"libcutils",
"libstagefright_foundation",
"libstagefright_bufferqueue_helper",
- "libstagefright_softomx",
"libstagefright_xmlparser",
"libdl",
"libhidlbase",
@@ -79,14 +78,10 @@
cc_library_shared {
name: "libstagefright_softomx",
vendor_available: true,
- vndk: {
- enabled: true,
- },
srcs: [
"SimpleSoftOMXComponent.cpp",
"SoftOMXComponent.cpp",
- "SoftOMXPlugin.cpp",
"SoftVideoDecoderOMXComponent.cpp",
"SoftVideoEncoderOMXComponent.cpp",
],
@@ -126,6 +121,49 @@
},
}
+cc_library_shared {
+ name: "libstagefright_softomx_plugin",
+ vendor_available: true,
+
+ srcs: [
+ "SoftOMXPlugin.cpp",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ header_libs: [
+ "media_plugin_headers",
+ ],
+
+ export_header_lib_headers: [
+ "media_plugin_headers",
+ ],
+
+ shared_libs: [
+ "libstagefright_softomx",
+ "libstagefright_foundation",
+ "liblog",
+ "libutils",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-Wno-unused-parameter",
+ "-Wno-documentation",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "signed-integer-overflow",
+ "unsigned-integer-overflow",
+ ],
+ cfi: true,
+ },
+}
+
cc_defaults {
name: "libstagefright_softomx-defaults",
vendor_available: true,
diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
index 0967b5f..8c5ca6e 100644
--- a/media/libstagefright/omx/OMXMaster.cpp
+++ b/media/libstagefright/omx/OMXMaster.cpp
@@ -29,8 +29,7 @@
namespace android {
-OMXMaster::OMXMaster()
- : mVendorLibHandle(NULL) {
+OMXMaster::OMXMaster() {
pid_t pid = getpid();
char filename[20];
@@ -52,47 +51,52 @@
}
addVendorPlugin();
- addPlugin(new SoftOMXPlugin);
+ addPlatformPlugin();
}
OMXMaster::~OMXMaster() {
clearPlugins();
-
- if (mVendorLibHandle != NULL) {
- dlclose(mVendorLibHandle);
- mVendorLibHandle = NULL;
- }
}
void OMXMaster::addVendorPlugin() {
addPlugin("libstagefrighthw.so");
}
-void OMXMaster::addPlugin(const char *libname) {
- mVendorLibHandle = android_load_sphal_library(libname, RTLD_NOW);
+void OMXMaster::addPlatformPlugin() {
+ addPlugin("libstagefright_softomx_plugin.so");
+}
- if (mVendorLibHandle == NULL) {
+void OMXMaster::addPlugin(const char *libname) {
+ void *libHandle = android_load_sphal_library(libname, RTLD_NOW);
+
+ if (libHandle == NULL) {
return;
}
typedef OMXPluginBase *(*CreateOMXPluginFunc)();
CreateOMXPluginFunc createOMXPlugin =
(CreateOMXPluginFunc)dlsym(
- mVendorLibHandle, "createOMXPlugin");
+ libHandle, "createOMXPlugin");
if (!createOMXPlugin)
createOMXPlugin = (CreateOMXPluginFunc)dlsym(
- mVendorLibHandle, "_ZN7android15createOMXPluginEv");
+ libHandle, "_ZN7android15createOMXPluginEv");
+ OMXPluginBase *plugin = nullptr;
if (createOMXPlugin) {
- addPlugin((*createOMXPlugin)());
+ plugin = (*createOMXPlugin)();
+ }
+
+ if (plugin) {
+ mPlugins.push_back({ plugin, libHandle });
+ addPlugin(plugin);
+ } else {
+ android_unload_sphal_library(libHandle);
}
}
void OMXMaster::addPlugin(OMXPluginBase *plugin) {
Mutex::Autolock autoLock(mLock);
- mPlugins.push_back(plugin);
-
OMX_U32 index = 0;
char name[128];
@@ -120,20 +124,20 @@
void OMXMaster::clearPlugins() {
Mutex::Autolock autoLock(mLock);
- typedef void (*DestroyOMXPluginFunc)(OMXPluginBase*);
- DestroyOMXPluginFunc destroyOMXPlugin =
- (DestroyOMXPluginFunc)dlsym(
- mVendorLibHandle, "destroyOMXPlugin");
-
mPluginByComponentName.clear();
+ mPluginByInstance.clear();
- for (List<OMXPluginBase *>::iterator it = mPlugins.begin();
- it != mPlugins.end(); ++it) {
+ typedef void (*DestroyOMXPluginFunc)(OMXPluginBase*);
+ for (const Plugin &plugin : mPlugins) {
+ DestroyOMXPluginFunc destroyOMXPlugin =
+ (DestroyOMXPluginFunc)dlsym(
+ plugin.mLibHandle, "destroyOMXPlugin");
if (destroyOMXPlugin)
- destroyOMXPlugin(*it);
+ destroyOMXPlugin(plugin.mOmx);
else
- delete *it;
- *it = NULL;
+ delete plugin.mOmx;
+
+ android_unload_sphal_library(plugin.mLibHandle);
}
mPlugins.clear();
diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp
index 1f3e8c1..a720bc9 100644
--- a/media/libstagefright/omx/SoftOMXPlugin.cpp
+++ b/media/libstagefright/omx/SoftOMXPlugin.cpp
@@ -71,6 +71,16 @@
static const size_t kNumComponents =
sizeof(kComponents) / sizeof(kComponents[0]);
+extern "C" OMXPluginBase* createOMXPlugin() {
+ ALOGI("createOMXPlugin");
+ return new SoftOMXPlugin();
+}
+
+extern "C" void destroyOMXPlugin(OMXPluginBase* plugin) {
+ ALOGI("destroyOMXPlugin");
+ delete plugin;
+}
+
SoftOMXPlugin::SoftOMXPlugin() {
}
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/1.0/OmxStore.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/OmxStore.h
index 006d2d9..15d46991 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/1.0/OmxStore.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/OmxStore.h
@@ -20,6 +20,7 @@
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
+#include <android/hardware/media/omx/1.0/IOmx.h>
#include <android/hardware/media/omx/1.0/IOmxStore.h>
#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
@@ -43,15 +44,14 @@
struct OmxStore : public IOmxStore {
OmxStore(
+ const sp<IOmx> &omx = nullptr,
const char* owner = "default",
- const char* const* searchDirs
- = MediaCodecsXmlParser::defaultSearchDirs,
- const char* mainXmlName
- = MediaCodecsXmlParser::defaultMainXmlName,
- const char* performanceXmlName
- = MediaCodecsXmlParser::defaultPerformanceXmlName,
- const char* profilingResultsXmlPath
- = MediaCodecsXmlParser::defaultProfilingResultsXmlPath);
+ const std::vector<std::string> &searchDirs =
+ MediaCodecsXmlParser::getDefaultSearchDirs(),
+ const std::vector<std::string> &xmlFiles =
+ MediaCodecsXmlParser::getDefaultXmlNames(),
+ const char *xmlProfilingResultsPath =
+ MediaCodecsXmlParser::defaultProfilingResultsXmlPath);
virtual ~OmxStore();
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMXMaster.h b/media/libstagefright/omx/include/media/stagefright/omx/OMXMaster.h
index 897f287..93eaef1 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/OMXMaster.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/OMXMaster.h
@@ -52,13 +52,16 @@
private:
char mProcessName[16];
Mutex mLock;
- List<OMXPluginBase *> mPlugins;
+ struct Plugin {
+ OMXPluginBase *mOmx;
+ void *mLibHandle;
+ };
+ List<Plugin> mPlugins;
KeyedVector<String8, OMXPluginBase *> mPluginByComponentName;
KeyedVector<OMX_COMPONENTTYPE *, OMXPluginBase *> mPluginByInstance;
- void *mVendorLibHandle;
-
void addVendorPlugin();
+ void addPlatformPlugin();
void addPlugin(const char *libname);
void addPlugin(OMXPluginBase *plugin);
void clearPlugins();
diff --git a/media/libstagefright/xmlparser/Android.bp b/media/libstagefright/xmlparser/Android.bp
index 202e964..38de831 100644
--- a/media/libstagefright/xmlparser/Android.bp
+++ b/media/libstagefright/xmlparser/Android.bp
@@ -20,15 +20,12 @@
],
shared_libs: [
+ "libbase",
"libexpat",
"liblog",
"libstagefright_omx_utils",
],
- header_libs: [
- "libbase_headers",
- ],
-
cflags: [
"-Werror",
"-Wall",
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index 7046f61..6a1b9a8 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -19,12 +19,18 @@
#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
+#include <android-base/logging.h>
#include <android-base/macros.h>
#include <utils/Log.h>
+
#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/omx/OMXUtils.h>
-#include <sys/stat.h>
+
#include <expat.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
#include <algorithm>
#include <cctype>
@@ -32,8 +38,15 @@
namespace android {
+using MCXP = MediaCodecsXmlParser;
+
namespace {
+bool fileExists(const std::string &path) {
+ struct stat fileStat;
+ return stat(path.c_str(), &fileStat) == 0 && S_ISREG(fileStat.st_mode);
+}
+
/**
* Search for a file in a list of search directories.
*
@@ -44,7 +57,7 @@
* search continues until the `nullptr` element in `searchDirs` is reached, at
* which point the function returns `false`.
*
- * \param[in] searchDirs Null-terminated array of search paths.
+ * \param[in] searchDirs array of search paths.
* \param[in] fileName Name of the file to search.
* \param[out] outPath Full path of the file. `outPath` will hold a valid file
* name if the return value of this function is `true`.
@@ -52,14 +65,13 @@
* valid file name; `false` otherwise.
*/
bool findFileInDirs(
- const char* const* searchDirs,
- const char *fileName,
+ const std::vector<std::string> &searchDirs,
+ const std::string &fileName,
std::string *outPath) {
- for (; *searchDirs != nullptr; ++searchDirs) {
- *outPath = std::string(*searchDirs) + "/" + fileName;
- struct stat fileStat;
- if (stat(outPath->c_str(), &fileStat) == 0 &&
- S_ISREG(fileStat.st_mode)) {
+ for (const std::string &searchDir : searchDirs) {
+ std::string path = searchDir + "/" + fileName;
+ if (fileExists(path)) {
+ *outPath = path;
return true;
}
}
@@ -85,123 +97,435 @@
bool parseBoolean(const char* s) {
return striEq(s, "y") ||
striEq(s, "yes") ||
+ striEq(s, "enabled") ||
striEq(s, "t") ||
striEq(s, "true") ||
striEq(s, "1");
}
-status_t limitFoundMissingAttr(const char* name, const char *attr, bool found = true) {
- ALOGE("limit '%s' with %s'%s' attribute", name,
- (found ? "" : "no "), attr);
- return BAD_VALUE;
+
+status_t combineStatus(status_t a, status_t b) {
+ if (a == NO_INIT) {
+ return b;
+ } else if ((a == OK && (b == NAME_NOT_FOUND || b == ALREADY_EXISTS || b == NO_INIT))
+ || (b == OK && (a == NAME_NOT_FOUND || a == ALREADY_EXISTS))) {
+ // ignore NAME_NOT_FOUND and ALREADY_EXIST errors as long as the other error is OK
+ // also handle OK + NO_INIT here
+ return OK;
+ } else {
+ // prefer the first error result
+ return a ? : b;
+ }
}
-status_t limitError(const char* name, const char *msg) {
- ALOGE("limit '%s' %s", name, msg);
- return BAD_VALUE;
+MCXP::StringSet parseCommaSeparatedStringSet(const char *s) {
+ MCXP::StringSet result;
+ for (const char *ptr = s ? : ""; *ptr; ) {
+ const char *end = strchrnul(ptr, ',');
+ if (ptr != end) { // skip empty values
+ result.emplace(ptr, end - ptr);
+ }
+ ptr = end + ('\0' != *end);
+ }
+ return result;
}
-status_t limitInvalidAttr(const char* name, const char* attr, const char* value) {
- ALOGE("limit '%s' with invalid '%s' attribute (%s)", name,
- attr, value);
- return BAD_VALUE;
-}
+#define PLOGD(msg, ...) \
+ ALOGD(msg " at line %zu of %s", ##__VA_ARGS__, \
+ (size_t)::XML_GetCurrentLineNumber(mParser.get()), mPath.c_str());
-}; // unnamed namespace
+} // unnamed namespace
-constexpr char const* MediaCodecsXmlParser::defaultSearchDirs[];
-constexpr char const* MediaCodecsXmlParser::defaultMainXmlName;
-constexpr char const* MediaCodecsXmlParser::defaultPerformanceXmlName;
+struct MediaCodecsXmlParser::Impl {
+ // status + error message
+ struct Result {
+ private:
+ status_t mStatus;
+ std::string mError;
+
+ public:
+ Result(status_t s, std::string error = "")
+ : mStatus(s),
+ mError(error) {
+ if (error.empty() && s) {
+ error = "Failed (" + std::string(asString(s)) + ")";
+ }
+ }
+ operator status_t() const { return mStatus; }
+ std::string error() const { return mError; }
+ };
+
+
+ // Parsed data
+ struct Data {
+ // Service attributes
+ AttributeMap mServiceAttributeMap;
+ CodecMap mCodecMap;
+ Result addGlobal(std::string key, std::string value, bool updating);
+ };
+
+ enum Section {
+ SECTION_TOPLEVEL,
+ SECTION_SETTINGS,
+ SECTION_DECODERS,
+ SECTION_DECODER,
+ SECTION_DECODER_TYPE,
+ SECTION_ENCODERS,
+ SECTION_ENCODER,
+ SECTION_ENCODER_TYPE,
+ SECTION_INCLUDE,
+ SECTION_VARIANT,
+ SECTION_UNKNOWN,
+ };
+
+ // XML parsing state
+ struct State {
+ private:
+ Data *mData;
+
+ // current codec and/or type, plus whether we are updating
+ struct CodecAndType {
+ std::string mName;
+ CodecMap::iterator mCodec;
+ TypeMap::iterator mType;
+ bool mUpdating;
+ };
+
+ // using vectors as we need to reset their sizes
+ std::vector<std::string> mIncludeStack;
+ std::vector<Section> mSectionStack;
+ std::vector<StringSet> mVariantsStack;
+ std::vector<CodecAndType> mCurrent;
+
+ public:
+ State(Data *data);
+
+ Data &data() { return *mData; }
+
+ // used to restore parsing state at XML include boundaries, in case parsing the included
+ // file fails.
+ struct RestorePoint {
+ size_t numIncludes;
+ size_t numSections;
+ size_t numVariantSets;
+ size_t numCodecAndTypes;
+ };
+
+ // method manipulating restore points (all state stacks)
+ RestorePoint createRestorePoint() const {
+ return {
+ mIncludeStack.size(), mSectionStack.size(), mVariantsStack.size(), mCurrent.size()
+ };
+ }
+
+ void restore(RestorePoint rp) {
+ CHECK_GE(mIncludeStack.size(), rp.numIncludes);
+ CHECK_GE(mSectionStack.size(), rp.numSections);
+ CHECK_GE(mVariantsStack.size(), rp.numVariantSets);
+ CHECK_GE(mCurrent.size(), rp.numCodecAndTypes);
+
+ mIncludeStack.resize(rp.numIncludes);
+ mSectionStack.resize(rp.numSections);
+ mVariantsStack.resize(rp.numVariantSets);
+ mCurrent.resize(rp.numCodecAndTypes);
+ }
+
+ // methods manipulating the include stack
+ Result enterInclude(const std::string &path);
+ void exitInclude() {
+ mIncludeStack.pop_back();
+ }
+
+ // methods manipulating the codec/type stack/state
+ bool inCodec() const {
+ return !mCurrent.empty() && mCurrent.back().mCodec != mData->mCodecMap.end();
+ }
+
+ bool inType() const {
+ return inCodec()
+ && mCurrent.back().mType != mCurrent.back().mCodec->second.typeMap.end();
+ }
+
+ Result enterMediaCodec(bool encoder, const char *name, const char *type, bool update);
+ Result enterType(const char *name, bool update);
+ void exitCodecOrType() {
+ mCurrent.pop_back();
+ }
+
+ // can only be called when inCodec()
+ MediaCodecsXmlParser::CodecProperties &codec() {
+ return mCurrent.back().mCodec->second;
+ }
+ // can only be called when inCodec()
+ std::string codecName() const {
+ return mCurrent.back().mName;
+ }
+ // can only be called when inCodec()
+ bool updating() const {
+ return mCurrent.back().mUpdating;
+ }
+ // can only be called when inType()
+ MediaCodecsXmlParser::AttributeMap &type() {
+ return mCurrent.back().mType->second;
+ }
+
+ // methods manipulating the section stack
+ Section section() const {
+ return mSectionStack.back();
+ }
+ Section lastNonIncludeSection() const;
+ void enterSection(Section s) {
+ mSectionStack.push_back(s);
+ }
+ void exitSection() {
+ mSectionStack.pop_back();
+ CHECK(!mSectionStack.empty());
+ }
+
+ // methods manipulating the variants stack
+ StringSet variants() const {
+ return mVariantsStack.back();
+ }
+ void enterVariants(StringSet variants) {
+ mVariantsStack.push_back(variants);
+ }
+ void exitVariants() {
+ mVariantsStack.pop_back();
+ }
+
+ // utility methods
+
+ // updates rank, domains, variants and enabledness on the current codec/type
+ Result updateCodec(
+ const char *rank, StringSet domains, StringSet variants, const char *enabled);
+ // adds a key-value attribute detail to the current type of the current codec
+ void addDetail(const std::string &key, const std::string &value);
+ };
+
+ /** XML Parser (state) */
+ struct Parser {
+ State *mState;
+
+ Parser(State *state, std::string path);
+
+ // keep track of the parser state
+ std::shared_ptr<XML_ParserStruct> mParser;
+ std::string mPath;
+ std::string mHrefBase;
+ status_t mStatus;
+
+ void parseXmlFile();
+
+ // XML parser callbacks
+ static void StartElementHandlerWrapper(void *me, const char *name, const char **attrs);
+ static void EndElementHandlerWrapper(void *me, const char *name);
+
+ void startElementHandler(const char *name, const char **attrs);
+ void endElementHandler(const char *name);
+
+ void updateStatus(status_t status);
+ void logAnyErrors(const Result &status) const;
+ status_t getStatus() const { return mStatus; }
+
+ status_t addAlias(const char **attrs);
+ status_t addFeature(const char **attrs);
+ status_t addLimit(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);
+ status_t enterType(const char **attrs);
+ status_t includeXmlFile(const char **attrs);
+ status_t limitVariants(const char **attrs);
+
+ status_t updateMediaCodec(
+ const char *rank, const StringSet &domain, const StringSet &variants,
+ const char *enabled);
+ };
+
+ status_t parseXmlFilesInSearchDirs(
+ const std::vector<std::string> &fileNames,
+ const std::vector<std::string> &searchDirs);
+
+ status_t parseXmlPath(const std::string &path);
+
+ // Computed longest common prefix
+ Data mData;
+ State mState;
+
+ // Role map
+ mutable std::string mCommonPrefix;
+ mutable RoleMap mRoleMap;
+ mutable std::mutex mLock;
+
+ status_t mParsingStatus;
+
+ Impl()
+ : mState(&mData),
+ mParsingStatus(NO_INIT) {
+ }
+
+ void generateRoleMap() const;
+ void generateCommonPrefix() const;
+
+ const AttributeMap& getServiceAttributeMap() const {
+ std::lock_guard<std::mutex> guard(mLock);
+ return mData.mServiceAttributeMap;
+ }
+
+ const CodecMap& getCodecMap() const {
+ std::lock_guard<std::mutex> guard(mLock);
+ return mData.mCodecMap;
+ }
+
+ const RoleMap& getRoleMap() const;
+ const char* getCommonPrefix() const;
+
+ status_t getParsingStatus() const {
+ std::lock_guard<std::mutex> guard(mLock);
+ return mParsingStatus;
+ }
+};
+
constexpr char const* MediaCodecsXmlParser::defaultProfilingResultsXmlPath;
-MediaCodecsXmlParser::MediaCodecsXmlParser(
- const char* const* searchDirs,
- const char* mainXmlName,
- const char* performanceXmlName,
- const char* profilingResultsXmlPath) :
- mParsingStatus(NO_INIT),
- mUpdate(false),
- mCodecCounter(0) {
- std::string path;
- if (findFileInDirs(searchDirs, mainXmlName, &path)) {
- parseTopLevelXMLFile(path.c_str(), false);
- } else {
- ALOGE("Cannot find %s", mainXmlName);
- mParsingStatus = NAME_NOT_FOUND;
- }
- if (findFileInDirs(searchDirs, performanceXmlName, &path)) {
- parseTopLevelXMLFile(path.c_str(), true);
- }
- if (profilingResultsXmlPath != nullptr) {
- parseTopLevelXMLFile(profilingResultsXmlPath, true);
- }
+MediaCodecsXmlParser::MediaCodecsXmlParser()
+ : mImpl(new Impl()) {
}
-bool MediaCodecsXmlParser::parseTopLevelXMLFile(
- const char *codecs_xml,
- bool ignore_errors) {
- // get href_base
- const char *href_base_end = strrchr(codecs_xml, '/');
- if (href_base_end != nullptr) {
- mHrefBase = std::string(codecs_xml, href_base_end - codecs_xml + 1);
- }
+status_t MediaCodecsXmlParser::parseXmlFilesInSearchDirs(
+ const std::vector<std::string> &fileNames,
+ const std::vector<std::string> &searchDirs) {
+ return mImpl->parseXmlFilesInSearchDirs(fileNames, searchDirs);
+}
- mParsingStatus = OK; // keeping this here for safety
- mCurrentSection = SECTION_TOPLEVEL;
+status_t MediaCodecsXmlParser::parseXmlPath(const std::string &path) {
+ return mImpl->parseXmlPath(path);
+}
- parseXMLFile(codecs_xml);
-
- if (mParsingStatus != OK) {
- ALOGW("parseTopLevelXMLFile(%s) failed", codecs_xml);
- if (ignore_errors) {
- mParsingStatus = OK;
- return false;
+status_t MediaCodecsXmlParser::Impl::parseXmlFilesInSearchDirs(
+ const std::vector<std::string> &fileNames,
+ const std::vector<std::string> &searchDirs) {
+ status_t res = NO_INIT;
+ for (const std::string fileName : fileNames) {
+ status_t err = NO_INIT;
+ std::string path;
+ if (findFileInDirs(searchDirs, fileName, &path)) {
+ err = parseXmlPath(path);
+ } else {
+ ALOGD("Cannot find %s", path.c_str());
}
- mCodecMap.clear();
- return false;
+ res = combineStatus(res, err);
}
- return true;
+ return res;
+}
+
+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());
+ mParsingStatus = combineStatus(mParsingStatus, NAME_NOT_FOUND);
+ return NAME_NOT_FOUND;
+ }
+
+ // save state (even though we should always be at toplevel here)
+ State::RestorePoint rp = mState.createRestorePoint();
+ Parser parser(&mState, path);
+ parser.parseXmlFile();
+ mState.restore(rp);
+
+ if (parser.getStatus() != OK) {
+ ALOGD("parseXmlPath(%s) failed with %s", path.c_str(), asString(parser.getStatus()));
+ }
+ mParsingStatus = combineStatus(mParsingStatus, parser.getStatus());
+ return parser.getStatus();
}
MediaCodecsXmlParser::~MediaCodecsXmlParser() {
}
-void MediaCodecsXmlParser::parseXMLFile(const char *path) {
+MediaCodecsXmlParser::Impl::State::State(MediaCodecsXmlParser::Impl::Data *data)
+ : mData(data) {
+ mSectionStack.emplace_back(SECTION_TOPLEVEL);
+}
+
+MediaCodecsXmlParser::Impl::Section
+MediaCodecsXmlParser::Impl::State::lastNonIncludeSection() const {
+ for (auto it = mSectionStack.end(); it != mSectionStack.begin(); --it) {
+ if (it[-1] != SECTION_INCLUDE) {
+ return it[-1];
+ }
+ }
+ TRESPASS("must have non-include section");
+}
+
+void MediaCodecsXmlParser::Impl::Parser::updateStatus(status_t status) {
+ mStatus = combineStatus(mStatus, status);
+}
+
+void MediaCodecsXmlParser::Impl::Parser::logAnyErrors(const Result &status) const {
+ if (status) {
+ if (status.error().empty()) {
+ PLOGD("error %s", asString((status_t)status));
+ } else {
+ PLOGD("%s", status.error().c_str());
+ }
+ }
+}
+
+MediaCodecsXmlParser::Impl::Parser::Parser(State *state, std::string path)
+ : mState(state),
+ mPath(path),
+ mStatus(NO_INIT) {
+ // determine href_base
+ std::string::size_type end = path.rfind("/");
+ if (end != std::string::npos) {
+ mHrefBase = path.substr(0, end + 1);
+ }
+}
+
+void MediaCodecsXmlParser::Impl::Parser::parseXmlFile() {
+ const char *path = mPath.c_str();
+ ALOGD("parsing %s...", path);
FILE *file = fopen(path, "r");
if (file == nullptr) {
- ALOGW("unable to open media codecs configuration xml file: %s", path);
- mParsingStatus = NAME_NOT_FOUND;
+ ALOGD("unable to open media codecs configuration xml file: %s", path);
+ mStatus = NAME_NOT_FOUND;
return;
}
- XML_Parser parser = ::XML_ParserCreate(nullptr);
- LOG_FATAL_IF(parser == nullptr, "XML_MediaCodecsXmlParserCreate() failed.");
+ mParser = std::shared_ptr<XML_ParserStruct>(
+ ::XML_ParserCreate(nullptr),
+ [](XML_ParserStruct *parser) { ::XML_ParserFree(parser); });
+ LOG_FATAL_IF(!mParser, "XML_MediaCodecsXmlParserCreate() failed.");
- ::XML_SetUserData(parser, this);
- ::XML_SetElementHandler(
- parser, StartElementHandlerWrapper, EndElementHandlerWrapper);
+ ::XML_SetUserData(mParser.get(), this);
+ ::XML_SetElementHandler(mParser.get(), StartElementHandlerWrapper, EndElementHandlerWrapper);
static constexpr int BUFF_SIZE = 512;
- while (mParsingStatus == OK) {
- void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
+ // updateStatus(OK);
+ if (mStatus == NO_INIT) {
+ mStatus = OK;
+ }
+ while (mStatus == OK) {
+ void *buff = ::XML_GetBuffer(mParser.get(), BUFF_SIZE);
if (buff == nullptr) {
- ALOGE("failed in call to XML_GetBuffer()");
- mParsingStatus = UNKNOWN_ERROR;
+ ALOGD("failed in call to XML_GetBuffer()");
+ mStatus = UNKNOWN_ERROR;
break;
}
int bytes_read = ::fread(buff, 1, BUFF_SIZE, file);
if (bytes_read < 0) {
- ALOGE("failed in call to read");
- mParsingStatus = ERROR_IO;
+ ALOGD("failed in call to read");
+ mStatus = ERROR_IO;
break;
}
- XML_Status status = ::XML_ParseBuffer(parser, bytes_read, bytes_read == 0);
+ XML_Status status = ::XML_ParseBuffer(mParser.get(), bytes_read, bytes_read == 0);
if (status != XML_STATUS_OK) {
- ALOGE("malformed (%s)", ::XML_ErrorString(::XML_GetErrorCode(parser)));
- mParsingStatus = ERROR_MALFORMED;
+ PLOGD("malformed (%s)", ::XML_ErrorString(::XML_GetErrorCode(mParser.get())));
+ mStatus = ERROR_MALFORMED;
break;
}
@@ -210,39 +534,47 @@
}
}
- ::XML_ParserFree(parser);
+ mParser.reset();
fclose(file);
file = nullptr;
}
// static
-void MediaCodecsXmlParser::StartElementHandlerWrapper(
+void MediaCodecsXmlParser::Impl::Parser::StartElementHandlerWrapper(
void *me, const char *name, const char **attrs) {
- static_cast<MediaCodecsXmlParser*>(me)->startElementHandler(name, attrs);
+ static_cast<MediaCodecsXmlParser::Impl::Parser*>(me)->startElementHandler(name, attrs);
}
// static
-void MediaCodecsXmlParser::EndElementHandlerWrapper(void *me, const char *name) {
- static_cast<MediaCodecsXmlParser*>(me)->endElementHandler(name);
+void MediaCodecsXmlParser::Impl::Parser::EndElementHandlerWrapper(void *me, const char *name) {
+ static_cast<MediaCodecsXmlParser::Impl::Parser*>(me)->endElementHandler(name);
}
-status_t MediaCodecsXmlParser::includeXMLFile(const char **attrs) {
+status_t MediaCodecsXmlParser::Impl::Parser::includeXmlFile(const char **attrs) {
const char *href = nullptr;
size_t i = 0;
while (attrs[i] != nullptr) {
- if (strEq(attrs[i], "href")) {
- if (attrs[++i] == nullptr) {
- return BAD_VALUE;
- }
- href = attrs[i];
- } else {
- ALOGE("includeXMLFile: unrecognized attribute: %s", attrs[i]);
+ CHECK((i & 1) == 0);
+ if (attrs[i + 1] == nullptr) {
+ PLOGD("Include: attribute '%s' is null", attrs[i]);
return BAD_VALUE;
}
+
+ if (strEq(attrs[i], "href")) {
+ href = attrs[++i];
+ } else {
+ PLOGD("Include: ignoring unrecognized attribute '%s'", attrs[i]);
+ ++i;
+ }
++i;
}
+ if (href == nullptr) {
+ PLOGD("Include with no 'href' attribute");
+ return BAD_VALUE;
+ }
+
// For security reasons and for simplicity, file names can only contain
// [a-zA-Z0-9_.] and must start with media_codecs_ and end with .xml
for (i = 0; href[i] != '\0'; i++) {
@@ -252,74 +584,114 @@
(href[i] >= 'a' && href[i] <= 'z')) {
continue;
}
- ALOGE("invalid include file name: %s", href);
+ PLOGD("invalid include file name: %s", href);
return BAD_VALUE;
}
std::string filename = href;
if (filename.compare(0, 13, "media_codecs_") != 0 ||
filename.compare(filename.size() - 4, 4, ".xml") != 0) {
- ALOGE("invalid include file name: %s", href);
+ PLOGD("invalid include file name: %s", href);
return BAD_VALUE;
}
filename.insert(0, mHrefBase);
- status_t oldParsingStatus = mParsingStatus;
+ Result res = mState->enterInclude(filename);
+ if (res) {
+ logAnyErrors(res);
+ return res;
+ }
- parseXMLFile(filename.c_str());
-
- status_t newParsingStatus = mParsingStatus;
- mParsingStatus = oldParsingStatus;
- return newParsingStatus;
+ // save state so that we can resume even if XML parsing of the included file failed midway
+ State::RestorePoint rp = mState->createRestorePoint();
+ Parser parser(mState, filename);
+ parser.parseXmlFile();
+ mState->restore(rp);
+ mState->exitInclude();
+ return parser.getStatus();
}
-void MediaCodecsXmlParser::startElementHandler(
+MediaCodecsXmlParser::Impl::Result
+MediaCodecsXmlParser::Impl::State::enterInclude(const std::string &fileName) {
+ if (std::find(mIncludeStack.begin(), mIncludeStack.end(), fileName)
+ != mIncludeStack.end()) {
+ return { BAD_VALUE, "recursive include chain" };
+ }
+ mIncludeStack.emplace_back(fileName);
+ return OK;
+}
+
+void MediaCodecsXmlParser::Impl::Parser::startElementHandler(
const char *name, const char **attrs) {
bool inType = true;
+ Result err = NO_INIT;
+ Section section = mState->section();
+
+ // handle include at any level
if (strEq(name, "Include")) {
- if (includeXMLFile(attrs) == OK) {
- mSectionStack.push_back(mCurrentSection);
- mCurrentSection = SECTION_INCLUDE;
- }
+ mState->enterSection(SECTION_INCLUDE);
+ updateStatus(includeXmlFile(attrs));
return;
}
- switch (mCurrentSection) {
+ // handle include section (top level)
+ if (section == SECTION_INCLUDE) {
+ if (strEq(name, "Included")) {
+ return;
+ }
+ // imitate prior level
+ section = mState->lastNonIncludeSection();
+ }
+
+ switch (section) {
case SECTION_TOPLEVEL:
{
+ Section nextSection;
if (strEq(name, "Decoders")) {
- mCurrentSection = SECTION_DECODERS;
+ nextSection = SECTION_DECODERS;
} else if (strEq(name, "Encoders")) {
- mCurrentSection = SECTION_ENCODERS;
+ nextSection = SECTION_ENCODERS;
} else if (strEq(name, "Settings")) {
- mCurrentSection = SECTION_SETTINGS;
+ nextSection = SECTION_SETTINGS;
+ } else if (strEq(name, "MediaCodecs")) {
+ return;
+ } else {
+ break;
}
- break;
+ mState->enterSection(nextSection);
+ return;
}
case SECTION_SETTINGS:
{
if (strEq(name, "Setting")) {
- (void)addSettingFromAttributes(attrs);
+ err = addSetting(attrs);
+ } else if (strEq(name, "Variant")) {
+ err = addSetting(attrs, "variant-");
+ } else if (strEq(name, "Domain")) {
+ err = addSetting(attrs, "domain-");
+ } else {
+ break;
}
- break;
+ updateStatus(err);
+ return;
}
case SECTION_DECODERS:
- {
- if (strEq(name, "MediaCodec")) {
- (void)addMediaCodecFromAttributes(false /* encoder */, attrs);
- mCurrentSection = SECTION_DECODER;
- }
- break;
- }
-
case SECTION_ENCODERS:
{
if (strEq(name, "MediaCodec")) {
- (void)addMediaCodecFromAttributes(true /* encoder */, attrs);
- mCurrentSection = SECTION_ENCODER;
+ err = enterMediaCodec(attrs, section == SECTION_ENCODERS);
+ updateStatus(err);
+ if (err != OK) { // skip this element on error
+ mState->enterSection(SECTION_UNKNOWN);
+ } else {
+ mState->enterVariants(mState->codec().variantSet);
+ mState->enterSection(
+ section == SECTION_DECODERS ? SECTION_DECODER : SECTION_ENCODER);
+ }
+ return;
}
break;
}
@@ -327,14 +699,21 @@
case SECTION_DECODER:
case SECTION_ENCODER:
{
- if (strEq(name, "Quirk") || strEq(name, "Attribute")) {
- (void)addQuirk(attrs, name);
+ if (strEq(name, "Quirk")) {
+ err = addQuirk(attrs, "quirk::");
+ } else if (strEq(name, "Attribute")) {
+ err = addQuirk(attrs, "attribute::");
+ } else if (strEq(name, "Alias")) {
+ err = addAlias(attrs);
} else if (strEq(name, "Type")) {
- (void)addTypeFromAttributes(attrs,
- (mCurrentSection == SECTION_ENCODER));
- mCurrentSection =
- (mCurrentSection == SECTION_DECODER ?
- SECTION_DECODER_TYPE : SECTION_ENCODER_TYPE);
+ err = enterType(attrs);
+ if (err != OK) { // skip this element on error
+ mState->enterSection(SECTION_UNKNOWN);
+ } else {
+ mState->enterSection(
+ section == SECTION_DECODER
+ ? SECTION_DECODER_TYPE : SECTION_ENCODER_TYPE);
+ }
}
}
inType = false;
@@ -342,91 +721,102 @@
case SECTION_DECODER_TYPE:
case SECTION_ENCODER_TYPE:
+ case SECTION_VARIANT:
{
// ignore limits and features specified outside of type
- bool outside = !inType &&
- mCurrentType == mCurrentCodec->second.typeMap.end();
- if (outside &&
- (strEq(name, "Limit") || strEq(name, "Feature"))) {
- ALOGW("ignoring %s specified outside of a Type", name);
- } else if (strEq(name, "Alias")) {
- (void)addAlias(attrs);
+ if (!mState->inType()
+ && (strEq(name, "Limit") || strEq(name, "Feature") || strEq(name, "Variant"))) {
+ PLOGD("ignoring %s specified outside of a Type", name);
+ return;
} else if (strEq(name, "Limit")) {
- (void)addLimit(attrs);
+ err = addLimit(attrs);
} else if (strEq(name, "Feature")) {
- (void)addFeature(attrs);
+ err = addFeature(attrs);
+ } else if (strEq(name, "Variant") && section != SECTION_VARIANT) {
+ err = limitVariants(attrs);
+ mState->enterSection(err == OK ? SECTION_VARIANT : SECTION_UNKNOWN);
+ } else if (inType
+ && (strEq(name, "Alias") || strEq(name, "Attribute") || strEq(name, "Quirk"))) {
+ PLOGD("ignoring %s specified not directly in a MediaCodec", name);
+ return;
+ } else if (err == NO_INIT) {
+ break;
}
- break;
+ updateStatus(err);
+ return;
}
default:
break;
}
+ if (section != SECTION_UNKNOWN) {
+ PLOGD("Ignoring unrecognized tag <%s>", name);
+ }
+ mState->enterSection(SECTION_UNKNOWN);
}
-void MediaCodecsXmlParser::endElementHandler(const char *name) {
- switch (mCurrentSection) {
+void MediaCodecsXmlParser::Impl::Parser::endElementHandler(const char *name) {
+ // XMLParser handles tag matching, so we really just need to handle the section state here
+ Section section = mState->section();
+ switch (section) {
+ case SECTION_INCLUDE:
+ {
+ // this could also be any of: Included, MediaCodecs
+ if (strEq(name, "Include")) {
+ mState->exitSection();
+ return;
+ }
+ break;
+ }
+
case SECTION_SETTINGS:
{
+ // this could also be any of: Domain, Variant, Setting
if (strEq(name, "Settings")) {
- mCurrentSection = SECTION_TOPLEVEL;
+ mState->exitSection();
}
break;
}
case SECTION_DECODERS:
- {
- if (strEq(name, "Decoders")) {
- mCurrentSection = SECTION_TOPLEVEL;
- }
- break;
- }
-
case SECTION_ENCODERS:
+ case SECTION_UNKNOWN:
{
- if (strEq(name, "Encoders")) {
- mCurrentSection = SECTION_TOPLEVEL;
- }
+ mState->exitSection();
break;
}
case SECTION_DECODER_TYPE:
case SECTION_ENCODER_TYPE:
{
+ // this could also be any of: Alias, Limit, Feature
if (strEq(name, "Type")) {
- mCurrentSection =
- (mCurrentSection == SECTION_DECODER_TYPE ?
- SECTION_DECODER : SECTION_ENCODER);
-
- mCurrentType = mCurrentCodec->second.typeMap.end();
+ mState->exitSection();
+ mState->exitCodecOrType();
}
break;
}
case SECTION_DECODER:
- {
- if (strEq(name, "MediaCodec")) {
- mCurrentSection = SECTION_DECODERS;
- mCurrentName.clear();
- }
- break;
- }
-
case SECTION_ENCODER:
{
+ // this could also be any of: Alias, Limit, Quirk, Variant
if (strEq(name, "MediaCodec")) {
- mCurrentSection = SECTION_ENCODERS;
- mCurrentName.clear();
+ mState->exitSection();
+ mState->exitCodecOrType();
+ mState->exitVariants();
}
break;
}
- case SECTION_INCLUDE:
+ case SECTION_VARIANT:
{
- if (strEq(name, "Include") && (mSectionStack.size() > 0)) {
- mCurrentSection = mSectionStack.back();
- mSectionStack.pop_back();
+ // this could also be any of: Alias, Limit, Quirk
+ if (strEq(name, "Variant")) {
+ mState->exitSection();
+ mState->exitVariants();
+ return;
}
break;
}
@@ -434,264 +824,302 @@
default:
break;
}
-
}
-status_t MediaCodecsXmlParser::addSettingFromAttributes(const char **attrs) {
- const char *name = nullptr;
- const char *value = nullptr;
- const char *update = nullptr;
+status_t MediaCodecsXmlParser::Impl::Parser::addSetting(const char **attrs, const char *prefix) {
+ const char *a_name = nullptr;
+ const char *a_value = nullptr;
+ const char *a_update = nullptr;
+ bool isBoolean = false;
size_t i = 0;
while (attrs[i] != nullptr) {
- if (strEq(attrs[i], "name")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addSettingFromAttributes: name is null");
- return BAD_VALUE;
- }
- name = attrs[i];
- } else if (strEq(attrs[i], "value")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addSettingFromAttributes: value is null");
- return BAD_VALUE;
- }
- value = attrs[i];
- } else if (strEq(attrs[i], "update")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addSettingFromAttributes: update is null");
- return BAD_VALUE;
- }
- update = attrs[i];
- } else {
- ALOGE("addSettingFromAttributes: unrecognized attribute: %s", attrs[i]);
+ CHECK((i & 1) == 0);
+ if (attrs[i + 1] == nullptr) {
+ PLOGD("Setting: attribute '%s' is null", attrs[i]);
return BAD_VALUE;
}
+
+ if (strEq(attrs[i], "name")) {
+ a_name = attrs[++i];
+ } else if (strEq(attrs[i], "value") || strEq(attrs[i], "enabled")) {
+ if (a_value) {
+ PLOGD("Setting: redundant attribute '%s'", attrs[i]);
+ return BAD_VALUE;
+ }
+ isBoolean = strEq(attrs[i], "enabled");
+ a_value = attrs[++i];
+ } else if (strEq(attrs[i], "update")) {
+ a_update = attrs[++i];
+ } else {
+ PLOGD("Setting: ignoring unrecognized attribute '%s'", attrs[i]);
+ ++i;
+ }
++i;
}
- if (name == nullptr || value == nullptr) {
- ALOGE("addSettingFromAttributes: name or value unspecified");
+ if (a_name == nullptr || a_value == nullptr) {
+ PLOGD("Setting with no 'name' or 'value' attribute");
return BAD_VALUE;
}
// Boolean values are converted to "0" or "1".
- if (strHasPrefix(name, "supports-")) {
- value = parseBoolean(value) ? "1" : "0";
+ if (strHasPrefix(a_name, "supports-") || isBoolean) {
+ a_value = parseBoolean(a_value) ? "1" : "0";
}
- mUpdate = (update != nullptr) && parseBoolean(update);
- auto attribute = mServiceAttributeMap.find(name);
+ bool update = (a_update != nullptr) && parseBoolean(a_update);
+ Result res = mState->data().addGlobal(std::string(prefix ? : "") + a_name, a_value, update);
+ if (res != OK) {
+ PLOGD("Setting: %s", res.error().c_str());
+ }
+ return res;
+}
+
+MediaCodecsXmlParser::Impl::Result MediaCodecsXmlParser::Impl::Data::addGlobal(
+ std::string key, std::string value, bool updating) {
+ auto attribute = mServiceAttributeMap.find(key);
if (attribute == mServiceAttributeMap.end()) { // New attribute name
- if (mUpdate) {
- ALOGE("addSettingFromAttributes: updating non-existing setting");
- return BAD_VALUE;
+ if (updating) {
+ return { NAME_NOT_FOUND, "cannot update non-existing setting" };
}
- mServiceAttributeMap.insert(Attribute(name, value));
+ mServiceAttributeMap.insert(Attribute(key, value));
} else { // Existing attribute name
- if (!mUpdate) {
- ALOGE("addSettingFromAttributes: adding existing setting");
- }
attribute->second = value;
+ if (!updating) {
+ return { ALREADY_EXISTS, "updating existing setting" };
+ }
}
return OK;
}
-status_t MediaCodecsXmlParser::addMediaCodecFromAttributes(
- bool encoder, const char **attrs) {
- const char *name = nullptr;
- const char *type = nullptr;
- const char *update = nullptr;
- const char *rank = nullptr;
+status_t MediaCodecsXmlParser::Impl::Parser::enterMediaCodec(
+ const char **attrs, bool encoder) {
+ const char *a_name = nullptr;
+ const char *a_type = nullptr;
+ const char *a_update = nullptr;
+ const char *a_rank = nullptr;
+ const char *a_domain = nullptr;
+ const char *a_variant = nullptr;
+ const char *a_enabled = nullptr;
size_t i = 0;
while (attrs[i] != nullptr) {
- if (strEq(attrs[i], "name")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addMediaCodecFromAttributes: name is null");
- return BAD_VALUE;
- }
- name = attrs[i];
- } else if (strEq(attrs[i], "type")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addMediaCodecFromAttributes: type is null");
- return BAD_VALUE;
- }
- type = attrs[i];
- } else if (strEq(attrs[i], "update")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addMediaCodecFromAttributes: update is null");
- return BAD_VALUE;
- }
- update = attrs[i];
- } else if (strEq(attrs[i], "rank")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addMediaCodecFromAttributes: rank is null");
- return BAD_VALUE;
- }
- rank = attrs[i];
- } else {
- ALOGE("addMediaCodecFromAttributes: unrecognized attribute: %s", attrs[i]);
+ CHECK((i & 1) == 0);
+ if (attrs[i + 1] == nullptr) {
+ PLOGD("MediaCodec: attribute '%s' is null", attrs[i]);
return BAD_VALUE;
}
+
+ if (strEq(attrs[i], "name")) {
+ a_name = attrs[++i];
+ } else if (strEq(attrs[i], "type")) {
+ a_type = attrs[++i];
+ } else if (strEq(attrs[i], "update")) {
+ a_update = attrs[++i];
+ } else if (strEq(attrs[i], "rank")) {
+ a_rank = attrs[++i];
+ } else if (strEq(attrs[i], "domain")) {
+ a_domain = attrs[++i];
+ } else if (strEq(attrs[i], "variant")) {
+ a_variant = attrs[++i];
+ } else if (strEq(attrs[i], "enabled")) {
+ a_enabled = attrs[++i];
+ } else {
+ PLOGD("MediaCodec: ignoring unrecognized attribute '%s'", attrs[i]);
+ ++i;
+ }
++i;
}
- if (name == nullptr) {
- ALOGE("addMediaCodecFromAttributes: name not found");
+ if (a_name == nullptr) {
+ PLOGD("MediaCodec with no 'name' attribute");
return BAD_VALUE;
}
- mUpdate = (update != nullptr) && parseBoolean(update);
- mCurrentCodec = mCodecMap.find(name);
- if (mCurrentCodec == mCodecMap.end()) { // New codec name
- if (mUpdate) {
- ALOGW("addMediaCodecFromAttributes: cannot update "
- "non-existing codec \"%s\".", name);
- return BAD_VALUE;
+ bool update = (a_update != nullptr) && parseBoolean(a_update);
+ if (a_domain != nullptr) {
+ // disable codecs with domain by default (unless updating)
+ if (!a_enabled && !update) {
+ a_enabled = "false";
+ }
+ }
+
+ Result res = mState->enterMediaCodec(encoder, a_name, a_type, update);
+ if (res != OK) {
+ logAnyErrors(res);
+ return res;
+ }
+
+ return updateMediaCodec(
+ a_rank, parseCommaSeparatedStringSet(a_domain),
+ parseCommaSeparatedStringSet(a_variant), a_enabled);
+}
+
+MediaCodecsXmlParser::Impl::Result
+MediaCodecsXmlParser::Impl::State::enterMediaCodec(
+ bool encoder, const char *name, const char *type, bool updating) {
+ // store name even in case of an error
+ CodecMap::iterator codecIt = mData->mCodecMap.find(name);
+ TypeMap::iterator typeIt;
+ if (codecIt == mData->mCodecMap.end()) { // New codec name
+ if (updating) {
+ return { NAME_NOT_FOUND, "MediaCodec: cannot update non-existing codec" };
}
// Create a new codec in mCodecMap
- mCurrentCodec = mCodecMap.insert(
- Codec(name, CodecProperties())).first;
+ codecIt = mData->mCodecMap.insert(Codec(name, CodecProperties())).first;
if (type != nullptr) {
- mCurrentType = mCurrentCodec->second.typeMap.insert(
- Type(type, AttributeMap())).first;
+ typeIt = codecIt->second.typeMap.insert(Type(type, AttributeMap())).first;
} else {
- mCurrentType = mCurrentCodec->second.typeMap.end();
+ typeIt = codecIt->second.typeMap.end();
}
- mCurrentCodec->second.isEncoder = encoder;
- mCurrentCodec->second.order = mCodecCounter++;
+ codecIt->second.isEncoder = encoder;
+ codecIt->second.order = mData->mCodecMap.size();
} else { // Existing codec name
- if (!mUpdate) {
- ALOGW("addMediaCodecFromAttributes: trying to add "
- "existing codec \"%s\"", name);
- return ALREADY_EXISTS;
+ if (!updating) {
+ return { ALREADY_EXISTS, "MediaCodec: cannot add existing codec" };
}
if (type != nullptr) {
- mCurrentType = mCurrentCodec->second.typeMap.find(type);
- if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
- ALOGE("addMediaCodecFromAttributes: cannot update "
- "non-existing type \"%s\" for codec \"%s\"",
- type, name);
- return BAD_VALUE;
+ typeIt = codecIt->second.typeMap.find(type);
+ if (typeIt == codecIt->second.typeMap.end()) {
+ return { NAME_NOT_FOUND, "MediaCodec: cannot update non-existing type for codec" };
}
} else {
// This should happen only when the codec has at most one type.
- mCurrentType = mCurrentCodec->second.typeMap.begin();
- if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
- ALOGE("addMediaCodecFromAttributes: cannot update "
- "codec \"%s\" without type specified", name);
- return BAD_VALUE;
+ typeIt = codecIt->second.typeMap.begin();
+ if (typeIt == codecIt->second.typeMap.end()
+ || codecIt->second.typeMap.size() != 1) {
+ return { BAD_VALUE, "MediaCodec: cannot update codec without type specified" };
}
}
}
+ mCurrent.emplace_back(CodecAndType{name, codecIt, typeIt, updating});
+ return OK;
+}
+
+status_t MediaCodecsXmlParser::Impl::Parser::updateMediaCodec(
+ const char *rank, const StringSet &domains, const StringSet &variants,
+ const char *enabled) {
+ CHECK(mState->inCodec());
+ CodecProperties &codec = mState->codec();
if (rank != nullptr) {
- if (!mCurrentCodec->second.rank.empty() && mCurrentCodec->second.rank != rank) {
- ALOGE("addMediaCodecFromAttributes: code \"%s\" rank changed from \"%s\" to \"%s\"",
- name, mCurrentCodec->second.rank.c_str(), rank);
- return BAD_VALUE;
- }
- mCurrentCodec->second.rank = rank;
+ ALOGD_IF(!codec.rank.empty() && codec.rank != rank,
+ "codec '%s' rank changed from '%s' to '%s'",
+ mState->codecName().c_str(), codec.rank.c_str(), rank);
+ codec.rank = rank;
}
+ codec.variantSet = variants;
+
+ for (const std::string &domain : domains) {
+ if (domain.size() && domain.at(0) == '!') {
+ codec.domainSet.erase(domain.substr(1));
+ } else {
+ codec.domainSet.emplace(domain);
+ }
+ }
+
+ if (enabled != nullptr) {
+ if (parseBoolean(enabled)) {
+ codec.quirkSet.erase("attribute::disabled");
+ ALOGD("enabling %s", mState->codecName().c_str());
+ } else {
+ codec.quirkSet.emplace("attribute::disabled");
+ ALOGD("disabling %s", mState->codecName().c_str());
+ }
+ }
return OK;
}
-status_t MediaCodecsXmlParser::addQuirk(const char **attrs, const char *tag) {
- if (mCurrentCodec == mCodecMap.end()) {
- return BAD_VALUE;
- }
-
- const char *name = nullptr;
+status_t MediaCodecsXmlParser::Impl::Parser::addQuirk(const char **attrs, const char *prefix) {
+ CHECK(mState->inCodec());
+ const char *a_name = nullptr;
size_t i = 0;
while (attrs[i] != nullptr) {
- if (strEq(attrs[i], "name")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addQuirk: name is null");
- return BAD_VALUE;
- }
- name = attrs[i];
- } else {
- ALOGE("addQuirk: unrecognized attribute: %s", attrs[i]);
+ CHECK((i & 1) == 0);
+ if (attrs[i + 1] == nullptr) {
+ PLOGD("Quirk: attribute '%s' is null", attrs[i]);
return BAD_VALUE;
}
+
+ if (strEq(attrs[i], "name")) {
+ a_name = attrs[++i];
+ } else {
+ PLOGD("Quirk: ignoring unrecognized attribute '%s'", attrs[i]);
+ ++i;
+ }
++i;
}
- if (name == nullptr) {
- ALOGE("addQuirk: name not found");
+ if (a_name == nullptr) {
+ PLOGD("Quirk with no 'name' attribute");
return BAD_VALUE;
}
- std::string tagString = tag;
- std::transform(tagString.begin(), tagString.end(), tagString.begin(), ::tolower);
- tagString.append("::");
- tagString.append(name);
- mCurrentCodec->second.quirkSet.emplace(tagString.c_str());
- ALOGI("adding %s to %s", tagString.c_str(), mCurrentCodec->first.c_str());
+ std::string key = std::string(prefix ? : "") + a_name;
+ mState->codec().quirkSet.emplace(key);
+ ALOGV("adding %s to %s", key.c_str(), mState->codecName().c_str());
return OK;
}
-status_t MediaCodecsXmlParser::addTypeFromAttributes(const char **attrs, bool encoder) {
- if (mCurrentCodec == mCodecMap.end()) {
- return BAD_VALUE;
- }
+status_t MediaCodecsXmlParser::Impl::Parser::enterType(const char **attrs) {
+ CHECK(mState->inCodec());
- const char *name = nullptr;
- const char *update = nullptr;
+ const char *a_name = nullptr;
+ const char *a_update = nullptr;
size_t i = 0;
while (attrs[i] != nullptr) {
+ CHECK((i & 1) == 0);
+ if (attrs[i + 1] == nullptr) {
+ PLOGD("Type: attribute '%s' is null", attrs[i]);
+ return BAD_VALUE;
+ }
+
if (strEq(attrs[i], "name")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addTypeFromAttributes: name is null");
- return BAD_VALUE;
- }
- name = attrs[i];
+ a_name = attrs[++i];
} else if (strEq(attrs[i], "update")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addTypeFromAttributes: update is null");
- return BAD_VALUE;
- }
- update = attrs[i];
+ a_update = attrs[++i];
} else {
- ALOGE("addTypeFromAttributes: unrecognized attribute: %s", attrs[i]);
- return BAD_VALUE;
+ PLOGD("Type: ignoring unrecognized attribute '%s'", attrs[i]);
+ ++i;
}
++i;
}
- if (name == nullptr) {
+ if (a_name == nullptr) {
+ PLOGD("Type with no 'name' attribute");
return BAD_VALUE;
}
- mCurrentCodec->second.isEncoder = encoder;
- mCurrentType = mCurrentCodec->second.typeMap.find(name);
- if (!mUpdate) {
- if (mCurrentType != mCurrentCodec->second.typeMap.end()) {
- ALOGW("addTypeFromAttributes: trying to update "
- "existing type \"%s\"", name);
- return ALREADY_EXISTS;
+ bool update = (a_update != nullptr) && parseBoolean(a_update);
+ return mState->enterType(a_name, update);
+}
+
+MediaCodecsXmlParser::Impl::Result
+MediaCodecsXmlParser::Impl::State::enterType(const char *name, bool update) {
+ update = update || updating(); // handle parent
+
+ CodecMap::iterator codecIt = mCurrent.back().mCodec;
+ TypeMap::iterator typeIt = codecIt->second.typeMap.find(name);
+ if (!update) {
+ if (typeIt != codecIt->second.typeMap.end()) {
+ return { ALREADY_EXISTS, "trying to update existing type '" + std::string(name) + "'" };
}
- mCurrentType = mCurrentCodec->second.typeMap.insert(
- Type(name, AttributeMap())).first;
- } else if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
- ALOGE("addTypeFromAttributes: updating non-existing type");
- return BAD_VALUE;
+ typeIt = codecIt->second.typeMap.insert(Type(name, AttributeMap())).first;
+ } else if (typeIt == codecIt->second.typeMap.end()) {
+ return { NAME_NOT_FOUND, "addType: updating non-existing type" };
}
+ mCurrent.push_back({ codecName(), codecIt, typeIt, update });
+ CHECK(inType());
return OK;
}
-status_t MediaCodecsXmlParser::addLimit(const char **attrs) {
- if (mCurrentCodec == mCodecMap.end()) {
- return BAD_VALUE;
- }
- if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
- return BAD_VALUE;
- }
-
+status_t MediaCodecsXmlParser::Impl::Parser::addLimit(const char **attrs) {
+ CHECK(mState->inType());
const char* a_name = nullptr;
const char* a_default = nullptr;
const char* a_in = nullptr;
@@ -704,69 +1132,39 @@
size_t i = 0;
while (attrs[i] != nullptr) {
- if (strEq(attrs[i], "name")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addLimit: name is null");
- return BAD_VALUE;
- }
- a_name = attrs[i];
- } else if (strEq(attrs[i], "default")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addLimit: default is null");
- return BAD_VALUE;
- }
- a_default = attrs[i];
- } else if (strEq(attrs[i], "in")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addLimit: in is null");
- return BAD_VALUE;
- }
- a_in = attrs[i];
- } else if (strEq(attrs[i], "max")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addLimit: max is null");
- return BAD_VALUE;
- }
- a_max = attrs[i];
- } else if (strEq(attrs[i], "min")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addLimit: min is null");
- return BAD_VALUE;
- }
- a_min = attrs[i];
- } else if (strEq(attrs[i], "range")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addLimit: range is null");
- return BAD_VALUE;
- }
- a_range = attrs[i];
- } else if (strEq(attrs[i], "ranges")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addLimit: ranges is null");
- return BAD_VALUE;
- }
- a_ranges = attrs[i];
- } else if (strEq(attrs[i], "scale")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addLimit: scale is null");
- return BAD_VALUE;
- }
- a_scale = attrs[i];
- } else if (strEq(attrs[i], "value")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addLimit: value is null");
- return BAD_VALUE;
- }
- a_value = attrs[i];
- } else {
- ALOGE("addLimit: unrecognized limit: %s", attrs[i]);
+ CHECK((i & 1) == 0);
+ if (attrs[i + 1] == nullptr) {
+ PLOGD("Limit: attribute '%s' is null", attrs[i]);
return BAD_VALUE;
}
+
+ if (strEq(attrs[i], "name")) {
+ a_name = attrs[++i];
+ } else if (strEq(attrs[i], "default")) {
+ a_default = attrs[++i];
+ } else if (strEq(attrs[i], "in")) {
+ a_in = attrs[++i];
+ } else if (strEq(attrs[i], "max")) {
+ a_max = attrs[++i];
+ } else if (strEq(attrs[i], "min")) {
+ a_min = attrs[++i];
+ } else if (strEq(attrs[i], "range")) {
+ a_range = attrs[++i];
+ } else if (strEq(attrs[i], "ranges")) {
+ a_ranges = attrs[++i];
+ } else if (strEq(attrs[i], "scale")) {
+ a_scale = attrs[++i];
+ } else if (strEq(attrs[i], "value")) {
+ a_value = attrs[++i];
+ } else {
+ PLOGD("Limit: ignoring unrecognized limit: %s", attrs[i]);
+ ++i;
+ }
++i;
}
if (a_name == nullptr) {
- ALOGE("limit with no 'name' attribute");
+ PLOGD("Limit with no 'name' attribute");
return BAD_VALUE;
}
@@ -774,8 +1172,50 @@
// measured-frame-rate, measured-blocks-per-second: range
// quality: range + default + [scale]
// complexity: range + default
- std::string range;
- if (strEq(a_name, "aspect-ratio") ||
+ std::string key = a_name, value;
+
+ // don't allow specifying more than one of value, range or min/max
+ if ((a_value != nullptr) + (a_range != nullptr) + (a_ranges != nullptr)
+ + (a_min != nullptr || a_max != nullptr) > 1) {
+ PLOGD("Limit '%s' has multiple 'min'/'max', 'range', 'ranges' or 'value' attributes",
+ a_name);
+ return BAD_VALUE;
+ }
+
+ // Min/max limits (only containing min or max attribute)
+ //
+ // Current "max" limits are "channel-count", "concurrent-instances".
+ // There are no current "min" limits
+ //
+ // Range limits. "range" is specified in exactly one of the following forms:
+ // 1) min-max
+ // 2) value-value
+ // 3) range
+ //
+ // Current range limits are "aspect-ratio", "bitrate", "block-count", "blocks-per-second",
+ // "complexity", "frame-rate", "quality", "size", "measured-blocks-per-second",
+ // "performance-point-*", "measured-frame-rate-*"
+ //
+ // Other limits (containing only value or ranges)
+ //
+ // Current ranges limit is "sample-rate"
+ if ((a_min != nullptr) ^ (a_max != nullptr)) {
+ // min/max limit
+ if (a_max != nullptr) {
+ key = "max-" + key;
+ value = a_max;
+ } else if (a_min != nullptr) {
+ key = "min-" + key;
+ value = a_min;
+ }
+ } else if (a_min != nullptr && a_max != nullptr) {
+ // min-max
+ key += "-range";
+ value = a_min + std::string("-") + a_max;
+ } else if (a_value != nullptr) {
+ // value-value or value
+ value = a_value;
+ if (strEq(a_name, "aspect-ratio") ||
strEq(a_name, "bitrate") ||
strEq(a_name, "block-count") ||
strEq(a_name, "blocks-per-second") ||
@@ -786,249 +1226,199 @@
strEq(a_name, "measured-blocks-per-second") ||
strHasPrefix(a_name, "performance-point-") ||
strHasPrefix(a_name, "measured-frame-rate-")) {
- // "range" is specified in exactly one of the following forms:
- // 1) min-max
- // 2) value-value
- // 3) range
- if (a_min != nullptr && a_max != nullptr) {
- // min-max
- if (a_range != nullptr || a_value != nullptr) {
- return limitError(a_name, "has 'min' and 'max' as well as 'range' or "
- "'value' attributes");
- }
- range = a_min;
- range += '-';
- range += a_max;
- } else if (a_min != nullptr || a_max != nullptr) {
- return limitError(a_name, "has only 'min' or 'max' attribute");
- } else if (a_value != nullptr) {
- // value-value
- if (a_range != nullptr) {
- return limitError(a_name, "has both 'range' and 'value' attributes");
- }
- range = a_value;
- range += '-';
- range += a_value;
- } else if (a_range == nullptr) {
- return limitError(a_name, "with no 'range', 'value' or 'min'/'max' attributes");
- } else {
- // range
- range = a_range;
+ key += "-range";
+ value += std::string("-") + a_value;
}
-
- // "aspect-ratio" requires some special treatment.
- if (strEq(a_name, "aspect-ratio")) {
- // "aspect-ratio" must have "in".
- if (a_in == nullptr) {
- return limitFoundMissingAttr(a_name, "in", false);
- }
- // "in" must be either "pixels" or "blocks".
- if (!strEq(a_in, "pixels") && !strEq(a_in, "blocks")) {
- return limitInvalidAttr(a_name, "in", a_in);
- }
- // name will be "pixel-aspect-ratio-range" or
- // "block-aspect-ratio-range".
- mCurrentType->second[
- std::string(a_in).substr(0, strlen(a_in) - 1) +
- "-aspect-ratio-range"] = range;
- } else {
- // For everything else (apart from "aspect-ratio"), simply append
- // "-range" to the name for the range-type property.
- mCurrentType->second[std::string(a_name) + "-range"] = range;
-
- // Only "quality" may have "scale".
- if (!strEq(a_name, "quality") && a_scale != nullptr) {
- return limitFoundMissingAttr(a_name, "scale");
- } else if (strEq(a_name, "quality")) {
- // The default value of "quality-scale" is "linear".
- mCurrentType->second["quality-scale"] = a_scale == nullptr ?
- "linear" : a_scale;
- }
-
- // "quality" and "complexity" must have "default".
- // Other limits must not have "default".
- if (strEq(a_name, "quality") || strEq(a_name, "complexity")) {
- if (a_default == nullptr) {
- return limitFoundMissingAttr(a_name, "default", false);
- }
- // name will be "quality-default" or "complexity-default".
- mCurrentType->second[std::string(a_name) + "-default"] = a_default;
- } else if (a_default != nullptr) {
- return limitFoundMissingAttr(a_name, "default", true);
- }
- }
+ } else if (a_range != nullptr) {
+ // range
+ key += "-range";
+ value = a_range;
+ } else if (a_ranges != nullptr) {
+ // ranges
+ key += "-ranges";
+ value = a_ranges;
} else {
- if (a_default != nullptr) {
- return limitFoundMissingAttr(a_name, "default");
- }
- if (a_in != nullptr) {
- return limitFoundMissingAttr(a_name, "in");
- }
- if (a_scale != nullptr) {
- return limitFoundMissingAttr(a_name, "scale");
- }
- if (a_range != nullptr) {
- return limitFoundMissingAttr(a_name, "range");
- }
- if (a_min != nullptr) {
- return limitFoundMissingAttr(a_name, "min");
- }
-
- if (a_max != nullptr) {
- // "max" must exist if and only if name is "channel-count" or
- // "concurrent-instances".
- // "min" is not ncessary.
- if (strEq(a_name, "channel-count") ||
- strEq(a_name, "concurrent-instances")) {
- mCurrentType->second[std::string("max-") + a_name] = a_max;
- } else {
- return limitFoundMissingAttr(a_name, "max", false);
- }
- } else if (strEq(a_name, "channel-count") ||
- strEq(a_name, "concurrent-instances")) {
- return limitFoundMissingAttr(a_name, "max");
- }
-
- if (a_ranges != nullptr) {
- // "ranges" must exist if and only if name is "sample-rate".
- if (strEq(a_name, "sample-rate")) {
- mCurrentType->second["sample-rate-ranges"] = a_ranges;
- } else {
- return limitFoundMissingAttr(a_name, "ranges", false);
- }
- } else if (strEq(a_name, "sample-rate")) {
- return limitFoundMissingAttr(a_name, "ranges");
- }
-
- if (a_value != nullptr) {
- // "value" must exist if and only if name is "alignment" or
- // "block-size".
- if (strEq(a_name, "alignment") || strEq(a_name, "block-size")) {
- mCurrentType->second[a_name] = a_value;
- } else {
- return limitFoundMissingAttr(a_name, "value", false);
- }
- } else if (strEq(a_name, "alignment") || strEq(a_name, "block-size")) {
- return limitFoundMissingAttr(a_name, "value", false);
- }
-
+ PLOGD("Limit '%s' with no 'range', 'value' or 'min'/'max' attributes", a_name);
+ return BAD_VALUE;
}
+ // handle 'in' attribute - this changes the key
+ if (a_in != nullptr) {
+ // Currently "aspect-ratio" uses in attribute
+ const size_t a_in_len = strlen(a_in);
+ key = std::string(a_in, a_in_len - a_in[a_in_len] == 's') + '-' + key;
+ }
+
+ // handle 'scale' attribute - this adds a new detail
+ if (a_scale != nullptr) {
+ mState->addDetail(a_name + std::string("-scale"), a_scale);
+ } else if (strEq(a_name, "quality")) {
+ // The default value of "quality-scale" is "linear" even if unspecified.
+ mState->addDetail(a_name + std::string("-scale"), "linear");
+ }
+
+ // handle 'default' attribute - this adds a new detail
+ if (a_default != nullptr) {
+ mState->addDetail(a_name + std::string("-default"), a_default);
+ }
+
+ mState->addDetail(key, value);
return OK;
}
-status_t MediaCodecsXmlParser::addFeature(const char **attrs) {
- if (mCurrentCodec == mCodecMap.end()) {
- return BAD_VALUE;
+void MediaCodecsXmlParser::Impl::State::addDetail(
+ const std::string &key, const std::string &value) {
+ CHECK(inType());
+ ALOGI("limit: %s = %s", key.c_str(), value.c_str());
+ const StringSet &variants = mVariantsStack.back();
+ if (variants.empty()) {
+ type()[key] = value;
+ } else {
+ for (const std::string &variant : variants) {
+ type()[variant + ":::" + key] = value;
+ }
}
- if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
+}
+
+status_t MediaCodecsXmlParser::Impl::Parser::limitVariants(const char **attrs) {
+ const char* a_name = nullptr;
+
+ size_t i = 0;
+ while (attrs[i] != nullptr) {
+ CHECK((i & 1) == 0);
+ if (attrs[i + 1] == nullptr) {
+ PLOGD("Variant: attribute '%s' is null", attrs[i]);
+ return BAD_VALUE;
+ }
+ if (strEq(attrs[i], "name")) {
+ a_name = attrs[++i];
+ } else {
+ PLOGD("Variant: ignoring unrecognized attribute: %s", attrs[i]);
+ ++i;
+ }
+ ++i;
+ }
+
+ if (a_name == nullptr || *a_name == '\0') {
+ PLOGD("Variant with no or empty 'name' attribute");
return BAD_VALUE;
}
+ StringSet variants;
+ for (const std::string &variant : parseCommaSeparatedStringSet(a_name)) {
+ if (mState->variants().count(variant)) {
+ variants.emplace(variant);
+ } else {
+ PLOGD("Variant: variant '%s' not in parent variants", variant.c_str());
+ return BAD_VALUE;
+ }
+ }
+ mState->enterVariants(variants);
+ return OK;
+}
+
+status_t MediaCodecsXmlParser::Impl::Parser::addFeature(const char **attrs) {
+ CHECK(mState->inType());
size_t i = 0;
- const char *name = nullptr;
+ const char *a_name = nullptr;
int32_t optional = -1;
int32_t required = -1;
- const char *value = nullptr;
+ const char *a_value = nullptr;
while (attrs[i] != nullptr) {
- if (strEq(attrs[i], "name")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addFeature: name is null");
- return BAD_VALUE;
- }
- name = attrs[i];
- } else if (strEq(attrs[i], "optional")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addFeature: optional is null");
- return BAD_VALUE;
- }
- optional = parseBoolean(attrs[i]) ? 1 : 0;
- } else if (strEq(attrs[i], "required")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addFeature: required is null");
- return BAD_VALUE;
- }
- required = parseBoolean(attrs[i]) ? 1 : 0;
- } else if (strEq(attrs[i], "value")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addFeature: value is null");
- return BAD_VALUE;
- }
- value = attrs[i];
- } else {
- ALOGE("addFeature: unrecognized attribute: %s", attrs[i]);
+ CHECK((i & 1) == 0);
+ if (attrs[i + 1] == nullptr) {
+ PLOGD("Feature: attribute '%s' is null", attrs[i]);
return BAD_VALUE;
}
+
+ if (strEq(attrs[i], "name")) {
+ a_name = attrs[++i];
+ } else if (strEq(attrs[i], "optional")) {
+ optional = parseBoolean(attrs[++i]) ? 1 : 0;
+ } else if (strEq(attrs[i], "required")) {
+ required = parseBoolean(attrs[++i]) ? 1 : 0;
+ } else if (strEq(attrs[i], "value")) {
+ a_value = attrs[++i];
+ } else {
+ PLOGD("Feature: ignoring unrecognized attribute '%s'", attrs[i]);
+ ++i;
+ }
++i;
}
// Every feature must have a name.
- if (name == nullptr) {
- ALOGE("feature with no 'name' attribute");
+ if (a_name == nullptr) {
+ PLOGD("Feature with no 'name' attribute");
return BAD_VALUE;
}
- if ((optional != -1) || (required != -1)) {
- if (optional == required) {
- ALOGE("feature '%s' is both/neither optional and required", name);
+ if (a_value != nullptr) {
+ if (optional != -1 || required != -1) {
+ PLOGD("Feature '%s' has both value and optional/required attributes", a_name);
return BAD_VALUE;
}
- if ((optional == 1) || (required == 1)) {
- if (value != nullptr) {
- ALOGE("feature '%s' cannot have extra 'value'", name);
- return BAD_VALUE;
- }
- mCurrentType->second[std::string("feature-") + name] =
- optional == 1 ? "0" : "1";
- return OK;
+ } else {
+ if (optional == required && optional != -1) {
+ PLOGD("Feature '%s' is both/neither optional and required", a_name);
+ return BAD_VALUE;
}
+ a_value = (required == 1 || optional == 0) ? "1" : "0";
}
- mCurrentType->second[std::string("feature-") + name] = value == nullptr ?
- "0" : value;
+
+ mState->addDetail(std::string("feature-") + a_name, a_value ? : "0");
return OK;
}
-status_t MediaCodecsXmlParser::addAlias(const char **attrs) {
+status_t MediaCodecsXmlParser::Impl::Parser::addAlias(const char **attrs) {
+ CHECK(mState->inCodec());
size_t i = 0;
- const char *name = nullptr;
+ const char *a_name = nullptr;
while (attrs[i] != nullptr) {
- if (strEq(attrs[i], "name")) {
- if (attrs[++i] == nullptr) {
- ALOGE("addAlias: name is null");
- return BAD_VALUE;
- }
- name = attrs[i];
- } else {
- ALOGE("addAlias: unrecognized attribute: %s", attrs[i]);
+ CHECK((i & 1) == 0);
+ if (attrs[i + 1] == nullptr) {
+ PLOGD("Alias: attribute '%s' is null", attrs[i]);
return BAD_VALUE;
}
+
+ if (strEq(attrs[i], "name")) {
+ a_name = attrs[++i];
+ } else {
+ PLOGD("Alias: ignoring unrecognized attribute '%s'", attrs[i]);
+ ++i;
+ }
++i;
}
// Every feature must have a name.
- if (name == nullptr) {
- ALOGE("alias with no 'name' attribute");
+ if (a_name == nullptr) {
+ PLOGD("Alias with no 'name' attribute");
return BAD_VALUE;
}
- mCurrentCodec->second.aliases.emplace_back(name);
+ mState->codec().aliases.emplace_back(a_name);
return OK;
}
const MediaCodecsXmlParser::AttributeMap&
- MediaCodecsXmlParser::getServiceAttributeMap() const {
- return mServiceAttributeMap;
+MediaCodecsXmlParser::getServiceAttributeMap() const {
+ return mImpl->getServiceAttributeMap();
}
const MediaCodecsXmlParser::CodecMap&
- MediaCodecsXmlParser::getCodecMap() const {
- return mCodecMap;
+MediaCodecsXmlParser::getCodecMap() const {
+ return mImpl->getCodecMap();
}
const MediaCodecsXmlParser::RoleMap&
- MediaCodecsXmlParser::getRoleMap() const {
+MediaCodecsXmlParser::getRoleMap() const {
+ return mImpl->getRoleMap();
+}
+
+const MediaCodecsXmlParser::RoleMap&
+MediaCodecsXmlParser::Impl::getRoleMap() const {
+ std::lock_guard<std::mutex> guard(mLock);
if (mRoleMap.empty()) {
generateRoleMap();
}
@@ -1036,6 +1426,11 @@
}
const char* MediaCodecsXmlParser::getCommonPrefix() const {
+ return mImpl->getCommonPrefix();
+}
+
+const char* MediaCodecsXmlParser::Impl::getCommonPrefix() const {
+ std::lock_guard<std::mutex> guard(mLock);
if (mCommonPrefix.empty()) {
generateCommonPrefix();
}
@@ -1043,12 +1438,15 @@
}
status_t MediaCodecsXmlParser::getParsingStatus() const {
- return mParsingStatus;
+ return mImpl->getParsingStatus();
}
-void MediaCodecsXmlParser::generateRoleMap() const {
- for (const auto& codec : mCodecMap) {
- const auto& codecName = codec.first;
+void MediaCodecsXmlParser::Impl::generateRoleMap() const {
+ for (const auto& codec : mData.mCodecMap) {
+ const auto &codecName = codec.first;
+ if (codecName == "<dummy>") {
+ continue;
+ }
bool isEncoder = codec.second.isEncoder;
size_t order = codec.second.order;
std::string rank = codec.second.rank;
@@ -1116,14 +1514,14 @@
}
}
-void MediaCodecsXmlParser::generateCommonPrefix() const {
- if (mCodecMap.empty()) {
+void MediaCodecsXmlParser::Impl::generateCommonPrefix() const {
+ if (mData.mCodecMap.empty()) {
return;
}
- auto i = mCodecMap.cbegin();
+ auto i = mData.mCodecMap.cbegin();
auto first = i->first.cbegin();
auto last = i->first.cend();
- for (++i; i != mCodecMap.cend(); ++i) {
+ for (++i; i != mData.mCodecMap.cend(); ++i) {
last = std::mismatch(
first, last, i->first.cbegin(), i->first.cend()).first;
}
@@ -1131,4 +1529,3 @@
}
} // namespace android
-
diff --git a/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h b/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
index 7a986b7..b666de4 100644
--- a/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
+++ b/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
@@ -19,34 +19,31 @@
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/Vector.h>
-#include <utils/StrongPointer.h>
-#include <string>
-#include <set>
#include <map>
+#include <mutex>
+#include <set>
+#include <string>
#include <vector>
+struct XML_ParserStruct; // from expat library
+
namespace android {
class MediaCodecsXmlParser {
public:
// Treblized media codec list will be located in /odm/etc or /vendor/etc.
- static constexpr char const* defaultSearchDirs[] =
- {"/odm/etc", "/vendor/etc", "/etc", nullptr};
- static constexpr char const* defaultMainXmlName =
- "media_codecs.xml";
- static constexpr char const* defaultPerformanceXmlName =
- "media_codecs_performance.xml";
+ static std::vector<std::string> getDefaultSearchDirs() {
+ return { "/odm/etc", "/vendor/etc", "/etc" };
+ }
+ static std::vector<std::string> getDefaultXmlNames() {
+ return { "media_codecs.xml", "media_codecs_performance.xml" };
+ }
static constexpr char const* defaultProfilingResultsXmlPath =
"/data/misc/media/media_codecs_profiling_results.xml";
- MediaCodecsXmlParser(
- const char* const* searchDirs = defaultSearchDirs,
- const char* mainXmlName = defaultMainXmlName,
- const char* performanceXmlName = defaultPerformanceXmlName,
- const char* profilingResultsXmlPath = defaultProfilingResultsXmlPath);
+ MediaCodecsXmlParser();
~MediaCodecsXmlParser();
typedef std::pair<std::string, std::string> Attribute;
@@ -55,7 +52,7 @@
typedef std::pair<std::string, AttributeMap> Type;
typedef std::map<std::string, AttributeMap> TypeMap;
- typedef std::set<std::string> QuirkSet;
+ typedef std::set<std::string> StringSet;
/**
* Properties of a codec (node)
@@ -63,7 +60,9 @@
struct CodecProperties {
bool isEncoder; ///< Whether this codec is an encoder or a decoder
size_t order; ///< Order of appearance in the file (starting from 0)
- QuirkSet quirkSet; ///< Set of quirks requested by this codec
+ StringSet quirkSet; ///< Set of quirks requested by this codec
+ StringSet domainSet; ///< Set of domains this codec is in
+ StringSet variantSet; ///< Set of variants this codec is enabled on
TypeMap typeMap; ///< Map of types supported by this codec
std::vector<std::string> aliases; ///< Name aliases for this codec
std::string rank; ///< Rank of this codec. This is a numeric string.
@@ -119,70 +118,31 @@
status_t getParsingStatus() const;
+ /**
+ * Parse top level XML files from a group of search directories.
+ *
+ * @param xmlFiles ordered list of XML file names (no paths)
+ * @param searchDirs ordered list of paths to consider
+ *
+ * @return parsing status
+ */
+ status_t parseXmlFilesInSearchDirs(
+ const std::vector<std::string> &xmlFiles = getDefaultXmlNames(),
+ const std::vector<std::string> &searchDirs = getDefaultSearchDirs());
+
+
+ /**
+ * Parse a top level XML file.
+ *
+ * @param path XML file path
+ *
+ * @return parsing status
+ */
+ status_t parseXmlPath(const std::string &path);
+
private:
- enum Section {
- SECTION_TOPLEVEL,
- SECTION_SETTINGS,
- SECTION_DECODERS,
- SECTION_DECODER,
- SECTION_DECODER_TYPE,
- SECTION_ENCODERS,
- SECTION_ENCODER,
- SECTION_ENCODER_TYPE,
- SECTION_INCLUDE,
- };
-
- status_t mParsingStatus;
- Section mCurrentSection;
- bool mUpdate;
- std::vector<Section> mSectionStack;
- std::string mHrefBase;
-
- // Service attributes
- AttributeMap mServiceAttributeMap;
-
- // Codec attributes
- std::string mCurrentName;
- std::set<std::string> mCodecSet;
- Codec mCodecListTemp[2048];
- CodecMap mCodecMap;
- size_t mCodecCounter;
- CodecMap::iterator mCurrentCodec;
- TypeMap::iterator mCurrentType;
-
- // Role map
- mutable RoleMap mRoleMap;
-
- // Computed longest common prefix
- mutable std::string mCommonPrefix;
-
- bool parseTopLevelXMLFile(const char *path, bool ignore_errors = false);
-
- void parseXMLFile(const char *path);
-
- static void StartElementHandlerWrapper(
- void *me, const char *name, const char **attrs);
-
- static void EndElementHandlerWrapper(void *me, const char *name);
-
- void startElementHandler(const char *name, const char **attrs);
- void endElementHandler(const char *name);
-
- status_t includeXMLFile(const char **attrs);
- status_t addSettingFromAttributes(const char **attrs);
- status_t addMediaCodecFromAttributes(bool encoder, const char **attrs);
- void addMediaCodec(bool encoder, const char *name,
- const char *type = nullptr);
-
- status_t addQuirk(const char **attrs, const char *tag);
- status_t addTypeFromAttributes(const char **attrs, bool encoder);
- status_t addAlias(const char **attrs);
- status_t addLimit(const char **attrs);
- status_t addFeature(const char **attrs);
- void addType(const char *name);
-
- void generateRoleMap() const;
- void generateCommonPrefix() const;
+ struct Impl;
+ std::shared_ptr<Impl> mImpl;
MediaCodecsXmlParser(const MediaCodecsXmlParser&) = delete;
MediaCodecsXmlParser& operator=(const MediaCodecsXmlParser&) = delete;
@@ -191,4 +151,3 @@
} // namespace android
#endif // MEDIA_STAGEFRIGHT_XMLPARSER_H_
-
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index a48b733..7daa929 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3277,6 +3277,7 @@
Vector< sp<EffectChain> > effectChains;
audio_session_t activeHapticSessionId = AUDIO_SESSION_NONE;
+ std::vector<sp<Track>> activeTracks;
// If the device is AUDIO_DEVICE_OUT_BUS, check for downstream latency.
//
@@ -3563,6 +3564,12 @@
}
}
+ // Acquire a local copy of active tracks with lock (release w/o lock).
+ //
+ // Control methods on the track acquire the ThreadBase lock (e.g. start()
+ // stop(), pause(), etc.), but the threadLoop is entitled to call audio
+ // data / buffer methods on tracks from activeTracks without the ThreadBase lock.
+ activeTracks.insert(activeTracks.end(), mActiveTracks.begin(), mActiveTracks.end());
} // mLock scope ends
if (mBytesRemaining == 0) {
@@ -3577,6 +3584,13 @@
threadLoop_sleepTime();
if (mSleepTimeUs == 0) {
mCurrentWriteLength = mSinkBufferSize;
+
+ // Tally underrun frames as we are inserting 0s here.
+ for (const auto& track : activeTracks) {
+ if (track->mFillingUpStatus == Track::FS_ACTIVE) {
+ track->mAudioTrackServerProxy->tallyUnderrunFrames(mNormalFrameCount);
+ }
+ }
}
}
// Either threadLoop_mix() or threadLoop_sleepTime() should have set
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index 2d182bd..d906f11 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -112,6 +112,9 @@
static bool isBetterFormatMatch(audio_format_t newFormat,
audio_format_t currentFormat,
audio_format_t targetFormat);
+ static uint32_t formatDistance(audio_format_t format1,
+ audio_format_t format2);
+ static const uint32_t kFormatDistanceMax = 4;
audio_module_handle_t getModuleHandle() const;
uint32_t getModuleVersionMajor() const;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index a66c695..c11490a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -282,30 +282,25 @@
return index1 - index2;
}
+uint32_t AudioPort::formatDistance(audio_format_t format1, audio_format_t format2)
+{
+ if (format1 == format2) {
+ return 0;
+ }
+ if (format1 == AUDIO_FORMAT_INVALID || format2 == AUDIO_FORMAT_INVALID) {
+ return kFormatDistanceMax;
+ }
+ int diffBytes = (int)audio_bytes_per_sample(format1) -
+ audio_bytes_per_sample(format2);
+
+ return abs(diffBytes);
+}
+
bool AudioPort::isBetterFormatMatch(audio_format_t newFormat,
audio_format_t currentFormat,
audio_format_t targetFormat)
{
- if (newFormat == currentFormat) {
- return false;
- }
- if (currentFormat == AUDIO_FORMAT_INVALID) {
- return true;
- }
- if (newFormat == targetFormat) {
- return true;
- }
- int currentDiffBytes = (int)audio_bytes_per_sample(targetFormat) -
- audio_bytes_per_sample(currentFormat);
- int newDiffBytes = (int)audio_bytes_per_sample(targetFormat) -
- audio_bytes_per_sample(newFormat);
-
- if (abs(newDiffBytes) < abs(currentDiffBytes)) {
- return true;
- } else if (abs(newDiffBytes) == abs(currentDiffBytes)) {
- return (newDiffBytes >= 0);
- }
- return false;
+ return formatDistance(newFormat, targetFormat) < formatDistance(currentFormat, targetFormat);
}
void AudioPort::pickAudioProfile(uint32_t &samplingRate,
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index c0ca440..2dc7cad 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -36,12 +36,12 @@
#define AUDIO_POLICY_BLUETOOTH_LEGACY_HAL_XML_CONFIG_FILE_NAME \
"audio_policy_configuration_bluetooth_legacy_hal.xml"
+#include <algorithm>
#include <inttypes.h>
#include <math.h>
#include <set>
#include <unordered_set>
#include <vector>
-
#include <AudioPolicyManagerInterface.h>
#include <AudioPolicyEngineInstance.h>
#include <cutils/properties.h>
@@ -592,7 +592,7 @@
AUDIO_DEVICE_OUT_TELEPHONY_TX, String8(), AUDIO_FORMAT_DEFAULT);
SortedVector<audio_io_handle_t> outputs =
getOutputsForDevices(DeviceVector(outputDevice), mOutputs);
- audio_io_handle_t output = selectOutput(outputs, AUDIO_OUTPUT_FLAG_NONE, AUDIO_FORMAT_INVALID);
+ const audio_io_handle_t output = selectOutput(outputs);
// request to reuse existing output stream if one is already opened to reach the target device
if (output != AUDIO_IO_HANDLE_NONE) {
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
@@ -883,7 +883,7 @@
// and AudioSystem::getOutputSamplingRate().
SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, mOutputs);
- audio_io_handle_t output = selectOutput(outputs, AUDIO_OUTPUT_FLAG_NONE, AUDIO_FORMAT_INVALID);
+ const audio_io_handle_t output = selectOutput(outputs);
ALOGV("getOutput() stream %d selected devices %s, output %d", stream,
devices.toString().c_str(), output);
@@ -1430,108 +1430,125 @@
audio_channel_mask_t channelMask,
uint32_t samplingRate)
{
+ LOG_ALWAYS_FATAL_IF(!(format == AUDIO_FORMAT_INVALID || audio_is_linear_pcm(format)),
+ "%s called with format %#x", __func__, format);
+
+ // Flags disqualifying an output: the match must happen before calling selectOutput()
+ static const audio_output_flags_t kExcludedFlags = (audio_output_flags_t)
+ (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
+
+ // Flags expressing a functional request: must be honored in priority over
+ // other criteria
+ static const audio_output_flags_t kFunctionalFlags = (audio_output_flags_t)
+ (AUDIO_OUTPUT_FLAG_VOIP_RX | AUDIO_OUTPUT_FLAG_INCALL_MUSIC |
+ AUDIO_OUTPUT_FLAG_TTS | AUDIO_OUTPUT_FLAG_DIRECT_PCM);
+ // Flags expressing a performance request: have lower priority than serving
+ // requested sampling rate or channel mask
+ static const audio_output_flags_t kPerformanceFlags = (audio_output_flags_t)
+ (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_DEEP_BUFFER |
+ AUDIO_OUTPUT_FLAG_RAW | AUDIO_OUTPUT_FLAG_SYNC);
+
+ const audio_output_flags_t functionalFlags =
+ (audio_output_flags_t)(flags & kFunctionalFlags);
+ const audio_output_flags_t performanceFlags =
+ (audio_output_flags_t)(flags & kPerformanceFlags);
+
+ audio_io_handle_t bestOutput = (outputs.size() == 0) ? AUDIO_IO_HANDLE_NONE : outputs[0];
+
// select one output among several that provide a path to a particular device or set of
// devices (the list was previously build by getOutputsForDevices()).
// The priority is as follows:
// 1: the output supporting haptic playback when requesting haptic playback
- // 2: the output with the highest number of requested policy flags
- // 3: the output with the bit depth the closest to the requested one
- // 4: the primary output
- // 5: the first output in the list
+ // 2: the output with the highest number of requested functional flags
+ // 3: the output supporting the exact channel mask
+ // 4: the output with a higher channel count than requested
+ // 5: the output with a higher sampling rate than requested
+ // 6: the output with the highest number of requested performance flags
+ // 7: the output with the bit depth the closest to the requested one
+ // 8: the primary output
+ // 9: the first output in the list
- if (outputs.size() == 0) {
- return AUDIO_IO_HANDLE_NONE;
- }
- if (outputs.size() == 1) {
- return outputs[0];
- }
+ // matching criteria values in priority order for best matching output so far
+ std::vector<uint32_t> bestMatchCriteria(8, 0);
- int maxCommonFlags = 0;
- const size_t hapticChannelCount = audio_channel_count_from_out_mask(
- channelMask & AUDIO_CHANNEL_HAPTIC_ALL);
- audio_io_handle_t outputForFlags = AUDIO_IO_HANDLE_NONE;
- audio_io_handle_t outputForPrimary = AUDIO_IO_HANDLE_NONE;
- audio_io_handle_t outputForFormat = AUDIO_IO_HANDLE_NONE;
- audio_format_t bestFormat = AUDIO_FORMAT_INVALID;
- audio_format_t bestFormatForFlags = AUDIO_FORMAT_INVALID;
-
- // Flags which must be present on both the request and the selected output
- static const audio_output_flags_t kMandatedFlags = (audio_output_flags_t)
- (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ);
+ const uint32_t channelCount = audio_channel_count_from_out_mask(channelMask);
+ const uint32_t hapticChannelCount = audio_channel_count_from_out_mask(
+ channelMask & AUDIO_CHANNEL_HAPTIC_ALL);
for (audio_io_handle_t output : outputs) {
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
- if (!outputDesc->isDuplicated()) {
- if (outputDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
- continue;
- }
- // If haptic channel is specified, use the haptic output if present.
- // When using haptic output, same audio format and sample rate are required.
- if (hapticChannelCount > 0) {
- // If haptic channel is specified, use the first output that
- // support haptic playback.
- if (audio_channel_count_from_out_mask(
- outputDesc->mChannelMask & AUDIO_CHANNEL_HAPTIC_ALL) >= hapticChannelCount
- && format == outputDesc->mFormat
- && samplingRate == outputDesc->mSamplingRate) {
- return output;
- }
- } else {
- // When haptic channel is not specified, skip haptic output.
- if (outputDesc->mChannelMask & AUDIO_CHANNEL_HAPTIC_ALL) {
- continue;
- }
- }
- if ((kMandatedFlags & flags) !=
- (kMandatedFlags & outputDesc->mProfile->getFlags())) {
- continue;
- }
+ // matching criteria values in priority order for current output
+ std::vector<uint32_t> currentMatchCriteria(8, 0);
- // if a valid format is specified, skip output if not compatible
- if (format != AUDIO_FORMAT_INVALID) {
- if (!audio_is_linear_pcm(format)) {
- continue;
- }
- if (AudioPort::isBetterFormatMatch(
- outputDesc->mFormat, bestFormat, format)) {
- outputForFormat = output;
- bestFormat = outputDesc->mFormat;
- }
- }
+ if (outputDesc->isDuplicated()) {
+ continue;
+ }
+ if ((kExcludedFlags & outputDesc->mFlags) != 0) {
+ continue;
+ }
- int commonFlags = popcount(outputDesc->mProfile->getFlags() & flags);
- if (commonFlags >= maxCommonFlags) {
- if (commonFlags == maxCommonFlags) {
- if (format != AUDIO_FORMAT_INVALID
- && AudioPort::isBetterFormatMatch(
- outputDesc->mFormat, bestFormatForFlags, format)) {
- outputForFlags = output;
- bestFormatForFlags = outputDesc->mFormat;
- }
- } else {
- outputForFlags = output;
- maxCommonFlags = commonFlags;
- bestFormatForFlags = outputDesc->mFormat;
- }
- ALOGV("selectOutput() commonFlags for output %d, %04x", output, commonFlags);
+ // If haptic channel is specified, use the haptic output if present.
+ // When using haptic output, same audio format and sample rate are required.
+ const uint32_t outputHapticChannelCount = audio_channel_count_from_out_mask(
+ outputDesc->mChannelMask & AUDIO_CHANNEL_HAPTIC_ALL);
+ if ((hapticChannelCount == 0) != (outputHapticChannelCount == 0)) {
+ continue;
+ }
+ if (outputHapticChannelCount >= hapticChannelCount
+ && format == outputDesc->mFormat
+ && samplingRate == outputDesc->mSamplingRate) {
+ currentMatchCriteria[0] = outputHapticChannelCount;
+ }
+
+ // functional flags match
+ currentMatchCriteria[1] = popcount(outputDesc->mFlags & functionalFlags);
+
+ // channel mask and channel count match
+ uint32_t outputChannelCount = audio_channel_count_from_out_mask(outputDesc->mChannelMask);
+ if (channelMask != AUDIO_CHANNEL_NONE && channelCount > 2 &&
+ channelCount <= outputChannelCount) {
+ if ((audio_channel_mask_get_representation(channelMask) ==
+ audio_channel_mask_get_representation(outputDesc->mChannelMask)) &&
+ ((channelMask & outputDesc->mChannelMask) == channelMask)) {
+ currentMatchCriteria[2] = outputChannelCount;
}
- if (outputDesc->mProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
- outputForPrimary = output;
- }
+ currentMatchCriteria[3] = outputChannelCount;
+ }
+
+ // sampling rate match
+ if (samplingRate > SAMPLE_RATE_HZ_DEFAULT &&
+ samplingRate <= outputDesc->mSamplingRate) {
+ currentMatchCriteria[4] = outputDesc->mSamplingRate;
+ }
+
+ // performance flags match
+ currentMatchCriteria[5] = popcount(outputDesc->mFlags & performanceFlags);
+
+ // format match
+ if (format != AUDIO_FORMAT_INVALID) {
+ currentMatchCriteria[6] =
+ AudioPort::kFormatDistanceMax -
+ AudioPort::formatDistance(format, outputDesc->mFormat);
+ }
+
+ // primary output match
+ currentMatchCriteria[7] = outputDesc->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY;
+
+ // compare match criteria by priority then value
+ if (std::lexicographical_compare(bestMatchCriteria.begin(), bestMatchCriteria.end(),
+ currentMatchCriteria.begin(), currentMatchCriteria.end())) {
+ bestMatchCriteria = currentMatchCriteria;
+ bestOutput = output;
+
+ std::stringstream result;
+ std::copy(bestMatchCriteria.begin(), bestMatchCriteria.end(),
+ std::ostream_iterator<int>(result, " "));
+ ALOGV("%s new bestOutput %d criteria %s",
+ __func__, bestOutput, result.str().c_str());
}
}
- if (outputForFlags != AUDIO_IO_HANDLE_NONE) {
- return outputForFlags;
- }
- if (outputForFormat != AUDIO_IO_HANDLE_NONE) {
- return outputForFormat;
- }
- if (outputForPrimary != AUDIO_IO_HANDLE_NONE) {
- return outputForPrimary;
- }
-
- return outputs[0];
+ return bestOutput;
}
status_t AudioPolicyManager::startOutput(audio_port_handle_t portId)
@@ -3003,22 +3020,11 @@
status_t AudioPolicyManager::removeUidDeviceAffinities(uid_t uid) {
ALOGV("%s() uid=%d", __FUNCTION__, uid);
- Vector<AudioDeviceTypeAddr> devices;
- status_t res = mPolicyMixes.getDevicesForUid(uid, devices);
- if (res == NO_ERROR) {
- // reevaluate outputs for all found devices
- for (size_t i = 0; i < devices.size(); i++) {
- sp<DeviceDescriptor> devDesc = mHwModules.getDeviceDescriptor(
- devices[i].mType, devices[i].mAddress, String8(),
- AUDIO_FORMAT_DEFAULT);
- SortedVector<audio_io_handle_t> outputs;
- if (checkOutputsForDevice(devDesc, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
- outputs) != NO_ERROR) {
- ALOGE("%s() error in checkOutputsForDevice for device=%08x addr=%s",
- __FUNCTION__, devices[i].mType, devices[i].mAddress.string());
- return INVALID_OPERATION;
- }
- }
+ status_t res = mPolicyMixes.removeUidDeviceAffinities(uid);
+ if (res != NO_ERROR) {
+ ALOGE("%s() Could not remove all device affinities fo uid = %d",
+ __FUNCTION__, uid);
+ return INVALID_OPERATION;
}
return res;
@@ -3485,7 +3491,7 @@
getOutputsForDevices(DeviceVector(sinkDevice), mOutputs);
// if the sink device is reachable via an opened output stream, request to go via
// this output stream by adding a second source to the patch description
- audio_io_handle_t output = selectOutput(outputs);
+ const audio_io_handle_t output = selectOutput(outputs);
if (output != AUDIO_IO_HANDLE_NONE) {
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
if (outputDesc->isDuplicated()) {
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 415b2d8..f4abba4 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2522,6 +2522,9 @@
CLOGE("Stream %d is unknown", streamId);
return BAD_VALUE;
}
+
+ // isConsumerConfigurationDeferred will be off after setConsumers
+ bool isDeferred = stream->isConsumerConfigurationDeferred();
status_t res = stream->setConsumers(consumers);
if (res != OK) {
CLOGE("Stream %d set consumer failed (error %d %s) ", streamId, res, strerror(-res));
@@ -2537,7 +2540,7 @@
surfaceIds->push_back(id);
}
- if (stream->isConsumerConfigurationDeferred()) {
+ if (isDeferred) {
if (!stream->isConfiguring()) {
CLOGE("Stream %d was already fully configured.", streamId);
return INVALID_OPERATION;
@@ -2612,7 +2615,6 @@
sp<Camera3Device::CaptureRequest> Camera3Device::createCaptureRequest(
const PhysicalCameraSettingsList &request, const SurfaceMap &surfaceMap) {
ATRACE_CALL();
- status_t res;
sp<CaptureRequest> newRequest = new CaptureRequest;
newRequest->mSettingsList = request;
@@ -2626,16 +2628,11 @@
inputStreams.data.u8[0]);
return NULL;
}
- // Lazy completion of stream configuration (allocation/registration)
- // on first use
+
if (mInputStream->isConfiguring()) {
- res = mInputStream->finishConfiguration();
- if (res != OK) {
- SET_ERR_L("Unable to finish configuring input stream %d:"
- " %s (%d)",
- mInputStream->getId(), strerror(-res), res);
- return NULL;
- }
+ SET_ERR_L("%s: input stream %d is not configured!",
+ __FUNCTION__, mInputStream->getId());
+ return NULL;
}
// Check if stream prepare is blocking requests.
if (mInputStream->isBlockedByPrepare()) {
@@ -2675,15 +2672,9 @@
newRequest->mOutputSurfaces[streams.data.i32[i]] = surfaces;
}
- // Lazy completion of stream configuration (allocation/registration)
- // on first use
if (stream->isConfiguring()) {
- res = stream->finishConfiguration();
- if (res != OK) {
- SET_ERR_L("Unable to finish configuring stream %d: %s (%d)",
- stream->getId(), strerror(-res), res);
- return NULL;
- }
+ SET_ERR_L("%s: stream %d is not configured!", __FUNCTION__, stream->getId());
+ return NULL;
}
// Check if stream prepare is blocking requests.
if (stream->isBlockedByPrepare()) {
@@ -2908,7 +2899,8 @@
// faster
if (mInputStream != NULL && mInputStream->isConfiguring()) {
- res = mInputStream->finishConfiguration();
+ bool streamReConfigured = false;
+ res = mInputStream->finishConfiguration(&streamReConfigured);
if (res != OK) {
CLOGE("Can't finish configuring input stream %d: %s (%d)",
mInputStream->getId(), strerror(-res), res);
@@ -2918,12 +2910,16 @@
}
return BAD_VALUE;
}
+ if (streamReConfigured) {
+ mInterface->onStreamReConfigured(mInputStream->getId());
+ }
}
for (size_t i = 0; i < mOutputStreams.size(); i++) {
sp<Camera3OutputStreamInterface> outputStream = mOutputStreams[i];
if (outputStream->isConfiguring() && !outputStream->isConsumerConfigurationDeferred()) {
- res = outputStream->finishConfiguration();
+ bool streamReConfigured = false;
+ res = outputStream->finishConfiguration(&streamReConfigured);
if (res != OK) {
CLOGE("Can't finish configuring output stream %d: %s (%d)",
outputStream->getId(), strerror(-res), res);
@@ -2933,6 +2929,9 @@
}
return BAD_VALUE;
}
+ if (streamReConfigured) {
+ mInterface->onStreamReConfigured(outputStream->getId());
+ }
}
}
@@ -4780,7 +4779,7 @@
__FUNCTION__, handle, streamId);
return;
} else {
- bufferId = it->second;
+ bufferId = it->second;
bIdMap.erase(it);
ALOGV("%s: stream %d now have %zu buffer caches after removing buf %p",
__FUNCTION__, streamId, bIdMap.size(), handle);
@@ -4788,6 +4787,22 @@
mFreedBuffers.push_back(std::make_pair(streamId, bufferId));
}
+void Camera3Device::HalInterface::onStreamReConfigured(int streamId) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+ auto mapIt = mBufferIdMaps.find(streamId);
+ if (mapIt == mBufferIdMaps.end()) {
+ ALOGE("%s: streamId %d not found!", __FUNCTION__, streamId);
+ return;
+ }
+
+ BufferIdMap& bIdMap = mapIt->second;
+ for (const auto& it : bIdMap) {
+ uint64_t bufferId = it.second;
+ mFreedBuffers.push_back(std::make_pair(streamId, bufferId));
+ }
+ bIdMap.clear();
+}
+
/**
* RequestThread inner class methods
*/
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index f8245df..23df3c7 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -336,6 +336,8 @@
// Get a vector of bufferId of currently inflight buffers
void getInflightRequestBufferKeys(std::vector<uint64_t>* out);
+ void onStreamReConfigured(int streamId);
+
static const uint64_t BUFFER_ID_NO_BUFFER = 0;
private:
// Always valid
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 12ff130..d73a2f9 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -287,8 +287,11 @@
return (mState == STATE_IN_CONFIG) || (mState == STATE_IN_RECONFIG);
}
-status_t Camera3Stream::finishConfiguration() {
+status_t Camera3Stream::finishConfiguration(/*out*/bool* streamReconfigured) {
ATRACE_CALL();
+ if (streamReconfigured != nullptr) {
+ *streamReconfigured = false;
+ }
Mutex::Autolock l(mLock);
switch (mState) {
case STATE_ERROR:
@@ -313,7 +316,7 @@
// Register for idle tracking
sp<StatusTracker> statusTracker = mStatusTracker.promote();
- if (statusTracker != 0) {
+ if (statusTracker != 0 && mStatusId == StatusTracker::NO_STATUS_ID) {
mStatusId = statusTracker->addComponent();
}
@@ -332,6 +335,7 @@
mPrepareBlockRequest = true;
mStreamUnpreparable = false;
+ bool reconfiguring = (mState == STATE_IN_RECONFIG);
status_t res;
res = configureQueueLocked();
// configureQueueLocked could return error in case of abandoned surface.
@@ -348,6 +352,9 @@
return res;
}
+ if (reconfiguring && streamReconfigured != nullptr) {
+ *streamReconfigured = true;
+ }
mState = STATE_CONFIGURED;
return res;
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 3d21029..c916fe8 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -197,6 +197,8 @@
* after this call, but can still be read until the destruction of the
* stream.
*
+ * streamReconfigured: set to true when a stream is being reconfigured.
+ *
* Returns:
* OK on a successful configuration
* NO_INIT in case of a serious error from the HAL device
@@ -204,7 +206,7 @@
* INVALID_OPERATION in case connecting to the consumer failed or consumer
* doesn't exist yet.
*/
- status_t finishConfiguration();
+ status_t finishConfiguration(/*out*/bool* streamReconfigured = nullptr);
/**
* Cancels the stream configuration process. This returns the stream to the
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 5cd11b7..73f501a 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -130,13 +130,15 @@
* modified after this call, but can still be read until the destruction of
* the stream.
*
+ * streamReconfigured: set to true when a stream is being reconfigured.
+ *
* Returns:
* OK on a successful configuration
* NO_INIT in case of a serious error from the HAL device
* NO_MEMORY in case of an error registering buffers
* INVALID_OPERATION in case connecting to the consumer failed
*/
- virtual status_t finishConfiguration() = 0;
+ virtual status_t finishConfiguration(/*out*/bool* streamReconfigured = nullptr) = 0;
/**
* Cancels the stream configuration process. This returns the stream to the
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index 6ffbd26..f668c33 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -49,12 +49,6 @@
// Default codec services
using namespace ::android::hardware::media::omx::V1_0;
- sp<IOmxStore> omxStore = new implementation::OmxStore();
- if (omxStore == nullptr) {
- LOG(ERROR) << "Cannot create IOmxStore HAL service.";
- } else if (omxStore->registerAsService() != OK) {
- LOG(ERROR) << "Cannot register IOmxStore HAL service.";
- }
sp<IOmx> omx = new implementation::Omx();
if (omx == nullptr) {
LOG(ERROR) << "Cannot create IOmx HAL service.";
@@ -63,6 +57,12 @@
} else {
LOG(INFO) << "IOmx HAL service created.";
}
+ sp<IOmxStore> omxStore = new implementation::OmxStore(omx);
+ if (omxStore == nullptr) {
+ LOG(ERROR) << "Cannot create IOmxStore HAL service.";
+ } else if (omxStore->registerAsService() != OK) {
+ LOG(ERROR) << "Cannot register IOmxStore HAL service.";
+ }
::android::hardware::joinRpcThreadpool();
}
diff --git a/services/mediaextractor/Android.bp b/services/mediaextractor/Android.bp
new file mode 100644
index 0000000..b812244
--- /dev/null
+++ b/services/mediaextractor/Android.bp
@@ -0,0 +1,71 @@
+// service library
+cc_library_shared {
+ name: "libmediaextractorservice",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ srcs: ["MediaExtractorService.cpp"],
+
+ shared_libs: [
+ "libmedia",
+ "libstagefright",
+ "libbinder",
+ "libutils",
+ ],
+}
+
+// service executable
+cc_binary {
+ name: "mediaextractor",
+
+ srcs: ["main_extractorservice.cpp"],
+ shared_libs: [
+ "libmedia",
+ "libmediaextractorservice",
+ "libbinder",
+ "libutils",
+ "liblog",
+ "libavservices_minijail",
+ ],
+ target: {
+ android: {
+ product_variables: {
+ malloc_not_svelte: {
+ // Scudo increases memory footprint, so only enable on
+ // non-svelte devices.
+ shared_libs: ["libc_scudo"],
+ },
+ },
+ },
+ },
+ init_rc: ["mediaextractor.rc"],
+
+ include_dirs: ["frameworks/av/media/libmedia"],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
+
+prebuilt_etc {
+ name: "mediaextractor.policy",
+ sub_dir: "seccomp_policy",
+ arch: {
+ arm: {
+ src: "seccomp_policy/mediaextractor-arm.policy",
+ },
+ arm64: {
+ src: "seccomp_policy/mediaextractor-arm64.policy",
+ },
+ x86: {
+ src: "seccomp_policy/mediaextractor-x86.policy",
+ },
+ x86_64: {
+ src: "seccomp_policy/mediaextractor-x86_64.policy",
+ },
+ },
+ required: ["crash_dump.policy"],
+}
+
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
deleted file mode 100644
index 9db6ed1..0000000
--- a/services/mediaextractor/Android.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-# service library
-include $(CLEAR_VARS)
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_SRC_FILES := \
- MediaExtractorService.cpp
-
-LOCAL_SHARED_LIBRARIES := libmedia libstagefright libbinder libutils
-LOCAL_MODULE:= libmediaextractorservice
-include $(BUILD_SHARED_LIBRARY)
-
-
-# service executable
-include $(CLEAR_VARS)
-# seccomp filters are defined for the following architectures:
-LOCAL_REQUIRED_MODULES_arm := crash_dump.policy mediaextractor.policy
-LOCAL_REQUIRED_MODULES_arm64 := crash_dump.policy mediaextractor.policy
-LOCAL_REQUIRED_MODULES_x86 := crash_dump.policy mediaextractor.policy
-LOCAL_REQUIRED_MODULES_x86_64 := crash_dump.policy mediaextractor.policy
-
-LOCAL_SRC_FILES := main_extractorservice.cpp
-ifneq (true, $(filter true, $(MALLOC_SVELTE)))
-# Scudo increases memory footprint, so only use on non-svelte configs.
-LOCAL_SHARED_LIBRARIES := libc_scudo
-endif
-LOCAL_SHARED_LIBRARIES += libmedia libmediaextractorservice libbinder libutils \
- liblog libandroidicu libavservices_minijail
-LOCAL_MODULE:= mediaextractor
-LOCAL_INIT_RC := mediaextractor.rc
-LOCAL_C_INCLUDES := frameworks/av/media/libmedia
-LOCAL_CFLAGS := -Wall -Werror
-include $(BUILD_EXECUTABLE)
-
-# service seccomp filter
-ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64 x86 x86_64))
-include $(CLEAR_VARS)
-LOCAL_MODULE := mediaextractor.policy
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
-LOCAL_SRC_FILES := seccomp_policy/mediaextractor-$(TARGET_ARCH).policy
-include $(BUILD_PREBUILT)
-endif
diff --git a/services/mediaextractor/main_extractorservice.cpp b/services/mediaextractor/main_extractorservice.cpp
index bb9a56b..3c4125b 100644
--- a/services/mediaextractor/main_extractorservice.cpp
+++ b/services/mediaextractor/main_extractorservice.cpp
@@ -15,7 +15,6 @@
** limitations under the License.
*/
-#include <aicu/AIcu.h>
#include <fcntl.h>
#include <sys/prctl.h>
#include <sys/wait.h>
@@ -37,7 +36,7 @@
using namespace android;
static const char kSystemSeccompPolicyPath[] =
- "/system/etc/seccomp_policy/mediaextractor.policy";
+ "/apex/com.android.media/etc/seccomp_policy/mediaextractor.policy";
static const char kVendorSeccompPolicyPath[] =
"/vendor/etc/seccomp_policy/mediaextractor.policy";
@@ -58,8 +57,6 @@
SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
- AIcu_initializeIcuOrDie();
-
strcpy(argv[0], "media.extractor");
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();