NUPlayer

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对象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

1)

MediaPlayer::start() -> MediaPlayerService::Client::start() -> 
NuPlayerDriver::start()

在NuPlayerDriver::setDataSource中mState被设置为STOPPED状态,所以在start函数中执行了mPlayer->start(),调用到NuPlayer::start()函数

2) NuPlayer::start()
发送kWhatStart消息

3) NuPlayer::onMessageReceived对kWhatStart消息的处理
接收到kWhatStart消息后,先对一些变量赋初始值,并调用mSource->start()函数,对于rtsp流来说,即调用NuPlayer::RTSPSource::start()函数

4) 新建Renderer对象mRenderer,传入mAudioSink ,kWhatRendererNotify
,把mRenderer注册到全局变量gLooperRoster的mHandlers成员中
Renderer构造函数只是简单的对变量赋默认值,并没有做其他处理

5) 调用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的通知消息

6) 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中

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值