1背景
这一篇是继续上一篇hplyaer的后续
2 详细记录
2.1 getIdlePlayer
在HMultiView.cpp中有如下代码
void HMultiView::play(HMedia& media) {
HVideoWidget* player = getIdlePlayer();
player->open(media);
先看这里getIdlePlayer的实现,在当前文件往上找,能找到如下代码
HVideoWidget* HMultiView::getIdlePlayer() {
for (int i = 0; i < views.size(); ++i) {
HVideoWidget *player = (HVideoWidget*)views[i];
if (player->isVisible() && player->status == HVideoWidget::STOP) {
return player;
}
}
return NULL;
}
这里是根据数组中的可见状态和停止状态来获取可用的播放器对象
然后在头文件HMultiView.h中可以看到
public:
QVector<QWidget*> views;
再cpp中initUI中有如下
void HMultiView::initUI() {
for (int i = 0; i < MV_STYLE_MAXNUM; ++i) {
HVideoWidget* player = new HVideoWidget(this);
player->playerid = i+1;
views.push_back(player);
}
上面player用了HVideoWidget,继续找对应的
2.2 HVideoWidget open
上面2.1中除了初始化,还有一个open的槽
class HVideoWidget : public QFrame
public slots:
void open(HMedia& media);
private:
HMedia media;
直接在HVideoWidget.cpp中看open的实现
void HVideoWidget::open(HMedia& media) {
this->media = media;
start();
}
这里media还是跟之前一样,只是存储一下信息,接下来看start实现
2.3 HVideoWidget start
先看声明,还是私有槽
public slots:
void start();
再看start定义
```c++
void HVideoWidget::start() {
if (media.type == MEDIA_TYPE_NONE) {
QMessageBox::information(this, tr("Info"), tr("Please first set media source, then start."));
updateUI();
return;
}
if (!pImpl_player) {
pImpl_player = HVideoPlayerFactory::create(media.type);
pImpl_player->set_media(media);
pImpl_player->set_event_callback(hplayer_event_callback, this);
title = media.src.c_str();
int ret = pImpl_player->start();
if (ret != 0) {
onOpenFailed();
}
else {
onOpenSucceed();
}
updateUI();
}
else {
if (status == PAUSE) {
resume();
}
}
}
前面的判断可以先跳过,上一篇中是打开的本地文件,可以直接往后面看,pImpl_player用了工厂方法创建对象
先看pImpl_player的声明,从下面的代码看是使用了HVideoPlayer
private:
HVideoPlayer* pImpl_player;
2.4 HVideoPlayerFactory::create
再看工厂方法HVideoPlayerFactory::create 这个在video目录下 #include "HVideoPlayerFactory.h"
class HVideoPlayerFactory
{
public:
static HVideoPlayer* create(media_type_e type) {
switch (type) {
case MEDIA_TYPE_FILE:
case MEDIA_TYPE_NETWORK:
return new HFFPlayer;
case MEDIA_TYPE_CAPTURE:
// return new HVideoCapture;
return new HFFPlayer;
default:
return NULL;
}
}
};
这里静态成员函数有实现,会导致头文件臃肿。在c++17下面,如果在源代码实现,头文件的静态成员函数要 添加 inline 关键字,否则被多个文件包含头文件会导致 odr违规。
- ODR 是 One Definition Rule(单一定定义规则)的缩写,这是 C++ 的核心规则之一。
上面工厂方法就返回了HFFPlayer的实例对象
2.5 HFFPlayer
在头文件HFFPlayer.h中有如下代码
class HFFPlayer : public HVideoPlayer, public HThread {
public:
HFFPlayer();
~HFFPlayer();
这里用了多继承,合理使用多继承可以高效实现功能组合。
在 C++ 中,多继承(Multiple Inheritance) 指一个派生类(子类)同时从多个基类(父类)继承属性和方法。
可能有的问题
- (1) 菱形继承(Diamond Problem) 若两个基类(如 HVideoPlayer 和 HThread )有共同的基类,会导致派生类中存在重复的基类成员。 解决方案:使用 虚继承(Virtual Inheritance)
- (2) 成员名冲突 若两个基类有同名成员,需通过作用域运算符 :: 明确指定
- (3) 构造函数初始化顺序 基类的构造函数按声明顺序调用(从左到右)
构造器中的实现如下
HFFPlayer::HFFPlayer()
: HVideoPlayer()
, HThread() {
fmt_opts = NULL;
codec_opts = NULL;
fmt_ctx = NULL;
codec_ctx = NULL;
packet = NULL;
frame = NULL;
sws_ctx = NULL;
block_starttime = time(NULL);
block_timeout = DEFAULT_BLOCK_TIMEOUT;
quit = 0;
if (!s_ffmpeg_init.test_and_set()) {
// av_register_all();
// avcodec_register_all();
avformat_network_init();
avdevice_register_all();
list_devices();
}
}