yanghn2002

View My GitHub Profile

AWPlayerHPP

一个 header-only 的封装库,对全志 Soc 硬解码视频播放器( TPlayer )的封装。

实现

首先,我并没有选择把应用程序链接到全志的动态库,因为除了 libtplayer.so 还需要链接更多更多动态库,我记得至少得有十多个,这太复杂了,动态加载的话反而都要简单不少,所以我选择后者。
加载动态库我实现了一个基类,带一个 load_symbols 的接口,可以调用 load_symbol 来加载所需的符号:

protected:
    template<typename SYM_T>
    SYM_T _load_symbol(const char* symbol) {
        if(_bool()) {
            SYM_T ptr = reinterpret_cast<SYM_T>(::dlsym(_dll, symbol));
            if(ptr) return ptr;
            else throw std::runtime_error("dlsym");
        } else return nullptr;
    }
    virtual void load_symbols(void) = 0;

播放器的基类 AWPlayer::AWPlayer 我定义了几个接口:

protected:
    virtual void _prepare(void) = 0;
    virtual void _start(void) = 0;
    virtual void _pause(void) = 0;
    virtual void _reset(void) = 0;
    virtual void _stop(void) = 0;
public:
    virtual void setVideo(const std::string&) = 0;
    virtual void setDisplayRect(const int, const int, const uint32_t, const uint32_t) = 0;

直接调用基类的 play 方法就可以直接从 url 播放视频:

void play(const std::string& url) {
    setVideo(url);
    prepare();
    start();
}

状态

TPlayer 播放器本身维护了一个状态机,在不同状态下允许不同行为。为了获得当前状态,它有一个接口 TPlayerIsPlaying ,但这肯定是不够的。我需要从 NotifyCallback 来获取状态然后根据参数判断事件再更新状态。
但这样为什么我不直接允许用户给不同时间直接注册回调呢?因为我不能在 NotifyCallbak 里面调用 AWPlayer 的 API ,会导致死锁,所以我只能在本地更新状态再允许用户轮询。当然我给了两个比较方便的接口:

enum State {
    ERROR    =-1,
    IDLE     = 0,
    COMPLETE = 1,
    STOPED   = 2,
    PLAYING  = 3,
    PREPARED = 4,
    PAUSED   = 5,
};
State state(void) {
    return _state;
}
bool isOk(void) {
    return static_cast<int>(_state) >= 0 ? true : false;
}
bool isWorking(void) {
    return static_cast<int>(_state) >= 3 ? true : false;
}

后续

没有后续了, TPlayer 可以用, XPlayer 没法实现。

本来我还在疑惑一件事,就是为什么全志有两套好像没什么区别的视频播放器实现,现在我知道了因为这个 XPlayer 并不是个完成品,我的意思是我全靠 libxplayer.so 是完全无法实现视频的播放的, xplayerdemo 本身还直接调用了 libcedarx 的其他接口,然后静态链接进去。然后 libtplayer 就是把 XPlayer 和其他播放所需的内容再封装一层得到的产物。所以我之前看到好像所有 TPlayer 的实现好像都是在调用 XPlayer ……
这种软件架构上的情况其实一般就反应着公司的管理情况。