Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix CI, fix or workaround build errors pre-FFmpeg 6.0 #187

Merged
merged 8 commits into from
Dec 7, 2024
26 changes: 15 additions & 11 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
name: Tests

on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
- push
- pull_request

env:
CARGO_TERM_COLOR: always

jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
include:
- os: ubuntu-24.04 # "noble", ffmpeg 6.1
ffmpeg_feature: "ffmpeg_6_0"
- os: ubuntu-22.04 # "jammy", ffmpeg 4.4
ffmpeg_feature: "ffmpeg_4_4"
runs-on: ${{ matrix.os }}
steps:
- name: Install ffmpeg
run: sudo apt-get -y install ffmpeg pkg-config libavutil-dev libavformat-dev libavfilter-dev libavdevice-dev
- uses: actions/checkout@v4
- name: Run tests
run: cargo test --all --verbose --features=ffmpeg_4_4
- name: Install ffmpeg
run: sudo apt-get -y install ffmpeg pkg-config libavutil-dev libavformat-dev libavfilter-dev libavdevice-dev
- uses: actions/checkout@v4
- name: Run tests
run: cargo test --all --verbose --features=${{ matrix.ffmpeg_feature }}
21 changes: 12 additions & 9 deletions examples/codec-info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,18 @@ fn print_codec(codec: Codec) {
println!("\t formats: any");
}

if let Some(layouts) = audio.channel_layouts() {
println!("\t channel_layouts:");
for layout in layouts {
println!("\t\t {}", layout.describe().unwrap());
}
}
else {
println!("\t channel_layouts: any");
}
#[cfg(feature = "ffmpeg_6_0")]
{
if let Some(layouts) = audio.channel_layouts() {
println!("\t channel_layouts:");
for layout in layouts {
println!("\t\t {}", layout.describe().unwrap());
}
}
else {
println!("\t channel_layouts: any");
}
}
}

println!("\t max_lowres: {:?}", codec.max_lowres());
Expand Down
1 change: 1 addition & 0 deletions examples/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ fn main() {
println!("\taudio.format: {:?}", audio.format());
println!("\taudio.frames: {}", audio.frames());
println!("\taudio.align: {}", audio.align());
#[cfg(feature = "ffmpeg_6_0")]
println!("\taudio.channel_layout: {:?}", audio.channel_layout());
}
}
Expand Down
36 changes: 25 additions & 11 deletions examples/transcode-audio.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::{env, path::Path};

use ffmpeg::{channel_layout::ChannelLayout, codec, filter, format, frame, media, rescale, Rescale};
use ffmpeg::{codec, filter, format, frame, media, rescale, Rescale};
#[cfg(feature = "ffmpeg_6_0")]
use ffmpeg::channel_layout::{self, ChannelLayout};

