Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
BC
public
external
ffmpeg
Commits
f75be985
Commit
f75be985
authored
May 27, 2012
by
Anton Khirnov
Browse files
lavfi: allow audio filters to request a given number of samples.
This makes synchronization simpler for filters with multiple inputs.
parent
58b049f2
Changes
2
Hide whitespace changes
Inline
Side-by-side
libavfilter/avfilter.h
View file @
f75be985
...
...
@@ -595,6 +595,15 @@ struct AVFilterLink {
AVFilterFormats
*
out_samplerates
;
struct
AVFilterChannelLayouts
*
in_channel_layouts
;
struct
AVFilterChannelLayouts
*
out_channel_layouts
;
/**
* Audio only, the destination filter sets this to a non-zero value to
* request that buffers with the given number of samples should be sent to
* it. AVFilterPad.needs_fifo must also be set on the corresponding input
* pad.
* Last buffer before EOF will be padded with silence.
*/
int
request_samples
;
};
/**
...
...
libavfilter/fifo.c
View file @
f75be985
...
...
@@ -23,6 +23,11 @@
* FIFO buffering filter
*/
#include "libavutil/avassert.h"
#include "libavutil/audioconvert.h"
#include "libavutil/mathematics.h"
#include "libavutil/samplefmt.h"
#include "audio.h"
#include "avfilter.h"
#include "internal.h"
...
...
@@ -36,6 +41,13 @@ typedef struct Buf {
typedef
struct
{
Buf
root
;
Buf
*
last
;
///< last buffered frame
/**
* When a specific number of output samples is requested, the partial
* buffer is stored here
*/
AVFilterBufferRef
*
buf_out
;
int
allocated_samples
;
///< number of samples buf_out was allocated for
}
FifoContext
;
static
av_cold
int
init
(
AVFilterContext
*
ctx
,
const
char
*
args
,
void
*
opaque
)
...
...
@@ -57,6 +69,8 @@ static av_cold void uninit(AVFilterContext *ctx)
avfilter_unref_buffer
(
buf
->
buf
);
av_free
(
buf
);
}
avfilter_unref_buffer
(
fifo
->
buf_out
);
}
static
void
add_to_queue
(
AVFilterLink
*
inlink
,
AVFilterBufferRef
*
buf
)
...
...
@@ -68,14 +82,143 @@ static void add_to_queue(AVFilterLink *inlink, AVFilterBufferRef *buf)
fifo
->
last
->
buf
=
buf
;
}
static
void
queue_pop
(
FifoContext
*
s
)
{
Buf
*
tmp
=
s
->
root
.
next
->
next
;
if
(
s
->
last
==
s
->
root
.
next
)
s
->
last
=
&
s
->
root
;
av_freep
(
&
s
->
root
.
next
);
s
->
root
.
next
=
tmp
;
}
static
void
end_frame
(
AVFilterLink
*
inlink
)
{
}
static
void
draw_slice
(
AVFilterLink
*
inlink
,
int
y
,
int
h
,
int
slice_dir
)
{
}
/**
* Move data pointers and pts offset samples forward.
*/
static
void
buffer_offset
(
AVFilterLink
*
link
,
AVFilterBufferRef
*
buf
,
int
offset
)
{
int
nb_channels
=
av_get_channel_layout_nb_channels
(
link
->
channel_layout
);
int
planar
=
av_sample_fmt_is_planar
(
link
->
format
);
int
planes
=
planar
?
nb_channels
:
1
;
int
block_align
=
av_get_bytes_per_sample
(
link
->
format
)
*
(
planar
?
1
:
nb_channels
);
int
i
;
av_assert0
(
buf
->
audio
->
nb_samples
>
offset
);
for
(
i
=
0
;
i
<
planes
;
i
++
)
buf
->
extended_data
[
i
]
+=
block_align
*
offset
;
if
(
buf
->
data
!=
buf
->
extended_data
)
memcpy
(
buf
->
data
,
buf
->
extended_data
,
FFMIN
(
planes
,
FF_ARRAY_ELEMS
(
buf
->
data
))
*
sizeof
(
*
buf
->
data
));
buf
->
linesize
[
0
]
-=
block_align
*
offset
;
buf
->
audio
->
nb_samples
-=
offset
;
if
(
buf
->
pts
!=
AV_NOPTS_VALUE
)
{
buf
->
pts
+=
av_rescale_q
(
offset
,
(
AVRational
){
1
,
link
->
sample_rate
},
link
->
time_base
);
}
}
static
int
calc_ptr_alignment
(
AVFilterBufferRef
*
buf
)
{
int
planes
=
av_sample_fmt_is_planar
(
buf
->
format
)
?
av_get_channel_layout_nb_channels
(
buf
->
audio
->
channel_layout
)
:
1
;
int
min_align
=
128
;
int
p
;
for
(
p
=
0
;
p
<
planes
;
p
++
)
{
int
cur_align
=
128
;
while
((
intptr_t
)
buf
->
extended_data
[
p
]
%
cur_align
)
cur_align
>>=
1
;
if
(
cur_align
<
min_align
)
min_align
=
cur_align
;
}
return
min_align
;
}
static
int
return_audio_frame
(
AVFilterContext
*
ctx
)
{
AVFilterLink
*
link
=
ctx
->
outputs
[
0
];
FifoContext
*
s
=
ctx
->
priv
;
AVFilterBufferRef
*
head
=
s
->
root
.
next
->
buf
;
AVFilterBufferRef
*
buf_out
;
int
ret
;
if
(
!
s
->
buf_out
&&
head
->
audio
->
nb_samples
>=
link
->
request_samples
&&
calc_ptr_alignment
(
head
)
>=
32
)
{
if
(
head
->
audio
->
nb_samples
==
link
->
request_samples
)
{
buf_out
=
head
;
queue_pop
(
s
);
}
else
{
buf_out
=
avfilter_ref_buffer
(
head
,
AV_PERM_READ
);
buf_out
->
audio
->
nb_samples
=
link
->
request_samples
;
buffer_offset
(
link
,
head
,
link
->
request_samples
);
}
}
else
{
int
nb_channels
=
av_get_channel_layout_nb_channels
(
link
->
channel_layout
);
if
(
!
s
->
buf_out
)
{
s
->
buf_out
=
ff_get_audio_buffer
(
link
,
AV_PERM_WRITE
,
link
->
request_samples
);
if
(
!
s
->
buf_out
)
return
AVERROR
(
ENOMEM
);
s
->
buf_out
->
audio
->
nb_samples
=
0
;
s
->
buf_out
->
pts
=
head
->
pts
;
s
->
allocated_samples
=
link
->
request_samples
;
}
else
if
(
link
->
request_samples
!=
s
->
allocated_samples
)
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"request_samples changed before the "
"buffer was returned.
\n
"
);
return
AVERROR
(
EINVAL
);
}
while
(
s
->
buf_out
->
audio
->
nb_samples
<
s
->
allocated_samples
)
{
int
len
=
FFMIN
(
s
->
allocated_samples
-
s
->
buf_out
->
audio
->
nb_samples
,
head
->
audio
->
nb_samples
);
av_samples_copy
(
s
->
buf_out
->
extended_data
,
head
->
extended_data
,
s
->
buf_out
->
audio
->
nb_samples
,
0
,
len
,
nb_channels
,
link
->
format
);
s
->
buf_out
->
audio
->
nb_samples
+=
len
;
if
(
len
==
head
->
audio
->
nb_samples
)
{
avfilter_unref_buffer
(
head
);
queue_pop
(
s
);
if
(
!
s
->
root
.
next
&&
(
ret
=
ff_request_frame
(
ctx
->
inputs
[
0
]))
<
0
)
{
if
(
ret
==
AVERROR_EOF
)
{
av_samples_set_silence
(
s
->
buf_out
->
extended_data
,
s
->
buf_out
->
audio
->
nb_samples
,
s
->
allocated_samples
-
s
->
buf_out
->
audio
->
nb_samples
,
nb_channels
,
link
->
format
);
s
->
buf_out
->
audio
->
nb_samples
=
s
->
allocated_samples
;
break
;
}
return
ret
;
}
head
=
s
->
root
.
next
->
buf
;
}
else
{
buffer_offset
(
link
,
head
,
len
);
}
}
buf_out
=
s
->
buf_out
;
s
->
buf_out
=
NULL
;
}
ff_filter_samples
(
link
,
buf_out
);
return
0
;
}
static
int
request_frame
(
AVFilterLink
*
outlink
)
{
FifoContext
*
fifo
=
outlink
->
src
->
priv
;
Buf
*
tmp
;
int
ret
;
if
(
!
fifo
->
root
.
next
)
{
...
...
@@ -90,20 +233,20 @@ static int request_frame(AVFilterLink *outlink)
ff_start_frame
(
outlink
,
fifo
->
root
.
next
->
buf
);
ff_draw_slice
(
outlink
,
0
,
outlink
->
h
,
1
);
ff_end_frame
(
outlink
);
queue_pop
(
fifo
);
break
;
case
AVMEDIA_TYPE_AUDIO
:
ff_filter_samples
(
outlink
,
fifo
->
root
.
next
->
buf
);
if
(
outlink
->
request_samples
)
{
return
return_audio_frame
(
outlink
->
src
);
}
else
{
ff_filter_samples
(
outlink
,
fifo
->
root
.
next
->
buf
);
queue_pop
(
fifo
);
}
break
;
default:
return
AVERROR
(
EINVAL
);
}
if
(
fifo
->
last
==
fifo
->
root
.
next
)
fifo
->
last
=
&
fifo
->
root
;
tmp
=
fifo
->
root
.
next
->
next
;
av_free
(
fifo
->
root
.
next
);
fifo
->
root
.
next
=
tmp
;
return
0
;
}
...
...
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