204 lines
5.3 KiB
C++
204 lines
5.3 KiB
C++
#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
|