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 #include <media/stagefright/OMXCodec.h>
30 
31 namespace android {
32 
getSupportedProfileLevels(Vector<ProfileLevel> * profileLevels) const33 void MediaCodecInfo::Capabilities::getSupportedProfileLevels(
34         Vector<ProfileLevel> *profileLevels) const {
35     profileLevels->clear();
36     profileLevels->appendVector(mProfileLevels);
37 }
38 
getSupportedColorFormats(Vector<uint32_t> * colorFormats) const39 void MediaCodecInfo::Capabilities::getSupportedColorFormats(
40         Vector<uint32_t> *colorFormats) const {
41     colorFormats->clear();
42     colorFormats->appendVector(mColorFormats);
43 }
44 
getFlags() const45 uint32_t MediaCodecInfo::Capabilities::getFlags() const {
46     return mFlags;
47 }
48 
getDetails() const49 const sp<AMessage> MediaCodecInfo::Capabilities::getDetails() const {
50     return mDetails;
51 }
52 
Capabilities()53 MediaCodecInfo::Capabilities::Capabilities()
54   : mFlags(0) {
55     mDetails = new AMessage;
56 }
57 
58 // static
FromParcel(const Parcel & parcel)59 sp<MediaCodecInfo::Capabilities> MediaCodecInfo::Capabilities::FromParcel(
60         const Parcel &parcel) {
61     sp<MediaCodecInfo::Capabilities> caps = new Capabilities();
62     size_t size = static_cast<size_t>(parcel.readInt32());
63     for (size_t i = 0; i < size; i++) {
64         ProfileLevel profileLevel;
65         profileLevel.mProfile = static_cast<uint32_t>(parcel.readInt32());
66         profileLevel.mLevel = static_cast<uint32_t>(parcel.readInt32());
67         if (caps != NULL) {
68             caps->mProfileLevels.push_back(profileLevel);
69         }
70     }
71     size = static_cast<size_t>(parcel.readInt32());
72     for (size_t i = 0; i < size; i++) {
73         uint32_t color = static_cast<uint32_t>(parcel.readInt32());
74         if (caps != NULL) {
75             caps->mColorFormats.push_back(color);
76         }
77     }
78     uint32_t flags = static_cast<uint32_t>(parcel.readInt32());
79     sp<AMessage> details = AMessage::FromParcel(parcel);
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 
isEncoder() const104 bool MediaCodecInfo::isEncoder() const {
105     return mIsEncoder;
106 }
107 
hasQuirk(const char * name) const108 bool MediaCodecInfo::hasQuirk(const char *name) const {
109     for (size_t ix = 0; ix < mQuirks.size(); ix++) {
110         if (mQuirks.itemAt(ix).equalsIgnoreCase(name)) {
111             return true;
112         }
113     }
114     return false;
115 }
116 
getSupportedMimes(Vector<AString> * mimes) const117 void MediaCodecInfo::getSupportedMimes(Vector<AString> *mimes) const {
118     mimes->clear();
119     for (size_t ix = 0; ix < mCaps.size(); ix++) {
120         mimes->push_back(mCaps.keyAt(ix));
121     }
122 }
123 
124 const sp<MediaCodecInfo::Capabilities>
getCapabilitiesFor(const char * mime) const125 MediaCodecInfo::getCapabilitiesFor(const char *mime) const {
126     ssize_t ix = getCapabilityIndex(mime);
127     if (ix >= 0) {
128         return mCaps.valueAt(ix);
129     }
130     return NULL;
131 }
132 
getCodecName() const133 const char *MediaCodecInfo::getCodecName() const {
134     return mName.c_str();
135 }
136 
137 // static
FromParcel(const Parcel & parcel)138 sp<MediaCodecInfo> MediaCodecInfo::FromParcel(const Parcel &parcel) {
139     AString name = AString::FromParcel(parcel);
140     bool isEncoder = static_cast<bool>(parcel.readInt32());
141     sp<MediaCodecInfo> info = new MediaCodecInfo(name, isEncoder, NULL);
142     size_t size = static_cast<size_t>(parcel.readInt32());
143     for (size_t i = 0; i < size; i++) {
144         AString quirk = AString::FromParcel(parcel);
145         if (info != NULL) {
146             info->mQuirks.push_back(quirk);
147         }
148     }
149     size = static_cast<size_t>(parcel.readInt32());
150     for (size_t i = 0; i < size; i++) {
151         AString mime = AString::FromParcel(parcel);
152         sp<Capabilities> caps = Capabilities::FromParcel(parcel);
153         if (info != NULL) {
154             info->mCaps.add(mime, caps);
155         }
156     }
157     return info;
158 }
159 
writeToParcel(Parcel * parcel) const160 status_t MediaCodecInfo::writeToParcel(Parcel *parcel) const {
161     mName.writeToParcel(parcel);
162     parcel->writeInt32(mIsEncoder);
163     parcel->writeInt32(mQuirks.size());
164     for (size_t i = 0; i < mQuirks.size(); i++) {
165         mQuirks.itemAt(i).writeToParcel(parcel);
166     }
167     parcel->writeInt32(mCaps.size());
168     for (size_t i = 0; i < mCaps.size(); i++) {
169         mCaps.keyAt(i).writeToParcel(parcel);
170         mCaps.valueAt(i)->writeToParcel(parcel);
171     }
172     return OK;
173 }
174 
getCapabilityIndex(const char * mime) const175 ssize_t MediaCodecInfo::getCapabilityIndex(const char *mime) const {
176     for (size_t ix = 0; ix < mCaps.size(); ix++) {
177         if (mCaps.keyAt(ix).equalsIgnoreCase(mime)) {
178             return ix;
179         }
180     }
181     return -1;
182 }
183 
MediaCodecInfo(AString name,bool encoder,const char * mime)184 MediaCodecInfo::MediaCodecInfo(AString name, bool encoder, const char *mime)
185     : mName(name),
186       mIsEncoder(encoder),
187       mHasSoleMime(false) {
188     if (mime != NULL) {
189         addMime(mime);
190         mHasSoleMime = true;
191     }
192 }
193 
addMime(const char * mime)194 status_t MediaCodecInfo::addMime(const char *mime) {
195     if (mHasSoleMime) {
196         ALOGE("Codec '%s' already had its type specified", mName.c_str());
197         return -EINVAL;
198     }
199     ssize_t ix = getCapabilityIndex(mime);
200     if (ix >= 0) {
201         mCurrentCaps = mCaps.valueAt(ix);
202     } else {
203         mCurrentCaps = new Capabilities();
204         mCaps.add(AString(mime), mCurrentCaps);
205     }
206     return OK;
207 }
208 
updateMime(const char * mime)209 status_t MediaCodecInfo::updateMime(const char *mime) {
210     ssize_t ix = getCapabilityIndex(mime);
211     if (ix < 0) {
212         ALOGE("updateMime mime not found %s", mime);
213         return -EINVAL;
214     }
215 
216     mCurrentCaps = mCaps.valueAt(ix);
217     return OK;
218 }
219 
removeMime(const char * mime)220 void MediaCodecInfo::removeMime(const char *mime) {
221     ssize_t ix = getCapabilityIndex(mime);
222     if (ix >= 0) {
223         mCaps.removeItemsAt(ix);
224         // mCurrentCaps will be removed when completed
225     }
226 }
227 
initializeCapabilities(const CodecCapabilities & caps)228 status_t MediaCodecInfo::initializeCapabilities(const CodecCapabilities &caps) {
229     mCurrentCaps->mProfileLevels.clear();
230     mCurrentCaps->mColorFormats.clear();
231 
232     for (size_t i = 0; i < caps.mProfileLevels.size(); ++i) {
233         const CodecProfileLevel &src = caps.mProfileLevels.itemAt(i);
234 
235         ProfileLevel profileLevel;
236         profileLevel.mProfile = src.mProfile;
237         profileLevel.mLevel = src.mLevel;
238         mCurrentCaps->mProfileLevels.push_back(profileLevel);
239     }
240 
241     for (size_t i = 0; i < caps.mColorFormats.size(); ++i) {
242         mCurrentCaps->mColorFormats.push_back(caps.mColorFormats.itemAt(i));
243     }
244 
245     mCurrentCaps->mFlags = caps.mFlags;
246     mCurrentCaps->mDetails = new AMessage;
247 
248     return OK;
249 }
250 
addQuirk(const char * name)251 void MediaCodecInfo::addQuirk(const char *name) {
252     if (!hasQuirk(name)) {
253         mQuirks.push(name);
254     }
255 }
256 
complete()257 void MediaCodecInfo::complete() {
258     mCurrentCaps = NULL;
259 }
260 
addDetail(const AString & key,const AString & value)261 void MediaCodecInfo::addDetail(const AString &key, const AString &value) {
262     mCurrentCaps->mDetails->setString(key.c_str(), value.c_str());
263 }
264 
addFeature(const AString & key,int32_t value)265 void MediaCodecInfo::addFeature(const AString &key, int32_t value) {
266     AString tag = "feature-";
267     tag.append(key);
268     mCurrentCaps->mDetails->setInt32(tag.c_str(), value);
269 }
270 
addFeature(const AString & key,const char * value)271 void MediaCodecInfo::addFeature(const AString &key, const char *value) {
272     AString tag = "feature-";
273     tag.append(key);
274     mCurrentCaps->mDetails->setString(tag.c_str(), value);
275 }
276 
277 }  // namespace android
278