mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2025-07-01 23:35:55 +00:00
Refactor frame pacing from VT renderer into a separate class for sharing with other renderers
This commit is contained in:
parent
2a3d5a27a8
commit
f714a5d0cb
@ -113,10 +113,13 @@ ffmpeg {
|
|||||||
DEFINES += HAVE_FFMPEG
|
DEFINES += HAVE_FFMPEG
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
streaming/video/ffmpeg.cpp \
|
streaming/video/ffmpeg.cpp \
|
||||||
streaming/video/ffmpeg-renderers/sdl.cpp
|
streaming/video/ffmpeg-renderers/sdl.cpp \
|
||||||
|
streaming/video/ffmpeg-renderers/pacer.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
streaming/video/ffmpeg.h \
|
streaming/video/ffmpeg.h \
|
||||||
streaming/video/ffmpeg-renderers/renderer.h
|
streaming/video/ffmpeg-renderers/renderer.h \
|
||||||
|
streaming/video/ffmpeg-renderers/pacer.h
|
||||||
}
|
}
|
||||||
libva {
|
libva {
|
||||||
message(VAAPI renderer selected)
|
message(VAAPI renderer selected)
|
||||||
|
70
app/streaming/video/ffmpeg-renderers/pacer.cpp
Normal file
70
app/streaming/video/ffmpeg-renderers/pacer.cpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#include "pacer.h"
|
||||||
|
|
||||||
|
#define FRAME_HISTORY_ENTRIES 8
|
||||||
|
|
||||||
|
Pacer::Pacer() :
|
||||||
|
m_FrameQueueLock(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Pacer::~Pacer()
|
||||||
|
{
|
||||||
|
drain();
|
||||||
|
}
|
||||||
|
|
||||||
|
AVFrame* Pacer::getFrameAtVsync()
|
||||||
|
{
|
||||||
|
SDL_AtomicLock(&m_FrameQueueLock);
|
||||||
|
|
||||||
|
int frameDropTarget;
|
||||||
|
|
||||||
|
// If the queue length history entries are large, be strict
|
||||||
|
// about dropping excess frames.
|
||||||
|
frameDropTarget = 1;
|
||||||
|
for (int i = 0; i < m_FrameQueueHistory.count(); i++) {
|
||||||
|
if (m_FrameQueueHistory[i] <= 1) {
|
||||||
|
// Be lenient as long as the queue length
|
||||||
|
// resolves before the end of frame history
|
||||||
|
frameDropTarget = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_FrameQueueHistory.count() == FRAME_HISTORY_ENTRIES) {
|
||||||
|
m_FrameQueueHistory.dequeue();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_FrameQueueHistory.enqueue(m_FrameQueue.count());
|
||||||
|
|
||||||
|
// Catch up if we're several frames ahead
|
||||||
|
while (m_FrameQueue.count() > frameDropTarget) {
|
||||||
|
AVFrame* frame = m_FrameQueue.dequeue();
|
||||||
|
av_frame_free(&frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_FrameQueue.isEmpty()) {
|
||||||
|
SDL_AtomicUnlock(&m_FrameQueueLock);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the first frame
|
||||||
|
AVFrame* frame = m_FrameQueue.dequeue();
|
||||||
|
SDL_AtomicUnlock(&m_FrameQueueLock);
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pacer::submitFrame(AVFrame* frame)
|
||||||
|
{
|
||||||
|
SDL_AtomicLock(&m_FrameQueueLock);
|
||||||
|
m_FrameQueue.enqueue(frame);
|
||||||
|
SDL_AtomicUnlock(&m_FrameQueueLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pacer::drain()
|
||||||
|
{
|
||||||
|
while (!m_FrameQueue.isEmpty()) {
|
||||||
|
AVFrame* frame = m_FrameQueue.dequeue();
|
||||||
|
av_frame_free(&frame);
|
||||||
|
}
|
||||||
|
}
|
24
app/streaming/video/ffmpeg-renderers/pacer.h
Normal file
24
app/streaming/video/ffmpeg-renderers/pacer.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "renderer.h"
|
||||||
|
|
||||||
|
#include <QQueue>
|
||||||
|
|
||||||
|
class Pacer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Pacer();
|
||||||
|
|
||||||
|
~Pacer();
|
||||||
|
|
||||||
|
AVFrame* getFrameAtVsync();
|
||||||
|
|
||||||
|
void submitFrame(AVFrame* frame);
|
||||||
|
|
||||||
|
void drain();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QQueue<AVFrame*> m_FrameQueue;
|
||||||
|
QQueue<int> m_FrameQueueHistory;
|
||||||
|
SDL_SpinLock m_FrameQueueLock;
|
||||||
|
};
|
@ -2,20 +2,17 @@
|
|||||||
// libavutil both defining AVMediaType
|
// libavutil both defining AVMediaType
|
||||||
#define AVMediaType AVMediaType_FFmpeg
|
#define AVMediaType AVMediaType_FFmpeg
|
||||||
#include "vt.h"
|
#include "vt.h"
|
||||||
|
#include "pacer.h"
|
||||||
#undef AVMediaType
|
#undef AVMediaType
|
||||||
|
|
||||||
#include <SDL_syswm.h>
|
#include <SDL_syswm.h>
|
||||||
#include <Limelight.h>
|
#include <Limelight.h>
|
||||||
|
|
||||||
#include <QQueue>
|
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
#import <VideoToolbox/VideoToolbox.h>
|
#import <VideoToolbox/VideoToolbox.h>
|
||||||
#import <AVFoundation/AVFoundation.h>
|
#import <AVFoundation/AVFoundation.h>
|
||||||
#import <CoreVideo/CoreVideo.h>
|
#import <CoreVideo/CoreVideo.h>
|
||||||
|
|
||||||
#define FRAME_HISTORY_ENTRIES 8
|
|
||||||
|
|
||||||
class VTRenderer : public IFFmpegRenderer
|
class VTRenderer : public IFFmpegRenderer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -24,13 +21,14 @@ public:
|
|||||||
m_DisplayLayer(nullptr),
|
m_DisplayLayer(nullptr),
|
||||||
m_FormatDesc(nullptr),
|
m_FormatDesc(nullptr),
|
||||||
m_View(nullptr),
|
m_View(nullptr),
|
||||||
m_DisplayLink(nullptr),
|
m_DisplayLink(nullptr)
|
||||||
m_FrameQueueLock(0)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~VTRenderer()
|
virtual ~VTRenderer()
|
||||||
{
|
{
|
||||||
|
m_Pacer.drain();
|
||||||
|
|
||||||
if (m_HwContext != nullptr) {
|
if (m_HwContext != nullptr) {
|
||||||
av_buffer_unref(&m_HwContext);
|
av_buffer_unref(&m_HwContext);
|
||||||
}
|
}
|
||||||
@ -44,11 +42,6 @@ public:
|
|||||||
CVDisplayLinkRelease(m_DisplayLink);
|
CVDisplayLinkRelease(m_DisplayLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!m_FrameQueue.isEmpty()) {
|
|
||||||
AVFrame* frame = m_FrameQueue.dequeue();
|
|
||||||
av_frame_free(&frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_View != nullptr) {
|
if (m_View != nullptr) {
|
||||||
[m_View removeFromSuperview];
|
[m_View removeFromSuperview];
|
||||||
}
|
}
|
||||||
@ -58,42 +51,11 @@ public:
|
|||||||
{
|
{
|
||||||
OSStatus status;
|
OSStatus status;
|
||||||
|
|
||||||
SDL_AtomicLock(&m_FrameQueueLock);
|
AVFrame* frame = m_Pacer.getFrameAtVsync();
|
||||||
|
if (frame == nullptr) {
|
||||||
int frameDropTarget;
|
|
||||||
|
|
||||||
// If the queue length history entries are large, be strict
|
|
||||||
// about dropping excess frames.
|
|
||||||
frameDropTarget = 1;
|
|
||||||
for (int i = 0; i < m_FrameQueueHistory.count(); i++) {
|
|
||||||
if (m_FrameQueueHistory[i] <= 1) {
|
|
||||||
// Be lenient as long as the queue length
|
|
||||||
// resolves before the end of frame history
|
|
||||||
frameDropTarget = 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_FrameQueueHistory.count() == FRAME_HISTORY_ENTRIES) {
|
|
||||||
m_FrameQueueHistory.dequeue();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_FrameQueueHistory.enqueue(m_FrameQueue.count());
|
|
||||||
|
|
||||||
// Catch up if we're several frames ahead
|
|
||||||
while (m_FrameQueue.count() > frameDropTarget) {
|
|
||||||
AVFrame* frame = m_FrameQueue.dequeue();
|
|
||||||
av_frame_free(&frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_FrameQueue.isEmpty()) {
|
|
||||||
SDL_AtomicUnlock(&m_FrameQueueLock);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab the first frame
|
|
||||||
AVFrame* frame = m_FrameQueue.dequeue();
|
|
||||||
SDL_AtomicUnlock(&m_FrameQueueLock);
|
|
||||||
|
|
||||||
CVPixelBufferRef pixBuf = reinterpret_cast<CVPixelBufferRef>(frame->data[3]);
|
CVPixelBufferRef pixBuf = reinterpret_cast<CVPixelBufferRef>(frame->data[3]);
|
||||||
|
|
||||||
// If the format has changed or doesn't exist yet, construct it with the
|
// If the format has changed or doesn't exist yet, construct it with the
|
||||||
@ -268,9 +230,7 @@ public:
|
|||||||
setupDisplayLayer();
|
setupDisplayLayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_AtomicLock(&m_FrameQueueLock);
|
m_Pacer.submitFrame(frame);
|
||||||
m_FrameQueue.enqueue(frame);
|
|
||||||
SDL_AtomicUnlock(&m_FrameQueueLock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -297,9 +257,7 @@ private:
|
|||||||
CMVideoFormatDescriptionRef m_FormatDesc;
|
CMVideoFormatDescriptionRef m_FormatDesc;
|
||||||
NSView* m_View;
|
NSView* m_View;
|
||||||
CVDisplayLinkRef m_DisplayLink;
|
CVDisplayLinkRef m_DisplayLink;
|
||||||
QQueue<AVFrame*> m_FrameQueue;
|
Pacer m_Pacer;
|
||||||
QQueue<int> m_FrameQueueHistory;
|
|
||||||
SDL_SpinLock m_FrameQueueLock;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
IFFmpegRenderer* VTRendererFactory::createRenderer() {
|
IFFmpegRenderer* VTRendererFactory::createRenderer() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user