Use NuPlayer for media playback everywhere
if media.stagefright.use-nuplayer is set to true.
Change-Id: Ibb217e7d7d5195b7feeea557554fe78e1585744c
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
new file mode 100644
index 0000000..99569c9
--- /dev/null
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include "GenericSource.h"
+
+#include "AnotherPacketSource.h"
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/FileSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+NuPlayer::GenericSource::GenericSource(
+ const char *url,
+ const KeyedVector<String8, String8> *headers,
+ bool uidValid,
+ uid_t uid)
+ : mDurationUs(0ll),
+ mAudioIsVorbis(false) {
+ DataSource::RegisterDefaultSniffers();
+
+ sp<DataSource> dataSource =
+ DataSource::CreateFromURI(url, headers);
+ CHECK(dataSource != NULL);
+
+ initFromDataSource(dataSource);
+}
+
+NuPlayer::GenericSource::GenericSource(
+ int fd, int64_t offset, int64_t length)
+ : mDurationUs(0ll),
+ mAudioIsVorbis(false) {
+ DataSource::RegisterDefaultSniffers();
+
+ sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
+
+ initFromDataSource(dataSource);
+}
+
+void NuPlayer::GenericSource::initFromDataSource(
+ const sp<DataSource> &dataSource) {
+ sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+
+ CHECK(extractor != NULL);
+
+ for (size_t i = 0; i < extractor->countTracks(); ++i) {
+ sp<MetaData> meta = extractor->getTrackMetaData(i);
+
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ sp<MediaSource> track;
+
+ if (!strncasecmp(mime, "audio/", 6)) {
+ if (mAudioTrack.mSource == NULL) {
+ mAudioTrack.mSource = track = extractor->getTrack(i);
+
+ if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
+ mAudioIsVorbis = true;
+ } else {
+ mAudioIsVorbis = false;
+ }
+ }
+ } else if (!strncasecmp(mime, "video/", 6)) {
+ if (mVideoTrack.mSource == NULL) {
+ mVideoTrack.mSource = track = extractor->getTrack(i);
+ }
+ }
+
+ if (track != NULL) {
+ int64_t durationUs;
+ if (meta->findInt64(kKeyDuration, &durationUs)) {
+ if (durationUs > mDurationUs) {
+ mDurationUs = durationUs;
+ }
+ }
+ }
+ }
+}
+
+NuPlayer::GenericSource::~GenericSource() {
+}
+
+void NuPlayer::GenericSource::start() {
+ ALOGI("start");
+
+ if (mAudioTrack.mSource != NULL) {
+ CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
+
+ mAudioTrack.mPackets =
+ new AnotherPacketSource(mAudioTrack.mSource->getFormat());
+
+ readBuffer(true /* audio */);
+ }
+
+ if (mVideoTrack.mSource != NULL) {
+ CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
+
+ mVideoTrack.mPackets =
+ new AnotherPacketSource(mVideoTrack.mSource->getFormat());
+
+ readBuffer(false /* audio */);
+ }
+}
+
+status_t NuPlayer::GenericSource::feedMoreTSData() {
+ return OK;
+}
+
+sp<MetaData> NuPlayer::GenericSource::getFormat(bool audio) {
+ sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
+
+ if (source == NULL) {
+ return NULL;
+ }
+
+ return source->getFormat();
+}
+
+status_t NuPlayer::GenericSource::dequeueAccessUnit(
+ bool audio, sp<ABuffer> *accessUnit) {
+ Track *track = audio ? &mAudioTrack : &mVideoTrack;
+
+ if (track->mSource == NULL) {
+ return -EWOULDBLOCK;
+ }
+
+ status_t finalResult;
+ if (!track->mPackets->hasBufferAvailable(&finalResult)) {
+ return finalResult == OK ? -EWOULDBLOCK : finalResult;
+ }
+
+ status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
+
+ readBuffer(audio, -1ll);
+
+ return result;
+}
+
+status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
+ *durationUs = mDurationUs;
+ return OK;
+}
+
+status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
+ if (mVideoTrack.mSource != NULL) {
+ int64_t actualTimeUs;
+ readBuffer(false /* audio */, seekTimeUs, &actualTimeUs);
+
+ seekTimeUs = actualTimeUs;
+ }
+
+ if (mAudioTrack.mSource != NULL) {
+ readBuffer(true /* audio */, seekTimeUs);
+ }
+
+ return OK;
+}
+
+void NuPlayer::GenericSource::readBuffer(
+ bool audio, int64_t seekTimeUs, int64_t *actualTimeUs) {
+ Track *track = audio ? &mAudioTrack : &mVideoTrack;
+ CHECK(track->mSource != NULL);
+
+ if (actualTimeUs) {
+ *actualTimeUs = seekTimeUs;
+ }
+
+ MediaSource::ReadOptions options;
+
+ bool seeking = false;
+
+ if (seekTimeUs >= 0) {
+ options.setSeekTo(seekTimeUs);
+ seeking = true;
+ }
+
+ for (;;) {
+ MediaBuffer *mbuf;
+ status_t err = track->mSource->read(&mbuf, &options);
+
+ options.clearSeekTo();
+
+ if (err == OK) {
+ size_t outLength = mbuf->range_length();
+
+ if (audio && mAudioIsVorbis) {
+ outLength += sizeof(int32_t);
+ }
+
+ sp<ABuffer> buffer = new ABuffer(outLength);
+
+ memcpy(buffer->data(),
+ (const uint8_t *)mbuf->data() + mbuf->range_offset(),
+ mbuf->range_length());
+
+ if (audio && mAudioIsVorbis) {
+ int32_t numPageSamples;
+ if (!mbuf->meta_data()->findInt32(
+ kKeyValidSamples, &numPageSamples)) {
+ numPageSamples = -1;
+ }
+
+ memcpy(buffer->data() + mbuf->range_length(),
+ &numPageSamples,
+ sizeof(numPageSamples));
+ }
+
+ int64_t timeUs;
+ CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
+
+ buffer->meta()->setInt64("timeUs", timeUs);
+
+ if (actualTimeUs) {
+ *actualTimeUs = timeUs;
+ }
+
+ mbuf->release();
+ mbuf = NULL;
+
+ if (seeking) {
+ track->mPackets->queueDiscontinuity(
+ ATSParser::DISCONTINUITY_SEEK, NULL);
+ }
+
+ track->mPackets->queueAccessUnit(buffer);
+ break;
+ } else if (err == INFO_FORMAT_CHANGED) {
+#if 0
+ track->mPackets->queueDiscontinuity(
+ ATSParser::DISCONTINUITY_FORMATCHANGE, NULL);
+#endif
+ } else {
+ track->mPackets->signalEOS(err);
+ break;
+ }
+ }
+}
+
+bool NuPlayer::GenericSource::isSeekable() {
+ return true;
+}
+
+} // namespace android