Skip to main content

ffmpeg_pipeline/
lib.rs

1//! Composable decoding, encoding, remuxing, scaling, resampling, and media I/O
2//! built on FFmpeg.
3
4mod audio;
5mod decode;
6mod encode;
7mod io;
8mod parse;
9mod remux;
10mod result;
11mod scaler;
12mod types;
13
14pub(crate) use audio::decoder_channel_layout;
15pub use audio::{transcode_audio_buffer, AudioSpec, AutoAudioBuffer, Resampler};
16pub use decode::{Decoder, Frame, FrameProcess};
17pub use encode::{EncodeParams, Encoder};
18pub use io::{
19    input_buffer, input_buffer_with_format, input_buffer_with_format_options, input_file,
20    input_reader, output_buffer, output_file, output_writer, read_attachment,
21};
22pub use parse::{parse_stream_info, parse_video_group};
23pub use remux::{remux, RemuxRequest, RemuxStream};
24pub use result::{FFmpegError, FFmpegResult};
25pub use scaler::{Scaler, ScalingAlgorithm};
26pub use types::{
27    AudioFrame, ChannelLayout, CodecId, FrameCalculation, FrameSize, Input, MediaType, Output,
28    Rational, Sample, SampleType, Stream, StreamDecoder, StreamEncoder, StreamFormat, StreamFrame,
29    VideoFrame, VideoGroups, VideoInfo, VideoPixel,
30};
31
32use ffmpeg_next::{
33    ffi::{AV_LOG_ERROR, AV_LOG_INFO, AV_LOG_TRACE, AV_LOG_WARNING},
34    sys::{av_log_set_level, AV_LOG_DEBUG},
35};
36use log::{debug, error};
37use std::{path::Path, time::Instant};
38
39pub fn initialize(level: log::Level) -> Result<(), ffmpeg_next::Error> {
40    let level = match level {
41        log::Level::Error => AV_LOG_ERROR,
42        log::Level::Warn => AV_LOG_WARNING,
43        log::Level::Info => AV_LOG_INFO,
44        log::Level::Debug => AV_LOG_DEBUG,
45        log::Level::Trace => AV_LOG_TRACE,
46    };
47    unsafe { av_log_set_level(level) }
48    ffmpeg_next::init()
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54    use ffmpeg_next::codec::Id;
55    use rav1e::prelude::{ChromaSampling, Config, Context, EncoderConfig, EncoderStatus};
56    use std::io::Cursor;
57
58    pub(crate) fn encoded_ogg() -> Vec<u8> {
59        let mut output = output_buffer("ogg").unwrap();
60        {
61            let mut encoder = Encoder::new(
62                output.as_mut(),
63                Id::OPUS,
64                EncodeParams::default()
65                    .with_bitrate(64 * 1024)
66                    .with_vbr(true),
67            )
68            .unwrap();
69            encoder.write_header().unwrap();
70            let (format, samples, layout, rate) = match encoder.get_encoder() {
71                StreamEncoder::Audio(encoder) => (
72                    encoder.format(),
73                    encoder.frame_size() as usize,
74                    encoder.channel_layout(),
75                    encoder.rate(),
76                ),
77                StreamEncoder::Video(_) => panic!("unexpected video encoder"),
78            };
79            for index in 0..4 {
80                let mut frame = AudioFrame::new(format, samples, layout);
81                frame.set_rate(rate);
82                frame.set_pts(Some((index * samples) as i64));
83                for plane in 0..frame.planes() {
84                    frame.data_mut(plane).fill(0);
85                }
86                encoder.send_frame(&StreamFrame::Audio(frame)).unwrap();
87                encoder.encode_frame().unwrap();
88            }
89            encoder.send_frame(&StreamFrame::Eof).unwrap();
90            encoder.encode_frame().unwrap();
91        }
92        output.into_inner::<Cursor<Vec<u8>>>().unwrap().into_inner()
93    }
94
95    pub(crate) fn encoded_ivf(frame_count: usize) -> Vec<u8> {
96        let mut encoder = EncoderConfig::with_speed_preset(10);
97        encoder.width = 16;
98        encoder.height = 16;
99        encoder.chroma_sampling = ChromaSampling::Cs420;
100        encoder.low_latency = false;
101        encoder.min_key_frame_interval = 4;
102        encoder.max_key_frame_interval = 4;
103        let config = Config::new().with_encoder_config(encoder).with_threads(1);
104        let mut context: Context<u8> = config.new_context().unwrap();
105        for index in 0..frame_count {
106            let mut frame = context.new_frame();
107            frame.planes[0].data_origin_mut().fill((index * 16) as u8);
108            frame.planes[1].data_origin_mut().fill(128);
109            frame.planes[2].data_origin_mut().fill(128);
110            context.send_frame(frame).unwrap();
111        }
112        context.flush();
113        let mut packets = Vec::new();
114        loop {
115            match context.receive_packet() {
116                Ok(packet) => packets.push((packet.input_frameno, packet.data)),
117                Err(EncoderStatus::Encoded | EncoderStatus::NeedMoreData) => continue,
118                Err(EncoderStatus::LimitReached) => break,
119                Err(error) => panic!("rav1e fixture failed: {error}"),
120            }
121        }
122
123        let mut ivf = Vec::new();
124        ivf.extend_from_slice(b"DKIF");
125        ivf.extend_from_slice(&0_u16.to_le_bytes());
126        ivf.extend_from_slice(&32_u16.to_le_bytes());
127        ivf.extend_from_slice(b"AV01");
128        ivf.extend_from_slice(&16_u16.to_le_bytes());
129        ivf.extend_from_slice(&16_u16.to_le_bytes());
130        ivf.extend_from_slice(&30_u32.to_le_bytes());
131        ivf.extend_from_slice(&1_u32.to_le_bytes());
132        ivf.extend_from_slice(&(packets.len() as u32).to_le_bytes());
133        ivf.extend_from_slice(&0_u32.to_le_bytes());
134        for (timestamp, packet) in packets {
135            ivf.extend_from_slice(&(packet.len() as u32).to_le_bytes());
136            ivf.extend_from_slice(&timestamp.to_le_bytes());
137            ivf.extend_from_slice(&packet);
138        }
139        ivf
140    }
141}