vp9: assert -> av_assert and fix associated compile error.
[ffmpeg.git] / libavcodec / cuvid.c
index 2a305ab..2ba8e00 100644 (file)
@@ -31,6 +31,7 @@
 #include "libavutil/pixdesc.h"
 
 #include "avcodec.h"
+#include "decode.h"
 #include "internal.h"
 
 typedef struct CuvidContext
@@ -42,6 +43,21 @@ typedef struct CuvidContext
 
     char *cu_gpu;
     int nb_surfaces;
+    int drop_second_field;
+    char *crop_expr;
+    char *resize_expr;
+
+    struct {
+        int left;
+        int top;
+        int right;
+        int bottom;
+    } crop;
+
+    struct {
+        int width;
+        int height;
+    } resize;
 
     AVBufferRef *hwdevice;
     AVBufferRef *hwframe;
@@ -51,6 +67,7 @@ typedef struct CuvidContext
     AVFifoBuffer *frame_queue;
 
     int deint_mode;
+    int deint_mode_current;
     int64_t prev_pts;
 
     int internal_error;
@@ -59,6 +76,8 @@ typedef struct CuvidContext
     cudaVideoCodec codec_type;
     cudaVideoChromaFormat chroma_format;
 
+    CUVIDDECODECAPS caps8, caps10, caps12;
+
     CUVIDPARSERPARAMS cuparseinfo;
     CUVIDEOFORMATEX cuparse_ext;
 
@@ -102,33 +121,75 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form
     AVCodecContext *avctx = opaque;
     CuvidContext *ctx = avctx->priv_data;
     AVHWFramesContext *hwframe_ctx = (AVHWFramesContext*)ctx->hwframe->data;
+    CUVIDDECODECAPS *caps = NULL;
     CUVIDDECODECREATEINFO cuinfo;
     int surface_fmt;
 
+    int old_width = avctx->width;
+    int old_height = avctx->height;
+
     enum AVPixelFormat pix_fmts[3] = { AV_PIX_FMT_CUDA,
                                        AV_PIX_FMT_NONE,  // Will be updated below
                                        AV_PIX_FMT_NONE };
 
     av_log(avctx, AV_LOG_TRACE, "pfnSequenceCallback, progressive_sequence=%d\n", format->progressive_sequence);
 
+    memset(&cuinfo, 0, sizeof(cuinfo));
+
     ctx->internal_error = 0;
 
+    avctx->coded_width = cuinfo.ulWidth = format->coded_width;
+    avctx->coded_height = cuinfo.ulHeight = format->coded_height;
+
+    // apply cropping
+    cuinfo.display_area.left = format->display_area.left + ctx->crop.left;
+    cuinfo.display_area.top = format->display_area.top + ctx->crop.top;
+    cuinfo.display_area.right = format->display_area.right - ctx->crop.right;
+    cuinfo.display_area.bottom = format->display_area.bottom - ctx->crop.bottom;
+
+    // width and height need to be set before calling ff_get_format
+    if (ctx->resize_expr) {
+        avctx->width = ctx->resize.width;
+        avctx->height = ctx->resize.height;
+    } else {
+        avctx->width = cuinfo.display_area.right - cuinfo.display_area.left;
+        avctx->height = cuinfo.display_area.bottom - cuinfo.display_area.top;
+    }
+
+    // target width/height need to be multiples of two
+    cuinfo.ulTargetWidth = avctx->width = (avctx->width + 1) & ~1;
+    cuinfo.ulTargetHeight = avctx->height = (avctx->height + 1) & ~1;
+
+    // aspect ratio conversion, 1:1, depends on scaled resolution
+    cuinfo.target_rect.left = 0;
+    cuinfo.target_rect.top = 0;
+    cuinfo.target_rect.right = cuinfo.ulTargetWidth;
+    cuinfo.target_rect.bottom = cuinfo.ulTargetHeight;
+
     switch (format->bit_depth_luma_minus8) {
     case 0: // 8-bit
         pix_fmts[1] = AV_PIX_FMT_NV12;
+        caps = &ctx->caps8;
         break;
     case 2: // 10-bit
         pix_fmts[1] = AV_PIX_FMT_P010;
+        caps = &ctx->caps10;
         break;
     case 4: // 12-bit
         pix_fmts[1] = AV_PIX_FMT_P016;
+        caps = &ctx->caps12;
         break;
     default:
+        break;
+    }
+
+    if (!caps || !caps->bIsSupported) {
         av_log(avctx, AV_LOG_ERROR, "unsupported bit depth: %d\n",
                format->bit_depth_luma_minus8 + 8);
         ctx->internal_error = AVERROR(EINVAL);
         return 0;
     }
