FFmpeg
Loading...
Searching...
No Matches
vf_thumbnail_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 "libavutil/hwcontext.h"
26#include "libavutil/mem.h"
27#include "libavutil/opt.h"
28#include "libavutil/pixdesc.h"
29
30#include "avfilter.h"
31#include "filters.h"
32
33#include "cuda/load_helper.h"
34
35#define CHECK_CU(x) FF_CUDA_CHECK_DL(ctx, s->hwctx->internal->cuda_dl, x)
36
37#define HIST_SIZE (3*256)
38#define DIV_UP(a, b) ( ((a) + (b) - 1) / (b) )
39#define BLOCKX 32
40#define BLOCKY 16
41
53
54struct thumb_frame {
55 AVFrame *buf; ///< cached frame
56 int histogram[HIST_SIZE]; ///< RGB color distribution histogram of the frame
57};
58
59typedef struct ThumbnailCudaContext {
60 const AVClass *class;
61 int n; ///< current frame
62 int n_frames; ///< number of frames for analysis
63 struct thumb_frame *frames; ///< the n_frames frames
64 AVRational tb; ///< copy of the input timebase to ease access
65
68
69 CUmodule cu_module;
70
71 CUfunction cu_func_uchar;
72 CUfunction cu_func_uchar2;
73 CUfunction cu_func_ushort;
74 CUfunction cu_func_ushort2;
75 CUstream cu_stream;
76
77 CUdeviceptr data;
78
80
81#define OFFSET(x) offsetof(ThumbnailCudaContext, x)
82#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
83
85 { "n", "set the frames batch size", OFFSET(n_frames), AV_OPT_TYPE_INT, {.i64=100}, 2, INT_MAX, FLAGS },
86 { NULL }
87};
88
89AVFILTER_DEFINE_CLASS(thumbnail_cuda);
90
92{
93 ThumbnailCudaContext *s = ctx->priv;
94
95 s->frames = av_calloc(s->n_frames, sizeof(*s->frames));
96 if (!s->frames) {
98 "Allocation failure, try to lower the number of frames\n");
99 return AVERROR(ENOMEM);
100 }
101 av_log(ctx, AV_LOG_VERBOSE, "batch size: %d frames\n", s->n_frames);
102 return 0;
103}
104
105/**
106 * @brief Compute Sum-square deviation to estimate "closeness".
107 * @param hist color distribution histogram
108 * @param median average color distribution histogram
109 * @return sum of squared errors
110 */
111static double frame_sum_square_err(const int *hist, const double *median)
112{
113 int i;
114 double err, sum_sq_err = 0;
115
116 for (i = 0; i < HIST_SIZE; i++) {
117 err = median[i] - (double)hist[i];
118 sum_sq_err += err*err;
119 }
120 return sum_sq_err;
121}
122
124{
125 AVFrame *picref;
126 ThumbnailCudaContext *s = ctx->priv;
127 int i, j, best_frame_idx = 0;
128 int nb_frames = s->n;
129 double avg_hist[HIST_SIZE] = {0}, sq_err, min_sq_err = -1;
130
131 // average histogram of the N frames
132 for (j = 0; j < FF_ARRAY_ELEMS(avg_hist); j++) {
133 for (i = 0; i < nb_frames; i++)
134 avg_hist[j] += (double)s->frames[i].histogram[j];
135 avg_hist[j] /= nb_frames;
136 }
137
138 // find the frame closer to the average using the sum of squared errors
139 for (i = 0; i < nb_frames; i++) {
140 sq_err = frame_sum_square_err(s->frames[i].histogram, avg_hist);
141 if (i == 0 || sq_err < min_sq_err)
142 best_frame_idx = i, min_sq_err = sq_err;
143 }
144
145 // free and reset everything (except the best frame buffer)
146 for (i = 0; i < nb_frames; i++) {
147 memset(s->frames[i].histogram, 0, sizeof(s->frames[i].histogram));
148 if (i != best_frame_idx)
149 av_frame_free(&s->frames[i].buf);
150 }
151 s->n = 0;
152
153 // raise the chosen one
154 picref = s->frames[best_frame_idx].buf;
155 av_log(ctx, AV_LOG_INFO, "frame id #%d (pts_time=%f) selected "
156 "from a set of %d images\n", best_frame_idx,
157 picref->pts * av_q2d(s->tb), nb_frames);
158 s->frames[best_frame_idx].buf = NULL;
159
160 return picref;
161}
162
163static int thumbnail_kernel(AVFilterContext *ctx, CUfunction func, int channels,
164 int *histogram, uint8_t *src_dptr, int src_width, int src_height, int src_pitch, int pixel_size)
165{
166 int ret;
167 ThumbnailCudaContext *s = ctx->priv;
168 CudaFunctions *cu = s->hwctx->internal->cuda_dl;
169 CUtexObject tex = 0;
170 void *args[] = { &tex, &histogram, &src_width, &src_height };
171
172 CUDA_TEXTURE_DESC tex_desc = {
173 .filterMode = CU_TR_FILTER_MODE_LINEAR,
174 .flags = CU_TRSF_READ_AS_INTEGER,
175 };
176
177 CUDA_RESOURCE_DESC res_desc = {
178 .resType = CU_RESOURCE_TYPE_PITCH2D,
179 .res.pitch2D.format = pixel_size == 1 ?
180 CU_AD_FORMAT_UNSIGNED_INT8 :
181 CU_AD_FORMAT_UNSIGNED_INT16,
182 .res.pitch2D.numChannels = channels,
183 .res.pitch2D.width = src_width,
184 .res.pitch2D.height = src_height,
185 .res.pitch2D.pitchInBytes = src_pitch,
186 .res.pitch2D.devPtr = (CUdeviceptr)src_dptr,
187 };
188
189 ret = CHECK_CU(cu->cuTexObjectCreate(&tex, &res_desc, &tex_desc, NULL));
190 if (ret < 0)
191 goto exit;
192
193 ret = CHECK_CU(cu->cuLaunchKernel(func,
194 DIV_UP(src_width, BLOCKX), DIV_UP(src_height, BLOCKY), 1,
195 BLOCKX, BLOCKY, 1, 0, s->cu_stream, args, NULL));
196exit:
197 if (tex)
198 CHECK_CU(cu->cuTexObjectDestroy(tex));
199
200 return ret;
201}
202
204{
206 ThumbnailCudaContext *s = ctx->priv;
207
208 switch (in_frames_ctx->sw_format) {
209 case AV_PIX_FMT_NV12:
210 thumbnail_kernel(ctx, s->cu_func_uchar, 1,
211 histogram, in->data[0], in->width, in->height, in->linesize[0], 1);
212 thumbnail_kernel(ctx, s->cu_func_uchar2, 2,
213 histogram + 256, in->data[1], in->width / 2, in->height / 2, in->linesize[1], 1);
214 break;
216 thumbnail_kernel(ctx, s->cu_func_uchar, 1,
217 histogram, in->data[0], in->width, in->height, in->linesize[0], 1);
218 thumbnail_kernel(ctx, s->cu_func_uchar, 1,
219 histogram + 256, in->data[1], in->width / 2, in->height / 2, in->linesize[1], 1);
220 thumbnail_kernel(ctx, s->cu_func_uchar, 1,
221 histogram + 512, in->data[2], in->width / 2, in->height / 2, in->linesize[2], 1);
222 break;
224 thumbnail_kernel(ctx, s->cu_func_uchar, 1,
225 histogram, in->data[0], in->width, in->height, in->linesize[0], 1);
226 thumbnail_kernel(ctx, s->cu_func_uchar, 1,
227 histogram + 256, in->data[1], in->width, in->height, in->linesize[1], 1);
228 thumbnail_kernel(ctx, s->cu_func_uchar, 1,
229 histogram + 512, in->data[2], in->width, in->height, in->linesize[2], 1);
230 break;
234 thumbnail_kernel(ctx, s->cu_func_ushort, 1,
235 histogram, in->data[0], in->width, in->height, in->linesize[0], 2);
236 thumbnail_kernel(ctx, s->cu_func_ushort2, 2,
237 histogram + 256, in->data[1], in->width / 2, in->height / 2, in->linesize[1], 2);
238 break;
242 thumbnail_kernel(ctx, s->cu_func_ushort2, 1,
243 histogram, in->data[0], in->width, in->height, in->linesize[0], 2);
244 thumbnail_kernel(ctx, s->cu_func_ushort2, 1,
245 histogram + 256, in->data[1], in->width, in->height, in->linesize[1], 2);
246 thumbnail_kernel(ctx, s->cu_func_ushort2, 1,
247 histogram + 512, in->data[2], in->width, in->height, in->linesize[2], 2);
248 break;
249 default:
250 return AVERROR_BUG;
251 }
252
253 return 0;
254}
255
257{
258 AVFilterContext *ctx = inlink->dst;
259 ThumbnailCudaContext *s = ctx->priv;
260 CudaFunctions *cu = s->hwctx->internal->cuda_dl;
261 AVFilterLink *outlink = ctx->outputs[0];
262 int *hist = s->frames[s->n].histogram;
263 AVHWFramesContext *hw_frames_ctx = (AVHWFramesContext*)s->hw_frames_ctx->data;
264 CUcontext dummy;
265 CUDA_MEMCPY2D cpy = { 0 };
266 int ret = 0;
267
268 // keep a reference of each frame
269 s->frames[s->n].buf = frame;
270
271 ret = CHECK_CU(cu->cuCtxPushCurrent(s->hwctx->cuda_ctx));
272 if (ret < 0)
273 return ret;
274
275 CHECK_CU(cu->cuMemsetD8Async(s->data, 0, HIST_SIZE * sizeof(int), s->cu_stream));
276
277 thumbnail(ctx, (int*)s->data, frame);
278
279 cpy.srcMemoryType = CU_MEMORYTYPE_DEVICE;
280 cpy.dstMemoryType = CU_MEMORYTYPE_HOST;
281 cpy.srcDevice = s->data;
282 cpy.dstHost = hist;
283 cpy.srcPitch = HIST_SIZE * sizeof(int);
284 cpy.dstPitch = HIST_SIZE * sizeof(int);
285 cpy.WidthInBytes = HIST_SIZE * sizeof(int);
286 cpy.Height = 1;
287
288 ret = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, s->cu_stream));
289 if (ret < 0)
290 return ret;
291
292 if (hw_frames_ctx->sw_format == AV_PIX_FMT_NV12 || hw_frames_ctx->sw_format == AV_PIX_FMT_YUV420P ||
293 hw_frames_ctx->sw_format == AV_PIX_FMT_P010LE || hw_frames_ctx->sw_format == AV_PIX_FMT_P012LE ||
294 hw_frames_ctx->sw_format == AV_PIX_FMT_P016LE)
295 {
296 int i;
297 for (i = 256; i < HIST_SIZE; i++)
298 hist[i] = 4 * hist[i];
299 }
300
301 ret = CHECK_CU(cu->cuCtxPopCurrent(&dummy));
302 if (ret < 0)
303 return ret;
304
305 // no selection until the buffer of N frames is filled up
306 s->n++;
307 if (s->n < s->n_frames)
308 return 0;
309
310 return ff_filter_frame(outlink, get_best_frame(ctx));
311}
312
314{
315 ThumbnailCudaContext *s = ctx->priv;
316
317 if (s->hwctx) {
318 CudaFunctions *cu = s->hwctx->internal->cuda_dl;
319
320 if (s->data) {
321 CHECK_CU(cu->cuMemFree(s->data));
322 s->data = 0;
323 }
324
325 if (s->cu_module) {
326 CHECK_CU(cu->cuModuleUnload(s->cu_module));
327 s->cu_module = NULL;
328 }
329 }
330
331 if (s->frames) {
332 for (int i = 0; i < s->n_frames && s->frames[i].buf; i++)
333 av_frame_free(&s->frames[i].buf);
334 av_freep(&s->frames);
335 }
336}
337
339{
340 AVFilterContext *ctx = link->src;
341 ThumbnailCudaContext *s = ctx->priv;
342 int ret = ff_request_frame(ctx->inputs[0]);
343
344 if (ret == AVERROR_EOF && s->n) {
345 ret = ff_filter_frame(link, get_best_frame(ctx));
346 if (ret < 0)
347 return ret;
348 ret = AVERROR_EOF;
349 }
350 if (ret < 0)
351 return ret;
352 return 0;
353}
354
356{
357 int i;
358
359 for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++)
360 if (supported_formats[i] == fmt)
361 return 1;
362 return 0;
363}
364
365static int config_props(AVFilterLink *inlink)
366{
367 AVFilterContext *ctx = inlink->dst;
368 FilterLink *inl = ff_filter_link(inlink);
369 FilterLink *outl = ff_filter_link(ctx->outputs[0]);
370 ThumbnailCudaContext *s = ctx->priv;
371 AVHWFramesContext *hw_frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data;
372 AVCUDADeviceContext *device_hwctx = hw_frames_ctx->device_ctx->hwctx;
373 CUcontext dummy, cuda_ctx = device_hwctx->cuda_ctx;
374 CudaFunctions *cu = device_hwctx->internal->cuda_dl;
375 int ret;
376
377 extern const unsigned char ff_vf_thumbnail_cuda_ptx_data[];
378 extern const unsigned int ff_vf_thumbnail_cuda_ptx_len;
379
380 s->hwctx = device_hwctx;
381 s->cu_stream = s->hwctx->stream;
382
383 ret = CHECK_CU(cu->cuCtxPushCurrent(cuda_ctx));
384 if (ret < 0)
385 return ret;
386
387 ret = ff_cuda_load_module(ctx, device_hwctx, &s->cu_module, ff_vf_thumbnail_cuda_ptx_data, ff_vf_thumbnail_cuda_ptx_len);
388 if (ret < 0)
389 return ret;
390
391 ret = CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_uchar, s->cu_module, "Thumbnail_uchar"));
392 if (ret < 0)
393 return ret;
394
395 ret = CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_uchar2, s->cu_module, "Thumbnail_uchar2"));
396 if (ret < 0)
397 return ret;
398
399 ret = CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_ushort, s->cu_module, "Thumbnail_ushort"));
400 if (ret < 0)
401 return ret;
402
403 ret = CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_ushort2, s->cu_module, "Thumbnail_ushort2"));
404 if (ret < 0)
405 return ret;
406
407 ret = CHECK_CU(cu->cuMemAlloc(&s->data, HIST_SIZE * sizeof(int)));
408 if (ret < 0)
409 return ret;
410
411 CHECK_CU(cu->cuCtxPopCurrent(&dummy));
412
413 s->hw_frames_ctx = inl->hw_frames_ctx;
414
415 outl->hw_frames_ctx = av_buffer_ref(s->hw_frames_ctx);
416 if (!outl->hw_frames_ctx)
417 return AVERROR(ENOMEM);
418
419 s->tb = inlink->time_base;
420
421 if (!format_is_supported(hw_frames_ctx->sw_format)) {
422 av_log(ctx, AV_LOG_ERROR, "Unsupported input format: %s\n", av_get_pix_fmt_name(hw_frames_ctx->sw_format));
423 return AVERROR(ENOSYS);
424 }
425
426 return 0;
427}
428
430 {
431 .name = "default",
432 .type = AVMEDIA_TYPE_VIDEO,
433 .config_props = config_props,
434 .filter_frame = filter_frame,
435 },
436};
437
439 {
440 .name = "default",
441 .type = AVMEDIA_TYPE_VIDEO,
442 .request_frame = request_frame,
443 },
444};
445
447 .p.name = "thumbnail_cuda",
448 .p.description = NULL_IF_CONFIG_SMALL("Select the most representative frame in a given sequence of consecutive frames using CUDA."),
449 .p.priv_class = &thumbnail_cuda_class,
450 .priv_size = sizeof(ThumbnailCudaContext),
451 .init = init,
452 .uninit = uninit,
456 .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
457};
static int request_frame(AVFilterLink *outlink)
Definition af_aecho.c:272
const FFFilter ff_vf_thumbnail_cuda
static AVFormatContext * ctx
channels
Definition aptx.h:31
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
int ff_request_frame(AVFilterLink *link)
Request an input frame from the filter at the other end of the link.
Definition avfilter.c:483
Main libavfilter public API header.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define FLAGS
Definition cmdutils.c:598
#define NULL
Definition coverity.c:32
static AVFrame * frame
static int filter_frame(DBEDecodeContext *s, AVFrame *frame)
Definition dolby_e.c:1067
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
#define HIST_SIZE
Definition f_ebur128.c:51
static int dummy
Definition ffplay.c:3754
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
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_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_INFO
Standard information.
Definition log.h:221
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition rational.h:104
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
FFmpeg internal API for CUDA.
static av_cold void uninit(AVBitStreamFilterContext *ctx)
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 AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
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
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:264
Memory handling functions.
AVOptions.
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
#define AV_PIX_FMT_P012
Definition pixfmt.h:609
#define AV_PIX_FMT_P010
Definition pixfmt.h:608
#define AV_PIX_FMT_P016
Definition pixfmt.h:610
#define AV_PIX_FMT_YUV444P12MSB
Definition pixfmt.h:561
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_P010LE
like NV12, with 10bpp per component, data in the high bits, zeros in the low bits,...
Definition pixfmt.h:307
@ 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_P016LE
like NV12, with 16bpp per component, little-endian
Definition pixfmt.h:323
@ AV_PIX_FMT_P012LE
like NV12, with 12bpp per component, data in the high bits, zeros in the low bits,...
Definition pixfmt.h:408
@ AV_PIX_FMT_CUDA
HW acceleration through CUDA.
Definition pixfmt.h:260
@ 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 FF_ARRAY_ELEMS(a)
static int config_props(AVBitStreamFilterLink *link)
Definition source.c:181
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.
AVCUDADeviceContextInternal * internal
Describe the class of an AVClass context structure.
Definition log.h:76
An instance of a filter.
Definition avfilter.h:273
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
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition frame.h:574
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition frame.h:493
int width
Definition frame.h:544
AVBufferRef * hw_frames_ctx
For hwaccel-format frames, this should be a reference to the AVHWFramesContext describing the frame.
Definition frame.h:769
int height
Definition frame.h:544
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition frame.h:517
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 sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition hwcontext.h:213
AVHWDeviceContext * device_ctx
The parent AVHWDeviceContext.
Definition hwcontext.h:137
AVOption.
Definition opt.h:428
Rational number (pair of numerator and denominator).
Definition rational.h:58
AVRational tb
copy of the input timebase to ease access
AVCUDADeviceContext * hwctx
AVBufferRef * hw_frames_ctx
struct thumb_frame * frames
the n_frames frames
int n_frames
number of frames for analysis
AVFrame * buf
cached frame
int histogram[HIST_SIZE]
RGB color distribution histogram of the frame.
#define av_freep(p)
#define av_log(a,...)
static enum AVPixelFormat supported_formats[]
#define DIV_UP(a, b)
#define BLOCKX
#define BLOCKY
static AVFrame * get_best_frame(AVFilterContext *ctx)
static const AVFilterPad thumbnail_cuda_outputs[]
static const AVOption thumbnail_cuda_options[]
#define DIV_UP(a, b)
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
#define HIST_SIZE
static int request_frame(AVFilterLink *link)
static int format_is_supported(enum AVPixelFormat fmt)
static int thumbnail(AVFilterContext *ctx, int *histogram, AVFrame *in)
static int thumbnail_kernel(AVFilterContext *ctx, CUfunction func, int channels, int *histogram, uint8_t *src_dptr, int src_width, int src_height, int src_pitch, int pixel_size)
#define CHECK_CU(x)
static int config_props(AVFilterLink *inlink)
static av_cold void uninit(AVFilterContext *ctx)
static double frame_sum_square_err(const int *hist, const double *median)
Compute Sum-square deviation to estimate "closeness".
#define OFFSET(x)
static const AVFilterPad thumbnail_cuda_inputs[]