Moonlight-XboxOG latest
Moonlight Xbox OG is a port of the Moonlight Game Streaming client to the original Xbox console.
ffmpeg_stream_backend.h
Go to the documentation of this file.
1
5#pragma once
6
7// standard includes
8#include <atomic>
9#include <cstdint>
10#include <mutex>
11#include <string>
12#include <vector>
13
14// lib includes
15#include <SDL.h>
16
17// local includes
18#include "third-party/moonlight-common-c/src/Limelight.h"
19
20struct AVCodecContext;
21struct AVFrame;
22struct AVPacket;
23struct SwrContext;
24struct SwsContext;
25
26namespace streaming {
27
31 using SdlThreadContext = void;
32
41 public:
46
51
53 FfmpegStreamBackend &operator=(const FfmpegStreamBackend &) = delete;
54
61 void initialize_callbacks(DECODER_RENDERER_CALLBACKS *videoCallbacks, AUDIO_RENDERER_CALLBACKS *audioCallbacks) const;
62
68 void set_audio_playback_enabled(bool enabled);
69
73 void shutdown();
74
84 bool render_latest_video_frame(SDL_Renderer *renderer, int screenWidth, int screenHeight, bool allowDirectFramebuffer = true);
85
91 bool has_decoded_video() const;
92
98 bool has_unrendered_video_frame() const;
99
106 std::uint64_t milliseconds_since_last_decoded_video_frame(std::uint64_t nowMicroseconds) const;
107
113 std::string build_overlay_status_line() const;
114
125 int setup_video_decoder(int videoFormat, int width, int height, int redrawRate, int drFlags);
126
130 void start_video_decoder();
131
135 void stop_video_decoder();
136
141
150 int initialize_audio_decoder(int audioConfiguration, const OPUS_MULTISTREAM_CONFIGURATION *opusConfig, int arFlags);
151
156
160 void stop_audio_playback();
161
166
173
180 void decode_and_play_audio_sample(const char *sampleData, int sampleLength);
181
182 private:
189 static int run_video_decode_thread_trampoline(SdlThreadContext *context);
190
196 int run_video_decode_thread();
197
205 int drop_queued_video_decode_units(VIDEO_FRAME_HANDLE *frameHandle, PDECODE_UNIT *decodeUnit);
206
214 int prepare_video_decode_unit(VIDEO_FRAME_HANDLE *frameHandle, PDECODE_UNIT *decodeUnit);
215
222 int decode_video_decode_unit(PDECODE_UNIT decodeUnit);
223
229 int receive_available_video_frames();
230
237 bool publish_video_frame(const AVFrame *frameToPresent);
238
246 bool render_latest_video_frame_to_framebuffer(int screenWidth, int screenHeight);
247
251 struct LatestVideoFrame {
252 int width = 0;
253 int height = 0;
254 int yPitch = 0;
255 int uPitch = 0;
256 int vPitch = 0;
257 std::vector<std::uint8_t> yPlane;
258 std::vector<std::uint8_t> uPlane;
259 std::vector<std::uint8_t> vPlane;
260 };
261
265 struct VideoState { // NOSONAR(cpp:S1820) Owned video pipeline state intentionally groups FFmpeg, SDL, queue, and metric lifetimes.
266 AVCodecContext *codecContext = nullptr;
267 SwsContext *scaleContext = nullptr;
268 SwsContext *presentScaleContext = nullptr;
269 AVFrame *decodedFrame = nullptr;
270 AVFrame *convertedFrame = nullptr;
271 AVPacket *packet = nullptr;
272 SDL_Texture *texture = nullptr;
273 SDL_Thread *decoderThread = nullptr;
274 int textureWidth = 0;
275 int textureHeight = 0;
276 std::uint64_t latestFrameVersion = 0;
277 std::uint64_t renderedFrameVersion = 0;
278 std::vector<std::uint8_t> convertedBuffer;
279 std::vector<std::uint8_t> packetBuffer;
280
286 [[nodiscard]] std::mutex &frame_mutex() const {
287 return frameMutex_;
288 }
289
290 private:
291 mutable std::mutex frameMutex_;
292
293 public:
294 SDL_Rect directFramebufferDestination {0, 0, 0, 0};
295 LatestVideoFrame latestFrame;
296 LatestVideoFrame decodeFrame;
297 LatestVideoFrame renderFrame;
298 bool directFramebufferCleared = false;
299 std::atomic<bool> decoderStopRequested = false;
300 std::atomic<bool> hasFrame = false;
301 std::atomic<std::uint64_t> publishedFrameVersion = 0;
302 std::atomic<std::uint64_t> submittedDecodeUnitCount = 0;
303 std::atomic<std::uint64_t> decodedFrameCount = 0;
304 std::atomic<std::uint64_t> droppedDecodeUnitCount = 0;
305 std::atomic<std::uint64_t> lastDecodeQueueUs = 0;
306 std::atomic<std::uint64_t> lastReceiveAgeUs = 0;
307 std::atomic<std::uint64_t> lastDecodedFrameUs = 0;
308 std::atomic<int> lastDecodeFrameNumber = 0;
309 };
310
314 struct AudioState {
315 AVCodecContext *codecContext = nullptr;
316 SwrContext *resampleContext = nullptr;
317 AVFrame *decodedFrame = nullptr;
318 AVPacket *packet = nullptr;
319 SDL_AudioDeviceID deviceId = 0;
320 SDL_AudioSpec obtainedSpec {};
321 std::vector<std::uint8_t> outputBuffer;
322 int resampleInputSampleRate = 0;
323 int resampleInputSampleFormat = -1;
324 int resampleInputChannelCount = 0;
325 std::atomic<bool> deviceStarted = false;
326 std::atomic<std::uint64_t> queuedAudioBytes = 0;
327 };
328
329 VideoState video_ {};
330 AudioState audio_ {};
331 std::atomic<bool> audioPlaybackEnabled_ = false;
332 };
333
334} // namespace streaming
Owns the FFmpeg decode and SDL presentation state for one stream.
Definition ffmpeg_stream_backend.h:40
void shutdown()
Release all FFmpeg, SDL, and cached frame resources.
Definition ffmpeg_stream_backend.cpp:372
bool ensure_audio_resampler()
Ensure the audio resampler matches the current decoded frame.
Definition ffmpeg_stream_backend.cpp:1099
std::string build_overlay_status_line() const
Build a short user-visible media status line.
Definition ffmpeg_stream_backend.cpp:443
void start_video_decoder()
Start the video decode path.
Definition ffmpeg_stream_backend.cpp:551
void initialize_callbacks(DECODER_RENDERER_CALLBACKS *videoCallbacks, AUDIO_RENDERER_CALLBACKS *audioCallbacks) const
Populate Moonlight callback tables for this backend.
Definition ffmpeg_stream_backend.cpp:341
std::uint64_t milliseconds_since_last_decoded_video_frame(std::uint64_t nowMicroseconds) const
Return how long it has been since FFmpeg published a decoded video frame.
Definition ffmpeg_stream_backend.cpp:435
void stop_audio_playback()
Stop SDL audio playback.
Definition ffmpeg_stream_backend.cpp:1062
void stop_video_decoder()
Stop the video decode path.
Definition ffmpeg_stream_backend.cpp:564
void decode_and_play_audio_sample(const char *sampleData, int sampleLength)
Decode and queue one Moonlight Opus audio payload.
Definition ffmpeg_stream_backend.cpp:1144
void set_audio_playback_enabled(bool enabled)
Configure whether streamed audio should be decoded and played locally.
Definition ffmpeg_stream_backend.cpp:368
bool has_unrendered_video_frame() const
Report whether a newly decoded video frame has not been presented yet.
Definition ffmpeg_stream_backend.cpp:431
FfmpegStreamBackend()=default
Construct an empty backend.
int initialize_audio_decoder(int audioConfiguration, const OPUS_MULTISTREAM_CONFIGURATION *opusConfig, int arFlags)
Initialize the FFmpeg Opus decoder and SDL playback device.
Definition ffmpeg_stream_backend.cpp:980
bool has_decoded_video() const
Report whether at least one decoded video frame is available.
Definition ffmpeg_stream_backend.cpp:377
void start_audio_playback()
Start SDL audio playback.
Definition ffmpeg_stream_backend.cpp:1054
int setup_video_decoder(int videoFormat, int width, int height, int redrawRate, int drFlags)
Initialize the FFmpeg H.264 decoder for Moonlight video callbacks.
Definition ffmpeg_stream_backend.cpp:506
~FfmpegStreamBackend()
Destroy the backend and release all resources.
Definition ffmpeg_stream_backend.cpp:337
void cleanup_video_decoder()
Clean up all FFmpeg video decode resources.
Definition ffmpeg_stream_backend.cpp:578
void cleanup_audio_decoder()
Clean up all FFmpeg audio decode resources.
Definition ffmpeg_stream_backend.cpp:1069
bool render_latest_video_frame(SDL_Renderer *renderer, int screenWidth, int screenHeight, bool allowDirectFramebuffer=true)
Render the latest decoded video frame to the supplied renderer.
Definition ffmpeg_stream_backend.cpp:453
void SdlThreadContext
Opaque SDL thread context payload.
Definition ffmpeg_stream_backend.h:31