本文均属自己阅读源码的点滴总结,转账请注明出处谢谢。
欢迎和大家交流。qq:1037701636 email: gzzaigcn2012@gmail.com
在上一文中,我们分析到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();
- 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;
- }
-
- if (!mQueueStarted) {
- mQueue.start();启动mQueue:TimeEventQueue首次启动
- mQueueStarted = true;
- }
-
- modifyFlags(PREPARING, SET);
- mAsyncPrepareEvent = new AwesomeEvent(
- this, &AwesomePlayer::onPrepareAsyncEvent);
-
- mQueue.postEvent(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 ) {
- (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);
-
- 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();
- }
- }
对于音视频解码器的创建和调用这里不在做分析,考虑到他是一块独特的模块,将在另一文中进行分析,自己也有很多内容需要进一步消化。
附件:MediaPlayer的创建过程以及A/V的分离简易流程图: