一个 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 ……
这种软件架构上的情况其实一般就反应着公司的管理情况。