add toxav incoming video (sdl video)
This commit is contained in:
parent
b5d0d16d31
commit
51ec99a42f
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user