注册StagefrightPlayer
StagefrightPlayer是对AwesomePlayer的封装,用mPlayer指向AwesomePlayer,StagefrightPlayer是一个壳,真正干活的是AwesomePlayer
在调用MediaPlayerService的setDataSource的函数后,会到达StagefrightPlayer中的setDataSource函数
所以代码都会调用到 mPlayer->setDataSource(source);接下来到达AwesomePlayer的setDataSource函数
status_t AwesomePlayer::setDataSource(
int fd, int64_t offset, int64_t length) {
Mutex::Autolock autoLock(mLock);
reset_l();
sp<DataSource> dataSource = new FileSource(fd, offset, length);
status_t err = dataSource->initCheck();
if (err != OK) {
return err;
}
mFileSource = dataSource;
#ifndef ANDROID_DEFAULT_CODE
String8 tmp;
if( mFileSource->fastsniff(fd, &tmp))
{
const char *sniffedMIME = tmp.string();
sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource, sniffedMIME);
if (extractor == NULL) {
return UNKNOWN_ERROR;
}
if (extractor->getDrmFlag()) {
checkDrmStatus(dataSource);
}
return setDataSource_l(extractor);
}
#endif
{
Mutex::Autolock autoLock(mStatsLock);
mStats.mFd = fd;
mStats.mURI = String8();
}
return setDataSource_l(dataSource);
}
解析数据,检测mime,计算比特率
根据mime判断音频视频及其他类型,OGG类型,如视频,获取显示区域的高宽,其实质是做音视频分离,分别分在mAudioTrack,mVideoTrack两个MediaSource中
String8 mime = String8(_mime);
if (!haveVideo && !strncasecmp(mime.string(), "video/", 6)) {
setVideoSource(extractor->getTrack(i));
haveVideo = true;
// Set the presentation/display size
int32_t displayWidth, displayHeight;
bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth);
if (success) {
success = meta->findInt32(kKeyDisplayHeight, &displayHeight);
}
if (success) {
mDisplayWidth = displayWidth;
mDisplayHeight = displayHeight;
}
{
Mutex::Autolock autoLock(mStatsLock);
mStats.mVideoTrackIndex = mStats.mTracks.size();
mStats.mTracks.push();
TrackStat *stat =
&mStats.mTracks.editItemAt(mStats.mVideoTrackIndex);
stat->mMIME = mime.string();
}
} else if (!haveAudio && !strncasecmp(mime.string(), "audio/", 6)
void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
CHECK(source != NULL);
mAudioTrack = source;
}
void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
CHECK(source != NULL);
mVideoTrack = source;
}
awesomeplayer主要用于本地播放,匹配不同的文件类型,并用数据解析器处理,mime表示资源的媒体类型,,**当出现常用的音视频封装格式时,**android播放器在Manifest.xml中设置了对应的类型,就能被播放器识别到,点击手机中的文件图标,就会弹出一个用哪个软件打开的提示
看一下数据解析器
MediaExtractor::Create
#ifndef ANDROID_DEFAULT_CODE
sp<MediaExtractor> ret;
#else
MediaExtractor *ret = NULL;
#endif
#ifdef MTK_PLAYREADY_SUPPORT
if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
|| !strcasecmp(mime, "audio/mp4") || !strcasecmp(mime, "video/ismv")) {
#else
if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
|| !strcasecmp(mime, "audio/mp4")) {
#endif
ret = new MPEG4Extractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
ret = new MP3Extractor(source, meta);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
|| !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
ret = new AMRExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {
ret = new FLACExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {
ret = new WAVExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {
ret = new OggExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {
ret = new MatroskaExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
ret = new MPEG2TSExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
#ifndef ANDROID_DEFAULT_CODE
#ifdef MTK_MTKPS_PLAYBACK_SUPPORT
ret = new MPEG2PSExtractor(source);
#else //MTK_MTKPS_PLAYBACK_SUPPORT
ALOGV(" MediaExtractor::is PS file, not support playing now");
ret =NULL;
#endif //MTK_MTKPS_PLAYBACK_SUPPORT
#else //#ifndef ANDROID_DEFAULT_CODE
ret = new MPEG2PSExtractor(source);
#endif //#ifndef ANDROID_DEFAULT_CODE
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_AVI)) {
#ifndef ANDROID_DEFAULT_CODE
#ifdef MTK_AVI_PLAYBACK_SUPPORT
ret = new MtkAVIExtractor(source);
#endif
#endif //#ifndef ANDROID_DEFAULT_CODE
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM)) {
// Return now. WVExtractor should not have the DrmFlag set in the block below.
return new WVMExtractor(source);
}
#ifndef ANDROID_DEFAULT_CODE
else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
ret = new MtkAACExtractor(source,meta);
}
#else
else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
ret = new AACExtractor(source, meta);
}
#endif
#ifndef ANDROID_DEFAULT_CODE
#ifdef MTK_WMV_PLAYBACK_SUPPORT
else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_ASF)) {
ret = ASFExtractorCreateInstance(source);
}
#endif
#ifdef MTK_FLV_PLAYBACK_SUPPORT
else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_FLV)) {
ret = new FLVExtractor(source);
}
#endif//#ifdef MTK_FLV_PLAYBACK_SUPPORT
#ifdef MTK_AUDIO_APE_SUPPORT
else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_APE)) {
ret = new APEExtractor(source, meta);
}
#endif
else if (!strcasecmp(mime, MEDIA_MIMETYPE_APPLICATION_SDP)) {
ret = new MtkSDPExtractor(source);
}
#ifdef MTK_OGM_PLAYBACK_SUPPORT
else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGM)) {
ret = new OgmExtractor(source);
}
#endif//#ifdef MTK_OGM_PLAYBACK_SUPPORT
#endif
if (ret != NULL) {
if (isDrm) {
ret->setDrmFlag(true);
} else {
ret->setDrmFlag(false);
}
}
ALOGD("JB -MediaExtractor::Create");
return ret;
针对文件解析的不同格式创建MediaExtractor解析器并解析,然后再回到setDataSource_l对新建的解析器做处理,
其实质是做音视频分离,demux
MediaPlayerService->StagefrightPlayer->AwesomePlaye->MPEG4Extractor->MPEG4Source
setAudioSource(extractor->getTrack(i));设置音频源 mAudioTrack
setVideoSource(extractor->getTrack(i));设置视频源 mVideoTrack
awesomeplayer解码过程
上面将音视频分离出来了,并分离出音频,视频,我们来看一上解码过程
awesomeplayer-》prepare->prepare_l->prepareAsync_l->beginPrepareAsync_l->
initVideoDecoder 初始化视频解码器
initAudioDecoder初始化音频解码器
如果是网络流,需要缓冲一下
初始化视频解码器
initVideoDecoder OMXCodec是视频解码器,主要负责编码,解码相关操作
initAudioDecoder大多和initVideoDecoder差不多,只是OMXCodec::Create参数中为mAudioTrack
awesomeplayer构造函数结束后,在setDataSource之后会调用prepare方法,其实现中会调用initAudioDecoder和initVideoDecoder由于在setDataSource中已经拿到了对应的解码器信息,因此此处initxxxxDecoder 便可以构造实际的解码器了
prepare
中完成了以下三件事
1。启动下载数据并缓存
2。初始化并创建编解码器
3。通知上层处理prepared状态
使用OMXCodec解码过程
从OMXCodec读到的数据已经是原始数据了,数据经过parse,decode两步后转化为原始数据
OMXCodec mAudioSource->start 初始化主要做了如下两件事
1.
err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
2.
allocateBuffers分配两个缓冲区,存放在mPortBuffers[2]中,分别用于输入输出
initxxxDecoder调用start(mVideoSource->start()/mAudioSource->start())
会触发MediaSource的子类VideoSource/AudioSource调用start函数后,它的内部就会开始从数据源获取数据并解析,等到缓冲区区满后停止,在awesomeplayer可以调用mediasource的read函数,读取解码后的数据
1。对于mVideoSource来说,将读取的数据mVideoSource->read(&mVideoBuffer, &options)交给显示模块进行渲染
2。对于mAudioSource来说,用mAudioPlayer对mAudioSource进行封装,然后由mAudioPlayer负责读取数据和播放器控制
3。awesomeplayer调用OMXCodec读取ES(基本码流,包括音频,视频,或数据的连续码流)并进行解码器处理
4。OMXCodec调用MediaSource的read来获取音视频数据
5。OMXCodec调用Android的IMOX的接口来实现一些音视频解码器操作
上面就是prepare的过程,主要用于分离音视频,给音频视频申请好buffer空间,做预解码操作
mediaPlayer.start->MediaplayerService->IPC->StagefrightPlayer.start->awesomeplayer.play
AwesomePlayer->play->play_l->
调用play后,通过 mVideoSource->read(&mVideoBuffer, &options);来读取数据,即也是通过omxcodec::read来读取数据,
1。调用drainInputBuffer函数对mPortBuffers[kPortIndexInput],这一步完成prase,由openmax从数据源把demux后的数据读取到输入缓冲区,作为openmax的输入
2。通过fillOutputBuffer对mPortBuffers[kPortIndexOutput]进行填充,这一步完成对解码数据的填充,由openmax对输入缓冲区的数据进行解码,然后把解码后的显示数据输出到输出缓冲区
AwesomePlayer.cpp通过mVideoRenderer->render(mVideoBuffer);对经过prase和decode处理的数据进行渲染,一个mVideoRenderer其实就是AwesomeNativeWindowRenderer
MeiaSource<------read-----OmxCodec-<–read----VideoRender/Audioplayer
渲染的构建
是在通知完解码完成的事件回调中实现
在AwesomePlayer构造一个AwesomeEvent传入onVideoEvent的引用地址
AwesomePlayer::AwesomePlayer()
mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
initRenderer_l初始化渲染器
startAudioPlayer_l开始音频解码
mVideoBuffer表示的是视频的buffer
我们将首先寻找视频源,然后是音频源。 为了避免由于音频编解码器从旧位置预取数据而导致的数据源偏移中的跳转
而视频编解码器已经从新的数据中读取数据位置,我们将“暂停”音频源,使其停止读取输入数据,直到后续搜索。
读出视频数据,再行视频渲染
initRenderer_l-》逻辑为如果是硬解码,则构建AwesomeNativeWindowRenderer渲染器,如果是软解码器,则构建AwesomeLocalRenderer渲染器,这两个渲染器都继承自AwesomeRenderer,
mNativeWindow是显示的窗口,由AwesomePlayer::setSurfaceTexture->setNativeWindow_l设置
代码的程序是:
setDisplay->_setVideoSurface->android_media_MediaPlayer_setVideoSurface->setVideoSurface->mp->setVideoSurfaceTexture(new_st)->
mPlayer->setSurfaceTexture(bufferProducer)->setNativeWindow_l
AwesomeNativeWindowRenderer与AwesomeLocalRenderer的分别是,AwesomeLocalRenderer会创建一个软渲染器
将音频数据放到buffer的过程
https://blog.csdn.net/tjy1985/article/details/7397752
数据的缓冲的执行者在onBufferingUpdate当数据缓冲区有足够数据播放时,调用play_l函数进行播放,play_l函数的关键是调用 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);-》AwesomePlayer::onVideoEvent()
Stagefright构架中音频播放用audioplayer来处理,它是在awesomeplayer中函数play_l被构建
createAudioPlayer_l创建audioplayer
createAudioPlayer_l
createAudioPlayer_l:
mAudioPlayer->setSource(mAudioSource);发送数据给播放器
构造audioplay时用到了maudiosink对象,实际上maudiosink为AudioOut对象
如MediaPlayerService中的定义:
startAudioPlayer_l
看一下, mAudioPlayer->start
这里若maudiosink为非空,则用maudiosink进行输出,maudiosink为AudioOut,AudioOut是audiotrack的封装
空则构建一个audiotrack进行输出
上面中AudioSinkCallback,start函数执行后会定期调用此函数从解码器中填充数据到解码后的队列中,
音视频同步
通过fillBuffer,不断的填充Buffer,
fillBuffer
mPositionTimeMediaUs音频帧在媒体文件中的时间戳
mPositionTimeRealUs播放此数据的实际时间(依据帧率和采样率算出)
Stagefright中的video依据得出的这两个时间戳的差值作为播放的依据
音视频同步
void AwesomePlayer::onVideoEvent() {
mVideoRenderer->render(mVideoBuffer);
}