MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches

◆ open()

bool MayaFlux::IO::VideoEncodeContext::open ( FFmpegMuxContext mux,
uint32_t  width,
uint32_t  height,
double  frame_rate,
AVPixelFormat  src_pixel_format,
AVCodecID  codec_id 
)

Open the encoder and register a video stream in the mux context.

Selects the encoder: if codec_id is AV_CODEC_ID_NONE the container's default video codec is used (MP4/MKV -> H.264, WebM -> VP9, AVI -> MPEG4). Allocates AVCodecContext, initialises SwsContext converting from src_pixel_format to the encoder's required pixel format, allocates the scratch AVFrame, and copies codec parameters to the new AVStream.

Must be called after FFmpegMuxContext::open() and before FFmpegMuxContext::write_header().

Parameters
muxOpen mux context that will own the output stream.
widthFrame width in pixels.
heightFrame height in pixels.
frame_rateAverage frame rate in frames per second.
src_pixel_formatSource AVPixelFormat delivered by the readback thread.
codec_idEncoder override; AV_CODEC_ID_NONE = container default.
Returns
True on success; false sets the internal error string.

< let encoder decide from crf

Definition at line 106 of file VideoEncodeContext.cpp.

112{
113 close();
114
115 if (!mux.is_open()) {
116 m_last_error = "VideoEncodeContext::open: mux context is not open";
117 return false;
118 }
119
120 if (width == 0 || height == 0 || frame_rate <= 0.0) {
121 m_last_error = "VideoEncodeContext::open: invalid dimensions or frame rate";
122 return false;
123 }
124
125 m_width = width;
127 m_src_src_bpp = bpp_for_format(src_pixel_format);
128 m_src_pixel_fmt = src_pixel_format;
129 m_src_pixel_fmt = src_pixel_format;
130
131 if (codec_id == AV_CODEC_ID_NONE)
132 codec_id = infer_video_codec(mux.format_context);
133
134 const AVCodec* codec = avcodec_find_encoder(codec_id);
135 if (!codec) {
136 m_last_error = std::string("avcodec_find_encoder failed for codec_id=")
137 + std::to_string(static_cast<int>(codec_id));
138 return false;
139 }
140
141 codec_context = avcodec_alloc_context3(codec);
142 if (!codec_context) {
143 m_last_error = "avcodec_alloc_context3 failed";
144 return false;
145 }
146
147 ///< H.264/H.265 require dimensions divisible by 2
148 codec_context->width = static_cast<int>(width % 2 == 0 ? width : width - 1);
149 codec_context->height = static_cast<int>(height % 2 == 0 ? height : height - 1);
150
151 /*
152 * Convert double fps to AVRational. Use millisecond time_base so fractional
153 * rates (23.976, 29.97, 59.94) round-trip without drift.
154 */
155 const int fps_num = static_cast<int>(std::round(frame_rate * 1000.0));
156 codec_context->framerate = { .num = fps_num, .den = 1000 };
157 codec_context->time_base = { .num = 1000, .den = fps_num };
158
159 /*
160 * YUV420P is the universally supported pixel format for H.264/H.265.
161 * VP9 and MPEG4 also accept it. For codecs that require a different native
162 * format, callers must pass an appropriate codec_id and the caller-side
163 * src_pixel_format. The sws_scale below handles any conversion.
164 */
165 codec_context->pix_fmt = AV_PIX_FMT_YUV420P;
166
167 /*
168 *Reasonable quality defaults — not tunable here; callers set codec options
169 * via AVDictionary on codec_context before open() returns if needed.
170 */
171 codec_context->bit_rate = 0; ///< let encoder decide from crf
172 if (codec_id == AV_CODEC_ID_H264 || codec_id == AV_CODEC_ID_H265) {
173 av_opt_set(codec_context->priv_data, "preset", "fast", 0);
174 av_opt_set(codec_context->priv_data, "crf", "23", 0);
175 }
176
177 if (mux.format_context->oformat->flags & AVFMT_GLOBALHEADER)
178 codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
179
180 if (avcodec_open2(codec_context, codec, nullptr) < 0) {
181 m_last_error = "avcodec_open2 failed";
182 close();
183 return false;
184 }
185
186 m_stream = mux.add_stream();
187 if (!m_stream) {
188 m_last_error = "FFmpegMuxContext::add_stream returned nullptr";
189 close();
190 return false;
191 }
192
193 if (avcodec_parameters_from_context(m_stream->codecpar, codec_context) < 0) {
194 m_last_error = "avcodec_parameters_from_context failed";
195 close();
196 return false;
197 }
198
199 m_stream->time_base = codec_context->time_base;
200 m_stream_index = m_stream->index;
201
202 // -------------------------------------------------------------------------
203 // SwsContext: source format -> YUV420P
204 // -------------------------------------------------------------------------
205 sws_context = sws_getContext(
206 codec_context->width,
207 codec_context->height,
208 src_pixel_format,
209 codec_context->width,
210 codec_context->height,
211 codec_context->pix_fmt,
212 SWS_BILINEAR,
213 nullptr, nullptr, nullptr);
214
215 if (!sws_context) {
216 m_last_error = "sws_getContext failed";
217 close();
218 return false;
219 }
220
221 // -------------------------------------------------------------------------
222 // Scratch frame for sws_scale output
223 // -------------------------------------------------------------------------
224 m_scratch_frame = av_frame_alloc();
225 if (!m_scratch_frame) {
226 m_last_error = "av_frame_alloc failed";
227 close();
228 return false;
229 }
230
231 m_scratch_frame->format = codec_context->pix_fmt;
232 m_scratch_frame->width = codec_context->width;
233 m_scratch_frame->height = codec_context->height;
234
235 if (av_frame_get_buffer(m_scratch_frame, 32) < 0) {
236 m_last_error = "av_frame_get_buffer failed";
237 close();
238 return false;
239 }
240
242 "[VideoEncodeContext] open: {}x{} @ {:.3f} fps | src={} enc={} stream#{}",
243 codec_context->width, codec_context->height, frame_rate,
244 av_get_pix_fmt_name(src_pixel_format) ? av_get_pix_fmt_name(src_pixel_format) : "unknown",
245 avcodec_get_name(codec_id),
247
248 return true;
249}
#define MF_INFO(comp, ctx,...)
AVStream * m_stream
Weak ref into FFmpegMuxContext; not owned.
AVFrame * m_scratch_frame
Owned scratch buffer for encoder input.
void close()
Release all owned resources.
SwsContext * sws_context
Owned; freed in destructor.
AVCodecContext * codec_context
Owned; freed in destructor.
@ FileIO
Filesystem I/O operations.
@ IO
Networking, file handling, streaming.

References MayaFlux::IO::FFmpegMuxContext::add_stream(), close(), codec_context, MayaFlux::Journal::FileIO, MayaFlux::IO::FFmpegMuxContext::format_context, height(), MayaFlux::Journal::IO, MayaFlux::IO::FFmpegMuxContext::is_open(), m_height, m_last_error, m_scratch_frame, m_src_pixel_fmt, m_src_src_bpp, m_stream, m_stream_index, m_width, MF_INFO, sws_context, and width().

Referenced by MayaFlux::IO::VideoFileWriter::worker_loop().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: