Hi, I have a couple of patches which add RF64 support to SoX. They've been in the patch queue [*] for a while, can they make the forthcoming release?
RF64 is an EBU developed extension to the WAV file format to add support for files larger than 4Gb. The full spec is here, http://tech.ebu.ch/docs/tech/tech3306-2009.pdf rf64.patch -- Add read support for RF64 files. sndfile_workaround.patch -- Extends this support to successfully read files generated by a buggy version of libsndfile which was distributed with Ubuntu 10.04 and probably elsewhere. Best regards, Dave Lambley [*] https://sourceforge.net/p/sox/patches/99/ On 16 October 2014 02:56, Chris Bagwell <ch...@cnpbagwell.com> wrote: > > > On Sun, Oct 12, 2014 at 7:31 PM, Eric Wong <normalper...@yhbt.net> wrote: > >> Chris Bagwell <ch...@cnpbagwell.com> wrote: >> > I'm flexible if anyone has a feature they wanted to get in but here is >> > rough schedule: >> >> Hi Chris, great to know a new release is on the way! >> >> I would like my LADSPA latency compensation patch looked at and >> hopefully merged: https://sourceforge.net/p/sox/patches/101/ >> >> I think that's it; haven't had much time for audio this year :x >> >> > Hi Eric. Let me push out the RC build until I have time to review your > patch and try to incorporate it. Hopefully done by this weekend. > > Thanks! > > Chris > > > > ------------------------------------------------------------------------------ > Comprehensive Server Monitoring with Site24x7. > Monitor 10 servers for $9/Month. > Get alerted through email, SMS, voice calls or mobile push notifications. > Take corrective actions from your mobile device. > http://p.sf.net/sfu/Zoho > _______________________________________________ > SoX-devel mailing list > SoX-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/sox-devel > >
diff --git a/src/formats.c b/src/formats.c index 1a8c503..724a4cd 100644 --- a/src/formats.c +++ b/src/formats.c @@ -62,6 +62,7 @@ static char const * auto_detect_format(sox_format_t * ft, char const * ext) CHECK(hcom ,65, 4, "FSSD" , 128,4, "HCOM") CHECK(wav , 0, 4, "RIFF" , 8, 4, "WAVE") CHECK(wav , 0, 4, "RIFX" , 8, 4, "WAVE") + CHECK(wav , 0, 4, "RF64" , 8, 4, "WAVE") CHECK(aiff , 0, 4, "FORM" , 8, 4, "AIFF") CHECK(aifc , 0, 4, "FORM" , 8, 4, "AIFC") CHECK(8svx , 0, 4, "FORM" , 8, 4, "8SVX") diff --git a/src/wav.c b/src/wav.c index d714ccf..cf74aae 100644 --- a/src/wav.c +++ b/src/wav.c @@ -94,6 +94,8 @@ typedef struct { gsm_signal *gsmsample; int gsmindex; size_t gsmbytecount; /* counts bytes written to data block */ + sox_bool isRF64; /* True if file being read is a RF64 */ + uint64_t ds64_dataSize; /* Size of data chunk from ds64 header */ } priv_t; static char *wav_format_str(unsigned wFormatTag); @@ -370,9 +372,13 @@ static void wavgsmstopwrite(sox_format_t * ft) /****************************************************************************/ /* General Sox WAV file code */ /****************************************************************************/ -static int findChunk(sox_format_t * ft, const char *Label, uint32_t *len) +static int findChunk(sox_format_t * ft, const char *Label, uint64_t *len) { char magic[5]; + priv_t *wav = (priv_t *) ft->priv; + uint32_t len_tmp; + + lsx_debug("Searching for %2x %2x %2x %2x", Label[0], Label[1], Label[2], Label[3]); for (;;) { if (lsx_reads(ft, magic, (size_t)4) == SOX_EOF) @@ -382,24 +388,41 @@ static int findChunk(sox_format_t * ft, const char *Label, uint32_t *len) return SOX_EOF; } lsx_debug("WAV Chunk %s", magic); - if (lsx_readdw(ft, len) == SOX_EOF) + if (lsx_readdw(ft, &len_tmp) == SOX_EOF) { lsx_fail_errno(ft, SOX_EHDR, "WAVE file %s chunk is too short", magic); return SOX_EOF; } - if (strncmp(Label, magic, (size_t)4) == 0) + if (len_tmp == 0xffffffff && wav->isRF64==sox_true) + { + /* Chunk length should come from ds64 header */ + if (memcmp(magic, "data", (size_t)4)==0) + { + *len = wav->ds64_dataSize; + } + else + { + lsx_fail_errno(ft, SOX_EHDR, "Cannot yet read block sizes of arbitary RF64 chunks, cannot find chunk '%s'", Label); + return SOX_EOF; + } + } + else { + *len = len_tmp; + } + + if (memcmp(Label, magic, (size_t)4) == 0) break; /* Found the given chunk */ - /* Chunks are required to be word aligned. */ - if ((*len) % 2) (*len)++; + /* Chunks are required to be word aligned. */ + if ((*len) % 2) (*len)++; /* skip to next chunk */ if (*len > 0 && lsx_seeki(ft, (off_t)(*len), SEEK_CUR) != SOX_SUCCESS) { lsx_fail_errno(ft,SOX_EHDR, - "WAV chunk appears to have invalid size %d.", *len); + "WAV chunk appears to have invalid size %ld.", *len); return SOX_EOF; } } @@ -424,10 +447,11 @@ static int startread(sox_format_t * ft) { priv_t * wav = (priv_t *) ft->priv; char magic[5]; - uint32_t len; + uint64_t len; /* wave file characteristics */ - uint32_t dwRiffLength; + uint64_t qwRiffLength; + uint32_t dwRiffLength_tmp; unsigned short wChannels; /* number of channels */ uint32_t dwSamplesPerSecond; /* samples per second per channel */ uint32_t dwAvgBytesPerSec;/* estimate of bytes per second needed */ @@ -435,7 +459,7 @@ static int startread(sox_format_t * ft) uint32_t wFmtSize; uint16_t wExtSize = 0; /* extended field for non-PCM */ - uint32_t dwDataLength; /* length of sound data in bytes */ + uint64_t qwDataLength; /* length of sound data in bytes */ size_t bytesPerBlock = 0; int bytespersample; /* bytes per sample (per channel */ char text[256]; @@ -445,7 +469,7 @@ static int startread(sox_format_t * ft) wav->ignoreSize = ft->signal.length == SOX_IGNORE_LENGTH; if (lsx_reads(ft, magic, (size_t)4) == SOX_EOF || (strncmp("RIFF", magic, (size_t)4) != 0 && - strncmp("RIFX", magic, (size_t)4) != 0)) + strncmp("RIFX", magic, (size_t)4) != 0 && strncmp("RF64", magic, (size_t)4)!=0 )) { lsx_fail_errno(ft,SOX_EHDR,"WAVE: RIFF header not found"); return SOX_EOF; @@ -459,7 +483,17 @@ static int startread(sox_format_t * ft) } else ft->encoding.reverse_bytes = MACHINE_IS_BIGENDIAN; - lsx_readdw(ft, &dwRiffLength); + if (strncmp("RF64", magic, (size_t)4) == 0) + { + wav->isRF64 = sox_true; + } + else + { + wav->isRF64 = sox_false; + } + + lsx_readdw(ft, &dwRiffLength_tmp); + qwRiffLength = dwRiffLength_tmp; if (lsx_reads(ft, magic, (size_t)4) == SOX_EOF || strncmp("WAVE", magic, (size_t)4)) { @@ -467,6 +501,21 @@ static int startread(sox_format_t * ft) return SOX_EOF; } + if (wav->isRF64 && findChunk(ft, "ds64", &len) != SOX_EOF) { + lsx_debug("Found ds64 header"); + + if (dwRiffLength_tmp==0xffffffff) + { + lsx_readqw(ft, &qwRiffLength); + } + else + { + lsx_skipbytes(ft, (size_t)8); + } + lsx_readqw(ft, &wav->ds64_dataSize); + lsx_skipbytes(ft, (size_t)len-16); + } + /* Now look for the format chunk */ if (findChunk(ft, "fmt ", &len) == SOX_EOF) { @@ -804,8 +853,11 @@ static int startread(sox_format_t * ft) lsx_fail_errno(ft, SOX_EOF, "Could not find data chunk."); return SOX_EOF; } - dwDataLength = len; - if (dwDataLength == MS_UNSPEC) { + + /* ds64 size will have been applied in findChunk */ + qwDataLength = len; + /* XXX - does MS_UNSPEC apply to RF64 files? */ + if (qwDataLength == MS_UNSPEC) { wav->ignoreSize = 1; lsx_debug("WAV Chunk data's length is value often used in pipes or 4G files. Ignoring length."); } @@ -819,9 +871,9 @@ static int startread(sox_format_t * ft) case WAVE_FORMAT_ADPCM: wav->numSamples = - lsx_ms_adpcm_samples_in((size_t)dwDataLength, (size_t)ft->signal.channels, + lsx_ms_adpcm_samples_in((size_t)qwDataLength, (size_t)ft->signal.channels, (size_t)wav->blockAlign, (size_t)wav->samplesPerBlock); - lsx_debug_more("datalen %d, numSamples %lu",dwDataLength, (unsigned long)wav->numSamples); + lsx_debug_more("datalen %ld, numSamples %lu",qwDataLength, (unsigned long)wav->numSamples); wav->blockSamplesRemaining = 0; /* Samples left in buffer */ ft->signal.length = wav->numSamples*ft->signal.channels; break; @@ -830,22 +882,22 @@ static int startread(sox_format_t * ft) /* Compute easiest part of number of samples. For every block, there are samplesPerBlock samples to read. */ wav->numSamples = - lsx_ima_samples_in((size_t)dwDataLength, (size_t)ft->signal.channels, + lsx_ima_samples_in((size_t)qwDataLength, (size_t)ft->signal.channels, (size_t)wav->blockAlign, (size_t)wav->samplesPerBlock); - lsx_debug_more("datalen %d, numSamples %lu",dwDataLength, (unsigned long)wav->numSamples); + lsx_debug_more("datalen %ld, numSamples %lu",qwDataLength, (unsigned long)wav->numSamples); wav->blockSamplesRemaining = 0; /* Samples left in buffer */ lsx_ima_init_table(); ft->signal.length = wav->numSamples*ft->signal.channels; break; case WAVE_FORMAT_GSM610: - wav->numSamples = ((dwDataLength / wav->blockAlign) * wav->samplesPerBlock); + wav->numSamples = ((qwDataLength / wav->blockAlign) * wav->samplesPerBlock); wavgsminit(ft); ft->signal.length = wav->numSamples*ft->signal.channels; break; default: - wav->numSamples = div_bits(dwDataLength, ft->encoding.bits_per_sample) / ft->signal.channels; + wav->numSamples = div_bits(qwDataLength, ft->encoding.bits_per_sample) / ft->signal.channels; ft->signal.length = wav->numSamples * ft->signal.channels; } @@ -858,8 +910,8 @@ static int startread(sox_format_t * ft) lsx_debug("Reading Wave file: %s format, %d channel%s, %d samp/sec", wav_format_str(wav->formatTag), ft->signal.channels, wChannels == 1 ? "" : "s", dwSamplesPerSecond); - lsx_debug(" %d byte/sec, %d block align, %d bits/samp, %u data bytes", - dwAvgBytesPerSec, wav->blockAlign, wBitsPerSample, dwDataLength); + lsx_debug(" %d byte/sec, %d block align, %d bits/samp, %lu data bytes", + dwAvgBytesPerSec, wav->blockAlign, wBitsPerSample, qwDataLength); /* Can also report extended fmt information */ switch (wav->formatTag) @@ -924,8 +976,10 @@ static int startread(sox_format_t * ft) } else { - if (lsx_readdw(ft,&len) == SOX_EOF) + uint32_t len_tmp; + if (lsx_readdw(ft,&len_tmp) == SOX_EOF) break; + len = len_tmp; if (strncmp(magic,"ICRD",(size_t)4) == 0) { lsx_debug("Chunk ICRD"); @@ -981,7 +1035,7 @@ static int startread(sox_format_t * ft) } else { - lsx_debug("Attempting to seek beyond unsupported chunk `%c%c%c%c' of length %d bytes", magic[0], magic[1], magic[2], magic[3], len); + lsx_debug("Attempting to seek beyond unsupported chunk `%c%c%c%c' of length %ld bytes", magic[0], magic[1], magic[2], magic[3], len); len = (len + 1) & ~1u; lsx_seeki(ft, (off_t)len, SEEK_CUR); }
diff --git a/src/wav.c b/src/wav.c index 303a2f9..a0b2cc6 100644 --- a/src/wav.c +++ b/src/wav.c @@ -372,6 +372,44 @@ static void wavgsmstopwrite(sox_format_t * ft) /****************************************************************************/ /* General Sox WAV file code */ /****************************************************************************/ + +static int sndfile_workaround(uint64_t *len, sox_format_t *ft) { + char magic[5]; + off_t here; + + here = lsx_tell(ft); + + lsx_debug("Attempting work around for bad ds64 length bug"); + + /* Seek to last four bytes of chunk, assuming size is correct. */ + if (lsx_seeki(ft, (off_t)(*len)-4, SEEK_CUR) != SOX_SUCCESS) + { + lsx_fail_errno(ft, SOX_EHDR, "WAV chunk appears to have invalid size %ld.", *len); + return SOX_EOF; + } + + /* Get the last four bytes to see if it is an "fmt " chunk */ + if (lsx_reads(ft, magic, (size_t)4) == SOX_EOF) + { + lsx_fail_errno(ft,SOX_EHDR, "WAV chunk appears to have invalid size %ld.", *len); + return SOX_EOF; + } + + /* Seek back to where we were, which won't work if you're piping */ + if (lsx_seeki(ft, here, SEEK_SET)!=SOX_SUCCESS) + { + lsx_fail_errno(ft,SOX_EHDR, "Cannot seek backwards to work around possible broken header."); + return SOX_EOF; + } + if (memcmp(magic, "fmt ", (size_t)4)==0) + { + /* If the last four bytes were "fmt ", len is almost certainly four bytes too big. */ + lsx_debug("File had libsndfile bug, working around tell=%ld", lsx_tell(ft)); + *len -= 4; + } + return SOX_SUCCESS; +} + static int findChunk(sox_format_t * ft, const char *Label, uint64_t *len) { char magic[5]; @@ -412,6 +450,18 @@ static int findChunk(sox_format_t * ft, const char *Label, uint64_t *len) *len = len_tmp; } + /* Work around for a bug in libsndfile + * https://github.com/erikd/libsndfile/commit/7fa1c57c37844a9d44642ea35e6638238b8af19e#src/rf64.c + The ds64 chunk should be 0x1c bytes, not 0x20. + */ + if ((*len) == 0x20 && memcmp(Label, "ds64", (size_t)4)==0) + { + int fail; + if ((fail = sndfile_workaround(len, ft)) != SOX_SUCCESS) { + return fail; + } + } + if (memcmp(Label, magic, (size_t)4) == 0) break; /* Found the given chunk */
------------------------------------------------------------------------------
_______________________________________________ SoX-devel mailing list SoX-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/sox-devel