| Index: media/base/android/media_codec_bridge_impl.cc
 | 
| diff --git a/media/base/android/media_codec_bridge_impl.cc b/media/base/android/media_codec_bridge_impl.cc
 | 
| index 15a33a421961ca7d36121852d8a94e803390c34d..e45a134df92817171582629fe7844c27b136e5be 100644
 | 
| --- a/media/base/android/media_codec_bridge_impl.cc
 | 
| +++ b/media/base/android/media_codec_bridge_impl.cc
 | 
| @@ -14,12 +14,15 @@
 | 
|  #include "base/android/jni_array.h"
 | 
|  #include "base/android/jni_string.h"
 | 
|  #include "base/logging.h"
 | 
| +#include "base/memory/ptr_util.h"
 | 
|  #include "base/numerics/safe_conversions.h"
 | 
|  #include "base/strings/string_util.h"
 | 
|  #include "jni/MediaCodecBridge_jni.h"
 | 
|  #include "media/base/android/media_codec_util.h"
 | 
| +#include "media/base/audio_codecs.h"
 | 
|  #include "media/base/bit_reader.h"
 | 
|  #include "media/base/subsample_entry.h"
 | 
| +#include "media/base/video_codecs.h"
 | 
|  
 | 
|  using base::android::AttachCurrentThread;
 | 
|  using base::android::ConvertJavaStringToUTF8;
 | 
| @@ -44,49 +47,276 @@ enum {
 | 
|    kConfigureFlagEncode = 1,    // CONFIGURE_FLAG_ENCODE
 | 
|  };
 | 
|  
 | 
| -const std::string AudioCodecToAndroidMimeType(const AudioCodec& codec) {
 | 
| -  switch (codec) {
 | 
| -    case kCodecMP3:
 | 
| -      return "audio/mpeg";
 | 
| -    case kCodecVorbis:
 | 
| -      return "audio/vorbis";
 | 
| -    case kCodecOpus:
 | 
| -      return "audio/opus";
 | 
| -    case kCodecAAC:
 | 
| -      return "audio/mp4a-latm";
 | 
| -    case kCodecAC3:
 | 
| -      return "audio/ac3";
 | 
| -    case kCodecEAC3:
 | 
| -      return "audio/eac3";
 | 
| -    default:
 | 
| -      return std::string();
 | 
| -  }
 | 
| -}
 | 
| +// Parses |extra_data| and sets the appropriate fields of the given MediaFormat.
 | 
| +bool ConfigureMediaFormatForAudio(jobject j_format,
 | 
| +                                  AudioCodec codec,
 | 
| +                                  const uint8_t* extra_data,
 | 
| +                                  size_t extra_data_size,
 | 
| +                                  int64_t codec_delay_ns,
 | 
| +                                  int64_t seek_preroll_ns) {
 | 
| +  if (extra_data_size == 0 && codec != kCodecOpus)
 | 
| +    return true;
 | 
|  
 | 
| -const std::string VideoCodecToAndroidMimeType(const VideoCodec& codec) {
 | 
| +  JNIEnv* env = AttachCurrentThread();
 | 
|    switch (codec) {
 | 
| -    case kCodecH264:
 | 
| -      return "video/avc";
 | 
| -    case kCodecHEVC:
 | 
| -      return "video/hevc";
 | 
| -    case kCodecVP8:
 | 
| -      return "video/x-vnd.on2.vp8";
 | 
| -    case kCodecVP9:
 | 
| -      return "video/x-vnd.on2.vp9";
 | 
| +    case kCodecVorbis: {
 | 
| +      if (extra_data[0] != 2) {
 | 
| +        LOG(ERROR) << "Invalid number of vorbis headers before the codec "
 | 
| +                   << "header: " << extra_data[0];
 | 
| +        return false;
 | 
| +      }
 | 
| +
 | 
| +      size_t header_length[2];
 | 
| +      // |total_length| keeps track of the total number of bytes before the last
 | 
| +      // header.
 | 
| +      size_t total_length = 1;
 | 
| +      const uint8_t* current_pos = extra_data;
 | 
| +      // Calculate the length of the first 2 headers.
 | 
| +      for (int i = 0; i < 2; ++i) {
 | 
| +        header_length[i] = 0;
 | 
| +        while (total_length < extra_data_size) {
 | 
| +          size_t size = *(++current_pos);
 | 
| +          total_length += 1 + size;
 | 
| +          if (total_length > 0x80000000) {
 | 
| +            LOG(ERROR) << "Vorbis header size too large";
 | 
| +            return false;
 | 
| +          }
 | 
| +          header_length[i] += size;
 | 
| +          if (size < 0xFF)
 | 
| +            break;
 | 
| +        }
 | 
| +        if (total_length >= extra_data_size) {
 | 
| +          LOG(ERROR) << "Invalid vorbis header size in the extra data";
 | 
| +          return false;
 | 
| +        }
 | 
| +      }
 | 
| +      current_pos++;
 | 
| +      // The first header is identification header.
 | 
| +      ScopedJavaLocalRef<jbyteArray> first_header =
 | 
| +          base::android::ToJavaByteArray(env, current_pos, header_length[0]);
 | 
| +      Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 0,
 | 
| +                                                 first_header);
 | 
| +      // The last header is codec header.
 | 
| +      ScopedJavaLocalRef<jbyteArray> last_header =
 | 
| +          base::android::ToJavaByteArray(env, extra_data + total_length,
 | 
| +                                         extra_data_size - total_length);
 | 
| +      Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 1, last_header);
 | 
| +      break;
 | 
| +    }
 | 
| +    case kCodecAAC: {
 | 
| +      media::BitReader reader(extra_data, extra_data_size);
 | 
| +
 | 
| +      // The following code is copied from aac.cc
 | 
| +      // TODO(qinmin): refactor the code in aac.cc to make it more reusable.
 | 
| +      uint8_t profile = 0;
 | 
| +      uint8_t frequency_index = 0;
 | 
| +      uint8_t channel_config = 0;
 | 
| +      RETURN_ON_ERROR(reader.ReadBits(5, &profile));
 | 
| +      RETURN_ON_ERROR(reader.ReadBits(4, &frequency_index));
 | 
| +
 | 
| +      if (0xf == frequency_index)
 | 
| +        RETURN_ON_ERROR(reader.SkipBits(24));
 | 
| +      RETURN_ON_ERROR(reader.ReadBits(4, &channel_config));
 | 
| +
 | 
| +      if (profile == 5 || profile == 29) {
 | 
| +        // Read extension config.
 | 
| +        RETURN_ON_ERROR(reader.ReadBits(4, &frequency_index));
 | 
| +        if (frequency_index == 0xf)
 | 
| +          RETURN_ON_ERROR(reader.SkipBits(24));
 | 
| +        RETURN_ON_ERROR(reader.ReadBits(5, &profile));
 | 
| +      }
 | 
| +
 | 
| +      if (profile < 1 || profile > 4 || frequency_index == 0xf ||
 | 
| +          channel_config > 7) {
 | 
| +        LOG(ERROR) << "Invalid AAC header";
 | 
| +        return false;
 | 
| +      }
 | 
| +
 | 
| +      const size_t kCsdLength = 2;
 | 
| +      uint8_t csd[kCsdLength];
 | 
| +      csd[0] = profile << 3 | frequency_index >> 1;
 | 
| +      csd[1] = (frequency_index & 0x01) << 7 | channel_config << 3;
 | 
| +      ScopedJavaLocalRef<jbyteArray> byte_array =
 | 
| +          base::android::ToJavaByteArray(env, csd, kCsdLength);
 | 
| +      Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 0, byte_array);
 | 
| +
 | 
| +      // TODO(qinmin): pass an extra variable to this function to determine
 | 
| +      // whether we need to call this.
 | 
| +      Java_MediaCodecBridge_setFrameHasADTSHeader(env, j_format);
 | 
| +      break;
 | 
| +    }
 | 
