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
e90a69e9
Commit
e90a69e9
authored
Dec 14, 2011
by
Nicolas George
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
lavfi: add astreamsync audio filter.
parent
e6362f3a
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
241 additions
and
0 deletions
+241
-0
Changelog
Changelog
+1
-0
filters.texi
doc/filters.texi
+29
-0
Makefile
libavfilter/Makefile
+1
-0
af_astreamsync.c
libavfilter/af_astreamsync.c
+209
-0
allfilters.c
libavfilter/allfilters.c
+1
-0
No files found.
Changelog
View file @
e90a69e9
...
...
@@ -12,6 +12,7 @@ version next:
- XML output in ffprobe
- asplit audio filter
- tinterlace video filter
- astreamsync audio filter
version 0.9:
...
...
doc/filters.texi
View file @
e90a69e9
...
...
@@ -237,6 +237,35 @@ For example:
will create two separate outputs from the same input, one cropped and
one padded.
@section astreamsync
Forward two audio streams and control the order the buffers are forwarded.
The argument to the filter is an expression deciding which stream should be
forwarded next: if the result is negative, the first stream is forwarded; if
the result is positive or zero, the second stream is forwarded. It can use
the following variables:
@table @var
@item b1 b2
number of buffers forwarded so far on each stream
@item s1 s2
number of samples forwarded so far on each stream
@item t1 t2
current timestamp of each stream
@end table
The default value is @code{t1-t2}, which means to always forward the stream
that has a smaller timestamp.
Example: stress-test @code{amerge} by randomly sending buffers on the wrong
input, while avoiding too much of a desynchronization:
@example
amovie=file.ogg [a] ; amovie=file.mp3 [b] ;
[a] [b] astreamsync=(2*random(1))-1+tanh(5*(t1-t2)) [a2] [b2] ;
[a2] [b2] amerge
@end example
@section earwax
Make audio easier to listen to on headphones.
...
...
libavfilter/Makefile
View file @
e90a69e9
...
...
@@ -30,6 +30,7 @@ OBJS-$(CONFIG_ANULL_FILTER) += af_anull.o
OBJS-$(CONFIG_ARESAMPLE_FILTER)
+=
af_aresample.o
OBJS-$(CONFIG_ASHOWINFO_FILTER)
+=
af_ashowinfo.o
OBJS-$(CONFIG_ASPLIT_FILTER)
+=
af_asplit.o
OBJS-$(CONFIG_ASTREAMSYNC_FILTER)
+=
af_astreamsync.o
OBJS-$(CONFIG_EARWAX_FILTER)
+=
af_earwax.o
OBJS-$(CONFIG_PAN_FILTER)
+=
af_pan.o
OBJS-$(CONFIG_VOLUME_FILTER)
+=
af_volume.o
...
...
libavfilter/af_astreamsync.c
0 → 100644
View file @
e90a69e9
/*
* Copyright (c) 2011 Nicolas George <nicolas.george@normalesup.org>
*
* 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 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
* Stream (de)synchronization filter
*/
#include "libavutil/eval.h"
#include "avfilter.h"
#include "internal.h"
#define QUEUE_SIZE 16
static
const
char
*
const
var_names
[]
=
{
"b1"
,
"b2"
,
"s1"
,
"s2"
,
"t1"
,
"t2"
,
NULL
};
enum
var_name
{
VAR_B1
,
VAR_B2
,
VAR_S1
,
VAR_S2
,
VAR_T1
,
VAR_T2
,
VAR_NB
};
typedef
struct
{
AVExpr
*
expr
;
double
var_values
[
VAR_NB
];
struct
buf_queue
{
AVFilterBufferRef
*
buf
[
QUEUE_SIZE
];
unsigned
tail
,
nb
;
/* buf[tail] is the oldest,
buf[(tail + nb) % QUEUE_SIZE] is where the next is added */
}
queue
[
2
];
int
req
[
2
];
int
next_out
;
int
eof
;
/* bitmask, one bit for each stream */
}
AStreamSyncContext
;
static
const
char
*
default_expr
=
"t1-t2"
;
static
av_cold
int
init
(
AVFilterContext
*
ctx
,
const
char
*
args0
,
void
*
opaque
)
{
AStreamSyncContext
*
as
=
ctx
->
priv
;
const
char
*
expr
=
args0
?
args0
:
default_expr
;
int
r
,
i
;
r
=
av_expr_parse
(
&
as
->
expr
,
expr
,
var_names
,
NULL
,
NULL
,
NULL
,
NULL
,
0
,
ctx
);
if
(
r
<
0
)
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"Error in expression
\"
%s
\"\n
"
,
expr
);
return
r
;
}
for
(
i
=
0
;
i
<
42
;
i
++
)
av_expr_eval
(
as
->
expr
,
as
->
var_values
,
NULL
);
/* exercize prng */
return
0
;
}
static
int
query_formats
(
AVFilterContext
*
ctx
)
{
int
i
;
AVFilterFormats
*
formats
;
for
(
i
=
0
;
i
<
2
;
i
++
)
{
formats
=
ctx
->
inputs
[
i
]
->
in_formats
;
avfilter_formats_ref
(
formats
,
&
ctx
->
inputs
[
i
]
->
out_formats
);
avfilter_formats_ref
(
formats
,
&
ctx
->
outputs
[
i
]
->
in_formats
);
formats
=
ctx
->
inputs
[
i
]
->
in_packing
;
avfilter_formats_ref
(
formats
,
&
ctx
->
inputs
[
i
]
->
out_packing
);
avfilter_formats_ref
(
formats
,
&
ctx
->
outputs
[
i
]
->
in_packing
);
formats
=
ctx
->
inputs
[
i
]
->
in_chlayouts
;
avfilter_formats_ref
(
formats
,
&
ctx
->
inputs
[
i
]
->
out_chlayouts
);
avfilter_formats_ref
(
formats
,
&
ctx
->
outputs
[
i
]
->
in_chlayouts
);
}
return
0
;
}
static
int
config_output
(
AVFilterLink
*
outlink
)
{
AVFilterContext
*
ctx
=
outlink
->
src
;
int
id
=
outlink
==
ctx
->
outputs
[
1
];
int
i
;
outlink
->
sample_rate
=
ctx
->
inputs
[
id
]
->
sample_rate
;
outlink
->
time_base
=
ctx
->
inputs
[
id
]
->
time_base
;
return
0
;
}
static
void
send_out
(
AVFilterContext
*
ctx
,
int
out_id
)
{
AStreamSyncContext
*
as
=
ctx
->
priv
;
struct
buf_queue
*
queue
=
&
as
->
queue
[
out_id
];
AVFilterBufferRef
*
buf
=
queue
->
buf
[
queue
->
tail
];
queue
->
buf
[
queue
->
tail
]
=
NULL
;
as
->
var_values
[
VAR_B1
+
out_id
]
++
;
as
->
var_values
[
VAR_S1
+
out_id
]
+=
buf
->
audio
->
nb_samples
;
if
(
buf
->
pts
!=
AV_NOPTS_VALUE
)
as
->
var_values
[
VAR_T1
+
out_id
]
=
av_q2d
(
ctx
->
outputs
[
out_id
]
->
time_base
)
*
buf
->
pts
;
as
->
var_values
[
VAR_T1
+
out_id
]
+=
buf
->
audio
->
nb_samples
/
(
double
)
ctx
->
inputs
[
out_id
]
->
sample_rate
;
avfilter_filter_samples
(
ctx
->
outputs
[
out_id
],
buf
);
queue
->
nb
--
;
queue
->
tail
=
(
queue
->
tail
+
1
)
%
QUEUE_SIZE
;
if
(
as
->
req
[
out_id
])
as
->
req
[
out_id
]
--
;
}
static
void
send_next
(
AVFilterContext
*
ctx
)
{
AStreamSyncContext
*
as
=
ctx
->
priv
;
int
i
;
while
(
1
)
{
if
(
!
as
->
queue
[
as
->
next_out
].
nb
)
break
;
send_out
(
ctx
,
as
->
next_out
);
if
(
!
as
->
eof
)
as
->
next_out
=
av_expr_eval
(
as
->
expr
,
as
->
var_values
,
NULL
)
>=
0
;
}
for
(
i
=
0
;
i
<
2
;
i
++
)
if
(
as
->
queue
[
i
].
nb
==
QUEUE_SIZE
)
send_out
(
ctx
,
i
);
}
static
int
request_frame
(
AVFilterLink
*
outlink
)
{
AVFilterContext
*
ctx
=
outlink
->
src
;
AStreamSyncContext
*
as
=
ctx
->
priv
;
int
id
=
outlink
==
ctx
->
outputs
[
1
];
as
->
req
[
id
]
++
;
while
(
as
->
req
[
id
]
&&
!
(
as
->
eof
&
(
1
<<
id
)))
{
if
(
as
->
queue
[
as
->
next_out
].
nb
)
{
send_next
(
ctx
);
}
else
{
as
->
eof
|=
1
<<
as
->
next_out
;
avfilter_request_frame
(
ctx
->
inputs
[
as
->
next_out
]);
if
(
as
->
eof
&
(
1
<<
as
->
next_out
))
as
->
next_out
=
!
as
->
next_out
;
}
}
return
0
;
}
static
void
filter_samples
(
AVFilterLink
*
inlink
,
AVFilterBufferRef
*
insamples
)
{
AVFilterContext
*
ctx
=
inlink
->
dst
;
AStreamSyncContext
*
as
=
ctx
->
priv
;
int
id
=
inlink
==
ctx
->
inputs
[
1
];
as
->
queue
[
id
].
buf
[(
as
->
queue
[
id
].
tail
+
as
->
queue
[
id
].
nb
++
)
%
QUEUE_SIZE
]
=
insamples
;
as
->
eof
&=
~
(
1
<<
id
);
send_next
(
ctx
);
}
AVFilter
avfilter_af_astreamsync
=
{
.
name
=
"astreamsync"
,
.
description
=
NULL_IF_CONFIG_SMALL
(
"Copy two streams of audio data "
"in a configurable order."
),
.
priv_size
=
sizeof
(
AStreamSyncContext
),
.
init
=
init
,
.
query_formats
=
query_formats
,
.
inputs
=
(
const
AVFilterPad
[])
{
{
.
name
=
"in1"
,
.
type
=
AVMEDIA_TYPE_AUDIO
,
.
filter_samples
=
filter_samples
,
.
min_perms
=
AV_PERM_READ
,
},
{
.
name
=
"in2"
,
.
type
=
AVMEDIA_TYPE_AUDIO
,
.
filter_samples
=
filter_samples
,
.
min_perms
=
AV_PERM_READ
,
},
{
.
name
=
NULL
}
},
.
outputs
=
(
const
AVFilterPad
[])
{
{
.
name
=
"out1"
,
.
type
=
AVMEDIA_TYPE_AUDIO
,
.
config_props
=
config_output
,
.
request_frame
=
request_frame
,
},
{
.
name
=
"out2"
,
.
type
=
AVMEDIA_TYPE_AUDIO
,
.
config_props
=
config_output
,
.
request_frame
=
request_frame
,
},
{
.
name
=
NULL
}
},
};
libavfilter/allfilters.c
View file @
e90a69e9
...
...
@@ -40,6 +40,7 @@ void avfilter_register_all(void)
REGISTER_FILTER
(
ARESAMPLE
,
aresample
,
af
);
REGISTER_FILTER
(
ASHOWINFO
,
ashowinfo
,
af
);
REGISTER_FILTER
(
ASPLIT
,
asplit
,
af
);
REGISTER_FILTER
(
ASTREAMSYNC
,
astreamsync
,
af
);
REGISTER_FILTER
(
EARWAX
,
earwax
,
af
);
REGISTER_FILTER
(
PAN
,
pan
,
af
);
REGISTER_FILTER
(
VOLUME
,
volume
,
af
);
...
...
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