fn filter(
spec: &str,
Expand All @@ -9,12 +11,20 @@ fn filter(
) -> Result<filter::Graph, ffmpeg::Error> {
let mut filter = filter::Graph::new();

#[cfg(feature = "ffmpeg_6_0")]
let channel_layout_arg = format!(":channel_layout={}",
decoder.channel_layout().describe().unwrap());

// Not yet implemented for older versions
#[cfg(not(feature = "ffmpeg_6_0"))]
let channel_layout_arg = "";

let args = format!(
"time_base={}:sample_rate={}:sample_fmt={}:channel_layout={}",
"time_base={}:sample_rate={}:sample_fmt={}{}",
decoder.time_base().unwrap(),
decoder.sample_rate(),
decoder.format().name(),
decoder.channel_layout().describe().unwrap()
channel_layout_arg
);

filter.add(&filter::find("abuffer").unwrap(), "in", &args)?;
Expand All @@ -24,6 +34,7 @@ fn filter(
let mut out = filter.get("out").unwrap();

out.set_sample_format(encoder.format());
#[cfg(feature = "ffmpeg_6_0")]
out.set_channel_layout(encoder.channel_layout());
out.set_sample_rate(encoder.sample_rate());
}
Expand Down Expand Up @@ -78,22 +89,25 @@ fn transcoder<P: AsRef<Path>>(
let mut output = octx.add_stream()?;
let mut encoder = codec::Encoder::new(codec)?.audio()?;

let channel_layout = codec
.channel_layouts()
.map(|cls| cls.best(decoder.channel_layout().channels()))
.unwrap_or(ChannelLayout::STEREO);

if global {
encoder.set_flags(ffmpeg::codec::flag::Flags::GLOBAL_HEADER);
}

encoder.set_sample_rate(decoder.sample_rate());
encoder.set_channel_layout(channel_layout);
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());

#[cfg(feature = "ffmpeg_6_0")]
{
let channel_layout = codec
.channel_layouts()
.map(|cls| cls.best(decoder.channel_layout().channels()))
.unwrap_or(ChannelLayout::STEREO);

encoder.set_channel_layout(channel_layout);
encoder.set_channels(channel_layout.channels());
}

let enc_tb = (1, decoder.sample_rate() as i32);
encoder.set_time_base(Some(enc_tb));
output.set_time_base(Some(enc_tb));
Expand Down
4 changes: 4 additions & 0 deletions src/codec/audio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ impl Audio {
}
}

#[cfg(feature = "ffmpeg_6_0")]
pub fn channel_layouts(&self) -> Option<ChannelLayoutIter> {
unsafe {
(!(*self.codec.as_ptr()).ch_layouts.is_null()).then(|| ChannelLayoutIter {
Expand Down Expand Up @@ -99,11 +100,13 @@ impl Iterator for FormatIter<'_> {
}
}

#[cfg(feature = "ffmpeg_6_0")]
pub struct ChannelLayoutIter<'a> {
inner: &'a Audio,
next_idx: isize,
}

#[cfg(feature = "ffmpeg_6_0")]
impl ChannelLayoutIter<'_> {
pub fn best(self, max: i32) -> ChannelLayout {
self.fold(crate::channel_layout::ChannelLayout::MONO, |acc, cur| {
Expand All @@ -117,6 +120,7 @@ impl ChannelLayoutIter<'_> {
}
}

#[cfg(feature = "ffmpeg_6_0")]
impl Iterator for ChannelLayoutIter<'_> {
type Item = ChannelLayout;

Expand Down
2 changes: 2 additions & 0 deletions src/codec/decoder/audio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ impl Audio {
unsafe { (*self.as_ptr()).block_align as usize }
}

#[cfg(feature = "ffmpeg_6_0")]
pub fn channel_layout(&self) -> ChannelLayout {
unsafe { (*self.as_ptr()).ch_layout.into() }
}

#[cfg(feature = "ffmpeg_6_0")]
pub fn set_channel_layout(&mut self, value: ChannelLayout) {
unsafe {
(*self.as_mut_ptr()).ch_layout = value.into();
Expand Down
2 changes: 2 additions & 0 deletions src/codec/encoder/audio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,14 @@ impl Audio {
unsafe { format::Sample::from((*self.as_ptr()).sample_fmt) }
}

#[cfg(feature = "ffmpeg_6_0")]
pub fn set_channel_layout(&mut self, value: ChannelLayout) {
unsafe {
(*self.as_mut_ptr()).ch_layout = value.into();
}
}

#[cfg(feature = "ffmpeg_6_0")]
pub fn channel_layout(&self) -> ChannelLayout {
unsafe { (*self.as_ptr()).ch_layout.into() }
}
Expand Down
4 changes: 4 additions & 0 deletions src/codec/packet/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,13 @@ impl Packet {
}

#[inline]
#[cfg(feature = "ffmpeg_5_0")]
pub fn time_base(&self) -> Option<Rational> {
Rational::from(self.0.time_base).non_zero()
}

#[inline]
#[cfg(feature = "ffmpeg_5_0")]
pub fn set_time_base(&mut self, time_base: Option<impl Into<Rational>>) {
self.0.time_base = time_base.map(Into::into).unwrap_or(Rational::ZERO).into();
}
Expand Down Expand Up @@ -255,11 +257,13 @@ impl Packet {
}

#[inline]
#[cfg(feature = "ffmpeg_5_0")]
pub fn opaque(&self) -> *mut c_void {
unsafe { (*self.as_ptr()).opaque }
}

#[inline]
#[cfg(feature = "ffmpeg_5_0")]
pub fn set_opaque(&mut self, data: *mut c_void) {
unsafe {
(*self.as_mut_ptr()).opaque = data;
Expand Down
8 changes: 8 additions & 0 deletions src/device/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ impl Iterator for AudioIter {

fn next(&mut self) -> Option<<Self as Iterator>::Item> {
unsafe {
#[cfg(feature = "ffmpeg_5_0")]
let ptr = av_input_audio_device_next(self.0);

#[cfg(not(feature = "ffmpeg_5_0"))]
let ptr = av_input_audio_device_next(self.0.cast_mut());

if ptr.is_null() && !self.0.is_null() {
None
}
Expand All @@ -34,8 +38,12 @@ impl Iterator for VideoIter {

fn next(&mut self) -> Option<<Self as Iterator>::Item> {
unsafe {
#[cfg(feature = "ffmpeg_5_0")]
let ptr = av_input_video_device_next(self.0);

#[cfg(not(feature = "ffmpeg_5_0"))]
let ptr = av_input_video_device_next(self.0.cast_mut());

if ptr.is_null() && !self.0.is_null() {
None
}
Expand Down
8 changes: 8 additions & 0 deletions src/device/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ impl Iterator for AudioIter {

fn next(&mut self) -> Option<<Self as Iterator>::Item> {
unsafe {
#[cfg(feature = "ffmpeg_5_0")]
let ptr = av_output_audio_device_next(self.0);

#[cfg(not(feature = "ffmpeg_5_0"))]
let ptr = av_output_audio_device_next(self.0.cast_mut());

if ptr.is_null() && !self.0.is_null() {
None
}
Expand All @@ -34,8 +38,12 @@ impl Iterator for VideoIter {

fn next(&mut self) -> Option<<Self as Iterator>::Item> {
unsafe {
#[cfg(feature = "ffmpeg_5_0")]
let ptr = av_output_video_device_next(self.0);

#[cfg(not(feature = "ffmpeg_5_0"))]
let ptr = av_output_video_device_next(self.0.cast_mut());

if ptr.is_null() && !self.0.is_null() {
None
}
Expand Down
16 changes: 14 additions & 2 deletions src/filter/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,17 @@ impl Filter {
unsafe {
let ptr = (*self.as_ptr()).inputs;

#[cfg(feature = "ffmpeg_5_0")]
let count = (*self.as_ptr()).nb_inputs;

#[cfg(not(feature = "ffmpeg_5_0"))]
let count = avfilter_pad_count((*self.as_ptr()).inputs);

if ptr.is_null() {
None
}
else {
Some(PadIter::new(ptr, (*self.as_ptr()).nb_inputs as usize))
Some(PadIter::new(ptr, count as usize))
}
}
}
Expand All @@ -56,11 +62,17 @@ impl Filter {
unsafe {
let ptr = (*self.as_ptr()).outputs;

#[cfg(feature = "ffmpeg_5_0")]
let count = (*self.as_ptr()).nb_outputs;

#[cfg(not(feature = "ffmpeg_5_0"))]
let count = avfilter_pad_count((*self.as_ptr()).outputs);

if ptr.is_null() {
None
}
else {
Some(PadIter::new(ptr, (*self.as_ptr()).nb_outputs as usize))
Some(PadIter::new(ptr, count as usize))
}
}
}
Expand Down
8 changes: 7 additions & 1 deletion src/format/chapter/chapter.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
use crate::{ffi::*, format::context::common::Context, DictionaryRef, Rational};

#[cfg(feature = "ffmpeg_5_0")]
pub type ChapterId = i64;

#[cfg(not(feature = "ffmpeg_5_0"))]
pub type ChapterId = i32;

// WARNING: index refers to the offset in the chapters array (starting from 0)
// it is not necessarly equal to the id (which may start at 1)
pub struct Chapter<'a> {
Expand All @@ -22,7 +28,7 @@ impl<'a> Chapter<'a> {
self.index
}

pub fn id(&self) -> i64 {
pub fn id(&self) -> ChapterId {
unsafe { (*self.as_ptr()).id }
}

Expand Down
4 changes: 2 additions & 2 deletions src/format/chapter/chapter_mut.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{mem, ops::Deref};

use super::Chapter;
use super::{ChapterId, Chapter};
use crate::{ffi::*, format::context::common::Context, Dictionary, DictionaryMut, Rational};

// WARNING: index refers to the offset in the chapters array (starting from 0)
Expand Down Expand Up @@ -28,7 +28,7 @@ impl<'a> ChapterMut<'a> {
}

impl<'a> ChapterMut<'a> {
pub fn set_id(&mut self, value: i64) {
pub fn set_id(&mut self, value: ChapterId) {
unsafe {
(*self.as_mut_ptr()).id = value;
}
Expand Down
1 change: 1 addition & 0 deletions src/format/chapter/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod chapter;
pub use self::chapter::Chapter;
pub use self::chapter::ChapterId;

mod chapter_mut;
pub use self::chapter_mut::ChapterMut;
7 changes: 6 additions & 1 deletion src/format/context/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,13 +172,18 @@ impl<'a> Best<'a> {
'a: 'b,
{
unsafe {
#[cfg(feature = "ffmpeg_5_0")]
let mut decoder = ptr::null::<AVCodec>();

#[cfg(not(feature = "ffmpeg_5_0"))]
let mut decoder = ptr::null_mut::<AVCodec>();

let index = av_find_best_stream(
self.context.ptr,
kind.into(),
self.wanted as c_int,
self.related as c_int,
&mut decoder as *mut _,
&mut decoder as *mut _,
0,
);

Expand Down
Loading