| +    case kCodecOpus: {
 | 
| +      if (!extra_data || extra_data_size == 0 || codec_delay_ns < 0 ||
 | 
| +          seek_preroll_ns < 0) {
 | 
| +        LOG(ERROR) << "Invalid Opus Header";
 | 
| +        return false;
 | 
| +      }
 | 
| +
 | 
| +      // csd0 - Opus Header
 | 
| +      ScopedJavaLocalRef<jbyteArray> csd0 =
 | 
| +          base::android::ToJavaByteArray(env, extra_data, extra_data_size);
 | 
| +      Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 0, csd0);
 | 
| +
 | 
| +      // csd1 - Codec Delay
 | 
| +      ScopedJavaLocalRef<jbyteArray> csd1 = base::android::ToJavaByteArray(
 | 
| +          env, reinterpret_cast<const uint8_t*>(&codec_delay_ns),
 | 
| +          sizeof(int64_t));
 | 
| +      Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 1, csd1);
 | 
| +
 | 
| +      // csd2 - Seek Preroll
 | 
| +      ScopedJavaLocalRef<jbyteArray> csd2 = base::android::ToJavaByteArray(
 | 
| +          env, reinterpret_cast<const uint8_t*>(&seek_preroll_ns),
 | 
| +          sizeof(int64_t));
 | 
| +      Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 2, csd2);
 | 
| +      break;
 | 
| +    }
 | 
|      default:
 | 
| -      return std::string();
 | 
| +      LOG(ERROR) << "Invalid header encountered for codec: "
 | 
| +                 << GetCodecName(codec);
 | 
| +      return false;
 | 
|    }
 | 
| -}
 | 
| -
 | 
| -static ScopedJavaLocalRef<jintArray>
 | 
| -ToJavaIntArray(JNIEnv* env, std::unique_ptr<jint[]> native_array, int size) {
 | 
| -  ScopedJavaLocalRef<jintArray> j_array(env, env->NewIntArray(size));
 | 
| -  env->SetIntArrayRegion(j_array.obj(), 0, size, native_array.get());
 | 
| -  return j_array;
 | 
| +  return true;
 | 
|  }
 | 
|  
 | 
|  }  // namespace
 | 
|  
 | 
| +// static
 | 
| +std::unique_ptr<MediaCodecBridge> MediaCodecBridgeImpl::CreateAudioDecoder(
 | 
| +    const AudioDecoderConfig& config,
 | 
| +    jobject media_crypto) {
 | 
| +  DVLOG(2) << __func__ << ": " << config.AsHumanReadableString()
 | 
| +           << " media_crypto:" << media_crypto;
 | 
| +
 | 
| +  if (!MediaCodecUtil::IsMediaCodecAvailable())
 | 
| +    return nullptr;
 | 
| +
 | 
| +  const std::string mime =
 | 
| +      MediaCodecUtil::CodecToAndroidMimeType(config.codec());
 | 
| +  if (mime.empty())
 | 
| +    return nullptr;
 | 
| +
 | 
| +  auto bridge = base::WrapUnique(new MediaCodecBridgeImpl(
 | 
| +      mime, false, MediaCodecDirection::DECODER, false));
 | 
| +  if (bridge->j_bridge_.is_null())
 | 
| +    return nullptr;
 | 
| +
 | 
| +  JNIEnv* env = AttachCurrentThread();
 | 
| +  ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime);
 | 
| +
 | 
| +  const int channel_count =
 | 
| +      ChannelLayoutToChannelCount(config.channel_layout());
 | 
| +  ScopedJavaLocalRef<jobject> j_format(Java_MediaCodecBridge_createAudioFormat(
 | 
| +      env, j_mime, config.samples_per_second(), channel_count));
 | 
| +  DCHECK(!j_format.is_null());
 | 
| +
 | 
| +  // It's important that the multiplication is first in this calculation to
 | 
| +  // reduce the precision loss due to integer truncation.
 | 
| +  const int64_t codec_delay_ns = base::Time::kNanosecondsPerSecond *
 | 
| +                                 config.codec_delay() /
 | 
| +                                 config.samples_per_second();
 | 
| +  const int64_t seek_preroll_ns = config.seek_preroll().InMicroseconds() *
 | 
| +                                  base::Time::kNanosecondsPerMicrosecond;
 | 
