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 #include <vector> | 10 #include <vector> |
(...skipping 17 matching lines...) Expand all Loading... |
28 using base::android::JavaIntArrayToIntVector; | 28 using base::android::JavaIntArrayToIntVector; |
29 using base::android::JavaRef; | 29 using base::android::JavaRef; |
30 using base::android::ScopedJavaLocalRef; | 30 using base::android::ScopedJavaLocalRef; |
31 using base::android::SDK_VERSION_JELLY_BEAN_MR2; | 31 using base::android::SDK_VERSION_JELLY_BEAN_MR2; |
32 using base::android::SDK_VERSION_KITKAT; | 32 using base::android::SDK_VERSION_KITKAT; |
33 using base::android::SDK_VERSION_LOLLIPOP_MR1; | 33 using base::android::SDK_VERSION_LOLLIPOP_MR1; |
34 | 34 |
35 namespace media { | 35 namespace media { |
36 | 36 |
37 namespace { | 37 namespace { |
38 | 38 const char kMp3MimeType[] = "audio/mpeg"; |
39 const char kMp4aMimeType[] = "audio/mp4a-latm"; | 39 const char kAacMimeType[] = "audio/mp4a-latm"; |
40 const char kOpusMimeType[] = "audio/opus"; | 40 const char kOpusMimeType[] = "audio/opus"; |
41 const char kVorbisMimeType[] = "audio/vorbis"; | 41 const char kVorbisMimeType[] = "audio/vorbis"; |
42 const char kAc3MimeType[] = "audio/ac3"; | 42 const char kAc3MimeType[] = "audio/ac3"; |
43 const char kEac3MimeType[] = "audio/eac3"; | 43 const char kEac3MimeType[] = "audio/eac3"; |
44 const char kAvcMimeType[] = "video/avc"; | 44 const char kAvcMimeType[] = "video/avc"; |
45 const char kHevcMimeType[] = "video/hevc"; | 45 const char kHevcMimeType[] = "video/hevc"; |
46 const char kVp8MimeType[] = "video/x-vnd.on2.vp8"; | 46 const char kVp8MimeType[] = "video/x-vnd.on2.vp8"; |
47 const char kVp9MimeType[] = "video/x-vnd.on2.vp9"; | 47 const char kVp9MimeType[] = "video/x-vnd.on2.vp9"; |
48 | |
49 } // namespace | 48 } // namespace |
50 | 49 |
51 static std::string CodecTypeToAndroidMimeType(const std::string& codec) { | |
52 // TODO(xhwang): Shall we handle more detailed strings like "mp4a.40.2"? | |
53 if (codec == "avc1") | |
54 return kAvcMimeType; | |
55 if (codec == "hvc1") | |
56 return kHevcMimeType; | |
57 if (codec == "mp4a") | |
58 return kMp4aMimeType; | |
59 if (codec == "vp8" || codec == "vp8.0") | |
60 return kVp8MimeType; | |
61 if (codec == "vp9" || codec == "vp9.0") | |
62 return kVp9MimeType; | |
63 if (codec == "vorbis") | |
64 return kVorbisMimeType; | |
65 if (codec == "opus") | |
66 return kOpusMimeType; | |
67 if (codec == "ac3") | |
68 return kAc3MimeType; | |
69 if (codec == "eac3") | |
70 return kEac3MimeType; | |
71 | |
72 DLOG(WARNING) << "Cannot convert codec to Android MIME type: " << codec; | |
73 return std::string(); | |
74 } | |
75 | |
76 static VideoCodec AndroidCodecToCodecEnum(const std::string& codec) { | |
77 if (codec == "AVC") | |
78 return kCodecH264; | |
79 if (codec == "VP8") | |
80 return kCodecVP8; | |
81 if (codec == "VP9") | |
82 return kCodecVP9; | |
83 if (codec == "HEVC") | |
84 return kCodecHEVC; | |
85 DLOG(WARNING) << "Unknown video codec name \"" << codec << "\""; | |
86 return kUnknownVideoCodec; | |
87 } | |
88 | |
89 static CodecProfileLevel MediaCodecProfileLevelToChromiumProfileLevel( | 50 static CodecProfileLevel MediaCodecProfileLevelToChromiumProfileLevel( |
90 JNIEnv* env, | 51 JNIEnv* env, |
91 const jobject& j_codec_profile_level) { | 52 const jobject& j_codec_profile_level) { |
92 ScopedJavaLocalRef<jstring> codec = | 53 VideoCodec codec = static_cast<VideoCodec>( |
93 Java_CodecProfileLevelAdapter_getCodec(env, j_codec_profile_level); | 54 Java_CodecProfileLevelAdapter_getCodec(env, j_codec_profile_level)); |
94 int profile = | 55 VideoCodecProfile profile = static_cast<VideoCodecProfile>( |
95 Java_CodecProfileLevelAdapter_getProfile(env, j_codec_profile_level); | 56 Java_CodecProfileLevelAdapter_getProfile(env, j_codec_profile_level)); |
96 int level = | 57 int level = |
97 Java_CodecProfileLevelAdapter_getLevel(env, j_codec_profile_level); | 58 Java_CodecProfileLevelAdapter_getLevel(env, j_codec_profile_level); |
98 return {AndroidCodecToCodecEnum(ConvertJavaStringToUTF8(codec)), | 59 return {codec, profile, level}; |
99 static_cast<VideoCodecProfile>(profile), level}; | |
100 } | 60 } |
101 | 61 |
102 static bool IsSupportedAndroidMimeType(const std::string& mime_type) { | 62 static bool IsSupportedAndroidMimeType(const std::string& mime_type) { |
103 std::vector<std::string> supported{ | 63 std::vector<std::string> supported{ |
104 kMp4aMimeType, kOpusMimeType, kVorbisMimeType, kAvcMimeType, | 64 kMp3MimeType, kAacMimeType, kOpusMimeType, kVorbisMimeType, |
105 kHevcMimeType, kVp8MimeType, kVp9MimeType}; | 65 kAvcMimeType, kHevcMimeType, kVp8MimeType, kVp9MimeType}; |
106 return std::find(supported.begin(), supported.end(), mime_type) != | 66 return std::find(supported.begin(), supported.end(), mime_type) != |
107 supported.end(); | 67 supported.end(); |
108 } | 68 } |
109 | 69 |
110 static std::string GetDefaultCodecName(const std::string& mime_type, | 70 static std::string GetDefaultCodecName(const std::string& mime_type, |
111 MediaCodecDirection direction, | 71 MediaCodecDirection direction, |
112 bool require_software_codec) { | 72 bool require_software_codec) { |
113 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); | 73 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); |
114 JNIEnv* env = AttachCurrentThread(); | 74 JNIEnv* env = AttachCurrentThread(); |
115 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime_type); | 75 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime_type); |
116 ScopedJavaLocalRef<jstring> j_codec_name = | 76 ScopedJavaLocalRef<jstring> j_codec_name = |
117 Java_MediaCodecUtil_getDefaultCodecName(env, j_mime, direction, | 77 Java_MediaCodecUtil_getDefaultCodecName( |
118 require_software_codec); | 78 env, j_mime, static_cast<int>(direction), require_software_codec); |
119 return ConvertJavaStringToUTF8(env, j_codec_name.obj()); | 79 return ConvertJavaStringToUTF8(env, j_codec_name.obj()); |
120 } | 80 } |
121 | 81 |
122 static bool IsDecoderSupportedByDevice(const std::string& android_mime_type) { | 82 static bool IsDecoderSupportedByDevice(const std::string& android_mime_type) { |
123 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); | 83 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); |
124 DCHECK(IsSupportedAndroidMimeType(android_mime_type)); | 84 DCHECK(IsSupportedAndroidMimeType(android_mime_type)); |
125 JNIEnv* env = AttachCurrentThread(); | 85 JNIEnv* env = AttachCurrentThread(); |
126 ScopedJavaLocalRef<jstring> j_mime = | 86 ScopedJavaLocalRef<jstring> j_mime = |
127 ConvertUTF8ToJavaString(env, android_mime_type); | 87 ConvertUTF8ToJavaString(env, android_mime_type); |
128 return Java_MediaCodecUtil_isDecoderSupportedForDevice(env, j_mime); | 88 return Java_MediaCodecUtil_isDecoderSupportedForDevice(env, j_mime); |
129 } | 89 } |
130 | 90 |
131 static bool IsEncoderSupportedByDevice(const std::string& android_mime_type) { | 91 static bool IsEncoderSupportedByDevice(const std::string& android_mime_type) { |
132 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); | 92 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); |
133 JNIEnv* env = AttachCurrentThread(); | 93 JNIEnv* env = AttachCurrentThread(); |
134 ScopedJavaLocalRef<jstring> j_mime = | 94 ScopedJavaLocalRef<jstring> j_mime = |
135 ConvertUTF8ToJavaString(env, android_mime_type); | 95 ConvertUTF8ToJavaString(env, android_mime_type); |
136 return Java_MediaCodecUtil_isEncoderSupportedByDevice(env, j_mime); | 96 return Java_MediaCodecUtil_isEncoderSupportedByDevice(env, j_mime); |
137 } | 97 } |
138 | 98 |
139 // static | 99 // static |
| 100 std::string MediaCodecUtil::CodecToAndroidMimeType(AudioCodec codec) { |
| 101 switch (codec) { |
| 102 case kCodecMP3: |
| 103 return kMp3MimeType; |
| 104 case kCodecVorbis: |
| 105 return kVorbisMimeType; |
| 106 case kCodecOpus: |
| 107 return kOpusMimeType; |
| 108 case kCodecAAC: |
| 109 return kAacMimeType; |
| 110 case kCodecAC3: |
| 111 return kAc3MimeType; |
| 112 case kCodecEAC3: |
| 113 return kEac3MimeType; |
| 114 default: |
| 115 return std::string(); |
| 116 } |
| 117 } |
| 118 |
| 119 // static |
| 120 std::string MediaCodecUtil::CodecToAndroidMimeType(VideoCodec codec) { |
| 121 switch (codec) { |
| 122 case kCodecH264: |
| 123 return kAvcMimeType; |
| 124 case kCodecHEVC: |
| 125 return kHevcMimeType; |
| 126 case kCodecVP8: |
| 127 return kVp8MimeType; |
| 128 case kCodecVP9: |
| 129 return kVp9MimeType; |
| 130 default: |
| 131 return std::string(); |
| 132 } |
| 133 } |
| 134 |
| 135 // static |
140 bool MediaCodecUtil::IsMediaCodecAvailable() { | 136 bool MediaCodecUtil::IsMediaCodecAvailable() { |
141 return IsMediaCodecAvailableFor( | 137 return IsMediaCodecAvailableFor( |
142 base::android::BuildInfo::GetInstance()->sdk_int(), | 138 base::android::BuildInfo::GetInstance()->sdk_int(), |
143 base::android::BuildInfo::GetInstance()->model()); | 139 base::android::BuildInfo::GetInstance()->model()); |
144 } | 140 } |
145 | 141 |
146 // static | 142 // static |
147 bool MediaCodecUtil::IsMediaCodecAvailableFor(int sdk, const char* model) { | 143 bool MediaCodecUtil::IsMediaCodecAvailableFor(int sdk, const char* model) { |
148 // We will blacklist the model on any sdk that is as old or older than | 144 // We will blacklist the model on any sdk that is as old or older than |
149 // |last_bad_sdk| for the given model. | 145 // |last_bad_sdk| for the given model. |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
212 if (j_color_format_array.obj()) { | 208 if (j_color_format_array.obj()) { |
213 std::vector<int> formats; | 209 std::vector<int> formats; |
214 JavaIntArrayToIntVector(env, j_color_format_array.obj(), &formats); | 210 JavaIntArrayToIntVector(env, j_color_format_array.obj(), &formats); |
215 color_formats = std::set<int>(formats.begin(), formats.end()); | 211 color_formats = std::set<int>(formats.begin(), formats.end()); |
216 } | 212 } |
217 | 213 |
218 return color_formats; | 214 return color_formats; |
219 } | 215 } |
220 | 216 |
221 // static | 217 // static |
222 bool MediaCodecUtil::CanDecode(const std::string& codec, bool is_secure) { | 218 bool MediaCodecUtil::CanDecode(VideoCodec codec, bool is_secure) { |
| 219 return CanDecodeInternal(CodecToAndroidMimeType(codec), is_secure); |
| 220 } |
| 221 |
| 222 // static |
| 223 bool MediaCodecUtil::CanDecode(AudioCodec codec) { |
| 224 return CanDecodeInternal(CodecToAndroidMimeType(codec), false); |
| 225 } |
| 226 |
| 227 // static |
| 228 bool MediaCodecUtil::CanDecodeInternal(const std::string& mime, |
| 229 bool is_secure) { |
223 if (!IsMediaCodecAvailable()) | 230 if (!IsMediaCodecAvailable()) |
224 return false; | 231 return false; |
| 232 if (mime.empty()) |
| 233 return false; |
225 | 234 |
226 JNIEnv* env = AttachCurrentThread(); | 235 JNIEnv* env = AttachCurrentThread(); |
227 std::string mime = CodecTypeToAndroidMimeType(codec); | |
228 if (mime.empty()) | |
229 return false; | |
230 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); | 236 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); |
231 return Java_MediaCodecUtil_canDecode(env, j_mime, is_secure); | 237 return Java_MediaCodecUtil_canDecode(env, j_mime, is_secure); |
232 } | 238 } |
233 | 239 |
234 // static | 240 // static |
235 bool MediaCodecUtil::AddSupportedCodecProfileLevels( | 241 bool MediaCodecUtil::AddSupportedCodecProfileLevels( |
236 std::vector<CodecProfileLevel>* result) { | 242 std::vector<CodecProfileLevel>* result) { |
237 DCHECK(result); | 243 DCHECK(result); |
238 if (!IsMediaCodecAvailable()) | 244 if (!IsMediaCodecAvailable()) |
239 return false; | 245 return false; |
240 JNIEnv* env = AttachCurrentThread(); | 246 JNIEnv* env = AttachCurrentThread(); |
241 ScopedJavaLocalRef<jobjectArray> j_codec_profile_levels( | 247 ScopedJavaLocalRef<jobjectArray> j_codec_profile_levels( |
242 Java_MediaCodecUtil_getSupportedCodecProfileLevels(env)); | 248 Java_MediaCodecUtil_getSupportedCodecProfileLevels(env)); |
243 int java_array_length = env->GetArrayLength(j_codec_profile_levels.obj()); | 249 int java_array_length = env->GetArrayLength(j_codec_profile_levels.obj()); |
244 for (int i = 0; i < java_array_length; ++i) { | 250 for (int i = 0; i < java_array_length; ++i) { |
245 const jobject& java_codec_profile_level = | 251 const jobject& java_codec_profile_level = |
246 env->GetObjectArrayElement(j_codec_profile_levels.obj(), i); | 252 env->GetObjectArrayElement(j_codec_profile_levels.obj(), i); |
247 result->push_back(MediaCodecProfileLevelToChromiumProfileLevel( | 253 result->push_back(MediaCodecProfileLevelToChromiumProfileLevel( |
248 env, java_codec_profile_level)); | 254 env, java_codec_profile_level)); |
249 } | 255 } |
250 return true; | 256 return true; |
251 } | 257 } |
252 | 258 |
253 // static | 259 // static |
254 bool MediaCodecUtil::IsKnownUnaccelerated(const std::string& android_mime_type, | 260 bool MediaCodecUtil::IsKnownUnaccelerated(VideoCodec codec, |
255 MediaCodecDirection direction) { | 261 MediaCodecDirection direction) { |
256 DCHECK(IsSupportedAndroidMimeType(android_mime_type)); | |
257 if (!IsMediaCodecAvailable()) | 262 if (!IsMediaCodecAvailable()) |
258 return true; | 263 return true; |
259 | 264 |
260 std::string codec_name = | 265 std::string codec_name = |
261 GetDefaultCodecName(android_mime_type, direction, false); | 266 GetDefaultCodecName(CodecToAndroidMimeType(codec), direction, false); |
262 DVLOG(1) << __func__ << "Default codec for " << android_mime_type << " : " | 267 DVLOG(1) << __func__ << "Default codec for " << GetCodecName(codec) << " : " |
263 << codec_name << ", direction: " << direction; | 268 << codec_name << ", direction: " << static_cast<int>(direction); |
264 if (codec_name.empty()) | 269 if (codec_name.empty()) |
265 return true; | 270 return true; |
266 | 271 |
267 // MediaTek hardware vp8 is known slower than the software implementation. | 272 // MediaTek hardware vp8 is known slower than the software implementation. |
268 // MediaTek hardware vp9 is known crashy, see http://crbug.com/446974 and | 273 // MediaTek hardware vp9 is known crashy, see http://crbug.com/446974 and |
269 // http://crbug.com/597836. | 274 // http://crbug.com/597836. |
270 if (base::StartsWith(codec_name, "OMX.MTK.", base::CompareCase::SENSITIVE)) { | 275 if (base::StartsWith(codec_name, "OMX.MTK.", base::CompareCase::SENSITIVE)) { |
271 if (android_mime_type == kVp8MimeType) | 276 if (codec == kCodecVP8) |
272 return true; | 277 return true; |
273 | 278 |
274 if (android_mime_type == kVp9MimeType) | 279 if (codec == kCodecVP9) |
275 return base::android::BuildInfo::GetInstance()->sdk_int() < 21; | 280 return base::android::BuildInfo::GetInstance()->sdk_int() < 21; |
276 | 281 |
277 return false; | 282 return false; |
278 } | 283 } |
279 | 284 |
280 // It would be nice if MediaCodecInfo externalized some notion of | 285 // It would be nice if MediaCodecInfo externalized some notion of |
281 // HW-acceleration but it doesn't. Android Media guidance is that the | 286 // HW-acceleration but it doesn't. Android Media guidance is that the |
282 // "OMX.google" prefix is always used for SW decoders, so that's what we | 287 // "OMX.google" prefix is always used for SW decoders, so that's what we |
283 // use. "OMX.SEC.*" codec is Samsung software implementation - report it | 288 // use. "OMX.SEC.*" codec is Samsung software implementation - report it |
284 // as unaccelerated as well. | 289 // as unaccelerated as well. |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
362 (sdk_int == 18 && ("OMX.SEC.avc.dec" == codec_name || | 367 (sdk_int == 18 && ("OMX.SEC.avc.dec" == codec_name || |
363 "OMX.SEC.avc.dec.secure" == codec_name)) || | 368 "OMX.SEC.avc.dec.secure" == codec_name)) || |
364 (sdk_int == 19 && | 369 (sdk_int == 19 && |
365 base::StartsWith(base::android::BuildInfo::GetInstance()->model(), | 370 base::StartsWith(base::android::BuildInfo::GetInstance()->model(), |
366 "SM-G800", base::CompareCase::INSENSITIVE_ASCII) && | 371 "SM-G800", base::CompareCase::INSENSITIVE_ASCII) && |
367 ("OMX.Exynos.avc.dec" == codec_name || | 372 ("OMX.Exynos.avc.dec" == codec_name || |
368 "OMX.Exynos.avc.dec.secure" == codec_name)); | 373 "OMX.Exynos.avc.dec.secure" == codec_name)); |
369 } | 374 } |
370 | 375 |
371 } // namespace media | 376 } // namespace media |
OLD | NEW |