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