Fix for browser_plugin_host_browsertest when embedder is not yet available.
[chromium-blink-merge.git] / media / base / android / media_codec_bridge.cc
blob1c4928aad9696603ca95f542b0d42ff65ac6b546
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
3 // found in the LICENSE file.
5 #include "media/base/android/media_codec_bridge.h"
7 #include <jni.h>
8 #include <string>
10 #include "base/android/build_info.h"
11 #include "base/android/jni_android.h"
12 #include "base/android/jni_array.h"
13 #include "base/android/jni_string.h"
14 #include "base/basictypes.h"
15 #include "base/lazy_instance.h"
16 #include "base/logging.h"
17 #include "base/safe_numerics.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h"
20 #include "jni/MediaCodecBridge_jni.h"
21 #include "media/base/bit_reader.h"
22 #include "media/base/decrypt_config.h"
24 using base::android::AttachCurrentThread;
25 using base::android::ConvertJavaStringToUTF8;
26 using base::android::ConvertUTF8ToJavaString;
27 using base::android::ScopedJavaLocalRef;
29 namespace media {
31 enum { kBufferFlagEndOfStream = 4 };
33 static const std::string AudioCodecToAndroidMimeType(const AudioCodec& codec) {
34 switch (codec) {
35 case kCodecMP3:
36 return "audio/mpeg";
37 case kCodecVorbis:
38 return "audio/vorbis";
39 case kCodecAAC:
40 return "audio/mp4a-latm";
41 default:
42 return std::string();
46 static const std::string VideoCodecToAndroidMimeType(const VideoCodec& codec) {
47 switch (codec) {
48 case kCodecH264:
49 return "video/avc";
50 case kCodecVP8:
51 return "video/x-vnd.on2.vp8";
52 default:
53 return std::string();
57 static const std::string CodecTypeToAndroidMimeType(const std::string& codec) {
58 // TODO(xhwang): Shall we handle more detailed strings like "mp4a.40.2"?
59 if (codec == "avc1")
60 return "video/avc";
61 if (codec == "mp4a")
62 return "audio/mp4a-latm";
63 if (codec == "vp8" || codec == "vp8.0")
64 return "video/x-vnd.on2.vp8";
65 if (codec == "vorbis")
66 return "audio/vorbis";
67 return std::string();
70 // TODO(qinmin): using a map to help all the conversions in this class.
71 static const std::string AndroidMimeTypeToCodecType(const std::string& mime) {
72 if (mime == "video/mp4v-es")
73 return "mp4v";
74 if (mime == "video/avc")
75 return "avc1";
76 if (mime == "video/x-vnd.on2.vp8")
77 return "vp8";
78 if (mime == "video/x-vnd.on2.vp9")
79 return "vp9";
80 if (mime == "audio/mp4a-latm")
81 return "mp4a";
82 if (mime == "audio/mpeg")
83 return "mp3";
84 if (mime == "audio/vorbis")
85 return "vorbis";
86 return std::string();
89 static ScopedJavaLocalRef<jintArray> ToJavaIntArray(
90 JNIEnv* env, scoped_ptr<jint[]> native_array, int size) {
91 ScopedJavaLocalRef<jintArray> j_array(env, env->NewIntArray(size));
92 env->SetIntArrayRegion(j_array.obj(), 0, size, native_array.get());
93 return j_array;
96 // static
97 bool MediaCodecBridge::IsAvailable() {
98 // MediaCodec is only available on JB and greater.
99 return base::android::BuildInfo::GetInstance()->sdk_int() >= 16;
102 // static
103 void MediaCodecBridge::GetCodecsInfo(
104 std::vector<CodecsInfo>* codecs_info) {
105 JNIEnv* env = AttachCurrentThread();
106 if (!IsAvailable())
107 return;
109 std::string mime_type;
110 std::string codec_name;
111 ScopedJavaLocalRef<jobjectArray> j_codec_info_array =
112 Java_MediaCodecBridge_getCodecsInfo(env);
113 jsize len = env->GetArrayLength(j_codec_info_array.obj());
114 for (jsize i = 0; i < len; ++i) {
115 ScopedJavaLocalRef<jobject> j_info(
116 env, env->GetObjectArrayElement(j_codec_info_array.obj(), i));
117 ScopedJavaLocalRef<jstring> j_codec_type =
118 Java_CodecInfo_codecType(env, j_info.obj());
119 ConvertJavaStringToUTF8(env, j_codec_type.obj(), &mime_type);
120 ScopedJavaLocalRef<jstring> j_codec_name =
121 Java_CodecInfo_codecName(env, j_info.obj());
122 CodecsInfo info;
123 info.codecs = AndroidMimeTypeToCodecType(mime_type);
124 ConvertJavaStringToUTF8(env, j_codec_name.obj(), &info.name);
125 info.secure_decoder_supported =
126 Java_CodecInfo_isSecureDecoderSupported(env, j_info.obj());
127 codecs_info->push_back(info);
131 // static
132 bool MediaCodecBridge::CanDecode(const std::string& codec, bool is_secure) {
133 JNIEnv* env = AttachCurrentThread();
134 std::string mime = CodecTypeToAndroidMimeType(codec);
135 if (mime.empty())
136 return false;
137 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime);
138 ScopedJavaLocalRef<jobject> j_media_codec_bridge =
139 Java_MediaCodecBridge_create(env, j_mime.obj(), is_secure);
140 if (!j_media_codec_bridge.is_null()) {
141 Java_MediaCodecBridge_release(env, j_media_codec_bridge.obj());
142 return true;
144 return false;
147 // static
148 bool MediaCodecBridge::IsKnownUnaccelerated(const std::string& mime_type) {
149 std::string codec_type = AndroidMimeTypeToCodecType(mime_type);
150 std::vector<media::MediaCodecBridge::CodecsInfo> codecs_info;
151 media::MediaCodecBridge::GetCodecsInfo(&codecs_info);
152 for (size_t i = 0; i < codecs_info.size(); ++i) {
153 if (codecs_info[i].codecs == codec_type) {
154 // It would be nice if MediaCodecInfo externalized some notion of
155 // HW-acceleration but it doesn't. Android Media guidance is that the
156 // prefix below is always used for SW decoders, so that's what we use.
157 return StartsWithASCII(codecs_info[i].name, "OMX.google.", true);
160 return true;
163 MediaCodecBridge::MediaCodecBridge(const std::string& mime, bool is_secure) {
164 JNIEnv* env = AttachCurrentThread();
165 CHECK(env);
166 DCHECK(!mime.empty());
167 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime);
168 j_media_codec_.Reset(
169 Java_MediaCodecBridge_create(env, j_mime.obj(), is_secure));
172 MediaCodecBridge::~MediaCodecBridge() {
173 JNIEnv* env = AttachCurrentThread();
174 CHECK(env);
175 if (j_media_codec_.obj())
176 Java_MediaCodecBridge_release(env, j_media_codec_.obj());
179 bool MediaCodecBridge::StartInternal() {
180 JNIEnv* env = AttachCurrentThread();
181 return Java_MediaCodecBridge_start(env, j_media_codec_.obj()) &&
182 GetOutputBuffers();
185 MediaCodecStatus MediaCodecBridge::Reset() {
186 JNIEnv* env = AttachCurrentThread();
187 return static_cast<MediaCodecStatus>(
188 Java_MediaCodecBridge_flush(env, j_media_codec_.obj()));
191 void MediaCodecBridge::Stop() {
192 JNIEnv* env = AttachCurrentThread();
193 Java_MediaCodecBridge_stop(env, j_media_codec_.obj());
196 void MediaCodecBridge::GetOutputFormat(int* width, int* height) {
197 JNIEnv* env = AttachCurrentThread();
199 *width = Java_MediaCodecBridge_getOutputWidth(env, j_media_codec_.obj());
200 *height = Java_MediaCodecBridge_getOutputHeight(env, j_media_codec_.obj());
203 MediaCodecStatus MediaCodecBridge::QueueInputBuffer(
204 int index, const uint8* data, int data_size,
205 const base::TimeDelta& presentation_time) {
206 if (!FillInputBuffer(index, data, data_size))
207 return MEDIA_CODEC_ERROR;
208 JNIEnv* env = AttachCurrentThread();
209 return static_cast<MediaCodecStatus>(Java_MediaCodecBridge_queueInputBuffer(
210 env, j_media_codec_.obj(),
211 index, 0, data_size, presentation_time.InMicroseconds(), 0));
214 MediaCodecStatus MediaCodecBridge::QueueSecureInputBuffer(
215 int index, const uint8* data, int data_size, const uint8* key_id,
216 int key_id_size, const uint8* iv, int iv_size,
217 const SubsampleEntry* subsamples, int subsamples_size,
218 const base::TimeDelta& presentation_time) {
219 if (!FillInputBuffer(index, data, data_size))
220 return MEDIA_CODEC_ERROR;
222 JNIEnv* env = AttachCurrentThread();
223 ScopedJavaLocalRef<jbyteArray> j_key_id =
224 base::android::ToJavaByteArray(env, key_id, key_id_size);
225 ScopedJavaLocalRef<jbyteArray> j_iv =
226 base::android::ToJavaByteArray(env, iv, iv_size);
228 // MediaCodec.CryptoInfo documentations says passing NULL for |clear_array|
229 // to indicate that all data is encrypted. But it doesn't specify what
230 // |cypher_array| and |subsamples_size| should be in that case. Passing
231 // one subsample here just to be on the safe side.
232 int new_subsamples_size = subsamples_size == 0 ? 1 : subsamples_size;
234 scoped_ptr<jint[]> native_clear_array(new jint[new_subsamples_size]);
235 scoped_ptr<jint[]> native_cypher_array(new jint[new_subsamples_size]);
237 if (subsamples_size == 0) {
238 DCHECK(!subsamples);
239 native_clear_array[0] = 0;
240 native_cypher_array[0] = data_size;
241 } else {
242 DCHECK_GT(subsamples_size, 0);
243 DCHECK(subsamples);
244 for (int i = 0; i < subsamples_size; ++i) {
245 native_clear_array[i] = subsamples[i].clear_bytes;
246 native_cypher_array[i] = subsamples[i].cypher_bytes;
250 ScopedJavaLocalRef<jintArray> clear_array =
251 ToJavaIntArray(env, native_clear_array.Pass(), new_subsamples_size);
252 ScopedJavaLocalRef<jintArray> cypher_array =
253 ToJavaIntArray(env, native_cypher_array.Pass(), new_subsamples_size);
255 return static_cast<MediaCodecStatus>(
256 Java_MediaCodecBridge_queueSecureInputBuffer(
257 env, j_media_codec_.obj(), index, 0, j_iv.obj(), j_key_id.obj(),
258 clear_array.obj(), cypher_array.obj(), new_subsamples_size,
259 presentation_time.InMicroseconds()));
262 void MediaCodecBridge::QueueEOS(int input_buffer_index) {
263 JNIEnv* env = AttachCurrentThread();
264 Java_MediaCodecBridge_queueInputBuffer(
265 env, j_media_codec_.obj(),
266 input_buffer_index, 0, 0, 0, kBufferFlagEndOfStream);
269 MediaCodecStatus MediaCodecBridge::DequeueInputBuffer(
270 const base::TimeDelta& timeout, int* index) {
271 JNIEnv* env = AttachCurrentThread();
272 ScopedJavaLocalRef<jobject> result = Java_MediaCodecBridge_dequeueInputBuffer(
273 env, j_media_codec_.obj(), timeout.InMicroseconds());
274 *index = Java_DequeueInputResult_index(env, result.obj());
275 return static_cast<MediaCodecStatus>(
276 Java_DequeueInputResult_status(env, result.obj()));
279 MediaCodecStatus MediaCodecBridge::DequeueOutputBuffer(
280 const base::TimeDelta& timeout, int* index, size_t* offset, size_t* size,
281 base::TimeDelta* presentation_time, bool* end_of_stream) {
282 JNIEnv* env = AttachCurrentThread();
283 ScopedJavaLocalRef<jobject> result =
284 Java_MediaCodecBridge_dequeueOutputBuffer(env, j_media_codec_.obj(),
285 timeout.InMicroseconds());
286 *index = Java_DequeueOutputResult_index(env, result.obj());;
287 *offset = base::checked_numeric_cast<size_t>(
288 Java_DequeueOutputResult_offset(env, result.obj()));
289 *size = base::checked_numeric_cast<size_t>(
290 Java_DequeueOutputResult_numBytes(env, result.obj()));
291 *presentation_time = base::TimeDelta::FromMicroseconds(
292 Java_DequeueOutputResult_presentationTimeMicroseconds(env, result.obj()));
293 int flags = Java_DequeueOutputResult_flags(env, result.obj());
294 *end_of_stream = flags & kBufferFlagEndOfStream;
295 return static_cast<MediaCodecStatus>(
296 Java_DequeueOutputResult_status(env, result.obj()));
299 void MediaCodecBridge::ReleaseOutputBuffer(int index, bool render) {
300 JNIEnv* env = AttachCurrentThread();
301 CHECK(env);
303 Java_MediaCodecBridge_releaseOutputBuffer(
304 env, j_media_codec_.obj(), index, render);
307 bool MediaCodecBridge::GetOutputBuffers() {
308 JNIEnv* env = AttachCurrentThread();
309 return Java_MediaCodecBridge_getOutputBuffers(env, j_media_codec_.obj());
312 bool MediaCodecBridge::FillInputBuffer(int index, const uint8* data, int size) {
313 JNIEnv* env = AttachCurrentThread();
315 ScopedJavaLocalRef<jobject> j_buffer(
316 Java_MediaCodecBridge_getInputBuffer(env, j_media_codec_.obj(), index));
317 jlong capacity = env->GetDirectBufferCapacity(j_buffer.obj());
318 if (size > capacity) {
319 LOG(ERROR) << "Input buffer size " << size
320 << " exceeds MediaCodec input buffer capacity: " << capacity;
321 return false;
324 uint8* direct_buffer =
325 static_cast<uint8*>(env->GetDirectBufferAddress(j_buffer.obj()));
326 memcpy(direct_buffer, data, size);
327 return true;
330 AudioCodecBridge::AudioCodecBridge(const std::string& mime)
331 // Audio codec doesn't care about security level.
332 : MediaCodecBridge(mime, false) {
335 bool AudioCodecBridge::Start(
336 const AudioCodec& codec, int sample_rate, int channel_count,
337 const uint8* extra_data, size_t extra_data_size, bool play_audio,
338 jobject media_crypto) {
339 JNIEnv* env = AttachCurrentThread();
341 if (!media_codec())
342 return false;
344 std::string codec_string = AudioCodecToAndroidMimeType(codec);
345 if (codec_string.empty())
346 return false;
348 ScopedJavaLocalRef<jstring> j_mime =
349 ConvertUTF8ToJavaString(env, codec_string);
350 ScopedJavaLocalRef<jobject> j_format(
351 Java_MediaCodecBridge_createAudioFormat(
352 env, j_mime.obj(), sample_rate, channel_count));
353 DCHECK(!j_format.is_null());
355 if (!ConfigureMediaFormat(j_format.obj(), codec, extra_data, extra_data_size))
356 return false;
358 if (!Java_MediaCodecBridge_configureAudio(
359 env, media_codec(), j_format.obj(), media_crypto, 0, play_audio)) {
360 return false;
363 return StartInternal();
366 bool AudioCodecBridge::ConfigureMediaFormat(
367 jobject j_format, const AudioCodec& codec, const uint8* extra_data,
368 size_t extra_data_size) {
369 if (extra_data_size == 0)
370 return true;
372 JNIEnv* env = AttachCurrentThread();
373 switch (codec) {
374 case kCodecVorbis:
376 if (extra_data[0] != 2) {
377 LOG(ERROR) << "Invalid number of vorbis headers before the codec "
378 << "header: " << extra_data[0];
379 return false;
382 size_t header_length[2];
383 // |total_length| keeps track of the total number of bytes before the last
384 // header.
385 size_t total_length = 1;
386 const uint8* current_pos = extra_data;
387 // Calculate the length of the first 2 headers.
388 for (int i = 0; i < 2; ++i) {
389 header_length[i] = 0;
390 while (total_length < extra_data_size) {
391 size_t size = *(++current_pos);
392 total_length += 1 + size;
393 if (total_length > 0x80000000) {
394 LOG(ERROR) << "Vorbis header size too large";
395 return false;
397 header_length[i] += size;
398 if (size < 0xFF)
399 break;
401 if (total_length >= extra_data_size) {
402 LOG(ERROR) << "Invalid vorbis header size in the extra data";
403 return false;
406 current_pos++;
407 // The first header is identification header.
408 ScopedJavaLocalRef<jbyteArray> first_header =
409 base::android::ToJavaByteArray(env, current_pos, header_length[0]);
410 Java_MediaCodecBridge_setCodecSpecificData(
411 env, j_format, 0, first_header.obj());
412 // The last header is codec header.
413 ScopedJavaLocalRef<jbyteArray> last_header =
414 base::android::ToJavaByteArray(
415 env, extra_data + total_length, extra_data_size - total_length);
416 Java_MediaCodecBridge_setCodecSpecificData(
417 env, j_format, 1, last_header.obj());
418 break;
420 case kCodecAAC:
422 media::BitReader reader(extra_data, extra_data_size);
424 // The following code is copied from aac.cc
425 // TODO(qinmin): refactor the code in aac.cc to make it more reusable.
426 uint8 profile = 0;
427 uint8 frequency_index = 0;
428 uint8 channel_config = 0;
429 if (!reader.ReadBits(5, &profile) ||
430 !reader.ReadBits(4, &frequency_index)) {
431 LOG(ERROR) << "Unable to parse AAC header";
432 return false;
434 if (0xf == frequency_index && !reader.SkipBits(24)) {
435 LOG(ERROR) << "Unable to parse AAC header";
436 return false;
438 if (!reader.ReadBits(4, &channel_config)) {
439 LOG(ERROR) << "Unable to parse AAC header";
440 return false;
443 if (profile < 1 || profile > 4 || frequency_index == 0xf ||
444 channel_config > 7) {
445 LOG(ERROR) << "Invalid AAC header";
446 return false;
448 const size_t kCsdLength = 2;
449 uint8 csd[kCsdLength];
450 csd[0] = profile << 3 | frequency_index >> 1;
451 csd[1] = (frequency_index & 0x01) << 7 | channel_config << 3;
452 ScopedJavaLocalRef<jbyteArray> byte_array =
453 base::android::ToJavaByteArray(env, csd, kCsdLength);
454 Java_MediaCodecBridge_setCodecSpecificData(
455 env, j_format, 0, byte_array.obj());
457 // TODO(qinmin): pass an extra variable to this function to determine
458 // whether we need to call this.
459 Java_MediaCodecBridge_setFrameHasADTSHeader(env, j_format);
460 break;
462 default:
463 LOG(ERROR) << "Invalid header encountered for codec: "
464 << AudioCodecToAndroidMimeType(codec);
465 return false;
467 return true;
470 void AudioCodecBridge::PlayOutputBuffer(int index, size_t size) {
471 DCHECK_LE(0, index);
472 int numBytes = base::checked_numeric_cast<int>(size);
473 JNIEnv* env = AttachCurrentThread();
474 ScopedJavaLocalRef<jobject> buf =
475 Java_MediaCodecBridge_getOutputBuffer(env, media_codec(), index);
476 uint8* buffer = static_cast<uint8*>(env->GetDirectBufferAddress(buf.obj()));
478 ScopedJavaLocalRef<jbyteArray> byte_array =
479 base::android::ToJavaByteArray(env, buffer, numBytes);
480 Java_MediaCodecBridge_playOutputBuffer(
481 env, media_codec(), byte_array.obj());
484 void AudioCodecBridge::SetVolume(double volume) {
485 JNIEnv* env = AttachCurrentThread();
486 Java_MediaCodecBridge_setVolume(env, media_codec(), volume);
489 VideoCodecBridge::VideoCodecBridge(const std::string& mime, bool is_secure)
490 : MediaCodecBridge(mime, is_secure) {
493 bool VideoCodecBridge::Start(
494 const VideoCodec& codec, const gfx::Size& size, jobject surface,
495 jobject media_crypto) {
496 JNIEnv* env = AttachCurrentThread();
498 if (!media_codec())
499 return false;
501 std::string codec_string = VideoCodecToAndroidMimeType(codec);
502 if (codec_string.empty())
503 return false;
505 ScopedJavaLocalRef<jstring> j_mime =
506 ConvertUTF8ToJavaString(env, codec_string);
507 ScopedJavaLocalRef<jobject> j_format(
508 Java_MediaCodecBridge_createVideoFormat(
509 env, j_mime.obj(), size.width(), size.height()));
510 DCHECK(!j_format.is_null());
511 if (!Java_MediaCodecBridge_configureVideo(
512 env, media_codec(), j_format.obj(), surface, media_crypto, 0)) {
513 return false;
516 return StartInternal();
519 AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec& codec) {
520 const std::string mime = AudioCodecToAndroidMimeType(codec);
521 return mime.empty() ? NULL : new AudioCodecBridge(mime);
524 // static
525 bool AudioCodecBridge::IsKnownUnaccelerated(const AudioCodec& codec) {
526 return MediaCodecBridge::IsKnownUnaccelerated(
527 AudioCodecToAndroidMimeType(codec));
530 VideoCodecBridge* VideoCodecBridge::Create(const VideoCodec& codec,
531 bool is_secure) {
532 const std::string mime = VideoCodecToAndroidMimeType(codec);
533 return mime.empty() ? NULL : new VideoCodecBridge(mime, is_secure);
536 // static
537 bool VideoCodecBridge::IsKnownUnaccelerated(const VideoCodec& codec) {
538 return MediaCodecBridge::IsKnownUnaccelerated(
539 VideoCodecToAndroidMimeType(codec));
542 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) {
543 return RegisterNativesImpl(env);
546 } // namespace media