@@ -5,7 +5,7 @@ use crate::buffer::{AudioBuffer, ChannelData};
5
5
6
6
use symphonia:: core:: audio:: AudioBufferRef ;
7
7
use symphonia:: core:: audio:: Signal ;
8
- use symphonia:: core:: codecs:: { Decoder , DecoderOptions } ;
8
+ use symphonia:: core:: codecs:: { Decoder , DecoderOptions , FinalizeResult } ;
9
9
use symphonia:: core:: conv:: FromSample ;
10
10
use symphonia:: core:: errors:: Error as SymphoniaError ;
11
11
use symphonia:: core:: formats:: { FormatOptions , FormatReader } ;
@@ -53,6 +53,8 @@ impl<R: Read + Send + Sync> symphonia::core::io::MediaSource for MediaInput<R> {
53
53
pub ( crate ) struct MediaDecoder {
54
54
format : Box < dyn FormatReader > ,
55
55
decoder : Box < dyn Decoder > ,
56
+ track_index : usize ,
57
+ packet_count : usize ,
56
58
}
57
59
58
60
impl MediaDecoder {
@@ -64,24 +66,27 @@ impl MediaDecoder {
64
66
pub fn try_new < R : std:: io:: Read + Send + Sync + ' static > (
65
67
input : R ,
66
68
) -> Result < Self , Box < dyn std:: error:: Error + Send + Sync > > {
67
- // Symfonia lib needs a Box<dyn MediaSource> - use our own MediaInput
69
+ // Symphonia lib needs a Box<dyn MediaSource> - use our own MediaInput
68
70
let input = Box :: new ( MediaInput :: new ( input) ) ;
69
71
70
72
// Create the media source stream using the boxed media source from above.
71
- let mss = symphonia:: core:: io:: MediaSourceStream :: new ( input, Default :: default ( ) ) ;
73
+ let stream = symphonia:: core:: io:: MediaSourceStream :: new ( input, Default :: default ( ) ) ;
72
74
73
75
// Create a hint to help the format registry guess what format reader is appropriate. In this
74
76
// function we'll leave it empty.
75
77
let hint = Hint :: new ( ) ;
76
78
77
- // Use the default options when reading and decoding .
79
+ // TODO: Allow to customize some options .
78
80
let format_opts: FormatOptions = Default :: default ( ) ;
79
81
let metadata_opts: MetadataOptions = Default :: default ( ) ;
80
- let decoder_opts: DecoderOptions = Default :: default ( ) ;
82
+ let decoder_opts = DecoderOptions {
83
+ // Opt-in to verify the decoded data against the checksums in the container.
84
+ verify : true ,
85
+ } ;
81
86
82
87
// Probe the media source stream for a format.
83
88
let probed =
84
- symphonia:: default:: get_probe ( ) . format ( & hint, mss , & format_opts, & metadata_opts) ?;
89
+ symphonia:: default:: get_probe ( ) . format ( & hint, stream , & format_opts, & metadata_opts) ?;
85
90
86
91
// Get the format reader yielded by the probe operation.
87
92
let format = probed. format ;
@@ -90,117 +95,140 @@ impl MediaDecoder {
90
95
let track = format. default_track ( ) . ok_or ( SymphoniaError :: Unsupported (
91
96
"no default media track available" ,
92
97
) ) ?;
93
-
98
+ let track_index = format
99
+ . tracks ( )
100
+ . iter ( )
101
+ . position ( |t| t. id == track. id )
102
+ . unwrap ( ) ;
94
103
// Create a (stateful) decoder for the track.
95
104
let decoder = symphonia:: default:: get_codecs ( ) . make ( & track. codec_params , & decoder_opts) ?;
96
105
97
- Ok ( Self { format, decoder } )
106
+ Ok ( Self {
107
+ format,
108
+ decoder,
109
+ track_index,
110
+ packet_count : 0 ,
111
+ } )
98
112
}
99
113
}
100
114
101
115
impl Iterator for MediaDecoder {
102
116
type Item = Result < AudioBuffer , Box < dyn Error + Send + Sync > > ;
103
117
104
118
fn next ( & mut self ) -> Option < Self :: Item > {
105
- let format = & mut self . format ;
106
- let decoder = & mut self . decoder ;
107
-
108
- // Get the default track.
109
- let track = format . default_track ( ) . unwrap ( ) ;
110
- let number_of_channels = track . codec_params . channels . unwrap ( ) . count ( ) ;
111
- let input_sample_rate = track . codec_params . sample_rate . unwrap ( ) as f32 ;
112
-
113
- // Store the track identifier, we'll use it to filter packets.
119
+ let Self {
120
+ format ,
121
+ decoder ,
122
+ track_index ,
123
+ packet_count ,
124
+ } = self ;
125
+
126
+ // Get the track.
127
+ let track = format . tracks ( ) . get ( * track_index ) ? ;
114
128
let track_id = track. id ;
115
129
116
130
loop {
117
131
// Get the next packet from the format reader.
118
132
let packet = match format. next_packet ( ) {
119
- Err ( e) => {
120
- log:: error!( "next packet err {:?}" , e) ;
121
- return None ;
133
+ Err ( err) => {
134
+ if let SymphoniaError :: IoError ( err) = & err {
135
+ if err. kind ( ) == std:: io:: ErrorKind :: UnexpectedEof {
136
+ // End of stream
137
+ log:: debug!( "Decoding finished after {packet_count} packet(s)" ) ;
138
+ let FinalizeResult { verify_ok } = decoder. finalize ( ) ;
139
+ if verify_ok == Some ( false ) {
140
+ log:: warn!( "Verification of decoded data failed" ) ;
141
+ }
142
+ return None ;
143
+ }
144
+ }
145
+ log:: warn!(
146
+ "Failed to fetch next packet following packet #{packet_count}: {err}"
147
+ ) ;
148
+ return Some ( Err ( Box :: new ( err) ) ) ;
149
+ }
150
+ Ok ( packet) => {
151
+ * packet_count += 1 ;
152
+ packet
122
153
}
123
- Ok ( p) => p,
124
154
} ;
125
155
126
156
// If the packet does not belong to the selected track, skip it.
127
- if packet. track_id ( ) != track_id {
157
+ let packet_track_id = packet. track_id ( ) ;
158
+ if packet_track_id != track_id {
159
+ log:: debug!(
160
+ "Skipping packet from other track {packet_track_id} while decoding track {track_id}"
161
+ ) ;
128
162
continue ;
129
163
}
130
164
131
- // Decode the packet into audio samples, ignoring any decode errors .
165
+ // Decode the packet into audio samples.
132
166
match decoder. decode ( & packet) {
133
- Ok ( audio_buf ) => {
134
- let output = convert_buf ( audio_buf , number_of_channels , input_sample_rate ) ;
167
+ Ok ( input ) => {
168
+ let output = convert_buf ( input ) ;
135
169
return Some ( Ok ( output) ) ;
136
170
}
137
- Err ( SymphoniaError :: DecodeError ( e) ) => {
138
- // Todo: treat decoding errors as fatal or move to next packet? Context:
139
- // https://github.com/RustAudio/rodio/issues/401#issuecomment-974747404
140
- log:: error!( "Symphonia DecodeError {:?} - abort stream" , e) ;
141
- return Some ( Err ( Box :: new ( SymphoniaError :: DecodeError ( e) ) ) ) ;
171
+ Err ( SymphoniaError :: DecodeError ( err) ) => {
172
+ // Recoverable error, continue with the next packet.
173
+ log:: warn!( "Failed to decode packet #{packet_count}: {err}" ) ;
142
174
}
143
- Err ( SymphoniaError :: IoError ( e) )
144
- if e. kind ( ) == std:: io:: ErrorKind :: UnexpectedEof =>
145
- {
146
- // this happens for Wav-files, running into EOF is expected
175
+ Err ( SymphoniaError :: IoError ( err) ) => {
176
+ // Recoverable error, continue with the next packet.
177
+ log:: warn!( "I/O error while decoding packet #{packet_count}: {err}" ) ;
147
178
}
148
- Err ( e ) => {
149
- // do not continue processing, return error result
150
- return Some ( Err ( Box :: new ( e ) ) ) ;
179
+ Err ( err ) => {
180
+ // All other errors are considered fatal and decoding must be aborted.
181
+ return Some ( Err ( Box :: new ( err ) ) ) ;
151
182
}
152
183
} ;
153
184
}
154
185
}
155
186
}
156
187
157
188
/// Convert a Symphonia AudioBufferRef to our own AudioBuffer
158
- fn convert_buf (
159
- input : AudioBufferRef < ' _ > ,
160
- number_of_channels : usize ,
161
- input_sample_rate : f32 ,
162
- ) -> AudioBuffer {
163
- let chans = 0 ..number_of_channels;
189
+ fn convert_buf ( input : AudioBufferRef < ' _ > ) -> AudioBuffer {
190
+ let channels = 0 ..input. spec ( ) . channels . count ( ) ;
191
+ let sample_rate = input. spec ( ) . rate as f32 ;
164
192
165
193
// This looks a bit awkward but this may be the only way to get the f32 samples
166
194
// out without making double copies.
167
195
use symphonia:: core:: audio:: AudioBufferRef :: * ;
168
196
169
197
let data: Vec < Vec < f32 > > = match input {
170
- U8 ( buf) => chans
198
+ U8 ( buf) => channels
171
199
. map ( |i| buf. chan ( i) . iter ( ) . copied ( ) . map ( f32:: from_sample) . collect ( ) )
172
200
. collect ( ) ,
173
- U16 ( buf) => chans
201
+ U16 ( buf) => channels
174
202
. map ( |i| buf. chan ( i) . iter ( ) . copied ( ) . map ( f32:: from_sample) . collect ( ) )
175
203
. collect ( ) ,
176
- U24 ( buf) => chans
204
+ U24 ( buf) => channels
177
205
. map ( |i| buf. chan ( i) . iter ( ) . copied ( ) . map ( f32:: from_sample) . collect ( ) )
178
206
. collect ( ) ,
179
- U32 ( buf) => chans
207
+ U32 ( buf) => channels
180
208
. map ( |i| buf. chan ( i) . iter ( ) . copied ( ) . map ( f32:: from_sample) . collect ( ) )
181
209
. collect ( ) ,
182
- S8 ( buf) => chans
210
+ S8 ( buf) => channels
183
211
. map ( |i| buf. chan ( i) . iter ( ) . copied ( ) . map ( f32:: from_sample) . collect ( ) )
184
212
. collect ( ) ,
185
- S16 ( buf) => chans
213
+ S16 ( buf) => channels
186
214
. map ( |i| buf. chan ( i) . iter ( ) . copied ( ) . map ( f32:: from_sample) . collect ( ) )
187
215
. collect ( ) ,
188
- S24 ( buf) => chans
216
+ S24 ( buf) => channels
189
217
. map ( |i| buf. chan ( i) . iter ( ) . copied ( ) . map ( f32:: from_sample) . collect ( ) )
190
218
. collect ( ) ,
191
- S32 ( buf) => chans
219
+ S32 ( buf) => channels
192
220
. map ( |i| buf. chan ( i) . iter ( ) . copied ( ) . map ( f32:: from_sample) . collect ( ) )
193
221
. collect ( ) ,
194
- F32 ( buf) => chans
222
+ F32 ( buf) => channels
195
223
. map ( |i| buf. chan ( i) . iter ( ) . copied ( ) . map ( f32:: from_sample) . collect ( ) )
196
224
. collect ( ) ,
197
- F64 ( buf) => chans
225
+ F64 ( buf) => channels
198
226
. map ( |i| buf. chan ( i) . iter ( ) . copied ( ) . map ( f32:: from_sample) . collect ( ) )
199
227
. collect ( ) ,
200
228
} ;
201
229
202
230
let channels = data. into_iter ( ) . map ( ChannelData :: from) . collect ( ) ;
203
- AudioBuffer :: from_channels ( channels, input_sample_rate )
231
+ AudioBuffer :: from_channels ( channels, sample_rate )
204
232
}
205
233
206
234
#[ cfg( test) ]
0 commit comments