Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 14:04:28 +01:00
parent 81b91f4139
commit f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions

View file

@ -0,0 +1,56 @@
#include "DesktopInterface.h"
#include "platform/tdesktop/VideoCapturerInterfaceImpl.h"
#include "platform/tdesktop/VideoCapturerTrackSource.h"
#include "api/video_codecs/builtin_video_encoder_factory.h"
#include "api/video_codecs/builtin_video_decoder_factory.h"
#include "pc/video_track_source_proxy.h"
#if TGCALLS_UWP_DESKTOP
#include "modules/video_coding/codecs/h264/win/h264_mf_factory.h"
#endif
namespace tgcalls {
std::unique_ptr<webrtc::VideoEncoderFactory> DesktopInterface::makeVideoEncoderFactory(bool preferHardwareEncoding, bool isScreencast) {
#if TGCALLS_UWP_DESKTOP
return std::make_unique<webrtc::H264MFEncoderFactory>();
#else
return webrtc::CreateBuiltinVideoEncoderFactory();
#endif
}
std::unique_ptr<webrtc::VideoDecoderFactory> DesktopInterface::makeVideoDecoderFactory() {
#if TGCALLS_UWP_DESKTOP
return std::make_unique<webrtc::H264MFDecoderFactory>();
#else
return webrtc::CreateBuiltinVideoDecoderFactory();
#endif
}
rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> DesktopInterface::makeVideoSource(rtc::Thread *signalingThread, rtc::Thread *workerThread) {
const auto videoTrackSource = rtc::scoped_refptr<VideoCapturerTrackSource>(
new rtc::RefCountedObject<VideoCapturerTrackSource>());
return videoTrackSource
? webrtc::VideoTrackSourceProxy::Create(signalingThread, workerThread, videoTrackSource)
: nullptr;
}
bool DesktopInterface::supportsEncoding(const std::string &codecName) {
return (codecName == cricket::kH264CodecName)
|| (codecName == cricket::kVp8CodecName);
}
void DesktopInterface::adaptVideoSource(rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> videoSource, int width, int height, int fps) {
}
std::unique_ptr<VideoCapturerInterface> DesktopInterface::makeVideoCapturer(rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> source, std::string deviceId, std::function<void(VideoState)> stateUpdated, std::function<void(PlatformCaptureInfo)> captureInfoUpdated, std::shared_ptr<PlatformContext> platformContext, std::pair<int, int> &outResolution) {
return std::make_unique<VideoCapturerInterfaceImpl>(source, deviceId, stateUpdated, platformContext, outResolution);
}
std::unique_ptr<PlatformInterface> CreatePlatformInterface() {
return std::make_unique<DesktopInterface>();
}
} // namespace tgcalls

View file

@ -0,0 +1,22 @@
#ifndef TGCALLS_DESKTOP_INTERFACE_H
#define TGCALLS_DESKTOP_INTERFACE_H
#include "platform/PlatformInterface.h"
#include "VideoCapturerInterface.h"
namespace tgcalls {
class DesktopInterface : public PlatformInterface {
public:
std::unique_ptr<webrtc::VideoEncoderFactory> makeVideoEncoderFactory(bool preferHardwareEncoding = false, bool isScreencast = false) override;
std::unique_ptr<webrtc::VideoDecoderFactory> makeVideoDecoderFactory() override;
bool supportsEncoding(const std::string &codecName) override;
rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> makeVideoSource(rtc::Thread *signalingThread, rtc::Thread *workerThread) override;
void adaptVideoSource(rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> videoSource, int width, int height, int fps) override;
std::unique_ptr<VideoCapturerInterface> makeVideoCapturer(rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> source, std::string deviceId, std::function<void(VideoState)> stateUpdated, std::function<void(PlatformCaptureInfo)> captureInfoUpdated, std::shared_ptr<PlatformContext> platformContext, std::pair<int, int> &outResolution) override;
};
} // namespace tgcalls
#endif // TGCALLS_DESKTOP_INTERFACE_H

View file

