RTSP流媒体使用的播放器框架是NuPlayer
1.选择播放器
MediaPlayerFactory
用来决定使用什么Player : stagefright , nuplayer, sonivox ...
对于一个URL , mediaplayerservice 调用
setdatasource ,调用getPlayerType
#define GET_PLAYER_TYPE_IMPL(a...) \
Mutex::Autolock lock_(&sLock); \
\
player_type ret = STAGEFRIGHT_PLAYER; \
float bestScore = 0.0; \
\
for (size_t i = 0; i < sFactoryMap.size(); ++i) { \
\
IFactory* v = sFactoryMap.valueAt(i); \
float thisScore; \
CHECK(v != NULL); \
thisScore = v->scoreFactory(a, bestScore); \
if (thisScore > bestScore) { \
ret = sFactoryMap.keyAt(i); \
bestScore = thisScore; \
} \
} \
\
if (0.0 == bestScore) { \
ret = getDefaultPlayerType(); \
} \
\
return ret;
player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
const char* url) {
GET_PLAYER_TYPE_IMPL(client, url);
}
class NuPlayerFactory : public MediaPlayerFactory::IFactory
对于每一个派生出来的Factory调用scoreFactory ,看谁的score高,就调用谁的creatPlayer. 对于用NuPlayer调用的是NuPlayerDriver。
2.创建NuplayerDriver
class Nuplayer : public MediaPlayerInterface
class stagefright : public MediaPlayerInterface
class MediaPlayerInterface : public MediaPlayerBase
这里面有 setDatasource, prepare, setAudioSink, start ,stop, notifyListener等接口。
特别的会New 一个mPlayer
mPlayer = new NuPlayer;
对于stagefrightPlayer
mPlayer = new AwesomePlayer
NuPlayerDriver::NuPlayerDriver()
: mState(STATE_IDLE),
mIsAsyncPrepare(false),
mAsyncResult(UNKNOWN_ERROR),
mSetSurfaceInProgress(false),
mDurationUs(-1),
mPositionUs(-1),
mNumFramesTotal(0),
mNumFramesDropped(0),
mLooper(new ALooper),
mPlayerFlags(0),
mAtEOS(false),
mStartupSeekTimeUs(-1) {
mLooper->setName("NuPlayerDriver Looper");
mLooper->start(
false, /* runOnCallingThread */
true, /* canCallJava */
PRIORITY_AUDIO);
mPlayer = new NuPlayer;
mLooper->registerHandler(mPlayer);
mPlayer->setDriver(this);
}
1.1 创建了ALooper对象mLooper,并调用了 mLooper->start函数,优先级为PRIORITY_AUDIO。
在ALooper::start函数中循环执行ALooper::loop()函数,在loop函数中调用gLooperRoster.deliverMessage函数,
最终执行了AHandler的子struct中的onMessageReceived函数。
1.2 创建NuPlayer对象mPlayer,并调用 mLooper->registerHandler(mPlayer)。
把mPlayer注册到全局变量gLooperRoster的mHandlers成员vector中。
gLooperRoster是一个全局变量。
ALooperRoster类:中转类,将消息中转给ALooper 或者 AHandleReflector
1.3NuPlayer NuPlayerDriver 双方都是调用函数接口的方式来相互调用
比如NuPlayerDriver 调用NuPlayer::setDataSourceAsync, 这里面发送一个消息AMessage(kWhatSetDataSource,id())
post()出去, NuPlayer里面onMessageReceived将会处理到。
这里的消息有kWhatSetDataSource, kWhatPrepare,kWhatStart, kWhatPause ....
就是一些播放器动作的消息
2.Nuplayer prepare
成员mSource 是在setDataSource里面创建的,
对于http:// m3u8 创建HTTPLiveSource.
对于rtsp:// 创建RTSPSource
其他的创建GenericSource
把这个对象通过AMessage(kWhatSetDataSource,id())发出去
NuPlayer里面onMessageReceived将会处理到
把创建好的mSource注册,looper()->registerHandle(mSource)
NuPlayer::Source 也是AHandler。
struct NuPlayer::RTSPSource : public NuPlayer::Source {
}
struct NuPlayer::Source : public AHandler {
}
要和谁(AHandle)通信就调用registerHandle,将来可以调用Amessage(kWhatXXX,id())->post()
prepareAsync ,发消息 kWhatPrepare
调用RTSPSource prepareAsync
void NuPlayer::RTSPSource::prepareAsync() {
if (mLooper == NULL) {
mLooper = new ALooper;
mLooper->setName("rtsp");
mLooper->start();
mReflector = new AHandlerReflector<RTSPSource>(this);
mLooper->registerHandler(mReflector);
}
CHECK(mHandler == NULL);
CHECK(mSDPLoader == NULL);
sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id());
CHECK_EQ(mState, (int)DISCONNECTED);
mState = CONNECTING;
if (mIsSDP) {
mSDPLoader = new SDPLoader(notify,
(mFlags & kFlagIncognito) ? SDPLoader::kFlagIncognito : 0,
mUIDValid, mUID);
mSDPLoader->load(
mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
} else {
mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID);
mLooper->registerHandler(mHandler);
mHandler->connect();
}
sp<AMessage> notifyStart = dupNotify();
notifyStart->setInt32("what", kWhatBufferingStart);
notifyStart->post();
}
(1)创建了ALooper对象mLooper,并调用了mLooper->setName("rtsp")和
mLooper->start()函数 启动消息处理(单独的loop线程)
(2)创建了AHandlerReflector<RTSPSource>对象mReflector,并通过
调用mLooper->registerHandler注册
RTSPSource的消息处理循环中的消息,是通过mReflector(反射类)发送,
创建Myhandle类(将这个notify传入),Myhandle里面就可以将消息传到RTSPSource里面来了。
(3)创建消息kWhatNotify,并做为MyHandler的参数,在
notify= new AMessge(kWhatNotify,mReflector->id());
mReflector是反射作用,这个是模板类,mTarget=>RTSPSource , 它的onMessageReceived调用target->onMessageReceived(), 也就是RTSPSource::onMessageReceived,
NuPlayer::RTSPSource::onMessageReceived函数中处理了kWhatNotify消息
(4)执行mHandler->connect(),链接到服务器,并把mState设置为CONNECTING状态
调用ARTSPConnection的connect函数,进行链接服务器的处理。
3.Nuplayer Start
MediaPlayer::start() -> MediaPlayerService::Client::start() ->
NuPlayerDriver::start()
在NuPlayerDriver::setDataSource中mState被设置为STOPPED状态,所以在start函数中执行了mPlayer->start(),调用到NuPlayer::start()函数
NuPlayer::start()
发送kWhatStart消息NuPlayer::onMessageReceived对kWhatStart消息的处理
接收到kWhatStart消息后,先对一些变量赋初始值,并调用mSource->start()函数,对于rtsp流来说,即调用NuPlayer::RTSPSource::start()函数新建Renderer对象mRenderer,传入mAudioSink ,kWhatRendererNotify
,把mRenderer注册到全局变量gLooperRoster的mHandlers成员中
Renderer构造函数只是简单的对变量赋默认值,并没有做其他处理调用postScanSources()函数,进行初始化audio/video的解码器decoder
NuPlayer::postScanSources()函数中发送了kWhatScanSources消息
instantiateDecoder函数执行 根据mSource中的format来初始化video和audio解码器。
new Decoder ==> NuPlayer::Decoder::Decoder()
==>new ACodec
NuPlayer::Decoder::configure
创建消息kWhatCodecNotify,用于ACodec对象mCodec的通知消息
- video解码时,创建ALooper对象mCodecLooper,用于释放主消息event队列.
3.MyHandle 处理RTSP消息
MyHandler是核心,其中包含ARTSPConnection和ARTPConnection两大部分。MyHandler负责向Server端发送Request和处理Response。
1) connect()
mConn = new ARTSPConnection
ARTSPConnection负责维护RTSP socket,发送Request,循环接收Server端数据,响应Server的Request。这里只是接收Response真正的处理在MyHandler侧。
ARTSPConnection用于建立RTSP 的连接, 建立socket, tcp connect ,receive , disconnect, sendrequest, receiveRTSPreponse
mRTPConn = new ARTPConnection
用于RTP RTCP包的接收,分析, parseRTP, parseRTCP. 这里面会创建ARTPSource , 对应于音频视频。
ARTPSource 分析SDP中的信息H264/ MP4A-LATM/ AMR/ MP2T/ ...
生成相对应的解封装的类AAVCAssembler, AMPEG4AudioAssembler, AAMRAssembler, AMPEG2TSAssembler
loop()->registerHandle(mConn);
消息处理运行在RTSPSource的mLooper中。
mNetLooper()->registerHandle(mRTPConn);消息处理运行在单独启动的线程中。
2) OnMessageReceived()
用来处理RTSP的response,RTSP 发送消息在RTSPConnection里面发送。
当收到conn , 则发送 describe, AMessage('desc')
当收到disc, 则quit or reconnect处理
当收到desc, 分析result和response, 分析SDP, setuptrack(1) setuptrack 里面会创建APacketSource, 构造一个TrackInfo,push到mTracks中
APacketSource主要用来存放Track的一些MetaData, 可以扩展,比如kKeyWidth,kKeyHeigh,kKeySampleRate,kKeyAVCC,....
然后发送setu消息
当收到setu, UDP 需要PokeAHole, 添加一个流准备接收数据,RTPConn ->addStream. 然后发送play消息
当收play, 分析npt时间,记录rtptime
当收到accu ,表示得到一个视频或音频帧
这是ARTPConnection发上来的消息
可以处理timeupdate ,first-rtp ..
如果10s timeout收不到任何rtp包 (postAccessunitTimeout) eos
将第一个收到的包rtptime 作为这个Track时间基准 setAnchor。
mRTPAnchor/mRTPBaseTIme,/mLastRTPTime,都是 rtp-time作为单位
onTimeUpdate更新rtptime npttime
调用OnAccessUnitComplete()
addMediaTimeStamp() 计算出PTS 将视频音频泳衣时间单位毫秒,
postQueueAccessunit() , 将消息kWhatAccessUnit发送到RTSPSource 处理
4. NuPlayer::feedDecoderInputData
从RTSPSource里面dequeue accessunit
mSource->dequeueAccessUnit(audio,&accessunit)
5. RTSPSource里的消息
RTSPSource的与播放框架接口,是播放框架的数据源。
NuPlayer通过RTSPSource接口得到数据流的信息和解码数据本身,RTSPSource的接口有start、getFormat、getDuration、seekTo、dequeueAccessUnit、feedMoreTSData和stop。
AnotherPacketSource在RTSPSource中作为mAudioTrack和mVideoTrack,他虽然继承了MediaSource接口,但是并没有使用read来读数据,而是通过dequeueAccessUnit接
口,Server端的压缩流通过queueAccessUnit保存到这里
kWhatNotify => 表示MyHandle发过来的消息
Myhandle::kWhatConnected , 接收到第一个Accu,则认为连接上,调用OnConnected()
notify 上层VideoSizeChanged, Prepared.
创建Tracks, 放入mTracks. ()
mAudioTrack, mVideoTrack ,info.mSource = new AnotherPacketSource
AnotherPacketSource 继承MediaSource
将AccessUnit存放于mBuffers的list里面, queueAccessUnit,dequeueAccessUnit
Myhandle::kWhatDisconnected
Myhandle::kWhatAccessunit 消息中携带accessunit的buffer
6. RTPConnection
通过消息的方式不停的onPollStreams ( select ,read RTP 包)
然后parseRTP ,调用RTPSource 的ProcessRTPPacket,对应queuePacket,并且调用相应的ARTPAssembler. 解封装,
AAVCAssembler, AMPEG4AudioAssembler, AAMRAssembler,
AMPEG2TSAssembler继承ARTPAssembler
这里会解析出accessunit并通过notify发送出去。
new Abuffer, 扩展任意meta,这里携带了rtp-time.
AMessage如何携带ABuffer ? 调用msg->setBuffer("access-unit",buf);
接受者可以通过msg->findBuffer("access-unit",&buf)可以提取出来
7. ACodec
相当于stagefrightplayer里面的OMXCodec,就是实例化OMX的Client,调用OMX组件实现解码
状态机
mUninitializedState, mLoaded , mLoadedtoIdleState, mIdelToExecutingState, mExecutingState, mExecutingtoIdleState, mIdletoLoadedState , mFlushingState.
当有消息来的时候,如果派生类有重写,则会调到重写的方法里,如果没有,则会调到BaseState.
ACodec收到的消息分两种,一种是MediaCodec传过来的,一种是OMX Component传过来的。分别对应onMessageReceived和onOMXMessage.
onOMXMessage里面又分4种:EVENT,EMPTY_BUFFER_DONE,FILL_BUFFER_DONE,FRAME_RENDERED.
ACodec是如何实现同OMXNodeInstance实现消息传递:
ACodec将CodecObserver observer对象通过omx->allocateNode()传递到OMXNodeInstance.
OMXNodeInstance将kCallbacks(OnEvent,OnEmptyBufferDone,OnFillBufferDone)传递给OMX Component.
当OMX Component有消息notify上来时,OMXNodeInstance最先收到,然后调用OMX.cpp。将消息在OMX.cpp里面将OMX Component thread转换到CallbackDispatcher线程中处理。CallbackDispatcher又将消息反调到OMXNodeInstance. 最后调用mObserver->onMessage()回到ACodec中