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