Skip to content

Commit

Permalink
write_samples WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
runei committed Aug 14, 2024
1 parent 551e31c commit 4488193
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "roc_audio/vorbis_encoder.h"
#include "roc_core/panic.h"
#include <iostream>

namespace roc {
namespace audio {
Expand All @@ -18,9 +19,9 @@ VorbisEncoder::VorbisEncoder(const SampleSpec& sample_spec)
, frame_size_(0) {
vorbis_info_init(&vorbis_info_);

const int num_channels = static_cast<int>(sample_spec.num_channels());
const int sample_rate = static_cast<int>(sample_spec.sample_rate());
int ret = vorbis_encode_init_vbr(&vorbis_info_, num_channels, sample_rate, 0.0f);
const long num_channels = static_cast<long>(sample_spec.num_channels());
const long sample_rate = static_cast<long>(sample_spec.sample_rate());
int ret = vorbis_encode_init_vbr(&vorbis_info_, num_channels, sample_rate, 0.5f);
if (ret != 0) {
roc_panic("vorbis encoder: failed to initialize vorbis encoder");
}
Expand Down Expand Up @@ -56,22 +57,16 @@ status::StatusCode VorbisEncoder::init_status() const {

size_t VorbisEncoder::encoded_byte_count(size_t num_samples) const {
if (!initialized_) {
roc_panic("vorbis encoder: encoder not initialized");
return 0;
}

if (vorbis_info_.rate <= 0 || vorbis_info_.channels <= 0
|| vorbis_info_.bitrate_nominal <= 0) {
roc_panic("vorbis encoder: vorbis_info structure has invalid values");
return 0;
}

// Average number of bits used per sample, per channel.
const size_t bit_width = static_cast<size_t>(
(vorbis_info_.bitrate_nominal / vorbis_info_.rate) / vorbis_info_.channels);
const size_t channels = static_cast<size_t>(vorbis_info_.channels);
// const size_t sample_rate = static_cast<size_t>(vorbis_info_.rate);
// const size_t bitrate_nominal = static_cast<size_t>(vorbis_info_.bitrate_nominal);

const size_t encoded_bytes = (num_samples * bit_width + 7) / 8;

return encoded_bytes;
size_t estimated_bytes = (32 * num_samples * channels) / (8);
return estimated_bytes;
}

void VorbisEncoder::begin_frame(void* frame_data, size_t frame_size) {
Expand All @@ -84,12 +79,95 @@ void VorbisEncoder::begin_frame(void* frame_data, size_t frame_size) {
}

size_t VorbisEncoder::write_samples(const sample_t* samples, size_t n_samples) {
roc_panic("TODO");
return 0;
if (!initialized_) {
roc_panic("vorbis encoder: encoder not initialized");
return 0;
}

if (!samples || n_samples == 0) {
return 0;
}

buffer_samples_(samples, n_samples);

size_t total_bytes_written = process_analysis_and_encoding_();

vorbis_analysis_wrote(&vorbis_dsp_, 0);

total_bytes_written += process_analysis_and_encoding_();

return total_bytes_written;
}

void VorbisEncoder::end_frame() {
roc_panic("TODO");
frame_data_ = NULL;
frame_size_ = 0;
}

void VorbisEncoder::buffer_samples_(const sample_t* samples, size_t n_samples) {
const int int_n_samples = static_cast<int>(n_samples);

float** buffer = vorbis_analysis_buffer(&vorbis_dsp_, int_n_samples);

for (int i = 0; i < int_n_samples; ++i) {
for (int ch = 0; ch < vorbis_info_.channels; ++ch) {
buffer[ch][i] = samples[i * vorbis_info_.channels + ch];
}
}

vorbis_analysis_wrote(&vorbis_dsp_, int_n_samples);
}

size_t VorbisEncoder::process_analysis_and_encoding_() {
size_t total_bytes_written = 0;

while (vorbis_analysis_blockout(&vorbis_dsp_, &vorbis_block_) == 1) {
vorbis_analysis(&vorbis_block_, NULL);

vorbis_bitrate_addblock(&vorbis_block_);

total_bytes_written += extract_and_write_packets_();
}

return total_bytes_written;
}

size_t VorbisEncoder::extract_and_write_packets_() {
size_t bytes_written = 0;

ogg_packet packet;
while (vorbis_bitrate_flushpacket(&vorbis_dsp_, &packet)) {
ogg_stream_packetin(&ogg_stream_, &packet);

bytes_written += write_ogg_pages_();
}

return bytes_written;
}

size_t VorbisEncoder::write_ogg_pages_() {
long bytes_written = 0;

ogg_page page;
while (ogg_stream_pageout(&ogg_stream_, &page)) {
if (bytes_written + page.header_len + page.body_len
> static_cast<long>(frame_size_)) {
roc_panic("vorbis encoder: frame buffer overflow");
}

write_to_frame_(page.header, page.header_len, bytes_written);
bytes_written += page.header_len;

write_to_frame_(page.body, page.body_len, bytes_written);
bytes_written += page.body_len;
}

return static_cast<size_t>(bytes_written);
}

void VorbisEncoder::write_to_frame_(const void* data, long size, long offset) {
const size_t casted_size = static_cast<size_t>(size);
memcpy(static_cast<uint8_t*>(frame_data_) + offset, data, casted_size);
}

} // namespace audio
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
*/

//! @file roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h
//! @brief Vorbis audio decoder.
//! @brief Vorbis audio encoder.

#ifndef ROC_AUDIO_VORBIS_ENCODER_H_
#define ROC_AUDIO_VORBIS_ENCODER_H_

#include "roc_audio/iframe_encoder.h"
#include "roc_audio/sample_spec.h"
#include <vorbis/codec.h>
#include <vorbis/vorbisenc.h>

namespace roc {
Expand Down Expand Up @@ -44,6 +45,12 @@ class VorbisEncoder : public IFrameEncoder {
virtual void end_frame();

private:
void buffer_samples_(const sample_t* samples, size_t n_samples);
size_t process_analysis_and_encoding_();
size_t extract_and_write_packets_();
size_t write_ogg_pages_();
void write_to_frame_(const void* data, long size, long offset);

bool initialized_;
void* frame_data_;
size_t frame_size_;
Expand Down

0 comments on commit 4488193

Please sign in to comment.