mirror of
https://github.com/obsproject/obs-studio.git
synced 2026-09-24 23:31:36 +08:00
mac-virtualcam: Do not rely on global state
This change updates the implementation of the mac-virtualcam plugin to not use any global state and instead rely on the state object that is passed by the OBS module system. This approach is similar to the virtual camera implementations for Linux and Windows.
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
#include <obs-module.h>
|
#include <obs-module.h>
|
||||||
#include <AppKit/AppKit.h>
|
|
||||||
#include "OBSDALMachServer.h"
|
#include "OBSDALMachServer.h"
|
||||||
#include "Defines.h"
|
#include "Defines.h"
|
||||||
|
|
||||||
@@ -10,10 +9,12 @@ MODULE_EXPORT const char *obs_module_description(void)
|
|||||||
return "macOS virtual webcam output";
|
return "macOS virtual webcam output";
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_output_t *outputRef;
|
struct virtualcam_data {
|
||||||
obs_video_info videoInfo;
|
obs_output_t *output;
|
||||||
CVPixelBufferPoolRef pool;
|
obs_video_info videoInfo;
|
||||||
static OBSDALMachServer *sMachServer;
|
CVPixelBufferPoolRef pool;
|
||||||
|
OBSDALMachServer *machServer;
|
||||||
|
};
|
||||||
|
|
||||||
static bool check_dal_plugin()
|
static bool check_dal_plugin()
|
||||||
{
|
{
|
||||||
@@ -129,31 +130,29 @@ static const char *virtualcam_output_get_name(void *type_data)
|
|||||||
return obs_module_text("Plugin_Name");
|
return obs_module_text("Plugin_Name");
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a dummy pointer so we have something to return from virtualcam_output_create
|
|
||||||
static void *data = &data;
|
|
||||||
|
|
||||||
static void *virtualcam_output_create(obs_data_t *settings,
|
static void *virtualcam_output_create(obs_data_t *settings,
|
||||||
obs_output_t *output)
|
obs_output_t *output)
|
||||||
{
|
{
|
||||||
UNUSED_PARAMETER(settings);
|
UNUSED_PARAMETER(settings);
|
||||||
|
|
||||||
outputRef = output;
|
struct virtualcam_data *vcam =
|
||||||
|
(struct virtualcam_data *)bzalloc(sizeof(*vcam));
|
||||||
|
|
||||||
blog(LOG_DEBUG, "output_create");
|
vcam->output = output;
|
||||||
sMachServer = [[OBSDALMachServer alloc] init];
|
vcam->machServer = [[OBSDALMachServer alloc] init];
|
||||||
return data;
|
return vcam;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtualcam_output_destroy(void *data)
|
static void virtualcam_output_destroy(void *data)
|
||||||
{
|
{
|
||||||
UNUSED_PARAMETER(data);
|
struct virtualcam_data *vcam = (struct virtualcam_data *)data;
|
||||||
blog(LOG_DEBUG, "output_destroy");
|
|
||||||
sMachServer = nil;
|
vcam->machServer = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool virtualcam_output_start(void *data)
|
static bool virtualcam_output_start(void *data)
|
||||||
{
|
{
|
||||||
UNUSED_PARAMETER(data);
|
struct virtualcam_data *vcam = (struct virtualcam_data *)data;
|
||||||
|
|
||||||
bool hasDalPlugin = check_dal_plugin();
|
bool hasDalPlugin = check_dal_plugin();
|
||||||
|
|
||||||
@@ -161,24 +160,22 @@ static bool virtualcam_output_start(void *data)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
blog(LOG_DEBUG, "output_start");
|
obs_get_video_info(&vcam->videoInfo);
|
||||||
|
|
||||||
obs_get_video_info(&videoInfo);
|
|
||||||
|
|
||||||
FourCharCode video_format =
|
FourCharCode video_format =
|
||||||
convert_video_format_to_mac(videoInfo.output_format);
|
convert_video_format_to_mac(vcam->videoInfo.output_format);
|
||||||
|
|
||||||
if (!video_format) {
|
if (!video_format) {
|
||||||
// Selected output format is not supported natively by CoreVideo, CPU conversion necessary
|
// Selected output format is not supported natively by CoreVideo, CPU conversion necessary
|
||||||
blog(LOG_WARNING,
|
blog(LOG_WARNING,
|
||||||
"Selected output format (%s) not supported by CoreVideo, enabling CPU transcoding...",
|
"Selected output format (%s) not supported by CoreVideo, enabling CPU transcoding...",
|
||||||
get_video_format_name(videoInfo.output_format));
|
get_video_format_name(vcam->videoInfo.output_format));
|
||||||
|
|
||||||
struct video_scale_info conversion = {};
|
struct video_scale_info conversion = {};
|
||||||
conversion.format = VIDEO_FORMAT_NV12;
|
conversion.format = VIDEO_FORMAT_NV12;
|
||||||
conversion.width = videoInfo.output_width;
|
conversion.width = vcam->videoInfo.output_width;
|
||||||
conversion.height = videoInfo.output_height;
|
conversion.height = vcam->videoInfo.output_height;
|
||||||
obs_output_set_video_conversion(outputRef, &conversion);
|
obs_output_set_video_conversion(vcam->output, &conversion);
|
||||||
|
|
||||||
video_format = convert_video_format_to_mac(conversion.format);
|
video_format = convert_video_format_to_mac(conversion.format);
|
||||||
}
|
}
|
||||||
@@ -186,22 +183,22 @@ static bool virtualcam_output_start(void *data)
|
|||||||
NSDictionary *pAttr = @{};
|
NSDictionary *pAttr = @{};
|
||||||
NSDictionary *pbAttr = @{
|
NSDictionary *pbAttr = @{
|
||||||
(id)kCVPixelBufferPixelFormatTypeKey: @(video_format),
|
(id)kCVPixelBufferPixelFormatTypeKey: @(video_format),
|
||||||
(id)kCVPixelBufferWidthKey: @(videoInfo.output_width),
|
(id)kCVPixelBufferWidthKey: @(vcam->videoInfo.output_width),
|
||||||
(id)kCVPixelBufferHeightKey: @(videoInfo.output_height),
|
(id)kCVPixelBufferHeightKey: @(vcam->videoInfo.output_height),
|
||||||
(id)kCVPixelBufferIOSurfacePropertiesKey: @{}
|
(id)kCVPixelBufferIOSurfacePropertiesKey: @{}
|
||||||
};
|
};
|
||||||
CVReturn status = CVPixelBufferPoolCreate(
|
CVReturn status = CVPixelBufferPoolCreate(
|
||||||
kCFAllocatorDefault, (__bridge CFDictionaryRef)pAttr,
|
kCFAllocatorDefault, (__bridge CFDictionaryRef)pAttr,
|
||||||
(__bridge CFDictionaryRef)pbAttr, &pool);
|
(__bridge CFDictionaryRef)pbAttr, &vcam->pool);
|
||||||
if (status != kCVReturnSuccess) {
|
if (status != kCVReturnSuccess) {
|
||||||
blog(LOG_ERROR,
|
blog(LOG_ERROR,
|
||||||
"unable to allocate pixel buffer pool (error %d)", status);
|
"unable to allocate pixel buffer pool (error %d)", status);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[sMachServer run];
|
[vcam->machServer run];
|
||||||
|
|
||||||
if (!obs_output_begin_data_capture(outputRef, 0)) {
|
if (!obs_output_begin_data_capture(vcam->output, 0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,23 +207,23 @@ static bool virtualcam_output_start(void *data)
|
|||||||
|
|
||||||
static void virtualcam_output_stop(void *data, uint64_t ts)
|
static void virtualcam_output_stop(void *data, uint64_t ts)
|
||||||
{
|
{
|
||||||
UNUSED_PARAMETER(data);
|
|
||||||
UNUSED_PARAMETER(ts);
|
UNUSED_PARAMETER(ts);
|
||||||
|
|
||||||
blog(LOG_DEBUG, "output_stop");
|
struct virtualcam_data *vcam = (struct virtualcam_data *)data;
|
||||||
obs_output_end_data_capture(outputRef);
|
|
||||||
[sMachServer stop];
|
|
||||||
|
|
||||||
CVPixelBufferPoolRelease(pool);
|
obs_output_end_data_capture(vcam->output);
|
||||||
|
[vcam->machServer stop];
|
||||||
|
|
||||||
|
CVPixelBufferPoolRelease(vcam->pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtualcam_output_raw_video(void *data, struct video_data *frame)
|
static void virtualcam_output_raw_video(void *data, struct video_data *frame)
|
||||||
{
|
{
|
||||||
UNUSED_PARAMETER(data);
|
struct virtualcam_data *vcam = (struct virtualcam_data *)data;
|
||||||
|
|
||||||
CVPixelBufferRef frameRef = NULL;
|
CVPixelBufferRef frameRef = nil;
|
||||||
CVReturn status = CVPixelBufferPoolCreatePixelBuffer(
|
CVReturn status = CVPixelBufferPoolCreatePixelBuffer(
|
||||||
kCFAllocatorDefault, pool, &frameRef);
|
kCFAllocatorDefault, vcam->pool, &frameRef);
|
||||||
|
|
||||||
if (status != kCVReturnSuccess) {
|
if (status != kCVReturnSuccess) {
|
||||||
blog(LOG_ERROR, "unable to allocate pixel buffer (error %d)",
|
blog(LOG_ERROR, "unable to allocate pixel buffer (error %d)",
|
||||||
@@ -295,10 +292,10 @@ static void virtualcam_output_raw_video(void *data, struct video_data *frame)
|
|||||||
CVPixelBufferUnlockBaseAddress(frameRef, 0);
|
CVPixelBufferUnlockBaseAddress(frameRef, 0);
|
||||||
|
|
||||||
// Share pixel buffer with clients
|
// Share pixel buffer with clients
|
||||||
[sMachServer sendPixelBuffer:frameRef
|
[vcam->machServer sendPixelBuffer:frameRef
|
||||||
timestamp:frame->timestamp
|
timestamp:frame->timestamp
|
||||||
fpsNumerator:videoInfo.fps_num
|
fpsNumerator:vcam->videoInfo.fps_num
|
||||||
fpsDenominator:videoInfo.fps_den];
|
fpsDenominator:vcam->videoInfo.fps_den];
|
||||||
|
|
||||||
CVPixelBufferRelease(frameRef);
|
CVPixelBufferRelease(frameRef);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user