Overhauled version, original patch by Miroslav Slugeň <thunder.m@email.cz>.
Timo Rothenpieler authored on 2017/03/05 23:32:36... | ... |
@@ -43,6 +43,20 @@ typedef struct CuvidContext |
43 | 43 |
char *cu_gpu; |
44 | 44 |
int nb_surfaces; |
45 | 45 |
int drop_second_field; |
46 |
+ char *crop_expr; |
|
47 |
+ char *resize_expr; |
|
48 |
+ |
|
49 |
+ struct { |
|
50 |
+ int left; |
|
51 |
+ int top; |
|
52 |
+ int right; |
|
53 |
+ int bottom; |
|
54 |
+ } crop; |
|
55 |
+ |
|
56 |
+ struct { |
|
57 |
+ int width; |
|
58 |
+ int height; |
|
59 |
+ } resize; |
|
46 | 60 |
|
47 | 61 |
AVBufferRef *hwdevice; |
48 | 62 |
AVBufferRef *hwframe; |
... | ... |
@@ -107,17 +121,46 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form |
107 | 107 |
CUVIDDECODECREATEINFO cuinfo; |
108 | 108 |
int surface_fmt; |
109 | 109 |
|
110 |
+ int old_width = avctx->width; |
|
111 |
+ int old_height = avctx->height; |
|
112 |
+ |
|
110 | 113 |
enum AVPixelFormat pix_fmts[3] = { AV_PIX_FMT_CUDA, |
111 | 114 |
AV_PIX_FMT_NONE, // Will be updated below |
112 | 115 |
AV_PIX_FMT_NONE }; |
113 | 116 |
|
114 | 117 |
av_log(avctx, AV_LOG_TRACE, "pfnSequenceCallback, progressive_sequence=%d\n", format->progressive_sequence); |
115 | 118 |
|
119 |
+ memset(&cuinfo, 0, sizeof(cuinfo)); |
|
120 |
+ |
|
116 | 121 |
ctx->internal_error = 0; |
117 | 122 |
|
123 |
+ avctx->coded_width = cuinfo.ulWidth = format->coded_width; |
|
124 |
+ avctx->coded_height = cuinfo.ulHeight = format->coded_height; |
|
125 |
+ |
|
126 |
+ // apply cropping |
|
127 |
+ cuinfo.display_area.left = format->display_area.left + ctx->crop.left; |
|
128 |
+ cuinfo.display_area.top = format->display_area.top + ctx->crop.top; |
|
129 |
+ cuinfo.display_area.right = format->display_area.right - ctx->crop.right; |
|
130 |
+ cuinfo.display_area.bottom = format->display_area.bottom - ctx->crop.bottom; |
|
131 |
+ |
|
118 | 132 |
// width and height need to be set before calling ff_get_format |
119 |
- avctx->width = format->display_area.right; |
|
120 |
- avctx->height = format->display_area.bottom; |
|
133 |
+ if (ctx->resize_expr) { |
|
134 |
+ avctx->width = ctx->resize.width; |
|
135 |
+ avctx->height = ctx->resize.height; |
|
136 |
+ } else { |
|
137 |
+ avctx->width = cuinfo.display_area.right - cuinfo.display_area.left; |
|
138 |
+ avctx->height = cuinfo.display_area.bottom - cuinfo.display_area.top; |
|
139 |
+ } |
|
140 |
+ |
|
141 |
+ // target width/height need to be multiples of two |
|
142 |
+ cuinfo.ulTargetWidth = avctx->width = (avctx->width + 1) & ~1; |
|
143 |
+ cuinfo.ulTargetHeight = avctx->height = (avctx->height + 1) & ~1; |
|
144 |
+ |
|
145 |
+ // aspect ratio conversion, 1:1, depends on scaled resolution |
|
146 |
+ cuinfo.target_rect.left = 0; |
|
147 |
+ cuinfo.target_rect.top = 0; |
|
148 |
+ cuinfo.target_rect.right = cuinfo.ulTargetWidth; |
|
149 |
+ cuinfo.target_rect.bottom = cuinfo.ulTargetHeight; |
|
121 | 150 |
|
122 | 151 |
switch (format->bit_depth_luma_minus8) { |
123 | 152 |
case 0: // 8-bit |
... | ... |
@@ -195,6 +238,8 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form |
195 | 195 |
if (ctx->cudecoder |
196 | 196 |
&& avctx->coded_width == format->coded_width |
197 | 197 |
&& avctx->coded_height == format->coded_height |
198 |
+ && avctx->width == old_width |
|
199 |
+ && avctx->height == old_height |
|
198 | 200 |
&& ctx->chroma_format == format->chroma_format |
199 | 201 |
&& ctx->codec_type == format->codec) |
200 | 202 |
return 1; |
... | ... |
@@ -228,13 +273,8 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form |
228 | 228 |
return 0; |
229 | 229 |
} |
230 | 230 |
|
231 |
- avctx->coded_width = format->coded_width; |
|
232 |
- avctx->coded_height = format->coded_height; |
|
233 |
- |
|
234 | 231 |
ctx->chroma_format = format->chroma_format; |
235 | 232 |
|
236 |
- memset(&cuinfo, 0, sizeof(cuinfo)); |
|
237 |
- |
|
238 | 233 |
cuinfo.CodecType = ctx->codec_type = format->codec; |
239 | 234 |
cuinfo.ChromaFormat = format->chroma_format; |
240 | 235 |
|
... | ... |
@@ -252,16 +292,6 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form |
252 | 252 |
return 0; |
253 | 253 |
} |
254 | 254 |
|
255 |
- cuinfo.ulWidth = avctx->coded_width; |
|
256 |
- cuinfo.ulHeight = avctx->coded_height; |
|
257 |
- cuinfo.ulTargetWidth = cuinfo.ulWidth; |
|
258 |
- cuinfo.ulTargetHeight = cuinfo.ulHeight; |
|
259 |
- |
|
260 |
- cuinfo.target_rect.left = 0; |
|
261 |
- cuinfo.target_rect.top = 0; |
|
262 |
- cuinfo.target_rect.right = cuinfo.ulWidth; |
|
263 |
- cuinfo.target_rect.bottom = cuinfo.ulHeight; |
|
264 |
- |
|
265 | 255 |
cuinfo.ulNumDecodeSurfaces = ctx->nb_surfaces; |
266 | 256 |
cuinfo.ulNumOutputSurfaces = 1; |
267 | 257 |
cuinfo.ulCreationFlags = cudaVideoCreate_PreferCUVID; |
... | ... |
@@ -486,7 +516,7 @@ static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame) |
486 | 486 |
if (ret < 0) |
487 | 487 |
goto error; |
488 | 488 |
|
489 |
- offset += avctx->coded_height; |
|
489 |
+ offset += avctx->height; |
|
490 | 490 |
} |
491 | 491 |
} else if (avctx->pix_fmt == AV_PIX_FMT_NV12 || |
492 | 492 |
avctx->pix_fmt == AV_PIX_FMT_P010 || |
... | ... |
@@ -502,7 +532,7 @@ static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame) |
502 | 502 |
tmp_frame->hw_frames_ctx = av_buffer_ref(ctx->hwframe); |
503 | 503 |
tmp_frame->data[0] = (uint8_t*)mapped_frame; |
504 | 504 |
tmp_frame->linesize[0] = pitch; |
505 |
- tmp_frame->data[1] = (uint8_t*)(mapped_frame + avctx->coded_height * pitch); |
|
505 |
+ tmp_frame->data[1] = (uint8_t*)(mapped_frame + avctx->height * pitch); |
|
506 | 506 |
tmp_frame->linesize[1] = pitch; |
507 | 507 |
tmp_frame->width = avctx->width; |
508 | 508 |
tmp_frame->height = avctx->height; |
... | ... |
@@ -708,6 +738,21 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) |
708 | 708 |
} |
709 | 709 |
avctx->pix_fmt = ret; |
710 | 710 |
|
711 |
+ if (ctx->resize_expr && sscanf(ctx->resize_expr, "%dx%d", |
|
712 |
+ &ctx->resize.width, &ctx->resize.height) != 2) { |
|
713 |
+ av_log(avctx, AV_LOG_ERROR, "Invalid resize expressions\n"); |
|
714 |
+ ret = AVERROR(EINVAL); |
|
715 |
+ goto error; |
|
716 |
+ } |
|
717 |
+ |
|
718 |
+ if (ctx->crop_expr && sscanf(ctx->crop_expr, "%dx%dx%dx%d", |
|
719 |
+ &ctx->crop.top, &ctx->crop.bottom, |
|
720 |
+ &ctx->crop.left, &ctx->crop.right) != 4) { |
|
721 |
+ av_log(avctx, AV_LOG_ERROR, "Invalid cropping expressions\n"); |
|
722 |
+ ret = AVERROR(EINVAL); |
|
723 |
+ goto error; |
|
724 |
+ } |
|
725 |
+ |
|
711 | 726 |
ret = cuvid_load_functions(&ctx->cvdl); |
712 | 727 |
if (ret < 0) { |
713 | 728 |
av_log(avctx, AV_LOG_ERROR, "Failed loading nvcuvid.\n"); |
... | ... |
@@ -953,6 +998,8 @@ static const AVOption options[] = { |
953 | 953 |
{ "gpu", "GPU to be used for decoding", OFFSET(cu_gpu), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD }, |
954 | 954 |
{ "surfaces", "Maximum surfaces to be used for decoding", OFFSET(nb_surfaces), AV_OPT_TYPE_INT, { .i64 = 25 }, 0, INT_MAX, VD }, |
955 | 955 |
{ "drop_second_field", "Drop second field when deinterlacing", OFFSET(drop_second_field), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VD }, |
956 |
+ { "crop", "Crop (top)x(bottom)x(left)x(right)", OFFSET(crop_expr), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD }, |
|
957 |
+ { "resize", "Resize (width)x(height)", OFFSET(resize_expr), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD }, |
|
956 | 958 |
{ NULL } |
957 | 959 |
}; |
958 | 960 |
|