1 /*
2 * Copyright 2014, 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 "MediaCodecInfo"
19 #include <utils/Log.h>
20
21 #include <media/IOMX.h>
22
23 #include <media/MediaCodecInfo.h>
24
25 #include <media/stagefright/foundation/ADebug.h>
26 #include <media/stagefright/foundation/AMessage.h>
27 #include <binder/Parcel.h>
28
29 namespace android {
30
getSupportedProfileLevels(Vector<ProfileLevel> * profileLevels) const31 void MediaCodecInfo::Capabilities::getSupportedProfileLevels(
32 Vector<ProfileLevel> *profileLevels) const {
33 profileLevels->clear();
34 profileLevels->appendVector(mProfileLevels);
35 }
36
getSupportedColorFormats(Vector<uint32_t> * colorFormats) const37 void MediaCodecInfo::Capabilities::getSupportedColorFormats(
38 Vector<uint32_t> *colorFormats) const {
39 colorFormats->clear();
40 colorFormats->appendVector(mColorFormats);
41 }
42
getFlags() const43 uint32_t MediaCodecInfo::Capabilities::getFlags() const {
44 return mFlags;
45 }
46
getDetails() const47 const sp<AMessage> MediaCodecInfo::Capabilities::getDetails() const {
48 return mDetails;
49 }
50
Capabilities()51 MediaCodecInfo::Capabilities::Capabilities()
52 : mFlags(0) {
53 mDetails = new AMessage;
54 }
55
56 // static
FromParcel(const Parcel & parcel)57 sp<MediaCodecInfo::Capabilities> MediaCodecInfo::Capabilities::FromParcel(
58 const Parcel &parcel) {
59 sp<MediaCodecInfo::Capabilities> caps = new Capabilities();
60 size_t size = static_cast<size_t>(parcel.readInt32());
61 for (size_t i = 0; i < size; i++) {
62 ProfileLevel profileLevel;
63 profileLevel.mProfile = static_cast<uint32_t>(parcel.readInt32());
64 profileLevel.mLevel = static_cast<uint32_t>(parcel.readInt32());
65 if (caps != NULL) {
66 caps->mProfileLevels.push_back(profileLevel);
67 }
68 }
69 size = static_cast<size_t>(parcel.readInt32());
70 for (size_t i = 0; i < size; i++) {
71 uint32_t color = static_cast<uint32_t>(parcel.readInt32());
72 if (caps != NULL) {
73 caps->mColorFormats.push_back(color);
74 }
75 }
76 uint32_t flags = static_cast<uint32_t>(parcel.readInt32());
77 sp<AMessage> details = AMessage::FromParcel(parcel);
78 if (details == NULL)
79 return NULL;
80 if (caps != NULL) {
81 caps->mFlags = flags;
82 caps->mDetails = details;
83 }
84 return caps;
85 }
86
writeToParcel(Parcel * parcel) const87 status_t MediaCodecInfo::Capabilities::writeToParcel(Parcel *parcel) const {
88 CHECK_LE(mProfileLevels.size(), INT32_MAX);
89 parcel->writeInt32(mProfileLevels.size());
90 for (size_t i = 0; i < mProfileLevels.size(); i++) {
91 parcel->writeInt32(mProfileLevels.itemAt(i).mProfile);
92 parcel->writeInt32(mProfileLevels.itemAt(i).mLevel);
93 }
94 CHECK_LE(mColorFormats.size(), INT32_MAX);
95 parcel->writeInt32(mColorFormats.size());
96 for (size_t i = 0; i < mColorFormats.size(); i++) {
97 parcel->writeInt32(mColorFormats.itemAt(i));
98 }
99 parcel->writeInt32(mFlags);
100 mDetails->writeToParcel(parcel);
101 return OK;
102 }
103
addProfileLevel(uint32_t profile,uint32_t level)104 void MediaCodecInfo::CapabilitiesBuilder::addProfileLevel(uint32_t profile, uint32_t level) {
105 ProfileLevel profileLevel;
106 profileLevel.mProfile = profile;
107 profileLevel.mLevel = level;
108 mProfileLevels.push_back(profileLevel);
109 }
110
addColorFormat(uint32_t format)111 void MediaCodecInfo::CapabilitiesBuilder::addColorFormat(uint32_t format) {
112 mColorFormats.push(format);
113 }
114
addFlags(uint32_t flags)115 void MediaCodecInfo::CapabilitiesBuilder::addFlags(uint32_t flags) {
116 mFlags |= flags;
117 }
118
isEncoder() const119 bool MediaCodecInfo::isEncoder() const {
120 return mIsEncoder;
121 }
122
hasQuirk(const char * name) const123 bool MediaCodecInfo::hasQuirk(const char *name) const {
124 if (name) {
125 for (size_t ix = 0; ix < mQuirks.size(); ix++) {
126 if (mQuirks.itemAt(ix).equalsIgnoreCase(name)) {
127 return true;
128 }
129 }
130 }
131 return false;
132 }
133
getSupportedMimes(Vector<AString> * mimes) const134 void MediaCodecInfo::getSupportedMimes(Vector<AString> *mimes) const {
135 mimes->clear();
136 for (size_t ix = 0; ix < mCaps.size(); ix++) {
137 mimes->push_back(mCaps.keyAt(ix));
138 }
139 }
140
141 const sp<MediaCodecInfo::Capabilities>
getCapabilitiesFor(const char * mime) const142 MediaCodecInfo::getCapabilitiesFor(const char *mime) const {
143 ssize_t ix = getCapabilityIndex(mime);
144 if (ix >= 0) {
145 return mCaps.valueAt(ix);
146 }
147 return NULL;
148 }
149
getCodecName() const150 const char *MediaCodecInfo::getCodecName() const {
151 return mName.c_str();
152 }
153
154 // static
FromParcel(const Parcel & parcel)155 sp<MediaCodecInfo> MediaCodecInfo::FromParcel(const Parcel &parcel) {
156 AString name = AString::FromParcel(parcel);
157 bool isEncoder = static_cast<bool>(parcel.readInt32());
158 sp<MediaCodecInfo> info = new MediaCodecInfo(name, isEncoder, NULL);
159 size_t size = static_cast<size_t>(parcel.readInt32());
160 for (size_t i = 0; i < size; i++) {
161 AString quirk = AString::FromParcel(parcel);
162 if (info != NULL) {
163 info->mQuirks.push_back(quirk);
164 }
165 }
166 size = static_cast<size_t>(parcel.readInt32());
167 for (size_t i = 0; i < size; i++) {
168 AString mime = AString::FromParcel(parcel);
169 sp<Capabilities> caps = Capabilities::FromParcel(parcel);
170 if (caps == NULL)
171 return NULL;
172 if (info != NULL) {
173 info->mCaps.add(mime, caps);
174 }
175 }
176 return info;
177 }
178
writeToParcel(Parcel * parcel) const179 status_t MediaCodecInfo::writeToParcel(Parcel *parcel) const {
180 mName.writeToParcel(parcel);
181 parcel->writeInt32(mIsEncoder);
182 parcel->writeInt32(mQuirks.size());
183 for (size_t i = 0; i < mQuirks.size(); i++) {
184 mQuirks.itemAt(i).writeToParcel(parcel);
185 }
186 parcel->writeInt32(mCaps.size());
187 for (size_t i = 0; i < mCaps.size(); i++) {
188 mCaps.keyAt(i).writeToParcel(parcel);
189 mCaps.valueAt(i)->writeToParcel(parcel);
190 }
191 return OK;
192 }
193
getCapabilityIndex(const char * mime) const194 ssize_t MediaCodecInfo::getCapabilityIndex(const char *mime) const {
195 if (mime) {
196 for (size_t ix = 0; ix < mCaps.size(); ix++) {
197 if (mCaps.keyAt(ix).equalsIgnoreCase(mime)) {
198 return ix;
199 }
200 }
201 }
202 return -1;
203 }
204
MediaCodecInfo(AString name,bool encoder,const char * mime)205 MediaCodecInfo::MediaCodecInfo(AString name, bool encoder, const char *mime)
206 : mName(name),
207 mIsEncoder(encoder),
208 mHasSoleMime(false) {
209 if (mime != NULL) {
210 addMime(mime);
211 mHasSoleMime = true;
212 }
213 }
214
addMime(const char * mime)215 status_t MediaCodecInfo::addMime(const char *mime) {
216 if (mHasSoleMime) {
217 ALOGE("Codec '%s' already had its type specified", mName.c_str());
218 return -EINVAL;
219 }
220 ssize_t ix = getCapabilityIndex(mime);
221 if (ix >= 0) {
222 mCurrentCaps = mCaps.valueAt(ix);
223 } else {
224 mCurrentCaps = new Capabilities();
225 mCaps.add(AString(mime), mCurrentCaps);
226 }
227 return OK;
228 }
229
updateMime(const char * mime)230 status_t MediaCodecInfo::updateMime(const char *mime) {
231 ssize_t ix = getCapabilityIndex(mime);
232 if (ix < 0) {
233 ALOGE("updateMime mime not found %s", mime);
234 return -EINVAL;
235 }
236
237 mCurrentCaps = mCaps.valueAt(ix);
238 return OK;
239 }
240
removeMime(const char * mime)241 void MediaCodecInfo::removeMime(const char *mime) {
242 ssize_t ix = getCapabilityIndex(mime);
243 if (ix >= 0) {
244 mCaps.removeItemsAt(ix);
245 // mCurrentCaps will be removed when completed
246 }
247 }
248
initializeCapabilities(const sp<Capabilities> & caps)249 status_t MediaCodecInfo::initializeCapabilities(const sp<Capabilities> &caps) {
250 // TRICKY: copy data to mCurrentCaps as it is a reference to
251 // an element of the capabilites map.
252 mCurrentCaps->mColorFormats.clear();
253 mCurrentCaps->mColorFormats.appendVector(caps->mColorFormats);
254 mCurrentCaps->mProfileLevels.clear();
255 mCurrentCaps->mProfileLevels.appendVector(caps->mProfileLevels);
256 mCurrentCaps->mFlags = caps->mFlags;
257 mCurrentCaps->mDetails = caps->mDetails;
258 return OK;
259 }
260
addQuirk(const char * name)261 void MediaCodecInfo::addQuirk(const char *name) {
262 if (!hasQuirk(name)) {
263 mQuirks.push(name);
264 }
265 }
266
complete()267 void MediaCodecInfo::complete() {
268 mCurrentCaps = NULL;
269 }
270
addDetail(const AString & key,const AString & value)271 void MediaCodecInfo::addDetail(const AString &key, const AString &value) {
272 mCurrentCaps->mDetails->setString(key.c_str(), value.c_str());
273 }
274
addFeature(const AString & key,int32_t value)275 void MediaCodecInfo::addFeature(const AString &key, int32_t value) {
276 AString tag = "feature-";
277 tag.append(key);
278 mCurrentCaps->mDetails->setInt32(tag.c_str(), value);
279 }
280
addFeature(const AString & key,const char * value)281 void MediaCodecInfo::addFeature(const AString &key, const char *value) {
282 AString tag = "feature-";
283 tag.append(key);
284 mCurrentCaps->mDetails->setString(tag.c_str(), value);
285 }
286
287 } // namespace android
288