00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00026 #include "libavutil/eval.h"
00027 #include "libavutil/fifo.h"
00028 #include "libavutil/internal.h"
00029 #include "avfilter.h"
00030 #include "formats.h"
00031 #include "internal.h"
00032 #include "video.h"
00033
00034 #if CONFIG_AVCODEC
00035 #include "libavcodec/dsputil.h"
00036 #endif
00037
00038 static const char *const var_names[] = {
00039 "TB",
00040
00041 "pts",
00042 "start_pts",
00043 "prev_pts",
00044 "prev_selected_pts",
00045
00046 "t",
00047 "start_t",
00048 "prev_t",
00049 "prev_selected_t",
00050
00051 "pict_type",
00052 "I",
00053 "P",
00054 "B",
00055 "S",
00056 "SI",
00057 "SP",
00058 "BI",
00059
00060 "interlace_type",
00061 "PROGRESSIVE",
00062 "TOPFIRST",
00063 "BOTTOMFIRST",
00064
00065 "n",
00066 "selected_n",
00067 "prev_selected_n",
00068
00069 "key",
00070 "pos",
00071
00072 "scene",
00073
00074 NULL
00075 };
00076
00077 enum var_name {
00078 VAR_TB,
00079
00080 VAR_PTS,
00081 VAR_START_PTS,
00082 VAR_PREV_PTS,
00083 VAR_PREV_SELECTED_PTS,
00084
00085 VAR_T,
00086 VAR_START_T,
00087 VAR_PREV_T,
00088 VAR_PREV_SELECTED_T,
00089
00090 VAR_PICT_TYPE,
00091 VAR_PICT_TYPE_I,
00092 VAR_PICT_TYPE_P,
00093 VAR_PICT_TYPE_B,
00094 VAR_PICT_TYPE_S,
00095 VAR_PICT_TYPE_SI,
00096 VAR_PICT_TYPE_SP,
00097 VAR_PICT_TYPE_BI,
00098
00099 VAR_INTERLACE_TYPE,
00100 VAR_INTERLACE_TYPE_P,
00101 VAR_INTERLACE_TYPE_T,
00102 VAR_INTERLACE_TYPE_B,
00103
00104 VAR_N,
00105 VAR_SELECTED_N,
00106 VAR_PREV_SELECTED_N,
00107
00108 VAR_KEY,
00109 VAR_POS,
00110
00111 VAR_SCENE,
00112
00113 VAR_VARS_NB
00114 };
00115
00116 #define FIFO_SIZE 8
00117
00118 typedef struct {
00119 AVExpr *expr;
00120 double var_values[VAR_VARS_NB];
00121 int do_scene_detect;
00122 #if CONFIG_AVCODEC
00123 AVCodecContext *avctx;
00124 DSPContext c;
00125 double prev_mafd;
00126 #endif
00127 AVFilterBufferRef *prev_picref;
00128 double select;
00129 int cache_frames;
00130 AVFifoBuffer *pending_frames;
00131 } SelectContext;
00132
00133 static av_cold int init(AVFilterContext *ctx, const char *args)
00134 {
00135 SelectContext *select = ctx->priv;
00136 int ret;
00137
00138 if ((ret = av_expr_parse(&select->expr, args ? args : "1",
00139 var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
00140 av_log(ctx, AV_LOG_ERROR, "Error while parsing expression '%s'\n", args);
00141 return ret;
00142 }
00143
00144 select->pending_frames = av_fifo_alloc(FIFO_SIZE*sizeof(AVFilterBufferRef*));
00145 if (!select->pending_frames) {
00146 av_log(ctx, AV_LOG_ERROR, "Failed to allocate pending frames buffer.\n");
00147 return AVERROR(ENOMEM);
00148 }
00149
00150 select->do_scene_detect = args && strstr(args, "scene");
00151 if (select->do_scene_detect && !CONFIG_AVCODEC) {
00152 av_log(ctx, AV_LOG_ERROR, "Scene detection is not available without libavcodec.\n");
00153 return AVERROR(EINVAL);
00154 }
00155 return 0;
00156 }
00157
00158 #define INTERLACE_TYPE_P 0
00159 #define INTERLACE_TYPE_T 1
00160 #define INTERLACE_TYPE_B 2
00161
00162 static int config_input(AVFilterLink *inlink)
00163 {
00164 SelectContext *select = inlink->dst->priv;
00165
00166 select->var_values[VAR_N] = 0.0;
00167 select->var_values[VAR_SELECTED_N] = 0.0;
00168
00169 select->var_values[VAR_TB] = av_q2d(inlink->time_base);
00170
00171 select->var_values[VAR_PREV_PTS] = NAN;
00172 select->var_values[VAR_PREV_SELECTED_PTS] = NAN;
00173 select->var_values[VAR_PREV_SELECTED_T] = NAN;
00174 select->var_values[VAR_START_PTS] = NAN;
00175 select->var_values[VAR_START_T] = NAN;
00176
00177 select->var_values[VAR_PICT_TYPE_I] = AV_PICTURE_TYPE_I;
00178 select->var_values[VAR_PICT_TYPE_P] = AV_PICTURE_TYPE_P;
00179 select->var_values[VAR_PICT_TYPE_B] = AV_PICTURE_TYPE_B;
00180 select->var_values[VAR_PICT_TYPE_SI] = AV_PICTURE_TYPE_SI;
00181 select->var_values[VAR_PICT_TYPE_SP] = AV_PICTURE_TYPE_SP;
00182
00183 select->var_values[VAR_INTERLACE_TYPE_P] = INTERLACE_TYPE_P;
00184 select->var_values[VAR_INTERLACE_TYPE_T] = INTERLACE_TYPE_T;
00185 select->var_values[VAR_INTERLACE_TYPE_B] = INTERLACE_TYPE_B;
00186
00187 if (CONFIG_AVCODEC && select->do_scene_detect) {
00188 select->avctx = avcodec_alloc_context3(NULL);
00189 if (!select->avctx)
00190 return AVERROR(ENOMEM);
00191 dsputil_init(&select->c, select->avctx);
00192 }
00193 return 0;
00194 }
00195
00196 #if CONFIG_AVCODEC
00197 static double get_scene_score(AVFilterContext *ctx, AVFilterBufferRef *picref)
00198 {
00199 double ret = 0;
00200 SelectContext *select = ctx->priv;
00201 AVFilterBufferRef *prev_picref = select->prev_picref;
00202
00203 if (prev_picref &&
00204 picref->video->h == prev_picref->video->h &&
00205 picref->video->w == prev_picref->video->w &&
00206 picref->linesize[0] == prev_picref->linesize[0]) {
00207 int x, y;
00208 int64_t sad;
00209 double mafd, diff;
00210 uint8_t *p1 = picref->data[0];
00211 uint8_t *p2 = prev_picref->data[0];
00212 const int linesize = picref->linesize[0];
00213
00214 for (sad = y = 0; y < picref->video->h; y += 8)
00215 for (x = 0; x < linesize; x += 8)
00216 sad += select->c.sad[1](select,
00217 p1 + y * linesize + x,
00218 p2 + y * linesize + x,
00219 linesize, 8);
00220 emms_c();
00221 mafd = sad / (picref->video->h * picref->video->w * 3);
00222 diff = fabs(mafd - select->prev_mafd);
00223 ret = av_clipf(FFMIN(mafd, diff) / 100., 0, 1);
00224 select->prev_mafd = mafd;
00225 avfilter_unref_buffer(prev_picref);
00226 }
00227 select->prev_picref = avfilter_ref_buffer(picref, ~0);
00228 return ret;
00229 }
00230 #endif
00231
00232 #define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d))
00233 #define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
00234
00235 static int select_frame(AVFilterContext *ctx, AVFilterBufferRef *picref)
00236 {
00237 SelectContext *select = ctx->priv;
00238 AVFilterLink *inlink = ctx->inputs[0];
00239 double res;
00240
00241 if (CONFIG_AVCODEC && select->do_scene_detect)
00242 select->var_values[VAR_SCENE] = get_scene_score(ctx, picref);
00243 if (isnan(select->var_values[VAR_START_PTS]))
00244 select->var_values[VAR_START_PTS] = TS2D(picref->pts);
00245 if (isnan(select->var_values[VAR_START_T]))
00246 select->var_values[VAR_START_T] = TS2D(picref->pts) * av_q2d(inlink->time_base);
00247
00248 select->var_values[VAR_PTS] = TS2D(picref->pts);
00249 select->var_values[VAR_T ] = TS2D(picref->pts) * av_q2d(inlink->time_base);
00250 select->var_values[VAR_POS] = picref->pos == -1 ? NAN : picref->pos;
00251 select->var_values[VAR_PREV_PTS] = TS2D(picref ->pts);
00252
00253 select->var_values[VAR_INTERLACE_TYPE] =
00254 !picref->video->interlaced ? INTERLACE_TYPE_P :
00255 picref->video->top_field_first ? INTERLACE_TYPE_T : INTERLACE_TYPE_B;
00256 select->var_values[VAR_PICT_TYPE] = picref->video->pict_type;
00257
00258 res = av_expr_eval(select->expr, select->var_values, NULL);
00259 av_log(inlink->dst, AV_LOG_DEBUG,
00260 "n:%d pts:%d t:%f pos:%d interlace_type:%c key:%d pict_type:%c "
00261 "-> select:%f\n",
00262 (int)select->var_values[VAR_N],
00263 (int)select->var_values[VAR_PTS],
00264 select->var_values[VAR_T],
00265 (int)select->var_values[VAR_POS],
00266 select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_P ? 'P' :
00267 select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_T ? 'T' :
00268 select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_B ? 'B' : '?',
00269 (int)select->var_values[VAR_KEY],
00270 av_get_picture_type_char(select->var_values[VAR_PICT_TYPE]),
00271 res);
00272
00273 select->var_values[VAR_N] += 1.0;
00274
00275 if (res) {
00276 select->var_values[VAR_PREV_SELECTED_N] = select->var_values[VAR_N];
00277 select->var_values[VAR_PREV_SELECTED_PTS] = select->var_values[VAR_PTS];
00278 select->var_values[VAR_PREV_SELECTED_T] = select->var_values[VAR_T];
00279 select->var_values[VAR_SELECTED_N] += 1.0;
00280 }
00281 return res;
00282 }
00283
00284 static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
00285 {
00286 SelectContext *select = inlink->dst->priv;
00287
00288 select->select = select_frame(inlink->dst, picref);
00289 if (select->select) {
00290 AVFilterBufferRef *buf_out;
00291
00292 if (select->cache_frames) {
00293 if (!av_fifo_space(select->pending_frames))
00294 av_log(inlink->dst, AV_LOG_ERROR,
00295 "Buffering limit reached, cannot cache more frames\n");
00296 else
00297 av_fifo_generic_write(select->pending_frames, &picref,
00298 sizeof(picref), NULL);
00299 return 0;
00300 }
00301 buf_out = avfilter_ref_buffer(picref, ~0);
00302 if (!buf_out)
00303 return AVERROR(ENOMEM);
00304 return ff_start_frame(inlink->dst->outputs[0], buf_out);
00305 }
00306
00307 return 0;
00308 }
00309
00310 static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
00311 {
00312 SelectContext *select = inlink->dst->priv;
00313
00314 if (select->select && !select->cache_frames)
00315 return ff_draw_slice(inlink->dst->outputs[0], y, h, slice_dir);
00316 return 0;
00317 }
00318
00319 static int end_frame(AVFilterLink *inlink)
00320 {
00321 SelectContext *select = inlink->dst->priv;
00322
00323 if (select->select) {
00324 if (select->cache_frames)
00325 return 0;
00326 return ff_end_frame(inlink->dst->outputs[0]);
00327 }
00328 return 0;
00329 }
00330
00331 static int request_frame(AVFilterLink *outlink)
00332 {
00333 AVFilterContext *ctx = outlink->src;
00334 SelectContext *select = ctx->priv;
00335 AVFilterLink *inlink = outlink->src->inputs[0];
00336 select->select = 0;
00337
00338 if (av_fifo_size(select->pending_frames)) {
00339 AVFilterBufferRef *picref;
00340 int ret;
00341
00342 av_fifo_generic_read(select->pending_frames, &picref, sizeof(picref), NULL);
00343 if ((ret = ff_start_frame(outlink, picref)) < 0 ||
00344 (ret = ff_draw_slice(outlink, 0, outlink->h, 1)) < 0 ||
00345 (ret = ff_end_frame(outlink)) < 0);
00346
00347 return ret;
00348 }
00349
00350 while (!select->select) {
00351 int ret = ff_request_frame(inlink);
00352 if (ret < 0)
00353 return ret;
00354 }
00355
00356 return 0;
00357 }
00358
00359 static int poll_frame(AVFilterLink *outlink)
00360 {
00361 SelectContext *select = outlink->src->priv;
00362 AVFilterLink *inlink = outlink->src->inputs[0];
00363 int count, ret;
00364
00365 if (!av_fifo_size(select->pending_frames)) {
00366 if ((count = ff_poll_frame(inlink)) <= 0)
00367 return count;
00368
00369 select->cache_frames = 1;
00370 while (count-- && av_fifo_space(select->pending_frames)) {
00371 ret = ff_request_frame(inlink);
00372 if (ret < 0)
00373 break;
00374 }
00375 select->cache_frames = 0;
00376 }
00377
00378 return av_fifo_size(select->pending_frames)/sizeof(AVFilterBufferRef *);
00379 }
00380
00381 static av_cold void uninit(AVFilterContext *ctx)
00382 {
00383 SelectContext *select = ctx->priv;
00384 AVFilterBufferRef *picref;
00385
00386 av_expr_free(select->expr);
00387 select->expr = NULL;
00388
00389 while (select->pending_frames &&
00390 av_fifo_generic_read(select->pending_frames, &picref, sizeof(picref), NULL) == sizeof(picref))
00391 avfilter_unref_buffer(picref);
00392 av_fifo_free(select->pending_frames);
00393 select->pending_frames = NULL;
00394
00395 if (select->do_scene_detect) {
00396 avfilter_unref_bufferp(&select->prev_picref);
00397 if (select->avctx) {
00398 avcodec_close(select->avctx);
00399 av_freep(&select->avctx);
00400 }
00401 }
00402 }
00403
00404 static int query_formats(AVFilterContext *ctx)
00405 {
00406 SelectContext *select = ctx->priv;
00407
00408 if (!select->do_scene_detect) {
00409 return ff_default_query_formats(ctx);
00410 } else {
00411 static const enum PixelFormat pix_fmts[] = {
00412 PIX_FMT_RGB24, PIX_FMT_BGR24,
00413 PIX_FMT_NONE
00414 };
00415 ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
00416 }
00417 return 0;
00418 }
00419
00420 AVFilter avfilter_vf_select = {
00421 .name = "select",
00422 .description = NULL_IF_CONFIG_SMALL("Select frames to pass in output."),
00423 .init = init,
00424 .uninit = uninit,
00425 .query_formats = query_formats,
00426
00427 .priv_size = sizeof(SelectContext),
00428
00429 .inputs = (const AVFilterPad[]) {{ .name = "default",
00430 .type = AVMEDIA_TYPE_VIDEO,
00431 .get_video_buffer = ff_null_get_video_buffer,
00432 .min_perms = AV_PERM_PRESERVE,
00433 .config_props = config_input,
00434 .start_frame = start_frame,
00435 .draw_slice = draw_slice,
00436 .end_frame = end_frame },
00437 { .name = NULL }},
00438 .outputs = (const AVFilterPad[]) {{ .name = "default",
00439 .type = AVMEDIA_TYPE_VIDEO,
00440 .poll_frame = poll_frame,
00441 .request_frame = request_frame, },
00442 { .name = NULL}},
00443 };