FFmpeg
Loading...
Searching...
No Matches
vf_coreimage.m
Go to the documentation of this file.
1/*
2 * Copyright (c) 2016 Thilo Borgmann
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/**
22 * @file
23 * Video processing based on Apple's CoreImage API
24 */
25
26#import <CoreImage/CoreImage.h>
27#import <AppKit/AppKit.h>
28
29#include "avfilter.h"
30#include "filters.h"
31#include "formats.h"
32#include "video.h"
33#include "libavutil/internal.h"
34#include "libavutil/mem.h"
35#include "libavutil/opt.h"
36#include "libavutil/pixdesc.h"
37
38typedef struct CoreImageContext {
39 const AVClass *class;
40
41 int is_video_source; ///< filter is used as video source
42
43 int w, h; ///< video size
44 AVRational sar; ///< sample aspect ratio
45 AVRational frame_rate; ///< video frame rate
46 AVRational time_base; ///< stream time base
47 int64_t duration; ///< duration expressed in microseconds
48 int64_t pts; ///< increasing presentation time stamp
49 AVFrame *picref; ///< cached reference containing the painted picture
50
51 CFTypeRef glctx; ///< OpenGL context
52 CGContextRef cgctx; ///< Bitmap context for image copy
53 CFTypeRef input_image; ///< Input image container for passing into Core Image API
54 CGColorSpaceRef color_space; ///< Common color space for input image and cgcontext
55 int bits_per_component; ///< Shared bpc for input-output operation
56
57 char *filter_string; ///< The complete user provided filter definition
58 CFTypeRef *filters; ///< CIFilter object for all requested filters
59 int num_filters; ///< Amount of filters in *filters
60
61 char *output_rect; ///< Rectangle to be filled with filter input
62 int list_filters; ///< Option used to list all available filters including generators
63 int list_generators; ///< Option used to list all available generators
65
66static int config_output(AVFilterLink *link)
67{
68 FilterLink *l = ff_filter_link(link);
69 CoreImageContext *ctx = link->src->priv;
70
71 link->w = ctx->w;
72 link->h = ctx->h;
73 link->sample_aspect_ratio = ctx->sar;
74 l->frame_rate = ctx->frame_rate;
75 link->time_base = ctx->time_base;
76
78 ctx->bits_per_component = av_get_bits_per_pixel(desc) / desc->nb_components;
79
80 return 0;
81}
82
83/** Determine image properties from input link of filter chain.
84 */
85static int config_input(AVFilterLink *link)
86{
87 CoreImageContext *ctx = link->dst->priv;
89 ctx->bits_per_component = av_get_bits_per_pixel(desc) / desc->nb_components;
90
91 return 0;
92}
93
94/** Print a list of all available filters including options and respective value ranges and defaults.
95 */
97{
98 // querying filters and attributes
99 NSArray *filter_categories = nil;
100
101 if (ctx->list_generators && !ctx->list_filters) {
102 filter_categories = [NSArray arrayWithObjects:kCICategoryGenerator, nil];
103 }
104
105 for (NSString *filter_name in [CIFilter filterNamesInCategories:filter_categories]) {
106 CIFilter *filter = [CIFilter filterWithName:filter_name];
107 NSDictionary<NSString *, id> *filter_attribs = [filter attributes];
108
109 av_log(ctx, AV_LOG_INFO, "Filter: %s\n", [filter_name UTF8String]);
110
111 for (NSString *input in [filter inputKeys]) {
112 NSDictionary *input_attribs = [filter_attribs valueForKey:input];
113 NSString *input_class = [input_attribs valueForKey:kCIAttributeClass];
114 if ([input_class isEqualToString:@"NSNumber"]) {
115 NSNumber *value_default = [input_attribs valueForKey:kCIAttributeDefault];
116 NSNumber *value_min = [input_attribs valueForKey:kCIAttributeSliderMin];
117 NSNumber *value_max = [input_attribs valueForKey:kCIAttributeSliderMax];
118
119 av_log(ctx, AV_LOG_INFO, "\tOption: %s\t[%s]\t[%s %s][%s]\n",
120 [input UTF8String],
121 [input_class UTF8String],
122 [[value_min stringValue] UTF8String],
123 [[value_max stringValue] UTF8String],
124 [[value_default stringValue] UTF8String]);
125 } else {
126 av_log(ctx, AV_LOG_INFO, "\tOption: %s\t[%s]\n",
127 [input UTF8String],
128 [input_class UTF8String]);
129 }
130 }
131 }
132}
133
135{
136 int i;
137
138 // (re-)initialize input image
139 const CGSize frame_size = {
140 frame->width,
141 frame->height
142 };
143
144 NSData *data = [NSData dataWithBytesNoCopy:frame->data[0]
145 length:frame->height*frame->linesize[0]
146 freeWhenDone:NO];
147
148 CIImage *ret = [(__bridge CIImage*)ctx->input_image initWithBitmapData:data
149 bytesPerRow:frame->linesize[0]
150 size:frame_size
151 format:kCIFormatARGB8
152 colorSpace:ctx->color_space]; //kCGColorSpaceGenericRGB
153 if (!ret) {
154 av_log(ctx, AV_LOG_ERROR, "Input image could not be initialized.\n");
155 return AVERROR_EXTERNAL;
156 }
157
158 CIFilter *filter = NULL;
159 CIImage *filter_input = (__bridge CIImage*)ctx->input_image;
160 CIImage *filter_output = NULL;
161
162 // successively apply all filters
163 for (i = 0; i < ctx->num_filters; i++) {
164 if (i) {
165 // set filter input to previous filter output
166 filter_input = [(__bridge CIImage*)ctx->filters[i-1] valueForKey:kCIOutputImageKey];
167 CGRect out_rect = [filter_input extent];
168 if (out_rect.size.width > frame->width || out_rect.size.height > frame->height) {
169 // do not keep padded image regions after filtering
170 out_rect.origin.x = 0.0f;
171 out_rect.origin.y = 0.0f;
172 out_rect.size.width = frame->width;
173 out_rect.size.height = frame->height;
174 }
175 filter_input = [filter_input imageByCroppingToRect:out_rect];
176 }
177
178 filter = (__bridge CIFilter*)ctx->filters[i];
179
180 // do not set input image for the first filter if used as video source
181 if (!ctx->is_video_source || i) {
182 @try {
183 [filter setValue:filter_input forKey:kCIInputImageKey];
184 } @catch (NSException *exception) {
185 if (![[exception name] isEqualToString:NSUndefinedKeyException]) {
186 av_log(ctx, AV_LOG_ERROR, "An error occurred: %s.", [exception.reason UTF8String]);
187 return AVERROR_EXTERNAL;
188 } else {
189 av_log(ctx, AV_LOG_WARNING, "Selected filter does not accept an input image.\n");
190 }
191 }
192 }
193 }
194
195 // get output of last filter
196 filter_output = [filter valueForKey:kCIOutputImageKey];
197
198 if (!filter_output) {
199 av_log(ctx, AV_LOG_ERROR, "Filter output not available.\n");
200 return AVERROR_EXTERNAL;
201 }
202
203 // do not keep padded image regions after filtering
204 CGRect out_rect = [filter_output extent];
205 if (out_rect.size.width > frame->width || out_rect.size.height > frame->height) {
206 av_log(ctx, AV_LOG_DEBUG, "Cropping output image.\n");
207 out_rect.origin.x = 0.0f;
208 out_rect.origin.y = 0.0f;
209 out_rect.size.width = frame->width;
210 out_rect.size.height = frame->height;
211 }
212
213 CGImageRef out = [(__bridge CIContext*)ctx->glctx createCGImage:filter_output
214 fromRect:out_rect];
215
216 if (!out) {
217 av_log(ctx, AV_LOG_ERROR, "Cannot create valid output image.\n");
218 }
219
220 // create bitmap context on the fly for rendering into current frame->data[]
221 if (ctx->cgctx) {
222 CGContextRelease(ctx->cgctx);
223 ctx->cgctx = NULL;
224 }
225 size_t out_width = CGImageGetWidth(out);
226 size_t out_height = CGImageGetHeight(out);
227
228 if (out_width > frame->width || out_height > frame->height) { // this might result in segfault
229 av_log(ctx, AV_LOG_WARNING, "Output image has unexpected size: %lux%lu (expected: %ix%i). This may crash...\n",
230 out_width, out_height, frame->width, frame->height);
231 }
232 ctx->cgctx = CGBitmapContextCreate(frame->data[0],
233 frame->width,
234 frame->height,
235 ctx->bits_per_component,
236 frame->linesize[0],
237 ctx->color_space,
238 (uint32_t)kCGImageAlphaPremultipliedFirst); // ARGB
239 if (!ctx->cgctx) {
240 av_log(ctx, AV_LOG_ERROR, "CGBitmap context cannot be created.\n");
241 return AVERROR_EXTERNAL;
242 }
243
244 // copy ("draw") the output image into the frame data
245 CGRect rect = {{0,0},{frame->width, frame->height}};
246 if (ctx->output_rect) {
247 @try {
248 NSString *tmp_string = [NSString stringWithUTF8String:ctx->output_rect];
249 NSRect tmp = NSRectFromString(tmp_string);
250 rect = NSRectToCGRect(tmp);
251 } @catch (NSException *exception) {
252 av_log(ctx, AV_LOG_ERROR, "An error occurred: %s.", [exception.reason UTF8String]);
253 return AVERROR_EXTERNAL;
254 }
255 if (rect.size.width == 0.0f) {
256 av_log(ctx, AV_LOG_WARNING, "Width of output rect is zero.\n");
257 }
258 if (rect.size.height == 0.0f) {
259 av_log(ctx, AV_LOG_WARNING, "Height of output rect is zero.\n");
260 }
261 }
262
263 CGContextDrawImage(ctx->cgctx, rect, out);
264
265 return ff_filter_frame(link, frame);
266}
267
268/** Apply all valid filters successively to the input image.
269 * The final output image is copied from the GPU by "drawing" using a bitmap context.
270 */
272{
273 return apply_filter(link->dst->priv, link->dst->outputs[0], frame);
274}
275
277{
278 CoreImageContext *ctx = link->src->priv;
279 AVFrame *frame;
280
281 if (ctx->duration >= 0 &&
282 av_rescale_q(ctx->pts, ctx->time_base, AV_TIME_BASE_Q) >= ctx->duration) {
283 return AVERROR_EOF;
284 }
285
286 if (!ctx->picref) {
287 ctx->picref = ff_get_video_buffer(link, ctx->w, ctx->h);
288 if (!ctx->picref) {
289 return AVERROR(ENOMEM);
290 }
291 }
292
293 frame = av_frame_clone(ctx->picref);
294 if (!frame) {
295 return AVERROR(ENOMEM);
296 }
297
298 frame->pts = ctx->pts;
299 frame->duration = 1;
300 frame->flags |= AV_FRAME_FLAG_KEY;
302 frame->pict_type = AV_PICTURE_TYPE_I;
303 frame->sample_aspect_ratio = ctx->sar;
304
305 ctx->pts++;
306
307 return apply_filter(ctx, link, frame);
308}
309
310/** Set an option of the given filter to the provided key-value pair.
311 */
312static void set_option(CoreImageContext *ctx, CIFilter *filter, const char *key, const char *value)
313{
314 NSString *input_key = [NSString stringWithUTF8String:key];
315 NSString *input_val = [NSString stringWithUTF8String:value];
316
317 NSDictionary *filter_attribs = [filter attributes]; // <nsstring, id>
318 NSDictionary *input_attribs = [filter_attribs valueForKey:input_key];
319
320 NSString *input_class = [input_attribs valueForKey:kCIAttributeClass];
321 NSString *input_type = [input_attribs valueForKey:kCIAttributeType];
322
323 if (!input_attribs) {
324 av_log(ctx, AV_LOG_WARNING, "Skipping unknown option: \"%s\".\n",
325 [input_key UTF8String]); // [[filter name] UTF8String]) not currently defined...
326 return;
327 }
328
329 av_log(ctx, AV_LOG_DEBUG, "key: %s, val: %s, #attribs: %lu, class: %s, type: %s\n",
330 [input_key UTF8String],
331 [input_val UTF8String],
332 input_attribs ? (unsigned long)[input_attribs count] : -1,
333 [input_class UTF8String],
334 [input_type UTF8String]);
335
336 if ([input_class isEqualToString:@"NSNumber"]) {
337 float input = input_val.floatValue;
338 NSNumber *max_value = [input_attribs valueForKey:kCIAttributeSliderMax];
339 NSNumber *min_value = [input_attribs valueForKey:kCIAttributeSliderMin];
340 NSNumber *used_value = nil;
341
342#define CLAMP_WARNING do { \
343av_log(ctx, AV_LOG_WARNING, "Value of \"%f\" for option \"%s\" is out of range [%f %f], clamping to \"%f\".\n", \
344 input, \
345 [input_key UTF8String], \
346 min_value.floatValue, \
347 max_value.floatValue, \
348 used_value.floatValue); \
349} while(0)
350 if (input > max_value.floatValue) {
351 used_value = max_value;
353 } else if (input < min_value.floatValue) {
354 used_value = min_value;
356 } else {
357 used_value = [NSNumber numberWithFloat:input];
358 }
359
360 [filter setValue:used_value forKey:input_key];
361 } else if ([input_class isEqualToString:@"CIVector"]) {
362 CIVector *input = [CIVector vectorWithString:input_val];
363
364 if (!input) {
365 av_log(ctx, AV_LOG_WARNING, "Skipping invalid CIVctor description: \"%s\".\n",
366 [input_val UTF8String]);
367 return;
368 }
369
370 [filter setValue:input forKey:input_key];
371 } else if ([input_class isEqualToString:@"CIColor"]) {
372 CIColor *input = [CIColor colorWithString:input_val];
373
374 if (!input) {
375 av_log(ctx, AV_LOG_WARNING, "Skipping invalid CIColor description: \"%s\".\n",
376 [input_val UTF8String]);
377 return;
378 }
379
380 [filter setValue:input forKey:input_key];
381 } else if ([input_class isEqualToString:@"NSString"]) { // set display name as string with latin1 encoding
382 [filter setValue:input_val forKey:input_key];
383 } else if ([input_class isEqualToString:@"NSData"]) { // set display name as string with latin1 encoding
384 NSData *input = [NSData dataWithBytes:(const void*)[input_val cStringUsingEncoding:NSISOLatin1StringEncoding]
385 length:[input_val lengthOfBytesUsingEncoding:NSISOLatin1StringEncoding]];
386
387 if (!input) {
388 av_log(ctx, AV_LOG_WARNING, "Skipping invalid NSData description: \"%s\".\n",
389 [input_val UTF8String]);
390 return;
391 }
392
393 [filter setValue:input forKey:input_key];
394 } else {
395 av_log(ctx, AV_LOG_WARNING, "Skipping unsupported option class: \"%s\".\n",
396 [input_class UTF8String]);
397 avpriv_report_missing_feature(ctx, "Handling of some option classes");
398 return;
399 }
400}
401
402/** Create a filter object by a given name and set all options to defaults.
403 * Overwrite any option given by the user to the provided value in filter_options.
404 */
405static CIFilter* create_filter(CoreImageContext *ctx, const char *filter_name, AVDictionary *filter_options)
406{
407 // create filter object
408 CIFilter *filter = [CIFilter filterWithName:[NSString stringWithUTF8String:filter_name]];
409
410 // set default options
411 [filter setDefaults];
412
413 // set user options
414 if (filter_options) {
415 const AVDictionaryEntry *o = NULL;
416 while ((o = av_dict_iterate(filter_options, o))) {
417 set_option(ctx, filter, o->key, o->value);
418 }
419 }
420
421 return filter;
422}
423
424static av_cold int init(AVFilterContext *fctx)
425{
426 CoreImageContext *ctx = fctx->priv;
427 AVDictionary *filter_dict = NULL;
428 const AVDictionaryEntry *f = NULL;
429 const AVDictionaryEntry *o = NULL;
430 int ret;
431 int i;
432
433 if (ctx->list_filters || ctx->list_generators) {
435 return AVERROR_EXIT;
436 }
437
438 if (ctx->filter_string) {
439 // parse filter string (filter=name@opt=val@opt2=val2#name2@opt3=val3) for filters separated by #
440 av_log(ctx, AV_LOG_DEBUG, "Filter_string: %s\n", ctx->filter_string);
441 ret = av_dict_parse_string(&filter_dict, ctx->filter_string, "@", "#", AV_DICT_MULTIKEY); // parse filter_name:all_filter_options
442 if (ret) {
443 av_dict_free(&filter_dict);
444 av_log(ctx, AV_LOG_ERROR, "Parsing of filters failed.\n");
445 return AVERROR(EIO);
446 }
447 ctx->num_filters = av_dict_count(filter_dict);
448 av_log(ctx, AV_LOG_DEBUG, "Filter count: %i\n", ctx->num_filters);
449
450 // allocate CIFilter array
451 ctx->filters = av_calloc(ctx->num_filters, sizeof(CIFilter*));
452 if (!ctx->filters) {
453 av_log(ctx, AV_LOG_ERROR, "Could not allocate filter array.\n");
454 return AVERROR(ENOMEM);
455 }
456
457 // parse filters for option key-value pairs (opt=val@opt2=val2) separated by @
458 i = 0;
459 while ((f = av_dict_iterate(filter_dict, f))) {
460 AVDictionary *filter_options = NULL;
461
462 if (strncmp(f->value, "default", 7)) { // not default
463 ret = av_dict_parse_string(&filter_options, f->value, "=", "@", 0); // parse option_name:option_value
464 if (ret) {
465 av_dict_free(&filter_options);
466 av_log(ctx, AV_LOG_ERROR, "Parsing of filter options for \"%s\" failed.\n", f->key);
467 return AVERROR(EIO);
468 }
469 }
470
472 av_log(ctx, AV_LOG_DEBUG, "Creating filter %i: \"%s\":\n", i, f->key);
473 if (!filter_options) {
474 av_log(ctx, AV_LOG_DEBUG, "\tusing default options\n");
475 } else {
476 while ((o = av_dict_iterate(filter_options, o))) {
477 av_log(ctx, AV_LOG_DEBUG, "\t%s: %s\n", o->key, o->value);
478 }
479 }
480 }
481
482 ctx->filters[i] = CFBridgingRetain(create_filter(ctx, f->key, filter_options));
483 if (!ctx->filters[i]) {
484 av_log(ctx, AV_LOG_ERROR, "Could not create filter \"%s\".\n", f->key);
485 return AVERROR(EINVAL);
486 }
487
488 i++;
489 }
490 } else {
491 av_log(ctx, AV_LOG_ERROR, "No filters specified.\n");
492 return AVERROR(EINVAL);
493 }
494
495 // create GPU context on OSX
496 const NSOpenGLPixelFormatAttribute attr[] = {
497 NSOpenGLPFAAccelerated,
498 NSOpenGLPFANoRecovery,
499 NSOpenGLPFAColorSize, 32,
500 0
501 };
502
503 NSOpenGLPixelFormat *pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:(void *)&attr];
504 ctx->color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
505 ctx->glctx = CFBridgingRetain([CIContext contextWithCGLContext:CGLGetCurrentContext()
506 pixelFormat:[pixel_format CGLPixelFormatObj]
507 colorSpace:ctx->color_space
508 options:nil]);
509
510 if (!ctx->glctx) {
511 av_log(ctx, AV_LOG_ERROR, "CIContext not created.\n");
512 return AVERROR_EXTERNAL;
513 }
514
515 // Creating an empty input image as input container for the context
516 ctx->input_image = CFBridgingRetain([CIImage emptyImage]);
517
518 return 0;
519}
520
522{
523 CoreImageContext *ctx = fctx->priv;
524
525 ctx->is_video_source = 1;
526 ctx->time_base = av_inv_q(ctx->frame_rate);
527 ctx->pts = 0;
528
529 return init(fctx);
530}
531
533{
534#define SafeCFRelease(ptr) do { \
535 if (ptr) { \
536 CFRelease(ptr); \
537 ptr = NULL; \
538 } \
539} while (0)
540
541 CoreImageContext *ctx = fctx->priv;
542
543 SafeCFRelease(ctx->glctx);
544 SafeCFRelease(ctx->cgctx);
545 SafeCFRelease(ctx->color_space);
546 SafeCFRelease(ctx->input_image);
547
548 if (ctx->filters) {
549 for (int i = 0; i < ctx->num_filters; i++) {
550 SafeCFRelease(ctx->filters[i]);
551 }
552 av_freep(&ctx->filters);
553 }
554
555 av_frame_free(&ctx->picref);
556}
557
559 {
560 .name = "default",
561 .type = AVMEDIA_TYPE_VIDEO,
562 .filter_frame = filter_frame,
563 .config_props = config_input,
564 },
565};
566
568 {
569 .name = "default",
570 .type = AVMEDIA_TYPE_VIDEO,
571 },
572};
573
575 {
576 .name = "default",
577 .type = AVMEDIA_TYPE_VIDEO,
578 .request_frame = request_frame,
579 .config_props = config_output,
580 },
581};
582
583#define OFFSET(x) offsetof(CoreImageContext, x)
584#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
585
586#define GENERATOR_OPTIONS \
587 {"size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0, FLAGS}, \
588 {"s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0, FLAGS}, \
589 {"rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, FLAGS}, \
590 {"r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, FLAGS}, \
591 {"duration", "set video duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS}, \
592 {"d", "set video duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS}, \
593 {"sar", "set video sample aspect ratio", OFFSET(sar), AV_OPT_TYPE_RATIONAL, {.dbl = 1}, 0, INT_MAX, FLAGS},
594
595#define FILTER_OPTIONS \
596 {"list_filters", "list available filters", OFFSET(list_filters), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, .flags = FLAGS}, \
597 {"list_generators", "list available generators", OFFSET(list_generators), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, .flags = FLAGS}, \
598 {"filter", "names and options of filters to apply", OFFSET(filter_string), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = FLAGS}, \
599 {"output_rect", "output rectangle within output image", OFFSET(output_rect), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = FLAGS},
600
601
602// definitions for coreimage video filter
603static const AVOption coreimage_options[] = {
605 { NULL }
606};
607
609
611 .p.name = "coreimage",
612 .p.description = NULL_IF_CONFIG_SMALL("Video filtering using CoreImage API."),
613 .p.priv_class = &coreimage_class,
614 .init = init,
615 .uninit = uninit,
616 .priv_size = sizeof(CoreImageContext),
620};
621
622// definitions for coreimagesrc video source
626 { NULL }
627};
628
630
632 .p.name = "coreimagesrc",
633 .p.description = NULL_IF_CONFIG_SMALL("Video source using image generators of CoreImage API."),
634 .p.priv_class = &coreimagesrc_class,
635 .p.inputs = NULL,
636 .init = init_src,
637 .uninit = uninit,
638 .priv_size = sizeof(CoreImageContext),
641};
static int config_input(AVFilterLink *inlink)
static int request_frame(AVFilterLink *outlink)
Definition af_aecho.c:272
const FFFilter ff_vsrc_coreimagesrc
const FFFilter ff_vf_coreimage
static FILE * out
static AVFormatContext * ctx
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 NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static AVFrame * frame
static int filter_frame(DBEDecodeContext *s, AVFrame *frame)
Definition dolby_e.c:1067
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
double value
Definition eval.c:102
const char * key
static const uint8_t frame_size[4]
Definition g723_1.h:222
#define AV_DICT_MULTIKEY
Allow to store several equal keys in the dictionary.
Definition dict.h:84
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition dict.c:233
const AVDictionaryEntry * av_dict_iterate(const AVDictionary *m, const AVDictionaryEntry *prev)
Iterate over a dictionary.
Definition dict.c:42
int av_dict_parse_string(AVDictionary **pm, const char *str, const char *key_val_sep, const char *pairs_sep, int flags)
Parse the key/value pairs list and add the parsed entries to a dictionary.
Definition dict.c:210
int av_dict_count(const AVDictionary *m)
Get number of entries in dictionary.
Definition dict.c:37
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition error.h:58
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition error.h:59
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
#define AV_FRAME_FLAG_INTERLACED
A flag to mark frames whose content is interlaced.
Definition frame.h:695
#define AV_FRAME_FLAG_KEY
A flag to mark frames that are keyframes.
Definition frame.h:687
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
Definition frame.c:483
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#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
int av_log_get_level(void)
Get the current log level.
Definition log.c:471
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
Definition rational.h:159
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
@ AV_PICTURE_TYPE_I
Intra.
Definition avutil.h:278
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition avutil.h:263
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int config_output(AVBitStreamFilterLink *outlink)
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
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
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
void avpriv_report_missing_feature(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
const char * desc
Definition libsvtav1.c:83
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:264
Memory handling functions.
const char data[16]
Definition mxf.c:149
AVOptions.
int av_get_bits_per_pixel(const AVPixFmtDescriptor *pixdesc)
Return the number of bits per pixel used by the pixel format described by pixdesc.
Definition pixdesc.c:3412
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition pixfmt.h:99
const char * name
Definition qsvenc.c:142
Describe the class of an AVClass context structure.
Definition log.h:76
char * key
Definition dict.h:91
char * value
Definition dict.h:92
An instance of a filter.
Definition avfilter.h:273
void * priv
private data for use by the filter
Definition avfilter.h:288
AVFilterLink ** outputs
array of pointers to output links
Definition avfilter.h:285
A filter pad used for either input or output.
Definition filters.h:40
Format I/O context.
Definition avformat.h:1333
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
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
CGContextRef cgctx
Bitmap context for image copy.
int num_filters
Amount of filters in *filters.
AVRational time_base
stream time base
int is_video_source
filter is used as video source
int64_t pts
increasing presentation time stamp
CFTypeRef glctx
OpenGL context.
int list_filters
Option used to list all available filters including generators.
CGColorSpaceRef color_space
Common color space for input image and cgcontext.
CFTypeRef * filters
CIFilter object for all requested filters.
int bits_per_component
Shared bpc for input-output operation.
CFTypeRef input_image
Input image container for passing into Core Image API.
char * filter_string
The complete user provided filter definition.
AVRational frame_rate
video frame rate
int h
video size
int64_t duration
duration expressed in microseconds
char * output_rect
Rectangle to be filled with filter input.
int list_generators
Option used to list all available generators.
AVFrame * picref
cached reference containing the painted picture
AVRational sar
sample aspect ratio
#define av_freep(p)
#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
static CIFilter * create_filter(CoreImageContext *ctx, const char *filter_name, AVDictionary *filter_options)
Create a filter object by a given name and set all options to defaults.
static void set_option(CoreImageContext *ctx, CIFilter *filter, const char *key, const char *value)
Set an option of the given filter to the provided key-value pair.
static const AVFilterPad vf_coreimage_inputs[]
static av_cold int init_src(AVFilterContext *fctx)
static const AVOption coreimage_options[]
static void list_filters(CoreImageContext *ctx)
Print a list of all available filters including options and respective value ranges and defaults.
static const AVFilterPad vsrc_coreimagesrc_outputs[]
static const AVFilterPad vf_coreimage_outputs[]
static int request_frame(AVFilterLink *link)
#define SafeCFRelease(ptr)
#define CLAMP_WARNING
static int filter_frame(AVFilterLink *link, AVFrame *frame)
Apply all valid filters successively to the input image.
static int config_input(AVFilterLink *link)
Determine image properties from input link of filter chain.
#define FILTER_OPTIONS
#define GENERATOR_OPTIONS
static int config_output(AVFilterLink *link)
static const AVOption coreimagesrc_options[]
static int apply_filter(CoreImageContext *ctx, AVFilterLink *link, AVFrame *frame)
static av_cold void uninit(AVFilterContext *fctx)
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition video.c:89