001package com.baidu.cloud.media.player;
002
003import android.annotation.TargetApi;
004import android.media.MediaCodecInfo;
005import android.media.MediaCodecInfo.CodecCapabilities;
006import android.media.MediaCodecInfo.CodecProfileLevel;
007import android.os.Build;
008import android.text.TextUtils;
009import android.util.Log;
010
011import java.util.Locale;
012import java.util.Map;
013import java.util.TreeMap;
014
015public class BDCloudMediaCodecInfo {
016    private static final String TAG = "BDCloudMediaCodecInfo";
017
018    public static final int RANK_MAX = 1000;
019    public static final int RANK_TESTED = 800;
020    public static final int RANK_ACCEPTABLE = 700;
021    public static final int RANK_LAST_CHANCE = 600;
022    public static final int RANK_SECURE = 300;
023    public static final int RANK_SOFTWARE = 200;
024    public static final int RANK_NON_STANDARD = 100;
025    public static final int RANK_NO_SENSE = 0;
026
027    public MediaCodecInfo mCodecInfo;
028    public int mRank = 0;
029    public String mMimeType;
030
031    private static Map<String, Integer> sKnownCodecList;
032
033    private static synchronized Map<String, Integer> getKnownCodecList() {
034        if (sKnownCodecList != null) {
035            return sKnownCodecList;
036        }
037
038        sKnownCodecList = new TreeMap<String, Integer>(String.CASE_INSENSITIVE_ORDER);
039
040        // ----- Nvidia -----
041        // Tegra3
042        // Nexus 7 (2012)
043        // Tegra K1
044        // Nexus 9
045        sKnownCodecList.put("OMX.Nvidia.h264.decode", RANK_TESTED);
046        sKnownCodecList.put("OMX.Nvidia.h264.decode.secure", RANK_SECURE);
047
048        // ----- Intel -----
049        // Atom Z3735
050        // Teclast X98 Air
051        sKnownCodecList.put("OMX.Intel.hw_vd.h264", RANK_TESTED + 1);
052        // Atom Z2560
053        // Dell Venue 7 3730
054        sKnownCodecList.put("OMX.Intel.VideoDecoder.AVC", RANK_TESTED);
055
056        // ----- Qualcomm -----
057        // MSM8260
058        // Xiaomi MI 1S
059        sKnownCodecList.put("OMX.qcom.video.decoder.avc", RANK_TESTED);
060        sKnownCodecList.put("OMX.ittiam.video.decoder.avc", RANK_NO_SENSE);
061
062        // ----- Samsung -----
063        // Exynos 3110
064        // Nexus S
065        sKnownCodecList.put("OMX.SEC.avc.dec", RANK_TESTED);
066        sKnownCodecList.put("OMX.SEC.AVC.Decoder", RANK_TESTED - 1);
067        // OMX.SEC.avcdec doesn't reorder output pictures on GT-9100
068        sKnownCodecList.put("OMX.SEC.avcdec", RANK_TESTED - 2);
069        sKnownCodecList.put("OMX.SEC.avc.sw.dec", RANK_SOFTWARE);
070        // Exynos 5 ?
071        sKnownCodecList.put("OMX.Exynos.avc.dec", RANK_TESTED);
072        sKnownCodecList.put("OMX.Exynos.AVC.Decoder", RANK_TESTED - 1);
073
074        // ------ Huawei hisilicon ------
075        // Kirin 910, Mali 450 MP
076        // Huawei HONOR 3C (H30-L01)
077        sKnownCodecList.put("OMX.k3.video.decoder.avc", RANK_TESTED);
078        // Kirin 920, Mali T624
079        // Huawei HONOR 6
080        sKnownCodecList.put("OMX.IMG.MSVDX.Decoder.AVC", RANK_TESTED);
081
082        // ----- TI -----
083        // TI OMAP4460
084        // Galaxy Nexus
085        sKnownCodecList.put("OMX.TI.DUCATI1.VIDEO.DECODER", RANK_TESTED);
086
087        // ------ RockChip ------
088        // Youku TVBox
089        sKnownCodecList.put("OMX.rk.video_decoder.avc", RANK_TESTED);
090
091        // ------ AMLogic -----
092        // MiBox1, 1s, 2
093        sKnownCodecList.put("OMX.amlogic.avc.decoder.awesome", RANK_TESTED);
094
095        // ------ Marvell ------
096        // Lenovo A788t
097        sKnownCodecList.put("OMX.MARVELL.VIDEO.HW.CODA7542DECODER", RANK_TESTED);
098        sKnownCodecList.put("OMX.MARVELL.VIDEO.H264DECODER", RANK_SOFTWARE);
099
100        // ----- TODO: need test -----
101        sKnownCodecList.remove("OMX.Action.Video.Decoder");
102        sKnownCodecList.remove("OMX.allwinner.video.decoder.avc");
103        sKnownCodecList.remove("OMX.BRCM.vc4.decoder.avc");
104        sKnownCodecList.remove("OMX.brcm.video.h264.hw.decoder");
105        sKnownCodecList.remove("OMX.brcm.video.h264.decoder");
106        sKnownCodecList.remove("OMX.cosmo.video.decoder.avc");
107        sKnownCodecList.remove("OMX.duos.h264.decoder");
108        sKnownCodecList.remove("OMX.hantro.81x0.video.decoder");
109        sKnownCodecList.remove("OMX.hantro.G1.video.decoder");
110        sKnownCodecList.remove("OMX.hisi.video.decoder");
111        sKnownCodecList.remove("OMX.LG.decoder.video.avc");
112        sKnownCodecList.remove("OMX.MS.AVC.Decoder");
113        sKnownCodecList.remove("OMX.RENESAS.VIDEO.DECODER.H264");
114        sKnownCodecList.remove("OMX.RTK.video.decoder");
115        sKnownCodecList.remove("OMX.sprd.h264.decoder");
116        sKnownCodecList.remove("OMX.ST.VFM.H264Dec");
117        sKnownCodecList.remove("OMX.vpu.video_decoder.avc");
118        sKnownCodecList.remove("OMX.WMT.decoder.avc");
119
120        // Really ?
121        sKnownCodecList.remove("OMX.bluestacks.hw.decoder");
122
123        // ---------------
124        // Useless codec
125        // ----- google -----
126        sKnownCodecList.put("OMX.google.h264.decoder", RANK_SOFTWARE);
127        sKnownCodecList.put("OMX.google.h264.lc.decoder", RANK_SOFTWARE);
128        // ----- huawei k920 -----
129        sKnownCodecList.put("OMX.k3.ffmpeg.decoder", RANK_SOFTWARE);
130        sKnownCodecList.put("OMX.ffmpeg.video.decoder", RANK_SOFTWARE);
131        // ----- unknown -----
132        sKnownCodecList.put("OMX.sprd.soft.h264.decoder", RANK_SOFTWARE);
133
134        return sKnownCodecList;
135    }
136
137    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
138    public static BDCloudMediaCodecInfo setupCandidate(MediaCodecInfo codecInfo, String mimeType) {
139        if (codecInfo == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
140            return null;
141        }
142
143        String name = codecInfo.getName();
144        if (TextUtils.isEmpty(name)) {
145            return null;
146        }
147
148        name = name.toLowerCase(Locale.US);
149        int rank = RANK_NO_SENSE;
150        if (!name.startsWith("omx.")) {
151            rank = RANK_NON_STANDARD;
152        } else if (name.startsWith("omx.pv")) {
153            rank = RANK_SOFTWARE;
154        } else if (name.startsWith("omx.google.")) {
155            rank = RANK_SOFTWARE;
156        } else if (name.startsWith("omx.ffmpeg.")) {
157            rank = RANK_SOFTWARE;
158        } else if (name.startsWith("omx.k3.ffmpeg.")) {
159            rank = RANK_SOFTWARE;
160        } else if (name.startsWith("omx.avcodec.")) {
161            rank = RANK_SOFTWARE;
162        } else if (name.startsWith("omx.ittiam.")) {
163            // unknown codec in qualcomm SoC
164            rank = RANK_NO_SENSE;
165        } else if (name.startsWith("omx.mtk.")) {
166            // 1. MTK only works on 4.3 and above
167            // 2. MTK works on MIUI 6 (4.2.1)
168            // 3. MTK still not ok when mpeg4
169            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2 || name.endsWith("decoder.mpeg4")) {
170                rank = RANK_NO_SENSE;
171            } else {
172                rank = RANK_TESTED;
173            }
174        } else {
175            Integer knownRank = getKnownCodecList().get(name);
176            if (knownRank != null) {
177                rank = knownRank;
178            } else {
179                try {
180                    CodecCapabilities cap = codecInfo.getCapabilitiesForType(mimeType);
181                    if (cap != null) {
182                        rank = RANK_ACCEPTABLE;
183                    } else {
184                        rank = RANK_LAST_CHANCE;
185                    }
186                } catch (Throwable e) {
187                    rank = RANK_LAST_CHANCE;
188                }
189            }
190        }
191
192        BDCloudMediaCodecInfo candidate = new BDCloudMediaCodecInfo();
193        candidate.mCodecInfo = codecInfo;
194        candidate.mRank = rank;
195        candidate.mMimeType = mimeType;
196        return candidate;
197    }
198
199    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
200    public void dumpProfileLevels(String mimeType) {
201        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
202            return;
203        }
204
205        try {
206            CodecCapabilities caps = mCodecInfo.getCapabilitiesForType(mimeType);
207            int maxProfile = 0;
208            int maxLevel = 0;
209            if (caps != null) {
210                if (caps.profileLevels != null) {
211                    for (CodecProfileLevel profileLevel : caps.profileLevels) {
212                        if (profileLevel == null) {
213                            continue;
214                        }
215
216                        maxProfile = Math.max(maxProfile, profileLevel.profile);
217                        maxLevel = Math.max(maxLevel, profileLevel.level);
218                    }
219                }
220            }
221
222            Log.i(TAG, String.format(Locale.US, "%s", getProfileLevelName(maxProfile, maxLevel)));
223        } catch (Throwable e) {
224            Log.i(TAG, "profile-level: exception");
225        }
226    }
227
228    public static String getProfileLevelName(int profile, int level) {
229        return String.format(Locale.US, " %s Profile Level %s (%d,%d)", getProfileName(profile), getLevelName(level),
230                profile, level);
231    }
232
233    public static String getProfileName(int profile) {
234        switch (profile) {
235            case CodecProfileLevel.AVCProfileBaseline:
236                return "Baseline";
237            case CodecProfileLevel.AVCProfileMain:
238                return "Main";
239            case CodecProfileLevel.AVCProfileExtended:
240                return "Extends";
241            case CodecProfileLevel.AVCProfileHigh:
242                return "High";
243            case CodecProfileLevel.AVCProfileHigh10:
244                return "High10";
245            case CodecProfileLevel.AVCProfileHigh422:
246                return "High422";
247            case CodecProfileLevel.AVCProfileHigh444:
248                return "High444";
249            default:
250                return "Unknown";
251        }
252    }
253
254    public static String getLevelName(int level) {
255        switch (level) {
256            case CodecProfileLevel.AVCLevel1:
257                return "1";
258            case CodecProfileLevel.AVCLevel1b:
259                return "1b";
260            case CodecProfileLevel.AVCLevel11:
261                return "11";
262            case CodecProfileLevel.AVCLevel12:
263                return "12";
264            case CodecProfileLevel.AVCLevel13:
265                return "13";
266            case CodecProfileLevel.AVCLevel2:
267                return "2";
268            case CodecProfileLevel.AVCLevel21:
269                return "21";
270            case CodecProfileLevel.AVCLevel22:
271                return "22";
272            case CodecProfileLevel.AVCLevel3:
273                return "3";
274            case CodecProfileLevel.AVCLevel31:
275                return "31";
276            case CodecProfileLevel.AVCLevel32:
277                return "32";
278            case CodecProfileLevel.AVCLevel4:
279                return "4";
280            case CodecProfileLevel.AVCLevel41:
281                return "41";
282            case CodecProfileLevel.AVCLevel42:
283                return "42";
284            case CodecProfileLevel.AVCLevel5:
285                return "5";
286            case CodecProfileLevel.AVCLevel51:
287                return "51";
288            case 65536: // CodecProfileLevel.AVCLevel52:
289                return "52";
290            default:
291                return "0";
292        }
293    }
294}