| +  if (!ConfigureMediaFormatForAudio(
 | 
| +          j_format.obj(), config.codec(), config.extra_data().data(),
 | 
| +          config.extra_data().size(), codec_delay_ns, seek_preroll_ns)) {
 | 
| +    return nullptr;
 | 
| +  }
 | 
| +
 | 
| +  if (!Java_MediaCodecBridge_configureAudio(env, bridge->j_bridge_, j_format,
 | 
| +                                            media_crypto, 0)) {
 | 
| +    return nullptr;
 | 
| +  }
 | 
| +
 | 
| +  return bridge->Start() ? std::move(bridge) : nullptr;
 | 
| +}
 | 
| +
 | 
| +// static
 | 
| +std::unique_ptr<MediaCodecBridge> MediaCodecBridgeImpl::CreateVideoDecoder(
 | 
| +    VideoCodec codec,
 | 
| +    bool is_secure,
 | 
| +    const gfx::Size& size,
 | 
| +    jobject surface,
 | 
| +    jobject media_crypto,
 | 
| +    const std::vector<uint8_t>& csd0,
 | 
| +    const std::vector<uint8_t>& csd1,
 | 
| +    bool allow_adaptive_playback,
 | 
| +    bool require_software_codec) {
 | 
| +  if (!MediaCodecUtil::IsMediaCodecAvailable())
 | 
| +    return nullptr;
 | 
| +
 | 
| +  const std::string mime = MediaCodecUtil::CodecToAndroidMimeType(codec);
 | 
| +  if (mime.empty())
 | 
| +    return nullptr;
 | 
| +
 | 
| +  std::unique_ptr<MediaCodecBridgeImpl> bridge(new MediaCodecBridgeImpl(
 | 
| +      mime, is_secure, MediaCodecDirection::DECODER, require_software_codec));
 | 
| +  if (bridge->j_bridge_.is_null())
 | 
| +    return nullptr;
 | 
| +
 | 
| +  JNIEnv* env = AttachCurrentThread();
 | 
| +  ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime);
 | 
| +  ScopedJavaLocalRef<jobject> j_format(
 | 
| +      Java_MediaCodecBridge_createVideoDecoderFormat(env, j_mime, size.width(),
 | 
| +                                                     size.height()));
 | 
| +  DCHECK(!j_format.is_null());
 | 
| +
 | 
| +  if (!csd0.empty()) {
 | 
| +    ScopedJavaLocalRef<jbyteArray> j_csd0 =
 | 
| +        base::android::ToJavaByteArray(env, csd0.data(), csd0.size());
 | 
| +    Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 0, j_csd0);
 | 
| +  }
 | 
| +
 | 
| +  if (!csd1.empty()) {
 | 
| +    ScopedJavaLocalRef<jbyteArray> j_csd1 =
 | 
| +        base::android::ToJavaByteArray(env, csd1.data(), csd1.size());
 | 
| +    Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 1, j_csd1);
 | 
| +  }
 | 
| +
 | 
| +  if (!Java_MediaCodecBridge_configureVideo(env, bridge->j_bridge_, j_format,
 | 
| +                                            surface, media_crypto, 0,
 | 
| +                                            allow_adaptive_playback)) {
 | 
| +    return nullptr;
 | 
| +  }
 | 
| +
 | 
| +  return bridge->Start() ? std::move(bridge) : nullptr;
 | 
| +}
 | 
| +
 | 
| +// static
 | 
| +std::unique_ptr<MediaCodecBridge> MediaCodecBridgeImpl::CreateVideoEncoder(
 | 
| +    VideoCodec codec,
 | 
| +    const gfx::Size& size,
 | 
| +    int bit_rate,
 | 
| +    int frame_rate,
 | 
| +    int i_frame_interval,
 | 
| +    int color_format) {
 | 
| +  if (!MediaCodecUtil::IsMediaCodecAvailable())
 | 
| +    return nullptr;
 | 
| +
 | 
| +  const std::string mime = MediaCodecUtil::CodecToAndroidMimeType(codec);
 | 
| +  if (mime.empty())
 | 
| +    return nullptr;
 | 
| +
 | 
| +  std::unique_ptr<MediaCodecBridgeImpl> bridge(new MediaCodecBridgeImpl(
 | 
| +      mime, false, MediaCodecDirection::ENCODER, false));
 | 
| +  if (bridge->j_bridge_.is_null())
 | 
| +    return nullptr;
 | 
| +
 | 
| +  JNIEnv* env = AttachCurrentThread();
 | 
| +  ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime);
 | 
| +  ScopedJavaLocalRef<jobject> j_format(
 | 
| +      Java_MediaCodecBridge_createVideoEncoderFormat(
 | 
| +          env, bridge->j_bridge_, j_mime, size.width(), size.height(), bit_rate,
 | 
| +          frame_rate, i_frame_interval, color_format));
 | 
| +  DCHECK(!j_format.is_null());
 | 
| +  if (!Java_MediaCodecBridge_configureVideo(env, bridge->j_bridge_, j_format,
 | 
| +                                            nullptr, nullptr,
 | 
| +                                            kConfigureFlagEncode, true)) {
 | 
| +    return nullptr;
 | 
| +  }
 | 
| +
 | 
| +  return bridge->Start() ? std::move(bridge) : nullptr;
 | 
| +}
 | 
| +
 | 
|  MediaCodecBridgeImpl::MediaCodecBridgeImpl(const std::string& mime,
 | 
|                                             bool is_secure,
 | 
|                                             MediaCodecDirection direction,
 | 
| @@ -94,36 +324,37 @@ MediaCodecBridgeImpl::MediaCodecBridgeImpl(const std::string& mime,
 | 
|    JNIEnv* env = AttachCurrentThread();
 | 
|    DCHECK(!mime.empty());
 | 
|    ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime);
 | 
| -  j_media_codec_.Reset(Java_MediaCodecBridge_create(
 | 
| -      env, j_mime, is_secure, direction, require_software_codec));
 | 
| +  j_bridge_.Reset(Java_MediaCodecBridge_create(env, j_mime, is_secure,
 | 
| +                                               static_cast<int>(direction),
 | 
| +                                               require_software_codec));
 | 
|  }
 | 
