|
|
|
@ -28,16 +28,13 @@ |
|
|
|
|
#include "libavutil/fifo.h" |
|
|
|
|
#include "libavutil/internal.h" |
|
|
|
|
#include "libavutil/opt.h" |
|
|
|
|
#include "libavutil/pixelutils.h" |
|
|
|
|
#include "avfilter.h" |
|
|
|
|
#include "audio.h" |
|
|
|
|
#include "formats.h" |
|
|
|
|
#include "internal.h" |
|
|
|
|
#include "video.h" |
|
|
|
|
|
|
|
|
|
#if CONFIG_AVCODEC |
|
|
|
|
#include "libavcodec/dsputil.h" |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
static const char *const var_names[] = { |
|
|
|
|
"TB", ///< timebase
|
|
|
|
|
|
|
|
|
@ -144,11 +141,8 @@ typedef struct SelectContext { |
|
|
|
|
AVExpr *expr; |
|
|
|
|
double var_values[VAR_VARS_NB]; |
|
|
|
|
int do_scene_detect; ///< 1 if the expression requires scene detection variables, 0 otherwise
|
|
|
|
|
#if CONFIG_AVCODEC |
|
|
|
|
AVCodecContext *avctx; ///< codec context required for the DSPContext (scene detect only)
|
|
|
|
|
DSPContext c; ///< context providing optimized SAD methods (scene detect only)
|
|
|
|
|
av_pixelutils_sad_fn sad; ///< Sum of the absolute difference function (scene detect only)
|
|
|
|
|
double prev_mafd; ///< previous MAFD (scene detect only)
|
|
|
|
|
#endif |
|
|
|
|
AVFrame *prev_picref; ///< previous frame (scene detect only)
|
|
|
|
|
double select; |
|
|
|
|
int select_out; ///< mark the selected output pad index
|
|
|
|
@ -240,18 +234,14 @@ static int config_input(AVFilterLink *inlink) |
|
|
|
|
select->var_values[VAR_SAMPLE_RATE] = |
|
|
|
|
inlink->type == AVMEDIA_TYPE_AUDIO ? inlink->sample_rate : NAN; |
|
|
|
|
|
|
|
|
|
#if CONFIG_AVCODEC |
|
|
|
|
if (select->do_scene_detect) { |
|
|
|
|
select->avctx = avcodec_alloc_context3(NULL); |
|
|
|
|
if (!select->avctx) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
avpriv_dsputil_init(&select->c, select->avctx); |
|
|
|
|
select->sad = av_pixelutils_get_sad_fn(3, 3, 2, select); // 8x8 both sources aligned
|
|
|
|
|
if (!select->sad) |
|
|
|
|
return AVERROR(EINVAL); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if CONFIG_AVCODEC |
|
|
|
|
static double get_scene_score(AVFilterContext *ctx, AVFrame *frame) |
|
|
|
|
{ |
|
|
|
|
double ret = 0; |
|
|
|
@ -259,24 +249,23 @@ static double get_scene_score(AVFilterContext *ctx, AVFrame *frame) |
|
|
|
|
AVFrame *prev_picref = select->prev_picref; |
|
|
|
|
|
|
|
|
|
if (prev_picref && |
|
|
|
|
frame->height == prev_picref->height && |
|
|
|
|
frame->width == prev_picref->width && |
|
|
|
|
frame->linesize[0] == prev_picref->linesize[0]) { |
|
|
|
|
frame->height == prev_picref->height && |
|
|
|
|
frame->width == prev_picref->width) { |
|
|
|
|
int x, y, nb_sad = 0; |
|
|
|
|
int64_t sad = 0; |
|
|
|
|
double mafd, diff; |
|
|
|
|
uint8_t *p1 = frame->data[0]; |
|
|
|
|
uint8_t *p2 = prev_picref->data[0]; |
|
|
|
|
const int linesize = frame->linesize[0]; |
|
|
|
|
const int p1_linesize = frame->linesize[0]; |
|
|
|
|
const int p2_linesize = prev_picref->linesize[0]; |
|
|
|
|
|
|
|
|
|
for (y = 0; y < frame->height - 8; y += 8) { |
|
|
|
|
for (x = 0; x < frame->width*3 - 8; x += 8) { |
|
|
|
|
sad += select->c.sad[1](NULL, p1 + x, p2 + x, |
|
|
|
|
linesize, 8); |
|
|
|
|
sad += select->sad(p1 + x, p1_linesize, p2 + x, p2_linesize); |
|
|
|
|
nb_sad += 8 * 8; |
|
|
|
|
} |
|
|
|
|
p1 += 8 * linesize; |
|
|
|
|
p2 += 8 * linesize; |
|
|
|
|
p1 += 8 * p1_linesize; |
|
|
|
|
p2 += 8 * p2_linesize; |
|
|
|
|
} |
|
|
|
|
emms_c(); |
|
|
|
|
mafd = nb_sad ? (double)sad / nb_sad : 0; |
|
|
|
@ -288,7 +277,6 @@ static double get_scene_score(AVFilterContext *ctx, AVFrame *frame) |
|
|
|
|
select->prev_picref = av_frame_clone(frame); |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d)) |
|
|
|
|
#define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts)) |
|
|
|
@ -320,7 +308,6 @@ static void select_frame(AVFilterContext *ctx, AVFrame *frame) |
|
|
|
|
!frame->interlaced_frame ? INTERLACE_TYPE_P : |
|
|
|
|
frame->top_field_first ? INTERLACE_TYPE_T : INTERLACE_TYPE_B; |
|
|
|
|
select->var_values[VAR_PICT_TYPE] = frame->pict_type; |
|
|
|
|
#if CONFIG_AVCODEC |
|
|
|
|
if (select->do_scene_detect) { |
|
|
|
|
char buf[32]; |
|
|
|
|
select->var_values[VAR_SCENE] = get_scene_score(ctx, frame); |
|
|
|
@ -328,7 +315,6 @@ static void select_frame(AVFilterContext *ctx, AVFrame *frame) |
|
|
|
|
snprintf(buf, sizeof(buf), "%f", select->var_values[VAR_SCENE]); |
|
|
|
|
av_dict_set(avpriv_frame_get_metadatap(frame), "lavfi.scene_score", buf, 0); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -418,15 +404,9 @@ static av_cold void uninit(AVFilterContext *ctx) |
|
|
|
|
for (i = 0; i < ctx->nb_outputs; i++) |
|
|
|
|
av_freep(&ctx->output_pads[i].name); |
|
|
|
|
|
|
|
|
|
#if CONFIG_AVCODEC |
|
|
|
|
if (select->do_scene_detect) { |
|
|
|
|
av_frame_free(&select->prev_picref); |
|
|
|
|
if (select->avctx) { |
|
|
|
|
avcodec_close(select->avctx); |
|
|
|
|
av_freep(&select->avctx); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int query_formats(AVFilterContext *ctx) |
|
|
|
@ -495,17 +475,11 @@ AVFILTER_DEFINE_CLASS(select); |
|
|
|
|
|
|
|
|
|
static av_cold int select_init(AVFilterContext *ctx) |
|
|
|
|
{ |
|
|
|
|
SelectContext *select = ctx->priv; |
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
if ((ret = init(ctx)) < 0) |
|
|
|
|
return ret; |
|
|
|
|
|
|
|
|
|
if (select->do_scene_detect && !CONFIG_AVCODEC) { |
|
|
|
|
av_log(ctx, AV_LOG_ERROR, "Scene detection is not available without libavcodec.\n"); |
|
|
|
|
return AVERROR(EINVAL); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|