StagefrightPlayer

注册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方法,其实现中会调用initAudioDecoderinitVideoDecoder由于在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对象,实际上maudiosinkAudioOut对象
如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);
}

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值