shithub: mcfs

ref: 7996b424b3ec858adcf6507c424bc5e06773e3fa
dir: /aac.c/

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>
#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 */
		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 */
		ctx->adts[4] = (sz>>3) & 0xff; /* frame length */
		ctx->adts[5] = (sz&7)<<5 | 0x1f; /* frame length, fullness */
		if(Bwrite(out, ctx->adts, 7) != 7 || Bwrite(out, p->data, p->sz) != p->sz)
			goto err;
	}
	ctx->frid++;

	return 0;
err:
	werrstr("aacpacket: adts: %r");
	return -1;
}