New upstream version 26.1.0+dfsg1

This commit is contained in:
Sebastian Ramacher 2020-12-22 18:32:50 +01:00
parent 040dcc3fc2
commit 013818c4af
594 changed files with 19576 additions and 4478 deletions

View file

@ -11,6 +11,10 @@ if (NOT "${FFMPEG_AVCODEC_LIBRARIES}" STREQUAL "")
list(REMOVE_ITEM FFMPEG_LIBRARIES ${FFMPEG_AVCODEC_LIBRARIES})
endif()
if(DEBUG_FFMPEG_MUX)
add_definitions(-DSHOW_SUBPROCESSES)
endif()
if(UNIX)
if (NOT APPLE)
find_package(X11 REQUIRED)
@ -139,7 +143,6 @@ elseif(APPLE)
set_source_files_properties(${libobs_PLATFORM_SOURCES}
PROPERTIES
LANGUAGE C
COMPILE_FLAGS "-fobjc-arc")
find_library(COCOA Cocoa)
@ -361,7 +364,8 @@ set(libobs_util_SOURCES
util/crc32.c
util/text-lookup.c
util/cf-parser.c
util/profiler.c)
util/profiler.c
util/bitstream.c)
set(libobs_util_HEADERS
util/curl/curl-helper.h
util/sse-intrin.h
@ -388,7 +392,8 @@ set(libobs_util_HEADERS
util/lexer.h
util/platform.h
util/profiler.h
util/profiler.hpp)
util/profiler.hpp
util/bitstream.h)
set(libobs_libobs_SOURCES
${libobs_PLATFORM_SOURCES}
@ -467,12 +472,10 @@ source_group("util\\Header Files" FILES ${libobs_util_HEADERS})
source_group("audio-monitoring\\Source Files" FILES ${libobs_audio_monitoring_SOURCES})
source_group("audio-monitoring\\Header Files" FILES ${libobs_audio_monitoring_HEADERS})
if(BUILD_CAPTIONS)
include_directories(${CMAKE_SOURCE_DIR}/deps/libcaption)
set(libobs_PLATFORM_DEPS
${libobs_PLATFORM_DEPS}
caption)
endif()
include_directories(${CMAKE_SOURCE_DIR}/deps/libcaption)
set(libobs_PLATFORM_DEPS
${libobs_PLATFORM_DEPS}
caption)
add_library(libobs SHARED ${libobs_SOURCES} ${libobs_HEADERS})
if(UNIX AND NOT APPLE)

View file

@ -183,8 +183,10 @@ static void do_stream_write(void *param)
if (bytesToFill > data->bytesRemaining)
bytesToFill = data->bytesRemaining;
pulseaudio_lock();
pa_stream_begin_write(data->stream, (void **)&buffer,
&bytesToFill);
pulseaudio_unlock();
circlebuf_pop_front(&data->new_data, buffer, bytesToFill);
@ -331,8 +333,20 @@ skip:
static void pulseaudio_stop_playback(struct audio_monitor *monitor)
{
if (monitor->stream) {
/* Stop the stream */
pulseaudio_lock();
pa_stream_disconnect(monitor->stream);
pulseaudio_unlock();
/* Remove the callbacks, to ensure we no longer try to do anything
* with this stream object */
pulseaudio_write_callback(monitor->stream, NULL, NULL);
pulseaudio_set_underflow_callback(monitor->stream, NULL, NULL);
/* Unreference the stream and drop it. PA will free it when it can. */
pulseaudio_lock();
pa_stream_unref(monitor->stream);
pulseaudio_unlock();
monitor->stream = NULL;
}

View file

@ -210,6 +210,7 @@ bool load_graphics_imports(struct gs_exports *exports, void *module,
GRAPHICS_IMPORT_OPTIONAL(gs_texture_release_dc);
GRAPHICS_IMPORT_OPTIONAL(device_texture_open_shared);
GRAPHICS_IMPORT_OPTIONAL(device_texture_get_shared_handle);
GRAPHICS_IMPORT_OPTIONAL(device_texture_wrap_obj);
GRAPHICS_IMPORT_OPTIONAL(device_texture_acquire_sync);
GRAPHICS_IMPORT_OPTIONAL(device_texture_release_sync);
GRAPHICS_IMPORT_OPTIONAL(device_texture_create_nv12);

View file

@ -299,6 +299,8 @@ struct gs_exports {
gs_texture_t *(*device_texture_open_shared)(gs_device_t *device,
uint32_t handle);
uint32_t (*device_texture_get_shared_handle)(gs_texture_t *tex);
gs_texture_t *(*device_texture_wrap_obj)(gs_device_t *device,
void *obj);
int (*device_texture_acquire_sync)(gs_texture_t *tex, uint64_t key,
uint32_t ms);
int (*device_texture_release_sync)(gs_texture_t *tex, uint64_t key);

View file

@ -2885,6 +2885,18 @@ uint32_t gs_texture_get_shared_handle(gs_texture_t *tex)
return GS_INVALID_HANDLE;
}
gs_texture_t *gs_texture_wrap_obj(void *obj)
{
graphics_t *graphics = thread_graphics;
if (!gs_valid("gs_texture_wrap_obj"))
return NULL;
if (graphics->exports.device_texture_wrap_obj)
return graphics->exports.device_texture_wrap_obj(
graphics->device, obj);
return NULL;
}
int gs_texture_acquire_sync(gs_texture_t *tex, uint64_t key, uint32_t ms)
{
graphics_t *graphics = thread_graphics;

View file

@ -867,6 +867,8 @@ EXPORT gs_texture_t *gs_texture_open_shared(uint32_t handle);
#define GS_INVALID_HANDLE (uint32_t) - 1
EXPORT uint32_t gs_texture_get_shared_handle(gs_texture_t *tex);
EXPORT gs_texture_t *gs_texture_wrap_obj(void *obj);
#define GS_WAIT_INFINITE (uint32_t) - 1
/**

View file

@ -224,6 +224,12 @@ static inline int process_packets(media_remux_job_t job,
if (ret < 0) {
blog(LOG_ERROR, "media_remux: Error muxing packet: %s",
av_err2str(ret));
/* Treat "Invalid data found when processing input" and
* "Invalid argument" as non-fatal */
if (ret == AVERROR_INVALIDDATA || ret == EINVAL)
continue;
break;
}
}

View file

@ -116,7 +116,7 @@ static bool discard_if_stopped(obs_source_t *source, size_t channels)
blog(LOG_DEBUG, "doing pending stop trick: '%s'",
source->context.name);
#endif
return true;
return false;
}
for (size_t ch = 0; ch < channels; ch++)

View file

@ -34,14 +34,14 @@
*
* Reset to zero each major version
*/
#define LIBOBS_API_MINOR_VER 0
#define LIBOBS_API_MINOR_VER 1
/*
* Increment if backward-compatible bug fix
*
* Reset to zero each major or minor version
*/
#define LIBOBS_API_PATCH_VER 2
#define LIBOBS_API_PATCH_VER 0
#define MAKE_SEMANTIC_VERSION(major, minor, patch) \
((major << 24) | (minor << 16) | patch)

View file

@ -1762,12 +1762,12 @@ bool obs_data_item_get_default_bool(obs_data_item_t *item)
obs_data_t *obs_data_item_get_default_obj(obs_data_item_t *item)
{
return data_item_get_obj(item, get_item_obj);
return data_item_get_obj(item, get_item_default_obj);
}
obs_data_array_t *obs_data_item_get_default_array(obs_data_item_t *item)
{
return data_item_get_array(item, get_item_array);
return data_item_get_array(item, get_item_default_array);
}
const char *obs_data_item_get_autoselect_string(obs_data_item_t *item)

View file

@ -36,6 +36,8 @@
#include "obs.h"
#include <caption/caption.h>
#define NUM_TEXTURES 2
#define NUM_CHANNELS 3
#define MICROSECOND_DEN 1000000
@ -587,6 +589,11 @@ struct audio_cb_info {
void *param;
};
struct caption_cb_info {
obs_source_caption_t callback;
void *param;
};
struct obs_source {
struct obs_context_data context;
struct obs_source_info info;
@ -690,6 +697,9 @@ struct obs_source {
uint32_t async_convert_width[MAX_AV_PLANES];
uint32_t async_convert_height[MAX_AV_PLANES];
pthread_mutex_t caption_cb_mutex;
DARRAY(struct caption_cb_info) caption_cb_list;
/* async video deinterlacing */
uint64_t deinterlace_offset;
uint64_t deinterlace_frame_ts;
@ -977,6 +987,8 @@ struct obs_output {
struct caption_text *caption_head;
struct caption_text *caption_tail;
struct circlebuf caption_data;
bool valid;
uint64_t active_delay_ns;

View file

@ -23,10 +23,12 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#if defined(__FreeBSD__)
#if defined(__FreeBSD__) || defined(__OpenBSD__)
#include <sys/sysctl.h>
#endif
#if !defined(__OpenBSD__)
#include <sys/sysinfo.h>
#endif
#include <sys/utsname.h>
#include <xcb/xcb.h>
#if USE_XINPUT
@ -155,9 +157,10 @@ static void log_processor_info(void)
dstr_free(&proc_speed);
free(line);
}
#elif defined(__FreeBSD__)
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
static void log_processor_speed(void)
{
#ifndef __OpenBSD__
char *line = NULL;
size_t linecap = 0;
FILE *fp;
@ -187,6 +190,7 @@ static void log_processor_speed(void)
fclose(fp);
dstr_free(&proc_speed);
free(line);
#endif
}
static void log_processor_name(void)
@ -218,6 +222,19 @@ static void log_processor_info(void)
static void log_memory_info(void)
{
#if defined(__OpenBSD__)
int mib[2];
size_t len;
int64_t mem;
mib[0] = CTL_HW;
mib[1] = HW_PHYSMEM64;
len = sizeof(mem);
if (sysctl(mib, 2, &mem, &len, NULL, 0) >= 0)
blog(LOG_INFO, "Physical Memory: %" PRIi64 "MB Total",
mem / 1024 / 1024);
#else
struct sysinfo info;
if (sysinfo(&info) < 0)
return;
@ -227,6 +244,7 @@ static void log_memory_info(void)
(uint64_t)info.totalram * info.mem_unit / 1024 / 1024,
((uint64_t)info.freeram + (uint64_t)info.bufferram) *
info.mem_unit / 1024 / 1024);
#endif
}
static void log_kernel_version(void)
@ -312,6 +330,14 @@ static void log_distribution_info(void)
dstr_free(&distro);
free(line);
}
static void log_desktop_session_info(void)
{
char *session_ptr = getenv("XDG_SESSION_TYPE");
if (session_ptr) {
blog(LOG_INFO, "Session Type: %s", session_ptr);
}
}
#endif
void log_system_info(void)
@ -324,6 +350,7 @@ void log_system_info(void)
log_kernel_version();
#if defined(__linux__)
log_distribution_info();
log_desktop_session_info();
#endif
log_x_info();
}

