Загрузка данных
#include "cameramanager.h"
#include "configkeys.h"
#include "lib_qt_common/qlogtools.h"
#include "uiconst.h"
// Компоненты EasyStreamer / EasyAV
#include "easyav/transport/clients/livetransportclient.h"
#include "easyapi_avadapter/defaultoptions.h"
#include "easygl/videoglwidget.h"
#include <QDebug>
#include <QLoggingCategory>
#include <QPointer>
#include <variant>
Q_DEVELOPER_LOG_CATGS(arm, CameraManager)
CameraManager::CameraManager(FrameDataSetter *dataSetter, QObject *parent)
: QObject(parent)
, mFrameDataSetter(dataSetter)
, mCamId(0) // Инициализируем дефолтным значением
{
}
void CameraManager::start(CamId camId, const QString &rtpUrl)
{
qCDebug(catg) << Q_FUNC_INFO << this << "Запуск камеры:" << camId << "URL:" << rtpUrl;
mCamId = camId;
mPaused = false;
// Сбрасываем старый пайплайн, если он существовал
if (mReciever.isPipelineExists(1))
{
mReciever.stopPipeline(1);
mReciever.removePipeline(1);
}
// Конфигурируем RTSP/RTP клиент на минимальную задержку (Low Delay)
AVDictionary *dict = EasyApi::DefaultOptions::makeRTPLowDelayFormatClientDict();
auto liveClient = std::make_shared<EasyAV::LiveTransportClient>(rtpUrl.toStdString(), dict);
av_dict_free(&dict);
// Создаем пайплайн с фиксированным ID = 1 (внутри этого менеджера)
mReciever.addMediaPipeline(1, liveClient);
}
void CameraManager::setRendererToStream(CameraWidget *wtCamera, CamId camId)
{
qCDebug(catg) << Q_FUNC_INFO << this << "Привязка рендерера для camId:" << camId;
if (!wtCamera) return;
// Проверяем, что настраиваем именно ту камеру, которая была запущена
if (camId != mCamId)
{
qCWarning(catg) << "Запрошена привязка для camId" << camId << ", но текущий mCamId =" << mCamId;
return;
}
// Извлекаем указатель на новый OpenGL виджет
auto* videoGlWidget = qobject_cast<EasyGL::VideoGlWidget*>(wtCamera->getWtVideo());
if (!videoGlWidget)
{
qCWarning(catg) << "Внутри CameraWidget используется старый виджет, ожидался EasyGL::VideoGlWidget!";
}
// Выставляем дефолтный Aspect Ratio до получения первого кадра
wtCamera->setVideoLayoutAspectRatio({ProjectUiConst::DefaultResolutionWidth, ProjectUiConst::DefaultResolutionHeight});
QPointer<CameraManager> guard(this);
// Коллбэк для пула потоков MediaReciever
EasyAV::MediaRecievePipeline::CbRenderer videoRenderer = [guard, videoGlWidget, wtCamera](std::shared_ptr<EasyApi::IEasyFrame> frame) {
if (!guard || guard->mPaused || !frame)
return;
if (frame->getMediaType() != EasyAV::MediaType::video)
return;
// Перенаправляем обработку и отрисовку кадра в главный GUI-поток Qt
QMetaObject::invokeMethod(guard.data(), [guard, videoGlWidget, wtCamera, frame]() {
if (!guard || guard->mPaused)
return;
auto frameInfo = frame->getFrameInfo();
// Безопасно извлекаем структуру VideoInfo с реальными размерами
if (auto* videoInfo = std::get_if<EasyApi::VideoInfo>(&frameInfo))
{
QSize originalSize(videoInfo->width, videoInfo->height);
// 1. Отдаем кадр напрямую в EasyGL::VideoGlWidget для отрисовки на GPU
if (videoGlWidget)
{
videoGlWidget->submitFrame(frame);
}
// 2. Проверяем изменение разрешения
if (guard->mShMemResolution != originalSize)
{
guard->mShMemResolution = originalSize;
emit guard->resolutionChanged(guard->mCamId, originalSize);
}
// 3. Динамически корректируем Aspect Ratio контейнера под размер стрима
QSize curAspectRatio = wtCamera->getVideoLayoutAspectRatio();
int64_t left = static_cast<int64_t>(originalSize.width()) * curAspectRatio.height();
int64_t right = static_cast<int64_t>(originalSize.height()) * curAspectRatio.width();
if (left != right)
{
wtCamera->setVideoLayoutAspectRatio(originalSize);
}
// 4. Синхронно обновляем телеметрию, прицелы и рамки нейросети
// Передаем mCamId вместо хардкода
if (guard->mFrameDataSetter)
{
guard->mFrameDataSetter->onNewFrameReceived(guard->mCamId, originalSize, frame->getPts().count());
}
emit guard->frameUpdated(guard->mCamId, originalSize, frame->getPts().count());
}
}, Qt::QueuedConnection);
};
// Регистрируем коллбэк рендерера в ресивере и запускаем декодирование
mReciever.addRenderer(1, EasyAV::MediaType::video, videoRenderer);
mReciever.playPipeline(1);
}
void CameraManager::pause(CamId camId)
{
qCDebug(catg) << Q_FUNC_INFO << this << "Пауза для camId:" << camId;
if (camId == mCamId)
{
mPaused = true;
if (mReciever.isPipelineExists(1))
{
mReciever.pausePipeline(1);
}
}
}
QSize CameraManager::getShMemResolution() const
{
return mShMemResolution;
}