MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
FFmpegMuxContext.hpp
Go to the documentation of this file.
1#pragma once
2
3extern "C" {
4struct AVFormatContext;
5struct AVStream;
6struct AVPacket;
7}
8
9namespace MayaFlux::IO {
10
11/**
12 * @class FFmpegMuxContext
13 * @brief RAII owner of a single AVFormatContext on the write path.
14 *
15 * Encapsulates all format-level (container) FFmpeg mux operations:
16 * - Allocating an output context and opening the I/O layer (avio)
17 * - Writing the container header after all streams have been added
18 * - Writing interleaved encoded packets
19 * - Writing the container trailer and releasing all resources
20 *
21 * Does NOT own any codec context, resampler, scaler, or stream — those are
22 * domain-specific and belong to AudioEncodeContext / VideoEncodeContext, which
23 * each call avformat_new_stream() on this context during their own open().
24 *
25 * Stream contexts must be opened and fully configured before write_header()
26 * is called. Packets submitted via write_packet() must have stream_index and
27 * PTS/DTS set by the originating encode context.
28 *
29 * Not copyable or movable; always stack- or member-allocated inside the owner
30 * (SoundFileWriter worker thread, future VideoFileWriter worker thread).
31 *
32 * FFmpeg global initialisation is shared with FFmpegDemuxContext via the
33 * static FFmpegDemuxContext::init_ffmpeg() call.
34 */
35class MAYAFLUX_API FFmpegMuxContext {
36public:
37 FFmpegMuxContext() = default;
39
44
45 // =========================================================================
46 // Lifecycle
47 // =========================================================================
48
49 /**
50 * @brief Allocate an output context and open the avio layer for writing.
51 *
52 * Format is inferred from the filepath extension via
53 * avformat_alloc_output_context2. Pass explicit_format to override
54 * (e.g. "matroska" to force MKV regardless of extension).
55 *
56 * Does NOT write any data to disk. Call write_header() after all stream
57 * contexts have been opened on this mux context.
58 *
59 * @param filepath Output file path. Extension determines container.
60 * @param explicit_format FFmpeg short format name override; empty = infer.
61 * @return True on success; false sets the internal error string.
62 */
63 bool open(const std::string& filepath,
64 const std::string& explicit_format = {});
65
66 /**
67 * @brief Write the container trailer, flush avio, and release all resources.
68 *
69 * av_write_trailer is called only if write_header() previously succeeded.
70 * Safe to call multiple times or on a context that was never successfully
71 * opened.
72 */
73 void close();
74
75 /**
76 * @brief True if the context is open and ready to accept streams / packets.
77 */
78 [[nodiscard]] bool is_open() const { return format_context != nullptr; }
79
80 /**
81 * @brief True if write_header() completed successfully.
82 *
83 * Encode contexts may use this to assert sequencing: packets must not be
84 * submitted before the header is written.
85 */
86 [[nodiscard]] bool is_header_written() const { return m_header_written; }
87
88 // =========================================================================
89 // Stream registration
90 // =========================================================================
91
92 /**
93 * @brief Allocate a new AVStream inside this context.
94 *
95 * Called by AudioEncodeContext::open() and VideoEncodeContext::open()
96 * to add their respective streams before write_header().
97 *
98 * @return Pointer to the new AVStream, or nullptr on failure.
99 */
100 [[nodiscard]] AVStream* add_stream();
101
102 // =========================================================================
103 // Header / packet writing
104 // =========================================================================
105
106 /**
107 * @brief Write the container header to the output file.
108 *
109 * Must be called after all stream contexts (audio, video, subtitle, etc.)
110 * have been opened and have set their codec parameters on their AVStream.
111 * Exactly one call is valid per open(); calling twice is an error.
112 *
113 * @return True on success.
114 */
115 bool write_header();
116
117 /**
118 * @brief Submit one encoded packet for interleaved writing.
119 *
120 * Uses av_interleaved_write_frame, which buffers packets internally to
121 * preserve correct interleaving order for containers that require it
122 * (MP4, MKV). For single-stream audio-only containers (WAV, FLAC) this
123 * is equivalent to av_write_frame.
124 *
125 * The packet's stream_index, PTS, DTS, and duration must be set by the
126 * calling encode context before this call. Ownership of the packet data
127 * is transferred to FFmpeg; the caller must not reference pkt after return.
128 *
129 * @param pkt Encoded packet with all fields populated.
130 * @return True on success.
131 */
132 bool write_packet(AVPacket* pkt);
133
134 // =========================================================================
135 // Error
136 // =========================================================================
137
138 [[nodiscard]] const std::string& last_error() const { return m_last_error; }
139
140 // =========================================================================
141 // Raw handle — accessible to encode contexts for stream setup
142 // =========================================================================
143
144 AVFormatContext* format_context = nullptr; ///< Owned; freed in close().
145
146private:
147 bool m_header_written {};
148 std::string m_last_error;
149};
150
151} // namespace MayaFlux::IO
bool is_header_written() const
True if write_header() completed successfully.
bool is_open() const
True if the context is open and ready to accept streams / packets.
FFmpegMuxContext & operator=(FFmpegMuxContext &&)=delete
const std::string & last_error() const
FFmpegMuxContext(FFmpegMuxContext &&)=delete
FFmpegMuxContext(const FFmpegMuxContext &)=delete
FFmpegMuxContext & operator=(const FFmpegMuxContext &)=delete
RAII owner of a single AVFormatContext on the write path.