11//! RIIR: https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/resample_audio.c
22use rsmpeg:: {
3- avutil:: { AVChannelLayout , AVFrame } ,
4- ffi,
3+ avutil:: { av_rescale_rnd , get_bytes_per_sample , AVChannelLayout , AVSamples } ,
4+ ffi:: { self , AV_CHANNEL_LAYOUT_STEREO , AV_CHANNEL_LAYOUT_SURROUND } ,
55 swresample:: SwrContext ,
66} ;
7- use std:: io:: Write ;
7+ use std:: { f64:: consts:: PI , io:: Write } ;
8+
9+ fn get_format_from_sample_fmt ( sample_fmt : ffi:: AVSampleFormat ) -> Option < & ' static str > {
10+ #[ cfg( target_endian = "big" ) ]
11+ let sample_fmt_entries = [
12+ ( ffi:: AV_SAMPLE_FMT_U8 , "u8" ) ,
13+ ( ffi:: AV_SAMPLE_FMT_S16 , "s16be" ) ,
14+ ( ffi:: AV_SAMPLE_FMT_S32 , "s32be" ) ,
15+ ( ffi:: AV_SAMPLE_FMT_FLT , "f32be" ) ,
16+ ( ffi:: AV_SAMPLE_FMT_DBL , "f64be" ) ,
17+ ] ;
18+ #[ cfg( target_endian = "little" ) ]
19+ let sample_fmt_entries = [
20+ ( ffi:: AV_SAMPLE_FMT_U8 , "u8" ) ,
21+ ( ffi:: AV_SAMPLE_FMT_S16 , "s16le" ) ,
22+ ( ffi:: AV_SAMPLE_FMT_S32 , "s32le" ) ,
23+ ( ffi:: AV_SAMPLE_FMT_FLT , "f32le" ) ,
24+ ( ffi:: AV_SAMPLE_FMT_DBL , "f64le" ) ,
25+ ] ;
26+ sample_fmt_entries
27+ . iter ( )
28+ . find ( |( fmt, _) | * fmt == sample_fmt)
29+ . map ( |( _, fmt) | * fmt)
30+ }
831
932fn fill_samples (
1033 buf : & mut [ f64 ] ,
@@ -14,7 +37,7 @@ fn fill_samples(
1437 t : & mut f64 ,
1538) {
1639 let tincr = 1.0 / sample_rate as f64 ;
17- let c = 2.0 * std :: f64 :: consts :: PI * 440.0 ;
40+ let c = 2.0 * PI * 440.0 ;
1841 let mut dstp = buf. as_mut_ptr ( ) ;
1942 for _ in 0 ..nb_samples {
2043 unsafe {
@@ -29,52 +52,118 @@ fn fill_samples(
2952}
3053
3154pub fn resample_audio_run ( out_path : & str ) -> anyhow:: Result < usize > {
32- // src: stereo dbl 48k, dst: 5.1 s16 44.1k
33- let src_ch = AVChannelLayout :: from_nb_channels ( 2 ) ;
34- let dst_ch = AVChannelLayout :: from_nb_channels ( 6 ) ;
55+ // Match C example: src=stereo 48kHz DBL, dst=surround 44.1kHz S16
56+ let src_ch_layout = unsafe { AVChannelLayout :: new ( AV_CHANNEL_LAYOUT_STEREO ) } ; // stereo
57+ let dst_ch_layout = unsafe { AVChannelLayout :: new ( AV_CHANNEL_LAYOUT_SURROUND ) } ; // surround
58+ let src_rate = 48000 ;
59+ let dst_rate = 44100 ;
60+ let src_sample_fmt = ffi:: AV_SAMPLE_FMT_DBL ;
61+ let dst_sample_fmt = ffi:: AV_SAMPLE_FMT_S16 ;
62+ let src_nb_samples = 1024 ;
63+ let src_nb_channels = src_ch_layout. nb_channels ;
64+ let dst_nb_channels = dst_ch_layout. nb_channels ;
65+
3566 let mut swr = SwrContext :: new (
36- & dst_ch . into_inner ( ) ,
37- ffi :: AV_SAMPLE_FMT_S16 ,
38- 44100 ,
39- & src_ch . into_inner ( ) ,
40- ffi :: AV_SAMPLE_FMT_DBL ,
41- 48000 ,
67+ & dst_ch_layout ,
68+ dst_sample_fmt ,
69+ dst_rate ,
70+ & src_ch_layout ,
71+ src_sample_fmt ,
72+ src_rate ,
4273 )
4374 . unwrap ( ) ;
4475 swr. init ( ) . unwrap ( ) ;
4576
46- // build src frame
47- let nb = 1024 ;
48- let mut src = AVFrame :: new ( ) ;
49- src. set_nb_samples ( nb) ;
50- src. set_format ( ffi:: AV_SAMPLE_FMT_DBL ) ;
51- src. set_sample_rate ( 48000 ) ;
52- src. set_ch_layout ( AVChannelLayout :: from_nb_channels ( 2 ) . into_inner ( ) ) ;
53- src. get_buffer ( 0 ) . unwrap ( ) ;
54- // For packed formats (non-planar), samples are interleaved per channel in data[0].
55- let mut t = 0.0f64 ;
56- let samples_mut =
57- unsafe { std:: slice:: from_raw_parts_mut ( src. data [ 0 ] as * mut f64 , ( nb * 2 ) as usize ) } ;
58- fill_samples ( samples_mut, nb as usize , 2 , 48000usize , & mut t) ;
77+ // Allocate source samples buffer using AVSamples like C example
78+ let src_data = AVSamples :: new ( src_nb_channels, src_nb_samples, src_sample_fmt, 0 ) . unwrap ( ) ;
5979
60- // dst frame (let swr allocate)
61- let mut dst = AVFrame :: new ( ) ;
62- dst. set_nb_samples ( 0 ) ;
63- dst. set_format ( ffi:: AV_SAMPLE_FMT_S16 ) ;
64- dst. set_sample_rate ( 44100 ) ;
65- dst. set_ch_layout ( AVChannelLayout :: from_nb_channels ( 6 ) . into_inner ( ) ) ;
80+ // Calculate destination buffer size with some extra space for resampling
81+ let max_dst_nb_samples = av_rescale_rnd (
82+ src_nb_samples as i64 ,
83+ dst_rate as i64 ,
84+ src_rate as i64 ,
85+ ffi:: AV_ROUND_UP ,
86+ ) as i32 ;
6687
67- swr. convert_frame ( Some ( & src) , & mut dst) . unwrap ( ) ;
88+ let mut dst_data =
89+ AVSamples :: new ( dst_nb_channels, max_dst_nb_samples, dst_sample_fmt, 1 ) . unwrap ( ) ;
6890
69- // Write interleaved s16 to file: nb_samples * channels * 2 bytes
70- let bytes = ( dst. nb_samples as usize ) * ( dst. ch_layout . nb_channels as usize ) * 2usize ;
7191 let mut f = std:: fs:: File :: create ( out_path) ?;
72- unsafe {
73- let p = dst. data [ 0 ] as * const u8 ;
74- let buf = std:: slice:: from_raw_parts ( p, bytes) ;
75- f. write_all ( buf) ?;
92+ let mut t = 0.0f64 ;
93+ let mut total_bytes = 0usize ;
94+
95+ // Generate 10 seconds of audio like C example
96+ loop {
97+ // Generate synthetic audio (sine wave at 440Hz)
98+ let samples_mut = unsafe {
99+ std:: slice:: from_raw_parts_mut (
100+ src_data. audio_data [ 0 ] as * mut f64 ,
101+ ( src_nb_samples * src_nb_channels) as usize ,
102+ )
103+ } ;
104+ fill_samples (
105+ samples_mut,
106+ src_nb_samples as usize ,
107+ src_nb_channels as usize ,
108+ src_rate as usize ,
109+ & mut t,
110+ ) ;
111+
112+ // Calculate actual destination samples needed including buffered samples
113+ let dst_nb_samples = av_rescale_rnd (
114+ swr. get_delay ( src_rate as usize ) as i64 + src_nb_samples as i64 ,
115+ dst_rate as i64 ,
116+ src_rate as i64 ,
117+ ffi:: AV_ROUND_UP ,
118+ ) as i32 ;
119+
120+ // Reallocate destination buffer if needed
121+ if dst_nb_samples > max_dst_nb_samples {
122+ dst_data = AVSamples :: new ( dst_nb_channels, dst_nb_samples, dst_sample_fmt, 1 ) . unwrap ( ) ;
123+ }
124+
125+ // Convert to destination format
126+ let ret = unsafe {
127+ swr. convert (
128+ dst_data. audio_data . as_mut_ptr ( ) ,
129+ dst_nb_samples,
130+ src_data. audio_data . as_ptr ( ) as * const * const u8 ,
131+ src_nb_samples,
132+ )
133+ }
134+ . unwrap ( ) ;
135+
136+ let dst_bufsize = get_bytes_per_sample ( dst_sample_fmt) . unwrap ( ) as usize
137+ * ret as usize
138+ * dst_nb_channels as usize ;
139+
140+ println ! ( "t:{:.6} in:{} out:{}" , t, src_nb_samples, ret) ;
141+
142+ unsafe {
143+ let p = dst_data. audio_data [ 0 ] as * const u8 ;
144+ let buf = std:: slice:: from_raw_parts ( p, dst_bufsize) ;
145+ f. write_all ( buf) ?;
146+ }
147+ total_bytes += dst_bufsize;
148+
149+ if t >= 10.0 {
150+ break ;
151+ }
76152 }
77- Ok ( bytes)
153+
154+ let fmt = get_format_from_sample_fmt ( dst_sample_fmt) . unwrap_or ( "?" ) ;
155+ let layout_str = dst_ch_layout
156+ . describe ( )
157+ . map ( |x| x. to_string_lossy ( ) . into_owned ( ) )
158+ . unwrap_or_else ( |_| "unknown" . into ( ) ) ;
159+
160+ eprintln ! (
161+ "Resampling succeeded. Play the output file with the command:\n \
162+ ffplay -f {} -channel_layout {} -channels {} -ar {} {}",
163+ fmt, layout_str, dst_nb_channels, dst_rate, out_path
164+ ) ;
165+
166+ Ok ( total_bytes)
78167}
79168
80169#[ test]
0 commit comments