FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
af_astreamsync.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011 Nicolas George <nicolas.george@normalesup.org>
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * @file
23  * Stream (de)synchronization filter
24  */
25 
26 #include "libavutil/eval.h"
27 #include "libavutil/opt.h"
28 #include "avfilter.h"
29 #include "audio.h"
30 #include "internal.h"
31 
32 #define QUEUE_SIZE 16
33 
34 static const char * const var_names[] = {
35  "b1", "b2",
36  "s1", "s2",
37  "t1", "t2",
38  NULL
39 };
40 
41 enum var_name {
46 };
47 
48 typedef struct {
49  const AVClass *class;
51  char *expr_str;
52  double var_values[VAR_NB];
53  struct buf_queue {
55  unsigned tail, nb;
56  /* buf[tail] is the oldest,
57  buf[(tail + nb) % QUEUE_SIZE] is where the next is added */
58  } queue[2];
59  int req[2];
60  int next_out;
61  int eof; /* bitmask, one bit for each stream */
63 
64 #define OFFSET(x) offsetof(AStreamSyncContext, x)
65 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
66 static const AVOption astreamsync_options[] = {
67  { "expr", "set stream selection expression", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "t1-t2" }, .flags = FLAGS },
68  { "e", "set stream selection expression", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "t1-t2" }, .flags = FLAGS },
69  { NULL }
70 };
71 
72 AVFILTER_DEFINE_CLASS(astreamsync);
73 
74 static av_cold int init(AVFilterContext *ctx)
75 {
76  AStreamSyncContext *as = ctx->priv;
77  int r, i;
78 
79  r = av_expr_parse(&as->expr, as->expr_str, var_names,
80  NULL, NULL, NULL, NULL, 0, ctx);
81  if (r < 0) {
82  av_log(ctx, AV_LOG_ERROR, "Error in expression \"%s\"\n", as->expr_str);
83  return r;
84  }
85  for (i = 0; i < 42; i++)
86  av_expr_eval(as->expr, as->var_values, NULL); /* exercize prng */
87  return 0;
88 }
89 
91 {
92  int i, ret;
95 
96  for (i = 0; i < 2; i++) {
97  formats = ctx->inputs[i]->in_formats;
98  if ((ret = ff_formats_ref(formats, &ctx->inputs[i]->out_formats)) < 0 ||
99  (ret = ff_formats_ref(formats, &ctx->outputs[i]->in_formats)) < 0)
100  return ret;
101  rates = ff_all_samplerates();
102  if ((ret = ff_formats_ref(rates, &ctx->inputs[i]->out_samplerates)) < 0 ||
103  (ret = ff_formats_ref(rates, &ctx->outputs[i]->in_samplerates)) < 0)
104  return ret;
105  layouts = ctx->inputs[i]->in_channel_layouts;
106  if ((ret = ff_channel_layouts_ref(layouts, &ctx->inputs[i]->out_channel_layouts)) < 0 ||
107  (ret = ff_channel_layouts_ref(layouts, &ctx->outputs[i]->in_channel_layouts)) < 0)
108  return ret;
109  }
110  return 0;
111 }
112 
113 static int config_output(AVFilterLink *outlink)
114 {
115  AVFilterContext *ctx = outlink->src;
116  int id = outlink == ctx->outputs[1];
117 
118  outlink->sample_rate = ctx->inputs[id]->sample_rate;
119  outlink->time_base = ctx->inputs[id]->time_base;
120  return 0;
121 }
122 
123 static int send_out(AVFilterContext *ctx, int out_id)
124 {
125  AStreamSyncContext *as = ctx->priv;
126  struct buf_queue *queue = &as->queue[out_id];
127  AVFrame *buf = queue->buf[queue->tail];
128  int ret;
129 
130  queue->buf[queue->tail] = NULL;
131  as->var_values[VAR_B1 + out_id]++;
132  as->var_values[VAR_S1 + out_id] += buf->nb_samples;
133  if (buf->pts != AV_NOPTS_VALUE)
134  as->var_values[VAR_T1 + out_id] =
135  av_q2d(ctx->outputs[out_id]->time_base) * buf->pts;
136  as->var_values[VAR_T1 + out_id] += buf->nb_samples /
137  (double)ctx->inputs[out_id]->sample_rate;
138  ret = ff_filter_frame(ctx->outputs[out_id], buf);
139  queue->nb--;
140  queue->tail = (queue->tail + 1) % QUEUE_SIZE;
141  if (as->req[out_id])
142  as->req[out_id]--;
143  return ret;
144 }
145 
146 static void send_next(AVFilterContext *ctx)
147 {
148  AStreamSyncContext *as = ctx->priv;
149  int i;
150 
151  while (1) {
152  if (!as->queue[as->next_out].nb)
153  break;
154  send_out(ctx, as->next_out);
155  if (!as->eof)
156  as->next_out = av_expr_eval(as->expr, as->var_values, NULL) >= 0;
157  }
158  for (i = 0; i < 2; i++)
159  if (as->queue[i].nb == QUEUE_SIZE)
160  send_out(ctx, i);
161 }
162 
163 static int request_frame(AVFilterLink *outlink)
164 {
165  AVFilterContext *ctx = outlink->src;
166  AStreamSyncContext *as = ctx->priv;
167  int id = outlink == ctx->outputs[1];
168 
169  as->req[id]++;
170  while (as->req[id] && !(as->eof & (1 << id))) {
171  if (as->queue[as->next_out].nb) {
172  send_next(ctx);
173  } else {
174  as->eof |= 1 << as->next_out;
175  ff_request_frame(ctx->inputs[as->next_out]);
176  if (as->eof & (1 << as->next_out))
177  as->next_out = !as->next_out;
178  }
179  }
180  return 0;
181 }
182 
183 static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
184 {
185  AVFilterContext *ctx = inlink->dst;
186  AStreamSyncContext *as = ctx->priv;
187  int id = inlink == ctx->inputs[1];
188 
189  as->queue[id].buf[(as->queue[id].tail + as->queue[id].nb++) % QUEUE_SIZE] =
190  insamples;
191  as->eof &= ~(1 << id);
192  send_next(ctx);
193  return 0;
194 }
195 
196 static av_cold void uninit(AVFilterContext *ctx)
197 {
198  AStreamSyncContext *as = ctx->priv;
199 
200  av_expr_free(as->expr);
201  as->expr = NULL;
202 }
203 
204 static const AVFilterPad astreamsync_inputs[] = {
205  {
206  .name = "in1",
207  .type = AVMEDIA_TYPE_AUDIO,
208  .filter_frame = filter_frame,
209  },{
210  .name = "in2",
211  .type = AVMEDIA_TYPE_AUDIO,
212  .filter_frame = filter_frame,
213  },
214  { NULL }
215 };
216 
218  {
219  .name = "out1",
220  .type = AVMEDIA_TYPE_AUDIO,
221  .config_props = config_output,
222  .request_frame = request_frame,
223  },{
224  .name = "out2",
225  .type = AVMEDIA_TYPE_AUDIO,
226  .config_props = config_output,
227  .request_frame = request_frame,
228  },
229  { NULL }
230 };
231 
233  .name = "astreamsync",
234  .description = NULL_IF_CONFIG_SMALL("Copy two streams of audio data "
235  "in a configurable order."),
236  .priv_size = sizeof(AStreamSyncContext),
237  .init = init,
238  .uninit = uninit,
240  .inputs = astreamsync_inputs,
241  .outputs = astreamsync_outputs,
242  .priv_class = &astreamsync_class,
243 };
#define NULL
Definition: coverity.c:32
This structure describes decoded (raw) audio or video data.
Definition: frame.h:171
AVOption.
Definition: opt.h:245
enum AVCodecID id
Definition: mxfenc.c:103
Main libavfilter public API header.
static enum AVSampleFormat formats[]
int av_expr_parse(AVExpr **expr, const char *s, const char *const *const_names, const char *const *func1_names, double(*const *funcs1)(void *, double), const char *const *func2_names, double(*const *funcs2)(void *, double, double), int log_offset, void *log_ctx)
Parse an expression.
Definition: eval.c:653
static int config_output(AVFilterLink *outlink)
const char * name
Pad name.
Definition: internal.h:58
#define OFFSET(x)
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:312
int ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref)
Add *ref as a new reference to f.
Definition: formats.c:424
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1133
#define av_cold
Definition: attributes.h:82
AVOptions.
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:252
Definition: eval.c:144
static double av_q2d(AVRational a)
Convert rational to double.
Definition: rational.h:80
static const AVFilterPad astreamsync_outputs[]
#define av_log(a,...)
#define FLAGS
static const int rates[]
A filter pad used for either input or output.
Definition: internal.h:52
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:175
static const AVOption astreamsync_options[]
const char * r
Definition: vf_curves.c:107
void * priv
private data for use by the filter
Definition: avfilter.h:319
static int query_formats(AVFilterContext *ctx)
var_name
Definition: aeval.c:46
int ff_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
Add *ref as a new reference to formats.
Definition: formats.c:429
static av_cold void uninit(AVFilterContext *ctx)
A list of supported channel layouts.
Definition: formats.h:85
static const AVFilterPad outputs[]
Definition: af_agate.c:222
#define QUEUE_SIZE
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
Definition: eval.c:313
AVFilter ff_af_astreamsync
double var_values[VAR_NB]
void * buf
Definition: avisynth_c.h:553
AVFrame * buf[QUEUE_SIZE]
struct AStreamSyncContext::buf_queue queue[2]
Describe the class of an AVClass context structure.
Definition: log.h:67
Filter definition.
Definition: avfilter.h:141
const char * name
Filter name.
Definition: avfilter.h:145
static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:316
enum MovChannelLayoutTag * layouts
Definition: mov_chan.c:434
AVFilterFormats * ff_all_samplerates(void)
Definition: formats.c:384
static void send_next(AVFilterContext *ctx)
static const AVFilterPad inputs[]
Definition: af_agate.c:212
static const AVFilterPad astreamsync_inputs[]
static av_cold int init(AVFilterContext *ctx)
AVFILTER_DEFINE_CLASS(astreamsync)
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
Definition: eval.c:708
A list of supported formats for one end of a filter link.
Definition: formats.h:64
An instance of a filter.
Definition: avfilter.h:304
int ff_request_frame(AVFilterLink *link)
Request an input frame from the filter at the other end of the link.
Definition: avfilter.c:343
static int send_out(AVFilterContext *ctx, int out_id)
internal API functions
int nb_samples
number of audio samples (per channel) described by this frame
Definition: frame.h:225
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:240
static const char *const var_names[]
static int request_frame(AVFilterLink *outlink)
simple arithmetic expression evaluator