|  
 | 
|  MediaCodecBridgeImpl::~MediaCodecBridgeImpl() {
 | 
|    JNIEnv* env = AttachCurrentThread();
 | 
| -  if (j_media_codec_.obj())
 | 
| -    Java_MediaCodecBridge_release(env, j_media_codec_);
 | 
| +  if (j_bridge_.obj())
 | 
| +    Java_MediaCodecBridge_release(env, j_bridge_);
 | 
|  }
 | 
|  
 | 
|  bool MediaCodecBridgeImpl::Start() {
 | 
|    JNIEnv* env = AttachCurrentThread();
 | 
| -  return Java_MediaCodecBridge_start(env, j_media_codec_);
 | 
| +  return Java_MediaCodecBridge_start(env, j_bridge_);
 | 
|  }
 | 
|  
 | 
|  void MediaCodecBridgeImpl::Stop() {
 | 
|    JNIEnv* env = AttachCurrentThread();
 | 
| -  Java_MediaCodecBridge_stop(env, j_media_codec_);
 | 
| +  Java_MediaCodecBridge_stop(env, j_bridge_);
 | 
|  }
 | 
|  
 | 
|  MediaCodecStatus MediaCodecBridgeImpl::Flush() {
 | 
|    JNIEnv* env = AttachCurrentThread();
 | 
|    return static_cast<MediaCodecStatus>(
 | 
| -      Java_MediaCodecBridge_flush(env, j_media_codec_));
 | 
| +      Java_MediaCodecBridge_flush(env, j_bridge_));
 | 
|  }
 | 
|  
 | 
