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"
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
;
31 enum { kBufferFlagEndOfStream
= 4 };
33 static const std::string
AudioCodecToAndroidMimeType(const AudioCodec
& codec
) {
38 return "audio/vorbis";
40 return "audio/mp4a-latm";
46 static const std::string
VideoCodecToAndroidMimeType(const VideoCodec
& codec
) {
51 return "video/x-vnd.on2.vp8";
57 static const std::string
CodecTypeToAndroidMimeType(const std::string
& codec
) {
58 // TODO(xhwang): Shall we handle more detailed strings like "mp4a.40.2"?
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";
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")
74 if (mime
== "video/avc")
76 if (mime
== "video/x-vnd.on2.vp8")
78 if (mime
== "video/x-vnd.on2.vp9")
80 if (mime
== "audio/mp4a-latm")
82 if (mime
== "audio/mpeg")
84 if (mime
== "audio/vorbis")
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());
97 bool MediaCodecBridge::IsAvailable() {
98 // MediaCodec is only available on JB and greater.
99 return base::android::BuildInfo::GetInstance()->sdk_int() >= 16;
103 void MediaCodecBridge::GetCodecsInfo(
104 std::vector
<CodecsInfo
>* codecs_info
) {
105 JNIEnv
* env
= AttachCurrentThread();
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());
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
);
132 bool MediaCodecBridge::CanDecode(const std::string
& codec
, bool is_secure
) {
133 JNIEnv
* env
= AttachCurrentThread();
134 std::string mime
= CodecTypeToAndroidMimeType(codec
);
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());
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);
163 MediaCodecBridge::MediaCodecBridge(const std::string
& mime
, bool is_secure
) {
164 JNIEnv
* env
= AttachCurrentThread();
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();
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()) &&
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) {
239 native_clear_array
[0] = 0;
240 native_cypher_array
[0] = data_size
;
242 DCHECK_GT(subsamples_size
, 0);
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();
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
;
324 uint8
* direct_buffer
=
325 static_cast<uint8
*>(env
->GetDirectBufferAddress(j_buffer
.obj()));
326 memcpy(direct_buffer
, data
, size
);
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();
344 std::string codec_string
= AudioCodecToAndroidMimeType(codec
);
345 if (codec_string
.empty())
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
))
358 if (!Java_MediaCodecBridge_configureAudio(
359 env
, media_codec(), j_format
.obj(), media_crypto
, 0, play_audio
)) {
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)
372 JNIEnv
* env
= AttachCurrentThread();
376 if (extra_data
[0] != 2) {
377 LOG(ERROR
) << "Invalid number of vorbis headers before the codec "
378 << "header: " << extra_data
[0];
382 size_t header_length
[2];
383 // |total_length| keeps track of the total number of bytes before the last
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";
397 header_length
[i
] += size
;
401 if (total_length
>= extra_data_size
) {
402 LOG(ERROR
) << "Invalid vorbis header size in the extra data";
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());
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.
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";
434 if (0xf == frequency_index
&& !reader
.SkipBits(24)) {
435 LOG(ERROR
) << "Unable to parse AAC header";
438 if (!reader
.ReadBits(4, &channel_config
)) {
439 LOG(ERROR
) << "Unable to parse AAC header";
443 if (profile
< 1 || profile
> 4 || frequency_index
== 0xf ||
444 channel_config
> 7) {
445 LOG(ERROR
) << "Invalid AAC header";
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
);
463 LOG(ERROR
) << "Invalid header encountered for codec: "
464 << AudioCodecToAndroidMimeType(codec
);
470 void AudioCodecBridge::PlayOutputBuffer(int index
, size_t size
) {
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();
501 std::string codec_string
= VideoCodecToAndroidMimeType(codec
);
502 if (codec_string
.empty())
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)) {
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
);
525 bool AudioCodecBridge::IsKnownUnaccelerated(const AudioCodec
& codec
) {
526 return MediaCodecBridge::IsKnownUnaccelerated(
527 AudioCodecToAndroidMimeType(codec
));
530 VideoCodecBridge
* VideoCodecBridge::Create(const VideoCodec
& codec
,
532 const std::string mime
= VideoCodecToAndroidMimeType(codec
);
533 return mime
.empty() ? NULL
: new VideoCodecBridge(mime
, is_secure
);
537 bool VideoCodecBridge::IsKnownUnaccelerated(const VideoCodec
& codec
) {
538 return MediaCodecBridge::IsKnownUnaccelerated(
539 VideoCodecToAndroidMimeType(codec
));
542 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv
* env
) {
543 return RegisterNativesImpl(env
);