int initRecorder(const char *path) { cleanupRecorder(); if (!path) { return 0; } _fileOs = fopen(path, "wb"); if (!_fileOs) { return 0; } inopt.rate = rate; inopt.gain = 0; inopt.endianness = 0; inopt.copy_comments = 0; inopt.rawmode = 1; inopt.ignorelength = 1; inopt.samplesize = 16; inopt.channels = 1; inopt.skip = 0; comment_init(&inopt.comments, &inopt.comments_length, opus_get_version_string()); if (rate > 24000) { coding_rate = 48000; } else if (rate > 16000) { coding_rate = 24000; } else if (rate > 12000) { coding_rate = 16000; } else if (rate > 8000) { coding_rate = 12000; } else { coding_rate = 8000; } if (rate != coding_rate) { LOGE("Invalid rate"); return 0; } header.channels = 1; header.channel_mapping = 0; header.input_sample_rate = rate; header.gain = inopt.gain; header.nb_streams = 1; int result = OPUS_OK; _encoder = opus_encoder_create(coding_rate, 1, OPUS_APPLICATION_AUDIO, &result); if (result != OPUS_OK) { LOGE("Error cannot create encoder: %s", opus_strerror(result)); return 0; } min_bytes = max_frame_bytes = (1275 * 3 + 7) * header.nb_streams; _packet = malloc(max_frame_bytes); result = opus_encoder_ctl(_encoder, OPUS_SET_BITRATE(bitrate)); if (result != OPUS_OK) { LOGE("Error OPUS_SET_BITRATE returned: %s", opus_strerror(result)); return 0; } #ifdef OPUS_SET_LSB_DEPTH result = opus_encoder_ctl(_encoder, OPUS_SET_LSB_DEPTH(max(8, min(24, inopt.samplesize)))); if (result != OPUS_OK) { LOGE("Warning OPUS_SET_LSB_DEPTH returned: %s", opus_strerror(result)); } #endif opus_int32 lookahead; result = opus_encoder_ctl(_encoder, OPUS_GET_LOOKAHEAD(&lookahead)); if (result != OPUS_OK) { LOGE("Error OPUS_GET_LOOKAHEAD returned: %s", opus_strerror(result)); return 0; } inopt.skip += lookahead; header.preskip = (int)(inopt.skip * (48000.0 / coding_rate)); inopt.extraout = (int)(header.preskip * (rate / 48000.0)); if (ogg_stream_init(&os, rand()) == -1) { LOGE("Error: stream init failed"); return 0; } unsigned char header_data[100]; int packet_size = opus_header_to_packet(&header, header_data, 100); op.packet = header_data; op.bytes = packet_size; op.b_o_s = 1; op.e_o_s = 0; op.granulepos = 0; op.packetno = 0; ogg_stream_packetin(&os, &op); while ((result = ogg_stream_flush(&os, &og))) { if (!result) { break; } int pageBytesWritten = writeOggPage(&og, _fileOs); if (pageBytesWritten != og.header_len + og.body_len) { LOGE("Error: failed writing header to output stream"); return 0; } bytes_written += pageBytesWritten; pages_out++; } comment_pad(&inopt.comments, &inopt.comments_length, comment_padding); op.packet = (unsigned char *)inopt.comments; op.bytes = inopt.comments_length; op.b_o_s = 0; op.e_o_s = 0; op.granulepos = 0; op.packetno = 1; ogg_stream_packetin(&os, &op); while ((result = ogg_stream_flush(&os, &og))) { if (result == 0) { break; } int writtenPageBytes = writeOggPage(&og, _fileOs); if (writtenPageBytes != og.header_len + og.body_len) { LOGE("Error: failed writing header to output stream"); return 0; } bytes_written += writtenPageBytes; pages_out++; } free(inopt.comments); return 1; }
static int OpenEncoder(vlc_object_t *p_this) { encoder_t *enc = (encoder_t *)p_this; if (enc->fmt_out.i_codec != VLC_CODEC_OPUS) return VLC_EGENERIC; encoder_sys_t *sys = malloc(sizeof(*sys)); if (!sys) return VLC_ENOMEM; int status = VLC_SUCCESS; sys->buffer = NULL; sys->enc = NULL; enc->pf_encode_audio = Encode; enc->fmt_in.i_codec = VLC_CODEC_FL32; enc->fmt_in.audio.i_rate = /* Only 48kHz */ enc->fmt_out.audio.i_rate = 48000; enc->fmt_out.audio.i_channels = enc->fmt_in.audio.i_channels; OpusHeader header; opus_prepare_header(enc->fmt_out.audio.i_channels, enc->fmt_out.audio.i_rate, &header); /* needed for max encoded size calculation */ sys->nb_streams = header.nb_streams; int err; sys->enc = opus_multistream_surround_encoder_create(enc->fmt_in.audio.i_rate, enc->fmt_in.audio.i_channels, header.channel_mapping, &header.nb_streams, &header.nb_coupled, header.stream_map, OPUS_APPLICATION_AUDIO, &err); if (err != OPUS_OK) { msg_Err(enc, "Could not create encoder: error %d", err); sys->enc = NULL; status = VLC_EGENERIC; goto error; } /* TODO: vbr, fec */ if( enc->fmt_out.i_bitrate ) opus_multistream_encoder_ctl(sys->enc, OPUS_SET_BITRATE( enc->fmt_out.i_bitrate )); /* Buffer for incoming audio, since opus only accepts frame sizes that are multiples of 2.5ms */ enc->p_sys = sys; sys->buffer = malloc(OPUS_FRAME_SIZE * header.channels * sizeof(float)); if (!sys->buffer) { status = VLC_ENOMEM; goto error; } sys->i_nb_samples = 0; sys->i_samples_delay = 0; int ret = opus_multistream_encoder_ctl(enc->p_sys->enc, OPUS_GET_LOOKAHEAD(&sys->i_samples_delay)); if (ret != OPUS_OK) msg_Err(enc, "Unable to get number of lookahead samples: %s\n", opus_strerror(ret)); header.preskip = sys->i_samples_delay; /* Now that we have preskip, we can write the header to extradata */ if (opus_write_header((uint8_t **) &enc->fmt_out.p_extra, &enc->fmt_out.i_extra, &header, opus_get_version_string())) { msg_Err(enc, "Failed to write header."); status = VLC_ENOMEM; goto error; } if (sys->i_samples_delay > 0) { const unsigned padding_samples = sys->i_samples_delay * enc->fmt_out.audio.i_channels; sys->padding = block_Alloc(padding_samples * sizeof(float)); if (!sys->padding) { status = VLC_ENOMEM; goto error; } sys->padding->i_nb_samples = sys->i_samples_delay; float *pad_ptr = (float *) sys->padding->p_buffer; memset(pad_ptr, 0, padding_samples * sizeof(float)); } else { sys->padding = NULL; } return status; error: if (sys->enc) opus_multistream_encoder_destroy(sys->enc); free(sys->buffer); free(sys); return status; }
void OggOpusFile::Init() { inopt.skip=0; //In our case, its 160 samples/frame. Changing rate to anything rather than 8000Hz may require significant change in the way of handle number of samples to fix the encoder frame_size=frame_size/(48000/coding_rate); /*OggOpus headers*/ /*FIXME: broke forcemono*/ header.channels=chan; header.channel_mapping= 0;//header.channels>8?255:chan>2; //=0 for wav header.input_sample_rate=rate; header.gain=inopt.gain; //=0 here st=opus_multistream_surround_encoder_create(coding_rate, chan, header.channel_mapping, &header.nb_streams, &header.nb_coupled, header.stream_map, frame_size<480/(48000/coding_rate)?OPUS_APPLICATION_RESTRICTED_LOWDELAY:OPUS_APPLICATION_AUDIO, &ret); if(ret!=OPUS_OK){ fprintf(stderr, "Error cannot create encoder: %s\n", opus_strerror(ret)); exit(1); } max_frame_bytes=(1275*3+7)*header.nb_streams; min_bytes=max_frame_bytes; m_outBuf = (unsigned char*)malloc(max_frame_bytes); if(m_outBuf==NULL){ fprintf(stderr,"Error allocating m_outBuf buffer.\n"); exit(1); } //We would set bitrate configurable as low as 6k //Or use the provided formulae to calculate a optimized bitrate if(bitrate<0){ /*Lower default rate for sampling rates [8000-44100) by a factor of (rate+16k)/(64k)*/ // bitrate=((64000*header.nb_streams+32000*header.nb_coupled)* // (IMIN(48,IMAX(8,((rate<44100?rate:48000)+1000)/1000))+16)+32)>>6; bitrate=6000; } if(bitrate>(1024000*chan)||bitrate<500){ fprintf(stderr,"Error: Bitrate %d bits/sec is insane.\nDid you mistake bits for kilobits?\n",bitrate); fprintf(stderr,"--bitrate values from 6-256 kbit/sec per channel are meaningful.\n"); exit(1); } bitrate=IMIN(chan*256000,bitrate); ret=opus_multistream_encoder_ctl(st, OPUS_SET_BITRATE(bitrate)); if(ret!=OPUS_OK){ fprintf(stderr,"Error OPUS_SET_BITRATE returned: %s\n",opus_strerror(ret)); exit(1); } ret=opus_multistream_encoder_ctl(st, OPUS_SET_VBR(!with_hard_cbr)); if(ret!=OPUS_OK){ fprintf(stderr,"Error OPUS_SET_VBR returned: %s\n",opus_strerror(ret)); exit(1); } if(!with_hard_cbr){ ret=opus_multistream_encoder_ctl(st, OPUS_SET_VBR_CONSTRAINT(with_cvbr)); if(ret!=OPUS_OK){ fprintf(stderr,"Error OPUS_SET_VBR_CONSTRAINT returned: %s\n",opus_strerror(ret)); exit(1); } } ret=opus_multistream_encoder_ctl(st, OPUS_SET_COMPLEXITY(complexity)); if(ret!=OPUS_OK){ fprintf(stderr,"Error OPUS_SET_COMPLEXITY returned: %s\n",opus_strerror(ret)); exit(1); } ret=opus_multistream_encoder_ctl(st, OPUS_SET_PACKET_LOSS_PERC(expect_loss)); if(ret!=OPUS_OK){ fprintf(stderr,"Error OPUS_SET_PACKET_LOSS_PERC returned: %s\n",opus_strerror(ret)); exit(1); } #ifdef OPUS_SET_LSB_DEPTH ret=opus_multistream_encoder_ctl(st, OPUS_SET_LSB_DEPTH(IMAX(8,IMIN(24,inopt.samplesize)))); if(ret!=OPUS_OK){ fprintf(stderr,"Warning OPUS_SET_LSB_DEPTH returned: %s\n",opus_strerror(ret)); } #endif for(i=0;i<opt_ctls;i++){ int target=opt_ctls_ctlval[i*3]; if(target==-1){ ret=opus_multistream_encoder_ctl(st,opt_ctls_ctlval[i*3+1],opt_ctls_ctlval[i*3+2]); if(ret!=OPUS_OK){ fprintf(stderr,"Error opus_multistream_encoder_ctl(st,%d,%d) returned: %s\n",opt_ctls_ctlval[i*3+1],opt_ctls_ctlval[i*3+2],opus_strerror(ret)); exit(1); } }else if(target<header.nb_streams){ OpusEncoder *oe; opus_multistream_encoder_ctl(st,OPUS_MULTISTREAM_GET_ENCODER_STATE(target,&oe)); ret=opus_encoder_ctl(oe, opt_ctls_ctlval[i*3+1],opt_ctls_ctlval[i*3+2]); if(ret!=OPUS_OK){ fprintf(stderr,"Error opus_encoder_ctl(st[%d],%d,%d) returned: %s\n",target,opt_ctls_ctlval[i*3+1],opt_ctls_ctlval[i*3+2],opus_strerror(ret)); exit(1); } }else{ fprintf(stderr,"Error --set-ctl-int target stream %d is higher than the maximum stream number %d.\n",target,header.nb_streams-1); exit(1); } } /*We do the lookahead check late so user CTLs can change it*/ ret=opus_multistream_encoder_ctl(st, OPUS_GET_LOOKAHEAD(&lookahead)); if(ret!=OPUS_OK){ fprintf(stderr,"Error OPUS_GET_LOOKAHEAD returned: %s\n",opus_strerror(ret)); exit(1); } inopt.skip+=lookahead; /*Regardless of the rate we're coding at the ogg timestamping/skip is always timed at 48000.*/ header.preskip=inopt.skip*(48000./coding_rate); /* Extra samples that need to be read to compensate for the pre-skip */ inopt.extraout=(int)header.preskip*(rate/48000.); /*Initialize Ogg stream struct*/ if(ogg_stream_init(&os, serialno)==-1){ fprintf(stderr,"Error: stream init failed\n"); exit(1); } int opus_app; fprintf(stderr,"Encoding using 1.1"); opus_multistream_encoder_ctl(st,OPUS_GET_APPLICATION(&opus_app)); if(opus_app==OPUS_APPLICATION_VOIP)fprintf(stderr," (VoIP)\n"); else if(opus_app==OPUS_APPLICATION_AUDIO)fprintf(stderr," (audio)\n"); else if(opus_app==OPUS_APPLICATION_RESTRICTED_LOWDELAY)fprintf(stderr," (low-delay)\n"); else fprintf(stderr," (unknown)\n"); fprintf(stderr,"-----------------------------------------------------\n"); fprintf(stderr," Input: %0.6gkHz %d channel%s\n", header.input_sample_rate/1000.,chan,chan<2?"":"s"); fprintf(stderr," Output: %d channel%s (",header.channels,header.channels<2?"":"s"); if(header.nb_coupled>0)fprintf(stderr,"%d coupled",header.nb_coupled*2); if(header.nb_streams-header.nb_coupled>0)fprintf(stderr, "%s%d uncoupled",header.nb_coupled>0?", ":"", header.nb_streams-header.nb_coupled); fprintf(stderr,")\n %0.2gms packets, %0.6gkbit/sec%s\n", frame_size/(coding_rate/1000.), bitrate/1000., with_hard_cbr?" CBR":with_cvbr?" CVBR":" VBR"); fprintf(stderr," Preskip: %d\n",header.preskip); }
krad_opus_t *krad_opus_encoder_create (int channels, int input_sample_rate, int bitrate, int application) { int c; krad_opus_t *krad_opus = calloc(1, sizeof(krad_opus_t)); krad_opus->opus_header = calloc(1, sizeof(OpusHeader)); krad_opus->input_sample_rate = input_sample_rate; krad_opus->channels = channels; krad_opus->bitrate = bitrate; krad_opus->application = application; krad_opus->complexity = DEFAULT_OPUS_COMPLEXITY; krad_opus->signal = OPUS_AUTO; krad_opus->frame_size = DEFAULT_OPUS_FRAME_SIZE; krad_opus->bandwidth = OPUS_BANDWIDTH_FULLBAND; krad_opus->new_frame_size = krad_opus->frame_size; krad_opus->new_complexity = krad_opus->complexity; krad_opus->new_bitrate = krad_opus->bitrate; krad_opus->new_signal = krad_opus->signal; krad_opus->new_bandwidth = krad_opus->bandwidth; for (c = 0; c < krad_opus->channels; c++) { krad_opus->ringbuf[c] = krad_ringbuffer_create (RINGBUFFER_SIZE); krad_opus->resampled_ringbuf[c] = krad_ringbuffer_create (RINGBUFFER_SIZE); krad_opus->samples[c] = malloc(16 * 8192); krad_opus->resampled_samples[c] = malloc(16 * 8192); krad_opus->src_resampler[c] = src_new (KRAD_OPUS_SRC_QUALITY, 1, &krad_opus->src_error[c]); if (krad_opus->src_resampler[c] == NULL) { failfast ("Krad Opus Encoder: src resampler error: %s", src_strerror (krad_opus->src_error[c])); } krad_opus->src_data[c].src_ratio = 48000.0 / krad_opus->input_sample_rate; } if (krad_opus->channels < 3) { krad_opus->streams = 1; if (krad_opus->channels == 2) { krad_opus->coupled_streams = 1; krad_opus->mapping[0] = 0; krad_opus->mapping[1] = 1; } else { krad_opus->coupled_streams = 0; krad_opus->mapping[0] = 0; } krad_opus->opus_header->channel_mapping = 0; } else { krad_opus->opus_header->channel_mapping = 1; switch (krad_opus->channels) { case 3: krad_opus->streams = 2; krad_opus->coupled_streams = 1; krad_opus->mapping[0] = 0; krad_opus->mapping[1] = 1; krad_opus->mapping[2] = 2; case 4: krad_opus->streams = 2; krad_opus->coupled_streams = 2; krad_opus->mapping[0] = 0; krad_opus->mapping[1] = 1; krad_opus->mapping[2] = 2; krad_opus->mapping[3] = 3; case 5: krad_opus->streams = 3; krad_opus->coupled_streams = 2; krad_opus->mapping[0] = 0; krad_opus->mapping[1] = 4; krad_opus->mapping[2] = 1; krad_opus->mapping[3] = 2; krad_opus->mapping[4] = 3; case 6: krad_opus->streams = 4; krad_opus->coupled_streams = 2; krad_opus->mapping[0] = 0; krad_opus->mapping[1] = 4; krad_opus->mapping[2] = 1; krad_opus->mapping[3] = 2; krad_opus->mapping[4] = 3; krad_opus->mapping[5] = 5; case 7: krad_opus->streams = 5; krad_opus->coupled_streams = 2; krad_opus->mapping[0] = 0; krad_opus->mapping[1] = 4; krad_opus->mapping[2] = 1; krad_opus->mapping[3] = 2; krad_opus->mapping[4] = 3; krad_opus->mapping[5] = 5; krad_opus->mapping[6] = 6; case 8: krad_opus->streams = 5; krad_opus->coupled_streams = 3; krad_opus->mapping[0] = 0; krad_opus->mapping[1] = 6; krad_opus->mapping[2] = 1; krad_opus->mapping[3] = 2; krad_opus->mapping[4] = 3; krad_opus->mapping[5] = 4; krad_opus->mapping[6] = 5; krad_opus->mapping[7] = 7; } } krad_opus->opus_header->channels = krad_opus->channels; krad_opus->opus_header->nb_streams = krad_opus->streams; krad_opus->opus_header->nb_coupled = krad_opus->coupled_streams; memcpy (krad_opus->opus_header->stream_map, krad_opus->mapping, 256); krad_opus->encoder = opus_multistream_encoder_create (48000, krad_opus->channels, krad_opus->streams, krad_opus->coupled_streams, krad_opus->mapping, krad_opus->application, &krad_opus->err); if (krad_opus->err != OPUS_OK) { failfast ("Krad Opus Encoder: Cannot create encoder: %s", opus_strerror (krad_opus->err)); } opus_multistream_encoder_ctl (krad_opus->encoder, OPUS_GET_LOOKAHEAD (&krad_opus->lookahead)); krad_opus->opus_header->preskip = krad_opus->lookahead; krad_opus->opus_header->gain = 0; krad_opus->opus_header->input_sample_rate = 48000; if (opus_multistream_encoder_ctl (krad_opus->encoder, OPUS_SET_BITRATE (krad_opus->bitrate)) != OPUS_OK) { failfast ("Krad Opus Encoder: bitrate request failed"); } krad_opus->header_data_size = opus_header_to_packet (krad_opus->opus_header, krad_opus->header_data, 100); krad_opus->krad_codec_header.codec = OPUS; krad_opus->krad_codec_header.header[0] = krad_opus->header_data; krad_opus->krad_codec_header.header_size[0] = krad_opus->header_data_size; krad_opus->krad_codec_header.header_combined = krad_opus->header_data; krad_opus->krad_codec_header.header_combined_size = krad_opus->header_data_size; krad_opus->krad_codec_header.header_count = 2; krad_opus->krad_codec_header.header_size[1] = 8 + 4 + strlen (opus_get_version_string ()) + 4 + 4 + strlen ("ENCODER=") + strlen (APPVERSION); krad_opus->opustags_header = calloc (1, krad_opus->krad_codec_header.header_size[1]); memcpy (krad_opus->opustags_header, "OpusTags", 8); krad_opus->opustags_header[8] = strlen (opus_get_version_string ()); memcpy (krad_opus->opustags_header + 12, opus_get_version_string (), strlen (opus_get_version_string ())); krad_opus->opustags_header[12 + strlen (opus_get_version_string ())] = 1; krad_opus->opustags_header[12 + strlen (opus_get_version_string ()) + 4] = strlen ("ENCODER=") + strlen (APPVERSION); memcpy (krad_opus->opustags_header + 12 + strlen (opus_get_version_string ()) + 4 + 4, "ENCODER=", strlen ("ENCODER=")); memcpy (krad_opus->opustags_header + 12 + strlen (opus_get_version_string ()) + 4 + 4 + strlen ("ENCODER="), APPVERSION, strlen (APPVERSION)); krad_opus->krad_codec_header.header[1] = krad_opus->opustags_header; return krad_opus; }
int krad_opus_encoder_read (krad_opus_t *krad_opus, unsigned char *buffer, int *nframes) { int ready; int bytes; int resp; int s, c; while (krad_ringbuffer_read_space (krad_opus->ringbuf[krad_opus->channels - 1]) >= 512 * 4 ) { for (c = 0; c < krad_opus->channels; c++) { krad_opus->ret = krad_ringbuffer_peek (krad_opus->ringbuf[c], (char *)krad_opus->samples[c], (512 * 4) ); krad_opus->src_data[c].data_in = krad_opus->samples[c]; krad_opus->src_data[c].input_frames = 512; krad_opus->src_data[c].data_out = krad_opus->resampled_samples[c]; krad_opus->src_data[c].output_frames = 2048; krad_opus->src_error[c] = src_process (krad_opus->src_resampler[c], &krad_opus->src_data[c]); if (krad_opus->src_error[c] != 0) { failfast ("Krad Opus Encoder: src resampler error: %s\n", src_strerror(krad_opus->src_error[c])); } krad_ringbuffer_read_advance (krad_opus->ringbuf[c], (krad_opus->src_data[c].input_frames_used * 4) ); krad_opus->ret = krad_ringbuffer_write (krad_opus->resampled_ringbuf[c], (char *)krad_opus->resampled_samples[c], (krad_opus->src_data[c].output_frames_gen * 4) ); } } if (krad_opus->new_bitrate != krad_opus->bitrate) { krad_opus->bitrate = krad_opus->new_bitrate; resp = opus_multistream_encoder_ctl (krad_opus->encoder, OPUS_SET_BITRATE(krad_opus->bitrate)); if (resp != OPUS_OK) { failfast ("Krad Opus Encoder: bitrate request failed %s\n", opus_strerror (resp)); } else { printk ("Krad Opus Encoder: set opus bitrate %d\n", krad_opus->bitrate); } } if (krad_opus->new_frame_size != krad_opus->frame_size) { krad_opus->frame_size = krad_opus->new_frame_size; printk ("Krad Opus Encoder: frame size is now %d\n", krad_opus->frame_size); } if (krad_opus->new_complexity != krad_opus->complexity) { krad_opus->complexity = krad_opus->new_complexity; resp = opus_multistream_encoder_ctl (krad_opus->encoder, OPUS_SET_COMPLEXITY(krad_opus->complexity)); if (resp != OPUS_OK) { failfast ("Krad Opus Encoder: complexity request failed %s. \n", opus_strerror(resp)); } else { printk ("Krad Opus Encoder: set opus complexity %d\n", krad_opus->complexity); } } if (krad_opus->new_signal != krad_opus->signal) { krad_opus->signal = krad_opus->new_signal; resp = opus_multistream_encoder_ctl (krad_opus->encoder, OPUS_SET_SIGNAL(krad_opus->signal)); if (resp != OPUS_OK) { failfast ("Krad Opus Encoder: signal request failed %s\n", opus_strerror(resp)); } else { printk ("Krad Opus Encoder: set opus signal mode %d\n", krad_opus->signal); } } if (krad_opus->new_bandwidth != krad_opus->bandwidth) { krad_opus->bandwidth = krad_opus->new_bandwidth; resp = opus_multistream_encoder_ctl (krad_opus->encoder, OPUS_SET_BANDWIDTH(krad_opus->bandwidth)); if (resp != OPUS_OK) { failfast ("Krad Opus Encoder: bandwidth request failed %s\n", opus_strerror(resp)); } else { printk ("Krad Opus Encoder: Set Opus bandwidth mode %d\n", krad_opus->bandwidth); } } ready = 1; for (c = 0; c < krad_opus->channels; c++) { if (krad_ringbuffer_read_space (krad_opus->resampled_ringbuf[c]) < krad_opus->frame_size * 4) { ready = 0; } } if (ready == 1) { for (c = 0; c < krad_opus->channels; c++) { krad_opus->ret = krad_ringbuffer_read (krad_opus->resampled_ringbuf[c], (char *)krad_opus->resampled_samples[c], (krad_opus->frame_size * 4) ); } for (s = 0; s < krad_opus->frame_size; s++) { for (c = 0; c < krad_opus->channels; c++) { krad_opus->interleaved_resampled_samples[s * krad_opus->channels + c] = krad_opus->resampled_samples[c][s]; } } bytes = opus_multistream_encode_float (krad_opus->encoder, krad_opus->interleaved_resampled_samples, krad_opus->frame_size, buffer, krad_opus->frame_size * 2); if (bytes < 0) { failfast ("Krad Opus Encoding failed: %s.", opus_strerror (bytes)); } *nframes = krad_opus->frame_size; return bytes; } return 0; }
int opus_encode_update(struct auenc_state **aesp, const struct aucodec *ac, struct auenc_param *param, const char *fmtp) { struct auenc_state *aes; struct opus_param prm, conf_prm; opus_int32 fch, vbr; const struct aucodec *auc = ac; (void)param; if (!aesp || !ac || !ac->ch) return EINVAL; debug("opus: encoder fmtp (%s)\n", fmtp); /* Save the incoming OPUS parameters from SDP offer */ if (str_isset(fmtp)) { opus_mirror_params(fmtp); } aes = *aesp; if (!aes) { const opus_int32 complex = 10; int opuserr; aes = mem_zalloc(sizeof(*aes), destructor); if (!aes) return ENOMEM; aes->ch = ac->ch; aes->enc = opus_encoder_create(ac->srate, ac->ch, /* this has big impact on cpu */ OPUS_APPLICATION_AUDIO, &opuserr); if (!aes->enc) { warning("opus: encoder create: %s\n", opus_strerror(opuserr)); mem_deref(aes); return ENOMEM; } (void)opus_encoder_ctl(aes->enc, OPUS_SET_COMPLEXITY(complex)); *aesp = aes; } prm.srate = 48000; prm.bitrate = OPUS_AUTO; prm.stereo = 1; prm.cbr = 0; prm.inband_fec = 0; prm.dtx = 0; opus_decode_fmtp(&prm, fmtp); conf_prm.bitrate = OPUS_AUTO; opus_decode_fmtp(&conf_prm, auc->fmtp); if ((prm.bitrate == OPUS_AUTO) || ((conf_prm.bitrate != OPUS_AUTO) && (conf_prm.bitrate < prm.bitrate))) prm.bitrate = conf_prm.bitrate; fch = prm.stereo ? OPUS_AUTO : 1; vbr = prm.cbr ? 0 : 1; (void)opus_encoder_ctl(aes->enc, OPUS_SET_MAX_BANDWIDTH(srate2bw(prm.srate))); (void)opus_encoder_ctl(aes->enc, OPUS_SET_BITRATE(prm.bitrate)); (void)opus_encoder_ctl(aes->enc, OPUS_SET_FORCE_CHANNELS(fch)); (void)opus_encoder_ctl(aes->enc, OPUS_SET_VBR(vbr)); (void)opus_encoder_ctl(aes->enc, OPUS_SET_INBAND_FEC(prm.inband_fec)); (void)opus_encoder_ctl(aes->enc, OPUS_SET_DTX(prm.dtx)); #if 0 { opus_int32 bw, complex; (void)opus_encoder_ctl(aes->enc, OPUS_GET_MAX_BANDWIDTH(&bw)); (void)opus_encoder_ctl(aes->enc, OPUS_GET_BITRATE(&prm.bitrate)); (void)opus_encoder_ctl(aes->enc, OPUS_GET_FORCE_CHANNELS(&fch)); (void)opus_encoder_ctl(aes->enc, OPUS_GET_VBR(&vbr)); (void)opus_encoder_ctl(aes->enc, OPUS_GET_INBAND_FEC(&prm.inband_fec)); (void)opus_encoder_ctl(aes->enc, OPUS_GET_DTX(&prm.dtx)); (void)opus_encoder_ctl(aes->enc, OPUS_GET_COMPLEXITY(&complex)); debug("opus: encode bw=%s bitrate=%i fch=%s " "vbr=%i fec=%i dtx=%i complex=%i\n", bwname(bw), prm.bitrate, chname(fch), vbr, prm.inband_fec, prm.dtx, complex); } #endif return 0; }
int main(int argc, char *argv[]) { int err; char *inFile, *outFile; FILE *fin, *fout; OpusEncoder *enc; OpusDecoder *dec; int args; int len[2]; int frame_size, channels; int bitrate_bps; unsigned char *data[2]; int sampling_rate; int use_vbr; int internal_sampling_rate_Hz; int max_payload_bytes; int complexity; int use_inbandfec; int use_dtx; int forcemono; int cvbr = 0; int packet_loss_perc; int count=0, count_act=0, k; int skip; int stop=0; int tot_read=0, tot_written=0; short *in, *out; int mode; double bits=0.0, bits_act=0.0, bits2=0.0, nrg; int bandwidth=-1; const char *bandwidth_string; int write_samples; int lost, lost_prev = 1; int toggle = 0; int enc_final_range[2]; if (argc < 7 ) { print_usage( argv ); return 1; } mode = atoi(argv[1]) + OPUS_MODE_AUTO; sampling_rate = atoi(argv[2]); channels = atoi(argv[3]); bitrate_bps = atoi(argv[4]); frame_size = sampling_rate/50; /* defaults: */ use_vbr = 1; bandwidth=BANDWIDTH_AUTO; internal_sampling_rate_Hz = sampling_rate; max_payload_bytes = MAX_PACKET; complexity = 10; use_inbandfec = 0; forcemono = 0; use_dtx = 0; packet_loss_perc = 0; args = 5; while( args < argc - 2 ) { /* process command line options */ if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-cbr" ) == 0 ) { use_vbr = 0; args++; } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-bandwidth" ) == 0 ) { if (strcmp(argv[ args + 1 ], "NB")==0) bandwidth = BANDWIDTH_NARROWBAND; else if (strcmp(argv[ args + 1 ], "MB")==0) bandwidth = BANDWIDTH_MEDIUMBAND; else if (strcmp(argv[ args + 1 ], "WB")==0) bandwidth = BANDWIDTH_WIDEBAND; else if (strcmp(argv[ args + 1 ], "SWB")==0) bandwidth = BANDWIDTH_SUPERWIDEBAND; else if (strcmp(argv[ args + 1 ], "FB")==0) bandwidth = BANDWIDTH_FULLBAND; else { fprintf(stderr, "Unknown bandwidth %s. Supported are NB, MB, WB, SWB, FB.\n", argv[ args + 1 ]); return 1; } args += 2; } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-framesize" ) == 0 ) { if (strcmp(argv[ args + 1 ], "2.5")==0) frame_size = sampling_rate/400; else if (strcmp(argv[ args + 1 ], "5")==0) frame_size = sampling_rate/200; else if (strcmp(argv[ args + 1 ], "10")==0) frame_size = sampling_rate/100; else if (strcmp(argv[ args + 1 ], "20")==0) frame_size = sampling_rate/50; else if (strcmp(argv[ args + 1 ], "40")==0) frame_size = sampling_rate/25; else if (strcmp(argv[ args + 1 ], "60")==0) frame_size = 3*sampling_rate/50; else { fprintf(stderr, "Unsupported frame size: %s ms. Supported are 2.5, 5, 10, 20, 40, 60.\n", argv[ args + 1 ]); return 1; } args += 2; } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-max_payload" ) == 0 ) { max_payload_bytes = atoi( argv[ args + 1 ] ); args += 2; } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-complexity" ) == 0 ) { complexity = atoi( argv[ args + 1 ] ); args += 2; } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-inbandfec" ) == 0 ) { use_inbandfec = 1; args++; } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-forcemono" ) == 0 ) { forcemono = 1; args++; } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-cvbr" ) == 0 ) { cvbr = 1; args++; } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-dtx") == 0 ) { use_dtx = 1; args++; } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-loss" ) == 0 ) { packet_loss_perc = atoi( argv[ args + 1 ] ); args += 2; } else { printf( "Error: unrecognized setting: %s\n\n", argv[ args ] ); print_usage( argv ); return 1; } } if( mode < OPUS_MODE_AUTO || mode > OPUS_MODE_AUDIO) { fprintf (stderr, "mode must be: 0, 1 or 2\n"); return 1; } if (max_payload_bytes < 0 || max_payload_bytes > MAX_PACKET) { fprintf (stderr, "max_payload_bytes must be between 0 and %d\n", MAX_PACKET); return 1; } if (bitrate_bps < 0 || bitrate_bps*frame_size/sampling_rate > max_payload_bytes*8) { fprintf (stderr, "bytes per packet must be between 0 and %d\n", max_payload_bytes); return 1; } inFile = argv[argc-2]; fin = fopen(inFile, "rb"); if (!fin) { fprintf (stderr, "Could not open input file %s\n", argv[argc-2]); return 1; } outFile = argv[argc-1]; fout = fopen(outFile, "wb+"); if (!fout) { fprintf (stderr, "Could not open output file %s\n", argv[argc-1]); return 1; } enc = opus_encoder_create(sampling_rate, channels); dec = opus_decoder_create(sampling_rate, channels); opus_encoder_ctl(enc, OPUS_SET_MODE(mode)); opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps)); opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth)); opus_encoder_ctl(enc, OPUS_SET_VBR_FLAG(use_vbr)); opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(cvbr)); opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity)); opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC_FLAG(use_inbandfec)); opus_encoder_ctl(enc, OPUS_SET_FORCE_MONO(forcemono)); opus_encoder_ctl(enc, OPUS_SET_DTX_FLAG(use_dtx)); opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc)); skip = 5*sampling_rate/1000; /* When SILK resamples, add 18 samples delay */ /*if (mode != MODE_SILK_ONLY || sampling_rate > 16000) skip += 18;*/ switch(bandwidth) { case BANDWIDTH_NARROWBAND: bandwidth_string = "narrowband"; break; case BANDWIDTH_MEDIUMBAND: bandwidth_string = "mediumband"; break; case BANDWIDTH_WIDEBAND: bandwidth_string = "wideband"; break; case BANDWIDTH_SUPERWIDEBAND: bandwidth_string = "superwideband"; break; case BANDWIDTH_FULLBAND: bandwidth_string = "fullband"; break; case BANDWIDTH_AUTO: bandwidth_string = "auto"; break; default: bandwidth_string = "unknown"; } printf("Encoding %d Hz input at %.3f kb/s in %s mode with %d-sample frames.\n", sampling_rate, bitrate_bps*0.001, bandwidth_string, frame_size); in = (short*)malloc(frame_size*channels*sizeof(short)); out = (short*)malloc(frame_size*channels*sizeof(short)); data[0] = (unsigned char*)calloc(max_payload_bytes,sizeof(char)); if( use_inbandfec ) { data[1] = (unsigned char*)calloc(max_payload_bytes,sizeof(char)); } while (!stop) { err = fread(in, sizeof(short), frame_size*channels, fin); tot_read += err; if (err < frame_size*channels) { int i; for (i=err;i<frame_size*channels;i++) in[i] = 0; } len[toggle] = opus_encode(enc, in, frame_size, data[toggle], max_payload_bytes); #if OPUS_TEST_RANGE_CODER_STATE enc_final_range[toggle] = opus_encoder_get_final_range( enc ); #endif if (len[toggle] < 0) { fprintf (stderr, "opus_encode() returned %d\n", len[toggle]); return 1; } lost = rand()%100 < packet_loss_perc || len[toggle]==0; if( count >= use_inbandfec ) { /* delay by one packet when using in-band FEC */ if( use_inbandfec ) { if( lost_prev ) { /* attempt to decode with in-band FEC from next packet */ opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, frame_size, 1); } else { /* regular decode */ opus_decode(dec, data[1-toggle], len[1-toggle], out, frame_size, 0); } } else { opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, frame_size, 0); } write_samples = frame_size-skip; tot_written += write_samples*channels; if (tot_written > tot_read) { write_samples -= (tot_written-tot_read)/channels; stop = 1; } fwrite(out+skip, sizeof(short), write_samples*channels, fout); skip = 0; } #if OPUS_TEST_RANGE_CODER_STATE /* compare final range encoder rng values of encoder and decoder */ if( !lost && !lost_prev && opus_decoder_get_final_range( dec ) != enc_final_range[toggle^use_inbandfec] ) { fprintf (stderr, "Error: Range coder state mismatch between encoder and decoder in frame %d.\n", count); return 0; } #endif lost_prev = lost; /* count bits */ bits += len[toggle]*8; if( count >= use_inbandfec ) { nrg = 0.0; for ( k = 0; k < frame_size * channels; k++ ) { nrg += in[ k ] * (double)in[ k ]; } if ( ( nrg / ( frame_size * channels ) ) > 1e5 ) { bits_act += len[toggle]*8; count_act++; } /* Variance */ bits2 += len[toggle]*len[toggle]*64; } count++; toggle = (toggle + use_inbandfec) & 1; } fprintf (stderr, "average bitrate: %7.3f kb/s\n", 1e-3*bits*sampling_rate/(frame_size*(double)count)); fprintf (stderr, "active bitrate: %7.3f kb/s\n", 1e-3*bits_act*sampling_rate/(frame_size*(double)count_act)); fprintf (stderr, "bitrate standard deviation: %7.3f kb/s\n", 1e-3*sqrt(bits2/count - bits*bits/(count*(double)count))*sampling_rate/frame_size); /* Close any files to which intermediate results were stored */ SILK_DEBUG_STORE_CLOSE_FILES silk_TimerSave("opus_timing.txt"); opus_encoder_destroy(enc); opus_decoder_destroy(dec); free(data[0]); if (use_inbandfec) free(data[1]); fclose(fin); fclose(fout); free(in); free(out); return 0; }