@ -0,0 +1,253 @@
#include "VideoCameraCapturer.h"
#include "api/video/i420_buffer.h"
#include "api/video/video_frame_buffer.h"
#include "api/video/video_rotation.h"
#include "modules/video_capture/video_capture_factory.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#ifdef WEBRTC_LINUX // Breaks compilation on MSVC because of ERROR define.
#include <modules/video_capture/video_capture_options.h>
#endif // WEBRTC_LINUX
#include <stdint.h>
#include <memory>
#include <algorithm>
namespace tgcalls {
namespace {
constexpr auto kPreferredWidth = 1280;
constexpr auto kPreferredHeight = 720;
constexpr auto kPreferredFps = 30;
#ifdef WEBRTC_LINUX
[[nodiscard]] webrtc::VideoCaptureOptions GetVideoCaptureOptions() {
auto result = webrtc::VideoCaptureOptions();
result.set_allow_v4l2(true);
#ifdef WEBRTC_USE_PIPEWIRE
//result.set_allow_pipewire(true);
// This requires a call to result.Init(callback)
// and waiting for the callback to finish.
#endif
return result;
}
#endif
} // namespace
VideoCameraCapturer::VideoCameraCapturer(
std::shared_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> sink)
: _sink(sink) {
}
VideoCameraCapturer::~VideoCameraCapturer() {
destroy();
}
void VideoCameraCapturer::create() {
_failed = false;
#ifdef WEBRTC_LINUX
auto options = GetVideoCaptureOptions();
const auto info = std::unique_ptr<
webrtc::VideoCaptureModule::DeviceInfo
>(webrtc::VideoCaptureFactory::CreateDeviceInfo(&options));
#else // WEBRTC_LINUX
const auto info = std::unique_ptr<
webrtc::VideoCaptureModule::DeviceInfo
>(webrtc::VideoCaptureFactory::CreateDeviceInfo());
#endif // WEBRTC_LINUX
if (!info) {
failed();
return;
}
const auto count = info->NumberOfDevices();
if (count <= 0) {
failed();
return;
}
const auto getId = [&](int index) {
constexpr auto kLengthLimit = 256;
char name[kLengthLimit] = { 0 };
char id[kLengthLimit] = { 0 };
return (info->GetDeviceName(index, name, kLengthLimit, id, kLengthLimit) == 0)
? std::string(id)
: std::string();
};
auto preferredId = std::string();
for (auto i = 0; i != count; ++i) {
const auto id = getId(i);
if ((_requestedDeviceId == id)
|| (preferredId.empty()
&& (_requestedDeviceId.empty() || _requestedDeviceId == "default"))) {
preferredId = id;
}
}
if (create(info.get(), preferredId)) {
return;
}
for (auto i = 0; i != count; ++i) {
if (create(info.get(), getId(i))) {
return;
}
}
failed();
}
void VideoCameraCapturer::failed() {
_failed = true;
if (_error) {
_error();
}
}
bool VideoCameraCapturer::create(
webrtc::VideoCaptureModule::DeviceInfo *info,
const std::string &deviceId) {
const auto deviceString = deviceId.c_str();
#ifdef WEBRTC_LINUX
auto options = GetVideoCaptureOptions();
_module = webrtc::VideoCaptureFactory::Create(&options, deviceString);
#else // WEBRTC_LINUX
_module = webrtc::VideoCaptureFactory::Create(deviceString);
#endif // WEBRTC_LINUX
if (!_module) {
RTC_LOG(LS_ERROR)
<< "Failed to create VideoCameraCapturer '" << deviceId << "'.";
return false;
}
_module->RegisterCaptureDataCallback(this);
auto requested = webrtc::VideoCaptureCapability();
requested.videoType = webrtc::VideoType::kI420;
requested.width = kPreferredWidth;
requested.height = kPreferredHeight;
requested.maxFPS = kPreferredFps;
info->GetBestMatchedCapability(
_module->CurrentDeviceName(),
requested,
_capability);
if (!_capability.width || !_capability.height || !_capability.maxFPS) {
_capability.width = kPreferredWidth;
_capability.height = kPreferredHeight;
_capability.maxFPS = kPreferredFps;
}
#ifndef WEBRTC_WIN
_capability.videoType = webrtc::VideoType::kI420;
#endif // WEBRTC_WIN
if (_module->StartCapture(_capability) != 0) {
RTC_LOG(LS_ERROR)
<< "Failed to start VideoCameraCapturer '" << _requestedDeviceId << "'.";
destroy();
return false;
}
_dimensions = std::make_pair(_capability.width, _capability.height);
return true;
}
void VideoCameraCapturer::setState(VideoState state) {
if (_state == state) {
return;
}
_state = state;
if (_state == VideoState::Active) {
create();
} else {
destroy();
}
}
void VideoCameraCapturer::setDeviceId(std::string deviceId) {
if (_requestedDeviceId == deviceId) {
return;
}
destroy();
_requestedDeviceId = deviceId;
if (_state == VideoState::Active) {
create();
}
}
void VideoCameraCapturer::setPreferredCaptureAspectRatio(float aspectRatio) {
_aspectRatio = aspectRatio;
}
void VideoCameraCapturer::setOnFatalError(std::function<void()> error) {
_error = std::move(error);
if (_failed && _error) {
_error();
}
}
std::pair<int, int> VideoCameraCapturer::resolution() const {
return _dimensions;
}
void VideoCameraCapturer::destroy() {
_failed = false;
if (!_module) {
return;
}
_module->StopCapture();
_module->DeRegisterCaptureDataCallback();
_module = nullptr;
}
void VideoCameraCapturer::OnFrame(const webrtc::VideoFrame &frame) {
if (_state != VideoState::Active) {
return;
} else if (_aspectRatio <= 0.001) {
_sink->OnFrame(frame);
return;
}
const auto originalWidth = frame.width();
const auto originalHeight = frame.height();
auto width = (originalWidth > _aspectRatio * originalHeight)
? int(std::round(_aspectRatio * originalHeight))
: originalWidth;
auto height = (originalWidth > _aspectRatio * originalHeight)
? originalHeight
: int(std::round(originalHeight / _aspectRatio));
if ((width >= originalWidth && height >= originalHeight) || !width || !height) {
_sink->OnFrame(frame);
return;
}
width &= ~int(1);
height &= ~int(1);
const auto left = (originalWidth - width) / 2;
const auto top = (originalHeight - height) / 2;
rtc::scoped_refptr<webrtc::I420Buffer> croppedBuffer =
webrtc::I420Buffer::Create(width, height);
croppedBuffer->CropAndScaleFrom(
*frame.video_frame_buffer()->ToI420(),
left,
top,
width,
height);
webrtc::VideoFrame::Builder croppedBuilder =
webrtc::VideoFrame::Builder()
.set_video_frame_buffer(croppedBuffer)
.set_rotation(webrtc::kVideoRotation_0)
.set_timestamp_us(frame.timestamp_us())
.set_id(frame.id());
if (frame.has_update_rect()) {
croppedBuilder.set_update_rect(frame.update_rect().ScaleWithFrame(
frame.width(),
frame.height(),
left,
top,
width,
height,
width,
height));
}
_sink->OnFrame(croppedBuilder.build());
}
} // namespace tgcalls

