mirror of
https://github.com/HappyTanuki/BumbleCee.git
synced 2025-10-25 17:35:58 +00:00
Compare commits
5 Commits
f846dd7195
...
refactor
| Author | SHA1 | Date | |
|---|---|---|---|
| 610074e4ac | |||
| e3b5e92164 | |||
| b123b2ecdb | |||
| e26d20a869 | |||
| f3974bb86f |
8
.clang-format
Normal file
8
.clang-format
Normal file
@@ -0,0 +1,8 @@
|
||||
# Google C/C++ Code Style Settings
|
||||
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
Standard: c++20
|
||||
IndentWidth: 2
|
||||
UseTab: Never
|
||||
ColumnLimit: 80
|
||||
10
.idea/.gitignore
generated
vendored
10
.idea/.gitignore
generated
vendored
@@ -1,10 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Environment-dependent path to Maven home directory
|
||||
/mavenHomeManager.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
9
.idea/BumbleCee.iml
generated
9
.idea/BumbleCee.iml
generated
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
6
.idea/misc.xml
generated
6
.idea/misc.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_23" default="true" project-jdk-name="openjdk-23" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/BumbleCee.iml" filepath="$PROJECT_DIR$/.idea/BumbleCee.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
19
.vscode/c_cpp_properties.json
vendored
19
.vscode/c_cpp_properties.json
vendored
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/include"
|
||||
],
|
||||
"defines": [
|
||||
"DDPP_CORO=on"
|
||||
],
|
||||
"compilerPath": "/usr/bin/gcc",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "c++20",
|
||||
"intelliSenseMode": "linux-gcc-x64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
13
.vscode/launch.json
vendored
13
.vscode/launch.json
vendored
@@ -1,13 +1,17 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug",
|
||||
"name": "(gdb) Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/build/BumbleCee",
|
||||
"program": "${workspaceFolder}/build/Debug Clang 18.1.3 x86_64-pc-linux-gnu/tests/${fileBasenameNoExtension}",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"cwd": "${fileDirname}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
@@ -22,8 +26,7 @@
|
||||
"text": "-gdb-set disassembly-flavor intel",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"preLaunchTask": "${defaultBuildTask}"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
57
.vscode/settings.json
vendored
57
.vscode/settings.json
vendored
@@ -1,9 +1,18 @@
|
||||
{
|
||||
"C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json",
|
||||
"editor.rulers": [
|
||||
{
|
||||
"column": 80
|
||||
}
|
||||
],
|
||||
"editor.renderWhitespace": "boundary",
|
||||
"editor.formatOnSave": true,
|
||||
"cmake.generator": "Ninja",
|
||||
"files.associations": {
|
||||
"cctype": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"csetjmp": "cpp",
|
||||
"csignal": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdio": "cpp",
|
||||
@@ -12,37 +21,53 @@
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"any": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"strstream": "cpp",
|
||||
"barrier": "cpp",
|
||||
"bit": "cpp",
|
||||
"bitset": "cpp",
|
||||
"cfenv": "cpp",
|
||||
"charconv": "cpp",
|
||||
"chrono": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"codecvt": "cpp",
|
||||
"compare": "cpp",
|
||||
"complex": "cpp",
|
||||
"concepts": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"coroutine": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"deque": "cpp",
|
||||
"forward_list": "cpp",
|
||||
"list": "cpp",
|
||||
"map": "cpp",
|
||||
"set": "cpp",
|
||||
"string": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"expected": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"regex": "cpp",
|
||||
"source_location": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"rope": "cpp",
|
||||
"slist": "cpp",
|
||||
"format": "cpp",
|
||||
"fstream": "cpp",
|
||||
"future": "cpp",
|
||||
@@ -51,20 +76,46 @@
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"latch": "cpp",
|
||||
"limits": "cpp",
|
||||
"mutex": "cpp",
|
||||
"new": "cpp",
|
||||
"numbers": "cpp",
|
||||
"ostream": "cpp",
|
||||
"ranges": "cpp",
|
||||
"scoped_allocator": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"shared_mutex": "cpp",
|
||||
"span": "cpp",
|
||||
"spanstream": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stacktrace": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"stdfloat": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"syncstream": "cpp",
|
||||
"thread": "cpp",
|
||||
"typeindex": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"valarray": "cpp",
|
||||
"variant": "cpp",
|
||||
"__config": "cpp",
|
||||
"rope": "cpp"
|
||||
"__locale": "cpp",
|
||||
"ios": "cpp",
|
||||
"locale": "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,
|
||||
"**/*.rpa": true,
|
||||
"**/*.rpymc": true,
|
||||
"**/cache/": true
|
||||
}
|
||||
}
|
||||
37
.vscode/tasks.json
vendored
37
.vscode/tasks.json
vendored
@@ -1,37 +0,0 @@
|
||||
{
|
||||
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "cppbuild",
|
||||
"label": "ninja",
|
||||
"command": "ninja",
|
||||
"args": [],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"dependsOn": ["cmake"]
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"label": "cmake",
|
||||
"command": "cmake",
|
||||
"args": [
|
||||
"..",
|
||||
"-G",
|
||||
"Ninja"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
119
CMakeLists.txt
119
CMakeLists.txt
@@ -2,23 +2,28 @@ cmake_minimum_required (VERSION 3.16)
|
||||
set(BOT_NAME "BumbleCee")
|
||||
project(${BOT_NAME} LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
set(BOOST_EXCLUDE_LIBRARIES nowide)
|
||||
set(BUILD_TESTING ON)
|
||||
|
||||
set(DPP_BUILD_TEST OFF)
|
||||
|
||||
enable_testing()
|
||||
|
||||
if(WIN32)
|
||||
set(OPENSSL_ROOT_DIR "C:/Program Files/OpenSSL-Win64")
|
||||
set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/include")
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
set(OPENSSL_CRYPTO_LIBRARY "${OPENSSL_ROOT_DIR}/lib/VC/x64/MDd/libcrypto.lib")
|
||||
set(OPENSSL_SSL_LIBRARY "${OPENSSL_ROOT_DIR}/lib/VC/x64/MDd/libssl.lib")
|
||||
set(OPENSSL_CRYPTO_LIBRARY "${OPENSSL_ROOT_DIR}/lib/VC/x64/MTd/libcrypto.lib")
|
||||
set(OPENSSL_SSL_LIBRARY "${OPENSSL_ROOT_DIR}/lib/VC/x64/MTd/libssl.lib")
|
||||
else()
|
||||
set(OPENSSL_CRYPTO_LIBRARY "${OPENSSL_ROOT_DIR}/lib/VC/x64/MD/libcrypto.lib")
|
||||
set(OPENSSL_SSL_LIBRARY "${OPENSSL_ROOT_DIR}/lib/VC/x64/MD/libssl.lib")
|
||||
set(OPENSSL_CRYPTO_LIBRARY "${OPENSSL_ROOT_DIR}/lib/VC/x64/MT/libcrypto.lib")
|
||||
set(OPENSSL_SSL_LIBRARY "${OPENSSL_ROOT_DIR}/lib/VC/x64/MT/libssl.lib")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -26,14 +31,15 @@ find_package(OpenSSL REQUIRED)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
set(BUILD_SHARED_LIBS_OLD ${BUILD_SHARED_LIBS})
|
||||
|
||||
FetchContent_Declare(
|
||||
Boost
|
||||
URL "https://github.com/boostorg/boost/releases/download/boost-1.89.0/boost-1.89.0-cmake.7z"
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP ON
|
||||
CMAKE_ARGS
|
||||
-DBOOST_USE_STATIC_LIBS=OFF # DLL 사용
|
||||
-DBOOST_USE_STATIC_RUNTIME=OFF # /MD, /MDd 사용
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Do not build SHARED libraries" FORCE)
|
||||
message(STATUS "Fetching and making available Boost...")
|
||||
FetchContent_MakeAvailable(Boost)
|
||||
|
||||
@@ -42,23 +48,23 @@ FetchContent_Declare(
|
||||
GIT_REPOSITORY "https://github.com/brainboxdotcc/DPP.git"
|
||||
GIT_TAG "v10.1.3"
|
||||
GIT_SHALLOW ON
|
||||
CMAKE_ARGS -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} -DCMAKE_CXX_STANDARD_REQUIRED=ON
|
||||
)
|
||||
set(BUILD_SHARED_LIBS ON CACHE BOOL "Build SHARED libraries" FORCE)
|
||||
message(STATUS "Fetching and making available dpp...")
|
||||
FetchContent_MakeAvailable(dpp)
|
||||
|
||||
set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_OLD} CACHE BOOL "Type of libraries to build" FORCE)
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# 플랫폼별 FFmpeg 바이너리 다운로드 및 링크
|
||||
# -------------------------------------------------------------
|
||||
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
|
||||
set(FFMPEG_URL "https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-win64-lgpl-shared.zip")
|
||||
set(FFMPEG_SHA256HASH "SHA256=c95a9d4e030f694f33c85a7611204383a0bca906514a08d83d3858496b122f76")
|
||||
set(FFMPEG_ARCHIVE_NAME "ffmpeg-windows")
|
||||
set(FFMPEG_LIB_DIR "lib")
|
||||
set(FFMPEG_INCLUDE_DIR "include")
|
||||
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
|
||||
set(FFMPEG_URL "https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linux64-lgpl-shared.tar.xz")
|
||||
set(FFMPEG_SHA256HASH "SHA256=ebf6b197ffe52d798504895b4c2b84114ad5d2b406ac76e18374b44d1184ade3")
|
||||
set(FFMPEG_ARCHIVE_NAME "ffmpeg-linux")
|
||||
set(FFMPEG_LIB_DIR "lib")
|
||||
set(FFMPEG_INCLUDE_DIR "include")
|
||||
@@ -69,7 +75,6 @@ endif()
|
||||
FetchContent_Declare(
|
||||
ffmpeg
|
||||
URL ${FFMPEG_URL}
|
||||
URL_HASH ${FFMPEG_SHA256HASH}
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP ON
|
||||
SOURCE_DIR ${CMAKE_BINARY_DIR}/${FFMPEG_ARCHIVE_NAME}
|
||||
)
|
||||
@@ -87,41 +92,42 @@ find_library(AVUTIL_LIBRARY NAMES avutil PATHS ${FFMPEG_LIBRARY_PATH} NO_DEFAULT
|
||||
message(STATUS "AVUTIL_LIBRARY = ${AVUTIL_LIBRARY}")
|
||||
find_library(SWSCALE_LIBRARY NAMES swscale PATHS ${FFMPEG_LIBRARY_PATH} NO_DEFAULT_PATH)
|
||||
message(STATUS "SWSCALE_LIBRARY = ${SWSCALE_LIBRARY}")
|
||||
find_library(SWRESAMPLE_LIBRARY NAMES swresample PATHS ${FFMPEG_LIBRARY_PATH} NO_DEFAULT_PATH)
|
||||
message(STATUS "SWRESAMPLE_LIBRARY = ${SWRESAMPLE_LIBRARY}")
|
||||
|
||||
if(NOT AVCODEC_LIBRARY OR NOT AVFORMAT_LIBRARY OR NOT AVUTIL_LIBRARY)
|
||||
if(NOT AVCODEC_LIBRARY OR NOT AVFORMAT_LIBRARY OR NOT AVUTIL_LIBRARY OR NOT SWRESAMPLE_LIBRARY)
|
||||
message(FATAL_ERROR "FFmpeg 라이브러리를 찾을 수 없습니다. 다운로드 경로를 확인해주세요.")
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE CORES "src/*.cpp" "src/*.cxx" "src/*.cc")
|
||||
file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.cxx" "src/*.cc")
|
||||
|
||||
set(ALL_SOURCE_FILES
|
||||
${CORES}
|
||||
${AUDIO_SOURCES}
|
||||
${COMMANDS_SOURCES}
|
||||
${QUEUE_SOURCES}
|
||||
${SETTINGS_SOURCES}
|
||||
${UTILS_SOURCES}
|
||||
)
|
||||
add_library(${BOT_NAME}_lib ${SOURCES})
|
||||
|
||||
add_executable(${BOT_NAME} ${ALL_SOURCE_FILES})
|
||||
target_include_directories(${BOT_NAME}_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
target_link_libraries(${BOT_NAME} PRIVATE dpp)
|
||||
target_link_libraries(${BOT_NAME} PRIVATE Boost::filesystem)
|
||||
target_link_libraries(${BOT_NAME} PRIVATE Boost::process)
|
||||
target_link_libraries(${BOT_NAME} PRIVATE Boost::log)
|
||||
target_link_libraries(${BOT_NAME} PRIVATE Boost::beast)
|
||||
target_link_libraries(${BOT_NAME} PRIVATE OpenSSL::Crypto)
|
||||
target_link_libraries(${BOT_NAME} PRIVATE OpenSSL::SSL)
|
||||
target_link_libraries(${BOT_NAME} PRIVATE ${AVUTIL_LIBRARY})
|
||||
target_link_libraries(${BOT_NAME} PRIVATE ${AVCODEC_LIBRARY})
|
||||
target_link_libraries(${BOT_NAME} PRIVATE ${AVFORMAT_LIBRARY})
|
||||
target_link_libraries(${BOT_NAME} PRIVATE ${SWSCALE_LIBRARY})
|
||||
target_include_directories(${BOT_NAME}_lib PUBLIC ${OpenSSL_INCLUDE_DIRS})
|
||||
target_include_directories(${BOT_NAME}_lib PUBLIC ${FFMPEG_INCLUDE_PATH})
|
||||
|
||||
target_precompile_headers(${BOT_NAME}_lib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include/precomp.h")
|
||||
|
||||
target_link_libraries(${BOT_NAME}_lib PUBLIC dpp)
|
||||
target_link_libraries(${BOT_NAME}_lib PUBLIC Boost::filesystem)
|
||||
target_link_libraries(${BOT_NAME}_lib PUBLIC Boost::process)
|
||||
target_link_libraries(${BOT_NAME}_lib PUBLIC Boost::log)
|
||||
target_link_libraries(${BOT_NAME}_lib PUBLIC Boost::beast)
|
||||
target_link_libraries(${BOT_NAME}_lib PUBLIC OpenSSL::Crypto)
|
||||
target_link_libraries(${BOT_NAME}_lib PUBLIC OpenSSL::SSL)
|
||||
target_link_libraries(${BOT_NAME}_lib PUBLIC ${AVUTIL_LIBRARY})
|
||||
target_link_libraries(${BOT_NAME}_lib PUBLIC ${AVCODEC_LIBRARY})
|
||||
target_link_libraries(${BOT_NAME}_lib PUBLIC ${AVFORMAT_LIBRARY})
|
||||
target_link_libraries(${BOT_NAME}_lib PUBLIC ${SWSCALE_LIBRARY})
|
||||
target_link_libraries(${BOT_NAME}_lib PUBLIC ${SWRESAMPLE_LIBRARY})
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(${BOT_NAME} PRIVATE ws2_32)
|
||||
target_link_libraries(${BOT_NAME}_lib PUBLIC ws2_32)
|
||||
endif()
|
||||
if(UNIX AND NOT APPLE AND CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
if(UNIX AND NOT APPLE)
|
||||
set_target_properties(${BOT_NAME}_lib PROPERTIES
|
||||
BUILD_WITH_INSTALL_RPATH TRUE
|
||||
INSTALL_RPATH "$ORIGIN"
|
||||
SKIP_BUILD_RPATH FALSE
|
||||
@@ -129,30 +135,29 @@ if(UNIX AND NOT APPLE AND CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
)
|
||||
endif()
|
||||
|
||||
target_include_directories(${BOT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
add_executable(${BOT_NAME} ${SOURCES})
|
||||
|
||||
target_include_directories(${BOT_NAME} PRIVATE ${OpenSSL_INCLUDE_DIRS})
|
||||
target_include_directories(${BOT_NAME} PRIVATE ${FFMPEG_INCLUDE_PATH})
|
||||
target_link_libraries(${BOT_NAME} PUBLIC ${BOT_NAME}_lib)
|
||||
|
||||
target_precompile_headers(${BOT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include/precomp.h")
|
||||
|
||||
add_custom_command(TARGET ${BOT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
"$<TARGET_FILE_DIR:Boost::filesystem>"
|
||||
"$<TARGET_FILE_DIR:${BOT_NAME}>"
|
||||
COMMENT "Copying Boost.Filesystem DLL/so files to output directory"
|
||||
file(GLOB FFMPEG_SHARED
|
||||
"${CMAKE_BINARY_DIR}/${FFMPEG_ARCHIVE_NAME}/bin/*.dll" # Windows
|
||||
"${CMAKE_BINARY_DIR}/${FFMPEG_ARCHIVE_NAME}/lib/*.so*" # Linux
|
||||
)
|
||||
|
||||
add_custom_command(TARGET ${BOT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
"$<TARGET_FILE_DIR:Boost::process>"
|
||||
"$<TARGET_FILE_DIR:${BOT_NAME}>"
|
||||
COMMENT "Copying Boost.Process DLL/so files to output directory"
|
||||
)
|
||||
foreach(ffmpeg_shared ${FFMPEG_SHARED})
|
||||
add_custom_command(TARGET ${BOT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${ffmpeg_shared}"
|
||||
"$<TARGET_FILE_DIR:${BOT_NAME}>"
|
||||
COMMENT "Copying ${ffmpeg_shared} to output directory"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
add_custom_command(TARGET ${BOT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
"${CMAKE_BINARY_DIR}/${FFMPEG_ARCHIVE_NAME}/bin"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"$<TARGET_FILE:dpp>"
|
||||
"$<TARGET_FILE_DIR:${BOT_NAME}>"
|
||||
COMMENT "Copying FFMpeg_AVCODEC DLL/so files to output directory"
|
||||
)
|
||||
COMMENT "Copying dpp DLL/so files to output directory"
|
||||
)
|
||||
|
||||
add_subdirectory(tests)
|
||||
19
include/core/bumblebee.h
Normal file
19
include/core/bumblebee.h
Normal 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
|
||||
@@ -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"
|
||||
|
||||
@@ -7,32 +7,35 @@ namespace utils {
|
||||
// @brief 명령어가 실행 가능한지 체크합니다
|
||||
// @param cmd 실행할 명령
|
||||
// @return int error_code
|
||||
int ValidateCommand(std::string cmd);
|
||||
int ValidateCommand(
|
||||
boost::asio::io_context& ctx, std::string cmd,
|
||||
const std::vector<std::string>& args = std::vector<std::string>());
|
||||
// @brief 명령어를 쉘에서 실행하고 결과를 EOF 전까지 읽어 반환합니다
|
||||
// @param cmd 실행할 명령
|
||||
// @param args 아규먼트
|
||||
// @return int error_code
|
||||
int ExecuteCommand(
|
||||
const std::string& cmd,
|
||||
boost::asio::io_context& ctx, const std::string& cmd,
|
||||
const std::vector<std::string>& args = std::vector<std::string>());
|
||||
// @brief 명령어를 쉘에서 실행하고 결과를 EOF 전까지 읽어 반환합니다
|
||||
// @param cmd 실행할 명령
|
||||
// @param result 실행결과
|
||||
// @return int error_code
|
||||
int ExecuteCommand(const std::string& cmd, std::string& result);
|
||||
int ExecuteCommand(boost::asio::io_context& ctx, const std::string& cmd,
|
||||
std::string& result);
|
||||
// @brief 명령어를 쉘에서 실행하고 결과를 EOF 전까지 읽어 반환합니다
|
||||
// @param cmd 실행할 명령
|
||||
// @param args 아규먼트
|
||||
// @param result 실행결과
|
||||
// @return int error_code
|
||||
int ExecuteCommand(const std::string& cmd, const std::vector<std::string>& args,
|
||||
std::string& result);
|
||||
int ExecuteCommand(boost::asio::io_context& ctx, const std::string& cmd,
|
||||
const std::vector<std::string>& args, std::string& result);
|
||||
// @brief 명령어를 쉘에서 실행하고 결과를 파이프로 연결하여 반환합니다
|
||||
// @param cmd 실행할 명령
|
||||
// @param args 아규먼트
|
||||
// @return boost::process::popen
|
||||
boost::process::popen OpenPipe(
|
||||
const std::string& cmd,
|
||||
boost::asio::io_context& ctx, const std::string& cmd,
|
||||
const std::vector<std::string>& args = std::vector<std::string>());
|
||||
} // namespace utils
|
||||
#endif
|
||||
@@ -5,9 +5,9 @@
|
||||
|
||||
namespace utils {
|
||||
|
||||
int InstallYtdlp();
|
||||
int InstallYtdlp(boost::asio::io_context& ctx);
|
||||
|
||||
int CheckUpdate();
|
||||
int CheckUpdate(boost::asio::io_context& ctx);
|
||||
|
||||
} // namespace utils
|
||||
|
||||
|
||||
29
src/main.cc
29
src/main.cc
@@ -3,33 +3,8 @@
|
||||
#include "utils/update_checker.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
boost::system::error_code ec;
|
||||
char buf[16384];
|
||||
std::string output;
|
||||
|
||||
utils::CheckUpdate();
|
||||
|
||||
// utils::ExecuteCommand("yt-dlp", {"-U"}, output);
|
||||
// std::cout << output;
|
||||
|
||||
// auto ytdlp_pipe = utils::OpenPipe(
|
||||
// "yt-dlp", {"-o", "-", "--quiet", "--ignore-errors", "-f", "bestaudio",
|
||||
// "https://youtu.be/9_bTl2vvYQg?si=IVhvpDhnpPvziwQR"});
|
||||
|
||||
// while (true) {
|
||||
// boost::system::error_code read_ec;
|
||||
// size_t bytes_read =
|
||||
// boost::asio::read(ytdlp_pipe, boost::asio::buffer(buf, 16384),
|
||||
// read_ec);
|
||||
|
||||
// if (bytes_read > 0) {
|
||||
// std::cout.write(buf, bytes_read);
|
||||
// }
|
||||
|
||||
// if (read_ec == boost::asio::error::eof || read_ec) {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
boost::asio::io_context ctx;
|
||||
utils::CheckUpdate(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -4,50 +4,50 @@
|
||||
|
||||
namespace utils {
|
||||
|
||||
int ValidateCommand(std::string cmd) {
|
||||
int ValidateCommand(boost::asio::io_context& ctx, std::string cmd,
|
||||
const std::vector<std::string>& args) {
|
||||
try {
|
||||
ExecuteCommand(cmd);
|
||||
ExecuteCommand(ctx, cmd, args);
|
||||
} catch (const boost::process::system_error& e) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ExecuteCommand(const std::string& cmd,
|
||||
int ExecuteCommand(boost::asio::io_context& ctx, const std::string& cmd,
|
||||
const std::vector<std::string>& args) {
|
||||
std::string ignored;
|
||||
return ExecuteCommand(cmd, args, ignored);
|
||||
return ExecuteCommand(ctx, cmd, args, ignored);
|
||||
}
|
||||
|
||||
int ExecuteCommand(const std::string& cmd, std::string& result) {
|
||||
std::vector<std::string> ignored;
|
||||
return ExecuteCommand(cmd, ignored, result);
|
||||
}
|
||||
|
||||
int ExecuteCommand(const std::string& cmd, const std::vector<std::string>& args,
|
||||
int ExecuteCommand(boost::asio::io_context& ctx, const std::string& cmd,
|
||||
std::string& result) {
|
||||
boost::system::error_code ec;
|
||||
boost::asio::io_context ctx;
|
||||
boost::process::popen proc(
|
||||
ctx, cmd, args, boost::process::process_stdio{{}, nullptr, nullptr});
|
||||
std::vector<std::string> ignored;
|
||||
return ExecuteCommand(ctx, cmd, ignored, result);
|
||||
}
|
||||
|
||||
boost::asio::read(proc, boost::asio::dynamic_buffer(result), ec);
|
||||
int ExecuteCommand(boost::asio::io_context& ctx, const std::string& cmd,
|
||||
const std::vector<std::string>& args, std::string& result) {
|
||||
try {
|
||||
boost::system::error_code ec;
|
||||
boost::process::popen proc(
|
||||
ctx, cmd, args, boost::process::process_stdio{{}, nullptr, nullptr});
|
||||
|
||||
if (ec != boost::asio::error::eof) {
|
||||
boost::asio::read(proc, boost::asio::dynamic_buffer(result), ec);
|
||||
|
||||
proc.wait();
|
||||
|
||||
return proc.exit_code();
|
||||
} catch (const boost::process::system_error& e) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
proc.wait();
|
||||
|
||||
return proc.exit_code();
|
||||
}
|
||||
|
||||
boost::process::popen OpenPipe(const std::string& cmd,
|
||||
boost::process::popen OpenPipe(boost::asio::io_context& ctx,
|
||||
const std::string& cmd,
|
||||
const std::vector<std::string>& args) {
|
||||
boost::asio::io_context ctx;
|
||||
boost::process::popen proc(
|
||||
ctx, cmd, args, boost::process::process_stdio{{}, nullptr, nullptr});
|
||||
return proc;
|
||||
return boost::process::popen(
|
||||
ctx, cmd, args, boost::process::process_stdio{nullptr, nullptr, nullptr});
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
@@ -55,8 +55,18 @@ void DownloadFileFromHTTPS(std::string url, std::string filename) {
|
||||
boost::beast::http::write(stream, req);
|
||||
|
||||
boost::beast::flat_buffer buffer;
|
||||
boost::beast::http::response<boost::beast::http::dynamic_body> res;
|
||||
boost::beast::http::read(stream, buffer, res);
|
||||
|
||||
// 응답 파서 만들기
|
||||
boost::beast::http::response_parser<boost::beast::http::dynamic_body>
|
||||
parser;
|
||||
|
||||
// body 제한 해제 (무제한)
|
||||
parser.body_limit((std::numeric_limits<std::uint64_t>::max)());
|
||||
|
||||
// 응답 읽기
|
||||
boost::beast::http::read(stream, buffer, parser);
|
||||
|
||||
auto res = parser.release();
|
||||
|
||||
int status = res.result_int();
|
||||
if (status / 100 == 3) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace utils {
|
||||
|
||||
int InstallYtdlp() {
|
||||
int InstallYtdlp(boost::asio::io_context& ctx) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "ytdlp is unavailable. downloading ytdlp...";
|
||||
#ifdef WIN32
|
||||
DownloadFileFromHTTPS(
|
||||
@@ -16,34 +16,54 @@ int InstallYtdlp() {
|
||||
DownloadFileFromHTTPS(
|
||||
"https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp",
|
||||
"yt-dlp");
|
||||
ExecuteCommand(boost::process::environment::find_executable("chmod").c_str(),
|
||||
ExecuteCommand(ctx,
|
||||
boost::process::environment::find_executable("chmod").string(),
|
||||
{"+x", "yt-dlp"});
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CheckUpdate() {
|
||||
char buf[16384];
|
||||
|
||||
if (ValidateCommand("yt-dlp") != 0) {
|
||||
InstallYtdlp();
|
||||
return 0;
|
||||
static int FindNewLinePos(std::string& string, int start_pos) {
|
||||
int newline_pos = start_pos;
|
||||
while (newline_pos < string.size()) {
|
||||
if (string[newline_pos] == '\n') {
|
||||
return newline_pos;
|
||||
}
|
||||
newline_pos++;
|
||||
}
|
||||
return newline_pos;
|
||||
}
|
||||
|
||||
auto ytdlp_pipe = utils::OpenPipe("yt-dlp", {"-U"});
|
||||
int CheckUpdate(boost::asio::io_context& ctx) {
|
||||
std::string output = "";
|
||||
int old_newline_pos = 0;
|
||||
int newline_pos = 0;
|
||||
|
||||
while (true) {
|
||||
boost::system::error_code read_ec;
|
||||
size_t bytes_read =
|
||||
boost::asio::read(ytdlp_pipe, boost::asio::buffer(buf, 16384), read_ec);
|
||||
|
||||
if (bytes_read > 0) {
|
||||
BOOST_LOG_TRIVIAL(info) << buf;
|
||||
}
|
||||
|
||||
if (read_ec == boost::asio::error::eof || read_ec) {
|
||||
break;
|
||||
}
|
||||
#ifdef WIN32
|
||||
if (ExecuteCommand(ctx, "yt-dlp.exe", {"--version", "--newline"}, output) !=
|
||||
0) {
|
||||
InstallYtdlp(ctx);
|
||||
ExecuteCommand(ctx, "yt-dlp.exe", {"--version", "--newline"}, output);
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << "yt-dlp version: "
|
||||
<< output.substr(0, output.size() - 1);
|
||||
output = "";
|
||||
ExecuteCommand(ctx, "yt-dlp.exe", {"-U", "--newline"}, output);
|
||||
#else
|
||||
if (ExecuteCommand(ctx, "yt-dlp", {"--version", "--newline"}, output) != 0) {
|
||||
InstallYtdlp(ctx);
|
||||
ExecuteCommand(ctx, "yt-dlp", {"--version", "--newline"}, output);
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << "yt-dlp version: "
|
||||
<< output.substr(0, output.size() - 1);
|
||||
output = "";
|
||||
ExecuteCommand(ctx, "yt-dlp", {"-U", "--newline"}, output);
|
||||
#endif
|
||||
while (newline_pos < output.size()) {
|
||||
old_newline_pos = newline_pos;
|
||||
newline_pos = FindNewLinePos(output, newline_pos);
|
||||
BOOST_LOG_TRIVIAL(info) << output.substr(old_newline_pos, newline_pos - 1);
|
||||
newline_pos++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
8
tests/CMakeLists.txt
Normal file
8
tests/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
file(GLOB_RECURSE TEST_SOURCES "*.cpp" "*.cxx" "*.cc")
|
||||
|
||||
foreach(test_src ${TEST_SOURCES})
|
||||
get_filename_component(test_name ${test_src} NAME_WE)
|
||||
add_executable(${test_name} ${test_src})
|
||||
target_link_libraries(${test_name} PRIVATE ${BOT_NAME}_lib)
|
||||
add_test(NAME ${test_name} COMMAND ${test_name})
|
||||
endforeach()
|
||||
52
tests/basic_yt_dlp_download.cc
Normal file
52
tests/basic_yt_dlp_download.cc
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "precomp.h"
|
||||
#include "utils/console.h"
|
||||
#include "utils/update_checker.h"
|
||||
|
||||
int main() {
|
||||
boost::asio::io_context ctx;
|
||||
boost::system::error_code ec;
|
||||
|
||||
// utils::CheckUpdate(ctx);
|
||||
|
||||
char buf[8192];
|
||||
#ifdef WIN32
|
||||
/*try {
|
||||
auto ytdlp_pipe = utils::OpenPipe(ctx,
|
||||
"yt-dlp.exe", { "-o", "-", "--quiet", "--ignore-errors", "-f",
|
||||
"bestaudio", "https://youtu.be/9_bTl2vvYQg?si=IVhvpDhnpPvziwQR" });
|
||||
|
||||
while (true) {
|
||||
boost::system::error_code read_ec;
|
||||
size_t bytes_read =
|
||||
boost::asio::read(ytdlp_pipe, boost::asio::buffer(buf,
|
||||
8192), read_ec); if (bytes_read > 0) { std::cout.write(buf, bytes_read);
|
||||
}
|
||||
if (read_ec == boost::asio::error::eof || read_ec) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const boost::process::system_error& e) {
|
||||
std::string error = e.what();
|
||||
return -1;
|
||||
}*/
|
||||
#else
|
||||
auto ytdlp_pipe = utils::OpenPipe(
|
||||
ctx, "yt-dlp",
|
||||
{"-o", "-", "--quiet", "--ignore-errors", "-f", "bestaudio",
|
||||
"https://youtu.be/9_bTl2vvYQg?si=IVhvpDhnpPvziwQR"});
|
||||
|
||||
while (true) {
|
||||
boost::system::error_code read_ec;
|
||||
size_t bytes_read =
|
||||
boost::asio::read(ytdlp_pipe, boost::asio::buffer(buf, 8192), read_ec);
|
||||
if (bytes_read > 0) {
|
||||
std::cout.write(buf, bytes_read);
|
||||
}
|
||||
if (read_ec == boost::asio::error::eof || read_ec) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
232
tests/ffmpeg_any_to_opus.cc
Normal file
232
tests/ffmpeg_any_to_opus.cc
Normal 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;
|
||||
}
|
||||
155
tests/ffmpeg_decode_audio.cc
Normal file
155
tests/ffmpeg_decode_audio.cc
Normal 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;
|
||||
}
|
||||
8
tests/update.cc
Normal file
8
tests/update.cc
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "precomp.h"
|
||||
#include "utils/update_checker.h"
|
||||
|
||||
int main() {
|
||||
boost::asio::io_context ctx;
|
||||
utils::CheckUpdate(ctx);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user