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 <QFileInfo>
|
2024-01-18 15:41:43 +08:00
|
|
|
|
#include <QProcess>
|
|
|
|
|
#include <QTime>
|
2024-05-07 15:06:36 +08:00
|
|
|
|
#include <chrono>
|
2024-01-18 15:41:43 +08:00
|
|
|
|
|
|
|
|
|
LinkObject* Channel::audioInput = nullptr;
|
|
|
|
|
LinkObject* Channel::audioOutput = nullptr;
|
|
|
|
|
LinkObject* Channel::rtspServer = nullptr;
|
|
|
|
|
|
|
|
|
|
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";
|
2024-01-25 09:57:08 +08:00
|
|
|
|
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);
|
2024-03-05 13:47:32 +08:00
|
|
|
|
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";
|
2024-05-07 15:06:36 +08:00
|
|
|
|
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);
|
|
|
|
|
|
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()
|
|
|
|
|
{
|
2024-03-05 13:47:32 +08:00
|
|
|
|
while (int secs = QTime::currentTime().second() % 60 != 0) {
|
|
|
|
|
}
|
|
|
|
|
QString curTime = QDateTime::currentDateTime().toString("yyyyMMddhhmm");
|
2024-01-18 15:41:43 +08:00
|
|
|
|
QVariantMap dataRecord;
|
2024-05-07 15:06:36 +08:00
|
|
|
|
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;
|
2024-01-25 09:57:08 +08:00
|
|
|
|
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-25 09:57:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
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();
|
2024-01-25 09:57:08 +08:00
|
|
|
|
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();
|
2024-01-25 09:57:08 +08:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2024-05-07 15:06:36 +08:00
|
|
|
|
* @brief 显示播放结束提示
|
2024-01-18 15:41:43 +08:00
|
|
|
|
*/
|
2024-05-07 15:06:36 +08:00
|
|
|
|
void Channel::showFinishPromot()
|
2024-01-18 15:41:43 +08:00
|
|
|
|
{
|
2024-05-07 15:06:36 +08:00
|
|
|
|
videoInput->unLinkV(videoDecoder);
|
|
|
|
|
QVariantMap dataImage;
|
|
|
|
|
dataImage["path"] = Constant::FinishImagePath;
|
|
|
|
|
image->setData(dataImage);
|
|
|
|
|
image->start(dataImage);
|
|
|
|
|
image->linkV(videoOutput);
|
|
|
|
|
state = Finish;
|
|
|
|
|
}
|