From cca1d056c9724b373a75d169909761f1cf8fe51d Mon Sep 17 00:00:00 2001 From: luocai Date: Thu, 18 Jan 2024 22:22:26 +0800 Subject: [PATCH] first commit --- .clang-format | 17 ++ AudioDecoder.cpp | 10 ++ AudioDecoder.h | 14 ++ CMakeLists.txt | 64 +++++++ CMakeLists.txt.user | 419 ++++++++++++++++++++++++++++++++++++++++++++ Demuxer.cpp | 66 +++++++ Demuxer.h | 42 +++++ VideoDecoder.cpp | 60 +++++++ VideoDecoder.h | 29 +++ WebRTCPublisher.cpp | 60 +++++++ WebRTCPublisher.h | 18 ++ main.cpp | 35 ++++ 12 files changed, 834 insertions(+) create mode 100644 .clang-format create mode 100644 AudioDecoder.cpp create mode 100644 AudioDecoder.h create mode 100644 CMakeLists.txt create mode 100644 CMakeLists.txt.user create mode 100644 Demuxer.cpp create mode 100644 Demuxer.h create mode 100644 VideoDecoder.cpp create mode 100644 VideoDecoder.h create mode 100644 WebRTCPublisher.cpp create mode 100644 WebRTCPublisher.h create mode 100644 main.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..f3960e2 --- /dev/null +++ b/.clang-format @@ -0,0 +1,17 @@ +BasedOnStyle: LLVM + +ObjCBlockIndentWidth: 4 +IndentWidth: 4 +TabWidth: 4 +AccessModifierOffset: -4 +ColumnLimit: 120 + +#模板声明后换行 +AlwaysBreakTemplateDeclarations: true + +# 是否允许短if单行 If true, if (a) return; 可以放到同一行 +AllowShortIfStatementsOnASingleLine: true + +#短句 while (true) continue; 能被放到单行。 +AllowShortLoopsOnASingleLine: true +AllowShortFunctionsOnASingleLine: false \ No newline at end of file diff --git a/AudioDecoder.cpp b/AudioDecoder.cpp new file mode 100644 index 0000000..e5deca2 --- /dev/null +++ b/AudioDecoder.cpp @@ -0,0 +1,10 @@ +#include "AudioDecoder.h" +extern "C" { +#include "libavcodec/avcodec.h" +} + +AudioDecoder::AudioDecoder(const AVCodec *codec) { +} + +void AudioDecoder::push(const std::shared_ptr &packet) { +} diff --git a/AudioDecoder.h b/AudioDecoder.h new file mode 100644 index 0000000..7119df9 --- /dev/null +++ b/AudioDecoder.h @@ -0,0 +1,14 @@ +#ifndef __AUDIODECODER_H__ +#define __AUDIODECODER_H__ + +#include + +struct AVCodec; +struct AVPacket; + +class AudioDecoder { +public: + AudioDecoder(const AVCodec *codec); + void push(const std::shared_ptr &packet); +}; +#endif // __AUDIODECODER_H__ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..11c7003 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,64 @@ +cmake_minimum_required(VERSION 3.27) + +project(FFmpegPlayer) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(Projects_ROOT E:/Projects) +set(Libraries_ROOT ${Projects_ROOT}/Libraries) + +set(BOOST_ROOT ${Libraries_ROOT}/boost_1_84_0_msvc2022_64bit) +set(Boost_INCLUDE_DIR ${BOOST_ROOT}/include/boost-1_84) +option(Boost_USE_STATIC_LIBS OFF) +add_compile_definitions( + BOOST_USE_WINAPI_VERSION=BOOST_WINAPI_VERSION_WIN10 +) + +find_package(Boost REQUIRED COMPONENTS json) + +set(OpenSSL_ROOT D:/Qt/Tools/OpenSSLv3/Win_x64) +set(OPENSSL_INCLUDE_DIR ${OpenSSL_ROOT}/include) +set(OpenSSL_LIBRARY_DIRS ${OpenSSL_ROOT}/lib) +set(OpenSSL_LIBRARIES libssl libcrypto) + + +set(FFMPEG_ROOT ${Libraries_ROOT}/ffmpeg-6.0-full_build-shared) +set(FFMPEG_INCLUDE_DIR ${FFMPEG_ROOT}/include) +set(FFMPEG_LIBRARY_DIRS ${FFMPEG_ROOT}/lib) +set(FFMPEG_LIBRARIES avcodec avformat avutil) + +find_package(Qt6 REQUIRED COMPONENTS Widgets) +qt_standard_project_setup() + + +set(LibDataChannel_DIR E:/Projects/Libraries/libdatachannel-0.19.5_msvc2022_64bit_debug/lib/cmake/LibDataChannel) +find_package(LibDataChannel) + +add_subdirectory(E:/Projects/Kylin/Universal Universal) +add_subdirectory(E:/Projects/Kylin/HttpProxy HttpProxy) + +add_executable(FFmpegPlayer main.cpp + Demuxer.h Demuxer.cpp + AudioDecoder.h AudioDecoder.cpp + VideoDecoder.h VideoDecoder.cpp + WebRTCPublisher.h WebRTCPublisher.cpp +) + +target_include_directories(FFmpegPlayer + PRIVATE ${FFMPEG_INCLUDE_DIR} +) + +target_link_directories(FFmpegPlayer + PRIVATE ${FFMPEG_LIBRARY_DIRS} + PRIVATE ${OpenSSL_LIBRARY_DIRS} +) + +target_link_libraries(FFmpegPlayer + PRIVATE Qt6::Widgets + PRIVATE Universal + PRIVATE HttpProxy + PRIVATE ${FFMPEG_LIBRARIES} + PRIVATE ${OpenSSL_LIBRARIES} + PRIVATE LibDataChannel::LibDataChannel +) diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user new file mode 100644 index 0000000..fc7ae3b --- /dev/null +++ b/CMakeLists.txt.user @@ -0,0 +1,419 @@ + + + + + + EnvironmentId + {11f4a1e9-12b5-4bf9-bf26-e33024189f36} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + 0 + false + true + false + 0 + true + true + 0 + 8 + true + false + 0 + true + true + true + *.md, *.MD, Makefile + false + true + true + + + + ProjectExplorer.Project.PluginSettings + + + true + false + true + true + true + true + + + 0 + true + + true + true + Builtin.DefaultTidyAndClazy + 3 + true + + + + true + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop Qt 6.6.1 MSVC2019 64bit + Desktop Qt 6.6.1 MSVC2019 64bit + qt.qt6.661.win64_msvc2019_64_kit + 0 + 0 + 0 + + Debug + 2 + false + + -DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_BUILD_TYPE:STRING=Debug +-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} + 0 + E:\Projects\FFmpegPlayer-Desktop_Qt_6_6_1_MSVC2019_64bit-Debug + + + + + all + + false + + true + 构建 + CMakeProjectManager.MakeStep + + 1 + 构建 + 构建 + ProjectExplorer.BuildSteps.Build + + + + + + clean + + false + + true + 构建 + CMakeProjectManager.MakeStep + + 1 + 清除 + 清除 + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Debug + CMakeProjectManager.CMakeBuildConfiguration + + + Release + 2 + false + + -DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_BUILD_TYPE:STRING=Release +-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} + E:\Projects\FFmpegPlayer-Desktop_Qt_6_6_1_MSVC2019_64bit-Release + + + + + all + + false + + true + CMakeProjectManager.MakeStep + + 1 + 构建 + 构建 + ProjectExplorer.BuildSteps.Build + + + + + + clean + + false + + true + CMakeProjectManager.MakeStep + + 1 + 清除 + 清除 + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Release + CMakeProjectManager.CMakeBuildConfiguration + + + RelWithDebInfo + 2 + false + + -DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo +-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} + E:\Projects\FFmpegPlayer-Desktop_Qt_6_6_1_MSVC2019_64bit-RelWithDebInfo + + + + + all + + false + + true + CMakeProjectManager.MakeStep + + 1 + 构建 + 构建 + ProjectExplorer.BuildSteps.Build + + + + + + clean + + false + + true + CMakeProjectManager.MakeStep + + 1 + 清除 + 清除 + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Release with Debug Information + CMakeProjectManager.CMakeBuildConfiguration + + + RelWithDebInfo + 2 + false + + -DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo +-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} + 0 + E:\Projects\FFmpegPlayer-Desktop_Qt_6_6_1_MSVC2019_64bit-Profile + + + + + all + + false + + true + CMakeProjectManager.MakeStep + + 1 + 构建 + 构建 + ProjectExplorer.BuildSteps.Build + + + + + + clean + + false + + true + CMakeProjectManager.MakeStep + + 1 + 清除 + 清除 + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Profile + CMakeProjectManager.CMakeBuildConfiguration + + + MinSizeRel + 2 + false + + -DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_BUILD_TYPE:STRING=MinSizeRel +-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} + E:\Projects\FFmpegPlayer-Desktop_Qt_6_6_1_MSVC2019_64bit-MinSizeRel + + + + + all + + false + + true + CMakeProjectManager.MakeStep + + 1 + 构建 + 构建 + ProjectExplorer.BuildSteps.Build + + + + + + clean + + false + + true + CMakeProjectManager.MakeStep + + 1 + 清除 + 清除 + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Minimum Size Release + CMakeProjectManager.CMakeBuildConfiguration + + 5 + + + 0 + 部署 + 部署 + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + true + true + 0 + true + + 2 + + false + FFmpegPlayer + CMakeProjectManager.CMakeRunConfiguration.FFmpegPlayer + FFmpegPlayer + false + true + true + true + E:/Projects/FFmpegPlayer-Desktop_Qt_6_6_1_MSVC2019_64bit-Debug + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + diff --git a/Demuxer.cpp b/Demuxer.cpp new file mode 100644 index 0000000..826639b --- /dev/null +++ b/Demuxer.cpp @@ -0,0 +1,66 @@ +#include "Demuxer.h" +#include "BoostLog.h" +extern "C" { +#include "libavformat/avformat.h" +} + +static_assert(AVMEDIA_TYPE_VIDEO == Stream::Video, "enum value must same..."); + +Demuxer::Demuxer() { + m_context = avformat_alloc_context(); +} + +Demuxer::~Demuxer() { + m_exit = true; + if (m_thread.joinable()) m_thread.join(); +} + +void Demuxer::open(const std::string &path) { + avformat_open_input(&m_context, path.c_str(), nullptr, nullptr); + av_dump_format(m_context, 0, path.c_str(), 0); + const AVCodec *videoCodec = nullptr, *audioCodec = nullptr; + m_streams[Stream::Video] = av_find_best_stream(m_context, AVMEDIA_TYPE_VIDEO, -1, -1, &videoCodec, 0); + m_streams[Stream::Audio] = av_find_best_stream(m_context, AVMEDIA_TYPE_AUDIO, -1, -1, &audioCodec, 0); + LOG(info) << "video stream index: " << m_streams[Stream::Video] + << ", audio stream index: " << m_streams[Stream::Audio]; + + m_codecInformations[Stream::Video] = {videoCodec, m_context->streams[Stream::Video]->codecpar}; + m_codecInformations[Stream::Audio] = + std::pair(audioCodec, m_context->streams[Stream::Audio]->codecpar); +} + +Demuxer::CodecInformation Demuxer::codecInformation(Stream type) const { + return m_codecInformations[type]; +} + +void Demuxer::setStreamPacketCallback(Stream type, const Callback &callback) { + m_callback[type] = callback; +} + +void Demuxer::start() { + m_exit = false; + m_thread = std::thread(&Demuxer::run, this); +} + +void Demuxer::run() { + auto packet = av_packet_alloc(); + while (!m_exit) { + int ret = av_read_frame(m_context, packet); + if (ret == AVERROR_EOF) { + LOG(info) << "end of file."; + break; + } else if (ret < 0) { + char buffer[AV_ERROR_MAX_STRING_SIZE] = {0}; + av_strerror(ret, buffer, sizeof(buffer)); + LOG(error) << "read failed: " << ret << ", " << buffer; + break; + } + + std::shared_ptr out(av_packet_alloc(), [](AVPacket *packet) { av_packet_free(&packet); }); + av_packet_ref(out.get(), packet); + if (m_callback[packet->stream_index]) m_callback[packet->stream_index](out); + // LOG(info) << ". " << packet->stream_index; + av_packet_unref(packet); + } + av_packet_free(&packet); +} diff --git a/Demuxer.h b/Demuxer.h new file mode 100644 index 0000000..a92fa36 --- /dev/null +++ b/Demuxer.h @@ -0,0 +1,42 @@ +#ifndef __DEMUXER_H__ +#define __DEMUXER_H__ + +#include +#include +#include + +struct AVFormatContext; +struct AVCodec; +struct AVCodecParameters; +struct AVPacket; + +enum Stream : uint32_t { + Video, + Audio, + Size, +}; + +class Demuxer { +public: + using CodecInformation = std::pair; + using Callback = std::function &)>; + Demuxer(); + ~Demuxer(); + void open(const std::string &path); + CodecInformation codecInformation(Stream type) const; + void setStreamPacketCallback(Stream type, const Callback &callback); + void start(); + +protected: + void run(); + +private: + bool m_exit; + std::thread m_thread; + AVFormatContext *m_context; + int m_streams[Stream::Size]; + CodecInformation m_codecInformations[Stream::Size]; + Callback m_callback[Stream::Size]; +}; + +#endif // __DEMUXER_H__ \ No newline at end of file diff --git a/VideoDecoder.cpp b/VideoDecoder.cpp new file mode 100644 index 0000000..5233b6a --- /dev/null +++ b/VideoDecoder.cpp @@ -0,0 +1,60 @@ +#include "VideoDecoder.h" +#include "BoostLog.h" +extern "C" { +#include "libavcodec/avcodec.h" +} + +VideoDecoder::VideoDecoder(const AVCodec *codec, const AVCodecParameters *parameters) { + m_context = avcodec_alloc_context3(codec); + avcodec_parameters_to_context(m_context, parameters); + avcodec_open2(m_context, codec, nullptr); +} + +void VideoDecoder::start() { + m_exit = false; + m_thread = std::thread(&VideoDecoder::run, this); +} + +void VideoDecoder::push(const std::shared_ptr &packet) { + std::lock_guard locker(m_mutex); + LOG(info) << "dts: " << packet->dts << ", pts: " << packet->pts; + m_packets.push(packet); +} + +void VideoDecoder::run() { + using namespace std::chrono_literals; + auto frame = av_frame_alloc(); + while (!m_exit) { + m_mutex.lock(); + if (m_packets.empty()) { + m_mutex.unlock(); + std::this_thread::sleep_for(5ms); + continue; + } + auto packet = m_packets.front(); + m_packets.pop(); + m_mutex.unlock(); + + auto ret = avcodec_send_packet(m_context, packet.get()); + if (ret < 0) { + char buffer[AV_ERROR_MAX_STRING_SIZE] = {0}; + av_strerror(ret, buffer, sizeof(buffer)); + LOG(error) << "read failed: " << ret << ", " << buffer; + } + while (true) { + ret = avcodec_receive_frame(m_context, frame); + if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) { + break; + } else if (ret < 0) { + char buffer[AV_ERROR_MAX_STRING_SIZE] = {0}; + av_strerror(ret, buffer, sizeof(buffer)); + LOG(error) << "read failed: " << ret << ", " << buffer; + break; + } + LOG(info) << "width: " << frame->width << ", height: " << frame->height << ", pts: " << frame->pts + << ", pkt_dts:" << frame->pkt_dts; + av_frame_unref(frame); + } + } + av_frame_free(&frame); +} diff --git a/VideoDecoder.h b/VideoDecoder.h new file mode 100644 index 0000000..fffe6c1 --- /dev/null +++ b/VideoDecoder.h @@ -0,0 +1,29 @@ +#ifndef __VIDEODECODER_H__ +#define __VIDEODECODER_H__ + +#include +#include +#include + +struct AVPacket; +struct AVCodec; +struct AVCodecContext; +struct AVCodecParameters; + +class VideoDecoder { +public: + VideoDecoder(const AVCodec *codec, const AVCodecParameters *parameters); + void start(); + void push(const std::shared_ptr &packet); + +protected: + void run(); + +private: + bool m_exit; + std::thread m_thread; + AVCodecContext *m_context; + std::mutex m_mutex; + std::queue> m_packets; +}; +#endif // __VIDEODECODER_H__ \ No newline at end of file diff --git a/WebRTCPublisher.cpp b/WebRTCPublisher.cpp new file mode 100644 index 0000000..461b9e2 --- /dev/null +++ b/WebRTCPublisher.cpp @@ -0,0 +1,60 @@ +#include "WebRTCPublisher.h" +#include "BoostLog.h" +#include "NetworkUtility.h" +#include +#include + +WebRTCPublisher::WebRTCPublisher(boost::asio::io_context &ioContext) : m_ioContext(ioContext) { + + m_configuration.iceServers.emplace_back("mystunserver.org:3478"); + m_peer = std::make_shared(m_configuration); + + m_peer->onLocalDescription([&, this](rtc::Description sdp) { + LOG(info) << "Send the SDP to the remote peer: " << std::string(sdp); + const auto serverIp = "172.16.7.16"; + const auto serverPort = "443"; + const auto streamUrl = "/live/livestream"; + std::ostringstream oss; + oss << "https://" << serverIp << ":" << serverPort << "/rtc/v1/publish/"; + + boost::json::object requestJson; + requestJson["api"] = oss.str(); + requestJson["streamurl"] = streamUrl; + requestJson["sdp"] = std::string(sdp); + auto request = boost::json::serialize(requestJson); + LOG(info) << "body: " << request; + boost::system::error_code error; + Http::Client https(m_ioContext, Http::SSL); + https.loadRootCertificates(error); + auto reply = https.post(serverIp, serverPort, "/rtc/v1/publish/", request, error); + LOG(info) << "reply " << reply; + + // Send the SDP to the remote peer + // MY_SEND_DESCRIPTION_TO_REMOTE(std::string(sdp)); + }); + + m_peer->onLocalCandidate([](rtc::Candidate candidate) { + // Send the candidate to the remote peer + // MY_SEND_CANDIDATE_TO_REMOTE(candidate.candidate(), candidate.mid()); + }); + + // MY_ON_RECV_DESCRIPTION_FROM_REMOTE([&pc](std::string sdp) { pc.setRemoteDescription(rtc::Description(sdp)); }); + + // MY_ON_RECV_CANDIDATE_FROM_REMOTE( + // [&pc](std::string candidate, std::string mid) { pc.addRemoteCandidate(rtc::Candidate(candidate, mid)); }); + + m_peer->onStateChange([](rtc::PeerConnection::State state) { LOG(info) << "State: " << (int)state; }); + + m_peer->onGatheringStateChange( + [](rtc::PeerConnection::GatheringState state) { LOG(info) << "Gathering state: " << (int)state; }); + + m_dataChannel = m_peer->createDataChannel("test"); + + m_dataChannel->onOpen([]() { LOG(info) << "Open" << std::endl; }); + + m_dataChannel->onMessage([](std::variant message) { + if (std::holds_alternative(message)) { + LOG(info) << "Received: " << get(message) << std::endl; + } + }); +} diff --git a/WebRTCPublisher.h b/WebRTCPublisher.h new file mode 100644 index 0000000..6c7515d --- /dev/null +++ b/WebRTCPublisher.h @@ -0,0 +1,18 @@ +#ifndef WEBRTCPUBLISHER_H +#define WEBRTCPUBLISHER_H + +#include "rtc/rtc.hpp" +#include + +class WebRTCPublisher { +public: + WebRTCPublisher(boost::asio::io_context &ioContext); + +private: + boost::asio::io_context &m_ioContext; + rtc::Configuration m_configuration; + std::shared_ptr m_peer; + std::shared_ptr m_dataChannel; +}; + +#endif // WEBRTCPUBLISHER_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..69ff317 --- /dev/null +++ b/main.cpp @@ -0,0 +1,35 @@ +#include "AudioDecoder.h" +#include "Demuxer.h" +#include "IoContext.h" +#include "VideoDecoder.h" +#include "WebRTCPublisher.h" +#include +#include +#include + +int main(int argc, char *argv[]) { + QApplication app(argc, argv); + auto ioContext = Amass::Singleton::instance(); + std::cout << "hello world." << std::endl; + constexpr auto path = "E:/Documents/juren-30s.mp4"; + Demuxer demuxer; + demuxer.open(path); + + // auto [audioCodec, audioCodecParameter] = demuxer.codecInformation(Stream::Audio); + // auto [videoCodec, videoCodecParameter] = demuxer.codecInformation(Stream::Video); + // VideoDecoder videoDecoder(videoCodec, videoCodecParameter); + // // AudioDecoder audioDecoder(audioCodec, audioCodecParameter); + + // demuxer.setStreamPacketCallback( + // Stream::Video, [&videoDecoder](const std::shared_ptr &packet) { videoDecoder.push(packet); }); + // // demuxer.setStreamPacketCallback(Stream::Audio, + // // std::bind(&AudioDecoder::push, &audioDecoder, std::placeholders::_1)); + // demuxer.start(); + // videoDecoder.start(); + + QWidget w; + // w.show(); + WebRTCPublisher rtc(*ioContext->ioContext()); + ioContext->run(); + return app.exec(); +}