承接上一章节分析:【五】Android MediaPlayer整体架构源码分析 -【prepareAsync/prepare数据准备处理流程】
完整系列章节分析:【一】Android MediaPlayer整体架构源码分析 -【初始化和创建】
本系列文章分析的安卓源码版本:【Android 10.0 版本】
start请求播放处理流程
示例代码:
mMediaPlayer.start();
该方法推荐在前面prepare处理流程分析中,使用异步prepareAsync执行监听prepared完成事件,然后该事件中执行start()方法即可请求开始播放。
start()方法实现:
由方法英文注释可知,该方法其实会执行开始播放和恢复播放两个流程,即若此前已经stopped或从未start过,那么将会从头开始播放,而若此前是paused状态,那么将会恢复上次暂停位置开始播放。
// [android.media.MediaPlayer.java]
/**
* Starts or resumes playback. If playback had previously been paused,
* playback will continue from where it was paused. If playback had
* been stopped, or never started before, playback will start at the
* beginning.
*
* @throws IllegalStateException if it is called in an invalid state
*/
public void start() throws IllegalStateException {
//FIXME use lambda to pass startImpl to superclass
// 根据方法名其实就可以知道该延迟时长是啥作用即延迟指定时长后才开始播放
final int delay = getStartDelayMs();
if (delay == 0) {
// 立即请求播放
// 见下面分析
startImpl();
} else {
new Thread() {
public void run() {
try {
// 线程睡眠指定时长
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 重置开始播放延迟时间
baseSetStartDelayMs(0);
try {
// 请求播放
startImpl();
} catch (IllegalStateException e) {
// fail silently for a state exception when it is happening after
// a delayed start, as the player state could have changed between the
// call to start() and the execution of startImpl()
}
}
}.start();
}
}
startImpl()实现分析:
// [android.media.MediaPlayer.java]
private void startImpl() {
// 基类方法
// 见下面的分析
baseStart();
// 保持唤醒锁状态,其实就是手机唤醒锁处理
// 见下面分析
stayAwake(true);
// native层方法请求播放
_start();
}
baseStart()实现分析:
// [android.media.PlayerBase.java]
/**
* Class to encapsulate a number of common player operations:
* - AppOps for OP_PLAY_AUDIO
* - more to come (routing, transport control)
* @hide
*/
public abstract class PlayerBase {
void baseStart() {
if (DEBUG) { Log.v(TAG, "baseStart() piid=" + mPlayerIId); }
// 更新播放状态
// 见下面分析
updateState(AudioPlaybackConfiguration.PLAYER_STATE_STARTED);
synchronized (mLock) {
// 通过分析,该方法默认返回false,因此不再分析
if (isRestricted_sync()) {
playerSetVolume(true/*muting*/,0, 0);
}
}
}
}
updateState() 实现分析:
更新播放状态
// [android.media.PlayerBase.java]
private void updateState(int state) {
final int piid;
synchronized (mLock) {
mState = state;
piid = mPlayerIId;
}
try {
// 通过Service【ServiceManager】通知播放器状态事件,此处不展开分析
getService().playerEvent(piid, state);
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, "
+ AudioPlaybackConfiguration.toLogFriendlyPlayerState(state)
+ " state will not be tracked for piid=" + piid, e);
}
}
stayAwake(true)实现分析:
唤醒锁处理
// [android.media.MediaPlayer.java]
private void stayAwake(boolean awake) {
if (mWakeLock != null) {
if (awake && !mWakeLock.isHeld()) {
// 需要获取唤醒状态并且唤醒锁未获取到时
mWakeLock.acquire();
} else if (!awake && mWakeLock.isHeld()) {
// 需要释放唤醒锁并且唤醒锁已获取到时
mWakeLock.release();
}
}
// 缓存唤醒锁状态
mStayAwake = awake;
// 更新Surface屏幕显示
// 内部执行的是SurfaceHolder的方法,因此放入以后相关章节分析,暂不分析
updateSurfaceScreenOn();
}
_start()实现:
native层方法
// [android.media.MediaPlayer.java]
private native void _start() throws IllegalStateException;
有前面章节的分析流程,可知对应于jni层android_media_MediaPlayer.cpp中的对应方法:
JNI方法映射,省略其他代码
// [frameworks/base/media/jni/android_media_MediaPlayer.cpp]
static const JNINativeMethod gMethods[] = {
{"_start", "()V", (void *)android_media_MediaPlayer_start}
}
android_media_MediaPlayer_start()实现分析:
// [frameworks/base/media/jni/android_media_MediaPlayer.cpp]
static void
android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
{
ALOGV("start");
// 获取native层此前创建缓存的MediaPlayer对象
// 备注:该实现不再分析,请参考前面已分析章节
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
}
// 调用native层MediaPlayer的start()方法
process_media_player_call( env, thiz, mp->start(), NULL, NULL );
}
mp->start()实现分析:
// [frameworks/av/media/libmedia/mediaplayer.cpp]
status_t MediaPlayer::start()
{
ALOGV("start");
status_t ret = NO_ERROR;
Mutex::Autolock _l(mLock);
// 获取本地线程ID
// 备注:注意该参数的意义所在,即该参数是用于MediaPlayer::notify()通知事件方法中判断通知回调时的线程
// 和当前请求的执行线程是否为同一个,若是不同则必现要加锁执行通知事件处理。
mLockThreadId = getThreadId();
if (mCurrentState & MEDIA_PLAYER_STARTED) {
// 此前已在播放状态时再次调用start方法则直接返回成功,不做其他处理
ret = NO_ERROR;
} else if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
// 若下一层播放器mPlayer不为空,并且当前状态为播放器已完成prepared状态、已播放完成状态、已暂停状态,
// 此三种状态下均可执行请求播放处理。
// 由前面章节分析可知,mPlayer是MediaPlayerService::Client在客户端的Bp端代理对象,
// 调用Client代理对象中方法即BpMediaPlayer代理类的对应方法实现。
// 因此后面的分析不在分析Binder机制的处理流程,直接分析其Bn实现端即BnMediaPlayer实现类即MediaPlayerService::Client对应实现。
// 上层APP是否在调用start之前设置了loop为true,默认为false,即true时表示需要自动循环播放
// 见下面的分析
mPlayer->setLooping(mLoop);
// 设置应用的左右音量,默认两值比例均为1即音量大小为当前系统音量设置的大小
// 见下面的分析
mPlayer->setVolume(mLeftVolume, mRightVolume);
// 设置【音效或混音】发送等级,其实就是调节音效增益效果,可参考java层MediaPlayer对应方法的注解
// 见下面的分析
mPlayer->setAuxEffectSendLevel(mSendLevel);
// 记录当前播放状态为 MEDIA_PLAYER_STARTED (已开始播放状态)
mCurrentState = MEDIA_PLAYER_STARTED;
// 此处将调用MediaPlayerService::Client.start()方法实现
// 见下面的分析
ret = mPlayer->start();
if (ret != NO_ERROR) {
// 请求下层播放器执行失败时,记录该状态
mCurrentState = MEDIA_PLAYER_STATE_ERROR;
} else {
if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
ALOGV("playback completed immediately following start()");
}
}
} else {
// 其他状态时表明调用start方法时当前播放器内部状态错误,即当前状态下不支持start操作,无效
ALOGE("start called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
ret = INVALID_OPERATION;
}
// 该流程执行完毕后将该值重置0
mLockThreadId = 0;
return ret;
}
关于native层Binder机制实现原理请查看:
Android C++底层Binder通信机制原理分析总结【通俗易懂】
1、mPlayer->setLooping(mLoop)对应的Bn实现端实现分析:
直接分析其Bn实现端即BnMediaPlayer实现类即MediaPlayerService::Client对应实现。
// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]
status_t MediaPlayerService::Client::setLooping(int loop)
{
ALOGV("[%d] setLooping(%d)", mConnId, loop);
// 缓存该值
mLoop = loop;
sp<MediaPlayerBase> p = getPlayer();
// 根据此前相关章节分析可知,此处将调用NuPlayerDriver的setLooping方法
if (p != 0) return p->setLooping(loop);
return NO_ERROR;
}
NuPlayerDriver的setLooping方法实现:
可以看到最终该值被缓存到了NuPlayerDriver中,其实该自动循环播放功能就是该类中实现的。(也就是在收到下一层播放器播放完成状态时检查该值是否为true,为true则直接seek 0 然后start从头开始播放)
// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp]
status_t NuPlayerDriver::setLooping(int loop) {
mLooping = loop != 0;
return OK;
}
mPlayer->setVolume(mLeftVolume, mRightVolume)实现分析:
设置应用的左右音量,默认两值比例均为1即音量大小为当前系统音量设置的大小
// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]
status_t MediaPlayerService::Client::setVolume(float leftVolume, float rightVolume)
{
ALOGV("[%d] setVolume(%f, %f)", mConnId, leftVolume, rightVolume);
// for hardware output, call player instead
sp<MediaPlayerBase> p = getPlayer();
{
Mutex::Autolock l(mLock);
// 由前面setDataSource章节分析可知,hardwareOutput()方法在NuPlayerDriver时默认返回false。
// 即默认未开启硬件输出模式
if (p != 0 && p->hardwareOutput()) {
MediaPlayerHWInterface* hwp =
reinterpret_cast<MediaPlayerHWInterface*>(p.get());
return hwp->setVolume(leftVolume, rightVolume);
} else {
// 执行AudioSink对应方法
// 见下面分析
if (mAudioOutput != 0) mAudioOutput->setVolume(leftVolume, rightVolume);
return NO_ERROR;
}
}
return NO_ERROR;
}
mAudioOutput->setVolume(leftVolume, rightVolume)实现分析:
// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]
void MediaPlayerService::AudioOutput::setVolume(float left, float right)
{
ALOGV("setVolume(%f, %f)", left, right);
Mutex::Autolock lock(mLock);
// 缓存应用左右音量值
mLeftVolume = left;
mRightVolume = right;
// 根据此前setDataSource章节分析可知,该类对象此时还未创建(其实它的创建会在后续执行AudioSink的open方法中)。
// 后续会分析到
if (mTrack != 0) {
mTrack->setVolume(left, right);
}
}
mPlayer->setAuxEffectSendLevel(mSendLevel)实现:
设置【音效或混音】发送等级,其实就是调节音效增益效果,可参考java层MediaPlayer对应方法的注解
// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]
status_t MediaPlayerService::Client::setAuxEffectSendLevel(float level)
{
ALOGV("[%d] setAuxEffectSendLevel(%f)", mConnId, level);
Mutex::Autolock l(mLock);
if (mAudioOutput != 0) return mAudioOutput->setAuxEffectSendLevel(level);
return NO_ERROR;
}
mAudioOutput->setAuxEffectSendLevel(level)实现:
// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]
status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level)
{
ALOGV("setAuxEffectSendLevel(%f)", level);
Mutex::Autolock lock(mLock);
// 缓存
mSendLevel = level;
// 根据此前setDataSource章节分析可知,该类对象此时还未创建(其实它的创建会在后续执行AudioSink的open方法中)。
// 后续会分析到
if (mTrack != 0) {
return mTrack->setAuxEffectSendLevel(level);
}
return NO_ERROR;
}
mPlayer->start() 即 MediaPlayerService::Client.start()方法实现分析:
// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]
status_t MediaPlayerService::Client::start()
{
ALOGV("[%d] start", mConnId);
// 根据此前相关章节分析可知,此处将调用NuPlayerDriver对应方法
sp<MediaPlayerBase> p = getPlayer();
if (p == 0) return UNKNOWN_ERROR;
// 见上面已有分析
p->setLooping(mLoop);
// 请求下层播放器执行播放请求流程
// 见下面的分析
return p->start();
}
p->start()实现分析:
// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp]
status_t NuPlayerDriver::start() {
ALOGV("start(%p), state is %d, eos is %d", this, mState, mAtEOS);
Mutex::Autolock autoLock(mLock);
return start_l();
}
start_l()实现:
// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp]
status_t NuPlayerDriver::start_l() {
switch (mState) {
case STATE_UNPREPARED:
// 由前面prepare处理流程章节分析可知,该状态为未执行prepare或prepare失败时的状态
{
// 此时需要先执行prepare流程,注意此时执行的prepare流程其实是同步prepare流程,
// 非异步prepare处理流程,因此上层APP必现注意这点即若跳过执行prepare直接进行start,那么可能会有耗时问题。
// 见下面的分析
status_t err = prepare_l();
if (err != OK) {
return err;
}
CHECK_EQ(mState, STATE_PREPARED);
FALLTHROUGH_INTENDED;
}
case STATE_PAUSED:
case STATE_STOPPED_AND_PREPARED:
case STATE_PREPARED:
// 以上几个状态时,将执行下一层播放器即NuPlayer对应方法
{
mPlayer->start();
FALLTHROUGH_INTENDED;
}
case STATE_RUNNING:
// 注意如果此前已经正在播放状态了,那么再次该方法时只是检查是否是播放结束
// (包括播放完成和播放异常时mAtEos都为true),若为true则直接从头seek播放
{
if (mAtEOS) {
mPlayer->seekToAsync(0);
mAtEOS = false;
mPositionUs = -1;
}
break;
}
default:
return INVALID_OPERATION;
}
// 记录正在播放状态
mState = STATE_RUNNING;
return OK;
}
prepare_l()实现分析:
同步执行prepare处理流程。
其实可以看到下面的实现,其实就是调用了下一层播放器NuPlayer的prepareAsync 和 seekToAsync方法,而这两个方法请见此前prepareAsync处理流程章节分析。同步执行流程不同之处就是需要同步等待下一层异步执行结果,因此就有了下面实现中的线程在mCondition该条件变量上等待wait。而该条件变量其实在此前的prepareAsync处理流程章节分析中可以知道,在prepare结束后将会向NuPlayerDriver通知该事件,然后其将会执行该条件变量唤醒其上等待的所有线程,即也就会唤醒此处的wait处,这样也就实现了同步prepare的处理流程。
因此下面的分析很简单不再详细分析了。关于seekToAsync方法实现分析将在后续seek流程章节分析。
// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp]
status_t NuPlayerDriver::prepare_l() {
switch (mState) {
case STATE_UNPREPARED:
mState = STATE_PREPARING;
// Make sure we're not posting any notifications, success or
// failure information is only communicated through our result
// code.
// 标记不是异步prepare流程
mIsAsyncPrepare = false;
mPlayer->prepareAsync();
// 等待执行结果
while (mState == STATE_PREPARING) {
mCondition.wait(mLock);
}
return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR;
case STATE_STOPPED:
// this is really just paused. handle as seek to start
mAtEOS = false;
mState = STATE_STOPPED_AND_PREPARING;
mIsAsyncPrepare = false;
mPlayer->seekToAsync(0, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */,
true /* needNotify */);
while (mState == STATE_STOPPED_AND_PREPARING) {
mCondition.wait(mLock);
}
return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR;
default:
return INVALID_OPERATION;
};
}
mPlayer->start() 即 NuPlayer的start() 实现分析:
推荐先查看:Android native层媒体通信架构AHandler/ALooper机制实现源码分析
// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp]
void NuPlayer::start() {
// 根据此前相关章节分析可知,发送【kWhatStart】事件消息给自身处理
(new AMessage(kWhatStart, this))->post();
}
【kWhatStart】事件消息处理:
// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp]
void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatStart:
{
ALOGV("kWhatStart");
// 此处说明一下mPaused、mPausedForBuffering、mPausedByClient的区别:
// mPaused:当前播放器真实实际暂停状态,包括Client端请求暂停或由于网络数据不足而缓冲暂停状态。
// mPausedForBuffering;网络数据不足而缓冲暂停状态。
// mPausedByClient:Client端请求暂停状态。
// 因此可以看出:mPaused = mPausedByClient + mPausedForBuffering的关系。
if (mStarted) {
// 此处理流程就是暂停情况下需要恢复播放处理流程,即注意:
// 在暂停请求处理流程中不会将修改 mStarted 的值,而在start流程中将会修改 mPaused 暂停状态值为false。
// 因此此处即为恢复播放处理流程,当然也需要考虑 mPausedForBuffering 参数值状态(默认值为false),
// mPausedForBuffering 该参数表示的是此前暂停状态的原因即
// 是buffer数据不足时的暂停状态,主要是用于网络请求缓冲处理时。
// 因此若需要数据缓冲时则不会再次处理恢复播放,而是等待数据缓冲流程结束,
// 否则将会执行恢复播放流程 onResume(),该流程处理见后续resume恢复播放流程章节分析。 TODO
// do not resume yet if the source is still buffering
if (!mPausedForBuffering) {
onResume();
}
} else {
// 执行开始播放处理流程
// 见下面的分析
onStart();
}
// 置为false
mPausedByClient = false;
break;
}
}
}
onStart()实现分析:
未传入参数,因此参数为方法声明默认值。
方法声明:
// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.h]
void onStart(
int64_t startPositionUs = -1,
MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC);
方法实现:
// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp]
void NuPlayer::onStart(int64_t startPositionUs, MediaPlayerSeekMode mode) {
// mCrypto 该信息对象表示的是当前播放源是受DMR即数字版权管理授权保护的加密信息,因此通常该值为空。
ALOGV("onStart: mCrypto: %p (%d)", mCrypto.get(),
(mCrypto != NULL ? mCrypto->getStrongCount() : 0));
if (!mSourceStarted) {
// 由此前章节分析可知,此处将指向GenericSource数据源对象的start()方法,并标记只执行一次
mSourceStarted = true;
// 见第1小节分析
mSource->start();
}
// startPositionUs 该值默认为-1,即不执行seek数据源操作。
if (startPositionUs > 0) {
// 此处暂不分析,默认从视频起点开始播放。
// seek流程见后续seek流程分析章节。TODO
performSeek(startPositionUs, mode);
if (mSource->getFormat(false /* audio */) == NULL) {
return;
}
}
// 初始化几个标记值
mOffloadAudio = false;
mAudioEOS = false;
mVideoEOS = false;
mStarted = true;
mPaused = false;
// 播放器渲染标记类型值
uint32_t flags = 0;
// GenericSource的isRealTime()该方法默认实现为false。
// 此返回值表示是否需要真实时间戳来同步音视频播放的同步时钟机制。
// 该flag有两种值枚举类型并且可能同时标记:FLAG_REAL_TIME 和
// FLAG_OFFLOAD_AUDIO(offload模式播放即平台音频硬解码器解码播放,
// 使用Callback回调方法来主动获取已解复用音频数据,然后以音频时间戳为基准时间来同步视频播放)
if (mSource->isRealTime()) {
flags |= Renderer::FLAG_REAL_TIME;
}
// 获取数据源音视频track格式信息即该track信息的媒体元数据信息对象,
// 若不为空则表示有该track信息即该媒体源有音频或视频数据。
// 见第2小节分析
bool hasAudio = (mSource->getFormat(true /* audio */) != NULL);
bool hasVideo = (mSource->getFormat(false /* audio */) != NULL);
if (!hasAudio && !hasVideo) {
// 若音视频数据源都不存在,则无法播放
ALOGE("no metadata for either audio or video source");
// 执行GenericSource数据源对象的stop()停止获取数据源流程
// 见第3小节分析
mSource->stop();
// 重置标记
mSourceStarted = false;
// 向上层播放器NuPlayerDriver通知该媒体数据异常无法播放错误事件,然后会一层层的往上层APP端上报该事件。
// 备注:该方法不再分析,前面章节中已分析过了。
notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_MALFORMED);
return;
}
ALOGV_IF(!hasAudio, "no metadata for audio source"); // video only stream
// 获取audio track信息的媒体元数据信息对象
// 见第2小节中的分析
sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
// 音频流类型(枚举值):默认为MUSIC流类型【AUDIO_STREAM_MUSIC】
audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
if (mAudioSink != NULL) {
// 根据前面setDataSource相关章节的分析可知,
// 当前mAudioSink不为空,会执行MediaPlayerServie::AudioOutput对象的该方法。
// 该值其实返回的是此前上层APP设置的audio属性值参数。
// 见第4小节分析
streamType = mAudioSink->getAudioStreamType();
}
// 判断是否支持offload音频流播放模式即使用平台音频硬解码器。
// 根据前面setDataSource分析第三章节可知,
// mPlaybackSettings该信息是播放速率参数,AUDIO_PLAYBACK_RATE_DEFAULT为默认值。
// 其播放速度mSpeed和音高mPitch均为1。其实就是音频硬解码器不支持变速播放。
// 见第5小节分析
mOffloadAudio =
canOffloadStream(audioMeta, hasVideo, mSource->isStreaming(), streamType)
&& (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
// 若有DRM数字版本管理媒体加密,则不支持offload模式。默认没有DRM
// Modular DRM: Disabling audio offload if the source is protected
if (mOffloadAudio && mIsDrmProtected) {
mOffloadAudio = false;
ALOGV("onStart: Disabling mOffloadAudio now that the source is protected.");
}
// 若支持offload音频播放模式,则设置播放器渲染标记类型值为offload模式
if (mOffloadAudio) {
flags |= Renderer::FLAG_OFFLOAD_AUDIO;
}
// 创建一个和NuPlayer进行消息通信的【kWhatRendererNotify】事件消息
sp<AMessage> notify = new AMessage(kWhatRendererNotify, this);
// 增加渲染器标志位即代数值,用于其他流程处理时判断是否应该丢弃其处理。默认为0
++mRendererGeneration;
// 添加该值参数
notify->setInt32("generation", mRendererGeneration);
// 创建渲染器,根据前面相关内容章节已有分析可知,
// 该实现其实就是new了一个NuPlayer::Renderer对象返回【因此不再分析create方法】。
// NuPlayer::Renderer类声明和构造函数实现
// 见第6小节分析
mRenderer = AVNuFactory::get()->createRenderer(mAudioSink, mMediaClock, notify, flags);
// 创建Renderer渲染器的ALooper消息机制
// 备注:关于ALooper的实现机制请查看上面推荐的ALooper分析章节分析
mRendererLooper = new ALooper;
mRendererLooper->setName("NuPlayerRenderer");
mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
// 由第6小节分析可知Renderer类是AHandler子类,因此可以注册到ALooper中接收该消息系统的消息事件处理
mRendererLooper->registerHandler(mRenderer);
// 设置播放设置信息对象给Renderer对象缓存和处理
// 备注:该实现流程暂不分析了,其主要实现,就是将该信息传递给渲染器去缓存
// 并且设置给MediaClock的setPlaybackRate方法处理播放速率。
// 但注意,若设置播放速率为0,那么将会停止渲染【onPause()】。
// NOTE:该调用将会和Renderer消息线程同步执行,并等待返回。
status_t err = mRenderer->setPlaybackSettings(mPlaybackSettings);
if (err != OK) {
// 失败处理
mSource->stop();
mSourceStarted = false;
notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
return;
}
if (mSurface != NULL) {
// surface不为空时
int64_t refreshDuration = 0;
// 获取native window刷新周期时长,也就是屏幕刷新间隔时长(单位为NS纳秒)。
// 其内部实现其实很简单,就是执行Surface的perform方法传入
// NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION标志位来获取其屏幕刷新时长,
// 关于Surface的perform方法放入后面Surface相关分析章节
native_window_get_refresh_cycle_duration(mSurface.get(), &refreshDuration);
if (refreshDuration > 0)
// 若大于0,则此处将会计算1秒内Surface屏幕刷新次数即屏幕刷新率。然后四舍五入得到允许的视频最大输出帧率。
mMaxOutputFrameRate = round(1000000000.0f / refreshDuration);
}
// 获取媒体默认视频帧率,失败将返回-1,无视频track将返回0
// 见第7小节分析
float rate = getFrameRate();
if (rate > 0) {
// 获取成功时,获取最佳可支持视频帧率
rate = (rate > mMaxOutputFrameRate) ? mMaxOutputFrameRate : rate;
// 设置给渲染器该信息
// 见第8小节分析
mRenderer->setVideoFrameRate(rate);
}
// 向解码器设置渲染器
// 第一次请求播放情况下,此时音视频解码器都还未创建,因此此处分析将放入后续的分析中
if (mVideoDecoder != NULL) {
mVideoDecoder->setRenderer(mRenderer);
}
if (mAudioDecoder != NULL) {
mAudioDecoder->setRenderer(mRenderer);
}
// 启动播放计时器
// 见第9小节分析
startPlaybackTimer("onstart");
// 发送扫描数据源消息事件去处理
// 见第10小节分析
postScanSources();
}
1、mSource->start() 实现分析:
由此前章节分析可知,此处将指向GenericSource数据源对象的start()方法,该方法只运行执行一次。
其实看这个实现其实很简单,就是此前prepare分析章节中分析到的audio track和video track两个对象执行其读取数据解复用处理流程,postReadBuffer() 该方法分析请查看前面prepare章节完整的分析,而该处理流程其实已在prepare章节执行过一次了。因此start方法的不同之处在于,记录了mStarted的值为true。即数据源已启动工作标志。
// [frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp]
void NuPlayer::GenericSource::start() {
Mutex::Autolock _l(mLock);
ALOGI("start");
if (mAudioTrack.mSource != NULL) {
postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
}
if (mVideoTrack.mSource != NULL) {
postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
}
// 标记数据源已启动工作
mStarted = true;
}
2、mSource->getFormat(true /* audio */)实现分析:
获取GenericSource数据源对象的音视频track格式信息即该track信息的媒体元数据信息对象,若不为空则表示有该track信息即该媒体源有音频或视频。
【关于AMessage实现原理:Android native层媒体通信架构AHandler/ALooper机制实现源码分析】
注意该方法其实不是在GenericSource.cpp中实现的,getFormat该方法是父类中声明的,而它是在NuPlayer.cpp中实现的,如下
// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp]
sp<AMessage> NuPlayer::Source::getFormat(bool audio) {
// getFormatMeta该方法也是父类中声明的,但相反的是,该方法是在GenericSource中实现的。
// 见下面的分析
sp<MetaData> meta = getFormatMeta(audio);
if (meta == NULL) {
return NULL;
}
sp<AMessage> msg = new AMessage;
// 此处将该track信息的媒体元数据KV信息全部转换到AMessage消息对象中存储,以供后续访问使用。
// 关于AMessage实现原理请查看上面提到的另外章节。
// convertMetaDataToMessage() 该方法的实现分析请查看前面prepare章节中已有的分析。
if(convertMetaDataToMessage(meta, &msg) == OK) {
return msg;
}
return NULL;
}
getFormatMeta(audio)的实现:
// [frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp]
sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
Mutex::Autolock _l(mLock);
return getFormatMeta_l(audio);
}
getFormatMeta_l(audio)实现分析:
【可查看相关章节内容:Android底层音视频播放媒体提取器【MediaExtractor】的解复用模块demuxers模块化加载和注册流程实现源码分析】
// [frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp]
sp<MetaData> NuPlayer::GenericSource::getFormatMeta_l(bool audio) {
// 根据前面prepare章节分析可知,此处获取的是能够访问底层具体媒体提取器解复用器实现的音频或视频track信息对象。
sp<IMediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
// 若为空,则当前媒体源没有对应的音频或视频数据源
if (source == NULL) {
return NULL;
}
// 因此此处将会获取到底层具体媒体提取器解复用器实现的音频或视频track信息对象的对应方法,
// 将返回该track对象的媒体元数据信息对象。
return source->getFormat();
}
3、mSource->stop()实现分析:
执行GenericSource数据源对象的stop()停止数据源工作流程。其实此处只是修改前面为true的mStarted变量为false。
该变量将会在后续分析的解码器获取解复用数据处理流程即GenericSource::dequeueAccessUnit()方法中作为是否应该获取解复用数据判断处理。若为false,则将会返回无数据源状态码给到解码器获取数据流程去做响应的处理。
// [frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp]
void NuPlayer::GenericSource::stop() {
Mutex::Autolock _l(mLock);
mStarted = false;
}
4、mAudioSink->getAudioStreamType()实现分析:
会执行MediaPlayerServie::AudioOutput对象的该方法。直接返回设置的变量参数值,而该值其实就是此前章节分析中,AudioOutput的setAudioStreamType方法设置的音频流类型。
// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.h]
virtual audio_stream_type_t getAudioStreamType() const { return mStreamType; }
5、canOffloadStream(audioMeta, hasVideo, mSource->isStreaming(), streamType)实现分析:
判断是否支持offload音频流播放模式即使用平台音频硬解码器。
由于篇幅长度过长,因此放入下一章节分析,请查看:
【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 2】