1extern crate ffmpeg_next as ffmpeg;
2
3use ffmpeg::codec::codec::Codec as AvCodec;
4use ffmpeg::codec::encoder::video::Encoder as AvEncoder;
5use ffmpeg::codec::encoder::video::Video as AvVideo;
6use ffmpeg::codec::flag::Flags as AvCodecFlags;
7use ffmpeg::codec::packet::Packet as AvPacket;
8use ffmpeg::codec::{Context as AvContext, Id as AvCodecId};
9use ffmpeg::format::flag::Flags as AvFormatFlags;
10use ffmpeg::software::scaling::context::Context as AvScaler;
11use ffmpeg::software::scaling::flag::Flags as AvScalerFlags;
12use ffmpeg::util::error::EAGAIN;
13use ffmpeg::util::format::Pixel as AvPixel;
14use ffmpeg::util::mathematics::rescale::TIME_BASE;
15use ffmpeg::util::picture::Type as AvFrameType;
16use ffmpeg::Error as AvError;
17use ffmpeg::Rational as AvRational;
18
19use crate::error::Error;
20use crate::ffi;
21#[cfg(feature = "ndarray")]
22use crate::frame::Frame;
23use crate::frame::{PixelFormat, RawFrame, FRAME_PIXEL_FORMAT};
24use crate::io::private::Write;
25use crate::io::{Writer, WriterBuilder};
26use crate::location::Location;
27use crate::options::Options;
28#[cfg(feature = "ndarray")]
29use crate::time::Time;
30
31type Result<T> = std::result::Result<T, Error>;
32
33pub struct EncoderBuilder<'a> {
35 destination: Location,
36 settings: Settings,
37 options: Option<&'a Options>,
38 format: Option<&'a str>,
39 interleaved: bool,
40}
41
42impl<'a> EncoderBuilder<'a> {
43 pub fn new(destination: impl Into<Location>, settings: Settings) -> Self {
48 Self {
49 destination: destination.into(),
50 settings,
51 options: None,
52 format: None,
53 interleaved: false,
54 }
55 }
56
57 pub fn with_options(mut self, options: &'a Options) -> Self {
63 self.options = Some(options);
64 self
65 }
66
67 pub fn with_format(mut self, format: &'a str) -> Self {
73 self.format = Some(format);
74 self
75 }
76
77 pub fn interleaved(mut self) -> Self {
80 self.interleaved = true;
81 self
82 }
83
84 pub fn build(self) -> Result<Encoder> {
86 let mut writer_builder = WriterBuilder::new(self.destination);
87 if let Some(options) = self.options {
88 writer_builder = writer_builder.with_options(options);
89 }
90 if let Some(format) = self.format {
91 writer_builder = writer_builder.with_format(format);
92 }
93 Encoder::from_writer(writer_builder.build()?, self.interleaved, self.settings)
94 }
95}
96
97pub struct Encoder {
118 writer: Writer,
119 writer_stream_index: usize,
120 encoder: AvEncoder,
121 encoder_time_base: AvRational,
122 keyframe_interval: u64,
123 interleaved: bool,
124 scaler: AvScaler,
125 scaler_width: u32,
126 scaler_height: u32,
127 frame_count: u64,
128 have_written_header: bool,
129 have_written_trailer: bool,
130}
131
132impl Encoder {
133 #[inline]
138 pub fn new(destination: impl Into<Location>, settings: Settings) -> Result<Self> {
139 EncoderBuilder::new(destination, settings).build()
140 }
141
142 #[cfg(feature = "ndarray")]
150 pub fn encode(&mut self, frame: &Frame, source_timestamp: Time) -> Result<()> {
151 let (height, width, channels) = frame.dim();
152 if height != self.scaler_height as usize
153 || width != self.scaler_width as usize
154 || channels != 3
155 {
156 return Err(Error::InvalidFrameFormat);
157 }
158
159 let mut frame = ffi::convert_ndarray_to_frame_rgb24(frame).map_err(Error::BackendError)?;
160
161 frame.set_pts(
162 source_timestamp
163 .aligned_with_rational(self.encoder_time_base)
164 .into_value(),
165 );
166
167 self.encode_raw(frame)
168 }
169
170 pub fn encode_raw(&mut self, frame: RawFrame) -> Result<()> {
176 if frame.width() != self.scaler_width
177 || frame.height() != self.scaler_height
178 || frame.format() != FRAME_PIXEL_FORMAT
179 {
180 return Err(Error::InvalidFrameFormat);
181 }
182
183 if !self.have_written_header {
185 self.writer.write_header()?;
186 self.have_written_header = true;
187 }
188
189 let mut frame = self.scale(frame)?;
191 if self.frame_count.is_multiple_of(self.keyframe_interval) {
193 frame.set_kind(AvFrameType::I);
194 }
195
196 self.encoder
197 .send_frame(&frame)
198 .map_err(Error::BackendError)?;
199 self.frame_count += 1;
202
203 if let Some(packet) = self.encoder_receive_packet()? {
204 self.write(packet)?;
205 }
206
207 Ok(())
208 }
209
210 pub fn finish(&mut self) -> Result<()> {
217 if self.have_written_header && !self.have_written_trailer {
218 self.have_written_trailer = true;
219 self.flush()?;
220 self.writer.write_trailer()?;
221 }
222
223 Ok(())
224 }
225
226 #[inline]
228 pub fn time_base(&self) -> AvRational {
229 self.encoder_time_base
230 }
231
232 fn from_writer(mut writer: Writer, interleaved: bool, settings: Settings) -> Result<Self> {
240 let global_header = writer
241 .output
242 .format()
243 .flags()
244 .contains(AvFormatFlags::GLOBAL_HEADER);
245
246 let mut writer_stream = writer.output.add_stream(settings.codec())?;
247 let writer_stream_index = writer_stream.index();
248
249 let mut encoder_context = match settings.codec() {
250 Some(codec) => ffi::codec_context_as(&codec)?,
251 None => AvContext::new(),
252 };
253
254 if global_header {
257 encoder_context.set_flags(AvCodecFlags::GLOBAL_HEADER);
258 }
259
260 let mut encoder = encoder_context.encoder().video()?;
261 settings.apply_to(&mut encoder);
262
263 encoder.set_time_base(TIME_BASE);
266
267 let encoder = encoder.open_with(settings.options().to_dict())?;
268 let encoder_time_base = ffi::get_encoder_time_base(&encoder);
269
270 writer_stream.set_parameters(&encoder);
271
272 let scaler_width = encoder.width();
273 let scaler_height = encoder.height();
274 let scaler = AvScaler::get(
275 FRAME_PIXEL_FORMAT,
276 scaler_width,
277 scaler_height,
278 encoder.format(),
279 scaler_width,
280 scaler_height,
281 AvScalerFlags::empty(),
282 )?;
283
284 Ok(Self {
285 writer,
286 writer_stream_index,
287 encoder,
288 encoder_time_base,
289 keyframe_interval: settings.keyframe_interval,
290 interleaved,
291 scaler,
292 scaler_width,
293 scaler_height,
294 frame_count: 0,
295 have_written_header: false,
296 have_written_trailer: false,
297 })
298 }
299
300 fn scale(&mut self, frame: RawFrame) -> Result<RawFrame> {
307 let mut frame_scaled = RawFrame::empty();
308 self.scaler
309 .run(&frame, &mut frame_scaled)
310 .map_err(Error::BackendError)?;
311 frame_scaled.set_pts(frame.pts());
313
314 Ok(frame_scaled)
315 }
316
317 fn encoder_receive_packet(&mut self) -> Result<Option<AvPacket>> {
320 let mut packet = AvPacket::empty();
321 let encode_result = self.encoder.receive_packet(&mut packet);
322 match encode_result {
323 Ok(()) => Ok(Some(packet)),
324 Err(AvError::Other { errno }) if errno == EAGAIN => Ok(None),
325 Err(err) => Err(err.into()),
326 }
327 }
328
329 fn stream_time_base(&mut self) -> AvRational {
331 self.writer
332 .output
333 .stream(self.writer_stream_index)
334 .unwrap()
335 .time_base()
336 }
337
338 fn write(&mut self, mut packet: AvPacket) -> Result<()> {
344 packet.set_stream(self.writer_stream_index);
345 packet.set_position(-1);
346 packet.rescale_ts(self.encoder_time_base, self.stream_time_base());
347 if self.interleaved {
348 self.writer.write_interleaved(&mut packet)?;
349 } else {
350 self.writer.write(&mut packet)?;
351 };
352
353 Ok(())
354 }
355
356 fn flush(&mut self) -> Result<()> {
358 const MAX_DRAIN_ITERATIONS: u32 = 100;
361
362 self.encoder.send_eof()?;
364
365 for _ in 0..MAX_DRAIN_ITERATIONS {
367 match self.encoder_receive_packet() {
368 Ok(Some(packet)) => self.write(packet)?,
369 Ok(None) => continue,
370 Err(_) => break,
371 }
372 }
373
374 Ok(())
375 }
376}
377
378impl Drop for Encoder {
379 fn drop(&mut self) {
380 let _ = self.finish();
381 }
382}
383
384#[derive(Debug, Clone)]
386pub struct Settings {
387 width: u32,
388 height: u32,
389 pixel_format: AvPixel,
390 keyframe_interval: u64,
391 options: Options,
392}
393
394impl Settings {
395 const KEY_FRAME_INTERVAL: u64 = 12;
397
398 const FRAME_RATE: i32 = 30;
401
402 pub fn preset_h264_yuv420p(width: usize, height: usize, realtime: bool) -> Settings {
406 let options = if realtime {
407 Options::preset_h264_realtime()
408 } else {
409 Options::preset_h264()
410 };
411
412 Self {
413 width: width as u32,
414 height: height as u32,
415 pixel_format: AvPixel::YUV420P,
416 keyframe_interval: Self::KEY_FRAME_INTERVAL,
417 options,
418 }
419 }
420
421 pub fn preset_h264_custom(
436 width: usize,
437 height: usize,
438 pixel_format: PixelFormat,
439 options: Options,
440 ) -> Settings {
441 Self {
442 width: width as u32,
443 height: height as u32,
444 pixel_format,
445 keyframe_interval: Self::KEY_FRAME_INTERVAL,
446 options,
447 }
448 }
449
450 pub fn set_keyframe_interval(&mut self, keyframe_interval: u64) {
452 self.keyframe_interval = keyframe_interval;
453 }
454
455 pub fn with_keyframe_interval(mut self, keyframe_interval: u64) -> Self {
457 self.set_keyframe_interval(keyframe_interval);
458 self
459 }
460
461 fn apply_to(&self, encoder: &mut AvVideo) {
471 encoder.set_width(self.width);
472 encoder.set_height(self.height);
473 encoder.set_format(self.pixel_format);
474 encoder.set_frame_rate(Some((Self::FRAME_RATE, 1)));
475 }
476
477 fn codec(&self) -> Option<AvCodec> {
479 Some(
482 ffmpeg::encoder::find_by_name("libx264")
483 .unwrap_or(ffmpeg::encoder::find(AvCodecId::H264)?),
484 )
485 }
486
487 fn options(&self) -> &Options {
489 &self.options
490 }
491}
492
493unsafe impl Send for Encoder {}
494unsafe impl Sync for Encoder {}