diff options
author | Sigrid Solveig Haflínudóttir <sigrid@ftrv.se> | 2023-02-11 16:52:56 +0000 |
---|---|---|
committer | Sigrid Solveig Haflínudóttir <sigrid@ftrv.se> | 2023-02-11 16:52:56 +0000 |
commit | 87a6e1873b3ebd90a6cc075b3a833cca5b675f1a (patch) | |
tree | 6c6f0814fbd487de278ef606599cc548d755510b /sys/src/cmd/audio | |
parent | 7f071685e9b7d9e32c1a9675f7fca0407d18e6e1 (diff) |
libtags: work around encoders producing Ogg containers with first granule position set to non-zero outside of the first page
Diffstat (limited to 'sys/src/cmd/audio')
-rw-r--r-- | sys/src/cmd/audio/libtags/opus.c | 24 | ||||
-rw-r--r-- | sys/src/cmd/audio/libtags/vorbis.c | 23 |
2 files changed, 45 insertions, 2 deletions
diff --git a/sys/src/cmd/audio/libtags/opus.c b/sys/src/cmd/audio/libtags/opus.c index fa2c7d403..7a71b8a7f 100644 --- a/sys/src/cmd/audio/libtags/opus.c +++ b/sys/src/cmd/audio/libtags/opus.c @@ -71,7 +71,29 @@ tagopus(Tagctx *ctx) /* calculate the duration */ if(ctx->samplerate > 0){ + uvlong first = 0; sz = ctx->bufsz <= 4096 ? ctx->bufsz : 4096; + /* go back a bit but make sure first page is skipped */ + ctx->seek(ctx, -sz, 1); + ctx->seek(ctx, 16, 1); + for(i = -sz; i < 65536; i += sz - 16){ + if(ctx->seek(ctx, sz - 16, 1) <= 0) + break; + v = ctx->buf; + if(ctx->read(ctx, v, sz) != sz) + break; + for(; v != nil && v < ctx->buf+sz;){ + v = memchr(v, 'O', ctx->buf+sz - v - 14); + if(v != nil && v[1] == 'g' && v[2] == 'g' && v[3] == 'S'){ + first = leuint(v+6) | (uvlong)leuint(v+10)<<32; + goto found; + } + if(v != nil) + v++; + } + } + +found: for(i = sz; i < 65536+16; i += sz - 16){ if(ctx->seek(ctx, -i, 2) <= 0) break; @@ -82,7 +104,7 @@ tagopus(Tagctx *ctx) v = memchr(v, 'O', ctx->buf+sz - v - 14); if(v != nil && v[1] == 'g' && v[2] == 'g' && v[3] == 'S'){ uvlong g = leuint(v+6) | (uvlong)leuint(v+10)<<32; - ctx->duration = g * 1000 / 48000; /* granule positions are always 48KHz */ + ctx->duration = (g - first) * 1000 / 48000; /* granule positions are always 48KHz */ } if(v != nil) v++; diff --git a/sys/src/cmd/audio/libtags/vorbis.c b/sys/src/cmd/audio/libtags/vorbis.c index 9cd434a68..969fc4e1d 100644 --- a/sys/src/cmd/audio/libtags/vorbis.c +++ b/sys/src/cmd/audio/libtags/vorbis.c @@ -107,7 +107,28 @@ tagvorbis(Tagctx *ctx) /* calculate the duration */ if(ctx->samplerate > 0){ + uvlong first = 0; sz = ctx->bufsz <= 4096 ? ctx->bufsz : 4096; + ctx->seek(ctx, -sz, 1); + ctx->seek(ctx, 16, 1); + for(i = -sz; i < 65536; i += sz - 16){ + if(ctx->seek(ctx, sz - 16, 1) <= 0) + break; + v = ctx->buf; + if(ctx->read(ctx, v, sz) != sz) + break; + for(; v != nil && v < ctx->buf+sz;){ + v = memchr(v, 'O', ctx->buf+sz - v - 14); + if(v != nil && v[1] == 'g' && v[2] == 'g' && v[3] == 'S'){ + first = leuint(v+6) | (uvlong)leuint(v+10)<<32; + goto found; + } + if(v != nil) + v++; + } + } + +found: for(i = sz; i < 65536+16; i += sz - 16){ if(ctx->seek(ctx, -i, 2) <= 0) break; @@ -118,7 +139,7 @@ tagvorbis(Tagctx *ctx) v = memchr(v, 'O', ctx->buf+sz - v - 14); if(v != nil && v[1] == 'g' && v[2] == 'g' && v[3] == 'S' && (v[5] & 4) == 4){ /* last page */ uvlong g = leuint(v+6) | (uvlong)leuint(v+10)<<32; - ctx->duration = g * 1000 / ctx->samplerate; + ctx->duration = (g - first) * 1000 / ctx->samplerate; } if(v != nil) v++; |