From 160497b8ff316f5ddd4deb6198302e5abbe7a56b Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Mon, 11 Apr 2016 14:24:48 -0400 Subject: encode_lavc: Migrate to codecpar API. --- audio/out/ao_lavc.c | 82 ++++++------- common/encode_lavc.c | 324 ++++++++++++++++++++++++++++----------------------- common/encode_lavc.h | 33 ++++-- video/out/vo_lavc.c | 66 ++++++----- 4 files changed, 274 insertions(+), 231 deletions(-) diff --git a/audio/out/ao_lavc.c b/audio/out/ao_lavc.c index bf1728682a..572874d27c 100644 --- a/audio/out/ao_lavc.c +++ b/audio/out/ao_lavc.c @@ -42,6 +42,7 @@ struct priv { uint8_t *buffer; size_t buffer_size; AVStream *stream; + AVCodecContext *codec; int pcmhack; int aframesize; int aframecount; @@ -98,15 +99,14 @@ static int init(struct ao *ao) 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"); - goto fail; + if (encode_lavc_alloc_stream(ao->encode_lavc_ctx, + AVMEDIA_TYPE_AUDIO, + &ac->stream, &ac->codec) < 0) { + MP_ERR(ao, "could not get a new audio stream\n"); + goto fail; } - codec = encode_lavc_get_codec(ao->encode_lavc_ctx, ac->stream); + codec = ao->encode_lavc_ctx->ac; int samplerate = af_select_best_samplerate(ao->samplerate, codec->supported_samplerates); @@ -118,40 +118,40 @@ static int init(struct ao *ao) // Using codec->time_bvase is deprecated, but needed for older lavf. ac->stream->time_base.num = 1; ac->stream->time_base.den = ao->samplerate; - ac->stream->codec->time_base.num = 1; - ac->stream->codec->time_base.den = ao->samplerate; + ac->codec->time_base.num = 1; + ac->codec->time_base.den = ao->samplerate; - ac->stream->codec->sample_rate = ao->samplerate; + ac->codec->sample_rate = ao->samplerate; struct mp_chmap_sel sel = {0}; mp_chmap_sel_add_any(&sel); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) 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); + ac->codec->channels = ao->channels.num; + ac->codec->channel_layout = mp_chmap_to_lavc(&ao->channels); - ac->stream->codec->sample_fmt = AV_SAMPLE_FMT_NONE; + ac->codec->sample_fmt = AV_SAMPLE_FMT_NONE; select_format(ao, codec); ac->sample_size = af_fmt_to_bytes(ao->format); - ac->stream->codec->sample_fmt = af_to_avformat(ao->format); - ac->stream->codec->bits_per_raw_sample = ac->sample_size * 8; + ac->codec->sample_fmt = af_to_avformat(ao->format); + ac->codec->bits_per_raw_sample = ac->sample_size * 8; - if (encode_lavc_open_codec(ao->encode_lavc_ctx, ac->stream) < 0) + if (encode_lavc_open_codec(ao->encode_lavc_ctx, ac->codec) < 0) goto fail; ac->pcmhack = 0; - if (ac->stream->codec->frame_size <= 1) - ac->pcmhack = av_get_bits_per_sample(ac->stream->codec->codec_id) / 8; + if (ac->codec->frame_size <= 1) + ac->pcmhack = av_get_bits_per_sample(ac->codec->codec_id) / 8; if (ac->pcmhack) { ac->aframesize = 16384; // "enough" ac->buffer_size = ac->aframesize * ac->pcmhack * ao->channels.num * 2 + 200; } else { - ac->aframesize = ac->stream->codec->frame_size; + ac->aframesize = ac->codec->frame_size; ac->buffer_size = ac->aframesize * ac->sample_size * ao->channels.num * 2 + 200; } @@ -203,7 +203,7 @@ static void uninit(struct ao *ao) double outpts = ac->expected_next_pts; if (!ectx->options->rawts && ectx->options->copyts) outpts += ectx->discontinuity_pts_offset; - outpts += encode_lavc_getoffset(ectx, ac->stream); + outpts += encode_lavc_getoffset(ectx, ac->codec); while (encode(ao, outpts, NULL) > 0) ; } @@ -252,25 +252,25 @@ static int encode(struct ao *ao, double apts, void **data) if (ectx->options->rawts || ectx->options->copyts) { // real audio pts - frame->pts = floor(apts * ac->stream->codec->time_base.den / ac->stream->codec->time_base.num + 0.5); + frame->pts = floor(apts * ac->codec->time_base.den / ac->codec->time_base.num + 0.5); } else { // audio playback time - frame->pts = floor(realapts * ac->stream->codec->time_base.den / ac->stream->codec->time_base.num + 0.5); + frame->pts = floor(realapts * ac->codec->time_base.den / ac->codec->time_base.num + 0.5); } - int64_t frame_pts = av_rescale_q(frame->pts, ac->stream->codec->time_base, ac->worst_time_base); + int64_t frame_pts = av_rescale_q(frame->pts, ac->codec->time_base, ac->worst_time_base); if (ac->lastpts != AV_NOPTS_VALUE && frame_pts <= ac->lastpts) { // this indicates broken video // (video pts failing to increase fast enough to match audio) MP_WARN(ao, "audio frame pts went backwards (%d <- %d), autofixed\n", (int)frame->pts, (int)ac->lastpts); frame_pts = ac->lastpts + 1; - frame->pts = av_rescale_q(frame_pts, ac->worst_time_base, ac->stream->codec->time_base); + frame->pts = av_rescale_q(frame_pts, ac->worst_time_base, ac->codec->time_base); } ac->lastpts = frame_pts; - frame->quality = ac->stream->codec->global_quality; - status = avcodec_encode_audio2(ac->stream->codec, &packet, frame, &gotpacket); + frame->quality = ac->codec->global_quality; + status = avcodec_encode_audio2(ac->codec, &packet, frame, &gotpacket); if (!status) { if (ac->savepts == AV_NOPTS_VALUE) @@ -281,7 +281,7 @@ static int encode(struct ao *ao, double apts, void **data) } else { - status = avcodec_encode_audio2(ac->stream->codec, &packet, NULL, &gotpacket); + status = avcodec_encode_audio2(ac->codec, &packet, NULL, &gotpacket); } if(status) { @@ -295,7 +295,7 @@ static int encode(struct ao *ao, double apts, void **data) MP_DBG(ao, "got pts %f (playback time: %f); out size: %d\n", apts, realapts, packet.size); - encode_lavc_write_stats(ao->encode_lavc_ctx, ac->stream); + encode_lavc_write_stats(ao->encode_lavc_ctx, ac->codec); packet.stream_index = ac->stream->index; @@ -307,20 +307,20 @@ static int encode(struct ao *ao, double apts, void **data) } if (packet.pts != AV_NOPTS_VALUE) - packet.pts = av_rescale_q(packet.pts, ac->stream->codec->time_base, + packet.pts = av_rescale_q(packet.pts, ac->codec->time_base, ac->stream->time_base); if (packet.dts != AV_NOPTS_VALUE) - packet.dts = av_rescale_q(packet.dts, ac->stream->codec->time_base, + packet.dts = av_rescale_q(packet.dts, ac->codec->time_base, ac->stream->time_base); if(packet.duration > 0) - packet.duration = av_rescale_q(packet.duration, ac->stream->codec->time_base, + packet.duration = av_rescale_q(packet.duration, ac->codec->time_base, ac->stream->time_base); ac->savepts = AV_NOPTS_VALUE; - if (encode_lavc_write_frame(ao->encode_lavc_ctx, &packet) < 0) { + if (encode_lavc_write_frame(ao->encode_lavc_ctx, ac->stream, &packet) < 0) { MP_ERR(ao, "error writing at %f %f/%f\n", realapts, (double) ac->stream->time_base.num, (double) ac->stream->time_base.den); @@ -377,22 +377,22 @@ static int play(struct ao *ao, void **data, int samples, int flags) } if (ac->worst_time_base.den == 0) { - //if (ac->stream->codec->time_base.num / ac->stream->codec->time_base.den >= ac->stream->time_base.num / ac->stream->time_base.den) - if (ac->stream->codec->time_base.num * (double) ac->stream->time_base.den >= - ac->stream->time_base.num * (double) ac->stream->codec->time_base.den) { + //if (ac->codec->time_base.num / ac->codec->time_base.den >= ac->stream->time_base.num / ac->stream->time_base.den) + if (ac->codec->time_base.num * (double) ac->stream->time_base.den >= + ac->stream->time_base.num * (double) ac->codec->time_base.den) { MP_VERBOSE(ao, "NOTE: using codec time base (%d/%d) for pts " "adjustment; the stream base (%d/%d) is not worse.\n", - (int)ac->stream->codec->time_base.num, - (int)ac->stream->codec->time_base.den, + (int)ac->codec->time_base.num, + (int)ac->codec->time_base.den, (int)ac->stream->time_base.num, (int)ac->stream->time_base.den); - ac->worst_time_base = ac->stream->codec->time_base; + ac->worst_time_base = ac->codec->time_base; ac->worst_time_base_is_stream = 0; } else { MP_WARN(ao, "NOTE: not using codec time base (%d/%d) for pts " "adjustment; the stream base (%d/%d) is worse.\n", - (int)ac->stream->codec->time_base.num, - (int)ac->stream->codec->time_base.den, + (int)ac->codec->time_base.num, + (int)ac->codec->time_base.den, (int)ac->stream->time_base.num, (int)ac->stream->time_base.den); ac->worst_time_base = ac->stream->time_base; @@ -437,7 +437,7 @@ static int play(struct ao *ao, void **data, int samples, int flags) } // Shift pts by the pts offset first. - outpts += encode_lavc_getoffset(ectx, ac->stream); + outpts += encode_lavc_getoffset(ectx, ac->codec); while (samples - bufpos >= ac->aframesize) { void *start[MP_NUM_CHANNELS] = {0}; diff --git a/common/encode_lavc.c b/common/encode_lavc.c index 6dd47a3816..78688545b5 100644 --- a/common/encode_lavc.c +++ b/common/encode_lavc.c @@ -21,6 +21,7 @@ #include +#include "config.h" #include "encode_lavc.h" #include "common/global.h" #include "common/msg.h" @@ -291,32 +292,20 @@ int encode_lavc_start(struct encode_lavc_context *ctx) CHECK_FAIL(ctx, 0); - if (ctx->expect_video) { - unsigned i; - for (i = 0; i < ctx->avc->nb_streams; ++i) - if (ctx->avc->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) - break; - if (i >= ctx->avc->nb_streams) { - if (ctx->avc->oformat->video_codec != AV_CODEC_ID_NONE || - ctx->options->vcodec) { - encode_lavc_fail(ctx, - "no video stream succeeded - invalid codec?\n"); - return 0; - } + if (ctx->expect_video && ctx->vcc == NULL) { + if (ctx->avc->oformat->video_codec != AV_CODEC_ID_NONE || + ctx->options->vcodec) { + encode_lavc_fail(ctx, + "no video stream succeeded - invalid codec?\n"); + return 0; } } - if (ctx->expect_audio) { - unsigned i; - for (i = 0; i < ctx->avc->nb_streams; ++i) - if (ctx->avc->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) - break; - if (i >= ctx->avc->nb_streams) { - if (ctx->avc->oformat->audio_codec != AV_CODEC_ID_NONE || - ctx->options->acodec) { - encode_lavc_fail(ctx, - "no audio stream succeeded - invalid codec?\n"); - return 0; - } + if (ctx->expect_audio && ctx->acc == NULL) { + if (ctx->avc->oformat->audio_codec != AV_CODEC_ID_NONE || + ctx->options->acodec) { + encode_lavc_fail(ctx, + "no audio stream succeeded - invalid codec?\n"); + return 0; } } @@ -387,33 +376,38 @@ void encode_lavc_finish(struct encode_lavc_context *ctx) if (ctx->header_written > 0) av_write_trailer(ctx->avc); // this is allowed to fail - for (i = 0; i < ctx->avc->nb_streams; i++) { - switch (ctx->avc->streams[i]->codec->codec_type) { - case AVMEDIA_TYPE_VIDEO: - if (ctx->twopass_bytebuffer_v) { - char *stats = ctx->avc->streams[i]->codec->stats_out; - if (stats) - stream_write_buffer(ctx->twopass_bytebuffer_v, - stats, strlen(stats)); - } - break; - case AVMEDIA_TYPE_AUDIO: - if (ctx->twopass_bytebuffer_a) { - char *stats = ctx->avc->streams[i]->codec->stats_out; - if (stats) - stream_write_buffer(ctx->twopass_bytebuffer_a, - stats, strlen(stats)); - } - break; - default: - break; + if (ctx->vcc) { + if (ctx->twopass_bytebuffer_v) { + char *stats = ctx->vcc->stats_out; + if (stats) + stream_write_buffer(ctx->twopass_bytebuffer_v, + stats, strlen(stats)); + } + avcodec_close(ctx->vcc); + talloc_free(ctx->vcc->stats_in); + av_free(ctx->vcc); + ctx->vcc = NULL; + } + + if (ctx->acc) { + if (ctx->twopass_bytebuffer_a) { + char *stats = ctx->acc->stats_out; + if (stats) + stream_write_buffer(ctx->twopass_bytebuffer_a, + stats, strlen(stats)); } - avcodec_close(ctx->avc->streams[i]->codec); - talloc_free(ctx->avc->streams[i]->codec->stats_in); - av_free(ctx->avc->streams[i]->codec); + avcodec_close(ctx->acc); + talloc_free(ctx->acc->stats_in); + av_free(ctx->acc); + ctx->acc = NULL; + } + + for (i = 0; i < ctx->avc->nb_streams; i++) { av_free(ctx->avc->streams[i]->info); av_free(ctx->avc->streams[i]); } + ctx->vst = NULL; + ctx->ast = NULL; if (ctx->twopass_bytebuffer_v) { free_stream(ctx->twopass_bytebuffer_v); @@ -437,6 +431,7 @@ void encode_lavc_finish(struct encode_lavc_context *ctx) } av_free(ctx->avc); + ctx->avc = NULL; } ctx->finished = true; @@ -461,7 +456,9 @@ void encode_lavc_set_audio_pts(struct encode_lavc_context *ctx, double pts) static void encode_2pass_prepare(struct encode_lavc_context *ctx, AVDictionary **dictp, - AVStream *stream, struct stream **bytebuf, + AVStream *stream, + AVCodecContext *codec, + struct stream **bytebuf, const char *prefix) { if (!*bytebuf) { @@ -476,7 +473,7 @@ static void encode_2pass_prepare(struct encode_lavc_context *ctx, if (!(*bytebuf = stream_open(buf, ctx->global))) { MP_WARN(ctx, "%s: could not open '%s', " "disabling 2-pass encoding at pass 2\n", prefix, buf); - stream->codec->flags &= ~CODEC_FLAG_PASS2; + codec->flags &= ~CODEC_FLAG_PASS2; set_to_avdictionary(ctx, dictp, "flags", "-pass2"); } else { struct bstr content = stream_read_complete(*bytebuf, NULL, @@ -487,7 +484,7 @@ static void encode_2pass_prepare(struct encode_lavc_context *ctx, prefix, ctx->avc->filename); } else { content.start[content.len] = 0; - stream->codec->stats_in = content.start; + codec->stats_in = content.start; } free_stream(*bytebuf); *bytebuf = NULL; @@ -506,43 +503,55 @@ static void encode_2pass_prepare(struct encode_lavc_context *ctx, } } -AVStream *encode_lavc_alloc_stream(struct encode_lavc_context *ctx, - enum AVMediaType mt) +int encode_lavc_alloc_stream(struct encode_lavc_context *ctx, + enum AVMediaType mt, + AVStream **stream_out, + AVCodecContext **codec_out) { AVDictionaryEntry *de; - AVStream *stream = NULL; char **p; - int i; - CHECK_FAIL(ctx, NULL); + *stream_out = NULL; + *codec_out = NULL; - if (ctx->header_written) - return NULL; + CHECK_FAIL(ctx, -1); - for (i = 0; i < ctx->avc->nb_streams; ++i) - if (ctx->avc->streams[i]->codec->codec_type == mt) - // already have a stream of that type, this cannot really happen - return NULL; + if (ctx->header_written) + return -1; if (ctx->avc->nb_streams == 0) { // if this stream isn't stream #0, allocate a dummy stream first for - // the next loop to use + // the next call to use if (mt == AVMEDIA_TYPE_VIDEO && ctx->audio_first) { MP_INFO(ctx, "vo-lavc: preallocated audio stream for later use\n"); - avformat_new_stream(ctx->avc, NULL); // this one is AVMEDIA_TYPE_UNKNOWN for now + ctx->ast = avformat_new_stream( + ctx->avc, NULL); // this one is AVMEDIA_TYPE_UNKNOWN for now } if (mt == AVMEDIA_TYPE_AUDIO && ctx->video_first) { MP_INFO(ctx, "ao-lavc: preallocated video stream for later use\n"); - avformat_new_stream(ctx->avc, NULL); // this one is AVMEDIA_TYPE_UNKNOWN for now + ctx->vst = avformat_new_stream( + ctx->avc, NULL); // this one is AVMEDIA_TYPE_UNKNOWN for now } - } else { - // find possibly preallocated stream - for (i = 0; i < ctx->avc->nb_streams; ++i) - if (ctx->avc->streams[i]->codec->codec_type == AVMEDIA_TYPE_UNKNOWN) // preallocated stream - stream = ctx->avc->streams[i]; } - if (!stream) - stream = avformat_new_stream(ctx->avc, NULL); + + // already have a stream of that type (this cannot really happen)? + switch (mt) { + case AVMEDIA_TYPE_VIDEO: + if (ctx->vcc != NULL) + return -1; + if (ctx->vst == NULL) + ctx->vst = avformat_new_stream(ctx->avc, NULL); + break; + case AVMEDIA_TYPE_AUDIO: + if (ctx->acc != NULL) + return -1; + if (ctx->ast == NULL) + ctx->ast = avformat_new_stream(ctx->avc, NULL); + break; + default: + encode_lavc_fail(ctx, "requested invalid stream type\n"); + return -1; + } if (ctx->timebase.den == 0) { AVRational r; @@ -584,13 +593,18 @@ AVStream *encode_lavc_alloc_stream(struct encode_lavc_context *ctx, ctx->options->vcodec) { encode_lavc_fail(ctx, "vo-lavc: encoder not found\n"); } - return NULL; + return -1; } - avcodec_get_context_defaults3(stream->codec, ctx->vc); +#if HAVE_AVCODEC_HAS_CODECPAR + ctx->vcc = avcodec_alloc_context3(ctx->vc); +#else + avcodec_get_context_defaults3(ctx->vst->codec, ctx->vc); + ctx->vcc = ctx->vst->codec; +#endif // Using codec->time_base is deprecated, but needed for older lavf. - stream->time_base = ctx->timebase; - stream->codec->time_base = ctx->timebase; + ctx->vst->time_base = ctx->timebase; + ctx->vcc->time_base = ctx->timebase; ctx->voptions = NULL; @@ -606,10 +620,12 @@ AVStream *encode_lavc_alloc_stream(struct encode_lavc_context *ctx, if (ctx->avc->oformat->flags & AVFMT_GLOBALHEADER) set_to_avdictionary(ctx, &ctx->voptions, "flags", "+global_header"); - encode_2pass_prepare(ctx, &ctx->voptions, stream, + encode_2pass_prepare(ctx, &ctx->voptions, ctx->vst, ctx->vcc, &ctx->twopass_bytebuffer_v, "vo-lavc"); - break; + *stream_out = ctx->vst; + *codec_out = ctx->vcc; + return 0; case AVMEDIA_TYPE_AUDIO: if (!ctx->ac) { @@ -617,15 +633,20 @@ AVStream *encode_lavc_alloc_stream(struct encode_lavc_context *ctx, ctx->options->acodec) { encode_lavc_fail(ctx, "ao-lavc: encoder not found\n"); } - return NULL; + return -1; } - avcodec_get_context_defaults3(stream->codec, ctx->ac); +#if HAVE_AVCODEC_HAS_CODECPAR + ctx->acc = avcodec_alloc_context3(ctx->ac); +#else + avcodec_get_context_defaults3(ctx->ast->codec, ctx->ac); + ctx->acc = ctx->ast->codec; +#endif // Using codec->time_base is deprecated, but needed for older lavf. - stream->time_base = ctx->timebase; - stream->codec->time_base = ctx->timebase; + ctx->ast->time_base = ctx->timebase; + ctx->acc->time_base = ctx->timebase; - ctx->aoptions = NULL; + ctx->aoptions = 0; if (ctx->options->aopts) for (p = ctx->options->aopts; *p; ++p) @@ -639,49 +660,34 @@ AVStream *encode_lavc_alloc_stream(struct encode_lavc_context *ctx, if (ctx->avc->oformat->flags & AVFMT_GLOBALHEADER) set_to_avdictionary(ctx, &ctx->aoptions, "flags", "+global_header"); - encode_2pass_prepare(ctx, &ctx->aoptions, stream, + encode_2pass_prepare(ctx, &ctx->aoptions, ctx->ast, ctx->acc, &ctx->twopass_bytebuffer_a, "ao-lavc"); - break; - default: - encode_lavc_fail(ctx, "requested invalid stream type\n"); - return NULL; + *stream_out = ctx->ast; + *codec_out = ctx->acc; + return 0; } - return stream; + // Unreachable. + return -1; } -AVCodec *encode_lavc_get_codec(struct encode_lavc_context *ctx, - AVStream *stream) -{ - CHECK_FAIL(ctx, NULL); - - switch (stream->codec->codec_type) { - case AVMEDIA_TYPE_VIDEO: - return ctx->vc; - case AVMEDIA_TYPE_AUDIO: - return ctx->ac; - default: - break; - } - return NULL; -} - -int encode_lavc_open_codec(struct encode_lavc_context *ctx, AVStream *stream) +int encode_lavc_open_codec(struct encode_lavc_context *ctx, + AVCodecContext *codec) { AVDictionaryEntry *de; int ret; CHECK_FAIL(ctx, -1); - switch (stream->codec->codec_type) { + switch (codec->codec_type) { case AVMEDIA_TYPE_VIDEO: MP_INFO(ctx, "Opening video encoder: %s [%s]\n", ctx->vc->long_name, ctx->vc->name); if (ctx->vc->capabilities & CODEC_CAP_EXPERIMENTAL) { - stream->codec->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; + codec->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; MP_WARN(ctx, "\n\n" " ********************************************\n" " **** Experimental VIDEO codec selected! ****\n" @@ -701,7 +707,11 @@ int encode_lavc_open_codec(struct encode_lavc_context *ctx, AVStream *stream) ctx->vc->name); } - ret = avcodec_open2(stream->codec, ctx->vc, &ctx->voptions); + ret = avcodec_open2(codec, ctx->vc, &ctx->voptions); +#if HAVE_AVCODEC_HAS_CODECPAR + if (ret >= 0) + ret = avcodec_parameters_from_context(ctx->vst->codecpar, codec); +#endif // complain about all remaining options, then free the dict for (de = NULL; (de = av_dict_get(ctx->voptions, "", de, @@ -716,7 +726,7 @@ int encode_lavc_open_codec(struct encode_lavc_context *ctx, AVStream *stream) ctx->ac->long_name, ctx->ac->name); if (ctx->ac->capabilities & CODEC_CAP_EXPERIMENTAL) { - stream->codec->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; + codec->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; MP_WARN(ctx, "\n\n" " ********************************************\n" " **** Experimental AUDIO codec selected! ****\n" @@ -735,7 +745,12 @@ int encode_lavc_open_codec(struct encode_lavc_context *ctx, AVStream *stream) "If none of this helps you, try another codec in place of %s.\n\n", ctx->ac->name); } - ret = avcodec_open2(stream->codec, ctx->ac, &ctx->aoptions); + + ret = avcodec_open2(codec, ctx->ac, &ctx->aoptions); +#if HAVE_AVCODEC_HAS_CODECPAR + if (ret >= 0) + ret = avcodec_parameters_from_context(ctx->ast->codecpar, codec); +#endif // complain about all remaining options, then free the dict for (de = NULL; (de = av_dict_get(ctx->aoptions, "", de, @@ -757,36 +772,43 @@ int encode_lavc_open_codec(struct encode_lavc_context *ctx, AVStream *stream) return ret; } -void encode_lavc_write_stats(struct encode_lavc_context *ctx, AVStream *stream) +void encode_lavc_write_stats(struct encode_lavc_context *ctx, + AVCodecContext *codec) { CHECK_FAIL(ctx, ); - switch (stream->codec->codec_type) { + switch (codec->codec_type) { case AVMEDIA_TYPE_VIDEO: if (ctx->twopass_bytebuffer_v) - if (stream->codec->stats_out) + if (codec->stats_out) stream_write_buffer(ctx->twopass_bytebuffer_v, - stream->codec->stats_out, - strlen(stream->codec->stats_out)); + codec->stats_out, + strlen(codec->stats_out)); break; case AVMEDIA_TYPE_AUDIO: if (ctx->twopass_bytebuffer_a) - if (stream->codec->stats_out) + if (codec->stats_out) stream_write_buffer(ctx->twopass_bytebuffer_a, - stream->codec->stats_out, - strlen(stream->codec->stats_out)); + codec->stats_out, + strlen(codec->stats_out)); break; default: break; } } -int encode_lavc_write_frame(struct encode_lavc_context *ctx, AVPacket *packet) +int encode_lavc_write_frame(struct encode_lavc_context *ctx, AVStream *stream, + AVPacket *packet) { int r; CHECK_FAIL(ctx, -1); + if (stream->index != packet->stream_index) { + MP_ERR(ctx, "Called encode_lavc_write_frame on the wrong stream\n"); + return -1; + } + if (ctx->header_written <= 0) return -1; @@ -795,27 +817,32 @@ int encode_lavc_write_frame(struct encode_lavc_context *ctx, AVPacket *packet) (int)packet->stream_index, (int)packet->pts, packet->pts - * (double)ctx->avc->streams[packet->stream_index]->time_base.num - / (double)ctx->avc->streams[packet->stream_index]->time_base.den, + * (double)stream->time_base.num + / (double)stream->time_base.den, (int)packet->dts, packet->dts - * (double)ctx->avc->streams[packet->stream_index]->time_base.num - / (double)ctx->avc->streams[packet->stream_index]->time_base.den, + * (double)stream->time_base.num + / (double)stream->time_base.den, (int)packet->size); - switch (ctx->avc->streams[packet->stream_index]->codec->codec_type) { - case AVMEDIA_TYPE_VIDEO: - ctx->vbytes += packet->size; - ++ctx->frames; - break; - case AVMEDIA_TYPE_AUDIO: - ctx->abytes += packet->size; - ctx->audioseconds += packet->duration - * (double)ctx->avc->streams[packet->stream_index]->time_base.num - / (double)ctx->avc->streams[packet->stream_index]->time_base.den; - break; - default: - break; + +#if HAVE_AVCODEC_HAS_CODECPAR + switch (stream->codecpar->codec_type) { +#else + switch (stream->codec->codec_type) { +#endif + case AVMEDIA_TYPE_VIDEO: + ctx->vbytes += packet->size; + ++ctx->frames; + break; + case AVMEDIA_TYPE_AUDIO: + ctx->abytes += packet->size; + ctx->audioseconds += packet->duration + * (double)stream->time_base.num + / (double)stream->time_base.den; + break; + default: + break; } r = av_interleaved_write_frame(ctx->avc, packet); @@ -1062,11 +1089,12 @@ bool encode_lavc_showhelp(struct mp_log *log, struct encode_opts *opts) return help_output; } -double encode_lavc_getoffset(struct encode_lavc_context *ctx, AVStream *stream) +double encode_lavc_getoffset(struct encode_lavc_context *ctx, + AVCodecContext *codec) { CHECK_FAIL(ctx, 0); - switch (stream->codec->codec_type) { + switch (codec->codec_type) { case AVMEDIA_TYPE_VIDEO: return ctx->options->voffset; case AVMEDIA_TYPE_AUDIO: @@ -1151,49 +1179,49 @@ void encode_lavc_fail(struct encode_lavc_context *ctx, const char *format, ...) } bool encode_lavc_set_csp(struct encode_lavc_context *ctx, - AVStream *stream, enum mp_csp csp) + AVCodecContext *codec, enum mp_csp csp) { CHECK_FAIL(ctx, NULL); if (ctx->header_written) { - if (stream->codec->colorspace != mp_csp_to_avcol_spc(csp)) + if (codec->colorspace != mp_csp_to_avcol_spc(csp)) MP_WARN(ctx, "can not change color space during encoding\n"); return false; } - stream->codec->colorspace = mp_csp_to_avcol_spc(csp); + codec->colorspace = mp_csp_to_avcol_spc(csp); return true; } bool encode_lavc_set_csp_levels(struct encode_lavc_context *ctx, - AVStream *stream, enum mp_csp_levels lev) + AVCodecContext *codec, enum mp_csp_levels lev) { CHECK_FAIL(ctx, NULL); if (ctx->header_written) { - if (stream->codec->color_range != mp_csp_levels_to_avcol_range(lev)) + if (codec->color_range != mp_csp_levels_to_avcol_range(lev)) MP_WARN(ctx, "can not change color space during encoding\n"); return false; } - stream->codec->color_range = mp_csp_levels_to_avcol_range(lev); + codec->color_range = mp_csp_levels_to_avcol_range(lev); return true; } enum mp_csp encode_lavc_get_csp(struct encode_lavc_context *ctx, - AVStream *stream) + AVCodecContext *codec) { CHECK_FAIL(ctx, 0); - return avcol_spc_to_mp_csp(stream->codec->colorspace); + return avcol_spc_to_mp_csp(codec->colorspace); } enum mp_csp_levels encode_lavc_get_csp_levels(struct encode_lavc_context *ctx, - AVStream *stream) + AVCodecContext *codec) { CHECK_FAIL(ctx, 0); - return avcol_range_to_mp_csp_levels(stream->codec->color_range); + return avcol_range_to_mp_csp_levels(codec->color_range); } // vim: ts=4 sw=4 et diff --git a/common/encode_lavc.h b/common/encode_lavc.h index 0ab922f788..7bfe4e4a8f 100644 --- a/common/encode_lavc.h +++ b/common/encode_lavc.h @@ -46,8 +46,14 @@ struct encode_lavc_context { float vo_fps; - // these are processed from the options + // FFmpeg contexts. AVFormatContext *avc; + AVStream *vst; + AVStream *ast; + AVCodecContext *vcc; + AVCodecContext *acc; + + // these are processed from the options AVRational timebase; AVCodec *vc; AVCodec *ac; @@ -88,26 +94,31 @@ struct encode_lavc_context { }; // interface for vo/ao drivers -AVStream *encode_lavc_alloc_stream(struct encode_lavc_context *ctx, enum AVMediaType mt); -void encode_lavc_write_stats(struct encode_lavc_context *ctx, AVStream *stream); -int encode_lavc_write_frame(struct encode_lavc_context *ctx, AVPacket *packet); +int encode_lavc_alloc_stream(struct encode_lavc_context *ctx, + enum AVMediaType mt, AVStream **stream_out, + AVCodecContext **codec_out); +void encode_lavc_write_stats(struct encode_lavc_context *ctx, + AVCodecContext *stream); +int encode_lavc_write_frame(struct encode_lavc_context *ctx, AVStream *stream, + AVPacket *packet); int encode_lavc_supports_pixfmt(struct encode_lavc_context *ctx, enum AVPixelFormat format); -AVCodec *encode_lavc_get_codec(struct encode_lavc_context *ctx, AVStream *stream); -int encode_lavc_open_codec(struct encode_lavc_context *ctx, AVStream *stream); +int encode_lavc_open_codec(struct encode_lavc_context *ctx, + AVCodecContext *codec); int encode_lavc_available(struct encode_lavc_context *ctx); int encode_lavc_timesyncfailed(struct encode_lavc_context *ctx); int encode_lavc_start(struct encode_lavc_context *ctx); // returns 1 on success int encode_lavc_oformat_flags(struct encode_lavc_context *ctx); -double encode_lavc_getoffset(struct encode_lavc_context *ctx, AVStream *stream); +double encode_lavc_getoffset(struct encode_lavc_context *ctx, + AVCodecContext *codec); void encode_lavc_fail(struct encode_lavc_context *ctx, const char *format, ...); // report failure of encoding bool encode_lavc_set_csp(struct encode_lavc_context *ctx, - AVStream *stream, enum mp_csp csp); + AVCodecContext *codec, enum mp_csp csp); bool encode_lavc_set_csp_levels(struct encode_lavc_context *ctx, - AVStream *stream, enum mp_csp_levels lev); + AVCodecContext *codec, enum mp_csp_levels lev); enum mp_csp encode_lavc_get_csp(struct encode_lavc_context *ctx, - AVStream *stream); + AVCodecContext *codec); enum mp_csp_levels encode_lavc_get_csp_levels(struct encode_lavc_context *ctx, - AVStream *stream); + AVCodecContext *codec); #endif diff --git a/video/out/vo_lavc.c b/video/out/vo_lavc.c index bd07d10208..d102fec869 100644 --- a/video/out/vo_lavc.c +++ b/video/out/vo_lavc.c @@ -37,6 +37,7 @@ struct priv { uint8_t *buffer; size_t buffer_size; AVStream *stream; + AVCodecContext *codec; int have_first_packet; int harddup; @@ -108,14 +109,14 @@ static int reconfig(struct vo *vo, struct mp_image_params *params) * warning here. We choose to ignore that; just because ffmpeg currently * uses a plain 'int' for these struct fields, it doesn't mean it always * will */ - if (width == vc->stream->codec->width && - height == vc->stream->codec->height) { - if (aspect.num != vc->stream->codec->sample_aspect_ratio.num || - aspect.den != vc->stream->codec->sample_aspect_ratio.den) { + if (width == vc->codec->width && + height == vc->codec->height) { + if (aspect.num != vc->codec->sample_aspect_ratio.num || + aspect.den != vc->codec->sample_aspect_ratio.den) { /* aspect-only changes are not critical */ MP_WARN(vo, "unsupported pixel aspect ratio change from %d:%d to %d:%d\n", - vc->stream->codec->sample_aspect_ratio.num, - vc->stream->codec->sample_aspect_ratio.den, + vc->codec->sample_aspect_ratio.num, + vc->codec->sample_aspect_ratio.den, aspect.num, aspect.den); } goto done; @@ -144,18 +145,20 @@ static int reconfig(struct vo *vo, struct mp_image_params *params) goto error; } - vc->stream = encode_lavc_alloc_stream(vo->encode_lavc_ctx, - AVMEDIA_TYPE_VIDEO); - vc->stream->sample_aspect_ratio = vc->stream->codec->sample_aspect_ratio = + if (encode_lavc_alloc_stream(vo->encode_lavc_ctx, + AVMEDIA_TYPE_VIDEO, + &vc->stream, &vc->codec) < 0) + goto error; + vc->stream->sample_aspect_ratio = vc->codec->sample_aspect_ratio = aspect; - vc->stream->codec->width = width; - vc->stream->codec->height = height; - vc->stream->codec->pix_fmt = pix_fmt; + vc->codec->width = width; + vc->codec->height = height; + vc->codec->pix_fmt = pix_fmt; - encode_lavc_set_csp(vo->encode_lavc_ctx, vc->stream, params->colorspace); - encode_lavc_set_csp_levels(vo->encode_lavc_ctx, vc->stream, params->colorlevels); + encode_lavc_set_csp(vo->encode_lavc_ctx, vc->codec, params->colorspace); + encode_lavc_set_csp_levels(vo->encode_lavc_ctx, vc->codec, params->colorlevels); - if (encode_lavc_open_codec(vo->encode_lavc_ctx, vc->stream) < 0) + if (encode_lavc_open_codec(vo->encode_lavc_ctx, vc->codec) < 0) goto error; vc->buffer_size = 6 * width * height + 200; @@ -204,7 +207,7 @@ static void write_packet(struct vo *vo, int size, AVPacket *packet) packet->stream_index = vc->stream->index; if (packet->pts != AV_NOPTS_VALUE) { packet->pts = av_rescale_q(packet->pts, - vc->stream->codec->time_base, + vc->codec->time_base, vc->stream->time_base); } else { MP_VERBOSE(vo, "codec did not provide pts\n"); @@ -213,12 +216,12 @@ static void write_packet(struct vo *vo, int size, AVPacket *packet) } if (packet->dts != AV_NOPTS_VALUE) { packet->dts = av_rescale_q(packet->dts, - vc->stream->codec->time_base, + vc->codec->time_base, vc->stream->time_base); } if (packet->duration > 0) { packet->duration = av_rescale_q(packet->duration, - vc->stream->codec->time_base, + vc->codec->time_base, vc->stream->time_base); } else { // HACK: libavformat calculates dts wrong if the initial packet @@ -226,15 +229,16 @@ static void write_packet(struct vo *vo, int size, AVPacket *packet) // have b-frames! if (!packet->duration) if (!vc->have_first_packet) - if (vc->stream->codec->has_b_frames - || vc->stream->codec->max_b_frames) + if (vc->codec->has_b_frames + || vc->codec->max_b_frames) if (vc->stream->time_base.num * 1000LL <= vc->stream->time_base.den) packet->duration = FFMAX(1, av_rescale_q(1, - vc->stream->codec->time_base, vc->stream->time_base)); + vc->codec->time_base, vc->stream->time_base)); } - if (encode_lavc_write_frame(vo->encode_lavc_ctx, packet) < 0) { + if (encode_lavc_write_frame(vo->encode_lavc_ctx, + vc->stream, packet) < 0) { MP_ERR(vo, "error writing\n"); return; } @@ -251,23 +255,23 @@ static int encode_video(struct vo *vo, AVFrame *frame, AVPacket *packet) return 0; memcpy(vc->buffer, frame, sizeof(AVPicture)); MP_DBG(vo, "got pts %f\n", - frame->pts * (double) vc->stream->codec->time_base.num / - (double) vc->stream->codec->time_base.den); + frame->pts * (double) vc->codec->time_base.num / + (double) vc->codec->time_base.den); packet->size = sizeof(AVPicture); return packet->size; } else { int got_packet = 0; - int status = avcodec_encode_video2(vc->stream->codec, packet, + int status = avcodec_encode_video2(vc->codec, packet, frame, &got_packet); int size = (status < 0) ? status : got_packet ? packet->size : 0; if (frame) MP_DBG(vo, "got pts %f; out size: %d\n", - frame->pts * (double) vc->stream->codec->time_base.num / - (double) vc->stream->codec->time_base.den, size); + frame->pts * (double) vc->codec->time_base.num / + (double) vc->codec->time_base.den, size); if (got_packet) - encode_lavc_write_stats(vo->encode_lavc_ctx, vc->stream); + encode_lavc_write_stats(vo->encode_lavc_ctx, vc->codec); return size; } } @@ -295,7 +299,7 @@ static void draw_image_unlocked(struct vo *vo, mp_image_t *mpi) pts = vc->expected_next_pts; } - avc = vc->stream->codec; + avc = vc->codec; if (vc->worst_time_base.den == 0) { //if (avc->time_base.num / avc->time_base.den >= vc->stream->time_base.num / vc->stream->time_base.den) @@ -376,7 +380,7 @@ static void draw_image_unlocked(struct vo *vo, mp_image_t *mpi) } vc->lastpts = outpts; ectx->last_video_in_pts = pts; - frameipts = floor((outpts + encode_lavc_getoffset(ectx, vc->stream)) + frameipts = floor((outpts + encode_lavc_getoffset(ectx, vc->codec)) / timeunit + 0.5); // calculate expected pts of next video frame @@ -396,7 +400,7 @@ static void draw_image_unlocked(struct vo *vo, mp_image_t *mpi) MP_INFO(vo, "--oneverdrop increased pts by %d\n", (int) (vc->lastipts - frameipts + step)); frameipts = vc->lastipts + step; - vc->lastpts = frameipts * timeunit - encode_lavc_getoffset(ectx, vc->stream); + vc->lastpts = frameipts * timeunit - encode_lavc_getoffset(ectx, vc->codec); } } -- cgit v1.2.3