summaryrefslogtreecommitdiffstats
path: root/common/encode_lavc.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/encode_lavc.c')
-rw-r--r--common/encode_lavc.c196
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;