2 Commits

7 changed files with 444 additions and 26 deletions

48
.vscode/launch.json vendored
View File

@@ -4,29 +4,29 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/Debug Clang 18.1.3 x86_64-pc-linux-gnu/tests/${fileBasenameNoExtension}",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Set Disassembly Flavor to Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
}
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/Debug Clang 18.1.3 x86_64-pc-linux-gnu/tests/${fileBasenameNoExtension}",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Set Disassembly Flavor to Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
}
]
}

11
.vscode/settings.json vendored
View File

@@ -4,6 +4,8 @@
"column": 80
}
],
"editor.renderWhitespace": "boundary",
"editor.formatOnSave": true,
"cmake.generator": "Ninja",
"files.associations": {
"cctype": "cpp",
@@ -101,7 +103,14 @@
"__locale": "cpp",
"ios": "cpp",
"locale": "cpp",
"print": "cpp"
"print": "cpp",
"__bit_reference": "cpp",
"__hash_table": "cpp",
"__node_handle": "cpp",
"__split_buffer": "cpp",
"__threading_support": "cpp",
"__verbose_abort": "cpp",
"queue": "cpp"
},
"files.exclude": {
"**/*.rpyc": true,

19
include/core/bumblebee.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef BUMBLEBEE_INCLUDE_CORE_BUMBLEBEE_H_
#define BUMBLEBEE_INCLUDE_CORE_BUMBLEBEE_H_
#include "precomp.h"
namespace bumblebee {
class BumbleBee {
public:
BumbleBee();
~BumbleBee();
private:
dpp::cluster cluster;
};
} // namespace bumblebee
#endif

View File

@@ -4,6 +4,8 @@
#include <winsock2.h>
#endif
#include <dpp/dpp.h>
#include <iostream>
#include <queue>
@@ -14,6 +16,7 @@
#include "boost/process.hpp"
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/avutil.h"
#include "libswresample/swresample.h"

View File

@@ -6,7 +6,7 @@ int main() {
boost::asio::io_context ctx;
boost::system::error_code ec;
utils::CheckUpdate(ctx);
// utils::CheckUpdate(ctx);
char buf[8192];
#ifdef WIN32

232
tests/ffmpeg_any_to_opus.cc Normal file
View File

@@ -0,0 +1,232 @@
#include "precomp.h"
#define OPUS_FRAME_SIZE 960 // 20ms @ 48kHz
int main() {
const char* input_filename = "golden.webm";
const char* output_filename = "output.opus";
AVFormatContext* fmt_ctx = NULL;
AVCodecContext* dec_ctx = NULL;
AVCodecContext* enc_ctx = NULL;
const AVCodec* decoder = NULL;
const AVCodec* encoder = NULL;
AVPacket* packet = NULL;
AVFrame* frame = NULL;
AVFrame* enc_frame = NULL;
SwrContext* swr_ctx = NULL;
FILE* outfile = NULL;
av_log_set_level(AV_LOG_ERROR);
if (avformat_open_input(&fmt_ctx, input_filename, NULL, NULL) < 0) {
fprintf(stderr, "Could not open input file\n");
return -1;
}
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
fprintf(stderr, "Could not find stream info\n");
return -1;
}
int stream_index = -1;
for (unsigned i = 0; i < fmt_ctx->nb_streams; i++) {
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
stream_index = i;
break;
}
}
if (stream_index == -1) {
fprintf(stderr, "No audio stream found\n");
return -1;
}
decoder =
avcodec_find_decoder(fmt_ctx->streams[stream_index]->codecpar->codec_id);
if (!decoder) {
fprintf(stderr, "Decoder not found\n");
return -1;
}
dec_ctx = avcodec_alloc_context3(decoder);
avcodec_parameters_to_context(dec_ctx,
fmt_ctx->streams[stream_index]->codecpar);
avcodec_open2(dec_ctx, decoder, NULL);
encoder = avcodec_find_encoder(AV_CODEC_ID_OPUS);
if (!encoder) {
fprintf(stderr, "Opus encoder not found\n");
return -1;
}
enc_ctx = avcodec_alloc_context3(encoder);
AVChannelLayout enc_layout;
av_channel_layout_default(&enc_layout, 2); // 스테레오
av_channel_layout_copy(&enc_ctx->ch_layout, &enc_layout);
enc_ctx->sample_rate = 48000;
enc_ctx->sample_fmt = AV_SAMPLE_FMT_FLT;
enc_ctx->bit_rate = 128000;
avcodec_open2(enc_ctx, encoder, NULL);
swr_ctx = NULL;
if (swr_alloc_set_opts2(&swr_ctx, &enc_ctx->ch_layout, enc_ctx->sample_fmt,
enc_ctx->sample_rate, &dec_ctx->ch_layout,
dec_ctx->sample_fmt, dec_ctx->sample_rate, 0,
NULL) < 0) {
fprintf(stderr, "Failed to allocate SwrContext\n");
return -1;
}
swr_init(swr_ctx);
packet = av_packet_alloc();
frame = av_frame_alloc();
enc_frame = av_frame_alloc();
outfile = fopen(output_filename, "wb");
if (!outfile) {
fprintf(stderr, "Could not open output file\n");
return -1;
}
// 임시 PCM 버퍼 (float, 스테레오)
float* pcm_buffer = (float*)malloc(sizeof(float) * 2 * OPUS_FRAME_SIZE *
4); // 충분히 큰 버퍼
int buffered_samples = 0;
while (av_read_frame(fmt_ctx, packet) >= 0) {
if (packet->stream_index != stream_index) {
av_packet_unref(packet);
continue;
}
avcodec_send_packet(dec_ctx, packet);
while (avcodec_receive_frame(dec_ctx, frame) == 0) {
int max_out = av_rescale_rnd(
swr_get_delay(swr_ctx, dec_ctx->sample_rate) + frame->nb_samples,
enc_ctx->sample_rate, dec_ctx->sample_rate, AV_ROUND_UP);
uint8_t** out_data = NULL;
int out_linesize = 0;
av_samples_alloc_array_and_samples(&out_data, &out_linesize, 2, max_out,
enc_ctx->sample_fmt, 0);
int converted =
swr_convert(swr_ctx, out_data, max_out, (const uint8_t**)frame->data,
frame->nb_samples);
// float PCM으로 임시 버퍼에 추가
memcpy(pcm_buffer + buffered_samples * 2, out_data[0],
converted * 2 * sizeof(float));
buffered_samples += converted;
av_freep(&out_data[0]);
free(out_data);
// OPUS_FRAME_SIZE 단위로 인코딩
while (buffered_samples >= OPUS_FRAME_SIZE) {
enc_frame->nb_samples = OPUS_FRAME_SIZE;
enc_frame->format = enc_ctx->sample_fmt;
enc_frame->sample_rate = enc_ctx->sample_rate;
av_channel_layout_copy(&enc_frame->ch_layout, &enc_ctx->ch_layout);
enc_frame->data[0] = (uint8_t*)pcm_buffer;
AVPacket* out_pkt = av_packet_alloc();
avcodec_send_frame(enc_ctx, enc_frame);
while (avcodec_receive_packet(enc_ctx, out_pkt) == 0) {
fwrite(out_pkt->data, 1, out_pkt->size, outfile);
av_packet_unref(out_pkt);
}
av_packet_free(&out_pkt);
// 버퍼 이동
memmove(pcm_buffer, pcm_buffer + OPUS_FRAME_SIZE * 2,
(buffered_samples - OPUS_FRAME_SIZE) * 2 * sizeof(float));
buffered_samples -= OPUS_FRAME_SIZE;
}
}
av_packet_unref(packet);
}
// 디코더 플러시
avcodec_send_packet(dec_ctx, NULL);
while (avcodec_receive_frame(dec_ctx, frame) == 0) {
int max_out = av_rescale_rnd(
swr_get_delay(swr_ctx, dec_ctx->sample_rate) + frame->nb_samples,
enc_ctx->sample_rate, dec_ctx->sample_rate, AV_ROUND_UP);
uint8_t** out_data = NULL;
int out_linesize = 0;
av_samples_alloc_array_and_samples(&out_data, &out_linesize, 2, max_out,
enc_ctx->sample_fmt, 0);
int converted =
swr_convert(swr_ctx, out_data, max_out, (const uint8_t**)frame->data,
frame->nb_samples);
memcpy(pcm_buffer + buffered_samples * 2, out_data[0],
converted * 2 * sizeof(float));
buffered_samples += converted;
av_freep(&out_data[0]);
free(out_data);
while (buffered_samples >= OPUS_FRAME_SIZE) {
enc_frame->nb_samples = OPUS_FRAME_SIZE;
enc_frame->format = enc_ctx->sample_fmt;
enc_frame->sample_rate = enc_ctx->sample_rate;
av_channel_layout_copy(&enc_frame->ch_layout, &enc_ctx->ch_layout);
enc_frame->data[0] = (uint8_t*)pcm_buffer;
AVPacket* out_pkt = av_packet_alloc();
avcodec_send_frame(enc_ctx, enc_frame);
while (avcodec_receive_packet(enc_ctx, out_pkt) == 0) {
fwrite(out_pkt->data, 1, out_pkt->size, outfile);
av_packet_unref(out_pkt);
}
av_packet_free(&out_pkt);
memmove(pcm_buffer, pcm_buffer + OPUS_FRAME_SIZE * 2,
(buffered_samples - OPUS_FRAME_SIZE) * 2 * sizeof(float));
buffered_samples -= OPUS_FRAME_SIZE;
}
}
// 마지막 남은 샘플 인코딩
if (buffered_samples > 0) {
enc_frame->nb_samples = buffered_samples;
enc_frame->format = enc_ctx->sample_fmt;
enc_frame->sample_rate = enc_ctx->sample_rate;
av_channel_layout_copy(&enc_frame->ch_layout, &enc_ctx->ch_layout);
enc_frame->data[0] = (uint8_t*)pcm_buffer;
AVPacket* out_pkt = av_packet_alloc();
avcodec_send_frame(enc_ctx, enc_frame);
while (avcodec_receive_packet(enc_ctx, out_pkt) == 0) {
fwrite(out_pkt->data, 1, out_pkt->size, outfile);
av_packet_unref(out_pkt);
}
av_packet_free(&out_pkt);
}
// 인코더 플러시
avcodec_send_frame(enc_ctx, NULL);
AVPacket* out_pkt = av_packet_alloc();
while (avcodec_receive_packet(enc_ctx, out_pkt) == 0) {
fwrite(out_pkt->data, 1, out_pkt->size, outfile);
av_packet_unref(out_pkt);
}
av_packet_free(&out_pkt);
fclose(outfile);
free(pcm_buffer);
swr_free(&swr_ctx);
av_frame_free(&frame);
av_frame_free(&enc_frame);
av_packet_free(&packet);
avcodec_free_context(&dec_ctx);
avcodec_free_context(&enc_ctx);
avformat_close_input(&fmt_ctx);
printf("Encoding finished: %s\n", output_filename);
return 0;
}

