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 From 49431626cb1bde400ab6de6adc68ce39cdbbf6f8 Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Mon, 11 Apr 2016 14:59:33 -0400 Subject: Revert "build: disable encoding mode by default" Reverting because the use of deprecated API has been fixed. This reverts commit d0238711dc776aeee2509452202ba4748f863ee4. --- wscript | 1 - 1 file changed, 1 deletion(-) diff --git a/wscript b/wscript index f4fe38ed59..6d77932681 100644 --- a/wscript +++ b/wscript @@ -325,7 +325,6 @@ iconv support use --disable-iconv.", } , { 'name' : '--encoding', 'desc' : 'Encoding', - 'default': 'disable', 'func': check_true, }, { 'name': '--libbluray', -- cgit v1.2.3 From f5ff2656e0d192a2e25fe5f65edf219972211a48 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 11 Apr 2016 20:46:05 +0200 Subject: vaapi: determine surface format in decoder, not in renderer Until now, we have made the assumption that a driver will use only 1 hardware surface format. the format is dictated by the driver (you don't create surfaces with a specific format - you just pass a rt_format and get a surface that will be in a specific driver-chosen format). In particular, the renderer created a dummy surface to probe the format, and hoped the decoder would produce the same format. Due to a driver bug this required a workaround to actually get the same format as the driver did. Change this so that the format is determined in the decoder. The format is then passed down as hw_subfmt, which allows the renderer to configure itself with the correct format. If the hardware surface changes its format midstream, the renderer can be reconfigured using the normal mechanisms. This calls va_surface_init_subformat() each time after the decoder returns a surface. Since libavcodec/AVFrame has no concept of sub- formats, this is unavoidable. It creates and destroys a derived VAImage, but this shouldn't have any bad performance effects (at least I didn't notice any measurable effects). Note that vaDeriveImage() failures are silently ignored as some drivers (the vdpau wrapper) support neither vaDeriveImage, nor EGL interop. In addition, we still probe whether we can map an image in the EGL interop code. This is important as it's the only way to determine whether EGL interop is supported at all. With respect to the driver bug mentioned above, it doesn't matter which format the test surface has. In vf_vavpp, also remove the rt_format guessing business. I think the existing logic was a bit meaningless anyway. It's not even a given that vavpp produces the same rt_format for output. --- video/decode/vaapi.c | 7 ++++++ video/filter/vf_vavpp.c | 27 ++++++++++++++--------- video/out/opengl/hwdec_vaegl.c | 50 +++++++++++------------------------------- video/vaapi.c | 32 +++++++++++++++++++++++++++ video/vaapi.h | 2 ++ 5 files changed, 71 insertions(+), 47 deletions(-) diff --git a/video/decode/vaapi.c b/video/decode/vaapi.c index 2682225876..169564d6c4 100644 --- a/video/decode/vaapi.c +++ b/video/decode/vaapi.c @@ -340,6 +340,12 @@ static struct mp_image *allocate_image(struct lavc_ctx *ctx, int w, int h) return img; } +static struct mp_image *update_format(struct lavc_ctx *ctx, struct mp_image *img) +{ + va_surface_init_subformat(img); + return img; +} + static void destroy_va_dummy_ctx(struct priv *p) { va_destroy(p->ctx); @@ -497,6 +503,7 @@ const struct vd_lavc_hwdec mp_vd_lavc_vaapi = { .allocate_image = allocate_image, .lock = intel_shit_lock, .unlock = intel_crap_unlock, + .process_image = update_format, }; const struct vd_lavc_hwdec mp_vd_lavc_vaapi_copy = { diff --git a/video/filter/vf_vavpp.c b/video/filter/vf_vavpp.c index ae1d6b5476..e076713e9e 100644 --- a/video/filter/vf_vavpp.c +++ b/video/filter/vf_vavpp.c @@ -304,14 +304,6 @@ static int filter_ext(struct vf_instance *vf, struct mp_image *in) struct vf_priv_s *p = vf->priv; if (in) { - int rt_format = in->imgfmt == IMGFMT_VAAPI ? va_surface_rt_format(in) - : VA_RT_FORMAT_YUV420; - if (!p->pool || p->current_rt_format != rt_format) { - talloc_free(p->pool); - p->pool = mp_image_pool_new(20); - va_pool_set_allocator(p->pool, p->va, rt_format); - p->current_rt_format = rt_format; - } if (in->imgfmt != IMGFMT_VAAPI) { struct mp_image *tmp = upload(vf, in); talloc_free(in); @@ -350,10 +342,25 @@ static int reconfig(struct vf_instance *vf, struct mp_image_params *in, { struct vf_priv_s *p = vf->priv; + flush_frames(vf); + talloc_free(p->pool); + p->pool = NULL; + p->params = *in; + + p->current_rt_format = VA_RT_FORMAT_YUV420; + p->pool = mp_image_pool_new(20); + va_pool_set_allocator(p->pool, p->va, p->current_rt_format); + + struct mp_image *probe = mp_image_pool_get(p->pool, IMGFMT_VAAPI, in->w, in->h); + if (!probe) + return -1; + va_surface_init_subformat(probe); *out = *in; - out->imgfmt = IMGFMT_VAAPI; - flush_frames(vf); + out->imgfmt = probe->params.imgfmt; + out->hw_subfmt = probe->params.hw_subfmt; + talloc_free(probe); + return 0; } diff --git a/video/out/opengl/hwdec_vaegl.c b/video/out/opengl/hwdec_vaegl.c index 7b34d6bb5c..d62a20a219 100644 --- a/video/out/opengl/hwdec_vaegl.c +++ b/video/out/opengl/hwdec_vaegl.c @@ -172,30 +172,6 @@ static void destroy(struct gl_hwdec *hw) va_destroy(p->ctx); } -// Create an empty dummy VPP. This works around a weird bug that affects the -// VA surface format, as it is reported by vaDeriveImage(). Before a VPP -// context or a decoder context is created, the surface format will be reported -// as YV12. Surfaces created after context creation will report NV12 (even -// though surface creation does not take a context as argument!). Existing -// surfaces will change their format from YV12 to NV12 as soon as the decoder -// renders to them! Because we want know the surface format in advance (to -// simplify our renderer configuration logic), we hope that this hack gives -// us reasonable behavior. -// See: https://bugs.freedesktop.org/show_bug.cgi?id=79848 -static void insane_hack(struct gl_hwdec *hw) -{ - struct priv *p = hw->priv; - VAConfigID config; - if (vaCreateConfig(p->display, VAProfileNone, VAEntrypointVideoProc, - NULL, 0, &config) == VA_STATUS_SUCCESS) - { - // We want to keep this until the VADisplay is destroyed. It will - // implicitly free the context. - VAContextID context; - vaCreateContext(p->display, config, 0, 0, 0, NULL, 0, &context); - } -} - static int create(struct gl_hwdec *hw) { GL *gl = hw->gl; @@ -248,7 +224,6 @@ static int create(struct gl_hwdec *hw) MP_VERBOSE(p, "using VAAPI EGL interop\n"); - insane_hack(hw); if (!test_format(hw)) { destroy(hw); return -1; @@ -278,6 +253,18 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) } gl->BindTexture(GL_TEXTURE_2D, 0); + hw->converted_imgfmt = va_fourcc_to_imgfmt(params->hw_subfmt); + if (hw->converted_imgfmt != IMGFMT_NV12 && + hw->converted_imgfmt != IMGFMT_420P) + { + MP_FATAL(p, "unsupported VA image format %s\n", + mp_tag_str(params->hw_subfmt)); + return -1; + } + + MP_VERBOSE(p, "format: %s %s\n", mp_tag_str(params->hw_subfmt), + mp_imgfmt_to_name(hw->converted_imgfmt)); + return 0; } @@ -308,18 +295,6 @@ static int map_image(struct gl_hwdec *hw, struct mp_image *hw_image, goto err; int mpfmt = va_fourcc_to_imgfmt(va_image->format.fourcc); - if (mpfmt != IMGFMT_NV12 && mpfmt != IMGFMT_420P) { - MP_FATAL(p, "unsupported VA image format %s\n", - mp_tag_str(va_image->format.fourcc)); - goto err; - } - - if (!hw->converted_imgfmt) { - MP_VERBOSE(p, "format: %s %s\n", mp_tag_str(va_image->format.fourcc), - mp_imgfmt_to_name(mpfmt)); - hw->converted_imgfmt = mpfmt; - } - if (hw->converted_imgfmt != mpfmt) { MP_FATAL(p, "mid-stream hwdec format change (%s -> %s) not supported\n", mp_imgfmt_to_name(hw->converted_imgfmt), mp_imgfmt_to_name(mpfmt)); @@ -387,6 +362,7 @@ static bool test_format(struct gl_hwdec *hw) va_pool_set_allocator(alloc, p->ctx, VA_RT_FORMAT_YUV420); struct mp_image *surface = mp_image_pool_get(alloc, IMGFMT_VAAPI, 64, 64); if (surface) { + va_surface_init_subformat(surface); struct mp_image_params params = surface->params; if (reinit(hw, ¶ms) >= 0) { GLuint textures[4]; diff --git a/video/vaapi.c b/video/vaapi.c index 61d94ef156..9a5820a98c 100644 --- a/video/vaapi.c +++ b/video/vaapi.c @@ -487,6 +487,38 @@ struct mp_image *va_surface_download(struct mp_image *src, return NULL; } +// Set the hw_subfmt from the surface's real format. Because of this bug: +// https://bugs.freedesktop.org/show_bug.cgi?id=79848 +// it should be assumed that the real format is only known after an arbitrary +// vaCreateContext() call has been made, or even better, after the surface +// has been rendered to. +// If the hw_subfmt is already set, this is a NOP. +void va_surface_init_subformat(struct mp_image *mpi) +{ + VAStatus status; + if (mpi->params.hw_subfmt) + return; + struct va_surface *p = va_surface_in_mp_image(mpi); + if (!p) + return; + + VAImage va_image = { .image_id = VA_INVALID_ID }; + + va_lock(p->ctx); + + status = vaDeriveImage(p->display, va_surface_id(mpi), &va_image); + if (status != VA_STATUS_SUCCESS) + goto err; + + mpi->params.hw_subfmt = va_image.format.fourcc; + + status = vaDestroyImage(p->display, va_image.image_id); + CHECK_VA_STATUS(p->ctx, "vaDestroyImage()"); + +err: + va_unlock(p->ctx); +} + struct pool_alloc_ctx { struct mp_vaapi_ctx *vaapi; int rt_format; diff --git a/video/vaapi.h b/video/vaapi.h index 11ff2c96f9..3f0d1dca37 100644 --- a/video/vaapi.h +++ b/video/vaapi.h @@ -69,6 +69,8 @@ struct mp_image *va_surface_download(struct mp_image *src, int va_surface_alloc_imgfmt(struct mp_image *img, int imgfmt); int va_surface_upload(struct mp_image *va_dst, struct mp_image *sw_src); +void va_surface_init_subformat(struct mp_image *mpi); + bool va_guess_if_emulated(struct mp_vaapi_ctx *ctx); #endif -- cgit v1.2.3 From 837b865c7f12d09dee5bcee8f8deb2955dacf410 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 11 Apr 2016 22:02:37 +0200 Subject: vf_vavpp: reindent --- video/filter/vf_vavpp.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/video/filter/vf_vavpp.c b/video/filter/vf_vavpp.c index e076713e9e..9dab15e2b9 100644 --- a/video/filter/vf_vavpp.c +++ b/video/filter/vf_vavpp.c @@ -303,14 +303,12 @@ static int filter_ext(struct vf_instance *vf, struct mp_image *in) { struct vf_priv_s *p = vf->priv; - if (in) { - if (in->imgfmt != IMGFMT_VAAPI) { - struct mp_image *tmp = upload(vf, in); - talloc_free(in); - in = tmp; - if (!in) - return -1; - } + if (in && in->imgfmt != IMGFMT_VAAPI) { + struct mp_image *tmp = upload(vf, in); + talloc_free(in); + in = tmp; + if (!in) + return -1; } if (in) { -- cgit v1.2.3 From f4142ab9ad1d929b60ff134754f482754b63043a Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 12 Apr 2016 15:41:44 +0200 Subject: demux_mkv: fix seeking with files that miss the first index entry Now it will always be able to seek back to the start, even if the index is sparse or misses the first entry. This can be achieved by reusing the logic for incremental index generation (for files with no index), and start time probing (for making sure the first block is always indexed). --- demux/demux_mkv.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index b0a910bf68..210f4d643f 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -773,8 +773,9 @@ static int demux_mkv_read_cues(demuxer_t *demuxer) if (cues.n_cue_point <= 3) // probably too sparse and will just break seeking goto done; - // Discard incremental index. - mkv_d->num_indexes = 0; + // Discard incremental index. (Keep the first entry, which must be the + // start of the file - helps with files that miss the first index entry.) + mkv_d->num_indexes = MPMIN(1, mkv_d->num_indexes); mkv_d->index_has_durations = false; for (int i = 0; i < cues.n_cue_point; i++) { @@ -2963,8 +2964,10 @@ static void probe_first_timestamp(struct demuxer *demuxer) return; struct block_info block; - if (read_next_block(demuxer, &block) > 0) + if (read_next_block(demuxer, &block) > 0) { + index_block(demuxer, &block); mkv_d->tmp_block = block; + } demuxer->start_time = mkv_d->cluster_tc / 1e9; -- cgit v1.2.3 From e3e03d0f34de86085d18f92a3dceab337c3220b6 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Tue, 12 Apr 2016 15:55:48 +0200 Subject: vo_opengl: simplify and improve up scale=oversample Since what we're doing is a linear blend of the four colors, we can just do it for free by using GPU sampling. This requires significantly fewer texture fetches and calculations to compute the final color, making it much more efficient. The code is also much shorter and simpler. --- video/out/opengl/video_shaders.c | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/video/out/opengl/video_shaders.c b/video/out/opengl/video_shaders.c index bea1bbf325..cf022b96dd 100644 --- a/video/out/opengl/video_shaders.c +++ b/video/out/opengl/video_shaders.c @@ -208,31 +208,15 @@ void pass_sample_oversample(struct gl_shader_cache *sc, struct scaler *scaler, GLSLF("{\n"); GLSL(vec2 pos = pos + vec2(0.5) * pt;) // round to nearest GLSL(vec2 fcoord = fract(pos * size - vec2(0.5));) - // We only need to sample from the four corner pixels since we're using - // nearest neighbour and can compute the exact transition point - GLSL(vec2 baseNW = pos - fcoord * pt;) - GLSL(vec2 baseNE = baseNW + vec2(pt.x, 0.0);) - GLSL(vec2 baseSW = baseNW + vec2(0.0, pt.y);) - GLSL(vec2 baseSE = baseNW + pt;) // Determine the mixing coefficient vector gl_sc_uniform_vec2(sc, "output_size", (float[2]){w, h}); - GLSL(vec2 coeff = vec2((baseSE - pos) * output_size);) - GLSL(coeff = clamp(coeff, 0.0, 1.0);) + GLSL(vec2 coeff = fcoord * output_size/size;) float threshold = scaler->conf.kernel.params[0]; - if (threshold > 0) { // also rules out NAN - GLSLF("coeff = mix(coeff, vec2(0.0), " - "lessThanEqual(coeff, vec2(%f)));\n", threshold); - GLSLF("coeff = mix(coeff, vec2(1.0), " - "greaterThanEqual(coeff, vec2(%f)));\n", 1.0 - threshold); - } + threshold = isnan(threshold) ? 0.0 : threshold; + GLSLF("coeff = (coeff - %f) / %f;\n", threshold, 1.0 - 2 * threshold); + GLSL(coeff = clamp(coeff, 0.0, 1.0);) // Compute the right blend of colors - GLSL(vec4 left = mix(texture(tex, baseSW), - texture(tex, baseNW), - coeff.y);) - GLSL(vec4 right = mix(texture(tex, baseSE), - texture(tex, baseNE), - coeff.y);) - GLSL(color = mix(right, left, coeff.x);) + GLSL(color = texture(tex, pos + pt * (coeff - fcoord));) GLSLF("}\n"); } -- cgit v1.2.3 From 9a4120f21f316d95d7788cbf71fe36abbb2e279e Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 13 Apr 2016 22:22:53 +0200 Subject: m_option: add string conversion for --audio-channels Requested in #3040. --- options/m_option.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/options/m_option.c b/options/m_option.c index 9f2d8758d0..5b07ba5d2a 100644 --- a/options/m_option.c +++ b/options/m_option.c @@ -2287,10 +2287,18 @@ static int parse_chmap(struct mp_log *log, const m_option_t *opt, return 1; } +static char *print_chmap(const m_option_t *opt, const void *val) +{ + const struct mp_chmap *chmap = val; + return talloc_strdup(NULL, mp_chmap_to_str(chmap)); +} + + const m_option_type_t m_option_type_chmap = { .name = "Audio channels or channel map", .size = sizeof(struct mp_chmap), .parse = parse_chmap, + .print = print_chmap, .copy = copy_opt, }; -- cgit v1.2.3 From 0467f5287debc3d37b9992f12912ee72c011468d Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 13 Apr 2016 22:25:51 +0200 Subject: m_option: slightly improve --msg-level=help output In particular get rid of the semi-deprecated ":" separator. --- options/m_option.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/m_option.c b/options/m_option.c index 5b07ba5d2a..1d929269b0 100644 --- a/options/m_option.c +++ b/options/m_option.c @@ -1654,7 +1654,7 @@ static int parse_msglevels(struct mp_log *log, const m_option_t *opt, struct bstr name, struct bstr param, void *dst) { if (bstr_equals0(param, "help")) { - mp_info(log, "Syntax: --msglevel=module1=level:module2=level:...\n" + mp_info(log, "Syntax:\n\n --msglevel=module1=level,module2=level,...\n\n" "'module' is output prefix as shown with -v, or a prefix\n" "of it. level is one of:\n\n" " fatal error warn info status v debug trace\n\n" -- cgit v1.2.3 From e13cc25a2ca815f6351def8ebb6e18a89b46b6b5 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 14 Apr 2016 18:20:13 +0200 Subject: build: add check for AVHWFramesContext API It's not used yet anywhere. Pushing this now so switching between branches is less bothersome. --- wscript | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wscript b/wscript index 6d77932681..a4ffce6031 100644 --- a/wscript +++ b/wscript @@ -496,6 +496,12 @@ FFmpeg/Libav libraries. You need at least {0}. Aborting.".format(libav_versions_ 'func': check_statement('libavformat/avformat.h', '(void)offsetof(AVStream, codecpar)', use='libav'), + }, { + 'name': 'avutil-has-hwcontext', + 'desc': 'libavutil AVHWFramesContext API', + 'func': check_statement('libavutil/frame.h', + '(void)offsetof(AVFrame, hw_frames_ctx)', + use='libav'), }, ] -- cgit v1.2.3 From 4ebac1e936f761f08d455acf77be40c93048f6d5 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 14 Apr 2016 22:39:10 +0200 Subject: player: fix use-after-free with --screenshot-directory Probably fixes #3049. --- player/screenshot.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/player/screenshot.c b/player/screenshot.c index 02cbb4a500..33b972bb25 100644 --- a/player/screenshot.c +++ b/player/screenshot.c @@ -287,9 +287,10 @@ static char *gen_fname(screenshot_ctx *ctx, const char *file_ext) void *t = fname; dir = mp_get_user_path(t, ctx->mpctx->global, dir); fname = mp_path_join(NULL, dir, fname); - talloc_free(t); mp_mkdirp(dir); + + talloc_free(t); } if (!mp_path_exists(fname)) -- cgit v1.2.3 From 8c02c92ab962107ee43c71854bd9712cc492046e Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 15 Apr 2016 09:45:15 +0200 Subject: vo_opengl: rpi: don't include x11 header file Copy & paste bug. --- video/out/opengl/context_rpi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/video/out/opengl/context_rpi.c b/video/out/opengl/context_rpi.c index c01c173b8f..c0ca73335a 100644 --- a/video/out/opengl/context_rpi.c +++ b/video/out/opengl/context_rpi.c @@ -19,7 +19,6 @@ #include #include "common/common.h" -#include "video/out/x11_common.h" #include "context.h" #include "context_rpi.h" -- cgit v1.2.3 From a9bd4535d2eac283824d8598aa17f1f44f83a74a Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 15 Apr 2016 11:31:24 +0200 Subject: client API: improve mpv_set_property() handling of MPV_FORMAT_NODE If a mpv_node wrapped a string, the behavior was different from calling mpv_set_property() with MPV_FORMAT_STRING directly. Change this. The original intention was to be strict about types if MPV_FORMAT_NODE is used. But I think the result was less than ideal, and the same change towards less strict behavior was made to mpv_set_option() ages ago. --- DOCS/client-api-changes.rst | 9 ++++++++ libmpv/client.h | 14 ++++++++++-- options/m_option.c | 15 +++++++++++++ options/m_option.h | 4 ++++ options/m_property.c | 17 +++++---------- player/client.c | 52 ++++++++++++++++----------------------------- 6 files changed, 63 insertions(+), 48 deletions(-) diff --git a/DOCS/client-api-changes.rst b/DOCS/client-api-changes.rst index f2cc5993eb..44490ea79d 100644 --- a/DOCS/client-api-changes.rst +++ b/DOCS/client-api-changes.rst @@ -32,6 +32,15 @@ API changes :: + --- mpv 0.17.1 --- + 1.21 - mpv_set_property() changes behavior with MPV_FORMAT_NODE. Before this + change it rejected mpv_nodes with format==MPV_FORMAT_STRING if the + property was not a string or did not have special mechanisms in place + the function failed. Now it always invokes the option string parser, + and mpv_node with a basic data type works exactly as if the function + is invoked with that type directly. This new behavior is equivalent + to mpv_set_option(). + This also affects the mp.set_property_native() Lua function. --- mpv 0.12.0 --- 1.20 - deprecate "GL