FFmpeg
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 
38 typedef 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 intput
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 
67 {
69  CoreImageContext *ctx = link->src->priv;
70 
71  link->w = ctx->w;
72  link->h = ctx->h;
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  */
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  NSArray *filter_names = [CIFilter filterNamesInCategories:filter_categories];
106  NSEnumerator *filters = [filter_names objectEnumerator];
107 
108  NSString *filter_name;
109  while (filter_name = [filters nextObject]) {
110  av_log(ctx, AV_LOG_INFO, "Filter: %s\n", [filter_name UTF8String]);
111  NSString *input;
112 
113  CIFilter *filter = [CIFilter filterWithName:filter_name];
114  NSDictionary *filter_attribs = [filter attributes]; // <nsstring, id>
115  NSArray *filter_inputs = [filter inputKeys]; // <nsstring>
116 
117  for (input in filter_inputs) {
118  NSDictionary *input_attribs = [filter_attribs valueForKey:input];
119  NSString *input_class = [input_attribs valueForKey:kCIAttributeClass];
120  if ([input_class isEqualToString:@"NSNumber"]) {
121  NSNumber *value_default = [input_attribs valueForKey:kCIAttributeDefault];
122  NSNumber *value_min = [input_attribs valueForKey:kCIAttributeSliderMin];
123  NSNumber *value_max = [input_attribs valueForKey:kCIAttributeSliderMax];
124 
125  av_log(ctx, AV_LOG_INFO, "\tOption: %s\t[%s]\t[%s %s][%s]\n",
126  [input UTF8String],
127  [input_class UTF8String],
128  [[value_min stringValue] UTF8String],
129  [[value_max stringValue] UTF8String],
130  [[value_default stringValue] UTF8String]);
131  } else {
132  av_log(ctx, AV_LOG_INFO, "\tOption: %s\t[%s]\n",
133  [input UTF8String],
134  [input_class UTF8String]);
135  }
136  }
137  }
138 }
139 
141 {
142  int i;
143 
144  // (re-)initialize input image
145  const CGSize frame_size = {
146  frame->width,
147  frame->height
148  };
149 
150  NSData *data = [NSData dataWithBytesNoCopy:frame->data[0]
151  length:frame->height*frame->linesize[0]
152  freeWhenDone:NO];
153 
154  CIImage *ret = [(__bridge CIImage*)ctx->input_image initWithBitmapData:data
155  bytesPerRow:frame->linesize[0]
156  size:frame_size
157  format:kCIFormatARGB8
158  colorSpace:ctx->color_space]; //kCGColorSpaceGenericRGB
159  if (!ret) {
160  av_log(ctx, AV_LOG_ERROR, "Input image could not be initialized.\n");
161  return AVERROR_EXTERNAL;
162  }
163 
164  CIFilter *filter = NULL;
165  CIImage *filter_input = (__bridge CIImage*)ctx->input_image;
166  CIImage *filter_output = NULL;
167 
168  // successively apply all filters
169  for (i = 0; i < ctx->num_filters; i++) {
170  if (i) {
171  // set filter input to previous filter output
172  filter_input = [(__bridge CIImage*)ctx->filters[i-1] valueForKey:kCIOutputImageKey];
173  CGRect out_rect = [filter_input extent];
174  if (out_rect.size.width > frame->width || out_rect.size.height > frame->height) {
175  // do not keep padded image regions after filtering
176  out_rect.origin.x = 0.0f;
177  out_rect.origin.y = 0.0f;
178  out_rect.size.width = frame->width;
179  out_rect.size.height = frame->height;
180  }
181  filter_input = [filter_input imageByCroppingToRect:out_rect];
182  }
183 
184  filter = (__bridge CIFilter*)ctx->filters[i];
185 
186  // do not set input image for the first filter if used as video source
187  if (!ctx->is_video_source || i) {
188  @try {
189  [filter setValue:filter_input forKey:kCIInputImageKey];
190  } @catch (NSException *exception) {
191  if (![[exception name] isEqualToString:NSUndefinedKeyException]) {
192  av_log(ctx, AV_LOG_ERROR, "An error occurred: %s.", [exception.reason UTF8String]);
193  return AVERROR_EXTERNAL;
194  } else {
195  av_log(ctx, AV_LOG_WARNING, "Selected filter does not accept an input image.\n");
196  }
197  }
198  }
199  }
200 
201  // get output of last filter
202  filter_output = [filter valueForKey:kCIOutputImageKey];
203 
204  if (!filter_output) {
205  av_log(ctx, AV_LOG_ERROR, "Filter output not available.\n");
206  return AVERROR_EXTERNAL;
207  }
208 
209  // do not keep padded image regions after filtering
210  CGRect out_rect = [filter_output extent];
211  if (out_rect.size.width > frame->width || out_rect.size.height > frame->height) {
212  av_log(ctx, AV_LOG_DEBUG, "Cropping output image.\n");
213  out_rect.origin.x = 0.0f;
214  out_rect.origin.y = 0.0f;
215  out_rect.size.width = frame->width;
216  out_rect.size.height = frame->height;
217  }
218 
219  CGImageRef out = [(__bridge CIContext*)ctx->glctx createCGImage:filter_output
220  fromRect:out_rect];
221 
222  if (!out) {
223  av_log(ctx, AV_LOG_ERROR, "Cannot create valid output image.\n");
224  }
225 
226  // create bitmap context on the fly for rendering into current frame->data[]
227  if (ctx->cgctx) {
228  CGContextRelease(ctx->cgctx);
229  ctx->cgctx = NULL;
230  }
231  size_t out_width = CGImageGetWidth(out);
232  size_t out_height = CGImageGetHeight(out);
233 
234  if (out_width > frame->width || out_height > frame->height) { // this might result in segfault
235  av_log(ctx, AV_LOG_WARNING, "Output image has unexpected size: %lux%lu (expected: %ix%i). This may crash...\n",
236  out_width, out_height, frame->width, frame->height);
237  }
238  ctx->cgctx = CGBitmapContextCreate(frame->data[0],
239  frame->width,
240  frame->height,
241  ctx->bits_per_component,
242  frame->linesize[0],
243  ctx->color_space,
244  (uint32_t)kCGImageAlphaPremultipliedFirst); // ARGB
245  if (!ctx->cgctx) {
246  av_log(ctx, AV_LOG_ERROR, "CGBitmap context cannot be created.\n");
247  return AVERROR_EXTERNAL;
248  }
249 
250  // copy ("draw") the output image into the frame data
251  CGRect rect = {{0,0},{frame->width, frame->height}};
252  if (ctx->output_rect) {
253  @try {
254  NSString *tmp_string = [NSString stringWithUTF8String:ctx->output_rect];
255  NSRect tmp = NSRectFromString(tmp_string);
256  rect = NSRectToCGRect(tmp);
257  } @catch (NSException *exception) {
258  av_log(ctx, AV_LOG_ERROR, "An error occurred: %s.", [exception.reason UTF8String]);
259  return AVERROR_EXTERNAL;
260  }
261  if (rect.size.width == 0.0f) {
262  av_log(ctx, AV_LOG_WARNING, "Width of output rect is zero.\n");
263  }
264  if (rect.size.height == 0.0f) {
265  av_log(ctx, AV_LOG_WARNING, "Height of output rect is zero.\n");
266  }
267  }
268 
269  CGContextDrawImage(ctx->cgctx, rect, out);
270 
271  return ff_filter_frame(link, frame);
272 }
273 
274 /** Apply all valid filters successively to the input image.
275  * The final output image is copied from the GPU by "drawing" using a bitmap context.
276  */
278 {
279  return apply_filter(link->dst->priv, link->dst->outputs[0], frame);
280 }
281 
283 {
284  CoreImageContext *ctx = link->src->priv;
285  AVFrame *frame;
286 
287  if (ctx->duration >= 0 &&
288  av_rescale_q(ctx->pts, ctx->time_base, AV_TIME_BASE_Q) >= ctx->duration) {
289  return AVERROR_EOF;
290  }
291 
292  if (!ctx->picref) {
293  ctx->picref = ff_get_video_buffer(link, ctx->w, ctx->h);
294  if (!ctx->picref) {
295  return AVERROR(ENOMEM);
296  }
297  }
298 
299  frame = av_frame_clone(ctx->picref);
300  if (!frame) {
301  return AVERROR(ENOMEM);
302  }
303 
304  frame->pts = ctx->pts;
305  frame->duration = 1;
306 #if FF_API_FRAME_KEY
307  frame->key_frame = 1;
308 #endif
309  frame->flags |= AV_FRAME_FLAG_KEY;
310 #if FF_API_INTERLACED_FRAME
311  frame->interlaced_frame = 0;
312 #endif
313  frame->flags &= ~AV_FRAME_FLAG_INTERLACED;
314  frame->pict_type = AV_PICTURE_TYPE_I;
315  frame->sample_aspect_ratio = ctx->sar;
316 
317  ctx->pts++;
318 
319  return apply_filter(ctx, link, frame);
320 }
321 
322 /** Set an option of the given filter to the provided key-value pair.
323  */
324 static void set_option(CoreImageContext *ctx, CIFilter *filter, const char *key, const char *value)
325 {
326  NSString *input_key = [NSString stringWithUTF8String:key];
327  NSString *input_val = [NSString stringWithUTF8String:value];
328 
329  NSDictionary *filter_attribs = [filter attributes]; // <nsstring, id>
330  NSDictionary *input_attribs = [filter_attribs valueForKey:input_key];
331 
332  NSString *input_class = [input_attribs valueForKey:kCIAttributeClass];
333  NSString *input_type = [input_attribs valueForKey:kCIAttributeType];
334 
335  if (!input_attribs) {
336  av_log(ctx, AV_LOG_WARNING, "Skipping unknown option: \"%s\".\n",
337  [input_key UTF8String]); // [[filter name] UTF8String]) not currently defined...
338  return;
339  }
340 
341  av_log(ctx, AV_LOG_DEBUG, "key: %s, val: %s, #attribs: %lu, class: %s, type: %s\n",
342  [input_key UTF8String],
343  [input_val UTF8String],
344  input_attribs ? (unsigned long)[input_attribs count] : -1,
345  [input_class UTF8String],
346  [input_type UTF8String]);
347 
348  if ([input_class isEqualToString:@"NSNumber"]) {
349  float input = input_val.floatValue;
350  NSNumber *max_value = [input_attribs valueForKey:kCIAttributeSliderMax];
351  NSNumber *min_value = [input_attribs valueForKey:kCIAttributeSliderMin];
352  NSNumber *used_value = nil;
353 
354 #define CLAMP_WARNING do { \
355 av_log(ctx, AV_LOG_WARNING, "Value of \"%f\" for option \"%s\" is out of range [%f %f], clamping to \"%f\".\n", \
356  input, \
357  [input_key UTF8String], \
358  min_value.floatValue, \
359  max_value.floatValue, \
360  used_value.floatValue); \
361 } while(0)
362  if (input > max_value.floatValue) {
363  used_value = max_value;
365  } else if (input < min_value.floatValue) {
366  used_value = min_value;
368  } else {
369  used_value = [NSNumber numberWithFloat:input];
370  }
371 
372  [filter setValue:used_value forKey:input_key];
373  } else if ([input_class isEqualToString:@"CIVector"]) {
374  CIVector *input = [CIVector vectorWithString:input_val];
375 
376  if (!input) {
377  av_log(ctx, AV_LOG_WARNING, "Skipping invalid CIVctor description: \"%s\".\n",
378  [input_val UTF8String]);
379  return;
380  }
381 
382  [filter setValue:input forKey:input_key];
383  } else if ([input_class isEqualToString:@"CIColor"]) {
384  CIColor *input = [CIColor colorWithString:input_val];
385 
386  if (!input) {
387  av_log(ctx, AV_LOG_WARNING, "Skipping invalid CIColor description: \"%s\".\n",
388  [input_val UTF8String]);
389  return;
390  }
391 
392  [filter setValue:input forKey:input_key];
393  } else if ([input_class isEqualToString:@"NSString"]) { // set display name as string with latin1 encoding
394  [filter setValue:input_val forKey:input_key];
395  } else if ([input_class isEqualToString:@"NSData"]) { // set display name as string with latin1 encoding
396  NSData *input = [NSData dataWithBytes:(const void*)[input_val cStringUsingEncoding:NSISOLatin1StringEncoding]
397  length:[input_val lengthOfBytesUsingEncoding:NSISOLatin1StringEncoding]];
398 
399  if (!input) {
400  av_log(ctx, AV_LOG_WARNING, "Skipping invalid NSData description: \"%s\".\n",
401  [input_val UTF8String]);
402  return;
403  }
404 
405  [filter setValue:input forKey:input_key];
406  } else {
407  av_log(ctx, AV_LOG_WARNING, "Skipping unsupported option class: \"%s\".\n",
408  [input_class UTF8String]);
409  avpriv_report_missing_feature(ctx, "Handling of some option classes");
410  return;
411  }
412 }
413 
414 /** Create a filter object by a given name and set all options to defaults.
415  * Overwrite any option given by the user to the provided value in filter_options.
416  */
417 static CIFilter* create_filter(CoreImageContext *ctx, const char *filter_name, AVDictionary *filter_options)
418 {
419  // create filter object
420  CIFilter *filter = [CIFilter filterWithName:[NSString stringWithUTF8String:filter_name]];
421 
422  // set default options
423  [filter setDefaults];
424 
425  // set user options
426  if (filter_options) {
427  const AVDictionaryEntry *o = NULL;
428  while ((o = av_dict_iterate(filter_options, o))) {
429  set_option(ctx, filter, o->key, o->value);
430  }
431  }
432 
433  return filter;
434 }
435 
436 static av_cold int init(AVFilterContext *fctx)
437 {
438  CoreImageContext *ctx = fctx->priv;
439  AVDictionary *filter_dict = NULL;
440  const AVDictionaryEntry *f = NULL;
441  const AVDictionaryEntry *o = NULL;
442  int ret;
443  int i;
444 
445  if (ctx->list_filters || ctx->list_generators) {
446  list_filters(ctx);
447  return AVERROR_EXIT;
448  }
449 
450  if (ctx->filter_string) {
451  // parse filter string (filter=name@opt=val@opt2=val2#name2@opt3=val3) for filters separated by #
452  av_log(ctx, AV_LOG_DEBUG, "Filter_string: %s\n", ctx->filter_string);
453  ret = av_dict_parse_string(&filter_dict, ctx->filter_string, "@", "#", AV_DICT_MULTIKEY); // parse filter_name:all_filter_options
454  if (ret) {
455  av_dict_free(&filter_dict);
456  av_log(ctx, AV_LOG_ERROR, "Parsing of filters failed.\n");
457  return AVERROR(EIO);
458  }
459  ctx->num_filters = av_dict_count(filter_dict);
460  av_log(ctx, AV_LOG_DEBUG, "Filter count: %i\n", ctx->num_filters);
461 
462  // allocate CIFilter array
463  ctx->filters = av_calloc(ctx->num_filters, sizeof(CIFilter*));
464  if (!ctx->filters) {
465  av_log(ctx, AV_LOG_ERROR, "Could not allocate filter array.\n");
466  return AVERROR(ENOMEM);
467  }
468 
469  // parse filters for option key-value pairs (opt=val@opt2=val2) separated by @
470  i = 0;
471  while ((f = av_dict_iterate(filter_dict, f))) {
472  AVDictionary *filter_options = NULL;
473 
474  if (strncmp(f->value, "default", 7)) { // not default
475  ret = av_dict_parse_string(&filter_options, f->value, "=", "@", 0); // parse option_name:option_value
476  if (ret) {
477  av_dict_free(&filter_options);
478  av_log(ctx, AV_LOG_ERROR, "Parsing of filter options for \"%s\" failed.\n", f->key);
479  return AVERROR(EIO);
480  }
481  }
482 
483  if (av_log_get_level() >= AV_LOG_DEBUG) {
484  av_log(ctx, AV_LOG_DEBUG, "Creating filter %i: \"%s\":\n", i, f->key);
485  if (!filter_options) {
486  av_log(ctx, AV_LOG_DEBUG, "\tusing default options\n");
487  } else {
488  while ((o = av_dict_iterate(filter_options, o))) {
489  av_log(ctx, AV_LOG_DEBUG, "\t%s: %s\n", o->key, o->value);
490  }
491  }
492  }
493 
494  ctx->filters[i] = CFBridgingRetain(create_filter(ctx, f->key, filter_options));
495  if (!ctx->filters[i]) {
496  av_log(ctx, AV_LOG_ERROR, "Could not create filter \"%s\".\n", f->key);
497  return AVERROR(EINVAL);
498  }
499 
500  i++;
501  }
502  } else {
503  av_log(ctx, AV_LOG_ERROR, "No filters specified.\n");
504  return AVERROR(EINVAL);
505  }
506 
507  // create GPU context on OSX
508  const NSOpenGLPixelFormatAttribute attr[] = {
509  NSOpenGLPFAAccelerated,
510  NSOpenGLPFANoRecovery,
511  NSOpenGLPFAColorSize, 32,
512  0
513  };
514 
515  NSOpenGLPixelFormat *pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:(void *)&attr];
516  ctx->color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
517  ctx->glctx = CFBridgingRetain([CIContext contextWithCGLContext:CGLGetCurrentContext()
518  pixelFormat:[pixel_format CGLPixelFormatObj]
519  colorSpace:ctx->color_space
520  options:nil]);
521 
522  if (!ctx->glctx) {
523  av_log(ctx, AV_LOG_ERROR, "CIContext not created.\n");
524  return AVERROR_EXTERNAL;
525  }
526 
527  // Creating an empty input image as input container for the context
528  ctx->input_image = CFBridgingRetain([CIImage emptyImage]);
529 
530  return 0;
531 }
532 
534 {
535  CoreImageContext *ctx = fctx->priv;
536 
537  ctx->is_video_source = 1;
538  ctx->time_base = av_inv_q(ctx->frame_rate);
539  ctx->pts = 0;
540 
541  return init(fctx);
542 }
543 
544 static av_cold void uninit(AVFilterContext *fctx)
545 {
546 #define SafeCFRelease(ptr) do { \
547  if (ptr) { \
548  CFRelease(ptr); \
549  ptr = NULL; \
550  } \
551 } while (0)
552 
553  CoreImageContext *ctx = fctx->priv;
554 
555  SafeCFRelease(ctx->glctx);
556  SafeCFRelease(ctx->cgctx);
557  SafeCFRelease(ctx->color_space);
558  SafeCFRelease(ctx->input_image);
559 
560  if (ctx->filters) {
561  for (int i = 0; i < ctx->num_filters; i++) {
562  SafeCFRelease(ctx->filters[i]);
563  }
564  av_freep(&ctx->filters);
565  }
566 
567  av_frame_free(&ctx->picref);
568 }
569 
571  {
572  .name = "default",
573  .type = AVMEDIA_TYPE_VIDEO,
574  .filter_frame = filter_frame,
575  .config_props = config_input,
576  },
577 };
578 
580  {
581  .name = "default",
582  .type = AVMEDIA_TYPE_VIDEO,
583  },
584 };
585 
587  {
588  .name = "default",
589  .type = AVMEDIA_TYPE_VIDEO,
590  .request_frame = request_frame,
591  .config_props = config_output,
592  },
593 };
594 
595 #define OFFSET(x) offsetof(CoreImageContext, x)
596 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
597 
598 #define GENERATOR_OPTIONS \
599  {"size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0, FLAGS}, \
600  {"s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0, FLAGS}, \
601  {"rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, FLAGS}, \
602  {"r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, FLAGS}, \
603  {"duration", "set video duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS}, \
604  {"d", "set video duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS}, \
605  {"sar", "set video sample aspect ratio", OFFSET(sar), AV_OPT_TYPE_RATIONAL, {.dbl = 1}, 0, INT_MAX, FLAGS},
606 
607 #define FILTER_OPTIONS \
608  {"list_filters", "list available filters", OFFSET(list_filters), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, .flags = FLAGS}, \
609  {"list_generators", "list available generators", OFFSET(list_generators), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, .flags = FLAGS}, \
610  {"filter", "names and options of filters to apply", OFFSET(filter_string), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = FLAGS}, \
611  {"output_rect", "output rectangle within output image", OFFSET(output_rect), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = FLAGS},
612 
613 
614 // definitions for coreimage video filter
615 static const AVOption coreimage_options[] = {
617  { NULL }
618 };
619 
620 AVFILTER_DEFINE_CLASS(coreimage);
621 
623  .name = "coreimage",
624  .description = NULL_IF_CONFIG_SMALL("Video filtering using CoreImage API."),
625  .init = init,
626  .uninit = uninit,
627  .priv_size = sizeof(CoreImageContext),
628  .priv_class = &coreimage_class,
632 };
633 
634 // definitions for coreimagesrc video source
635 static const AVOption coreimagesrc_options[] = {
638  { NULL }
639 };
640 
641 AVFILTER_DEFINE_CLASS(coreimagesrc);
642 
644  .name = "coreimagesrc",
645  .description = NULL_IF_CONFIG_SMALL("Video source using image generators of CoreImage API."),
646  .init = init_src,
647  .uninit = uninit,
648  .priv_size = sizeof(CoreImageContext),
649  .priv_class = &coreimagesrc_class,
650  .inputs = NULL,
653 };
ff_vsrc_coreimagesrc
const AVFilter ff_vsrc_coreimagesrc
Definition: vf_coreimage.m:643
ff_get_video_buffer
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:116
CoreImageContext::glctx
CFTypeRef glctx
OpenGL context.
Definition: vf_coreimage.m:51
CoreImageContext::w
int w
Definition: vf_coreimage.m:43
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
name
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
CoreImageContext::duration
int64_t duration
duration expressed in microseconds
Definition: vf_coreimage.m:47
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
out
FILE * out
Definition: movenc.c:55
CoreImageContext::cgctx
CGContextRef cgctx
Bitmap context for image copy.
Definition: vf_coreimage.m:52
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1023
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2965
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
av_dict_count
int av_dict_count(const AVDictionary *m)
Get number of entries in dictionary.
Definition: dict.c:39
rect
Definition: f_ebur128.c:76
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(coreimage)
AV_TIME_BASE_Q
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition: avutil.h:264
int64_t
long long int64_t
Definition: coverity.c:34
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:162
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: filters.h:262
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:389
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:28
pixdesc.h
AVOption
AVOption.
Definition: opt.h:429
create_filter
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.
Definition: vf_coreimage.m:417
data
const char data[16]
Definition: mxf.c:148
CoreImageContext::color_space
CGColorSpaceRef color_space
Common color space for input image and cgcontext.
Definition: vf_coreimage.m:54
vf_coreimage_outputs
static const AVFilterPad vf_coreimage_outputs[]
Definition: vf_coreimage.m:579
filter
void(* filter)(uint8_t *src, int stride, int qscale)
Definition: h263dsp.c:29
av_get_bits_per_pixel
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:2917
AVDictionary
Definition: dict.c:34
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:205
coreimage_options
static const AVOption coreimage_options[]
Definition: vf_coreimage.m:615
video.h
CoreImageContext
Definition: vf_coreimage.m:38
formats.h
ff_vf_coreimage
const AVFilter ff_vf_coreimage
Definition: vf_coreimage.m:622
filter_frame
static int filter_frame(AVFilterLink *link, AVFrame *frame)
Apply all valid filters successively to the input image.
Definition: vf_coreimage.m:277
CLAMP_WARNING
#define CLAMP_WARNING
AVFilterContext::priv
void * priv
private data for use by the filter
Definition: avfilter.h:472
vsrc_coreimagesrc_outputs
static const AVFilterPad vsrc_coreimagesrc_outputs[]
Definition: vf_coreimage.m:586
request_frame
static int request_frame(AVFilterLink *link)
Definition: vf_coreimage.m:282
init
static av_cold int init(AVFilterContext *fctx)
Definition: vf_coreimage.m:436
AVFilterPad
A filter pad used for either input or output.
Definition: filters.h:38
config_output
static int config_output(AVFilterLink *link)
Definition: vf_coreimage.m:66
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
av_cold
#define av_cold
Definition: attributes.h:90
AV_FRAME_FLAG_KEY
#define AV_FRAME_FLAG_KEY
A flag to mark frames that are keyframes.
Definition: frame.h:640
CoreImageContext::picref
AVFrame * picref
cached reference containing the painted picture
Definition: vf_coreimage.m:49
AVDictionaryEntry::key
char * key
Definition: dict.h:90
frame_size
int frame_size
Definition: mxfenc.c:2424
FILTER_OPTIONS
#define FILTER_OPTIONS
Definition: vf_coreimage.m:607
filters
#define filters(fmt, type, inverse, clp, inverset, clip, one, clip_fn, packed)
Definition: af_crystalizer.c:55
CoreImageContext::h
int h
video size
Definition: vf_coreimage.m:43
filters.h
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
ctx
AVFormatContext * ctx
Definition: movenc.c:49
av_frame_clone
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
Definition: frame.c:597
av_rescale_q
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:142
CoreImageContext::time_base
AVRational time_base
stream time base
Definition: vf_coreimage.m:46
key
const char * key
Definition: hwcontext_opencl.c:189
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: filters.h:263
link
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a link
Definition: filter_design.txt:23
if
if(ret)
Definition: filter_design.txt:179
config_input
static int config_input(AVFilterLink *link)
Determine image properties from input link of filter chain.
Definition: vf_coreimage.m:85
av_log_get_level
int av_log_get_level(void)
Get the current log level.
Definition: log.c:442
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
NULL
#define NULL
Definition: coverity.c:32
AV_DICT_MULTIKEY
#define AV_DICT_MULTIKEY
Allow to store several equal keys in the dictionary.
Definition: dict.h:84
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
CoreImageContext::filters
CFTypeRef * filters
CIFilter object for all requested filters.
Definition: vf_coreimage.m:58
CoreImageContext::bits_per_component
int bits_per_component
Shared bpc for input-output operation.
Definition: vf_coreimage.m:55
AV_PICTURE_TYPE_I
@ AV_PICTURE_TYPE_I
Intra.
Definition: avutil.h:279
inputs
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
Definition: filter_design.txt:243
ff_filter_link
static FilterLink * ff_filter_link(AVFilterLink *link)
Definition: filters.h:197
CoreImageContext::pts
int64_t pts
increasing presentation time stamp
Definition: vf_coreimage.m:48
options
const OptionDef options[]
f
f
Definition: af_crystalizer.c:122
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:94
CoreImageContext::sar
AVRational sar
sample aspect ratio
Definition: vf_coreimage.m:44
CoreImageContext::input_image
CFTypeRef input_image
Input image container for passing into Core Image API.
Definition: vf_coreimage.m:53
for
for(k=2;k<=8;++k)
Definition: h264pred_template.c:425
avpriv_report_missing_feature
void avpriv_report_missing_feature(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
AVFrame::time_base
AVRational time_base
Time base for the timestamps in this frame.
Definition: frame.h:516
AVFrame::format
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition: frame.h:476
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
av_dict_free
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition: dict.c:223
input
and forward the test the status of outputs and forward it to the corresponding return FFERROR_NOT_READY If the filters stores internally one or a few frame for some input
Definition: filter_design.txt:172
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
AV_PIX_FMT_ARGB
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition: pixfmt.h:99
list_filters
static void list_filters(CoreImageContext *ctx)
Print a list of all available filters including options and respective value ranges and defaults.
Definition: vf_coreimage.m:96
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
coreimagesrc_options
static const AVOption coreimagesrc_options[]
Definition: vf_coreimage.m:635
internal.h
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
av_inv_q
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
Definition: rational.h:159
CoreImageContext::filter_string
char * filter_string
The complete user provided filter definition.
Definition: vf_coreimage.m:57
AVFilterPad::name
const char * name
Pad name.
Definition: filters.h:44
set_option
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.
Definition: vf_coreimage.m:324
AV_FRAME_FLAG_INTERLACED
#define AV_FRAME_FLAG_INTERLACED
A flag to mark frames whose content is interlaced.
Definition: frame.h:648
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:264
CoreImageContext::frame_rate
AVRational frame_rate
video frame rate
Definition: vf_coreimage.m:45
AVFilter
Filter definition.
Definition: avfilter.h:201
ret
ret
Definition: filter_design.txt:187
CoreImageContext::output_rect
char * output_rect
Rectangle to be filled with filter intput.
Definition: vf_coreimage.m:61
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
AVFrame::sample_aspect_ratio
AVRational sample_aspect_ratio
Sample aspect ratio for the video frame, 0/1 if unknown/unspecified.
Definition: frame.h:496
CoreImageContext::num_filters
int num_filters
Amount of filters in *filters.
Definition: vf_coreimage.m:59
CoreImageContext::list_generators
int list_generators
Option used to list all available generators.
Definition: vf_coreimage.m:63
init_src
static av_cold int init_src(AVFilterContext *fctx)
Definition: vf_coreimage.m:533
avfilter.h
av_dict_parse_string
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:200
CoreImageContext::is_video_source
int is_video_source
filter is used as video source
Definition: vf_coreimage.m:41
apply_filter
static int apply_filter(CoreImageContext *ctx, AVFilterLink *link, AVFrame *frame)
Definition: vf_coreimage.m:140
AVFormatContext::duration
int64_t duration
Duration of the stream, in AV_TIME_BASE fractional seconds.
Definition: avformat.h:1422
AVFilterContext
An instance of a filter.
Definition: avfilter.h:457
desc
const char * desc
Definition: libsvtav1.c:79
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
uninit
static av_cold void uninit(AVFilterContext *fctx)
Definition: vf_coreimage.m:544
mem.h
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
AVDictionaryEntry
Definition: dict.h:89
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
vf_coreimage_inputs
static const AVFilterPad vf_coreimage_inputs[]
Definition: vf_coreimage.m:570
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
GENERATOR_OPTIONS
#define GENERATOR_OPTIONS
Definition: vf_coreimage.m:598
AVERROR_EXIT
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition: error.h:58
SafeCFRelease
#define SafeCFRelease(ptr)
AVDictionaryEntry::value
char * value
Definition: dict.h:91
FILTER_SINGLE_PIXFMT
#define FILTER_SINGLE_PIXFMT(pix_fmt_)
Definition: filters.h:252
av_dict_iterate
const AVDictionaryEntry * av_dict_iterate(const AVDictionary *m, const AVDictionaryEntry *prev)
Iterate over a dictionary.
Definition: dict.c:44
CoreImageContext::list_filters
int list_filters
Option used to list all available filters including generators.
Definition: vf_coreimage.m:62