MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
AudioEncodeContext.hpp
Go to the documentation of this file.
1#pragma once
2
4
5extern "C" {
6#include <libavcodec/avcodec.h>
7struct AVAudioFifo;
8struct AVStream;
9struct SwrContext;
10}
11
12namespace MayaFlux::IO {
13
14/**
15 * @class AudioEncodeContext
16 * @brief RAII owner of one audio stream's encoder, resampler, and sample FIFO.
17 *
18 * Encapsulates all audio-stream-specific FFmpeg objects on the write path:
19 * - AVCodecContext for the selected or inferred encoder
20 * - SwrContext converting AV_SAMPLE_FMT_DBL (engine canonical) to the encoder's
21 * native sample format
22 * - AVAudioFifo absorbing arbitrary-size input chunks and emitting fixed-size
23 * frames required by block-aligned encoders (AAC: 1024, Vorbis: variable)
24 * - AVStream registered inside the supplied FFmpegMuxContext
25 *
26 * Does NOT own AVFormatContext — that belongs to FFmpegMuxContext.
27 *
28 * Destruction order (enforced in destructor):
29 * fifo → swr_context → codec_context
30 * The associated FFmpegMuxContext must outlive this object.
31 *
32 * Open sequence:
33 * 1. FFmpegMuxContext::open()
34 * 2. AudioEncodeContext::open() ← adds stream, configures codec+swr+fifo
35 * 3. FFmpegMuxContext::write_header()
36 * 4. encode_frames() loop
37 * 5. drain() ← flushes fifo remainder + encoder delay
38 * 6. FFmpegMuxContext::close() ← writes trailer
39 */
40class MAYAFLUX_API AudioEncodeContext {
41public:
42 AudioEncodeContext() = default;
44
49
50 // =========================================================================
51 // Lifecycle
52 // =========================================================================
53
54 /**
55 * @brief Open the encoder and register an audio stream in the mux context.
56 *
57 * Selects the encoder: if codec_id is AV_CODEC_ID_NONE the container's
58 * default audio codec is used (WAV → PCM_S16LE, MP4/MKV → AAC,
59 * OGG → Vorbis, FLAC → FLAC). Allocates and opens AVCodecContext,
60 * copies parameters to the new AVStream, initialises SwrContext
61 * (AV_SAMPLE_FMT_DBL → encoder native format), and allocates AVAudioFifo
62 * sized to two encoder frames.
63 *
64 * Must be called after FFmpegMuxContext::open() and before
65 * FFmpegMuxContext::write_header().
66 *
67 * @param mux Open mux context that will own the output stream.
68 * @param sample_rate PCM sample rate in Hz.
69 * @param channels Number of interleaved channels.
70 * @param codec_id Encoder override; AV_CODEC_ID_NONE = container default.
71 * @return True on success; false sets the internal error string.
72 */
73 bool open(FFmpegMuxContext& mux,
74 uint32_t sample_rate,
75 uint32_t channels,
76 AVCodecID codec_id);
77
78 /**
79 * @brief Release all owned resources.
80 * Safe to call multiple times or on a context that never opened.
81 */
82 void close();
83
84 /**
85 * @brief True if codec, resampler, and FIFO are all ready.
86 */
87 [[nodiscard]] bool is_valid() const
88 {
89 return codec_context && swr_context && fifo && m_stream_index >= 0;
90 }
91
92 // =========================================================================
93 // Encoding
94 // =========================================================================
95
96 /**
97 * @brief Encode a block of interleaved double-precision PCM frames.
98 *
99 * Converts input via SwrContext, writes converted samples into the FIFO,
100 * then drains the FIFO in encoder-frame-sized chunks. For encoders with
101 * frame_size == 0 (PCM, some raw formats) the entire FIFO content is
102 * submitted as one frame per call.
103 *
104 * Non-blocking: returns false only on a hard encode error, not on FIFO
105 * underrun. Safe to call with any number of frames per call.
106 *
107 * @param interleaved Interleaved samples in double precision.
108 * @param num_frames Number of PCM frames (samples / channels).
109 * @param mux Mux context to receive encoded packets.
110 * @return True on success.
111 */
112 bool encode_frames(std::span<const double> interleaved,
113 uint32_t num_frames,
114 FFmpegMuxContext& mux);
115
116 /**
117 * @brief Flush the FIFO remainder and encoder internal delay to the mux.
118 *
119 * Pads the final partial FIFO frame with silence if needed, sends it,
120 * then sends a null frame to signal EOS to the encoder and drains all
121 * buffered output packets. Call once before FFmpegMuxContext::close().
122 *
123 * @param mux Mux context to receive remaining packets.
124 * @return True if all remaining packets were written successfully.
125 */
126 bool drain(FFmpegMuxContext& mux);
127
128 // =========================================================================
129 // Error
130 // =========================================================================
131
132 [[nodiscard]] const std::string& last_error() const { return m_last_error; }
133
134 // =========================================================================
135 // Owned handles
136 // =========================================================================
137
138 AVCodecContext* codec_context {}; ///< Owned; freed in destructor.
139 SwrContext* swr_context {}; ///< Owned; freed in destructor.
140 AVAudioFifo* fifo {}; ///< Owned; freed in destructor.
141 AVStream* stream {}; ///< Owned by mux; pointer cached here.
142
143 int m_stream_index { -1 };
144 uint32_t m_sample_rate {};
145 uint32_t m_channels {};
146
147private:
148 int64_t m_pts = 0;
149 std::string m_last_error;
150
151 bool setup_resampler();
152 bool setup_fifo();
153
154 /**
155 * @brief Pull one frame from the FIFO and send it to the encoder.
156 * If the FIFO has fewer samples than frame_size, pads with silence.
157 * Drains all output packets into the mux after sending.
158 */
159 bool send_fifo_frame(FFmpegMuxContext& mux, bool pad_to_frame_size);
160
161 /**
162 * @brief Drain all packets currently available from the encoder into mux.
163 */
164 bool drain_packets(FFmpegMuxContext& mux);
165};
166
167} // namespace MayaFlux::IO
Core::GlobalStreamInfo stream
Definition Config.cpp:34
const std::string & last_error() const
bool is_valid() const
True if codec, resampler, and FIFO are all ready.
AudioEncodeContext(const AudioEncodeContext &)=delete
AudioEncodeContext(AudioEncodeContext &&)=delete
AudioEncodeContext & operator=(AudioEncodeContext &&)=delete
AudioEncodeContext & operator=(const AudioEncodeContext &)=delete
RAII owner of one audio stream's encoder, resampler, and sample FIFO.
RAII owner of a single AVFormatContext on the write path.