lavfi/deshake: support named options.
This commit is contained in:
@@ -2320,8 +2320,10 @@ Attempt to fix small changes in horizontal and/or vertical shift. This
|
|||||||
filter helps remove camera shake from hand-holding a camera, bumping a
|
filter helps remove camera shake from hand-holding a camera, bumping a
|
||||||
tripod, moving on a vehicle, etc.
|
tripod, moving on a vehicle, etc.
|
||||||
|
|
||||||
The filter accepts parameters as a string of the form
|
The filter accepts parameters as a list of @var{key}=@var{value}
|
||||||
"@var{x}:@var{y}:@var{w}:@var{h}:@var{rx}:@var{ry}:@var{edge}:@var{blocksize}:@var{contrast}:@var{search}:@var{filename}"
|
pairs, separated by ":". If the key of the first options is omitted,
|
||||||
|
the arguments are interpreted according to the syntax
|
||||||
|
@var{x}:@var{y}:@var{w}:@var{h}:@var{rx}:@var{ry}:@var{edge}:@var{blocksize}:@var{contrast}:@var{search}:@var{filename}.
|
||||||
|
|
||||||
A description of the accepted parameters follows.
|
A description of the accepted parameters follows.
|
||||||
|
|
||||||
@@ -2351,19 +2353,18 @@ range 0-64 pixels. Default 16.
|
|||||||
|
|
||||||
@item edge
|
@item edge
|
||||||
Specify how to generate pixels to fill blanks at the edge of the
|
Specify how to generate pixels to fill blanks at the edge of the
|
||||||
frame. An integer from 0 to 3 as follows:
|
frame. Available values are:
|
||||||
@table @option
|
@table @samp
|
||||||
@item 0
|
@item blank, 0
|
||||||
Fill zeroes at blank locations
|
Fill zeroes at blank locations
|
||||||
@item 1
|
@item original, 1
|
||||||
Original image at blank locations
|
Original image at blank locations
|
||||||
@item 2
|
@item clamp, 2
|
||||||
Extruded edge value at blank locations
|
Extruded edge value at blank locations
|
||||||
@item 3
|
@item mirror, 3
|
||||||
Mirrored edge at blank locations
|
Mirrored edge at blank locations
|
||||||
@end table
|
@end table
|
||||||
|
Default value is @samp{mirror}.
|
||||||
The default setting is mirror edge at blank locations.
|
|
||||||
|
|
||||||
@item blocksize
|
@item blocksize
|
||||||
Specify the blocksize to use for motion search. Range 4-128 pixels,
|
Specify the blocksize to use for motion search. Range 4-128 pixels,
|
||||||
@@ -2375,8 +2376,14 @@ the specified contrast (difference between darkest and lightest
|
|||||||
pixels) will be considered. Range 1-255, default 125.
|
pixels) will be considered. Range 1-255, default 125.
|
||||||
|
|
||||||
@item search
|
@item search
|
||||||
Specify the search strategy 0 = exhaustive search, 1 = less exhaustive
|
Specify the search strategy. Available values are:
|
||||||
search. Default - exhaustive search.
|
@table @samp
|
||||||
|
@item exhaustive, 0
|
||||||
|
Set exhaustive search
|
||||||
|
@item less, 1
|
||||||
|
Set less exhaustive search.
|
||||||
|
@end table
|
||||||
|
Default value is @samp{exhaustive}.
|
||||||
|
|
||||||
@item filename
|
@item filename
|
||||||
If set then a detailed log of the motion search is written to the
|
If set then a detailed log of the motion search is written to the
|
||||||
|
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
#define LIBAVFILTER_VERSION_MAJOR 3
|
#define LIBAVFILTER_VERSION_MAJOR 3
|
||||||
#define LIBAVFILTER_VERSION_MINOR 42
|
#define LIBAVFILTER_VERSION_MINOR 42
|
||||||
#define LIBAVFILTER_VERSION_MICRO 102
|
#define LIBAVFILTER_VERSION_MICRO 103
|
||||||
|
|
||||||
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
|
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
|
||||||
LIBAVFILTER_VERSION_MINOR, \
|
LIBAVFILTER_VERSION_MINOR, \
|
||||||
|
@@ -55,6 +55,7 @@
|
|||||||
#include "video.h"
|
#include "video.h"
|
||||||
#include "libavutil/common.h"
|
#include "libavutil/common.h"
|
||||||
#include "libavutil/mem.h"
|
#include "libavutil/mem.h"
|
||||||
|
#include "libavutil/opt.h"
|
||||||
#include "libavutil/pixdesc.h"
|
#include "libavutil/pixdesc.h"
|
||||||
#include "libavcodec/dsputil.h"
|
#include "libavcodec/dsputil.h"
|
||||||
|
|
||||||
@@ -86,7 +87,7 @@ typedef struct {
|
|||||||
} Transform;
|
} Transform;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
AVClass av_class;
|
const AVClass *class;
|
||||||
AVFilterBufferRef *ref; ///< Previous frame
|
AVFilterBufferRef *ref; ///< Previous frame
|
||||||
int rx; ///< Maximum horizontal shift
|
int rx; ///< Maximum horizontal shift
|
||||||
int ry; ///< Maximum vertical shift
|
int ry; ///< Maximum vertical shift
|
||||||
@@ -104,8 +105,35 @@ typedef struct {
|
|||||||
int ch;
|
int ch;
|
||||||
int cx;
|
int cx;
|
||||||
int cy;
|
int cy;
|
||||||
|
char *filename; ///< Motion search detailed log filename
|
||||||
} DeshakeContext;
|
} DeshakeContext;
|
||||||
|
|
||||||
|
#define OFFSET(x) offsetof(DeshakeContext, x)
|
||||||
|
#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
|
||||||
|
|
||||||
|
static const AVOption deshake_options[] = {
|
||||||
|
{ "x", "set x for the rectangular search area", OFFSET(cx), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS },
|
||||||
|
{ "y", "set y for the rectangular search area", OFFSET(cy), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS },
|
||||||
|
{ "w", "set width for the rectangular search area", OFFSET(cw), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS },
|
||||||
|
{ "h", "set height for the rectangular search area", OFFSET(ch), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS },
|
||||||
|
{ "rx", "set x for the rectangular search area", OFFSET(rx), AV_OPT_TYPE_INT, {.i64=16}, 0, 64, .flags = FLAGS },
|
||||||
|
{ "ry", "set y for the rectangular search area", OFFSET(ry), AV_OPT_TYPE_INT, {.i64=16}, 0, 64, .flags = FLAGS },
|
||||||
|
{ "edge", "set edge mode", OFFSET(edge), AV_OPT_TYPE_INT, {.i64=FILL_MIRROR}, FILL_BLANK, FILL_COUNT-1, FLAGS, "edge"},
|
||||||
|
{ "blank", "fill zeroes at blank locations", 0, AV_OPT_TYPE_CONST, {.i64=FILL_BLANK}, INT_MIN, INT_MAX, FLAGS, "edge" },
|
||||||
|
{ "original", "original image at blank locations", 0, AV_OPT_TYPE_CONST, {.i64=FILL_ORIGINAL}, INT_MIN, INT_MAX, FLAGS, "edge" },
|
||||||
|
{ "clamp", "extruded edge value at blank locations", 0, AV_OPT_TYPE_CONST, {.i64=FILL_CLAMP}, INT_MIN, INT_MAX, FLAGS, "edge" },
|
||||||
|
{ "mirror", "mirrored edge at blank locations", 0, AV_OPT_TYPE_CONST, {.i64=FILL_MIRROR}, INT_MIN, INT_MAX, FLAGS, "edge" },
|
||||||
|
{ "blocksize", "set motion search blocksize", OFFSET(blocksize), AV_OPT_TYPE_INT, {.i64=8}, 4, 128, .flags = FLAGS },
|
||||||
|
{ "contrast", "set contrast threshold for blocks", OFFSET(contrast), AV_OPT_TYPE_INT, {.i64=125}, 1, 255, .flags = FLAGS },
|
||||||
|
{ "search", "set search strategy", OFFSET(search), AV_OPT_TYPE_INT, {.i64=EXHAUSTIVE}, EXHAUSTIVE, SEARCH_COUNT-1, FLAGS, "smode" },
|
||||||
|
{ "exhaustive", "exhaustive search", 0, AV_OPT_TYPE_CONST, {.i64=EXHAUSTIVE}, INT_MIN, INT_MAX, FLAGS, "smode" },
|
||||||
|
{ "less", "less exhaustive search", 0, AV_OPT_TYPE_CONST, {.i64=SMART_EXHAUSTIVE}, INT_MIN, INT_MAX, FLAGS, "smode" },
|
||||||
|
{ "filename", "set motion search detailed log file name", OFFSET(filename), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
AVFILTER_DEFINE_CLASS(deshake);
|
||||||
|
|
||||||
static int cmp(const double *a, const double *b)
|
static int cmp(const double *a, const double *b)
|
||||||
{
|
{
|
||||||
return *a < *b ? -1 : ( *a > *b ? 1 : 0 );
|
return *a < *b ? -1 : ( *a > *b ? 1 : 0 );
|
||||||
@@ -334,40 +362,28 @@ static void find_motion(DeshakeContext *deshake, uint8_t *src1, uint8_t *src2,
|
|||||||
|
|
||||||
static av_cold int init(AVFilterContext *ctx, const char *args)
|
static av_cold int init(AVFilterContext *ctx, const char *args)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
DeshakeContext *deshake = ctx->priv;
|
DeshakeContext *deshake = ctx->priv;
|
||||||
char filename[256] = {0};
|
static const char *shorthand[] = {
|
||||||
|
"x", "y", "w", "h", "rx", "ry", "edge",
|
||||||
|
"blocksize", "contrast", "search", "filename",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
deshake->rx = 16;
|
deshake->refcount = 20; // XXX: add to options?
|
||||||
deshake->ry = 16;
|
|
||||||
deshake->edge = FILL_MIRROR;
|
|
||||||
deshake->blocksize = 8;
|
|
||||||
deshake->contrast = 125;
|
|
||||||
deshake->search = EXHAUSTIVE;
|
|
||||||
deshake->refcount = 20;
|
|
||||||
|
|
||||||
deshake->cw = -1;
|
deshake->class = &deshake_class;
|
||||||
deshake->ch = -1;
|
av_opt_set_defaults(deshake);
|
||||||
deshake->cx = -1;
|
|
||||||
deshake->cy = -1;
|
|
||||||
|
|
||||||
if (args) {
|
ret = av_opt_set_from_string(deshake, args, shorthand, "=", ":");
|
||||||
sscanf(args, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%255s",
|
if (ret < 0)
|
||||||
&deshake->cx, &deshake->cy, &deshake->cw, &deshake->ch,
|
return ret;
|
||||||
&deshake->rx, &deshake->ry, &deshake->edge,
|
|
||||||
&deshake->blocksize, &deshake->contrast, &deshake->search, filename);
|
|
||||||
|
|
||||||
deshake->blocksize /= 2;
|
deshake->blocksize /= 2;
|
||||||
|
deshake->blocksize = av_clip(deshake->blocksize, 4, 128);
|
||||||
|
|
||||||
deshake->rx = av_clip(deshake->rx, 0, 64);
|
if (deshake->filename)
|
||||||
deshake->ry = av_clip(deshake->ry, 0, 64);
|
deshake->fp = fopen(deshake->filename, "w");
|
||||||
deshake->edge = av_clip(deshake->edge, FILL_BLANK, FILL_COUNT - 1);
|
|
||||||
deshake->blocksize = av_clip(deshake->blocksize, 4, 128);
|
|
||||||
deshake->contrast = av_clip(deshake->contrast, 1, 255);
|
|
||||||
deshake->search = av_clip(deshake->search, EXHAUSTIVE, SEARCH_COUNT - 1);
|
|
||||||
|
|
||||||
}
|
|
||||||
if (*filename)
|
|
||||||
deshake->fp = fopen(filename, "w");
|
|
||||||
if (deshake->fp)
|
if (deshake->fp)
|
||||||
fwrite("Ori x, Avg x, Fin x, Ori y, Avg y, Fin y, Ori angle, Avg angle, Fin angle, Ori zoom, Avg zoom, Fin zoom\n", sizeof(char), 104, deshake->fp);
|
fwrite("Ori x, Avg x, Fin x, Ori y, Avg y, Fin y, Ori angle, Avg angle, Fin angle, Ori zoom, Avg zoom, Fin zoom\n", sizeof(char), 104, deshake->fp);
|
||||||
|
|
||||||
@@ -424,6 +440,7 @@ static av_cold void uninit(AVFilterContext *ctx)
|
|||||||
if (deshake->avctx)
|
if (deshake->avctx)
|
||||||
avcodec_close(deshake->avctx);
|
avcodec_close(deshake->avctx);
|
||||||
av_freep(&deshake->avctx);
|
av_freep(&deshake->avctx);
|
||||||
|
av_opt_free(deshake);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int filter_frame(AVFilterLink *link, AVFilterBufferRef *in)
|
static int filter_frame(AVFilterLink *link, AVFilterBufferRef *in)
|
||||||
@@ -565,4 +582,5 @@ AVFilter avfilter_vf_deshake = {
|
|||||||
.query_formats = query_formats,
|
.query_formats = query_formats,
|
||||||
.inputs = deshake_inputs,
|
.inputs = deshake_inputs,
|
||||||
.outputs = deshake_outputs,
|
.outputs = deshake_outputs,
|
||||||
|
.priv_class = &deshake_class,
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user