View file

@ -0,0 +1,57 @@
#ifndef TGCALLS_VIDEO_CAMERA_CAPTURER_H
#define TGCALLS_VIDEO_CAMERA_CAPTURER_H
#include "api/scoped_refptr.h"
#include "api/video/video_frame.h"
#include "api/video/video_source_interface.h"
#include "media/base/video_adapter.h"
#include "modules/video_capture/video_capture.h"
#include "VideoCaptureInterface.h"
#include <memory>
#include <vector>
#include <stddef.h>
namespace tgcalls {
class VideoCameraCapturer
: public rtc::VideoSinkInterface<webrtc::VideoFrame> {
public:
explicit VideoCameraCapturer(
std::shared_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> sink);
~VideoCameraCapturer();
void setState(VideoState state);
void setDeviceId(std::string deviceId);
void setPreferredCaptureAspectRatio(float aspectRatio);
void setOnFatalError(std::function<void()> error);
std::pair<int, int> resolution() const;
void OnFrame(const webrtc::VideoFrame &frame) override;
private:
void create();
bool create(
webrtc::VideoCaptureModule::DeviceInfo *info,
const std::string &deviceId);
void destroy();
void failed();
std::shared_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> _sink;
rtc::scoped_refptr<webrtc::VideoCaptureModule> _module;
webrtc::VideoCaptureCapability _capability;
VideoState _state = VideoState::Inactive;
std::string _requestedDeviceId;
std::pair<int, int> _dimensions;
std::function<void()> _error;
float _aspectRatio = 0.;
bool _failed = false;
};
} // namespace tgcalls
#endif

