#include"node.h" #include #include #include"img.h" #include #include struct CHiEncodeOpusNode { CHiPubNode pubn; size_t pcmSamples, pcmCapacity; int16_t *pcmbuf; size_t timestamp; bool firstFrame; OpusEncoder *enc; }; static int encodeopus_perform(CHiPubNode *pubn) { struct CHiEncodeOpusNode *n = (struct CHiEncodeOpusNode*) pubn; CHiImage *newpcm = CHi_Crawl(&pubn->sinks[0])->data.sample; if(newpcm) { if(n->pcmSamples + newpcm->width > n->pcmCapacity) { n->pcmbuf = realloc(n->pcmbuf, sizeof(*n->pcmbuf) * (n->pcmCapacity = ((n->pcmSamples + newpcm->width + 1023) & ~1023))); } memcpy(&n->pcmbuf[n->pcmSamples], newpcm->data16, sizeof(*n->pcmbuf) * newpcm->width); n->pcmSamples += newpcm->width; } CHiBSFrames *frames = malloc(sizeof(*frames)); frames->count = 0; if(!n->firstFrame) { frames = CHi_BS_Grow(frames, 1); struct OpusHead { uint8_t magic[8]; uint8_t version; uint8_t channelCount; uint16_t preSkip; uint32_t inputSampleRate; uint16_t outputGain; uint8_t mappingFamily; } __attribute__((packed)); struct OpusHead *head = calloc(1, sizeof(*head)); *head = (struct OpusHead) {{'O', 'p', 'u', 's', 'H', 'e', 'a', 'd'}, 1, 1, 3840, 48000, 0, 0}; frames->data[0].timestamp = 0; frames->data[0].flags = CUTIHI_BS_SETUP_PACKET; frames->data[0].ptr = head; frames->data[0].sz = sizeof(*head); n->firstFrame = true; } size_t samp; for(samp = 0; samp + 960 <= n->pcmSamples; samp += 960) { frames = CHi_BS_Grow(frames, 1); frames->data[frames->count - 1].timestamp = n->timestamp; frames->data[frames->count - 1].ptr = malloc(1276); frames->data[frames->count - 1].sz = opus_encode(n->enc, &n->pcmbuf[samp], 960, frames->data[frames->count - 1].ptr, 1276); if(frames->data[frames->count - 1].sz < 0) puts("OPUS ERR"); n->timestamp += 20; } memmove(n->pcmbuf, n->pcmbuf + samp, sizeof(*n->pcmbuf) * (n->pcmSamples - samp)); n->pcmSamples -= samp; pubn->sources[0].type = CUTIHI_VAL_OPUSBS; pubn->sources[0].data.bitstream = frames; return 1; } static int CHi_EncodeOpus_Start(CHiPubNode *pubn) { struct CHiEncodeOpusNode *n = (struct CHiEncodeOpusNode*) pubn; int error; n->enc = opus_encoder_create(48000, 1, OPUS_APPLICATION_AUDIO, &error); n->pcmSamples = 0; n->pcmCapacity = 1024; n->pcmbuf = malloc(sizeof(*n->pcmbuf) * n->pcmCapacity); n->timestamp = 0; return 1; } static int CHi_EncodeOpus_Stop(CHiPubNode *pubn) { struct CHiEncodeOpusNode *n = (struct CHiEncodeOpusNode*) pubn; opus_encoder_destroy(n->enc); free(n->pcmbuf); return 1; } CUTIVIS CHiPubNode *CHi_EncodeOpus() { struct CHiEncodeOpusNode *ret = calloc(1, sizeof(*ret)); ret->pubn.type = CUTIHI_T('CEnc','Opus'); ret->pubn.Start = CHi_EncodeOpus_Start; ret->pubn.Perform = &encodeopus_perform; ret->pubn.Stop = CHi_EncodeOpus_Stop; ret->pubn.sinks = calloc(sizeof(*ret->pubn.sinks), ret->pubn.sinkCount = 1); ret->pubn.sources = calloc(sizeof(*ret->pubn.sources), ret->pubn.sourceCount = 1); return &ret->pubn; }