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