yading@10
|
1 /*
|
yading@10
|
2 * Copyright (c) 2012 Michael Niedermayer
|
yading@10
|
3 *
|
yading@10
|
4 * This file is part of FFmpeg.
|
yading@10
|
5 *
|
yading@10
|
6 * FFmpeg is free software; you can redistribute it and/or
|
yading@10
|
7 * modify it under the terms of the GNU Lesser General Public
|
yading@10
|
8 * License as published by the Free Software Foundation; either
|
yading@10
|
9 * version 2.1 of the License, or (at your option) any later version.
|
yading@10
|
10 *
|
yading@10
|
11 * FFmpeg is distributed in the hope that it will be useful,
|
yading@10
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
yading@10
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
yading@10
|
14 * Lesser General Public License for more details.
|
yading@10
|
15 *
|
yading@10
|
16 * You should have received a copy of the GNU Lesser General Public
|
yading@10
|
17 * License along with FFmpeg; if not, write to the Free Software
|
yading@10
|
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
yading@10
|
19 *
|
yading@10
|
20 */
|
yading@10
|
21
|
yading@10
|
22 /**
|
yading@10
|
23 * @file
|
yading@10
|
24 * audio pad filter.
|
yading@10
|
25 *
|
yading@10
|
26 * Based on af_aresample.c
|
yading@10
|
27 */
|
yading@10
|
28
|
yading@10
|
29 #include "libavutil/avstring.h"
|
yading@10
|
30 #include "libavutil/channel_layout.h"
|
yading@10
|
31 #include "libavutil/opt.h"
|
yading@10
|
32 #include "libavutil/samplefmt.h"
|
yading@10
|
33 #include "libavutil/avassert.h"
|
yading@10
|
34 #include "avfilter.h"
|
yading@10
|
35 #include "audio.h"
|
yading@10
|
36 #include "internal.h"
|
yading@10
|
37
|
yading@10
|
38 typedef struct {
|
yading@10
|
39 const AVClass *class;
|
yading@10
|
40 int64_t next_pts;
|
yading@10
|
41
|
yading@10
|
42 int packet_size;
|
yading@10
|
43 int64_t pad_len;
|
yading@10
|
44 int64_t whole_len;
|
yading@10
|
45 } APadContext;
|
yading@10
|
46
|
yading@10
|
47 #define OFFSET(x) offsetof(APadContext, x)
|
yading@10
|
48 #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
|
yading@10
|
49
|
yading@10
|
50 static const AVOption apad_options[] = {
|
yading@10
|
51 { "packet_size", "set silence packet size", OFFSET(packet_size), AV_OPT_TYPE_INT, { .i64 = 4096 }, 0, INT_MAX, A },
|
yading@10
|
52 { "pad_len", "number of samples of silence to add", OFFSET(pad_len), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, A },
|
yading@10
|
53 { "whole_len", "target number of samples in the audio stream", OFFSET(whole_len), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, A },
|
yading@10
|
54 { NULL },
|
yading@10
|
55 };
|
yading@10
|
56
|
yading@10
|
57 AVFILTER_DEFINE_CLASS(apad);
|
yading@10
|
58
|
yading@10
|
59 static av_cold int init(AVFilterContext *ctx)
|
yading@10
|
60 {
|
yading@10
|
61 APadContext *apad = ctx->priv;
|
yading@10
|
62
|
yading@10
|
63 apad->next_pts = AV_NOPTS_VALUE;
|
yading@10
|
64 if (apad->whole_len && apad->pad_len) {
|
yading@10
|
65 av_log(ctx, AV_LOG_ERROR, "Both whole and pad length are set, this is not possible\n");
|
yading@10
|
66 return AVERROR(EINVAL);
|
yading@10
|
67 }
|
yading@10
|
68
|
yading@10
|
69 return 0;
|
yading@10
|
70 }
|
yading@10
|
71
|
yading@10
|
72 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
|
yading@10
|
73 {
|
yading@10
|
74 AVFilterContext *ctx = inlink->dst;
|
yading@10
|
75 APadContext *apad = ctx->priv;
|
yading@10
|
76
|
yading@10
|
77 if (apad->whole_len)
|
yading@10
|
78 apad->whole_len -= frame->nb_samples;
|
yading@10
|
79
|
yading@10
|
80 apad->next_pts = frame->pts + av_rescale_q(frame->nb_samples, (AVRational){1, inlink->sample_rate}, inlink->time_base);
|
yading@10
|
81 return ff_filter_frame(ctx->outputs[0], frame);
|
yading@10
|
82 }
|
yading@10
|
83
|
yading@10
|
84 static int request_frame(AVFilterLink *outlink)
|
yading@10
|
85 {
|
yading@10
|
86 AVFilterContext *ctx = outlink->src;
|
yading@10
|
87 APadContext *apad = ctx->priv;
|
yading@10
|
88 int ret;
|
yading@10
|
89
|
yading@10
|
90 ret = ff_request_frame(ctx->inputs[0]);
|
yading@10
|
91
|
yading@10
|
92 if (ret == AVERROR_EOF) {
|
yading@10
|
93 int n_out = apad->packet_size;
|
yading@10
|
94 AVFrame *outsamplesref;
|
yading@10
|
95
|
yading@10
|
96 if (apad->whole_len > 0) {
|
yading@10
|
97 apad->pad_len = apad->whole_len;
|
yading@10
|
98 apad->whole_len = 0;
|
yading@10
|
99 }
|
yading@10
|
100 if (apad->pad_len > 0) {
|
yading@10
|
101 n_out = FFMIN(n_out, apad->pad_len);
|
yading@10
|
102 apad->pad_len -= n_out;
|
yading@10
|
103 }
|
yading@10
|
104
|
yading@10
|
105 if(!n_out)
|
yading@10
|
106 return AVERROR_EOF;
|
yading@10
|
107
|
yading@10
|
108 outsamplesref = ff_get_audio_buffer(outlink, n_out);
|
yading@10
|
109 if (!outsamplesref)
|
yading@10
|
110 return AVERROR(ENOMEM);
|
yading@10
|
111
|
yading@10
|
112 av_assert0(outsamplesref->sample_rate == outlink->sample_rate);
|
yading@10
|
113 av_assert0(outsamplesref->nb_samples == n_out);
|
yading@10
|
114
|
yading@10
|
115 av_samples_set_silence(outsamplesref->extended_data, 0,
|
yading@10
|
116 n_out,
|
yading@10
|
117 av_frame_get_channels(outsamplesref),
|
yading@10
|
118 outsamplesref->format);
|
yading@10
|
119
|
yading@10
|
120 outsamplesref->pts = apad->next_pts;
|
yading@10
|
121 if (apad->next_pts != AV_NOPTS_VALUE)
|
yading@10
|
122 apad->next_pts += av_rescale_q(n_out, (AVRational){1, outlink->sample_rate}, outlink->time_base);
|
yading@10
|
123
|
yading@10
|
124 return ff_filter_frame(outlink, outsamplesref);
|
yading@10
|
125 }
|
yading@10
|
126 return ret;
|
yading@10
|
127 }
|
yading@10
|
128
|
yading@10
|
129 static const AVFilterPad apad_inputs[] = {
|
yading@10
|
130 {
|
yading@10
|
131 .name = "default",
|
yading@10
|
132 .type = AVMEDIA_TYPE_AUDIO,
|
yading@10
|
133 .filter_frame = filter_frame,
|
yading@10
|
134 },
|
yading@10
|
135 { NULL },
|
yading@10
|
136 };
|
yading@10
|
137
|
yading@10
|
138 static const AVFilterPad apad_outputs[] = {
|
yading@10
|
139 {
|
yading@10
|
140 .name = "default",
|
yading@10
|
141 .request_frame = request_frame,
|
yading@10
|
142 .type = AVMEDIA_TYPE_AUDIO,
|
yading@10
|
143 },
|
yading@10
|
144 { NULL },
|
yading@10
|
145 };
|
yading@10
|
146
|
yading@10
|
147 AVFilter avfilter_af_apad = {
|
yading@10
|
148 .name = "apad",
|
yading@10
|
149 .description = NULL_IF_CONFIG_SMALL("Pad audio with silence."),
|
yading@10
|
150 .init = init,
|
yading@10
|
151 .priv_size = sizeof(APadContext),
|
yading@10
|
152 .inputs = apad_inputs,
|
yading@10
|
153 .outputs = apad_outputs,
|
yading@10
|
154 .priv_class = &apad_class,
|
yading@10
|
155 };
|