增加ffmeida 3588编解码进行推拉流
This commit is contained in:
parent
78676ed65d
commit
68a6dba1e6
72
Module/FFMediaStream/FFMediaStream.pro
Normal file
72
Module/FFMediaStream/FFMediaStream.pro
Normal file
@ -0,0 +1,72 @@
|
||||
# FFMediaStream.pro
|
||||
# 基于 ffmedia_release (Rockchip MPP/RGA/RTSP) 的二次封装
|
||||
# 提供 RTSP 推流 (IVrFFMediaPusher) 和 RTSP 拉流 (IVrFFMediaPuller) 接口
|
||||
|
||||
CONFIG -= qt
|
||||
TEMPLATE = lib
|
||||
DEFINES += FFMEDIASTREAM_LIBRARY
|
||||
|
||||
CONFIG += c++17
|
||||
|
||||
# 全平台使用动态库
|
||||
CONFIG += shared
|
||||
|
||||
win32-msvc {
|
||||
QMAKE_CXXFLAGS += /utf-8
|
||||
QMAKE_CFLAGS += /utf-8
|
||||
}
|
||||
|
||||
# 头文件路径
|
||||
INCLUDEPATH += ./Inc
|
||||
INCLUDEPATH += ./_Inc
|
||||
INCLUDEPATH += $$PWD/../../Utils/VrCommon/Inc
|
||||
INCLUDEPATH += $$PWD/../../Utils/VrUtils/Inc
|
||||
|
||||
# ffmedia 头文件
|
||||
INCLUDEPATH += $$PWD/../../SDK/ffmedia_release/include
|
||||
INCLUDEPATH += $$PWD/../../SDK/ffmedia_release/include/base
|
||||
INCLUDEPATH += $$PWD/../../SDK/ffmedia_release/include/module
|
||||
|
||||
SOURCES += \
|
||||
Src/CVrFFMediaPusher.cpp \
|
||||
Src/CVrFFMediaPuller.cpp
|
||||
|
||||
HEADERS += \
|
||||
Inc/IVrFFMediaPusher.h \
|
||||
Inc/IVrFFMediaPuller.h \
|
||||
_Inc/CVrFFMediaPusher.h \
|
||||
_Inc/CVrFFMediaPuller.h
|
||||
|
||||
# 链接
|
||||
win32:CONFIG(debug, debug|release) {
|
||||
LIBS += -L../../Utils/VrUtils/debug -lVrUtils
|
||||
}else:win32:CONFIG(release, debug|release){
|
||||
LIBS += -L../../Utils/VrUtils/release -lVrUtils
|
||||
}else:unix:!macx {
|
||||
LIBS += -L../../Utils/VrUtils -lVrUtils
|
||||
|
||||
# ffmedia 主库(仅 ARM/Linux 真正可用,Windows 下纯占位)
|
||||
FFMEDIA_LIB_DIR = $$PWD/../../SDK/ffmedia_release/lib
|
||||
RKNN_LIB_DIR = $$PWD/../../SDK/ffmedia_release/inference_examples/lib/RK3588
|
||||
LIBS += -L$${FFMEDIA_LIB_DIR} -lff_media
|
||||
QMAKE_LFLAGS += -Wl,-rpath-link,$${FFMEDIA_LIB_DIR}
|
||||
QMAKE_LFLAGS += -Wl,-rpath-link,$${RKNN_LIB_DIR}
|
||||
|
||||
# 系统依赖(RK3588):rga / mpp / drm。
|
||||
# 这些库由 firefly 系统镜像自带,无需提供。
|
||||
LIBS += -lrga -lrockchip_mpp -ldrm -lpthread -ldl
|
||||
}
|
||||
|
||||
# Windows 下提供编译占位(实现内部用 #ifdef __linux__ 守卫具体调用)
|
||||
win32 {
|
||||
DEFINES += FFMEDIA_PLATFORM_DUMMY
|
||||
LIBS += -lws2_32
|
||||
}
|
||||
|
||||
unix:!macx {
|
||||
message("build FFMediaStream for unix (ffmedia_release)")
|
||||
QMAKE_CXXFLAGS += -fPIC
|
||||
target.path = /usr/lib
|
||||
}
|
||||
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
95
Module/FFMediaStream/Inc/IVrFFMediaPuller.h
Normal file
95
Module/FFMediaStream/Inc/IVrFFMediaPuller.h
Normal file
@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
// DLL 导出宏(FFMEDIASTREAM_LIBRARY 在 .pro 中已定义)
|
||||
#ifdef _WIN32
|
||||
# ifdef FFMEDIASTREAM_LIBRARY
|
||||
# define VR_FFMEDIA_API __declspec(dllexport)
|
||||
# else
|
||||
# define VR_FFMEDIA_API __declspec(dllimport)
|
||||
# endif
|
||||
#else
|
||||
# define VR_FFMEDIA_API
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 拉流帧输出格式
|
||||
*/
|
||||
enum class EFFPullPixelFormat
|
||||
{
|
||||
NV12 = 0, // 原生硬解输出,零拷贝最快
|
||||
RGBA32, // 适合 QImage::Format_RGBA8888 直接显示
|
||||
BGR24, // 适合 OpenCV
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 拉流参数
|
||||
*/
|
||||
struct VrFFPullConfig
|
||||
{
|
||||
std::string rtspUrl; // rtsp://user:pass@host:port/path
|
||||
bool useTcp{true}; // true=TCP 模式,false=UDP(低延迟但容易丢包)
|
||||
bool enableVideo{true};
|
||||
bool enableAudio{false};
|
||||
|
||||
// 解码后输出:是否做 RGA 转换到 RGBA32 / BGR24,以及目标分辨率
|
||||
EFFPullPixelFormat outputFormat{EFFPullPixelFormat::RGBA32};
|
||||
unsigned int outputWidth{0}; // 0 = 跟随输入
|
||||
unsigned int outputHeight{0};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 拉流回调帧
|
||||
*/
|
||||
struct VrFFPulledFrame
|
||||
{
|
||||
const void* data{nullptr};
|
||||
size_t size{0};
|
||||
unsigned int width{0};
|
||||
unsigned int height{0};
|
||||
unsigned int stride{0}; // 一行字节数(RGBA=width*4,BGR=width*3,NV12=hstride)
|
||||
EFFPullPixelFormat format{EFFPullPixelFormat::RGBA32};
|
||||
int64_t ptsUs{0}; // PTS
|
||||
};
|
||||
|
||||
using FFPulledFrameCallback = std::function<void(const VrFFPulledFrame&)>;
|
||||
|
||||
/**
|
||||
* @brief IVrFFMediaPuller
|
||||
*
|
||||
* 基于 ffmedia_release 的 RTSP 拉流(RTSP -> MPP 解码 -> RGA 转换 -> 内存回调)。
|
||||
*
|
||||
* 典型用法:
|
||||
* IVrFFMediaPuller* puller = nullptr;
|
||||
* IVrFFMediaPuller::CreateObject(&puller);
|
||||
* puller->Init(cfg);
|
||||
* puller->SetFrameCallback([](const VrFFPulledFrame& f){ ... });
|
||||
* puller->Start();
|
||||
* ...
|
||||
* puller->Stop();
|
||||
* delete puller;
|
||||
*/
|
||||
class VR_FFMEDIA_API IVrFFMediaPuller
|
||||
{
|
||||
public:
|
||||
virtual ~IVrFFMediaPuller() = default;
|
||||
|
||||
static bool CreateObject(IVrFFMediaPuller** ppPuller);
|
||||
|
||||
virtual int Init(const VrFFPullConfig& config) = 0;
|
||||
|
||||
virtual void SetFrameCallback(FFPulledFrameCallback callback) = 0;
|
||||
|
||||
virtual int Start() = 0;
|
||||
virtual int Stop() = 0;
|
||||
virtual int UnInit() = 0;
|
||||
|
||||
/**
|
||||
* @brief 当前是否处于拉流状态
|
||||
*/
|
||||
virtual bool IsStreaming() const = 0;
|
||||
};
|
||||
133
Module/FFMediaStream/Inc/IVrFFMediaPusher.h
Normal file
133
Module/FFMediaStream/Inc/IVrFFMediaPusher.h
Normal file
@ -0,0 +1,133 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
// DLL 导出宏(FFMEDIASTREAM_LIBRARY 在 .pro 中已定义)
|
||||
#ifdef _WIN32
|
||||
# ifdef FFMEDIASTREAM_LIBRARY
|
||||
# define VR_FFMEDIA_API __declspec(dllexport)
|
||||
# else
|
||||
# define VR_FFMEDIA_API __declspec(dllimport)
|
||||
# endif
|
||||
#else
|
||||
# define VR_FFMEDIA_API
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 推流帧像素格式
|
||||
*/
|
||||
enum class EFFPushPixelFormat
|
||||
{
|
||||
NV12 = 0, // 4:2:0 半平面 (Y + UV)
|
||||
YUV420P, // 4:2:0 平面
|
||||
BGR24, // OpenCV 默认
|
||||
RGB24,
|
||||
BGRA32,
|
||||
RGBA32,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 编码类型
|
||||
*/
|
||||
enum class EFFEncodeType
|
||||
{
|
||||
H264 = 0,
|
||||
H265,
|
||||
MJPEG,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 码率控制模式
|
||||
*/
|
||||
enum class EFFRcMode
|
||||
{
|
||||
CBR = 0,
|
||||
VBR,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 推流参数
|
||||
*/
|
||||
struct VrFFPushConfig
|
||||
{
|
||||
// 帧参数
|
||||
unsigned int width{1920};
|
||||
unsigned int height{1080};
|
||||
EFFPushPixelFormat pixelFormat{EFFPushPixelFormat::NV12};
|
||||
|
||||
// 编码参数
|
||||
EFFEncodeType encodeType{EFFEncodeType::H264};
|
||||
unsigned int fps{30};
|
||||
unsigned int gop{60};
|
||||
unsigned int bitrateKbps{4096}; // 码率 (kbps)
|
||||
EFFRcMode rcMode{EFFRcMode::CBR};
|
||||
|
||||
// RTSP 服务参数
|
||||
std::string rtspPath{"/live/stream"}; // URL 路径
|
||||
unsigned short rtspPort{8554};
|
||||
std::string authRealm;
|
||||
std::string authUser;
|
||||
std::string authPass;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief IVrFFMediaPusher
|
||||
*
|
||||
* 基于 ffmedia_release 的 RTSP 推流(内存输入 -> RGA 格式转换 -> MPP 编码 -> RTSP)。
|
||||
*
|
||||
* 典型用法:
|
||||
* IVrFFMediaPusher* pusher = nullptr;
|
||||
* IVrFFMediaPusher::CreateObject(&pusher);
|
||||
* pusher->Init(cfg);
|
||||
* pusher->Start();
|
||||
* pusher->PushFrame(data, size);
|
||||
* ...
|
||||
* pusher->Stop();
|
||||
* delete pusher;
|
||||
*/
|
||||
class VR_FFMEDIA_API IVrFFMediaPusher
|
||||
{
|
||||
public:
|
||||
virtual ~IVrFFMediaPusher() = default;
|
||||
|
||||
// 工厂
|
||||
static bool CreateObject(IVrFFMediaPusher** ppPusher);
|
||||
|
||||
/**
|
||||
* @brief 初始化推流链路
|
||||
* @return 0 成功
|
||||
*/
|
||||
virtual int Init(const VrFFPushConfig& config) = 0;
|
||||
|
||||
/**
|
||||
* @brief 启动推流(建立 RTSP 服务,等待客户端拉流)
|
||||
*/
|
||||
virtual int Start() = 0;
|
||||
|
||||
/**
|
||||
* @brief 喂入一帧待编码的图像
|
||||
* @param data 帧数据指针
|
||||
* @param size 帧数据大小(字节)
|
||||
* @param ptsUs PTS,单位微秒;传 0 由内部生成
|
||||
* @return 0 成功
|
||||
*/
|
||||
virtual int PushFrame(const void* data, size_t size, int64_t ptsUs = 0) = 0;
|
||||
|
||||
/**
|
||||
* @brief 停止推流
|
||||
*/
|
||||
virtual int Stop() = 0;
|
||||
|
||||
/**
|
||||
* @brief 反初始化
|
||||
*/
|
||||
virtual int UnInit() = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取当前推流 URL(含 IP/端口/路径)
|
||||
*/
|
||||
virtual std::string GetRtspUrl(const std::string& localIp) const = 0;
|
||||
};
|
||||
203
Module/FFMediaStream/Src/CVrFFMediaPuller.cpp
Normal file
203
Module/FFMediaStream/Src/CVrFFMediaPuller.cpp
Normal file
@ -0,0 +1,203 @@
|
||||
#include "CVrFFMediaPuller.h"
|
||||
#include "VrError.h"
|
||||
#include "VrLog.h"
|
||||
|
||||
#if !defined(FFMEDIA_PLATFORM_DUMMY)
|
||||
#include <linux/videodev2.h>
|
||||
#endif
|
||||
|
||||
bool IVrFFMediaPuller::CreateObject(IVrFFMediaPuller** ppPuller)
|
||||
{
|
||||
if (!ppPuller) return false;
|
||||
try { *ppPuller = new CVrFFMediaPuller(); return true; }
|
||||
catch (...) { return false; }
|
||||
}
|
||||
|
||||
CVrFFMediaPuller::CVrFFMediaPuller() = default;
|
||||
|
||||
CVrFFMediaPuller::~CVrFFMediaPuller()
|
||||
{
|
||||
try { UnInit(); } catch (...) {}
|
||||
}
|
||||
|
||||
void CVrFFMediaPuller::SetFrameCallback(FFPulledFrameCallback callback)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_mutex);
|
||||
m_callback = std::move(callback);
|
||||
}
|
||||
|
||||
bool CVrFFMediaPuller::IsStreaming() const
|
||||
{
|
||||
return m_bStarted.load();
|
||||
}
|
||||
|
||||
#if defined(FFMEDIA_PLATFORM_DUMMY)
|
||||
|
||||
// =================== Windows / 非 RK3588 占位实现 ===================
|
||||
|
||||
int CVrFFMediaPuller::Init(const VrFFPullConfig& config)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_mutex);
|
||||
m_config = config;
|
||||
m_bInited = true;
|
||||
LOG_INFO("FFMediaPuller: Init (dummy)\n");
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int CVrFFMediaPuller::Start()
|
||||
{
|
||||
if (!m_bInited.load()) return ERR_CODE(DEV_NO_OPEN);
|
||||
m_bStarted = true;
|
||||
LOG_INFO("FFMediaPuller: Start (dummy)\n");
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int CVrFFMediaPuller::Stop()
|
||||
{
|
||||
m_bStarted = false;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int CVrFFMediaPuller::UnInit()
|
||||
{
|
||||
Stop();
|
||||
m_bInited = false;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// =================== RK3588 真正实现 ===================
|
||||
|
||||
static uint32_t ToV4l2OutPix(EFFPullPixelFormat fmt)
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
case EFFPullPixelFormat::NV12: return V4L2_PIX_FMT_NV12;
|
||||
case EFFPullPixelFormat::RGBA32: return V4L2_PIX_FMT_RGBA32;
|
||||
case EFFPullPixelFormat::BGR24: return V4L2_PIX_FMT_BGR24;
|
||||
}
|
||||
return V4L2_PIX_FMT_RGBA32;
|
||||
}
|
||||
|
||||
static unsigned int PixelBpp(EFFPullPixelFormat fmt)
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
case EFFPullPixelFormat::NV12: return 1; // 平均 1.5 byte/px,但 stride 用 width
|
||||
case EFFPullPixelFormat::RGBA32: return 4;
|
||||
case EFFPullPixelFormat::BGR24: return 3;
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
||||
int CVrFFMediaPuller::Init(const VrFFPullConfig& config)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_mutex);
|
||||
if (m_bInited.load()) return SUCCESS;
|
||||
|
||||
m_config = config;
|
||||
|
||||
// 1) RTSP 拉流
|
||||
m_rtspClient = std::make_shared<ModuleRtspClient>(
|
||||
config.rtspUrl.c_str(),
|
||||
config.useTcp ? RTSP_STREAM_TYPE_TCP : RTSP_STREAM_TYPE_UDP,
|
||||
config.enableVideo,
|
||||
config.enableAudio
|
||||
);
|
||||
if (m_rtspClient->init() != 0)
|
||||
{
|
||||
LOG_ERROR("FFMediaPuller: rtspClient init fail (%s)\n", config.rtspUrl.c_str());
|
||||
return ERR_CODE(DEV_OPEN_ERR);
|
||||
}
|
||||
|
||||
// 2) MPP 解码
|
||||
ImagePara inPara = m_rtspClient->getOutputImagePara();
|
||||
m_decoder = std::make_shared<ModuleMppDec>(inPara);
|
||||
m_decoder->setProductor(m_rtspClient);
|
||||
if (m_decoder->init() != 0)
|
||||
{
|
||||
LOG_ERROR("FFMediaPuller: mppdec init fail\n");
|
||||
return ERR_CODE(DEV_OPEN_ERR);
|
||||
}
|
||||
|
||||
// 3) RGA 转目标格式
|
||||
ImagePara decOut = m_decoder->getOutputImagePara();
|
||||
const uint32_t outFmt = ToV4l2OutPix(config.outputFormat);
|
||||
const unsigned int outW = config.outputWidth ? config.outputWidth : decOut.width;
|
||||
const unsigned int outH = config.outputHeight ? config.outputHeight : decOut.height;
|
||||
ImagePara outPara(outW, outH, outW, outH, outFmt);
|
||||
|
||||
m_rga = std::make_shared<ModuleRga>(decOut, outPara, RGA_ROTATE_NONE);
|
||||
m_rga->setBufferType(VideoBuffer::MALLOC_BUFFER);
|
||||
m_rga->setProductor(m_decoder);
|
||||
|
||||
// 注册输出回调
|
||||
m_rga->setOutputDataCallback(
|
||||
this,
|
||||
[](void* ctx, std::shared_ptr<MediaBuffer> buffer) {
|
||||
if (!ctx || !buffer) return;
|
||||
CVrFFMediaPuller* self = static_cast<CVrFFMediaPuller*>(ctx);
|
||||
FFPulledFrameCallback cb;
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(self->m_mutex);
|
||||
cb = self->m_callback;
|
||||
}
|
||||
if (!cb) return;
|
||||
|
||||
VideoBuffer* vbuf = static_cast<VideoBuffer*>(buffer.get());
|
||||
ImagePara para = vbuf->getImagePara();
|
||||
VrFFPulledFrame frame;
|
||||
frame.data = vbuf->getData();
|
||||
frame.size = vbuf->getActiveSize();
|
||||
frame.width = para.width;
|
||||
frame.height = para.height;
|
||||
frame.stride = para.hstride * PixelBpp(self->m_config.outputFormat);
|
||||
frame.format = self->m_config.outputFormat;
|
||||
frame.ptsUs = vbuf->getPUstimestamp();
|
||||
|
||||
try { cb(frame); } catch (...) {}
|
||||
}
|
||||
);
|
||||
|
||||
if (m_rga->init() != 0)
|
||||
{
|
||||
LOG_ERROR("FFMediaPuller: rga init fail\n");
|
||||
return ERR_CODE(DEV_OPEN_ERR);
|
||||
}
|
||||
|
||||
m_bInited = true;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int CVrFFMediaPuller::Start()
|
||||
{
|
||||
if (!m_bInited.load()) return ERR_CODE(DEV_NO_OPEN);
|
||||
if (m_bStarted.load()) return SUCCESS;
|
||||
if (!m_rtspClient) return ERR_CODE(DEV_CTRL_ERR);
|
||||
|
||||
m_rtspClient->start();
|
||||
m_bStarted = true;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int CVrFFMediaPuller::Stop()
|
||||
{
|
||||
if (!m_bStarted.load()) return SUCCESS;
|
||||
if (m_rtspClient) m_rtspClient->stop();
|
||||
m_bStarted = false;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int CVrFFMediaPuller::UnInit()
|
||||
{
|
||||
Stop();
|
||||
std::lock_guard<std::mutex> lk(m_mutex);
|
||||
m_rga.reset();
|
||||
m_decoder.reset();
|
||||
m_rtspClient.reset();
|
||||
m_bInited = false;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
#endif // FFMEDIA_PLATFORM_DUMMY
|
||||
229
Module/FFMediaStream/Src/CVrFFMediaPusher.cpp
Normal file
229
Module/FFMediaStream/Src/CVrFFMediaPusher.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
#include "CVrFFMediaPusher.h"
|
||||
#include "VrError.h"
|
||||
#include "VrLog.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#if !defined(FFMEDIA_PLATFORM_DUMMY)
|
||||
#include <linux/videodev2.h>
|
||||
#endif
|
||||
|
||||
bool IVrFFMediaPusher::CreateObject(IVrFFMediaPusher** ppPusher)
|
||||
{
|
||||
if (!ppPusher) return false;
|
||||
try { *ppPusher = new CVrFFMediaPusher(); return true; }
|
||||
catch (...) { return false; }
|
||||
}
|
||||
|
||||
CVrFFMediaPusher::CVrFFMediaPusher() = default;
|
||||
|
||||
CVrFFMediaPusher::~CVrFFMediaPusher()
|
||||
{
|
||||
try { UnInit(); } catch (...) {}
|
||||
}
|
||||
|
||||
#if defined(FFMEDIA_PLATFORM_DUMMY)
|
||||
|
||||
// =================== Windows / 非 RK3588 占位实现 ===================
|
||||
// 实际编码/推流仅在 RK3588 + ffmedia_release 下可用
|
||||
// Windows 仅保证编译通过和接口存在
|
||||
|
||||
int CVrFFMediaPusher::Init(const VrFFPushConfig& config)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_mutex);
|
||||
m_config = config;
|
||||
m_bInited = true;
|
||||
LOG_INFO("FFMediaPusher: Init (dummy on this platform)\n");
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int CVrFFMediaPusher::Start()
|
||||
{
|
||||
if (!m_bInited.load()) return ERR_CODE(DEV_NO_OPEN);
|
||||
m_bStarted = true;
|
||||
LOG_INFO("FFMediaPusher: Start (dummy)\n");
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int CVrFFMediaPusher::PushFrame(const void* /*data*/, size_t /*size*/, int64_t /*ptsUs*/)
|
||||
{
|
||||
return m_bStarted.load() ? SUCCESS : ERR_CODE(DEV_NO_OPEN);
|
||||
}
|
||||
|
||||
int CVrFFMediaPusher::Stop()
|
||||
{
|
||||
m_bStarted = false;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int CVrFFMediaPusher::UnInit()
|
||||
{
|
||||
Stop();
|
||||
m_bInited = false;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// =================== RK3588 真正实现 ===================
|
||||
|
||||
static uint32_t ToV4l2Pix(EFFPushPixelFormat fmt)
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
case EFFPushPixelFormat::NV12: return V4L2_PIX_FMT_NV12;
|
||||
case EFFPushPixelFormat::YUV420P: return V4L2_PIX_FMT_YUV420;
|
||||
case EFFPushPixelFormat::BGR24: return V4L2_PIX_FMT_BGR24;
|
||||
case EFFPushPixelFormat::RGB24: return V4L2_PIX_FMT_RGB24;
|
||||
case EFFPushPixelFormat::BGRA32: return V4L2_PIX_FMT_BGR32;
|
||||
case EFFPushPixelFormat::RGBA32: return V4L2_PIX_FMT_RGBA32;
|
||||
}
|
||||
return V4L2_PIX_FMT_NV12;
|
||||
}
|
||||
|
||||
static EncodeType ToFFEncode(EFFEncodeType t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case EFFEncodeType::H264: return ENCODE_TYPE_H264;
|
||||
case EFFEncodeType::H265: return ENCODE_TYPE_H265;
|
||||
case EFFEncodeType::MJPEG: return ENCODE_TYPE_MJPEG;
|
||||
}
|
||||
return ENCODE_TYPE_H264;
|
||||
}
|
||||
|
||||
int CVrFFMediaPusher::Init(const VrFFPushConfig& config)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_mutex);
|
||||
if (m_bInited.load()) return SUCCESS;
|
||||
|
||||
m_config = config;
|
||||
|
||||
const uint32_t inPix = ToV4l2Pix(config.pixelFormat);
|
||||
const bool needRga = (config.pixelFormat != EFFPushPixelFormat::NV12);
|
||||
|
||||
// 1) 内存输入源
|
||||
ImagePara inPara(config.width, config.height, config.width, config.height, inPix);
|
||||
m_memReader = std::make_shared<ModuleMemReader>(inPara);
|
||||
if (m_memReader->init() != 0)
|
||||
{
|
||||
LOG_ERROR("FFMediaPusher: memReader init fail\n");
|
||||
return ERR_CODE(DEV_OPEN_ERR);
|
||||
}
|
||||
|
||||
// 2) (可选)RGA 转 NV12
|
||||
std::shared_ptr<ModuleMedia> encInput = m_memReader;
|
||||
if (needRga)
|
||||
{
|
||||
ImagePara nv12Para(config.width, config.height, config.width, config.height, V4L2_PIX_FMT_NV12);
|
||||
m_rga = std::make_shared<ModuleRga>(inPara, nv12Para, RGA_ROTATE_NONE);
|
||||
m_rga->setProductor(m_memReader);
|
||||
if (m_rga->init() != 0)
|
||||
{
|
||||
LOG_ERROR("FFMediaPusher: rga init fail\n");
|
||||
return ERR_CODE(DEV_OPEN_ERR);
|
||||
}
|
||||
encInput = m_rga;
|
||||
}
|
||||
|
||||
// 3) MPP 硬件编码
|
||||
m_encoder = std::make_shared<ModuleMppEnc>(
|
||||
ToFFEncode(config.encodeType),
|
||||
config.fps,
|
||||
config.gop,
|
||||
config.bitrateKbps,
|
||||
(config.rcMode == EFFRcMode::CBR) ? ENCODE_RC_MODE_CBR : ENCODE_RC_MODE_VBR,
|
||||
ENCODE_QUALITY_BEST,
|
||||
ENCODE_PROFILE_HIGH
|
||||
);
|
||||
m_encoder->setProductor(encInput);
|
||||
m_encoder->setDuration(1000000 / std::max<uint32_t>(1, config.fps));
|
||||
if (m_encoder->init() != 0)
|
||||
{
|
||||
LOG_ERROR("FFMediaPusher: encoder init fail\n");
|
||||
return ERR_CODE(DEV_OPEN_ERR);
|
||||
}
|
||||
|
||||
// 4) RTSP 推流
|
||||
m_rtspServer = std::make_shared<ModuleRtspServer>(config.rtspPath.c_str(), config.rtspPort);
|
||||
if (!config.authUser.empty())
|
||||
{
|
||||
m_rtspServer->setAuthInfo(config.authRealm, config.authUser, config.authPass);
|
||||
}
|
||||
m_rtspServer->setProductor(m_encoder);
|
||||
if (m_rtspServer->init() != 0)
|
||||
{
|
||||
LOG_ERROR("FFMediaPusher: rtsp server init fail\n");
|
||||
return ERR_CODE(DEV_OPEN_ERR);
|
||||
}
|
||||
|
||||
m_bInited = true;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int CVrFFMediaPusher::Start()
|
||||
{
|
||||
if (!m_bInited.load()) return ERR_CODE(DEV_NO_OPEN);
|
||||
if (m_bStarted.load()) return SUCCESS;
|
||||
if (!m_memReader) return ERR_CODE(DEV_CTRL_ERR);
|
||||
|
||||
m_memReader->start();
|
||||
m_bStarted = true;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int CVrFFMediaPusher::PushFrame(const void* data, size_t size, int64_t ptsUs)
|
||||
{
|
||||
if (!m_bStarted.load()) return ERR_CODE(DEV_NO_OPEN);
|
||||
if (!m_memReader) return ERR_CODE(DEV_CTRL_ERR);
|
||||
|
||||
if (ptsUs == 0)
|
||||
{
|
||||
auto now = std::chrono::steady_clock::now().time_since_epoch();
|
||||
ptsUs = std::chrono::duration_cast<std::chrono::microseconds>(now).count();
|
||||
}
|
||||
m_lastPtsUs = ptsUs;
|
||||
|
||||
int ret = m_memReader->setInputBuffer(const_cast<void*>(data), size, -1, ptsUs);
|
||||
if (ret != 0)
|
||||
{
|
||||
LOG_DEBUG("FFMediaPusher: setInputBuffer fail %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
m_memReader->waitProcess(2000);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int CVrFFMediaPusher::Stop()
|
||||
{
|
||||
if (!m_bStarted.load()) return SUCCESS;
|
||||
if (m_memReader)
|
||||
{
|
||||
m_memReader->setProcessStatus(ModuleMemReader::PROCESS_STATUS_EXIT);
|
||||
m_memReader->stop();
|
||||
}
|
||||
m_bStarted = false;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int CVrFFMediaPusher::UnInit()
|
||||
{
|
||||
Stop();
|
||||
std::lock_guard<std::mutex> lk(m_mutex);
|
||||
m_rtspServer.reset();
|
||||
m_encoder.reset();
|
||||
m_rga.reset();
|
||||
m_memReader.reset();
|
||||
m_bInited = false;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
#endif // FFMEDIA_PLATFORM_DUMMY
|
||||
|
||||
std::string CVrFFMediaPusher::GetRtspUrl(const std::string& localIp) const
|
||||
{
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "rtsp://%s:%u%s",
|
||||
localIp.c_str(), m_config.rtspPort, m_config.rtspPath.c_str());
|
||||
return std::string(buf);
|
||||
}
|
||||
39
Module/FFMediaStream/_Inc/CVrFFMediaPuller.h
Normal file
39
Module/FFMediaStream/_Inc/CVrFFMediaPuller.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "IVrFFMediaPuller.h"
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
|
||||
#if !defined(FFMEDIA_PLATFORM_DUMMY)
|
||||
#include "module/vi/module_rtspClient.hpp"
|
||||
#include "module/vp/module_mppdec.hpp"
|
||||
#include "module/vp/module_rga.hpp"
|
||||
#endif
|
||||
|
||||
class CVrFFMediaPuller : public IVrFFMediaPuller
|
||||
{
|
||||
public:
|
||||
CVrFFMediaPuller();
|
||||
~CVrFFMediaPuller() override;
|
||||
|
||||
int Init(const VrFFPullConfig& config) override;
|
||||
void SetFrameCallback(FFPulledFrameCallback callback) override;
|
||||
int Start() override;
|
||||
int Stop() override;
|
||||
int UnInit() override;
|
||||
bool IsStreaming() const override;
|
||||
|
||||
private:
|
||||
VrFFPullConfig m_config;
|
||||
std::atomic<bool> m_bStarted{false};
|
||||
std::atomic<bool> m_bInited{false};
|
||||
FFPulledFrameCallback m_callback;
|
||||
std::mutex m_mutex;
|
||||
|
||||
#if !defined(FFMEDIA_PLATFORM_DUMMY)
|
||||
std::shared_ptr<ModuleRtspClient> m_rtspClient;
|
||||
std::shared_ptr<ModuleMppDec> m_decoder;
|
||||
std::shared_ptr<ModuleRga> m_rga;
|
||||
#endif
|
||||
};
|
||||
42
Module/FFMediaStream/_Inc/CVrFFMediaPusher.h
Normal file
42
Module/FFMediaStream/_Inc/CVrFFMediaPusher.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "IVrFFMediaPusher.h"
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
|
||||
// ffmedia 头(仅在 Linux/RK3588 平台真正可用)
|
||||
#if !defined(FFMEDIA_PLATFORM_DUMMY)
|
||||
#include "module/vi/module_memReader.hpp"
|
||||
#include "module/vp/module_mppenc.hpp"
|
||||
#include "module/vo/module_rtspServer.hpp"
|
||||
#include "module/vp/module_rga.hpp"
|
||||
#endif
|
||||
|
||||
class CVrFFMediaPusher : public IVrFFMediaPusher
|
||||
{
|
||||
public:
|
||||
CVrFFMediaPusher();
|
||||
~CVrFFMediaPusher() override;
|
||||
|
||||
int Init(const VrFFPushConfig& config) override;
|
||||
int Start() override;
|
||||
int PushFrame(const void* data, size_t size, int64_t ptsUs = 0) override;
|
||||
int Stop() override;
|
||||
int UnInit() override;
|
||||
std::string GetRtspUrl(const std::string& localIp) const override;
|
||||
|
||||
private:
|
||||
VrFFPushConfig m_config;
|
||||
std::atomic<bool> m_bStarted{false};
|
||||
std::atomic<bool> m_bInited{false};
|
||||
std::mutex m_mutex;
|
||||
int64_t m_lastPtsUs{0};
|
||||
|
||||
#if !defined(FFMEDIA_PLATFORM_DUMMY)
|
||||
std::shared_ptr<ModuleMemReader> m_memReader;
|
||||
std::shared_ptr<ModuleRga> m_rga; // 输入格式转 NV12(若非 NV12)
|
||||
std::shared_ptr<ModuleMppEnc> m_encoder;
|
||||
std::shared_ptr<ModuleRtspServer> m_rtspServer;
|
||||
#endif
|
||||
};
|
||||
1
SDK/ffmedia_release
Submodule
1
SDK/ffmedia_release
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 6fe74d3fd783faa8725cba9be5f8487e9d92e6d2
|
||||
Loading…
x
Reference in New Issue
Block a user