New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add avfilter module/command #1038
Conversation
FFmpeg filter graph integration
modules/avfilter/avfilter.c
Outdated
* | ||
*/ | ||
|
||
static struct lock *lock = (void*)0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to initialise lock, static/global vars are inited to null.
modules/avfilter/avfilter.c
Outdated
int err; | ||
err = lock_alloc(&lock); | ||
if (err) | ||
return ENOMEM; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should return err
here, instead of ENOMEM
modules/avfilter/avfilter.c
Outdated
|
||
static int module_close(void) | ||
{ | ||
mem_deref(lock); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also setting lock to NULL makes it more robust:
lock = mem_deref(lock)
#include <baresip.h> | ||
#include "avfilter.h" | ||
#include "util.h" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 empty lines between functions
modules/avfilter/filter.c
Outdated
snprintf(args, sizeof(args), | ||
"video_size=%dx%d:pix_fmt=%d:" | ||
"time_base=%d/%d:pixel_aspect=1/1", | ||
frame->size.w, frame->size.h, src_format, 1, 25); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
time_base = 1/25 is hardcoded.
if you want to use the timestamps from the API you can use 1/1000000 as time_base.
(or VIDEO_TIMEBASE
constant)
modules/avfilter/filter.c
Outdated
return err; | ||
} | ||
|
||
int filter_reset(struct avfilter_st* st) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 empty lines between functions
st->enabled = false; | ||
info("avfilter: filter graph reset\n"); | ||
return 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since filter_reset always returns 0, you can change the return type to void
modules/avfilter/filter.c
Outdated
return 0; | ||
} | ||
|
||
bool filter_valid(struct avfilter_st* st, struct vidframe *frame) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the two input arguments can be made const
modules/avfilter/util.c
Outdated
#include "util.h" | ||
|
||
static int swap_lines(uint8_t *a, uint8_t *b, size_t size) { | ||
uint8_t tmp[size]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is dangerous to declare a variable size array on the stack.
probably better to use a heap buffer, or a fixed size stack buffer
modules/avfilter/util.c
Outdated
return 0; | ||
} | ||
|
||
static int reverse_lines(uint8_t *data, int linesize, int count) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
curly brace at the end {
should be moved to next line
|
||
/* | ||
* Sometimes AVFrame contains planes with lines in bottom-up order. | ||
* Then linesize is negative and data points to the last row in buffer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this sounds strange, I have never seen a negative linesize. Which plane was it (0 to 3) ?
the linesize is the number of pixels in a horizontal line, for each plane.
example: [320, 160, 160, 0]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For bottom-up frames all planes have negative linesizes, like this: linesize = {-1920, -960, -960, 0, 0, 0, 0, 0}
(this is from gdb inspecting AVFrame structure).
modules/avfilter/util.c
Outdated
return 0; | ||
} | ||
|
||
enum AVPixelFormat vidfmt_to_avpixfmt(const enum vidfmt fmt) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const is not needed
modules/avfilter/util.c
Outdated
} | ||
} | ||
|
||
enum vidfmt avpixfmt_to_vidfmt(const enum AVPixelFormat pix_fmt) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const is not needed
src/config.c
Outdated
@@ -806,6 +806,7 @@ int config_write_template(const char *file, const struct config *cfg) | |||
(void)re_fprintf(f, "#module\t\t\t" "snapshot" MOD_EXT "\n"); | |||
(void)re_fprintf(f, "#module\t\t\t" "swscale" MOD_EXT "\n"); | |||
(void)re_fprintf(f, "#module\t\t\t" "vidinfo" MOD_EXT "\n"); | |||
(void)re_fprintf(f, "#module\t\t\t" "avfilter" MOD_EXT "\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use TAB for indentation
hi @mkurkov many thanks for this good and useful piece of work. we will merge it to master. regarding bottom-up frames, I have never seen negative linesize in the wild. regarding copying of buffers, it is fine to update data pointers in struct vidframe to point I tested this with ffmpeg 4.1.4 and it works just fine:
I added some review comments inline, please have a look |
please also add your name and the new module to this list: |
@alfredh thanks for reviewing, will fix mentioned issues. Regarding bottom-up frames, I run into them trying simple filters like {data = {0x7fffe7675cc0 '\353' <repeats 199 times>, <incomplete sequence \353>...,
0x7fffe76f85a0 '\200' <repeats 200 times>..., 0x7fffe7777dc0 '\200' <repeats 200 times>..., 0x0, 0x0, 0x0, 0x0, 0x0},
linesize = {-1920, -960, -960, 0, 0, 0, 0, 0}, extended_data = 0x7fffec0e7600, width = 1920, height = 1080, I guess vflip switches frame to bottom-up as optimization. Looking at vflip implementation, it's visible that they also change data to point on last row in buffer: static int filter_frame(AVFilterLink *link, AVFrame *frame)
{
FlipContext *flip = link->dst->priv;
int i;
for (i = 0; i < 4; i ++) {
int vsub = i == 1 || i == 2 ? flip->vsub : 0;
int height = FF_CEIL_RSHIFT(link->h, vsub);
if (frame->data[i]) {
frame->data[i] += (height - 1) * frame->linesize[i];
frame->linesize[i] = -frame->linesize[i];
}
}
return ff_filter_frame(link->dst->outputs[0], frame);
} Not sure if this could be a problem in other parts of Baresip, but avfilter needs to support bottom-up frames too. |
@alfredh issues should be resolved in last commits. |
thanks I get an error when compiling now:
|
https://patchwork.ffmpeg.org/project/ffmpeg/patch/20170806190921.10897-1-cus@passwd.hu/ librem/baresip supports only positive linesize: /** Video frame */
struct vidframe {
uint8_t *data[4]; /**< Video planes */
uint16_t linesize[4]; /**< Array of line-sizes */
struct vidsz size; /**< Frame resolution */
enum vidfmt fmt; /**< Video pixel format */
}; this has worked fine for many years. adding support for negative linesize, would mean updating and testing I think for now it is best that you work around it in avfilter.so |
thanks a lot for your contribution :) |
(Presumably the changelog [Unreleased] section is for 1.0.0) = Baresip Changelog == [Unreleased] === Added - aac: add AAC_STREAMTYPE_AUDIO enum value - aac: add AAC_ prefix - Video mode param to call_answer(), ua_answer() and ua_hold_answer [#966] - video_stop_display() API function [#977] - module: add path to module_load() function - conf: add conf_configure_buf - test: add usage of g711.so module [#978] - JSON initial codec state command and response [#973] - account_set_video_codecs() API function [#981] - net: add fallback dns nameserver [#996] - gtk: show call_peername in notify title [#1006] - call: Added call_state() API function that returns enum state of the call [#1013] - account_set_stun_user() and account_set_stun_pass() API functions [#1015] - API functions account_stun_uri and account_set_stun_uri. [#1018] - ausine: Audio sine wave input module [#1021] - gtk/menu: replace spaces from uri [#1007] - jack: allowing jack client name to be specified in the config file [#1025] [#1020] - snapshot: Add snapshot_send and snapshot_recv commands [#1029] - webrtc_aec: 'extended_filter' config option [#1030] - avfilter: FFmpeg filter graphs integration [#1038] - reg: view proxy expiry value in reg_status [#1068] - account: add parameter rwait for re-register interval [#1069] - call, stream, menu: add cmd to set the direction of video stream [#1073] === Changed - **Using [baresip/re](https://github.com/baresip/re) fork now** - audio: move calculation to audio_jb_current_value - avformat: clean up docs - gzrtp: update docs - account: increased size of audio codec list to 16 - video: make video_sdp_attr_decode public - config: Derive default audio driver from default audio device [#1009] - jack: modifying info message on jack client creation [#1019] - call: when video stream is disabled, stop also video display [#1023] - dtls_srtp: use tls_set_selfsigned_rsa with keysize 2048 [#1062] [#1056] - rst: use a min ptime of 20ms - aac: change ptime to 4ms === Fixed - avcodec: fix H.264 interop with Firefox - winwave: waveInGetPosition is no longer supported for use as of Windows Vista [#960] - avcodec: call av_hwdevice_ctx_create before if-statement - account: use single quote instead of backtick - ice: fix segfault in connh [#980] - call: Update call->got_offer when re-INVITE or answer to re-INVITE is received [#986] - mk: Test also for /usr/lib64/libspeexdsp.so to cover Fedora/RHEL/CentOS [#992] - config: Allow distribution specific CA trust bundle locations (fixes [#993] - config: Allow distribution specific default audio device (fixes [#994] - mqtt: fix err is never read (found by clang static analyzer) - avcodec: fix err is never read (found by clang static analyzer) - gtk: notification buttons do not work on Systems [#1012] - gtk: fix dtmf_tone and add tones as feedback [#1010] - pulse: drain pulse buffers before freeing [#1016] - jack: jack_play connect all physical ports [#1028] - Makefile: do not try to install modules if build is static [#1031] - gzrtp: media_alloc function is missing [#1034] [#1022] - call: when updating video, check if video stream has been disabled [#1037] - amr: fix length check, fixes [#1011] - modules: fix search path for avdevice.h [#1043] - gtk: declare variables C89 style - config: init newly added member - menu: fix segfault in ua_event_handler [#1059] [#1061] - debug_cmd: fix OpenSSL no-deprecated [#1065] - aac: handle missing bitrate parameter in SDP format - av1: properly configure encoder === Removed - ice: remove support for ICE-lite - ice: remove ice_debug, use log level DEBUG instead - ice: make stun server optional - config: remove ice_debug option (unused) === Contributors (many thanks) - Alfred E. Heggestad - Alexander Gramner - Andrew Webster - Christian Spielberger - Christoph Huber - Davide Alberani - Ethan Funk - Juha Heinanen - mbattista - Michael Malone - Mikl Kurkov - ndilieto - Robert Scheck - Roger Sandholm - Sebastian Reimers [#966]: baresip/baresip#966 [#977]: baresip/baresip#977 [#978]: baresip/baresip#978 [#973]: baresip/baresip#973 [#981]: baresip/baresip#981 [#996]: baresip/baresip#996 [#1006]: baresip/baresip#1006 [#1013]: baresip/baresip#1013 [#1015]: baresip/baresip#1015 [#1018]: baresip/baresip#1018 [#1021]: baresip/baresip#1021 [#1007]: baresip/baresip#1007 [#1025]: baresip/baresip#1025 [#1020]: baresip/baresip#1020 [#1029]: baresip/baresip#1029 [#1030]: baresip/baresip#1030 [#1038]: baresip/baresip#1038 [#1009]: baresip/baresip#1009 [#1019]: baresip/baresip#1019 [#1023]: baresip/baresip#1023 [#1062]: baresip/baresip#1062 [#1056]: baresip/baresip#1056 [#960]: baresip/baresip#960 [#980]: baresip/baresip#980 [#986]: baresip/baresip#986 [#992]: baresip/baresip#992 [#993]: baresip/baresip#993 [#994]: baresip/baresip#994 [#1012]: baresip/baresip#1012 [#1010]: baresip/baresip#1010 [#1016]: baresip/baresip#1016 [#1028]: baresip/baresip#1028 [#1031]: baresip/baresip#1031 [#1034]: baresip/baresip#1034 [#1022]: baresip/baresip#1022 [#1037]: baresip/baresip#1037 [#1011]: baresip/baresip#1011 [#1043]: baresip/baresip#1043 [#1059]: baresip/baresip#1059 [#1061]: baresip/baresip#1061 [#1065]: baresip/baresip#1065 [#1068]: baresip/baresip#1068 [#1069]: baresip/baresip#1069 [#1073]: baresip/baresip#1073 [Unreleased]: baresip/baresip@v0.6.6...HEAD
Hi,
Here is my attempt to add FFmpeg filter graphs integration to baresip.
Idea is to allow dynamically set video filter graph for current video stream. And then remove it when needed.
It's implemented as baresip filter module and command
/avfilter
. For example to enablevflip
simple filter graph just call/avfilter vflip
at any time and see how video is flipped. To disable filter graph just send/avfilter
command without any filter string.As more complex example you can apply some png overlay on top of current video stream with
/avfilter movie=/path/to/some/image.png[pic];[in][pic]overlay=(W-w)/2:H-h-20
command.Full syntax and list of filters are available on FFmpeg Filtegraph's page: https://ffmpeg.org/ffmpeg-filters.html#Filtergraph-description
I run into several issues during development:
1. Bottom-up FFmpeg frames.
It seems that FFmpeg frame structure could keep both top-down and bottom-up plane lines orders. In the last case
linesizes are negative and data pointers point to the last rows in the buffer. Baresip uses unsigned linesizes, so as I understand
it doesn't support bottom-up order. As workaround I had to rearrange plane lines in top-down order for such frames and
update linesizes/data pointers. So my question is how Baresip works with bottom-up frames and is my approach valid.
2. Moving data between AVFrame/vidframe structures
I wonder how properly work with FFmpeg AVFrame structure. Currently as I get new AVFrame from filter graph pipeline, I just
update incoming filter frame, setting data pointers and linesizes to AVframe data. It seems to work well and without any additional copying. Main question is when I supposed to unref AVFrame structure. Normally it should be done in the end of encoding pipeline, but filter module sits in the middle of pipeline and doesn't control it. Now I unref previous AVFrame before processing new one, assuming that previous encoding cycle is finished and it's safe to clean memory. Am I right or there is a more proper way to do it?
I don't have much experience with baresip modules and video processing, so any suggestions are greatly appreciated.
Thanks,
Mikhail