From 197d4899548957762cda8a55fe7f2564732312a5 Mon Sep 17 00:00:00 2001 From: cat Date: Sat, 27 Sep 2025 07:13:47 +0300 Subject: [PATCH] Added ChargeAudio and subsequently a half baked audio support Audio is almost ready(thank you miniaudio), there is a drift that needs to be solved and then we are golden. --- CMakeLists.txt | 1 + src/ChargeVideo.hpp | 26 ++++++++++++++++------- src/Video.cpp | 51 +++++++++++++++++++++++++++++++-------------- 3 files changed, 54 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7841be1..1c5cbf1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ target_link_libraries( PRIVATE Corrade::Main Magnum::GL Magnum::Magnum + ChargeAudio::ChargeAudio ${AVFORMAT_LIBRARIES} ${AVCODEC_LIBRARIES} ${AVUTIL_LIBRARIES} diff --git a/src/ChargeVideo.hpp b/src/ChargeVideo.hpp index 299b7b3..4c5c518 100644 --- a/src/ChargeVideo.hpp +++ b/src/ChargeVideo.hpp @@ -1,18 +1,21 @@ #ifndef CHARGE_VIDEO_BASE_H #define CHARGE_VIDEO_BASE_H -#include -#include -#include -#include -#include - #include #include #include #include #include +#include +#include +#include +#include +#include +#include + +#include + namespace ChargeVideo { namespace _ffmpeg { extern "C" { @@ -60,8 +63,8 @@ private: class Video { public: - Video(std::string path, bool ShouldVideoLoop = true, - float BufferSizeInSeconds = 1.0f); + Video(std::string path, ChargeAudio::Engine *audioEngine = nullptr, + bool ShouldVideoLoop = true, float BufferSizeInSeconds = 1.0f); ~Video(); // Manual Control @@ -99,6 +102,13 @@ private: uint32_t currentFrameNumber = 0; float timeSink = 0.0f, frameTime = 0.0f; + // Audio + ChargeAudio::Engine *audioEngine; + ChargeAudio::SoundContainer bufferedAudio; + + _ffmpeg::AVChannelLayout outLayout; + _ffmpeg::AVSampleFormat sampleFormat = _ffmpeg::AV_SAMPLE_FMT_FLT; + // Buffering std::queue frameBuffer; uint32_t bufferMaxFrames = 0; diff --git a/src/Video.cpp b/src/Video.cpp index ce8e316..5ac5eef 100644 --- a/src/Video.cpp +++ b/src/Video.cpp @@ -1,10 +1,17 @@ +#include + #include "ChargeVideo.hpp" +#include +#include #include #include #include #include +#include +#include +#include using namespace ChargeVideo; using namespace _ffmpeg; @@ -13,9 +20,10 @@ using namespace _ffmpeg; // ================== Video Construct/Destruct ================== // ShouldVideoLoop default is true -Video::Video(std::string path, bool ShouldVideoLoop, float BufferSizeInSeconds) +Video::Video(std::string path, ChargeAudio::Engine *engine, + bool ShouldVideoLoop, float BufferSizeInSeconds) : BufferLenghtInSeconds(BufferSizeInSeconds), - isVideoLooping(ShouldVideoLoop) { + isVideoLooping(ShouldVideoLoop), audioEngine(engine) { // Context to hold our data ctx = avformat_alloc_context(); if (!ctx) { @@ -63,7 +71,7 @@ Video::Video(std::string path, bool ShouldVideoLoop, float BufferSizeInSeconds) NULL); // open2 is such a stupid name // Some videos do not have audio streams - if (audioStreamNum != -1) { + if (audioStreamNum != -1 && audioEngine) { aCodec = avcodec_find_decoder(audioStream->codecpar->codec_id); aCodecCtx = avcodec_alloc_context3(aCodec); avcodec_parameters_to_context(aCodecCtx, audioStream->codecpar); @@ -72,11 +80,18 @@ Video::Video(std::string path, bool ShouldVideoLoop, float BufferSizeInSeconds) // Hoo boy I love bunch of different ways to do the same thing!!!!!! // Now we have to deal with all of the ways to do that thing!!!!! - AVChannelLayout outLayout = AV_CHANNEL_LAYOUT_STEREO; - swr_alloc_set_opts2(&swrCtx, &outLayout, AV_SAMPLE_FMT_S16, 44100, - &aCodecCtx->ch_layout, aCodecCtx->sample_fmt, - aCodecCtx->sample_rate, 0, NULL); + if (audioEngine->GetChannelCount() == 2) { + outLayout = AV_CHANNEL_LAYOUT_STEREO; + } else { + outLayout = AV_CHANNEL_LAYOUT_MONO; + } + swr_alloc_set_opts2(&swrCtx, &outLayout, sampleFormat, + audioEngine->GetSampleRate(), &aCodecCtx->ch_layout, + aCodecCtx->sample_fmt, aCodecCtx->sample_rate, 0, NULL); swr_init(swrCtx); + + // Creating buffered audio + bufferedAudio = audioEngine->CreateSound(10); } // Timing stuff @@ -155,6 +170,8 @@ void Video::continueVideo() { } loadTexture(frameBuffer.front()); + if (bufferedAudio->GetState() == ChargeAudio::Sound::SoundState::Idle) + bufferedAudio->Play(); frameBuffer.pop(); } @@ -167,20 +184,22 @@ Containers::Array Video::loadNextFrame() { // A hard stop if we are out of frames to read while (av_read_frame(ctx, packet) >= 0) { - if (static_cast(packet->stream_index) == audioStreamNum) { + if (audioEngine && + static_cast(packet->stream_index) == audioStreamNum) { avcodec_send_packet(aCodecCtx, packet); avcodec_receive_frame(aCodecCtx, audioFrame); - if (audioFrame->format != -1) { - convertedAudioFrame->format = AV_SAMPLE_FMT_S16; + if (audioFrame->format != -1 && audioEngine) { + convertedAudioFrame->format = sampleFormat; + convertedAudioFrame->sample_rate = audioEngine->GetSampleRate(); + convertedAudioFrame->ch_layout = outLayout; convertedAudioFrame->nb_samples = swr_get_out_samples(swrCtx, audioFrame->nb_samples); - convertedAudioFrame->ch_layout = AV_CHANNEL_LAYOUT_STEREO; - av_frame_get_buffer(convertedAudioFrame, - 2); // since it is LRLRLRLRLRLRLR + av_frame_get_buffer(convertedAudioFrame, 0); - swr_convert(swrCtx, convertedAudioFrame->data, - convertedAudioFrame->nb_samples, audioFrame->data, - audioFrame->nb_samples); + swr_convert_frame(swrCtx, convertedAudioFrame, audioFrame); + + bufferedAudio->WriteToRingBuffer(convertedAudioFrame->data[0], + convertedAudioFrame->linesize[0]); } }