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)
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, *rates;
00084 AVFilterChannelLayouts *layouts;
00085
00086 for (i = 0; i < 2; i++) {
00087 formats = ctx->inputs[i]->in_formats;
00088 ff_formats_ref(formats, &ctx->inputs[i]->out_formats);
00089 ff_formats_ref(formats, &ctx->outputs[i]->in_formats);
00090 rates = ff_all_samplerates();
00091 ff_formats_ref(rates, &ctx->inputs[i]->out_samplerates);
00092 ff_formats_ref(rates, &ctx->outputs[i]->in_samplerates);
00093 layouts = ctx->inputs[i]->in_channel_layouts;
00094 ff_channel_layouts_ref(layouts, &ctx->inputs[i]->out_channel_layouts);
00095 ff_channel_layouts_ref(layouts, &ctx->outputs[i]->in_channel_layouts);
00096 }
00097 return 0;
00098 }
00099
00100 static int config_output(AVFilterLink *outlink)
00101 {
00102 AVFilterContext *ctx = outlink->src;
00103 int id = outlink == ctx->outputs[1];
00104
00105 outlink->sample_rate = ctx->inputs[id]->sample_rate;
00106 outlink->time_base = ctx->inputs[id]->time_base;
00107 return 0;
00108 }
00109
00110 static int send_out(AVFilterContext *ctx, int out_id)
00111 {
00112 AStreamSyncContext *as = ctx->priv;
00113 struct buf_queue *queue = &as->queue[out_id];
00114 AVFilterBufferRef *buf = queue->buf[queue->tail];
00115 int ret;
00116
00117 queue->buf[queue->tail] = NULL;
00118 as->var_values[VAR_B1 + out_id]++;
00119 as->var_values[VAR_S1 + out_id] += buf->audio->nb_samples;
00120 if (buf->pts != AV_NOPTS_VALUE)
00121 as->var_values[VAR_T1 + out_id] =
00122 av_q2d(ctx->outputs[out_id]->time_base) * buf->pts;
00123 as->var_values[VAR_T1 + out_id] += buf->audio->nb_samples /
00124 (double)ctx->inputs[out_id]->sample_rate;
00125 ret = ff_filter_samples(ctx->outputs[out_id], buf);
00126 queue->nb--;
00127 queue->tail = (queue->tail + 1) % QUEUE_SIZE;
00128 if (as->req[out_id])
00129 as->req[out_id]--;
00130 return ret;
00131 }
00132
00133 static void send_next(AVFilterContext *ctx)
00134 {
00135 AStreamSyncContext *as = ctx->priv;
00136 int i;
00137
00138 while (1) {
00139 if (!as->queue[as->next_out].nb)
00140 break;
00141 send_out(ctx, as->next_out);
00142 if (!as->eof)
00143 as->next_out = av_expr_eval(as->expr, as->var_values, NULL) >= 0;
00144 }
00145 for (i = 0; i < 2; i++)
00146 if (as->queue[i].nb == QUEUE_SIZE)
00147 send_out(ctx, i);
00148 }
00149
00150 static int request_frame(AVFilterLink *outlink)
00151 {
00152 AVFilterContext *ctx = outlink->src;
00153 AStreamSyncContext *as = ctx->priv;
00154 int id = outlink == ctx->outputs[1];
00155
00156 as->req[id]++;
00157 while (as->req[id] && !(as->eof & (1 << id))) {
00158 if (as->queue[as->next_out].nb) {
00159 send_next(ctx);
00160 } else {
00161 as->eof |= 1 << as->next_out;
00162 ff_request_frame(ctx->inputs[as->next_out]);
00163 if (as->eof & (1 << as->next_out))
00164 as->next_out = !as->next_out;
00165 }
00166 }
00167 return 0;
00168 }
00169
00170 static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
00171 {
00172 AVFilterContext *ctx = inlink->dst;
00173 AStreamSyncContext *as = ctx->priv;
00174 int id = inlink == ctx->inputs[1];
00175
00176 as->queue[id].buf[(as->queue[id].tail + as->queue[id].nb++) % QUEUE_SIZE] =
00177 insamples;
00178 as->eof &= ~(1 << id);
00179 send_next(ctx);
00180 return 0;
00181 }
00182
00183 AVFilter avfilter_af_astreamsync = {
00184 .name = "astreamsync",
00185 .description = NULL_IF_CONFIG_SMALL("Copy two streams of audio data "
00186 "in a configurable order."),
00187 .priv_size = sizeof(AStreamSyncContext),
00188 .init = init,
00189 .query_formats = query_formats,
00190
00191 .inputs = (const AVFilterPad[]) {
00192 { .name = "in1",
00193 .type = AVMEDIA_TYPE_AUDIO,
00194 .filter_samples = filter_samples,
00195 .min_perms = AV_PERM_READ | AV_PERM_PRESERVE, },
00196 { .name = "in2",
00197 .type = AVMEDIA_TYPE_AUDIO,
00198 .filter_samples = filter_samples,
00199 .min_perms = AV_PERM_READ | AV_PERM_PRESERVE, },
00200 { .name = NULL }
00201 },
00202 .outputs = (const AVFilterPad[]) {
00203 { .name = "out1",
00204 .type = AVMEDIA_TYPE_AUDIO,
00205 .config_props = config_output,
00206 .request_frame = request_frame, },
00207 { .name = "out2",
00208 .type = AVMEDIA_TYPE_AUDIO,
00209 .config_props = config_output,
00210 .request_frame = request_frame, },
00211 { .name = NULL }
00212 },
00213 };