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;
AVFifoBuffer *frame_queue;
int deint_mode;
+ int deint_mode_current;
int64_t prev_pts;
int internal_error;
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;
avctx->pix_fmt = surface_fmt;
- avctx->width = format->display_area.right;
- avctx->height = format->display_area.bottom;
+ // Update our hwframe ctx, as the get_format callback might have refreshed it!
+ if (avctx->hw_frames_ctx) {
+ av_buffer_unref(&ctx->hwframe);
+
+ ctx->hwframe = av_buffer_ref(avctx->hw_frames_ctx);
+ if (!ctx->hwframe) {
+ ctx->internal_error = AVERROR(ENOMEM);
+ return 0;
+ }
+
+ hwframe_ctx = (AVHWFramesContext*)ctx->hwframe->data;
+ }
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;
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;
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;
}
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;
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));
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;
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 ||
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;
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);
}
}
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");
{ "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 }
};