|  MediaCodecStatus MediaCodecBridgeImpl::GetOutputSize(gfx::Size* size) {
 | 
|    JNIEnv* env = AttachCurrentThread();
 | 
|    ScopedJavaLocalRef<jobject> result =
 | 
| -      Java_MediaCodecBridge_getOutputFormat(env, j_media_codec_);
 | 
| +      Java_MediaCodecBridge_getOutputFormat(env, j_bridge_);
 | 
|    MediaCodecStatus status = static_cast<MediaCodecStatus>(
 | 
|        Java_GetOutputFormatResult_status(env, result));
 | 
|    if (status == MEDIA_CODEC_OK) {
 | 
| @@ -137,7 +368,7 @@ MediaCodecStatus MediaCodecBridgeImpl::GetOutputSamplingRate(
 | 
|      int* sampling_rate) {
 | 
|    JNIEnv* env = AttachCurrentThread();
 | 
|    ScopedJavaLocalRef<jobject> result =
 | 
| -      Java_MediaCodecBridge_getOutputFormat(env, j_media_codec_);
 | 
| +      Java_MediaCodecBridge_getOutputFormat(env, j_bridge_);
 | 
|    MediaCodecStatus status = static_cast<MediaCodecStatus>(
 | 
|        Java_GetOutputFormatResult_status(env, result));
 | 
|    if (status == MEDIA_CODEC_OK)
 | 
| @@ -149,7 +380,7 @@ MediaCodecStatus MediaCodecBridgeImpl::GetOutputChannelCount(
 | 
|      int* channel_count) {
 | 
|    JNIEnv* env = AttachCurrentThread();
 | 
|    ScopedJavaLocalRef<jobject> result =
 | 
| -      Java_MediaCodecBridge_getOutputFormat(env, j_media_codec_);
 | 
| +      Java_MediaCodecBridge_getOutputFormat(env, j_bridge_);
 | 
|    MediaCodecStatus status = static_cast<MediaCodecStatus>(
 | 
|        Java_GetOutputFormatResult_status(env, result));
 | 
|    if (status == MEDIA_CODEC_OK)
 | 
| @@ -171,8 +402,8 @@ MediaCodecStatus MediaCodecBridgeImpl::QueueInputBuffer(
 | 
|      return MEDIA_CODEC_ERROR;
 | 
|    JNIEnv* env = AttachCurrentThread();
 | 
|    return static_cast<MediaCodecStatus>(Java_MediaCodecBridge_queueInputBuffer(
 | 
| -      env, j_media_codec_, index, 0, data_size,
 | 
| -      presentation_time.InMicroseconds(), 0));
 | 
| +      env, j_bridge_, index, 0, data_size, presentation_time.InMicroseconds(),
 | 
| +      0));
 | 
|  }
 | 
|  
 | 
|  MediaCodecStatus MediaCodecBridgeImpl::QueueSecureInputBuffer(
 | 
| @@ -223,14 +454,14 @@ MediaCodecStatus MediaCodecBridgeImpl::QueueSecureInputBuffer(
 | 
|      }
 | 
|    }
 | 
|  
 | 
| -  ScopedJavaLocalRef<jintArray> clear_array =
 | 
| -      ToJavaIntArray(env, std::move(native_clear_array), num_subsamples);
 | 
| -  ScopedJavaLocalRef<jintArray> cypher_array =
 | 
| -      ToJavaIntArray(env, std::move(native_cypher_array), num_subsamples);
 | 
| +  ScopedJavaLocalRef<jintArray> clear_array = base::android::ToJavaIntArray(
 | 
| +      env, native_clear_array.get(), num_subsamples);
 | 
| +  ScopedJavaLocalRef<jintArray> cypher_array = base::android::ToJavaIntArray(
 | 
| +      env, native_cypher_array.get(), num_subsamples);
 | 
|  
 | 
|    return static_cast<MediaCodecStatus>(
 | 
|        Java_MediaCodecBridge_queueSecureInputBuffer(
 | 
| -          env, j_media_codec_.obj(), index, 0, j_iv.obj(), j_key_id.obj(),
 | 
| +          env, j_bridge_.obj(), index, 0, j_iv.obj(), j_key_id.obj(),
 | 
|            clear_array, cypher_array, num_subsamples,
 | 
|            static_cast<int>(encryption_scheme.mode()),
 | 
|            static_cast<int>(encryption_scheme.pattern().encrypt_blocks()),
 | 
| @@ -241,8 +472,8 @@ MediaCodecStatus MediaCodecBridgeImpl::QueueSecureInputBuffer(
 | 
|  void MediaCodecBridgeImpl::QueueEOS(int input_buffer_index) {
 | 
|    DVLOG(3) << __func__ << ": " << input_buffer_index;
 | 
|    JNIEnv* env = AttachCurrentThread();
 | 
| -  Java_MediaCodecBridge_queueInputBuffer(
 | 
| -      env, j_media_codec_, input_buffer_index, 0, 0, 0, kBufferFlagEndOfStream);
 | 
| +  Java_MediaCodecBridge_queueInputBuffer(env, j_bridge_, input_buffer_index, 0,
 | 
| +                                         0, 0, kBufferFlagEndOfStream);
 | 
|  }
 | 
|  
 | 
|  MediaCodecStatus MediaCodecBridgeImpl::DequeueInputBuffer(
 | 
| @@ -250,7 +481,7 @@ MediaCodecStatus MediaCodecBridgeImpl::DequeueInputBuffer(
 | 
|      int* index) {
 | 
|    JNIEnv* env = AttachCurrentThread();
 | 
|    ScopedJavaLocalRef<jobject> result = Java_MediaCodecBridge_dequeueInputBuffer(
 | 
| -      env, j_media_codec_, timeout.InMicroseconds());
 | 
| +      env, j_bridge_, timeout.InMicroseconds());
 | 
|    *index = Java_DequeueInputResult_index(env, result);
 | 
|    MediaCodecStatus status = static_cast<MediaCodecStatus>(
 | 
|        Java_DequeueInputResult_status(env, result));
 | 
| @@ -268,7 +499,7 @@ MediaCodecStatus MediaCodecBridgeImpl::DequeueOutputBuffer(
 | 
|      bool* key_frame) {
 | 
|    JNIEnv* env = AttachCurrentThread();
 | 
|    ScopedJavaLocalRef<jobject> result =
 | 
| -      Java_MediaCodecBridge_dequeueOutputBuffer(env, j_media_codec_,
 | 
| +      Java_MediaCodecBridge_dequeueOutputBuffer(env, j_bridge_,
 | 
|                                                  timeout.InMicroseconds());
 | 
|    *index = Java_DequeueOutputResult_index(env, result);
 | 
|    *offset =
 | 
| @@ -295,15 +526,15 @@ MediaCodecStatus MediaCodecBridgeImpl::DequeueOutputBuffer(
 | 
|  void MediaCodecBridgeImpl::ReleaseOutputBuffer(int index, bool render) {
 | 
|    DVLOG(3) << __func__ << ": " << index;
 | 
|    JNIEnv* env = AttachCurrentThread();
 | 
| -  Java_MediaCodecBridge_releaseOutputBuffer(env, j_media_codec_, index, render);
 | 
| +  Java_MediaCodecBridge_releaseOutputBuffer(env, j_bridge_, index, render);
 | 
|  }
 | 
|  
 | 
|  MediaCodecStatus MediaCodecBridgeImpl::GetInputBuffer(int input_buffer_index,
 | 
|                                                        uint8_t** data,
 | 
|                                                        size_t* capacity) {
 | 
|    JNIEnv* env = AttachCurrentThread();
 | 
| -  ScopedJavaLocalRef<jobject> j_buffer(Java_MediaCodecBridge_getInputBuffer(
 | 
| -      env, j_media_codec_, input_buffer_index));
 | 
| +  ScopedJavaLocalRef<jobject> j_buffer(
 | 
| +      Java_MediaCodecBridge_getInputBuffer(env, j_bridge_, input_buffer_index));
 | 
|    if (j_buffer.is_null())
 | 
|      return MEDIA_CODEC_ERROR;
 | 
|  
 | 
| @@ -335,7 +566,7 @@ MediaCodecStatus MediaCodecBridgeImpl::GetOutputBufferAddress(
 | 
|      size_t* capacity) {
 | 
|    JNIEnv* env = AttachCurrentThread();
 | 
|    ScopedJavaLocalRef<jobject> j_buffer(
 | 
| -      Java_MediaCodecBridge_getOutputBuffer(env, j_media_codec_, index));
 | 
| +      Java_MediaCodecBridge_getOutputBuffer(env, j_bridge_, index));
 | 
|    if (j_buffer.is_null())
 | 
|      return MEDIA_CODEC_ERROR;
 | 
|    const size_t total_capacity = env->GetDirectBufferCapacity(j_buffer.obj());
 | 
| @@ -352,10 +583,31 @@ std::string MediaCodecBridgeImpl::GetName() {
 | 
|      return "";
 | 
|    JNIEnv* env = AttachCurrentThread();
 | 
|    ScopedJavaLocalRef<jstring> j_name =
 | 
| -      Java_MediaCodecBridge_getName(env, j_media_codec_);
 | 
| +      Java_MediaCodecBridge_getName(env, j_bridge_);
 | 
|    return ConvertJavaStringToUTF8(env, j_name);
 | 
|  }
 | 
|  
 | 
| +bool MediaCodecBridgeImpl::SetSurface(jobject surface) {
 | 
| +  DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 23);
 | 
| +  JNIEnv* env = AttachCurrentThread();
 | 
| +  return Java_MediaCodecBridge_setSurface(env, j_bridge_, surface);
 | 
| +}
 | 
| +
 | 
| +void MediaCodecBridgeImpl::SetVideoBitrate(int bps, int frame_rate) {
 | 
| +  JNIEnv* env = AttachCurrentThread();
 | 
| +  Java_MediaCodecBridge_setVideoBitrate(env, j_bridge_, bps, frame_rate);
 | 
| +}
 | 
| +
 | 
| +void MediaCodecBridgeImpl::RequestKeyFrameSoon() {
 | 
| +  JNIEnv* env = AttachCurrentThread();
 | 
| +  Java_MediaCodecBridge_requestKeyFrameSoon(env, j_bridge_);
 | 
| +}
 | 
| +
 | 
| +bool MediaCodecBridgeImpl::IsAdaptivePlaybackSupported() {
 | 
| +  JNIEnv* env = AttachCurrentThread();
 | 
| +  return Java_MediaCodecBridge_isAdaptivePlaybackSupported(env, j_bridge_);
 | 
| +}
 | 
| +
 | 
|  bool MediaCodecBridgeImpl::FillInputBuffer(int index,
 | 
|                                             const uint8_t* data,
 | 
|                                             size_t size) {
 | 
| @@ -377,346 +629,4 @@ bool MediaCodecBridgeImpl::FillInputBuffer(int index,
 | 
|    return true;
 | 
|  }
 | 
|  
 | 
| -// static
 | 
| -AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec& codec) {
 | 
| -  if (!MediaCodecUtil::IsMediaCodecAvailable())
 | 
| -    return nullptr;
 | 
| -
 | 
| -  const std::string mime = AudioCodecToAndroidMimeType(codec);
 | 
| -  if (mime.empty())
 | 
| -    return nullptr;
 | 
| -
 | 
| -  std::unique_ptr<AudioCodecBridge> bridge(new AudioCodecBridge(mime));
 | 
| -  if (!bridge->media_codec())
 | 
| -    return nullptr;
 | 
| -
 | 
| -  return bridge.release();
 | 
| -}
 | 
| -
 | 
| -// static
 | 
| -bool AudioCodecBridge::IsKnownUnaccelerated(const AudioCodec& codec) {
 | 
| -  return MediaCodecUtil::IsKnownUnaccelerated(
 | 
| -      AudioCodecToAndroidMimeType(codec), MEDIA_CODEC_DECODER);
 | 
| -}
 | 
| -
 | 
| -AudioCodecBridge::AudioCodecBridge(const std::string& mime)
 | 
| -    // Audio codec doesn't care about security level and there is no need for
 | 
| -    // audio encoding yet.
 | 
| -    : MediaCodecBridgeImpl(mime, false, MEDIA_CODEC_DECODER, false) {}
 | 
| -
 | 
| -bool AudioCodecBridge::ConfigureAndStart(const AudioDecoderConfig& config,
 | 
| -                                         jobject media_crypto) {
 | 
| -  const int channel_count =
 | 
| -      ChannelLayoutToChannelCount(config.channel_layout());
 | 
| -  const int64_t codec_delay_ns = base::Time::kNanosecondsPerSecond *
 | 
| -                                 config.codec_delay() /
 | 
| -                                 config.samples_per_second();
 | 
| -  const int64_t seek_preroll_ns =
 | 
| -      1000LL * config.seek_preroll().InMicroseconds();
 | 
| -
 | 
| -  return ConfigureAndStart(config.codec(), config.samples_per_second(),
 | 
| -                           channel_count, config.extra_data().data(),
 | 
| -                           config.extra_data().size(), codec_delay_ns,
 | 
| -                           seek_preroll_ns, media_crypto);
 | 
| -}
 | 
| -
 | 
| -bool AudioCodecBridge::ConfigureAndStart(const AudioCodec& codec,
 | 
| -                                         int sample_rate,
 | 
| -                                         int channel_count,
 | 
| -                                         const uint8_t* extra_data,
 | 
| -                                         size_t extra_data_size,
 | 
| -                                         int64_t codec_delay_ns,
 | 
| -                                         int64_t seek_preroll_ns,
 | 
| -                                         jobject media_crypto) {
 | 
| -  DVLOG(2) << __func__ << ": "
 | 
| -           << " codec:" << GetCodecName(codec)
 | 
| -           << " samples_per_second:" << sample_rate
 | 
| -           << " channel_count:" << channel_count
 | 
| -           << " codec_delay_ns:" << codec_delay_ns
 | 
| -           << " seek_preroll_ns:" << seek_preroll_ns
 | 
| -           << " extra data size:" << extra_data_size
 | 
| -           << " media_crypto:" << media_crypto;
 | 
| -  DCHECK(media_codec());
 | 
| -
 | 
| -  std::string codec_string = AudioCodecToAndroidMimeType(codec);
 | 
| -  if (codec_string.empty())
 | 
| -    return false;
 | 
| -
 | 
| -  JNIEnv* env = AttachCurrentThread();
 | 
| -
 | 
| -  ScopedJavaLocalRef<jstring> j_mime =
 | 
| -      ConvertUTF8ToJavaString(env, codec_string);
 | 
| -  ScopedJavaLocalRef<jobject> j_format(Java_MediaCodecBridge_createAudioFormat(
 | 
| -      env, j_mime, sample_rate, channel_count));
 | 
| -  DCHECK(!j_format.is_null());
 | 
| -
 | 
| -  if (!ConfigureMediaFormat(j_format.obj(), codec, extra_data, extra_data_size,
 | 
| -                            codec_delay_ns, seek_preroll_ns)) {
 | 
| -    return false;
 | 
| -  }
 | 
| -
 | 
| -  if (!Java_MediaCodecBridge_configureAudio(env, media_codec(), j_format,
 | 
| -                                            media_crypto, 0)) {
 | 
| -    return false;
 | 
| -  }
 | 
| -
 | 
| -  return Start();
 | 
| -}
 | 
| -
 | 
| -bool AudioCodecBridge::ConfigureMediaFormat(jobject j_format,
 | 
| -                                            const AudioCodec& codec,
 | 
| -                                            const uint8_t* extra_data,
 | 
| -                                            size_t extra_data_size,
 | 
| -                                            int64_t codec_delay_ns,
 | 
| -                                            int64_t seek_preroll_ns) {
 | 
| -  if (extra_data_size == 0 && codec != kCodecOpus)
 | 
| -    return true;
 | 
| -
 | 
| -  JNIEnv* env = AttachCurrentThread();
 | 
| -  switch (codec) {
 | 
| -    case kCodecVorbis: {
 | 
| -      if (extra_data[0] != 2) {
 | 
| -        LOG(ERROR) << "Invalid number of vorbis headers before the codec "
 | 
| -                   << "header: " << extra_data[0];
 | 
| -        return false;
 | 
| -      }
 | 
| -
 | 
| -      size_t header_length[2];
 | 
| -      // |total_length| keeps track of the total number of bytes before the last
 | 
| -      // header.
 | 
| -      size_t total_length = 1;
 | 
| -      const uint8_t* current_pos = extra_data;
 | 
| -      // Calculate the length of the first 2 headers.
 | 
| -      for (int i = 0; i < 2; ++i) {
 | 
| -        header_length[i] = 0;
 | 
| -        while (total_length < extra_data_size) {
 | 
| -          size_t size = *(++current_pos);
 | 
| -          total_length += 1 + size;
 | 
| -          if (total_length > 0x80000000) {
 | 
| -            LOG(ERROR) << "Vorbis header size too large";
 | 
| -            return false;
 | 
| -          }
 | 
| -          header_length[i] += size;
 | 
| -          if (size < 0xFF)
 | 
| -            break;
 | 
| -        }
 | 
| -        if (total_length >= extra_data_size) {
 | 
| -          LOG(ERROR) << "Invalid vorbis header size in the extra data";
 | 
| -          return false;
 | 
| -        }
 | 
| -      }
 | 
| -      current_pos++;
 | 
| -      // The first header is identification header.
 | 
| -      ScopedJavaLocalRef<jbyteArray> first_header =
 | 
| -          base::android::ToJavaByteArray(env, current_pos, header_length[0]);
 | 
| -      Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 0,
 | 
| -                                                 first_header);
 | 
| -      // The last header is codec header.
 | 
| -      ScopedJavaLocalRef<jbyteArray> last_header =
 | 
| -          base::android::ToJavaByteArray(env, extra_data + total_length,
 | 
| -                                         extra_data_size - total_length);
 | 
| -      Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 1, last_header);
 | 
| -      break;
 | 
| -    }
 | 
| -    case kCodecAAC: {
 | 
| -      media::BitReader reader(extra_data, extra_data_size);
 | 
| -
 | 
| -      // The following code is copied from aac.cc
 | 
| -      // TODO(qinmin): refactor the code in aac.cc to make it more reusable.
 | 
| -      uint8_t profile = 0;
 | 
| -      uint8_t frequency_index = 0;
 | 
| -      uint8_t channel_config = 0;
 | 
| -      RETURN_ON_ERROR(reader.ReadBits(5, &profile));
 | 
| -      RETURN_ON_ERROR(reader.ReadBits(4, &frequency_index));
 | 
| -
 | 
| -      if (0xf == frequency_index)
 | 
| -        RETURN_ON_ERROR(reader.SkipBits(24));
 | 
| -      RETURN_ON_ERROR(reader.ReadBits(4, &channel_config));
 | 
| -
 | 
| -      if (profile == 5 || profile == 29) {
 | 
| -        // Read extension config.
 | 
| -        RETURN_ON_ERROR(reader.ReadBits(4, &frequency_index));
 | 
| -        if (frequency_index == 0xf)
 | 
| -          RETURN_ON_ERROR(reader.SkipBits(24));
 | 
| -        RETURN_ON_ERROR(reader.ReadBits(5, &profile));
 | 
| -      }
 | 
| -
 | 
| -      if (profile < 1 || profile > 4 || frequency_index == 0xf ||
 | 
| -          channel_config > 7) {
 | 
| -        LOG(ERROR) << "Invalid AAC header";
 | 
| -        return false;
 | 
| -      }
 | 
| -
 | 
| -      const size_t kCsdLength = 2;
 | 
| -      uint8_t csd[kCsdLength];
 | 
| -      csd[0] = profile << 3 | frequency_index >> 1;
 | 
| -      csd[1] = (frequency_index & 0x01) << 7 | channel_config << 3;
 | 
| -      ScopedJavaLocalRef<jbyteArray> byte_array =
 | 
| -          base::android::ToJavaByteArray(env, csd, kCsdLength);
 | 
| -      Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 0, byte_array);
 | 
| -
 | 
| -      // TODO(qinmin): pass an extra variable to this function to determine
 | 
| -      // whether we need to call this.
 | 
| -      Java_MediaCodecBridge_setFrameHasADTSHeader(env, j_format);
 | 
| -      break;
 | 
| -    }
 | 
| -    case kCodecOpus: {
 | 
| -      if (!extra_data || extra_data_size == 0 || codec_delay_ns < 0 ||
 | 
| -          seek_preroll_ns < 0) {
 | 
| -        LOG(ERROR) << "Invalid Opus Header";
 | 
| -        return false;
 | 
| -      }
 | 
| -
 | 
| -      // csd0 - Opus Header
 | 
| -      ScopedJavaLocalRef<jbyteArray> csd0 =
 | 
| -          base::android::ToJavaByteArray(env, extra_data, extra_data_size);
 | 
| -      Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 0, csd0);
 | 
| -
 | 
| -      // csd1 - Codec Delay
 | 
| -      ScopedJavaLocalRef<jbyteArray> csd1 = base::android::ToJavaByteArray(
 | 
| -          env, reinterpret_cast<const uint8_t*>(&codec_delay_ns),
 | 
| -          sizeof(int64_t));
 | 
| -      Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 1, csd1);
 | 
| -
 | 
| -      // csd2 - Seek Preroll
 | 
| -      ScopedJavaLocalRef<jbyteArray> csd2 = base::android::ToJavaByteArray(
 | 
| -          env, reinterpret_cast<const uint8_t*>(&seek_preroll_ns),
 | 
| -          sizeof(int64_t));
 | 
| -      Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 2, csd2);
 | 
| -      break;
 | 
| -    }
 | 
| -    default:
 | 
| -      LOG(ERROR) << "Invalid header encountered for codec: "
 | 
| -                 << AudioCodecToAndroidMimeType(codec);
 | 
| -      return false;
 | 
| -  }
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -// static
 | 
| -bool VideoCodecBridge::IsKnownUnaccelerated(const VideoCodec& codec,
 | 
| -                                            MediaCodecDirection direction) {
 | 
| -  return MediaCodecUtil::IsKnownUnaccelerated(
 | 
| -      VideoCodecToAndroidMimeType(codec), direction);
 | 
| -}
 | 
| -
 | 
| -// static
 | 
| -VideoCodecBridge* VideoCodecBridge::CreateDecoder(
 | 
| -    const VideoCodec& codec,
 | 
| -    bool is_secure,
 | 
| -    const gfx::Size& size,
 | 
| -    jobject surface,
 | 
| -    jobject media_crypto,
 | 
| -    const std::vector<uint8_t>& csd0,
 | 
| -    const std::vector<uint8_t>& csd1,
 | 
| -    bool allow_adaptive_playback,
 | 
| -    bool require_software_codec) {
 | 
| -  if (!MediaCodecUtil::IsMediaCodecAvailable())
 | 
| -    return nullptr;
 | 
| -
 | 
| -  const std::string mime = VideoCodecToAndroidMimeType(codec);
 | 
| -  if (mime.empty())
 | 
| -    return nullptr;
 | 
| -
 | 
| -  std::unique_ptr<VideoCodecBridge> bridge(new VideoCodecBridge(
 | 
| -      mime, is_secure, MEDIA_CODEC_DECODER, require_software_codec));
 | 
| -  if (!bridge->media_codec())
 | 
| -    return nullptr;
 | 
| -
 | 
| -  JNIEnv* env = AttachCurrentThread();
 | 
| -  ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime);
 | 
| -  ScopedJavaLocalRef<jobject> j_format(
 | 
| -      Java_MediaCodecBridge_createVideoDecoderFormat(env, j_mime, size.width(),
 | 
| -                                                     size.height()));
 | 
| -  DCHECK(!j_format.is_null());
 | 
| -
 | 
| -  if (!csd0.empty()) {
 | 
| -    ScopedJavaLocalRef<jbyteArray> j_csd0 =
 | 
| -        base::android::ToJavaByteArray(env, csd0.data(), csd0.size());
 | 
| -    Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 0, j_csd0);
 | 
| -  }
 | 
| -
 | 
| -  if (!csd1.empty()) {
 | 
| -    ScopedJavaLocalRef<jbyteArray> j_csd1 =
 | 
| -        base::android::ToJavaByteArray(env, csd1.data(), csd1.size());
 | 
| -    Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 1, j_csd1);
 | 
| -  }
 | 
| -
 | 
| -  if (!Java_MediaCodecBridge_configureVideo(env, bridge->media_codec(),
 | 
| -                                            j_format, surface, media_crypto, 0,
 | 
| -                                            allow_adaptive_playback)) {
 | 
| -    return nullptr;
 | 
| -  }
 | 
| -
 | 
| -  return bridge->Start() ? bridge.release() : nullptr;
 | 
| -}
 | 
| -
 | 
| -// static
 | 
| -VideoCodecBridge* VideoCodecBridge::CreateEncoder(const VideoCodec& codec,
 | 
| -                                                  const gfx::Size& size,
 | 
| -                                                  int bit_rate,
 | 
| -                                                  int frame_rate,
 | 
| -                                                  int i_frame_interval,
 | 
| -                                                  int color_format) {
 | 
| -  if (!MediaCodecUtil::IsMediaCodecAvailable())
 | 
| -    return nullptr;
 | 
| -
 | 
| -  const std::string mime = VideoCodecToAndroidMimeType(codec);
 | 
| -  if (mime.empty())
 | 
| -    return nullptr;
 | 
| -
 | 
| -  std::unique_ptr<VideoCodecBridge> bridge(
 | 
| -      new VideoCodecBridge(mime, false, MEDIA_CODEC_ENCODER, false));
 | 
| -  if (!bridge->media_codec())
 | 
| -    return nullptr;
 | 
| -
 | 
| -  JNIEnv* env = AttachCurrentThread();
 | 
| -  ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime);
 | 
| -  ScopedJavaLocalRef<jobject> j_format(
 | 
| -      Java_MediaCodecBridge_createVideoEncoderFormat(
 | 
| -          env, bridge->media_codec(), j_mime, size.width(), size.height(),
 | 
| -          bit_rate, frame_rate, i_frame_interval, color_format));
 | 
| -  DCHECK(!j_format.is_null());
 | 
| -  if (!Java_MediaCodecBridge_configureVideo(env, bridge->media_codec(),
 | 
| -                                            j_format, nullptr, nullptr,
 | 
| -                                            kConfigureFlagEncode, true)) {
 | 
| -    return nullptr;
 | 
| -  }
 | 
| -
 | 
| -  return bridge->Start() ? bridge.release() : nullptr;
 | 
| -}
 | 
