From 5ffd6a9e9b7a0d894d7513ad20c24c2727426ecd Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 8 Mar 2014 23:38:53 +0100 Subject: encode: add locking Since the AO will run in a thread, and there's lots of shared state with encoding, we have to add locking. One case this doesn't handle correctly are the encode_lavc_available() calls in ao_lavc.c and vo_lavc.c. They don't do much (and usually only to protect against doing --ao=lavc with normal playback), and changing it would be a bit messy. So just leave them. --- common/encode_lavc.c | 40 ++++++++++++++++++++++++++++++++++++---- common/encode_lavc.h | 7 +++++++ 2 files changed, 43 insertions(+), 4 deletions(-) (limited to 'common') diff --git a/common/encode_lavc.c b/common/encode_lavc.c index 5f9e2a0390..5d9853673b 100644 --- a/common/encode_lavc.c +++ b/common/encode_lavc.c @@ -103,6 +103,15 @@ static bool value_has_flag(const char *value, const char *flag) return val; \ } +#define CHECK_FAIL_UNLOCK(ctx, val) \ + if (ctx && (ctx->failed || ctx->finished)) { \ + MP_ERR(ctx, \ + "Called a function on a %s encoding context. Bailing out.\n", \ + ctx->failed ? "failed" : "finished"); \ + pthread_mutex_unlock(&ctx->lock); \ + return val; \ + } + int encode_lavc_available(struct encode_lavc_context *ctx) { CHECK_FAIL(ctx, 0); @@ -134,6 +143,7 @@ struct encode_lavc_context *encode_lavc_init(struct encode_output_conf *options, mp_msg_force_stderr(global, true); ctx = talloc_zero(NULL, struct encode_lavc_context); + pthread_mutex_init(&ctx->lock, NULL); ctx->log = mp_log_new(ctx, global->log, "encode-lavc"); ctx->global = global; encode_lavc_discontinuity(ctx); @@ -309,6 +319,7 @@ void encode_lavc_free(struct encode_lavc_context *ctx) encode_lavc_fail(ctx, "called encode_lavc_free without encode_lavc_finish\n"); + pthread_mutex_destroy(&ctx->lock); talloc_free(ctx); } @@ -383,14 +394,18 @@ void encode_lavc_finish(struct encode_lavc_context *ctx) void encode_lavc_set_video_fps(struct encode_lavc_context *ctx, float fps) { + pthread_mutex_lock(&ctx->lock); ctx->vo_fps = fps; + pthread_mutex_unlock(&ctx->lock); } void encode_lavc_set_audio_pts(struct encode_lavc_context *ctx, double pts) { if (ctx) { + pthread_mutex_lock(&ctx->lock); ctx->last_audio_in_pts = pts; ctx->samples_since_last_pts = 0; + pthread_mutex_unlock(&ctx->lock); } } @@ -780,11 +795,15 @@ void encode_lavc_discontinuity(struct encode_lavc_context *ctx) if (!ctx) return; - CHECK_FAIL(ctx, ); + pthread_mutex_lock(&ctx->lock); + + CHECK_FAIL_UNLOCK(ctx, ); ctx->audio_pts_offset = MP_NOPTS_VALUE; ctx->last_video_in_pts = MP_NOPTS_VALUE; ctx->discontinuity_pts_offset = MP_NOPTS_VALUE; + + pthread_mutex_unlock(&ctx->lock); } static void encode_lavc_printoptions(struct mp_log *log, void *obj, @@ -1013,7 +1032,9 @@ int encode_lavc_getstatus(struct encode_lavc_context *ctx, if (!ctx) return -1; - CHECK_FAIL(ctx, -1); + pthread_mutex_lock(&ctx->lock); + + CHECK_FAIL_UNLOCK(ctx, -1); minutes = (now - ctx->t0) / 60.0 * (1 - f) / f; megabytes = ctx->avc->pb ? (avio_size(ctx->avc->pb) / 1048576.0 / f) : 0; @@ -1029,12 +1050,16 @@ int encode_lavc_getstatus(struct encode_lavc_context *ctx, snprintf(buf, bufsize, "{%.1fmin %.1fMB}", minutes, megabytes); buf[bufsize - 1] = 0; + + pthread_mutex_unlock(&ctx->lock); return 0; } void encode_lavc_expect_stream(struct encode_lavc_context *ctx, int mt) { - CHECK_FAIL(ctx, ); + pthread_mutex_lock(&ctx->lock); + + CHECK_FAIL_UNLOCK(ctx, ); switch (mt) { case AVMEDIA_TYPE_VIDEO: @@ -1044,11 +1069,18 @@ void encode_lavc_expect_stream(struct encode_lavc_context *ctx, int mt) ctx->expect_audio = true; break; } + + pthread_mutex_unlock(&ctx->lock); } bool encode_lavc_didfail(struct encode_lavc_context *ctx) { - return ctx && ctx->failed; + if (!ctx) + return false; + pthread_mutex_lock(&ctx->lock); + bool fail = ctx && ctx->failed; + pthread_mutex_unlock(&ctx->lock); + return fail; } void encode_lavc_fail(struct encode_lavc_context *ctx, const char *format, ...) diff --git a/common/encode_lavc.h b/common/encode_lavc.h index deaf42b684..af7f4fba3d 100644 --- a/common/encode_lavc.h +++ b/common/encode_lavc.h @@ -22,6 +22,8 @@ #ifndef MPLAYER_ENCODE_LAVC_H #define MPLAYER_ENCODE_LAVC_H +#include + #include #include #include @@ -37,6 +39,11 @@ struct encode_lavc_context { struct encode_output_conf *options; struct mp_log *log; + // All entry points must be guarded with the lock. Functions called by + // the playback core lock this automatically, but ao_lavc.c and vo_lavc.c + // must lock manually before accessing state. + pthread_mutex_t lock; + float vo_fps; // these are processed from the options -- cgit v1.2.3