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