summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoracleung <acleung@chromium.org>2015-12-14 16:23:57 -0800
committerCommit bot <commit-bot@chromium.org>2015-12-15 00:24:44 +0000
commit04baa92bc02e36182c623632f831c1b3411e8434 (patch)
tree1321a672cac2465182835aa34ac35377f6f9354f
parent80b21c78d9b898185a0da875a95079bfb392865f (diff)
downloadchromium_src-04baa92bc02e36182c623632f831c1b3411e8434.zip
chromium_src-04baa92bc02e36182c623632f831c1b3411e8434.tar.gz
chromium_src-04baa92bc02e36182c623632f831c1b3411e8434.tar.bz2
Revert of Refactor MediaCodecBridge to add support for NDK APIs (patchset #5 id:100001 of https://codereview.chromium.org/1472943002/ )
Reason for revert: This breaks 64bit ARM https://code.google.com/p/chromium/issues/detail?id=568923 Original issue's description: > Refactor MediaCodecBridge to add support for NDK APIs > > Currently MediaCodecBridge is implemented with android MediaCodec SDK API. > On android-21, MediaCodec NDK APIs have been added. > This CL makes MediaCodecBridge a common ancestor inherited by the > SDK and NDK implementation. > Some common java functions are moved to MediaCodecUtil.java. > The original native MediaCodecBridge class is renamed to > SdkMediaCodecBridge. > The NdkMediaCodecBridge is still WIP. > > BUG=560451 > > Committed: https://crrev.com/5d52e0f8e63a294179df028a0dabc76a042cf9ec > Cr-Commit-Position: refs/heads/master@{#363374} TBR=timav@chromium.org,xhwang@chromium.org,sievers@chromium.org,qinmin@chromium.org NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=560451 Review URL: https://codereview.chromium.org/1525003002 Cr-Commit-Position: refs/heads/master@{#365131}
-rw-r--r--components/cdm/browser/cdm_message_filter_android.cc5
-rw-r--r--content/child/runtime_features.cc8
-rw-r--r--content/common/gpu/media/android_video_decode_accelerator.h2
-rw-r--r--content/common/gpu/media/android_video_decode_accelerator_unittest.cc4
-rw-r--r--content/common/gpu/media/android_video_encode_accelerator.cc9
-rw-r--r--content/common/gpu/media/android_video_encode_accelerator.h2
-rw-r--r--content/common/gpu/media/avda_shared_state.h2
-rw-r--r--content/renderer/media/webrtc/peer_connection_dependency_factory.cc4
-rw-r--r--media/BUILD.gn9
-rw-r--r--media/base/android/BUILD.gn7
-rw-r--r--media/base/android/audio_decoder_job.cc12
-rw-r--r--media/base/android/java/src/org/chromium/media/MediaCodecBridge.java144
-rw-r--r--media/base/android/java/src/org/chromium/media/MediaCodecUtil.java231
-rw-r--r--media/base/android/media_codec_audio_decoder.cc17
-rw-r--r--media/base/android/media_codec_bridge.cc847
-rw-r--r--media/base/android/media_codec_bridge.h247
-rw-r--r--media/base/android/media_codec_bridge_unittest.cc319
-rw-r--r--media/base/android/media_codec_decoder.cc4
-rw-r--r--media/base/android/media_codec_decoder_unittest.cc12
-rw-r--r--media/base/android/media_codec_player_unittest.cc12
-rw-r--r--media/base/android/media_codec_util.cc225
-rw-r--r--media/base/android/media_codec_util.h63
-rw-r--r--media/base/android/media_codec_video_decoder.cc2
-rw-r--r--media/base/android/media_decoder_job.cc8
-rw-r--r--media/base/android/media_jni_registrar.cc34
-rw-r--r--media/base/android/media_source_player_unittest.cc12
-rw-r--r--media/base/android/ndk_media_codec_bridge.cc234
-rw-r--r--media/base/android/ndk_media_codec_bridge.h80
-rw-r--r--media/base/android/sdk_media_codec_bridge.cc643
-rw-r--r--media/base/android/sdk_media_codec_bridge.h198
-rw-r--r--media/base/android/sdk_media_codec_bridge_unittest.cc300
-rw-r--r--media/base/android/video_decoder_job.cc2
-rw-r--r--media/media.gyp21
33 files changed, 1592 insertions, 2127 deletions
diff --git a/components/cdm/browser/cdm_message_filter_android.cc b/components/cdm/browser/cdm_message_filter_android.cc
index 14043e1..e9399f6 100644
--- a/components/cdm/browser/cdm_message_filter_android.cc
+++ b/components/cdm/browser/cdm_message_filter_android.cc
@@ -9,10 +9,11 @@
#include "components/cdm/common/cdm_messages_android.h"
#include "ipc/ipc_message_macros.h"
-#include "media/base/android/media_codec_util.h"
+#include "media/base/android/media_codec_bridge.h"
#include "media/base/android/media_drm_bridge.h"
using content::BrowserThread;
+using media::MediaCodecBridge;
using media::MediaDrmBridge;
using media::SupportedCodecs;
@@ -58,7 +59,7 @@ static SupportedCodecs GetSupportedCodecs(
if ((request.codecs & info.codec) &&
MediaDrmBridge::IsKeySystemSupportedWithType(
key_system, info.container_mime_type) &&
- media::MediaCodecUtil::CanDecode(info.codec_name, is_secure)) {
+ MediaCodecBridge::CanDecode(info.codec_name, is_secure)) {
supported_codecs |= info.codec;
}
}
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 3a8bffa..274a902 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -19,7 +19,7 @@
#include <cpu-features.h>
#include "base/android/build_info.h"
#include "base/metrics/field_trial.h"
-#include "media/base/android/media_codec_util.h"
+#include "media/base/android/media_codec_bridge.h"
#elif defined(OS_WIN)
#include "base/win/windows_version.h"
#endif
@@ -34,7 +34,7 @@ static void SetRuntimeFeatureDefaultsForPlatform() {
#if defined(OS_ANDROID)
// MSE/EME implementation needs Android MediaCodec API.
- if (!media::MediaCodecUtil::IsMediaCodecAvailable()) {
+ if (!media::MediaCodecBridge::IsAvailable()) {
WebRuntimeFeatures::enableMediaSource(false);
WebRuntimeFeatures::enablePrefixedEncryptedMedia(false);
WebRuntimeFeatures::enableEncryptedMedia(false);
@@ -43,7 +43,7 @@ static void SetRuntimeFeatureDefaultsForPlatform() {
// is available.
AndroidCpuFamily cpu_family = android_getCpuFamily();
WebRuntimeFeatures::enableWebAudio(
- media::MediaCodecUtil::IsMediaCodecAvailable() &&
+ media::MediaCodecBridge::IsAvailable() &&
((cpu_family == ANDROID_CPU_FAMILY_ARM) ||
(cpu_family == ANDROID_CPU_FAMILY_ARM64) ||
(cpu_family == ANDROID_CPU_FAMILY_X86) ||
@@ -121,7 +121,7 @@ void SetRuntimeFeaturesDefaultsAndUpdateFromArgs(
// API is available.
WebRuntimeFeatures::enableWebAudio(
!command_line.HasSwitch(switches::kDisableWebAudio) &&
- media::MediaCodecUtil::IsMediaCodecAvailable());
+ media::MediaCodecBridge::IsAvailable());
#else
if (command_line.HasSwitch(switches::kDisableWebAudio))
WebRuntimeFeatures::enableWebAudio(false);
diff --git a/content/common/gpu/media/android_video_decode_accelerator.h b/content/common/gpu/media/android_video_decode_accelerator.h
index 6221ad9..e79f0c0 100644
--- a/content/common/gpu/media/android_video_decode_accelerator.h
+++ b/content/common/gpu/media/android_video_decode_accelerator.h
@@ -17,7 +17,7 @@
#include "content/common/content_export.h"
#include "content/common/gpu/media/avda_state_provider.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
-#include "media/base/android/sdk_media_codec_bridge.h"
+#include "media/base/android/media_codec_bridge.h"
#include "media/video/video_decode_accelerator.h"
namespace gfx {
diff --git a/content/common/gpu/media/android_video_decode_accelerator_unittest.cc b/content/common/gpu/media/android_video_decode_accelerator_unittest.cc
index 400d7cc..5ad3f2c 100644
--- a/content/common/gpu/media/android_video_decode_accelerator_unittest.cc
+++ b/content/common/gpu/media/android_video_decode_accelerator_unittest.cc
@@ -12,7 +12,7 @@
#include "content/common/gpu/media/android_copying_backing_strategy.h"
#include "content/common/gpu/media/android_video_decode_accelerator.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
-#include "media/base/android/media_codec_util.h"
+#include "media/base/android/media_codec_bridge.h"
#include "media/base/android/media_jni_registrar.h"
#include "media/video/picture.h"
#include "media/video/video_decode_accelerator.h"
@@ -91,7 +91,7 @@ TEST_F(AndroidVideoDecodeAcceleratorTest, ConfigureUnsupportedCodec) {
}
TEST_F(AndroidVideoDecodeAcceleratorTest, ConfigureSupportedCodec) {
- if (!media::MediaCodecUtil::IsMediaCodecAvailable())
+ if (!media::MediaCodecBridge::IsAvailable())
return;
EXPECT_TRUE(Configure(media::kCodecVP8));
}
diff --git a/content/common/gpu/media/android_video_encode_accelerator.cc b/content/common/gpu/media/android_video_encode_accelerator.cc
index 72689c9..06931bf 100644
--- a/content/common/gpu/media/android_video_encode_accelerator.cc
+++ b/content/common/gpu/media/android_video_encode_accelerator.cc
@@ -14,7 +14,7 @@
#include "content/common/gpu/gpu_channel.h"
#include "content/public/common/content_switches.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
-#include "media/base/android/media_codec_util.h"
+#include "media/base/android/media_codec_bridge.h"
#include "media/base/bitstream_buffer.h"
#include "media/base/limits.h"
#include "media/video/picture.h"
@@ -22,6 +22,7 @@
#include "ui/gl/android/scoped_java_surface.h"
#include "ui/gl/gl_bindings.h"
+using media::MediaCodecBridge;
using media::VideoCodecBridge;
using media::VideoFrame;
@@ -82,7 +83,7 @@ static bool GetSupportedColorFormatForMime(const std::string& mime,
if (mime.empty())
return false;
- std::set<int> formats = media::MediaCodecUtil::GetEncoderColorFormats(mime);
+ std::set<int> formats = MediaCodecBridge::GetEncoderColorFormats(mime);
if (formats.count(COLOR_FORMAT_YUV420_SEMIPLANAR) > 0)
*pixel_format = COLOR_FORMAT_YUV420_SEMIPLANAR;
else if (formats.count(COLOR_FORMAT_YUV420_PLANAR) > 0)
@@ -156,8 +157,8 @@ bool AndroidVideoEncodeAccelerator::Initialize(
client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client));
- if (!(media::MediaCodecUtil::SupportsSetParameters() &&
- format == media::PIXEL_FORMAT_I420)) {
+ if (!(media::MediaCodecBridge::SupportsSetParameters() &&
+ format == media::PIXEL_FORMAT_I420)) {
DLOG(ERROR) << "Unexpected combo: " << format << ", " << output_profile;
return false;
}
diff --git a/content/common/gpu/media/android_video_encode_accelerator.h b/content/common/gpu/media/android_video_encode_accelerator.h
index 1528726..6608b87 100644
--- a/content/common/gpu/media/android_video_encode_accelerator.h
+++ b/content/common/gpu/media/android_video_encode_accelerator.h
@@ -16,7 +16,7 @@
#include "base/timer/timer.h"
#include "base/tuple.h"
#include "content/common/content_export.h"
-#include "media/base/android/sdk_media_codec_bridge.h"
+#include "media/base/android/media_codec_bridge.h"
#include "media/video/video_encode_accelerator.h"
namespace media {
diff --git a/content/common/gpu/media/avda_shared_state.h b/content/common/gpu/media/avda_shared_state.h
index 474037d..a64bf3a 100644
--- a/content/common/gpu/media/avda_shared_state.h
+++ b/content/common/gpu/media/avda_shared_state.h
@@ -6,7 +6,7 @@
#define CONTENT_COMMON_GPU_AVDA_SHARED_STATE_H_
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
-#include "media/base/android/sdk_media_codec_bridge.h"
+#include "media/base/android/media_codec_bridge.h"
#include "ui/gl/gl_image.h"
namespace gfx {
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
index a7b373e..ac524a6 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
@@ -63,7 +63,7 @@
#include "third_party/webrtc/base/ssladapter.h"
#if defined(OS_ANDROID)
-#include "media/base/android/media_codec_util.h"
+#include "media/base/android/media_codec_bridge.h"
#endif
namespace content {
@@ -335,7 +335,7 @@ void PeerConnectionDependencyFactory::InitializeSignalingThread(
}
#if defined(OS_ANDROID)
- if (!media::MediaCodecUtil::SupportsSetParameters())
+ if (!media::MediaCodecBridge::SupportsSetParameters())
encoder_factory.reset();
#endif
diff --git a/media/BUILD.gn b/media/BUILD.gn
index 746437c..1c2a73f 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -396,15 +396,6 @@ component("media") {
"//media/base/android:video_capture_jni_headers",
]
- # Only 64 bit builds are using android-21 NDK library, check common.gypi
- if (current_cpu == "arm64" || current_cpu == "x64" ||
- current_cpu == "mips64el") {
- sources += [
- "base/android/ndk_media_codec_bridge.cc",
- "base/android/ndk_media_codec_bridge.h",
- ]
- libs += [ "mediandk" ]
- }
allow_circular_includes_from = [ "//media/base/android" ]
}
diff --git a/media/base/android/BUILD.gn b/media/base/android/BUILD.gn
index 75c6717..c51ee6b 100644
--- a/media/base/android/BUILD.gn
+++ b/media/base/android/BUILD.gn
@@ -31,8 +31,6 @@ source_set("android") {
"media_codec_decoder.h",
"media_codec_player.cc",
"media_codec_player.h",
- "media_codec_util.cc",
- "media_codec_util.h",
"media_codec_video_decoder.cc",
"media_codec_video_decoder.h",
"media_decoder_job.cc",
@@ -60,8 +58,6 @@ source_set("android") {
"media_task_runner.h",
"media_url_interceptor.h",
"provision_fetcher.h",
- "sdk_media_codec_bridge.cc",
- "sdk_media_codec_bridge.h",
"video_decoder_job.cc",
"video_decoder_job.h",
"webaudio_media_codec_bridge.cc",
@@ -85,12 +81,12 @@ source_set("unittests") {
testonly = true
sources = [
"access_unit_queue_unittest.cc",
+ "media_codec_bridge_unittest.cc",
"media_codec_decoder_unittest.cc",
"media_codec_player_unittest.cc",
"media_drm_bridge_unittest.cc",
"media_player_bridge_unittest.cc",
"media_source_player_unittest.cc",
- "sdk_media_codec_bridge_unittest.cc",
"test_data_factory.cc",
"test_data_factory.h",
"test_statistics.h",
@@ -110,7 +106,6 @@ generate_jni("media_jni_headers") {
"java/src/org/chromium/media/AudioManagerAndroid.java",
"java/src/org/chromium/media/AudioRecordInput.java",
"java/src/org/chromium/media/MediaCodecBridge.java",
- "java/src/org/chromium/media/MediaCodecUtil.java",
"java/src/org/chromium/media/MediaDrmBridge.java",
"java/src/org/chromium/media/MediaPlayerBridge.java",
"java/src/org/chromium/media/MediaPlayerListener.java",
diff --git a/media/base/android/audio_decoder_job.cc b/media/base/android/audio_decoder_job.cc
index 3cf2c5f..66c6a60 100644
--- a/media/base/android/audio_decoder_job.cc
+++ b/media/base/android/audio_decoder_job.cc
@@ -7,7 +7,7 @@
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/threading/thread.h"
-#include "media/base/android/sdk_media_codec_bridge.h"
+#include "media/base/android/media_codec_bridge.h"
#include "media/base/audio_timestamp_helper.h"
#include "media/base/timestamp_constants.h"
@@ -161,12 +161,10 @@ MediaDecoderJob::MediaDecoderJobStatus
if (!media_codec_bridge_)
return STATUS_FAILURE;
- if (!(static_cast<AudioCodecBridge*>(media_codec_bridge_.get()))
- ->ConfigureAndStart(audio_codec_, config_sampling_rate_,
- num_channels_, &audio_extra_data_[0],
- audio_extra_data_.size(), audio_codec_delay_ns_,
- audio_seek_preroll_ns_, true,
- GetMediaCrypto())) {
+ if (!(static_cast<AudioCodecBridge*>(media_codec_bridge_.get()))->Start(
+ audio_codec_, config_sampling_rate_, num_channels_, &audio_extra_data_[0],
+ audio_extra_data_.size(), audio_codec_delay_ns_, audio_seek_preroll_ns_,
+ true, GetMediaCrypto())) {
media_codec_bridge_.reset();
return STATUS_FAILURE;
}
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
index 3a62582..72c3964 100644
--- a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
@@ -22,6 +22,9 @@ import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
/**
* A wrapper of the MediaCodec class to facilitate exception capturing and
@@ -44,6 +47,10 @@ class MediaCodecBridge {
private static final int MEDIA_CODEC_ABORT = 8;
private static final int MEDIA_CODEC_ERROR = 9;
+ // Codec direction. Keep this in sync with media_codec_bridge.h.
+ private static final int MEDIA_CODEC_DECODER = 0;
+ private static final int MEDIA_CODEC_ENCODER = 1;
+
// Max adaptive playback size to be supplied to the decoder.
private static final int MAX_ADAPTIVE_PLAYBACK_WIDTH = 1920;
private static final int MAX_ADAPTIVE_PLAYBACK_HEIGHT = 1080;
@@ -93,6 +100,37 @@ class MediaCodecBridge {
}
}
+ /**
+ * This class represents supported android codec information.
+ */
+ private static class CodecInfo {
+ private final String mCodecType; // e.g. "video/x-vnd.on2.vp8".
+ private final String mCodecName; // e.g. "OMX.google.vp8.decoder".
+ private final int mDirection;
+
+ private CodecInfo(String codecType, String codecName,
+ int direction) {
+ mCodecType = codecType;
+ mCodecName = codecName;
+ mDirection = direction;
+ }
+
+ @CalledByNative("CodecInfo")
+ private String codecType() {
+ return mCodecType;
+ }
+
+ @CalledByNative("CodecInfo")
+ private String codecName() {
+ return mCodecName;
+ }
+
+ @CalledByNative("CodecInfo")
+ private int direction() {
+ return mDirection;
+ }
+ }
+
private static class DequeueOutputResult {
private final int mStatus;
private final int mIndex;
@@ -142,6 +180,105 @@ class MediaCodecBridge {
}
}
+ /**
+ * Get a list of supported android codec mimes.
+ */
+ @SuppressWarnings("deprecation")
+ @CalledByNative
+ private static CodecInfo[] getCodecsInfo() {
+ // Return the first (highest-priority) codec for each MIME type.
+ Map<String, CodecInfo> encoderInfoMap = new HashMap<String, CodecInfo>();
+ Map<String, CodecInfo> decoderInfoMap = new HashMap<String, CodecInfo>();
+ int count = MediaCodecList.getCodecCount();
+ for (int i = 0; i < count; ++i) {
+ MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
+ int direction =
+ info.isEncoder() ? MEDIA_CODEC_ENCODER : MEDIA_CODEC_DECODER;
+ String codecString = info.getName();
+ String[] supportedTypes = info.getSupportedTypes();
+ for (int j = 0; j < supportedTypes.length; ++j) {
+ Map<String, CodecInfo> map = info.isEncoder() ? encoderInfoMap : decoderInfoMap;
+ if (!map.containsKey(supportedTypes[j])) {
+ map.put(supportedTypes[j], new CodecInfo(
+ supportedTypes[j], codecString, direction));
+ }
+ }
+ }
+ ArrayList<CodecInfo> codecInfos = new ArrayList<CodecInfo>(
+ decoderInfoMap.size() + encoderInfoMap.size());
+ codecInfos.addAll(encoderInfoMap.values());
+ codecInfos.addAll(decoderInfoMap.values());
+ return codecInfos.toArray(new CodecInfo[codecInfos.size()]);
+ }
+
+ /**
+ * Get a name of default android codec.
+ */
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
+ @SuppressWarnings("deprecation")
+ @CalledByNative
+ private static String getDefaultCodecName(String mime, int direction) {
+ String codecName = "";
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ try {
+ MediaCodec mediaCodec = null;
+ if (direction == MEDIA_CODEC_ENCODER) {
+ mediaCodec = MediaCodec.createEncoderByType(mime);
+ } else {
+ mediaCodec = MediaCodec.createDecoderByType(mime);
+ }
+ codecName = mediaCodec.getName();
+ mediaCodec.release();
+ } catch (Exception e) {
+ Log.w(TAG, "getDefaultCodecName: Failed to create MediaCodec: %s, direction: %d",
+ mime, direction, e);
+ }
+ }
+ return codecName;
+ }
+
+ /**
+ * Get a list of encoder supported color formats for specified mime type.
+ */
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ @SuppressWarnings("deprecation")
+ @CalledByNative
+ private static int[] getEncoderColorFormatsForMime(String mime) {
+ MediaCodecInfo[] codecs = null;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
+ codecs = mediaCodecList.getCodecInfos();
+ } else {
+ int count = MediaCodecList.getCodecCount();
+ if (count <= 0) {
+ return null;
+ }
+ codecs = new MediaCodecInfo[count];
+ for (int i = 0; i < count; ++i) {
+ MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
+ codecs[i] = info;
+ }
+ }
+
+ for (int i = 0; i < codecs.length; i++) {
+ if (!codecs[i].isEncoder()) {
+ continue;
+ }
+
+ String[] supportedTypes = codecs[i].getSupportedTypes();
+ for (int j = 0; j < supportedTypes.length; ++j) {
+ if (!supportedTypes[j].equalsIgnoreCase(mime)) {
+ continue;
+ }
+
+ MediaCodecInfo.CodecCapabilities capabilities =
+ codecs[i].getCapabilitiesForType(mime);
+ return capabilities.colorFormats;
+ }
+ }
+ return null;
+ }
+
@SuppressWarnings("deprecation")
private static String getDecoderNameForMime(String mime) {
int count = MediaCodecList.getCodecCount();
@@ -184,9 +321,8 @@ class MediaCodecBridge {
boolean adaptivePlaybackSupported = false;
try {
// |isSecure| only applies to video decoders.
- if (mime.startsWith("video") && isSecure
- && direction == MediaCodecUtil.MEDIA_CODEC_DECODER) {
- String decoderName = MediaCodecUtil.getDecoderNameForMime(mime);
+ if (mime.startsWith("video") && isSecure && direction == MEDIA_CODEC_DECODER) {
+ String decoderName = getDecoderNameForMime(mime);
if (decoderName == null) {
return null;
}
@@ -200,7 +336,7 @@ class MediaCodecBridge {
}
mediaCodec = MediaCodec.createByCodecName(decoderName + ".secure");
} else {
- if (direction == MediaCodecUtil.MEDIA_CODEC_ENCODER) {
+ if (direction == MEDIA_CODEC_ENCODER) {
mediaCodec = MediaCodec.createEncoderByType(mime);
} else {
mediaCodec = MediaCodec.createDecoderByType(mime);
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
deleted file mode 100644
index b498b29..0000000
--- a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
+++ /dev/null
@@ -1,231 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.media;
-
-import android.annotation.TargetApi;
-import android.media.MediaCodec;
-import android.media.MediaCodecInfo;
-import android.media.MediaCodecList;
-import android.os.Build;
-
-import org.chromium.base.Log;
-import org.chromium.base.annotations.CalledByNative;
-import org.chromium.base.annotations.JNINamespace;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A collection of MediaCodec utility functions.
- */
-@JNINamespace("media")
-class MediaCodecUtil {
- private static final String TAG = "MediaCodecUtil";
-
- // Codec direction. Keep this in sync with media_codec_bridge.h.
- static final int MEDIA_CODEC_DECODER = 0;
- static final int MEDIA_CODEC_ENCODER = 1;
-
- /**
- * This class represents supported android codec information.
- */
- private static class CodecInfo {
- private final String mCodecType; // e.g. "video/x-vnd.on2.vp8".
- private final String mCodecName; // e.g. "OMX.google.vp8.decoder".
- private final int mDirection;
-
- private CodecInfo(String codecType, String codecName, int direction) {
- mCodecType = codecType;
- mCodecName = codecName;
- mDirection = direction;
- }
-
- @CalledByNative("CodecInfo")
- private String codecType() {
- return mCodecType;
- }
-
- @CalledByNative("CodecInfo")
- private String codecName() {
- return mCodecName;
- }
-
- @CalledByNative("CodecInfo")
- private int direction() {
- return mDirection;
- }
- }
-
- /**
- * @return a list of supported android codec information.
- */
- @SuppressWarnings("deprecation")
- @CalledByNative
- private static CodecInfo[] getCodecsInfo() {
- // Return the first (highest-priority) codec for each MIME type.
- Map<String, CodecInfo> encoderInfoMap = new HashMap<String, CodecInfo>();
- Map<String, CodecInfo> decoderInfoMap = new HashMap<String, CodecInfo>();
- int count = MediaCodecList.getCodecCount();
- for (int i = 0; i < count; ++i) {
- MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
- int direction = info.isEncoder() ? MEDIA_CODEC_ENCODER : MEDIA_CODEC_DECODER;
- String codecString = info.getName();
- String[] supportedTypes = info.getSupportedTypes();
- for (int j = 0; j < supportedTypes.length; ++j) {
- Map<String, CodecInfo> map = info.isEncoder() ? encoderInfoMap : decoderInfoMap;
- if (!map.containsKey(supportedTypes[j])) {
- map.put(supportedTypes[j],
- new CodecInfo(supportedTypes[j], codecString, direction));
- }
- }
- }
- ArrayList<CodecInfo> codecInfos =
- new ArrayList<CodecInfo>(decoderInfoMap.size() + encoderInfoMap.size());
- codecInfos.addAll(encoderInfoMap.values());
- codecInfos.addAll(decoderInfoMap.values());
- return codecInfos.toArray(new CodecInfo[codecInfos.size()]);
- }
-
- /**
- * Get a name of default android codec.
- * @param mime MIME type of the media.
- * @param direction Whether this is encoder or decoder.
- * @return name of the codec.
- */
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
- @SuppressWarnings("deprecation")
- @CalledByNative
- private static String getDefaultCodecName(String mime, int direction) {
- String codecName = "";
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
- try {
- MediaCodec mediaCodec = null;
- if (direction == MEDIA_CODEC_ENCODER) {
- mediaCodec = MediaCodec.createEncoderByType(mime);
- } else {
- mediaCodec = MediaCodec.createDecoderByType(mime);
- }
- codecName = mediaCodec.getName();
- mediaCodec.release();
- } catch (Exception e) {
- Log.w(TAG, "getDefaultCodecName: Failed to create MediaCodec: %s, direction: %d",
- mime, direction, e);
- }
- }
- return codecName;
- }
-
- /**
- * Get a list of encoder supported color formats for specified MIME type.
- * @param mime MIME type of the media format.
- * @return a list of encoder supported color formats.
- */
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- @SuppressWarnings("deprecation")
- @CalledByNative
- private static int[] getEncoderColorFormatsForMime(String mime) {
- MediaCodecInfo[] codecs = null;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
- codecs = mediaCodecList.getCodecInfos();
- } else {
- int count = MediaCodecList.getCodecCount();
- if (count <= 0) {
- return null;
- }
- codecs = new MediaCodecInfo[count];
- for (int i = 0; i < count; ++i) {
- MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
- codecs[i] = info;
- }
- }
-
- for (int i = 0; i < codecs.length; i++) {
- if (!codecs[i].isEncoder()) {
- continue;
- }
-
- String[] supportedTypes = codecs[i].getSupportedTypes();
- for (int j = 0; j < supportedTypes.length; ++j) {
- if (!supportedTypes[j].equalsIgnoreCase(mime)) {
- continue;
- }
-
- MediaCodecInfo.CodecCapabilities capabilities =
- codecs[i].getCapabilitiesForType(mime);
- return capabilities.colorFormats;
- }
- }
- return null;
- }
-
- /**
- * Get decoder name for the input MIME type.
- * @param mime MIME type of the media.
- * @return name of the decoder.
- */
- @SuppressWarnings("deprecation")
- protected static String getDecoderNameForMime(String mime) {
- int count = MediaCodecList.getCodecCount();
- for (int i = 0; i < count; ++i) {
- MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
- if (info.isEncoder()) {
- continue;
- }
-
- String[] supportedTypes = info.getSupportedTypes();
- for (int j = 0; j < supportedTypes.length; ++j) {
- if (supportedTypes[j].equalsIgnoreCase(mime)) {
- return info.getName();
- }
- }
- }
- return null;
- }
-
- /**
- * Check if a given MIME type can be decoded.
- * @param mime MIME type of the media.
- * @param secure Whether secure decoder is required.
- * @return true if system is able to decode, or false otherwise.
- */
- @CalledByNative
- private static boolean canDecode(String mime, boolean isSecure) {
- // Creation of ".secure" codecs sometimes crash instead of throwing exceptions
- // on pre-JBMR2 devices.
- if (isSecure && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
- return false;
- }
- MediaCodec mediaCodec = null;
- try {
- // |isSecure| only applies to video decoders.
- if (mime.startsWith("video") && isSecure) {
- String decoderName = getDecoderNameForMime(mime);
- if (decoderName == null) return false;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- // To work around an issue that we cannot get the codec info from the secure
- // decoder, create an insecure decoder first so that we can query its codec
- // info. http://b/15587335.
- MediaCodec insecureCodec = MediaCodec.createByCodecName(decoderName);
- insecureCodec.release();
- }
- mediaCodec = MediaCodec.createByCodecName(decoderName + ".secure");
- } else {
- mediaCodec = MediaCodec.createDecoderByType(mime);
- }
- } catch (Exception e) {
- Log.e(TAG, "Failed to create MediaCodec: %s, isSecure: %s", mime, isSecure, e);
- }
-
- if (mediaCodec == null) return false;
- try {
- mediaCodec.release();
- } catch (IllegalStateException e) {
- Log.e(TAG, "Cannot release media codec", e);
- }
- return true;
- }
-}
diff --git a/media/base/android/media_codec_audio_decoder.cc b/media/base/android/media_codec_audio_decoder.cc
index f68a07e..4b8a076 100644
--- a/media/base/android/media_codec_audio_decoder.cc
+++ b/media/base/android/media_codec_audio_decoder.cc
@@ -6,8 +6,8 @@
#include "base/bind.h"
#include "base/logging.h"
+#include "media/base/android/media_codec_bridge.h"
#include "media/base/android/media_statistics.h"
-#include "media/base/android/sdk_media_codec_bridge.h"
#include "media/base/audio_timestamp_helper.h"
#include "media/base/demuxer_stream.h"
@@ -144,11 +144,16 @@ MediaCodecDecoder::ConfigStatus MediaCodecAudioDecoder::ConfigureInternal(
return kConfigFailure;
if (!(static_cast<AudioCodecBridge*>(media_codec_bridge_.get()))
- ->ConfigureAndStart(
- configs_.audio_codec, configs_.audio_sampling_rate,
- configs_.audio_channels, &configs_.audio_extra_data[0],
- configs_.audio_extra_data.size(), configs_.audio_codec_delay_ns,
- configs_.audio_seek_preroll_ns, true, media_crypto)) {
+ ->Start(
+ configs_.audio_codec,
+ configs_.audio_sampling_rate,
+ configs_.audio_channels,
+ &configs_.audio_extra_data[0],
+ configs_.audio_extra_data.size(),
+ configs_.audio_codec_delay_ns,
+ configs_.audio_seek_preroll_ns,
+ true,
+ media_crypto)) {
DVLOG(0) << class_name() << "::" << __FUNCTION__
<< " failed: cannot start audio codec";
diff --git a/media/base/android/media_codec_bridge.cc b/media/base/android/media_codec_bridge.cc
index 6ca7e48..9acec21 100644
--- a/media/base/android/media_codec_bridge.cc
+++ b/media/base/android/media_codec_bridge.cc
@@ -5,13 +5,20 @@
#include "media/base/android/media_codec_bridge.h"
#include <algorithm>
+#include <limits>
#include "base/android/build_info.h"
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
+#include "base/basictypes.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "jni/MediaCodecBridge_jni.h"
+#include "media/base/bit_reader.h"
#include "media/base/decrypt_config.h"
using base::android::AttachCurrentThread;
@@ -20,11 +27,321 @@ using base::android::ConvertUTF8ToJavaString;
using base::android::JavaIntArrayToIntVector;
using base::android::ScopedJavaLocalRef;
+#define RETURN_ON_ERROR(condition) \
+ do { \
+ if (!(condition)) { \
+ LOG(ERROR) << "Unable to parse AAC header: " #condition; \
+ return false; \
+ } \
+ } while (0)
+
namespace media {
-MediaCodecBridge::MediaCodecBridge() {}
+enum {
+ kBufferFlagSyncFrame = 1, // BUFFER_FLAG_SYNC_FRAME
+ kBufferFlagEndOfStream = 4, // BUFFER_FLAG_END_OF_STREAM
+ kConfigureFlagEncode = 1, // CONFIGURE_FLAG_ENCODE
+};
+
+static 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";
+ default:
+ return std::string();
+ }
+}
+
+static const std::string VideoCodecToAndroidMimeType(const VideoCodec& codec) {
+ 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";
+ default:
+ return std::string();
+ }
+}
+
+static const std::string CodecTypeToAndroidMimeType(const std::string& codec) {
+ // TODO(xhwang): Shall we handle more detailed strings like "mp4a.40.2"?
+ if (codec == "avc1")
+ return "video/avc";
+ if (codec == "hvc1")
+ return "video/hevc";
+ if (codec == "mp4a")
+ return "audio/mp4a-latm";
+ if (codec == "vp8" || codec == "vp8.0")
+ return "video/x-vnd.on2.vp8";
+ if (codec == "vp9" || codec == "vp9.0")
+ return "video/x-vnd.on2.vp9";
+ if (codec == "vorbis")
+ return "audio/vorbis";
+ if (codec == "opus")
+ return "audio/opus";
+ return std::string();
+}
+
+// TODO(qinmin): using a map to help all the conversions in this class.
+static const std::string AndroidMimeTypeToCodecType(const std::string& mime) {
+ if (mime == "video/mp4v-es")
+ return "mp4v";
+ if (mime == "video/avc")
+ return "avc1";
+ if (mime == "video/hevc")
+ return "hvc1";
+ if (mime == "video/x-vnd.on2.vp8")
+ return "vp8";
+ if (mime == "video/x-vnd.on2.vp9")
+ return "vp9";
+ if (mime == "audio/mp4a-latm")
+ return "mp4a";
+ if (mime == "audio/mpeg")
+ return "mp3";
+ if (mime == "audio/vorbis")
+ return "vorbis";
+ if (mime == "audio/opus")
+ return "opus";
+ return std::string();
+}
+
+static ScopedJavaLocalRef<jintArray>
+ToJavaIntArray(JNIEnv* env, scoped_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;
+}
+
+// static
+bool MediaCodecBridge::IsAvailable() {
+ // MediaCodec is only available on JB and greater.
+ if (base::android::BuildInfo::GetInstance()->sdk_int() < 16)
+ return false;
+ // Blacklist some devices on Jellybean as for MediaCodec support is buggy.
+ // http://crbug.com/365494.
+ if (base::android::BuildInfo::GetInstance()->sdk_int() == 16) {
+ std::string model(base::android::BuildInfo::GetInstance()->model());
+ return model != "GT-I9100" && model != "GT-I9300" && model != "GT-N7000";
+ }
+ return true;
+}
+
+// static
+bool MediaCodecBridge::SupportsSetParameters() {
+ // MediaCodec.setParameters() is only available starting with K.
+ return base::android::BuildInfo::GetInstance()->sdk_int() >= 19;
+}
+
+// static
+bool MediaCodecBridge::SupportsGetName() {
+ // MediaCodec.getName() is only available on JB MR2 and greater.
+ return base::android::BuildInfo::GetInstance()->sdk_int() >= 18;
+}
+
+// static
+std::vector<MediaCodecBridge::CodecsInfo> MediaCodecBridge::GetCodecsInfo() {
+ std::vector<CodecsInfo> codecs_info;
+ if (!IsAvailable())
+ return codecs_info;
+
+ JNIEnv* env = AttachCurrentThread();
+ std::string mime_type;
+ ScopedJavaLocalRef<jobjectArray> j_codec_info_array =
+ Java_MediaCodecBridge_getCodecsInfo(env);
+ jsize len = env->GetArrayLength(j_codec_info_array.obj());
+ for (jsize i = 0; i < len; ++i) {
+ ScopedJavaLocalRef<jobject> j_info(
+ env, env->GetObjectArrayElement(j_codec_info_array.obj(), i));
+ ScopedJavaLocalRef<jstring> j_codec_type =
+ Java_CodecInfo_codecType(env, j_info.obj());
+ ConvertJavaStringToUTF8(env, j_codec_type.obj(), &mime_type);
+ ScopedJavaLocalRef<jstring> j_codec_name =
+ Java_CodecInfo_codecName(env, j_info.obj());
+ CodecsInfo info;
+ info.codecs = AndroidMimeTypeToCodecType(mime_type);
+ ConvertJavaStringToUTF8(env, j_codec_name.obj(), &info.name);
+ info.direction = static_cast<MediaCodecDirection>(
+ Java_CodecInfo_direction(env, j_info.obj()));
+ codecs_info.push_back(info);
+ }
+ return codecs_info;
+}
+
+// static
+std::string MediaCodecBridge::GetDefaultCodecName(
+ const std::string& mime_type,
+ MediaCodecDirection direction) {
+ if (!IsAvailable())
+ return std::string();
-MediaCodecBridge::~MediaCodecBridge() {}
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime_type);
+ ScopedJavaLocalRef<jstring> j_codec_name =
+ Java_MediaCodecBridge_getDefaultCodecName(env, j_mime.obj(), direction);
+ return ConvertJavaStringToUTF8(env, j_codec_name.obj());
+}
+
+// static
+std::set<int> MediaCodecBridge::GetEncoderColorFormats(
+ const std::string& mime_type) {
+ std::set<int> color_formats;
+ if (!IsAvailable())
+ return color_formats;
+
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime_type);
+ ScopedJavaLocalRef<jintArray> j_color_format_array =
+ Java_MediaCodecBridge_getEncoderColorFormatsForMime(env, j_mime.obj());
+
+ if (j_color_format_array.obj()) {
+ std::vector<int> formats;
+ JavaIntArrayToIntVector(env, j_color_format_array.obj(), &formats);
+ color_formats = std::set<int>(formats.begin(), formats.end());
+ }
+
+ return color_formats;
+}
+
+// static
+bool MediaCodecBridge::CanDecode(const std::string& codec, bool is_secure) {
+ if (!IsAvailable())
+ return false;
+
+ JNIEnv* env = AttachCurrentThread();
+ std::string mime = CodecTypeToAndroidMimeType(codec);
+ if (mime.empty())
+ return false;
+ ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime);
+ ScopedJavaLocalRef<jobject> j_media_codec_bridge =
+ Java_MediaCodecBridge_create(env, j_mime.obj(), is_secure, false);
+ if (!j_media_codec_bridge.is_null()) {
+ Java_MediaCodecBridge_release(env, j_media_codec_bridge.obj());
+ return true;
+ }
+ return false;
+}
+
+// static
+bool MediaCodecBridge::IsKnownUnaccelerated(const std::string& mime_type,
+ MediaCodecDirection direction) {
+ if (!IsAvailable())
+ return true;
+
+ std::string codec_name;
+ if (SupportsGetName()) {
+ codec_name = GetDefaultCodecName(mime_type, direction);
+ } else {
+ std::string codec_type = AndroidMimeTypeToCodecType(mime_type);
+ std::vector<media::MediaCodecBridge::CodecsInfo> codecs_info =
+ MediaCodecBridge::GetCodecsInfo();
+ for (size_t i = 0; i < codecs_info.size(); ++i) {
+ if (codecs_info[i].codecs == codec_type &&
+ codecs_info[i].direction == direction) {
+ codec_name = codecs_info[i].name;
+ break;
+ }
+ }
+ }
+ DVLOG(1) << __PRETTY_FUNCTION__ << "Default codec for " << mime_type <<
+ " : " << codec_name;
+ // It would be nice if MediaCodecInfo externalized some notion of
+ // HW-acceleration but it doesn't. Android Media guidance is that the
+ // "OMX.google" prefix is always used for SW decoders, so that's what we
+ // use. "OMX.SEC.*" codec is Samsung software implementation - report it
+ // as unaccelerated as well. Also temporary blacklist Exynos and MediaTek
+ // devices while HW decoder video freezes and distortions are
+ // investigated - http://crbug.com/446974.
+ if (codec_name.length() > 0) {
+ return (base::StartsWith(codec_name, "OMX.google.",
+ base::CompareCase::SENSITIVE) ||
+ base::StartsWith(codec_name, "OMX.SEC.",
+ base::CompareCase::SENSITIVE) ||
+ base::StartsWith(codec_name, "OMX.MTK.",
+ base::CompareCase::SENSITIVE) ||
+ base::StartsWith(codec_name, "OMX.Exynos.",
+ base::CompareCase::SENSITIVE));
+ }
+ return true;
+}
+
+MediaCodecBridge::MediaCodecBridge(const std::string& mime,
+ bool is_secure,
+ MediaCodecDirection direction) {
+ JNIEnv* env = AttachCurrentThread();
+ CHECK(env);
+ DCHECK(!mime.empty());
+ ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime);
+ j_media_codec_.Reset(
+ Java_MediaCodecBridge_create(env, j_mime.obj(), is_secure, direction));
+}
+
+MediaCodecBridge::~MediaCodecBridge() {
+ JNIEnv* env = AttachCurrentThread();
+ CHECK(env);
+ if (j_media_codec_.obj())
+ Java_MediaCodecBridge_release(env, j_media_codec_.obj());
+}
+
+bool MediaCodecBridge::StartInternal() {
+ JNIEnv* env = AttachCurrentThread();
+ return Java_MediaCodecBridge_start(env, j_media_codec_.obj());
+}
+
+MediaCodecStatus MediaCodecBridge::Reset() {
+ JNIEnv* env = AttachCurrentThread();
+ return static_cast<MediaCodecStatus>(
+ Java_MediaCodecBridge_flush(env, j_media_codec_.obj()));
+}
+
+void MediaCodecBridge::Stop() {
+ JNIEnv* env = AttachCurrentThread();
+ Java_MediaCodecBridge_stop(env, j_media_codec_.obj());
+}
+
+void MediaCodecBridge::GetOutputFormat(int* width, int* height) {
+ JNIEnv* env = AttachCurrentThread();
+
+ *width = Java_MediaCodecBridge_getOutputWidth(env, j_media_codec_.obj());
+ *height = Java_MediaCodecBridge_getOutputHeight(env, j_media_codec_.obj());
+}
+
+int MediaCodecBridge::GetOutputSamplingRate() {
+ JNIEnv* env = AttachCurrentThread();
+
+ return Java_MediaCodecBridge_getOutputSamplingRate(env, j_media_codec_.obj());
+}
+
+MediaCodecStatus MediaCodecBridge::QueueInputBuffer(
+ int index,
+ const uint8* data,
+ size_t data_size,
+ const base::TimeDelta& presentation_time) {
+ DVLOG(3) << __PRETTY_FUNCTION__ << index << ": " << data_size;
+ if (data_size >
+ base::checked_cast<size_t>(std::numeric_limits<int32_t>::max()))
+ return MEDIA_CODEC_ERROR;
+ if (data && !FillInputBuffer(index, data, data_size))
+ return MEDIA_CODEC_ERROR;
+ JNIEnv* env = AttachCurrentThread();
+ return static_cast<MediaCodecStatus>(
+ Java_MediaCodecBridge_queueInputBuffer(env,
+ j_media_codec_.obj(),
+ index,
+ 0,
+ data_size,
+ presentation_time.InMicroseconds(),
+ 0));
+}
MediaCodecStatus MediaCodecBridge::QueueSecureInputBuffer(
int index,
@@ -34,25 +351,205 @@ MediaCodecStatus MediaCodecBridge::QueueSecureInputBuffer(
const std::string& iv,
const std::vector<SubsampleEntry>& subsamples,
const base::TimeDelta& presentation_time) {
- const std::vector<char> key_vec(key_id.begin(), key_id.end());
- const std::vector<char> iv_vec(iv.begin(), iv.end());
- return QueueSecureInputBuffer(index, data, data_size, key_vec, iv_vec,
- subsamples.empty() ? nullptr : &subsamples[0],
- subsamples.size(), presentation_time);
+ return QueueSecureInputBuffer(
+ index, data, data_size, reinterpret_cast<const uint8_t*>(key_id.data()),
+ key_id.size(), reinterpret_cast<const uint8_t*>(iv.data()), iv.size(),
+ subsamples.empty() ? nullptr : &subsamples[0], subsamples.size(),
+ presentation_time);
+}
+
+// TODO(timav): Combine this and above methods together keeping only the first
+// interface after we switch to Spitzer pipeline.
+MediaCodecStatus MediaCodecBridge::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) {
+ DVLOG(3) << __PRETTY_FUNCTION__ << index << ": " << data_size;
+ if (data_size >
+ base::checked_cast<size_t>(std::numeric_limits<int32_t>::max()))
+ return MEDIA_CODEC_ERROR;
+ if (data && !FillInputBuffer(index, data, data_size))
+ return MEDIA_CODEC_ERROR;
+
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jbyteArray> j_key_id =
+ base::android::ToJavaByteArray(env, key_id, key_id_size);
+ ScopedJavaLocalRef<jbyteArray> j_iv =
+ base::android::ToJavaByteArray(env, iv, iv_size);
+
+ // MediaCodec.CryptoInfo documentations says passing NULL for |clear_array|
+ // to indicate that all data is encrypted. But it doesn't specify what
+ // |cypher_array| and |subsamples_size| should be in that case. Passing
+ // one subsample here just to be on the safe side.
+ int new_subsamples_size = subsamples_size == 0 ? 1 : subsamples_size;
+
+ scoped_ptr<jint[]> native_clear_array(new jint[new_subsamples_size]);
+ scoped_ptr<jint[]> native_cypher_array(new jint[new_subsamples_size]);
+
+ if (subsamples_size == 0) {
+ DCHECK(!subsamples);
+ native_clear_array[0] = 0;
+ native_cypher_array[0] = data_size;
+ } else {
+ DCHECK_GT(subsamples_size, 0);
+ DCHECK(subsamples);
+ for (int i = 0; i < subsamples_size; ++i) {
+ DCHECK(subsamples[i].clear_bytes <= std::numeric_limits<uint16>::max());
+ if (subsamples[i].cypher_bytes >
+ static_cast<uint32>(std::numeric_limits<jint>::max())) {
+ return MEDIA_CODEC_ERROR;
+ }
+
+ native_clear_array[i] = subsamples[i].clear_bytes;
+ native_cypher_array[i] = subsamples[i].cypher_bytes;
+ }
+ }
+
+ ScopedJavaLocalRef<jintArray> clear_array =
+ ToJavaIntArray(env, native_clear_array.Pass(), new_subsamples_size);
+ ScopedJavaLocalRef<jintArray> cypher_array =
+ ToJavaIntArray(env, native_cypher_array.Pass(), new_subsamples_size);
+
+ return static_cast<MediaCodecStatus>(
+ Java_MediaCodecBridge_queueSecureInputBuffer(
+ env,
+ j_media_codec_.obj(),
+ index,
+ 0,
+ j_iv.obj(),
+ j_key_id.obj(),
+ clear_array.obj(),
+ cypher_array.obj(),
+ new_subsamples_size,
+ presentation_time.InMicroseconds()));
+}
+
+void MediaCodecBridge::QueueEOS(int input_buffer_index) {
+ DVLOG(3) << __PRETTY_FUNCTION__ << ": " << input_buffer_index;
+ JNIEnv* env = AttachCurrentThread();
+ Java_MediaCodecBridge_queueInputBuffer(env,
+ j_media_codec_.obj(),
+ input_buffer_index,
+ 0,
+ 0,
+ 0,
+ kBufferFlagEndOfStream);
+}
+
+MediaCodecStatus MediaCodecBridge::DequeueInputBuffer(
+ const base::TimeDelta& timeout,
+ int* index) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> result = Java_MediaCodecBridge_dequeueInputBuffer(
+ env, j_media_codec_.obj(), timeout.InMicroseconds());
+ *index = Java_DequeueInputResult_index(env, result.obj());
+ MediaCodecStatus status = static_cast<MediaCodecStatus>(
+ Java_DequeueInputResult_status(env, result.obj()));
+ DVLOG(3) << __PRETTY_FUNCTION__ << ": status: " << status
+ << ", index: " << *index;
+ return status;
+}
+
+MediaCodecStatus MediaCodecBridge::DequeueOutputBuffer(
+ const base::TimeDelta& timeout,
+ int* index,
+ size_t* offset,
+ size_t* size,
+ base::TimeDelta* presentation_time,
+ bool* end_of_stream,
+ bool* key_frame) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> result =
+ Java_MediaCodecBridge_dequeueOutputBuffer(
+ env, j_media_codec_.obj(), timeout.InMicroseconds());
+ *index = Java_DequeueOutputResult_index(env, result.obj());
+ *offset = base::checked_cast<size_t>(
+ Java_DequeueOutputResult_offset(env, result.obj()));
+ *size = base::checked_cast<size_t>(
+ Java_DequeueOutputResult_numBytes(env, result.obj()));
+ if (presentation_time) {
+ *presentation_time = base::TimeDelta::FromMicroseconds(
+ Java_DequeueOutputResult_presentationTimeMicroseconds(env,
+ result.obj()));
+ }
+ int flags = Java_DequeueOutputResult_flags(env, result.obj());
+ if (end_of_stream)
+ *end_of_stream = flags & kBufferFlagEndOfStream;
+ if (key_frame)
+ *key_frame = flags & kBufferFlagSyncFrame;
+ MediaCodecStatus status = static_cast<MediaCodecStatus>(
+ Java_DequeueOutputResult_status(env, result.obj()));
+ DVLOG(3) << __PRETTY_FUNCTION__ << ": status: " << status
+ << ", index: " << *index << ", offset: " << *offset
+ << ", size: " << *size << ", flags: " << flags;
+ return status;
+}
+
+void MediaCodecBridge::ReleaseOutputBuffer(int index, bool render) {
+ DVLOG(3) << __PRETTY_FUNCTION__ << ": " << index;
+ JNIEnv* env = AttachCurrentThread();
+ CHECK(env);
+
+ Java_MediaCodecBridge_releaseOutputBuffer(
+ env, j_media_codec_.obj(), index, render);
}
int MediaCodecBridge::GetOutputBuffersCount() {
- return 0;
+ JNIEnv* env = AttachCurrentThread();
+ return Java_MediaCodecBridge_getOutputBuffersCount(env, j_media_codec_.obj());
}
size_t MediaCodecBridge::GetOutputBuffersCapacity() {
- return 0;
+ JNIEnv* env = AttachCurrentThread();
+ return Java_MediaCodecBridge_getOutputBuffersCapacity(env,
+ j_media_codec_.obj());
+}
+
+void MediaCodecBridge::GetInputBuffer(int input_buffer_index,
+ uint8** data,
+ size_t* capacity) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> j_buffer(Java_MediaCodecBridge_getInputBuffer(
+ env, j_media_codec_.obj(), input_buffer_index));
+ *data = static_cast<uint8*>(env->GetDirectBufferAddress(j_buffer.obj()));
+ *capacity = base::checked_cast<size_t>(
+ env->GetDirectBufferCapacity(j_buffer.obj()));
+}
+
+bool MediaCodecBridge::CopyFromOutputBuffer(int index,
+ size_t offset,
+ void* dst,
+ int dst_size) {
+ void* src_data = nullptr;
+ int src_capacity = GetOutputBufferAddress(index, offset, &src_data);
+ if (src_capacity < dst_size)
+ return false;
+ memcpy(dst, src_data, dst_size);
+ return true;
+}
+
+int MediaCodecBridge::GetOutputBufferAddress(int index,
+ size_t offset,
+ void** addr) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> j_buffer(
+ Java_MediaCodecBridge_getOutputBuffer(env, j_media_codec_.obj(), index));
+ *addr = reinterpret_cast<uint8*>(
+ env->GetDirectBufferAddress(j_buffer.obj())) + offset;
+ return env->GetDirectBufferCapacity(j_buffer.obj()) - offset;
}
bool MediaCodecBridge::FillInputBuffer(int index,
const uint8_t* data,
size_t size) {
- uint8_t* dst = nullptr;
+ uint8* dst = NULL;
size_t capacity = 0;
GetInputBuffer(index, &dst, &capacity);
CHECK(dst);
@@ -67,4 +564,334 @@ bool MediaCodecBridge::FillInputBuffer(int index,
return true;
}
+AudioCodecBridge::AudioCodecBridge(const std::string& mime)
+ // Audio codec doesn't care about security level and there is no need for
+ // audio encoding yet.
+ : MediaCodecBridge(mime, false, MEDIA_CODEC_DECODER) {}
+
+bool AudioCodecBridge::Start(const AudioCodec& codec,
+ int sample_rate,
+ int channel_count,
+ const uint8* extra_data,
+ size_t extra_data_size,
+ int64 codec_delay_ns,
+ int64 seek_preroll_ns,
+ bool play_audio,
+ jobject media_crypto) {
+ JNIEnv* env = AttachCurrentThread();
+
+ if (!media_codec())
+ return false;
+
+ std::string codec_string = AudioCodecToAndroidMimeType(codec);
+ if (codec_string.empty())
+ return false;
+
+ ScopedJavaLocalRef<jstring> j_mime =
+ ConvertUTF8ToJavaString(env, codec_string);
+ ScopedJavaLocalRef<jobject> j_format(Java_MediaCodecBridge_createAudioFormat(
+ env, j_mime.obj(), 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.obj(), media_crypto, 0, play_audio)) {
+ return false;
+ }
+
+ return StartInternal();
+}
+
+bool AudioCodecBridge::ConfigureMediaFormat(jobject j_format,
+ const AudioCodec& codec,
+ const uint8* extra_data,
+ size_t extra_data_size,
+ int64 codec_delay_ns,
+ int64 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* 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.obj());
+ // 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.obj());
+ 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 profile = 0;
+ uint8 frequency_index = 0;
+ uint8 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 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.obj());
+
+ // 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.obj());
+
+ // csd1 - Codec Delay
+ ScopedJavaLocalRef<jbyteArray> csd1 =
+ base::android::ToJavaByteArray(
+ env, reinterpret_cast<const uint8*>(&codec_delay_ns),
+ sizeof(int64_t));
+ Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 1, csd1.obj());
+
+ // csd2 - Seek Preroll
+ ScopedJavaLocalRef<jbyteArray> csd2 =
+ base::android::ToJavaByteArray(
+ env, reinterpret_cast<const uint8*>(&seek_preroll_ns),
+ sizeof(int64_t));
+ Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 2, csd2.obj());
+ break;
+ }
+ default:
+ LOG(ERROR) << "Invalid header encountered for codec: "
+ << AudioCodecToAndroidMimeType(codec);
+ return false;
+ }
+ return true;
+}
+
+int64 AudioCodecBridge::PlayOutputBuffer(int index,
+ size_t size,
+ size_t offset,
+ bool postpone) {
+ DCHECK_LE(0, index);
+ int numBytes = base::checked_cast<int>(size);
+
+ void* buffer = nullptr;
+ int capacity = GetOutputBufferAddress(index, offset, &buffer);
+ numBytes = std::min(capacity, numBytes);
+ CHECK_GE(numBytes, 0);
+
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jbyteArray> byte_array = base::android::ToJavaByteArray(
+ env, static_cast<uint8*>(buffer), numBytes);
+ return Java_MediaCodecBridge_playOutputBuffer(env, media_codec(),
+ byte_array.obj(), postpone);
+}
+
+void AudioCodecBridge::SetVolume(double volume) {
+ JNIEnv* env = AttachCurrentThread();
+ Java_MediaCodecBridge_setVolume(env, media_codec(), volume);
+}
+
+// static
+AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec& codec) {
+ if (!MediaCodecBridge::IsAvailable())
+ return NULL;
+
+ const std::string mime = AudioCodecToAndroidMimeType(codec);
+ return mime.empty() ? NULL : new AudioCodecBridge(mime);
+}
+
+// static
+bool AudioCodecBridge::IsKnownUnaccelerated(const AudioCodec& codec) {
+ return MediaCodecBridge::IsKnownUnaccelerated(
+ AudioCodecToAndroidMimeType(codec), MEDIA_CODEC_DECODER);
+}
+
+// static
+bool VideoCodecBridge::IsKnownUnaccelerated(const VideoCodec& codec,
+ MediaCodecDirection direction) {
+ return MediaCodecBridge::IsKnownUnaccelerated(
+ VideoCodecToAndroidMimeType(codec), direction);
+}
+
+// static
+VideoCodecBridge* VideoCodecBridge::CreateDecoder(const VideoCodec& codec,
+ bool is_secure,
+ const gfx::Size& size,
+ jobject surface,
+ jobject media_crypto) {
+ if (!MediaCodecBridge::IsAvailable())
+ return NULL;
+
+ const std::string mime = VideoCodecToAndroidMimeType(codec);
+ if (mime.empty())
+ return NULL;
+
+ scoped_ptr<VideoCodecBridge> bridge(
+ new VideoCodecBridge(mime, is_secure, MEDIA_CODEC_DECODER));
+ if (!bridge->media_codec())
+ return NULL;
+
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime);
+ ScopedJavaLocalRef<jobject> j_format(
+ Java_MediaCodecBridge_createVideoDecoderFormat(
+ env, j_mime.obj(), size.width(), size.height()));
+ DCHECK(!j_format.is_null());
+ if (!Java_MediaCodecBridge_configureVideo(env,
+ bridge->media_codec(),
+ j_format.obj(),
+ surface,
+ media_crypto,
+ 0)) {
+ return NULL;
+ }
+
+ return bridge->StartInternal() ? bridge.release() : NULL;
+}
+
+// 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 (!MediaCodecBridge::IsAvailable())
+ return NULL;
+
+ const std::string mime = VideoCodecToAndroidMimeType(codec);
+ if (mime.empty())
+ return NULL;
+
+ scoped_ptr<VideoCodecBridge> bridge(
+ new VideoCodecBridge(mime, false, MEDIA_CODEC_ENCODER));
+ if (!bridge->media_codec())
+ return NULL;
+
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime);
+ ScopedJavaLocalRef<jobject> j_format(
+ Java_MediaCodecBridge_createVideoEncoderFormat(env,
+ j_mime.obj(),
+ 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.obj(),
+ NULL,
+ NULL,
+ kConfigureFlagEncode)) {
+ return NULL;
+ }
+
+ return bridge->StartInternal() ? bridge.release() : NULL;
+}
+
+VideoCodecBridge::VideoCodecBridge(const std::string& mime,
+ bool is_secure,
+ MediaCodecDirection direction)
+ : MediaCodecBridge(mime, is_secure, direction),
+ adaptive_playback_supported_for_testing_(-1) {}
+
+void VideoCodecBridge::SetVideoBitrate(int bps) {
+ JNIEnv* env = AttachCurrentThread();
+ Java_MediaCodecBridge_setVideoBitrate(env, media_codec(), bps);
+}
+
+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);
+}
+
+bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
} // namespace media
diff --git a/media/base/android/media_codec_bridge.h b/media/base/android/media_codec_bridge.h
index 02a29f9..45361c88b 100644
--- a/media/base/android/media_codec_bridge.h
+++ b/media/base/android/media_codec_bridge.h
@@ -5,16 +5,15 @@
#ifndef MEDIA_BASE_ANDROID_MEDIA_CODEC_BRIDGE_H_
#define MEDIA_BASE_ANDROID_MEDIA_CODEC_BRIDGE_H_
-#include <stdint.h>
-
+#include <jni.h>
#include <set>
#include <string>
-#include <vector>
-#include "base/compiler_specific.h"
+#include "base/android/scoped_java_ref.h"
#include "base/time/time.h"
-#include "media/base/android/media_codec_util.h"
-#include "media/base/media_export.h"
+#include "media/base/audio_decoder_config.h"
+#include "media/base/video_decoder_config.h"
+#include "ui/gfx/geometry/size.h"
namespace media {
@@ -35,12 +34,59 @@ enum MediaCodecStatus {
MEDIA_CODEC_ERROR
};
-// Interface for wrapping different Android MediaCodec implementations. For
-// more information on Android MediaCodec, check
+// Codec direction. Keep this in sync with MediaCodecBridge.java.
+enum MediaCodecDirection {
+ MEDIA_CODEC_DECODER,
+ MEDIA_CODEC_ENCODER,
+};
+
+// This class serves as a bridge for native code to call java functions inside
+// Android MediaCodec class. For more information on Android MediaCodec, check
// http://developer.android.com/reference/android/media/MediaCodec.html
// Note: MediaCodec is only available on JB and greater.
+// Use AudioCodecBridge or VideoCodecBridge to create an instance of this
+// object.
+//
+// TODO(fischman,xhwang): replace this (and the enums that go with it) with
+// chromium's JNI auto-generation hotness.
class MEDIA_EXPORT MediaCodecBridge {
public:
+ // Returns true if MediaCodec is available on the device.
+ // All other static methods check IsAvailable() internally. There's no need
+ // to check IsAvailable() explicitly before calling them.
+ static bool IsAvailable();
+
+ // Returns true if MediaCodec.setParameters() is available on the device.
+ static bool SupportsSetParameters();
+
+ // Returns true if MediaCodec.getName() is available on the device.
+ static bool SupportsGetName();
+
+ // Returns whether MediaCodecBridge has a decoder that |is_secure| and can
+ // decode |codec| type.
+ static bool CanDecode(const std::string& codec, bool is_secure);
+
+ // Represents supported codecs on android.
+ // TODO(qinmin): Currently the codecs string only contains one codec. Do we
+ // need to support codecs separated by comma. (e.g. "vp8" -> "vp8, vp8.0")?
+ struct CodecsInfo {
+ std::string codecs; // E.g. "vp8" or "avc1".
+ std::string name; // E.g. "OMX.google.vp8.decoder".
+ MediaCodecDirection direction;
+ };
+
+ // Get a list of supported codecs.
+ static std::vector<CodecsInfo> GetCodecsInfo();
+
+ // Get default codec name for |mime_type|.
+ static std::string GetDefaultCodecName(const std::string& mime_type,
+ MediaCodecDirection direction);
+
+ // Get a list of encoder supported color formats for |mime_type|.
+ // The mapping of color format name and its value refers to
+ // MediaCodecInfo.CodecCapabilities.
+ static std::set<int> GetEncoderColorFormats(const std::string& mime_type);
+
virtual ~MediaCodecBridge();
// Resets both input and output, all indices previously returned in calls to
@@ -49,36 +95,31 @@ class MEDIA_EXPORT MediaCodecBridge {
// words, there will be no outputs until new input is provided.
// Returns MEDIA_CODEC_ERROR if an unexpected error happens, or Media_CODEC_OK
// otherwise.
- virtual MediaCodecStatus Reset() = 0;
-
- // Calls start() against the media codec instance. Returns whether media
- // codec was successfully started.
- virtual bool Start() = 0;
+ MediaCodecStatus Reset();
// Finishes the decode/encode session. The instance remains active
// and ready to be StartAudio/Video()ed again. HOWEVER, due to the buggy
// vendor's implementation , b/8125974, Stop() -> StartAudio/Video() may not
// work on some devices. For reliability, Stop() -> delete and recreate new
// instance -> StartAudio/Video() is recommended.
- virtual void Stop() = 0;
+ void Stop();
// Used for getting output format. This is valid after DequeueInputBuffer()
// returns a format change by returning INFO_OUTPUT_FORMAT_CHANGED
- virtual void GetOutputFormat(int* width, int* height) = 0;
+ void GetOutputFormat(int* width, int* height);
// Used for checking for new sampling rate after DequeueInputBuffer() returns
// INFO_OUTPUT_FORMAT_CHANGED
- virtual int GetOutputSamplingRate() = 0;
+ int GetOutputSamplingRate();
// Submits a byte array to the given input buffer. Call this after getting an
- // available buffer from DequeueInputBuffer(). If |data| is NULL, assume the
+ // available buffer from DequeueInputBuffer(). If |data| is NULL, assume the
// input buffer has already been populated (but still obey |size|).
// |data_size| must be less than kint32max (because Java).
- virtual MediaCodecStatus QueueInputBuffer(
- int index,
- const uint8_t* data,
- size_t data_size,
- const base::TimeDelta& presentation_time) = 0;
+ MediaCodecStatus QueueInputBuffer(int index,
+ const uint8* data,
+ size_t data_size,
+ const base::TimeDelta& presentation_time);
// Similar to the above call, but submits a buffer that is encrypted. Note:
// NULL |subsamples| indicates the whole buffer is encrypted. If |data| is
@@ -97,18 +138,20 @@ class MEDIA_EXPORT MediaCodecBridge {
// and MediaCodecPlayer.
// TODO(timav): remove this method and keep only the one above after we
// switch to the Spitzer pipeline.
- virtual MediaCodecStatus QueueSecureInputBuffer(
+ MediaCodecStatus QueueSecureInputBuffer(
int index,
const uint8_t* data,
size_t data_size,
- const std::vector<char>& key_id,
- const std::vector<char>& iv,
+ 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) = 0;
+ const base::TimeDelta& presentation_time);
// Submits an empty buffer with a EOS (END OF STREAM) flag.
- virtual void QueueEOS(int input_buffer_index) = 0;
+ void QueueEOS(int input_buffer_index);
// Returns:
// MEDIA_CODEC_OK if an input buffer is ready to be filled with valid data,
@@ -116,8 +159,8 @@ class MEDIA_EXPORT MediaCodecBridge {
// MEDIA_CODEC_ERROR if unexpected error happens.
// Note: Never use infinite timeout as this would block the decoder thread and
// prevent the decoder job from being released.
- virtual MediaCodecStatus DequeueInputBuffer(const base::TimeDelta& timeout,
- int* index) = 0;
+ MediaCodecStatus DequeueInputBuffer(const base::TimeDelta& timeout,
+ int* index);
// Dequeues an output buffer, block at most timeout_us microseconds.
// Returns the status of this operation. If OK is returned, the output
@@ -128,51 +171,159 @@ class MEDIA_EXPORT MediaCodecBridge {
// prevent the decoder job from being released.
// TODO(xhwang): Can we drop |end_of_stream| and return
// MEDIA_CODEC_OUTPUT_END_OF_STREAM?
- virtual MediaCodecStatus DequeueOutputBuffer(
- const base::TimeDelta& timeout,
- int* index,
- size_t* offset,
- size_t* size,
- base::TimeDelta* presentation_time,
- bool* end_of_stream,
- bool* key_frame) = 0;
+ MediaCodecStatus DequeueOutputBuffer(const base::TimeDelta& timeout,
+ int* index,
+ size_t* offset,
+ size_t* size,
+ base::TimeDelta* presentation_time,
+ bool* end_of_stream,
+ bool* key_frame);
// Returns the buffer to the codec. If you previously specified a surface when
// configuring this video decoder you can optionally render the buffer.
- virtual void ReleaseOutputBuffer(int index, bool render) = 0;
+ void ReleaseOutputBuffer(int index, bool render);
// Returns the number of output buffers used by the codec.
// TODO(qinmin): this call is deprecated in Lollipop.
- virtual int GetOutputBuffersCount();
+ int GetOutputBuffersCount();
// Returns the capacity of each output buffer used by the codec.
// TODO(qinmin): this call is deprecated in Lollipop.
- virtual size_t GetOutputBuffersCapacity();
+ size_t GetOutputBuffersCapacity();
// Returns an input buffer's base pointer and capacity.
- virtual void GetInputBuffer(int input_buffer_index,
- uint8_t** data,
- size_t* capacity) = 0;
+ void GetInputBuffer(int input_buffer_index, uint8** data, size_t* capacity);
// Copy |dst_size| bytes from output buffer |index|'s |offset| onwards into
// |*dst|.
- virtual bool CopyFromOutputBuffer(int index,
- size_t offset,
- void* dst,
- int dst_size) = 0;
+ bool CopyFromOutputBuffer(int index, size_t offset, void* dst, int dst_size);
+
+ static bool RegisterMediaCodecBridge(JNIEnv* env);
protected:
- MediaCodecBridge();
+ // Returns true if |mime_type| is known to be unaccelerated (i.e. backed by a
+ // software codec instead of a hardware one).
+ static bool IsKnownUnaccelerated(const std::string& mime_type,
+ MediaCodecDirection direction);
+
+ MediaCodecBridge(const std::string& mime,
+ bool is_secure,
+ MediaCodecDirection direction);
+
+ // Calls start() against the media codec instance. Used in StartXXX() after
+ // configuring media codec. Returns whether media codec was successfully
+ // started.
+ bool StartInternal() WARN_UNUSED_RESULT;
+
+ // Called to get the buffer address given the output buffer index and offset.
+ // This function returns the size of the output and |addr| is the pointer to
+ // the address to read.
+ int GetOutputBufferAddress(int index, size_t offset, void** addr);
+ jobject media_codec() { return j_media_codec_.obj(); }
+ MediaCodecDirection direction_;
+
+ private:
// Fills a particular input buffer; returns false if |data_size| exceeds the
// input buffer's capacity (and doesn't touch the input buffer in that case).
bool FillInputBuffer(int index,
const uint8_t* data,
size_t data_size) WARN_UNUSED_RESULT;
+ // Java MediaCodec instance.
+ base::android::ScopedJavaGlobalRef<jobject> j_media_codec_;
+
DISALLOW_COPY_AND_ASSIGN(MediaCodecBridge);
};
+class AudioCodecBridge : public MediaCodecBridge {
+ public:
+ // Returns an AudioCodecBridge instance if |codec| is supported, or a NULL
+ // pointer otherwise.
+ static AudioCodecBridge* Create(const AudioCodec& codec);
+
+ // See MediaCodecBridge::IsKnownUnaccelerated().
+ static bool IsKnownUnaccelerated(const AudioCodec& codec);
+
+ // Start the audio codec bridge.
+ bool Start(const AudioCodec& codec, int sample_rate, int channel_count,
+ const uint8* extra_data, size_t extra_data_size,
+ int64 codec_delay_ns, int64 seek_preroll_ns,
+ bool play_audio, jobject media_crypto) WARN_UNUSED_RESULT;
+
+ // Plays the output buffer right away or save for later playback if |postpone|
+ // is set to true. This call must be called after DequeueOutputBuffer() and
+ // before ReleaseOutputBuffer. The data is extracted from the output buffers
+ // using |index|, |size| and |offset|. Returns the playback head position
+ // expressed in frames.
+ // When |postpone| is set to true, the next PlayOutputBuffer() should have
+ // postpone == false, and it will play two buffers: the postponed one and
+ // the one identified by |index|.
+ int64 PlayOutputBuffer(int index,
+ size_t size,
+ size_t offset,
+ bool postpone = false);
+
+ // Set the volume of the audio output.
+ void SetVolume(double volume);
+
+ private:
+ explicit AudioCodecBridge(const std::string& mime);
+
+ // Configure the java MediaFormat object with the extra codec data passed in.
+ bool ConfigureMediaFormat(jobject j_format, const AudioCodec& codec,
+ const uint8* extra_data, size_t extra_data_size,
+ int64 codec_delay_ns, int64 seek_preroll_ns);
+};
+
+class MEDIA_EXPORT VideoCodecBridge : public MediaCodecBridge {
+ public:
+ // See MediaCodecBridge::IsKnownUnaccelerated().
+ static bool IsKnownUnaccelerated(const VideoCodec& codec,
+ MediaCodecDirection direction);
+
+ // Create, start, and return a VideoCodecBridge decoder or NULL on failure.
+ static VideoCodecBridge* CreateDecoder(
+ const VideoCodec& codec, // e.g. media::kCodecVP8
+ bool is_secure,
+ const gfx::Size& size, // Output frame size.
+ jobject surface, // Output surface, optional.
+ jobject media_crypto); // MediaCrypto object, optional.
+
+ // Create, start, and return a VideoCodecBridge encoder or NULL on failure.
+ static VideoCodecBridge* CreateEncoder(
+ const VideoCodec& codec, // e.g. media::kCodecVP8
+ const gfx::Size& size, // input frame size
+ int bit_rate, // bits/second
+ int frame_rate, // frames/second
+ int i_frame_interval, // count
+ int color_format); // MediaCodecInfo.CodecCapabilities.
+
+ void SetVideoBitrate(int bps);
+ void RequestKeyFrameSoon();
+
+ // Returns whether adaptive playback is supported for this object given
+ // the new size.
+ bool IsAdaptivePlaybackSupported(int width, int height);
+
+ // Test-only method to set the return value of IsAdaptivePlaybackSupported().
+ // Without this function, the return value of that function will be device
+ // dependent. If |adaptive_playback_supported| is equal to 0, the return value
+ // will be false. If |adaptive_playback_supported| is larger than 0, the
+ // return value will be true.
+ void set_adaptive_playback_supported_for_testing(
+ int adaptive_playback_supported) {
+ adaptive_playback_supported_for_testing_ = adaptive_playback_supported;
+ }
+
+ private:
+ VideoCodecBridge(const std::string& mime,
+ bool is_secure,
+ MediaCodecDirection direction);
+
+ int adaptive_playback_supported_for_testing_;
+};
+
} // namespace media
#endif // MEDIA_BASE_ANDROID_MEDIA_CODEC_BRIDGE_H_
diff --git a/media/base/android/media_codec_bridge_unittest.cc b/media/base/android/media_codec_bridge_unittest.cc
new file mode 100644
index 0000000..f1c0471
--- /dev/null
+++ b/media/base/android/media_codec_bridge_unittest.cc
@@ -0,0 +1,319 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "media/base/android/media_codec_bridge.h"
+#include "media/base/decoder_buffer.h"
+#include "media/base/test_data_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace {
+
+// The first frame of
+// http://www.html5rocks.com/en/tutorials/audio/quick/test.mp3
+unsigned char test_mp3[] = {
+ 0xff, 0xfb, 0xd2, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x05, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0d, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x7e, 0x40,
+ 0xc0, 0x19, 0x4a, 0x80, 0x0d, 0x60, 0x48, 0x1b, 0x40, 0xf7, 0xbd, 0xb9,
+ 0xd9, 0x40, 0x6f, 0x82, 0x01, 0x8b, 0x17, 0xa0, 0x80, 0xc5, 0x01, 0xad,
+ 0x9a, 0xd3, 0x00, 0x12, 0xc0, 0x72, 0x93, 0x67, 0xd0, 0x03, 0x6f, 0xa4,
+ 0xc0, 0xc3, 0x23, 0xee, 0x9b, 0xc0, 0xcc, 0x02, 0xa0, 0xa1, 0x30, 0x0c,
+ 0x52, 0x2d, 0xfd, 0x6e, 0x08, 0x83, 0x60, 0x40, 0x46, 0x06, 0x4b, 0x20,
+ 0x82, 0x82, 0x7f, 0xd4, 0x81, 0xe7, 0x00, 0x64, 0x20, 0x18, 0xec, 0xc2,
+ 0x06, 0x57, 0x0f, 0x81, 0x93, 0x0b, 0x00, 0x66, 0xe3, 0xb7, 0xe8, 0x32,
+ 0x6e, 0xf0, 0x32, 0xb0, 0x58, 0x0c, 0x7c, 0x3a, 0x03, 0x22, 0x14, 0x80,
+ 0xc9, 0x01, 0x80, 0x30, 0x20, 0x14, 0x0c, 0x96, 0x73, 0xfe, 0x9f, 0x6c,
+ 0x0c, 0xd2, 0x25, 0x0f, 0xdc, 0x0c, 0x32, 0x43, 0x03, 0x27, 0x87, 0xc0,
+ 0xc2, 0xc0, 0x20, 0xfc, 0x42, 0xc5, 0xff, 0xff, 0xd4, 0x80, 0x01, 0x01,
+ 0x80, 0xc3, 0x81, 0x01, 0x95, 0x03, 0x28, 0x82, 0xc0, 0xc3, 0x01, 0xa1,
+ 0x06, 0x81, 0x87, 0xc2, 0x40, 0x64, 0xc1, 0xf0, 0x12, 0x02, 0xff, 0xf6,
+ 0x5b, 0x9f, 0x44, 0xdc, 0xdd, 0x0b, 0x38, 0x59, 0xe0, 0x31, 0x71, 0x60,
+ 0x0c, 0xb4, 0x22, 0x03, 0x3b, 0x96, 0x40, 0xc8, 0x63, 0x90, 0x0a, 0x23,
+ 0x81, 0x9e, 0x4c, 0x20, 0x65, 0xb3, 0x18, 0x19, 0x6c, 0x42, 0x06, 0x36,
+ 0x1d, 0x01, 0x90, 0x87, 0xdf, 0xff, 0xd0, 0x65, 0xa6, 0xea, 0x66, 0xfd,
+ 0x40, 0x0c, 0x48, 0x03, 0x1a, 0x09, 0x01, 0x21, 0x98, 0x19, 0x2c, 0x36,
+ 0x06, 0x43, 0x21, 0x81, 0x92, 0xca, 0x60, 0x64, 0x70, 0xb8, 0x19, 0x20,
+ 0x6c, 0x02, 0x83, 0x80, 0xcb, 0x60, 0x65, 0x32, 0x28, 0x18, 0x64, 0x24,
+ 0x06, 0x3a, 0x0c, 0x00, 0xe1, 0x00, 0x18, 0xd0, 0x35, 0xff, 0xff, 0xff,
+ 0xe8, 0x32, 0xef, 0xb2, 0x90, 0x65, 0xbb, 0xdd, 0x94, 0x82, 0x0b, 0x4c,
+ 0xfa, 0x25, 0xf3, 0x74, 0x13, 0x0f, 0xf8, 0x19, 0x28, 0x84, 0x06, 0x36,
+ 0x11, 0x01, 0x20, 0x80, 0x18, 0xb4, 0x52, 0x0e, 0x15, 0x00, 0x30, 0x50,
+ 0x0c, 0x84, 0x32, 0x03, 0x11, 0x04, 0x03, 0x48, 0x04, 0x00, 0x00, 0x31,
+ 0x21, 0x00, 0x0c, 0x84, 0x18, 0x03, 0x07, 0x85, 0x40, 0xc6, 0xa5, 0x70,
+ 0x32, 0xb8, 0x7c, 0x0c, 0x54, 0x04, 0x00, 0xd0, 0x08, 0x59, 0x58, 0x18,
+ 0x20, 0x14, 0x06, 0x30, 0x30, 0x01, 0x9b, 0x86, 0x00, 0x6b, 0x54, 0xa8,
+ 0x19, 0x8c, 0x2a, 0x06, 0x16, 0x09, 0x01, 0xa0, 0xd0, 0xa0, 0x69, 0x74,
+ 0xb8, 0x19, 0xc4, 0x4a, 0xa3, 0xda, 0x9d, 0x1e, 0x4f, 0x05, 0xc0, 0x5b,
+ 0x0b, 0x03, 0xc2, 0x76, 0xa3, 0x4f, 0xb9, 0x16, 0xc2, 0x70, 0x41, 0x07,
+ 0xa0, 0x84, 0x16, 0x38, 0x4a, 0xc8, 0xaf, 0xee, 0x7f, 0x93, 0xb5, 0x5c,
+ 0x39, 0x1e, 0x29, 0xd9, 0x8c, 0x80, 0xb5, 0x80, 0xe6, 0x85, 0xb2, 0x99,
+ 0x68, 0x85, 0x46, 0x91, 0x60, 0xdb, 0x06, 0xfa, 0x38, 0x7a, 0xc7, 0xac,
+ 0x85, 0xa8, 0xd3, 0xe6, 0x99, 0x3b, 0x66, 0x43, 0x23, 0x1f, 0x84, 0xe1,
+ 0x65, 0x5e, 0xbc, 0x84, 0x18, 0x62, 0xe6, 0x42, 0x0b, 0x82, 0xe4, 0xd3,
+ 0x42, 0xd2, 0x05, 0x81, 0x4e, 0xe4, 0x9f, 0x8c, 0xc8, 0x7f, 0xa3, 0xe0,
+ 0x8d, 0xf1, 0x0f, 0x38, 0xe5, 0x3f, 0xc4, 0x2c, 0x24, 0x65, 0x8d, 0xb9,
+ 0x58, 0xac, 0x39, 0x0e, 0x37, 0x99, 0x2e, 0x85, 0xe0, 0xb7, 0x98, 0x41,
+ 0x20, 0x38, 0x1b, 0x95, 0x07, 0xfa, 0xa8, 0x9c, 0x21, 0x0f, 0x13, 0x8c,
+ 0xa5, 0xc1, 0x76, 0xae, 0x0b, 0xc1, 0x30, 0x27, 0x08, 0xc1, 0xf6, 0x4d,
+ 0xce, 0xb4, 0x41, 0x38, 0x1e, 0x82, 0x10, 0x74, 0x45, 0x91, 0x90, 0xff,
+ 0x41, 0x8b, 0x62, 0x1a, 0x71, 0xb6, 0x45, 0x63, 0x8c, 0xce, 0xb8, 0x54,
+ 0x1b, 0xe8, 0x5d, 0x9e, 0x35, 0x9d, 0x6c, 0xac, 0xe8, 0x83, 0xa1, 0xe9,
+ 0x3f, 0x13, 0x74, 0x11, 0x04, 0x10, 0xf1, 0x37, 0x38, 0xc6, 0x00, 0x60,
+ 0x27, 0x48, 0x38, 0x85, 0x92, 0x76, 0xb7, 0xf3, 0xa7, 0x1c, 0x4b, 0xf9,
+ 0x3b, 0x5a, 0x88, 0xac, 0x60, 0x1b, 0x85, 0x81, 0x16, 0xab, 0x44, 0x17,
+ 0x08, 0x2e, 0x0f, 0xd4, 0xe2, 0xde, 0x49, 0xc9, 0xe1, 0xc0, 0xc0, 0xa0,
+ 0x7e, 0x73, 0xa1, 0x67, 0xf8, 0xf5, 0x9f, 0xc4, 0x21, 0x50, 0x4f, 0x05,
+ 0x2c, 0xfc, 0x5c, 0xaa, 0x85, 0xb0, 0xfa, 0x67, 0x80, 0x7e, 0x0f, 0xfd,
+ 0x92, 0x30, 0xd5, 0xa0, 0xd4, 0x05, 0xdd, 0x06, 0x68, 0x1d, 0x6e, 0x4e,
+ 0x8b, 0x79, 0xd6, 0xfc, 0xff, 0x2e, 0x6e, 0x7c, 0xba, 0x03, 0x90, 0xd4,
+ 0x25, 0x65, 0x8e, 0xe7, 0x3a, 0xd1, 0xd6, 0xdc, 0xf0, 0xbe, 0x12, 0xc4,
+ 0x31, 0x08, 0x16, 0x70, 0x31, 0x85, 0x61, 0x38, 0x27, 0x0a, 0x91, 0x5f,
+ 0x03, 0x38, 0xeb, 0x37, 0x13, 0x48, 0x41, 0xbe, 0x7f, 0x04, 0x70, 0x62,
+ 0x2b, 0x15, 0x91, 0x67, 0x63, 0x4f, 0xad, 0xa7, 0x1d, 0x3f, 0x44, 0x17,
+ 0x02, 0x08, 0x0d, 0xf2, 0xfc, 0x03, 0xa0, 0x74, 0x21, 0x8b, 0x07, 0x3a,
+ 0x8d, 0x0f, 0x54, 0x58, 0x94, 0x12, 0xc5, 0x62, 0x18, 0xb9, 0x42, 0xf0,
+ 0x6c, 0x73, 0xa0, 0x92, 0xad, 0x27, 0x1c, 0x20, 0x0f, 0xc1, 0xca, 0x44,
+ 0x87, 0x47, 0xc5, 0x43, 0x23, 0x01, 0xda, 0x23, 0xe2, 0x89, 0x38, 0x9f,
+ 0x1f, 0x8d, 0x8c, 0xc6, 0x95, 0xa3, 0x34, 0x21, 0x21, 0x2d, 0x49, 0xea,
+ 0x4b, 0x05, 0x85, 0xf5, 0x58, 0x25, 0x13, 0xcd, 0x51, 0x19, 0x1a, 0x88,
+ 0xa6, 0x83, 0xd6, 0xd0, 0xbc, 0x25, 0x19, 0x1c, 0x92, 0x12, 0x44, 0x5d,
+ 0x1c, 0x04, 0xf1, 0x99, 0xdf, 0x92, 0x8e, 0x09, 0x85, 0xf3, 0x88, 0x82,
+ 0x4c, 0x22, 0x17, 0xc5, 0x25, 0x23, 0xed, 0x78, 0xf5, 0x41, 0xd1, 0xe9,
+ 0x8a, 0xb3, 0x52, 0xd1, 0x3d, 0x79, 0x81, 0x4d, 0x31, 0x24, 0xf9, 0x38,
+ 0x96, 0xbc, 0xf4, 0x8c, 0x25, 0xe9, 0xf2, 0x73, 0x94, 0x85, 0xc2, 0x61,
+ 0x6a, 0x34, 0x68, 0x65, 0x78, 0x87, 0xa6, 0x4f
+};
+
+} // namespace
+
+namespace media {
+
+// Helper macro to skip the test if MediaCodecBridge isn't available.
+#define SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE() \
+ do { \
+ if (!MediaCodecBridge::IsAvailable()) { \
+ VLOG(0) << "Could not run test - not supported on device."; \
+ return; \
+ } \
+ } while (0)
+
+static const int kPresentationTimeBase = 100;
+
+static inline const base::TimeDelta InfiniteTimeOut() {
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
+void DecodeMediaFrame(
+ VideoCodecBridge* media_codec, const uint8* data, size_t data_size,
+ const base::TimeDelta input_presentation_timestamp,
+ const base::TimeDelta initial_timestamp_lower_bound) {
+ base::TimeDelta input_pts = input_presentation_timestamp;
+ base::TimeDelta timestamp = initial_timestamp_lower_bound;
+ base::TimeDelta new_timestamp;
+ for (int i = 0; i < 10; ++i) {
+ int input_buf_index = -1;
+ MediaCodecStatus status =
+ media_codec->DequeueInputBuffer(InfiniteTimeOut(), &input_buf_index);
+ ASSERT_EQ(MEDIA_CODEC_OK, status);
+
+ media_codec->QueueInputBuffer(
+ input_buf_index, data, data_size, input_presentation_timestamp);
+
+ size_t unused_offset = 0;
+ size_t size = 0;
+ bool eos = false;
+ int output_buf_index = -1;
+ status = media_codec->DequeueOutputBuffer(InfiniteTimeOut(),
+ &output_buf_index,
+ &unused_offset,
+ &size,
+ &new_timestamp,
+ &eos,
+ NULL);
+
+ if (status == MEDIA_CODEC_OK && output_buf_index > 0) {
+ media_codec->ReleaseOutputBuffer(output_buf_index, false);
+ }
+ // Output time stamp should not be smaller than old timestamp.
+ ASSERT_TRUE(new_timestamp >= timestamp);
+ input_pts += base::TimeDelta::FromMicroseconds(33000);
+ timestamp = new_timestamp;
+ }
+}
+
+TEST(MediaCodecBridgeTest, Initialize) {
+ SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+ scoped_ptr<media::MediaCodecBridge> media_codec;
+ media_codec.reset(VideoCodecBridge::CreateDecoder(
+ kCodecH264, false, gfx::Size(640, 480), NULL, NULL));
+}
+
+TEST(MediaCodecBridgeTest, DoNormal) {
+ SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+ scoped_ptr<media::AudioCodecBridge> media_codec;
+ media_codec.reset(AudioCodecBridge::Create(kCodecMP3));
+
+ ASSERT_TRUE(media_codec->Start(
+ kCodecMP3, 44100, 2, NULL, 0, 0, 0, false, NULL));
+
+ int input_buf_index = -1;
+ MediaCodecStatus status =
+ media_codec->DequeueInputBuffer(InfiniteTimeOut(), &input_buf_index);
+ ASSERT_EQ(MEDIA_CODEC_OK, status);
+ ASSERT_GE(input_buf_index, 0);
+
+ int64 input_pts = kPresentationTimeBase;
+ media_codec->QueueInputBuffer(input_buf_index,
+ test_mp3,
+ sizeof(test_mp3),
+ base::TimeDelta::FromMicroseconds(++input_pts));
+
+ status = media_codec->DequeueInputBuffer(InfiniteTimeOut(), &input_buf_index);
+ media_codec->QueueInputBuffer(
+ input_buf_index, test_mp3, sizeof(test_mp3),
+ base::TimeDelta::FromMicroseconds(++input_pts));
+
+ status = media_codec->DequeueInputBuffer(InfiniteTimeOut(), &input_buf_index);
+ media_codec->QueueEOS(input_buf_index);
+
+ input_pts = kPresentationTimeBase;
+ bool eos = false;
+ while (!eos) {
+ size_t unused_offset = 0;
+ size_t size = 0;
+ base::TimeDelta timestamp;
+ int output_buf_index = -1;
+ status = media_codec->DequeueOutputBuffer(InfiniteTimeOut(),
+ &output_buf_index,
+ &unused_offset,
+ &size,
+ &timestamp,
+ &eos,
+ NULL);
+ switch (status) {
+ case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
+ FAIL();
+ return;
+
+ case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
+ continue;
+
+ case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED:
+ continue;
+
+ default:
+ break;
+ }
+ ASSERT_GE(output_buf_index, 0);
+ EXPECT_LE(1u, size);
+ if (!eos)
+ EXPECT_EQ(++input_pts, timestamp.InMicroseconds());
+ ASSERT_LE(input_pts, kPresentationTimeBase + 2);
+ }
+ ASSERT_EQ(input_pts, kPresentationTimeBase + 2);
+}
+
+TEST(MediaCodecBridgeTest, InvalidVorbisHeader) {
+ SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+ scoped_ptr<media::AudioCodecBridge> media_codec;
+ media_codec.reset(AudioCodecBridge::Create(kCodecVorbis));
+
+ // The first byte of the header is not 0x02.
+ uint8 invalid_first_byte[] = { 0x00, 0xff, 0xff, 0xff, 0xff };
+ EXPECT_FALSE(media_codec->Start(
+ kCodecVorbis, 44100, 2, invalid_first_byte, sizeof(invalid_first_byte),
+ 0, 0, false, NULL));
+
+ // Size of the header does not match with the data we passed in.
+ uint8 invalid_size[] = { 0x02, 0x01, 0xff, 0x01, 0xff };
+ EXPECT_FALSE(media_codec->Start(
+ kCodecVorbis, 44100, 2, invalid_size, sizeof(invalid_size),
+ 0, 0, false, NULL));
+
+ // Size of the header is too large.
+ size_t large_size = 8 * 1024 * 1024 + 2;
+ uint8* very_large_header = new uint8[large_size];
+ very_large_header[0] = 0x02;
+ for (size_t i = 1; i < large_size - 1; ++i)
+ very_large_header[i] = 0xff;
+ very_large_header[large_size - 1] = 0xfe;
+ EXPECT_FALSE(media_codec->Start(
+ kCodecVorbis, 44100, 2, very_large_header, 0x80000000,
+ 0, 0, false, NULL));
+ delete[] very_large_header;
+}
+
+TEST(MediaCodecBridgeTest, InvalidOpusHeader) {
+ SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+ scoped_ptr<media::AudioCodecBridge> media_codec;
+ media_codec.reset(AudioCodecBridge::Create(kCodecOpus));
+ uint8 dummy_extra_data[] = { 0, 0 };
+
+ // Extra Data is NULL.
+ EXPECT_FALSE(media_codec->Start(
+ kCodecOpus, 48000, 2, NULL, 0, -1, 0, false, NULL));
+
+ // Codec Delay is < 0.
+ EXPECT_FALSE(media_codec->Start(
+ kCodecOpus, 48000, 2, dummy_extra_data, sizeof(dummy_extra_data),
+ -1, 0, false, NULL));
+
+ // Seek Preroll is < 0.
+ EXPECT_FALSE(media_codec->Start(
+ kCodecOpus, 48000, 2, dummy_extra_data, sizeof(dummy_extra_data),
+ 0, -1, false, NULL));
+}
+
+TEST(MediaCodecBridgeTest, PresentationTimestampsDoNotDecrease) {
+ SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+ scoped_ptr<VideoCodecBridge> media_codec(VideoCodecBridge::CreateDecoder(
+ kCodecVP8, false, gfx::Size(320, 240), NULL, NULL));
+ EXPECT_TRUE(media_codec.get());
+ scoped_refptr<DecoderBuffer> buffer =
+ ReadTestDataFile("vp8-I-frame-320x240");
+ DecodeMediaFrame(media_codec.get(),
+ buffer->data(),
+ buffer->data_size(),
+ base::TimeDelta(),
+ base::TimeDelta());
+
+ // Simulate a seek to 10 seconds, and each chunk has 2 I-frames.
+ std::vector<uint8> chunk(buffer->data(),
+ buffer->data() + buffer->data_size());
+ chunk.insert(chunk.end(), buffer->data(),
+ buffer->data() + buffer->data_size());
+ media_codec->Reset();
+ DecodeMediaFrame(media_codec.get(),
+ &chunk[0],
+ chunk.size(),
+ base::TimeDelta::FromMicroseconds(10000000),
+ base::TimeDelta::FromMicroseconds(9900000));
+
+ // Simulate a seek to 5 seconds.
+ media_codec->Reset();
+ DecodeMediaFrame(media_codec.get(),
+ &chunk[0],
+ chunk.size(),
+ base::TimeDelta::FromMicroseconds(5000000),
+ base::TimeDelta::FromMicroseconds(4900000));
+}
+
+TEST(MediaCodecBridgeTest, CreateUnsupportedCodec) {
+ EXPECT_EQ(NULL, AudioCodecBridge::Create(kUnknownAudioCodec));
+ EXPECT_EQ(
+ NULL,
+ VideoCodecBridge::CreateDecoder(
+ kUnknownVideoCodec, false, gfx::Size(320, 240), NULL, NULL));
+}
+
+} // namespace media
diff --git a/media/base/android/media_codec_decoder.cc b/media/base/android/media_codec_decoder.cc
index 67d7188..cdbaf07 100644
--- a/media/base/android/media_codec_decoder.cc
+++ b/media/base/android/media_codec_decoder.cc
@@ -738,7 +738,9 @@ bool MediaCodecDecoder::EnqueueInputBuffer() {
<< " subsamples size:" << unit->subsamples.size();
status = media_codec_bridge_->QueueSecureInputBuffer(
- index, &unit->data[0], unit->data.size(), unit->key_id, unit->iv,
+ index, &unit->data[0], unit->data.size(),
+ reinterpret_cast<const uint8_t*>(&unit->key_id[0]), unit->key_id.size(),
+ reinterpret_cast<const uint8_t*>(&unit->iv[0]), unit->iv.size(),
unit->subsamples.empty() ? nullptr : &unit->subsamples[0],
unit->subsamples.size(), unit->timestamp);
}
diff --git a/media/base/android/media_codec_decoder_unittest.cc b/media/base/android/media_codec_decoder_unittest.cc
index 2b14820..322407b 100644
--- a/media/base/android/media_codec_decoder_unittest.cc
+++ b/media/base/android/media_codec_decoder_unittest.cc
@@ -7,10 +7,9 @@
#include "base/thread_task_runner_handle.h"
#include "base/timer/timer.h"
#include "media/base/android/media_codec_audio_decoder.h"
-#include "media/base/android/media_codec_util.h"
+#include "media/base/android/media_codec_bridge.h"
#include "media/base/android/media_codec_video_decoder.h"
#include "media/base/android/media_statistics.h"
-#include "media/base/android/sdk_media_codec_bridge.h"
#include "media/base/android/test_data_factory.h"
#include "media/base/android/test_statistics.h"
#include "media/base/timestamp_constants.h"
@@ -19,6 +18,15 @@
namespace media {
+// Helper macro to skip the test if MediaCodecBridge isn't available.
+#define SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE() \
+ do { \
+ if (!MediaCodecBridge::IsAvailable()) { \
+ VLOG(0) << "Could not run test - not supported on device."; \
+ return; \
+ } \
+ } while (0)
+
namespace {
const base::TimeDelta kDefaultTimeout = base::TimeDelta::FromMilliseconds(200);
diff --git a/media/base/android/media_codec_player_unittest.cc b/media/base/android/media_codec_player_unittest.cc
index 628de1ce..46b95fc 100644
--- a/media/base/android/media_codec_player_unittest.cc
+++ b/media/base/android/media_codec_player_unittest.cc
@@ -8,11 +8,10 @@
#include "base/logging.h"
#include "base/timer/timer.h"
#include "media/base/android/demuxer_android.h"
+#include "media/base/android/media_codec_bridge.h"
#include "media/base/android/media_codec_player.h"
-#include "media/base/android/media_codec_util.h"
#include "media/base/android/media_player_manager.h"
#include "media/base/android/media_task_runner.h"
-#include "media/base/android/sdk_media_codec_bridge.h"
#include "media/base/android/test_data_factory.h"
#include "media/base/android/test_statistics.h"
#include "media/base/timestamp_constants.h"
@@ -21,6 +20,15 @@
namespace media {
+// Helper macro to skip the test if MediaCodecBridge isn't available.
+#define SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE() \
+ do { \
+ if (!MediaCodecBridge::IsAvailable()) { \
+ VLOG(0) << "Could not run test - not supported on device."; \
+ return; \
+ } \
+ } while (0)
+
#define RUN_ON_MEDIA_THREAD(CLASS, METHOD, ...) \
do { \
if (!GetMediaTaskRunner()->BelongsToCurrentThread()) { \
diff --git a/media/base/android/media_codec_util.cc b/media/base/android/media_codec_util.cc
deleted file mode 100644
index cb31ef9..0000000
--- a/media/base/android/media_codec_util.cc
+++ /dev/null
@@ -1,225 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/base/android/media_codec_util.h"
-
-#include <algorithm>
-
-#include "base/android/build_info.h"
-#include "base/android/jni_android.h"
-#include "base/android/jni_array.h"
-#include "base/android/jni_string.h"
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "base/strings/string_util.h"
-#include "jni/MediaCodecUtil_jni.h"
-
-using base::android::AttachCurrentThread;
-using base::android::ConvertJavaStringToUTF8;
-using base::android::ConvertUTF8ToJavaString;
-using base::android::JavaIntArrayToIntVector;
-using base::android::ScopedJavaLocalRef;
-
-namespace media {
-
-// static
-const std::string CodecTypeToAndroidMimeType(const std::string& codec) {
- // TODO(xhwang): Shall we handle more detailed strings like "mp4a.40.2"?
- if (codec == "avc1")
- return "video/avc";
- if (codec == "hvc1")
- return "video/hevc";
- if (codec == "mp4a")
- return "audio/mp4a-latm";
- if (codec == "vp8" || codec == "vp8.0")
- return "video/x-vnd.on2.vp8";
- if (codec == "vp9" || codec == "vp9.0")
- return "video/x-vnd.on2.vp9";
- if (codec == "vorbis")
- return "audio/vorbis";
- if (codec == "opus")
- return "audio/opus";
- return std::string();
-}
-
-// TODO(qinmin): using a map to help all the conversions in this class.
-const std::string AndroidMimeTypeToCodecType(const std::string& mime) {
- if (mime == "video/mp4v-es")
- return "mp4v";
- if (mime == "video/avc")
- return "avc1";
- if (mime == "video/hevc")
- return "hvc1";
- if (mime == "video/x-vnd.on2.vp8")
- return "vp8";
- if (mime == "video/x-vnd.on2.vp9")
- return "vp9";
- if (mime == "audio/mp4a-latm")
- return "mp4a";
- if (mime == "audio/mpeg")
- return "mp3";
- if (mime == "audio/vorbis")
- return "vorbis";
- if (mime == "audio/opus")
- return "opus";
- return std::string();
-}
-
-std::string GetDefaultCodecName(const std::string& mime_type,
- MediaCodecDirection direction) {
- if (!MediaCodecUtil::IsMediaCodecAvailable())
- return std::string();
-
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime_type);
- ScopedJavaLocalRef<jstring> j_codec_name =
- Java_MediaCodecUtil_getDefaultCodecName(env, j_mime.obj(), direction);
- return ConvertJavaStringToUTF8(env, j_codec_name.obj());
-}
-
-bool SupportsGetName() {
- // MediaCodec.getName() is only available on JB MR2 and greater.
- return base::android::BuildInfo::GetInstance()->sdk_int() >= 18;
-}
-
-// Represents supported codecs on android.
-// TODO(qinmin): Currently the codecs string only contains one codec. Do we
-// need to support codecs separated by comma. (e.g. "vp8" -> "vp8, vp8.0")?
-struct CodecsInfo {
- std::string codecs; // E.g. "vp8" or "avc1".
- std::string name; // E.g. "OMX.google.vp8.decoder".
- MediaCodecDirection direction;
-};
-
-// Get a list of supported codecs.
-std::vector<CodecsInfo> GetCodecsInfo() {
- std::vector<CodecsInfo> codecs_info;
- if (!MediaCodecUtil::IsMediaCodecAvailable())
- return codecs_info;
-
- JNIEnv* env = AttachCurrentThread();
- std::string mime_type;
- ScopedJavaLocalRef<jobjectArray> j_codec_info_array =
- Java_MediaCodecUtil_getCodecsInfo(env);
- jsize len = env->GetArrayLength(j_codec_info_array.obj());
- for (jsize i = 0; i < len; ++i) {
- ScopedJavaLocalRef<jobject> j_info(
- env, env->GetObjectArrayElement(j_codec_info_array.obj(), i));
- ScopedJavaLocalRef<jstring> j_codec_type =
- Java_CodecInfo_codecType(env, j_info.obj());
- ConvertJavaStringToUTF8(env, j_codec_type.obj(), &mime_type);
- ScopedJavaLocalRef<jstring> j_codec_name =
- Java_CodecInfo_codecName(env, j_info.obj());
- CodecsInfo info;
- info.codecs = AndroidMimeTypeToCodecType(mime_type);
- ConvertJavaStringToUTF8(env, j_codec_name.obj(), &info.name);
- info.direction = static_cast<MediaCodecDirection>(
- Java_CodecInfo_direction(env, j_info.obj()));
- codecs_info.push_back(info);
- }
- return codecs_info;
-}
-
-// static
-bool MediaCodecUtil::IsMediaCodecAvailable() {
- // MediaCodec is only available on JB and greater.
- if (base::android::BuildInfo::GetInstance()->sdk_int() < 16)
- return false;
- // Blacklist some devices on Jellybean as for MediaCodec support is buggy.
- // http://crbug.com/365494.
- if (base::android::BuildInfo::GetInstance()->sdk_int() == 16) {
- std::string model(base::android::BuildInfo::GetInstance()->model());
- return model != "GT-I9100" && model != "GT-I9300" && model != "GT-N7000";
- }
- return true;
-}
-
-// static
-bool MediaCodecUtil::SupportsSetParameters() {
- // MediaCodec.setParameters() is only available starting with K.
- return base::android::BuildInfo::GetInstance()->sdk_int() >= 19;
-}
-
-// static
-std::set<int> MediaCodecUtil::GetEncoderColorFormats(
- const std::string& mime_type) {
- std::set<int> color_formats;
- if (!IsMediaCodecAvailable())
- return color_formats;
-
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime_type);
- ScopedJavaLocalRef<jintArray> j_color_format_array =
- Java_MediaCodecUtil_getEncoderColorFormatsForMime(env, j_mime.obj());
-
- if (j_color_format_array.obj()) {
- std::vector<int> formats;
- JavaIntArrayToIntVector(env, j_color_format_array.obj(), &formats);
- color_formats = std::set<int>(formats.begin(), formats.end());
- }
-
- return color_formats;
-}
-
-// static
-bool MediaCodecUtil::CanDecode(const std::string& codec, bool is_secure) {
- if (!IsMediaCodecAvailable())
- return false;
-
- JNIEnv* env = AttachCurrentThread();
- std::string mime = CodecTypeToAndroidMimeType(codec);
- if (mime.empty())
- return false;
- ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime);
- return Java_MediaCodecUtil_canDecode(env, j_mime.obj(), is_secure);
-}
-
-// static
-bool MediaCodecUtil::IsKnownUnaccelerated(const std::string& mime_type,
- MediaCodecDirection direction) {
- if (!IsMediaCodecAvailable())
- return true;
-
- std::string codec_name;
- if (SupportsGetName()) {
- codec_name = GetDefaultCodecName(mime_type, direction);
- } else {
- std::string codec_type = AndroidMimeTypeToCodecType(mime_type);
- std::vector<CodecsInfo> codecs_info = GetCodecsInfo();
- for (size_t i = 0; i < codecs_info.size(); ++i) {
- if (codecs_info[i].codecs == codec_type &&
- codecs_info[i].direction == direction) {
- codec_name = codecs_info[i].name;
- break;
- }
- }
- }
- DVLOG(1) << __PRETTY_FUNCTION__ << "Default codec for " << mime_type << " : "
- << codec_name;
- // It would be nice if MediaCodecInfo externalized some notion of
- // HW-acceleration but it doesn't. Android Media guidance is that the
- // "OMX.google" prefix is always used for SW decoders, so that's what we
- // use. "OMX.SEC.*" codec is Samsung software implementation - report it
- // as unaccelerated as well. Also temporary blacklist Exynos and MediaTek
- // devices while HW decoder video freezes and distortions are
- // investigated - http://crbug.com/446974.
- if (codec_name.length() > 0) {
- return (base::StartsWith(codec_name, "OMX.google.",
- base::CompareCase::SENSITIVE) ||
- base::StartsWith(codec_name, "OMX.SEC.",
- base::CompareCase::SENSITIVE) ||
- base::StartsWith(codec_name, "OMX.MTK.",
- base::CompareCase::SENSITIVE) ||
- base::StartsWith(codec_name, "OMX.Exynos.",
- base::CompareCase::SENSITIVE));
- }
- return true;
-}
-
-// static
-bool MediaCodecUtil::RegisterMediaCodecUtil(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
-} // namespace media
diff --git a/media/base/android/media_codec_util.h b/media/base/android/media_codec_util.h
deleted file mode 100644
index 604ce5d..0000000
--- a/media/base/android/media_codec_util.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_BASE_ANDROID_MEDIA_CODEC_UTIL_H_
-#define MEDIA_BASE_ANDROID_MEDIA_CODEC_UTIL_H_
-
-#include <jni.h>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "media/base/media_export.h"
-
-namespace media {
-
-// Helper macro to skip the test if MediaCodecBridge isn't available.
-#define SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE() \
- do { \
- if (!MediaCodecUtil::IsMediaCodecAvailable()) { \
- VLOG(0) << "Could not run test - not supported on device."; \
- return; \
- } \
- } while (0)
-
-// Codec direction. Keep this in sync with MediaCodecUtil.java.
-enum MediaCodecDirection {
- MEDIA_CODEC_DECODER,
- MEDIA_CODEC_ENCODER,
-};
-
-class MEDIA_EXPORT MediaCodecUtil {
- public:
- // Returns true if MediaCodec is available on the device.
- // All other static methods check IsAvailable() internally. There's no need
- // to check IsAvailable() explicitly before calling them.
- static bool IsMediaCodecAvailable();
-
- // Returns true if MediaCodec.setParameters() is available on the device.
- static bool SupportsSetParameters();
-
- // Returns whether MediaCodecBridge has a decoder that |is_secure| and can
- // decode |codec| type.
- static bool CanDecode(const std::string& codec, bool is_secure);
-
- // Get a list of encoder supported color formats for |mime_type|.
- // The mapping of color format name and its value refers to
- // MediaCodecInfo.CodecCapabilities.
- static std::set<int> GetEncoderColorFormats(const std::string& mime_type);
-
- // Returns true if |mime_type| is known to be unaccelerated (i.e. backed by a
- // software codec instead of a hardware one).
- static bool IsKnownUnaccelerated(const std::string& mime_type,
- MediaCodecDirection direction);
-
- static bool RegisterMediaCodecUtil(JNIEnv* env);
-};
-
-} // namespace media
-
-#endif // MEDIA_BASE_ANDROID_MEDIA_CODEC_UTIL_H_
diff --git a/media/base/android/media_codec_video_decoder.cc b/media/base/android/media_codec_video_decoder.cc
index 928f2e7..f20bbeb 100644
--- a/media/base/android/media_codec_video_decoder.cc
+++ b/media/base/android/media_codec_video_decoder.cc
@@ -6,8 +6,8 @@
#include "base/bind.h"
#include "base/logging.h"
+#include "media/base/android/media_codec_bridge.h"
#include "media/base/android/media_statistics.h"
-#include "media/base/android/sdk_media_codec_bridge.h"
#include "media/base/demuxer_stream.h"
#include "media/base/timestamp_constants.h"
diff --git a/media/base/android/media_decoder_job.cc b/media/base/android/media_decoder_job.cc
index 9e0a216..8689107 100644
--- a/media/base/android/media_decoder_job.cc
+++ b/media/base/android/media_decoder_job.cc
@@ -282,9 +282,13 @@ MediaCodecStatus MediaDecoderJob::QueueInputBuffer(const AccessUnit& unit) {
}
MediaCodecStatus status = media_codec_bridge_->QueueSecureInputBuffer(
- input_buf_index, &unit.data[0], unit.data.size(), unit.key_id, unit.iv,
+ input_buf_index,
+ &unit.data[0], unit.data.size(),
+ reinterpret_cast<const uint8*>(&unit.key_id[0]), unit.key_id.size(),
+ reinterpret_cast<const uint8*>(&unit.iv[0]), unit.iv.size(),
unit.subsamples.empty() ? NULL : &unit.subsamples[0],
- unit.subsamples.size(), unit.timestamp);
+ unit.subsamples.size(),
+ unit.timestamp);
// In case of MEDIA_CODEC_NO_KEY, we must reuse the |input_buf_index_|.
// Otherwise MediaDrm will report errors.
diff --git a/media/base/android/media_jni_registrar.cc b/media/base/android/media_jni_registrar.cc
index cc8bc1d..2020469 100644
--- a/media/base/android/media_jni_registrar.cc
+++ b/media/base/android/media_jni_registrar.cc
@@ -10,11 +10,10 @@
#include "media/audio/android/audio_manager_android.h"
#include "media/audio/android/audio_record_input.h"
-#include "media/base/android/media_codec_util.h"
+#include "media/base/android/media_codec_bridge.h"
#include "media/base/android/media_drm_bridge.h"
#include "media/base/android/media_player_bridge.h"
#include "media/base/android/media_player_listener.h"
-#include "media/base/android/sdk_media_codec_bridge.h"
#include "media/base/android/webaudio_media_codec_bridge.h"
#include "media/capture/video/android/video_capture_device_android.h"
#include "media/capture/video/android/video_capture_device_factory_android.h"
@@ -22,19 +21,24 @@
namespace media {
static base::android::RegistrationMethod kMediaRegisteredMethods[] = {
- {"AudioManagerAndroid", AudioManagerAndroid::RegisterAudioManager},
- {"AudioRecordInput", AudioRecordInputStream::RegisterAudioRecordInput},
- {"MediaDrmBridge", MediaDrmBridge::RegisterMediaDrmBridge},
- {"MediaPlayerBridge", MediaPlayerBridge::RegisterMediaPlayerBridge},
- {"MediaPlayerListener", MediaPlayerListener::RegisterMediaPlayerListener},
- {"SdkMediaCodecBridge", SdkMediaCodecBridge::RegisterSdkMediaCodecBridge},
- {"MediaCodecUtil", MediaCodecUtil::RegisterMediaCodecUtil},
- {"VideoCaptureDevice",
- VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice},
- {"VideoCaptureDeviceFactory",
- VideoCaptureDeviceFactoryAndroid::RegisterVideoCaptureDeviceFactory},
- {"WebAudioMediaCodecBridge",
- WebAudioMediaCodecBridge::RegisterWebAudioMediaCodecBridge},
+ { "AudioManagerAndroid",
+ AudioManagerAndroid::RegisterAudioManager },
+ { "AudioRecordInput",
+ AudioRecordInputStream::RegisterAudioRecordInput },
+ { "MediaCodecBridge",
+ MediaCodecBridge::RegisterMediaCodecBridge },
+ { "MediaDrmBridge",
+ MediaDrmBridge::RegisterMediaDrmBridge },
+ { "MediaPlayerBridge",
+ MediaPlayerBridge::RegisterMediaPlayerBridge },
+ { "MediaPlayerListener",
+ MediaPlayerListener::RegisterMediaPlayerListener },
+ { "VideoCaptureDevice",
+ VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice },
+ { "VideoCaptureDeviceFactory",
+ VideoCaptureDeviceFactoryAndroid::RegisterVideoCaptureDeviceFactory },
+ { "WebAudioMediaCodecBridge",
+ WebAudioMediaCodecBridge::RegisterWebAudioMediaCodecBridge },
};
bool RegisterJni(JNIEnv* env) {
diff --git a/media/base/android/media_source_player_unittest.cc b/media/base/android/media_source_player_unittest.cc
index b7cab6c..fd4a725 100644
--- a/media/base/android/media_source_player_unittest.cc
+++ b/media/base/android/media_source_player_unittest.cc
@@ -9,12 +9,11 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/stringprintf.h"
#include "media/base/android/audio_decoder_job.h"
-#include "media/base/android/media_codec_util.h"
+#include "media/base/android/media_codec_bridge.h"
#include "media/base/android/media_drm_bridge.h"
#include "media/base/android/media_player_manager.h"
#include "media/base/android/media_source_player.h"
#include "media/base/android/media_url_interceptor.h"
-#include "media/base/android/sdk_media_codec_bridge.h"
#include "media/base/android/video_decoder_job.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/decoder_buffer.h"
@@ -25,6 +24,15 @@
namespace media {
+// Helper macro to skip the test if MediaCodecBridge isn't available.
+#define SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE() \
+ do { \
+ if (!MediaCodecBridge::IsAvailable()) { \
+ VLOG(0) << "Could not run test - not supported on device."; \
+ return; \
+ } \
+ } while (0)
+
const base::TimeDelta kDefaultDuration =
base::TimeDelta::FromMilliseconds(10000);
diff --git a/media/base/android/ndk_media_codec_bridge.cc b/media/base/android/ndk_media_codec_bridge.cc
deleted file mode 100644
index 2ce2a0f..0000000
--- a/media/base/android/ndk_media_codec_bridge.cc
+++ /dev/null
@@ -1,234 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/base/android/ndk_media_codec_bridge.h"
-
-#include <media/NdkMediaError.h>
-#include <media/NdkMediaFormat.h>
-
-#include <limits>
-
-#include "base/strings/string_util.h"
-#include "media/base/decrypt_config.h"
-
-namespace {
-const char kMediaFormatKeyCropLeft[] = "crop-left";
-const char kMediaFormatKeyCropRight[] = "crop-right";
-const char kMediaFormatKeyCropBottom[] = "crop-bottom";
-const char kMediaFormatKeyCropTop[] = "crop-top";
-}
-
-namespace media {
-
-// Translate media_status_t to MediaCodecStatus.
-static MediaCodecStatus TranslateMediaCodecStatus(media_status_t status) {
- switch (status) {
- case AMEDIA_OK:
- return MEDIA_CODEC_OK;
- case AMEDIA_DRM_NEED_KEY:
- return MEDIA_CODEC_NO_KEY;
- default:
- return MEDIA_CODEC_ERROR;
- }
-}
-
-NdkMediaCodecBridge::~NdkMediaCodecBridge() {}
-
-NdkMediaCodecBridge::NdkMediaCodecBridge(const std::string& mime,
- bool is_secure,
- MediaCodecDirection direction) {
- if (base::StartsWith(mime, "video", base::CompareCase::SENSITIVE) &&
- is_secure && direction == MEDIA_CODEC_DECODER) {
- // TODO(qinmin): get the secure decoder name from java.
- NOTIMPLEMENTED();
- return;
- }
-
- if (direction == MEDIA_CODEC_DECODER)
- media_codec_.reset(AMediaCodec_createDecoderByType(mime.c_str()));
- else
- media_codec_.reset(AMediaCodec_createEncoderByType(mime.c_str()));
-}
-
-MediaCodecStatus NdkMediaCodecBridge::Reset() {
- media_status_t status = AMediaCodec_flush(media_codec_.get());
- return TranslateMediaCodecStatus(status);
-}
-
-bool NdkMediaCodecBridge::Start() {
- return AMEDIA_OK == AMediaCodec_start(media_codec_.get());
-}
-
-void NdkMediaCodecBridge::Stop() {
- AMediaCodec_stop(media_codec_.get());
-}
-
-void NdkMediaCodecBridge::GetOutputFormat(int* width, int* height) {
- AMediaFormat* format = AMediaCodec_getOutputFormat(media_codec_.get());
- int left, right, bottom, top;
- bool has_left = AMediaFormat_getInt32(format, kMediaFormatKeyCropLeft, &left);
- bool has_right =
- AMediaFormat_getInt32(format, kMediaFormatKeyCropRight, &right);
- bool has_bottom =
- AMediaFormat_getInt32(format, kMediaFormatKeyCropBottom, &bottom);
- bool has_top = AMediaFormat_getInt32(format, kMediaFormatKeyCropTop, &top);
- if (has_left && has_right && has_bottom && has_top) {
- // Use crop size as it is more accurate. right and bottom are inclusive.
- *width = right - left + 1;
- *height = top - bottom + 1;
- } else {
- AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, width);
- AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, height);
- }
-}
-
-int NdkMediaCodecBridge::GetOutputSamplingRate() {
- AMediaFormat* format = AMediaCodec_getOutputFormat(media_codec_.get());
- int sample_rate = 0;
- AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &sample_rate);
- DCHECK(sample_rate != 0);
- return sample_rate;
-}
-
-MediaCodecStatus NdkMediaCodecBridge::QueueInputBuffer(
- int index,
- const uint8_t* data,
- size_t data_size,
- const base::TimeDelta& presentation_time) {
- if (data_size >
- base::checked_cast<size_t>(std::numeric_limits<int32_t>::max())) {
- return MEDIA_CODEC_ERROR;
- }
- if (data && !FillInputBuffer(index, data, data_size))
- return MEDIA_CODEC_ERROR;
-
- media_status_t status =
- AMediaCodec_queueInputBuffer(media_codec_.get(), index, 0, data_size,
- presentation_time.InMicroseconds(), 0);
- return TranslateMediaCodecStatus(status);
-}
-
-MediaCodecStatus NdkMediaCodecBridge::QueueSecureInputBuffer(
- int index,
- const uint8_t* data,
- size_t data_size,
- const std::vector<char>& key_id,
- const std::vector<char>& iv,
- const SubsampleEntry* subsamples,
- int subsamples_size,
- const base::TimeDelta& presentation_time) {
- if (data_size >
- base::checked_cast<size_t>(std::numeric_limits<int32_t>::max())) {
- return MEDIA_CODEC_ERROR;
- }
- if (key_id.size() > 16 || iv.size())
- return MEDIA_CODEC_ERROR;
- if (data && !FillInputBuffer(index, data, data_size))
- return MEDIA_CODEC_ERROR;
-
- int new_subsamples_size = subsamples_size == 0 ? 1 : subsamples_size;
- std::vector<size_t> clear_data, encrypted_data;
- if (subsamples_size == 0) {
- DCHECK(!subsamples);
- clear_data.push_back(0);
- encrypted_data.push_back(data_size);
- } else {
- DCHECK_GT(subsamples_size, 0);
- DCHECK(subsamples);
- for (int i = 0; i < subsamples_size; ++i) {
- DCHECK(subsamples[i].clear_bytes <= std::numeric_limits<uint16_t>::max());
- if (subsamples[i].cypher_bytes >
- static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) {
- return MEDIA_CODEC_ERROR;
- }
- clear_data.push_back(subsamples[i].clear_bytes);
- encrypted_data.push_back(subsamples[i].cypher_bytes);
- }
- }
-
- AMediaCodecCryptoInfo* crypto_info = AMediaCodecCryptoInfo_new(
- new_subsamples_size,
- reinterpret_cast<uint8_t*>(const_cast<char*>(key_id.data())),
- reinterpret_cast<uint8_t*>(const_cast<char*>(iv.data())),
- AMEDIACODECRYPTOINFO_MODE_AES_CTR, clear_data.data(),
- encrypted_data.data());
-
- media_status_t status = AMediaCodec_queueSecureInputBuffer(
- media_codec_.get(), index, 0, crypto_info,
- presentation_time.InMicroseconds(), 0);
- return TranslateMediaCodecStatus(status);
-}
-
-void NdkMediaCodecBridge::QueueEOS(int input_buffer_index) {
- AMediaCodec_queueInputBuffer(media_codec_.get(), input_buffer_index, 0, 0, 0,
- AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
-}
-
-MediaCodecStatus NdkMediaCodecBridge::DequeueInputBuffer(
- const base::TimeDelta& timeout,
- int* index) {
- *index = AMediaCodec_dequeueInputBuffer(media_codec_.get(),
- timeout.InMicroseconds());
- if (*index >= 0)
- return MEDIA_CODEC_OK;
- else if (*index == AMEDIACODEC_INFO_TRY_AGAIN_LATER)
- return MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER;
- else
- return MEDIA_CODEC_ERROR;
-}
-
-MediaCodecStatus NdkMediaCodecBridge::DequeueOutputBuffer(
- const base::TimeDelta& timeout,
- int* index,
- size_t* offset,
- size_t* size,
- base::TimeDelta* presentation_time,
- bool* end_of_stream,
- bool* key_frame) {
- AMediaCodecBufferInfo buffer_info;
- *index = AMediaCodec_dequeueOutputBuffer(media_codec_.get(), &buffer_info,
- timeout.InMicroseconds());
- *offset = buffer_info.offset;
- *size = buffer_info.size;
- *presentation_time =
- base::TimeDelta::FromMicroseconds(buffer_info.presentationTimeUs);
- if (end_of_stream)
- *end_of_stream = buffer_info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
- if (key_frame)
- *key_frame = false; // This is deprecated.
- if (*index >= 0)
- return MEDIA_CODEC_OK;
- else if (*index == AMEDIACODEC_INFO_TRY_AGAIN_LATER)
- return MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER;
- else
- return MEDIA_CODEC_ERROR;
-}
-
-void NdkMediaCodecBridge::ReleaseOutputBuffer(int index, bool render) {
- AMediaCodec_releaseOutputBuffer(media_codec_.get(), index, render);
-}
-
-void NdkMediaCodecBridge::GetInputBuffer(int input_buffer_index,
- uint8_t** data,
- size_t* capacity) {
- *data = AMediaCodec_getInputBuffer(media_codec_.get(), input_buffer_index,
- capacity);
-}
-
-bool NdkMediaCodecBridge::CopyFromOutputBuffer(int index,
- size_t offset,
- void* dst,
- int dst_size) {
- size_t capacity;
- uint8_t* src_data =
- AMediaCodec_getOutputBuffer(media_codec_.get(), index, &capacity);
-
- if (capacity < offset || capacity - offset < static_cast<size_t>(dst_size))
- return false;
-
- memcpy(dst, src_data + offset, dst_size);
- return true;
-}
-
-} // namespace media
diff --git a/media/base/android/ndk_media_codec_bridge.h b/media/base/android/ndk_media_codec_bridge.h
deleted file mode 100644
index d16d6f8..0000000
--- a/media/base/android/ndk_media_codec_bridge.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_BASE_ANDROID_NDK_MEDIA_CODEC_BRIDGE_H_
-#define MEDIA_BASE_ANDROID_NDK_MEDIA_CODEC_BRIDGE_H_
-
-#include <media/NdkMediaCodec.h>
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/time/time.h"
-#include "media/base/android/media_codec_bridge.h"
-#include "media/base/media_export.h"
-
-namespace media {
-
-class MEDIA_EXPORT NdkMediaCodecBridge : public MediaCodecBridge {
- public:
- ~NdkMediaCodecBridge() override;
-
- // MediaCodecBridge implementation.
- MediaCodecStatus Reset() override;
- bool Start() override;
- void Stop() override;
- void GetOutputFormat(int* width, int* height) override;
- int GetOutputSamplingRate() override;
- MediaCodecStatus QueueInputBuffer(
- int index,
- const uint8_t* data,
- size_t data_size,
- const base::TimeDelta& presentation_time) override;
- using MediaCodecBridge::QueueSecureInputBuffer;
- MediaCodecStatus QueueSecureInputBuffer(
- int index,
- const uint8_t* data,
- size_t data_size,
- const std::vector<char>& key_id,
- const std::vector<char>& iv,
- const SubsampleEntry* subsamples,
- int subsamples_size,
- const base::TimeDelta& presentation_time) override;
- void QueueEOS(int input_buffer_index);
- MediaCodecStatus DequeueInputBuffer(const base::TimeDelta& timeout,
- int* index) override;
- MediaCodecStatus DequeueOutputBuffer(const base::TimeDelta& timeout,
- int* index,
- size_t* offset,
- size_t* size,
- base::TimeDelta* presentation_time,
- bool* end_of_stream,
- bool* key_frame) override;
- void ReleaseOutputBuffer(int index, bool render) override;
- void GetInputBuffer(int input_buffer_index,
- uint8_t** data,
- size_t* capacity) override;
- bool CopyFromOutputBuffer(int index,
- size_t offset,
- void* dst,
- int dst_size) override;
-
- protected:
- NdkMediaCodecBridge(const std::string& mime,
- bool is_secure,
- MediaCodecDirection direction);
-
- private:
- struct AMediaCodecDeleter {
- inline void operator()(AMediaCodec* ptr) const { AMediaCodec_delete(ptr); }
- };
-
- scoped_ptr<AMediaCodec, AMediaCodecDeleter> media_codec_;
-
- DISALLOW_COPY_AND_ASSIGN(NdkMediaCodecBridge);
-};
-
-} // namespace media
-
-#endif // MEDIA_BASE_ANDROID_NDK_MEDIA_CODEC_BRIDGE_H_
diff --git a/media/base/android/sdk_media_codec_bridge.cc b/media/base/android/sdk_media_codec_bridge.cc
deleted file mode 100644
index 0c6e25f..0000000
--- a/media/base/android/sdk_media_codec_bridge.cc
+++ /dev/null
@@ -1,643 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/base/android/sdk_media_codec_bridge.h"
-
-#include <algorithm>
-#include <limits>
-
-#include "base/android/build_info.h"
-#include "base/android/jni_android.h"
-#include "base/android/jni_array.h"
-#include "base/android/jni_string.h"
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/strings/string_util.h"
-#include "jni/MediaCodecBridge_jni.h"
-#include "media/base/bit_reader.h"
-#include "media/base/decrypt_config.h"
-
-using base::android::AttachCurrentThread;
-using base::android::ConvertJavaStringToUTF8;
-using base::android::ConvertUTF8ToJavaString;
-using base::android::JavaIntArrayToIntVector;
-using base::android::ScopedJavaLocalRef;
-
-#define RETURN_ON_ERROR(condition) \
- do { \
- if (!(condition)) { \
- LOG(ERROR) << "Unable to parse AAC header: " #condition; \
- return false; \
- } \
- } while (0)
-
-namespace media {
-
-enum {
- kBufferFlagSyncFrame = 1, // BUFFER_FLAG_SYNC_FRAME
- kBufferFlagEndOfStream = 4, // BUFFER_FLAG_END_OF_STREAM
- kConfigureFlagEncode = 1, // CONFIGURE_FLAG_ENCODE
-};
-
-static ScopedJavaLocalRef<jintArray>
-ToJavaIntArray(JNIEnv* env, scoped_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;
-}
-
-static 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";
- default:
- return std::string();
- }
-}
-
-static const std::string VideoCodecToAndroidMimeType(const VideoCodec& codec) {
- 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";
- default:
- return std::string();
- }
-}
-
-SdkMediaCodecBridge::SdkMediaCodecBridge(const std::string& mime,
- bool is_secure,
- MediaCodecDirection direction) {
- JNIEnv* env = AttachCurrentThread();
- CHECK(env);
- DCHECK(!mime.empty());
- ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime);
- j_media_codec_.Reset(
- Java_MediaCodecBridge_create(env, j_mime.obj(), is_secure, direction));
-}
-
-SdkMediaCodecBridge::~SdkMediaCodecBridge() {
- JNIEnv* env = AttachCurrentThread();
- CHECK(env);
- if (j_media_codec_.obj())
- Java_MediaCodecBridge_release(env, j_media_codec_.obj());
-}
-
-MediaCodecStatus SdkMediaCodecBridge::Reset() {
- JNIEnv* env = AttachCurrentThread();
- return static_cast<MediaCodecStatus>(
- Java_MediaCodecBridge_flush(env, j_media_codec_.obj()));
-}
-
-bool SdkMediaCodecBridge::Start() {
- JNIEnv* env = AttachCurrentThread();
- return Java_MediaCodecBridge_start(env, j_media_codec_.obj());
-}
-
-void SdkMediaCodecBridge::Stop() {
- JNIEnv* env = AttachCurrentThread();
- Java_MediaCodecBridge_stop(env, j_media_codec_.obj());
-}
-
-void SdkMediaCodecBridge::GetOutputFormat(int* width, int* height) {
- JNIEnv* env = AttachCurrentThread();
-
- *width = Java_MediaCodecBridge_getOutputWidth(env, j_media_codec_.obj());
- *height = Java_MediaCodecBridge_getOutputHeight(env, j_media_codec_.obj());
-}
-
-int SdkMediaCodecBridge::GetOutputSamplingRate() {
- JNIEnv* env = AttachCurrentThread();
-
- return Java_MediaCodecBridge_getOutputSamplingRate(env, j_media_codec_.obj());
-}
-
-MediaCodecStatus SdkMediaCodecBridge::QueueInputBuffer(
- int index,
- const uint8_t* data,
- size_t data_size,
- const base::TimeDelta& presentation_time) {
- DVLOG(3) << __PRETTY_FUNCTION__ << index << ": " << data_size;
- if (data_size >
- base::checked_cast<size_t>(std::numeric_limits<int32_t>::max())) {
- return MEDIA_CODEC_ERROR;
- }
- if (data && !FillInputBuffer(index, data, data_size))
- return MEDIA_CODEC_ERROR;
- JNIEnv* env = AttachCurrentThread();
- return static_cast<MediaCodecStatus>(Java_MediaCodecBridge_queueInputBuffer(
- env, j_media_codec_.obj(), index, 0, data_size,
- presentation_time.InMicroseconds(), 0));
-}
-
-// TODO(timav): Combine this and above methods together keeping only the first
-// interface after we switch to Spitzer pipeline.
-MediaCodecStatus SdkMediaCodecBridge::QueueSecureInputBuffer(
- int index,
- const uint8_t* data,
- size_t data_size,
- const std::vector<char>& key_id,
- const std::vector<char>& iv,
- const SubsampleEntry* subsamples,
- int subsamples_size,
- const base::TimeDelta& presentation_time) {
- DVLOG(3) << __PRETTY_FUNCTION__ << index << ": " << data_size;
- if (data_size >
- base::checked_cast<size_t>(std::numeric_limits<int32_t>::max())) {
- return MEDIA_CODEC_ERROR;
- }
- if (data && !FillInputBuffer(index, data, data_size))
- return MEDIA_CODEC_ERROR;
-
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jbyteArray> j_key_id = base::android::ToJavaByteArray(
- env, reinterpret_cast<const uint8_t*>(key_id.data()), key_id.size());
- ScopedJavaLocalRef<jbyteArray> j_iv = base::android::ToJavaByteArray(
- env, reinterpret_cast<const uint8_t*>(iv.data()), iv.size());
-
- // MediaCodec.CryptoInfo documentations says passing NULL for |clear_array|
- // to indicate that all data is encrypted. But it doesn't specify what
- // |cypher_array| and |subsamples_size| should be in that case. Passing
- // one subsample here just to be on the safe side.
- int new_subsamples_size = subsamples_size == 0 ? 1 : subsamples_size;
-
- scoped_ptr<jint[]> native_clear_array(new jint[new_subsamples_size]);
- scoped_ptr<jint[]> native_cypher_array(new jint[new_subsamples_size]);
-
- if (subsamples_size == 0) {
- DCHECK(!subsamples);
- native_clear_array[0] = 0;
- native_cypher_array[0] = data_size;
- } else {
- DCHECK_GT(subsamples_size, 0);
- DCHECK(subsamples);
- for (int i = 0; i < subsamples_size; ++i) {
- DCHECK(subsamples[i].clear_bytes <= std::numeric_limits<uint16_t>::max());
- if (subsamples[i].cypher_bytes >
- static_cast<uint32_t>(std::numeric_limits<jint>::max())) {
- return MEDIA_CODEC_ERROR;
- }
-
- native_clear_array[i] = subsamples[i].clear_bytes;
- native_cypher_array[i] = subsamples[i].cypher_bytes;
- }
- }
-
- ScopedJavaLocalRef<jintArray> clear_array =
- ToJavaIntArray(env, native_clear_array.Pass(), new_subsamples_size);
- ScopedJavaLocalRef<jintArray> cypher_array =
- ToJavaIntArray(env, native_cypher_array.Pass(), new_subsamples_size);
-
- return static_cast<MediaCodecStatus>(
- Java_MediaCodecBridge_queueSecureInputBuffer(
- env, j_media_codec_.obj(), index, 0, j_iv.obj(), j_key_id.obj(),
- clear_array.obj(), cypher_array.obj(), new_subsamples_size,
- presentation_time.InMicroseconds()));
-}
-
-void SdkMediaCodecBridge::QueueEOS(int input_buffer_index) {
- DVLOG(3) << __PRETTY_FUNCTION__ << ": " << input_buffer_index;
- JNIEnv* env = AttachCurrentThread();
- Java_MediaCodecBridge_queueInputBuffer(env, j_media_codec_.obj(),
- input_buffer_index, 0, 0, 0,
- kBufferFlagEndOfStream);
-}
-
-MediaCodecStatus SdkMediaCodecBridge::DequeueInputBuffer(
- const base::TimeDelta& timeout,
- int* index) {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> result = Java_MediaCodecBridge_dequeueInputBuffer(
- env, j_media_codec_.obj(), timeout.InMicroseconds());
- *index = Java_DequeueInputResult_index(env, result.obj());
- MediaCodecStatus status = static_cast<MediaCodecStatus>(
- Java_DequeueInputResult_status(env, result.obj()));
- DVLOG(3) << __PRETTY_FUNCTION__ << ": status: " << status
- << ", index: " << *index;
- return status;
-}
-
-MediaCodecStatus SdkMediaCodecBridge::DequeueOutputBuffer(
- const base::TimeDelta& timeout,
- int* index,
- size_t* offset,
- size_t* size,
- base::TimeDelta* presentation_time,
- bool* end_of_stream,
- bool* key_frame) {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> result =
- Java_MediaCodecBridge_dequeueOutputBuffer(env, j_media_codec_.obj(),
- timeout.InMicroseconds());
- *index = Java_DequeueOutputResult_index(env, result.obj());
- *offset = base::checked_cast<size_t>(
- Java_DequeueOutputResult_offset(env, result.obj()));
- *size = base::checked_cast<size_t>(
- Java_DequeueOutputResult_numBytes(env, result.obj()));
- if (presentation_time) {
- *presentation_time = base::TimeDelta::FromMicroseconds(
- Java_DequeueOutputResult_presentationTimeMicroseconds(env,
- result.obj()));
- }
- int flags = Java_DequeueOutputResult_flags(env, result.obj());
- if (end_of_stream)
- *end_of_stream = flags & kBufferFlagEndOfStream;
- if (key_frame)
- *key_frame = flags & kBufferFlagSyncFrame;
- MediaCodecStatus status = static_cast<MediaCodecStatus>(
- Java_DequeueOutputResult_status(env, result.obj()));
- DVLOG(3) << __PRETTY_FUNCTION__ << ": status: " << status
- << ", index: " << *index << ", offset: " << *offset
- << ", size: " << *size << ", flags: " << flags;
- return status;
-}
-
-void SdkMediaCodecBridge::ReleaseOutputBuffer(int index, bool render) {
- DVLOG(3) << __PRETTY_FUNCTION__ << ": " << index;
- JNIEnv* env = AttachCurrentThread();
- CHECK(env);
-
- Java_MediaCodecBridge_releaseOutputBuffer(env, j_media_codec_.obj(), index,
- render);
-}
-
-int SdkMediaCodecBridge::GetOutputBuffersCount() {
- JNIEnv* env = AttachCurrentThread();
- return Java_MediaCodecBridge_getOutputBuffersCount(env, j_media_codec_.obj());
-}
-
-size_t SdkMediaCodecBridge::GetOutputBuffersCapacity() {
- JNIEnv* env = AttachCurrentThread();
- return Java_MediaCodecBridge_getOutputBuffersCapacity(env,
- j_media_codec_.obj());
-}
-
-void SdkMediaCodecBridge::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_.obj(), input_buffer_index));
- *data = static_cast<uint8_t*>(env->GetDirectBufferAddress(j_buffer.obj()));
- *capacity =
- base::checked_cast<size_t>(env->GetDirectBufferCapacity(j_buffer.obj()));
-}
-
-bool SdkMediaCodecBridge::CopyFromOutputBuffer(int index,
- size_t offset,
- void* dst,
- int dst_size) {
- void* src_data = nullptr;
- size_t src_capacity = GetOutputBufferAddress(index, offset, &src_data);
- if (src_capacity < offset ||
- src_capacity - offset < static_cast<size_t>(dst_size)) {
- return false;
- }
- memcpy(dst, static_cast<uint8_t*>(src_data) + offset, dst_size);
- return true;
-}
-
-int SdkMediaCodecBridge::GetOutputBufferAddress(int index,
- size_t offset,
- void** addr) {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> j_buffer(
- Java_MediaCodecBridge_getOutputBuffer(env, j_media_codec_.obj(), index));
- *addr =
- reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(j_buffer.obj())) +
- offset;
- return env->GetDirectBufferCapacity(j_buffer.obj()) - offset;
-}
-
-// static
-bool SdkMediaCodecBridge::RegisterSdkMediaCodecBridge(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
-// static
-AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec& codec) {
- if (!MediaCodecUtil::IsMediaCodecAvailable())
- return nullptr;
-
- const std::string mime = AudioCodecToAndroidMimeType(codec);
- return mime.empty() ? nullptr : new AudioCodecBridge(mime);
-}
-
-// 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.
- : SdkMediaCodecBridge(mime, false, MEDIA_CODEC_DECODER) {}
-
-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,
- bool play_audio,
- jobject media_crypto) {
- JNIEnv* env = AttachCurrentThread();
-
- if (!media_codec())
- return false;
-
- std::string codec_string = AudioCodecToAndroidMimeType(codec);
- if (codec_string.empty())
- return false;
-
- ScopedJavaLocalRef<jstring> j_mime =
- ConvertUTF8ToJavaString(env, codec_string);
- ScopedJavaLocalRef<jobject> j_format(Java_MediaCodecBridge_createAudioFormat(
- env, j_mime.obj(), 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.obj(),
- media_crypto, 0, play_audio)) {
- 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.obj());
- // 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.obj());
- 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.obj());
-
- // 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.obj());
-
- // 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.obj());
-
- // 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.obj());
- break;
- }
- default:
- LOG(ERROR) << "Invalid header encountered for codec: "
- << AudioCodecToAndroidMimeType(codec);
- return false;
- }
- return true;
-}
-
-int64_t AudioCodecBridge::PlayOutputBuffer(int index,
- size_t size,
- size_t offset,
- bool postpone) {
- DCHECK_LE(0, index);
- int numBytes = base::checked_cast<int>(size);
-
- void* buffer = nullptr;
- int capacity = GetOutputBufferAddress(index, offset, &buffer);
- numBytes = std::min(capacity, numBytes);
- CHECK_GE(numBytes, 0);
-
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jbyteArray> byte_array = base::android::ToJavaByteArray(
- env, static_cast<uint8_t*>(buffer), numBytes);
- return Java_MediaCodecBridge_playOutputBuffer(env, media_codec(),
- byte_array.obj(), postpone);
-}
-
-void AudioCodecBridge::SetVolume(double volume) {
- JNIEnv* env = AttachCurrentThread();
- Java_MediaCodecBridge_setVolume(env, media_codec(), volume);
-}
-
-// 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) {
- if (!MediaCodecUtil::IsMediaCodecAvailable())
- return nullptr;
-
- const std::string mime = VideoCodecToAndroidMimeType(codec);
- if (mime.empty())
- return nullptr;
-
- scoped_ptr<VideoCodecBridge> bridge(
- new VideoCodecBridge(mime, is_secure, MEDIA_CODEC_DECODER));
- 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.obj(), size.width(), size.height()));
- DCHECK(!j_format.is_null());
- if (!Java_MediaCodecBridge_configureVideo(env, bridge->media_codec(),
- j_format.obj(), surface,
- media_crypto, 0)) {
- 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;
-
- scoped_ptr<VideoCodecBridge> bridge(
- new VideoCodecBridge(mime, false, MEDIA_CODEC_ENCODER));
- if (!bridge->media_codec())
- return nullptr;
-
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime);
- ScopedJavaLocalRef<jobject> j_format(
- Java_MediaCodecBridge_createVideoEncoderFormat(
- env, j_mime.obj(), 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.obj(), nullptr, nullptr,
- kConfigureFlagEncode)) {
- return nullptr;
- }
-
- return bridge->Start() ? bridge.release() : nullptr;
-}
-
-VideoCodecBridge::VideoCodecBridge(const std::string& mime,
- bool is_secure,
- MediaCodecDirection direction)
- : SdkMediaCodecBridge(mime, is_secure, direction),
- adaptive_playback_supported_for_testing_(-1) {}
-
-void VideoCodecBridge::SetVideoBitrate(int bps) {
- JNIEnv* env = AttachCurrentThread();
- Java_MediaCodecBridge_setVideoBitrate(env, media_codec(), bps);
-}
-
-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
diff --git a/media/base/android/sdk_media_codec_bridge.h b/media/base/android/sdk_media_codec_bridge.h
deleted file mode 100644
index c495ffc9..0000000
--- a/media/base/android/sdk_media_codec_bridge.h
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_BASE_ANDROID_SDK_MEDIA_CODEC_BRIDGE_H_
-#define MEDIA_BASE_ANDROID_SDK_MEDIA_CODEC_BRIDGE_H_
-
-#include <jni.h>
-#include <stdint.h>
-
-#include <set>
-#include <string>
-
-#include "base/android/scoped_java_ref.h"
-#include "base/macros.h"
-#include "base/time/time.h"
-#include "media/base/android/media_codec_bridge.h"
-#include "media/base/audio_decoder_config.h"
-#include "media/base/media_export.h"
-#include "media/base/video_decoder_config.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace media {
-
-// This class implements MediaCodecBridge using android MediaCodec SDK APIs.
-class MEDIA_EXPORT SdkMediaCodecBridge : public MediaCodecBridge {
- public:
- ~SdkMediaCodecBridge() override;
-
- // MediaCodecBridge implementations.
- MediaCodecStatus Reset() override;
- bool Start() override;
- void Stop() override;
- void GetOutputFormat(int* width, int* height) override;
- int GetOutputSamplingRate() override;
- MediaCodecStatus QueueInputBuffer(
- int index,
- const uint8_t* data,
- size_t data_size,
- const base::TimeDelta& presentation_time) override;
- using MediaCodecBridge::QueueSecureInputBuffer;
- MediaCodecStatus QueueSecureInputBuffer(
- int index,
- const uint8_t* data,
- size_t data_size,
- const std::vector<char>& key_id,
- const std::vector<char>& iv,
- const SubsampleEntry* subsamples,
- int subsamples_size,
- const base::TimeDelta& presentation_time) override;
- void QueueEOS(int input_buffer_index) override;
- MediaCodecStatus DequeueInputBuffer(const base::TimeDelta& timeout,
- int* index) override;
- MediaCodecStatus DequeueOutputBuffer(const base::TimeDelta& timeout,
- int* index,
- size_t* offset,
- size_t* size,
- base::TimeDelta* presentation_time,
- bool* end_of_stream,
- bool* key_frame) override;
- void ReleaseOutputBuffer(int index, bool render) override;
- int GetOutputBuffersCount() override;
- size_t GetOutputBuffersCapacity() override;
- void GetInputBuffer(int input_buffer_index,
- uint8_t** data,
- size_t* capacity) override;
- bool CopyFromOutputBuffer(int index,
- size_t offset,
- void* dst,
- int dst_size) override;
-
- static bool RegisterSdkMediaCodecBridge(JNIEnv* env);
-
- protected:
- SdkMediaCodecBridge(const std::string& mime,
- bool is_secure,
- MediaCodecDirection direction);
-
- // Called to get the buffer address given the output buffer index and offset.
- // This function returns the size of the output and |addr| is the pointer to
- // the address to read.
- int GetOutputBufferAddress(int index, size_t offset, void** addr);
-
- jobject media_codec() { return j_media_codec_.obj(); }
- MediaCodecDirection direction_;
-
- private:
- // Java MediaCodec instance.
- base::android::ScopedJavaGlobalRef<jobject> j_media_codec_;
-
- DISALLOW_COPY_AND_ASSIGN(SdkMediaCodecBridge);
-};
-
-// Class for handling audio decoding using android MediaCodec APIs.
-// TODO(qinmin): implement the logic to switch between NDK and SDK
-// MediaCodecBridge.
-class MEDIA_EXPORT AudioCodecBridge : public SdkMediaCodecBridge {
- public:
- // Returns an AudioCodecBridge instance if |codec| is supported, or a NULL
- // pointer otherwise.
- static AudioCodecBridge* Create(const AudioCodec& codec);
-
- // See MediaCodecUtil::IsKnownUnaccelerated().
- static bool IsKnownUnaccelerated(const AudioCodec& codec);
-
- // Start the audio codec bridge.
- bool 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,
- bool play_audio,
- jobject media_crypto) WARN_UNUSED_RESULT;
-
- // Plays the output buffer right away or save for later playback if |postpone|
- // is set to true. This call must be called after DequeueOutputBuffer() and
- // before ReleaseOutputBuffer. The data is extracted from the output buffers
- // using |index|, |size| and |offset|. Returns the playback head position
- // expressed in frames.
- // When |postpone| is set to true, the next PlayOutputBuffer() should have
- // postpone == false, and it will play two buffers: the postponed one and
- // the one identified by |index|.
- int64_t PlayOutputBuffer(int index,
- size_t size,
- size_t offset,
- bool postpone = false);
-
- // Set the volume of the audio output.
- void SetVolume(double volume);
-
- private:
- explicit AudioCodecBridge(const std::string& mime);
-
- // Configure the java MediaFormat object with the extra codec data passed in.
- bool 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);
-};
-
-// Class for handling video encoding/decoding using android MediaCodec APIs.
-// TODO(qinmin): implement the logic to switch between NDK and SDK
-// MediaCodecBridge.
-class MEDIA_EXPORT VideoCodecBridge : public SdkMediaCodecBridge {
- public:
- // See MediaCodecUtil::IsKnownUnaccelerated().
- static bool IsKnownUnaccelerated(const VideoCodec& codec,
- MediaCodecDirection direction);
-
- // Create, start, and return a VideoCodecBridge decoder or NULL on failure.
- static VideoCodecBridge* CreateDecoder(
- const VideoCodec& codec, // e.g. media::kCodecVP8
- bool is_secure,
- const gfx::Size& size, // Output frame size.
- jobject surface, // Output surface, optional.
- jobject media_crypto); // MediaCrypto object, optional.
-
- // Create, start, and return a VideoCodecBridge encoder or NULL on failure.
- static VideoCodecBridge* CreateEncoder(
- const VideoCodec& codec, // e.g. media::kCodecVP8
- const gfx::Size& size, // input frame size
- int bit_rate, // bits/second
- int frame_rate, // frames/second
- int i_frame_interval, // count
- int color_format); // MediaCodecInfo.CodecCapabilities.
-
- void SetVideoBitrate(int bps);
- void RequestKeyFrameSoon();
-
- // Returns whether adaptive playback is supported for this object given
- // the new size.
- bool IsAdaptivePlaybackSupported(int width, int height);
-
- // Test-only method to set the return value of IsAdaptivePlaybackSupported().
- // Without this function, the return value of that function will be device
- // dependent. If |adaptive_playback_supported| is equal to 0, the return value
- // will be false. If |adaptive_playback_supported| is larger than 0, the
- // return value will be true.
- void set_adaptive_playback_supported_for_testing(
- int adaptive_playback_supported) {
- adaptive_playback_supported_for_testing_ = adaptive_playback_supported;
- }
-
- private:
- VideoCodecBridge(const std::string& mime,
- bool is_secure,
- MediaCodecDirection direction);
-
- int adaptive_playback_supported_for_testing_;
-};
-
-} // namespace media
-
-#endif // MEDIA_BASE_ANDROID_SDK_MEDIA_CODEC_BRIDGE_H_
diff --git a/media/base/android/sdk_media_codec_bridge_unittest.cc b/media/base/android/sdk_media_codec_bridge_unittest.cc
deleted file mode 100644
index 2f6274f..0000000
--- a/media/base/android/sdk_media_codec_bridge_unittest.cc
+++ /dev/null
@@ -1,300 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "media/base/android/media_codec_util.h"
-#include "media/base/android/sdk_media_codec_bridge.h"
-#include "media/base/decoder_buffer.h"
-#include "media/base/test_data_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace {
-
-// The first frame of
-// http://www.html5rocks.com/en/tutorials/audio/quick/test.mp3
-unsigned char test_mp3[] = {
- 0xff, 0xfb, 0xd2, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x05, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x0d, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x7e, 0x40,
- 0xc0, 0x19, 0x4a, 0x80, 0x0d, 0x60, 0x48, 0x1b, 0x40, 0xf7, 0xbd, 0xb9,
- 0xd9, 0x40, 0x6f, 0x82, 0x01, 0x8b, 0x17, 0xa0, 0x80, 0xc5, 0x01, 0xad,
- 0x9a, 0xd3, 0x00, 0x12, 0xc0, 0x72, 0x93, 0x67, 0xd0, 0x03, 0x6f, 0xa4,
- 0xc0, 0xc3, 0x23, 0xee, 0x9b, 0xc0, 0xcc, 0x02, 0xa0, 0xa1, 0x30, 0x0c,
- 0x52, 0x2d, 0xfd, 0x6e, 0x08, 0x83, 0x60, 0x40, 0x46, 0x06, 0x4b, 0x20,
- 0x82, 0x82, 0x7f, 0xd4, 0x81, 0xe7, 0x00, 0x64, 0x20, 0x18, 0xec, 0xc2,
- 0x06, 0x57, 0x0f, 0x81, 0x93, 0x0b, 0x00, 0x66, 0xe3, 0xb7, 0xe8, 0x32,
- 0x6e, 0xf0, 0x32, 0xb0, 0x58, 0x0c, 0x7c, 0x3a, 0x03, 0x22, 0x14, 0x80,
- 0xc9, 0x01, 0x80, 0x30, 0x20, 0x14, 0x0c, 0x96, 0x73, 0xfe, 0x9f, 0x6c,
- 0x0c, 0xd2, 0x25, 0x0f, 0xdc, 0x0c, 0x32, 0x43, 0x03, 0x27, 0x87, 0xc0,
- 0xc2, 0xc0, 0x20, 0xfc, 0x42, 0xc5, 0xff, 0xff, 0xd4, 0x80, 0x01, 0x01,
- 0x80, 0xc3, 0x81, 0x01, 0x95, 0x03, 0x28, 0x82, 0xc0, 0xc3, 0x01, 0xa1,
- 0x06, 0x81, 0x87, 0xc2, 0x40, 0x64, 0xc1, 0xf0, 0x12, 0x02, 0xff, 0xf6,
- 0x5b, 0x9f, 0x44, 0xdc, 0xdd, 0x0b, 0x38, 0x59, 0xe0, 0x31, 0x71, 0x60,
- 0x0c, 0xb4, 0x22, 0x03, 0x3b, 0x96, 0x40, 0xc8, 0x63, 0x90, 0x0a, 0x23,
- 0x81, 0x9e, 0x4c, 0x20, 0x65, 0xb3, 0x18, 0x19, 0x6c, 0x42, 0x06, 0x36,
- 0x1d, 0x01, 0x90, 0x87, 0xdf, 0xff, 0xd0, 0x65, 0xa6, 0xea, 0x66, 0xfd,
- 0x40, 0x0c, 0x48, 0x03, 0x1a, 0x09, 0x01, 0x21, 0x98, 0x19, 0x2c, 0x36,
- 0x06, 0x43, 0x21, 0x81, 0x92, 0xca, 0x60, 0x64, 0x70, 0xb8, 0x19, 0x20,
- 0x6c, 0x02, 0x83, 0x80, 0xcb, 0x60, 0x65, 0x32, 0x28, 0x18, 0x64, 0x24,
- 0x06, 0x3a, 0x0c, 0x00, 0xe1, 0x00, 0x18, 0xd0, 0x35, 0xff, 0xff, 0xff,
- 0xe8, 0x32, 0xef, 0xb2, 0x90, 0x65, 0xbb, 0xdd, 0x94, 0x82, 0x0b, 0x4c,
- 0xfa, 0x25, 0xf3, 0x74, 0x13, 0x0f, 0xf8, 0x19, 0x28, 0x84, 0x06, 0x36,
- 0x11, 0x01, 0x20, 0x80, 0x18, 0xb4, 0x52, 0x0e, 0x15, 0x00, 0x30, 0x50,
- 0x0c, 0x84, 0x32, 0x03, 0x11, 0x04, 0x03, 0x48, 0x04, 0x00, 0x00, 0x31,
- 0x21, 0x00, 0x0c, 0x84, 0x18, 0x03, 0x07, 0x85, 0x40, 0xc6, 0xa5, 0x70,
- 0x32, 0xb8, 0x7c, 0x0c, 0x54, 0x04, 0x00, 0xd0, 0x08, 0x59, 0x58, 0x18,
- 0x20, 0x14, 0x06, 0x30, 0x30, 0x01, 0x9b, 0x86, 0x00, 0x6b, 0x54, 0xa8,
- 0x19, 0x8c, 0x2a, 0x06, 0x16, 0x09, 0x01, 0xa0, 0xd0, 0xa0, 0x69, 0x74,
- 0xb8, 0x19, 0xc4, 0x4a, 0xa3, 0xda, 0x9d, 0x1e, 0x4f, 0x05, 0xc0, 0x5b,
- 0x0b, 0x03, 0xc2, 0x76, 0xa3, 0x4f, 0xb9, 0x16, 0xc2, 0x70, 0x41, 0x07,
- 0xa0, 0x84, 0x16, 0x38, 0x4a, 0xc8, 0xaf, 0xee, 0x7f, 0x93, 0xb5, 0x5c,
- 0x39, 0x1e, 0x29, 0xd9, 0x8c, 0x80, 0xb5, 0x80, 0xe6, 0x85, 0xb2, 0x99,
- 0x68, 0x85, 0x46, 0x91, 0x60, 0xdb, 0x06, 0xfa, 0x38, 0x7a, 0xc7, 0xac,
- 0x85, 0xa8, 0xd3, 0xe6, 0x99, 0x3b, 0x66, 0x43, 0x23, 0x1f, 0x84, 0xe1,
- 0x65, 0x5e, 0xbc, 0x84, 0x18, 0x62, 0xe6, 0x42, 0x0b, 0x82, 0xe4, 0xd3,
- 0x42, 0xd2, 0x05, 0x81, 0x4e, 0xe4, 0x9f, 0x8c, 0xc8, 0x7f, 0xa3, 0xe0,
- 0x8d, 0xf1, 0x0f, 0x38, 0xe5, 0x3f, 0xc4, 0x2c, 0x24, 0x65, 0x8d, 0xb9,
- 0x58, 0xac, 0x39, 0x0e, 0x37, 0x99, 0x2e, 0x85, 0xe0, 0xb7, 0x98, 0x41,
- 0x20, 0x38, 0x1b, 0x95, 0x07, 0xfa, 0xa8, 0x9c, 0x21, 0x0f, 0x13, 0x8c,
- 0xa5, 0xc1, 0x76, 0xae, 0x0b, 0xc1, 0x30, 0x27, 0x08, 0xc1, 0xf6, 0x4d,
- 0xce, 0xb4, 0x41, 0x38, 0x1e, 0x82, 0x10, 0x74, 0x45, 0x91, 0x90, 0xff,
- 0x41, 0x8b, 0x62, 0x1a, 0x71, 0xb6, 0x45, 0x63, 0x8c, 0xce, 0xb8, 0x54,
- 0x1b, 0xe8, 0x5d, 0x9e, 0x35, 0x9d, 0x6c, 0xac, 0xe8, 0x83, 0xa1, 0xe9,
- 0x3f, 0x13, 0x74, 0x11, 0x04, 0x10, 0xf1, 0x37, 0x38, 0xc6, 0x00, 0x60,
- 0x27, 0x48, 0x38, 0x85, 0x92, 0x76, 0xb7, 0xf3, 0xa7, 0x1c, 0x4b, 0xf9,
- 0x3b, 0x5a, 0x88, 0xac, 0x60, 0x1b, 0x85, 0x81, 0x16, 0xab, 0x44, 0x17,
- 0x08, 0x2e, 0x0f, 0xd4, 0xe2, 0xde, 0x49, 0xc9, 0xe1, 0xc0, 0xc0, 0xa0,
- 0x7e, 0x73, 0xa1, 0x67, 0xf8, 0xf5, 0x9f, 0xc4, 0x21, 0x50, 0x4f, 0x05,
- 0x2c, 0xfc, 0x5c, 0xaa, 0x85, 0xb0, 0xfa, 0x67, 0x80, 0x7e, 0x0f, 0xfd,
- 0x92, 0x30, 0xd5, 0xa0, 0xd4, 0x05, 0xdd, 0x06, 0x68, 0x1d, 0x6e, 0x4e,
- 0x8b, 0x79, 0xd6, 0xfc, 0xff, 0x2e, 0x6e, 0x7c, 0xba, 0x03, 0x90, 0xd4,
- 0x25, 0x65, 0x8e, 0xe7, 0x3a, 0xd1, 0xd6, 0xdc, 0xf0, 0xbe, 0x12, 0xc4,
- 0x31, 0x08, 0x16, 0x70, 0x31, 0x85, 0x61, 0x38, 0x27, 0x0a, 0x91, 0x5f,
- 0x03, 0x38, 0xeb, 0x37, 0x13, 0x48, 0x41, 0xbe, 0x7f, 0x04, 0x70, 0x62,
- 0x2b, 0x15, 0x91, 0x67, 0x63, 0x4f, 0xad, 0xa7, 0x1d, 0x3f, 0x44, 0x17,
- 0x02, 0x08, 0x0d, 0xf2, 0xfc, 0x03, 0xa0, 0x74, 0x21, 0x8b, 0x07, 0x3a,
- 0x8d, 0x0f, 0x54, 0x58, 0x94, 0x12, 0xc5, 0x62, 0x18, 0xb9, 0x42, 0xf0,
- 0x6c, 0x73, 0xa0, 0x92, 0xad, 0x27, 0x1c, 0x20, 0x0f, 0xc1, 0xca, 0x44,
- 0x87, 0x47, 0xc5, 0x43, 0x23, 0x01, 0xda, 0x23, 0xe2, 0x89, 0x38, 0x9f,
- 0x1f, 0x8d, 0x8c, 0xc6, 0x95, 0xa3, 0x34, 0x21, 0x21, 0x2d, 0x49, 0xea,
- 0x4b, 0x05, 0x85, 0xf5, 0x58, 0x25, 0x13, 0xcd, 0x51, 0x19, 0x1a, 0x88,
- 0xa6, 0x83, 0xd6, 0xd0, 0xbc, 0x25, 0x19, 0x1c, 0x92, 0x12, 0x44, 0x5d,
- 0x1c, 0x04, 0xf1, 0x99, 0xdf, 0x92, 0x8e, 0x09, 0x85, 0xf3, 0x88, 0x82,
- 0x4c, 0x22, 0x17, 0xc5, 0x25, 0x23, 0xed, 0x78, 0xf5, 0x41, 0xd1, 0xe9,
- 0x8a, 0xb3, 0x52, 0xd1, 0x3d, 0x79, 0x81, 0x4d, 0x31, 0x24, 0xf9, 0x38,
- 0x96, 0xbc, 0xf4, 0x8c, 0x25, 0xe9, 0xf2, 0x73, 0x94, 0x85, 0xc2, 0x61,
- 0x6a, 0x34, 0x68, 0x65, 0x78, 0x87, 0xa6, 0x4f};
-
-} // namespace
-
-namespace media {
-
-// Helper macro to skip the test if MediaCodecBridge isn't available.
-#define SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE() \
- do { \
- if (!MediaCodecUtil::IsMediaCodecAvailable()) { \
- VLOG(0) << "Could not run test - not supported on device."; \
- return; \
- } \
- } while (0)
-
-static const int kPresentationTimeBase = 100;
-
-static inline const base::TimeDelta InfiniteTimeOut() {
- return base::TimeDelta::FromMicroseconds(-1);
-}
-
-void DecodeMediaFrame(VideoCodecBridge* media_codec,
- const uint8* data,
- size_t data_size,
- const base::TimeDelta input_presentation_timestamp,
- const base::TimeDelta initial_timestamp_lower_bound) {
- base::TimeDelta input_pts = input_presentation_timestamp;
- base::TimeDelta timestamp = initial_timestamp_lower_bound;
- base::TimeDelta new_timestamp;
- for (int i = 0; i < 10; ++i) {
- int input_buf_index = -1;
- MediaCodecStatus status =
- media_codec->DequeueInputBuffer(InfiniteTimeOut(), &input_buf_index);
- ASSERT_EQ(MEDIA_CODEC_OK, status);
-
- media_codec->QueueInputBuffer(input_buf_index, data, data_size,
- input_presentation_timestamp);
-
- size_t unused_offset = 0;
- size_t size = 0;
- bool eos = false;
- int output_buf_index = -1;
- status = media_codec->DequeueOutputBuffer(
- InfiniteTimeOut(), &output_buf_index, &unused_offset, &size,
- &new_timestamp, &eos, nullptr);
-
- if (status == MEDIA_CODEC_OK && output_buf_index > 0) {
- media_codec->ReleaseOutputBuffer(output_buf_index, false);
- }
- // Output time stamp should not be smaller than old timestamp.
- ASSERT_TRUE(new_timestamp >= timestamp);
- input_pts += base::TimeDelta::FromMicroseconds(33000);
- timestamp = new_timestamp;
- }
-}
-
-TEST(SdkMediaCodecBridgeTest, Initialize) {
- SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
-
- scoped_ptr<media::MediaCodecBridge> media_codec;
- media_codec.reset(VideoCodecBridge::CreateDecoder(
- kCodecH264, false, gfx::Size(640, 480), nullptr, nullptr));
-}
-
-TEST(SdkMediaCodecBridgeTest, DoNormal) {
- SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
-
- scoped_ptr<media::AudioCodecBridge> media_codec;
- media_codec.reset(AudioCodecBridge::Create(kCodecMP3));
-
- ASSERT_TRUE(media_codec->ConfigureAndStart(kCodecMP3, 44100, 2, nullptr, 0, 0,
- 0, false, nullptr));
-
- int input_buf_index = -1;
- MediaCodecStatus status =
- media_codec->DequeueInputBuffer(InfiniteTimeOut(), &input_buf_index);
- ASSERT_EQ(MEDIA_CODEC_OK, status);
- ASSERT_GE(input_buf_index, 0);
-
- int64 input_pts = kPresentationTimeBase;
- media_codec->QueueInputBuffer(input_buf_index, test_mp3, sizeof(test_mp3),
- base::TimeDelta::FromMicroseconds(++input_pts));
-
- status = media_codec->DequeueInputBuffer(InfiniteTimeOut(), &input_buf_index);
- media_codec->QueueInputBuffer(input_buf_index, test_mp3, sizeof(test_mp3),
- base::TimeDelta::FromMicroseconds(++input_pts));
-
- status = media_codec->DequeueInputBuffer(InfiniteTimeOut(), &input_buf_index);
- media_codec->QueueEOS(input_buf_index);
-
- input_pts = kPresentationTimeBase;
- bool eos = false;
- while (!eos) {
- size_t unused_offset = 0;
- size_t size = 0;
- base::TimeDelta timestamp;
- int output_buf_index = -1;
- status = media_codec->DequeueOutputBuffer(InfiniteTimeOut(),
- &output_buf_index, &unused_offset,
- &size, &timestamp, &eos, nullptr);
- switch (status) {
- case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
- FAIL();
- return;
-
- case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
- continue;
-
- case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED:
- continue;
-
- default:
- break;
- }
- ASSERT_GE(output_buf_index, 0);
- EXPECT_LE(1u, size);
- if (!eos)
- EXPECT_EQ(++input_pts, timestamp.InMicroseconds());
- ASSERT_LE(input_pts, kPresentationTimeBase + 2);
- }
- ASSERT_EQ(input_pts, kPresentationTimeBase + 2);
-}
-
-TEST(SdkMediaCodecBridgeTest, InvalidVorbisHeader) {
- SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
-
- scoped_ptr<media::AudioCodecBridge> media_codec;
- media_codec.reset(AudioCodecBridge::Create(kCodecVorbis));
-
- // The first byte of the header is not 0x02.
- uint8 invalid_first_byte[] = {0x00, 0xff, 0xff, 0xff, 0xff};
- EXPECT_FALSE(media_codec->ConfigureAndStart(
- kCodecVorbis, 44100, 2, invalid_first_byte, sizeof(invalid_first_byte), 0,
- 0, false, nullptr));
-
- // Size of the header does not match with the data we passed in.
- uint8 invalid_size[] = {0x02, 0x01, 0xff, 0x01, 0xff};
- EXPECT_FALSE(media_codec->ConfigureAndStart(
- kCodecVorbis, 44100, 2, invalid_size, sizeof(invalid_size), 0, 0, false,
- nullptr));
-
- // Size of the header is too large.
- size_t large_size = 8 * 1024 * 1024 + 2;
- uint8* very_large_header = new uint8[large_size];
- very_large_header[0] = 0x02;
- for (size_t i = 1; i < large_size - 1; ++i)
- very_large_header[i] = 0xff;
- very_large_header[large_size - 1] = 0xfe;
- EXPECT_FALSE(media_codec->ConfigureAndStart(kCodecVorbis, 44100, 2,
- very_large_header, 0x80000000, 0,
- 0, false, nullptr));
- delete[] very_large_header;
-}
-
-TEST(SdkMediaCodecBridgeTest, InvalidOpusHeader) {
- SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
-
- scoped_ptr<media::AudioCodecBridge> media_codec;
- media_codec.reset(AudioCodecBridge::Create(kCodecOpus));
- uint8 dummy_extra_data[] = {0, 0};
-
- // Extra Data is NULL.
- EXPECT_FALSE(media_codec->ConfigureAndStart(kCodecOpus, 48000, 2, nullptr, 0,
- -1, 0, false, nullptr));
-
- // Codec Delay is < 0.
- EXPECT_FALSE(media_codec->ConfigureAndStart(
- kCodecOpus, 48000, 2, dummy_extra_data, sizeof(dummy_extra_data), -1, 0,
- false, nullptr));
-
- // Seek Preroll is < 0.
- EXPECT_FALSE(media_codec->ConfigureAndStart(
- kCodecOpus, 48000, 2, dummy_extra_data, sizeof(dummy_extra_data), 0, -1,
- false, nullptr));
-}
-
-TEST(SdkMediaCodecBridgeTest, PresentationTimestampsDoNotDecrease) {
- SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
-
- scoped_ptr<VideoCodecBridge> media_codec(VideoCodecBridge::CreateDecoder(
- kCodecVP8, false, gfx::Size(320, 240), nullptr, nullptr));
- EXPECT_TRUE(media_codec.get());
- scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile("vp8-I-frame-320x240");
- DecodeMediaFrame(media_codec.get(), buffer->data(), buffer->data_size(),
- base::TimeDelta(), base::TimeDelta());
-
- // Simulate a seek to 10 seconds, and each chunk has 2 I-frames.
- std::vector<uint8> chunk(buffer->data(),
- buffer->data() + buffer->data_size());
- chunk.insert(chunk.end(), buffer->data(),
- buffer->data() + buffer->data_size());
- media_codec->Reset();
- DecodeMediaFrame(media_codec.get(), &chunk[0], chunk.size(),
- base::TimeDelta::FromMicroseconds(10000000),
- base::TimeDelta::FromMicroseconds(9900000));
-
- // Simulate a seek to 5 seconds.
- media_codec->Reset();
- DecodeMediaFrame(media_codec.get(), &chunk[0], chunk.size(),
- base::TimeDelta::FromMicroseconds(5000000),
- base::TimeDelta::FromMicroseconds(4900000));
-}
-
-TEST(SdkMediaCodecBridgeTest, CreateUnsupportedCodec) {
- EXPECT_EQ(nullptr, AudioCodecBridge::Create(kUnknownAudioCodec));
- EXPECT_EQ(nullptr, VideoCodecBridge::CreateDecoder(kUnknownVideoCodec, false,
- gfx::Size(320, 240),
- nullptr, nullptr));
-}
-
-} // namespace media
diff --git a/media/base/android/video_decoder_job.cc b/media/base/android/video_decoder_job.cc
index 3dfe3b8..cec1b39 100644
--- a/media/base/android/video_decoder_job.cc
+++ b/media/base/android/video_decoder_job.cc
@@ -7,8 +7,8 @@
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/threading/thread.h"
+#include "media/base/android/media_codec_bridge.h"
#include "media/base/android/media_drm_bridge.h"
-#include "media/base/android/sdk_media_codec_bridge.h"
namespace media {
diff --git a/media/media.gyp b/media/media.gyp
index 70be514..dbd452d 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -1187,12 +1187,12 @@
],
'sources': [
'base/android/access_unit_queue_unittest.cc',
+ 'base/android/media_codec_bridge_unittest.cc',
'base/android/media_codec_decoder_unittest.cc',
'base/android/media_codec_player_unittest.cc',
'base/android/media_drm_bridge_unittest.cc',
'base/android/media_player_bridge_unittest.cc',
'base/android/media_source_player_unittest.cc',
- 'base/android/sdk_media_codec_bridge_unittest.cc',
'base/android/test_data_factory.cc',
'base/android/test_data_factory.h',
'base/android/test_statistics.h',
@@ -1813,7 +1813,6 @@
'base/android/java/src/org/chromium/media/AudioManagerAndroid.java',
'base/android/java/src/org/chromium/media/AudioRecordInput.java',
'base/android/java/src/org/chromium/media/MediaCodecBridge.java',
- 'base/android/java/src/org/chromium/media/MediaCodecUtil.java',
'base/android/java/src/org/chromium/media/MediaDrmBridge.java',
'base/android/java/src/org/chromium/media/MediaPlayerBridge.java',
'base/android/java/src/org/chromium/media/MediaPlayerListener.java',
@@ -1863,8 +1862,6 @@
'base/android/media_codec_player.h',
'base/android/media_codec_video_decoder.cc',
'base/android/media_codec_video_decoder.h',
- 'base/android/media_codec_util.cc',
- 'base/android/media_codec_util.h',
'base/android/media_common_android.h',
'base/android/media_decoder_job.cc',
'base/android/media_decoder_job.h',
@@ -1891,28 +1888,12 @@
'base/android/media_task_runner.h',
'base/android/media_url_interceptor.h',
'base/android/provision_fetcher.h',
- 'base/android/sdk_media_codec_bridge.cc',
- 'base/android/sdk_media_codec_bridge.h',
'base/android/video_decoder_job.cc',
'base/android/video_decoder_job.h',
'base/android/webaudio_media_codec_bridge.cc',
'base/android/webaudio_media_codec_bridge.h',
'base/android/webaudio_media_codec_info.h',
],
- 'conditions': [
- # Only 64 bit builds are using android-21 NDK library, check common.gypi
- ['target_arch=="arm64" or target_arch=="x64" or target_arch=="mips64el"', {
- 'sources': [
- 'base/android/ndk_media_codec_bridge.cc',
- 'base/android/ndk_media_codec_bridge.h',
- ],
- 'link_settings': {
- 'libraries': [
- '-lmediandk',
- ],
- },
- }],
- ],
'dependencies': [
'../base/base.gyp:base',
'../third_party/widevine/cdm/widevine_cdm.gyp:widevine_cdm_version_h',