diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ceaeeef --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +**/target +test_output/ \ No newline at end of file diff --git a/Dockerfile.bookworm b/Dockerfile.bookworm new file mode 100644 index 0000000..b1a820c --- /dev/null +++ b/Dockerfile.bookworm @@ -0,0 +1,15 @@ +FROM rust:bookworm +WORKDIR /src +COPY . . +RUN apt update && apt install -y \ + build-essential \ + libavcodec-dev \ + libavformat-dev \ + libavutil-dev \ + libavdevice-dev \ + libswresample-dev \ + libswscale-dev \ + libpipewire-0.3-dev \ + libasound2-dev \ + libclang-dev +RUN cargo build --release \ No newline at end of file diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..902bfa8 --- /dev/null +++ b/build.rs @@ -0,0 +1,19 @@ +use std::env; + +fn main() { + // re-export ffmpeg-sys-the-third features + // https://github.com/FFmpeg/FFmpeg/blob/master/doc/APIchanges + for (name, _value) in env::vars() { + if name.starts_with("DEP_FFMPEG_CHECK_") { + println!( + r#"cargo:rustc-check-cfg=cfg(feature, values("{}"))"#, + name["DEP_FFMPEG_CHECK_".len()..name.len()].to_lowercase() + ); + } else if name.starts_with("DEP_FFMPEG_") { + println!( + r#"cargo:rustc-cfg=feature="{}""#, + name["DEP_FFMPEG_".len()..name.len()].to_lowercase() + ); + } + } +} diff --git a/src/audio_fifo.rs b/src/audio_fifo.rs index b912cd4..794a5ef 100644 --- a/src/audio_fifo.rs +++ b/src/audio_fifo.rs @@ -30,11 +30,12 @@ impl AudioFifo { av_audio_fifo_realloc(self.ctx, av_audio_fifo_size(self.ctx) + (*frame).nb_samples); bail_ffmpeg!(ret); - ret = av_audio_fifo_write( - self.ctx, - (*frame).extended_data as *const _, - (*frame).nb_samples, - ); + #[cfg(feature = "avutil_version_greater_than_58_22")] + let buf_ptr = (*frame).extended_data as *const _; + #[cfg(not(feature = "avutil_version_greater_than_58_22"))] + let buf_ptr = (*frame).extended_data as *mut _; + + ret = av_audio_fifo_write(self.ctx, buf_ptr, (*frame).nb_samples); bail_ffmpeg!(ret); if av_audio_fifo_size(self.ctx) >= samples_out as _ { @@ -47,12 +48,12 @@ impl AudioFifo { ret = av_frame_get_buffer(out_frame, 0); bail_ffmpeg!(ret, { av_frame_free(&mut out_frame) }); - if av_audio_fifo_read( - self.ctx, - (*out_frame).extended_data as *mut _, - samples_out as _, - ) < samples_out as _ - { + #[cfg(feature = "avutil_version_greater_than_58_22")] + let buf_ptr = (*out_frame).extended_data as *const _; + #[cfg(not(feature = "avutil_version_greater_than_58_22"))] + let buf_ptr = (*out_frame).extended_data as *mut _; + + if av_audio_fifo_read(self.ctx, buf_ptr, samples_out as _) < samples_out as _ { av_frame_free(&mut out_frame); bail!("Failed to read audio frame"); } diff --git a/src/demux.rs b/src/demux.rs index 8935689..a6f5c50 100644 --- a/src/demux.rs +++ b/src/demux.rs @@ -1,6 +1,9 @@ -use crate::{bail_ffmpeg, cstr, rstr, StreamGroupInfo, StreamGroupType}; +use crate::{bail_ffmpeg, cstr, rstr}; use crate::{DemuxerInfo, StreamInfo, StreamType}; +#[cfg(feature = "avformat_version_greater_than_60_19")] +use crate::{StreamGroupInfo, StreamGroupType}; use anyhow::{bail, Error, Result}; +#[cfg(feature = "avformat_version_greater_than_60_22")] use ffmpeg_sys_the_third::AVStreamGroupParamsType::AV_STREAM_GROUP_PARAMS_TILE_GRID; use ffmpeg_sys_the_third::*; use log::warn; @@ -124,13 +127,16 @@ impl Demuxer { } let mut streams = vec![]; + #[cfg(feature = "avformat_version_greater_than_60_19")] let mut stream_groups = vec![]; let mut n_stream = 0; + #[cfg(feature = "avformat_version_greater_than_60_19")] for n in 0..(*self.ctx).nb_stream_groups as usize { let group = *(*self.ctx).stream_groups.add(n); n_stream += (*group).nb_streams as usize; match (*group).type_ { + #[cfg(feature = "avformat_version_greater_than_60_22")] AV_STREAM_GROUP_PARAMS_TILE_GRID => { let tg = (*group).params.tile_grid; let codec_par = (*(*(*group).streams.add(0))).codecpar; @@ -216,6 +222,7 @@ impl Demuxer { duration: (*self.ctx).duration as f32 / AV_TIME_BASE as f32, bitrate: (*self.ctx).bit_rate as usize, streams, + #[cfg(feature = "avformat_version_greater_than_60_19")] groups: stream_groups, }; Ok(info) @@ -255,6 +262,7 @@ impl Drop for Demuxer { mod tests { use super::*; + #[cfg(feature = "avformat_version_greater_than_60_19")] #[test] #[ignore] fn test_stream_groups() -> Result<()> { diff --git a/src/encode.rs b/src/encode.rs index 63c5d5f..45ca327 100644 --- a/src/encode.rs +++ b/src/encode.rs @@ -4,10 +4,13 @@ use ffmpeg_sys_the_third::AVPictureType::AV_PICTURE_TYPE_NONE; use ffmpeg_sys_the_third::{ av_channel_layout_default, av_d2q, av_inv_q, av_packet_alloc, av_packet_free, avcodec_alloc_context3, avcodec_find_encoder, avcodec_find_encoder_by_name, - avcodec_free_context, avcodec_get_supported_config, avcodec_open2, avcodec_receive_packet, - avcodec_send_frame, AVChannelLayout, AVCodec, AVCodecConfig, AVCodecContext, AVCodecID, - AVFrame, AVPacket, AVPixelFormat, AVRational, AVSampleFormat, AVERROR, AVERROR_EOF, + avcodec_free_context, avcodec_open2, avcodec_receive_packet, avcodec_send_frame, + AVChannelLayout, AVCodec, AVCodecContext, AVCodecID, AVFrame, AVPacket, AVPixelFormat, + AVRational, AVSampleFormat, AVERROR, AVERROR_EOF, }; +#[cfg(feature = "avcodec_version_greater_than_61_13")] +use ffmpeg_sys_the_third::{avcodec_get_supported_config, AVCodecConfig}; + use libc::EAGAIN; use std::collections::HashMap; use std::io::Write; @@ -79,6 +82,7 @@ impl Encoder { self.ctx } + #[cfg(feature = "avcodec_version_greater_than_61_13")] /// List supported configs (see [avcodec_get_supported_config]) pub unsafe fn list_configs<'a, T>(&mut self, cfg: AVCodecConfig) -> Result<&'a [T], Error> { let mut dst = ptr::null_mut(); @@ -261,6 +265,7 @@ impl Encoder { mod tests { use super::*; use crate::generate_test_frame; + use ffmpeg_sys_the_third::AVPixelFormat::AV_PIX_FMT_YUV420P; #[test] fn test_encode_png() -> Result<(), Error> { @@ -270,8 +275,12 @@ mod tests { .with_width((*frame).width) .with_height((*frame).height); + #[cfg(feature = "avcodec_version_greater_than_61_13")] let pix_fmts: &[AVPixelFormat] = encoder.list_configs(AVCodecConfig::AV_CODEC_CONFIG_PIX_FORMAT)?; + #[cfg(not(feature = "avcodec_version_greater_than_61_13"))] + let pix_fmts = [AV_PIX_FMT_YUV420P]; + encoder = encoder.with_pix_fmt(pix_fmts[0]).open(None)?; std::fs::create_dir_all("test_output")?; diff --git a/src/mux.rs b/src/mux.rs index 68707fd..5049f20 100644 --- a/src/mux.rs +++ b/src/mux.rs @@ -14,7 +14,8 @@ use std::{ptr, slice}; unsafe extern "C" fn write_data( opaque: *mut libc::c_void, - buffer: *const u8, + #[cfg(feature = "avformat_version_greater_than_60_12")] buffer: *const u8, + #[cfg(not(feature = "avformat_version_greater_than_60_12"))] buffer: *mut u8, size: libc::c_int, ) -> libc::c_int where diff --git a/src/resample.rs b/src/resample.rs index a0f4c55..9bbe413 100644 --- a/src/resample.rs +++ b/src/resample.rs @@ -5,7 +5,6 @@ use ffmpeg_sys_the_third::{ swr_alloc_set_opts2, swr_convert_frame, swr_free, swr_init, AVChannelLayout, AVFrame, AVSampleFormat, SwrContext, }; -use libc::malloc; use std::mem::transmute; use std::ptr; @@ -40,15 +39,15 @@ impl Resample { if !self.ctx.is_null() { return Ok(()); } - let layout = malloc(size_of::()) as *mut AVChannelLayout; - av_channel_layout_default(layout, self.channels as libc::c_int); + let mut layout = AVChannelLayout::empty(); + av_channel_layout_default(&mut layout, self.channels as libc::c_int); let ret = swr_alloc_set_opts2( &mut self.ctx, - layout, + ptr::addr_of_mut!(layout), self.format, self.sample_rate as libc::c_int, - &(*frame).ch_layout, + ptr::addr_of_mut!((*frame).ch_layout), transmute((*frame).format), (*frame).sample_rate, 0, @@ -63,10 +62,7 @@ impl Resample { } /// Resample an audio frame - pub unsafe fn process_frame( - &mut self, - frame: *mut AVFrame - ) -> Result<*mut AVFrame, Error> { + pub unsafe fn process_frame(&mut self, frame: *mut AVFrame) -> Result<*mut AVFrame, Error> { if !(*frame).hw_frames_ctx.is_null() { anyhow::bail!("Hardware frames are not supported in this software re-sampler"); } diff --git a/src/stream_info.rs b/src/stream_info.rs index 36607cc..994a992 100644 --- a/src/stream_info.rs +++ b/src/stream_info.rs @@ -1,8 +1,10 @@ use crate::{format_time, rstr}; +#[cfg(feature = "avformat_version_greater_than_60_19")] +use ffmpeg_sys_the_third::AVStreamGroup; use ffmpeg_sys_the_third::{ av_get_pix_fmt_name, av_get_sample_fmt_name, avcodec_get_name, AVMediaType, AVStream, - AVStreamGroup, }; + use std::fmt::{Display, Formatter}; use std::intrinsics::transmute; @@ -11,6 +13,7 @@ pub struct DemuxerInfo { pub bitrate: usize, pub duration: f32, pub streams: Vec, + #[cfg(feature = "avformat_version_greater_than_60_19")] pub groups: Vec, } @@ -178,6 +181,7 @@ impl Display for StreamInfo { } } +#[cfg(feature = "avformat_version_greater_than_60_19")] #[derive(Clone, Debug, PartialEq)] pub enum StreamGroupType { TileGrid { @@ -189,6 +193,7 @@ pub enum StreamGroupType { }, } +#[cfg(feature = "avformat_version_greater_than_60_19")] #[derive(Clone, Debug, PartialEq)] pub struct StreamGroupInfo { pub index: usize, @@ -198,4 +203,5 @@ pub struct StreamGroupInfo { pub(crate) group: *mut AVStreamGroup, } +#[cfg(feature = "avformat_version_greater_than_60_19")] unsafe impl Send for StreamGroupInfo {}