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
24using base::android::AttachCurrentThread;
25using base::android::ConvertJavaStringToUTF8;
26using base::android::ConvertUTF8ToJavaString;
27using base::android::ScopedJavaLocalRef;
28
29namespace media {
30
31enum {
32  kBufferFlagSyncFrame = 1,    // BUFFER_FLAG_SYNC_FRAME
33  kBufferFlagEndOfStream = 4,  // BUFFER_FLAG_END_OF_STREAM
34  kConfigureFlagEncode = 1,    // CONFIGURE_FLAG_ENCODE
35};
36
37static 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
50static 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
63static 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.
79static 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
97static ScopedJavaLocalRef<jintArray>
98ToJavaIntArray(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
105bool MediaCodecBridge::IsAvailable() {
106  // MediaCodec is only available on JB and greater.
107  return base::android::BuildInfo::GetInstance()->sdk_int() >= 16;
108}
109
110// static
111bool MediaCodecBridge::SupportsSetParameters() {
112  // MediaCodec.setParameters() is only available starting with K.
113  return base::android::BuildInfo::GetInstance()->sdk_int() >= 19;
114}
115
116// static
117std::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
147bool 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
163bool 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
180MediaCodecBridge::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
191MediaCodecBridge::~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
198bool MediaCodecBridge::StartInternal() {
199  JNIEnv* env = AttachCurrentThread();
200  return Java_MediaCodecBridge_start(env, j_media_codec_.obj()) &&
201         GetOutputBuffers();
202}
203
204MediaCodecStatus MediaCodecBridge::Reset() {
205  JNIEnv* env = AttachCurrentThread();
206  return static_cast<MediaCodecStatus>(
207      Java_MediaCodecBridge_flush(env, j_media_codec_.obj()));
208}
209
210void MediaCodecBridge::Stop() {
211  JNIEnv* env = AttachCurrentThread();
212  Java_MediaCodecBridge_stop(env, j_media_codec_.obj());
213}
214
215void 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
222MediaCodecStatus 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
243MediaCodecStatus 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
313void 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
325MediaCodecStatus 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
339MediaCodecStatus 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
374void 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
383int MediaCodecBridge::GetInputBuffersCount() {
384  JNIEnv* env = AttachCurrentThread();
385  return Java_MediaCodecBridge_getInputBuffersCount(env, j_media_codec_.obj());
386}
387
388int MediaCodecBridge::GetOutputBuffersCount() {
389  JNIEnv* env = AttachCurrentThread();
390  return Java_MediaCodecBridge_getOutputBuffersCount(env, j_media_codec_.obj());
391}
392
393size_t MediaCodecBridge::GetOutputBuffersCapacity() {
394  JNIEnv* env = AttachCurrentThread();
395  return Java_MediaCodecBridge_getOutputBuffersCapacity(env,
396                                                        j_media_codec_.obj());
397}
398
399bool MediaCodecBridge::GetOutputBuffers() {
400  JNIEnv* env = AttachCurrentThread();
401  return Java_MediaCodecBridge_getOutputBuffers(env, j_media_codec_.obj());
402}
403
404void 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
415bool 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
432bool 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
450AudioCodecBridge::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
455bool 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
488bool 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
591void 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
604void AudioCodecBridge::SetVolume(double volume) {
605  JNIEnv* env = AttachCurrentThread();
606  Java_MediaCodecBridge_setVolume(env, media_codec(), volume);
607}
608
609AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec& codec) {
610  const std::string mime = AudioCodecToAndroidMimeType(codec);
611  return mime.empty() ? NULL : new AudioCodecBridge(mime);
612}
613
614// static
615bool AudioCodecBridge::IsKnownUnaccelerated(const AudioCodec& codec) {
616  return MediaCodecBridge::IsKnownUnaccelerated(
617      AudioCodecToAndroidMimeType(codec), MEDIA_CODEC_DECODER);
618}
619
620// static
621bool VideoCodecBridge::IsKnownUnaccelerated(const VideoCodec& codec,
622                                            MediaCodecDirection direction) {
623  return MediaCodecBridge::IsKnownUnaccelerated(
624      VideoCodecToAndroidMimeType(codec), direction);
625}
626
627VideoCodecBridge* 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
659VideoCodecBridge* 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
698VideoCodecBridge::VideoCodecBridge(const std::string& mime,
699                                   bool is_secure,
700                                   MediaCodecDirection direction)
701    : MediaCodecBridge(mime, is_secure, direction) {}
702
703void VideoCodecBridge::SetVideoBitrate(int bps) {
704  JNIEnv* env = AttachCurrentThread();
705  Java_MediaCodecBridge_setVideoBitrate(env, media_codec(), bps);
706}
707
708void VideoCodecBridge::RequestKeyFrameSoon() {
709  JNIEnv* env = AttachCurrentThread();
710  Java_MediaCodecBridge_requestKeyFrameSoon(env, media_codec());
711}
712
713bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) {
714  return RegisterNativesImpl(env);
715}
716
717}  // namespace media
718