Skip to content

Instantly share code, notes, and snippets.

@bitristan
Created September 25, 2024 23:45
Show Gist options
  • Save bitristan/52c35b57edc09b419e6aa13b863ccd83 to your computer and use it in GitHub Desktop.
Save bitristan/52c35b57edc09b419e6aa13b863ccd83 to your computer and use it in GitHub Desktop.
convert pcm to ogg opus
#include <opusenc.h>
#include <vector>
#include <fstream>
#include <iostream>
std::vector<unsigned char> readFile(const std::string &filename) {
std::ifstream file(filename, std::ios::binary | std::ios::ate);
if (!file.is_open()) {
throw std::runtime_error("Failed to open file: " + filename);
}
std::streamsize size = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<unsigned char> buffer(size);
if (!file.read(reinterpret_cast<char *>(buffer.data()), size)) {
throw std::runtime_error("Failed to read file: " + filename);
}
return buffer;
}
void writeFile(const std::string &filename, const std::vector<unsigned char> &data) {
std::ofstream file(filename, std::ios::binary);
if (!file.is_open()) {
throw std::runtime_error("Failed to open file: " + filename);
}
if (!file.write(reinterpret_cast<const char *>(data.data()), data.size())) {
throw std::runtime_error("Failed to write file: " + filename);
}
}
std::vector<unsigned char> encodeToOgg(const std::vector<unsigned char> &pcmData, int sampleRate, int channels) {
OggOpusComments *comments = ope_comments_create();
if (comments == nullptr) {
throw std::runtime_error("Failed to create Opus comments.");
}
int error;
OggOpusEnc *enc = ope_encoder_create_pull(comments, sampleRate, channels, 0, &error);
if (error != OPE_OK) {
ope_comments_destroy(comments);
throw std::runtime_error("ope encoder create pull error: " + std::string(ope_strerror(error)));
}
if (ope_encoder_write(enc, reinterpret_cast<const opus_int16 *>(pcmData.data()), pcmData.size() / (2 * channels)) != OPE_OK) {
ope_encoder_destroy(enc);
ope_comments_destroy(comments);
throw std::runtime_error("Failed to write PCM data to encoder.");
}
if (ope_encoder_drain(enc) != OPE_OK) {
ope_encoder_destroy(enc);
ope_comments_destroy(comments);
throw std::runtime_error("Failed to drain encoder.");
}
std::vector<unsigned char> buffer;
while (true) {
unsigned char *page;
opus_int32 page_size;
int result = ope_encoder_get_page(enc, &page, &page_size, 0);
if (result == 0) {
break;
}
buffer.insert(buffer.end(), page, page + page_size);
}
ope_encoder_destroy(enc);
ope_comments_destroy(comments);
return buffer;
}
int main() {
try {
std::vector<unsigned char> pcmData = readFile("input.pcm");
int sampleRate = 16000;
int channels = 1;
std::vector<unsigned char> oggData = encodeToOgg(pcmData, sampleRate, channels);
writeFile("output.ogg", oggData);
std::cout << "Conversion successful. Output saved to output.ogg" << std::endl;
} catch (const std::exception &e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment