@@ -5,6 +5,7 @@ use std::{
55
66use ffmpeg_audio:: {
77 AudioReader ,
8+ RawAudioData ,
89 ResampleOptions ,
910 SeekMode ,
1011} ;
@@ -419,6 +420,79 @@ fn test_planar_format_mismatch_rejection_planar_to_packed() {
419420 ) ;
420421}
421422
423+ #[ test]
424+ fn test_raw_data_extraction_packed_and_type_safety ( ) {
425+ let wav_data = generate_sine_wav ( 0.1 ) ;
426+ let mut reader = AudioReader :: new ( Cursor :: new ( wav_data) ) . unwrap ( ) ;
427+
428+ let channels = reader. source_info ( ) . channels as usize ;
429+
430+ let frame = reader. receive_frame ( ) . unwrap ( ) . expect ( "应能读取到 WAV 帧" ) ;
431+
432+ let err_result = frame. raw_data :: < f32 > ( ) ;
433+ assert ! (
434+ matches!( err_result, Err ( ffmpeg_audio:: AudioError :: FormatMismatch ) ) ,
435+ "期望类型不匹配错误,但得到了: {err_result:?}"
436+ ) ;
437+
438+ let raw = frame. raw_data :: < i16 > ( ) . expect ( "提取 i16 原始数据失败" ) ;
439+
440+ match raw {
441+ RawAudioData :: Packed ( data) => {
442+ let expected_len = frame. samples ( ) * channels;
443+
444+ assert_eq ! (
445+ data. len( ) ,
446+ expected_len,
447+ "Packed 切片的元素总数 ({}) 应等于逻辑样本数 ({}) 乘以声道数 ({})" ,
448+ data. len( ) ,
449+ frame. samples( ) ,
450+ channels
451+ ) ;
452+
453+ let has_signal = data. iter ( ) . any ( |& s| s != 0 ) ;
454+ assert ! ( has_signal, "捞出的原始 PCM 不应全为静音" ) ;
455+ }
456+ RawAudioData :: Planar ( _) => panic ! ( "WAV 应该被解码为 Packed 布局,却得到了 Planar" ) ,
457+ }
458+ }
459+
460+ #[ test]
461+ fn test_raw_data_signal_integrity_across_frames ( ) {
462+ let sample_rate = 44100 ;
463+ let freq: f32 = 440.0 ;
464+ let duration = 0.1 ;
465+
466+ let wav_data = generate_sine_wav ( duration) ;
467+ let mut reader = AudioReader :: new ( Cursor :: new ( wav_data) ) . unwrap ( ) ;
468+
469+ let mut global_sample_index = 0 ;
470+
471+ while let Some ( frame) = reader. receive_frame ( ) . unwrap ( ) {
472+ let raw = frame. raw_data :: < i16 > ( ) . expect ( "提取 i16 失败" ) ;
473+
474+ if let RawAudioData :: Packed ( data) = raw {
475+ for & actual_sample in data {
476+ let t = global_sample_index as f32 / sample_rate as f32 ;
477+ let expected_sample =
478+ ( f32:: sin ( 2.0 * std:: f32:: consts:: PI * freq * t) * 16000.0 ) as i16 ;
479+
480+ let diff = ( i32:: from ( actual_sample) - i32:: from ( expected_sample) ) . abs ( ) ;
481+ assert ! (
482+ diff <= 1 ,
483+ "信号失真!在全局样本索引 {global_sample_index} 期望 {expected_sample}, 实际得到 {actual_sample}"
484+ ) ;
485+
486+ global_sample_index += 1 ;
487+ }
488+ } else {
489+ panic ! ( "WAV 应为 Packed 格式" ) ;
490+ }
491+ }
492+
493+ assert_eq ! ( global_sample_index, 4410 , "解码出的样本总数不对" ) ;
494+ }
495+
422496#[ cfg( not( target_arch = "wasm32" ) ) ]
423497mod file_tests {
424498 use std:: fs:: File ;
@@ -495,4 +569,45 @@ mod file_tests {
495569 "Should have successfully decoded mutated stream"
496570 ) ;
497571 }
572+
573+ #[ test]
574+ fn test_raw_data_extraction_planar_with_seek_offset ( ) {
575+ let file = File :: open ( AAC_SEEK_PATH ) . expect ( "Failed to open AAC test asset" ) ;
576+ let mut reader = AudioReader :: new ( file) . unwrap ( ) ;
577+
578+ let expected_channels = reader. source_info ( ) . channels as usize ;
579+
580+ let target = Duration :: from_millis ( 501 ) ;
581+ reader. seek ( target, SeekMode :: Accurate ) . unwrap ( ) ;
582+
583+ let frame = reader. receive_frame ( ) . unwrap ( ) . expect ( "Seek 后读取帧失败" ) ;
584+
585+ assert ! ( frame. samples( ) > 0 , "修剪后应仍有剩余数据" ) ;
586+
587+ let raw = frame. raw_data :: < f32 > ( ) . expect ( "提取 f32 原始数据失败" ) ;
588+
589+ match raw {
590+ RawAudioData :: Planar ( planes) => {
591+ assert_eq ! (
592+ planes. len( ) ,
593+ expected_channels,
594+ "返回的平面切片数量 ({}) 应等于文件的物理声道数 ({})" ,
595+ planes. len( ) ,
596+ expected_channels
597+ ) ;
598+
599+ for ( ch_idx, plane) in planes. iter ( ) . enumerate ( ) {
600+ assert_eq ! (
601+ plane. len( ) ,
602+ frame. samples( ) ,
603+ "声道 {ch_idx} 的切片长度未与修剪后的样本数对齐"
604+ ) ;
605+
606+ let has_signal = plane. iter ( ) . any ( |& s| s. abs ( ) > 0.0 ) ;
607+ assert ! ( has_signal, "提取出来的声道 {ch_idx} 数据异常" ) ;
608+ }
609+ }
610+ RawAudioData :: Packed ( _) => panic ! ( "AAC 应该被解码为 Planar 布局,却得到了 Packed" ) ,
611+ }
612+ }
498613}
0 commit comments