+
     surface_fmt = ff_get_format(avctx, pix_fmts);
     if (surface_fmt < 0) {
         av_log(avctx, AV_LOG_ERROR, "ff_get_format failed: %d\n", surface_fmt);
@@ -156,14 +217,15 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form
         hwframe_ctx = (AVHWFramesContext*)ctx->hwframe->data;
     }
 
-    avctx->width = format->display_area.right;
-    avctx->height = format->display_area.bottom;
-
     ff_set_sar(avctx, av_div_q(
         (AVRational){ format->display_aspect_ratio.x, format->display_aspect_ratio.y },
         (AVRational){ avctx->width, avctx->height }));
 
-    if (!format->progressive_sequence && ctx->deint_mode == cudaVideoDeinterlaceMode_Weave)
+    ctx->deint_mode_current = format->progressive_sequence
+                              ? cudaVideoDeinterlaceMode_Weave
+                              : ctx->deint_mode;
+
+    if (!format->progressive_sequence && ctx->deint_mode_current == cudaVideoDeinterlaceMode_Weave)
         avctx->flags |= AV_CODEC_FLAG_INTERLACED_DCT;
     else
         avctx->flags &= ~AV_CODEC_FLAG_INTERLACED_DCT;
@@ -188,6 +250,8 @@ 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
+            && avctx->width == old_width
+            && avctx->height == old_height
             && ctx->chroma_format == format->chroma_format
             && ctx->codec_type == format->codec)
         return 1;
@@ -206,6 +270,11 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form
             hwframe_ctx->format != AV_PIX_FMT_CUDA ||
             hwframe_ctx->sw_format != avctx->sw_pix_fmt)) {
         av_log(avctx, AV_LOG_ERROR, "AVHWFramesContext is already initialized with incompatible parameters\n");
+        av_log(avctx, AV_LOG_DEBUG, "width: %d <-> %d\n", hwframe_ctx->width, avctx->width);
+        av_log(avctx, AV_LOG_DEBUG, "height: %d <-> %d\n", hwframe_ctx->height, avctx->height);
+        av_log(avctx, AV_LOG_DEBUG, "format: %s <-> cuda\n", av_get_pix_fmt_name(hwframe_ctx->format));
+        av_log(avctx, AV_LOG_DEBUG, "sw_format: %s <-> %s\n",
+               av_get_pix_fmt_name(hwframe_ctx->sw_format), av_get_pix_fmt_name(avctx->sw_pix_fmt));
         ctx->internal_error = AVERROR(EINVAL);
         return 0;
     }
@@ -216,13 +285,8 @@ 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->chroma_format = format->chroma_format;
 
-    memset(&cuinfo, 0, sizeof(cuinfo));
-
     cuinfo.CodecType = ctx->codec_type = format->codec;
     cuinfo.ChromaFormat = format->chroma_format;
 
@@ -240,28 +304,13 @@ 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.target_rect.left = 0;
-    cuinfo.target_rect.top = 0;
-    cuinfo.target_rect.right = cuinfo.ulWidth;
-    cuinfo.target_rect.bottom = cuinfo.ulHeight;
-
     cuinfo.ulNumDecodeSurfaces = ctx->nb_surfaces;
     cuinfo.ulNumOutputSurfaces = 1;
     cuinfo.ulCreationFlags = cudaVideoCreate_PreferCUVID;
     cuinfo.bitDepthMinus8 = format->bit_depth_luma_minus8;
+    cuinfo.DeinterlaceMode = ctx->deint_mode_current;
 
