diff options
Diffstat (limited to 'common/encode_lavc.c')
-rw-r--r-- | common/encode_lavc.c | 197 |
1 files changed, 85 insertions, 112 deletions
diff --git a/common/encode_lavc.c b/common/encode_lavc.c index 94428c6733..33743007dd 100644 --- a/common/encode_lavc.c +++ b/common/encode_lavc.c @@ -23,7 +23,6 @@ #include <libavutil/avutil.h> #include <libavutil/timestamp.h> -#include "config.h" #include "encode_lavc.h" #include "common/av_common.h" #include "common/global.h" @@ -77,38 +76,22 @@ struct mux_stream { #define OPT_BASE_STRUCT struct encode_opts const struct m_sub_options encode_config = { .opts = (const m_option_t[]) { - {"o", OPT_STRING(file), .flags = CONF_NOCFG | CONF_PRE_PARSE | M_OPT_FILE, - .deprecation_message = "lack of maintainer"}, + {"o", OPT_STRING(file), .flags = CONF_NOCFG | CONF_PRE_PARSE | M_OPT_FILE}, {"of", OPT_STRING(format)}, {"ofopts", OPT_KEYVALUELIST(fopts), .flags = M_OPT_HAVE_HELP}, {"ovc", OPT_STRING(vcodec)}, {"ovcopts", OPT_KEYVALUELIST(vopts), .flags = M_OPT_HAVE_HELP}, {"oac", OPT_STRING(acodec)}, {"oacopts", OPT_KEYVALUELIST(aopts), .flags = M_OPT_HAVE_HELP}, - {"ovoffset", OPT_FLOAT(voffset), M_RANGE(-1000000.0, 1000000.0), - .deprecation_message = "--audio-delay (once unbroken)"}, - {"oaoffset", OPT_FLOAT(aoffset), M_RANGE(-1000000.0, 1000000.0), - .deprecation_message = "--audio-delay (once unbroken)"}, - {"orawts", OPT_FLAG(rawts)}, - {"ovfirst", OPT_FLAG(video_first), - .deprecation_message = "no replacement"}, - {"oafirst", OPT_FLAG(audio_first), - .deprecation_message = "no replacement"}, - {"ocopy-metadata", OPT_FLAG(copy_metadata)}, + {"orawts", OPT_BOOL(rawts)}, + {"ocopy-metadata", OPT_BOOL(copy_metadata)}, {"oset-metadata", OPT_KEYVALUELIST(set_metadata)}, {"oremove-metadata", OPT_STRINGLIST(remove_metadata)}, - - {"ocopyts", OPT_REMOVED("ocopyts is now the default")}, - {"oneverdrop", OPT_REMOVED("no replacement")}, - {"oharddup", OPT_REMOVED("use --vf-add=fps=VALUE")}, - {"ofps", OPT_REMOVED("no replacement (use --vf-add=fps=VALUE for CFR)")}, - {"oautofps", OPT_REMOVED("no replacement")}, - {"omaxfps", OPT_REMOVED("no replacement")}, {0} }, .size = sizeof(struct encode_opts), .defaults = &(const struct encode_opts){ - .copy_metadata = 1, + .copy_metadata = true, }, }; @@ -121,7 +104,7 @@ struct encode_lavc_context *encode_lavc_init(struct mpv_global *global) .priv = talloc_zero(ctx, struct encode_priv), .log = mp_log_new(ctx, global->log, "encode"), }; - pthread_mutex_init(&ctx->lock, NULL); + mp_mutex_init(&ctx->lock); struct encode_priv *p = ctx->priv; p->log = ctx->log; @@ -134,12 +117,6 @@ struct encode_lavc_context *encode_lavc_init(struct mpv_global *global) if (!strcmp(filename, "-")) filename = "pipe:1"; - if (filename && ( - !strcmp(filename, "/dev/stdout") || - !strcmp(filename, "pipe:") || - !strcmp(filename, "pipe:1"))) - mp_msg_force_stderr(global, true); - encode_lavc_discontinuity(ctx); p->muxer = avformat_alloc_context(); @@ -174,7 +151,7 @@ void encode_lavc_set_metadata(struct encode_lavc_context *ctx, { struct encode_priv *p = ctx->priv; - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); if (ctx->options->copy_metadata) { p->metadata = mp_tags_dup(ctx, metadata); @@ -201,7 +178,7 @@ void encode_lavc_set_metadata(struct encode_lavc_context *ctx, } } - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); } bool encode_lavc_free(struct encode_lavc_context *ctx) @@ -237,22 +214,12 @@ bool encode_lavc_free(struct encode_lavc_context *ctx) res = !p->failed; - pthread_mutex_destroy(&ctx->lock); + mp_mutex_destroy(&ctx->lock); talloc_free(ctx); return res; } -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); - } -} - // called locked static void maybe_init_muxer(struct encode_lavc_context *ctx) { @@ -340,7 +307,7 @@ void encode_lavc_expect_stream(struct encode_lavc_context *ctx, { struct encode_priv *p = ctx->priv; - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); enum AVMediaType codec_type = mp_to_av_stream_type(type); @@ -364,32 +331,7 @@ void encode_lavc_expect_stream(struct encode_lavc_context *ctx, MP_TARRAY_APPEND(p, p->streams, p->num_streams, dst); done: - pthread_mutex_unlock(&ctx->lock); -} - -void encode_lavc_stream_eof(struct encode_lavc_context *ctx, - enum stream_type type) -{ - if (!ctx) - return; - - struct encode_priv *p = ctx->priv; - - pthread_mutex_lock(&ctx->lock); - - enum AVMediaType codec_type = mp_to_av_stream_type(type); - struct mux_stream *dst = find_mux_stream(ctx, codec_type); - - // If we've reached EOF, even though the stream was selected, and we didn't - // ever initialize it, we have a problem. We could mux some sort of dummy - // stream (and could fail if actual data arrives later), or we bail out - // early. - if (dst && !dst->st) { - MP_ERR(p, "No data on stream %s.\n", dst->name); - p->failed = true; - } - - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); } // Signal that you are ready to encode (you provide the codec params etc. too). @@ -403,7 +345,7 @@ static void encode_lavc_add_stream(struct encoder_context *enc, { struct encode_priv *p = ctx->priv; - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); struct mux_stream *dst = find_mux_stream(ctx, info->codecpar->codec_type); if (!dst) { @@ -439,7 +381,7 @@ static void encode_lavc_add_stream(struct encoder_context *enc, maybe_init_muxer(ctx); done: - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); } // Write a packet. This will take over ownership of `pkt` @@ -450,7 +392,7 @@ static void encode_lavc_add_packet(struct mux_stream *dst, AVPacket *pkt) assert(dst->st); - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); if (p->failed) goto done; @@ -487,7 +429,7 @@ static void encode_lavc_add_packet(struct mux_stream *dst, AVPacket *pkt) pkt = NULL; done: - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); if (pkt) av_packet_unref(pkt); } @@ -502,12 +444,9 @@ void encode_lavc_discontinuity(struct encode_lavc_context *ctx) if (!ctx) return; - pthread_mutex_lock(&ctx->lock); - - ctx->audio_pts_offset = MP_NOPTS_VALUE; + mp_mutex_lock(&ctx->lock); ctx->discontinuity_pts_offset = MP_NOPTS_VALUE; - - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); } static void encode_lavc_printoptions(struct mp_log *log, const void *obj, @@ -728,7 +667,7 @@ int encode_lavc_getstatus(struct encode_lavc_context *ctx, float minutes, megabytes, fps, x; float f = MPMAX(0.0001, relative_position); - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); if (p->failed) { snprintf(buf, bufsize, "(failed)\n"); @@ -752,7 +691,7 @@ int encode_lavc_getstatus(struct encode_lavc_context *ctx, buf[bufsize - 1] = 0; done: - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); return 0; } @@ -760,9 +699,9 @@ bool encode_lavc_didfail(struct encode_lavc_context *ctx) { if (!ctx) return false; - pthread_mutex_lock(&ctx->lock); + mp_mutex_lock(&ctx->lock); bool fail = ctx->priv->failed; - pthread_mutex_unlock(&ctx->lock); + mp_mutex_unlock(&ctx->lock); return fail; } @@ -770,10 +709,53 @@ static void encoder_destroy(void *ptr) { struct encoder_context *p = ptr; + av_packet_free(&p->pkt); + avcodec_parameters_free(&p->info.codecpar); avcodec_free_context(&p->encoder); free_stream(p->twopass_bytebuffer); } +static const AVCodec *find_codec_for(struct encode_lavc_context *ctx, + enum stream_type type, bool *used_auto) +{ + char *codec_name = type == STREAM_VIDEO + ? ctx->options->vcodec + : ctx->options->acodec; + enum AVMediaType codec_type = mp_to_av_stream_type(type); + const char *tname = stream_type_name(type); + + *used_auto = !(codec_name && codec_name[0]); + + const AVCodec *codec; + if (*used_auto) { + codec = avcodec_find_encoder(av_guess_codec(ctx->oformat, NULL, + ctx->options->file, NULL, + codec_type)); + } else { + codec = avcodec_find_encoder_by_name(codec_name); + if (!codec) + MP_FATAL(ctx, "codec '%s' not found.\n", codec_name); + } + + if (codec && codec->type != codec_type) { + MP_FATAL(ctx, "codec for %s has wrong media type\n", tname); + codec = NULL; + } + + return codec; +} + +// Return whether the stream type is "supposed" to work. +bool encode_lavc_stream_type_ok(struct encode_lavc_context *ctx, + enum stream_type type) +{ + // If a codec was forced, let it proceed to actual encoding, and then error + // if it doesn't work. (Worried that av_guess_codec() may return NULL for + // some formats where a specific codec works anyway.) + bool auto_codec; + return !!find_codec_for(ctx, type, &auto_codec) || !auto_codec; +} + struct encoder_context *encoder_context_alloc(struct encode_lavc_context *ctx, enum stream_type type, struct mp_log *log) @@ -794,27 +776,13 @@ struct encoder_context *encoder_context_alloc(struct encode_lavc_context *ctx, .encode_lavc_ctx = ctx, }; - char *codec_name = type == STREAM_VIDEO - ? p->options->vcodec - : p->options->acodec; - enum AVMediaType codec_type = mp_to_av_stream_type(type); + bool auto_codec; + const AVCodec *codec = find_codec_for(ctx, type, &auto_codec); const char *tname = stream_type_name(type); - AVCodec *codec; - if (codec_name&& codec_name[0]) { - codec = avcodec_find_encoder_by_name(codec_name); - } else { - codec = avcodec_find_encoder(av_guess_codec(p->oformat, NULL, - p->options->file, NULL, - codec_type)); - } - if (!codec) { - MP_FATAL(p, "codec for %s not found\n", tname); - goto fail; - } - if (codec->type != codec_type) { - MP_FATAL(p, "codec for %s has wrong media type\n", tname); + if (auto_codec) + MP_FATAL(p, "codec for %s not found\n", tname); goto fail; } @@ -896,8 +864,8 @@ bool encoder_init_codec_and_muxer(struct encoder_context *p, " ********************************************\n\n" "This means the output file may be broken or bad.\n" "Possible reasons, problems, workarounds:\n" - "- Codec implementation in ffmpeg/libav is not finished yet.\n" - " Try updating ffmpeg or libav.\n" + "- Codec implementation in ffmpeg is not finished yet.\n" + " Try updating ffmpeg.\n" "- Bad picture quality, blocks, blurriness.\n" " Experiment with codec settings to maybe still get the\n" " desired quality output at the expense of bitrate.\n" @@ -922,6 +890,9 @@ bool encoder_init_codec_and_muxer(struct encoder_context *p, if (avcodec_parameters_from_context(p->info.codecpar, p->encoder) < 0) goto fail; + p->pkt = av_packet_alloc(); + MP_HANDLE_OOM(p->pkt); + encode_lavc_add_stream(p, p->encode_lavc_ctx, &p->info, on_ready, ctx); if (!p->mux_stream) goto fail; @@ -929,7 +900,7 @@ bool encoder_init_codec_and_muxer(struct encoder_context *p, return true; fail: - avcodec_close(p->encoder); + avcodec_free_context(&p->encoder); return false; } @@ -942,11 +913,9 @@ bool encoder_encode(struct encoder_context *p, AVFrame *frame) goto fail; } + AVPacket *packet = p->pkt; for (;;) { - AVPacket packet = {0}; - av_init_packet(&packet); - - status = avcodec_receive_packet(p->encoder, &packet); + status = avcodec_receive_packet(p->encoder, packet); if (status == AVERROR(EAGAIN)) break; if (status < 0 && status != AVERROR_EOF) @@ -960,7 +929,7 @@ bool encoder_encode(struct encoder_context *p, AVFrame *frame) if (status == AVERROR_EOF) break; - encode_lavc_add_packet(p->mux_stream, &packet); + encode_lavc_add_packet(p->mux_stream, packet); } return true; @@ -971,13 +940,17 @@ fail: return false; } -double encoder_get_offset(struct encoder_context *p) +void encoder_update_log(struct mpv_global *global) { - switch (p->encoder->codec_type) { - case AVMEDIA_TYPE_VIDEO: return p->options->voffset; - case AVMEDIA_TYPE_AUDIO: return p->options->aoffset; - default: return 0; + struct encode_opts *options = mp_get_config_group(NULL, global, &encode_config); + if (options->file && (!strcmp(options->file, "-") || + !strcmp(options->file, "/dev/stdout") || + !strcmp(options->file, "pipe:") || + !strcmp(options->file, "pipe:1"))) + { + mp_msg_force_stderr(global, true); } + talloc_free(options); } // vim: ts=4 sw=4 et |