xref: /aosp_15_r20/frameworks/av/media/libstagefright/xmlparser/test/XMLParserTest.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "XMLParserTest"
19 
20 #include <utils/Log.h>
21 
22 #include <fstream>
23 
24 #include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
25 
26 #include "XMLParserTestEnvironment.h"
27 
28 #define XML_FILE_NAME "media_codecs_unit_test_caller.xml"
29 
30 using namespace android;
31 
32 static XMLParserTestEnvironment *gEnv = nullptr;
33 
34 struct CodecProperties {
35     string codecName;
36     MediaCodecsXmlParser::CodecProperties codecProp;
37 };
38 
39 struct RoleProperties {
40     string roleName;
41     string typeName;
42     string codecName;
43     bool isEncoder;
44     size_t order;
45     vector<pair<string, string>> attributeMap;
46 };
47 
48 class XMLParseTest : public ::testing::Test {
49   public:
~XMLParseTest()50     ~XMLParseTest() {
51         if (mEleStream.is_open()) mEleStream.close();
52         mInputDataVector.clear();
53         mInputRoleVector.clear();
54     }
55 
SetUp()56     virtual void SetUp() override { setUpDatabase(); }
57 
58     void setUpDatabase();
59 
60     void setCodecProperties(string codecName, bool isEncoder, int32_t order, set<string> quirkSet,
61                             set<string> domainSet, set<string> variantSet, string typeName,
62                             vector<pair<string, string>> domain, vector<string> aliases,
63                             string rank);
64 
65     void setRoleProperties(string roleName, bool isEncoder, int32_t order, string typeName,
66                            string codecName, vector<pair<string, string>> domain);
67 
68     void setServiceAttribute(map<string, string> serviceAttributeNameValuePair);
69 
70     void printCodecMap(const MediaCodecsXmlParser::Codec mcodec);
71 
72     void checkRoleMap(int32_t index, bool isEncoder, string typeName, string codecName,
73                       vector<pair<string, string>> attrMap);
74 
75     bool compareMap(const map<string, string> &lhs, const map<string, string> &rhs);
76 
77     ifstream mEleStream;
78     MediaCodecsXmlParser mParser;
79     vector<CodecProperties> mInputDataVector;
80     vector<RoleProperties> mInputRoleVector;
81     map<string, string> mInputServiceAttributeMap;
82 };
83 
setUpDatabase()84 void XMLParseTest::setUpDatabase() {
85     // The values set below are specific to test vector testdata/media_codecs_unit_test.xml
86     setCodecProperties("test1.decoder", false, 1, {"attribute::disabled", "quirk::quirk1"},
87                        {"telephony"}, {}, "audio/mpeg", {}, {"alias1.decoder"}, "4");
88 
89     setCodecProperties("test2.decoder", false, 2, {"quirk::quirk1"}, {}, {}, "audio/3gpp", {}, {},
90                        "");
91 
92     setCodecProperties("test3.decoder", false, 3, {}, {}, {}, "audio/amr-wb",
93                        {
94                                pair<string, string>("feature-feature1", "feature1Val"),
95                                pair<string, string>("feature-feature2", "0"),
96                                pair<string, string>("feature-feature3", "0"),
97                        },
98                        {}, "");
99 
100     setCodecProperties("test4.decoder", false, 4, {}, {}, {}, "audio/flac",
101                        {pair<string, string>("feature-feature1", "feature1Val")}, {}, "");
102 
103     setCodecProperties("test5.decoder", false, 5, {"attribute::attributeQuirk1"}, {}, {},
104                        "audio/g711-mlaw", {}, {}, "");
105 
106     setCodecProperties("test6.decoder", false, 6, {}, {}, {"variant1", "variant2"},
107                        "audio/mp4a-latm",
108                        {pair<string, string>("variant1:::variant1Limit1-range",
109                                              "variant1Limit1Min-variant1Limit1Max"),
110                         pair<string, string>("variant1:::variant1Limit2-range",
111                                              "variant1Limit2Low-variant1Limit2High"),
112                         pair<string, string>("variant2:::variant2Limit1", "variant2Limit1Value")},
113                        {}, "");
114 
115     setCodecProperties(
116             "test7.decoder", false, 7, {}, {}, {}, "audio/vorbis",
117             {
118                     pair<string, string>("-min-limit1", "limit1Min"),
119                     /*pair<string, string>("limit1-in", "limit1In"),*/
120                     pair<string, string>("limit2-range", "limit2Min-limit2Max"),
121                     pair<string, string>("limit2-scale", "limit2Scale"),
122                     pair<string, string>("limit3-default", "limit3Val3"),
123                     pair<string, string>("limit3-ranges", "limit3Val1,limit3Val2,limit3Val3"),
124             },
125             {}, "");
126 
127     setCodecProperties("test8.encoder", true, 8, {}, {}, {}, "audio/opus",
128                        {pair<string, string>("max-limit1", "limit1Max")}, {}, "");
129 
130     setCodecProperties("test9.encoder", true, 9, {}, {}, {}, "video/avc",
131            {
132                    pair<string, string>("mapping-sure-before", "after"),
133            },
134            {}, "");
135 
136     setCodecProperties("test10.encoder", true, 10, {}, {}, {}, "video/hevc",
137            {
138                    pair<string, string>("mapping-fire-from", "to"),
139            },
140            {}, "");
141     setCodecProperties("test11.encoder", true, 11, {}, {}, {}, "video/av01",
142            {
143                    pair<string, string>("tuning-hungry", "yes"),
144                    pair<string, string>("tuning-pi", "3.1415"),
145            },
146            {}, "");
147 
148     // minsdk
149     setCodecProperties("test12.encoder", true, 12, {"attribute::disabled"}, {}, {}, "video/t12",
150            {
151                    pair<string, string>("tuning-enable-goal", "no"),
152            },
153            {}, "");
154     setCodecProperties("test13.encoder", true, 13, {"attribute::disabled"}, {}, {}, "video/t13",
155            {
156                    pair<string, string>("tuning-enable-goal", "no"),
157            },
158            {}, "");
159     setCodecProperties("test14.encoder", true, 14, {"attribute::disabled"}, {}, {}, "video/t14",
160            {
161                    pair<string, string>("tuning-enable-goal", "no"),
162            },
163            {}, "");
164     setCodecProperties("test15.encoder", true, 15, {}, {}, {}, "video/t15",
165            {
166                    pair<string, string>("tuning-enable-goal", "yes"),
167            },
168            {}, "");
169     setCodecProperties("test16.encoder", true, 16, {}, {}, {}, "video/t16",
170            {
171                    pair<string, string>("tuning-enable-goal", "yes"),
172            },
173            {}, "");
174 
175     setRoleProperties("audio_decoder.mp3", false, 1, "audio/mpeg", "test1.decoder",
176                       {pair<string, string>("attribute::disabled", "present"),
177                        pair<string, string>("rank", "4")});
178 
179     setRoleProperties("audio_decoder.amrnb", false, 2, "audio/3gpp", "test2.decoder", {});
180 
181     setRoleProperties("audio_decoder.amrwb", false, 3, "audio/amr-wb", "test3.decoder",
182                       {pair<string, string>("feature-feature1", "feature1Val"),
183                        pair<string, string>("feature-feature2", "0"),
184                        pair<string, string>("feature-feature3", "0")});
185 
186     setRoleProperties("audio/flac", false, 4, "audio/flac", "test4.decoder",
187                       {pair<string, string>("feature-feature1", "feature1Val")});
188 
189     setRoleProperties("audio_decoder.g711mlaw", false, 5, "audio/g711-mlaw", "test5.decoder",
190                       {pair<string, string>("attribute::attributeQuirk1", "present")});
191 
192     setRoleProperties("audio_decoder.aac", false, 6, "audio/mp4a-latm", "test6.decoder",
193                       {pair<string, string>("variant1:::variant1Limit1-range",
194                                             "variant1Limit1Min-variant1Limit1Max"),
195                        pair<string, string>("variant1:::variant1Limit2-range",
196                                             "variant1Limit2Low-variant1Limit2High"),
197                        pair<string, string>("variant2:::variant2Limit1", "variant2Limit1Value")});
198 
199     setRoleProperties("audio_decoder.vorbis", false, 7, "audio/vorbis", "test7.decoder",
200                       {pair<string, string>("-min-limit1", "limit1Min"),
201                        /*pair<string, string>("limit1-in", "limit1In"),*/
202                        pair<string, string>("limit2-range", "limit2Min-limit2Max"),
203                        pair<string, string>("limit2-scale", "limit2Scale"),
204                        pair<string, string>("limit3-default", "limit3Val3"),
205                        pair<string, string>("limit3-ranges", "limit3Val1,limit3Val2,limit3Val3")});
206 
207     setRoleProperties("audio_encoder.opus", true, 8, "audio/opus", "test8.encoder",
208                       {pair<string, string>("max-limit1", "limit1Max")});
209 
210     setRoleProperties("video_encoder.avc", true, 9, "video/avc", "test9.encoder",
211                        {pair<string, string>("mapping-sure-before", "after")});
212 
213     setRoleProperties("video_encoder.hevc", true, 10, "video/hevc", "test10.encoder",
214                        { pair<string, string>("mapping-fire-from", "to")});
215 
216     setRoleProperties("video_encoder.av01", true, 11, "video/av01", "test11.encoder",
217                        {pair<string, string>("tuning-hungry", "yes"),
218                         pair<string, string>("tuning-pi", "3.1415")
219                        });
220 
221     // minsdk
222     setRoleProperties("video_encoder.t12", true, 12, "video/t12", "test12.encoder",
223                        {pair<string, string>("tuning-enable-goal", "no"),
224                         pair<string, string>("attribute::disabled", "present") });
225     setRoleProperties("video_encoder.t13", true, 13, "video/t13", "test13.encoder",
226                        {pair<string, string>("tuning-enable-goal", "no"),
227                         pair<string, string>("attribute::disabled", "present") });
228     setRoleProperties("video_encoder.t14", true, 14, "video/t14", "test14.encoder",
229                        {pair<string, string>("tuning-enable-goal", "no"),
230                         pair<string, string>("attribute::disabled", "present") });
231     setRoleProperties("video_encoder.t15", true, 15, "video/t15", "test15.encoder",
232                        {pair<string, string>("tuning-enable-goal", "yes")});
233     setRoleProperties("video_encoder.t16", true, 16, "video/t16", "test16.encoder",
234                        {pair<string, string>("tuning-enable-goal", "yes")});
235 
236 
237     setServiceAttribute(
238             {pair<string, string>("domain-telephony", "0"), pair<string, string>("domain-tv", "0"),
239              pair<string, string>("setting2", "0"), pair<string, string>("variant-variant1", "0")});
240 }
241 
compareMap(const map<string,string> & lhs,const map<string,string> & rhs)242 bool XMLParseTest::compareMap(const map<string, string> &lhs, const map<string, string> &rhs) {
243     return lhs.size() == rhs.size() && equal(lhs.begin(), lhs.end(), rhs.begin());
244 }
245 
setCodecProperties(string codecName,bool isEncoder,int32_t order,set<string> quirkSet,set<string> domainSet,set<string> variantSet,string typeName,vector<pair<string,string>> domain,vector<string> aliases,string rank)246 void XMLParseTest::setCodecProperties(string codecName, bool isEncoder, int32_t order,
247                                       set<string> quirkSet, set<string> domainSet,
248                                       set<string> variantSet, string typeName,
249                                       vector<pair<string, string>> domain, vector<string> aliases,
250                                       string rank) {
251     map<string, string> AttributeMapDB;
252     for (const auto &AttrStr : domain) {
253         AttributeMapDB.insert(AttrStr);
254     }
255     map<string, MediaCodecsXmlParser::AttributeMap> TypeMapDataBase;
256     TypeMapDataBase.insert(
257             pair<string, MediaCodecsXmlParser::AttributeMap>(typeName, AttributeMapDB));
258     CodecProperties codecProperty;
259     codecProperty.codecName = codecName;
260     codecProperty.codecProp.isEncoder = isEncoder;
261     codecProperty.codecProp.order = order;
262     codecProperty.codecProp.quirkSet = quirkSet;
263     codecProperty.codecProp.domainSet = domainSet;
264     codecProperty.codecProp.variantSet = variantSet;
265     codecProperty.codecProp.typeMap = TypeMapDataBase;
266     codecProperty.codecProp.aliases = aliases;
267     codecProperty.codecProp.rank = rank;
268     mInputDataVector.push_back(codecProperty);
269 }
270 
setRoleProperties(string roleName,bool isEncoder,int32_t order,string typeName,string codecName,vector<pair<string,string>> attributeNameValuePair)271 void XMLParseTest::setRoleProperties(string roleName, bool isEncoder, int32_t order,
272                                      string typeName, string codecName,
273                                      vector<pair<string, string>> attributeNameValuePair) {
274     struct RoleProperties roleProperty;
275     roleProperty.roleName = roleName;
276     roleProperty.typeName = typeName;
277     roleProperty.codecName = codecName;
278     roleProperty.isEncoder = isEncoder;
279     roleProperty.order = order;
280     roleProperty.attributeMap = attributeNameValuePair;
281     mInputRoleVector.push_back(roleProperty);
282 }
283 
setServiceAttribute(map<string,string> serviceAttributeNameValuePair)284 void XMLParseTest::setServiceAttribute(map<string, string> serviceAttributeNameValuePair) {
285     for (const auto &serviceAttrStr : serviceAttributeNameValuePair) {
286         mInputServiceAttributeMap.insert(serviceAttrStr);
287     }
288 }
289 
printCodecMap(const MediaCodecsXmlParser::Codec mcodec)290 void XMLParseTest::printCodecMap(const MediaCodecsXmlParser::Codec mcodec) {
291     const string &name = mcodec.first;
292     ALOGV("codec name = %s\n", name.c_str());
293     const MediaCodecsXmlParser::CodecProperties &properties = mcodec.second;
294     bool isEncoder = properties.isEncoder;
295     ALOGV("isEncoder = %d\n", isEncoder);
296     size_t order = properties.order;
297     ALOGV("order = %zu\n", order);
298     string rank = properties.rank;
299     ALOGV("rank = %s\n", rank.c_str());
300 
301     for (auto &itrQuirkSet : properties.quirkSet) {
302         ALOGV("quirkSet= %s", itrQuirkSet.c_str());
303     }
304 
305     for (auto &itrDomainSet : properties.domainSet) {
306         ALOGV("domainSet= %s", itrDomainSet.c_str());
307     }
308 
309     for (auto &itrVariantSet : properties.variantSet) {
310         ALOGV("variantSet= %s", itrVariantSet.c_str());
311     }
312 
313     map<string, MediaCodecsXmlParser::AttributeMap> TypeMap = properties.typeMap;
314     ALOGV("The TypeMap is :");
315 
316     for (auto &itrTypeMap : TypeMap) {
317         ALOGV("itrTypeMap->first\t%s\t", itrTypeMap.first.c_str());
318 
319         for (auto &itrAttributeMap : itrTypeMap.second) {
320             ALOGV("AttributeMap->first = %s", itrAttributeMap.first.c_str());
321             ALOGV("AttributeMap->second = %s", itrAttributeMap.second.c_str());
322         }
323     }
324 }
325 
checkRoleMap(int32_t index,bool isEncoder,string typeName,string codecName,vector<pair<string,string>> AttributePairMap)326 void XMLParseTest::checkRoleMap(int32_t index, bool isEncoder, string typeName, string codecName,
327                                 vector<pair<string, string>> AttributePairMap) {
328     ASSERT_EQ(isEncoder, mInputRoleVector.at(index).isEncoder)
329             << "Invalid RoleMap data. IsEncoder mismatch";
330     ASSERT_EQ(typeName, mInputRoleVector.at(index).typeName)
331             << "Invalid RoleMap data. typeName mismatch";
332     ASSERT_EQ(codecName, mInputRoleVector.at(index).codecName)
333             << "Invalid RoleMap data. codecName mismatch";
334 
335     vector<pair<string, string>>::iterator itr_attributeMapDB =
336             (mInputRoleVector.at(index).attributeMap).begin();
337     vector<pair<string, string>>::iterator itr_attributeMap = AttributePairMap.begin();
338     for (; itr_attributeMap != AttributePairMap.end() &&
339            itr_attributeMapDB != mInputRoleVector.at(index).attributeMap.end();
340          ++itr_attributeMap, ++itr_attributeMapDB) {
341         string attributeName = itr_attributeMap->first;
342         string attributeNameDB = itr_attributeMapDB->first;
343         string attributevalue = itr_attributeMap->second;
344         string attributeValueDB = itr_attributeMapDB->second;
345         ASSERT_EQ(attributeName, attributeNameDB)
346                 << "Invalid RoleMap data. Attribute name mismatch\t" << attributeName << " != "
347                 << "attributeNameDB";
348         ASSERT_EQ(attributevalue, attributeValueDB)
349                 << "Invalid RoleMap data. Attribute value mismatch\t" << attributevalue << " != "
350                 << "attributeValueDB";
351     }
352 }
353 
TEST_F(XMLParseTest,CodecMapParseTest)354 TEST_F(XMLParseTest, CodecMapParseTest) {
355     string inputFileName = gEnv->getRes() + XML_FILE_NAME;
356     mEleStream.open(inputFileName, ifstream::binary);
357     ASSERT_EQ(mEleStream.is_open(), true) << "Failed to open inputfile " << inputFileName;
358 
359     mParser.parseXmlPath(inputFileName);
360     for (const MediaCodecsXmlParser::Codec &mcodec : mParser.getCodecMap()) {
361         printCodecMap(mcodec);
362         const MediaCodecsXmlParser::CodecProperties &properties = mcodec.second;
363         int32_t index = properties.order - 1;
364         ASSERT_GE(index, 0) << "Invalid order";
365         ASSERT_EQ(mInputDataVector.at(index).codecName, mcodec.first.c_str())
366                 << "Invalid CodecMap data. codecName mismatch";
367         ASSERT_EQ(properties.isEncoder, mInputDataVector.at(index).codecProp.isEncoder)
368                 << "Invalid CodecMap data. isEncoder mismatch";
369         ASSERT_EQ(properties.order, mInputDataVector.at(index).codecProp.order)
370                 << "Invalid CodecMap data. order mismatch";
371 
372         set<string> quirkSetDB = mInputDataVector.at(index).codecProp.quirkSet;
373         set<string> quirkSet = properties.quirkSet;
374         set<string> quirkDifference;
375         set_difference(quirkSetDB.begin(), quirkSetDB.end(), quirkSet.begin(), quirkSet.end(),
376                        inserter(quirkDifference, quirkDifference.end()));
377         ASSERT_EQ(quirkDifference.size(), 0) << "CodecMap:quirk mismatch";
378 
379         map<string, MediaCodecsXmlParser::AttributeMap> TypeMapDB =
380                 mInputDataVector.at(index).codecProp.typeMap;
381         map<string, MediaCodecsXmlParser::AttributeMap> TypeMap = properties.typeMap;
382         map<string, MediaCodecsXmlParser::AttributeMap>::iterator itr_TypeMapDB = TypeMapDB.begin();
383         map<string, MediaCodecsXmlParser::AttributeMap>::iterator itr_TypeMap = TypeMap.begin();
384 
385         ASSERT_EQ(TypeMapDB.size(), TypeMap.size())
386                 << "Invalid CodecMap data. Typemap size mismatch";
387 
388         for (; itr_TypeMap != TypeMap.end() && itr_TypeMapDB != TypeMapDB.end();
389              ++itr_TypeMap, ++itr_TypeMapDB) {
390             ASSERT_EQ(itr_TypeMap->first, itr_TypeMapDB->first)
391                     << "Invalid CodecMap data. type mismatch";
392             bool flag = compareMap(itr_TypeMap->second, itr_TypeMapDB->second);
393             ASSERT_TRUE(flag) << "typeMap mismatch";
394         }
395         ASSERT_EQ(mInputDataVector.at(index).codecProp.rank, properties.rank)
396                 << "Invalid CodecMap data. rank mismatch";
397     }
398 }
399 
TEST_F(XMLParseTest,RoleMapParseTest)400 TEST_F(XMLParseTest, RoleMapParseTest) {
401     string inputFileName = gEnv->getRes() + XML_FILE_NAME;
402     mEleStream.open(inputFileName, ifstream::binary);
403     ASSERT_EQ(mEleStream.is_open(), true) << "Failed to open inputfile " << inputFileName;
404 
405     mParser.parseXmlPath(inputFileName);
406 
407     for (auto &mRole : mParser.getRoleMap()) {
408         typedef pair<string, string> Attribute;
409         const string &roleName = mRole.first;
410         ALOGV("Role map:name = %s\n", roleName.c_str());
411         const MediaCodecsXmlParser::RoleProperties &properties = mRole.second;
412         string type = properties.type;
413         ALOGV("Role map: type = %s\n", type.c_str());
414 
415         bool isEncoder = properties.isEncoder;
416         ALOGV("Role map: isEncoder = %d\n", isEncoder);
417 
418         multimap<size_t, MediaCodecsXmlParser::NodeInfo> nodeList = properties.nodeList;
419         multimap<size_t, MediaCodecsXmlParser::NodeInfo>::iterator itr_Node;
420         ALOGV("\nThe multimap nodeList is : \n");
421         for (itr_Node = nodeList.begin(); itr_Node != nodeList.end(); ++itr_Node) {
422             ALOGV("itr_Node->first=ORDER=\t%zu\t", itr_Node->first);
423             int32_t index = itr_Node->first - 1;
424             MediaCodecsXmlParser::NodeInfo nodePtr = itr_Node->second;
425             ALOGV("Role map:itr_Node->second.name = %s\n", nodePtr.name.c_str());
426             vector<Attribute> attrList = nodePtr.attributeList;
427             for (auto attrNameValueList = attrList.begin(); attrNameValueList != attrList.end();
428                  ++attrNameValueList) {
429                 ALOGV("Role map:nodePtr.attributeList->first = %s\n",
430                       attrNameValueList->first.c_str());
431                 ALOGV("Role map:nodePtr.attributeList->second = %s\n",
432                       attrNameValueList->second.c_str());
433             }
434             checkRoleMap(index, isEncoder, properties.type, nodePtr.name.c_str(), attrList);
435         }
436     }
437 }
438 
TEST_F(XMLParseTest,ServiceAttributeMapParseTest)439 TEST_F(XMLParseTest, ServiceAttributeMapParseTest) {
440     string inputFileName = gEnv->getRes() + XML_FILE_NAME;
441     mEleStream.open(inputFileName, ifstream::binary);
442     ASSERT_EQ(mEleStream.is_open(), true) << "Failed to open inputfile " << inputFileName;
443 
444     mParser.parseXmlPath(inputFileName);
445     const auto serviceAttributeMap = mParser.getServiceAttributeMap();
446     for (const auto &attributePair : serviceAttributeMap) {
447         ALOGV("serviceAttribute.key = %s \t serviceAttribute.value = %s",
448               attributePair.first.c_str(), attributePair.second.c_str());
449     }
450     bool flag = compareMap(mInputServiceAttributeMap, serviceAttributeMap);
451     ASSERT_TRUE(flag) << "ServiceMapParseTest: typeMap mismatch";
452 }
453 
main(int argc,char ** argv)454 int main(int argc, char **argv) {
455     gEnv = new XMLParserTestEnvironment();
456     ::testing::AddGlobalTestEnvironment(gEnv);
457     ::testing::InitGoogleTest(&argc, argv);
458     int status = gEnv->initFromOptions(argc, argv);
459     if (status == 0) {
460         status = RUN_ALL_TESTS();
461         ALOGD("XML Parser Test Result = %d\n", status);
462     }
463     return status;
464 }
465