| 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 if (!codec_name.size()) |
| 190 std::string codec_type = AndroidMimeTypeToCodecType(mime_type); | 121 return true; |
| 191 std::vector<CodecsInfo> codecs_info = GetCodecsInfo(); | 122 |
| 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 | 123 // It would be nice if MediaCodecInfo externalized some notion of |
| 203 // HW-acceleration but it doesn't. Android Media guidance is that the | 124 // 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 | 125 // "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 | 126 // use. "OMX.SEC.*" codec is Samsung software implementation - report it |
| 206 // as unaccelerated as well. MediaTek hardware vp8 is known slower than | 127 // as unaccelerated as well. MediaTek hardware vp8 is known slower than |
| 207 // the software implementation. http://crbug.com/446974. | 128 // the software implementation. http://crbug.com/446974. |
| 208 if (codec_name.length() > 0) { | 129 return base::StartsWith(codec_name, "OMX.google.", |
| 209 return base::StartsWith(codec_name, "OMX.google.", | 130 base::CompareCase::SENSITIVE) || |
| 210 base::CompareCase::SENSITIVE) || | 131 base::StartsWith(codec_name, "OMX.SEC.", |
| 211 base::StartsWith(codec_name, "OMX.SEC.", | 132 base::CompareCase::SENSITIVE) || |
| 212 base::CompareCase::SENSITIVE) || | 133 (base::StartsWith(codec_name, "OMX.MTK.", |
| 213 (base::StartsWith(codec_name, "OMX.MTK.", | 134 base::CompareCase::SENSITIVE) && |
| 214 base::CompareCase::SENSITIVE) && | 135 mime_type == "video/x-vnd.on2.vp8"); |
| 215 mime_type == "video/x-vnd.on2.vp8"); | |
| 216 } | |
| 217 return true; | |
| 218 } | 136 } |
| 219 | 137 |
| 220 // static | 138 // static |
| 221 bool MediaCodecUtil::IsHLSPath(const GURL& url) { | 139 bool MediaCodecUtil::IsHLSPath(const GURL& url) { |
| 222 if (!url.SchemeIsHTTPOrHTTPS() && !url.SchemeIsFile()) | 140 if (!url.SchemeIsHTTPOrHTTPS() && !url.SchemeIsFile()) |
| 223 return false; | 141 return false; |
| 224 | 142 |
| 225 std::string path = url.path(); | 143 std::string path = url.path(); |
| 226 return base::EndsWith(path, ".m3u8", base::CompareCase::INSENSITIVE_ASCII); | 144 return base::EndsWith(path, ".m3u8", base::CompareCase::INSENSITIVE_ASCII); |
| 227 } | 145 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 254 } | 172 } |
| 255 | 173 |
| 256 // static | 174 // static |
| 257 bool MediaCodecUtil::IsVp8EncoderAvailable() { | 175 bool MediaCodecUtil::IsVp8EncoderAvailable() { |
| 258 // Currently the vp8 encoder and decoder blacklists cover the same devices, | 176 // Currently the vp8 encoder and decoder blacklists cover the same devices, |
| 259 // but we have a second method for clarity in future issues. | 177 // but we have a second method for clarity in future issues. |
| 260 return IsVp8DecoderAvailable(); | 178 return IsVp8DecoderAvailable(); |
| 261 } | 179 } |
| 262 | 180 |
| 263 } // namespace media | 181 } // namespace media |
| OLD | NEW |