View file

@ -0,0 +1,145 @@
#include "tgcalls/platform/tdesktop/VideoCapturerInterfaceImpl.h"
#include "tgcalls/platform/tdesktop/VideoCapturerTrackSource.h"
#include "tgcalls/platform/tdesktop/VideoCameraCapturer.h"
#ifndef TGCALLS_UWP_DESKTOP
#include "tgcalls/desktop_capturer/DesktopCaptureSourceHelper.h"
#endif // TGCALLS_DISABLE_DESKTOP_CAPTURE
#include "pc/video_track_source_proxy.h"
namespace tgcalls {
namespace {
std::shared_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> GetSink(
const rtc::scoped_refptr<
webrtc::VideoTrackSourceInterface> &nativeSource) {
const auto proxy = static_cast<webrtc::VideoTrackSourceProxy*>(
nativeSource.get());
const auto internal = static_cast<VideoCapturerTrackSource*>(
proxy->internal());
return internal->sink();
}
} // namespace
VideoCapturerInterfaceImpl::VideoCapturerInterfaceImpl(
rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> source,
std::string deviceId,
std::function<void(VideoState)> stateUpdated,
std::shared_ptr<PlatformContext> platformContext,
std::pair<int, int> &outResolution)
: _source(source)
, _sink(GetSink(source))
, _stateUpdated(stateUpdated) {
#ifdef TGCALLS_UWP_DESKTOP
if (deviceId == "GraphicsCaptureItem")
{
auto uwpContext = std::static_pointer_cast<UwpContext>(platformContext);
_screenCapturer = std::make_unique<UwpScreenCapturer>(_sink, uwpContext->item);
_screenCapturer->setState(VideoState::Active);
outResolution = _screenCapturer->resolution();
}
else
#else
if (const auto source = DesktopCaptureSourceForKey(deviceId)) {
const auto data = DesktopCaptureSourceData{
/*.aspectSize = */{ 1280, 720 },
/*.fps = */24.,
/*.captureMouse = */true,
};
_desktopCapturer = std::make_unique<DesktopCaptureSourceHelper>(
source,
data);
_desktopCapturer->setOutput(_sink);
_desktopCapturer->start();
outResolution = { 1280, 960 };
} else if (!ShouldBeDesktopCapture(deviceId))
#endif // TGCALLS_UWP_DESKTOP
{
_cameraCapturer = std::make_unique<VideoCameraCapturer>(_sink);
_cameraCapturer->setDeviceId(deviceId);
_cameraCapturer->setState(VideoState::Active);
outResolution = _cameraCapturer->resolution();
}
}
VideoCapturerInterfaceImpl::~VideoCapturerInterfaceImpl() {
}
void VideoCapturerInterfaceImpl::setState(VideoState state) {
#ifdef TGCALLS_UWP_DESKTOP
if (_screenCapturer) {
_screenCapturer->setState(state);
} else
#else
if (_desktopCapturer) {
if (state == VideoState::Active) {
_desktopCapturer->start();
} else {
_desktopCapturer->stop();
}
} else
#endif // TGCALLS_UWP_DESKTOP
if (_cameraCapturer) {
_cameraCapturer->setState(state);
}
if (_stateUpdated) {
_stateUpdated(state);
}
}
void VideoCapturerInterfaceImpl::setPreferredCaptureAspectRatio(
float aspectRatio) {
if (_cameraCapturer) {
_cameraCapturer->setPreferredCaptureAspectRatio(aspectRatio);
}
}
void VideoCapturerInterfaceImpl::setUncroppedOutput(
std::shared_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> sink) {
if (_uncroppedSink != nullptr) {
_source->RemoveSink(_uncroppedSink.get());
}
_uncroppedSink = sink;
if (_uncroppedSink != nullptr) {
_source->AddOrUpdateSink(
_uncroppedSink.get(),
rtc::VideoSinkWants());
}
}
void VideoCapturerInterfaceImpl::setOnFatalError(std::function<void()> error) {
#ifdef TGCALLS_UWP_DESKTOP
if (_screenCapturer) {
_screenCapturer->setOnFatalError(std::move(error));
} else if (!_screenCapturer && !_cameraCapturer && error) {
error();
}
#else // TGCALLS_UWP_DESKTOP
if (_desktopCapturer) {
_desktopCapturer->setOnFatalError(std::move(error));
} else if (!_desktopCapturer && !_cameraCapturer && error) {
error();
}
#endif // TGCALLS_UWP_DESKTOP
if (_cameraCapturer) {
_cameraCapturer->setOnFatalError(std::move(error));
}
}
void VideoCapturerInterfaceImpl::setOnPause(std::function<void(bool)> pause) {
#ifdef TGCALLS_UWP_DESKTOP
if (_screenCapturer) {
_screenCapturer->setOnPause(std::move(pause));
}
#else // TGCALLS_UWP_DESKTOP
if (_desktopCapturer) {
_desktopCapturer->setOnPause(std::move(pause));
}
#endif // TGCALLS_UWP_DESKTOP
}
} // namespace tgcalls

