- add sources.
[platform/framework/web/crosswalk.git] / src / media / base / android / media_codec_bridge.cc
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 { kBufferFlagEndOfStream = 4 };
32
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();
43   }
44 }
45
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();
54   }
55 }
56
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();
68 }
69
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();
87 }
88
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;
94 }
95
96 // static
97 bool MediaCodecBridge::IsAvailable() {
98   // MediaCodec is only available on JB and greater.
99   return base::android::BuildInfo::GetInstance()->sdk_int() >= 16;
100 }
101
102 // static
103 void MediaCodecBridge::GetCodecsInfo(
104     std::vector<CodecsInfo>* codecs_info) {
105   JNIEnv* env = AttachCurrentThread();
106   if (!IsAvailable())
107     return;
108
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);
128   }
129 }
130
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;
143   }
144   return false;
145 }
146
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);
158     }
159   }
160   return true;
161 }
162
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));
170 }
171
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());
177 }
178
179 bool MediaCodecBridge::StartInternal() {
180   JNIEnv* env = AttachCurrentThread();
181   return Java_MediaCodecBridge_start(env, j_media_codec_.obj()) &&
182          GetOutputBuffers();
183 }
184
185 MediaCodecStatus MediaCodecBridge::Reset() {
186   JNIEnv* env = AttachCurrentThread();
187   return static_cast<MediaCodecStatus>(
188       Java_MediaCodecBridge_flush(env, j_media_codec_.obj()));
189 }
190
191 void MediaCodecBridge::Stop() {
192   JNIEnv* env = AttachCurrentThread();
193   Java_MediaCodecBridge_stop(env, j_media_codec_.obj());
194 }
195
196 void MediaCodecBridge::GetOutputFormat(int* width, int* height) {
197   JNIEnv* env = AttachCurrentThread();
198
199   *width = Java_MediaCodecBridge_getOutputWidth(env, j_media_codec_.obj());
200   *height = Java_MediaCodecBridge_getOutputHeight(env, j_media_codec_.obj());
201 }
202
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));
212 }
213
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;
221
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);
227
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;
233
234   scoped_ptr<jint[]> native_clear_array(new jint[new_subsamples_size]);
235   scoped_ptr<jint[]> native_cypher_array(new jint[new_subsamples_size]);
236
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;
247     }
248   }
249
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);
254
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()));
260 }
261
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);
267 }
268
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()));
277 }
278
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()));
297 }
298
299 void MediaCodecBridge::ReleaseOutputBuffer(int index, bool render) {
300   JNIEnv* env = AttachCurrentThread();
301   CHECK(env);
302
303   Java_MediaCodecBridge_releaseOutputBuffer(
304       env, j_media_codec_.obj(), index, render);
305 }
306
307 bool MediaCodecBridge::GetOutputBuffers() {
308   JNIEnv* env = AttachCurrentThread();
309   return Java_MediaCodecBridge_getOutputBuffers(env, j_media_codec_.obj());
310 }
311
312 bool MediaCodecBridge::FillInputBuffer(int index, const uint8* data, int size) {
313   JNIEnv* env = AttachCurrentThread();
314
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;
322   }
323
324   uint8* direct_buffer =
325       static_cast<uint8*>(env->GetDirectBufferAddress(j_buffer.obj()));
326   memcpy(direct_buffer, data, size);
327   return true;
328 }
329
330 AudioCodecBridge::AudioCodecBridge(const std::string& mime)
331     // Audio codec doesn't care about security level.
332     : MediaCodecBridge(mime, false) {
333 }
334
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();
340
341   if (!media_codec())
342     return false;
343
344   std::string codec_string = AudioCodecToAndroidMimeType(codec);
345   if (codec_string.empty())
346     return false;
347
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());
354
355   if (!ConfigureMediaFormat(j_format.obj(), codec, extra_data, extra_data_size))
356     return false;
357
358   if (!Java_MediaCodecBridge_configureAudio(
359       env, media_codec(), j_format.obj(), media_crypto, 0, play_audio)) {
360     return false;
361   }
362
363   return StartInternal();
364 }
365
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;
371
372   JNIEnv* env = AttachCurrentThread();
373   switch (codec) {
374     case kCodecVorbis:
375     {
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;
380       }
381
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;
396           }
397           header_length[i] += size;
398           if (size < 0xFF)
399             break;
400         }
401         if (total_length >= extra_data_size) {
402           LOG(ERROR) << "Invalid vorbis header size in the extra data";
403           return false;
404         }
405       }
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;
419     }
420     case kCodecAAC:
421     {
422       media::BitReader reader(extra_data, extra_data_size);
423
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;
433       }
434       if (0xf == frequency_index && !reader.SkipBits(24)) {
435         LOG(ERROR) << "Unable to parse AAC header";
436         return false;
437       }
438       if (!reader.ReadBits(4, &channel_config)) {
439         LOG(ERROR) << "Unable to parse AAC header";
440         return false;
441       }
442
443       if (profile < 1 || profile > 4 || frequency_index == 0xf ||
444           channel_config > 7) {
445         LOG(ERROR) << "Invalid AAC header";
446         return false;
447       }
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());
456
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;
461     }
462     default:
463       LOG(ERROR) << "Invalid header encountered for codec: "
464                  << AudioCodecToAndroidMimeType(codec);
465       return false;
466   }
467   return true;
468 }
469
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()));
477
478   ScopedJavaLocalRef<jbyteArray> byte_array =
479       base::android::ToJavaByteArray(env, buffer, numBytes);
480   Java_MediaCodecBridge_playOutputBuffer(
481       env, media_codec(), byte_array.obj());
482 }
483
484 void AudioCodecBridge::SetVolume(double volume) {
485   JNIEnv* env = AttachCurrentThread();
486   Java_MediaCodecBridge_setVolume(env, media_codec(), volume);
487 }
488
489 VideoCodecBridge::VideoCodecBridge(const std::string& mime, bool is_secure)
490     : MediaCodecBridge(mime, is_secure) {
491 }
492
493 bool VideoCodecBridge::Start(
494     const VideoCodec& codec, const gfx::Size& size, jobject surface,
495     jobject media_crypto) {
496   JNIEnv* env = AttachCurrentThread();
497
498   if (!media_codec())
499     return false;
500
501   std::string codec_string = VideoCodecToAndroidMimeType(codec);
502   if (codec_string.empty())
503     return false;
504
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;
514   }
515
516   return StartInternal();
517 }
518
519 AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec& codec) {
520   const std::string mime = AudioCodecToAndroidMimeType(codec);
521   return mime.empty() ? NULL : new AudioCodecBridge(mime);
522 }
523
524 // static
525 bool AudioCodecBridge::IsKnownUnaccelerated(const AudioCodec& codec) {
526   return MediaCodecBridge::IsKnownUnaccelerated(
527       AudioCodecToAndroidMimeType(codec));
528 }
529
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);
534 }
535
536 // static
537 bool VideoCodecBridge::IsKnownUnaccelerated(const VideoCodec& codec) {
538   return MediaCodecBridge::IsKnownUnaccelerated(
539       VideoCodecToAndroidMimeType(codec));
540 }
541
542 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) {
543   return RegisterNativesImpl(env);
544 }
545
546 }  // namespace media