• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 "Codec2InfoBuilder"
19 #include <log/log.h>
20 
21 #include <codec2/hidl/client.h>
22 
23 #include <C2Component.h>
24 #include <C2Config.h>
25 #include <C2Debug.h>
26 #include <C2PlatformSupport.h>
27 #include <C2V4l2Support.h>
28 #include <Codec2Mapper.h>
29 
30 #include <android-base/properties.h>
31 #include <media/stagefright/MediaCodecConstants.h>
32 #include <media/stagefright/foundation/MediaDefs.h>
33 #include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
34 
35 #include "Codec2InfoBuilder.h"
36 
37 namespace android {
38 
39 using Traits = C2Component::Traits;
40 
41 namespace /* unnamed */ {
42 
hasPrefix(const std::string & s,const char * prefix)43 bool hasPrefix(const std::string& s, const char* prefix) {
44     size_t prefixLen = strlen(prefix);
45     return s.compare(0, prefixLen, prefix) == 0;
46 }
47 
hasSuffix(const std::string & s,const char * suffix)48 bool hasSuffix(const std::string& s, const char* suffix) {
49     size_t suffixLen = strlen(suffix);
50     return suffixLen > s.size() ? false :
51             s.compare(s.size() - suffixLen, suffixLen, suffix) == 0;
52 }
53 
54 } // unnamed namespace
55 
buildMediaCodecList(MediaCodecListWriter * writer)56 status_t Codec2InfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
57     // TODO: Remove run-time configurations once all codecs are working
58     // properly. (Assume "full" behavior eventually.)
59     //
60     // debug.stagefright.ccodec supports 5 values.
61     //   0 - Only OMX components are available.
62     //   1 - Codec2.0 software audio decoders/encoders are available and
63     //       ranked 1st.
64     //       Components with "c2.vda." prefix are available with their normal
65     //       ranks.
66     //       Other components with ".avc.decoder" or ".avc.encoder" suffix are
67     //       available, but ranked last.
68     //   2 - All Codec2.0 components are available.
69     //       Codec2.0 software audio decoders are ranked 1st.
70     //       The other Codec2.0 components have their normal ranks.
71     //   3 - All Codec2.0 components are available.
72     //       Codec2.0 software components are ranked 1st.
73     //       The other Codec2.0 components have their normal ranks.
74     //   4 - All Codec2.0 components are available with their normal ranks.
75     //
76     // The default value (boot time) is 1.
77     //
78     // Note: Currently, OMX components have default rank 0x100, while all
79     // Codec2.0 software components have default rank 0x200.
80     int option = ::android::base::GetIntProperty("debug.stagefright.ccodec", 1);
81 
82     // Obtain Codec2Client
83     std::vector<Traits> traits = Codec2Client::ListComponents();
84 
85     MediaCodecsXmlParser parser(
86             MediaCodecsXmlParser::defaultSearchDirs,
87             "media_codecs_c2.xml");
88     if (parser.getParsingStatus() != OK) {
89         ALOGD("XML parser no good");
90         return OK;
91     }
92     for (const Traits& trait : traits) {
93         if (parser.getCodecMap().count(trait.name.c_str()) == 0) {
94             ALOGD("%s not found in xml", trait.name.c_str());
95             continue;
96         }
97 
98         // TODO: Remove this block once all codecs are enabled by default.
99         C2Component::rank_t rank = trait.rank;
100         switch (option) {
101         case 0:
102             continue;
103         case 1:
104             if (hasPrefix(trait.name, "c2.vda.")) {
105                 break;
106             }
107             if (hasPrefix(trait.name, "c2.android.")) {
108                 if (trait.domain == C2Component::DOMAIN_AUDIO) {
109                     rank = 1;
110                     break;
111                 }
112                 continue;
113             }
114             if (hasSuffix(trait.name, ".avc.decoder") ||
115                     hasSuffix(trait.name, ".avc.encoder")) {
116                 rank = std::numeric_limits<decltype(rank)>::max();
117                 break;
118             }
119             continue;
120         case 2:
121             if (trait.domain == C2Component::DOMAIN_AUDIO &&
122                     trait.kind == C2Component::KIND_DECODER) {
123         case 3:
124                 if (hasPrefix(trait.name, "c2.android.")) {
125                     rank = 1;
126                 }
127             }
128             break;
129         }
130 
131         const MediaCodecsXmlParser::CodecProperties &codec = parser.getCodecMap().at(trait.name);
132         std::unique_ptr<MediaCodecInfoWriter> codecInfo = writer->addMediaCodecInfo();
133         codecInfo->setName(trait.name.c_str());
134         codecInfo->setOwner("dummy");
135         // TODO: get this from trait.kind
136         bool encoder = (trait.name.find("encoder") != std::string::npos);
137         codecInfo->setEncoder(encoder);
138         codecInfo->setRank(rank);
139         for (auto typeIt = codec.typeMap.begin(); typeIt != codec.typeMap.end(); ++typeIt) {
140             const std::string &mediaType = typeIt->first;
141             const MediaCodecsXmlParser::AttributeMap &attrMap = typeIt->second;
142             std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
143                 codecInfo->addMime(mediaType.c_str());
144             for (auto attrIt = attrMap.begin(); attrIt != attrMap.end(); ++attrIt) {
145                 std::string key, value;
146                 std::tie(key, value) = *attrIt;
147                 if (key.find("feature-") == 0 && key.find("feature-bitrate-modes") != 0) {
148                     caps->addDetail(key.c_str(), std::stoi(value));
149                 } else {
150                     caps->addDetail(key.c_str(), value.c_str());
151                 }
152             }
153 
154             bool gotProfileLevels = false;
155             std::shared_ptr<Codec2Client::Interface> intf =
156                 Codec2Client::CreateInterfaceByName(trait.name.c_str());
157             if (intf) {
158                 std::shared_ptr<C2Mapper::ProfileLevelMapper> mapper =
159                     C2Mapper::GetProfileLevelMapper(trait.mediaType);
160                 // if we don't know the media type, pass through all values unmapped
161 
162                 // TODO: we cannot find levels that are local 'maxima' without knowing the coding
163                 // e.g. H.263 level 45 and level 30 could be two values for highest level as
164                 // they don't include one another. For now we use the last supported value.
165                 C2StreamProfileLevelInfo pl(encoder /* output */, 0u);
166                 std::vector<C2FieldSupportedValuesQuery> profileQuery = {
167                     C2FieldSupportedValuesQuery::Possible(C2ParamField(&pl, &pl.profile))
168                 };
169 
170                 c2_status_t err = intf->querySupportedValues(profileQuery, C2_DONT_BLOCK);
171                 ALOGV("query supported profiles -> %s | %s",
172                         asString(err), asString(profileQuery[0].status));
173                 if (err == C2_OK && profileQuery[0].status == C2_OK) {
174                     if (profileQuery[0].values.type == C2FieldSupportedValues::VALUES) {
175                         for (C2Value::Primitive profile : profileQuery[0].values.values) {
176                             pl.profile = (C2Config::profile_t)profile.ref<uint32_t>();
177                             std::vector<std::unique_ptr<C2SettingResult>> failures;
178                             err = intf->config({&pl}, C2_DONT_BLOCK, &failures);
179                             ALOGV("set profile to %u -> %s", pl.profile, asString(err));
180                             std::vector<C2FieldSupportedValuesQuery> levelQuery = {
181                                 C2FieldSupportedValuesQuery::Current(C2ParamField(&pl, &pl.level))
182                             };
183                             err = intf->querySupportedValues(levelQuery, C2_DONT_BLOCK);
184                             ALOGV("query supported levels -> %s | %s",
185                                     asString(err), asString(levelQuery[0].status));
186                             if (err == C2_OK && levelQuery[0].status == C2_OK) {
187                                 if (levelQuery[0].values.type == C2FieldSupportedValues::VALUES
188                                         && levelQuery[0].values.values.size() > 0) {
189                                     C2Value::Primitive level = levelQuery[0].values.values.back();
190                                     pl.level = (C2Config::level_t)level.ref<uint32_t>();
191                                     ALOGV("supporting level: %u", pl.level);
192                                     int32_t sdkProfile, sdkLevel;
193                                     if (mapper && mapper->mapProfile(pl.profile, &sdkProfile)
194                                             && mapper->mapLevel(pl.level, &sdkLevel)) {
195                                         caps->addProfileLevel(
196                                                 (uint32_t)sdkProfile, (uint32_t)sdkLevel);
197                                         gotProfileLevels = true;
198                                     } else if (!mapper) {
199                                         caps->addProfileLevel(pl.profile, pl.level);
200                                         gotProfileLevels = true;
201                                     }
202                                 }
203                             }
204                         }
205                     }
206                 }
207             }
208 
209             if (!gotProfileLevels) {
210                 if (mediaType == MIMETYPE_VIDEO_VP9) {
211                     if (encoder) {
212                         caps->addProfileLevel(VP9Profile0,    VP9Level41);
213                     } else {
214                         caps->addProfileLevel(VP9Profile0,    VP9Level5);
215                         caps->addProfileLevel(VP9Profile2,    VP9Level5);
216                         caps->addProfileLevel(VP9Profile2HDR, VP9Level5);
217                     }
218                 } else if (mediaType == MIMETYPE_VIDEO_HEVC && !encoder) {
219                     caps->addProfileLevel(HEVCProfileMain,      HEVCMainTierLevel51);
220                     caps->addProfileLevel(HEVCProfileMainStill, HEVCMainTierLevel51);
221                 } else if (mediaType == MIMETYPE_VIDEO_VP8) {
222                     if (encoder) {
223                         caps->addProfileLevel(VP8ProfileMain, VP8Level_Version0);
224                     } else {
225                         caps->addProfileLevel(VP8ProfileMain, VP8Level_Version0);
226                     }
227                 } else if (mediaType == MIMETYPE_VIDEO_AVC) {
228                     if (encoder) {
229                         caps->addProfileLevel(AVCProfileBaseline,            AVCLevel41);
230 //                      caps->addProfileLevel(AVCProfileConstrainedBaseline, AVCLevel41);
231                         caps->addProfileLevel(AVCProfileMain,                AVCLevel41);
232                     } else {
233                         caps->addProfileLevel(AVCProfileBaseline,            AVCLevel52);
234                         caps->addProfileLevel(AVCProfileConstrainedBaseline, AVCLevel52);
235                         caps->addProfileLevel(AVCProfileMain,                AVCLevel52);
236                         caps->addProfileLevel(AVCProfileConstrainedHigh,     AVCLevel52);
237                         caps->addProfileLevel(AVCProfileHigh,                AVCLevel52);
238                     }
239                 } else if (mediaType == MIMETYPE_VIDEO_MPEG4) {
240                     if (encoder) {
241                         caps->addProfileLevel(MPEG4ProfileSimple,  MPEG4Level2);
242                     } else {
243                         caps->addProfileLevel(MPEG4ProfileSimple,  MPEG4Level3);
244                     }
245                 } else if (mediaType == MIMETYPE_VIDEO_H263) {
246                     if (encoder) {
247                         caps->addProfileLevel(H263ProfileBaseline, H263Level45);
248                     } else {
249                         caps->addProfileLevel(H263ProfileBaseline, H263Level30);
250                         caps->addProfileLevel(H263ProfileBaseline, H263Level45);
251                         caps->addProfileLevel(H263ProfileISWV2,    H263Level30);
252                         caps->addProfileLevel(H263ProfileISWV2,    H263Level45);
253                     }
254                 } else if (mediaType == MIMETYPE_VIDEO_MPEG2 && !encoder) {
255                     caps->addProfileLevel(MPEG2ProfileSimple, MPEG2LevelHL);
256                     caps->addProfileLevel(MPEG2ProfileMain,   MPEG2LevelHL);
257                 }
258             }
259 
260             // TODO: get this from intf() as well, but how do we map them to
261             // MediaCodec color formats?
262             if (mediaType.find("video") != std::string::npos) {
263                 // vendor video codecs prefer opaque format
264                 if (trait.name.find("android") == std::string::npos) {
265                     caps->addColorFormat(COLOR_FormatSurface);
266                 }
267                 caps->addColorFormat(COLOR_FormatYUV420Flexible);
268                 caps->addColorFormat(COLOR_FormatYUV420Planar);
269                 caps->addColorFormat(COLOR_FormatYUV420SemiPlanar);
270                 caps->addColorFormat(COLOR_FormatYUV420PackedPlanar);
271                 caps->addColorFormat(COLOR_FormatYUV420PackedSemiPlanar);
272                 // framework video encoders must support surface format, though it is unclear
273                 // that they will be able to map it if it is opaque
274                 if (encoder && trait.name.find("android") != std::string::npos) {
275                     caps->addColorFormat(COLOR_FormatSurface);
276                 }
277             }
278         }
279     }
280     return OK;
281 }
282 
283 }  // namespace android
284 
CreateBuilder()285 extern "C" android::MediaCodecListBuilderBase *CreateBuilder() {
286     return new android::Codec2InfoBuilder;
287 }
288 
289