/***************************************************************************** * ProcessHeaders: process Opus headers. *****************************************************************************/ static int ProcessHeaders( decoder_t *p_dec ) { ogg_packet oggpacket; unsigned pi_size[XIPH_MAX_HEADER_COUNT]; void *pp_data[XIPH_MAX_HEADER_COUNT]; unsigned i_count; int i_extra = p_dec->fmt_in.i_extra; uint8_t *p_extra = p_dec->fmt_in.p_extra; /* If we have no header (e.g. from RTP), make one. */ bool b_dummy_header = false; if( !i_extra ) { OpusHeader header; opus_prepare_header( p_dec->fmt_in.audio.i_channels, p_dec->fmt_in.audio.i_rate, &header ); if( opus_write_header( &p_extra, &i_extra, &header, opus_get_version_string() ) ) return VLC_ENOMEM; b_dummy_header = true; } if( xiph_SplitHeaders( pi_size, pp_data, &i_count, i_extra, p_extra ) ) { if( b_dummy_header ) free( p_extra ); return VLC_EGENERIC; } if( i_count < 2 ) { if( b_dummy_header ) free( p_extra ); return VLC_EGENERIC; } oggpacket.granulepos = -1; oggpacket.e_o_s = 0; oggpacket.packetno = 0; /* Take care of the initial Opus header */ oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */ oggpacket.bytes = pi_size[0]; oggpacket.packet = pp_data[0]; int ret = ProcessInitialHeader( p_dec, &oggpacket ); if (ret != VLC_SUCCESS) msg_Err( p_dec, "initial Opus header is corrupted" ); if( b_dummy_header ) free( p_extra ); return ret; }
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; if (opus_prepare_header(enc->fmt_out.audio.i_channels, enc->fmt_out.audio.i_rate, &header)) { msg_Err(enc, "Failed to prepare header."); status = VLC_ENOMEM; goto error; } /* 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, bitrate, fec */ /* 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)) { 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; }