OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/base/android/media_codec_util.h" | 5 #include "media/base/android/media_codec_util.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 | 10 |
11 #include "base/android/build_info.h" | 11 #include "base/android/build_info.h" |
12 #include "base/android/jni_android.h" | 12 #include "base/android/jni_android.h" |
13 #include "base/android/jni_array.h" | 13 #include "base/android/jni_array.h" |
14 #include "base/android/jni_string.h" | 14 #include "base/android/jni_string.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/strings/string_util.h" | 16 #include "base/strings/string_util.h" |
17 #include "jni/MediaCodecUtil_jni.h" | 17 #include "jni/MediaCodecUtil_jni.h" |
18 #include "url/gurl.h" | 18 #include "url/gurl.h" |
19 | 19 |
20 using base::android::AttachCurrentThread; | 20 using base::android::AttachCurrentThread; |
21 using base::android::ConvertJavaStringToUTF8; | 21 using base::android::ConvertJavaStringToUTF8; |
22 using base::android::ConvertUTF8ToJavaString; | 22 using base::android::ConvertUTF8ToJavaString; |
23 using base::android::JavaIntArrayToIntVector; | 23 using base::android::JavaIntArrayToIntVector; |
24 using base::android::ScopedJavaLocalRef; | 24 using base::android::ScopedJavaLocalRef; |
25 | 25 |
26 namespace media { | 26 namespace media { |
27 | 27 |
28 // static | 28 static std::string CodecTypeToAndroidMimeType(const std::string& codec) { |
29 const std::string CodecTypeToAndroidMimeType(const std::string& codec) { | |
30 // TODO(xhwang): Shall we handle more detailed strings like "mp4a.40.2"? | 29 // TODO(xhwang): Shall we handle more detailed strings like "mp4a.40.2"? |
31 if (codec == "avc1") | 30 if (codec == "avc1") |
32 return "video/avc"; | 31 return "video/avc"; |
33 if (codec == "hvc1") | 32 if (codec == "hvc1") |
34 return "video/hevc"; | 33 return "video/hevc"; |
35 if (codec == "mp4a") | 34 if (codec == "mp4a") |
36 return "audio/mp4a-latm"; | 35 return "audio/mp4a-latm"; |
37 if (codec == "vp8" || codec == "vp8.0") | 36 if (codec == "vp8" || codec == "vp8.0") |
38 return "video/x-vnd.on2.vp8"; | 37 return "video/x-vnd.on2.vp8"; |
39 if (codec == "vp9" || codec == "vp9.0") | 38 if (codec == "vp9" || codec == "vp9.0") |
40 return "video/x-vnd.on2.vp9"; | 39 return "video/x-vnd.on2.vp9"; |
41 if (codec == "vorbis") | 40 if (codec == "vorbis") |
42 return "audio/vorbis"; | 41 return "audio/vorbis"; |
43 if (codec == "opus") | 42 if (codec == "opus") |
44 return "audio/opus"; | 43 return "audio/opus"; |
45 return std::string(); | 44 return std::string(); |
46 } | 45 } |
47 | 46 |
48 // TODO(qinmin): using a map to help all the conversions in this class. | 47 static std::string GetDefaultCodecName(const std::string& mime_type, |
49 const std::string AndroidMimeTypeToCodecType(const std::string& mime) { | 48 MediaCodecDirection direction) { |
50 if (mime == "video/mp4v-es") | 49 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); |
51 return "mp4v"; | |
52 if (mime == "video/avc") | |
53 return "avc1"; | |
54 if (mime == "video/hevc") | |
55 return "hvc1"; | |
56 if (mime == "video/x-vnd.on2.vp8") | |
57 return "vp8"; | |
58 if (mime == "video/x-vnd.on2.vp9") | |
59 return "vp9"; | |
60 if (mime == "audio/mp4a-latm") | |
61 return "mp4a"; | |
62 if (mime == "audio/mpeg") | |
63 return "mp3"; | |
64 if (mime == "audio/vorbis") | |
65 return "vorbis"; | |
66 if (mime == "audio/opus") | |
67 return "opus"; | |
68 return std::string(); | |
69 } | |
70 | |
71 std::string GetDefaultCodecName(const std::string& mime_type, | |
72 MediaCodecDirection direction) { | |
73 if (!MediaCodecUtil::IsMediaCodecAvailable()) | |
74 return std::string(); | |
75 | |
76 JNIEnv* env = AttachCurrentThread(); | 50 JNIEnv* env = AttachCurrentThread(); |
77 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime_type); | 51 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime_type); |
78 ScopedJavaLocalRef<jstring> j_codec_name = | 52 ScopedJavaLocalRef<jstring> j_codec_name = |
79 Java_MediaCodecUtil_getDefaultCodecName(env, j_mime.obj(), direction); | 53 Java_MediaCodecUtil_getDefaultCodecName(env, j_mime.obj(), direction); |
80 return ConvertJavaStringToUTF8(env, j_codec_name.obj()); | 54 return ConvertJavaStringToUTF8(env, j_codec_name.obj()); |
81 } | 55 } |
82 | 56 |
83 bool SupportsGetName() { | |
84 // MediaCodec.getName() is only available on JB MR2 and greater. | |
85 return base::android::BuildInfo::GetInstance()->sdk_int() >= 18; | |
86 } | |
87 | |
88 // Represents supported codecs on android. | |
89 // TODO(qinmin): Currently the codecs string only contains one codec. Do we | |
90 // need to support codecs separated by comma. (e.g. "vp8" -> "vp8, vp8.0")? | |
91 struct CodecsInfo { | |
92 std::string codecs; // E.g. "vp8" or "avc1". | |
93 std::string name; // E.g. "OMX.google.vp8.decoder". | |
94 MediaCodecDirection direction; | |
95 }; | |
96 | |
97 // Get a list of supported codecs. | |
98 std::vector<CodecsInfo> GetCodecsInfo() { | |
99 std::vector<CodecsInfo> codecs_info; | |
100 if (!MediaCodecUtil::IsMediaCodecAvailable()) | |
101 return codecs_info; | |
102 | |
103 JNIEnv* env = AttachCurrentThread(); | |
104 std::string mime_type; | |
105 ScopedJavaLocalRef<jobjectArray> j_codec_info_array = | |
106 Java_MediaCodecUtil_getCodecsInfo(env); | |
107 jsize len = env->GetArrayLength(j_codec_info_array.obj()); | |
108 for (jsize i = 0; i < len; ++i) { | |
109 ScopedJavaLocalRef<jobject> j_info( | |
110 env, env->GetObjectArrayElement(j_codec_info_array.obj(), i)); | |
111 ScopedJavaLocalRef<jstring> j_codec_type = | |
112 Java_CodecInfo_codecType(env, j_info.obj()); | |
113 ConvertJavaStringToUTF8(env, j_codec_type.obj(), &mime_type); | |
114 ScopedJavaLocalRef<jstring> j_codec_name = | |
115 Java_CodecInfo_codecName(env, j_info.obj()); | |
116 CodecsInfo info; | |
117 info.codecs = AndroidMimeTypeToCodecType(mime_type); | |
118 ConvertJavaStringToUTF8(env, j_codec_name.obj(), &info.name); | |
119 info.direction = static_cast<MediaCodecDirection>( | |
120 Java_CodecInfo_direction(env, j_info.obj())); | |
121 codecs_info.push_back(info); | |
122 } | |
123 return codecs_info; | |
124 } | |
125 | |
126 // static | 57 // static |
127 bool MediaCodecUtil::IsMediaCodecAvailable() { | 58 bool MediaCodecUtil::IsMediaCodecAvailable() { |
128 // MediaCodec is only available on JB and greater. | 59 // MediaCodec is only available on JB and greater. |
129 if (base::android::BuildInfo::GetInstance()->sdk_int() < 16) | 60 if (base::android::BuildInfo::GetInstance()->sdk_int() < 16) |
130 return false; | 61 return false; |
131 // Blacklist some devices on Jellybean as for MediaCodec support is buggy. | 62 // Blacklist some devices on Jellybean as for MediaCodec support is buggy. |
132 // http://crbug.com/365494. | 63 // http://crbug.com/365494. |
133 if (base::android::BuildInfo::GetInstance()->sdk_int() == 16) { | 64 if (base::android::BuildInfo::GetInstance()->sdk_int() == 16) { |
134 std::string model(base::android::BuildInfo::GetInstance()->model()); | 65 std::string model(base::android::BuildInfo::GetInstance()->model()); |
135 return model != "GT-I9100" && model != "GT-I9300" && model != "GT-N7000"; | 66 return model != "GT-I9100" && model != "GT-I9300" && model != "GT-N7000"; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
176 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); | 107 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); |
177 return Java_MediaCodecUtil_canDecode(env, j_mime.obj(), is_secure); | 108 return Java_MediaCodecUtil_canDecode(env, j_mime.obj(), is_secure); |
178 } | 109 } |
179 | 110 |
180 // static | 111 // static |
181 bool MediaCodecUtil::IsKnownUnaccelerated(const std::string& mime_type, | 112 bool MediaCodecUtil::IsKnownUnaccelerated(const std::string& mime_type, |
182 MediaCodecDirection direction) { | 113 MediaCodecDirection direction) { |
183 if (!IsMediaCodecAvailable()) | 114 if (!IsMediaCodecAvailable()) |
184 return true; | 115 return true; |
185 | 116 |
186 std::string codec_name; | 117 std::string codec_name = GetDefaultCodecName(mime_type, direction); |
187 if (SupportsGetName()) { | 118 DVLOG(1) << __FUNCTION__ << "Default codec for " << mime_type << " : " |
188 codec_name = GetDefaultCodecName(mime_type, direction); | 119 << codec_name << ", direction: " << direction; |
189 } else { | 120 |
190 std::string codec_type = AndroidMimeTypeToCodecType(mime_type); | |
191 std::vector<CodecsInfo> codecs_info = GetCodecsInfo(); | |
192 for (size_t i = 0; i < codecs_info.size(); ++i) { | |
193 if (codecs_info[i].codecs == codec_type && | |
194 codecs_info[i].direction == direction) { | |
195 codec_name = codecs_info[i].name; | |
196 break; | |
197 } | |
198 } | |
199 } | |
200 DVLOG(1) << __PRETTY_FUNCTION__ << "Default codec for " << mime_type << " : " | |
201 << codec_name; | |
202 // It would be nice if MediaCodecInfo externalized some notion of | 121 // It would be nice if MediaCodecInfo externalized some notion of |
203 // HW-acceleration but it doesn't. Android Media guidance is that the | 122 // HW-acceleration but it doesn't. Android Media guidance is that the |
204 // "OMX.google" prefix is always used for SW decoders, so that's what we | 123 // "OMX.google" prefix is always used for SW decoders, so that's what we |
205 // use. "OMX.SEC.*" codec is Samsung software implementation - report it | 124 // use. "OMX.SEC.*" codec is Samsung software implementation - report it |
206 // as unaccelerated as well. MediaTek hardware vp8 is known slower than | 125 // as unaccelerated as well. MediaTek hardware vp8 is known slower than |
207 // the software implementation. http://crbug.com/446974. | 126 // the software implementation. http://crbug.com/446974. |
208 if (codec_name.length() > 0) { | 127 return base::StartsWith(codec_name, "OMX.google.", |
Tima Vaisburd
2016/03/15 21:38:17
I think codec_name can be empty string?
In this ca
DaleCurtis
2016/03/15 23:02:45
Whoops, done.
| |
209 return base::StartsWith(codec_name, "OMX.google.", | 128 base::CompareCase::SENSITIVE) || |
210 base::CompareCase::SENSITIVE) || | 129 base::StartsWith(codec_name, "OMX.SEC.", |
211 base::StartsWith(codec_name, "OMX.SEC.", | 130 base::CompareCase::SENSITIVE) || |
212 base::CompareCase::SENSITIVE) || | 131 (base::StartsWith(codec_name, "OMX.MTK.", |
213 (base::StartsWith(codec_name, "OMX.MTK.", | 132 base::CompareCase::SENSITIVE) && |
214 base::CompareCase::SENSITIVE) && | 133 mime_type == "video/x-vnd.on2.vp8"); |
215 mime_type == "video/x-vnd.on2.vp8"); | |
216 } | |
217 return true; | |
218 } | 134 } |
219 | 135 |
220 // static | 136 // static |
221 bool MediaCodecUtil::IsHLSPath(const GURL& url) { | 137 bool MediaCodecUtil::IsHLSPath(const GURL& url) { |
222 if (!url.SchemeIsHTTPOrHTTPS() && !url.SchemeIsFile()) | 138 if (!url.SchemeIsHTTPOrHTTPS() && !url.SchemeIsFile()) |
223 return false; | 139 return false; |
224 | 140 |
225 std::string path = url.path(); | 141 std::string path = url.path(); |
226 return base::EndsWith(path, ".m3u8", base::CompareCase::INSENSITIVE_ASCII); | 142 return base::EndsWith(path, ".m3u8", base::CompareCase::INSENSITIVE_ASCII); |
227 } | 143 } |
(...skipping 26 matching lines...) Expand all Loading... | |
254 } | 170 } |
255 | 171 |
256 // static | 172 // static |
257 bool MediaCodecUtil::IsVp8EncoderAvailable() { | 173 bool MediaCodecUtil::IsVp8EncoderAvailable() { |
258 // Currently the vp8 encoder and decoder blacklists cover the same devices, | 174 // Currently the vp8 encoder and decoder blacklists cover the same devices, |
259 // but we have a second method for clarity in future issues. | 175 // but we have a second method for clarity in future issues. |
260 return IsVp8DecoderAvailable(); | 176 return IsVp8DecoderAvailable(); |
261 } | 177 } |
262 | 178 |
263 } // namespace media | 179 } // namespace media |
OLD | NEW |