NuPlayer的解码模块相对比较简单,统一使用了一个基类NuPlayerDecoderBase管理,该类中包含了一个MediaCodec的对象,实际解码工作全靠MediaCodec。
如果你不会知道MediaCodec是什么,推荐去官网看看:MediaCodec
那他的主要功能有哪些呢?
将音视频的原始数据缓存到队列
音频数据消耗播放
视频数据消耗显示
音视频同步
播放器控制
void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) { int32_t audio; CHECK(msg->findInt32("audio", &audio)); if (dropBufferIfStale(audio, msg)) { return; } if (audio) { mHasAudio = true; //音频 } else { mHasVideo = true; //视频 } if (mHasVideo) { if (mVideoScheduler == NULL) { mVideoScheduler = new VideoFrameScheduler(); //视频渲染调整 mVideoScheduler->init(); } } sp<ABuffer> buffer; CHECK(msg->findBuffer("buffer", &buffer)); sp<AMessage> notifyConsumed; CHECK(msg->findMessage("notifyConsumed", ¬ifyConsumed)); QueueEntry entry; entry.mBuffer = buffer; entry.mNotifyConsumed = notifyConsumed; entry.mOffset = 0; entry.mFinalResult = OK; entry.mBufferOrdinal = ++mTotalBuffersQueued; if (audio) { Mutex::Autolock autoLock(mLock); mAudioQueue.push_back(entry); postDrainAudioQueue_l(); //刷新音频 } else { mVideoQueue.push_back(entry); postDrainVideoQueue(); //刷新视频 } Mutex::Autolock autoLock(mLock); if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) { return; } sp<ABuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer; sp<ABuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer; if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) { // EOS signalled on either queue. syncQueuesDone_l(); return; } int64_t firstAudioTimeUs; int64_t firstVideoTimeUs; CHECK(firstAudioBuffer->meta() ->findInt64("timeUs", &firstAudioTimeUs)); CHECK(firstVideoBuffer->meta() ->findInt64("timeUs", &firstVideoTimeUs)); int64_t diff = firstVideoTimeUs - firstAudioTimeUs; ALOGV("queueDiff = %.2f secs", diff / 1E6); if (diff > 100000ll) { // Audio data starts More than 0.1 secs before video. // Drop some audio. (*mAudioQueue.begin()).mNotifyConsumed->post(); mAudioQueue.erase(mAudioQueue.begin()); return; } syncQueuesDone_l(); }