Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

obs-webrtc: prototype / playground #7192

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ jobs:
- name: 'Switch to Xcode 14 Beta'
run: sudo xcode-select -switch /Applications/Xcode_14.0.app

- name: 'aarch64-apple-darwin'
run: rustup target add aarch64-apple-darwin

- name: 'Install dependencies'
env:
RESTORED_VLC: ${{ steps.vlc-cache.outputs.cache-hit }}
Expand Down
7 changes: 7 additions & 0 deletions CI/macos/02_build_obs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ _configure_obs() {
UNITTEST_OPTIONS="-DENABLE_UNIT_TESTS=ON"
fi

if [ "${CI}" -a "${ARCH}" = "x86_64" ]; then
Rust_CARGO_TARGET="x86_64-apple-darwin"
else
Rust_CARGO_TARGET="aarch64-apple-darwin"
fi

cmake -S . -B ${BUILD_DIR} -G ${GENERATOR} \
-DCEF_ROOT_DIR="${DEPS_BUILD_DIR}/cef_binary_${MACOS_CEF_BUILD_VERSION:-${CI_MACOS_CEF_VERSION}}_macos_${ARCH:-x86_64}" \
-DENABLE_BROWSER=ON \
Expand All @@ -82,6 +88,7 @@ _configure_obs() {
-DCMAKE_INSTALL_PREFIX=${BUILD_DIR}/install \
-DCMAKE_BUILD_TYPE=${BUILD_CONFIG} \
-DOBS_BUNDLE_CODESIGN_IDENTITY="${CODESIGN_IDENT:--}" \
-DRust_CARGO_TARGET="${Rust_CARGO_TARGET}" \
${YOUTUBE_OPTIONS} \
${TWITCH_OPTIONS} \
${RESTREAM_OPTIONS} \
Expand Down
8 changes: 6 additions & 2 deletions UI/window-basic-settings-stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ extern QCefCookieManager *panel_cookies;
enum class ListOpt : int {
ShowAll = 1,
Custom,
WHIP,
};

enum class Section : int {
Expand All @@ -38,7 +39,8 @@ enum class Section : int {

inline bool OBSBasicSettings::IsCustomService() const
{
return ui->service->currentData().toInt() == (int)ListOpt::Custom;
return ui->service->currentData().toInt() == (int)ListOpt::Custom ||
ui->service->currentData().toInt() == (int)ListOpt::WHIP;
}

void OBSBasicSettings::InitStreamPage()
Expand Down Expand Up @@ -235,7 +237,7 @@ void OBSBasicSettings::SaveStream1Settings()
obs_data_set_string(settings, "key", QT_TO_UTF8(ui->key->text()));

OBSServiceAutoRelease newService = obs_service_create(
service_id, "default_service", settings, hotkeyData);
"whip", "default_service", settings, hotkeyData);

if (!newService)
return;
Expand Down Expand Up @@ -349,6 +351,8 @@ void OBSBasicSettings::LoadServices(bool showAll)
for (QString &name : names)
ui->service->addItem(name);

ui->service->insertItem(0, QTStr("WHIP"), QVariant((int)ListOpt::WHIP));

if (!showAll) {
ui->service->addItem(
QTStr("Basic.AutoConfig.StreamPage.Service.ShowAll"),
Expand Down
1 change: 1 addition & 0 deletions plugins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,4 @@ add_subdirectory(obs-transitions)
add_subdirectory(rtmp-services)
add_subdirectory(text-freetype2)
add_subdirectory(aja)
add_subdirectory(obs-webrtc)
51 changes: 51 additions & 0 deletions plugins/obs-webrtc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
project(obs-webrtc)

include(FetchContent)

FetchContent_Declare(
Corrosion
GIT_REPOSITORY https://github.com/AndrewGaspar/corrosion.git
GIT_TAG origin/master # Optionally specify a version tag or branch here
)

FetchContent_MakeAvailable(Corrosion)

# find_package(Libcurl REQUIRED)

include_directories(${LIBCURL_INCLUDE_DIRS})

include_directories(${OBS_JANSSON_INCLUDE_DIRS})

option(ENABLE_FFMPEG_LOGGING "Enables obs-ffmpeg logging" OFF)

find_package(
FFmpeg REQUIRED
COMPONENTS avcodec
avfilter
avdevice
avutil
swscale
avformat
swresample)
include_directories(${FFMPEG_INCLUDE_DIRS})

set(obs-webrtc_HEADERS webrtc-stream.h webrtc-source.h webrtc-call.h)
set(obs-webrtc_SOURCES whip.c webrtc-stream.c webrtc-source.c webrtc.c
webrtc-call.c)

if(WIN32)
set(MODULE_DESCRIPTION "OBS webrtc module")
configure_file(${CMAKE_SOURCE_DIR}/cmake/bundle/windows/obs-module.rc.in
obs-webrtc.rc)
list(APPEND obs-webrtc_SOURCES obs-webrtc.rc)
endif()

add_library(obs-webrtc MODULE ${obs-webrtc_SOURCES} ${obs-webrtc_HEADERS})

corrosion_import_crate(MANIFEST_PATH webrtc/Cargo.toml)

target_link_libraries(obs-webrtc libobs webrtc-rs-lib ${OBS_JANSSON_IMPORT}
${LIBCURL_LIBRARIES} ${FFMPEG_LIBRARIES})
set_target_properties(obs-webrtc PROPERTIES FOLDER "plugins")

setup_plugin_target(obs-webrtc data)
Empty file added plugins/obs-webrtc/data/.keepme
Empty file.
147 changes: 147 additions & 0 deletions plugins/obs-webrtc/webrtc-call.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#include <obs.h>
#include <graphics/graphics.h>
#include <util/threading.h>
#include <util/platform.h>

#include <libavutil/pixdesc.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>

#include "webrtc-call.h"
#include "./webrtc/bindings.h"

OBSWebRTCCall *call;

pthread_t thread;

AVFrame *frame;
AVFrame *audioFrame;
AVFrame *dst;

struct OBSCallParticipant {
AVCodecContext *videoContext;
AVCodecContext *audioContext;
};

void packet_callback(const void *user_data, const uint8_t *packet_data,
unsigned int length, unsigned int video)
{

//blog(LOG_INFO, "%d", length);
struct OBSCallParticipant *participant =
(struct OBSCallParticipant *)user_data;

AVCodecContext *context = NULL;
if (video) {
context = participant->videoContext;
} else {
context = participant->audioContext;
}

uint8_t *unowned_packet = bzalloc(sizeof(uint8_t) * length);
memcpy(unowned_packet, packet_data, length);

AVPacket *packet = av_packet_alloc();
av_packet_from_data(packet, unowned_packet, length);
avcodec_send_packet(context, packet);

if (video) {
int res = avcodec_receive_frame(context, frame);

if (res == 0) {

/*blog(LOG_INFO, "Width: %d, Height: %d, Format: %s",
frame->width, frame->height,
av_get_pix_fmt_name(frame->format));*/

dst->width = frame->width;
dst->height = frame->height;
dst->format = AV_PIX_FMT_BGRA;
av_image_alloc(dst->data, dst->linesize, frame->width,
frame->height, AV_PIX_FMT_BGRA, 1);
struct SwsContext *swsContext = sws_getContext(
frame->width, frame->height, frame->format,
frame->width, frame->height, AV_PIX_FMT_BGRA,
SWS_BILINEAR, NULL, NULL, NULL);
int out = sws_scale(swsContext,
(const uint8_t *const *)frame->data,
frame->linesize, 0, frame->height,
dst->data, dst->linesize);
sws_freeContext(swsContext);

//blog(LOG_INFO, "out %d", out);

//blog(LOG_INFO, "Width: %d, Height: %d, Format: %s", dst->width, dst->height, av_get_pix_fmt_name(dst->format));

obs_enter_graphics();

webrtcTexture = gs_texture_create(
dst->width, dst->height, GS_BGRA, 1,
(const uint8_t **)&dst->data, GS_DYNAMIC);

//gs_texture_set_image(webrtcTexture, (const uint8_t **)&frame->data, frame->linesize[0], false);

obs_leave_graphics();
}
} else {
int res = avcodec_receive_frame(context, audioFrame);

if (res == 0) {
//blog(LOG_INFO, "channels: %d", audioFrame->channels);
}
}
}

void setup_call()
{
obs_enter_graphics();
webrtcTexture =
gs_texture_create(1920, 1080, GS_BGRA, 1, NULL, GS_DYNAMIC);
obs_leave_graphics();

const AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264);

AVDictionary *opts = NULL;
//av_dict_set(&opts, "b", "2.5M", 0);
if (!codec)
exit(1);
AVCodecContext *context = avcodec_alloc_context3(codec);
if (avcodec_open2(context, codec, &opts) < 0)
exit(1);

/*AVCodecParameters* codecpar = avcodec_parameters_alloc();
codecpar->codec_id = AV_CODEC_ID_H264;
codecpar->height = 720;
codecpar->width = 1280;*/

frame = av_frame_alloc();
audioFrame = av_frame_alloc();
dst = av_frame_alloc();

const AVCodec *opusCodec = avcodec_find_decoder(AV_CODEC_ID_OPUS);
AVCodecContext *audioContext = avcodec_alloc_context3(opusCodec);
if (avcodec_open2(audioContext, opusCodec, NULL) < 0)
exit(1);

//codecpar->

//avcodec_parameters_to_context(context, codecpar);

struct OBSCallParticipant *callParticipant =
malloc(sizeof(struct OBSCallParticipant));
callParticipant->videoContext = context;
callParticipant->audioContext = audioContext;

call = obs_webrtc_call_init(callParticipant, packet_callback);

/*if (pthread_create(&thread, NULL, video_thread, NULL) != 0) {
blog(LOG_ERROR, "Failed to make render thread of webrtc call");
}else {
blog(LOG_ERROR, "Thread running");
}*/
}

void start_call()
{
obs_webrtc_call_start(call);
}
9 changes: 9 additions & 0 deletions plugins/obs-webrtc/webrtc-call.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once

#include <libavcodec/avcodec.h>

extern struct gs_texture *webrtcTexture;

void setup_call();
void start_call();
static void *video_thread(void *data);
42 changes: 42 additions & 0 deletions plugins/obs-webrtc/webrtc-services-main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "util/text-lookup.h"
#include "util/threading.h"
#include "util/platform.h"
#include "util/dstr.h"
#include "obs-module.h"
#include "file-updater/file-updater.h"

OBS_DECLARE_MODULE()
OBS_MODULE_USE_DEFAULT_LOCALE("obs-webrtc-services", "en-US")
MODULE_EXPORT const char *obs_module_description(void)
{
return "OBS core WebRTC services";
}

#define RTMP_SERVICES_LOG_STR "[obs-webrtc-services plugin] "
#define RTMP_SERVICES_VER_STR \
"obs-webrtc-services plugin (libobs " OBS_VERSION ")"

extern struct obs_service_info whip_service;

static update_info_t *update_info = NULL;
static struct dstr module_name = {0};

const char *get_module_name(void)
{
return module_name.array;
}

bool obs_module_load(void)
{
dstr_copy(&module_name, "obs-webrtc-services plugin (libobs ");
dstr_cat(&module_name, obs_get_version_string());
dstr_cat(&module_name, ")");

obs_register_service(&whip_service);
return true;
}

void obs_module_unload(void)
{
dstr_free(&module_name);
}
Loading