New upstream version 24.0.1+dfsg1
This commit is contained in:
parent
b14f9eae6d
commit
5a730d6ec3
842 changed files with 42245 additions and 33385 deletions
|
|
@ -454,7 +454,7 @@ if(UNIX AND NOT APPLE)
|
|||
set(PRIVATE_LIBS "${PRIVATE_LIBS} -l${LIB}")
|
||||
endforeach()
|
||||
CONFIGURE_FILE("libobs.pc.in" "libobs.pc" @ONLY)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libobs.pc" DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libobs.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
endif()
|
||||
|
||||
set_target_properties(libobs PROPERTIES
|
||||
|
|
|
|||
|
|
@ -8,21 +8,20 @@
|
|||
#include "mac-helpers.h"
|
||||
|
||||
static bool obs_enum_audio_monitoring_device(obs_enum_audio_device_cb cb,
|
||||
void *data, AudioDeviceID id, bool allow_inputs)
|
||||
void *data, AudioDeviceID id,
|
||||
bool allow_inputs)
|
||||
{
|
||||
UInt32 size = 0;
|
||||
UInt32 size = 0;
|
||||
CFStringRef cf_name = NULL;
|
||||
CFStringRef cf_uid = NULL;
|
||||
char *name = NULL;
|
||||
char *uid = NULL;
|
||||
OSStatus stat;
|
||||
bool cont = true;
|
||||
CFStringRef cf_uid = NULL;
|
||||
char *name = NULL;
|
||||
char *uid = NULL;
|
||||
OSStatus stat;
|
||||
bool cont = true;
|
||||
|
||||
AudioObjectPropertyAddress addr = {
|
||||
kAudioDevicePropertyStreams,
|
||||
kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMaster
|
||||
};
|
||||
AudioObjectPropertyAddress addr = {kAudioDevicePropertyStreams,
|
||||
kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMaster};
|
||||
|
||||
/* Check if the device is capable of audio output. */
|
||||
AudioObjectGetPropertyDataSize(id, &addr, 0, NULL, &size);
|
||||
|
|
@ -66,33 +65,31 @@ fail:
|
|||
}
|
||||
|
||||
static void enum_audio_devices(obs_enum_audio_device_cb cb, void *data,
|
||||
bool allow_inputs)
|
||||
bool allow_inputs)
|
||||
{
|
||||
AudioObjectPropertyAddress addr = {
|
||||
kAudioHardwarePropertyDevices,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMaster
|
||||
};
|
||||
AudioObjectPropertyAddress addr = {kAudioHardwarePropertyDevices,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMaster};
|
||||
|
||||
UInt32 size = 0;
|
||||
UInt32 count;
|
||||
OSStatus stat;
|
||||
UInt32 size = 0;
|
||||
UInt32 count;
|
||||
OSStatus stat;
|
||||
AudioDeviceID *ids;
|
||||
|
||||
stat = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr,
|
||||
0, NULL, &size);
|
||||
0, NULL, &size);
|
||||
if (!success(stat, "get data size"))
|
||||
return;
|
||||
|
||||
ids = malloc(size);
|
||||
ids = malloc(size);
|
||||
count = size / sizeof(AudioDeviceID);
|
||||
|
||||
stat = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr,
|
||||
0, NULL, &size, ids);
|
||||
stat = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0,
|
||||
NULL, &size, ids);
|
||||
if (success(stat, "get data")) {
|
||||
for (UInt32 i = 0; i < count; i++) {
|
||||
if (!obs_enum_audio_monitoring_device(cb, data, ids[i],
|
||||
allow_inputs))
|
||||
allow_inputs))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -119,21 +116,20 @@ static void get_default_id(char **p_id)
|
|||
AudioObjectPropertyAddress addr = {
|
||||
kAudioHardwarePropertyDefaultSystemOutputDevice,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMaster
|
||||
};
|
||||
kAudioObjectPropertyElementMaster};
|
||||
|
||||
if (*p_id)
|
||||
return;
|
||||
|
||||
OSStatus stat;
|
||||
OSStatus stat;
|
||||
AudioDeviceID id = 0;
|
||||
UInt32 size = sizeof(id);
|
||||
UInt32 size = sizeof(id);
|
||||
|
||||
stat = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0,
|
||||
NULL, &size, &id);
|
||||
NULL, &size, &id);
|
||||
if (success(stat, "AudioObjectGetPropertyData"))
|
||||
obs_enum_audio_monitoring_device(alloc_default_id, p_id, id,
|
||||
true);
|
||||
true);
|
||||
if (!*p_id)
|
||||
*p_id = bzalloc(1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,21 +13,21 @@
|
|||
#include "mac-helpers.h"
|
||||
|
||||
struct audio_monitor {
|
||||
obs_source_t *source;
|
||||
AudioQueueRef queue;
|
||||
AudioQueueBufferRef buffers[3];
|
||||
obs_source_t *source;
|
||||
AudioQueueRef queue;
|
||||
AudioQueueBufferRef buffers[3];
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
struct circlebuf empty_buffers;
|
||||
struct circlebuf new_data;
|
||||
audio_resampler_t *resampler;
|
||||
size_t buffer_size;
|
||||
size_t wait_size;
|
||||
uint32_t channels;
|
||||
pthread_mutex_t mutex;
|
||||
struct circlebuf empty_buffers;
|
||||
struct circlebuf new_data;
|
||||
audio_resampler_t *resampler;
|
||||
size_t buffer_size;
|
||||
size_t wait_size;
|
||||
uint32_t channels;
|
||||
|
||||
volatile bool active;
|
||||
bool paused;
|
||||
bool ignore;
|
||||
volatile bool active;
|
||||
bool paused;
|
||||
bool ignore;
|
||||
};
|
||||
|
||||
static inline bool fill_buffer(struct audio_monitor *monitor)
|
||||
|
|
@ -41,21 +41,21 @@ static inline bool fill_buffer(struct audio_monitor *monitor)
|
|||
|
||||
circlebuf_pop_front(&monitor->empty_buffers, &buf, sizeof(buf));
|
||||
circlebuf_pop_front(&monitor->new_data, buf->mAudioData,
|
||||
monitor->buffer_size);
|
||||
monitor->buffer_size);
|
||||
|
||||
buf->mAudioDataByteSize = monitor->buffer_size;
|
||||
|
||||
stat = AudioQueueEnqueueBuffer(monitor->queue, buf, 0, NULL);
|
||||
if (!success(stat, "AudioQueueEnqueueBuffer")) {
|
||||
blog(LOG_WARNING, "%s: %s", __FUNCTION__,
|
||||
"Failed to enqueue buffer");
|
||||
"Failed to enqueue buffer");
|
||||
AudioQueueStop(monitor->queue, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void on_audio_playback(void *param, obs_source_t *source,
|
||||
const struct audio_data *audio_data, bool muted)
|
||||
const struct audio_data *audio_data, bool muted)
|
||||
{
|
||||
struct audio_monitor *monitor = param;
|
||||
float vol = source->user_volume;
|
||||
|
|
@ -72,10 +72,10 @@ static void on_audio_playback(void *param, obs_source_t *source,
|
|||
uint64_t ts_offset;
|
||||
bool success;
|
||||
|
||||
success = audio_resampler_resample(monitor->resampler, resample_data,
|
||||
&resample_frames, &ts_offset,
|
||||
(const uint8_t *const *)audio_data->data,
|
||||
(uint32_t)audio_data->frames);
|
||||
success = audio_resampler_resample(
|
||||
monitor->resampler, resample_data, &resample_frames, &ts_offset,
|
||||
(const uint8_t *const *)audio_data->data,
|
||||
(uint32_t)audio_data->frames);
|
||||
if (!success) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -87,9 +87,9 @@ static void on_audio_playback(void *param, obs_source_t *source,
|
|||
} else {
|
||||
/* apply volume */
|
||||
if (!close_float(vol, 1.0f, EPSILON)) {
|
||||
register float *cur = (float*)resample_data[0];
|
||||
register float *end = cur +
|
||||
resample_frames * monitor->channels;
|
||||
register float *cur = (float *)resample_data[0];
|
||||
register float *end =
|
||||
cur + resample_frames * monitor->channels;
|
||||
|
||||
while (cur < end)
|
||||
*(cur++) *= vol;
|
||||
|
|
@ -141,10 +141,10 @@ static void buffer_audio(void *data, AudioQueueRef aq, AudioQueueBufferRef buf)
|
|||
extern bool devices_match(const char *id1, const char *id2);
|
||||
|
||||
static bool audio_monitor_init(struct audio_monitor *monitor,
|
||||
obs_source_t *source)
|
||||
obs_source_t *source)
|
||||
{
|
||||
const struct audio_output_info *info = audio_output_get_info(
|
||||
obs->audio.audio);
|
||||
const struct audio_output_info *info =
|
||||
audio_output_get_info(obs->audio.audio);
|
||||
uint32_t channels = get_audio_channels(info->speakers);
|
||||
OSStatus stat;
|
||||
|
||||
|
|
@ -152,13 +152,12 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
|
|||
.mSampleRate = (Float64)info->samples_per_sec,
|
||||
.mFormatID = kAudioFormatLinearPCM,
|
||||
.mFormatFlags = kAudioFormatFlagIsFloat |
|
||||
kAudioFormatFlagIsPacked,
|
||||
kAudioFormatFlagIsPacked,
|
||||
.mBytesPerPacket = sizeof(float) * channels,
|
||||
.mFramesPerPacket = 1,
|
||||
.mBytesPerFrame = sizeof(float) * channels,
|
||||
.mChannelsPerFrame = channels,
|
||||
.mBitsPerChannel = sizeof(float) * 8
|
||||
};
|
||||
.mBitsPerChannel = sizeof(float) * 8};
|
||||
|
||||
monitor->source = source;
|
||||
|
||||
|
|
@ -187,20 +186,19 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
|
|||
}
|
||||
|
||||
stat = AudioQueueNewOutput(&desc, buffer_audio, monitor, NULL, NULL, 0,
|
||||
&monitor->queue);
|
||||
&monitor->queue);
|
||||
if (!success(stat, "AudioStreamBasicDescription")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(uid, "default") != 0) {
|
||||
CFStringRef cf_uid = CFStringCreateWithBytes(NULL,
|
||||
(const UInt8*)uid, strlen(uid),
|
||||
kCFStringEncodingUTF8,
|
||||
false);
|
||||
CFStringRef cf_uid = CFStringCreateWithBytes(
|
||||
NULL, (const UInt8 *)uid, strlen(uid),
|
||||
kCFStringEncodingUTF8, false);
|
||||
|
||||
stat = AudioQueueSetProperty(monitor->queue,
|
||||
kAudioQueueProperty_CurrentDevice,
|
||||
&cf_uid, sizeof(cf_uid));
|
||||
kAudioQueueProperty_CurrentDevice,
|
||||
&cf_uid, sizeof(cf_uid));
|
||||
CFRelease(cf_uid);
|
||||
|
||||
if (!success(stat, "set current device")) {
|
||||
|
|
@ -208,45 +206,42 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
|
|||
}
|
||||
}
|
||||
|
||||
stat = AudioQueueSetParameter(monitor->queue,
|
||||
kAudioQueueParam_Volume, 1.0);
|
||||
stat = AudioQueueSetParameter(monitor->queue, kAudioQueueParam_Volume,
|
||||
1.0);
|
||||
if (!success(stat, "set volume")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
stat = AudioQueueAllocateBuffer(monitor->queue,
|
||||
monitor->buffer_size, &monitor->buffers[i]);
|
||||
monitor->buffer_size,
|
||||
&monitor->buffers[i]);
|
||||
if (!success(stat, "allocation of buffer")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
circlebuf_push_back(&monitor->empty_buffers,
|
||||
&monitor->buffers[i],
|
||||
sizeof(monitor->buffers[i]));
|
||||
&monitor->buffers[i],
|
||||
sizeof(monitor->buffers[i]));
|
||||
}
|
||||
|
||||
if (pthread_mutex_init(&monitor->mutex, NULL) != 0) {
|
||||
blog(LOG_WARNING, "%s: %s", __FUNCTION__,
|
||||
"Failed to init mutex");
|
||||
"Failed to init mutex");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct resample_info from = {
|
||||
.samples_per_sec = info->samples_per_sec,
|
||||
.speakers = info->speakers,
|
||||
.format = AUDIO_FORMAT_FLOAT_PLANAR
|
||||
};
|
||||
struct resample_info to = {
|
||||
.samples_per_sec = info->samples_per_sec,
|
||||
.speakers = info->speakers,
|
||||
.format = AUDIO_FORMAT_FLOAT
|
||||
};
|
||||
struct resample_info from = {.samples_per_sec = info->samples_per_sec,
|
||||
.speakers = info->speakers,
|
||||
.format = AUDIO_FORMAT_FLOAT_PLANAR};
|
||||
struct resample_info to = {.samples_per_sec = info->samples_per_sec,
|
||||
.speakers = info->speakers,
|
||||
.format = AUDIO_FORMAT_FLOAT};
|
||||
|
||||
monitor->resampler = audio_resampler_create(&to, &from);
|
||||
if (!monitor->resampler) {
|
||||
blog(LOG_WARNING, "%s: %s", __FUNCTION__,
|
||||
"Failed to create resampler");
|
||||
"Failed to create resampler");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -263,7 +258,7 @@ static void audio_monitor_free(struct audio_monitor *monitor)
|
|||
{
|
||||
if (monitor->source) {
|
||||
obs_source_remove_audio_capture_callback(
|
||||
monitor->source, on_audio_playback, monitor);
|
||||
monitor->source, on_audio_playback, monitor);
|
||||
}
|
||||
if (monitor->active) {
|
||||
AudioQueueStop(monitor->queue, true);
|
||||
|
|
@ -271,7 +266,7 @@ static void audio_monitor_free(struct audio_monitor *monitor)
|
|||
for (size_t i = 0; i < 3; i++) {
|
||||
if (monitor->buffers[i]) {
|
||||
AudioQueueFreeBuffer(monitor->queue,
|
||||
monitor->buffers[i]);
|
||||
monitor->buffers[i]);
|
||||
}
|
||||
}
|
||||
if (monitor->queue) {
|
||||
|
|
@ -290,7 +285,7 @@ static void audio_monitor_init_final(struct audio_monitor *monitor)
|
|||
return;
|
||||
|
||||
obs_source_add_audio_capture_callback(monitor->source,
|
||||
on_audio_playback, monitor);
|
||||
on_audio_playback, monitor);
|
||||
}
|
||||
|
||||
struct audio_monitor *audio_monitor_create(obs_source_t *source)
|
||||
|
|
|
|||
|
|
@ -3,13 +3,11 @@
|
|||
static bool success_(OSStatus stat, const char *func, const char *call)
|
||||
{
|
||||
if (stat != noErr) {
|
||||
blog(LOG_WARNING, "%s: %s failed: %d",
|
||||
func, call, (int)stat);
|
||||
blog(LOG_WARNING, "%s: %s failed: %d", func, call, (int)stat);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define success(stat, call) \
|
||||
success_(stat, __FUNCTION__, call)
|
||||
#define success(stat, call) success_(stat, __FUNCTION__, call)
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@
|
|||
#include "pulseaudio-wrapper.h"
|
||||
|
||||
static void pulseaudio_output_info(pa_context *c, const pa_source_info *i,
|
||||
int eol, void *userdata)
|
||||
int eol, void *userdata)
|
||||
{
|
||||
UNUSED_PARAMETER(c);
|
||||
if (eol != 0 || i->monitor_of_sink == PA_INVALID_INDEX)
|
||||
goto skip;
|
||||
|
||||
struct enum_cb *ecb = (struct enum_cb *) userdata;
|
||||
struct enum_cb *ecb = (struct enum_cb *)userdata;
|
||||
if (ecb->cont)
|
||||
ecb->cont = ecb->cb(ecb->data, i->description, i->name);
|
||||
|
||||
|
|
@ -16,8 +16,7 @@ skip:
|
|||
pulseaudio_signal(0);
|
||||
}
|
||||
|
||||
void obs_enum_audio_monitoring_devices(obs_enum_audio_device_cb cb,
|
||||
void *data)
|
||||
void obs_enum_audio_monitoring_devices(obs_enum_audio_device_cb cb, void *data)
|
||||
{
|
||||
struct enum_cb *ecb = bzalloc(sizeof(struct enum_cb));
|
||||
ecb->cb = cb;
|
||||
|
|
@ -26,7 +25,7 @@ void obs_enum_audio_monitoring_devices(obs_enum_audio_device_cb cb,
|
|||
|
||||
pulseaudio_init();
|
||||
pa_source_info_cb_t pa_cb = pulseaudio_output_info;
|
||||
pulseaudio_get_source_info_list(pa_cb, (void *) ecb);
|
||||
pulseaudio_get_source_info_list(pa_cb, (void *)ecb);
|
||||
pulseaudio_unref();
|
||||
|
||||
bfree(ecb);
|
||||
|
|
|
|||
|
|
@ -5,47 +5,56 @@
|
|||
#define blog(level, msg, ...) blog(level, "pulse-am: " msg, ##__VA_ARGS__)
|
||||
|
||||
struct audio_monitor {
|
||||
obs_source_t *source;
|
||||
pa_stream *stream;
|
||||
char *device;
|
||||
pa_buffer_attr attr;
|
||||
enum speaker_layout speakers;
|
||||
pa_sample_format_t format;
|
||||
uint_fast32_t samples_per_sec;
|
||||
uint_fast32_t bytes_per_frame;
|
||||
uint_fast8_t channels;
|
||||
obs_source_t *source;
|
||||
pa_stream *stream;
|
||||
char *device;
|
||||
pa_buffer_attr attr;
|
||||
enum speaker_layout speakers;
|
||||
pa_sample_format_t format;
|
||||
uint_fast32_t samples_per_sec;
|
||||
uint_fast32_t bytes_per_frame;
|
||||
uint_fast8_t channels;
|
||||
|
||||
uint_fast32_t packets;
|
||||
uint_fast64_t frames;
|
||||
uint_fast32_t packets;
|
||||
uint_fast64_t frames;
|
||||
|
||||
struct circlebuf new_data;
|
||||
audio_resampler_t *resampler;
|
||||
size_t buffer_size;
|
||||
size_t bytesRemaining;
|
||||
size_t bytes_per_channel;
|
||||
struct circlebuf new_data;
|
||||
audio_resampler_t *resampler;
|
||||
size_t buffer_size;
|
||||
size_t bytesRemaining;
|
||||
size_t bytes_per_channel;
|
||||
|
||||
bool ignore;
|
||||
pthread_mutex_t playback_mutex;
|
||||
bool ignore;
|
||||
pthread_mutex_t playback_mutex;
|
||||
};
|
||||
|
||||
static enum speaker_layout pulseaudio_channels_to_obs_speakers(
|
||||
uint_fast32_t channels)
|
||||
static enum speaker_layout
|
||||
pulseaudio_channels_to_obs_speakers(uint_fast32_t channels)
|
||||
{
|
||||
switch (channels) {
|
||||
case 0: return SPEAKERS_UNKNOWN;
|
||||
case 1: return SPEAKERS_MONO;
|
||||
case 2: return SPEAKERS_STEREO;
|
||||
case 3: return SPEAKERS_2POINT1;
|
||||
case 4: return SPEAKERS_4POINT0;
|
||||
case 5: return SPEAKERS_4POINT1;
|
||||
case 6: return SPEAKERS_5POINT1;
|
||||
case 8: return SPEAKERS_7POINT1;
|
||||
default: return SPEAKERS_UNKNOWN;
|
||||
case 0:
|
||||
return SPEAKERS_UNKNOWN;
|
||||
case 1:
|
||||
return SPEAKERS_MONO;
|
||||
case 2:
|
||||
return SPEAKERS_STEREO;
|
||||
case 3:
|
||||
return SPEAKERS_2POINT1;
|
||||
case 4:
|
||||
return SPEAKERS_4POINT0;
|
||||
case 5:
|
||||
return SPEAKERS_4POINT1;
|
||||
case 6:
|
||||
return SPEAKERS_5POINT1;
|
||||
case 8:
|
||||
return SPEAKERS_7POINT1;
|
||||
default:
|
||||
return SPEAKERS_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static enum audio_format pulseaudio_to_obs_audio_format(
|
||||
pa_sample_format_t format)
|
||||
static enum audio_format
|
||||
pulseaudio_to_obs_audio_format(pa_sample_format_t format)
|
||||
{
|
||||
switch (format) {
|
||||
case PA_SAMPLE_U8:
|
||||
|
|
@ -118,7 +127,7 @@ static pa_channel_map pulseaudio_channel_map(enum speaker_layout layout)
|
|||
|
||||
static void process_byte(void *p, size_t frames, size_t channels, float vol)
|
||||
{
|
||||
register char *cur = (char *) p;
|
||||
register char *cur = (char *)p;
|
||||
register char *end = cur + frames * channels;
|
||||
|
||||
while (cur < end)
|
||||
|
|
@ -127,7 +136,7 @@ static void process_byte(void *p, size_t frames, size_t channels, float vol)
|
|||
|
||||
static void process_short(void *p, size_t frames, size_t channels, float vol)
|
||||
{
|
||||
register short *cur = (short *) p;
|
||||
register short *cur = (short *)p;
|
||||
register short *end = cur + frames * channels;
|
||||
|
||||
while (cur < end)
|
||||
|
|
@ -136,7 +145,7 @@ static void process_short(void *p, size_t frames, size_t channels, float vol)
|
|||
|
||||
static void process_float(void *p, size_t frames, size_t channels, float vol)
|
||||
{
|
||||
register float *cur = (float *) p;
|
||||
register float *cur = (float *)p;
|
||||
register float *end = cur + frames * channels;
|
||||
|
||||
while (cur < end)
|
||||
|
|
@ -144,20 +153,20 @@ static void process_float(void *p, size_t frames, size_t channels, float vol)
|
|||
}
|
||||
|
||||
void process_volume(const struct audio_monitor *monitor, float vol,
|
||||
uint8_t *const *resample_data, uint32_t resample_frames)
|
||||
uint8_t *const *resample_data, uint32_t resample_frames)
|
||||
{
|
||||
switch (monitor->bytes_per_channel) {
|
||||
case 1:
|
||||
process_byte(resample_data[0], resample_frames,
|
||||
monitor->channels, vol);
|
||||
monitor->channels, vol);
|
||||
break;
|
||||
case 2:
|
||||
process_short(resample_data[0], resample_frames,
|
||||
monitor->channels, vol);
|
||||
monitor->channels, vol);
|
||||
break;
|
||||
default:
|
||||
process_float(resample_data[0], resample_frames,
|
||||
monitor->channels, vol);
|
||||
monitor->channels, vol);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -168,20 +177,20 @@ static void do_stream_write(void *param)
|
|||
uint8_t *buffer = NULL;
|
||||
|
||||
while (data->new_data.size >= data->buffer_size &&
|
||||
data->bytesRemaining > 0) {
|
||||
data->bytesRemaining > 0) {
|
||||
size_t bytesToFill = data->buffer_size;
|
||||
|
||||
if (bytesToFill > data->bytesRemaining)
|
||||
bytesToFill = data->bytesRemaining;
|
||||
|
||||
pa_stream_begin_write(data->stream, (void **) &buffer,
|
||||
&bytesToFill);
|
||||
pa_stream_begin_write(data->stream, (void **)&buffer,
|
||||
&bytesToFill);
|
||||
|
||||
circlebuf_pop_front(&data->new_data, buffer, bytesToFill);
|
||||
|
||||
pulseaudio_lock();
|
||||
pa_stream_write(data->stream, buffer, bytesToFill, NULL,
|
||||
0LL, PA_SEEK_RELATIVE);
|
||||
pa_stream_write(data->stream, buffer, bytesToFill, NULL, 0LL,
|
||||
PA_SEEK_RELATIVE);
|
||||
pulseaudio_unlock();
|
||||
|
||||
data->bytesRemaining -= bytesToFill;
|
||||
|
|
@ -189,7 +198,7 @@ static void do_stream_write(void *param)
|
|||
}
|
||||
|
||||
static void on_audio_playback(void *param, obs_source_t *source,
|
||||
const struct audio_data *audio_data, bool muted)
|
||||
const struct audio_data *audio_data, bool muted)
|
||||
{
|
||||
struct audio_monitor *monitor = param;
|
||||
float vol = source->user_volume;
|
||||
|
|
@ -206,10 +215,10 @@ static void on_audio_playback(void *param, obs_source_t *source,
|
|||
if (os_atomic_load_long(&source->activate_refs) == 0)
|
||||
goto unlock;
|
||||
|
||||
success = audio_resampler_resample(monitor->resampler, resample_data,
|
||||
&resample_frames, &ts_offset,
|
||||
(const uint8_t *const *) audio_data->data,
|
||||
(uint32_t) audio_data->frames);
|
||||
success = audio_resampler_resample(
|
||||
monitor->resampler, resample_data, &resample_frames, &ts_offset,
|
||||
(const uint8_t *const *)audio_data->data,
|
||||
(uint32_t)audio_data->frames);
|
||||
|
||||
if (!success)
|
||||
goto unlock;
|
||||
|
|
@ -221,7 +230,7 @@ static void on_audio_playback(void *param, obs_source_t *source,
|
|||
} else {
|
||||
if (!close_float(vol, 1.0f, EPSILON)) {
|
||||
process_volume(monitor, vol, resample_data,
|
||||
resample_frames);
|
||||
resample_frames);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -262,19 +271,19 @@ static void pulseaudio_underflow(pa_stream *p, void *userdata)
|
|||
}
|
||||
|
||||
static void pulseaudio_server_info(pa_context *c, const pa_server_info *i,
|
||||
void *userdata)
|
||||
void *userdata)
|
||||
{
|
||||
UNUSED_PARAMETER(c);
|
||||
UNUSED_PARAMETER(userdata);
|
||||
|
||||
blog(LOG_INFO, "Server name: '%s %s'", i->server_name,
|
||||
i->server_version);
|
||||
i->server_version);
|
||||
|
||||
pulseaudio_signal(0);
|
||||
}
|
||||
|
||||
static void pulseaudio_source_info(pa_context *c, const pa_source_info *i,
|
||||
int eol, void *userdata)
|
||||
int eol, void *userdata)
|
||||
{
|
||||
UNUSED_PARAMETER(c);
|
||||
PULSE_DATA(userdata);
|
||||
|
|
@ -287,29 +296,29 @@ static void pulseaudio_source_info(pa_context *c, const pa_source_info *i,
|
|||
if (eol > 0)
|
||||
goto skip;
|
||||
|
||||
blog(LOG_INFO, "Audio format: %s, %"PRIu32" Hz, %"PRIu8" channels",
|
||||
pa_sample_format_to_string(i->sample_spec.format),
|
||||
i->sample_spec.rate, i->sample_spec.channels);
|
||||
blog(LOG_INFO, "Audio format: %s, %" PRIu32 " Hz, %" PRIu8 " channels",
|
||||
pa_sample_format_to_string(i->sample_spec.format),
|
||||
i->sample_spec.rate, i->sample_spec.channels);
|
||||
|
||||
pa_sample_format_t format = i->sample_spec.format;
|
||||
if (pulseaudio_to_obs_audio_format(format) == AUDIO_FORMAT_UNKNOWN) {
|
||||
format = PA_SAMPLE_FLOAT32LE;
|
||||
|
||||
blog(LOG_INFO, "Sample format %s not supported by OBS,"
|
||||
"using %s instead for recording",
|
||||
pa_sample_format_to_string(
|
||||
i->sample_spec.format),
|
||||
pa_sample_format_to_string(format));
|
||||
blog(LOG_INFO,
|
||||
"Sample format %s not supported by OBS,"
|
||||
"using %s instead for recording",
|
||||
pa_sample_format_to_string(i->sample_spec.format),
|
||||
pa_sample_format_to_string(format));
|
||||
}
|
||||
|
||||
uint8_t channels = i->sample_spec.channels;
|
||||
if (pulseaudio_channels_to_obs_speakers(channels) == SPEAKERS_UNKNOWN) {
|
||||
channels = 2;
|
||||
|
||||
blog(LOG_INFO, "%c channels not supported by OBS,"
|
||||
"using %c instead for recording",
|
||||
i->sample_spec.channels,
|
||||
channels);
|
||||
blog(LOG_INFO,
|
||||
"%c channels not supported by OBS,"
|
||||
"using %c instead for recording",
|
||||
i->sample_spec.channels, channels);
|
||||
}
|
||||
|
||||
data->format = format;
|
||||
|
|
@ -328,15 +337,16 @@ static void pulseaudio_stop_playback(struct audio_monitor *monitor)
|
|||
}
|
||||
|
||||
blog(LOG_INFO, "Stopped Monitoring in '%s'", monitor->device);
|
||||
blog(LOG_INFO, "Got %"PRIuFAST32" packets with %"PRIuFAST64" frames",
|
||||
monitor->packets, monitor->frames);
|
||||
blog(LOG_INFO,
|
||||
"Got %" PRIuFAST32 " packets with %" PRIuFAST64 " frames",
|
||||
monitor->packets, monitor->frames);
|
||||
|
||||
monitor->packets = 0;
|
||||
monitor->frames = 0;
|
||||
}
|
||||
|
||||
static bool audio_monitor_init(struct audio_monitor *monitor,
|
||||
obs_source_t *source)
|
||||
obs_source_t *source)
|
||||
{
|
||||
pthread_mutex_init_value(&monitor->playback_mutex);
|
||||
|
||||
|
|
@ -355,7 +365,7 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
|
|||
if (match) {
|
||||
monitor->ignore = true;
|
||||
blog(LOG_INFO, "Prevented feedback-loop in '%s'",
|
||||
s_dev_id);
|
||||
s_dev_id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -371,25 +381,25 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
|
|||
return false;
|
||||
|
||||
if (pulseaudio_get_server_info(pulseaudio_server_info,
|
||||
(void *) monitor) < 0) {
|
||||
(void *)monitor) < 0) {
|
||||
blog(LOG_ERROR, "Unable to get server info !");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pulseaudio_get_source_info(pulseaudio_source_info, monitor->device,
|
||||
(void *) monitor) < 0) {
|
||||
(void *)monitor) < 0) {
|
||||
blog(LOG_ERROR, "Unable to get source info !");
|
||||
return false;
|
||||
}
|
||||
if (monitor->format == PA_SAMPLE_INVALID) {
|
||||
blog(LOG_ERROR,
|
||||
"An error occurred while getting the source info!");
|
||||
"An error occurred while getting the source info!");
|
||||
return false;
|
||||
}
|
||||
|
||||
pa_sample_spec spec;
|
||||
spec.format = monitor->format;
|
||||
spec.rate = (uint32_t) monitor->samples_per_sec;
|
||||
spec.rate = (uint32_t)monitor->samples_per_sec;
|
||||
spec.channels = monitor->channels;
|
||||
|
||||
if (!pa_sample_spec_valid(&spec)) {
|
||||
|
|
@ -397,31 +407,27 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
|
|||
return false;
|
||||
}
|
||||
|
||||
const struct audio_output_info *info = audio_output_get_info(
|
||||
obs->audio.audio);
|
||||
const struct audio_output_info *info =
|
||||
audio_output_get_info(obs->audio.audio);
|
||||
|
||||
struct resample_info from = {
|
||||
.samples_per_sec = info->samples_per_sec,
|
||||
.speakers = info->speakers,
|
||||
.format = AUDIO_FORMAT_FLOAT_PLANAR
|
||||
};
|
||||
struct resample_info from = {.samples_per_sec = info->samples_per_sec,
|
||||
.speakers = info->speakers,
|
||||
.format = AUDIO_FORMAT_FLOAT_PLANAR};
|
||||
struct resample_info to = {
|
||||
.samples_per_sec = (uint32_t) monitor->samples_per_sec,
|
||||
.speakers = pulseaudio_channels_to_obs_speakers(
|
||||
monitor->channels),
|
||||
.format = pulseaudio_to_obs_audio_format
|
||||
(monitor->format)
|
||||
};
|
||||
.samples_per_sec = (uint32_t)monitor->samples_per_sec,
|
||||
.speakers =
|
||||
pulseaudio_channels_to_obs_speakers(monitor->channels),
|
||||
.format = pulseaudio_to_obs_audio_format(monitor->format)};
|
||||
|
||||
monitor->resampler = audio_resampler_create(&to, &from);
|
||||
if (!monitor->resampler) {
|
||||
blog(LOG_WARNING, "%s: %s", __FUNCTION__,
|
||||
"Failed to create resampler");
|
||||
"Failed to create resampler");
|
||||
return false;
|
||||
}
|
||||
|
||||
monitor->bytes_per_channel = get_audio_bytes_per_channel(
|
||||
pulseaudio_to_obs_audio_format(monitor->format));
|
||||
pulseaudio_to_obs_audio_format(monitor->format));
|
||||
monitor->speakers = pulseaudio_channels_to_obs_speakers(spec.channels);
|
||||
monitor->bytes_per_frame = pa_frame_size(&spec);
|
||||
|
||||
|
|
@ -434,26 +440,26 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
|
|||
return false;
|
||||
}
|
||||
|
||||
monitor->attr.fragsize = (uint32_t) -1;
|
||||
monitor->attr.maxlength = (uint32_t) -1;
|
||||
monitor->attr.minreq = (uint32_t) -1;
|
||||
monitor->attr.prebuf = (uint32_t) -1;
|
||||
monitor->attr.fragsize = (uint32_t)-1;
|
||||
monitor->attr.maxlength = (uint32_t)-1;
|
||||
monitor->attr.minreq = (uint32_t)-1;
|
||||
monitor->attr.prebuf = (uint32_t)-1;
|
||||
monitor->attr.tlength = pa_usec_to_bytes(25000, &spec);
|
||||
|
||||
monitor->buffer_size = monitor->bytes_per_frame *
|
||||
pa_usec_to_bytes(5000, &spec);
|
||||
monitor->buffer_size =
|
||||
monitor->bytes_per_frame * pa_usec_to_bytes(5000, &spec);
|
||||
|
||||
pa_stream_flags_t flags = PA_STREAM_INTERPOLATE_TIMING |
|
||||
PA_STREAM_AUTO_TIMING_UPDATE;
|
||||
PA_STREAM_AUTO_TIMING_UPDATE;
|
||||
|
||||
if (pthread_mutex_init(&monitor->playback_mutex, NULL) != 0) {
|
||||
blog(LOG_WARNING, "%s: %s", __FUNCTION__,
|
||||
"Failed to init mutex");
|
||||
"Failed to init mutex");
|
||||
return false;
|
||||
}
|
||||
|
||||
int_fast32_t ret = pulseaudio_connect_playback(monitor->stream,
|
||||
monitor->device, &monitor->attr, flags);
|
||||
int_fast32_t ret = pulseaudio_connect_playback(
|
||||
monitor->stream, monitor->device, &monitor->attr, flags);
|
||||
if (ret < 0) {
|
||||
pulseaudio_stop_playback(monitor);
|
||||
blog(LOG_ERROR, "Unable to connect to stream");
|
||||
|
|
@ -470,13 +476,13 @@ static void audio_monitor_init_final(struct audio_monitor *monitor)
|
|||
return;
|
||||
|
||||
obs_source_add_audio_capture_callback(monitor->source,
|
||||
on_audio_playback, monitor);
|
||||
on_audio_playback, monitor);
|
||||
|
||||
pulseaudio_write_callback(monitor->stream, pulseaudio_stream_write,
|
||||
(void *) monitor);
|
||||
(void *)monitor);
|
||||
|
||||
pulseaudio_set_underflow_callback(monitor->stream, pulseaudio_underflow,
|
||||
(void *) monitor);
|
||||
(void *)monitor);
|
||||
}
|
||||
|
||||
static inline void audio_monitor_free(struct audio_monitor *monitor)
|
||||
|
|
@ -485,8 +491,8 @@ static inline void audio_monitor_free(struct audio_monitor *monitor)
|
|||
return;
|
||||
|
||||
if (monitor->source)
|
||||
obs_source_remove_audio_capture_callback(monitor->source,
|
||||
on_audio_playback, monitor);
|
||||
obs_source_remove_audio_capture_callback(
|
||||
monitor->source, on_audio_playback, monitor);
|
||||
|
||||
audio_resampler_destroy(monitor->resampler);
|
||||
circlebuf_free(&monitor->new_data);
|
||||
|
|
|
|||
|
|
@ -32,11 +32,11 @@ static pa_threaded_mainloop *pulseaudio_mainloop = NULL;
|
|||
static pa_context *pulseaudio_context = NULL;
|
||||
|
||||
static void pulseaudio_default_devices(pa_context *c, const pa_server_info *i,
|
||||
void *userdata)
|
||||
void *userdata)
|
||||
{
|
||||
UNUSED_PARAMETER(c);
|
||||
struct pulseaudio_default_output *d =
|
||||
(struct pulseaudio_default_output *) userdata;
|
||||
(struct pulseaudio_default_output *)userdata;
|
||||
d->default_sink_name = bstrdup(i->default_sink_name);
|
||||
pulseaudio_signal(0);
|
||||
}
|
||||
|
|
@ -44,11 +44,10 @@ static void pulseaudio_default_devices(pa_context *c, const pa_server_info *i,
|
|||
void get_default_id(char **id)
|
||||
{
|
||||
pulseaudio_init();
|
||||
struct pulseaudio_default_output *pdo = bzalloc(
|
||||
sizeof(struct pulseaudio_default_output));
|
||||
struct pulseaudio_default_output *pdo =
|
||||
bzalloc(sizeof(struct pulseaudio_default_output));
|
||||
pulseaudio_get_server_info(
|
||||
(pa_server_info_cb_t) pulseaudio_default_devices,
|
||||
(void *) pdo);
|
||||
(pa_server_info_cb_t)pulseaudio_default_devices, (void *)pdo);
|
||||
*id = bzalloc(strlen(pdo->default_sink_name) + 9);
|
||||
strcat(*id, pdo->default_sink_name);
|
||||
strcat(*id, ".monitor");
|
||||
|
|
@ -118,14 +117,14 @@ static void pulseaudio_init_context()
|
|||
|
||||
pa_proplist *p = pulseaudio_properties();
|
||||
pulseaudio_context = pa_context_new_with_proplist(
|
||||
pa_threaded_mainloop_get_api(pulseaudio_mainloop),
|
||||
"OBS-Monitor", p);
|
||||
pa_threaded_mainloop_get_api(pulseaudio_mainloop),
|
||||
"OBS-Monitor", p);
|
||||
|
||||
pa_context_set_state_callback(pulseaudio_context,
|
||||
pulseaudio_context_state_changed, NULL);
|
||||
pulseaudio_context_state_changed, NULL);
|
||||
|
||||
pa_context_connect(pulseaudio_context, NULL, PA_CONTEXT_NOAUTOSPAWN,
|
||||
NULL);
|
||||
NULL);
|
||||
pa_proplist_free(p);
|
||||
|
||||
pulseaudio_unlock();
|
||||
|
|
@ -217,15 +216,15 @@ void pulseaudio_accept()
|
|||
}
|
||||
|
||||
int_fast32_t pulseaudio_get_source_info_list(pa_source_info_cb_t cb,
|
||||
void *userdata)
|
||||
void *userdata)
|
||||
{
|
||||
if (pulseaudio_context_ready() < 0)
|
||||
return -1;
|
||||
|
||||
pulseaudio_lock();
|
||||
|
||||
pa_operation *op = pa_context_get_source_info_list(
|
||||
pulseaudio_context, cb, userdata);
|
||||
pa_operation *op = pa_context_get_source_info_list(pulseaudio_context,
|
||||
cb, userdata);
|
||||
if (!op) {
|
||||
pulseaudio_unlock();
|
||||
return -1;
|
||||
|
|
@ -240,7 +239,7 @@ int_fast32_t pulseaudio_get_source_info_list(pa_source_info_cb_t cb,
|
|||
}
|
||||
|
||||
int_fast32_t pulseaudio_get_source_info(pa_source_info_cb_t cb,
|
||||
const char *name, void *userdata)
|
||||
const char *name, void *userdata)
|
||||
{
|
||||
if (pulseaudio_context_ready() < 0)
|
||||
return -1;
|
||||
|
|
@ -248,7 +247,7 @@ int_fast32_t pulseaudio_get_source_info(pa_source_info_cb_t cb,
|
|||
pulseaudio_lock();
|
||||
|
||||
pa_operation *op = pa_context_get_source_info_by_name(
|
||||
pulseaudio_context, name, cb, userdata);
|
||||
pulseaudio_context, name, cb, userdata);
|
||||
if (!op) {
|
||||
pulseaudio_unlock();
|
||||
return -1;
|
||||
|
|
@ -269,8 +268,8 @@ int_fast32_t pulseaudio_get_server_info(pa_server_info_cb_t cb, void *userdata)
|
|||
|
||||
pulseaudio_lock();
|
||||
|
||||
pa_operation *op = pa_context_get_server_info(
|
||||
pulseaudio_context, cb, userdata);
|
||||
pa_operation *op =
|
||||
pa_context_get_server_info(pulseaudio_context, cb, userdata);
|
||||
if (!op) {
|
||||
pulseaudio_unlock();
|
||||
return -1;
|
||||
|
|
@ -284,7 +283,7 @@ int_fast32_t pulseaudio_get_server_info(pa_server_info_cb_t cb, void *userdata)
|
|||
}
|
||||
|
||||
pa_stream *pulseaudio_stream_new(const char *name, const pa_sample_spec *ss,
|
||||
const pa_channel_map *map)
|
||||
const pa_channel_map *map)
|
||||
{
|
||||
if (pulseaudio_context_ready() < 0)
|
||||
return NULL;
|
||||
|
|
@ -292,8 +291,8 @@ pa_stream *pulseaudio_stream_new(const char *name, const pa_sample_spec *ss,
|
|||
pulseaudio_lock();
|
||||
|
||||
pa_proplist *p = pulseaudio_properties();
|
||||
pa_stream *s = pa_stream_new_with_proplist(
|
||||
pulseaudio_context, name, ss, map, p);
|
||||
pa_stream *s = pa_stream_new_with_proplist(pulseaudio_context, name, ss,
|
||||
map, p);
|
||||
pa_proplist_free(p);
|
||||
|
||||
pulseaudio_unlock();
|
||||
|
|
@ -301,7 +300,8 @@ pa_stream *pulseaudio_stream_new(const char *name, const pa_sample_spec *ss,
|
|||
}
|
||||
|
||||
int_fast32_t pulseaudio_connect_playback(pa_stream *s, const char *name,
|
||||
const pa_buffer_attr *attr, pa_stream_flags_t flags)
|
||||
const pa_buffer_attr *attr,
|
||||
pa_stream_flags_t flags)
|
||||
{
|
||||
if (pulseaudio_context_ready() < 0)
|
||||
return -1;
|
||||
|
|
@ -311,8 +311,8 @@ int_fast32_t pulseaudio_connect_playback(pa_stream *s, const char *name,
|
|||
memcpy(device, name, dev_len);
|
||||
|
||||
pulseaudio_lock();
|
||||
int_fast32_t ret = pa_stream_connect_playback(s, device, attr, flags,
|
||||
NULL, NULL);
|
||||
int_fast32_t ret =
|
||||
pa_stream_connect_playback(s, device, attr, flags, NULL, NULL);
|
||||
pulseaudio_unlock();
|
||||
|
||||
bfree(device);
|
||||
|
|
@ -320,7 +320,7 @@ int_fast32_t pulseaudio_connect_playback(pa_stream *s, const char *name,
|
|||
}
|
||||
|
||||
void pulseaudio_write_callback(pa_stream *p, pa_stream_request_cb_t cb,
|
||||
void *userdata)
|
||||
void *userdata)
|
||||
{
|
||||
if (pulseaudio_context_ready() < 0)
|
||||
return;
|
||||
|
|
@ -331,7 +331,7 @@ void pulseaudio_write_callback(pa_stream *p, pa_stream_request_cb_t cb,
|
|||
}
|
||||
|
||||
void pulseaudio_set_underflow_callback(pa_stream *p, pa_stream_notify_cb_t cb,
|
||||
void *userdata)
|
||||
void *userdata)
|
||||
{
|
||||
if (pulseaudio_context_ready() < 0)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ void pulseaudio_accept();
|
|||
* @warning call without active locks
|
||||
*/
|
||||
int_fast32_t pulseaudio_get_source_info_list(pa_source_info_cb_t cb,
|
||||
void *userdata);
|
||||
void *userdata);
|
||||
|
||||
/**
|
||||
* Request source information from a specific source
|
||||
|
|
@ -126,7 +126,7 @@ int_fast32_t pulseaudio_get_source_info_list(pa_source_info_cb_t cb,
|
|||
* @warning call without active locks
|
||||
*/
|
||||
int_fast32_t pulseaudio_get_source_info(pa_source_info_cb_t cb,
|
||||
const char *name, void *userdata);
|
||||
const char *name, void *userdata);
|
||||
|
||||
/**
|
||||
* Request server information
|
||||
|
|
@ -150,7 +150,7 @@ int_fast32_t pulseaudio_get_server_info(pa_server_info_cb_t cb, void *userdata);
|
|||
* @warning call without active locks
|
||||
*/
|
||||
pa_stream *pulseaudio_stream_new(const char *name, const pa_sample_spec *ss,
|
||||
const pa_channel_map *map);
|
||||
const pa_channel_map *map);
|
||||
|
||||
/**
|
||||
* Connect to a pulseaudio playback stream
|
||||
|
|
@ -162,7 +162,8 @@ pa_stream *pulseaudio_stream_new(const char *name, const pa_sample_spec *ss,
|
|||
* @return negative on error
|
||||
*/
|
||||
int_fast32_t pulseaudio_connect_playback(pa_stream *s, const char *name,
|
||||
const pa_buffer_attr *attr, pa_stream_flags_t flags);
|
||||
const pa_buffer_attr *attr,
|
||||
pa_stream_flags_t flags);
|
||||
|
||||
/**
|
||||
* Sets a callback function for when data can be written to the stream
|
||||
|
|
@ -172,7 +173,7 @@ int_fast32_t pulseaudio_connect_playback(pa_stream *s, const char *name,
|
|||
* @param userdata pointer to userdata the callback will be called with
|
||||
*/
|
||||
void pulseaudio_write_callback(pa_stream *p, pa_stream_request_cb_t cb,
|
||||
void *userdata);
|
||||
void *userdata);
|
||||
|
||||
/**
|
||||
* Sets a callback function for when an underflow happen
|
||||
|
|
@ -182,4 +183,4 @@ void pulseaudio_write_callback(pa_stream *p, pa_stream_request_cb_t cb,
|
|||
* @param userdata pointer to userdata the callback will be called with
|
||||
*/
|
||||
void pulseaudio_set_underflow_callback(pa_stream *p, pa_stream_notify_cb_t cb,
|
||||
void *userdata);
|
||||
void *userdata);
|
||||
|
|
|
|||
|
|
@ -10,10 +10,22 @@
|
|||
#undef DEFINE_PROPERTYKEY
|
||||
#endif
|
||||
#define DEFINE_PROPERTYKEY(id, a, b, c, d, e, f, g, h, i, j, k, l) \
|
||||
const PROPERTYKEY id = { { a,b,c, { d,e,f,g,h,i,j,k, } }, l };
|
||||
DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, \
|
||||
0xa45c254e, 0xdf1c, 0x4efd, 0x80, \
|
||||
0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14);
|
||||
const PROPERTYKEY id = {{a, \
|
||||
b, \
|
||||
c, \
|
||||
{ \
|
||||
d, \
|
||||
e, \
|
||||
f, \
|
||||
g, \
|
||||
h, \
|
||||
i, \
|
||||
j, \
|
||||
k, \
|
||||
}}, \
|
||||
l};
|
||||
DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,
|
||||
0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14);
|
||||
|
||||
#else
|
||||
|
||||
|
|
@ -22,7 +34,7 @@ DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, \
|
|||
#endif
|
||||
|
||||
static bool get_device_info(obs_enum_audio_device_cb cb, void *data,
|
||||
IMMDeviceCollection *collection, UINT idx)
|
||||
IMMDeviceCollection *collection, UINT idx)
|
||||
{
|
||||
IPropertyStore *store = NULL;
|
||||
IMMDevice *device = NULL;
|
||||
|
|
@ -50,7 +62,7 @@ static bool get_device_info(obs_enum_audio_device_cb cb, void *data,
|
|||
|
||||
PropVariantInit(&name_var);
|
||||
hr = store->lpVtbl->GetValue(store, &PKEY_Device_FriendlyName,
|
||||
&name_var);
|
||||
&name_var);
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -68,8 +80,7 @@ fail:
|
|||
return cont;
|
||||
}
|
||||
|
||||
void obs_enum_audio_monitoring_devices(obs_enum_audio_device_cb cb,
|
||||
void *data)
|
||||
void obs_enum_audio_monitoring_devices(obs_enum_audio_device_cb cb, void *data)
|
||||
{
|
||||
IMMDeviceEnumerator *enumerator = NULL;
|
||||
IMMDeviceCollection *collection = NULL;
|
||||
|
|
@ -77,13 +88,13 @@ void obs_enum_audio_monitoring_devices(obs_enum_audio_device_cb cb,
|
|||
HRESULT hr;
|
||||
|
||||
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
|
||||
&IID_IMMDeviceEnumerator, &enumerator);
|
||||
&IID_IMMDeviceEnumerator, &enumerator);
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = enumerator->lpVtbl->EnumAudioEndpoints(enumerator, eRender,
|
||||
DEVICE_STATE_ACTIVE, &collection);
|
||||
hr = enumerator->lpVtbl->EnumAudioEndpoints(
|
||||
enumerator, eRender, DEVICE_STATE_ACTIVE, &collection);
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -115,13 +126,13 @@ static void get_default_id(char **p_id)
|
|||
return;
|
||||
|
||||
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
|
||||
&IID_IMMDeviceEnumerator, &immde);
|
||||
&IID_IMMDeviceEnumerator, &immde);
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = immde->lpVtbl->GetDefaultAudioEndpoint(immde,
|
||||
eRender, eConsole, &device);
|
||||
hr = immde->lpVtbl->GetDefaultAudioEndpoint(immde, eRender, eConsole,
|
||||
&device);
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,49 +7,45 @@
|
|||
#include "wasapi-output.h"
|
||||
|
||||
#define ACTUALLY_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
EXTERN_C const GUID DECLSPEC_SELECTANY name \
|
||||
= { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
|
||||
EXTERN_C const GUID DECLSPEC_SELECTANY name = { \
|
||||
l, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}}
|
||||
|
||||
ACTUALLY_DEFINE_GUID(CLSID_MMDeviceEnumerator,
|
||||
0xBCDE0395, 0xE52F, 0x467C,
|
||||
0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E);
|
||||
ACTUALLY_DEFINE_GUID(IID_IMMDeviceEnumerator,
|
||||
0xA95664D2, 0x9614, 0x4F35,
|
||||
0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6);
|
||||
ACTUALLY_DEFINE_GUID(IID_IAudioClient,
|
||||
0x1CB9AD4C, 0xDBFA, 0x4C32,
|
||||
0xB1, 0x78, 0xC2, 0xF5, 0x68, 0xA7, 0x03, 0xB2);
|
||||
ACTUALLY_DEFINE_GUID(IID_IAudioRenderClient,
|
||||
0xF294ACFC, 0x3146, 0x4483,
|
||||
0xA7, 0xBF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2);
|
||||
ACTUALLY_DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xBCDE0395, 0xE52F, 0x467C, 0x8E,
|
||||
0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E);
|
||||
ACTUALLY_DEFINE_GUID(IID_IMMDeviceEnumerator, 0xA95664D2, 0x9614, 0x4F35, 0xA7,
|
||||
0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6);
|
||||
ACTUALLY_DEFINE_GUID(IID_IAudioClient, 0x1CB9AD4C, 0xDBFA, 0x4C32, 0xB1, 0x78,
|
||||
0xC2, 0xF5, 0x68, 0xA7, 0x03, 0xB2);
|
||||
ACTUALLY_DEFINE_GUID(IID_IAudioRenderClient, 0xF294ACFC, 0x3146, 0x4483, 0xA7,
|
||||
0xBF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2);
|
||||
|
||||
struct audio_monitor {
|
||||
obs_source_t *source;
|
||||
IMMDevice *device;
|
||||
IAudioClient *client;
|
||||
obs_source_t *source;
|
||||
IMMDevice *device;
|
||||
IAudioClient *client;
|
||||
IAudioRenderClient *render;
|
||||
|
||||
uint64_t last_recv_time;
|
||||
uint64_t prev_video_ts;
|
||||
uint64_t time_since_prev;
|
||||
audio_resampler_t *resampler;
|
||||
uint32_t sample_rate;
|
||||
uint32_t channels;
|
||||
bool source_has_video;
|
||||
bool ignore;
|
||||
uint64_t last_recv_time;
|
||||
uint64_t prev_video_ts;
|
||||
uint64_t time_since_prev;
|
||||
audio_resampler_t *resampler;
|
||||
uint32_t sample_rate;
|
||||
uint32_t channels;
|
||||
bool source_has_video;
|
||||
bool ignore;
|
||||
|
||||
int64_t lowest_audio_offset;
|
||||
struct circlebuf delay_buffer;
|
||||
uint32_t delay_size;
|
||||
int64_t lowest_audio_offset;
|
||||
struct circlebuf delay_buffer;
|
||||
uint32_t delay_size;
|
||||
|
||||
DARRAY(float) buf;
|
||||
pthread_mutex_t playback_mutex;
|
||||
DARRAY(float) buf;
|
||||
pthread_mutex_t playback_mutex;
|
||||
};
|
||||
|
||||
/* #define DEBUG_AUDIO */
|
||||
|
||||
static bool process_audio_delay(struct audio_monitor *monitor,
|
||||
float **data, uint32_t *frames, uint64_t ts, uint32_t pad)
|
||||
static bool process_audio_delay(struct audio_monitor *monitor, float **data,
|
||||
uint32_t *frames, uint64_t ts, uint32_t pad)
|
||||
{
|
||||
obs_source_t *s = monitor->source;
|
||||
uint64_t last_frame_ts = s->last_frame_ts;
|
||||
|
|
@ -68,15 +64,14 @@ static bool process_audio_delay(struct audio_monitor *monitor,
|
|||
|
||||
circlebuf_push_back(&monitor->delay_buffer, &ts, sizeof(ts));
|
||||
circlebuf_push_back(&monitor->delay_buffer, frames, sizeof(*frames));
|
||||
circlebuf_push_back(&monitor->delay_buffer, *data,
|
||||
*frames * blocksize);
|
||||
circlebuf_push_back(&monitor->delay_buffer, *data, *frames * blocksize);
|
||||
|
||||
if (!monitor->prev_video_ts) {
|
||||
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 += (uint64_t)*frames * 1000000000ULL /
|
||||
(uint64_t)monitor->sample_rate;
|
||||
} else {
|
||||
monitor->time_since_prev = 0;
|
||||
}
|
||||
|
|
@ -86,44 +81,45 @@ static bool process_audio_delay(struct audio_monitor *monitor,
|
|||
bool bad_diff;
|
||||
|
||||
circlebuf_peek_front(&monitor->delay_buffer, &cur_ts,
|
||||
sizeof(ts));
|
||||
front_ts = cur_ts -
|
||||
((uint64_t)pad * 1000000000ULL /
|
||||
(uint64_t)monitor->sample_rate);
|
||||
sizeof(ts));
|
||||
front_ts = cur_ts - ((uint64_t)pad * 1000000000ULL /
|
||||
(uint64_t)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;
|
||||
bad_diff = !last_frame_ts || llabs(diff) > 5000000000 ||
|
||||
monitor->time_since_prev > 100000000ULL;
|
||||
|
||||
/* delay audio if rushing */
|
||||
if (!bad_diff && diff > 75000000) {
|
||||
#ifdef DEBUG_AUDIO
|
||||
blog(LOG_INFO, "audio rushing, cutting audio, "
|
||||
"diff: %lld, delay buffer size: %lu, "
|
||||
"v: %llu: a: %llu",
|
||||
diff, (int)monitor->delay_buffer.size,
|
||||
last_frame_ts, front_ts);
|
||||
blog(LOG_INFO,
|
||||
"audio rushing, cutting audio, "
|
||||
"diff: %lld, delay buffer size: %lu, "
|
||||
"v: %llu: a: %llu",
|
||||
diff, (int)monitor->delay_buffer.size,
|
||||
last_frame_ts, front_ts);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
circlebuf_pop_front(&monitor->delay_buffer, NULL, sizeof(ts));
|
||||
circlebuf_pop_front(&monitor->delay_buffer, frames,
|
||||
sizeof(*frames));
|
||||
sizeof(*frames));
|
||||
|
||||
size = *frames * blocksize;
|
||||
da_resize(monitor->buf, size);
|
||||
circlebuf_pop_front(&monitor->delay_buffer,
|
||||
monitor->buf.array, size);
|
||||
circlebuf_pop_front(&monitor->delay_buffer, monitor->buf.array,
|
||||
size);
|
||||
|
||||
/* cut audio if dragging */
|
||||
if (!bad_diff && diff < -75000000 && monitor->delay_buffer.size > 0) {
|
||||
if (!bad_diff && diff < -75000000 &&
|
||||
monitor->delay_buffer.size > 0) {
|
||||
#ifdef DEBUG_AUDIO
|
||||
blog(LOG_INFO, "audio dragging, cutting audio, "
|
||||
"diff: %lld, delay buffer size: %lu, "
|
||||
"v: %llu: a: %llu",
|
||||
diff, (int)monitor->delay_buffer.size,
|
||||
last_frame_ts, front_ts);
|
||||
blog(LOG_INFO,
|
||||
"audio dragging, cutting audio, "
|
||||
"diff: %lld, delay buffer size: %lu, "
|
||||
"v: %llu: a: %llu",
|
||||
diff, (int)monitor->delay_buffer.size,
|
||||
last_frame_ts, front_ts);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
|
@ -136,7 +132,7 @@ static bool process_audio_delay(struct audio_monitor *monitor,
|
|||
}
|
||||
|
||||
static void on_audio_playback(void *param, obs_source_t *source,
|
||||
const struct audio_data *audio_data, bool muted)
|
||||
const struct audio_data *audio_data, bool muted)
|
||||
{
|
||||
struct audio_monitor *monitor = param;
|
||||
IAudioRenderClient *render = monitor->render;
|
||||
|
|
@ -154,10 +150,10 @@ static void on_audio_playback(void *param, obs_source_t *source,
|
|||
goto unlock;
|
||||
}
|
||||
|
||||
success = audio_resampler_resample(monitor->resampler, resample_data,
|
||||
&resample_frames, &ts_offset,
|
||||
(const uint8_t *const *)audio_data->data,
|
||||
(uint32_t)audio_data->frames);
|
||||
success = audio_resampler_resample(
|
||||
monitor->resampler, resample_data, &resample_frames, &ts_offset,
|
||||
(const uint8_t *const *)audio_data->data,
|
||||
(uint32_t)audio_data->frames);
|
||||
if (!success) {
|
||||
goto unlock;
|
||||
}
|
||||
|
|
@ -165,20 +161,20 @@ static void on_audio_playback(void *param, obs_source_t *source,
|
|||
UINT32 pad = 0;
|
||||
monitor->client->lpVtbl->GetCurrentPadding(monitor->client, &pad);
|
||||
|
||||
bool decouple_audio =
|
||||
source->async_unbuffered && source->async_decoupled;
|
||||
bool decouple_audio = source->async_unbuffered &&
|
||||
source->async_decoupled;
|
||||
|
||||
if (monitor->source_has_video && !decouple_audio) {
|
||||
uint64_t ts = audio_data->timestamp - ts_offset;
|
||||
|
||||
if (!process_audio_delay(monitor, (float**)(&resample_data[0]),
|
||||
&resample_frames, ts, pad)) {
|
||||
if (!process_audio_delay(monitor, (float **)(&resample_data[0]),
|
||||
&resample_frames, ts, pad)) {
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr = render->lpVtbl->GetBuffer(render, resample_frames,
|
||||
&output);
|
||||
HRESULT hr =
|
||||
render->lpVtbl->GetBuffer(render, resample_frames, &output);
|
||||
if (FAILED(hr)) {
|
||||
goto unlock;
|
||||
}
|
||||
|
|
@ -186,20 +182,19 @@ static void on_audio_playback(void *param, obs_source_t *source,
|
|||
if (!muted) {
|
||||
/* apply volume */
|
||||
if (!close_float(vol, 1.0f, EPSILON)) {
|
||||
register float *cur = (float*)resample_data[0];
|
||||
register float *end = cur +
|
||||
resample_frames * monitor->channels;
|
||||
register float *cur = (float *)resample_data[0];
|
||||
register float *end =
|
||||
cur + resample_frames * monitor->channels;
|
||||
|
||||
while (cur < end)
|
||||
*(cur++) *= vol;
|
||||
}
|
||||
memcpy(output, resample_data[0],
|
||||
resample_frames * monitor->channels *
|
||||
sizeof(float));
|
||||
resample_frames * monitor->channels * sizeof(float));
|
||||
}
|
||||
|
||||
render->lpVtbl->ReleaseBuffer(render, resample_frames,
|
||||
muted ? AUDCLNT_BUFFERFLAGS_SILENT : 0);
|
||||
muted ? AUDCLNT_BUFFERFLAGS_SILENT : 0);
|
||||
|
||||
unlock:
|
||||
pthread_mutex_unlock(&monitor->playback_mutex);
|
||||
|
|
@ -212,7 +207,7 @@ static inline void audio_monitor_free(struct audio_monitor *monitor)
|
|||
|
||||
if (monitor->source) {
|
||||
obs_source_remove_audio_capture_callback(
|
||||
monitor->source, on_audio_playback, monitor);
|
||||
monitor->source, on_audio_playback, monitor);
|
||||
}
|
||||
|
||||
if (monitor->client)
|
||||
|
|
@ -229,11 +224,16 @@ static inline void audio_monitor_free(struct audio_monitor *monitor)
|
|||
static enum speaker_layout convert_speaker_layout(DWORD layout, WORD channels)
|
||||
{
|
||||
switch (layout) {
|
||||
case KSAUDIO_SPEAKER_2POINT1: return SPEAKERS_2POINT1;
|
||||
case KSAUDIO_SPEAKER_SURROUND: return SPEAKERS_4POINT0;
|
||||
case KSAUDIO_SPEAKER_4POINT1: return SPEAKERS_4POINT1;
|
||||
case KSAUDIO_SPEAKER_5POINT1: return SPEAKERS_5POINT1;
|
||||
case KSAUDIO_SPEAKER_7POINT1: return SPEAKERS_7POINT1;
|
||||
case KSAUDIO_SPEAKER_2POINT1:
|
||||
return SPEAKERS_2POINT1;
|
||||
case KSAUDIO_SPEAKER_SURROUND:
|
||||
return SPEAKERS_4POINT0;
|
||||
case KSAUDIO_SPEAKER_4POINT1:
|
||||
return SPEAKERS_4POINT1;
|
||||
case KSAUDIO_SPEAKER_5POINT1:
|
||||
return SPEAKERS_5POINT1;
|
||||
case KSAUDIO_SPEAKER_7POINT1:
|
||||
return SPEAKERS_7POINT1;
|
||||
}
|
||||
|
||||
return (enum speaker_layout)channels;
|
||||
|
|
@ -242,7 +242,7 @@ static enum speaker_layout convert_speaker_layout(DWORD layout, WORD channels)
|
|||
extern bool devices_match(const char *id1, const char *id2);
|
||||
|
||||
static bool audio_monitor_init(struct audio_monitor *monitor,
|
||||
obs_source_t *source)
|
||||
obs_source_t *source)
|
||||
{
|
||||
IMMDeviceEnumerator *immde = NULL;
|
||||
WAVEFORMATEX *wfex = NULL;
|
||||
|
|
@ -275,14 +275,14 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
|
|||
* Init device */
|
||||
|
||||
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
|
||||
&IID_IMMDeviceEnumerator, (void**)&immde);
|
||||
&IID_IMMDeviceEnumerator, (void **)&immde);
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(id, "default") == 0) {
|
||||
hr = immde->lpVtbl->GetDefaultAudioEndpoint(immde,
|
||||
eRender, eConsole, &monitor->device);
|
||||
hr = immde->lpVtbl->GetDefaultAudioEndpoint(
|
||||
immde, eRender, eConsole, &monitor->device);
|
||||
} else {
|
||||
wchar_t w_id[512];
|
||||
os_utf8_to_wcs(id, 0, w_id, 512);
|
||||
|
|
@ -298,8 +298,8 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
|
|||
* Init client */
|
||||
|
||||
hr = monitor->device->lpVtbl->Activate(monitor->device,
|
||||
&IID_IAudioClient, CLSCTX_ALL, NULL,
|
||||
(void**)&monitor->client);
|
||||
&IID_IAudioClient, CLSCTX_ALL,
|
||||
NULL, (void **)&monitor->client);
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -310,8 +310,8 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
|
|||
}
|
||||
|
||||
hr = monitor->client->lpVtbl->Initialize(monitor->client,
|
||||
AUDCLNT_SHAREMODE_SHARED, 0,
|
||||
10000000, 0, wfex, NULL);
|
||||
AUDCLNT_SHAREMODE_SHARED, 0,
|
||||
10000000, 0, wfex, NULL);
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -319,9 +319,9 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
|
|||
/* ------------------------------------------ *
|
||||
* Init resampler */
|
||||
|
||||
const struct audio_output_info *info = audio_output_get_info(
|
||||
obs->audio.audio);
|
||||
WAVEFORMATEXTENSIBLE *ext = (WAVEFORMATEXTENSIBLE*)wfex;
|
||||
const struct audio_output_info *info =
|
||||
audio_output_get_info(obs->audio.audio);
|
||||
WAVEFORMATEXTENSIBLE *ext = (WAVEFORMATEXTENSIBLE *)wfex;
|
||||
struct resample_info from;
|
||||
struct resample_info to;
|
||||
|
||||
|
|
@ -330,8 +330,8 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
|
|||
from.format = AUDIO_FORMAT_FLOAT_PLANAR;
|
||||
|
||||
to.samples_per_sec = (uint32_t)wfex->nSamplesPerSec;
|
||||
to.speakers = convert_speaker_layout(ext->dwChannelMask,
|
||||
wfex->nChannels);
|
||||
to.speakers =
|
||||
convert_speaker_layout(ext->dwChannelMask, wfex->nChannels);
|
||||
to.format = AUDIO_FORMAT_FLOAT;
|
||||
|
||||
monitor->sample_rate = (uint32_t)wfex->nSamplesPerSec;
|
||||
|
|
@ -350,7 +350,8 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
|
|||
}
|
||||
|
||||
hr = monitor->client->lpVtbl->GetService(monitor->client,
|
||||
&IID_IAudioRenderClient, (void**)&monitor->render);
|
||||
&IID_IAudioRenderClient,
|
||||
(void **)&monitor->render);
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -381,7 +382,7 @@ static void audio_monitor_init_final(struct audio_monitor *monitor)
|
|||
monitor->source_has_video =
|
||||
(monitor->source->info.output_flags & OBS_SOURCE_VIDEO) != 0;
|
||||
obs_source_add_audio_capture_callback(monitor->source,
|
||||
on_audio_playback, monitor);
|
||||
on_audio_playback, monitor);
|
||||
}
|
||||
|
||||
struct audio_monitor *audio_monitor_create(obs_source_t *source)
|
||||
|
|
|
|||
|
|
@ -4,21 +4,21 @@
|
|||
#include <mmdeviceapi.h>
|
||||
#include <audioclient.h>
|
||||
|
||||
|
||||
#ifndef KSAUDIO_SPEAKER_2POINT1
|
||||
#define KSAUDIO_SPEAKER_2POINT1 (KSAUDIO_SPEAKER_STEREO|SPEAKER_LOW_FREQUENCY)
|
||||
#define KSAUDIO_SPEAKER_2POINT1 (KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY)
|
||||
#endif
|
||||
|
||||
#define KSAUDIO_SPEAKER_SURROUND_AVUTIL \
|
||||
(KSAUDIO_SPEAKER_STEREO|SPEAKER_FRONT_CENTER)
|
||||
(KSAUDIO_SPEAKER_STEREO | SPEAKER_FRONT_CENTER)
|
||||
|
||||
#ifndef KSAUDIO_SPEAKER_4POINT1
|
||||
#define KSAUDIO_SPEAKER_4POINT1 (KSAUDIO_SPEAKER_SURROUND|SPEAKER_LOW_FREQUENCY)
|
||||
#define KSAUDIO_SPEAKER_4POINT1 \
|
||||
(KSAUDIO_SPEAKER_SURROUND | SPEAKER_LOW_FREQUENCY)
|
||||
#endif
|
||||
|
||||
#define safe_release(ptr) \
|
||||
do { \
|
||||
if (ptr) { \
|
||||
#define safe_release(ptr) \
|
||||
do { \
|
||||
if (ptr) { \
|
||||
ptr->lpVtbl->Release(ptr); \
|
||||
} \
|
||||
} \
|
||||
} while (false)
|
||||
|
|
|
|||
|
|
@ -65,8 +65,7 @@ static inline const char *cd_serialize_string(uint8_t **pos)
|
|||
return (size != 0) ? str : NULL;
|
||||
}
|
||||
|
||||
static bool cd_getparam(const calldata_t *data, const char *name,
|
||||
uint8_t **pos)
|
||||
static bool cd_getparam(const calldata_t *data, const char *name, uint8_t **pos)
|
||||
{
|
||||
size_t name_size;
|
||||
|
||||
|
|
@ -97,7 +96,7 @@ static bool cd_getparam(const calldata_t *data, const char *name,
|
|||
static inline void cd_copy_string(uint8_t **pos, const char *str, size_t len)
|
||||
{
|
||||
if (!len)
|
||||
len = strlen(str)+1;
|
||||
len = strlen(str) + 1;
|
||||
|
||||
memcpy(*pos, &len, sizeof(size_t));
|
||||
*pos += sizeof(size_t);
|
||||
|
|
@ -117,20 +116,20 @@ static inline void cd_copy_data(uint8_t **pos, const void *in, size_t size)
|
|||
}
|
||||
|
||||
static inline void cd_set_first_param(calldata_t *data, const char *name,
|
||||
const void *in, size_t size)
|
||||
const void *in, size_t size)
|
||||
{
|
||||
uint8_t *pos;
|
||||
size_t capacity;
|
||||
size_t name_len = strlen(name)+1;
|
||||
size_t name_len = strlen(name) + 1;
|
||||
|
||||
capacity = sizeof(size_t)*3 + name_len + size;
|
||||
capacity = sizeof(size_t) * 3 + name_len + size;
|
||||
data->size = capacity;
|
||||
|
||||
if (capacity < 128)
|
||||
capacity = 128;
|
||||
|
||||
data->capacity = capacity;
|
||||
data->stack = bmalloc(capacity);
|
||||
data->stack = bmalloc(capacity);
|
||||
|
||||
pos = data->stack;
|
||||
cd_copy_string(&pos, name, name_len);
|
||||
|
|
@ -139,7 +138,7 @@ static inline void cd_set_first_param(calldata_t *data, const char *name,
|
|||
}
|
||||
|
||||
static inline bool cd_ensure_capacity(calldata_t *data, uint8_t **pos,
|
||||
size_t new_size)
|
||||
size_t new_size)
|
||||
{
|
||||
size_t offset;
|
||||
size_t new_capacity;
|
||||
|
|
@ -157,7 +156,7 @@ static inline bool cd_ensure_capacity(calldata_t *data, uint8_t **pos,
|
|||
if (new_capacity < new_size)
|
||||
new_capacity = new_size;
|
||||
|
||||
data->stack = brealloc(data->stack, new_capacity);
|
||||
data->stack = brealloc(data->stack, new_capacity);
|
||||
data->capacity = new_capacity;
|
||||
|
||||
*pos = data->stack + offset;
|
||||
|
|
@ -167,7 +166,7 @@ static inline bool cd_ensure_capacity(calldata_t *data, uint8_t **pos,
|
|||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
bool calldata_get_data(const calldata_t *data, const char *name, void *out,
|
||||
size_t size)
|
||||
size_t size)
|
||||
{
|
||||
uint8_t *pos;
|
||||
size_t data_size;
|
||||
|
|
@ -187,7 +186,7 @@ bool calldata_get_data(const calldata_t *data, const char *name, void *out,
|
|||
}
|
||||
|
||||
void calldata_set_data(calldata_t *data, const char *name, const void *in,
|
||||
size_t size)
|
||||
size_t size)
|
||||
{
|
||||
uint8_t *pos = NULL;
|
||||
|
||||
|
|
@ -209,22 +208,22 @@ void calldata_set_data(calldata_t *data, const char *name, const void *in,
|
|||
|
||||
if (!cd_ensure_capacity(data, &pos, bytes + offset))
|
||||
return;
|
||||
memmove(pos+offset, pos, bytes - (pos - data->stack));
|
||||
memmove(pos + offset, pos, bytes - (pos - data->stack));
|
||||
data->size += offset;
|
||||
|
||||
} else if (cur_size > size) {
|
||||
size_t offset = cur_size - size;
|
||||
size_t bytes = data->size - offset;
|
||||
|
||||
memmove(pos, pos+offset, bytes - (pos - data->stack));
|
||||
memmove(pos, pos + offset, bytes - (pos - data->stack));
|
||||
data->size -= offset;
|
||||
}
|
||||
|
||||
cd_copy_data(&pos, in, size);
|
||||
|
||||
} else {
|
||||
size_t name_len = strlen(name)+1;
|
||||
size_t offset = name_len + size + sizeof(size_t)*2;
|
||||
size_t name_len = strlen(name) + 1;
|
||||
size_t offset = name_len + size + sizeof(size_t) * 2;
|
||||
if (!cd_ensure_capacity(data, &pos, data->size + offset))
|
||||
return;
|
||||
data->size += offset;
|
||||
|
|
@ -236,7 +235,7 @@ void calldata_set_data(calldata_t *data, const char *name, const void *in,
|
|||
}
|
||||
|
||||
bool calldata_get_string(const calldata_t *data, const char *name,
|
||||
const char **str)
|
||||
const char **str)
|
||||
{
|
||||
uint8_t *pos;
|
||||
if (!data || !name || !*name)
|
||||
|
|
|
|||
|
|
@ -40,14 +40,14 @@ enum call_param_type {
|
|||
CALL_PARAM_TYPE_STRING
|
||||
};
|
||||
|
||||
#define CALL_PARAM_IN (1<<0)
|
||||
#define CALL_PARAM_OUT (1<<1)
|
||||
#define CALL_PARAM_IN (1 << 0)
|
||||
#define CALL_PARAM_OUT (1 << 1)
|
||||
|
||||
struct calldata {
|
||||
uint8_t *stack;
|
||||
size_t size; /* size of the stack, in bytes */
|
||||
size_t capacity; /* capacity of the stack, in bytes */
|
||||
bool fixed; /* fixed size (using call stack) */
|
||||
size_t size; /* size of the stack, in bytes */
|
||||
size_t capacity; /* capacity of the stack, in bytes */
|
||||
bool fixed; /* fixed size (using call stack) */
|
||||
};
|
||||
|
||||
typedef struct calldata calldata_t;
|
||||
|
|
@ -60,7 +60,7 @@ static inline void calldata_init(struct calldata *data)
|
|||
static inline void calldata_clear(struct calldata *data);
|
||||
|
||||
static inline void calldata_init_fixed(struct calldata *data, uint8_t *stack,
|
||||
size_t size)
|
||||
size_t size)
|
||||
{
|
||||
data->stack = stack;
|
||||
data->capacity = size;
|
||||
|
|
@ -76,9 +76,9 @@ static inline void calldata_free(struct calldata *data)
|
|||
}
|
||||
|
||||
EXPORT bool calldata_get_data(const calldata_t *data, const char *name,
|
||||
void *out, size_t size);
|
||||
void *out, size_t size);
|
||||
EXPORT void calldata_set_data(calldata_t *data, const char *name,
|
||||
const void *in, size_t new_size);
|
||||
const void *in, size_t new_size);
|
||||
|
||||
static inline void calldata_clear(struct calldata *data)
|
||||
{
|
||||
|
|
@ -90,7 +90,7 @@ static inline void calldata_clear(struct calldata *data)
|
|||
|
||||
static inline calldata_t *calldata_create(void)
|
||||
{
|
||||
return (calldata_t*)bzalloc(sizeof(struct calldata));
|
||||
return (calldata_t *)bzalloc(sizeof(struct calldata));
|
||||
}
|
||||
|
||||
static inline void calldata_destroy(calldata_t *cd)
|
||||
|
|
@ -104,31 +104,31 @@ static inline void calldata_destroy(calldata_t *cd)
|
|||
* same type. They return false otherwise. */
|
||||
|
||||
static inline bool calldata_get_int(const calldata_t *data, const char *name,
|
||||
long long *val)
|
||||
long long *val)
|
||||
{
|
||||
return calldata_get_data(data, name, val, sizeof(*val));
|
||||
}
|
||||
|
||||
static inline bool calldata_get_float (const calldata_t *data, const char *name,
|
||||
double *val)
|
||||
static inline bool calldata_get_float(const calldata_t *data, const char *name,
|
||||
double *val)
|
||||
{
|
||||
return calldata_get_data(data, name, val, sizeof(*val));
|
||||
}
|
||||
|
||||
static inline bool calldata_get_bool (const calldata_t *data, const char *name,
|
||||
bool *val)
|
||||
static inline bool calldata_get_bool(const calldata_t *data, const char *name,
|
||||
bool *val)
|
||||
{
|
||||
return calldata_get_data(data, name, val, sizeof(*val));
|
||||
}
|
||||
|
||||
static inline bool calldata_get_ptr (const calldata_t *data, const char *name,
|
||||
void *p_ptr)
|
||||
static inline bool calldata_get_ptr(const calldata_t *data, const char *name,
|
||||
void *p_ptr)
|
||||
{
|
||||
return calldata_get_data(data, name, p_ptr, sizeof(p_ptr));
|
||||
}
|
||||
|
||||
EXPORT bool calldata_get_string(const calldata_t *data, const char *name,
|
||||
const char **str);
|
||||
const char **str);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* call if you know your data is valid */
|
||||
|
|
@ -162,7 +162,7 @@ static inline void *calldata_ptr(const calldata_t *data, const char *name)
|
|||
}
|
||||
|
||||
static inline const char *calldata_string(const calldata_t *data,
|
||||
const char *name)
|
||||
const char *name)
|
||||
{
|
||||
const char *val = NULL;
|
||||
calldata_get_string(data, name, &val);
|
||||
|
|
@ -171,35 +171,35 @@ static inline const char *calldata_string(const calldata_t *data,
|
|||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static inline void calldata_set_int (calldata_t *data, const char *name,
|
||||
long long val)
|
||||
static inline void calldata_set_int(calldata_t *data, const char *name,
|
||||
long long val)
|
||||
{
|
||||
calldata_set_data(data, name, &val, sizeof(val));
|
||||
}
|
||||
|
||||
static inline void calldata_set_float (calldata_t *data, const char *name,
|
||||
double val)
|
||||
static inline void calldata_set_float(calldata_t *data, const char *name,
|
||||
double val)
|
||||
{
|
||||
calldata_set_data(data, name, &val, sizeof(val));
|
||||
}
|
||||
|
||||
static inline void calldata_set_bool (calldata_t *data, const char *name,
|
||||
bool val)
|
||||
static inline void calldata_set_bool(calldata_t *data, const char *name,
|
||||
bool val)
|
||||
{
|
||||
calldata_set_data(data, name, &val, sizeof(val));
|
||||
}
|
||||
|
||||
static inline void calldata_set_ptr (calldata_t *data, const char *name,
|
||||
void *ptr)
|
||||
static inline void calldata_set_ptr(calldata_t *data, const char *name,
|
||||
void *ptr)
|
||||
{
|
||||
calldata_set_data(data, name, &ptr, sizeof(ptr));
|
||||
}
|
||||
|
||||
static inline void calldata_set_string(calldata_t *data, const char *name,
|
||||
const char *str)
|
||||
const char *str)
|
||||
{
|
||||
if (str)
|
||||
calldata_set_data(data, name, str, strlen(str)+1);
|
||||
calldata_set_data(data, name, str, strlen(str) + 1);
|
||||
else
|
||||
calldata_set_data(data, name, NULL, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,16 +18,16 @@
|
|||
#include "decl.h"
|
||||
|
||||
static inline void err_specifier_exists(struct cf_parser *cfp,
|
||||
const char *storage)
|
||||
const char *storage)
|
||||
{
|
||||
cf_adderror(cfp, "'$1' specifier already exists", LEX_ERROR,
|
||||
storage, NULL, NULL);
|
||||
cf_adderror(cfp, "'$1' specifier already exists", LEX_ERROR, storage,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
static inline void err_reserved_name(struct cf_parser *cfp, const char *name)
|
||||
{
|
||||
cf_adderror(cfp, "'$1' is a reserved name", LEX_ERROR,
|
||||
name, NULL, NULL);
|
||||
cf_adderror(cfp, "'$1' is a reserved name", LEX_ERROR, name, NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static inline void err_existing_name(struct cf_parser *cfp, const char *name)
|
||||
|
|
@ -36,7 +36,7 @@ static inline void err_existing_name(struct cf_parser *cfp, const char *name)
|
|||
}
|
||||
|
||||
static bool is_in_out_specifier(struct cf_parser *cfp, struct strref *name,
|
||||
uint32_t *type)
|
||||
uint32_t *type)
|
||||
{
|
||||
if (strref_cmp(name, "in") == 0) {
|
||||
if (*type & CALL_PARAM_IN)
|
||||
|
|
@ -60,7 +60,7 @@ static bool is_in_out_specifier(struct cf_parser *cfp, struct strref *name,
|
|||
#define TYPE_OR_STORAGE "type or storage specifier"
|
||||
|
||||
static bool get_type(struct strref *ref, enum call_param_type *type,
|
||||
bool is_return)
|
||||
bool is_return)
|
||||
{
|
||||
if (strref_cmp(ref, "int") == 0)
|
||||
*type = CALL_PARAM_TYPE_INT;
|
||||
|
|
@ -82,12 +82,9 @@ static bool get_type(struct strref *ref, enum call_param_type *type,
|
|||
|
||||
static bool is_reserved_name(const char *str)
|
||||
{
|
||||
return (strcmp(str, "int") == 0) ||
|
||||
(strcmp(str, "float") == 0) ||
|
||||
(strcmp(str, "bool") == 0) ||
|
||||
(strcmp(str, "ptr") == 0) ||
|
||||
(strcmp(str, "string") == 0) ||
|
||||
(strcmp(str, "void") == 0) ||
|
||||
return (strcmp(str, "int") == 0) || (strcmp(str, "float") == 0) ||
|
||||
(strcmp(str, "bool") == 0) || (strcmp(str, "ptr") == 0) ||
|
||||
(strcmp(str, "string") == 0) || (strcmp(str, "void") == 0) ||
|
||||
(strcmp(str, "return") == 0);
|
||||
}
|
||||
|
||||
|
|
@ -105,9 +102,9 @@ static bool name_exists(struct decl_info *decl, const char *name)
|
|||
|
||||
static int parse_param(struct cf_parser *cfp, struct decl_info *decl)
|
||||
{
|
||||
struct strref ref;
|
||||
int code;
|
||||
struct decl_param param = {0};
|
||||
struct strref ref;
|
||||
int code;
|
||||
struct decl_param param = {0};
|
||||
|
||||
/* get storage specifiers */
|
||||
code = cf_next_name_ref(cfp, &ref, TYPE_OR_STORAGE, ",");
|
||||
|
|
@ -180,7 +177,7 @@ static void print_errors(struct cf_parser *cfp, const char *decl_string)
|
|||
|
||||
if (errors) {
|
||||
blog(LOG_WARNING, "Errors/warnings for '%s':\n\n%s",
|
||||
decl_string, errors);
|
||||
decl_string, errors);
|
||||
|
||||
bfree(errors);
|
||||
}
|
||||
|
|
@ -188,11 +185,11 @@ static void print_errors(struct cf_parser *cfp, const char *decl_string)
|
|||
|
||||
bool parse_decl_string(struct decl_info *decl, const char *decl_string)
|
||||
{
|
||||
struct cf_parser cfp;
|
||||
struct strref ret_type;
|
||||
struct decl_param ret_param = {0};
|
||||
int code;
|
||||
bool success;
|
||||
struct cf_parser cfp;
|
||||
struct strref ret_type;
|
||||
struct decl_param ret_param = {0};
|
||||
int code;
|
||||
bool success;
|
||||
|
||||
decl->decl_string = decl_string;
|
||||
ret_param.flags = CALL_PARAM_OUT;
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
struct decl_param {
|
||||
char *name;
|
||||
char *name;
|
||||
enum call_param_type type;
|
||||
uint32_t flags;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
static inline void decl_param_free(struct decl_param *param)
|
||||
|
|
@ -37,8 +37,8 @@ static inline void decl_param_free(struct decl_param *param)
|
|||
}
|
||||
|
||||
struct decl_info {
|
||||
char *name;
|
||||
const char *decl_string;
|
||||
char *name;
|
||||
const char *decl_string;
|
||||
DARRAY(struct decl_param) params;
|
||||
};
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ static inline void decl_info_free(struct decl_info *decl)
|
|||
{
|
||||
if (decl) {
|
||||
for (size_t i = 0; i < decl->params.num; i++)
|
||||
decl_param_free(decl->params.array+i);
|
||||
decl_param_free(decl->params.array + i);
|
||||
da_free(decl->params);
|
||||
|
||||
bfree(decl->name);
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@
|
|||
#include "proc.h"
|
||||
|
||||
struct proc_info {
|
||||
struct decl_info func;
|
||||
void *data;
|
||||
struct decl_info func;
|
||||
void *data;
|
||||
proc_handler_proc_t callback;
|
||||
};
|
||||
|
||||
|
|
@ -46,39 +46,41 @@ void proc_handler_destroy(proc_handler_t *handler)
|
|||
{
|
||||
if (handler) {
|
||||
for (size_t i = 0; i < handler->procs.num; i++)
|
||||
proc_info_free(handler->procs.array+i);
|
||||
proc_info_free(handler->procs.array + i);
|
||||
da_free(handler->procs);
|
||||
bfree(handler);
|
||||
}
|
||||
}
|
||||
|
||||
void proc_handler_add(proc_handler_t *handler, const char *decl_string,
|
||||
proc_handler_proc_t proc, void *data)
|
||||
proc_handler_proc_t proc, void *data)
|
||||
{
|
||||
if (!handler) return;
|
||||
if (!handler)
|
||||
return;
|
||||
|
||||
struct proc_info pi;
|
||||
memset(&pi, 0, sizeof(struct proc_info));
|
||||
|
||||
if (!parse_decl_string(&pi.func, decl_string)) {
|
||||
blog(LOG_ERROR, "Function declaration invalid: %s",
|
||||
decl_string);
|
||||
decl_string);
|
||||
return;
|
||||
}
|
||||
|
||||
pi.callback = proc;
|
||||
pi.data = data;
|
||||
pi.data = data;
|
||||
|
||||
da_push_back(handler->procs, &pi);
|
||||
}
|
||||
|
||||
bool proc_handler_call(proc_handler_t *handler, const char *name,
|
||||
calldata_t *params)
|
||||
calldata_t *params)
|
||||
{
|
||||
if (!handler) return false;
|
||||
if (!handler)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < handler->procs.num; i++) {
|
||||
struct proc_info *info = handler->procs.array+i;
|
||||
struct proc_info *info = handler->procs.array + i;
|
||||
|
||||
if (strcmp(info->func.name, name) == 0) {
|
||||
info->callback(info->data, params);
|
||||
|
|
|
|||
|
|
@ -34,20 +34,20 @@ extern "C" {
|
|||
|
||||
struct proc_handler;
|
||||
typedef struct proc_handler proc_handler_t;
|
||||
typedef void (*proc_handler_proc_t)(void*, calldata_t*);
|
||||
typedef void (*proc_handler_proc_t)(void *, calldata_t *);
|
||||
|
||||
EXPORT proc_handler_t *proc_handler_create(void);
|
||||
EXPORT void proc_handler_destroy(proc_handler_t *handler);
|
||||
|
||||
EXPORT void proc_handler_add(proc_handler_t *handler, const char *decl_string,
|
||||
proc_handler_proc_t proc, void *data);
|
||||
proc_handler_proc_t proc, void *data);
|
||||
|
||||
/**
|
||||
* Calls a function in a procedure handler. Returns false if the named
|
||||
* procedure is not found.
|
||||
*/
|
||||
EXPORT bool proc_handler_call(proc_handler_t *handler, const char *name,
|
||||
calldata_t *params);
|
||||
calldata_t *params);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,18 +22,18 @@
|
|||
|
||||
struct signal_callback {
|
||||
signal_callback_t callback;
|
||||
void *data;
|
||||
bool remove;
|
||||
bool keep_ref;
|
||||
void *data;
|
||||
bool remove;
|
||||
bool keep_ref;
|
||||
};
|
||||
|
||||
struct signal_info {
|
||||
struct decl_info func;
|
||||
struct decl_info func;
|
||||
DARRAY(struct signal_callback) callbacks;
|
||||
pthread_mutex_t mutex;
|
||||
bool signalling;
|
||||
pthread_mutex_t mutex;
|
||||
bool signalling;
|
||||
|
||||
struct signal_info *next;
|
||||
struct signal_info *next;
|
||||
};
|
||||
|
||||
static inline struct signal_info *signal_info_create(struct decl_info *info)
|
||||
|
|
@ -48,8 +48,8 @@ static inline struct signal_info *signal_info_create(struct decl_info *info)
|
|||
|
||||
si = bmalloc(sizeof(struct signal_info));
|
||||
|
||||
si->func = *info;
|
||||
si->next = NULL;
|
||||
si->func = *info;
|
||||
si->next = NULL;
|
||||
si->signalling = false;
|
||||
da_init(si->callbacks);
|
||||
|
||||
|
|
@ -75,10 +75,11 @@ static inline void signal_info_destroy(struct signal_info *si)
|
|||
}
|
||||
|
||||
static inline size_t signal_get_callback_idx(struct signal_info *si,
|
||||
signal_callback_t callback, void *data)
|
||||
signal_callback_t callback,
|
||||
void *data)
|
||||
{
|
||||
for (size_t i = 0; i < si->callbacks.num; i++) {
|
||||
struct signal_callback *sc = si->callbacks.array+i;
|
||||
struct signal_callback *sc = si->callbacks.array + i;
|
||||
|
||||
if (sc->callback == callback && sc->data == data)
|
||||
return i;
|
||||
|
|
@ -89,24 +90,25 @@ static inline size_t signal_get_callback_idx(struct signal_info *si,
|
|||
|
||||
struct global_callback_info {
|
||||
global_signal_callback_t callback;
|
||||
void *data;
|
||||
long signaling;
|
||||
bool remove;
|
||||
void *data;
|
||||
long signaling;
|
||||
bool remove;
|
||||
};
|
||||
|
||||
struct signal_handler {
|
||||
struct signal_info *first;
|
||||
pthread_mutex_t mutex;
|
||||
volatile long refs;
|
||||
pthread_mutex_t mutex;
|
||||
volatile long refs;
|
||||
|
||||
DARRAY(struct global_callback_info) global_callbacks;
|
||||
pthread_mutex_t global_callbacks_mutex;
|
||||
pthread_mutex_t global_callbacks_mutex;
|
||||
};
|
||||
|
||||
static struct signal_info *getsignal(signal_handler_t *handler,
|
||||
const char *name, struct signal_info **p_last)
|
||||
const char *name,
|
||||
struct signal_info **p_last)
|
||||
{
|
||||
struct signal_info *signal, *last= NULL;
|
||||
struct signal_info *signal, *last = NULL;
|
||||
|
||||
signal = handler->first;
|
||||
while (signal != NULL) {
|
||||
|
|
@ -206,8 +208,9 @@ bool signal_handler_add(signal_handler_t *handler, const char *signal_decl)
|
|||
}
|
||||
|
||||
static void signal_handler_connect_internal(signal_handler_t *handler,
|
||||
const char *signal, signal_callback_t callback, void *data,
|
||||
bool keep_ref)
|
||||
const char *signal,
|
||||
signal_callback_t callback,
|
||||
void *data, bool keep_ref)
|
||||
{
|
||||
struct signal_info *sig, *last;
|
||||
struct signal_callback cb_data = {callback, data, false, keep_ref};
|
||||
|
|
@ -221,8 +224,10 @@ static void signal_handler_connect_internal(signal_handler_t *handler,
|
|||
pthread_mutex_unlock(&handler->mutex);
|
||||
|
||||
if (!sig) {
|
||||
blog(LOG_WARNING, "signal_handler_connect: "
|
||||
"signal '%s' not found", signal);
|
||||
blog(LOG_WARNING,
|
||||
"signal_handler_connect: "
|
||||
"signal '%s' not found",
|
||||
signal);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -241,19 +246,19 @@ static void signal_handler_connect_internal(signal_handler_t *handler,
|
|||
}
|
||||
|
||||
void signal_handler_connect(signal_handler_t *handler, const char *signal,
|
||||
signal_callback_t callback, void *data)
|
||||
signal_callback_t callback, void *data)
|
||||
{
|
||||
signal_handler_connect_internal(handler, signal, callback, data, false);
|
||||
}
|
||||
|
||||
void signal_handler_connect_ref(signal_handler_t *handler, const char *signal,
|
||||
signal_callback_t callback, void *data)
|
||||
signal_callback_t callback, void *data)
|
||||
{
|
||||
signal_handler_connect_internal(handler, signal, callback, data, true);
|
||||
}
|
||||
|
||||
static inline struct signal_info *getsignal_locked(signal_handler_t *handler,
|
||||
const char *name)
|
||||
const char *name)
|
||||
{
|
||||
struct signal_info *sig;
|
||||
|
||||
|
|
@ -268,7 +273,7 @@ static inline struct signal_info *getsignal_locked(signal_handler_t *handler,
|
|||
}
|
||||
|
||||
void signal_handler_disconnect(signal_handler_t *handler, const char *signal,
|
||||
signal_callback_t callback, void *data)
|
||||
signal_callback_t callback, void *data)
|
||||
{
|
||||
struct signal_info *sig = getsignal_locked(handler, signal);
|
||||
bool keep_ref = false;
|
||||
|
|
@ -308,7 +313,7 @@ void signal_handler_remove_current(void)
|
|||
}
|
||||
|
||||
void signal_handler_signal(signal_handler_t *handler, const char *signal,
|
||||
calldata_t *params)
|
||||
calldata_t *params)
|
||||
{
|
||||
struct signal_info *sig = getsignal_locked(handler, signal);
|
||||
long remove_refs = 0;
|
||||
|
|
@ -320,7 +325,7 @@ void signal_handler_signal(signal_handler_t *handler, const char *signal,
|
|||
sig->signalling = true;
|
||||
|
||||
for (size_t i = 0; i < sig->callbacks.num; i++) {
|
||||
struct signal_callback *cb = sig->callbacks.array+i;
|
||||
struct signal_callback *cb = sig->callbacks.array + i;
|
||||
if (!cb->remove) {
|
||||
current_signal_cb = cb;
|
||||
cb->callback(cb->data, params);
|
||||
|
|
@ -329,12 +334,12 @@ void signal_handler_signal(signal_handler_t *handler, const char *signal,
|
|||
}
|
||||
|
||||
for (size_t i = sig->callbacks.num; i > 0; i--) {
|
||||
struct signal_callback *cb = sig->callbacks.array+i-1;
|
||||
struct signal_callback *cb = sig->callbacks.array + i - 1;
|
||||
if (cb->remove) {
|
||||
if (cb->keep_ref)
|
||||
remove_refs++;
|
||||
|
||||
da_erase(sig->callbacks, i-1);
|
||||
da_erase(sig->callbacks, i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -363,20 +368,21 @@ void signal_handler_signal(signal_handler_t *handler, const char *signal,
|
|||
|
||||
if (cb->remove && !cb->signaling)
|
||||
da_erase(handler->global_callbacks, i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&handler->global_callbacks_mutex);
|
||||
|
||||
if (remove_refs) {
|
||||
os_atomic_set_long(&handler->refs,
|
||||
os_atomic_load_long(&handler->refs) -
|
||||
remove_refs);
|
||||
os_atomic_load_long(&handler->refs) -
|
||||
remove_refs);
|
||||
}
|
||||
}
|
||||
|
||||
void signal_handler_connect_global(signal_handler_t *handler,
|
||||
global_signal_callback_t callback, void *data)
|
||||
global_signal_callback_t callback,
|
||||
void *data)
|
||||
{
|
||||
struct global_callback_info cb_data = {callback, data, 0, false};
|
||||
size_t idx;
|
||||
|
|
@ -394,7 +400,8 @@ void signal_handler_connect_global(signal_handler_t *handler,
|
|||
}
|
||||
|
||||
void signal_handler_disconnect_global(signal_handler_t *handler,
|
||||
global_signal_callback_t callback, void *data)
|
||||
global_signal_callback_t callback,
|
||||
void *data)
|
||||
{
|
||||
struct global_callback_info cb_data = {callback, data, false};
|
||||
size_t idx;
|
||||
|
|
|
|||
|
|
@ -33,17 +33,17 @@ extern "C" {
|
|||
|
||||
struct signal_handler;
|
||||
typedef struct signal_handler signal_handler_t;
|
||||
typedef void (*global_signal_callback_t)(void*, const char*, calldata_t*);
|
||||
typedef void (*signal_callback_t)(void*, calldata_t*);
|
||||
typedef void (*global_signal_callback_t)(void *, const char *, calldata_t *);
|
||||
typedef void (*signal_callback_t)(void *, calldata_t *);
|
||||
|
||||
EXPORT signal_handler_t *signal_handler_create(void);
|
||||
EXPORT void signal_handler_destroy(signal_handler_t *handler);
|
||||
|
||||
EXPORT bool signal_handler_add(signal_handler_t *handler,
|
||||
const char *signal_decl);
|
||||
const char *signal_decl);
|
||||
|
||||
static inline bool signal_handler_add_array(signal_handler_t *handler,
|
||||
const char **signal_decls)
|
||||
const char **signal_decls)
|
||||
{
|
||||
bool success = true;
|
||||
if (!signal_decls)
|
||||
|
|
@ -57,21 +57,26 @@ static inline bool signal_handler_add_array(signal_handler_t *handler,
|
|||
}
|
||||
|
||||
EXPORT void signal_handler_connect(signal_handler_t *handler,
|
||||
const char *signal, signal_callback_t callback, void *data);
|
||||
const char *signal,
|
||||
signal_callback_t callback, void *data);
|
||||
EXPORT void signal_handler_connect_ref(signal_handler_t *handler,
|
||||
const char *signal, signal_callback_t callback, void *data);
|
||||
const char *signal,
|
||||
signal_callback_t callback, void *data);
|
||||
EXPORT void signal_handler_disconnect(signal_handler_t *handler,
|
||||
const char *signal, signal_callback_t callback, void *data);
|
||||
const char *signal,
|
||||
signal_callback_t callback, void *data);
|
||||
|
||||
EXPORT void signal_handler_connect_global(signal_handler_t *handler,
|
||||
global_signal_callback_t callback, void *data);
|
||||
global_signal_callback_t callback,
|
||||
void *data);
|
||||
EXPORT void signal_handler_disconnect_global(signal_handler_t *handler,
|
||||
global_signal_callback_t callback, void *data);
|
||||
global_signal_callback_t callback,
|
||||
void *data);
|
||||
|
||||
EXPORT void signal_handler_remove_current(void);
|
||||
|
||||
EXPORT void signal_handler_signal(signal_handler_t *handler, const char *signal,
|
||||
calldata_t *params);
|
||||
calldata_t *params);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,29 @@
|
|||
uniform float4x4 ViewProj;
|
||||
uniform float2 base_dimension;
|
||||
uniform float2 base_dimension_i;
|
||||
uniform texture2d image;
|
||||
|
||||
struct VertInOut {
|
||||
sampler_state textureSampler {
|
||||
Filter = Linear;
|
||||
AddressU = Clamp;
|
||||
AddressV = Clamp;
|
||||
};
|
||||
|
||||
struct VertData {
|
||||
float4 pos : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
VertInOut VSDefault(VertInOut vert_in)
|
||||
struct VertInOut {
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 pos : POSITION;
|
||||
};
|
||||
|
||||
struct FragData {
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
VertInOut VSDefault(VertData vert_in)
|
||||
{
|
||||
VertInOut vert_out;
|
||||
vert_out.pos = mul(float4(vert_in.pos.xyz, 1.0), ViewProj);
|
||||
|
|
@ -15,43 +31,97 @@ VertInOut VSDefault(VertInOut vert_in)
|
|||
return vert_out;
|
||||
}
|
||||
|
||||
float4 PSDrawAreaRGBA(VertInOut vert_in) : TARGET
|
||||
float4 DrawArea(float2 uv)
|
||||
{
|
||||
float4 totalcolor = float4(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
float2 uv = vert_in.uv;
|
||||
float2 uvdelta = float2(ddx(uv.x), ddy(uv.y));
|
||||
float2 uv_delta = float2(ddx(uv.x), ddy(uv.y));
|
||||
|
||||
// Handle potential OpenGL flip.
|
||||
uvdelta.y = abs(uvdelta.y);
|
||||
if (obs_glsl_compile)
|
||||
uv_delta.y = abs(uv_delta.y);
|
||||
|
||||
float2 uvhalfdelta = 0.5 * uvdelta;
|
||||
float2 uvmin = uv - uvhalfdelta;
|
||||
float2 uvmax = uv + uvhalfdelta;
|
||||
float2 uv_min = uv - 0.5 * uv_delta;
|
||||
float2 uv_max = uv_min + uv_delta;
|
||||
|
||||
int2 loadindexmin = int2(uvmin / base_dimension_i);
|
||||
int2 loadindexmax = int2(uvmax / base_dimension_i);
|
||||
float2 load_index_begin = floor(uv_min * base_dimension);
|
||||
float2 load_index_end = ceil(uv_max * base_dimension);
|
||||
|
||||
float2 targetpos = uv / uvdelta;
|
||||
float2 targetposmin = targetpos - 0.5;
|
||||
float2 targetposmax = targetpos + 0.5;
|
||||
float2 scale = base_dimension_i / uvdelta;
|
||||
for (int loadindexy = loadindexmin.y; loadindexy <= loadindexmax.y; ++loadindexy)
|
||||
{
|
||||
for (int loadindexx = loadindexmin.x; loadindexx <= loadindexmax.x; ++loadindexx)
|
||||
{
|
||||
int2 loadindex = int2(loadindexx, loadindexy);
|
||||
float2 potentialtargetmin = float2(loadindex) * scale;
|
||||
float2 potentialtargetmax = potentialtargetmin + scale;
|
||||
float2 targetmin = max(potentialtargetmin, targetposmin);
|
||||
float2 targetmax = min(potentialtargetmax, targetposmax);
|
||||
float area = (targetmax.x - targetmin.x) * (targetmax.y - targetmin.y);
|
||||
float4 sample = image.Load(int3(loadindex, 0));
|
||||
totalcolor += area * sample;
|
||||
}
|
||||
}
|
||||
float2 target_dimension = 1.0 / uv_delta;
|
||||
float2 target_pos = uv * target_dimension;
|
||||
float2 target_pos_min = target_pos - 0.5;
|
||||
float2 target_pos_max = target_pos + 0.5;
|
||||
float2 scale = base_dimension_i * target_dimension;
|
||||
|
||||
return totalcolor;
|
||||
float4 total_color = float4(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
float load_index_y = load_index_begin.y;
|
||||
do {
|
||||
float source_y_min = load_index_y * scale.y;
|
||||
float source_y_max = source_y_min + scale.y;
|
||||
float y_min = max(source_y_min, target_pos_min.y);
|
||||
float y_max = min(source_y_max, target_pos_max.y);
|
||||
float height = y_max - y_min;
|
||||
|
||||
float load_index_x = load_index_begin.x;
|
||||
do {
|
||||
float source_x_min = load_index_x * scale.x;
|
||||
float source_x_max = source_x_min + scale.x;
|
||||
float x_min = max(source_x_min, target_pos_min.x);
|
||||
float x_max = min(source_x_max, target_pos_max.x);
|
||||
float width = x_max - x_min;
|
||||
float area = width * height;
|
||||
|
||||
float4 color = image.Load(int3(load_index_x, load_index_y, 0));
|
||||
total_color += area * color;
|
||||
|
||||
++load_index_x;
|
||||
} while (load_index_x < load_index_end.x);
|
||||
|
||||
++load_index_y;
|
||||
} while (load_index_y < load_index_end.y);
|
||||
|
||||
return total_color;
|
||||
}
|
||||
|
||||
float4 PSDrawAreaRGBA(FragData frag_in) : TARGET
|
||||
{
|
||||
return DrawArea(frag_in.uv);
|
||||
}
|
||||
|
||||
float4 PSDrawAreaRGBADivide(FragData frag_in) : TARGET
|
||||
{
|
||||
float4 rgba = DrawArea(frag_in.uv);
|
||||
float alpha = rgba.a;
|
||||
float multiplier = (alpha > 0.0) ? (1.0 / alpha) : 0.0;
|
||||
return float4(rgba.rgb * multiplier, alpha);
|
||||
}
|
||||
|
||||
float4 PSDrawAreaRGBAUpscale(FragData frag_in) : TARGET
|
||||
{
|
||||
float2 uv = frag_in.uv;
|
||||
float2 uv_delta = float2(ddx(uv.x), ddy(uv.y));
|
||||
|
||||
// Handle potential OpenGL flip.
|
||||
if (obs_glsl_compile)
|
||||
uv_delta.y = abs(uv_delta.y);
|
||||
|
||||
float2 uv_min = uv - 0.5 * uv_delta;
|
||||
float2 uv_max = uv_min + uv_delta;
|
||||
|
||||
float2 load_index_first = floor(uv_min * base_dimension);
|
||||
float2 load_index_last = ceil(uv_max * base_dimension) - 1.0;
|
||||
|
||||
if (load_index_first.x < load_index_last.x) {
|
||||
float uv_boundary_x = load_index_last.x * base_dimension_i.x;
|
||||
uv.x = ((uv.x - uv_boundary_x) / uv_delta.x) * base_dimension_i.x + uv_boundary_x;
|
||||
} else
|
||||
uv.x = (load_index_first.x + 0.5) * base_dimension_i.x;
|
||||
if (load_index_first.y < load_index_last.y) {
|
||||
float uv_boundary_y = load_index_last.y * base_dimension_i.y;
|
||||
uv.y = ((uv.y - uv_boundary_y) / uv_delta.y) * base_dimension_i.y + uv_boundary_y;
|
||||
} else
|
||||
uv.y = (load_index_first.y + 0.5) * base_dimension_i.y;
|
||||
|
||||
return image.Sample(textureSampler, uv);
|
||||
}
|
||||
|
||||
technique Draw
|
||||
|
|
@ -59,6 +129,24 @@ technique Draw
|
|||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSDrawAreaRGBA(vert_in);
|
||||
pixel_shader = PSDrawAreaRGBA(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique DrawAlphaDivide
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSDrawAreaRGBADivide(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique DrawUpscale
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSDrawAreaRGBAUpscale(frag_in);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
uniform float4x4 ViewProj;
|
||||
uniform texture2d image;
|
||||
uniform float4x4 color_matrix;
|
||||
uniform float2 base_dimension;
|
||||
uniform float2 base_dimension_i;
|
||||
uniform float undistort_factor = 1.0;
|
||||
|
||||
|
|
@ -21,45 +21,31 @@ struct VertData {
|
|||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
VertData VSDefault(VertData v_in)
|
||||
struct VertOut {
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 pos : POSITION;
|
||||
};
|
||||
|
||||
struct FragData {
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
VertOut VSDefault(VertData v_in)
|
||||
{
|
||||
VertData vert_out;
|
||||
VertOut vert_out;
|
||||
vert_out.uv = v_in.uv * base_dimension;
|
||||
vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj);
|
||||
vert_out.uv = v_in.uv;
|
||||
return vert_out;
|
||||
}
|
||||
|
||||
float weight(float x)
|
||||
{
|
||||
float ax = abs(x);
|
||||
|
||||
/* Sharper version. May look better in some cases. */
|
||||
const float B = 0.0;
|
||||
const float C = 0.75;
|
||||
|
||||
if (ax < 1.0)
|
||||
return (pow(x, 2.0) *
|
||||
((12.0 - 9.0 * B - 6.0 * C) * ax +
|
||||
(-18.0 + 12.0 * B + 6.0 * C)) +
|
||||
(6.0 - 2.0 * B))
|
||||
/ 6.0;
|
||||
else if ((ax >= 1.0) && (ax < 2.0))
|
||||
return (pow(x, 2.0) *
|
||||
((-B - 6.0 * C) * ax + (6.0 * B + 30.0 * C)) +
|
||||
(-12.0 * B - 48.0 * C) * ax +
|
||||
(8.0 * B + 24.0 * C))
|
||||
/ 6.0;
|
||||
else
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
float4 weight4(float x)
|
||||
{
|
||||
/* Sharper version. May look better in some cases. B=0, C=0.75 */
|
||||
return float4(
|
||||
weight(x - 2.0),
|
||||
weight(x - 1.0),
|
||||
weight(x),
|
||||
weight(x + 1.0));
|
||||
((-0.75 * x + 1.5) * x - 0.75) * x,
|
||||
(1.25 * x - 2.25) * x * x + 1.0,
|
||||
((-1.25 * x + 1.5) * x + 0.75) * x,
|
||||
(0.75 * x - 0.75) * x * x);
|
||||
}
|
||||
|
||||
float AspectUndistortX(float x, float a)
|
||||
|
|
@ -74,83 +60,94 @@ float AspectUndistortU(float u)
|
|||
return AspectUndistortX((u - 0.5) * 2.0, undistort_factor) * 0.5 + 0.5;
|
||||
}
|
||||
|
||||
float2 pixel_coord(float xpos, float ypos)
|
||||
float2 undistort_coord(float xpos, float ypos)
|
||||
{
|
||||
return float2(AspectUndistortU(xpos), ypos);
|
||||
}
|
||||
|
||||
float4 pixel(float xpos, float ypos, bool undistort)
|
||||
float4 undistort_pixel(float xpos, float ypos)
|
||||
{
|
||||
if (undistort)
|
||||
return image.Sample(textureSampler, pixel_coord(xpos, ypos));
|
||||
else
|
||||
return image.Sample(textureSampler, float2(xpos, ypos));
|
||||
return image.Sample(textureSampler, undistort_coord(xpos, ypos));
|
||||
}
|
||||
|
||||
float4 get_line(float ypos, float4 xpos, float4 linetaps, bool undistort)
|
||||
float4 undistort_line(float4 xpos, float ypos, float4 rowtaps)
|
||||
{
|
||||
return
|
||||
pixel(xpos.r, ypos, undistort) * linetaps.r +
|
||||
pixel(xpos.g, ypos, undistort) * linetaps.g +
|
||||
pixel(xpos.b, ypos, undistort) * linetaps.b +
|
||||
pixel(xpos.a, ypos, undistort) * linetaps.a;
|
||||
return undistort_pixel(xpos.x, ypos) * rowtaps.x +
|
||||
undistort_pixel(xpos.y, ypos) * rowtaps.y +
|
||||
undistort_pixel(xpos.z, ypos) * rowtaps.z +
|
||||
undistort_pixel(xpos.w, ypos) * rowtaps.w;
|
||||
}
|
||||
|
||||
float4 DrawBicubic(VertData v_in, bool undistort)
|
||||
float4 DrawBicubic(FragData f_in, bool undistort)
|
||||
{
|
||||
float2 stepxy = base_dimension_i;
|
||||
float2 pos = v_in.uv + stepxy * 0.5;
|
||||
float2 f = frac(pos / stepxy);
|
||||
float2 pos = f_in.uv;
|
||||
float2 pos1 = floor(pos - 0.5) + 0.5;
|
||||
float2 f = pos - pos1;
|
||||
|
||||
float4 rowtaps = weight4(1.0 - f.x);
|
||||
float4 coltaps = weight4(1.0 - f.y);
|
||||
float4 rowtaps = weight4(f.x);
|
||||
float4 coltaps = weight4(f.y);
|
||||
|
||||
/* make sure all taps added together is exactly 1.0, otherwise some
|
||||
* (very small) distortion can occur */
|
||||
rowtaps /= rowtaps.r + rowtaps.g + rowtaps.b + rowtaps.a;
|
||||
coltaps /= coltaps.r + coltaps.g + coltaps.b + coltaps.a;
|
||||
float2 uv1 = pos1 * base_dimension_i;
|
||||
float2 uv0 = uv1 - base_dimension_i;
|
||||
float2 uv2 = uv1 + base_dimension_i;
|
||||
float2 uv3 = uv2 + base_dimension_i;
|
||||
|
||||
float2 xystart = (-1.5 - f) * stepxy + pos;
|
||||
float4 xpos = float4(
|
||||
xystart.x,
|
||||
xystart.x + stepxy.x,
|
||||
xystart.x + stepxy.x * 2.0,
|
||||
xystart.x + stepxy.x * 3.0
|
||||
);
|
||||
if (undistort) {
|
||||
float4 xpos = float4(uv0.x, uv1.x, uv2.x, uv3.x);
|
||||
return undistort_line(xpos, uv0.y, rowtaps) * coltaps.x +
|
||||
undistort_line(xpos, uv1.y, rowtaps) * coltaps.y +
|
||||
undistort_line(xpos, uv2.y, rowtaps) * coltaps.z +
|
||||
undistort_line(xpos, uv3.y, rowtaps) * coltaps.w;
|
||||
}
|
||||
|
||||
return
|
||||
get_line(xystart.y , xpos, rowtaps, undistort) * coltaps.r +
|
||||
get_line(xystart.y + stepxy.y , xpos, rowtaps, undistort) * coltaps.g +
|
||||
get_line(xystart.y + stepxy.y * 2.0, xpos, rowtaps, undistort) * coltaps.b +
|
||||
get_line(xystart.y + stepxy.y * 3.0, xpos, rowtaps, undistort) * coltaps.a;
|
||||
float u_weight_sum = rowtaps.y + rowtaps.z;
|
||||
float u_middle_offset = rowtaps.z * base_dimension_i.x / u_weight_sum;
|
||||
float u_middle = uv1.x + u_middle_offset;
|
||||
|
||||
float v_weight_sum = coltaps.y + coltaps.z;
|
||||
float v_middle_offset = coltaps.z * base_dimension_i.y / v_weight_sum;
|
||||
float v_middle = uv1.y + v_middle_offset;
|
||||
|
||||
int2 coord_top_left = int2(max(uv0 * base_dimension, 0.5));
|
||||
int2 coord_bottom_right = int2(min(uv3 * base_dimension, base_dimension - 0.5));
|
||||
|
||||
float4 top = image.Load(int3(coord_top_left, 0)) * rowtaps.x;
|
||||
top += image.Sample(textureSampler, float2(u_middle, uv0.y)) * u_weight_sum;
|
||||
top += image.Load(int3(coord_bottom_right.x, coord_top_left.y, 0)) * rowtaps.w;
|
||||
float4 total = top * coltaps.x;
|
||||
|
||||
float4 middle = image.Sample(textureSampler, float2(uv0.x, v_middle)) * rowtaps.x;
|
||||
middle += image.Sample(textureSampler, float2(u_middle, v_middle)) * u_weight_sum;
|
||||
middle += image.Sample(textureSampler, float2(uv3.x, v_middle)) * rowtaps.w;
|
||||
total += middle * v_weight_sum;
|
||||
|
||||
float4 bottom = image.Load(int3(coord_top_left.x, coord_bottom_right.y, 0)) * rowtaps.x;
|
||||
bottom += image.Sample(textureSampler, float2(u_middle, uv3.y)) * u_weight_sum;
|
||||
bottom += image.Load(int3(coord_bottom_right, 0)) * rowtaps.w;
|
||||
total += bottom * coltaps.w;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
float4 PSDrawBicubicRGBA(VertData v_in, bool undistort) : TARGET
|
||||
float4 PSDrawBicubicRGBA(FragData f_in, bool undistort) : TARGET
|
||||
{
|
||||
return DrawBicubic(v_in, undistort);
|
||||
return DrawBicubic(f_in, undistort);
|
||||
}
|
||||
|
||||
float4 PSDrawBicubicRGBADivide(VertData v_in) : TARGET
|
||||
float4 PSDrawBicubicRGBADivide(FragData f_in) : TARGET
|
||||
{
|
||||
float4 rgba = DrawBicubic(v_in, false);
|
||||
float4 rgba = DrawBicubic(f_in, false);
|
||||
float alpha = rgba.a;
|
||||
float multiplier = (alpha > 0.0) ? (1.0 / alpha) : 0.0;
|
||||
return float4(rgba.rgb * multiplier, alpha);
|
||||
}
|
||||
|
||||
float4 PSDrawBicubicMatrix(VertData v_in) : TARGET
|
||||
{
|
||||
float3 rgb = DrawBicubic(v_in, false).rgb;
|
||||
float3 yuv = mul(float4(saturate(rgb), 1.0), color_matrix).xyz;
|
||||
return float4(yuv, 1.0);
|
||||
}
|
||||
|
||||
technique Draw
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(v_in);
|
||||
pixel_shader = PSDrawBicubicRGBA(v_in, false);
|
||||
pixel_shader = PSDrawBicubicRGBA(f_in, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -159,7 +156,7 @@ technique DrawAlphaDivide
|
|||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(v_in);
|
||||
pixel_shader = PSDrawBicubicRGBADivide(v_in);
|
||||
pixel_shader = PSDrawBicubicRGBADivide(f_in);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -168,15 +165,6 @@ technique DrawUndistort
|
|||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(v_in);
|
||||
pixel_shader = PSDrawBicubicRGBA(v_in, true);
|
||||
}
|
||||
}
|
||||
|
||||
technique DrawMatrix
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(v_in);
|
||||
pixel_shader = PSDrawBicubicMatrix(v_in);
|
||||
pixel_shader = PSDrawBicubicRGBA(f_in, true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
/*
|
||||
* bilinear low res scaling, samples 9 pixels of a larger image to scale to a
|
||||
* bilinear low res scaling, samples 8 pixels of a larger image to scale to a
|
||||
* low resolution image below half size
|
||||
*/
|
||||
|
||||
uniform float4x4 ViewProj;
|
||||
uniform texture2d image;
|
||||
uniform float4x4 color_matrix;
|
||||
uniform float2 base_dimension_i;
|
||||
|
||||
sampler_state textureSampler {
|
||||
Filter = Linear;
|
||||
|
|
@ -34,19 +32,24 @@ float4 pixel(float2 uv)
|
|||
|
||||
float4 DrawLowresBilinear(VertData v_in)
|
||||
{
|
||||
float2 stepxy = base_dimension_i;
|
||||
float4 out_color;
|
||||
float2 uv = v_in.uv;
|
||||
float2 stepxy = float2(ddx(uv.x), ddy(uv.y));
|
||||
float2 stepxy1 = stepxy * 0.0625;
|
||||
float2 stepxy3 = stepxy * 0.1875;
|
||||
float2 stepxy5 = stepxy * 0.3125;
|
||||
float2 stepxy7 = stepxy * 0.4375;
|
||||
|
||||
out_color = pixel(v_in.uv);
|
||||
out_color += pixel(v_in.uv + float2(-stepxy.x, -stepxy.y));
|
||||
out_color += pixel(v_in.uv + float2(-stepxy.x, 0.0));
|
||||
out_color += pixel(v_in.uv + float2(-stepxy.x, stepxy.y));
|
||||
out_color += pixel(v_in.uv + float2( 0.0, -stepxy.y));
|
||||
out_color += pixel(v_in.uv + float2( 0.0, stepxy.y));
|
||||
out_color += pixel(v_in.uv + float2( stepxy.x, -stepxy.y));
|
||||
out_color += pixel(v_in.uv + float2( stepxy.x, 0.0));
|
||||
out_color += pixel(v_in.uv + float2( stepxy.x, stepxy.y));
|
||||
return out_color / float4(9.0, 9.0, 9.0, 9.0);
|
||||
// Simulate Direct3D 8-sample pattern
|
||||
float4 out_color;
|
||||
out_color = pixel(uv + float2( stepxy1.x, -stepxy3.y));
|
||||
out_color += pixel(uv + float2(-stepxy1.x, stepxy3.y));
|
||||
out_color += pixel(uv + float2( stepxy5.x, stepxy1.y));
|
||||
out_color += pixel(uv + float2(-stepxy3.x, -stepxy5.y));
|
||||
out_color += pixel(uv + float2(-stepxy5.x, stepxy5.y));
|
||||
out_color += pixel(uv + float2(-stepxy7.x, -stepxy1.y));
|
||||
out_color += pixel(uv + float2( stepxy3.x, stepxy7.y));
|
||||
out_color += pixel(uv + float2( stepxy7.x, -stepxy7.y));
|
||||
return out_color * 0.125;
|
||||
}
|
||||
|
||||
float4 PSDrawLowresBilinearRGBA(VertData v_in) : TARGET
|
||||
|
|
@ -62,13 +65,6 @@ float4 PSDrawLowresBilinearRGBADivide(VertData v_in) : TARGET
|
|||
return float4(rgba.rgb * multiplier, alpha);
|
||||
}
|
||||
|
||||
float4 PSDrawLowresBilinearMatrix(VertData v_in) : TARGET
|
||||
{
|
||||
float3 rgb = DrawLowresBilinear(v_in).rgb;
|
||||
float3 yuv = mul(float4(saturate(rgb), 1.0), color_matrix).xyz;
|
||||
return float4(yuv, 1.0);
|
||||
}
|
||||
|
||||
technique Draw
|
||||
{
|
||||
pass
|
||||
|
|
@ -87,12 +83,3 @@ technique DrawAlphaDivide
|
|||
}
|
||||
}
|
||||
|
||||
technique DrawMatrix
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(v_in);
|
||||
pixel_shader = PSDrawLowresBilinearMatrix(v_in);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
uniform float4x4 ViewProj;
|
||||
uniform float4x4 color_matrix;
|
||||
uniform texture2d image;
|
||||
|
||||
sampler_state def_sampler {
|
||||
|
|
@ -34,13 +33,6 @@ float4 PSDrawAlphaDivide(VertInOut vert_in) : TARGET
|
|||
return float4(rgba.rgb * multiplier, alpha);
|
||||
}
|
||||
|
||||
float4 PSDrawMatrix(VertInOut vert_in) : TARGET
|
||||
{
|
||||
float3 rgb = image.Sample(def_sampler, vert_in.uv).rgb;
|
||||
float3 yuv = mul(float4(rgb, 1.0), color_matrix).xyz;
|
||||
return float4(yuv, 1.0);
|
||||
}
|
||||
|
||||
technique Draw
|
||||
{
|
||||
pass
|
||||
|
|
@ -58,12 +50,3 @@ technique DrawAlphaDivide
|
|||
pixel_shader = PSDrawAlphaDivide(vert_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique DrawMatrix
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSDrawMatrix(vert_in);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,38 +15,23 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
//#define DEBUGGING
|
||||
|
||||
uniform float4x4 ViewProj;
|
||||
|
||||
uniform float u_plane_offset;
|
||||
uniform float v_plane_offset;
|
||||
|
||||
uniform float width;
|
||||
uniform float height;
|
||||
uniform float width_i;
|
||||
uniform float height_i;
|
||||
uniform float width_d2;
|
||||
uniform float height_d2;
|
||||
uniform float width_d2_i;
|
||||
uniform float height_d2_i;
|
||||
uniform float input_width;
|
||||
uniform float input_height;
|
||||
uniform float input_width_i;
|
||||
uniform float input_height_i;
|
||||
uniform float input_width_i_d2;
|
||||
uniform float input_height_i_d2;
|
||||
uniform float width_x2_i;
|
||||
|
||||
uniform int int_width;
|
||||
uniform int int_input_width;
|
||||
uniform int int_u_plane_offset;
|
||||
uniform int int_v_plane_offset;
|
||||
|
||||
uniform float4x4 color_matrix;
|
||||
uniform float4 color_vec0;
|
||||
uniform float4 color_vec1;
|
||||
uniform float4 color_vec2;
|
||||
uniform float3 color_range_min = {0.0, 0.0, 0.0};
|
||||
uniform float3 color_range_max = {1.0, 1.0, 1.0};
|
||||
|
||||
uniform texture2d image;
|
||||
uniform texture2d image1;
|
||||
uniform texture2d image2;
|
||||
uniform texture2d image3;
|
||||
|
||||
sampler_state def_sampler {
|
||||
Filter = Linear;
|
||||
|
|
@ -54,354 +39,385 @@ sampler_state def_sampler {
|
|||
AddressV = Clamp;
|
||||
};
|
||||
|
||||
struct VertInOut {
|
||||
struct FragPos {
|
||||
float4 pos : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
VertInOut VSDefault(VertInOut vert_in)
|
||||
struct VertTexPos {
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 pos : POSITION;
|
||||
};
|
||||
|
||||
struct VertPosWide {
|
||||
float3 pos_wide : TEXCOORD0;
|
||||
float4 pos : POSITION;
|
||||
};
|
||||
|
||||
struct VertTexPosWide {
|
||||
float3 uuv : TEXCOORD0;
|
||||
float4 pos : POSITION;
|
||||
};
|
||||
|
||||
struct FragTex {
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct FragPosWide {
|
||||
float3 pos_wide : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct FragTexWide {
|
||||
float3 uuv : TEXCOORD0;
|
||||
};
|
||||
|
||||
FragPos VSPos(uint id : VERTEXID)
|
||||
{
|
||||
VertInOut vert_out;
|
||||
vert_out.pos = mul(float4(vert_in.pos.xyz, 1.0), ViewProj);
|
||||
vert_out.uv = vert_in.uv;
|
||||
float idHigh = float(id >> 1);
|
||||
float idLow = float(id & uint(1));
|
||||
|
||||
float x = idHigh * 4.0 - 1.0;
|
||||
float y = idLow * 4.0 - 1.0;
|
||||
|
||||
FragPos vert_out;
|
||||
vert_out.pos = float4(x, y, 0.0, 1.0);
|
||||
return vert_out;
|
||||
}
|
||||
|
||||
/* used to prevent internal GPU precision issues width fmod in particular */
|
||||
#define PRECISION_OFFSET 0.2
|
||||
|
||||
float4 PSNV12(VertInOut vert_in) : TARGET
|
||||
VertTexPosWide VSTexPos_Left(uint id : VERTEXID)
|
||||
{
|
||||
float v_mul = floor(vert_in.uv.y * input_height);
|
||||
float idHigh = float(id >> 1);
|
||||
float idLow = float(id & uint(1));
|
||||
|
||||
float byte_offset = floor((v_mul + vert_in.uv.x) * width) * 4.0;
|
||||
byte_offset += PRECISION_OFFSET;
|
||||
float x = idHigh * 4.0 - 1.0;
|
||||
float y = idLow * 4.0 - 1.0;
|
||||
|
||||
float2 sample_pos[4];
|
||||
float u_right = idHigh * 2.0;
|
||||
float u_left = u_right - width_i;
|
||||
float v = obs_glsl_compile ? (idLow * 2.0) : (1.0 - idLow * 2.0);
|
||||
|
||||
if (byte_offset < u_plane_offset) {
|
||||
#ifdef DEBUGGING
|
||||
return float4(1.0, 1.0, 1.0, 1.0);
|
||||
#endif
|
||||
|
||||
float lum_u = floor(fmod(byte_offset, width)) * width_i;
|
||||
float lum_v = floor(byte_offset * width_i) * height_i;
|
||||
|
||||
/* move to texel centers to sample the 4 pixels properly */
|
||||
lum_u += width_i * 0.5;
|
||||
lum_v += height_i * 0.5;
|
||||
|
||||
sample_pos[0] = float2(lum_u, lum_v);
|
||||
sample_pos[1] = float2(lum_u += width_i, lum_v);
|
||||
sample_pos[2] = float2(lum_u += width_i, lum_v);
|
||||
sample_pos[3] = float2(lum_u + width_i, lum_v);
|
||||
|
||||
float4x4 out_val = float4x4(
|
||||
image.Sample(def_sampler, sample_pos[0]),
|
||||
image.Sample(def_sampler, sample_pos[1]),
|
||||
image.Sample(def_sampler, sample_pos[2]),
|
||||
image.Sample(def_sampler, sample_pos[3])
|
||||
);
|
||||
|
||||
return transpose(out_val)[1];
|
||||
} else {
|
||||
#ifdef DEBUGGING
|
||||
return float4(0.5, 0.2, 0.5, 0.2);
|
||||
#endif
|
||||
|
||||
float new_offset = byte_offset - u_plane_offset;
|
||||
|
||||
float ch_u = floor(fmod(new_offset, width)) * width_i;
|
||||
float ch_v = floor(new_offset * width_i) * height_d2_i;
|
||||
float width_i2 = width_i*2.0;
|
||||
|
||||
/* move to the borders of each set of 4 pixels to force it
|
||||
* to do bilinear averaging */
|
||||
ch_u += width_i;
|
||||
ch_v += height_i;
|
||||
|
||||
sample_pos[0] = float2(ch_u, ch_v);
|
||||
sample_pos[1] = float2(ch_u + width_i2, ch_v);
|
||||
|
||||
return float4(
|
||||
image.Sample(def_sampler, sample_pos[0]).rb,
|
||||
image.Sample(def_sampler, sample_pos[1]).rb
|
||||
);
|
||||
}
|
||||
VertTexPosWide vert_out;
|
||||
vert_out.uuv = float3(u_left, u_right, v);
|
||||
vert_out.pos = float4(x, y, 0.0, 1.0);
|
||||
return vert_out;
|
||||
}
|
||||
|
||||
float PSNV12_Y(VertInOut vert_in) : TARGET
|
||||
VertTexPos VSTexPosHalf_Reverse(uint id : VERTEXID)
|
||||
{
|
||||
return image.Sample(def_sampler, vert_in.uv.xy).y;
|
||||
float idHigh = float(id >> 1);
|
||||
float idLow = float(id & uint(1));
|
||||
|
||||
float x = idHigh * 4.0 - 1.0;
|
||||
float y = idLow * 4.0 - 1.0;
|
||||
|
||||
float u = idHigh * 2.0;
|
||||
float v = obs_glsl_compile ? (idLow * 2.0) : (1.0 - idLow * 2.0);
|
||||
|
||||
VertTexPos vert_out;
|
||||
vert_out.uv = float2(width_d2 * u, height * v);
|
||||
vert_out.pos = float4(x, y, 0.0, 1.0);
|
||||
return vert_out;
|
||||
}
|
||||
|
||||
float2 PSNV12_UV(VertInOut vert_in) : TARGET
|
||||
VertTexPos VSTexPosHalfHalf_Reverse(uint id : VERTEXID)
|
||||
{
|
||||
return image.Sample(def_sampler, vert_in.uv.xy).xz;
|
||||
float idHigh = float(id >> 1);
|
||||
float idLow = float(id & uint(1));
|
||||
|
||||
float x = idHigh * 4.0 - 1.0;
|
||||
float y = idLow * 4.0 - 1.0;
|
||||
|
||||
float u = idHigh * 2.0;
|
||||
float v = obs_glsl_compile ? (idLow * 2.0) : (1.0 - idLow * 2.0);
|
||||
|
||||
VertTexPos vert_out;
|
||||
vert_out.uv = float2(width_d2 * u, height_d2 * v);
|
||||
vert_out.pos = float4(x, y, 0.0, 1.0);
|
||||
return vert_out;
|
||||
}
|
||||
|
||||
float4 PSPlanar420(VertInOut vert_in) : TARGET
|
||||
VertPosWide VSPosWide_Reverse(uint id : VERTEXID)
|
||||
{
|
||||
float v_mul = floor(vert_in.uv.y * input_height);
|
||||
float idHigh = float(id >> 1);
|
||||
float idLow = float(id & uint(1));
|
||||
|
||||
float byte_offset = floor((v_mul + vert_in.uv.x) * width) * 4.0;
|
||||
byte_offset += PRECISION_OFFSET;
|
||||
float x = idHigh * 4.0 - 1.0;
|
||||
float y = idLow * 4.0 - 1.0;
|
||||
|
||||
float2 sample_pos[4];
|
||||
float u = idHigh * 2.0;
|
||||
float v = obs_glsl_compile ? (idLow * 2.0) : (1.0 - idLow * 2.0);
|
||||
|
||||
if (byte_offset < u_plane_offset) {
|
||||
#ifdef DEBUGGING
|
||||
return float4(1.0, 1.0, 1.0, 1.0);
|
||||
#endif
|
||||
|
||||
float lum_u = floor(fmod(byte_offset, width)) * width_i;
|
||||
float lum_v = floor(byte_offset * width_i) * height_i;
|
||||
|
||||
/* move to texel centers to sample the 4 pixels properly */
|
||||
lum_u += width_i * 0.5;
|
||||
lum_v += height_i * 0.5;
|
||||
|
||||
sample_pos[0] = float2(lum_u, lum_v);
|
||||
sample_pos[1] = float2(lum_u += width_i, lum_v);
|
||||
sample_pos[2] = float2(lum_u += width_i, lum_v);
|
||||
sample_pos[3] = float2(lum_u + width_i, lum_v);
|
||||
|
||||
} else {
|
||||
#ifdef DEBUGGING
|
||||
return ((byte_offset < v_plane_offset) ?
|
||||
float4(0.5, 0.5, 0.5, 0.5) :
|
||||
float4(0.2, 0.2, 0.2, 0.2));
|
||||
#endif
|
||||
|
||||
float new_offset = byte_offset -
|
||||
((byte_offset < v_plane_offset) ?
|
||||
u_plane_offset : v_plane_offset);
|
||||
|
||||
float ch_u = floor(fmod(new_offset, width_d2)) * width_d2_i;
|
||||
float ch_v = floor(new_offset * width_d2_i) * height_d2_i;
|
||||
float width_i2 = width_i*2.0;
|
||||
|
||||
/* move to the borders of each set of 4 pixels to force it
|
||||
* to do bilinear averaging */
|
||||
ch_u += width_i;
|
||||
ch_v += height_i;
|
||||
|
||||
/* set up coordinates for next chroma line, in case
|
||||
* (width / 2) % 4 == 2, i.e. the current set of 4 pixels is split
|
||||
* between the current and the next chroma line; do note that the next
|
||||
* chroma line is two source lines below the current source line */
|
||||
float ch_u_n = 0. + width_i;
|
||||
float ch_v_n = ch_v + height_i * 3;
|
||||
|
||||
sample_pos[0] = float2(ch_u, ch_v);
|
||||
sample_pos[1] = float2(ch_u += width_i2, ch_v);
|
||||
|
||||
ch_u += width_i2;
|
||||
// check if ch_u overflowed the current source and chroma line
|
||||
if (ch_u > 1.0) {
|
||||
sample_pos[2] = float2(ch_u_n, ch_v_n);
|
||||
sample_pos[2] = float2(ch_u_n + width_i2, ch_v_n);
|
||||
} else {
|
||||
sample_pos[2] = float2(ch_u, ch_v);
|
||||
sample_pos[3] = float2(ch_u + width_i2, ch_v);
|
||||
}
|
||||
}
|
||||
|
||||
float4x4 out_val = float4x4(
|
||||
image.Sample(def_sampler, sample_pos[0]),
|
||||
image.Sample(def_sampler, sample_pos[1]),
|
||||
image.Sample(def_sampler, sample_pos[2]),
|
||||
image.Sample(def_sampler, sample_pos[3])
|
||||
);
|
||||
|
||||
out_val = transpose(out_val);
|
||||
|
||||
if (byte_offset < u_plane_offset)
|
||||
return out_val[1];
|
||||
else if (byte_offset < v_plane_offset)
|
||||
return out_val[0];
|
||||
else
|
||||
return out_val[2];
|
||||
VertPosWide vert_out;
|
||||
vert_out.pos_wide = float3(float2(width, width_d2) * u, height * v);
|
||||
vert_out.pos = float4(x, y, 0.0, 1.0);
|
||||
return vert_out;
|
||||
}
|
||||
|
||||
float4 PSPlanar444(VertInOut vert_in) : TARGET
|
||||
float PS_Y(FragPos frag_in) : TARGET
|
||||
{
|
||||
float v_mul = floor(vert_in.uv.y * input_height);
|
||||
|
||||
float byte_offset = floor((v_mul + vert_in.uv.x) * width) * 4.0;
|
||||
byte_offset += PRECISION_OFFSET;
|
||||
|
||||
float new_byte_offset = byte_offset;
|
||||
|
||||
if (byte_offset >= v_plane_offset)
|
||||
new_byte_offset -= v_plane_offset;
|
||||
else if (byte_offset >= u_plane_offset)
|
||||
new_byte_offset -= u_plane_offset;
|
||||
|
||||
float2 sample_pos[4];
|
||||
|
||||
float u_val = floor(fmod(new_byte_offset, width)) * width_i;
|
||||
float v_val = floor(new_byte_offset * width_i) * height_i;
|
||||
|
||||
/* move to texel centers to sample the 4 pixels properly */
|
||||
u_val += width_i * 0.5;
|
||||
v_val += height_i * 0.5;
|
||||
|
||||
sample_pos[0] = float2(u_val, v_val);
|
||||
sample_pos[1] = float2(u_val += width_i, v_val);
|
||||
sample_pos[2] = float2(u_val += width_i, v_val);
|
||||
sample_pos[3] = float2(u_val + width_i, v_val);
|
||||
|
||||
float4x4 out_val = float4x4(
|
||||
image.Sample(def_sampler, sample_pos[0]),
|
||||
image.Sample(def_sampler, sample_pos[1]),
|
||||
image.Sample(def_sampler, sample_pos[2]),
|
||||
image.Sample(def_sampler, sample_pos[3])
|
||||
);
|
||||
|
||||
out_val = transpose(out_val);
|
||||
|
||||
if (byte_offset < u_plane_offset)
|
||||
return out_val[1];
|
||||
else if (byte_offset < v_plane_offset)
|
||||
return out_val[0];
|
||||
else
|
||||
return out_val[2];
|
||||
float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb;
|
||||
float y = dot(color_vec0.xyz, rgb) + color_vec0.w;
|
||||
return y;
|
||||
}
|
||||
|
||||
float GetIntOffsetColor(int offset)
|
||||
float2 PS_UV_Wide(FragTexWide frag_in) : TARGET
|
||||
{
|
||||
return image.Load(int3(offset % int_input_width,
|
||||
offset / int_input_width,
|
||||
0)).r;
|
||||
float3 rgb_left = image.Sample(def_sampler, frag_in.uuv.xz).rgb;
|
||||
float3 rgb_right = image.Sample(def_sampler, frag_in.uuv.yz).rgb;
|
||||
float3 rgb = (rgb_left + rgb_right) * 0.5;
|
||||
float u = dot(color_vec1.xyz, rgb) + color_vec1.w;
|
||||
float v = dot(color_vec2.xyz, rgb) + color_vec2.w;
|
||||
return float2(u, v);
|
||||
}
|
||||
|
||||
float4 PSPacked422_Reverse(VertInOut vert_in, int u_pos, int v_pos,
|
||||
int y0_pos, int y1_pos) : TARGET
|
||||
float PS_U(FragPos frag_in) : TARGET
|
||||
{
|
||||
float y = vert_in.uv.y;
|
||||
float odd = floor(fmod(width * vert_in.uv.x + PRECISION_OFFSET, 2.0));
|
||||
float x = floor(width_d2 * vert_in.uv.x + PRECISION_OFFSET) *
|
||||
width_d2_i;
|
||||
float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb;
|
||||
float u = dot(color_vec1.xyz, rgb) + color_vec1.w;
|
||||
return u;
|
||||
}
|
||||
|
||||
x += input_width_i_d2;
|
||||
float PS_V(FragPos frag_in) : TARGET
|
||||
{
|
||||
float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb;
|
||||
float v = dot(color_vec2.xyz, rgb) + color_vec2.w;
|
||||
return v;
|
||||
}
|
||||
|
||||
float4 texel = image.Sample(def_sampler, float2(x, y));
|
||||
float3 yuv = float3(odd > 0.5 ? texel[y1_pos] : texel[y0_pos],
|
||||
texel[u_pos], texel[v_pos]);
|
||||
float PS_U_Wide(FragTexWide frag_in) : TARGET
|
||||
{
|
||||
float3 rgb_left = image.Sample(def_sampler, frag_in.uuv.xz).rgb;
|
||||
float3 rgb_right = image.Sample(def_sampler, frag_in.uuv.yz).rgb;
|
||||
float3 rgb = (rgb_left + rgb_right) * 0.5;
|
||||
float u = dot(color_vec1.xyz, rgb) + color_vec1.w;
|
||||
return u;
|
||||
}
|
||||
|
||||
float PS_V_Wide(FragTexWide frag_in) : TARGET
|
||||
{
|
||||
float3 rgb_left = image.Sample(def_sampler, frag_in.uuv.xz).rgb;
|
||||
float3 rgb_right = image.Sample(def_sampler, frag_in.uuv.yz).rgb;
|
||||
float3 rgb = (rgb_left + rgb_right) * 0.5;
|
||||
float v = dot(color_vec2.xyz, rgb) + color_vec2.w;
|
||||
return v;
|
||||
}
|
||||
|
||||
float3 YUV_to_RGB(float3 yuv)
|
||||
{
|
||||
yuv = clamp(yuv, color_range_min, color_range_max);
|
||||
return saturate(mul(float4(yuv, 1.0), color_matrix));
|
||||
float r = dot(color_vec0.xyz, yuv) + color_vec0.w;
|
||||
float g = dot(color_vec1.xyz, yuv) + color_vec1.w;
|
||||
float b = dot(color_vec2.xyz, yuv) + color_vec2.w;
|
||||
return float3(r, g, b);
|
||||
}
|
||||
|
||||
float4 PSPlanar420_Reverse(VertInOut vert_in) : TARGET
|
||||
float3 PSUYVY_Reverse(FragTex frag_in) : TARGET
|
||||
{
|
||||
int x = int(vert_in.uv.x * width + PRECISION_OFFSET);
|
||||
int y = int(vert_in.uv.y * height + PRECISION_OFFSET);
|
||||
|
||||
int lum_offset = y * int_width + x;
|
||||
int chroma_offset = (y / 2) * (int_width / 2) + x / 2;
|
||||
int chroma1 = int_u_plane_offset + chroma_offset;
|
||||
int chroma2 = int_v_plane_offset + chroma_offset;
|
||||
|
||||
float3 yuv = float3(
|
||||
GetIntOffsetColor(lum_offset),
|
||||
GetIntOffsetColor(chroma1),
|
||||
GetIntOffsetColor(chroma2)
|
||||
);
|
||||
yuv = clamp(yuv, color_range_min, color_range_max);
|
||||
return saturate(mul(float4(yuv, 1.0), color_matrix));
|
||||
float4 y2uv = image.Load(int3(frag_in.uv.xy, 0));
|
||||
float2 y01 = y2uv.yw;
|
||||
float2 cbcr = y2uv.zx;
|
||||
float leftover = frac(frag_in.uv.x);
|
||||
float y = (leftover < 0.5) ? y01.x : y01.y;
|
||||
float3 yuv = float3(y, cbcr);
|
||||
float3 rgb = YUV_to_RGB(yuv);
|
||||
return rgb;
|
||||
}
|
||||
|
||||
float4 PSPlanar444_Reverse(VertInOut vert_in) : TARGET
|
||||
float3 PSYUY2_Reverse(FragTex frag_in) : TARGET
|
||||
{
|
||||
int x = int(vert_in.uv.x * width + PRECISION_OFFSET);
|
||||
int y = int(vert_in.uv.y * height + PRECISION_OFFSET);
|
||||
|
||||
int lum_offset = y * int_width + x;
|
||||
int chroma_offset = y * int_width + x;
|
||||
int chroma1 = int_u_plane_offset + chroma_offset;
|
||||
int chroma2 = int_v_plane_offset + chroma_offset;
|
||||
|
||||
float3 yuv = float3(
|
||||
GetIntOffsetColor(lum_offset),
|
||||
GetIntOffsetColor(chroma1),
|
||||
GetIntOffsetColor(chroma2)
|
||||
);
|
||||
yuv = clamp(yuv, color_range_min, color_range_max);
|
||||
return saturate(mul(float4(yuv, 1.0), color_matrix));
|
||||
float4 y2uv = image.Load(int3(frag_in.uv.xy, 0));
|
||||
float2 y01 = y2uv.zx;
|
||||
float2 cbcr = y2uv.yw;
|
||||
float leftover = frac(frag_in.uv.x);
|
||||
float y = (leftover < 0.5) ? y01.x : y01.y;
|
||||
float3 yuv = float3(y, cbcr);
|
||||
float3 rgb = YUV_to_RGB(yuv);
|
||||
return rgb;
|
||||
}
|
||||
|
||||
float4 PSNV12_Reverse(VertInOut vert_in) : TARGET
|
||||
float3 PSYVYU_Reverse(FragTex frag_in) : TARGET
|
||||
{
|
||||
int x = int(vert_in.uv.x * width + PRECISION_OFFSET);
|
||||
int y = int(vert_in.uv.y * height + PRECISION_OFFSET);
|
||||
|
||||
int lum_offset = y * int_width + x;
|
||||
int chroma_offset = (y / 2) * (int_width / 2) + x / 2;
|
||||
int chroma = int_u_plane_offset + chroma_offset * 2;
|
||||
|
||||
float3 yuv = float3(
|
||||
GetIntOffsetColor(lum_offset),
|
||||
GetIntOffsetColor(chroma),
|
||||
GetIntOffsetColor(chroma + 1)
|
||||
);
|
||||
yuv = clamp(yuv, color_range_min, color_range_max);
|
||||
return saturate(mul(float4(yuv, 1.0), color_matrix));
|
||||
float4 y2uv = image.Load(int3(frag_in.uv.xy, 0));
|
||||
float2 y01 = y2uv.zx;
|
||||
float2 cbcr = y2uv.wy;
|
||||
float leftover = frac(frag_in.uv.x);
|
||||
float y = (leftover < 0.5) ? y01.x : y01.y;
|
||||
float3 yuv = float3(y, cbcr);
|
||||
float3 rgb = YUV_to_RGB(yuv);
|
||||
return rgb;
|
||||
}
|
||||
|
||||
float4 PSY800_Limited(VertInOut vert_in) : TARGET
|
||||
float3 PSPlanar420_Reverse(VertTexPos frag_in) : TARGET
|
||||
{
|
||||
int x = int(vert_in.uv.x * width + PRECISION_OFFSET);
|
||||
int y = int(vert_in.uv.y * height + PRECISION_OFFSET);
|
||||
|
||||
float limited = image.Load(int3(x, y, 0)).x;
|
||||
float full = saturate((limited - (16.0 / 255.0)) * (255.0 / 219.0));
|
||||
return float4(full, full, full, 1.0);
|
||||
float y = image.Load(int3(frag_in.pos.xy, 0)).x;
|
||||
int3 xy0_chroma = int3(frag_in.uv, 0);
|
||||
float cb = image1.Load(xy0_chroma).x;
|
||||
float cr = image2.Load(xy0_chroma).x;
|
||||
float3 yuv = float3(y, cb, cr);
|
||||
float3 rgb = YUV_to_RGB(yuv);
|
||||
return rgb;
|
||||
}
|
||||
|
||||
float4 PSY800_Full(VertInOut vert_in) : TARGET
|
||||
float4 PSPlanar420A_Reverse(VertTexPos frag_in) : TARGET
|
||||
{
|
||||
int x = int(vert_in.uv.x * width + PRECISION_OFFSET);
|
||||
int y = int(vert_in.uv.y * height + PRECISION_OFFSET);
|
||||
|
||||
float3 full = image.Load(int3(x, y, 0)).xxx;
|
||||
return float4(full, 1.0);
|
||||
}
|
||||
|
||||
float4 PSRGB_Limited(VertInOut vert_in) : TARGET
|
||||
{
|
||||
int x = int(vert_in.uv.x * width + PRECISION_OFFSET);
|
||||
int y = int(vert_in.uv.y * height + PRECISION_OFFSET);
|
||||
|
||||
float4 rgba = image.Load(int3(x, y, 0));
|
||||
rgba.rgb = saturate((rgba.rgb - (16.0 / 255.0)) * (255.0 / 219.0));
|
||||
int3 xy0_luma = int3(frag_in.pos.xy, 0);
|
||||
float y = image.Load(xy0_luma).x;
|
||||
int3 xy0_chroma = int3(frag_in.uv, 0);
|
||||
float cb = image1.Load(xy0_chroma).x;
|
||||
float cr = image2.Load(xy0_chroma).x;
|
||||
float alpha = image3.Load(xy0_luma).x;
|
||||
float3 yuv = float3(y, cb, cr);
|
||||
float4 rgba = float4(YUV_to_RGB(yuv), alpha);
|
||||
return rgba;
|
||||
}
|
||||
|
||||
technique Planar420
|
||||
float3 PSPlanar422_Reverse(FragPosWide frag_in) : TARGET
|
||||
{
|
||||
float y = image.Load(int3(frag_in.pos_wide.xz, 0)).x;
|
||||
int3 xy0_chroma = int3(frag_in.pos_wide.yz, 0);
|
||||
float cb = image1.Load(xy0_chroma).x;
|
||||
float cr = image2.Load(xy0_chroma).x;
|
||||
float3 yuv = float3(y, cb, cr);
|
||||
float3 rgb = YUV_to_RGB(yuv);
|
||||
return rgb;
|
||||
}
|
||||
|
||||
float4 PSPlanar422A_Reverse(FragPosWide frag_in) : TARGET
|
||||
{
|
||||
int3 xy0_luma = int3(frag_in.pos_wide.xz, 0);
|
||||
float y = image.Load(xy0_luma).x;
|
||||
int3 xy0_chroma = int3(frag_in.pos_wide.yz, 0);
|
||||
float cb = image1.Load(xy0_chroma).x;
|
||||
float cr = image2.Load(xy0_chroma).x;
|
||||
float alpha = image3.Load(xy0_luma).x;
|
||||
float3 yuv = float3(y, cb, cr);
|
||||
float4 rgba = float4(YUV_to_RGB(yuv), alpha);
|
||||
return rgba;
|
||||
}
|
||||
|
||||
float3 PSPlanar444_Reverse(FragPos frag_in) : TARGET
|
||||
{
|
||||
int3 xy0 = int3(frag_in.pos.xy, 0);
|
||||
float y = image.Load(xy0).x;
|
||||
float cb = image1.Load(xy0).x;
|
||||
float cr = image2.Load(xy0).x;
|
||||
float3 yuv = float3(y, cb, cr);
|
||||
float3 rgb = YUV_to_RGB(yuv);
|
||||
return rgb;
|
||||
}
|
||||
|
||||
float4 PSPlanar444A_Reverse(FragPos frag_in) : TARGET
|
||||
{
|
||||
int3 xy0 = int3(frag_in.pos.xy, 0);
|
||||
float y = image.Load(xy0).x;
|
||||
float cb = image1.Load(xy0).x;
|
||||
float cr = image2.Load(xy0).x;
|
||||
float alpha = image3.Load(xy0).x;
|
||||
float3 yuv = float3(y, cb, cr);
|
||||
float4 rgba = float4(YUV_to_RGB(yuv), alpha);
|
||||
return rgba;
|
||||
}
|
||||
|
||||
float4 PSAYUV_Reverse(FragPos frag_in) : TARGET
|
||||
{
|
||||
float4 yuva = image.Load(int3(frag_in.pos.xy, 0));
|
||||
float4 rgba = float4(YUV_to_RGB(yuva.xyz), yuva.a);
|
||||
return rgba;
|
||||
}
|
||||
|
||||
float3 PSNV12_Reverse(VertTexPos frag_in) : TARGET
|
||||
{
|
||||
float y = image.Load(int3(frag_in.pos.xy, 0)).x;
|
||||
float2 cbcr = image1.Load(int3(frag_in.uv, 0)).xy;
|
||||
float3 yuv = float3(y, cbcr);
|
||||
float3 rgb = YUV_to_RGB(yuv);
|
||||
return rgb;
|
||||
}
|
||||
|
||||
float3 PSY800_Limited(FragPos frag_in) : TARGET
|
||||
{
|
||||
float limited = image.Load(int3(frag_in.pos.xy, 0)).x;
|
||||
float full = (255.0 / 219.0) * limited - (16.0 / 219.0);
|
||||
return float3(full, full, full);
|
||||
}
|
||||
|
||||
float3 PSY800_Full(FragPos frag_in) : TARGET
|
||||
{
|
||||
float3 full = image.Load(int3(frag_in.pos.xy, 0)).xxx;
|
||||
return full;
|
||||
}
|
||||
|
||||
float4 PSRGB_Limited(FragPos frag_in) : TARGET
|
||||
{
|
||||
float4 rgba = image.Load(int3(frag_in.pos.xy, 0));
|
||||
rgba.rgb = (255.0 / 219.0) * rgba.rgb - (16.0 / 219.0);
|
||||
return rgba;
|
||||
}
|
||||
|
||||
float3 PSBGR3_Limited(FragPos frag_in) : TARGET
|
||||
{
|
||||
float x = frag_in.pos.x * 3.0;
|
||||
float y = frag_in.pos.y;
|
||||
float b = image.Load(int3(x - 1.0, y, 0)).x;
|
||||
float g = image.Load(int3(x, y, 0)).x;
|
||||
float r = image.Load(int3(x + 1.0, y, 0)).x;
|
||||
float3 rgb = float3(r, g, b);
|
||||
rgb = (255.0 / 219.0) * rgb - (16.0 / 219.0);
|
||||
return rgb;
|
||||
}
|
||||
|
||||
float3 PSBGR3_Full(FragPos frag_in) : TARGET
|
||||
{
|
||||
float x = frag_in.pos.x * 3.0;
|
||||
float y = frag_in.pos.y;
|
||||
float b = image.Load(int3(x - 1.0, y, 0)).x;
|
||||
float g = image.Load(int3(x, y, 0)).x;
|
||||
float r = image.Load(int3(x + 1.0, y, 0)).x;
|
||||
float3 rgb = float3(r, g, b);
|
||||
return rgb;
|
||||
}
|
||||
|
||||
technique Planar_Y
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSPlanar420(vert_in);
|
||||
vertex_shader = VSPos(id);
|
||||
pixel_shader = PS_Y(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique Planar444
|
||||
technique Planar_U
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSPlanar444(vert_in);
|
||||
vertex_shader = VSPos(id);
|
||||
pixel_shader = PS_U(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique NV12
|
||||
technique Planar_V
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSNV12(vert_in);
|
||||
vertex_shader = VSPos(id);
|
||||
pixel_shader = PS_V(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique Planar_U_Left
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSTexPos_Left(id);
|
||||
pixel_shader = PS_U_Wide(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique Planar_V_Left
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSTexPos_Left(id);
|
||||
pixel_shader = PS_V_Wide(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -409,8 +425,8 @@ technique NV12_Y
|
|||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSNV12_Y(vert_in);
|
||||
vertex_shader = VSPos(id);
|
||||
pixel_shader = PS_Y(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -418,8 +434,8 @@ technique NV12_UV
|
|||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSNV12_UV(vert_in);
|
||||
vertex_shader = VSTexPos_Left(id);
|
||||
pixel_shader = PS_UV_Wide(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -427,8 +443,8 @@ technique UYVY_Reverse
|
|||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSPacked422_Reverse(vert_in, 2, 0, 1, 3);
|
||||
vertex_shader = VSTexPosHalf_Reverse(id);
|
||||
pixel_shader = PSUYVY_Reverse(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -436,8 +452,8 @@ technique YUY2_Reverse
|
|||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSPacked422_Reverse(vert_in, 1, 3, 2, 0);
|
||||
vertex_shader = VSTexPosHalf_Reverse(id);
|
||||
pixel_shader = PSYUY2_Reverse(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -445,8 +461,8 @@ technique YVYU_Reverse
|
|||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSPacked422_Reverse(vert_in, 3, 1, 2, 0);
|
||||
vertex_shader = VSTexPosHalf_Reverse(id);
|
||||
pixel_shader = PSYVYU_Reverse(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -454,8 +470,35 @@ technique I420_Reverse
|
|||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSPlanar420_Reverse(vert_in);
|
||||
vertex_shader = VSTexPosHalfHalf_Reverse(id);
|
||||
pixel_shader = PSPlanar420_Reverse(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique I40A_Reverse
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSTexPosHalfHalf_Reverse(id);
|
||||
pixel_shader = PSPlanar420A_Reverse(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique I422_Reverse
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSPosWide_Reverse(id);
|
||||
pixel_shader = PSPlanar422_Reverse(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique I42A_Reverse
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSPosWide_Reverse(id);
|
||||
pixel_shader = PSPlanar422A_Reverse(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -463,8 +506,26 @@ technique I444_Reverse
|
|||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSPlanar444_Reverse(vert_in);
|
||||
vertex_shader = VSPos(id);
|
||||
pixel_shader = PSPlanar444_Reverse(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique YUVA_Reverse
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSPos(id);
|
||||
pixel_shader = PSPlanar444A_Reverse(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique AYUV_Reverse
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSPos(id);
|
||||
pixel_shader = PSAYUV_Reverse(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -472,8 +533,8 @@ technique NV12_Reverse
|
|||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSNV12_Reverse(vert_in);
|
||||
vertex_shader = VSTexPosHalfHalf_Reverse(id);
|
||||
pixel_shader = PSNV12_Reverse(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -481,8 +542,8 @@ technique Y800_Limited
|
|||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSY800_Limited(vert_in);
|
||||
vertex_shader = VSPos(id);
|
||||
pixel_shader = PSY800_Limited(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -490,8 +551,8 @@ technique Y800_Full
|
|||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSY800_Full(vert_in);
|
||||
vertex_shader = VSPos(id);
|
||||
pixel_shader = PSY800_Full(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -499,7 +560,25 @@ technique RGB_Limited
|
|||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSRGB_Limited(vert_in);
|
||||
vertex_shader = VSPos(id);
|
||||
pixel_shader = PSRGB_Limited(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique BGR3_Limited
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSPos(id);
|
||||
pixel_shader = PSBGR3_Limited(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique BGR3_Full
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSPos(id);
|
||||
pixel_shader = PSBGR3_Full(frag_in);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
uniform float4x4 ViewProj;
|
||||
uniform texture2d image;
|
||||
uniform float4x4 color_matrix;
|
||||
uniform float2 base_dimension;
|
||||
uniform float2 base_dimension_i;
|
||||
uniform float undistort_factor = 1.0;
|
||||
|
||||
|
|
@ -22,45 +22,46 @@ struct VertData {
|
|||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct FragData {
|
||||
struct VertOut {
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 pos : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float2 scale : TEXCOORD1;
|
||||
};
|
||||
|
||||
FragData VSDefault(VertData v_in)
|
||||
struct FragData {
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
VertOut VSDefault(VertData v_in)
|
||||
{
|
||||
FragData vert_out;
|
||||
VertOut vert_out;
|
||||
vert_out.uv = v_in.uv * base_dimension;
|
||||
vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj);
|
||||
vert_out.uv = v_in.uv;
|
||||
vert_out.scale = min(0.25 + abs(0.75 / mul(float4(1.0 / base_dimension_i.xy, 1.0, 1.0), ViewProj).xy), 1.0);
|
||||
|
||||
return vert_out;
|
||||
}
|
||||
|
||||
float sinc(float x)
|
||||
float weight(float x)
|
||||
{
|
||||
const float PIval = 3.1415926535897932384626433832795;
|
||||
return sin(x * PIval) / (x * PIval);
|
||||
float x_pi = x * 3.141592654;
|
||||
return 3.0 * sin(x_pi) * sin(x_pi * (1.0 / 3.0)) / (x_pi * x_pi);
|
||||
}
|
||||
|
||||
float weight(float x, float radius)
|
||||
void weight6(float f_neg, out float3 tap012, out float3 tap345)
|
||||
{
|
||||
float ax = abs(x);
|
||||
if (x == 0.0)
|
||||
return 1.0;
|
||||
else if (ax < radius)
|
||||
return sinc(x) * sinc(x / radius);
|
||||
else
|
||||
return 0.0;
|
||||
}
|
||||
tap012 = float3(
|
||||
weight(f_neg - 2.0),
|
||||
weight(f_neg - 1.0),
|
||||
min(1.0, weight(f_neg))); // Replace NaN with 1.0.
|
||||
tap345 = float3(
|
||||
weight(f_neg + 1.0),
|
||||
weight(f_neg + 2.0),
|
||||
weight(f_neg + 3.0));
|
||||
|
||||
float3 weight3(float x, float scale)
|
||||
{
|
||||
return float3(
|
||||
weight((x * 2.0 + 0.0 * 2.0 - 3.0) * scale, 3.0),
|
||||
weight((x * 2.0 + 1.0 * 2.0 - 3.0) * scale, 3.0),
|
||||
weight((x * 2.0 + 2.0 * 2.0 - 3.0) * scale, 3.0));
|
||||
// Normalize weights
|
||||
float sum = tap012.x + tap012.y + tap012.z + tap345.x + tap345.y + tap345.z;
|
||||
float sum_i = 1.0 / sum;
|
||||
tap012 = tap012 * sum_i;
|
||||
tap345 = tap345 * sum_i;
|
||||
}
|
||||
|
||||
float AspectUndistortX(float x, float a)
|
||||
|
|
@ -75,90 +76,134 @@ float AspectUndistortU(float u)
|
|||
return AspectUndistortX((u - 0.5) * 2.0, undistort_factor) * 0.5 + 0.5;
|
||||
}
|
||||
|
||||
float2 pixel_coord(float xpos, float ypos)
|
||||
float2 undistort_coord(float xpos, float ypos)
|
||||
{
|
||||
return float2(AspectUndistortU(xpos), ypos);
|
||||
}
|
||||
|
||||
float4 pixel(float xpos, float ypos, bool undistort)
|
||||
float4 undistort_pixel(float xpos, float ypos)
|
||||
{
|
||||
if (undistort)
|
||||
return image.Sample(textureSampler, pixel_coord(xpos, ypos));
|
||||
else
|
||||
return image.Sample(textureSampler, float2(xpos, ypos));
|
||||
return image.Sample(textureSampler, undistort_coord(xpos, ypos));
|
||||
}
|
||||
|
||||
float4 get_line(float ypos, float3 xpos1, float3 xpos2, float3 rowtap1,
|
||||
float3 rowtap2, bool undistort)
|
||||
float4 undistort_line(float3 xpos012, float3 xpos345, float ypos, float3 rowtap012,
|
||||
float3 rowtap345)
|
||||
{
|
||||
return
|
||||
pixel(xpos1.r, ypos, undistort) * rowtap1.r +
|
||||
pixel(xpos1.g, ypos, undistort) * rowtap2.r +
|
||||
pixel(xpos1.b, ypos, undistort) * rowtap1.g +
|
||||
pixel(xpos2.r, ypos, undistort) * rowtap2.g +
|
||||
pixel(xpos2.g, ypos, undistort) * rowtap1.b +
|
||||
pixel(xpos2.b, ypos, undistort) * rowtap2.b;
|
||||
undistort_pixel(xpos012.x, ypos) * rowtap012.x +
|
||||
undistort_pixel(xpos012.y, ypos) * rowtap012.y +
|
||||
undistort_pixel(xpos012.z, ypos) * rowtap012.z +
|
||||
undistort_pixel(xpos345.x, ypos) * rowtap345.x +
|
||||
undistort_pixel(xpos345.y, ypos) * rowtap345.y +
|
||||
undistort_pixel(xpos345.z, ypos) * rowtap345.z;
|
||||
}
|
||||
|
||||
float4 DrawLanczos(FragData v_in, bool undistort)
|
||||
float4 DrawLanczos(FragData f_in, bool undistort)
|
||||
{
|
||||
float2 stepxy = base_dimension_i;
|
||||
float2 pos = v_in.uv + stepxy * 0.5;
|
||||
float2 f = frac(pos / stepxy);
|
||||
float2 pos = f_in.uv;
|
||||
float2 pos2 = floor(pos - 0.5) + 0.5;
|
||||
float2 f_neg = pos2 - pos;
|
||||
|
||||
float3 rowtap1 = weight3((1.0 - f.x) / 2.0, v_in.scale.x);
|
||||
float3 rowtap2 = weight3((1.0 - f.x) / 2.0 + 0.5, v_in.scale.x);
|
||||
float3 coltap1 = weight3((1.0 - f.y) / 2.0, v_in.scale.y);
|
||||
float3 coltap2 = weight3((1.0 - f.y) / 2.0 + 0.5, v_in.scale.y);
|
||||
float3 rowtap012, rowtap345;
|
||||
weight6(f_neg.x, rowtap012, rowtap345);
|
||||
|
||||
/* make sure all taps added together is exactly 1.0, otherwise some
|
||||
* (very small) distortion can occur */
|
||||
float suml = rowtap1.r + rowtap1.g + rowtap1.b + rowtap2.r + rowtap2.g + rowtap2.b;
|
||||
float sumc = coltap1.r + coltap1.g + coltap1.b + coltap2.r + coltap2.g + coltap2.b;
|
||||
rowtap1 /= suml;
|
||||
rowtap2 /= suml;
|
||||
coltap1 /= sumc;
|
||||
coltap2 /= sumc;
|
||||
float3 coltap012, coltap345;
|
||||
weight6(f_neg.y, coltap012, coltap345);
|
||||
|
||||
float2 xystart = (-2.5 - f) * stepxy + pos;
|
||||
float3 xpos1 = float3(xystart.x , xystart.x + stepxy.x , xystart.x + stepxy.x * 2.0);
|
||||
float3 xpos2 = float3(xystart.x + stepxy.x * 3.0, xystart.x + stepxy.x * 4.0, xystart.x + stepxy.x * 5.0);
|
||||
float2 uv2 = pos2 * base_dimension_i;
|
||||
float2 uv1 = uv2 - base_dimension_i;
|
||||
float2 uv0 = uv1 - base_dimension_i;
|
||||
float2 uv3 = uv2 + base_dimension_i;
|
||||
float2 uv4 = uv3 + base_dimension_i;
|
||||
float2 uv5 = uv4 + base_dimension_i;
|
||||
|
||||
return
|
||||
get_line(xystart.y , xpos1, xpos2, rowtap1, rowtap2, undistort) * coltap1.r +
|
||||
get_line(xystart.y + stepxy.y , xpos1, xpos2, rowtap1, rowtap2, undistort) * coltap2.r +
|
||||
get_line(xystart.y + stepxy.y * 2.0, xpos1, xpos2, rowtap1, rowtap2, undistort) * coltap1.g +
|
||||
get_line(xystart.y + stepxy.y * 3.0, xpos1, xpos2, rowtap1, rowtap2, undistort) * coltap2.g +
|
||||
get_line(xystart.y + stepxy.y * 4.0, xpos1, xpos2, rowtap1, rowtap2, undistort) * coltap1.b +
|
||||
get_line(xystart.y + stepxy.y * 5.0, xpos1, xpos2, rowtap1, rowtap2, undistort) * coltap2.b;
|
||||
if (undistort) {
|
||||
float3 xpos012 = float3(uv0.x, uv1.x, uv2.x);
|
||||
float3 xpos345 = float3(uv3.x, uv4.x, uv5.x);
|
||||
return undistort_line(xpos012, xpos345, uv0.y, rowtap012, rowtap345) * coltap012.x +
|
||||
undistort_line(xpos012, xpos345, uv1.y, rowtap012, rowtap345) * coltap012.y +
|
||||
undistort_line(xpos012, xpos345, uv2.y, rowtap012, rowtap345) * coltap012.z +
|
||||
undistort_line(xpos012, xpos345, uv3.y, rowtap012, rowtap345) * coltap345.x +
|
||||
undistort_line(xpos012, xpos345, uv4.y, rowtap012, rowtap345) * coltap345.y +
|
||||
undistort_line(xpos012, xpos345, uv5.y, rowtap012, rowtap345) * coltap345.z;
|
||||
}
|
||||
|
||||
float u_weight_sum = rowtap012.z + rowtap345.x;
|
||||
float u_middle_offset = rowtap345.x * base_dimension_i.x / u_weight_sum;
|
||||
float u_middle = uv2.x + u_middle_offset;
|
||||
|
||||
float v_weight_sum = coltap012.z + coltap345.x;
|
||||
float v_middle_offset = coltap345.x * base_dimension_i.y / v_weight_sum;
|
||||
float v_middle = uv2.y + v_middle_offset;
|
||||
|
||||
float2 coord_limit = base_dimension - 0.5;
|
||||
float2 coord0_f = max(uv0 * base_dimension, 0.5);
|
||||
float2 coord1_f = max(uv1 * base_dimension, 0.5);
|
||||
float2 coord4_f = min(uv4 * base_dimension, coord_limit);
|
||||
float2 coord5_f = min(uv5 * base_dimension, coord_limit);
|
||||
|
||||
int2 coord0 = int2(coord0_f);
|
||||
int2 coord1 = int2(coord1_f);
|
||||
int2 coord4 = int2(coord4_f);
|
||||
int2 coord5 = int2(coord5_f);
|
||||
|
||||
float4 row0 = image.Load(int3(coord0, 0)) * rowtap012.x;
|
||||
row0 += image.Load(int3(coord1.x, coord0.y, 0)) * rowtap012.y;
|
||||
row0 += image.Sample(textureSampler, float2(u_middle, uv0.y)) * u_weight_sum;
|
||||
row0 += image.Load(int3(coord4.x, coord0.y, 0)) * rowtap345.y;
|
||||
row0 += image.Load(int3(coord5.x, coord0.y, 0)) * rowtap345.z;
|
||||
float4 total = row0 * coltap012.x;
|
||||
|
||||
float4 row1 = image.Load(int3(coord0.x, coord1.y, 0)) * rowtap012.x;
|
||||
row1 += image.Load(int3(coord1.x, coord1.y, 0)) * rowtap012.y;
|
||||
row1 += image.Sample(textureSampler, float2(u_middle, uv1.y)) * u_weight_sum;
|
||||
row1 += image.Load(int3(coord4.x, coord1.y, 0)) * rowtap345.y;
|
||||
row1 += image.Load(int3(coord5.x, coord1.y, 0)) * rowtap345.z;
|
||||
total += row1 * coltap012.y;
|
||||
|
||||
float4 row23 = image.Sample(textureSampler, float2(uv0.x, v_middle)) * rowtap012.x;
|
||||
row23 += image.Sample(textureSampler, float2(uv1.x, v_middle)) * rowtap012.y;
|
||||
row23 += image.Sample(textureSampler, float2(u_middle, v_middle)) * u_weight_sum;
|
||||
row23 += image.Sample(textureSampler, float2(uv4.x, v_middle)) * rowtap345.y;
|
||||
row23 += image.Sample(textureSampler, float2(uv5.x, v_middle)) * rowtap345.z;
|
||||
total += row23 * v_weight_sum;
|
||||
|
||||
float4 row4 = image.Load(int3(coord0.x, coord4.y, 0)) * rowtap012.x;
|
||||
row4 += image.Load(int3(coord1.x, coord4.y, 0)) * rowtap012.y;
|
||||
row4 += image.Sample(textureSampler, float2(u_middle, uv4.y)) * u_weight_sum;
|
||||
row4 += image.Load(int3(coord4.x, coord4.y, 0)) * rowtap345.y;
|
||||
row4 += image.Load(int3(coord5.x, coord4.y, 0)) * rowtap345.z;
|
||||
total += row4 * coltap345.y;
|
||||
|
||||
float4 row5 = image.Load(int3(coord0.x, coord5.y, 0)) * rowtap012.x;
|
||||
row5 += image.Load(int3(coord1.x, coord5.y, 0)) * rowtap012.y;
|
||||
row5 += image.Sample(textureSampler, float2(u_middle, uv5.y)) * u_weight_sum;
|
||||
row5 += image.Load(int3(coord4.x, coord5.y, 0)) * rowtap345.y;
|
||||
row5 += image.Load(int3(coord5, 0)) * rowtap345.z;
|
||||
total += row5 * coltap345.z;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
float4 PSDrawLanczosRGBA(FragData v_in, bool undistort) : TARGET
|
||||
float4 PSDrawLanczosRGBA(FragData f_in, bool undistort) : TARGET
|
||||
{
|
||||
return DrawLanczos(v_in, undistort);
|
||||
return DrawLanczos(f_in, undistort);
|
||||
}
|
||||
|
||||
float4 PSDrawLanczosRGBADivide(FragData v_in) : TARGET
|
||||
float4 PSDrawLanczosRGBADivide(FragData f_in) : TARGET
|
||||
{
|
||||
float4 rgba = DrawLanczos(v_in, false);
|
||||
float4 rgba = DrawLanczos(f_in, false);
|
||||
float alpha = rgba.a;
|
||||
float multiplier = (alpha > 0.0) ? (1.0 / alpha) : 0.0;
|
||||
return float4(rgba.rgb * multiplier, alpha);
|
||||
}
|
||||
|
||||
float4 PSDrawLanczosMatrix(FragData v_in) : TARGET
|
||||
{
|
||||
float3 rgb = DrawLanczos(v_in, false).rgb;
|
||||
float3 yuv = mul(float4(saturate(rgb), 1.0), color_matrix).xyz;
|
||||
return float4(yuv, 1.0);
|
||||
}
|
||||
|
||||
technique Draw
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(v_in);
|
||||
pixel_shader = PSDrawLanczosRGBA(v_in, false);
|
||||
pixel_shader = PSDrawLanczosRGBA(f_in, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -167,7 +212,7 @@ technique DrawAlphaDivide
|
|||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(v_in);
|
||||
pixel_shader = PSDrawLanczosRGBADivide(v_in);
|
||||
pixel_shader = PSDrawLanczosRGBADivide(f_in);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -176,15 +221,6 @@ technique DrawUndistort
|
|||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(v_in);
|
||||
pixel_shader = PSDrawLanczosRGBA(v_in, true);
|
||||
}
|
||||
}
|
||||
|
||||
technique DrawMatrix
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(v_in);
|
||||
pixel_shader = PSDrawLanczosMatrix(v_in);
|
||||
pixel_shader = PSDrawLanczosRGBA(f_in, true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@ void axisang_from_quat(struct axisang *dst, const struct quat *q)
|
|||
{
|
||||
float len, leni;
|
||||
|
||||
len = q->x*q->x + q->y*q->y + q->z*q->z;
|
||||
len = q->x * q->x + q->y * q->y + q->z * q->z;
|
||||
if (!close_float(len, 0.0f, EPSILON)) {
|
||||
leni = 1.0f/sqrtf(len);
|
||||
leni = 1.0f / sqrtf(len);
|
||||
dst->x = q->x * leni;
|
||||
dst->y = q->y * leni;
|
||||
dst->z = q->z * leni;
|
||||
dst->w = acosf(q->w)*2.0f;
|
||||
dst->w = acosf(q->w) * 2.0f;
|
||||
} else {
|
||||
dst->x = 0.0f;
|
||||
dst->y = 0.0f;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,9 @@ struct quat;
|
|||
|
||||
struct axisang {
|
||||
union {
|
||||
struct {float x, y, z, w;};
|
||||
struct {
|
||||
float x, y, z, w;
|
||||
};
|
||||
float ptr[4];
|
||||
};
|
||||
};
|
||||
|
|
@ -49,7 +51,7 @@ static inline void axisang_copy(struct axisang *dst, struct axisang *aa)
|
|||
}
|
||||
|
||||
static inline void axisang_set(struct axisang *dst, float x, float y, float z,
|
||||
float w)
|
||||
float w)
|
||||
{
|
||||
dst->x = x;
|
||||
dst->y = y;
|
||||
|
|
|
|||
|
|
@ -22,35 +22,34 @@
|
|||
#include "plane.h"
|
||||
|
||||
void bounds_move(struct bounds *dst, const struct bounds *b,
|
||||
const struct vec3 *v)
|
||||
const struct vec3 *v)
|
||||
{
|
||||
vec3_add(&dst->min, &b->min, v);
|
||||
vec3_add(&dst->max, &b->max, v);
|
||||
}
|
||||
|
||||
void bounds_scale(struct bounds *dst, const struct bounds *b,
|
||||
const struct vec3 *v)
|
||||
const struct vec3 *v)
|
||||
{
|
||||
vec3_mul(&dst->min, &b->min, v);
|
||||
vec3_mul(&dst->max, &b->max, v);
|
||||
}
|
||||
|
||||
void bounds_merge(struct bounds *dst, const struct bounds *b1,
|
||||
const struct bounds *b2)
|
||||
const struct bounds *b2)
|
||||
{
|
||||
vec3_min(&dst->min, &b1->min, &b2->min);
|
||||
vec3_max(&dst->max, &b1->max, &b2->max);
|
||||
}
|
||||
|
||||
void bounds_merge_point(struct bounds *dst, const struct bounds *b,
|
||||
const struct vec3 *v)
|
||||
const struct vec3 *v)
|
||||
{
|
||||
vec3_min(&dst->min, &b->min, v);
|
||||
vec3_max(&dst->max, &b->max, v);
|
||||
}
|
||||
|
||||
void bounds_get_point(struct vec3 *dst, const struct bounds *b,
|
||||
unsigned int i)
|
||||
void bounds_get_point(struct vec3 *dst, const struct bounds *b, unsigned int i)
|
||||
{
|
||||
if (i > 8)
|
||||
return;
|
||||
|
|
@ -68,11 +67,19 @@ void bounds_get_point(struct vec3 *dst, const struct bounds *b,
|
|||
* 7 = MAX.x,MAX.y,MAX.z
|
||||
*/
|
||||
|
||||
if(i > 3) {dst->x = b->max.x; i -= 4;}
|
||||
else {dst->x = b->min.x;}
|
||||
if (i > 3) {
|
||||
dst->x = b->max.x;
|
||||
i -= 4;
|
||||
} else {
|
||||
dst->x = b->min.x;
|
||||
}
|
||||
|
||||
if(i > 1) {dst->y = b->max.y; i -= 2;}
|
||||
else {dst->y = b->min.y;}
|
||||
if (i > 1) {
|
||||
dst->y = b->max.y;
|
||||
i -= 2;
|
||||
} else {
|
||||
dst->y = b->min.y;
|
||||
}
|
||||
|
||||
dst->z = (i == 1) ? b->max.z : b->min.z;
|
||||
}
|
||||
|
|
@ -85,7 +92,7 @@ void bounds_get_center(struct vec3 *dst, const struct bounds *b)
|
|||
}
|
||||
|
||||
void bounds_transform(struct bounds *dst, const struct bounds *b,
|
||||
const struct matrix4 *m)
|
||||
const struct matrix4 *m)
|
||||
{
|
||||
struct bounds temp;
|
||||
bool b_init = false;
|
||||
|
|
@ -124,7 +131,7 @@ void bounds_transform(struct bounds *dst, const struct bounds *b,
|
|||
}
|
||||
|
||||
void bounds_transform3x4(struct bounds *dst, const struct bounds *b,
|
||||
const struct matrix3 *m)
|
||||
const struct matrix3 *m)
|
||||
{
|
||||
struct bounds temp;
|
||||
bool b_init = false;
|
||||
|
|
@ -163,7 +170,7 @@ void bounds_transform3x4(struct bounds *dst, const struct bounds *b,
|
|||
}
|
||||
|
||||
bool bounds_intersection_ray(const struct bounds *b, const struct vec3 *orig,
|
||||
const struct vec3 *dir, float *t)
|
||||
const struct vec3 *dir, float *t)
|
||||
{
|
||||
float t_max = M_INFINITE;
|
||||
float t_min = -M_INFINITE;
|
||||
|
|
@ -179,22 +186,26 @@ bool bounds_intersection_ray(const struct bounds *b, const struct vec3 *orig,
|
|||
float f = dir->ptr[i];
|
||||
|
||||
if (fabsf(f) > 0.0f) {
|
||||
float fi = 1.0f/f;
|
||||
float t1 = (e+max_offset.ptr[i])*fi;
|
||||
float t2 = (e-max_offset.ptr[i])*fi;
|
||||
float fi = 1.0f / f;
|
||||
float t1 = (e + max_offset.ptr[i]) * fi;
|
||||
float t2 = (e - max_offset.ptr[i]) * fi;
|
||||
if (t1 > t2) {
|
||||
if (t2 > t_min) t_min = t2;
|
||||
if (t1 < t_max) t_max = t1;
|
||||
if (t2 > t_min)
|
||||
t_min = t2;
|
||||
if (t1 < t_max)
|
||||
t_max = t1;
|
||||
} else {
|
||||
if (t1 > t_min) t_min = t1;
|
||||
if (t2 < t_max) t_max = t2;
|
||||
if (t1 > t_min)
|
||||
t_min = t1;
|
||||
if (t2 < t_max)
|
||||
t_max = t2;
|
||||
}
|
||||
if (t_min > t_max)
|
||||
return false;
|
||||
if (t_max < 0.0f)
|
||||
return false;
|
||||
} else if ((-e - max_offset.ptr[i]) > 0.0f ||
|
||||
(-e + max_offset.ptr[i]) < 0.0f) {
|
||||
(-e + max_offset.ptr[i]) < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -204,7 +215,7 @@ bool bounds_intersection_ray(const struct bounds *b, const struct vec3 *orig,
|
|||
}
|
||||
|
||||
bool bounds_intersection_line(const struct bounds *b, const struct vec3 *p1,
|
||||
const struct vec3 *p2, float *t)
|
||||
const struct vec3 *p2, float *t)
|
||||
{
|
||||
struct vec3 dir;
|
||||
float length;
|
||||
|
|
@ -214,7 +225,7 @@ bool bounds_intersection_line(const struct bounds *b, const struct vec3 *p1,
|
|||
if (length <= TINY_EPSILON)
|
||||
return false;
|
||||
|
||||
vec3_mulf(&dir, &dir, 1.0f/length);
|
||||
vec3_mulf(&dir, &dir, 1.0f / length);
|
||||
|
||||
if (!bounds_intersection_ray(b, p1, &dir, t))
|
||||
return false;
|
||||
|
|
@ -259,7 +270,7 @@ bool bounds_under_plane(const struct bounds *b, const struct plane *p)
|
|||
}
|
||||
|
||||
bool bounds_intersects(const struct bounds *b, const struct bounds *test,
|
||||
float epsilon)
|
||||
float epsilon)
|
||||
{
|
||||
return ((b->min.x - test->max.x) <= epsilon) &&
|
||||
((test->min.x - b->max.x) <= epsilon) &&
|
||||
|
|
@ -270,7 +281,7 @@ bool bounds_intersects(const struct bounds *b, const struct bounds *test,
|
|||
}
|
||||
|
||||
bool bounds_intersects_obb(const struct bounds *b, const struct bounds *test,
|
||||
const struct matrix4 *m, float epsilon)
|
||||
const struct matrix4 *m, float epsilon)
|
||||
{
|
||||
struct bounds b_tr, test_tr;
|
||||
struct matrix4 m_inv;
|
||||
|
|
@ -285,7 +296,7 @@ bool bounds_intersects_obb(const struct bounds *b, const struct bounds *test,
|
|||
}
|
||||
|
||||
bool bounds_intersects_obb3x4(const struct bounds *b, const struct bounds *test,
|
||||
const struct matrix3 *m, float epsilon)
|
||||
const struct matrix3 *m, float epsilon)
|
||||
{
|
||||
struct bounds b_tr, test_tr;
|
||||
struct matrix3 m_inv;
|
||||
|
|
@ -300,7 +311,7 @@ bool bounds_intersects_obb3x4(const struct bounds *b, const struct bounds *test,
|
|||
}
|
||||
|
||||
static inline float vec3or_offset_len(const struct bounds *b,
|
||||
const struct vec3 *v)
|
||||
const struct vec3 *v)
|
||||
{
|
||||
struct vec3 temp1, temp2;
|
||||
vec3_sub(&temp1, &b->max, &b->min);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ extern "C" {
|
|||
#define BOUNDS_MAX_Z 4
|
||||
|
||||
#define BOUNDS_OUTSIDE 1
|
||||
#define BOUNDS_INSIDE 2
|
||||
#define BOUNDS_INSIDE 2
|
||||
#define BOUNDS_PARTIAL 3
|
||||
|
||||
struct bounds {
|
||||
|
|
@ -53,18 +53,18 @@ static inline void bounds_copy(struct bounds *dst, const struct bounds *b)
|
|||
}
|
||||
|
||||
EXPORT void bounds_move(struct bounds *dst, const struct bounds *b,
|
||||
const struct vec3 *v);
|
||||
const struct vec3 *v);
|
||||
|
||||
EXPORT void bounds_scale(struct bounds *dst, const struct bounds *b,
|
||||
const struct vec3 *v);
|
||||
const struct vec3 *v);
|
||||
|
||||
EXPORT void bounds_merge(struct bounds *dst, const struct bounds *b1,
|
||||
const struct bounds *b2);
|
||||
const struct bounds *b2);
|
||||
EXPORT void bounds_merge_point(struct bounds *dst, const struct bounds *b,
|
||||
const struct vec3 *v);
|
||||
const struct vec3 *v);
|
||||
|
||||
EXPORT void bounds_get_point(struct vec3 *dst, const struct bounds *b,
|
||||
unsigned int i);
|
||||
unsigned int i);
|
||||
EXPORT void bounds_get_center(struct vec3 *dst, const struct bounds *b);
|
||||
|
||||
/**
|
||||
|
|
@ -72,59 +72,56 @@ EXPORT void bounds_get_center(struct vec3 *dst, const struct bounds *b);
|
|||
* the actual size becoming larger than it originally was.
|
||||
*/
|
||||
EXPORT void bounds_transform(struct bounds *dst, const struct bounds *b,
|
||||
const struct matrix4 *m);
|
||||
const struct matrix4 *m);
|
||||
EXPORT void bounds_transform3x4(struct bounds *dst, const struct bounds *b,
|
||||
const struct matrix3 *m);
|
||||
const struct matrix3 *m);
|
||||
|
||||
EXPORT bool bounds_intersection_ray(const struct bounds *b,
|
||||
const struct vec3 *orig, const struct vec3 *dir, float *t);
|
||||
const struct vec3 *orig,
|
||||
const struct vec3 *dir, float *t);
|
||||
EXPORT bool bounds_intersection_line(const struct bounds *b,
|
||||
const struct vec3 *p1, const struct vec3 *p2, float *t);
|
||||
const struct vec3 *p1,
|
||||
const struct vec3 *p2, float *t);
|
||||
|
||||
EXPORT bool bounds_plane_test(const struct bounds *b, const struct plane *p);
|
||||
EXPORT bool bounds_under_plane(const struct bounds *b,
|
||||
const struct plane *p);
|
||||
EXPORT bool bounds_under_plane(const struct bounds *b, const struct plane *p);
|
||||
|
||||
static inline bool bounds_inside(const struct bounds *b,
|
||||
const struct bounds *test)
|
||||
const struct bounds *test)
|
||||
{
|
||||
return test->min.x >= b->min.x &&
|
||||
test->min.y >= b->min.y &&
|
||||
test->min.z >= b->min.z &&
|
||||
test->max.x <= b->max.x &&
|
||||
test->max.y <= b->max.y &&
|
||||
test->max.z <= b->max.z;
|
||||
return test->min.x >= b->min.x && test->min.y >= b->min.y &&
|
||||
test->min.z >= b->min.z && test->max.x <= b->max.x &&
|
||||
test->max.y <= b->max.y && test->max.z <= b->max.z;
|
||||
}
|
||||
|
||||
static inline bool bounds_vec3_inside(const struct bounds *b,
|
||||
const struct vec3 *v)
|
||||
const struct vec3 *v)
|
||||
{
|
||||
return v->x >= (b->min.x-EPSILON) &&
|
||||
v->x <= (b->max.x+EPSILON) &&
|
||||
v->y >= (b->min.y-EPSILON) &&
|
||||
v->y <= (b->max.y+EPSILON) &&
|
||||
v->z >= (b->min.z-EPSILON) &&
|
||||
v->z <= (b->max.z+EPSILON);
|
||||
return v->x >= (b->min.x - EPSILON) && v->x <= (b->max.x + EPSILON) &&
|
||||
v->y >= (b->min.y - EPSILON) && v->y <= (b->max.y + EPSILON) &&
|
||||
v->z >= (b->min.z - EPSILON) && v->z <= (b->max.z + EPSILON);
|
||||
}
|
||||
|
||||
EXPORT bool bounds_intersects(const struct bounds *b,
|
||||
const struct bounds *test, float epsilon);
|
||||
EXPORT bool bounds_intersects(const struct bounds *b, const struct bounds *test,
|
||||
float epsilon);
|
||||
EXPORT bool bounds_intersects_obb(const struct bounds *b,
|
||||
const struct bounds *test, const struct matrix4 *m,
|
||||
float epsilon);
|
||||
const struct bounds *test,
|
||||
const struct matrix4 *m, float epsilon);
|
||||
EXPORT bool bounds_intersects_obb3x4(const struct bounds *b,
|
||||
const struct bounds *test, const struct matrix3 *m,
|
||||
float epsilon);
|
||||
const struct bounds *test,
|
||||
const struct matrix3 *m, float epsilon);
|
||||
|
||||
static inline bool bounds_intersects_ray(const struct bounds *b,
|
||||
const struct vec3 *orig, const struct vec3 *dir)
|
||||
const struct vec3 *orig,
|
||||
const struct vec3 *dir)
|
||||
{
|
||||
float t;
|
||||
return bounds_intersection_ray(b, orig, dir, &t);
|
||||
}
|
||||
|
||||
static inline bool bounds_intersects_line(const struct bounds *b,
|
||||
const struct vec3 *p1, const struct vec3 *p2)
|
||||
const struct vec3 *p1,
|
||||
const struct vec3 *p2)
|
||||
{
|
||||
float t;
|
||||
return bounds_intersection_line(b, p1, p2, &t);
|
||||
|
|
|
|||
|
|
@ -25,90 +25,103 @@ extern "C" {
|
|||
|
||||
EXPORT const char *device_get_name(void);
|
||||
EXPORT int device_get_type(void);
|
||||
EXPORT bool device_enum_adapters(
|
||||
bool (*callback)(void *param, const char *name, uint32_t id),
|
||||
void *param);
|
||||
EXPORT bool device_enum_adapters(bool (*callback)(void *param, const char *name,
|
||||
uint32_t id),
|
||||
void *param);
|
||||
EXPORT const char *device_preprocessor_name(void);
|
||||
EXPORT int device_create(gs_device_t **device, uint32_t adapter);
|
||||
EXPORT void device_destroy(gs_device_t *device);
|
||||
EXPORT void device_enter_context(gs_device_t *device);
|
||||
EXPORT void device_leave_context(gs_device_t *device);
|
||||
EXPORT void *device_get_device_obj(gs_device_t *device);
|
||||
EXPORT gs_swapchain_t *device_swapchain_create(gs_device_t *device,
|
||||
const struct gs_init_data *data);
|
||||
const struct gs_init_data *data);
|
||||
EXPORT void device_resize(gs_device_t *device, uint32_t x, uint32_t y);
|
||||
EXPORT void device_get_size(const gs_device_t *device, uint32_t *x, uint32_t *y);
|
||||
EXPORT void device_get_size(const gs_device_t *device, uint32_t *x,
|
||||
uint32_t *y);
|
||||
EXPORT uint32_t device_get_width(const gs_device_t *device);
|
||||
EXPORT uint32_t device_get_height(const gs_device_t *device);
|
||||
EXPORT gs_texture_t *device_texture_create(gs_device_t *device, uint32_t width,
|
||||
uint32_t height, enum gs_color_format color_format,
|
||||
uint32_t levels, const uint8_t **data, uint32_t flags);
|
||||
EXPORT gs_texture_t *device_cubetexture_create(gs_device_t *device,
|
||||
uint32_t size, enum gs_color_format color_format,
|
||||
uint32_t levels, const uint8_t **data, uint32_t flags);
|
||||
EXPORT gs_texture_t *device_voltexture_create(gs_device_t *device,
|
||||
uint32_t width, uint32_t height, uint32_t depth,
|
||||
enum gs_color_format color_format, uint32_t levels,
|
||||
const uint8_t **data, uint32_t flags);
|
||||
EXPORT gs_texture_t *
|
||||
device_texture_create(gs_device_t *device, uint32_t width, uint32_t height,
|
||||
enum gs_color_format color_format, uint32_t levels,
|
||||
const uint8_t **data, uint32_t flags);
|
||||
EXPORT gs_texture_t *
|
||||
device_cubetexture_create(gs_device_t *device, uint32_t size,
|
||||
enum gs_color_format color_format, uint32_t levels,
|
||||
const uint8_t **data, uint32_t flags);
|
||||
EXPORT gs_texture_t *
|
||||
device_voltexture_create(gs_device_t *device, uint32_t width, uint32_t height,
|
||||
uint32_t depth, enum gs_color_format color_format,
|
||||
uint32_t levels, const uint8_t **data, uint32_t flags);
|
||||
EXPORT gs_zstencil_t *device_zstencil_create(gs_device_t *device,
|
||||
uint32_t width, uint32_t height,
|
||||
enum gs_zstencil_format format);
|
||||
EXPORT gs_stagesurf_t *device_stagesurface_create(gs_device_t *device,
|
||||
uint32_t width, uint32_t height,
|
||||
enum gs_color_format color_format);
|
||||
EXPORT gs_samplerstate_t *device_samplerstate_create(gs_device_t *device,
|
||||
const struct gs_sampler_info *info);
|
||||
uint32_t width, uint32_t height,
|
||||
enum gs_zstencil_format format);
|
||||
EXPORT gs_stagesurf_t *
|
||||
device_stagesurface_create(gs_device_t *device, uint32_t width, uint32_t height,
|
||||
enum gs_color_format color_format);
|
||||
EXPORT gs_samplerstate_t *
|
||||
device_samplerstate_create(gs_device_t *device,
|
||||
const struct gs_sampler_info *info);
|
||||
EXPORT gs_shader_t *device_vertexshader_create(gs_device_t *device,
|
||||
const char *shader, const char *file,
|
||||
char **error_string);
|
||||
const char *shader,
|
||||
const char *file,
|
||||
char **error_string);
|
||||
EXPORT gs_shader_t *device_pixelshader_create(gs_device_t *device,
|
||||
const char *shader, const char *file,
|
||||
char **error_string);
|
||||
const char *shader,
|
||||
const char *file,
|
||||
char **error_string);
|
||||
EXPORT gs_vertbuffer_t *device_vertexbuffer_create(gs_device_t *device,
|
||||
struct gs_vb_data *data, uint32_t flags);
|
||||
struct gs_vb_data *data,
|
||||
uint32_t flags);
|
||||
EXPORT gs_indexbuffer_t *device_indexbuffer_create(gs_device_t *device,
|
||||
enum gs_index_type type, void *indices, size_t num,
|
||||
uint32_t flags);
|
||||
EXPORT enum gs_texture_type device_get_texture_type(
|
||||
const gs_texture_t *texture);
|
||||
enum gs_index_type type,
|
||||
void *indices, size_t num,
|
||||
uint32_t flags);
|
||||
EXPORT gs_timer_t *device_timer_create(gs_device_t *device);
|
||||
EXPORT gs_timer_range_t *device_timer_range_create(gs_device_t *device);
|
||||
EXPORT enum gs_texture_type
|
||||
device_get_texture_type(const gs_texture_t *texture);
|
||||
EXPORT void device_load_vertexbuffer(gs_device_t *device,
|
||||
gs_vertbuffer_t *vertbuffer);
|
||||
gs_vertbuffer_t *vertbuffer);
|
||||
EXPORT void device_load_indexbuffer(gs_device_t *device,
|
||||
gs_indexbuffer_t *indexbuffer);
|
||||
gs_indexbuffer_t *indexbuffer);
|
||||
EXPORT void device_load_texture(gs_device_t *device, gs_texture_t *tex,
|
||||
int unit);
|
||||
int unit);
|
||||
EXPORT void device_load_samplerstate(gs_device_t *device,
|
||||
gs_samplerstate_t *samplerstate, int unit);
|
||||
gs_samplerstate_t *samplerstate, int unit);
|
||||
EXPORT void device_load_vertexshader(gs_device_t *device,
|
||||
gs_shader_t *vertshader);
|
||||
gs_shader_t *vertshader);
|
||||
EXPORT void device_load_pixelshader(gs_device_t *device,
|
||||
gs_shader_t *pixelshader);
|
||||
gs_shader_t *pixelshader);
|
||||
EXPORT void device_load_default_samplerstate(gs_device_t *device, bool b_3d,
|
||||
int unit);
|
||||
int unit);
|
||||
EXPORT gs_shader_t *device_get_vertex_shader(const gs_device_t *device);
|
||||
EXPORT gs_shader_t *device_get_pixel_shader(const gs_device_t *device);
|
||||
EXPORT gs_texture_t *device_get_render_target(const gs_device_t *device);
|
||||
EXPORT gs_zstencil_t *device_get_zstencil_target(const gs_device_t *device);
|
||||
EXPORT void device_set_render_target(gs_device_t *device, gs_texture_t *tex,
|
||||
gs_zstencil_t *zstencil);
|
||||
gs_zstencil_t *zstencil);
|
||||
EXPORT void device_set_cube_render_target(gs_device_t *device,
|
||||
gs_texture_t *cubetex,
|
||||
int side, gs_zstencil_t *zstencil);
|
||||
gs_texture_t *cubetex, int side,
|
||||
gs_zstencil_t *zstencil);
|
||||
EXPORT void device_copy_texture(gs_device_t *device, gs_texture_t *dst,
|
||||
gs_texture_t *src);
|
||||
EXPORT void device_copy_texture_region(gs_device_t *device,
|
||||
gs_texture_t *dst, uint32_t dst_x, uint32_t dst_y,
|
||||
gs_texture_t *src, uint32_t src_x, uint32_t src_y,
|
||||
uint32_t src_w, uint32_t src_h);
|
||||
gs_texture_t *src);
|
||||
EXPORT void device_copy_texture_region(gs_device_t *device, gs_texture_t *dst,
|
||||
uint32_t dst_x, uint32_t dst_y,
|
||||
gs_texture_t *src, uint32_t src_x,
|
||||
uint32_t src_y, uint32_t src_w,
|
||||
uint32_t src_h);
|
||||
EXPORT void device_stage_texture(gs_device_t *device, gs_stagesurf_t *dst,
|
||||
gs_texture_t *src);
|
||||
gs_texture_t *src);
|
||||
EXPORT void device_begin_scene(gs_device_t *device);
|
||||
EXPORT void device_draw(gs_device_t *device, enum gs_draw_mode draw_mode,
|
||||
uint32_t start_vert, uint32_t num_verts);
|
||||
uint32_t start_vert, uint32_t num_verts);
|
||||
EXPORT void device_end_scene(gs_device_t *device);
|
||||
EXPORT void device_load_swapchain(gs_device_t *device,
|
||||
gs_swapchain_t *swapchain);
|
||||
gs_swapchain_t *swapchain);
|
||||
EXPORT void device_clear(gs_device_t *device, uint32_t clear_flags,
|
||||
const struct vec4 *color, float depth, uint8_t stencil);
|
||||
const struct vec4 *color, float depth,
|
||||
uint8_t stencil);
|
||||
EXPORT void device_present(gs_device_t *device);
|
||||
EXPORT void device_flush(gs_device_t *device);
|
||||
EXPORT void device_set_cull_mode(gs_device_t *device, enum gs_cull_mode mode);
|
||||
|
|
@ -118,32 +131,37 @@ EXPORT void device_enable_depth_test(gs_device_t *device, bool enable);
|
|||
EXPORT void device_enable_stencil_test(gs_device_t *device, bool enable);
|
||||
EXPORT void device_enable_stencil_write(gs_device_t *device, bool enable);
|
||||
EXPORT void device_enable_color(gs_device_t *device, bool red, bool green,
|
||||
bool blue, bool alpha);
|
||||
bool blue, bool alpha);
|
||||
EXPORT void device_blend_function(gs_device_t *device, enum gs_blend_type src,
|
||||
enum gs_blend_type dest);
|
||||
enum gs_blend_type dest);
|
||||
EXPORT void device_blend_function_separate(gs_device_t *device,
|
||||
enum gs_blend_type src_c, enum gs_blend_type dest_c,
|
||||
enum gs_blend_type src_a, enum gs_blend_type dest_a);
|
||||
enum gs_blend_type src_c,
|
||||
enum gs_blend_type dest_c,
|
||||
enum gs_blend_type src_a,
|
||||
enum gs_blend_type dest_a);
|
||||
EXPORT void device_depth_function(gs_device_t *device, enum gs_depth_test test);
|
||||
EXPORT void device_stencil_function(gs_device_t *device,
|
||||
enum gs_stencil_side side, enum gs_depth_test test);
|
||||
enum gs_stencil_side side,
|
||||
enum gs_depth_test test);
|
||||
EXPORT void device_stencil_op(gs_device_t *device, enum gs_stencil_side side,
|
||||
enum gs_stencil_op_type fail, enum gs_stencil_op_type zfail,
|
||||
enum gs_stencil_op_type zpass);
|
||||
enum gs_stencil_op_type fail,
|
||||
enum gs_stencil_op_type zfail,
|
||||
enum gs_stencil_op_type zpass);
|
||||
EXPORT void device_set_viewport(gs_device_t *device, int x, int y, int width,
|
||||
int height);
|
||||
int height);
|
||||
EXPORT void device_get_viewport(const gs_device_t *device,
|
||||
struct gs_rect *rect);
|
||||
struct gs_rect *rect);
|
||||
EXPORT void device_set_scissor_rect(gs_device_t *device,
|
||||
const struct gs_rect *rect);
|
||||
const struct gs_rect *rect);
|
||||
EXPORT void device_ortho(gs_device_t *device, float left, float right,
|
||||
float top, float bottom, float znear, float zfar);
|
||||
float top, float bottom, float znear, float zfar);
|
||||
EXPORT void device_frustum(gs_device_t *device, float left, float right,
|
||||
float top, float bottom, float znear, float zfar);
|
||||
float top, float bottom, float znear, float zfar);
|
||||
EXPORT void device_projection_push(gs_device_t *device);
|
||||
EXPORT void device_projection_pop(gs_device_t *device);
|
||||
EXPORT void device_debug_marker_begin(gs_device_t *device,
|
||||
const char *markername, const float color[4]);
|
||||
const char *markername,
|
||||
const float color[4]);
|
||||
EXPORT void device_debug_marker_end(gs_device_t *device);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -67,9 +67,9 @@ static inline void ep_var_free(struct ep_var *epv)
|
|||
/* effect parser param data */
|
||||
|
||||
struct ep_param {
|
||||
char *type, *name;
|
||||
DARRAY(uint8_t) default_val;
|
||||
DARRAY(char*) properties;
|
||||
char *type, *name;
|
||||
DARRAY(uint8_t) default_val;
|
||||
DARRAY(char *) properties;
|
||||
struct gs_effect_param *param;
|
||||
bool is_const, is_property, is_uniform, is_texture, written;
|
||||
int writeorder, array_count;
|
||||
|
|
@ -78,18 +78,18 @@ struct ep_param {
|
|||
|
||||
extern void ep_param_writevar(struct dstr *dst, struct darray *use_params);
|
||||
|
||||
static inline void ep_param_init(struct ep_param *epp,
|
||||
char *type, char *name,
|
||||
bool is_property, bool is_const, bool is_uniform)
|
||||
static inline void ep_param_init(struct ep_param *epp, char *type, char *name,
|
||||
bool is_property, bool is_const,
|
||||
bool is_uniform)
|
||||
{
|
||||
epp->type = type;
|
||||
epp->name = name;
|
||||
epp->type = type;
|
||||
epp->name = name;
|
||||
epp->is_property = is_property;
|
||||
epp->is_const = is_const;
|
||||
epp->is_uniform = is_uniform;
|
||||
epp->is_texture = (astrcmp_n(epp->type, "texture", 7) == 0);
|
||||
epp->written = false;
|
||||
epp->writeorder = false;
|
||||
epp->is_const = is_const;
|
||||
epp->is_uniform = is_uniform;
|
||||
epp->is_texture = (astrcmp_n(epp->type, "texture", 7) == 0);
|
||||
epp->written = false;
|
||||
epp->writeorder = false;
|
||||
epp->array_count = 0;
|
||||
da_init(epp->default_val);
|
||||
da_init(epp->properties);
|
||||
|
|
@ -136,7 +136,7 @@ static inline void ep_struct_free(struct ep_struct *eps)
|
|||
|
||||
bfree(eps->name);
|
||||
for (i = 0; i < eps->vars.num; i++)
|
||||
ep_var_free(eps->vars.array+i);
|
||||
ep_var_free(eps->vars.array + i);
|
||||
da_free(eps->vars);
|
||||
}
|
||||
|
||||
|
|
@ -145,8 +145,8 @@ static inline void ep_struct_free(struct ep_struct *eps)
|
|||
|
||||
struct ep_sampler {
|
||||
char *name;
|
||||
DARRAY(char*) states;
|
||||
DARRAY(char*) values;
|
||||
DARRAY(char *) states;
|
||||
DARRAY(char *) values;
|
||||
|
||||
bool written;
|
||||
};
|
||||
|
|
@ -210,7 +210,7 @@ static inline void ep_technique_free(struct ep_technique *ept)
|
|||
size_t i;
|
||||
|
||||
for (i = 0; i < ept->passes.num; i++)
|
||||
ep_pass_free(ept->passes.array+i);
|
||||
ep_pass_free(ept->passes.array + i);
|
||||
|
||||
bfree(ept->name);
|
||||
da_free(ept->passes);
|
||||
|
|
@ -223,18 +223,17 @@ struct ep_func {
|
|||
char *name, *ret_type, *mapping;
|
||||
struct dstr contents;
|
||||
DARRAY(struct ep_var) param_vars;
|
||||
DARRAY(const char*) func_deps;
|
||||
DARRAY(const char*) struct_deps;
|
||||
DARRAY(const char*) param_deps;
|
||||
DARRAY(const char*) sampler_deps;
|
||||
DARRAY(const char *) func_deps;
|
||||
DARRAY(const char *) struct_deps;
|
||||
DARRAY(const char *) param_deps;
|
||||
DARRAY(const char *) sampler_deps;
|
||||
bool written;
|
||||
};
|
||||
|
||||
static inline void ep_func_init(struct ep_func *epf, char *ret_type,
|
||||
char *name)
|
||||
static inline void ep_func_init(struct ep_func *epf, char *ret_type, char *name)
|
||||
{
|
||||
memset(epf, 0, sizeof(struct ep_func));
|
||||
epf->name = name;
|
||||
epf->name = name;
|
||||
epf->ret_type = ret_type;
|
||||
}
|
||||
|
||||
|
|
@ -242,7 +241,7 @@ static inline void ep_func_free(struct ep_func *epf)
|
|||
{
|
||||
size_t i;
|
||||
for (i = 0; i < epf->param_vars.num; i++)
|
||||
ep_var_free(epf->param_vars.array+i);
|
||||
ep_var_free(epf->param_vars.array + i);
|
||||
|
||||
bfree(epf->name);
|
||||
bfree(epf->ret_type);
|
||||
|
|
@ -260,10 +259,10 @@ static inline void ep_func_free(struct ep_func *epf)
|
|||
struct effect_parser {
|
||||
gs_effect_t *effect;
|
||||
|
||||
DARRAY(struct ep_param) params;
|
||||
DARRAY(struct ep_struct) structs;
|
||||
DARRAY(struct ep_func) funcs;
|
||||
DARRAY(struct ep_sampler) samplers;
|
||||
DARRAY(struct ep_param) params;
|
||||
DARRAY(struct ep_struct) structs;
|
||||
DARRAY(struct ep_func) funcs;
|
||||
DARRAY(struct ep_sampler) samplers;
|
||||
DARRAY(struct ep_technique) techniques;
|
||||
|
||||
/* internal vars */
|
||||
|
|
@ -291,7 +290,7 @@ static inline void ep_init(struct effect_parser *ep)
|
|||
extern void ep_free(struct effect_parser *ep);
|
||||
|
||||
extern bool ep_parse(struct effect_parser *ep, gs_effect_t *effect,
|
||||
const char *effect_string, const char *file);
|
||||
const char *effect_string, const char *file);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,12 +36,13 @@ void gs_effect_destroy(gs_effect_t *effect)
|
|||
}
|
||||
|
||||
gs_technique_t *gs_effect_get_technique(const gs_effect_t *effect,
|
||||
const char *name)
|
||||
const char *name)
|
||||
{
|
||||
if (!effect) return NULL;
|
||||
if (!effect)
|
||||
return NULL;
|
||||
|
||||
for (size_t i = 0; i < effect->techniques.num; i++) {
|
||||
struct gs_effect_technique *tech = effect->techniques.array+i;
|
||||
struct gs_effect_technique *tech = effect->techniques.array + i;
|
||||
if (strcmp(tech->name, name) == 0)
|
||||
return tech;
|
||||
}
|
||||
|
|
@ -51,7 +52,8 @@ gs_technique_t *gs_effect_get_technique(const gs_effect_t *effect,
|
|||
|
||||
gs_technique_t *gs_effect_get_current_technique(const gs_effect_t *effect)
|
||||
{
|
||||
if (!effect) return NULL;
|
||||
if (!effect)
|
||||
return NULL;
|
||||
|
||||
return effect->cur_technique;
|
||||
}
|
||||
|
|
@ -67,14 +69,16 @@ bool gs_effect_loop(gs_effect_t *effect, const char *name)
|
|||
|
||||
if (!!gs_get_effect()) {
|
||||
blog(LOG_WARNING, "gs_effect_loop: An effect is "
|
||||
"already active");
|
||||
"already active");
|
||||
return false;
|
||||
}
|
||||
|
||||
tech = gs_effect_get_technique(effect, name);
|
||||
if (!tech) {
|
||||
blog(LOG_WARNING, "gs_effect_loop: Technique '%s' "
|
||||
"not found.", name);
|
||||
blog(LOG_WARNING,
|
||||
"gs_effect_loop: Technique '%s' "
|
||||
"not found.",
|
||||
name);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -86,7 +90,7 @@ bool gs_effect_loop(gs_effect_t *effect, const char *name)
|
|||
}
|
||||
|
||||
if (!gs_technique_begin_pass(effect->cur_technique,
|
||||
effect->loop_pass++)) {
|
||||
effect->loop_pass++)) {
|
||||
gs_technique_end(effect->cur_technique);
|
||||
effect->looping = false;
|
||||
effect->loop_pass = 0;
|
||||
|
|
@ -98,7 +102,8 @@ bool gs_effect_loop(gs_effect_t *effect, const char *name)
|
|||
|
||||
size_t gs_technique_begin(gs_technique_t *tech)
|
||||
{
|
||||
if (!tech) return 0;
|
||||
if (!tech)
|
||||
return 0;
|
||||
|
||||
tech->effect->cur_technique = tech;
|
||||
tech->effect->graphics->cur_effect = tech->effect;
|
||||
|
|
@ -108,7 +113,8 @@ size_t gs_technique_begin(gs_technique_t *tech)
|
|||
|
||||
void gs_technique_end(gs_technique_t *tech)
|
||||
{
|
||||
if (!tech) return;
|
||||
if (!tech)
|
||||
return;
|
||||
|
||||
struct gs_effect *effect = tech->effect;
|
||||
struct gs_effect_param *params = effect->params.array;
|
||||
|
|
@ -121,7 +127,7 @@ void gs_technique_end(gs_technique_t *tech)
|
|||
tech->effect->graphics->cur_effect = NULL;
|
||||
|
||||
for (i = 0; i < effect->params.num; i++) {
|
||||
struct gs_effect_param *param = params+i;
|
||||
struct gs_effect_param *param = params + i;
|
||||
|
||||
da_free(param->cur_val);
|
||||
param->changed = false;
|
||||
|
|
@ -145,12 +151,13 @@ static void upload_shader_params(struct darray *pass_params, bool changed_only)
|
|||
size_t i;
|
||||
|
||||
for (i = 0; i < pass_params->num; i++) {
|
||||
struct pass_shaderparam *param = params+i;
|
||||
struct pass_shaderparam *param = params + i;
|
||||
struct gs_effect_param *eparam = param->eparam;
|
||||
gs_sparam_t *sparam = param->sparam;
|
||||
|
||||
if (eparam->next_sampler)
|
||||
gs_shader_set_next_sampler(sparam, eparam->next_sampler);
|
||||
gs_shader_set_next_sampler(sparam,
|
||||
eparam->next_sampler);
|
||||
|
||||
if (changed_only && !eparam->changed)
|
||||
continue;
|
||||
|
|
@ -163,12 +170,12 @@ static void upload_shader_params(struct darray *pass_params, bool changed_only)
|
|||
}
|
||||
|
||||
gs_shader_set_val(sparam, eparam->cur_val.array,
|
||||
eparam->cur_val.num);
|
||||
eparam->cur_val.num);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void upload_parameters(struct gs_effect *effect,
|
||||
bool changed_only)
|
||||
bool changed_only)
|
||||
{
|
||||
struct darray *vshader_params, *pshader_params;
|
||||
|
||||
|
|
@ -184,7 +191,7 @@ static inline void upload_parameters(struct gs_effect *effect,
|
|||
reset_params(pshader_params);
|
||||
}
|
||||
|
||||
void gs_effect_update_params(gs_effect_t *effect)
|
||||
void gs_effect_update_params(gs_effect_t *effect)
|
||||
{
|
||||
if (effect)
|
||||
upload_parameters(effect, true);
|
||||
|
|
@ -199,7 +206,7 @@ bool gs_technique_begin_pass(gs_technique_t *tech, size_t idx)
|
|||
return false;
|
||||
|
||||
passes = tech->passes.array;
|
||||
cur_pass = passes+idx;
|
||||
cur_pass = passes + idx;
|
||||
|
||||
tech->effect->cur_pass = cur_pass;
|
||||
gs_load_vertexshader(cur_pass->vertshader);
|
||||
|
|
@ -209,14 +216,13 @@ bool gs_technique_begin_pass(gs_technique_t *tech, size_t idx)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool gs_technique_begin_pass_by_name(gs_technique_t *tech,
|
||||
const char *name)
|
||||
bool gs_technique_begin_pass_by_name(gs_technique_t *tech, const char *name)
|
||||
{
|
||||
if (!tech)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < tech->passes.num; i++) {
|
||||
struct gs_effect_pass *pass = tech->passes.array+i;
|
||||
struct gs_effect_pass *pass = tech->passes.array + i;
|
||||
if (strcmp(pass->name, name) == 0) {
|
||||
gs_technique_begin_pass(tech, i);
|
||||
return true;
|
||||
|
|
@ -231,7 +237,7 @@ static inline void clear_tex_params(struct darray *in_params)
|
|||
struct pass_shaderparam *params = in_params->array;
|
||||
|
||||
for (size_t i = 0; i < in_params->num; i++) {
|
||||
struct pass_shaderparam *param = params+i;
|
||||
struct pass_shaderparam *param = params + i;
|
||||
struct gs_shader_param_info info;
|
||||
|
||||
gs_shader_get_param_info(param->sparam, &info);
|
||||
|
|
@ -242,7 +248,8 @@ static inline void clear_tex_params(struct darray *in_params)
|
|||
|
||||
void gs_technique_end_pass(gs_technique_t *tech)
|
||||
{
|
||||
if (!tech) return;
|
||||
if (!tech)
|
||||
return;
|
||||
|
||||
struct gs_effect_pass *pass = tech->effect->cur_pass;
|
||||
if (!pass)
|
||||
|
|
@ -260,24 +267,26 @@ size_t gs_effect_get_num_params(const gs_effect_t *effect)
|
|||
|
||||
gs_eparam_t *gs_effect_get_param_by_idx(const gs_effect_t *effect, size_t param)
|
||||
{
|
||||
if (!effect) return NULL;
|
||||
if (!effect)
|
||||
return NULL;
|
||||
|
||||
struct gs_effect_param *params = effect->params.array;
|
||||
if (param >= effect->params.num)
|
||||
return NULL;
|
||||
|
||||
return params+param;
|
||||
return params + param;
|
||||
}
|
||||
|
||||
gs_eparam_t *gs_effect_get_param_by_name(const gs_effect_t *effect,
|
||||
const char *name)
|
||||
const char *name)
|
||||
{
|
||||
if (!effect) return NULL;
|
||||
if (!effect)
|
||||
return NULL;
|
||||
|
||||
struct gs_effect_param *params = effect->params.array;
|
||||
|
||||
for (size_t i = 0; i < effect->params.num; i++) {
|
||||
struct gs_effect_param *param = params+i;
|
||||
struct gs_effect_param *param = params + i;
|
||||
|
||||
if (strcmp(param->name, name) == 0)
|
||||
return param;
|
||||
|
|
@ -292,10 +301,11 @@ size_t gs_param_get_num_annotations(const gs_eparam_t *param)
|
|||
}
|
||||
|
||||
gs_eparam_t *gs_param_get_annotation_by_idx(const gs_eparam_t *param,
|
||||
size_t annotation)
|
||||
size_t annotation)
|
||||
{
|
||||
if (!param) return NULL;
|
||||
|
||||
if (!param)
|
||||
return NULL;
|
||||
|
||||
struct gs_effect_param *params = param->annotations.array;
|
||||
if (annotation > param->annotations.num)
|
||||
return NULL;
|
||||
|
|
@ -304,9 +314,10 @@ gs_eparam_t *gs_param_get_annotation_by_idx(const gs_eparam_t *param,
|
|||
}
|
||||
|
||||
gs_eparam_t *gs_param_get_annotation_by_name(const gs_eparam_t *param,
|
||||
const char *name)
|
||||
const char *name)
|
||||
{
|
||||
if (!param) return NULL;
|
||||
if (!param)
|
||||
return NULL;
|
||||
struct gs_effect_param *params = param->annotations.array;
|
||||
|
||||
for (size_t i = 0; i < param->annotations.num; i++) {
|
||||
|
|
@ -318,9 +329,10 @@ gs_eparam_t *gs_param_get_annotation_by_name(const gs_eparam_t *param,
|
|||
}
|
||||
|
||||
gs_epass_t *gs_technique_get_pass_by_idx(const gs_technique_t *technique,
|
||||
size_t pass)
|
||||
size_t pass)
|
||||
{
|
||||
if (!technique) return NULL;
|
||||
if (!technique)
|
||||
return NULL;
|
||||
struct gs_effect_pass *passes = technique->passes.array;
|
||||
|
||||
if (pass > technique->passes.num)
|
||||
|
|
@ -330,9 +342,10 @@ gs_epass_t *gs_technique_get_pass_by_idx(const gs_technique_t *technique,
|
|||
}
|
||||
|
||||
gs_epass_t *gs_technique_get_pass_by_name(const gs_technique_t *technique,
|
||||
const char *name)
|
||||
const char *name)
|
||||
{
|
||||
if (!technique) return NULL;
|
||||
if (!technique)
|
||||
return NULL;
|
||||
struct gs_effect_pass *passes = technique->passes.array;
|
||||
|
||||
for (size_t i = 0; i < technique->passes.num; i++) {
|
||||
|
|
@ -354,7 +367,7 @@ gs_eparam_t *gs_effect_get_world_matrix(const gs_effect_t *effect)
|
|||
}
|
||||
|
||||
void gs_effect_get_param_info(const gs_eparam_t *param,
|
||||
struct gs_effect_param_info *info)
|
||||
struct gs_effect_param_info *info)
|
||||
{
|
||||
if (!param)
|
||||
return;
|
||||
|
|
@ -363,8 +376,8 @@ void gs_effect_get_param_info(const gs_eparam_t *param,
|
|||
info->type = param->type;
|
||||
}
|
||||
|
||||
static inline void effect_setval_inline(gs_eparam_t *param,
|
||||
const void *data, size_t size)
|
||||
static inline void effect_setval_inline(gs_eparam_t *param, const void *data,
|
||||
size_t size)
|
||||
{
|
||||
bool size_changed;
|
||||
|
||||
|
|
@ -390,10 +403,10 @@ static inline void effect_setval_inline(gs_eparam_t *param,
|
|||
}
|
||||
|
||||
#ifndef min
|
||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
static inline void effect_getval_inline(gs_eparam_t *param, void *data,
|
||||
size_t size)
|
||||
size_t size)
|
||||
{
|
||||
if (!param) {
|
||||
blog(LOG_ERROR, "effect_getval_inline: invalid param");
|
||||
|
|
@ -411,7 +424,7 @@ static inline void effect_getval_inline(gs_eparam_t *param, void *data,
|
|||
}
|
||||
|
||||
static inline void effect_getdefaultval_inline(gs_eparam_t *param, void *data,
|
||||
size_t size)
|
||||
size_t size)
|
||||
{
|
||||
if (!param) {
|
||||
blog(LOG_ERROR, "effect_getdefaultval_inline: invalid param");
|
||||
|
|
@ -473,7 +486,7 @@ void gs_effect_set_color(gs_eparam_t *param, uint32_t argb)
|
|||
|
||||
void gs_effect_set_texture(gs_eparam_t *param, gs_texture_t *val)
|
||||
{
|
||||
effect_setval_inline(param, &val, sizeof(gs_texture_t*));
|
||||
effect_setval_inline(param, &val, sizeof(gs_texture_t *));
|
||||
}
|
||||
|
||||
void gs_effect_set_val(gs_eparam_t *param, const void *val, size_t size)
|
||||
|
|
@ -491,7 +504,7 @@ void *gs_effect_get_val(gs_eparam_t *param)
|
|||
void *data;
|
||||
|
||||
if (size)
|
||||
data = (void*)bzalloc(size);
|
||||
data = (void *)bzalloc(size);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
|
|
@ -515,7 +528,7 @@ void *gs_effect_get_default_val(gs_eparam_t *param)
|
|||
void *data;
|
||||
|
||||
if (size)
|
||||
data = (void*)bzalloc(size);
|
||||
data = (void *)bzalloc(size);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
|
|
@ -532,7 +545,7 @@ size_t gs_effect_get_default_val_size(gs_eparam_t *param)
|
|||
void gs_effect_set_default(gs_eparam_t *param)
|
||||
{
|
||||
effect_setval_inline(param, param->default_val.array,
|
||||
param->default_val.num);
|
||||
param->default_val.num);
|
||||
}
|
||||
|
||||
void gs_effect_set_next_sampler(gs_eparam_t *param, gs_samplerstate_t *sampler)
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ static inline void effect_param_free(struct gs_effect_param *param)
|
|||
}
|
||||
|
||||
EXPORT void effect_param_parse_property(gs_eparam_t *param,
|
||||
const char *property);
|
||||
const char *property);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
|
|
@ -139,7 +139,7 @@ static inline void effect_technique_free(struct gs_effect_technique *t)
|
|||
{
|
||||
size_t i;
|
||||
for (i = 0; i < t->passes.num; i++)
|
||||
effect_pass_free(t->passes.array+i);
|
||||
effect_pass_free(t->passes.array + i);
|
||||
|
||||
da_free(t->passes);
|
||||
bfree(t->name);
|
||||
|
|
@ -176,9 +176,9 @@ static inline void effect_free(gs_effect_t *effect)
|
|||
{
|
||||
size_t i;
|
||||
for (i = 0; i < effect->params.num; i++)
|
||||
effect_param_free(effect->params.array+i);
|
||||
effect_param_free(effect->params.array + i);
|
||||
for (i = 0; i < effect->techniques.num; i++)
|
||||
effect_technique_free(effect->techniques.array+i);
|
||||
effect_technique_free(effect->techniques.array + i);
|
||||
|
||||
da_free(effect->params);
|
||||
da_free(effect->techniques);
|
||||
|
|
@ -191,8 +191,9 @@ static inline void effect_free(gs_effect_t *effect)
|
|||
|
||||
EXPORT void effect_upload_params(gs_effect_t *effect, bool changed_only);
|
||||
EXPORT void effect_upload_shader_params(gs_effect_t *effect,
|
||||
gs_shader_t *shader, struct darray *pass_params,
|
||||
bool changed_only);
|
||||
gs_shader_t *shader,
|
||||
struct darray *pass_params,
|
||||
bool changed_only);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,42 +7,44 @@
|
|||
#include "../obs-ffmpeg-compat.h"
|
||||
|
||||
struct ffmpeg_image {
|
||||
const char *file;
|
||||
AVFormatContext *fmt_ctx;
|
||||
AVCodecContext *decoder_ctx;
|
||||
AVCodec *decoder;
|
||||
AVStream *stream;
|
||||
int stream_idx;
|
||||
const char *file;
|
||||
AVFormatContext *fmt_ctx;
|
||||
AVCodecContext *decoder_ctx;
|
||||
AVCodec *decoder;
|
||||
AVStream *stream;
|
||||
int stream_idx;
|
||||
|
||||
int cx, cy;
|
||||
int cx, cy;
|
||||
enum AVPixelFormat format;
|
||||
};
|
||||
|
||||
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);
|
||||
int ret = av_find_best_stream(info->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));
|
||||
info->file, av_err2str(ret));
|
||||
return false;
|
||||
}
|
||||
|
||||
info->stream_idx = ret;
|
||||
info->stream = info->fmt_ctx->streams[ret];
|
||||
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);
|
||||
info->decoder = avcodec_find_decoder(info->decoder_ctx->codec_id);
|
||||
|
||||
if (!info->decoder) {
|
||||
blog(LOG_WARNING, "Failed to find decoder for file '%s'",
|
||||
info->file);
|
||||
info->file);
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = avcodec_open2(info->decoder_ctx, info->decoder, NULL);
|
||||
if (ret < 0) {
|
||||
blog(LOG_WARNING, "Failed to open video codec for file '%s': "
|
||||
"%s", info->file, av_err2str(ret));
|
||||
blog(LOG_WARNING,
|
||||
"Failed to open video codec for file '%s': "
|
||||
"%s",
|
||||
info->file, av_err2str(ret));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -63,28 +65,30 @@ static bool ffmpeg_image_init(struct ffmpeg_image *info, const char *file)
|
|||
return false;
|
||||
|
||||
memset(info, 0, sizeof(struct ffmpeg_image));
|
||||
info->file = file;
|
||||
info->file = file;
|
||||
info->stream_idx = -1;
|
||||
|
||||
ret = avformat_open_input(&info->fmt_ctx, file, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
blog(LOG_WARNING, "Failed to open file '%s': %s",
|
||||
info->file, av_err2str(ret));
|
||||
blog(LOG_WARNING, "Failed to open file '%s': %s", info->file,
|
||||
av_err2str(ret));
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = avformat_find_stream_info(info->fmt_ctx, NULL);
|
||||
if (ret < 0) {
|
||||
blog(LOG_WARNING, "Could not find stream info for file '%s':"
|
||||
" %s", info->file, av_err2str(ret));
|
||||
blog(LOG_WARNING,
|
||||
"Could not find stream info for file '%s':"
|
||||
" %s",
|
||||
info->file, av_err2str(ret));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!ffmpeg_image_open_decoder_context(info))
|
||||
goto fail;
|
||||
|
||||
info->cx = info->decoder_ctx->width;
|
||||
info->cy = info->decoder_ctx->height;
|
||||
info->cx = info->decoder_ctx->width;
|
||||
info->cy = info->decoder_ctx->height;
|
||||
info->format = info->decoder_ctx->pix_fmt;
|
||||
return true;
|
||||
|
||||
|
|
@ -94,18 +98,20 @@ fail:
|
|||
}
|
||||
|
||||
static bool ffmpeg_image_reformat_frame(struct ffmpeg_image *info,
|
||||
AVFrame *frame, uint8_t *out, int linesize)
|
||||
AVFrame *frame, uint8_t *out,
|
||||
int linesize)
|
||||
{
|
||||
struct SwsContext *sws_ctx = NULL;
|
||||
int ret = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (info->format == AV_PIX_FMT_RGBA ||
|
||||
info->format == AV_PIX_FMT_BGRA ||
|
||||
info->format == AV_PIX_FMT_BGR0) {
|
||||
|
||||
if (linesize != frame->linesize[0]) {
|
||||
int min_line = linesize < frame->linesize[0] ?
|
||||
linesize : frame->linesize[0];
|
||||
int min_line = linesize < frame->linesize[0]
|
||||
? linesize
|
||||
: frame->linesize[0];
|
||||
|
||||
for (int y = 0; y < info->cy; y++)
|
||||
memcpy(out + y * linesize,
|
||||
|
|
@ -117,21 +123,23 @@ static bool ffmpeg_image_reformat_frame(struct ffmpeg_image *info,
|
|||
|
||||
} else {
|
||||
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, AV_PIX_FMT_BGRA,
|
||||
SWS_POINT, NULL, NULL, NULL);
|
||||
if (!sws_ctx) {
|
||||
blog(LOG_WARNING, "Failed to create scale context "
|
||||
"for '%s'", info->file);
|
||||
blog(LOG_WARNING,
|
||||
"Failed to create scale context "
|
||||
"for '%s'",
|
||||
info->file);
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = sws_scale(sws_ctx, (const uint8_t *const*)frame->data,
|
||||
ret = sws_scale(sws_ctx, (const uint8_t *const *)frame->data,
|
||||
frame->linesize, 0, info->cy, &out, &linesize);
|
||||
sws_freeContext(sws_ctx);
|
||||
|
||||
if (ret < 0) {
|
||||
blog(LOG_WARNING, "sws_scale failed for '%s': %s",
|
||||
info->file, av_err2str(ret));
|
||||
info->file, av_err2str(ret));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -142,24 +150,24 @@ static bool ffmpeg_image_reformat_frame(struct ffmpeg_image *info,
|
|||
}
|
||||
|
||||
static bool ffmpeg_image_decode(struct ffmpeg_image *info, uint8_t *out,
|
||||
int linesize)
|
||||
int linesize)
|
||||
{
|
||||
AVPacket packet = {0};
|
||||
bool success = false;
|
||||
AVFrame *frame = av_frame_alloc();
|
||||
int got_frame = 0;
|
||||
int ret;
|
||||
AVPacket packet = {0};
|
||||
bool success = false;
|
||||
AVFrame *frame = av_frame_alloc();
|
||||
int got_frame = 0;
|
||||
int ret;
|
||||
|
||||
if (!frame) {
|
||||
blog(LOG_WARNING, "Failed to create frame data for '%s'",
|
||||
info->file);
|
||||
info->file);
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = av_read_frame(info->fmt_ctx, &packet);
|
||||
if (ret < 0) {
|
||||
blog(LOG_WARNING, "Failed to read image frame from '%s': %s",
|
||||
info->file, av_err2str(ret));
|
||||
info->file, av_err2str(ret));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
@ -175,11 +183,11 @@ static bool ffmpeg_image_decode(struct ffmpeg_image *info, uint8_t *out,
|
|||
ret = 0;
|
||||
#else
|
||||
ret = avcodec_decode_video2(info->decoder_ctx, frame,
|
||||
&got_frame, &packet);
|
||||
&got_frame, &packet);
|
||||
#endif
|
||||
if (ret < 0) {
|
||||
blog(LOG_WARNING, "Failed to decode frame for '%s': %s",
|
||||
info->file, av_err2str(ret));
|
||||
info->file, av_err2str(ret));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
|
@ -194,27 +202,30 @@ fail:
|
|||
|
||||
void gs_init_image_deps(void)
|
||||
{
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
|
||||
av_register_all();
|
||||
#endif
|
||||
}
|
||||
|
||||
void gs_free_image_deps(void)
|
||||
{
|
||||
}
|
||||
void gs_free_image_deps(void) {}
|
||||
|
||||
static inline enum gs_color_format convert_format(enum AVPixelFormat format)
|
||||
{
|
||||
switch ((int)format) {
|
||||
case AV_PIX_FMT_RGBA: return GS_RGBA;
|
||||
case AV_PIX_FMT_BGRA: return GS_BGRA;
|
||||
case AV_PIX_FMT_BGR0: return GS_BGRX;
|
||||
case AV_PIX_FMT_RGBA:
|
||||
return GS_RGBA;
|
||||
case AV_PIX_FMT_BGRA:
|
||||
return GS_BGRA;
|
||||
case AV_PIX_FMT_BGR0:
|
||||
return GS_BGRX;
|
||||
}
|
||||
|
||||
return GS_BGRX;
|
||||
}
|
||||
|
||||
uint8_t *gs_create_texture_file_data(const char *file,
|
||||
enum gs_color_format *format,
|
||||
uint32_t *cx_out, uint32_t *cy_out)
|
||||
enum gs_color_format *format,
|
||||
uint32_t *cx_out, uint32_t *cy_out)
|
||||
{
|
||||
struct ffmpeg_image image;
|
||||
uint8_t *data = NULL;
|
||||
|
|
|
|||
|
|
@ -20,23 +20,25 @@
|
|||
#include "../util/platform.h"
|
||||
#include "graphics-internal.h"
|
||||
|
||||
#define GRAPHICS_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); \
|
||||
} \
|
||||
#define GRAPHICS_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)
|
||||
|
||||
#define GRAPHICS_IMPORT_OPTIONAL(func) \
|
||||
do { \
|
||||
#define GRAPHICS_IMPORT_OPTIONAL(func) \
|
||||
do { \
|
||||
exports->func = os_dlsym(module, #func); \
|
||||
} while (false)
|
||||
|
||||
bool load_graphics_imports(struct gs_exports *exports, void *module,
|
||||
const char *module_name)
|
||||
const char *module_name)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
|
|
@ -48,6 +50,7 @@ bool load_graphics_imports(struct gs_exports *exports, void *module,
|
|||
GRAPHICS_IMPORT(device_destroy);
|
||||
GRAPHICS_IMPORT(device_enter_context);
|
||||
GRAPHICS_IMPORT(device_leave_context);
|
||||
GRAPHICS_IMPORT(device_get_device_obj);
|
||||
GRAPHICS_IMPORT(device_swapchain_create);
|
||||
GRAPHICS_IMPORT(device_resize);
|
||||
GRAPHICS_IMPORT(device_get_size);
|
||||
|
|
@ -63,6 +66,8 @@ bool load_graphics_imports(struct gs_exports *exports, void *module,
|
|||
GRAPHICS_IMPORT(device_pixelshader_create);
|
||||
GRAPHICS_IMPORT(device_vertexbuffer_create);
|
||||
GRAPHICS_IMPORT(device_indexbuffer_create);
|
||||
GRAPHICS_IMPORT(device_timer_create);
|
||||
GRAPHICS_IMPORT(device_timer_range_create);
|
||||
GRAPHICS_IMPORT(device_get_texture_type);
|
||||
GRAPHICS_IMPORT(device_load_vertexbuffer);
|
||||
GRAPHICS_IMPORT(device_load_indexbuffer);
|
||||
|
|
@ -151,6 +156,15 @@ bool load_graphics_imports(struct gs_exports *exports, void *module,
|
|||
GRAPHICS_IMPORT(gs_indexbuffer_get_num_indices);
|
||||
GRAPHICS_IMPORT(gs_indexbuffer_get_type);
|
||||
|
||||
GRAPHICS_IMPORT(gs_timer_destroy);
|
||||
GRAPHICS_IMPORT(gs_timer_begin);
|
||||
GRAPHICS_IMPORT(gs_timer_end);
|
||||
GRAPHICS_IMPORT(gs_timer_get_data);
|
||||
GRAPHICS_IMPORT(gs_timer_range_destroy);
|
||||
GRAPHICS_IMPORT(gs_timer_range_begin);
|
||||
GRAPHICS_IMPORT(gs_timer_range_end);
|
||||
GRAPHICS_IMPORT(gs_timer_range_get_data);
|
||||
|
||||
GRAPHICS_IMPORT(gs_shader_destroy);
|
||||
GRAPHICS_IMPORT(gs_shader_get_num_params);
|
||||
GRAPHICS_IMPORT(gs_shader_get_param_by_idx);
|
||||
|
|
|
|||
|
|
@ -26,162 +26,180 @@
|
|||
struct gs_exports {
|
||||
const char *(*device_get_name)(void);
|
||||
int (*device_get_type)(void);
|
||||
bool (*device_enum_adapters)(
|
||||
bool (*callback)(void*, const char*, uint32_t),
|
||||
void*);
|
||||
bool (*device_enum_adapters)(bool (*callback)(void *, const char *,
|
||||
uint32_t),
|
||||
void *);
|
||||
const char *(*device_preprocessor_name)(void);
|
||||
int (*device_create)(gs_device_t **device, uint32_t adapter);
|
||||
void (*device_destroy)(gs_device_t *device);
|
||||
void (*device_enter_context)(gs_device_t *device);
|
||||
void (*device_leave_context)(gs_device_t *device);
|
||||
gs_swapchain_t *(*device_swapchain_create)(gs_device_t *device,
|
||||
const struct gs_init_data *data);
|
||||
void *(*device_get_device_obj)(gs_device_t *device);
|
||||
gs_swapchain_t *(*device_swapchain_create)(
|
||||
gs_device_t *device, const struct gs_init_data *data);
|
||||
void (*device_resize)(gs_device_t *device, uint32_t x, uint32_t y);
|
||||
void (*device_get_size)(const gs_device_t *device,
|
||||
uint32_t *x, uint32_t *y);
|
||||
void (*device_get_size)(const gs_device_t *device, uint32_t *x,
|
||||
uint32_t *y);
|
||||
uint32_t (*device_get_width)(const gs_device_t *device);
|
||||
uint32_t (*device_get_height)(const gs_device_t *device);
|
||||
gs_texture_t *(*device_texture_create)(gs_device_t *device,
|
||||
uint32_t width, uint32_t height,
|
||||
enum gs_color_format color_format, uint32_t levels,
|
||||
const uint8_t **data, uint32_t flags);
|
||||
gs_texture_t *(*device_cubetexture_create)(gs_device_t *device,
|
||||
uint32_t size, enum gs_color_format color_format,
|
||||
uint32_t levels, const uint8_t **data, uint32_t flags);
|
||||
gs_texture_t *(*device_voltexture_create)(gs_device_t *device,
|
||||
uint32_t width, uint32_t height, uint32_t depth,
|
||||
enum gs_color_format color_format, uint32_t levels,
|
||||
const uint8_t **data, uint32_t flags);
|
||||
gs_zstencil_t *(*device_zstencil_create)(gs_device_t *device,
|
||||
uint32_t width, uint32_t height,
|
||||
enum gs_zstencil_format format);
|
||||
gs_stagesurf_t *(*device_stagesurface_create)(gs_device_t *device,
|
||||
uint32_t width, uint32_t height,
|
||||
enum gs_color_format color_format);
|
||||
gs_samplerstate_t *(*device_samplerstate_create)(gs_device_t *device,
|
||||
const struct gs_sampler_info *info);
|
||||
gs_texture_t *(*device_texture_create)(
|
||||
gs_device_t *device, uint32_t width, uint32_t height,
|
||||
enum gs_color_format color_format, uint32_t levels,
|
||||
const uint8_t **data, uint32_t flags);
|
||||
gs_texture_t *(*device_cubetexture_create)(
|
||||
gs_device_t *device, uint32_t size,
|
||||
enum gs_color_format color_format, uint32_t levels,
|
||||
const uint8_t **data, uint32_t flags);
|
||||
gs_texture_t *(*device_voltexture_create)(
|
||||
gs_device_t *device, uint32_t width, uint32_t height,
|
||||
uint32_t depth, enum gs_color_format color_format,
|
||||
uint32_t levels, const uint8_t **data, uint32_t flags);
|
||||
gs_zstencil_t *(*device_zstencil_create)(
|
||||
gs_device_t *device, uint32_t width, uint32_t height,
|
||||
enum gs_zstencil_format format);
|
||||
gs_stagesurf_t *(*device_stagesurface_create)(
|
||||
gs_device_t *device, uint32_t width, uint32_t height,
|
||||
enum gs_color_format color_format);
|
||||
gs_samplerstate_t *(*device_samplerstate_create)(
|
||||
gs_device_t *device, const struct gs_sampler_info *info);
|
||||
gs_shader_t *(*device_vertexshader_create)(gs_device_t *device,
|
||||
const char *shader, const char *file,
|
||||
char **error_string);
|
||||
const char *shader,
|
||||
const char *file,
|
||||
char **error_string);
|
||||
gs_shader_t *(*device_pixelshader_create)(gs_device_t *device,
|
||||
const char *shader, const char *file,
|
||||
char **error_string);
|
||||
const char *shader,
|
||||
const char *file,
|
||||
char **error_string);
|
||||
gs_vertbuffer_t *(*device_vertexbuffer_create)(gs_device_t *device,
|
||||
struct gs_vb_data *data, uint32_t flags);
|
||||
struct gs_vb_data *data,
|
||||
uint32_t flags);
|
||||
gs_indexbuffer_t *(*device_indexbuffer_create)(gs_device_t *device,
|
||||
enum gs_index_type type, void *indices, size_t num,
|
||||
uint32_t flags);
|
||||
enum gs_index_type type,
|
||||
void *indices,
|
||||
size_t num,
|
||||
uint32_t flags);
|
||||
gs_timer_t *(*device_timer_create)(gs_device_t *device);
|
||||
gs_timer_range_t *(*device_timer_range_create)(gs_device_t *device);
|
||||
enum gs_texture_type (*device_get_texture_type)(
|
||||
const gs_texture_t *texture);
|
||||
const gs_texture_t *texture);
|
||||
void (*device_load_vertexbuffer)(gs_device_t *device,
|
||||
gs_vertbuffer_t *vertbuffer);
|
||||
gs_vertbuffer_t *vertbuffer);
|
||||
void (*device_load_indexbuffer)(gs_device_t *device,
|
||||
gs_indexbuffer_t *indexbuffer);
|
||||
gs_indexbuffer_t *indexbuffer);
|
||||
void (*device_load_texture)(gs_device_t *device, gs_texture_t *tex,
|
||||
int unit);
|
||||
int unit);
|
||||
void (*device_load_samplerstate)(gs_device_t *device,
|
||||
gs_samplerstate_t *samplerstate, int unit);
|
||||
gs_samplerstate_t *samplerstate,
|
||||
int unit);
|
||||
void (*device_load_vertexshader)(gs_device_t *device,
|
||||
gs_shader_t *vertshader);
|
||||
gs_shader_t *vertshader);
|
||||
void (*device_load_pixelshader)(gs_device_t *device,
|
||||
gs_shader_t *pixelshader);
|
||||
void (*device_load_default_samplerstate)(gs_device_t *device,
|
||||
bool b_3d, int unit);
|
||||
gs_shader_t *pixelshader);
|
||||
void (*device_load_default_samplerstate)(gs_device_t *device, bool b_3d,
|
||||
int unit);
|
||||
gs_shader_t *(*device_get_vertex_shader)(const gs_device_t *device);
|
||||
gs_shader_t *(*device_get_pixel_shader)(const gs_device_t *device);
|
||||
gs_texture_t *(*device_get_render_target)(const gs_device_t *device);
|
||||
gs_zstencil_t *(*device_get_zstencil_target)(const gs_device_t *device);
|
||||
void (*device_set_render_target)(gs_device_t *device, gs_texture_t *tex,
|
||||
gs_zstencil_t *zstencil);
|
||||
gs_zstencil_t *zstencil);
|
||||
void (*device_set_cube_render_target)(gs_device_t *device,
|
||||
gs_texture_t *cubetex, int side, gs_zstencil_t *zstencil);
|
||||
gs_texture_t *cubetex, int side,
|
||||
gs_zstencil_t *zstencil);
|
||||
void (*device_copy_texture)(gs_device_t *device, gs_texture_t *dst,
|
||||
gs_texture_t *src);
|
||||
gs_texture_t *src);
|
||||
void (*device_copy_texture_region)(gs_device_t *device,
|
||||
gs_texture_t *dst, uint32_t dst_x, uint32_t dst_y,
|
||||
gs_texture_t *src, uint32_t src_x, uint32_t src_y,
|
||||
uint32_t src_w, uint32_t src_h);
|
||||
gs_texture_t *dst, uint32_t dst_x,
|
||||
uint32_t dst_y, gs_texture_t *src,
|
||||
uint32_t src_x, uint32_t src_y,
|
||||
uint32_t src_w, uint32_t src_h);
|
||||
void (*device_stage_texture)(gs_device_t *device, gs_stagesurf_t *dst,
|
||||
gs_texture_t *src);
|
||||
gs_texture_t *src);
|
||||
void (*device_begin_scene)(gs_device_t *device);
|
||||
void (*device_draw)(gs_device_t *device, enum gs_draw_mode draw_mode,
|
||||
uint32_t start_vert, uint32_t num_verts);
|
||||
uint32_t start_vert, uint32_t num_verts);
|
||||
void (*device_end_scene)(gs_device_t *device);
|
||||
void (*device_load_swapchain)(gs_device_t *device,
|
||||
gs_swapchain_t *swaphchain);
|
||||
gs_swapchain_t *swaphchain);
|
||||
void (*device_clear)(gs_device_t *device, uint32_t clear_flags,
|
||||
const struct vec4 *color, float depth, uint8_t stencil);
|
||||
const struct vec4 *color, float depth,
|
||||
uint8_t stencil);
|
||||
void (*device_present)(gs_device_t *device);
|
||||
void (*device_flush)(gs_device_t *device);
|
||||
void (*device_set_cull_mode)(gs_device_t *device,
|
||||
enum gs_cull_mode mode);
|
||||
enum gs_cull_mode mode);
|
||||
enum gs_cull_mode (*device_get_cull_mode)(const gs_device_t *device);
|
||||
void (*device_enable_blending)(gs_device_t *device, bool enable);
|
||||
void (*device_enable_depth_test)(gs_device_t *device, bool enable);
|
||||
void (*device_enable_stencil_test)(gs_device_t *device, bool enable);
|
||||
void (*device_enable_stencil_write)(gs_device_t *device, bool enable);
|
||||
void (*device_enable_color)(gs_device_t *device, bool red, bool green,
|
||||
bool blue, bool alpha);
|
||||
bool blue, bool alpha);
|
||||
void (*device_blend_function)(gs_device_t *device,
|
||||
enum gs_blend_type src, enum gs_blend_type dest);
|
||||
enum gs_blend_type src,
|
||||
enum gs_blend_type dest);
|
||||
void (*device_blend_function_separate)(gs_device_t *device,
|
||||
enum gs_blend_type src_c, enum gs_blend_type dest_c,
|
||||
enum gs_blend_type src_a, enum gs_blend_type dest_a);
|
||||
enum gs_blend_type src_c,
|
||||
enum gs_blend_type dest_c,
|
||||
enum gs_blend_type src_a,
|
||||
enum gs_blend_type dest_a);
|
||||
void (*device_depth_function)(gs_device_t *device,
|
||||
enum gs_depth_test test);
|
||||
enum gs_depth_test test);
|
||||
void (*device_stencil_function)(gs_device_t *device,
|
||||
enum gs_stencil_side side, enum gs_depth_test test);
|
||||
enum gs_stencil_side side,
|
||||
enum gs_depth_test test);
|
||||
void (*device_stencil_op)(gs_device_t *device,
|
||||
enum gs_stencil_side side,
|
||||
enum gs_stencil_op_type fail,
|
||||
enum gs_stencil_op_type zfail,
|
||||
enum gs_stencil_op_type zpass);
|
||||
enum gs_stencil_side side,
|
||||
enum gs_stencil_op_type fail,
|
||||
enum gs_stencil_op_type zfail,
|
||||
enum gs_stencil_op_type zpass);
|
||||
void (*device_set_viewport)(gs_device_t *device, int x, int y,
|
||||
int width, int height);
|
||||
int width, int height);
|
||||
void (*device_get_viewport)(const gs_device_t *device,
|
||||
struct gs_rect *rect);
|
||||
struct gs_rect *rect);
|
||||
void (*device_set_scissor_rect)(gs_device_t *device,
|
||||
const struct gs_rect *rect);
|
||||
const struct gs_rect *rect);
|
||||
void (*device_ortho)(gs_device_t *device, float left, float right,
|
||||
float top, float bottom, float znear, float zfar);
|
||||
float top, float bottom, float znear, float zfar);
|
||||
void (*device_frustum)(gs_device_t *device, float left, float right,
|
||||
float top, float bottom, float znear, float zfar);
|
||||
float top, float bottom, float znear,
|
||||
float zfar);
|
||||
void (*device_projection_push)(gs_device_t *device);
|
||||
void (*device_projection_pop)(gs_device_t *device);
|
||||
|
||||
void (*gs_swapchain_destroy)(gs_swapchain_t *swapchain);
|
||||
void (*gs_swapchain_destroy)(gs_swapchain_t *swapchain);
|
||||
|
||||
void (*gs_texture_destroy)(gs_texture_t *tex);
|
||||
void (*gs_texture_destroy)(gs_texture_t *tex);
|
||||
uint32_t (*gs_texture_get_width)(const gs_texture_t *tex);
|
||||
uint32_t (*gs_texture_get_height)(const gs_texture_t *tex);
|
||||
enum gs_color_format (*gs_texture_get_color_format)(
|
||||
const gs_texture_t *tex);
|
||||
bool (*gs_texture_map)(gs_texture_t *tex, uint8_t **ptr,
|
||||
uint32_t *linesize);
|
||||
void (*gs_texture_unmap)(gs_texture_t *tex);
|
||||
bool (*gs_texture_is_rect)(const gs_texture_t *tex);
|
||||
void *(*gs_texture_get_obj)(const gs_texture_t *tex);
|
||||
const gs_texture_t *tex);
|
||||
bool (*gs_texture_map)(gs_texture_t *tex, uint8_t **ptr,
|
||||
uint32_t *linesize);
|
||||
void (*gs_texture_unmap)(gs_texture_t *tex);
|
||||
bool (*gs_texture_is_rect)(const gs_texture_t *tex);
|
||||
void *(*gs_texture_get_obj)(const gs_texture_t *tex);
|
||||
|
||||
void (*gs_cubetexture_destroy)(gs_texture_t *cubetex);
|
||||
void (*gs_cubetexture_destroy)(gs_texture_t *cubetex);
|
||||
uint32_t (*gs_cubetexture_get_size)(const gs_texture_t *cubetex);
|
||||
enum gs_color_format (*gs_cubetexture_get_color_format)(
|
||||
const gs_texture_t *cubetex);
|
||||
const gs_texture_t *cubetex);
|
||||
|
||||
void (*gs_voltexture_destroy)(gs_texture_t *voltex);
|
||||
void (*gs_voltexture_destroy)(gs_texture_t *voltex);
|
||||
uint32_t (*gs_voltexture_get_width)(const gs_texture_t *voltex);
|
||||
uint32_t (*gs_voltexture_get_height)(const gs_texture_t *voltex);
|
||||
uint32_t (*gs_voltexture_get_depth)(const gs_texture_t *voltex);
|
||||
enum gs_color_format (*gs_voltexture_get_color_format)(
|
||||
const gs_texture_t *voltex);
|
||||
const gs_texture_t *voltex);
|
||||
|
||||
void (*gs_stagesurface_destroy)(gs_stagesurf_t *stagesurf);
|
||||
void (*gs_stagesurface_destroy)(gs_stagesurf_t *stagesurf);
|
||||
uint32_t (*gs_stagesurface_get_width)(const gs_stagesurf_t *stagesurf);
|
||||
uint32_t (*gs_stagesurface_get_height)(const gs_stagesurf_t *stagesurf);
|
||||
enum gs_color_format (*gs_stagesurface_get_color_format)(
|
||||
const gs_stagesurf_t *stagesurf);
|
||||
bool (*gs_stagesurface_map)(gs_stagesurf_t *stagesurf,
|
||||
uint8_t **data, uint32_t *linesize);
|
||||
void (*gs_stagesurface_unmap)(gs_stagesurf_t *stagesurf);
|
||||
const gs_stagesurf_t *stagesurf);
|
||||
bool (*gs_stagesurface_map)(gs_stagesurf_t *stagesurf, uint8_t **data,
|
||||
uint32_t *linesize);
|
||||
void (*gs_stagesurface_unmap)(gs_stagesurf_t *stagesurf);
|
||||
|
||||
void (*gs_zstencil_destroy)(gs_zstencil_t *zstencil);
|
||||
|
||||
|
|
@ -190,98 +208,113 @@ struct gs_exports {
|
|||
void (*gs_vertexbuffer_destroy)(gs_vertbuffer_t *vertbuffer);
|
||||
void (*gs_vertexbuffer_flush)(gs_vertbuffer_t *vertbuffer);
|
||||
void (*gs_vertexbuffer_flush_direct)(gs_vertbuffer_t *vertbuffer,
|
||||
const struct gs_vb_data *data);
|
||||
const struct gs_vb_data *data);
|
||||
struct gs_vb_data *(*gs_vertexbuffer_get_data)(
|
||||
const gs_vertbuffer_t *vertbuffer);
|
||||
const gs_vertbuffer_t *vertbuffer);
|
||||
|
||||
void (*gs_indexbuffer_destroy)(gs_indexbuffer_t *indexbuffer);
|
||||
void (*gs_indexbuffer_flush)(gs_indexbuffer_t *indexbuffer);
|
||||
void (*gs_indexbuffer_flush_direct)(gs_indexbuffer_t *indexbuffer,
|
||||
const void *data);
|
||||
void *(*gs_indexbuffer_get_data)(const gs_indexbuffer_t *indexbuffer);
|
||||
void (*gs_indexbuffer_destroy)(gs_indexbuffer_t *indexbuffer);
|
||||
void (*gs_indexbuffer_flush)(gs_indexbuffer_t *indexbuffer);
|
||||
void (*gs_indexbuffer_flush_direct)(gs_indexbuffer_t *indexbuffer,
|
||||
const void *data);
|
||||
void *(*gs_indexbuffer_get_data)(const gs_indexbuffer_t *indexbuffer);
|
||||
size_t (*gs_indexbuffer_get_num_indices)(
|
||||
const gs_indexbuffer_t *indexbuffer);
|
||||
const gs_indexbuffer_t *indexbuffer);
|
||||
enum gs_index_type (*gs_indexbuffer_get_type)(
|
||||
const gs_indexbuffer_t *indexbuffer);
|
||||
const gs_indexbuffer_t *indexbuffer);
|
||||
|
||||
void (*gs_timer_destroy)(gs_timer_t *timer);
|
||||
void (*gs_timer_begin)(gs_timer_t *timer);
|
||||
void (*gs_timer_end)(gs_timer_t *timer);
|
||||
bool (*gs_timer_get_data)(gs_timer_t *timer, uint64_t *ticks);
|
||||
void (*gs_timer_range_destroy)(gs_timer_range_t *range);
|
||||
bool (*gs_timer_range_begin)(gs_timer_range_t *range);
|
||||
bool (*gs_timer_range_end)(gs_timer_range_t *range);
|
||||
bool (*gs_timer_range_get_data)(gs_timer_range_t *range, bool *disjoint,
|
||||
uint64_t *frequency);
|
||||
|
||||
void (*gs_shader_destroy)(gs_shader_t *shader);
|
||||
int (*gs_shader_get_num_params)(const gs_shader_t *shader);
|
||||
gs_sparam_t *(*gs_shader_get_param_by_idx)(gs_shader_t *shader,
|
||||
uint32_t param);
|
||||
uint32_t param);
|
||||
gs_sparam_t *(*gs_shader_get_param_by_name)(gs_shader_t *shader,
|
||||
const char *name);
|
||||
gs_sparam_t *(*gs_shader_get_viewproj_matrix)(
|
||||
const gs_shader_t *shader);
|
||||
const char *name);
|
||||
gs_sparam_t *(*gs_shader_get_viewproj_matrix)(const gs_shader_t *shader);
|
||||
gs_sparam_t *(*gs_shader_get_world_matrix)(const gs_shader_t *shader);
|
||||
void (*gs_shader_get_param_info)(const gs_sparam_t *param,
|
||||
struct gs_shader_param_info *info);
|
||||
struct gs_shader_param_info *info);
|
||||
void (*gs_shader_set_bool)(gs_sparam_t *param, bool val);
|
||||
void (*gs_shader_set_float)(gs_sparam_t *param, float val);
|
||||
void (*gs_shader_set_int)(gs_sparam_t *param, int val);
|
||||
void (*gs_shader_set_matrix3)(gs_sparam_t *param,
|
||||
const struct matrix3 *val);
|
||||
const struct matrix3 *val);
|
||||
void (*gs_shader_set_matrix4)(gs_sparam_t *param,
|
||||
const struct matrix4 *val);
|
||||
const struct matrix4 *val);
|
||||
void (*gs_shader_set_vec2)(gs_sparam_t *param, const struct vec2 *val);
|
||||
void (*gs_shader_set_vec3)(gs_sparam_t *param, const struct vec3 *val);
|
||||
void (*gs_shader_set_vec4)(gs_sparam_t *param, const struct vec4 *val);
|
||||
void (*gs_shader_set_texture)(gs_sparam_t *param, gs_texture_t *val);
|
||||
void (*gs_shader_set_val)(gs_sparam_t *param, const void *val,
|
||||
size_t size);
|
||||
size_t size);
|
||||
void (*gs_shader_set_default)(gs_sparam_t *param);
|
||||
void (*gs_shader_set_next_sampler)(gs_sparam_t *param,
|
||||
gs_samplerstate_t *sampler);
|
||||
gs_samplerstate_t *sampler);
|
||||
|
||||
bool (*device_nv12_available)(gs_device_t *device);
|
||||
|
||||
void (*device_debug_marker_begin)(gs_device_t *device,
|
||||
const char *markername, const float color[4]);
|
||||
const char *markername,
|
||||
const float color[4]);
|
||||
void (*device_debug_marker_end)(gs_device_t *device);
|
||||
|
||||
#ifdef __APPLE__
|
||||
/* OSX/Cocoa specific functions */
|
||||
gs_texture_t *(*device_texture_create_from_iosurface)(gs_device_t *dev,
|
||||
void *iosurf);
|
||||
void *iosurf);
|
||||
bool (*gs_texture_rebind_iosurface)(gs_texture_t *texture,
|
||||
void *iosurf);
|
||||
void *iosurf);
|
||||
|
||||
#elif _WIN32
|
||||
bool (*device_gdi_texture_available)(void);
|
||||
bool (*device_shared_texture_available)(void);
|
||||
|
||||
bool (*device_get_duplicator_monitor_info)(gs_device_t *device,
|
||||
int monitor_idx, struct gs_monitor_info *monitor_info);
|
||||
bool (*device_get_duplicator_monitor_info)(
|
||||
gs_device_t *device, int monitor_idx,
|
||||
struct gs_monitor_info *monitor_info);
|
||||
|
||||
gs_duplicator_t *(*device_duplicator_create)(gs_device_t *device,
|
||||
int monitor_idx);
|
||||
int monitor_idx);
|
||||
void (*gs_duplicator_destroy)(gs_duplicator_t *duplicator);
|
||||
|
||||
bool (*gs_duplicator_update_frame)(gs_duplicator_t *duplicator);
|
||||
gs_texture_t *(*gs_duplicator_get_texture)(gs_duplicator_t *duplicator);
|
||||
|
||||
gs_texture_t *(*device_texture_create_gdi)(gs_device_t *device,
|
||||
uint32_t width, uint32_t height);
|
||||
uint32_t width,
|
||||
uint32_t height);
|
||||
|
||||
void *(*gs_texture_get_dc)(gs_texture_t *gdi_tex);
|
||||
void (*gs_texture_release_dc)(gs_texture_t *gdi_tex);
|
||||
|
||||
gs_texture_t *(*device_texture_open_shared)(gs_device_t *device,
|
||||
uint32_t handle);
|
||||
uint32_t handle);
|
||||
uint32_t (*device_texture_get_shared_handle)(gs_texture_t *tex);
|
||||
int (*device_texture_acquire_sync)(gs_texture_t *tex, uint64_t key,
|
||||
uint32_t ms);
|
||||
uint32_t ms);
|
||||
int (*device_texture_release_sync)(gs_texture_t *tex, uint64_t key);
|
||||
bool (*device_texture_create_nv12)(gs_device_t *device,
|
||||
gs_texture_t **tex_y, gs_texture_t **tex_uv,
|
||||
uint32_t width, uint32_t height, uint32_t flags);
|
||||
gs_texture_t **tex_y,
|
||||
gs_texture_t **tex_uv,
|
||||
uint32_t width, uint32_t height,
|
||||
uint32_t flags);
|
||||
|
||||
gs_stagesurf_t *(*device_stagesurface_create_nv12)(gs_device_t *device,
|
||||
uint32_t width, uint32_t height);
|
||||
uint32_t width,
|
||||
uint32_t height);
|
||||
#endif
|
||||
};
|
||||
|
||||
struct blend_state {
|
||||
bool enabled;
|
||||
bool enabled;
|
||||
enum gs_blend_type src_c;
|
||||
enum gs_blend_type dest_c;
|
||||
enum gs_blend_type src_a;
|
||||
|
|
@ -289,34 +322,34 @@ struct blend_state {
|
|||
};
|
||||
|
||||
struct graphics_subsystem {
|
||||
void *module;
|
||||
gs_device_t *device;
|
||||
struct gs_exports exports;
|
||||
void *module;
|
||||
gs_device_t *device;
|
||||
struct gs_exports exports;
|
||||
|
||||
DARRAY(struct gs_rect) viewport_stack;
|
||||
|
||||
DARRAY(struct matrix4) matrix_stack;
|
||||
size_t cur_matrix;
|
||||
size_t cur_matrix;
|
||||
|
||||
struct matrix4 projection;
|
||||
struct gs_effect *cur_effect;
|
||||
struct matrix4 projection;
|
||||
struct gs_effect *cur_effect;
|
||||
|
||||
gs_vertbuffer_t *sprite_buffer;
|
||||
gs_vertbuffer_t *sprite_buffer;
|
||||
|
||||
bool using_immediate;
|
||||
struct gs_vb_data *vbd;
|
||||
gs_vertbuffer_t *immediate_vertbuffer;
|
||||
DARRAY(struct vec3) verts;
|
||||
DARRAY(struct vec3) norms;
|
||||
DARRAY(uint32_t) colors;
|
||||
DARRAY(struct vec2) texverts[16];
|
||||
bool using_immediate;
|
||||
struct gs_vb_data *vbd;
|
||||
gs_vertbuffer_t *immediate_vertbuffer;
|
||||
DARRAY(struct vec3) verts;
|
||||
DARRAY(struct vec3) norms;
|
||||
DARRAY(uint32_t) colors;
|
||||
DARRAY(struct vec2) texverts[16];
|
||||
|
||||
pthread_mutex_t effect_mutex;
|
||||
struct gs_effect *first_effect;
|
||||
pthread_mutex_t effect_mutex;
|
||||
struct gs_effect *first_effect;
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
volatile long ref;
|
||||
pthread_mutex_t mutex;
|
||||
volatile long ref;
|
||||
|
||||
struct blend_state cur_blend_state;
|
||||
struct blend_state cur_blend_state;
|
||||
DARRAY(struct blend_state) blend_state_stack;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "obsconfig.h"
|
||||
|
||||
#define MAGICKCORE_QUANTUM_DEPTH 16
|
||||
#define MAGICKCORE_HDRI_ENABLE 0
|
||||
#define MAGICKCORE_HDRI_ENABLE 0
|
||||
|
||||
#if LIBOBS_IMAGEMAGICK_DIR_STYLE == LIBOBS_IMAGEMAGICK_DIR_STYLE_6L
|
||||
#include <magick/MagickCore.h>
|
||||
|
|
@ -21,33 +21,34 @@ void gs_free_image_deps()
|
|||
}
|
||||
|
||||
uint8_t *gs_create_texture_file_data(const char *file,
|
||||
enum gs_color_format *format,
|
||||
uint32_t *cx_out, uint32_t *cy_out)
|
||||
enum gs_color_format *format,
|
||||
uint32_t *cx_out, uint32_t *cy_out)
|
||||
{
|
||||
uint8_t *data = NULL;
|
||||
ImageInfo *info;
|
||||
uint8_t *data = NULL;
|
||||
ImageInfo *info;
|
||||
ExceptionInfo *exception;
|
||||
Image *image;
|
||||
Image *image;
|
||||
|
||||
if (!file || !*file)
|
||||
return NULL;
|
||||
|
||||
info = CloneImageInfo(NULL);
|
||||
info = CloneImageInfo(NULL);
|
||||
exception = AcquireExceptionInfo();
|
||||
|
||||
strcpy(info->filename, file);
|
||||
image = ReadImage(info, exception);
|
||||
if (image) {
|
||||
size_t cx = image->magick_columns;
|
||||
size_t cy = image->magick_rows;
|
||||
data = bmalloc(cx * cy * 4);
|
||||
size_t cx = image->magick_columns;
|
||||
size_t cy = image->magick_rows;
|
||||
data = bmalloc(cx * cy * 4);
|
||||
|
||||
ExportImagePixels(image, 0, 0, cx, cy, "BGRA", CharPixel,
|
||||
data, exception);
|
||||
ExportImagePixels(image, 0, 0, cx, cy, "BGRA", CharPixel, data,
|
||||
exception);
|
||||
if (exception->severity != UndefinedException) {
|
||||
blog(LOG_WARNING, "magickcore warning/error getting "
|
||||
"pixels from file '%s': %s", file,
|
||||
exception->reason);
|
||||
blog(LOG_WARNING,
|
||||
"magickcore warning/error getting "
|
||||
"pixels from file '%s': %s",
|
||||
file, exception->reason);
|
||||
bfree(data);
|
||||
data = NULL;
|
||||
}
|
||||
|
|
@ -58,8 +59,10 @@ uint8_t *gs_create_texture_file_data(const char *file,
|
|||
DestroyImage(image);
|
||||
|
||||
} else if (exception->severity != UndefinedException) {
|
||||
blog(LOG_WARNING, "magickcore warning/error reading file "
|
||||
"'%s': %s", file, exception->reason);
|
||||
blog(LOG_WARNING,
|
||||
"magickcore warning/error reading file "
|
||||
"'%s': %s",
|
||||
file, exception->reason);
|
||||
}
|
||||
|
||||
DestroyImageInfo(info);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -50,7 +50,7 @@ enum gs_draw_mode {
|
|||
GS_LINES,
|
||||
GS_LINESTRIP,
|
||||
GS_TRIS,
|
||||
GS_TRISTRIP
|
||||
GS_TRISTRIP,
|
||||
};
|
||||
|
||||
enum gs_color_format {
|
||||
|
|
@ -80,18 +80,18 @@ enum gs_zstencil_format {
|
|||
GS_Z16,
|
||||
GS_Z24_S8,
|
||||
GS_Z32F,
|
||||
GS_Z32F_S8X24
|
||||
GS_Z32F_S8X24,
|
||||
};
|
||||
|
||||
enum gs_index_type {
|
||||
GS_UNSIGNED_SHORT,
|
||||
GS_UNSIGNED_LONG
|
||||
GS_UNSIGNED_LONG,
|
||||
};
|
||||
|
||||
enum gs_cull_mode {
|
||||
GS_BACK,
|
||||
GS_FRONT,
|
||||
GS_NEITHER
|
||||
GS_NEITHER,
|
||||
};
|
||||
|
||||
enum gs_blend_type {
|
||||
|
|
@ -105,7 +105,7 @@ enum gs_blend_type {
|
|||
GS_BLEND_INVDSTCOLOR,
|
||||
GS_BLEND_DSTALPHA,
|
||||
GS_BLEND_INVDSTALPHA,
|
||||
GS_BLEND_SRCALPHASAT
|
||||
GS_BLEND_SRCALPHASAT,
|
||||
};
|
||||
|
||||
enum gs_depth_test {
|
||||
|
|
@ -116,13 +116,13 @@ enum gs_depth_test {
|
|||
GS_GEQUAL,
|
||||
GS_GREATER,
|
||||
GS_NOTEQUAL,
|
||||
GS_ALWAYS
|
||||
GS_ALWAYS,
|
||||
};
|
||||
|
||||
enum gs_stencil_side {
|
||||
GS_STENCIL_FRONT=1,
|
||||
GS_STENCIL_FRONT = 1,
|
||||
GS_STENCIL_BACK,
|
||||
GS_STENCIL_BOTH
|
||||
GS_STENCIL_BOTH,
|
||||
};
|
||||
|
||||
enum gs_stencil_op_type {
|
||||
|
|
@ -131,7 +131,7 @@ enum gs_stencil_op_type {
|
|||
GS_REPLACE,
|
||||
GS_INCR,
|
||||
GS_DECR,
|
||||
GS_INVERT
|
||||
GS_INVERT,
|
||||
};
|
||||
|
||||
enum gs_cube_sides {
|
||||
|
|
@ -140,7 +140,7 @@ enum gs_cube_sides {
|
|||
GS_POSITIVE_Y,
|
||||
GS_NEGATIVE_Y,
|
||||
GS_POSITIVE_Z,
|
||||
GS_NEGATIVE_Z
|
||||
GS_NEGATIVE_Z,
|
||||
};
|
||||
|
||||
enum gs_sample_filter {
|
||||
|
|
@ -160,13 +160,13 @@ enum gs_address_mode {
|
|||
GS_ADDRESS_WRAP,
|
||||
GS_ADDRESS_MIRROR,
|
||||
GS_ADDRESS_BORDER,
|
||||
GS_ADDRESS_MIRRORONCE
|
||||
GS_ADDRESS_MIRRORONCE,
|
||||
};
|
||||
|
||||
enum gs_texture_type {
|
||||
GS_TEXTURE_2D,
|
||||
GS_TEXTURE_3D,
|
||||
GS_TEXTURE_CUBE
|
||||
GS_TEXTURE_CUBE,
|
||||
};
|
||||
|
||||
struct gs_monitor_info {
|
||||
|
|
@ -195,7 +195,7 @@ struct gs_vb_data {
|
|||
|
||||
static inline struct gs_vb_data *gs_vbdata_create(void)
|
||||
{
|
||||
return (struct gs_vb_data*)bzalloc(sizeof(struct gs_vb_data));
|
||||
return (struct gs_vb_data *)bzalloc(sizeof(struct gs_vb_data));
|
||||
}
|
||||
|
||||
static inline void gs_vbdata_destroy(struct gs_vb_data *data)
|
||||
|
|
@ -247,6 +247,7 @@ struct gs_index_buffer;
|
|||
struct gs_sampler_state;
|
||||
struct gs_shader;
|
||||
struct gs_swap_chain;
|
||||
struct gs_timer;
|
||||
struct gs_texrender;
|
||||
struct gs_shader_param;
|
||||
struct gs_effect;
|
||||
|
|
@ -256,22 +257,24 @@ struct gs_effect_param;
|
|||
struct gs_device;
|
||||
struct graphics_subsystem;
|
||||
|
||||
typedef struct gs_texture gs_texture_t;
|
||||
typedef struct gs_stage_surface gs_stagesurf_t;
|
||||
typedef struct gs_zstencil_buffer gs_zstencil_t;
|
||||
typedef struct gs_vertex_buffer gs_vertbuffer_t;
|
||||
typedef struct gs_index_buffer gs_indexbuffer_t;
|
||||
typedef struct gs_sampler_state gs_samplerstate_t;
|
||||
typedef struct gs_swap_chain gs_swapchain_t;
|
||||
typedef struct gs_texture_render gs_texrender_t;
|
||||
typedef struct gs_shader gs_shader_t;
|
||||
typedef struct gs_shader_param gs_sparam_t;
|
||||
typedef struct gs_effect gs_effect_t;
|
||||
typedef struct gs_texture gs_texture_t;
|
||||
typedef struct gs_stage_surface gs_stagesurf_t;
|
||||
typedef struct gs_zstencil_buffer gs_zstencil_t;
|
||||
typedef struct gs_vertex_buffer gs_vertbuffer_t;
|
||||
typedef struct gs_index_buffer gs_indexbuffer_t;
|
||||
typedef struct gs_sampler_state gs_samplerstate_t;
|
||||
typedef struct gs_swap_chain gs_swapchain_t;
|
||||
typedef struct gs_timer gs_timer_t;
|
||||
typedef struct gs_timer_range gs_timer_range_t;
|
||||
typedef struct gs_texture_render gs_texrender_t;
|
||||
typedef struct gs_shader gs_shader_t;
|
||||
typedef struct gs_shader_param gs_sparam_t;
|
||||
typedef struct gs_effect gs_effect_t;
|
||||
typedef struct gs_effect_technique gs_technique_t;
|
||||
typedef struct gs_effect_pass gs_epass_t;
|
||||
typedef struct gs_effect_param gs_eparam_t;
|
||||
typedef struct gs_device gs_device_t;
|
||||
typedef struct graphics_subsystem graphics_t;
|
||||
typedef struct gs_effect_pass gs_epass_t;
|
||||
typedef struct gs_effect_param gs_eparam_t;
|
||||
typedef struct gs_device gs_device_t;
|
||||
typedef struct graphics_subsystem graphics_t;
|
||||
|
||||
/* ---------------------------------------------------
|
||||
* shader functions
|
||||
|
|
@ -308,20 +311,22 @@ EXPORT void gs_shader_destroy(gs_shader_t *shader);
|
|||
|
||||
EXPORT int gs_shader_get_num_params(const gs_shader_t *shader);
|
||||
EXPORT gs_sparam_t *gs_shader_get_param_by_idx(gs_shader_t *shader,
|
||||
uint32_t param);
|
||||
uint32_t param);
|
||||
EXPORT gs_sparam_t *gs_shader_get_param_by_name(gs_shader_t *shader,
|
||||
const char *name);
|
||||
const char *name);
|
||||
|
||||
EXPORT gs_sparam_t *gs_shader_get_viewproj_matrix(const gs_shader_t *shader);
|
||||
EXPORT gs_sparam_t *gs_shader_get_world_matrix(const gs_shader_t *shader);
|
||||
|
||||
EXPORT void gs_shader_get_param_info(const gs_sparam_t *param,
|
||||
struct gs_shader_param_info *info);
|
||||
struct gs_shader_param_info *info);
|
||||
EXPORT void gs_shader_set_bool(gs_sparam_t *param, bool val);
|
||||
EXPORT void gs_shader_set_float(gs_sparam_t *param, float val);
|
||||
EXPORT void gs_shader_set_int(gs_sparam_t *param, int val);
|
||||
EXPORT void gs_shader_set_matrix3(gs_sparam_t *param, const struct matrix3 *val);
|
||||
EXPORT void gs_shader_set_matrix4(gs_sparam_t *param, const struct matrix4 *val);
|
||||
EXPORT void gs_shader_set_matrix3(gs_sparam_t *param,
|
||||
const struct matrix3 *val);
|
||||
EXPORT void gs_shader_set_matrix4(gs_sparam_t *param,
|
||||
const struct matrix4 *val);
|
||||
EXPORT void gs_shader_set_vec2(gs_sparam_t *param, const struct vec2 *val);
|
||||
EXPORT void gs_shader_set_vec3(gs_sparam_t *param, const struct vec3 *val);
|
||||
EXPORT void gs_shader_set_vec4(gs_sparam_t *param, const struct vec4 *val);
|
||||
|
|
@ -329,7 +334,7 @@ EXPORT void gs_shader_set_texture(gs_sparam_t *param, gs_texture_t *val);
|
|||
EXPORT void gs_shader_set_val(gs_sparam_t *param, const void *val, size_t size);
|
||||
EXPORT void gs_shader_set_default(gs_sparam_t *param);
|
||||
EXPORT void gs_shader_set_next_sampler(gs_sparam_t *param,
|
||||
gs_samplerstate_t *sampler);
|
||||
gs_samplerstate_t *sampler);
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------
|
||||
|
|
@ -359,32 +364,33 @@ struct gs_effect_param_info {
|
|||
EXPORT void gs_effect_destroy(gs_effect_t *effect);
|
||||
|
||||
EXPORT gs_technique_t *gs_effect_get_technique(const gs_effect_t *effect,
|
||||
const char *name);
|
||||
const char *name);
|
||||
|
||||
EXPORT gs_technique_t *gs_effect_get_current_technique(
|
||||
const gs_effect_t *effect);
|
||||
EXPORT gs_technique_t *
|
||||
gs_effect_get_current_technique(const gs_effect_t *effect);
|
||||
|
||||
EXPORT size_t gs_technique_begin(gs_technique_t *technique);
|
||||
EXPORT void gs_technique_end(gs_technique_t *technique);
|
||||
EXPORT bool gs_technique_begin_pass(gs_technique_t *technique, size_t pass);
|
||||
EXPORT bool gs_technique_begin_pass_by_name(gs_technique_t *technique,
|
||||
const char *name);
|
||||
const char *name);
|
||||
EXPORT void gs_technique_end_pass(gs_technique_t *technique);
|
||||
EXPORT gs_epass_t *gs_technique_get_pass_by_idx(const gs_technique_t *technique,
|
||||
size_t pass);
|
||||
EXPORT gs_epass_t *gs_technique_get_pass_by_name(
|
||||
const gs_technique_t *technique, const char *name);
|
||||
size_t pass);
|
||||
EXPORT gs_epass_t *
|
||||
gs_technique_get_pass_by_name(const gs_technique_t *technique,
|
||||
const char *name);
|
||||
|
||||
EXPORT size_t gs_effect_get_num_params(const gs_effect_t *effect);
|
||||
EXPORT gs_eparam_t *gs_effect_get_param_by_idx(const gs_effect_t *effect,
|
||||
size_t param);
|
||||
size_t param);
|
||||
EXPORT gs_eparam_t *gs_effect_get_param_by_name(const gs_effect_t *effect,
|
||||
const char *name);
|
||||
const char *name);
|
||||
EXPORT size_t gs_param_get_num_annotations(const gs_eparam_t *param);
|
||||
EXPORT gs_eparam_t *gs_param_get_annotation_by_idx(const gs_eparam_t *param,
|
||||
size_t annotation);
|
||||
size_t annotation);
|
||||
EXPORT gs_eparam_t *gs_param_get_annotation_by_name(const gs_eparam_t *param,
|
||||
const char *name);
|
||||
const char *name);
|
||||
|
||||
/** Helper function to simplify effect usage. Use with a while loop that
|
||||
* contains drawing functions. Automatically handles techniques, passes, and
|
||||
|
|
@ -399,14 +405,14 @@ EXPORT gs_eparam_t *gs_effect_get_world_matrix(const gs_effect_t *effect);
|
|||
|
||||
#ifndef SWIG
|
||||
EXPORT void gs_effect_get_param_info(const gs_eparam_t *param,
|
||||
struct gs_effect_param_info *info);
|
||||
struct gs_effect_param_info *info);
|
||||
#endif
|
||||
|
||||
EXPORT void gs_effect_set_bool(gs_eparam_t *param, bool val);
|
||||
EXPORT void gs_effect_set_float(gs_eparam_t *param, float val);
|
||||
EXPORT void gs_effect_set_int(gs_eparam_t *param, int val);
|
||||
EXPORT void gs_effect_set_matrix4(gs_eparam_t *param,
|
||||
const struct matrix4 *val);
|
||||
const struct matrix4 *val);
|
||||
EXPORT void gs_effect_set_vec2(gs_eparam_t *param, const struct vec2 *val);
|
||||
EXPORT void gs_effect_set_vec3(gs_eparam_t *param, const struct vec3 *val);
|
||||
EXPORT void gs_effect_set_vec4(gs_eparam_t *param, const struct vec4 *val);
|
||||
|
|
@ -418,7 +424,7 @@ EXPORT void *gs_effect_get_val(gs_eparam_t *param);
|
|||
EXPORT size_t gs_effect_get_default_val_size(gs_eparam_t *param);
|
||||
EXPORT void *gs_effect_get_default_val(gs_eparam_t *param);
|
||||
EXPORT void gs_effect_set_next_sampler(gs_eparam_t *param,
|
||||
gs_samplerstate_t *sampler);
|
||||
gs_samplerstate_t *sampler);
|
||||
|
||||
EXPORT void gs_effect_set_color(gs_eparam_t *param, uint32_t argb);
|
||||
|
||||
|
|
@ -427,10 +433,10 @@ EXPORT void gs_effect_set_color(gs_eparam_t *param, uint32_t argb);
|
|||
* --------------------------------------------------- */
|
||||
|
||||
EXPORT gs_texrender_t *gs_texrender_create(enum gs_color_format format,
|
||||
enum gs_zstencil_format zsformat);
|
||||
enum gs_zstencil_format zsformat);
|
||||
EXPORT void gs_texrender_destroy(gs_texrender_t *texrender);
|
||||
EXPORT bool gs_texrender_begin(gs_texrender_t *texrender, uint32_t cx,
|
||||
uint32_t cy);
|
||||
uint32_t cy);
|
||||
EXPORT void gs_texrender_end(gs_texrender_t *texrender);
|
||||
EXPORT void gs_texrender_reset(gs_texrender_t *texrender);
|
||||
EXPORT gs_texture_t *gs_texrender_get_texture(const gs_texrender_t *texrender);
|
||||
|
|
@ -439,60 +445,62 @@ EXPORT gs_texture_t *gs_texrender_get_texture(const gs_texrender_t *texrender);
|
|||
* graphics subsystem
|
||||
* --------------------------------------------------- */
|
||||
|
||||
#define GS_BUILD_MIPMAPS (1<<0)
|
||||
#define GS_DYNAMIC (1<<1)
|
||||
#define GS_RENDER_TARGET (1<<2)
|
||||
#define GS_GL_DUMMYTEX (1<<3) /**<< texture with no allocated texture data */
|
||||
#define GS_DUP_BUFFER (1<<4) /**<< do not pass buffer ownership when
|
||||
#define GS_BUILD_MIPMAPS (1 << 0)
|
||||
#define GS_DYNAMIC (1 << 1)
|
||||
#define GS_RENDER_TARGET (1 << 2)
|
||||
#define GS_GL_DUMMYTEX (1 << 3) /**<< texture with no allocated texture data */
|
||||
#define GS_DUP_BUFFER \
|
||||
(1 << 4) /**<< do not pass buffer ownership when
|
||||
* creating a vertex/index buffer */
|
||||
#define GS_SHARED_TEX (1<<5)
|
||||
#define GS_SHARED_KM_TEX (1<<6)
|
||||
#define GS_SHARED_TEX (1 << 5)
|
||||
#define GS_SHARED_KM_TEX (1 << 6)
|
||||
|
||||
/* ---------------- */
|
||||
/* global functions */
|
||||
|
||||
#define GS_SUCCESS 0
|
||||
#define GS_ERROR_FAIL -1
|
||||
#define GS_SUCCESS 0
|
||||
#define GS_ERROR_FAIL -1
|
||||
#define GS_ERROR_MODULE_NOT_FOUND -2
|
||||
#define GS_ERROR_NOT_SUPPORTED -3
|
||||
#define GS_ERROR_NOT_SUPPORTED -3
|
||||
|
||||
struct gs_window {
|
||||
#if defined(_WIN32)
|
||||
void *hwnd;
|
||||
void *hwnd;
|
||||
#elif defined(__APPLE__)
|
||||
__unsafe_unretained id view;
|
||||
__unsafe_unretained id view;
|
||||
#elif defined(__linux__) || defined(__FreeBSD__)
|
||||
/* I'm not sure how portable defining id to uint32_t is. */
|
||||
uint32_t id;
|
||||
void* display;
|
||||
void *display;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct gs_init_data {
|
||||
struct gs_window window;
|
||||
uint32_t cx, cy;
|
||||
uint32_t num_backbuffers;
|
||||
enum gs_color_format format;
|
||||
struct gs_window window;
|
||||
uint32_t cx, cy;
|
||||
uint32_t num_backbuffers;
|
||||
enum gs_color_format format;
|
||||
enum gs_zstencil_format zsformat;
|
||||
uint32_t adapter;
|
||||
uint32_t adapter;
|
||||
};
|
||||
|
||||
#define GS_DEVICE_OPENGL 1
|
||||
#define GS_DEVICE_OPENGL 1
|
||||
#define GS_DEVICE_DIRECT3D_11 2
|
||||
|
||||
EXPORT const char *gs_get_device_name(void);
|
||||
EXPORT int gs_get_device_type(void);
|
||||
EXPORT void gs_enum_adapters(
|
||||
bool (*callback)(void *param, const char *name, uint32_t id),
|
||||
void *param);
|
||||
EXPORT void gs_enum_adapters(bool (*callback)(void *param, const char *name,
|
||||
uint32_t id),
|
||||
void *param);
|
||||
|
||||
EXPORT int gs_create(graphics_t **graphics, const char *module,
|
||||
uint32_t adapter);
|
||||
uint32_t adapter);
|
||||
EXPORT void gs_destroy(graphics_t *graphics);
|
||||
|
||||
EXPORT void gs_enter_context(graphics_t *graphics);
|
||||
EXPORT void gs_leave_context(void);
|
||||
EXPORT graphics_t *gs_get_context(void);
|
||||
EXPORT void *gs_get_device_obj(void);
|
||||
|
||||
EXPORT void gs_matrix_push(void);
|
||||
EXPORT void gs_matrix_pop(void);
|
||||
|
|
@ -527,21 +535,22 @@ EXPORT input_t *gs_get_input(void);
|
|||
EXPORT gs_effect_t *gs_get_effect(void);
|
||||
|
||||
EXPORT gs_effect_t *gs_effect_create_from_file(const char *file,
|
||||
char **error_string);
|
||||
char **error_string);
|
||||
EXPORT gs_effect_t *gs_effect_create(const char *effect_string,
|
||||
const char *filename, char **error_string);
|
||||
const char *filename, char **error_string);
|
||||
|
||||
EXPORT gs_shader_t *gs_vertexshader_create_from_file(const char *file,
|
||||
char **error_string);
|
||||
char **error_string);
|
||||
EXPORT gs_shader_t *gs_pixelshader_create_from_file(const char *file,
|
||||
char **error_string);
|
||||
char **error_string);
|
||||
|
||||
EXPORT gs_texture_t *gs_texture_create_from_file(const char *file);
|
||||
EXPORT uint8_t *gs_create_texture_file_data(const char *file,
|
||||
enum gs_color_format *format, uint32_t *cx, uint32_t *cy);
|
||||
enum gs_color_format *format,
|
||||
uint32_t *cx, uint32_t *cy);
|
||||
|
||||
#define GS_FLIP_U (1<<0)
|
||||
#define GS_FLIP_V (1<<1)
|
||||
#define GS_FLIP_U (1 << 0)
|
||||
#define GS_FLIP_V (1 << 1)
|
||||
|
||||
/**
|
||||
* Draws a 2D sprite
|
||||
|
|
@ -551,13 +560,15 @@ EXPORT uint8_t *gs_create_texture_file_data(const char *file,
|
|||
* axis with GS_FLIP_U and GS_FLIP_V.
|
||||
*/
|
||||
EXPORT void gs_draw_sprite(gs_texture_t *tex, uint32_t flip, uint32_t width,
|
||||
uint32_t height);
|
||||
uint32_t height);
|
||||
|
||||
EXPORT void gs_draw_sprite_subregion(gs_texture_t *tex, uint32_t flip,
|
||||
uint32_t x, uint32_t y, uint32_t cx, uint32_t cy);
|
||||
uint32_t x, uint32_t y, uint32_t cx,
|
||||
uint32_t cy);
|
||||
|
||||
EXPORT void gs_draw_cube_backdrop(gs_texture_t *cubetex, const struct quat *rot,
|
||||
float left, float right, float top, float bottom, float znear);
|
||||
float left, float right, float top,
|
||||
float bottom, float znear);
|
||||
|
||||
/** sets the viewport to current swap chain size */
|
||||
EXPORT void gs_reset_viewport(void);
|
||||
|
|
@ -571,9 +582,10 @@ EXPORT void gs_viewport_push(void);
|
|||
EXPORT void gs_viewport_pop(void);
|
||||
|
||||
EXPORT void gs_texture_set_image(gs_texture_t *tex, const uint8_t *data,
|
||||
uint32_t linesize, bool invert);
|
||||
uint32_t linesize, bool invert);
|
||||
EXPORT void gs_cubetexture_set_image(gs_texture_t *cubetex, uint32_t side,
|
||||
const void *data, uint32_t linesize, bool invert);
|
||||
const void *data, uint32_t linesize,
|
||||
bool invert);
|
||||
|
||||
EXPORT void gs_perspective(float fovy, float aspect, float znear, float zfar);
|
||||
|
||||
|
|
@ -592,33 +604,41 @@ EXPORT uint32_t gs_get_width(void);
|
|||
EXPORT uint32_t gs_get_height(void);
|
||||
|
||||
EXPORT gs_texture_t *gs_texture_create(uint32_t width, uint32_t height,
|
||||
enum gs_color_format color_format, uint32_t levels,
|
||||
const uint8_t **data, uint32_t flags);
|
||||
EXPORT gs_texture_t *gs_cubetexture_create(uint32_t size,
|
||||
enum gs_color_format color_format, uint32_t levels,
|
||||
const uint8_t **data, uint32_t flags);
|
||||
enum gs_color_format color_format,
|
||||
uint32_t levels, const uint8_t **data,
|
||||
uint32_t flags);
|
||||
EXPORT gs_texture_t *
|
||||
gs_cubetexture_create(uint32_t size, enum gs_color_format color_format,
|
||||
uint32_t levels, const uint8_t **data, uint32_t flags);
|
||||
EXPORT gs_texture_t *gs_voltexture_create(uint32_t width, uint32_t height,
|
||||
uint32_t depth, enum gs_color_format color_format,
|
||||
uint32_t levels, const uint8_t **data, uint32_t flags);
|
||||
uint32_t depth,
|
||||
enum gs_color_format color_format,
|
||||
uint32_t levels, const uint8_t **data,
|
||||
uint32_t flags);
|
||||
|
||||
EXPORT gs_zstencil_t *gs_zstencil_create(uint32_t width, uint32_t height,
|
||||
enum gs_zstencil_format format);
|
||||
enum gs_zstencil_format format);
|
||||
|
||||
EXPORT gs_stagesurf_t *gs_stagesurface_create(uint32_t width, uint32_t height,
|
||||
enum gs_color_format color_format);
|
||||
EXPORT gs_stagesurf_t *
|
||||
gs_stagesurface_create(uint32_t width, uint32_t height,
|
||||
enum gs_color_format color_format);
|
||||
|
||||
EXPORT gs_samplerstate_t *gs_samplerstate_create(
|
||||
const struct gs_sampler_info *info);
|
||||
EXPORT gs_samplerstate_t *
|
||||
gs_samplerstate_create(const struct gs_sampler_info *info);
|
||||
|
||||
EXPORT gs_shader_t *gs_vertexshader_create(const char *shader,
|
||||
const char *file, char **error_string);
|
||||
EXPORT gs_shader_t *gs_pixelshader_create(const char *shader,
|
||||
const char *file, char **error_string);
|
||||
EXPORT gs_shader_t *gs_vertexshader_create(const char *shader, const char *file,
|
||||
char **error_string);
|
||||
EXPORT gs_shader_t *gs_pixelshader_create(const char *shader, const char *file,
|
||||
char **error_string);
|
||||
|
||||
EXPORT gs_vertbuffer_t *gs_vertexbuffer_create(struct gs_vb_data *data,
|
||||
uint32_t flags);
|
||||
uint32_t flags);
|
||||
EXPORT gs_indexbuffer_t *gs_indexbuffer_create(enum gs_index_type type,
|
||||
void *indices, size_t num, uint32_t flags);
|
||||
void *indices, size_t num,
|
||||
uint32_t flags);
|
||||
|
||||
EXPORT gs_timer_t *gs_timer_create();
|
||||
EXPORT gs_timer_range_t *gs_timer_range_create();
|
||||
|
||||
EXPORT enum gs_texture_type gs_get_texture_type(const gs_texture_t *texture);
|
||||
|
||||
|
|
@ -634,32 +654,32 @@ EXPORT void gs_load_default_samplerstate(bool b_3d, int unit);
|
|||
EXPORT gs_shader_t *gs_get_vertex_shader(void);
|
||||
EXPORT gs_shader_t *gs_get_pixel_shader(void);
|
||||
|
||||
EXPORT gs_texture_t *gs_get_render_target(void);
|
||||
EXPORT gs_texture_t *gs_get_render_target(void);
|
||||
EXPORT gs_zstencil_t *gs_get_zstencil_target(void);
|
||||
|
||||
EXPORT void gs_set_render_target(gs_texture_t *tex, gs_zstencil_t *zstencil);
|
||||
EXPORT void gs_set_cube_render_target(gs_texture_t *cubetex, int side,
|
||||
gs_zstencil_t *zstencil);
|
||||
gs_zstencil_t *zstencil);
|
||||
|
||||
EXPORT void gs_copy_texture(gs_texture_t *dst, gs_texture_t *src);
|
||||
EXPORT void gs_copy_texture_region(
|
||||
gs_texture_t *dst, uint32_t dst_x, uint32_t dst_y,
|
||||
gs_texture_t *src, uint32_t src_x, uint32_t src_y,
|
||||
uint32_t src_w, uint32_t src_h);
|
||||
EXPORT void gs_copy_texture_region(gs_texture_t *dst, uint32_t dst_x,
|
||||
uint32_t dst_y, gs_texture_t *src,
|
||||
uint32_t src_x, uint32_t src_y,
|
||||
uint32_t src_w, uint32_t src_h);
|
||||
EXPORT void gs_stage_texture(gs_stagesurf_t *dst, gs_texture_t *src);
|
||||
|
||||
EXPORT void gs_begin_scene(void);
|
||||
EXPORT void gs_draw(enum gs_draw_mode draw_mode, uint32_t start_vert,
|
||||
uint32_t num_verts);
|
||||
uint32_t num_verts);
|
||||
EXPORT void gs_end_scene(void);
|
||||
|
||||
#define GS_CLEAR_COLOR (1<<0)
|
||||
#define GS_CLEAR_DEPTH (1<<1)
|
||||
#define GS_CLEAR_STENCIL (1<<2)
|
||||
#define GS_CLEAR_COLOR (1 << 0)
|
||||
#define GS_CLEAR_DEPTH (1 << 1)
|
||||
#define GS_CLEAR_STENCIL (1 << 2)
|
||||
|
||||
EXPORT void gs_load_swapchain(gs_swapchain_t *swapchain);
|
||||
EXPORT void gs_clear(uint32_t clear_flags, const struct vec4 *color,
|
||||
float depth, uint8_t stencil);
|
||||
float depth, uint8_t stencil);
|
||||
EXPORT void gs_present(void);
|
||||
EXPORT void gs_flush(void);
|
||||
|
||||
|
|
@ -673,109 +693,119 @@ EXPORT void gs_enable_stencil_write(bool enable);
|
|||
EXPORT void gs_enable_color(bool red, bool green, bool blue, bool alpha);
|
||||
|
||||
EXPORT void gs_blend_function(enum gs_blend_type src, enum gs_blend_type dest);
|
||||
EXPORT void gs_blend_function_separate(
|
||||
enum gs_blend_type src_c, enum gs_blend_type dest_c,
|
||||
enum gs_blend_type src_a, enum gs_blend_type dest_a);
|
||||
EXPORT void gs_blend_function_separate(enum gs_blend_type src_c,
|
||||
enum gs_blend_type dest_c,
|
||||
enum gs_blend_type src_a,
|
||||
enum gs_blend_type dest_a);
|
||||
EXPORT void gs_depth_function(enum gs_depth_test test);
|
||||
|
||||
EXPORT void gs_stencil_function(enum gs_stencil_side side,
|
||||
enum gs_depth_test test);
|
||||
enum gs_depth_test test);
|
||||
EXPORT void gs_stencil_op(enum gs_stencil_side side,
|
||||
enum gs_stencil_op_type fail,
|
||||
enum gs_stencil_op_type zfail,
|
||||
enum gs_stencil_op_type zpass);
|
||||
enum gs_stencil_op_type fail,
|
||||
enum gs_stencil_op_type zfail,
|
||||
enum gs_stencil_op_type zpass);
|
||||
|
||||
EXPORT void gs_set_viewport(int x, int y, int width, int height);
|
||||
EXPORT void gs_get_viewport(struct gs_rect *rect);
|
||||
EXPORT void gs_set_scissor_rect(const struct gs_rect *rect);
|
||||
|
||||
EXPORT void gs_ortho(float left, float right, float top, float bottom,
|
||||
float znear, float zfar);
|
||||
float znear, float zfar);
|
||||
EXPORT void gs_frustum(float left, float right, float top, float bottom,
|
||||
float znear, float zfar);
|
||||
float znear, float zfar);
|
||||
|
||||
EXPORT void gs_projection_push(void);
|
||||
EXPORT void gs_projection_pop(void);
|
||||
|
||||
EXPORT void gs_swapchain_destroy(gs_swapchain_t *swapchain);
|
||||
EXPORT void gs_swapchain_destroy(gs_swapchain_t *swapchain);
|
||||
|
||||
EXPORT void gs_texture_destroy(gs_texture_t *tex);
|
||||
EXPORT void gs_texture_destroy(gs_texture_t *tex);
|
||||
EXPORT uint32_t gs_texture_get_width(const gs_texture_t *tex);
|
||||
EXPORT uint32_t gs_texture_get_height(const gs_texture_t *tex);
|
||||
EXPORT enum gs_color_format gs_texture_get_color_format(
|
||||
const gs_texture_t *tex);
|
||||
EXPORT bool gs_texture_map(gs_texture_t *tex, uint8_t **ptr,
|
||||
uint32_t *linesize);
|
||||
EXPORT void gs_texture_unmap(gs_texture_t *tex);
|
||||
EXPORT enum gs_color_format
|
||||
gs_texture_get_color_format(const gs_texture_t *tex);
|
||||
EXPORT bool gs_texture_map(gs_texture_t *tex, uint8_t **ptr,
|
||||
uint32_t *linesize);
|
||||
EXPORT void gs_texture_unmap(gs_texture_t *tex);
|
||||
/** special-case function (GL only) - specifies whether the texture is a
|
||||
* GL_TEXTURE_RECTANGLE type, which doesn't use normalized texture
|
||||
* coordinates, doesn't support mipmapping, and requires address clamping */
|
||||
EXPORT bool gs_texture_is_rect(const gs_texture_t *tex);
|
||||
EXPORT bool gs_texture_is_rect(const gs_texture_t *tex);
|
||||
/**
|
||||
* Gets a pointer to the context-specific object associated with the texture.
|
||||
* For example, for GL, this is a GLuint*. For D3D11, ID3D11Texture2D*.
|
||||
*/
|
||||
EXPORT void *gs_texture_get_obj(gs_texture_t *tex);
|
||||
EXPORT void *gs_texture_get_obj(gs_texture_t *tex);
|
||||
|
||||
EXPORT void gs_cubetexture_destroy(gs_texture_t *cubetex);
|
||||
EXPORT void gs_cubetexture_destroy(gs_texture_t *cubetex);
|
||||
EXPORT uint32_t gs_cubetexture_get_size(const gs_texture_t *cubetex);
|
||||
EXPORT enum gs_color_format gs_cubetexture_get_color_format(
|
||||
const gs_texture_t *cubetex);
|
||||
EXPORT enum gs_color_format
|
||||
gs_cubetexture_get_color_format(const gs_texture_t *cubetex);
|
||||
|
||||
EXPORT void gs_voltexture_destroy(gs_texture_t *voltex);
|
||||
EXPORT void gs_voltexture_destroy(gs_texture_t *voltex);
|
||||
EXPORT uint32_t gs_voltexture_get_width(const gs_texture_t *voltex);
|
||||
EXPORT uint32_t gs_voltexture_get_height(const gs_texture_t *voltex);
|
||||
EXPORT uint32_t gs_voltexture_get_depth(const gs_texture_t *voltex);
|
||||
EXPORT enum gs_color_format gs_voltexture_get_color_format(
|
||||
const gs_texture_t *voltex);
|
||||
EXPORT enum gs_color_format
|
||||
gs_voltexture_get_color_format(const gs_texture_t *voltex);
|
||||
|
||||
EXPORT void gs_stagesurface_destroy(gs_stagesurf_t *stagesurf);
|
||||
EXPORT void gs_stagesurface_destroy(gs_stagesurf_t *stagesurf);
|
||||
EXPORT uint32_t gs_stagesurface_get_width(const gs_stagesurf_t *stagesurf);
|
||||
EXPORT uint32_t gs_stagesurface_get_height(const gs_stagesurf_t *stagesurf);
|
||||
EXPORT enum gs_color_format gs_stagesurface_get_color_format(
|
||||
const gs_stagesurf_t *stagesurf);
|
||||
EXPORT bool gs_stagesurface_map(gs_stagesurf_t *stagesurf, uint8_t **data,
|
||||
uint32_t *linesize);
|
||||
EXPORT void gs_stagesurface_unmap(gs_stagesurf_t *stagesurf);
|
||||
EXPORT enum gs_color_format
|
||||
gs_stagesurface_get_color_format(const gs_stagesurf_t *stagesurf);
|
||||
EXPORT bool gs_stagesurface_map(gs_stagesurf_t *stagesurf, uint8_t **data,
|
||||
uint32_t *linesize);
|
||||
EXPORT void gs_stagesurface_unmap(gs_stagesurf_t *stagesurf);
|
||||
|
||||
EXPORT void gs_zstencil_destroy(gs_zstencil_t *zstencil);
|
||||
EXPORT void gs_zstencil_destroy(gs_zstencil_t *zstencil);
|
||||
|
||||
EXPORT void gs_samplerstate_destroy(gs_samplerstate_t *samplerstate);
|
||||
EXPORT void gs_samplerstate_destroy(gs_samplerstate_t *samplerstate);
|
||||
|
||||
EXPORT void gs_vertexbuffer_destroy(gs_vertbuffer_t *vertbuffer);
|
||||
EXPORT void gs_vertexbuffer_flush(gs_vertbuffer_t *vertbuffer);
|
||||
EXPORT void gs_vertexbuffer_flush_direct(gs_vertbuffer_t *vertbuffer,
|
||||
const struct gs_vb_data *data);
|
||||
EXPORT struct gs_vb_data *gs_vertexbuffer_get_data(
|
||||
const gs_vertbuffer_t *vertbuffer);
|
||||
EXPORT void gs_vertexbuffer_destroy(gs_vertbuffer_t *vertbuffer);
|
||||
EXPORT void gs_vertexbuffer_flush(gs_vertbuffer_t *vertbuffer);
|
||||
EXPORT void gs_vertexbuffer_flush_direct(gs_vertbuffer_t *vertbuffer,
|
||||
const struct gs_vb_data *data);
|
||||
EXPORT struct gs_vb_data *
|
||||
gs_vertexbuffer_get_data(const gs_vertbuffer_t *vertbuffer);
|
||||
|
||||
EXPORT void gs_indexbuffer_destroy(gs_indexbuffer_t *indexbuffer);
|
||||
EXPORT void gs_indexbuffer_flush(gs_indexbuffer_t *indexbuffer);
|
||||
EXPORT void gs_indexbuffer_flush_direct(gs_indexbuffer_t *indexbuffer,
|
||||
const void *data);
|
||||
EXPORT void *gs_indexbuffer_get_data(const gs_indexbuffer_t *indexbuffer);
|
||||
EXPORT size_t gs_indexbuffer_get_num_indices(
|
||||
const gs_indexbuffer_t *indexbuffer);
|
||||
EXPORT enum gs_index_type gs_indexbuffer_get_type(
|
||||
const gs_indexbuffer_t *indexbuffer);
|
||||
EXPORT void gs_indexbuffer_destroy(gs_indexbuffer_t *indexbuffer);
|
||||
EXPORT void gs_indexbuffer_flush(gs_indexbuffer_t *indexbuffer);
|
||||
EXPORT void gs_indexbuffer_flush_direct(gs_indexbuffer_t *indexbuffer,
|
||||
const void *data);
|
||||
EXPORT void *gs_indexbuffer_get_data(const gs_indexbuffer_t *indexbuffer);
|
||||
EXPORT size_t
|
||||
gs_indexbuffer_get_num_indices(const gs_indexbuffer_t *indexbuffer);
|
||||
EXPORT enum gs_index_type
|
||||
gs_indexbuffer_get_type(const gs_indexbuffer_t *indexbuffer);
|
||||
|
||||
EXPORT bool gs_nv12_available(void);
|
||||
EXPORT void gs_timer_destroy(gs_timer_t *timer);
|
||||
EXPORT void gs_timer_begin(gs_timer_t *timer);
|
||||
EXPORT void gs_timer_end(gs_timer_t *timer);
|
||||
EXPORT bool gs_timer_get_data(gs_timer_t *timer, uint64_t *ticks);
|
||||
EXPORT void gs_timer_range_destroy(gs_timer_range_t *timer);
|
||||
EXPORT void gs_timer_range_begin(gs_timer_range_t *range);
|
||||
EXPORT void gs_timer_range_end(gs_timer_range_t *range);
|
||||
EXPORT bool gs_timer_range_get_data(gs_timer_range_t *range, bool *disjoint,
|
||||
uint64_t *frequency);
|
||||
|
||||
EXPORT bool gs_nv12_available(void);
|
||||
|
||||
#define GS_USE_DEBUG_MARKERS 0
|
||||
#if GS_USE_DEBUG_MARKERS
|
||||
static const float GS_DEBUG_COLOR_DEFAULT[] = { 0.5f, 0.5f, 0.5f, 1.0f };
|
||||
static const float GS_DEBUG_COLOR_RENDER_VIDEO[] = { 0.0f, 0.5f, 0.0f, 1.0f };
|
||||
static const float GS_DEBUG_COLOR_MAIN_TEXTURE[] = { 0.0f, 0.25f, 0.0f, 1.0f };
|
||||
static const float GS_DEBUG_COLOR_DISPLAY[] = { 0.0f, 0.5f, 0.5f, 1.0f };
|
||||
static const float GS_DEBUG_COLOR_SOURCE[] = { 0.0f, 0.5f, 5.0f, 1.0f };
|
||||
static const float GS_DEBUG_COLOR_ITEM[] = { 0.5f, 0.0f, 0.0f, 1.0f };
|
||||
static const float GS_DEBUG_COLOR_ITEM_TEXTURE[] = { 0.25f, 0.0f, 0.0f, 1.0f };
|
||||
static const float GS_DEBUG_COLOR_CONVERT_FORMAT[] = { 0.5f, 0.5f, 0.0f, 1.0f };
|
||||
static const float GS_DEBUG_COLOR_DEFAULT[] = {0.5f, 0.5f, 0.5f, 1.0f};
|
||||
static const float GS_DEBUG_COLOR_RENDER_VIDEO[] = {0.0f, 0.5f, 0.0f, 1.0f};
|
||||
static const float GS_DEBUG_COLOR_MAIN_TEXTURE[] = {0.0f, 0.25f, 0.0f, 1.0f};
|
||||
static const float GS_DEBUG_COLOR_DISPLAY[] = {0.0f, 0.5f, 0.5f, 1.0f};
|
||||
static const float GS_DEBUG_COLOR_SOURCE[] = {0.0f, 0.5f, 5.0f, 1.0f};
|
||||
static const float GS_DEBUG_COLOR_ITEM[] = {0.5f, 0.0f, 0.0f, 1.0f};
|
||||
static const float GS_DEBUG_COLOR_ITEM_TEXTURE[] = {0.25f, 0.0f, 0.0f, 1.0f};
|
||||
static const float GS_DEBUG_COLOR_CONVERT_FORMAT[] = {0.5f, 0.5f, 0.0f, 1.0f};
|
||||
#define GS_DEBUG_MARKER_BEGIN(color, markername) \
|
||||
gs_debug_marker_begin(color, markername)
|
||||
gs_debug_marker_begin(color, markername)
|
||||
#define GS_DEBUG_MARKER_BEGIN_FORMAT(color, format, ...) \
|
||||
gs_debug_marker_begin_format(color, format, \
|
||||
__VA_ARGS__)
|
||||
gs_debug_marker_begin_format(color, format, __VA_ARGS__)
|
||||
#define GS_DEBUG_MARKER_END() gs_debug_marker_end()
|
||||
#else
|
||||
#define GS_DEBUG_MARKER_BEGIN(color, markername) ((void)0)
|
||||
|
|
@ -783,19 +813,17 @@ static const float GS_DEBUG_COLOR_CONVERT_FORMAT[] = { 0.5f, 0.5f, 0.0f, 1.0f };
|
|||
#define GS_DEBUG_MARKER_END() ((void)0)
|
||||
#endif
|
||||
|
||||
EXPORT void gs_debug_marker_begin(const float color[4],
|
||||
const char *markername);
|
||||
EXPORT void gs_debug_marker_begin_format(const float color[4],
|
||||
const char *format, ...);
|
||||
EXPORT void gs_debug_marker_end(void);
|
||||
EXPORT void gs_debug_marker_begin(const float color[4], const char *markername);
|
||||
EXPORT void gs_debug_marker_begin_format(const float color[4],
|
||||
const char *format, ...);
|
||||
EXPORT void gs_debug_marker_end(void);
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
/** platform specific function for creating (GL_TEXTURE_RECTANGLE) textures
|
||||
* from shared surface resources */
|
||||
EXPORT gs_texture_t *gs_texture_create_from_iosurface(void *iosurf);
|
||||
EXPORT bool gs_texture_rebind_iosurface(gs_texture_t *texture,
|
||||
void *iosurf);
|
||||
EXPORT bool gs_texture_rebind_iosurface(gs_texture_t *texture, void *iosurf);
|
||||
|
||||
#elif _WIN32
|
||||
|
||||
|
|
@ -809,8 +837,9 @@ typedef struct gs_duplicator gs_duplicator_t;
|
|||
* Gets information about the monitor at the specific index, returns false
|
||||
* when there is no monitor at the specified index
|
||||
*/
|
||||
EXPORT bool gs_get_duplicator_monitor_info(int monitor_idx,
|
||||
struct gs_monitor_info *monitor_info);
|
||||
EXPORT bool
|
||||
gs_get_duplicator_monitor_info(int monitor_idx,
|
||||
struct gs_monitor_info *monitor_info);
|
||||
|
||||
/** creates a windows 8+ output duplicator (monitor capture) */
|
||||
EXPORT gs_duplicator_t *gs_duplicator_create(int monitor_idx);
|
||||
|
|
@ -828,16 +857,17 @@ EXPORT void gs_texture_release_dc(gs_texture_t *gdi_tex);
|
|||
/** creates a windows shared texture from a texture handle */
|
||||
EXPORT gs_texture_t *gs_texture_open_shared(uint32_t handle);
|
||||
|
||||
#define GS_INVALID_HANDLE (uint32_t)-1
|
||||
#define GS_INVALID_HANDLE (uint32_t) - 1
|
||||
EXPORT uint32_t gs_texture_get_shared_handle(gs_texture_t *tex);
|
||||
|
||||
#define GS_WAIT_INFINITE (uint32_t)-1
|
||||
#define GS_WAIT_INFINITE (uint32_t) - 1
|
||||
|
||||
/**
|
||||
* acquires a lock on a keyed mutex texture.
|
||||
* returns -1 on generic failure, ETIMEDOUT if timed out
|
||||
*/
|
||||
EXPORT int gs_texture_acquire_sync(gs_texture_t *tex, uint64_t key, uint32_t ms);
|
||||
EXPORT int gs_texture_acquire_sync(gs_texture_t *tex, uint64_t key,
|
||||
uint32_t ms);
|
||||
|
||||
/**
|
||||
* releases a lock on a keyed mutex texture to another device.
|
||||
|
|
@ -846,10 +876,11 @@ EXPORT int gs_texture_acquire_sync(gs_texture_t *tex, uint64_t key, uint32_t ms)
|
|||
EXPORT int gs_texture_release_sync(gs_texture_t *tex, uint64_t key);
|
||||
|
||||
EXPORT bool gs_texture_create_nv12(gs_texture_t **tex_y, gs_texture_t **tex_uv,
|
||||
uint32_t width, uint32_t height, uint32_t flags);
|
||||
uint32_t width, uint32_t height,
|
||||
uint32_t flags);
|
||||
|
||||
EXPORT gs_stagesurf_t *gs_stagesurface_create_nv12(
|
||||
uint32_t width, uint32_t height);
|
||||
EXPORT gs_stagesurf_t *gs_stagesurface_create_nv12(uint32_t width,
|
||||
uint32_t height);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -858,25 +889,44 @@ EXPORT gs_stagesurf_t *gs_stagesurface_create_nv12(
|
|||
static inline uint32_t gs_get_format_bpp(enum gs_color_format format)
|
||||
{
|
||||
switch (format) {
|
||||
case GS_A8: return 8;
|
||||
case GS_R8: return 8;
|
||||
case GS_RGBA: return 32;
|
||||
case GS_BGRX: return 32;
|
||||
case GS_BGRA: return 32;
|
||||
case GS_R10G10B10A2: return 32;
|
||||
case GS_RGBA16: return 64;
|
||||
case GS_R16: return 16;
|
||||
case GS_RGBA16F: return 64;
|
||||
case GS_RGBA32F: return 128;
|
||||
case GS_RG16F: return 32;
|
||||
case GS_RG32F: return 64;
|
||||
case GS_R16F: return 16;
|
||||
case GS_R32F: return 32;
|
||||
case GS_DXT1: return 4;
|
||||
case GS_DXT3: return 8;
|
||||
case GS_DXT5: return 8;
|
||||
case GS_R8G8: return 16;
|
||||
case GS_UNKNOWN: return 0;
|
||||
case GS_A8:
|
||||
return 8;
|
||||
case GS_R8:
|
||||
return 8;
|
||||
case GS_RGBA:
|
||||
return 32;
|
||||
case GS_BGRX:
|
||||
return 32;
|
||||
case GS_BGRA:
|
||||
return 32;
|
||||
case GS_R10G10B10A2:
|
||||
return 32;
|
||||
case GS_RGBA16:
|
||||
return 64;
|
||||
case GS_R16:
|
||||
return 16;
|
||||
case GS_RGBA16F:
|
||||
return 64;
|
||||
case GS_RGBA32F:
|
||||
return 128;
|
||||
case GS_RG16F:
|
||||
return 32;
|
||||
case GS_RG32F:
|
||||
return 64;
|
||||
case GS_R16F:
|
||||
return 16;
|
||||
case GS_R32F:
|
||||
return 32;
|
||||
case GS_DXT1:
|
||||
return 4;
|
||||
case GS_DXT3:
|
||||
return 8;
|
||||
case GS_DXT5:
|
||||
return 8;
|
||||
case GS_R8G8:
|
||||
return 16;
|
||||
case GS_UNKNOWN:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ static bool bi_def_bitmap_test_opaque(void *bitmap)
|
|||
|
||||
static unsigned char *bi_def_bitmap_get_buffer(void *bitmap)
|
||||
{
|
||||
return (unsigned char*)bitmap;
|
||||
return (unsigned char *)bitmap;
|
||||
}
|
||||
|
||||
static void bi_def_bitmap_destroy(void *bitmap)
|
||||
|
|
@ -56,11 +56,12 @@ static void bi_def_bitmap_modified(void *bitmap)
|
|||
|
||||
static inline int get_full_decoded_gif_size(gs_image_file_t *image)
|
||||
{
|
||||
return image->gif.width * image->gif.height * 4 * image->gif.frame_count;
|
||||
return image->gif.width * image->gif.height * 4 *
|
||||
image->gif.frame_count;
|
||||
}
|
||||
|
||||
static inline void *alloc_mem(gs_image_file_t *image, uint64_t *mem_usage,
|
||||
size_t size)
|
||||
size_t size)
|
||||
{
|
||||
UNUSED_PARAMETER(image);
|
||||
|
||||
|
|
@ -70,7 +71,7 @@ static inline void *alloc_mem(gs_image_file_t *image, uint64_t *mem_usage,
|
|||
}
|
||||
|
||||
static bool init_animated_gif(gs_image_file_t *image, const char *path,
|
||||
uint64_t *mem_usage)
|
||||
uint64_t *mem_usage)
|
||||
{
|
||||
bool is_animated_gif = true;
|
||||
gif_result result;
|
||||
|
|
@ -107,24 +108,26 @@ static bool init_animated_gif(gs_image_file_t *image, const char *path,
|
|||
do {
|
||||
result = gif_initialise(&image->gif, size, image->gif_data);
|
||||
if (result < 0) {
|
||||
blog(LOG_WARNING, "Failed to initialize gif '%s', "
|
||||
"possible file corruption", path);
|
||||
blog(LOG_WARNING,
|
||||
"Failed to initialize gif '%s', "
|
||||
"possible file corruption",
|
||||
path);
|
||||
goto fail;
|
||||
}
|
||||
} while (result != GIF_OK);
|
||||
|
||||
if (image->gif.width > 4096 || image->gif.height > 4096) {
|
||||
blog(LOG_WARNING, "Bad texture dimensions (%dx%d) in '%s'",
|
||||
image->gif.width, image->gif.height, path);
|
||||
image->gif.width, image->gif.height, path);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
max_size = (uint64_t)image->gif.width * (uint64_t)image->gif.height *
|
||||
(uint64_t)image->gif.frame_count * 4LLU;
|
||||
(uint64_t)image->gif.frame_count * 4LLU;
|
||||
|
||||
if ((uint64_t)get_full_decoded_gif_size(image) != max_size) {
|
||||
blog(LOG_WARNING, "Gif '%s' overflowed maximum pointer size",
|
||||
path);
|
||||
path);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
@ -132,15 +135,18 @@ static bool init_animated_gif(gs_image_file_t *image, const char *path,
|
|||
if (image->is_animated_gif) {
|
||||
gif_decode_frame(&image->gif, 0);
|
||||
|
||||
image->animation_frame_cache = alloc_mem(image, mem_usage,
|
||||
image->gif.frame_count * sizeof(uint8_t*));
|
||||
image->animation_frame_data = alloc_mem(image, mem_usage,
|
||||
get_full_decoded_gif_size(image));
|
||||
image->animation_frame_cache =
|
||||
alloc_mem(image, mem_usage,
|
||||
image->gif.frame_count * sizeof(uint8_t *));
|
||||
image->animation_frame_data = alloc_mem(
|
||||
image, mem_usage, get_full_decoded_gif_size(image));
|
||||
|
||||
for (unsigned int i = 0; i < image->gif.frame_count; i++) {
|
||||
if (gif_decode_frame(&image->gif, i) != GIF_OK)
|
||||
blog(LOG_WARNING, "Couldn't decode frame %u "
|
||||
"of '%s'", i, path);
|
||||
blog(LOG_WARNING,
|
||||
"Couldn't decode frame %u "
|
||||
"of '%s'",
|
||||
i, path);
|
||||
}
|
||||
|
||||
gif_decode_frame(&image->gif, 0);
|
||||
|
|
@ -174,7 +180,7 @@ not_animated:
|
|||
}
|
||||
|
||||
static void gs_image_file_init_internal(gs_image_file_t *image,
|
||||
const char *file, uint64_t *mem_usage)
|
||||
const char *file, uint64_t *mem_usage)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
|
|
@ -193,12 +199,12 @@ static void gs_image_file_init_internal(gs_image_file_t *image,
|
|||
return;
|
||||
}
|
||||
|
||||
image->texture_data = gs_create_texture_file_data(file,
|
||||
&image->format, &image->cx, &image->cy);
|
||||
image->texture_data = gs_create_texture_file_data(
|
||||
file, &image->format, &image->cx, &image->cy);
|
||||
|
||||
if (mem_usage) {
|
||||
*mem_usage += image->cx * image->cy *
|
||||
gs_get_format_bpp(image->format) / 8;
|
||||
gs_get_format_bpp(image->format) / 8;
|
||||
}
|
||||
|
||||
image->loaded = !!image->texture_data;
|
||||
|
|
@ -245,14 +251,13 @@ void gs_image_file_init_texture(gs_image_file_t *image)
|
|||
|
||||
if (image->is_animated_gif) {
|
||||
image->texture = gs_texture_create(
|
||||
image->cx, image->cy, image->format, 1,
|
||||
(const uint8_t**)&image->gif.frame_image,
|
||||
GS_DYNAMIC);
|
||||
image->cx, image->cy, image->format, 1,
|
||||
(const uint8_t **)&image->gif.frame_image, GS_DYNAMIC);
|
||||
|
||||
} else {
|
||||
image->texture = gs_texture_create(
|
||||
image->cx, image->cy, image->format, 1,
|
||||
(const uint8_t**)&image->texture_data, 0);
|
||||
image->cx, image->cy, image->format, 1,
|
||||
(const uint8_t **)&image->texture_data, 0);
|
||||
bfree(image->texture_data);
|
||||
image->texture_data = NULL;
|
||||
}
|
||||
|
|
@ -267,7 +272,7 @@ static inline uint64_t get_time(gs_image_file_t *image, int i)
|
|||
}
|
||||
|
||||
static inline int calculate_new_frame(gs_image_file_t *image,
|
||||
uint64_t elapsed_time_ns, int loops)
|
||||
uint64_t elapsed_time_ns, int loops)
|
||||
{
|
||||
int new_frame = image->cur_frame;
|
||||
|
||||
|
|
@ -297,8 +302,9 @@ static void decode_new_frame(gs_image_file_t *image, int new_frame)
|
|||
int last_frame;
|
||||
|
||||
/* if looped, decode frame 0 */
|
||||
last_frame = (new_frame < image->last_decoded_frame) ?
|
||||
0 : image->last_decoded_frame + 1;
|
||||
last_frame = (new_frame < image->last_decoded_frame)
|
||||
? 0
|
||||
: image->last_decoded_frame + 1;
|
||||
|
||||
/* decode missed frames */
|
||||
for (int i = last_frame; i < new_frame; i++) {
|
||||
|
|
@ -309,14 +315,13 @@ static void decode_new_frame(gs_image_file_t *image, int new_frame)
|
|||
/* decode actual desired frame */
|
||||
if (gif_decode_frame(&image->gif, new_frame) == GIF_OK) {
|
||||
size_t pos = new_frame * image->gif.width *
|
||||
image->gif.height * 4;
|
||||
image->gif.height * 4;
|
||||
image->animation_frame_cache[new_frame] =
|
||||
image->animation_frame_data + pos;
|
||||
|
||||
memcpy(image->animation_frame_cache[new_frame],
|
||||
image->gif.frame_image,
|
||||
image->gif.width *
|
||||
image->gif.height * 4);
|
||||
image->gif.frame_image,
|
||||
image->gif.width * image->gif.height * 4);
|
||||
|
||||
image->last_decoded_frame = new_frame;
|
||||
}
|
||||
|
|
@ -337,8 +342,8 @@ bool gs_image_file_tick(gs_image_file_t *image, uint64_t elapsed_time_ns)
|
|||
loops = 0;
|
||||
|
||||
if (!loops || image->cur_loop < loops) {
|
||||
int new_frame = calculate_new_frame(image, elapsed_time_ns,
|
||||
loops);
|
||||
int new_frame =
|
||||
calculate_new_frame(image, elapsed_time_ns, loops);
|
||||
|
||||
if (new_frame != image->cur_frame) {
|
||||
decode_new_frame(image, new_frame);
|
||||
|
|
@ -358,6 +363,6 @@ void gs_image_file_update_texture(gs_image_file_t *image)
|
|||
decode_new_frame(image, image->cur_frame);
|
||||
|
||||
gs_texture_set_image(image->texture,
|
||||
image->animation_frame_cache[image->cur_frame],
|
||||
image->gif.width * 4, false);
|
||||
image->animation_frame_cache[image->cur_frame],
|
||||
image->gif.width * 4, false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ EXPORT void gs_image_file_free(gs_image_file_t *image);
|
|||
|
||||
EXPORT void gs_image_file_init_texture(gs_image_file_t *image);
|
||||
EXPORT bool gs_image_file_tick(gs_image_file_t *image,
|
||||
uint64_t elapsed_time_ns);
|
||||
uint64_t elapsed_time_ns);
|
||||
EXPORT void gs_image_file_update_texture(gs_image_file_t *image);
|
||||
|
||||
EXPORT void gs_image_file2_init(gs_image_file2_t *if2, const char *file);
|
||||
|
|
@ -76,7 +76,7 @@ static inline void gs_image_file2_init_texture(gs_image_file2_t *if2)
|
|||
}
|
||||
|
||||
static inline bool gs_image_file2_tick(gs_image_file2_t *if2,
|
||||
uint64_t elapsed_time_ns)
|
||||
uint64_t elapsed_time_ns)
|
||||
{
|
||||
return gs_image_file_tick(&if2->image, elapsed_time_ns);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,123 +23,123 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define KBC_ESCAPE 0x0
|
||||
#define KBC_1 0x1
|
||||
#define KBC_2 0x2
|
||||
#define KBC_3 0x3
|
||||
#define KBC_4 0x4
|
||||
#define KBC_5 0x5
|
||||
#define KBC_6 0x6
|
||||
#define KBC_7 0x7
|
||||
#define KBC_8 0x8
|
||||
#define KBC_9 0x9
|
||||
#define KBC_0 0xA
|
||||
#define KBC_MINUS 0xB
|
||||
#define KBC_EQUALS 0xC
|
||||
#define KBC_BACK 0xD
|
||||
#define KBC_TAB 0xE
|
||||
#define KBC_Q 0xF
|
||||
#define KBC_W 0x10
|
||||
#define KBC_E 0x11
|
||||
#define KBC_R 0x12
|
||||
#define KBC_T 0x13
|
||||
#define KBC_Y 0x14
|
||||
#define KBC_U 0x15
|
||||
#define KBC_I 0x16
|
||||
#define KBC_O 0x17
|
||||
#define KBC_P 0x18
|
||||
#define KBC_LBRACKET 0x19
|
||||
#define KBC_RBRACKET 0x1A
|
||||
#define KBC_RETURN 0x1B
|
||||
#define KBC_LCONTROL 0x1C
|
||||
#define KBC_A 0x1D
|
||||
#define KBC_S 0x1E
|
||||
#define KBC_D 0x1F
|
||||
#define KBC_F 0x20
|
||||
#define KBC_G 0x21
|
||||
#define KBC_H 0x22
|
||||
#define KBC_J 0x23
|
||||
#define KBC_K 0x24
|
||||
#define KBC_L 0x25
|
||||
#define KBC_SEMICOLON 0x26
|
||||
#define KBC_APOSTROPHE 0x27
|
||||
#define KBC_TILDE 0x28
|
||||
#define KBC_LSHIFT 0x29
|
||||
#define KBC_BACKSLASH 0x2A
|
||||
#define KBC_Z 0x2B
|
||||
#define KBC_X 0x2C
|
||||
#define KBC_C 0x2D
|
||||
#define KBC_V 0x2E
|
||||
#define KBC_B 0x2F
|
||||
#define KBC_N 0x30
|
||||
#define KBC_M 0x31
|
||||
#define KBC_COMMA 0x32
|
||||
#define KBC_PERIOD 0x33
|
||||
#define KBC_SLASH 0x34
|
||||
#define KBC_RSHIFT 0x35
|
||||
#define KBC_MULTIPLY 0x36
|
||||
#define KBC_LALT 0x37
|
||||
#define KBC_SPACE 0x38
|
||||
#define KBC_CAPSLOCK 0x39
|
||||
#define KBC_F1 0x3A
|
||||
#define KBC_F2 0x3B
|
||||
#define KBC_F3 0x3C
|
||||
#define KBC_F4 0x3D
|
||||
#define KBC_F5 0x3E
|
||||
#define KBC_F6 0x3F
|
||||
#define KBC_F7 0x40
|
||||
#define KBC_F8 0x41
|
||||
#define KBC_F9 0x42
|
||||
#define KBC_F10 0x43
|
||||
#define KBC_NUMLOCK 0x44
|
||||
#define KBC_SCROLLLOCK 0x45
|
||||
#define KBC_NUMPAD7 0x46
|
||||
#define KBC_NUMPAD8 0x47
|
||||
#define KBC_NUMPAD9 0x48
|
||||
#define KBC_SUBTRACT 0x49
|
||||
#define KBC_NUMPAD4 0x4A
|
||||
#define KBC_NUMPAD5 0x4B
|
||||
#define KBC_NUMPAD6 0x4C
|
||||
#define KBC_ADD 0x4D
|
||||
#define KBC_NUMPAD1 0x4E
|
||||
#define KBC_NUMPAD2 0x4F
|
||||
#define KBC_NUMPAD3 0x50
|
||||
#define KBC_NUMPAD0 0x51
|
||||
#define KBC_DECIMAL 0x52
|
||||
#define KBC_F11 0x53
|
||||
#define KBC_F12 0x54
|
||||
#define KBC_NUMPADENTER 0x55
|
||||
#define KBC_RCONTROL 0x56
|
||||
#define KBC_DIVIDE 0x57
|
||||
#define KBC_SYSRQ 0x58
|
||||
#define KBC_RALT 0x59
|
||||
#define KBC_PAUSE 0x5A
|
||||
#define KBC_HOME 0x5B
|
||||
#define KBC_UP 0x5C
|
||||
#define KBC_PAGEDOWN 0x5D
|
||||
#define KBC_LEFT 0x5E
|
||||
#define KBC_RIGHT 0x5F
|
||||
#define KBC_END 0x60
|
||||
#define KBC_DOWN 0x61
|
||||
#define KBC_PAGEUP 0x62
|
||||
#define KBC_INSERT 0x63
|
||||
#define KBC_DELETE 0x64
|
||||
#define KBC_ESCAPE 0x0
|
||||
#define KBC_1 0x1
|
||||
#define KBC_2 0x2
|
||||
#define KBC_3 0x3
|
||||
#define KBC_4 0x4
|
||||
#define KBC_5 0x5
|
||||
#define KBC_6 0x6
|
||||
#define KBC_7 0x7
|
||||
#define KBC_8 0x8
|
||||
#define KBC_9 0x9
|
||||
#define KBC_0 0xA
|
||||
#define KBC_MINUS 0xB
|
||||
#define KBC_EQUALS 0xC
|
||||
#define KBC_BACK 0xD
|
||||
#define KBC_TAB 0xE
|
||||
#define KBC_Q 0xF
|
||||
#define KBC_W 0x10
|
||||
#define KBC_E 0x11
|
||||
#define KBC_R 0x12
|
||||
#define KBC_T 0x13
|
||||
#define KBC_Y 0x14
|
||||
#define KBC_U 0x15
|
||||
#define KBC_I 0x16
|
||||
#define KBC_O 0x17
|
||||
#define KBC_P 0x18
|
||||
#define KBC_LBRACKET 0x19
|
||||
#define KBC_RBRACKET 0x1A
|
||||
#define KBC_RETURN 0x1B
|
||||
#define KBC_LCONTROL 0x1C
|
||||
#define KBC_A 0x1D
|
||||
#define KBC_S 0x1E
|
||||
#define KBC_D 0x1F
|
||||
#define KBC_F 0x20
|
||||
#define KBC_G 0x21
|
||||
#define KBC_H 0x22
|
||||
#define KBC_J 0x23
|
||||
#define KBC_K 0x24
|
||||
#define KBC_L 0x25
|
||||
#define KBC_SEMICOLON 0x26
|
||||
#define KBC_APOSTROPHE 0x27
|
||||
#define KBC_TILDE 0x28
|
||||
#define KBC_LSHIFT 0x29
|
||||
#define KBC_BACKSLASH 0x2A
|
||||
#define KBC_Z 0x2B
|
||||
#define KBC_X 0x2C
|
||||
#define KBC_C 0x2D
|
||||
#define KBC_V 0x2E
|
||||
#define KBC_B 0x2F
|
||||
#define KBC_N 0x30
|
||||
#define KBC_M 0x31
|
||||
#define KBC_COMMA 0x32
|
||||
#define KBC_PERIOD 0x33
|
||||
#define KBC_SLASH 0x34
|
||||
#define KBC_RSHIFT 0x35
|
||||
#define KBC_MULTIPLY 0x36
|
||||
#define KBC_LALT 0x37
|
||||
#define KBC_SPACE 0x38
|
||||
#define KBC_CAPSLOCK 0x39
|
||||
#define KBC_F1 0x3A
|
||||
#define KBC_F2 0x3B
|
||||
#define KBC_F3 0x3C
|
||||
#define KBC_F4 0x3D
|
||||
#define KBC_F5 0x3E
|
||||
#define KBC_F6 0x3F
|
||||
#define KBC_F7 0x40
|
||||
#define KBC_F8 0x41
|
||||
#define KBC_F9 0x42
|
||||
#define KBC_F10 0x43
|
||||
#define KBC_NUMLOCK 0x44
|
||||
#define KBC_SCROLLLOCK 0x45
|
||||
#define KBC_NUMPAD7 0x46
|
||||
#define KBC_NUMPAD8 0x47
|
||||
#define KBC_NUMPAD9 0x48
|
||||
#define KBC_SUBTRACT 0x49
|
||||
#define KBC_NUMPAD4 0x4A
|
||||
#define KBC_NUMPAD5 0x4B
|
||||
#define KBC_NUMPAD6 0x4C
|
||||
#define KBC_ADD 0x4D
|
||||
#define KBC_NUMPAD1 0x4E
|
||||
#define KBC_NUMPAD2 0x4F
|
||||
#define KBC_NUMPAD3 0x50
|
||||
#define KBC_NUMPAD0 0x51
|
||||
#define KBC_DECIMAL 0x52
|
||||
#define KBC_F11 0x53
|
||||
#define KBC_F12 0x54
|
||||
#define KBC_NUMPADENTER 0x55
|
||||
#define KBC_RCONTROL 0x56
|
||||
#define KBC_DIVIDE 0x57
|
||||
#define KBC_SYSRQ 0x58
|
||||
#define KBC_RALT 0x59
|
||||
#define KBC_PAUSE 0x5A
|
||||
#define KBC_HOME 0x5B
|
||||
#define KBC_UP 0x5C
|
||||
#define KBC_PAGEDOWN 0x5D
|
||||
#define KBC_LEFT 0x5E
|
||||
#define KBC_RIGHT 0x5F
|
||||
#define KBC_END 0x60
|
||||
#define KBC_DOWN 0x61
|
||||
#define KBC_PAGEUP 0x62
|
||||
#define KBC_INSERT 0x63
|
||||
#define KBC_DELETE 0x64
|
||||
|
||||
#define MOUSE_LEFTBUTTON 0x65
|
||||
#define MOUSE_MIDDLEBUTTON 0x66
|
||||
#define MOUSE_RIGHTBUTTON 0x67
|
||||
#define MOUSE_WHEEL 0x68
|
||||
#define MOUSE_MOVE 0x69
|
||||
#define MOUSE_LEFTBUTTON 0x65
|
||||
#define MOUSE_MIDDLEBUTTON 0x66
|
||||
#define MOUSE_RIGHTBUTTON 0x67
|
||||
#define MOUSE_WHEEL 0x68
|
||||
#define MOUSE_MOVE 0x69
|
||||
|
||||
#define KBC_CONTROL 0xFFFFFFFE
|
||||
#define KBC_ALT 0xFFFFFFFD
|
||||
#define KBC_SHIFT 0xFFFFFFFC
|
||||
#define KBC_CONTROL 0xFFFFFFFE
|
||||
#define KBC_ALT 0xFFFFFFFD
|
||||
#define KBC_SHIFT 0xFFFFFFFC
|
||||
|
||||
#define STATE_LBUTTONDOWN (1<<0)
|
||||
#define STATE_RBUTTONDOWN (1<<1)
|
||||
#define STATE_MBUTTONDOWN (1<<2)
|
||||
#define STATE_X4BUTTONDOWN (1<<3)
|
||||
#define STATE_X5BUTTONDOWN (1<<4)
|
||||
#define STATE_LBUTTONDOWN (1 << 0)
|
||||
#define STATE_RBUTTONDOWN (1 << 1)
|
||||
#define STATE_MBUTTONDOWN (1 << 2)
|
||||
#define STATE_X4BUTTONDOWN (1 << 3)
|
||||
#define STATE_X5BUTTONDOWN (1 << 4)
|
||||
|
||||
/* wrapped opaque data types */
|
||||
struct input_subsystem;
|
||||
|
|
|
|||
3
libobs/graphics/libnsgif/.clang-format
Normal file
3
libobs/graphics/libnsgif/.clang-format
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
Language: Cpp
|
||||
SortIncludes: false
|
||||
DisableFormat: true
|
||||
|
|
@ -25,19 +25,19 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932384626433832795f
|
||||
#define M_PI 3.1415926535897932384626433832795f
|
||||
#endif
|
||||
|
||||
#define RAD(val) ((val)*0.0174532925199432957692369076848f)
|
||||
#define DEG(val) ((val)*57.295779513082320876798154814105f)
|
||||
#define LARGE_EPSILON 1e-2f
|
||||
#define EPSILON 1e-4f
|
||||
#define TINY_EPSILON 1e-5f
|
||||
#define M_INFINITE 3.4e38f
|
||||
#define RAD(val) ((val)*0.0174532925199432957692369076848f)
|
||||
#define DEG(val) ((val)*57.295779513082320876798154814105f)
|
||||
#define LARGE_EPSILON 1e-2f
|
||||
#define EPSILON 1e-4f
|
||||
#define TINY_EPSILON 1e-5f
|
||||
#define M_INFINITE 3.4e38f
|
||||
|
||||
static inline bool close_float(float f1, float f2, float precision)
|
||||
{
|
||||
return fabsf(f1-f2) <= precision;
|
||||
return fabsf(f1 - f2) <= precision;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -24,12 +24,12 @@
|
|||
void polar_to_cart(struct vec3 *dst, const struct vec3 *v)
|
||||
{
|
||||
struct vec3 cart;
|
||||
float sinx = cosf(v->x);
|
||||
float sinx_z = v->z * sinx;
|
||||
float sinx = cosf(v->x);
|
||||
float sinx_z = v->z * sinx;
|
||||
|
||||
cart.x = sinx_z * sinf(v->y);
|
||||
cart.z = sinx_z * cosf(v->y);
|
||||
cart.y = v->z * sinf(v->x);
|
||||
cart.y = v->z * sinf(v->x);
|
||||
|
||||
vec3_copy(dst, &cart);
|
||||
}
|
||||
|
|
@ -65,28 +65,28 @@ void polar_to_norm(struct vec3 *dst, const struct vec2 *polar)
|
|||
}
|
||||
|
||||
float calc_torquef(float val1, float val2, float torque, float min_adjust,
|
||||
float t)
|
||||
float t)
|
||||
{
|
||||
float out = val1;
|
||||
float dist;
|
||||
bool over;
|
||||
bool over;
|
||||
|
||||
if (close_float(val1, val2, EPSILON))
|
||||
return val1;
|
||||
|
||||
dist = (val2-val1)*torque;
|
||||
dist = (val2 - val1) * torque;
|
||||
over = dist > 0.0f;
|
||||
|
||||
if (over) {
|
||||
if (dist < min_adjust) /* prevents from going too slow */
|
||||
dist = min_adjust;
|
||||
out += dist*t; /* add torque */
|
||||
if (out > val2) /* clamp if overshoot */
|
||||
out += dist * t; /* add torque */
|
||||
if (out > val2) /* clamp if overshoot */
|
||||
out = val2;
|
||||
} else {
|
||||
if (dist > -min_adjust)
|
||||
dist = -min_adjust;
|
||||
out += dist*t;
|
||||
out += dist * t;
|
||||
if (out < val2)
|
||||
out = val2;
|
||||
}
|
||||
|
|
@ -94,9 +94,8 @@ float calc_torquef(float val1, float val2, float torque, float min_adjust,
|
|||
return out;
|
||||
}
|
||||
|
||||
void calc_torque(struct vec3 *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2, float torque, float min_adjust,
|
||||
float t)
|
||||
void calc_torque(struct vec3 *dst, const struct vec3 *v1, const struct vec3 *v2,
|
||||
float torque, float min_adjust, float t)
|
||||
{
|
||||
struct vec3 line, dir;
|
||||
float orig_dist, torque_dist, adjust_dist;
|
||||
|
|
@ -108,26 +107,26 @@ void calc_torque(struct vec3 *dst, const struct vec3 *v1,
|
|||
|
||||
vec3_sub(&line, v2, v1);
|
||||
orig_dist = vec3_len(&line);
|
||||
vec3_mulf(&dir, &line, 1.0f/orig_dist);
|
||||
vec3_mulf(&dir, &line, 1.0f / orig_dist);
|
||||
|
||||
torque_dist = orig_dist*torque; /* use distance to determine speed */
|
||||
if (torque_dist < min_adjust) /* prevent from going too slow */
|
||||
torque_dist = orig_dist * torque; /* use distance to determine speed */
|
||||
if (torque_dist < min_adjust) /* prevent from going too slow */
|
||||
torque_dist = min_adjust;
|
||||
|
||||
adjust_dist = torque_dist*t;
|
||||
adjust_dist = torque_dist * t;
|
||||
|
||||
if (adjust_dist <= (orig_dist-LARGE_EPSILON)) {
|
||||
if (adjust_dist <= (orig_dist - LARGE_EPSILON)) {
|
||||
vec3_mulf(dst, &dir, adjust_dist);
|
||||
vec3_add(dst, dst, v1); /* add torque */
|
||||
} else {
|
||||
vec3_copy(dst, v2); /* clamp if overshoot */
|
||||
vec3_copy(dst, v2); /* clamp if overshoot */
|
||||
}
|
||||
}
|
||||
|
||||
float rand_float(int positive_only)
|
||||
{
|
||||
if (positive_only)
|
||||
return (float)((double)rand()/(double)RAND_MAX);
|
||||
return (float)((double)rand() / (double)RAND_MAX);
|
||||
else
|
||||
return (float)(((double)rand()/(double)RAND_MAX*2.0)-1.0);
|
||||
return (float)(((double)rand() / (double)RAND_MAX * 2.0) - 1.0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,20 +40,20 @@ EXPORT void norm_to_polar(struct vec2 *dst, const struct vec3 *norm);
|
|||
EXPORT void polar_to_norm(struct vec3 *dst, const struct vec2 *polar);
|
||||
|
||||
EXPORT float calc_torquef(float val1, float val2, float torque,
|
||||
float min_adjust, float t);
|
||||
float min_adjust, float t);
|
||||
|
||||
EXPORT void calc_torque(struct vec3 *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2, float torque, float min_adjust,
|
||||
float t);
|
||||
const struct vec3 *v2, float torque, float min_adjust,
|
||||
float t);
|
||||
|
||||
static inline float get_percentage(float start, float end, float mid)
|
||||
{
|
||||
return (mid-start) / (end-start);
|
||||
return (mid - start) / (end - start);
|
||||
}
|
||||
|
||||
static inline float get_percentagei(int start, int end, int mid)
|
||||
{
|
||||
return (float)(mid-start) / (float)(end-start);
|
||||
return (float)(mid - start) / (float)(end - start);
|
||||
}
|
||||
|
||||
EXPORT float rand_float(int positive_only);
|
||||
|
|
|
|||
|
|
@ -21,11 +21,10 @@
|
|||
#include "plane.h"
|
||||
#include "quat.h"
|
||||
|
||||
|
||||
void matrix3_from_quat(struct matrix3 *dst, const struct quat *q)
|
||||
{
|
||||
float norm = quat_dot(q, q);
|
||||
float s = (norm > 0.0f) ? (2.0f/norm) : 0.0f;
|
||||
float s = (norm > 0.0f) ? (2.0f / norm) : 0.0f;
|
||||
|
||||
float xx = q->x * q->x * s;
|
||||
float yy = q->y * q->y * s;
|
||||
|
|
@ -63,7 +62,7 @@ void matrix3_from_matrix4(struct matrix3 *dst, const struct matrix4 *m)
|
|||
}
|
||||
|
||||
void matrix3_mul(struct matrix3 *dst, const struct matrix3 *m1,
|
||||
const struct matrix3 *m2)
|
||||
const struct matrix3 *m2)
|
||||
{
|
||||
if (dst == m2) {
|
||||
struct matrix3 temp;
|
||||
|
|
@ -81,7 +80,7 @@ void matrix3_mul(struct matrix3 *dst, const struct matrix3 *m1,
|
|||
}
|
||||
|
||||
void matrix3_rotate(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct quat *q)
|
||||
const struct quat *q)
|
||||
{
|
||||
struct matrix3 temp;
|
||||
matrix3_from_quat(&temp, q);
|
||||
|
|
@ -89,7 +88,7 @@ void matrix3_rotate(struct matrix3 *dst, const struct matrix3 *m,
|
|||
}
|
||||
|
||||
void matrix3_rotate_aa(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct axisang *aa)
|
||||
const struct axisang *aa)
|
||||
{
|
||||
struct matrix3 temp;
|
||||
matrix3_from_axisang(&temp, aa);
|
||||
|
|
@ -97,7 +96,7 @@ void matrix3_rotate_aa(struct matrix3 *dst, const struct matrix3 *m,
|
|||
}
|
||||
|
||||
void matrix3_scale(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct vec3 *v)
|
||||
const struct vec3 *v)
|
||||
{
|
||||
vec3_mul(&dst->x, &m->x, v);
|
||||
vec3_mul(&dst->y, &m->y, v);
|
||||
|
|
@ -122,12 +121,12 @@ void matrix3_inv(struct matrix3 *dst, const struct matrix3 *m)
|
|||
{
|
||||
struct matrix4 m4;
|
||||
matrix4_from_matrix3(&m4, m);
|
||||
matrix4_inv((struct matrix4*)dst, &m4);
|
||||
matrix4_inv((struct matrix4 *)dst, &m4);
|
||||
dst->t.w = 0.0f;
|
||||
}
|
||||
|
||||
void matrix3_mirror(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct plane *p)
|
||||
const struct plane *p)
|
||||
{
|
||||
vec3_mirrorv(&dst->x, &m->x, &p->dir);
|
||||
vec3_mirrorv(&dst->y, &m->y, &p->dir);
|
||||
|
|
@ -136,7 +135,7 @@ void matrix3_mirror(struct matrix3 *dst, const struct matrix3 *m,
|
|||
}
|
||||
|
||||
void matrix3_mirrorv(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct vec3 *v)
|
||||
const struct vec3 *v)
|
||||
{
|
||||
vec3_mirrorv(&dst->x, &m->x, v);
|
||||
vec3_mirrorv(&dst->y, &m->y, v);
|
||||
|
|
|
|||
|
|
@ -53,34 +53,35 @@ static inline void matrix3_identity(struct matrix3 *dst)
|
|||
}
|
||||
|
||||
EXPORT void matrix3_from_quat(struct matrix3 *dst, const struct quat *q);
|
||||
EXPORT void matrix3_from_axisang(struct matrix3 *dst,
|
||||
const struct axisang *aa);
|
||||
EXPORT void matrix3_from_axisang(struct matrix3 *dst, const struct axisang *aa);
|
||||
EXPORT void matrix3_from_matrix4(struct matrix3 *dst, const struct matrix4 *m);
|
||||
|
||||
EXPORT void matrix3_mul(struct matrix3 *dst, const struct matrix3 *m1,
|
||||
const struct matrix3 *m2);
|
||||
const struct matrix3 *m2);
|
||||
static inline void matrix3_translate(struct matrix3 *dst,
|
||||
const struct matrix3 *m, const struct vec3 *v)
|
||||
const struct matrix3 *m,
|
||||
const struct vec3 *v)
|
||||
{
|
||||
vec3_sub(&dst->t, &m->t, v);
|
||||
}
|
||||
|
||||
EXPORT void matrix3_rotate(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct quat *q);
|
||||
const struct quat *q);
|
||||
EXPORT void matrix3_rotate_aa(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct axisang *aa);
|
||||
const struct axisang *aa);
|
||||
EXPORT void matrix3_scale(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct vec3 *v);
|
||||
const struct vec3 *v);
|
||||
EXPORT void matrix3_transpose(struct matrix3 *dst, const struct matrix3 *m);
|
||||
EXPORT void matrix3_inv(struct matrix3 *dst, const struct matrix3 *m);
|
||||
|
||||
EXPORT void matrix3_mirror(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct plane *p);
|
||||
const struct plane *p);
|
||||
EXPORT void matrix3_mirrorv(struct matrix3 *dst, const struct matrix3 *m,
|
||||
const struct vec3 *v);
|
||||
const struct vec3 *v);
|
||||
|
||||
static inline void matrix3_translate3f(struct matrix3 *dst,
|
||||
const struct matrix3 *m, float x, float y, float z)
|
||||
const struct matrix3 *m, float x,
|
||||
float y, float z)
|
||||
{
|
||||
struct vec3 v;
|
||||
vec3_set(&v, x, y, z);
|
||||
|
|
@ -88,15 +89,16 @@ static inline void matrix3_translate3f(struct matrix3 *dst,
|
|||
}
|
||||
|
||||
static inline void matrix3_rotate_aa4f(struct matrix3 *dst,
|
||||
const struct matrix3 *m, float x, float y, float z, float rot)
|
||||
const struct matrix3 *m, float x,
|
||||
float y, float z, float rot)
|
||||
{
|
||||
struct axisang aa;
|
||||
axisang_set(&aa, x, y, z, rot);
|
||||
matrix3_rotate_aa(dst, m, &aa);
|
||||
}
|
||||
|
||||
static inline void matrix3_scale3f(struct matrix3 *dst,
|
||||
const struct matrix3 *m, float x, float y, float z)
|
||||
static inline void matrix3_scale3f(struct matrix3 *dst, const struct matrix3 *m,
|
||||
float x, float y, float z)
|
||||
{
|
||||
struct vec3 v;
|
||||
vec3_set(&v, x, y, z);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ void matrix4_from_matrix3(struct matrix4 *dst, const struct matrix3 *m)
|
|||
void matrix4_from_quat(struct matrix4 *dst, const struct quat *q)
|
||||
{
|
||||
float norm = quat_dot(q, q);
|
||||
float s = (norm > 0.0f) ? (2.0f/norm) : 0.0f;
|
||||
float s = (norm > 0.0f) ? (2.0f / norm) : 0.0f;
|
||||
|
||||
float xx = q->x * q->x * s;
|
||||
float yy = q->y * q->y * s;
|
||||
|
|
@ -58,26 +58,27 @@ void matrix4_from_axisang(struct matrix4 *dst, const struct axisang *aa)
|
|||
}
|
||||
|
||||
void matrix4_mul(struct matrix4 *dst, const struct matrix4 *m1,
|
||||
const struct matrix4 *m2)
|
||||
const struct matrix4 *m2)
|
||||
{
|
||||
const struct vec4 *m1v = (const struct vec4*)m1;
|
||||
const float *m2f = (const float*)m2;
|
||||
const struct vec4 *m1v = (const struct vec4 *)m1;
|
||||
const float *m2f = (const float *)m2;
|
||||
struct vec4 out[4];
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j=0; j<4; j++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
struct vec4 temp;
|
||||
vec4_set(&temp, m2f[j], m2f[j+4], m2f[j+8], m2f[j+12]);
|
||||
vec4_set(&temp, m2f[j], m2f[j + 4], m2f[j + 8],
|
||||
m2f[j + 12]);
|
||||
out[i].ptr[j] = vec4_dot(&m1v[i], &temp);
|
||||
}
|
||||
}
|
||||
|
||||
matrix4_copy(dst, (struct matrix4*)out);
|
||||
matrix4_copy(dst, (struct matrix4 *)out);
|
||||
}
|
||||
|
||||
static inline void get_3x3_submatrix(float *dst, const struct matrix4 *m,
|
||||
int i, int j)
|
||||
static inline void get_3x3_submatrix(float *dst, const struct matrix4 *m, int i,
|
||||
int j)
|
||||
{
|
||||
const float *mf = (const float *)m;
|
||||
int ti, tj, idst, jdst;
|
||||
|
|
@ -86,7 +87,7 @@ static inline void get_3x3_submatrix(float *dst, const struct matrix4 *m,
|
|||
if (ti < i)
|
||||
idst = ti;
|
||||
else if (ti > i)
|
||||
idst = ti-1;
|
||||
idst = ti - 1;
|
||||
else
|
||||
continue;
|
||||
|
||||
|
|
@ -94,20 +95,20 @@ static inline void get_3x3_submatrix(float *dst, const struct matrix4 *m,
|
|||
if (tj < j)
|
||||
jdst = tj;
|
||||
else if (tj > j)
|
||||
jdst = tj-1;
|
||||
jdst = tj - 1;
|
||||
else
|
||||
continue;
|
||||
|
||||
dst[(idst*3) + jdst] = mf[(ti*4) + tj];
|
||||
dst[(idst * 3) + jdst] = mf[(ti * 4) + tj];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline float get_3x3_determinant(const float *m)
|
||||
{
|
||||
return (m[0] * ((m[4]*m[8]) - (m[7]*m[5]))) -
|
||||
(m[1] * ((m[3]*m[8]) - (m[6]*m[5]))) +
|
||||
(m[2] * ((m[3]*m[7]) - (m[6]*m[4])));
|
||||
return (m[0] * ((m[4] * m[8]) - (m[7] * m[5]))) -
|
||||
(m[1] * ((m[3] * m[8]) - (m[6] * m[5]))) +
|
||||
(m[2] * ((m[3] * m[7]) - (m[6] * m[4])));
|
||||
}
|
||||
|
||||
float matrix4_determinant(const struct matrix4 *m)
|
||||
|
|
@ -117,10 +118,10 @@ float matrix4_determinant(const struct matrix4 *m)
|
|||
float m3x3[9];
|
||||
int n;
|
||||
|
||||
for (n = 0; n < 4; n++, i *= -1.0f) {
|
||||
for (n = 0; n < 4; n++, i = -i) { // NOLINT(clang-tidy-cert-flp30-c)
|
||||
get_3x3_submatrix(m3x3, m, 0, n);
|
||||
|
||||
det = get_3x3_determinant(m3x3);
|
||||
det = get_3x3_determinant(m3x3);
|
||||
result += mf[n] * det * i;
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +129,7 @@ float matrix4_determinant(const struct matrix4 *m)
|
|||
}
|
||||
|
||||
void matrix4_translate3v(struct matrix4 *dst, const struct matrix4 *m,
|
||||
const struct vec3 *v)
|
||||
const struct vec3 *v)
|
||||
{
|
||||
struct matrix4 temp;
|
||||
vec4_set(&temp.x, 1.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
|
@ -140,7 +141,7 @@ void matrix4_translate3v(struct matrix4 *dst, const struct matrix4 *m,
|
|||
}
|
||||
|
||||
void matrix4_translate4v(struct matrix4 *dst, const struct matrix4 *m,
|
||||
const struct vec4 *v)
|
||||
const struct vec4 *v)
|
||||
{
|
||||
struct matrix4 temp;
|
||||
vec4_set(&temp.x, 1.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
|
@ -152,7 +153,7 @@ void matrix4_translate4v(struct matrix4 *dst, const struct matrix4 *m,
|
|||
}
|
||||
|
||||
void matrix4_rotate(struct matrix4 *dst, const struct matrix4 *m,
|
||||
const struct quat *q)
|
||||
const struct quat *q)
|
||||
{
|
||||
struct matrix4 temp;
|
||||
matrix4_from_quat(&temp, q);
|
||||
|
|
@ -160,7 +161,7 @@ void matrix4_rotate(struct matrix4 *dst, const struct matrix4 *m,
|
|||
}
|
||||
|
||||
void matrix4_rotate_aa(struct matrix4 *dst, const struct matrix4 *m,
|
||||
const struct axisang *aa)
|
||||
const struct axisang *aa)
|
||||
{
|
||||
struct matrix4 temp;
|
||||
matrix4_from_axisang(&temp, aa);
|
||||
|
|
@ -168,7 +169,7 @@ void matrix4_rotate_aa(struct matrix4 *dst, const struct matrix4 *m,
|
|||
}
|
||||
|
||||
void matrix4_scale(struct matrix4 *dst, const struct matrix4 *m,
|
||||
const struct vec3 *v)
|
||||
const struct vec3 *v)
|
||||
{
|
||||
struct matrix4 temp;
|
||||
vec4_set(&temp.x, v->x, 0.0f, 0.0f, 0.0f);
|
||||
|
|
@ -179,7 +180,7 @@ void matrix4_scale(struct matrix4 *dst, const struct matrix4 *m,
|
|||
}
|
||||
|
||||
void matrix4_translate3v_i(struct matrix4 *dst, const struct vec3 *v,
|
||||
const struct matrix4 *m)
|
||||
const struct matrix4 *m)
|
||||
{
|
||||
struct matrix4 temp;
|
||||
vec4_set(&temp.x, 1.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
|
@ -191,7 +192,7 @@ void matrix4_translate3v_i(struct matrix4 *dst, const struct vec3 *v,
|
|||
}
|
||||
|
||||
void matrix4_translate4v_i(struct matrix4 *dst, const struct vec4 *v,
|
||||
const struct matrix4 *m)
|
||||
const struct matrix4 *m)
|
||||
{
|
||||
struct matrix4 temp;
|
||||
vec4_set(&temp.x, 1.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
|
@ -203,7 +204,7 @@ void matrix4_translate4v_i(struct matrix4 *dst, const struct vec4 *v,
|
|||
}
|
||||
|
||||
void matrix4_rotate_i(struct matrix4 *dst, const struct quat *q,
|
||||
const struct matrix4 *m)
|
||||
const struct matrix4 *m)
|
||||
{
|
||||
struct matrix4 temp;
|
||||
matrix4_from_quat(&temp, q);
|
||||
|
|
@ -211,7 +212,7 @@ void matrix4_rotate_i(struct matrix4 *dst, const struct quat *q,
|
|||
}
|
||||
|
||||
void matrix4_rotate_aa_i(struct matrix4 *dst, const struct axisang *aa,
|
||||
const struct matrix4 *m)
|
||||
const struct matrix4 *m)
|
||||
{
|
||||
struct matrix4 temp;
|
||||
matrix4_from_axisang(&temp, aa);
|
||||
|
|
@ -219,7 +220,7 @@ void matrix4_rotate_aa_i(struct matrix4 *dst, const struct axisang *aa,
|
|||
}
|
||||
|
||||
void matrix4_scale_i(struct matrix4 *dst, const struct vec3 *v,
|
||||
const struct matrix4 *m)
|
||||
const struct matrix4 *m)
|
||||
{
|
||||
struct matrix4 temp;
|
||||
vec4_set(&temp.x, v->x, 0.0f, 0.0f, 0.0f);
|
||||
|
|
@ -234,7 +235,7 @@ bool matrix4_inv(struct matrix4 *dst, const struct matrix4 *m)
|
|||
struct vec4 *dstv;
|
||||
float det;
|
||||
float m3x3[9];
|
||||
int i, j, sign;
|
||||
int i, j, sign;
|
||||
|
||||
if (dst == m) {
|
||||
struct matrix4 temp = *m;
|
||||
|
|
@ -242,17 +243,17 @@ bool matrix4_inv(struct matrix4 *dst, const struct matrix4 *m)
|
|||
}
|
||||
|
||||
dstv = (struct vec4 *)dst;
|
||||
det = matrix4_determinant(m);
|
||||
det = matrix4_determinant(m);
|
||||
|
||||
if (fabs(det) < 0.0005f)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
sign = 1 - ((i+j) % 2) * 2;
|
||||
sign = 1 - ((i + j) % 2) * 2;
|
||||
get_3x3_submatrix(m3x3, m, i, j);
|
||||
dstv[j].ptr[i] = get_3x3_determinant(m3x3) *
|
||||
(float)sign / det;
|
||||
dstv[j].ptr[i] =
|
||||
get_3x3_determinant(m3x3) * (float)sign / det;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,40 +55,40 @@ static inline void matrix4_identity(struct matrix4 *dst)
|
|||
|
||||
EXPORT void matrix4_from_matrix3(struct matrix4 *dst, const struct matrix3 *m);
|
||||
EXPORT void matrix4_from_quat(struct matrix4 *dst, const struct quat *q);
|
||||
EXPORT void matrix4_from_axisang(struct matrix4 *dst,
|
||||
const struct axisang *aa);
|
||||
EXPORT void matrix4_from_axisang(struct matrix4 *dst, const struct axisang *aa);
|
||||
|
||||
EXPORT void matrix4_mul(struct matrix4 *dst, const struct matrix4 *m1,
|
||||
const struct matrix4 *m2);
|
||||
const struct matrix4 *m2);
|
||||
|
||||
EXPORT float matrix4_determinant(const struct matrix4 *m);
|
||||
|
||||
EXPORT void matrix4_translate3v(struct matrix4 *dst, const struct matrix4 *m,
|
||||
const struct vec3 *v);
|
||||
const struct vec3 *v);
|
||||
EXPORT void matrix4_translate4v(struct matrix4 *dst, const struct matrix4 *m,
|
||||
const struct vec4 *v);
|
||||
const struct vec4 *v);
|
||||
EXPORT void matrix4_rotate(struct matrix4 *dst, const struct matrix4 *m,
|
||||
const struct quat *q);
|
||||
const struct quat *q);
|
||||
EXPORT void matrix4_rotate_aa(struct matrix4 *dst, const struct matrix4 *m,
|
||||
const struct axisang *aa);
|
||||
const struct axisang *aa);
|
||||
EXPORT void matrix4_scale(struct matrix4 *dst, const struct matrix4 *m,
|
||||
const struct vec3 *v);
|
||||
const struct vec3 *v);
|
||||
EXPORT bool matrix4_inv(struct matrix4 *dst, const struct matrix4 *m);
|
||||
EXPORT void matrix4_transpose(struct matrix4 *dst, const struct matrix4 *m);
|
||||
|
||||
EXPORT void matrix4_translate3v_i(struct matrix4 *dst, const struct vec3 *v,
|
||||
const struct matrix4 *m);
|
||||
const struct matrix4 *m);
|
||||
EXPORT void matrix4_translate4v_i(struct matrix4 *dst, const struct vec4 *v,
|
||||
const struct matrix4 *m);
|
||||
const struct matrix4 *m);
|
||||
EXPORT void matrix4_rotate_i(struct matrix4 *dst, const struct quat *q,
|
||||
const struct matrix4 *m);
|
||||
const struct matrix4 *m);
|
||||
EXPORT void matrix4_rotate_aa_i(struct matrix4 *dst, const struct axisang *aa,
|
||||
const struct matrix4 *m);
|
||||
const struct matrix4 *m);
|
||||
EXPORT void matrix4_scale_i(struct matrix4 *dst, const struct vec3 *v,
|
||||
const struct matrix4 *m);
|
||||
const struct matrix4 *m);
|
||||
|
||||
static inline void matrix4_translate3f(struct matrix4 *dst,
|
||||
const struct matrix4 *m, float x, float y, float z)
|
||||
const struct matrix4 *m, float x,
|
||||
float y, float z)
|
||||
{
|
||||
struct vec3 v;
|
||||
vec3_set(&v, x, y, z);
|
||||
|
|
@ -96,15 +96,16 @@ static inline void matrix4_translate3f(struct matrix4 *dst,
|
|||
}
|
||||
|
||||
static inline void matrix4_rotate_aa4f(struct matrix4 *dst,
|
||||
const struct matrix4 *m, float x, float y, float z, float rot)
|
||||
const struct matrix4 *m, float x,
|
||||
float y, float z, float rot)
|
||||
{
|
||||
struct axisang aa;
|
||||
axisang_set(&aa, x, y, z, rot);
|
||||
matrix4_rotate_aa(dst, m, &aa);
|
||||
}
|
||||
|
||||
static inline void matrix4_scale3f(struct matrix4 *dst,
|
||||
const struct matrix4 *m, float x, float y, float z)
|
||||
static inline void matrix4_scale3f(struct matrix4 *dst, const struct matrix4 *m,
|
||||
float x, float y, float z)
|
||||
{
|
||||
struct vec3 v;
|
||||
vec3_set(&v, x, y, z);
|
||||
|
|
|
|||
|
|
@ -19,10 +19,8 @@
|
|||
#include "matrix3.h"
|
||||
#include "plane.h"
|
||||
|
||||
void plane_from_tri(struct plane *dst,
|
||||
const struct vec3 *v1,
|
||||
const struct vec3 *v2,
|
||||
const struct vec3 *v3)
|
||||
void plane_from_tri(struct plane *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2, const struct vec3 *v3)
|
||||
{
|
||||
struct vec3 temp;
|
||||
|
||||
|
|
@ -34,7 +32,7 @@ void plane_from_tri(struct plane *dst,
|
|||
}
|
||||
|
||||
void plane_transform(struct plane *dst, const struct plane *p,
|
||||
const struct matrix4 *m)
|
||||
const struct matrix4 *m)
|
||||
{
|
||||
struct vec3 temp;
|
||||
|
||||
|
|
@ -48,7 +46,7 @@ void plane_transform(struct plane *dst, const struct plane *p,
|
|||
}
|
||||
|
||||
void plane_transform3x4(struct plane *dst, const struct plane *p,
|
||||
const struct matrix3 *m)
|
||||
const struct matrix3 *m)
|
||||
{
|
||||
struct vec3 temp;
|
||||
|
||||
|
|
@ -60,7 +58,7 @@ void plane_transform3x4(struct plane *dst, const struct plane *p,
|
|||
}
|
||||
|
||||
bool plane_intersection_ray(const struct plane *p, const struct vec3 *orig,
|
||||
const struct vec3 *dir, float *t)
|
||||
const struct vec3 *dir, float *t)
|
||||
{
|
||||
float c = vec3_dot(&p->dir, dir);
|
||||
|
||||
|
|
@ -74,10 +72,10 @@ bool plane_intersection_ray(const struct plane *p, const struct vec3 *orig,
|
|||
}
|
||||
|
||||
bool plane_intersection_line(const struct plane *p, const struct vec3 *v1,
|
||||
const struct vec3 *v2, float *t)
|
||||
const struct vec3 *v2, float *t)
|
||||
{
|
||||
float p1_dist, p2_dist, p1_abs_dist, dist2;
|
||||
bool p1_over, p2_over;
|
||||
bool p1_over, p2_over;
|
||||
|
||||
p1_dist = vec3_plane_dist(v1, p);
|
||||
p2_dist = vec3_plane_dist(v2, p);
|
||||
|
|
@ -108,11 +106,9 @@ bool plane_intersection_line(const struct plane *p, const struct vec3 *v1,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool plane_tri_inside(const struct plane *p,
|
||||
const struct vec3 *v1,
|
||||
const struct vec3 *v2,
|
||||
const struct vec3 *v3,
|
||||
float precision)
|
||||
bool plane_tri_inside(const struct plane *p, const struct vec3 *v1,
|
||||
const struct vec3 *v2, const struct vec3 *v3,
|
||||
float precision)
|
||||
{
|
||||
/* bit 1: part or all is behind the plane */
|
||||
/* bit 2: part or all is in front of the plane */
|
||||
|
|
@ -140,7 +136,7 @@ bool plane_tri_inside(const struct plane *p,
|
|||
}
|
||||
|
||||
bool plane_line_inside(const struct plane *p, const struct vec3 *v1,
|
||||
const struct vec3 *v2, float precision)
|
||||
const struct vec3 *v2, float precision)
|
||||
{
|
||||
/* bit 1: part or all is behind the plane */
|
||||
/* bit 2: part or all is in front of the plane */
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ struct matrix4;
|
|||
|
||||
struct plane {
|
||||
struct vec3 dir;
|
||||
float dist;
|
||||
float dist;
|
||||
};
|
||||
|
||||
static inline void plane_copy(struct plane *dst, const struct plane *p)
|
||||
|
|
@ -39,52 +39,50 @@ static inline void plane_copy(struct plane *dst, const struct plane *p)
|
|||
}
|
||||
|
||||
static inline void plane_set(struct plane *dst, const struct vec3 *dir,
|
||||
float dist)
|
||||
float dist)
|
||||
{
|
||||
vec3_copy(&dst->dir, dir);
|
||||
dst->dist = dist;
|
||||
}
|
||||
|
||||
static inline void plane_setf(struct plane *dst, float a, float b, float c,
|
||||
float d)
|
||||
float d)
|
||||
{
|
||||
vec3_set(&dst->dir, a, b, c);
|
||||
dst->dist = d;
|
||||
}
|
||||
|
||||
EXPORT void plane_from_tri(struct plane *dst,
|
||||
const struct vec3 *v1,
|
||||
const struct vec3 *v2,
|
||||
const struct vec3 *v3);
|
||||
EXPORT void plane_from_tri(struct plane *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2, const struct vec3 *v3);
|
||||
|
||||
EXPORT void plane_transform(struct plane *dst, const struct plane *p,
|
||||
const struct matrix4 *m);
|
||||
const struct matrix4 *m);
|
||||
EXPORT void plane_transform3x4(struct plane *dst, const struct plane *p,
|
||||
const struct matrix3 *m);
|
||||
const struct matrix3 *m);
|
||||
|
||||
EXPORT bool plane_intersection_ray(const struct plane *p,
|
||||
const struct vec3 *orig, const struct vec3 *dir, float *t);
|
||||
const struct vec3 *orig,
|
||||
const struct vec3 *dir, float *t);
|
||||
EXPORT bool plane_intersection_line(const struct plane *p,
|
||||
const struct vec3 *v1, const struct vec3 *v2, float *t);
|
||||
const struct vec3 *v1,
|
||||
const struct vec3 *v2, float *t);
|
||||
|
||||
EXPORT bool plane_tri_inside(const struct plane *p,
|
||||
const struct vec3 *v1,
|
||||
const struct vec3 *v2,
|
||||
const struct vec3 *v3,
|
||||
float precision);
|
||||
EXPORT bool plane_tri_inside(const struct plane *p, const struct vec3 *v1,
|
||||
const struct vec3 *v2, const struct vec3 *v3,
|
||||
float precision);
|
||||
|
||||
EXPORT bool plane_line_inside(const struct plane *p, const struct vec3 *v1,
|
||||
const struct vec3 *v2, float precision);
|
||||
const struct vec3 *v2, float precision);
|
||||
|
||||
static inline bool plane_close(const struct plane *p1, const struct plane *p2,
|
||||
float precision)
|
||||
float precision)
|
||||
{
|
||||
return vec3_close(&p1->dir, &p2->dir, precision) &&
|
||||
close_float(p1->dist, p2->dist, precision);
|
||||
}
|
||||
|
||||
static inline bool plane_coplanar(const struct plane *p1,
|
||||
const struct plane *p2, float precision)
|
||||
const struct plane *p2, float precision)
|
||||
{
|
||||
float cos_angle = vec3_dot(&p1->dir, &p2->dir);
|
||||
|
||||
|
|
|
|||
|
|
@ -47,12 +47,12 @@ void quat_mul(struct quat *dst, const struct quat *q1, const struct quat *q2)
|
|||
void quat_from_axisang(struct quat *dst, const struct axisang *aa)
|
||||
{
|
||||
float halfa = aa->w * 0.5f;
|
||||
float sine = sinf(halfa);
|
||||
float sine = sinf(halfa);
|
||||
|
||||
dst->x = aa->x * sine;
|
||||
dst->y = aa->y * sine;
|
||||
dst->z = aa->z * sine;
|
||||
dst->w = cosf(halfa);
|
||||
dst->w = cosf(halfa);
|
||||
}
|
||||
|
||||
struct f4x4 {
|
||||
|
|
@ -61,7 +61,7 @@ struct f4x4 {
|
|||
|
||||
void quat_from_matrix3(struct quat *dst, const struct matrix3 *m)
|
||||
{
|
||||
quat_from_matrix4(dst, (const struct matrix4*)m);
|
||||
quat_from_matrix4(dst, (const struct matrix4 *)m);
|
||||
}
|
||||
|
||||
void quat_from_matrix4(struct quat *dst, const struct matrix4 *m)
|
||||
|
|
@ -69,7 +69,7 @@ void quat_from_matrix4(struct quat *dst, const struct matrix4 *m)
|
|||
float tr = (m->x.x + m->y.y + m->z.z);
|
||||
float inv_half;
|
||||
float four_d;
|
||||
int i,j,k;
|
||||
int i, j, k;
|
||||
|
||||
if (tr > 0.0f) {
|
||||
four_d = sqrtf(tr + 1.0f);
|
||||
|
|
@ -80,27 +80,28 @@ void quat_from_matrix4(struct quat *dst, const struct matrix4 *m)
|
|||
dst->y = (m->z.x - m->x.z) * inv_half;
|
||||
dst->z = (m->x.y - m->y.x) * inv_half;
|
||||
} else {
|
||||
struct f4x4 *val = (struct f4x4*)m;
|
||||
struct f4x4 *val = (struct f4x4 *)m;
|
||||
|
||||
i = (m->x.x > m->y.y) ? 0 : 1;
|
||||
|
||||
if (m->z.z > val->ptr[i][i])
|
||||
i = 2;
|
||||
|
||||
j = (i+1) % 3;
|
||||
k = (i+2) % 3;
|
||||
j = (i + 1) % 3;
|
||||
k = (i + 2) % 3;
|
||||
|
||||
/* ---------------------------------- */
|
||||
|
||||
four_d = sqrtf((val->ptr[i][i] - val->ptr[j][j] -
|
||||
val->ptr[k][k]) + 1.0f);
|
||||
four_d = sqrtf(
|
||||
(val->ptr[i][i] - val->ptr[j][j] - val->ptr[k][k]) +
|
||||
1.0f);
|
||||
|
||||
dst->ptr[i] = four_d * 0.5f;
|
||||
|
||||
inv_half = 0.5f / four_d;
|
||||
dst->ptr[j] = (val->ptr[i][j] + val->ptr[j][i]) * inv_half;
|
||||
dst->ptr[k] = (val->ptr[i][k] + val->ptr[k][i]) * inv_half;
|
||||
dst->w = (val->ptr[j][k] - val->ptr[k][j]) * inv_half;
|
||||
dst->ptr[j] = (val->ptr[i][j] + val->ptr[j][i]) * inv_half;
|
||||
dst->ptr[k] = (val->ptr[i][k] + val->ptr[k][i]) * inv_half;
|
||||
dst->w = (val->ptr[j][k] - val->ptr[k][j]) * inv_half;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -115,8 +116,8 @@ void quat_set_look_dir(struct quat *dst, const struct vec3 *dir)
|
|||
{
|
||||
struct vec3 new_dir;
|
||||
struct quat xz_rot, yz_rot;
|
||||
bool xz_valid;
|
||||
bool yz_valid;
|
||||
bool xz_valid;
|
||||
bool yz_valid;
|
||||
struct axisang aa;
|
||||
|
||||
vec3_norm(&new_dir, dir);
|
||||
|
|
@ -126,12 +127,12 @@ void quat_set_look_dir(struct quat *dst, const struct vec3 *dir)
|
|||
quat_identity(&yz_rot);
|
||||
|
||||
xz_valid = close_float(new_dir.x, 0.0f, EPSILON) ||
|
||||
close_float(new_dir.z, 0.0f, EPSILON);
|
||||
close_float(new_dir.z, 0.0f, EPSILON);
|
||||
yz_valid = close_float(new_dir.y, 0.0f, EPSILON);
|
||||
|
||||
if (xz_valid) {
|
||||
axisang_set(&aa, 0.0f, 1.0f, 0.0f,
|
||||
atan2f(new_dir.x, new_dir.z));
|
||||
atan2f(new_dir.x, new_dir.z));
|
||||
|
||||
quat_from_axisang(&xz_rot, &aa);
|
||||
}
|
||||
|
|
@ -151,31 +152,31 @@ void quat_set_look_dir(struct quat *dst, const struct vec3 *dir)
|
|||
void quat_log(struct quat *dst, const struct quat *q)
|
||||
{
|
||||
float angle = acosf(q->w);
|
||||
float sine = sinf(angle);
|
||||
float w = q->w;
|
||||
float sine = sinf(angle);
|
||||
float w = q->w;
|
||||
|
||||
quat_copy(dst, q);
|
||||
dst->w = 0.0f;
|
||||
|
||||
if ((fabsf(w) < 1.0f) && (fabsf(sine) >= EPSILON)) {
|
||||
sine = angle/sine;
|
||||
sine = angle / sine;
|
||||
quat_mulf(dst, dst, sine);
|
||||
}
|
||||
}
|
||||
|
||||
void quat_exp(struct quat *dst, const struct quat *q)
|
||||
{
|
||||
float length = sqrtf(q->x*q->x + q->y*q->y + q->z*q->z);
|
||||
float sine = sinf(length);
|
||||
float length = sqrtf(q->x * q->x + q->y * q->y + q->z * q->z);
|
||||
float sine = sinf(length);
|
||||
|
||||
quat_copy(dst, q);
|
||||
sine = (length > EPSILON) ? (sine/length) : 1.0f;
|
||||
sine = (length > EPSILON) ? (sine / length) : 1.0f;
|
||||
quat_mulf(dst, dst, sine);
|
||||
dst->w = cosf(length);
|
||||
}
|
||||
|
||||
void quat_interpolate(struct quat *dst, const struct quat *q1,
|
||||
const struct quat *q2, float t)
|
||||
const struct quat *q2, float t)
|
||||
{
|
||||
float dot = quat_dot(q1, q2);
|
||||
float anglef = acosf(dot);
|
||||
|
|
@ -183,10 +184,10 @@ void quat_interpolate(struct quat *dst, const struct quat *q1,
|
|||
struct quat temp;
|
||||
|
||||
if (anglef >= EPSILON) {
|
||||
sine = sinf(anglef);
|
||||
sinei = 1/sine;
|
||||
sinet = sinf(anglef*t)*sinei;
|
||||
sineti = sinf(anglef*(1.0f-t))*sinei;
|
||||
sine = sinf(anglef);
|
||||
sinei = 1 / sine;
|
||||
sinet = sinf(anglef * t) * sinei;
|
||||
sineti = sinf(anglef * (1.0f - t)) * sinei;
|
||||
|
||||
quat_mulf(&temp, q1, sineti);
|
||||
quat_mulf(dst, q2, sinet);
|
||||
|
|
@ -199,7 +200,7 @@ void quat_interpolate(struct quat *dst, const struct quat *q1,
|
|||
}
|
||||
|
||||
void quat_get_tangent(struct quat *dst, const struct quat *prev,
|
||||
const struct quat *q, const struct quat *next)
|
||||
const struct quat *q, const struct quat *next)
|
||||
{
|
||||
struct quat temp;
|
||||
|
||||
|
|
@ -209,14 +210,13 @@ void quat_get_tangent(struct quat *dst, const struct quat *prev,
|
|||
quat_mulf(dst, &temp, 0.5f);
|
||||
}
|
||||
|
||||
void quat_interpolate_cubic(struct quat *dst,
|
||||
const struct quat *q1, const struct quat *q2,
|
||||
const struct quat *m1, const struct quat *m2,
|
||||
float t)
|
||||
void quat_interpolate_cubic(struct quat *dst, const struct quat *q1,
|
||||
const struct quat *q2, const struct quat *m1,
|
||||
const struct quat *m2, float t)
|
||||
{
|
||||
struct quat temp1, temp2;
|
||||
|
||||
quat_interpolate(&temp1, q1, q2, t);
|
||||
quat_interpolate(&temp2, m1, m2, t);
|
||||
quat_interpolate(dst, &temp1, &temp2, 2.0f*(1.0f-t)*t);
|
||||
quat_interpolate(dst, &temp1, &temp2, 2.0f * (1.0f - t) * t);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,9 @@ struct axisang;
|
|||
|
||||
struct quat {
|
||||
union {
|
||||
struct {float x, y, z, w;};
|
||||
struct {
|
||||
float x, y, z, w;
|
||||
};
|
||||
float ptr[4];
|
||||
__m128 m;
|
||||
};
|
||||
|
|
@ -53,7 +55,7 @@ static inline void quat_identity(struct quat *q)
|
|||
}
|
||||
|
||||
static inline void quat_set(struct quat *dst, float x, float y, float z,
|
||||
float w)
|
||||
float w)
|
||||
{
|
||||
dst->m = _mm_set_ps(x, y, z, w);
|
||||
}
|
||||
|
|
@ -64,40 +66,36 @@ static inline void quat_copy(struct quat *dst, const struct quat *q)
|
|||
}
|
||||
|
||||
static inline void quat_add(struct quat *dst, const struct quat *q1,
|
||||
const struct quat *q2)
|
||||
const struct quat *q2)
|
||||
{
|
||||
dst->m = _mm_add_ps(q1->m, q2->m);
|
||||
}
|
||||
|
||||
static inline void quat_sub(struct quat *dst, const struct quat *q1,
|
||||
const struct quat *q2)
|
||||
const struct quat *q2)
|
||||
{
|
||||
dst->m = _mm_sub_ps(q1->m, q2->m);
|
||||
}
|
||||
|
||||
EXPORT void quat_mul(struct quat *dst, const struct quat *q1,
|
||||
const struct quat *q2);
|
||||
const struct quat *q2);
|
||||
|
||||
static inline void quat_addf(struct quat *dst, const struct quat *q,
|
||||
float f)
|
||||
static inline void quat_addf(struct quat *dst, const struct quat *q, float f)
|
||||
{
|
||||
dst->m = _mm_add_ps(q->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline void quat_subf(struct quat *dst, const struct quat *q,
|
||||
float f)
|
||||
static inline void quat_subf(struct quat *dst, const struct quat *q, float f)
|
||||
{
|
||||
dst->m = _mm_sub_ps(q->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline void quat_mulf(struct quat *dst, const struct quat *q,
|
||||
float f)
|
||||
static inline void quat_mulf(struct quat *dst, const struct quat *q, float f)
|
||||
{
|
||||
dst->m = _mm_mul_ps(q->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline void quat_divf(struct quat *dst, const struct quat *q,
|
||||
float f)
|
||||
static inline void quat_divf(struct quat *dst, const struct quat *q, float f)
|
||||
{
|
||||
dst->m = _mm_div_ps(q->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
|
@ -145,19 +143,17 @@ static inline float quat_dist(const struct quat *q1, const struct quat *q2)
|
|||
static inline void quat_norm(struct quat *dst, const struct quat *q)
|
||||
{
|
||||
float dot_val = quat_dot(q, q);
|
||||
dst->m = (dot_val > 0.0f) ?
|
||||
_mm_mul_ps(q->m, _mm_set1_ps(1.0f/sqrtf(dot_val))) :
|
||||
_mm_setzero_ps();
|
||||
dst->m = (dot_val > 0.0f)
|
||||
? _mm_mul_ps(q->m, _mm_set1_ps(1.0f / sqrtf(dot_val)))
|
||||
: _mm_setzero_ps();
|
||||
}
|
||||
|
||||
static inline bool quat_close(const struct quat *q1, const struct quat *q2,
|
||||
float epsilon)
|
||||
float epsilon)
|
||||
{
|
||||
struct quat test;
|
||||
quat_sub(&test, q1, q2);
|
||||
return test.x < epsilon &&
|
||||
test.y < epsilon &&
|
||||
test.z < epsilon &&
|
||||
return test.x < epsilon && test.y < epsilon && test.z < epsilon &&
|
||||
test.w < epsilon;
|
||||
}
|
||||
|
||||
|
|
@ -172,12 +168,12 @@ EXPORT void quat_log(struct quat *dst, const struct quat *q);
|
|||
EXPORT void quat_exp(struct quat *dst, const struct quat *q);
|
||||
|
||||
EXPORT void quat_interpolate(struct quat *dst, const struct quat *q1,
|
||||
const struct quat *q2, float t);
|
||||
const struct quat *q2, float t);
|
||||
EXPORT void quat_get_tangent(struct quat *dst, const struct quat *prev,
|
||||
const struct quat *q, const struct quat *next);
|
||||
const struct quat *q, const struct quat *next);
|
||||
EXPORT void quat_interpolate_cubic(struct quat *dst, const struct quat *q1,
|
||||
const struct quat *q2, const struct quat *m1,
|
||||
const struct quat *m2, float t);
|
||||
const struct quat *q2, const struct quat *m1,
|
||||
const struct quat *m2, float t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,12 +53,12 @@ enum gs_sample_filter get_sample_filter(const char *filter)
|
|||
if (astrcmpi(filter, "Anisotropy") == 0)
|
||||
return GS_FILTER_ANISOTROPIC;
|
||||
|
||||
else if (astrcmpi(filter, "Point") == 0 ||
|
||||
strcmp(filter, "MIN_MAG_MIP_POINT") == 0)
|
||||
else if (astrcmpi(filter, "Point") == 0 ||
|
||||
strcmp(filter, "MIN_MAG_MIP_POINT") == 0)
|
||||
return GS_FILTER_POINT;
|
||||
|
||||
else if (astrcmpi(filter, "Linear") == 0 ||
|
||||
strcmp(filter, "MIN_MAG_MIP_LINEAR") == 0)
|
||||
else if (astrcmpi(filter, "Linear") == 0 ||
|
||||
strcmp(filter, "MIN_MAG_MIP_LINEAR") == 0)
|
||||
return GS_FILTER_LINEAR;
|
||||
|
||||
else if (strcmp(filter, "MIN_MAG_POINT_MIP_LINEAR") == 0)
|
||||
|
|
@ -99,7 +99,7 @@ extern enum gs_address_mode get_address_mode(const char *mode)
|
|||
}
|
||||
|
||||
void shader_sampler_convert(struct shader_sampler *ss,
|
||||
struct gs_sampler_info *info)
|
||||
struct gs_sampler_info *info)
|
||||
{
|
||||
size_t i;
|
||||
memset(info, 0, sizeof(struct gs_sampler_info));
|
||||
|
|
@ -128,22 +128,26 @@ void shader_sampler_convert(struct shader_sampler *ss,
|
|||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static int sp_parse_sampler_state_item(struct shader_parser *sp,
|
||||
struct shader_sampler *ss)
|
||||
struct shader_sampler *ss)
|
||||
{
|
||||
int ret;
|
||||
char *state = NULL, *value = NULL;
|
||||
|
||||
ret = cf_next_name(&sp->cfp, &state, "state name", ";");
|
||||
if (ret != PARSE_SUCCESS) goto fail;
|
||||
if (ret != PARSE_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
ret = cf_next_token_should_be(&sp->cfp, "=", ";", NULL);
|
||||
if (ret != PARSE_SUCCESS) goto fail;
|
||||
if (ret != PARSE_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
ret = cf_next_token_copy(&sp->cfp, &value);
|
||||
if (ret != PARSE_SUCCESS) goto fail;
|
||||
if (ret != PARSE_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
ret = cf_next_token_should_be(&sp->cfp, ";", ";", NULL);
|
||||
if (ret != PARSE_SUCCESS) goto fail;
|
||||
if (ret != PARSE_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
da_push_back(ss->states, &state);
|
||||
da_push_back(ss->values, &value);
|
||||
|
|
@ -191,17 +195,20 @@ error:
|
|||
}
|
||||
|
||||
static inline int sp_parse_struct_var(struct shader_parser *sp,
|
||||
struct shader_var *var)
|
||||
struct shader_var *var)
|
||||
{
|
||||
int code;
|
||||
|
||||
/* -------------------------------------- */
|
||||
/* variable type */
|
||||
|
||||
if (!cf_next_valid_token(&sp->cfp)) return PARSE_EOF;
|
||||
if (!cf_next_valid_token(&sp->cfp))
|
||||
return PARSE_EOF;
|
||||
|
||||
if (cf_token_is(&sp->cfp, ";")) return PARSE_CONTINUE;
|
||||
if (cf_token_is(&sp->cfp, "}")) return PARSE_BREAK;
|
||||
if (cf_token_is(&sp->cfp, ";"))
|
||||
return PARSE_CONTINUE;
|
||||
if (cf_token_is(&sp->cfp, "}"))
|
||||
return PARSE_BREAK;
|
||||
|
||||
code = cf_token_is_type(&sp->cfp, CFTOKEN_NAME, "type name", ";");
|
||||
if (code != PARSE_SUCCESS)
|
||||
|
|
@ -212,13 +219,15 @@ static inline int sp_parse_struct_var(struct shader_parser *sp,
|
|||
/* -------------------------------------- */
|
||||
/* variable name */
|
||||
|
||||
if (!cf_next_valid_token(&sp->cfp)) return PARSE_EOF;
|
||||
if (!cf_next_valid_token(&sp->cfp))
|
||||
return PARSE_EOF;
|
||||
|
||||
if (cf_token_is(&sp->cfp, ";")) return PARSE_UNEXPECTED_CONTINUE;
|
||||
if (cf_token_is(&sp->cfp, "}")) return PARSE_UNEXPECTED_BREAK;
|
||||
if (cf_token_is(&sp->cfp, ";"))
|
||||
return PARSE_UNEXPECTED_CONTINUE;
|
||||
if (cf_token_is(&sp->cfp, "}"))
|
||||
return PARSE_UNEXPECTED_BREAK;
|
||||
|
||||
code = cf_token_is_type(&sp->cfp, CFTOKEN_NAME, "variable name",
|
||||
";");
|
||||
code = cf_token_is_type(&sp->cfp, CFTOKEN_NAME, "variable name", ";");
|
||||
if (code != PARSE_SUCCESS)
|
||||
return code;
|
||||
|
||||
|
|
@ -227,24 +236,27 @@ static inline int sp_parse_struct_var(struct shader_parser *sp,
|
|||
/* -------------------------------------- */
|
||||
/* variable mapping if any (POSITION, TEXCOORD, etc) */
|
||||
|
||||
if (!cf_next_valid_token(&sp->cfp)) return PARSE_EOF;
|
||||
if (!cf_next_valid_token(&sp->cfp))
|
||||
return PARSE_EOF;
|
||||
|
||||
if (cf_token_is(&sp->cfp, ":")) {
|
||||
if (!cf_next_valid_token(&sp->cfp)) return PARSE_EOF;
|
||||
if (!cf_next_valid_token(&sp->cfp))
|
||||
return PARSE_EOF;
|
||||
|
||||
if (cf_token_is(&sp->cfp, ";"))
|
||||
return PARSE_UNEXPECTED_CONTINUE;
|
||||
if (cf_token_is(&sp->cfp, "}"))
|
||||
return PARSE_UNEXPECTED_BREAK;
|
||||
|
||||
code = cf_token_is_type(&sp->cfp, CFTOKEN_NAME,
|
||||
"mapping name", ";");
|
||||
code = cf_token_is_type(&sp->cfp, CFTOKEN_NAME, "mapping name",
|
||||
";");
|
||||
if (code != PARSE_SUCCESS)
|
||||
return code;
|
||||
|
||||
cf_copy_token(&sp->cfp, &var->mapping);
|
||||
|
||||
if (!cf_next_valid_token(&sp->cfp)) return PARSE_EOF;
|
||||
if (!cf_next_valid_token(&sp->cfp))
|
||||
return PARSE_EOF;
|
||||
}
|
||||
|
||||
/* -------------------------------------- */
|
||||
|
|
@ -314,7 +326,7 @@ error:
|
|||
}
|
||||
|
||||
static inline int sp_check_for_keyword(struct shader_parser *sp,
|
||||
const char *keyword, bool *val)
|
||||
const char *keyword, bool *val)
|
||||
{
|
||||
bool new_val = cf_token_is(&sp->cfp, keyword);
|
||||
if (new_val) {
|
||||
|
|
@ -323,7 +335,7 @@ static inline int sp_check_for_keyword(struct shader_parser *sp,
|
|||
|
||||
if (new_val && *val)
|
||||
cf_adderror(&sp->cfp, "'$1' keyword already specified",
|
||||
LEX_WARNING, keyword, NULL, NULL);
|
||||
LEX_WARNING, keyword, NULL, NULL);
|
||||
*val = new_val;
|
||||
|
||||
return PARSE_CONTINUE;
|
||||
|
|
@ -333,7 +345,7 @@ static inline int sp_check_for_keyword(struct shader_parser *sp,
|
|||
}
|
||||
|
||||
static inline int sp_parse_func_param(struct shader_parser *sp,
|
||||
struct shader_var *var)
|
||||
struct shader_var *var)
|
||||
{
|
||||
int code;
|
||||
bool var_type_keyword = false;
|
||||
|
|
@ -384,7 +396,7 @@ static inline int sp_parse_func_param(struct shader_parser *sp,
|
|||
|
||||
if (cf_token_is(&sp->cfp, ":")) {
|
||||
code = cf_next_name(&sp->cfp, &var->mapping,
|
||||
"mapping specifier", ")");
|
||||
"mapping specifier", ")");
|
||||
if (code != PARSE_SUCCESS)
|
||||
return code;
|
||||
|
||||
|
|
@ -396,7 +408,7 @@ static inline int sp_parse_func_param(struct shader_parser *sp,
|
|||
}
|
||||
|
||||
static bool sp_parse_func_params(struct shader_parser *sp,
|
||||
struct shader_func *func)
|
||||
struct shader_func *func)
|
||||
{
|
||||
struct cf_token peek;
|
||||
int code;
|
||||
|
|
@ -449,8 +461,8 @@ static void sp_parse_function(struct shader_parser *sp, char *type, char *name)
|
|||
/* if function is mapped to something, for example COLOR */
|
||||
if (cf_token_is(&sp->cfp, ":")) {
|
||||
char *mapping = NULL;
|
||||
int errorcode = cf_next_name(&sp->cfp, &mapping, "mapping",
|
||||
"{");
|
||||
int errorcode =
|
||||
cf_next_name(&sp->cfp, &mapping, "mapping", "{");
|
||||
if (errorcode != PARSE_SUCCESS)
|
||||
goto error;
|
||||
|
||||
|
|
@ -482,17 +494,18 @@ error:
|
|||
|
||||
/* parses "array[count]" */
|
||||
static bool sp_parse_param_array(struct shader_parser *sp,
|
||||
struct shader_var *param)
|
||||
struct shader_var *param)
|
||||
{
|
||||
if (!cf_next_valid_token(&sp->cfp))
|
||||
return false;
|
||||
|
||||
if (sp->cfp.cur_token->type != CFTOKEN_NUM ||
|
||||
!valid_int_str(sp->cfp.cur_token->str.array,
|
||||
sp->cfp.cur_token->str.len))
|
||||
sp->cfp.cur_token->str.len))
|
||||
return false;
|
||||
|
||||
param->array_count =(int)strtol(sp->cfp.cur_token->str.array, NULL, 10);
|
||||
param->array_count =
|
||||
(int)strtol(sp->cfp.cur_token->str.array, NULL, 10);
|
||||
|
||||
if (cf_next_token_should_be(&sp->cfp, "]", ";", NULL) == PARSE_EOF)
|
||||
return false;
|
||||
|
|
@ -504,7 +517,8 @@ static bool sp_parse_param_array(struct shader_parser *sp,
|
|||
}
|
||||
|
||||
static inline int sp_parse_param_assign_intfloat(struct shader_parser *sp,
|
||||
struct shader_var *param, bool is_float)
|
||||
struct shader_var *param,
|
||||
bool is_float)
|
||||
{
|
||||
int code;
|
||||
bool is_negative = false;
|
||||
|
|
@ -525,11 +539,13 @@ static inline int sp_parse_param_assign_intfloat(struct shader_parser *sp,
|
|||
|
||||
if (is_float) {
|
||||
float f = (float)os_strtod(sp->cfp.cur_token->str.array);
|
||||
if (is_negative) f = -f;
|
||||
if (is_negative)
|
||||
f = -f;
|
||||
da_push_back_array(param->default_val, &f, sizeof(float));
|
||||
} else {
|
||||
long l = strtol(sp->cfp.cur_token->str.array, NULL, 10);
|
||||
if (is_negative) l = -l;
|
||||
if (is_negative)
|
||||
l = -l;
|
||||
da_push_back_array(param->default_val, &l, sizeof(long));
|
||||
}
|
||||
|
||||
|
|
@ -541,47 +557,50 @@ static inline int sp_parse_param_assign_intfloat(struct shader_parser *sp,
|
|||
* for float3x3, float4x4, etc
|
||||
*/
|
||||
static inline int sp_parse_param_assign_float_array(struct shader_parser *sp,
|
||||
struct shader_var *param)
|
||||
struct shader_var *param)
|
||||
{
|
||||
const char *float_type = param->type+5;
|
||||
const char *float_type = param->type + 5;
|
||||
int float_count = 0, code, i;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
if (float_type[0] < '1' || float_type[0] > '4')
|
||||
cf_adderror(&sp->cfp, "Invalid row count", LEX_ERROR,
|
||||
NULL, NULL, NULL);
|
||||
cf_adderror(&sp->cfp, "Invalid row count", LEX_ERROR, NULL,
|
||||
NULL, NULL);
|
||||
|
||||
float_count = float_type[0]-'0';
|
||||
float_count = float_type[0] - '0';
|
||||
|
||||
if (float_type[1] == 'x') {
|
||||
if (float_type[2] < '1' || float_type[2] > '4')
|
||||
cf_adderror(&sp->cfp, "Invalid column count",
|
||||
LEX_ERROR, NULL, NULL, NULL);
|
||||
cf_adderror(&sp->cfp, "Invalid column count", LEX_ERROR,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
float_count *= float_type[2]-'0';
|
||||
float_count *= float_type[2] - '0';
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
code = cf_next_token_should_be(&sp->cfp, "{", ";", NULL);
|
||||
if (code != PARSE_SUCCESS) return code;
|
||||
if (code != PARSE_SUCCESS)
|
||||
return code;
|
||||
|
||||
for (i = 0; i < float_count; i++) {
|
||||
char *next = ((i+1) < float_count) ? "," : "}";
|
||||
char *next = ((i + 1) < float_count) ? "," : "}";
|
||||
|
||||
code = sp_parse_param_assign_intfloat(sp, param, true);
|
||||
if (code != PARSE_SUCCESS) return code;
|
||||
if (code != PARSE_SUCCESS)
|
||||
return code;
|
||||
|
||||
code = cf_next_token_should_be(&sp->cfp, next, ";", NULL);
|
||||
if (code != PARSE_SUCCESS) return code;
|
||||
if (code != PARSE_SUCCESS)
|
||||
return code;
|
||||
}
|
||||
|
||||
return PARSE_SUCCESS;
|
||||
}
|
||||
|
||||
static int sp_parse_param_assignment_val(struct shader_parser *sp,
|
||||
struct shader_var *param)
|
||||
struct shader_var *param)
|
||||
{
|
||||
if (strcmp(param->type, "int") == 0)
|
||||
return sp_parse_param_assign_intfloat(sp, param, false);
|
||||
|
|
@ -591,13 +610,13 @@ static int sp_parse_param_assignment_val(struct shader_parser *sp,
|
|||
return sp_parse_param_assign_float_array(sp, param);
|
||||
|
||||
cf_adderror(&sp->cfp, "Invalid type '$1' used for assignment",
|
||||
LEX_ERROR, param->type, NULL, NULL);
|
||||
LEX_ERROR, param->type, NULL, NULL);
|
||||
|
||||
return PARSE_CONTINUE;
|
||||
}
|
||||
|
||||
static inline bool sp_parse_param_assign(struct shader_parser *sp,
|
||||
struct shader_var *param)
|
||||
struct shader_var *param)
|
||||
{
|
||||
if (sp_parse_param_assignment_val(sp, param) != PARSE_SUCCESS)
|
||||
return false;
|
||||
|
|
@ -608,8 +627,8 @@ static inline bool sp_parse_param_assign(struct shader_parser *sp,
|
|||
return true;
|
||||
}
|
||||
|
||||
static void sp_parse_param(struct shader_parser *sp,
|
||||
char *type, char *name, bool is_const, bool is_uniform)
|
||||
static void sp_parse_param(struct shader_parser *sp, char *type, char *name,
|
||||
bool is_const, bool is_uniform)
|
||||
{
|
||||
struct shader_var param;
|
||||
shader_var_init_param(¶m, type, name, is_uniform, is_const);
|
||||
|
|
@ -631,10 +650,10 @@ error:
|
|||
shader_var_free(¶m);
|
||||
}
|
||||
|
||||
static bool sp_get_var_specifiers(struct shader_parser *sp,
|
||||
bool *is_const, bool *is_uniform)
|
||||
static bool sp_get_var_specifiers(struct shader_parser *sp, bool *is_const,
|
||||
bool *is_uniform)
|
||||
{
|
||||
while(true) {
|
||||
while (true) {
|
||||
int code = sp_check_for_keyword(sp, "const", is_const);
|
||||
if (code == PARSE_EOF)
|
||||
return false;
|
||||
|
|
@ -654,12 +673,13 @@ static bool sp_get_var_specifiers(struct shader_parser *sp,
|
|||
}
|
||||
|
||||
static inline void report_invalid_func_keyword(struct shader_parser *sp,
|
||||
const char *name, bool val)
|
||||
const char *name, bool val)
|
||||
{
|
||||
if (val)
|
||||
cf_adderror(&sp->cfp, "'$1' keyword cannot be used with a "
|
||||
"function", LEX_ERROR,
|
||||
name, NULL, NULL);
|
||||
cf_adderror(&sp->cfp,
|
||||
"'$1' keyword cannot be used with a "
|
||||
"function",
|
||||
LEX_ERROR, name, NULL, NULL);
|
||||
}
|
||||
|
||||
static void sp_parse_other(struct shader_parser *sp)
|
||||
|
|
@ -679,8 +699,8 @@ static void sp_parse_other(struct shader_parser *sp)
|
|||
goto error;
|
||||
|
||||
if (cf_token_is(&sp->cfp, "(")) {
|
||||
report_invalid_func_keyword(sp, "const", is_const);
|
||||
report_invalid_func_keyword(sp, "uniform", is_uniform);
|
||||
report_invalid_func_keyword(sp, "const", is_const);
|
||||
report_invalid_func_keyword(sp, "uniform", is_uniform);
|
||||
|
||||
sp_parse_function(sp, type, name);
|
||||
return;
|
||||
|
|
@ -695,7 +715,7 @@ error:
|
|||
}
|
||||
|
||||
bool shader_parse(struct shader_parser *sp, const char *shader,
|
||||
const char *file)
|
||||
const char *file)
|
||||
{
|
||||
if (!cf_parser_parse(&sp->cfp, shader, file))
|
||||
return false;
|
||||
|
|
@ -713,7 +733,7 @@ bool shader_parse(struct shader_parser *sp, const char *shader,
|
|||
|
||||
} else if (cf_token_is(&sp->cfp, "{")) {
|
||||
cf_adderror(&sp->cfp, "Unexpected code segment",
|
||||
LEX_ERROR, NULL, NULL, NULL);
|
||||
LEX_ERROR, NULL, NULL, NULL);
|
||||
cf_pass_pair(&sp->cfp, '{', '}');
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -61,9 +61,9 @@ static inline void shader_var_init(struct shader_var *sv)
|
|||
memset(sv, 0, sizeof(struct shader_var));
|
||||
}
|
||||
|
||||
static inline void shader_var_init_param(struct shader_var *sv,
|
||||
char *type, char *name, bool is_uniform,
|
||||
bool is_const)
|
||||
static inline void shader_var_init_param(struct shader_var *sv, char *type,
|
||||
char *name, bool is_uniform,
|
||||
bool is_const)
|
||||
{
|
||||
if (is_uniform)
|
||||
sv->var_type = SHADER_VAR_UNIFORM;
|
||||
|
|
@ -72,10 +72,11 @@ static inline void shader_var_init_param(struct shader_var *sv,
|
|||
else
|
||||
sv->var_type = SHADER_VAR_NONE;
|
||||
|
||||
sv->type = type;
|
||||
sv->name = name;
|
||||
sv->mapping = NULL;
|
||||
sv->type = type;
|
||||
sv->name = name;
|
||||
sv->mapping = NULL;
|
||||
sv->array_count = 0;
|
||||
sv->gl_sampler_id = (size_t)-1;
|
||||
da_init(sv->default_val);
|
||||
}
|
||||
|
||||
|
|
@ -91,8 +92,8 @@ static inline void shader_var_free(struct shader_var *sv)
|
|||
|
||||
struct shader_sampler {
|
||||
char *name;
|
||||
DARRAY(char*) states;
|
||||
DARRAY(char*) values;
|
||||
DARRAY(char *) states;
|
||||
DARRAY(char *) values;
|
||||
};
|
||||
|
||||
static inline void shader_sampler_init(struct shader_sampler *ss)
|
||||
|
|
@ -114,7 +115,7 @@ static inline void shader_sampler_free(struct shader_sampler *ss)
|
|||
}
|
||||
|
||||
EXPORT void shader_sampler_convert(struct shader_sampler *ss,
|
||||
struct gs_sampler_info *info);
|
||||
struct gs_sampler_info *info);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
|
|
@ -133,7 +134,7 @@ static inline void shader_struct_free(struct shader_struct *ss)
|
|||
size_t i;
|
||||
|
||||
for (i = 0; i < ss->vars.num; i++)
|
||||
shader_var_free(ss->vars.array+i);
|
||||
shader_var_free(ss->vars.array + i);
|
||||
|
||||
bfree(ss->name);
|
||||
da_free(ss->vars);
|
||||
|
|
@ -150,16 +151,16 @@ struct shader_func {
|
|||
struct cf_token *start, *end;
|
||||
};
|
||||
|
||||
static inline void shader_func_init(struct shader_func *sf,
|
||||
char *return_type, char *name)
|
||||
static inline void shader_func_init(struct shader_func *sf, char *return_type,
|
||||
char *name)
|
||||
{
|
||||
da_init(sf->params);
|
||||
|
||||
sf->return_type = return_type;
|
||||
sf->return_type = return_type;
|
||||
sf->mapping = NULL;
|
||||
sf->name = name;
|
||||
sf->start = NULL;
|
||||
sf->end = NULL;
|
||||
sf->name = name;
|
||||
sf->start = NULL;
|
||||
sf->end = NULL;
|
||||
}
|
||||
|
||||
static inline void shader_func_free(struct shader_func *sf)
|
||||
|
|
@ -167,7 +168,7 @@ static inline void shader_func_free(struct shader_func *sf)
|
|||
size_t i;
|
||||
|
||||
for (i = 0; i < sf->params.num; i++)
|
||||
shader_var_free(sf->params.array+i);
|
||||
shader_var_free(sf->params.array + i);
|
||||
|
||||
bfree(sf->name);
|
||||
bfree(sf->return_type);
|
||||
|
|
@ -180,10 +181,10 @@ static inline void shader_func_free(struct shader_func *sf)
|
|||
struct shader_parser {
|
||||
struct cf_parser cfp;
|
||||
|
||||
DARRAY(struct shader_var) params;
|
||||
DARRAY(struct shader_struct) structs;
|
||||
DARRAY(struct shader_var) params;
|
||||
DARRAY(struct shader_struct) structs;
|
||||
DARRAY(struct shader_sampler) samplers;
|
||||
DARRAY(struct shader_func) funcs;
|
||||
DARRAY(struct shader_func) funcs;
|
||||
};
|
||||
|
||||
static inline void shader_parser_init(struct shader_parser *sp)
|
||||
|
|
@ -201,13 +202,13 @@ static inline void shader_parser_free(struct shader_parser *sp)
|
|||
size_t i;
|
||||
|
||||
for (i = 0; i < sp->params.num; i++)
|
||||
shader_var_free(sp->params.array+i);
|
||||
shader_var_free(sp->params.array + i);
|
||||
for (i = 0; i < sp->structs.num; i++)
|
||||
shader_struct_free(sp->structs.array+i);
|
||||
shader_struct_free(sp->structs.array + i);
|
||||
for (i = 0; i < sp->samplers.num; i++)
|
||||
shader_sampler_free(sp->samplers.array+i);
|
||||
shader_sampler_free(sp->samplers.array + i);
|
||||
for (i = 0; i < sp->funcs.num; i++)
|
||||
shader_func_free(sp->funcs.array+i);
|
||||
shader_func_free(sp->funcs.array + i);
|
||||
|
||||
cf_parser_free(&sp->cfp);
|
||||
da_free(sp->params);
|
||||
|
|
@ -217,19 +218,19 @@ static inline void shader_parser_free(struct shader_parser *sp)
|
|||
}
|
||||
|
||||
EXPORT bool shader_parse(struct shader_parser *sp, const char *shader,
|
||||
const char *file);
|
||||
const char *file);
|
||||
|
||||
static inline char *shader_parser_geterrors(struct shader_parser *sp)
|
||||
{
|
||||
return error_data_buildstring(&sp->cfp.error_list);
|
||||
}
|
||||
|
||||
static inline struct shader_var *shader_parser_getparam(
|
||||
struct shader_parser *sp, const char *param_name)
|
||||
static inline struct shader_var *
|
||||
shader_parser_getparam(struct shader_parser *sp, const char *param_name)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < sp->params.num; i++) {
|
||||
struct shader_var *param = sp->params.array+i;
|
||||
struct shader_var *param = sp->params.array + i;
|
||||
if (strcmp(param->name, param_name) == 0)
|
||||
return param;
|
||||
}
|
||||
|
|
@ -237,12 +238,12 @@ static inline struct shader_var *shader_parser_getparam(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct shader_struct *shader_parser_getstruct(
|
||||
struct shader_parser *sp, const char *struct_name)
|
||||
static inline struct shader_struct *
|
||||
shader_parser_getstruct(struct shader_parser *sp, const char *struct_name)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < sp->structs.num; i++) {
|
||||
struct shader_struct *st = sp->structs.array+i;
|
||||
struct shader_struct *st = sp->structs.array + i;
|
||||
if (strcmp(st->name, struct_name) == 0)
|
||||
return st;
|
||||
}
|
||||
|
|
@ -250,12 +251,12 @@ static inline struct shader_struct *shader_parser_getstruct(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct shader_sampler *shader_parser_getsampler(
|
||||
struct shader_parser *sp, const char *sampler_name)
|
||||
static inline struct shader_sampler *
|
||||
shader_parser_getsampler(struct shader_parser *sp, const char *sampler_name)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < sp->samplers.num; i++) {
|
||||
struct shader_sampler *sampler = sp->samplers.array+i;
|
||||
struct shader_sampler *sampler = sp->samplers.array + i;
|
||||
if (strcmp(sampler->name, sampler_name) == 0)
|
||||
return sampler;
|
||||
}
|
||||
|
|
@ -263,12 +264,12 @@ static inline struct shader_sampler *shader_parser_getsampler(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct shader_func *shader_parser_getfunc(
|
||||
struct shader_parser *sp, const char *func_name)
|
||||
static inline struct shader_func *
|
||||
shader_parser_getfunc(struct shader_parser *sp, const char *func_name)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < sp->funcs.num; i++) {
|
||||
struct shader_func *func = sp->funcs.array+i;
|
||||
struct shader_func *func = sp->funcs.array + i;
|
||||
if (strcmp(func->name, func_name) == 0)
|
||||
return func;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,23 +24,23 @@
|
|||
#include "graphics.h"
|
||||
|
||||
struct gs_texture_render {
|
||||
gs_texture_t *target, *prev_target;
|
||||
gs_texture_t *target, *prev_target;
|
||||
gs_zstencil_t *zs, *prev_zs;
|
||||
|
||||
uint32_t cx, cy;
|
||||
|
||||
enum gs_color_format format;
|
||||
enum gs_color_format format;
|
||||
enum gs_zstencil_format zsformat;
|
||||
|
||||
bool rendered;
|
||||
};
|
||||
|
||||
gs_texrender_t *gs_texrender_create(enum gs_color_format format,
|
||||
enum gs_zstencil_format zsformat)
|
||||
enum gs_zstencil_format zsformat)
|
||||
{
|
||||
struct gs_texture_render *texrender;
|
||||
texrender = bzalloc(sizeof(struct gs_texture_render));
|
||||
texrender->format = format;
|
||||
texrender->format = format;
|
||||
texrender->zsformat = zsformat;
|
||||
|
||||
return texrender;
|
||||
|
|
@ -56,7 +56,7 @@ void gs_texrender_destroy(gs_texrender_t *texrender)
|
|||
}
|
||||
|
||||
static bool texrender_resetbuffer(gs_texrender_t *texrender, uint32_t cx,
|
||||
uint32_t cy)
|
||||
uint32_t cy)
|
||||
{
|
||||
if (!texrender)
|
||||
return false;
|
||||
|
|
@ -65,12 +65,12 @@ static bool texrender_resetbuffer(gs_texrender_t *texrender, uint32_t cx,
|
|||
gs_zstencil_destroy(texrender->zs);
|
||||
|
||||
texrender->target = NULL;
|
||||
texrender->zs = NULL;
|
||||
texrender->cx = cx;
|
||||
texrender->cy = cy;
|
||||
texrender->zs = NULL;
|
||||
texrender->cx = cx;
|
||||
texrender->cy = cy;
|
||||
|
||||
texrender->target = gs_texture_create(cx, cy, texrender->format,
|
||||
1, NULL, GS_RENDER_TARGET);
|
||||
texrender->target = gs_texture_create(cx, cy, texrender->format, 1,
|
||||
NULL, GS_RENDER_TARGET);
|
||||
if (!texrender->target)
|
||||
return false;
|
||||
|
||||
|
|
@ -108,7 +108,7 @@ bool gs_texrender_begin(gs_texrender_t *texrender, uint32_t cx, uint32_t cy)
|
|||
gs_matrix_identity();
|
||||
|
||||
texrender->prev_target = gs_get_render_target();
|
||||
texrender->prev_zs = gs_get_zstencil_target();
|
||||
texrender->prev_zs = gs_get_zstencil_target();
|
||||
gs_set_render_target(texrender->target, texrender->zs);
|
||||
|
||||
gs_set_viewport(0, 0, texrender->cx, texrender->cy);
|
||||
|
|
|
|||
|
|
@ -52,51 +52,47 @@ static inline void vec2_copy(struct vec2 *dst, const struct vec2 *v)
|
|||
}
|
||||
|
||||
static inline void vec2_add(struct vec2 *dst, const struct vec2 *v1,
|
||||
const struct vec2 *v2)
|
||||
const struct vec2 *v2)
|
||||
{
|
||||
vec2_set(dst, v1->x+v2->x, v1->y+v2->y);
|
||||
vec2_set(dst, v1->x + v2->x, v1->y + v2->y);
|
||||
}
|
||||
|
||||
static inline void vec2_sub(struct vec2 *dst, const struct vec2 *v1,
|
||||
const struct vec2 *v2)
|
||||
const struct vec2 *v2)
|
||||
{
|
||||
vec2_set(dst, v1->x-v2->x, v1->y-v2->y);
|
||||
vec2_set(dst, v1->x - v2->x, v1->y - v2->y);
|
||||
}
|
||||
|
||||
static inline void vec2_mul(struct vec2 *dst, const struct vec2 *v1,
|
||||
const struct vec2 *v2)
|
||||
const struct vec2 *v2)
|
||||
{
|
||||
vec2_set(dst, v1->x*v2->x, v1->y*v2->y);
|
||||
vec2_set(dst, v1->x * v2->x, v1->y * v2->y);
|
||||
}
|
||||
|
||||
static inline void vec2_div(struct vec2 *dst, const struct vec2 *v1,
|
||||
const struct vec2 *v2)
|
||||
const struct vec2 *v2)
|
||||
{
|
||||
vec2_set(dst, v1->x/v2->x, v1->y/v2->y);
|
||||
vec2_set(dst, v1->x / v2->x, v1->y / v2->y);
|
||||
}
|
||||
|
||||
static inline void vec2_addf(struct vec2 *dst, const struct vec2 *v,
|
||||
float f)
|
||||
static inline void vec2_addf(struct vec2 *dst, const struct vec2 *v, float f)
|
||||
{
|
||||
vec2_set(dst, v->x+f, v->y+f);
|
||||
vec2_set(dst, v->x + f, v->y + f);
|
||||
}
|
||||
|
||||
static inline void vec2_subf(struct vec2 *dst, const struct vec2 *v,
|
||||
float f)
|
||||
static inline void vec2_subf(struct vec2 *dst, const struct vec2 *v, float f)
|
||||
{
|
||||
vec2_set(dst, v->x-f, v->y-f);
|
||||
vec2_set(dst, v->x - f, v->y - f);
|
||||
}
|
||||
|
||||
static inline void vec2_mulf(struct vec2 *dst, const struct vec2 *v,
|
||||
float f)
|
||||
static inline void vec2_mulf(struct vec2 *dst, const struct vec2 *v, float f)
|
||||
{
|
||||
vec2_set(dst, v->x*f, v->y*f);
|
||||
vec2_set(dst, v->x * f, v->y * f);
|
||||
}
|
||||
|
||||
static inline void vec2_divf(struct vec2 *dst, const struct vec2 *v,
|
||||
float f)
|
||||
static inline void vec2_divf(struct vec2 *dst, const struct vec2 *v, float f)
|
||||
{
|
||||
vec2_set(dst, v->x/f, v->y/f);
|
||||
vec2_set(dst, v->x / f, v->y / f);
|
||||
}
|
||||
|
||||
static inline void vec2_neg(struct vec2 *dst, const struct vec2 *v)
|
||||
|
|
@ -106,12 +102,12 @@ static inline void vec2_neg(struct vec2 *dst, const struct vec2 *v)
|
|||
|
||||
static inline float vec2_dot(const struct vec2 *v1, const struct vec2 *v2)
|
||||
{
|
||||
return v1->x*v2->x + v1->y*v2->y;
|
||||
return v1->x * v2->x + v1->y * v2->y;
|
||||
}
|
||||
|
||||
static inline float vec2_len(const struct vec2 *v)
|
||||
{
|
||||
return sqrtf(v->x*v->x + v->y*v->y);
|
||||
return sqrtf(v->x * v->x + v->y * v->y);
|
||||
}
|
||||
|
||||
static inline float vec2_dist(const struct vec2 *v1, const struct vec2 *v2)
|
||||
|
|
@ -121,8 +117,7 @@ static inline float vec2_dist(const struct vec2 *v1, const struct vec2 *v2)
|
|||
return vec2_len(&temp);
|
||||
}
|
||||
|
||||
static inline void vec2_minf(struct vec2 *dst, const struct vec2 *v,
|
||||
float val)
|
||||
static inline void vec2_minf(struct vec2 *dst, const struct vec2 *v, float val)
|
||||
{
|
||||
if (v->x < val)
|
||||
dst->x = val;
|
||||
|
|
@ -131,7 +126,7 @@ static inline void vec2_minf(struct vec2 *dst, const struct vec2 *v,
|
|||
}
|
||||
|
||||
static inline void vec2_min(struct vec2 *dst, const struct vec2 *v,
|
||||
const struct vec2 *min_v)
|
||||
const struct vec2 *min_v)
|
||||
{
|
||||
if (v->x < min_v->x)
|
||||
dst->x = min_v->x;
|
||||
|
|
@ -139,8 +134,7 @@ static inline void vec2_min(struct vec2 *dst, const struct vec2 *v,
|
|||
dst->y = min_v->y;
|
||||
}
|
||||
|
||||
static inline void vec2_maxf(struct vec2 *dst, const struct vec2 *v,
|
||||
float val)
|
||||
static inline void vec2_maxf(struct vec2 *dst, const struct vec2 *v, float val)
|
||||
{
|
||||
if (v->x > val)
|
||||
dst->x = val;
|
||||
|
|
@ -149,7 +143,7 @@ static inline void vec2_maxf(struct vec2 *dst, const struct vec2 *v,
|
|||
}
|
||||
|
||||
static inline void vec2_max(struct vec2 *dst, const struct vec2 *v,
|
||||
const struct vec2 *max_v)
|
||||
const struct vec2 *max_v)
|
||||
{
|
||||
if (v->x > max_v->x)
|
||||
dst->x = max_v->x;
|
||||
|
|
@ -161,7 +155,7 @@ EXPORT void vec2_abs(struct vec2 *dst, const struct vec2 *v);
|
|||
EXPORT void vec2_floor(struct vec2 *dst, const struct vec2 *v);
|
||||
EXPORT void vec2_ceil(struct vec2 *dst, const struct vec2 *v);
|
||||
EXPORT int vec2_close(const struct vec2 *v1, const struct vec2 *v2,
|
||||
float epsilon);
|
||||
float epsilon);
|
||||
EXPORT void vec2_norm(struct vec2 *dst, const struct vec2 *v);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ float vec3_plane_dist(const struct vec3 *v, const struct plane *p)
|
|||
}
|
||||
|
||||
void vec3_rotate(struct vec3 *dst, const struct vec3 *v,
|
||||
const struct matrix3 *m)
|
||||
const struct matrix3 *m)
|
||||
{
|
||||
struct vec3 temp;
|
||||
vec3_copy(&temp, v);
|
||||
|
|
@ -47,7 +47,7 @@ void vec3_rotate(struct vec3 *dst, const struct vec3 *v,
|
|||
}
|
||||
|
||||
void vec3_transform(struct vec3 *dst, const struct vec3 *v,
|
||||
const struct matrix4 *m)
|
||||
const struct matrix4 *m)
|
||||
{
|
||||
struct vec4 v4;
|
||||
vec4_from_vec3(&v4, v);
|
||||
|
|
@ -56,7 +56,7 @@ void vec3_transform(struct vec3 *dst, const struct vec3 *v,
|
|||
}
|
||||
|
||||
void vec3_transform3x4(struct vec3 *dst, const struct vec3 *v,
|
||||
const struct matrix3 *m)
|
||||
const struct matrix3 *m)
|
||||
{
|
||||
struct vec3 temp;
|
||||
vec3_sub(&temp, v, &m->t);
|
||||
|
|
@ -75,7 +75,7 @@ void vec3_mirror(struct vec3 *dst, const struct vec3 *v, const struct plane *p)
|
|||
}
|
||||
|
||||
void vec3_mirrorv(struct vec3 *dst, const struct vec3 *v,
|
||||
const struct vec3 *vec)
|
||||
const struct vec3 *vec)
|
||||
{
|
||||
struct vec3 temp;
|
||||
vec3_mulf(&temp, vec, vec3_dot(v, vec) * 2.0f);
|
||||
|
|
|
|||
|
|
@ -58,54 +58,50 @@ static inline void vec3_copy(struct vec3 *dst, const struct vec3 *v)
|
|||
EXPORT void vec3_from_vec4(struct vec3 *dst, const struct vec4 *v);
|
||||
|
||||
static inline void vec3_add(struct vec3 *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2)
|
||||
const struct vec3 *v2)
|
||||
{
|
||||
dst->m = _mm_add_ps(v1->m, v2->m);
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec3_sub(struct vec3 *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2)
|
||||
const struct vec3 *v2)
|
||||
{
|
||||
dst->m = _mm_sub_ps(v1->m, v2->m);
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec3_mul(struct vec3 *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2)
|
||||
const struct vec3 *v2)
|
||||
{
|
||||
dst->m = _mm_mul_ps(v1->m, v2->m);
|
||||
}
|
||||
|
||||
static inline void vec3_div(struct vec3 *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2)
|
||||
const struct vec3 *v2)
|
||||
{
|
||||
dst->m = _mm_div_ps(v1->m, v2->m);
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec3_addf(struct vec3 *dst, const struct vec3 *v,
|
||||
float f)
|
||||
static inline void vec3_addf(struct vec3 *dst, const struct vec3 *v, float f)
|
||||
{
|
||||
dst->m = _mm_add_ps(v->m, _mm_set1_ps(f));
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec3_subf(struct vec3 *dst, const struct vec3 *v,
|
||||
float f)
|
||||
static inline void vec3_subf(struct vec3 *dst, const struct vec3 *v, float f)
|
||||
{
|
||||
dst->m = _mm_sub_ps(v->m, _mm_set1_ps(f));
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec3_mulf(struct vec3 *dst, const struct vec3 *v,
|
||||
float f)
|
||||
static inline void vec3_mulf(struct vec3 *dst, const struct vec3 *v, float f)
|
||||
{
|
||||
dst->m = _mm_mul_ps(v->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline void vec3_divf(struct vec3 *dst, const struct vec3 *v,
|
||||
float f)
|
||||
static inline void vec3_divf(struct vec3 *dst, const struct vec3 *v, float f)
|
||||
{
|
||||
dst->m = _mm_div_ps(v->m, _mm_set1_ps(f));
|
||||
dst->w = 0.0f;
|
||||
|
|
@ -121,7 +117,7 @@ static inline float vec3_dot(const struct vec3 *v1, const struct vec3 *v2)
|
|||
}
|
||||
|
||||
static inline void vec3_cross(struct vec3 *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2)
|
||||
const struct vec3 *v2)
|
||||
{
|
||||
__m128 s1v1 = _mm_shuffle_ps(v1->m, v1->m, _MM_SHUFFLE(3, 0, 2, 1));
|
||||
__m128 s1v2 = _mm_shuffle_ps(v2->m, v2->m, _MM_SHUFFLE(3, 1, 0, 2));
|
||||
|
|
@ -157,13 +153,13 @@ static inline float vec3_dist(const struct vec3 *v1, const struct vec3 *v2)
|
|||
static inline void vec3_norm(struct vec3 *dst, const struct vec3 *v)
|
||||
{
|
||||
float dot_val = vec3_dot(v, v);
|
||||
dst->m = (dot_val > 0.0f) ?
|
||||
_mm_mul_ps(v->m, _mm_set1_ps(1.0f/sqrtf(dot_val))) :
|
||||
_mm_setzero_ps();
|
||||
dst->m = (dot_val > 0.0f)
|
||||
? _mm_mul_ps(v->m, _mm_set1_ps(1.0f / sqrtf(dot_val)))
|
||||
: _mm_setzero_ps();
|
||||
}
|
||||
|
||||
static inline bool vec3_close(const struct vec3 *v1, const struct vec3 *v2,
|
||||
float epsilon)
|
||||
float epsilon)
|
||||
{
|
||||
struct vec3 test;
|
||||
vec3_sub(&test, v1, v2);
|
||||
|
|
@ -171,28 +167,26 @@ static inline bool vec3_close(const struct vec3 *v1, const struct vec3 *v2,
|
|||
}
|
||||
|
||||
static inline void vec3_min(struct vec3 *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2)
|
||||
const struct vec3 *v2)
|
||||
{
|
||||
dst->m = _mm_min_ps(v1->m, v2->m);
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec3_minf(struct vec3 *dst, const struct vec3 *v,
|
||||
float f)
|
||||
static inline void vec3_minf(struct vec3 *dst, const struct vec3 *v, float f)
|
||||
{
|
||||
dst->m = _mm_min_ps(v->m, _mm_set1_ps(f));
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec3_max(struct vec3 *dst, const struct vec3 *v1,
|
||||
const struct vec3 *v2)
|
||||
const struct vec3 *v2)
|
||||
{
|
||||
dst->m = _mm_max_ps(v1->m, v2->m);
|
||||
dst->w = 0.0f;
|
||||
}
|
||||
|
||||
static inline void vec3_maxf(struct vec3 *dst, const struct vec3 *v,
|
||||
float f)
|
||||
static inline void vec3_maxf(struct vec3 *dst, const struct vec3 *v, float f)
|
||||
{
|
||||
dst->m = _mm_max_ps(v->m, _mm_set1_ps(f));
|
||||
dst->w = 0.0f;
|
||||
|
|
@ -225,17 +219,17 @@ static inline void vec3_ceil(struct vec3 *dst, const struct vec3 *v)
|
|||
EXPORT float vec3_plane_dist(const struct vec3 *v, const struct plane *p);
|
||||
|
||||
EXPORT void vec3_transform(struct vec3 *dst, const struct vec3 *v,
|
||||
const struct matrix4 *m);
|
||||
const struct matrix4 *m);
|
||||
|
||||
EXPORT void vec3_rotate(struct vec3 *dst, const struct vec3 *v,
|
||||
const struct matrix3 *m);
|
||||
const struct matrix3 *m);
|
||||
EXPORT void vec3_transform3x4(struct vec3 *dst, const struct vec3 *v,
|
||||
const struct matrix3 *m);
|
||||
const struct matrix3 *m);
|
||||
|
||||
EXPORT void vec3_mirror(struct vec3 *dst, const struct vec3 *v,
|
||||
const struct plane *p);
|
||||
const struct plane *p);
|
||||
EXPORT void vec3_mirrorv(struct vec3 *dst, const struct vec3 *v,
|
||||
const struct vec3 *vec);
|
||||
const struct vec3 *vec);
|
||||
|
||||
EXPORT void vec3_rand(struct vec3 *dst, int positive_only);
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ void vec4_from_vec3(struct vec4 *dst, const struct vec3 *v)
|
|||
}
|
||||
|
||||
void vec4_transform(struct vec4 *dst, const struct vec4 *v,
|
||||
const struct matrix4 *m)
|
||||
const struct matrix4 *m)
|
||||
{
|
||||
struct vec4 temp;
|
||||
struct matrix4 transpose;
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ static inline void vec4_zero(struct vec4 *v)
|
|||
}
|
||||
|
||||
static inline void vec4_set(struct vec4 *dst, float x, float y, float z,
|
||||
float w)
|
||||
float w)
|
||||
{
|
||||
dst->m = _mm_set_ps(w, z, y, x);
|
||||
}
|
||||
|
|
@ -56,49 +56,45 @@ static inline void vec4_copy(struct vec4 *dst, const struct vec4 *v)
|
|||
EXPORT void vec4_from_vec3(struct vec4 *dst, const struct vec3 *v);
|
||||
|
||||
static inline void vec4_add(struct vec4 *dst, const struct vec4 *v1,
|
||||
const struct vec4 *v2)
|
||||
const struct vec4 *v2)
|
||||
{
|
||||
dst->m = _mm_add_ps(v1->m, v2->m);
|
||||
}
|
||||
|
||||
static inline void vec4_sub(struct vec4 *dst, const struct vec4 *v1,
|
||||
const struct vec4 *v2)
|
||||
const struct vec4 *v2)
|
||||
{
|
||||
dst->m = _mm_sub_ps(v1->m, v2->m);
|
||||
}
|
||||
|
||||
static inline void vec4_mul(struct vec4 *dst, const struct vec4 *v1,
|
||||
const struct vec4 *v2)
|
||||
const struct vec4 *v2)
|
||||
{
|
||||
dst->m = _mm_mul_ps(v1->m, v2->m);
|
||||
}
|
||||
|
||||
static inline void vec4_div(struct vec4 *dst, const struct vec4 *v1,
|
||||
const struct vec4 *v2)
|
||||
const struct vec4 *v2)
|
||||
{
|
||||
dst->m = _mm_div_ps(v1->m, v2->m);
|
||||
}
|
||||
|
||||
static inline void vec4_addf(struct vec4 *dst, const struct vec4 *v,
|
||||
float f)
|
||||
static inline void vec4_addf(struct vec4 *dst, const struct vec4 *v, float f)
|
||||
{
|
||||
dst->m = _mm_add_ps(v->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline void vec4_subf(struct vec4 *dst, const struct vec4 *v,
|
||||
float f)
|
||||
static inline void vec4_subf(struct vec4 *dst, const struct vec4 *v, float f)
|
||||
{
|
||||
dst->m = _mm_sub_ps(v->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline void vec4_mulf(struct vec4 *dst, const struct vec4 *v,
|
||||
float f)
|
||||
static inline void vec4_mulf(struct vec4 *dst, const struct vec4 *v, float f)
|
||||
{
|
||||
dst->m = _mm_mul_ps(v->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline void vec4_divf(struct vec4 *dst, const struct vec4 *v,
|
||||
float f)
|
||||
static inline void vec4_divf(struct vec4 *dst, const struct vec4 *v, float f)
|
||||
{
|
||||
dst->m = _mm_div_ps(v->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
|
@ -139,42 +135,38 @@ static inline float vec4_dist(const struct vec4 *v1, const struct vec4 *v2)
|
|||
static inline void vec4_norm(struct vec4 *dst, const struct vec4 *v)
|
||||
{
|
||||
float dot_val = vec4_dot(v, v);
|
||||
dst->m = (dot_val > 0.0f) ?
|
||||
_mm_mul_ps(v->m, _mm_set1_ps(1.0f/sqrtf(dot_val))) :
|
||||
_mm_setzero_ps();
|
||||
dst->m = (dot_val > 0.0f)
|
||||
? _mm_mul_ps(v->m, _mm_set1_ps(1.0f / sqrtf(dot_val)))
|
||||
: _mm_setzero_ps();
|
||||
}
|
||||
|
||||
static inline int vec4_close(const struct vec4 *v1, const struct vec4 *v2,
|
||||
float epsilon)
|
||||
float epsilon)
|
||||
{
|
||||
struct vec4 test;
|
||||
vec4_sub(&test, v1, v2);
|
||||
return test.x < epsilon &&
|
||||
test.y < epsilon &&
|
||||
test.z < epsilon &&
|
||||
return test.x < epsilon && test.y < epsilon && test.z < epsilon &&
|
||||
test.w < epsilon;
|
||||
}
|
||||
|
||||
static inline void vec4_min(struct vec4 *dst, const struct vec4 *v1,
|
||||
const struct vec4 *v2)
|
||||
const struct vec4 *v2)
|
||||
{
|
||||
dst->m = _mm_min_ps(v1->m, v2->m);
|
||||
}
|
||||
|
||||
static inline void vec4_minf(struct vec4 *dst, const struct vec4 *v,
|
||||
float f)
|
||||
static inline void vec4_minf(struct vec4 *dst, const struct vec4 *v, float f)
|
||||
{
|
||||
dst->m = _mm_min_ps(v->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
||||
static inline void vec4_max(struct vec4 *dst, const struct vec4 *v1,
|
||||
const struct vec4 *v2)
|
||||
const struct vec4 *v2)
|
||||
{
|
||||
dst->m = _mm_max_ps(v1->m, v2->m);
|
||||
}
|
||||
|
||||
static inline void vec4_maxf(struct vec4 *dst, const struct vec4 *v,
|
||||
float f)
|
||||
static inline void vec4_maxf(struct vec4 *dst, const struct vec4 *v, float f)
|
||||
{
|
||||
dst->m = _mm_max_ps(v->m, _mm_set1_ps(f));
|
||||
}
|
||||
|
|
@ -206,7 +198,7 @@ static inline void vec4_ceil(struct vec4 *dst, const struct vec4 *v)
|
|||
static inline uint32_t vec4_to_rgba(const struct vec4 *src)
|
||||
{
|
||||
uint32_t val;
|
||||
val = (uint32_t)((double)src->x * 255.0);
|
||||
val = (uint32_t)((double)src->x * 255.0);
|
||||
val |= (uint32_t)((double)src->y * 255.0) << 8;
|
||||
val |= (uint32_t)((double)src->z * 255.0) << 16;
|
||||
val |= (uint32_t)((double)src->w * 255.0) << 24;
|
||||
|
|
@ -216,7 +208,7 @@ static inline uint32_t vec4_to_rgba(const struct vec4 *src)
|
|||
static inline uint32_t vec4_to_bgra(const struct vec4 *src)
|
||||
{
|
||||
uint32_t val;
|
||||
val = (uint32_t)((double)src->z * 255.0);
|
||||
val = (uint32_t)((double)src->z * 255.0);
|
||||
val |= (uint32_t)((double)src->y * 255.0) << 8;
|
||||
val |= (uint32_t)((double)src->x * 255.0) << 16;
|
||||
val |= (uint32_t)((double)src->w * 255.0) << 24;
|
||||
|
|
@ -225,28 +217,28 @@ static inline uint32_t vec4_to_bgra(const struct vec4 *src)
|
|||
|
||||
static inline void vec4_from_rgba(struct vec4 *dst, uint32_t rgba)
|
||||
{
|
||||
dst->x = (float)((double)(rgba&0xFF) * (1.0/255.0));
|
||||
dst->x = (float)((double)(rgba & 0xFF) * (1.0 / 255.0));
|
||||
rgba >>= 8;
|
||||
dst->y = (float)((double)(rgba&0xFF) * (1.0/255.0));
|
||||
dst->y = (float)((double)(rgba & 0xFF) * (1.0 / 255.0));
|
||||
rgba >>= 8;
|
||||
dst->z = (float)((double)(rgba&0xFF) * (1.0/255.0));
|
||||
dst->z = (float)((double)(rgba & 0xFF) * (1.0 / 255.0));
|
||||
rgba >>= 8;
|
||||
dst->w = (float)((double)(rgba&0xFF) * (1.0/255.0));
|
||||
dst->w = (float)((double)(rgba & 0xFF) * (1.0 / 255.0));
|
||||
}
|
||||
|
||||
static inline void vec4_from_bgra(struct vec4 *dst, uint32_t bgra)
|
||||
{
|
||||
dst->z = (float)((double)(bgra&0xFF) * (1.0/255.0));
|
||||
dst->z = (float)((double)(bgra & 0xFF) * (1.0 / 255.0));
|
||||
bgra >>= 8;
|
||||
dst->y = (float)((double)(bgra&0xFF) * (1.0/255.0));
|
||||
dst->y = (float)((double)(bgra & 0xFF) * (1.0 / 255.0));
|
||||
bgra >>= 8;
|
||||
dst->x = (float)((double)(bgra&0xFF) * (1.0/255.0));
|
||||
dst->x = (float)((double)(bgra & 0xFF) * (1.0 / 255.0));
|
||||
bgra >>= 8;
|
||||
dst->w = (float)((double)(bgra&0xFF) * (1.0/255.0));
|
||||
dst->w = (float)((double)(bgra & 0xFF) * (1.0 / 255.0));
|
||||
}
|
||||
|
||||
EXPORT void vec4_transform(struct vec4 *dst, const struct vec4 *v,
|
||||
const struct matrix4 *m);
|
||||
const struct matrix4 *m);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
prefix=@DEST_DIR@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/@OBS_LIBRARY_DESTINATION@
|
||||
includedir=${prefix}/include
|
||||
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
|
||||
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||
|
||||
Name: libobs
|
||||
Description: OBS Studio Library
|
||||
|
|
|
|||
|
|
@ -31,11 +31,14 @@ extern profiler_name_store_t *obs_get_profiler_name_store(void);
|
|||
|
||||
/* #define DEBUG_AUDIO */
|
||||
|
||||
#define nop() do {int invalid = 0;} while(0)
|
||||
#define nop() \
|
||||
do { \
|
||||
int invalid = 0; \
|
||||
} while (0)
|
||||
|
||||
struct audio_input {
|
||||
struct audio_convert_info conversion;
|
||||
audio_resampler_t *resampler;
|
||||
audio_resampler_t *resampler;
|
||||
|
||||
audio_output_callback_t callback;
|
||||
void *param;
|
||||
|
|
@ -52,20 +55,20 @@ struct audio_mix {
|
|||
};
|
||||
|
||||
struct audio_output {
|
||||
struct audio_output_info info;
|
||||
size_t block_size;
|
||||
size_t channels;
|
||||
size_t planes;
|
||||
struct audio_output_info info;
|
||||
size_t block_size;
|
||||
size_t channels;
|
||||
size_t planes;
|
||||
|
||||
pthread_t thread;
|
||||
os_event_t *stop_event;
|
||||
pthread_t thread;
|
||||
os_event_t *stop_event;
|
||||
|
||||
bool initialized;
|
||||
bool initialized;
|
||||
|
||||
audio_input_callback_t input_cb;
|
||||
void *input_param;
|
||||
pthread_mutex_t input_mutex;
|
||||
struct audio_mix mixes[MAX_AUDIO_MIXES];
|
||||
audio_input_callback_t input_cb;
|
||||
void *input_param;
|
||||
pthread_mutex_t input_mutex;
|
||||
struct audio_mix mixes[MAX_AUDIO_MIXES];
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
|
@ -84,7 +87,7 @@ static inline double ts_to_frames(const audio_t *audio, uint64_t ts)
|
|||
|
||||
static inline double positive_round(double val)
|
||||
{
|
||||
return floor(val+0.5);
|
||||
return floor(val + 0.5);
|
||||
}
|
||||
|
||||
static int64_t ts_diff_frames(const audio_t *audio, uint64_t ts1, uint64_t ts2)
|
||||
|
|
@ -116,33 +119,32 @@ static inline size_t min_size(size_t a, size_t b)
|
|||
#endif
|
||||
|
||||
static bool resample_audio_output(struct audio_input *input,
|
||||
struct audio_data *data)
|
||||
struct audio_data *data)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
if (input->resampler) {
|
||||
uint8_t *output[MAX_AV_PLANES];
|
||||
uint8_t *output[MAX_AV_PLANES];
|
||||
uint32_t frames;
|
||||
uint64_t offset;
|
||||
|
||||
memset(output, 0, sizeof(output));
|
||||
|
||||
success = audio_resampler_resample(input->resampler,
|
||||
output, &frames, &offset,
|
||||
(const uint8_t *const *)data->data,
|
||||
data->frames);
|
||||
success = audio_resampler_resample(
|
||||
input->resampler, output, &frames, &offset,
|
||||
(const uint8_t *const *)data->data, data->frames);
|
||||
|
||||
for (size_t i = 0; i < MAX_AV_PLANES; i++)
|
||||
data->data[i] = output[i];
|
||||
data->frames = frames;
|
||||
data->frames = frames;
|
||||
data->timestamp -= offset;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static inline void do_audio_output(struct audio_output *audio,
|
||||
size_t mix_idx, uint64_t timestamp, uint32_t frames)
|
||||
static inline void do_audio_output(struct audio_output *audio, size_t mix_idx,
|
||||
uint64_t timestamp, uint32_t frames)
|
||||
{
|
||||
struct audio_mix *mix = &audio->mixes[mix_idx];
|
||||
struct audio_data data;
|
||||
|
|
@ -150,10 +152,10 @@ static inline void do_audio_output(struct audio_output *audio,
|
|||
pthread_mutex_lock(&audio->input_mutex);
|
||||
|
||||
for (size_t i = mix->inputs.num; i > 0; i--) {
|
||||
struct audio_input *input = mix->inputs.array+(i-1);
|
||||
struct audio_input *input = mix->inputs.array + (i - 1);
|
||||
|
||||
for (size_t i = 0; i < audio->planes; i++)
|
||||
data.data[i] = (uint8_t*)mix->buffer[i];
|
||||
data.data[i] = (uint8_t *)mix->buffer[i];
|
||||
data.frames = frames;
|
||||
data.timestamp = timestamp;
|
||||
|
||||
|
|
@ -181,7 +183,7 @@ static inline void clamp_audio_output(struct audio_output *audio, size_t bytes)
|
|||
|
||||
while (mix_data < mix_end) {
|
||||
float val = *mix_data;
|
||||
val = (val > 1.0f) ? 1.0f : val;
|
||||
val = (val > 1.0f) ? 1.0f : val;
|
||||
val = (val < -1.0f) ? -1.0f : val;
|
||||
*(mix_data++) = val;
|
||||
}
|
||||
|
|
@ -189,8 +191,8 @@ static inline void clamp_audio_output(struct audio_output *audio, size_t bytes)
|
|||
}
|
||||
}
|
||||
|
||||
static void input_and_output(struct audio_output *audio,
|
||||
uint64_t audio_time, uint64_t prev_time)
|
||||
static void input_and_output(struct audio_output *audio, uint64_t audio_time,
|
||||
uint64_t prev_time)
|
||||
{
|
||||
size_t bytes = AUDIO_OUTPUT_FRAMES * audio->block_size;
|
||||
struct audio_output_data data[MAX_AUDIO_MIXES];
|
||||
|
|
@ -202,7 +204,7 @@ static void input_and_output(struct audio_output *audio,
|
|||
|
||||
#ifdef DEBUG_AUDIO
|
||||
blog(LOG_DEBUG, "audio_time: %llu, prev_time: %llu, bytes: %lu",
|
||||
audio_time, prev_time, bytes);
|
||||
audio_time, prev_time, bytes);
|
||||
#endif
|
||||
|
||||
/* get mixers */
|
||||
|
|
@ -217,8 +219,9 @@ static void input_and_output(struct audio_output *audio,
|
|||
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], 0,
|
||||
AUDIO_OUTPUT_FRAMES * MAX_AUDIO_CHANNELS *
|
||||
sizeof(float));
|
||||
|
||||
for (size_t i = 0; i < audio->planes; i++)
|
||||
data[mix_idx].data[i] = mix->buffer[i];
|
||||
|
|
@ -226,7 +229,7 @@ static void input_and_output(struct audio_output *audio,
|
|||
|
||||
/* get new audio data */
|
||||
success = audio->input_cb(audio->input_param, prev_time, audio_time,
|
||||
&new_ts, active_mixes, data);
|
||||
&new_ts, active_mixes, data);
|
||||
if (!success)
|
||||
return;
|
||||
|
||||
|
|
@ -246,15 +249,14 @@ static void *audio_thread(void *param)
|
|||
uint64_t start_time = os_gettime_ns();
|
||||
uint64_t prev_time = start_time;
|
||||
uint64_t audio_time = prev_time;
|
||||
uint32_t audio_wait_time =
|
||||
(uint32_t)(audio_frames_to_ns(rate, AUDIO_OUTPUT_FRAMES) /
|
||||
1000000);
|
||||
uint32_t audio_wait_time = (uint32_t)(
|
||||
audio_frames_to_ns(rate, AUDIO_OUTPUT_FRAMES) / 1000000);
|
||||
|
||||
os_set_thread_name("audio-io: audio thread");
|
||||
|
||||
const char *audio_thread_name =
|
||||
profile_store_name(obs_get_profiler_name_store(),
|
||||
"audio_thread(%s)", audio->info.name);
|
||||
"audio_thread(%s)", audio->info.name);
|
||||
|
||||
while (os_event_try(audio->stop_event) == EAGAIN) {
|
||||
uint64_t cur_time;
|
||||
|
|
@ -266,8 +268,8 @@ static void *audio_thread(void *param)
|
|||
cur_time = os_gettime_ns();
|
||||
while (audio_time <= cur_time) {
|
||||
samples += AUDIO_OUTPUT_FRAMES;
|
||||
audio_time = start_time +
|
||||
audio_frames_to_ns(rate, samples);
|
||||
audio_time =
|
||||
start_time + audio_frames_to_ns(rate, samples);
|
||||
|
||||
input_and_output(audio, audio_time, prev_time);
|
||||
prev_time = audio_time;
|
||||
|
|
@ -284,12 +286,12 @@ static void *audio_thread(void *param)
|
|||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static size_t audio_get_input_idx(const audio_t *audio, size_t mix_idx,
|
||||
audio_output_callback_t callback, void *param)
|
||||
audio_output_callback_t callback, void *param)
|
||||
{
|
||||
const struct audio_mix *mix = &audio->mixes[mix_idx];
|
||||
|
||||
for (size_t i = 0; i < mix->inputs.num; i++) {
|
||||
struct audio_input *input = mix->inputs.array+i;
|
||||
struct audio_input *input = mix->inputs.array + i;
|
||||
|
||||
if (input->callback == callback && input->param == param)
|
||||
return i;
|
||||
|
|
@ -299,27 +301,25 @@ static size_t audio_get_input_idx(const audio_t *audio, size_t mix_idx,
|
|||
}
|
||||
|
||||
static inline bool audio_input_init(struct audio_input *input,
|
||||
struct audio_output *audio)
|
||||
struct audio_output *audio)
|
||||
{
|
||||
if (input->conversion.format != audio->info.format ||
|
||||
if (input->conversion.format != audio->info.format ||
|
||||
input->conversion.samples_per_sec != audio->info.samples_per_sec ||
|
||||
input->conversion.speakers != audio->info.speakers) {
|
||||
input->conversion.speakers != audio->info.speakers) {
|
||||
struct resample_info from = {
|
||||
.format = audio->info.format,
|
||||
.format = audio->info.format,
|
||||
.samples_per_sec = audio->info.samples_per_sec,
|
||||
.speakers = audio->info.speakers
|
||||
};
|
||||
.speakers = audio->info.speakers};
|
||||
|
||||
struct resample_info to = {
|
||||
.format = input->conversion.format,
|
||||
.format = input->conversion.format,
|
||||
.samples_per_sec = input->conversion.samples_per_sec,
|
||||
.speakers = input->conversion.speakers
|
||||
};
|
||||
.speakers = input->conversion.speakers};
|
||||
|
||||
input->resampler = audio_resampler_create(&to, &from);
|
||||
if (!input->resampler) {
|
||||
blog(LOG_ERROR, "audio_input_init: Failed to "
|
||||
"create resampler");
|
||||
"create resampler");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -330,12 +330,13 @@ static inline bool audio_input_init(struct audio_input *input,
|
|||
}
|
||||
|
||||
bool audio_output_connect(audio_t *audio, size_t mi,
|
||||
const struct audio_convert_info *conversion,
|
||||
audio_output_callback_t callback, void *param)
|
||||
const struct audio_convert_info *conversion,
|
||||
audio_output_callback_t callback, void *param)
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
if (!audio || mi >= MAX_AUDIO_MIXES) return false;
|
||||
if (!audio || mi >= MAX_AUDIO_MIXES)
|
||||
return false;
|
||||
|
||||
pthread_mutex_lock(&audio->input_mutex);
|
||||
|
||||
|
|
@ -343,7 +344,7 @@ bool audio_output_connect(audio_t *audio, size_t mi,
|
|||
struct audio_mix *mix = &audio->mixes[mi];
|
||||
struct audio_input input;
|
||||
input.callback = callback;
|
||||
input.param = param;
|
||||
input.param = param;
|
||||
|
||||
if (conversion) {
|
||||
input.conversion = *conversion;
|
||||
|
|
@ -373,16 +374,17 @@ bool audio_output_connect(audio_t *audio, size_t mi,
|
|||
}
|
||||
|
||||
void audio_output_disconnect(audio_t *audio, size_t mix_idx,
|
||||
audio_output_callback_t callback, void *param)
|
||||
audio_output_callback_t callback, void *param)
|
||||
{
|
||||
if (!audio || mix_idx >= MAX_AUDIO_MIXES) return;
|
||||
if (!audio || mix_idx >= MAX_AUDIO_MIXES)
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&audio->input_mutex);
|
||||
|
||||
size_t idx = audio_get_input_idx(audio, mix_idx, callback, param);
|
||||
if (idx != DARRAY_INVALID) {
|
||||
struct audio_mix *mix = &audio->mixes[mix_idx];
|
||||
audio_input_free(mix->inputs.array+idx);
|
||||
audio_input_free(mix->inputs.array + idx);
|
||||
da_erase(mix->inputs, idx);
|
||||
}
|
||||
|
||||
|
|
@ -409,12 +411,12 @@ int audio_output_open(audio_t **audio, struct audio_output_info *info)
|
|||
goto fail;
|
||||
|
||||
memcpy(&out->info, info, sizeof(struct audio_output_info));
|
||||
out->channels = get_audio_channels(info->speakers);
|
||||
out->planes = planar ? out->channels : 1;
|
||||
out->input_cb = info->input_callback;
|
||||
out->input_param= info->input_param;
|
||||
out->channels = get_audio_channels(info->speakers);
|
||||
out->planes = planar ? out->channels : 1;
|
||||
out->input_cb = info->input_callback;
|
||||
out->input_param = info->input_param;
|
||||
out->block_size = (planar ? 1 : out->channels) *
|
||||
get_audio_bytes_per_channel(info->format);
|
||||
get_audio_bytes_per_channel(info->format);
|
||||
|
||||
if (pthread_mutexattr_init(&attr) != 0)
|
||||
goto fail;
|
||||
|
|
@ -452,7 +454,7 @@ void audio_output_close(audio_t *audio)
|
|||
struct audio_mix *mix = &audio->mixes[mix_idx];
|
||||
|
||||
for (size_t i = 0; i < mix->inputs.num; i++)
|
||||
audio_input_free(mix->inputs.array+i);
|
||||
audio_input_free(mix->inputs.array + i);
|
||||
|
||||
da_free(mix->inputs);
|
||||
}
|
||||
|
|
@ -468,7 +470,8 @@ const struct audio_output_info *audio_output_get_info(const audio_t *audio)
|
|||
|
||||
bool audio_output_active(const audio_t *audio)
|
||||
{
|
||||
if (!audio) return false;
|
||||
if (!audio)
|
||||
return false;
|
||||
|
||||
for (size_t mix_idx = 0; mix_idx < MAX_AUDIO_MIXES; mix_idx++) {
|
||||
const struct audio_mix *mix = &audio->mixes[mix_idx];
|
||||
|
|
|
|||
|
|
@ -25,13 +25,13 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_AUDIO_MIXES 6
|
||||
#define MAX_AUDIO_CHANNELS 8
|
||||
#define MAX_AUDIO_MIXES 6
|
||||
#define MAX_AUDIO_CHANNELS 8
|
||||
#define AUDIO_OUTPUT_FRAMES 1024
|
||||
|
||||
#define TOTAL_AUDIO_SIZE \
|
||||
(MAX_AUDIO_MIXES * MAX_AUDIO_CHANNELS * \
|
||||
AUDIO_OUTPUT_FRAMES * sizeof(float))
|
||||
#define TOTAL_AUDIO_SIZE \
|
||||
(MAX_AUDIO_MIXES * MAX_AUDIO_CHANNELS * AUDIO_OUTPUT_FRAMES * \
|
||||
sizeof(float))
|
||||
|
||||
/*
|
||||
* Base audio output component. Use this to create an audio output track
|
||||
|
|
@ -65,58 +65,67 @@ enum audio_format {
|
|||
* https://trac.ffmpeg.org/wiki/AudioChannelManipulation
|
||||
*/
|
||||
enum speaker_layout {
|
||||
SPEAKERS_UNKNOWN, /**< Unknown setting, fallback is stereo. */
|
||||
SPEAKERS_MONO, /**< Channels: MONO */
|
||||
SPEAKERS_STEREO, /**< Channels: FL, FR */
|
||||
SPEAKERS_2POINT1, /**< Channels: FL, FR, LFE */
|
||||
SPEAKERS_4POINT0, /**< Channels: FL, FR, FC, RC */
|
||||
SPEAKERS_4POINT1, /**< Channels: FL, FR, FC, LFE, RC */
|
||||
SPEAKERS_5POINT1, /**< Channels: FL, FR, FC, LFE, RL, RR */
|
||||
SPEAKERS_7POINT1=8, /**< Channels: FL, FR, FC, LFE, RL, RR, SL, SR */
|
||||
SPEAKERS_UNKNOWN, /**< Unknown setting, fallback is stereo. */
|
||||
SPEAKERS_MONO, /**< Channels: MONO */
|
||||
SPEAKERS_STEREO, /**< Channels: FL, FR */
|
||||
SPEAKERS_2POINT1, /**< Channels: FL, FR, LFE */
|
||||
SPEAKERS_4POINT0, /**< Channels: FL, FR, FC, RC */
|
||||
SPEAKERS_4POINT1, /**< Channels: FL, FR, FC, LFE, RC */
|
||||
SPEAKERS_5POINT1, /**< Channels: FL, FR, FC, LFE, RL, RR */
|
||||
SPEAKERS_7POINT1 = 8, /**< Channels: FL, FR, FC, LFE, RL, RR, SL, SR */
|
||||
};
|
||||
|
||||
struct audio_data {
|
||||
uint8_t *data[MAX_AV_PLANES];
|
||||
uint32_t frames;
|
||||
uint64_t timestamp;
|
||||
uint8_t *data[MAX_AV_PLANES];
|
||||
uint32_t frames;
|
||||
uint64_t timestamp;
|
||||
};
|
||||
|
||||
struct audio_output_data {
|
||||
float *data[MAX_AUDIO_CHANNELS];
|
||||
float *data[MAX_AUDIO_CHANNELS];
|
||||
};
|
||||
|
||||
typedef bool (*audio_input_callback_t)(void *param,
|
||||
uint64_t start_ts, uint64_t end_ts, uint64_t *new_ts,
|
||||
uint32_t active_mixers, struct audio_output_data *mixes);
|
||||
typedef bool (*audio_input_callback_t)(void *param, uint64_t start_ts,
|
||||
uint64_t end_ts, uint64_t *new_ts,
|
||||
uint32_t active_mixers,
|
||||
struct audio_output_data *mixes);
|
||||
|
||||
struct audio_output_info {
|
||||
const char *name;
|
||||
const char *name;
|
||||
|
||||
uint32_t samples_per_sec;
|
||||
enum audio_format format;
|
||||
uint32_t samples_per_sec;
|
||||
enum audio_format format;
|
||||
enum speaker_layout speakers;
|
||||
|
||||
audio_input_callback_t input_callback;
|
||||
void *input_param;
|
||||
void *input_param;
|
||||
};
|
||||
|
||||
struct audio_convert_info {
|
||||
uint32_t samples_per_sec;
|
||||
enum audio_format format;
|
||||
uint32_t samples_per_sec;
|
||||
enum audio_format format;
|
||||
enum speaker_layout speakers;
|
||||
};
|
||||
|
||||
static inline uint32_t get_audio_channels(enum speaker_layout speakers)
|
||||
{
|
||||
switch (speakers) {
|
||||
case SPEAKERS_MONO: return 1;
|
||||
case SPEAKERS_STEREO: return 2;
|
||||
case SPEAKERS_2POINT1: return 3;
|
||||
case SPEAKERS_4POINT0: return 4;
|
||||
case SPEAKERS_4POINT1: return 5;
|
||||
case SPEAKERS_5POINT1: return 6;
|
||||
case SPEAKERS_7POINT1: return 8;
|
||||
case SPEAKERS_UNKNOWN: return 0;
|
||||
case SPEAKERS_MONO:
|
||||
return 1;
|
||||
case SPEAKERS_STEREO:
|
||||
return 2;
|
||||
case SPEAKERS_2POINT1:
|
||||
return 3;
|
||||
case SPEAKERS_4POINT0:
|
||||
return 4;
|
||||
case SPEAKERS_4POINT1:
|
||||
return 5;
|
||||
case SPEAKERS_5POINT1:
|
||||
return 6;
|
||||
case SPEAKERS_7POINT1:
|
||||
return 8;
|
||||
case SPEAKERS_UNKNOWN:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -169,23 +178,22 @@ static inline bool is_audio_planar(enum audio_format format)
|
|||
}
|
||||
|
||||
static inline size_t get_audio_planes(enum audio_format format,
|
||||
enum speaker_layout speakers)
|
||||
enum speaker_layout speakers)
|
||||
{
|
||||
return (is_audio_planar(format) ? get_audio_channels(speakers) : 1);
|
||||
}
|
||||
|
||||
static inline size_t get_audio_size(enum audio_format format,
|
||||
enum speaker_layout speakers, uint32_t frames)
|
||||
enum speaker_layout speakers,
|
||||
uint32_t frames)
|
||||
{
|
||||
bool planar = is_audio_planar(format);
|
||||
|
||||
return (planar ? 1 : get_audio_channels(speakers)) *
|
||||
get_audio_bytes_per_channel(format) *
|
||||
frames;
|
||||
get_audio_bytes_per_channel(format) * frames;
|
||||
}
|
||||
|
||||
static inline uint64_t audio_frames_to_ns(size_t sample_rate,
|
||||
uint64_t frames)
|
||||
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);
|
||||
|
|
@ -193,8 +201,7 @@ static inline uint64_t audio_frames_to_ns(size_t sample_rate,
|
|||
return val.low;
|
||||
}
|
||||
|
||||
static inline uint64_t ns_to_audio_frames(size_t sample_rate,
|
||||
uint64_t frames)
|
||||
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);
|
||||
|
|
@ -202,21 +209,22 @@ static inline uint64_t ns_to_audio_frames(size_t sample_rate,
|
|||
return val.low;
|
||||
}
|
||||
|
||||
#define AUDIO_OUTPUT_SUCCESS 0
|
||||
#define AUDIO_OUTPUT_SUCCESS 0
|
||||
#define AUDIO_OUTPUT_INVALIDPARAM -1
|
||||
#define AUDIO_OUTPUT_FAIL -2
|
||||
#define AUDIO_OUTPUT_FAIL -2
|
||||
|
||||
EXPORT int audio_output_open(audio_t **audio, struct audio_output_info *info);
|
||||
EXPORT void audio_output_close(audio_t *audio);
|
||||
|
||||
typedef void (*audio_output_callback_t)(void *param, size_t mix_idx,
|
||||
struct audio_data *data);
|
||||
struct audio_data *data);
|
||||
|
||||
EXPORT bool audio_output_connect(audio_t *video, size_t mix_idx,
|
||||
const struct audio_convert_info *conversion,
|
||||
audio_output_callback_t callback, void *param);
|
||||
const struct audio_convert_info *conversion,
|
||||
audio_output_callback_t callback, void *param);
|
||||
EXPORT void audio_output_disconnect(audio_t *video, size_t mix_idx,
|
||||
audio_output_callback_t callback, void *param);
|
||||
audio_output_callback_t callback,
|
||||
void *param);
|
||||
|
||||
EXPORT bool audio_output_active(const audio_t *audio);
|
||||
|
||||
|
|
@ -224,9 +232,8 @@ EXPORT size_t audio_output_get_block_size(const audio_t *audio);
|
|||
EXPORT size_t audio_output_get_planes(const audio_t *audio);
|
||||
EXPORT size_t audio_output_get_channels(const audio_t *audio);
|
||||
EXPORT uint32_t audio_output_get_sample_rate(const audio_t *audio);
|
||||
EXPORT const struct audio_output_info *audio_output_get_info(
|
||||
const audio_t *audio);
|
||||
|
||||
EXPORT const struct audio_output_info *
|
||||
audio_output_get_info(const audio_t *audio);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,34 +23,43 @@
|
|||
#include <libswresample/swresample.h>
|
||||
|
||||
struct audio_resampler {
|
||||
struct SwrContext *context;
|
||||
bool opened;
|
||||
struct SwrContext *context;
|
||||
bool opened;
|
||||
|
||||
uint32_t input_freq;
|
||||
uint64_t input_layout;
|
||||
uint32_t input_freq;
|
||||
uint64_t input_layout;
|
||||
enum AVSampleFormat input_format;
|
||||
|
||||
uint8_t *output_buffer[MAX_AV_PLANES];
|
||||
uint64_t output_layout;
|
||||
uint8_t *output_buffer[MAX_AV_PLANES];
|
||||
uint64_t output_layout;
|
||||
enum AVSampleFormat output_format;
|
||||
int output_size;
|
||||
uint32_t output_ch;
|
||||
uint32_t output_freq;
|
||||
uint32_t output_planes;
|
||||
int output_size;
|
||||
uint32_t output_ch;
|
||||
uint32_t output_freq;
|
||||
uint32_t output_planes;
|
||||
};
|
||||
|
||||
static inline enum AVSampleFormat convert_audio_format(enum audio_format format)
|
||||
{
|
||||
switch (format) {
|
||||
case AUDIO_FORMAT_UNKNOWN: return AV_SAMPLE_FMT_S16;
|
||||
case AUDIO_FORMAT_U8BIT: return AV_SAMPLE_FMT_U8;
|
||||
case AUDIO_FORMAT_16BIT: return AV_SAMPLE_FMT_S16;
|
||||
case AUDIO_FORMAT_32BIT: return AV_SAMPLE_FMT_S32;
|
||||
case AUDIO_FORMAT_FLOAT: return AV_SAMPLE_FMT_FLT;
|
||||
case AUDIO_FORMAT_U8BIT_PLANAR: return AV_SAMPLE_FMT_U8P;
|
||||
case AUDIO_FORMAT_16BIT_PLANAR: return AV_SAMPLE_FMT_S16P;
|
||||
case AUDIO_FORMAT_32BIT_PLANAR: return AV_SAMPLE_FMT_S32P;
|
||||
case AUDIO_FORMAT_FLOAT_PLANAR: return AV_SAMPLE_FMT_FLTP;
|
||||
case AUDIO_FORMAT_UNKNOWN:
|
||||
return AV_SAMPLE_FMT_S16;
|
||||
case AUDIO_FORMAT_U8BIT:
|
||||
return AV_SAMPLE_FMT_U8;
|
||||
case AUDIO_FORMAT_16BIT:
|
||||
return AV_SAMPLE_FMT_S16;
|
||||
case AUDIO_FORMAT_32BIT:
|
||||
return AV_SAMPLE_FMT_S32;
|
||||
case AUDIO_FORMAT_FLOAT:
|
||||
return AV_SAMPLE_FMT_FLT;
|
||||
case AUDIO_FORMAT_U8BIT_PLANAR:
|
||||
return AV_SAMPLE_FMT_U8P;
|
||||
case AUDIO_FORMAT_16BIT_PLANAR:
|
||||
return AV_SAMPLE_FMT_S16P;
|
||||
case AUDIO_FORMAT_32BIT_PLANAR:
|
||||
return AV_SAMPLE_FMT_S32P;
|
||||
case AUDIO_FORMAT_FLOAT_PLANAR:
|
||||
return AV_SAMPLE_FMT_FLTP;
|
||||
}
|
||||
|
||||
/* shouldn't get here */
|
||||
|
|
@ -60,14 +69,22 @@ static inline enum AVSampleFormat convert_audio_format(enum audio_format format)
|
|||
static inline uint64_t convert_speaker_layout(enum speaker_layout layout)
|
||||
{
|
||||
switch (layout) {
|
||||
case SPEAKERS_UNKNOWN: return 0;
|
||||
case SPEAKERS_MONO: return AV_CH_LAYOUT_MONO;
|
||||
case SPEAKERS_STEREO: return AV_CH_LAYOUT_STEREO;
|
||||
case SPEAKERS_2POINT1: return AV_CH_LAYOUT_SURROUND;
|
||||
case SPEAKERS_4POINT0: return AV_CH_LAYOUT_4POINT0;
|
||||
case SPEAKERS_4POINT1: return AV_CH_LAYOUT_4POINT1;
|
||||
case SPEAKERS_5POINT1: return AV_CH_LAYOUT_5POINT1_BACK;
|
||||
case SPEAKERS_7POINT1: return AV_CH_LAYOUT_7POINT1;
|
||||
case SPEAKERS_UNKNOWN:
|
||||
return 0;
|
||||
case SPEAKERS_MONO:
|
||||
return AV_CH_LAYOUT_MONO;
|
||||
case SPEAKERS_STEREO:
|
||||
return AV_CH_LAYOUT_STEREO;
|
||||
case SPEAKERS_2POINT1:
|
||||
return AV_CH_LAYOUT_SURROUND;
|
||||
case SPEAKERS_4POINT0:
|
||||
return AV_CH_LAYOUT_4POINT0;
|
||||
case SPEAKERS_4POINT1:
|
||||
return AV_CH_LAYOUT_4POINT1;
|
||||
case SPEAKERS_5POINT1:
|
||||
return AV_CH_LAYOUT_5POINT1_BACK;
|
||||
case SPEAKERS_7POINT1:
|
||||
return AV_CH_LAYOUT_7POINT1;
|
||||
}
|
||||
|
||||
/* shouldn't get here */
|
||||
|
|
@ -75,26 +92,27 @@ static inline uint64_t convert_speaker_layout(enum speaker_layout layout)
|
|||
}
|
||||
|
||||
audio_resampler_t *audio_resampler_create(const struct resample_info *dst,
|
||||
const struct resample_info *src)
|
||||
const struct resample_info *src)
|
||||
{
|
||||
struct audio_resampler *rs = bzalloc(sizeof(struct audio_resampler));
|
||||
int errcode;
|
||||
|
||||
rs->opened = false;
|
||||
rs->input_freq = src->samples_per_sec;
|
||||
rs->input_layout = convert_speaker_layout(src->speakers);
|
||||
rs->input_format = convert_audio_format(src->format);
|
||||
rs->output_size = 0;
|
||||
rs->output_ch = get_audio_channels(dst->speakers);
|
||||
rs->output_freq = dst->samples_per_sec;
|
||||
rs->opened = false;
|
||||
rs->input_freq = src->samples_per_sec;
|
||||
rs->input_layout = convert_speaker_layout(src->speakers);
|
||||
rs->input_format = convert_audio_format(src->format);
|
||||
rs->output_size = 0;
|
||||
rs->output_ch = get_audio_channels(dst->speakers);
|
||||
rs->output_freq = dst->samples_per_sec;
|
||||
rs->output_layout = convert_speaker_layout(dst->speakers);
|
||||
rs->output_format = convert_audio_format(dst->format);
|
||||
rs->output_planes = is_audio_planar(dst->format) ? rs->output_ch : 1;
|
||||
|
||||
rs->context = swr_alloc_set_opts(NULL,
|
||||
rs->output_layout, rs->output_format, dst->samples_per_sec,
|
||||
rs->input_layout, rs->input_format, src->samples_per_sec,
|
||||
0, NULL);
|
||||
rs->context = swr_alloc_set_opts(NULL, rs->output_layout,
|
||||
rs->output_format,
|
||||
dst->samples_per_sec, rs->input_layout,
|
||||
rs->input_format, src->samples_per_sec,
|
||||
0, NULL);
|
||||
|
||||
if (!rs->context) {
|
||||
blog(LOG_ERROR, "swr_alloc_set_opts failed");
|
||||
|
|
@ -104,23 +122,25 @@ audio_resampler_t *audio_resampler_create(const struct resample_info *dst,
|
|||
|
||||
if (rs->input_layout == AV_CH_LAYOUT_MONO && rs->output_ch > 1) {
|
||||
const double matrix[MAX_AUDIO_CHANNELS][MAX_AUDIO_CHANNELS] = {
|
||||
{1},
|
||||
{1, 1},
|
||||
{1, 1, 0},
|
||||
{1, 1, 1, 1},
|
||||
{1, 1, 1, 0, 1},
|
||||
{1, 1, 1, 1, 1, 1},
|
||||
{1, 1, 1, 0, 1, 1, 1},
|
||||
{1, 1, 1, 0, 1, 1, 1, 1},
|
||||
{1},
|
||||
{1, 1},
|
||||
{1, 1, 0},
|
||||
{1, 1, 1, 1},
|
||||
{1, 1, 1, 0, 1},
|
||||
{1, 1, 1, 1, 1, 1},
|
||||
{1, 1, 1, 0, 1, 1, 1},
|
||||
{1, 1, 1, 0, 1, 1, 1, 1},
|
||||
};
|
||||
if (swr_set_matrix(rs->context, matrix[rs->output_ch - 1], 1) < 0)
|
||||
blog(LOG_DEBUG, "swr_set_matrix failed for mono upmix\n");
|
||||
if (swr_set_matrix(rs->context, matrix[rs->output_ch - 1], 1) <
|
||||
0)
|
||||
blog(LOG_DEBUG,
|
||||
"swr_set_matrix failed for mono upmix\n");
|
||||
}
|
||||
|
||||
errcode = swr_init(rs->context);
|
||||
if (errcode != 0) {
|
||||
blog(LOG_ERROR, "avresample_open failed: error code %d",
|
||||
errcode);
|
||||
errcode);
|
||||
audio_resampler_destroy(rs);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -140,20 +160,21 @@ void audio_resampler_destroy(audio_resampler_t *rs)
|
|||
}
|
||||
}
|
||||
|
||||
bool audio_resampler_resample(audio_resampler_t *rs,
|
||||
uint8_t *output[], uint32_t *out_frames, uint64_t *ts_offset,
|
||||
const uint8_t *const input[], uint32_t in_frames)
|
||||
bool audio_resampler_resample(audio_resampler_t *rs, uint8_t *output[],
|
||||
uint32_t *out_frames, uint64_t *ts_offset,
|
||||
const uint8_t *const input[], uint32_t in_frames)
|
||||
{
|
||||
if (!rs) return false;
|
||||
if (!rs)
|
||||
return false;
|
||||
|
||||
struct SwrContext *context = rs->context;
|
||||
int ret;
|
||||
|
||||
int64_t delay = swr_get_delay(context, rs->input_freq);
|
||||
int estimated = (int)av_rescale_rnd(
|
||||
delay + (int64_t)in_frames,
|
||||
(int64_t)rs->output_freq, (int64_t)rs->input_freq,
|
||||
AV_ROUND_UP);
|
||||
int estimated = (int)av_rescale_rnd(delay + (int64_t)in_frames,
|
||||
(int64_t)rs->output_freq,
|
||||
(int64_t)rs->input_freq,
|
||||
AV_ROUND_UP);
|
||||
|
||||
*ts_offset = (uint64_t)swr_get_delay(context, 1000000000);
|
||||
|
||||
|
|
@ -163,14 +184,13 @@ bool audio_resampler_resample(audio_resampler_t *rs,
|
|||
av_freep(&rs->output_buffer[0]);
|
||||
|
||||
av_samples_alloc(rs->output_buffer, NULL, rs->output_ch,
|
||||
estimated, rs->output_format, 0);
|
||||
estimated, rs->output_format, 0);
|
||||
|
||||
rs->output_size = estimated;
|
||||
}
|
||||
|
||||
ret = swr_convert(context,
|
||||
rs->output_buffer, rs->output_size,
|
||||
(const uint8_t**)input, in_frames);
|
||||
ret = swr_convert(context, rs->output_buffer, rs->output_size,
|
||||
(const uint8_t **)input, in_frames);
|
||||
|
||||
if (ret < 0) {
|
||||
blog(LOG_ERROR, "swr_convert failed: %d", ret);
|
||||
|
|
|
|||
|
|
@ -28,18 +28,21 @@ struct audio_resampler;
|
|||
typedef struct audio_resampler audio_resampler_t;
|
||||
|
||||
struct resample_info {
|
||||
uint32_t samples_per_sec;
|
||||
enum audio_format format;
|
||||
uint32_t samples_per_sec;
|
||||
enum audio_format format;
|
||||
enum speaker_layout speakers;
|
||||
};
|
||||
|
||||
EXPORT audio_resampler_t *audio_resampler_create(const struct resample_info *dst,
|
||||
const struct resample_info *src);
|
||||
EXPORT audio_resampler_t *
|
||||
audio_resampler_create(const struct resample_info *dst,
|
||||
const struct resample_info *src);
|
||||
EXPORT void audio_resampler_destroy(audio_resampler_t *resampler);
|
||||
|
||||
EXPORT bool audio_resampler_resample(audio_resampler_t *resampler,
|
||||
uint8_t *output[], uint32_t *out_frames, uint64_t *ts_offset,
|
||||
const uint8_t *const input[], uint32_t in_frames);
|
||||
uint8_t *output[], uint32_t *out_frames,
|
||||
uint64_t *ts_offset,
|
||||
const uint8_t *const input[],
|
||||
uint32_t in_frames);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,194 +22,191 @@
|
|||
/* ...surprisingly, if I don't use a macro to force inlining, it causes the
|
||||
* CPU usage to boost by a tremendous amount in debug builds. */
|
||||
|
||||
#define get_m128_32_0(val) (*((uint32_t*)&val))
|
||||
#define get_m128_32_1(val) (*(((uint32_t*)&val)+1))
|
||||
#define get_m128_32_0(val) (*((uint32_t *)&val))
|
||||
#define get_m128_32_1(val) (*(((uint32_t *)&val) + 1))
|
||||
|
||||
#define pack_shift(lum_plane, lum_pos0, lum_pos1, line1, line2, mask, sh) \
|
||||
do { \
|
||||
__m128i pack_val = _mm_packs_epi32( \
|
||||
_mm_srli_si128(_mm_and_si128(line1, mask), sh), \
|
||||
_mm_srli_si128(_mm_and_si128(line2, mask), sh)); \
|
||||
pack_val = _mm_packus_epi16(pack_val, pack_val); \
|
||||
\
|
||||
*(uint32_t*)(lum_plane+lum_pos0) = get_m128_32_0(pack_val); \
|
||||
*(uint32_t*)(lum_plane+lum_pos1) = get_m128_32_1(pack_val); \
|
||||
} while (false)
|
||||
#define pack_shift(lum_plane, lum_pos0, lum_pos1, line1, line2, mask, sh) \
|
||||
do { \
|
||||
__m128i pack_val = _mm_packs_epi32( \
|
||||
_mm_srli_si128(_mm_and_si128(line1, mask), sh), \
|
||||
_mm_srli_si128(_mm_and_si128(line2, mask), sh)); \
|
||||
pack_val = _mm_packus_epi16(pack_val, pack_val); \
|
||||
\
|
||||
*(uint32_t *)(lum_plane + lum_pos0) = get_m128_32_0(pack_val); \
|
||||
*(uint32_t *)(lum_plane + lum_pos1) = get_m128_32_1(pack_val); \
|
||||
} while (false)
|
||||
|
||||
#define pack_val(lum_plane, lum_pos0, lum_pos1, line1, line2, mask) \
|
||||
do { \
|
||||
__m128i pack_val = _mm_packs_epi32( \
|
||||
_mm_and_si128(line1, mask), \
|
||||
_mm_and_si128(line2, mask)); \
|
||||
pack_val = _mm_packus_epi16(pack_val, pack_val); \
|
||||
\
|
||||
*(uint32_t*)(lum_plane+lum_pos0) = get_m128_32_0(pack_val); \
|
||||
*(uint32_t*)(lum_plane+lum_pos1) = get_m128_32_1(pack_val); \
|
||||
} while (false)
|
||||
#define pack_val(lum_plane, lum_pos0, lum_pos1, line1, line2, mask) \
|
||||
do { \
|
||||
__m128i pack_val = \
|
||||
_mm_packs_epi32(_mm_and_si128(line1, mask), \
|
||||
_mm_and_si128(line2, mask)); \
|
||||
pack_val = _mm_packus_epi16(pack_val, pack_val); \
|
||||
\
|
||||
*(uint32_t *)(lum_plane + lum_pos0) = get_m128_32_0(pack_val); \
|
||||
*(uint32_t *)(lum_plane + lum_pos1) = get_m128_32_1(pack_val); \
|
||||
} while (false)
|
||||
|
||||
#define pack_ch_1plane(uv_plane, chroma_pos, line1, line2, uv_mask) \
|
||||
do { \
|
||||
__m128i add_val = _mm_add_epi64( \
|
||||
_mm_and_si128(line1, uv_mask), \
|
||||
_mm_and_si128(line2, uv_mask)); \
|
||||
__m128i avg_val = _mm_add_epi64( \
|
||||
add_val, \
|
||||
_mm_shuffle_epi32(add_val, _MM_SHUFFLE(2, 3, 0, 1))); \
|
||||
avg_val = _mm_srai_epi16(avg_val, 2); \
|
||||
avg_val = _mm_shuffle_epi32(avg_val, _MM_SHUFFLE(3, 1, 2, 0)); \
|
||||
avg_val = _mm_packus_epi16(avg_val, avg_val); \
|
||||
\
|
||||
*(uint32_t*)(uv_plane+chroma_pos) = get_m128_32_0(avg_val); \
|
||||
} while (false)
|
||||
|
||||
#define pack_ch_2plane(u_plane, v_plane, chroma_pos, line1, line2, uv_mask) \
|
||||
do { \
|
||||
uint32_t packed_vals; \
|
||||
\
|
||||
__m128i add_val = _mm_add_epi64( \
|
||||
_mm_and_si128(line1, uv_mask), \
|
||||
_mm_and_si128(line2, uv_mask)); \
|
||||
__m128i avg_val = _mm_add_epi64( \
|
||||
add_val, \
|
||||
_mm_shuffle_epi32(add_val, _MM_SHUFFLE(2, 3, 0, 1))); \
|
||||
avg_val = _mm_srai_epi16(avg_val, 2); \
|
||||
avg_val = _mm_shuffle_epi32(avg_val, _MM_SHUFFLE(3, 1, 2, 0)); \
|
||||
avg_val = _mm_shufflelo_epi16(avg_val, _MM_SHUFFLE(3, 1, 2, 0)); \
|
||||
avg_val = _mm_packus_epi16(avg_val, avg_val); \
|
||||
\
|
||||
packed_vals = get_m128_32_0(avg_val); \
|
||||
\
|
||||
*(uint16_t*)(u_plane+chroma_pos) = (uint16_t)(packed_vals); \
|
||||
*(uint16_t*)(v_plane+chroma_pos) = (uint16_t)(packed_vals>>16); \
|
||||
} while (false)
|
||||
#define pack_ch_1plane(uv_plane, chroma_pos, line1, line2, uv_mask) \
|
||||
do { \
|
||||
__m128i add_val = \
|
||||
_mm_add_epi64(_mm_and_si128(line1, uv_mask), \
|
||||
_mm_and_si128(line2, uv_mask)); \
|
||||
__m128i avg_val = _mm_add_epi64( \
|
||||
add_val, \
|
||||
_mm_shuffle_epi32(add_val, _MM_SHUFFLE(2, 3, 0, 1))); \
|
||||
avg_val = _mm_srai_epi16(avg_val, 2); \
|
||||
avg_val = _mm_shuffle_epi32(avg_val, _MM_SHUFFLE(3, 1, 2, 0)); \
|
||||
avg_val = _mm_packus_epi16(avg_val, avg_val); \
|
||||
\
|
||||
*(uint32_t *)(uv_plane + chroma_pos) = get_m128_32_0(avg_val); \
|
||||
} while (false)
|
||||
|
||||
#define pack_ch_2plane(u_plane, v_plane, chroma_pos, line1, line2, uv_mask) \
|
||||
do { \
|
||||
uint32_t packed_vals; \
|
||||
\
|
||||
__m128i add_val = \
|
||||
_mm_add_epi64(_mm_and_si128(line1, uv_mask), \
|
||||
_mm_and_si128(line2, uv_mask)); \
|
||||
__m128i avg_val = _mm_add_epi64( \
|
||||
add_val, \
|
||||
_mm_shuffle_epi32(add_val, _MM_SHUFFLE(2, 3, 0, 1))); \
|
||||
avg_val = _mm_srai_epi16(avg_val, 2); \
|
||||
avg_val = _mm_shuffle_epi32(avg_val, _MM_SHUFFLE(3, 1, 2, 0)); \
|
||||
avg_val = \
|
||||
_mm_shufflelo_epi16(avg_val, _MM_SHUFFLE(3, 1, 2, 0)); \
|
||||
avg_val = _mm_packus_epi16(avg_val, avg_val); \
|
||||
\
|
||||
packed_vals = get_m128_32_0(avg_val); \
|
||||
\
|
||||
*(uint16_t *)(u_plane + chroma_pos) = (uint16_t)(packed_vals); \
|
||||
*(uint16_t *)(v_plane + chroma_pos) = \
|
||||
(uint16_t)(packed_vals >> 16); \
|
||||
} while (false)
|
||||
|
||||
static FORCE_INLINE uint32_t min_uint32(uint32_t a, uint32_t b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
void compress_uyvx_to_i420(
|
||||
const uint8_t *input, uint32_t in_linesize,
|
||||
uint32_t start_y, uint32_t end_y,
|
||||
uint8_t *output[], const uint32_t out_linesize[])
|
||||
void compress_uyvx_to_i420(const uint8_t *input, uint32_t in_linesize,
|
||||
uint32_t start_y, uint32_t end_y, uint8_t *output[],
|
||||
const uint32_t out_linesize[])
|
||||
{
|
||||
uint8_t *lum_plane = output[0];
|
||||
uint8_t *u_plane = output[1];
|
||||
uint8_t *v_plane = output[2];
|
||||
uint32_t width = min_uint32(in_linesize, out_linesize[0]);
|
||||
uint8_t *lum_plane = output[0];
|
||||
uint8_t *u_plane = output[1];
|
||||
uint8_t *v_plane = output[2];
|
||||
uint32_t width = min_uint32(in_linesize, out_linesize[0]);
|
||||
uint32_t y;
|
||||
|
||||
__m128i lum_mask = _mm_set1_epi32(0x0000FF00);
|
||||
__m128i uv_mask = _mm_set1_epi16(0x00FF);
|
||||
__m128i uv_mask = _mm_set1_epi16(0x00FF);
|
||||
|
||||
for (y = start_y; y < end_y; y += 2) {
|
||||
uint32_t y_pos = y * in_linesize;
|
||||
uint32_t chroma_y_pos = (y>>1) * out_linesize[1];
|
||||
uint32_t lum_y_pos = y * out_linesize[0];
|
||||
uint32_t y_pos = y * in_linesize;
|
||||
uint32_t chroma_y_pos = (y >> 1) * out_linesize[1];
|
||||
uint32_t lum_y_pos = y * out_linesize[0];
|
||||
uint32_t x;
|
||||
|
||||
for (x = 0; x < width; x += 4) {
|
||||
const uint8_t *img = input + y_pos + x*4;
|
||||
uint32_t lum_pos0 = lum_y_pos + x;
|
||||
uint32_t lum_pos1 = lum_pos0 + out_linesize[0];
|
||||
const uint8_t *img = input + y_pos + x * 4;
|
||||
uint32_t lum_pos0 = lum_y_pos + x;
|
||||
uint32_t lum_pos1 = lum_pos0 + out_linesize[0];
|
||||
|
||||
__m128i line1 = _mm_load_si128((const __m128i*)img);
|
||||
__m128i line1 = _mm_load_si128((const __m128i *)img);
|
||||
__m128i line2 = _mm_load_si128(
|
||||
(const __m128i*)(img + in_linesize));
|
||||
(const __m128i *)(img + in_linesize));
|
||||
|
||||
pack_shift(lum_plane, lum_pos0, lum_pos1,
|
||||
line1, line2, lum_mask, 1);
|
||||
pack_shift(lum_plane, lum_pos0, lum_pos1, line1, line2,
|
||||
lum_mask, 1);
|
||||
pack_ch_2plane(u_plane, v_plane,
|
||||
chroma_y_pos + (x>>1),
|
||||
line1, line2, uv_mask);
|
||||
chroma_y_pos + (x >> 1), line1, line2,
|
||||
uv_mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void compress_uyvx_to_nv12(
|
||||
const uint8_t *input, uint32_t in_linesize,
|
||||
uint32_t start_y, uint32_t end_y,
|
||||
uint8_t *output[], const uint32_t out_linesize[])
|
||||
void compress_uyvx_to_nv12(const uint8_t *input, uint32_t in_linesize,
|
||||
uint32_t start_y, uint32_t end_y, uint8_t *output[],
|
||||
const uint32_t out_linesize[])
|
||||
{
|
||||
uint8_t *lum_plane = output[0];
|
||||
uint8_t *lum_plane = output[0];
|
||||
uint8_t *chroma_plane = output[1];
|
||||
uint32_t width = min_uint32(in_linesize, out_linesize[0]);
|
||||
uint32_t width = min_uint32(in_linesize, out_linesize[0]);
|
||||
uint32_t y;
|
||||
|
||||
__m128i lum_mask = _mm_set1_epi32(0x0000FF00);
|
||||
__m128i uv_mask = _mm_set1_epi16(0x00FF);
|
||||
__m128i uv_mask = _mm_set1_epi16(0x00FF);
|
||||
|
||||
for (y = start_y; y < end_y; y += 2) {
|
||||
uint32_t y_pos = y * in_linesize;
|
||||
uint32_t chroma_y_pos = (y>>1) * out_linesize[1];
|
||||
uint32_t lum_y_pos = y * out_linesize[0];
|
||||
uint32_t y_pos = y * in_linesize;
|
||||
uint32_t chroma_y_pos = (y >> 1) * out_linesize[1];
|
||||
uint32_t lum_y_pos = y * out_linesize[0];
|
||||
uint32_t x;
|
||||
|
||||
for (x = 0; x < width; x += 4) {
|
||||
const uint8_t *img = input + y_pos + x*4;
|
||||
uint32_t lum_pos0 = lum_y_pos + x;
|
||||
uint32_t lum_pos1 = lum_pos0 + out_linesize[0];
|
||||
const uint8_t *img = input + y_pos + x * 4;
|
||||
uint32_t lum_pos0 = lum_y_pos + x;
|
||||
uint32_t lum_pos1 = lum_pos0 + out_linesize[0];
|
||||
|
||||
__m128i line1 = _mm_load_si128((const __m128i*)img);
|
||||
__m128i line1 = _mm_load_si128((const __m128i *)img);
|
||||
__m128i line2 = _mm_load_si128(
|
||||
(const __m128i*)(img + in_linesize));
|
||||
(const __m128i *)(img + in_linesize));
|
||||
|
||||
pack_shift(lum_plane, lum_pos0, lum_pos1,
|
||||
line1, line2, lum_mask, 1);
|
||||
pack_ch_1plane(chroma_plane, chroma_y_pos + x,
|
||||
line1, line2, uv_mask);
|
||||
pack_shift(lum_plane, lum_pos0, lum_pos1, line1, line2,
|
||||
lum_mask, 1);
|
||||
pack_ch_1plane(chroma_plane, chroma_y_pos + x, line1,
|
||||
line2, uv_mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void convert_uyvx_to_i444(
|
||||
const uint8_t *input, uint32_t in_linesize,
|
||||
uint32_t start_y, uint32_t end_y,
|
||||
uint8_t *output[], const uint32_t out_linesize[])
|
||||
void convert_uyvx_to_i444(const uint8_t *input, uint32_t in_linesize,
|
||||
uint32_t start_y, uint32_t end_y, uint8_t *output[],
|
||||
const uint32_t out_linesize[])
|
||||
{
|
||||
uint8_t *lum_plane = output[0];
|
||||
uint8_t *u_plane = output[1];
|
||||
uint8_t *v_plane = output[2];
|
||||
uint32_t width = min_uint32(in_linesize, out_linesize[0]);
|
||||
uint8_t *lum_plane = output[0];
|
||||
uint8_t *u_plane = output[1];
|
||||
uint8_t *v_plane = output[2];
|
||||
uint32_t width = min_uint32(in_linesize, out_linesize[0]);
|
||||
uint32_t y;
|
||||
|
||||
__m128i lum_mask = _mm_set1_epi32(0x0000FF00);
|
||||
__m128i u_mask = _mm_set1_epi32(0x000000FF);
|
||||
__m128i v_mask = _mm_set1_epi32(0x00FF0000);
|
||||
__m128i u_mask = _mm_set1_epi32(0x000000FF);
|
||||
__m128i v_mask = _mm_set1_epi32(0x00FF0000);
|
||||
|
||||
for (y = start_y; y < end_y; y += 2) {
|
||||
uint32_t y_pos = y * in_linesize;
|
||||
uint32_t lum_y_pos = y * out_linesize[0];
|
||||
uint32_t y_pos = y * in_linesize;
|
||||
uint32_t lum_y_pos = y * out_linesize[0];
|
||||
uint32_t x;
|
||||
|
||||
for (x = 0; x < width; x += 4) {
|
||||
const uint8_t *img = input + y_pos + x*4;
|
||||
uint32_t lum_pos0 = lum_y_pos + x;
|
||||
uint32_t lum_pos1 = lum_pos0 + out_linesize[0];
|
||||
const uint8_t *img = input + y_pos + x * 4;
|
||||
uint32_t lum_pos0 = lum_y_pos + x;
|
||||
uint32_t lum_pos1 = lum_pos0 + out_linesize[0];
|
||||
|
||||
__m128i line1 = _mm_load_si128((const __m128i*)img);
|
||||
__m128i line1 = _mm_load_si128((const __m128i *)img);
|
||||
__m128i line2 = _mm_load_si128(
|
||||
(const __m128i*)(img + in_linesize));
|
||||
(const __m128i *)(img + in_linesize));
|
||||
|
||||
pack_shift(lum_plane, lum_pos0, lum_pos1,
|
||||
line1, line2, lum_mask, 1);
|
||||
pack_val(u_plane, lum_pos0, lum_pos1,
|
||||
line1, line2, u_mask);
|
||||
pack_shift(v_plane, lum_pos0, lum_pos1,
|
||||
line1, line2, v_mask, 2);
|
||||
pack_shift(lum_plane, lum_pos0, lum_pos1, line1, line2,
|
||||
lum_mask, 1);
|
||||
pack_val(u_plane, lum_pos0, lum_pos1, line1, line2,
|
||||
u_mask);
|
||||
pack_shift(v_plane, lum_pos0, lum_pos1, line1, line2,
|
||||
v_mask, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void decompress_420(
|
||||
const uint8_t *const input[], const uint32_t in_linesize[],
|
||||
uint32_t start_y, uint32_t end_y,
|
||||
uint8_t *output, uint32_t out_linesize)
|
||||
void decompress_420(const uint8_t *const input[], const uint32_t in_linesize[],
|
||||
uint32_t start_y, uint32_t end_y, uint8_t *output,
|
||||
uint32_t out_linesize)
|
||||
{
|
||||
uint32_t start_y_d2 = start_y/2;
|
||||
uint32_t width_d2 = in_linesize[0]/2;
|
||||
uint32_t height_d2 = end_y/2;
|
||||
uint32_t start_y_d2 = start_y / 2;
|
||||
uint32_t width_d2 = in_linesize[0] / 2;
|
||||
uint32_t height_d2 = end_y / 2;
|
||||
uint32_t y;
|
||||
|
||||
for (y = start_y_d2; y < height_d2; y++) {
|
||||
|
|
@ -221,8 +218,8 @@ void decompress_420(
|
|||
|
||||
lum0 = input[0] + y * 2 * in_linesize[0];
|
||||
lum1 = lum0 + in_linesize[0];
|
||||
output0 = (uint32_t*)(output + y * 2 * out_linesize);
|
||||
output1 = (uint32_t*)((uint8_t*)output0 + out_linesize);
|
||||
output0 = (uint32_t *)(output + y * 2 * out_linesize);
|
||||
output1 = (uint32_t *)((uint8_t *)output0 + out_linesize);
|
||||
|
||||
for (x = 0; x < width_d2; x++) {
|
||||
uint32_t out;
|
||||
|
|
@ -237,14 +234,13 @@ void decompress_420(
|
|||
}
|
||||
}
|
||||
|
||||
void decompress_nv12(
|
||||
const uint8_t *const input[], const uint32_t in_linesize[],
|
||||
uint32_t start_y, uint32_t end_y,
|
||||
uint8_t *output, uint32_t out_linesize)
|
||||
void decompress_nv12(const uint8_t *const input[], const uint32_t in_linesize[],
|
||||
uint32_t start_y, uint32_t end_y, uint8_t *output,
|
||||
uint32_t out_linesize)
|
||||
{
|
||||
uint32_t start_y_d2 = start_y/2;
|
||||
uint32_t width_d2 = min_uint32(in_linesize[0], out_linesize)/2;
|
||||
uint32_t height_d2 = end_y/2;
|
||||
uint32_t start_y_d2 = start_y / 2;
|
||||
uint32_t width_d2 = min_uint32(in_linesize[0], out_linesize) / 2;
|
||||
uint32_t height_d2 = end_y / 2;
|
||||
uint32_t y;
|
||||
|
||||
for (y = start_y_d2; y < height_d2; y++) {
|
||||
|
|
@ -253,11 +249,11 @@ void decompress_nv12(
|
|||
register uint32_t *output0, *output1;
|
||||
uint32_t x;
|
||||
|
||||
chroma = (const uint16_t*)(input[1] + y * in_linesize[1]);
|
||||
chroma = (const uint16_t *)(input[1] + y * in_linesize[1]);
|
||||
lum0 = input[0] + y * 2 * in_linesize[0];
|
||||
lum1 = lum0 + in_linesize[0];
|
||||
output0 = (uint32_t*)(output + y * 2 * out_linesize);
|
||||
output1 = (uint32_t*)((uint8_t*)output0 + out_linesize);
|
||||
output0 = (uint32_t *)(output + y * 2 * out_linesize);
|
||||
output1 = (uint32_t *)((uint8_t *)output0 + out_linesize);
|
||||
|
||||
for (x = 0; x < width_d2; x++) {
|
||||
uint32_t out = *(chroma++) << 8;
|
||||
|
|
@ -271,31 +267,29 @@ void decompress_nv12(
|
|||
}
|
||||
}
|
||||
|
||||
void decompress_422(
|
||||
const uint8_t *input, uint32_t in_linesize,
|
||||
uint32_t start_y, uint32_t end_y,
|
||||
uint8_t *output, uint32_t out_linesize,
|
||||
bool leading_lum)
|
||||
void decompress_422(const uint8_t *input, uint32_t in_linesize,
|
||||
uint32_t start_y, uint32_t end_y, uint8_t *output,
|
||||
uint32_t out_linesize, bool leading_lum)
|
||||
{
|
||||
uint32_t width_d2 = min_uint32(in_linesize, out_linesize)/2;
|
||||
uint32_t width_d2 = min_uint32(in_linesize, out_linesize) / 2;
|
||||
uint32_t y;
|
||||
|
||||
register const uint32_t *input32;
|
||||
register const uint32_t *input32_end;
|
||||
register uint32_t *output32;
|
||||
register uint32_t *output32;
|
||||
|
||||
if (leading_lum) {
|
||||
for (y = start_y; y < end_y; y++) {
|
||||
input32 = (const uint32_t*)(input + y*in_linesize);
|
||||
input32 = (const uint32_t *)(input + y * in_linesize);
|
||||
input32_end = input32 + width_d2;
|
||||
output32 = (uint32_t*)(output + y*out_linesize);
|
||||
output32 = (uint32_t *)(output + y * out_linesize);
|
||||
|
||||
while(input32 < input32_end) {
|
||||
while (input32 < input32_end) {
|
||||
register uint32_t dw = *input32;
|
||||
|
||||
output32[0] = dw;
|
||||
dw &= 0xFFFFFF00;
|
||||
dw |= (uint8_t)(dw>>16);
|
||||
dw |= (uint8_t)(dw >> 16);
|
||||
output32[1] = dw;
|
||||
|
||||
output32 += 2;
|
||||
|
|
@ -304,16 +298,16 @@ void decompress_422(
|
|||
}
|
||||
} else {
|
||||
for (y = start_y; y < end_y; y++) {
|
||||
input32 = (const uint32_t*)(input + y*in_linesize);
|
||||
input32 = (const uint32_t *)(input + y * in_linesize);
|
||||
input32_end = input32 + width_d2;
|
||||
output32 = (uint32_t*)(output + y*out_linesize);
|
||||
output32 = (uint32_t *)(output + y * out_linesize);
|
||||
|
||||
while (input32 < input32_end) {
|
||||
register uint32_t dw = *input32;
|
||||
|
||||
output32[0] = dw;
|
||||
dw &= 0xFFFF00FF;
|
||||
dw |= (dw>>16) & 0xFF00;
|
||||
dw |= (dw >> 16) & 0xFF00;
|
||||
output32[1] = dw;
|
||||
|
||||
output32 += 2;
|
||||
|
|
|
|||
|
|
@ -27,36 +27,34 @@ extern "C" {
|
|||
* Functions for converting to and from packed 444 YUV
|
||||
*/
|
||||
|
||||
EXPORT void compress_uyvx_to_i420(
|
||||
const uint8_t *input, uint32_t in_linesize,
|
||||
uint32_t start_y, uint32_t end_y,
|
||||
uint8_t *output[], const uint32_t out_linesize[]);
|
||||
EXPORT void compress_uyvx_to_i420(const uint8_t *input, uint32_t in_linesize,
|
||||
uint32_t start_y, uint32_t end_y,
|
||||
uint8_t *output[],
|
||||
const uint32_t out_linesize[]);
|
||||
|
||||
EXPORT void compress_uyvx_to_nv12(
|
||||
const uint8_t *input, uint32_t in_linesize,
|
||||
uint32_t start_y, uint32_t end_y,
|
||||
uint8_t *output[], const uint32_t out_linesize[]);
|
||||
EXPORT void compress_uyvx_to_nv12(const uint8_t *input, uint32_t in_linesize,
|
||||
uint32_t start_y, uint32_t end_y,
|
||||
uint8_t *output[],
|
||||
const uint32_t out_linesize[]);
|
||||
|
||||
EXPORT void convert_uyvx_to_i444(
|
||||
const uint8_t *input, uint32_t in_linesize,
|
||||
uint32_t start_y, uint32_t end_y,
|
||||
uint8_t *output[], const uint32_t out_linesize[]);
|
||||
EXPORT void convert_uyvx_to_i444(const uint8_t *input, uint32_t in_linesize,
|
||||
uint32_t start_y, uint32_t end_y,
|
||||
uint8_t *output[],
|
||||
const uint32_t out_linesize[]);
|
||||
|
||||
EXPORT void decompress_nv12(
|
||||
const uint8_t *const input[], const uint32_t in_linesize[],
|
||||
uint32_t start_y, uint32_t end_y,
|
||||
uint8_t *output, uint32_t out_linesize);
|
||||
EXPORT void decompress_nv12(const uint8_t *const input[],
|
||||
const uint32_t in_linesize[], uint32_t start_y,
|
||||
uint32_t end_y, uint8_t *output,
|
||||
uint32_t out_linesize);
|
||||
|
||||
EXPORT void decompress_420(
|
||||
const uint8_t *const input[], const uint32_t in_linesize[],
|
||||
uint32_t start_y, uint32_t end_y,
|
||||
uint8_t *output, uint32_t out_linesize);
|
||||
EXPORT void decompress_420(const uint8_t *const input[],
|
||||
const uint32_t in_linesize[], uint32_t start_y,
|
||||
uint32_t end_y, uint8_t *output,
|
||||
uint32_t out_linesize);
|
||||
|
||||
EXPORT void decompress_422(
|
||||
const uint8_t *input, uint32_t in_linesize,
|
||||
uint32_t start_y, uint32_t end_y,
|
||||
uint8_t *output, uint32_t out_linesize,
|
||||
bool leading_lum);
|
||||
EXPORT void decompress_422(const uint8_t *input, uint32_t in_linesize,
|
||||
uint32_t start_y, uint32_t end_y, uint8_t *output,
|
||||
uint32_t out_linesize, bool leading_lum);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,20 +9,20 @@ struct media_frames_per_second {
|
|||
uint32_t denominator;
|
||||
};
|
||||
|
||||
static inline double media_frames_per_second_to_frame_interval(
|
||||
struct media_frames_per_second fps)
|
||||
static inline double
|
||||
media_frames_per_second_to_frame_interval(struct media_frames_per_second fps)
|
||||
{
|
||||
return (double)fps.denominator / fps.numerator;
|
||||
}
|
||||
|
||||
static inline double media_frames_per_second_to_fps(
|
||||
struct media_frames_per_second fps)
|
||||
static inline double
|
||||
media_frames_per_second_to_fps(struct media_frames_per_second fps)
|
||||
{
|
||||
return (double)fps.numerator / fps.denominator;
|
||||
}
|
||||
|
||||
static inline bool media_frames_per_second_is_valid(
|
||||
struct media_frames_per_second fps)
|
||||
static inline bool
|
||||
media_frames_per_second_is_valid(struct media_frames_per_second fps)
|
||||
{
|
||||
return fps.numerator && fps.denominator;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ static inline bool init_input(media_remux_job_t job, const char *in_filename)
|
|||
int ret = avformat_open_input(&job->ifmt_ctx, in_filename, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
blog(LOG_ERROR, "media_remux: Could not open input file '%s'",
|
||||
in_filename);
|
||||
in_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -76,16 +76,16 @@ static inline bool init_output(media_remux_job_t job, const char *out_filename)
|
|||
int ret;
|
||||
|
||||
avformat_alloc_output_context2(&job->ofmt_ctx, NULL, NULL,
|
||||
out_filename);
|
||||
out_filename);
|
||||
if (!job->ofmt_ctx) {
|
||||
blog(LOG_ERROR, "media_remux: Could not create output context");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < job->ifmt_ctx->nb_streams; i++) {
|
||||
AVStream *in_stream = job->ifmt_ctx->streams[i];
|
||||
AVStream *out_stream = avformat_new_stream(job->ofmt_ctx,
|
||||
in_stream->codec->codec);
|
||||
AVStream *in_stream = job->ifmt_ctx->streams[i];
|
||||
AVStream *out_stream = avformat_new_stream(
|
||||
job->ofmt_ctx, in_stream->codec->codec);
|
||||
if (!out_stream) {
|
||||
blog(LOG_ERROR, "media_remux: Failed to allocate output"
|
||||
" stream");
|
||||
|
|
@ -97,7 +97,7 @@ static inline bool init_output(media_remux_job_t job, const char *out_filename)
|
|||
ret = avcodec_parameters_from_context(par, in_stream->codec);
|
||||
if (ret == 0)
|
||||
ret = avcodec_parameters_to_context(out_stream->codec,
|
||||
par);
|
||||
par);
|
||||
avcodec_parameters_free(&par);
|
||||
#else
|
||||
ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
|
||||
|
|
@ -124,8 +124,10 @@ static inline bool init_output(media_remux_job_t job, const char *out_filename)
|
|||
ret = avio_open(&job->ofmt_ctx->pb, out_filename,
|
||||
AVIO_FLAG_WRITE);
|
||||
if (ret < 0) {
|
||||
blog(LOG_ERROR, "media_remux: Failed to open output"
|
||||
" file '%s'", out_filename);
|
||||
blog(LOG_ERROR,
|
||||
"media_remux: Failed to open output"
|
||||
" file '%s'",
|
||||
out_filename);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -134,7 +136,7 @@ static inline bool init_output(media_remux_job_t job, const char *out_filename)
|
|||
}
|
||||
|
||||
bool media_remux_job_create(media_remux_job_t *job, const char *in_filename,
|
||||
const char *out_filename)
|
||||
const char *out_filename)
|
||||
{
|
||||
if (!job)
|
||||
return false;
|
||||
|
|
@ -152,7 +154,9 @@ bool media_remux_job_create(media_remux_job_t *job, const char *in_filename,
|
|||
|
||||
init_size(*job, in_filename);
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
|
||||
av_register_all();
|
||||
#endif
|
||||
|
||||
if (!init_input(*job, in_filename))
|
||||
goto fail;
|
||||
|
|
@ -167,23 +171,23 @@ fail:
|
|||
return false;
|
||||
}
|
||||
|
||||
static inline void process_packet(AVPacket *pkt,
|
||||
AVStream *in_stream, AVStream *out_stream)
|
||||
static inline void process_packet(AVPacket *pkt, AVStream *in_stream,
|
||||
AVStream *out_stream)
|
||||
{
|
||||
pkt->pts = av_rescale_q_rnd(pkt->pts, in_stream->time_base,
|
||||
out_stream->time_base,
|
||||
AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
|
||||
out_stream->time_base,
|
||||
AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
|
||||
pkt->dts = av_rescale_q_rnd(pkt->dts, in_stream->time_base,
|
||||
out_stream->time_base,
|
||||
AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
|
||||
pkt->duration = (int)av_rescale_q(pkt->duration,
|
||||
in_stream->time_base, out_stream->time_base);
|
||||
out_stream->time_base,
|
||||
AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
|
||||
pkt->duration = (int)av_rescale_q(pkt->duration, in_stream->time_base,
|
||||
out_stream->time_base);
|
||||
pkt->pos = -1;
|
||||
|
||||
}
|
||||
|
||||
static inline int process_packets(media_remux_job_t job,
|
||||
media_remux_progress_callback callback, void *data)
|
||||
media_remux_progress_callback callback,
|
||||
void *data)
|
||||
{
|
||||
AVPacket pkt;
|
||||
|
||||
|
|
@ -192,9 +196,10 @@ static inline int process_packets(media_remux_job_t job,
|
|||
ret = av_read_frame(job->ifmt_ctx, &pkt);
|
||||
if (ret < 0) {
|
||||
if (ret != AVERROR_EOF)
|
||||
blog(LOG_ERROR, "media_remux: Error reading"
|
||||
" packet: %s",
|
||||
av_err2str(ret));
|
||||
blog(LOG_ERROR,
|
||||
"media_remux: Error reading"
|
||||
" packet: %s",
|
||||
av_err2str(ret));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -206,14 +211,14 @@ static inline int process_packets(media_remux_job_t job,
|
|||
}
|
||||
|
||||
process_packet(&pkt, job->ifmt_ctx->streams[pkt.stream_index],
|
||||
job->ofmt_ctx->streams[pkt.stream_index]);
|
||||
job->ofmt_ctx->streams[pkt.stream_index]);
|
||||
|
||||
ret = av_interleaved_write_frame(job->ofmt_ctx, &pkt);
|
||||
av_packet_unref(&pkt);
|
||||
|
||||
if (ret < 0) {
|
||||
blog(LOG_ERROR, "media_remux: Error muxing packet: %s",
|
||||
av_err2str(ret));
|
||||
av_err2str(ret));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -222,7 +227,7 @@ static inline int process_packets(media_remux_job_t job,
|
|||
}
|
||||
|
||||
bool media_remux_job_process(media_remux_job_t job,
|
||||
media_remux_progress_callback callback, void *data)
|
||||
media_remux_progress_callback callback, void *data)
|
||||
{
|
||||
int ret;
|
||||
bool success = false;
|
||||
|
|
@ -233,7 +238,7 @@ bool media_remux_job_process(media_remux_job_t job,
|
|||
ret = avformat_write_header(job->ofmt_ctx, NULL);
|
||||
if (ret < 0) {
|
||||
blog(LOG_ERROR, "media_remux: Error opening output file: %s",
|
||||
av_err2str(ret));
|
||||
av_err2str(ret));
|
||||
return success;
|
||||
}
|
||||
|
||||
|
|
@ -246,7 +251,7 @@ bool media_remux_job_process(media_remux_job_t job,
|
|||
ret = av_write_trailer(job->ofmt_ctx);
|
||||
if (ret < 0) {
|
||||
blog(LOG_ERROR, "media_remux: av_write_trailer: %s",
|
||||
av_err2str(ret));
|
||||
av_err2str(ret));
|
||||
success = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,16 +22,18 @@
|
|||
struct media_remux_job;
|
||||
typedef struct media_remux_job *media_remux_job_t;
|
||||
|
||||
typedef bool (media_remux_progress_callback)(void *data, float percent);
|
||||
typedef bool(media_remux_progress_callback)(void *data, float percent);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
EXPORT bool media_remux_job_create(media_remux_job_t *job,
|
||||
const char *in_filename, const char *out_filename);
|
||||
const char *in_filename,
|
||||
const char *out_filename);
|
||||
EXPORT bool media_remux_job_process(media_remux_job_t job,
|
||||
media_remux_progress_callback callback, void *data);
|
||||
media_remux_progress_callback callback,
|
||||
void *data);
|
||||
EXPORT void media_remux_job_destroy(media_remux_job_t job);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -24,31 +24,29 @@
|
|||
enum video_format video_format_from_fourcc(uint32_t fourcc)
|
||||
{
|
||||
switch (fourcc) {
|
||||
case MAKE_FOURCC('U','Y','V','Y'):
|
||||
case MAKE_FOURCC('H','D','Y','C'):
|
||||
case MAKE_FOURCC('U','Y','N','V'):
|
||||
case MAKE_FOURCC('U','Y','N','Y'):
|
||||
case MAKE_FOURCC('u','y','v','1'):
|
||||
case MAKE_FOURCC('2','v','u','y'):
|
||||
case MAKE_FOURCC('2','V','u','y'):
|
||||
return VIDEO_FORMAT_UYVY;
|
||||
case MAKE_FOURCC('U', 'Y', 'V', 'Y'):
|
||||
case MAKE_FOURCC('H', 'D', 'Y', 'C'):
|
||||
case MAKE_FOURCC('U', 'Y', 'N', 'V'):
|
||||
case MAKE_FOURCC('U', 'Y', 'N', 'Y'):
|
||||
case MAKE_FOURCC('u', 'y', 'v', '1'):
|
||||
case MAKE_FOURCC('2', 'v', 'u', 'y'):
|
||||
case MAKE_FOURCC('2', 'V', 'u', 'y'):
|
||||
return VIDEO_FORMAT_UYVY;
|
||||
|
||||
case MAKE_FOURCC('Y','U','Y','2'):
|
||||
case MAKE_FOURCC('Y','4','2','2'):
|
||||
case MAKE_FOURCC('V','4','2','2'):
|
||||
case MAKE_FOURCC('V','Y','U','Y'):
|
||||
case MAKE_FOURCC('Y','U','N','V'):
|
||||
case MAKE_FOURCC('y','u','v','2'):
|
||||
case MAKE_FOURCC('y','u','v','s'):
|
||||
return VIDEO_FORMAT_YUY2;
|
||||
case MAKE_FOURCC('Y', 'U', 'Y', '2'):
|
||||
case MAKE_FOURCC('Y', '4', '2', '2'):
|
||||
case MAKE_FOURCC('V', '4', '2', '2'):
|
||||
case MAKE_FOURCC('V', 'Y', 'U', 'Y'):
|
||||
case MAKE_FOURCC('Y', 'U', 'N', 'V'):
|
||||
case MAKE_FOURCC('y', 'u', 'v', '2'):
|
||||
case MAKE_FOURCC('y', 'u', 'v', 's'):
|
||||
return VIDEO_FORMAT_YUY2;
|
||||
|
||||
case MAKE_FOURCC('Y','V','Y','U'):
|
||||
return VIDEO_FORMAT_YVYU;
|
||||
case MAKE_FOURCC('Y', 'V', 'Y', 'U'):
|
||||
return VIDEO_FORMAT_YVYU;
|
||||
|
||||
case MAKE_FOURCC('Y','8','0','0'):
|
||||
return VIDEO_FORMAT_Y800;
|
||||
|
||||
case MAKE_FOURCC('Y', '8', '0', '0'):
|
||||
return VIDEO_FORMAT_Y800;
|
||||
}
|
||||
return VIDEO_FORMAT_NONE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,18 +17,18 @@
|
|||
|
||||
#include "video-frame.h"
|
||||
|
||||
#define ALIGN_SIZE(size, align) \
|
||||
size = (((size)+(align-1)) & (~(align-1)))
|
||||
#define ALIGN_SIZE(size, align) size = (((size) + (align - 1)) & (~(align - 1)))
|
||||
|
||||
/* messy code alarm */
|
||||
void video_frame_init(struct video_frame *frame, enum video_format format,
|
||||
uint32_t width, uint32_t height)
|
||||
uint32_t width, uint32_t height)
|
||||
{
|
||||
size_t size;
|
||||
size_t offsets[MAX_AV_PLANES];
|
||||
int alignment = base_get_alignment();
|
||||
int alignment = base_get_alignment();
|
||||
|
||||
if (!frame) return;
|
||||
if (!frame)
|
||||
return;
|
||||
|
||||
memset(frame, 0, sizeof(struct video_frame));
|
||||
memset(offsets, 0, sizeof(offsets));
|
||||
|
|
@ -41,27 +41,27 @@ void video_frame_init(struct video_frame *frame, enum video_format format,
|
|||
size = width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[0] = size;
|
||||
size += (width/2) * (height/2);
|
||||
size += (width / 2) * (height / 2);
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[1] = size;
|
||||
size += (width/2) * (height/2);
|
||||
size += (width / 2) * (height / 2);
|
||||
ALIGN_SIZE(size, alignment);
|
||||
frame->data[0] = bmalloc(size);
|
||||
frame->data[1] = (uint8_t*)frame->data[0] + offsets[0];
|
||||
frame->data[2] = (uint8_t*)frame->data[0] + offsets[1];
|
||||
frame->data[1] = (uint8_t *)frame->data[0] + offsets[0];
|
||||
frame->data[2] = (uint8_t *)frame->data[0] + offsets[1];
|
||||
frame->linesize[0] = width;
|
||||
frame->linesize[1] = width/2;
|
||||
frame->linesize[2] = width/2;
|
||||
frame->linesize[1] = width / 2;
|
||||
frame->linesize[2] = width / 2;
|
||||
break;
|
||||
|
||||
case VIDEO_FORMAT_NV12:
|
||||
size = width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[0] = size;
|
||||
size += (width/2) * (height/2) * 2;
|
||||
size += (width / 2) * (height / 2) * 2;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
frame->data[0] = bmalloc(size);
|
||||
frame->data[1] = (uint8_t*)frame->data[0] + offsets[0];
|
||||
frame->data[1] = (uint8_t *)frame->data[0] + offsets[0];
|
||||
frame->linesize[0] = width;
|
||||
frame->linesize[1] = width;
|
||||
break;
|
||||
|
|
@ -79,33 +79,124 @@ void video_frame_init(struct video_frame *frame, enum video_format format,
|
|||
size = width * height * 2;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
frame->data[0] = bmalloc(size);
|
||||
frame->linesize[0] = width*2;
|
||||
frame->linesize[0] = width * 2;
|
||||
break;
|
||||
|
||||
case VIDEO_FORMAT_RGBA:
|
||||
case VIDEO_FORMAT_BGRA:
|
||||
case VIDEO_FORMAT_BGRX:
|
||||
case VIDEO_FORMAT_AYUV:
|
||||
size = width * height * 4;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
frame->data[0] = bmalloc(size);
|
||||
frame->linesize[0] = width*4;
|
||||
frame->linesize[0] = width * 4;
|
||||
break;
|
||||
|
||||
case VIDEO_FORMAT_I444:
|
||||
size = width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
frame->data[0] = bmalloc(size * 3);
|
||||
frame->data[1] = (uint8_t*)frame->data[0] + size;
|
||||
frame->data[2] = (uint8_t*)frame->data[1] + size;
|
||||
frame->data[1] = (uint8_t *)frame->data[0] + size;
|
||||
frame->data[2] = (uint8_t *)frame->data[1] + size;
|
||||
frame->linesize[0] = width;
|
||||
frame->linesize[1] = width;
|
||||
frame->linesize[2] = width;
|
||||
break;
|
||||
|
||||
case VIDEO_FORMAT_BGR3:
|
||||
size = width * height * 3;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
frame->data[0] = bmalloc(size);
|
||||
frame->linesize[0] = width * 3;
|
||||
break;
|
||||
|
||||
case VIDEO_FORMAT_I422:
|
||||
size = width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[0] = size;
|
||||
size += (width / 2) * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[1] = size;
|
||||
size += (width / 2) * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
frame->data[0] = bmalloc(size);
|
||||
frame->data[1] = (uint8_t *)frame->data[0] + offsets[0];
|
||||
frame->data[2] = (uint8_t *)frame->data[0] + offsets[1];
|
||||
frame->linesize[0] = width;
|
||||
frame->linesize[1] = width / 2;
|
||||
frame->linesize[2] = width / 2;
|
||||
break;
|
||||
|
||||
case VIDEO_FORMAT_I40A:
|
||||
size = width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[0] = size;
|
||||
size += (width / 2) * (height / 2);
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[1] = size;
|
||||
size += (width / 2) * (height / 2);
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[2] = size;
|
||||
size += width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
frame->data[0] = bmalloc(size);
|
||||
frame->data[1] = (uint8_t *)frame->data[0] + offsets[0];
|
||||
frame->data[2] = (uint8_t *)frame->data[0] + offsets[1];
|
||||
frame->data[3] = (uint8_t *)frame->data[0] + offsets[2];
|
||||
frame->linesize[0] = width;
|
||||
frame->linesize[1] = width / 2;
|
||||
frame->linesize[2] = width / 2;
|
||||
frame->linesize[3] = width;
|
||||
break;
|
||||
|
||||
case VIDEO_FORMAT_I42A:
|
||||
size = width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[0] = size;
|
||||
size += (width / 2) * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[1] = size;
|
||||
size += (width / 2) * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[2] = size;
|
||||
size += width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
frame->data[0] = bmalloc(size);
|
||||
frame->data[1] = (uint8_t *)frame->data[0] + offsets[0];
|
||||
frame->data[2] = (uint8_t *)frame->data[0] + offsets[1];
|
||||
frame->data[3] = (uint8_t *)frame->data[0] + offsets[2];
|
||||
frame->linesize[0] = width;
|
||||
frame->linesize[1] = width / 2;
|
||||
frame->linesize[2] = width / 2;
|
||||
frame->linesize[3] = width;
|
||||
break;
|
||||
|
||||
case VIDEO_FORMAT_YUVA:
|
||||
size = width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[0] = size;
|
||||
size += width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[1] = size;
|
||||
size += width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[2] = size;
|
||||
size += width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
frame->data[0] = bmalloc(size);
|
||||
frame->data[1] = (uint8_t *)frame->data[0] + offsets[0];
|
||||
frame->data[2] = (uint8_t *)frame->data[0] + offsets[1];
|
||||
frame->data[3] = (uint8_t *)frame->data[0] + offsets[2];
|
||||
frame->linesize[0] = width;
|
||||
frame->linesize[1] = width;
|
||||
frame->linesize[2] = width;
|
||||
frame->linesize[3] = width;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void video_frame_copy(struct video_frame *dst, const struct video_frame *src,
|
||||
enum video_format format, uint32_t cy)
|
||||
enum video_format format, uint32_t cy)
|
||||
{
|
||||
switch (format) {
|
||||
case VIDEO_FORMAT_NONE:
|
||||
|
|
@ -129,13 +220,31 @@ void video_frame_copy(struct video_frame *dst, const struct video_frame *src,
|
|||
case VIDEO_FORMAT_RGBA:
|
||||
case VIDEO_FORMAT_BGRA:
|
||||
case VIDEO_FORMAT_BGRX:
|
||||
case VIDEO_FORMAT_BGR3:
|
||||
case VIDEO_FORMAT_AYUV:
|
||||
memcpy(dst->data[0], src->data[0], src->linesize[0] * cy);
|
||||
break;
|
||||
|
||||
case VIDEO_FORMAT_I444:
|
||||
case VIDEO_FORMAT_I422:
|
||||
memcpy(dst->data[0], src->data[0], src->linesize[0] * cy);
|
||||
memcpy(dst->data[1], src->data[1], src->linesize[1] * cy);
|
||||
memcpy(dst->data[2], src->data[2], src->linesize[2] * cy);
|
||||
break;
|
||||
|
||||
case VIDEO_FORMAT_I40A:
|
||||
memcpy(dst->data[0], src->data[0], src->linesize[0] * cy);
|
||||
memcpy(dst->data[1], src->data[1], src->linesize[1] * cy / 2);
|
||||
memcpy(dst->data[2], src->data[2], src->linesize[2] * cy / 2);
|
||||
memcpy(dst->data[3], src->data[3], src->linesize[3] * cy);
|
||||
break;
|
||||
|
||||
case VIDEO_FORMAT_I42A:
|
||||
case VIDEO_FORMAT_YUVA:
|
||||
memcpy(dst->data[0], src->data[0], src->linesize[0] * cy);
|
||||
memcpy(dst->data[1], src->data[1], src->linesize[1] * cy);
|
||||
memcpy(dst->data[2], src->data[2], src->linesize[2] * cy);
|
||||
memcpy(dst->data[3], src->data[3], src->linesize[3] * cy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,12 +21,13 @@
|
|||
#include "video-io.h"
|
||||
|
||||
struct video_frame {
|
||||
uint8_t *data[MAX_AV_PLANES];
|
||||
uint8_t *data[MAX_AV_PLANES];
|
||||
uint32_t linesize[MAX_AV_PLANES];
|
||||
};
|
||||
|
||||
EXPORT void video_frame_init(struct video_frame *frame,
|
||||
enum video_format format, uint32_t width, uint32_t height);
|
||||
enum video_format format, uint32_t width,
|
||||
uint32_t height);
|
||||
|
||||
static inline void video_frame_free(struct video_frame *frame)
|
||||
{
|
||||
|
|
@ -36,12 +37,12 @@ static inline void video_frame_free(struct video_frame *frame)
|
|||
}
|
||||
}
|
||||
|
||||
static inline struct video_frame *video_frame_create(
|
||||
enum video_format format, uint32_t width, uint32_t height)
|
||||
static inline struct video_frame *
|
||||
video_frame_create(enum video_format format, uint32_t width, uint32_t height)
|
||||
{
|
||||
struct video_frame *frame;
|
||||
|
||||
frame = (struct video_frame*)bzalloc(sizeof(struct video_frame));
|
||||
frame = (struct video_frame *)bzalloc(sizeof(struct video_frame));
|
||||
video_frame_init(frame, format, width, height);
|
||||
return frame;
|
||||
}
|
||||
|
|
@ -55,5 +56,5 @@ static inline void video_frame_destroy(struct video_frame *frame)
|
|||
}
|
||||
|
||||
EXPORT void video_frame_copy(struct video_frame *dst,
|
||||
const struct video_frame *src, enum video_format format,
|
||||
uint32_t height);
|
||||
const struct video_frame *src,
|
||||
enum video_format format, uint32_t height);
|
||||
|
|
|
|||
|
|
@ -40,10 +40,10 @@ struct cached_frame_info {
|
|||
};
|
||||
|
||||
struct video_input {
|
||||
struct video_scale_info conversion;
|
||||
video_scaler_t *scaler;
|
||||
struct video_frame frame[MAX_CONVERT_BUFFERS];
|
||||
int cur_frame;
|
||||
struct video_scale_info conversion;
|
||||
video_scaler_t *scaler;
|
||||
struct video_frame frame[MAX_CONVERT_BUFFERS];
|
||||
int cur_frame;
|
||||
|
||||
void (*callback)(void *param, struct video_data *frame);
|
||||
void *param;
|
||||
|
|
@ -57,35 +57,35 @@ static inline void video_input_free(struct video_input *input)
|
|||
}
|
||||
|
||||
struct video_output {
|
||||
struct video_output_info info;
|
||||
struct video_output_info info;
|
||||
|
||||
pthread_t thread;
|
||||
pthread_mutex_t data_mutex;
|
||||
bool stop;
|
||||
pthread_t thread;
|
||||
pthread_mutex_t data_mutex;
|
||||
bool stop;
|
||||
|
||||
os_sem_t *update_semaphore;
|
||||
uint64_t frame_time;
|
||||
volatile long skipped_frames;
|
||||
volatile long total_frames;
|
||||
os_sem_t *update_semaphore;
|
||||
uint64_t frame_time;
|
||||
volatile long skipped_frames;
|
||||
volatile long total_frames;
|
||||
|
||||
bool initialized;
|
||||
bool initialized;
|
||||
|
||||
pthread_mutex_t input_mutex;
|
||||
pthread_mutex_t input_mutex;
|
||||
DARRAY(struct video_input) inputs;
|
||||
|
||||
size_t available_frames;
|
||||
size_t first_added;
|
||||
size_t last_added;
|
||||
struct cached_frame_info cache[MAX_CACHE_SIZE];
|
||||
size_t available_frames;
|
||||
size_t first_added;
|
||||
size_t last_added;
|
||||
struct cached_frame_info cache[MAX_CACHE_SIZE];
|
||||
|
||||
volatile bool raw_active;
|
||||
volatile long gpu_refs;
|
||||
volatile bool raw_active;
|
||||
volatile long gpu_refs;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static inline bool scale_video_output(struct video_input *input,
|
||||
struct video_data *data)
|
||||
struct video_data *data)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
|
|
@ -97,14 +97,14 @@ static inline bool scale_video_output(struct video_input *input,
|
|||
|
||||
frame = &input->frame[input->cur_frame];
|
||||
|
||||
success = video_scaler_scale(input->scaler,
|
||||
frame->data, frame->linesize,
|
||||
(const uint8_t * const*)data->data,
|
||||
data->linesize);
|
||||
success = video_scaler_scale(input->scaler, frame->data,
|
||||
frame->linesize,
|
||||
(const uint8_t *const *)data->data,
|
||||
data->linesize);
|
||||
|
||||
if (success) {
|
||||
for (size_t i = 0; i < MAX_AV_PLANES; i++) {
|
||||
data->data[i] = frame->data[i];
|
||||
data->data[i] = frame->data[i];
|
||||
data->linesize[i] = frame->linesize[i];
|
||||
}
|
||||
} else {
|
||||
|
|
@ -134,7 +134,7 @@ static inline bool video_output_cur_frame(struct video_output *video)
|
|||
pthread_mutex_lock(&video->input_mutex);
|
||||
|
||||
for (size_t i = 0; i < video->inputs.num; i++) {
|
||||
struct video_input *input = video->inputs.array+i;
|
||||
struct video_input *input = video->inputs.array + i;
|
||||
struct video_data frame = frame_info->frame;
|
||||
|
||||
if (scale_video_output(input, &frame))
|
||||
|
|
@ -177,7 +177,7 @@ static void *video_thread(void *param)
|
|||
|
||||
const char *video_thread_name =
|
||||
profile_store_name(obs_get_profiler_name_store(),
|
||||
"video_thread(%s)", video->info.name);
|
||||
"video_thread(%s)", video->info.name);
|
||||
|
||||
while (os_sem_wait(video->update_semaphore) == 0) {
|
||||
if (video->stop)
|
||||
|
|
@ -212,10 +212,10 @@ static inline void init_cache(struct video_output *video)
|
|||
|
||||
for (size_t i = 0; i < video->info.cache_size; i++) {
|
||||
struct video_frame *frame;
|
||||
frame = (struct video_frame*)&video->cache[i];
|
||||
frame = (struct video_frame *)&video->cache[i];
|
||||
|
||||
video_frame_init(frame, video->info.format,
|
||||
video->info.width, video->info.height);
|
||||
video_frame_init(frame, video->info.format, video->info.width,
|
||||
video->info.height);
|
||||
}
|
||||
|
||||
video->available_frames = video->info.cache_size;
|
||||
|
|
@ -235,7 +235,7 @@ int video_output_open(video_t **video, struct video_output_info *info)
|
|||
|
||||
memcpy(&out->info, info, sizeof(struct video_output_info));
|
||||
out->frame_time = (uint64_t)(1000000000.0 * (double)info->fps_den /
|
||||
(double)info->fps_num);
|
||||
(double)info->fps_num);
|
||||
out->initialized = false;
|
||||
|
||||
if (pthread_mutexattr_init(&attr) != 0)
|
||||
|
|
@ -274,7 +274,7 @@ void video_output_close(video_t *video)
|
|||
da_free(video->inputs);
|
||||
|
||||
for (size_t i = 0; i < video->info.cache_size; i++)
|
||||
video_frame_free((struct video_frame*)&video->cache[i]);
|
||||
video_frame_free((struct video_frame *)&video->cache[i]);
|
||||
|
||||
os_sem_destroy(video->update_semaphore);
|
||||
pthread_mutex_destroy(&video->data_mutex);
|
||||
|
|
@ -283,11 +283,12 @@ void video_output_close(video_t *video)
|
|||
}
|
||||
|
||||
static size_t video_get_input_idx(const video_t *video,
|
||||
void (*callback)(void *param, struct video_data *frame),
|
||||
void *param)
|
||||
void (*callback)(void *param,
|
||||
struct video_data *frame),
|
||||
void *param)
|
||||
{
|
||||
for (size_t i = 0; i < video->inputs.num; i++) {
|
||||
struct video_input *input = video->inputs.array+i;
|
||||
struct video_input *input = video->inputs.array + i;
|
||||
if (input->callback == callback && input->param == param)
|
||||
return i;
|
||||
}
|
||||
|
|
@ -296,38 +297,37 @@ static size_t video_get_input_idx(const video_t *video,
|
|||
}
|
||||
|
||||
static inline bool video_input_init(struct video_input *input,
|
||||
struct video_output *video)
|
||||
struct video_output *video)
|
||||
{
|
||||
if (input->conversion.width != video->info.width ||
|
||||
if (input->conversion.width != video->info.width ||
|
||||
input->conversion.height != video->info.height ||
|
||||
input->conversion.format != video->info.format) {
|
||||
struct video_scale_info from = {
|
||||
.format = video->info.format,
|
||||
.width = video->info.width,
|
||||
.height = video->info.height,
|
||||
.range = video->info.range,
|
||||
.colorspace = video->info.colorspace
|
||||
};
|
||||
struct video_scale_info from = {.format = video->info.format,
|
||||
.width = video->info.width,
|
||||
.height = video->info.height,
|
||||
.range = video->info.range,
|
||||
.colorspace =
|
||||
video->info.colorspace};
|
||||
|
||||
int ret = video_scaler_create(&input->scaler,
|
||||
&input->conversion, &from,
|
||||
VIDEO_SCALE_FAST_BILINEAR);
|
||||
&input->conversion, &from,
|
||||
VIDEO_SCALE_FAST_BILINEAR);
|
||||
if (ret != VIDEO_SCALER_SUCCESS) {
|
||||
if (ret == VIDEO_SCALER_BAD_CONVERSION)
|
||||
blog(LOG_ERROR, "video_input_init: Bad "
|
||||
"scale conversion type");
|
||||
"scale conversion type");
|
||||
else
|
||||
blog(LOG_ERROR, "video_input_init: Failed to "
|
||||
"create scaler");
|
||||
"create scaler");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < MAX_CONVERT_BUFFERS; i++)
|
||||
video_frame_init(&input->frame[i],
|
||||
input->conversion.format,
|
||||
input->conversion.width,
|
||||
input->conversion.height);
|
||||
input->conversion.format,
|
||||
input->conversion.width,
|
||||
input->conversion.height);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -339,10 +339,9 @@ static inline void reset_frames(video_t *video)
|
|||
os_atomic_set_long(&video->total_frames, 0);
|
||||
}
|
||||
|
||||
bool video_output_connect(video_t *video,
|
||||
const struct video_scale_info *conversion,
|
||||
void (*callback)(void *param, struct video_data *frame),
|
||||
void *param)
|
||||
bool video_output_connect(
|
||||
video_t *video, const struct video_scale_info *conversion,
|
||||
void (*callback)(void *param, struct video_data *frame), void *param)
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
|
|
@ -356,14 +355,14 @@ bool video_output_connect(video_t *video,
|
|||
memset(&input, 0, sizeof(input));
|
||||
|
||||
input.callback = callback;
|
||||
input.param = param;
|
||||
input.param = param;
|
||||
|
||||
if (conversion) {
|
||||
input.conversion = *conversion;
|
||||
} else {
|
||||
input.conversion.format = video->info.format;
|
||||
input.conversion.width = video->info.width;
|
||||
input.conversion.height = video->info.height;
|
||||
input.conversion.format = video->info.format;
|
||||
input.conversion.width = video->info.width;
|
||||
input.conversion.height = video->info.height;
|
||||
}
|
||||
|
||||
if (input.conversion.width == 0)
|
||||
|
|
@ -393,22 +392,22 @@ static void log_skipped(video_t *video)
|
|||
long skipped = os_atomic_load_long(&video->skipped_frames);
|
||||
double percentage_skipped =
|
||||
(double)skipped /
|
||||
(double)os_atomic_load_long(&video->total_frames) *
|
||||
100.0;
|
||||
(double)os_atomic_load_long(&video->total_frames) * 100.0;
|
||||
|
||||
if (skipped)
|
||||
blog(LOG_INFO, "Video stopped, number of "
|
||||
"skipped frames due "
|
||||
"to encoding lag: "
|
||||
"%ld/%ld (%0.1f%%)",
|
||||
video->skipped_frames,
|
||||
video->total_frames,
|
||||
percentage_skipped);
|
||||
blog(LOG_INFO,
|
||||
"Video stopped, number of "
|
||||
"skipped frames due "
|
||||
"to encoding lag: "
|
||||
"%ld/%ld (%0.1f%%)",
|
||||
video->skipped_frames, video->total_frames,
|
||||
percentage_skipped);
|
||||
}
|
||||
|
||||
void video_output_disconnect(video_t *video,
|
||||
void (*callback)(void *param, struct video_data *frame),
|
||||
void *param)
|
||||
void (*callback)(void *param,
|
||||
struct video_data *frame),
|
||||
void *param)
|
||||
{
|
||||
if (!video || !callback)
|
||||
return;
|
||||
|
|
@ -417,7 +416,7 @@ void video_output_disconnect(video_t *video,
|
|||
|
||||
size_t idx = video_get_input_idx(video, callback, param);
|
||||
if (idx != DARRAY_INVALID) {
|
||||
video_input_free(video->inputs.array+idx);
|
||||
video_input_free(video->inputs.array + idx);
|
||||
da_erase(video->inputs, idx);
|
||||
|
||||
if (video->inputs.num == 0) {
|
||||
|
|
@ -433,7 +432,8 @@ void video_output_disconnect(video_t *video,
|
|||
|
||||
bool video_output_active(const video_t *video)
|
||||
{
|
||||
if (!video) return false;
|
||||
if (!video)
|
||||
return false;
|
||||
return os_atomic_load_bool(&video->raw_active);
|
||||
}
|
||||
|
||||
|
|
@ -443,12 +443,13 @@ const struct video_output_info *video_output_get_info(const video_t *video)
|
|||
}
|
||||
|
||||
bool video_output_lock_frame(video_t *video, struct video_frame *frame,
|
||||
int count, uint64_t timestamp)
|
||||
int count, uint64_t timestamp)
|
||||
{
|
||||
struct cached_frame_info *cfi;
|
||||
bool locked;
|
||||
|
||||
if (!video) return false;
|
||||
if (!video)
|
||||
return false;
|
||||
|
||||
pthread_mutex_lock(&video->data_mutex);
|
||||
|
||||
|
|
@ -480,7 +481,8 @@ bool video_output_lock_frame(video_t *video, struct video_frame *frame,
|
|||
|
||||
void video_output_unlock_frame(video_t *video)
|
||||
{
|
||||
if (!video) return;
|
||||
if (!video)
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&video->data_mutex);
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,24 @@ enum video_format {
|
|||
|
||||
/* planar 4:4:4 */
|
||||
VIDEO_FORMAT_I444,
|
||||
|
||||
/* more packed uncompressed formats */
|
||||
VIDEO_FORMAT_BGR3,
|
||||
|
||||
/* planar 4:2:2 */
|
||||
VIDEO_FORMAT_I422,
|
||||
|
||||
/* planar 4:2:0 with alpha */
|
||||
VIDEO_FORMAT_I40A,
|
||||
|
||||
/* planar 4:2:2 with alpha */
|
||||
VIDEO_FORMAT_I42A,
|
||||
|
||||
/* planar 4:4:4 with alpha */
|
||||
VIDEO_FORMAT_YUVA,
|
||||
|
||||
/* packed 4:4:4 with alpha */
|
||||
VIDEO_FORMAT_AYUV,
|
||||
};
|
||||
|
||||
enum video_colorspace {
|
||||
|
|
@ -65,20 +83,20 @@ enum video_range_type {
|
|||
};
|
||||
|
||||
struct video_data {
|
||||
uint8_t *data[MAX_AV_PLANES];
|
||||
uint32_t linesize[MAX_AV_PLANES];
|
||||
uint64_t timestamp;
|
||||
uint8_t *data[MAX_AV_PLANES];
|
||||
uint32_t linesize[MAX_AV_PLANES];
|
||||
uint64_t timestamp;
|
||||
};
|
||||
|
||||
struct video_output_info {
|
||||
const char *name;
|
||||
const char *name;
|
||||
|
||||
enum video_format format;
|
||||
uint32_t fps_num;
|
||||
uint32_t fps_den;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
size_t cache_size;
|
||||
uint32_t fps_num;
|
||||
uint32_t fps_den;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
size_t cache_size;
|
||||
|
||||
enum video_colorspace colorspace;
|
||||
enum video_range_type range;
|
||||
|
|
@ -89,16 +107,22 @@ static inline bool format_is_yuv(enum video_format format)
|
|||
switch (format) {
|
||||
case VIDEO_FORMAT_I420:
|
||||
case VIDEO_FORMAT_NV12:
|
||||
case VIDEO_FORMAT_I422:
|
||||
case VIDEO_FORMAT_YVYU:
|
||||
case VIDEO_FORMAT_YUY2:
|
||||
case VIDEO_FORMAT_UYVY:
|
||||
case VIDEO_FORMAT_I444:
|
||||
case VIDEO_FORMAT_I40A:
|
||||
case VIDEO_FORMAT_I42A:
|
||||
case VIDEO_FORMAT_YUVA:
|
||||
case VIDEO_FORMAT_AYUV:
|
||||
return true;
|
||||
case VIDEO_FORMAT_NONE:
|
||||
case VIDEO_FORMAT_RGBA:
|
||||
case VIDEO_FORMAT_BGRA:
|
||||
case VIDEO_FORMAT_BGRX:
|
||||
case VIDEO_FORMAT_Y800:
|
||||
case VIDEO_FORMAT_BGR3:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -108,16 +132,38 @@ static inline bool format_is_yuv(enum video_format format)
|
|||
static inline const char *get_video_format_name(enum video_format format)
|
||||
{
|
||||
switch (format) {
|
||||
case VIDEO_FORMAT_I420: return "I420";
|
||||
case VIDEO_FORMAT_NV12: return "NV12";
|
||||
case VIDEO_FORMAT_YVYU: return "YVYU";
|
||||
case VIDEO_FORMAT_YUY2: return "YUY2";
|
||||
case VIDEO_FORMAT_UYVY: return "UYVY";
|
||||
case VIDEO_FORMAT_RGBA: return "RGBA";
|
||||
case VIDEO_FORMAT_BGRA: return "BGRA";
|
||||
case VIDEO_FORMAT_BGRX: return "BGRX";
|
||||
case VIDEO_FORMAT_I444: return "I444";
|
||||
case VIDEO_FORMAT_Y800: return "Y800";
|
||||
case VIDEO_FORMAT_I420:
|
||||
return "I420";
|
||||
case VIDEO_FORMAT_NV12:
|
||||
return "NV12";
|
||||
case VIDEO_FORMAT_I422:
|
||||
return "I422";
|
||||
case VIDEO_FORMAT_YVYU:
|
||||
return "YVYU";
|
||||
case VIDEO_FORMAT_YUY2:
|
||||
return "YUY2";
|
||||
case VIDEO_FORMAT_UYVY:
|
||||
return "UYVY";
|
||||
case VIDEO_FORMAT_RGBA:
|
||||
return "RGBA";
|
||||
case VIDEO_FORMAT_BGRA:
|
||||
return "BGRA";
|
||||
case VIDEO_FORMAT_BGRX:
|
||||
return "BGRX";
|
||||
case VIDEO_FORMAT_I444:
|
||||
return "I444";
|
||||
case VIDEO_FORMAT_Y800:
|
||||
return "Y800";
|
||||
case VIDEO_FORMAT_BGR3:
|
||||
return "BGR3";
|
||||
case VIDEO_FORMAT_I40A:
|
||||
return "I40A";
|
||||
case VIDEO_FORMAT_I42A:
|
||||
return "I42A";
|
||||
case VIDEO_FORMAT_YUVA:
|
||||
return "YUVA";
|
||||
case VIDEO_FORMAT_AYUV:
|
||||
return "AYUV";
|
||||
case VIDEO_FORMAT_NONE:;
|
||||
}
|
||||
|
||||
|
|
@ -127,7 +173,8 @@ 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_709: return "709";
|
||||
case VIDEO_CS_709:
|
||||
return "709";
|
||||
case VIDEO_CS_601:
|
||||
case VIDEO_CS_DEFAULT:;
|
||||
}
|
||||
|
|
@ -135,20 +182,19 @@ static inline const char *get_video_colorspace_name(enum video_colorspace cs)
|
|||
return "601";
|
||||
}
|
||||
|
||||
static inline enum video_range_type resolve_video_range(
|
||||
enum video_format format, enum video_range_type range)
|
||||
static inline enum video_range_type
|
||||
resolve_video_range(enum video_format format, enum video_range_type range)
|
||||
{
|
||||
if (range == VIDEO_RANGE_DEFAULT) {
|
||||
range = format_is_yuv(format)
|
||||
? VIDEO_RANGE_PARTIAL
|
||||
: VIDEO_RANGE_FULL;
|
||||
range = format_is_yuv(format) ? VIDEO_RANGE_PARTIAL
|
||||
: VIDEO_RANGE_FULL;
|
||||
}
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
static inline const char *get_video_range_name(enum video_format format,
|
||||
enum video_range_type range)
|
||||
enum video_range_type range)
|
||||
{
|
||||
range = resolve_video_range(format, range);
|
||||
return range == VIDEO_RANGE_FULL ? "Full" : "Partial";
|
||||
|
|
@ -163,9 +209,9 @@ enum video_scale_type {
|
|||
};
|
||||
|
||||
struct video_scale_info {
|
||||
enum video_format format;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
enum video_format format;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
enum video_range_type range;
|
||||
enum video_colorspace colorspace;
|
||||
};
|
||||
|
|
@ -173,30 +219,32 @@ struct video_scale_info {
|
|||
EXPORT enum video_format video_format_from_fourcc(uint32_t fourcc);
|
||||
|
||||
EXPORT bool video_format_get_parameters(enum video_colorspace color_space,
|
||||
enum video_range_type range, float matrix[16],
|
||||
float min_range[3], float max_range[3]);
|
||||
enum video_range_type range,
|
||||
float matrix[16], float min_range[3],
|
||||
float max_range[3]);
|
||||
|
||||
#define VIDEO_OUTPUT_SUCCESS 0
|
||||
#define VIDEO_OUTPUT_SUCCESS 0
|
||||
#define VIDEO_OUTPUT_INVALIDPARAM -1
|
||||
#define VIDEO_OUTPUT_FAIL -2
|
||||
#define VIDEO_OUTPUT_FAIL -2
|
||||
|
||||
EXPORT int video_output_open(video_t **video, struct video_output_info *info);
|
||||
EXPORT void video_output_close(video_t *video);
|
||||
|
||||
EXPORT bool video_output_connect(video_t *video,
|
||||
const struct video_scale_info *conversion,
|
||||
void (*callback)(void *param, struct video_data *frame),
|
||||
void *param);
|
||||
EXPORT bool
|
||||
video_output_connect(video_t *video, const struct video_scale_info *conversion,
|
||||
void (*callback)(void *param, struct video_data *frame),
|
||||
void *param);
|
||||
EXPORT void video_output_disconnect(video_t *video,
|
||||
void (*callback)(void *param, struct video_data *frame),
|
||||
void *param);
|
||||
void (*callback)(void *param,
|
||||
struct video_data *frame),
|
||||
void *param);
|
||||
|
||||
EXPORT bool video_output_active(const video_t *video);
|
||||
|
||||
EXPORT const struct video_output_info *video_output_get_info(
|
||||
const video_t *video);
|
||||
EXPORT const struct video_output_info *
|
||||
video_output_get_info(const video_t *video);
|
||||
EXPORT bool video_output_lock_frame(video_t *video, struct video_frame *frame,
|
||||
int count, uint64_t timestamp);
|
||||
int count, uint64_t timestamp);
|
||||
EXPORT void video_output_unlock_frame(video_t *video);
|
||||
EXPORT uint64_t video_output_get_frame_time(const video_t *video);
|
||||
EXPORT void video_output_stop(video_t *video);
|
||||
|
|
@ -215,7 +263,6 @@ extern void video_output_dec_texture_encoders(video_t *video);
|
|||
extern void video_output_inc_texture_frames(video_t *video);
|
||||
extern void video_output_inc_texture_skipped_frames(video_t *video);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -37,69 +37,59 @@ static struct {
|
|||
|
||||
} format_info[] = {
|
||||
{VIDEO_CS_601,
|
||||
0.114f, 0.299f, {16, 16, 16}, {235, 240, 240},
|
||||
{{16, 128, 128}, {0, 128, 128}},
|
||||
0.114f,
|
||||
0.299f,
|
||||
{16, 16, 16},
|
||||
{235, 240, 240},
|
||||
{{16, 128, 128}, {0, 128, 128}},
|
||||
#ifndef COMPUTE_MATRICES
|
||||
{ 16.0f/255.0f, 16.0f/255.0f, 16.0f/255.0f},
|
||||
{235.0f/255.0f, 240.0f/255.0f, 240.0f/255.0f},
|
||||
{
|
||||
{
|
||||
1.164384f, 0.000000f, 1.596027f, -0.874202f,
|
||||
1.164384f, -0.391762f, -0.812968f, 0.531668f,
|
||||
1.164384f, 2.017232f, 0.000000f, -1.085631f,
|
||||
0.000000f, 0.000000f, 0.000000f, 1.000000f
|
||||
},
|
||||
{
|
||||
1.000000f, 0.000000f, 1.407520f, -0.706520f,
|
||||
1.000000f, -0.345491f, -0.716948f, 0.533303f,
|
||||
1.000000f, 1.778976f, 0.000000f, -0.892976f,
|
||||
0.000000f, 0.000000f, 0.000000f, 1.000000f
|
||||
}
|
||||
}
|
||||
{16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f},
|
||||
{235.0f / 255.0f, 240.0f / 255.0f, 240.0f / 255.0f},
|
||||
{{1.164384f, 0.000000f, 1.596027f, -0.874202f, 1.164384f, -0.391762f,
|
||||
-0.812968f, 0.531668f, 1.164384f, 2.017232f, 0.000000f, -1.085631f,
|
||||
0.000000f, 0.000000f, 0.000000f, 1.000000f},
|
||||
{1.000000f, 0.000000f, 1.407520f, -0.706520f, 1.000000f, -0.345491f,
|
||||
-0.716948f, 0.533303f, 1.000000f, 1.778976f, 0.000000f, -0.892976f,
|
||||
0.000000f, 0.000000f, 0.000000f, 1.000000f}}
|
||||
#endif
|
||||
},
|
||||
{VIDEO_CS_709,
|
||||
0.0722f, 0.2126f, {16, 16, 16}, {235, 240, 240},
|
||||
{{16, 128, 128}, {0, 128, 128}},
|
||||
0.0722f,
|
||||
0.2126f,
|
||||
{16, 16, 16},
|
||||
{235, 240, 240},
|
||||
{{16, 128, 128}, {0, 128, 128}},
|
||||
#ifndef COMPUTE_MATRICES
|
||||
{ 16.0f/255.0f, 16.0f/255.0f, 16.0f/255.0f},
|
||||
{235.0f/255.0f, 240.0f/255.0f, 240.0f/255.0f},
|
||||
{
|
||||
{
|
||||
1.164384f, 0.000000f, 1.792741f, -0.972945f,
|
||||
1.164384f, -0.213249f, -0.532909f, 0.301483f,
|
||||
1.164384f, 2.112402f, 0.000000f, -1.133402f,
|
||||
0.000000f, 0.000000f, 0.000000f, 1.000000f
|
||||
},
|
||||
{
|
||||
1.000000f, 0.000000f, 1.581000f, -0.793600f,
|
||||
1.000000f, -0.188062f, -0.469967f, 0.330305f,
|
||||
1.000000f, 1.862906f, 0.000000f, -0.935106f,
|
||||
0.000000f, 0.000000f, 0.000000f, 1.000000f
|
||||
}
|
||||
}
|
||||
{16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f},
|
||||
{235.0f / 255.0f, 240.0f / 255.0f, 240.0f / 255.0f},
|
||||
{{1.164384f, 0.000000f, 1.792741f, -0.972945f, 1.164384f, -0.213249f,
|
||||
-0.532909f, 0.301483f, 1.164384f, 2.112402f, 0.000000f, -1.133402f,
|
||||
0.000000f, 0.000000f, 0.000000f, 1.000000f},
|
||||
{1.000000f, 0.000000f, 1.581000f, -0.793600f, 1.000000f, -0.188062f,
|
||||
-0.469967f, 0.330305f, 1.000000f, 1.862906f, 0.000000f, -0.935106f,
|
||||
0.000000f, 0.000000f, 0.000000f, 1.000000f}}
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
#define NUM_FORMATS (sizeof(format_info)/sizeof(format_info[0]))
|
||||
#define NUM_FORMATS (sizeof(format_info) / sizeof(format_info[0]))
|
||||
|
||||
#ifdef COMPUTE_MATRICES
|
||||
static void log_matrix(float const matrix[16])
|
||||
{
|
||||
blog(LOG_DEBUG, "\n% f, % f, % f, % f" \
|
||||
"\n% f, % f, % f, % f" \
|
||||
"\n% f, % f, % f, % f" \
|
||||
"\n% f, % f, % f, % f",
|
||||
matrix[ 0], matrix[ 1], matrix[ 2], matrix[ 3],
|
||||
matrix[ 4], matrix[ 5], matrix[ 6], matrix[ 7],
|
||||
matrix[ 8], matrix[ 9], matrix[10], matrix[11],
|
||||
matrix[12], matrix[13], matrix[14], matrix[15]);
|
||||
blog(LOG_DEBUG,
|
||||
"\n% f, % f, % f, % f"
|
||||
"\n% f, % f, % f, % f"
|
||||
"\n% f, % f, % f, % f"
|
||||
"\n% f, % f, % f, % f",
|
||||
matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5],
|
||||
matrix[6], matrix[7], matrix[8], matrix[9], matrix[10], matrix[11],
|
||||
matrix[12], matrix[13], matrix[14], matrix[15]);
|
||||
}
|
||||
|
||||
static void initialize_matrix(float const Kb, float const Kr,
|
||||
int const range_min[3], int const range_max[3],
|
||||
int const black_levels[3], float matrix[16])
|
||||
int const range_min[3], int const range_max[3],
|
||||
int const black_levels[3], float matrix[16])
|
||||
{
|
||||
struct matrix3 color_matrix;
|
||||
|
||||
|
|
@ -107,35 +97,29 @@ static void initialize_matrix(float const Kb, float const Kr,
|
|||
int uvals = (range_max[1] - range_min[1]) / 2;
|
||||
int vvals = (range_max[2] - range_min[2]) / 2;
|
||||
|
||||
vec3_set(&color_matrix.x, 255./yvals,
|
||||
0.,
|
||||
255./vvals * (1. - Kr));
|
||||
vec3_set(&color_matrix.y, 255./yvals,
|
||||
255./uvals * (Kb - 1.) * Kb / (1. - Kb - Kr),
|
||||
255./vvals * (Kr - 1.) * Kr / (1. - Kb - Kr));
|
||||
vec3_set(&color_matrix.z, 255./yvals,
|
||||
255./uvals * (1. - Kb),
|
||||
0.);
|
||||
vec3_set(&color_matrix.x, 255. / yvals, 0., 255. / vvals * (1. - Kr));
|
||||
vec3_set(&color_matrix.y, 255. / yvals,
|
||||
255. / uvals * (Kb - 1.) * Kb / (1. - Kb - Kr),
|
||||
255. / vvals * (Kr - 1.) * Kr / (1. - Kb - Kr));
|
||||
vec3_set(&color_matrix.z, 255. / yvals, 255. / uvals * (1. - Kb), 0.);
|
||||
|
||||
struct vec3 offsets, multiplied;
|
||||
vec3_set(&offsets,
|
||||
-black_levels[0]/255.,
|
||||
-black_levels[1]/255.,
|
||||
-black_levels[2]/255.);
|
||||
vec3_set(&offsets, -black_levels[0] / 255., -black_levels[1] / 255.,
|
||||
-black_levels[2] / 255.);
|
||||
vec3_rotate(&multiplied, &offsets, &color_matrix);
|
||||
|
||||
matrix[ 0] = color_matrix.x.x;
|
||||
matrix[ 1] = color_matrix.x.y;
|
||||
matrix[ 2] = color_matrix.x.z;
|
||||
matrix[ 3] = multiplied.x;
|
||||
matrix[0] = color_matrix.x.x;
|
||||
matrix[1] = color_matrix.x.y;
|
||||
matrix[2] = color_matrix.x.z;
|
||||
matrix[3] = multiplied.x;
|
||||
|
||||
matrix[ 4] = color_matrix.y.x;
|
||||
matrix[ 5] = color_matrix.y.y;
|
||||
matrix[ 6] = color_matrix.y.z;
|
||||
matrix[ 7] = multiplied.y;
|
||||
matrix[4] = color_matrix.y.x;
|
||||
matrix[5] = color_matrix.y.y;
|
||||
matrix[6] = color_matrix.y.z;
|
||||
matrix[7] = multiplied.y;
|
||||
|
||||
matrix[ 8] = color_matrix.z.x;
|
||||
matrix[ 9] = color_matrix.z.y;
|
||||
matrix[8] = color_matrix.z.x;
|
||||
matrix[9] = color_matrix.z.y;
|
||||
matrix[10] = color_matrix.z.z;
|
||||
matrix[11] = multiplied.z;
|
||||
|
||||
|
|
@ -147,26 +131,26 @@ static void initialize_matrix(float const Kb, float const Kr,
|
|||
|
||||
static void initialize_matrices()
|
||||
{
|
||||
static int range_min[] = { 0, 0, 0};
|
||||
static int range_min[] = {0, 0, 0};
|
||||
static int range_max[] = {255, 255, 255};
|
||||
|
||||
for (size_t i = 0; i < NUM_FORMATS; i++) {
|
||||
initialize_matrix(format_info[i].Kb, format_info[i].Kr,
|
||||
range_min, range_max,
|
||||
format_info[i].black_levels[1],
|
||||
format_info[i].matrix[1]);
|
||||
range_min, range_max,
|
||||
format_info[i].black_levels[1],
|
||||
format_info[i].matrix[1]);
|
||||
|
||||
initialize_matrix(format_info[i].Kb, format_info[i].Kr,
|
||||
format_info[i].range_min,
|
||||
format_info[i].range_max,
|
||||
format_info[i].black_levels[0],
|
||||
format_info[i].matrix[0]);
|
||||
format_info[i].range_min,
|
||||
format_info[i].range_max,
|
||||
format_info[i].black_levels[0],
|
||||
format_info[i].matrix[0]);
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
format_info[i].float_range_min[j] =
|
||||
format_info[i].range_min[j]/255.;
|
||||
format_info[i].range_min[j] / 255.;
|
||||
format_info[i].float_range_max[j] =
|
||||
format_info[i].range_max[j]/255.;
|
||||
format_info[i].range_max[j] / 255.;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -178,8 +162,8 @@ static const float full_min[3] = {0.0f, 0.0f, 0.0f};
|
|||
static const float full_max[3] = {1.0f, 1.0f, 1.0f};
|
||||
|
||||
bool video_format_get_parameters(enum video_colorspace color_space,
|
||||
enum video_range_type range, float matrix[16],
|
||||
float range_min[3], float range_max[3])
|
||||
enum video_range_type range, float matrix[16],
|
||||
float range_min[3], float range_max[3])
|
||||
{
|
||||
#ifdef COMPUTE_MATRICES
|
||||
if (!matrices_initialized) {
|
||||
|
|
@ -196,7 +180,7 @@ bool video_format_get_parameters(enum video_colorspace color_space,
|
|||
|
||||
int full_range = range == VIDEO_RANGE_FULL ? 1 : 0;
|
||||
memcpy(matrix, format_info[i].matrix[full_range],
|
||||
sizeof(float) * 16);
|
||||
sizeof(float) * 16);
|
||||
|
||||
if (range == VIDEO_RANGE_FULL) {
|
||||
if (range_min)
|
||||
|
|
@ -208,11 +192,11 @@ bool video_format_get_parameters(enum video_colorspace color_space,
|
|||
|
||||
if (range_min)
|
||||
memcpy(range_min, format_info[i].float_range_min,
|
||||
sizeof(float) * 3);
|
||||
sizeof(float) * 3);
|
||||
|
||||
if (range_max)
|
||||
memcpy(range_max, format_info[i].float_range_max,
|
||||
sizeof(float) * 3);
|
||||
sizeof(float) * 3);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,21 +25,43 @@ struct video_scaler {
|
|||
int src_height;
|
||||
};
|
||||
|
||||
static inline enum AVPixelFormat get_ffmpeg_video_format(
|
||||
enum video_format format)
|
||||
static inline enum AVPixelFormat
|
||||
get_ffmpeg_video_format(enum video_format format)
|
||||
{
|
||||
switch (format) {
|
||||
case VIDEO_FORMAT_NONE: return AV_PIX_FMT_NONE;
|
||||
case VIDEO_FORMAT_I420: return AV_PIX_FMT_YUV420P;
|
||||
case VIDEO_FORMAT_NV12: return AV_PIX_FMT_NV12;
|
||||
case VIDEO_FORMAT_YVYU: return AV_PIX_FMT_NONE;
|
||||
case VIDEO_FORMAT_YUY2: return AV_PIX_FMT_YUYV422;
|
||||
case VIDEO_FORMAT_UYVY: return AV_PIX_FMT_UYVY422;
|
||||
case VIDEO_FORMAT_RGBA: return AV_PIX_FMT_RGBA;
|
||||
case VIDEO_FORMAT_BGRA: return AV_PIX_FMT_BGRA;
|
||||
case VIDEO_FORMAT_BGRX: return AV_PIX_FMT_BGRA;
|
||||
case VIDEO_FORMAT_Y800: return AV_PIX_FMT_GRAY8;
|
||||
case VIDEO_FORMAT_I444: return AV_PIX_FMT_YUV444P;
|
||||
case VIDEO_FORMAT_I420:
|
||||
return AV_PIX_FMT_YUV420P;
|
||||
case VIDEO_FORMAT_NV12:
|
||||
return AV_PIX_FMT_NV12;
|
||||
case VIDEO_FORMAT_YUY2:
|
||||
return AV_PIX_FMT_YUYV422;
|
||||
case VIDEO_FORMAT_UYVY:
|
||||
return AV_PIX_FMT_UYVY422;
|
||||
case VIDEO_FORMAT_RGBA:
|
||||
return AV_PIX_FMT_RGBA;
|
||||
case VIDEO_FORMAT_BGRA:
|
||||
return AV_PIX_FMT_BGRA;
|
||||
case VIDEO_FORMAT_BGRX:
|
||||
return AV_PIX_FMT_BGRA;
|
||||
case VIDEO_FORMAT_Y800:
|
||||
return AV_PIX_FMT_GRAY8;
|
||||
case VIDEO_FORMAT_I444:
|
||||
return AV_PIX_FMT_YUV444P;
|
||||
case VIDEO_FORMAT_BGR3:
|
||||
return AV_PIX_FMT_BGR24;
|
||||
case VIDEO_FORMAT_I422:
|
||||
return AV_PIX_FMT_YUV422P;
|
||||
case VIDEO_FORMAT_I40A:
|
||||
return AV_PIX_FMT_YUVA420P;
|
||||
case VIDEO_FORMAT_I42A:
|
||||
return AV_PIX_FMT_YUVA422P;
|
||||
case VIDEO_FORMAT_YUVA:
|
||||
return AV_PIX_FMT_YUVA444P;
|
||||
case VIDEO_FORMAT_NONE:
|
||||
case VIDEO_FORMAT_YVYU:
|
||||
case VIDEO_FORMAT_AYUV:
|
||||
/* not supported by FFmpeg */
|
||||
return AV_PIX_FMT_NONE;
|
||||
}
|
||||
|
||||
return AV_PIX_FMT_NONE;
|
||||
|
|
@ -48,11 +70,16 @@ static inline enum AVPixelFormat get_ffmpeg_video_format(
|
|||
static inline int get_ffmpeg_scale_type(enum video_scale_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case VIDEO_SCALE_DEFAULT: return SWS_FAST_BILINEAR;
|
||||
case VIDEO_SCALE_POINT: return SWS_POINT;
|
||||
case VIDEO_SCALE_FAST_BILINEAR: return SWS_FAST_BILINEAR;
|
||||
case VIDEO_SCALE_BILINEAR: return SWS_BILINEAR | SWS_AREA;
|
||||
case VIDEO_SCALE_BICUBIC: return SWS_BICUBIC;
|
||||
case VIDEO_SCALE_DEFAULT:
|
||||
return SWS_FAST_BILINEAR;
|
||||
case VIDEO_SCALE_POINT:
|
||||
return SWS_POINT;
|
||||
case VIDEO_SCALE_FAST_BILINEAR:
|
||||
return SWS_FAST_BILINEAR;
|
||||
case VIDEO_SCALE_BILINEAR:
|
||||
return SWS_BILINEAR | SWS_AREA;
|
||||
case VIDEO_SCALE_BICUBIC:
|
||||
return SWS_BICUBIC;
|
||||
}
|
||||
|
||||
return SWS_POINT;
|
||||
|
|
@ -61,9 +88,12 @@ 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);
|
||||
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);
|
||||
}
|
||||
|
||||
return sws_getCoefficients(SWS_CS_ITU601);
|
||||
|
|
@ -72,58 +102,59 @@ static inline const int *get_ffmpeg_coeffs(enum video_colorspace cs)
|
|||
static inline int get_ffmpeg_range_type(enum video_range_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case VIDEO_RANGE_DEFAULT: return 0;
|
||||
case VIDEO_RANGE_PARTIAL: return 0;
|
||||
case VIDEO_RANGE_FULL: return 1;
|
||||
case VIDEO_RANGE_DEFAULT:
|
||||
return 0;
|
||||
case VIDEO_RANGE_PARTIAL:
|
||||
return 0;
|
||||
case VIDEO_RANGE_FULL:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FIXED_1_0 (1<<16)
|
||||
#define FIXED_1_0 (1 << 16)
|
||||
|
||||
int video_scaler_create(video_scaler_t **scaler_out,
|
||||
const struct video_scale_info *dst,
|
||||
const struct video_scale_info *src,
|
||||
enum video_scale_type type)
|
||||
const struct video_scale_info *dst,
|
||||
const struct video_scale_info *src,
|
||||
enum video_scale_type type)
|
||||
{
|
||||
enum AVPixelFormat format_src = get_ffmpeg_video_format(src->format);
|
||||
enum AVPixelFormat format_dst = get_ffmpeg_video_format(dst->format);
|
||||
int scale_type = get_ffmpeg_scale_type(type);
|
||||
const int *coeff_src = get_ffmpeg_coeffs(src->colorspace);
|
||||
const int *coeff_dst = get_ffmpeg_coeffs(dst->colorspace);
|
||||
int range_src = get_ffmpeg_range_type(src->range);
|
||||
int range_dst = get_ffmpeg_range_type(dst->range);
|
||||
int scale_type = get_ffmpeg_scale_type(type);
|
||||
const int *coeff_src = get_ffmpeg_coeffs(src->colorspace);
|
||||
const int *coeff_dst = get_ffmpeg_coeffs(dst->colorspace);
|
||||
int range_src = get_ffmpeg_range_type(src->range);
|
||||
int range_dst = get_ffmpeg_range_type(dst->range);
|
||||
struct video_scaler *scaler;
|
||||
int ret;
|
||||
|
||||
if (!scaler_out)
|
||||
return VIDEO_SCALER_FAILED;
|
||||
|
||||
if (format_src == AV_PIX_FMT_NONE ||
|
||||
format_dst == AV_PIX_FMT_NONE)
|
||||
if (format_src == AV_PIX_FMT_NONE || format_dst == AV_PIX_FMT_NONE)
|
||||
return VIDEO_SCALER_BAD_CONVERSION;
|
||||
|
||||
scaler = bzalloc(sizeof(struct video_scaler));
|
||||
scaler->src_height = src->height;
|
||||
|
||||
scaler->swscale = sws_getCachedContext(NULL,
|
||||
src->width, src->height, format_src,
|
||||
dst->width, dst->height, format_dst,
|
||||
scale_type, NULL, NULL, NULL);
|
||||
scaler->swscale = sws_getCachedContext(NULL, src->width, src->height,
|
||||
format_src, dst->width,
|
||||
dst->height, format_dst,
|
||||
scale_type, NULL, NULL, NULL);
|
||||
if (!scaler->swscale) {
|
||||
blog(LOG_ERROR, "video_scaler_create: Could not create "
|
||||
"swscale");
|
||||
"swscale");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = sws_setColorspaceDetails(scaler->swscale,
|
||||
coeff_src, range_src,
|
||||
coeff_dst, range_dst,
|
||||
0, FIXED_1_0, FIXED_1_0);
|
||||
ret = sws_setColorspaceDetails(scaler->swscale, coeff_src, range_src,
|
||||
coeff_dst, range_dst, 0, FIXED_1_0,
|
||||
FIXED_1_0);
|
||||
if (ret < 0) {
|
||||
blog(LOG_DEBUG, "video_scaler_create: "
|
||||
"sws_setColorspaceDetails failed, ignoring");
|
||||
"sws_setColorspaceDetails failed, ignoring");
|
||||
}
|
||||
|
||||
*scaler_out = scaler;
|
||||
|
|
@ -142,20 +173,20 @@ void video_scaler_destroy(video_scaler_t *scaler)
|
|||
}
|
||||
}
|
||||
|
||||
bool video_scaler_scale(video_scaler_t *scaler,
|
||||
uint8_t *output[], const uint32_t out_linesize[],
|
||||
const uint8_t *const input[], const uint32_t in_linesize[])
|
||||
bool video_scaler_scale(video_scaler_t *scaler, uint8_t *output[],
|
||||
const uint32_t out_linesize[],
|
||||
const uint8_t *const input[],
|
||||
const uint32_t in_linesize[])
|
||||
{
|
||||
if (!scaler)
|
||||
return false;
|
||||
|
||||
int ret = sws_scale(scaler->swscale,
|
||||
input, (const int *)in_linesize,
|
||||
0, scaler->src_height,
|
||||
output, (const int *)out_linesize);
|
||||
int ret = sws_scale(scaler->swscale, input, (const int *)in_linesize, 0,
|
||||
scaler->src_height, output,
|
||||
(const int *)out_linesize);
|
||||
if (ret <= 0) {
|
||||
blog(LOG_ERROR, "video_scaler_scale: sws_scale failed: %d",
|
||||
ret);
|
||||
ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,19 +27,20 @@ extern "C" {
|
|||
struct video_scaler;
|
||||
typedef struct video_scaler video_scaler_t;
|
||||
|
||||
#define VIDEO_SCALER_SUCCESS 0
|
||||
#define VIDEO_SCALER_SUCCESS 0
|
||||
#define VIDEO_SCALER_BAD_CONVERSION -1
|
||||
#define VIDEO_SCALER_FAILED -2
|
||||
#define VIDEO_SCALER_FAILED -2
|
||||
|
||||
EXPORT int video_scaler_create(video_scaler_t **scaler,
|
||||
const struct video_scale_info *dst,
|
||||
const struct video_scale_info *src,
|
||||
enum video_scale_type type);
|
||||
const struct video_scale_info *dst,
|
||||
const struct video_scale_info *src,
|
||||
enum video_scale_type type);
|
||||
EXPORT void video_scaler_destroy(video_scaler_t *scaler);
|
||||
|
||||
EXPORT bool video_scaler_scale(video_scaler_t *scaler,
|
||||
uint8_t *output[], const uint32_t out_linesize[],
|
||||
const uint8_t *const input[], const uint32_t in_linesize[]);
|
||||
EXPORT bool video_scaler_scale(video_scaler_t *scaler, uint8_t *output[],
|
||||
const uint32_t out_linesize[],
|
||||
const uint8_t *const input[],
|
||||
const uint32_t in_linesize[]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,45 +38,45 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
typedef float (*obs_fader_conversion_t)(const float val);
|
||||
|
||||
struct fader_cb {
|
||||
obs_fader_changed_t callback;
|
||||
void *param;
|
||||
obs_fader_changed_t callback;
|
||||
void *param;
|
||||
};
|
||||
|
||||
struct obs_fader {
|
||||
pthread_mutex_t mutex;
|
||||
pthread_mutex_t mutex;
|
||||
obs_fader_conversion_t def_to_db;
|
||||
obs_fader_conversion_t db_to_def;
|
||||
obs_source_t *source;
|
||||
enum obs_fader_type type;
|
||||
float max_db;
|
||||
float min_db;
|
||||
float cur_db;
|
||||
bool ignore_next_signal;
|
||||
obs_source_t *source;
|
||||
enum obs_fader_type type;
|
||||
float max_db;
|
||||
float min_db;
|
||||
float cur_db;
|
||||
bool ignore_next_signal;
|
||||
|
||||
pthread_mutex_t callback_mutex;
|
||||
DARRAY(struct fader_cb)callbacks;
|
||||
pthread_mutex_t callback_mutex;
|
||||
DARRAY(struct fader_cb) callbacks;
|
||||
};
|
||||
|
||||
struct meter_cb {
|
||||
obs_volmeter_updated_t callback;
|
||||
void *param;
|
||||
void *param;
|
||||
};
|
||||
|
||||
struct obs_volmeter {
|
||||
pthread_mutex_t mutex;
|
||||
obs_source_t *source;
|
||||
enum obs_fader_type type;
|
||||
float cur_db;
|
||||
pthread_mutex_t mutex;
|
||||
obs_source_t *source;
|
||||
enum obs_fader_type type;
|
||||
float cur_db;
|
||||
|
||||
pthread_mutex_t callback_mutex;
|
||||
DARRAY(struct meter_cb) callbacks;
|
||||
pthread_mutex_t callback_mutex;
|
||||
DARRAY(struct meter_cb) callbacks;
|
||||
|
||||
enum obs_peak_meter_type peak_meter_type;
|
||||
unsigned int update_ms;
|
||||
float prev_samples[MAX_AUDIO_CHANNELS][4];
|
||||
enum obs_peak_meter_type peak_meter_type;
|
||||
unsigned int update_ms;
|
||||
float prev_samples[MAX_AUDIO_CHANNELS][4];
|
||||
|
||||
float magnitude[MAX_AUDIO_CHANNELS];
|
||||
float peak[MAX_AUDIO_CHANNELS];
|
||||
float magnitude[MAX_AUDIO_CHANNELS];
|
||||
float peak[MAX_AUDIO_CHANNELS];
|
||||
};
|
||||
|
||||
static float cubic_def_to_db(const float def)
|
||||
|
|
@ -157,12 +157,12 @@ static float iec_db_to_def(const float db)
|
|||
return def;
|
||||
}
|
||||
|
||||
#define LOG_OFFSET_DB 6.0f
|
||||
#define LOG_RANGE_DB 96.0f
|
||||
#define LOG_OFFSET_DB 6.0f
|
||||
#define LOG_RANGE_DB 96.0f
|
||||
/* equals -log10f(LOG_OFFSET_DB) */
|
||||
#define LOG_OFFSET_VAL -0.77815125038364363f
|
||||
/* equals -log10f(-LOG_RANGE_DB + LOG_OFFSET_DB) */
|
||||
#define LOG_RANGE_VAL -2.00860017176191756f
|
||||
#define LOG_RANGE_VAL -2.00860017176191756f
|
||||
|
||||
static float log_def_to_db(const float def)
|
||||
{
|
||||
|
|
@ -171,9 +171,10 @@ static float log_def_to_db(const float def)
|
|||
else if (def <= 0.0f)
|
||||
return -INFINITY;
|
||||
|
||||
return -(LOG_RANGE_DB + LOG_OFFSET_DB) * powf(
|
||||
(LOG_RANGE_DB + LOG_OFFSET_DB) / LOG_OFFSET_DB, -def)
|
||||
+ LOG_OFFSET_DB;
|
||||
return -(LOG_RANGE_DB + LOG_OFFSET_DB) *
|
||||
powf((LOG_RANGE_DB + LOG_OFFSET_DB) / LOG_OFFSET_DB,
|
||||
-def) +
|
||||
LOG_OFFSET_DB;
|
||||
}
|
||||
|
||||
static float log_db_to_def(const float db)
|
||||
|
|
@ -183,8 +184,8 @@ static float log_db_to_def(const float db)
|
|||
else if (db <= -96.0f)
|
||||
return 0.0f;
|
||||
|
||||
return (-log10f(-db + LOG_OFFSET_DB) - LOG_RANGE_VAL)
|
||||
/ (LOG_OFFSET_VAL - LOG_RANGE_VAL);
|
||||
return (-log10f(-db + LOG_OFFSET_DB) - LOG_RANGE_VAL) /
|
||||
(LOG_OFFSET_VAL - LOG_RANGE_VAL);
|
||||
}
|
||||
|
||||
static void signal_volume_changed(struct obs_fader *fader, const float db)
|
||||
|
|
@ -198,9 +199,9 @@ static void signal_volume_changed(struct obs_fader *fader, const float db)
|
|||
}
|
||||
|
||||
static void signal_levels_updated(struct obs_volmeter *volmeter,
|
||||
const float magnitude[MAX_AUDIO_CHANNELS],
|
||||
const float peak[MAX_AUDIO_CHANNELS],
|
||||
const float input_peak[MAX_AUDIO_CHANNELS])
|
||||
const float magnitude[MAX_AUDIO_CHANNELS],
|
||||
const float peak[MAX_AUDIO_CHANNELS],
|
||||
const float input_peak[MAX_AUDIO_CHANNELS])
|
||||
{
|
||||
pthread_mutex_lock(&volmeter->callback_mutex);
|
||||
for (size_t i = volmeter->callbacks.num; i > 0; i--) {
|
||||
|
|
@ -212,7 +213,7 @@ static void signal_levels_updated(struct obs_volmeter *volmeter,
|
|||
|
||||
static void fader_source_volume_changed(void *vptr, calldata_t *calldata)
|
||||
{
|
||||
struct obs_fader *fader = (struct obs_fader *) vptr;
|
||||
struct obs_fader *fader = (struct obs_fader *)vptr;
|
||||
|
||||
pthread_mutex_lock(&fader->mutex);
|
||||
|
||||
|
|
@ -222,9 +223,9 @@ static void fader_source_volume_changed(void *vptr, calldata_t *calldata)
|
|||
return;
|
||||
}
|
||||
|
||||
const float mul = (float)calldata_float(calldata, "volume");
|
||||
const float db = mul_to_db(mul);
|
||||
fader->cur_db = db;
|
||||
const float mul = (float)calldata_float(calldata, "volume");
|
||||
const float db = mul_to_db(mul);
|
||||
fader->cur_db = db;
|
||||
|
||||
pthread_mutex_unlock(&fader->mutex);
|
||||
|
||||
|
|
@ -233,11 +234,11 @@ static void fader_source_volume_changed(void *vptr, calldata_t *calldata)
|
|||
|
||||
static void volmeter_source_volume_changed(void *vptr, calldata_t *calldata)
|
||||
{
|
||||
struct obs_volmeter *volmeter = (struct obs_volmeter *) vptr;
|
||||
struct obs_volmeter *volmeter = (struct obs_volmeter *)vptr;
|
||||
|
||||
pthread_mutex_lock(&volmeter->mutex);
|
||||
|
||||
float mul = (float) calldata_float(calldata, "volume");
|
||||
float mul = (float)calldata_float(calldata, "volume");
|
||||
volmeter->cur_db = mul_to_db(mul);
|
||||
|
||||
pthread_mutex_unlock(&volmeter->mutex);
|
||||
|
|
@ -246,7 +247,7 @@ static void volmeter_source_volume_changed(void *vptr, calldata_t *calldata)
|
|||
static void fader_source_destroyed(void *vptr, calldata_t *calldata)
|
||||
{
|
||||
UNUSED_PARAMETER(calldata);
|
||||
struct obs_fader *fader = (struct obs_fader *) vptr;
|
||||
struct obs_fader *fader = (struct obs_fader *)vptr;
|
||||
|
||||
obs_fader_detach_source(fader);
|
||||
}
|
||||
|
|
@ -254,7 +255,7 @@ static void fader_source_destroyed(void *vptr, calldata_t *calldata)
|
|||
static void volmeter_source_destroyed(void *vptr, calldata_t *calldata)
|
||||
{
|
||||
UNUSED_PARAMETER(calldata);
|
||||
struct obs_volmeter *volmeter = (struct obs_volmeter *) vptr;
|
||||
struct obs_volmeter *volmeter = (struct obs_volmeter *)vptr;
|
||||
|
||||
obs_volmeter_detach_source(volmeter);
|
||||
}
|
||||
|
|
@ -271,43 +272,44 @@ static int get_nr_channels_from_audio_data(const struct audio_data *data)
|
|||
|
||||
/* msb(h, g, f, e) lsb(d, c, b, a) --> msb(h, h, g, f) lsb(e, d, c, b)
|
||||
*/
|
||||
#define SHIFT_RIGHT_2PS(msb, lsb) {\
|
||||
__m128 tmp = _mm_shuffle_ps(lsb, msb, _MM_SHUFFLE(0, 0, 3, 3));\
|
||||
lsb = _mm_shuffle_ps(lsb, tmp, _MM_SHUFFLE(2, 1, 2, 1));\
|
||||
msb = _mm_shuffle_ps(msb, msb, _MM_SHUFFLE(3, 3, 2, 1));\
|
||||
}
|
||||
#define SHIFT_RIGHT_2PS(msb, lsb) \
|
||||
{ \
|
||||
__m128 tmp = \
|
||||
_mm_shuffle_ps(lsb, msb, _MM_SHUFFLE(0, 0, 3, 3)); \
|
||||
lsb = _mm_shuffle_ps(lsb, tmp, _MM_SHUFFLE(2, 1, 2, 1)); \
|
||||
msb = _mm_shuffle_ps(msb, msb, _MM_SHUFFLE(3, 3, 2, 1)); \
|
||||
}
|
||||
|
||||
/* x(d, c, b, a) --> (|d|, |c|, |b|, |a|)
|
||||
*/
|
||||
#define abs_ps(v) \
|
||||
_mm_andnot_ps(_mm_set1_ps(-0.f), v)
|
||||
#define abs_ps(v) _mm_andnot_ps(_mm_set1_ps(-0.f), v)
|
||||
|
||||
/* Take cross product of a vector with a matrix resulting in vector.
|
||||
*/
|
||||
#define VECTOR_MATRIX_CROSS_PS(out, v, m0, m1, m2, m3) \
|
||||
{\
|
||||
out = _mm_mul_ps(v, m0);\
|
||||
__m128 mul1 = _mm_mul_ps(v, m1);\
|
||||
__m128 mul2 = _mm_mul_ps(v, m2);\
|
||||
__m128 mul3 = _mm_mul_ps(v, m3);\
|
||||
\
|
||||
_MM_TRANSPOSE4_PS(out, mul1, mul2, mul3);\
|
||||
\
|
||||
out = _mm_add_ps(out, mul1);\
|
||||
out = _mm_add_ps(out, mul2);\
|
||||
out = _mm_add_ps(out, mul3);\
|
||||
}
|
||||
#define VECTOR_MATRIX_CROSS_PS(out, v, m0, m1, m2, m3) \
|
||||
{ \
|
||||
out = _mm_mul_ps(v, m0); \
|
||||
__m128 mul1 = _mm_mul_ps(v, m1); \
|
||||
__m128 mul2 = _mm_mul_ps(v, m2); \
|
||||
__m128 mul3 = _mm_mul_ps(v, m3); \
|
||||
\
|
||||
_MM_TRANSPOSE4_PS(out, mul1, mul2, mul3); \
|
||||
\
|
||||
out = _mm_add_ps(out, mul1); \
|
||||
out = _mm_add_ps(out, mul2); \
|
||||
out = _mm_add_ps(out, mul3); \
|
||||
}
|
||||
|
||||
/* x4(d, c, b, a) --> max(a, b, c, d)
|
||||
*/
|
||||
#define hmax_ps(r, x4) \
|
||||
do { \
|
||||
float x4_mem[4]; \
|
||||
#define hmax_ps(r, x4) \
|
||||
do { \
|
||||
float x4_mem[4]; \
|
||||
_mm_storeu_ps(x4_mem, x4); \
|
||||
r = x4_mem[0]; \
|
||||
r = fmaxf(r, x4_mem[1]); \
|
||||
r = fmaxf(r, x4_mem[2]); \
|
||||
r = fmaxf(r, x4_mem[3]); \
|
||||
r = x4_mem[0]; \
|
||||
r = fmaxf(r, x4_mem[1]); \
|
||||
r = fmaxf(r, x4_mem[2]); \
|
||||
r = fmaxf(r, x4_mem[3]); \
|
||||
} while (false)
|
||||
|
||||
/* Calculate the true peak over a set of samples.
|
||||
|
|
@ -323,15 +325,19 @@ static int get_nr_channels_from_audio_data(const struct audio_data *data)
|
|||
* @returns 5 times oversampled true-peak from the set of samples.
|
||||
*/
|
||||
static float get_true_peak(__m128 previous_samples, const float *samples,
|
||||
size_t nr_samples)
|
||||
size_t nr_samples)
|
||||
{
|
||||
/* These are normalized-sinc parameters for interpolating over sample
|
||||
* points which are located at x-coords: -1.5, -0.5, +0.5, +1.5.
|
||||
* And oversample points at x-coords: -0.3, -0.1, 0.1, 0.3. */
|
||||
const __m128 m3 = _mm_set_ps(-0.155915f, 0.935489f, 0.233872f, -0.103943f);
|
||||
const __m128 m1 = _mm_set_ps(-0.216236f, 0.756827f, 0.504551f, -0.189207f);
|
||||
const __m128 p1 = _mm_set_ps(-0.189207f, 0.504551f, 0.756827f, -0.216236f);
|
||||
const __m128 p3 = _mm_set_ps(-0.103943f, 0.233872f, 0.935489f, -0.155915f);
|
||||
const __m128 m3 =
|
||||
_mm_set_ps(-0.155915f, 0.935489f, 0.233872f, -0.103943f);
|
||||
const __m128 m1 =
|
||||
_mm_set_ps(-0.216236f, 0.756827f, 0.504551f, -0.189207f);
|
||||
const __m128 p1 =
|
||||
_mm_set_ps(-0.189207f, 0.504551f, 0.756827f, -0.216236f);
|
||||
const __m128 p3 =
|
||||
_mm_set_ps(-0.103943f, 0.233872f, 0.935489f, -0.155915f);
|
||||
|
||||
__m128 work = previous_samples;
|
||||
__m128 peak = previous_samples;
|
||||
|
|
@ -370,7 +376,7 @@ static float get_true_peak(__m128 previous_samples, const float *samples,
|
|||
* over. They will have come from a previous iteration.
|
||||
*/
|
||||
static float get_sample_peak(__m128 previous_samples, const float *samples,
|
||||
size_t nr_samples)
|
||||
size_t nr_samples)
|
||||
{
|
||||
__m128 peak = previous_samples;
|
||||
for (size_t i = 0; (i + 3) < nr_samples; i += 4) {
|
||||
|
|
@ -384,7 +390,8 @@ static float get_sample_peak(__m128 previous_samples, const float *samples,
|
|||
}
|
||||
|
||||
static void volmeter_process_peak_last_samples(obs_volmeter_t *volmeter,
|
||||
int channel_nr, float *samples, size_t nr_samples)
|
||||
int channel_nr, float *samples,
|
||||
size_t nr_samples)
|
||||
{
|
||||
/* Take the last 4 samples that need to be used for the next peak
|
||||
* calculation. If there are less than 4 samples in total the new
|
||||
|
|
@ -395,38 +402,39 @@ static void volmeter_process_peak_last_samples(obs_volmeter_t *volmeter,
|
|||
break;
|
||||
case 1:
|
||||
volmeter->prev_samples[channel_nr][0] =
|
||||
volmeter->prev_samples[channel_nr][1];
|
||||
volmeter->prev_samples[channel_nr][1];
|
||||
volmeter->prev_samples[channel_nr][1] =
|
||||
volmeter->prev_samples[channel_nr][2];
|
||||
volmeter->prev_samples[channel_nr][2];
|
||||
volmeter->prev_samples[channel_nr][2] =
|
||||
volmeter->prev_samples[channel_nr][3];
|
||||
volmeter->prev_samples[channel_nr][3] = samples[nr_samples-1];
|
||||
volmeter->prev_samples[channel_nr][3];
|
||||
volmeter->prev_samples[channel_nr][3] = samples[nr_samples - 1];
|
||||
break;
|
||||
case 2:
|
||||
volmeter->prev_samples[channel_nr][0] =
|
||||
volmeter->prev_samples[channel_nr][2];
|
||||
volmeter->prev_samples[channel_nr][2];
|
||||
volmeter->prev_samples[channel_nr][1] =
|
||||
volmeter->prev_samples[channel_nr][3];
|
||||
volmeter->prev_samples[channel_nr][2] = samples[nr_samples-2];
|
||||
volmeter->prev_samples[channel_nr][3] = samples[nr_samples-1];
|
||||
volmeter->prev_samples[channel_nr][3];
|
||||
volmeter->prev_samples[channel_nr][2] = samples[nr_samples - 2];
|
||||
volmeter->prev_samples[channel_nr][3] = samples[nr_samples - 1];
|
||||
break;
|
||||
case 3:
|
||||
volmeter->prev_samples[channel_nr][0] =
|
||||
volmeter->prev_samples[channel_nr][3];
|
||||
volmeter->prev_samples[channel_nr][1] = samples[nr_samples-3];
|
||||
volmeter->prev_samples[channel_nr][2] = samples[nr_samples-2];
|
||||
volmeter->prev_samples[channel_nr][3] = samples[nr_samples-1];
|
||||
volmeter->prev_samples[channel_nr][3];
|
||||
volmeter->prev_samples[channel_nr][1] = samples[nr_samples - 3];
|
||||
volmeter->prev_samples[channel_nr][2] = samples[nr_samples - 2];
|
||||
volmeter->prev_samples[channel_nr][3] = samples[nr_samples - 1];
|
||||
break;
|
||||
default:
|
||||
volmeter->prev_samples[channel_nr][0] = samples[nr_samples-4];
|
||||
volmeter->prev_samples[channel_nr][1] = samples[nr_samples-3];
|
||||
volmeter->prev_samples[channel_nr][2] = samples[nr_samples-2];
|
||||
volmeter->prev_samples[channel_nr][3] = samples[nr_samples-1];
|
||||
volmeter->prev_samples[channel_nr][0] = samples[nr_samples - 4];
|
||||
volmeter->prev_samples[channel_nr][1] = samples[nr_samples - 3];
|
||||
volmeter->prev_samples[channel_nr][2] = samples[nr_samples - 2];
|
||||
volmeter->prev_samples[channel_nr][3] = samples[nr_samples - 1];
|
||||
}
|
||||
}
|
||||
|
||||
static void volmeter_process_peak(obs_volmeter_t *volmeter,
|
||||
const struct audio_data *data, int nr_channels)
|
||||
const struct audio_data *data,
|
||||
int nr_channels)
|
||||
{
|
||||
int nr_samples = data->frames;
|
||||
int channel_nr = 0;
|
||||
|
|
@ -437,8 +445,8 @@ static void volmeter_process_peak(obs_volmeter_t *volmeter,
|
|||
}
|
||||
if (((uintptr_t)samples & 0xf) > 0) {
|
||||
printf("Audio plane %i is not aligned %p skipping "
|
||||
"peak volume measurement.\n",
|
||||
plane_nr, samples);
|
||||
"peak volume measurement.\n",
|
||||
plane_nr, samples);
|
||||
volmeter->peak[channel_nr] = 1.0;
|
||||
channel_nr++;
|
||||
continue;
|
||||
|
|
@ -446,26 +454,25 @@ static void volmeter_process_peak(obs_volmeter_t *volmeter,
|
|||
|
||||
/* volmeter->prev_samples may not be aligned to 16 bytes;
|
||||
* use unaligned load. */
|
||||
__m128 previous_samples = _mm_loadu_ps(
|
||||
volmeter->prev_samples[channel_nr]);
|
||||
__m128 previous_samples =
|
||||
_mm_loadu_ps(volmeter->prev_samples[channel_nr]);
|
||||
|
||||
float peak;
|
||||
switch (volmeter->peak_meter_type) {
|
||||
case TRUE_PEAK_METER:
|
||||
peak = get_true_peak(previous_samples, samples,
|
||||
nr_samples);
|
||||
nr_samples);
|
||||
break;
|
||||
|
||||
case SAMPLE_PEAK_METER:
|
||||
default:
|
||||
peak = get_sample_peak(previous_samples, samples,
|
||||
nr_samples);
|
||||
nr_samples);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
volmeter_process_peak_last_samples(volmeter, channel_nr, samples,
|
||||
nr_samples);
|
||||
volmeter_process_peak_last_samples(volmeter, channel_nr,
|
||||
samples, nr_samples);
|
||||
|
||||
volmeter->peak[channel_nr] = peak;
|
||||
|
||||
|
|
@ -479,7 +486,8 @@ static void volmeter_process_peak(obs_volmeter_t *volmeter,
|
|||
}
|
||||
|
||||
static void volmeter_process_magnitude(obs_volmeter_t *volmeter,
|
||||
const struct audio_data *data, int nr_channels)
|
||||
const struct audio_data *data,
|
||||
int nr_channels)
|
||||
{
|
||||
size_t nr_samples = data->frames;
|
||||
|
||||
|
|
@ -502,7 +510,7 @@ static void volmeter_process_magnitude(obs_volmeter_t *volmeter,
|
|||
}
|
||||
|
||||
static void volmeter_process_audio_data(obs_volmeter_t *volmeter,
|
||||
const struct audio_data *data)
|
||||
const struct audio_data *data)
|
||||
{
|
||||
int nr_channels = get_nr_channels_from_audio_data(data);
|
||||
|
||||
|
|
@ -511,9 +519,10 @@ static void volmeter_process_audio_data(obs_volmeter_t *volmeter,
|
|||
}
|
||||
|
||||
static void volmeter_source_data_received(void *vptr, obs_source_t *source,
|
||||
const struct audio_data *data, bool muted)
|
||||
const struct audio_data *data,
|
||||
bool muted)
|
||||
{
|
||||
struct obs_volmeter *volmeter = (struct obs_volmeter *) vptr;
|
||||
struct obs_volmeter *volmeter = (struct obs_volmeter *)vptr;
|
||||
float mul;
|
||||
float magnitude[MAX_AUDIO_CHANNELS];
|
||||
float peak[MAX_AUDIO_CHANNELS];
|
||||
|
|
@ -527,16 +536,14 @@ static void volmeter_source_data_received(void *vptr, obs_source_t *source,
|
|||
// And convert to dB.
|
||||
mul = muted ? 0.0f : db_to_mul(volmeter->cur_db);
|
||||
for (int channel_nr = 0; channel_nr < MAX_AUDIO_CHANNELS;
|
||||
channel_nr++) {
|
||||
magnitude[channel_nr] = mul_to_db(
|
||||
volmeter->magnitude[channel_nr] * mul);
|
||||
peak[channel_nr] = mul_to_db(
|
||||
volmeter->peak[channel_nr] * mul);
|
||||
channel_nr++) {
|
||||
magnitude[channel_nr] =
|
||||
mul_to_db(volmeter->magnitude[channel_nr] * mul);
|
||||
peak[channel_nr] = mul_to_db(volmeter->peak[channel_nr] * mul);
|
||||
|
||||
/* The input-peak is NOT adjusted with volume, so that the user
|
||||
* can check the input-gain. */
|
||||
input_peak[channel_nr] = mul_to_db(
|
||||
volmeter->peak[channel_nr]);
|
||||
input_peak[channel_nr] = mul_to_db(volmeter->peak[channel_nr]);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&volmeter->mutex);
|
||||
|
|
@ -559,24 +566,24 @@ obs_fader_t *obs_fader_create(enum obs_fader_type type)
|
|||
if (pthread_mutex_init(&fader->callback_mutex, NULL) != 0)
|
||||
goto fail;
|
||||
|
||||
switch(type) {
|
||||
switch (type) {
|
||||
case OBS_FADER_CUBIC:
|
||||
fader->def_to_db = cubic_def_to_db;
|
||||
fader->db_to_def = cubic_db_to_def;
|
||||
fader->max_db = 0.0f;
|
||||
fader->min_db = -INFINITY;
|
||||
fader->max_db = 0.0f;
|
||||
fader->min_db = -INFINITY;
|
||||
break;
|
||||
case OBS_FADER_IEC:
|
||||
fader->def_to_db = iec_def_to_db;
|
||||
fader->db_to_def = iec_db_to_def;
|
||||
fader->max_db = 0.0f;
|
||||
fader->min_db = -INFINITY;
|
||||
fader->max_db = 0.0f;
|
||||
fader->min_db = -INFINITY;
|
||||
break;
|
||||
case OBS_FADER_LOG:
|
||||
fader->def_to_db = log_def_to_db;
|
||||
fader->db_to_def = log_db_to_def;
|
||||
fader->max_db = 0.0f;
|
||||
fader->min_db = -96.0f;
|
||||
fader->max_db = 0.0f;
|
||||
fader->min_db = -96.0f;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
|
|
@ -610,21 +617,21 @@ bool obs_fader_set_db(obs_fader_t *fader, const float db)
|
|||
|
||||
pthread_mutex_lock(&fader->mutex);
|
||||
|
||||
bool clamped = false;
|
||||
bool clamped = false;
|
||||
fader->cur_db = db;
|
||||
|
||||
if (fader->cur_db > fader->max_db) {
|
||||
fader->cur_db = fader->max_db;
|
||||
clamped = true;
|
||||
clamped = true;
|
||||
}
|
||||
if (fader->cur_db < fader->min_db) {
|
||||
fader->cur_db = -INFINITY;
|
||||
clamped = true;
|
||||
clamped = true;
|
||||
}
|
||||
|
||||
fader->ignore_next_signal = true;
|
||||
obs_source_t *src = fader->source;
|
||||
const float mul = db_to_mul(fader->cur_db);
|
||||
obs_source_t *src = fader->source;
|
||||
const float mul = db_to_mul(fader->cur_db);
|
||||
|
||||
pthread_mutex_unlock(&fader->mutex);
|
||||
|
||||
|
|
@ -697,10 +704,9 @@ bool obs_fader_attach_source(obs_fader_t *fader, obs_source_t *source)
|
|||
obs_fader_detach_source(fader);
|
||||
|
||||
sh = obs_source_get_signal_handler(source);
|
||||
signal_handler_connect(sh, "volume",
|
||||
fader_source_volume_changed, fader);
|
||||
signal_handler_connect(sh, "destroy",
|
||||
fader_source_destroyed, fader);
|
||||
signal_handler_connect(sh, "volume", fader_source_volume_changed,
|
||||
fader);
|
||||
signal_handler_connect(sh, "destroy", fader_source_destroyed, fader);
|
||||
vol = obs_source_get_volume(source);
|
||||
|
||||
pthread_mutex_lock(&fader->mutex);
|
||||
|
|
@ -730,15 +736,13 @@ void obs_fader_detach_source(obs_fader_t *fader)
|
|||
return;
|
||||
|
||||
sh = obs_source_get_signal_handler(source);
|
||||
signal_handler_disconnect(sh, "volume",
|
||||
fader_source_volume_changed, fader);
|
||||
signal_handler_disconnect(sh, "destroy",
|
||||
fader_source_destroyed, fader);
|
||||
|
||||
signal_handler_disconnect(sh, "volume", fader_source_volume_changed,
|
||||
fader);
|
||||
signal_handler_disconnect(sh, "destroy", fader_source_destroyed, fader);
|
||||
}
|
||||
|
||||
void obs_fader_add_callback(obs_fader_t *fader, obs_fader_changed_t callback,
|
||||
void *param)
|
||||
void *param)
|
||||
{
|
||||
struct fader_cb cb = {callback, param};
|
||||
|
||||
|
|
@ -751,7 +755,7 @@ void obs_fader_add_callback(obs_fader_t *fader, obs_fader_changed_t callback,
|
|||
}
|
||||
|
||||
void obs_fader_remove_callback(obs_fader_t *fader, obs_fader_changed_t callback,
|
||||
void *param)
|
||||
void *param)
|
||||
{
|
||||
struct fader_cb cb = {callback, param};
|
||||
|
||||
|
|
@ -810,12 +814,12 @@ bool obs_volmeter_attach_source(obs_volmeter_t *volmeter, obs_source_t *source)
|
|||
obs_volmeter_detach_source(volmeter);
|
||||
|
||||
sh = obs_source_get_signal_handler(source);
|
||||
signal_handler_connect(sh, "volume",
|
||||
volmeter_source_volume_changed, volmeter);
|
||||
signal_handler_connect(sh, "destroy",
|
||||
volmeter_source_destroyed, volmeter);
|
||||
obs_source_add_audio_capture_callback(source,
|
||||
volmeter_source_data_received, volmeter);
|
||||
signal_handler_connect(sh, "volume", volmeter_source_volume_changed,
|
||||
volmeter);
|
||||
signal_handler_connect(sh, "destroy", volmeter_source_destroyed,
|
||||
volmeter);
|
||||
obs_source_add_audio_capture_callback(
|
||||
source, volmeter_source_data_received, volmeter);
|
||||
vol = obs_source_get_volume(source);
|
||||
|
||||
pthread_mutex_lock(&volmeter->mutex);
|
||||
|
|
@ -845,16 +849,16 @@ void obs_volmeter_detach_source(obs_volmeter_t *volmeter)
|
|||
return;
|
||||
|
||||
sh = obs_source_get_signal_handler(source);
|
||||
signal_handler_disconnect(sh, "volume",
|
||||
volmeter_source_volume_changed, volmeter);
|
||||
signal_handler_disconnect(sh, "destroy",
|
||||
volmeter_source_destroyed, volmeter);
|
||||
obs_source_remove_audio_capture_callback(source,
|
||||
volmeter_source_data_received, volmeter);
|
||||
signal_handler_disconnect(sh, "volume", volmeter_source_volume_changed,
|
||||
volmeter);
|
||||
signal_handler_disconnect(sh, "destroy", volmeter_source_destroyed,
|
||||
volmeter);
|
||||
obs_source_remove_audio_capture_callback(
|
||||
source, volmeter_source_data_received, volmeter);
|
||||
}
|
||||
|
||||
void obs_volmeter_set_peak_meter_type(obs_volmeter_t *volmeter,
|
||||
enum obs_peak_meter_type peak_meter_type)
|
||||
enum obs_peak_meter_type peak_meter_type)
|
||||
{
|
||||
pthread_mutex_lock(&volmeter->mutex);
|
||||
volmeter->peak_meter_type = peak_meter_type;
|
||||
|
|
@ -862,7 +866,7 @@ void obs_volmeter_set_peak_meter_type(obs_volmeter_t *volmeter,
|
|||
}
|
||||
|
||||
void obs_volmeter_set_update_interval(obs_volmeter_t *volmeter,
|
||||
const unsigned int ms)
|
||||
const unsigned int ms)
|
||||
{
|
||||
if (!volmeter || !ms)
|
||||
return;
|
||||
|
|
@ -907,7 +911,7 @@ int obs_volmeter_get_nr_channels(obs_volmeter_t *volmeter)
|
|||
}
|
||||
|
||||
void obs_volmeter_add_callback(obs_volmeter_t *volmeter,
|
||||
obs_volmeter_updated_t callback, void *param)
|
||||
obs_volmeter_updated_t callback, void *param)
|
||||
{
|
||||
struct meter_cb cb = {callback, param};
|
||||
|
||||
|
|
@ -920,7 +924,7 @@ void obs_volmeter_add_callback(obs_volmeter_t *volmeter,
|
|||
}
|
||||
|
||||
void obs_volmeter_remove_callback(obs_volmeter_t *volmeter,
|
||||
obs_volmeter_updated_t callback, void *param)
|
||||
obs_volmeter_updated_t callback, void *param)
|
||||
{
|
||||
struct meter_cb cb = {callback, param};
|
||||
|
||||
|
|
|
|||
|
|
@ -178,9 +178,10 @@ EXPORT void obs_fader_detach_source(obs_fader_t *fader);
|
|||
typedef void (*obs_fader_changed_t)(void *param, float db);
|
||||
|
||||
EXPORT void obs_fader_add_callback(obs_fader_t *fader,
|
||||
obs_fader_changed_t callback, void *param);
|
||||
obs_fader_changed_t callback, void *param);
|
||||
EXPORT void obs_fader_remove_callback(obs_fader_t *fader,
|
||||
obs_fader_changed_t callback, void *param);
|
||||
obs_fader_changed_t callback,
|
||||
void *param);
|
||||
|
||||
/**
|
||||
* @brief Create a volume meter
|
||||
|
|
@ -213,7 +214,7 @@ EXPORT void obs_volmeter_destroy(obs_volmeter_t *volmeter);
|
|||
* signal.
|
||||
*/
|
||||
EXPORT bool obs_volmeter_attach_source(obs_volmeter_t *volmeter,
|
||||
obs_source_t *source);
|
||||
obs_source_t *source);
|
||||
|
||||
/**
|
||||
* @brief Detach the volume meter from the currently attached source
|
||||
|
|
@ -226,8 +227,9 @@ EXPORT void obs_volmeter_detach_source(obs_volmeter_t *volmeter);
|
|||
* @param volmeter pointer to the volume meter object
|
||||
* @param peak_meter_type set if true-peak needs to be measured.
|
||||
*/
|
||||
EXPORT void obs_volmeter_set_peak_meter_type(obs_volmeter_t *volmeter,
|
||||
enum obs_peak_meter_type peak_meter_type);
|
||||
EXPORT void
|
||||
obs_volmeter_set_peak_meter_type(obs_volmeter_t *volmeter,
|
||||
enum obs_peak_meter_type peak_meter_type);
|
||||
|
||||
/**
|
||||
* @brief Set the update interval for the volume meter
|
||||
|
|
@ -248,7 +250,7 @@ EXPORT void obs_volmeter_set_peak_meter_type(obs_volmeter_t *volmeter,
|
|||
* circumstances.
|
||||
*/
|
||||
EXPORT void obs_volmeter_set_update_interval(obs_volmeter_t *volmeter,
|
||||
const unsigned int ms);
|
||||
const unsigned int ms);
|
||||
|
||||
/**
|
||||
* @brief Get the update interval currently used for the volume meter
|
||||
|
|
@ -263,15 +265,17 @@ EXPORT unsigned int obs_volmeter_get_update_interval(obs_volmeter_t *volmeter);
|
|||
*/
|
||||
EXPORT int obs_volmeter_get_nr_channels(obs_volmeter_t *volmeter);
|
||||
|
||||
typedef void (*obs_volmeter_updated_t)(void *param,
|
||||
const float magnitude[MAX_AUDIO_CHANNELS],
|
||||
const float peak[MAX_AUDIO_CHANNELS],
|
||||
const float input_peak[MAX_AUDIO_CHANNELS]);
|
||||
typedef void (*obs_volmeter_updated_t)(
|
||||
void *param, const float magnitude[MAX_AUDIO_CHANNELS],
|
||||
const float peak[MAX_AUDIO_CHANNELS],
|
||||
const float input_peak[MAX_AUDIO_CHANNELS]);
|
||||
|
||||
EXPORT void obs_volmeter_add_callback(obs_volmeter_t *volmeter,
|
||||
obs_volmeter_updated_t callback, void *param);
|
||||
obs_volmeter_updated_t callback,
|
||||
void *param);
|
||||
EXPORT void obs_volmeter_remove_callback(obs_volmeter_t *volmeter,
|
||||
obs_volmeter_updated_t callback, void *param);
|
||||
obs_volmeter_updated_t callback,
|
||||
void *param);
|
||||
|
||||
EXPORT float obs_mul_to_db(float mul);
|
||||
EXPORT float obs_db_to_mul(float db);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ static void push_audio_tree(obs_source_t *parent, obs_source_t *source, void *p)
|
|||
|
||||
if (da_find(audio->render_order, &source, 0) == DARRAY_INVALID) {
|
||||
obs_source_t *s = obs_source_get_ref(source);
|
||||
if (s) da_push_back(audio->render_order, &s);
|
||||
if (s)
|
||||
da_push_back(audio->render_order, &s);
|
||||
}
|
||||
|
||||
UNUSED_PARAMETER(parent);
|
||||
|
|
@ -44,8 +45,8 @@ static inline size_t convert_time_to_frames(size_t sample_rate, uint64_t t)
|
|||
}
|
||||
|
||||
static inline void mix_audio(struct audio_output_data *mixes,
|
||||
obs_source_t *source, size_t channels, size_t sample_rate,
|
||||
struct ts_info *ts)
|
||||
obs_source_t *source, size_t channels,
|
||||
size_t sample_rate, struct ts_info *ts)
|
||||
{
|
||||
size_t total_floats = AUDIO_OUTPUT_FRAMES;
|
||||
size_t start_point = 0;
|
||||
|
|
@ -54,8 +55,8 @@ static inline void mix_audio(struct audio_output_data *mixes,
|
|||
return;
|
||||
|
||||
if (source->audio_ts != ts->start) {
|
||||
start_point = convert_time_to_frames(sample_rate,
|
||||
source->audio_ts - ts->start);
|
||||
start_point = convert_time_to_frames(
|
||||
sample_rate, source->audio_ts - ts->start);
|
||||
if (start_point == AUDIO_OUTPUT_FRAMES)
|
||||
return;
|
||||
|
||||
|
|
@ -79,18 +80,18 @@ static inline void mix_audio(struct audio_output_data *mixes,
|
|||
}
|
||||
|
||||
static void ignore_audio(obs_source_t *source, size_t channels,
|
||||
size_t sample_rate)
|
||||
size_t sample_rate)
|
||||
{
|
||||
size_t num_floats = source->audio_input_buf[0].size / sizeof(float);
|
||||
|
||||
if (num_floats) {
|
||||
for (size_t ch = 0; ch < channels; ch++)
|
||||
circlebuf_pop_front(&source->audio_input_buf[ch], NULL,
|
||||
source->audio_input_buf[ch].size);
|
||||
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;
|
||||
(uint64_t)sample_rate;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -112,14 +113,14 @@ static bool discard_if_stopped(obs_source_t *source, size_t channels)
|
|||
source->pending_stop = true;
|
||||
#if DEBUG_AUDIO == 1
|
||||
blog(LOG_DEBUG, "doing pending stop trick: '%s'",
|
||||
source->context.name);
|
||||
source->context.name);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
for (size_t ch = 0; ch < channels; ch++)
|
||||
circlebuf_pop_front(&source->audio_input_buf[ch], NULL,
|
||||
source->audio_input_buf[ch].size);
|
||||
source->audio_input_buf[ch].size);
|
||||
|
||||
source->pending_stop = false;
|
||||
source->audio_ts = 0;
|
||||
|
|
@ -138,8 +139,8 @@ static bool discard_if_stopped(obs_source_t *source, size_t channels)
|
|||
#define MAX_AUDIO_SIZE (AUDIO_OUTPUT_FRAMES * sizeof(float))
|
||||
|
||||
static inline void discard_audio(struct obs_core_audio *audio,
|
||||
obs_source_t *source, size_t channels, size_t sample_rate,
|
||||
struct ts_info *ts)
|
||||
obs_source_t *source, size_t channels,
|
||||
size_t sample_rate, struct ts_info *ts)
|
||||
{
|
||||
size_t total_floats = AUDIO_OUTPUT_FRAMES;
|
||||
size_t size;
|
||||
|
|
@ -155,10 +156,11 @@ static inline void discard_audio(struct obs_core_audio *audio,
|
|||
|
||||
if (ts->end <= source->audio_ts) {
|
||||
#if DEBUG_AUDIO == 1
|
||||
blog(LOG_DEBUG, "can't discard, source "
|
||||
"timestamp (%"PRIu64") >= "
|
||||
"end timestamp (%"PRIu64")",
|
||||
source->audio_ts, ts->end);
|
||||
blog(LOG_DEBUG,
|
||||
"can't discard, source "
|
||||
"timestamp (%" PRIu64 ") >= "
|
||||
"end timestamp (%" PRIu64 ")",
|
||||
source->audio_ts, ts->end);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
|
@ -171,10 +173,11 @@ static inline void discard_audio(struct obs_core_audio *audio,
|
|||
|
||||
#if DEBUG_AUDIO == 1
|
||||
if (is_audio_source) {
|
||||
blog(LOG_DEBUG, "can't discard, source "
|
||||
"timestamp (%"PRIu64") < "
|
||||
"start timestamp (%"PRIu64")",
|
||||
source->audio_ts, ts->start);
|
||||
blog(LOG_DEBUG,
|
||||
"can't discard, source "
|
||||
"timestamp (%" PRIu64 ") < "
|
||||
"start timestamp (%" PRIu64 ")",
|
||||
source->audio_ts, ts->start);
|
||||
}
|
||||
#endif
|
||||
if (audio->total_buffering_ticks == MAX_BUFFERING_TICKS)
|
||||
|
|
@ -184,8 +187,8 @@ static inline void discard_audio(struct obs_core_audio *audio,
|
|||
|
||||
if (source->audio_ts != ts->start &&
|
||||
source->audio_ts != (ts->start - 1)) {
|
||||
size_t start_point = convert_time_to_frames(sample_rate,
|
||||
source->audio_ts - ts->start);
|
||||
size_t start_point = convert_time_to_frames(
|
||||
sample_rate, source->audio_ts - ts->start);
|
||||
if (start_point == AUDIO_OUTPUT_FRAMES) {
|
||||
#if DEBUG_AUDIO == 1
|
||||
if (is_audio_source)
|
||||
|
|
@ -208,6 +211,7 @@ static inline void discard_audio(struct obs_core_audio *audio,
|
|||
if (is_audio_source)
|
||||
blog(LOG_DEBUG, "can't discard, data still pending");
|
||||
#endif
|
||||
source->audio_ts = ts->end;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -218,8 +222,7 @@ static inline void discard_audio(struct obs_core_audio *audio,
|
|||
|
||||
#if DEBUG_AUDIO == 1
|
||||
if (is_audio_source)
|
||||
blog(LOG_DEBUG, "audio discarded, new ts: %"PRIu64,
|
||||
ts->end);
|
||||
blog(LOG_DEBUG, "audio discarded, new ts: %" PRIu64, ts->end);
|
||||
#endif
|
||||
|
||||
source->pending_stop = false;
|
||||
|
|
@ -227,8 +230,8 @@ static inline void discard_audio(struct obs_core_audio *audio,
|
|||
}
|
||||
|
||||
static void add_audio_buffering(struct obs_core_audio *audio,
|
||||
size_t sample_rate, struct ts_info *ts, uint64_t min_ts,
|
||||
const char *buffering_name)
|
||||
size_t sample_rate, struct ts_info *ts,
|
||||
uint64_t min_ts, const char *buffering_name)
|
||||
{
|
||||
struct ts_info new_ts;
|
||||
uint64_t offset;
|
||||
|
|
@ -257,44 +260,50 @@ static void add_audio_buffering(struct obs_core_audio *audio,
|
|||
|
||||
ms = ticks * AUDIO_OUTPUT_FRAMES * 1000 / sample_rate;
|
||||
total_ms = audio->total_buffering_ticks * AUDIO_OUTPUT_FRAMES * 1000 /
|
||||
sample_rate;
|
||||
sample_rate;
|
||||
|
||||
blog(LOG_INFO, "adding %d milliseconds of audio buffering, total "
|
||||
"audio buffering is now %d milliseconds"
|
||||
" (source: %s)\n",
|
||||
(int)ms, (int)total_ms, buffering_name);
|
||||
blog(LOG_INFO,
|
||||
"adding %d milliseconds of audio buffering, total "
|
||||
"audio buffering is now %d milliseconds"
|
||||
" (source: %s)\n",
|
||||
(int)ms, (int)total_ms, buffering_name);
|
||||
#if DEBUG_AUDIO == 1
|
||||
blog(LOG_DEBUG, "min_ts (%"PRIu64") < start timestamp "
|
||||
"(%"PRIu64")", min_ts, ts->start);
|
||||
blog(LOG_DEBUG, "old buffered ts: %"PRIu64"-%"PRIu64,
|
||||
ts->start, ts->end);
|
||||
blog(LOG_DEBUG,
|
||||
"min_ts (%" PRIu64 ") < start timestamp "
|
||||
"(%" PRIu64 ")",
|
||||
min_ts, ts->start);
|
||||
blog(LOG_DEBUG, "old buffered ts: %" PRIu64 "-%" PRIu64, ts->start,
|
||||
ts->end);
|
||||
#endif
|
||||
|
||||
new_ts.start = audio->buffered_ts - audio_frames_to_ns(sample_rate,
|
||||
audio->buffering_wait_ticks * AUDIO_OUTPUT_FRAMES);
|
||||
new_ts.start =
|
||||
audio->buffered_ts -
|
||||
audio_frames_to_ns(sample_rate, audio->buffering_wait_ticks *
|
||||
AUDIO_OUTPUT_FRAMES);
|
||||
|
||||
while (ticks--) {
|
||||
int cur_ticks = ++audio->buffering_wait_ticks;
|
||||
|
||||
new_ts.end = new_ts.start;
|
||||
new_ts.start = audio->buffered_ts - audio_frames_to_ns(
|
||||
sample_rate,
|
||||
cur_ticks * AUDIO_OUTPUT_FRAMES);
|
||||
new_ts.start =
|
||||
audio->buffered_ts -
|
||||
audio_frames_to_ns(sample_rate,
|
||||
cur_ticks * AUDIO_OUTPUT_FRAMES);
|
||||
|
||||
#if DEBUG_AUDIO == 1
|
||||
blog(LOG_DEBUG, "add buffered ts: %"PRIu64"-%"PRIu64,
|
||||
new_ts.start, new_ts.end);
|
||||
blog(LOG_DEBUG, "add buffered ts: %" PRIu64 "-%" PRIu64,
|
||||
new_ts.start, new_ts.end);
|
||||
#endif
|
||||
|
||||
circlebuf_push_front(&audio->buffered_timestamps, &new_ts,
|
||||
sizeof(new_ts));
|
||||
sizeof(new_ts));
|
||||
}
|
||||
|
||||
*ts = new_ts;
|
||||
}
|
||||
|
||||
static bool audio_buffer_insuffient(struct obs_source *source,
|
||||
size_t sample_rate, uint64_t min_ts)
|
||||
size_t sample_rate, uint64_t min_ts)
|
||||
{
|
||||
size_t total_floats = AUDIO_OUTPUT_FRAMES;
|
||||
size_t size;
|
||||
|
|
@ -304,10 +313,9 @@ static bool audio_buffer_insuffient(struct obs_source *source,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (source->audio_ts != min_ts &&
|
||||
source->audio_ts != (min_ts - 1)) {
|
||||
size_t start_point = convert_time_to_frames(sample_rate,
|
||||
source->audio_ts - min_ts);
|
||||
if (source->audio_ts != min_ts && source->audio_ts != (min_ts - 1)) {
|
||||
size_t start_point = convert_time_to_frames(
|
||||
sample_rate, source->audio_ts - min_ts);
|
||||
if (start_point >= AUDIO_OUTPUT_FRAMES)
|
||||
return false;
|
||||
|
||||
|
|
@ -325,39 +333,39 @@ static bool audio_buffer_insuffient(struct obs_source *source,
|
|||
}
|
||||
|
||||
static inline const char *find_min_ts(struct obs_core_data *data,
|
||||
uint64_t *min_ts)
|
||||
uint64_t *min_ts)
|
||||
{
|
||||
obs_source_t *buffering_source = NULL;
|
||||
struct obs_source *source = data->first_audio_source;
|
||||
while (source) {
|
||||
if (!source->audio_pending && source->audio_ts &&
|
||||
source->audio_ts < *min_ts) {
|
||||
source->audio_ts < *min_ts) {
|
||||
*min_ts = source->audio_ts;
|
||||
buffering_source = source;
|
||||
}
|
||||
|
||||
source = (struct obs_source*)source->next_audio_source;
|
||||
source = (struct obs_source *)source->next_audio_source;
|
||||
}
|
||||
return buffering_source ? obs_source_get_name(buffering_source) : NULL;
|
||||
}
|
||||
|
||||
static inline bool mark_invalid_sources(struct obs_core_data *data,
|
||||
size_t sample_rate, uint64_t min_ts)
|
||||
size_t sample_rate, uint64_t min_ts)
|
||||
{
|
||||
bool recalculate = false;
|
||||
|
||||
struct obs_source *source = data->first_audio_source;
|
||||
while (source) {
|
||||
recalculate |= audio_buffer_insuffient(source, sample_rate,
|
||||
min_ts);
|
||||
source = (struct obs_source*)source->next_audio_source;
|
||||
recalculate |=
|
||||
audio_buffer_insuffient(source, sample_rate, min_ts);
|
||||
source = (struct obs_source *)source->next_audio_source;
|
||||
}
|
||||
|
||||
return recalculate;
|
||||
}
|
||||
|
||||
static inline const char *calc_min_ts(struct obs_core_data *data,
|
||||
size_t sample_rate, uint64_t *min_ts)
|
||||
size_t sample_rate, uint64_t *min_ts)
|
||||
{
|
||||
const char *buffering_name = find_min_ts(data, min_ts);
|
||||
if (mark_invalid_sources(data, sample_rate, *min_ts))
|
||||
|
|
@ -371,9 +379,9 @@ static inline void release_audio_sources(struct obs_core_audio *audio)
|
|||
obs_source_release(audio->render_order.array[i]);
|
||||
}
|
||||
|
||||
bool audio_callback(void *param,
|
||||
uint64_t start_ts_in, uint64_t end_ts_in, uint64_t *out_ts,
|
||||
uint32_t mixers, struct audio_output_data *mixes)
|
||||
bool audio_callback(void *param, uint64_t start_ts_in, uint64_t end_ts_in,
|
||||
uint64_t *out_ts, uint32_t mixers,
|
||||
struct audio_output_data *mixes)
|
||||
{
|
||||
struct obs_core_data *data = &obs->data;
|
||||
struct obs_core_audio *audio = &obs->audio;
|
||||
|
|
@ -404,7 +412,7 @@ bool audio_callback(void *param,
|
|||
obs_source_t *source = obs_get_output_source(i);
|
||||
if (source) {
|
||||
obs_source_enum_active_tree(source, push_audio_tree,
|
||||
audio);
|
||||
audio);
|
||||
push_audio_tree(NULL, source, audio);
|
||||
da_push_back(audio->root_nodes, &source);
|
||||
obs_source_release(source);
|
||||
|
|
@ -416,7 +424,7 @@ bool audio_callback(void *param,
|
|||
source = data->first_audio_source;
|
||||
while (source) {
|
||||
push_audio_tree(NULL, source, audio);
|
||||
source = (struct obs_source*)source->next_audio_source;
|
||||
source = (struct obs_source *)source->next_audio_source;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&data->audio_sources_mutex);
|
||||
|
|
@ -426,7 +434,7 @@ bool audio_callback(void *param,
|
|||
for (size_t i = 0; i < audio->render_order.num; i++) {
|
||||
obs_source_t *source = audio->render_order.array[i];
|
||||
obs_source_audio_render(source, mixers, channels, sample_rate,
|
||||
audio_size);
|
||||
audio_size);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------ */
|
||||
|
|
@ -439,7 +447,7 @@ bool audio_callback(void *param,
|
|||
/* if a source has gone backward in time, buffer */
|
||||
if (min_ts < ts.start)
|
||||
add_audio_buffering(audio, sample_rate, &ts, min_ts,
|
||||
buffering_name);
|
||||
buffering_name);
|
||||
|
||||
/* ------------------------------------------------ */
|
||||
/* mix audio */
|
||||
|
|
@ -454,7 +462,7 @@ bool audio_callback(void *param,
|
|||
|
||||
if (source->audio_output_buf[0][0] && source->audio_ts)
|
||||
mix_audio(mixes, source, channels, sample_rate,
|
||||
&ts);
|
||||
&ts);
|
||||
|
||||
pthread_mutex_unlock(&source->audio_buf_mutex);
|
||||
}
|
||||
|
|
@ -470,7 +478,7 @@ bool audio_callback(void *param,
|
|||
discard_audio(audio, source, channels, sample_rate, &ts);
|
||||
pthread_mutex_unlock(&source->audio_buf_mutex);
|
||||
|
||||
source = (struct obs_source*)source->next_audio_source;
|
||||
source = (struct obs_source *)source->next_audio_source;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&data->audio_sources_mutex);
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ bool obs_avc_keyframe(const uint8_t *data, size_t size)
|
|||
|
||||
nal_start = obs_avc_find_startcode(data, end);
|
||||
while (true) {
|
||||
while (nal_start < end && !*(nal_start++));
|
||||
while (nal_start < end && !*(nal_start++))
|
||||
;
|
||||
|
||||
if (nal_start == end)
|
||||
break;
|
||||
|
|
@ -48,7 +49,7 @@ bool obs_avc_keyframe(const uint8_t *data, size_t size)
|
|||
* scenarios that I was unaware of, so instead of just searching for {0, 0, 1}
|
||||
* we'll just use the code from FFmpeg - http://www.ffmpeg.org/ */
|
||||
static const uint8_t *ff_avc_find_startcode_internal(const uint8_t *p,
|
||||
const uint8_t *end)
|
||||
const uint8_t *end)
|
||||
{
|
||||
const uint8_t *a = p + 4 - ((intptr_t)p & 3);
|
||||
|
||||
|
|
@ -58,21 +59,21 @@ static const uint8_t *ff_avc_find_startcode_internal(const uint8_t *p,
|
|||
}
|
||||
|
||||
for (end -= 3; p < end; p += 4) {
|
||||
uint32_t x = *(const uint32_t*)p;
|
||||
uint32_t x = *(const uint32_t *)p;
|
||||
|
||||
if ((x - 0x01010101) & (~x) & 0x80808080) {
|
||||
if (p[1] == 0) {
|
||||
if (p[0] == 0 && p[2] == 1)
|
||||
return p;
|
||||
if (p[2] == 0 && p[3] == 1)
|
||||
return p+1;
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
if (p[3] == 0) {
|
||||
if (p[2] == 0 && p[4] == 1)
|
||||
return p+2;
|
||||
return p + 2;
|
||||
if (p[4] == 0 && p[5] == 1)
|
||||
return p+3;
|
||||
return p + 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -87,8 +88,9 @@ static const uint8_t *ff_avc_find_startcode_internal(const uint8_t *p,
|
|||
|
||||
const uint8_t *obs_avc_find_startcode(const uint8_t *p, const uint8_t *end)
|
||||
{
|
||||
const uint8_t *out= ff_avc_find_startcode_internal(p, end);
|
||||
if (p < out && out < end && !out[-1]) out--;
|
||||
const uint8_t *out = ff_avc_find_startcode_internal(p, end);
|
||||
if (p < out && out < end && !out[-1])
|
||||
out--;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
@ -98,15 +100,16 @@ static inline int get_drop_priority(int priority)
|
|||
}
|
||||
|
||||
static void serialize_avc_data(struct serializer *s, const uint8_t *data,
|
||||
size_t size, bool *is_keyframe, int *priority)
|
||||
size_t size, bool *is_keyframe, int *priority)
|
||||
{
|
||||
const uint8_t *nal_start, *nal_end;
|
||||
const uint8_t *end = data+size;
|
||||
const uint8_t *end = data + size;
|
||||
int type;
|
||||
|
||||
nal_start = obs_avc_find_startcode(data, end);
|
||||
while (true) {
|
||||
while (nal_start < end && !*(nal_start++));
|
||||
while (nal_start < end && !*(nal_start++))
|
||||
;
|
||||
|
||||
if (nal_start == end)
|
||||
break;
|
||||
|
|
@ -128,7 +131,7 @@ static void serialize_avc_data(struct serializer *s, const uint8_t *data,
|
|||
}
|
||||
|
||||
void obs_parse_avc_packet(struct encoder_packet *avc_packet,
|
||||
const struct encoder_packet *src)
|
||||
const struct encoder_packet *src)
|
||||
{
|
||||
struct array_output_data output;
|
||||
struct serializer s;
|
||||
|
|
@ -139,32 +142,32 @@ void obs_parse_avc_packet(struct encoder_packet *avc_packet,
|
|||
|
||||
serialize(&s, &ref, sizeof(ref));
|
||||
serialize_avc_data(&s, src->data, src->size, &avc_packet->keyframe,
|
||||
&avc_packet->priority);
|
||||
&avc_packet->priority);
|
||||
|
||||
avc_packet->data = output.bytes.array + sizeof(ref);
|
||||
avc_packet->size = output.bytes.num - sizeof(ref);
|
||||
avc_packet->data = output.bytes.array + sizeof(ref);
|
||||
avc_packet->size = output.bytes.num - sizeof(ref);
|
||||
avc_packet->drop_priority = get_drop_priority(avc_packet->priority);
|
||||
}
|
||||
|
||||
static inline bool has_start_code(const uint8_t *data)
|
||||
{
|
||||
if (data[0] != 0 || data[1] != 0)
|
||||
return false;
|
||||
return false;
|
||||
|
||||
return data[2] == 1 || (data[2] == 0 && data[3] == 1);
|
||||
}
|
||||
|
||||
static void get_sps_pps(const uint8_t *data, size_t size,
|
||||
const uint8_t **sps, size_t *sps_size,
|
||||
const uint8_t **pps, size_t *pps_size)
|
||||
static void get_sps_pps(const uint8_t *data, size_t size, const uint8_t **sps,
|
||||
size_t *sps_size, const uint8_t **pps, size_t *pps_size)
|
||||
{
|
||||
const uint8_t *nal_start, *nal_end;
|
||||
const uint8_t *end = data+size;
|
||||
const uint8_t *end = data + size;
|
||||
int type;
|
||||
|
||||
nal_start = obs_avc_find_startcode(data, end);
|
||||
while (true) {
|
||||
while (nal_start < end && !*(nal_start++));
|
||||
while (nal_start < end && !*(nal_start++))
|
||||
;
|
||||
|
||||
if (nal_start == end)
|
||||
break;
|
||||
|
|
@ -193,7 +196,8 @@ size_t obs_parse_avc_header(uint8_t **header, const uint8_t *data, size_t size)
|
|||
|
||||
array_output_serializer_init(&s, &output);
|
||||
|
||||
if (size <= 6) return 0;
|
||||
if (size <= 6)
|
||||
return 0;
|
||||
|
||||
if (!has_start_code(data)) {
|
||||
*header = bmemdup(data, size);
|
||||
|
|
@ -205,7 +209,7 @@ size_t obs_parse_avc_header(uint8_t **header, const uint8_t *data, size_t size)
|
|||
return 0;
|
||||
|
||||
s_w8(&s, 0x01);
|
||||
s_write(&s, sps+1, 3);
|
||||
s_write(&s, sps + 1, 3);
|
||||
s_w8(&s, 0xff);
|
||||
s_w8(&s, 0xe1);
|
||||
|
||||
|
|
@ -220,9 +224,9 @@ size_t obs_parse_avc_header(uint8_t **header, const uint8_t *data, size_t size)
|
|||
}
|
||||
|
||||
void obs_extract_avc_headers(const uint8_t *packet, size_t size,
|
||||
uint8_t **new_packet_data, size_t *new_packet_size,
|
||||
uint8_t **header_data, size_t *header_size,
|
||||
uint8_t **sei_data, size_t *sei_size)
|
||||
uint8_t **new_packet_data, size_t *new_packet_size,
|
||||
uint8_t **header_data, size_t *header_size,
|
||||
uint8_t **sei_data, size_t *sei_size)
|
||||
{
|
||||
DARRAY(uint8_t) new_packet;
|
||||
DARRAY(uint8_t) header;
|
||||
|
|
@ -240,7 +244,8 @@ void obs_extract_avc_headers(const uint8_t *packet, size_t size,
|
|||
while (nal_end != end) {
|
||||
nal_codestart = nal_start;
|
||||
|
||||
while (nal_start < end && !*(nal_start++));
|
||||
while (nal_start < end && !*(nal_start++))
|
||||
;
|
||||
|
||||
if (nal_start == end)
|
||||
break;
|
||||
|
|
@ -253,14 +258,14 @@ void obs_extract_avc_headers(const uint8_t *packet, size_t size,
|
|||
|
||||
if (type == OBS_NAL_SPS || type == OBS_NAL_PPS) {
|
||||
da_push_back_array(header, nal_codestart,
|
||||
nal_end - nal_codestart);
|
||||
nal_end - nal_codestart);
|
||||
} else if (type == OBS_NAL_SEI) {
|
||||
da_push_back_array(sei, nal_codestart,
|
||||
nal_end - nal_codestart);
|
||||
nal_end - nal_codestart);
|
||||
|
||||
} else {
|
||||
da_push_back_array(new_packet, nal_codestart,
|
||||
nal_end - nal_codestart);
|
||||
nal_end - nal_codestart);
|
||||
}
|
||||
|
||||
nal_start = nal_end;
|
||||
|
|
|
|||
|
|
@ -25,40 +25,39 @@ extern "C" {
|
|||
|
||||
struct encoder_packet;
|
||||
|
||||
enum {
|
||||
OBS_NAL_UNKNOWN = 0,
|
||||
OBS_NAL_SLICE = 1,
|
||||
OBS_NAL_SLICE_DPA = 2,
|
||||
OBS_NAL_SLICE_DPB = 3,
|
||||
OBS_NAL_SLICE_DPC = 4,
|
||||
OBS_NAL_SLICE_IDR = 5,
|
||||
OBS_NAL_SEI = 6,
|
||||
OBS_NAL_SPS = 7,
|
||||
OBS_NAL_PPS = 8,
|
||||
OBS_NAL_AUD = 9,
|
||||
OBS_NAL_FILLER = 12,
|
||||
enum { OBS_NAL_UNKNOWN = 0,
|
||||
OBS_NAL_SLICE = 1,
|
||||
OBS_NAL_SLICE_DPA = 2,
|
||||
OBS_NAL_SLICE_DPB = 3,
|
||||
OBS_NAL_SLICE_DPC = 4,
|
||||
OBS_NAL_SLICE_IDR = 5,
|
||||
OBS_NAL_SEI = 6,
|
||||
OBS_NAL_SPS = 7,
|
||||
OBS_NAL_PPS = 8,
|
||||
OBS_NAL_AUD = 9,
|
||||
OBS_NAL_FILLER = 12,
|
||||
};
|
||||
|
||||
enum {
|
||||
OBS_NAL_PRIORITY_DISPOSABLE = 0,
|
||||
OBS_NAL_PRIORITY_LOW = 1,
|
||||
OBS_NAL_PRIORITY_HIGH = 2,
|
||||
OBS_NAL_PRIORITY_HIGHEST = 3,
|
||||
enum { OBS_NAL_PRIORITY_DISPOSABLE = 0,
|
||||
OBS_NAL_PRIORITY_LOW = 1,
|
||||
OBS_NAL_PRIORITY_HIGH = 2,
|
||||
OBS_NAL_PRIORITY_HIGHEST = 3,
|
||||
};
|
||||
|
||||
/* Helpers for parsing AVC NAL units. */
|
||||
|
||||
EXPORT bool obs_avc_keyframe(const uint8_t *data, size_t size);
|
||||
EXPORT const uint8_t *obs_avc_find_startcode(const uint8_t *p,
|
||||
const uint8_t *end);
|
||||
const uint8_t *end);
|
||||
EXPORT void obs_parse_avc_packet(struct encoder_packet *avc_packet,
|
||||
const struct encoder_packet *src);
|
||||
const struct encoder_packet *src);
|
||||
EXPORT size_t obs_parse_avc_header(uint8_t **header, const uint8_t *data,
|
||||
size_t size);
|
||||
size_t size);
|
||||
EXPORT void obs_extract_avc_headers(const uint8_t *packet, size_t size,
|
||||
uint8_t **new_packet_data, size_t *new_packet_size,
|
||||
uint8_t **header_data, size_t *header_size,
|
||||
uint8_t **sei_data, size_t *sei_size);
|
||||
uint8_t **new_packet_data,
|
||||
size_t *new_packet_size,
|
||||
uint8_t **header_data, size_t *header_size,
|
||||
uint8_t **sei_data, size_t *sei_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
1702
libobs/obs-cocoa.c
1702
libobs/obs-cocoa.c
File diff suppressed because it is too large
Load diff
|
|
@ -27,45 +27,42 @@
|
|||
/*
|
||||
* Increment if major breaking API changes
|
||||
*/
|
||||
#define LIBOBS_API_MAJOR_VER 23
|
||||
#define LIBOBS_API_MAJOR_VER 24
|
||||
|
||||
/*
|
||||
* Increment if backward-compatible additions
|
||||
*
|
||||
* Reset to zero each major version
|
||||
*/
|
||||
#define LIBOBS_API_MINOR_VER 2
|
||||
#define LIBOBS_API_MINOR_VER 0
|
||||
|
||||
/*
|
||||
* Increment if backward-compatible bug fix
|
||||
*
|
||||
* Reset to zero each major or minor version
|
||||
*/
|
||||
#define LIBOBS_API_PATCH_VER 1
|
||||
#define LIBOBS_API_PATCH_VER 1
|
||||
|
||||
#define MAKE_SEMANTIC_VERSION(major, minor, patch) \
|
||||
((major << 24) | \
|
||||
(minor << 16) | \
|
||||
patch )
|
||||
((major << 24) | (minor << 16) | patch)
|
||||
|
||||
#define LIBOBS_API_VER \
|
||||
MAKE_SEMANTIC_VERSION(LIBOBS_API_MAJOR_VER, \
|
||||
LIBOBS_API_MINOR_VER, \
|
||||
LIBOBS_API_PATCH_VER)
|
||||
#define LIBOBS_API_VER \
|
||||
MAKE_SEMANTIC_VERSION(LIBOBS_API_MAJOR_VER, LIBOBS_API_MINOR_VER, \
|
||||
LIBOBS_API_PATCH_VER)
|
||||
|
||||
#ifdef HAVE_OBSCONFIG_H
|
||||
# include "obsconfig.h"
|
||||
#include "obsconfig.h"
|
||||
#else
|
||||
# define OBS_VERSION "unknown"
|
||||
# define OBS_DATA_PATH "../../data"
|
||||
# define OBS_INSTALL_PREFIX ""
|
||||
# define OBS_PLUGIN_DESTINATION "obs-plugins"
|
||||
# define OBS_RELATIVE_PREFIX "../../"
|
||||
# define OBS_RELEASE_CANDIDATE_MAJOR 0
|
||||
# define OBS_RELEASE_CANDIDATE_MINOR 0
|
||||
# define OBS_RELEASE_CANDIDATE_PATCH 0
|
||||
# define OBS_RELEASE_CANDIDATE_VER 0
|
||||
# define OBS_RELEASE_CANDIDATE 0
|
||||
#define OBS_VERSION "unknown"
|
||||
#define OBS_DATA_PATH "../../data"
|
||||
#define OBS_INSTALL_PREFIX ""
|
||||
#define OBS_PLUGIN_DESTINATION "obs-plugins"
|
||||
#define OBS_RELATIVE_PREFIX "../../"
|
||||
#define OBS_RELEASE_CANDIDATE_MAJOR 0
|
||||
#define OBS_RELEASE_CANDIDATE_MINOR 0
|
||||
#define OBS_RELEASE_CANDIDATE_PATCH 0
|
||||
#define OBS_RELEASE_CANDIDATE_VER 0
|
||||
#define OBS_RELEASE_CANDIDATE 0
|
||||
#endif
|
||||
|
||||
#define OBS_INSTALL_DATA_PATH OBS_INSTALL_PREFIX OBS_DATA_PATH
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -39,8 +39,8 @@ struct quat;
|
|||
struct obs_data;
|
||||
struct obs_data_item;
|
||||
struct obs_data_array;
|
||||
typedef struct obs_data obs_data_t;
|
||||
typedef struct obs_data_item obs_data_item_t;
|
||||
typedef struct obs_data obs_data_t;
|
||||
typedef struct obs_data_item obs_data_item_t;
|
||||
typedef struct obs_data_array obs_data_array_t;
|
||||
|
||||
enum obs_data_type {
|
||||
|
|
@ -65,14 +65,15 @@ EXPORT obs_data_t *obs_data_create();
|
|||
EXPORT obs_data_t *obs_data_create_from_json(const char *json_string);
|
||||
EXPORT obs_data_t *obs_data_create_from_json_file(const char *json_file);
|
||||
EXPORT obs_data_t *obs_data_create_from_json_file_safe(const char *json_file,
|
||||
const char *backup_ext);
|
||||
const char *backup_ext);
|
||||
EXPORT void obs_data_addref(obs_data_t *data);
|
||||
EXPORT void obs_data_release(obs_data_t *data);
|
||||
|
||||
EXPORT const char *obs_data_get_json(obs_data_t *data);
|
||||
EXPORT bool obs_data_save_json(obs_data_t *data, const char *file);
|
||||
EXPORT bool obs_data_save_json_safe(obs_data_t *data, const char *file,
|
||||
const char *temp_ext, const char *backup_ext);
|
||||
const char *temp_ext,
|
||||
const char *backup_ext);
|
||||
|
||||
EXPORT void obs_data_apply(obs_data_t *target, obs_data_t *apply_data);
|
||||
|
||||
|
|
@ -81,28 +82,28 @@ EXPORT void obs_data_clear(obs_data_t *data);
|
|||
|
||||
/* Set functions */
|
||||
EXPORT void obs_data_set_string(obs_data_t *data, const char *name,
|
||||
const char *val);
|
||||
EXPORT void obs_data_set_int(obs_data_t *data, const char *name,
|
||||
long long val);
|
||||
const char *val);
|
||||
EXPORT void obs_data_set_int(obs_data_t *data, const char *name, long long val);
|
||||
EXPORT void obs_data_set_double(obs_data_t *data, const char *name, double val);
|
||||
EXPORT void obs_data_set_bool(obs_data_t *data, const char *name, bool val);
|
||||
EXPORT void obs_data_set_obj(obs_data_t *data, const char *name, obs_data_t *obj);
|
||||
EXPORT void obs_data_set_obj(obs_data_t *data, const char *name,
|
||||
obs_data_t *obj);
|
||||
EXPORT void obs_data_set_array(obs_data_t *data, const char *name,
|
||||
obs_data_array_t *array);
|
||||
obs_data_array_t *array);
|
||||
|
||||
/*
|
||||
* Default value functions.
|
||||
*/
|
||||
EXPORT void obs_data_set_default_string(obs_data_t *data, const char *name,
|
||||
const char *val);
|
||||
const char *val);
|
||||
EXPORT void obs_data_set_default_int(obs_data_t *data, const char *name,
|
||||
long long val);
|
||||
long long val);
|
||||
EXPORT void obs_data_set_default_double(obs_data_t *data, const char *name,
|
||||
double val);
|
||||
double val);
|
||||
EXPORT void obs_data_set_default_bool(obs_data_t *data, const char *name,
|
||||
bool val);
|
||||
bool val);
|
||||
EXPORT void obs_data_set_default_obj(obs_data_t *data, const char *name,
|
||||
obs_data_t *obj);
|
||||
obs_data_t *obj);
|
||||
|
||||
/*
|
||||
* Application overrides
|
||||
|
|
@ -110,15 +111,15 @@ EXPORT void obs_data_set_default_obj(obs_data_t *data, const char *name,
|
|||
* settings aren't appropriate
|
||||
*/
|
||||
EXPORT void obs_data_set_autoselect_string(obs_data_t *data, const char *name,
|
||||
const char *val);
|
||||
const char *val);
|
||||
EXPORT void obs_data_set_autoselect_int(obs_data_t *data, const char *name,
|
||||
long long val);
|
||||
long long val);
|
||||
EXPORT void obs_data_set_autoselect_double(obs_data_t *data, const char *name,
|
||||
double val);
|
||||
double val);
|
||||
EXPORT void obs_data_set_autoselect_bool(obs_data_t *data, const char *name,
|
||||
bool val);
|
||||
bool val);
|
||||
EXPORT void obs_data_set_autoselect_obj(obs_data_t *data, const char *name,
|
||||
obs_data_t *obj);
|
||||
obs_data_t *obj);
|
||||
|
||||
/*
|
||||
* Get functions
|
||||
|
|
@ -131,23 +132,25 @@ EXPORT obs_data_t *obs_data_get_obj(obs_data_t *data, const char *name);
|
|||
EXPORT obs_data_array_t *obs_data_get_array(obs_data_t *data, const char *name);
|
||||
|
||||
EXPORT const char *obs_data_get_default_string(obs_data_t *data,
|
||||
const char *name);
|
||||
const char *name);
|
||||
EXPORT long long obs_data_get_default_int(obs_data_t *data, const char *name);
|
||||
EXPORT double obs_data_get_default_double(obs_data_t *data, const char *name);
|
||||
EXPORT bool obs_data_get_default_bool(obs_data_t *data, const char *name);
|
||||
EXPORT obs_data_t *obs_data_get_default_obj(obs_data_t *data, const char *name);
|
||||
EXPORT obs_data_array_t *obs_data_get_default_array(obs_data_t *data,
|
||||
const char *name);
|
||||
const char *name);
|
||||
|
||||
EXPORT const char *obs_data_get_autoselect_string(obs_data_t *data,
|
||||
const char *name);
|
||||
EXPORT long long obs_data_get_autoselect_int(obs_data_t *data, const char *name);
|
||||
EXPORT double obs_data_get_autoselect_double(obs_data_t *data, const char *name);
|
||||
const char *name);
|
||||
EXPORT long long obs_data_get_autoselect_int(obs_data_t *data,
|
||||
const char *name);
|
||||
EXPORT double obs_data_get_autoselect_double(obs_data_t *data,
|
||||
const char *name);
|
||||
EXPORT bool obs_data_get_autoselect_bool(obs_data_t *data, const char *name);
|
||||
EXPORT obs_data_t *obs_data_get_autoselect_obj(obs_data_t *data,
|
||||
const char *name);
|
||||
const char *name);
|
||||
EXPORT obs_data_array_t *obs_data_get_autoselect_array(obs_data_t *data,
|
||||
const char *name);
|
||||
const char *name);
|
||||
|
||||
/* Array functions */
|
||||
EXPORT obs_data_array_t *obs_data_array_create();
|
||||
|
|
@ -156,11 +159,12 @@ EXPORT void obs_data_array_release(obs_data_array_t *array);
|
|||
|
||||
EXPORT size_t obs_data_array_count(obs_data_array_t *array);
|
||||
EXPORT obs_data_t *obs_data_array_item(obs_data_array_t *array, size_t idx);
|
||||
EXPORT size_t obs_data_array_push_back(obs_data_array_t *array, obs_data_t *obj);
|
||||
EXPORT size_t obs_data_array_push_back(obs_data_array_t *array,
|
||||
obs_data_t *obj);
|
||||
EXPORT void obs_data_array_insert(obs_data_array_t *array, size_t idx,
|
||||
obs_data_t *obj);
|
||||
obs_data_t *obj);
|
||||
EXPORT void obs_data_array_push_back_array(obs_data_array_t *array,
|
||||
obs_data_array_t *array2);
|
||||
obs_data_array_t *array2);
|
||||
EXPORT void obs_data_array_erase(obs_data_array_t *array, size_t idx);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
|
@ -189,7 +193,8 @@ EXPORT void obs_data_item_unset_autoselect_value(obs_data_item_t *data);
|
|||
/* Item iteration */
|
||||
|
||||
EXPORT obs_data_item_t *obs_data_first(obs_data_t *data);
|
||||
EXPORT obs_data_item_t *obs_data_item_byname(obs_data_t *data, const char *name);
|
||||
EXPORT obs_data_item_t *obs_data_item_byname(obs_data_t *data,
|
||||
const char *name);
|
||||
EXPORT bool obs_data_item_next(obs_data_item_t **item);
|
||||
EXPORT void obs_data_item_release(obs_data_item_t **item);
|
||||
EXPORT void obs_data_item_remove(obs_data_item_t **item);
|
||||
|
|
@ -206,29 +211,31 @@ EXPORT void obs_data_item_set_double(obs_data_item_t **item, double val);
|
|||
EXPORT void obs_data_item_set_bool(obs_data_item_t **item, bool val);
|
||||
EXPORT void obs_data_item_set_obj(obs_data_item_t **item, obs_data_t *val);
|
||||
EXPORT void obs_data_item_set_array(obs_data_item_t **item,
|
||||
obs_data_array_t *val);
|
||||
obs_data_array_t *val);
|
||||
|
||||
EXPORT void obs_data_item_set_default_string(obs_data_item_t **item,
|
||||
const char *val);
|
||||
EXPORT void obs_data_item_set_default_int(obs_data_item_t **item, long long val);
|
||||
EXPORT void obs_data_item_set_default_double(obs_data_item_t **item, double val);
|
||||
const char *val);
|
||||
EXPORT void obs_data_item_set_default_int(obs_data_item_t **item,
|
||||
long long val);
|
||||
EXPORT void obs_data_item_set_default_double(obs_data_item_t **item,
|
||||
double val);
|
||||
EXPORT void obs_data_item_set_default_bool(obs_data_item_t **item, bool val);
|
||||
EXPORT void obs_data_item_set_default_obj(obs_data_item_t **item,
|
||||
obs_data_t *val);
|
||||
obs_data_t *val);
|
||||
EXPORT void obs_data_item_set_default_array(obs_data_item_t **item,
|
||||
obs_data_array_t *val);
|
||||
obs_data_array_t *val);
|
||||
|
||||
EXPORT void obs_data_item_set_autoselect_string(obs_data_item_t **item,
|
||||
const char *val);
|
||||
const char *val);
|
||||
EXPORT void obs_data_item_set_autoselect_int(obs_data_item_t **item,
|
||||
long long val);
|
||||
long long val);
|
||||
EXPORT void obs_data_item_set_autoselect_double(obs_data_item_t **item,
|
||||
double val);
|
||||
double val);
|
||||
EXPORT void obs_data_item_set_autoselect_bool(obs_data_item_t **item, bool val);
|
||||
EXPORT void obs_data_item_set_autoselect_obj(obs_data_item_t **item,
|
||||
obs_data_t *val);
|
||||
obs_data_t *val);
|
||||
EXPORT void obs_data_item_set_autoselect_array(obs_data_item_t **item,
|
||||
obs_data_array_t *val);
|
||||
obs_data_array_t *val);
|
||||
|
||||
/* Item get functions */
|
||||
EXPORT const char *obs_data_item_get_string(obs_data_item_t *item);
|
||||
|
|
@ -250,106 +257,114 @@ EXPORT long long obs_data_item_get_autoselect_int(obs_data_item_t *item);
|
|||
EXPORT double obs_data_item_get_autoselect_double(obs_data_item_t *item);
|
||||
EXPORT bool obs_data_item_get_autoselect_bool(obs_data_item_t *item);
|
||||
EXPORT obs_data_t *obs_data_item_get_autoselect_obj(obs_data_item_t *item);
|
||||
EXPORT obs_data_array_t *obs_data_item_get_autoselect_array(
|
||||
obs_data_item_t *item);
|
||||
EXPORT obs_data_array_t *
|
||||
obs_data_item_get_autoselect_array(obs_data_item_t *item);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Helper functions for certain structures */
|
||||
EXPORT void obs_data_set_vec2(obs_data_t *data, const char *name,
|
||||
const struct vec2 *val);
|
||||
const struct vec2 *val);
|
||||
EXPORT void obs_data_set_vec3(obs_data_t *data, const char *name,
|
||||
const struct vec3 *val);
|
||||
const struct vec3 *val);
|
||||
EXPORT void obs_data_set_vec4(obs_data_t *data, const char *name,
|
||||
const struct vec4 *val);
|
||||
const struct vec4 *val);
|
||||
EXPORT void obs_data_set_quat(obs_data_t *data, const char *name,
|
||||
const struct quat *val);
|
||||
const struct quat *val);
|
||||
|
||||
EXPORT void obs_data_set_default_vec2(obs_data_t *data, const char *name,
|
||||
const struct vec2 *val);
|
||||
const struct vec2 *val);
|
||||
EXPORT void obs_data_set_default_vec3(obs_data_t *data, const char *name,
|
||||
const struct vec3 *val);
|
||||
const struct vec3 *val);
|
||||
EXPORT void obs_data_set_default_vec4(obs_data_t *data, const char *name,
|
||||
const struct vec4 *val);
|
||||
const struct vec4 *val);
|
||||
EXPORT void obs_data_set_default_quat(obs_data_t *data, const char *name,
|
||||
const struct quat *val);
|
||||
const struct quat *val);
|
||||
|
||||
EXPORT void obs_data_set_autoselect_vec2(obs_data_t *data, const char *name,
|
||||
const struct vec2 *val);
|
||||
const struct vec2 *val);
|
||||
EXPORT void obs_data_set_autoselect_vec3(obs_data_t *data, const char *name,
|
||||
const struct vec3 *val);
|
||||
const struct vec3 *val);
|
||||
EXPORT void obs_data_set_autoselect_vec4(obs_data_t *data, const char *name,
|
||||
const struct vec4 *val);
|
||||
const struct vec4 *val);
|
||||
EXPORT void obs_data_set_autoselect_quat(obs_data_t *data, const char *name,
|
||||
const struct quat *val);
|
||||
const struct quat *val);
|
||||
|
||||
EXPORT void obs_data_get_vec2(obs_data_t *data, const char *name,
|
||||
struct vec2 *val);
|
||||
struct vec2 *val);
|
||||
EXPORT void obs_data_get_vec3(obs_data_t *data, const char *name,
|
||||
struct vec3 *val);
|
||||
struct vec3 *val);
|
||||
EXPORT void obs_data_get_vec4(obs_data_t *data, const char *name,
|
||||
struct vec4 *val);
|
||||
struct vec4 *val);
|
||||
EXPORT void obs_data_get_quat(obs_data_t *data, const char *name,
|
||||
struct quat *val);
|
||||
struct quat *val);
|
||||
|
||||
EXPORT void obs_data_get_default_vec2(obs_data_t *data, const char *name,
|
||||
struct vec2 *val);
|
||||
struct vec2 *val);
|
||||
EXPORT void obs_data_get_default_vec3(obs_data_t *data, const char *name,
|
||||
struct vec3 *val);
|
||||
struct vec3 *val);
|
||||
EXPORT void obs_data_get_default_vec4(obs_data_t *data, const char *name,
|
||||
struct vec4 *val);
|
||||
struct vec4 *val);
|
||||
EXPORT void obs_data_get_default_quat(obs_data_t *data, const char *name,
|
||||
struct quat *val);
|
||||
struct quat *val);
|
||||
|
||||
EXPORT void obs_data_get_autoselect_vec2(obs_data_t *data, const char *name,
|
||||
struct vec2 *val);
|
||||
struct vec2 *val);
|
||||
EXPORT void obs_data_get_autoselect_vec3(obs_data_t *data, const char *name,
|
||||
struct vec3 *val);
|
||||
struct vec3 *val);
|
||||
EXPORT void obs_data_get_autoselect_vec4(obs_data_t *data, const char *name,
|
||||
struct vec4 *val);
|
||||
struct vec4 *val);
|
||||
EXPORT void obs_data_get_autoselect_quat(obs_data_t *data, const char *name,
|
||||
struct quat *val);
|
||||
struct quat *val);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Helper functions for media_frames_per_second/OBS_PROPERTY_FRAME_RATE */
|
||||
EXPORT void obs_data_set_frames_per_second(obs_data_t *data,
|
||||
const char *name,
|
||||
struct media_frames_per_second fps, const char *option);
|
||||
EXPORT void obs_data_set_default_frames_per_second(obs_data_t *data,
|
||||
const char *name,
|
||||
struct media_frames_per_second fps, const char *option);
|
||||
EXPORT void obs_data_set_autoselect_frames_per_second(obs_data_t *data,
|
||||
const char *name,
|
||||
struct media_frames_per_second fps, const char *option);
|
||||
EXPORT void obs_data_set_frames_per_second(obs_data_t *data, const char *name,
|
||||
struct media_frames_per_second fps,
|
||||
const char *option);
|
||||
EXPORT void
|
||||
obs_data_set_default_frames_per_second(obs_data_t *data, const char *name,
|
||||
struct media_frames_per_second fps,
|
||||
const char *option);
|
||||
EXPORT void
|
||||
obs_data_set_autoselect_frames_per_second(obs_data_t *data, const char *name,
|
||||
struct media_frames_per_second fps,
|
||||
const char *option);
|
||||
|
||||
EXPORT bool obs_data_get_frames_per_second(obs_data_t *data,
|
||||
const char *name,
|
||||
struct media_frames_per_second *fps, const char **option);
|
||||
EXPORT bool obs_data_get_default_frames_per_second(obs_data_t *data,
|
||||
const char *name,
|
||||
struct media_frames_per_second *fps, const char **option);
|
||||
EXPORT bool obs_data_get_autoselect_frames_per_second(obs_data_t *data,
|
||||
const char *name,
|
||||
struct media_frames_per_second *fps, const char **option);
|
||||
EXPORT bool obs_data_get_frames_per_second(obs_data_t *data, const char *name,
|
||||
struct media_frames_per_second *fps,
|
||||
const char **option);
|
||||
EXPORT bool
|
||||
obs_data_get_default_frames_per_second(obs_data_t *data, const char *name,
|
||||
struct media_frames_per_second *fps,
|
||||
const char **option);
|
||||
EXPORT bool
|
||||
obs_data_get_autoselect_frames_per_second(obs_data_t *data, const char *name,
|
||||
struct media_frames_per_second *fps,
|
||||
const char **option);
|
||||
|
||||
EXPORT void obs_data_item_set_frames_per_second(
|
||||
obs_data_item_t **item,
|
||||
struct media_frames_per_second fps, const char *option);
|
||||
EXPORT void obs_data_item_set_default_frames_per_second(
|
||||
obs_data_item_t **item,
|
||||
struct media_frames_per_second fps, const char *option);
|
||||
EXPORT void
|
||||
obs_data_item_set_frames_per_second(obs_data_item_t **item,
|
||||
struct media_frames_per_second fps,
|
||||
const char *option);
|
||||
EXPORT void
|
||||
obs_data_item_set_default_frames_per_second(obs_data_item_t **item,
|
||||
struct media_frames_per_second fps,
|
||||
const char *option);
|
||||
EXPORT void obs_data_item_set_autoselect_frames_per_second(
|
||||
obs_data_item_t **item,
|
||||
struct media_frames_per_second fps, const char *option);
|
||||
obs_data_item_t **item, struct media_frames_per_second fps,
|
||||
const char *option);
|
||||
|
||||
EXPORT bool obs_data_item_get_frames_per_second(
|
||||
obs_data_item_t *item,
|
||||
struct media_frames_per_second *fps, const char **option);
|
||||
EXPORT bool obs_data_item_get_default_frames_per_second(
|
||||
obs_data_item_t *item,
|
||||
struct media_frames_per_second *fps, const char **option);
|
||||
EXPORT bool
|
||||
obs_data_item_get_frames_per_second(obs_data_item_t *item,
|
||||
struct media_frames_per_second *fps,
|
||||
const char **option);
|
||||
EXPORT bool
|
||||
obs_data_item_get_default_frames_per_second(obs_data_item_t *item,
|
||||
struct media_frames_per_second *fps,
|
||||
const char **option);
|
||||
EXPORT bool obs_data_item_get_autoselect_frames_per_second(
|
||||
obs_data_item_t *item,
|
||||
struct media_frames_per_second *fps, const char **option);
|
||||
obs_data_item_t *item, struct media_frames_per_second *fps,
|
||||
const char **option);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* OBS-specific functions */
|
||||
|
|
|
|||
|
|
@ -21,30 +21,30 @@
|
|||
#define MAX_CHANNELS 64
|
||||
|
||||
#define OBS_ALIGN_CENTER (0)
|
||||
#define OBS_ALIGN_LEFT (1<<0)
|
||||
#define OBS_ALIGN_RIGHT (1<<1)
|
||||
#define OBS_ALIGN_TOP (1<<2)
|
||||
#define OBS_ALIGN_BOTTOM (1<<3)
|
||||
#define OBS_ALIGN_LEFT (1 << 0)
|
||||
#define OBS_ALIGN_RIGHT (1 << 1)
|
||||
#define OBS_ALIGN_TOP (1 << 2)
|
||||
#define OBS_ALIGN_BOTTOM (1 << 3)
|
||||
|
||||
#define MODULE_SUCCESS 0
|
||||
#define MODULE_ERROR -1
|
||||
#define MODULE_FILE_NOT_FOUND -2
|
||||
#define MODULE_MISSING_EXPORTS -3
|
||||
#define MODULE_INCOMPATIBLE_VER -4
|
||||
#define MODULE_SUCCESS 0
|
||||
#define MODULE_ERROR -1
|
||||
#define MODULE_FILE_NOT_FOUND -2
|
||||
#define MODULE_MISSING_EXPORTS -3
|
||||
#define MODULE_INCOMPATIBLE_VER -4
|
||||
|
||||
#define OBS_OUTPUT_SUCCESS 0
|
||||
#define OBS_OUTPUT_BAD_PATH -1
|
||||
#define OBS_OUTPUT_SUCCESS 0
|
||||
#define OBS_OUTPUT_BAD_PATH -1
|
||||
#define OBS_OUTPUT_CONNECT_FAILED -2
|
||||
#define OBS_OUTPUT_INVALID_STREAM -3
|
||||
#define OBS_OUTPUT_ERROR -4
|
||||
#define OBS_OUTPUT_DISCONNECTED -5
|
||||
#define OBS_OUTPUT_UNSUPPORTED -6
|
||||
#define OBS_OUTPUT_NO_SPACE -7
|
||||
#define OBS_OUTPUT_ENCODE_ERROR -8
|
||||
#define OBS_OUTPUT_ERROR -4
|
||||
#define OBS_OUTPUT_DISCONNECTED -5
|
||||
#define OBS_OUTPUT_UNSUPPORTED -6
|
||||
#define OBS_OUTPUT_NO_SPACE -7
|
||||
#define OBS_OUTPUT_ENCODE_ERROR -8
|
||||
|
||||
#define OBS_VIDEO_SUCCESS 0
|
||||
#define OBS_VIDEO_FAIL -1
|
||||
#define OBS_VIDEO_NOT_SUPPORTED -2
|
||||
#define OBS_VIDEO_INVALID_PARAM -3
|
||||
#define OBS_VIDEO_SUCCESS 0
|
||||
#define OBS_VIDEO_FAIL -1
|
||||
#define OBS_VIDEO_NOT_SUPPORTED -2
|
||||
#define OBS_VIDEO_INVALID_PARAM -3
|
||||
#define OBS_VIDEO_CURRENTLY_ACTIVE -4
|
||||
#define OBS_VIDEO_MODULE_NOT_FOUND -5
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#include "obs-internal.h"
|
||||
|
||||
bool obs_display_init(struct obs_display *display,
|
||||
const struct gs_init_data *graphics_data)
|
||||
const struct gs_init_data *graphics_data)
|
||||
{
|
||||
pthread_mutex_init_value(&display->draw_callbacks_mutex);
|
||||
pthread_mutex_init_value(&display->draw_info_mutex);
|
||||
|
|
@ -29,7 +29,7 @@ bool obs_display_init(struct obs_display *display,
|
|||
display->swap = gs_swapchain_create(graphics_data);
|
||||
if (!display->swap) {
|
||||
blog(LOG_ERROR, "obs_display_init: Failed to "
|
||||
"create swap chain");
|
||||
"create swap chain");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -51,7 +51,7 @@ bool obs_display_init(struct obs_display *display,
|
|||
}
|
||||
|
||||
obs_display_t *obs_display_create(const struct gs_init_data *graphics_data,
|
||||
uint32_t background_color)
|
||||
uint32_t background_color)
|
||||
{
|
||||
struct obs_display *display = bzalloc(sizeof(struct obs_display));
|
||||
|
||||
|
|
@ -64,8 +64,8 @@ obs_display_t *obs_display_create(const struct gs_init_data *graphics_data,
|
|||
display = NULL;
|
||||
} else {
|
||||
pthread_mutex_lock(&obs->data.displays_mutex);
|
||||
display->prev_next = &obs->data.first_display;
|
||||
display->next = obs->data.first_display;
|
||||
display->prev_next = &obs->data.first_display;
|
||||
display->next = obs->data.first_display;
|
||||
obs->data.first_display = display;
|
||||
if (display->next)
|
||||
display->next->prev_next = &display->next;
|
||||
|
|
@ -109,7 +109,8 @@ void obs_display_destroy(obs_display_t *display)
|
|||
|
||||
void obs_display_resize(obs_display_t *display, uint32_t cx, uint32_t cy)
|
||||
{
|
||||
if (!display) return;
|
||||
if (!display)
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&display->draw_info_mutex);
|
||||
|
||||
|
|
@ -121,10 +122,12 @@ void obs_display_resize(obs_display_t *display, uint32_t cx, uint32_t cy)
|
|||
}
|
||||
|
||||
void obs_display_add_draw_callback(obs_display_t *display,
|
||||
void (*draw)(void *param, uint32_t cx, uint32_t cy),
|
||||
void *param)
|
||||
void (*draw)(void *param, uint32_t cx,
|
||||
uint32_t cy),
|
||||
void *param)
|
||||
{
|
||||
if (!display) return;
|
||||
if (!display)
|
||||
return;
|
||||
|
||||
struct draw_callback data = {draw, param};
|
||||
|
||||
|
|
@ -134,10 +137,12 @@ void obs_display_add_draw_callback(obs_display_t *display,
|
|||
}
|
||||
|
||||
void obs_display_remove_draw_callback(obs_display_t *display,
|
||||
void (*draw)(void *param, uint32_t cx, uint32_t cy),
|
||||
void *param)
|
||||
void (*draw)(void *param, uint32_t cx,
|
||||
uint32_t cy),
|
||||
void *param)
|
||||
{
|
||||
if (!display) return;
|
||||
if (!display)
|
||||
return;
|
||||
|
||||
struct draw_callback data = {draw, param};
|
||||
|
||||
|
|
@ -147,7 +152,8 @@ void obs_display_remove_draw_callback(obs_display_t *display,
|
|||
}
|
||||
|
||||
static inline void render_display_begin(struct obs_display *display,
|
||||
uint32_t cx, uint32_t cy, bool size_changed)
|
||||
uint32_t cx, uint32_t cy,
|
||||
bool size_changed)
|
||||
{
|
||||
struct vec4 clear_color;
|
||||
|
||||
|
|
@ -162,7 +168,7 @@ static inline void render_display_begin(struct obs_display *display,
|
|||
clear_color.w = 1.0f;
|
||||
|
||||
gs_clear(GS_CLEAR_COLOR | GS_CLEAR_DEPTH | GS_CLEAR_STENCIL,
|
||||
&clear_color, 1.0f, 0);
|
||||
&clear_color, 1.0f, 0);
|
||||
|
||||
gs_enable_depth_test(false);
|
||||
/* gs_enable_blending(false); */
|
||||
|
|
@ -182,7 +188,8 @@ void render_display(struct obs_display *display)
|
|||
uint32_t cx, cy;
|
||||
bool size_changed;
|
||||
|
||||
if (!display || !display->enabled) return;
|
||||
if (!display || !display->enabled)
|
||||
return;
|
||||
|
||||
GS_DEBUG_MARKER_BEGIN(GS_DEBUG_COLOR_DISPLAY, "obs_display");
|
||||
|
||||
|
|
@ -207,7 +214,7 @@ void render_display(struct obs_display *display)
|
|||
|
||||
for (size_t i = 0; i < display->draw_callbacks.num; i++) {
|
||||
struct draw_callback *callback;
|
||||
callback = display->draw_callbacks.array+i;
|
||||
callback = display->draw_callbacks.array + i;
|
||||
|
||||
callback->draw(callback->param, cx, cy);
|
||||
}
|
||||
|
|
@ -238,8 +245,7 @@ void obs_display_set_background_color(obs_display_t *display, uint32_t color)
|
|||
display->background_color = color;
|
||||
}
|
||||
|
||||
void obs_display_size(obs_display_t *display,
|
||||
uint32_t *width, uint32_t *height)
|
||||
void obs_display_size(obs_display_t *display, uint32_t *width, uint32_t *height)
|
||||
{
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -29,8 +29,9 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define OBS_ENCODER_CAP_DEPRECATED (1<<0)
|
||||
#define OBS_ENCODER_CAP_PASS_TEXTURE (1<<1)
|
||||
#define OBS_ENCODER_CAP_DEPRECATED (1 << 0)
|
||||
#define OBS_ENCODER_CAP_PASS_TEXTURE (1 << 1)
|
||||
#define OBS_ENCODER_CAP_DYN_BITRATE (1 << 2)
|
||||
|
||||
/** Specifies the encoder type */
|
||||
enum obs_encoder_type {
|
||||
|
|
@ -40,27 +41,27 @@ enum obs_encoder_type {
|
|||
|
||||
/** Encoder output packet */
|
||||
struct encoder_packet {
|
||||
uint8_t *data; /**< Packet data */
|
||||
size_t size; /**< Packet size */
|
||||
uint8_t *data; /**< Packet data */
|
||||
size_t size; /**< Packet size */
|
||||
|
||||
int64_t pts; /**< Presentation timestamp */
|
||||
int64_t dts; /**< Decode timestamp */
|
||||
int64_t pts; /**< Presentation timestamp */
|
||||
int64_t dts; /**< Decode timestamp */
|
||||
|
||||
int32_t timebase_num; /**< Timebase numerator */
|
||||
int32_t timebase_den; /**< Timebase denominator */
|
||||
int32_t timebase_num; /**< Timebase numerator */
|
||||
int32_t timebase_den; /**< Timebase denominator */
|
||||
|
||||
enum obs_encoder_type type; /**< Encoder type */
|
||||
enum obs_encoder_type type; /**< Encoder type */
|
||||
|
||||
bool keyframe; /**< Is a keyframe */
|
||||
bool keyframe; /**< Is a keyframe */
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* Internal video variables (will be parsed automatically) */
|
||||
|
||||
/* DTS in microseconds */
|
||||
int64_t dts_usec;
|
||||
int64_t dts_usec;
|
||||
|
||||
/* System DTS in microseconds */
|
||||
int64_t sys_dts_usec;
|
||||
int64_t sys_dts_usec;
|
||||
|
||||
/**
|
||||
* Packet priority
|
||||
|
|
@ -68,7 +69,7 @@ struct encoder_packet {
|
|||
* This is generally use by video encoders to specify the priority
|
||||
* of the packet.
|
||||
*/
|
||||
int priority;
|
||||
int priority;
|
||||
|
||||
/**
|
||||
* Dropped packet priority
|
||||
|
|
@ -76,28 +77,28 @@ struct encoder_packet {
|
|||
* If this packet needs to be dropped, the next packet must be of this
|
||||
* priority or higher to continue transmission.
|
||||
*/
|
||||
int drop_priority;
|
||||
int drop_priority;
|
||||
|
||||
/** Audio track index (used with outputs) */
|
||||
size_t track_idx;
|
||||
size_t track_idx;
|
||||
|
||||
/** Encoder from which the track originated from */
|
||||
obs_encoder_t *encoder;
|
||||
obs_encoder_t *encoder;
|
||||
};
|
||||
|
||||
/** Encoder input frame */
|
||||
struct encoder_frame {
|
||||
/** Data for the frame/audio */
|
||||
uint8_t *data[MAX_AV_PLANES];
|
||||
uint8_t *data[MAX_AV_PLANES];
|
||||
|
||||
/** size of each plane */
|
||||
uint32_t linesize[MAX_AV_PLANES];
|
||||
uint32_t linesize[MAX_AV_PLANES];
|
||||
|
||||
/** Number of frames (audio only) */
|
||||
uint32_t frames;
|
||||
uint32_t frames;
|
||||
|
||||
/** Presentation timestamp */
|
||||
int64_t pts;
|
||||
int64_t pts;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -161,7 +162,7 @@ struct obs_encoder_info {
|
|||
* @return true if successful, false otherwise.
|
||||
*/
|
||||
bool (*encode)(void *data, struct encoder_frame *frame,
|
||||
struct encoder_packet *packet, bool *received_packet);
|
||||
struct encoder_packet *packet, bool *received_packet);
|
||||
|
||||
/** Audio encoder only: Returns the frame size for this encoder */
|
||||
size_t (*get_frame_size)(void *data);
|
||||
|
|
@ -238,6 +239,9 @@ struct obs_encoder_info {
|
|||
|
||||
/**
|
||||
* Gets the default settings for this encoder
|
||||
*
|
||||
* If get_defaults is also defined both will be called, and the first
|
||||
* call will be to get_defaults, then to get_defaults2.
|
||||
*
|
||||
* @param[out] settings Data to assign default settings to
|
||||
* @param[in] typedata Type Data
|
||||
|
|
@ -254,12 +258,13 @@ struct obs_encoder_info {
|
|||
obs_properties_t *(*get_properties2)(void *data, void *type_data);
|
||||
|
||||
bool (*encode_texture)(void *data, uint32_t handle, int64_t pts,
|
||||
uint64_t lock_key, uint64_t *next_key,
|
||||
struct encoder_packet *packet, bool *received_packet);
|
||||
uint64_t lock_key, uint64_t *next_key,
|
||||
struct encoder_packet *packet,
|
||||
bool *received_packet);
|
||||
};
|
||||
|
||||
EXPORT void obs_register_encoder_s(const struct obs_encoder_info *info,
|
||||
size_t size);
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* Register an encoder definition to the current obs context. This should be
|
||||
|
|
|
|||
|
|
@ -6,18 +6,20 @@
|
|||
* a is the major version
|
||||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
#define LIBAVCODEC_VERSION_CHECK( a, b, c, d, e ) \
|
||||
( (LIBAVCODEC_VERSION_MICRO < 100 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT( a, b, c ) ) || \
|
||||
(LIBAVCODEC_VERSION_MICRO >= 100 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT( a, d, e ) ) )
|
||||
#define LIBAVCODEC_VERSION_CHECK(a, b, c, d, e) \
|
||||
((LIBAVCODEC_VERSION_MICRO < 100 && \
|
||||
LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(a, b, c)) || \
|
||||
(LIBAVCODEC_VERSION_MICRO >= 100 && \
|
||||
LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(a, d, e)))
|
||||
|
||||
#if !LIBAVCODEC_VERSION_CHECK(54, 28, 0, 59, 100)
|
||||
# define avcodec_free_frame av_freep
|
||||
#define avcodec_free_frame av_freep
|
||||
#endif
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT < 0x371c01
|
||||
# define av_frame_alloc avcodec_alloc_frame
|
||||
# define av_frame_unref avcodec_get_frame_defaults
|
||||
# define av_frame_free avcodec_free_frame
|
||||
#define av_frame_alloc avcodec_alloc_frame
|
||||
#define av_frame_unref avcodec_get_frame_defaults
|
||||
#define av_frame_free avcodec_free_frame
|
||||
#endif
|
||||
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 58
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ struct obs_hotkey_name_map_edge {
|
|||
struct obs_hotkey_name_map_node *node;
|
||||
};
|
||||
|
||||
|
||||
static inline obs_hotkey_name_map_node_t *new_node(void)
|
||||
{
|
||||
return bzalloc(sizeof(obs_hotkey_name_map_node_t));
|
||||
|
|
@ -88,12 +87,12 @@ static inline obs_hotkey_name_map_node_t *new_leaf(void)
|
|||
|
||||
static inline char *get_prefix(obs_hotkey_name_map_edge_t *e)
|
||||
{
|
||||
return e->prefix_len >= NAME_MAP_COMPRESS_LENGTH ?
|
||||
e->prefix : e->compressed_prefix;
|
||||
return e->prefix_len >= NAME_MAP_COMPRESS_LENGTH ? e->prefix
|
||||
: e->compressed_prefix;
|
||||
}
|
||||
|
||||
static void set_prefix(obs_hotkey_name_map_edge_t *e, const char *prefix,
|
||||
size_t l)
|
||||
size_t l)
|
||||
{
|
||||
assert(e->prefix_len == 0);
|
||||
|
||||
|
|
@ -105,7 +104,7 @@ static void set_prefix(obs_hotkey_name_map_edge_t *e, const char *prefix,
|
|||
}
|
||||
|
||||
static obs_hotkey_name_map_edge_t *add_leaf(obs_hotkey_name_map_node_t *node,
|
||||
const char *key, size_t l, int v)
|
||||
const char *key, size_t l, int v)
|
||||
{
|
||||
obs_hotkey_name_map_edge_t *e = da_push_back_new(node->children);
|
||||
|
||||
|
|
@ -135,19 +134,19 @@ static void shrink_prefix(obs_hotkey_name_map_edge_t *e, size_t l)
|
|||
}
|
||||
|
||||
static void connect(obs_hotkey_name_map_edge_t *e,
|
||||
obs_hotkey_name_map_node_t *n)
|
||||
obs_hotkey_name_map_node_t *n)
|
||||
{
|
||||
e->node = n;
|
||||
}
|
||||
|
||||
static void reduce_edge(obs_hotkey_name_map_edge_t *e, const char *key,
|
||||
size_t l, int v)
|
||||
size_t l, int v)
|
||||
{
|
||||
const char *str = get_prefix(e), *str_ = key;
|
||||
size_t common_length = 0;
|
||||
while (*str == *str_) {
|
||||
common_length += 1;
|
||||
str += 1;
|
||||
str += 1;
|
||||
str_ += 1;
|
||||
}
|
||||
|
||||
|
|
@ -171,8 +170,8 @@ enum obs_hotkey_name_map_edge_compare_result {
|
|||
RES_PREFIX_MATCHES,
|
||||
};
|
||||
|
||||
static enum obs_hotkey_name_map_edge_compare_result compare_prefix(
|
||||
obs_hotkey_name_map_edge_t *edge, const char *key, size_t l)
|
||||
static enum obs_hotkey_name_map_edge_compare_result
|
||||
compare_prefix(obs_hotkey_name_map_edge_t *edge, const char *key, size_t l)
|
||||
{
|
||||
uint8_t pref_len = edge->prefix_len;
|
||||
const char *str = get_prefix(edge);
|
||||
|
|
@ -182,7 +181,6 @@ static enum obs_hotkey_name_map_edge_compare_result compare_prefix(
|
|||
if (str[i] != key[i])
|
||||
break;
|
||||
|
||||
|
||||
if (i != 0 && pref_len == i)
|
||||
return l == i ? RES_MATCHES : RES_PREFIX_MATCHES;
|
||||
if (i != 0)
|
||||
|
|
@ -191,8 +189,8 @@ static enum obs_hotkey_name_map_edge_compare_result compare_prefix(
|
|||
}
|
||||
|
||||
static void insert(obs_hotkey_name_map_edge_t *edge,
|
||||
obs_hotkey_name_map_node_t *node,
|
||||
const char *key, size_t l, int v)
|
||||
obs_hotkey_name_map_node_t *node, const char *key, size_t l,
|
||||
int v)
|
||||
{
|
||||
if (node->is_leaf && l > 0) {
|
||||
obs_hotkey_name_map_node_t *new_node_ = new_node();
|
||||
|
|
@ -220,7 +218,7 @@ static void insert(obs_hotkey_name_map_edge_t *edge,
|
|||
case RES_MATCHES:
|
||||
case RES_PREFIX_MATCHES:
|
||||
insert(e, e->node, key + e->prefix_len,
|
||||
l - e->prefix_len, v);
|
||||
l - e->prefix_len, v);
|
||||
return;
|
||||
|
||||
case RES_COMMON_PREFIX:
|
||||
|
|
@ -233,7 +231,7 @@ static void insert(obs_hotkey_name_map_edge_t *edge,
|
|||
}
|
||||
|
||||
static void obs_hotkey_name_map_insert(obs_hotkey_name_map_t *trie,
|
||||
const char *key, int v)
|
||||
const char *key, int v)
|
||||
{
|
||||
if (!trie || !key)
|
||||
return;
|
||||
|
|
@ -242,7 +240,7 @@ static void obs_hotkey_name_map_insert(obs_hotkey_name_map_t *trie,
|
|||
}
|
||||
|
||||
static bool obs_hotkey_name_map_lookup(obs_hotkey_name_map_t *trie,
|
||||
const char *key, int *v)
|
||||
const char *key, int *v)
|
||||
{
|
||||
if (!trie || !key)
|
||||
return false;
|
||||
|
|
@ -276,14 +274,16 @@ static bool obs_hotkey_name_map_lookup(obs_hotkey_name_map_t *trie,
|
|||
if (n->children.array[j].prefix_len)
|
||||
continue;
|
||||
|
||||
if (v) *v =
|
||||
n->children.array[j].node->val;
|
||||
if (v)
|
||||
*v = n->children.array[j]
|
||||
.node->val;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (v) *v = n->val;
|
||||
if (v)
|
||||
*v = n->val;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -310,7 +310,7 @@ static void show_node(obs_hotkey_name_map_node_t *node, int in)
|
|||
|
||||
obs_hotkey_name_map_edge_t *e = &node->children.array[i];
|
||||
printf("%s", get_prefix(e));
|
||||
show_node(e->node, in+2);
|
||||
show_node(e->node, in + 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -319,17 +319,19 @@ void trie_print_size(obs_hotkey_name_map_t *trie)
|
|||
show_node(&trie->root, 0);
|
||||
}
|
||||
|
||||
static const char* obs_key_names[] = {
|
||||
static const char *obs_key_names[] = {
|
||||
#define OBS_HOTKEY(x) #x,
|
||||
#include "obs-hotkeys.h"
|
||||
#undef OBS_HOTKEY
|
||||
};
|
||||
|
||||
const char* obs_key_to_name(obs_key_t key)
|
||||
const char *obs_key_to_name(obs_key_t key)
|
||||
{
|
||||
if (key >= OBS_KEY_LAST_VALUE) {
|
||||
blog(LOG_ERROR, "obs-hotkey.c: queried unknown key "
|
||||
"with code %d", (int)key);
|
||||
blog(LOG_ERROR,
|
||||
"obs-hotkey.c: queried unknown key "
|
||||
"with code %d",
|
||||
(int)key);
|
||||
return "";
|
||||
}
|
||||
|
||||
|
|
@ -338,7 +340,9 @@ const char* obs_key_to_name(obs_key_t key)
|
|||
|
||||
static obs_key_t obs_key_from_name_fallback(const char *name)
|
||||
{
|
||||
#define OBS_HOTKEY(x) if (strcmp(#x, name) == 0) return x;
|
||||
#define OBS_HOTKEY(x) \
|
||||
if (strcmp(#x, name) == 0) \
|
||||
return x;
|
||||
#include "obs-hotkeys.h"
|
||||
#undef OBS_HOTKEY
|
||||
return OBS_KEY_NONE;
|
||||
|
|
@ -397,7 +401,8 @@ static void free_node(obs_hotkey_name_map_node_t *node, bool release)
|
|||
da_free(node->children);
|
||||
}
|
||||
|
||||
if (release && !node->is_leaf) bfree(node);
|
||||
if (release && !node->is_leaf)
|
||||
bfree(node);
|
||||
}
|
||||
|
||||
void obs_hotkey_name_map_free(void)
|
||||
|
|
|
|||
|
|
@ -63,8 +63,8 @@ obs_hotkey_id obs_hotkey_get_pair_partner_id(const obs_hotkey_t *key)
|
|||
return key->pair_partner_id;
|
||||
}
|
||||
|
||||
obs_key_combination_t obs_hotkey_binding_get_key_combination(
|
||||
obs_hotkey_binding_t *binding)
|
||||
obs_key_combination_t
|
||||
obs_hotkey_binding_get_key_combination(obs_hotkey_binding_t *binding)
|
||||
{
|
||||
return binding->key;
|
||||
}
|
||||
|
|
@ -105,8 +105,8 @@ void obs_hotkey_set_description(obs_hotkey_id id, const char *desc)
|
|||
}
|
||||
|
||||
static inline bool find_pair_id(obs_hotkey_pair_id id, size_t *idx);
|
||||
void obs_hotkey_pair_set_names(obs_hotkey_pair_id id,
|
||||
const char *name0, const char *name1)
|
||||
void obs_hotkey_pair_set_names(obs_hotkey_pair_id id, const char *name0,
|
||||
const char *name1)
|
||||
{
|
||||
size_t idx;
|
||||
obs_hotkey_pair_t pair;
|
||||
|
|
@ -120,8 +120,8 @@ void obs_hotkey_pair_set_names(obs_hotkey_pair_id id,
|
|||
obs_hotkey_set_name(pair.id[1], name1);
|
||||
}
|
||||
|
||||
void obs_hotkey_pair_set_descriptions(obs_hotkey_pair_id id,
|
||||
const char *desc0, const char *desc1)
|
||||
void obs_hotkey_pair_set_descriptions(obs_hotkey_pair_id id, const char *desc0,
|
||||
const char *desc1)
|
||||
{
|
||||
size_t idx;
|
||||
obs_hotkey_pair_t pair;
|
||||
|
|
@ -150,31 +150,31 @@ static inline void fixup_pointers(void);
|
|||
static inline void load_bindings(obs_hotkey_t *hotkey, obs_data_array_t *data);
|
||||
|
||||
static inline void context_add_hotkey(struct obs_context_data *context,
|
||||
obs_hotkey_id id)
|
||||
obs_hotkey_id id)
|
||||
{
|
||||
da_push_back(context->hotkeys, &id);
|
||||
}
|
||||
|
||||
static inline obs_hotkey_id obs_hotkey_register_internal(
|
||||
obs_hotkey_registerer_t type, void *registerer,
|
||||
struct obs_context_data *context,
|
||||
const char *name, const char *description,
|
||||
obs_hotkey_func func, void *data)
|
||||
static inline obs_hotkey_id
|
||||
obs_hotkey_register_internal(obs_hotkey_registerer_t type, void *registerer,
|
||||
struct obs_context_data *context, const char *name,
|
||||
const char *description, obs_hotkey_func func,
|
||||
void *data)
|
||||
{
|
||||
if ((obs->hotkeys.next_id + 1) == OBS_INVALID_HOTKEY_ID)
|
||||
blog(LOG_WARNING, "obs-hotkey: Available hotkey ids exhausted");
|
||||
|
||||
obs_hotkey_t *base_addr = obs->hotkeys.hotkeys.array;
|
||||
obs_hotkey_id result = obs->hotkeys.next_id++;
|
||||
obs_hotkey_t *hotkey = da_push_back_new(obs->hotkeys.hotkeys);
|
||||
obs_hotkey_id result = obs->hotkeys.next_id++;
|
||||
obs_hotkey_t *hotkey = da_push_back_new(obs->hotkeys.hotkeys);
|
||||
|
||||
hotkey->id = result;
|
||||
hotkey->name = bstrdup(name);
|
||||
hotkey->description = bstrdup(description);
|
||||
hotkey->func = func;
|
||||
hotkey->data = data;
|
||||
hotkey->id = result;
|
||||
hotkey->name = bstrdup(name);
|
||||
hotkey->description = bstrdup(description);
|
||||
hotkey->func = func;
|
||||
hotkey->data = data;
|
||||
hotkey->registerer_type = type;
|
||||
hotkey->registerer = registerer;
|
||||
hotkey->registerer = registerer;
|
||||
hotkey->pair_partner_id = OBS_INVALID_HOTKEY_PAIR_ID;
|
||||
|
||||
if (context) {
|
||||
|
|
@ -195,81 +195,81 @@ static inline obs_hotkey_id obs_hotkey_register_internal(
|
|||
}
|
||||
|
||||
obs_hotkey_id obs_hotkey_register_frontend(const char *name,
|
||||
const char *description, obs_hotkey_func func, void *data)
|
||||
const char *description,
|
||||
obs_hotkey_func func, void *data)
|
||||
{
|
||||
if (!lock())
|
||||
return OBS_INVALID_HOTKEY_ID;
|
||||
|
||||
obs_hotkey_id id = obs_hotkey_register_internal(
|
||||
OBS_HOTKEY_REGISTERER_FRONTEND, NULL, NULL,
|
||||
name, description, func, data);
|
||||
obs_hotkey_id id = obs_hotkey_register_internal(
|
||||
OBS_HOTKEY_REGISTERER_FRONTEND, NULL, NULL, name, description,
|
||||
func, data);
|
||||
|
||||
unlock();
|
||||
return id;
|
||||
}
|
||||
|
||||
obs_hotkey_id obs_hotkey_register_encoder(obs_encoder_t *encoder,
|
||||
const char *name, const char *description,
|
||||
obs_hotkey_func func, void *data)
|
||||
const char *name,
|
||||
const char *description,
|
||||
obs_hotkey_func func, void *data)
|
||||
{
|
||||
if (!encoder || !lock())
|
||||
return OBS_INVALID_HOTKEY_ID;
|
||||
|
||||
obs_hotkey_id id = obs_hotkey_register_internal(
|
||||
OBS_HOTKEY_REGISTERER_ENCODER,
|
||||
obs_encoder_get_weak_encoder(encoder),
|
||||
&encoder->context, name, description,
|
||||
func, data);
|
||||
OBS_HOTKEY_REGISTERER_ENCODER,
|
||||
obs_encoder_get_weak_encoder(encoder), &encoder->context, name,
|
||||
description, func, data);
|
||||
|
||||
unlock();
|
||||
return id;
|
||||
}
|
||||
|
||||
obs_hotkey_id obs_hotkey_register_output(obs_output_t *output,
|
||||
const char *name, const char *description,
|
||||
obs_hotkey_func func, void *data)
|
||||
obs_hotkey_id obs_hotkey_register_output(obs_output_t *output, const char *name,
|
||||
const char *description,
|
||||
obs_hotkey_func func, void *data)
|
||||
{
|
||||
if (!output || !lock())
|
||||
return OBS_INVALID_HOTKEY_ID;
|
||||
|
||||
obs_hotkey_id id = obs_hotkey_register_internal(
|
||||
OBS_HOTKEY_REGISTERER_OUTPUT,
|
||||
obs_output_get_weak_output(output),
|
||||
&output->context, name, description,
|
||||
func, data);
|
||||
OBS_HOTKEY_REGISTERER_OUTPUT,
|
||||
obs_output_get_weak_output(output), &output->context, name,
|
||||
description, func, data);
|
||||
|
||||
unlock();
|
||||
return id;
|
||||
}
|
||||
|
||||
obs_hotkey_id obs_hotkey_register_service(obs_service_t *service,
|
||||
const char *name, const char *description,
|
||||
obs_hotkey_func func, void *data)
|
||||
const char *name,
|
||||
const char *description,
|
||||
obs_hotkey_func func, void *data)
|
||||
{
|
||||
if (!service || !lock())
|
||||
return OBS_INVALID_HOTKEY_ID;
|
||||
|
||||
obs_hotkey_id id = obs_hotkey_register_internal(
|
||||
OBS_HOTKEY_REGISTERER_SERVICE,
|
||||
obs_service_get_weak_service(service),
|
||||
&service->context, name, description,
|
||||
func, data);
|
||||
OBS_HOTKEY_REGISTERER_SERVICE,
|
||||
obs_service_get_weak_service(service), &service->context, name,
|
||||
description, func, data);
|
||||
|
||||
unlock();
|
||||
return id;
|
||||
}
|
||||
|
||||
obs_hotkey_id obs_hotkey_register_source(obs_source_t *source, const char *name,
|
||||
const char *description, obs_hotkey_func func, void *data)
|
||||
const char *description,
|
||||
obs_hotkey_func func, void *data)
|
||||
{
|
||||
if (!source || source->context.private || !lock())
|
||||
return OBS_INVALID_HOTKEY_ID;
|
||||
|
||||
obs_hotkey_id id = obs_hotkey_register_internal(
|
||||
OBS_HOTKEY_REGISTERER_SOURCE,
|
||||
obs_source_get_weak_source(source),
|
||||
&source->context, name, description,
|
||||
func, data);
|
||||
OBS_HOTKEY_REGISTERER_SOURCE,
|
||||
obs_source_get_weak_source(source), &source->context, name,
|
||||
description, func, data);
|
||||
|
||||
unlock();
|
||||
return id;
|
||||
|
|
@ -278,16 +278,16 @@ obs_hotkey_id obs_hotkey_register_source(obs_source_t *source, const char *name,
|
|||
static inline void fixup_pair_pointers(void);
|
||||
|
||||
static obs_hotkey_pair_t *create_hotkey_pair(struct obs_context_data *context,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1,
|
||||
void *data0, void *data1)
|
||||
obs_hotkey_active_func func0,
|
||||
obs_hotkey_active_func func1,
|
||||
void *data0, void *data1)
|
||||
{
|
||||
if ((obs->hotkeys.next_pair_id + 1) == OBS_INVALID_HOTKEY_PAIR_ID)
|
||||
blog(LOG_WARNING, "obs-hotkey: Available hotkey pair ids "
|
||||
"exhausted");
|
||||
"exhausted");
|
||||
|
||||
obs_hotkey_pair_t *base_addr = obs->hotkeys.hotkey_pairs.array;
|
||||
obs_hotkey_pair_t *pair =
|
||||
da_push_back_new(obs->hotkeys.hotkey_pairs);
|
||||
obs_hotkey_pair_t *pair = da_push_back_new(obs->hotkeys.hotkey_pairs);
|
||||
|
||||
pair->pair_id = obs->hotkeys.next_pair_id++;
|
||||
pair->func[0] = func0;
|
||||
|
|
@ -306,8 +306,8 @@ static obs_hotkey_pair_t *create_hotkey_pair(struct obs_context_data *context,
|
|||
return pair;
|
||||
}
|
||||
|
||||
static void obs_hotkey_pair_first_func(void *data,
|
||||
obs_hotkey_id id, obs_hotkey_t *hotkey, bool pressed)
|
||||
static void obs_hotkey_pair_first_func(void *data, obs_hotkey_id id,
|
||||
obs_hotkey_t *hotkey, bool pressed)
|
||||
{
|
||||
UNUSED_PARAMETER(id);
|
||||
|
||||
|
|
@ -321,8 +321,8 @@ static void obs_hotkey_pair_first_func(void *data,
|
|||
pair->pressed0 = pressed;
|
||||
}
|
||||
|
||||
static void obs_hotkey_pair_second_func(void *data,
|
||||
obs_hotkey_id id, obs_hotkey_t *hotkey, bool pressed)
|
||||
static void obs_hotkey_pair_second_func(void *data, obs_hotkey_id id,
|
||||
obs_hotkey_t *hotkey, bool pressed)
|
||||
{
|
||||
UNUSED_PARAMETER(id);
|
||||
|
||||
|
|
@ -338,30 +338,28 @@ static void obs_hotkey_pair_second_func(void *data,
|
|||
|
||||
static inline bool find_id(obs_hotkey_id id, size_t *idx);
|
||||
static obs_hotkey_pair_id register_hotkey_pair_internal(
|
||||
obs_hotkey_registerer_t type, void *registerer,
|
||||
void *(*weak_ref)(void*),
|
||||
struct obs_context_data *context,
|
||||
const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1,
|
||||
void *data0, void *data1)
|
||||
obs_hotkey_registerer_t type, void *registerer,
|
||||
void *(*weak_ref)(void *), struct obs_context_data *context,
|
||||
const char *name0, const char *description0, const char *name1,
|
||||
const char *description1, obs_hotkey_active_func func0,
|
||||
obs_hotkey_active_func func1, void *data0, void *data1)
|
||||
{
|
||||
|
||||
if (!lock())
|
||||
return OBS_INVALID_HOTKEY_PAIR_ID;
|
||||
|
||||
obs_hotkey_pair_t *pair = create_hotkey_pair(context,
|
||||
func0, func1, data0, data1);
|
||||
obs_hotkey_pair_t *pair =
|
||||
create_hotkey_pair(context, func0, func1, data0, data1);
|
||||
|
||||
pair->id[0] = obs_hotkey_register_internal(
|
||||
type, weak_ref(registerer), context,
|
||||
name0, description0,
|
||||
obs_hotkey_pair_first_func, pair);
|
||||
pair->id[0] = obs_hotkey_register_internal(type, weak_ref(registerer),
|
||||
context, name0, description0,
|
||||
obs_hotkey_pair_first_func,
|
||||
pair);
|
||||
|
||||
pair->id[1] = obs_hotkey_register_internal(
|
||||
type, weak_ref(registerer), context,
|
||||
name1, description1,
|
||||
obs_hotkey_pair_second_func, pair);
|
||||
pair->id[1] = obs_hotkey_register_internal(type, weak_ref(registerer),
|
||||
context, name1, description1,
|
||||
obs_hotkey_pair_second_func,
|
||||
pair);
|
||||
|
||||
size_t idx;
|
||||
if (find_id(pair->id[0], &idx))
|
||||
|
|
@ -382,15 +380,14 @@ static inline void *obs_id_(void *id_)
|
|||
}
|
||||
|
||||
obs_hotkey_pair_id obs_hotkey_pair_register_frontend(
|
||||
const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1,
|
||||
void *data0, void *data1)
|
||||
const char *name0, const char *description0, const char *name1,
|
||||
const char *description1, obs_hotkey_active_func func0,
|
||||
obs_hotkey_active_func func1, void *data0, void *data1)
|
||||
{
|
||||
return register_hotkey_pair_internal(
|
||||
OBS_HOTKEY_REGISTERER_FRONTEND, NULL, obs_id_, NULL,
|
||||
name0, description0, name1, description1,
|
||||
func0, func1, data0, data1);
|
||||
return register_hotkey_pair_internal(OBS_HOTKEY_REGISTERER_FRONTEND,
|
||||
NULL, obs_id_, NULL, name0,
|
||||
description0, name1, description1,
|
||||
func0, func1, data0, data1);
|
||||
}
|
||||
|
||||
static inline void *weak_encoder_ref(void *ref)
|
||||
|
|
@ -398,19 +395,19 @@ static inline void *weak_encoder_ref(void *ref)
|
|||
return obs_encoder_get_weak_encoder(ref);
|
||||
}
|
||||
|
||||
obs_hotkey_pair_id obs_hotkey_pair_register_encoder(obs_encoder_t *encoder,
|
||||
const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1,
|
||||
void *data0, void *data1)
|
||||
obs_hotkey_pair_id obs_hotkey_pair_register_encoder(
|
||||
obs_encoder_t *encoder, const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1, void *data0,
|
||||
void *data1)
|
||||
{
|
||||
if (!encoder) return OBS_INVALID_HOTKEY_PAIR_ID;
|
||||
return register_hotkey_pair_internal(
|
||||
OBS_HOTKEY_REGISTERER_ENCODER, encoder,
|
||||
weak_encoder_ref,
|
||||
&encoder->context,
|
||||
name0, description0, name1, description1,
|
||||
func0, func1, data0, data1);
|
||||
if (!encoder)
|
||||
return OBS_INVALID_HOTKEY_PAIR_ID;
|
||||
return register_hotkey_pair_internal(OBS_HOTKEY_REGISTERER_ENCODER,
|
||||
encoder, weak_encoder_ref,
|
||||
&encoder->context, name0,
|
||||
description0, name1, description1,
|
||||
func0, func1, data0, data1);
|
||||
}
|
||||
|
||||
static inline void *weak_output_ref(void *ref)
|
||||
|
|
@ -418,19 +415,19 @@ static inline void *weak_output_ref(void *ref)
|
|||
return obs_output_get_weak_output(ref);
|
||||
}
|
||||
|
||||
obs_hotkey_pair_id obs_hotkey_pair_register_output(obs_output_t *output,
|
||||
const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1,
|
||||
void *data0, void *data1)
|
||||
obs_hotkey_pair_id obs_hotkey_pair_register_output(
|
||||
obs_output_t *output, const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1, void *data0,
|
||||
void *data1)
|
||||
{
|
||||
if (!output) return OBS_INVALID_HOTKEY_PAIR_ID;
|
||||
return register_hotkey_pair_internal(
|
||||
OBS_HOTKEY_REGISTERER_OUTPUT, output,
|
||||
weak_output_ref,
|
||||
&output->context,
|
||||
name0, description0, name1, description1,
|
||||
func0, func1, data0, data1);
|
||||
if (!output)
|
||||
return OBS_INVALID_HOTKEY_PAIR_ID;
|
||||
return register_hotkey_pair_internal(OBS_HOTKEY_REGISTERER_OUTPUT,
|
||||
output, weak_output_ref,
|
||||
&output->context, name0,
|
||||
description0, name1, description1,
|
||||
func0, func1, data0, data1);
|
||||
}
|
||||
|
||||
static inline void *weak_service_ref(void *ref)
|
||||
|
|
@ -438,19 +435,19 @@ static inline void *weak_service_ref(void *ref)
|
|||
return obs_service_get_weak_service(ref);
|
||||
}
|
||||
|
||||
obs_hotkey_pair_id obs_hotkey_pair_register_service(obs_service_t *service,
|
||||
const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1,
|
||||
void *data0, void *data1)
|
||||
obs_hotkey_pair_id obs_hotkey_pair_register_service(
|
||||
obs_service_t *service, const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1, void *data0,
|
||||
void *data1)
|
||||
{
|
||||
if (!service) return OBS_INVALID_HOTKEY_PAIR_ID;
|
||||
return register_hotkey_pair_internal(
|
||||
OBS_HOTKEY_REGISTERER_SERVICE, service,
|
||||
weak_service_ref,
|
||||
&service->context,
|
||||
name0, description0, name1, description1,
|
||||
func0, func1, data0, data1);
|
||||
if (!service)
|
||||
return OBS_INVALID_HOTKEY_PAIR_ID;
|
||||
return register_hotkey_pair_internal(OBS_HOTKEY_REGISTERER_SERVICE,
|
||||
service, weak_service_ref,
|
||||
&service->context, name0,
|
||||
description0, name1, description1,
|
||||
func0, func1, data0, data1);
|
||||
}
|
||||
|
||||
static inline void *weak_source_ref(void *ref)
|
||||
|
|
@ -458,27 +455,27 @@ static inline void *weak_source_ref(void *ref)
|
|||
return obs_source_get_weak_source(ref);
|
||||
}
|
||||
|
||||
obs_hotkey_pair_id obs_hotkey_pair_register_source(obs_source_t *source,
|
||||
const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1,
|
||||
void *data0, void *data1)
|
||||
obs_hotkey_pair_id obs_hotkey_pair_register_source(
|
||||
obs_source_t *source, const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1, void *data0,
|
||||
void *data1)
|
||||
{
|
||||
if (!source) return OBS_INVALID_HOTKEY_PAIR_ID;
|
||||
return register_hotkey_pair_internal(
|
||||
OBS_HOTKEY_REGISTERER_SOURCE, source,
|
||||
weak_source_ref,
|
||||
&source->context,
|
||||
name0, description0, name1, description1,
|
||||
func0, func1, data0, data1);
|
||||
if (!source)
|
||||
return OBS_INVALID_HOTKEY_PAIR_ID;
|
||||
return register_hotkey_pair_internal(OBS_HOTKEY_REGISTERER_SOURCE,
|
||||
source, weak_source_ref,
|
||||
&source->context, name0,
|
||||
description0, name1, description1,
|
||||
func0, func1, data0, data1);
|
||||
}
|
||||
|
||||
typedef bool (*obs_hotkey_internal_enum_func)(void *data,
|
||||
size_t idx, obs_hotkey_t *hotkey);
|
||||
typedef bool (*obs_hotkey_internal_enum_func)(void *data, size_t idx,
|
||||
obs_hotkey_t *hotkey);
|
||||
|
||||
static inline void enum_hotkeys(obs_hotkey_internal_enum_func func, void *data)
|
||||
{
|
||||
const size_t num = obs->hotkeys.hotkeys.num;
|
||||
const size_t num = obs->hotkeys.hotkeys.num;
|
||||
obs_hotkey_t *array = obs->hotkeys.hotkeys.array;
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
if (!func(data, i, &array[i]))
|
||||
|
|
@ -487,12 +484,13 @@ static inline void enum_hotkeys(obs_hotkey_internal_enum_func func, void *data)
|
|||
}
|
||||
|
||||
typedef bool (*obs_hotkey_pair_internal_enum_func)(size_t idx,
|
||||
obs_hotkey_pair_t *pair, void *data);
|
||||
obs_hotkey_pair_t *pair,
|
||||
void *data);
|
||||
|
||||
static inline void enum_hotkey_pairs(obs_hotkey_pair_internal_enum_func func,
|
||||
void *data)
|
||||
void *data)
|
||||
{
|
||||
const size_t num = obs->hotkeys.hotkey_pairs.num;
|
||||
const size_t num = obs->hotkeys.hotkey_pairs.num;
|
||||
obs_hotkey_pair_t *array = obs->hotkeys.hotkey_pairs.array;
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
if (!func(i, &array[i], data))
|
||||
|
|
@ -500,13 +498,13 @@ static inline void enum_hotkey_pairs(obs_hotkey_pair_internal_enum_func func,
|
|||
}
|
||||
}
|
||||
|
||||
typedef bool (*obs_hotkey_binding_internal_enum_func)(void *data,
|
||||
size_t idx, obs_hotkey_binding_t *binding);
|
||||
typedef bool (*obs_hotkey_binding_internal_enum_func)(
|
||||
void *data, size_t idx, obs_hotkey_binding_t *binding);
|
||||
|
||||
static inline void enum_bindings(obs_hotkey_binding_internal_enum_func func,
|
||||
void *data)
|
||||
void *data)
|
||||
{
|
||||
const size_t num = obs->hotkeys.bindings.num;
|
||||
const size_t num = obs->hotkeys.bindings.num;
|
||||
obs_hotkey_binding_t *array = obs->hotkeys.bindings.array;
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
if (!func(data, i, &array[i]))
|
||||
|
|
@ -516,8 +514,8 @@ static inline void enum_bindings(obs_hotkey_binding_internal_enum_func func,
|
|||
|
||||
struct obs_hotkey_internal_find_forward {
|
||||
obs_hotkey_id id;
|
||||
bool found;
|
||||
size_t idx;
|
||||
bool found;
|
||||
size_t idx;
|
||||
};
|
||||
|
||||
static inline bool find_id_helper(void *data, size_t idx, obs_hotkey_t *hotkey)
|
||||
|
|
@ -526,7 +524,7 @@ static inline bool find_id_helper(void *data, size_t idx, obs_hotkey_t *hotkey)
|
|||
if (hotkey->id != find->id)
|
||||
return true;
|
||||
|
||||
find->idx = idx;
|
||||
find->idx = idx;
|
||||
find->found = true;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -539,8 +537,8 @@ static inline bool find_id(obs_hotkey_id id, size_t *idx)
|
|||
return find.found;
|
||||
}
|
||||
|
||||
static inline bool pointer_fixup_func(void *data,
|
||||
size_t idx, obs_hotkey_binding_t *binding)
|
||||
static inline bool pointer_fixup_func(void *data, size_t idx,
|
||||
obs_hotkey_binding_t *binding)
|
||||
{
|
||||
UNUSED_PARAMETER(idx);
|
||||
UNUSED_PARAMETER(data);
|
||||
|
|
@ -548,10 +546,10 @@ static inline bool pointer_fixup_func(void *data,
|
|||
size_t idx_;
|
||||
if (!find_id(binding->hotkey_id, &idx_)) {
|
||||
bcrash("obs-hotkey: Could not find hotkey id '%" PRIuMAX "' "
|
||||
"for binding '%s' (modifiers 0x%x)",
|
||||
(uintmax_t)binding->hotkey_id,
|
||||
obs_key_to_name(binding->key.key),
|
||||
binding->key.modifiers);
|
||||
"for binding '%s' (modifiers 0x%x)",
|
||||
(uintmax_t)binding->hotkey_id,
|
||||
obs_key_to_name(binding->key.key),
|
||||
binding->key.modifiers);
|
||||
binding->hotkey = NULL;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -568,18 +566,18 @@ static inline void fixup_pointers(void)
|
|||
|
||||
struct obs_hotkey_internal_find_pair_forward {
|
||||
obs_hotkey_pair_id id;
|
||||
bool found;
|
||||
size_t idx;
|
||||
bool found;
|
||||
size_t idx;
|
||||
};
|
||||
|
||||
static inline bool find_pair_id_helper(size_t idx, obs_hotkey_pair_t *pair,
|
||||
void *data)
|
||||
void *data)
|
||||
{
|
||||
struct obs_hotkey_internal_find_pair_forward *find = data;
|
||||
if (pair->pair_id != find->id)
|
||||
return true;
|
||||
|
||||
find->idx = idx;
|
||||
find->idx = idx;
|
||||
find->found = true;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -592,8 +590,8 @@ static inline bool find_pair_id(obs_hotkey_pair_id id, size_t *idx)
|
|||
return find.found;
|
||||
}
|
||||
|
||||
static inline bool pair_pointer_fixup_func(size_t idx,
|
||||
obs_hotkey_pair_t *pair, void *data)
|
||||
static inline bool pair_pointer_fixup_func(size_t idx, obs_hotkey_pair_t *pair,
|
||||
void *data)
|
||||
{
|
||||
UNUSED_PARAMETER(idx);
|
||||
UNUSED_PARAMETER(data);
|
||||
|
|
@ -613,9 +611,10 @@ static inline void fixup_pair_pointers(void)
|
|||
}
|
||||
|
||||
static inline void enum_context_hotkeys(struct obs_context_data *context,
|
||||
obs_hotkey_internal_enum_func func, void *data)
|
||||
obs_hotkey_internal_enum_func func,
|
||||
void *data)
|
||||
{
|
||||
const size_t num = context->hotkeys.num;
|
||||
const size_t num = context->hotkeys.num;
|
||||
const obs_hotkey_id *array = context->hotkeys.array;
|
||||
obs_hotkey_t *hotkey_array = obs->hotkeys.hotkeys.array;
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
|
|
@ -629,14 +628,14 @@ static inline void enum_context_hotkeys(struct obs_context_data *context,
|
|||
}
|
||||
|
||||
static inline void load_modifier(uint32_t *modifiers, obs_data_t *data,
|
||||
const char *name, uint32_t flag)
|
||||
const char *name, uint32_t flag)
|
||||
{
|
||||
if (obs_data_get_bool(data, name))
|
||||
*modifiers |= flag;
|
||||
}
|
||||
|
||||
static inline void create_binding(obs_hotkey_t *hotkey,
|
||||
obs_key_combination_t combo)
|
||||
obs_key_combination_t combo)
|
||||
{
|
||||
obs_hotkey_binding_t *binding = da_push_back_new(obs->hotkeys.bindings);
|
||||
if (!binding)
|
||||
|
|
@ -644,7 +643,7 @@ static inline void create_binding(obs_hotkey_t *hotkey,
|
|||
|
||||
binding->key = combo;
|
||||
binding->hotkey_id = hotkey->id;
|
||||
binding->hotkey = hotkey;
|
||||
binding->hotkey = hotkey;
|
||||
}
|
||||
|
||||
static inline void load_binding(obs_hotkey_t *hotkey, obs_data_t *data)
|
||||
|
|
@ -660,8 +659,8 @@ static inline void load_binding(obs_hotkey_t *hotkey, obs_data_t *data)
|
|||
load_modifier(modifiers, data, "command", INTERACT_COMMAND_KEY);
|
||||
|
||||
combo.key = obs_key_from_name(obs_data_get_string(data, "key"));
|
||||
if (!modifiers && (combo.key == OBS_KEY_NONE ||
|
||||
combo.key >= OBS_KEY_LAST_VALUE))
|
||||
if (!modifiers &&
|
||||
(combo.key == OBS_KEY_NONE || combo.key >= OBS_KEY_LAST_VALUE))
|
||||
return;
|
||||
|
||||
create_binding(hotkey, combo);
|
||||
|
|
@ -682,7 +681,7 @@ static inline void load_bindings(obs_hotkey_t *hotkey, obs_data_array_t *data)
|
|||
static inline void remove_bindings(obs_hotkey_id id);
|
||||
|
||||
void obs_hotkey_load_bindings(obs_hotkey_id id,
|
||||
obs_key_combination_t *combinations, size_t num)
|
||||
obs_key_combination_t *combinations, size_t num)
|
||||
{
|
||||
size_t idx;
|
||||
|
||||
|
|
@ -714,8 +713,8 @@ void obs_hotkey_load(obs_hotkey_id id, obs_data_array_t *data)
|
|||
unlock();
|
||||
}
|
||||
|
||||
static inline bool enum_load_bindings(void *data,
|
||||
size_t idx, obs_hotkey_t *hotkey)
|
||||
static inline bool enum_load_bindings(void *data, size_t idx,
|
||||
obs_hotkey_t *hotkey)
|
||||
{
|
||||
UNUSED_PARAMETER(idx);
|
||||
|
||||
|
|
@ -773,7 +772,7 @@ void obs_hotkeys_load_source(obs_source_t *source, obs_data_t *hotkeys)
|
|||
}
|
||||
|
||||
void obs_hotkey_pair_load(obs_hotkey_pair_id id, obs_data_array_t *data0,
|
||||
obs_data_array_t *data1)
|
||||
obs_data_array_t *data1)
|
||||
{
|
||||
if ((!data0 && !data1) || !lock())
|
||||
return;
|
||||
|
|
@ -798,7 +797,7 @@ unlock:
|
|||
}
|
||||
|
||||
static inline void save_modifier(uint32_t modifiers, obs_data_t *data,
|
||||
const char *name, uint32_t flag)
|
||||
const char *name, uint32_t flag)
|
||||
{
|
||||
if ((modifiers & flag) == flag)
|
||||
obs_data_set_bool(data, name, true);
|
||||
|
|
@ -806,11 +805,11 @@ static inline void save_modifier(uint32_t modifiers, obs_data_t *data,
|
|||
|
||||
struct save_bindings_helper_t {
|
||||
obs_data_array_t *array;
|
||||
obs_hotkey_t *hotkey;
|
||||
obs_hotkey_t *hotkey;
|
||||
};
|
||||
|
||||
static inline bool save_bindings_helper(void *data,
|
||||
size_t idx, obs_hotkey_binding_t *binding)
|
||||
static inline bool save_bindings_helper(void *data, size_t idx,
|
||||
obs_hotkey_binding_t *binding)
|
||||
{
|
||||
UNUSED_PARAMETER(idx);
|
||||
struct save_bindings_helper_t *h = data;
|
||||
|
|
@ -860,9 +859,8 @@ obs_data_array_t *obs_hotkey_save(obs_hotkey_id id)
|
|||
return result;
|
||||
}
|
||||
|
||||
void obs_hotkey_pair_save(obs_hotkey_pair_id id,
|
||||
obs_data_array_t **p_data0,
|
||||
obs_data_array_t **p_data1)
|
||||
void obs_hotkey_pair_save(obs_hotkey_pair_id id, obs_data_array_t **p_data0,
|
||||
obs_data_array_t **p_data1)
|
||||
{
|
||||
if ((!p_data0 && !p_data1) || !lock())
|
||||
return;
|
||||
|
|
@ -884,8 +882,8 @@ unlock:
|
|||
unlock();
|
||||
}
|
||||
|
||||
static inline bool enum_save_hotkey(void *data,
|
||||
size_t idx, obs_hotkey_t *hotkey)
|
||||
static inline bool enum_save_hotkey(void *data, size_t idx,
|
||||
obs_hotkey_t *hotkey)
|
||||
{
|
||||
UNUSED_PARAMETER(idx);
|
||||
|
||||
|
|
@ -963,14 +961,14 @@ struct binding_find_data {
|
|||
bool found;
|
||||
};
|
||||
|
||||
static inline bool binding_finder(void *data,
|
||||
size_t idx, obs_hotkey_binding_t *binding)
|
||||
static inline bool binding_finder(void *data, size_t idx,
|
||||
obs_hotkey_binding_t *binding)
|
||||
{
|
||||
struct binding_find_data *find = data;
|
||||
if (binding->hotkey_id != find->id)
|
||||
return true;
|
||||
|
||||
*find->idx = idx;
|
||||
*find->idx = idx;
|
||||
find->found = true;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1099,7 +1097,7 @@ static void context_release_hotkeys(struct obs_context_data *context)
|
|||
bool need_fixup = false;
|
||||
for (size_t i = 0; i < context->hotkeys.num; i++)
|
||||
need_fixup = unregister_hotkey(context->hotkeys.array[i]) ||
|
||||
need_fixup;
|
||||
need_fixup;
|
||||
|
||||
if (need_fixup)
|
||||
fixup_pointers();
|
||||
|
|
@ -1115,9 +1113,9 @@ static void context_release_hotkey_pairs(struct obs_context_data *context)
|
|||
|
||||
bool need_fixup = false;
|
||||
for (size_t i = 0; i < context->hotkey_pairs.num; i++)
|
||||
need_fixup =
|
||||
unregister_hotkey_pair(context->hotkey_pairs.array[i])
|
||||
|| need_fixup;
|
||||
need_fixup = unregister_hotkey_pair(
|
||||
context->hotkey_pairs.array[i]) ||
|
||||
need_fixup;
|
||||
|
||||
if (need_fixup)
|
||||
fixup_pair_pointers();
|
||||
|
|
@ -1140,7 +1138,7 @@ void obs_hotkeys_context_release(struct obs_context_data *context)
|
|||
|
||||
void obs_hotkeys_free(void)
|
||||
{
|
||||
const size_t num = obs->hotkeys.hotkeys.num;
|
||||
const size_t num = obs->hotkeys.hotkeys.num;
|
||||
obs_hotkey_t *hotkeys = obs->hotkeys.hotkeys.array;
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
bfree(hotkeys[i].name);
|
||||
|
|
@ -1162,7 +1160,7 @@ void obs_hotkeys_free(void)
|
|||
|
||||
struct obs_hotkey_internal_enum_forward {
|
||||
obs_hotkey_enum_func func;
|
||||
void *data;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static inline bool enum_hotkey(void *data, size_t idx, obs_hotkey_t *hotkey)
|
||||
|
|
@ -1193,18 +1191,18 @@ void obs_enum_hotkey_bindings(obs_hotkey_binding_enum_func func, void *data)
|
|||
}
|
||||
|
||||
static inline bool modifiers_match(obs_hotkey_binding_t *binding,
|
||||
uint32_t modifiers_, bool strict_modifiers)
|
||||
uint32_t modifiers_, bool strict_modifiers)
|
||||
{
|
||||
uint32_t modifiers = binding->key.modifiers;
|
||||
return !modifiers ||
|
||||
(!strict_modifiers && (modifiers & modifiers_) == modifiers) ||
|
||||
(strict_modifiers && modifiers == modifiers_);
|
||||
(!strict_modifiers && (modifiers & modifiers_) == modifiers) ||
|
||||
(strict_modifiers && modifiers == modifiers_);
|
||||
}
|
||||
|
||||
static inline bool is_pressed(obs_key_t key)
|
||||
{
|
||||
return obs_hotkeys_platform_is_pressed(obs->hotkeys.platform_context,
|
||||
key);
|
||||
key);
|
||||
}
|
||||
|
||||
static inline void press_released_binding(obs_hotkey_binding_t *binding)
|
||||
|
|
@ -1219,7 +1217,7 @@ static inline void press_released_binding(obs_hotkey_binding_t *binding)
|
|||
hotkey->func(hotkey->data, hotkey->id, hotkey, true);
|
||||
else if (obs->hotkeys.router_func)
|
||||
obs->hotkeys.router_func(obs->hotkeys.router_func_data,
|
||||
hotkey->id, true);
|
||||
hotkey->id, true);
|
||||
}
|
||||
|
||||
static inline void release_pressed_binding(obs_hotkey_binding_t *binding)
|
||||
|
|
@ -1234,16 +1232,16 @@ static inline void release_pressed_binding(obs_hotkey_binding_t *binding)
|
|||
hotkey->func(hotkey->data, hotkey->id, hotkey, false);
|
||||
else if (obs->hotkeys.router_func)
|
||||
obs->hotkeys.router_func(obs->hotkeys.router_func_data,
|
||||
hotkey->id, false);
|
||||
hotkey->id, false);
|
||||
}
|
||||
|
||||
static inline void handle_binding(obs_hotkey_binding_t *binding,
|
||||
uint32_t modifiers, bool no_press, bool strict_modifiers,
|
||||
bool *pressed)
|
||||
uint32_t modifiers, bool no_press,
|
||||
bool strict_modifiers, bool *pressed)
|
||||
{
|
||||
bool modifiers_match_ = modifiers_match(binding, modifiers,
|
||||
strict_modifiers);
|
||||
bool modifiers_only = binding->key.key == OBS_KEY_NONE;
|
||||
bool modifiers_match_ =
|
||||
modifiers_match(binding, modifiers, strict_modifiers);
|
||||
bool modifiers_only = binding->key.key == OBS_KEY_NONE;
|
||||
|
||||
if (!binding->key.modifiers)
|
||||
binding->modifiers_match = true;
|
||||
|
|
@ -1258,7 +1256,7 @@ static inline void handle_binding(obs_hotkey_binding_t *binding,
|
|||
goto reset;
|
||||
|
||||
if ((pressed && !*pressed) ||
|
||||
(!pressed && !is_pressed(binding->key.key)))
|
||||
(!pressed && !is_pressed(binding->key.key)))
|
||||
goto reset;
|
||||
|
||||
if (binding->pressed || no_press)
|
||||
|
|
@ -1277,22 +1275,22 @@ reset:
|
|||
|
||||
struct obs_hotkey_internal_inject {
|
||||
obs_key_combination_t hotkey;
|
||||
bool pressed;
|
||||
bool strict_modifiers;
|
||||
bool pressed;
|
||||
bool strict_modifiers;
|
||||
};
|
||||
|
||||
static inline bool inject_hotkey(void *data,
|
||||
size_t idx, obs_hotkey_binding_t *binding)
|
||||
static inline bool inject_hotkey(void *data, size_t idx,
|
||||
obs_hotkey_binding_t *binding)
|
||||
{
|
||||
UNUSED_PARAMETER(idx);
|
||||
struct obs_hotkey_internal_inject *event = data;
|
||||
|
||||
if (modifiers_match(binding, event->hotkey.modifiers,
|
||||
event->strict_modifiers)) {
|
||||
event->strict_modifiers)) {
|
||||
bool pressed = binding->key.key == event->hotkey.key &&
|
||||
event->pressed;
|
||||
event->pressed;
|
||||
handle_binding(binding, event->hotkey.modifiers, false,
|
||||
event->strict_modifiers, &pressed);
|
||||
event->strict_modifiers, &pressed);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -1305,7 +1303,8 @@ void obs_hotkey_inject_event(obs_key_combination_t hotkey, bool pressed)
|
|||
|
||||
struct obs_hotkey_internal_inject event = {
|
||||
{hotkey.modifiers, hotkey.key},
|
||||
pressed, obs->hotkeys.strict_modifiers,
|
||||
pressed,
|
||||
obs->hotkeys.strict_modifiers,
|
||||
};
|
||||
enum_bindings(inject_hotkey, &event);
|
||||
unlock();
|
||||
|
|
@ -1331,19 +1330,19 @@ void obs_hotkey_enable_strict_modifiers(bool enable)
|
|||
|
||||
struct obs_query_hotkeys_helper {
|
||||
uint32_t modifiers;
|
||||
bool no_press;
|
||||
bool strict_modifiers;
|
||||
bool no_press;
|
||||
bool strict_modifiers;
|
||||
};
|
||||
|
||||
static inline bool query_hotkey(void *data,
|
||||
size_t idx, obs_hotkey_binding_t *binding)
|
||||
static inline bool query_hotkey(void *data, size_t idx,
|
||||
obs_hotkey_binding_t *binding)
|
||||
{
|
||||
UNUSED_PARAMETER(idx);
|
||||
|
||||
struct obs_query_hotkeys_helper *param =
|
||||
(struct obs_query_hotkeys_helper*)data;
|
||||
(struct obs_query_hotkeys_helper *)data;
|
||||
handle_binding(binding, param->modifiers, param->no_press,
|
||||
param->strict_modifiers, NULL);
|
||||
param->strict_modifiers, NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1376,7 +1375,7 @@ void *obs_hotkey_thread(void *arg)
|
|||
|
||||
const char *hotkey_thread_name =
|
||||
profile_store_name(obs_get_profiler_name_store(),
|
||||
"obs_hotkey_thread(%g"NBSP"ms)", 25.);
|
||||
"obs_hotkey_thread(%g" NBSP "ms)", 25.);
|
||||
profile_register_root(hotkey_thread_name, (uint64_t)25000000);
|
||||
|
||||
while (os_event_timedwait(obs->hotkeys.stop_event, 25) == ETIMEDOUT) {
|
||||
|
|
@ -1414,7 +1413,7 @@ unlock:
|
|||
}
|
||||
|
||||
void obs_hotkey_set_callback_routing_func(obs_hotkey_callback_router_func func,
|
||||
void *data)
|
||||
void *data)
|
||||
{
|
||||
if (!lock())
|
||||
return;
|
||||
|
|
@ -1443,10 +1442,10 @@ static void obs_set_key_translation(obs_key_t key, const char *translation)
|
|||
}
|
||||
|
||||
void obs_hotkeys_set_translations_s(
|
||||
struct obs_hotkeys_translations *translations, size_t size)
|
||||
struct obs_hotkeys_translations *translations, size_t size)
|
||||
{
|
||||
#define ADD_TRANSLATION(key_name, var_name) \
|
||||
if (t.var_name) \
|
||||
if (t.var_name) \
|
||||
obs_set_key_translation(key_name, t.var_name);
|
||||
|
||||
struct obs_hotkeys_translations t = {0};
|
||||
|
|
@ -1505,10 +1504,10 @@ void obs_hotkeys_set_translations_s(
|
|||
dstr_cat(&numpad, " %1");
|
||||
}
|
||||
|
||||
#define ADD_NUMPAD_NUM(idx) \
|
||||
dstr_copy_dstr(&button, &numpad); \
|
||||
dstr_replace(&button, "%1", #idx); \
|
||||
obs_set_key_translation(OBS_KEY_NUM ## idx, button.array)
|
||||
#define ADD_NUMPAD_NUM(idx) \
|
||||
dstr_copy_dstr(&button, &numpad); \
|
||||
dstr_replace(&button, "%1", #idx); \
|
||||
obs_set_key_translation(OBS_KEY_NUM##idx, button.array)
|
||||
|
||||
ADD_NUMPAD_NUM(0);
|
||||
ADD_NUMPAD_NUM(1);
|
||||
|
|
@ -1530,10 +1529,10 @@ void obs_hotkeys_set_translations_s(
|
|||
dstr_cat(&mouse, " %1");
|
||||
}
|
||||
|
||||
#define ADD_MOUSE_NUM(idx) \
|
||||
dstr_copy_dstr(&button, &mouse); \
|
||||
dstr_replace(&button, "%1", #idx); \
|
||||
obs_set_key_translation(OBS_KEY_MOUSE ## idx, button.array)
|
||||
#define ADD_MOUSE_NUM(idx) \
|
||||
dstr_copy_dstr(&button, &mouse); \
|
||||
dstr_replace(&button, "%1", #idx); \
|
||||
obs_set_key_translation(OBS_KEY_MOUSE##idx, button.array)
|
||||
|
||||
ADD_MOUSE_NUM(1);
|
||||
ADD_MOUSE_NUM(2);
|
||||
|
|
@ -1577,24 +1576,28 @@ const char *obs_get_hotkey_translation(obs_key_t key, const char *def)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return obs->hotkeys.translations[key] ?
|
||||
obs->hotkeys.translations[key] : def;
|
||||
return obs->hotkeys.translations[key] ? obs->hotkeys.translations[key]
|
||||
: def;
|
||||
}
|
||||
|
||||
void obs_hotkey_update_atomic(obs_hotkey_atomic_update_func func, void *data)
|
||||
{
|
||||
if (!lock()) return;
|
||||
if (!lock())
|
||||
return;
|
||||
|
||||
func(data);
|
||||
|
||||
unlock();
|
||||
}
|
||||
|
||||
void obs_hotkeys_set_audio_hotkeys_translations(
|
||||
const char *mute, const char *unmute,
|
||||
const char *push_to_mute, const char *push_to_talk)
|
||||
void obs_hotkeys_set_audio_hotkeys_translations(const char *mute,
|
||||
const char *unmute,
|
||||
const char *push_to_mute,
|
||||
const char *push_to_talk)
|
||||
{
|
||||
#define SET_T(n) bfree(obs->hotkeys.n); obs->hotkeys.n = bstrdup(n)
|
||||
#define SET_T(n) \
|
||||
bfree(obs->hotkeys.n); \
|
||||
obs->hotkeys.n = bstrdup(n)
|
||||
SET_T(mute);
|
||||
SET_T(unmute);
|
||||
SET_T(push_to_mute);
|
||||
|
|
@ -1602,10 +1605,11 @@ void obs_hotkeys_set_audio_hotkeys_translations(
|
|||
#undef SET_T
|
||||
}
|
||||
|
||||
void obs_hotkeys_set_sceneitem_hotkeys_translations(
|
||||
const char *show, const char *hide)
|
||||
void obs_hotkeys_set_sceneitem_hotkeys_translations(const char *show,
|
||||
const char *hide)
|
||||
{
|
||||
#define SET_T(n) bfree(obs->hotkeys.sceneitem_##n); \
|
||||
#define SET_T(n) \
|
||||
bfree(obs->hotkeys.sceneitem_##n); \
|
||||
obs->hotkeys.sceneitem_##n = bstrdup(n)
|
||||
SET_T(show);
|
||||
SET_T(hide);
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ enum obs_key {
|
|||
typedef enum obs_key obs_key_t;
|
||||
|
||||
struct obs_key_combination {
|
||||
uint32_t modifiers;
|
||||
uint32_t modifiers;
|
||||
obs_key_t key;
|
||||
};
|
||||
typedef struct obs_key_combination obs_key_combination_t;
|
||||
|
|
@ -65,27 +65,27 @@ typedef enum obs_hotkey_registerer_type obs_hotkey_registerer_t;
|
|||
EXPORT obs_hotkey_id obs_hotkey_get_id(const obs_hotkey_t *key);
|
||||
EXPORT const char *obs_hotkey_get_name(const obs_hotkey_t *key);
|
||||
EXPORT const char *obs_hotkey_get_description(const obs_hotkey_t *key);
|
||||
EXPORT obs_hotkey_registerer_t obs_hotkey_get_registerer_type(
|
||||
const obs_hotkey_t *key);
|
||||
EXPORT obs_hotkey_registerer_t
|
||||
obs_hotkey_get_registerer_type(const obs_hotkey_t *key);
|
||||
EXPORT void *obs_hotkey_get_registerer(const obs_hotkey_t *key);
|
||||
EXPORT obs_hotkey_id obs_hotkey_get_pair_partner_id(const obs_hotkey_t *key);
|
||||
|
||||
|
||||
EXPORT obs_key_combination_t obs_hotkey_binding_get_key_combination(
|
||||
obs_hotkey_binding_t *binding);
|
||||
EXPORT obs_hotkey_id obs_hotkey_binding_get_hotkey_id(
|
||||
obs_hotkey_binding_t *binding);
|
||||
EXPORT obs_hotkey_t *obs_hotkey_binding_get_hotkey(
|
||||
obs_hotkey_binding_t *binding);
|
||||
EXPORT obs_key_combination_t
|
||||
obs_hotkey_binding_get_key_combination(obs_hotkey_binding_t *binding);
|
||||
EXPORT obs_hotkey_id
|
||||
obs_hotkey_binding_get_hotkey_id(obs_hotkey_binding_t *binding);
|
||||
EXPORT obs_hotkey_t *
|
||||
obs_hotkey_binding_get_hotkey(obs_hotkey_binding_t *binding);
|
||||
|
||||
/* setter functions */
|
||||
|
||||
EXPORT void obs_hotkey_set_name(obs_hotkey_id id, const char *name);
|
||||
EXPORT void obs_hotkey_set_description(obs_hotkey_id id, const char *desc);
|
||||
EXPORT void obs_hotkey_pair_set_names(obs_hotkey_pair_id id,
|
||||
const char *name0, const char *name1);
|
||||
EXPORT void obs_hotkey_pair_set_names(obs_hotkey_pair_id id, const char *name0,
|
||||
const char *name1);
|
||||
EXPORT void obs_hotkey_pair_set_descriptions(obs_hotkey_pair_id id,
|
||||
const char *desc0, const char *desc1);
|
||||
const char *desc0,
|
||||
const char *desc1);
|
||||
|
||||
#ifndef SWIG
|
||||
struct obs_hotkeys_translations {
|
||||
|
|
@ -134,81 +134,88 @@ struct obs_hotkeys_translations {
|
|||
* translations for these keys, it will use the operating system's translation
|
||||
* over these translations. If no translations are specified, it will use
|
||||
* the default English translations for that specific operating system. */
|
||||
EXPORT void obs_hotkeys_set_translations_s(
|
||||
struct obs_hotkeys_translations *translations, size_t size);
|
||||
EXPORT void
|
||||
obs_hotkeys_set_translations_s(struct obs_hotkeys_translations *translations,
|
||||
size_t size);
|
||||
#endif
|
||||
|
||||
#define obs_hotkeys_set_translations(translations) \
|
||||
obs_hotkeys_set_translations_s(translations, \
|
||||
sizeof(struct obs_hotkeys_translations))
|
||||
obs_hotkeys_set_translations_s( \
|
||||
translations, sizeof(struct obs_hotkeys_translations))
|
||||
|
||||
EXPORT void obs_hotkeys_set_audio_hotkeys_translations(
|
||||
const char *mute, const char *unmute,
|
||||
const char *push_to_mute, const char *push_to_talk);
|
||||
EXPORT void
|
||||
obs_hotkeys_set_audio_hotkeys_translations(const char *mute, const char *unmute,
|
||||
const char *push_to_mute,
|
||||
const char *push_to_talk);
|
||||
|
||||
EXPORT void obs_hotkeys_set_sceneitem_hotkeys_translations(
|
||||
const char *show, const char *hide);
|
||||
EXPORT void obs_hotkeys_set_sceneitem_hotkeys_translations(const char *show,
|
||||
const char *hide);
|
||||
|
||||
/* registering hotkeys (giving hotkeys a name and a function) */
|
||||
|
||||
typedef void (*obs_hotkey_func)(void *data,
|
||||
obs_hotkey_id id, obs_hotkey_t *hotkey, bool pressed);
|
||||
typedef void (*obs_hotkey_func)(void *data, obs_hotkey_id id,
|
||||
obs_hotkey_t *hotkey, bool pressed);
|
||||
|
||||
EXPORT obs_hotkey_id obs_hotkey_register_frontend(const char *name,
|
||||
const char *description, obs_hotkey_func func, void *data);
|
||||
const char *description,
|
||||
obs_hotkey_func func,
|
||||
void *data);
|
||||
|
||||
EXPORT obs_hotkey_id obs_hotkey_register_encoder(obs_encoder_t *encoder,
|
||||
const char *name, const char *description,
|
||||
obs_hotkey_func func, void *data);
|
||||
const char *name,
|
||||
const char *description,
|
||||
obs_hotkey_func func,
|
||||
void *data);
|
||||
|
||||
EXPORT obs_hotkey_id obs_hotkey_register_output(obs_output_t *output,
|
||||
const char *name, const char *description,
|
||||
obs_hotkey_func func, void *data);
|
||||
const char *name,
|
||||
const char *description,
|
||||
obs_hotkey_func func,
|
||||
void *data);
|
||||
|
||||
EXPORT obs_hotkey_id obs_hotkey_register_service(obs_service_t *service,
|
||||
const char *name, const char *description,
|
||||
obs_hotkey_func func, void *data);
|
||||
const char *name,
|
||||
const char *description,
|
||||
obs_hotkey_func func,
|
||||
void *data);
|
||||
|
||||
EXPORT obs_hotkey_id obs_hotkey_register_source(obs_source_t *source,
|
||||
const char *name, const char *description,
|
||||
obs_hotkey_func func, void *data);
|
||||
const char *name,
|
||||
const char *description,
|
||||
obs_hotkey_func func,
|
||||
void *data);
|
||||
|
||||
typedef bool (*obs_hotkey_active_func)(void *data,
|
||||
obs_hotkey_pair_id id, obs_hotkey_t *hotkey, bool pressed);
|
||||
typedef bool (*obs_hotkey_active_func)(void *data, obs_hotkey_pair_id id,
|
||||
obs_hotkey_t *hotkey, bool pressed);
|
||||
|
||||
EXPORT obs_hotkey_pair_id obs_hotkey_pair_register_frontend(
|
||||
const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1,
|
||||
void *data0, void *data1);
|
||||
const char *name0, const char *description0, const char *name1,
|
||||
const char *description1, obs_hotkey_active_func func0,
|
||||
obs_hotkey_active_func func1, void *data0, void *data1);
|
||||
|
||||
EXPORT obs_hotkey_pair_id obs_hotkey_pair_register_encoder(
|
||||
obs_encoder_t *encoder,
|
||||
const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1,
|
||||
void *data0, void *data1);
|
||||
obs_encoder_t *encoder, const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1, void *data0,
|
||||
void *data1);
|
||||
|
||||
EXPORT obs_hotkey_pair_id obs_hotkey_pair_register_output(
|
||||
obs_output_t *output,
|
||||
const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1,
|
||||
void *data0, void *data1);
|
||||
obs_output_t *output, const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1, void *data0,
|
||||
void *data1);
|
||||
|
||||
EXPORT obs_hotkey_pair_id obs_hotkey_pair_register_service(
|
||||
obs_service_t *service,
|
||||
const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1,
|
||||
void *data0, void *data1);
|
||||
obs_service_t *service, const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1, void *data0,
|
||||
void *data1);
|
||||
|
||||
EXPORT obs_hotkey_pair_id obs_hotkey_pair_register_source(
|
||||
obs_source_t *source,
|
||||
const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1,
|
||||
void *data0, void *data1);
|
||||
obs_source_t *source, const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1, void *data0,
|
||||
void *data1);
|
||||
|
||||
EXPORT void obs_hotkey_unregister(obs_hotkey_id id);
|
||||
|
||||
|
|
@ -217,29 +224,29 @@ EXPORT void obs_hotkey_pair_unregister(obs_hotkey_pair_id id);
|
|||
/* loading hotkeys (associating a hotkey with a physical key and modifiers) */
|
||||
|
||||
EXPORT void obs_hotkey_load_bindings(obs_hotkey_id id,
|
||||
obs_key_combination_t *combinations, size_t num);
|
||||
obs_key_combination_t *combinations,
|
||||
size_t num);
|
||||
|
||||
EXPORT void obs_hotkey_load(obs_hotkey_id id, obs_data_array_t *data);
|
||||
|
||||
EXPORT void obs_hotkeys_load_encoder(obs_encoder_t *encoder,
|
||||
obs_data_t *hotkeys);
|
||||
obs_data_t *hotkeys);
|
||||
|
||||
EXPORT void obs_hotkeys_load_output(obs_output_t *output, obs_data_t *hotkeys);
|
||||
|
||||
EXPORT void obs_hotkeys_load_service(obs_service_t *service,
|
||||
obs_data_t *hotkeys);
|
||||
obs_data_t *hotkeys);
|
||||
|
||||
EXPORT void obs_hotkeys_load_source(obs_source_t *source, obs_data_t *hotkeys);
|
||||
|
||||
EXPORT void obs_hotkey_pair_load(obs_hotkey_pair_id id, obs_data_array_t *data0,
|
||||
obs_data_array_t *data1);
|
||||
|
||||
obs_data_array_t *data1);
|
||||
|
||||
EXPORT obs_data_array_t *obs_hotkey_save(obs_hotkey_id id);
|
||||
|
||||
EXPORT void obs_hotkey_pair_save(obs_hotkey_pair_id id,
|
||||
obs_data_array_t **p_data0,
|
||||
obs_data_array_t **p_data1);
|
||||
obs_data_array_t **p_data0,
|
||||
obs_data_array_t **p_data1);
|
||||
|
||||
EXPORT obs_data_t *obs_hotkeys_save_encoder(obs_encoder_t *encoder);
|
||||
|
||||
|
|
@ -251,18 +258,18 @@ EXPORT obs_data_t *obs_hotkeys_save_source(obs_source_t *source);
|
|||
|
||||
/* enumerating hotkeys */
|
||||
|
||||
typedef bool (*obs_hotkey_enum_func)(void *data,
|
||||
obs_hotkey_id id, obs_hotkey_t *key);
|
||||
typedef bool (*obs_hotkey_enum_func)(void *data, obs_hotkey_id id,
|
||||
obs_hotkey_t *key);
|
||||
|
||||
EXPORT void obs_enum_hotkeys(obs_hotkey_enum_func func, void *data);
|
||||
|
||||
/* enumerating bindings */
|
||||
|
||||
typedef bool (*obs_hotkey_binding_enum_func)(void *data,
|
||||
size_t idx, obs_hotkey_binding_t* binding);
|
||||
typedef bool (*obs_hotkey_binding_enum_func)(void *data, size_t idx,
|
||||
obs_hotkey_binding_t *binding);
|
||||
|
||||
EXPORT void obs_enum_hotkey_bindings(obs_hotkey_binding_enum_func func,
|
||||
void *data);
|
||||
void *data);
|
||||
|
||||
/* hotkey event control */
|
||||
|
||||
|
|
@ -274,11 +281,12 @@ EXPORT void obs_hotkey_enable_strict_modifiers(bool enable);
|
|||
|
||||
/* hotkey callback routing (trigger callbacks through e.g. a UI thread) */
|
||||
|
||||
typedef void (*obs_hotkey_callback_router_func)(void *data,
|
||||
obs_hotkey_id id, bool pressed);
|
||||
typedef void (*obs_hotkey_callback_router_func)(void *data, obs_hotkey_id id,
|
||||
bool pressed);
|
||||
|
||||
EXPORT void obs_hotkey_set_callback_routing_func(obs_hotkey_callback_router_func
|
||||
func, void *data);
|
||||
EXPORT void
|
||||
obs_hotkey_set_callback_routing_func(obs_hotkey_callback_router_func func,
|
||||
void *data);
|
||||
|
||||
EXPORT void obs_hotkey_trigger_routed_callback(obs_hotkey_id id, bool pressed);
|
||||
|
||||
|
|
@ -290,12 +298,12 @@ EXPORT void obs_hotkey_enable_callback_rerouting(bool enable);
|
|||
|
||||
typedef void (*obs_hotkey_atomic_update_func)(void *);
|
||||
EXPORT void obs_hotkey_update_atomic(obs_hotkey_atomic_update_func func,
|
||||
void *data);
|
||||
void *data);
|
||||
|
||||
struct dstr;
|
||||
EXPORT void obs_key_to_str(obs_key_t key, struct dstr *str);
|
||||
EXPORT void obs_key_combination_to_str(obs_key_combination_t key,
|
||||
struct dstr *str);
|
||||
struct dstr *str);
|
||||
|
||||
EXPORT obs_key_t obs_key_from_virtual_key(int code);
|
||||
EXPORT int obs_key_to_virtual_key(obs_key_t key);
|
||||
|
|
|
|||
|
|
@ -437,7 +437,6 @@ OBS_HOTKEY(OBS_KEY_SLEEP)
|
|||
OBS_HOTKEY(OBS_KEY_ZOOM)
|
||||
OBS_HOTKEY(OBS_KEY_CANCEL)
|
||||
|
||||
|
||||
#ifndef OBS_MOUSE_BUTTON
|
||||
#define OBS_MOUSE_BUTTON(x) OBS_HOTKEY(x)
|
||||
#define OBS_MOUSE_BUTTON_DEFAULT 1
|
||||
|
|
|
|||
|
|
@ -20,37 +20,37 @@
|
|||
#include "util/c99defs.h"
|
||||
|
||||
enum obs_interaction_flags {
|
||||
INTERACT_NONE = 0,
|
||||
INTERACT_CAPS_KEY = 1,
|
||||
INTERACT_SHIFT_KEY = 1 << 1,
|
||||
INTERACT_CONTROL_KEY = 1 << 2,
|
||||
INTERACT_ALT_KEY = 1 << 3,
|
||||
INTERACT_MOUSE_LEFT = 1 << 4,
|
||||
INTERACT_MOUSE_MIDDLE = 1 << 5,
|
||||
INTERACT_MOUSE_RIGHT = 1 << 6,
|
||||
INTERACT_COMMAND_KEY = 1 << 7,
|
||||
INTERACT_NUMLOCK_KEY = 1 << 8,
|
||||
INTERACT_IS_KEY_PAD = 1 << 9,
|
||||
INTERACT_IS_LEFT = 1 << 10,
|
||||
INTERACT_IS_RIGHT = 1 << 11
|
||||
INTERACT_NONE = 0,
|
||||
INTERACT_CAPS_KEY = 1,
|
||||
INTERACT_SHIFT_KEY = 1 << 1,
|
||||
INTERACT_CONTROL_KEY = 1 << 2,
|
||||
INTERACT_ALT_KEY = 1 << 3,
|
||||
INTERACT_MOUSE_LEFT = 1 << 4,
|
||||
INTERACT_MOUSE_MIDDLE = 1 << 5,
|
||||
INTERACT_MOUSE_RIGHT = 1 << 6,
|
||||
INTERACT_COMMAND_KEY = 1 << 7,
|
||||
INTERACT_NUMLOCK_KEY = 1 << 8,
|
||||
INTERACT_IS_KEY_PAD = 1 << 9,
|
||||
INTERACT_IS_LEFT = 1 << 10,
|
||||
INTERACT_IS_RIGHT = 1 << 11,
|
||||
};
|
||||
|
||||
enum obs_mouse_button_type {
|
||||
MOUSE_LEFT,
|
||||
MOUSE_MIDDLE,
|
||||
MOUSE_RIGHT
|
||||
MOUSE_RIGHT,
|
||||
};
|
||||
|
||||
struct obs_mouse_event {
|
||||
uint32_t modifiers;
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
uint32_t modifiers;
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
};
|
||||
|
||||
struct obs_key_event {
|
||||
uint32_t modifiers;
|
||||
char *text;
|
||||
uint32_t native_modifiers;
|
||||
uint32_t native_scancode;
|
||||
uint32_t native_vkey;
|
||||
uint32_t modifiers;
|
||||
char *text;
|
||||
uint32_t native_modifiers;
|
||||
uint32_t native_scancode;
|
||||
uint32_t native_vkey;
|
||||
};
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue