Загрузка данных
#pragma once
#include <QObject>
#include <QSize>
#include "easyav/reciever/mediareciever.h"
// Предварительные объявления
class CameraWidget;
using CamId = int; // Замените на ваш реальный тип
class CameraManager : public QObject
{
QObject
public:
explicit CameraManager(QObject *parent = nullptr);
~CameraManager() override = default;
// Добавляем URL для инициализации RTP потока
void start(CamId camId, const QString &rtpUrl);
void pause(CamId camId);
void setRendererToStream(CameraWidget *wtCamera, CamId camId);
QSize getShMemResolution() const;
signals:
void resolutionChanged(CamId camId, QSize originalSize);
void frameUpdated(CamId camId, QSize originalSize, quint64 frameNum);
private:
EasyAV::MediaReciever mReciever;
CamId mCamId;
QSize mShMemResolution;
bool mPaused = false;
};
#include "cameramanager.h"
#include "configkeys.h"
#include "lib_qt_common/qlogtools.h"
#include "uiconst.h"
#include "videocontrol/widgets/ivideoprocessor.h"
// Подключаем нужные компоненты EasyStreamer
#include "easyav/transport/clients/livetransportclient.h"
#include "easyapi_avadapter/defaultoptions.h"
#include <QDebug>
#include <QLoggingCategory>
#include <QPointer>
Q_DEVELOPER_LOG_CATGS(arm, CameraManager)
CameraManager::CameraManager(QObject *parent)
: QObject(parent)
{
}
void CameraManager::start(CamId camId, const QString &rtpUrl)
{
qCDebug(catg) << Q_FUNC_INFO << this << camId << rtpUrl;
mCamId = camId;
mPaused = false;
// Очищаем предыдущий пайплайн, если камера перезапускается
if (mReciever.isPipelineExists(1))
{
mReciever.stopPipeline(1);
mReciever.removePipeline(1);
}
// Создаем RTP клиент с параметрами минимальной задержки, как в MediaPlayerWt
AVDictionary *dict = EasyApi::DefaultOptions::makeRTPLowDelayFormatClientDict();
auto liveClient = std::make_shared<EasyAV::LiveTransportClient>(rtpUrl.toStdString(), dict);
av_dict_free(&dict);
mReciever.addMediaPipeline(1, liveClient);
// Опционально: если нужно аппаратное ускорение для камер
// mReciever.setHardwareDeviceForCodec(1, hwConfig);
// mReciever.setCustomVideoCodecName(1, "auto");
}
void CameraManager::setRendererToStream(CameraWidget *wtCamera, CamId camId)
{
qCDebug(catg) << Q_FUNC_INFO << this << camId;
if (camId == mCamId)
{
wtCamera->setVideoLayoutAspectRatio({ProjectUiConst::DefaultResolutionWidth, ProjectUiConst::DefaultResolutionHeight});
QPointer<CameraManager> guard(this);
// Настраиваем коллбэк для получения кадров
EasyAV::MediaRecievePipeline::CbRenderer videoRenderer = [guard, wtCamera](std::shared_ptr<EasyAV::IEasyFrame> frame) {
if (!guard || guard->mPaused || !frame)
return;
// ВАЖНО: Коллбэк вызывается из рабочего пула потоков MediaReciever.
// Любая работа с виджетами (wtCamera) должна происходить в главном GUI потоке.
QMetaObject::invokeMethod(guard.data(), [guard, wtCamera, frame]() {
if (!guard || guard->mPaused)
return;
// Получаем оригинальный размер из IEasyFrame
QSize originalSize(frame->getWidth(), frame->getHeight());
if (guard->mShMemResolution != originalSize)
{
guard->mShMemResolution = originalSize;
emit guard->resolutionChanged(guard->mCamId, originalSize);
}
// Корректируем Aspect Ratio
QSize curAspectRatio = wtCamera->getVideoLayoutAspectRatio();
int64_t left = originalSize.width() * curAspectRatio.height();
int64_t right = originalSize.height() * curAspectRatio.width();
if (left != right)
{
wtCamera->setVideoLayoutAspectRatio(originalSize);
}
// --- ОБНОВЛЕНИЕ КАДРА ---
// Вариант А: Если CameraWidget уже переведен на EasyGL::VideoGlWidget
// auto videoWidget = qobject_cast<EasyGL::VideoGlWidget *>(wtCamera->getWtVideo());
// if (videoWidget) videoWidget->submitFrame(frame);
// Вариант Б: Совместимость со старым интерфейсом IVideoProcessor (QPixmap)
auto iVideoProcessor = dynamic_cast<IVideoProcessor *>(wtCamera->getWtVideo());
if (iVideoProcessor)
{
// Внимание: если IVideoProcessor требует именно QPixmap, вам потребуется
// конвертировать IEasyFrame -> QImage -> QPixmap (как вы это делали в
// MediaPlayerWt::makeSwScaledImage).
// Для примера оставил структуру вызова:
// iVideoProcessor->updatePixmap(convertedPixmap, frame->getPts().count());
}
// Вызываем сигнал об обновлении. В качестве frameNum можно использовать PTS кадра.
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;
mPaused = true;
// Если требуется полная остановка декодера, а не просто игнорирование кадров:
// mReciever.pausePipeline(1);
}
QSize CameraManager::getShMemResolution() const
{
return mShMemResolution;
}