-    if (format->progressive_sequence) {
-        ctx->deint_mode = cuinfo.DeinterlaceMode = cudaVideoDeinterlaceMode_Weave;
-    } else {
-        cuinfo.DeinterlaceMode = ctx->deint_mode;
-    }
-
-    if (ctx->deint_mode != cudaVideoDeinterlaceMode_Weave)
+    if (ctx->deint_mode_current != cudaVideoDeinterlaceMode_Weave && !ctx->drop_second_field)
         avctx->framerate = av_mul_q(avctx->framerate, (AVRational){2, 1});
 
     ctx->internal_error = CHECK_CU(ctx->cvdl->cuvidCreateDecoder(&ctx->cudecoder, &cuinfo));
@@ -306,18 +355,27 @@ static int CUDAAPI cuvid_handle_picture_display(void *opaque, CUVIDPARSERDISPINF
     parsed_frame.dispinfo = *dispinfo;
     ctx->internal_error = 0;
 
-    if (ctx->deint_mode == cudaVideoDeinterlaceMode_Weave) {
+    if (ctx->deint_mode_current == cudaVideoDeinterlaceMode_Weave) {
         av_fifo_generic_write(ctx->frame_queue, &parsed_frame, sizeof(CuvidParsedFrame), NULL);
     } else {
         parsed_frame.is_deinterlacing = 1;
         av_fifo_generic_write(ctx->frame_queue, &parsed_frame, sizeof(CuvidParsedFrame), NULL);
-        parsed_frame.second_field = 1;
-        av_fifo_generic_write(ctx->frame_queue, &parsed_frame, sizeof(CuvidParsedFrame), NULL);
+        if (!ctx->drop_second_field) {
+            parsed_frame.second_field = 1;
+            av_fifo_generic_write(ctx->frame_queue, &parsed_frame, sizeof(CuvidParsedFrame), NULL);
+        }
     }
 
     return 1;
 }
 
+static int cuvid_is_buffer_full(AVCodecContext *avctx)
+{
+    CuvidContext *ctx = avctx->priv_data;
+
+    return (av_fifo_size(ctx->frame_queue) / sizeof(CuvidParsedFrame)) + 2 > ctx->nb_surfaces;
+}
+
 static int cuvid_decode_packet(AVCodecContext *avctx, const AVPacket *avpkt)
 {
     CuvidContext *ctx = avctx->priv_data;
@@ -334,7 +392,7 @@ static int cuvid_decode_packet(AVCodecContext *avctx, const AVPacket *avpkt)
     if (is_flush && avpkt && avpkt->size)
         return AVERROR_EOF;
 
-    if ((av_fifo_size(ctx->frame_queue) / sizeof(CuvidParsedFrame)) + 2 > ctx->nb_surfaces && avpkt && avpkt->size)
+    if (cuvid_is_buffer_full(avctx) && avpkt && avpkt->size)
         return AVERROR(EAGAIN);
 
     if (ctx->bsf && avpkt && avpkt->size) {
@@ -425,6 +483,20 @@ static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame)
             return ret;
     }
 
+    if (!cuvid_is_buffer_full(avctx)) {
+        AVPacket pkt = {0};
+        ret = ff_decode_get_packet(avctx, &pkt);
+        if (ret < 0 && ret != AVERROR_EOF)
+            return ret;
+        ret = cuvid_decode_packet(avctx, &pkt);
+        av_packet_unref(&pkt);
+        // cuvid_is_buffer_full() should avoid this.
+        if (ret == AVERROR(EAGAIN))
+            ret = AVERROR_EXTERNAL;
+        if (ret < 0 && ret != AVERROR_EOF)
+            return ret;
+    }
+
     ret = CHECK_CU(ctx->cudl->cuCtxPushCurrent(cuda_ctx));
     if (ret < 0)
         return ret;
@@ -477,7 +549,7 @@ static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame)
                 if (ret < 0)
                     goto error;
 
-                offset += avctx->coded_height;
+                offset += avctx->height;
             }
         } else if (avctx->pix_fmt == AV_PIX_FMT_NV12 ||
                    avctx->pix_fmt == AV_PIX_FMT_P010 ||
@@ -493,7 +565,7 @@ static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame)
             tmp_frame->hw_frames_ctx = av_buffer_ref(ctx->hwframe);
             tmp_frame->data[0]       = (uint8_t*)mapped_frame;
             tmp_frame->linesize[0]   = pitch;
