首先从NuPlayer的prepareAsync方法开始:
//frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
void NuPlayer::prepareAsync() {
ALOGV("prepareAsync");
(new AMessage(kWhatPrepare, this))->post();
}
发送kWhatPrepare消息,消息在onMessageReceived方法中处理:
sp<Source> mSource;
//frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatPrepare:
{
ALOGV("onMessageReceived kWhatPrepare");
mSource->prepareAsync(); //调用Source的prepareAsync方法
break;
}
default:
TRESPASS();
break;
}
}
调用Source的prepareAsync方法:
//frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp
void NuPlayer::GenericSource::prepareAsync() {
Mutex::Autolock _l(mLock);
ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));
if (mLooper == NULL) {
mLooper = new ALooper;
mLooper->setName("generic");
mLooper->start();
mLooper->registerHandler(this);
}
sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);
msg->post();
}
发送kWhatPrepareAsync消息,消息在onMessageReceived中处理:
//frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp
void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
Mutex::Autolock _l(mLock);
switch (msg->what()) {
case kWhatPrepareAsync:
{
onPrepareAsync();
break;
}
default:
Source::onMessageReceived(msg);
break;
}
}
调用onPrepareAsync方法:
//frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp
void NuPlayer::GenericSource::onPrepareAsync() {
mDisconnectLock.lock();
ALOGV("onPrepareAsync: mDataSource: %d", (mDataSource != NULL));
// delayed data source creation
if (mDataSource == NULL) {
// set to false first, if the extractor
// comes back as secure, set it to true then.
mIsSecure = false;
if (!mUri.empty()) {
const char* uri = mUri.c_str();
String8 contentType;
if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
sp<DataSource> httpSource;
mDisconnectLock.unlock();
httpSource = PlayerServiceDataSourceFactory::getInstance()
->CreateMediaHTTP(mHTTPService);
if (httpSource == NULL) {
ALOGE("Failed to create http source!");
notifyPreparedAndCleanup(UNKNOWN_ERROR);
return;
}
mDisconnectLock.lock();
if (!mDisconnected) {
mHttpSource = httpSource;
}
}
mLock.unlock();
mDisconnectLock.unlock();
// This might take long time if connection has some issue.
sp<DataSource> dataSource = PlayerServiceDataSourceFactory::getInstance()
->CreateFromURI(mHTTPService, uri, &mUriHeaders, &contentType,
static_cast<HTTPBase *>(mHttpSource.get()));
mDisconnectLock.lock();
mLock.lock();
if (!mDisconnected) {
mDataSource = dataSource;
}
} else {
if (property_get_bool("media.stagefright.extractremote", true) &&
!PlayerServiceFileSource::requiresDrm(
mFd.get(), mOffset, mLength, nullptr /* mime */)) {
sp<IBinder> binder =
defaultServiceManager()->getService(String16("media.extractor"));
if (binder != nullptr) {
ALOGD("FileSource remote");
sp<IMediaExtractorService> mediaExService(
interface_cast<IMediaExtractorService>(binder));
sp<IDataSource> source;
mediaExService->makeIDataSource(base::unique_fd(dup(mFd.get())), mOffset, mLength, &source);
ALOGV("IDataSource(FileSource): %p %d %lld %lld",
source.get(), mFd.get(), (long long)mOffset, (long long)mLength);
if (source.get() != nullptr) {
mDataSource = CreateDataSourceFromIDataSource(source);
} else {
ALOGW("extractor service cannot make data source");
}
} else {
ALOGW("extractor service not running");
}
}
if (mDataSource == nullptr) {
ALOGD("FileSource local");
mDataSource = new PlayerServiceFileSource(dup(mFd.get()), mOffset, mLength);
}
}
if (mDataSource == NULL) {
ALOGE("Failed to create data source!");
mDisconnectLock.unlock();
notifyPreparedAndCleanup(UNKNOWN_ERROR);
return;
}
}
if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
}
mDisconnectLock.unlock();
// For cached streaming cases, we need to wait for enough
// buffering before reporting prepared.
mIsStreaming = (mCachedSource != NULL);
// init extractor from data source
status_t err = initFromDataSource(); //初始化解析器,解析器的作用是解析音视频数据
if (err != OK) {
ALOGE("Failed to init from data source!");
notifyPreparedAndCleanup(err);
return;
}
if (mVideoTrack.mSource != NULL) {
sp<MetaData> meta = getFormatMeta_l(false /* audio */);
sp<AMessage> msg = new AMessage;
err = convertMetaDataToMessage(meta, &msg);
if(err != OK) {
notifyPreparedAndCleanup(err);
return;
}
notifyVideoSizeChanged(msg); //通知上层Video尺寸变化
}
notifyFlagsChanged( /通知上层Flags变化
// FLAG_SECURE will be known if/when prepareDrm is called by the app
// FLAG_PROTECTED will be known if/when prepareDrm is called by the app
FLAG_CAN_PAUSE |
FLAG_CAN_SEEK_BACKWARD |
FLAG_CAN_SEEK_FORWARD |
FLAG_CAN_SEEK);
finishPrepareAsync();
ALOGV("onPrepareAsync: Done");
}
上面方法的主要处理如下:
1、调用initFromDataSource方法,初始化分离器,分离器的作用是音视频数据分离
2、调用finishPrepareAsync
下面分析进行分析:
NuPlayer::GenericSource::initFromDataSource
//frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp
status_t NuPlayer::GenericSource::initFromDataSource() {
sp<IMediaExtractor> extractor;
sp<DataSource> dataSource;
{
Mutex::Autolock _l_d(mDisconnectLock);
dataSource = mDataSource;
}
CHECK(dataSource != NULL);
mLock.unlock();
// This might take long time if data source is not reliable.
extractor = MediaExtractorFactory::Create(dataSource, NULL); //通过MediaExtractorFactory创建MediaExtractor
if (extractor == NULL) {
ALOGE("initFromDataSource, cannot create extractor!");
mLock.lock();
return UNKNOWN_ERROR;
}
sp<MetaData> fileMeta = extractor->getMetaData();
size_t numtracks = extractor->countTracks();
if (numtracks == 0) {
ALOGE("initFromDataSource, source has no track!");
mLock.lock();
return UNKNOWN_ERROR;
}
mLock.lock();
mFileMeta = fileMeta;
if (mFileMeta != NULL) {
int64_t duration;
if (mFileMeta->findInt64(kKeyDuration, &duration)) {
mDurationUs = duration;
}
}
int32_t totalBitrate = 0;
mMimes.clear();
for (size_t i = 0; i < numtracks; ++i) {
sp<IMediaSource> track = extractor->getTrack(i);
if (track == NULL) {
continue;
}
sp<MetaData> meta = extractor->getTrackMetaData(i);
if (meta == NULL) {
ALOGE("no metadata for track %zu", i);
return UNKNOWN_ERROR;
}
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
ALOGV("initFromDataSource track[%zu]: %s", i, mime);
// Do the string compare immediately with "mime",
// we can't assume "mime" would stay valid after another
// extractor operation, some extractors might modify meta
// during getTrack() and make it invalid.
if (!strncasecmp(mime, "audio/", 6)) {
if (mAudioTrack.mSource == NULL) {
mAudioTrack.mIndex = i;
mAudioTrack.mSource = track;
mAudioTrack.mPackets =
new AnotherPacketSource(mAudioTrack.mSource->getFormat());
if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
mAudioIsVorbis = true;
} else {
mAudioIsVorbis = false;
}
mMimes.add(String8(mime));
}
} else if (!strncasecmp(mime, "video/", 6)) {
if (mVideoTrack.mSource == NULL) {
mVideoTrack.mIndex = i;
mVideoTrack.mSource = track;
mVideoTrack.mPackets =
new AnotherPacketSource(mVideoTrack.mSource->getFormat());
// video always at the beginning
mMimes.insertAt(String8(mime), 0);
}
}
mSources.push(track);
int64_t durationUs;
if (meta->findInt64(kKeyDuration, &durationUs)) {
if (durationUs > mDurationUs) {
mDurationUs = durationUs;
}
}
int32_t bitrate;
if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
totalBitrate += bitrate;
} else {
totalBitrate = -1;
}
}
ALOGV("initFromDataSource mSources.size(): %zu mIsSecure: %d mime[0]: %s", mSources.size(),
mIsSecure, (mMimes.isEmpty() ? "NONE" : mMimes[0].string()));
if (mSources.size() == 0) {
ALOGE("b/23705695");
return UNKNOWN_ERROR;
}
// Modular DRM: The return value doesn't affect source initialization.
(void)checkDrmInfo();
mBitrate = totalBitrate;
return OK;
}
上面方法主要处理如下:
1、调用MediaExtractorFactory::Create,通过MediaExtractorFactory创建MediaExtractor
2、通过MediaExtractor的getMetaData方法取得MetaData
3、调用MediaExtractor的countTracks方法
4、调用MediaExtractor的getTrack方法取得track
MediaExtractor相关的内容会在MediaExtractor中介绍。
NuPlayer::GenericSource::finishPrepareAsync
//frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp
void NuPlayer::GenericSource::finishPrepareAsync() {
ALOGV("finishPrepareAsync");
status_t err = startSources();
if (err != OK) {
ALOGE("Failed to init start data source!");
notifyPreparedAndCleanup(err);
return;
}
if (mIsStreaming) {
mCachedSource->resumeFetchingIfNecessary();
mPreparing = true;
schedulePollBuffering();
} else {
notifyPrepared();
}
if (mAudioTrack.mSource != NULL) {
postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
}
if (mVideoTrack.mSource != NULL) {
postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
}
}
NuPlayer::GenericSource::startSources
调用startSources方法:
struct Track {
size_t mIndex;
sp<IMediaSource> mSource;
sp<AnotherPacketSource> mPackets;
};
Track mAudioTrack;
Track mVideoTrack;
//frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp
status_t NuPlayer::GenericSource::startSources() {
// Start the selected A/V tracks now before we start buffering.
// Widevine sources might re-initialize crypto when starting, if we delay
// this to start(), all data buffered during prepare would be wasted.
// (We don't actually start reading until start().)
//
// TODO: this logic may no longer be relevant after the removal of widevine
// support
if (mAudioTrack.mSource != NULL && mAudioTrack.mSource->start() != OK) {
ALOGE("failed to start audio track!");
return UNKNOWN_ERROR;
}
if (mVideoTrack.mSource != NULL && mVideoTrack.mSource->start() != OK) {
ALOGE("failed to start video track!");
return UNKNOWN_ERROR;
}
return OK;
}
调用IMediaSource的start方法:
//frameworks/av/media/libmedia/IMediaSource.cpp
class BpMediaSource : public BpInterface<IMediaSource> {
public:
explicit BpMediaSource(const sp<IBinder>& impl)
: BpInterface<IMediaSource>(impl), mBuffersSinceStop(0)
{
}
virtual status_t start(MetaData *params) {
ALOGV("start");
Parcel data, reply;
data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
if (params) {
params->writeToParcel(data);
}
status_t ret = remote()->transact(START, data, &reply);
if (ret == NO_ERROR && params) {
ALOGW("ignoring potentially modified MetaData from start");
ALOGW("input:");
params->dumpToLog();
sp<MetaData> meta = MetaData::createFromParcel(reply);
ALOGW("output:");
meta->dumpToLog();
}
return ret;
}
}
调用remote()->transact(START, data, &reply)方法,在onTransact中处理:
//frameworks/av/media/libmedia/IMediaSource.cpp
status_t BnMediaSource::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch (code) {
case START: {
ALOGV("start");
CHECK_INTERFACE(IMediaSource, data, reply);
sp<MetaData> meta;
if (data.dataAvail()) {
meta = MetaData::createFromParcel(data);
}
status_t ret = start(meta.get());
if (ret == NO_ERROR && meta != NULL) {
meta->writeToParcel(*reply);
}
return ret;
}
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
RemoteMediaSource::start
调用start方法,start方法由BnMediaSource的子类RemoteMediaSource实现:
MediaTrack *mTrack;
//frameworks/av/media/libstagefright/RemoteMediaSource.cpp
status_t RemoteMediaSource::start(MetaData *params) {
if (params) {
ALOGW("dropping start parameters:");
params->dumpToLog();
}
return mTrack->start();
}
调用MediaTrack的start方法,MediaTrackCUnwrapper继承于MediaTrack,因此调用MediaTrackCUnwrapper的start方法:
CMediaTrack *wrapper;
//frameworks/av/media/libstagefright/MediaTrack.cpp
status_t MediaTrackCUnwrapper::start() {
if (bufferGroup == nullptr) {
bufferGroup = new MediaBufferGroup(); //创建MediaBufferGroup对象
}
return reverse_translate_error(wrapper->start(wrapper->data, bufferGroup->wrap())); //调用CMediaTrack的start方法
}
调用CMediaTrack的start方法,CMediaTrack是一个结构体,定义在MediaExtractorPluginApi.h中:
//frameworks/av/include/media/MediaExtractorPluginApi.h
struct CMediaTrack {
void *data;
void (*free)(void *data);
media_status_t (*start)(void *data, CMediaBufferGroup *bufferGroup);
media_status_t (*stop)(void *data);
media_status_t (*getFormat)(void *data, AMediaFormat *format);
media_status_t (*read)(void *data, CMediaBuffer **buffer, uint32_t options, int64_t seekPosUs);
bool (*supportsNonBlockingRead)(void *data);
}