On Wed, Oct 25, 2023 at 12:06:05AM +0600, Maria Morisot wrote:
> 
> I don't have a test machine and I'm trying to keep my installation
> as simple as possible, but if anyone wants to try piping a wav file
> into mplayer or ffplay, I'd be interested in the results. Does it
> work?

faad -o file.wav file.m4a

results in a file.wav that aucat and most players can play.

faad -w file.m4a | cat >file.wav

results in a file with zero-size data chunk (because faad couldn't
seek to the beginning of the file to fixup the header). aucat,
audacious, audacity and sox can't play it; mpv, and ffplay can

Here's a diff for aucat to cope with such files:

  - if the header indicates zero-size data chunk, try to play the data
    until the end of the file is reached

  - if there are small sections to skip (padding for alignement or
    meta info), then read it instead of using lseek(2)

  - short reads are allowed for pipes, so when reading the headers,
    retry if needed.

please test

Index: afile.c
===================================================================
RCS file: /cvs/src/usr.bin/aucat/afile.c,v
diff -u -p -r1.12 afile.c
--- afile.c     27 Mar 2023 15:36:18 -0000      1.12
+++ afile.c     24 Oct 2023 20:05:30 -0000
@@ -217,14 +217,60 @@ be32_set(be32_t *p, unsigned int v)
 }
 
 static int
