From 4e10eeda09601b06b20064089e9aa8e59fcb1239 Mon Sep 17 00:00:00 2001 From: jp9000 Date: Fri, 28 Feb 2014 03:50:30 -0700 Subject: [PATCH] Wrap FFmpeg operations in mutexes, switch to MP4 I can't believe I wasn't doing this. This is why file output was getting corrupted. Audio and video send in data from separate threads. I should be embarassed for not having considered that. Key lesson: Increase threading paranoia levels. Apparently my threading paranoid levels are lackluster. --- obs/window-basic-main.cpp | 2 +- plugins/obs-ffmpeg/obs-ffmpeg-output.c | 19 ++++++++++++++++++- vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj | 8 ++++---- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/obs/window-basic-main.cpp b/obs/window-basic-main.cpp index 3b241eb4d..7f3887344 100644 --- a/obs/window-basic-main.cpp +++ b/obs/window-basic-main.cpp @@ -601,7 +601,7 @@ void OBSBasic::on_recordButton_clicked() } else { QString path = QFileDialog::getSaveFileName(this, "Please enter a file name", QString(), - "AVI Files (*.avi)"); + "MP4 Files (*.mp4)"); if (path.isNull() || path.isEmpty()) return; diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-output.c b/plugins/obs-ffmpeg/obs-ffmpeg-output.c index 68297f764..ca4bea962 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-output.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-output.c @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -49,6 +50,8 @@ struct ffmpeg_data { AVFrame *aframe; int total_samples; + pthread_mutex_t write_mutex; + const char *filename_test; bool initialized; @@ -332,6 +335,7 @@ static void close_audio(struct ffmpeg_data *data) static void ffmpeg_data_free(struct ffmpeg_data *data) { + pthread_mutex_lock(&data->write_mutex); if (data->initialized) av_write_trailer(data->output); @@ -344,17 +348,25 @@ static void ffmpeg_data_free(struct ffmpeg_data *data) avformat_free_context(data->output); + pthread_mutex_unlock(&data->write_mutex); + pthread_mutex_destroy(&data->write_mutex); + memset(data, 0, sizeof(struct ffmpeg_data)); } static bool ffmpeg_data_init(struct ffmpeg_data *data, const char *filename) { memset(data, 0, sizeof(struct ffmpeg_data)); + pthread_mutex_init_value(&data->write_mutex); + data->filename_test = filename; if (!filename || !*filename) return false; + if (pthread_mutex_init(&data->write_mutex, NULL) != 0) + return false; + av_register_all(); /* TODO: settings */ @@ -390,7 +402,6 @@ static const char *ffmpeg_output_getname(const char *locale) static void ffmpeg_log_callback(void *param, int level, const char *format, va_list args) { - if (level < AV_LOG_WARNING) blogva(LOG_DEBUG, format, args); UNUSED_PARAMETER(param); @@ -476,7 +487,9 @@ static void receive_video(void *param, const struct video_data *frame) packet.data = data->dst_picture.data[0]; packet.size = sizeof(AVPicture); + pthread_mutex_lock(&data->write_mutex); ret = av_interleaved_write_frame(data->output, &packet); + pthread_mutex_unlock(&data->write_mutex); } else { data->vframe->pts = data->total_frames; @@ -497,8 +510,10 @@ static void receive_video(void *param, const struct video_data *frame) context->time_base, data->video->time_base); + pthread_mutex_lock(&data->write_mutex); ret = av_interleaved_write_frame(data->output, &packet); + pthread_mutex_unlock(&data->write_mutex); } else { ret = 0; } @@ -552,10 +567,12 @@ static inline void encode_audio(struct ffmpeg_data *output, output->audio->time_base); packet.stream_index = output->audio->index; + pthread_mutex_lock(&output->write_mutex); ret = av_interleaved_write_frame(output->output, &packet); if (ret != 0) blog(LOG_ERROR, "receive_audio: Error writing audio: %s", av_err2str(ret)); + pthread_mutex_unlock(&output->write_mutex); } static bool prepare_audio(struct ffmpeg_data *data, diff --git a/vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj b/vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj index b29fc4c6a..2bfb22298 100644 --- a/vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj +++ b/vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj @@ -99,7 +99,7 @@ Windows true $(OutDir);%(AdditionalLibraryDirectories) - avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies) + pthreads.lib;avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies) copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/32bit/$(TargetName)$(TargetExt)" @@ -118,7 +118,7 @@ Windows true $(OutDir);%(AdditionalLibraryDirectories) - avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies) + pthreads.lib;avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies) copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/64bit/$(TargetName)$(TargetExt)" @@ -141,7 +141,7 @@ true true $(OutDir);%(AdditionalLibraryDirectories) - avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies) + pthreads.lib;avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies) copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/32bit/$(TargetName)$(TargetExt)" @@ -164,7 +164,7 @@ true true $(OutDir);%(AdditionalLibraryDirectories) - avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies) + pthreads.lib;avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies) copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/64bit/$(TargetName)$(TargetExt)"