add toxav incoming video (sdl video)

This commit is contained in:
Green Sky 2024-10-02 11:28:36 +02:00
parent b5d0d16d31
commit 51ec99a42f
No known key found for this signature in database
2 changed files with 133 additions and 7 deletions

View File

@ -9,8 +9,17 @@
#include "./frame_streams/multi_source.hpp" #include "./frame_streams/multi_source.hpp"
#include "./frame_streams/audio_stream_pop_reframer.hpp" #include "./frame_streams/audio_stream_pop_reframer.hpp"
#include "./frame_streams/sdl/video.hpp"
#include <cstring>
#include <iostream> #include <iostream>
// fwd
namespace Message {
uint64_t getTimeMS(void);
} // Message
namespace Components { namespace Components {
struct ToxAVIncomingAV { struct ToxAVIncomingAV {
bool incoming_audio {false}; bool incoming_audio {false};
@ -21,12 +30,15 @@ namespace Components {
ObjectHandle o; ObjectHandle o;
// ptr? // ptr?
}; };
// vid struct ToxAVVideoSink {
ObjectHandle o;
};
struct ToxAVAudioSource { struct ToxAVAudioSource {
ObjectHandle o; ObjectHandle o;
// ptr?
}; };
// vid struct ToxAVVideoSource {
ObjectHandle o;
};
} // Components } // Components
struct ToxAVCallAudioSink : public FrameStream2SinkI<AudioFrame2> { struct ToxAVCallAudioSink : public FrameStream2SinkI<AudioFrame2> {
@ -94,13 +106,11 @@ void ToxAVVoIPModel::addAudioSource(ObjectHandle session, uint32_t friend_number
incoming_audio.emplace<Components::FrameStream2Source<AudioFrame2>>(std::move(new_asrc)); incoming_audio.emplace<Components::FrameStream2Source<AudioFrame2>>(std::move(new_asrc));
incoming_audio.emplace<Components::StreamSource>(Components::StreamSource::create<AudioFrame2>("ToxAV Friend Call Incoming Audio")); incoming_audio.emplace<Components::StreamSource>(Components::StreamSource::create<AudioFrame2>("ToxAV Friend Call Incoming Audio"));
std::cout << "new incoming audio\n";
if ( if (
const auto* defaults = session.try_get<Components::VoIP::DefaultConfig>(); const auto* defaults = session.try_get<Components::VoIP::DefaultConfig>();
defaults != nullptr && defaults->incoming_audio defaults != nullptr && defaults->incoming_audio
) { ) {
incoming_audio.emplace<Components::TagConnectToDefault>(); // depends on what was specified in enter() incoming_audio.emplace<Components::TagConnectToDefault>(); // depends on what was specified in enter()
std::cout << "with default\n";
} }
stream_source.push_back(incoming_audio); stream_source.push_back(incoming_audio);
@ -135,6 +145,35 @@ void ToxAVVoIPModel::addAudioSink(ObjectHandle session, uint32_t friend_number)
_os.throwEventConstruct(outgoing_audio); _os.throwEventConstruct(outgoing_audio);
} }
void ToxAVVoIPModel::addVideoSource(ObjectHandle session, uint32_t friend_number) {
auto& stream_source = session.get_or_emplace<Components::VoIP::StreamSources>().streams;
ObjectHandle incoming_video {_os.registry(), _os.registry().create()};
auto new_vsrc = std::make_unique<FrameStream2MultiSource<SDLVideoFrame>>();
incoming_video.emplace<FrameStream2MultiSource<SDLVideoFrame>*>(new_vsrc.get());
incoming_video.emplace<Components::FrameStream2Source<SDLVideoFrame>>(std::move(new_vsrc));
incoming_video.emplace<Components::StreamSource>(Components::StreamSource::create<SDLVideoFrame>("ToxAV Friend Call Incoming Video"));
if (
const auto* defaults = session.try_get<Components::VoIP::DefaultConfig>();
defaults != nullptr && defaults->incoming_audio
) {
incoming_video.emplace<Components::TagConnectToDefault>(); // depends on what was specified in enter()
}
stream_source.push_back(incoming_video);
session.emplace<Components::ToxAVVideoSource>(incoming_video);
// TODO: tie session to stream
_video_sources[friend_number] = incoming_video;
_os.throwEventConstruct(incoming_video);
}
void ToxAVVoIPModel::addVideoSink(ObjectHandle session, uint32_t friend_number) {
}
void ToxAVVoIPModel::destroySession(ObjectHandle session) { void ToxAVVoIPModel::destroySession(ObjectHandle session) {
if (!static_cast<bool>(session)) { if (!static_cast<bool>(session)) {
return; return;
@ -153,6 +192,18 @@ void ToxAVVoIPModel::destroySession(ObjectHandle session) {
_audio_sources.erase(it_asrc); _audio_sources.erase(it_asrc);
} }
} }
if (session.all_of<Components::ToxAVVideoSource>()) {
auto it_vsrc = std::find_if(
_video_sources.cbegin(), _video_sources.cend(),
[o = session.get<Components::ToxAVVideoSource>().o](const auto& it) {
return it.second == o;
}
);
if (it_vsrc != _video_sources.cend()) {
_video_sources.erase(it_vsrc);
}
}
// destory sources // destory sources
if (auto* ss = session.try_get<Components::VoIP::StreamSources>(); ss != nullptr) { if (auto* ss = session.try_get<Components::VoIP::StreamSources>(); ss != nullptr) {
@ -311,6 +362,8 @@ bool ToxAVVoIPModel::accept(ObjectHandle session, const Components::VoIP::Defaul
// bitrate cb or what? // bitrate cb or what?
assert(!session.all_of<Components::ToxAVAudioSink>()); assert(!session.all_of<Components::ToxAVAudioSink>());
addAudioSink(session, friend_number); addAudioSink(session, friend_number);
assert(!session.all_of<Components::ToxAVVideoSink>());
addVideoSink(session, friend_number);
if (const auto* i_av = session.try_get<Components::ToxAVIncomingAV>(); i_av != nullptr) { if (const auto* i_av = session.try_get<Components::ToxAVIncomingAV>(); i_av != nullptr) {
// create audio src // create audio src
@ -321,6 +374,8 @@ bool ToxAVVoIPModel::accept(ObjectHandle session, const Components::VoIP::Defaul
// create video src // create video src
if (i_av->incoming_video) { if (i_av->incoming_video) {
assert(!session.all_of<Components::ToxAVVideoSource>());
addVideoSource(session, friend_number);
} }
} }
@ -419,6 +474,11 @@ bool ToxAVVoIPModel::onEvent(const Events::FriendCallState& e) {
} }
// video // video
if (s.is_accepting_v() && !o.all_of<Components::ToxAVVideoSink>()) {
addVideoSink(o, e.friend_number);
} else if (!s.is_accepting_v() && o.all_of<Components::ToxAVVideoSink>()) {
// remove vsink?
}
// add/update sources // add/update sources
// audio // audio
@ -429,6 +489,11 @@ bool ToxAVVoIPModel::onEvent(const Events::FriendCallState& e) {
} }
// video // video
if (s.is_sending_v() && !o.all_of<Components::ToxAVVideoSource>()) {
addVideoSource(o, e.friend_number);
} else if (!s.is_sending_v() && o.all_of<Components::ToxAVVideoSource>()) {
// remove vsrc?
}
} }
} }
} }
@ -470,7 +535,66 @@ bool ToxAVVoIPModel::onEvent(const Events::FriendAudioFrame& e) {
return true; return true;
} }
bool ToxAVVoIPModel::onEvent(const Events::FriendVideoFrame&) { bool ToxAVVoIPModel::onEvent(const Events::FriendVideoFrame& e) {
auto vsrc_it = _video_sources.find(e.friend_number);
if (vsrc_it == _video_sources.cend()) {
// missing src from lookup table
return false;
}
auto vsrc = vsrc_it->second;
if (!static_cast<bool>(vsrc)) {
// missing src to put frame into ??
return false;
}
assert(vsrc.all_of<FrameStream2MultiSource<SDLVideoFrame>*>());
assert(vsrc.all_of<Components::FrameStream2Source<SDLVideoFrame>>());
auto* new_surf = SDL_CreateSurface(e.width, e.height, SDL_PIXELFORMAT_IYUV);
assert(new_surf);
if (SDL_LockSurface(new_surf)) {
// copy the data
// we know how the implementation works, its y u v consecutivlely
// y
for (size_t y = 0; y < e.height; y++) {
std::memcpy(
//static_cast<uint8_t*>(new_surf->pixels) + new_surf->pitch*y,
static_cast<uint8_t*>(new_surf->pixels) + e.width*y,
e.y.ptr + e.ystride*y,
e.width
);
}
// u
for (size_t y = 0; y < e.height/2; y++) {
std::memcpy(
static_cast<uint8_t*>(new_surf->pixels) + (e.width*e.height) + (e.width/2)*y,
e.u.ptr + e.ustride*y,
e.width/2
);
}
// v
for (size_t y = 0; y < e.height/2; y++) {
std::memcpy(
static_cast<uint8_t*>(new_surf->pixels) + (e.width*e.height) + ((e.width/2)*(e.height/2)) + (e.width/2)*y,
e.v.ptr + e.vstride*y,
e.width/2
);
}
SDL_UnlockSurface(new_surf);
}
vsrc.get<FrameStream2MultiSource<SDLVideoFrame>*>()->push({
// ms -> us
Message::getTimeMS() * 1000, // TODO: make more precise
new_surf
});
SDL_DestroySurface(new_surf);
return false; return false;
} }

View File

@ -16,11 +16,13 @@ class ToxAVVoIPModel : protected ToxAVEventI, public VoIPModelI {
// for faster lookup // for faster lookup
std::unordered_map<uint32_t, ObjectHandle> _audio_sources; std::unordered_map<uint32_t, ObjectHandle> _audio_sources;
std::unordered_map<uint32_t, ObjectHandle> _video_sources;
// TODO: virtual? strategy? protected? // TODO: virtual? strategy? protected?
virtual void addAudioSource(ObjectHandle session, uint32_t friend_number); virtual void addAudioSource(ObjectHandle session, uint32_t friend_number);
virtual void addAudioSink(ObjectHandle session, uint32_t friend_number); virtual void addAudioSink(ObjectHandle session, uint32_t friend_number);
// TODO: video virtual void addVideoSource(ObjectHandle session, uint32_t friend_number);
virtual void addVideoSink(ObjectHandle session, uint32_t friend_number);
void destroySession(ObjectHandle session); void destroySession(ObjectHandle session);