1This document is a tutorial/initiation for writing simple filters in 2libavfilter. 3 4Foreword: just like everything else in FFmpeg, libavfilter is monolithic, which 5means that it is highly recommended that you submit your filters to the FFmpeg 6development mailing-list and make sure that they are applied. Otherwise, your filters 7are likely to have a very short lifetime due to more or less regular internal API 8changes, and a limited distribution, review, and testing. 9 10Bootstrap 11========= 12 13Let's say you want to write a new simple video filter called "foobar" which 14takes one frame in input, changes the pixels in whatever fashion you fancy, and 15outputs the modified frame. The most simple way of doing this is to take a 16similar filter. We'll pick edgedetect, but any other should do. You can look 17for others using the `./ffmpeg -v 0 -filters|grep ' V->V '` command. 18 19 - sed 's/edgedetect/foobar/g;s/EdgeDetect/Foobar/g' libavfilter/vf_edgedetect.c > libavfilter/vf_foobar.c 20 - edit libavfilter/Makefile, and add an entry for "foobar" following the 21 pattern of the other filters. 22 - edit libavfilter/allfilters.c, and add an entry for "foobar" following the 23 pattern of the other filters. 24 - ./configure ... 25 - make -j<whatever> ffmpeg 26 - ./ffmpeg -i http://samples.ffmpeg.org/image-samples/lena.pnm -vf foobar foobar.png 27 Note here: you can obviously use a random local image instead of a remote URL. 28 29If everything went right, you should get a foobar.png with Lena edge-detected. 30 31That's it, your new playground is ready. 32 33Some little details about what's going on: 34libavfilter/allfilters.c:this file is parsed by the configure script, which in turn 35will define variables for the build system and the C: 36 37 --- after running configure --- 38 39 $ grep FOOBAR ffbuild/config.mak 40 CONFIG_FOOBAR_FILTER=yes 41 $ grep FOOBAR config.h 42 #define CONFIG_FOOBAR_FILTER 1 43 44CONFIG_FOOBAR_FILTER=yes from the ffbuild/config.mak is later used to enable 45the filter in libavfilter/Makefile and CONFIG_FOOBAR_FILTER=1 from the config.h 46will be used for registering the filter in libavfilter/allfilters.c. 47 48Filter code layout 49================== 50 51You now need some theory about the general code layout of a filter. Open your 52libavfilter/vf_foobar.c. This section will detail the important parts of the 53code you need to understand before messing with it. 54 55Copyright 56--------- 57 58First chunk is the copyright. Most filters are LGPL, and we are assuming 59vf_foobar is as well. We are also assuming vf_foobar is not an edge detector 60filter, so you can update the boilerplate with your credits. 61 62Doxy 63---- 64 65Next chunk is the Doxygen about the file. See https://ffmpeg.org/doxygen/trunk/. 66Detail here what the filter is, does, and add some references if you feel like 67it. 68 69Context 70------- 71 72Skip the headers and scroll down to the definition of FoobarContext. This is 73your local state context. It is already filled with 0 when you get it so do not 74worry about uninitialized reads into this context. This is where you put all 75"global" information that you need; typically the variables storing the user options. 76You'll notice the first field "const AVClass *class"; it's the only field you 77need to keep assuming you have a context. There is some magic you don't need to 78care about around this field, just let it be (in the first position) for now. 79 80Options 81------- 82 83Then comes the options array. This is what will define the user accessible 84options. For example, -vf foobar=mode=colormix:high=0.4:low=0.1. Most options 85have the following pattern: 86 name, description, offset, type, default value, minimum value, maximum value, flags 87 88 - name is the option name, keep it simple and lowercase 89 - description are short, in lowercase, without period, and describe what they 90 do, for example "set the foo of the bar" 91 - offset is the offset of the field in your local context, see the OFFSET() 92 macro; the option parser will use that information to fill the fields 93 according to the user input 94 - type is any of AV_OPT_TYPE_* defined in libavutil/opt.h 95 - default value is an union where you pick the appropriate type; "{.dbl=0.3}", 96 "{.i64=0x234}", "{.str=NULL}", ... 97 - min and max values define the range of available values, inclusive 98 - flags are AVOption generic flags. See AV_OPT_FLAG_* definitions 99 100When in doubt, just look at the other AVOption definitions all around the codebase, 101there are tons of examples. 102 103Class 104----- 105 106AVFILTER_DEFINE_CLASS(foobar) will define a unique foobar_class with some kind 107of signature referencing the options, etc. which will be referenced in the 108definition of the AVFilter. 109 110Filter definition 111----------------- 112 113At the end of the file, you will find foobar_inputs, foobar_outputs and 114the AVFilter ff_vf_foobar. Don't forget to update the AVFilter.description with 115a description of what the filter does, starting with a capitalized letter and 116ending with a period. You'd better drop the AVFilter.flags entry for now, and 117re-add them later depending on the capabilities of your filter. 118 119Callbacks 120--------- 121 122Let's now study the common callbacks. Before going into details, note that all 123these callbacks are explained in details in libavfilter/avfilter.h, so in 124doubt, refer to the doxy in that file. 125 126init() 127~~~~~~ 128 129First one to be called is init(). It's flagged as cold because not called 130often. Look for "cold" on 131http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html for more 132information. 133 134As the name suggests, init() is where you eventually initialize and allocate 135your buffers, pre-compute your data, etc. Note that at this point, your local 136context already has the user options initialized, but you still haven't any 137clue about the kind of data input you will get, so this function is often 138mainly used to sanitize the user options. 139 140Some init()s will also define the number of inputs or outputs dynamically 141according to the user options. A good example of this is the split filter, but 142we won't cover this here since vf_foobar is just a simple 1:1 filter. 143 144uninit() 145~~~~~~~~ 146 147Similarly, there is the uninit() callback, doing what the name suggests. Free 148everything you allocated here. 149 150query_formats() 151~~~~~~~~~~~~~~~ 152 153This follows the init() and is used for the format negotiation. Basically 154you specify here what pixel format(s) (gray, rgb 32, yuv 4:2:0, ...) you accept 155for your inputs, and what you can output. All pixel formats are defined in 156libavutil/pixfmt.h. If you don't change the pixel format between the input and 157the output, you just have to define a pixel formats array and call 158ff_set_common_formats(). For more complex negotiation, you can refer to other 159filters such as vf_scale. 160 161config_props() 162~~~~~~~~~~~~~~ 163 164This callback is not necessary, but you will probably have one or more 165config_props() anyway. It's not a callback for the filter itself but for its 166inputs or outputs (they're called "pads" - AVFilterPad - in libavfilter's 167lexicon). 168 169Inside the input config_props(), you are at a point where you know which pixel 170format has been picked after query_formats(), and more information such as the 171video width and height (inlink->{w,h}). So if you need to update your internal 172context state depending on your input you can do it here. In edgedetect you can 173see that this callback is used to allocate buffers depending on these 174information. They will be destroyed in uninit(). 175 176Inside the output config_props(), you can define what you want to change in the 177output. Typically, if your filter is going to double the size of the video, you 178will update outlink->w and outlink->h. 179 180filter_frame() 181~~~~~~~~~~~~~~ 182 183This is the callback you are waiting for from the beginning: it is where you 184process the received frames. Along with the frame, you get the input link from 185where the frame comes from. 186 187 static int filter_frame(AVFilterLink *inlink, AVFrame *in) { ... } 188 189You can get the filter context through that input link: 190 191 AVFilterContext *ctx = inlink->dst; 192 193Then access your internal state context: 194 195 FoobarContext *foobar = ctx->priv; 196 197And also the output link where you will send your frame when you are done: 198 199 AVFilterLink *outlink = ctx->outputs[0]; 200 201Here, we are picking the first output. You can have several, but in our case we 202only have one since we are in a 1:1 input-output situation. 203 204If you want to define a simple pass-through filter, you can just do: 205 206 return ff_filter_frame(outlink, in); 207 208But of course, you probably want to change the data of that frame. 209 210This can be done by accessing frame->data[] and frame->linesize[]. Important 211note here: the width does NOT match the linesize. The linesize is always 212greater or equal to the width. The padding created should not be changed or 213even read. Typically, keep in mind that a previous filter in your chain might 214have altered the frame dimension but not the linesize. Imagine a crop filter 215that halves the video size: the linesizes won't be changed, just the width. 216 217 <-------------- linesize ------------------------> 218 +-------------------------------+----------------+ ^ 219 | | | | 220 | | | | 221 | picture | padding | | height 222 | | | | 223 | | | | 224 +-------------------------------+----------------+ v 225 <----------- width -------------> 226 227Before modifying the "in" frame, you have to make sure it is writable, or get a 228new one. Multiple scenarios are possible here depending on the kind of 229processing you are doing. 230 231Let's say you want to change one pixel depending on multiple pixels (typically 232the surrounding ones) of the input. In that case, you can't do an in-place 233processing of the input so you will need to allocate a new frame, with the same 234properties as the input one, and send that new frame to the next filter: 235 236 AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h); 237 if (!out) { 238 av_frame_free(&in); 239 return AVERROR(ENOMEM); 240 } 241 av_frame_copy_props(out, in); 242 243 // out->data[...] = foobar(in->data[...]) 244 245 av_frame_free(&in); 246 return ff_filter_frame(outlink, out); 247 248In-place processing 249~~~~~~~~~~~~~~~~~~~ 250 251If you can just alter the input frame, you probably just want to do that 252instead: 253 254 av_frame_make_writable(in); 255 // in->data[...] = foobar(in->data[...]) 256 return ff_filter_frame(outlink, in); 257 258You may wonder why a frame might not be writable. The answer is that for 259example a previous filter might still own the frame data: imagine a filter 260prior to yours in the filtergraph that needs to cache the frame. You must not 261alter that frame, otherwise it will make that previous filter buggy. This is 262where av_frame_make_writable() helps (it won't have any effect if the frame 263already is writable). 264 265The problem with using av_frame_make_writable() is that in the worst case it 266will copy the whole input frame before you change it all over again with your 267filter: if the frame is not writable, av_frame_make_writable() will allocate 268new buffers, and copy the input frame data. You don't want that, and you can 269avoid it by just allocating a new buffer if necessary, and process from in to 270out in your filter, saving the memcpy. Generally, this is done following this 271scheme: 272 273 int direct = 0; 274 AVFrame *out; 275 276 if (av_frame_is_writable(in)) { 277 direct = 1; 278 out = in; 279 } else { 280 out = ff_get_video_buffer(outlink, outlink->w, outlink->h); 281 if (!out) { 282 av_frame_free(&in); 283 return AVERROR(ENOMEM); 284 } 285 av_frame_copy_props(out, in); 286 } 287 288 // out->data[...] = foobar(in->data[...]) 289 290 if (!direct) 291 av_frame_free(&in); 292 return ff_filter_frame(outlink, out); 293 294Of course, this will only work if you can do in-place processing. To test if 295your filter handles well the permissions, you can use the perms filter. For 296example with: 297 298 -vf perms=random,foobar 299 300Make sure no automatic pixel conversion is inserted between perms and foobar, 301otherwise the frames permissions might change again and the test will be 302meaningless: add av_log(0,0,"direct=%d\n",direct) in your code to check that. 303You can avoid the issue with something like: 304 305 -vf format=rgb24,perms=random,foobar 306 307...assuming your filter accepts rgb24 of course. This will make sure the 308necessary conversion is inserted before the perms filter. 309 310Timeline 311~~~~~~~~ 312 313Adding timeline support 314(http://ffmpeg.org/ffmpeg-filters.html#Timeline-editing) is often an easy 315feature to add. In the most simple case, you just have to add 316AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC to the AVFilter.flags. You can typically 317do this when your filter does not need to save the previous context frames, or 318basically if your filter just alters whatever goes in and doesn't need 319previous/future information. See for instance commit 86cb986ce that adds 320timeline support to the fieldorder filter. 321 322In some cases, you might need to reset your context somehow. This is handled by 323the AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL flag which is used if the filter 324must not process the frames but still wants to keep track of the frames going 325through (to keep them in cache for when it's enabled again). See for example 326commit 69d72140a that adds timeline support to the phase filter. 327 328Threading 329~~~~~~~~~ 330 331libavfilter does not yet support frame threading, but you can add slice 332threading to your filters. 333 334Let's say the foobar filter has the following frame processing function: 335 336 dst = out->data[0]; 337 src = in ->data[0]; 338 339 for (y = 0; y < inlink->h; y++) { 340 for (x = 0; x < inlink->w; x++) 341 dst[x] = foobar(src[x]); 342 dst += out->linesize[0]; 343 src += in ->linesize[0]; 344 } 345 346The first thing is to make this function work into slices. The new code will 347look like this: 348 349 for (y = slice_start; y < slice_end; y++) { 350 for (x = 0; x < inlink->w; x++) 351 dst[x] = foobar(src[x]); 352 dst += out->linesize[0]; 353 src += in ->linesize[0]; 354 } 355 356The source and destination pointers, and slice_start/slice_end will be defined 357according to the number of jobs. Generally, it looks like this: 358 359 const int slice_start = (in->height * jobnr ) / nb_jobs; 360 const int slice_end = (in->height * (jobnr+1)) / nb_jobs; 361 uint8_t *dst = out->data[0] + slice_start * out->linesize[0]; 362 const uint8_t *src = in->data[0] + slice_start * in->linesize[0]; 363 364This new code will be isolated in a new filter_slice(): 365 366 static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { ... } 367 368Note that we need our input and output frame to define slice_{start,end} and 369dst/src, which are not available in that callback. They will be transmitted 370through the opaque void *arg. You have to define a structure which contains 371everything you need: 372 373 typedef struct ThreadData { 374 AVFrame *in, *out; 375 } ThreadData; 376 377If you need some more information from your local context, put them here. 378 379In you filter_slice function, you access it like that: 380 381 const ThreadData *td = arg; 382 383Then in your filter_frame() callback, you need to call the threading 384distributor with something like this: 385 386 ThreadData td; 387 388 // ... 389 390 td.in = in; 391 td.out = out; 392 ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); 393 394 // ... 395 396 return ff_filter_frame(outlink, out); 397 398Last step is to add AVFILTER_FLAG_SLICE_THREADS flag to AVFilter.flags. 399 400For more example of slice threading additions, you can try to run git log -p 401--grep 'slice threading' libavfilter/ 402 403Finalization 404~~~~~~~~~~~~ 405 406When your awesome filter is finished, you have a few more steps before you're 407done: 408 409 - write its documentation in doc/filters.texi, and test the output with make 410 doc/ffmpeg-filters.html. 411 - add a FATE test, generally by adding an entry in 412 tests/fate/filter-video.mak, add running make fate-filter-foobar GEN=1 to 413 generate the data. 414 - add an entry in the Changelog 415 - edit libavfilter/version.h and increase LIBAVFILTER_VERSION_MINOR by one 416 (and reset LIBAVFILTER_VERSION_MICRO to 100) 417 - git add ... && git commit -m "avfilter: add foobar filter." && git format-patch -1 418 419When all of this is done, you can submit your patch to the ffmpeg-devel 420mailing-list for review. If you need any help, feel free to come on our IRC 421channel, #ffmpeg-devel on irc.libera.chat. 422