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_push_converter.hpp
|
||||
./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.cpp
|
||||
|
@ -297,7 +297,10 @@ float ChatGui4::render(float time_delta) {
|
||||
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")) {
|
||||
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 "./frame_streams/sdl/sdl_audio2_frame_stream2.hpp"
|
||||
#include "./frame_streams/sdl/sdl_video_frame_stream2.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
@ -178,6 +179,27 @@ MainScreen::MainScreen(SimpleConfigModel&& conf_, SDL_Renderer* renderer_, Theme
|
||||
} else {
|
||||
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) {
|
||||
|
Loading…
Reference in New Issue
Block a user