-            tmp_frame->data[1]       = (uint8_t*)(mapped_frame + avctx->coded_height * pitch);
+            tmp_frame->data[1]       = (uint8_t*)(mapped_frame + avctx->height * pitch);
             tmp_frame->linesize[1]   = pitch;
             tmp_frame->width         = avctx->width;
             tmp_frame->height        = avctx->height;
@@ -543,9 +615,9 @@ FF_DISABLE_DEPRECATION_WARNINGS
         frame->pkt_pts = frame->pts;
 FF_ENABLE_DEPRECATION_WARNINGS
 #endif
-        av_frame_set_pkt_pos(frame, -1);
-        av_frame_set_pkt_duration(frame, 0);
-        av_frame_set_pkt_size(frame, -1);
+        frame->pkt_pos = -1;
+        frame->pkt_duration = 0;
+        frame->pkt_size = -1;
 
         frame->interlaced_frame = !parsed_frame.is_deinterlacing && !parsed_frame.dispinfo.progressive_frame;
 
@@ -577,7 +649,7 @@ static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
 
     av_log(avctx, AV_LOG_TRACE, "cuvid_decode_frame\n");
 
-    if (ctx->deint_mode != cudaVideoDeinterlaceMode_Weave) {
+    if (ctx->deint_mode_current != cudaVideoDeinterlaceMode_Weave) {
         av_log(avctx, AV_LOG_ERROR, "Deinterlacing is not supported via the old API\n");
         return AVERROR(EINVAL);
     }
@@ -625,46 +697,90 @@ static av_cold int cuvid_decode_end(AVCodecContext *avctx)
     return 0;
 }
 
