MXVK Vulkan Framework 0.35.0
C++20 Vulkan rendering framework for practical 2D and 3D application development with SDL3.
Loading...
Searching...
No Matches
mxvk_ff_capture.hpp
Go to the documentation of this file.
1/**
2 * @file mxvk_ff_capture.hpp
3 * @brief FFmpeg video-file capture with optional CUDA hardware decoding.
4 */
5#pragma once
6
7#include <cstdint>
8#include <string>
9#include <vector>
10
11extern "C" {
12#include <libavcodec/avcodec.h>
13#include <libavformat/avformat.h>
14#include <libavutil/hwcontext.h>
15#include <libavutil/pixfmt.h>
16#include <libswscale/swscale.h>
17}
18#ifdef MXVK_CUDA
19#include <cuda_runtime_api.h>
20#include <opencv2/core/cuda.hpp>
21#include <opencv2/cudaimgproc.hpp>
22#endif
23
24namespace mxvk {
25
26 /**
27 * @brief FFmpeg-backed video-file capture source.
28 *
29 * VK_FF_Capture opens video files directly through FFmpeg, prefers CUDA
30 * hardware decoding when available, and returns tightly packed RGBA8 or
31 * RGBA16 frames suitable for Vulkan staging uploads or encoder input.
32 */
34 public:
35 /** @brief Construct a closed capture source. */
36 VK_FF_Capture() = default;
37 /** @brief Close and release FFmpeg resources. */
39 VK_FF_Capture(const VK_FF_Capture &) = delete;
43
44 /**
45 * @brief Open a video file.
46 * @param filename Path to the input video file.
47 * @return true on success.
48 */
49 bool open(const std::string &filename);
50 /**
51 * @brief Open a video file on a selected CUDA decode device.
52 * @param filename Path to the input video file.
53 * @param cuda_device CUDA device index used for hardware decode; a negative
54 * value lets FFmpeg select its default device.
55 * @return true on success.
56 */
57 bool open(const std::string &filename, int cuda_device);
58 /**
59 * @brief Seek the active video stream back to its beginning.
60 *
61 * The decoder and optional hardware-device context remain active.
62 * @return true when the input was sought and the decoder was flushed.
63 */
64 bool seek_start();
65 /**
66 * @brief Decode and discard the next video frame.
67 *
68 * Hardware frames remain on the decoder device and no RGBA conversion
69 * or host transfer is performed. This is intended for media-clock
70 * catch-up when a late source frame must not be rendered.
71 * @return true when a frame was decoded and discarded.
72 */
73 bool skip();
74 /** @brief Close the active file and release decoder resources. */
75 void close();
76 /** @brief Check whether a decoder is open. */
77 [[nodiscard]] bool is_open() const { return formatCtx != nullptr && codecCtx != nullptr; }
78
79 /**
80 * @brief Decode the next frame as tightly packed RGBA8.
81 * @param rgba Output byte buffer, resized to pitch * height.
82 * @param width Output frame width in pixels.
83 * @param height Output frame height in pixels.
84 * @param pitch Output row pitch in bytes.
85 * @param flipY Flip rows vertically after conversion when true.
86 * @return true when a frame was decoded, false on EOF or failure.
87 */
88 bool readRgba(std::vector<uint8_t> &rgba, int &width, int &height, int &pitch, bool flipY = false);
89 /**
90 * @brief Decode the next frame as native-endian RGBA16.
91 * @param rgba Output 16-bit component buffer, resized to pitch * height.
92 * @param width Output frame width in pixels.
93 * @param height Output frame height in pixels.
94 * @param pitch Output row pitch in bytes.
95 * @param flipY Flip rows vertically after conversion when true.
96 * @return true when a frame was decoded, false on EOF or failure.
97 *
98 * Ten-bit YUV/P010 sources retain their component precision. Values
99 * remain transfer-encoded; this method does not linearize PQ or HLG.
100 */
101 bool readRgba16(std::vector<uint16_t> &rgba, int &width, int &height, int &pitch, bool flipY = false);
102#ifdef MXVK_CUDA
103 /**
104 * @brief Decode the next frame as a CUDA-resident RGBA8 image.
105 * @param rgba Output CUDA GpuMat containing RGBA8 pixels.
106 * @param stream CUDA stream used for device copies and color conversion.
107 * @param flipY Flip rows vertically after conversion when true.
108 * @return true when a frame was decoded and converted.
109 */
110 bool readGpuRgba(cv::cuda::GpuMat &rgba, cv::cuda::Stream &stream, bool flipY = false);
111#endif
112
113 /** @brief Source width in pixels. */
114 [[nodiscard]] int width() const { return frameWidth; }
115 /** @brief Source height in pixels. */
116 [[nodiscard]] int height() const { return frameHeight; }
117 /** @brief Source frame rate, falling back to 30 fps when unknown. */
118 [[nodiscard]] double fps() const { return frameFps; }
119 /** @brief True when CUDA hardware decode is active. */
120 [[nodiscard]] bool using_hardware_decode() const { return hardwareDecode; }
121 /** @brief Selected CUDA hardware-decode device, or -1 for FFmpeg's default. */
122 [[nodiscard]] int hardware_decode_device() const { return hardwareDecodeDevice; }
123
124 private:
125 static AVPixelFormat chooseHwFormat(AVCodecContext *ctx, const AVPixelFormat *formats);
126 [[nodiscard]] AVPixelFormat selectHwFormat(const AVPixelFormat *formats) const;
127 bool initHardwareDevice(const AVCodec *decoder, int cuda_device);
128 bool decodeNextFrame();
129 bool convertFrameToRgba(const AVFrame *decodedFrame, std::vector<uint8_t> &rgba, int &width, int &height, int &pitch, bool flipY);
130 bool convertFrameToRgba16(const AVFrame *decodedFrame, std::vector<uint16_t> &rgba, int &width, int &height, int &pitch, bool flipY);
131#ifdef MXVK_CUDA
132 bool convertFrameToGpuRgba(const AVFrame *decodedFrame, cv::cuda::GpuMat &rgba, cv::cuda::Stream &stream, bool flipY);
133#endif
134 void flipRows(std::vector<uint8_t> &rgba, int pitch) const;
135
136 AVFormatContext *formatCtx = nullptr;
137 AVCodecContext *codecCtx = nullptr;
138 AVPacket *packet = nullptr;
139 AVFrame *frame = nullptr;
140 AVFrame *swFrame = nullptr;
141 AVBufferRef *hwDeviceCtx = nullptr;
142 SwsContext *swsCtx = nullptr;
143 bool rgba16_conversion_logged = false;
144 int videoStream = -1;
145 int frameWidth = 0;
146 int frameHeight = 0;
147 double frameFps = 30.0;
148 AVPixelFormat hwPixFmt = AV_PIX_FMT_NONE;
149 bool hardwareDecode = false;
150 int hardwareDecodeDevice = -1;
151#ifdef MXVK_CUDA
152 cv::cuda::GpuMat gpuNv12{};
153 cv::cuda::GpuMat gpuRgb{};
154 cv::cuda::GpuMat gpuRgba{};
155 cv::cuda::GpuMat gpuFlippedRgba{};
156 cudaEvent_t decoder_surface_copy_event = nullptr;
157 bool decoder_surface_barrier_logged = false;
158#endif
159 };
160
161} // namespace mxvk
void close()
Close the active file and release decoder resources.
bool is_open() const
Check whether a decoder is open.
VK_FF_Capture & operator=(const VK_FF_Capture &)=delete
double fps() const
Source frame rate, falling back to 30 fps when unknown.
int width() const
Source width in pixels.
int height() const
Source height in pixels.
VK_FF_Capture(VK_FF_Capture &&)=delete
bool open(const std::string &filename)
Open a video file.
bool readRgba16(std::vector< uint16_t > &rgba, int &width, int &height, int &pitch, bool flipY=false)
Decode the next frame as native-endian RGBA16.
VK_FF_Capture(const VK_FF_Capture &)=delete
VK_FF_Capture()=default
Construct a closed capture source.
VK_FF_Capture & operator=(VK_FF_Capture &&)=delete
bool readRgba(std::vector< uint8_t > &rgba, int &width, int &height, int &pitch, bool flipY=false)
Decode the next frame as tightly packed RGBA8.
int hardware_decode_device() const
Selected CUDA hardware-decode device, or -1 for FFmpeg's default.
bool skip()
Decode and discard the next video frame.
bool using_hardware_decode() const
True when CUDA hardware decode is active.
bool seek_start()
Seek the active video stream back to its beginning.
Utilities for loading and saving PNG images.
Definition mxvk.hpp:31