OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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_bridge.h" | 5 #include "media/base/android/media_codec_bridge.h" |
6 | 6 |
7 #include <jni.h> | 7 #include <jni.h> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/android/build_info.h" | 10 #include "base/android/build_info.h" |
(...skipping 10 matching lines...) Expand all Loading... |
21 #include "media/base/bit_reader.h" | 21 #include "media/base/bit_reader.h" |
22 #include "media/base/decrypt_config.h" | 22 #include "media/base/decrypt_config.h" |
23 | 23 |
24 using base::android::AttachCurrentThread; | 24 using base::android::AttachCurrentThread; |
25 using base::android::ConvertJavaStringToUTF8; | 25 using base::android::ConvertJavaStringToUTF8; |
26 using base::android::ConvertUTF8ToJavaString; | 26 using base::android::ConvertUTF8ToJavaString; |
27 using base::android::ScopedJavaLocalRef; | 27 using base::android::ScopedJavaLocalRef; |
28 | 28 |
29 namespace media { | 29 namespace media { |
30 | 30 |
31 enum { kBufferFlagEndOfStream = 4 }; | 31 enum { |
| 32 kBufferFlagSyncFrame = 1, // BUFFER_FLAG_SYNC_FRAME |
| 33 kBufferFlagEndOfStream = 4, // BUFFER_FLAG_END_OF_STREAM |
| 34 kConfigureFlagEncode = 1, // CONFIGURE_FLAG_ENCODE |
| 35 }; |
32 | 36 |
33 static const std::string AudioCodecToAndroidMimeType(const AudioCodec& codec) { | 37 static const std::string AudioCodecToAndroidMimeType(const AudioCodec& codec) { |
34 switch (codec) { | 38 switch (codec) { |
35 case kCodecMP3: | 39 case kCodecMP3: |
36 return "audio/mpeg"; | 40 return "audio/mpeg"; |
37 case kCodecVorbis: | 41 case kCodecVorbis: |
38 return "audio/vorbis"; | 42 return "audio/vorbis"; |
39 case kCodecAAC: | 43 case kCodecAAC: |
40 return "audio/mp4a-latm"; | 44 return "audio/mp4a-latm"; |
41 default: | 45 default: |
(...skipping 15 matching lines...) Expand all Loading... |
57 } | 61 } |
58 | 62 |
59 static const std::string CodecTypeToAndroidMimeType(const std::string& codec) { | 63 static const std::string CodecTypeToAndroidMimeType(const std::string& codec) { |
60 // TODO(xhwang): Shall we handle more detailed strings like "mp4a.40.2"? | 64 // TODO(xhwang): Shall we handle more detailed strings like "mp4a.40.2"? |
61 if (codec == "avc1") | 65 if (codec == "avc1") |
62 return "video/avc"; | 66 return "video/avc"; |
63 if (codec == "mp4a") | 67 if (codec == "mp4a") |
64 return "audio/mp4a-latm"; | 68 return "audio/mp4a-latm"; |
65 if (codec == "vp8" || codec == "vp8.0") | 69 if (codec == "vp8" || codec == "vp8.0") |
66 return "video/x-vnd.on2.vp8"; | 70 return "video/x-vnd.on2.vp8"; |
67 if (codec == "vp9" || codec == "vp9.0") | 71 if (codec == "vp9" || codec == "vp9.0") |
68 return "video/x-vnd.on2.vp9"; | 72 return "video/x-vnd.on2.vp9"; |
69 if (codec == "vorbis") | 73 if (codec == "vorbis") |
70 return "audio/vorbis"; | 74 return "audio/vorbis"; |
71 return std::string(); | 75 return std::string(); |
72 } | 76 } |
73 | 77 |
74 // TODO(qinmin): using a map to help all the conversions in this class. | 78 // TODO(qinmin): using a map to help all the conversions in this class. |
75 static const std::string AndroidMimeTypeToCodecType(const std::string& mime) { | 79 static const std::string AndroidMimeTypeToCodecType(const std::string& mime) { |
76 if (mime == "video/mp4v-es") | 80 if (mime == "video/mp4v-es") |
77 return "mp4v"; | 81 return "mp4v"; |
78 if (mime == "video/avc") | 82 if (mime == "video/avc") |
79 return "avc1"; | 83 return "avc1"; |
80 if (mime == "video/x-vnd.on2.vp8") | 84 if (mime == "video/x-vnd.on2.vp8") |
81 return "vp8"; | 85 return "vp8"; |
82 if (mime == "video/x-vnd.on2.vp9") | 86 if (mime == "video/x-vnd.on2.vp9") |
83 return "vp9"; | 87 return "vp9"; |
84 if (mime == "audio/mp4a-latm") | 88 if (mime == "audio/mp4a-latm") |
85 return "mp4a"; | 89 return "mp4a"; |
86 if (mime == "audio/mpeg") | 90 if (mime == "audio/mpeg") |
87 return "mp3"; | 91 return "mp3"; |
88 if (mime == "audio/vorbis") | 92 if (mime == "audio/vorbis") |
89 return "vorbis"; | 93 return "vorbis"; |
90 return std::string(); | 94 return std::string(); |
91 } | 95 } |
92 | 96 |
93 static ScopedJavaLocalRef<jintArray> ToJavaIntArray( | 97 static ScopedJavaLocalRef<jintArray> |
94 JNIEnv* env, scoped_ptr<jint[]> native_array, int size) { | 98 ToJavaIntArray(JNIEnv* env, scoped_ptr<jint[]> native_array, int size) { |
95 ScopedJavaLocalRef<jintArray> j_array(env, env->NewIntArray(size)); | 99 ScopedJavaLocalRef<jintArray> j_array(env, env->NewIntArray(size)); |
96 env->SetIntArrayRegion(j_array.obj(), 0, size, native_array.get()); | 100 env->SetIntArrayRegion(j_array.obj(), 0, size, native_array.get()); |
97 return j_array; | 101 return j_array; |
98 } | 102 } |
99 | 103 |
100 // static | 104 // static |
101 bool MediaCodecBridge::IsAvailable() { | 105 bool MediaCodecBridge::IsAvailable() { |
102 // MediaCodec is only available on JB and greater. | 106 // MediaCodec is only available on JB and greater. |
103 return base::android::BuildInfo::GetInstance()->sdk_int() >= 16; | 107 return base::android::BuildInfo::GetInstance()->sdk_int() >= 16; |
104 } | 108 } |
105 | 109 |
106 // static | 110 // static |
107 void MediaCodecBridge::GetCodecsInfo( | 111 bool MediaCodecBridge::SupportsSetParameters() { |
108 std::vector<CodecsInfo>* codecs_info) { | 112 // MediaCodec.setParameters() is only available starting with K. |
| 113 return base::android::BuildInfo::GetInstance()->sdk_int() >= 19; |
| 114 } |
| 115 |
| 116 // static |
| 117 std::vector<MediaCodecBridge::CodecsInfo> MediaCodecBridge::GetCodecsInfo() { |
| 118 std::vector<CodecsInfo> codecs_info; |
109 JNIEnv* env = AttachCurrentThread(); | 119 JNIEnv* env = AttachCurrentThread(); |
110 if (!IsAvailable()) | 120 if (!IsAvailable()) |
111 return; | 121 return codecs_info; |
112 | 122 |
113 std::string mime_type; | 123 std::string mime_type; |
114 std::string codec_name; | 124 std::string codec_name; |
115 ScopedJavaLocalRef<jobjectArray> j_codec_info_array = | 125 ScopedJavaLocalRef<jobjectArray> j_codec_info_array = |
116 Java_MediaCodecBridge_getCodecsInfo(env); | 126 Java_MediaCodecBridge_getCodecsInfo(env); |
117 jsize len = env->GetArrayLength(j_codec_info_array.obj()); | 127 jsize len = env->GetArrayLength(j_codec_info_array.obj()); |
118 for (jsize i = 0; i < len; ++i) { | 128 for (jsize i = 0; i < len; ++i) { |
119 ScopedJavaLocalRef<jobject> j_info( | 129 ScopedJavaLocalRef<jobject> j_info( |
120 env, env->GetObjectArrayElement(j_codec_info_array.obj(), i)); | 130 env, env->GetObjectArrayElement(j_codec_info_array.obj(), i)); |
121 ScopedJavaLocalRef<jstring> j_codec_type = | 131 ScopedJavaLocalRef<jstring> j_codec_type = |
122 Java_CodecInfo_codecType(env, j_info.obj()); | 132 Java_CodecInfo_codecType(env, j_info.obj()); |
123 ConvertJavaStringToUTF8(env, j_codec_type.obj(), &mime_type); | 133 ConvertJavaStringToUTF8(env, j_codec_type.obj(), &mime_type); |
124 ScopedJavaLocalRef<jstring> j_codec_name = | 134 ScopedJavaLocalRef<jstring> j_codec_name = |
125 Java_CodecInfo_codecName(env, j_info.obj()); | 135 Java_CodecInfo_codecName(env, j_info.obj()); |
126 CodecsInfo info; | 136 CodecsInfo info; |
127 info.codecs = AndroidMimeTypeToCodecType(mime_type); | 137 info.codecs = AndroidMimeTypeToCodecType(mime_type); |
128 ConvertJavaStringToUTF8(env, j_codec_name.obj(), &info.name); | 138 ConvertJavaStringToUTF8(env, j_codec_name.obj(), &info.name); |
129 codecs_info->push_back(info); | 139 info.direction = static_cast<MediaCodecDirection>( |
| 140 Java_CodecInfo_direction(env, j_info.obj())); |
| 141 codecs_info.push_back(info); |
130 } | 142 } |
| 143 return codecs_info; |
131 } | 144 } |
132 | 145 |
133 // static | 146 // static |
134 bool MediaCodecBridge::CanDecode(const std::string& codec, bool is_secure) { | 147 bool MediaCodecBridge::CanDecode(const std::string& codec, bool is_secure) { |
135 JNIEnv* env = AttachCurrentThread(); | 148 JNIEnv* env = AttachCurrentThread(); |
136 std::string mime = CodecTypeToAndroidMimeType(codec); | 149 std::string mime = CodecTypeToAndroidMimeType(codec); |
137 if (mime.empty()) | 150 if (mime.empty()) |
138 return false; | 151 return false; |
139 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); | 152 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); |
140 ScopedJavaLocalRef<jobject> j_media_codec_bridge = | 153 ScopedJavaLocalRef<jobject> j_media_codec_bridge = |
141 Java_MediaCodecBridge_create(env, j_mime.obj(), is_secure); | 154 Java_MediaCodecBridge_create(env, j_mime.obj(), is_secure, false); |
142 if (!j_media_codec_bridge.is_null()) { | 155 if (!j_media_codec_bridge.is_null()) { |
143 Java_MediaCodecBridge_release(env, j_media_codec_bridge.obj()); | 156 Java_MediaCodecBridge_release(env, j_media_codec_bridge.obj()); |
144 return true; | 157 return true; |
145 } | 158 } |
146 return false; | 159 return false; |
147 } | 160 } |
148 | 161 |
149 // static | 162 // static |
150 bool MediaCodecBridge::IsKnownUnaccelerated(const std::string& mime_type) { | 163 bool MediaCodecBridge::IsKnownUnaccelerated(const std::string& mime_type, |
| 164 MediaCodecDirection direction) { |
151 std::string codec_type = AndroidMimeTypeToCodecType(mime_type); | 165 std::string codec_type = AndroidMimeTypeToCodecType(mime_type); |
152 std::vector<media::MediaCodecBridge::CodecsInfo> codecs_info; | 166 std::vector<media::MediaCodecBridge::CodecsInfo> codecs_info = |
153 media::MediaCodecBridge::GetCodecsInfo(&codecs_info); | 167 MediaCodecBridge::GetCodecsInfo(); |
154 for (size_t i = 0; i < codecs_info.size(); ++i) { | 168 for (size_t i = 0; i < codecs_info.size(); ++i) { |
155 if (codecs_info[i].codecs == codec_type) { | 169 if (codecs_info[i].codecs == codec_type && |
| 170 codecs_info[i].direction == direction) { |
156 // It would be nice if MediaCodecInfo externalized some notion of | 171 // It would be nice if MediaCodecInfo externalized some notion of |
157 // HW-acceleration but it doesn't. Android Media guidance is that the | 172 // HW-acceleration but it doesn't. Android Media guidance is that the |
158 // prefix below is always used for SW decoders, so that's what we use. | 173 // prefix below is always used for SW decoders, so that's what we use. |
159 return StartsWithASCII(codecs_info[i].name, "OMX.google.", true); | 174 return StartsWithASCII(codecs_info[i].name, "OMX.google.", true); |
160 } | 175 } |
161 } | 176 } |
162 return true; | 177 return true; |
163 } | 178 } |
164 | 179 |
165 MediaCodecBridge::MediaCodecBridge(const std::string& mime, bool is_secure) { | 180 MediaCodecBridge::MediaCodecBridge(const std::string& mime, |
| 181 bool is_secure, |
| 182 MediaCodecDirection direction) { |
166 JNIEnv* env = AttachCurrentThread(); | 183 JNIEnv* env = AttachCurrentThread(); |
167 CHECK(env); | 184 CHECK(env); |
168 DCHECK(!mime.empty()); | 185 DCHECK(!mime.empty()); |
169 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); | 186 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); |
170 j_media_codec_.Reset( | 187 j_media_codec_.Reset( |
171 Java_MediaCodecBridge_create(env, j_mime.obj(), is_secure)); | 188 Java_MediaCodecBridge_create(env, j_mime.obj(), is_secure, direction)); |
172 } | 189 } |
173 | 190 |
174 MediaCodecBridge::~MediaCodecBridge() { | 191 MediaCodecBridge::~MediaCodecBridge() { |
175 JNIEnv* env = AttachCurrentThread(); | 192 JNIEnv* env = AttachCurrentThread(); |
176 CHECK(env); | 193 CHECK(env); |
177 if (j_media_codec_.obj()) | 194 if (j_media_codec_.obj()) |
178 Java_MediaCodecBridge_release(env, j_media_codec_.obj()); | 195 Java_MediaCodecBridge_release(env, j_media_codec_.obj()); |
179 } | 196 } |
180 | 197 |
181 bool MediaCodecBridge::StartInternal() { | 198 bool MediaCodecBridge::StartInternal() { |
(...skipping 14 matching lines...) Expand all Loading... |
196 } | 213 } |
197 | 214 |
198 void MediaCodecBridge::GetOutputFormat(int* width, int* height) { | 215 void MediaCodecBridge::GetOutputFormat(int* width, int* height) { |
199 JNIEnv* env = AttachCurrentThread(); | 216 JNIEnv* env = AttachCurrentThread(); |
200 | 217 |
201 *width = Java_MediaCodecBridge_getOutputWidth(env, j_media_codec_.obj()); | 218 *width = Java_MediaCodecBridge_getOutputWidth(env, j_media_codec_.obj()); |
202 *height = Java_MediaCodecBridge_getOutputHeight(env, j_media_codec_.obj()); | 219 *height = Java_MediaCodecBridge_getOutputHeight(env, j_media_codec_.obj()); |
203 } | 220 } |
204 | 221 |
205 MediaCodecStatus MediaCodecBridge::QueueInputBuffer( | 222 MediaCodecStatus MediaCodecBridge::QueueInputBuffer( |
206 int index, const uint8* data, int data_size, | 223 int index, |
| 224 const uint8* data, |
| 225 int orig_data_size, |
207 const base::TimeDelta& presentation_time) { | 226 const base::TimeDelta& presentation_time) { |
208 if (!FillInputBuffer(index, data, data_size)) | 227 DVLOG(3) << "MediaCodecBridge::QueueInputBuffer: " << index << ": " |
| 228 << orig_data_size; |
| 229 size_t data_size = base::checked_numeric_cast<size_t>(orig_data_size); |
| 230 if (data && !FillInputBuffer(index, data, data_size)) |
209 return MEDIA_CODEC_ERROR; | 231 return MEDIA_CODEC_ERROR; |
210 JNIEnv* env = AttachCurrentThread(); | 232 JNIEnv* env = AttachCurrentThread(); |
211 return static_cast<MediaCodecStatus>(Java_MediaCodecBridge_queueInputBuffer( | 233 return static_cast<MediaCodecStatus>( |
212 env, j_media_codec_.obj(), | 234 Java_MediaCodecBridge_queueInputBuffer(env, |
213 index, 0, data_size, presentation_time.InMicroseconds(), 0)); | 235 j_media_codec_.obj(), |
| 236 index, |
| 237 0, |
| 238 data_size, |
| 239 presentation_time.InMicroseconds(), |
| 240 0)); |
214 } | 241 } |
215 | 242 |
216 MediaCodecStatus MediaCodecBridge::QueueSecureInputBuffer( | 243 MediaCodecStatus MediaCodecBridge::QueueSecureInputBuffer( |
217 int index, const uint8* data, int data_size, const uint8* key_id, | 244 int index, |
218 int key_id_size, const uint8* iv, int iv_size, | 245 const uint8* data, |
219 const SubsampleEntry* subsamples, int subsamples_size, | 246 int orig_data_size, |
| 247 const uint8* key_id, |
| 248 int key_id_size, |
| 249 const uint8* iv, |
| 250 int iv_size, |
| 251 const SubsampleEntry* subsamples, |
| 252 int subsamples_size, |
220 const base::TimeDelta& presentation_time) { | 253 const base::TimeDelta& presentation_time) { |
221 if (!FillInputBuffer(index, data, data_size)) | 254 DVLOG(3) << "MediaCodecBridge::QueueSecureInputBuffer: " << index << ": " |
| 255 << orig_data_size; |
| 256 size_t data_size = base::checked_numeric_cast<size_t>(orig_data_size); |
| 257 if (data && !FillInputBuffer(index, data, data_size)) |
222 return MEDIA_CODEC_ERROR; | 258 return MEDIA_CODEC_ERROR; |
223 | 259 |
224 JNIEnv* env = AttachCurrentThread(); | 260 JNIEnv* env = AttachCurrentThread(); |
225 ScopedJavaLocalRef<jbyteArray> j_key_id = | 261 ScopedJavaLocalRef<jbyteArray> j_key_id = |
226 base::android::ToJavaByteArray(env, key_id, key_id_size); | 262 base::android::ToJavaByteArray(env, key_id, key_id_size); |
227 ScopedJavaLocalRef<jbyteArray> j_iv = | 263 ScopedJavaLocalRef<jbyteArray> j_iv = |
228 base::android::ToJavaByteArray(env, iv, iv_size); | 264 base::android::ToJavaByteArray(env, iv, iv_size); |
229 | 265 |
230 // MediaCodec.CryptoInfo documentations says passing NULL for |clear_array| | 266 // MediaCodec.CryptoInfo documentations says passing NULL for |clear_array| |
231 // to indicate that all data is encrypted. But it doesn't specify what | 267 // to indicate that all data is encrypted. But it doesn't specify what |
(...skipping 17 matching lines...) Expand all Loading... |
249 static_cast<uint32>(std::numeric_limits<jint>::max())) { | 285 static_cast<uint32>(std::numeric_limits<jint>::max())) { |
250 return MEDIA_CODEC_ERROR; | 286 return MEDIA_CODEC_ERROR; |
251 } | 287 } |
252 | 288 |
253 native_clear_array[i] = subsamples[i].clear_bytes; | 289 native_clear_array[i] = subsamples[i].clear_bytes; |
254 native_cypher_array[i] = subsamples[i].cypher_bytes; | 290 native_cypher_array[i] = subsamples[i].cypher_bytes; |
255 } | 291 } |
256 } | 292 } |
257 | 293 |
258 ScopedJavaLocalRef<jintArray> clear_array = | 294 ScopedJavaLocalRef<jintArray> clear_array = |
259 ToJavaIntArray(env, native_clear_array.Pass(), new_subsamples_size); | 295 ToJavaIntArray(env, native_clear_array.Pass(), new_subsamples_size); |
260 ScopedJavaLocalRef<jintArray> cypher_array = | 296 ScopedJavaLocalRef<jintArray> cypher_array = |
261 ToJavaIntArray(env, native_cypher_array.Pass(), new_subsamples_size); | 297 ToJavaIntArray(env, native_cypher_array.Pass(), new_subsamples_size); |
262 | 298 |
263 return static_cast<MediaCodecStatus>( | 299 return static_cast<MediaCodecStatus>( |
264 Java_MediaCodecBridge_queueSecureInputBuffer( | 300 Java_MediaCodecBridge_queueSecureInputBuffer( |
265 env, j_media_codec_.obj(), index, 0, j_iv.obj(), j_key_id.obj(), | 301 env, |
266 clear_array.obj(), cypher_array.obj(), new_subsamples_size, | 302 j_media_codec_.obj(), |
| 303 index, |
| 304 0, |
| 305 j_iv.obj(), |
| 306 j_key_id.obj(), |
| 307 clear_array.obj(), |
| 308 cypher_array.obj(), |
| 309 new_subsamples_size, |
267 presentation_time.InMicroseconds())); | 310 presentation_time.InMicroseconds())); |
268 } | 311 } |
269 | 312 |
270 void MediaCodecBridge::QueueEOS(int input_buffer_index) { | 313 void MediaCodecBridge::QueueEOS(int input_buffer_index) { |
| 314 DVLOG(3) << "MediaCodecBridge::QueueEOS: " << input_buffer_index; |
271 JNIEnv* env = AttachCurrentThread(); | 315 JNIEnv* env = AttachCurrentThread(); |
272 Java_MediaCodecBridge_queueInputBuffer( | 316 Java_MediaCodecBridge_queueInputBuffer(env, |
273 env, j_media_codec_.obj(), | 317 j_media_codec_.obj(), |
274 input_buffer_index, 0, 0, 0, kBufferFlagEndOfStream); | 318 input_buffer_index, |
| 319 0, |
| 320 0, |
| 321 0, |
| 322 kBufferFlagEndOfStream); |
275 } | 323 } |
276 | 324 |
277 MediaCodecStatus MediaCodecBridge::DequeueInputBuffer( | 325 MediaCodecStatus MediaCodecBridge::DequeueInputBuffer( |
278 const base::TimeDelta& timeout, int* index) { | 326 const base::TimeDelta& timeout, |
| 327 int* index) { |
279 JNIEnv* env = AttachCurrentThread(); | 328 JNIEnv* env = AttachCurrentThread(); |
280 ScopedJavaLocalRef<jobject> result = Java_MediaCodecBridge_dequeueInputBuffer( | 329 ScopedJavaLocalRef<jobject> result = Java_MediaCodecBridge_dequeueInputBuffer( |
281 env, j_media_codec_.obj(), timeout.InMicroseconds()); | 330 env, j_media_codec_.obj(), timeout.InMicroseconds()); |
282 *index = Java_DequeueInputResult_index(env, result.obj()); | 331 *index = Java_DequeueInputResult_index(env, result.obj()); |
283 return static_cast<MediaCodecStatus>( | 332 MediaCodecStatus status = static_cast<MediaCodecStatus>( |
284 Java_DequeueInputResult_status(env, result.obj())); | 333 Java_DequeueInputResult_status(env, result.obj())); |
| 334 DVLOG(3) << "MediaCodecBridge::DequeueInputBuffer: status: " << status |
| 335 << ", index: " << *index; |
| 336 return status; |
285 } | 337 } |
286 | 338 |
287 MediaCodecStatus MediaCodecBridge::DequeueOutputBuffer( | 339 MediaCodecStatus MediaCodecBridge::DequeueOutputBuffer( |
288 const base::TimeDelta& timeout, int* index, size_t* offset, size_t* size, | 340 const base::TimeDelta& timeout, |
289 base::TimeDelta* presentation_time, bool* end_of_stream) { | 341 int* index, |
| 342 size_t* offset, |
| 343 size_t* size, |
| 344 base::TimeDelta* presentation_time, |
| 345 bool* end_of_stream, |
| 346 bool* key_frame) { |
290 JNIEnv* env = AttachCurrentThread(); | 347 JNIEnv* env = AttachCurrentThread(); |
291 ScopedJavaLocalRef<jobject> result = | 348 ScopedJavaLocalRef<jobject> result = |
292 Java_MediaCodecBridge_dequeueOutputBuffer(env, j_media_codec_.obj(), | 349 Java_MediaCodecBridge_dequeueOutputBuffer( |
293 timeout.InMicroseconds()); | 350 env, j_media_codec_.obj(), timeout.InMicroseconds()); |
294 *index = Java_DequeueOutputResult_index(env, result.obj());; | 351 *index = Java_DequeueOutputResult_index(env, result.obj()); |
295 *offset = base::checked_numeric_cast<size_t>( | 352 *offset = base::checked_numeric_cast<size_t>( |
296 Java_DequeueOutputResult_offset(env, result.obj())); | 353 Java_DequeueOutputResult_offset(env, result.obj())); |
297 *size = base::checked_numeric_cast<size_t>( | 354 *size = base::checked_numeric_cast<size_t>( |
298 Java_DequeueOutputResult_numBytes(env, result.obj())); | 355 Java_DequeueOutputResult_numBytes(env, result.obj())); |
299 *presentation_time = base::TimeDelta::FromMicroseconds( | 356 if (presentation_time) { |
300 Java_DequeueOutputResult_presentationTimeMicroseconds(env, result.obj())); | 357 *presentation_time = base::TimeDelta::FromMicroseconds( |
| 358 Java_DequeueOutputResult_presentationTimeMicroseconds(env, |
| 359 result.obj())); |
| 360 } |
301 int flags = Java_DequeueOutputResult_flags(env, result.obj()); | 361 int flags = Java_DequeueOutputResult_flags(env, result.obj()); |
302 *end_of_stream = flags & kBufferFlagEndOfStream; | 362 if (end_of_stream) |
303 return static_cast<MediaCodecStatus>( | 363 *end_of_stream = flags & kBufferFlagEndOfStream; |
| 364 if (key_frame) |
| 365 *key_frame = flags & kBufferFlagSyncFrame; |
| 366 MediaCodecStatus status = static_cast<MediaCodecStatus>( |
304 Java_DequeueOutputResult_status(env, result.obj())); | 367 Java_DequeueOutputResult_status(env, result.obj())); |
| 368 DVLOG(3) << "MediaCodecBridge::DequeueOutputBuffer: status: " << status |
| 369 << ", index: " << *index << ", offset: " << *offset |
| 370 << ", size: " << *size << ", flags: " << flags; |
| 371 return status; |
305 } | 372 } |
306 | 373 |
307 void MediaCodecBridge::ReleaseOutputBuffer(int index, bool render) { | 374 void MediaCodecBridge::ReleaseOutputBuffer(int index, bool render) { |
| 375 DVLOG(3) << "MediaCodecBridge::ReleaseOutputBuffer: " << index; |
308 JNIEnv* env = AttachCurrentThread(); | 376 JNIEnv* env = AttachCurrentThread(); |
309 CHECK(env); | 377 CHECK(env); |
310 | 378 |
311 Java_MediaCodecBridge_releaseOutputBuffer( | 379 Java_MediaCodecBridge_releaseOutputBuffer( |
312 env, j_media_codec_.obj(), index, render); | 380 env, j_media_codec_.obj(), index, render); |
313 } | 381 } |
314 | 382 |
| 383 int MediaCodecBridge::GetInputBuffersCount() { |
| 384 JNIEnv* env = AttachCurrentThread(); |
| 385 return Java_MediaCodecBridge_getInputBuffersCount(env, j_media_codec_.obj()); |
| 386 } |
| 387 |
| 388 int MediaCodecBridge::GetOutputBuffersCount() { |
| 389 JNIEnv* env = AttachCurrentThread(); |
| 390 return Java_MediaCodecBridge_getOutputBuffersCount(env, j_media_codec_.obj()); |
| 391 } |
| 392 |
| 393 size_t MediaCodecBridge::GetOutputBuffersCapacity() { |
| 394 JNIEnv* env = AttachCurrentThread(); |
| 395 return Java_MediaCodecBridge_getOutputBuffersCapacity(env, |
| 396 j_media_codec_.obj()); |
| 397 } |
| 398 |
315 bool MediaCodecBridge::GetOutputBuffers() { | 399 bool MediaCodecBridge::GetOutputBuffers() { |
316 JNIEnv* env = AttachCurrentThread(); | 400 JNIEnv* env = AttachCurrentThread(); |
317 return Java_MediaCodecBridge_getOutputBuffers(env, j_media_codec_.obj()); | 401 return Java_MediaCodecBridge_getOutputBuffers(env, j_media_codec_.obj()); |
318 } | 402 } |
319 | 403 |
320 bool MediaCodecBridge::FillInputBuffer(int index, const uint8* data, int size) { | 404 void MediaCodecBridge::GetInputBuffer(int input_buffer_index, |
| 405 uint8** data, |
| 406 size_t* capacity) { |
321 JNIEnv* env = AttachCurrentThread(); | 407 JNIEnv* env = AttachCurrentThread(); |
| 408 ScopedJavaLocalRef<jobject> j_buffer(Java_MediaCodecBridge_getInputBuffer( |
| 409 env, j_media_codec_.obj(), input_buffer_index)); |
| 410 *data = static_cast<uint8*>(env->GetDirectBufferAddress(j_buffer.obj())); |
| 411 *capacity = base::checked_numeric_cast<size_t>( |
| 412 env->GetDirectBufferCapacity(j_buffer.obj())); |
| 413 } |
322 | 414 |
| 415 bool MediaCodecBridge::CopyFromOutputBuffer(int index, |
| 416 size_t offset, |
| 417 void* dst, |
| 418 int dst_size) { |
| 419 JNIEnv* env = AttachCurrentThread(); |
323 ScopedJavaLocalRef<jobject> j_buffer( | 420 ScopedJavaLocalRef<jobject> j_buffer( |
324 Java_MediaCodecBridge_getInputBuffer(env, j_media_codec_.obj(), index)); | 421 Java_MediaCodecBridge_getOutputBuffer(env, j_media_codec_.obj(), index)); |
325 jlong capacity = env->GetDirectBufferCapacity(j_buffer.obj()); | 422 void* src_data = |
| 423 reinterpret_cast<uint8*>(env->GetDirectBufferAddress(j_buffer.obj())) + |
| 424 offset; |
| 425 int src_capacity = env->GetDirectBufferCapacity(j_buffer.obj()) - offset; |
| 426 if (src_capacity < dst_size) |
| 427 return false; |
| 428 memcpy(dst, src_data, dst_size); |
| 429 return true; |
| 430 } |
| 431 |
| 432 bool MediaCodecBridge::FillInputBuffer(int index, |
| 433 const uint8* data, |
| 434 size_t size) { |
| 435 uint8* dst = NULL; |
| 436 size_t capacity = 0; |
| 437 GetInputBuffer(index, &dst, &capacity); |
| 438 CHECK(dst); |
| 439 |
326 if (size > capacity) { | 440 if (size > capacity) { |
327 LOG(ERROR) << "Input buffer size " << size | 441 LOG(ERROR) << "Input buffer size " << size |
328 << " exceeds MediaCodec input buffer capacity: " << capacity; | 442 << " exceeds MediaCodec input buffer capacity: " << capacity; |
329 return false; | 443 return false; |
330 } | 444 } |
331 | 445 |
332 uint8* direct_buffer = | 446 memcpy(dst, data, size); |
333 static_cast<uint8*>(env->GetDirectBufferAddress(j_buffer.obj())); | |
334 memcpy(direct_buffer, data, size); | |
335 return true; | 447 return true; |
336 } | 448 } |
337 | 449 |
338 AudioCodecBridge::AudioCodecBridge(const std::string& mime) | 450 AudioCodecBridge::AudioCodecBridge(const std::string& mime) |
339 // Audio codec doesn't care about security level. | 451 // Audio codec doesn't care about security level and there is no need for |
340 : MediaCodecBridge(mime, false) { | 452 // audio encoding yet. |
341 } | 453 : MediaCodecBridge(mime, false, MEDIA_CODEC_DECODER) {} |
342 | 454 |
343 bool AudioCodecBridge::Start( | 455 bool AudioCodecBridge::Start(const AudioCodec& codec, |
344 const AudioCodec& codec, int sample_rate, int channel_count, | 456 int sample_rate, |
345 const uint8* extra_data, size_t extra_data_size, bool play_audio, | 457 int channel_count, |
346 jobject media_crypto) { | 458 const uint8* extra_data, |
| 459 size_t extra_data_size, |
| 460 bool play_audio, |
| 461 jobject media_crypto) { |
347 JNIEnv* env = AttachCurrentThread(); | 462 JNIEnv* env = AttachCurrentThread(); |
348 | 463 |
349 if (!media_codec()) | 464 if (!media_codec()) |
350 return false; | 465 return false; |
351 | 466 |
352 std::string codec_string = AudioCodecToAndroidMimeType(codec); | 467 std::string codec_string = AudioCodecToAndroidMimeType(codec); |
353 if (codec_string.empty()) | 468 if (codec_string.empty()) |
354 return false; | 469 return false; |
355 | 470 |
356 ScopedJavaLocalRef<jstring> j_mime = | 471 ScopedJavaLocalRef<jstring> j_mime = |
357 ConvertUTF8ToJavaString(env, codec_string); | 472 ConvertUTF8ToJavaString(env, codec_string); |
358 ScopedJavaLocalRef<jobject> j_format( | 473 ScopedJavaLocalRef<jobject> j_format(Java_MediaCodecBridge_createAudioFormat( |
359 Java_MediaCodecBridge_createAudioFormat( | 474 env, j_mime.obj(), sample_rate, channel_count)); |
360 env, j_mime.obj(), sample_rate, channel_count)); | |
361 DCHECK(!j_format.is_null()); | 475 DCHECK(!j_format.is_null()); |
362 | 476 |
363 if (!ConfigureMediaFormat(j_format.obj(), codec, extra_data, extra_data_size)) | 477 if (!ConfigureMediaFormat(j_format.obj(), codec, extra_data, extra_data_size)) |
364 return false; | 478 return false; |
365 | 479 |
366 if (!Java_MediaCodecBridge_configureAudio( | 480 if (!Java_MediaCodecBridge_configureAudio( |
367 env, media_codec(), j_format.obj(), media_crypto, 0, play_audio)) { | 481 env, media_codec(), j_format.obj(), media_crypto, 0, play_audio)) { |
368 return false; | 482 return false; |
369 } | 483 } |
370 | 484 |
371 return StartInternal(); | 485 return StartInternal(); |
372 } | 486 } |
373 | 487 |
374 bool AudioCodecBridge::ConfigureMediaFormat( | 488 bool AudioCodecBridge::ConfigureMediaFormat(jobject j_format, |
375 jobject j_format, const AudioCodec& codec, const uint8* extra_data, | 489 const AudioCodec& codec, |
376 size_t extra_data_size) { | 490 const uint8* extra_data, |
| 491 size_t extra_data_size) { |
377 if (extra_data_size == 0) | 492 if (extra_data_size == 0) |
378 return true; | 493 return true; |
379 | 494 |
380 JNIEnv* env = AttachCurrentThread(); | 495 JNIEnv* env = AttachCurrentThread(); |
381 switch (codec) { | 496 switch (codec) { |
382 case kCodecVorbis: | 497 case kCodecVorbis: { |
383 { | |
384 if (extra_data[0] != 2) { | 498 if (extra_data[0] != 2) { |
385 LOG(ERROR) << "Invalid number of vorbis headers before the codec " | 499 LOG(ERROR) << "Invalid number of vorbis headers before the codec " |
386 << "header: " << extra_data[0]; | 500 << "header: " << extra_data[0]; |
387 return false; | 501 return false; |
388 } | 502 } |
389 | 503 |
390 size_t header_length[2]; | 504 size_t header_length[2]; |
391 // |total_length| keeps track of the total number of bytes before the last | 505 // |total_length| keeps track of the total number of bytes before the last |
392 // header. | 506 // header. |
393 size_t total_length = 1; | 507 size_t total_length = 1; |
(...skipping 24 matching lines...) Expand all Loading... |
418 Java_MediaCodecBridge_setCodecSpecificData( | 532 Java_MediaCodecBridge_setCodecSpecificData( |
419 env, j_format, 0, first_header.obj()); | 533 env, j_format, 0, first_header.obj()); |
420 // The last header is codec header. | 534 // The last header is codec header. |
421 ScopedJavaLocalRef<jbyteArray> last_header = | 535 ScopedJavaLocalRef<jbyteArray> last_header = |
422 base::android::ToJavaByteArray( | 536 base::android::ToJavaByteArray( |
423 env, extra_data + total_length, extra_data_size - total_length); | 537 env, extra_data + total_length, extra_data_size - total_length); |
424 Java_MediaCodecBridge_setCodecSpecificData( | 538 Java_MediaCodecBridge_setCodecSpecificData( |
425 env, j_format, 1, last_header.obj()); | 539 env, j_format, 1, last_header.obj()); |
426 break; | 540 break; |
427 } | 541 } |
428 case kCodecAAC: | 542 case kCodecAAC: { |
429 { | |
430 media::BitReader reader(extra_data, extra_data_size); | 543 media::BitReader reader(extra_data, extra_data_size); |
431 | 544 |
432 // The following code is copied from aac.cc | 545 // The following code is copied from aac.cc |
433 // TODO(qinmin): refactor the code in aac.cc to make it more reusable. | 546 // TODO(qinmin): refactor the code in aac.cc to make it more reusable. |
434 uint8 profile = 0; | 547 uint8 profile = 0; |
435 uint8 frequency_index = 0; | 548 uint8 frequency_index = 0; |
436 uint8 channel_config = 0; | 549 uint8 channel_config = 0; |
437 if (!reader.ReadBits(5, &profile) || | 550 if (!reader.ReadBits(5, &profile) || |
438 !reader.ReadBits(4, &frequency_index)) { | 551 !reader.ReadBits(4, &frequency_index)) { |
439 LOG(ERROR) << "Unable to parse AAC header"; | 552 LOG(ERROR) << "Unable to parse AAC header"; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
478 void AudioCodecBridge::PlayOutputBuffer(int index, size_t size) { | 591 void AudioCodecBridge::PlayOutputBuffer(int index, size_t size) { |
479 DCHECK_LE(0, index); | 592 DCHECK_LE(0, index); |
480 int numBytes = base::checked_numeric_cast<int>(size); | 593 int numBytes = base::checked_numeric_cast<int>(size); |
481 JNIEnv* env = AttachCurrentThread(); | 594 JNIEnv* env = AttachCurrentThread(); |
482 ScopedJavaLocalRef<jobject> buf = | 595 ScopedJavaLocalRef<jobject> buf = |
483 Java_MediaCodecBridge_getOutputBuffer(env, media_codec(), index); | 596 Java_MediaCodecBridge_getOutputBuffer(env, media_codec(), index); |
484 uint8* buffer = static_cast<uint8*>(env->GetDirectBufferAddress(buf.obj())); | 597 uint8* buffer = static_cast<uint8*>(env->GetDirectBufferAddress(buf.obj())); |
485 | 598 |
486 ScopedJavaLocalRef<jbyteArray> byte_array = | 599 ScopedJavaLocalRef<jbyteArray> byte_array = |
487 base::android::ToJavaByteArray(env, buffer, numBytes); | 600 base::android::ToJavaByteArray(env, buffer, numBytes); |
488 Java_MediaCodecBridge_playOutputBuffer( | 601 Java_MediaCodecBridge_playOutputBuffer(env, media_codec(), byte_array.obj()); |
489 env, media_codec(), byte_array.obj()); | |
490 } | 602 } |
491 | 603 |
492 void AudioCodecBridge::SetVolume(double volume) { | 604 void AudioCodecBridge::SetVolume(double volume) { |
493 JNIEnv* env = AttachCurrentThread(); | 605 JNIEnv* env = AttachCurrentThread(); |
494 Java_MediaCodecBridge_setVolume(env, media_codec(), volume); | 606 Java_MediaCodecBridge_setVolume(env, media_codec(), volume); |
495 } | 607 } |
496 | 608 |
497 VideoCodecBridge::VideoCodecBridge(const std::string& mime, bool is_secure) | |
498 : MediaCodecBridge(mime, is_secure) { | |
499 } | |
500 | |
501 bool VideoCodecBridge::Start( | |
502 const VideoCodec& codec, const gfx::Size& size, jobject surface, | |
503 jobject media_crypto) { | |
504 JNIEnv* env = AttachCurrentThread(); | |
505 | |
506 if (!media_codec()) | |
507 return false; | |
508 | |
509 std::string codec_string = VideoCodecToAndroidMimeType(codec); | |
510 if (codec_string.empty()) | |
511 return false; | |
512 | |
513 ScopedJavaLocalRef<jstring> j_mime = | |
514 ConvertUTF8ToJavaString(env, codec_string); | |
515 ScopedJavaLocalRef<jobject> j_format( | |
516 Java_MediaCodecBridge_createVideoFormat( | |
517 env, j_mime.obj(), size.width(), size.height())); | |
518 DCHECK(!j_format.is_null()); | |
519 if (!Java_MediaCodecBridge_configureVideo( | |
520 env, media_codec(), j_format.obj(), surface, media_crypto, 0)) { | |
521 return false; | |
522 } | |
523 | |
524 return StartInternal(); | |
525 } | |
526 | |
527 AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec& codec) { | 609 AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec& codec) { |
528 const std::string mime = AudioCodecToAndroidMimeType(codec); | 610 const std::string mime = AudioCodecToAndroidMimeType(codec); |
529 return mime.empty() ? NULL : new AudioCodecBridge(mime); | 611 return mime.empty() ? NULL : new AudioCodecBridge(mime); |
530 } | 612 } |
531 | 613 |
532 // static | 614 // static |
533 bool AudioCodecBridge::IsKnownUnaccelerated(const AudioCodec& codec) { | 615 bool AudioCodecBridge::IsKnownUnaccelerated(const AudioCodec& codec) { |
534 return MediaCodecBridge::IsKnownUnaccelerated( | 616 return MediaCodecBridge::IsKnownUnaccelerated( |
535 AudioCodecToAndroidMimeType(codec)); | 617 AudioCodecToAndroidMimeType(codec), MEDIA_CODEC_DECODER); |
536 } | |
537 | |
538 VideoCodecBridge* VideoCodecBridge::Create(const VideoCodec& codec, | |
539 bool is_secure) { | |
540 const std::string mime = VideoCodecToAndroidMimeType(codec); | |
541 return mime.empty() ? NULL : new VideoCodecBridge(mime, is_secure); | |
542 } | 618 } |
543 | 619 |
544 // static | 620 // static |
545 bool VideoCodecBridge::IsKnownUnaccelerated(const VideoCodec& codec) { | 621 bool VideoCodecBridge::IsKnownUnaccelerated(const VideoCodec& codec, |
| 622 MediaCodecDirection direction) { |
546 return MediaCodecBridge::IsKnownUnaccelerated( | 623 return MediaCodecBridge::IsKnownUnaccelerated( |
547 VideoCodecToAndroidMimeType(codec)); | 624 VideoCodecToAndroidMimeType(codec), direction); |
| 625 } |
| 626 |
| 627 VideoCodecBridge* VideoCodecBridge::CreateDecoder(const VideoCodec& codec, |
| 628 bool is_secure, |
| 629 const gfx::Size& size, |
| 630 jobject surface, |
| 631 jobject media_crypto) { |
| 632 JNIEnv* env = AttachCurrentThread(); |
| 633 const std::string mime = VideoCodecToAndroidMimeType(codec); |
| 634 if (mime.empty()) |
| 635 return NULL; |
| 636 |
| 637 scoped_ptr<VideoCodecBridge> bridge( |
| 638 new VideoCodecBridge(mime, is_secure, MEDIA_CODEC_DECODER)); |
| 639 |
| 640 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); |
| 641 ScopedJavaLocalRef<jobject> j_format( |
| 642 Java_MediaCodecBridge_createVideoDecoderFormat( |
| 643 env, j_mime.obj(), size.width(), size.height())); |
| 644 DCHECK(!j_format.is_null()); |
| 645 if (!Java_MediaCodecBridge_configureVideo(env, |
| 646 bridge->media_codec(), |
| 647 j_format.obj(), |
| 648 surface, |
| 649 media_crypto, |
| 650 0)) { |
| 651 return NULL; |
| 652 } |
| 653 |
| 654 return bridge->StartInternal() ? bridge.release() : NULL; |
| 655 } |
| 656 |
| 657 VideoCodecBridge* VideoCodecBridge::CreateEncoder(const VideoCodec& codec, |
| 658 const gfx::Size& size, |
| 659 int bit_rate, |
| 660 int frame_rate, |
| 661 int i_frame_interval, |
| 662 int color_format) { |
| 663 JNIEnv* env = AttachCurrentThread(); |
| 664 const std::string mime = VideoCodecToAndroidMimeType(codec); |
| 665 if (mime.empty()) |
| 666 return NULL; |
| 667 |
| 668 scoped_ptr<VideoCodecBridge> bridge( |
| 669 new VideoCodecBridge(mime, false, MEDIA_CODEC_ENCODER)); |
| 670 |
| 671 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); |
| 672 ScopedJavaLocalRef<jobject> j_format( |
| 673 Java_MediaCodecBridge_createVideoEncoderFormat(env, |
| 674 j_mime.obj(), |
| 675 size.width(), |
| 676 size.height(), |
| 677 bit_rate, |
| 678 frame_rate, |
| 679 i_frame_interval, |
| 680 color_format)); |
| 681 DCHECK(!j_format.is_null()); |
| 682 if (!Java_MediaCodecBridge_configureVideo(env, |
| 683 bridge->media_codec(), |
| 684 j_format.obj(), |
| 685 NULL, |
| 686 NULL, |
| 687 kConfigureFlagEncode)) { |
| 688 return NULL; |
| 689 } |
| 690 |
| 691 return bridge->StartInternal() ? bridge.release() : NULL; |
| 692 } |
| 693 |
| 694 VideoCodecBridge::VideoCodecBridge(const std::string& mime, |
| 695 bool is_secure, |
| 696 MediaCodecDirection direction) |
| 697 : MediaCodecBridge(mime, is_secure, direction) {} |
| 698 |
| 699 void VideoCodecBridge::SetVideoBitrate(int bps) { |
| 700 JNIEnv* env = AttachCurrentThread(); |
| 701 Java_MediaCodecBridge_setVideoBitrate(env, media_codec(), bps); |
| 702 } |
| 703 |
| 704 void VideoCodecBridge::RequestKeyFrameSoon() { |
| 705 JNIEnv* env = AttachCurrentThread(); |
| 706 Java_MediaCodecBridge_requestKeyFrameSoon(env, media_codec()); |
548 } | 707 } |
549 | 708 |
550 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) { | 709 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) { |
551 return RegisterNativesImpl(env); | 710 return RegisterNativesImpl(env); |
552 } | 711 } |
553 | 712 |
554 } // namespace media | 713 } // namespace media |
OLD | NEW |