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| DecodeError::Ffmpeg {
53 code: e,
54 message: format!("Failed to open file: {}", ff_sys::av_error_string(e)),
55 })?
56 };
57 Ok(Self(format_ctx))
58 }
59
60 const fn as_ptr(&self) -> *mut AVFormatContext {
62 self.0
63 }
64
65 fn into_raw(self) -> *mut AVFormatContext {
67 let ptr = self.0;
68 std::mem::forget(self);
69 ptr
70 }
71}
72
73impl Drop for AvFormatContextGuard {
74 fn drop(&mut self) {
75 if !self.0.is_null() {
76 unsafe {
78 ff_sys::avformat::close_input(&mut (self.0 as *mut _));
79 }
80 }
81 }
82}
83
84struct AvCodecContextGuard(*mut AVCodecContext);
86
87impl AvCodecContextGuard {
88 unsafe fn new(codec: *const ff_sys::AVCodec) -> Result<Self, DecodeError> {
94 let codec_ctx = unsafe {
96 ff_sys::avcodec::alloc_context3(codec).map_err(|e| DecodeError::Ffmpeg {
97 code: e,
98 message: format!("Failed to allocate codec context: {e}"),
99 })?
100 };
101 Ok(Self(codec_ctx))
102 }
103
104 const fn as_ptr(&self) -> *mut AVCodecContext {
106 self.0
107 }
108
109 fn into_raw(self) -> *mut AVCodecContext {
111 let ptr = self.0;
112 std::mem::forget(self);
113 ptr
114 }
115}
116
117impl Drop for AvCodecContextGuard {
118 fn drop(&mut self) {
119 if !self.0.is_null() {
120 unsafe {
122 ff_sys::avcodec::free_context(&mut (self.0 as *mut _));
123 }
124 }
125 }
126}
127
128struct AvPacketGuard(*mut AVPacket);
130
131impl AvPacketGuard {
132 unsafe fn new() -> Result<Self, DecodeError> {
138 let packet = unsafe { ff_sys::av_packet_alloc() };
140 if packet.is_null() {
141 return Err(DecodeError::Ffmpeg {
142 code: 0,
143 message: "Failed to allocate packet".to_string(),
144 });
145 }
146 Ok(Self(packet))
147 }
148
149 fn into_raw(self) -> *mut AVPacket {
151 let ptr = self.0;
152 std::mem::forget(self);
153 ptr
154 }
155}
156
157impl Drop for AvPacketGuard {
158 fn drop(&mut self) {
159 if !self.0.is_null() {
160 unsafe {
162 ff_sys::av_packet_free(&mut (self.0 as *mut _));
163 }
164 }
165 }
166}
167
168struct AvFrameGuard(*mut AVFrame);
170
171impl AvFrameGuard {
172 unsafe fn new() -> Result<Self, DecodeError> {
178 let frame = unsafe { ff_sys::av_frame_alloc() };
180 if frame.is_null() {
181 return Err(DecodeError::Ffmpeg {
182 code: 0,
183 message: "Failed to allocate frame".to_string(),
184 });
185 }
186 Ok(Self(frame))
187 }
188
189 fn into_raw(self) -> *mut AVFrame {
191 let ptr = self.0;
192 std::mem::forget(self);
193 ptr
194 }
195}
196
197impl Drop for AvFrameGuard {
198 fn drop(&mut self) {
199 if !self.0.is_null() {
200 unsafe {
202 ff_sys::av_frame_free(&mut (self.0 as *mut _));
203 }
204 }
205 }
206}
207
208struct SwrContextGuard(*mut SwrContext);
210
211impl SwrContextGuard {
212 #[allow(dead_code)]
214 fn into_raw(self) -> *mut SwrContext {
215 let ptr = self.0;
216 std::mem::forget(self);
217 ptr
218 }
219}
220
221impl Drop for SwrContextGuard {
222 fn drop(&mut self) {
223 if !self.0.is_null() {
224 unsafe {
226 ff_sys::swr_free(&mut (self.0 as *mut _));
227 }
228 }
229 }
230}
231
232pub(crate) struct AudioDecoderInner {
237 format_ctx: *mut AVFormatContext,
239 codec_ctx: *mut AVCodecContext,
241 stream_index: i32,
243 swr_ctx: Option<*mut SwrContext>,
245 output_format: Option<SampleFormat>,
247 output_sample_rate: Option<u32>,
249 output_channels: Option<u32>,
251 eof: bool,
253 position: Duration,
255 packet: *mut AVPacket,
257 frame: *mut AVFrame,
259}
260
261impl AudioDecoderInner {
262 pub(crate) fn new(
279 path: &Path,
280 output_format: Option<SampleFormat>,
281 output_sample_rate: Option<u32>,
282 output_channels: Option<u32>,
283 ) -> Result<(Self, AudioStreamInfo), DecodeError> {
284 ff_sys::ensure_initialized();
286
287 let format_ctx_guard = unsafe { AvFormatContextGuard::new(path)? };
290 let format_ctx = format_ctx_guard.as_ptr();
291
292 unsafe {
295 ff_sys::avformat::find_stream_info(format_ctx).map_err(|e| DecodeError::Ffmpeg {
296 code: e,
297 message: format!("Failed to find stream info: {}", ff_sys::av_error_string(e)),
298 })?;
299 }
300
301 let (stream_index, codec_id) =
304 unsafe { Self::find_audio_stream(format_ctx) }.ok_or_else(|| {
305 DecodeError::NoAudioStream {
306 path: path.to_path_buf(),
307 }
308 })?;
309
310 let codec = unsafe {
313 ff_sys::avcodec::find_decoder(codec_id).ok_or_else(|| {
314 DecodeError::UnsupportedCodec {
315 codec: format!("codec_id={codec_id:?}"),
316 }
317 })?
318 };
319
320 let codec_ctx_guard = unsafe { AvCodecContextGuard::new(codec)? };
323 let codec_ctx = codec_ctx_guard.as_ptr();
324
325 unsafe {
328 let stream = (*format_ctx).streams.add(stream_index as usize);
329 let codecpar = (*(*stream)).codecpar;
330 ff_sys::avcodec::parameters_to_context(codec_ctx, codecpar).map_err(|e| {
331 DecodeError::Ffmpeg {
332 code: e,
333 message: format!(
334 "Failed to copy codec parameters: {}",
335 ff_sys::av_error_string(e)
336 ),
337 }
338 })?;
339 }
340
341 unsafe {
344 ff_sys::avcodec::open2(codec_ctx, codec, ptr::null_mut()).map_err(|e| {
345 DecodeError::Ffmpeg {
346 code: e,
347 message: format!("Failed to open codec: {}", ff_sys::av_error_string(e)),
348 }
349 })?;
350 }
351
352 let stream_info =
355 unsafe { Self::extract_stream_info(format_ctx, stream_index as i32, codec_ctx)? };
356
357 let packet_guard = unsafe { AvPacketGuard::new()? };
360 let frame_guard = unsafe { AvFrameGuard::new()? };
361
362 Ok((
364 Self {
365 format_ctx: format_ctx_guard.into_raw(),
366 codec_ctx: codec_ctx_guard.into_raw(),
367 stream_index: stream_index as i32,
368 swr_ctx: None,
369 output_format,
370 output_sample_rate,
371 output_channels,
372 eof: false,
373 position: Duration::ZERO,
374 packet: packet_guard.into_raw(),
375 frame: frame_guard.into_raw(),
376 },
377 stream_info,
378 ))
379 }
380
381 unsafe fn find_audio_stream(format_ctx: *mut AVFormatContext) -> Option<(usize, AVCodecID)> {
391 unsafe {
393 let nb_streams = (*format_ctx).nb_streams as usize;
394
395 for i in 0..nb_streams {
396 let stream = (*format_ctx).streams.add(i);
397 let codecpar = (*(*stream)).codecpar;
398
399 if (*codecpar).codec_type == AVMediaType_AVMEDIA_TYPE_AUDIO {
400 return Some((i, (*codecpar).codec_id));
401 }
402 }
403
404 None
405 }
406 }
407
408 unsafe fn extract_stream_info(
410 format_ctx: *mut AVFormatContext,
411 stream_index: i32,
412 codec_ctx: *mut AVCodecContext,
413 ) -> Result<AudioStreamInfo, DecodeError> {
414 let (sample_rate, channels, sample_fmt, duration_val, channel_layout, codec_id) = unsafe {
416 let stream = (*format_ctx).streams.add(stream_index as usize);
417 let codecpar = (*(*stream)).codecpar;
418
419 (
420 (*codecpar).sample_rate as u32,
421 (*codecpar).ch_layout.nb_channels as u32,
422 (*codec_ctx).sample_fmt,
423 (*format_ctx).duration,
424 (*codecpar).ch_layout,
425 (*codecpar).codec_id,
426 )
427 };
428
429 let duration = if duration_val > 0 {
431 let duration_secs = duration_val as f64 / 1_000_000.0;
432 Some(Duration::from_secs_f64(duration_secs))
433 } else {
434 None
435 };
436
437 let sample_format = Self::convert_sample_format(sample_fmt);
439
440 let channel_layout_enum = Self::convert_channel_layout(&channel_layout, channels);
442
443 let codec = Self::convert_codec(codec_id);
445
446 let mut builder = AudioStreamInfo::builder()
448 .index(stream_index as u32)
449 .codec(codec)
450 .sample_rate(sample_rate)
451 .channels(channels)
452 .sample_format(sample_format)
453 .channel_layout(channel_layout_enum);
454
455 if let Some(d) = duration {
456 builder = builder.duration(d);
457 }
458
459 Ok(builder.build())
460 }
461
462 fn convert_sample_format(fmt: AVSampleFormat) -> SampleFormat {
464 if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_U8 {
465 SampleFormat::U8
466 } else if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_S16 {
467 SampleFormat::I16
468 } else if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_S32 {
469 SampleFormat::I32
470 } else if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_FLT {
471 SampleFormat::F32
472 } else if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_DBL {
473 SampleFormat::F64
474 } else if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_U8P {
475 SampleFormat::U8p
476 } else if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_S16P {
477 SampleFormat::I16p
478 } else if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_S32P {
479 SampleFormat::I32p
480 } else if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_FLTP {
481 SampleFormat::F32p
482 } else if fmt == ff_sys::AVSampleFormat_AV_SAMPLE_FMT_DBLP {
483 SampleFormat::F64p
484 } else {
485 log::warn!(
486 "sample_format unsupported, falling back to F32 requested={fmt} fallback=F32"
487 );
488 SampleFormat::F32
489 }
490 }
491
492 fn convert_channel_layout(layout: &ff_sys::AVChannelLayout, channels: u32) -> ChannelLayout {
494 if layout.order == ff_sys::AVChannelOrder_AV_CHANNEL_ORDER_NATIVE {
495 let mask = unsafe { layout.u.mask };
497 match mask {
498 0x4 => ChannelLayout::Mono,
499 0x3 => ChannelLayout::Stereo,
500 0x103 => ChannelLayout::Stereo2_1,
501 0x7 => ChannelLayout::Surround3_0,
502 0x33 => ChannelLayout::Quad,
503 0x37 => ChannelLayout::Surround5_0,
504 0x3F => ChannelLayout::Surround5_1,
505 0x13F => ChannelLayout::Surround6_1,
506 0x63F => ChannelLayout::Surround7_1,
507 _ => {
508 log::warn!(
509 "channel_layout mask has no mapping, deriving from channel count \
510 mask={mask} channels={channels}"
511 );
512 ChannelLayout::from_channels(channels)
513 }
514 }
515 } else {
516 log::warn!(
517 "channel_layout order is not NATIVE, deriving from channel count \
518 order={order} channels={channels}",
519 order = layout.order
520 );
521 ChannelLayout::from_channels(channels)
522 }
523 }
524
525 unsafe fn create_channel_layout(channels: u32) -> ff_sys::AVChannelLayout {
531 let mut layout = unsafe { std::mem::zeroed::<ff_sys::AVChannelLayout>() };
533 unsafe {
535 ff_sys::av_channel_layout_default(&raw mut layout, channels as i32);
536 }
537 layout
538 }
539
540 fn convert_codec(codec_id: AVCodecID) -> AudioCodec {
542 if codec_id == ff_sys::AVCodecID_AV_CODEC_ID_AAC {
543 AudioCodec::Aac
544 } else if codec_id == ff_sys::AVCodecID_AV_CODEC_ID_MP3 {
545 AudioCodec::Mp3
546 } else if codec_id == ff_sys::AVCodecID_AV_CODEC_ID_OPUS {
547 AudioCodec::Opus
548 } else if codec_id == ff_sys::AVCodecID_AV_CODEC_ID_VORBIS {
549 AudioCodec::Vorbis
550 } else if codec_id == ff_sys::AVCodecID_AV_CODEC_ID_FLAC {
551 AudioCodec::Flac
552 } else if codec_id == ff_sys::AVCodecID_AV_CODEC_ID_PCM_S16LE {
553 AudioCodec::Pcm
554 } else {
555 log::warn!(
556 "audio codec unsupported, falling back to Aac codec_id={codec_id} fallback=Aac"
557 );
558 AudioCodec::Aac
559 }
560 }
561
562 pub(crate) fn decode_one(&mut self) -> Result<Option<AudioFrame>, DecodeError> {
570 if self.eof {
571 return Ok(None);
572 }
573
574 unsafe {
575 loop {
576 let ret = ff_sys::avcodec_receive_frame(self.codec_ctx, self.frame);
578
579 if ret == 0 {
580 let audio_frame = self.convert_frame_to_audio_frame()?;
582
583 let pts = (*self.frame).pts;
585 if pts != ff_sys::AV_NOPTS_VALUE {
586 let stream = (*self.format_ctx).streams.add(self.stream_index as usize);
587 let time_base = (*(*stream)).time_base;
588 let timestamp_secs =
589 pts as f64 * time_base.num as f64 / time_base.den as f64;
590 self.position = Duration::from_secs_f64(timestamp_secs);
591 }
592
593 return Ok(Some(audio_frame));
594 } else if ret == ff_sys::error_codes::EAGAIN {
595 let read_ret = ff_sys::av_read_frame(self.format_ctx, self.packet);
598
599 if read_ret == ff_sys::error_codes::EOF {
600 ff_sys::avcodec_send_packet(self.codec_ctx, ptr::null());
602 self.eof = true;
603 continue;
604 } else if read_ret < 0 {
605 return Err(DecodeError::Ffmpeg {
606 code: read_ret,
607 message: format!(
608 "Failed to read frame: {}",
609 ff_sys::av_error_string(read_ret)
610 ),
611 });
612 }
613
614 if (*self.packet).stream_index == self.stream_index {
616 let send_ret = ff_sys::avcodec_send_packet(self.codec_ctx, self.packet);
618 ff_sys::av_packet_unref(self.packet);
619
620 if send_ret < 0 && send_ret != ff_sys::error_codes::EAGAIN {
621 return Err(DecodeError::Ffmpeg {
622 code: send_ret,
623 message: format!(
624 "Failed to send packet: {}",
625 ff_sys::av_error_string(send_ret)
626 ),
627 });
628 }
629 } else {
630 ff_sys::av_packet_unref(self.packet);
632 }
633 } else if ret == ff_sys::error_codes::EOF {
634 self.eof = true;
636 return Ok(None);
637 } else {
638 return Err(DecodeError::DecodingFailed {
639 timestamp: Some(self.position),
640 reason: ff_sys::av_error_string(ret),
641 });
642 }
643 }
644 }
645 }
646
647 unsafe fn convert_frame_to_audio_frame(&mut self) -> Result<AudioFrame, DecodeError> {
649 unsafe {
651 let nb_samples = (*self.frame).nb_samples as usize;
652 let channels = (*self.frame).ch_layout.nb_channels as u32;
653 let sample_rate = (*self.frame).sample_rate as u32;
654 let src_format = (*self.frame).format;
655
656 let needs_conversion = self.output_format.is_some()
658 || self.output_sample_rate.is_some()
659 || self.output_channels.is_some();
660
661 if needs_conversion {
662 self.convert_with_swr(nb_samples, channels, sample_rate, src_format)
663 } else {
664 self.av_frame_to_audio_frame(self.frame)
665 }
666 }
667 }
668
669 unsafe fn convert_with_swr(
671 &mut self,
672 nb_samples: usize,
673 src_channels: u32,
674 src_sample_rate: u32,
675 src_format: i32,
676 ) -> Result<AudioFrame, DecodeError> {
677 let dst_format = self
679 .output_format
680 .map_or(src_format, Self::sample_format_to_av);
681 let dst_sample_rate = self.output_sample_rate.unwrap_or(src_sample_rate);
682 let dst_channels = self.output_channels.unwrap_or(src_channels);
683
684 if src_format == dst_format
686 && src_sample_rate == dst_sample_rate
687 && src_channels == dst_channels
688 {
689 return unsafe { self.av_frame_to_audio_frame(self.frame) };
690 }
691
692 let mut src_ch_layout = unsafe { Self::create_channel_layout(src_channels) };
695 let mut dst_ch_layout = unsafe { Self::create_channel_layout(dst_channels) };
696
697 let mut swr_ctx: *mut SwrContext = ptr::null_mut();
699
700 let ret = unsafe {
702 ff_sys::swr_alloc_set_opts2(
703 &raw mut swr_ctx,
704 &raw const dst_ch_layout,
705 dst_format,
706 dst_sample_rate as i32,
707 &raw const src_ch_layout,
708 src_format,
709 src_sample_rate as i32,
710 0,
711 ptr::null_mut(),
712 )
713 };
714
715 if ret < 0 {
716 unsafe {
718 ff_sys::av_channel_layout_uninit(&raw mut src_ch_layout);
719 ff_sys::av_channel_layout_uninit(&raw mut dst_ch_layout);
720 }
721 return Err(DecodeError::Ffmpeg {
722 code: ret,
723 message: format!(
724 "Failed to allocate SwrContext: {}",
725 ff_sys::av_error_string(ret)
726 ),
727 });
728 }
729
730 let _swr_guard = SwrContextGuard(swr_ctx);
732
733 let ret = unsafe { ff_sys::swr_init(swr_ctx) };
736 if ret < 0 {
737 unsafe {
739 ff_sys::av_channel_layout_uninit(&raw mut src_ch_layout);
740 ff_sys::av_channel_layout_uninit(&raw mut dst_ch_layout);
741 }
742 return Err(DecodeError::Ffmpeg {
743 code: ret,
744 message: format!(
745 "Failed to initialize SwrContext: {}",
746 ff_sys::av_error_string(ret)
747 ),
748 });
749 }
750
751 let out_samples = unsafe { ff_sys::swr_get_out_samples(swr_ctx, nb_samples as i32) };
754
755 if out_samples < 0 {
756 unsafe {
758 ff_sys::av_channel_layout_uninit(&raw mut src_ch_layout);
759 ff_sys::av_channel_layout_uninit(&raw mut dst_ch_layout);
760 }
761 return Err(DecodeError::Ffmpeg {
762 code: 0,
763 message: "Failed to calculate output sample count".to_string(),
764 });
765 }
766
767 let out_samples = out_samples as usize;
768
769 let dst_sample_fmt = Self::convert_sample_format(dst_format);
771 let bytes_per_sample = dst_sample_fmt.bytes_per_sample();
772 let is_planar = dst_sample_fmt.is_planar();
773
774 let buffer_size = if is_planar {
776 out_samples * bytes_per_sample * dst_channels as usize
778 } else {
779 out_samples * bytes_per_sample * dst_channels as usize
781 };
782
783 let mut out_buffer = vec![0u8; buffer_size];
784
785 let mut out_ptrs = if is_planar {
787 let plane_size = out_samples * bytes_per_sample;
789 (0..dst_channels)
790 .map(|i| {
791 let offset = i as usize * plane_size;
792 out_buffer[offset..].as_mut_ptr()
793 })
794 .collect::<Vec<_>>()
795 } else {
796 vec![out_buffer.as_mut_ptr()]
798 };
799
800 let in_ptrs = unsafe { (*self.frame).data };
803
804 let converted_samples = unsafe {
807 ff_sys::swr_convert(
808 swr_ctx,
809 out_ptrs.as_mut_ptr(),
810 out_samples as i32,
811 in_ptrs.as_ptr() as *mut *const u8,
812 nb_samples as i32,
813 )
814 };
815
816 unsafe {
818 ff_sys::av_channel_layout_uninit(&raw mut src_ch_layout);
819 ff_sys::av_channel_layout_uninit(&raw mut dst_ch_layout);
820 }
821
822 if converted_samples < 0 {
823 return Err(DecodeError::Ffmpeg {
824 code: converted_samples,
825 message: format!(
826 "Failed to convert samples: {}",
827 ff_sys::av_error_string(converted_samples)
828 ),
829 });
830 }
831
832 let timestamp = unsafe {
835 let pts = (*self.frame).pts;
836 if pts != ff_sys::AV_NOPTS_VALUE {
837 let stream = (*self.format_ctx).streams.add(self.stream_index as usize);
838 let time_base = (*(*stream)).time_base;
839 Timestamp::new(pts, Rational::new(time_base.num, time_base.den))
840 } else {
841 let stream = (*self.format_ctx).streams.add(self.stream_index as usize);
842 let time_base = (*(*stream)).time_base;
843 Timestamp::zero(Rational::new(time_base.num, time_base.den))
844 }
845 };
846
847 let planes = if is_planar {
849 let plane_size = converted_samples as usize * bytes_per_sample;
850 (0..dst_channels)
851 .map(|i| {
852 let offset = i as usize * plane_size;
853 out_buffer[offset..offset + plane_size].to_vec()
854 })
855 .collect()
856 } else {
857 vec![
859 out_buffer[..converted_samples as usize * bytes_per_sample * dst_channels as usize]
860 .to_vec(),
861 ]
862 };
863
864 AudioFrame::new(
865 planes,
866 converted_samples as usize,
867 dst_channels,
868 dst_sample_rate,
869 dst_sample_fmt,
870 timestamp,
871 )
872 .map_err(|e| DecodeError::Ffmpeg {
873 code: 0,
874 message: format!("Failed to create AudioFrame: {e}"),
875 })
876 }
877
878 unsafe fn av_frame_to_audio_frame(
880 &self,
881 frame: *const AVFrame,
882 ) -> Result<AudioFrame, DecodeError> {
883 unsafe {
885 let nb_samples = (*frame).nb_samples as usize;
886 let channels = (*frame).ch_layout.nb_channels as u32;
887 let sample_rate = (*frame).sample_rate as u32;
888 let format = Self::convert_sample_format((*frame).format);
889
890 let pts = (*frame).pts;
892 let timestamp = if pts != ff_sys::AV_NOPTS_VALUE {
893 let stream = (*self.format_ctx).streams.add(self.stream_index as usize);
894 let time_base = (*(*stream)).time_base;
895 Timestamp::new(
896 pts as i64,
897 Rational::new(time_base.num as i32, time_base.den as i32),
898 )
899 } else {
900 Timestamp::default()
901 };
902
903 let planes = Self::extract_planes(frame, nb_samples, channels, format)?;
905
906 AudioFrame::new(planes, nb_samples, channels, sample_rate, format, timestamp).map_err(
907 |e| DecodeError::Ffmpeg {
908 code: 0,
909 message: format!("Failed to create AudioFrame: {e}"),
910 },
911 )
912 }
913 }
914
915 unsafe fn extract_planes(
917 frame: *const AVFrame,
918 nb_samples: usize,
919 channels: u32,
920 format: SampleFormat,
921 ) -> Result<Vec<Vec<u8>>, DecodeError> {
922 unsafe {
924 let mut planes = Vec::new();
925 let bytes_per_sample = format.bytes_per_sample();
926
927 if format.is_planar() {
928 for ch in 0..channels as usize {
930 let plane_size = nb_samples * bytes_per_sample;
931 let mut plane_data = vec![0u8; plane_size];
932
933 let src_ptr = (*frame).data[ch];
934 std::ptr::copy_nonoverlapping(src_ptr, plane_data.as_mut_ptr(), plane_size);
935
936 planes.push(plane_data);
937 }
938 } else {
939 let plane_size = nb_samples * channels as usize * bytes_per_sample;
941 let mut plane_data = vec![0u8; plane_size];
942
943 let src_ptr = (*frame).data[0];
944 std::ptr::copy_nonoverlapping(src_ptr, plane_data.as_mut_ptr(), plane_size);
945
946 planes.push(plane_data);
947 }
948
949 Ok(planes)
950 }
951 }
952
953 fn sample_format_to_av(format: SampleFormat) -> AVSampleFormat {
955 match format {
956 SampleFormat::U8 => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_U8,
957 SampleFormat::I16 => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_S16,
958 SampleFormat::I32 => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_S32,
959 SampleFormat::F32 => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_FLT,
960 SampleFormat::F64 => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_DBL,
961 SampleFormat::U8p => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_U8P,
962 SampleFormat::I16p => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_S16P,
963 SampleFormat::I32p => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_S32P,
964 SampleFormat::F32p => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_FLTP,
965 SampleFormat::F64p => ff_sys::AVSampleFormat_AV_SAMPLE_FMT_DBLP,
966 _ => {
967 log::warn!(
968 "sample_format has no AV mapping, falling back to F32 format={format:?} fallback=AV_SAMPLE_FMT_FLT"
969 );
970 ff_sys::AVSampleFormat_AV_SAMPLE_FMT_FLT
971 }
972 }
973 }
974
975 pub(crate) fn position(&self) -> Duration {
977 self.position
978 }
979
980 pub(crate) fn is_eof(&self) -> bool {
982 self.eof
983 }
984
985 fn duration_to_pts(&self, duration: Duration) -> i64 {
987 let time_base = unsafe {
989 let stream = (*self.format_ctx).streams.add(self.stream_index as usize);
990 (*(*stream)).time_base
991 };
992
993 let time_base_f64 = time_base.den as f64 / time_base.num as f64;
995 (duration.as_secs_f64() * time_base_f64) as i64
996 }
997
998 pub(crate) fn seek(
1009 &mut self,
1010 position: Duration,
1011 mode: crate::SeekMode,
1012 ) -> Result<(), DecodeError> {
1013 use crate::SeekMode;
1014
1015 let timestamp = self.duration_to_pts(position);
1016 let flags = ff_sys::avformat::seek_flags::BACKWARD;
1017
1018 unsafe {
1021 ff_sys::av_packet_unref(self.packet);
1022 ff_sys::av_frame_unref(self.frame);
1023 }
1024
1025 unsafe {
1028 ff_sys::avformat::seek_frame(self.format_ctx, self.stream_index, timestamp, flags)
1029 .map_err(|e| DecodeError::SeekFailed {
1030 target: position,
1031 reason: ff_sys::av_error_string(e),
1032 })?;
1033 }
1034
1035 unsafe {
1038 ff_sys::avcodec::flush_buffers(self.codec_ctx);
1039 }
1040
1041 unsafe {
1044 loop {
1045 let ret = ff_sys::avcodec_receive_frame(self.codec_ctx, self.frame);
1046 if ret == ff_sys::error_codes::EAGAIN || ret == ff_sys::error_codes::EOF {
1047 break;
1048 } else if ret == 0 {
1049 ff_sys::av_frame_unref(self.frame);
1050 } else {
1051 break;
1052 }
1053 }
1054 }
1055
1056 self.eof = false;
1058
1059 if mode == SeekMode::Exact {
1061 self.skip_to_exact(position)?;
1062 }
1063 Ok(())
1066 }
1067
1068 fn skip_to_exact(&mut self, target: Duration) -> Result<(), DecodeError> {
1076 while let Some(frame) = self.decode_one()? {
1078 let frame_time = frame.timestamp().as_duration();
1079 if frame_time >= target {
1080 break;
1082 }
1083 }
1085 Ok(())
1086 }
1087
1088 pub(crate) fn flush(&mut self) {
1090 unsafe {
1092 ff_sys::avcodec::flush_buffers(self.codec_ctx);
1093 }
1094 self.eof = false;
1095 }
1096}
1097
1098impl Drop for AudioDecoderInner {
1099 fn drop(&mut self) {
1100 if let Some(swr_ctx) = self.swr_ctx {
1102 unsafe {
1104 ff_sys::swr_free(&mut (swr_ctx as *mut _));
1106 }
1107 }
1108
1109 if !self.frame.is_null() {
1111 unsafe {
1113 ff_sys::av_frame_free(&mut (self.frame as *mut _));
1114 }
1115 }
1116
1117 if !self.packet.is_null() {
1118 unsafe {
1120 ff_sys::av_packet_free(&mut (self.packet as *mut _));
1121 }
1122 }
1123
1124 if !self.codec_ctx.is_null() {
1126 unsafe {
1128 ff_sys::avcodec::free_context(&mut (self.codec_ctx as *mut _));
1129 }
1130 }
1131
1132 if !self.format_ctx.is_null() {
1134 unsafe {
1136 ff_sys::avformat::close_input(&mut (self.format_ctx as *mut _));
1137 }
1138 }
1139 }
1140}
1141
1142unsafe impl Send for AudioDecoderInner {}
1145
1146#[cfg(test)]
1147#[allow(unsafe_code)]
1148mod tests {
1149 use ff_format::channel::ChannelLayout;
1150
1151 use super::AudioDecoderInner;
1152
1153 fn native_layout(mask: u64, nb_channels: i32) -> ff_sys::AVChannelLayout {
1155 ff_sys::AVChannelLayout {
1156 order: ff_sys::AVChannelOrder_AV_CHANNEL_ORDER_NATIVE,
1157 nb_channels,
1158 u: ff_sys::AVChannelLayout__bindgen_ty_1 { mask },
1159 opaque: std::ptr::null_mut(),
1160 }
1161 }
1162
1163 fn unspec_layout(nb_channels: i32) -> ff_sys::AVChannelLayout {
1165 ff_sys::AVChannelLayout {
1166 order: ff_sys::AVChannelOrder_AV_CHANNEL_ORDER_UNSPEC,
1167 nb_channels,
1168 u: ff_sys::AVChannelLayout__bindgen_ty_1 { mask: 0 },
1169 opaque: std::ptr::null_mut(),
1170 }
1171 }
1172
1173 #[test]
1174 fn native_mask_mono() {
1175 let layout = native_layout(0x4, 1);
1176 assert_eq!(
1177 AudioDecoderInner::convert_channel_layout(&layout, 1),
1178 ChannelLayout::Mono
1179 );
1180 }
1181
1182 #[test]
1183 fn native_mask_stereo() {
1184 let layout = native_layout(0x3, 2);
1185 assert_eq!(
1186 AudioDecoderInner::convert_channel_layout(&layout, 2),
1187 ChannelLayout::Stereo
1188 );
1189 }
1190
1191 #[test]
1192 fn native_mask_stereo2_1() {
1193 let layout = native_layout(0x103, 3);
1194 assert_eq!(
1195 AudioDecoderInner::convert_channel_layout(&layout, 3),
1196 ChannelLayout::Stereo2_1
1197 );
1198 }
1199
1200 #[test]
1201 fn native_mask_surround3_0() {
1202 let layout = native_layout(0x7, 3);
1203 assert_eq!(
1204 AudioDecoderInner::convert_channel_layout(&layout, 3),
1205 ChannelLayout::Surround3_0
1206 );
1207 }
1208
1209 #[test]
1210 fn native_mask_quad() {
1211 let layout = native_layout(0x33, 4);
1212 assert_eq!(
1213 AudioDecoderInner::convert_channel_layout(&layout, 4),
1214 ChannelLayout::Quad
1215 );
1216 }
1217
1218 #[test]
1219 fn native_mask_surround5_0() {
1220 let layout = native_layout(0x37, 5);
1221 assert_eq!(
1222 AudioDecoderInner::convert_channel_layout(&layout, 5),
1223 ChannelLayout::Surround5_0
1224 );
1225 }
1226
1227 #[test]
1228 fn native_mask_surround5_1() {
1229 let layout = native_layout(0x3F, 6);
1230 assert_eq!(
1231 AudioDecoderInner::convert_channel_layout(&layout, 6),
1232 ChannelLayout::Surround5_1
1233 );
1234 }
1235
1236 #[test]
1237 fn native_mask_surround6_1() {
1238 let layout = native_layout(0x13F, 7);
1239 assert_eq!(
1240 AudioDecoderInner::convert_channel_layout(&layout, 7),
1241 ChannelLayout::Surround6_1
1242 );
1243 }
1244
1245 #[test]
1246 fn native_mask_surround7_1() {
1247 let layout = native_layout(0x63F, 8);
1248 assert_eq!(
1249 AudioDecoderInner::convert_channel_layout(&layout, 8),
1250 ChannelLayout::Surround7_1
1251 );
1252 }
1253
1254 #[test]
1255 fn native_mask_unknown_falls_back_to_from_channels() {
1256 let layout = native_layout(0x1, 2);
1258 assert_eq!(
1259 AudioDecoderInner::convert_channel_layout(&layout, 2),
1260 ChannelLayout::from_channels(2)
1261 );
1262 }
1263
1264 #[test]
1265 fn non_native_order_falls_back_to_from_channels() {
1266 let layout = unspec_layout(6);
1267 assert_eq!(
1268 AudioDecoderInner::convert_channel_layout(&layout, 6),
1269 ChannelLayout::from_channels(6)
1270 );
1271 }
1272}