这个解码线程基类的设计,是到目前为止个人觉得自己设计的最好的基类之一,当然也不是一开始就知道这样设计,没有个三五年的摸爬滚打以及社会的毒打,是想不到要这样设计的,一方面是要不断提炼各种视频类视频组件的共性作为局部变量,比如通用的参数有视频画面宽度videoWidth、视频画面高度videoHeight、视频画面帧率frameRate、视频旋转角度rotate、音频采样率sampleRate、音频通道数channelCount等。这些共性参数都是在疯狂实战的过程中提炼的,久而久之就出来了。
翻阅Qt源码本身,他里面也基本上都是这种设计思路,有个巨大的好处可以复用这些代码,子类只要继承了这个类,就能直接使用,不需要还在子类中写这些参数变量,函数接口只需要重载实现即可,重载实现了的就调用子类的实现,没有重载的就调用基类的实现,这也是为何c++如此流行的一个重要原因,封装、继承、多态这三大特性成就了c++。
基类的设计优点优势巨大,也不是没有缺点的,缺点就是有部分共性是大部分子类都有的,但是部分没有,或者部分子类没有去实现重载,所以使用的时候万一实例化的子类没有去实现对应接口,就算你调用了,可能没效果,因为默认是基类的,所以有的时候就会很纳闷为何明明调用了函数,但是没有效果,仔细跟进一查原来子类并没有去实现接口,可能该子类是本来就不需要这个接口。
void AbstractVideoThread::debug(const QString &head, const QString &msg, const QString &url)
{if (debugInfo == 0) {return;}//如果设置了唯一标识则放在打印前面QString text = head;if (!flag.isEmpty()) {text = QString("标识[%1] %2").arg(flag).arg(text);}QString addr = url;if (debugInfo == 2) {//为空的时候获取一次即可if (ip.isEmpty()) {ip = UrlHelper::getUrlIP(url);}addr = ip;}if (msg.isEmpty()) {qDebug() << TIMEMS << QString("%1 -> 地址: %2").arg(text).arg(addr);} else {qDebug() << TIMEMS << QString("%1 -> %2 地址: %3").arg(text).arg(msg).arg(addr);}
}void AbstractVideoThread::setImage(const QImage &image)
{lastTime = QDateTime::currentDateTime();emit receiveImage(image, 0);
}void AbstractVideoThread::setRgb(int width, int height, quint8 *dataRGB, int type)
{lastTime = QDateTime::currentDateTime();emit receiveFrame(width, height, dataRGB, type);
}void AbstractVideoThread::setYuv(int width, int height, quint8 *dataY, quint8 *dataU, quint8 *dataV)
{lastTime = QDateTime::currentDateTime();emit receiveFrame(width, height, dataY, dataU, dataV, width, width / 2, width / 2);
}void AbstractVideoThread::play()
{//没有运行才需要启动if (!this->isRunning()) {stopped = false;isPause = false;isSnap = false;this->start();}
}void AbstractVideoThread::stop()
{//处于运行状态才可以停止if (this->isRunning()) {stopped = true;isPause = false;isSnap = false;this->wait();}
}void AbstractVideoThread::pause()
{if (this->isRunning()) {isPause = true;}
}void AbstractVideoThread::next()
{if (this->isRunning()) {isPause = false;}
}void AbstractVideoThread::snap(const QString &snapName)
{if (this->isRunning()) {isSnap = true;this->setSnapName(snapName);}
}void AbstractVideoThread::snapFinsh(const QImage &image)
{//如果填了截图文件名称则先保存图片if (!snapName.isEmpty() && !image.isNull()) {//取出拓展名根据拓展名保存格式QString suffix = snapName.split(".").last();image.save(snapName, suffix.toLatin1().constData());}//发送截图完成信号emit snapImage(image, snapName);
}void AbstractVideoThread::recordStart(const QString &fileName)
{
#ifdef videosavethis->setFileName(fileName);if (saveAudioType > 0) {//处于暂停阶段则切换暂停标志位(暂停后再次恢复说明又重新开始录制)if (saveAudio->getIsPause()) {saveAudio->pause();emit recorderStateChanged(RecorderState_Recording, saveAudio->getFileName());} else {saveAudio->setPara(saveAudioType, sampleRate, channelCount, profile);saveAudio->open(fileName);if (saveAudio->getIsOk()) {emit recorderStateChanged(RecorderState_Recording, saveAudio->getFileName());}}}if (saveVideoType == SaveVideoType_Yuv && !onlyAudio) {//处于暂停阶段则切换暂停标志位(暂停后再次恢复说明又重新开始录制)if (saveVideo->getIsPause()) {isRecord = true;saveVideo->pause();emit recorderStateChanged(RecorderState_Recording, saveVideo->getFileName());} else {saveVideo->setPara(saveVideoType, videoWidth, videoHeight, frameRate);saveVideo->open(fileName);if (saveVideo->getIsOk()) {isRecord = true;emit recorderStateChanged(RecorderState_Recording, saveVideo->getFileName());}}}
#endif
}void AbstractVideoThread::recordPause()
{
#ifdef videosaveif (saveAudioType > 0) {if (saveAudio->getIsOk()) {saveAudio->pause();emit recorderStateChanged(RecorderState_Paused, saveAudio->getFileName());}}if (saveVideoType == SaveVideoType_Yuv && !onlyAudio) {if (saveVideo->getIsOk()) {isRecord = false;saveVideo->pause();emit recorderStateChanged(RecorderState_Paused, saveVideo->getFileName());}}
#endif
}void AbstractVideoThread::recordStop()
{
#ifdef videosaveif (saveAudioType > 0) {if (saveAudio->getIsOk()) {saveAudio->stop();emit recorderStateChanged(RecorderState_Stopped, saveAudio->getFileName());}}if (saveVideoType == SaveVideoType_Yuv && !onlyAudio) {if (saveVideo->getIsOk()) {isRecord = false;saveVideo->stop();emit recorderStateChanged(RecorderState_Stopped, saveVideo->getFileName());}}
#endif
}void AbstractVideoThread::writeVideoData(int width, int height, quint8 *dataY, quint8 *dataU, quint8 *dataV)
{
#ifdef videosaveif (saveVideoType == SaveVideoType_Yuv && isRecord) {saveVideo->setPara(SaveVideoType_Yuv, width, height, frameRate);saveVideo->write(dataY, dataU, dataV);}
#endif
}void AbstractVideoThread::writeAudioData(const char *data, qint64 len)
{
#ifdef videosaveif (saveAudioType > 0 && saveAudio->getIsOk()) {saveAudio->write(data, len);}
#endif
}void AbstractVideoThread::writeAudioData(const QByteArray &data)
{
#ifdef videosaveif (saveAudioType > 0 && saveAudio->getIsOk()) {this->writeAudioData(data.constData(), data.length());}
#endif
}void AbstractVideoThread::setOsdInfo(const QList &listOsd)
{this->listOsd = listOsd;
}void AbstractVideoThread::setGraphInfo(const QList &listGraph)
{this->listGraph = listGraph;
}