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.
This commit is contained in:
jp9000 2014-03-10 19:04:00 -07:00
parent faabeff743
commit 585fd8f969
7 changed files with 203 additions and 77 deletions

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -16,6 +16,9 @@
#ifdef __APPLE__
#include <sys/time.h>
#include <mach/semaphore.h>
#else
#include <semaphore.h>
#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

View File

@ -20,27 +20,31 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
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;
}

View File

@ -28,11 +28,9 @@
#ifdef _MSC_VER
#include "../../deps/w32-pthreads/pthread.h"
#include "../../deps/w32-pthreads/semaphore.h"
#else
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#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

View File

@ -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;
}

View File

@ -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;