From 585fd8f969b156247747f9c4249ad835a9e030a5 Mon Sep 17 00:00:00 2001 From: jp9000 Date: Mon, 10 Mar 2014 19:04:00 -0700 Subject: [PATCH] Fix audio streaming and mac semaphores ...The reason why audio didn't work was because I overwrote the bitrate values. As for semaphores, mac doesn't support unnamed semaphores without using mach semaphores. So, I just implemented a semaphore wrapper for each OS. --- libobs/media-io/audio-io.c | 10 +-- libobs/media-io/video-io.c | 24 +++---- libobs/util/threading-posix.c | 86 +++++++++++++++++++++++++- libobs/util/threading-windows.c | 60 ++++++++++++++---- libobs/util/threading.h | 33 +++++----- plugins/obs-ffmpeg/obs-ffmpeg-output.c | 57 +++++++++-------- test/test-input/test-sinewave.c | 10 +-- 7 files changed, 203 insertions(+), 77 deletions(-) diff --git a/libobs/media-io/audio-io.c b/libobs/media-io/audio-io.c index 67be023b6..69c4b3a77 100644 --- a/libobs/media-io/audio-io.c +++ b/libobs/media-io/audio-io.c @@ -80,7 +80,7 @@ struct audio_output { size_t planes; pthread_t thread; - event_t stop_event; + os_event_t stop_event; DARRAY(uint8_t) mix_buffers[MAX_AV_PLANES]; @@ -437,7 +437,7 @@ static void *audio_thread(void *param) uint64_t prev_time = os_gettime_ns() - buffer_time; uint64_t audio_time; - while (event_try(audio->stop_event) == EAGAIN) { + while (os_event_try(audio->stop_event) == EAGAIN) { os_sleep_ms(AUDIO_WAIT_TIME); pthread_mutex_lock(&audio->line_mutex); @@ -590,7 +590,7 @@ int audio_output_open(audio_t *audio, struct audio_output_info *info) goto fail; if (pthread_mutex_init(&out->input_mutex, NULL) != 0) goto fail; - if (event_init(&out->stop_event, EVENT_TYPE_MANUAL) != 0) + if (os_event_init(&out->stop_event, OS_EVENT_TYPE_MANUAL) != 0) goto fail; if (pthread_create(&out->thread, NULL, audio_thread, out) != 0) goto fail; @@ -613,7 +613,7 @@ void audio_output_close(audio_t audio) return; if (audio->initialized) { - event_signal(audio->stop_event); + os_event_signal(audio->stop_event); pthread_join(audio->thread, &thread_ret); } @@ -631,7 +631,7 @@ void audio_output_close(audio_t audio) da_free(audio->mix_buffers[i]); da_free(audio->inputs); - event_destroy(audio->stop_event); + os_event_destroy(audio->stop_event); pthread_mutex_destroy(&audio->line_mutex); bfree(audio); } diff --git a/libobs/media-io/video-io.c b/libobs/media-io/video-io.c index c1b0adf1e..e71ce71fd 100644 --- a/libobs/media-io/video-io.c +++ b/libobs/media-io/video-io.c @@ -50,13 +50,13 @@ struct video_output { pthread_t thread; pthread_mutex_t data_mutex; - event_t stop_event; + os_event_t stop_event; struct video_data cur_frame; struct video_data next_frame; bool new_frame; - event_t update_event; + os_event_t update_event; uint64_t frame_time; volatile uint64_t cur_video_time; @@ -125,13 +125,13 @@ static void *video_thread(void *param) struct video_output *video = param; uint64_t cur_time = os_gettime_ns(); - while (event_try(video->stop_event) == EAGAIN) { + while (os_event_try(video->stop_event) == EAGAIN) { /* wait half a frame, update frame */ cur_time += (video->frame_time/2); os_sleepto_ns(cur_time); video->cur_video_time = cur_time; - event_signal(video->update_event); + os_event_signal(video->update_event); /* wait another half a frame, swap and output frames */ cur_time += (video->frame_time/2); @@ -174,9 +174,9 @@ int video_output_open(video_t *video, struct video_output_info *info) goto fail; if (pthread_mutex_init(&out->input_mutex, NULL) != 0) goto fail; - if (event_init(&out->stop_event, EVENT_TYPE_MANUAL) != 0) + if (os_event_init(&out->stop_event, OS_EVENT_TYPE_MANUAL) != 0) goto fail; - if (event_init(&out->update_event, EVENT_TYPE_AUTO) != 0) + if (os_event_init(&out->update_event, OS_EVENT_TYPE_AUTO) != 0) goto fail; if (pthread_create(&out->thread, NULL, video_thread, out) != 0) goto fail; @@ -201,8 +201,8 @@ void video_output_close(video_t video) video_input_free(&video->inputs.array[i]); da_free(video->inputs); - event_destroy(video->update_event); - event_destroy(video->stop_event); + os_event_destroy(video->update_event); + os_event_destroy(video->stop_event); pthread_mutex_destroy(&video->data_mutex); pthread_mutex_destroy(&video->input_mutex); bfree(video); @@ -342,8 +342,8 @@ bool video_output_wait(video_t video) { if (!video) return false; - event_wait(video->update_event); - return event_try(video->stop_event) == EAGAIN; + os_event_wait(video->update_event); + return os_event_try(video->stop_event) == EAGAIN; } uint64_t video_getframetime(video_t video) @@ -364,8 +364,8 @@ void video_output_stop(video_t video) return; if (video->initialized) { - event_signal(video->stop_event); + os_event_signal(video->stop_event); pthread_join(video->thread, &thread_ret); - event_signal(video->update_event); + os_event_signal(video->update_event); } } diff --git a/libobs/util/threading-posix.c b/libobs/util/threading-posix.c index 8b15ddd50..58508b732 100644 --- a/libobs/util/threading-posix.c +++ b/libobs/util/threading-posix.c @@ -16,6 +16,9 @@ #ifdef __APPLE__ #include +#include +#else +#include #endif #include "bmem.h" @@ -45,7 +48,7 @@ int event_init(event_t *event, enum event_type type) return code; } - data->manual = (type == EVENT_TYPE_MANUAL); + data->manual = (type == OS_EVENT_TYPE_MANUAL); data->signalled = false; *event = data; @@ -149,3 +152,84 @@ void event_reset(event_t event) event->signalled = false; pthread_mutex_unlock(&event->mutex); } + +#ifdef __APPLE__ + +struct os_sem_data { + semaphore_t sem; + task_t task; +}; + +int os_sem_init(os_sem_t *sem, int value) +{ + semaphore_t new_sem; + task_t task = mach_task_self(); + + if (semaphore_create(task, &new_sem, 0, value) != KERN_SUCCESS) + return -1; + + *sem = bzalloc(sizeof(struct os_sem_data)); + (*sem)->sem = new_sem; + (*sem)->task = task; + return 0; +} + +void os_sem_destroy(os_sem_t sem) +{ + if (sem) { + semaphore_destroy(sem->task, sem->sem); + bfree(sem); + } +} + +int os_sem_post(os_sem_t sem) +{ + if (!sem) return -1; + return (semaphore_signal(sem->sem) == KERN_SUCCESS) ? 0 : -1; +} + +int os_sem_wait(os_sem_t sem) +{ + if (!sem) return -1; + return (semaphore_wait(sem->sem) == KERN_SUCCESS) ? 0 : -1; +} + +#else + +struct os_sem_data { + sem_t sem; +}; + +int os_sem_init(os_sem_t *sem, int value) +{ + sem_t new_sem; + int ret = sem_init(&new_sem, 0, value); + if (ret != 0) + return ret; + + *sem = bzalloc(sizeof(struct os_sem_data)); + (*sem)->sem = new_sem; + return 0; +} + +void os_sem_destroy(os_sem_t sem) +{ + if (sem) { + semaphore_destroy(&sem->sem); + bfree(sem); + } +} + +int os_sem_post(os_sem_t sem) +{ + if (!sem) return -1; + return sem_post(&sem->sem); +} + +int os_sem_wait(os_sem_t sem) +{ + if (!sem) return -1; + return sem_wait(&sem->sem); +} + +#endif diff --git a/libobs/util/threading-windows.c b/libobs/util/threading-windows.c index c299a8fc2..6aff50da6 100644 --- a/libobs/util/threading-windows.c +++ b/libobs/util/threading-windows.c @@ -20,27 +20,31 @@ #define WIN32_LEAN_AND_MEAN #include -struct event_data { +struct os_event_data { HANDLE handle; }; -int event_init(event_t *event, enum event_type type) +struct os_sem_data { + HANDLE handle; +}; + +int os_event_init(os_event_t *event, enum os_event_type type) { HANDLE handle; - struct event_data *data; + struct os_event_data *data; - handle = CreateEvent(NULL, (type == EVENT_TYPE_MANUAL), FALSE, NULL); + handle = CreateEvent(NULL, (type == OS_EVENT_TYPE_MANUAL), FALSE, NULL); if (!handle) return -1; - data = bmalloc(sizeof(struct event_data)); + data = bmalloc(sizeof(struct os_event_data)); data->handle = handle; *event = data; return 0; } -void event_destroy(event_t event) +void os_event_destroy(os_event_t event) { if (event) { CloseHandle(event->handle); @@ -48,7 +52,7 @@ void event_destroy(event_t event) } } -int event_wait(event_t event) +int os_event_wait(os_event_t event) { DWORD code; @@ -62,7 +66,7 @@ int event_wait(event_t event) return 0; } -int event_timedwait(event_t event, unsigned long milliseconds) +int os_event_timedwait(os_event_t event, unsigned long milliseconds) { DWORD code; @@ -78,7 +82,7 @@ int event_timedwait(event_t event, unsigned long milliseconds) return 0; } -int event_try(event_t event) +int os_event_try(os_event_t event) { DWORD code; @@ -94,7 +98,7 @@ int event_try(event_t event) return 0; } -int event_signal(event_t event) +int os_event_signal(os_event_t event) { if (!event) return EINVAL; @@ -105,10 +109,44 @@ int event_signal(event_t event) return 0; } -void event_reset(event_t event) +void os_event_reset(os_event_t event) { if (!event) return; ResetEvent(event->handle); } + +int os_sem_init(os_sem_t *sem, int value) +{ + HANDLE handle = CreateSemaphore(NULL, (LONG)value, 0x7FFFFFFF, NULL); + if (!handle) + return -1; + + *sem = bzalloc(sizeof(struct os_sem_data)); + (*sem)->handle = handle; + return 0; +} + +void os_sem_destroy(os_sem_t sem) +{ + if (sem) { + CloseHandle(sem->handle); + bfree(sem); + } +} + +int os_sem_post(os_sem_t sem) +{ + if (!sem) return -1; + return ReleaseSemaphore(sem->handle, 1, NULL) ? 0 : -1; +} + +int os_sem_wait(os_sem_t sem) +{ + DWORD ret; + + if (!sem) return -1; + ret = WaitForSingleObject(sem->handle, INFINITE); + return (ret == WAIT_OBJECT_0) ? 0 : -1; +} diff --git a/libobs/util/threading.h b/libobs/util/threading.h index f39b92f60..1ae17cdec 100644 --- a/libobs/util/threading.h +++ b/libobs/util/threading.h @@ -28,11 +28,9 @@ #ifdef _MSC_VER #include "../../deps/w32-pthreads/pthread.h" -#include "../../deps/w32-pthreads/semaphore.h" #else #include #include -#include #endif #ifdef __cplusplus @@ -46,21 +44,28 @@ static inline void pthread_mutex_init_value(pthread_mutex_t *mutex) *mutex = init_val; } -enum event_type { - EVENT_TYPE_AUTO, - EVENT_TYPE_MANUAL +enum os_event_type { + OS_EVENT_TYPE_AUTO, + OS_EVENT_TYPE_MANUAL }; -struct event_data; -typedef struct event_data *event_t; +struct os_event_data; +struct os_sem_data; +typedef struct os_event_data *os_event_t; +typedef struct os_sem_data *os_sem_t; -EXPORT int event_init(event_t *event, enum event_type type); -EXPORT void event_destroy(event_t event); -EXPORT int event_wait(event_t event); -EXPORT int event_timedwait(event_t event, unsigned long milliseconds); -EXPORT int event_try(event_t event); -EXPORT int event_signal(event_t event); -EXPORT void event_reset(event_t event); +EXPORT int os_event_init(os_event_t *event, enum os_event_type type); +EXPORT void os_event_destroy(os_event_t event); +EXPORT int os_event_wait(os_event_t event); +EXPORT int os_event_timedwait(os_event_t event, unsigned long milliseconds); +EXPORT int os_event_try(os_event_t event); +EXPORT int os_event_signal(os_event_t event); +EXPORT void os_event_reset(os_event_t event); + +EXPORT int os_sem_init(os_sem_t *sem, int value); +EXPORT void os_sem_destroy(os_sem_t sem); +EXPORT int os_sem_post(os_sem_t sem); +EXPORT int os_sem_wait(os_sem_t sem); #ifdef __cplusplus diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-output.c b/plugins/obs-ffmpeg/obs-ffmpeg-output.c index 0ed545bbf..700e14a63 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-output.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-output.c @@ -71,8 +71,8 @@ struct ffmpeg_output { bool write_thread_active; pthread_mutex_t write_mutex; pthread_t write_thread; - sem_t write_sem; - event_t stop_event; + os_sem_t write_sem; + os_event_t stop_event; DARRAY(AVPacket) packets; }; @@ -368,12 +368,15 @@ static void ffmpeg_data_free(struct ffmpeg_data *data) memset(data, 0, sizeof(struct ffmpeg_data)); } -static bool ffmpeg_data_init(struct ffmpeg_data *data, const char *filename) +static bool ffmpeg_data_init(struct ffmpeg_data *data, const char *filename, + int vbitrate, int abitrate) { bool is_rtmp = false; memset(data, 0, sizeof(struct ffmpeg_data)); data->filename_test = filename; + data->video_bitrate = vbitrate; + data->audio_bitrate = abitrate; if (!filename || !*filename) return false; @@ -386,8 +389,10 @@ static bool ffmpeg_data_init(struct ffmpeg_data *data, const char *filename) /* TODO: settings */ avformat_alloc_output_context2(&data->output, NULL, is_rtmp ? "flv" : NULL, data->filename_test); - data->output->oformat->video_codec = AV_CODEC_ID_H264; - data->output->oformat->audio_codec = AV_CODEC_ID_AAC; + if (is_rtmp) { + data->output->oformat->video_codec = AV_CODEC_ID_H264; + data->output->oformat->audio_codec = AV_CODEC_ID_AAC; + } if (!data->output) { blog(LOG_WARNING, "Couldn't create avformat context"); @@ -435,9 +440,9 @@ static void *ffmpeg_output_create(obs_data_t settings, obs_output_t output) if (pthread_mutex_init(&data->write_mutex, NULL) != 0) goto fail; - if (event_init(&data->stop_event, EVENT_TYPE_AUTO) != 0) + if (os_event_init(&data->stop_event, OS_EVENT_TYPE_AUTO) != 0) goto fail; - if (sem_init(&data->write_sem, 0, 0) != 0) + if (os_sem_init(&data->write_sem, 0) != 0) goto fail; signal_handler_add(obs_output_signalhandler(output), @@ -450,7 +455,7 @@ static void *ffmpeg_output_create(obs_data_t settings, obs_output_t output) fail: pthread_mutex_destroy(&data->write_mutex); - event_destroy(data->stop_event); + os_event_destroy(data->stop_event); bfree(data); return NULL; } @@ -468,8 +473,8 @@ static void ffmpeg_output_destroy(void *data) ffmpeg_output_stop(output); pthread_mutex_destroy(&output->write_mutex); - sem_destroy(&output->write_sem); - event_destroy(output->stop_event); + os_sem_destroy(output->write_sem); + os_event_destroy(output->stop_event); bfree(data); } } @@ -535,7 +540,7 @@ static void receive_video(void *param, const struct video_data *frame) pthread_mutex_lock(&output->write_mutex); da_push_back(output->packets, &packet); pthread_mutex_unlock(&output->write_mutex); - sem_post(&output->write_sem); + os_sem_post(output->write_sem); } else { data->vframe->pts = data->total_frames; @@ -559,7 +564,7 @@ static void receive_video(void *param, const struct video_data *frame) pthread_mutex_lock(&output->write_mutex); da_push_back(output->packets, &packet); pthread_mutex_unlock(&output->write_mutex); - sem_post(&output->write_sem); + os_sem_post(output->write_sem); } else { ret = 0; } @@ -618,7 +623,7 @@ static inline void encode_audio(struct ffmpeg_output *output, pthread_mutex_lock(&output->write_mutex); da_push_back(output->packets, &packet); pthread_mutex_unlock(&output->write_mutex); - sem_post(&output->write_sem); + os_sem_post(output->write_sem); } static bool prepare_audio(struct ffmpeg_data *data, @@ -680,7 +685,6 @@ static bool process_packet(struct ffmpeg_output *output) { AVPacket packet; bool new_packet = false; - uint64_t time1, time2; int ret; pthread_mutex_lock(&output->write_mutex); @@ -694,7 +698,10 @@ static bool process_packet(struct ffmpeg_output *output) if (!new_packet) return true; - time1 = os_gettime_ns(); + /*blog(LOG_DEBUG, "size = %d, flags = %lX, stream = %d, " + "packets queued: %lu", + packet.size, packet.flags, + packet.stream_index, output->packets.num);*/ ret = av_interleaved_write_frame(output->ff_data.output, &packet); if (ret < 0) { @@ -706,12 +713,6 @@ static bool process_packet(struct ffmpeg_output *output) return false; } - time2 = os_gettime_ns(); - /*blog(LOG_DEBUG, "%llu, size = %d, flags = %lX, stream = %d, " - "packets queued: %lu: time1; %llu", - time2-time1, packet.size, packet.flags, - packet.stream_index, output->packets.num, time1);*/ - return true; } @@ -719,9 +720,9 @@ static void *write_thread(void *data) { struct ffmpeg_output *output = data; - while (sem_wait(&output->write_sem) == 0) { + while (os_sem_wait(output->write_sem) == 0) { /* check to see if shutting down */ - if (event_try(output->stop_event) == 0) + if (os_event_try(output->stop_event) == 0) break; if (!process_packet(output)) { @@ -758,10 +759,8 @@ static bool try_connect(struct ffmpeg_output *output) if (!filename_test || !*filename_test) return false; - output->ff_data.video_bitrate = video_bitrate; - output->ff_data.audio_bitrate = audio_bitrate; - - if (!ffmpeg_data_init(&output->ff_data, filename_test)) + if (!ffmpeg_data_init(&output->ff_data, filename_test, + video_bitrate, audio_bitrate)) return false; struct audio_convert_info aci = { @@ -827,8 +826,8 @@ static void ffmpeg_output_stop(void *data) audio_output_disconnect(obs_audio(), receive_audio, data); if (output->write_thread_active) { - event_signal(output->stop_event); - sem_post(&output->write_sem); + os_event_signal(output->stop_event); + os_sem_post(output->write_sem); pthread_join(output->write_thread, NULL); output->write_thread_active = false; } diff --git a/test/test-input/test-sinewave.c b/test/test-input/test-sinewave.c index ebba14efd..dae293483 100644 --- a/test/test-input/test-sinewave.c +++ b/test/test-input/test-sinewave.c @@ -7,7 +7,7 @@ struct sinewave_data { bool initialized_thread; pthread_t thread; - event_t event; + os_event_t event; obs_source_t source; }; @@ -28,7 +28,7 @@ static void *sinewave_thread(void *pdata) double cos_val = 0.0; uint8_t bytes[480]; - while (event_try(swd->event) == EAGAIN) { + while (os_event_try(swd->event) == EAGAIN) { if (!os_sleepto_ns(last_time += 10000000)) last_time = os_gettime_ns(); @@ -71,11 +71,11 @@ static void sinewave_destroy(void *data) if (swd) { if (swd->initialized_thread) { void *ret; - event_signal(swd->event); + os_event_signal(swd->event); pthread_join(swd->thread, &ret); } - event_destroy(swd->event); + os_event_destroy(swd->event); bfree(swd); } } @@ -86,7 +86,7 @@ static void *sinewave_create(obs_data_t settings, struct sinewave_data *swd = bzalloc(sizeof(struct sinewave_data)); swd->source = source; - if (event_init(&swd->event, EVENT_TYPE_MANUAL) != 0) + if (os_event_init(&swd->event, OS_EVENT_TYPE_MANUAL) != 0) goto fail; if (pthread_create(&swd->thread, NULL, sinewave_thread, swd) != 0) goto fail;