278 lines
6.6 KiB
C++
278 lines
6.6 KiB
C++
|
#include "BoxController.h"
|
||
|
#include <QProcess>
|
||
|
#include <QThread>
|
||
|
#include <QTime>
|
||
|
|
||
|
const char* path = "/root/usb";
|
||
|
|
||
|
BoxController::BoxController(QObject* parent)
|
||
|
: QObject(parent)
|
||
|
{
|
||
|
// init output in constructor;
|
||
|
videoOutput = Link::create("OutputVo");
|
||
|
QVariantMap dataVo;
|
||
|
dataVo["type"] = "hdmi";
|
||
|
dataVo["interface"] = "HDMI-OUT0";
|
||
|
videoOutput->setData(dataVo);
|
||
|
videoOutput->start();
|
||
|
|
||
|
// init video duration
|
||
|
videoDuration = 1 * 60 * 1000;
|
||
|
recordTimer = new QTimer();
|
||
|
recordTimer->setInterval(videoDuration);
|
||
|
recordTimer->stop();
|
||
|
connect(recordTimer, SIGNAL(timeout()), this, SLOT(onTimeout()));
|
||
|
|
||
|
// init record params
|
||
|
videoEncodeParams["codec"] = "h264";
|
||
|
videoEncodeParams["width"] = 1920;
|
||
|
videoEncodeParams["height"] = 1080;
|
||
|
videoEncodeParams["bitrate"] = 4000;
|
||
|
videoEncodeParams["framerate"] = 30;
|
||
|
|
||
|
audioEncodeParams["codec"] = "aac";
|
||
|
audioEncodeParams["samplerate"] = 48000;
|
||
|
audioEncodeParams["bitrate"] = 128000;
|
||
|
audioEncodeParams["channels"] = 1;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief initialize "Link" components
|
||
|
*/
|
||
|
void BoxController::init()
|
||
|
{
|
||
|
// audio input by external microphone
|
||
|
audioInput = Link::create("InputAlsa");
|
||
|
QVariantMap dataAi;
|
||
|
dataAi["path"] = "hw:0,0";
|
||
|
dataAi["channels"] = 2;
|
||
|
audioInput->start(dataAi);
|
||
|
|
||
|
// audio output by external speaker
|
||
|
audioOutput = Link::create("OutputAlsa");
|
||
|
QVariantMap dataAo;
|
||
|
dataAo["path"] = "hw:0,0";
|
||
|
audioOutput->start(dataAo);
|
||
|
|
||
|
videoInputA = Link::create("InputVi");
|
||
|
QVariantMap dataVi;
|
||
|
dataVi["interface"] = "HDMI-A";
|
||
|
videoInputA->start(dataVi);
|
||
|
|
||
|
// capture picture from video
|
||
|
snap = Link::create("EncodeV");
|
||
|
QVariantMap dataSnap;
|
||
|
dataSnap["codec"] = "jpeg";
|
||
|
dataSnap["snap"] = true;
|
||
|
dataSnap["width"] = videoEncodeParams.value("width");
|
||
|
dataSnap["height"] = videoEncodeParams.value("height");
|
||
|
snap->start(dataSnap);
|
||
|
videoInputA->linkV(snap);
|
||
|
// sleep 1s, if didnt sleep , function snap would return flase and capture failed
|
||
|
QThread::sleep(1);
|
||
|
|
||
|
videoInputA->linkV(videoOutput);
|
||
|
|
||
|
// video encode
|
||
|
videoEncoder = Link::create("EncodeV");
|
||
|
videoEncoder->start(videoEncodeParams);
|
||
|
|
||
|
// audio encode
|
||
|
audioEncoder = Link::create("EncodeA");
|
||
|
audioEncoder->start(audioEncodeParams);
|
||
|
|
||
|
// record
|
||
|
record = Link::create("Mux");
|
||
|
QVariantMap dataMp4;
|
||
|
dataMp4["format"] = "mp4";
|
||
|
dataMp4["mute"] = true;
|
||
|
record->setData(dataMp4);
|
||
|
videoInputA->linkV(videoEncoder)->linkV(record);
|
||
|
audioInput->linkA(audioEncoder)->linkA(record);
|
||
|
|
||
|
// rtmp server
|
||
|
rtmpServer = Link::create("Mux");
|
||
|
QVariantMap dataRtmp;
|
||
|
dataRtmp["path"] = "rtmp://127.0.0.1/live/stream";
|
||
|
dataRtmp["mute"] = true;
|
||
|
rtmpServer->setData(dataRtmp);
|
||
|
videoInputA->linkV(videoEncoder)->linkV(rtmpServer);
|
||
|
audioInput->linkA(audioEncoder)->linkA(rtmpServer);
|
||
|
|
||
|
// init file and decoder
|
||
|
file = Link::create("InputFile");
|
||
|
file->start();
|
||
|
videoDecoder = Link::create("DecodeV");
|
||
|
videoDecoder->start();
|
||
|
audioDecoder = Link::create("DecodeA");
|
||
|
audioDecoder->start();
|
||
|
file->linkV(videoDecoder)->linkV(videoOutput);
|
||
|
file->linkA(audioDecoder)->linkA(audioOutput);
|
||
|
|
||
|
connect(file, &LinkObject::newEvent, [=](QString type, QVariant) {
|
||
|
if (type == "EOF") {
|
||
|
qDebug() << "one video playback end";
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief start record
|
||
|
*/
|
||
|
void BoxController::startRecord()
|
||
|
{
|
||
|
if (!isMountDisk()) {
|
||
|
return;
|
||
|
}
|
||
|
QString curTime = QDateTime::currentDateTime().toString("yyyy-MM-dd_hh:mm:ss");
|
||
|
QVariantMap dataRecord;
|
||
|
dataRecord["path"] = QString("%1/videos/%2.mp4").arg(path).arg(curTime);
|
||
|
record->setData(dataRecord);
|
||
|
record->start();
|
||
|
isRecord = true;
|
||
|
|
||
|
recordTimer->start();
|
||
|
snap->invoke("snapSync", QString("%1/snap/%2.jpg").arg(path).arg(curTime));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief stop record
|
||
|
*/
|
||
|
void BoxController::stopRecord()
|
||
|
{
|
||
|
record->stop(true);
|
||
|
isRecord = false;
|
||
|
recordTimer->stop();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief BoxController::onTimeout
|
||
|
*/
|
||
|
void BoxController::onTimeout()
|
||
|
{
|
||
|
if (!isMountDisk()) {
|
||
|
return;
|
||
|
}
|
||
|
record->stop(true);
|
||
|
recordTimer->stop();
|
||
|
|
||
|
QString curTime = QDateTime::currentDateTime().toString("yyyy-MM-dd_hh:mm:ss");
|
||
|
QVariantMap dataRecord;
|
||
|
dataRecord["path"] = QString("%1/videos/%2.mp4").arg(path).arg(curTime);
|
||
|
record->setData(dataRecord);
|
||
|
record->start();
|
||
|
|
||
|
recordTimer->start();
|
||
|
snap->invoke("snapSync", QString("%1/snap/%2.jpg").arg(path).arg(curTime));
|
||
|
}
|
||
|
|
||
|
void BoxController::startRtmpServer()
|
||
|
{
|
||
|
if (rtmpServer->getState() != "started") {
|
||
|
rtmpServer->start();
|
||
|
qDebug() << "start rtmp server...";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief open console process, and use it by command
|
||
|
* @param com
|
||
|
* @return
|
||
|
*/
|
||
|
QString BoxController::writeCom(const QString& com)
|
||
|
{
|
||
|
QProcess proc;
|
||
|
QStringList argList;
|
||
|
argList << "-c" << com;
|
||
|
proc.start("/bin/sh", argList);
|
||
|
// wait process start
|
||
|
proc.waitForFinished();
|
||
|
proc.waitForReadyRead();
|
||
|
// read data from console
|
||
|
QByteArray procOutput = proc.readAll();
|
||
|
proc.close();
|
||
|
return QString(procOutput);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief judge the disk whether mounted
|
||
|
* @return
|
||
|
*/
|
||
|
bool BoxController::isMountDisk()
|
||
|
{
|
||
|
QString mount = writeCom(QString("df %1").arg(path));
|
||
|
if (!mount.contains(path))
|
||
|
return false;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief start playback and output hdmi signals
|
||
|
* @param fileName
|
||
|
*/
|
||
|
void BoxController::startPlayback(QString fileName)
|
||
|
{
|
||
|
QString path = "/root/usb/videos/" + fileName;
|
||
|
videoInputA->unLinkV(videoOutput);
|
||
|
QVariantMap dataFile;
|
||
|
dataFile["path"] = path;
|
||
|
file->start(dataFile);
|
||
|
emit playListNeedHide();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief play live
|
||
|
*/
|
||
|
void BoxController::startPlayLive()
|
||
|
{
|
||
|
videoInputA->linkV(videoOutput);
|
||
|
file->stop(true);
|
||
|
emit playListNeedHide();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief playback -10s
|
||
|
*/
|
||
|
void BoxController::back()
|
||
|
{
|
||
|
qDebug() << "back";
|
||
|
int curPos = file->invoke("getPosition").toInt();
|
||
|
curPos -= 10 * 100;
|
||
|
file->invoke("seek", curPos);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief playback +10s
|
||
|
*/
|
||
|
void BoxController::forward()
|
||
|
{
|
||
|
qDebug() << "forward";
|
||
|
int curPos = file->invoke("getPosition").toInt();
|
||
|
curPos += 10 * 100;
|
||
|
file->invoke("seek", curPos);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief playback pause
|
||
|
*/
|
||
|
void BoxController::pause()
|
||
|
{
|
||
|
QString state = file->getState();
|
||
|
if (state != "started") {
|
||
|
return;
|
||
|
}
|
||
|
file->invoke("pause", true);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief playback resume
|
||
|
*/
|
||
|
void BoxController::resume()
|
||
|
{
|
||
|
QString state = file->getState();
|
||
|
if (state != "started") {
|
||
|
return;
|
||
|
}
|
||
|
file->invoke("pause", false);
|
||
|
}
|