@@ -5062,9 +5062,12 @@ def test_audio_demuxer_seek(self):
50625062 # ===== Audio decoding: RawAudioSamples =====
50635063
50645064 @staticmethod
5065- def _decode_audio (asset , stream_index = None ):
5065+ def _decode_audio (asset , stream_index = None , seek_seconds = None ):
50665066 demuxer = AudioDemuxer (asset .path , stream_index = stream_index )
50675067 decoder = AudioPacketDecoder (demuxer )
5068+ if seek_seconds is not None :
5069+ demuxer .seek (seek_seconds )
5070+ decoder .reset ()
50685071 chunks = []
50695072 for packet in demuxer :
50705073 chunks += decoder .decode (packet )
@@ -5117,11 +5120,39 @@ def test_audio_raw_samples_dtype_and_shape(self, asset, sample_format, dtype):
51175120 NASA_AUDIO ,
51185121 ),
51195122 )
5120- def test_audio_raw_samples_match_audio_decoder (self , asset ):
5123+ @pytest .mark .parametrize ("seek_fraction" , (None , 1 / 3 , 2 / 3 ))
5124+ def test_audio_raw_samples_match_audio_decoder (self , asset , seek_fraction ):
51215125 # We hand out the true source samples: normalizing them the way FFmpeg
51225126 # does reproduces AudioDecoder's output bit for bit. This is also what
51235127 # pins the de-interleaving, most visibly on the 16-channel asset.
5124- raw = torch .cat ([chunk .data for chunk in self ._decode_audio (asset )], dim = 1 )
5128+ #
5129+ # It holds after a seek too, but only once the caller has done the
5130+ # pre-roll these blocks don't do: a lossy codec decodes its first frames
5131+ # after a seek from a flushed state, so they come out subtly wrong -
5132+ # plausible, but not what whole-file decoding gives - until it
5133+ # re-primes. Dropping those frames is exactly what pre-rolling means,
5134+ # and everything from there on is bit exact again. Without the drop,
5135+ # mp3 and aac diverge over their first ~1000-1600 samples and match
5136+ # perfectly after that.
5137+ if seek_fraction is not None and asset is SINE_STEREO_MP2_MPEG_PS :
5138+ pytest .skip (
5139+ "MPEG-PS resync after a seek is unreliable for both the blocks "
5140+ "and AudioDecoder (which raises seeking this file to 2.8s), so "
5141+ "it can't tell us anything here. See "
5142+ "test_audio_decoder_mpeg_ps_resync_after_seek."
5143+ )
5144+
5145+ seek_seconds = (
5146+ None if seek_fraction is None else asset .duration_seconds * seek_fraction
5147+ )
5148+ chunks = self ._decode_audio (asset , seek_seconds = seek_seconds )
5149+ if seek_seconds is not None :
5150+ # Same number of frames SingleStreamDecoder pre-rolls by, see
5151+ # Note [Audio pre-roll and post-roll].
5152+ chunks = chunks [4 :]
5153+ assert len (chunks ) > 0
5154+
5155+ raw = torch .cat ([chunk .data for chunk in chunks ], dim = 1 )
51255156
51265157 if raw .dtype == torch .uint8 :
51275158 got = (raw .to (torch .float32 ) - 128 ) / 128
@@ -5130,7 +5161,15 @@ def test_audio_raw_samples_match_audio_decoder(self, asset):
51305161 else :
51315162 got = raw .to (torch .float32 )
51325163
5133- expected = AudioDecoder (asset .path ).get_all_samples ().data
5164+ decoder = AudioDecoder (asset .path )
5165+ if seek_seconds is None :
5166+ expected = decoder .get_all_samples ().data
5167+ else :
5168+ # Re-anchor on the first frame we kept, so both sides start on the
5169+ # same sample.
5170+ expected = decoder .get_samples_played_in_range (
5171+ start_seconds = chunks [0 ].pts_seconds
5172+ ).data
51345173 torch .testing .assert_close (got , expected , atol = 0 , rtol = 0 )
51355174
51365175 def test_audio_raw_samples_pts (self ):
0 commit comments