View File

@@ -0,0 +1,155 @@
#include <fstream>
#include "ffmpeg/libavcodec.h"
#include "precomp.h"
int main() {
const char* input_filename = "golden.webm";
const char* output_filename = "output.pcm";
AVFormatContext* fmt_ctx = NULL;
AVCodecContext* codec_ctx = NULL;
const AVCodec* codec = NULL;
AVPacket* packet = NULL;
AVFrame* frame = NULL;
SwrContext* swr_ctx = NULL;
FILE* outfile = NULL;
if (avformat_open_input(&fmt_ctx, input_filename, NULL, NULL) < 0) {
fprintf(stderr, "Could not open input file\n");
return -1;
}
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
fprintf(stderr, "Could not find stream info\n");
return -1;
}
int stream_index = -1;
for (unsigned i = 0; i < fmt_ctx->nb_streams; i++) {
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
stream_index = i;
break;
}
}
if (stream_index == -1) {
fprintf(stderr, "Could not find audio stream\n");
return -1;
}
codec =
avcodec_find_decoder(fmt_ctx->streams[stream_index]->codecpar->codec_id);
if (!codec) {
fprintf(stderr, "Could not find decoder\n");
return -1;
}
codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx) {
fprintf(stderr, "Could not allocate codec context\n");
return -1;
}
if (avcodec_parameters_to_context(
codec_ctx, fmt_ctx->streams[stream_index]->codecpar) < 0) {
fprintf(stderr, "Failed to copy codec parameters\n");
return -1;
}
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
return -1;
}
packet = av_packet_alloc();
frame = av_frame_alloc();
if (!packet || !frame) {
fprintf(stderr, "Could not allocate packet or frame\n");
return -1;
}
outfile = fopen(output_filename, "wb");
if (!outfile) {
fprintf(stderr, "Could not open output file\n");
return -1;
}
// AVChannelLayout 초기화
AVChannelLayout in_layout, out_layout;
if (av_channel_layout_copy(&in_layout, &codec_ctx->ch_layout) < 0) {
fprintf(stderr, "Failed to copy channel layout\n");
return -1;
}
av_channel_layout_default(&out_layout, 2); // 스테레오
swr_ctx = NULL; // 먼저 NULL로 선언
if (swr_alloc_set_opts2(&swr_ctx, &out_layout, AV_SAMPLE_FMT_S16, 48000,
&in_layout, codec_ctx->sample_fmt,
codec_ctx->sample_rate, 0, NULL) < 0) {
fprintf(stderr, "Failed to allocate and set SwrContext\n");
return -1;
}
if (swr_init(swr_ctx) < 0) {
fprintf(stderr, "Failed to initialize SwrContext\n");
return -1;
}
while (av_read_frame(fmt_ctx, packet) >= 0) {
if (packet->stream_index == stream_index) {
if (avcodec_send_packet(codec_ctx, packet) == 0) {
while (avcodec_receive_frame(codec_ctx, frame) == 0) {
int out_samples =
av_rescale_rnd(swr_get_delay(swr_ctx, codec_ctx->sample_rate) +
frame->nb_samples,
48000, codec_ctx->sample_rate, AV_ROUND_UP);
uint8_t** out_buf = NULL;
int out_linesize = 0;
av_samples_alloc_array_and_samples(&out_buf, &out_linesize, 2,
out_samples, AV_SAMPLE_FMT_S16, 0);
int converted_samples =
swr_convert(swr_ctx, out_buf, out_samples,
(const uint8_t**)frame->data, frame->nb_samples);
fwrite(out_buf[0], 1, converted_samples * 2 * 2, outfile);
av_freep(&out_buf[0]);
free(out_buf);
}
}
}
av_packet_unref(packet);
}
// 디코더 플러시
avcodec_send_packet(codec_ctx, NULL);
while (avcodec_receive_frame(codec_ctx, frame) == 0) {
int out_samples = av_rescale_rnd(
swr_get_delay(swr_ctx, codec_ctx->sample_rate) + frame->nb_samples,
48000, codec_ctx->sample_rate, AV_ROUND_UP);
uint8_t** out_buf = NULL;
int out_linesize = 0;
av_samples_alloc_array_and_samples(&out_buf, &out_linesize, 2, out_samples,
AV_SAMPLE_FMT_S16, 0);
int converted_samples =
swr_convert(swr_ctx, out_buf, out_samples, (const uint8_t**)frame->data,
frame->nb_samples);
fwrite(out_buf[0], 1, converted_samples * 2 * 2, outfile);
av_freep(&out_buf[0]);
free(out_buf);
}
fclose(outfile);
swr_free(&swr_ctx);
av_frame_free(&frame);
av_packet_free(&packet);
avcodec_free_context(&codec_ctx);
avformat_close_input(&fmt_ctx);
printf("Decoding finished, output saved to %s\n", output_filename);
return 0;
}