26#import <CoreImage/CoreImage.h>
27#import <AppKit/AppKit.h>
99 NSArray *filter_categories = nil;
101 if (
ctx->list_generators && !
ctx->list_filters) {
102 filter_categories = [NSArray arrayWithObjects:kCICategoryGenerator, nil];
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];
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];
121 [input_class UTF8String],
122 [[value_min stringValue] UTF8String],
123 [[value_max stringValue] UTF8String],
124 [[value_default stringValue] UTF8String]);
128 [input_class UTF8String]);
144 NSData *
data = [NSData dataWithBytesNoCopy:frame->data[0]
145 length:frame->height*frame->linesize[0]
148 CIImage *ret = [(__bridge CIImage*)
ctx->input_image initWithBitmapData:data
149 bytesPerRow:frame->linesize[0]
151 format:kCIFormatARGB8
152 colorSpace:ctx->color_space];
159 CIImage *filter_input = (__bridge CIImage*)
ctx->input_image;
160 CIImage *filter_output =
NULL;
163 for (
i = 0;
i <
ctx->num_filters;
i++) {
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) {
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;
175 filter_input = [filter_input imageByCroppingToRect:out_rect];
181 if (!
ctx->is_video_source ||
i) {
183 [filter setValue:filter_input forKey:kCIInputImageKey];
184 }
@catch (NSException *exception) {
185 if (![[exception
name] isEqualToString:NSUndefinedKeyException]) {
196 filter_output = [filter valueForKey:kCIOutputImageKey];
198 if (!filter_output) {
204 CGRect out_rect = [filter_output extent];
205 if (out_rect.size.width >
frame->width || out_rect.size.height >
frame->height) {
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;
213 CGImageRef
out = [(__bridge CIContext*)
ctx->glctx createCGImage:filter_output
222 CGContextRelease(
ctx->cgctx);
225 size_t out_width = CGImageGetWidth(
out);
226 size_t out_height = CGImageGetHeight(
out);
228 if (out_width >
frame->width || out_height >
frame->height) {
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);
232 ctx->cgctx = CGBitmapContextCreate(
frame->data[0],
235 ctx->bits_per_component,
238 (uint32_t)kCGImageAlphaPremultipliedFirst);
246 if (
ctx->output_rect) {
248 NSString *tmp_string = [NSString stringWithUTF8String:ctx->output_rect];
249 NSRect
tmp = NSRectFromString(tmp_string);
251 }
@catch (NSException *exception) {
255 if (
rect.size.width == 0.0f) {
258 if (
rect.size.height == 0.0f) {
281 if (
ctx->duration >= 0 &&
303 frame->sample_aspect_ratio =
ctx->sar;
314 NSString *input_key = [NSString stringWithUTF8String:key];
315 NSString *input_val = [NSString stringWithUTF8String:value];
317 NSDictionary *filter_attribs = [filter attributes];
318 NSDictionary *input_attribs = [filter_attribs valueForKey:input_key];
320 NSString *input_class = [input_attribs valueForKey:kCIAttributeClass];
321 NSString *input_type = [input_attribs valueForKey:kCIAttributeType];
323 if (!input_attribs) {
325 [input_key UTF8String]);
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]);
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;
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", \
345 [input_key UTF8String], \
346 min_value.floatValue, \
347 max_value.floatValue, \
348 used_value.floatValue); \
350 if (input > max_value.floatValue) {
351 used_value = max_value;
353 }
else if (input < min_value.floatValue) {
354 used_value = min_value;
357 used_value = [NSNumber numberWithFloat:input];
360 [filter setValue:used_value forKey:input_key];
361 }
else if ([input_class isEqualToString:
@"CIVector"]) {
362 CIVector *input = [CIVector vectorWithString:input_val];
366 [input_val UTF8String]);
370 [filter setValue:input forKey:input_key];
371 }
else if ([input_class isEqualToString:
@"CIColor"]) {
372 CIColor *input = [CIColor colorWithString:input_val];
376 [input_val UTF8String]);
380 [filter setValue:input forKey:input_key];
381 }
else if ([input_class isEqualToString:
@"NSString"]) {
382 [filter setValue:input_val forKey:input_key];
383 }
else if ([input_class isEqualToString:
@"NSData"]) {
384 NSData *input = [NSData dataWithBytes:(const void*)[input_val cStringUsingEncoding:NSISOLatin1StringEncoding]
385 length:[input_val lengthOfBytesUsingEncoding:NSISOLatin1StringEncoding]];
389 [input_val UTF8String]);
393 [filter setValue:input forKey:input_key];
396 [input_class UTF8String]);
408 CIFilter *
filter = [CIFilter filterWithName:[NSString stringWithUTF8String:filter_name]];
411 [filter setDefaults];
414 if (filter_options) {
433 if (
ctx->list_filters ||
ctx->list_generators) {
438 if (
ctx->filter_string) {
462 if (strncmp(
f->value,
"default", 7)) {
473 if (!filter_options) {
483 if (!
ctx->filters[
i]) {
496 const NSOpenGLPixelFormatAttribute attr[] = {
497 NSOpenGLPFAAccelerated,
498 NSOpenGLPFANoRecovery,
499 NSOpenGLPFAColorSize, 32,
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
516 ctx->input_image = CFBridgingRetain([CIImage emptyImage]);
525 ctx->is_video_source = 1;
534#define SafeCFRelease(ptr) do { \
549 for (
int i = 0;
i <
ctx->num_filters;
i++) {
583#define OFFSET(x) offsetof(CoreImageContext, x)
584#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
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},
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},
611 .p.name =
"coreimage",
613 .p.priv_class = &coreimage_class,
632 .p.name =
"coreimagesrc",
634 .p.priv_class = &coreimagesrc_class,
static int config_input(AVFilterLink *inlink)
static int request_frame(AVFilterLink *outlink)
const FFFilter ff_vsrc_coreimagesrc
const FFFilter ff_vf_coreimage
static AVFormatContext * ctx
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Main libavfilter public API header.
#define i(width, name, range_min, range_max)
static int filter_frame(DBEDecodeContext *s, AVFrame *frame)
int(* init)(AVBSFContext *ctx)
static const uint8_t frame_size[4]
#define AV_DICT_MULTIKEY
Allow to store several equal keys in the dictionary.
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
const AVDictionaryEntry * av_dict_iterate(const AVDictionary *m, const AVDictionaryEntry *prev)
Iterate over a dictionary.
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.
int av_dict_count(const AVDictionary *m)
Get number of entries in dictionary.
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
#define AVERROR_EXTERNAL
Generic error in an external library.
#define AVERROR_EOF
End of file.
#define AV_FRAME_FLAG_INTERLACED
A flag to mark frames whose content is interlaced.
#define AV_FRAME_FLAG_KEY
A flag to mark frames that are keyframes.
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
#define AV_LOG_WARNING
Something somehow does not look correct.
#define AV_LOG_INFO
Standard information.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
int av_log_get_level(void)
Get the current log level.
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
@ AV_PICTURE_TYPE_I
Intra.
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int config_output(AVBitStreamFilterLink *outlink)
#define FILTER_INPUTS(array)
#define FILTER_OUTPUTS(array)
static FilterLink * ff_filter_link(AVFilterLink *link)
#define FILTER_SINGLE_PIXFMT(pix_fmt_)
#define AVFILTER_DEFINE_CLASS(fname)
common internal API header
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
void avpriv_report_missing_feature(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
void * av_calloc(size_t nmemb, size_t size)
Memory handling functions.
int av_get_bits_per_pixel(const AVPixFmtDescriptor *pixdesc)
Return the number of bits per pixel used by the pixel format described by pixdesc.
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Describe the class of an AVClass context structure.
void * priv
private data for use by the filter
AVFilterLink ** outputs
array of pointers to output links
A link between two filters.
int w
agreed upon image width
int h
agreed upon image height
AVFilterContext * src
source filter
AVRational time_base
Define the time base used by the PTS of the frames/samples which will pass through this link.
AVRational sample_aspect_ratio
agreed upon sample aspect ratio
AVFilterContext * dst
dest filter
int format
agreed upon media format
A filter pad used for either input or output.
This structure describes decoded (raw) audio or video data.
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Rational number (pair of numerator and denominator).
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
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
Link properties exposed to filter code, but not external callers.
AVRational frame_rate
Frame rate of the stream on the link, or 1/0 if unknown or variable.
void(* filter)(uint8_t *src, ptrdiff_t stride, int qscale)
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)
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 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.