breakfastquay / rubberband

Official mirror of Rubber Band Library, an audio time-stretching and pitch-shifting library.
http://breakfastquay.com/rubberband/
GNU General Public License v2.0
561 stars 89 forks source link

ignore invalid wav size for files larger than 4GiB #101

Open milahu opened 2 months ago

milahu commented 2 months ago

currently rubberband honors invalid wav sizes and silently produces cropped output files

$ ffmpeg -i src.mkv -map 0:a:0 src.mkv.a0.wav
[wav @ 0x586900] Filesize 5088049254 invalid for wav, output file will be broken
[out#0/wav @ 0x5858c0] video:0kB audio:4968798kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000002%
size= 4968798kB time=02:27:13.40 bitrate=4608.0kbits/s speed=5.81x    

$ # fix tempo from 24 to 24000/1001 fps

$ rubberband --time 1.001 src.mkv.a0.wav src.mkv.a0.wav.fixed-tempo.wav

$ ffprobe-get-duration.sh *mkv *wav
8833.418000  02:27:13.418000  src.mkv
8833.418667  02:27:13.418667  src.mkv.a0.wav
7463.996979  02:04:23.996979  src.mkv.a0.wav.fixed-tempo.wav

$ du -b *wav
5088049254      src.mkv.a0.wav
4299262340      src.mkv.a0.wav.fixed-tempo.wav

$ python -c 'print(4299262340/1024/1024/1024)'
4.004000071436167

$ ffmpeg -i src.mkv.a0.wav 2>&1 | grep Audio
  Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 48000 Hz, 5.1(side), s16, 4608 kb/s

$ mpv src.mkv --audio-file=src.mkv.a0.wav
[ffmpeg/demuxer] wav: Ignoring maximum wav data size, file may be invalid
[ffmpeg/demuxer] wav: Estimating duration from bitrate, this may be inaccurate

https://en.wikipedia.org/wiki/WAV

The WAV format is limited to files that are less than 4 GiB, because of its use of a 32-bit unsigned integer to record the file size in the header. Although this is equivalent to about 6.8 hours of CD-quality audio at 44.1 kHz, 16-bit stereo, it is sometimes necessary to exceed this limit, especially when greater sampling rates, bit resolutions or channel count are required. The W64 format was therefore created for use in Sound Forge. Its 64-bit file size field in the header allows for much longer recording times. The RF64 format specified by the European Broadcasting Union has also been created to solve this problem.

ffprobe-get-duration.sh ```sh #!/bin/sh # https://trac.ffmpeg.org/wiki/FFprobeTips#Formatcontainerduration set -e set -u for f in "$@"; do # duration in float seconds, including milliseconds duration=$(ffprobe -i "$f" -loglevel 0 -show_entries format=duration -of default=nw=1:nk=1) # get nanoseconds. jq does not support %f or %N format duration_ns=${duration#*.} if [ "$duration" = "$duration_ns" ]; then duration_ns=000000 fi duration_h=$(echo $duration | jq -r 'tonumber | strftime("%H:%M:%S")').$duration_ns echo "$duration $duration_h $f" done ```

possible workarounds

RF64 works

$ ffmpeg -i src.mkv -map 0:a:0 -rf64 auto src.mkv.a0.rf64.wav
$ rubberband --time 1.001 src.mkv.a0.rf64.wav src.mkv.a0.rf64.wav.fixed-tempo.wav
$ ffprobe-get-duration.sh *wav
8833.418667  02:27:13.418667  src.mkv.a0.rf64.wav
8842.252083  02:27:22.252083  src.mkv.a0.rf64.wav.fixed-tempo.wav
$ python -c 'print(8833.418667 * 1.001)'
8842.252085667