mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-09-19 20:32:15 +02:00
obs-output module: Fill out more functions
- Add start/stop code to obs-output module - Use a circular buffer for the buffered encoder packets instead of a dynamic array - Add pthreads.lib as a dependency to obs-output module on windows in visual studio project files - Fix an windows export bug for avc parsing functions on windows. Also, rename those functions to be more consistent with each other. - Make outputs use a single function for encoded data rather than multiple functions - Add the ability to make 'text' properties be passworded
This commit is contained in:
parent
fd9d395509
commit
4a652ec82d
@ -16,6 +16,7 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include "obs.h"
|
||||
#include "obs-avc.h"
|
||||
#include "util/array-serializer.h"
|
||||
|
||||
enum {
|
||||
@ -127,8 +128,8 @@ static void serialize_avc_data(struct serializer *s, const uint8_t *data,
|
||||
}
|
||||
}
|
||||
|
||||
void obs_create_avc_packet(struct encoder_packet *avc_packet,
|
||||
struct encoder_packet *src)
|
||||
void obs_parse_avc_packet(struct encoder_packet *avc_packet,
|
||||
const struct encoder_packet *src)
|
||||
{
|
||||
struct array_output_data output;
|
||||
struct serializer s;
|
||||
@ -182,7 +183,7 @@ static void get_sps_pps(const uint8_t *data, size_t size,
|
||||
}
|
||||
}
|
||||
|
||||
size_t obs_create_avc_header(uint8_t **header, const uint8_t *data, size_t size)
|
||||
size_t obs_parse_avc_header(uint8_t **header, const uint8_t *data, size_t size)
|
||||
{
|
||||
struct array_output_data output;
|
||||
struct serializer s;
|
||||
|
@ -17,13 +17,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/c99defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct encoder_packet;
|
||||
|
||||
/* Helpers for parsing AVC NAL units. */
|
||||
|
||||
const uint8_t *obs_avc_find_startcode(const uint8_t *p, const uint8_t *end);
|
||||
|
||||
EXPORT void obs_create_avc_packet(struct encoder_packet *avc_packet,
|
||||
struct encoder_packet *src);
|
||||
EXPORT size_t obs_create_avc_header(uint8_t **header, const uint8_t *data,
|
||||
EXPORT const uint8_t *obs_avc_find_startcode(const uint8_t *p,
|
||||
const uint8_t *end);
|
||||
EXPORT void obs_parse_avc_packet(struct encoder_packet *avc_packet,
|
||||
const struct encoder_packet *src);
|
||||
EXPORT size_t obs_parse_avc_header(uint8_t **header, const uint8_t *data,
|
||||
size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -30,3 +30,4 @@
|
||||
#define OBS_OUTPUT_BAD_PATH -1
|
||||
#define OBS_OUTPUT_CONNECT_FAILED -2
|
||||
#define OBS_OUTPUT_INVALID_STREAM -3
|
||||
#define OBS_OUTPUT_FAIL -4
|
||||
|
@ -200,13 +200,7 @@ void obs_register_output(const struct obs_output_info *info)
|
||||
CHECK_REQUIRED_VAL(info, stop, obs_register_output);
|
||||
|
||||
if (info->flags & OBS_OUTPUT_ENCODED) {
|
||||
if (info->flags & OBS_OUTPUT_VIDEO)
|
||||
CHECK_REQUIRED_VAL(info, encoded_video,
|
||||
obs_register_output);
|
||||
|
||||
if (info->flags & OBS_OUTPUT_AUDIO)
|
||||
CHECK_REQUIRED_VAL(info, encoded_audio,
|
||||
obs_register_output);
|
||||
CHECK_REQUIRED_VAL(info, encoded_data, obs_register_output);
|
||||
} else {
|
||||
if (info->flags & OBS_OUTPUT_VIDEO)
|
||||
CHECK_REQUIRED_VAL(info, raw_video,
|
||||
|
@ -322,11 +322,11 @@ static void hook_data_capture(struct obs_output *output, bool encoded,
|
||||
if (encoded) {
|
||||
if (has_video)
|
||||
obs_encoder_start(output->video_encoder,
|
||||
output->info.encoded_video,
|
||||
output->info.encoded_data,
|
||||
output->data);
|
||||
if (has_audio)
|
||||
obs_encoder_start(output->audio_encoder,
|
||||
output->info.encoded_audio,
|
||||
output->info.encoded_data,
|
||||
output->data);
|
||||
} else {
|
||||
if (has_video)
|
||||
@ -414,11 +414,11 @@ void obs_output_end_data_capture(obs_output_t output)
|
||||
if (encoded) {
|
||||
if (has_video)
|
||||
obs_encoder_stop(output->video_encoder,
|
||||
output->info.encoded_video,
|
||||
output->info.encoded_data,
|
||||
output->data);
|
||||
if (has_audio)
|
||||
obs_encoder_stop(output->audio_encoder,
|
||||
output->info.encoded_audio,
|
||||
output->info.encoded_data,
|
||||
output->data);
|
||||
} else {
|
||||
if (has_video)
|
||||
|
@ -42,8 +42,7 @@ struct obs_output_info {
|
||||
void (*raw_video)(void *data, struct video_data *frame);
|
||||
void (*raw_audio)(void *data, struct audio_data *frames);
|
||||
|
||||
void (*encoded_video)(void *data, struct encoder_packet *packet);
|
||||
void (*encoded_audio)(void *data, struct encoder_packet *packet);
|
||||
void (*encoded_data)(void *data, struct encoder_packet *packet);
|
||||
|
||||
/* optional */
|
||||
void (*update)(void *data, obs_data_t settings);
|
||||
|
@ -36,6 +36,10 @@ struct list_item {
|
||||
char *value;
|
||||
};
|
||||
|
||||
struct text_data {
|
||||
enum obs_text_type type;
|
||||
};
|
||||
|
||||
struct list_data {
|
||||
DARRAY(struct list_item) items;
|
||||
enum obs_combo_type type;
|
||||
@ -136,7 +140,7 @@ static inline size_t get_property_size(enum obs_property_type type)
|
||||
case OBS_PROPERTY_BOOL: return 0;
|
||||
case OBS_PROPERTY_INT: return sizeof(struct int_data);
|
||||
case OBS_PROPERTY_FLOAT: return sizeof(struct float_data);
|
||||
case OBS_PROPERTY_TEXT: return 0;
|
||||
case OBS_PROPERTY_TEXT: return sizeof(struct text_data);
|
||||
case OBS_PROPERTY_PATH: return 0;
|
||||
case OBS_PROPERTY_LIST: return sizeof(struct list_data);
|
||||
case OBS_PROPERTY_COLOR: return 0;
|
||||
@ -224,10 +228,13 @@ void obs_properties_add_float(obs_properties_t props, const char *name,
|
||||
}
|
||||
|
||||
void obs_properties_add_text(obs_properties_t props, const char *name,
|
||||
const char *desc)
|
||||
const char *desc, enum obs_text_type type)
|
||||
{
|
||||
if (!props || has_prop(props, name)) return;
|
||||
new_prop(props, name, desc, OBS_PROPERTY_TEXT);
|
||||
|
||||
struct obs_property *p = new_prop(props, name, desc, OBS_PROPERTY_TEXT);
|
||||
struct text_data *data = get_property_data(p);
|
||||
data->type = type;
|
||||
}
|
||||
|
||||
void obs_properties_add_path(obs_properties_t props, const char *name,
|
||||
@ -356,6 +363,12 @@ double obs_property_float_step(obs_property_t p)
|
||||
return data ? data->step : 0;
|
||||
}
|
||||
|
||||
enum obs_text_type obs_proprety_text_type(obs_property_t p)
|
||||
{
|
||||
struct text_data *data = get_type_data(p, OBS_PROPERTY_TEXT);
|
||||
return data ? data->type : OBS_TEXT_DEFAULT;
|
||||
}
|
||||
|
||||
enum obs_combo_type obs_property_list_type(obs_property_t p)
|
||||
{
|
||||
struct list_data *data = get_list_data(p);
|
||||
|
@ -47,6 +47,11 @@ enum obs_combo_type {
|
||||
OBS_COMBO_TYPE_LIST,
|
||||
};
|
||||
|
||||
enum obs_text_type {
|
||||
OBS_TEXT_DEFAULT,
|
||||
OBS_TEXT_PASSWORD,
|
||||
};
|
||||
|
||||
struct obs_properties;
|
||||
struct obs_property;
|
||||
typedef struct obs_properties *obs_properties_t;
|
||||
@ -71,7 +76,7 @@ EXPORT void obs_properties_add_int(obs_properties_t props, const char *name,
|
||||
EXPORT void obs_properties_add_float(obs_properties_t props, const char *name,
|
||||
const char *description, double min, double max, double step);
|
||||
EXPORT void obs_properties_add_text(obs_properties_t props, const char *name,
|
||||
const char *description);
|
||||
const char *description, enum obs_text_type type);
|
||||
EXPORT void obs_properties_add_path(obs_properties_t props, const char *name,
|
||||
const char *description);
|
||||
EXPORT obs_property_t obs_properties_add_list(obs_properties_t props,
|
||||
@ -97,6 +102,7 @@ EXPORT int obs_property_int_step(obs_property_t p);
|
||||
EXPORT double obs_property_float_min(obs_property_t p);
|
||||
EXPORT double obs_property_float_max(obs_property_t p);
|
||||
EXPORT double obs_property_float_step(obs_property_t p);
|
||||
EXPORT enum obs_text_type obs_proprety_text_type(obs_property_t p);
|
||||
EXPORT enum obs_combo_type obs_property_list_type(obs_property_t p);
|
||||
EXPORT enum obs_combo_format obs_property_list_format(obs_property_t p);
|
||||
|
||||
|
@ -63,9 +63,13 @@ QWidget *OBSPropertiesView::AddCheckbox(obs_property_t prop)
|
||||
|
||||
QWidget *OBSPropertiesView::AddText(obs_property_t prop)
|
||||
{
|
||||
const char *name = obs_property_name(prop);
|
||||
const char *val = obs_data_getstring(settings, name);
|
||||
QLineEdit *edit = new QLineEdit();
|
||||
const char *name = obs_property_name(prop);
|
||||
const char *val = obs_data_getstring(settings, name);
|
||||
obs_text_type type = obs_proprety_text_type(prop);
|
||||
QLineEdit *edit = new QLineEdit();
|
||||
|
||||
if (type == OBS_TEXT_PASSWORD)
|
||||
edit->setEchoMode(QLineEdit::Password);
|
||||
|
||||
edit->setText(QT_UTF8(val));
|
||||
|
||||
|
@ -82,10 +82,11 @@ void flv_meta_data(obs_output_t context, uint8_t **output, size_t *size)
|
||||
uint8_t *meta_data;
|
||||
size_t meta_data_size;
|
||||
|
||||
array_output_serializer_init(&s, &data);
|
||||
|
||||
build_flv_meta_data(context, &meta_data, &meta_data_size);
|
||||
|
||||
array_output_serializer_init(&s, &data);
|
||||
s_w8(&s, RTMP_PACKET_TYPE_VIDEO);
|
||||
s_w8(&s, RTMP_PACKET_TYPE_INFO);
|
||||
|
||||
s_wb24(&s, (uint32_t)meta_data_size);
|
||||
s_wb32(&s, 0);
|
||||
|
@ -2,8 +2,12 @@
|
||||
|
||||
OBS_DECLARE_MODULE()
|
||||
|
||||
extern struct obs_output_info rtmp_output_info;
|
||||
|
||||
bool obs_module_load(uint32_t libobs_ver)
|
||||
{
|
||||
obs_register_output(&rtmp_output_info);
|
||||
|
||||
UNUSED_PARAMETER(libobs_ver);
|
||||
return true;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include <obs.h>
|
||||
#include <obs-avc.h>
|
||||
#include <util/darray.h>
|
||||
#include <util/circlebuf.h>
|
||||
#include <util/dstr.h>
|
||||
#include <util/threading.h>
|
||||
#include "librtmp/rtmp.h"
|
||||
@ -25,23 +25,24 @@
|
||||
#include "flv-mux.h"
|
||||
|
||||
struct rtmp_stream {
|
||||
obs_output_t output;
|
||||
obs_output_t output;
|
||||
|
||||
pthread_mutex_t packets_mutex;
|
||||
DARRAY(struct encoder_packet) packets;
|
||||
pthread_mutex_t packets_mutex;
|
||||
struct circlebuf packets;
|
||||
|
||||
bool connecting;
|
||||
bool active;
|
||||
pthread_t connect_thread;
|
||||
pthread_t send_thread;
|
||||
bool connecting;
|
||||
pthread_t connect_thread;
|
||||
|
||||
os_sem_t send_sem;
|
||||
os_event_t stop_event;
|
||||
bool active;
|
||||
pthread_t send_thread;
|
||||
|
||||
struct dstr path, key;
|
||||
struct dstr username, password;
|
||||
os_sem_t send_sem;
|
||||
os_event_t stop_event;
|
||||
|
||||
RTMP rtmp;
|
||||
struct dstr path, key;
|
||||
struct dstr username, password;
|
||||
|
||||
RTMP rtmp;
|
||||
};
|
||||
|
||||
static const char *rtmp_stream_getname(const char *locale)
|
||||
@ -58,11 +59,25 @@ static void log_rtmp(int level, const char *format, va_list args)
|
||||
UNUSED_PARAMETER(level);
|
||||
}
|
||||
|
||||
static inline void free_packets(struct rtmp_stream *stream)
|
||||
{
|
||||
while (stream->packets.size) {
|
||||
struct encoder_packet packet;
|
||||
circlebuf_pop_front(&stream->packets, &packet, sizeof(packet));
|
||||
obs_free_encoder_packet(&packet);
|
||||
}
|
||||
}
|
||||
|
||||
static void rtmp_stream_stop(void *data);
|
||||
|
||||
static void rtmp_stream_destroy(void *data)
|
||||
{
|
||||
struct rtmp_stream *stream = data;
|
||||
|
||||
if (stream) {
|
||||
rtmp_stream_stop(stream);
|
||||
|
||||
free_packets(stream);
|
||||
dstr_free(&stream->path);
|
||||
dstr_free(&stream->key);
|
||||
dstr_free(&stream->username);
|
||||
@ -99,13 +114,21 @@ fail:
|
||||
|
||||
static void rtmp_stream_stop(void *data)
|
||||
{
|
||||
UNUSED_PARAMETER(data);
|
||||
}
|
||||
struct rtmp_stream *stream = data;
|
||||
void *ret;
|
||||
|
||||
static void rtmp_stream_update(void *data, obs_data_t settings)
|
||||
{
|
||||
UNUSED_PARAMETER(data);
|
||||
UNUSED_PARAMETER(settings);
|
||||
os_event_signal(stream->stop_event);
|
||||
|
||||
if (stream->connecting)
|
||||
pthread_join(stream->connect_thread, &ret);
|
||||
|
||||
if (stream->active) {
|
||||
obs_output_end_data_capture(stream->output);
|
||||
os_sem_post(stream->send_sem);
|
||||
pthread_join(stream->send_thread, &ret);
|
||||
}
|
||||
|
||||
os_event_reset(stream->stop_event);
|
||||
}
|
||||
|
||||
static inline void set_rtmp_str(AVal *val, const char *str)
|
||||
@ -128,44 +151,70 @@ static inline bool get_next_packet(struct rtmp_stream *stream,
|
||||
bool new_packet = false;
|
||||
|
||||
pthread_mutex_lock(&stream->packets_mutex);
|
||||
if (stream->packets.num) {
|
||||
*packet = stream->packets.array[0];
|
||||
if (stream->packets.size) {
|
||||
circlebuf_pop_front(&stream->packets, packet,
|
||||
sizeof(struct encoder_packet));
|
||||
new_packet = true;
|
||||
da_erase(stream->packets, 0);
|
||||
}
|
||||
pthread_mutex_unlock(&stream->packets_mutex);
|
||||
|
||||
return new_packet;
|
||||
}
|
||||
|
||||
static void send_packet(struct rtmp_stream *stream,
|
||||
static int send_packet(struct rtmp_stream *stream,
|
||||
struct encoder_packet *packet, bool is_header)
|
||||
{
|
||||
uint8_t *data;
|
||||
size_t size;
|
||||
int ret;
|
||||
|
||||
flv_packet_mux(packet, &data, &size, is_header);
|
||||
RTMP_Write(&stream->rtmp, (char*)data, (int)size);
|
||||
ret = RTMP_Write(&stream->rtmp, (char*)data, (int)size);
|
||||
bfree(data);
|
||||
|
||||
obs_free_encoder_packet(packet);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool send_remaining_packets(struct rtmp_stream *stream)
|
||||
{
|
||||
struct encoder_packet packet;
|
||||
|
||||
while (get_next_packet(stream, &packet))
|
||||
if (send_packet(stream, &packet, false) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void *send_thread(void *data)
|
||||
{
|
||||
struct rtmp_stream *stream = data;
|
||||
bool disconnected = false;
|
||||
|
||||
while (os_sem_wait(stream->send_sem) == 0) {
|
||||
struct encoder_packet packet;
|
||||
|
||||
if (os_event_try(stream->stop_event) != EAGAIN)
|
||||
break;
|
||||
|
||||
if (!get_next_packet(stream, &packet))
|
||||
continue;
|
||||
|
||||
send_packet(stream, &packet, false);
|
||||
obs_free_encoder_packet(&packet);
|
||||
if (send_packet(stream, &packet, false) < 0) {
|
||||
disconnected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!disconnected && !send_remaining_packets(stream))
|
||||
disconnected = true;
|
||||
|
||||
if (disconnected)
|
||||
free_packets(stream);
|
||||
|
||||
if (os_event_try(stream->stop_event) == EAGAIN)
|
||||
pthread_detach(stream->send_thread);
|
||||
|
||||
stream->active = false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -173,8 +222,8 @@ static void *send_thread(void *data)
|
||||
|
||||
static void send_meta_data(struct rtmp_stream *stream)
|
||||
{
|
||||
uint8_t *meta_data;
|
||||
size_t meta_data_size;
|
||||
uint8_t *meta_data;
|
||||
size_t meta_data_size;
|
||||
|
||||
flv_meta_data(stream->output, &meta_data, &meta_data_size);
|
||||
RTMP_Write(&stream->rtmp, (char*)meta_data, (int)meta_data_size);
|
||||
@ -183,8 +232,8 @@ static void send_meta_data(struct rtmp_stream *stream)
|
||||
|
||||
static void send_audio_header(struct rtmp_stream *stream)
|
||||
{
|
||||
obs_output_t context = stream->output;
|
||||
obs_encoder_t aencoder = obs_output_get_audio_encoder(context);
|
||||
obs_output_t context = stream->output;
|
||||
obs_encoder_t aencoder = obs_output_get_audio_encoder(context);
|
||||
|
||||
struct encoder_packet packet = {
|
||||
.type = OBS_ENCODER_AUDIO,
|
||||
@ -197,10 +246,10 @@ static void send_audio_header(struct rtmp_stream *stream)
|
||||
|
||||
static void send_video_header(struct rtmp_stream *stream)
|
||||
{
|
||||
obs_output_t context = stream->output;
|
||||
obs_encoder_t vencoder = obs_output_get_video_encoder(context);
|
||||
uint8_t *header;
|
||||
size_t size;
|
||||
obs_output_t context = stream->output;
|
||||
obs_encoder_t vencoder = obs_output_get_video_encoder(context);
|
||||
uint8_t *header;
|
||||
size_t size;
|
||||
|
||||
struct encoder_packet packet = {
|
||||
.type = OBS_ENCODER_VIDEO,
|
||||
@ -208,7 +257,7 @@ static void send_video_header(struct rtmp_stream *stream)
|
||||
};
|
||||
|
||||
obs_encoder_get_extra_data(vencoder, &header, &size);
|
||||
packet.size = obs_create_avc_header(&packet.data, header, size);
|
||||
packet.size = obs_parse_avc_header(&packet.data, header, size);
|
||||
send_packet(stream, &packet, true);
|
||||
obs_free_encoder_packet(&packet);
|
||||
}
|
||||
@ -230,11 +279,11 @@ static inline bool reset_semaphore(struct rtmp_stream *stream)
|
||||
#define socklen_t int
|
||||
#endif
|
||||
|
||||
static void init_send(struct rtmp_stream *stream)
|
||||
static int init_send(struct rtmp_stream *stream)
|
||||
{
|
||||
int cur_sendbuf_size = MIN_SENDBUF_SIZE;
|
||||
socklen_t size = sizeof(int);
|
||||
socklen_t ret;
|
||||
int ret;
|
||||
|
||||
getsockopt(stream->rtmp.m_sb.sb_socket, SOL_SOCKET, SO_SNDBUF,
|
||||
(char*)&cur_sendbuf_size, &size);
|
||||
@ -248,11 +297,14 @@ static void init_send(struct rtmp_stream *stream)
|
||||
reset_semaphore(stream);
|
||||
|
||||
ret = pthread_create(&stream->send_thread, NULL, send_thread, stream);
|
||||
if (ret != 0)
|
||||
bcrash("Failed to create send thread");
|
||||
if (ret != 0) {
|
||||
RTMP_Close(&stream->rtmp);
|
||||
return OBS_OUTPUT_FAIL;
|
||||
}
|
||||
|
||||
send_headers(stream);
|
||||
obs_output_begin_data_capture(stream->output, 0);
|
||||
return OBS_OUTPUT_SUCCESS;
|
||||
}
|
||||
|
||||
static int try_connect(struct rtmp_stream *stream)
|
||||
@ -276,13 +328,21 @@ static int try_connect(struct rtmp_stream *stream)
|
||||
if (!RTMP_ConnectStream(&stream->rtmp, 0))
|
||||
return OBS_OUTPUT_INVALID_STREAM;
|
||||
|
||||
init_send(stream);
|
||||
return OBS_OUTPUT_SUCCESS;
|
||||
return init_send(stream);
|
||||
}
|
||||
|
||||
static void *connect_thread(void *data)
|
||||
{
|
||||
UNUSED_PARAMETER(data);
|
||||
struct rtmp_stream *stream = data;
|
||||
int ret = try_connect(stream);
|
||||
|
||||
if (ret != OBS_OUTPUT_SUCCESS)
|
||||
obs_output_signal_start_fail(stream->output, ret);
|
||||
|
||||
if (os_event_try(stream->stop_event) == EAGAIN)
|
||||
pthread_detach(stream->connect_thread);
|
||||
|
||||
stream->connecting = false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -305,8 +365,46 @@ static bool rtmp_stream_start(void *data)
|
||||
stream) != 0;
|
||||
}
|
||||
|
||||
static bool rtmp_stream_active(void *data)
|
||||
static void rtmp_stream_data(void *data, struct encoder_packet *packet)
|
||||
{
|
||||
UNUSED_PARAMETER(data);
|
||||
return false;
|
||||
struct rtmp_stream *stream = data;
|
||||
struct encoder_packet new_packet;
|
||||
|
||||
if (packet->type == OBS_ENCODER_AUDIO)
|
||||
obs_duplicate_encoder_packet(&new_packet, packet);
|
||||
else if (packet->type == OBS_ENCODER_VIDEO)
|
||||
obs_parse_avc_packet(&new_packet, packet);
|
||||
|
||||
pthread_mutex_lock(&stream->packets_mutex);
|
||||
circlebuf_push_back(&stream->packets, &new_packet, sizeof(new_packet));
|
||||
pthread_mutex_unlock(&stream->packets_mutex);
|
||||
os_sem_post(stream->send_sem);
|
||||
}
|
||||
|
||||
static obs_properties_t rtmp_stream_properties(const char *locale)
|
||||
{
|
||||
obs_properties_t props = obs_properties_create();
|
||||
|
||||
/* TODO: locale */
|
||||
obs_properties_add_text(props, "path", "Stream URL", OBS_TEXT_DEFAULT);
|
||||
obs_properties_add_text(props, "key", "Stream Key", OBS_TEXT_PASSWORD);
|
||||
obs_properties_add_text(props, "username", "User Name",
|
||||
OBS_TEXT_DEFAULT);
|
||||
obs_properties_add_text(props, "password", "Password",
|
||||
OBS_TEXT_PASSWORD);
|
||||
|
||||
UNUSED_PARAMETER(locale);
|
||||
return props;
|
||||
}
|
||||
|
||||
struct obs_output_info rtmp_output_info = {
|
||||
.id = "rtmp_output",
|
||||
.flags = OBS_OUTPUT_AV | OBS_OUTPUT_ENCODED | OBS_OUTPUT_SERVICE,
|
||||
.getname = rtmp_stream_getname,
|
||||
.create = rtmp_stream_create,
|
||||
.destroy = rtmp_stream_destroy,
|
||||
.start = rtmp_stream_start,
|
||||
.stop = rtmp_stream_stop,
|
||||
.encoded_data = rtmp_stream_data,
|
||||
.properties = rtmp_stream_properties
|
||||
};
|
||||
|
@ -122,7 +122,8 @@ static obs_properties_t obs_x264_props(const char *locale)
|
||||
add_strings(list, x264_tune_names);
|
||||
|
||||
obs_properties_add_text(props, "x264opts",
|
||||
"x264 encoder options (separated by ':')");
|
||||
"x264 encoder options (separated by ':')",
|
||||
OBS_TEXT_DEFAULT);
|
||||
|
||||
return props;
|
||||
}
|
||||
|
@ -90,7 +90,7 @@
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>libobs.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>pthreads.lib;libobs.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
@ -109,7 +109,7 @@
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>libobs.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>pthreads.lib;libobs.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
@ -132,7 +132,7 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>libobs.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>pthreads.lib;libobs.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
@ -155,7 +155,7 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>libobs.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>pthreads.lib;libobs.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
|
Loading…
Reference in New Issue
Block a user