mirror of
https://github.com/moonlight-stream/moonlight-qt
synced 2024-11-10 05:34:17 +00:00
Refactor parameter passing to decoders and split backend/decode-only and frontend renderers
This commit is contained in:
parent
9dcd770df2
commit
25e5175c54
16 changed files with 173 additions and 168 deletions
|
@ -143,19 +143,28 @@ void Session::clConnectionStatusUpdate(int connectionStatus)
|
|||
}
|
||||
}
|
||||
|
||||
#define CALL_INITIALIZE(dec) (dec)->initialize(vds, window, videoFormat, width, height, frameRate, enableVsync, enableFramePacing)
|
||||
|
||||
bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
|
||||
SDL_Window* window, int videoFormat, int width, int height,
|
||||
int frameRate, bool enableVsync, bool enableFramePacing, bool testOnly, IVideoDecoder*& chosenDecoder)
|
||||
{
|
||||
DECODER_PARAMETERS params;
|
||||
|
||||
params.width = width;
|
||||
params.height = height;
|
||||
params.frameRate = frameRate;
|
||||
params.videoFormat = videoFormat;
|
||||
params.window = window;
|
||||
params.enableVsync = enableVsync;
|
||||
params.enableFramePacing = enableFramePacing;
|
||||
params.vds = vds;
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"V-sync %s",
|
||||
enableVsync ? "enabled" : "disabled");
|
||||
|
||||
#ifdef HAVE_SLVIDEO
|
||||
chosenDecoder = new SLVideoDecoder(testOnly);
|
||||
if (CALL_INITIALIZE(chosenDecoder)) {
|
||||
if (chosenDecoder->initialize(¶ms)) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SLVideo video decoder chosen");
|
||||
return true;
|
||||
|
@ -170,7 +179,7 @@ bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
|
|||
|
||||
#ifdef HAVE_FFMPEG
|
||||
chosenDecoder = new FFmpegVideoDecoder(testOnly);
|
||||
if (CALL_INITIALIZE(chosenDecoder)) {
|
||||
if (chosenDecoder->initialize(¶ms)) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"FFmpeg-based video decoder chosen");
|
||||
return true;
|
||||
|
|
|
@ -26,17 +26,22 @@ typedef struct _VIDEO_STATS {
|
|||
uint32_t measurementStartTimestamp;
|
||||
} VIDEO_STATS, *PVIDEO_STATS;
|
||||
|
||||
typedef struct _DECODER_PARAMETERS {
|
||||
SDL_Window* window;
|
||||
StreamingPreferences::VideoDecoderSelection vds;
|
||||
|
||||
int videoFormat;
|
||||
int width;
|
||||
int height;
|
||||
int frameRate;
|
||||
bool enableVsync;
|
||||
bool enableFramePacing;
|
||||
} DECODER_PARAMETERS, *PDECODER_PARAMETERS;
|
||||
|
||||
class IVideoDecoder {
|
||||
public:
|
||||
virtual ~IVideoDecoder() {}
|
||||
virtual bool initialize(StreamingPreferences::VideoDecoderSelection vds,
|
||||
SDL_Window* window,
|
||||
int videoFormat,
|
||||
int width,
|
||||
int height,
|
||||
int frameRate,
|
||||
bool enableVsync,
|
||||
bool enableFramePacing) = 0;
|
||||
virtual bool initialize(PDECODER_PARAMETERS params) = 0;
|
||||
virtual bool isHardwareAccelerated() = 0;
|
||||
virtual int getDecoderCapabilities() = 0;
|
||||
virtual int submitDecodeUnit(PDECODE_UNIT du) = 0;
|
||||
|
|
|
@ -107,7 +107,7 @@ bool DXVA2Renderer::prepareDecoderContext(AVCodecContext* context)
|
|||
|
||||
int DXVA2Renderer::ffGetBuffer2(AVCodecContext* context, AVFrame* frame, int)
|
||||
{
|
||||
DXVA2Renderer* me = (DXVA2Renderer*)((FFmpegVideoDecoder*)context->opaque)->getRenderer();
|
||||
DXVA2Renderer* me = (DXVA2Renderer*)((FFmpegVideoDecoder*)context->opaque)->getBackendRenderer();
|
||||
|
||||
frame->buf[0] = av_buffer_pool_get(me->m_Pool);
|
||||
if (!frame->buf[0]) {
|
||||
|
@ -649,11 +649,11 @@ bool DXVA2Renderer::initializeDevice(SDL_Window* window, bool enableVsync)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DXVA2Renderer::initialize(SDL_Window* window, int videoFormat, int width, int height, int, bool enableVsync)
|
||||
bool DXVA2Renderer::initialize(PDECODER_PARAMETERS params)
|
||||
{
|
||||
m_VideoFormat = videoFormat;
|
||||
m_VideoWidth = width;
|
||||
m_VideoHeight = height;
|
||||
m_VideoFormat = params->videoFormat;
|
||||
m_VideoWidth = params->width;
|
||||
m_VideoHeight = params->height;
|
||||
|
||||
RtlZeroMemory(&m_Desc, sizeof(m_Desc));
|
||||
|
||||
|
@ -682,7 +682,7 @@ bool DXVA2Renderer::initialize(SDL_Window* window, int videoFormat, int width, i
|
|||
m_Desc.SampleFormat.SampleFormat = DXVA2_SampleProgressiveFrame;
|
||||
m_Desc.Format = (D3DFORMAT)MAKEFOURCC('N','V','1','2');
|
||||
|
||||
if (!initializeDevice(window, enableVsync)) {
|
||||
if (!initializeDevice(params->window, params->enableVsync)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,12 +16,7 @@ class DXVA2Renderer : public IFFmpegRenderer
|
|||
public:
|
||||
DXVA2Renderer();
|
||||
virtual ~DXVA2Renderer();
|
||||
virtual bool initialize(SDL_Window* window,
|
||||
int videoFormat,
|
||||
int width,
|
||||
int height,
|
||||
int maxFps,
|
||||
bool enableVsync) override;
|
||||
virtual bool initialize(PDECODER_PARAMETERS params) override;
|
||||
virtual bool prepareDecoderContext(AVCodecContext* context) override;
|
||||
virtual void renderFrame(AVFrame* frame) override;
|
||||
virtual bool needsTestFrame() override;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "streaming/video/decoder.h"
|
||||
#include "streaming/video/overlaymanager.h"
|
||||
|
||||
extern "C" {
|
||||
|
@ -16,12 +17,7 @@ public:
|
|||
PACING_ANY
|
||||
};
|
||||
|
||||
virtual bool initialize(SDL_Window* window,
|
||||
int videoFormat,
|
||||
int width,
|
||||
int height,
|
||||
int maxFps,
|
||||
bool enableVsync) = 0;
|
||||
virtual bool initialize(PDECODER_PARAMETERS params) = 0;
|
||||
virtual bool prepareDecoderContext(AVCodecContext* context) = 0;
|
||||
virtual void renderFrame(AVFrame* frame) = 0;
|
||||
virtual bool needsTestFrame() = 0;
|
||||
|
|
|
@ -144,20 +144,15 @@ bool SdlRenderer::isRenderThreadSupported()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SdlRenderer::initialize(SDL_Window* window,
|
||||
int,
|
||||
int width,
|
||||
int height,
|
||||
int,
|
||||
bool enableVsync)
|
||||
bool SdlRenderer::initialize(PDECODER_PARAMETERS params)
|
||||
{
|
||||
Uint32 rendererFlags = SDL_RENDERER_ACCELERATED;
|
||||
|
||||
if ((SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN) {
|
||||
if ((SDL_GetWindowFlags(params->window) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN) {
|
||||
// In full-screen exclusive mode, we enable V-sync if requested. For other modes, Windows and Mac
|
||||
// have compositors that make rendering tear-free. Linux compositor varies by distro and user
|
||||
// configuration but doesn't seem feasible to detect here.
|
||||
if (enableVsync) {
|
||||
if (params->enableVsync) {
|
||||
rendererFlags |= SDL_RENDERER_PRESENTVSYNC;
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +165,7 @@ bool SdlRenderer::initialize(SDL_Window* window,
|
|||
SDL_SetHintWithPriority(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, "1", SDL_HINT_OVERRIDE);
|
||||
#endif
|
||||
|
||||
m_Renderer = SDL_CreateRenderer(window, -1, rendererFlags);
|
||||
m_Renderer = SDL_CreateRenderer(params->window, -1, rendererFlags);
|
||||
if (!m_Renderer) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_CreateRenderer() failed: %s",
|
||||
|
@ -180,7 +175,7 @@ bool SdlRenderer::initialize(SDL_Window* window,
|
|||
|
||||
// The window may be smaller than the stream size, so ensure our
|
||||
// logical rendering surface size is equal to the stream size
|
||||
SDL_RenderSetLogicalSize(m_Renderer, width, height);
|
||||
SDL_RenderSetLogicalSize(m_Renderer, params->width, params->height);
|
||||
|
||||
// Draw a black frame until the video stream starts rendering
|
||||
SDL_SetRenderDrawColor(m_Renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
|
||||
|
@ -190,8 +185,8 @@ bool SdlRenderer::initialize(SDL_Window* window,
|
|||
m_Texture = SDL_CreateTexture(m_Renderer,
|
||||
SDL_PIXELFORMAT_YV12,
|
||||
SDL_TEXTUREACCESS_STREAMING,
|
||||
width,
|
||||
height);
|
||||
params->width,
|
||||
params->height);
|
||||
if (!m_Texture) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_CreateRenderer() failed: %s",
|
||||
|
@ -252,6 +247,32 @@ void SdlRenderer::renderOverlay(Overlay::OverlayType type)
|
|||
|
||||
void SdlRenderer::renderFrame(AVFrame* frame)
|
||||
{
|
||||
int err;
|
||||
AVFrame* swFrame = nullptr;
|
||||
|
||||
if (frame->hw_frames_ctx != nullptr) {
|
||||
// If we are acting as the frontend for a hardware
|
||||
// accelerated decoder, we'll need to read the frame
|
||||
// back to render it.
|
||||
|
||||
swFrame = av_frame_alloc();
|
||||
if (swFrame == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
swFrame->width = frame->width;
|
||||
swFrame->height = frame->height;
|
||||
swFrame->format = AV_PIX_FMT_YUV420P;
|
||||
|
||||
err = av_hwframe_transfer_data(swFrame, frame, 0);
|
||||
if (err != 0) {
|
||||
av_frame_free(&swFrame);
|
||||
return;
|
||||
}
|
||||
|
||||
frame = swFrame;
|
||||
}
|
||||
|
||||
SDL_UpdateYUVTexture(m_Texture, nullptr,
|
||||
frame->data[0],
|
||||
frame->linesize[0],
|
||||
|
@ -271,4 +292,8 @@ void SdlRenderer::renderFrame(AVFrame* frame)
|
|||
}
|
||||
|
||||
SDL_RenderPresent(m_Renderer);
|
||||
|
||||
if (swFrame != nullptr) {
|
||||
av_frame_free(&swFrame);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,7 @@ class SdlRenderer : public IFFmpegRenderer {
|
|||
public:
|
||||
SdlRenderer();
|
||||
virtual ~SdlRenderer() override;
|
||||
virtual bool initialize(SDL_Window* window,
|
||||
int videoFormat,
|
||||
int width,
|
||||
int height,
|
||||
int maxFps,
|
||||
bool enableVsync) override;
|
||||
virtual bool initialize(PDECODER_PARAMETERS params) override;
|
||||
virtual bool prepareDecoderContext(AVCodecContext* context) override;
|
||||
virtual void renderFrame(AVFrame* frame) override;
|
||||
virtual bool needsTestFrame() override;
|
||||
|
|
|
@ -29,19 +29,19 @@ VAAPIRenderer::~VAAPIRenderer()
|
|||
}
|
||||
|
||||
bool
|
||||
VAAPIRenderer::initialize(SDL_Window* window, int, int width, int height, int, bool)
|
||||
VAAPIRenderer::initialize(PDECODER_PARAMETERS params)
|
||||
{
|
||||
int err;
|
||||
SDL_SysWMinfo info;
|
||||
|
||||
m_VideoWidth = width;
|
||||
m_VideoHeight = height;
|
||||
m_VideoWidth = params->width;
|
||||
m_VideoHeight = params->height;
|
||||
|
||||
SDL_GetWindowSize(window, &m_DisplayWidth, &m_DisplayHeight);
|
||||
SDL_GetWindowSize(params->window, &m_DisplayWidth, &m_DisplayHeight);
|
||||
|
||||
SDL_VERSION(&info.version);
|
||||
|
||||
if (!SDL_GetWindowWMInfo(window, &info)) {
|
||||
if (!SDL_GetWindowWMInfo(params->window, &info)) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_GetWindowWMInfo() failed: %s",
|
||||
SDL_GetError());
|
||||
|
|
|
@ -30,12 +30,7 @@ class VAAPIRenderer : public IFFmpegRenderer
|
|||
public:
|
||||
VAAPIRenderer();
|
||||
virtual ~VAAPIRenderer();
|
||||
virtual bool initialize(SDL_Window* window,
|
||||
int videoFormat,
|
||||
int width,
|
||||
int height,
|
||||
int maxFps,
|
||||
bool enableVsync);
|
||||
virtual bool initialize(PDECODER_PARAMETERS params);
|
||||
virtual bool prepareDecoderContext(AVCodecContext* context);
|
||||
virtual void renderFrame(AVFrame* frame);
|
||||
virtual bool needsTestFrame();
|
||||
|
|
|
@ -54,14 +54,14 @@ VDPAURenderer::~VDPAURenderer()
|
|||
}
|
||||
}
|
||||
|
||||
bool VDPAURenderer::initialize(SDL_Window* window, int, int width, int height, int, bool)
|
||||
bool VDPAURenderer::initialize(PDECODER_PARAMETERS params)
|
||||
{
|
||||
int err;
|
||||
VdpStatus status;
|
||||
SDL_SysWMinfo info;
|
||||
|
||||
m_VideoWidth = width;
|
||||
m_VideoHeight = height;
|
||||
m_VideoWidth = params->width;
|
||||
m_VideoHeight = params->height;
|
||||
|
||||
err = av_hwdevice_ctx_create(&m_HwContext,
|
||||
AV_HWDEVICE_TYPE_VDPAU,
|
||||
|
@ -93,11 +93,11 @@ bool VDPAURenderer::initialize(SDL_Window* window, int, int width, int height, i
|
|||
GET_PROC_ADDRESS(VDP_FUNC_ID_VIDEO_SURFACE_GET_PARAMETERS, &m_VdpVideoSurfaceGetParameters);
|
||||
GET_PROC_ADDRESS(VDP_FUNC_ID_GET_INFORMATION_STRING, &m_VdpGetInformationString);
|
||||
|
||||
SDL_GetWindowSize(window, (int*)&m_DisplayWidth, (int*)&m_DisplayHeight);
|
||||
SDL_GetWindowSize(params->window, (int*)&m_DisplayWidth, (int*)&m_DisplayHeight);
|
||||
|
||||
SDL_VERSION(&info.version);
|
||||
|
||||
if (!SDL_GetWindowWMInfo(window, &info)) {
|
||||
if (!SDL_GetWindowWMInfo(params->window, &info)) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_GetWindowWMInfo() failed: %s",
|
||||
SDL_GetError());
|
||||
|
|
|
@ -13,12 +13,7 @@ class VDPAURenderer : public IFFmpegRenderer
|
|||
public:
|
||||
VDPAURenderer();
|
||||
virtual ~VDPAURenderer();
|
||||
virtual bool initialize(SDL_Window* window,
|
||||
int videoFormat,
|
||||
int width,
|
||||
int height,
|
||||
int maxFps,
|
||||
bool enableVsync);
|
||||
virtual bool initialize(PDECODER_PARAMETERS params);
|
||||
virtual bool prepareDecoderContext(AVCodecContext* context);
|
||||
virtual void renderFrame(AVFrame* frame);
|
||||
virtual bool needsTestFrame();
|
||||
|
|
|
@ -106,16 +106,11 @@ public:
|
|||
CFRelease(sampleBuffer);
|
||||
}
|
||||
|
||||
virtual bool initialize(SDL_Window* window,
|
||||
int videoFormat,
|
||||
int,
|
||||
int,
|
||||
int,
|
||||
bool) override
|
||||
virtual bool initialize(PDECODER_PARAMETERS params) override
|
||||
{
|
||||
int err;
|
||||
|
||||
if (videoFormat & VIDEO_FORMAT_MASK_H264) {
|
||||
if (params->videoFormat & VIDEO_FORMAT_MASK_H264) {
|
||||
// Prior to 10.13, we'll just assume everything has
|
||||
// H.264 support and fail open to allow VT decode.
|
||||
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
|
||||
|
@ -133,7 +128,7 @@ public:
|
|||
"Assuming H.264 HW decode on < macOS 10.13");
|
||||
}
|
||||
}
|
||||
else if (videoFormat & VIDEO_FORMAT_MASK_H265) {
|
||||
else if (params->videoFormat & VIDEO_FORMAT_MASK_H265) {
|
||||
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
|
||||
if (__builtin_available(macOS 10.13, *)) {
|
||||
if (!VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) {
|
||||
|
@ -156,7 +151,7 @@ public:
|
|||
|
||||
SDL_VERSION(&info.version);
|
||||
|
||||
if (!SDL_GetWindowWMInfo(window, &info)) {
|
||||
if (!SDL_GetWindowWMInfo(params->window, &info)) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_GetWindowWMInfo() failed: %s",
|
||||
SDL_GetError());
|
||||
|
|
|
@ -38,7 +38,7 @@ bool FFmpegVideoDecoder::isHardwareAccelerated()
|
|||
|
||||
int FFmpegVideoDecoder::getDecoderCapabilities()
|
||||
{
|
||||
return m_Renderer->getDecoderCapabilities();
|
||||
return m_BackendRenderer->getDecoderCapabilities();
|
||||
}
|
||||
|
||||
enum AVPixelFormat FFmpegVideoDecoder::ffGetFormat(AVCodecContext* context,
|
||||
|
@ -66,7 +66,8 @@ FFmpegVideoDecoder::FFmpegVideoDecoder(bool testOnly)
|
|||
: m_VideoDecoderCtx(nullptr),
|
||||
m_DecodeBuffer(1024 * 1024, 0),
|
||||
m_HwDecodeCfg(nullptr),
|
||||
m_Renderer(nullptr),
|
||||
m_BackendRenderer(nullptr),
|
||||
m_FrontendRenderer(nullptr),
|
||||
m_ConsecutiveFailedDecodes(0),
|
||||
m_Pacer(nullptr),
|
||||
m_LastFrameNumber(0),
|
||||
|
@ -95,9 +96,9 @@ FFmpegVideoDecoder::~FFmpegVideoDecoder()
|
|||
av_log_set_level(AV_LOG_INFO);
|
||||
}
|
||||
|
||||
IFFmpegRenderer* FFmpegVideoDecoder::getRenderer()
|
||||
IFFmpegRenderer* FFmpegVideoDecoder::getBackendRenderer()
|
||||
{
|
||||
return m_Renderer;
|
||||
return m_BackendRenderer;
|
||||
}
|
||||
|
||||
void FFmpegVideoDecoder::reset()
|
||||
|
@ -116,8 +117,14 @@ void FFmpegVideoDecoder::reset()
|
|||
Session::get()->getOverlayManager().setOverlayRenderer(nullptr);
|
||||
}
|
||||
|
||||
delete m_Renderer;
|
||||
m_Renderer = nullptr;
|
||||
// If we have a separate frontend renderer, free that first
|
||||
if (m_FrontendRenderer != m_BackendRenderer) {
|
||||
delete m_FrontendRenderer;
|
||||
m_FrontendRenderer = nullptr;
|
||||
}
|
||||
|
||||
delete m_BackendRenderer;
|
||||
m_BackendRenderer = nullptr;
|
||||
|
||||
if (!m_TestOnly) {
|
||||
logVideoStats(m_GlobalVideoStats, "Global video stats");
|
||||
|
@ -128,35 +135,46 @@ void FFmpegVideoDecoder::reset()
|
|||
}
|
||||
}
|
||||
|
||||
bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* window,
|
||||
int videoFormat, int width, int height,
|
||||
int maxFps, bool enableFramePacing, bool testFrame)
|
||||
bool FFmpegVideoDecoder::createFrontendRenderer(PDECODER_PARAMETERS params)
|
||||
{
|
||||
m_FrontendRenderer = m_BackendRenderer;
|
||||
|
||||
// Determine whether the frontend renderer prefers frame pacing
|
||||
auto vsyncConstraint = m_FrontendRenderer->getFramePacingConstraint();
|
||||
if (vsyncConstraint == IFFmpegRenderer::PACING_FORCE_OFF && params->enableFramePacing) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Frame pacing is forcefully disabled by the frontend renderer");
|
||||
params->enableFramePacing = false;
|
||||
}
|
||||
else if (vsyncConstraint == IFFmpegRenderer::PACING_FORCE_ON && !params->enableFramePacing) {
|
||||
// FIXME: This duplicates logic in Session.cpp
|
||||
int displayHz = StreamUtils::getDisplayRefreshRate(params->window);
|
||||
if (displayHz + 5 >= params->frameRate) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Frame pacing is forcefully enabled by the frontend renderer");
|
||||
params->enableFramePacing = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, PDECODER_PARAMETERS params, bool testFrame)
|
||||
{
|
||||
// In test-only mode, we should only see test frames
|
||||
SDL_assert(!m_TestOnly || testFrame);
|
||||
|
||||
auto vsyncConstraint = m_Renderer->getFramePacingConstraint();
|
||||
if (vsyncConstraint == IFFmpegRenderer::PACING_FORCE_OFF && enableFramePacing) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Frame pacing is forcefully disabled by the active renderer");
|
||||
enableFramePacing = false;
|
||||
}
|
||||
else if (vsyncConstraint == IFFmpegRenderer::PACING_FORCE_ON && !enableFramePacing) {
|
||||
// FIXME: This duplicates logic in Session.cpp
|
||||
int displayHz = StreamUtils::getDisplayRefreshRate(window);
|
||||
if (displayHz + 5 >= maxFps) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Frame pacing is forcefully enabled by the active renderer");
|
||||
enableFramePacing = true;
|
||||
}
|
||||
// Create the frontend renderer based on the capabilities of the backend renderer
|
||||
if (!createFrontendRenderer(params)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_StreamFps = maxFps;
|
||||
m_StreamFps = params->frameRate;
|
||||
|
||||
// Don't bother initializing Pacer if we're not actually going to render
|
||||
if (!testFrame) {
|
||||
m_Pacer = new Pacer(m_Renderer, &m_ActiveWndVideoStats);
|
||||
if (!m_Pacer->initialize(window, maxFps, enableFramePacing)) {
|
||||
m_Pacer = new Pacer(m_FrontendRenderer, &m_ActiveWndVideoStats);
|
||||
if (!m_Pacer->initialize(params->window, params->frameRate, params->enableFramePacing)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -176,7 +194,7 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* wi
|
|||
m_VideoDecoderCtx->flags2 |= AV_CODEC_FLAG2_SHOW_ALL;
|
||||
|
||||
// Enable slice multi-threading for software decoding
|
||||
if (!m_HwDecodeCfg) {
|
||||
if (!isHardwareAccelerated()) {
|
||||
m_VideoDecoderCtx->thread_type = FF_THREAD_SLICE;
|
||||
m_VideoDecoderCtx->thread_count = qMin(MAX_SLICES, SDL_GetCPUCount());
|
||||
}
|
||||
|
@ -186,13 +204,13 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* wi
|
|||
}
|
||||
|
||||
// Setup decoding parameters
|
||||
m_VideoDecoderCtx->width = width;
|
||||
m_VideoDecoderCtx->height = height;
|
||||
m_VideoDecoderCtx->width = params->width;
|
||||
m_VideoDecoderCtx->height = params->height;
|
||||
m_VideoDecoderCtx->pix_fmt = AV_PIX_FMT_YUV420P; // FIXME: HDR
|
||||
m_VideoDecoderCtx->get_format = ffGetFormat;
|
||||
|
||||
// Allow the renderer to attach data to this decoder
|
||||
if (!m_Renderer->prepareDecoderContext(m_VideoDecoderCtx)) {
|
||||
// Allow the backend renderer to attach data to this decoder
|
||||
if (!m_BackendRenderer->prepareDecoderContext(m_VideoDecoderCtx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -207,7 +225,7 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* wi
|
|||
if (err < 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Unable to open decoder for format: %x",
|
||||
videoFormat);
|
||||
params->videoFormat);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -217,7 +235,7 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* wi
|
|||
// now to see if things will actually work when the video stream
|
||||
// comes in.
|
||||
if (testFrame) {
|
||||
if (videoFormat & VIDEO_FORMAT_MASK_H264) {
|
||||
if (params->videoFormat & VIDEO_FORMAT_MASK_H264) {
|
||||
m_Pkt.data = (uint8_t*)k_H264TestFrame;
|
||||
m_Pkt.size = sizeof(k_H264TestFrame);
|
||||
}
|
||||
|
@ -236,8 +254,8 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* wi
|
|||
}
|
||||
}
|
||||
else {
|
||||
if ((videoFormat & VIDEO_FORMAT_MASK_H264) &&
|
||||
!(m_Renderer->getDecoderCapabilities() & CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC)) {
|
||||
if ((params->videoFormat & VIDEO_FORMAT_MASK_H264) &&
|
||||
!(m_BackendRenderer->getDecoderCapabilities() & CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC)) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Using H.264 SPS fixup");
|
||||
m_NeedsSpsFixup = true;
|
||||
|
@ -246,8 +264,8 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* wi
|
|||
m_NeedsSpsFixup = false;
|
||||
}
|
||||
|
||||
// Tell overlay manager to use this renderer
|
||||
Session::get()->getOverlayManager().setOverlayRenderer(m_Renderer);
|
||||
// Tell overlay manager to use this frontend renderer
|
||||
Session::get()->getOverlayManager().setOverlayRenderer(m_FrontendRenderer);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -361,25 +379,17 @@ IFFmpegRenderer* FFmpegVideoDecoder::createAcceleratedRenderer(const AVCodecHWCo
|
|||
}
|
||||
}
|
||||
|
||||
bool FFmpegVideoDecoder::initialize(
|
||||
StreamingPreferences::VideoDecoderSelection vds,
|
||||
SDL_Window* window,
|
||||
int videoFormat,
|
||||
int width,
|
||||
int height,
|
||||
int maxFps,
|
||||
bool enableVsync,
|
||||
bool enableFramePacing)
|
||||
bool FFmpegVideoDecoder::initialize(PDECODER_PARAMETERS params)
|
||||
{
|
||||
AVCodec* decoder;
|
||||
|
||||
// Increase log level until the first frame is decoded
|
||||
av_log_set_level(AV_LOG_DEBUG);
|
||||
|
||||
if (videoFormat & VIDEO_FORMAT_MASK_H264) {
|
||||
if (params->videoFormat & VIDEO_FORMAT_MASK_H264) {
|
||||
decoder = avcodec_find_decoder(AV_CODEC_ID_H264);
|
||||
}
|
||||
else if (videoFormat & VIDEO_FORMAT_MASK_H265) {
|
||||
else if (params->videoFormat & VIDEO_FORMAT_MASK_H265) {
|
||||
decoder = avcodec_find_decoder(AV_CODEC_ID_HEVC);
|
||||
}
|
||||
else {
|
||||
|
@ -390,20 +400,20 @@ bool FFmpegVideoDecoder::initialize(
|
|||
if (!decoder) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Unable to find decoder for format: %x",
|
||||
videoFormat);
|
||||
params->videoFormat);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0;; i++) {
|
||||
const AVCodecHWConfig *config = avcodec_get_hw_config(decoder, i);
|
||||
if (!config || vds == StreamingPreferences::VDS_FORCE_SOFTWARE) {
|
||||
if (!config || params->vds == StreamingPreferences::VDS_FORCE_SOFTWARE) {
|
||||
// No matching hardware acceleration support.
|
||||
// This is not an error.
|
||||
m_HwDecodeCfg = nullptr;
|
||||
m_Renderer = new SdlRenderer();
|
||||
if (vds != StreamingPreferences::VDS_FORCE_HARDWARE &&
|
||||
m_Renderer->initialize(window, videoFormat, width, height, maxFps, enableVsync) &&
|
||||
completeInitialization(decoder, window, videoFormat, width, height, maxFps, enableFramePacing, m_TestOnly)) {
|
||||
m_BackendRenderer = new SdlRenderer();
|
||||
if (params->vds != StreamingPreferences::VDS_FORCE_HARDWARE &&
|
||||
m_BackendRenderer->initialize(params) &&
|
||||
completeInitialization(decoder, params, m_TestOnly)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
@ -412,27 +422,27 @@ bool FFmpegVideoDecoder::initialize(
|
|||
}
|
||||
}
|
||||
|
||||
m_Renderer = createAcceleratedRenderer(config);
|
||||
if (!m_Renderer) {
|
||||
m_BackendRenderer = createAcceleratedRenderer(config);
|
||||
if (!m_BackendRenderer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_HwDecodeCfg = config;
|
||||
// Initialize the hardware codec and submit a test frame if the renderer needs it
|
||||
if (m_Renderer->initialize(window, videoFormat, width, height, maxFps, enableVsync) &&
|
||||
completeInitialization(decoder, window, videoFormat, width, height, maxFps, enableFramePacing, m_TestOnly || m_Renderer->needsTestFrame())) {
|
||||
if (m_BackendRenderer->initialize(params) &&
|
||||
completeInitialization(decoder, params, m_TestOnly || m_BackendRenderer->needsTestFrame())) {
|
||||
if (m_TestOnly) {
|
||||
// This decoder is only for testing capabilities, so don't bother
|
||||
// creating a usable renderer
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_Renderer->needsTestFrame()) {
|
||||
if (m_BackendRenderer->needsTestFrame()) {
|
||||
// The test worked, so now let's initialize it for real
|
||||
reset();
|
||||
if ((m_Renderer = createAcceleratedRenderer(config)) != nullptr &&
|
||||
m_Renderer->initialize(window, videoFormat, width, height, maxFps, enableVsync) &&
|
||||
completeInitialization(decoder, window, videoFormat, width, height, maxFps, enableFramePacing, false)) {
|
||||
if ((m_BackendRenderer = createAcceleratedRenderer(config)) != nullptr &&
|
||||
m_BackendRenderer->initialize(params) &&
|
||||
completeInitialization(decoder, params, false)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -12,25 +12,16 @@ class FFmpegVideoDecoder : public IVideoDecoder {
|
|||
public:
|
||||
FFmpegVideoDecoder(bool testOnly);
|
||||
virtual ~FFmpegVideoDecoder() override;
|
||||
virtual bool initialize(StreamingPreferences::VideoDecoderSelection vds,
|
||||
SDL_Window* window,
|
||||
int videoFormat,
|
||||
int width,
|
||||
int height,
|
||||
int maxFps,
|
||||
bool enableVsync,
|
||||
bool enableFramePacing) override;
|
||||
virtual bool initialize(PDECODER_PARAMETERS params) override;
|
||||
virtual bool isHardwareAccelerated() override;
|
||||
virtual int getDecoderCapabilities() override;
|
||||
virtual int submitDecodeUnit(PDECODE_UNIT du) override;
|
||||
virtual void renderFrameOnMainThread() override;
|
||||
|
||||
virtual IFFmpegRenderer* getRenderer();
|
||||
virtual IFFmpegRenderer* getBackendRenderer();
|
||||
|
||||
private:
|
||||
bool completeInitialization(AVCodec* decoder, SDL_Window* window,
|
||||
int videoFormat, int width, int height,
|
||||
int maxFps, bool enableFramePacing, bool testFrame);
|
||||
bool completeInitialization(AVCodec* decoder, PDECODER_PARAMETERS params, bool testFrame);
|
||||
|
||||
void stringifyVideoStats(VIDEO_STATS& stats, char* output);
|
||||
|
||||
|
@ -38,6 +29,8 @@ private:
|
|||
|
||||
void addVideoStats(VIDEO_STATS& src, VIDEO_STATS& dst);
|
||||
|
||||
bool createFrontendRenderer(PDECODER_PARAMETERS params);
|
||||
|
||||
IFFmpegRenderer* createAcceleratedRenderer(const AVCodecHWConfig* hwDecodeCfg);
|
||||
|
||||
void reset();
|
||||
|
@ -52,7 +45,8 @@ private:
|
|||
AVCodecContext* m_VideoDecoderCtx;
|
||||
QByteArray m_DecodeBuffer;
|
||||
const AVCodecHWConfig* m_HwDecodeCfg;
|
||||
IFFmpegRenderer* m_Renderer;
|
||||
IFFmpegRenderer* m_BackendRenderer;
|
||||
IFFmpegRenderer* m_FrontendRenderer;
|
||||
int m_ConsecutiveFailedDecodes;
|
||||
Pacer* m_Pacer;
|
||||
VIDEO_STATS m_ActiveWndVideoStats;
|
||||
|
|
|
@ -32,17 +32,15 @@ SLVideoDecoder::getDecoderCapabilities()
|
|||
}
|
||||
|
||||
bool
|
||||
SLVideoDecoder::initialize(StreamingPreferences::VideoDecoderSelection vds,
|
||||
SDL_Window*,
|
||||
int videoFormat, int, int, int frameRate, bool, bool)
|
||||
SLVideoDecoder::initialize(PDECODER_PARAMETERS params)
|
||||
{
|
||||
// SLVideo only supports hardware decoding
|
||||
if (vds == StreamingPreferences::VDS_FORCE_SOFTWARE) {
|
||||
if (params->vds == StreamingPreferences::VDS_FORCE_SOFTWARE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// SLVideo only supports H.264
|
||||
if (videoFormat != VIDEO_FORMAT_H264) {
|
||||
if (params->videoFormat != VIDEO_FORMAT_H264) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -61,7 +59,7 @@ SLVideoDecoder::initialize(StreamingPreferences::VideoDecoderSelection vds,
|
|||
return false;
|
||||
}
|
||||
|
||||
SLVideo_SetStreamTargetFramerate(m_VideoStream, frameRate, 1);
|
||||
SLVideo_SetStreamTargetFramerate(m_VideoStream, params->frameRate, 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -9,14 +9,7 @@ class SLVideoDecoder : public IVideoDecoder
|
|||
public:
|
||||
SLVideoDecoder(bool testOnly);
|
||||
virtual ~SLVideoDecoder();
|
||||
virtual bool initialize(StreamingPreferences::VideoDecoderSelection vds,
|
||||
SDL_Window* window,
|
||||
int videoFormat,
|
||||
int width,
|
||||
int height,
|
||||
int frameRate,
|
||||
bool enableVsync,
|
||||
bool enableFramePacing);
|
||||
virtual bool initialize(PDECODER_PARAMETERS params);
|
||||
virtual bool isHardwareAccelerated();
|
||||
virtual int getDecoderCapabilities();
|
||||
virtual int submitDecodeUnit(PDECODE_UNIT du);
|
||||
|
|
Loading…
Reference in a new issue