Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
F
ffmpeg.wasm-core
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
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Linshizhi
ffmpeg.wasm-core
Commits
d763fb7d
Commit
d763fb7d
authored
May 07, 2011
by
Stefano Sabatini
Committed by
Anton Khirnov
Sep 17, 2011
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
lavfi: add select filter
Signed-off-by:
Anton Khirnov
<
anton@khirnov.net
>
parent
0e7efb9d
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
473 additions
and
1 deletion
+473
-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
+353
-0
No files found.
Changelog
View file @
d763fb7d
...
...
@@ -46,6 +46,7 @@ easier to use. The changes are:
- showinfo filter
- split filter
- libcdio-paranoia input device for audio CD grabbing
- select filter
version 0.7:
...
...
doc/filters.texi
View file @
d763fb7d
...
...
@@ -1064,6 +1064,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 type of the filtered frame, can assume one of the following
values:
@table @option
@item I
@item P
@item B
@item S
@item SI
@item SP
@item BI
@end table
@item interlace_type
the frame interlace type, can assume one of the following values:
@table @option
@item PROGRESSIVE
the frame is progressive (not interlaced)
@item TOPFIRST
the frame is top-field-first
@item BOTTOMFIRST
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\,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\,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 @
d763fb7d
...
...
@@ -40,6 +40,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 @
d763fb7d
...
...
@@ -61,6 +61,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 @
d763fb7d
...
...
@@ -29,7 +29,7 @@
#include "libavutil/rational.h"
#define LIBAVFILTER_VERSION_MAJOR 2
#define LIBAVFILTER_VERSION_MINOR
6
#define LIBAVFILTER_VERSION_MINOR
7
#define LIBAVFILTER_VERSION_MICRO 0
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
...
...
libavfilter/vf_select.c
0 → 100644
View file @
d763fb7d
/*
* Copyright (c) 2011 Stefano Sabatini
*
* This file is part of Libav.
*
* Libav 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.
*
* Libav 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 Libav; 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 "libavutil/mathematics.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
"I"
,
"P"
,
"B"
,
"S"
,
"SI"
,
"SP"
,
"BI"
,
"interlace_type"
,
///< the frame interlace type
"PROGRESSIVE"
,
"TOPFIRST"
,
"BOTTOMFIRST"
,
"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
);
if
(
isnan
(
select
->
var_values
[
VAR_START_T
]))
select
->
var_values
[
VAR_START_T
]
=
TS2D
(
picref
->
pts
)
*
av_q2d
(
inlink
->
time_base
);
select
->
var_values
[
VAR_PTS
]
=
TS2D
(
picref
->
pts
);
select
->
var_values
[
VAR_T
]
=
TS2D
(
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
;
av_expr_free
(
select
->
expr
);
select
->
expr
=
NULL
;
while
(
select
->
pending_frames
&&
av_fifo_generic_read
(
select
->
pending_frames
,
&
picref
,
sizeof
(
picref
),
NULL
)
==
sizeof
(
picref
))
avfilter_unref_buffer
(
picref
);
av_fifo_free
(
select
->
pending_frames
);
select
->
pending_frames
=
NULL
;
}
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