| -
 | 
| -VideoCodecBridge::VideoCodecBridge(const std::string& mime,
 | 
| -                                   bool is_secure,
 | 
| -                                   MediaCodecDirection direction,
 | 
| -                                   bool require_software_codec)
 | 
| -    : MediaCodecBridgeImpl(mime, is_secure, direction, require_software_codec),
 | 
| -      adaptive_playback_supported_for_testing_(-1) {}
 | 
| -
 | 
| -bool VideoCodecBridge::SetSurface(jobject surface) {
 | 
| -  DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 23);
 | 
| -  JNIEnv* env = AttachCurrentThread();
 | 
| -  return Java_MediaCodecBridge_setSurface(env, media_codec(), surface);
 | 
| -}
 | 
| -
 | 
| -void VideoCodecBridge::SetVideoBitrate(int bps, int frame_rate) {
 | 
| -  JNIEnv* env = AttachCurrentThread();
 | 
| -  Java_MediaCodecBridge_setVideoBitrate(env, media_codec(), bps, frame_rate);
 | 
| -}
 | 
| -
 | 
| -void VideoCodecBridge::RequestKeyFrameSoon() {
 | 
| -  JNIEnv* env = AttachCurrentThread();
 | 
| -  Java_MediaCodecBridge_requestKeyFrameSoon(env, media_codec());
 | 
| -}
 | 
| -
 | 
| -bool VideoCodecBridge::IsAdaptivePlaybackSupported(int width, int height) {
 | 
| -  if (adaptive_playback_supported_for_testing_ == 0)
 | 
| -    return false;
 | 
| -  else if (adaptive_playback_supported_for_testing_ > 0)
 | 
| -    return true;
 | 
| -  JNIEnv* env = AttachCurrentThread();
 | 
| -  return Java_MediaCodecBridge_isAdaptivePlaybackSupported(env, media_codec(),
 | 
| -                                                           width, height);
 | 
| -}
 | 
| -
 | 
|  }  // namespace media
 | 
| 
 |