stagefright框架下的awesomeplayer设置数据源阶段

Android的MediaPlayerService下一个重要的框架就是stagefright(演讲胆怯者),在它之下就是具体的播放器了。与其关系同等的是NuPlayer,本文将分析stagefright常规框架和一些关键技术。

先看几个类的关系:

class MediaPlayerBase : public RefBase
class MediaPlayerInterface : public MediaPlayerBase
class StagefrightPlayer : public MediaPlayerInterface 
struct AwesomePlayer 

struct AHandler : public RefBase 
struct NuPlayer : public AHandler 
struct NuPlayerDriver : public MediaPlayerInterface

以RefBase为基准,MediaPlayerBase和AHandler处于同一级,StagefrightPlayer与NuPlayerDriver为同一级,代表两种不同的架构的播放器。AwesomePlayer与NuPlayer为同一级,代表在两种不同播放器架构下具体的播放器实现。
一般说来,现在本地文件播放用AwesomePlayer,而流媒体用NuPlayer,难道是NuPlayer对RTP处理得更好?

一个播放器通常的架构或者说工作流程为:

创建播放器 – 设置数据源 – 音视频分离 – 编解码 – 渲染 – 画面呈现

先来看下AwesomePlayer的构造函数:

AwesomePlayer::AwesomePlayer()
    : mQueueStarted(false),      
      mAudioPlayer(NULL),
      mFlags(0),
      mExtractorFlags(0),
      mVideoBuffer(NULL),
      mDecryptHandle(NULL),      

      DataSource::RegisterDefaultSniffers();

    mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
    mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
    mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
    mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate);

mAudioPlayer音频播放器,mFlags播放状态标志,mDecryptHandle解密处理,mVideoBuffer视频处理buffer。
接着注册数据源嗅探器,所谓的嗅探器对应着不同格式的文件,即从一个给定的文件源中,获取相应的字段,以确定文件类型:
DataSource::RegisterDefaultSniffers();

    RegisterSniffer_l(SniffMPEG4);
    RegisterSniffer_l(SniffMatroska);
    RegisterSniffer_l(SniffOgg);
    RegisterSniffer_l(SniffWAV);
    RegisterSniffer_l(SniffFLAC);
    RegisterSniffer_l(SniffAMR);
    RegisterSniffer_l(SniffMPEG2TS);
    RegisterSniffer_l(SniffMP3);
    RegisterSniffer_l(SniffAAC);
    RegisterSniffer_l(SniffMPEG2PS);
    RegisterSniffer_l(SniffWVM);

    char value[PROPERTY_VALUE_MAX];
    if (property_get("drm.service.enabled", value, NULL)
            && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
        RegisterSniffer_l(SniffDRM);
    }

除了常见的mp3、mp4等还有一个DRM嗅探器(Digital Rights Management数字版权管理)。

最后注册了几个重要事件:
mVideoEvent,mStreamDoneEvent,mBufferingEvent,mVideoLagEvent
当这些事件触发时会调用相关联的函数,即回调函数。

还是从status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)开始,

status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length) {
    player_type playerType = MediaPlayerFactory::getPlayerType(this,fd, offset, length);
    sp<MediaPlayerBase> p = setDataSource_pre(playerType);
    // now set data source
    setDataSource_post(p, p->setDataSource(fd, offset, length));
}

这里playerType=StagefrightPlayer,即AwesomePlayer。创建好AwesomePlayer实例,调用其setDataSource方法:

status_t AwesomePlayer::setDataSource(
        int fd, int64_t offset, int64_t length) {    
    sp<DataSource> dataSource = new FileSource(fd, offset, length);
    status_t err = dataSource->initCheck();
    return setDataSource_l(dataSource);
}

status_t AwesomePlayer::setDataSource_l(
        const sp<DataSource> &dataSource) {
    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);

    if (extractor->getDrmFlag()) {
        checkDrmStatus(dataSource);
    }

    return setDataSource_l(extractor);
}

class FileSource : public DataSource 
class DataSource : public RefBase 
class MP3Extractor : public MediaExtractor 
class MediaExtractor : public RefBase 

根据传入的mp3文件构造一个dataSource,然后开始创建分离器:ediaExtractor::Create(dataSource);

p<MediaExtractor> MediaExtractor::Create(
        const sp<DataSource> &source, const char *mime) {
    if (!source->sniff(&tmp, &confidence, &meta))
        mime = tmp.string();

    MediaExtractor *ret = NULL;
    else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
        ret = new MP3Extractor(source, meta);
}
RegisterSniffer_l(SniffMP3);
bool SniffMP3(
        const sp<DataSource> &source, String8 *mimeType,
        float *confidence, sp<AMessage> *meta) {
    *meta = new AMessage;
    (*meta)->setInt64("offset", pos);
    (*meta)->setInt32("header", header);
    (*meta)->setInt64("post-id3-offset", post_id3_pos);

    *mimeType = MEDIA_MIMETYPE_AUDIO_MPEG;
    *confidence = 0.2f;
    return true;
}

先嗅探出mime字串,根据dataSource中的mime值MEDIA_MIMETYPE_AUDIO_MPEG,创建一个mp3分离器:MP3Extractor。然后调用setDataSource_l:
status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor)
开始音频和视频数据分离:

status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
    CHECK(meta->findCString(kKeyMIMEType, &_mime));
    if (!haveVideo && !strncasecmp(mime.string(), "video/", 6)) {
        setVideoSource(extractor->getTrack(i));
        meta->findInt32(kKeyDisplayWidth, &displayWidth);
        meta->findInt32(kKeyDisplayHeight, &displayHeight);
    } else if (!haveAudio && !strncasecmp(mime.string(), "audio/", 6)) {
        setAudioSource(extractor->getTrack(i)); 
    }

    mExtractorFlags = extractor->flags();   

分离前先从mp3文件中找到kKeyMIMEType结构,标识着video还是audio。视频分离setVideoSource(extractor->getTrack(i));同时将视频显示的高度和宽度记录下来。音频分离也很简单:setAudioSource(extractor->getTrack(i));
分离完成后,设置分离之后的标志:
CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;

这样AwesomePlayer的实例就创建好了,并且数据设置完毕,音视频也分离开来,成为独立的数据源。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值