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
08acab85
Commit
08acab85
authored
Feb 11, 2016
by
Paul B Mahol
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
avfilter: add loop filters
Signed-off-by:
Paul B Mahol
<
onemda@gmail.com
>
parent
5590ab45
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
450 additions
and
1 deletion
+450
-1
Changelog
Changelog
+1
-0
APIchanges
doc/APIchanges
+3
-0
filters.texi
doc/filters.texi
+19
-0
Makefile
libavfilter/Makefile
+2
-0
allfilters.c
libavfilter/allfilters.c
+2
-0
f_loop.c
libavfilter/f_loop.c
+381
-0
version.h
libavfilter/version.h
+1
-1
audio_fifo.c
libavutil/audio_fifo.c
+24
-0
audio_fifo.h
libavutil/audio_fifo.h
+17
-0
No files found.
Changelog
View file @
08acab85
...
...
@@ -4,6 +4,7 @@ releases are sorted from youngest to oldest.
version <next>:
- DXVA2-accelerated HEVC Main10 decoding
- fieldhint filter
- loop video filter and aloop audio filter
version 3.0:
...
...
doc/APIchanges
View file @
08acab85
...
...
@@ -15,6 +15,9 @@ libavutil: 2015-08-28
API changes, most recent first:
2016-xx-xx - lavu 55.18.100
xxxxxxx audio_fifo.h - Add av_audio_fifo_peek_at().
2016-xx-xx - lavu 55.18.0
xxxxxxx buffer.h - Add av_buffer_pool_init2().
xxxxxxx hwcontext.h - Add a new installed header hwcontext.h with a new API
...
...
doc/filters.texi
View file @
08acab85
...
...
@@ -8185,6 +8185,25 @@ The formula that generates the correction is:
where @var{r_0} is halve of the image diagonal and @var{r_src} and @var{r_tgt} are the
distances from the focal point in the source and target images, respectively.
@section loop, aloop
Loop video frames or audio samples.
Those filters accepts the following options:
@table @option
@item loop
Set the number of loops.
@item size
Set maximal size in number of frames for @code{loop} filter or maximal number
of samples in case of @code{aloop} filter.
@item start
Set first frame of loop for @code{loop} filter or first sample of loop in case
of @code{aloop} filter.
@end table
@anchor{lut3d}
@section lut3d
...
...
libavfilter/Makefile
View file @
08acab85
...
...
@@ -38,6 +38,7 @@ OBJS-$(CONFIG_AGATE_FILTER) += af_agate.o
OBJS-$(CONFIG_AINTERLEAVE_FILTER)
+=
f_interleave.o
OBJS-$(CONFIG_ALIMITER_FILTER)
+=
af_alimiter.o
OBJS-$(CONFIG_ALLPASS_FILTER)
+=
af_biquads.o
OBJS-$(CONFIG_ALOOP_FILTER)
+=
f_loop.o
OBJS-$(CONFIG_AMERGE_FILTER)
+=
af_amerge.o
OBJS-$(CONFIG_AMETADATA_FILTER)
+=
f_metadata.o
OBJS-$(CONFIG_AMIX_FILTER)
+=
af_amix.o
...
...
@@ -181,6 +182,7 @@ OBJS-$(CONFIG_INTERLACE_FILTER) += vf_interlace.o
OBJS-$(CONFIG_INTERLEAVE_FILTER)
+=
f_interleave.o
OBJS-$(CONFIG_KERNDEINT_FILTER)
+=
vf_kerndeint.o
OBJS-$(CONFIG_LENSCORRECTION_FILTER)
+=
vf_lenscorrection.o
OBJS-$(CONFIG_LOOP_FILTER)
+=
f_loop.o
OBJS-$(CONFIG_LUT3D_FILTER)
+=
vf_lut3d.o
OBJS-$(CONFIG_LUT_FILTER)
+=
vf_lut.o
OBJS-$(CONFIG_LUTRGB_FILTER)
+=
vf_lut.o
...
...
libavfilter/allfilters.c
View file @
08acab85
...
...
@@ -58,6 +58,7 @@ void avfilter_register_all(void)
REGISTER_FILTER
(
AINTERLEAVE
,
ainterleave
,
af
);
REGISTER_FILTER
(
ALIMITER
,
alimiter
,
af
);
REGISTER_FILTER
(
ALLPASS
,
allpass
,
af
);
REGISTER_FILTER
(
ALOOP
,
aloop
,
af
);
REGISTER_FILTER
(
AMERGE
,
amerge
,
af
);
REGISTER_FILTER
(
AMETADATA
,
ametadata
,
af
);
REGISTER_FILTER
(
AMIX
,
amix
,
af
);
...
...
@@ -202,6 +203,7 @@ void avfilter_register_all(void)
REGISTER_FILTER
(
INTERLEAVE
,
interleave
,
vf
);
REGISTER_FILTER
(
KERNDEINT
,
kerndeint
,
vf
);
REGISTER_FILTER
(
LENSCORRECTION
,
lenscorrection
,
vf
);
REGISTER_FILTER
(
LOOP
,
loop
,
vf
);
REGISTER_FILTER
(
LUT3D
,
lut3d
,
vf
);
REGISTER_FILTER
(
LUT
,
lut
,
vf
);
REGISTER_FILTER
(
LUTRGB
,
lutrgb
,
vf
);
...
...
libavfilter/f_loop.c
0 → 100644
View file @
08acab85
/*
* Copyright (c) 2016 Paul B Mahol
*
* 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
*/
#include "libavutil/audio_fifo.h"
#include "libavutil/avassert.h"
#include "libavutil/fifo.h"
#include "libavutil/internal.h"
#include "libavutil/opt.h"
#include "avfilter.h"
#include "audio.h"
#include "formats.h"
#include "internal.h"
#include "video.h"
typedef
struct
LoopContext
{
const
AVClass
*
class
;
AVAudioFifo
*
fifo
;
AVAudioFifo
*
left
;
AVFrame
**
frames
;
int
nb_frames
;
int
current_frame
;
int64_t
start_pts
;
int64_t
duration
;
int64_t
current_sample
;
int64_t
nb_samples
;
int64_t
ignored_samples
;
int
loop
;
int64_t
size
;
int64_t
start
;
int64_t
pts
;
}
LoopContext
;
#define AFLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
#define VFLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
#define OFFSET(x) offsetof(LoopContext, x)
#if CONFIG_ALOOP_FILTER
static
int
aconfig_input
(
AVFilterLink
*
inlink
)
{
AVFilterContext
*
ctx
=
inlink
->
dst
;
LoopContext
*
s
=
ctx
->
priv
;
s
->
fifo
=
av_audio_fifo_alloc
(
inlink
->
format
,
inlink
->
channels
,
8192
);
s
->
left
=
av_audio_fifo_alloc
(
inlink
->
format
,
inlink
->
channels
,
8192
);
if
(
!
s
->
fifo
||
!
s
->
left
)
return
AVERROR
(
ENOMEM
);
return
0
;
}
static
av_cold
void
auninit
(
AVFilterContext
*
ctx
)
{
LoopContext
*
s
=
ctx
->
priv
;
av_audio_fifo_free
(
s
->
fifo
);
av_audio_fifo_free
(
s
->
left
);
}
static
int
push_samples
(
AVFilterContext
*
ctx
,
int
nb_samples
)
{
AVFilterLink
*
outlink
=
ctx
->
outputs
[
0
];
LoopContext
*
s
=
ctx
->
priv
;
AVFrame
*
out
;
int
ret
,
i
=
0
;
while
(
s
->
loop
!=
0
&&
i
<
nb_samples
)
{
out
=
ff_get_audio_buffer
(
outlink
,
FFMIN
(
nb_samples
,
s
->
nb_samples
-
s
->
current_sample
));
if
(
!
out
)
return
AVERROR
(
ENOMEM
);
ret
=
av_audio_fifo_peek_at
(
s
->
fifo
,
(
void
**
)
out
->
extended_data
,
out
->
nb_samples
,
s
->
current_sample
);
if
(
ret
<
0
)
return
ret
;
out
->
pts
=
s
->
pts
;
out
->
nb_samples
=
ret
;
s
->
pts
+=
out
->
nb_samples
;
i
+=
out
->
nb_samples
;
s
->
current_sample
+=
out
->
nb_samples
;
ret
=
ff_filter_frame
(
outlink
,
out
);
if
(
ret
<
0
)
return
ret
;
if
(
s
->
current_sample
>=
s
->
nb_samples
)
{
s
->
current_sample
=
0
;
if
(
s
->
loop
>
0
)
s
->
loop
--
;
}
}
return
ret
;
}
static
int
afilter_frame
(
AVFilterLink
*
inlink
,
AVFrame
*
frame
)
{
AVFilterContext
*
ctx
=
inlink
->
dst
;
AVFilterLink
*
outlink
=
ctx
->
outputs
[
0
];
LoopContext
*
s
=
ctx
->
priv
;
int
ret
=
0
;
if
(
s
->
ignored_samples
+
frame
->
nb_samples
>
s
->
start
&&
s
->
size
>
0
&&
s
->
loop
!=
0
)
{
if
(
s
->
nb_samples
<
s
->
size
)
{
int
written
=
FFMIN
(
frame
->
nb_samples
,
s
->
size
-
s
->
nb_samples
);
int
drain
=
0
;
ret
=
av_audio_fifo_write
(
s
->
fifo
,
(
void
**
)
frame
->
extended_data
,
written
);
if
(
ret
<
0
)
return
ret
;
if
(
!
s
->
nb_samples
)
{
drain
=
FFMAX
(
0
,
s
->
start
-
s
->
ignored_samples
);
s
->
pts
=
frame
->
pts
;
av_audio_fifo_drain
(
s
->
fifo
,
drain
);
s
->
pts
+=
s
->
start
-
s
->
ignored_samples
;
}
s
->
nb_samples
+=
ret
-
drain
;
drain
=
frame
->
nb_samples
-
written
;
if
(
s
->
nb_samples
==
s
->
size
&&
drain
>
0
)
{
int
ret2
;
ret2
=
av_audio_fifo_write
(
s
->
left
,
(
void
**
)
frame
->
extended_data
,
frame
->
nb_samples
);
if
(
ret2
<
0
)
return
ret2
;
av_audio_fifo_drain
(
s
->
left
,
drain
);
}
frame
->
nb_samples
=
ret
;
s
->
pts
+=
ret
;
ret
=
ff_filter_frame
(
outlink
,
frame
);
}
else
{
int
nb_samples
=
frame
->
nb_samples
;
av_frame_free
(
&
frame
);
ret
=
push_samples
(
ctx
,
nb_samples
);
}
}
else
{
s
->
ignored_samples
+=
frame
->
nb_samples
;
frame
->
pts
=
s
->
pts
;
s
->
pts
+=
frame
->
nb_samples
;
ret
=
ff_filter_frame
(
outlink
,
frame
);
}
return
ret
;
}
static
int
arequest_frame
(
AVFilterLink
*
outlink
)
{
AVFilterContext
*
ctx
=
outlink
->
src
;
LoopContext
*
s
=
ctx
->
priv
;
int
ret
=
0
;
if
((
!
s
->
size
)
||
(
s
->
nb_samples
<
s
->
size
)
||
(
s
->
nb_samples
>=
s
->
size
&&
s
->
loop
==
0
))
{
int
nb_samples
=
av_audio_fifo_size
(
s
->
left
);
if
(
s
->
loop
==
0
&&
nb_samples
>
0
)
{
AVFrame
*
out
;
out
=
ff_get_audio_buffer
(
outlink
,
nb_samples
);
if
(
!
out
)
return
AVERROR
(
ENOMEM
);
av_audio_fifo_read
(
s
->
left
,
(
void
**
)
out
->
extended_data
,
nb_samples
);
out
->
pts
=
s
->
pts
;
s
->
pts
+=
nb_samples
;
ret
=
ff_filter_frame
(
outlink
,
out
);
if
(
ret
<
0
)
return
ret
;
}
ret
=
ff_request_frame
(
ctx
->
inputs
[
0
]);
}
else
{
ret
=
push_samples
(
ctx
,
1024
);
}
if
(
ret
==
AVERROR_EOF
&&
s
->
nb_samples
>
0
&&
s
->
loop
!=
0
)
{
ret
=
push_samples
(
ctx
,
outlink
->
sample_rate
);
}
return
ret
;
}
static
const
AVOption
aloop_options
[]
=
{
{
"loop"
,
"number of loops"
,
OFFSET
(
loop
),
AV_OPT_TYPE_INT
,
{.
i64
=
0
},
-
1
,
INT_MAX
,
AFLAGS
},
{
"size"
,
"max number of samples to loop"
,
OFFSET
(
size
),
AV_OPT_TYPE_INT64
,
{.
i64
=
0
},
0
,
INT32_MAX
,
AFLAGS
},
{
"start"
,
"set the loop start sample"
,
OFFSET
(
start
),
AV_OPT_TYPE_INT64
,
{.
i64
=
0
},
0
,
INT64_MAX
,
AFLAGS
},
{
NULL
}
};
AVFILTER_DEFINE_CLASS
(
aloop
);
static
const
AVFilterPad
ainputs
[]
=
{
{
.
name
=
"default"
,
.
type
=
AVMEDIA_TYPE_AUDIO
,
.
filter_frame
=
afilter_frame
,
.
config_props
=
aconfig_input
,
},
{
NULL
}
};
static
const
AVFilterPad
aoutputs
[]
=
{
{
.
name
=
"default"
,
.
type
=
AVMEDIA_TYPE_AUDIO
,
.
request_frame
=
arequest_frame
,
},
{
NULL
}
};
AVFilter
ff_af_aloop
=
{
.
name
=
"aloop"
,
.
description
=
NULL_IF_CONFIG_SMALL
(
"Loop audio samples."
),
.
priv_size
=
sizeof
(
LoopContext
),
.
priv_class
=
&
aloop_class
,
.
uninit
=
auninit
,
.
query_formats
=
ff_query_formats_all
,
.
inputs
=
ainputs
,
.
outputs
=
aoutputs
,
};
#endif
/* CONFIG_ALOOP_FILTER */
#if CONFIG_LOOP_FILTER
static
av_cold
int
init
(
AVFilterContext
*
ctx
)
{
LoopContext
*
s
=
ctx
->
priv
;
s
->
frames
=
av_calloc
(
s
->
size
,
sizeof
(
*
s
->
frames
));
if
(
!
s
->
frames
)
return
AVERROR
(
ENOMEM
);
return
0
;
}
static
av_cold
void
uninit
(
AVFilterContext
*
ctx
)
{
LoopContext
*
s
=
ctx
->
priv
;
int
i
;
for
(
i
=
0
;
i
<
s
->
nb_frames
;
i
++
)
av_frame_free
(
&
s
->
frames
[
i
]);
av_freep
(
&
s
->
frames
);
s
->
nb_frames
=
0
;
}
static
int
push_frame
(
AVFilterContext
*
ctx
)
{
AVFilterLink
*
outlink
=
ctx
->
outputs
[
0
];
LoopContext
*
s
=
ctx
->
priv
;
int64_t
pts
;
int
ret
;
AVFrame
*
out
=
av_frame_clone
(
s
->
frames
[
s
->
current_frame
]);
if
(
!
out
)
return
AVERROR
(
ENOMEM
);
out
->
pts
+=
s
->
duration
-
s
->
start_pts
;
pts
=
out
->
pts
+
av_frame_get_pkt_duration
(
out
);
ret
=
ff_filter_frame
(
outlink
,
out
);
s
->
current_frame
++
;
if
(
s
->
current_frame
>=
s
->
nb_frames
)
{
s
->
duration
=
pts
;
s
->
current_frame
=
0
;
if
(
s
->
loop
>
0
)
s
->
loop
--
;
}
return
ret
;
}
static
int
filter_frame
(
AVFilterLink
*
inlink
,
AVFrame
*
frame
)
{
AVFilterContext
*
ctx
=
inlink
->
dst
;
AVFilterLink
*
outlink
=
ctx
->
outputs
[
0
];
LoopContext
*
s
=
ctx
->
priv
;
int
ret
=
0
;
if
(
inlink
->
frame_count
>=
s
->
start
&&
s
->
size
>
0
&&
s
->
loop
!=
0
)
{
if
(
s
->
nb_frames
<
s
->
size
)
{
if
(
!
s
->
nb_frames
)
s
->
start_pts
=
frame
->
pts
;
s
->
frames
[
s
->
nb_frames
]
=
av_frame_clone
(
frame
);
if
(
!
s
->
frames
[
s
->
nb_frames
])
{
av_frame_free
(
&
frame
);
return
AVERROR
(
ENOMEM
);
}
s
->
nb_frames
++
;
s
->
duration
=
frame
->
pts
+
av_frame_get_pkt_duration
(
frame
);
ret
=
ff_filter_frame
(
outlink
,
frame
);
}
else
{
av_frame_free
(
&
frame
);
ret
=
push_frame
(
ctx
);
}
}
else
{
frame
->
pts
+=
s
->
duration
;
ret
=
ff_filter_frame
(
outlink
,
frame
);
}
return
ret
;
}
static
int
request_frame
(
AVFilterLink
*
outlink
)
{
AVFilterContext
*
ctx
=
outlink
->
src
;
LoopContext
*
s
=
ctx
->
priv
;
int
ret
=
0
;
if
((
!
s
->
size
)
||
(
s
->
nb_frames
<
s
->
size
)
||
(
s
->
nb_frames
>=
s
->
size
&&
s
->
loop
==
0
))
{
ret
=
ff_request_frame
(
ctx
->
inputs
[
0
]);
}
else
{
ret
=
push_frame
(
ctx
);
}
if
(
ret
==
AVERROR_EOF
&&
s
->
nb_frames
>
0
&&
s
->
loop
!=
0
)
{
ret
=
push_frame
(
ctx
);
}
return
ret
;
}
static
const
AVOption
loop_options
[]
=
{
{
"loop"
,
"number of loops"
,
OFFSET
(
loop
),
AV_OPT_TYPE_INT
,
{.
i64
=
0
},
-
1
,
INT_MAX
,
VFLAGS
},
{
"size"
,
"max number of frames to loop"
,
OFFSET
(
size
),
AV_OPT_TYPE_INT64
,
{.
i64
=
0
},
0
,
INT16_MAX
,
VFLAGS
},
{
"start"
,
"set the loop start frame"
,
OFFSET
(
start
),
AV_OPT_TYPE_INT64
,
{.
i64
=
0
},
0
,
INT64_MAX
,
VFLAGS
},
{
NULL
}
};
AVFILTER_DEFINE_CLASS
(
loop
);
static
const
AVFilterPad
inputs
[]
=
{
{
.
name
=
"default"
,
.
type
=
AVMEDIA_TYPE_VIDEO
,
.
filter_frame
=
filter_frame
,
},
{
NULL
}
};
static
const
AVFilterPad
outputs
[]
=
{
{
.
name
=
"default"
,
.
type
=
AVMEDIA_TYPE_VIDEO
,
.
request_frame
=
request_frame
,
},
{
NULL
}
};
AVFilter
ff_vf_loop
=
{
.
name
=
"loop"
,
.
description
=
NULL_IF_CONFIG_SMALL
(
"Loop video frames."
),
.
priv_size
=
sizeof
(
LoopContext
),
.
priv_class
=
&
loop_class
,
.
init
=
init
,
.
uninit
=
uninit
,
.
inputs
=
inputs
,
.
outputs
=
outputs
,
};
#endif
/* CONFIG_LOOP_FILTER */
libavfilter/version.h
View file @
08acab85
...
...
@@ -30,7 +30,7 @@
#include "libavutil/version.h"
#define LIBAVFILTER_VERSION_MAJOR 6
#define LIBAVFILTER_VERSION_MINOR 3
2
#define LIBAVFILTER_VERSION_MINOR 3
3
#define LIBAVFILTER_VERSION_MICRO 100
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
...
...
libavutil/audio_fifo.c
View file @
08acab85
...
...
@@ -155,6 +155,30 @@ int av_audio_fifo_peek(AVAudioFifo *af, void **data, int nb_samples)
return
nb_samples
;
}
int
av_audio_fifo_peek_at
(
AVAudioFifo
*
af
,
void
**
data
,
int
nb_samples
,
int
offset
)
{
int
i
,
ret
,
size
;
if
(
offset
<
0
||
offset
>=
af
->
nb_samples
)
return
AVERROR
(
EINVAL
);
if
(
nb_samples
<
0
)
return
AVERROR
(
EINVAL
);
nb_samples
=
FFMIN
(
nb_samples
,
af
->
nb_samples
);
if
(
!
nb_samples
)
return
0
;
if
(
offset
>
af
->
nb_samples
-
nb_samples
)
return
AVERROR
(
EINVAL
);
offset
*=
af
->
sample_size
;
size
=
nb_samples
*
af
->
sample_size
;
for
(
i
=
0
;
i
<
af
->
nb_buffers
;
i
++
)
{
if
((
ret
=
av_fifo_generic_peek_at
(
af
->
buf
[
i
],
data
[
i
],
offset
,
size
,
NULL
))
<
0
)
return
AVERROR_BUG
;
}
return
nb_samples
;
}
int
av_audio_fifo_read
(
AVAudioFifo
*
af
,
void
**
data
,
int
nb_samples
)
{
int
i
,
ret
,
size
;
...
...
libavutil/audio_fifo.h
View file @
08acab85
...
...
@@ -110,6 +110,23 @@ int av_audio_fifo_write(AVAudioFifo *af, void **data, int nb_samples);
*/
int
av_audio_fifo_peek
(
AVAudioFifo
*
af
,
void
**
data
,
int
nb_samples
);
/**
* Peek data from an AVAudioFifo.
*
* @see enum AVSampleFormat
* The documentation for AVSampleFormat describes the data layout.
*
* @param af AVAudioFifo to read from
* @param data audio data plane pointers
* @param nb_samples number of samples to peek
* @param offset offset from current read position
* @return number of samples actually peek, or negative AVERROR code
* on failure. The number of samples actually peek will not
* be greater than nb_samples, and will only be less than
* nb_samples if av_audio_fifo_size is less than nb_samples.
*/
int
av_audio_fifo_peek_at
(
AVAudioFifo
*
af
,
void
**
data
,
int
nb_samples
,
int
offset
);
/**
* Read data from an AVAudioFifo.
*
...
...
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