forked from Green-Sky/tomato
sdl camera input source
This commit is contained in:
parent
54a57896b6
commit
2554229211
@ -117,6 +117,8 @@ target_sources(tomato PUBLIC
|
|||||||
./frame_streams/sdl/video.hpp
|
./frame_streams/sdl/video.hpp
|
||||||
./frame_streams/sdl/video_push_converter.hpp
|
./frame_streams/sdl/video_push_converter.hpp
|
||||||
./frame_streams/sdl/video_push_converter.cpp
|
./frame_streams/sdl/video_push_converter.cpp
|
||||||
|
./frame_streams/sdl/sdl_video_frame_stream2.hpp
|
||||||
|
./frame_streams/sdl/sdl_video_frame_stream2.cpp
|
||||||
|
|
||||||
./stream_manager_ui.hpp
|
./stream_manager_ui.hpp
|
||||||
./stream_manager_ui.cpp
|
./stream_manager_ui.cpp
|
||||||
|
@ -297,7 +297,10 @@ float ChatGui4::render(float time_delta) {
|
|||||||
acceptable_sessions.push_back(o);
|
acceptable_sessions.push_back(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Components::VoIP::DefaultConfig g_default_connections{};
|
static Components::VoIP::DefaultConfig g_default_connections{
|
||||||
|
true, true,
|
||||||
|
true, false
|
||||||
|
};
|
||||||
|
|
||||||
if (ImGui::BeginMenu("default connections")) {
|
if (ImGui::BeginMenu("default connections")) {
|
||||||
ImGui::MenuItem("incoming audio", nullptr, &g_default_connections.incoming_audio);
|
ImGui::MenuItem("incoming audio", nullptr, &g_default_connections.incoming_audio);
|
||||||
|
168
src/frame_streams/sdl/sdl_video_frame_stream2.cpp
Normal file
168
src/frame_streams/sdl/sdl_video_frame_stream2.cpp
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
#include "./sdl_video_frame_stream2.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
SDLVideo2InputDevice::SDLVideo2InputDevice(void) {
|
||||||
|
int devcount {0};
|
||||||
|
SDL_CameraID *devices = SDL_GetCameras(&devcount);
|
||||||
|
std::cout << "SDLVID: SDL Camera Driver: " << SDL_GetCurrentCameraDriver() << "\n";
|
||||||
|
|
||||||
|
if (devices == nullptr || devcount < 1) {
|
||||||
|
throw int(2); // TODO: proper error code
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "SDLVID: found cameras:\n";
|
||||||
|
for (int i = 0; i < devcount; i++) {
|
||||||
|
const SDL_CameraID device = devices[i];
|
||||||
|
|
||||||
|
const char *name = SDL_GetCameraName(device);
|
||||||
|
std::cout << " - Camera #" << i << ": " << name << "\n";
|
||||||
|
|
||||||
|
int speccount {0};
|
||||||
|
SDL_CameraSpec** specs = SDL_GetCameraSupportedFormats(device, &speccount);
|
||||||
|
if (specs == nullptr) {
|
||||||
|
std::cout << " - no supported spec\n";
|
||||||
|
} else {
|
||||||
|
for (int spec_i = 0; spec_i < speccount; spec_i++) {
|
||||||
|
std::cout << " - " << specs[spec_i]->width << "x" << specs[spec_i]->height << "@" << float(specs[spec_i]->framerate_numerator)/specs[spec_i]->framerate_denominator << "fps " << SDL_GetPixelFormatName(specs[spec_i]->format) << "\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
SDL_free(specs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SDL_free(devices);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDLVideo2InputDevice::~SDLVideo2InputDevice(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<FrameStream2I<SDLVideoFrame>> SDLVideo2InputDevice::subscribe(void) {
|
||||||
|
const int prev_ref = _ref++;
|
||||||
|
if (prev_ref == 0) {
|
||||||
|
// there was previously no stream, we assume no thread
|
||||||
|
// open device here? or on the thread?
|
||||||
|
|
||||||
|
int devcount {0};
|
||||||
|
SDL_CameraID *devices = SDL_GetCameras(&devcount);
|
||||||
|
//std::cout << "SDL Camera Driver: " << SDL_GetCurrentCameraDriver() << "\n";
|
||||||
|
|
||||||
|
if (devices == nullptr || devcount < 1) {
|
||||||
|
_ref--;
|
||||||
|
// error/no devices, should we do this in the constructor?
|
||||||
|
SDL_free(devices);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: relist on device open?
|
||||||
|
//std::cout << "### found cameras:\n";
|
||||||
|
//for (int i = 0; i < devcount; i++) {
|
||||||
|
// const SDL_CameraID device = devices[i];
|
||||||
|
|
||||||
|
// const char *name = SDL_GetCameraName(device);
|
||||||
|
// std::cout << " - Camera #" << i << ": " << name << "\n";
|
||||||
|
|
||||||
|
// int speccount {0};
|
||||||
|
// SDL_CameraSpec** specs = SDL_GetCameraSupportedFormats(device, &speccount);
|
||||||
|
// if (specs == nullptr) {
|
||||||
|
// std::cout << " - no supported spec\n";
|
||||||
|
// } else {
|
||||||
|
// for (int spec_i = 0; spec_i < speccount; spec_i++) {
|
||||||
|
// std::cout << " - " << specs[spec_i]->width << "x" << specs[spec_i]->height << "@" << float(specs[spec_i]->framerate_numerator)/specs[spec_i]->framerate_denominator << "fps " << SDL_GetPixelFormatName(specs[spec_i]->format) << "\n";
|
||||||
|
|
||||||
|
// }
|
||||||
|
// SDL_free(specs);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
std::unique_ptr<SDL_Camera, decltype(&SDL_CloseCamera)> camera {nullptr, &SDL_CloseCamera};
|
||||||
|
|
||||||
|
SDL_CameraSpec spec {
|
||||||
|
// FORCE a different pixel format
|
||||||
|
//SDL_PIXELFORMAT_UNKNOWN,
|
||||||
|
SDL_PIXELFORMAT_YUY2,
|
||||||
|
//SDL_COLORSPACE_UNKNOWN,
|
||||||
|
SDL_COLORSPACE_YUV_DEFAULT,
|
||||||
|
|
||||||
|
1280, 720,
|
||||||
|
|
||||||
|
30, 1
|
||||||
|
};
|
||||||
|
camera = {
|
||||||
|
//SDL_OpenCamera(devices[0], &spec),
|
||||||
|
SDL_OpenCamera(devices[0], nullptr),
|
||||||
|
&SDL_CloseCamera
|
||||||
|
};
|
||||||
|
SDL_free(devices);
|
||||||
|
|
||||||
|
// seems like we need this before get format() ?
|
||||||
|
// TODO: best would be waiting in thread, but that obv does not work well
|
||||||
|
// TODO: sometimes if the device is/was in use it will stay 0 for ever
|
||||||
|
while (SDL_GetCameraPermissionState(camera.get()) == 0) {
|
||||||
|
//std::cerr << "permission for camera not granted\n";
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SDL_GetCameraPermissionState(camera.get()) <= 0) {
|
||||||
|
std::cerr << "SDLVID error: user denied camera permission\n";
|
||||||
|
_ref--;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fps {1.f};
|
||||||
|
if (!SDL_GetCameraFormat(camera.get(), &spec)) {
|
||||||
|
// meh
|
||||||
|
_ref--;
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
fps = float(spec.framerate_numerator)/float(spec.framerate_denominator);
|
||||||
|
std::cout << "SDLVID: camera fps: " << fps << "fps (" << spec.framerate_numerator << "/" << spec.framerate_denominator << ")\n";
|
||||||
|
auto* format_name = SDL_GetPixelFormatName(spec.format);
|
||||||
|
std::cout << "SDLVID: camera format: " << format_name << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
_thread = std::thread([this, camera = std::move(camera), fps](void) {
|
||||||
|
while (_ref > 0) {
|
||||||
|
Uint64 timestampNS = 0;
|
||||||
|
|
||||||
|
// aquire frame
|
||||||
|
SDL_Surface* sdl_frame_next = SDL_AcquireCameraFrame(camera.get(), ×tampNS);
|
||||||
|
|
||||||
|
if (sdl_frame_next != nullptr) {
|
||||||
|
SDLVideoFrame new_frame_non_owning {
|
||||||
|
timestampNS/1000,
|
||||||
|
sdl_frame_next
|
||||||
|
};
|
||||||
|
|
||||||
|
// creates surface copies
|
||||||
|
push(new_frame_non_owning);
|
||||||
|
|
||||||
|
SDL_ReleaseCameraFrame(camera.get(), sdl_frame_next);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sleep for interval
|
||||||
|
// TODO: do we really need half?
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(int64_t((1000/fps)*0.5)));
|
||||||
|
}
|
||||||
|
// camera destructor closes device here
|
||||||
|
});
|
||||||
|
std::cout << "SDLVID: started new cam thread\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return FrameStream2MultiSource<SDLVideoFrame>::subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SDLVideo2InputDevice::unsubscribe(const std::shared_ptr<FrameStream2I<SDLVideoFrame>>& sub) {
|
||||||
|
if (FrameStream2MultiSource<SDLVideoFrame>::unsubscribe(sub)) {
|
||||||
|
if (--_ref == 0) {
|
||||||
|
// was last stream, close device and thread
|
||||||
|
_thread.join(); // TODO: defer to destructor or new thread?
|
||||||
|
// this might take a moment and lock up the main thread
|
||||||
|
std::cout << "SDLVID: ended cam thread\n";
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
24
src/frame_streams/sdl/sdl_video_frame_stream2.hpp
Normal file
24
src/frame_streams/sdl/sdl_video_frame_stream2.hpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "./video.hpp"
|
||||||
|
#include "../frame_stream2.hpp"
|
||||||
|
#include "../multi_source.hpp"
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
// while a stream is subscribed, have the camera device open
|
||||||
|
// and aquire and push frames from a thread
|
||||||
|
struct SDLVideo2InputDevice : public FrameStream2MultiSource<SDLVideoFrame> {
|
||||||
|
std::atomic_uint _ref {0};
|
||||||
|
std::thread _thread;
|
||||||
|
|
||||||
|
// TODO: device id
|
||||||
|
SDLVideo2InputDevice(void);
|
||||||
|
virtual ~SDLVideo2InputDevice(void);
|
||||||
|
|
||||||
|
// we hook int multi source
|
||||||
|
std::shared_ptr<FrameStream2I<SDLVideoFrame>> subscribe(void) override;
|
||||||
|
bool unsubscribe(const std::shared_ptr<FrameStream2I<SDLVideoFrame>>& sub) override;
|
||||||
|
};
|
||||||
|
|
@ -6,6 +6,7 @@
|
|||||||
#include <solanaceae/contact/components.hpp>
|
#include <solanaceae/contact/components.hpp>
|
||||||
|
|
||||||
#include "./frame_streams/sdl/sdl_audio2_frame_stream2.hpp"
|
#include "./frame_streams/sdl/sdl_audio2_frame_stream2.hpp"
|
||||||
|
#include "./frame_streams/sdl/sdl_video_frame_stream2.hpp"
|
||||||
|
|
||||||
#include <imgui/imgui.h>
|
#include <imgui/imgui.h>
|
||||||
|
|
||||||
@ -178,6 +179,27 @@ MainScreen::MainScreen(SimpleConfigModel&& conf_, SDL_Renderer* renderer_, Theme
|
|||||||
} else {
|
} else {
|
||||||
std::cerr << "MS warning: no sdl audio: " << SDL_GetError() << "\n";
|
std::cerr << "MS warning: no sdl audio: " << SDL_GetError() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SDL_InitSubSystem(SDL_INIT_CAMERA)) {
|
||||||
|
{ // video in
|
||||||
|
ObjectHandle vsrc {os.registry(), os.registry().create()};
|
||||||
|
try {
|
||||||
|
vsrc.emplace<Components::FrameStream2Source<SDLVideoFrame>>(
|
||||||
|
std::make_unique<SDLVideo2InputDevice>()
|
||||||
|
);
|
||||||
|
|
||||||
|
vsrc.emplace<Components::StreamSource>(Components::StreamSource::create<SDLVideoFrame>("SDL Video Default Recording Device"));
|
||||||
|
vsrc.emplace<Components::TagDefaultTarget>();
|
||||||
|
|
||||||
|
os.throwEventConstruct(vsrc);
|
||||||
|
} catch (...) {
|
||||||
|
std::cerr << "MS error: failed constructing default video input source\n";
|
||||||
|
os.registry().destroy(vsrc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cerr << "MS warning: no sdl camera: " << SDL_GetError() << "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MainScreen::~MainScreen(void) {
|
MainScreen::~MainScreen(void) {
|
||||||
|
Loading…
Reference in New Issue
Block a user