-static int cuvid_test_dummy_decoder(AVCodecContext *avctx,
-                                    const CUVIDPARSERPARAMS *cuparseinfo,
-                                    int probed_width,
-                                    int probed_height)
+static int cuvid_test_capabilities(AVCodecContext *avctx,
+                                   const CUVIDPARSERPARAMS *cuparseinfo,
+                                   int probed_width,
+                                   int probed_height,
+                                   int bit_depth)
 {
     CuvidContext *ctx = avctx->priv_data;
-    CUVIDDECODECREATEINFO cuinfo;
-    CUvideodecoder cudec = 0;
-    int ret = 0;
-
-    memset(&cuinfo, 0, sizeof(cuinfo));
-
-    cuinfo.CodecType = cuparseinfo->CodecType;
-    cuinfo.ChromaFormat = cudaVideoChromaFormat_420;
-    cuinfo.OutputFormat = cudaVideoSurfaceFormat_NV12;
-
-    cuinfo.ulWidth = probed_width;
-    cuinfo.ulHeight = probed_height;
-    cuinfo.ulTargetWidth = cuinfo.ulWidth;
-    cuinfo.ulTargetHeight = cuinfo.ulHeight;
+    CUVIDDECODECAPS *caps;
+    int res8 = 0, res10 = 0, res12 = 0;
+
+    if (!ctx->cvdl->cuvidGetDecoderCaps) {
+        av_log(avctx, AV_LOG_WARNING, "Used Nvidia driver is too old to perform a capability check.\n");
+        av_log(avctx, AV_LOG_WARNING, "The minimum required version is "
+#if defined(_WIN32) || defined(__CYGWIN__)
+            "378.66"
+#else
+            "378.13"
+#endif
+            ". Continuing blind.\n");
+        ctx->caps8.bIsSupported = ctx->caps10.bIsSupported = 1;
+        // 12 bit was not supported before the capability check was introduced, so disable it.
+        ctx->caps12.bIsSupported = 0;
+        return 0;
+    }
 
-    cuinfo.target_rect.left = 0;
-    cuinfo.target_rect.top = 0;
-    cuinfo.target_rect.right = cuinfo.ulWidth;
-    cuinfo.target_rect.bottom = cuinfo.ulHeight;
+    ctx->caps8.eCodecType = ctx->caps10.eCodecType = ctx->caps12.eCodecType
+        = cuparseinfo->CodecType;
+    ctx->caps8.eChromaFormat = ctx->caps10.eChromaFormat = ctx->caps12.eChromaFormat
+        = cudaVideoChromaFormat_420;
+
+    ctx->caps8.nBitDepthMinus8 = 0;
+    ctx->caps10.nBitDepthMinus8 = 2;
+    ctx->caps12.nBitDepthMinus8 = 4;
+
+    res8 = CHECK_CU(ctx->cvdl->cuvidGetDecoderCaps(&ctx->caps8));
+    res10 = CHECK_CU(ctx->cvdl->cuvidGetDecoderCaps(&ctx->caps10));
+    res12 = CHECK_CU(ctx->cvdl->cuvidGetDecoderCaps(&ctx->caps12));
+
+    av_log(avctx, AV_LOG_VERBOSE, "CUVID capabilities for %s:\n", avctx->codec->name);
+    av_log(avctx, AV_LOG_VERBOSE, "8 bit: supported: %d, min_width: %d, max_width: %d, min_height: %d, max_height: %d\n",
+           ctx->caps8.bIsSupported, ctx->caps8.nMinWidth, ctx->caps8.nMaxWidth, ctx->caps8.nMinHeight, ctx->caps8.nMaxHeight);
+    av_log(avctx, AV_LOG_VERBOSE, "10 bit: supported: %d, min_width: %d, max_width: %d, min_height: %d, max_height: %d\n",
+           ctx->caps10.bIsSupported, ctx->caps10.nMinWidth, ctx->caps10.nMaxWidth, ctx->caps10.nMinHeight, ctx->caps10.nMaxHeight);
+    av_log(avctx, AV_LOG_VERBOSE, "12 bit: supported: %d, min_width: %d, max_width: %d, min_height: %d, max_height: %d\n",
+           ctx->caps12.bIsSupported, ctx->caps12.nMinWidth, ctx->caps12.nMaxWidth, ctx->caps12.nMinHeight, ctx->caps12.nMaxHeight);
+
+    switch (bit_depth) {
+    case 10:
+        caps = &ctx->caps10;
+        if (res10 < 0)
+            return res10;
+        break;
+    case 12:
+        caps = &ctx->caps12;
+        if (res12 < 0)
+            return res12;
+        break;
+    default:
+        caps = &ctx->caps8;
+        if (res8 < 0)
+            return res8;
+    }
 
-    cuinfo.ulNumDecodeSurfaces = ctx->nb_surfaces;
-    cuinfo.ulNumOutputSurfaces = 1;
-    cuinfo.ulCreationFlags = cudaVideoCreate_PreferCUVID;
-    cuinfo.bitDepthMinus8 = 0;
+    if (!ctx->caps8.bIsSupported) {
+        av_log(avctx, AV_LOG_ERROR, "Codec %s is not supported.\n", avctx->codec->name);
+        return AVERROR(EINVAL);
+    }
 
-    cuinfo.DeinterlaceMode = cudaVideoDeinterlaceMode_Weave;
+    if (!caps->bIsSupported) {
+        av_log(avctx, AV_LOG_ERROR, "Bit depth %d is not supported.\n", bit_depth);
+        return AVERROR(EINVAL);
+    }
 
-    ret = CHECK_CU(ctx->cvdl->cuvidCreateDecoder(&cudec, &cuinfo));
-    if (ret < 0)
-        return ret;
+    if (probed_width > caps->nMaxWidth || probed_width < caps->nMinWidth) {
+        av_log(avctx, AV_LOG_ERROR, "Video width %d not within range from %d to %d\n",
+               probed_width, caps->nMinWidth, caps->nMaxWidth);
+        return AVERROR(EINVAL);
+    }
 
-    ret = CHECK_CU(ctx->cvdl->cuvidDestroyDecoder(cudec));
-    if (ret < 0)
-        return ret;
+    if (probed_height > caps->nMaxHeight || probed_height < caps->nMinHeight) {
+        av_log(avctx, AV_LOG_ERROR, "Video height %d not within range from %d to %d\n",
+               probed_height, caps->nMinHeight, caps->nMaxHeight);
+        return AVERROR(EINVAL);
+    }
 
     return 0;
 }
