... | ... |
@@ -191,6 +191,13 @@ Null audio sink, do absolutely nothing with the input audio. It is |
191 | 191 |
mainly useful as a template and to be employed in analysis / debugging |
192 | 192 |
tools. |
193 | 193 |
|
194 |
+@section abuffersink |
|
195 |
+This sink is intended for programmatic use. Frames that arrive on this sink can |
|
196 |
+be retrieved by the calling program using the interface defined in |
|
197 |
+@file{libavfilter/buffersink.h}. |
|
198 |
+ |
|
199 |
+This filter accepts no parameters. |
|
200 |
+ |
|
194 | 201 |
@c man end AUDIO SINKS |
195 | 202 |
|
196 | 203 |
@chapter Video Filters |
... | ... |
@@ -104,6 +104,10 @@ void avfilter_register_all(void) |
104 | 104 |
avfilter_register(&avfilter_vsink_buffer); |
105 | 105 |
} |
106 | 106 |
{ |
107 |
+ extern AVFilter avfilter_asink_abuffer; |
|
108 |
+ avfilter_register(&avfilter_asink_abuffer); |
|
109 |
+ } |
|
110 |
+ { |
|
107 | 111 |
extern AVFilter avfilter_vf_scale; |
108 | 112 |
avfilter_register(&avfilter_vf_scale); |
109 | 113 |
} |
... | ... |
@@ -23,13 +23,20 @@ |
23 | 23 |
* buffer sink |
24 | 24 |
*/ |
25 | 25 |
|
26 |
+#include "libavutil/audio_fifo.h" |
|
27 |
+#include "libavutil/audioconvert.h" |
|
26 | 28 |
#include "libavutil/fifo.h" |
29 |
+#include "libavutil/mathematics.h" |
|
27 | 30 |
|
31 |
+#include "audio.h" |
|
28 | 32 |
#include "avfilter.h" |
29 | 33 |
#include "buffersink.h" |
30 | 34 |
|
31 | 35 |
typedef struct { |
32 |
- AVFifoBuffer *fifo; ///< FIFO buffer of video frame references |
|
36 |
+ AVFifoBuffer *fifo; ///< FIFO buffer of frame references |
|
37 |
+ |
|
38 |
+ AVAudioFifo *audio_fifo; ///< FIFO for audio samples |
|
39 |
+ int64_t next_pts; ///< interpolating audio pts |
|
33 | 40 |
} BufferSinkContext; |
34 | 41 |
|
35 | 42 |
#define FIFO_INIT_SIZE 8 |
... | ... |
@@ -44,6 +51,9 @@ static av_cold void uninit(AVFilterContext *ctx) |
44 | 44 |
avfilter_unref_buffer(buf); |
45 | 45 |
} |
46 | 46 |
av_fifo_free(sink->fifo); |
47 |
+ |
|
48 |
+ if (sink->audio_fifo) |
|
49 |
+ av_audio_fifo_free(sink->audio_fifo); |
|
47 | 50 |
} |
48 | 51 |
|
49 | 52 |
static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) |
... | ... |
@@ -58,9 +68,8 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) |
58 | 58 |
return 0; |
59 | 59 |
} |
60 | 60 |
|
61 |
-static void end_frame(AVFilterLink *link) |
|
61 |
+static void write_buf(AVFilterContext *ctx, AVFilterBufferRef *buf) |
|
62 | 62 |
{ |
63 |
- AVFilterContext *ctx = link->dst; |
|
64 | 63 |
BufferSinkContext *sink = ctx->priv; |
65 | 64 |
|
66 | 65 |
if (av_fifo_space(sink->fifo) < sizeof(AVFilterBufferRef *) && |
... | ... |
@@ -69,10 +78,20 @@ static void end_frame(AVFilterLink *link) |
69 | 69 |
return; |
70 | 70 |
} |
71 | 71 |
|
72 |
- av_fifo_generic_write(sink->fifo, &link->cur_buf, sizeof(link->cur_buf), NULL); |
|
72 |
+ av_fifo_generic_write(sink->fifo, &buf, sizeof(buf), NULL); |
|
73 |
+} |
|
74 |
+ |
|
75 |
+static void end_frame(AVFilterLink *link) |
|
76 |
+{ |
|
77 |
+ write_buf(link->dst, link->cur_buf); |
|
73 | 78 |
link->cur_buf = NULL; |
74 | 79 |
} |
75 | 80 |
|
81 |
+static void filter_samples(AVFilterLink *link, AVFilterBufferRef *buf) |
|
82 |
+{ |
|
83 |
+ write_buf(link->dst, buf); |
|
84 |
+} |
|
85 |
+ |
|
76 | 86 |
int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf) |
77 | 87 |
{ |
78 | 88 |
BufferSinkContext *sink = ctx->priv; |
... | ... |
@@ -98,6 +117,66 @@ int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf) |
98 | 98 |
return 0; |
99 | 99 |
} |
100 | 100 |
|
101 |
+static int read_from_fifo(AVFilterContext *ctx, AVFilterBufferRef **pbuf, |
|
102 |
+ int nb_samples) |
|
103 |
+{ |
|
104 |
+ BufferSinkContext *s = ctx->priv; |
|
105 |
+ AVFilterLink *link = ctx->inputs[0]; |
|
106 |
+ AVFilterBufferRef *buf; |
|
107 |
+ |
|
108 |
+ if (!(buf = ff_get_audio_buffer(link, AV_PERM_WRITE, nb_samples))) |
|
109 |
+ return AVERROR(ENOMEM); |
|
110 |
+ av_audio_fifo_read(s->audio_fifo, (void**)buf->extended_data, nb_samples); |
|
111 |
+ |
|
112 |
+ buf->pts = s->next_pts; |
|
113 |
+ s->next_pts += av_rescale_q(nb_samples, (AVRational){1, link->sample_rate}, |
|
114 |
+ link->time_base); |
|
115 |
+ |
|
116 |
+ *pbuf = buf; |
|
117 |
+ return 0; |
|
118 |
+ |
|
119 |
+} |
|
120 |
+ |
|
121 |
+int av_buffersink_read_samples(AVFilterContext *ctx, AVFilterBufferRef **pbuf, |
|
122 |
+ int nb_samples) |
|
123 |
+{ |
|
124 |
+ BufferSinkContext *s = ctx->priv; |
|
125 |
+ AVFilterLink *link = ctx->inputs[0]; |
|
126 |
+ int ret = 0; |
|
127 |
+ |
|
128 |
+ if (!s->audio_fifo) { |
|
129 |
+ int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout); |
|
130 |
+ if (!(s->audio_fifo = av_audio_fifo_alloc(link->format, nb_channels, nb_samples))) |
|
131 |
+ return AVERROR(ENOMEM); |
|
132 |
+ } |
|
133 |
+ |
|
134 |
+ while (ret >= 0) { |
|
135 |
+ AVFilterBufferRef *buf; |
|
136 |
+ |
|
137 |
+ if (av_audio_fifo_size(s->audio_fifo) >= nb_samples) |
|
138 |
+ return read_from_fifo(ctx, pbuf, nb_samples); |
|
139 |
+ |
|
140 |
+ ret = av_buffersink_read(ctx, &buf); |
|
141 |
+ if (ret == AVERROR_EOF && av_audio_fifo_size(s->audio_fifo)) |
|
142 |
+ return read_from_fifo(ctx, pbuf, av_audio_fifo_size(s->audio_fifo)); |
|
143 |
+ else if (ret < 0) |
|
144 |
+ return ret; |
|
145 |
+ |
|
146 |
+ if (buf->pts != AV_NOPTS_VALUE) { |
|
147 |
+ s->next_pts = buf->pts - |
|
148 |
+ av_rescale_q(av_audio_fifo_size(s->audio_fifo), |
|
149 |
+ (AVRational){ 1, link->sample_rate }, |
|
150 |
+ link->time_base); |
|
151 |
+ } |
|
152 |
+ |
|
153 |
+ ret = av_audio_fifo_write(s->audio_fifo, (void**)buf->extended_data, |
|
154 |
+ buf->audio->nb_samples); |
|
155 |
+ avfilter_unref_buffer(buf); |
|
156 |
+ } |
|
157 |
+ |
|
158 |
+ return ret; |
|
159 |
+} |
|
160 |
+ |
|
101 | 161 |
AVFilter avfilter_vsink_buffer = { |
102 | 162 |
.name = "buffersink", |
103 | 163 |
.description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."), |
... | ... |
@@ -112,3 +191,18 @@ AVFilter avfilter_vsink_buffer = { |
112 | 112 |
{ .name = NULL }}, |
113 | 113 |
.outputs = (AVFilterPad[]) {{ .name = NULL }}, |
114 | 114 |
}; |
115 |
+ |
|
116 |
+AVFilter avfilter_asink_abuffer = { |
|
117 |
+ .name = "abuffersink", |
|
118 |
+ .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."), |
|
119 |
+ .priv_size = sizeof(BufferSinkContext), |
|
120 |
+ .init = init, |
|
121 |
+ .uninit = uninit, |
|
122 |
+ |
|
123 |
+ .inputs = (AVFilterPad[]) {{ .name = "default", |
|
124 |
+ .type = AVMEDIA_TYPE_AUDIO, |
|
125 |
+ .filter_samples = filter_samples, |
|
126 |
+ .min_perms = AV_PERM_READ, }, |
|
127 |
+ { .name = NULL }}, |
|
128 |
+ .outputs = (AVFilterPad[]) {{ .name = NULL }}, |
|
129 |
+}; |
... | ... |
@@ -29,7 +29,7 @@ |
29 | 29 |
/** |
30 | 30 |
* Get a buffer with filtered data from sink and put it in buf. |
31 | 31 |
* |
32 |
- * @param sink pointer to a context of a buffersink AVFilter. |
|
32 |
+ * @param sink pointer to a context of a buffersink or abuffersink AVFilter. |
|
33 | 33 |
* @param buf pointer to the buffer will be written here if buf is non-NULL. buf |
34 | 34 |
* must be freed by the caller using avfilter_unref_buffer(). |
35 | 35 |
* Buf may also be NULL to query whether a buffer is ready to be |
... | ... |
@@ -40,4 +40,23 @@ |
40 | 40 |
*/ |
41 | 41 |
int av_buffersink_read(AVFilterContext *sink, AVFilterBufferRef **buf); |
42 | 42 |
|
43 |
+/** |
|
44 |
+ * Same as av_buffersink_read, but with the ability to specify the number of |
|
45 |
+ * samples read. This function is less efficient than av_buffersink_read(), |
|
46 |
+ * because it copies the data around. |
|
47 |
+ * |
|
48 |
+ * @param sink pointer to a context of the abuffersink AVFilter. |
|
49 |
+ * @param buf pointer to the buffer will be written here if buf is non-NULL. buf |
|
50 |
+ * must be freed by the caller using avfilter_unref_buffer(). buf |
|
51 |
+ * will contain exactly nb_samples audio samples, except at the end |
|
52 |
+ * of stream, when it can contain less than nb_samples. |
|
53 |
+ * Buf may also be NULL to query whether a buffer is ready to be |
|
54 |
+ * output. |
|
55 |
+ * |
|
56 |
+ * @warning do not mix this function with av_buffersink_read(). Use only one or |
|
57 |
+ * the other with a single sink, not both. |
|
58 |
+ */ |
|
59 |
+int av_buffersink_read_samples(AVFilterContext *ctx, AVFilterBufferRef **buf, |
|
60 |
+ int nb_samples); |
|
61 |
+ |
|
43 | 62 |
#endif /* AVFILTER_BUFFERSINK_H */ |