Merge "Use NuPlayer for media playback everywhere"
This commit is contained in:
committed by
Android (Google) Code Review
commit
4355b001cb
@@ -176,8 +176,9 @@ protected:
|
||||
}
|
||||
|
||||
onDrainThisBuffer(msg);
|
||||
} else if (what == ACodec::kWhatEOS) {
|
||||
printf("$\n");
|
||||
} else if (what == ACodec::kWhatEOS
|
||||
|| what == ACodec::kWhatError) {
|
||||
printf((what == ACodec::kWhatEOS) ? "$\n" : "E\n");
|
||||
|
||||
int64_t delayUs = ALooper::GetNowUs() - mStartTimeUs;
|
||||
|
||||
@@ -412,7 +413,8 @@ private:
|
||||
sp<AMessage> reply;
|
||||
CHECK(msg->findMessage("reply", &reply));
|
||||
|
||||
if (mSeekState == SEEK_FLUSHING) {
|
||||
if (mSource == NULL || mSeekState == SEEK_FLUSHING) {
|
||||
reply->setInt32("err", ERROR_END_OF_STREAM);
|
||||
reply->post();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -541,6 +541,12 @@ void MediaPlayerService::Client::disconnect()
|
||||
}
|
||||
|
||||
static player_type getDefaultPlayerType() {
|
||||
char value[PROPERTY_VALUE_MAX];
|
||||
if (property_get("media.stagefright.use-nuplayer", value, NULL)
|
||||
&& (!strcmp("1", value) || !strcasecmp("true", value))) {
|
||||
return NU_PLAYER;
|
||||
}
|
||||
|
||||
return STAGEFRIGHT_PLAYER;
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@ static sp<MediaMetadataRetrieverBase> createRetriever(player_type playerType)
|
||||
sp<MediaMetadataRetrieverBase> p;
|
||||
switch (playerType) {
|
||||
case STAGEFRIGHT_PLAYER:
|
||||
case NU_PLAYER:
|
||||
{
|
||||
p = new StagefrightMetadataRetriever;
|
||||
break;
|
||||
|
||||
@@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES:= \
|
||||
GenericSource.cpp \
|
||||
HTTPLiveSource.cpp \
|
||||
NuPlayer.cpp \
|
||||
NuPlayerDecoder.cpp \
|
||||
|
||||
265
media/libmediaplayerservice/nuplayer/GenericSource.cpp
Normal file
265
media/libmediaplayerservice/nuplayer/GenericSource.cpp
Normal file
@@ -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
|
||||
79
media/libmediaplayerservice/nuplayer/GenericSource.h
Normal file
79
media/libmediaplayerservice/nuplayer/GenericSource.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef GENERIC_SOURCE_H_
|
||||
|
||||
#define GENERIC_SOURCE_H_
|
||||
|
||||
#include "NuPlayer.h"
|
||||
#include "NuPlayerSource.h"
|
||||
|
||||
#include "ATSParser.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
struct AnotherPacketSource;
|
||||
struct ARTSPController;
|
||||
struct DataSource;
|
||||
struct MediaSource;
|
||||
|
||||
struct NuPlayer::GenericSource : public NuPlayer::Source {
|
||||
GenericSource(
|
||||
const char *url,
|
||||
const KeyedVector<String8, String8> *headers,
|
||||
bool uidValid = false,
|
||||
uid_t uid = 0);
|
||||
|
||||
GenericSource(int fd, int64_t offset, int64_t length);
|
||||
|
||||
virtual void start();
|
||||
|
||||
virtual status_t feedMoreTSData();
|
||||
|
||||
virtual sp<MetaData> getFormat(bool audio);
|
||||
virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
|
||||
|
||||
virtual status_t getDuration(int64_t *durationUs);
|
||||
virtual status_t seekTo(int64_t seekTimeUs);
|
||||
virtual bool isSeekable();
|
||||
|
||||
protected:
|
||||
virtual ~GenericSource();
|
||||
|
||||
private:
|
||||
struct Track {
|
||||
sp<MediaSource> mSource;
|
||||
sp<AnotherPacketSource> mPackets;
|
||||
};
|
||||
|
||||
Track mAudioTrack;
|
||||
Track mVideoTrack;
|
||||
|
||||
int64_t mDurationUs;
|
||||
bool mAudioIsVorbis;
|
||||
|
||||
void initFromDataSource(const sp<DataSource> &dataSource);
|
||||
|
||||
void readBuffer(
|
||||
bool audio,
|
||||
int64_t seekTimeUs = -1ll, int64_t *actualTimeUs = NULL);
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(GenericSource);
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // GENERIC_SOURCE_H_
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "NuPlayerSource.h"
|
||||
#include "RTSPSource.h"
|
||||
#include "StreamingSource.h"
|
||||
#include "GenericSource.h"
|
||||
|
||||
#include "ATSParser.h"
|
||||
|
||||
@@ -84,18 +85,44 @@ void NuPlayer::setDataSource(const sp<IStreamSource> &source) {
|
||||
msg->post();
|
||||
}
|
||||
|
||||
static bool IsHTTPLiveURL(const char *url) {
|
||||
if (!strncasecmp("http://", url, 7)
|
||||
|| !strncasecmp("https://", url, 8)) {
|
||||
size_t len = strlen(url);
|
||||
if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strstr(url,"m3u8")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void NuPlayer::setDataSource(
|
||||
const char *url, const KeyedVector<String8, String8> *headers) {
|
||||
sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
|
||||
|
||||
if (!strncasecmp(url, "rtsp://", 7)) {
|
||||
msg->setObject(
|
||||
"source", new RTSPSource(url, headers, mUIDValid, mUID));
|
||||
sp<Source> source;
|
||||
if (IsHTTPLiveURL(url)) {
|
||||
source = new HTTPLiveSource(url, headers, mUIDValid, mUID);
|
||||
} else if (!strncasecmp(url, "rtsp://", 7)) {
|
||||
source = new RTSPSource(url, headers, mUIDValid, mUID);
|
||||
} else {
|
||||
msg->setObject(
|
||||
"source", new HTTPLiveSource(url, headers, mUIDValid, mUID));
|
||||
source = new GenericSource(url, headers, mUIDValid, mUID);
|
||||
}
|
||||
|
||||
msg->setObject("source", source);
|
||||
msg->post();
|
||||
}
|
||||
|
||||
void NuPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
|
||||
sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
|
||||
|
||||
sp<Source> source = new GenericSource(fd, offset, length);
|
||||
msg->setObject("source", source);
|
||||
msg->post();
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@ struct NuPlayer : public AHandler {
|
||||
void setDataSource(
|
||||
const char *url, const KeyedVector<String8, String8> *headers);
|
||||
|
||||
void setDataSource(int fd, int64_t offset, int64_t length);
|
||||
|
||||
void setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture);
|
||||
void setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink);
|
||||
void start();
|
||||
@@ -60,12 +62,13 @@ protected:
|
||||
|
||||
private:
|
||||
struct Decoder;
|
||||
struct GenericSource;
|
||||
struct HTTPLiveSource;
|
||||
struct NuPlayerStreamListener;
|
||||
struct Renderer;
|
||||
struct RTSPSource;
|
||||
struct Source;
|
||||
struct StreamingSource;
|
||||
struct RTSPSource;
|
||||
|
||||
enum {
|
||||
kWhatSetDataSource = '=DaS',
|
||||
|
||||
@@ -226,6 +226,20 @@ sp<AMessage> NuPlayer::Decoder::makeFormat(const sp<MetaData> &meta) {
|
||||
memcpy(buffer->data(), codec_specific_data,
|
||||
codec_specific_data_size);
|
||||
|
||||
buffer->meta()->setInt32("csd", true);
|
||||
mCSD.push(buffer);
|
||||
} else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) {
|
||||
sp<ABuffer> buffer = new ABuffer(size);
|
||||
memcpy(buffer->data(), data, size);
|
||||
|
||||
buffer->meta()->setInt32("csd", true);
|
||||
mCSD.push(buffer);
|
||||
|
||||
CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size));
|
||||
|
||||
buffer = new ABuffer(size);
|
||||
memcpy(buffer->data(), data, size);
|
||||
|
||||
buffer->meta()->setInt32("csd", true);
|
||||
mCSD.push(buffer);
|
||||
}
|
||||
|
||||
@@ -76,7 +76,13 @@ status_t NuPlayerDriver::setDataSource(
|
||||
}
|
||||
|
||||
status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
|
||||
return INVALID_OPERATION;
|
||||
CHECK_EQ((int)mState, (int)UNINITIALIZED);
|
||||
|
||||
mPlayer->setDataSource(fd, offset, length);
|
||||
|
||||
mState = STOPPED;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) {
|
||||
@@ -97,13 +103,16 @@ status_t NuPlayerDriver::setVideoSurfaceTexture(
|
||||
}
|
||||
|
||||
status_t NuPlayerDriver::prepare() {
|
||||
sendEvent(MEDIA_SET_VIDEO_SIZE, 320, 240);
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t NuPlayerDriver::prepareAsync() {
|
||||
status_t err = prepare();
|
||||
|
||||
notifyListener(MEDIA_PREPARED);
|
||||
|
||||
return OK;
|
||||
return err;
|
||||
}
|
||||
|
||||
status_t NuPlayerDriver::start() {
|
||||
|
||||
@@ -376,7 +376,8 @@ void NuPlayer::Renderer::onDrainVideoQueue() {
|
||||
bool tooLate = (mVideoLateByUs > 40000);
|
||||
|
||||
if (tooLate) {
|
||||
ALOGV("video late by %lld us (%.2f secs)", mVideoLateByUs, mVideoLateByUs / 1E6);
|
||||
ALOGV("video late by %lld us (%.2f secs)",
|
||||
mVideoLateByUs, mVideoLateByUs / 1E6);
|
||||
} else {
|
||||
ALOGV("rendering video at media time %.2f secs", mediaTimeUs / 1E6);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user