This patch is for discussion only, not ready to commit yet.

1. Cuvid decoder actualy support scaling input to requested resolution without any performance penalty (like libnpp does), so this patch is proof of concept that it is working like expected.

2. Cuvid also supports cropping, but from tests only in 4px steps, this is also very nice, because hwaccel cuvid hasn't any cropping filter.

Anybody feel free to adopt this patch and modify it for final commit.

--
Miroslav Slugeň














>From 9f5dfd6e9cabd3d419a3a58f7bfa3b3c1e179638 Mon Sep 17 00:00:00 2001
From: Miroslav Slugen <thunde...@email.cz>
Date: Sun, 12 Feb 2017 20:29:34 +0100
Subject: [PATCH 1/1] cuvid: add resize and crop futures

---
 ffmpeg.h           |  2 ++
 ffmpeg_opt.c       | 12 +++++++
 libavcodec/cuvid.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++--------
 3 files changed, 96 insertions(+), 13 deletions(-)

diff --git a/ffmpeg.h b/ffmpeg.h
index 85a8f18..0374f11 100644
--- a/ffmpeg.h
+++ b/ffmpeg.h
@@ -132,6 +132,8 @@ typedef struct OptionsContext {
     int        nb_hwaccel_output_formats;
     SpecifierOpt *autorotate;
     int        nb_autorotate;
+    SpecifierOpt *resize;
+    int        nb_resize;
 
     /* output options */
     StreamMap *stream_maps;
diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c
index 6a47d32..fcf4792 100644
--- a/ffmpeg_opt.c
+++ b/ffmpeg_opt.c
@@ -659,6 +659,7 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
         char *codec_tag = NULL;
         char *next;
         char *discard_str = NULL;
+        char *resize_str = NULL;
         const AVClass *cc = avcodec_get_class();
         const AVOption *discard_opt = av_opt_find(&cc, "skip_frame", NULL, 0, 0);
 
@@ -722,6 +723,14 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
         case AVMEDIA_TYPE_VIDEO:
             if(!ist->dec)
                 ist->dec = avcodec_find_decoder(par->codec_id);
+
+            MATCH_PER_STREAM_OPT(resize, str, resize_str, ic, st);
+            if (resize_str) {
+                av_parse_video_size(&ist->dec_ctx->width, &ist->dec_ctx->height, resize_str);
+                ist->dec_ctx->coded_width  = ist->dec_ctx->width;
+                ist->dec_ctx->coded_height = ist->dec_ctx->height;
+            }
+
 #if FF_API_EMU_EDGE
             if (av_codec_get_lowres(st->codec)) {
                 av_codec_set_lowres(ist->dec_ctx, av_codec_get_lowres(st->codec));
@@ -3591,6 +3600,9 @@ const OptionDef options[] = {
     { "hwaccel_output_format", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
                           OPT_SPEC | OPT_INPUT,                                  { .off = OFFSET(hwaccel_output_formats) },
         "select output format used with HW accelerated decoding", "format" },
+    { "resize",         OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
+                        OPT_SPEC | OPT_INPUT | OPT_OUTPUT,                       { .off = OFFSET(resize) },
+        "resizer builtin input or output" },
 #if CONFIG_VDA || CONFIG_VIDEOTOOLBOX
     { "videotoolbox_pixfmt", HAS_ARG | OPT_STRING | OPT_EXPERT, { &videotoolbox_pixfmt}, "" },
 #endif
diff --git a/libavcodec/cuvid.c b/libavcodec/cuvid.c
index a2e125d..7370ed1 100644
--- a/libavcodec/cuvid.c
+++ b/libavcodec/cuvid.c
@@ -21,6 +21,7 @@
 
 #include "compat/cuda/dynlink_loader.h"
 
+#include "libavutil/avstring.h"
 #include "libavutil/buffer.h"
 #include "libavutil/mathematics.h"
 #include "libavutil/hwcontext.h"
@@ -43,6 +44,15 @@ typedef struct CuvidContext
     char *cu_gpu;
     int nb_surfaces;
     int drop_second_field;
+    char *crop;
+    char *resize;
+
+    struct {
+        short left;
+        short top;
+        short right;
+        short bottom;
+    } offset;
 
     AVBufferRef *hwdevice;
     AVBufferRef *hwframe;
@@ -57,6 +67,10 @@ typedef struct CuvidContext
     int internal_error;
     int decoder_flushing;
 
+    int width;
+    int height;
+    int coded_width;
+    int coded_height;
     cudaVideoCodec codec_type;
     cudaVideoChromaFormat chroma_format;
 
@@ -105,6 +119,7 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form
     AVHWFramesContext *hwframe_ctx = (AVHWFramesContext*)ctx->hwframe->data;
     CUVIDDECODECREATEINFO cuinfo;
     int surface_fmt;
+    int width, height;
 
     enum AVPixelFormat pix_fmts[3] = { AV_PIX_FMT_CUDA,
                                        AV_PIX_FMT_NONE,  // Will be updated below
@@ -144,8 +159,8 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form
 
     avctx->pix_fmt = surface_fmt;
 
-    avctx->width = format->display_area.right;
-    avctx->height = format->display_area.bottom;
+    width = format->display_area.right - format->display_area.left;
+    height = format->display_area.bottom - format->display_area.top;
 
     ff_set_sar(avctx, av_div_q(
         (AVRational){ format->display_aspect_ratio.x, format->display_aspect_ratio.y },
@@ -174,8 +189,10 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form
     }
 
     if (ctx->cudecoder
-            && avctx->coded_width == format->coded_width
-            && avctx->coded_height == format->coded_height
+            && ctx->width == width
+            && ctx->height == height
+            && ctx->coded_width == format->coded_width
+            && ctx->coded_height == format->coded_height
             && ctx->chroma_format == format->chroma_format
             && ctx->codec_type == format->codec)
         return 1;
@@ -204,11 +221,15 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form
         return 0;
     }
 
-    avctx->coded_width = format->coded_width;
-    avctx->coded_height = format->coded_height;
-
+    ctx->width = width;
+    ctx->height = height;
+    ctx->coded_width = format->coded_width;
+    ctx->coded_height = format->coded_height;
     ctx->chroma_format = format->chroma_format;
 
+    avctx->coded_width = avctx->width;
+    avctx->coded_height = avctx->height;
+
     memset(&cuinfo, 0, sizeof(cuinfo));
 
     cuinfo.CodecType = ctx->codec_type = format->codec;
@@ -228,15 +249,24 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form
         return 0;
     }
 
-    cuinfo.ulWidth = avctx->coded_width;
-    cuinfo.ulHeight = avctx->coded_height;
-    cuinfo.ulTargetWidth = cuinfo.ulWidth;
-    cuinfo.ulTargetHeight = cuinfo.ulHeight;
+    cuinfo.ulWidth = ctx->coded_width;
+    cuinfo.ulHeight = ctx->coded_height;
+
+    /* cropping depends on original resolution */
+    cuinfo.display_area.left = ctx->offset.left;
+    cuinfo.display_area.top = ctx->offset.top;
+    cuinfo.display_area.right = cuinfo.ulWidth - ctx->offset.right;
+    cuinfo.display_area.bottom = cuinfo.ulHeight - ctx->offset.bottom;
 
+    /* scaling to requested resolution */
+    cuinfo.ulTargetWidth = avctx->width;
+    cuinfo.ulTargetHeight = avctx->height;
+
+    /* aspect ratio conversion, 1:1, depends on scaled resolution */
     cuinfo.target_rect.left = 0;
     cuinfo.target_rect.top = 0;
-    cuinfo.target_rect.right = cuinfo.ulWidth;
-    cuinfo.target_rect.bottom = cuinfo.ulHeight;
+    cuinfo.target_rect.right = cuinfo.ulTargetWidth;
+    cuinfo.target_rect.bottom = cuinfo.ulTargetHeight;
 
     cuinfo.ulNumDecodeSurfaces = ctx->nb_surfaces;
     cuinfo.ulNumOutputSurfaces = 1;
@@ -636,6 +666,11 @@ static int cuvid_test_dummy_decoder(AVCodecContext *avctx,
     cuinfo.ulTargetWidth = cuinfo.ulWidth;
     cuinfo.ulTargetHeight = cuinfo.ulHeight;
 
+    cuinfo.display_area.left = 0;
+    cuinfo.display_area.top = 0;
+    cuinfo.display_area.right = cuinfo.ulWidth;
+    cuinfo.display_area.bottom = cuinfo.ulHeight;
+
     cuinfo.target_rect.left = 0;
     cuinfo.target_rect.top = 0;
     cuinfo.target_rect.right = cuinfo.ulWidth;
@@ -822,6 +857,38 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx)
                FFMIN(sizeof(ctx->cuparse_ext.raw_seqhdr_data), avctx->extradata_size));
     }
 
+    ctx->offset.top = 0;
+    ctx->offset.bottom = 0;
+    ctx->offset.left = 0;
+    ctx->offset.right = 0;
+    if (ctx->crop) {
+        char *crop_str, *saveptr;
+        int crop_idx = 0;
+        crop_str = av_strdup(ctx->crop);
+        crop_str = av_strtok(crop_str, "x", &saveptr);
+        while (crop_str) {
+            switch (crop_idx++) {
+            case 0:
+                ctx->offset.top = atoi(crop_str);
+                break;
+            case 1:
+                ctx->offset.bottom = atoi(crop_str);
+                break;
+            case 2:
+                ctx->offset.left = atoi(crop_str);
+                break;
+            case 3:
+                ctx->offset.right = atoi(crop_str);
+                break;
+            default:
+                break;
+            }
+            crop_str = av_strtok(NULL, "x", &saveptr);
+        }
+        free(crop_str);
+    }
+
+
     ctx->cuparseinfo.ulMaxNumDecodeSurfaces = ctx->nb_surfaces;
     ctx->cuparseinfo.ulMaxDisplayDelay = 4;
     ctx->cuparseinfo.pUserData = avctx;
@@ -934,6 +1001,8 @@ static const AVOption options[] = {
     { "gpu",      "GPU to be used for decoding", OFFSET(cu_gpu), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD },
     { "surfaces", "Maximum surfaces to be used for decoding", OFFSET(nb_surfaces), AV_OPT_TYPE_INT, { .i64 = 25 }, 0, INT_MAX, VD },
     { "drop_second_field", "Drop second field when deinterlacing", OFFSET(drop_second_field), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VD },
+    { "crop",     "Crop (top)x(bottom)x(left)x(right)", OFFSET(crop), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD },
+    { "resize",   "Resize (width)x(height)", OFFSET(resize), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD },
     { NULL }
 };
 
-- 
2.1.4

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to