RecordControlApplication/Channel.cpp

279 lines
7.2 KiB
C++
Raw Normal View History

2024-01-18 15:41:43 +08:00
#include "Channel.h"
2024-03-04 16:22:40 +08:00
#include "Constant.h"
#include "Log.h"
#include "Tool.h"
#include <QCoreApplication>
2024-03-04 16:22:40 +08:00
#include <QFileInfo>
2024-01-18 15:41:43 +08:00
#include <QProcess>
#include <QTime>
#include <chrono>
2024-01-18 15:41:43 +08:00
LinkObject* Channel::audioInput = nullptr;
LinkObject* Channel::audioOutput = nullptr;
LinkObject* Channel::rtspServer = nullptr;
QString Channel::curRecordFilename = "";
2024-01-18 15:41:43 +08:00
extern LinkObject* vo;
extern LinkObject* vo1;
Channel::Channel(QObject* parent)
: QObject(parent)
{
videoInput = nullptr;
videoOutput = nullptr;
2024-01-19 09:04:21 +08:00
videoEncoder = nullptr;
2024-01-18 15:41:43 +08:00
audioEncoder = nullptr;
record = nullptr;
rtsp = nullptr;
2024-03-04 16:22:40 +08:00
file = nullptr;
videoDecoder = nullptr;
audioDecoder = nullptr;
image = Link::create("InputImage");
2024-01-18 15:41:43 +08:00
if (audioInput == nullptr) {
audioInput = Link::create("InputAlsa");
QVariantMap dataIn;
dataIn["path"] = "hw:0,0";
dataIn["channels"] = 2;
2024-01-18 15:41:43 +08:00
audioInput->start(dataIn);
}
if (audioOutput == nullptr) {
audioOutput = Link::create("OutputAlsa");
QVariantMap dataOut;
dataOut["path"] = "hw:0,0";
audioOutput->start(dataOut);
}
if (rtspServer == nullptr) {
rtspServer = Link::create("Rtsp");
rtspServer->start();
}
}
/**
2024-03-04 16:22:40 +08:00
* @brief
2024-01-18 15:41:43 +08:00
*/
void Channel::init()
{
if (channelName.isEmpty()) {
2024-03-04 16:22:40 +08:00
Log::error("channel name is empty!");
2024-01-18 15:41:43 +08:00
return;
}
2024-03-04 16:22:40 +08:00
if (channelName == Constant::MainChannel) {
2024-01-18 15:41:43 +08:00
videoOutput = vo;
} else {
videoOutput = vo1;
}
2024-03-04 16:22:40 +08:00
// 视频输入
2024-01-18 15:41:43 +08:00
videoInput = Link::create("InputVi");
QVariantMap dataVi;
dataVi["interface"] = channelName;
2024-03-04 16:22:40 +08:00
dataVi["width"] = 1920;
dataVi["height"] = 1080;
2024-01-18 15:41:43 +08:00
videoInput->start(dataVi);
videoInput->linkV(videoOutput);
2024-01-18 15:41:43 +08:00
2024-03-04 16:22:40 +08:00
// 视频编码
2024-01-18 15:41:43 +08:00
videoEncoder = Link::create("EncodeV");
videoEncoder->start(videoEncoderParams);
2024-03-04 16:22:40 +08:00
// 音频编码
2024-01-18 15:41:43 +08:00
audioEncoder = Link::create("EncodeA");
audioEncoder->start(audioEncoderParams);
2024-03-04 16:22:40 +08:00
// 录制
2024-01-18 15:41:43 +08:00
record = Link::create("Mux");
QVariantMap dataMp4;
dataMp4["format"] = "mp4";
dataMp4["segmentDuration"] = duration;
dataMp4["lowLatency"] = true;
// dataMp4["filecache"] = 20480000;
2024-01-18 15:41:43 +08:00
record->setData(dataMp4);
videoInput->linkV(videoEncoder)->linkV(record);
audioInput->linkA(audioEncoder)->linkA(record);
connect(record, &LinkObject::newEvent, [=](QString type, QVariant data) {
if (type == "newSegment") {
int id = data.toInt();
curRecordFilename = QString("%1_%2.mp4")
.arg(curRecordFilename.split("_")[0])
.arg(id, 2, 10, QLatin1Char('0'));
}
});
2024-03-04 16:22:40 +08:00
// rstp流
2024-01-18 15:41:43 +08:00
rtsp = Link::create("Mux");
QVariantMap dataRtsp;
dataRtsp["path"] = QString("mem://%1").arg(pushCode);
dataRtsp["format"] = "rtsp";
rtsp->start(dataRtsp);
videoInput->linkV(videoEncoder)->linkV(rtsp)->linkV(rtspServer);
audioInput->linkA(audioEncoder)->linkA(rtsp)->linkA(rtspServer);
2024-03-04 16:22:40 +08:00
// 播放文件
file = Link::create("InputFile");
connect(file, &LinkObject::newEvent, [=](QString type, QVariant msg) {
if (type == "EOF") {
Log::info("{} one video playback end", channelName.toStdString());
emit playEnd();
}
});
// 音频解码只在HDMI-OUT0输出音频
audioDecoder = Link::create("DecodeA");
audioDecoder->start();
if (channelName == Constant::MainChannel) {
file->linkA(audioDecoder)->linkA(audioOutput);
} else {
file->linkA(audioDecoder);
}
// 视频解码
videoDecoder = Link::create("DecodeV");
videoDecoder->start();
file->linkV(videoDecoder)->linkV(videoOutput);
2024-01-18 15:41:43 +08:00
}
/**
2024-03-04 16:22:40 +08:00
* @brief
2024-01-18 15:41:43 +08:00
*/
void Channel::startRecord()
{
// 阻塞到整分钟才开始录制,方便上位机进行回放
while (int secs = QTime::currentTime().second() % 60 != 0) {
QCoreApplication::processEvents();
}
QString curTime = QDateTime::currentDateTime().toString("yyyyMMddhhmm");
curRecordFilename = curTime + "_00.mp4";
2024-01-18 15:41:43 +08:00
QVariantMap dataRecord;
QString path = QString("%1/%2/%3.mp4").arg(Constant::VideoPath).arg(channelName).arg(curTime + "_%02d");
2024-03-04 16:22:40 +08:00
dataRecord["path"] = path;
record->start(dataRecord);
isRecord = true;
Log::info("{} start recording...", channelName.toStdString());
emit showRecordState(true);
2024-01-18 15:41:43 +08:00
}
/**
2024-03-04 16:22:40 +08:00
* @brief
2024-01-18 15:41:43 +08:00
*/
void Channel::stopRecord()
{
2024-03-04 16:22:40 +08:00
Log::info("{} stop recording...", channelName.toStdString());
2024-01-18 15:41:43 +08:00
record->stop(true);
2024-03-04 16:22:40 +08:00
emit showRecordState(false);
2024-01-18 15:41:43 +08:00
}
/**
2024-03-04 16:22:40 +08:00
* @brief
* @param path
* @return /
2024-01-18 15:41:43 +08:00
*/
2024-03-04 16:22:40 +08:00
bool Channel::startPlayback(QString path)
2024-01-18 15:41:43 +08:00
{
2024-03-04 16:22:40 +08:00
QFileInfo info(path);
if (!info.exists()) {
Log::error("cannot open video {} , video file does not exist", path.toStdString());
videoInput->unLinkV(videoOutput);
QVariantMap dataImage;
dataImage["path"] = Constant::EmptyImagePath;
image->setData(dataImage);
image->start(dataImage);
image->linkV(videoOutput);
state = Error;
return false;
}
2024-01-18 15:41:43 +08:00
2024-03-04 16:22:40 +08:00
// 开始回放
2024-01-18 15:41:43 +08:00
QVariantMap dataFile;
dataFile["path"] = path;
dataFile["async"] = false;
2024-01-19 09:04:21 +08:00
file->start(dataFile);
2024-01-18 15:41:43 +08:00
2024-03-04 16:22:40 +08:00
// 判断视频是否损坏,如果损坏则输出提示图片
int duration = file->invoke("getDuration", path).toInt() / 1000;
if (duration == 0) {
Log::error("cannot open video {}, video file was corrupted", path.toStdString());
file->stop();
videoInput->unLinkV(videoOutput);
QVariantMap dataImage;
dataImage["path"] = Constant::ErrorImagePath;
image->setData(dataImage);
image->start(dataImage);
image->linkV(videoOutput);
state = Error;
return false;
}
2024-01-18 15:41:43 +08:00
2024-03-04 16:22:40 +08:00
videoInput->unLinkV(videoOutput);
videoDecoder->linkV(videoOutput);
playbackDuration = duration;
state = Playback;
return true;
}
2024-01-19 09:04:21 +08:00
/**
2024-03-04 16:22:40 +08:00
* @brief
2024-01-19 09:04:21 +08:00
*/
void Channel::startPlayLive()
{
2024-03-04 16:22:40 +08:00
if (state == Playback) {
videoDecoder->unLinkV(videoOutput);
file->stop(true);
} else if (state == Error) {
image->unLinkV(videoOutput);
image->stop(true);
}
2024-01-19 09:04:21 +08:00
videoInput->linkV(videoOutput);
2024-03-04 16:22:40 +08:00
state = Stop;
2024-01-19 09:04:21 +08:00
}
2024-01-18 15:41:43 +08:00
/**
2024-03-04 16:22:40 +08:00
* @brief 退10s
2024-01-18 15:41:43 +08:00
*/
void Channel::back()
{
2024-03-04 16:22:40 +08:00
Log::info("{} back 10s", channelName.toStdString());
2024-01-18 15:41:43 +08:00
int curPos = file->invoke("getPosition").toInt();
curPos -= 10 * 1000;
2024-01-18 15:41:43 +08:00
file->invoke("seek", curPos);
}
/**
2024-03-04 16:22:40 +08:00
* @brief 10s
2024-01-18 15:41:43 +08:00
*/
void Channel::forward()
{
2024-03-04 16:22:40 +08:00
Log::info("{} forward 10s", channelName.toStdString());
2024-01-18 15:41:43 +08:00
int curPos = file->invoke("getPosition").toInt();
curPos += 10 * 1000;
2024-01-18 15:41:43 +08:00
file->invoke("seek", curPos);
}
/**
2024-03-04 16:22:40 +08:00
* @brief
2024-01-18 15:41:43 +08:00
*/
void Channel::togglePause()
{
2024-03-04 16:22:40 +08:00
if (state == Stop || state == Error)
return;
if (state == Playback)
state = Pause;
else
state = Playback;
file->invoke("pause", state == Pause);
2024-01-18 15:41:43 +08:00
}
/**
* @brief
2024-01-18 15:41:43 +08:00
*/
void Channel::showFinishPromot()
2024-01-18 15:41:43 +08:00
{
videoInput->unLinkV(videoDecoder);
QVariantMap dataImage;
dataImage["path"] = Constant::FinishImagePath;
image->setData(dataImage);
image->start(dataImage);
image->linkV(videoOutput);
state = Finish;
}