#include"node.h" #include #include #include"img.h" #include #include #include #include #include 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; }