• awsomeplayer结构认识


    把这个搞明白,算是顿悟的一个真实例子。怎么也搞不懂的架构,突然就想明白了。不过这其实是一个思维的过程。

    当然如果你想明白这些东西,至少要非常清楚一个概念:接口。

    我只是一个半路出家的开发者,我真正明白什么接口时,我已经写了一年多代码了。书面的解释实在拗口,我记不住。

    我的理解就是:接口,在C语言里面,就是函数接口,在C++里面就是纯虚函数,在java里面就是interface。用接口,而不是实现来编程一个最大的好处就是:隔离变化。其实这些东西,都是我在李先静老师《系统程序员成长计划》里面领悟到的。

    好吧说完了接口的体会,少说废话,步入正题。

    我们要思考一个问题,对于一个播放器,解决的主要问题有哪些?当然是播放音视频。如何播放?播放的过程有哪几步?

    想到这一点,剩下的东西,就很简单了。

    播放器的四大基本组件:access/demux/decode/render。(这些知识,我已经在之前的文章写过了)

    下面来看android awesomeplayer是如何抽象这四大组件的。时刻记住,我们是面向接口编程,一定要找准接口。

    1.access

    有些问题我们之前说过,获取stream的方式是多样的,本地文件,rtsp,http都有可能。我们要足够抽象才行。其实我不知道如何抽象一个好的接口,这也不是这个文章的要点,我们的要点是:印证自己的想法,理解别人的设计理念。

    android抽象了一个叫DataSource的接口类,来隔离获stream方式的变化。

    virtual status_t initCheck() const = 0;

    virtual ssize_t readAt(off64_t offset, void *data, size_t size) = 0;

    这个类,规定了两个接口。我们剩下的任务就是找出谁继承了这个类,就知道android能支持的stream种类了。

    class FileSource : public DataSource 

    struct HTTPBase : public DataSource 

    struct ChromiumHTTPDataSource : public HTTPBase

    struct NuCachedSource2 : public DataSource

    这里http方式的流,没有直接继承datasource,而是又加了一层包装,另外这个http协议的实现是直接使用的webkit的库。

    最后一种stream,我也没搞明白是什么。。。。。

    这三种流,分别实现了上述的两个接口,完全了第一步抽象。

    2.demux

    同理,不同的container,也是需要隔离变化的,avi,mkv,mp4,需要不同的实现。我们不多说其他的,找出基类,看看谁继承了他。

    原来他叫MediaExtractor ,再来看看他抽象了什么接口:

    virtual size_t countTracks() = 0;
    virtual sp<MediaSource> getTrack(size_t index) = 0;

    virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags = 0) = 0;

    ok,原来是这三个接口需要实现。

    再来看看谁实现了他。

    class AacAdtsExtractor : public MediaExtractor

    class AACExtractor : public MediaExtractor

    struct ARTSPController : public MediaExtractor

    struct AVIExtractor : public MediaExtractor

    class DRMExtractor : public MediaExtractor 

    class FLACExtractor : public MediaExtractor 

    struct MatroskaExtractor : public MediaExtractor

    class MP3Extractor : public MediaExtractor

    struct MPEG2TSExtractor : public MediaExtractor 

    class MPEG4Extractor : public MediaExtractor 

    struct OggExtractor : public MediaExtractor 

    class WAVExtractor : public MediaExtractor 

    这就是android默认支持的demux文件各类了,如果我们要支持新的文件格式,比如flv,就可以新加个类

    比如:class FlvExtractor:pulic MediaExtractor这样的,然后实现上述三个接口,就可以支持flv文件格式了。

    3.encodec/decodec

    这块代码主要是omx在实现,比较复杂,但还是符合我们上述所说的接口抽象,隔离变化的原则的

    主要的抽象类是:

    MediaSource

       virtual status_t start(MetaData *params = NULL) = 0;
       virtual status_t stop() = 0;
       virtual sp<MetaData> getFormat() = 0;

       virtual status_t read(MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;

    MediaBufferObserver

      virtual void signalBufferReturned(MediaBuffer *buffer) = 0;

    这里使用了观察者模式,我不知道为什么要这么设计才好,理解不了这样的设计,但是隐隐知道是有道理的。

    实现这两个类的是:

    struct OMXCodec : public MediaSource,public MediaBufferObserver 

    当然是OMXCodec,这个类,隔离了所有的codec的种类,软解,硬解,h264,mpeg4,mp3。。。。。

    这是awesomeplayer中最复杂的类,隔离了最复杂的东西,屏避了最大的变化。

    从代码分析,原生代码里面omxcodec只支持软解,但是对实际的soc来说,都加入了硬解支持。

    下篇文章会分析,omx的组件如何构成以及如何在omxcodec里面加入硬解支持。

    4.render。

    对于这一步来说,android似乎是最轻松的,因为不用考虑太多变化的问题。因为对android的render来说,实际上没有任何变化。音频直接给audioflinger,图像直接给surfaceflinger。

    这里只需要简单包装一下即可。

    因为我只对视频有兴趣,我们就看看视频是如何抽象的。这一步甚至已经简单到不用单独起一个文件的地步了。其实整个stragefright目录,除掉上面写的那些类(每个类基本都是一个文件)和一些基本工具类(比如handler,timeevent,string。。类),就没有太多额外的东西了。整体架构比较简洁,比起vlc/directshow这种重型的多媒体框架/应用来说,相当简单。

    这个类,只有一个接口。两种实现

    struct AwesomeRenderer 

    virtual void render(MediaBuffer *buffer) = 0;

    struct AwesomeLocalRenderer : public AwesomeRenderer

    struct AwesomeNativeWindowRenderer : public AwesomeRenderer

    local/native不同codec出来的数据

    这里有几行注释,

    // Hardware decoders avoid the CPU color conversion by decoding
    // directly to ANativeBuffers, so we must use a renderer that
    // just pushes those buffers to the ANativeWindow.

    可以解释这个问题。

    localrenderer,额外做了colorspace转化的工作,当然一般都是yv12/nv12(i420p)到rgb565这种,大众的,呵呵,如果你要支持特殊硬件,就要自己手写了。

    好了。主要内容就是这些,理一下框架

    datasource-->MediaExtractor-->MediaSource--->AwesomeRenderer 

    四大步,四种抽象接口。与其他的多媒体框架相比,抽象方法是一样的,只是接口略有区别。over..

  • 相关阅读:
    我们可以用微服务创建状态机吗?
    MyBatis 实现一对多有几种方式,怎么操作的?
    说几个 zookeeper 常用的命令?
    使用 RabbitMQ 有什么好处?
    消息基于什么传输?
    如何获取自动生成的(主)键值?
    vue打包压缩
    mysqldump数据库全备份_MySQL
    mysql的binlog
    开启BinLog_MySQL
  • 原文地址:https://www.cnblogs.com/mr-nop/p/3280271.html
Copyright © 2020-2023  润新知