+afile_readseg(struct afile *f, void *addr, size_t size)
+{
+       ssize_t n;
+
+       /*
+        * retry as pipes may return fewer bytes than requested
+        */
+       while (size > 0) {
+               n = read(f->fd, addr, size);
+               if (n == 0 || n == -1)
+                       return 0;
+               addr = (char *)addr + n;
+               size -= n;
+               f->curpos += n;
+       }
+       return 1;
+}
+
+static int
+afile_setpos(struct afile *f, off_t pos)
+{
+       static char unused[512];
+       off_t off = pos - f->curpos;
+
+       /*
+        * seek only if needed (to avoid errors with pipes)
+        */
+       if (off != 0) {
+               /*
+                * to skip few bytes only (padding, meta-info), simply read
+                * them instead of using lseek(2)
+                */
+               if (off > 0 && off <= sizeof(unused)) {
+                       log_puts("reading\n");
+                       return afile_readseg(f, unused, off);
+               }
+
+               log_puts("seeking\n");
+               if (lseek(f->fd, pos, SEEK_SET) == -1)
+                       return 0;
+               f->curpos = pos;
+       }
+       return 1;
+}
+
+static int
 afile_readhdr(struct afile *f, void *addr, size_t size)
 {
-       if (lseek(f->fd, 0, SEEK_SET) == -1) {
+       if (!afile_setpos(f, 0)) {
                log_puts(f->path);
                log_puts(": failed to seek to beginning of file\n");
                return 0;
        }
-       if (read(f->fd, addr, size) != size) {
+       if (!afile_readseg(f, addr, size)) {
                log_puts(f->path);
                log_puts(": failed to read header\n");
                return 0;
@@ -301,7 +347,7 @@ afile_wav_readfmt(struct afile *f, unsig
        }
        if (csize > WAV_FMT_EXT_SIZE)
                csize = WAV_FMT_EXT_SIZE;
-       if (read(f->fd, &fmt, csize) != csize) {
+       if (!afile_readseg(f, &fmt, csize)) {
                log_puts(f->path);
                log_puts(": failed to read format chunk\n");
                return 0;
@@ -377,7 +423,7 @@ afile_wav_readhdr(struct afile *f)
                        log_puts(": missing data chunk\n");
                        return 0;
                }
-               if (read(f->fd, &chunk, sizeof(chunk)) != sizeof(chunk)) {
+               if (!afile_readseg(f, &chunk, sizeof(chunk))) {
                        log_puts(f->path);
                        log_puts(": failed to read chunk header\n");
                        return 0;
@@ -389,7 +435,15 @@ afile_wav_readhdr(struct afile *f)
                        fmt_done = 1;
                } else if (memcmp(chunk.id, wav_id_data, 4) == 0) {
                        f->startpos = pos + sizeof(riff) + sizeof(chunk);
-                       f->endpos = f->startpos + csize;
+                       if (csize > 0)
+                               f->endpos = f->startpos + csize;
+                       else {
+                               if (log_level >= 2) {
+                                       log_puts(f->path);
+                                       log_puts(": reading to end-fo-file\n");
+                               }
+                               f->endpos = -1; /* read until EOF */
+                       }
                        break;
                } else {
 #ifdef DEBUG
@@ -404,7 +458,7 @@ afile_wav_readhdr(struct afile *f)
                 * next chunk
                 */
                pos += sizeof(struct wav_chunk) + csize;
-               if (lseek(f->fd, sizeof(riff) + pos, SEEK_SET) == -1) {
+               if (!afile_setpos(f, sizeof(riff) + pos)) {
                        log_puts(f->path);
                        log_puts(": failed to seek to chunk\n");
                        return 0;
@@ -465,7 +519,7 @@ afile_aiff_readcomm(struct afile *f, uns
                log_puts(": bogus comm chunk size\n");
                return 0;
        }
-       if (read(f->fd, &comm, csize_min) != csize_min) {
+       if (!afile_readseg(f, &comm, csize_min)) {
                log_puts(f->path);
                log_puts(": failed to read comm chunk\n");
                return 0;
@@ -522,7 +576,7 @@ afile_aiff_readdata(struct afile *f, uns
                return 0;
        }
        csize = sizeof(struct aiff_data);
-       if (read(f->fd, &data, csize) != csize) {
+       if (!afile_readseg(f, &data, csize)) {
                log_puts(f->path);
                log_puts(": failed to read data chunk\n");
                return 0;
@@ -562,7 +616,7 @@ afile_aiff_readhdr(struct afile *f)
                        log_puts(": missing data chunk\n");
                        return 0;
                }
-               if (read(f->fd, &chunk, sizeof(chunk)) != sizeof(chunk)) {
+               if (!afile_readseg(f, &chunk, sizeof(chunk))) {
                        log_puts(f->path);
                        log_puts(": failed to read chunk header\n");
                        return 0;
@@ -598,7 +652,7 @@ afile_aiff_readhdr(struct afile *f)
                csize = (csize + 1) & ~1;
                pos += sizeof(struct aiff_chunk) + csize;
 
-               if (lseek(f->fd, sizeof(form) + pos, SEEK_SET) == -1) {
+               if (!afile_setpos(f, sizeof(form) + pos)) {
                        log_puts(f->path);
                        log_puts(": failed to seek to chunk\n");
                        return 0;
@@ -609,7 +663,15 @@ afile_aiff_readhdr(struct afile *f)
                log_puts(": missing comm chunk\n");
                return 0;
        }
-       f->endpos = f->startpos + f->par.bps * f->nch * nfr;
+       if (nfr > 0)
+               f->endpos = f->startpos + f->par.bps * f->nch * nfr;
+       else {
+               if (log_level >= 2) {
+                       log_puts(f->path);
+                       log_puts(": reading to end-fo-file\n");
+               }
+               f->endpos = -1; /* read until EOF */
+       }
        return 1;
 }
 
@@ -660,6 +722,7 @@ afile_au_readhdr(struct afile *f)
 {
        struct au_hdr hdr;
        unsigned int fmt;
+       off_t size;
 
        if (!afile_readhdr(f, &hdr, sizeof(struct au_hdr)))
                return 0;
@@ -669,7 +732,16 @@ afile_au_readhdr(struct afile *f)
                return 0;
        }
        f->startpos = be32_get(&hdr.offs);
-       f->endpos = f->startpos + be32_get(&hdr.size);
+       size = be32_get(&hdr.size);
+       if (size > 0)
+               f->endpos = f->startpos + size;
+       else {
+               if (log_level >= 2) {
+                       log_puts(f->path);
+                       log_puts(": reading to end-fo-file\n");
+               }
+               f->endpos = -1; /* read until EOF */
+       }
        fmt = be32_get(&hdr.fmt);
        switch (fmt) {
        case AU_FMT_PCM8:
@@ -713,7 +785,7 @@ afile_au_readhdr(struct afile *f)
        f->par.msb = 0;
        f->rate = be32_get(&hdr.rate);
        f->nch = be32_get(&hdr.nch);
-       if (lseek(f->fd, f->startpos, SEEK_SET) == -1) {
+       if (!afile_setpos(f, f->startpos)) {
                log_puts(f->path);
                log_puts(": ");
                log_puts("failed to seek to data chunk\n");
@@ -907,6 +979,7 @@ afile_open(struct afile *f, char *path, 
                                return 0;
                        }
                }
+               f->curpos = 0;
                if (f->hdr == AFILE_HDR_WAV) {
                        if (!afile_wav_readhdr(f))
                                goto bad_close;
@@ -921,7 +994,6 @@ afile_open(struct afile *f, char *path, 
                        f->endpos = -1; /* read until EOF */
                        f->fmt = AFILE_FMT_PCM;
                }
-               f->curpos = f->startpos;
        } else if (flags == AFILE_FWRITE) {
                if (strcmp(path, "-") == 0) {
                        f->path = "stdout";

Reply via email to