cuticle/hi/aaclc.c
2025-03-09 10:29:35 +02:00

142 lines
4.2 KiB
C

#include"node.h"
#include<fdk-aac/aacenc_lib.h>
#include<string.h>
#include"img.h"
#include<stdlib.h>
#include<stdio.h>
#include<assert.h>
#include<stdbool.h>
#include<math.h>
typedef struct {
CHiPubNode pub;
HANDLE_AACENCODER enc;
int16_t *pcmbuf;
size_t pcmbufSz;
uint64_t timestamp; // In samples (48000 Hz)
AACENC_InfoStruct info;
bool extradataSent;
} Internal;
static int encodeaac_perform(CHiPubNode *pub) {
Internal *n = (Internal*) pub;
CHiImage *newpcm = CHi_Crawl(&pub->sinks[0])->data.sample;
if(newpcm && newpcm->width) {
n->pcmbuf = realloc(n->pcmbuf, sizeof(*n->pcmbuf) * (n->pcmbufSz + newpcm->width * newpcm->channels));
memcpy(n->pcmbuf + n->pcmbufSz, newpcm->data8, newpcm->width * newpcm->channels * sizeof(*n->pcmbuf));
/*for(size_t z = 0; z < newpcm->width; z++) {
static size_t lol = 0;
n->pcmbuf[n->pcmbufSz + z] = sinf(lol++ * 440.0 / 48000 * 2.0 * 3.14159) * 15000;
}*/
n->pcmbufSz += newpcm->width * newpcm->channels;
}
CHiBSFrames *frames = calloc(1, sizeof(*frames) + 1 * sizeof(CHiBSFrame));
if(!n->extradataSent) {
frames->count++;
frames->data[frames->count - 1].timestamp = 0;
frames->data[frames->count - 1].flags = CUTIHI_BS_SETUP_PACKET;
frames->data[frames->count - 1].ptr = n->info.confBuf;
frames->data[frames->count - 1].sz = n->info.confSize;
n->extradataSent = true;
}
while(n->pcmbufSz) {
int inIdentifier = IN_AUDIO_DATA;
int inSize = n->pcmbufSz * sizeof(*n->pcmbuf);
int inElSize = 2;
AACENC_BufDesc inbuf = { .numBufs = 1, .bufs = &n->pcmbuf, .bufferIdentifiers = &inIdentifier, .bufSizes = &inSize, .bufElSizes = &inElSize };
int outIdentifier = OUT_BITSTREAM_DATA;
int outSize = 2048;
int outElSize = 1;
void *outBuf = malloc(outSize);
AACENC_BufDesc outbuf = { .numBufs = 1, .bufs = &outBuf, .bufferIdentifiers = &outIdentifier, .bufSizes = &outSize, .bufElSizes = &outElSize };
AACENC_InArgs inargs = { .numInSamples = n->pcmbufSz };
AACENC_OutArgs outargs = {};
int err = aacEncEncode(n->enc, &inbuf, &outbuf, &inargs, &outargs);
if(err == AACENC_OK) {
if(outargs.numOutBytes > 0) {
frames = realloc(frames, sizeof(*frames) + (++frames->count) * sizeof(CHiBSFrame));
frames->data[frames->count - 1].timestamp = n->timestamp / 48; // ms
frames->data[frames->count - 1].flags = 0;
frames->data[frames->count - 1].ptr = outBuf;
frames->data[frames->count - 1].sz = outargs.numOutBytes;
}
if(outargs.numInSamples > 0) {
memmove(n->pcmbuf, n->pcmbuf + outargs.numInSamples, sizeof(*n->pcmbuf) * (n->pcmbufSz - outargs.numInSamples));
n->pcmbufSz -= outargs.numInSamples;
n->timestamp += outargs.numInSamples;
}
if(outargs.numOutBytes == 0 || outargs.numInSamples == 0) {
break;
}
} else if(err == AACENC_ENCODE_EOF) {
break;
} else {
abort();
return 0;
}
}
n->pub.sources[0].type = CUTIHI_VAL_AACBS;
n->pub.sources[0].data.bitstream = frames;
return 1;
}
static int encodeaac_start(CHiPubNode *pub) {
Internal *n = (Internal*) pub;
assert(aacEncOpen(&n->enc, 0, 1) == AACENC_OK);
assert(aacEncoder_SetParam(n->enc, AACENC_AOT, 2) == AACENC_OK); // Low complexity profile
assert(aacEncoder_SetParam(n->enc, AACENC_SAMPLERATE, 48000) == AACENC_OK);
assert(aacEncoder_SetParam(n->enc, AACENC_CHANNELMODE, MODE_1) == AACENC_OK);
assert(aacEncoder_SetParam(n->enc, AACENC_CHANNELORDER, 1) == AACENC_OK);
assert(aacEncoder_SetParam(n->enc, AACENC_BITRATEMODE, 3) == AACENC_OK);
assert(aacEncEncode(n->enc, NULL, NULL, NULL, NULL) == AACENC_OK);
memset(&n->info, 0, sizeof(n->info));
assert(aacEncInfo(n->enc, &n->info) == AACENC_OK);
n->pcmbuf = NULL;
n->pcmbufSz = 0;
n->timestamp = 0;
n->extradataSent = false;
return 1;
}
static int encodeaac_stop(CHiPubNode *pub) {
Internal *n = (Internal*) pub;
aacEncClose(&n->enc);
return 1;
}
CUTIVIS CHiPubNode *CHi_EncodeAAC() {
Internal *ret = calloc(1, sizeof(*ret));
ret->pub.type = CUTIHI_T('CEnc','AACL');
ret->pub.Start = encodeaac_start;
ret->pub.Perform = encodeaac_perform;
ret->pub.Stop = encodeaac_stop;
ret->pub.sinks = calloc(sizeof(*ret->pub.sinks), ret->pub.sinkCount = 1);
ret->pub.sources = calloc(sizeof(*ret->pub.sources), ret->pub.sourceCount = 1);
return &ret->pub;
}