00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00026 #include "libavutil/eval.h"
00027 #include "avfilter.h"
00028 #include "audio.h"
00029 #include "internal.h"
00030
00031 #define QUEUE_SIZE 16
00032
00033 static const char * const var_names[] = {
00034 "b1", "b2",
00035 "s1", "s2",
00036 "t1", "t2",
00037 NULL
00038 };
00039
00040 enum var_name {
00041 VAR_B1, VAR_B2,
00042 VAR_S1, VAR_S2,
00043 VAR_T1, VAR_T2,
00044 VAR_NB
00045 };
00046
00047 typedef struct {
00048 AVExpr *expr;
00049 double var_values[VAR_NB];
00050 struct buf_queue {
00051 AVFilterBufferRef *buf[QUEUE_SIZE];
00052 unsigned tail, nb;
00053
00054
00055 } queue[2];
00056 int req[2];
00057 int next_out;
00058 int eof;
00059 } AStreamSyncContext;
00060
00061 static const char *default_expr = "t1-t2";
00062
00063 static av_cold int init(AVFilterContext *ctx, const char *args0, void *opaque)
00064 {
00065 AStreamSyncContext *as = ctx->priv;
00066 const char *expr = args0 ? args0 : default_expr;
00067 int r, i;
00068
00069 r = av_expr_parse(&as->expr, expr, var_names,
00070 NULL, NULL, NULL, NULL, 0, ctx);
00071 if (r < 0) {
00072 av_log(ctx, AV_LOG_ERROR, "Error in expression \"%s\"\n", expr);
00073 return r;
00074 }
00075 for (i = 0; i < 42; i++)
00076 av_expr_eval(as->expr, as->var_values, NULL);
00077 return 0;
00078 }
00079
00080 static int query_formats(AVFilterContext *ctx)
00081 {
00082 int i;
00083 AVFilterFormats *formats;
00084 AVFilterChannelLayouts *layouts;
00085
00086 for (i = 0; i < 2; i++) {
00087 formats = ctx->inputs[i]->in_formats;
00088 avfilter_formats_ref(formats, &ctx->inputs[i]->out_formats);
00089 avfilter_formats_ref(formats, &ctx->outputs[i]->in_formats);
00090 layouts = ctx->inputs[i]->in_channel_layouts;
00091 ff_channel_layouts_ref(layouts, &ctx->inputs[i]->out_channel_layouts);
00092 ff_channel_layouts_ref(layouts, &ctx->outputs[i]->in_channel_layouts);
00093 }
00094 return 0;
00095 }
00096
00097 static int config_output(AVFilterLink *outlink)
00098 {
00099 AVFilterContext *ctx = outlink->src;
00100 int id = outlink == ctx->outputs[1];
00101
00102 outlink->sample_rate = ctx->inputs[id]->sample_rate;
00103 outlink->time_base = ctx->inputs[id]->time_base;
00104 return 0;
00105 }
00106
00107 static void send_out(AVFilterContext *ctx, int out_id)
00108 {
00109 AStreamSyncContext *as = ctx->priv;
00110 struct buf_queue *queue = &as->queue[out_id];
00111 AVFilterBufferRef *buf = queue->buf[queue->tail];
00112
00113 queue->buf[queue->tail] = NULL;
00114 as->var_values[VAR_B1 + out_id]++;
00115 as->var_values[VAR_S1 + out_id] += buf->audio->nb_samples;
00116 if (buf->pts != AV_NOPTS_VALUE)
00117 as->var_values[VAR_T1 + out_id] =
00118 av_q2d(ctx->outputs[out_id]->time_base) * buf->pts;
00119 as->var_values[VAR_T1 + out_id] += buf->audio->nb_samples /
00120 (double)ctx->inputs[out_id]->sample_rate;
00121 ff_filter_samples(ctx->outputs[out_id], buf);
00122 queue->nb--;
00123 queue->tail = (queue->tail + 1) % QUEUE_SIZE;
00124 if (as->req[out_id])
00125 as->req[out_id]--;
00126 }
00127
00128 static void send_next(AVFilterContext *ctx)
00129 {
00130 AStreamSyncContext *as = ctx->priv;
00131 int i;
00132
00133 while (1) {
00134 if (!as->queue[as->next_out].nb)
00135 break;
00136 send_out(ctx, as->next_out);
00137 if (!as->eof)
00138 as->next_out = av_expr_eval(as->expr, as->var_values, NULL) >= 0;
00139 }
00140 for (i = 0; i < 2; i++)
00141 if (as->queue[i].nb == QUEUE_SIZE)
00142 send_out(ctx, i);
00143 }
00144
00145 static int request_frame(AVFilterLink *outlink)
00146 {
00147 AVFilterContext *ctx = outlink->src;
00148 AStreamSyncContext *as = ctx->priv;
00149 int id = outlink == ctx->outputs[1];
00150
00151 as->req[id]++;
00152 while (as->req[id] && !(as->eof & (1 << id))) {
00153 if (as->queue[as->next_out].nb) {
00154 send_next(ctx);
00155 } else {
00156 as->eof |= 1 << as->next_out;
00157 avfilter_request_frame(ctx->inputs[as->next_out]);
00158 if (as->eof & (1 << as->next_out))
00159 as->next_out = !as->next_out;
00160 }
00161 }
00162 return 0;
00163 }
00164
00165 static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
00166 {
00167 AVFilterContext *ctx = inlink->dst;
00168 AStreamSyncContext *as = ctx->priv;
00169 int id = inlink == ctx->inputs[1];
00170
00171 as->queue[id].buf[(as->queue[id].tail + as->queue[id].nb++) % QUEUE_SIZE] =
00172 insamples;
00173 as->eof &= ~(1 << id);
00174 send_next(ctx);
00175 }
00176
00177 AVFilter avfilter_af_astreamsync = {
00178 .name = "astreamsync",
00179 .description = NULL_IF_CONFIG_SMALL("Copy two streams of audio data "
00180 "in a configurable order."),
00181 .priv_size = sizeof(AStreamSyncContext),
00182 .init = init,
00183 .query_formats = query_formats,
00184
00185 .inputs = (const AVFilterPad[]) {
00186 { .name = "in1",
00187 .type = AVMEDIA_TYPE_AUDIO,
00188 .filter_samples = filter_samples,
00189 .min_perms = AV_PERM_READ, },
00190 { .name = "in2",
00191 .type = AVMEDIA_TYPE_AUDIO,
00192 .filter_samples = filter_samples,
00193 .min_perms = AV_PERM_READ, },
00194 { .name = NULL }
00195 },
00196 .outputs = (const AVFilterPad[]) {
00197 { .name = "out1",
00198 .type = AVMEDIA_TYPE_AUDIO,
00199 .config_props = config_output,
00200 .request_frame = request_frame, },
00201 { .name = "out2",
00202 .type = AVMEDIA_TYPE_AUDIO,
00203 .config_props = config_output,
00204 .request_frame = request_frame, },
00205 { .name = NULL }
00206 },
00207 };