View file

@ -21,10 +21,8 @@
#include "obs.h"
#include "obs-internal.h"
#if BUILD_CAPTIONS
#include <caption/caption.h>
#include <caption/mpeg.h>
#endif
static inline bool active(const struct obs_output *output)
{
@ -227,6 +225,7 @@ void obs_output_destroy(obs_output_t *output)
os_event_destroy(output->reconnect_stop_event);
obs_context_data_free(&output->context);
circlebuf_free(&output->delay_data);
circlebuf_free(&output->caption_data);
if (output->owns_info_id)
bfree((void *)output->info.id);
if (output->last_error_message)
@ -267,6 +266,10 @@ bool obs_output_actual_start(obs_output_t *output)
os_atomic_dec_long(&output->delay_restart_refs);
output->caption_timestamp = 0;
circlebuf_free(&output->caption_data);
circlebuf_init(&output->caption_data);
return success;
}
@ -1201,13 +1204,11 @@ static inline bool has_higher_opposing_ts(struct obs_output *output,
return output->highest_video_ts > packet->dts_usec;
}
#if BUILD_CAPTIONS
static const uint8_t nal_start[4] = {0, 0, 0, 1};
static bool add_caption(struct obs_output *output, struct encoder_packet *out)
{
struct encoder_packet backup = *out;
caption_frame_t cf;
sei_t sei;
uint8_t *data;
size_t size;
@ -1224,10 +1225,62 @@ static bool add_caption(struct obs_output *output, struct encoder_packet *out)
da_push_back_array(out_data, &ref, sizeof(ref));
da_push_back_array(out_data, out->data, out->size);
caption_frame_init(&cf);
caption_frame_from_text(&cf, &output->caption_head->text[0]);
if (output->caption_data.size > 0) {
sei_from_caption_frame(&sei, &cf);
cea708_t cea708;
cea708_init(&cea708, 0); // set up a new popon frame
void *caption_buf = bzalloc(3 * sizeof(uint8_t));
while (output->caption_data.size > 0) {
circlebuf_pop_front(&output->caption_data, caption_buf,
3 * sizeof(uint8_t));
if ((((uint8_t *)caption_buf)[0] & 0x3) != 0) {
// only send cea 608
continue;
}
uint16_t captionData = ((uint8_t *)caption_buf)[1];
captionData = captionData << 8;
captionData += ((uint8_t *)caption_buf)[2];
// padding
if (captionData == 0x8080) {
continue;
}
if (captionData == 0) {
continue;
}
if (!eia608_parity_varify(captionData)) {
continue;
}
cea708_add_cc_data(&cea708, 1,
((uint8_t *)caption_buf)[0] & 0x3,
captionData);
}
bfree(caption_buf);
sei_message_t *msg =
sei_message_new(sei_type_user_data_registered_itu_t_t35,
0, CEA608_MAX_SIZE);
msg->size = cea708_render(&cea708, sei_message_data(msg),
sei_message_size(msg));
sei_message_append(&sei, msg);
} else if (output->caption_head) {
caption_frame_t cf;
caption_frame_init(&cf);
caption_frame_from_text(&cf, &output->caption_head->text[0]);
sei_from_caption_frame(&sei, &cf);
struct caption_text *next = output->caption_head->next;
bfree(output->caption_head);
output->caption_head = next;
}
data = malloc(sei_render_size(&sei));
size = sei_render(&sei, data);
@ -1244,12 +1297,10 @@ static bool add_caption(struct obs_output *output, struct encoder_packet *out)
sei_free(&sei);
struct caption_text *next = output->caption_head->next;
bfree(output->caption_head);
output->caption_head = next;
return true;
}
#endif
double last_caption_timestamp = 0;
static inline void send_interleaved(struct obs_output *output)
{
@ -1266,7 +1317,6 @@ static inline void send_interleaved(struct obs_output *output)
if (out.type == OBS_ENCODER_VIDEO) {
output->total_frames++;
#if BUILD_CAPTIONS
pthread_mutex_lock(&output->caption_mutex);
double frame_timestamp =
@ -1286,8 +1336,14 @@ static inline void send_interleaved(struct obs_output *output)
}
}
if (output->caption_data.size > 0) {
if (last_caption_timestamp < frame_timestamp) {
last_caption_timestamp = frame_timestamp;
add_caption(output, &out);
}
}
pthread_mutex_unlock(&output->caption_mutex);
#endif
}
output->info.encoded_packet(output->context.data, &out);
@ -2471,7 +2527,18 @@ const char *obs_output_get_id(const obs_output_t *output)
: NULL;
}
#if BUILD_CAPTIONS
void obs_output_caption(obs_output_t *output,
const struct obs_source_cea_708 *captions)
{
pthread_mutex_lock(&output->caption_mutex);
for (size_t i = 0; i < captions->packets; i++) {
circlebuf_push_back(&output->caption_data,
captions->data + (i * 3),
3 * sizeof(uint8_t));
}
pthread_mutex_unlock(&output->caption_mutex);
}
static struct caption_text *caption_text_new(const char *text, size_t bytes,
struct caption_text *tail,
struct caption_text **head,
@ -2518,7 +2585,6 @@ void obs_output_output_caption_text2(obs_output_t *output, const char *text,
pthread_mutex_unlock(&output->caption_mutex);
}
#endif
float obs_output_get_congestion(obs_output_t *output)
{

View file

@ -418,3 +418,51 @@ const char *obs_service_get_output_type(const obs_service_t *service)
return service->info.get_output_type(service->context.data);
return NULL;
}
void obs_service_get_supported_resolutions(
const obs_service_t *service,
struct obs_service_resolution **resolutions, size_t *count)
{
if (!obs_service_valid(service, "obs_service_supported_resolutions"))
return;
if (!obs_ptr_valid(resolutions, "obs_service_supported_resolutions"))
return;
if (!obs_ptr_valid(count, "obs_service_supported_resolutions"))
return;
*resolutions = NULL;
*count = 0;
if (service->info.get_supported_resolutions)
service->info.get_supported_resolutions(service->context.data,
resolutions, count);
}
void obs_service_get_max_fps(const obs_service_t *service, int *fps)
{
if (!obs_service_valid(service, "obs_service_get_max_fps"))
return;
if (!obs_ptr_valid(fps, "obs_service_get_max_fps"))
return;
*fps = 0;
if (service->info.get_max_fps)
service->info.get_max_fps(service->context.data, fps);
}
void obs_service_get_max_bitrate(const obs_service_t *service,
int *video_bitrate, int *audio_bitrate)
{
if (video_bitrate)
*video_bitrate = 0;
if (audio_bitrate)
*audio_bitrate = 0;
if (!obs_service_valid(service, "obs_service_get_max_bitrate"))
return;
if (service->info.get_max_bitrate)
service->info.get_max_bitrate(service->context.data,
video_bitrate, audio_bitrate);
}

View file

@ -28,6 +28,11 @@
extern "C" {
#endif
struct obs_service_resolution {
int cx;
int cy;
};
struct obs_service_info {
/* required */
const char *id;
@ -74,7 +79,13 @@ struct obs_service_info {
const char *(*get_output_type)(void *data);
/* TODO: more stuff later */
void (*get_supported_resolutions)(
void *data, struct obs_service_resolution **resolutions,
size_t *count);
void (*get_max_fps)(void *data, int *fps);
void (*get_max_bitrate)(void *data, int *video_bitrate,
int *audio_bitrate);
};
EXPORT void obs_register_service_s(const struct obs_service_info *info,

View file

@ -31,6 +31,8 @@
#include "obs.h"
#include "obs-internal.h"
static bool filter_compatible(obs_source_t *source, obs_source_t *filter);
static inline bool data_valid(const struct obs_source *source, const char *f)
{
return obs_source_valid(source, f) && source->context.data;
@ -182,6 +184,7 @@ static bool obs_source_init(struct obs_source *source)
pthread_mutex_init_value(&source->audio_mutex);
pthread_mutex_init_value(&source->audio_buf_mutex);
pthread_mutex_init_value(&source->audio_cb_mutex);
pthread_mutex_init_value(&source->caption_cb_mutex);
if (pthread_mutexattr_init(&attr) != 0)
return false;
@ -199,6 +202,8 @@ static bool obs_source_init(struct obs_source *source)
return false;
if (pthread_mutex_init(&source->async_mutex, NULL) != 0)
return false;
if (pthread_mutex_init(&source->caption_cb_mutex, NULL) != 0)
return false;
if (is_audio_source(source) || is_composite_source(source))
allocate_audio_output_buffer(source);
@ -493,6 +498,32 @@ void obs_source_copy_filters(obs_source_t *dst, obs_source_t *src)
duplicate_filters(dst, src, dst->context.private);
}
static void duplicate_filter(obs_source_t *dst, obs_source_t *filter)
{
if (!filter_compatible(dst, filter))
return;
char *new_name = get_new_filter_name(dst, filter->context.name);
bool enabled = obs_source_enabled(filter);
obs_source_t *dst_filter = obs_source_duplicate(filter, new_name, true);
obs_source_set_enabled(dst_filter, enabled);
bfree(new_name);
obs_source_filter_add(dst, dst_filter);
obs_source_release(dst_filter);
}
void obs_source_copy_single_filter(obs_source_t *dst, obs_source_t *filter)
{
if (!obs_source_valid(dst, "obs_source_copy_single_filter"))
return;
if (!obs_source_valid(filter, "obs_source_copy_single_filter"))
return;
duplicate_filter(dst, filter);
}
obs_source_t *obs_source_duplicate(obs_source_t *source, const char *new_name,
bool create_private)
{
@ -655,6 +686,7 @@ void obs_source_destroy(struct obs_source *source)
da_free(source->audio_actions);
da_free(source->audio_cb_list);
da_free(source->caption_cb_list);
da_free(source->async_cache);
da_free(source->async_frames);
da_free(source->filters);
@ -663,6 +695,7 @@ void obs_source_destroy(struct obs_source *source)
pthread_mutex_destroy(&source->audio_buf_mutex);
pthread_mutex_destroy(&source->audio_cb_mutex);
pthread_mutex_destroy(&source->audio_mutex);
pthread_mutex_destroy(&source->caption_cb_mutex);
pthread_mutex_destroy(&source->async_mutex);
obs_data_release(source->private_settings);
obs_context_data_free(&source->context);
@ -2870,6 +2903,51 @@ void obs_source_set_async_rotation(obs_source_t *source, long rotation)
source->async_rotation = rotation;
}
void obs_source_output_cea708(obs_source_t *source,
const struct obs_source_cea_708 *captions)
{
if (!captions) {
return;
}
pthread_mutex_lock(&source->caption_cb_mutex);
for (size_t i = source->caption_cb_list.num; i > 0; i--) {
struct caption_cb_info info =
source->caption_cb_list.array[i - 1];
info.callback(info.param, source, captions);
}
pthread_mutex_unlock(&source->caption_cb_mutex);
}
void obs_source_add_caption_callback(obs_source_t *source,
obs_source_caption_t callback, void *param)
{
struct caption_cb_info info = {callback, param};
if (!obs_source_valid(source, "obs_source_add_caption_callback"))
return;
pthread_mutex_lock(&source->caption_cb_mutex);
da_push_back(source->caption_cb_list, &info);
pthread_mutex_unlock(&source->caption_cb_mutex);
}
void obs_source_remove_caption_callback(obs_source_t *source,
obs_source_caption_t callback,
void *param)
{
struct caption_cb_info info = {callback, param};
if (!obs_source_valid(source, "obs_source_remove_caption_callback"))
return;
pthread_mutex_lock(&source->caption_cb_mutex);
da_erase_item(source->caption_cb_list, &info);
pthread_mutex_unlock(&source->caption_cb_mutex);
}
static inline bool preload_frame_changed(obs_source_t *source,
const struct obs_source_frame *in)
{

View file

@ -186,6 +186,11 @@ enum obs_media_state {
*/
#define OBS_SOURCE_CONTROLLABLE_MEDIA (1 << 13)
/**
* Source type provides cea708 data
*/
#define OBS_SOURCE_CEA_708 (1 << 14)
/** @} */
typedef void (*obs_source_enum_proc_t)(obs_source_t *parent,

View file

@ -212,6 +212,12 @@ struct obs_source_audio {
uint64_t timestamp;
};
struct obs_source_cea_708 {
const uint8_t *data;
uint32_t packets;
uint64_t timestamp;
};
/**
* Source asynchronous video output structure. Used with
* obs_source_output_video to output asynchronous video. Video is buffered as
@ -1085,6 +1091,8 @@ EXPORT obs_source_t *obs_source_get_filter_by_name(obs_source_t *source,
const char *name);
EXPORT void obs_source_copy_filters(obs_source_t *dst, obs_source_t *src);
EXPORT void obs_source_copy_single_filter(obs_source_t *dst,
obs_source_t *filter);
EXPORT bool obs_source_enabled(const obs_source_t *source);
EXPORT void obs_source_set_enabled(obs_source_t *source, bool enabled);
@ -1115,6 +1123,16 @@ EXPORT void obs_source_add_audio_capture_callback(
EXPORT void obs_source_remove_audio_capture_callback(
obs_source_t *source, obs_source_audio_capture_t callback, void *param);
typedef void (*obs_source_caption_t)(void *param, obs_source_t *source,
const struct obs_source_cea_708 *captions);
EXPORT void obs_source_add_caption_callback(obs_source_t *source,
obs_source_caption_t callback,
void *param);
EXPORT void obs_source_remove_caption_callback(obs_source_t *source,
obs_source_caption_t callback,
void *param);
enum obs_deinterlace_mode {
OBS_DEINTERLACE_MODE_DISABLE,
OBS_DEINTERLACE_MODE_DISCARD,
@ -1206,6 +1224,9 @@ EXPORT void obs_source_output_video2(obs_source_t *source,
EXPORT void obs_source_set_async_rotation(obs_source_t *source, long rotation);
EXPORT void obs_source_output_cea708(obs_source_t *source,
const struct obs_source_cea_708 *captions);
/**
* Preloads asynchronous video data to allow instantaneous playback
*
@ -1882,13 +1903,14 @@ EXPORT uint32_t obs_output_get_height(const obs_output_t *output);
EXPORT const char *obs_output_get_id(const obs_output_t *output);
#if BUILD_CAPTIONS
EXPORT void obs_output_caption(obs_output_t *output,
const struct obs_source_cea_708 *captions);
EXPORT void obs_output_output_caption_text1(obs_output_t *output,
const char *text);
EXPORT void obs_output_output_caption_text2(obs_output_t *output,
const char *text,
double display_duration);
#endif
EXPORT float obs_output_get_congestion(obs_output_t *output);
EXPORT int obs_output_get_connect_time_ms(obs_output_t *output);
@ -2209,6 +2231,14 @@ EXPORT void *obs_service_get_type_data(obs_service_t *service);
EXPORT const char *obs_service_get_id(const obs_service_t *service);
EXPORT void obs_service_get_supported_resolutions(
const obs_service_t *service,
struct obs_service_resolution **resolutions, size_t *count);
EXPORT void obs_service_get_max_fps(const obs_service_t *service, int *fps);
EXPORT void obs_service_get_max_bitrate(const obs_service_t *service,
int *video_bitrate, int *audio_bitrate);
/* NOTE: This function is temporary and should be removed/replaced at a later
* date. */
EXPORT const char *obs_service_get_output_type(const obs_service_t *service);

View file

@ -15,7 +15,6 @@
#define OBS_PLUGIN_DESTINATION "@OBS_PLUGIN_DESTINATION@"
#define OBS_RELATIVE_PREFIX "@OBS_RELATIVE_PREFIX@"
#define OBS_UNIX_STRUCTURE @OBS_UNIX_STRUCTURE@
#define BUILD_CAPTIONS @BUILD_CAPTIONS@
#define HAVE_DBUS @HAVE_DBUS@
#define HAVE_PULSEAUDIO @HAVE_PULSEAUDIO@
#define USE_XINPUT @USE_XINPUT@

52
libobs/util/bitstream.c Normal file
View file

@ -0,0 +1,52 @@
#include "bitstream.h"
#include <stdlib.h>
#include <string.h>
void bitstream_reader_init(struct bitstream_reader *r, uint8_t *data,
size_t len)
{
memset(r, 0, sizeof(struct bitstream_reader));
r->buf = data;
r->subPos = 0x80;
r->len = len;
}
uint8_t bitstream_reader_read_bit(struct bitstream_reader *r)
{
if (r->pos >= r->len)
return 0;
uint8_t bit = (*(r->buf + r->pos) & r->subPos) == r->subPos ? 1 : 0;
r->subPos >>= 0x1;
if (r->subPos == 0) {
r->subPos = 0x80;
r->pos++;
}
return bit;
}
uint8_t bitstream_reader_read_bits(struct bitstream_reader *r, int bits)
{
uint8_t res = 0;
for (int i = 1; i <= bits; i++) {
res <<= 1;
res |= bitstream_reader_read_bit(r);
}
return res;
}
uint8_t bitstream_reader_r8(struct bitstream_reader *r)
{
return bitstream_reader_read_bits(r, 8);
}
uint16_t bitstream_reader_r16(struct bitstream_reader *r)
{
uint8_t b = bitstream_reader_read_bits(r, 8);
return ((uint16_t)b << 8) | bitstream_reader_read_bits(r, 8);
}

29
libobs/util/bitstream.h Normal file
View file

@ -0,0 +1,29 @@
#pragma once
#include "c99defs.h"
/*
* General programmable serialization functions. (A shared interface to
* various reading/writing to/from different inputs/outputs)
*/
#ifdef __cplusplus
extern "C" {
#endif
struct bitstream_reader {
uint8_t pos;
uint8_t subPos;
uint8_t *buf;
size_t len;
};
EXPORT void bitstream_reader_init(struct bitstream_reader *r, uint8_t *data,
size_t len);
EXPORT uint8_t bitstream_reader_read_bits(struct bitstream_reader *r, int bits);
EXPORT uint8_t bitstream_reader_r8(struct bitstream_reader *r);
EXPORT uint16_t bitstream_reader_r16(struct bitstream_reader *r);
#ifdef __cplusplus
}
#endif

View file

@ -57,11 +57,15 @@ static inline bool create_process(const char *cmd_line, HANDLE stdin_handle,
si.hStdOutput = stdout_handle;
si.hStdError = stderr_handle;
DWORD flags = 0;
#ifndef SHOW_SUBPROCESSES
flags = CREATE_NO_WINDOW;
#endif
os_utf8_to_wcs_ptr(cmd_line, 0, &cmd_line_w);
if (cmd_line_w) {
success = !!CreateProcessW(NULL, cmd_line_w, NULL, NULL, true,
CREATE_NO_WINDOW, NULL, NULL, &si,
&pi);
flags, NULL, NULL, &si, &pi);
if (success) {
*process = pi.hProcess;

View file

@ -34,14 +34,16 @@
#include <sys/times.h>
#include <sys/wait.h>
#include <libgen.h>
#ifdef __FreeBSD__
#if defined(__FreeBSD__) || defined(__OpenBSD__)
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <unistd.h>
#if defined(__FreeBSD__)
#include <libprocstat.h>
#endif
#else
#include <sys/resource.h>
#endif
@ -272,6 +274,62 @@ char *os_get_program_data_path_ptr(const char *name)
return str;
}
#if defined(__OpenBSD__)
// a bit modified version of https://stackoverflow.com/a/31495527
ssize_t os_openbsd_get_executable_path(char *epath)
{
int mib[4];
char **argv;
size_t len;
const char *comm;
int ok = 0;
mib[0] = CTL_KERN;
mib[1] = KERN_PROC_ARGS;
mib[2] = getpid();
mib[3] = KERN_PROC_ARGV;
if (sysctl(mib, 4, NULL, &len, NULL, 0) < 0)
abort();
if (!(argv = malloc(len)))
abort();
if (sysctl(mib, 4, argv, &len, NULL, 0) < 0)
abort();
comm = argv[0];
if (*comm == '/' || *comm == '.') {
if (realpath(comm, epath))
ok = 1;
} else {
char *sp;
char *xpath = strdup(getenv("PATH"));
char *path = strtok_r(xpath, ":", &sp);
struct stat st;
if (!xpath)
abort();
while (path) {
snprintf(epath, PATH_MAX, "%s/%s", path, comm);
if (!stat(epath, &st) && (st.st_mode & S_IXUSR)) {
ok = 1;
break;
}
path = strtok_r(NULL, ":", &sp);
}
free(xpath);
}
free(argv);
return ok ? (ssize_t)strlen(epath) : -1;
}
#endif
char *os_get_executable_path_ptr(const char *name)
{
char exe[PATH_MAX];
@ -286,6 +344,8 @@ char *os_get_executable_path_ptr(const char *name)
return NULL;
}
count = pathlen;
#elif defined(__OpenBSD__)
ssize_t count = os_openbsd_get_executable_path(exe);
#else
ssize_t count = readlink("/proc/self/exe", exe, PATH_MAX - 1);
if (count >= 0) {

View file

@ -1058,7 +1058,11 @@ bool profiler_snapshot_dump_csv_gz(const profiler_snapshot_t *snap,
profiler_snapshot_dump(snap, dump_csv_gzwrite, gz);
#ifdef _WIN32
gzclose_w(gz);
#else
gzclose(gz);
#endif
return true;
}