本文均属自己阅读源码的点滴总结,转账请注明出处谢谢。
欢迎和大家交流。qq:1037701636 email: [email protected]
在上一文中,我们分析到setDataSource_pre()函数最终实际返回的是StagefrightPlayer类(class StagefrightPlayer : public MediaPlayerInterface).
1 .继续分析setDataSource 函数:
-
// now set data source
-
setDataSource_post(p, p->setDataSource(fd, offset, length));
实际是多态下的StagefrightPlayer的setDataSource 函数的实现:
-
status_t StagefrightPlayer::setDataSource(
-
const char *url, const KeyedVector<String8, String8> *headers) {
-
return mPlayer->setDataSource(url, headers);
-
}
mPlayer这个成员函数是new AwesomePlayer出来的对象,故最终是进入了stagefright中去做进一步的处理:
-
status_t AwesomePlayer::setDataSource(
-
int fd, int64_t offset, int64_t length) {
-
Mutex::Autolock autoLock(mLock); ... ..... return setDataSource_l(dataSource);
-
}
-
status_t AwesomePlayer::setDataSource_l(
-
const sp<DataSource> &dataSource) {
-
sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);//创建一个解析器MPEG4Extractor,mime = NULL
-
-
if (extractor == NULL) {
-
return UNKNOWN_ERROR;
-
}
-
-
if (extractor->getDrmFlag()) {
-
checkDrmStatus(dataSource);
-
}
-
-
return setDataSource_l(extractor);
-
}
MediaExtractor类,可以理解为音视频数据源的解析器,我们来看其创建过程,传入是默认参数mime= NULL:
-
sp<MediaExtractor> MediaExtractor::Create(
-
const sp<DataSource> &source, const char *mime) {
-
sp<AMessage> meta;
-
-
String8 tmp;
-
if (mime == NULL) {
-
float confidence;
-
if (!source->sniff(&tmp, &confidence, &meta)) {//提取mime数值
-
ALOGV("FAILED to autodetect media content.");
-
-
return NULL;
-
}
-
-
mime = tmp.string();//获取mime值
-
ALOGV("Autodetected media content as '%s' with confidence %.2f",
-
mime, confidence);
-
}
-
-
//根据对文件解析的不同格式创建一个Extractor解析器
-
MediaExtractor *ret = NULL;
-
if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
-
|| !strcasecmp(mime, "audio/mp4")) {
-
int fragmented = 0;
-
if (meta != NULL && meta->findInt32("fragmented", &fragmented) && fragmented) {
-
ret = new FragmentedMP4Extractor(source);
-
} else {
-
ret = new MPEG4Extractor(source);
-
}
-
.................
-
return ret;
-
}
在这里穿插解释下MIME类型的概念,谷歌来的,应该是表示各种视频格式的一个字符段:
-
video/x-ms-asf asf
-
video/mpeg mpeg mpg
-
video/x-msvideo avi
-
application/vnd.rn-realmedia rm
-
audio/x-pn-realaudio ram ra
-
audio/x-aiff aif aiff aifc
-
audio/mpeg mpga mp3
-
audio/midi mid midi
-
audio/wav wav
-
audio/x-ms-wma wma
-
video/x-ms-wmv wmv
2. 这里和大家简单分析source->sniff的实现过程,其目的很清楚就是获取当前视频源的MIME类型。
-
bool DataSource::sniff(
-
String8 *mimeType, float *confidence, sp<AMessage> *meta) {
-
*mimeType = "";
-
*confidence = 0.0f;
-
meta->clear();
-
-
Mutex::Autolock autoLock(gSnifferMutex);
-
for (List<SnifferFunc>::iterator it = gSniffers.begin();
-
it != gSniffers.end(); ++it) {
-
String8 newMimeType;
-
float newConfidence;
-
sp<AMessage> newMeta;
-
if ((*it)(this, &newMimeType, &newConfidence, &newMeta)) {
-
if (newConfidence > *confidence) {
-
*mimeType = newMimeType;
-
*confidence = newConfidence;
-
*meta = newMeta;
-
}
-
}
-
}
-
-
return *confidence > 0.0;
-
}
该函数中一个gSnifers的全局变量中查找注册的函数it,函数指针类型为SnifferFunc。那么这些函数是如何注册的呢,我们回到AwesomePlay的构造函数中去:
-
DataSource::RegisterDefaultSniffers();
-
void DataSource::RegisterDefaultSniffers() {
-
RegisterSniffer(SniffMPEG4);
-
RegisterSniffer(SniffFragmentedMP4);
-
..........
-
-
char value[PROPERTY_VALUE_MAX];
-
if (property_get("drm.service.enabled", value, NULL)
-
&& (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
-
RegisterSniffer(SniffDRM);
-
}
-
}
我们看到其注册了多个函数指针,而这都是针对不同的格式进行的注册,将他维护在这个gSniffers迭代器中:
-
void DataSource::RegisterSniffer(SnifferFunc func) {
-
Mutex::Autolock autoLock(gSnifferMutex);
-
-
for (List<SnifferFunc>::iterator it = gSniffers.begin();
-
it != gSniffers.end(); ++it) {
-
if (*it == func) {
-
return;
-
}
-
}
-
-
gSniffers.push_back(func);//保存函数指针
-
}
最终都回调到这个函数指针之中去:
-
bool SniffMPEG4(
-
const sp<DataSource> &source, String8 *mimeType, float *confidence,
-
sp<AMessage> *meta) {
-
if (BetterSniffMPEG4(source, mimeType, confidence, meta)) {
-
return true;
-
}
-
-
if (LegacySniffMPEG4(source, mimeType, confidence)) {
-
ALOGW("Identified supported mpeg4 through LegacySniffMPEG4.");
-
return true;
-
}
-
-
return false;
-
}
这里的BetterSniffMPEG4()函数逻辑比较复杂,但总体思想是读取出source的一些头信息,如果好当前的MPEG4格式所需具备的信息一样则返回。
最终返回一个属于该source的MIEM类型,如这里假设的是MEDIA_MIMETYPE_CONTAINER_MPEG4的格式。
3.解析器的创建
经历过上述的过程,继续回到sp<MediaExtractor> MediaExtractor::Create()函数中去,根据提取到的MEME的类型,做如下操作。
-
ret = new MPEG4Extractor(source);
创建好上述的解析器后,我们回到AwesomePlayer::setDataSource_l()中,继续执行setDataSource_l(extractor),对新建的这个解析器做处理,其实质是显示音视频A/V的分离。
setVideoSource(extractor->getTrack(i));//设置视频源mVideoTrack ;
setAudioSource(extractor->getTrack(i));//设置音频源mAudioTrack;
mVideoTrack和mAudioTrack的做为创建的AwesomePlay的成员函数,其类型为MPEG4Source,继承了MediaSource。
-
sp<MediaSource> MPEG4Extractor::getTrack(size_t index) {
-
status_t err;
-
if ((err = readMetaData()) != OK) {
-
return NULL;
-
}
-
-
Track *track = mFirstTrack;
-
while (index > 0) {
-
if (track == NULL) {
-
return NULL;
-
}
-
-
track = track->next;
-
--index;
-
}
-
-
if (track == NULL) {
-
return NULL;
-
}
-
-
return new MPEG4Source(
-
track->meta, mDataSource, track->timescale, track->sampleTable);
-
}
到此为止就是讲视频源进行了A\V的分离,其过程是通过Stagefrightplay多媒体框架——>Awesomeplay——>MPEG4Extractor——>MPEG4Source.这几个过程。
4. 准备好解码器
在完成APP侧的setDataSource后,就进入prepare操作。在MPS侧由如下函数来实现:
-
status_t MediaPlayerService::Client::prepareAsync()
-
{
-
ALOGV("[%d] prepareAsync", mConnId);
-
sp<MediaPlayerBase> p = getPlayer();//stragefrightplay类
-
if (p == 0) return UNKNOWN_ERROR;
-
status_t ret;
-
-
ret = p->prepareAsync();
-
-
#if CALLBACK_ANTAGONIZER
-
ALOGD("start Antagonizer");
-
if (ret == NO_ERROR) mAntagonizer->start();
-
#endif
-
return ret;
-
}
getPlayer获取之前创建的播放器StagefrightPlayer这个对象,继续执行:
-
status_t StagefrightPlayer::prepareAsync() {
-
return mPlayer->prepareAsync();
-
}
mPlayer即为Awesomeplayer,实际的实现如下:
-
status_t AwesomePlayer::prepareAsync_l() {
-
if (mFlags & PREPARING) {
-
return UNKNOWN_ERROR; // async prepare already pending
-
}
-
-
if (!mQueueStarted) {
-
mQueue.start();启动mQueue:TimeEventQueue首次启动
-
mQueueStarted = true;
-
}
-
-
modifyFlags(PREPARING, SET);
-
mAsyncPrepareEvent = new AwesomeEvent(
-
this, &AwesomePlayer::onPrepareAsyncEvent);//onPrepareAsyncEvent回调函数,事件处理
-
-
mQueue.postEvent(mAsyncPrepareEvent);//传入类对象AwesomeEvent,mAsyncPrepareEvent
-
-
return OK;
-
}
在这里将回答在(一)中提到的事件注册与处理的这个过程。
4.1 AwesomePlayer中的Event处理机制。
a. 首先这里需要来看mQueue,他是TimedEventQueue类的对象,称为时间事件队列。首次调用是,需要进行start。
-
void TimedEventQueue::start() {
-
if (mRunning) {
-
return;
-
}
-
-
mStopped = false;
-
-
pthread_attr_t attr;
-
pthread_attr_init(&attr);
-
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
-
-
pthread_create(&mThread, &attr, ThreadWrapper, this);//创建一个进程
-
-
pthread_attr_destroy(&attr);
-
-
mRunning = true;
-
}
显而易见的是,这个Event事件处理机制脱离了Awesomeplayer,独立创建了一个线程ThradWrapper,其内部调用thredEntry来处理
-
void TimedEventQueue::threadEntry() {
-
prctl(PR_SET_NAME, (unsigned long)"TimedEventQueue", 0, 0, 0);
-
-
for (;;) {
-
int64_t now_us = 0;
-
sp<Event> event;
-
while (mQueue.empty()) {
-
mQueueNotEmptyCondition.wait(mLock);
-
}
-
.......
-
}
该函数就是在不断等待着有事件需要处理,类似于一个Queue里面非空则一直阻塞,等待signal唤醒。
b.我们来看AwesomeEvent类继承了TimedEventQueue的Event内部类。其构造函数表明,将一个函数指针作为一个参数维护在mMethod。可以猜测到这个函数将会作为事件发生时的处理函数。那么这个过程如何触发呢?
-
struct AwesomeEvent : public TimedEventQueue::Event {
-
AwesomeEvent(
-
AwesomePlayer *player,
-
void (AwesomePlayer::*method)())
-
: mPlayer(player),
-
mMethod(method) {
-
}
-
-
protected:
-
virtual ~AwesomeEvent() {}
-
-
virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
-
(mPlayer->*mMethod)();//调用最终的注册的处理函数
-
}
-
-
private:
-
AwesomePlayer *mPlayer;
-
void (AwesomePlayer::*mMethod)();
-
-
AwesomeEvent(const AwesomeEvent &);
-
AwesomeEvent &operator=(const AwesomeEvent &);
-
};
c. mQueue.postEvent(mAsyncPrepareEvent);//传入类对象AwesomeEvent,mAsyncPrepareEvent来实现事件的唤醒与处理
-
TimedEventQueue::event_id TimedEventQueue::postTimedEvent(
-
const sp<Event> &event, int64_t realtime_us) {
-
Mutex::Autolock autoLock(mLock);
-
-
event->setEventID(mNextEventID++);
-
-
List<QueueItem>::iterator it = mQueue.begin();
-
while (it != mQueue.end() && realtime_us >= (*it).realtime_us) {
-
++it;
-
}
-
-
QueueItem item;
-
item.event = event;
-
item.realtime_us = realtime_us;
-
-
if (it == mQueue.begin()) {
-
mQueueHeadChangedCondition.signal();
-
}
-
-
mQueue.insert(it, item);//在mQueue中插入event
-
-
mQueueNotEmptyCondition.signal();//发出信号触发事件
-
-
return event->eventID();
-
}
将当前的Event对象插入打Awesomeplayer的mQueue队列中,然后发出signal,唤醒threadEntry线程,让线程去处理当前的事件。
5.真正进入解码器创建的世界
-
void AwesomePlayer::onPrepareAsyncEvent() { //基于队列和事件机制调用
-
Mutex::Autolock autoLock(mLock);
-
-
if (mFlags & PREPARE_CANCELLED) {
-
ALOGI("prepare was cancelled before doing anything");
-
abortPrepare(UNKNOWN_ERROR);
-
return;
-
}
-
-
if (mUri.size() > 0) {
-
status_t err = finishSetDataSource_l();
-
-
if (err != OK) {
-
abortPrepare(err);
-
return;
-
}
-
}
-
-
if (mVideoTrack != NULL && mVideoSource == NULL) {
-
status_t err = initVideoDecoder();//初始化视频解码器
-
-
if (err != OK) {
-
abortPrepare(err);
-
return;
-
}
-
}
-
-
if (mAudioTrack != NULL && mAudioSource == NULL) {
-
status_t err = initAudioDecoder();//初始化饮品解码器
-
-
if (err != OK) {
-
abortPrepare(err);
-
return;
-
}
-
}
-
-
modifyFlags(PREPARING_CONNECTED, SET);
-
-
if (isStreamingHTTP()) {
-
postBufferingEvent_l();
-
} else {
-
finishAsyncPrepare_l();//完成异步的prepare
-
}
-
}
对于音视频解码器的创建和调用这里不在做分析,考虑到他是一块独特的模块,将在另一文中进行分析,自己也有很多内容需要进一步消化。
附件:MediaPlayer的创建过程以及A/V的分离简易流程图: