一般视频控件上会给出个悬浮条,这个悬浮条用于显示分辨率或者一些用户期望看到的信息,一般常用的信息除了分辨率以外,还有帧率、封装格式、视频解码器名称、音频解码器名称、实时码率等,由于实际的场景不一样,用户希望能过自定义勾选开启哪些信息,开启的就显示,不开启的则可以不用显示,这样也方便节约空间甚至节约CPU占用,比如实时码率大部分时候是不需要的,而计算实时码率在采集数据的时候就需要不断运算累加,需要的时候开启不需要的时候不开启,这样也能避免不必要的计算。一般默认会开启显示分辨率,这个信息非常重要,其他的用户自己选择。
视频控件采用多重基类的设计方式,最开始是AbstractVideoWidget视频基类窗体,这个基类提供给camera采集类和video采集类集成使用,悬浮条在基类中的enterEvent和leaveEvent两个鼠标移入移除信号来控制显示和隐藏。一般都是这个策略,当然也可以改成获取焦点的就一直显示,没有焦点的就不显示。由于是在基类就显示,要显示的信息只能在子类中才能获取到,所以搞个虚拟的函数virtual QString getBannerText() const;专门用于获取悬浮条信息文本内容,子类中负责实现该函数,在获取的时候根据悬浮条信息结构体参数勾选了哪些就获取哪些,最后拼成字符串返回。
QString VideoWidget::getBannerText() const
{
if (!getIsRunning()) {
return QString();
}
//悬浮条如果宽度不够则不显示文字信息
int width = bannerWidget->width();
if (width < 200) {
return QString();
}
//线程已经开启并处于打开中/还未打开完成
if (!videoThread->getIsOk()) {
return QString("打开中...");
}
QStringList list;
if (bannerInfo.resolution) {
if (videoWidth > 0) {
list << QString("%1%2 x %3").arg(width > 240 ? "分辨率: " : "").arg(videoWidth).arg(videoHeight);
}
}
if (bannerInfo.frameRate) {
int fps = videoThread->getFrameRate();
if (fps > 0) {
list << QString("帧率: %1").arg(fps);
}
}
if (bannerInfo.formatName) {
QString name = VideoHelper::getFormatName(videoThread);
if (!name.isEmpty()) {
list << QString("格式: %1").arg(name);
}
}
if (bannerInfo.videoCodecName) {
QString name = videoThread->getVideoCodecName();
if (!name.isEmpty()) {
list << QString("视频: %1").arg(name);
}
}
if (bannerInfo.audioCodecName) {
QString name = videoThread->getAudioCodecName();
if (!name.isEmpty()) {
list << QString("音频: %1").arg(name);
}
}
if (bannerInfo.realBitRate) {
if (kbps > 0) {
list << QString("码率: %1kbps").arg((int)kbps);
}
}
if (bannerInfo.hardware) {
QString hardware = videoThread->getHardware();
if (hardware != "none") {
list << QString("硬解: %1").arg(hardware);
}
}
if (bannerInfo.videoMode) {
QString videoMode = "句柄";
if (widgetPara.videoMode == VideoMode_Opengl) {
videoMode = "GPU";
} else if (widgetPara.videoMode == VideoMode_Painter) {
videoMode = "绘制";
}
list << QString("模式: %1").arg(videoMode);
}
return list.join(" ");
}
QString VideoHelper::getFormatName(VideoThread *videoThread)
{
//文件封装格式可能是一个很长的字符串比如 mov,mp4,m4a,3gp,3g2,mj2
QString name = videoThread->getFormatName();
if (name.contains(",")) {
QString url = videoThread->getMediaUrl();
MediaType type = videoThread->getMediaType();
if (type == MediaType_FileLocal) {
name = url.split(".").last();
} else if (type == MediaType_FileWeb) {
name = url.split("://").first();
} else if (name.contains("v4l2")) {
name = "v4l2";
} else {
name = "file";
}
} else if (name.contains("-")) {
name = name.split("-").first();
name = name.trimmed();
}
return name;
}
void AbstractVideoWidget::enterEvent(QEventx *)
{
//这里可以自行增加判断(是否获取了焦点的或者是否处于预览阶段的才需要显示)
//if (this->hasFocus()) {}
if (isRunning && widgetPara.bannerEnable) {
this->setRealBitRate(bannerInfo.realBitRate);
bannerWidget->setVisible(true);
bannerWidget->showInfo(getBannerText());
}
}
void AbstractVideoWidget::leaveEvent(QEvent *)
{
//这里不用判断其他的反正永远隐藏就对了(防止中途改变过其中的变量导致无法隐藏)
//增加电子放大期间不隐藏/方便标记当前哪个通道处于电子放大期间
if (!bannerWidget->getIsCrop()) {
this->setRealBitRate(false);
bannerWidget->setVisible(false);
}
}