#include "Record.h"#include "Json.h"#include <QFile>#include <QDir>#include <QDateTime>#include <QProcess>#include <QJsonArray>#include <QJsonObject>#include <QRegularExpression>#include <QStorageInfo>#include <sys/statvfs.h>#include <cmath>Record::Record(QObject *parent) : QObject(parent){}void Record::init(){if(QFile::exists(RECPATH)){config = Json::loadFile(RECPATH).toMap();if(config.isEmpty() || !config.contains("format"))restConf();}elserestConf();config = Json::loadFile(RECPATH).toMap();QVariantMap formatMap = config["format"].toMap();for(int i=0;i<Config::chns.count();i++){Channel *chn = Config::chns[i];RecChn *recChn = new RecChn;recChn->chnId = chn->id;if(chn->data.contains("rdir"))recChn->chnName = chn->data["rdir"].toString();elserecChn->chnName = chn->type.toUpper()+QString::number(chn->id);recChn->startTime = -1;recChn->hadPause = false;recChn->pauseCount = 0;recChn->durTime = "--:--:--";recChn->curFileName = "------";recChn->pauseTimer = new QTimer(this);recChn->snapTimer = new QTimer(this);recChn->snapPath = "";recChn->snapCount = 0;for(int j=0;j<formatMap.keys().count();j++){LinkObject *mux = Link::create("Mux");QVariantMap dd;if(chn->encA==NULL || chn->encA->getState()!="started")dd["mute"]=true;elsechn->encA->linkA(mux);if(chn->encV != NULL)chn->encV->linkV(mux);mux->setData(dd);RecFormat *recFormat = new RecFormat{false,-1,0,mux};connect(mux, &LinkObject::newEvent, [=](const QString &type, const QVariant &msg){if(type == "newSegment"){recFormat->startNum = msg.toInt();if(config["type"].toString() == "loop"){QStringList pathlist = recChn->snapPath.split("/");recChn->snapPath = QString().sprintf(QString("/"+pathlist[1]+"/"+pathlist[2]+"/"+pathlist[3]+"/%03d_").toLatin1().data(),msg.toInt());}QMetaObject::invokeMethod(recChn->snapTimer, "start", Qt::QueuedConnection, Q_ARG(int, 300));}});recChn->recFormats[formatMap.keys()[j]] = recFormat;}connect(recChn->pauseTimer,&QTimer::timeout,[=](){recChn->pauseCount++;});connect(recChn->snapTimer,&QTimer::timeout,[=](){Channel *chn = Config::findChannelById(recChn->chnId);if(chn != NULL){QString jpg=recChn->snapPath+"preview.jpg";if(chn->snap->invoke("snapSync",jpg).toBool()){recChn->snapCount++;if(recChn->snapCount > 2){recChn->snapCount = 0;recChn->snapTimer->stop();}}}});recChns << recChn;}clearTimer = new QTimer(this);connect(clearTimer,SIGNAL(timeout()),this,SLOT(onClearRecFile()));if(config["auto"].toBool())this->start();}void Record::resetEnc(){for(int i=0;i<recChns.count();i++){Channel *chn = Config::findChannelById(recChns[i]->chnId);if(chn == NULL)return;for(int j=0;j<recChns[i]->recFormats.keys().count();j++){QString format = recChns[i]->recFormats.keys()[j];LinkObject *mux = recChns[i]->recFormats[format]->mux;QVariantMap dd;if(chn->encA==NULL || chn->encA->getState()!="started"){dd["mute"]=true;if(chn->encA !=NULL)chn->encA->unLinkA(mux);}else{dd["mute"]=false;chn->encA->linkA(mux);}if(chn->encV != NULL)chn->encV->linkV(mux);mux->setData(dd);}}}bool Record::start(){if(!isMountDisk())return false;QVariantList chnList = config["chns"].toList();QVariantMap formatMap = config["format"].toMap();QVariantMap fragmentMap = config["fragment"].toMap();QDateTime curTime = QDateTime::currentDateTime();QString curTimeStr = curTime.toString("yyyy-MM-dd_hhmmss");int maxIndex = getLoopRecIndex("max");for(int i=0;i<recChns.count();i++){RecChn *recChn = recChns[i];if(chnList.contains(recChn->chnId)){QString recPath = "";for(int j=0;j<formatMap.keys().count();j++){QString format = formatMap.keys()[j];RecFormat *recFormat = recChn->recFormats[format];if(formatMap[format].toBool()){QVariantMap dd;if(fragmentMap["enable"].toBool()){if(fragmentMap["mode"].toString() == "dura"){dd["segmentDuration"] = fragmentMap["dura"].toInt()*1000;dd["segmentSize"] = 0;}if(fragmentMap["mode"].toString() == "size"){dd["segmentDuration"] = 0;dd["segmentSize"] = fragmentMap["size"].toInt()*1024*1024;}}else{dd["segmentDuration"] = 0;dd["segmentSize"] = 0;}QString fileName,dirPath;if(config["type"].toString() == "normal"){dirPath = rootPath+"/"+curTimeStr+"/"+recChn->chnName;fileName = dirPath+"/"+curTimeStr;if(fragmentMap["enable"].toBool()){fileName += "_%d";dd["startNum"] = 1;recFormat->startNum = 1;}if(recPath.isEmpty())recPath = dirPath;}if(config["type"].toString() == "loop"){dirPath = rootPath+"/"+recChn->chnName;fileName = dirPath + "/" + QString("%1").arg(maxIndex+1, 3, 10, QChar('0')) + "_" + curTimeStr;if(fragmentMap["enable"].toBool()){fileName = dirPath+"/%03d_${yyyy-MM-dd_hhmmss}";dd["startNum"] = maxIndex+1;recFormat->startNum = maxIndex+1;}if(recPath.isEmpty())recPath = QString().sprintf(QString(dirPath+"/%03d_").toLatin1().data(),maxIndex+1);}QDir().mkpath(dirPath);if(recChn->curFileName.contains("---"))recChn->curFileName = fileName;dd["path"] = fileName+"."+format;if(format == "mp4")dd["filecache"]=20480000;if(!recFormat->hadRec){recFormat->mux->start(dd);recFormat->hadRec = true;recFormat->fileCount++;recChn->startTime = curTime.toTime_t();this->newEvent("record",true);}}else{recFormat->mux->stop();recFormat->hadRec = false;recFormat->startNum = -1;}}if(!recPath.isEmpty()){recChn->snapPath = recPath;if(config["type"].toString() == "normal")recChn->snapPath += "/";recChn->snapTimer->start(1000);}}}if(config["type"].toString() == "loop")clearTimer->start(1000*10);return true;}bool Record::execute(const QString &json){if(!isMountDisk())return false;QVariantList stateList = Json::decode(json).toList();QVariantMap formatMap = config["format"].toMap();QVariantMap fragmentMap = config["fragment"].toMap();QDateTime curTime = QDateTime::currentDateTime();QString curTimeStr = curTime.toString("yyyy-MM-dd_hhmmss");bool allChnStopRec = true;for(int i=0;i<stateList.count();i++){QVariantMap stateMap = stateList[i].toMap();RecChn *recChn = recChns[i];bool isrec = false;for(int j=0;j<formatMap.keys().count();j++){QString format = formatMap.keys()[j];if(stateMap.contains(format)){RecFormat *recFormat = recChn->recFormats[format];if(!recFormat->hadRec && stateMap[format].toBool()){QVariantMap dd;if(fragmentMap["enable"].toBool()){if(fragmentMap["mode"].toString() == "dura"){dd["segmentDuration"] = fragmentMap["dura"].toInt()*1000;dd["segmentSize"] = 0;}if(fragmentMap["mode"].toString() == "size"){dd["segmentDuration"] = 0;dd["segmentSize"] = fragmentMap["size"].toInt()*1024*1024;}}else{dd["segmentDuration"] = 0;dd["segmentSize"] = 0;}QString fileName,dirPath;if(!recChn->curFileName.contains("---")){fileName = recChn->curFileName;dirPath = QFileInfo(fileName).absolutePath();if (config["type"].toString() == "normal" && fragmentMap["enable"].toBool())dd["startNum"] = 1;if (config["type"].toString() == "loop" && fragmentMap["enable"].toBool())dd["startNum"] = getLoopRecIndex("max");if(recFormat->fileCount == 0)dd["path"] = recChn->curFileName+"."+format;elsedd["path"] = recChn->curFileName+"_"+QString::number(recFormat->fileCount)+"."+format;}else{if(config["type"].toString() == "normal"){dirPath = rootPath+"/"+curTimeStr+"/"+recChn->chnName;fileName = dirPath+"/"+curTimeStr;if(fragmentMap["enable"].toBool()){fileName += "_%d";dd["startNum"] = 1;recFormat->startNum = 1;}recChn->snapPath = dirPath+"/";}if(config["type"].toString() == "loop"){int maxIndex = getLoopRecIndex("max");dirPath = rootPath+"/"+recChn->chnName;fileName = QString().sprintf(QString(dirPath+"/%03d_"+curTimeStr).toLatin1().data(),maxIndex+1);if(fragmentMap["enable"].toBool()){fileName = dirPath+"/%03d_"+curTimeStr;dd["startNum"] = maxIndex+1;recFormat->startNum = maxIndex+1;}recChn->snapPath = QString().sprintf(QString(dirPath+"/%03d_").toLatin1().data(),maxIndex+1);}dd["path"] = fileName+"."+format;if(recChn->curFileName.contains("---"))recChn->curFileName = fileName;QDir().mkpath(dirPath);}recChn->snapTimer->start(300);if(format == "mp4")dd["filecache"]=20480000;if(!recFormat->hadRec){recFormat->mux->start(dd);recFormat->hadRec = true;recFormat->fileCount++;if(recChn->startTime == -1)recChn->startTime = curTime.toTime_t();this->newEvent("record",true);}}if(recFormat->hadRec && !stateMap[format].toBool()){recFormat->mux->stop();recFormat->hadRec = false;}if(!isrec && recFormat->hadRec)isrec = true;}}recChn->hadPause = stateMap["pause"].toBool();recChn->hadPause ? recChn->pauseTimer->start(1000) : recChn->pauseTimer->stop();foreach (QString format, recChn->recFormats.keys())recChn->recFormats[format]->mux->invoke(recChn->hadPause ? "pause" : "resume");if(!isrec){for (QVariantMap::const_iterator it = formatMap.constBegin(); it != formatMap.constEnd(); it++){recChn->recFormats[it.key()]->mux->stop();recChn->recFormats[it.key()]->hadRec = false;recChn->recFormats[it.key()]->fileCount = 0;recChn->recFormats[it.key()]->startNum = -1;}recChn->startTime = -1;recChn->curFileName = "------";recChn->pauseTimer->stop();recChn->pauseCount = 0;recChn->snapTimer->stop();recChn->snapPath.clear();recChn->snapCount = 0;}else{allChnStopRec = false;if(config["type"] == "loop")clearTimer->start(1000*30);}}if(allChnStopRec)stop();return true;}bool Record::stop(){QVariantMap formatMap = config["format"].toMap();for(int i=0;i<recChns.count();i++){RecChn *recChn = recChns[i];for (QVariantMap::const_iterator it = formatMap.constBegin(); it != formatMap.constEnd(); it++){recChn->recFormats[it.key()]->mux->stop();recChn->recFormats[it.key()]->hadRec = false;recChn->recFormats[it.key()]->fileCount = 0;recChn->recFormats[it.key()]->startNum = -1;}recChn->startTime = -1;recChn->curFileName = "------";recChn->pauseTimer->stop();recChn->pauseCount = 0;recChn->snapTimer->stop();recChn->snapPath.clear();recChn->snapCount = 0;}writeCom("sync");clearTimer->stop();this->newEvent("record",false);return true;}bool Record::isRecordState(){QVariantMap formatMap = config["format"].toMap();for(int i=0;i<recChns.count();i++){RecChn *recChn = recChns[i];for (QVariantMap::const_iterator it = formatMap.constBegin(); it != formatMap.constEnd(); it++){if(recChn->recFormats[it.key()]->hadRec)return true;}}return false;}bool Record::update(QString json){config = Json::decode(json).toMap();Json::saveFile(config,RECPATH);return true;}QString Record::getDurTime(){QVariantMap retMap;for(int i=0;i<recChns.count();i++){RecChn *recChn = recChns[i];retMap["chn"+QString::number(recChn->chnId)] = "--:--:--";if(recChn->startTime != -1){int pauseTime = recChn->pauseCount;int time_t = QDateTime::currentDateTime().toTime_t();int diff = time_t - recChn->startTime - pauseTime;int h = diff/3600;int m = (diff%3600)/60;int s = (diff%3600)%60;QString hh = QString::number(h);QString mm = QString::number(m);QString ss = QString::number(s);if(hh.length() < 2)hh = "0"+hh;if(mm.length() < 2)mm = "0"+mm;if(ss.length() < 2)ss = "0"+ss;QString durTime = "hh:mm:ss";durTime = durTime.replace("hh",hh);durTime = durTime.replace("mm",mm);durTime = durTime.replace("ss",ss);retMap["chn"+QString::number(recChn->chnId)] = durTime;}}return Json::encode(retMap);}QVariantMap Record::getState(){if(!isMountDisk())return QVariantMap();QVariantMap obj;struct statvfs stat;if(statvfs(rootPath.toUtf8().constData(), &stat) != 0)return obj;quint64 blockSize = stat.f_frsize ? stat.f_frsize : stat.f_bsize;quint64 total = (quint64)stat.f_blocks * blockSize;quint64 free = (quint64)stat.f_bfree * blockSize;quint64 used = (total >= free) ? (total - free) : 0;double percent = 0.0;if (total > 0) {percent = (double)used / (double)total * 100.0;if (percent > 100.0)percent = 100.0;percent = floor(percent * 100.0 + 0.5) / 100.0;}const char units[] = {'T','G','M','K','B'};const quint64 sizes[] = {1024ull*1024*1024*1024,1024ull*1024*1024,1024ull*1024,1024,1};auto formatAuto = [&](quint64 bytes) -> QString {for(int i=0;i<5;i++){if(bytes >= sizes[i])return QString::number(bytes / (double)sizes[i], 'f', 1) + units[i];}return QString::number(bytes) + "B";};obj["total"] = formatAuto(total);obj["used"] = formatAuto(used);obj["free"] = formatAuto(free);obj["percent"] = percent;return obj;}bool Record::isMountDisk(){if(rootPath.endsWith('/') && rootPath.length() > 1)rootPath.chop(1);QByteArray t = rootPath.toUtf8();QFile file("/proc/mounts");if(!file.open(QIODevice::ReadOnly))return false;while (true){QByteArray line = file.readLine();if (line.isEmpty())break;QList<QByteArray> parts = line.split(' ');if (parts.size() < 2)continue;QByteArray dev = parts[0];QByteArray mount = parts[1];if (mount.endsWith('/') && mount.size() > 1)mount.chop(1);if (t == dev || t == mount)return true;}return false;}QVariantList Record::getRecChnsState(){QVariantList retList;QVariantMap durTimeMap = Json::decode(getDurTime()).toMap();QVariantMap formatMap = config["format"].toMap();for(int i=0;i<recChns.count();i++){QVariantMap recChnMap;RecChn *recChn = recChns[i];recChnMap["id"] = recChn->chnId;recChnMap["name"] = recChn->chnName;recChnMap["pause"] = recChn->hadPause;recChnMap["durTime"] = durTimeMap["chn"+QString::number(recChn->chnId)];recChnMap["curFileName"] = "------";if(!recChn->curFileName.contains("---")){int startNum = 0;for (QVariantMap::const_iterator it = formatMap.constBegin(); it != formatMap.constEnd(); it++){if(recChn->recFormats[it.key()]->startNum > startNum)startNum = recChn->recFormats[it.key()]->startNum;}if(config["type"].toString() == "normal")recChnMap["curFileName"] = QString().sprintf(QFileInfo(recChn->curFileName).fileName().toLatin1().data(),startNum);if(config["type"].toString() == "loop"){QVariantMap fragmentMap = config["fragment"].toMap();if(fragmentMap["enable"].toBool())recChnMap["curFileName"] = QString::number(startNum);elserecChnMap["curFileName"] = QString().sprintf(QFileInfo(recChn->curFileName).fileName().toLatin1().data(),startNum);}}for (QVariantMap::const_iterator it = formatMap.constBegin(); it != formatMap.constEnd(); it++)recChnMap[it.key()] = recChn->recFormats[it.key()]->hadRec;retList << recChnMap;}return retList;}void Record::onClearRecFile(){if(config["type"].toString() != "loop")return;int limitMb = config["limit"].toInt();QString output = writeCom("df -m "+rootPath);QStringList lines = output.split('\n');if (lines.size() > 1){QStringList columns = lines[1].split(QRegExp("\\s+"));if (columns.size() >= 4){int freeMb = columns[3].toInt();if(freeMb < limitMb){QString delWith = QString("%1").arg(getLoopRecIndex("min"), 3, 10, QChar('0'))+"_";if(delWith == QString::number(INT_MAX)+"_")return;for(int i=0;i<Config::chns.count();i++){QString rdir = Config::chns[i]->data["rdir"].toString();QDir dir(rootPath+"/"+rdir);if(!dir.exists())continue;writeCom("rm -rf "+rootPath+"/"+rdir+"/"+delWith+"*");}}}}}int Record::getLoopRecIndex(const QString &type){int number = 0;if(type == "min")number = INT_MAX;QRegularExpression re(R"(^(\d{3,5})_\d{4}-\d{2}-\d{2}_\d{6}(?:_\d+)?\.(ts|mp4|flv|mkv|mov)$)");for(int i=0;i<Config::chns.count();i++){QString rdir = Config::chns[i]->data["rdir"].toString();QDir dir(rootPath+"/"+rdir);if(!dir.exists())continue;QStringList files = dir.entryList(QDir::Files);for (const QString &file : files){QRegularExpressionMatch match = re.match(file);if (match.hasMatch()){int nm = match.captured(1).toInt();if (type == "max" && nm > number)number = nm;if(type == "min" && nm < number)number = nm;}}}return number;}void Record::restConf(){QVariantMap rootMap;rootMap["chns"] = QVariantList();rootMap["type"] = "normal";rootMap["auto"] = false;rootMap["limit"] = 500;QVariantMap formatMap;formatMap["mp4"] = false;formatMap["flv"] = false;formatMap["mkv"] = false;formatMap["mov"] = false;formatMap["ts"] = false;rootMap["format"] = formatMap;QVariantMap fragmentMap;fragmentMap["enable"] = false;fragmentMap["mode"] = "dura"; //sizefragmentMap["dura"] = 3600;fragmentMap["size"] = 500;rootMap["fragment"] = fragmentMap;Json::saveFile(rootMap,RECPATH);}QString Record::writeCom(const QString &com){QProcess proc;QStringList argList;argList << "-c" << com;proc.start("/bin/sh",argList);// 等待进程启动proc.waitForFinished();proc.waitForReadyRead();// 读取进程输出到控制台的数据QByteArray procOutput = proc.readAll();proc.close();return QString(procOutput);}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。