X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=libavcodec%2Flibvpxenc.c;h=f690de145ca0d577a34e9549abbc4aaef389a035;hb=e61f39849c2e2b7f492c17b42058242ed2fa4d57;hp=9774d5aec4a0b5847168e10123c81cb3d72dba26;hpb=12776d5d2a46363c52603ae2be888a3094fce1c6;p=ffmpeg diff --git a/libavcodec/libvpxenc.c b/libavcodec/libvpxenc.c index 9774d5aec4a..f690de145ca 100644 --- a/libavcodec/libvpxenc.c +++ b/libavcodec/libvpxenc.c @@ -30,6 +30,7 @@ #include "avcodec.h" #include "internal.h" +#include "libvpx.h" #include "libavutil/base64.h" #include "libavutil/common.h" #include "libavutil/mathematics.h" @@ -65,6 +66,7 @@ typedef struct VP8EncoderContext { int lag_in_frames; int error_resilient; int crf; + int static_thresh; } VP8Context; /** String mappings for enum vp8e_enc_control_id */ @@ -158,7 +160,7 @@ static void coded_frame_add(void *list, struct FrameListData *cx_frame) { struct FrameListData **p = list; - while (*p != NULL) + while (*p) p = &(*p)->next; *p = cx_frame; cx_frame->next = NULL; @@ -214,11 +216,11 @@ static av_cold int vp8_free(AVCodecContext *avctx) return 0; } -static av_cold int vp8_init(AVCodecContext *avctx) +static av_cold int vpx_init(AVCodecContext *avctx, + const struct vpx_codec_iface *iface) { VP8Context *ctx = avctx->priv_data; - const struct vpx_codec_iface *iface = &vpx_codec_vp8_cx_algo; - struct vpx_codec_enc_cfg enccfg; + struct vpx_codec_enc_cfg enccfg = { 0 }; int res; av_log(avctx, AV_LOG_INFO, "%s\n", vpx_codec_version_str()); @@ -290,7 +292,7 @@ static av_cold int vp8_init(AVCodecContext *avctx) if (enccfg.g_pass == VPX_RC_FIRST_PASS) enccfg.g_lag_in_frames = 0; else if (enccfg.g_pass == VPX_RC_LAST_PASS) { - int decode_size; + int decode_size, ret; if (!avctx->stats_in) { av_log(avctx, AV_LOG_ERROR, "No stats file for second pass\n"); @@ -298,12 +300,12 @@ static av_cold int vp8_init(AVCodecContext *avctx) } ctx->twopass_stats.sz = strlen(avctx->stats_in) * 3 / 4; - ctx->twopass_stats.buf = av_malloc(ctx->twopass_stats.sz); - if (!ctx->twopass_stats.buf) { + ret = av_reallocp(&ctx->twopass_stats.buf, ctx->twopass_stats.sz); + if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Stat buffer alloc (%zu bytes) failed\n", ctx->twopass_stats.sz); - return AVERROR(ENOMEM); + return ret; } decode_size = av_base64_decode(ctx->twopass_stats.buf, avctx->stats_in, ctx->twopass_stats.sz); @@ -319,8 +321,12 @@ static av_cold int vp8_init(AVCodecContext *avctx) /* 0-3: For non-zero values the encoder increasingly optimizes for reduced complexity playback on low powered devices at the expense of encode quality. */ - if (avctx->profile != FF_PROFILE_UNKNOWN) - enccfg.g_profile = avctx->profile; + if (avctx->profile != FF_PROFILE_UNKNOWN) + enccfg.g_profile = avctx->profile; + else if (avctx->pix_fmt == AV_PIX_FMT_YUV420P) + avctx->profile = enccfg.g_profile = FF_PROFILE_VP9_0; + else + avctx->profile = enccfg.g_profile = FF_PROFILE_VP9_1; enccfg.g_error_resilient = ctx->error_resilient; @@ -344,16 +350,28 @@ static av_cold int vp8_init(AVCodecContext *avctx) codecctl_int(avctx, VP8E_SET_ARNR_STRENGTH, ctx->arnr_strength); if (ctx->arnr_type >= 0) codecctl_int(avctx, VP8E_SET_ARNR_TYPE, ctx->arnr_type); - codecctl_int(avctx, VP8E_SET_NOISE_SENSITIVITY, avctx->noise_reduction); - codecctl_int(avctx, VP8E_SET_TOKEN_PARTITIONS, av_log2(avctx->slices)); - codecctl_int(avctx, VP8E_SET_STATIC_THRESHOLD, avctx->mb_threshold); + + if (CONFIG_LIBVPX_VP8_ENCODER && iface == &vpx_codec_vp8_cx_algo) { + codecctl_int(avctx, VP8E_SET_NOISE_SENSITIVITY, avctx->noise_reduction); + codecctl_int(avctx, VP8E_SET_TOKEN_PARTITIONS, av_log2(avctx->slices)); + } +#if FF_API_MPV_OPT + FF_DISABLE_DEPRECATION_WARNINGS + if (avctx->mb_threshold) { + av_log(avctx, AV_LOG_WARNING, "The mb_threshold option is deprecated, " + "use the static-thresh private option instead.\n"); + ctx->static_thresh = avctx->mb_threshold; + } + FF_ENABLE_DEPRECATION_WARNINGS +#endif + codecctl_int(avctx, VP8E_SET_STATIC_THRESHOLD, ctx->static_thresh); codecctl_int(avctx, VP8E_SET_CQ_LEVEL, ctx->crf); //provide dummy value to initialize wrapper, values will be updated each _encode() - vpx_img_wrap(&ctx->rawimg, VPX_IMG_FMT_I420, avctx->width, avctx->height, 1, - (unsigned char*)1); + vpx_img_wrap(&ctx->rawimg, ff_vpx_pixfmt_to_imgfmt(avctx->pix_fmt), + avctx->width, avctx->height, 1, (unsigned char *)1); - avctx->coded_frame = avcodec_alloc_frame(); + avctx->coded_frame = av_frame_alloc(); if (!avctx->coded_frame) { av_log(avctx, AV_LOG_ERROR, "Error allocating coded frame\n"); vp8_free(avctx); @@ -459,6 +477,7 @@ static int queue_frames(AVCodecContext *avctx, AVPacket *pkt_out, av_log(avctx, AV_LOG_ERROR, "Data buffer alloc (%zu bytes) failed\n", cx_frame->sz); + av_freep(&cx_frame); return AVERROR(ENOMEM); } memcpy(cx_frame->buf, pkt->data.frame.buf, pkt->data.frame.sz); @@ -467,11 +486,13 @@ static int queue_frames(AVCodecContext *avctx, AVPacket *pkt_out, break; case VPX_CODEC_STATS_PKT: { struct vpx_fixed_buf *stats = &ctx->twopass_stats; - stats->buf = av_realloc(stats->buf, - stats->sz + pkt->data.twopass_stats.sz); - if (!stats->buf) { + int err; + if ((err = av_reallocp(&stats->buf, + stats->sz + + pkt->data.twopass_stats.sz)) < 0) { + stats->sz = 0; av_log(avctx, AV_LOG_ERROR, "Stat buffer realloc failed\n"); - return AVERROR(ENOMEM); + return err; } memcpy((uint8_t*)stats->buf + stats->sz, pkt->data.twopass_stats.buf, pkt->data.twopass_stats.sz); @@ -495,6 +516,7 @@ static int vp8_encode(AVCodecContext *avctx, AVPacket *pkt, struct vpx_image *rawimg = NULL; int64_t timestamp = 0; int res, coded_size; + vpx_enc_frame_flags_t flags = 0; if (frame) { rawimg = &ctx->rawimg; @@ -505,10 +527,12 @@ static int vp8_encode(AVCodecContext *avctx, AVPacket *pkt, rawimg->stride[VPX_PLANE_U] = frame->linesize[1]; rawimg->stride[VPX_PLANE_V] = frame->linesize[2]; timestamp = frame->pts; + if (frame->pict_type == AV_PICTURE_TYPE_I) + flags |= VPX_EFLAG_FORCE_KF; } res = vpx_codec_encode(&ctx->encoder, rawimg, timestamp, - avctx->ticks_per_frame, 0, ctx->deadline); + avctx->ticks_per_frame, flags, ctx->deadline); if (res != VPX_CODEC_OK) { log_encoder_error(avctx, "Error encoding frame"); return AVERROR_INVALIDDATA; @@ -535,7 +559,7 @@ static int vp8_encode(AVCodecContext *avctx, AVPacket *pkt, #define OFFSET(x) offsetof(VP8Context, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "cpu-used", "Quality/Speed ratio modifier", OFFSET(cpu_used), AV_OPT_TYPE_INT, {.i64 = INT_MIN}, INT_MIN, INT_MAX, VE}, + { "cpu-used", "Quality/Speed ratio modifier", OFFSET(cpu_used), AV_OPT_TYPE_INT, {.i64 = 1}, INT_MIN, INT_MAX, VE}, { "auto-alt-ref", "Enable use of alternate reference " "frames (2-pass only)", OFFSET(auto_alt_ref), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, VE}, { "lag-in-frames", "Number of frames to look ahead for " @@ -559,16 +583,10 @@ static const AVOption options[] = { " is still done over the partition boundary.", 0, AV_OPT_TYPE_CONST, {.i64 = VPX_ERROR_RESILIENT_PARTITIONS}, 0, 0, VE, "er"}, #endif { "crf", "Select the quality for constant quality mode", offsetof(VP8Context, crf), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 63, VE }, + { "static-thresh", "A change threshold on blocks below which they will be skipped by the encoder", OFFSET(static_thresh), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, { NULL } }; -static const AVClass class = { - .class_name = "libvpx encoder", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, -}; - static const AVCodecDefault defaults[] = { { "qmin", "-1" }, { "qmax", "-1" }, @@ -577,8 +595,22 @@ static const AVCodecDefault defaults[] = { { NULL }, }; -AVCodec ff_libvpx_encoder = { +#if CONFIG_LIBVPX_VP8_ENCODER +static av_cold int vp8_init(AVCodecContext *avctx) +{ + return vpx_init(avctx, &vpx_codec_vp8_cx_algo); +} + +static const AVClass class_vp8 = { + .class_name = "libvpx encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_libvpx_vp8_encoder = { .name = "libvpx", + .long_name = NULL_IF_CONFIG_SMALL("libvpx VP8"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VP8, .priv_data_size = sizeof(VP8Context), @@ -587,7 +619,53 @@ AVCodec ff_libvpx_encoder = { .close = vp8_free, .capabilities = CODEC_CAP_DELAY | CODEC_CAP_AUTO_THREADS, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, - .long_name = NULL_IF_CONFIG_SMALL("libvpx VP8"), - .priv_class = &class, + .priv_class = &class_vp8, + .defaults = defaults, +}; +#endif /* CONFIG_LIBVPX_VP8_ENCODER */ + +#if CONFIG_LIBVPX_VP9_ENCODER +static av_cold int vp9_init(AVCodecContext *avctx) +{ + return vpx_init(avctx, &vpx_codec_vp9_cx_algo); +} + +static const AVClass class_vp9 = { + .class_name = "libvpx encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVProfile profiles[] = { + { FF_PROFILE_VP9_0, "Profile 0" }, + { FF_PROFILE_VP9_1, "Profile 1" }, + { FF_PROFILE_VP9_2, "Profile 2" }, + { FF_PROFILE_VP9_3, "Profile 3" }, + { FF_PROFILE_UNKNOWN }, +}; + +AVCodec ff_libvpx_vp9_encoder = { + .name = "libvpx-vp9", + .long_name = NULL_IF_CONFIG_SMALL("libvpx VP9"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_VP9, + .priv_data_size = sizeof(VP8Context), + .init = vp9_init, + .encode2 = vp8_encode, + .close = vp8_free, + .capabilities = CODEC_CAP_DELAY | CODEC_CAP_AUTO_THREADS, + .pix_fmts = (const enum AVPixelFormat[]) { + AV_PIX_FMT_YUV420P, +#if VPX_IMAGE_ABI_VERSION >= 3 + AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUV440P, +#endif + AV_PIX_FMT_NONE, + }, + .profiles = NULL_IF_CONFIG_SMALL(profiles), + .priv_class = &class_vp9, .defaults = defaults, }; +#endif /* CONFIG_LIBVPX_VP9_ENCODER */