shithub: mcfs

Download patch

ref: f7bc176c6bb458b631d7792dd049aaa103eeeca4
parent: 5c91e882a725ff431be5abd6272e12b274307b72
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Thu Feb 18 08:22:12 EST 2021

aac: reconstruct adts header from matroska elements

--- a/aac.c
+++ b/aac.c
@@ -4,33 +4,94 @@
 #include "common.h"
 #include "packet.h"
 
+static int ratecfg[] = {
+	96000,
+	88200,
+	64000,
+	48000,
+	44100,
+	32000,
+	24000,
+	22050,
+	16000,
+	12000,
+	11025,
+	8000,
+	7350,
+	-1,
+	-1,
+	-1,
+};
+
 int
 aacpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts)
 {
 	int i, chanc, ratei, objt, sz;
 	u16int x;
+	char *c;
 
 	USED(ts);
 	if(ctx->frid == 0){ /* set up ADTS */
-		if(ctx->codec.priv.sz < 2){
-			/* FIXME we could reconstruct it from codec mapping and Audio element */
-			werrstr("no codec private data to construct ADTS");
-			return -1;
-		}
-		x = ctx->codec.priv.data[0]<<8 | ctx->codec.priv.data[1];
-		chanc = (x>>3) & 0xf;
-		ratei = (x>>7) & 0xf;
-		objt = x>>11;
-		if(objt > 4){
-			werrstr("AAC object type %d, can't write ADTS", objt);
-			return -1;
-		}
 		ctx->adts[0] = 0xff; /* syncword */
 		ctx->adts[1] = 0xf1; /* syncword, mpeg4, no crc */
+		if(ctx->codec.priv.sz >= 2){ /* prefer code private data */
+			x = ctx->codec.priv.data[0]<<8 | ctx->codec.priv.data[1];
+			chanc = (x>>3) & 0xf;
+			ratei = (x>>7) & 0xf;
+			objt = x>>11;
+			if(chanc > 7){
+				werrstr("channel config out of range: %d", chanc);
+				goto err;
+			}
+			if(ratecfg[ratei] < 1){
+				werrstr("invalid rate config: %d", ratei);
+				goto err;
+			}
+			if(objt > 4){
+				werrstr("object type out of range: %d", objt);
+				goto err;
+			}
+		}else{
+			for(ratei = 0; ratei < nelem(ratecfg) && ratecfg[ratei] != ctx->audio.samplerate; ratei++);
+			if(ratei >= nelem(ratecfg) || ratecfg[ratei] < 1){
+				werrstr("unsupported sample rate: %d", (int)ctx->audio.samplerate);
+				goto err;
+			}
+
+			c = ctx->codec.name;
+			if(memcmp(c, "A_AAC/MPEG2/", 12) == 0){
+				ctx->adts[1] |= 1<<3;
+			}else if(memcmp(c, "A_AAC/MPEG4/", 12) != 0){
+badcodec:
+				werrstr("unsupported codec: %s", c);
+				goto err;
+			}
+			if(strcmp(c+12, "MAIN") == 0)
+				objt = 1;
+			else if(memcmp(c+12, "LC", 2) == 2 && (c[14] == 0 || strcmp(c+14, "/SBR") == 0))
+				objt = 2;
+			else if(strcmp(c+12, "SSR") == 0)
+				objt = 3;
+			else if(strcmp(c+12, "LTP") == 0)
+				objt = 4;
+			else
+				goto badcodec;
+
+			if(ctx->audio.channels >= 1 && ctx->audio.channels <= 6)
+				chanc = ctx->audio.channels;
+			else if(ctx->audio.channels == 8)
+				chanc = 7;
+			else{ /* FIXME is it possible to use 0 and provide a custom channel config? */
+				werrstr("unsupported number of channels: %d", ctx->audio.channels);
+				goto err;
+			}
+		}
+
 		ctx->adts[2] = (objt-1)<<6 | ratei<<2 | chanc>>2; /* object type, rate, channel config */
 		ctx->adts[3] = (chanc&3)<<6; /* channel config */
 		ctx->adts[6] = 0xfc; /* fullness, number of frames */
 	}
+
 	for(i = 0; i < np; i++, p++){
 		sz = 7+p->sz;
 		ctx->adts[3] = ctx->adts[3]&(3<<6) | (sz>>11)&3; /* channels, frame length */
@@ -43,6 +104,6 @@
 
 	return 0;
 err:
-	werrstr("aacpacket: %r");
+	werrstr("aacpacket: adts: %r");
 	return -1;
 }