00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00027
00028
00029 #include "libavutil/eval.h"
00030 #include "libavutil/internal.h"
00031 #include "libavutil/mathematics.h"
00032 #include "avfilter.h"
00033 #include "internal.h"
00034 #include "audio.h"
00035 #include "video.h"
00036
00037 static const char *const var_names[] = {
00038 "INTERLACED",
00039 "N",
00040 "NB_CONSUMED_SAMPLES",
00041 "NB_SAMPLES",
00042 "POS",
00043 "PREV_INPTS",
00044 "PREV_OUTPTS",
00045 "PTS",
00046 "SAMPLE_RATE",
00047 "STARTPTS",
00048 "TB",
00049 NULL
00050 };
00051
00052 enum var_name {
00053 VAR_INTERLACED,
00054 VAR_N,
00055 VAR_NB_CONSUMED_SAMPLES,
00056 VAR_NB_SAMPLES,
00057 VAR_POS,
00058 VAR_PREV_INPTS,
00059 VAR_PREV_OUTPTS,
00060 VAR_PTS,
00061 VAR_SAMPLE_RATE,
00062 VAR_STARTPTS,
00063 VAR_TB,
00064 VAR_VARS_NB
00065 };
00066
00067 typedef struct {
00068 AVExpr *expr;
00069 double var_values[VAR_VARS_NB];
00070 enum AVMediaType type;
00071 } SetPTSContext;
00072
00073 static av_cold int init(AVFilterContext *ctx, const char *args)
00074 {
00075 SetPTSContext *setpts = ctx->priv;
00076 int ret;
00077
00078 if ((ret = av_expr_parse(&setpts->expr, args ? args : "PTS",
00079 var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
00080 av_log(ctx, AV_LOG_ERROR, "Error while parsing expression '%s'\n", args);
00081 return ret;
00082 }
00083
00084 setpts->var_values[VAR_N ] = 0.0;
00085 setpts->var_values[VAR_PREV_INPTS ] = NAN;
00086 setpts->var_values[VAR_PREV_OUTPTS] = NAN;
00087 setpts->var_values[VAR_STARTPTS ] = NAN;
00088 return 0;
00089 }
00090
00091 static int config_input(AVFilterLink *inlink)
00092 {
00093 AVFilterContext *ctx = inlink->dst;
00094 SetPTSContext *setpts = ctx->priv;
00095
00096 setpts->type = inlink->type;
00097 setpts->var_values[VAR_TB] = av_q2d(inlink->time_base);
00098
00099 if (setpts->type == AVMEDIA_TYPE_AUDIO)
00100 setpts->var_values[VAR_SAMPLE_RATE] = inlink->sample_rate;
00101
00102 av_log(inlink->src, AV_LOG_VERBOSE, "TB:%f SAMPLE_RATE:%f\n",
00103 setpts->var_values[VAR_TB], setpts->var_values[VAR_SAMPLE_RATE]);
00104 return 0;
00105 }
00106
00107 #define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d))
00108 #define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
00109
00110 static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
00111 {
00112 SetPTSContext *setpts = inlink->dst->priv;
00113 double d;
00114 AVFilterBufferRef *outpicref = avfilter_ref_buffer(inpicref, ~0);
00115
00116 if (!outpicref)
00117 return AVERROR(ENOMEM);
00118
00119 if (isnan(setpts->var_values[VAR_STARTPTS]))
00120 setpts->var_values[VAR_STARTPTS] = TS2D(inpicref->pts);
00121 setpts->var_values[VAR_PTS ] = TS2D(inpicref->pts);
00122 setpts->var_values[VAR_POS ] = inpicref->pos == -1 ? NAN : inpicref->pos;
00123
00124 switch (inlink->type) {
00125 case AVMEDIA_TYPE_VIDEO:
00126 setpts->var_values[VAR_INTERLACED] = inpicref->video->interlaced;
00127 break;
00128
00129 case AVMEDIA_TYPE_AUDIO:
00130 setpts->var_values[VAR_NB_SAMPLES] = inpicref->audio->nb_samples;
00131 break;
00132 }
00133
00134 d = av_expr_eval(setpts->expr, setpts->var_values, NULL);
00135 outpicref->pts = D2TS(d);
00136
00137 #ifdef DEBUG
00138 av_log(inlink->dst, AV_LOG_DEBUG,
00139 "n:%"PRId64" interlaced:%d nb_samples:%d nb_consumed_samples:%d "
00140 "pos:%"PRId64" pts:%"PRId64" t:%f -> pts:%"PRId64" t:%f\n",
00141 (int64_t)setpts->var_values[VAR_N],
00142 (int)setpts->var_values[VAR_INTERLACED],
00143 (int)setpts->var_values[VAR_NB_SAMPLES],
00144 (int)setpts->var_values[VAR_NB_CONSUMED_SAMPLES],
00145 inpicref ->pos,
00146 inpicref ->pts, inpicref ->pts * av_q2d(inlink->time_base),
00147 outpicref->pts, outpicref->pts * av_q2d(inlink->time_base));
00148
00149 #endif
00150
00151 setpts->var_values[VAR_N] += 1.0;
00152 setpts->var_values[VAR_PREV_INPTS ] = TS2D(inpicref ->pts);
00153 setpts->var_values[VAR_PREV_OUTPTS] = TS2D(outpicref->pts);
00154
00155 if (setpts->type == AVMEDIA_TYPE_AUDIO) {
00156 setpts->var_values[VAR_NB_CONSUMED_SAMPLES] += inpicref->audio->nb_samples;
00157 return ff_filter_samples(inlink->dst->outputs[0], outpicref);
00158 } else
00159 return ff_start_frame (inlink->dst->outputs[0], outpicref);
00160 }
00161
00162 static av_cold void uninit(AVFilterContext *ctx)
00163 {
00164 SetPTSContext *setpts = ctx->priv;
00165 av_expr_free(setpts->expr);
00166 setpts->expr = NULL;
00167 }
00168
00169 #if CONFIG_ASETPTS_FILTER
00170 AVFilter avfilter_af_asetpts = {
00171 .name = "asetpts",
00172 .description = NULL_IF_CONFIG_SMALL("Set PTS for the output audio frame."),
00173 .init = init,
00174 .uninit = uninit,
00175
00176 .priv_size = sizeof(SetPTSContext),
00177
00178 .inputs = (const AVFilterPad[]) {
00179 {
00180 .name = "default",
00181 .type = AVMEDIA_TYPE_AUDIO,
00182 .get_audio_buffer = ff_null_get_audio_buffer,
00183 .config_props = config_input,
00184 .filter_samples = filter_frame,
00185 },
00186 { .name = NULL }
00187 },
00188 .outputs = (const AVFilterPad[]) {
00189 {
00190 .name = "default",
00191 .type = AVMEDIA_TYPE_AUDIO,
00192 },
00193 { .name = NULL }
00194 },
00195 };
00196 #endif
00197
00198 #if CONFIG_SETPTS_FILTER
00199 AVFilter avfilter_vf_setpts = {
00200 .name = "setpts",
00201 .description = NULL_IF_CONFIG_SMALL("Set PTS for the output video frame."),
00202 .init = init,
00203 .uninit = uninit,
00204
00205 .priv_size = sizeof(SetPTSContext),
00206
00207 .inputs = (const AVFilterPad[]) {{ .name = "default",
00208 .type = AVMEDIA_TYPE_VIDEO,
00209 .get_video_buffer = ff_null_get_video_buffer,
00210 .config_props = config_input,
00211 .start_frame = filter_frame, },
00212 { .name = NULL }},
00213 .outputs = (const AVFilterPad[]) {{ .name = "default",
00214 .type = AVMEDIA_TYPE_VIDEO, },
00215 { .name = NULL}},
00216 };
00217 #endif