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