diff options
Diffstat (limited to 'common/encode_lavc.c')
-rw-r--r-- | common/encode_lavc.c | 196 |
1 files changed, 99 insertions, 97 deletions
diff --git a/common/encode_lavc.c b/common/encode_lavc.c index 213e2ba5a1..bf77f04969 100644 --- a/common/encode_lavc.c +++ b/common/encode_lavc.c @@ -77,32 +77,32 @@ struct mux_stream { #define OPT_BASE_STRUCT struct encode_opts const struct m_sub_options encode_config = { .opts = (const m_option_t[]) { - OPT_STRING("o", file, M_OPT_FIXED | CONF_NOCFG | CONF_PRE_PARSE | M_OPT_FILE), - OPT_STRING("of", format, M_OPT_FIXED), - OPT_KEYVALUELIST("ofopts", fopts, M_OPT_FIXED | M_OPT_HAVE_HELP), - OPT_STRING("ovc", vcodec, M_OPT_FIXED), - OPT_KEYVALUELIST("ovcopts", vopts, M_OPT_FIXED | M_OPT_HAVE_HELP), - OPT_STRING("oac", acodec, M_OPT_FIXED), - OPT_KEYVALUELIST("oacopts", aopts, M_OPT_FIXED | M_OPT_HAVE_HELP), - OPT_FLOATRANGE("ovoffset", voffset, M_OPT_FIXED, -1000000.0, 1000000.0, - .deprecation_message = "--audio-delay (once unbroken)"), - OPT_FLOATRANGE("oaoffset", aoffset, M_OPT_FIXED, -1000000.0, 1000000.0, - .deprecation_message = "--audio-delay (once unbroken)"), - OPT_FLAG("orawts", rawts, M_OPT_FIXED), - OPT_FLAG("ovfirst", video_first, M_OPT_FIXED, - .deprecation_message = "no replacement"), - OPT_FLAG("oafirst", audio_first, M_OPT_FIXED, - .deprecation_message = "no replacement"), - OPT_FLAG("ocopy-metadata", copy_metadata, M_OPT_FIXED), - OPT_KEYVALUELIST("oset-metadata", set_metadata, M_OPT_FIXED), - OPT_STRINGLIST("oremove-metadata", remove_metadata, M_OPT_FIXED), - - OPT_REMOVED("ocopyts", "ocopyts is now the default"), - OPT_REMOVED("oneverdrop", "no replacement"), - OPT_REMOVED("oharddup", "use --vf-add=fps=VALUE"), - OPT_REMOVED("ofps", "no replacement (use --vf-add=fps=VALUE for CFR)"), - OPT_REMOVED("oautofps", "no replacement"), - OPT_REMOVED("omaxfps", "no replacement"), + {"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)}, + {"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), @@ -242,16 +242,6 @@ bool encode_lavc_free(struct encode_lavc_context *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) { @@ -366,38 +356,14 @@ 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); -} - // Signal that you are ready to encode (you provide the codec params etc. too). // This returns a muxing handle which you can use to add encodec packets. // Can be called only once per stream. info is copied by callee as needed. -static struct mux_stream *encode_lavc_add_stream(struct encode_lavc_context *ctx, - struct encoder_stream_info *info, - void (*on_ready)(void *ctx), - void *on_ready_ctx) +static void encode_lavc_add_stream(struct encoder_context *enc, + struct encode_lavc_context *ctx, + struct encoder_stream_info *info, + void (*on_ready)(void *ctx), + void *on_ready_ctx) { struct encode_priv *p = ctx->priv; @@ -422,18 +388,22 @@ static struct mux_stream *encode_lavc_add_stream(struct encode_lavc_context *ctx dst->encoder_timebase = info->timebase; dst->st->time_base = info->timebase; // lavf will change this on muxer init + // Some muxers (e.g. Matroska one) expect the sample_aspect_ratio to be + // set on the AVStream. + if (info->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + dst->st->sample_aspect_ratio = info->codecpar->sample_aspect_ratio; + if (avcodec_parameters_copy(dst->st->codecpar, info->codecpar) < 0) MP_HANDLE_OOM(0); dst->on_ready = on_ready; dst->on_ready_ctx = on_ready_ctx; + enc->mux_stream = dst; maybe_init_muxer(ctx); done: pthread_mutex_unlock(&ctx->lock); - - return dst; } // Write a packet. This will take over ownership of `pkt` @@ -486,16 +456,18 @@ done: av_packet_unref(pkt); } +AVRational encoder_get_mux_timebase_unlocked(struct encoder_context *p) +{ + return p->mux_stream->st->time_base; +} + void encode_lavc_discontinuity(struct encode_lavc_context *ctx) { if (!ctx) return; pthread_mutex_lock(&ctx->lock); - - ctx->audio_pts_offset = MP_NOPTS_VALUE; ctx->discontinuity_pts_offset = MP_NOPTS_VALUE; - pthread_mutex_unlock(&ctx->lock); } @@ -715,7 +687,7 @@ int encode_lavc_getstatus(struct encode_lavc_context *ctx, double now = mp_time_sec(); float minutes, megabytes, fps, x; - float f = FFMAX(0.0001, relative_position); + float f = MPMAX(0.0001, relative_position); pthread_mutex_lock(&ctx->lock); @@ -759,10 +731,52 @@ static void encoder_destroy(void *ptr) { struct encoder_context *p = ptr; + av_packet_free(&p->pkt); 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) @@ -783,27 +797,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; } @@ -825,7 +825,9 @@ static void encoder_2pass_prepare(struct encoder_context *p) if (p->encoder->flags & AV_CODEC_FLAG_PASS2) { MP_INFO(p, "Reading 2-pass log: %s\n", filename); - struct stream *s = stream_open(filename, p->global); + struct stream *s = stream_create(filename, + STREAM_ORIGIN_DIRECT | STREAM_READ, + NULL, p->global); if (s) { struct bstr content = stream_read_complete(s, p, 1000000000); if (content.start) { @@ -909,8 +911,10 @@ bool encoder_init_codec_and_muxer(struct encoder_context *p, if (avcodec_parameters_from_context(p->info.codecpar, p->encoder) < 0) goto fail; - p->mux_stream = encode_lavc_add_stream(p->encode_lavc_ctx, &p->info, - on_ready, ctx); + 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; @@ -930,11 +934,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) @@ -948,7 +950,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; |