Go to the documentation of this file.
26 #import <CoreImage/CoreImage.h>
27 #import <AppKit/AppKit.h>
72 link->frame_rate =
ctx->frame_rate;
73 link->time_base =
ctx->time_base;
97 NSArray *filter_categories = nil;
99 if (
ctx->list_generators && !
ctx->list_filters) {
100 filter_categories = [NSArray arrayWithObjects:kCICategoryGenerator, nil];
103 NSArray *filter_names = [CIFilter filterNamesInCategories:filter_categories];
104 NSEnumerator *
filters = [filter_names objectEnumerator];
106 NSString *filter_name;
107 while (filter_name = [
filters nextObject]) {
111 CIFilter *
filter = [CIFilter filterWithName:filter_name];
112 NSDictionary *filter_attribs = [filter attributes];
113 NSArray *filter_inputs = [filter inputKeys];
116 NSDictionary *input_attribs = [filter_attribs valueForKey:input];
117 NSString *input_class = [input_attribs valueForKey:kCIAttributeClass];
118 if ([input_class isEqualToString:
@"NSNumber"]) {
119 NSNumber *value_default = [input_attribs valueForKey:kCIAttributeDefault];
120 NSNumber *value_min = [input_attribs valueForKey:kCIAttributeSliderMin];
121 NSNumber *value_max = [input_attribs valueForKey:kCIAttributeSliderMax];
125 [input_class UTF8String],
126 [[value_min stringValue] UTF8String],
127 [[value_max stringValue] UTF8String],
128 [[value_default stringValue] UTF8String]);
132 [input_class UTF8String]);
191 NSData *
data = [NSData dataWithBytesNoCopy:frame->data[0]
192 length:frame->height*frame->linesize[0]
195 CIImage *
ret = [(__bridge CIImage*)ctx->input_image initWithBitmapData:data
196 bytesPerRow:frame->linesize[0]
198 format:kCIFormatARGB8
199 colorSpace:ctx->color_space];
206 CIImage *filter_input = (__bridge CIImage*)
ctx->input_image;
207 CIImage *filter_output =
NULL;
213 filter_input = [(__bridge CIImage*)ctx->filters[i-1] valueForKey:kCIOutputImageKey];
214 CGRect out_rect = [filter_input extent];
215 if (out_rect.size.width >
frame->width || out_rect.size.height >
frame->height) {
217 out_rect.origin.x = 0.0f;
218 out_rect.origin.y = 0.0f;
219 out_rect.size.width =
frame->width;
220 out_rect.size.height =
frame->height;
222 filter_input = [filter_input imageByCroppingToRect:out_rect];
228 if (!
ctx->is_video_source ||
i) {
230 [filter setValue:filter_input forKey:kCIInputImageKey];
231 }
@catch (NSException *exception) {
232 if (![[exception
name] isEqualToString:NSUndefinedKeyException]) {
243 filter_output = [filter valueForKey:kCIOutputImageKey];
245 if (!filter_output) {
251 CGRect out_rect = [filter_output extent];
252 if (out_rect.size.width >
frame->width || out_rect.size.height >
frame->height) {
254 out_rect.origin.x = 0.0f;
255 out_rect.origin.y = 0.0f;
256 out_rect.size.width =
frame->width;
257 out_rect.size.height =
frame->height;
260 CGImageRef
out = [(__bridge CIContext*)ctx->glctx createCGImage:filter_output
269 CGContextRelease(
ctx->cgctx);
272 size_t out_width = CGImageGetWidth(
out);
273 size_t out_height = CGImageGetHeight(
out);
275 if (out_width >
frame->width || out_height >
frame->height) {
276 av_log(
ctx,
AV_LOG_WARNING,
"Output image has unexpected size: %lux%lu (expected: %ix%i). This may crash...\n",
277 out_width, out_height,
frame->width,
frame->height);
279 ctx->cgctx = CGBitmapContextCreate(
frame->data[0],
282 ctx->bits_per_component,
285 (uint32_t)kCGImageAlphaPremultipliedFirst);
293 if (
ctx->output_rect) {
295 NSString *tmp_string = [NSString stringWithUTF8String:ctx->output_rect];
296 NSRect
tmp = NSRectFromString(tmp_string);
298 }
@catch (NSException *exception) {
302 if (
rect.size.width == 0.0f) {
305 if (
rect.size.height == 0.0f) {
346 frame->key_frame = 1;
347 frame->interlaced_frame = 0;
349 frame->sample_aspect_ratio =
ctx->sar;
360 NSString *input_key = [NSString stringWithUTF8String:key];
361 NSString *input_val = [NSString stringWithUTF8String:value];
363 NSDictionary *filter_attribs = [filter attributes];
364 NSDictionary *input_attribs = [filter_attribs valueForKey:input_key];
366 NSString *input_class = [input_attribs valueForKey:kCIAttributeClass];
367 NSString *input_type = [input_attribs valueForKey:kCIAttributeType];
369 if (!input_attribs) {
371 [input_key UTF8String]);
376 [input_key UTF8String],
377 [input_val UTF8String],
378 input_attribs ? (
unsigned long)[input_attribs
count] : -1,
379 [input_class UTF8String],
380 [input_type UTF8String]);
382 if ([input_class isEqualToString:
@"NSNumber"]) {
383 float input = input_val.floatValue;
384 NSNumber *max_value = [input_attribs valueForKey:kCIAttributeSliderMax];
385 NSNumber *min_value = [input_attribs valueForKey:kCIAttributeSliderMin];
386 NSNumber *used_value = nil;
388 #define CLAMP_WARNING do { \
389 av_log(ctx, AV_LOG_WARNING, "Value of \"%f\" for option \"%s\" is out of range [%f %f], clamping to \"%f\".\n", \
391 [input_key UTF8String], \
392 min_value.floatValue, \
393 max_value.floatValue, \
394 used_value.floatValue); \
396 if (
input > max_value.floatValue) {
397 used_value = max_value;
399 }
else if (
input < min_value.floatValue) {
400 used_value = min_value;
403 used_value = [NSNumber numberWithFloat:input];
406 [filter setValue:used_value forKey:input_key];
407 }
else if ([input_class isEqualToString:
@"CIVector"]) {
408 CIVector *
input = [CIVector vectorWithString:input_val];
412 [input_val UTF8String]);
416 [filter setValue:input forKey:input_key];
417 }
else if ([input_class isEqualToString:
@"CIColor"]) {
418 CIColor *
input = [CIColor colorWithString:input_val];
422 [input_val UTF8String]);
426 [filter setValue:input forKey:input_key];
427 }
else if ([input_class isEqualToString:
@"NSString"]) {
428 [filter setValue:input_val forKey:input_key];
429 }
else if ([input_class isEqualToString:
@"NSData"]) {
430 NSData *
input = [NSData dataWithBytes:(const void*)[input_val cStringUsingEncoding:NSISOLatin1StringEncoding]
431 length:[input_val lengthOfBytesUsingEncoding:NSISOLatin1StringEncoding]];
435 [input_val UTF8String]);
439 [filter setValue:input forKey:input_key];
442 [input_class UTF8String]);
454 CIFilter *
filter = [CIFilter filterWithName:[NSString stringWithUTF8String:filter_name]];
457 [filter setDefaults];
460 if (filter_options) {
479 if (
ctx->list_filters ||
ctx->list_generators) {
484 if (
ctx->filter_string) {
507 if (strncmp(
f->value,
"default", 7)) {
517 if (!filter_options) {
527 if (!
ctx->filters[
i]) {
540 const NSOpenGLPixelFormatAttribute attr[] = {
541 NSOpenGLPFAAccelerated,
542 NSOpenGLPFANoRecovery,
543 NSOpenGLPFAColorSize, 32,
547 NSOpenGLPixelFormat *pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:(void *)&attr];
548 ctx->color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
549 ctx->glctx = CFBridgingRetain([CIContext contextWithCGLContext:CGLGetCurrentContext()
550 pixelFormat:[pixel_format CGLPixelFormatObj]
551 colorSpace:
ctx->color_space
560 ctx->input_image = CFBridgingRetain([CIImage emptyImage]);
569 ctx->is_video_source = 1;
578 #define SafeCFRelease(ptr) do { \
593 for (
int i = 0;
i <
ctx->num_filters;
i++) {
630 #define OFFSET(x) offsetof(CoreImageContext, x)
631 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
633 #define GENERATOR_OPTIONS \
634 {"size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0, FLAGS}, \
635 {"s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0, FLAGS}, \
636 {"rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, FLAGS}, \
637 {"r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, FLAGS}, \
638 {"duration", "set video duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS}, \
639 {"d", "set video duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS}, \
640 {"sar", "set video sample aspect ratio", OFFSET(sar), AV_OPT_TYPE_RATIONAL, {.dbl = 1}, 0, INT_MAX, FLAGS},
642 #define FILTER_OPTIONS \
643 {"list_filters", "list available filters", OFFSET(list_filters), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, .flags = FLAGS}, \
644 {"list_generators", "list available generators", OFFSET(list_generators), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, .flags = FLAGS}, \
645 {"filter", "names and options of filters to apply", OFFSET(filter_string), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = FLAGS}, \
646 {"output_rect", "output rectangle within output image", OFFSET(output_rect), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = FLAGS},
663 .priv_class = &coreimage_class,
679 .
name =
"coreimagesrc",
684 .priv_class = &coreimagesrc_class,
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
CFTypeRef glctx
OpenGL context.
#define AV_LOG_WARNING
Something somehow does not look correct.
AVPixelFormat
Pixel format.
int64_t duration
duration expressed in microseconds
AVFilter ff_vsrc_coreimagesrc
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
CGContextRef cgctx
Bitmap context for image copy.
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
#define AVERROR_EOF
End of file.
static const struct PPFilter filters[]
int av_dict_count(const AVDictionary *m)
Get number of entries in dictionary.
AVFilterFormats * in_formats
Lists of formats and channel layouts supported by the input and output filters respectively.
AVFILTER_DEFINE_CLASS(coreimage)
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
This structure describes decoded (raw) audio or video data.
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.
#define AV_DICT_IGNORE_SUFFIX
Return first entry in a dictionary whose first part corresponds to the search key,...
void * av_mallocz_array(size_t nmemb, size_t size)
CGColorSpaceRef color_space
Common color space for input image and cgcontext.
static const AVFilterPad vf_coreimage_outputs[]
int av_get_bits_per_pixel(const AVPixFmtDescriptor *pixdesc)
Return the number of bits per pixel used by the pixel format described by pixdesc.
filter_frame For filters that do not use the this method is called when a frame is pushed to the filter s input It can be called at any time except in a reentrant way If the input frame is enough to produce then the filter should push the output frames on the output link immediately As an exception to the previous rule if the input frame is enough to produce several output frames then the filter needs output only at least one per link The additional frames can be left buffered in the filter
const char * name
Filter name.
static const AVOption coreimage_options[]
A link between two filters.
static int filter_frame(AVFilterLink *link, AVFrame *frame)
Apply all valid filters successively to the input image.
void * priv
private data for use by the filter
static const AVFilterPad vsrc_coreimagesrc_outputs[]
static int request_frame(AVFilterLink *link)
static av_cold int init(AVFilterContext *fctx)
static int query_formats(AVFilterContext *fctx)
A filter pad used for either input or output.
static int config_output(AVFilterLink *link)
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
AVFrame * picref
cached reference containing the painted picture
static const AVFilterPad outputs[]
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
AVRational time_base
stream time base
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
static int config_input(AVFilterLink *link)
Determine image properties from input link of filter chain.
int av_log_get_level(void)
Get the current log level.
Describe the class of an AVClass context structure.
#define AV_DICT_MULTIKEY
Allow to store several equal keys in the dictionary.
Rational number (pair of numerator and denominator).
CFTypeRef * filters
CIFilter object for all requested filters.
int bits_per_component
Shared bpc for input-output operation.
AVFilterLink ** inputs
array of pointers to input links
@ AV_PICTURE_TYPE_I
Intra.
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
int64_t pts
increasing presentation time stamp
const OptionDef options[]
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
AVRational sar
sample aspect ratio
CFTypeRef input_image
Input image container for passing into Core Image API.
void avpriv_report_missing_feature(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
#define AVERROR_EXTERNAL
Generic error in an external library.
AVFilterFormats * out_formats
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
#define AV_LOG_INFO
Standard information.
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi - 0x80) *(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi - 0x80) *(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(const int16_t *) pi >> 8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(const int32_t *) pi >> 24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31)))) #define SET_CONV_FUNC_GROUP(ofmt, ifmt) static void set_generic_function(AudioConvert *ac) { } void ff_audio_convert_free(AudioConvert **ac) { if(! *ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);} AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, int sample_rate, int apply_map) { AudioConvert *ac;int in_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) return NULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method !=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt) > 2) { ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc) { av_free(ac);return NULL;} return ac;} in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar) { ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar ? ac->channels :1;} else if(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;else ac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);return ac;} int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) { int use_generic=1;int len=in->nb_samples;int p;if(ac->dc) { av_log(ac->avr, AV_LOG_TRACE, "%d samples - audio_convert: %s to %s (dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));return ff_convert_dither(ac-> in
static void list_filters(CoreImageContext *ctx)
Print a list of all available filters including options and respective value ranges and defaults.
#define i(width, name, range_min, range_max)
static const AVOption coreimagesrc_options[]
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
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
char * filter_string
The complete user provided filter definition.
const char * name
Pad name.
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.
AVRational frame_rate
video frame rate
char * output_rect
Rectangle to be filled with filter intput.
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
AVRational sample_aspect_ratio
Sample aspect ratio for the video frame, 0/1 if unknown/unspecified.
int num_filters
Amount of filters in *filters.
int list_generators
Option used to list all available generators.
static av_cold int init_src(AVFilterContext *fctx)
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 is_video_source
filter is used as video source
static int apply_filter(CoreImageContext *ctx, AVFilterLink *link, AVFrame *frame)
int64_t duration
Duration of the stream, in AV_TIME_BASE fractional seconds.
static int query_formats_src(AVFilterContext *fctx)
static av_cold void uninit(AVFilterContext *fctx)
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
static const AVFilterPad vf_coreimage_inputs[]
#define GENERATOR_OPTIONS
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
#define SafeCFRelease(ptr)
int list_filters
Option used to list all available filters including generators.
AVFilterLink ** outputs
array of pointers to output links