Merge "Revert "Move MediaBufferXXX from foundation to libmediaextractor""
diff --git a/media/extractors/mp4/Android.bp b/media/extractors/mp4/Android.bp
index fce8dd6..3fe2336 100644
--- a/media/extractors/mp4/Android.bp
+++ b/media/extractors/mp4/Android.bp
@@ -1,4 +1,5 @@
-cc_library_shared {
+cc_defaults {
+ name: "libmp4extractor_defaults",
srcs: [
"ItemTable.cpp",
@@ -23,17 +24,21 @@
"libstagefright_id3",
],
- name: "libmp4extractor",
- relative_install_path: "extractors",
-
- compile_multilib: "first",
-
cflags: [
"-Werror",
"-Wall",
"-fvisibility=hidden",
],
version_script: "exports.lds",
+ relative_install_path: "extractors",
+ compile_multilib: "first",
+}
+
+cc_library_shared {
+
+
+ name: "libmp4extractor",
+ defaults: ["libmp4extractor_defaults"],
sanitize: {
cfi: true,
@@ -47,3 +52,9 @@
},
}
+
+cc_library_static {
+ name: "libmp4extractor_fuzzing",
+
+ defaults: ["libmp4extractor_defaults"],
+}
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index bc294c5..3aebb8a 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -77,22 +77,47 @@
return rawbuffer;
}
+static std::string audioSourceString(audio_source_t value) {
+ std::string source;
+ if (SourceTypeConverter::toString(value, source)) {
+ return source;
+ }
+ char rawbuffer[16]; // room for "%d"
+ snprintf(rawbuffer, sizeof(rawbuffer), "%d", value);
+ return rawbuffer;
+}
+
void AudioRecord::MediaMetrics::gather(const AudioRecord *record)
{
// key for media statistics is defined in the header
// attrs for media statistics
static constexpr char kAudioRecordChannelCount[] = "android.media.audiorecord.channels";
- static constexpr char kAudioRecordFormat[] = "android.media.audiorecord.format";
+ static constexpr char kAudioRecordEncoding[] = "android.media.audiorecord.encoding";
static constexpr char kAudioRecordLatency[] = "android.media.audiorecord.latency";
static constexpr char kAudioRecordSampleRate[] = "android.media.audiorecord.samplerate";
+ static constexpr char kAudioRecordSource[] = "android.media.audiotrack.source";
// constructor guarantees mAnalyticsItem is valid
mAnalyticsItem->setInt32(kAudioRecordLatency, record->mLatency);
mAnalyticsItem->setInt32(kAudioRecordSampleRate, record->mSampleRate);
mAnalyticsItem->setInt32(kAudioRecordChannelCount, record->mChannelCount);
- mAnalyticsItem->setCString(kAudioRecordFormat,
+ mAnalyticsItem->setCString(kAudioRecordEncoding,
audioFormatTypeString(record->mFormat).c_str());
+ mAnalyticsItem->setCString(kAudioRecordSource,
+ audioSourceString(record->mAttributes.source).c_str());
+}
+
+// hand the user a snapshot of the metrics.
+status_t AudioRecord::getMetrics(MediaAnalyticsItem * &item)
+{
+ mMediaMetrics.gather(this);
+ MediaAnalyticsItem *tmp = mMediaMetrics.dup();
+ if (tmp == nullptr) {
+ return BAD_VALUE;
+ }
+ item = tmp;
+ return NO_ERROR;
}
AudioRecord::AudioRecord(const String16 &opPackageName)
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index a3c66fe..7dd3f29 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -189,22 +189,23 @@
static constexpr char kAudioTrackUsage[] = "android.media.audiotrack.usage";
static constexpr char kAudioTrackSampleRate[] = "android.media.audiotrack.samplerate";
static constexpr char kAudioTrackChannelMask[] = "android.media.audiotrack.channelmask";
-#if 0
- // XXX: disabled temporarily for b/72027185
static constexpr char kAudioTrackUnderrunFrames[] = "android.media.audiotrack.underrunframes";
-#endif
static constexpr char kAudioTrackStartupGlitch[] = "android.media.audiotrack.glitch.startup";
+ // only if we're in a good state...
+ // XXX: shall we gather alternative info if failing?
+ const status_t lstatus = track->initCheck();
+ if (lstatus != NO_ERROR) {
+ ALOGD("no metrics gathered, track status=%d", (int) lstatus);
+ return;
+ }
+
// constructor guarantees mAnalyticsItem is valid
-#if 0
- // XXX: disabled temporarily for b/72027185
- // must gather underrun info before cleaning mProxy information.
const int32_t underrunFrames = track->getUnderrunFrames();
if (underrunFrames != 0) {
mAnalyticsItem->setInt32(kAudioTrackUnderrunFrames, underrunFrames);
}
-#endif
if (track->mTimestampStartupGlitchReported) {
mAnalyticsItem->setInt32(kAudioTrackStartupGlitch, 1);
@@ -223,6 +224,17 @@
mAnalyticsItem->setInt64(kAudioTrackChannelMask, track->mChannelMask);
}
+// hand the user a snapshot of the metrics.
+status_t AudioTrack::getMetrics(MediaAnalyticsItem * &item)
+{
+ mMediaMetrics.gather(this);
+ MediaAnalyticsItem *tmp = mMediaMetrics.dup();
+ if (tmp == nullptr) {
+ return BAD_VALUE;
+ }
+ item = tmp;
+ return NO_ERROR;
+}
AudioTrack::AudioTrack()
: mStatus(NO_INIT),
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index fea973a..caaefce 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -256,6 +256,11 @@
*/
uint32_t getNotificationPeriodInFrames() const { return mNotificationFramesAct; }
+ /*
+ * return metrics information for the current instance.
+ */
+ status_t getMetrics(MediaAnalyticsItem * &item);
+
/* After it's created the track is not active. Call start() to
* make it active. If set, the callback will start being called.
* If event is not AudioSystem::SYNC_EVENT_NONE, the capture start will be delayed until
@@ -703,6 +708,7 @@
}
}
void gather(const AudioRecord *record);
+ MediaAnalyticsItem *dup() { return mAnalyticsItem->dup(); }
private:
std::unique_ptr<MediaAnalyticsItem> mAnalyticsItem;
};
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index c146db9..8fbe980 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -386,6 +386,11 @@
/* Return the static buffer specified in constructor or set(), or 0 for streaming mode */
sp<IMemory> sharedBuffer() const { return mSharedBuffer; }
+ /*
+ * return metrics information for the current track.
+ */
+ status_t getMetrics(MediaAnalyticsItem * &item);
+
/* After it's created the track is not active. Call start() to
* make it active. If set, the callback will start being called.
* If the track was previously paused, volume is ramped up over the first mix buffer.
@@ -1198,6 +1203,7 @@
}
}
void gather(const AudioTrack *track);
+ MediaAnalyticsItem *dup() { return mAnalyticsItem->dup(); }
private:
std::unique_ptr<MediaAnalyticsItem> mAnalyticsItem;
};
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 17c9648..d96f7e0 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -660,6 +660,28 @@
return err;
}
+status_t NuMediaExtractor::getSampleSize(size_t *sampleSize) {
+ Mutex::Autolock autoLock(mLock);
+
+ ssize_t minIndex = fetchAllTrackSamples();
+
+ if (minIndex < 0) {
+ return ERROR_END_OF_STREAM;
+ }
+
+ TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
+ auto it = info->mSamples.begin();
+ *sampleSize = it->mBuffer->range_length();
+
+ if (info->mTrackFlags & kIsVorbis) {
+ // Each sample's data is suffixed by the number of page samples
+ // or -1 if not available.
+ *sampleSize += sizeof(int32_t);
+ }
+
+ return OK;
+}
+
status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) {
Mutex::Autolock autoLock(mLock);
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index eed0f05..6a2e39b 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -85,6 +85,7 @@
// readSampleData() reads the sample with the lowest timestamp.
status_t readSampleData(const sp<ABuffer> &buffer);
+ status_t getSampleSize(size_t *sampleSize);
status_t getSampleTrackIndex(size_t *trackIndex);
status_t getSampleTime(int64_t *sampleTimeUs);
status_t getSampleMeta(sp<MetaData> *sampleMeta);
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index cea2f9e..ca691f7 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -37,6 +37,7 @@
srcs: [
"NdkMediaCodec.cpp",
"NdkMediaCrypto.cpp",
+ "NdkMediaDataSource.cpp",
"NdkMediaExtractor.cpp",
"NdkMediaFormat.cpp",
"NdkMediaMuxer.cpp",
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
new file mode 100644
index 0000000..0cae6f4
--- /dev/null
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NdkMediaDataSource"
+
+#include "NdkMediaDataSourcePriv.h"
+
+#include <inttypes.h>
+#include <jni.h>
+#include <unistd.h>
+
+#include <binder/IServiceManager.h>
+#include <cutils/properties.h>
+#include <utils/Log.h>
+#include <utils/StrongPointer.h>
+#include <media/NdkMediaError.h>
+#include <media/NdkMediaDataSource.h>
+#include <media/stagefright/InterfaceUtils.h>
+
+#include "../../libstagefright/include/HTTPBase.h"
+#include "../../libstagefright/include/NuCachedSource2.h"
+
+using namespace android;
+
+struct AMediaDataSource {
+ void *userdata;
+ AMediaDataSourceReadAt readAt;
+ AMediaDataSourceGetSize getSize;
+};
+
+NdkDataSource::NdkDataSource(AMediaDataSource *dataSource)
+ : mDataSource(dataSource) {
+}
+
+status_t NdkDataSource::initCheck() const {
+ return OK;
+}
+
+ssize_t NdkDataSource::readAt(off64_t offset, void *data, size_t size) {
+ Mutex::Autolock l(mLock);
+ if (mDataSource->getSize == NULL || mDataSource->userdata == NULL) {
+ return -1;
+ }
+ return mDataSource->readAt(mDataSource->userdata, offset, data, size);
+}
+
+status_t NdkDataSource::getSize(off64_t *size) {
+ Mutex::Autolock l(mLock);
+ if (mDataSource->getSize == NULL || mDataSource->userdata == NULL) {
+ return NO_INIT;
+ }
+ if (size != NULL) {
+ *size = mDataSource->getSize(mDataSource->userdata);
+ }
+ return OK;
+}
+
+String8 NdkDataSource::toString() {
+ return String8::format("NdkDataSource(pid %d, uid %d)", getpid(), getuid());
+}
+
+String8 NdkDataSource::getMIMEType() const {
+ return String8("application/octet-stream");
+}
+
+extern "C" {
+
+EXPORT
+AMediaDataSource* AMediaDataSource_new() {
+ AMediaDataSource *mSource = new AMediaDataSource();
+ mSource->userdata = NULL;
+ mSource->readAt = NULL;
+ mSource->getSize = NULL;
+ return mSource;
+}
+
+EXPORT
+void AMediaDataSource_delete(AMediaDataSource *mSource) {
+ ALOGV("dtor");
+ if (mSource != NULL) {
+ delete mSource;
+ }
+}
+
+EXPORT
+void AMediaDataSource_setUserdata(AMediaDataSource *mSource, void *userdata) {
+ mSource->userdata = userdata;
+}
+
+EXPORT
+void AMediaDataSource_setReadAt(AMediaDataSource *mSource, AMediaDataSourceReadAt readAt) {
+ mSource->readAt = readAt;
+}
+
+EXPORT
+void AMediaDataSource_setGetSize(AMediaDataSource *mSource, AMediaDataSourceGetSize getSize) {
+ mSource->getSize = getSize;
+}
+
+} // extern "C"
+
diff --git a/media/ndk/NdkMediaDataSourcePriv.h b/media/ndk/NdkMediaDataSourcePriv.h
new file mode 100644
index 0000000..a1cb331
--- /dev/null
+++ b/media/ndk/NdkMediaDataSourcePriv.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_MEDIA_DATASOURCE_PRIV_H
+#define _NDK_MEDIA_DATASOURCE_PRIV_H
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <media/DataSource.h>
+#include <media/NdkMediaDataSource.h>
+#include <utils/Mutex.h>
+#include <utils/String8.h>
+
+using namespace android;
+
+struct NdkDataSource : public DataSource {
+
+ NdkDataSource(AMediaDataSource *);
+
+ virtual status_t initCheck() const;
+ virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+ virtual status_t getSize(off64_t *);
+ virtual String8 toString();
+ virtual String8 getMIMEType() const;
+
+private:
+
+ Mutex mLock;
+ AMediaDataSource *mDataSource;
+
+};
+
+#endif // _NDK_MEDIA_DATASOURCE_PRIV_H
+
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index e677d00..5dee8b0 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -20,6 +20,7 @@
#include <media/NdkMediaError.h>
#include <media/NdkMediaExtractor.h>
+#include "NdkMediaDataSourcePriv.h"
#include "NdkMediaFormatPriv.h"
@@ -121,6 +122,11 @@
}
EXPORT
+media_status_t AMediaExtractor_setDataSourceCustom(AMediaExtractor* mData, AMediaDataSource *src) {
+ return translate_error(mData->mImpl->setDataSource(new NdkDataSource(src)));
+}
+
+EXPORT
size_t AMediaExtractor_getTrackCount(AMediaExtractor *mData) {
return mData->mImpl->countTracks();
}
diff --git a/media/ndk/include/media/NdkMediaDataSource.h b/media/ndk/include/media/NdkMediaDataSource.h
new file mode 100644
index 0000000..752b684
--- /dev/null
+++ b/media/ndk/include/media/NdkMediaDataSource.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_MEDIA_DATASOURCE_H
+#define _NDK_MEDIA_DATASOURCE_H
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <media/NdkMediaError.h>
+
+__BEGIN_DECLS
+
+struct AMediaDataSource;
+typedef struct AMediaDataSource AMediaDataSource;
+
+#if __ANDROID_API__ >= 28
+
+/*
+ * AMediaDataSource's callbacks will be invoked on an implementation-defined thread
+ * or thread pool. No guarantees are provided about which thread(s) will be used for
+ * callbacks. However, it is guaranteed that AMediaDataSource's callbacks will only
+ * ever be invoked by a single thread at a time.
+ *
+ * There will be a thread synchronization point between each call to ensure that
+ * modifications to the state of your AMediaDataSource are visible to future
+ * calls. This means you don't need to do your own synchronization unless you're
+ * modifying the AMediaDataSource from another thread while it's being used by the
+ * framework.
+ */
+
+/**
+ * Called to request data from the given |offset|.
+ *
+ * Implementations should should write up to |size| bytes into
+ * |buffer|, and return the number of bytes written.
+ *
+ * Return 0 if size is zero (thus no bytes are read).
+ *
+ * Return -1 to indicate that end of stream is reached.
+ */
+typedef ssize_t (*AMediaDataSourceReadAt)(
+ void *userdata, off64_t offset, void * buffer, size_t size);
+
+/**
+ * Called to get the size of the data source.
+ *
+ * Return the size of data source in bytes, or -1 if the size is unknown.
+ */
+typedef ssize_t (*AMediaDataSourceGetSize)(void *userdata);
+
+/**
+ * Create new media data source. Returns NULL if memory allocation
+ * for the new data source object fails.
+ */
+AMediaDataSource* AMediaDataSource_new();
+
+/**
+ * Delete a previously created media data source.
+ */
+void AMediaDataSource_delete(AMediaDataSource*);
+
+/**
+ * Set an user provided opaque handle. This opaque handle is passed as
+ * the first argument to the data source callbacks.
+ */
+void AMediaDataSource_setUserdata(
+ AMediaDataSource*, void *userdata);
+
+/**
+ * Set a custom callback for supplying random access media data to the
+ * NDK media framework.
+ *
+ * Implement this if your app has special requirements for the way media
+ * data is obtained, or if you need a callback when data is read by the
+ * NDK media framework.
+ *
+ * Please refer to the definition of AMediaDataSourceReadAt for
+ * additional details.
+ */
+void AMediaDataSource_setReadAt(
+ AMediaDataSource*,
+ AMediaDataSourceReadAt);
+
+/**
+ * Set a custom callback for supplying the size of the data source to the
+ * NDK media framework.
+ *
+ * Please refer to the definition of AMediaDataSourceGetSize for
+ * additional details.
+ */
+void AMediaDataSource_setGetSize(
+ AMediaDataSource*,
+ AMediaDataSourceGetSize);
+
+#endif /*__ANDROID_API__ >= 28 */
+
+__END_DECLS
+
+#endif // _NDK_MEDIA_DATASOURCE_H
diff --git a/media/ndk/include/media/NdkMediaExtractor.h b/media/ndk/include/media/NdkMediaExtractor.h
index bf0e46d..820e9f5 100644
--- a/media/ndk/include/media/NdkMediaExtractor.h
+++ b/media/ndk/include/media/NdkMediaExtractor.h
@@ -32,6 +32,7 @@
#include <sys/types.h>
#include "NdkMediaCodec.h"
+#include "NdkMediaDataSource.h"
#include "NdkMediaFormat.h"
#include "NdkMediaCrypto.h"
@@ -64,6 +65,15 @@
media_status_t AMediaExtractor_setDataSource(AMediaExtractor*, const char *location);
// TODO support headers
+#if __ANDROID_API__ >= 28
+
+/**
+ * Set the custom data source implementation from which the extractor will read.
+ */
+media_status_t AMediaExtractor_setDataSourceCustom(AMediaExtractor*, AMediaDataSource *src);
+
+#endif /* __ANDROID_API__ >= 28 */
+
/**
* Return the number of tracks in the previously specified media file
*/
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index f2d97cd..613cc63 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -123,6 +123,11 @@
AMediaCrypto_isCryptoSchemeSupported;
AMediaCrypto_new;
AMediaCrypto_requiresSecureDecoderComponent;
+ AMediaDataSource_delete; # introduced=28
+ AMediaDataSource_new; # introduced=28
+ AMediaDataSource_setGetSize; # introduced=28
+ AMediaDataSource_setReadAt; # introduced=28
+ AMediaDataSource_setUserdata; # introduced=28
AMediaDrm_closeSession;
AMediaDrm_createByUUID;
AMediaDrm_decrypt;
@@ -160,6 +165,7 @@
AMediaExtractor_seekTo;
AMediaExtractor_selectTrack;
AMediaExtractor_setDataSource;
+ AMediaExtractor_setDataSourceCustom; # introduced=28
AMediaExtractor_setDataSourceFd;
AMediaExtractor_unselectTrack;
AMediaFormat_delete;
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index 4c312f8..f3aaec8 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -35,6 +35,7 @@
import android.media.SubtitleController;
import android.media.TtmlRenderer;
import android.media.WebVttRenderer;
+import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.media.update.VideoView2Provider;
@@ -95,6 +96,7 @@
private MediaPlayer mMediaPlayer;
private MediaControlView2 mMediaControlView;
private MediaSession mMediaSession;
+ private MediaController mMediaController;
private Metadata mMetadata;
private String mTitle;
@@ -102,7 +104,7 @@
private int mTargetState = STATE_IDLE;
private int mCurrentState = STATE_IDLE;
private int mCurrentBufferPercentage;
- private int mSeekWhenPrepared; // recording the seek position while preparing
+ private long mSeekWhenPrepared; // recording the seek position while preparing
private int mVideoWidth;
private int mVideoHeight;
@@ -179,79 +181,16 @@
}
@Override
+ public MediaController getMediaController_impl() {
+ return mMediaController;
+ }
+
+ @Override
public MediaControlView2 getMediaControlView2_impl() {
return mMediaControlView;
}
@Override
- public void start_impl() {
- if (isInPlaybackState() && mCurrentView.hasAvailableSurface()) {
- applySpeed();
- mMediaPlayer.start();
- mCurrentState = STATE_PLAYING;
- updatePlaybackState();
- }
- mTargetState = STATE_PLAYING;
- if (DEBUG) {
- Log.d(TAG, "start(). mCurrentState=" + mCurrentState
- + ", mTargetState=" + mTargetState);
- }
- }
-
- @Override
- public void pause_impl() {
- if (isInPlaybackState()) {
- if (mMediaPlayer.isPlaying()) {
- mMediaPlayer.pause();
- mCurrentState = STATE_PAUSED;
- updatePlaybackState();
- }
- }
- mTargetState = STATE_PAUSED;
- if (DEBUG) {
- Log.d(TAG, "pause(). mCurrentState=" + mCurrentState
- + ", mTargetState=" + mTargetState);
- }
- }
-
- @Override
- public int getDuration_impl() {
- if (isInPlaybackState()) {
- return mMediaPlayer.getDuration();
- }
- return -1;
- }
-
- @Override
- public int getCurrentPosition_impl() {
- if (isInPlaybackState()) {
- return mMediaPlayer.getCurrentPosition();
- }
- return 0;
- }
-
- @Override
- public void seekTo_impl(int msec) {
- if (isInPlaybackState()) {
- mMediaPlayer.seekTo(msec);
- mSeekWhenPrepared = 0;
- updatePlaybackState();
- } else {
- mSeekWhenPrepared = msec;
- }
- }
-
- @Override
- public boolean isPlaying_impl() {
- return (isInPlaybackState()) && mMediaPlayer.isPlaying();
- }
-
- @Override
- public int getBufferPercentage_impl() {
- return mCurrentBufferPercentage;
- }
-
- @Override
public int getAudioSessionId_impl() {
if (mAudioSession == 0) {
MediaPlayer foo = new MediaPlayer();
@@ -296,6 +235,7 @@
}
}
+ // TODO: remove setSpeed_impl once MediaController2 is ready.
@Override
public void setSpeed_impl(float speed) {
if (speed <= 0.0f) {
@@ -306,20 +246,7 @@
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
applySpeed();
}
- }
-
- @Override
- public float getSpeed_impl() {
- if (DEBUG) {
- if (mMediaPlayer != null) {
- float speed = mMediaPlayer.getPlaybackParams().getSpeed();
- if (speed != mSpeed) {
- Log.w(TAG, "VideoView2's speed : " + mSpeed + " is different from "
- + "MediaPlayer's speed : " + speed);
- }
- }
- }
- return mSpeed;
+ updatePlaybackState();
}
@Override
@@ -389,11 +316,6 @@
}
@Override
- public void stopPlayback_impl() {
- resetPlayer();
- }
-
- @Override
public void setOnPreparedListener_impl(VideoView2.OnPreparedListener l) {
mOnPreparedListener = l;
}
@@ -430,6 +352,7 @@
// Create MediaSession
mMediaSession = new MediaSession(mInstance.getContext(), "VideoView2MediaSession");
mMediaSession.setCallback(new MediaSessionCallback());
+ mMediaController = mMediaSession.getController();
attachMediaControlView();
}
@@ -482,23 +405,23 @@
if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK
|| keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
if (mMediaPlayer.isPlaying()) {
- mInstance.pause();
+ mMediaController.getTransportControls().pause();
mMediaControlView.show();
} else {
- mInstance.start();
+ mMediaController.getTransportControls().play();
mMediaControlView.hide();
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
if (!mMediaPlayer.isPlaying()) {
- mInstance.start();
+ mMediaController.getTransportControls().play();
mMediaControlView.hide();
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
|| keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
if (mMediaPlayer.isPlaying()) {
- mInstance.pause();
+ mMediaController.getTransportControls().pause();
mMediaControlView.show();
}
return true;
@@ -537,7 +460,7 @@
+ ", " + view.toString());
}
if (needToStart()) {
- mInstance.start();
+ mMediaController.getTransportControls().play();
}
}
@@ -571,7 +494,7 @@
mOnViewTypeChangedListener.onViewTypeChanged(view.getViewType());
}
if (needToStart()) {
- mInstance.start();
+ mMediaController.getTransportControls().play();
}
}
@@ -738,9 +661,9 @@
mStateBuilder.addCustomAction(MediaControlView2Impl.COMMAND_HIDE_SUBTITLE, null, -1);
}
mStateBuilder.setState(getCorrespondingPlaybackState(),
- mInstance.getCurrentPosition(), 1.0f);
+ mMediaPlayer.getCurrentPosition(), mSpeed);
mStateBuilder.setBufferedPosition(
- (long) (mCurrentBufferPercentage / 100.0) * mInstance.getDuration());
+ (long) (mCurrentBufferPercentage / 100.0) * mMediaPlayer.getDuration());
// Set PlaybackState for MediaSession
if (mMediaSession != null) {
@@ -837,9 +760,9 @@
int videoHeight = mp.getVideoHeight();
// mSeekWhenPrepared may be changed after seekTo() call
- int seekToPosition = mSeekWhenPrepared;
+ long seekToPosition = mSeekWhenPrepared;
if (seekToPosition != 0) {
- mInstance.seekTo(seekToPosition);
+ mMediaController.getTransportControls().seekTo(seekToPosition);
}
if (videoWidth != 0 && videoHeight != 0) {
@@ -859,12 +782,12 @@
}
if (needToStart()) {
- mInstance.start();
+ mMediaController.getTransportControls().play();
if (mMediaControlView != null) {
mMediaControlView.show();
}
- } else if (!mInstance.isPlaying() && (seekToPosition != 0
- || mInstance.getCurrentPosition() > 0)) {
+ } else if (!(isInPlaybackState() && mMediaPlayer.isPlaying())
+ && (seekToPosition != 0 || mMediaPlayer.getCurrentPosition() > 0)) {
if (mMediaControlView != null) {
// Show the media controls when we're paused into a video and
// make them stick.
@@ -875,7 +798,7 @@
// We don't know the video size yet, but should start anyway.
// The video size might be reported to us later.
if (needToStart()) {
- mInstance.start();
+ mMediaController.getTransportControls().play();
}
}
// Create and set playback state for MediaControlView2
@@ -887,7 +810,7 @@
mTitle = mMetadata.getString(Metadata.TITLE);
}
builder.putString(MediaMetadata.METADATA_KEY_TITLE, mTitle);
- builder.putLong(MediaMetadata.METADATA_KEY_DURATION, mInstance.getDuration());
+ builder.putLong(MediaMetadata.METADATA_KEY_DURATION, mMediaPlayer.getDuration());
if (mMediaSession != null) {
mMediaSession.setMetadata(builder.build());
@@ -1006,17 +929,49 @@
@Override
public void onPlay() {
- mInstance.start();
+ if (isInPlaybackState() && mCurrentView.hasAvailableSurface()) {
+ applySpeed();
+ mMediaPlayer.start();
+ mCurrentState = STATE_PLAYING;
+ updatePlaybackState();
+ }
+ mTargetState = STATE_PLAYING;
+ if (DEBUG) {
+ Log.d(TAG, "onPlay(). mCurrentState=" + mCurrentState
+ + ", mTargetState=" + mTargetState);
+ }
}
@Override
public void onPause() {
- mInstance.pause();
+ if (isInPlaybackState()) {
+ if (mMediaPlayer.isPlaying()) {
+ mMediaPlayer.pause();
+ mCurrentState = STATE_PAUSED;
+ updatePlaybackState();
+ }
+ }
+ mTargetState = STATE_PAUSED;
+ if (DEBUG) {
+ Log.d(TAG, "onPause(). mCurrentState=" + mCurrentState
+ + ", mTargetState=" + mTargetState);
+ }
}
@Override
public void onSeekTo(long pos) {
- mInstance.seekTo((int) pos);
+ if (isInPlaybackState()) {
+ mMediaPlayer.seekTo(pos, MediaPlayer.SEEK_PREVIOUS_SYNC);
+ mSeekWhenPrepared = 0;
+ updatePlaybackState();
+ } else {
+ mSeekWhenPrepared = pos;
+ }
+ }
+
+ @Override
+ public void onStop() {
+ resetPlayer();
}
}
}