Refactor parameter passing to decoders and split backend/decode-only and frontend renderers

This commit is contained in:
Cameron Gutman 2019-04-11 22:27:20 -07:00
parent 9dcd770df2
commit 25e5175c54
16 changed files with 173 additions and 168 deletions

View file

@ -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(&params)) {
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(&params)) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"FFmpeg-based video decoder chosen");
return true;

View file

@ -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;

View file

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

View file

@ -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;

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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());

View file

@ -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();

View file

@ -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());

View file

@ -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();

View file

@ -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());

View file

@ -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 {

View file

@ -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;

View file

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

View file

@ -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);