• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "CodecListTest"
19 #include <utils/Log.h>
20 
21 #include <gtest/gtest.h>
22 
23 #include <binder/Parcel.h>
24 #include <media/stagefright/MediaCodecConstants.h>
25 #include <media/stagefright/MediaCodecList.h>
26 #include <media/stagefright/foundation/ABuffer.h>
27 #include <media/stagefright/foundation/AString.h>
28 #include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
29 
30 #define kSwCodecXmlPath "/apex/com.android.media.swcodec/etc/"
31 
32 using namespace android;
33 
34 struct CddReq {
CddReqCddReq35     CddReq(const char *type, bool encoder) {
36         mediaType = type;
37         isEncoder = encoder;
38     }
39 
40     const char *mediaType;
41     bool isEncoder;
42 };
43 
TEST(CodecListTest,CodecListSanityTest)44 TEST(CodecListTest, CodecListSanityTest) {
45     sp<IMediaCodecList> list = MediaCodecList::getInstance();
46     ASSERT_NE(list, nullptr) << "Unable to get MediaCodecList instance.";
47     EXPECT_GT(list->countCodecs(), 0) << "No codecs in CodecList";
48     for (size_t i = 0; i < list->countCodecs(); ++i) {
49         sp<MediaCodecInfo> info = list->getCodecInfo(i);
50         ASSERT_NE(info, nullptr) << "CodecInfo is null";
51         ssize_t index = list->findCodecByName(info->getCodecName());
52         EXPECT_GE(index, 0) << "Wasn't able to find existing codec: " << info->getCodecName();
53     }
54 }
55 
TEST(CodecListTest,CodecListByTypeTest)56 TEST(CodecListTest, CodecListByTypeTest) {
57     sp<IMediaCodecList> list = MediaCodecList::getInstance();
58     ASSERT_NE(list, nullptr) << "Unable to get MediaCodecList instance.";
59 
60     std::vector<CddReq> cddReq{
61             // media type, isEncoder
62             CddReq(MIMETYPE_AUDIO_AAC, false),
63             CddReq(MIMETYPE_AUDIO_AAC, true),
64 
65             CddReq(MIMETYPE_VIDEO_AVC, false),
66             CddReq(MIMETYPE_VIDEO_HEVC, false),
67             CddReq(MIMETYPE_VIDEO_MPEG4, false),
68             CddReq(MIMETYPE_VIDEO_VP8, false),
69             CddReq(MIMETYPE_VIDEO_VP9, false),
70 
71             CddReq(MIMETYPE_VIDEO_AVC, true),
72             CddReq(MIMETYPE_VIDEO_VP8, true),
73     };
74 
75     for (CddReq codecReq : cddReq) {
76         ssize_t index = list->findCodecByType(codecReq.mediaType, codecReq.isEncoder);
77         EXPECT_GE(index, 0) << "Wasn't able to find codec for media type: " << codecReq.mediaType
78                             << (codecReq.isEncoder ? " encoder" : " decoder");
79     }
80 }
81 
TEST(CodecInfoTest,ListInfoTest)82 TEST(CodecInfoTest, ListInfoTest) {
83     ALOGV("Compare CodecInfo with info in XML");
84     MediaCodecsXmlParser parser;
85     status_t status = parser.parseXmlFilesInSearchDirs();
86     ASSERT_EQ(status, OK) << "XML Parsing failed for default paths";
87 
88     const std::vector<std::string> &xmlFiles = MediaCodecsXmlParser::getDefaultXmlNames();
89     const std::vector<std::string> &searchDirsApex{std::string(kSwCodecXmlPath)};
90     status = parser.parseXmlFilesInSearchDirs(xmlFiles, searchDirsApex);
91     ASSERT_EQ(status, OK) << "XML Parsing of " << kSwCodecXmlPath << " failed";
92 
93     MediaCodecsXmlParser::CodecMap codecMap = parser.getCodecMap();
94 
95     sp<IMediaCodecList> list = MediaCodecList::getInstance();
96     ASSERT_NE(list, nullptr) << "Unable to get MediaCodecList instance";
97 
98     // Compare CodecMap from XML to CodecList
99     for (auto mapIter : codecMap) {
100         ssize_t index = list->findCodecByName(mapIter.first.c_str());
101         if (index < 0) {
102             std::cout << "[   WARN   ] " << mapIter.first << " not found in CodecList \n";
103             continue;
104         }
105 
106         sp<MediaCodecInfo> info = list->getCodecInfo(index);
107         ASSERT_NE(info, nullptr) << "CodecInfo is null";
108 
109         MediaCodecsXmlParser::CodecProperties codecProperties = mapIter.second;
110         ASSERT_EQ(codecProperties.isEncoder, info->isEncoder()) << "Encoder property mismatch";
111 
112         ALOGV("codec name: %s", info->getCodecName());
113         ALOGV("codec rank: %d", info->getRank());
114         ALOGV("codec ownername: %s", info->getOwnerName());
115         ALOGV("codec isEncoder: %d", info->isEncoder());
116 
117         ALOGV("attributeFlags: kFlagIsHardwareAccelerated, kFlagIsSoftwareOnly, kFlagIsVendor, "
118               "kFlagIsEncoder");
119         std::bitset<4> attr(info->getAttributes());
120         ALOGV("codec attributes: %s", attr.to_string().c_str());
121 
122         Vector<AString> mediaTypes;
123         info->getSupportedMediaTypes(&mediaTypes);
124         ALOGV("supported media types count: %zu", mediaTypes.size());
125         ASSERT_FALSE(mediaTypes.isEmpty())
126                 << "no media type supported by codec: " << info->getCodecName();
127 
128         MediaCodecsXmlParser::TypeMap typeMap = codecProperties.typeMap;
129         for (auto mediaType : mediaTypes) {
130             ALOGV("codec mediaTypes: %s", mediaType.c_str());
131             auto searchTypeMap = typeMap.find(mediaType.c_str());
132             ASSERT_NE(searchTypeMap, typeMap.end())
133                     << "CodecList doesn't contain codec media type: " << mediaType.c_str();
134             MediaCodecsXmlParser::AttributeMap attributeMap = searchTypeMap->second;
135 
136             const sp<MediaCodecInfo::Capabilities> &capabilities =
137                     info->getCapabilitiesFor(mediaType.c_str());
138 
139             Vector<uint32_t> colorFormats;
140             capabilities->getSupportedColorFormats(&colorFormats);
141             for (auto colorFormat : colorFormats) {
142                 ALOGV("supported color formats: %d", colorFormat);
143             }
144 
145             Vector<MediaCodecInfo::ProfileLevel> profileLevels;
146             capabilities->getSupportedProfileLevels(&profileLevels);
147             if (!profileLevels.empty()) {
148                 ALOGV("supported profilelevel for media type: %s", mediaType.c_str());
149             }
150             for (auto profileLevel : profileLevels) {
151                 ALOGV("profile: %d, level: %d", profileLevel.mProfile, profileLevel.mLevel);
152             }
153 
154             sp<AMessage> details = capabilities->getDetails();
155             ASSERT_NE(details, nullptr) << "Details in codec capabilities is null";
156             ALOGV("no. of entries in details: %zu", details->countEntries());
157 
158             for (size_t idxDetail = 0; idxDetail < details->countEntries(); idxDetail++) {
159                 AMessage::Type type;
160                 const char *name = details->getEntryNameAt(idxDetail, &type);
161                 ALOGV("details entry name: %s", name);
162                 AMessage::ItemData itemData = details->getEntryAt(idxDetail);
163                 switch (type) {
164                     case AMessage::kTypeInt32:
165                         int32_t val32;
166                         if (itemData.find(&val32)) {
167                             ALOGV("entry int val: %d", val32);
168                             auto searchAttr = attributeMap.find(name);
169                             if (searchAttr == attributeMap.end()) {
170                                 ALOGW("Parser doesn't have key: %s", name);
171                             } else if (stoi(searchAttr->second) != val32) {
172                                 ALOGW("Values didn't match for key: %s", name);
173                                 ALOGV("Values act/exp: %d / %d", val32, stoi(searchAttr->second));
174                             }
175                         }
176                         break;
177                     case AMessage::kTypeString:
178                         if (AString valStr; itemData.find(&valStr)) {
179                             ALOGV("entry str val: %s", valStr.c_str());
180                             auto searchAttr = attributeMap.find(name);
181                             if (searchAttr == attributeMap.end()) {
182                                 ALOGW("Parser doesn't have key: %s", name);
183                             } else if (searchAttr->second != valStr.c_str()) {
184                                 ALOGW("Values didn't match for key: %s", name);
185                                 ALOGV("Values act/exp: %s / %s", valStr.c_str(),
186                                       searchAttr->second.c_str());
187                             }
188                         }
189                         break;
190                     default:
191                         ALOGV("data type: %d shouldn't be present in details", type);
192                         break;
193                 }
194             }
195         }
196 
197         Parcel *codecInfoParcel = new Parcel();
198         ASSERT_NE(codecInfoParcel, nullptr) << "Unable to create parcel";
199 
200         status_t status = info->writeToParcel(codecInfoParcel);
201         ASSERT_EQ(status, OK) << "Writing to parcel failed";
202 
203         codecInfoParcel->setDataPosition(0);
204         sp<MediaCodecInfo> parcelCodecInfo = info->FromParcel(*codecInfoParcel);
205         ASSERT_NE(parcelCodecInfo, nullptr) << "CodecInfo from parcel is null";
206         delete codecInfoParcel;
207 
208         EXPECT_STREQ(info->getCodecName(), parcelCodecInfo->getCodecName())
209                 << "Returned codec name in info doesn't match";
210         EXPECT_EQ(info->getRank(), parcelCodecInfo->getRank())
211                 << "Returned component rank in info doesn't match";
212     }
213 }
214 
TEST(CodecListTest,CodecListGlobalSettingsTest)215 TEST(CodecListTest, CodecListGlobalSettingsTest) {
216     sp<IMediaCodecList> list = MediaCodecList::getInstance();
217     ASSERT_NE(list, nullptr) << "Unable to get MediaCodecList instance";
218 
219     sp<AMessage> globalSettings = list->getGlobalSettings();
220     ASSERT_NE(globalSettings, nullptr) << "GlobalSettings AMessage is null";
221     ALOGV("global settings: %s", globalSettings->debugString(0).c_str());
222 }
223