### Basic Remuxing Setup Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/codec/encoder/fn.find.html Sets up the FFmpeg library and input/output contexts for a basic remuxing operation. This example focuses on initializing the process and preparing for stream mapping. ```rust let input_file = env::args().nth(1).expect("missing input file"); let output_file = env::args().nth(2).expect("missing output file"); ffmpeg::init().unwrap(); log::set_level(log::Level::Warning); let mut ictx = format::input(&input_file).unwrap(); let mut octx = format::output(&output_file).unwrap(); let mut stream_mapping = vec![0; ictx.nb_streams() as _]; let mut ist_time_bases = vec![Rational(0, 1); ictx.nb_streams() as _]; let mut ost_index = 0; for (ist_index, ist) in ictx.streams().enumerate() { let ist_medium = ist.parameters().medium(); if ist_medium != media::Type::Audio && ist_medium != media::Type::Video && ist_medium != media::Type::Subtitle { stream_mapping[ist_index] = -1; } } ``` -------------------------------- ### Setup H.264 Encoder with Custom Options Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/codec/decoder/video/struct.Video.html This example demonstrates how to set up an H.264 encoder with custom options, including setting video parameters like resolution, frame rate, and time base. It's part of a larger transcoding process. ```rust 43 fn new( 44 ist: &format::stream::Stream, 45 octx: &mut format::context::Output, 46 ost_index: usize, 47 x264_opts: Dictionary, 48 enable_logging: bool, 49 ) -> Result { 50 let global_header = octx.format().flags().contains(format::Flags::GLOBAL_HEADER); 51 let decoder = ffmpeg::codec::context::Context::from_parameters(ist.parameters())?. 52 decoder() 53 .video()?; 54 55 let codec = encoder::find(codec::Id::H264); 56 let mut ost = octx.add_stream(codec)?; 57 58 let mut encoder = 59 codec::context::Context::new_with_codec(codec.ok_or(ffmpeg::Error::InvalidData)?) 60 .encoder() 61 .video()?; 62 ost.set_parameters(&encoder); 63 encoder.set_height(decoder.height()); 64 encoder.set_width(decoder.width()); 65 encoder.set_aspect_ratio(decoder.aspect_ratio()); 66 encoder.set_format(decoder.format()); 67 encoder.set_frame_rate(decoder.frame_rate()); 68 encoder.set_time_base(ist.time_base()); 69 70 if global_header { 71 encoder.set_flags(codec::Flags::GLOBAL_HEADER); 72 } 73 74 let opened_encoder = encoder 75 .open_with(x264_opts) 76 .expect("error opening x264 with supplied settings"); 77 ost.set_parameters(&opened_encoder); 78 Ok(Self { 79 ost_index, 80 decoder, 81 input_time_base: ist.time_base(), 82 encoder: opened_encoder, 83 logging_enabled: enable_logging, 84 frame_count: 0, 85 last_log_frame_count: 0, 86 starting_time: Instant::now(), 87 last_log_time: Instant::now(), 88 }) 89 } ``` -------------------------------- ### Reading and Writing Chapters with Metadata Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/format/chapter/struct.ChapterMut.html This example demonstrates how to initialize FFmpeg, open an input file, iterate through its chapters, print chapter details (ID, time base, start, end, metadata), and then add these chapters to an output file. It also shows how to retrieve chapter information from the output file. ```rust fn main() { ffmpeg::init().unwrap(); match ffmpeg::format::input(&env::args().nth(1).expect("missing input file name")) { Ok(ictx) => { println!("Nb chapters: {}", ictx.nb_chapters()); for chapter in ictx.chapters() { println!("chapter id {}:", chapter.id()); println!("\ttime_base: {}", chapter.time_base()); println!("\tstart: {}", chapter.start()); println!("\tend: {}", chapter.end()); for (k, v) in chapter.metadata().iter() { println!("\t{}: {}", k, v); } } let mut octx = ffmpeg::format::output(&"test.mkv").expect("Couldn't open test file"); for chapter in ictx.chapters() { let title = match chapter.metadata().get("title") { Some(title) => String::from(title), None => String::new(), }; match octx.add_chapter( chapter.id(), chapter.time_base(), chapter.start(), chapter.end(), &title, ) { Ok(chapter) => println!("Added chapter with id {} to output", chapter.id()), Err(error) => { println!("Error adding chapter with id: {} - {}", chapter.id(), error) } } } println!("\nOuput: nb chapters: {}", octx.nb_chapters()); for chapter in octx.chapters() { println!("chapter id {}:", chapter.id()); println!("\ttime_base: {}", chapter.time_base()); println!("\tstart: {}", chapter.start()); println!("\tend: {}", chapter.end()); for (k, v) in chapter.metadata().iter() { println!("\t{}: {}", k, v); } } } Err(error) => println!("error: {}", error), } } ``` -------------------------------- ### Example: Transcoding with x264 Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/codec/context/struct.Context.html This example demonstrates creating a new video encoder context for H.264 using x264 options. It configures parameters like resolution, aspect ratio, and frame rate, and opens the encoder with specific settings. ```rust let mut encoder = codec::context::Context::new_with_codec(codec.ok_or(ffmpeg::Error::InvalidData)?) .encoder() .video() .unwrap(); ost.set_parameters(&encoder); encoder.set_height(decoder.height()); encoder.set_width(decoder.width()); encoder.set_aspect_ratio(decoder.aspect_ratio()); encoder.set_format(decoder.format()); encoder.set_frame_rate(decoder.frame_rate()); encoder.set_time_base(ist.time_base()); if global_header { encoder.set_flags(codec::Flags::GLOBAL_HEADER); } let opened_encoder = encoder .open_with(x264_opts) .expect("error opening x264 with supplied settings"); ost.set_parameters(&opened_encoder); ``` -------------------------------- ### Encoder Configuration Example Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/codec/encoder/audio/struct.Encoder.html This example demonstrates how to configure an audio encoder with specific channel layout, sample rate, and format, as shown in the `transcode-audio.rs` example. ```APIDOC ## Encoder Configuration This section details the configuration of an audio encoder. ### Methods - `set_rate(rate: i32)`: Sets the audio sample rate. - `set_channel_layout(channel_layout: ChannelLayout)`: Sets the audio channel layout. - `set_channels(channels: u32)`: Sets the number of audio channels (deprecated in favor of `set_channel_layout` for ffmpeg 7.0+). - `set_format(format: SampleFormat)`: Sets the audio sample format. - `set_bit_rate(bit_rate: i32)`: Sets the audio bit rate. - `set_max_bit_rate(max_bit_rate: i32)`: Sets the maximum audio bit rate. - `set_time_base(time_base: TimeBase)`: Sets the time base for the encoder. ### Example Usage ```rust // Assuming 'encoder' is a mutable reference to an audio encoder context // and 'decoder' is a reference to an audio decoder context. encoder.set_rate(decoder.rate() as i32); encoder.set_channel_layout(channel_layout); #[cfg(not(feature = "ffmpeg_7_0"))] { encoder.set_channels(channel_layout.channels()); } encoder.set_format( codec .formats() .expect("unknown supported formats") .next() .unwrap(), ); encoder.set_bit_rate(decoder.bit_rate()); encoder.set_max_bit_rate(decoder.max_bit_rate()); encoder.set_time_base((1, decoder.rate() as i32)); ``` ### Related Functions - `channel_layout()`: Retrieves the current channel layout of the encoder. - `filter()`: Function to create and configure an audio filter graph. ``` -------------------------------- ### Dump Video Frames Example (Rust) Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/codec/decoder/opened/struct.Opened.html This example demonstrates how to open an input file, find the best video stream, set up a decoder and scaler, and then process and save each decoded frame as an RGB24 image. ```rust { ffmpeg::init().unwrap(); if let Ok(mut ictx) = input(&env::args().nth(1).expect("Cannot open file.")) { let input = ictx .streams() .best(Type::Video) .ok_or(ffmpeg::Error::StreamNotFound)?; let video_stream_index = input.index(); let context_decoder = ffmpeg::codec::context::Context::from_parameters(input.parameters())?; let mut decoder = context_decoder.decoder().video()?; let mut scaler = Context::get( decoder.format(), decoder.width(), decoder.height(), Pixel::RGB24, decoder.width(), decoder.height(), Flags::BILINEAR, )?; let mut frame_index = 0; let mut receive_and_process_decoded_frames = |decoder: &mut ffmpeg::decoder::Video| -> Result<(), ffmpeg::Error> { let mut decoded = Video::empty(); while decoder.receive_frame(&mut decoded).is_ok() { let mut rgb_frame = Video::empty(); scaler.run(&decoded, &mut rgb_frame)?; save_file(&rgb_frame, frame_index).unwrap(); frame_index += 1; } Ok(()) }; for (stream, packet) in ictx.packets() { if stream.index() == video_stream_index { decoder.send_packet(&packet)?; receive_and_process_decoded_frames(&mut decoder)?; } } decoder.send_eof()?; receive_and_process_decoded_frames(&mut decoder)?; } Ok(()) } ``` -------------------------------- ### Transcoding and Stream Copying Example Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/format/context/input/struct.Input.html This example demonstrates a full transcoding process, including setting up transcoders for video streams and performing stream copies for other media types. It handles packet rescaling and writing interleaved output. ```rust unsafe { (*ost.parameters().as_mut_ptr()).codec_tag = 0; } ``` ```rust octx.set_metadata(ictx.metadata().to_owned()); octx.write_header().unwrap(); for (stream, mut packet) in ictx.packets() { let ist_index = stream.index(); let ost_index = stream_mapping[ist_index]; if ost_index < 0 { continue; } let ost = octx.stream(ost_index as _).unwrap(); packet.rescale_ts(ist_time_bases[ist_index], ost.time_base()); packet.set_position(-1); packet.set_stream(ost_index as _); packet.write_interleaved(&mut octx).unwrap(); } octx.write_trailer().unwrap(); ``` -------------------------------- ### Audio Transcoding Setup Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/format/stream/struct.StreamMut.html This snippet shows the setup for audio transcoding. It finds the best audio stream, configures the decoder and encoder contexts, and sets various audio parameters like sample rate, channel layout, and bit rate. This is part of a larger transcoding process. ```rust fn transcoder + ?Sized>( ictx: &mut format::context::Input, octx: &mut format::context::Output, path: &P, filter_spec: &str, ) -> Result { let input = ictx .streams() .best(media::Type::Audio) .expect("could not find best audio stream"); let context = ffmpeg::codec::context::Context::from_parameters(input.parameters())?; let mut decoder = context.decoder().audio()?; let codec = ffmpeg::encoder::find(octx.format().codec(path, media::Type::Audio)) .expect("failed to find encoder") .audio()?; let global = octx .format() .flags() .contains(ffmpeg::format::flag::Flags::GLOBAL_HEADER); decoder.set_parameters(input.parameters())?; let mut output = octx.add_stream(codec)?; let context = ffmpeg::codec::context::Context::from_parameters(output.parameters())?; let mut encoder = context.encoder().audio()?; let channel_layout = codec .channel_layouts() .map(|cls| cls.best(decoder.channel_layout().channels())) .unwrap_or(ffmpeg::channel_layout::ChannelLayout::STEREO); if global { encoder.set_flags(ffmpeg::codec::flag::Flags::GLOBAL_HEADER); } encoder.set_rate(decoder.rate() as i32); encoder.set_channel_layout(channel_layout); #[cfg(not(feature = "ffmpeg_7_0"))] { encoder.set_channels(channel_layout.channels()); } encoder.set_format( codec .formats() .expect("unknown supported formats") .next() .unwrap(), ); encoder.set_bit_rate(decoder.bit_rate()); encoder.set_max_bit_rate(decoder.max_bit_rate()); ``` -------------------------------- ### Extract Metadata and Stream Information Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/format/stream/struct.StreamMut.html This example shows how to extract metadata, duration, and identify the best video, audio, and subtitle streams from an input file. It also demonstrates how to access detailed information for each stream, including time base, start time, duration, frame count, disposition, and discard settings. ```rust fn main() -> Result<(), ffmpeg::Error> { ffmpeg::init().unwrap(); match ffmpeg::format::input(&env::args().nth(1).expect("missing file")) { Ok(context) => { for (k, v) in context.metadata().iter() { println!("{}: {}", k, v); } if let Some(stream) = context.streams().best(ffmpeg::media::Type::Video) { println!("Best video stream index: {}", stream.index()); } if let Some(stream) = context.streams().best(ffmpeg::media::Type::Audio) { println!("Best audio stream index: {}", stream.index()); } if let Some(stream) = context.streams().best(ffmpeg::media::Type::Subtitle) { println!("Best subtitle stream index: {}", stream.index()); } println!( "duration (seconds): {:.2}", context.duration() as f64 / f64::from(ffmpeg::ffi::AV_TIME_BASE) ); for stream in context.streams() { println!("stream index {}:", stream.index()); println!("\ttime_base: {}", stream.time_base()); println!("\tstart_time: {}", stream.start_time()); println!("\tduration (stream timebase): {}", stream.duration()); println!( "\tduration (seconds): {:.2}", stream.duration() as f64 * f64::from(stream.time_base()) ); println!("\tframes: {}", stream.frames()); println!("\tdisposition: {:?}", stream.disposition()); println!("\tdiscard: {:?}", stream.discard()); } } Err(e) => return Err(e), } Ok(()) } ``` -------------------------------- ### Example Usage of a Scraped Function Source: https://docs.rs/ffmpeg-next/latest/scrape-examples-help.html Create an example in your project that calls a documented item from your library. This example will be scraped and included in the documentation. ```rust // examples/ex.rs fn main() { a_crate::a_func(); } ``` -------------------------------- ### Transcoding and Stream Copy Example Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/util/log/fn.set_level.html This example demonstrates a typical FFmpeg transcoding loop, including handling stream copying for non-video streams. It shows how to rescale timestamps, set packet positions and streams, and write packets to the output context. This is useful for complex media processing pipelines. ```rust octx.set_metadata(ictx.metadata().to_owned()); format::context::output::dump(&octx, 0, Some(&output_file)); octx.write_header().unwrap(); for (ost_index, _) in octx.streams().enumerate() { ost_time_bases[ost_index] = octx.stream(ost_index as _).unwrap().time_base(); } for (stream, mut packet) in ictx.packets() { let ist_index = stream.index(); let ost_index = stream_mapping[ist_index]; if ost_index < 0 { continue; } let ost_time_base = ost_time_bases[ost_index as usize]; match transcoders.get_mut(&ist_index) { Some(transcoder) => { transcoder.send_packet_to_decoder(&packet); transcoder.receive_and_process_decoded_frames(&mut octx, ost_time_base); } None => { // Do stream copy on non-video streams. packet.rescale_ts(ist_time_bases[ist_index], ost_time_base); packet.set_position(-1); packet.set_stream(ost_index as _); packet.write_interleaved(&mut octx).unwrap(); } } } // Flush encoders and decoders. for (ost_index, transcoder) in transcoders.iter_mut() { let ost_time_base = ost_time_bases[*ost_index]; transcoder.send_eof_to_decoder(); transcoder.receive_and_process_decoded_frames(&mut octx, ost_time_base); transcoder.send_eof_to_encoder(); transcoder.receive_and_process_encoded_packets(&mut octx, ost_time_base); } octx.write_trailer().unwrap(); } ``` -------------------------------- ### Get Start Time Source: https://docs.rs/ffmpeg-next/latest/src/ffmpeg_next/format/stream/stream.rs.html Retrieves the start time of the stream in the stream's time base. ```rust pub fn start_time(&self) -> i64 { unsafe { (*self.as_ptr()).start_time } } ``` -------------------------------- ### relative Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/util/time/index.html Gets the time relative to the start of the clock. This is useful for measuring durations. ```APIDOC ## relative ### Description Gets the time relative to the start of the clock. ### Signature `fn relative() -> Timestamp` ``` -------------------------------- ### Read and Write Chapters in FFmpeg Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/format/chapter/struct.Chapter.html This example demonstrates how to initialize FFmpeg, open an input file, iterate through its chapters, print chapter details and metadata, and then add these chapters to an output file. It also shows how to retrieve chapters from the output file. ```rust 5fn main() { 6 ffmpeg::init().unwrap(); 7 8 match ffmpeg::format::input(&env::args().nth(1).expect("missing input file name")) { 9 Ok(ictx) => { 10 println!("Nb chapters: {}", ictx.nb_chapters()); 11 12 for chapter in ictx.chapters() { 13 println!("chapter id {}", chapter.id()); 14 println!("\ttime_base: {}", chapter.time_base()); 15 println!("\tstart: {}", chapter.start()); 16 println!("\tend: {}", chapter.end()); 17 18 for (k, v) in chapter.metadata().iter() { 19 println!("\t{}: {}", k, v); 20 } 21 } 22 23 let mut octx = ffmpeg::format::output(&"test.mkv").expect("Couldn't open test file"); 24 25 for chapter in ictx.chapters() { 26 let title = match chapter.metadata().get("title") { 27 Some(title) => String::from(title), 28 None => String::new(), 29 }; 30 31 match octx.add_chapter( 32 chapter.id(), 33 chapter.time_base(), 34 chapter.start(), 35 chapter.end(), 36 &title, 37 ) { 38 Ok(chapter) => println!("Added chapter with id {} to output", chapter.id()), 39 Err(error) => { 40 println!("Error adding chapter with id: {} - {}", chapter.id(), error) 41 } 42 } 43 } 44 45 println!("\nOuput: nb chapters: {}", octx.nb_chapters()); 46 for chapter in octx.chapters() { 47 println!("chapter id {}", chapter.id()); 48 println!("\ttime_base: {}", chapter.time_base()); 49 println!("\tstart: {}", chapter.start()); 50 println!("\tend: {}", chapter.end()); 51 for (k, v) in chapter.metadata().iter() { 52 println!("\t{}: {}", k, v); 53 } 54 } 55 } 56 57 Err(error) => println!("error: {}", error), 58 } 59} ``` -------------------------------- ### Get Timecode Frame Start Source: https://docs.rs/ffmpeg-next/latest/src/ffmpeg_next/codec/decoder/audio.rs.html Retrieves the starting frame number for timecode information. Returns `None` if the value is -1, indicating it's not set or removed in FFmpeg 5.0+. ```rust pub fn frame_start(&self) -> Option { unsafe { // Removed in ffmpeg >= 5.0 in favor of using encoder // private options. match (*self.as_ptr()).timecode_frame_start { -1 => None, n => Some(n as usize), } } } ``` -------------------------------- ### Get FFmpeg Device Configuration Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/device/fn.configuration.html Call this function to retrieve a static string describing the FFmpeg device configuration. No setup or imports are required. ```rust pub fn configuration() -> &'static str ``` -------------------------------- ### Read Video Metadata and Stream Information Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/codec/decoder/video/struct.Video.html This example demonstrates how to initialize FFmpeg, open an input file, iterate through its metadata, and find the best video, audio, and subtitle streams. It also shows how to calculate the total duration of the media in seconds. ```rust 5fn main() -> Result<(), ffmpeg::Error> { ffmpeg::init().unwrap(); match ffmpeg::format::input(&env::args().nth(1).expect("missing file")) { Ok(context) => { for (k, v) in context.metadata().iter() { println!("{}: {}", k, v); } if let Some(stream) = context.streams().best(ffmpeg::media::Type::Video) { println!("Best video stream index: {}", stream.index()); } if let Some(stream) = context.streams().best(ffmpeg::media::Type::Audio) { println!("Best audio stream index: {}", stream.index()); } if let Some(stream) = context.streams().best(ffmpeg::media::Type::Subtitle) { println!("Best subtitle stream index: {}", stream.index()); } println!( "duration (seconds): {:.2}", context.duration() as f64 / f64::from(ffmpeg::ffi::AV_TIME_BASE) ); for stream in context.streams() { println!("stream index {}:", stream.index()); println!("\ttime_base: {}", stream.time_base()); println!("\tstart_time: {}", stream.start_time()); println!("\tduration (stream timebase): {}", stream.duration()); println!( "\tduration (seconds): {:.2}", stream.duration() as f64 * f64::from(stream.time_base()) ); println!("\tframes: {}", stream.frames()); println!("\tdisposition: {:?}", stream.disposition()); println!("\tdiscard: {:?}", stream.discard()); println!("\trate: {}", stream.rate()); let codec = ffmpeg::codec::context::Context::from_parameters(stream.parameters())?; println!("\tmedium: {:?}", codec.medium()); println!("\tid: {:?}", codec.id()); if codec.medium() == ffmpeg::media::Type::Video { if let Ok(video) = codec.decoder().video() { println!("\tbit_rate: {}", video.bit_rate()); println!("\tmax_rate: {}", video.max_bit_rate()); println!("\tdelay: {}", video.delay()); println!("\tvideo.width: {}", video.width()); println!("\tvideo.height: {}", video.height()); println!("\tvideo.format: {:?}", video.format()); println!("\tvideo.has_b_frames: {}", video.has_b_frames()); println!("\tvideo.aspect_ratio: {}", video.aspect_ratio()); println!("\tvideo.color_space: {:?}", video.color_space()); println!("\tvideo.color_range: {:?}", video.color_range()); println!("\tvideo.color_primaries: {:?}", video.color_primaries()); println!( "\tvideo.color_transfer_characteristic: {:?}", video.color_transfer_characteristic() ); println!("\tvideo.chroma_location: {:?}", video.chroma_location()); println!("\tvideo.references: {}", video.references()); println!("\tvideo.intra_dc_precision: {}", video.intra_dc_precision()); } } else if codec.medium() == ffmpeg::media::Type::Audio { if let Ok(audio) = codec.decoder().audio() { println!("\tbit_rate: {}", audio.bit_rate()); println!("\tmax_rate: {}", audio.max_bit_rate()); println!("\tdelay: {}", audio.delay()); println!("\taudio.rate: {}", audio.rate()); println!("\taudio.channels: {}", audio.channels()); println!("\taudio.format: {:?}", audio.format()); println!("\taudio.frames: {}", audio.frames()); println!("\taudio.align: {}", audio.align()); println!("\taudio.channel_layout: {:?}", audio.channel_layout()); } } } } Err(error) => println!("error: {}", error), } Ok(()) } ``` -------------------------------- ### Initialize FFmpeg and Setup Transcoder Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/format/stream/struct.Stream.html Initializes the FFmpeg library and sets up the input and output contexts. It then creates a `Transcoder` instance to handle the audio stream processing. ```rust ffmpeg::init().unwrap(); let input = env::args().nth(1).expect("missing input"); let output = env::args().nth(2).expect("missing output"); let filter = env::args().nth(3).unwrap_or_else(|| "anull".to_owned()); let seek = env::args().nth(4).and_then(|s| s.parse::().ok()); let mut ictx = format::input(&input).unwrap(); let mut octx = format::output(&output).unwrap(); let mut transcoder = transcoder(&mut ictx, &mut octx, &output, &filter).unwrap(); if let Some(position) = seek { // If the position was given in seconds, rescale it to ffmpegs base timebase. let position = position.rescale((1, 1), rescale::TIME_BASE); } ``` -------------------------------- ### Chapter Struct and Methods Source: https://docs.rs/ffmpeg-next/latest/src/ffmpeg_next/format/chapter/chapter.rs.html Provides access to chapter information within an FFmpeg context. Includes methods to get the chapter index, ID, time base, start and end times, and associated metadata. ```APIDOC ## Chapter Struct ### Description Represents a chapter within an FFmpeg media file. It allows access to various properties of the chapter. ### Methods #### `new(context: &Context, index: usize) -> Chapter<'_>` * **Description**: Creates a new `Chapter` instance. This is an unsafe method and requires a valid `Context` and chapter `index`. * **Safety**: The caller must ensure that `context` is valid and `index` is within the bounds of the available chapters. #### `as_ptr(&self) -> *const AVChapter` * **Description**: Returns a raw pointer to the underlying `AVChapter` struct. * **Safety**: The returned pointer is only valid as long as the `Chapter` and its associated `Context` are valid. #### `index(&self) -> usize` * **Description**: Returns the index of the chapter. #### `id(&self) -> i64` * **Description**: Returns the ID of the chapter. #### `time_base(&self) -> Rational` * **Description**: Returns the time base of the chapter as a `Rational` number. #### `start(&self) -> i64` * **Description**: Returns the start timestamp of the chapter. #### `end(&self) -> i64` * **Description**: Returns the end timestamp of the chapter. #### `metadata(&self) -> DictionaryRef<'_>` * **Description**: Returns a `DictionaryRef` containing the metadata associated with the chapter. ### Equality #### `PartialEq` implementation * **Description**: Allows comparing two `Chapter` instances for equality based on their underlying `AVChapter` pointers. ``` -------------------------------- ### Iterate Streams and Print Codec Info Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/codec/decoder/opened/struct.Opened.html This example demonstrates how to initialize ffmpeg, open an input file, iterate through its streams, and print detailed information about each stream's codec parameters. It specifically shows how to access video-specific properties like bit rate, resolution, and delay, as well as audio-specific properties like sample rate, channels, and format. ```rust fn main() -> Result<(), ffmpeg::Error> { ffmpeg::init().unwrap(); match ffmpeg::format::input(&env::args().nth(1).expect("missing file")) { Ok(context) => { for (k, v) in context.metadata().iter() { println!("{}: {}", k, v); } if let Some(stream) = context.streams().best(ffmpeg::media::Type::Video) { println!("Best video stream index: {}", stream.index()); } if let Some(stream) = context.streams().best(ffmpeg::media::Type::Audio) { println!("Best audio stream index: {}", stream.index()); } if let Some(stream) = context.streams().best(ffmpeg::media::Type::Subtitle) { println!("Best subtitle stream index: {}", stream.index()); } println!( "duration (seconds): {:.2}", context.duration() as f64 / f64::from(ffmpeg::ffi::AV_TIME_BASE) ); for stream in context.streams() { println!("stream index {}:", stream.index()); println!("\ttime_base: {}", stream.time_base()); println!("\tstart_time: {}", stream.start_time()); println!("\tduration (stream timebase): {}", stream.duration()); println!( "\tduration (seconds): {:.2}", stream.duration() as f64 * f64::from(stream.time_base()) ); println!("\tframes: {}", stream.frames()); println!("\tdisposition: {:?}", stream.disposition()); println!("\tdiscard: {:?}", stream.discard()); println!("\trate: {}", stream.rate()); let codec = ffmpeg::codec::context::Context::from_parameters(stream.parameters())?; println!("\tmedium: {:?}", codec.medium()); println!("\tid: {:?}", codec.id()); if codec.medium() == ffmpeg::media::Type::Video { if let Ok(video) = codec.decoder().video() { println!("\tbit_rate: {}", video.bit_rate()); println!("\tmax_rate: {}", video.max_bit_rate()); println!("\tdelay: {}", video.delay()); println!("\tvideo.width: {}", video.width()); println!("\tvideo.height: {}", video.height()); println!("\tvideo.format: {:?}", video.format()); println!("\tvideo.has_b_frames: {}", video.has_b_frames()); println!("\tvideo.aspect_ratio: {}", video.aspect_ratio()); println!("\tvideo.color_space: {:?}", video.color_space()); println!("\tvideo.color_range: {:?}", video.color_range()); println!("\tvideo.color_primaries: {:?}", video.color_primaries()); println!( "\tvideo.color_transfer_characteristic: {:?}", video.color_transfer_characteristic() ); println!("\tvideo.chroma_location: {:?}", video.chroma_location()); println!("\tvideo.references: {}", video.references()); println!("\tvideo.intra_dc_precision: {}", video.intra_dc_precision()); } } else if codec.medium() == ffmpeg::media::Type::Audio { if let Ok(audio) = codec.decoder().audio() { println!("\tbit_rate: {}", audio.bit_rate()); println!("\tmax_rate: {}", audio.max_bit_rate()); println!("\tdelay: {}", audio.delay()); println!("\taudio.rate: {}", audio.rate()); println!("\taudio.channels: {}", audio.channels()); println!("\taudio.format: {:?}", audio.format()); println!("\taudio.frames: {}", audio.frames()); println!("\taudio.align: {}", audio.align()); println!("\taudio.channel_layout: {:?}", audio.channel_layout()); } } } } Err(error) => println!("error: {}", error), } Ok(()) } ``` -------------------------------- ### Find and Configure Audio Encoder Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/format/format/struct.Output.html This example demonstrates how to find an appropriate audio encoder for an output format and configure its parameters based on the input stream. It sets up the encoder's rate, channel layout, format, and bitrate. ```rust 65fn transcoder + ?Sized>( ictx: &mut format::context::Input, octx: &mut format::context::Output, path: &P, filter_spec: &str, )-> Result { let input = ictx .streams() .best(media::Type::Audio) .expect("could not find best audio stream"); let context = ffmpeg::codec::context::Context::from_parameters(input.parameters())?; let mut decoder = context.decoder().audio()?; let codec = ffmpeg::encoder::find(octx.format().codec(path, media::Type::Audio)) .expect("failed to find encoder") .audio()?; let global = octx .format() .flags() .contains(ffmpeg::format::flag::Flags::GLOBAL_HEADER); decoder.set_parameters(input.parameters())?; let mut output = octx.add_stream(codec)?; let context = ffmpeg::codec::context::Context::from_parameters(output.parameters())?; let mut encoder = context.encoder().audio()?; let channel_layout = codec .channel_layouts() .map(|cls| cls.best(decoder.channel_layout().channels())) .unwrap_or(ffmpeg::channel_layout::ChannelLayout::STEREO); if global { encoder.set_flags(ffmpeg::codec::flag::Flags::GLOBAL_HEADER); } encoder.set_rate(decoder.rate() as i32); encoder.set_channel_layout(channel_layout); #[cfg(not(feature = "ffmpeg_7_0"))] { encoder.set_channels(channel_layout.channels()); } encoder.set_format( codec .formats() .expect("unknown supported formats") .next() .unwrap(), ); encoder.set_bit_rate(decoder.bit_rate()); encoder.set_max_bit_rate(decoder.max_bit_rate()); encoder.set_time_base((1, decoder.rate() as i32)); output.set_time_base((1, decoder.rate() as i32)); let encoder = encoder.open_as(codec)?; output.set_parameters(&encoder); let filter = filter(filter_spec, &decoder, &encoder)?; let in_time_base = decoder.time_base(); let out_time_base = output.time_base(); Ok(Transcoder { stream: input.index(), filter, decoder, encoder, in_time_base, out_time_base, }) } ``` -------------------------------- ### Subtitle Structure and Basic Accessors Source: https://docs.rs/ffmpeg-next/latest/src/ffmpeg_next/codec/subtitle/mod.rs.html Represents an FFmpeg subtitle structure. Provides methods to get and set presentation timestamp (PTS), start and end display times, and raw pointers to the underlying FFmpeg structure. ```rust pub struct Subtitle(AVSubtitle); impl Subtitle { pub unsafe fn as_ptr(&self) -> *const AVSubtitle { &self.0 } pub unsafe fn as_mut_ptr(&mut self) -> *mut AVSubtitle { &mut self.0 } pub fn new() -> Self { unsafe { Subtitle(mem::zeroed()) } } pub fn pts(&self) -> Option { match self.0.pts { AV_NOPTS_VALUE => None, pts => Some(pts), } } pub fn set_pts(&mut self, value: Option) { self.0.pts = value.unwrap_or(AV_NOPTS_VALUE); } pub fn start(&self) -> u32 { self.0.start_display_time } pub fn set_start(&mut self, value: u32) { self.0.start_display_time = value; } pub fn end(&self) -> u32 { self.0.end_display_time } pub fn set_end(&mut self, value: u32) { self.0.end_display_time = value; } } impl Default for Subtitle { fn default() -> Self { Self::new() } } ``` -------------------------------- ### Initialize FFmpeg and Set Up Input/Output Contexts Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/codec/encoder/fn.find.html Initializes the FFmpeg library and sets up input and output contexts for file processing. This is a prerequisite for most FFmpeg operations. ```rust ffmpeg::init().unwrap(); log::set_level(log::Level::Info); let mut ictx = format::input(&input_file).unwrap(); let mut octx = format::output(&output_file).unwrap(); ``` -------------------------------- ### Initialize FFmpeg and Set Up Output Context Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/format/stream/struct.StreamMut.html Initializes the FFmpeg library, sets the logging level, and prepares the output context for writing to a file. It also configures streams, including video transcoding and copying for other media types. ```rust ffmpeg::init().unwrap(); log::set_level(log::Level::Info); let mut ictx = format::input(&input_file).unwrap(); let mut octx = format::output(&output_file).unwrap(); format::context::input::dump(&ictx, 0, Some(&input_file)); let best_video_stream_index = ictx .streams() .best(media::Type::Video) .map(|stream| stream.index()); let mut stream_mapping: Vec = vec![0; ictx.nb_streams() as _]; let mut ist_time_bases = vec![Rational(0, 0); ictx.nb_streams() as _]; let mut ost_time_bases = vec![Rational(0, 0); ictx.nb_streams() as _]; let mut transcoders = HashMap::new(); let mut ost_index = 0; for (ist_index, ist) in ictx.streams().enumerate() { let ist_medium = ist.parameters().medium(); if ist_medium != media::Type::Audio && ist_medium != media::Type::Video && ist_medium != media::Type::Subtitle { stream_mapping[ist_index] = -1; continue; } stream_mapping[ist_index] = ost_index; ist_time_bases[ist_index] = ist.time_base(); if ist_medium == media::Type::Video { // Initialize transcoder for video stream. transcoders.insert( ist_index, Transcoder::new( &ist, &mut octx, ost_index as _, x264_opts.to_owned(), Some(ist_index) == best_video_stream_index, ) .unwrap(), ); } else { // Set up for stream copy for non-video stream. let mut ost = octx.add_stream(encoder::find(codec::Id::None)).unwrap(); ost.set_parameters(ist.parameters()); // We need to set codec_tag to 0 lest we run into incompatible codec tag // issues when muxing into a different container format. Unfortunately // there's no high level API to do this (yet). unsafe { (*ost.parameters().as_mut_ptr()).codec_tag = 0; } } ost_index += 1; } octx.set_metadata(ictx.metadata().to_owned()); format::context::output::dump(&octx, 0, Some(&output_file)); octx.write_header().unwrap(); for (ost_index, _) in octx.streams().enumerate() { ost_time_bases[ost_index] = octx.stream(ost_index as _).unwrap().time_base(); } for (stream, mut packet) in ictx.packets() { let ist_index = stream.index(); let ost_index = stream_mapping[ist_index]; if ost_index < 0 { continue; } let ost_time_base = ost_time_bases[ost_index as usize]; match transcoders.get_mut(&ist_index) { Some(transcoder) => { transcoder.send_packet_to_decoder(&packet); ``` -------------------------------- ### Initialize FFmpeg and Set Up Contexts Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/format/stream/struct.Stream.html Initializes the FFmpeg library, sets the log level, and opens input and output file contexts. This is a prerequisite for most FFmpeg operations. ```rust ffmpeg::init().unwrap(); log::set_level(log::Level::Info); let mut ictx = format::input(&input_file).unwrap(); let mut octx = format::output(&output_file).unwrap(); format::context::input::dump(&ictx, 0, Some(&input_file)); ``` -------------------------------- ### Set chapter start time Source: https://docs.rs/ffmpeg-next/latest/src/ffmpeg_next/format/chapter/chapter_mut.rs.html Sets the start timestamp for a chapter. ```rust pub fn set_start(&mut self, value: i64) { unsafe { (*self.as_mut_ptr()).start = value; } } ``` -------------------------------- ### Codec Information Retrieval Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/codec/codec/struct.Codec.html This example demonstrates how to initialize FFmpeg, iterate through command-line arguments to find codecs (both decoders and encoders), and print detailed information about each codec. It includes fetching capabilities, profiles, video and audio specific details, and the maximum low-resolution setting. ```rust fn main() { ffmpeg::init().unwrap(); for arg in env::args().skip(1) { if let Some(codec) = ffmpeg::decoder::find_by_name(&arg) { println!("type: decoder"); println!("\tid: {:?}", codec.id()); println!("\tname: {}", codec.name()); println!("\tdescription: {}", codec.description()); println!("\tmedium: {:?}", codec.medium()); println!("\tcapabilities: {:?}", codec.capabilities()); if let Some(profiles) = codec.profiles() { println!("\tprofiles: {:?}", profiles.collect::>()); } else { println!("\tprofiles: none"); } if let Ok(video) = codec.video() { if let Some(rates) = video.rates() { println!("\trates: {:?}", rates.collect::>()); } else { println!("\trates: any"); } if let Some(formats) = video.formats() { println!("\tformats: {:?}", formats.collect::>()); } else { println!("\tformats: any"); } } if let Ok(audio) = codec.audio() { if let Some(rates) = audio.rates() { println!("\trates: {:?}", rates.collect::>()); } else { println!("\trates: any"); } if let Some(formats) = audio.formats() { println!("\tformats: {:?}", formats.collect::>()); } else { println!("\tformats: any"); } if let Some(layouts) = audio.channel_layouts() { println!("\tchannel_layouts: {:?}", layouts.collect::>()); } else { println!("\tchannel_layouts: any"); } } println!("\tmax_lowres: {:?}", codec.max_lowres()); } if let Some(codec) = ffmpeg::encoder::find_by_name(&arg) { println!(); println!("type: encoder"); println!("\tid: {:?}", codec.id()); println!("\tname: {}", codec.name()); println!("\tdescription: {}", codec.description()); println!("\tmedium: {:?}", codec.medium()); println!("\tcapabilities: {:?}", codec.capabilities()); if let Some(profiles) = codec.profiles() { println!("\tprofiles: {:?}", profiles.collect::>()); } if let Ok(video) = codec.video() { if let Some(rates) = video.rates() { println!("\trates: {:?}", rates.collect::>()); } else { println!("\trates: any"); } if let Some(formats) = video.formats() { println!("\tformats: {:?}", formats.collect::>()); } else { println!("\tformats: any"); } } if let Ok(audio) = codec.audio() { if let Some(rates) = audio.rates() { println!("\trates: {:?}", rates.collect::>()); } else { println!("\trates: any"); } if let Some(formats) = audio.formats() { println!("\tformats: {:?}", formats.collect::>()); } else { println!("\tformats: any"); } if let Some(layouts) = audio.channel_layouts() { println!("\tchannel_layouts: {:?}", layouts.collect::>()); } else { println!("\tchannel_layouts: any"); } } println!("\tmax_lowres: {:?}", codec.max_lowres()); } } } ``` -------------------------------- ### Set PTS using Timestamp from Frame (Video Example) Source: https://docs.rs/ffmpeg-next/latest/ffmpeg_next/util/frame/struct.Frame.html This example shows setting the PTS of a video frame using its timestamp, similar to the audio example. It's part of a decoding and processing loop. ```rust 107 let timestamp = frame.timestamp(); 111 frame.set_pts(timestamp); ```