Загрузка данных


#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; 
}