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 |
(...skipping 11 matching lines...) Expand all Loading... | |
22 | 22 |
23 using base::android::AttachCurrentThread; | 23 using base::android::AttachCurrentThread; |
24 using base::android::ConvertJavaStringToUTF8; | 24 using base::android::ConvertJavaStringToUTF8; |
25 using base::android::ConvertUTF8ToJavaString; | 25 using base::android::ConvertUTF8ToJavaString; |
26 using base::android::JavaIntArrayToIntVector; | 26 using base::android::JavaIntArrayToIntVector; |
27 using base::android::JavaRef; | 27 using base::android::JavaRef; |
28 using base::android::ScopedJavaLocalRef; | 28 using base::android::ScopedJavaLocalRef; |
29 | 29 |
30 namespace media { | 30 namespace media { |
31 | 31 |
32 namespace { | 32 namespace mime_type { |
liberato (no reviews please)
2017/02/14 17:44:11
these seem to be alternately named "android mime t
DaleCurtis
2017/02/14 18:10:32
I feel like these should share the values we have
watk
2017/02/14 23:28:57
I agree, but didn't see an obvious way to share, s
| |
33 | 33 const char kMp3[] = "audio/mpeg"; |
34 const char kMp4aMimeType[] = "audio/mp4a-latm"; | 34 const char kAac[] = "audio/mp4a-latm"; |
35 const char kOpusMimeType[] = "audio/opus"; | 35 const char kOpus[] = "audio/opus"; |
36 const char kVorbisMimeType[] = "audio/vorbis"; | 36 const char kVorbis[] = "audio/vorbis"; |
37 const char kAc3MimeType[] = "audio/ac3"; | 37 const char kAc3[] = "audio/ac3"; |
38 const char kEac3MimeType[] = "audio/eac3"; | 38 const char kEac3[] = "audio/eac3"; |
39 const char kAvcMimeType[] = "video/avc"; | 39 const char kAvc[] = "video/avc"; |
40 const char kHevcMimeType[] = "video/hevc"; | 40 const char kHevc[] = "video/hevc"; |
41 const char kVp8MimeType[] = "video/x-vnd.on2.vp8"; | 41 const char kVp8[] = "video/x-vnd.on2.vp8"; |
42 const char kVp9MimeType[] = "video/x-vnd.on2.vp9"; | 42 const char kVp9[] = "video/x-vnd.on2.vp9"; |
43 | 43 } // namespace mime_type |
44 } // namespace | |
45 | |
46 static std::string CodecTypeToAndroidMimeType(const std::string& codec) { | |
47 // TODO(xhwang): Shall we handle more detailed strings like "mp4a.40.2"? | |
48 if (codec == "avc1") | |
49 return kAvcMimeType; | |
50 if (codec == "hvc1") | |
51 return kHevcMimeType; | |
52 if (codec == "mp4a") | |
53 return kMp4aMimeType; | |
54 if (codec == "vp8" || codec == "vp8.0") | |
55 return kVp8MimeType; | |
56 if (codec == "vp9" || codec == "vp9.0") | |
57 return kVp9MimeType; | |
58 if (codec == "vorbis") | |
59 return kVorbisMimeType; | |
60 if (codec == "opus") | |
61 return kOpusMimeType; | |
62 if (codec == "ac3") | |
63 return kAc3MimeType; | |
64 if (codec == "eac3") | |
65 return kEac3MimeType; | |
66 | |
67 DLOG(WARNING) << "Cannot convert codec to Android MIME type: " << codec; | |
68 return std::string(); | |
69 } | |
70 | |
71 static VideoCodec AndroidCodecToCodecEnum(const std::string& codec) { | |
72 if (codec == "AVC") | |
73 return kCodecH264; | |
74 if (codec == "VP8") | |
75 return kCodecVP8; | |
76 if (codec == "VP9") | |
77 return kCodecVP9; | |
78 if (codec == "HEVC") | |
79 return kCodecHEVC; | |
80 DLOG(WARNING) << "Unknown video codec name \"" << codec << "\""; | |
81 return kUnknownVideoCodec; | |
82 } | |
83 | 44 |
84 static CodecProfileLevel MediaCodecProfileLevelToChromiumProfileLevel( | 45 static CodecProfileLevel MediaCodecProfileLevelToChromiumProfileLevel( |
85 JNIEnv* env, | 46 JNIEnv* env, |
86 const jobject& j_codec_profile_level) { | 47 const jobject& j_codec_profile_level) { |
87 ScopedJavaLocalRef<jstring> codec = | 48 VideoCodec codec = static_cast<VideoCodec>( |
88 Java_CodecProfileLevelAdapter_getCodec(env, j_codec_profile_level); | 49 Java_CodecProfileLevelAdapter_getCodec(env, j_codec_profile_level)); |
89 int profile = | 50 VideoCodecProfile profile = static_cast<VideoCodecProfile>( |
90 Java_CodecProfileLevelAdapter_getProfile(env, j_codec_profile_level); | 51 Java_CodecProfileLevelAdapter_getProfile(env, j_codec_profile_level)); |
91 int level = | 52 int level = |
92 Java_CodecProfileLevelAdapter_getLevel(env, j_codec_profile_level); | 53 Java_CodecProfileLevelAdapter_getLevel(env, j_codec_profile_level); |
93 return {AndroidCodecToCodecEnum(ConvertJavaStringToUTF8(codec)), | 54 return {codec, profile, level}; |
94 static_cast<VideoCodecProfile>(profile), level}; | |
95 } | 55 } |
96 | 56 |
97 static bool IsSupportedAndroidMimeType(const std::string& mime_type) { | 57 static bool IsSupportedAndroidMimeType(const std::string& mime_type) { |
98 std::vector<std::string> supported{ | 58 std::vector<std::string> supported{ |
99 kMp4aMimeType, kOpusMimeType, kVorbisMimeType, kAvcMimeType, | 59 mime_type::kMp3, mime_type::kAac, mime_type::kOpus, mime_type::kVorbis, |
watk
2017/02/14 23:35:56
I added mp3 here, because I didn't know why it wou
DaleCurtis
2017/02/14 23:44:43
Probably because there are no protected content mp
| |
100 kHevcMimeType, kVp8MimeType, kVp9MimeType}; | 60 mime_type::kAvc, mime_type::kHevc, mime_type::kVp8, mime_type::kVp9}; |
101 return std::find(supported.begin(), supported.end(), mime_type) != | 61 return std::find(supported.begin(), supported.end(), mime_type) != |
102 supported.end(); | 62 supported.end(); |
103 } | 63 } |
104 | 64 |
105 static std::string GetDefaultCodecName(const std::string& mime_type, | 65 static std::string GetDefaultCodecName(const std::string& mime_type, |
106 MediaCodecDirection direction, | 66 MediaCodecDirection direction, |
107 bool require_software_codec) { | 67 bool require_software_codec) { |
108 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); | 68 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); |
109 JNIEnv* env = AttachCurrentThread(); | 69 JNIEnv* env = AttachCurrentThread(); |
110 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime_type); | 70 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime_type); |
111 ScopedJavaLocalRef<jstring> j_codec_name = | 71 ScopedJavaLocalRef<jstring> j_codec_name = |
112 Java_MediaCodecUtil_getDefaultCodecName(env, j_mime, direction, | 72 Java_MediaCodecUtil_getDefaultCodecName( |
113 require_software_codec); | 73 env, j_mime, static_cast<int>(direction), require_software_codec); |
114 return ConvertJavaStringToUTF8(env, j_codec_name.obj()); | 74 return ConvertJavaStringToUTF8(env, j_codec_name.obj()); |
115 } | 75 } |
116 | 76 |
117 static bool IsDecoderSupportedByDevice(const std::string& android_mime_type) { | 77 static bool IsDecoderSupportedByDevice(const std::string& android_mime_type) { |
118 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); | 78 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); |
119 DCHECK(IsSupportedAndroidMimeType(android_mime_type)); | 79 DCHECK(IsSupportedAndroidMimeType(android_mime_type)); |
120 JNIEnv* env = AttachCurrentThread(); | 80 JNIEnv* env = AttachCurrentThread(); |
121 ScopedJavaLocalRef<jstring> j_mime = | 81 ScopedJavaLocalRef<jstring> j_mime = |
122 ConvertUTF8ToJavaString(env, android_mime_type); | 82 ConvertUTF8ToJavaString(env, android_mime_type); |
123 return Java_MediaCodecUtil_isDecoderSupportedForDevice(env, j_mime); | 83 return Java_MediaCodecUtil_isDecoderSupportedForDevice(env, j_mime); |
124 } | 84 } |
125 | 85 |
126 static bool IsEncoderSupportedByDevice(const std::string& android_mime_type) { | 86 static bool IsEncoderSupportedByDevice(const std::string& android_mime_type) { |
127 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); | 87 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); |
128 JNIEnv* env = AttachCurrentThread(); | 88 JNIEnv* env = AttachCurrentThread(); |
129 ScopedJavaLocalRef<jstring> j_mime = | 89 ScopedJavaLocalRef<jstring> j_mime = |
130 ConvertUTF8ToJavaString(env, android_mime_type); | 90 ConvertUTF8ToJavaString(env, android_mime_type); |
131 return Java_MediaCodecUtil_isEncoderSupportedByDevice(env, j_mime); | 91 return Java_MediaCodecUtil_isEncoderSupportedByDevice(env, j_mime); |
132 } | 92 } |
133 | 93 |
134 // static | 94 // static |
95 std::string MediaCodecUtil::CodecToAndroidMimeType(AudioCodec codec) { | |
96 switch (codec) { | |
97 case kCodecMP3: | |
98 return mime_type::kMp3; | |
99 case kCodecVorbis: | |
100 return mime_type::kVorbis; | |
101 case kCodecOpus: | |
102 return mime_type::kOpus; | |
103 case kCodecAAC: | |
104 return mime_type::kAac; | |
105 case kCodecAC3: | |
106 return mime_type::kAc3; | |
107 case kCodecEAC3: | |
108 return mime_type::kEac3; | |
109 default: | |
110 return std::string(); | |
111 } | |
112 } | |
113 | |
114 // static | |
115 std::string MediaCodecUtil::CodecToAndroidMimeType(VideoCodec codec) { | |
116 switch (codec) { | |
117 case kCodecH264: | |
118 return mime_type::kAvc; | |
119 case kCodecHEVC: | |
120 return mime_type::kHevc; | |
121 case kCodecVP8: | |
122 return mime_type::kVp8; | |
123 case kCodecVP9: | |
124 return mime_type::kVp9; | |
125 default: | |
126 return std::string(); | |
127 } | |
128 } | |
129 | |
130 // static | |
135 bool MediaCodecUtil::IsMediaCodecAvailable() { | 131 bool MediaCodecUtil::IsMediaCodecAvailable() { |
136 // Blacklist some devices on Jellybean as MediaCodec is buggy. | 132 // Blacklist some devices on Jellybean as MediaCodec is buggy. |
137 // http://crbug.com/365494, http://crbug.com/615872 | 133 // http://crbug.com/365494, http://crbug.com/615872 |
138 // Blacklist Lenovo A6600 / A6800 on KitKat, which tends to crash a lot. | 134 // Blacklist Lenovo A6600 / A6800 on KitKat, which tends to crash a lot. |
139 // See crbug.com/628059 . We include < K since they don't exist. | 135 // See crbug.com/628059 . We include < K since they don't exist. |
140 // Blacklist Samsung Galaxy Star Pro (GT-S7262) (crbug.com/634920). | 136 // Blacklist Samsung Galaxy Star Pro (GT-S7262) (crbug.com/634920). |
141 // GT-S5282 and GT-I8552 are for crbug.com/634920 . | 137 // GT-S5282 and GT-I8552 are for crbug.com/634920 . |
142 if (base::android::BuildInfo::GetInstance()->sdk_int() <= 19) { | 138 if (base::android::BuildInfo::GetInstance()->sdk_int() <= 19) { |
143 std::string model(base::android::BuildInfo::GetInstance()->model()); | 139 std::string model(base::android::BuildInfo::GetInstance()->model()); |
144 return model != "GT-I9100" && model != "GT-I9300" && model != "GT-N7000" && | 140 return model != "GT-I9100" && model != "GT-I9300" && model != "GT-N7000" && |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
176 if (j_color_format_array.obj()) { | 172 if (j_color_format_array.obj()) { |
177 std::vector<int> formats; | 173 std::vector<int> formats; |
178 JavaIntArrayToIntVector(env, j_color_format_array.obj(), &formats); | 174 JavaIntArrayToIntVector(env, j_color_format_array.obj(), &formats); |
179 color_formats = std::set<int>(formats.begin(), formats.end()); | 175 color_formats = std::set<int>(formats.begin(), formats.end()); |
180 } | 176 } |
181 | 177 |
182 return color_formats; | 178 return color_formats; |
183 } | 179 } |
184 | 180 |
185 // static | 181 // static |
186 bool MediaCodecUtil::CanDecode(const std::string& codec, bool is_secure) { | 182 bool MediaCodecUtil::CanDecode(const std::string& mime, bool is_secure) { |
187 if (!IsMediaCodecAvailable()) | 183 if (!IsMediaCodecAvailable()) |
188 return false; | 184 return false; |
185 if (mime.empty()) | |
186 return false; | |
189 | 187 |
190 JNIEnv* env = AttachCurrentThread(); | 188 JNIEnv* env = AttachCurrentThread(); |
191 std::string mime = CodecTypeToAndroidMimeType(codec); | |
192 if (mime.empty()) | |
193 return false; | |
194 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); | 189 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); |
195 return Java_MediaCodecUtil_canDecode(env, j_mime, is_secure); | 190 return Java_MediaCodecUtil_canDecode(env, j_mime, is_secure); |
196 } | 191 } |
197 | 192 |
198 // static | 193 // static |
199 bool MediaCodecUtil::AddSupportedCodecProfileLevels( | 194 bool MediaCodecUtil::AddSupportedCodecProfileLevels( |
200 std::vector<CodecProfileLevel>* result) { | 195 std::vector<CodecProfileLevel>* result) { |
201 DCHECK(result); | 196 DCHECK(result); |
202 if (!IsMediaCodecAvailable()) | 197 if (!IsMediaCodecAvailable()) |
203 return false; | 198 return false; |
204 JNIEnv* env = AttachCurrentThread(); | 199 JNIEnv* env = AttachCurrentThread(); |
205 ScopedJavaLocalRef<jobjectArray> j_codec_profile_levels( | 200 ScopedJavaLocalRef<jobjectArray> j_codec_profile_levels( |
206 Java_MediaCodecUtil_getSupportedCodecProfileLevels(env)); | 201 Java_MediaCodecUtil_getSupportedCodecProfileLevels(env)); |
207 int java_array_length = env->GetArrayLength(j_codec_profile_levels.obj()); | 202 int java_array_length = env->GetArrayLength(j_codec_profile_levels.obj()); |
208 for (int i = 0; i < java_array_length; ++i) { | 203 for (int i = 0; i < java_array_length; ++i) { |
209 const jobject& java_codec_profile_level = | 204 const jobject& java_codec_profile_level = |
210 env->GetObjectArrayElement(j_codec_profile_levels.obj(), i); | 205 env->GetObjectArrayElement(j_codec_profile_levels.obj(), i); |
211 result->push_back(MediaCodecProfileLevelToChromiumProfileLevel( | 206 result->push_back(MediaCodecProfileLevelToChromiumProfileLevel( |
212 env, java_codec_profile_level)); | 207 env, java_codec_profile_level)); |
213 } | 208 } |
214 return true; | 209 return true; |
215 } | 210 } |
216 | 211 |
217 // static | 212 // static |
218 bool MediaCodecUtil::IsKnownUnaccelerated(const std::string& android_mime_type, | 213 bool MediaCodecUtil::IsKnownUnaccelerated(VideoCodec codec, |
219 MediaCodecDirection direction) { | 214 MediaCodecDirection direction) { |
220 DCHECK(IsSupportedAndroidMimeType(android_mime_type)); | |
221 if (!IsMediaCodecAvailable()) | 215 if (!IsMediaCodecAvailable()) |
222 return true; | 216 return true; |
223 | 217 |
224 std::string codec_name = | 218 std::string codec_name = |
225 GetDefaultCodecName(android_mime_type, direction, false); | 219 GetDefaultCodecName(CodecToAndroidMimeType(codec), direction, false); |
226 DVLOG(1) << __func__ << "Default codec for " << android_mime_type << " : " | 220 DVLOG(1) << __func__ << "Default codec for " << GetCodecName(codec) << " : " |
227 << codec_name << ", direction: " << direction; | 221 << codec_name << ", direction: " << static_cast<int>(direction); |
228 if (codec_name.empty()) | 222 if (codec_name.empty()) |
229 return true; | 223 return true; |
230 | 224 |
231 // MediaTek hardware vp8 is known slower than the software implementation. | 225 // MediaTek hardware vp8 is known slower than the software implementation. |
232 // MediaTek hardware vp9 is known crashy, see http://crbug.com/446974 and | 226 // MediaTek hardware vp9 is known crashy, see http://crbug.com/446974 and |
233 // http://crbug.com/597836. | 227 // http://crbug.com/597836. |
234 if (base::StartsWith(codec_name, "OMX.MTK.", base::CompareCase::SENSITIVE)) { | 228 if (base::StartsWith(codec_name, "OMX.MTK.", base::CompareCase::SENSITIVE)) { |
235 if (android_mime_type == kVp8MimeType) | 229 if (codec == kCodecVP8) |
236 return true; | 230 return true; |
237 | 231 |
238 if (android_mime_type == kVp9MimeType) | 232 if (codec == kCodecVP9) |
239 return base::android::BuildInfo::GetInstance()->sdk_int() < 21; | 233 return base::android::BuildInfo::GetInstance()->sdk_int() < 21; |
240 | 234 |
241 return false; | 235 return false; |
242 } | 236 } |
243 | 237 |
244 // It would be nice if MediaCodecInfo externalized some notion of | 238 // It would be nice if MediaCodecInfo externalized some notion of |
245 // HW-acceleration but it doesn't. Android Media guidance is that the | 239 // HW-acceleration but it doesn't. Android Media guidance is that the |
246 // "OMX.google" prefix is always used for SW decoders, so that's what we | 240 // "OMX.google" prefix is always used for SW decoders, so that's what we |
247 // use. "OMX.SEC.*" codec is Samsung software implementation - report it | 241 // use. "OMX.SEC.*" codec is Samsung software implementation - report it |
248 // as unaccelerated as well. | 242 // as unaccelerated as well. |
(...skipping 10 matching lines...) Expand all Loading... | |
259 } | 253 } |
260 | 254 |
261 // static | 255 // static |
262 bool MediaCodecUtil::IsHLSURL(const GURL& url) { | 256 bool MediaCodecUtil::IsHLSURL(const GURL& url) { |
263 return (url.SchemeIsHTTPOrHTTPS() || url.SchemeIsFile()) && | 257 return (url.SchemeIsHTTPOrHTTPS() || url.SchemeIsFile()) && |
264 url.spec().find("m3u8") != std::string::npos; | 258 url.spec().find("m3u8") != std::string::npos; |
265 } | 259 } |
266 | 260 |
267 // static | 261 // static |
268 bool MediaCodecUtil::IsVp8DecoderAvailable() { | 262 bool MediaCodecUtil::IsVp8DecoderAvailable() { |
269 return IsMediaCodecAvailable() && IsDecoderSupportedByDevice(kVp8MimeType); | 263 return IsMediaCodecAvailable() && IsDecoderSupportedByDevice(mime_type::kVp8); |
270 } | 264 } |
271 | 265 |
272 // static | 266 // static |
273 bool MediaCodecUtil::IsVp8EncoderAvailable() { | 267 bool MediaCodecUtil::IsVp8EncoderAvailable() { |
274 // Currently the vp8 encoder and decoder blacklists cover the same devices, | 268 // Currently the vp8 encoder and decoder blacklists cover the same devices, |
275 // but we have a second method for clarity in future issues. | 269 // but we have a second method for clarity in future issues. |
276 return IsVp8DecoderAvailable(); | 270 return IsVp8DecoderAvailable(); |
277 } | 271 } |
278 | 272 |
279 // static | 273 // static |
280 bool MediaCodecUtil::IsVp9DecoderAvailable() { | 274 bool MediaCodecUtil::IsVp9DecoderAvailable() { |
281 return IsMediaCodecAvailable() && IsDecoderSupportedByDevice(kVp9MimeType); | 275 return IsMediaCodecAvailable() && IsDecoderSupportedByDevice(mime_type::kVp9); |
282 } | 276 } |
283 | 277 |
284 // static | 278 // static |
285 bool MediaCodecUtil::IsH264EncoderAvailable() { | 279 bool MediaCodecUtil::IsH264EncoderAvailable() { |
286 return IsMediaCodecAvailable() && IsEncoderSupportedByDevice(kAvcMimeType); | 280 return IsMediaCodecAvailable() && IsEncoderSupportedByDevice(mime_type::kAvc); |
287 } | 281 } |
288 | 282 |
289 // static | 283 // static |
290 bool MediaCodecUtil::IsSurfaceViewOutputSupported() { | 284 bool MediaCodecUtil::IsSurfaceViewOutputSupported() { |
291 // Disable SurfaceView output for the Samsung Galaxy S3; it does not work | 285 // Disable SurfaceView output for the Samsung Galaxy S3; it does not work |
292 // well enough for even 360p24 H264 playback. http://crbug.com/602870. | 286 // well enough for even 360p24 H264 playback. http://crbug.com/602870. |
293 // | 287 // |
294 // Notably this is codec agnostic at present, so any devices added to | 288 // Notably this is codec agnostic at present, so any devices added to |
295 // the blacklist will avoid trying to play any codecs on SurfaceView. If | 289 // the blacklist will avoid trying to play any codecs on SurfaceView. If |
296 // needed in the future this can be expanded to be codec specific. | 290 // needed in the future this can be expanded to be codec specific. |
(...skipping 29 matching lines...) Expand all Loading... | |
326 (sdk_int == 18 && ("OMX.SEC.avc.dec" == codec_name || | 320 (sdk_int == 18 && ("OMX.SEC.avc.dec" == codec_name || |
327 "OMX.SEC.avc.dec.secure" == codec_name)) || | 321 "OMX.SEC.avc.dec.secure" == codec_name)) || |
328 (sdk_int == 19 && | 322 (sdk_int == 19 && |
329 base::StartsWith(base::android::BuildInfo::GetInstance()->model(), | 323 base::StartsWith(base::android::BuildInfo::GetInstance()->model(), |
330 "SM-G800", base::CompareCase::INSENSITIVE_ASCII) && | 324 "SM-G800", base::CompareCase::INSENSITIVE_ASCII) && |
331 ("OMX.Exynos.avc.dec" == codec_name || | 325 ("OMX.Exynos.avc.dec" == codec_name || |
332 "OMX.Exynos.avc.dec.secure" == codec_name)); | 326 "OMX.Exynos.avc.dec.secure" == codec_name)); |
333 } | 327 } |
334 | 328 |
335 } // namespace media | 329 } // namespace media |
OLD | NEW |