1#![allow(unsafe_code)]
8#![allow(clippy::similar_names)]
10#![allow(clippy::too_many_lines)]
11#![allow(clippy::cast_sign_loss)]
12#![allow(clippy::cast_possible_truncation)]
13#![allow(clippy::cast_possible_wrap)]
14#![allow(clippy::module_name_repetitions)]
15#![allow(clippy::match_same_arms)]
16#![allow(clippy::ptr_as_ptr)]
17#![allow(clippy::doc_markdown)]
18#![allow(clippy::unnecessary_cast)]
19#![allow(clippy::if_not_else)]
20#![allow(clippy::unnecessary_wraps)]
21#![allow(clippy::cast_precision_loss)]
22#![allow(clippy::if_same_then_else)]
23#![allow(clippy::cast_lossless)]
24
25use std::path::Path;
26use std::ptr;
27use std::time::Duration;
28
29use ff_format::channel::ChannelLayout;
30use ff_format::codec::AudioCodec;
31use ff_format::time::{Rational, Timestamp};
32use ff_format::{AudioFrame, AudioStreamInfo, SampleFormat};
33use ff_sys::{
34 AVCodecContext, AVCodecID, AVFormatContext, AVFrame, AVMediaType_AVMEDIA_TYPE_AUDIO, AVPacket,
35 AVSampleFormat, SwrContext,
36};
37
38use crate::error::DecodeError;
39
40struct AvFormatContextGuard(*mut AVFormatContext);
42
43impl AvFormatContextGuard {
44 unsafe fn new(path: &Path) -> Result<Self, DecodeError> {
50 let format_ctx = unsafe {
52 ff_sys::avformat::open_input(path).map_err(|e| {
53 DecodeError::Ffmpeg(format!(
54 "Failed to open file: {}",
55 ff_sys::av_error_string(e)
56 ))
57 })?
58 };
59 Ok(Self(format_ctx))
60 }
61
62 const fn as_ptr(&self) -> *mut AVFormatContext {
64 self.0
65 }
66
67 fn into_raw(self) -> *mut AVFormatContext {
69 let ptr = self.0;
70 std::mem::forget(self);
71 ptr
72 }
73}
74
75impl Drop for AvFormatContextGuard {
76 fn drop(&mut self) {
77 if !self.0.is_null() {
78 unsafe {
80 ff_sys::avformat::close_input(&mut (self.0 as *mut _));
81 }
82 }
83 }
84}
85
86struct AvCodecContextGuard(*mut AVCodecContext);
88
89impl AvCodecContextGuard {
90 unsafe fn new(codec: *const ff_sys::AVCodec) -> Result<Self, DecodeError> {
96 let codec_ctx = unsafe {
98 ff_sys::avcodec::alloc_context3(codec).map_err(|e| {
99 DecodeError::Ffmpeg(format!("Failed to allocate codec context: {e}"))
100 })?
101 };
102 Ok(Self(codec_ctx))
103 }
104
105 const fn as_ptr(&self) -> *mut AVCodecContext {
107 self.0
108 }
109
110 fn into_raw(self) -> *mut AVCodecContext {
112 let ptr = self.0;
113 std::mem::forget(self);
114 ptr
115 }
116}
117
118impl Drop for AvCodecContextGuard {
119 fn drop(&mut self) {
120 if !self.0.is_null() {
121 unsafe {
123 ff_sys::avcodec::free_context(&mut (self.0 as *mut _));
124 }
125 }
126 }
127}
128
129struct AvPacketGuard(*mut AVPacket);
131
132impl AvPacketGuard {
133 unsafe fn new() -> Result<Self, DecodeError> {
139 let packet = unsafe { ff_sys::av_packet_alloc() };
141 if packet.is_null() {
142 return Err(DecodeError::Ffmpeg("Failed to allocate packet".to_string()));
143 }
144 Ok(Self(packet))
145 }
146
147 fn into_raw(self) -> *mut AVPacket {
149 let ptr = self.0;
150 std::mem::forget(self);
151 ptr
152 }
153}
154
155impl Drop for AvPacketGuard {
156 fn drop(&mut self) {
157 if !self.0.is_null() {
158 unsafe {
160 ff_sys::av_packet_free(&mut (self.0 as *mut _));
161 }
162 }
163 }
164}
165
166struct AvFrameGuard(*mut AVFrame);
168
169impl AvFrameGuard {
170 unsafe fn new() -> Result<Self, DecodeError> {
176 let frame = unsafe { ff_sys::av_frame_alloc() };
178 if frame.is_null() {
179 return Err(DecodeError::Ffmpeg("Failed to allocate frame".to_string()));
180 }
181 Ok(Self(frame))
182 }
183
184 fn into_raw(self) -> *mut AVFrame {
186 let ptr = self.0;
187 std::mem::forget(self);
188 ptr
189 }
190}
191
192impl Drop for AvFrameGuard {
193 fn drop(&mut self) {
194 if !self.0.is_null() {
195 unsafe {
197 ff_sys::av_frame_free(&mut (self.0 as *mut _));
198 }
199 }
200 }
201}
202
203struct SwrContextGuard(*mut SwrContext);
205
206impl SwrContextGuard {
207 #[allow(dead_code)]
209 fn into_raw(self) -> *mut SwrContext {
210 let ptr = self.0;
211 std::mem::forget(self);
212 ptr
213 }
214}
215
216impl Drop for SwrContextGuard {
217 fn drop(&mut self) {
218 if !self.0.is_null() {
219 unsafe {
221 ff_sys::swr_free(&mut (self.0 as *mut _));
222 }
223 }
224 }
225}
226
227pub(crate) struct AudioDecoderInner {
232 format_ctx: *mut AVFormatContext,
234 codec_ctx: *mut AVCodecContext,
236 stream_index: i32,
238 swr_ctx: Option<*mut SwrContext>,
240 output_format: Option<SampleFormat>,
242 output_sample_rate: Option<u32>,
244 output_channels: Option<u32>,
246 eof: bool,
248 position: Duration,
250 packet: *mut AVPacket,
252 frame: *mut AVFrame,
254}
255
256impl AudioDecoderInner {
257 pub(crate) fn new(
274 path: &Path,
275 output_format: Option<SampleFormat>,
276 output_sample_rate: Option<u32>,
277 output_channels: Option<u32>,
278 ) -> Result<(Self, AudioStreamInfo), DecodeError> {
279 ff_sys::ensure_initialized();
281
282 let format_ctx_guard = unsafe { AvFormatContextGuard::new(path)? };
285 let format_ctx = format_ctx_guard.as_ptr();
286
287 unsafe {
290 ff_sys::avformat::find_stream_info(format_ctx).map_err(|e| {
291 DecodeError::Ffmpeg(format!(
292 "Failed to find stream info: {}",
293 ff_sys::av_error_string(e)
294 ))
295 })?;
296 }
297
298 let (stream_index, codec_id) =
301 unsafe { Self::find_audio_stream(format_ctx) }.ok_or_else(|| {
302 DecodeError::NoAudioStream {
303 path: path.to_path_buf(),
304 }
305 })?;
306
307 let codec = unsafe {
310 ff_sys::avcodec::find_decoder(codec_id).ok_or_else(|| {
311 DecodeError::UnsupportedCodec {
312 codec: format!("codec_id={codec_id:?}"),
313 }
314 })?
315 };
316
317 let codec_ctx_guard = unsafe { AvCodecContextGuard::new(codec)? };
320 let codec_ctx = codec_ctx_guard.as_ptr();
321
322 unsafe {
325 let stream = (*format_ctx).streams.add(stream_index as usize);
326 let codecpar = (*(*stream)).codecpar;
327 ff_sys::avcodec::parameters_to_context(codec_ctx, codecpar).map_err(|e| {
328 DecodeError::Ffmpeg(format!(
329 "Failed to copy codec parameters: {}",
330 ff_sys::av_error_string(e)
331 ))
332 })?;
333 }
334
335 unsafe {
338 ff_sys::avcodec::open2(codec_ctx, codec, ptr::null_mut()).map_err(|e| {
339 DecodeError::Ffmpeg(format!(
340 "Failed to open codec: {}",
341 ff_sys::av_error_string(e)
342 ))
343 })?;
344 }
345
346 let stream_info =
349 unsafe { Self::extract_stream_info(format_ctx, stream_index as i32, codec_ctx)? };
350
351 let packet_guard = unsafe { AvPacketGuard::new()? };
354 let frame_guard = unsafe { AvFrameGuard::new()? };
355
356 Ok((
358 Self {
359 format_ctx: format_ctx_guard.into_raw(),
360 codec_ctx: codec_ctx_guard.into_raw(),
361 stream_index: stream_index as i32,
362 swr_ctx: None,
363 output_format,
364 output_sample_rate,
365 output_channels,
366 eof: false,
367 position: Duration::ZERO,
368 packet: packet_guard.into_raw(),
369 frame: frame_guard.into_raw(),
370 },
371 stream_info,
372 ))
373 }
374
375 unsafe fn find_audio_stream(format_ctx: *mut AVFormatContext) -> Option<(usize, AVCodecID)> {
385 unsafe {
387 let nb_streams = (*format_ctx).nb_streams as usize;
388
389 for i in 0..nb_streams {
390 let stream = (*format_ctx).streams.add(i);
391 let codecpar = (*(*stream)).codecpar;
392
393 if (*codecpar).codec_type == AVMediaType_AVMEDIA_TYPE_AUDIO {
394 return Some((i, (*codecpar).codec_id));
395 }
396 }
397
398 None
399 }
400 }
401
402 unsafe fn extract_stream_info(
404 format_ctx: *mut AVFormatContext,
405 stream_index: i32,
406 codec_ctx: *mut AVCodecContext,
407 ) -> Result<AudioStreamInfo, DecodeError> {
408 let (sample_rate, channels, sample_fmt, duration_val, channel_layout, codec_id) = unsafe {
410 let stream = (*format_ctx).streams.add(stream_index as usize);
411 let codecpar = (*(*stream)).codecpar;
412
413 (
414 (*codecpar).sample_rate as u32,
415 (*codecpar).ch_layout.nb_channels as u32,
416 (*codec_ctx).sample_fmt,
417 (*format_ctx).duration,
418 (*codecpar).ch_layout,
419 (*codecpar).codec_id,
420 )
421 };
422
423 let duration = if duration_val > 0 {
425 let duration_secs = duration_val as f64 / 1_000_000.0;
426 Some(Duration::from_secs_f64(duration_secs))
427 } else {
428 None
429 };
430
431 let sample_format = Self::convert_sample_format(sample_fmt);
433
434 let channel_layout_enum = Self::convert_channel_layout(&channel_layout, channels);
436
437 let codec = Self::convert_codec(codec_id);
439
440 let mut builder = AudioStreamInfo::builder()
442 .index(stream_index as u32)
443 .codec(codec)
444 .sample_rate(sample_rate)
445 .channels(channels)
446 .sample_format(sample_format)
447 .channel_layout(channel_layout_enum);
448
449 if let Some(d) = duration {
450 builder = builder.duration(d);
451 }
452
453 Ok(builder.build())
454 }
455
456 fn convert_sample_format(fmt: AVSampleFormat) -> SampleFormat {
458 if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_U8 {
459 SampleFormat::U8
460 } else if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_S16 {
461 SampleFormat::I16
462 } else if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_S32 {
463 SampleFormat::I32
464 } else if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_FLT {
465 SampleFormat::F32
466 } else if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_DBL {
467 SampleFormat::F64
468 } else if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_U8P {
469 SampleFormat::U8p
470 } else if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_S16P {
471 SampleFormat::I16p
472 } else if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_S32P {
473 SampleFormat::I32p
474 } else if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_FLTP {
475 SampleFormat::F32p
476 } else if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_DBLP {
477 SampleFormat::F64p
478 } else {
479 log::warn!(
480 "sample_format unsupported, falling back to F32 requested={fmt} fallback=F32"
481 );
482 SampleFormat::F32
483 }
484 }
485
486 fn convert_channel_layout(layout: &ff_sys::AVChannelLayout, channels: u32) -> ChannelLayout {
488 if layout.order == ff_sys::AVChannelOrder_AV_CHANNEL_ORDER_NATIVE {
489 let mask = unsafe { layout.u.mask };
491 match mask {
492 0x4 => ChannelLayout::Mono,
493 0x3 => ChannelLayout::Stereo,
494 0x103 => ChannelLayout::Stereo2_1,
495 0x7 => ChannelLayout::Surround3_0,
496 0x33 => ChannelLayout::Quad,
497 0x37 => ChannelLayout::Surround5_0,
498 0x3F => ChannelLayout::Surround5_1,
499 0x13F => ChannelLayout::Surround6_1,
500 0x63F => ChannelLayout::Surround7_1,
501 _ => {
502 log::warn!(
503 "channel_layout mask has no mapping, deriving from channel count \
504 mask={mask} channels={channels}"
505 );
506 ChannelLayout::from_channels(channels)
507 }
508 }
509 } else {
510 log::warn!(
511 "channel_layout order is not NATIVE, deriving from channel count \
512 order={order} channels={channels}",
513 order = layout.order
514 );
515 ChannelLayout::from_channels(channels)
516 }
517 }
518
519 unsafe fn create_channel_layout(channels: u32) -> ff_sys::AVChannelLayout {
525 let mut layout = unsafe { std::mem::zeroed::<ff_sys::AVChannelLayout>() };
527 unsafe {
529 ff_sys::av_channel_layout_default(&raw mut layout, channels as i32);
530 }
531 layout
532 }
533
534 fn convert_codec(codec_id: AVCodecID) -> AudioCodec {
536 if codec_id == ff_sys::AVCodecID_AV_CODEC_ID_AAC {
537 AudioCodec::Aac
538 } else if codec_id == ff_sys::AVCodecID_AV_CODEC_ID_MP3 {
539 AudioCodec::Mp3
540 } else if codec_id == ff_sys::AVCodecID_AV_CODEC_ID_OPUS {
541 AudioCodec::Opus
542 } else if codec_id == ff_sys::AVCodecID_AV_CODEC_ID_VORBIS {
543 AudioCodec::Vorbis
544 } else if codec_id == ff_sys::AVCodecID_AV_CODEC_ID_FLAC {
545 AudioCodec::Flac
546 } else if codec_id == ff_sys::AVCodecID_AV_CODEC_ID_PCM_S16LE {
547 AudioCodec::Pcm
548 } else {
549 log::warn!(
550 "audio codec unsupported, falling back to Aac codec_id={codec_id} fallback=Aac"
551 );
552 AudioCodec::Aac
553 }
554 }
555
556 pub(crate) fn decode_one(&mut self) -> Result<Option<AudioFrame>, DecodeError> {
564 if self.eof {
565 return Ok(None);
566 }
567
568 unsafe {
569 loop {
570 let ret = ff_sys::avcodec_receive_frame(self.codec_ctx, self.frame);
572
573 if ret == 0 {
574 let audio_frame = self.convert_frame_to_audio_frame()?;
576
577 let pts = (*self.frame).pts;
579 if pts != ff_sys::AV_NOPTS_VALUE {
580 let stream = (*self.format_ctx).streams.add(self.stream_index as usize);
581 let time_base = (*(*stream)).time_base;
582 let timestamp_secs =
583 pts as f64 * time_base.num as f64 / time_base.den as f64;
584 self.position = Duration::from_secs_f64(timestamp_secs);
585 }
586
587 return Ok(Some(audio_frame));
588 } else if ret == ff_sys::error_codes::EAGAIN {
589 let read_ret = ff_sys::av_read_frame(self.format_ctx, self.packet);
592
593 if read_ret == ff_sys::error_codes::EOF {
594 ff_sys::avcodec_send_packet(self.codec_ctx, ptr::null());
596 self.eof = true;
597 continue;
598 } else if read_ret < 0 {
599 return Err(DecodeError::Ffmpeg(format!(
600 "Failed to read frame: {}",
601 ff_sys::av_error_string(read_ret)
602 )));
603 }
604
605 if (*self.packet).stream_index == self.stream_index {
607 let send_ret = ff_sys::avcodec_send_packet(self.codec_ctx, self.packet);
609 ff_sys::av_packet_unref(self.packet);
610
611 if send_ret < 0 && send_ret != ff_sys::error_codes::EAGAIN {
612 return Err(DecodeError::Ffmpeg(format!(
613 "Failed to send packet: {}",
614 ff_sys::av_error_string(send_ret)
615 )));
616 }
617 } else {
618 ff_sys::av_packet_unref(self.packet);
620 }
621 } else if ret == ff_sys::error_codes::EOF {
622 self.eof = true;
624 return Ok(None);
625 } else {
626 return Err(DecodeError::DecodingFailed {
627 timestamp: Some(self.position),
628 reason: ff_sys::av_error_string(ret),
629 });
630 }
631 }
632 }
633 }
634
635 unsafe fn convert_frame_to_audio_frame(&mut self) -> Result<AudioFrame, DecodeError> {
637 unsafe {
639 let nb_samples = (*self.frame).nb_samples as usize;
640 let channels = (*self.frame).ch_layout.nb_channels as u32;
641 let sample_rate = (*self.frame).sample_rate as u32;
642 let src_format = (*self.frame).format;
643
644 let needs_conversion = self.output_format.is_some()
646 || self.output_sample_rate.is_some()
647 || self.output_channels.is_some();
648
649 if needs_conversion {
650 self.convert_with_swr(nb_samples, channels, sample_rate, src_format)
651 } else {
652 self.av_frame_to_audio_frame(self.frame)
653 }
654 }
655 }
656
657 unsafe fn convert_with_swr(
659 &mut self,
660 nb_samples: usize,
661 src_channels: u32,
662 src_sample_rate: u32,
663 src_format: i32,
664 ) -> Result<AudioFrame, DecodeError> {
665 let dst_format = self
667 .output_format
668 .map_or(src_format, Self::sample_format_to_av);
669 let dst_sample_rate = self.output_sample_rate.unwrap_or(src_sample_rate);
670 let dst_channels = self.output_channels.unwrap_or(src_channels);
671
672 if src_format == dst_format
674 && src_sample_rate == dst_sample_rate
675 && src_channels == dst_channels
676 {
677 return unsafe { self.av_frame_to_audio_frame(self.frame) };
678 }
679
680 let mut src_ch_layout = unsafe { Self::create_channel_layout(src_channels) };
683 let mut dst_ch_layout = unsafe { Self::create_channel_layout(dst_channels) };
684
685 let mut swr_ctx: *mut SwrContext = ptr::null_mut();
687
688 let ret = unsafe {
690 ff_sys::swr_alloc_set_opts2(
691 &raw mut swr_ctx,
692 &raw const dst_ch_layout,
693 dst_format,
694 dst_sample_rate as i32,
695 &raw const src_ch_layout,
696 src_format,
697 src_sample_rate as i32,
698 0,
699 ptr::null_mut(),
700 )
701 };
702
703 if ret < 0 {
704 unsafe {
706 ff_sys::av_channel_layout_uninit(&raw mut src_ch_layout);
707 ff_sys::av_channel_layout_uninit(&raw mut dst_ch_layout);
708 }
709 return Err(DecodeError::Ffmpeg(format!(
710 "Failed to allocate SwrContext: {}",
711 ff_sys::av_error_string(ret)
712 )));
713 }
714
715 let _swr_guard = SwrContextGuard(swr_ctx);
717
718 let ret = unsafe { ff_sys::swr_init(swr_ctx) };
721 if ret < 0 {
722 unsafe {
724 ff_sys::av_channel_layout_uninit(&raw mut src_ch_layout);
725 ff_sys::av_channel_layout_uninit(&raw mut dst_ch_layout);
726 }
727 return Err(DecodeError::Ffmpeg(format!(
728 "Failed to initialize SwrContext: {}",
729 ff_sys::av_error_string(ret)
730 )));
731 }
732
733 let out_samples = unsafe { ff_sys::swr_get_out_samples(swr_ctx, nb_samples as i32) };
736
737 if out_samples < 0 {
738 unsafe {
740 ff_sys::av_channel_layout_uninit(&raw mut src_ch_layout);
741 ff_sys::av_channel_layout_uninit(&raw mut dst_ch_layout);
742 }
743 return Err(DecodeError::Ffmpeg(
744 "Failed to calculate output sample count".to_string(),
745 ));
746 }
747
748 let out_samples = out_samples as usize;
749
750 let dst_sample_fmt = Self::convert_sample_format(dst_format);
752 let bytes_per_sample = dst_sample_fmt.bytes_per_sample();
753 let is_planar = dst_sample_fmt.is_planar();
754
755 let buffer_size = if is_planar {
757 out_samples * bytes_per_sample * dst_channels as usize
759 } else {
760 out_samples * bytes_per_sample * dst_channels as usize
762 };
763
764 let mut out_buffer = vec![0u8; buffer_size];
765
766 let mut out_ptrs = if is_planar {
768 let plane_size = out_samples * bytes_per_sample;
770 (0..dst_channels)
771 .map(|i| {
772 let offset = i as usize * plane_size;
773 out_buffer[offset..].as_mut_ptr()
774 })
775 .collect::<Vec<_>>()
776 } else {
777 vec![out_buffer.as_mut_ptr()]
779 };
780
781 let in_ptrs = unsafe { (*self.frame).data };
784
785 let converted_samples = unsafe {
788 ff_sys::swr_convert(
789 swr_ctx,
790 out_ptrs.as_mut_ptr(),
791 out_samples as i32,
792 in_ptrs.as_ptr() as *mut *const u8,
793 nb_samples as i32,
794 )
795 };
796
797 unsafe {
799 ff_sys::av_channel_layout_uninit(&raw mut src_ch_layout);
800 ff_sys::av_channel_layout_uninit(&raw mut dst_ch_layout);
801 }
802
803 if converted_samples < 0 {
804 return Err(DecodeError::Ffmpeg(format!(
805 "Failed to convert samples: {}",
806 ff_sys::av_error_string(converted_samples)
807 )));
808 }
809
810 let timestamp = unsafe {
813 let pts = (*self.frame).pts;
814 if pts != ff_sys::AV_NOPTS_VALUE {
815 let stream = (*self.format_ctx).streams.add(self.stream_index as usize);
816 let time_base = (*(*stream)).time_base;
817 Timestamp::new(pts, Rational::new(time_base.num, time_base.den))
818 } else {
819 let stream = (*self.format_ctx).streams.add(self.stream_index as usize);
820 let time_base = (*(*stream)).time_base;
821 Timestamp::zero(Rational::new(time_base.num, time_base.den))
822 }
823 };
824
825 let planes = if is_planar {
827 let plane_size = converted_samples as usize * bytes_per_sample;
828 (0..dst_channels)
829 .map(|i| {
830 let offset = i as usize * plane_size;
831 out_buffer[offset..offset + plane_size].to_vec()
832 })
833 .collect()
834 } else {
835 vec![
837 out_buffer[..converted_samples as usize * bytes_per_sample * dst_channels as usize]
838 .to_vec(),
839 ]
840 };
841
842 AudioFrame::new(
843 planes,
844 converted_samples as usize,
845 dst_channels,
846 dst_sample_rate,
847 dst_sample_fmt,
848 timestamp,
849 )
850 .map_err(|e| DecodeError::Ffmpeg(format!("Failed to create AudioFrame: {e}")))
851 }
852
853 unsafe fn av_frame_to_audio_frame(
855 &self,
856 frame: *const AVFrame,
857 ) -> Result<AudioFrame, DecodeError> {
858 unsafe {
860 let nb_samples = (*frame).nb_samples as usize;
861 let channels = (*frame).ch_layout.nb_channels as u32;
862 let sample_rate = (*frame).sample_rate as u32;
863 let format = Self::convert_sample_format((*frame).format);
864
865 let pts = (*frame).pts;
867 let timestamp = if pts != ff_sys::AV_NOPTS_VALUE {
868 let stream = (*self.format_ctx).streams.add(self.stream_index as usize);
869 let time_base = (*(*stream)).time_base;
870 Timestamp::new(
871 pts as i64,
872 Rational::new(time_base.num as i32, time_base.den as i32),
873 )
874 } else {
875 Timestamp::default()
876 };
877
878 let planes = Self::extract_planes(frame, nb_samples, channels, format)?;
880
881 AudioFrame::new(planes, nb_samples, channels, sample_rate, format, timestamp)
882 .map_err(|e| DecodeError::Ffmpeg(format!("Failed to create AudioFrame: {e}")))
883 }
884 }
885
886 unsafe fn extract_planes(
888 frame: *const AVFrame,
889 nb_samples: usize,
890 channels: u32,
891 format: SampleFormat,
892 ) -> Result<Vec<Vec<u8>>, DecodeError> {
893 unsafe {
895 let mut planes = Vec::new();
896 let bytes_per_sample = format.bytes_per_sample();
897
898 if format.is_planar() {
899 for ch in 0..channels as usize {
901 let plane_size = nb_samples * bytes_per_sample;
902 let mut plane_data = vec![0u8; plane_size];
903
904 let src_ptr = (*frame).data[ch];
905 std::ptr::copy_nonoverlapping(src_ptr, plane_data.as_mut_ptr(), plane_size);
906
907 planes.push(plane_data);
908 }
909 } else {
910 let plane_size = nb_samples * channels as usize * bytes_per_sample;
912 let mut plane_data = vec![0u8; plane_size];
913
914 let src_ptr = (*frame).data[0];
915 std::ptr::copy_nonoverlapping(src_ptr, plane_data.as_mut_ptr(), plane_size);
916
917 planes.push(plane_data);
918 }
919
920 Ok(planes)
921 }
922 }
923
924 fn sample_format_to_av(format: SampleFormat) -> AVSampleFormat {
926 match format {
927 SampleFormat::U8 => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_U8,
928 SampleFormat::I16 => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_S16,
929 SampleFormat::I32 => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_S32,
930 SampleFormat::F32 => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_FLT,
931 SampleFormat::F64 => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_DBL,
932 SampleFormat::U8p => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_U8P,
933 SampleFormat::I16p => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_S16P,
934 SampleFormat::I32p => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_S32P,
935 SampleFormat::F32p => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_FLTP,
936 SampleFormat::F64p => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_DBLP,
937 _ => {
938 log::warn!(
939 "sample_format has no AV mapping, falling back to F32 format={format:?} fallback=AV_SAMPLE_FMT_FLT"
940 );
941 ff_sys::AVSampleFormat_AV_SAMPLE_FMT_FLT
942 }
943 }
944 }
945
946 pub(crate) fn position(&self) -> Duration {
948 self.position
949 }
950
951 pub(crate) fn is_eof(&self) -> bool {
953 self.eof
954 }
955
956 fn duration_to_pts(&self, duration: Duration) -> i64 {
958 let time_base = unsafe {
960 let stream = (*self.format_ctx).streams.add(self.stream_index as usize);
961 (*(*stream)).time_base
962 };
963
964 let time_base_f64 = time_base.den as f64 / time_base.num as f64;
966 (duration.as_secs_f64() * time_base_f64) as i64
967 }
968
969 pub(crate) fn seek(
980 &mut self,
981 position: Duration,
982 mode: crate::SeekMode,
983 ) -> Result<(), DecodeError> {
984 use crate::SeekMode;
985
986 let timestamp = self.duration_to_pts(position);
987 let flags = ff_sys::avformat::seek_flags::BACKWARD;
988
989 unsafe {
992 ff_sys::av_packet_unref(self.packet);
993 ff_sys::av_frame_unref(self.frame);
994 }
995
996 unsafe {
999 ff_sys::avformat::seek_frame(self.format_ctx, self.stream_index, timestamp, flags)
1000 .map_err(|e| DecodeError::SeekFailed {
1001 target: position,
1002 reason: ff_sys::av_error_string(e),
1003 })?;
1004 }
1005
1006 unsafe {
1009 ff_sys::avcodec::flush_buffers(self.codec_ctx);
1010 }
1011
1012 unsafe {
1015 loop {
1016 let ret = ff_sys::avcodec_receive_frame(self.codec_ctx, self.frame);
1017 if ret == ff_sys::error_codes::EAGAIN || ret == ff_sys::error_codes::EOF {
1018 break;
1019 } else if ret == 0 {
1020 ff_sys::av_frame_unref(self.frame);
1021 } else {
1022 break;
1023 }
1024 }
1025 }
1026
1027 self.eof = false;
1029
1030 if mode == SeekMode::Exact {
1032 self.skip_to_exact(position)?;
1033 }
1034 Ok(())
1037 }
1038
1039 fn skip_to_exact(&mut self, target: Duration) -> Result<(), DecodeError> {
1047 while let Some(frame) = self.decode_one()? {
1049 let frame_time = frame.timestamp().as_duration();
1050 if frame_time >= target {
1051 break;
1053 }
1054 }
1056 Ok(())
1057 }
1058
1059 pub(crate) fn flush(&mut self) {
1061 unsafe {
1063 ff_sys::avcodec::flush_buffers(self.codec_ctx);
1064 }
1065 self.eof = false;
1066 }
1067}
1068
1069impl Drop for AudioDecoderInner {
1070 fn drop(&mut self) {
1071 if let Some(swr_ctx) = self.swr_ctx {
1073 unsafe {
1075 ff_sys::swr_free(&mut (swr_ctx as *mut _));
1077 }
1078 }
1079
1080 if !self.frame.is_null() {
1082 unsafe {
1084 ff_sys::av_frame_free(&mut (self.frame as *mut _));
1085 }
1086 }
1087
1088 if !self.packet.is_null() {
1089 unsafe {
1091 ff_sys::av_packet_free(&mut (self.packet as *mut _));
1092 }
1093 }
1094
1095 if !self.codec_ctx.is_null() {
1097 unsafe {
1099 ff_sys::avcodec::free_context(&mut (self.codec_ctx as *mut _));
1100 }
1101 }
1102
1103 if !self.format_ctx.is_null() {
1105 unsafe {
1107 ff_sys::avformat::close_input(&mut (self.format_ctx as *mut _));
1108 }
1109 }
1110 }
1111}
1112
1113unsafe impl Send for AudioDecoderInner {}
1116
1117#[cfg(test)]
1118#[allow(unsafe_code)]
1119mod tests {
1120 use ff_format::channel::ChannelLayout;
1121
1122 use super::AudioDecoderInner;
1123
1124 fn native_layout(mask: u64, nb_channels: i32) -> ff_sys::AVChannelLayout {
1126 ff_sys::AVChannelLayout {
1127 order: ff_sys::AVChannelOrder_AV_CHANNEL_ORDER_NATIVE,
1128 nb_channels,
1129 u: ff_sys::AVChannelLayout__bindgen_ty_1 { mask },
1130 opaque: std::ptr::null_mut(),
1131 }
1132 }
1133
1134 fn unspec_layout(nb_channels: i32) -> ff_sys::AVChannelLayout {
1136 ff_sys::AVChannelLayout {
1137 order: ff_sys::AVChannelOrder_AV_CHANNEL_ORDER_UNSPEC,
1138 nb_channels,
1139 u: ff_sys::AVChannelLayout__bindgen_ty_1 { mask: 0 },
1140 opaque: std::ptr::null_mut(),
1141 }
1142 }
1143
1144 #[test]
1145 fn native_mask_mono() {
1146 let layout = native_layout(0x4, 1);
1147 assert_eq!(
1148 AudioDecoderInner::convert_channel_layout(&layout, 1),
1149 ChannelLayout::Mono
1150 );
1151 }
1152
1153 #[test]
1154 fn native_mask_stereo() {
1155 let layout = native_layout(0x3, 2);
1156 assert_eq!(
1157 AudioDecoderInner::convert_channel_layout(&layout, 2),
1158 ChannelLayout::Stereo
1159 );
1160 }
1161
1162 #[test]
1163 fn native_mask_stereo2_1() {
1164 let layout = native_layout(0x103, 3);
1165 assert_eq!(
1166 AudioDecoderInner::convert_channel_layout(&layout, 3),
1167 ChannelLayout::Stereo2_1
1168 );
1169 }
1170
1171 #[test]
1172 fn native_mask_surround3_0() {
1173 let layout = native_layout(0x7, 3);
1174 assert_eq!(
1175 AudioDecoderInner::convert_channel_layout(&layout, 3),
1176 ChannelLayout::Surround3_0
1177 );
1178 }
1179
1180 #[test]
1181 fn native_mask_quad() {
1182 let layout = native_layout(0x33, 4);
1183 assert_eq!(
1184 AudioDecoderInner::convert_channel_layout(&layout, 4),
1185 ChannelLayout::Quad
1186 );
1187 }
1188
1189 #[test]
1190 fn native_mask_surround5_0() {
1191 let layout = native_layout(0x37, 5);
1192 assert_eq!(
1193 AudioDecoderInner::convert_channel_layout(&layout, 5),
1194 ChannelLayout::Surround5_0
1195 );
1196 }
1197
1198 #[test]
1199 fn native_mask_surround5_1() {
1200 let layout = native_layout(0x3F, 6);
1201 assert_eq!(
1202 AudioDecoderInner::convert_channel_layout(&layout, 6),
1203 ChannelLayout::Surround5_1
1204 );
1205 }
1206
1207 #[test]
1208 fn native_mask_surround6_1() {
1209 let layout = native_layout(0x13F, 7);
1210 assert_eq!(
1211 AudioDecoderInner::convert_channel_layout(&layout, 7),
1212 ChannelLayout::Surround6_1
1213 );
1214 }
1215
1216 #[test]
1217 fn native_mask_surround7_1() {
1218 let layout = native_layout(0x63F, 8);
1219 assert_eq!(
1220 AudioDecoderInner::convert_channel_layout(&layout, 8),
1221 ChannelLayout::Surround7_1
1222 );
1223 }
1224
1225 #[test]
1226 fn native_mask_unknown_falls_back_to_from_channels() {
1227 let layout = native_layout(0x1, 2);
1229 assert_eq!(
1230 AudioDecoderInner::convert_channel_layout(&layout, 2),
1231 ChannelLayout::from_channels(2)
1232 );
1233 }
1234
1235 #[test]
1236 fn non_native_order_falls_back_to_from_channels() {
1237 let layout = unspec_layout(6);
1238 assert_eq!(
1239 AudioDecoderInner::convert_channel_layout(&layout, 6),
1240 ChannelLayout::from_channels(6)
1241 );
1242 }
1243}