MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
VideoEncodeContext.hpp
Go to the documentation of this file.
1#pragma once
2
4
5extern "C" {
6#include <libavcodec/avcodec.h>
7struct AVStream;
8struct SwsContext;
9}
10
11namespace MayaFlux::IO {
12
13/**
14 * @class VideoEncodeContext
15 * @brief RAII owner of one video stream's encoder and pixel-format converter on the write path.
16 *
17 * Encapsulates all video-stream-specific FFmpeg objects:
18 * - AVCodecContext for the selected or inferred encoder
19 * - SwsContext converting from the source pixel format (e.g. AV_PIX_FMT_BGRA, as
20 * delivered by the Vulkan swapchain readback) to the encoder's required format
21 * (typically AV_PIX_FMT_YUV420P for H.264/H.265)
22 * - AVFrame scratch buffer for sws_scale output
23 * - Monotonically increasing PTS counter
24 *
25 * Does NOT own AVFormatContext — that belongs to FFmpegMuxContext.
26 *
27 * Open sequence:
28 * 1. FFmpegMuxContext::open()
29 * 2. VideoEncodeContext::open() — adds stream, configures codec + sws
30 * 3. FFmpegMuxContext::write_header()
31 * 4. encode_frame() loop
32 * 5. drain() — flushes encoder delay
33 * 6. FFmpegMuxContext::close() — writes trailer
34 *
35 * The source pixel format passed to open() must match the format delivered
36 * to every subsequent encode_frame() call. Swapchain BGRA readbacks map to
37 * AV_PIX_FMT_BGRA; RGBA readbacks to AV_PIX_FMT_RGBA.
38 *
39 * Not copyable or movable; always stack- or member-allocated inside the owner
40 * (VideoFileWriter worker thread).
41 *
42 * The associated FFmpegMuxContext must outlive this object.
43 */
44class MAYAFLUX_API VideoEncodeContext {
45public:
46 VideoEncodeContext() = default;
48
53
54 // =========================================================================
55 // Lifecycle
56 // =========================================================================
57
58 /**
59 * @brief Open the encoder and register a video stream in the mux context.
60 *
61 * Selects the encoder: if codec_id is AV_CODEC_ID_NONE the container's
62 * default video codec is used (MP4/MKV -> H.264, WebM -> VP9, AVI -> MPEG4).
63 * Allocates AVCodecContext, initialises SwsContext converting from
64 * src_pixel_format to the encoder's required pixel format, allocates the
65 * scratch AVFrame, and copies codec parameters to the new AVStream.
66 *
67 * Must be called after FFmpegMuxContext::open() and before
68 * FFmpegMuxContext::write_header().
69 *
70 * @param mux Open mux context that will own the output stream.
71 * @param width Frame width in pixels.
72 * @param height Frame height in pixels.
73 * @param frame_rate Average frame rate in frames per second.
74 * @param src_pixel_format Source AVPixelFormat delivered by the readback thread.
75 * @param codec_id Encoder override; AV_CODEC_ID_NONE = container default.
76 * @return True on success; false sets the internal error string.
77 */
78 bool open(FFmpegMuxContext& mux,
79 uint32_t width,
80 uint32_t height,
81 double frame_rate,
82 AVPixelFormat src_pixel_format,
83 AVCodecID codec_id);
84
85 /**
86 * @brief Release all owned resources.
87 * Safe to call multiple times or on a context that never opened.
88 */
89 void close();
90
91 /**
92 * @brief True if codec, scaler, and scratch frame are all ready.
93 */
94 [[nodiscard]] bool is_valid() const
95 {
96 return codec_context && sws_context && m_scratch_frame && m_stream_index >= 0;
97 }
98
99 // =========================================================================
100 // Encoding
101 // =========================================================================
102
103 /**
104 * @brief Encode one raw pixel frame into the mux context.
105 *
106 * Converts src_data from the source pixel format to the encoder's required
107 * format via SwsContext, stamps the monotonic PTS, and submits the frame
108 * to the encoder. Drains any available packets to the mux immediately.
109 *
110 * src_data must be a packed, row-major image of exactly width * height *
111 * bytes_per_pixel(src_pixel_format) bytes as delivered by the swapchain
112 * readback. No stride padding is expected; the source linesize is computed
113 * as width * bytes_per_pixel.
114 *
115 * Non-blocking with respect to the observer thread: this runs exclusively
116 * on the VideoFileWriter worker thread.
117 *
118 * @param src_data Pointer to the first byte of the packed source image.
119 * @param src_size Byte count of src_data; must equal width * height * bpp.
120 * @param mux Mux context to receive encoded packets.
121 * @return True on success.
122 */
123 bool encode_frame(const uint8_t* src_data,
124 size_t src_size,
125 uint32_t src_width,
126 uint32_t src_height,
127 FFmpegMuxContext& mux);
128
129 /**
130 * @brief Flush all buffered frames from the encoder to the mux.
131 *
132 * Sends a null frame to signal EOS to the encoder and drains all remaining
133 * output packets. Call once before FFmpegMuxContext::close().
134 *
135 * @param mux Mux context to receive remaining packets.
136 * @return True if all remaining packets were written successfully.
137 */
138 bool drain(FFmpegMuxContext& mux);
139
140 // =========================================================================
141 // Error
142 // =========================================================================
143
144 [[nodiscard]] const std::string& last_error() const { return m_last_error; }
145
146 // =========================================================================
147 // Owned handles
148 // =========================================================================
149
150 AVCodecContext* codec_context {}; ///< Owned; freed in destructor.
151 SwsContext* sws_context {}; ///< Owned; freed in destructor.
152
153 [[nodiscard]] uint32_t width() const { return m_width; }
154 [[nodiscard]] uint32_t height() const { return m_height; }
155
156private:
157 AVStream* m_stream {}; ///< Weak ref into FFmpegMuxContext; not owned.
158 AVFrame* m_scratch_frame {}; ///< Owned scratch buffer for encoder input.
159 int64_t m_pts {};
160 int m_stream_index { -1 };
161 uint32_t m_width {};
162 uint32_t m_height {};
163 int m_src_src_bpp { 4 };
164 AVPixelFormat m_src_pixel_fmt { AV_PIX_FMT_BGRA };
165 int m_cached_src_width { -1 };
166 int m_cached_src_height { -1 };
167
168 std::string m_last_error;
169
170 bool drain_packets(FFmpegMuxContext& mux);
171};
172
173} // namespace MayaFlux::IO
uint32_t width
Definition Decoder.cpp:59
RAII owner of a single AVFormatContext on the write path.
VideoEncodeContext(VideoEncodeContext &&)=delete
const std::string & last_error() const
bool is_valid() const
True if codec, scaler, and scratch frame are all ready.
VideoEncodeContext(const VideoEncodeContext &)=delete
VideoEncodeContext & operator=(const VideoEncodeContext &)=delete
VideoEncodeContext & operator=(VideoEncodeContext &&)=delete
RAII owner of one video stream's encoder and pixel-format converter on the write path.