mirror of https://github.com/mpv-player/mpv
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.
This commit is contained in:
parent
b48d09a89d
commit
5ffd6a9e9b
|
@ -102,12 +102,14 @@ static int init(struct ao *ao)
|
|||
return -1;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&ao->encode_lavc_ctx->lock);
|
||||
|
||||
ac->stream = encode_lavc_alloc_stream(ao->encode_lavc_ctx,
|
||||
AVMEDIA_TYPE_AUDIO);
|
||||
|
||||
if (!ac->stream) {
|
||||
MP_ERR(ao, "could not get a new audio stream\n");
|
||||
return -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
codec = encode_lavc_get_codec(ao->encode_lavc_ctx, ac->stream);
|
||||
|
@ -126,7 +128,7 @@ static int init(struct ao *ao)
|
|||
struct mp_chmap_sel sel = {0};
|
||||
mp_chmap_sel_add_any(&sel);
|
||||
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
|
||||
return -1;
|
||||
goto fail;
|
||||
mp_chmap_reorder_to_lavc(&ao->channels);
|
||||
ac->stream->codec->channels = ao->channels.num;
|
||||
ac->stream->codec->channel_layout = mp_chmap_to_lavc(&ao->channels);
|
||||
|
@ -140,7 +142,7 @@ static int init(struct ao *ao)
|
|||
ac->stream->codec->bits_per_raw_sample = ac->sample_size * 8;
|
||||
|
||||
if (encode_lavc_open_codec(ao->encode_lavc_ctx, ac->stream) < 0)
|
||||
return -1;
|
||||
goto fail;
|
||||
|
||||
ac->pcmhack = 0;
|
||||
if (ac->stream->codec->frame_size <= 1)
|
||||
|
@ -169,7 +171,12 @@ static int init(struct ao *ao)
|
|||
|
||||
ao->untimed = true;
|
||||
|
||||
pthread_mutex_unlock(&ao->encode_lavc_ctx->lock);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
pthread_mutex_unlock(&ao->encode_lavc_ctx->lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// close audio device
|
||||
|
@ -179,8 +186,11 @@ static void uninit(struct ao *ao, bool cut_audio)
|
|||
struct priv *ac = ao->priv;
|
||||
struct encode_lavc_context *ectx = ao->encode_lavc_ctx;
|
||||
|
||||
pthread_mutex_lock(&ectx->lock);
|
||||
|
||||
if (!encode_lavc_start(ectx)) {
|
||||
MP_WARN(ao, "not even ready to encode audio at end -> dropped");
|
||||
pthread_mutex_unlock(&ectx->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -192,7 +202,7 @@ static void uninit(struct ao *ao, bool cut_audio)
|
|||
while (encode(ao, outpts, NULL) > 0) ;
|
||||
}
|
||||
|
||||
ao->priv = NULL;
|
||||
pthread_mutex_unlock(&ectx->lock);
|
||||
}
|
||||
|
||||
// return: how many bytes can be played without blocking
|
||||
|
@ -323,8 +333,11 @@ static int play(struct ao *ao, void **data, int samples, int flags)
|
|||
double nextpts;
|
||||
double outpts;
|
||||
|
||||
pthread_mutex_lock(&ectx->lock);
|
||||
|
||||
if (!encode_lavc_start(ectx)) {
|
||||
MP_WARN(ao, "not ready yet for encoding audio\n");
|
||||
pthread_mutex_unlock(&ectx->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -354,6 +367,7 @@ static int play(struct ao *ao, void **data, int samples, int flags)
|
|||
talloc_free(tmp);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&ectx->lock);
|
||||
return FFMIN(written, samples);
|
||||
}
|
||||
|
||||
|
@ -444,6 +458,7 @@ static int play(struct ao *ao, void **data, int samples, int flags)
|
|||
ectx->next_in_pts = nextpts;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&ectx->lock);
|
||||
return bufpos;
|
||||
}
|
||||
|
||||
|
|
|
@ -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, ...)
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#ifndef MPLAYER_ENCODE_LAVC_H
|
||||
#define MPLAYER_ENCODE_LAVC_H
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/avstring.h>
|
||||
|
@ -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
|
||||
|
|
|
@ -74,19 +74,21 @@ static int preinit(struct vo *vo)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void draw_image(struct vo *vo, mp_image_t *mpi);
|
||||
static void draw_image_unlocked(struct vo *vo, mp_image_t *mpi);
|
||||
static void uninit(struct vo *vo)
|
||||
{
|
||||
struct priv *vc = vo->priv;
|
||||
if (!vc)
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&vo->encode_lavc_ctx->lock);
|
||||
|
||||
if (vc->lastipts >= 0 && vc->stream)
|
||||
draw_image(vo, NULL);
|
||||
draw_image_unlocked(vo, NULL);
|
||||
|
||||
mp_image_unrefp(&vc->lastimg);
|
||||
|
||||
vo->priv = NULL;
|
||||
pthread_mutex_unlock(&vo->encode_lavc_ctx->lock);
|
||||
}
|
||||
|
||||
static int reconfig(struct vo *vo, struct mp_image_params *params, int flags)
|
||||
|
@ -101,6 +103,8 @@ static int reconfig(struct vo *vo, struct mp_image_params *params, int flags)
|
|||
if (!vc)
|
||||
return -1;
|
||||
|
||||
pthread_mutex_lock(&vo->encode_lavc_ctx->lock);
|
||||
|
||||
display_aspect_ratio.num = params->d_w;
|
||||
display_aspect_ratio.den = params->d_h;
|
||||
image_aspect_ratio.num = width;
|
||||
|
@ -123,7 +127,7 @@ static int reconfig(struct vo *vo, struct mp_image_params *params, int flags)
|
|||
vc->stream->codec->sample_aspect_ratio.den,
|
||||
aspect.num, aspect.den);
|
||||
}
|
||||
return 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* FIXME Is it possible with raw video? */
|
||||
|
@ -168,9 +172,12 @@ static int reconfig(struct vo *vo, struct mp_image_params *params, int flags)
|
|||
|
||||
mp_image_unrefp(&vc->lastimg);
|
||||
|
||||
done:
|
||||
pthread_mutex_unlock(&vo->encode_lavc_ctx->lock);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
pthread_mutex_unlock(&vo->encode_lavc_ctx->lock);
|
||||
uninit(vo);
|
||||
return -1;
|
||||
}
|
||||
|
@ -182,14 +189,12 @@ static int query_format(struct vo *vo, uint32_t format)
|
|||
if (!vo->encode_lavc_ctx)
|
||||
return 0;
|
||||
|
||||
if (!encode_lavc_supports_pixfmt(vo->encode_lavc_ctx, pix_fmt))
|
||||
return 0;
|
||||
|
||||
return
|
||||
VFCAP_CSP_SUPPORTED |
|
||||
// we can do it
|
||||
VFCAP_CSP_SUPPORTED_BY_HW;
|
||||
// we don't convert colorspaces here
|
||||
pthread_mutex_lock(&vo->encode_lavc_ctx->lock);
|
||||
int flags = 0;
|
||||
if (encode_lavc_supports_pixfmt(vo->encode_lavc_ctx, pix_fmt))
|
||||
flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW;
|
||||
pthread_mutex_unlock(&vo->encode_lavc_ctx->lock);
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void write_packet(struct vo *vo, int size, AVPacket *packet)
|
||||
|
@ -272,7 +277,7 @@ static int encode_video(struct vo *vo, AVFrame *frame, AVPacket *packet)
|
|||
}
|
||||
}
|
||||
|
||||
static void draw_image(struct vo *vo, mp_image_t *mpi)
|
||||
static void draw_image_unlocked(struct vo *vo, mp_image_t *mpi)
|
||||
{
|
||||
struct priv *vc = vo->priv;
|
||||
struct encode_lavc_context *ectx = vo->encode_lavc_ctx;
|
||||
|
@ -479,6 +484,13 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
|
|||
}
|
||||
}
|
||||
|
||||
static void draw_image(struct vo *vo, mp_image_t *mpi)
|
||||
{
|
||||
pthread_mutex_lock(&vo->encode_lavc_ctx->lock);
|
||||
draw_image_unlocked(vo, mpi);
|
||||
pthread_mutex_unlock(&vo->encode_lavc_ctx->lock);
|
||||
}
|
||||
|
||||
static void flip_page_timed(struct vo *vo, int64_t pts_us, int duration)
|
||||
{
|
||||
}
|
||||
|
@ -487,6 +499,8 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
|
|||
{
|
||||
struct priv *vc = vo->priv;
|
||||
|
||||
pthread_mutex_lock(&vo->encode_lavc_ctx->lock);
|
||||
|
||||
if (vc->lastimg && vc->lastimg_wants_osd && vo->params) {
|
||||
struct mp_osd_res dim = osd_res_from_image_params(vo->params);
|
||||
|
||||
|
@ -495,11 +509,15 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
|
|||
osd_draw_on_image(osd, dim, osd_get_vo_pts(osd), OSD_DRAW_SUB_ONLY,
|
||||
vc->lastimg);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&vo->encode_lavc_ctx->lock);
|
||||
}
|
||||
|
||||
static int control(struct vo *vo, uint32_t request, void *data)
|
||||
{
|
||||
struct priv *vc = vo->priv;
|
||||
int r = VO_NOTIMPL;
|
||||
pthread_mutex_lock(&vo->encode_lavc_ctx->lock);
|
||||
switch (request) {
|
||||
case VOCTRL_SET_YUV_COLORSPACE:
|
||||
vc->colorspace = *(struct mp_csp_details *)data;
|
||||
|
@ -509,12 +527,15 @@ static int control(struct vo *vo, uint32_t request, void *data)
|
|||
vc->colorspace.format = encode_lavc_get_csp(vo->encode_lavc_ctx, vc->stream);
|
||||
vc->colorspace.levels_out = encode_lavc_get_csp_levels(vo->encode_lavc_ctx, vc->stream);
|
||||
}
|
||||
return 1;
|
||||
r = 1;
|
||||
break;
|
||||
case VOCTRL_GET_YUV_COLORSPACE:
|
||||
*(struct mp_csp_details *)data = vc->colorspace;
|
||||
return 1;
|
||||
r = 1;
|
||||
break;
|
||||
}
|
||||
return VO_NOTIMPL;
|
||||
pthread_mutex_unlock(&vo->encode_lavc_ctx->lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
const struct vo_driver video_out_lavc = {
|
||||
|
|
Loading…
Reference in New Issue