FFmpeg
vf_vidstabdetect.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Georg Martius <georg dot martius at web dot de>
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 #define DEFAULT_RESULT_NAME "transforms.trf"
22 
23 #include <vid.stab/libvidstab.h>
24 
25 #include "libavutil/common.h"
26 #include "libavutil/opt.h"
27 #include "libavutil/imgutils.h"
28 #include "avfilter.h"
29 #include "internal.h"
30 
31 #include "vidstabutils.h"
32 
33 typedef struct StabData {
34  const AVClass *class;
35 
36  VSMotionDetect md;
37  VSMotionDetectConfig conf;
38 
39  char *result;
40  FILE *f;
41 } StabData;
42 
43 
44 #define OFFSET(x) offsetof(StabData, x)
45 #define OFFSETC(x) (offsetof(StabData, conf)+offsetof(VSMotionDetectConfig, x))
46 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
47 
48 static const AVOption vidstabdetect_options[] = {
49  {"result", "path to the file used to write the transforms", OFFSET(result), AV_OPT_TYPE_STRING, {.str = DEFAULT_RESULT_NAME}, .flags = FLAGS},
50  {"shakiness", "how shaky is the video and how quick is the camera?"
51  " 1: little (fast) 10: very strong/quick (slow)", OFFSETC(shakiness), AV_OPT_TYPE_INT, {.i64 = 5}, 1, 10, FLAGS},
52  {"accuracy", "(>=shakiness) 1: low 15: high (slow)", OFFSETC(accuracy), AV_OPT_TYPE_INT, {.i64 = 15}, 1, 15, FLAGS},
53  {"stepsize", "region around minimum is scanned with 1 pixel resolution", OFFSETC(stepSize), AV_OPT_TYPE_INT, {.i64 = 6}, 1, 32, FLAGS},
54  {"mincontrast", "below this contrast a field is discarded (0-1)", OFFSETC(contrastThreshold), AV_OPT_TYPE_DOUBLE, {.dbl = 0.25}, 0.0, 1.0, FLAGS},
55  {"show", "0: draw nothing; 1,2: show fields and transforms", OFFSETC(show), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 2, FLAGS},
56  {"tripod", "virtual tripod mode (if >0): motion is compared to a reference"
57  " reference frame (frame # is the value)", OFFSETC(virtualTripod), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS},
58  {NULL}
59 };
60 
61 AVFILTER_DEFINE_CLASS(vidstabdetect);
62 
64 {
65  StabData *s = ctx->priv;
66  ff_vs_init();
67  s->class = &vidstabdetect_class;
68  av_log(ctx, AV_LOG_VERBOSE, "vidstabdetect filter: init %s\n", LIBVIDSTAB_VERSION);
69  return 0;
70 }
71 
73 {
74  StabData *s = ctx->priv;
75  VSMotionDetect *md = &(s->md);
76 
77  if (s->f) {
78  fclose(s->f);
79  s->f = NULL;
80  }
81 
82  vsMotionDetectionCleanup(md);
83 }
84 
86 {
87  // If you add something here also add it in vidstabutils.c
88  static const enum AVPixelFormat pix_fmts[] = {
94  };
95 
96  AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
97  if (!fmts_list)
98  return AVERROR(ENOMEM);
99  return ff_set_common_formats(ctx, fmts_list);
100 }
101 
103 {
104  AVFilterContext *ctx = inlink->dst;
105  StabData *s = ctx->priv;
106 
107  VSMotionDetect* md = &(s->md);
108  VSFrameInfo fi;
110  int is_planar = desc->flags & AV_PIX_FMT_FLAG_PLANAR;
111 
112  vsFrameInfoInit(&fi, inlink->w, inlink->h,
113  ff_av2vs_pixfmt(ctx, inlink->format));
114  if (!is_planar && fi.bytesPerPixel != av_get_bits_per_pixel(desc)/8) {
115  av_log(ctx, AV_LOG_ERROR, "pixel-format error: wrong bits/per/pixel, please report a BUG");
116  return AVERROR(EINVAL);
117  }
118  if (fi.log2ChromaW != desc->log2_chroma_w) {
119  av_log(ctx, AV_LOG_ERROR, "pixel-format error: log2_chroma_w, please report a BUG");
120  return AVERROR(EINVAL);
121  }
122 
123  if (fi.log2ChromaH != desc->log2_chroma_h) {
124  av_log(ctx, AV_LOG_ERROR, "pixel-format error: log2_chroma_h, please report a BUG");
125  return AVERROR(EINVAL);
126  }
127 
128  // set values that are not initialized by the options
129  s->conf.algo = 1;
130  s->conf.modName = "vidstabdetect";
131  if (vsMotionDetectInit(md, &s->conf, &fi) != VS_OK) {
132  av_log(ctx, AV_LOG_ERROR, "initialization of Motion Detection failed, please report a BUG");
133  return AVERROR(EINVAL);
134  }
135 
136  vsMotionDetectGetConfig(&s->conf, md);
137  av_log(ctx, AV_LOG_INFO, "Video stabilization settings (pass 1/2):\n");
138  av_log(ctx, AV_LOG_INFO, " shakiness = %d\n", s->conf.shakiness);
139  av_log(ctx, AV_LOG_INFO, " accuracy = %d\n", s->conf.accuracy);
140  av_log(ctx, AV_LOG_INFO, " stepsize = %d\n", s->conf.stepSize);
141  av_log(ctx, AV_LOG_INFO, " mincontrast = %f\n", s->conf.contrastThreshold);
142  av_log(ctx, AV_LOG_INFO, " tripod = %d\n", s->conf.virtualTripod);
143  av_log(ctx, AV_LOG_INFO, " show = %d\n", s->conf.show);
144  av_log(ctx, AV_LOG_INFO, " result = %s\n", s->result);
145 
146  s->f = fopen(s->result, "w");
147  if (s->f == NULL) {
148  av_log(ctx, AV_LOG_ERROR, "cannot open transform file %s\n", s->result);
149  return AVERROR(EINVAL);
150  } else {
151  if (vsPrepareFile(md, s->f) != VS_OK) {
152  av_log(ctx, AV_LOG_ERROR, "cannot write to transform file %s\n", s->result);
153  return AVERROR(EINVAL);
154  }
155  }
156  return 0;
157 }
158 
160 {
161  AVFilterContext *ctx = inlink->dst;
162  StabData *s = ctx->priv;
163  VSMotionDetect *md = &(s->md);
164  LocalMotions localmotions;
165 
166  AVFilterLink *outlink = inlink->dst->outputs[0];
167  VSFrame frame;
168  int plane;
169 
170  if (s->conf.show > 0 && !av_frame_is_writable(in))
172 
173  for (plane = 0; plane < md->fi.planes; plane++) {
174  frame.data[plane] = in->data[plane];
175  frame.linesize[plane] = in->linesize[plane];
176  }
177  if (vsMotionDetection(md, &localmotions, &frame) != VS_OK) {
178  av_log(ctx, AV_LOG_ERROR, "motion detection failed");
179  return AVERROR(AVERROR_EXTERNAL);
180  } else {
181  if (vsWriteToFile(md, s->f, &localmotions) != VS_OK) {
182  int ret = AVERROR(errno);
183  av_log(ctx, AV_LOG_ERROR, "cannot write to transform file");
184  return ret;
185  }
186  vs_vector_del(&localmotions);
187  }
188 
189  return ff_filter_frame(outlink, in);
190 }
191 
193  {
194  .name = "default",
195  .type = AVMEDIA_TYPE_VIDEO,
196  .filter_frame = filter_frame,
197  .config_props = config_input,
198  },
199  { NULL }
200 };
201 
203  {
204  .name = "default",
205  .type = AVMEDIA_TYPE_VIDEO,
206  },
207  { NULL }
208 };
209 
211  .name = "vidstabdetect",
212  .description = NULL_IF_CONFIG_SMALL("Extract relative transformations, "
213  "pass 1 of 2 for stabilization "
214  "(see vidstabtransform for pass 2)."),
215  .priv_size = sizeof(StabData),
216  .init = init,
217  .uninit = uninit,
219  .inputs = avfilter_vf_vidstabdetect_inputs,
220  .outputs = avfilter_vf_vidstabdetect_outputs,
221  .priv_class = &vidstabdetect_class,
222 };
int plane
Definition: avisynth_c.h:384
static av_cold int init(AVFilterContext *ctx)
#define NULL
Definition: coverity.c:32
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2522
This structure describes decoded (raw) audio or video data.
Definition: frame.h:295
AVOption.
Definition: opt.h:246
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:71
misc image utilities
Main libavfilter public API header.
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
const char * desc
Definition: nvenc.c:68
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:2474
AVFILTER_DEFINE_CLASS(vidstabdetect)
static int query_formats(AVFilterContext *ctx)
uint8_t log2_chroma_w
Amount to shift the luma width right to find the chroma width.
Definition: pixdesc.h:92
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:283
const char * name
Pad name.
Definition: internal.h:60
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1093
planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples)
Definition: pixfmt.h:101
static const AVOption vidstabdetect_options[]
#define av_cold
Definition: attributes.h:82
#define FLAGS
static int config_input(AVFilterLink *inlink)
AVOptions.
AVFilter ff_vf_vidstabdetect
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
static const AVFilterPad avfilter_vf_vidstabdetect_outputs[]
#define av_log(a,...)
A filter pad used for either input or output.
Definition: internal.h:54
AVS_FilterInfo ** fi
Definition: avisynth_c.h:807
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:569
#define OFFSET(x)
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition: pixdesc.h:101
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
void * priv
private data for use by the filter
Definition: avfilter.h:353
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
VSMotionDetect md
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:70
uint64_t flags
Combination of AV_PIX_FMT_FLAG_...
Definition: pixdesc.h:106
const AVClass * class
AVFormatContext * ctx
Definition: movenc.c:48
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
#define s(width, name)
Definition: cbs_vp9.c:257
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
static const AVFilterPad avfilter_vf_vidstabdetect_inputs[]
int av_frame_is_writable(AVFrame *frame)
Check if the frame data is writable.
Definition: frame.c:594
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:326
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:81
#define DEFAULT_RESULT_NAME
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
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
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition: pixfmt.h:72
Describe the class of an AVClass context structure.
Definition: log.h:67
Filter definition.
Definition: avfilter.h:144
const char * name
Filter name.
Definition: avfilter.h:148
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:350
VSMotionDetectConfig conf
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:275
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
int av_frame_make_writable(AVFrame *frame)
Ensure that the frame data is writable, avoiding data copy if possible.
Definition: frame.c:611
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:309
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
#define OFFSETC(x)
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:66
Y , 8bpp.
Definition: pixfmt.h:74
VSPixelFormat ff_av2vs_pixfmt(AVFilterContext *ctx, enum AVPixelFormat pf)
convert AV&#39;s pixelformat to vid.stab pixelformat
Definition: vidstabutils.c:24
common internal and external API header
char * result
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
Definition: pixfmt.h:73
static av_cold void uninit(AVFilterContext *ctx)
A list of supported formats for one end of a filter link.
Definition: formats.h:64
An instance of a filter.
Definition: avfilter.h:338
void ff_vs_init(void)
sets the memory allocation function and logging constants to av versions
Definition: vidstabutils.c:69
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition: pixfmt.h:99
internal API functions
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
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:57
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
#define AV_PIX_FMT_FLAG_PLANAR
At least one pixel component is not in the first data plane.
Definition: pixdesc.h:144