- A+
要解析nuplayer的原理 ,首先要了解播放器的原理,可以先复习下之前的文章
Android 音视频学习基础--1.1 音视频基础知识
Android 音视频学习基础--1.2 需要认识的一些工具
Android 音视频学习基础--1.3 主流的开源项目
Android 音视频学习基础--1.4 ffmpeg pcm输出
Android 音视频学习基础--1.5 ffmpeg yuv输出
Android 音视频学习基础--1.6 ffmpeg 简单视频播放器
Android 音视频学习基础--1.7 Android最简单的音频播放器
Android 音视频学习基础--1.8 Android最简单的音频播放器
Android 音视频学习基础--1.9 Android最简单的视频播放器
Android 音视频学习基础--1.10 Android自制简单音视频播放器
我们按照应用的上层习惯
MediaPlayer player = new MediaPlayer(); player.setDataSource(); player.prepare(); player.start();
来梳理下Nu里面的
setDataSourceAsync prepareAsync start
setDataSource
void NuPlayer::setDataSourceAsync(int fd, int64_t offset, int64_t length) { sp<AMessage> msg = new AMessage(kWhatSetDataSource, this); ... sp<GenericSource> source = new GenericSource(notify, mUIDValid, mUID); status_t err = source->setDataSource(fd, offset, length); ... msg->setObject("source", source); ... msg->post(); #endif } void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatSetDataSource: { ... sp<RefBase> obj; CHECK(msg->findObject("source", &obj)); if (obj != NULL) { Mutex::Autolock autoLock(mSourceLock); mSource = static_cast<Source *>(obj.get()); } else { err = UNKNOWN_ERROR; ... break; }
- 在Nupayer的setDataSourceAsync,生成了三大部件里面的GenericSource,并把fd交给了他。
- msg->post(),这个大家把他看成一个handler ,发送消息接收的在onMessageReceived,这里面只是保存mSource;Nuplayer里面很多这样的发送消息的大家把它当成handler就行,
prepareAsync
void NuPlayer::prepareAsync() { (new AMessage(kWhatPrepare, this))->post(); } void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { ... case kWhatPrepare: { ... mSource->prepareAsync(); break; } ...
其实Nuplayer 是没什么好准备的,主要是通知数据去准备,
void NuPlayer::GenericSource::prepareAsync() { ... sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this); msg->post(); } void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatPrepareAsync: { onPrepareAsync(); break; } ... } void NuPlayer::GenericSource::onPrepareAsync() { ... // init extractor from data source status_t err = initFromDataSource(); ... } status_t NuPlayer::GenericSource::initFromDataSource() { ... extractor = MediaExtractor::Create(mDataSource,mimeType.isEmpty() ? NULL : mimeType.string()); size_t numtracks = extractor->countTracks(); for (size_t i = 0; i < numtracks; ++i) { sp<IMediaSource> track = extractor->getTrack(i); if (!strncasecmp(mime, "audio/", 6)) { mAudioTrack.mSource = track; } else if (!strncasecmp(mime, "video/", 6)) { mVideoTrack.mSource = track; } } ... }
这里面特别有意思,出现了三大组件的另外一个MediaExtractor,分离器。并且将数据分离开来了,将视频的数据分到mVideoTrack,把音频的分到mAudioTrack。所以上层调用prepare的时候耗时是消耗在这里。他需要分离出数据,解析一部分头信息,一些比较复杂的格式,需要较长的时间。
start
最后我们来看下start
void NuPlayer::start() {
(new AMessage(kWhatStart, this))->post();
}
void NuPlayer::onStart(int64_t startPositionUs) {
mRenderer = new Renderer(mAudioSink, notify, flags);
postScanSources();
}
这里面又出现了个组件 Renderer 用于后期数据输出的。
void NuPlayer::postScanSources() { ... sp<AMessage> msg = new AMessage(kWhatScanSources, this); msg->setInt32("generation", mScanSourcesGeneration); msg->post(); ... } void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { ... case kWhatScanSources: { if (mSurface != NULL) { if (instantiateDecoder(false, &mVideoDecoder) == -EWOULDBLOCK) { rescan = true; } } if (mAudioSink != NULL && mAudioDecoder == NULL) { if (instantiateDecoder(true, &mAudioDecoder) == -EWOULDBLOCK) { rescan = true; } } } ... }
这里已经是最后一步了,在instantiateDecoder中分别创建 音频和视频的分离器
status_t NuPlayer::instantiateDecoder( *decoder = new Decoder(notify, mSource, mPID, mRenderer); }
至此 Nuplayer里面的四大组件都准备好了 有GenericSource负责输入数据,MediaExtractor负责分离数据,MediaCodec负责解析数据,Renderer负责输出数据。
2.0 Android NuPlayer流程简介
2.1 Android NuPlayer流程 —进程启动
2.2 Android NuPlayer流程—-MediaPlayer的创建
2.3 Android NuPlayer流程 -MediaPlayer的setDataSource流程
2.4 Android NuPlayer流程—-Nuplayer的工作原理
2.5 Android NuPlayer流程—-视频和音频的输出
您可以选择一种方式赞助本站
支付宝扫一扫赞助
微信钱包扫描赞助
赏