Chromium Code Reviews| 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 10 matching lines...) Expand all Loading... | |
| 21 #include "url/gurl.h" | 21 #include "url/gurl.h" |
| 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 | |
| 32 namespace { | 31 namespace { |
| 33 | 32 |
| 34 const char kMp4aMimeType[] = "audio/mp4a-latm"; | 33 const char kMp3MimeType[] = "audio/mpeg"; |
| 34 const char kAacMimeType[] = "audio/mp4a-latm"; | |
| 35 const char kOpusMimeType[] = "audio/opus"; | 35 const char kOpusMimeType[] = "audio/opus"; |
| 36 const char kVorbisMimeType[] = "audio/vorbis"; | 36 const char kVorbisMimeType[] = "audio/vorbis"; |
| 37 const char kAc3MimeType[] = "audio/ac3"; | 37 const char kAc3MimeType[] = "audio/ac3"; |
| 38 const char kEac3MimeType[] = "audio/eac3"; | 38 const char kEac3MimeType[] = "audio/eac3"; |
| 39 const char kAvcMimeType[] = "video/avc"; | 39 const char kAvcMimeType[] = "video/avc"; |
| 40 const char kHevcMimeType[] = "video/hevc"; | 40 const char kHevcMimeType[] = "video/hevc"; |
| 41 const char kVp8MimeType[] = "video/x-vnd.on2.vp8"; | 41 const char kVp8MimeType[] = "video/x-vnd.on2.vp8"; |
| 42 const char kVp9MimeType[] = "video/x-vnd.on2.vp9"; | 42 const char kVp9MimeType[] = "video/x-vnd.on2.vp9"; |
| 43 | 43 |
| 44 } // namespace | 44 } // namespace |
| 45 | 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) { | 46 static VideoCodec AndroidCodecToCodecEnum(const std::string& codec) { |
| 72 if (codec == "AVC") | 47 if (codec == "AVC") |
| 73 return kCodecH264; | 48 return kCodecH264; |
| 74 if (codec == "VP8") | 49 if (codec == "VP8") |
| 75 return kCodecVP8; | 50 return kCodecVP8; |
| 76 if (codec == "VP9") | 51 if (codec == "VP9") |
| 77 return kCodecVP9; | 52 return kCodecVP9; |
| 78 if (codec == "HEVC") | 53 if (codec == "HEVC") |
| 79 return kCodecHEVC; | 54 return kCodecHEVC; |
| 80 DLOG(WARNING) << "Unknown video codec name \"" << codec << "\""; | 55 DLOG(WARNING) << "Unknown video codec name \"" << codec << "\""; |
| 81 return kUnknownVideoCodec; | 56 return kUnknownVideoCodec; |
| 82 } | 57 } |
| 83 | 58 |
| 84 static CodecProfileLevel MediaCodecProfileLevelToChromiumProfileLevel( | 59 static CodecProfileLevel MediaCodecProfileLevelToChromiumProfileLevel( |
| 85 JNIEnv* env, | 60 JNIEnv* env, |
| 86 const jobject& j_codec_profile_level) { | 61 const jobject& j_codec_profile_level) { |
| 87 ScopedJavaLocalRef<jstring> codec = | 62 ScopedJavaLocalRef<jstring> codec = |
| 88 Java_CodecProfileLevelAdapter_getCodec(env, j_codec_profile_level); | 63 Java_CodecProfileLevelAdapter_getCodec(env, j_codec_profile_level); |
| 89 int profile = | 64 int profile = |
| 90 Java_CodecProfileLevelAdapter_getProfile(env, j_codec_profile_level); | 65 Java_CodecProfileLevelAdapter_getProfile(env, j_codec_profile_level); |
| 91 int level = | 66 int level = |
| 92 Java_CodecProfileLevelAdapter_getLevel(env, j_codec_profile_level); | 67 Java_CodecProfileLevelAdapter_getLevel(env, j_codec_profile_level); |
| 93 return {AndroidCodecToCodecEnum(ConvertJavaStringToUTF8(codec)), | 68 return {AndroidCodecToCodecEnum(ConvertJavaStringToUTF8(codec)), |
| 94 static_cast<VideoCodecProfile>(profile), level}; | 69 static_cast<VideoCodecProfile>(profile), level}; |
| 95 } | 70 } |
| 96 | 71 |
| 97 static bool IsSupportedAndroidMimeType(const std::string& mime_type) { | 72 static bool IsSupportedAndroidMimeType(const std::string& mime_type) { |
| 98 std::vector<std::string> supported{ | 73 std::vector<std::string> supported{ |
| 99 kMp4aMimeType, kOpusMimeType, kVorbisMimeType, kAvcMimeType, | 74 kMp3MimeType, kAacMimeType, kOpusMimeType, kVorbisMimeType, |
|
watk
2017/02/14 01:40:51
I added mp3 here. Seems like it was missing before
| |
| 100 kHevcMimeType, kVp8MimeType, kVp9MimeType}; | 75 kAvcMimeType, kHevcMimeType, kVp8MimeType, kVp9MimeType}; |
| 101 return std::find(supported.begin(), supported.end(), mime_type) != | 76 return std::find(supported.begin(), supported.end(), mime_type) != |
| 102 supported.end(); | 77 supported.end(); |
| 103 } | 78 } |
| 104 | 79 |
| 105 static std::string GetDefaultCodecName(const std::string& mime_type, | 80 static std::string GetDefaultCodecName(const std::string& mime_type, |
| 106 MediaCodecDirection direction, | 81 MediaCodecDirection direction, |
| 107 bool require_software_codec) { | 82 bool require_software_codec) { |
| 108 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); | 83 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); |
| 109 JNIEnv* env = AttachCurrentThread(); | 84 JNIEnv* env = AttachCurrentThread(); |
| 110 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime_type); | 85 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime_type); |
| 111 ScopedJavaLocalRef<jstring> j_codec_name = | 86 ScopedJavaLocalRef<jstring> j_codec_name = |
| 112 Java_MediaCodecUtil_getDefaultCodecName(env, j_mime, direction, | 87 Java_MediaCodecUtil_getDefaultCodecName( |
| 113 require_software_codec); | 88 env, j_mime, static_cast<int>(direction), require_software_codec); |
| 114 return ConvertJavaStringToUTF8(env, j_codec_name.obj()); | 89 return ConvertJavaStringToUTF8(env, j_codec_name.obj()); |
| 115 } | 90 } |
| 116 | 91 |
| 117 static bool IsDecoderSupportedByDevice(const std::string& android_mime_type) { | 92 static bool IsDecoderSupportedByDevice(const std::string& android_mime_type) { |
| 118 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); | 93 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); |
| 119 DCHECK(IsSupportedAndroidMimeType(android_mime_type)); | 94 DCHECK(IsSupportedAndroidMimeType(android_mime_type)); |
| 120 JNIEnv* env = AttachCurrentThread(); | 95 JNIEnv* env = AttachCurrentThread(); |
| 121 ScopedJavaLocalRef<jstring> j_mime = | 96 ScopedJavaLocalRef<jstring> j_mime = |
| 122 ConvertUTF8ToJavaString(env, android_mime_type); | 97 ConvertUTF8ToJavaString(env, android_mime_type); |
| 123 return Java_MediaCodecUtil_isDecoderSupportedForDevice(env, j_mime); | 98 return Java_MediaCodecUtil_isDecoderSupportedForDevice(env, j_mime); |
| 124 } | 99 } |
| 125 | 100 |
| 126 static bool IsEncoderSupportedByDevice(const std::string& android_mime_type) { | 101 static bool IsEncoderSupportedByDevice(const std::string& android_mime_type) { |
| 127 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); | 102 DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); |
| 128 JNIEnv* env = AttachCurrentThread(); | 103 JNIEnv* env = AttachCurrentThread(); |
| 129 ScopedJavaLocalRef<jstring> j_mime = | 104 ScopedJavaLocalRef<jstring> j_mime = |
| 130 ConvertUTF8ToJavaString(env, android_mime_type); | 105 ConvertUTF8ToJavaString(env, android_mime_type); |
| 131 return Java_MediaCodecUtil_isEncoderSupportedByDevice(env, j_mime); | 106 return Java_MediaCodecUtil_isEncoderSupportedByDevice(env, j_mime); |
| 132 } | 107 } |
| 133 | 108 |
| 134 // static | 109 // static |
| 110 std::string MediaCodecUtil::CodecToAndroidMimeType(AudioCodec codec) { | |
| 111 switch (codec) { | |
| 112 case kCodecMP3: | |
| 113 return kMp3MimeType; | |
| 114 case kCodecVorbis: | |
| 115 return kVorbisMimeType; | |
| 116 case kCodecOpus: | |
| 117 return kOpusMimeType; | |
| 118 case kCodecAAC: | |
| 119 return kAacMimeType; | |
| 120 case kCodecAC3: | |
| 121 return kAc3MimeType; | |
| 122 case kCodecEAC3: | |
| 123 return kEac3MimeType; | |
| 124 default: | |
| 125 return std::string(); | |
| 126 } | |
| 127 } | |
| 128 | |
| 129 // static | |
| 130 std::string MediaCodecUtil::CodecToAndroidMimeType(VideoCodec codec) { | |
| 131 switch (codec) { | |
| 132 case kCodecH264: | |
| 133 return kAvcMimeType; | |
| 134 case kCodecHEVC: | |
| 135 return kHevcMimeType; | |
| 136 case kCodecVP8: | |
| 137 return kVp8MimeType; | |
| 138 case kCodecVP9: | |
| 139 return kVp9MimeType; | |
| 140 default: | |
| 141 return std::string(); | |
| 142 } | |
| 143 } | |
| 144 | |
| 145 // static | |
| 135 bool MediaCodecUtil::IsMediaCodecAvailable() { | 146 bool MediaCodecUtil::IsMediaCodecAvailable() { |
| 136 // Blacklist some devices on Jellybean as MediaCodec is buggy. | 147 // Blacklist some devices on Jellybean as MediaCodec is buggy. |
| 137 // http://crbug.com/365494, http://crbug.com/615872 | 148 // http://crbug.com/365494, http://crbug.com/615872 |
| 138 // Blacklist Lenovo A6600 / A6800 on KitKat, which tends to crash a lot. | 149 // 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. | 150 // See crbug.com/628059 . We include < K since they don't exist. |
| 140 // Blacklist Samsung Galaxy Star Pro (GT-S7262) (crbug.com/634920). | 151 // Blacklist Samsung Galaxy Star Pro (GT-S7262) (crbug.com/634920). |
| 141 // GT-S5282 and GT-I8552 are for crbug.com/634920 . | 152 // GT-S5282 and GT-I8552 are for crbug.com/634920 . |
| 142 if (base::android::BuildInfo::GetInstance()->sdk_int() <= 19) { | 153 if (base::android::BuildInfo::GetInstance()->sdk_int() <= 19) { |
| 143 std::string model(base::android::BuildInfo::GetInstance()->model()); | 154 std::string model(base::android::BuildInfo::GetInstance()->model()); |
| 144 return model != "GT-I9100" && model != "GT-I9300" && model != "GT-N7000" && | 155 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()) { | 187 if (j_color_format_array.obj()) { |
| 177 std::vector<int> formats; | 188 std::vector<int> formats; |
| 178 JavaIntArrayToIntVector(env, j_color_format_array.obj(), &formats); | 189 JavaIntArrayToIntVector(env, j_color_format_array.obj(), &formats); |
| 179 color_formats = std::set<int>(formats.begin(), formats.end()); | 190 color_formats = std::set<int>(formats.begin(), formats.end()); |
| 180 } | 191 } |
| 181 | 192 |
| 182 return color_formats; | 193 return color_formats; |
| 183 } | 194 } |
| 184 | 195 |
| 185 // static | 196 // static |
| 186 bool MediaCodecUtil::CanDecode(const std::string& codec, bool is_secure) { | 197 bool MediaCodecUtil::CanDecode(const std::string& mime, bool is_secure) { |
| 187 if (!IsMediaCodecAvailable()) | 198 if (!IsMediaCodecAvailable()) |
| 188 return false; | 199 return false; |
| 200 if (mime.empty()) | |
| 201 return false; | |
| 189 | 202 |
| 190 JNIEnv* env = AttachCurrentThread(); | 203 JNIEnv* env = AttachCurrentThread(); |
| 191 std::string mime = CodecTypeToAndroidMimeType(codec); | |
| 192 if (mime.empty()) | |
| 193 return false; | |
| 194 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); | 204 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); |
| 195 return Java_MediaCodecUtil_canDecode(env, j_mime, is_secure); | 205 return Java_MediaCodecUtil_canDecode(env, j_mime, is_secure); |
| 196 } | 206 } |
| 197 | 207 |
| 198 // static | 208 // static |
| 199 bool MediaCodecUtil::AddSupportedCodecProfileLevels( | 209 bool MediaCodecUtil::AddSupportedCodecProfileLevels( |
| 200 std::vector<CodecProfileLevel>* result) { | 210 std::vector<CodecProfileLevel>* result) { |
| 201 DCHECK(result); | 211 DCHECK(result); |
| 202 if (!IsMediaCodecAvailable()) | 212 if (!IsMediaCodecAvailable()) |
| 203 return false; | 213 return false; |
| 204 JNIEnv* env = AttachCurrentThread(); | 214 JNIEnv* env = AttachCurrentThread(); |
| 205 ScopedJavaLocalRef<jobjectArray> j_codec_profile_levels( | 215 ScopedJavaLocalRef<jobjectArray> j_codec_profile_levels( |
| 206 Java_MediaCodecUtil_getSupportedCodecProfileLevels(env)); | 216 Java_MediaCodecUtil_getSupportedCodecProfileLevels(env)); |
| 207 int java_array_length = env->GetArrayLength(j_codec_profile_levels.obj()); | 217 int java_array_length = env->GetArrayLength(j_codec_profile_levels.obj()); |
| 208 for (int i = 0; i < java_array_length; ++i) { | 218 for (int i = 0; i < java_array_length; ++i) { |
| 209 const jobject& java_codec_profile_level = | 219 const jobject& java_codec_profile_level = |
| 210 env->GetObjectArrayElement(j_codec_profile_levels.obj(), i); | 220 env->GetObjectArrayElement(j_codec_profile_levels.obj(), i); |
| 211 result->push_back(MediaCodecProfileLevelToChromiumProfileLevel( | 221 result->push_back(MediaCodecProfileLevelToChromiumProfileLevel( |
| 212 env, java_codec_profile_level)); | 222 env, java_codec_profile_level)); |
| 213 } | 223 } |
| 214 return true; | 224 return true; |
| 215 } | 225 } |
| 216 | 226 |
| 217 // static | 227 // static |
| 218 bool MediaCodecUtil::IsKnownUnaccelerated(const std::string& android_mime_type, | 228 bool MediaCodecUtil::IsKnownUnaccelerated(VideoCodec codec, |
| 219 MediaCodecDirection direction) { | 229 MediaCodecDirection direction) { |
| 220 DCHECK(IsSupportedAndroidMimeType(android_mime_type)); | |
| 221 if (!IsMediaCodecAvailable()) | 230 if (!IsMediaCodecAvailable()) |
| 222 return true; | 231 return true; |
| 223 | 232 |
| 224 std::string codec_name = | 233 std::string codec_name = |
| 225 GetDefaultCodecName(android_mime_type, direction, false); | 234 GetDefaultCodecName(CodecToAndroidMimeType(codec), direction, false); |
| 226 DVLOG(1) << __func__ << "Default codec for " << android_mime_type << " : " | 235 DVLOG(1) << __func__ << "Default codec for " << GetCodecName(codec) << " : " |
| 227 << codec_name << ", direction: " << direction; | 236 << codec_name << ", direction: " << static_cast<int>(direction); |
| 228 if (codec_name.empty()) | 237 if (codec_name.empty()) |
| 229 return true; | 238 return true; |
| 230 | 239 |
| 231 // MediaTek hardware vp8 is known slower than the software implementation. | 240 // MediaTek hardware vp8 is known slower than the software implementation. |
| 232 // MediaTek hardware vp9 is known crashy, see http://crbug.com/446974 and | 241 // MediaTek hardware vp9 is known crashy, see http://crbug.com/446974 and |
| 233 // http://crbug.com/597836. | 242 // http://crbug.com/597836. |
| 234 if (base::StartsWith(codec_name, "OMX.MTK.", base::CompareCase::SENSITIVE)) { | 243 if (base::StartsWith(codec_name, "OMX.MTK.", base::CompareCase::SENSITIVE)) { |
| 235 if (android_mime_type == kVp8MimeType) | 244 if (codec == kCodecVP8) |
| 236 return true; | 245 return true; |
| 237 | 246 |
| 238 if (android_mime_type == kVp9MimeType) | 247 if (codec == kCodecVP9) |
| 239 return base::android::BuildInfo::GetInstance()->sdk_int() < 21; | 248 return base::android::BuildInfo::GetInstance()->sdk_int() < 21; |
| 240 | 249 |
| 241 return false; | 250 return false; |
| 242 } | 251 } |
| 243 | 252 |
| 244 // It would be nice if MediaCodecInfo externalized some notion of | 253 // It would be nice if MediaCodecInfo externalized some notion of |
| 245 // HW-acceleration but it doesn't. Android Media guidance is that the | 254 // 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 | 255 // "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 | 256 // use. "OMX.SEC.*" codec is Samsung software implementation - report it |
| 248 // as unaccelerated as well. | 257 // as unaccelerated as well. |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 326 (sdk_int == 18 && ("OMX.SEC.avc.dec" == codec_name || | 335 (sdk_int == 18 && ("OMX.SEC.avc.dec" == codec_name || |
| 327 "OMX.SEC.avc.dec.secure" == codec_name)) || | 336 "OMX.SEC.avc.dec.secure" == codec_name)) || |
| 328 (sdk_int == 19 && | 337 (sdk_int == 19 && |
| 329 base::StartsWith(base::android::BuildInfo::GetInstance()->model(), | 338 base::StartsWith(base::android::BuildInfo::GetInstance()->model(), |
| 330 "SM-G800", base::CompareCase::INSENSITIVE_ASCII) && | 339 "SM-G800", base::CompareCase::INSENSITIVE_ASCII) && |
| 331 ("OMX.Exynos.avc.dec" == codec_name || | 340 ("OMX.Exynos.avc.dec" == codec_name || |
| 332 "OMX.Exynos.avc.dec.secure" == codec_name)); | 341 "OMX.Exynos.avc.dec.secure" == codec_name)); |
| 333 } | 342 } |
| 334 | 343 |
| 335 } // namespace media | 344 } // namespace media |
| OLD | NEW |