FFmpeg
Loading...
Searching...
No Matches
vf_scale_cuda.c
Go to the documentation of this file.
1/*
2* Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
3*
4* Permission is hereby granted, free of charge, to any person obtaining a
5* copy of this software and associated documentation files (the "Software"),
6* to deal in the Software without restriction, including without limitation
7* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8* and/or sell copies of the Software, and to permit persons to whom the
9* Software is furnished to do so, subject to the following conditions:
10*
11* The above copyright notice and this permission notice shall be included in
12* all copies or substantial portions of the Software.
13*
14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20* DEALINGS IN THE SOFTWARE.
21*/
22
23#include <float.h>
24#include <stdio.h>
25#include <string.h>
26
27#include "libavutil/common.h"
28#include "libavutil/hwcontext.h"
31#include "libavutil/internal.h"
32#include "libavutil/mem.h"
33#include "libavutil/opt.h"
34#include "libavutil/pixdesc.h"
35#include "libavutil/refstruct.h"
36
37#include "libswscale/filters.h"
38
39#include "avfilter.h"
40#include "filters.h"
41#include "scale_eval.h"
42#include "video.h"
43
44#include "cuda/load_helper.h"
45#include "vf_scale_cuda.h"
46
49 char name[13];
50};
51
52static const struct format_entry supported_formats[] = {
53 {AV_PIX_FMT_YUV420P, "planar8"},
54 {AV_PIX_FMT_YUV422P, "planar8"},
55 {AV_PIX_FMT_YUV444P, "planar8"},
56 {AV_PIX_FMT_YUV420P10,"planar10"},
57 {AV_PIX_FMT_YUV422P10,"planar10"},
58 {AV_PIX_FMT_YUV444P10,"planar10"},
59 {AV_PIX_FMT_YUV444P10MSB,"planar16"},
60 {AV_PIX_FMT_YUV444P12MSB,"planar16"},
61 {AV_PIX_FMT_YUV444P16,"planar16"},
62 {AV_PIX_FMT_NV12, "semiplanar8"},
63 {AV_PIX_FMT_NV16, "semiplanar8"},
64 {AV_PIX_FMT_P010, "semiplanar10"},
65 {AV_PIX_FMT_P210, "semiplanar10"},
66 {AV_PIX_FMT_P012, "semiplanar16"},
67 {AV_PIX_FMT_P212, "semiplanar16"},
68 {AV_PIX_FMT_P016, "semiplanar16"},
69 {AV_PIX_FMT_P216, "semiplanar16"},
70 {AV_PIX_FMT_0RGB32, "bgr0"},
71 {AV_PIX_FMT_0BGR32, "rgb0"},
72 {AV_PIX_FMT_RGB32, "bgra"},
73 {AV_PIX_FMT_BGR32, "rgba"},
74};
75
76#define DIV_UP(a, b) ( ((a) + (b) - 1) / (b) )
77#define BLOCKX 32
78#define BLOCKY 16
79
80#define CHECK_CU(x) FF_CUDA_CHECK_DL(ctx, s->hwctx->internal->cuda_dl, x)
81
82enum {
84
89
91};
92
93enum {
97};
98
99typedef struct CUDAScaleFilter {
100 CUdeviceptr weights; ///< float[dst_size][filter_size]
101 CUdeviceptr offsets; ///< int[dst_size]
105
116
117typedef struct CUDAScaleContext {
118 const AVClass *class;
119
121
122 enum AVPixelFormat in_fmt, out_fmt;
127
130
133
134 /**
135 * Output sw format. AV_PIX_FMT_NONE for no conversion.
136 */
138
139 char *w_expr; ///< width expression string
140 char *h_expr; ///< height expression string
141
145
146 CUcontext cu_ctx;
147 CUmodule cu_module;
148 CUfunction cu_func[FILTER_NB];
150 CUstream cu_stream;
151
155
159 int use_filters; /* -1 for auto */
160
161 float param;
163
165{
166 CUDAScaleContext *s = ctx->priv;
167
168 s->frame = av_frame_alloc();
169 if (!s->frame)
170 return AVERROR(ENOMEM);
171
172 s->tmp_frame = av_frame_alloc();
173 if (!s->tmp_frame)
174 return AVERROR(ENOMEM);
175
176 return 0;
177}
178
179static void filter_uninit(CudaFunctions *cu, CUDAScaleFilter *filter)
180{
181 if (filter->weights)
182 cu->cuMemFree(filter->weights);
183 if (filter->offsets)
184 cu->cuMemFree(filter->offsets);
185 memset(filter, 0, sizeof(*filter));
186}
187
188static void cuda_tex_uninit(CudaFunctions *cu, CUDATex *t)
189{
190 for (int i = 0; i < FF_ARRAY_ELEMS(t->tex); i++) {
191 if (t->tex[i])
192 cu->cuTexObjectDestroy(t->tex[i]);
193 if (t->data[i] && !t->external_data)
194 cu->cuMemFree(t->data[i]);
195 }
196
197 memset(t, 0, sizeof(*t));
198}
199
201{
202 CUDAScaleContext *s = ctx->priv;
203
204 if (s->hwctx) {
205 CudaFunctions *cu = s->hwctx->internal->cuda_dl;
206 CUcontext dummy;
207
208 CHECK_CU(cu->cuCtxPushCurrent(s->hwctx->cuda_ctx));
209
210 cuda_tex_uninit(cu, &s->inter_tex);
211 for (int i = 0; i < FF_ARRAY_ELEMS(s->filters); i++) {
212 filter_uninit(cu, &s->filters[i]);
213 filter_uninit(cu, &s->filters_uv[i]);
214 }
215
216 if (s->cu_module) {
217 CHECK_CU(cu->cuModuleUnload(s->cu_module));
218 s->cu_module = NULL;
219 }
220
221 CHECK_CU(cu->cuCtxPopCurrent(&dummy));
222 }
223
224 av_frame_free(&s->frame);
225 av_buffer_unref(&s->frames_ctx);
226 av_frame_free(&s->tmp_frame);
227}
228
230{
231 AVBufferRef *out_ref = NULL;
232 AVHWFramesContext *out_ctx;
233 int ret;
234
235 out_ref = av_hwframe_ctx_alloc(device_ctx);
236 if (!out_ref)
237 return AVERROR(ENOMEM);
238 out_ctx = (AVHWFramesContext*)out_ref->data;
239
240 out_ctx->format = AV_PIX_FMT_CUDA;
241 out_ctx->sw_format = s->out_fmt;
242 out_ctx->width = FFALIGN(width, 32);
243 out_ctx->height = FFALIGN(height, 32);
244
245 ret = av_hwframe_ctx_init(out_ref);
246 if (ret < 0)
247 goto fail;
248
249 av_frame_unref(s->frame);
250 ret = av_hwframe_get_buffer(out_ref, s->frame, 0);
251 if (ret < 0)
252 goto fail;
253
254 s->frame->width = width;
255 s->frame->height = height;
256
257 av_buffer_unref(&s->frames_ctx);
258 s->frames_ctx = out_ref;
259
260 return 0;
261fail:
262 av_buffer_unref(&out_ref);
263 return ret;
264}
265
266static av_cold int inter_buf_init(AVFilterContext *ctx, int out_width, int in_height)
267{
268 CUDAScaleContext *s = ctx->priv;
269 CudaFunctions *cu = s->hwctx->internal->cuda_dl;
270 int ret = 0;
271
272 cuda_tex_uninit(cu, &s->inter_tex);
273 s->inter_tex = (CUDATex) {
274 .width = out_width,
275 .height = in_height,
276 .crop_width = out_width,
277 .crop_height = in_height,
278 .log2_chroma_w = s->out_desc->log2_chroma_w,
279 .log2_chroma_h = s->in_desc->log2_chroma_h,
280 };
281
282 for (int i = 0; i < s->in_planes; i++) {
283 const int is_chroma = i == 1 || i == 2;
284 const int sub_x = is_chroma ? s->inter_tex.log2_chroma_w : 0;
285 const int sub_y = is_chroma ? s->inter_tex.log2_chroma_h : 0;
286 const int plane_w = AV_CEIL_RSHIFT(out_width, sub_x);
287 const int plane_h = AV_CEIL_RSHIFT(in_height, sub_y);
288 const int sizeof_pixel = (s->in_plane_depths[i] <= 8 ? 1 : 2) *
289 s->in_plane_channels[i];
290
291 size_t pitch;
292 ret = CHECK_CU(cu->cuMemAllocPitch(&s->inter_tex.data[i], &pitch,
293 (size_t) plane_w * sizeof_pixel,
294 plane_h, 16));
295 if (ret < 0)
296 goto fail;
297 s->inter_tex.linesize[i] = pitch;
298
299 CUDA_TEXTURE_DESC tex_desc = {
300 /* inter tex is always read as float */
301 .filterMode = CU_TR_FILTER_MODE_POINT,
302 };
303
304 CUDA_RESOURCE_DESC res_desc = {
305 .resType = CU_RESOURCE_TYPE_PITCH2D,
306 .res.pitch2D.format = s->in_plane_depths[i] <= 8 ?
307 CU_AD_FORMAT_UNSIGNED_INT8 :
308 CU_AD_FORMAT_UNSIGNED_INT16,
309 .res.pitch2D.numChannels = s->in_plane_channels[i],
310 .res.pitch2D.devPtr = s->inter_tex.data[i],
311 .res.pitch2D.pitchInBytes = pitch,
312 .res.pitch2D.width = plane_w,
313 .res.pitch2D.height = plane_h,
314 };
315
316 ret = CHECK_CU(cu->cuTexObjectCreate(&s->inter_tex.tex[i], &res_desc,
317 &tex_desc, NULL));
318 if (ret < 0)
319 goto fail;
320 }
321
322 return 0;
323
324fail:
325 cuda_tex_uninit(cu, &s->inter_tex);
326 return ret;
327}
328
330{
331 for (int i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++)
332 if (supported_formats[i].format == fmt)
333 return 1;
334 return 0;
335}
336
337static const char* get_format_name(enum AVPixelFormat fmt)
338{
339 for (int i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++)
340 if (supported_formats[i].format == fmt)
341 return supported_formats[i].name;
342 return NULL;
343}
344
345static av_cold void set_format_info(AVFilterContext *ctx, enum AVPixelFormat in_format, enum AVPixelFormat out_format)
346{
347 CUDAScaleContext *s = ctx->priv;
348 int i, p, d;
349
350 s->in_fmt = in_format;
351 s->out_fmt = out_format;
352
353 s->in_desc = av_pix_fmt_desc_get(s->in_fmt);
354 s->out_desc = av_pix_fmt_desc_get(s->out_fmt);
355 s->in_planes = av_pix_fmt_count_planes(s->in_fmt);
356 s->out_planes = av_pix_fmt_count_planes(s->out_fmt);
357
358 // find maximum step of each component of each plane
359 // For our subset of formats, this should accurately tell us how many channels CUDA needs
360 // i.e. 1 for Y plane, 2 for UV plane of NV12, 4 for single plane of RGB0 formats
361
362 for (i = 0; i < s->in_desc->nb_components; i++) {
363 d = (s->in_desc->comp[i].depth + 7) / 8;
364 p = s->in_desc->comp[i].plane;
365 s->in_plane_channels[p] = FFMAX(s->in_plane_channels[p], s->in_desc->comp[i].step / d);
366
367 s->in_plane_depths[p] = s->in_desc->comp[i].depth;
368 }
369}
370
371static av_cold int init_processing_chain(AVFilterContext *ctx, int in_width, int in_height,
372 int out_width, int out_height)
373{
374 CUDAScaleContext *s = ctx->priv;
375 FilterLink *inl = ff_filter_link(ctx->inputs[0]);
376 FilterLink *outl = ff_filter_link(ctx->outputs[0]);
377
378 AVHWFramesContext *in_frames_ctx;
379
380 enum AVPixelFormat in_format;
381 enum AVPixelFormat out_format;
382 int ret;
383
384 /* check that we have a hw context */
385 if (!inl->hw_frames_ctx) {
386 av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n");
387 return AVERROR(EINVAL);
388 }
389 in_frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data;
390 in_format = in_frames_ctx->sw_format;
391 out_format = (s->format == AV_PIX_FMT_NONE) ? in_format : s->format;
392
393 if (!format_is_supported(in_format)) {
394 av_log(ctx, AV_LOG_ERROR, "Unsupported input format: %s\n",
395 av_get_pix_fmt_name(in_format));
396 return AVERROR(ENOSYS);
397 }
398 if (!format_is_supported(out_format)) {
399 av_log(ctx, AV_LOG_ERROR, "Unsupported output format: %s\n",
400 av_get_pix_fmt_name(out_format));
401 return AVERROR(ENOSYS);
402 }
403
404 set_format_info(ctx, in_format, out_format);
405
406 if (s->passthrough && in_width == out_width && in_height == out_height && in_format == out_format) {
407 s->frames_ctx = av_buffer_ref(inl->hw_frames_ctx);
408 if (!s->frames_ctx)
409 return AVERROR(ENOMEM);
410 } else {
411 s->passthrough = 0;
412
413 ret = init_hwframe_ctx(s, in_frames_ctx->device_ref, out_width, out_height);
414 if (ret < 0)
415 return ret;
416
417 if (in_width == out_width && in_height == out_height &&
418 in_format == out_format && s->interp_algo == INTERP_ALGO_DEFAULT)
419 s->interp_algo = INTERP_ALGO_NEAREST;
420
421 if (s->interp_algo == INTERP_ALGO_NEAREST) {
422 s->use_filters = 0;
423 } else if (s->use_filters < 0 && (out_width < in_width || out_height < in_height))
424 s->use_filters = 1; /* downscaling; needed for anti-aliasing */
425 else if (s->use_filters < 0)
426 s->use_filters = 0;
427 }
428
429 outl->hw_frames_ctx = av_buffer_ref(s->frames_ctx);
430 if (!outl->hw_frames_ctx)
431 return AVERROR(ENOMEM);
432
433 return 0;
434}
435
437{
438 CUDAScaleContext *s = ctx->priv;
439 CUcontext dummy, cuda_ctx = s->hwctx->cuda_ctx;
440 CudaFunctions *cu = s->hwctx->internal->cuda_dl;
441 char buf[128];
442 int ret;
443
444 const char *in_fmt_name = get_format_name(s->in_fmt);
445 const char *out_fmt_name = get_format_name(s->out_fmt);
446
447 const char *function_infix = "";
448
449 extern const unsigned char ff_vf_scale_cuda_ptx_data[];
450 extern const unsigned int ff_vf_scale_cuda_ptx_len;
451
452 if (s->use_filters) {
453 /* Final pass is always vertical unless not vertically scaling */
454 AVFilterLink *inlink = ctx->inputs[0];
455 AVFilterLink *outlink = ctx->outputs[0];
456 function_infix = inlink->h == outlink->h ? "Generic_h" : "Generic_v";
457 s->interp_use_linear = 0;
458 s->interp_as_integer = 0;
459 } else {
460 switch(s->interp_algo) {
462 function_infix = "Nearest";
463 s->interp_use_linear = 0;
464 s->interp_as_integer = 1;
465 break;
467 function_infix = "Bilinear";
468 s->interp_use_linear = 1;
469 s->interp_as_integer = 1;
470 break;
473 function_infix = "Bicubic";
474 s->interp_use_linear = 0;
475 s->interp_as_integer = 0;
476 break;
478 function_infix = "Lanczos";
479 s->interp_use_linear = 0;
480 s->interp_as_integer = 0;
481 break;
482 default:
483 av_log(ctx, AV_LOG_ERROR, "Unknown interpolation algorithm\n");
484 return AVERROR_BUG;
485 }
486 }
487
488 ret = CHECK_CU(cu->cuCtxPushCurrent(cuda_ctx));
489 if (ret < 0)
490 return ret;
491
492 ret = ff_cuda_load_module(ctx, s->hwctx, &s->cu_module,
493 ff_vf_scale_cuda_ptx_data, ff_vf_scale_cuda_ptx_len);
494 if (ret < 0)
495 goto fail;
496
497 snprintf(buf, sizeof(buf), "Subsample_%s_%s_%s", function_infix, in_fmt_name, out_fmt_name);
498 ret = CHECK_CU(cu->cuModuleGetFunction(&s->cu_func[FILTER_OUT], s->cu_module, buf));
499 if (ret < 0) {
500 av_log(ctx, AV_LOG_FATAL, "Unsupported conversion: %s -> %s\n", in_fmt_name, out_fmt_name);
501 ret = AVERROR(ENOSYS);
502 goto fail;
503 }
504 av_log(ctx, AV_LOG_DEBUG, "Luma filter: %s (%s -> %s)\n", buf, av_get_pix_fmt_name(s->in_fmt), av_get_pix_fmt_name(s->out_fmt));
505
506 snprintf(buf, sizeof(buf), "Subsample_%s_%s_%s_uv", function_infix, in_fmt_name, out_fmt_name);
507 ret = CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_uv[FILTER_OUT], s->cu_module, buf));
508 if (ret < 0)
509 goto fail;
510 av_log(ctx, AV_LOG_DEBUG, "Chroma filter: %s (%s -> %s)\n", buf, av_get_pix_fmt_name(s->in_fmt), av_get_pix_fmt_name(s->out_fmt));
511
512 if (s->use_filters) {
513 /* Intermediate pass is always horizontal */
514 snprintf(buf, sizeof(buf), "Subsample_Generic_h_%s_%s", in_fmt_name, in_fmt_name);
515 ret = CHECK_CU(cu->cuModuleGetFunction(&s->cu_func[FILTER_TMP], s->cu_module, buf));
516 if (ret < 0)
517 goto fail;
518
519 snprintf(buf, sizeof(buf), "Subsample_Generic_h_%s_%s_uv", in_fmt_name, in_fmt_name);
520 ret = CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_uv[FILTER_TMP], s->cu_module, buf));
521 if (ret < 0)
522 goto fail;
523 }
524
525fail:
526 CHECK_CU(cu->cuCtxPopCurrent(&dummy));
527
528 return ret;
529}
530
533 int src_size, int dst_size,
534 double virtual_size)
535{
536 CUDAScaleContext *s = ctx->priv;
537 CudaFunctions *cu = s->hwctx->internal->cuda_dl;
538
540 .scaler_params = { SWS_PARAM_DEFAULT, SWS_PARAM_DEFAULT },
541 .src_size = src_size,
542 .dst_size = dst_size,
543 .virtual_size = virtual_size,
544 };
545
546 switch (s->interp_algo) {
547 case INTERP_ALGO_NEAREST: return 0; /* no weights needed */
548 case INTERP_ALGO_BILINEAR: params.scaler = SWS_SCALE_BILINEAR; break;
549 case INTERP_ALGO_LANCZOS: params.scaler = SWS_SCALE_LANCZOS; break;
552 params.scaler = SWS_SCALE_BICUBIC;
553 params.scaler_params[0] = params.scaler_params[1] = 0.0;
554 if (s->param != SCALE_CUDA_PARAM_DEFAULT)
555 params.scaler_params[1] = s->param;
556 break;
557 }
558
561 if (ret < 0) {
562 if (ret == AVERROR(ENOTSUP)) {
563 av_log(ctx, AV_LOG_ERROR, "Filter size exceeds the maximum "
564 "currently supported by the CUDA scaler (%d).\n",
566 }
567 return ret;
568 }
569
570 float *tmp = av_malloc_array(weights->num_weights, sizeof(*tmp));
571 if (!tmp) {
572 ret = AVERROR(ENOMEM);
573 goto fail;
574 }
575 for (size_t i = 0; i < weights->num_weights; i++)
576 tmp[i] = weights->weights[i] / (float) SWS_FILTER_SCALE;
577
578 f->filter_size = weights->filter_size;
579 f->dst_size = dst_size;
580
581 const size_t weights_size = weights->num_weights * sizeof(*tmp);
582 ret = CHECK_CU(cu->cuMemAlloc(&f->weights, weights_size));
583 if (ret < 0)
584 goto fail;
585 ret = CHECK_CU(cu->cuMemcpyHtoD(f->weights, tmp, weights_size));
586 if (ret < 0)
587 goto fail;
588
589 const size_t offsets_size = dst_size * sizeof(*weights->offsets);
590 ret = CHECK_CU(cu->cuMemAlloc(&f->offsets, offsets_size));
591 if (ret < 0)
592 goto fail;
593 ret = CHECK_CU(cu->cuMemcpyHtoD(f->offsets, weights->offsets, offsets_size));
594 if (ret < 0)
595 goto fail;
596
597 av_log(ctx, AV_LOG_VERBOSE, " using %d tap '%s' filter: %d -> %d\n",
598 f->filter_size, weights->name, src_size, dst_size);
599
600 ret = 0;
601
602fail:
603 av_free(tmp);
605 return ret;
606}
607
609{
610 CUDAScaleContext *s = ctx->priv;
611 AVFilterLink *inlink = ctx->inputs[0];
612 AVFilterLink *outlink = ctx->outputs[0];
613 CudaFunctions *cu = s->hwctx->internal->cuda_dl;
614 CUcontext dummy;
615 int ret;
616
617 const int in_sub_x = s->in_desc->log2_chroma_w;
618 const int in_sub_y = s->in_desc->log2_chroma_h;
619 const int out_sub_x = s->out_desc->log2_chroma_w;
620 const int out_sub_y = s->out_desc->log2_chroma_h;
621
622 ret = CHECK_CU(cu->cuCtxPushCurrent(s->hwctx->cuda_ctx));
623 if (ret < 0)
624 return ret;
625
626 int pass_x = -1, pass_y = -1;
627 if (inlink->w != outlink->w && inlink->h != outlink->h) {
628 /* Always perform the horizontal scaling pass first */
629 pass_x = FILTER_TMP;
630 pass_y = FILTER_OUT;
631 } else if (inlink->w != outlink->w) {
632 pass_x = FILTER_OUT;
633 } else if (inlink->h != outlink->h) {
634 pass_y = FILTER_OUT;
635 }
636
637 if (pass_x >= 0) {
638 ret = cudascale_filter_init(ctx, &s->filters[pass_x],
639 inlink->w, outlink->w, 0.0);
640 if (ret < 0)
641 goto fail;
642 if (s->in_planes > 1) {
643 const int src_size = AV_CEIL_RSHIFT(inlink->w, in_sub_x);
644 const int dst_size = AV_CEIL_RSHIFT(outlink->w, out_sub_x);
645 const double virtual_size = (double) outlink->w / (1 << out_sub_x);
646 ret = cudascale_filter_init(ctx, &s->filters_uv[pass_x],
647 src_size, dst_size, virtual_size);
648 if (ret < 0)
649 goto fail;
650 }
651 }
652
653 if (pass_y >= 0) {
654 ret = cudascale_filter_init(ctx, &s->filters[pass_y],
655 inlink->h, outlink->h, 0.0);
656 if (ret < 0)
657 goto fail;
658 if (s->in_planes > 1) {
659 const int src_size = AV_CEIL_RSHIFT(inlink->h, in_sub_y);
660 const int dst_size = AV_CEIL_RSHIFT(outlink->h, out_sub_y);
661 const double virtual_size = (double) outlink->h / (1 << out_sub_y);
662 ret = cudascale_filter_init(ctx, &s->filters_uv[pass_y],
663 src_size, dst_size, virtual_size);
664 if (ret < 0)
665 goto fail;
666 }
667 }
668
669 ret = inter_buf_init(ctx, outlink->w, inlink->h);
670 if (ret < 0)
671 goto fail;
672
673 ret = 0;
674
675fail:
676 CHECK_CU(cu->cuCtxPopCurrent(&dummy));
677 return ret;
678}
679
681{
682 AVFilterContext *ctx = outlink->src;
683 AVFilterLink *inlink = outlink->src->inputs[0];
684 FilterLink *inl = ff_filter_link(inlink);
685 CUDAScaleContext *s = ctx->priv;
686 AVHWFramesContext *frames_ctx;
687 AVCUDADeviceContext *device_hwctx;
688 int w, h;
689 double w_adj = 1.0;
690 int ret;
691
692 if ((ret = ff_scale_eval_dimensions(s,
693 s->w_expr, s->h_expr,
694 inlink, outlink,
695 &w, &h)) < 0)
696 goto fail;
697
698 if (s->reset_sar)
699 w_adj = inlink->sample_aspect_ratio.num ?
701
702 ret = ff_scale_adjust_dimensions(inlink, &w, &h,
703 s->force_original_aspect_ratio,
704 s->force_divisible_by, w_adj);
705 if (ret < 0)
706 goto fail;
707
708 if (((int64_t)h * inlink->w) > INT_MAX ||
709 ((int64_t)w * inlink->h) > INT_MAX)
710 av_log(ctx, AV_LOG_ERROR, "Rescaled value for width or height is too big.\n");
711
712 outlink->w = w;
713 outlink->h = h;
714
715 ret = init_processing_chain(ctx, inlink->w, inlink->h, w, h);
716 if (ret < 0)
717 return ret;
718
719 frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data;
720 device_hwctx = frames_ctx->device_ctx->hwctx;
721
722 s->hwctx = device_hwctx;
723 s->cu_stream = s->hwctx->stream;
724
725 if (s->reset_sar)
726 outlink->sample_aspect_ratio = (AVRational){1, 1};
727 else if (inlink->sample_aspect_ratio.num) {
728 outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h*inlink->w,
729 outlink->w*inlink->h},
730 inlink->sample_aspect_ratio);
731 } else {
732 outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
733 }
734
735 av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s -> w:%d h:%d fmt:%s%s\n",
736 inlink->w, inlink->h, av_get_pix_fmt_name(s->in_fmt),
737 outlink->w, outlink->h, av_get_pix_fmt_name(s->out_fmt),
738 s->passthrough ? " (passthrough)" : "");
739
740 if (s->use_filters) {
742 if (ret < 0)
743 return ret;
744 }
745
747 if (ret < 0)
748 return ret;
749
750 return 0;
751
752fail:
753 return ret;
754}
755
756/* if depths/channels are NULL, only maps pointers without creating textures */
758 const int depths[4], const int channels[4],
759 CUDATex *tex)
760{
761 CUDAScaleContext *s = ctx->priv;
762 CudaFunctions *cu = s->hwctx->internal->cuda_dl;
763
764 const AVHWFramesContext *fctx = (const AVHWFramesContext*)frame->hw_frames_ctx->data;
766 const int planes = av_pix_fmt_count_planes(fctx->sw_format);
767
768 *tex = (CUDATex) {
769 .width = frame->width,
770 .height = frame->height,
771 .crop_left = frame->crop_left,
772 .crop_top = frame->crop_top,
773 .crop_width = (frame->width - frame->crop_right) - frame->crop_left,
774 .crop_height = (frame->height - frame->crop_bottom) - frame->crop_top,
775 .color_range = frame->color_range,
776 .log2_chroma_w = desc->log2_chroma_w,
777 .log2_chroma_h = desc->log2_chroma_h,
778 .external_data = 1,
779 };
780
781 for (int i = 0; i < planes; i++) {
782 tex->data[i] = (CUdeviceptr)frame->data[i];
783 tex->linesize[i] = frame->linesize[i];
784 if (!depths || !channels)
785 continue;
786
787 CUDA_TEXTURE_DESC tex_desc = {
788 .filterMode = s->interp_use_linear ?
789 CU_TR_FILTER_MODE_LINEAR :
790 CU_TR_FILTER_MODE_POINT,
791 .flags = s->interp_as_integer ? CU_TRSF_READ_AS_INTEGER : 0,
792 };
793
794 const int is_chroma = i == 1 || i == 2;
795 const int sub_x = is_chroma ? desc->log2_chroma_w : 0;
796 const int sub_y = is_chroma ? desc->log2_chroma_h : 0;
797 CUDA_RESOURCE_DESC res_desc = {
798 .resType = CU_RESOURCE_TYPE_PITCH2D,
799 .res.pitch2D.format = depths[i] <= 8 ?
800 CU_AD_FORMAT_UNSIGNED_INT8 :
801 CU_AD_FORMAT_UNSIGNED_INT16,
802 .res.pitch2D.numChannels = channels[i],
803 .res.pitch2D.pitchInBytes = tex->linesize[i],
804 .res.pitch2D.devPtr = tex->data[i],
805 .res.pitch2D.width = AV_CEIL_RSHIFT(frame->width, sub_x),
806 .res.pitch2D.height = AV_CEIL_RSHIFT(frame->height, sub_y),
807 };
808
809 int ret = CHECK_CU(cu->cuTexObjectCreate(&tex->tex[i], &res_desc, &tex_desc, NULL));
810 if (ret < 0) {
811 cuda_tex_uninit(cu, tex);
812 return ret;
813 }
814 }
815
816 return 0;
817}
818
820 const CUtexObject src_tex[4],
821 int src_left, int src_top, int src_width, int src_height,
822 const CUdeviceptr out_data[4],
823 int dst_width, int dst_height, int dst_pitch, int mpeg_range,
824 const CUDAScaleFilter *filter)
825{
826 CUDAScaleContext *s = ctx->priv;
827 CudaFunctions *cu = s->hwctx->internal->cuda_dl;
828
830 .src_tex = {src_tex[0], src_tex[1], src_tex[2], src_tex[3]},
831 .dst = {
832 out_data[0],
833 out_data[1],
834 out_data[2],
835 out_data[3]
836 },
837 .dst_width = dst_width,
838 .dst_height = dst_height,
839 .dst_pitch = dst_pitch,
840 .src_left = src_left,
841 .src_top = src_top,
842 .src_width = src_width,
843 .src_height = src_height,
844 .param = s->param,
845 .mpeg_range = mpeg_range,
846 };
847
848 if (filter) {
849 params.weights = filter->weights;
850 params.offsets = filter->offsets;
851 params.filter_size = filter->filter_size;
852 }
853
854 void *args[] = { &params };
855
856 return CHECK_CU(cu->cuLaunchKernel(func,
857 DIV_UP(dst_width, BLOCKX), DIV_UP(dst_height, BLOCKY), 1,
858 BLOCKX, BLOCKY, 1, 0, s->cu_stream, args, NULL));
859}
860
862 const CUDATex *out, const CUDATex *in)
863{
864 CUDAScaleContext *s = ctx->priv;
865 int mpeg_range = in->color_range != AVCOL_RANGE_JPEG;
866 int ret;
867
868 int out_planes = s->out_planes;
869 if (pass == FILTER_TMP)
870 out_planes = s->in_planes;
871
872 // scale primary plane(s). Usually Y (and A), or single plane of RGB frames.
873 ret = call_resize_kernel(ctx, s->cu_func[pass],
874 in->tex, in->crop_left, in->crop_top,
875 in->crop_width, in->crop_height,
876 out->data, out->width, out->height,
877 out->linesize[0], mpeg_range,
878 &s->filters[pass]);
879 if (ret < 0)
880 return ret;
881
882 if (out_planes > 1) {
883 // scale UV plane. Scale function sets both U and V plane, or singular interleaved plane.
884 ret = call_resize_kernel(ctx, s->cu_func_uv[pass], in->tex,
889 out->data,
890 AV_CEIL_RSHIFT(out->width, out->log2_chroma_w),
891 AV_CEIL_RSHIFT(out->height, out->log2_chroma_h),
892 out->linesize[1], mpeg_range,
893 &s->filters_uv[pass]);
894 if (ret < 0)
895 return ret;
896 }
897
898 return 0;
899}
900
902{
903 CUDAScaleContext *s = ctx->priv;
904 CudaFunctions *cu = s->hwctx->internal->cuda_dl;
905 AVFilterLink *outlink = ctx->outputs[0];
906 int ret = 0;
907
908 CUDATex in_tex = {0}, out_tex = {0};
909 ret = cuda_tex_map_frame(ctx, in, s->in_plane_depths, s->in_plane_channels, &in_tex);
910 if (ret < 0)
911 goto fail;
912
913 ret = cuda_tex_map_frame(ctx, s->frame, NULL, NULL, &out_tex);
914 if (ret < 0)
915 goto fail;
916
917 const CUDATex *src = &in_tex;
918 if (s->use_filters) {
919 /* Handle first pass separately */
920 s->inter_tex.color_range = in->color_range;
921 ret = scalecuda_resize(ctx, FILTER_TMP, &s->inter_tex, src);
922 if (ret < 0)
923 goto fail;
924 src = &s->inter_tex;
925 }
926
927 ret = scalecuda_resize(ctx, FILTER_OUT, &out_tex, src);
928 if (ret < 0)
929 goto fail;
930
931 ret = av_hwframe_get_buffer(s->frame->hw_frames_ctx, s->tmp_frame, 0);
932 if (ret < 0)
933 goto fail;
934
935 av_frame_move_ref(out, s->frame);
936 av_frame_move_ref(s->frame, s->tmp_frame);
937
938 s->frame->width = outlink->w;
939 s->frame->height = outlink->h;
940
941 ret = av_frame_copy_props(out, in);
942 if (ret < 0)
943 goto fail;
944
945 if (out->width != in->width || out->height != in->height) {
946 av_frame_side_data_remove_by_props(&out->side_data, &out->nb_side_data,
948 }
949
950fail:
951 cuda_tex_uninit(cu, &in_tex);
952 cuda_tex_uninit(cu, &out_tex);
953 return ret;
954}
955
957{
958 AVFilterContext *ctx = link->dst;
959 CUDAScaleContext *s = ctx->priv;
960 AVFilterLink *outlink = ctx->outputs[0];
961 CudaFunctions *cu = s->hwctx->internal->cuda_dl;
962
963 AVFrame *out = NULL;
964 CUcontext dummy;
965 int ret = 0;
966
967 if (s->passthrough)
968 return ff_filter_frame(outlink, in);
969
971 if (!out) {
972 ret = AVERROR(ENOMEM);
973 goto fail;
974 }
975
976 ret = CHECK_CU(cu->cuCtxPushCurrent(s->hwctx->cuda_ctx));
977 if (ret < 0)
978 goto fail;
979
980 ret = cudascale_scale(ctx, out, in);
981
982 CHECK_CU(cu->cuCtxPopCurrent(&dummy));
983 if (ret < 0)
984 goto fail;
985
986 if (s->reset_sar) {
987 out->sample_aspect_ratio = (AVRational){1, 1};
988 } else {
989 av_reduce(&out->sample_aspect_ratio.num, &out->sample_aspect_ratio.den,
990 (int64_t)in->sample_aspect_ratio.num * outlink->h * link->w,
991 (int64_t)in->sample_aspect_ratio.den * outlink->w * link->h,
992 INT_MAX);
993 }
994
995 av_frame_free(&in);
996 return ff_filter_frame(outlink, out);
997fail:
998 av_frame_free(&in);
1000 return ret;
1001}
1002
1004{
1005 CUDAScaleContext *s = inlink->dst->priv;
1006
1007 return s->passthrough ?
1008 ff_null_get_video_buffer (inlink, w, h) :
1010}
1011
1012#define OFFSET(x) offsetof(CUDAScaleContext, x)
1013#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM)
1014static const AVOption options[] = {
1015 { "w", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str = "iw" }, .flags = FLAGS },
1016 { "h", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str = "ih" }, .flags = FLAGS },
1017 { "interp_algo", "Interpolation algorithm used for resizing", OFFSET(interp_algo), AV_OPT_TYPE_INT, { .i64 = INTERP_ALGO_DEFAULT }, 0, INTERP_ALGO_COUNT - 1, FLAGS, .unit = "interp_algo" },
1018 { "nearest", "nearest neighbour", 0, AV_OPT_TYPE_CONST, { .i64 = INTERP_ALGO_NEAREST }, 0, 0, FLAGS, .unit = "interp_algo" },
1019 { "bilinear", "bilinear", 0, AV_OPT_TYPE_CONST, { .i64 = INTERP_ALGO_BILINEAR }, 0, 0, FLAGS, .unit = "interp_algo" },
1020 { "bicubic", "bicubic", 0, AV_OPT_TYPE_CONST, { .i64 = INTERP_ALGO_BICUBIC }, 0, 0, FLAGS, .unit = "interp_algo" },
1021 { "lanczos", "lanczos", 0, AV_OPT_TYPE_CONST, { .i64 = INTERP_ALGO_LANCZOS }, 0, 0, FLAGS, .unit = "interp_algo" },
1022 { "format", "Output video pixel format", OFFSET(format), AV_OPT_TYPE_PIXEL_FMT, { .i64 = AV_PIX_FMT_NONE }, INT_MIN, INT_MAX, .flags=FLAGS },
1023 { "passthrough", "Do not process frames at all if parameters match", OFFSET(passthrough), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS },
1024 { "use_filters", "Use generic filters instead of fixed function kernels", OFFSET(use_filters), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, FLAGS, .unit = "use_filters" },
1025 { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, FLAGS, .unit = "use_filters" },
1026 { "param", "Algorithm-Specific parameter", OFFSET(param), AV_OPT_TYPE_FLOAT, { .dbl = SCALE_CUDA_PARAM_DEFAULT }, -FLT_MAX, FLT_MAX, FLAGS },
1027 { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, SCALE_FORCE_OAR_NB-1, FLAGS, .unit = "force_oar" },
1028 { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_DISABLE }, 0, 0, FLAGS, .unit = "force_oar" },
1029 { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_DECREASE }, 0, 0, FLAGS, .unit = "force_oar" },
1030 { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_INCREASE }, 0, 0, FLAGS, .unit = "force_oar" },
1031 { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 256, FLAGS },
1032 { "reset_sar", "reset SAR to 1 and scale to square pixels if scaling proportionally", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
1033 { NULL },
1034};
1035
1036static const AVClass cudascale_class = {
1037 .class_name = "cudascale",
1038 .item_name = av_default_item_name,
1039 .option = options,
1040 .version = LIBAVUTIL_VERSION_INT,
1041};
1042
1044 {
1045 .name = "default",
1046 .type = AVMEDIA_TYPE_VIDEO,
1047 .filter_frame = cudascale_filter_frame,
1048 .get_buffer.video = cudascale_get_video_buffer,
1049 },
1050};
1051
1053 {
1054 .name = "default",
1055 .type = AVMEDIA_TYPE_VIDEO,
1056 .config_props = cudascale_config_props,
1057 },
1058};
1059
1061 .p.name = "scale_cuda",
1062 .p.description = NULL_IF_CONFIG_SMALL("GPU accelerated video resizer"),
1063
1064 .p.priv_class = &cudascale_class,
1065
1066 .init = cudascale_init,
1067 .uninit = cudascale_uninit,
1068
1069 .priv_size = sizeof(CUDAScaleContext),
1070
1073
1075
1076 .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
1077};
SwsAArch64OpImplParams params
Definition ops.c:51
static const char *const format[]
Definition af_aiir.c:444
const FFFilter ff_vf_scale_cuda
channels
Definition aptx.h:31
@ FILTER_NB
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
Main libavfilter public API header.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define f(width, name)
Definition cbs_vp8.c:236
#define s(width, name)
Definition cbs_vp9.c:198
#define FLAGS
Definition cmdutils.c:598
common internal and external API header
#define AV_CEIL_RSHIFT(a, b)
Definition common.h:60
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static AVFrame * frame
static int dummy
Definition ffplay.c:3754
int ff_sws_filter_generate(void *log, const SwsFilterParams *params, SwsFilterWeights **out)
Generate a filter kernel for the given parameters.
Definition filters.c:187
#define fail
Definition test.h:479
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_PIXEL_FMT
Underlying C type is enum AVPixelFormat.
Definition opt.h:306
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_FLOAT
Underlying C type is float.
Definition opt.h:270
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition opt.h:275
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it.
Definition buffer.c:139
AVBufferRef * av_buffer_ref(const AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition buffer.c:103
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition error.h:52
#define AVERROR(e)
Definition error.h:45
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition frame.c:496
void av_frame_move_ref(AVFrame *dst, AVFrame *src)
Move everything contained in src to dst and reset src.
Definition frame.c:523
void av_frame_side_data_remove_by_props(AVFrameSideData ***sd, int *nb_sd, int props)
Remove and free all side data instances that match any of the given side data properties.
Definition side_data.c:123
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition frame.c:599
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition frame.c:52
@ AV_SIDE_DATA_PROP_SIZE_DEPENDENT
Side data depends on the video dimensions.
Definition frame.h:354
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_FATAL
Something went wrong and recovery is not possible.
Definition log.h:204
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
AVRational av_mul_q(AVRational b, AVRational c)
Multiply two rationals.
Definition rational.c:80
int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max)
Reduce a fraction.
Definition rational.c:35
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
#define SWS_PARAM_DEFAULT
Definition swscale.h:456
@ SWS_SCALE_LANCZOS
3-tap sinc/sinc
Definition swscale.h:104
@ SWS_SCALE_BILINEAR
bilinear filtering
Definition swscale.h:98
@ SWS_SCALE_BICUBIC
2-tap cubic BC-spline
Definition swscale.h:99
static const int weights[]
Definition hevc_pel.c:32
int av_hwframe_ctx_init(AVBufferRef *ref)
Finalize the context before use.
Definition hwcontext.c:337
AVBufferRef * av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
Allocate an AVHWFramesContext tied to a given device context.
Definition hwcontext.c:263
int av_hwframe_get_buffer(AVBufferRef *hwframe_ref, AVFrame *frame, int flags)
Allocate a new frame attached to the given AVHWFramesContext.
Definition hwcontext.c:506
FFmpeg internal API for CUDA.
int(* func)(AVBPrint *dst, const char *in, const char *arg)
Definition jacosubdec.c:66
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#define FF_FILTER_FLAG_HWFRAME_AWARE
The filter is aware of hardware frames, and any hardware frame context should not be automatically pr...
Definition filters.h:208
static FilterLink * ff_filter_link(AVFilterLink *link)
Definition filters.h:199
#define FILTER_SINGLE_PIXFMT(pix_fmt_)
Definition filters.h:254
#define av_cold
Definition attributes.h:117
common internal API header
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
const char * desc
Definition libsvtav1.c:83
@ SWS_FILTER_SIZE_MAX
Definition filters.h:41
@ SWS_FILTER_SCALE
14-bit coefficients are picked to fit comfortably within int16_t for efficient SIMD processing (e....
Definition filters.h:40
static const struct @257111027162314367033347246032313251342043035002 planes[]
uint8_t w
Definition llvidencdsp.c:39
int ff_cuda_load_module(void *avctx, AVCUDADeviceContext *hwctx, CUmodule *cu_module, const unsigned char *data, const unsigned int length)
Loads a CUDA module and applies any decompression, if necessary.
Definition load_helper.c:34
#define FFMAX(a, b)
Definition macros.h:47
#define FFALIGN(x, a)
Definition macros.h:78
Memory handling functions.
AVOptions.
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3500
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition pixdesc.c:3380
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
#define AV_PIX_FMT_0RGB32
Definition pixfmt.h:521
#define AV_PIX_FMT_P212
Definition pixfmt.h:624
#define AV_PIX_FMT_YUV420P10
Definition pixfmt.h:545
@ AVCOL_RANGE_JPEG
Full range content.
Definition pixfmt.h:783
#define AV_PIX_FMT_P210
Definition pixfmt.h:622
#define AV_PIX_FMT_P012
Definition pixfmt.h:609
#define AV_PIX_FMT_P216
Definition pixfmt.h:626
#define AV_PIX_FMT_P010
Definition pixfmt.h:608
#define AV_PIX_FMT_P016
Definition pixfmt.h:610
#define AV_PIX_FMT_YUV422P10
Definition pixfmt.h:546
#define AV_PIX_FMT_YUV444P12MSB
Definition pixfmt.h:561
#define AV_PIX_FMT_BGR32
Definition pixfmt.h:519
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_NV12
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition pixfmt.h:96
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition pixfmt.h:73
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition pixfmt.h:77
@ AV_PIX_FMT_CUDA
HW acceleration through CUDA.
Definition pixfmt.h:260
@ AV_PIX_FMT_NV16
interleaved chroma YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition pixfmt.h:198
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition pixfmt.h:78
#define AV_PIX_FMT_YUV444P16
Definition pixfmt.h:558
#define AV_PIX_FMT_YUV444P10MSB
Definition pixfmt.h:560
#define AV_PIX_FMT_0BGR32
Definition pixfmt.h:522
#define AV_PIX_FMT_RGB32
Definition pixfmt.h:517
#define AV_PIX_FMT_YUV444P10
Definition pixfmt.h:548
void av_refstruct_unref(void *objp)
Decrement the reference count of the underlying object and automatically free the object if there are...
Definition refstruct.c:120
int ff_scale_adjust_dimensions(AVFilterLink *inlink, int *ret_w, int *ret_h, int force_original_aspect_ratio, int force_divisible_by, double w_adj)
Transform evaluated width and height obtained from ff_scale_eval_dimensions into actual target width ...
Definition scale_eval.c:123
int ff_scale_eval_dimensions(void *log_ctx, const char *w_expr, const char *h_expr, AVFilterLink *inlink, AVFilterLink *outlink, int *ret_w, int *ret_h)
Parse and evaluate string expressions for width and height.
Definition scale_eval.c:58
@ SCALE_FORCE_OAR_DISABLE
Definition scale_eval.h:25
@ SCALE_FORCE_OAR_NB
Definition scale_eval.h:28
@ SCALE_FORCE_OAR_INCREASE
Definition scale_eval.h:27
@ SCALE_FORCE_OAR_DECREASE
Definition scale_eval.h:26
#define FF_ARRAY_ELEMS(a)
#define snprintf
Definition snprintf.h:34
A reference to a data buffer.
Definition buffer.h:82
uint8_t * data
The data buffer.
Definition buffer.h:90
This struct is allocated as AVHWDeviceContext.hwctx.
Describe the class of an AVClass context structure.
Definition log.h:76
An instance of a filter.
Definition avfilter.h:273
AVFilterLink ** inputs
array of pointers to input links
Definition avfilter.h:281
void * priv
private data for use by the filter
Definition avfilter.h:288
A filter pad used for either input or output.
Definition filters.h:40
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
int width
Definition frame.h:544
int height
Definition frame.h:544
AVRational sample_aspect_ratio
Sample aspect ratio for the video frame, 0/1 if unknown/unspecified.
Definition frame.h:569
enum AVColorRange color_range
MPEG vs JPEG YUV range.
Definition frame.h:723
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition hwcontext.h:88
This struct describes a set or pool of "hardware" frames (i.e.
Definition hwcontext.h:118
enum AVPixelFormat format
The pixel format identifying the underlying HW surface type.
Definition hwcontext.h:200
AVBufferRef * device_ref
A reference to the parent AVHWDeviceContext.
Definition hwcontext.h:129
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition hwcontext.h:213
int width
The allocated dimensions of the frames in this pool.
Definition hwcontext.h:220
AVHWDeviceContext * device_ctx
The parent AVHWDeviceContext.
Definition hwcontext.h:137
AVOption.
Definition opt.h:428
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition pixdesc.h:69
Rational number (pair of numerator and denominator).
Definition rational.h:58
int num
Numerator.
Definition rational.h:59
int den
Denominator.
Definition rational.h:60
CUDAScaleFilter filters_uv[FILTER_NB]
enum AVPixelFormat format
Output sw format.
const AVPixFmtDescriptor * in_desc
enum AVPixelFormat in_fmt out_fmt
CUfunction cu_func[FILTER_NB]
AVCUDADeviceContext * hwctx
CUDAScaleFilter filters[FILTER_NB]
char * w_expr
width expression string
CUfunction cu_func_uv[FILTER_NB]
const AVPixFmtDescriptor * out_desc
char * h_expr
height expression string
AVBufferRef * frames_ctx
CUdeviceptr weights
float[dst_size][filter_size]
CUdeviceptr offsets
int[dst_size]
int external_data
CUtexObject tex[4]
CUdeviceptr data[4]
int color_range
int log2_chroma_h
int linesize[4]
int crop_height
int log2_chroma_w
Represents a computed filter kernel.
Definition filters.h:85
enum AVPixelFormat format
char name[13]
#define av_free(p)
#define av_malloc_array(a, b)
#define av_log(a,...)
static uint8_t tmp[40]
Definition aes_ctr.c:52
void(* filter)(uint8_t *src, ptrdiff_t stride, int qscale)
Definition h263dsp.c:29
#define src
Definition vp8dsp.c:248
static FILE * out
Definition movenc.c:55
static AVFormatContext * ctx
Definition movenc.c:49
#define height
Definition dsp.h:89
#define width
Definition dsp.h:89
static enum AVPixelFormat supported_formats[]
#define DIV_UP(a, b)
#define BLOCKX
#define BLOCKY
static av_cold int cudascale_setup_filters(AVFilterContext *ctx)
static av_cold int init_hwframe_ctx(CUDAScaleContext *s, AVBufferRef *device_ctx, int width, int height)
static av_cold void cudascale_uninit(AVFilterContext *ctx)
static int scalecuda_resize(AVFilterContext *ctx, int pass, const CUDATex *out, const CUDATex *in)
static int cudascale_scale(AVFilterContext *ctx, AVFrame *out, AVFrame *in)
#define DIV_UP(a, b)
static av_cold int cudascale_config_props(AVFilterLink *outlink)
static av_cold int init_processing_chain(AVFilterContext *ctx, int in_width, int in_height, int out_width, int out_height)
static av_cold int cudascale_init(AVFilterContext *ctx)
static const AVClass cudascale_class
static av_cold int cudascale_load_functions(AVFilterContext *ctx)
static const char * get_format_name(enum AVPixelFormat fmt)
static av_cold int cudascale_filter_init(AVFilterContext *ctx, CUDAScaleFilter *f, int src_size, int dst_size, double virtual_size)
static int call_resize_kernel(AVFilterContext *ctx, CUfunction func, const CUtexObject src_tex[4], int src_left, int src_top, int src_width, int src_height, const CUdeviceptr out_data[4], int dst_width, int dst_height, int dst_pitch, int mpeg_range, const CUDAScaleFilter *filter)
@ INTERP_ALGO_LANCZOS
@ INTERP_ALGO_BICUBIC
@ INTERP_ALGO_DEFAULT
@ INTERP_ALGO_BILINEAR
@ INTERP_ALGO_COUNT
@ INTERP_ALGO_NEAREST
static void cuda_tex_uninit(CudaFunctions *cu, CUDATex *t)
static int format_is_supported(enum AVPixelFormat fmt)
#define CHECK_CU(x)
static av_cold void set_format_info(AVFilterContext *ctx, enum AVPixelFormat in_format, enum AVPixelFormat out_format)
static AVFrame * cudascale_get_video_buffer(AVFilterLink *inlink, int w, int h)
#define OFFSET(x)
static void filter_uninit(CudaFunctions *cu, CUDAScaleFilter *filter)
static int cudascale_filter_frame(AVFilterLink *link, AVFrame *in)
static av_cold int inter_buf_init(AVFilterContext *ctx, int out_width, int in_height)
static const AVFilterPad cudascale_outputs[]
static const AVFilterPad cudascale_inputs[]
@ FILTER_NB
@ FILTER_OUT
@ FILTER_TMP
static int cuda_tex_map_frame(AVFilterContext *ctx, const AVFrame *frame, const int depths[4], const int channels[4], CUDATex *tex)
#define SCALE_CUDA_PARAM_DEFAULT
AVFrame * ff_null_get_video_buffer(AVFilterLink *link, int w, int h)
Definition video.c:44
AVFrame * ff_default_get_video_buffer(AVFilterLink *link, int w, int h)
Definition video.c:84