summaryrefslogtreecommitdiff
path: root/media/base/android
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2013-05-09 18:35:53 +0100
committerTorne (Richard Coles) <torne@google.com>2013-05-13 13:57:14 +0100
commitc2e0dbddbe15c98d52c4786dac06cb8952a8ae6d (patch)
tree1dbdbb0624cc869ab25ee7f46971984c6fee3e7a /media/base/android
parent2d519ce2457219605d4f472da8d2ffd469796035 (diff)
downloadchromium_org-c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d.tar.gz
Merge from Chromium at DEPS revision r198571
This commit was generated by merge_to_master.py. Change-Id: I951118a03836157090561764dd2627f0add8118f
Diffstat (limited to 'media/base/android')
-rw-r--r--media/base/android/OWNERS2
-rw-r--r--media/base/android/demuxer_stream_player_params.cc32
-rw-r--r--media/base/android/demuxer_stream_player_params.h61
-rw-r--r--media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java24
-rw-r--r--media/base/android/java/src/org/chromium/media/VideoCapture.java4
-rw-r--r--media/base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java165
-rw-r--r--media/base/android/media_codec_bridge.cc111
-rw-r--r--media/base/android/media_codec_bridge.h46
-rw-r--r--media/base/android/media_codec_bridge_unittest.cc8
-rw-r--r--media/base/android/media_jni_registrar.cc9
-rw-r--r--media/base/android/media_player_bridge.cc173
-rw-r--r--media/base/android/media_player_bridge.h92
-rw-r--r--media/base/android/media_player_manager.cc (renamed from media/base/android/media_player_bridge_manager.cc)4
-rw-r--r--media/base/android/media_player_manager.h (renamed from media/base/android/media_player_bridge_manager.h)17
-rw-r--r--media/base/android/media_resource_getter.h10
-rw-r--r--media/base/android/webaudio_media_codec_bridge.cc131
-rw-r--r--media/base/android/webaudio_media_codec_bridge.h73
-rw-r--r--media/base/android/webaudio_media_codec_info.h20
18 files changed, 834 insertions, 148 deletions
diff --git a/media/base/android/OWNERS b/media/base/android/OWNERS
index 25a5e6b4e2..e604870cbb 100644
--- a/media/base/android/OWNERS
+++ b/media/base/android/OWNERS
@@ -1,3 +1,3 @@
bulach@chromium.org
jcivelli@chromium.org
-yfriedman@chromium.org
+qinmin@chromium.org
diff --git a/media/base/android/demuxer_stream_player_params.cc b/media/base/android/demuxer_stream_player_params.cc
new file mode 100644
index 0000000000..ab9fcafaf5
--- /dev/null
+++ b/media/base/android/demuxer_stream_player_params.cc
@@ -0,0 +1,32 @@
+// 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/demuxer_stream_player_params.h"
+
+namespace media {
+
+MediaPlayerHostMsg_DemuxerReady_Params::
+ MediaPlayerHostMsg_DemuxerReady_Params()
+ : audio_channels(0),
+ audio_sampling_rate(0),
+ is_audio_encrypted(false),
+ is_video_encrypted(false),
+ duration_ms(0) {}
+
+MediaPlayerHostMsg_DemuxerReady_Params::
+ ~MediaPlayerHostMsg_DemuxerReady_Params() {}
+
+MediaPlayerHostMsg_ReadFromDemuxerAck_Params::
+ MediaPlayerHostMsg_ReadFromDemuxerAck_Params()
+ : type(DemuxerStream::UNKNOWN) {}
+
+MediaPlayerHostMsg_ReadFromDemuxerAck_Params::
+ ~MediaPlayerHostMsg_ReadFromDemuxerAck_Params() {}
+
+MediaPlayerHostMsg_ReadFromDemuxerAck_Params::AccessUnit::AccessUnit()
+ : end_of_stream(false) {}
+
+MediaPlayerHostMsg_ReadFromDemuxerAck_Params::AccessUnit::~AccessUnit() {}
+
+} // namespace media
diff --git a/media/base/android/demuxer_stream_player_params.h b/media/base/android/demuxer_stream_player_params.h
new file mode 100644
index 0000000000..face665b57
--- /dev/null
+++ b/media/base/android/demuxer_stream_player_params.h
@@ -0,0 +1,61 @@
+// 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_DEMUXER_STREAM_PLAYER_PARAMS_H_
+#define MEDIA_BASE_ANDROID_DEMUXER_STREAM_PLAYER_PARAMS_H_
+
+#include <string>
+#include <vector>
+
+#include "media/base/audio_decoder_config.h"
+#include "media/base/decrypt_config.h"
+#include "media/base/demuxer_stream.h"
+#include "media/base/media_export.h"
+#include "media/base/video_decoder_config.h"
+#include "ui/gfx/size.h"
+
+namespace media {
+
+struct MEDIA_EXPORT MediaPlayerHostMsg_DemuxerReady_Params {
+ MediaPlayerHostMsg_DemuxerReady_Params();
+ ~MediaPlayerHostMsg_DemuxerReady_Params();
+
+ AudioCodec audio_codec;
+ int audio_channels;
+ int audio_sampling_rate;
+ bool is_audio_encrypted;
+
+ VideoCodec video_codec;
+ gfx::Size video_size;
+ bool is_video_encrypted;
+
+ int duration_ms;
+ std::string key_system;
+};
+
+struct MEDIA_EXPORT MediaPlayerHostMsg_ReadFromDemuxerAck_Params {
+ struct MEDIA_EXPORT AccessUnit {
+ AccessUnit();
+ ~AccessUnit();
+
+ DemuxerStream::Status status;
+ bool end_of_stream;
+ // TODO(ycheo): Use the shared memory to transfer the block data.
+ std::vector<unsigned char> data;
+ base::TimeDelta timestamp;
+ std::vector<char> key_id;
+ std::vector<char> iv;
+ std::vector<media::SubsampleEntry> subsamples;
+ };
+
+ MediaPlayerHostMsg_ReadFromDemuxerAck_Params();
+ ~MediaPlayerHostMsg_ReadFromDemuxerAck_Params();
+
+ DemuxerStream::Type type;
+ std::vector<AccessUnit> access_units;
+};
+
+}; // namespace media
+
+#endif // MEDIA_BASE_ANDROID_DEMUXER_STREAM_PLAYER_PARAMS_H_
diff --git a/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java b/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
index ee6f46ea9e..9066380d62 100644
--- a/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
+++ b/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
@@ -9,6 +9,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
+import android.os.Build;
+import android.util.Log;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
@@ -25,7 +27,12 @@ class AudioManagerAndroid {
@CalledByNative
public void setMode(int mode) {
- mAudioManager.setMode(mode);
+ try {
+ mAudioManager.setMode(mode);
+ } catch (SecurityException e) {
+ Log.e(TAG, "setMode exception: " + e.getMessage());
+ logDeviceInfo();
+ }
}
@CalledByNative
@@ -51,8 +58,13 @@ class AudioManagerAndroid {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_HEADSET_PLUG.equals(intent.getAction())) {
- mAudioManager.setSpeakerphoneOn(
- intent.getIntExtra("state", 0) == 0);
+ try {
+ mAudioManager.setSpeakerphoneOn(
+ intent.getIntExtra("state", 0) == 0);
+ } catch (SecurityException e) {
+ Log.e(TAG, "setMode exception: " + e.getMessage());
+ logDeviceInfo();
+ }
}
}
};
@@ -65,4 +77,10 @@ class AudioManagerAndroid {
mReceiver = null;
mAudioManager.setSpeakerphoneOn(mOriginalSpeakerStatus);
}
+
+ private void logDeviceInfo() {
+ Log.i(TAG, "Manufacturer:" + Build.MANUFACTURER +
+ " Board: " + Build.BOARD + " Device: " + Build.DEVICE +
+ " Model: " + Build.MODEL + " PRODUCT: " + Build.PRODUCT);
+ }
}
diff --git a/media/base/android/java/src/org/chromium/media/VideoCapture.java b/media/base/android/java/src/org/chromium/media/VideoCapture.java
index 0266558ca7..150f3b6946 100644
--- a/media/base/android/java/src/org/chromium/media/VideoCapture.java
+++ b/media/base/android/java/src/org/chromium/media/VideoCapture.java
@@ -251,8 +251,8 @@ public class VideoCapture implements PreviewCallback, OnFrameAvailableListener {
stopCapture();
try {
mCamera.setPreviewTexture(null);
- mSurfaceTexture.setOnFrameAvailableListener(null);
- GLES20.glDeleteTextures(1, mGlTextures, 0);
+ if (mGlTextures != null)
+ GLES20.glDeleteTextures(1, mGlTextures, 0);
mCurrentCapability = null;
mCamera.release();
mCamera = null;
diff --git a/media/base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java
new file mode 100644
index 0000000000..25596933b1
--- /dev/null
+++ b/media/base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java
@@ -0,0 +1,165 @@
+// 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.
+
+package org.chromium.media;
+
+import android.content.Context;
+import android.media.AudioFormat;
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import java.nio.ByteBuffer;
+import android.os.ParcelFileDescriptor;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
+
+@JNINamespace("media")
+class WebAudioMediaCodecBridge {
+ private static final boolean DEBUG = true;
+ static final String LOG_TAG = "WebAudioMediaCodec";
+ // TODO(rtoy): What is the correct timeout value for reading
+ // from a file in memory?
+ static final long TIMEOUT_MICROSECONDS = 500;
+ @CalledByNative
+ private static boolean decodeAudioFile(Context ctx,
+ int nativeMediaCodecBridge,
+ int inputFD,
+ long dataSize) {
+
+ if (dataSize < 0 || dataSize > 0x7fffffff)
+ return false;
+
+ MediaExtractor extractor = new MediaExtractor();
+
+ ParcelFileDescriptor encodedFD;
+ encodedFD = ParcelFileDescriptor.adoptFd(inputFD);
+ try {
+ extractor.setDataSource(encodedFD.getFileDescriptor(), 0, dataSize);
+ } catch (Exception e) {
+ e.printStackTrace();
+ encodedFD.detachFd();
+ return false;
+ }
+
+ if (extractor.getTrackCount() <= 0) {
+ encodedFD.detachFd();
+ return false;
+ }
+
+ MediaFormat format = extractor.getTrackFormat(0);
+
+ int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
+ int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
+ String mime = format.getString(MediaFormat.KEY_MIME);
+
+ long durationMicroseconds = 0;
+ if (format.containsKey(MediaFormat.KEY_DURATION)) {
+ try {
+ durationMicroseconds = format.getLong(MediaFormat.KEY_DURATION);
+ } catch (Exception e) {
+ Log.d(LOG_TAG, "Cannot get duration");
+ }
+ }
+
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Tracks: " + extractor.getTrackCount()
+ + " Rate: " + sampleRate
+ + " Channels: " + channelCount
+ + " Mime: " + mime
+ + " Duration: " + durationMicroseconds + " microsec");
+ }
+
+ nativeInitializeDestination(nativeMediaCodecBridge,
+ channelCount,
+ sampleRate,
+ durationMicroseconds);
+
+ // Create decoder
+ MediaCodec codec = MediaCodec.createDecoderByType(mime);
+ codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
+ codec.start();
+
+ ByteBuffer[] codecInputBuffers = codec.getInputBuffers();
+ ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers();
+
+ // A track must be selected and will be used to read samples.
+ extractor.selectTrack(0);
+
+ boolean sawInputEOS = false;
+ boolean sawOutputEOS = false;
+
+ // Keep processing until the output is done.
+ while (!sawOutputEOS) {
+ if (!sawInputEOS) {
+ // Input side
+ int inputBufIndex = codec.dequeueInputBuffer(TIMEOUT_MICROSECONDS);
+
+ if (inputBufIndex >= 0) {
+ ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
+ int sampleSize = extractor.readSampleData(dstBuf, 0);
+ long presentationTimeMicroSec = 0;
+
+ if (sampleSize < 0) {
+ sawInputEOS = true;
+ sampleSize = 0;
+ } else {
+ presentationTimeMicroSec = extractor.getSampleTime();
+ }
+
+ codec.queueInputBuffer(inputBufIndex,
+ 0, /* offset */
+ sampleSize,
+ presentationTimeMicroSec,
+ sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
+
+ if (!sawInputEOS) {
+ extractor.advance();
+ }
+ }
+ }
+
+ // Output side
+ MediaCodec.BufferInfo info = new BufferInfo();
+ final int outputBufIndex = codec.dequeueOutputBuffer(info, TIMEOUT_MICROSECONDS);
+
+ if (outputBufIndex >= 0) {
+ ByteBuffer buf = codecOutputBuffers[outputBufIndex];
+
+ if (info.size > 0) {
+ nativeOnChunkDecoded(nativeMediaCodecBridge, buf, info.size);
+ }
+
+ buf.clear();
+ codec.releaseOutputBuffer(outputBufIndex, false /* render */);
+
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ sawOutputEOS = true;
+ }
+ } else if (outputBufIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+ codecOutputBuffers = codec.getOutputBuffers();
+ }
+ }
+
+ encodedFD.detachFd();
+
+ codec.stop();
+ codec.release();
+ codec = null;
+
+ return true;
+ }
+
+ private static native void nativeOnChunkDecoded(
+ int nativeWebAudioMediaCodecBridge, ByteBuffer buf, int size);
+
+ private static native void nativeInitializeDestination(
+ int nativeWebAudioMediaCodecBridge,
+ int channelCount,
+ int sampleRate,
+ long durationMicroseconds);
+}
diff --git a/media/base/android/media_codec_bridge.cc b/media/base/android/media_codec_bridge.cc
index d66430da8a..e466654c41 100644
--- a/media/base/android/media_codec_bridge.cc
+++ b/media/base/android/media_codec_bridge.cc
@@ -32,7 +32,7 @@ static const char kMediaCodecBufferInfoClassPath[] =
static bool MediaCodecBufferInfo_RegisterNativesImpl(JNIEnv* env) {
g_MediaCodecBufferInfo_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
- base::android::GetUnscopedClass(env, kMediaCodecBufferInfoClassPath)));
+ base::android::GetClass(env, kMediaCodecBufferInfoClassPath).obj()));
base::android::CheckException(env);
return true;
}
@@ -97,12 +97,27 @@ namespace media {
enum { kBufferFlagEndOfStream = 4 };
-static const char* CodecToMimeType(const MediaCodecBridge::Codec codec) {
+static const char* AudioCodecToMimeType(const AudioCodec codec) {
switch (codec) {
- case MediaCodecBridge::AUDIO_MPEG: return "audio/mpeg";
- case MediaCodecBridge::VIDEO_H264: return "video/avc";
- case MediaCodecBridge::VIDEO_VP8: return "video/x-vnd.on2.vp8";
- default: return NULL;
+ case kCodecMP3:
+ return "audio/mpeg";
+ case kCodecVorbis:
+ return "audio/vorbis";
+ case kCodecAAC:
+ return "audio/mp4a-latm";
+ default:
+ return NULL;
+ }
+}
+
+static const char* VideoCodecToMimeType(const VideoCodec codec) {
+ switch (codec) {
+ case kCodecH264:
+ return "video/avc";
+ case kCodecVP8:
+ return "video/x-vnd.on2.vp8";
+ default:
+ return NULL;
}
}
@@ -120,14 +135,14 @@ bool MediaCodecBridge::IsAvailable() {
return base::android::BuildInfo::GetInstance()->sdk_int() >= 16;
}
-MediaCodecBridge::MediaCodecBridge(const Codec codec) {
+MediaCodecBridge::MediaCodecBridge(const char* mime) {
JNIEnv* env = AttachCurrentThread();
CHECK(env);
CHECK(g_native_registerer.Pointer()->IsRegistered());
- DCHECK(CodecToMimeType(codec));
+ DCHECK(mime);
ScopedJavaLocalRef<jstring> j_type =
- ConvertUTF8ToJavaString(env, CodecToMimeType(codec));
+ ConvertUTF8ToJavaString(env, mime);
ScopedJavaLocalRef<jobject> tmp(
JNI_MediaCodec::Java_MediaCodec_createDecoderByType(env, j_type.obj()));
@@ -142,43 +157,7 @@ MediaCodecBridge::~MediaCodecBridge() {
JNI_MediaCodec::Java_MediaCodec_release(env, j_media_codec_.obj());
}
-void MediaCodecBridge::StartAudio(
- const Codec codec, int sample_rate, int channel_count) {
- JNIEnv* env = AttachCurrentThread();
- DCHECK(CodecToMimeType(codec));
-
- ScopedJavaLocalRef<jstring> j_mime =
- ConvertUTF8ToJavaString(env, CodecToMimeType(codec));
- ScopedJavaLocalRef<jobject> j_format(
- JNI_MediaFormat::Java_MediaFormat_createAudioFormat(
- env, j_mime.obj(), sample_rate, channel_count));
- DCHECK(!j_format.is_null());
-
- JNI_MediaCodec::Java_MediaCodec_configure(
- env, j_media_codec_.obj(), j_format.obj(), NULL, NULL, 0);
-
- Start();
-}
-
-void MediaCodecBridge::StartVideo(
- const Codec codec, const gfx::Size& size, jobject surface) {
- JNIEnv* env = AttachCurrentThread();
- DCHECK(CodecToMimeType(codec));
-
- ScopedJavaLocalRef<jstring> j_mime =
- ConvertUTF8ToJavaString(env, CodecToMimeType(codec));
- ScopedJavaLocalRef<jobject> j_format(
- JNI_MediaFormat::Java_MediaFormat_createVideoFormat(
- env, j_mime.obj(), size.width(), size.height()));
- DCHECK(!j_format.is_null());
-
- JNI_MediaCodec::Java_MediaCodec_configure(
- env, j_media_codec_.obj(), j_format.obj(), surface, NULL, 0);
-
- Start();
-}
-
-void MediaCodecBridge::Start() {
+void MediaCodecBridge::StartInternal() {
JNIEnv* env = AttachCurrentThread();
JNI_MediaCodec::Java_MediaCodec_start(env, j_media_codec_.obj());
GetInputBuffers();
@@ -298,5 +277,45 @@ int MediaCodecBridge::GetOutputBuffers() {
return env->GetArrayLength(j_output_buffers_.obj());
}
+AudioCodecBridge::AudioCodecBridge(const AudioCodec codec)
+ : MediaCodecBridge(AudioCodecToMimeType(codec)) {
+}
+
+void AudioCodecBridge::Start(
+ const AudioCodec codec, int sample_rate, int channel_count) {
+ JNIEnv* env = AttachCurrentThread();
+ DCHECK(AudioCodecToMimeType(codec));
+
+ ScopedJavaLocalRef<jstring> j_mime =
+ ConvertUTF8ToJavaString(env, AudioCodecToMimeType(codec));
+ ScopedJavaLocalRef<jobject> j_format(
+ JNI_MediaFormat::Java_MediaFormat_createAudioFormat(
+ env, j_mime.obj(), sample_rate, channel_count));
+ DCHECK(!j_format.is_null());
+ JNI_MediaCodec::Java_MediaCodec_configure(
+ env, media_codec(), j_format.obj(), NULL, NULL, 0);
+ StartInternal();
+}
+
+VideoCodecBridge::VideoCodecBridge(const VideoCodec codec)
+ : MediaCodecBridge(VideoCodecToMimeType(codec)) {
+}
+
+void VideoCodecBridge::Start(
+ const VideoCodec codec, const gfx::Size& size, jobject surface) {
+ JNIEnv* env = AttachCurrentThread();
+ DCHECK(VideoCodecToMimeType(codec));
+
+ ScopedJavaLocalRef<jstring> j_mime =
+ ConvertUTF8ToJavaString(env, VideoCodecToMimeType(codec));
+ ScopedJavaLocalRef<jobject> j_format(
+ JNI_MediaFormat::Java_MediaFormat_createVideoFormat(
+ env, j_mime.obj(), size.width(), size.height()));
+ DCHECK(!j_format.is_null());
+ JNI_MediaCodec::Java_MediaCodec_configure(
+ env, media_codec(), j_format.obj(), surface, NULL, 0);
+ StartInternal();
+}
+
} // namespace media
diff --git a/media/base/android/media_codec_bridge.h b/media/base/android/media_codec_bridge.h
index 402b78796d..c291f827c6 100644
--- a/media/base/android/media_codec_bridge.h
+++ b/media/base/android/media_codec_bridge.h
@@ -10,6 +10,8 @@
#include "base/android/scoped_java_ref.h"
#include "base/time.h"
+#include "media/base/audio_decoder_config.h"
+#include "media/base/video_decoder_config.h"
#include "ui/gfx/size.h"
namespace media {
@@ -18,14 +20,10 @@ namespace media {
// 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.
class MediaCodecBridge {
public:
- enum Codec {
- AUDIO_MPEG,
- VIDEO_H264,
- VIDEO_VP8,
- };
-
enum DequeueBufferInfo {
INFO_OUTPUT_BUFFERS_CHANGED = -3,
INFO_OUTPUT_FORMAT_CHANGED = -2,
@@ -38,15 +36,7 @@ class MediaCodecBridge {
// Returns true if MediaCodec is available on the device.
static bool IsAvailable();
- explicit MediaCodecBridge(const Codec codec);
-
- ~MediaCodecBridge();
-
- // Starts decoding with the given codec params.
- void StartAudio(
- const Codec codec, int sample_rate, int channel_count);
- void StartVideo(
- const Codec codec, const gfx::Size& size, jobject surface);
+ virtual ~MediaCodecBridge();
// Resets both input and output, all indices previously returned in calls to
// DequeueInputBuffer() and DequeueOutputBuffer() become invalid.
@@ -95,12 +85,16 @@ class MediaCodecBridge {
// To access them, use DequeueOutputBuffer() and GetFromOutputBuffer().
int GetOutputBuffers();
- private:
+ protected:
+ explicit MediaCodecBridge(const char* mime);
// Calls start() against the media codec instance. Used in StartXXX() after
// configuring media codec.
- void Start();
+ void StartInternal();
+
+ jobject media_codec() { return j_media_codec_.obj(); }
+ private:
// Gets input buffers from media codec and keeps them inside this class.
// To access them, use DequeueInputBuffer(), PutToInputBuffer() and
// QueueInputBuffer().
@@ -118,6 +112,24 @@ class MediaCodecBridge {
DISALLOW_COPY_AND_ASSIGN(MediaCodecBridge);
};
+class AudioCodecBridge : public MediaCodecBridge {
+ public:
+ explicit AudioCodecBridge(const AudioCodec codec);
+
+ // Start the audio codec bridge.
+ void Start(
+ const AudioCodec codec, int sample_rate, int channel_count);
+};
+
+class VideoCodecBridge : public MediaCodecBridge {
+ public:
+ explicit VideoCodecBridge(const VideoCodec codec);
+
+ // Start the video codec bridge.
+ void Start(
+ const VideoCodec codec, const gfx::Size& size, jobject surface);
+};
+
} // 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
index 998aa2bf6d..d77041cf7a 100644
--- a/media/base/android/media_codec_bridge_unittest.cc
+++ b/media/base/android/media_codec_bridge_unittest.cc
@@ -97,17 +97,17 @@ TEST(MediaCodecBridgeTest, Initialize) {
return;
scoped_ptr<media::MediaCodecBridge> media_codec;
- media_codec.reset(new MediaCodecBridge(MediaCodecBridge::VIDEO_H264));
+ media_codec.reset(new VideoCodecBridge(kCodecH264));
}
TEST(MediaCodecBridgeTest, DoNormal) {
if (!MediaCodecBridge::IsAvailable())
return;
- scoped_ptr<media::MediaCodecBridge> media_codec;
- media_codec.reset(new MediaCodecBridge(MediaCodecBridge::AUDIO_MPEG));
+ scoped_ptr<media::AudioCodecBridge> media_codec;
+ media_codec.reset(new AudioCodecBridge(kCodecMP3));
- media_codec->StartAudio(MediaCodecBridge::AUDIO_MPEG, 44100, 2);
+ media_codec->Start(kCodecMP3, 44100, 2);
ASSERT_GT(media_codec->GetOutputBuffers(), 0);
diff --git a/media/base/android/media_jni_registrar.cc b/media/base/android/media_jni_registrar.cc
index 3a4ac82d11..9cedfac7e0 100644
--- a/media/base/android/media_jni_registrar.cc
+++ b/media/base/android/media_jni_registrar.cc
@@ -8,22 +8,25 @@
#include "base/android/jni_android.h"
#include "base/android/jni_registrar.h"
-#include "media/audio/audio_manager_base.h"
+#include "media/audio/android/audio_manager_android.h"
#include "media/base/android/media_player_bridge.h"
#include "media/base/android/media_player_listener.h"
+#include "media/base/android/webaudio_media_codec_bridge.h"
#include "media/video/capture/android/video_capture_device_android.h"
namespace media {
static base::android::RegistrationMethod kMediaRegisteredMethods[] = {
- { "AudioManagerBase",
- AudioManagerBase::RegisterAudioManager },
+ { "AudioManagerAndroid",
+ AudioManagerAndroid::RegisterAudioManager },
{ "MediaPlayerBridge",
MediaPlayerBridge::RegisterMediaPlayerBridge },
{ "MediaPlayerListener",
MediaPlayerListener::RegisterMediaPlayerListener },
{ "VideoCaptureDevice",
VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice },
+ { "WebAudioMediaCodecBridge",
+ WebAudioMediaCodecBridge::RegisterWebAudioMediaCodecBridge },
};
bool RegisterJni(JNIEnv* env) {
diff --git a/media/base/android/media_player_bridge.cc b/media/base/android/media_player_bridge.cc
index bbf497b5c7..f08d3a758a 100644
--- a/media/base/android/media_player_bridge.cc
+++ b/media/base/android/media_player_bridge.cc
@@ -8,11 +8,10 @@
#include "base/android/jni_string.h"
#include "base/basictypes.h"
#include "base/logging.h"
-#include "base/stringprintf.h"
#include "base/message_loop_proxy.h"
#include "jni/MediaPlayerBridge_jni.h"
#include "jni/MediaPlayer_jni.h"
-#include "media/base/android/media_player_bridge_manager.h"
+#include "media/base/android/media_player_manager.h"
#include "media/base/android/media_resource_getter.h"
using base::android::ConvertUTF8ToJavaString;
@@ -21,28 +20,60 @@ using base::android::ScopedJavaLocalRef;
// Time update happens every 250ms.
static const int kTimeUpdateInterval = 250;
-// Because we create the media player lazily on android, the duration of the
-// media is initially unknown to us. This makes the user unable to perform
+// Android MediaMetadataRetriever may fail to extract the metadata from the
+// media under some circumstances. This makes the user unable to perform
// seek. To solve this problem, we use a temporary duration of 100 seconds when
// the duration is unknown. And we scale the seek position later when duration
// is available.
-// TODO(qinmin): create a thread and use android MediaMetadataRetriever
-// class to extract the duration.
static const int kTemporaryDuration = 100;
namespace media {
+#if !defined(GOOGLE_TV)
+// static
+MediaPlayerBridge* MediaPlayerBridge::Create(
+ int player_id,
+ const GURL& url,
+ bool is_media_source,
+ const GURL& first_party_for_cookies,
+ bool hide_url_log,
+ MediaPlayerManager* manager,
+ const MediaErrorCB& media_error_cb,
+ const VideoSizeChangedCB& video_size_changed_cb,
+ const BufferingUpdateCB& buffering_update_cb,
+ const MediaMetadataChangedCB& media_prepared_cb,
+ const PlaybackCompleteCB& playback_complete_cb,
+ const SeekCompleteCB& seek_complete_cb,
+ const TimeUpdateCB& time_update_cb,
+ const MediaInterruptedCB& media_interrupted_cb) {
+ LOG_IF(WARNING, is_media_source) << "MSE is not supported";
+ return new MediaPlayerBridge(
+ player_id,
+ url,
+ first_party_for_cookies,
+ hide_url_log,
+ manager,
+ media_error_cb,
+ video_size_changed_cb,
+ buffering_update_cb,
+ media_prepared_cb,
+ playback_complete_cb,
+ seek_complete_cb,
+ time_update_cb,
+ media_interrupted_cb);
+}
+#endif
+
MediaPlayerBridge::MediaPlayerBridge(
int player_id,
const GURL& url,
const GURL& first_party_for_cookies,
- MediaResourceGetter* resource_getter,
bool hide_url_log,
- MediaPlayerBridgeManager* manager,
+ MediaPlayerManager* manager,
const MediaErrorCB& media_error_cb,
const VideoSizeChangedCB& video_size_changed_cb,
const BufferingUpdateCB& buffering_update_cb,
- const MediaPreparedCB& media_prepared_cb,
+ const MediaMetadataChangedCB& media_metadata_changed_cb,
const PlaybackCompleteCB& playback_complete_cb,
const SeekCompleteCB& seek_complete_cb,
const TimeUpdateCB& time_update_cb,
@@ -50,7 +81,7 @@ MediaPlayerBridge::MediaPlayerBridge(
: media_error_cb_(media_error_cb),
video_size_changed_cb_(video_size_changed_cb),
buffering_update_cb_(buffering_update_cb),
- media_prepared_cb_(media_prepared_cb),
+ media_metadata_changed_cb_(media_metadata_changed_cb),
playback_complete_cb_(playback_complete_cb),
seek_complete_cb_(seek_complete_cb),
media_interrupted_cb_(media_interrupted_cb),
@@ -68,23 +99,54 @@ MediaPlayerBridge::MediaPlayerBridge(
can_seek_forward_(true),
can_seek_backward_(true),
manager_(manager),
- resource_getter_(resource_getter),
- ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)),
+ weak_this_(this),
listener_(base::MessageLoopProxy::current(),
weak_this_.GetWeakPtr()) {
- has_cookies_ = url_.SchemeIsFileSystem() || url_.SchemeIsFile();
+ Initialize();
}
MediaPlayerBridge::~MediaPlayerBridge() {
Release();
}
-void MediaPlayerBridge::InitializePlayer() {
+void MediaPlayerBridge::Initialize() {
+ if (url_.SchemeIsFile()) {
+ cookies_.clear();
+ ExtractMediaMetadata(url_.spec());
+ return;
+ }
+
+ media::MediaResourceGetter* resource_getter =
+ manager_->GetMediaResourceGetter();
+
+ if (url_.SchemeIsFileSystem()) {
+ cookies_.clear();
+ resource_getter->GetPlatformPathFromFileSystemURL(url_, base::Bind(
+ &MediaPlayerBridge::ExtractMediaMetadata, weak_this_.GetWeakPtr()));
+ return;
+ }
+
+ resource_getter->GetCookies(url_, first_party_for_cookies_, base::Bind(
+ &MediaPlayerBridge::OnCookiesRetrieved, weak_this_.GetWeakPtr()));
+}
+
+void MediaPlayerBridge::CreateMediaPlayer() {
JNIEnv* env = base::android::AttachCurrentThread();
CHECK(env);
j_media_player_.Reset(JNI_MediaPlayer::Java_MediaPlayer_Constructor(env));
+ SetMediaPlayerListener();
+}
+
+void MediaPlayerBridge::SetMediaPlayer(jobject j_media_player) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ CHECK(env);
+
+ j_media_player_.Reset(env, j_media_player);
+}
+
+void MediaPlayerBridge::SetMediaPlayerListener() {
jobject j_context = base::android::GetApplicationContext();
DCHECK(j_context);
@@ -92,8 +154,11 @@ void MediaPlayerBridge::InitializePlayer() {
}
void MediaPlayerBridge::SetVideoSurface(jobject surface) {
- if (j_media_player_.is_null() && surface != NULL)
+ if (j_media_player_.is_null()) {
+ if (surface == NULL)
+ return;
Prepare();
+ }
JNIEnv* env = base::android::AttachCurrentThread();
CHECK(env);
@@ -104,26 +169,11 @@ void MediaPlayerBridge::SetVideoSurface(jobject surface) {
void MediaPlayerBridge::Prepare() {
if (j_media_player_.is_null())
- InitializePlayer();
-
- if (has_cookies_) {
- GetCookiesCallback(cookies_);
- } else {
- resource_getter_->GetCookies(url_, first_party_for_cookies_, base::Bind(
- &MediaPlayerBridge::GetCookiesCallback, weak_this_.GetWeakPtr()));
- }
-}
-
-void MediaPlayerBridge::GetCookiesCallback(const std::string& cookies) {
- cookies_ = cookies;
- has_cookies_ = true;
-
- if (j_media_player_.is_null())
- return;
-
+ CreateMediaPlayer();
if (url_.SchemeIsFileSystem()) {
- resource_getter_->GetPlatformPathFromFileSystemURL(url_, base::Bind(
- &MediaPlayerBridge::SetDataSource, weak_this_.GetWeakPtr()));
+ manager_->GetMediaResourceGetter()->GetPlatformPathFromFileSystemURL(
+ url_, base::Bind(&MediaPlayerBridge::SetDataSource,
+ weak_this_.GetWeakPtr()));
} else {
SetDataSource(url_.spec());
}
@@ -147,8 +197,7 @@ void MediaPlayerBridge::SetDataSource(const std::string& url) {
if (Java_MediaPlayerBridge_setDataSource(
env, j_media_player_.obj(), j_context, j_url_string.obj(),
j_cookies.obj(), hide_url_log_)) {
- if (manager_)
- manager_->RequestMediaResources(this);
+ RequestMediaResourcesFromManager();
JNI_MediaPlayer::Java_MediaPlayer_prepareAsync(
env, j_media_player_.obj());
} else {
@@ -156,6 +205,33 @@ void MediaPlayerBridge::SetDataSource(const std::string& url) {
}
}
+void MediaPlayerBridge::OnCookiesRetrieved(const std::string& cookies) {
+ cookies_ = cookies;
+ ExtractMediaMetadata(url_.spec());
+}
+
+void MediaPlayerBridge::ExtractMediaMetadata(const std::string& url) {
+ manager_->GetMediaResourceGetter()->ExtractMediaMetadata(
+ url, cookies_, base::Bind(&MediaPlayerBridge::OnMediaMetadataExtracted,
+ weak_this_.GetWeakPtr()));
+}
+
+void MediaPlayerBridge::OnMediaMetadataExtracted(
+ base::TimeDelta duration, int width, int height, bool success) {
+ if (success) {
+ duration_ = duration;
+ width_ = width;
+ height_ = height;
+ }
+ media_metadata_changed_cb_.Run(player_id_, duration_, width_, height_,
+ success);
+}
+
+void MediaPlayerBridge::RequestMediaResourcesFromManager() {
+ if (manager_)
+ manager_->RequestMediaResources(this);
+}
+
void MediaPlayerBridge::Start() {
if (j_media_player_.is_null()) {
pending_play_ = true;
@@ -315,19 +391,18 @@ void MediaPlayerBridge::OnMediaPrepared() {
// If media player was recovered from a saved state, consume all the pending
// events.
- SeekInternal(pending_seek_);
+ PendingSeekInternal(pending_seek_);
if (pending_play_) {
StartInternal();
pending_play_ = false;
}
- GetMetadata();
-
- media_prepared_cb_.Run(player_id_, duration_);
+ GetAllowedOperations();
+ media_metadata_changed_cb_.Run(player_id_, duration_, width_, height_, true);
}
-void MediaPlayerBridge::GetMetadata() {
+void MediaPlayerBridge::GetAllowedOperations() {
JNIEnv* env = base::android::AttachCurrentThread();
CHECK(env);
@@ -357,6 +432,10 @@ void MediaPlayerBridge::PauseInternal() {
time_update_timer_.Stop();
}
+void MediaPlayerBridge::PendingSeekInternal(base::TimeDelta time) {
+ SeekInternal(time);
+}
+
void MediaPlayerBridge::SeekInternal(base::TimeDelta time) {
JNIEnv* env = base::android::AttachCurrentThread();
CHECK(env);
@@ -374,4 +453,16 @@ bool MediaPlayerBridge::RegisterMediaPlayerBridge(JNIEnv* env) {
return ret;
}
+#if defined(GOOGLE_TV)
+void MediaPlayerBridge::DemuxerReady(
+ const MediaPlayerHostMsg_DemuxerReady_Params& params) {
+ NOTREACHED() << "Unexpected ipc received";
+}
+
+void MediaPlayerBridge::ReadFromDemuxerAck(
+ const MediaPlayerHostMsg_ReadFromDemuxerAck_Params& params) {
+ NOTREACHED() << "Unexpected ipc received";
+}
+#endif
+
} // namespace media
diff --git a/media/base/android/media_player_bridge.h b/media/base/android/media_player_bridge.h
index db32d94223..6733ec6598 100644
--- a/media/base/android/media_player_bridge.h
+++ b/media/base/android/media_player_bridge.h
@@ -17,12 +17,14 @@
#include "base/timer.h"
#include "googleurl/src/gurl.h"
#include "media/base/media_export.h"
+#if defined(GOOGLE_TV)
+#include "media/base/android/demuxer_stream_player_params.h"
+#endif
#include "media/base/android/media_player_listener.h"
namespace media {
-class MediaResourceGetter;
-class MediaPlayerBridgeManager;
+class MediaPlayerManager;
// This class serves as a bridge for native code to call java functions inside
// android mediaplayer class. For more information on android mediaplayer, check
@@ -52,7 +54,8 @@ class MEDIA_EXPORT MediaPlayerBridge {
typedef base::Callback<void(int, int)> BufferingUpdateCB;
// Callback when player got prepared. Args: player ID, duration of the media.
- typedef base::Callback<void(int, base::TimeDelta)> MediaPreparedCB;
+ typedef base::Callback<void(int, base::TimeDelta, int, int, bool)>
+ MediaMetadataChangedCB;
// Callbacks when seek completed. Args: player ID, current time.
typedef base::Callback<void(int, base::TimeDelta)> SeekCompleteCB;
@@ -67,8 +70,33 @@ class MEDIA_EXPORT MediaPlayerBridge {
// current time.
typedef base::Callback<void(int, base::TimeDelta)> TimeUpdateCB;
+#if defined(GOOGLE_TV)
+ // Callback when DemuxerStreamPlayer wants to read data from the demuxer.
+ typedef base::Callback<void(int, DemuxerStream::Type, bool)>
+ ReadFromDemuxerCB;
+#endif
+
static bool RegisterMediaPlayerBridge(JNIEnv* env);
+ static MediaPlayerBridge* Create(
+ int player_id,
+ const GURL& url,
+ bool is_media_source,
+ const GURL& first_party_for_cookies,
+ bool hide_url_log,
+ MediaPlayerManager* manager,
+#if defined(GOOGLE_TV)
+ const ReadFromDemuxerCB read_from_demuxer_cb,
+#endif
+ const MediaErrorCB& media_error_cb,
+ const VideoSizeChangedCB& video_size_changed_cb,
+ const BufferingUpdateCB& buffering_update_cb,
+ const MediaMetadataChangedCB& media_prepared_cb,
+ const PlaybackCompleteCB& playback_complete_cb,
+ const SeekCompleteCB& seek_complete_cb,
+ const TimeUpdateCB& time_update_cb,
+ const MediaInterruptedCB& media_interrupted_cb);
+
// Construct a MediaPlayerBridge object with all the needed media player
// callbacks. This object needs to call |manager|'s RequestMediaResources()
// before decoding the media stream. This allows |manager| to track
@@ -77,18 +105,17 @@ class MEDIA_EXPORT MediaPlayerBridge {
MediaPlayerBridge(int player_id,
const GURL& url,
const GURL& first_party_for_cookies,
- MediaResourceGetter* resource_getter,
bool hide_url_log,
- MediaPlayerBridgeManager* manager,
+ MediaPlayerManager* manager,
const MediaErrorCB& media_error_cb,
const VideoSizeChangedCB& video_size_changed_cb,
const BufferingUpdateCB& buffering_update_cb,
- const MediaPreparedCB& media_prepared_cb,
+ const MediaMetadataChangedCB& media_prepared_cb,
const PlaybackCompleteCB& playback_complete_cb,
const SeekCompleteCB& seek_complete_cb,
const TimeUpdateCB& time_update_cb,
const MediaInterruptedCB& media_interrupted_cb);
- ~MediaPlayerBridge();
+ virtual ~MediaPlayerBridge();
typedef std::map<std::string, std::string> HeadersMap;
@@ -105,7 +132,7 @@ class MEDIA_EXPORT MediaPlayerBridge {
void SeekTo(base::TimeDelta time);
// Release the player resources.
- void Release();
+ virtual void Release();
// Set the player volume.
void SetVolume(float leftVolume, float rightVolume);
@@ -117,8 +144,18 @@ class MEDIA_EXPORT MediaPlayerBridge {
base::TimeDelta GetDuration();
bool IsPlaying();
- // Get metadata from the media.
- void GetMetadata();
+ // Get allowed operations from the player.
+ void GetAllowedOperations();
+
+#if defined(GOOGLE_TV)
+ // Methods for DeumxerStreamPlayer.
+ // Informs DemuxerStreamPlayer that the demuxer is ready.
+ virtual void DemuxerReady(
+ const MediaPlayerHostMsg_DemuxerReady_Params& params);
+ // Called when the requested data is received from the demuxer.
+ virtual void ReadFromDemuxerAck(
+ const MediaPlayerHostMsg_ReadFromDemuxerAck_Params& params);
+#endif
// Called by the timer to check for current time routinely and generates
// time update events.
@@ -137,10 +174,11 @@ class MEDIA_EXPORT MediaPlayerBridge {
// Prepare the player for playback, asynchronously. When succeeds,
// OnMediaPrepared() will be called. Otherwise, OnMediaError() will
// be called with an error type.
- void Prepare();
+ virtual void Prepare();
- // Callback function passed to |resource_getter_|.
- void GetCookiesCallback(const std::string& cookies);
+ // Callback function passed to |resource_getter_|. Called when the cookies
+ // are retrieved.
+ void OnCookiesRetrieved(const std::string& cookies);
int player_id() { return player_id_; }
bool can_pause() { return can_pause_; }
@@ -148,9 +186,19 @@ class MEDIA_EXPORT MediaPlayerBridge {
bool can_seek_backward() { return can_seek_backward_; }
bool prepared() { return prepared_; }
+ protected:
+ void SetMediaPlayer(jobject j_media_player);
+ void SetMediaPlayerListener();
+ void RequestMediaResourcesFromManager();
+
+ virtual void PendingSeekInternal(base::TimeDelta time);
+
private:
+ // Initialize this object and extract the metadata from the media.
+ void Initialize();
+
// Create the actual android media player.
- void InitializePlayer();
+ void CreateMediaPlayer();
// Set the data source for the media player.
void SetDataSource(const std::string& url);
@@ -160,11 +208,17 @@ class MEDIA_EXPORT MediaPlayerBridge {
void PauseInternal();
void SeekInternal(base::TimeDelta time);
+ // Extract the media metadata from a url, asynchronously.
+ // OnMediaMetadataExtracted() will be called when this call finishes.
+ void ExtractMediaMetadata(const std::string& url);
+ void OnMediaMetadataExtracted(base::TimeDelta duration, int width, int height,
+ bool success);
+
// Callbacks when events are received.
MediaErrorCB media_error_cb_;
VideoSizeChangedCB video_size_changed_cb_;
BufferingUpdateCB buffering_update_cb_;
- MediaPreparedCB media_prepared_cb_;
+ MediaMetadataChangedCB media_metadata_changed_cb_;
PlaybackCompleteCB playback_complete_cb_;
SeekCompleteCB seek_complete_cb_;
MediaInterruptedCB media_interrupted_cb_;
@@ -190,9 +244,6 @@ class MEDIA_EXPORT MediaPlayerBridge {
// First party url for cookies.
GURL first_party_for_cookies_;
- // Whether cookies are available.
- bool has_cookies_;
-
// Hide url log from media player.
bool hide_url_log_;
@@ -210,10 +261,7 @@ class MEDIA_EXPORT MediaPlayerBridge {
std::string cookies_;
// Resource manager for all the media players.
- MediaPlayerBridgeManager* manager_;
-
- // Object for retrieving resources for this media player.
- scoped_ptr<MediaResourceGetter> resource_getter_;
+ MediaPlayerManager* manager_;
// Java MediaPlayer instance.
base::android::ScopedJavaGlobalRef<jobject> j_media_player_;
diff --git a/media/base/android/media_player_bridge_manager.cc b/media/base/android/media_player_manager.cc
index 26f2219693..45e8fa4c92 100644
--- a/media/base/android/media_player_bridge_manager.cc
+++ b/media/base/android/media_player_manager.cc
@@ -2,10 +2,10 @@
// 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_player_bridge_manager.h"
+#include "media/base/android/media_player_manager.h"
namespace media {
-MediaPlayerBridgeManager::~MediaPlayerBridgeManager() {}
+MediaPlayerManager::~MediaPlayerManager() {}
} // namespace media
diff --git a/media/base/android/media_player_bridge_manager.h b/media/base/android/media_player_manager.h
index 93bd99cbd2..c4ae120a8c 100644
--- a/media/base/android/media_player_bridge_manager.h
+++ b/media/base/android/media_player_manager.h
@@ -2,21 +2,21 @@
// 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_PLAYER_BRIDGE_MANAGER_H_
-#define MEDIA_BASE_ANDROID_MEDIA_PLAYER_BRIDGE_MANAGER_H_
+#ifndef MEDIA_BASE_ANDROID_MEDIA_PLAYER_MANAGER_H_
+#define MEDIA_BASE_ANDROID_MEDIA_PLAYER_MANAGER_H_
#include "media/base/media_export.h"
namespace media {
class MediaPlayerBridge;
+class MediaResourceGetter;
// This class is responsible for managing active MediaPlayerBridge objects.
-// It is implemented by webkit_media::MediaPlayerBridgeManagerImpl and
-// content::MediaPlayerManagerAndroid.
-class MEDIA_EXPORT MediaPlayerBridgeManager {
+// It is implemented by content::MediaPlayerManagerImpl.
+class MEDIA_EXPORT MediaPlayerManager {
public:
- virtual ~MediaPlayerBridgeManager();
+ virtual ~MediaPlayerManager();
// Called by a MediaPlayerBridge object when it is going to decode
// media streams. This helps the manager object maintain an array
@@ -27,8 +27,11 @@ class MEDIA_EXPORT MediaPlayerBridgeManager {
// Called when a MediaPlayerBridge object releases all its decoding
// resources.
virtual void ReleaseMediaResources(MediaPlayerBridge* player) = 0;
+
+ // Return a pointer to the MediaResourceGetter object.
+ virtual MediaResourceGetter* GetMediaResourceGetter() = 0;
};
} // namespace media
-#endif // MEDIA_BASE_ANDROID_MEDIA_PLAYER_BRIDGE_MANAGER_H_
+#endif // MEDIA_BASE_ANDROID_MEDIA_PLAYER_MANAGER_H_
diff --git a/media/base/android/media_resource_getter.h b/media/base/android/media_resource_getter.h
index ae4a6e52c5..abeee36cdd 100644
--- a/media/base/android/media_resource_getter.h
+++ b/media/base/android/media_resource_getter.h
@@ -9,6 +9,7 @@
#include "base/callback.h"
#include "base/files/file_path.h"
+#include "base/time.h"
#include "googleurl/src/gurl.h"
#include "media/base/media_export.h"
@@ -20,6 +21,8 @@ class MEDIA_EXPORT MediaResourceGetter {
public:
typedef base::Callback<void(const std::string&)> GetCookieCB;
typedef base::Callback<void(const std::string&)> GetPlatformPathCB;
+ typedef base::Callback<void(base::TimeDelta, int, int, bool)>
+ ExtractMediaMetadataCB;
virtual ~MediaResourceGetter();
// Method for getting the cookies for a given URL.
@@ -31,6 +34,13 @@ class MEDIA_EXPORT MediaResourceGetter {
virtual void GetPlatformPathFromFileSystemURL(
const GURL& url,
const GetPlatformPathCB& callback) = 0;
+
+ // Extract the metadata from a media URL. Once completed, the provided
+ // callback function will be run.
+ virtual void ExtractMediaMetadata(
+ const std::string& url,
+ const std::string& cookies,
+ const ExtractMediaMetadataCB& callback) = 0;
};
} // namespace media
diff --git a/media/base/android/webaudio_media_codec_bridge.cc b/media/base/android/webaudio_media_codec_bridge.cc
new file mode 100644
index 0000000000..7a21261b13
--- /dev/null
+++ b/media/base/android/webaudio_media_codec_bridge.cc
@@ -0,0 +1,131 @@
+// Copyright (c) 2012 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/webaudio_media_codec_bridge.h"
+
+#include <errno.h>
+#include <unistd.h>
+#include <vector>
+
+#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/posix/eintr_wrapper.h"
+#include "jni/WebAudioMediaCodecBridge_jni.h"
+#include "media/base/android/webaudio_media_codec_info.h"
+
+
+using base::android::AttachCurrentThread;
+
+namespace media {
+
+void WebAudioMediaCodecBridge::RunWebAudioMediaCodec(
+ base::SharedMemoryHandle encoded_audio_handle,
+ base::FileDescriptor pcm_output,
+ size_t data_size) {
+ WebAudioMediaCodecBridge bridge(encoded_audio_handle, pcm_output, data_size);
+
+ bridge.DecodeInMemoryAudioFile();
+}
+
+WebAudioMediaCodecBridge::WebAudioMediaCodecBridge(
+ base::SharedMemoryHandle encoded_audio_handle,
+ base::FileDescriptor pcm_output,
+ size_t data_size)
+ : encoded_audio_handle_(encoded_audio_handle.fd),
+ pcm_output_(pcm_output.fd),
+ data_size_(data_size) {
+ DVLOG(1) << "WebAudioMediaCodecBridge start **********************"
+ << "input fd = " << encoded_audio_handle_
+ << " output fd = " << pcm_output.fd;
+}
+
+WebAudioMediaCodecBridge::~WebAudioMediaCodecBridge() {
+ if (close(pcm_output_)) {
+ DVLOG(1) << "Couldn't close output fd " << pcm_output_
+ << ": " << strerror(errno);
+ }
+
+ if (close(encoded_audio_handle_)) {
+ DVLOG(1) << "Couldn't close shared mem fd " << encoded_audio_handle_
+ << ": " << strerror(errno);
+ }
+}
+
+bool WebAudioMediaCodecBridge::DecodeInMemoryAudioFile() {
+ // Process the encoded data from |encoded_data_handle_|.
+
+ JNIEnv* env = AttachCurrentThread();
+ CHECK(env);
+ jboolean decoded = Java_WebAudioMediaCodecBridge_decodeAudioFile(
+ env,
+ base::android::GetApplicationContext(),
+ reinterpret_cast<intptr_t>(this),
+ encoded_audio_handle_,
+ data_size_);
+
+ DVLOG(1) << "decoded = " << decoded;
+ return decoded;
+}
+
+void WebAudioMediaCodecBridge::InitializeDestination(
+ JNIEnv* env,
+ jobject /*java object*/,
+ jint channel_count,
+ jint sample_rate,
+ jlong duration_microsec) {
+ // Send information about this audio file: number of channels,
+ // sample rate (Hz), and the number of frames.
+ struct WebAudioMediaCodecInfo info = {
+ static_cast<unsigned long>(channel_count),
+ static_cast<unsigned long>(sample_rate),
+ // The number of frames is the duration of the file
+ // (in microseconds) times the sample rate.
+ static_cast<unsigned long>(
+ 0.5 + (duration_microsec * 0.000001 *
+ sample_rate))
+ };
+
+ DVLOG(1) << "InitializeDestination:"
+ << " channel count = " << channel_count
+ << " rate = " << sample_rate
+ << " duration = " << duration_microsec << " microsec";
+
+ HANDLE_EINTR(write(pcm_output_, &info, sizeof(info)));
+}
+
+void WebAudioMediaCodecBridge::OnChunkDecoded(
+ JNIEnv* env,
+ jobject /*java object*/,
+ jobject buf,
+ jint buf_size) {
+
+ if (buf_size <= 0 || !buf)
+ return;
+
+ int8_t* buffer =
+ static_cast<int8_t*>(env->GetDirectBufferAddress(buf));
+
+ size_t count = static_cast<size_t>(buf_size);
+
+ // Write out the data to the pipe in small chunks if necessary.
+ while (count > 0) {
+ int bytes_to_write = (count >= PIPE_BUF) ? PIPE_BUF : count;
+ ssize_t bytes_written = HANDLE_EINTR(write(pcm_output_,
+ buffer,
+ bytes_to_write));
+ if (bytes_written == -1)
+ break;
+ count -= bytes_written;
+ buffer += bytes_written;
+ }
+}
+
+bool WebAudioMediaCodecBridge::RegisterWebAudioMediaCodecBridge(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace
diff --git a/media/base/android/webaudio_media_codec_bridge.h b/media/base/android/webaudio_media_codec_bridge.h
new file mode 100644
index 0000000000..76de6677e2
--- /dev/null
+++ b/media/base/android/webaudio_media_codec_bridge.h
@@ -0,0 +1,73 @@
+// 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_MEDIA_CODEC_BRIDGE_H_
+#define MEDIA_BASE_ANDROID_MEDIA_CODEC_BRIDGE_H_
+
+#include <jni.h>
+
+#include "base/file_descriptor_posix.h"
+#include "base/shared_memory.h"
+#include "media/base/media_export.h"
+
+namespace media {
+
+// This class serves as a bridge for native code to call Java
+// functions in the Android MediaCodec class. See
+// http://developer.android.com/reference/android/media/MediaCodec.html.
+class MEDIA_EXPORT WebAudioMediaCodecBridge {
+ public:
+ // Create the bridge with the given file descriptors. We read from
+ // |encoded_audio_handle| to get the encoded audio data. Audio file
+ // information and decoded PCM samples are written to |pcm_output|.
+ // We also take ownership of |pcm_output|.
+ WebAudioMediaCodecBridge(base::SharedMemoryHandle encoded_audio_handle,
+ base::FileDescriptor pcm_output,
+ size_t data_size);
+ ~WebAudioMediaCodecBridge();
+
+ // Inform JNI about this bridge. Returns true if registration
+ // succeeded.
+ static bool RegisterWebAudioMediaCodecBridge(JNIEnv* env);
+
+ // Start MediaCodec to process the encoded data in
+ // |encoded_audio_handle|. The PCM samples are sent to |pcm_output|.
+ static void RunWebAudioMediaCodec(
+ base::SharedMemoryHandle encoded_audio_handle,
+ base::FileDescriptor pcm_output,
+ size_t data_size);
+
+ void OnChunkDecoded(JNIEnv* env,
+ jobject /*java object*/,
+ jobject buf,
+ jint buf_size);
+
+ void InitializeDestination(JNIEnv* env,
+ jobject /*java object*/,
+ jint channel_count,
+ jint sample_rate,
+ jlong duration_us);
+
+ private:
+ // Handles MediaCodec processing of the encoded data in
+ // |encoded_audio_handle_| and sends the pcm data to |pcm_output_|.
+ // Returns true if decoding was successful.
+ bool DecodeInMemoryAudioFile();
+
+ // The encoded audio data is read from this file descriptor for the
+ // shared memory that holds the encoded data.
+ int encoded_audio_handle_;
+
+ // The audio file information and decoded pcm data are written to
+ // this file descriptor. We take ownership of this descriptor.
+ int pcm_output_;
+
+ // The length of the encoded data.
+ size_t data_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebAudioMediaCodecBridge);
+};
+
+} // namespace media
+#endif // MEDIA_BASE_ANDROID_MEDIA_CODEC_BRIDGE_H_
diff --git a/media/base/android/webaudio_media_codec_info.h b/media/base/android/webaudio_media_codec_info.h
new file mode 100644
index 0000000000..423af91e8c
--- /dev/null
+++ b/media/base/android/webaudio_media_codec_info.h
@@ -0,0 +1,20 @@
+// Copyright 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_WEBAUDIO_MEDIA_CODEC_INFO_H_
+#define MEDIA_BASE_ANDROID_WEBAUDIO_MEDIA_CODEC_INFO_H_
+
+namespace media {
+
+// This structure holds the information about the audio file
+// determined by MediaCodec that is needed by the audio decoder to
+// create the necessary destination bus.
+struct WebAudioMediaCodecInfo {
+ unsigned long channel_count;
+ unsigned long sample_rate;
+ unsigned long number_of_frames;
+};
+
+} // namespace media
+#endif // MEDIA_BASE_ANDROID_WEBAUDIO_MEDIA_CODEC_INFO_H_