Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
F
ffmpeg
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
ffmpeg
Commits
07586b68
Commit
07586b68
authored
May 07, 2011
by
Stefano Sabatini
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
lavfi: add select filter
Address trac issue #92.
parent
3c2c52ba
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
471 additions
and
1 deletion
+471
-1
Changelog
Changelog
+1
-0
filters.texi
doc/filters.texi
+116
-0
Makefile
libavfilter/Makefile
+1
-0
allfilters.c
libavfilter/allfilters.c
+1
-0
avfilter.h
libavfilter/avfilter.h
+1
-1
vf_select.c
libavfilter/vf_select.c
+351
-0
No files found.
Changelog
View file @
07586b68
...
...
@@ -18,6 +18,7 @@ version <next>:
- 9bit and 10bit H.264 decoding
- 9bit and 10bit FFV1 encoding / decoding
- split filter added
- select filter added
version 0.7_beta1:
...
...
doc/filters.texi
View file @
07586b68
...
...
@@ -1163,6 +1163,122 @@ scale="trunc(3/2*iw/hsub)*hsub:trunc(3/2*ih/vsub)*vsub"
scale='min(500\, iw*3/2):-1'
@end example
@section select
Select frames to pass in output.
It accepts in input an expression, which is evaluated for each input
frame. If the expression is evaluated to a non-zero value, the frame
is selected and passed to the output, otherwise it is discarded.
The expression can contain the following constants:
@table @option
@item PI
Greek PI
@item PHI
golden ratio
@item E
Euler number
@item n
the sequential number of the filtered frame, starting from 0
@item selected_n
the sequential number of the selected frame, starting from 0
@item prev_selected_n
the sequential number of the last selected frame, NAN if undefined
@item TB
timebase of the input timestamps
@item pts
the PTS (Presentation TimeStamp) of the filtered video frame,
expressed in @var{TB} units, NAN if undefined
@item t
the PTS (Presentation TimeStamp) of the filtered video frame,
expressed in seconds, NAN if undefined
@item prev_pts
the PTS of the previously filtered video frame, NAN if undefined
@item prev_selected_pts
the PTS of the last previously filtered video frame, NAN if undefined
@item prev_selected_t
the PTS of the last previously selected video frame, NAN if undefined
@item start_pts
the PTS of the first video frame in the video, NAN if undefined
@item start_t
the time of the first video frame in the video, NAN if undefined
@item pict_type
the picture type of the filtered frame, can assume one of the following
values:
@table @option
@item PICT_TYPE_I
@item PICT_TYPE_P
@item PICT_TYPE_B
@item PICT_TYPE_S
@item PICT_TYPE_SI
@item PICT_TYPE_SP
@item PICT_TYPE_BI
@end table
@item interlace_type
the frame interlace type, can assume one of the following values:
@table @option
@item INTERLACE_TYPE_P
the frame is progressive (not interlaced)
@item INTERLACE_TYPE_T
the frame is top-field-first
@item INTERLACE_TYPE_B
the frame is bottom-field-first
@end table
@item key
1 if the filtered frame is a key-frame, 0 otherwise
@item pos
the position in the file of the filtered frame, -1 if the information
is not available (e.g. for synthetic video)
@end table
The default value of the select expression is "1".
Some examples follow:
@example
# select all frames in input
select
# the above is the same as:
select=1
# skip all frames:
select=0
# select only I-frames
select='eq(pict_type\,PICT_TYPE_I)'
# select one frame every 100
select='not(mod(n\,100))'
# select only frames contained in the 10-20 time interval
select='gte(t\,10)*lte(t\,20)'
# select only I frames contained in the 10-20 time interval
select='gte(t\,10)*lte(t\,20)*eq(pict_type\,PICT_TYPE_I)'
# select frames with a minimum distance of 10 seconds
select='isnan(prev_selected_t)+gte(t-prev_selected_t\,10)'
@end example
@anchor{setdar}
@section setdar
...
...
libavfilter/Makefile
View file @
07586b68
...
...
@@ -46,6 +46,7 @@ OBJS-$(CONFIG_OVERLAY_FILTER) += vf_overlay.o
OBJS-$(CONFIG_PAD_FILTER)
+=
vf_pad.o
OBJS-$(CONFIG_PIXDESCTEST_FILTER)
+=
vf_pixdesctest.o
OBJS-$(CONFIG_SCALE_FILTER)
+=
vf_scale.o
OBJS-$(CONFIG_SELECT_FILTER)
+=
vf_select.o
OBJS-$(CONFIG_SETDAR_FILTER)
+=
vf_aspect.o
OBJS-$(CONFIG_SETPTS_FILTER)
+=
vf_setpts.o
OBJS-$(CONFIG_SETSAR_FILTER)
+=
vf_aspect.o
...
...
libavfilter/allfilters.c
View file @
07586b68
...
...
@@ -62,6 +62,7 @@ void avfilter_register_all(void)
REGISTER_FILTER
(
PAD
,
pad
,
vf
);
REGISTER_FILTER
(
PIXDESCTEST
,
pixdesctest
,
vf
);
REGISTER_FILTER
(
SCALE
,
scale
,
vf
);
REGISTER_FILTER
(
SELECT
,
select
,
vf
);
REGISTER_FILTER
(
SETDAR
,
setdar
,
vf
);
REGISTER_FILTER
(
SETPTS
,
setpts
,
vf
);
REGISTER_FILTER
(
SETSAR
,
setsar
,
vf
);
...
...
libavfilter/avfilter.h
View file @
07586b68
...
...
@@ -26,7 +26,7 @@
#include "libavutil/samplefmt.h"
#define LIBAVFILTER_VERSION_MAJOR 2
#define LIBAVFILTER_VERSION_MINOR 1
0
#define LIBAVFILTER_VERSION_MINOR 1
1
#define LIBAVFILTER_VERSION_MICRO 0
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
...
...
libavfilter/vf_select.c
0 → 100644
View file @
07586b68
/*
* Copyright (c) 2011 Stefano Sabatini
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* filter for selecting which frame passes in the filterchain
*/
#include "libavutil/eval.h"
#include "libavutil/fifo.h"
#include "avfilter.h"
static
const
char
*
var_names
[]
=
{
"E"
,
///< Euler number
"PHI"
,
///< golden ratio
"PI"
,
///< greek pi
"TB"
,
///< timebase
"pts"
,
///< original pts in the file of the frame
"start_pts"
,
///< first PTS in the stream, expressed in TB units
"prev_pts"
,
///< previous frame PTS
"prev_selected_pts"
,
///< previous selected frame PTS
"t"
,
///< first PTS in seconds
"start_t"
,
///< first PTS in the stream, expressed in seconds
"prev_t"
,
///< previous frame time
"prev_selected_t"
,
///< previously selected time
"pict_type"
,
///< the type of picture in the movie
"PICT_TYPE_I"
,
"PICT_TYPE_P"
,
"PICT_TYPE_B"
,
"PICT_TYPE_S"
,
"PICT_TYPE_SI"
,
"PICT_TYPE_SP"
,
"PICT_TYPE_BI"
,
"interlace_type"
,
///< the frame interlace type
"INTERLACE_TYPE_P"
,
"INTERLACE_TYPE_T"
,
"INTERLACE_TYPE_B"
,
"n"
,
///< frame number (starting from zero)
"selected_n"
,
///< selected frame number (starting from zero)
"prev_selected_n"
,
///< number of the last selected frame
"key"
,
///< tell if the frame is a key frame
"pos"
,
///< original position in the file of the frame
NULL
};
enum
var_name
{
VAR_E
,
VAR_PHI
,
VAR_PI
,
VAR_TB
,
VAR_PTS
,
VAR_START_PTS
,
VAR_PREV_PTS
,
VAR_PREV_SELECTED_PTS
,
VAR_T
,
VAR_START_T
,
VAR_PREV_T
,
VAR_PREV_SELECTED_T
,
VAR_PICT_TYPE
,
VAR_PICT_TYPE_I
,
VAR_PICT_TYPE_P
,
VAR_PICT_TYPE_B
,
VAR_PICT_TYPE_S
,
VAR_PICT_TYPE_SI
,
VAR_PICT_TYPE_SP
,
VAR_PICT_TYPE_BI
,
VAR_INTERLACE_TYPE
,
VAR_INTERLACE_TYPE_P
,
VAR_INTERLACE_TYPE_T
,
VAR_INTERLACE_TYPE_B
,
VAR_N
,
VAR_SELECTED_N
,
VAR_PREV_SELECTED_N
,
VAR_KEY
,
VAR_POS
,
VAR_VARS_NB
};
#define FIFO_SIZE 8
typedef
struct
{
AVExpr
*
expr
;
double
var_values
[
VAR_VARS_NB
];
double
select
;
int
cache_frames
;
AVFifoBuffer
*
pending_frames
;
///< FIFO buffer of video frames
}
SelectContext
;
static
av_cold
int
init
(
AVFilterContext
*
ctx
,
const
char
*
args
,
void
*
opaque
)
{
SelectContext
*
select
=
ctx
->
priv
;
int
ret
;
if
((
ret
=
av_expr_parse
(
&
select
->
expr
,
args
?
args
:
"1"
,
var_names
,
NULL
,
NULL
,
NULL
,
NULL
,
0
,
ctx
))
<
0
)
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"Error while parsing expression '%s'
\n
"
,
args
);
return
ret
;
}
select
->
pending_frames
=
av_fifo_alloc
(
FIFO_SIZE
*
sizeof
(
AVFilterBufferRef
*
));
if
(
!
select
->
pending_frames
)
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"Failed to allocate pending frames buffer.
\n
"
);
return
AVERROR
(
ENOMEM
);
}
return
0
;
}
#define INTERLACE_TYPE_P 0
#define INTERLACE_TYPE_T 1
#define INTERLACE_TYPE_B 2
static
int
config_input
(
AVFilterLink
*
inlink
)
{
SelectContext
*
select
=
inlink
->
dst
->
priv
;
select
->
var_values
[
VAR_E
]
=
M_E
;
select
->
var_values
[
VAR_PHI
]
=
M_PHI
;
select
->
var_values
[
VAR_PI
]
=
M_PI
;
select
->
var_values
[
VAR_N
]
=
0
.
0
;
select
->
var_values
[
VAR_SELECTED_N
]
=
0
.
0
;
select
->
var_values
[
VAR_TB
]
=
av_q2d
(
inlink
->
time_base
);
select
->
var_values
[
VAR_PREV_PTS
]
=
NAN
;
select
->
var_values
[
VAR_PREV_SELECTED_PTS
]
=
NAN
;
select
->
var_values
[
VAR_PREV_SELECTED_T
]
=
NAN
;
select
->
var_values
[
VAR_START_PTS
]
=
NAN
;
select
->
var_values
[
VAR_START_T
]
=
NAN
;
select
->
var_values
[
VAR_PICT_TYPE_I
]
=
AV_PICTURE_TYPE_I
;
select
->
var_values
[
VAR_PICT_TYPE_P
]
=
AV_PICTURE_TYPE_P
;
select
->
var_values
[
VAR_PICT_TYPE_B
]
=
AV_PICTURE_TYPE_B
;
select
->
var_values
[
VAR_PICT_TYPE_SI
]
=
AV_PICTURE_TYPE_SI
;
select
->
var_values
[
VAR_PICT_TYPE_SP
]
=
AV_PICTURE_TYPE_SP
;
select
->
var_values
[
VAR_INTERLACE_TYPE_P
]
=
INTERLACE_TYPE_P
;
select
->
var_values
[
VAR_INTERLACE_TYPE_T
]
=
INTERLACE_TYPE_T
;
select
->
var_values
[
VAR_INTERLACE_TYPE_B
]
=
INTERLACE_TYPE_B
;;
return
0
;
}
#define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d))
#define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
static
int
select_frame
(
AVFilterContext
*
ctx
,
AVFilterBufferRef
*
picref
)
{
SelectContext
*
select
=
ctx
->
priv
;
AVFilterLink
*
inlink
=
ctx
->
inputs
[
0
];
double
res
;
if
(
isnan
(
select
->
var_values
[
VAR_START_PTS
]))
select
->
var_values
[
VAR_START_PTS
]
=
TS2D
(
picref
->
pts
);
select
->
var_values
[
VAR_PTS
]
=
TS2D
(
picref
->
pts
);
select
->
var_values
[
VAR_T
]
=
picref
->
pts
*
av_q2d
(
inlink
->
time_base
);
select
->
var_values
[
VAR_POS
]
=
picref
->
pos
==
-
1
?
NAN
:
picref
->
pos
;
select
->
var_values
[
VAR_PREV_PTS
]
=
TS2D
(
picref
->
pts
);
select
->
var_values
[
VAR_INTERLACE_TYPE
]
=
!
picref
->
video
->
interlaced
?
INTERLACE_TYPE_P
:
picref
->
video
->
top_field_first
?
INTERLACE_TYPE_T
:
INTERLACE_TYPE_B
;
select
->
var_values
[
VAR_PICT_TYPE
]
=
picref
->
video
->
pict_type
;
res
=
av_expr_eval
(
select
->
expr
,
select
->
var_values
,
NULL
);
av_log
(
inlink
->
dst
,
AV_LOG_DEBUG
,
"n:%d pts:%d t:%f pos:%d interlace_type:%c key:%d pict_type:%c "
"-> select:%f
\n
"
,
(
int
)
select
->
var_values
[
VAR_N
],
(
int
)
select
->
var_values
[
VAR_PTS
],
select
->
var_values
[
VAR_T
],
(
int
)
select
->
var_values
[
VAR_POS
],
select
->
var_values
[
VAR_INTERLACE_TYPE
]
==
INTERLACE_TYPE_P
?
'P'
:
select
->
var_values
[
VAR_INTERLACE_TYPE
]
==
INTERLACE_TYPE_T
?
'T'
:
select
->
var_values
[
VAR_INTERLACE_TYPE
]
==
INTERLACE_TYPE_B
?
'B'
:
'?'
,
(
int
)
select
->
var_values
[
VAR_KEY
],
av_get_picture_type_char
(
select
->
var_values
[
VAR_PICT_TYPE
]),
res
);
select
->
var_values
[
VAR_N
]
+=
1
.
0
;
if
(
res
)
{
select
->
var_values
[
VAR_PREV_SELECTED_N
]
=
select
->
var_values
[
VAR_N
];
select
->
var_values
[
VAR_PREV_SELECTED_PTS
]
=
select
->
var_values
[
VAR_PTS
];
select
->
var_values
[
VAR_PREV_SELECTED_T
]
=
select
->
var_values
[
VAR_T
];
select
->
var_values
[
VAR_SELECTED_N
]
+=
1
.
0
;
}
return
res
;
}
static
void
start_frame
(
AVFilterLink
*
inlink
,
AVFilterBufferRef
*
picref
)
{
SelectContext
*
select
=
inlink
->
dst
->
priv
;
select
->
select
=
select_frame
(
inlink
->
dst
,
picref
);
if
(
select
->
select
)
{
/* frame was requested through poll_frame */
if
(
select
->
cache_frames
)
{
if
(
!
av_fifo_space
(
select
->
pending_frames
))
av_log
(
inlink
->
dst
,
AV_LOG_ERROR
,
"Buffering limit reached, cannot cache more frames
\n
"
);
else
av_fifo_generic_write
(
select
->
pending_frames
,
&
picref
,
sizeof
(
picref
),
NULL
);
return
;
}
avfilter_start_frame
(
inlink
->
dst
->
outputs
[
0
],
avfilter_ref_buffer
(
picref
,
~
0
));
}
}
static
void
draw_slice
(
AVFilterLink
*
inlink
,
int
y
,
int
h
,
int
slice_dir
)
{
SelectContext
*
select
=
inlink
->
dst
->
priv
;
if
(
select
->
select
&&
!
select
->
cache_frames
)
avfilter_draw_slice
(
inlink
->
dst
->
outputs
[
0
],
y
,
h
,
slice_dir
);
}
static
void
end_frame
(
AVFilterLink
*
inlink
)
{
SelectContext
*
select
=
inlink
->
dst
->
priv
;
AVFilterBufferRef
*
picref
=
inlink
->
cur_buf
;
if
(
select
->
select
)
{
if
(
select
->
cache_frames
)
return
;
avfilter_end_frame
(
inlink
->
dst
->
outputs
[
0
]);
}
avfilter_unref_buffer
(
picref
);
}
static
int
request_frame
(
AVFilterLink
*
outlink
)
{
AVFilterContext
*
ctx
=
outlink
->
src
;
SelectContext
*
select
=
ctx
->
priv
;
AVFilterLink
*
inlink
=
outlink
->
src
->
inputs
[
0
];
select
->
select
=
0
;
if
(
av_fifo_size
(
select
->
pending_frames
))
{
AVFilterBufferRef
*
picref
;
av_fifo_generic_read
(
select
->
pending_frames
,
&
picref
,
sizeof
(
picref
),
NULL
);
avfilter_start_frame
(
outlink
,
avfilter_ref_buffer
(
picref
,
~
0
));
avfilter_draw_slice
(
outlink
,
0
,
outlink
->
h
,
1
);
avfilter_end_frame
(
outlink
);
avfilter_unref_buffer
(
picref
);
return
0
;
}
while
(
!
select
->
select
)
{
int
ret
=
avfilter_request_frame
(
inlink
);
if
(
ret
<
0
)
return
ret
;
}
return
0
;
}
static
int
poll_frame
(
AVFilterLink
*
outlink
)
{
SelectContext
*
select
=
outlink
->
src
->
priv
;
AVFilterLink
*
inlink
=
outlink
->
src
->
inputs
[
0
];
int
count
,
ret
;
if
(
!
av_fifo_size
(
select
->
pending_frames
))
{
if
((
count
=
avfilter_poll_frame
(
inlink
))
<=
0
)
return
count
;
/* request frame from input, and apply select condition to it */
select
->
cache_frames
=
1
;
while
(
count
--
&&
av_fifo_space
(
select
->
pending_frames
))
{
ret
=
avfilter_request_frame
(
inlink
);
if
(
ret
<
0
)
break
;
}
select
->
cache_frames
=
0
;
}
return
av_fifo_size
(
select
->
pending_frames
)
/
sizeof
(
AVFilterBufferRef
*
);
}
static
av_cold
void
uninit
(
AVFilterContext
*
ctx
)
{
SelectContext
*
select
=
ctx
->
priv
;
AVFilterBufferRef
*
picref
;
int
i
;
av_expr_free
(
select
->
expr
);
select
->
expr
=
NULL
;
for
(
i
=
0
;
i
<
av_fifo_size
(
select
->
pending_frames
)
/
sizeof
(
picref
);
i
++
)
{
av_fifo_generic_read
(
select
->
pending_frames
,
&
picref
,
sizeof
(
picref
),
NULL
);
avfilter_unref_buffer
(
picref
);
}
av_fifo_free
(
select
->
pending_frames
);
}
AVFilter
avfilter_vf_select
=
{
.
name
=
"select"
,
.
description
=
NULL_IF_CONFIG_SMALL
(
"Select frames to pass in output."
),
.
init
=
init
,
.
uninit
=
uninit
,
.
priv_size
=
sizeof
(
SelectContext
),
.
inputs
=
(
AVFilterPad
[])
{{
.
name
=
"default"
,
.
type
=
AVMEDIA_TYPE_VIDEO
,
.
get_video_buffer
=
avfilter_null_get_video_buffer
,
.
config_props
=
config_input
,
.
start_frame
=
start_frame
,
.
draw_slice
=
draw_slice
,
.
end_frame
=
end_frame
},
{
.
name
=
NULL
}},
.
outputs
=
(
AVFilterPad
[])
{{
.
name
=
"default"
,
.
type
=
AVMEDIA_TYPE_VIDEO
,
.
poll_frame
=
poll_frame
,
.
request_frame
=
request_frame
,
},
{
.
name
=
NULL
}},
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment