From fd2d71c92b2b5a42d0d3b783e633d62f93767f00 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Tue, 30 Apr 2024 03:38:37 +0200 Subject: [PATCH] Support FFmpeg 7.0 (#48) * sys: Run cargo fmt * sys: Add new channel layout consts * sys: Update build script for 7.0 - Add new FF_API flags - Update version_check_info range - Add ffmpeg_7_0 feature entry * sys: Update non-exhaustive match statement * Update enums * Mark old APIs as removed with 7.0 * Make Audio frame work with 7.0 The .unwrap() in clone() is a bit wonky * Add API for swr_alloc_set_opts2 * Use AVFrame::duration field in 7.0+ * Include 7.0 in CI runs * Add fn ChanneLayoutIter::best * Update examples for new API * Add/update Context setter for ch layout --- .github/workflows/build.yml | 17 ++-- examples/codec-info.rs | 6 +- examples/metadata.rs | 8 +- examples/transcode-audio.rs | 40 ++++++--- ffmpeg-sys-the-third/build.rs | 17 +++- .../src/avutil/channel_layout.rs | 19 +++- ffmpeg-sys-the-third/src/avutil/rational.rs | 2 +- src/codec/audio.rs | 21 ++++- src/codec/decoder/audio.rs | 10 ++- src/codec/decoder/video.rs | 1 + src/codec/encoder/audio.rs | 9 +- src/codec/id.rs | 15 ++++ src/codec/packet/side_data.rs | 27 ++++++ src/filter/context/context.rs | 14 ++- src/software/mod.rs | 13 ++- src/software/resampling/context.rs | 89 +++++++++++++++++++ src/software/resampling/extensions.rs | 46 +++++++++- src/util/channel_layout/layout.rs | 5 ++ src/util/channel_layout/mask.rs | 6 ++ src/util/channel_layout/order.rs | 3 + src/util/format/pixel.rs | 15 +++- src/util/frame/audio.rs | 47 ++++++++-- src/util/frame/mod.rs | 3 + src/util/frame/video.rs | 2 + src/util/option/mod.rs | 21 ++++- src/util/option/traits.rs | 6 +- 26 files changed, 419 insertions(+), 43 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9aca2a4..fec0445 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,7 +30,7 @@ jobs: strategy: matrix: ffmpeg_version: - ["3.4", "4.0", "4.1", "4.2", "4.3", "4.4", "5.0", "5.1", "6.0", "6.1"] + ["3.4", "4.0", "4.1", "4.2", "4.3", "4.4", "5.0", "5.1", "6.0", "6.1", "7.0"] fail-fast: false steps: @@ -45,8 +45,9 @@ jobs: components: rustfmt, clippy - uses: Swatinem/rust-cache@v2 with: + prefix-key: "v2-rust" # Only save cache for one FFmpeg version - save-if: ${{ matrix.ffmpeg_version == '6.1' }} + save-if: ${{ matrix.ffmpeg_version == '7.0' }} - name: Check format run: cargo fmt -- --check @@ -75,6 +76,8 @@ jobs: with: components: rustfmt, clippy - uses: Swatinem/rust-cache@v2 + with: + prefix-key: "v2-rust" - name: Check format run: cargo fmt -- --check @@ -97,7 +100,7 @@ jobs: strategy: matrix: # GyanD builds don't go as far back as the Ubuntu builds - ffmpeg_version: ["4.4", "5.0", "5.1", "6.0", "6.1"] + ffmpeg_version: ["4.4", "5.0", "5.1", "6.0", "6.1", "7.0"] fail-fast: false env: @@ -127,8 +130,8 @@ jobs: components: rustfmt, clippy - uses: Swatinem/rust-cache@v2 with: - prefix-key: "v1-rust" - save-if: ${{ matrix.ffmpeg_version == '6.1' }} + prefix-key: "v2-rust" + save-if: ${{ matrix.ffmpeg_version == '7.0' }} - name: Check format run: cargo fmt -- --check @@ -147,7 +150,7 @@ jobs: msrv: runs-on: ubuntu-22.04 - container: jrottenberg/ffmpeg:6.1-ubuntu + container: jrottenberg/ffmpeg:7.0-ubuntu steps: - uses: actions/checkout@v4 @@ -159,6 +162,8 @@ jobs: - name: Install Rust 1.61.0 uses: dtolnay/rust-toolchain@1.61.0 - uses: Swatinem/rust-cache@v2 + with: + prefix-key: "v2-rust" - name: Use predefined lockfile run: mv Cargo.lock.MSRV Cargo.lock diff --git a/examples/codec-info.rs b/examples/codec-info.rs index 756abc0..6210cf7 100644 --- a/examples/codec-info.rs +++ b/examples/codec-info.rs @@ -47,7 +47,8 @@ fn main() { println!("\t formats: any"); } - if let Some(layouts) = audio.channel_layouts() { + #[cfg(feature = "ffmpeg_5_1")] + if let Some(layouts) = audio.ch_layouts() { println!("\t channel_layouts: {:?}", layouts.collect::>()); } else { println!("\t channel_layouts: any"); @@ -97,7 +98,8 @@ fn main() { println!("\t formats: any"); } - if let Some(layouts) = audio.channel_layouts() { + #[cfg(feature = "ffmpeg_5_1")] + if let Some(layouts) = audio.ch_layouts() { println!("\t channel_layouts: {:?}", layouts.collect::>()); } else { println!("\t channel_layouts: any"); diff --git a/examples/metadata.rs b/examples/metadata.rs index 47cb4d4..c0ee2d9 100644 --- a/examples/metadata.rs +++ b/examples/metadata.rs @@ -73,10 +73,14 @@ fn main() -> Result<(), ffmpeg::Error> { 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()); + #[cfg(feature = "ffmpeg_5_1")] + println!("\taudio.ch_layout: {:?}", audio.ch_layout()); + + #[cfg(not(feature = "ffmpeg_5_1"))] + println!("\taudio.channels: {}", audio.channels()); + #[cfg(not(feature = "ffmpeg_5_1"))] println!("\taudio.channel_layout: {:?}", audio.channel_layout()); } } diff --git a/examples/transcode-audio.rs b/examples/transcode-audio.rs index 5b4337a..4a49160 100644 --- a/examples/transcode-audio.rs +++ b/examples/transcode-audio.rs @@ -13,12 +13,16 @@ fn filter( ) -> Result { let mut filter = filter::Graph::new(); + #[cfg(feature = "ffmpeg_5_1")] + let channel_layout = decoder.ch_layout().description(); + #[cfg(not(feature = "ffmpeg_5_1"))] + let channel_layout = format!("0x{:x}", decoder.channel_layout().bits()); + let args = format!( - "time_base={}:sample_rate={}:sample_fmt={}:channel_layout=0x{:x}", + "time_base={}:sample_rate={}:sample_fmt={}:channel_layout={channel_layout}", decoder.time_base(), decoder.rate(), - decoder.format().name(), - decoder.channel_layout().bits() + decoder.format().name() ); filter.add(&filter::find("abuffer").unwrap(), "in", &args)?; @@ -28,7 +32,10 @@ fn filter( let mut out = filter.get("out").unwrap(); out.set_sample_format(encoder.format()); + #[cfg(not(feature = "ffmpeg_5_1"))] out.set_channel_layout(encoder.channel_layout()); + #[cfg(feature = "ffmpeg_5_1")] + out.set_ch_layout(encoder.ch_layout()); out.set_sample_rate(encoder.rate()); } @@ -88,18 +95,31 @@ fn transcoder>( 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::ChannelLayoutMask::STEREO); - if global { encoder.set_flags(ffmpeg::codec::flag::Flags::GLOBAL_HEADER); } + #[cfg(feature = "ffmpeg_5_1")] + { + let ch_layout = codec + .ch_layouts() + .map(|cls| cls.best(decoder.ch_layout().channels())) + .unwrap_or(ffmpeg::channel_layout::ChannelLayout::STEREO); + + encoder.set_ch_layout(ch_layout); + } + + #[cfg(not(feature = "ffmpeg_5_1"))] + { + let channel_layout = codec + .channel_layouts() + .map(|cls| cls.best(decoder.channel_layout().channels())) + .unwrap_or(ffmpeg::channel_layout::ChannelLayoutMask::STEREO); + encoder.set_channel_layout(channel_layout); + encoder.set_channels(channel_layout.channels()); + } + encoder.set_rate(decoder.rate() as i32); - encoder.set_channel_layout(channel_layout); - encoder.set_channels(channel_layout.channels()); encoder.set_format( codec .formats() diff --git a/ffmpeg-sys-the-third/build.rs b/ffmpeg-sys-the-third/build.rs index 281e931..f428ebb 100644 --- a/ffmpeg-sys-the-third/build.rs +++ b/ffmpeg-sys-the-third/build.rs @@ -114,6 +114,7 @@ static AVUTIL_FEATURES: &[AVFeature] = &[ AVFeature::new("FRAME_KEY"), AVFeature::new("PALETTE_HAS_CHANGED"), AVFeature::new("VULKAN_CONTIGUOUS_MEMORY"), + AVFeature::new("H274_FILM_GRAIN_VCS"), ]; static AVCODEC_FEATURES: &[AVFeature] = &[ @@ -199,6 +200,9 @@ static AVCODEC_FEATURES: &[AVFeature] = &[ AVFeature::new("DROPCHANGED"), AVFeature::new("AVFFT"), AVFeature::new("FF_PROFILE_LEVEL"), + AVFeature::new("AVCODEC_CLOSE"), + AVFeature::new("BUFFER_MIN_SIZE"), + AVFeature::new("VDPAU_ALLOC_GET_SET"), ]; static AVFORMAT_FEATURES: &[AVFeature] = &[ @@ -220,9 +224,16 @@ static AVFORMAT_FEATURES: &[AVFeature] = &[ AVFeature::new("LAVF_SHORTEST"), AVFeature::new("ALLOW_FLUSH"), AVFeature::new("AVSTREAM_SIDE_DATA"), + AVFeature::new("GET_DUR_ESTIMATE_METHOD"), + AVFeature::new("R_FRAME_RATE"), ]; -static AVDEVICE_FEATURES: &[AVFeature] = &[AVFeature::new("DEVICE_CAPABILITIES")]; +static AVDEVICE_FEATURES: &[AVFeature] = &[ + AVFeature::new("DEVICE_CAPABILITIES"), + AVFeature::new("BKTR_DEVICE"), + AVFeature::new("OPENGL_DEVICE"), + AVFeature::new("SDL2_DEVICE"), +]; static AVFILTER_FEATURES: &[AVFeature] = &[ AVFeature::new("AVFILTERPAD_PUBLIC"), @@ -237,6 +248,7 @@ static AVFILTER_FEATURES: &[AVFeature] = &[ AVFeature::new("BUFFERSINK_ALLOC"), AVFeature::new("PAD_COUNT"), AVFeature::new("LIBPLACEBO_OPTS"), + AVFeature::new("LINK_PUBLIC"), ]; static AVRESAMPLE_FEATURES: &[AVFeature] = &[AVFeature::new("RESAMPLE_CLOSE_OPEN")]; @@ -736,7 +748,7 @@ fn check_features(include_paths: &[PathBuf]) { ); } } - let version_check_info = [("avcodec", 56, 61, 0, 108)]; + let version_check_info = [("avcodec", 56, 62, 0, 108)]; for &(lib, begin_version_major, end_version_major, begin_version_minor, end_version_minor) in version_check_info.iter() { @@ -880,6 +892,7 @@ fn check_features(include_paths: &[PathBuf]) { ("ffmpeg_5_1", 59, 37), ("ffmpeg_6_0", 60, 3), ("ffmpeg_6_1", 60, 31), + ("ffmpeg_7_0", 61, 3), ]; for &(ffmpeg_version_flag, lavc_version_major, lavc_version_minor) in ffmpeg_lavc_versions.iter() diff --git a/ffmpeg-sys-the-third/src/avutil/channel_layout.rs b/ffmpeg-sys-the-third/src/avutil/channel_layout.rs index be50c9c..a40ad9d 100644 --- a/ffmpeg-sys-the-third/src/avutil/channel_layout.rs +++ b/ffmpeg-sys-the-third/src/avutil/channel_layout.rs @@ -77,9 +77,10 @@ impl fmt::Debug for AVChannelLayout { "map", &std::slice::from_raw_parts(self.u.map, self.nb_channels as usize), ); - } // Starting with FFmpeg 7.0: - // Not part of public API, but we have to exhaustively match - // AVChannelOrder::FF_CHANNEL_ORDER_NB => {} + } + // Not part of public API, but we have to exhaustively match + #[cfg(feature = "ffmpeg_7_0")] + AVChannelOrder::FF_CHANNEL_ORDER_NB => {} } } @@ -184,6 +185,12 @@ pub const AV_CH_LAYOUT_7POINT1POINT2: u64 = AV_CH_LAYOUT_7POINT1 | AV_CH_TOP_FRONT_LEFT | AV_CH_TOP_FRONT_RIGHT; pub const AV_CH_LAYOUT_7POINT1POINT4_BACK: u64 = AV_CH_LAYOUT_7POINT1POINT2 | AV_CH_TOP_BACK_LEFT | AV_CH_TOP_BACK_RIGHT; +#[cfg(feature = "ffmpeg_7_0")] +pub const AV_CH_LAYOUT_7POINT2POINT3: u64 = + AV_CH_LAYOUT_7POINT1POINT2 | AV_CH_TOP_BACK_CENTER | AV_CH_LOW_FREQUENCY_2; +#[cfg(feature = "ffmpeg_7_0")] +pub const AV_CH_LAYOUT_9POINT1POINT4_BACK: u64 = + AV_CH_LAYOUT_7POINT1POINT4_BACK | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER; pub const AV_CH_LAYOUT_HEXADECAGONAL: u64 = AV_CH_LAYOUT_OCTAGONAL | AV_CH_WIDE_LEFT | AV_CH_WIDE_RIGHT @@ -285,6 +292,12 @@ pub const AV_CHANNEL_LAYOUT_7POINT1POINT2: AVChannelLayout = AV_CHANNEL_LAYOUT_MASK(10, AV_CH_LAYOUT_7POINT1POINT2); pub const AV_CHANNEL_LAYOUT_7POINT1POINT4_BACK: AVChannelLayout = AV_CHANNEL_LAYOUT_MASK(12, AV_CH_LAYOUT_7POINT1POINT4_BACK); +#[cfg(feature = "ffmpeg_7_0")] +pub const AV_CHANNEL_LAYOUT_7POINT2POINT3: AVChannelLayout = + AV_CHANNEL_LAYOUT_MASK(12, AV_CH_LAYOUT_7POINT2POINT3); +#[cfg(feature = "ffmpeg_7_0")] +pub const AV_CHANNEL_LAYOUT_9POINT1POINT4_BACK: AVChannelLayout = + AV_CHANNEL_LAYOUT_MASK(14, AV_CH_LAYOUT_9POINT1POINT4_BACK); pub const AV_CHANNEL_LAYOUT_HEXADECAGONAL: AVChannelLayout = AV_CHANNEL_LAYOUT_MASK(16, AV_CH_LAYOUT_HEXADECAGONAL); pub const AV_CHANNEL_LAYOUT_STEREO_DOWNMIX: AVChannelLayout = diff --git a/ffmpeg-sys-the-third/src/avutil/rational.rs b/ffmpeg-sys-the-third/src/avutil/rational.rs index a1e057d..73e7c83 100644 --- a/ffmpeg-sys-the-third/src/avutil/rational.rs +++ b/ffmpeg-sys-the-third/src/avutil/rational.rs @@ -1,5 +1,5 @@ -use libc::{c_double, c_int}; use crate::AVRational; +use libc::{c_double, c_int}; #[inline(always)] pub unsafe fn av_make_q(num: c_int, den: c_int) -> AVRational { diff --git a/src/codec/audio.rs b/src/codec/audio.rs index 87c8edb..0e7988a 100644 --- a/src/codec/audio.rs +++ b/src/codec/audio.rs @@ -2,7 +2,10 @@ use std::ops::Deref; use super::codec::Codec; use crate::ffi::*; -use crate::{format, ChannelLayoutMask}; +use crate::format; + +#[cfg(not(feature = "ffmpeg_7_0"))] +use crate::ChannelLayoutMask; #[derive(PartialEq, Eq, Copy, Clone)] pub struct Audio { @@ -36,6 +39,7 @@ impl Audio { } } + #[cfg(not(feature = "ffmpeg_7_0"))] pub fn channel_layouts(&self) -> Option { unsafe { if (*self.codec.as_ptr()).channel_layouts.is_null() { @@ -116,10 +120,12 @@ impl Iterator for FormatIter { } } +#[cfg(not(feature = "ffmpeg_7_0"))] pub struct ChannelLayoutMaskIter { ptr: *const u64, } +#[cfg(not(feature = "ffmpeg_7_0"))] impl ChannelLayoutMaskIter { pub fn new(ptr: *const u64) -> Self { ChannelLayoutMaskIter { ptr } @@ -136,6 +142,7 @@ impl ChannelLayoutMaskIter { } } +#[cfg(not(feature = "ffmpeg_7_0"))] impl Iterator for ChannelLayoutMaskIter { type Item = ChannelLayoutMask; @@ -171,6 +178,18 @@ mod ch_layout { } } + impl<'a> ChannelLayoutIter<'a> { + pub fn best(self, max: u32) -> ChannelLayout<'a> { + self.fold(ChannelLayout::MONO, |acc, cur| { + if cur.channels() > acc.channels() && cur.channels() <= max { + cur + } else { + acc + } + }) + } + } + impl<'a> Iterator for ChannelLayoutIter<'a> { type Item = ChannelLayout<'a>; diff --git a/src/codec/decoder/audio.rs b/src/codec/decoder/audio.rs index 3e65e4a..159483a 100644 --- a/src/codec/decoder/audio.rs +++ b/src/codec/decoder/audio.rs @@ -10,13 +10,16 @@ use crate::codec::Context; #[cfg(not(feature = "ffmpeg_5_0"))] use crate::frame; use crate::util::format; +use crate::AudioService; #[cfg(not(feature = "ffmpeg_5_0"))] use crate::{packet, Error}; -use crate::{AudioService, ChannelLayoutMask}; #[cfg(feature = "ffmpeg_5_1")] use crate::ChannelLayout; +#[cfg(not(feature = "ffmpeg_7_0"))] +use crate::ChannelLayoutMask; + pub struct Audio(pub Opened); impl Audio { @@ -50,6 +53,7 @@ impl Audio { unsafe { (*self.as_ptr()).sample_rate as u32 } } + #[cfg(not(feature = "ffmpeg_7_0"))] pub fn channels(&self) -> u16 { unsafe { (*self.as_ptr()).channels as u16 } } @@ -64,6 +68,7 @@ impl Audio { } } + #[cfg(not(feature = "ffmpeg_7_0"))] pub fn frames(&self) -> usize { unsafe { (*self.as_ptr()).frame_number as usize } } @@ -72,16 +77,19 @@ impl Audio { unsafe { (*self.as_ptr()).block_align as usize } } + #[cfg(not(feature = "ffmpeg_7_0"))] pub fn channel_layout(&self) -> ChannelLayoutMask { unsafe { ChannelLayoutMask::from_bits_truncate((*self.as_ptr()).channel_layout) } } + #[cfg(not(feature = "ffmpeg_7_0"))] pub fn set_channel_layout(&mut self, value: ChannelLayoutMask) { unsafe { (*self.as_mut_ptr()).channel_layout = value.bits(); } } + #[cfg(not(feature = "ffmpeg_7_0"))] pub fn request_channel_layout(&mut self, value: ChannelLayoutMask) { unsafe { (*self.as_mut_ptr()).request_channel_layout = value.bits(); diff --git a/src/codec/decoder/video.rs b/src/codec/decoder/video.rs index e0d746d..c54a202 100644 --- a/src/codec/decoder/video.rs +++ b/src/codec/decoder/video.rs @@ -84,6 +84,7 @@ impl Video { unsafe { chroma::Location::from((*self.as_ptr()).chroma_sample_location) } } + #[cfg(not(feature = "ffmpeg_7_0"))] pub fn set_slice_count(&mut self, value: usize) { unsafe { (*self.as_mut_ptr()).slice_count = value as c_int; diff --git a/src/codec/encoder/audio.rs b/src/codec/encoder/audio.rs index 9f521c3..1f17bd2 100644 --- a/src/codec/encoder/audio.rs +++ b/src/codec/encoder/audio.rs @@ -10,11 +10,14 @@ use crate::codec::{traits, Context}; use crate::util::format; #[cfg(not(feature = "ffmpeg_5_0"))] use crate::{frame, packet}; -use crate::{ChannelLayoutMask, Dictionary, Error}; +use crate::{Dictionary, Error}; #[cfg(feature = "ffmpeg_5_1")] use crate::ChannelLayout; +#[cfg(not(feature = "ffmpeg_7_0"))] +use crate::ChannelLayoutMask; + pub struct Audio(pub Super); impl Audio { @@ -96,22 +99,26 @@ impl Audio { unsafe { format::Sample::from((*self.as_ptr()).sample_fmt) } } + #[cfg(not(feature = "ffmpeg_7_0"))] pub fn set_channel_layout(&mut self, value: ChannelLayoutMask) { unsafe { (*self.as_mut_ptr()).channel_layout = value.bits(); } } + #[cfg(not(feature = "ffmpeg_7_0"))] pub fn channel_layout(&self) -> ChannelLayoutMask { unsafe { ChannelLayoutMask::from_bits_truncate((*self.as_ptr()).channel_layout) } } + #[cfg(not(feature = "ffmpeg_7_0"))] pub fn set_channels(&mut self, value: i32) { unsafe { (*self.as_mut_ptr()).channels = value; } } + #[cfg(not(feature = "ffmpeg_7_0"))] pub fn channels(&self) -> u16 { unsafe { (*self.as_ptr()).channels as u16 } } diff --git a/src/codec/id.rs b/src/codec/id.rs index 2c92783..3a16619 100644 --- a/src/codec/id.rs +++ b/src/codec/id.rs @@ -214,6 +214,7 @@ pub enum Id { AVRP, V012, AVUI, + #[cfg(not(feature = "ffmpeg_7_0"))] AYUV, TARGA_Y216, V308, @@ -656,10 +657,14 @@ pub enum Id { RTV1, #[cfg(feature = "ffmpeg_6_1")] VMIX, + #[cfg(feature = "ffmpeg_7_0")] + LEAD, #[cfg(feature = "ffmpeg_6_1")] AC4, #[cfg(feature = "ffmpeg_6_1")] OSQ, + #[cfg(feature = "ffmpeg_7_0")] + QOA, #[cfg(feature = "ffmpeg_6_1")] SMPTE_2038, } @@ -881,6 +886,7 @@ impl From for Id { AV_CODEC_ID_AVRP => Id::AVRP, AV_CODEC_ID_012V => Id::V012, AV_CODEC_ID_AVUI => Id::AVUI, + #[cfg(not(feature = "ffmpeg_7_0"))] AV_CODEC_ID_AYUV => Id::AYUV, AV_CODEC_ID_TARGA_Y216 => Id::TARGA_Y216, AV_CODEC_ID_V308 => Id::V308, @@ -1322,10 +1328,14 @@ impl From for Id { AV_CODEC_ID_RTV1 => Id::RTV1, #[cfg(feature = "ffmpeg_6_1")] AV_CODEC_ID_VMIX => Id::VMIX, + #[cfg(feature = "ffmpeg_7_0")] + AV_CODEC_ID_LEAD => Id::LEAD, #[cfg(feature = "ffmpeg_6_1")] AV_CODEC_ID_AC4 => Id::AC4, #[cfg(feature = "ffmpeg_6_1")] AV_CODEC_ID_OSQ => Id::OSQ, + #[cfg(feature = "ffmpeg_7_0")] + AV_CODEC_ID_QOA => Id::QOA, #[cfg(feature = "ffmpeg_6_1")] AV_CODEC_ID_SMPTE_2038 => Id::SMPTE_2038, @@ -1541,6 +1551,7 @@ impl From for AVCodecID { Id::AVRP => AV_CODEC_ID_AVRP, Id::V012 => AV_CODEC_ID_012V, Id::AVUI => AV_CODEC_ID_AVUI, + #[cfg(not(feature = "ffmpeg_7_0"))] Id::AYUV => AV_CODEC_ID_AYUV, Id::TARGA_Y216 => AV_CODEC_ID_TARGA_Y216, Id::V308 => AV_CODEC_ID_V308, @@ -1982,10 +1993,14 @@ impl From for AVCodecID { Id::RTV1 => AV_CODEC_ID_RTV1, #[cfg(feature = "ffmpeg_6_1")] Id::VMIX => AV_CODEC_ID_VMIX, + #[cfg(feature = "ffmpeg_7_0")] + Id::LEAD => AV_CODEC_ID_LEAD, #[cfg(feature = "ffmpeg_6_1")] Id::AC4 => AV_CODEC_ID_AC4, #[cfg(feature = "ffmpeg_6_1")] Id::OSQ => AV_CODEC_ID_OSQ, + #[cfg(feature = "ffmpeg_7_0")] + Id::QOA => AV_CODEC_ID_QOA, #[cfg(feature = "ffmpeg_6_1")] Id::SMPTE_2038 => AV_CODEC_ID_SMPTE_2038, } diff --git a/src/codec/packet/side_data.rs b/src/codec/packet/side_data.rs index aa2c716..cbd3ba1 100644 --- a/src/codec/packet/side_data.rs +++ b/src/codec/packet/side_data.rs @@ -57,6 +57,15 @@ pub enum Type { #[cfg(feature = "ffmpeg_5_0")] DYNAMIC_HDR10_PLUS, + + #[cfg(feature = "ffmpeg_7_0")] + IAMF_MIX_GAIN_PARAM, + #[cfg(feature = "ffmpeg_7_0")] + IAMF_DEMIXING_INFO_PARAM, + #[cfg(feature = "ffmpeg_7_0")] + IAMF_RECON_GAIN_INFO_PARAM, + #[cfg(feature = "ffmpeg_7_0")] + AMBIENT_VIEWING_ENVIRONMENT, } impl From for Type { @@ -110,6 +119,15 @@ impl From for Type { #[cfg(feature = "ffmpeg_5_0")] AV_PKT_DATA_DYNAMIC_HDR10_PLUS => Type::DYNAMIC_HDR10_PLUS, + #[cfg(feature = "ffmpeg_7_0")] + AV_PKT_DATA_IAMF_MIX_GAIN_PARAM => Type::IAMF_MIX_GAIN_PARAM, + #[cfg(feature = "ffmpeg_7_0")] + AV_PKT_DATA_IAMF_DEMIXING_INFO_PARAM => Type::IAMF_DEMIXING_INFO_PARAM, + #[cfg(feature = "ffmpeg_7_0")] + AV_PKT_DATA_IAMF_RECON_GAIN_INFO_PARAM => Type::IAMF_RECON_GAIN_INFO_PARAM, + #[cfg(feature = "ffmpeg_7_0")] + AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT => Type::AMBIENT_VIEWING_ENVIRONMENT, + #[cfg(feature = "non-exhaustive-enums")] _ => unimplemented!(), } @@ -166,6 +184,15 @@ impl From for AVPacketSideDataType { #[cfg(feature = "ffmpeg_5_0")] Type::DYNAMIC_HDR10_PLUS => AV_PKT_DATA_DYNAMIC_HDR10_PLUS, + + #[cfg(feature = "ffmpeg_7_0")] + Type::IAMF_MIX_GAIN_PARAM => AV_PKT_DATA_IAMF_MIX_GAIN_PARAM, + #[cfg(feature = "ffmpeg_7_0")] + Type::IAMF_DEMIXING_INFO_PARAM => AV_PKT_DATA_IAMF_DEMIXING_INFO_PARAM, + #[cfg(feature = "ffmpeg_7_0")] + Type::IAMF_RECON_GAIN_INFO_PARAM => AV_PKT_DATA_IAMF_RECON_GAIN_INFO_PARAM, + #[cfg(feature = "ffmpeg_7_0")] + Type::AMBIENT_VIEWING_ENVIRONMENT => AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT, } } } diff --git a/src/filter/context/context.rs b/src/filter/context/context.rs index 94ae437..dbdccae 100644 --- a/src/filter/context/context.rs +++ b/src/filter/context/context.rs @@ -2,9 +2,15 @@ use std::marker::PhantomData; use super::{Sink, Source}; use crate::ffi::*; -use crate::{format, option, ChannelLayoutMask}; +use crate::{format, option}; use libc::c_void; +#[cfg(feature = "ffmpeg_5_1")] +use crate::ChannelLayout; + +#[cfg(not(feature = "ffmpeg_7_0"))] +use crate::ChannelLayoutMask; + pub struct Context<'a> { ptr: *mut AVFilterContext, @@ -49,9 +55,15 @@ impl<'a> Context<'a> { let _ = option::Settable::set(self, "sample_rates", &i64::from(value)); } + #[cfg(not(feature = "ffmpeg_7_0"))] pub fn set_channel_layout(&mut self, value: ChannelLayoutMask) { let _ = option::Settable::set(self, "channel_layouts", &value.bits()); } + + #[cfg(feature = "ffmpeg_5_1")] + pub fn set_ch_layout(&mut self, value: ChannelLayout) { + let _ = option::Settable::set_str(self, "channel_layouts", &value.description()); + } } unsafe impl<'a> option::Target for Context<'a> { diff --git a/src/software/mod.rs b/src/software/mod.rs index 821e72e..37e477a 100644 --- a/src/software/mod.rs +++ b/src/software/mod.rs @@ -35,7 +35,7 @@ pub fn converter( #[cfg(feature = "software-resampling")] pub mod resampling; -#[cfg(feature = "software-resampling")] +#[cfg(all(feature = "software-resampling", not(feature = "ffmpeg_7_0")))] #[inline] pub fn resampler( (in_format, in_layout, in_rate): (crate::format::Sample, crate::ChannelLayoutMask, u32), @@ -45,3 +45,14 @@ pub fn resampler( in_format, in_layout, in_rate, out_format, out_layout, out_rate, ) } + +#[cfg(all(feature = "software-resampling", feature = "ffmpeg_5_1"))] +#[inline] +pub fn resampler2( + (in_format, in_layout, in_rate): (crate::format::Sample, crate::ChannelLayout, u32), + (out_format, out_layout, out_rate): (crate::format::Sample, crate::ChannelLayout, u32), +) -> Result { + resampling::Context::get2( + in_format, in_layout, in_rate, out_format, out_layout, out_rate, + ) +} diff --git a/src/software/resampling/context.rs b/src/software/resampling/context.rs index 01901cb..8a50d2a 100644 --- a/src/software/resampling/context.rs +++ b/src/software/resampling/context.rs @@ -8,6 +8,9 @@ use crate::{frame, ChannelLayoutMask, Error}; use libc::c_int; use std::ffi::c_void; +#[cfg(feature = "ffmpeg_5_1")] +use crate::ChannelLayout; + #[derive(Eq, PartialEq, Copy, Clone)] pub struct Definition { pub format: format::Sample, @@ -38,6 +41,7 @@ impl Context { impl Context { /// Create a resampler with the given definitions. + #[cfg(not(feature = "ffmpeg_7_0"))] pub fn get( src_format: format::Sample, src_channel_layout: ChannelLayoutMask, @@ -58,6 +62,7 @@ impl Context { } /// Create a resampler with the given definitions and custom options dictionary. + #[cfg(not(feature = "ffmpeg_7_0"))] pub fn get_with( src_format: format::Sample, src_channel_layout: ChannelLayoutMask, @@ -114,6 +119,90 @@ impl Context { } } + /// Create a resampler with the given definitions. + #[cfg(feature = "ffmpeg_5_1")] + pub fn get2( + src_format: format::Sample, + src_channel_layout: ChannelLayout, + src_rate: u32, + dst_format: format::Sample, + dst_channel_layout: ChannelLayout, + dst_rate: u32, + ) -> Result { + Self::get_with2( + src_format, + src_channel_layout, + src_rate, + dst_format, + dst_channel_layout, + dst_rate, + Dictionary::new(), + ) + } + + /// Create a resampler with the given definitions and custom options dictionary. + #[cfg(feature = "ffmpeg_5_1")] + pub fn get_with2( + src_format: format::Sample, + src_channel_layout: ChannelLayout, + src_rate: u32, + dst_format: format::Sample, + dst_channel_layout: ChannelLayout, + dst_rate: u32, + options: Dictionary, + ) -> Result { + unsafe { + let mut context_ptr = ptr::null_mut(); + let res = swr_alloc_set_opts2( + ptr::addr_of_mut!(context_ptr), + dst_channel_layout.as_ptr() as _, + dst_format.into(), + dst_rate as c_int, + src_channel_layout.as_ptr() as _, + src_format.into(), + src_rate as c_int, + 0, + ptr::null_mut(), + ); + + if res < 0 { + return Err(Error::from(res)); + } + + let mut opts = options.disown(); + let res = av_opt_set_dict(context_ptr as *mut c_void, &mut opts); + Dictionary::own(opts); + + if res != 0 { + return Err(Error::from(res)); + } + + if !context_ptr.is_null() { + match swr_init(context_ptr) { + e if e < 0 => Err(Error::from(e)), + + _ => Ok(Context { + ptr: context_ptr, + + input: Definition { + format: src_format, + channel_layout: src_channel_layout.mask().unwrap(), + rate: src_rate, + }, + + output: Definition { + format: dst_format, + channel_layout: dst_channel_layout.mask().unwrap(), + rate: dst_rate, + }, + }), + } + } else { + Err(Error::InvalidData) + } + } + } + /// Get the input definition. pub fn input(&self) -> &Definition { &self.input diff --git a/src/software/resampling/extensions.rs b/src/software/resampling/extensions.rs index 8e209c6..001cb6e 100644 --- a/src/software/resampling/extensions.rs +++ b/src/software/resampling/extensions.rs @@ -1,8 +1,15 @@ use super::Context; use crate::util::format; -use crate::{decoder, frame, ChannelLayoutMask, Error}; +use crate::{decoder, frame, Error}; + +#[cfg(feature = "ffmpeg_5_1")] +use crate::ChannelLayout; + +#[cfg(not(feature = "ffmpeg_7_0"))] +use crate::ChannelLayoutMask; impl frame::Audio { + #[cfg(not(feature = "ffmpeg_7_0"))] #[inline] pub fn resampler( &self, @@ -19,9 +26,28 @@ impl frame::Audio { rate, ) } + + #[cfg(feature = "ffmpeg_5_1")] + #[inline] + pub fn resampler2( + &self, + format: format::Sample, + ch_layout: ChannelLayout, + rate: u32, + ) -> Result { + Context::get2( + self.format(), + self.ch_layout(), + unsafe { (*self.as_ptr()).sample_rate as u32 }, + format, + ch_layout, + rate, + ) + } } impl decoder::Audio { + #[cfg(not(feature = "ffmpeg_7_0"))] #[inline] pub fn resampler( &self, @@ -38,4 +64,22 @@ impl decoder::Audio { rate, ) } + + #[cfg(feature = "ffmpeg_5_1")] + #[inline] + pub fn resampler2( + &self, + format: format::Sample, + ch_layout: ChannelLayout, + rate: u32, + ) -> Result { + Context::get2( + self.format(), + self.ch_layout(), + self.rate(), + format, + ch_layout, + rate, + ) + } } diff --git a/src/util/channel_layout/layout.rs b/src/util/channel_layout/layout.rs index 05b0b64..468b884 100644 --- a/src/util/channel_layout/layout.rs +++ b/src/util/channel_layout/layout.rs @@ -306,6 +306,11 @@ impl<'a> ChannelLayout<'a> { pub const _7POINT1POINT2: Scl = ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_7POINT1POINT2)); pub const _7POINT1POINT4_BACK: Scl = ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_7POINT1POINT4_BACK)); + #[cfg(feature = "ffmpeg_7_0")] + pub const _7POINT2POINT3: Scl = ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_7POINT2POINT3)); + #[cfg(feature = "ffmpeg_7_0")] + pub const _9POINT1POINT4_BACK: Scl = + ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_9POINT1POINT4_BACK)); pub const HEXADECAGONAL: Scl = ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_HEXADECAGONAL)); pub const STEREO_DOWNMIX: Scl = ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_STEREO_DOWNMIX)); pub const _22POINT2: Scl = ChannelLayout(Cow::Owned(AV_CHANNEL_LAYOUT_22POINT2)); diff --git a/src/util/channel_layout/mask.rs b/src/util/channel_layout/mask.rs index e5f8e70..5cd85ee 100644 --- a/src/util/channel_layout/mask.rs +++ b/src/util/channel_layout/mask.rs @@ -28,6 +28,7 @@ bitflags! { const SURROUND_DIRECT_LEFT = AV_CH_SURROUND_DIRECT_LEFT; const SURROUND_DIRECT_RIGHT = AV_CH_SURROUND_DIRECT_RIGHT; const LOW_FREQUENCY_2 = AV_CH_LOW_FREQUENCY_2; + #[cfg(not(feature = "ffmpeg_7_0"))] const NATIVE = AV_CH_LAYOUT_NATIVE; const MONO = AV_CH_LAYOUT_MONO; @@ -68,6 +69,10 @@ bitflags! { const _7POINT1POINT2 = AV_CH_LAYOUT_7POINT1POINT2; #[cfg(feature = "ffmpeg_5_1")] const _7POINT1POINT4_BACK = AV_CH_LAYOUT_7POINT1POINT4_BACK; + #[cfg(feature = "ffmpeg_7_0")] + const _7POINT2POINT3 = AV_CH_LAYOUT_7POINT2POINT3; + #[cfg(feature = "ffmpeg_7_0")] + const _9POINT1POINT4_BACK = AV_CH_LAYOUT_9POINT1POINT4_BACK; const HEXADECAGONAL = AV_CH_LAYOUT_HEXADECAGONAL; const STEREO_DOWNMIX = AV_CH_LAYOUT_STEREO_DOWNMIX; #[cfg(feature = "ffmpeg_5_1")] @@ -75,6 +80,7 @@ bitflags! { } } +#[cfg(not(feature = "ffmpeg_7_0"))] impl ChannelLayoutMask { #[inline] pub fn channels(&self) -> i32 { diff --git a/src/util/channel_layout/order.rs b/src/util/channel_layout/order.rs index 3abf0fe..634a45b 100644 --- a/src/util/channel_layout/order.rs +++ b/src/util/channel_layout/order.rs @@ -29,6 +29,9 @@ impl From for ChannelOrder { AV_CHANNEL_ORDER_NATIVE => Native, AV_CHANNEL_ORDER_CUSTOM => Custom, AV_CHANNEL_ORDER_AMBISONIC => Ambisonic, + #[cfg(feature = "ffmpeg_7_0")] + // Not part of the API, should never be used + FF_CHANNEL_ORDER_NB => unreachable!(), #[cfg(feature = "non-exhaustive-enums")] _ => unimplemented!(), } diff --git a/src/util/format/pixel.rs b/src/util/format/pixel.rs index a424c82..d362a73 100644 --- a/src/util/format/pixel.rs +++ b/src/util/format/pixel.rs @@ -225,7 +225,7 @@ pub enum Pixel { VIDEOTOOLBOX, // --- defaults - #[cfg(feature = "ffmpeg_4_0")] + #[cfg(all(feature = "ffmpeg_4_0", not(feature = "ffmpeg_7_0")))] XVMC, RGB32, @@ -417,6 +417,9 @@ pub enum Pixel { #[cfg(feature = "ffmpeg_6_1")] GBRAP14LE, + #[cfg(feature = "ffmpeg_7_0")] + D3D12, + #[cfg(feature = "rpi")] RPI, #[cfg(feature = "rpi")] @@ -498,7 +501,7 @@ impl From for Pixel { AV_PIX_FMT_YUVJ420P => Pixel::YUVJ420P, AV_PIX_FMT_YUVJ422P => Pixel::YUVJ422P, AV_PIX_FMT_YUVJ444P => Pixel::YUVJ444P, - #[cfg(feature = "ffmpeg_4_0")] + #[cfg(all(feature = "ffmpeg_4_0", not(feature = "ffmpeg_7_0")))] AV_PIX_FMT_XVMC => Pixel::XVMC, #[cfg(all(feature = "ff_api_xvmc", not(feature = "ffmpeg_5_0")))] AV_PIX_FMT_XVMC_MPEG2_MC => Pixel::XVMC_MPEG2_MC, @@ -825,6 +828,9 @@ impl From for Pixel { #[cfg(feature = "ffmpeg_6_1")] AV_PIX_FMT_GBRAP14LE => Pixel::GBRAP14LE, + #[cfg(feature = "ffmpeg_7_0")] + AV_PIX_FMT_D3D12 => Pixel::D3D12, + #[cfg(feature = "rpi")] AV_PIX_FMT_RPI => Pixel::RPI, #[cfg(feature = "rpi")] @@ -1062,7 +1068,7 @@ impl From for AVPixelFormat { Pixel::VIDEOTOOLBOX => AV_PIX_FMT_VIDEOTOOLBOX, // --- defaults - #[cfg(feature = "ffmpeg_4_0")] + #[cfg(all(feature = "ffmpeg_4_0", not(feature = "ffmpeg_7_0")))] Pixel::XVMC => AV_PIX_FMT_XVMC, Pixel::RGB32 => AV_PIX_FMT_RGB32, @@ -1254,6 +1260,9 @@ impl From for AVPixelFormat { #[cfg(feature = "ffmpeg_6_1")] Pixel::GBRAP14LE => AV_PIX_FMT_GBRAP14LE, + #[cfg(feature = "ffmpeg_7_0")] + Pixel::D3D12 => AV_PIX_FMT_D3D12, + #[cfg(feature = "rpi")] Pixel::RPI => AV_PIX_FMT_RPI, #[cfg(feature = "rpi")] diff --git a/src/util/frame/audio.rs b/src/util/frame/audio.rs index 2352897..5218474 100644 --- a/src/util/frame/audio.rs +++ b/src/util/frame/audio.rs @@ -6,11 +6,14 @@ use super::Frame; use crate::ffi::*; use crate::util::format; use crate::ChannelLayoutMask; -use libc::{c_int, c_ulonglong}; +use libc::c_int; #[cfg(feature = "ffmpeg_5_1")] use crate::ChannelLayout; +#[cfg(not(feature = "ffmpeg_7_0"))] +use libc::c_ulonglong; + #[derive(PartialEq, Eq)] pub struct Audio(Frame); @@ -29,7 +32,10 @@ impl Audio { ) { self.set_format(format); self.set_samples(samples); + #[cfg(not(feature = "ffmpeg_7_0"))] self.set_channel_layout(layout); + #[cfg(feature = "ffmpeg_7_0")] + self.set_ch_layout(ChannelLayout::from_mask(layout).unwrap()); av_frame_get_buffer(self.as_mut_ptr(), 0); } @@ -69,6 +75,7 @@ impl Audio { } } + #[cfg(not(feature = "ffmpeg_7_0"))] #[inline] pub fn channel_layout(&self) -> ChannelLayoutMask { unsafe { @@ -76,6 +83,7 @@ impl Audio { } } + #[cfg(not(feature = "ffmpeg_7_0"))] #[inline] pub fn set_channel_layout(&mut self, value: ChannelLayoutMask) { unsafe { @@ -97,11 +105,13 @@ impl Audio { } } + #[cfg(not(feature = "ffmpeg_7_0"))] #[inline] pub fn channels(&self) -> u16 { unsafe { (*self.as_ptr()).channels as u16 } } + #[cfg(not(feature = "ffmpeg_7_0"))] #[inline] pub fn set_channels(&mut self, value: u16) { unsafe { @@ -154,7 +164,12 @@ impl Audio { if self.is_packed() { 1 } else { - self.channels() as usize + #[cfg(not(feature = "ffmpeg_5_1"))] + let channels = self.channels() as usize; + #[cfg(feature = "ffmpeg_5_1")] + let channels = self.ch_layout().channels() as usize; + + channels } } @@ -164,7 +179,12 @@ impl Audio { panic!("out of bounds"); } - if !::is_valid(self.format(), self.channels() as u16) { + #[cfg(not(feature = "ffmpeg_5_1"))] + let channels = self.channels() as u16; + #[cfg(feature = "ffmpeg_5_1")] + let channels = self.ch_layout().channels() as u16; + + if !::is_valid(self.format(), channels) { panic!("unsupported type"); } @@ -177,7 +197,12 @@ impl Audio { panic!("out of bounds"); } - if !::is_valid(self.format(), self.channels() as u16) { + #[cfg(not(feature = "ffmpeg_5_1"))] + let channels = self.channels() as u16; + #[cfg(feature = "ffmpeg_5_1")] + let channels = self.ch_layout().channels() as u16; + + if !::is_valid(self.format(), channels) { panic!("unsupported type"); } @@ -231,9 +256,14 @@ impl DerefMut for Audio { impl ::std::fmt::Debug for Audio { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + #[cfg(not(feature = "ffmpeg_5_1"))] + let channels = self.channels() as u16; + #[cfg(feature = "ffmpeg_5_1")] + let channels = self.ch_layout().channels() as u16; + f.write_str("ffmpeg::frame::Audio { ")?; f.write_str(&format!("format: {:?}, ", self.format()))?; - f.write_str(&format!("channels: {:?}, ", self.channels()))?; + f.write_str(&format!("channels: {channels}, "))?; f.write_str(&format!("rate: {:?}, ", self.rate()))?; f.write_str(&format!("samples: {:?} ", self.samples()))?; f.write_str("}") @@ -242,7 +272,12 @@ impl ::std::fmt::Debug for Audio { impl Clone for Audio { fn clone(&self) -> Self { - let mut cloned = Audio::new(self.format(), self.samples(), self.channel_layout()); + #[cfg(not(feature = "ffmpeg_5_1"))] + let mask = self.channel_layout(); + #[cfg(feature = "ffmpeg_5_1")] + let mask = self.ch_layout().mask().unwrap(); + + let mut cloned = Audio::new(self.format(), self.samples(), mask); cloned.clone_from(self); cloned diff --git a/src/util/frame/mod.rs b/src/util/frame/mod.rs index c950ae9..0e43287 100644 --- a/src/util/frame/mod.rs +++ b/src/util/frame/mod.rs @@ -89,7 +89,10 @@ impl Frame { pub fn packet(&self) -> Packet { unsafe { Packet { + #[cfg(not(feature = "ffmpeg_7_0"))] duration: (*self.as_ptr()).pkt_duration as i64, + #[cfg(feature = "ffmpeg_7_0")] + duration: (*self.as_ptr()).duration as i64, position: (*self.as_ptr()).pkt_pos as i64, size: (*self.as_ptr()).pkt_size as usize, diff --git a/src/util/frame/video.rs b/src/util/frame/video.rs index 886fd0f..551517e 100644 --- a/src/util/frame/video.rs +++ b/src/util/frame/video.rs @@ -173,11 +173,13 @@ impl Video { unsafe { Rational::from((*self.as_ptr()).sample_aspect_ratio) } } + #[cfg(not(feature = "ffmpeg_7_0"))] #[inline] pub fn coded_number(&self) -> usize { unsafe { (*self.as_ptr()).coded_picture_number as usize } } + #[cfg(not(feature = "ffmpeg_7_0"))] #[inline] pub fn display_number(&self) -> usize { unsafe { (*self.as_ptr()).display_picture_number as usize } diff --git a/src/util/option/mod.rs b/src/util/option/mod.rs index 79fefca..6207509 100644 --- a/src/util/option/mod.rs +++ b/src/util/option/mod.rs @@ -26,9 +26,18 @@ pub enum Type { VideoRate, Duration, Color, + #[cfg(not(feature = "ffmpeg_7_0"))] ChannelLayout, + #[cfg(feature = "ffmpeg_5_1")] + ChLayout, c_ulong, bool, + + // FIXME: This is not supported yet. `enum Type` should become a bitflags struct. + // FIXME: AVOptionType is also not technically an enum because it may contain + // values that are outside the defined enum variants! + #[cfg(feature = "ffmpeg_7_0")] + ArrayFlag = 0x10000, } impl From for Type { @@ -53,9 +62,13 @@ impl From for Type { AV_OPT_TYPE_VIDEO_RATE => Type::VideoRate, AV_OPT_TYPE_DURATION => Type::Duration, AV_OPT_TYPE_COLOR => Type::Color, + #[cfg(not(feature = "ffmpeg_7_0"))] AV_OPT_TYPE_CHANNEL_LAYOUT => Type::ChannelLayout, #[cfg(feature = "ffmpeg_5_1")] - AV_OPT_TYPE_CHLAYOUT => Type::ChannelLayout, + AV_OPT_TYPE_CHLAYOUT => Type::ChLayout, + + #[cfg(feature = "ffmpeg_7_0")] + AV_OPT_TYPE_FLAG_ARRAY => Type::ArrayFlag, #[cfg(feature = "non-exhaustive-enums")] _ => unimplemented!(), @@ -85,7 +98,13 @@ impl From for AVOptionType { Type::VideoRate => AV_OPT_TYPE_VIDEO_RATE, Type::Duration => AV_OPT_TYPE_DURATION, Type::Color => AV_OPT_TYPE_COLOR, + #[cfg(not(feature = "ffmpeg_7_0"))] Type::ChannelLayout => AV_OPT_TYPE_CHANNEL_LAYOUT, + #[cfg(feature = "ffmpeg_5_1")] + Type::ChLayout => AV_OPT_TYPE_CHLAYOUT, + + #[cfg(feature = "ffmpeg_7_0")] + Type::ArrayFlag => AV_OPT_TYPE_FLAG_ARRAY, } } } diff --git a/src/util/option/traits.rs b/src/util/option/traits.rs index 223976f..c7bc66d 100644 --- a/src/util/option/traits.rs +++ b/src/util/option/traits.rs @@ -5,9 +5,12 @@ use std::mem; use crate::ffi::*; use crate::util::format; -use crate::{ChannelLayoutMask, Error, Rational}; +use crate::{Error, Rational}; use libc::{c_int, c_void}; +#[cfg(not(feature = "ffmpeg_7_0"))] +use crate::ChannelLayoutMask; + macro_rules! check { ($expr:expr) => { match $expr { @@ -130,6 +133,7 @@ pub trait Settable: Target { } } + #[cfg(not(feature = "ffmpeg_7_0"))] fn set_channel_layout(&mut self, name: &str, layout: ChannelLayoutMask) -> Result<(), Error> { unsafe { let name = CString::new(name).unwrap();