ref: 87a6e1873b3ebd90a6cc075b3a833cca5b675f1a
parent: 7f071685e9b7d9e32c1a9675f7fca0407d18e6e1
author: Sigrid Solveig Haflínudóttir <[email protected]>
date: Sat Feb 11 11:52:56 EST 2023
libtags: work around encoders producing Ogg containers with first granule position set to non-zero outside of the first page
--- a/sys/src/cmd/audio/libtags/opus.c
+++ b/sys/src/cmd/audio/libtags/opus.c
@@ -71,7 +71,29 @@
/* 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 @@
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++;
--- a/sys/src/cmd/audio/libtags/vorbis.c
+++ b/sys/src/cmd/audio/libtags/vorbis.c
@@ -107,7 +107,28 @@
/* 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 @@
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++;