View file

@ -0,0 +1,55 @@
#ifndef TGCALLS_VIDEO_CAPTURER_INTERFACE_IMPL_H
#define TGCALLS_VIDEO_CAPTURER_INTERFACE_IMPL_H
#include "VideoCapturerInterface.h"
#ifdef TGCALLS_UWP_DESKTOP
#include "platform/uwp/UwpContext.h"
#include "platform/uwp/UwpScreenCapturer.h"
#endif // TGCALLS_UWP_DESKTOP
#include "api/media_stream_interface.h"
namespace tgcalls {
class DesktopCaptureSourceHelper;
class VideoCameraCapturer;
class PlatformContext;
class VideoCapturerInterfaceImpl final : public VideoCapturerInterface {
public:
VideoCapturerInterfaceImpl(
rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> source,
std::string deviceId,
std::function<void(VideoState)> stateUpdated,
std::shared_ptr<PlatformContext> platformContext,
std::pair<int, int> &outResolution);
~VideoCapturerInterfaceImpl() override;
void setState(VideoState state) override;
void setPreferredCaptureAspectRatio(float aspectRatio) override;
void setUncroppedOutput(std::shared_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> sink) override;
int getRotation() override {
return 0;
}
void setOnFatalError(std::function<void()> error) override;
void setOnPause(std::function<void(bool)> pause) override;
private:
rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> _source;
std::shared_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> _sink;
#ifdef TGCALLS_UWP_DESKTOP
std::unique_ptr<UwpScreenCapturer> _screenCapturer;
#else // TGCALLS_UWP_DESKTOP
std::unique_ptr<DesktopCaptureSourceHelper> _desktopCapturer;
#endif // TGCALLS_UWP_DESKTOP
std::unique_ptr<VideoCameraCapturer> _cameraCapturer;
std::shared_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> _uncroppedSink;
std::function<void(VideoState)> _stateUpdated;
std::function<void()> _onFatalError;
};
} // namespace tgcalls
#endif

View file

@ -0,0 +1,19 @@
#include "tgcalls/platform/tdesktop/VideoCapturerTrackSource.h"
namespace tgcalls {
VideoCapturerTrackSource::VideoCapturerTrackSource()
: VideoTrackSource(/*remote=*/false)
, _broadcaster(std::make_shared<rtc::VideoBroadcaster>()) {
}
auto VideoCapturerTrackSource::sink()
-> std::shared_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> {
return _broadcaster;
}
rtc::VideoSourceInterface<webrtc::VideoFrame> *VideoCapturerTrackSource::source() {
return _broadcaster.get();
}
} // namespace tgcalls

View file

@ -0,0 +1,30 @@
#ifndef TGCALLS_VIDEO_CAPTURER_TRACK_SOURCE_H
#define TGCALLS_VIDEO_CAPTURER_TRACK_SOURCE_H
#include "pc/video_track_source.h"
#include "api/video/video_sink_interface.h"
#include "media/base/video_broadcaster.h"
#include "VideoCameraCapturer.h"
namespace tgcalls {
class VideoCameraCapturer;
class DesktopCapturer;
class VideoCapturerTrackSource : public webrtc::VideoTrackSource {
public:
VideoCapturerTrackSource();
std::shared_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> sink();
private:
rtc::VideoSourceInterface<webrtc::VideoFrame> *source() override;
std::shared_ptr<rtc::VideoBroadcaster> _broadcaster;
};
} // namespace tgcalls
#endif