Expand description
A crate designed to provide a simple interface to the native ffmpeg c-bindings.
See the changelog for a full release history.
§Feature flags
channel
— Enables channel support for IOtokio-channel
— Enables tokio channel supportcrossbeam-channel
— Enables crossbeam-channel supporttracing
— Enables tracing supportlink_system_ffmpeg
(enabled by default) — Links ffmpeg via systemlink_vcpkg_ffmpeg
— Links ffmpeg via vcpkgdocs
— Enables changelog and documentation of feature flags
§Why do we need this?
This crate aims to provide a simple-safe interface to the native ffmpeg c-bindings.
Currently this crate only supports the latest versions of ffmpeg (7.x.x).
§How is this different from other ffmpeg crates?
The other main ffmpeg crate is ffmpeg-next.
This crate adds a few features and has a safer API. Notably it adds the ability to provide an in-memory decode / encode buffer.
§Examples
§Decoding a audio/video file
// 1. Store the input of the file from the path `path`
// this can be any seekable io stream (std::io::Read + std::io::Seek)
// if you don't have seek, you can just use Input::new(std::io::Read) (no seeking support)
let mut input = scuffle_ffmpeg::io::Input::seekable(std::fs::File::open(path)?)?;
// 2. Get the streams from the input
let streams = input.streams();
dbg!(&streams);
// 3. Find the best audio & video streams.
let best_video_stream = streams.best(AVMediaType::Video).expect("no video stream found");
let best_audio_stream = streams.best(AVMediaType::Audio).expect("no audio stream found");
dbg!(&best_video_stream);
dbg!(&best_audio_stream);
// 4. Create a decoder for each stream
let mut video_decoder = scuffle_ffmpeg::decoder::Decoder::new(&best_video_stream)?
.video()
.expect("not an video decoder");
let mut audio_decoder = scuffle_ffmpeg::decoder::Decoder::new(&best_audio_stream)?
.audio()
.expect("not an audio decoder");
dbg!(&video_decoder);
dbg!(&audio_decoder);
// 5. Get the stream index of the video and audio streams.
let video_stream_index = best_video_stream.index();
let audio_stream_index = best_audio_stream.index();
// 6. Iterate over the packets in the input.
for packet in input.packets() {
let packet = packet?;
// 7. Send the packet to the respective decoder.
// 8. Receive the frame from the decoder.
if packet.stream_index() == video_stream_index {
video_decoder.send_packet(&packet)?;
while let Some(frame) = video_decoder.receive_frame()? {
dbg!(&frame);
}
} else if packet.stream_index() == audio_stream_index {
audio_decoder.send_packet(&packet)?;
while let Some(frame) = audio_decoder.receive_frame()? {
dbg!(&frame);
}
}
}
// 9. Send the EOF to the decoders.
video_decoder.send_eof()?;
audio_decoder.send_eof()?;
// 10. Receive the remaining frames from the decoders.
while let Some(frame) = video_decoder.receive_frame()? {
dbg!(&frame);
}
while let Some(frame) = audio_decoder.receive_frame()? {
dbg!(&frame);
}
§Re-encoding a audio/video file
// 1. Create an input for reading. In this case we open it from a std::fs::File, however
// it can be from any seekable io stream (std::io::Read + std::io::Seek) for example a std::io::Cursor.
// It can also be a non-seekable stream in that case you can use Input::new(std::io::Read)
let input = scuffle_ffmpeg::io::Input::seekable(std::fs::File::open(path)?)?;
// 2. Get the streams from the input.
let streams = input.streams();
// 3. Find the best audio & video streams.
let best_video_stream = streams.best(AVMediaType::Video).expect("no video stream found");
let best_audio_stream = streams.best(AVMediaType::Audio).expect("no audio stream found");
// 4. Create a decoder for each stream
let mut video_decoder = scuffle_ffmpeg::decoder::Decoder::new(&best_video_stream)?
.video()
.expect("not an video decoder");
let mut audio_decoder = scuffle_ffmpeg::decoder::Decoder::new(&best_audio_stream)?
.audio()
.expect("not an audio decoder");
// 5. Create an output for writing. In this case we use a std::io::Cursor,
// however it can be any seekable io stream (std::io::Read + std::io::Seek)
// for example a std::io::Cursor. It can also be a non-seekable stream
// in that case you can use Output::new(std::io::Read)
let mut output = scuffle_ffmpeg::io::Output::seekable(
std::io::Cursor::new(Vec::new()),
OutputOptions::builder().format_name("mp4")?.build(),
)?;
// 6. Find encoders for the streams by name or codec
let x264 = scuffle_ffmpeg::codec::EncoderCodec::by_name("libx264")
.expect("no h264 encoder found");
let aac = scuffle_ffmpeg::codec::EncoderCodec::new(AVCodecID::Aac)
.expect("no aac encoder found");
// 7. Setup the settings for each encoder
let video_settings = VideoEncoderSettings::builder()
.width(video_decoder.width())
.height(video_decoder.height())
.frame_rate(video_decoder.frame_rate())
.pixel_format(video_decoder.pixel_format())
.build();
let audio_settings = AudioEncoderSettings::builder()
.sample_rate(audio_decoder.sample_rate())
.ch_layout(AudioChannelLayout::new(
audio_decoder.channels()
).expect("invalid channel layout"))
.sample_fmt(audio_decoder.sample_format())
.build();
// 8. Initialize the encoders
let mut video_encoder = scuffle_ffmpeg::encoder::Encoder::new(
x264,
&mut output,
best_video_stream.time_base(),
best_video_stream.time_base(),
video_settings,
).expect("not an video encoder");
let mut audio_encoder = scuffle_ffmpeg::encoder::Encoder::new(
aac,
&mut output,
best_audio_stream.time_base(),
best_audio_stream.time_base(),
audio_settings,
).expect("not an audio encoder");
// 9. Write the header to the output.
output.write_header()?;
loop {
let mut audio_done = false;
let mut video_done = false;
// 10. Receive the frame from the decoders.
// 11. Send the frame to the encoders.
// 12. Receive the packet from the encoders.
// 13. Write the packet to the output.
if let Some(frame) = audio_decoder.receive_frame()? {
audio_encoder.send_frame(&frame)?;
while let Some(packet) = audio_encoder.receive_packet()? {
output.write_packet(&packet)?;
}
} else {
audio_done = true;
}
if let Some(frame) = video_decoder.receive_frame()? {
video_encoder.send_frame(&frame)?;
while let Some(packet) = video_encoder.receive_packet()? {
output.write_packet(&packet)?;
}
} else {
video_done = true;
}
// 14. Break the loop if both the audio and video are done.
if audio_done && video_done {
break;
}
}
// 15. Send the EOF to the decoders.
video_decoder.send_eof()?;
audio_decoder.send_eof()?;
// 16. Receive the remaining packets from the encoders.
while let Some(packet) = video_encoder.receive_packet()? {
output.write_packet(&packet)?;
}
while let Some(packet) = audio_encoder.receive_packet()? {
output.write_packet(&packet)?;
}
// 17. Write the trailer to the output.
output.write_trailer()?;
// 18. Do something with the output data (write to disk, upload to s3, etc).
let output_data = output.into_inner();
§License
This project is licensed under the MIT or Apache-2.0 license. You can choose between one of them if you use this work.
SPDX-License-Identifier: MIT OR Apache-2.0
Modules§
- codec
- Codec specific functionality.
- consts
- Constants.
- decoder
- Decoder specific functionality.
- dict
- Dictionary specific functionality.
- encoder
- Encoder specific functionality.
- error
- Error handling.
- filter_
graph - Filter graph specific functionality.
- frame
- Frame specific functionality.
- io
- Input/Output specific functionality.
- log
- Logging specific functionality.
- packet
- Packet specific functionality.
- rational
- Rational number specific functionality.
- resampler
frame::AudioFrame
resampling and format conversion.- scaler
- Scaler specific functionality.
- stream
- Stream specific functionality.
- utils
- Utility functionality.
- changelog
- Changelogs generated by scuffle_changelog
Structs§
- AVCodecID
- Enum representing various FFmpeg codec IDs.
- AVMedia
Type - Represents the different media types supported by FFmpeg.
- AVDictionary
Flags - Dictionary flags used in FFmpeg’s AVDictionary API.
- AVPixel
Format - Pixel formats used in FFmpeg’s
AVPixelFormat
enumeration. - AVSample
Format - Audio sample formats used in FFmpeg’s
AVSampleFormat
enumeration. - AVFormat
Flags - Format flags used in FFmpeg’s
AVFormatContext
configuration. - AVFmt
Flags - Format flags used in FFmpeg’s
AVFormatContext
. - AVPicture
Type - Picture types used in FFmpeg’s
AVPictureType
. - AVSeek
Flag - Seek flags used in FFmpeg’s
av_seek_frame
function. - AVSeek
Whence - Seek flags used in FFmpeg’s
av_seek_frame
function. - AVIO
Flag - I/O flags used in FFmpeg’s
AVIOContext
. - AVChannel
Order - Audio channel ordering schemes used in FFmpeg’s
AVChannelOrder
. - AVRounding
- Rounding methods used in FFmpeg’s
av_rescale_rnd
function. - AVPkt
Flags - Packet flags used in FFmpeg’s
AVPacket
. - AVDiscard
- Discard levels used in FFmpeg’s
AVDiscard
.