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";