MXVK Vulkan Framework 0.33.1
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 frames
31 * 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#ifdef MXVK_CUDA
90 /**
91 * @brief Decode the next frame as a CUDA-resident RGBA8 image.
92 * @param rgba Output CUDA GpuMat containing RGBA8 pixels.
93 * @param stream CUDA stream used for device copies and color conversion.
94 * @param flipY Flip rows vertically after conversion when true.
95 * @return true when a frame was decoded and converted.
96 */
97 bool readGpuRgba(cv::cuda::GpuMat &rgba, cv::cuda::Stream &stream, bool flipY = false);
98#endif
99
100 /** @brief Source width in pixels. */
101 [[nodiscard]] int width() const { return frameWidth; }
102 /** @brief Source height in pixels. */
103 [[nodiscard]] int height() const { return frameHeight; }
104 /** @brief Source frame rate, falling back to 30 fps when unknown. */
105 [[nodiscard]] double fps() const { return frameFps; }
106 /** @brief True when CUDA hardware decode is active. */
107 [[nodiscard]] bool using_hardware_decode() const { return hardwareDecode; }
108 /** @brief Selected CUDA hardware-decode device, or -1 for FFmpeg's default. */
109 [[nodiscard]] int hardware_decode_device() const { return hardwareDecodeDevice; }
110
111 private:
112 static AVPixelFormat chooseHwFormat(AVCodecContext *ctx, const AVPixelFormat *formats);
113 [[nodiscard]] AVPixelFormat selectHwFormat(const AVPixelFormat *formats) const;
114 bool initHardwareDevice(const AVCodec *decoder, int cuda_device);
115 bool decodeNextFrame();
116 bool convertFrameToRgba(const AVFrame *decodedFrame, std::vector<uint8_t> &rgba, int &width, int &height, int &pitch, bool flipY);
117#ifdef MXVK_CUDA
118 bool convertFrameToGpuRgba(const AVFrame *decodedFrame, cv::cuda::GpuMat &rgba, cv::cuda::Stream &stream, bool flipY);
119#endif
120 void flipRows(std::vector<uint8_t> &rgba, int pitch) const;
121
122 AVFormatContext *formatCtx = nullptr;
123 AVCodecContext *codecCtx = nullptr;
124 AVPacket *packet = nullptr;
125 AVFrame *frame = nullptr;
126 AVFrame *swFrame = nullptr;
127 AVBufferRef *hwDeviceCtx = nullptr;
128 SwsContext *swsCtx = nullptr;
129 int videoStream = -1;
130 int frameWidth = 0;
131 int frameHeight = 0;
132 double frameFps = 30.0;
133 AVPixelFormat hwPixFmt = AV_PIX_FMT_NONE;
134 bool hardwareDecode = false;
135 int hardwareDecodeDevice = -1;
136#ifdef MXVK_CUDA
137 cv::cuda::GpuMat gpuNv12{};
138 cv::cuda::GpuMat gpuRgb{};
139 cv::cuda::GpuMat gpuRgba{};
140 cv::cuda::GpuMat gpuFlippedRgba{};
141 cudaEvent_t decoder_surface_copy_event = nullptr;
142 bool decoder_surface_barrier_logged = false;
143#endif
144 };
145
146} // 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.
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