@@ -687,6 +803,11 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx)
 
     int probed_width = avctx->coded_width ? avctx->coded_width : 1280;
     int probed_height = avctx->coded_height ? avctx->coded_height : 720;
+    int probed_bit_depth = 8;
+
+    const AVPixFmtDescriptor *probe_desc = av_pix_fmt_desc_get(avctx->pix_fmt);
+    if (probe_desc && probe_desc->nb_components)
+        probed_bit_depth = probe_desc->comp[0].depth;
 
     // Accelerated transcoding scenarios with 'ffmpeg' require that the
     // pix_fmt be set to AV_PIX_FMT_CUDA early. The sw_pix_fmt, and the
@@ -699,6 +820,21 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx)
     }
     avctx->pix_fmt = ret;
 
+    if (ctx->resize_expr && sscanf(ctx->resize_expr, "%dx%d",
+                                   &ctx->resize.width, &ctx->resize.height) != 2) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid resize expressions\n");
+        ret = AVERROR(EINVAL);
+        goto error;
+    }
+
+    if (ctx->crop_expr && sscanf(ctx->crop_expr, "%dx%dx%dx%d",
+                                 &ctx->crop.top, &ctx->crop.bottom,
+                                 &ctx->crop.left, &ctx->crop.right) != 4) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid cropping expressions\n");
+        ret = AVERROR(EINVAL);
+        goto error;
+    }
+
     ret = cuvid_load_functions(&ctx->cvdl);
     if (ret < 0) {
         av_log(avctx, AV_LOG_ERROR, "Failed loading nvcuvid.\n");
@@ -726,9 +862,17 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx)
             goto error;
         }
     } else {
-        ret = av_hwdevice_ctx_create(&ctx->hwdevice, AV_HWDEVICE_TYPE_CUDA, ctx->cu_gpu, NULL, 0);
-        if (ret < 0)
-            goto error;
+        if (avctx->hw_device_ctx) {
+            ctx->hwdevice = av_buffer_ref(avctx->hw_device_ctx);
+            if (!ctx->hwdevice) {
+                ret = AVERROR(ENOMEM);
+                goto error;
+            }
+        } else {
+            ret = av_hwdevice_ctx_create(&ctx->hwdevice, AV_HWDEVICE_TYPE_CUDA, ctx->cu_gpu, NULL, 0);
+            if (ret < 0)
+                goto error;
+        }
 
         ctx->hwframe = av_hwframe_ctx_alloc(ctx->hwdevice);
         if (!ctx->hwframe) {
@@ -843,9 +987,10 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx)
     if (ret < 0)
         goto error;
 
-    ret = cuvid_test_dummy_decoder(avctx, &ctx->cuparseinfo,
-                                   probed_width,
-                                   probed_height);
+    ret = cuvid_test_capabilities(avctx, &ctx->cuparseinfo,
+                                  probed_width,
+                                  probed_height,
+                                  probed_bit_depth);
     if (ret < 0)
         goto error;
 
@@ -943,6 +1088,9 @@ static const AVOption options[] = {
     { "adaptive", "Adaptive deinterlacing",                  0, AV_OPT_TYPE_CONST, { .i64 = cudaVideoDeinterlaceMode_Adaptive }, 0, 0, VD, "deint" },
     { "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 = 0 }, 0, 1, VD },
+    { "crop",     "Crop (top)x(bottom)x(left)x(right)", OFFSET(crop_expr), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD },
+    { "resize",   "Resize (width)x(height)", OFFSET(resize_expr), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD },
     { NULL }
 };
 
@@ -969,7 +1117,6 @@ static const AVOption options[] = {
         .init           = cuvid_decode_init, \
         .close          = cuvid_decode_end, \
         .decode         = cuvid_decode_frame, \
-        .send_packet    = cuvid_decode_packet, \
         .receive_frame  = cuvid_output_frame, \
         .flush          = cuvid_flush, \
         .capabilities   = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \