New upstream version 26.0.0+dfsg1
This commit is contained in:
parent
8e020cdacb
commit
240080891f
837 changed files with 41275 additions and 9196 deletions
|
|
@ -13,6 +13,7 @@ endif()
|
|||
|
||||
if(UNIX)
|
||||
if (NOT APPLE)
|
||||
find_package(X11 REQUIRED)
|
||||
find_package(X11_XCB REQUIRED)
|
||||
find_package(XCB OPTIONAL_COMPONENTS XINPUT)
|
||||
if (XCB_XINPUT_FOUND)
|
||||
|
|
@ -74,7 +75,7 @@ endif()
|
|||
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
||||
include_directories(SYSTEM ${ZLIB_INCLUDE_DIR})
|
||||
include_directories(SYSTEM ${ZLIB_INCLUDE_DIRS})
|
||||
|
||||
add_definitions(-DLIBOBS_EXPORTS)
|
||||
|
||||
|
|
@ -221,11 +222,13 @@ elseif(UNIX)
|
|||
endif()
|
||||
|
||||
include_directories(
|
||||
${X11_X11_INCLUDE_PATH}
|
||||
${X11_XCB_INCLUDE_DIRS})
|
||||
add_definitions(
|
||||
${X11_XCB_DEFINITIONS})
|
||||
set(libobs_PLATFORM_DEPS
|
||||
${libobs_PLATFORM_DEPS}
|
||||
${X11_X11_LIB}
|
||||
${X11_XCB_LIBRARIES})
|
||||
|
||||
if(USE_XINPUT)
|
||||
|
|
@ -362,6 +365,7 @@ set(libobs_util_SOURCES
|
|||
set(libobs_util_HEADERS
|
||||
util/curl/curl-helper.h
|
||||
util/sse-intrin.h
|
||||
util/sse2neon.h
|
||||
util/array-serializer.h
|
||||
util/file-serializer.h
|
||||
util/utf8.h
|
||||
|
|
@ -370,6 +374,7 @@ set(libobs_util_HEADERS
|
|||
util/text-lookup.h
|
||||
util/bmem.h
|
||||
util/c99defs.h
|
||||
util/util_uint64.h
|
||||
util/util_uint128.h
|
||||
util/cf-parser.h
|
||||
util/threading.h
|
||||
|
|
@ -475,11 +480,15 @@ if(UNIX AND NOT APPLE)
|
|||
foreach(LIB "obs" "rt")
|
||||
set(PRIVATE_LIBS "${PRIVATE_LIBS} -l${LIB}")
|
||||
endforeach()
|
||||
if(LOWERCASE_CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64(le)?")
|
||||
set(PPC64_CFLAGS "-DNO_WARN_X86_INTRINSICS -mvsx")
|
||||
endif()
|
||||
CONFIGURE_FILE("libobs.pc.in" "libobs.pc" @ONLY)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libobs.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
endif()
|
||||
|
||||
set_target_properties(libobs PROPERTIES
|
||||
FOLDER "core"
|
||||
OUTPUT_NAME obs
|
||||
VERSION "0"
|
||||
SOVERSION "0")
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "../../util/circlebuf.h"
|
||||
#include "../../util/platform.h"
|
||||
#include "../../util/darray.h"
|
||||
#include "../../util/util_uint64.h"
|
||||
#include "../../obs-internal.h"
|
||||
|
||||
#include "wasapi-output.h"
|
||||
|
|
@ -78,8 +79,8 @@ static bool process_audio_delay(struct audio_monitor *monitor, float **data,
|
|||
monitor->prev_video_ts = last_frame_ts;
|
||||
|
||||
} else if (monitor->prev_video_ts == last_frame_ts) {
|
||||
monitor->time_since_prev += (uint64_t)*frames * 1000000000ULL /
|
||||
(uint64_t)monitor->sample_rate;
|
||||
monitor->time_since_prev += util_mul_div64(
|
||||
*frames, 1000000000ULL, monitor->sample_rate);
|
||||
} else {
|
||||
monitor->time_since_prev = 0;
|
||||
}
|
||||
|
|
@ -90,8 +91,8 @@ static bool process_audio_delay(struct audio_monitor *monitor, float **data,
|
|||
|
||||
circlebuf_peek_front(&monitor->delay_buffer, &cur_ts,
|
||||
sizeof(ts));
|
||||
front_ts = cur_ts - ((uint64_t)pad * 1000000000ULL /
|
||||
(uint64_t)monitor->sample_rate);
|
||||
front_ts = cur_ts - util_mul_div64(pad, 1000000000ULL,
|
||||
monitor->sample_rate);
|
||||
diff = (int64_t)front_ts - (int64_t)last_frame_ts;
|
||||
bad_diff = !last_frame_ts || llabs(diff) > 5000000000 ||
|
||||
monitor->time_since_prev > 100000000ULL;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libswscale/swscale.h>
|
||||
|
||||
#include "../obs-ffmpeg-compat.h"
|
||||
|
|
@ -10,9 +11,6 @@ struct ffmpeg_image {
|
|||
const char *file;
|
||||
AVFormatContext *fmt_ctx;
|
||||
AVCodecContext *decoder_ctx;
|
||||
AVCodec *decoder;
|
||||
AVStream *stream;
|
||||
int stream_idx;
|
||||
|
||||
int cx, cy;
|
||||
enum AVPixelFormat format;
|
||||
|
|
@ -20,26 +18,46 @@ struct ffmpeg_image {
|
|||
|
||||
static bool ffmpeg_image_open_decoder_context(struct ffmpeg_image *info)
|
||||
{
|
||||
int ret = av_find_best_stream(info->fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, 1,
|
||||
NULL, 0);
|
||||
AVFormatContext *const fmt_ctx = info->fmt_ctx;
|
||||
int ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, 1, NULL,
|
||||
0);
|
||||
if (ret < 0) {
|
||||
blog(LOG_WARNING, "Couldn't find video stream in file '%s': %s",
|
||||
info->file, av_err2str(ret));
|
||||
return false;
|
||||
}
|
||||
|
||||
info->stream_idx = ret;
|
||||
info->stream = info->fmt_ctx->streams[ret];
|
||||
info->decoder_ctx = info->stream->codec;
|
||||
info->decoder = avcodec_find_decoder(info->decoder_ctx->codec_id);
|
||||
|
||||
if (!info->decoder) {
|
||||
AVStream *const stream = fmt_ctx->streams[ret];
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
|
||||
AVCodecParameters *const codecpar = stream->codecpar;
|
||||
AVCodec *const decoder = avcodec_find_decoder(codecpar->codec_id);
|
||||
#else
|
||||
AVCodecContext *const decoder_ctx = stream->codec;
|
||||
AVCodec *const decoder = avcodec_find_decoder(decoder_ctx->codec_id);
|
||||
#endif
|
||||
if (!decoder) {
|
||||
blog(LOG_WARNING, "Failed to find decoder for file '%s'",
|
||||
info->file);
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = avcodec_open2(info->decoder_ctx, info->decoder, NULL);
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
|
||||
AVCodecContext *const decoder_ctx = avcodec_alloc_context3(decoder);
|
||||
avcodec_parameters_to_context(decoder_ctx, codecpar);
|
||||
#endif
|
||||
|
||||
info->decoder_ctx = decoder_ctx;
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
|
||||
info->cx = codecpar->width;
|
||||
info->cy = codecpar->height;
|
||||
info->format = codecpar->format;
|
||||
#else
|
||||
info->cx = decoder_ctx->width;
|
||||
info->cy = decoder_ctx->height;
|
||||
info->format = decoder_ctx->pix_fmt;
|
||||
#endif
|
||||
|
||||
ret = avcodec_open2(decoder_ctx, decoder, NULL);
|
||||
if (ret < 0) {
|
||||
blog(LOG_WARNING,
|
||||
"Failed to open video codec for file '%s': "
|
||||
|
|
@ -53,7 +71,11 @@ static bool ffmpeg_image_open_decoder_context(struct ffmpeg_image *info)
|
|||
|
||||
static void ffmpeg_image_free(struct ffmpeg_image *info)
|
||||
{
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
|
||||
avcodec_free_context(&info->decoder_ctx);
|
||||
#else
|
||||
avcodec_close(info->decoder_ctx);
|
||||
#endif
|
||||
avformat_close_input(&info->fmt_ctx);
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +88,6 @@ static bool ffmpeg_image_init(struct ffmpeg_image *info, const char *file)
|
|||
|
||||
memset(info, 0, sizeof(struct ffmpeg_image));
|
||||
info->file = file;
|
||||
info->stream_idx = -1;
|
||||
|
||||
ret = avformat_open_input(&info->fmt_ctx, file, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
|
|
@ -87,9 +108,6 @@ static bool ffmpeg_image_init(struct ffmpeg_image *info, const char *file)
|
|||
if (!ffmpeg_image_open_decoder_context(info))
|
||||
goto fail;
|
||||
|
||||
info->cx = info->decoder_ctx->width;
|
||||
info->cy = info->decoder_ctx->height;
|
||||
info->format = info->decoder_ctx->pix_fmt;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
|
|
@ -122,9 +140,11 @@ static bool ffmpeg_image_reformat_frame(struct ffmpeg_image *info,
|
|||
}
|
||||
|
||||
} else {
|
||||
static const enum AVPixelFormat format = AV_PIX_FMT_BGRA;
|
||||
|
||||
sws_ctx = sws_getContext(info->cx, info->cy, info->format,
|
||||
info->cx, info->cy, AV_PIX_FMT_BGRA,
|
||||
SWS_POINT, NULL, NULL, NULL);
|
||||
info->cx, info->cy, format, SWS_POINT,
|
||||
NULL, NULL, NULL);
|
||||
if (!sws_ctx) {
|
||||
blog(LOG_WARNING,
|
||||
"Failed to create scale context "
|
||||
|
|
@ -133,17 +153,36 @@ static bool ffmpeg_image_reformat_frame(struct ffmpeg_image *info,
|
|||
return false;
|
||||
}
|
||||
|
||||
uint8_t *pointers[4];
|
||||
int linesizes[4];
|
||||
ret = av_image_alloc(pointers, linesizes, info->cx, info->cy,
|
||||
format, 32);
|
||||
if (ret < 0) {
|
||||
blog(LOG_WARNING, "av_image_alloc failed for '%s': %s",
|
||||
info->file, av_err2str(ret));
|
||||
sws_freeContext(sws_ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = sws_scale(sws_ctx, (const uint8_t *const *)frame->data,
|
||||
frame->linesize, 0, info->cy, &out, &linesize);
|
||||
frame->linesize, 0, info->cy, pointers,
|
||||
linesizes);
|
||||
sws_freeContext(sws_ctx);
|
||||
|
||||
if (ret < 0) {
|
||||
blog(LOG_WARNING, "sws_scale failed for '%s': %s",
|
||||
info->file, av_err2str(ret));
|
||||
av_freep(pointers);
|
||||
return false;
|
||||
}
|
||||
|
||||
info->format = AV_PIX_FMT_BGRA;
|
||||
for (size_t y = 0; y < (size_t)info->cy; y++)
|
||||
memcpy(out + y * linesize,
|
||||
pointers[0] + y * linesizes[0], linesize);
|
||||
|
||||
av_freep(pointers);
|
||||
|
||||
info->format = format;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1143,33 +1143,38 @@ void gs_texture_set_image(gs_texture_t *tex, const uint8_t *data,
|
|||
{
|
||||
uint8_t *ptr;
|
||||
uint32_t linesize_out;
|
||||
uint32_t row_copy;
|
||||
int32_t height;
|
||||
int32_t y;
|
||||
size_t row_copy;
|
||||
size_t height;
|
||||
|
||||
if (!gs_valid_p2("gs_texture_set_image", tex, data))
|
||||
return;
|
||||
|
||||
height = (int32_t)gs_texture_get_height(tex);
|
||||
|
||||
if (!gs_texture_map(tex, &ptr, &linesize_out))
|
||||
return;
|
||||
|
||||
row_copy = (linesize < linesize_out) ? linesize : linesize_out;
|
||||
|
||||
height = gs_texture_get_height(tex);
|
||||
|
||||
if (flip) {
|
||||
for (y = height - 1; y >= 0; y--)
|
||||
memcpy(ptr + (uint32_t)y * linesize_out,
|
||||
data + (uint32_t)(height - y - 1) * linesize,
|
||||
row_copy);
|
||||
uint8_t *const end = ptr + height * linesize_out;
|
||||
data += (height - 1) * linesize;
|
||||
while (ptr < end) {
|
||||
memcpy(ptr, data, row_copy);
|
||||
ptr += linesize_out;
|
||||
data -= linesize;
|
||||
}
|
||||
|
||||
} else if (linesize == linesize_out) {
|
||||
memcpy(ptr, data, row_copy * height);
|
||||
|
||||
} else {
|
||||
for (y = 0; y < height; y++)
|
||||
memcpy(ptr + (uint32_t)y * linesize_out,
|
||||
data + (uint32_t)y * linesize, row_copy);
|
||||
uint8_t *const end = ptr + height * linesize_out;
|
||||
while (ptr < end) {
|
||||
memcpy(ptr, data, row_copy);
|
||||
ptr += linesize_out;
|
||||
data += linesize;
|
||||
}
|
||||
}
|
||||
|
||||
gs_texture_unmap(tex);
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ float calc_torquef(float val1, float val2, float torque, float min_adjust,
|
|||
bool over;
|
||||
|
||||
if (close_float(val1, val2, EPSILON))
|
||||
return val1;
|
||||
return val2;
|
||||
|
||||
dist = (val2 - val1) * torque;
|
||||
over = dist > 0.0f;
|
||||
|
|
|
|||
|
|
@ -7,5 +7,5 @@ Name: libobs
|
|||
Description: OBS Studio Library
|
||||
Version: @OBS_VERSION@
|
||||
Requires: x11
|
||||
Cflags: -I${includedir}
|
||||
Cflags: -I${includedir} @PPC64_CFLAGS@
|
||||
Libs: -L${libdir} @PRIVATE_LIBS@
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "../util/circlebuf.h"
|
||||
#include "../util/platform.h"
|
||||
#include "../util/profiler.h"
|
||||
#include "../util/util_uint64.h"
|
||||
|
||||
#include "audio-io.h"
|
||||
#include "audio-resampler.h"
|
||||
|
|
@ -72,51 +73,6 @@ struct audio_output {
|
|||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* the following functions are used to calculate frame offsets based upon
|
||||
* timestamps. this will actually work accurately as long as you handle the
|
||||
* values correctly */
|
||||
|
||||
static inline double ts_to_frames(const audio_t *audio, uint64_t ts)
|
||||
{
|
||||
double audio_offset_d = (double)ts;
|
||||
audio_offset_d /= 1000000000.0;
|
||||
audio_offset_d *= (double)audio->info.samples_per_sec;
|
||||
|
||||
return audio_offset_d;
|
||||
}
|
||||
|
||||
static inline double positive_round(double val)
|
||||
{
|
||||
return floor(val + 0.5);
|
||||
}
|
||||
|
||||
static int64_t ts_diff_frames(const audio_t *audio, uint64_t ts1, uint64_t ts2)
|
||||
{
|
||||
double diff = ts_to_frames(audio, ts1) - ts_to_frames(audio, ts2);
|
||||
return (int64_t)positive_round(diff);
|
||||
}
|
||||
|
||||
static int64_t ts_diff_bytes(const audio_t *audio, uint64_t ts1, uint64_t ts2)
|
||||
{
|
||||
return ts_diff_frames(audio, ts1, ts2) * (int64_t)audio->block_size;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static inline uint64_t min_uint64(uint64_t a, uint64_t b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
static inline size_t min_size(size_t a, size_t b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
#ifndef CLAMP
|
||||
#define CLAMP(val, minval, maxval) \
|
||||
((val > maxval) ? maxval : ((val < minval) ? minval : val))
|
||||
#endif
|
||||
|
||||
static bool resample_audio_output(struct audio_input *input,
|
||||
struct audio_data *data)
|
||||
|
|
@ -219,9 +175,7 @@ static void input_and_output(struct audio_output *audio, uint64_t audio_time,
|
|||
for (size_t mix_idx = 0; mix_idx < MAX_AUDIO_MIXES; mix_idx++) {
|
||||
struct audio_mix *mix = &audio->mixes[mix_idx];
|
||||
|
||||
memset(mix->buffer[0], 0,
|
||||
AUDIO_OUTPUT_FRAMES * MAX_AUDIO_CHANNELS *
|
||||
sizeof(float));
|
||||
memset(mix->buffer, 0, sizeof(mix->buffer));
|
||||
|
||||
for (size_t i = 0; i < audio->planes; i++)
|
||||
data[mix_idx].data[i] = mix->buffer[i];
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#include "media-io-defs.h"
|
||||
#include "../util/c99defs.h"
|
||||
#include "../util/util_uint128.h"
|
||||
#include "../util/util_uint64.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -195,18 +195,12 @@ static inline size_t get_audio_size(enum audio_format format,
|
|||
|
||||
static inline uint64_t audio_frames_to_ns(size_t sample_rate, uint64_t frames)
|
||||
{
|
||||
util_uint128_t val;
|
||||
val = util_mul64_64(frames, 1000000000ULL);
|
||||
val = util_div128_32(val, (uint32_t)sample_rate);
|
||||
return val.low;
|
||||
return util_mul_div64(frames, 1000000000ULL, sample_rate);
|
||||
}
|
||||
|
||||
static inline uint64_t ns_to_audio_frames(size_t sample_rate, uint64_t frames)
|
||||
{
|
||||
util_uint128_t val;
|
||||
val = util_mul64_64(frames, sample_rate);
|
||||
val = util_div128_32(val, 1000000000);
|
||||
return val.low;
|
||||
return util_mul_div64(frames, sample_rate, 1000000000ULL);
|
||||
}
|
||||
|
||||
#define AUDIO_OUTPUT_SUCCESS 0
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ static inline bool init_input(media_remux_job_t job, const char *in_filename)
|
|||
return false;
|
||||
}
|
||||
|
||||
#ifndef _NDEBUG
|
||||
#ifndef NDEBUG
|
||||
av_dump_format(job->ifmt_ctx, 0, in_filename, false);
|
||||
#endif
|
||||
return true;
|
||||
|
|
@ -84,8 +84,12 @@ static inline bool init_output(media_remux_job_t job, const char *out_filename)
|
|||
|
||||
for (unsigned i = 0; i < job->ifmt_ctx->nb_streams; i++) {
|
||||
AVStream *in_stream = job->ifmt_ctx->streams[i];
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
|
||||
AVStream *out_stream = avformat_new_stream(job->ofmt_ctx, NULL);
|
||||
#else
|
||||
AVStream *out_stream = avformat_new_stream(
|
||||
job->ofmt_ctx, in_stream->codec->codec);
|
||||
#endif
|
||||
if (!out_stream) {
|
||||
blog(LOG_ERROR, "media_remux: Failed to allocate output"
|
||||
" stream");
|
||||
|
|
@ -93,30 +97,31 @@ static inline bool init_output(media_remux_job_t job, const char *out_filename)
|
|||
}
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
|
||||
AVCodecParameters *par = avcodec_parameters_alloc();
|
||||
ret = avcodec_parameters_from_context(par, in_stream->codec);
|
||||
if (ret == 0)
|
||||
ret = avcodec_parameters_to_context(out_stream->codec,
|
||||
par);
|
||||
avcodec_parameters_free(&par);
|
||||
ret = avcodec_parameters_copy(out_stream->codecpar,
|
||||
in_stream->codecpar);
|
||||
#else
|
||||
ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
|
||||
#endif
|
||||
|
||||
if (ret < 0) {
|
||||
blog(LOG_ERROR, "media_remux: Failed to copy context");
|
||||
blog(LOG_ERROR,
|
||||
"media_remux: Failed to copy parameters");
|
||||
return false;
|
||||
}
|
||||
out_stream->time_base = out_stream->codec->time_base;
|
||||
|
||||
av_dict_copy(&out_stream->metadata, in_stream->metadata, 0);
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
|
||||
out_stream->codecpar->codec_tag = 0;
|
||||
#else
|
||||
out_stream->codec->codec_tag = 0;
|
||||
out_stream->time_base = out_stream->codec->time_base;
|
||||
if (job->ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
|
||||
out_stream->codec->flags |= CODEC_FLAG_GLOBAL_H;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef _NDEBUG
|
||||
#ifndef NDEBUG
|
||||
av_dump_format(job->ofmt_ctx, 0, out_filename, true);
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "../util/profiler.h"
|
||||
#include "../util/threading.h"
|
||||
#include "../util/darray.h"
|
||||
#include "../util/util_uint64.h"
|
||||
|
||||
#include "format-conversion.h"
|
||||
#include "video-io.h"
|
||||
|
|
@ -234,8 +235,8 @@ int video_output_open(video_t **video, struct video_output_info *info)
|
|||
goto fail;
|
||||
|
||||
memcpy(&out->info, info, sizeof(struct video_output_info));
|
||||
out->frame_time = (uint64_t)(1000000000.0 * (double)info->fps_den /
|
||||
(double)info->fps_num);
|
||||
out->frame_time =
|
||||
util_mul_div64(1000000000ULL, info->fps_den, info->fps_num);
|
||||
out->initialized = false;
|
||||
|
||||
if (pthread_mutexattr_init(&attr) != 0)
|
||||
|
|
|
|||
|
|
@ -174,11 +174,12 @@ static inline const char *get_video_format_name(enum video_format format)
|
|||
static inline const char *get_video_colorspace_name(enum video_colorspace cs)
|
||||
{
|
||||
switch (cs) {
|
||||
case VIDEO_CS_DEFAULT:
|
||||
case VIDEO_CS_709:
|
||||
return "709";
|
||||
case VIDEO_CS_601:
|
||||
case VIDEO_CS_DEFAULT:
|
||||
case VIDEO_CS_SRGB:;
|
||||
case VIDEO_CS_SRGB:
|
||||
return "sRGB";
|
||||
case VIDEO_CS_601:;
|
||||
}
|
||||
|
||||
return "601";
|
||||
|
|
|
|||
|
|
@ -171,8 +171,8 @@ bool video_format_get_parameters(enum video_colorspace color_space,
|
|||
matrices_initialized = true;
|
||||
}
|
||||
#endif
|
||||
if (color_space == VIDEO_CS_DEFAULT)
|
||||
color_space = VIDEO_CS_601;
|
||||
if ((color_space == VIDEO_CS_DEFAULT) || (color_space == VIDEO_CS_SRGB))
|
||||
color_space = VIDEO_CS_709;
|
||||
|
||||
for (size_t i = 0; i < NUM_FORMATS; i++) {
|
||||
if (format_info[i].color_space != color_space)
|
||||
|
|
|
|||
|
|
@ -18,11 +18,15 @@
|
|||
#include "../util/bmem.h"
|
||||
#include "video-scaler.h"
|
||||
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libswscale/swscale.h>
|
||||
|
||||
struct video_scaler {
|
||||
struct SwsContext *swscale;
|
||||
int src_height;
|
||||
int dst_heights[4];
|
||||
uint8_t *dst_pointers[4];
|
||||
int dst_linesizes[4];
|
||||
};
|
||||
|
||||
static inline enum AVPixelFormat
|
||||
|
|
@ -87,16 +91,9 @@ static inline int get_ffmpeg_scale_type(enum video_scale_type type)
|
|||
|
||||
static inline const int *get_ffmpeg_coeffs(enum video_colorspace cs)
|
||||
{
|
||||
switch (cs) {
|
||||
case VIDEO_CS_DEFAULT:
|
||||
return sws_getCoefficients(SWS_CS_ITU601);
|
||||
case VIDEO_CS_601:
|
||||
return sws_getCoefficients(SWS_CS_ITU601);
|
||||
case VIDEO_CS_709:
|
||||
return sws_getCoefficients(SWS_CS_ITU709);
|
||||
default:
|
||||
return sws_getCoefficients(SWS_CS_ITU601);
|
||||
}
|
||||
const int colorspace = (cs == VIDEO_CS_601) ? SWS_CS_ITU601
|
||||
: SWS_CS_ITU709;
|
||||
return sws_getCoefficients(colorspace);
|
||||
}
|
||||
|
||||
static inline int get_ffmpeg_range_type(enum video_range_type type)
|
||||
|
|
@ -139,6 +136,28 @@ int video_scaler_create(video_scaler_t **scaler_out,
|
|||
scaler = bzalloc(sizeof(struct video_scaler));
|
||||
scaler->src_height = src->height;
|
||||
|
||||
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format_dst);
|
||||
bool has_plane[4] = {0};
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
has_plane[desc->comp[i].plane] = 1;
|
||||
|
||||
scaler->dst_heights[0] = dst->height;
|
||||
for (size_t i = 1; i < 4; ++i) {
|
||||
if (has_plane[i]) {
|
||||
const int s = (i == 1 || i == 2) ? desc->log2_chroma_h
|
||||
: 0;
|
||||
scaler->dst_heights[i] = dst->height >> s;
|
||||
}
|
||||
}
|
||||
|
||||
ret = av_image_alloc(scaler->dst_pointers, scaler->dst_linesizes,
|
||||
dst->width, dst->height, format_dst, 32);
|
||||
if (ret < 0) {
|
||||
blog(LOG_WARNING,
|
||||
"video_scaler_create: av_image_alloc failed: %d", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
scaler->swscale = sws_getCachedContext(NULL, src->width, src->height,
|
||||
format_src, dst->width,
|
||||
dst->height, format_dst,
|
||||
|
|
@ -169,6 +188,10 @@ void video_scaler_destroy(video_scaler_t *scaler)
|
|||
{
|
||||
if (scaler) {
|
||||
sws_freeContext(scaler->swscale);
|
||||
|
||||
if (scaler->dst_pointers[0])
|
||||
av_freep(scaler->dst_pointers);
|
||||
|
||||
bfree(scaler);
|
||||
}
|
||||
}
|
||||
|
|
@ -182,13 +205,37 @@ bool video_scaler_scale(video_scaler_t *scaler, uint8_t *output[],
|
|||
return false;
|
||||
|
||||
int ret = sws_scale(scaler->swscale, input, (const int *)in_linesize, 0,
|
||||
scaler->src_height, output,
|
||||
(const int *)out_linesize);
|
||||
scaler->src_height, scaler->dst_pointers,
|
||||
scaler->dst_linesizes);
|
||||
if (ret <= 0) {
|
||||
blog(LOG_ERROR, "video_scaler_scale: sws_scale failed: %d",
|
||||
ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t plane = 0; plane < 4; ++plane) {
|
||||
if (!scaler->dst_pointers[plane])
|
||||
continue;
|
||||
|
||||
const size_t scaled_linesize = scaler->dst_linesizes[plane];
|
||||
const size_t plane_linesize = out_linesize[plane];
|
||||
uint8_t *dst = output[plane];
|
||||
const uint8_t *src = scaler->dst_pointers[plane];
|
||||
const size_t height = scaler->dst_heights[plane];
|
||||
if (scaled_linesize == plane_linesize) {
|
||||
memcpy(dst, src, scaled_linesize * height);
|
||||
} else {
|
||||
size_t linesize = scaled_linesize;
|
||||
if (linesize > plane_linesize)
|
||||
linesize = plane_linesize;
|
||||
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
memcpy(dst, src, linesize);
|
||||
dst += plane_linesize;
|
||||
src += scaled_linesize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <inttypes.h>
|
||||
#include "obs-internal.h"
|
||||
#include "util/util_uint64.h"
|
||||
|
||||
struct ts_info {
|
||||
uint64_t start;
|
||||
|
|
@ -41,7 +42,7 @@ static void push_audio_tree(obs_source_t *parent, obs_source_t *source, void *p)
|
|||
|
||||
static inline size_t convert_time_to_frames(size_t sample_rate, uint64_t t)
|
||||
{
|
||||
return (size_t)(t * (uint64_t)sample_rate / 1000000000ULL);
|
||||
return util_mul_div64(t, sample_rate, 1000000000ULL);
|
||||
}
|
||||
|
||||
static inline void mix_audio(struct audio_output_data *mixes,
|
||||
|
|
@ -90,8 +91,8 @@ static void ignore_audio(obs_source_t *source, size_t channels,
|
|||
source->audio_input_buf[ch].size);
|
||||
|
||||
source->last_audio_input_buf_size = 0;
|
||||
source->audio_ts += (uint64_t)num_floats * 1000000000ULL /
|
||||
(uint64_t)sample_rate;
|
||||
source->audio_ts +=
|
||||
util_mul_div64(num_floats, 1000000000ULL, sample_rate);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1804,3 +1804,17 @@ bool obs_hotkeys_platform_is_pressed(obs_hotkeys_platform_t *plat,
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
void *obs_graphics_thread_autorelease(void *param)
|
||||
{
|
||||
@autoreleasepool {
|
||||
return obs_graphics_thread(param);
|
||||
}
|
||||
}
|
||||
|
||||
bool obs_graphics_thread_loop_autorelease(struct obs_graphics_context *context)
|
||||
{
|
||||
@autoreleasepool {
|
||||
return obs_graphics_thread_loop(context);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
/*
|
||||
* Increment if major breaking API changes
|
||||
*/
|
||||
#define LIBOBS_API_MAJOR_VER 25
|
||||
#define LIBOBS_API_MAJOR_VER 26
|
||||
|
||||
/*
|
||||
* Increment if backward-compatible additions
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
*
|
||||
* Reset to zero each major or minor version
|
||||
*/
|
||||
#define LIBOBS_API_PATCH_VER 8
|
||||
#define LIBOBS_API_PATCH_VER 0
|
||||
|
||||
#define MAKE_SEMANTIC_VERSION(major, minor, patch) \
|
||||
((major << 24) | (minor << 16) | patch)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "obs.h"
|
||||
#include "obs-internal.h"
|
||||
#include "util/util_uint64.h"
|
||||
|
||||
#define encoder_active(encoder) os_atomic_load_bool(&encoder->active)
|
||||
#define set_encoder_active(encoder, val) \
|
||||
|
|
@ -1076,8 +1077,7 @@ static inline size_t calc_offset_size(struct obs_encoder *encoder,
|
|||
uint64_t v_start_ts, uint64_t a_start_ts)
|
||||
{
|
||||
uint64_t offset = v_start_ts - a_start_ts;
|
||||
offset = (uint64_t)offset * (uint64_t)encoder->samplerate /
|
||||
1000000000ULL;
|
||||
offset = util_mul_div64(offset, encoder->samplerate, 1000000000ULL);
|
||||
return (size_t)offset * encoder->blocksize;
|
||||
}
|
||||
|
||||
|
|
@ -1124,8 +1124,8 @@ static bool buffer_audio(struct obs_encoder *encoder, struct audio_data *data)
|
|||
|
||||
/* audio starting point still not synced with video starting
|
||||
* point, so don't start audio */
|
||||
end_ts += (uint64_t)data->frames * 1000000000ULL /
|
||||
(uint64_t)encoder->samplerate;
|
||||
end_ts += util_mul_div64(data->frames, 1000000000ULL,
|
||||
encoder->samplerate);
|
||||
if (end_ts <= v_start_ts) {
|
||||
success = false;
|
||||
goto fail;
|
||||
|
|
|
|||
|
|
@ -332,7 +332,7 @@ static void obs_hotkey_pair_second_func(void *data, obs_hotkey_id id,
|
|||
|
||||
if (pair->pressed1 && !pressed)
|
||||
pair->pressed1 = false;
|
||||
else if (pair->func[1](pair->data[0], pair->pair_id, hotkey, pressed))
|
||||
else if (pair->func[1](pair->data[1], pair->pair_id, hotkey, pressed))
|
||||
pair->pressed1 = pressed;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ struct obs_module {
|
|||
void (*unload)(void);
|
||||
void (*post_load)(void);
|
||||
void (*set_locale)(const char *locale);
|
||||
bool (*get_string)(const char *lookup_string,
|
||||
const char **translated_string);
|
||||
void (*free_locale)(void);
|
||||
uint32_t (*ver)(void);
|
||||
void (*set_pointer)(obs_module_t *module);
|
||||
|
|
@ -434,7 +436,27 @@ struct obs_core {
|
|||
|
||||
extern struct obs_core *obs;
|
||||
|
||||
struct obs_graphics_context {
|
||||
uint64_t last_time;
|
||||
uint64_t interval;
|
||||
uint64_t frame_time_total_ns;
|
||||
uint64_t fps_total_ns;
|
||||
uint32_t fps_total_frames;
|
||||
#ifdef _WIN32
|
||||
bool gpu_was_active;
|
||||
#endif
|
||||
bool raw_was_active;
|
||||
bool was_active;
|
||||
const char *video_thread_name;
|
||||
};
|
||||
|
||||
extern void *obs_graphics_thread(void *param);
|
||||
extern bool obs_graphics_thread_loop(struct obs_graphics_context *context);
|
||||
#ifdef __APPLE__
|
||||
extern void *obs_graphics_thread_autorelease(void *param);
|
||||
extern bool
|
||||
obs_graphics_thread_loop_autorelease(struct obs_graphics_context *context);
|
||||
#endif
|
||||
|
||||
extern gs_effect_t *obs_load_effect(gs_effect_t **effect, const char *file);
|
||||
|
||||
|
|
@ -579,7 +601,7 @@ struct obs_source {
|
|||
bool owns_info_id;
|
||||
|
||||
/* signals to call the source update in the video thread */
|
||||
bool defer_update;
|
||||
long defer_update_count;
|
||||
|
||||
/* ensures show/hide are only called once */
|
||||
volatile long show_refs;
|
||||
|
|
|
|||
|
|
@ -55,9 +55,29 @@ static int load_module_exports(struct obs_module *mod, const char *path)
|
|||
mod->name = os_dlsym(mod->module, "obs_module_name");
|
||||
mod->description = os_dlsym(mod->module, "obs_module_description");
|
||||
mod->author = os_dlsym(mod->module, "obs_module_author");
|
||||
mod->get_string = os_dlsym(mod->module, "obs_module_get_string");
|
||||
return MODULE_SUCCESS;
|
||||
}
|
||||
|
||||
bool obs_module_get_locale_string(const obs_module_t *mod,
|
||||
const char *lookup_string,
|
||||
const char **translated_string)
|
||||
{
|
||||
if (mod->get_string) {
|
||||
return mod->get_string(lookup_string, translated_string);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *obs_module_get_locale_text(const obs_module_t *mod,
|
||||
const char *text)
|
||||
{
|
||||
const char *str = text;
|
||||
obs_module_get_locale_string(mod, text, &str);
|
||||
return str;
|
||||
}
|
||||
|
||||
static inline char *get_module_name(const char *file)
|
||||
{
|
||||
static size_t ext_len = 0;
|
||||
|
|
@ -189,6 +209,20 @@ const char *obs_get_module_data_path(obs_module_t *module)
|
|||
return module ? module->data_path : NULL;
|
||||
}
|
||||
|
||||
obs_module_t *obs_get_module(const char *name)
|
||||
{
|
||||
obs_module_t *module = obs->first_module;
|
||||
while (module) {
|
||||
if (strcmp(module->mod_name, name) == 0) {
|
||||
return module;
|
||||
}
|
||||
|
||||
module = module->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *obs_find_module_file(obs_module_t *module, const char *file)
|
||||
{
|
||||
struct dstr output = {0};
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ MODULE_EXTERN const char *obs_module_text(const char *lookup_string);
|
|||
|
||||
/** Helper function for looking up locale if default locale handler was used,
|
||||
* returns true if text found, otherwise false */
|
||||
MODULE_EXTERN bool obs_module_get_string(const char *lookup_string,
|
||||
MODULE_EXPORT bool obs_module_get_string(const char *lookup_string,
|
||||
const char **translated_string);
|
||||
|
||||
/** Helper function that returns the current module */
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <inttypes.h>
|
||||
#include "util/platform.h"
|
||||
#include "util/util_uint64.h"
|
||||
#include "obs.h"
|
||||
#include "obs-internal.h"
|
||||
|
||||
|
|
@ -806,6 +807,13 @@ void obs_output_set_video_encoder(obs_output_t *output, obs_encoder_t *encoder)
|
|||
"encoder passed is not a video encoder");
|
||||
return;
|
||||
}
|
||||
if (active(output)) {
|
||||
blog(LOG_WARNING,
|
||||
"%s: tried to set video encoder on output \"%s\" "
|
||||
"while the output is still active!",
|
||||
__FUNCTION__, output->context.name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (output->video_encoder == encoder)
|
||||
return;
|
||||
|
|
@ -831,6 +839,13 @@ void obs_output_set_audio_encoder(obs_output_t *output, obs_encoder_t *encoder,
|
|||
"encoder passed is not an audio encoder");
|
||||
return;
|
||||
}
|
||||
if (active(output)) {
|
||||
blog(LOG_WARNING,
|
||||
"%s: tried to set audio encoder %d on output \"%s\" "
|
||||
"while the output is still active!",
|
||||
__FUNCTION__, (int)idx, output->context.name);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((output->info.flags & OBS_OUTPUT_MULTI_TRACK) != 0) {
|
||||
if (idx >= MAX_AUDIO_MIXES) {
|
||||
|
|
@ -1017,27 +1032,10 @@ void obs_output_set_audio_conversion(
|
|||
output->audio_conversion_set = true;
|
||||
}
|
||||
|
||||
static inline bool service_supports_multitrack(const struct obs_output *output)
|
||||
{
|
||||
const struct obs_service *service = output->service;
|
||||
|
||||
if (!service || !service->info.supports_multitrack) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return service->info.supports_multitrack(service->context.data);
|
||||
}
|
||||
|
||||
static inline size_t num_audio_mixes(const struct obs_output *output)
|
||||
{
|
||||
size_t mix_count = 1;
|
||||
|
||||
if ((output->info.flags & OBS_OUTPUT_SERVICE) != 0) {
|
||||
if (!service_supports_multitrack(output)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((output->info.flags & OBS_OUTPUT_MULTI_TRACK) != 0) {
|
||||
mix_count = 0;
|
||||
|
||||
|
|
@ -1731,8 +1729,8 @@ static bool prepare_audio(struct obs_output *output,
|
|||
*new = *old;
|
||||
|
||||
if (old->timestamp < output->video_start_ts) {
|
||||
uint64_t duration = (uint64_t)old->frames * 1000000000 /
|
||||
(uint64_t)output->sample_rate;
|
||||
uint64_t duration = util_mul_div64(old->frames, 1000000000ULL,
|
||||
output->sample_rate);
|
||||
uint64_t end_ts = (old->timestamp + duration);
|
||||
uint64_t cutoff;
|
||||
|
||||
|
|
@ -1742,7 +1740,8 @@ static bool prepare_audio(struct obs_output *output,
|
|||
cutoff = output->video_start_ts - old->timestamp;
|
||||
new->timestamp += cutoff;
|
||||
|
||||
cutoff = cutoff * (uint64_t)output->sample_rate / 1000000000;
|
||||
cutoff = util_mul_div64(cutoff, output->sample_rate,
|
||||
1000000000ULL);
|
||||
|
||||
for (size_t i = 0; i < output->planes; i++)
|
||||
new->data[i] += output->audio_size *(uint32_t)cutoff;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
******************************************************************************/
|
||||
|
||||
#include "util/threading.h"
|
||||
#include "util/util_uint64.h"
|
||||
#include "graphics/math-defs.h"
|
||||
#include "obs-scene.h"
|
||||
|
||||
|
|
@ -974,8 +975,8 @@ static void apply_scene_item_audio_actions(struct obs_scene_item *item,
|
|||
if (timestamp < ts)
|
||||
timestamp = ts;
|
||||
|
||||
new_frame_num = (timestamp - ts) * (uint64_t)sample_rate /
|
||||
1000000000ULL;
|
||||
new_frame_num = util_mul_div64(timestamp - ts, sample_rate,
|
||||
1000000000ULL);
|
||||
|
||||
if (ts && new_frame_num >= AUDIO_OUTPUT_FRAMES)
|
||||
break;
|
||||
|
|
@ -1024,8 +1025,8 @@ static bool apply_scene_item_volume(struct obs_scene_item *item, float **buf,
|
|||
pthread_mutex_unlock(&item->actions_mutex);
|
||||
|
||||
if (actions_pending) {
|
||||
uint64_t duration = (uint64_t)AUDIO_OUTPUT_FRAMES *
|
||||
1000000000ULL / (uint64_t)sample_rate;
|
||||
uint64_t duration = util_mul_div64(AUDIO_OUTPUT_FRAMES,
|
||||
1000000000ULL, sample_rate);
|
||||
|
||||
if (!ts || action.timestamp < (ts + duration)) {
|
||||
apply_scene_item_audio_actions(item, buf, ts,
|
||||
|
|
@ -1166,7 +1167,7 @@ const struct obs_source_info scene_info = {
|
|||
.id = "scene",
|
||||
.type = OBS_SOURCE_TYPE_SCENE,
|
||||
.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW |
|
||||
OBS_SOURCE_COMPOSITE,
|
||||
OBS_SOURCE_COMPOSITE | OBS_SOURCE_DO_NOT_DUPLICATE,
|
||||
.get_name = scene_getname,
|
||||
.create = scene_create,
|
||||
.destroy = scene_destroy,
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ struct obs_service_info {
|
|||
const char *(*get_username)(void *data);
|
||||
const char *(*get_password)(void *data);
|
||||
|
||||
bool (*supports_multitrack)(void *data);
|
||||
bool (*deprecated_1)();
|
||||
|
||||
void (*apply_encoder_settings)(void *data,
|
||||
obs_data_t *video_encoder_settings,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
******************************************************************************/
|
||||
|
||||
#include "obs-internal.h"
|
||||
#include "util/util_uint64.h"
|
||||
#include "graphics/math-extra.h"
|
||||
|
||||
#define lock_transition(transition) \
|
||||
|
|
@ -866,7 +867,7 @@ static inline float get_sample_time(obs_source_t *transition,
|
|||
uint64_t ts)
|
||||
{
|
||||
uint64_t sample_ts_offset =
|
||||
(uint64_t)sample * 1000000000ULL / (uint64_t)sample_rate;
|
||||
util_mul_div64(sample, 1000000000ULL, sample_rate);
|
||||
uint64_t i_ts = ts + sample_ts_offset;
|
||||
return calc_time(transition, i_ts);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "media-io/audio-io.h"
|
||||
#include "util/threading.h"
|
||||
#include "util/platform.h"
|
||||
#include "util/util_uint64.h"
|
||||
#include "callback/calldata.h"
|
||||
#include "graphics/matrix3.h"
|
||||
#include "graphics/vec3.h"
|
||||
|
|
@ -501,13 +502,12 @@ obs_source_t *obs_source_duplicate(obs_source_t *source, const char *new_name,
|
|||
if (!obs_source_valid(source, "obs_source_duplicate"))
|
||||
return NULL;
|
||||
|
||||
if ((source->info.output_flags & OBS_SOURCE_DO_NOT_DUPLICATE) != 0) {
|
||||
obs_source_addref(source);
|
||||
return source;
|
||||
}
|
||||
|
||||
if (source->info.type == OBS_SOURCE_TYPE_SCENE) {
|
||||
obs_scene_t *scene = obs_scene_from_source(source);
|
||||
if (scene && !create_private) {
|
||||
obs_source_addref(source);
|
||||
return source;
|
||||
}
|
||||
if (!scene)
|
||||
scene = obs_group_from_source(source);
|
||||
if (!scene)
|
||||
|
|
@ -521,6 +521,11 @@ obs_source_t *obs_source_duplicate(obs_source_t *source, const char *new_name,
|
|||
return new_source;
|
||||
}
|
||||
|
||||
if ((source->info.output_flags & OBS_SOURCE_DO_NOT_DUPLICATE) != 0) {
|
||||
obs_source_addref(source);
|
||||
return source;
|
||||
}
|
||||
|
||||
settings = obs_data_create();
|
||||
obs_data_apply(settings, source->context.settings);
|
||||
|
||||
|
|
@ -855,11 +860,13 @@ uint32_t obs_get_source_output_flags(const char *id)
|
|||
|
||||
static void obs_source_deferred_update(obs_source_t *source)
|
||||
{
|
||||
if (source->context.data && source->info.update)
|
||||
if (source->context.data && source->info.update) {
|
||||
long count = os_atomic_load_long(&source->defer_update_count);
|
||||
source->info.update(source->context.data,
|
||||
source->context.settings);
|
||||
|
||||
source->defer_update = false;
|
||||
os_atomic_compare_swap_long(&source->defer_update_count, count,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
void obs_source_update(obs_source_t *source, obs_data_t *settings)
|
||||
|
|
@ -871,7 +878,7 @@ void obs_source_update(obs_source_t *source, obs_data_t *settings)
|
|||
obs_data_apply(source->context.settings, settings);
|
||||
|
||||
if (source->info.output_flags & OBS_SOURCE_VIDEO) {
|
||||
source->defer_update = true;
|
||||
os_atomic_inc_long(&source->defer_update_count);
|
||||
} else if (source->context.data && source->info.update) {
|
||||
source->info.update(source->context.data,
|
||||
source->context.settings);
|
||||
|
|
@ -1096,7 +1103,7 @@ void obs_source_video_tick(obs_source_t *source, float seconds)
|
|||
if ((source->info.output_flags & OBS_SOURCE_ASYNC) != 0)
|
||||
async_tick(source);
|
||||
|
||||
if (source->defer_update)
|
||||
if (os_atomic_load_long(&source->defer_update_count) > 0)
|
||||
obs_source_deferred_update(source);
|
||||
|
||||
/* reset the filter render texture information once every frame */
|
||||
|
|
@ -1165,13 +1172,13 @@ static inline uint64_t conv_frames_to_time(const size_t sample_rate,
|
|||
if (!sample_rate)
|
||||
return 0;
|
||||
|
||||
return (uint64_t)frames * 1000000000ULL / (uint64_t)sample_rate;
|
||||
return util_mul_div64(frames, 1000000000ULL, sample_rate);
|
||||
}
|
||||
|
||||
static inline size_t conv_time_to_frames(const size_t sample_rate,
|
||||
const uint64_t duration)
|
||||
{
|
||||
return (size_t)(duration * (uint64_t)sample_rate / 1000000000ULL);
|
||||
return (size_t)util_mul_div64(duration, sample_rate, 1000000000ULL);
|
||||
}
|
||||
|
||||
/* maximum buffer size */
|
||||
|
|
@ -1211,6 +1218,7 @@ static void handle_ts_jump(obs_source_t *source, uint64_t expected, uint64_t ts,
|
|||
|
||||
pthread_mutex_lock(&source->audio_buf_mutex);
|
||||
reset_audio_timing(source, ts, os_time);
|
||||
reset_audio_data(source, os_time);
|
||||
pthread_mutex_unlock(&source->audio_buf_mutex);
|
||||
}
|
||||
|
||||
|
|
@ -1235,7 +1243,7 @@ static inline uint64_t uint64_diff(uint64_t ts1, uint64_t ts2)
|
|||
static inline size_t get_buf_placement(audio_t *audio, uint64_t offset)
|
||||
{
|
||||
uint32_t sample_rate = audio_output_get_sample_rate(audio);
|
||||
return (size_t)(offset * (uint64_t)sample_rate / 1000000000ULL);
|
||||
return (size_t)util_mul_div64(offset, sample_rate, 1000000000ULL);
|
||||
}
|
||||
|
||||
static void source_output_audio_place(obs_source_t *source,
|
||||
|
|
@ -2368,7 +2376,7 @@ void obs_source_filter_add(obs_source_t *source, obs_source_t *filter)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!filter_compatible(source, filter)) {
|
||||
if (!source->owns_info_id && !filter_compatible(source, filter)) {
|
||||
pthread_mutex_unlock(&source->filter_mutex);
|
||||
return;
|
||||
}
|
||||
|
|
@ -2882,8 +2890,6 @@ obs_source_preload_video_internal(obs_source_t *source,
|
|||
if (!frame)
|
||||
return;
|
||||
|
||||
obs_enter_graphics();
|
||||
|
||||
if (preload_frame_changed(source, frame)) {
|
||||
obs_source_frame_destroy(source->async_preload_frame);
|
||||
source->async_preload_frame = obs_source_frame_create(
|
||||
|
|
@ -2891,13 +2897,8 @@ obs_source_preload_video_internal(obs_source_t *source,
|
|||
}
|
||||
|
||||
copy_frame_data(source->async_preload_frame, frame);
|
||||
set_async_texture_size(source, source->async_preload_frame);
|
||||
update_async_textures(source, source->async_preload_frame,
|
||||
source->async_textures, source->async_texrender);
|
||||
|
||||
source->last_frame_ts = frame->timestamp;
|
||||
|
||||
obs_leave_graphics();
|
||||
}
|
||||
|
||||
void obs_source_preload_video(obs_source_t *source,
|
||||
|
|
@ -2956,8 +2957,18 @@ void obs_source_show_preloaded_video(obs_source_t *source)
|
|||
if (!obs_source_valid(source, "obs_source_show_preloaded_video"))
|
||||
return;
|
||||
|
||||
if (!source->async_preload_frame)
|
||||
return;
|
||||
|
||||
obs_enter_graphics();
|
||||
|
||||
set_async_texture_size(source, source->async_preload_frame);
|
||||
update_async_textures(source, source->async_preload_frame,
|
||||
source->async_textures, source->async_texrender);
|
||||
source->async_active = true;
|
||||
|
||||
obs_leave_graphics();
|
||||
|
||||
pthread_mutex_lock(&source->audio_buf_mutex);
|
||||
sys_ts = (source->monitoring_type != OBS_MONITORING_TYPE_MONITOR_ONLY)
|
||||
? os_gettime_ns()
|
||||
|
|
@ -2967,6 +2978,82 @@ void obs_source_show_preloaded_video(obs_source_t *source)
|
|||
pthread_mutex_unlock(&source->audio_buf_mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
obs_source_set_video_frame_internal(obs_source_t *source,
|
||||
const struct obs_source_frame *frame)
|
||||
{
|
||||
if (!obs_source_valid(source, "obs_source_set_video_frame"))
|
||||
return;
|
||||
if (!frame)
|
||||
return;
|
||||
|
||||
obs_enter_graphics();
|
||||
|
||||
if (preload_frame_changed(source, frame)) {
|
||||
obs_source_frame_destroy(source->async_preload_frame);
|
||||
source->async_preload_frame = obs_source_frame_create(
|
||||
frame->format, frame->width, frame->height);
|
||||
}
|
||||
|
||||
copy_frame_data(source->async_preload_frame, frame);
|
||||
set_async_texture_size(source, source->async_preload_frame);
|
||||
update_async_textures(source, source->async_preload_frame,
|
||||
source->async_textures, source->async_texrender);
|
||||
|
||||
source->last_frame_ts = frame->timestamp;
|
||||
|
||||
obs_leave_graphics();
|
||||
}
|
||||
|
||||
void obs_source_set_video_frame(obs_source_t *source,
|
||||
const struct obs_source_frame *frame)
|
||||
{
|
||||
if (!frame) {
|
||||
obs_source_preload_video_internal(source, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
struct obs_source_frame new_frame = *frame;
|
||||
new_frame.full_range =
|
||||
format_is_yuv(frame->format) ? new_frame.full_range : true;
|
||||
|
||||
obs_source_set_video_frame_internal(source, &new_frame);
|
||||
}
|
||||
|
||||
void obs_source_set_video_frame2(obs_source_t *source,
|
||||
const struct obs_source_frame2 *frame)
|
||||
{
|
||||
if (!frame) {
|
||||
obs_source_preload_video_internal(source, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
struct obs_source_frame new_frame;
|
||||
enum video_range_type range =
|
||||
resolve_video_range(frame->format, frame->range);
|
||||
|
||||
for (size_t i = 0; i < MAX_AV_PLANES; i++) {
|
||||
new_frame.data[i] = frame->data[i];
|
||||
new_frame.linesize[i] = frame->linesize[i];
|
||||
}
|
||||
|
||||
new_frame.width = frame->width;
|
||||
new_frame.height = frame->height;
|
||||
new_frame.timestamp = frame->timestamp;
|
||||
new_frame.format = frame->format;
|
||||
new_frame.full_range = range == VIDEO_RANGE_FULL;
|
||||
new_frame.flip = frame->flip;
|
||||
|
||||
memcpy(&new_frame.color_matrix, &frame->color_matrix,
|
||||
sizeof(frame->color_matrix));
|
||||
memcpy(&new_frame.color_range_min, &frame->color_range_min,
|
||||
sizeof(frame->color_range_min));
|
||||
memcpy(&new_frame.color_range_max, &frame->color_range_max,
|
||||
sizeof(frame->color_range_max));
|
||||
|
||||
obs_source_set_video_frame_internal(source, &new_frame);
|
||||
}
|
||||
|
||||
static inline struct obs_audio_data *
|
||||
filter_async_audio(obs_source_t *source, struct obs_audio_data *in)
|
||||
{
|
||||
|
|
@ -3747,7 +3834,7 @@ static void enum_source_full_tree_callback(obs_source_t *parent,
|
|||
child, enum_source_full_tree_callback, param);
|
||||
if (child->info.enum_all_sources) {
|
||||
if (child->context.data) {
|
||||
child->info.enum_active_sources(
|
||||
child->info.enum_all_sources(
|
||||
child->context.data,
|
||||
enum_source_full_tree_callback, data);
|
||||
}
|
||||
|
|
@ -4830,7 +4917,7 @@ enum obs_icon_type obs_source_get_icon_type(const char *id)
|
|||
|
||||
void obs_source_media_play_pause(obs_source_t *source, bool pause)
|
||||
{
|
||||
if (!obs_source_valid(source, "obs_source_media_play_pause"))
|
||||
if (!data_valid(source, "obs_source_media_play_pause"))
|
||||
return;
|
||||
|
||||
if (!source->info.media_play_pause)
|
||||
|
|
@ -4846,7 +4933,7 @@ void obs_source_media_play_pause(obs_source_t *source, bool pause)
|
|||
|
||||
void obs_source_media_restart(obs_source_t *source)
|
||||
{
|
||||
if (!obs_source_valid(source, "obs_source_media_restart"))
|
||||
if (!data_valid(source, "obs_source_media_restart"))
|
||||
return;
|
||||
|
||||
if (!source->info.media_restart)
|
||||
|
|
@ -4859,7 +4946,7 @@ void obs_source_media_restart(obs_source_t *source)
|
|||
|
||||
void obs_source_media_stop(obs_source_t *source)
|
||||
{
|
||||
if (!obs_source_valid(source, "obs_source_media_stop"))
|
||||
if (!data_valid(source, "obs_source_media_stop"))
|
||||
return;
|
||||
|
||||
if (!source->info.media_stop)
|
||||
|
|
@ -4872,7 +4959,7 @@ void obs_source_media_stop(obs_source_t *source)
|
|||
|
||||
void obs_source_media_next(obs_source_t *source)
|
||||
{
|
||||
if (!obs_source_valid(source, "obs_source_media_next"))
|
||||
if (!data_valid(source, "obs_source_media_next"))
|
||||
return;
|
||||
|
||||
if (!source->info.media_next)
|
||||
|
|
@ -4885,7 +4972,7 @@ void obs_source_media_next(obs_source_t *source)
|
|||
|
||||
void obs_source_media_previous(obs_source_t *source)
|
||||
{
|
||||
if (!obs_source_valid(source, "obs_source_media_previous"))
|
||||
if (!data_valid(source, "obs_source_media_previous"))
|
||||
return;
|
||||
|
||||
if (!source->info.media_previous)
|
||||
|
|
@ -4898,7 +4985,7 @@ void obs_source_media_previous(obs_source_t *source)
|
|||
|
||||
int64_t obs_source_media_get_duration(obs_source_t *source)
|
||||
{
|
||||
if (!obs_source_valid(source, "obs_source_media_get_duration"))
|
||||
if (!data_valid(source, "obs_source_media_get_duration"))
|
||||
return 0;
|
||||
|
||||
if (source->info.media_get_duration)
|
||||
|
|
@ -4909,7 +4996,7 @@ int64_t obs_source_media_get_duration(obs_source_t *source)
|
|||
|
||||
int64_t obs_source_media_get_time(obs_source_t *source)
|
||||
{
|
||||
if (!obs_source_valid(source, "obs_source_media_get_time"))
|
||||
if (!data_valid(source, "obs_source_media_get_time"))
|
||||
return 0;
|
||||
|
||||
if (source->info.media_get_time)
|
||||
|
|
@ -4920,7 +5007,7 @@ int64_t obs_source_media_get_time(obs_source_t *source)
|
|||
|
||||
void obs_source_media_set_time(obs_source_t *source, int64_t ms)
|
||||
{
|
||||
if (!obs_source_valid(source, "obs_source_media_set_time"))
|
||||
if (!data_valid(source, "obs_source_media_set_time"))
|
||||
return;
|
||||
|
||||
if (source->info.media_set_time)
|
||||
|
|
@ -4929,7 +5016,7 @@ void obs_source_media_set_time(obs_source_t *source, int64_t ms)
|
|||
|
||||
enum obs_media_state obs_source_media_get_state(obs_source_t *source)
|
||||
{
|
||||
if (!obs_source_valid(source, "obs_source_media_get_state"))
|
||||
if (!data_valid(source, "obs_source_media_get_state"))
|
||||
return OBS_MEDIA_STATE_NONE;
|
||||
|
||||
if (source->info.media_get_state)
|
||||
|
|
|
|||
|
|
@ -539,7 +539,7 @@ static const uint8_t *set_gpu_converted_plane(uint32_t width, uint32_t height,
|
|||
const uint8_t *in, uint8_t *out)
|
||||
{
|
||||
if ((width == linesize_input) && (width == linesize_output)) {
|
||||
size_t total = width * height;
|
||||
size_t total = (size_t)width * (size_t)height;
|
||||
memcpy(out, in, total);
|
||||
in += total;
|
||||
} else {
|
||||
|
|
@ -672,10 +672,12 @@ static inline void copy_rgbx_frame(struct video_frame *output,
|
|||
|
||||
/* if the line sizes match, do a single copy */
|
||||
if (input->linesize[0] == output->linesize[0]) {
|
||||
memcpy(out_ptr, in_ptr, input->linesize[0] * info->height);
|
||||
memcpy(out_ptr, in_ptr,
|
||||
(size_t)input->linesize[0] * (size_t)info->height);
|
||||
} else {
|
||||
const size_t copy_size = (size_t)info->width * 4;
|
||||
for (size_t y = 0; y < info->height; y++) {
|
||||
memcpy(out_ptr, in_ptr, info->width * 4);
|
||||
memcpy(out_ptr, in_ptr, copy_size);
|
||||
in_ptr += input->linesize[0];
|
||||
out_ptr += output->linesize[0];
|
||||
}
|
||||
|
|
@ -835,24 +837,188 @@ static void execute_graphics_tasks(void)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
struct winrt_exports {
|
||||
void (*winrt_initialize)();
|
||||
void (*winrt_uninitialize)();
|
||||
struct winrt_disaptcher *(*winrt_dispatcher_init)();
|
||||
void (*winrt_dispatcher_free)(struct winrt_disaptcher *dispatcher);
|
||||
void (*winrt_capture_thread_start)();
|
||||
void (*winrt_capture_thread_stop)();
|
||||
};
|
||||
|
||||
#define WINRT_IMPORT(func) \
|
||||
do { \
|
||||
exports->func = os_dlsym(module, #func); \
|
||||
if (!exports->func) { \
|
||||
success = false; \
|
||||
blog(LOG_ERROR, \
|
||||
"Could not load function '%s' from " \
|
||||
"module '%s'", \
|
||||
#func, module_name); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
static bool load_winrt_imports(struct winrt_exports *exports, void *module,
|
||||
const char *module_name)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
WINRT_IMPORT(winrt_initialize);
|
||||
WINRT_IMPORT(winrt_uninitialize);
|
||||
WINRT_IMPORT(winrt_dispatcher_init);
|
||||
WINRT_IMPORT(winrt_dispatcher_free);
|
||||
WINRT_IMPORT(winrt_capture_thread_start);
|
||||
WINRT_IMPORT(winrt_capture_thread_stop);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
struct winrt_state {
|
||||
bool loaded;
|
||||
void *winrt_module;
|
||||
struct winrt_exports exports;
|
||||
struct winrt_disaptcher *dispatcher;
|
||||
};
|
||||
|
||||
static void init_winrt_state(struct winrt_state *winrt)
|
||||
{
|
||||
static const char *const module_name = "libobs-winrt";
|
||||
|
||||
winrt->winrt_module = os_dlopen(module_name);
|
||||
winrt->loaded = winrt->winrt_module &&
|
||||
load_winrt_imports(&winrt->exports, winrt->winrt_module,
|
||||
module_name);
|
||||
winrt->dispatcher = NULL;
|
||||
if (winrt->loaded) {
|
||||
winrt->exports.winrt_initialize();
|
||||
winrt->dispatcher = winrt->exports.winrt_dispatcher_init();
|
||||
|
||||
gs_enter_context(obs->video.graphics);
|
||||
winrt->exports.winrt_capture_thread_start();
|
||||
gs_leave_context();
|
||||
}
|
||||
}
|
||||
|
||||
static void uninit_winrt_state(struct winrt_state *winrt)
|
||||
{
|
||||
if (winrt->winrt_module) {
|
||||
if (winrt->loaded) {
|
||||
winrt->exports.winrt_capture_thread_stop();
|
||||
if (winrt->dispatcher)
|
||||
winrt->exports.winrt_dispatcher_free(
|
||||
winrt->dispatcher);
|
||||
winrt->exports.winrt_uninitialize();
|
||||
}
|
||||
|
||||
os_dlclose(winrt->winrt_module);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifdef _WIN32
|
||||
|
||||
static const char *tick_sources_name = "tick_sources";
|
||||
static const char *render_displays_name = "render_displays";
|
||||
static const char *output_frame_name = "output_frame";
|
||||
bool obs_graphics_thread_loop(struct obs_graphics_context *context)
|
||||
{
|
||||
/* defer loop break to clean up sources */
|
||||
const bool stop_requested = video_output_stopped(obs->video.video);
|
||||
|
||||
uint64_t frame_start = os_gettime_ns();
|
||||
uint64_t frame_time_ns;
|
||||
bool raw_active = obs->video.raw_active > 0;
|
||||
#ifdef _WIN32
|
||||
const bool gpu_active = obs->video.gpu_encoder_active > 0;
|
||||
const bool active = raw_active || gpu_active;
|
||||
#else
|
||||
const bool gpu_active = 0;
|
||||
const bool active = raw_active;
|
||||
#endif
|
||||
|
||||
if (!context->was_active && active)
|
||||
clear_base_frame_data();
|
||||
if (!context->raw_was_active && raw_active)
|
||||
clear_raw_frame_data();
|
||||
#ifdef _WIN32
|
||||
if (!context->gpu_was_active && gpu_active)
|
||||
clear_gpu_frame_data();
|
||||
|
||||
context->gpu_was_active = gpu_active;
|
||||
#endif
|
||||
context->raw_was_active = raw_active;
|
||||
context->was_active = active;
|
||||
|
||||
profile_start(context->video_thread_name);
|
||||
|
||||
gs_enter_context(obs->video.graphics);
|
||||
gs_begin_frame();
|
||||
gs_leave_context();
|
||||
|
||||
profile_start(tick_sources_name);
|
||||
context->last_time =
|
||||
tick_sources(obs->video.video_time, context->last_time);
|
||||
profile_end(tick_sources_name);
|
||||
|
||||
execute_graphics_tasks();
|
||||
|
||||
#ifdef _WIN32
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
#endif
|
||||
|
||||
profile_start(output_frame_name);
|
||||
output_frame(raw_active, gpu_active);
|
||||
profile_end(output_frame_name);
|
||||
|
||||
profile_start(render_displays_name);
|
||||
render_displays();
|
||||
profile_end(render_displays_name);
|
||||
|
||||
frame_time_ns = os_gettime_ns() - frame_start;
|
||||
|
||||
profile_end(context->video_thread_name);
|
||||
|
||||
profile_reenable_thread();
|
||||
|
||||
video_sleep(&obs->video, raw_active, gpu_active, &obs->video.video_time,
|
||||
context->interval);
|
||||
|
||||
context->frame_time_total_ns += frame_time_ns;
|
||||
context->fps_total_ns += (obs->video.video_time - context->last_time);
|
||||
context->fps_total_frames++;
|
||||
|
||||
if (context->fps_total_ns >= 1000000000ULL) {
|
||||
obs->video.video_fps =
|
||||
(double)context->fps_total_frames /
|
||||
((double)context->fps_total_ns / 1000000000.0);
|
||||
obs->video.video_avg_frame_time_ns =
|
||||
context->frame_time_total_ns /
|
||||
(uint64_t)context->fps_total_frames;
|
||||
|
||||
context->frame_time_total_ns = 0;
|
||||
context->fps_total_ns = 0;
|
||||
context->fps_total_frames = 0;
|
||||
}
|
||||
|
||||
return !stop_requested;
|
||||
}
|
||||
|
||||
void *obs_graphics_thread(void *param)
|
||||
{
|
||||
uint64_t last_time = 0;
|
||||
uint64_t interval = video_output_get_frame_time(obs->video.video);
|
||||
uint64_t frame_time_total_ns = 0;
|
||||
uint64_t fps_total_ns = 0;
|
||||
uint32_t fps_total_frames = 0;
|
||||
#ifdef _WIN32
|
||||
bool gpu_was_active = false;
|
||||
#endif
|
||||
bool raw_was_active = false;
|
||||
bool was_active = false;
|
||||
struct winrt_state winrt;
|
||||
init_winrt_state(&winrt);
|
||||
#endif // #ifdef _WIN32
|
||||
|
||||
is_graphics_thread = true;
|
||||
|
||||
const uint64_t interval = video_output_get_frame_time(obs->video.video);
|
||||
|
||||
obs->video.video_time = os_gettime_ns();
|
||||
obs->video.video_frame_interval_ns = interval;
|
||||
|
||||
|
|
@ -865,93 +1031,30 @@ void *obs_graphics_thread(void *param)
|
|||
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
for (;;) {
|
||||
/* defer loop break to clean up sources */
|
||||
const bool stop_requested =
|
||||
video_output_stopped(obs->video.video);
|
||||
|
||||
uint64_t frame_start = os_gettime_ns();
|
||||
uint64_t frame_time_ns;
|
||||
bool raw_active = obs->video.raw_active > 0;
|
||||
struct obs_graphics_context context;
|
||||
context.interval = video_output_get_frame_time(obs->video.video);
|
||||
context.frame_time_total_ns = 0;
|
||||
context.fps_total_ns = 0;
|
||||
context.fps_total_frames = 0;
|
||||
context.last_time = 0;
|
||||
#ifdef _WIN32
|
||||
const bool gpu_active = obs->video.gpu_encoder_active > 0;
|
||||
const bool active = raw_active || gpu_active;
|
||||
context.gpu_was_active = false;
|
||||
#endif
|
||||
context.raw_was_active = false;
|
||||
context.was_active = false;
|
||||
context.video_thread_name = video_thread_name;
|
||||
|
||||
#ifdef __APPLE__
|
||||
while (obs_graphics_thread_loop_autorelease(&context))
|
||||
#else
|
||||
const bool gpu_active = 0;
|
||||
const bool active = raw_active;
|
||||
while (obs_graphics_thread_loop(&context))
|
||||
#endif
|
||||
|
||||
if (!was_active && active)
|
||||
clear_base_frame_data();
|
||||
if (!raw_was_active && raw_active)
|
||||
clear_raw_frame_data();
|
||||
#ifdef _WIN32
|
||||
if (!gpu_was_active && gpu_active)
|
||||
clear_gpu_frame_data();
|
||||
|
||||
gpu_was_active = gpu_active;
|
||||
#endif
|
||||
raw_was_active = raw_active;
|
||||
was_active = active;
|
||||
|
||||
profile_start(video_thread_name);
|
||||
|
||||
gs_enter_context(obs->video.graphics);
|
||||
gs_begin_frame();
|
||||
gs_leave_context();
|
||||
|
||||
profile_start(tick_sources_name);
|
||||
last_time = tick_sources(obs->video.video_time, last_time);
|
||||
profile_end(tick_sources_name);
|
||||
|
||||
execute_graphics_tasks();
|
||||
;
|
||||
|
||||
#ifdef _WIN32
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
uninit_winrt_state(&winrt);
|
||||
#endif
|
||||
|
||||
profile_start(output_frame_name);
|
||||
output_frame(raw_active, gpu_active);
|
||||
profile_end(output_frame_name);
|
||||
|
||||
profile_start(render_displays_name);
|
||||
render_displays();
|
||||
profile_end(render_displays_name);
|
||||
|
||||
frame_time_ns = os_gettime_ns() - frame_start;
|
||||
|
||||
profile_end(video_thread_name);
|
||||
|
||||
profile_reenable_thread();
|
||||
|
||||
video_sleep(&obs->video, raw_active, gpu_active,
|
||||
&obs->video.video_time, interval);
|
||||
|
||||
frame_time_total_ns += frame_time_ns;
|
||||
fps_total_ns += (obs->video.video_time - last_time);
|
||||
fps_total_frames++;
|
||||
|
||||
if (fps_total_ns >= 1000000000ULL) {
|
||||
obs->video.video_fps =
|
||||
(double)fps_total_frames /
|
||||
((double)fps_total_ns / 1000000000.0);
|
||||
obs->video.video_avg_frame_time_ns =
|
||||
frame_time_total_ns /
|
||||
(uint64_t)fps_total_frames;
|
||||
|
||||
frame_time_total_ns = 0;
|
||||
fps_total_ns = 0;
|
||||
fps_total_frames = 0;
|
||||
}
|
||||
|
||||
if (stop_requested)
|
||||
break;
|
||||
}
|
||||
|
||||
UNUSED_PARAMETER(param);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -246,6 +246,8 @@ static inline void init_module_info(struct exception_handler_data *data)
|
|||
data);
|
||||
}
|
||||
|
||||
extern const char *get_win_release_id();
|
||||
|
||||
static inline void write_header(struct exception_handler_data *data)
|
||||
{
|
||||
char date_time[80];
|
||||
|
|
@ -260,18 +262,20 @@ static inline void write_header(struct exception_handler_data *data)
|
|||
else
|
||||
obs_bitness = "32";
|
||||
|
||||
const char *release_id = get_win_release_id();
|
||||
|
||||
dstr_catf(&data->str,
|
||||
"Unhandled exception: %x\r\n"
|
||||
"Date/Time: %s\r\n"
|
||||
"Fault address: %" PRIX64 " (%s)\r\n"
|
||||
"libobs version: " OBS_VERSION " (%s-bit)\r\n"
|
||||
"Windows version: %d.%d build %d (revision: %d; "
|
||||
"Windows version: %d.%d build %d (release: %s; revision: %d; "
|
||||
"%s-bit)\r\n"
|
||||
"CPU: %s\r\n\r\n",
|
||||
data->exception->ExceptionRecord->ExceptionCode, date_time,
|
||||
data->main_trace.instruction_ptr, data->module_name.array,
|
||||
obs_bitness, data->win_version.major, data->win_version.minor,
|
||||
data->win_version.build, data->win_version.revis,
|
||||
data->win_version.build, release_id, data->win_version.revis,
|
||||
is_64_bit_windows() ? "64" : "32", data->cpu_info.array);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -199,6 +199,8 @@ static void log_aero(void)
|
|||
L"SOFTWARE\\Policies\\Microsoft\\Windows\\GameDVR"
|
||||
#define WIN10_GAME_DVR_REG_KEY L"System\\GameConfigStore"
|
||||
#define WIN10_GAME_MODE_REG_KEY L"Software\\Microsoft\\GameBar"
|
||||
#define WIN10_HAGS_REG_KEY \
|
||||
L"SYSTEM\\CurrentControlSet\\Control\\GraphicsDrivers"
|
||||
|
||||
static void log_gaming_features(void)
|
||||
{
|
||||
|
|
@ -210,6 +212,7 @@ static void log_gaming_features(void)
|
|||
struct reg_dword game_dvr_enabled;
|
||||
struct reg_dword game_dvr_bg_recording;
|
||||
struct reg_dword game_mode_enabled;
|
||||
struct reg_dword hags_enabled;
|
||||
|
||||
get_reg_dword(HKEY_CURRENT_USER, WIN10_GAME_BAR_REG_KEY,
|
||||
L"AppCaptureEnabled", &game_bar_enabled);
|
||||
|
|
@ -221,6 +224,9 @@ static void log_gaming_features(void)
|
|||
L"HistoricalCaptureEnabled", &game_dvr_bg_recording);
|
||||
get_reg_dword(HKEY_CURRENT_USER, WIN10_GAME_MODE_REG_KEY,
|
||||
L"AllowAutoGameMode", &game_mode_enabled);
|
||||
get_reg_dword(HKEY_LOCAL_MACHINE, WIN10_HAGS_REG_KEY, L"HwSchMode",
|
||||
&hags_enabled);
|
||||
|
||||
if (game_mode_enabled.status != ERROR_SUCCESS) {
|
||||
get_reg_dword(HKEY_CURRENT_USER, WIN10_GAME_MODE_REG_KEY,
|
||||
L"AutoGameModeEnabled", &game_mode_enabled);
|
||||
|
|
@ -251,6 +257,11 @@ static void log_gaming_features(void)
|
|||
blog(LOG_INFO, "\tGame Mode: %s",
|
||||
(bool)game_mode_enabled.return_value ? "On" : "Off");
|
||||
}
|
||||
|
||||
if (hags_enabled.status == ERROR_SUCCESS) {
|
||||
blog(LOG_INFO, "\tHardware GPU Scheduler: %s",
|
||||
(hags_enabled.return_value == 2) ? "On" : "Off");
|
||||
}
|
||||
}
|
||||
|
||||
static const char *get_str_for_state(int state)
|
||||
|
|
@ -1040,6 +1051,9 @@ void obs_key_to_str(obs_key_t key, struct dstr *str)
|
|||
if (key == OBS_KEY_NONE) {
|
||||
return;
|
||||
|
||||
} else if (key >= OBS_KEY_F13 && key <= OBS_KEY_F24) {
|
||||
dstr_printf(str, "F%d", (int)(key - OBS_KEY_F13 + 13));
|
||||
return;
|
||||
} else if (key >= OBS_KEY_MOUSE1 && key <= OBS_KEY_MOUSE29) {
|
||||
if (obs->hotkeys.translations[key]) {
|
||||
dstr_copy(str, obs->hotkeys.translations[key]);
|
||||
|
|
@ -1264,9 +1278,7 @@ bool initialize_com(void)
|
|||
{
|
||||
const HRESULT hr = CoInitializeEx(0, COINIT_APARTMENTTHREADED);
|
||||
const bool success = SUCCEEDED(hr);
|
||||
if (success)
|
||||
blog(LOG_INFO, "CoInitializeEx succeeded: 0x%08X", hr);
|
||||
else
|
||||
if (!success)
|
||||
blog(LOG_ERROR, "CoInitializeEx failed: 0x%08X", hr);
|
||||
return success;
|
||||
}
|
||||
|
|
|
|||
202
libobs/obs.c
202
libobs/obs.c
|
|
@ -429,8 +429,13 @@ static int obs_init_video(struct obs_video_info *ovi)
|
|||
if (pthread_mutex_init(&video->task_mutex, NULL) < 0)
|
||||
return OBS_VIDEO_FAIL;
|
||||
|
||||
#ifdef __APPLE__
|
||||
errorcode = pthread_create(&video->video_thread, NULL,
|
||||
obs_graphics_thread_autorelease, obs);
|
||||
#else
|
||||
errorcode = pthread_create(&video->video_thread, NULL,
|
||||
obs_graphics_thread, obs);
|
||||
#endif
|
||||
if (errorcode != 0)
|
||||
return OBS_VIDEO_FAIL;
|
||||
|
||||
|
|
@ -907,7 +912,6 @@ void obs_add_data_path(const char *path)
|
|||
{
|
||||
struct dstr *new_path = da_push_back_new(core_module_paths);
|
||||
dstr_init_copy(new_path, path);
|
||||
da_push_back(core_module_paths, new_path);
|
||||
}
|
||||
|
||||
bool obs_remove_data_path(const char *path)
|
||||
|
|
@ -989,10 +993,6 @@ struct obs_cmdline_args obs_get_cmdline_args(void)
|
|||
void obs_shutdown(void)
|
||||
{
|
||||
struct obs_module *module;
|
||||
struct obs_core *core;
|
||||
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < obs->source_types.num; i++) {
|
||||
struct obs_source_info *item = &obs->source_types.array[i];
|
||||
|
|
@ -1028,6 +1028,14 @@ void obs_shutdown(void)
|
|||
stop_video();
|
||||
stop_hotkeys();
|
||||
|
||||
module = obs->first_module;
|
||||
while (module) {
|
||||
struct obs_module *next = module->next;
|
||||
free_module(module);
|
||||
module = next;
|
||||
}
|
||||
obs->first_module = NULL;
|
||||
|
||||
obs_free_audio();
|
||||
obs_free_data();
|
||||
obs_free_video();
|
||||
|
|
@ -1038,27 +1046,17 @@ void obs_shutdown(void)
|
|||
obs->procs = NULL;
|
||||
obs->signals = NULL;
|
||||
|
||||
core = obs;
|
||||
for (size_t i = 0; i < obs->module_paths.num; i++)
|
||||
free_module_path(obs->module_paths.array + i);
|
||||
da_free(obs->module_paths);
|
||||
|
||||
if (obs->name_store_owned)
|
||||
profiler_name_store_free(obs->name_store);
|
||||
|
||||
bfree(obs->module_config_path);
|
||||
bfree(obs->locale);
|
||||
bfree(obs);
|
||||
obs = NULL;
|
||||
|
||||
module = core->first_module;
|
||||
while (module) {
|
||||
struct obs_module *next = module->next;
|
||||
free_module(module);
|
||||
module = next;
|
||||
}
|
||||
core->first_module = NULL;
|
||||
|
||||
for (size_t i = 0; i < core->module_paths.num; i++)
|
||||
free_module_path(core->module_paths.array + i);
|
||||
da_free(core->module_paths);
|
||||
|
||||
if (core->name_store_owned)
|
||||
profiler_name_store_free(core->name_store);
|
||||
|
||||
bfree(core->module_config_path);
|
||||
bfree(core->locale);
|
||||
bfree(core);
|
||||
bfree(cmdline_args.argv);
|
||||
|
||||
#ifdef _WIN32
|
||||
|
|
@ -1085,8 +1083,6 @@ const char *obs_get_version_string(void)
|
|||
void obs_set_locale(const char *locale)
|
||||
{
|
||||
struct obs_module *module;
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
if (obs->locale)
|
||||
bfree(obs->locale);
|
||||
|
|
@ -1103,7 +1099,7 @@ void obs_set_locale(const char *locale)
|
|||
|
||||
const char *obs_get_locale(void)
|
||||
{
|
||||
return obs ? obs->locale : NULL;
|
||||
return obs->locale;
|
||||
}
|
||||
|
||||
#define OBS_SIZE_MIN 2
|
||||
|
|
@ -1193,9 +1189,6 @@ bool obs_reset_audio(const struct obs_audio_info *oai)
|
|||
{
|
||||
struct audio_output_info ai;
|
||||
|
||||
if (!obs)
|
||||
return false;
|
||||
|
||||
/* don't allow changing of audio settings if active. */
|
||||
if (obs->audio.audio && audio_output_active(obs->audio.audio))
|
||||
return false;
|
||||
|
|
@ -1224,7 +1217,7 @@ bool obs_get_video_info(struct obs_video_info *ovi)
|
|||
{
|
||||
struct obs_core_video *video = &obs->video;
|
||||
|
||||
if (!obs || !video->graphics)
|
||||
if (!video->graphics)
|
||||
return false;
|
||||
|
||||
*ovi = video->ovi;
|
||||
|
|
@ -1236,7 +1229,7 @@ bool obs_get_audio_info(struct obs_audio_info *oai)
|
|||
struct obs_core_audio *audio = &obs->audio;
|
||||
const struct audio_output_info *info;
|
||||
|
||||
if (!obs || !oai || !audio->audio)
|
||||
if (!oai || !audio->audio)
|
||||
return false;
|
||||
|
||||
info = audio_output_get_info(audio->audio);
|
||||
|
|
@ -1248,9 +1241,6 @@ bool obs_get_audio_info(struct obs_audio_info *oai)
|
|||
|
||||
bool obs_enum_source_types(size_t idx, const char **id)
|
||||
{
|
||||
if (!obs)
|
||||
return false;
|
||||
|
||||
if (idx >= obs->source_types.num)
|
||||
return false;
|
||||
*id = obs->source_types.array[idx].id;
|
||||
|
|
@ -1259,9 +1249,6 @@ bool obs_enum_source_types(size_t idx, const char **id)
|
|||
|
||||
bool obs_enum_input_types(size_t idx, const char **id)
|
||||
{
|
||||
if (!obs)
|
||||
return false;
|
||||
|
||||
if (idx >= obs->input_types.num)
|
||||
return false;
|
||||
*id = obs->input_types.array[idx].id;
|
||||
|
|
@ -1271,9 +1258,6 @@ bool obs_enum_input_types(size_t idx, const char **id)
|
|||
bool obs_enum_input_types2(size_t idx, const char **id,
|
||||
const char **unversioned_id)
|
||||
{
|
||||
if (!obs)
|
||||
return false;
|
||||
|
||||
if (idx >= obs->input_types.num)
|
||||
return false;
|
||||
if (id)
|
||||
|
|
@ -1288,8 +1272,6 @@ const char *obs_get_latest_input_type_id(const char *unversioned_id)
|
|||
struct obs_source_info *latest = NULL;
|
||||
int version = -1;
|
||||
|
||||
if (!obs)
|
||||
return NULL;
|
||||
if (!unversioned_id)
|
||||
return NULL;
|
||||
|
||||
|
|
@ -1311,9 +1293,6 @@ const char *obs_get_latest_input_type_id(const char *unversioned_id)
|
|||
|
||||
bool obs_enum_filter_types(size_t idx, const char **id)
|
||||
{
|
||||
if (!obs)
|
||||
return false;
|
||||
|
||||
if (idx >= obs->filter_types.num)
|
||||
return false;
|
||||
*id = obs->filter_types.array[idx].id;
|
||||
|
|
@ -1322,9 +1301,6 @@ bool obs_enum_filter_types(size_t idx, const char **id)
|
|||
|
||||
bool obs_enum_transition_types(size_t idx, const char **id)
|
||||
{
|
||||
if (!obs)
|
||||
return false;
|
||||
|
||||
if (idx >= obs->transition_types.num)
|
||||
return false;
|
||||
*id = obs->transition_types.array[idx].id;
|
||||
|
|
@ -1333,9 +1309,6 @@ bool obs_enum_transition_types(size_t idx, const char **id)
|
|||
|
||||
bool obs_enum_output_types(size_t idx, const char **id)
|
||||
{
|
||||
if (!obs)
|
||||
return false;
|
||||
|
||||
if (idx >= obs->output_types.num)
|
||||
return false;
|
||||
*id = obs->output_types.array[idx].id;
|
||||
|
|
@ -1344,9 +1317,6 @@ bool obs_enum_output_types(size_t idx, const char **id)
|
|||
|
||||
bool obs_enum_encoder_types(size_t idx, const char **id)
|
||||
{
|
||||
if (!obs)
|
||||
return false;
|
||||
|
||||
if (idx >= obs->encoder_types.num)
|
||||
return false;
|
||||
*id = obs->encoder_types.array[idx].id;
|
||||
|
|
@ -1355,9 +1325,6 @@ bool obs_enum_encoder_types(size_t idx, const char **id)
|
|||
|
||||
bool obs_enum_service_types(size_t idx, const char **id)
|
||||
{
|
||||
if (!obs)
|
||||
return false;
|
||||
|
||||
if (idx >= obs->service_types.num)
|
||||
return false;
|
||||
*id = obs->service_types.array[idx].id;
|
||||
|
|
@ -1366,24 +1333,24 @@ bool obs_enum_service_types(size_t idx, const char **id)
|
|||
|
||||
void obs_enter_graphics(void)
|
||||
{
|
||||
if (obs && obs->video.graphics)
|
||||
if (obs->video.graphics)
|
||||
gs_enter_context(obs->video.graphics);
|
||||
}
|
||||
|
||||
void obs_leave_graphics(void)
|
||||
{
|
||||
if (obs && obs->video.graphics)
|
||||
if (obs->video.graphics)
|
||||
gs_leave_context();
|
||||
}
|
||||
|
||||
audio_t *obs_get_audio(void)
|
||||
{
|
||||
return (obs != NULL) ? obs->audio.audio : NULL;
|
||||
return obs->audio.audio;
|
||||
}
|
||||
|
||||
video_t *obs_get_video(void)
|
||||
{
|
||||
return (obs != NULL) ? obs->video.video : NULL;
|
||||
return obs->video.video;
|
||||
}
|
||||
|
||||
/* TODO: optimize this later so it's not just O(N) string lookups */
|
||||
|
|
@ -1442,17 +1409,12 @@ void *obs_create_ui(const char *name, const char *task, const char *target,
|
|||
{
|
||||
struct obs_modeless_ui *callback;
|
||||
|
||||
if (!obs)
|
||||
return NULL;
|
||||
|
||||
callback = get_modeless_ui_callback(name, task, target);
|
||||
return callback ? callback->create(data, ui_data) : NULL;
|
||||
}
|
||||
|
||||
obs_source_t *obs_get_output_source(uint32_t channel)
|
||||
{
|
||||
if (!obs)
|
||||
return NULL;
|
||||
return obs_view_get_source(&obs->data.main_view, channel);
|
||||
}
|
||||
|
||||
|
|
@ -1460,8 +1422,6 @@ void obs_set_output_source(uint32_t channel, obs_source_t *source)
|
|||
{
|
||||
assert(channel < MAX_CHANNELS);
|
||||
|
||||
if (!obs)
|
||||
return;
|
||||
if (channel >= MAX_CHANNELS)
|
||||
return;
|
||||
|
||||
|
|
@ -1499,9 +1459,6 @@ void obs_enum_sources(bool (*enum_proc)(void *, obs_source_t *), void *param)
|
|||
{
|
||||
obs_source_t *source;
|
||||
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&obs->data.sources_mutex);
|
||||
source = obs->data.first_source;
|
||||
|
||||
|
|
@ -1528,9 +1485,6 @@ void obs_enum_scenes(bool (*enum_proc)(void *, obs_source_t *), void *param)
|
|||
{
|
||||
obs_source_t *source;
|
||||
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&obs->data.sources_mutex);
|
||||
source = obs->data.first_source;
|
||||
|
||||
|
|
@ -1574,24 +1528,18 @@ static inline void obs_enum(void *pstart, pthread_mutex_t *mutex, void *proc,
|
|||
|
||||
void obs_enum_outputs(bool (*enum_proc)(void *, obs_output_t *), void *param)
|
||||
{
|
||||
if (!obs)
|
||||
return;
|
||||
obs_enum(&obs->data.first_output, &obs->data.outputs_mutex, enum_proc,
|
||||
param);
|
||||
}
|
||||
|
||||
void obs_enum_encoders(bool (*enum_proc)(void *, obs_encoder_t *), void *param)
|
||||
{
|
||||
if (!obs)
|
||||
return;
|
||||
obs_enum(&obs->data.first_encoder, &obs->data.encoders_mutex, enum_proc,
|
||||
param);
|
||||
}
|
||||
|
||||
void obs_enum_services(bool (*enum_proc)(void *, obs_service_t *), void *param)
|
||||
{
|
||||
if (!obs)
|
||||
return;
|
||||
obs_enum(&obs->data.first_service, &obs->data.services_mutex, enum_proc,
|
||||
param);
|
||||
}
|
||||
|
|
@ -1645,8 +1593,6 @@ static inline void *obs_id_(void *data)
|
|||
|
||||
obs_source_t *obs_get_source_by_name(const char *name)
|
||||
{
|
||||
if (!obs)
|
||||
return NULL;
|
||||
return get_context_by_name(&obs->data.first_source, name,
|
||||
&obs->data.sources_mutex,
|
||||
obs_source_addref_safe_);
|
||||
|
|
@ -1654,8 +1600,6 @@ obs_source_t *obs_get_source_by_name(const char *name)
|
|||
|
||||
obs_output_t *obs_get_output_by_name(const char *name)
|
||||
{
|
||||
if (!obs)
|
||||
return NULL;
|
||||
return get_context_by_name(&obs->data.first_output, name,
|
||||
&obs->data.outputs_mutex,
|
||||
obs_output_addref_safe_);
|
||||
|
|
@ -1663,8 +1607,6 @@ obs_output_t *obs_get_output_by_name(const char *name)
|
|||
|
||||
obs_encoder_t *obs_get_encoder_by_name(const char *name)
|
||||
{
|
||||
if (!obs)
|
||||
return NULL;
|
||||
return get_context_by_name(&obs->data.first_encoder, name,
|
||||
&obs->data.encoders_mutex,
|
||||
obs_encoder_addref_safe_);
|
||||
|
|
@ -1672,8 +1614,6 @@ obs_encoder_t *obs_get_encoder_by_name(const char *name)
|
|||
|
||||
obs_service_t *obs_get_service_by_name(const char *name)
|
||||
{
|
||||
if (!obs)
|
||||
return NULL;
|
||||
return get_context_by_name(&obs->data.first_service, name,
|
||||
&obs->data.services_mutex,
|
||||
obs_service_addref_safe_);
|
||||
|
|
@ -1681,9 +1621,6 @@ obs_service_t *obs_get_service_by_name(const char *name)
|
|||
|
||||
gs_effect_t *obs_get_base_effect(enum obs_base_effect effect)
|
||||
{
|
||||
if (!obs)
|
||||
return NULL;
|
||||
|
||||
switch (effect) {
|
||||
case OBS_EFFECT_DEFAULT:
|
||||
return obs->video.default_effect;
|
||||
|
|
@ -1713,30 +1650,22 @@ gs_effect_t *obs_get_base_effect(enum obs_base_effect effect)
|
|||
/* OBS_DEPRECATED */
|
||||
gs_effect_t *obs_get_default_rect_effect(void)
|
||||
{
|
||||
if (!obs)
|
||||
return NULL;
|
||||
return obs->video.default_rect_effect;
|
||||
}
|
||||
|
||||
signal_handler_t *obs_get_signal_handler(void)
|
||||
{
|
||||
if (!obs)
|
||||
return NULL;
|
||||
return obs->signals;
|
||||
}
|
||||
|
||||
proc_handler_t *obs_get_proc_handler(void)
|
||||
{
|
||||
if (!obs)
|
||||
return NULL;
|
||||
return obs->procs;
|
||||
}
|
||||
|
||||
/* OBS_DEPRECATED */
|
||||
void obs_render_main_view(void)
|
||||
{
|
||||
if (!obs)
|
||||
return;
|
||||
obs_view_render(&obs->data.main_view);
|
||||
}
|
||||
|
||||
|
|
@ -1750,9 +1679,6 @@ static void obs_render_main_texture_internal(enum gs_blend_type src_c,
|
|||
gs_effect_t *effect;
|
||||
gs_eparam_t *param;
|
||||
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
video = &obs->video;
|
||||
if (!video->texture_rendered)
|
||||
return;
|
||||
|
|
@ -1787,9 +1713,6 @@ gs_texture_t *obs_get_main_texture(void)
|
|||
{
|
||||
struct obs_core_video *video;
|
||||
|
||||
if (!obs)
|
||||
return NULL;
|
||||
|
||||
video = &obs->video;
|
||||
if (!video->texture_rendered)
|
||||
return NULL;
|
||||
|
|
@ -1801,9 +1724,6 @@ void obs_set_master_volume(float volume)
|
|||
{
|
||||
struct calldata data = {0};
|
||||
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
calldata_set_float(&data, "volume", volume);
|
||||
signal_handler_signal(obs->signals, "master_volume", &data);
|
||||
volume = (float)calldata_float(&data, "volume");
|
||||
|
|
@ -1814,7 +1734,7 @@ void obs_set_master_volume(float volume)
|
|||
|
||||
float obs_get_master_volume(void)
|
||||
{
|
||||
return obs ? obs->audio.user_volume : 0.0f;
|
||||
return obs->audio.user_volume;
|
||||
}
|
||||
|
||||
static obs_source_t *obs_load_source_type(obs_data_t *source_data)
|
||||
|
|
@ -1956,9 +1876,6 @@ obs_source_t *obs_load_source(obs_data_t *source_data)
|
|||
void obs_load_sources(obs_data_array_t *array, obs_load_source_cb cb,
|
||||
void *private_data)
|
||||
{
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
struct obs_core_data *data = &obs->data;
|
||||
DARRAY(obs_source_t *) sources;
|
||||
size_t count;
|
||||
|
|
@ -2093,9 +2010,6 @@ obs_data_t *obs_save_source(obs_source_t *source)
|
|||
obs_data_array_t *obs_save_sources_filtered(obs_save_source_filter_cb cb,
|
||||
void *data_)
|
||||
{
|
||||
if (!obs)
|
||||
return NULL;
|
||||
|
||||
struct obs_core_data *data = &obs->data;
|
||||
obs_data_array_t *array;
|
||||
obs_source_t *source;
|
||||
|
|
@ -2262,30 +2176,27 @@ void obs_context_data_setname(struct obs_context_data *context,
|
|||
|
||||
profiler_name_store_t *obs_get_profiler_name_store(void)
|
||||
{
|
||||
if (!obs)
|
||||
return NULL;
|
||||
|
||||
return obs->name_store;
|
||||
}
|
||||
|
||||
uint64_t obs_get_video_frame_time(void)
|
||||
{
|
||||
return obs ? obs->video.video_time : 0;
|
||||
return obs->video.video_time;
|
||||
}
|
||||
|
||||
double obs_get_active_fps(void)
|
||||
{
|
||||
return obs ? obs->video.video_fps : 0.0;
|
||||
return obs->video.video_fps;
|
||||
}
|
||||
|
||||
uint64_t obs_get_average_frame_time_ns(void)
|
||||
{
|
||||
return obs ? obs->video.video_avg_frame_time_ns : 0;
|
||||
return obs->video.video_avg_frame_time_ns;
|
||||
}
|
||||
|
||||
uint64_t obs_get_frame_interval_ns(void)
|
||||
{
|
||||
return obs ? obs->video.video_frame_interval_ns : 0;
|
||||
return obs->video.video_frame_interval_ns;
|
||||
}
|
||||
|
||||
enum obs_obj_type obs_obj_get_type(void *obj)
|
||||
|
|
@ -2335,7 +2246,7 @@ void *obs_obj_get_data(void *obj)
|
|||
|
||||
bool obs_set_audio_monitoring_device(const char *name, const char *id)
|
||||
{
|
||||
if (!obs || !name || !id || !*name || !*id)
|
||||
if (!name || !id || !*name || !*id)
|
||||
return false;
|
||||
|
||||
#if defined(_WIN32) || HAVE_PULSEAUDIO || defined(__APPLE__)
|
||||
|
|
@ -2368,9 +2279,6 @@ bool obs_set_audio_monitoring_device(const char *name, const char *id)
|
|||
|
||||
void obs_get_audio_monitoring_device(const char **name, const char **id)
|
||||
{
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
if (name)
|
||||
*name = obs->audio.monitoring_device_name;
|
||||
if (id)
|
||||
|
|
@ -2380,9 +2288,6 @@ void obs_get_audio_monitoring_device(const char **name, const char **id)
|
|||
void obs_add_tick_callback(void (*tick)(void *param, float seconds),
|
||||
void *param)
|
||||
{
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
struct tick_callback data = {tick, param};
|
||||
|
||||
pthread_mutex_lock(&obs->data.draw_callbacks_mutex);
|
||||
|
|
@ -2393,9 +2298,6 @@ void obs_add_tick_callback(void (*tick)(void *param, float seconds),
|
|||
void obs_remove_tick_callback(void (*tick)(void *param, float seconds),
|
||||
void *param)
|
||||
{
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
struct tick_callback data = {tick, param};
|
||||
|
||||
pthread_mutex_lock(&obs->data.draw_callbacks_mutex);
|
||||
|
|
@ -2407,9 +2309,6 @@ void obs_add_main_render_callback(void (*draw)(void *param, uint32_t cx,
|
|||
uint32_t cy),
|
||||
void *param)
|
||||
{
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
struct draw_callback data = {draw, param};
|
||||
|
||||
pthread_mutex_lock(&obs->data.draw_callbacks_mutex);
|
||||
|
|
@ -2421,9 +2320,6 @@ void obs_remove_main_render_callback(void (*draw)(void *param, uint32_t cx,
|
|||
uint32_t cy),
|
||||
void *param)
|
||||
{
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
struct draw_callback data = {draw, param};
|
||||
|
||||
pthread_mutex_lock(&obs->data.draw_callbacks_mutex);
|
||||
|
|
@ -2433,12 +2329,12 @@ void obs_remove_main_render_callback(void (*draw)(void *param, uint32_t cx,
|
|||
|
||||
uint32_t obs_get_total_frames(void)
|
||||
{
|
||||
return obs ? obs->video.total_frames : 0;
|
||||
return obs->video.total_frames;
|
||||
}
|
||||
|
||||
uint32_t obs_get_lagged_frames(void)
|
||||
{
|
||||
return obs ? obs->video.lagged_frames : 0;
|
||||
return obs->video.lagged_frames;
|
||||
}
|
||||
|
||||
void start_raw_video(video_t *v, const struct video_scale_info *conversion,
|
||||
|
|
@ -2465,8 +2361,6 @@ void obs_add_raw_video_callback(const struct video_scale_info *conversion,
|
|||
void *param)
|
||||
{
|
||||
struct obs_core_video *video = &obs->video;
|
||||
if (!obs)
|
||||
return;
|
||||
start_raw_video(video->video, conversion, callback, param);
|
||||
}
|
||||
|
||||
|
|
@ -2475,14 +2369,12 @@ void obs_remove_raw_video_callback(void (*callback)(void *param,
|
|||
void *param)
|
||||
{
|
||||
struct obs_core_video *video = &obs->video;
|
||||
if (!obs)
|
||||
return;
|
||||
stop_raw_video(video->video, callback, param);
|
||||
}
|
||||
|
||||
void obs_apply_private_data(obs_data_t *settings)
|
||||
{
|
||||
if (!obs || !settings)
|
||||
if (!settings)
|
||||
return;
|
||||
|
||||
obs_data_apply(obs->data.private_data, settings);
|
||||
|
|
@ -2490,9 +2382,6 @@ void obs_apply_private_data(obs_data_t *settings)
|
|||
|
||||
void obs_set_private_data(obs_data_t *settings)
|
||||
{
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
obs_data_clear(obs->data.private_data);
|
||||
if (settings)
|
||||
obs_data_apply(obs->data.private_data, settings);
|
||||
|
|
@ -2500,9 +2389,6 @@ void obs_set_private_data(obs_data_t *settings)
|
|||
|
||||
obs_data_t *obs_get_private_data(void)
|
||||
{
|
||||
if (!obs)
|
||||
return NULL;
|
||||
|
||||
obs_data_t *private_data = obs->data.private_data;
|
||||
obs_data_addref(private_data);
|
||||
return private_data;
|
||||
|
|
@ -2568,8 +2454,6 @@ void stop_gpu_encode(obs_encoder_t *encoder)
|
|||
bool obs_video_active(void)
|
||||
{
|
||||
struct obs_core_video *video = &obs->video;
|
||||
if (!obs)
|
||||
return false;
|
||||
|
||||
return os_atomic_load_long(&video->raw_active) > 0 ||
|
||||
os_atomic_load_long(&video->gpu_encoder_active) > 0;
|
||||
|
|
@ -2578,9 +2462,6 @@ bool obs_video_active(void)
|
|||
bool obs_nv12_tex_active(void)
|
||||
{
|
||||
struct obs_core_video *video = &obs->video;
|
||||
if (!obs)
|
||||
return false;
|
||||
|
||||
return video->using_nv12_tex;
|
||||
}
|
||||
|
||||
|
|
@ -2616,9 +2497,6 @@ static bool in_task_thread(enum obs_task_type type)
|
|||
void obs_queue_task(enum obs_task_type type, obs_task_t task, void *param,
|
||||
bool wait)
|
||||
{
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
if (type == OBS_TASK_UI) {
|
||||
if (obs->ui_task_handler) {
|
||||
obs->ui_task_handler(task, param, wait);
|
||||
|
|
@ -2652,7 +2530,5 @@ void obs_queue_task(enum obs_task_type type, obs_task_t task, void *param,
|
|||
|
||||
void obs_set_ui_task_handler(obs_task_handler_t handler)
|
||||
{
|
||||
if (!obs)
|
||||
return;
|
||||
obs->ui_task_handler = handler;
|
||||
}
|
||||
|
|
|
|||
23
libobs/obs.h
23
libobs/obs.h
|
|
@ -420,6 +420,17 @@ EXPORT int obs_open_module(obs_module_t **module, const char *path,
|
|||
*/
|
||||
EXPORT bool obs_init_module(obs_module_t *module);
|
||||
|
||||
/** Returns a module based upon its name, or NULL if not found */
|
||||
EXPORT obs_module_t *obs_get_module(const char *name);
|
||||
|
||||
/** Returns locale text from a specific module */
|
||||
EXPORT bool obs_module_get_locale_string(const obs_module_t *mod,
|
||||
const char *lookup_string,
|
||||
const char **translated_string);
|
||||
|
||||
EXPORT const char *obs_module_get_locale_text(const obs_module_t *mod,
|
||||
const char *text);
|
||||
|
||||
/** Logs loaded modules */
|
||||
EXPORT void obs_log_loaded_modules(void);
|
||||
|
||||
|
|
@ -1210,6 +1221,18 @@ EXPORT void obs_source_preload_video2(obs_source_t *source,
|
|||
/** Shows any preloaded video data */
|
||||
EXPORT void obs_source_show_preloaded_video(obs_source_t *source);
|
||||
|
||||
/**
|
||||
* Sets current async video frame immediately
|
||||
*
|
||||
* NOTE: Non-YUV formats will always be treated as full range with this
|
||||
* function! Use obs_source_preload_video2 instead if partial range support is
|
||||
* desired for non-YUV video formats.
|
||||
*/
|
||||
EXPORT void obs_source_set_video_frame(obs_source_t *source,
|
||||
const struct obs_source_frame *frame);
|
||||
EXPORT void obs_source_set_video_frame2(obs_source_t *source,
|
||||
const struct obs_source_frame2 *frame);
|
||||
|
||||
/** Outputs audio data (always asynchronous) */
|
||||
EXPORT void obs_source_output_audio(obs_source_t *source,
|
||||
const struct obs_source_audio *audio);
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ public:
|
|||
}
|
||||
|
||||
inline operator T() const { return val; }
|
||||
inline T Get() const { return val; }
|
||||
|
||||
inline bool operator==(T p) const { return val == p; }
|
||||
inline bool operator!=(T p) const { return val != p; }
|
||||
|
|
@ -266,16 +267,3 @@ public:
|
|||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class OBSContext {
|
||||
public:
|
||||
inline OBSContext() {}
|
||||
inline OBSContext(const char *locale,
|
||||
const char *module_config_path = nullptr,
|
||||
profiler_name_store *store = nullptr)
|
||||
{
|
||||
obs_startup(locale, module_config_path, store);
|
||||
}
|
||||
|
||||
inline ~OBSContext() { obs_shutdown(); }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ static inline void darray_reserve(const size_t element_size, struct darray *dst,
|
|||
const size_t capacity)
|
||||
{
|
||||
void *ptr;
|
||||
if (capacity == 0 || capacity <= dst->num)
|
||||
if (capacity == 0 || capacity <= dst->capacity)
|
||||
return;
|
||||
|
||||
ptr = bmalloc(element_size * capacity);
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ wchar_t *wstrstri(const wchar_t *str, const wchar_t *find)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool is_padding(char ch)
|
||||
static inline bool is_padding(int ch)
|
||||
{
|
||||
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
|
||||
}
|
||||
|
|
@ -218,7 +218,7 @@ char *strdepad(char *str)
|
|||
while (is_padding(*temp))
|
||||
++temp;
|
||||
|
||||
len = strlen(str);
|
||||
len = strlen(temp);
|
||||
if (temp != str)
|
||||
memmove(str, temp, len + 1);
|
||||
|
||||
|
|
@ -244,16 +244,16 @@ wchar_t *wcsdepad(wchar_t *str)
|
|||
temp = str;
|
||||
|
||||
/* remove preceding spaces/tabs */
|
||||
while (*temp == ' ' || *temp == '\t')
|
||||
while (is_padding(*temp))
|
||||
++temp;
|
||||
|
||||
len = wcslen(str);
|
||||
len = wcslen(temp);
|
||||
if (temp != str)
|
||||
memmove(str, temp, (len + 1) * sizeof(wchar_t));
|
||||
|
||||
if (len) {
|
||||
temp = str + (len - 1);
|
||||
while (*temp == ' ' || *temp == '\t')
|
||||
while (is_padding(*temp))
|
||||
*(temp--) = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -287,7 +287,10 @@ char *os_get_executable_path_ptr(const char *name)
|
|||
}
|
||||
count = pathlen;
|
||||
#else
|
||||
ssize_t count = readlink("/proc/self/exe", exe, PATH_MAX);
|
||||
ssize_t count = readlink("/proc/self/exe", exe, PATH_MAX - 1);
|
||||
if (count >= 0) {
|
||||
exe[count] = '\0';
|
||||
}
|
||||
#endif
|
||||
const char *path_out = NULL;
|
||||
struct dstr path;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,12 @@
|
|||
|
||||
#else
|
||||
|
||||
#if defined(__aarch64__) || defined(__arm__)
|
||||
#include <arm_neon.h>
|
||||
#include "sse2neon.h"
|
||||
#else
|
||||
#include <xmmintrin.h>
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
4207
libobs/util/sse2neon.h
Normal file
4207
libobs/util/sse2neon.h
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -77,15 +77,19 @@ int os_event_wait(os_event_t *event)
|
|||
{
|
||||
int code = 0;
|
||||
pthread_mutex_lock(&event->mutex);
|
||||
if (!event->signalled)
|
||||
while (!event->signalled) {
|
||||
code = pthread_cond_wait(&event->cond, &event->mutex);
|
||||
if (code != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (code == 0) {
|
||||
if (!event->manual)
|
||||
event->signalled = false;
|
||||
pthread_mutex_unlock(&event->mutex);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&event->mutex);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +107,7 @@ int os_event_timedwait(os_event_t *event, unsigned long milliseconds)
|
|||
{
|
||||
int code = 0;
|
||||
pthread_mutex_lock(&event->mutex);
|
||||
if (!event->signalled) {
|
||||
while (!event->signalled) {
|
||||
struct timespec ts;
|
||||
#if defined(__APPLE__) || defined(__MINGW32__)
|
||||
struct timeval tv;
|
||||
|
|
@ -115,6 +119,8 @@ int os_event_timedwait(os_event_t *event, unsigned long milliseconds)
|
|||
#endif
|
||||
add_ms_to_ts(&ts, milliseconds);
|
||||
code = pthread_cond_timedwait(&event->cond, &event->mutex, &ts);
|
||||
if (code != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (code == 0) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "bmem.h"
|
||||
#include "threading.h"
|
||||
#include "util/platform.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
|
@ -192,4 +193,21 @@ void os_set_thread_name(const char *name)
|
|||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef HRESULT(WINAPI * set_thread_description_t)(HANDLE thread,
|
||||
PCWSTR desc);
|
||||
|
||||
HMODULE k32 = LoadLibraryW(L"Kernel32.dll");
|
||||
set_thread_description_t std = NULL;
|
||||
std = (set_thread_description_t)GetProcAddress(k32,
|
||||
"SetThreadDescription");
|
||||
if (std) {
|
||||
wchar_t *wname;
|
||||
os_utf8_to_wcs_ptr(name, 0, &wname);
|
||||
|
||||
std(GetCurrentThread(), wname);
|
||||
|
||||
bfree(wname);
|
||||
}
|
||||
FreeLibrary(k32);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ static int utf8_forbidden(unsigned char octet)
|
|||
*
|
||||
* It takes the following arguments:
|
||||
* in - input UTF-8 string. It can be null-terminated.
|
||||
* insize - size of input string in bytes. If insize is 0,
|
||||
* insize - size of input string in bytes. If insize is 0,
|
||||
* function continues until a null terminator is reached.
|
||||
* out - result buffer for UCS-4 string. If out is NULL,
|
||||
* function returns size of result buffer.
|
||||
|
|
@ -143,7 +143,7 @@ size_t utf8_to_wchar(const char *in, size_t insize, wchar_t *out,
|
|||
total = 0;
|
||||
p = (unsigned char *)in;
|
||||
lim = (insize != 0) ? (p + insize) : (unsigned char *)-1;
|
||||
wlim = out + outsize;
|
||||
wlim = out == NULL ? NULL : out + outsize;
|
||||
|
||||
for (; p < lim; p += n) {
|
||||
if (!*p)
|
||||
|
|
@ -272,7 +272,7 @@ size_t wchar_to_utf8(const wchar_t *in, size_t insize, char *out,
|
|||
w = (wchar_t *)in;
|
||||
wlim = (insize != 0) ? (w + insize) : (wchar_t *)-1;
|
||||
p = (unsigned char *)out;
|
||||
lim = p + outsize;
|
||||
lim = out == NULL ? NULL : p + outsize;
|
||||
total = 0;
|
||||
|
||||
for (; w < wlim; w++) {
|
||||
|
|
|
|||
24
libobs/util/util_uint64.h
Normal file
24
libobs/util/util_uint64.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Hans Petter Selasky <hps@selasky.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
static inline uint64_t util_mul_div64(uint64_t num, uint64_t mul, uint64_t div)
|
||||
{
|
||||
const uint64_t rem = num % div;
|
||||
|
||||
return (num / div) * mul + (rem * mul) / div;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue