This exposes VP8E_SET_SCREEN_CONTENT_MODE option from libvpx. Changes since v1: - Put the new param initialzation in the right place, - Account for cases when the encoder's output is queued up.
Co-authored-by: Erik Språng <spr...@webrtc.org> Signed-off-by: Dariusz Marcinkiewicz <dar...@google.com> --- doc/encoders.texi | 7 ++++-- libavcodec/libvpxenc.c | 56 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/doc/encoders.texi b/doc/encoders.texi index c9fe6d6143..2a9b38f62a 100644 --- a/doc/encoders.texi +++ b/doc/encoders.texi @@ -2186,6 +2186,11 @@ Enable error resiliency features. Increase sharpness at the expense of lower PSNR. The valid range is [0, 7]. +@item tune-content +Set content type. +For VP8: default (0), screen (1), screen with aggressive rate control (2). +For VP9: default (0), screen (1), film (2). + @item ts-parameters Sets the temporal scalability configuration using a :-separated list of key=value pairs. For example, to specify temporal scalability parameters @@ -2268,8 +2273,6 @@ colorspaces: @end table @item row-mt @var{boolean} Enable row based multi-threading. -@item tune-content -Set content type: default (0), screen (1), film (2). @item corpus-complexity Corpus VBR mode is a variant of standard VBR where the complexity distribution midpoint is passed in rather than calculated for a specific clip or chunk. diff --git a/libavcodec/libvpxenc.c b/libavcodec/libvpxenc.c index 80988a2608..c73c92d49b 100644 --- a/libavcodec/libvpxenc.c +++ b/libavcodec/libvpxenc.c @@ -164,6 +164,7 @@ static const char *const ctlidstr[] = { [VP8E_SET_MAX_INTRA_BITRATE_PCT] = "VP8E_SET_MAX_INTRA_BITRATE_PCT", [VP8E_SET_SHARPNESS] = "VP8E_SET_SHARPNESS", [VP8E_SET_TEMPORAL_LAYER_ID] = "VP8E_SET_TEMPORAL_LAYER_ID", + [VP8E_SET_SCREEN_CONTENT_MODE] = "VP8E_SET_SCREEN_CONTENT_MODE", #if CONFIG_LIBVPX_VP9_ENCODER [VP9E_SET_LOSSLESS] = "VP9E_SET_LOSSLESS", [VP9E_SET_TILE_COLUMNS] = "VP9E_SET_TILE_COLUMNS", @@ -1262,6 +1263,16 @@ static av_cold int vpx_init(AVCodecContext *avctx, #endif } #endif +#ifdef VPX_CTRL_VP8E_SET_SCREEN_CONTENT_MODE + if (avctx->codec_id == AV_CODEC_ID_VP8 && ctx->tune_content >= 0) { + if (ctx->tune_content == 2 && ctx->is_alpha) { + av_log(avctx, AV_LOG_ERROR, + "Transparency encoding with screen mode with aggressive rate control not supported\n"); + return AVERROR(EINVAL); + } + codecctl_int(avctx, VP8E_SET_SCREEN_CONTENT_MODE, ctx->tune_content); + } +#endif av_log(avctx, AV_LOG_DEBUG, "Using deadline: %d\n", ctx->deadline); @@ -1379,14 +1390,15 @@ static int storeframe(AVCodecContext *avctx, struct FrameListData *cx_frame, * @return AVERROR(ENOMEM) on coded frame queue data allocation error */ static int queue_frames(AVCodecContext *avctx, struct vpx_codec_ctx *encoder, - struct FrameListData **frame_list, AVPacket *pkt_out) + struct FrameListData **frame_list, AVPacket *pkt_out, + int queue_only, int *frame_enc) { VPxContext *ctx = avctx->priv_data; const struct vpx_codec_cx_pkt *pkt; const void *iter = NULL; int size = 0; - if (!ctx->is_alpha && *frame_list) { + if (!queue_only && *frame_list) { struct FrameListData *cx_frame = *frame_list; /* return the leading frame if we've already begun queueing */ size = storeframe(avctx, cx_frame, NULL, pkt_out); @@ -1401,7 +1413,7 @@ static int queue_frames(AVCodecContext *avctx, struct vpx_codec_ctx *encoder, while (pkt = vpx_codec_get_cx_data(encoder, &iter)) { switch (pkt->kind) { case VPX_CODEC_CX_FRAME_PKT: - if (!ctx->is_alpha && !size) { + if (!queue_only && !size) { struct FrameListData cx_frame; /* avoid storing the frame when the list is empty and we haven't yet @@ -1411,6 +1423,8 @@ static int queue_frames(AVCodecContext *avctx, struct vpx_codec_ctx *encoder, size = storeframe(avctx, &cx_frame, NULL, pkt_out); if (size < 0) return size; + if (size > 0) + *frame_enc = 1; } else { struct FrameListData *cx_frame = av_malloc(sizeof(*cx_frame)); @@ -1430,6 +1444,8 @@ static int queue_frames(AVCodecContext *avctx, struct vpx_codec_ctx *encoder, return AVERROR(ENOMEM); } memcpy(cx_frame->buf, pkt->data.frame.buf, pkt->data.frame.sz); + if (pkt->data.frame.sz > 0) + *frame_enc = 1; coded_frame_add(frame_list, cx_frame); } break; @@ -1693,6 +1709,7 @@ static int vpx_encode(AVCodecContext *avctx, AVPacket *pkt, vpx_svc_layer_id_t layer_id; int layer_id_valid = 0; unsigned long duration = 0; + int frame_enc = 0; if (avctx->qmax >= 0 && enccfg->rc_max_quantizer != avctx->qmax) { struct vpx_codec_enc_cfg cfg = *enccfg; @@ -1856,9 +1873,32 @@ FF_ENABLE_DEPRECATION_WARNINGS } } - coded_size = queue_frames(avctx, &ctx->encoder, &ctx->coded_frame_list, pkt); + coded_size = queue_frames(avctx, &ctx->encoder, &ctx->coded_frame_list, + pkt, ctx->is_alpha, &frame_enc); + if (avctx->codec_id == AV_CODEC_ID_VP8 && frame_enc == 0 && + ctx->tune_content == 2 && frame) { + // VP8 tuned for screen content with aggresive rate control - returned + // OK status code but produced no output, this indicates frame was + // rolled back due to bitrate overshoot - try to encode it again. + av_log(avctx, AV_LOG_VERBOSE, + "Attempting to reencode dropped VP8 screencast frame.\n"); + res = vpx_codec_encode(&ctx->encoder, rawimg, timestamp, + duration, flags, ctx->deadline); + if (res != VPX_CODEC_OK) { + log_encoder_error(avctx, "Error encoding frame"); + return AVERROR_INVALIDDATA; + } + if (!coded_size) + coded_size = queue_frames(avctx, &ctx->encoder, &ctx->coded_frame_list, + pkt, /*queue_only*/0, &frame_enc); + else + queue_frames(avctx, &ctx->encoder, &ctx->coded_frame_list, pkt, + /*queue_only*/1, &frame_enc); + } + if (ctx->is_alpha) { - queue_frames(avctx, &ctx->encoder_alpha, &ctx->alpha_coded_frame_list, NULL); + queue_frames(avctx, &ctx->encoder_alpha, &ctx->alpha_coded_frame_list, + NULL, /*queue_only*/1, &frame_enc); if (ctx->coded_frame_list && ctx->alpha_coded_frame_list) { struct FrameListData *cx_frame = ctx->coded_frame_list; @@ -1946,6 +1986,12 @@ static const AVOption vp8_options[] = { { "auto-alt-ref", "Enable use of alternate reference " "frames (2-pass only)", OFFSET(auto_alt_ref), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 2, VE}, { "cpu-used", "Quality/Speed ratio modifier", OFFSET(cpu_used), AV_OPT_TYPE_INT, {.i64 = 1}, -16, 16, VE}, +#ifdef VPX_CTRL_VP8E_SET_SCREEN_CONTENT_MODE + { "tune-content", "Tune content type", OFFSET(tune_content), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 2, VE, "tune_content"}, + { "default", "Regular video content", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, VE, "tune_content"}, + { "screen", "Screen content mode on", 0, AV_OPT_TYPE_CONST, {.i64 = 1}, 0, 0, VE, "tune_content"}, + { "screen-rate-control", "Screen content mode with aggressive rate control", 0, AV_OPT_TYPE_CONST, {.i64 = 2}, 0, 0, VE, "tune_content"}, +#endif LEGACY_OPTIONS { NULL } }; -- 2.43.0.429.g432eaa2c6b-goog _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".