Stagefright之一
——Video Playback的流程
下面根据log分析Playback a video的流程。
ActivityManager:()
Starting: Intent{act=android.intent.action.VIEW dat=file:///sdcard/test.avi typ=video/* flg=0x4000000 cmp=com.estrongs.android.pop/.app.PopVideoPlayer}from pid 370
Starting: Intent{act=android.intent.action.VIEW dat=file:///sdcard/test.flac typ=audio/* flg=0x4000000 cmp=com.android.music/.AudioPreview} frompid 402
一. Java层:MediaPlayer.java
MediaPlayer mp = new MediaPlayer();
mp.setDataSource(context, uri);
mp.prepare();
mp.start();
二.JNI层
MediaPlayer-JNI(jni程序android_media_MediaPlayer.cpp)
{
staticJNINativeMethod gMethods[] = {
{"setDataSource", "(Ljava/lang/String;)V",(void *)android_media_MediaPlayer_setDataSource},
{"_setVideoSurface", "()V", (void *)android_media_MediaPlayer_setVideoSurface},
{"prepare","()V", (void*)android_media_MediaPlayer_prepare},
……
……
}
JNI文件中主要是一个映射表数组,在JNINativeMethod结构体中,
第一个变量:是Java中函数的名字。
第二个变量:用字符串是描述了函数的参数和返回值
第三个变量:是函数指针,指向C函数。
三.C层
1. MediaPlayer类 //对应java层的函数实现
继承于public BnMediaPlayerClient,public virtual IMediaDeathNotifier
BnMediaPlayerClient是个接口类,继承于public BnInterface<IMediaPlayerClient>;
IMediaDeathNotifier类中有函数getMediaPlayerService(),返回一个指向IMediaPlayerService的智能指针。
2. MediaPlayerService类
继承于public BnMediaPlayerService,此类是一个接口类,涉及到binder机制。
在MediaPlayerService类定义时候,在其内部又定义了三个类,class AudioOutput,class AudioCache,以及class Client
这里有个问题,从log上来看,就是在1中getMediaPlayerService()函数之后,只出现调用了class Client的构造函数的log,而没有调用MediaPlayerService的构造函数???
{
getPlayerType(url) //根据url起正确的player,默认Stagefrightplayer,rtsp player type = 4 // STAGEFRIGHT_PLAYER
caseSTAGEFRIGHT_PLAYER:
p = new StagefrightPlayer;
}
3.StagefrightPlayer类
继承于public MediaPlayerInterface
StagefrightPlayer是对AwesomePlayer类的一层封装,它的函数都是调用AwesomePlayer的成员函数,在其构造函数中,
{
mPlayer(new AwesomePlayer);
}
4.AwesomePlayer类
这个类就是video playback具体实现了。在它的构造函数中,
{
CHECK_EQ(mClient.connect(),OK);
// register all OMX components (相关类有class client/ OMX /OMXMaster)
//跟过一下,在OMXMaster类实现中调用aomxcore .cpp的OMX_Init()函数
AwesomeEventconstructor //4个event实例
reset();
setListener(); //这个以后可以跟一下
}
video play 类的调用层次基本上就是上面介绍的几个。下面分析AwesomePlayer类的实现。
(1)设置数据源Setdatasource()
/StagefrightPlayer:initCheck();
/StagefrightPlayer:setAudioSink(); //这个可以跟一下
/AwesomePlayer: setAudioSink();
/MediaPlayerService: setDataSource(url);
/StagefrightPlayer:setDataSource(url)
/AwesomePlayer:setDataSource(url)
(2)启动mQueue,作为event handle
status_t AwesomePlayer::prepare_l()
{
prepareAsync_l();
while (mFlags & PREPARING)
{
mPreparedCondition.wait(mLock);
}
}
status_t AwesomePlayer::prepareAsync_l()
{
mQueue.start();
mFlags |= PREPARING;
mAsyncPrepareEvent = new AwesomeEvent(this, &AwesomePlayer::onPrepareAsyncEvent);
mQueue.postEvent(mAsyncPrepareEvent);
}
(3) onPrepareAsyncEvent被触发
void AwesomePlayer::onPrepareAsyncEvent()
{
finishSetDataSource_l();
initVideoDecoder(); ...... (3.3)
initAudioDecoder();
}
status_tAwesomePlayer::finishSetDataSource_l()
{
//在这里会去打开文件
// FileSource 类
// mFile(fopen(filename,"rb"));
dataSource= DataSource::CreateFromURI(mUri.string(), ...);
sp<MediaExtractor> extractor =
MediaExtractor::Create(dataSource); ..... (3.1)
return setDataSource_l(extractor); ......................... (3.2)
}
(3.1) 解析mUri所指定的video,并且根据其header来选择对应的extractor
//Autodetected media mimetype, 取confidence值大的
//实例化mimetype所对应的Extractor
//通过spliter得到videotype和audiotype,以及相关parameter
sp<MediaExtractor>MediaExtractor::Create(const sp<DataSource> &source, ...)
{
source->sniff(&tmp, ...);
mime = tmp.string();
if(!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
{
return new MPEG4Extractor(source);
}
else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG))
{
return new MP3Extractor(source);
}
elseif(……)
}
(3.2) 使用extractor对视频做A/V的分离(mVideoTrack/mAudioTrack)
status_tAwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor)
{
for(size_t i = 0; i < extractor->countTracks(); ++i)
{
sp<MetaData> meta =extractor->getTrackMetaData(i);
CHECK(meta->findCString(kKeyMIMEType,&mime));
if (!haveVideo && !strncasecmp(mime, "video/", 6))
{
setVideoSource(extractor->getTrack(i));
haveVideo = true;
}
else if (!haveAudio && !strncasecmp(mime, "audio/",6))
{
setAudioSource(extractor->getTrack(i));
haveAudio = true;
}
}
}
voidAwesomePlayer::setVideoSource(sp<MediaSource> source)
{
mVideoTrack = source;
}
(3.3) 根据mVideoTrack中的编码类型来选择video decoder (mVideoSource)
//OsclSharedLibrary动态加载对应的OMX组件库
//allocateBuffersOnPort() 分配MediaBufferconstructor(buffer数目在omx组件中定义)
//包括 input port 和output port
status_t AwesomePlayer::initVideoDecoder()
{
mVideoSource = OMXCodec::Create(mClient.interface(),
mVideoTrack->getFormat(),
false,
mVideoTrack);
}
(4) 将mVideoEvent放入mQueue中,开始解码播放,并交由mVideoRenderer来显示
status_t AwesomePlayer::play_l()
{
postVideoEvent_l();
}
voidAwesomePlayer::postVideoEvent_l(int64_t delayUs)
{
mQueue.postEventWithDelay(mVideoEvent, delayUs);
}
void AwesomePlayer::onVideoEvent()
{
mVideoSource->read(&mVideoBuffer, &options);
[Check Timestamp]
mVideoRenderer->render(mVideoBuffer);
postVideoEvent_l();
}
其中:
OMXCodec:drainInputBuffer(); //是一个for(;;)
//trackisaudio
//AVIExtractor:read();
OMXCodec:fillOutputBuffer();
on_message();
OMXCodec:drainInputBuffer();
//trackisvideo
//AVIExtractor:read();
OMXCodec:fillOutputBuffer();
on_message();