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 *frame)
00127 {
00128 SetPTSContext *setpts = inlink->dst->priv;
00129 int64_t in_pts = frame->pts;
00130 double d;
00131
00132 if (isnan(setpts->var_values[VAR_STARTPTS])) {
00133 setpts->var_values[VAR_STARTPTS] = TS2D(frame->pts);
00134 setpts->var_values[VAR_STARTT ] = TS2T(frame->pts, inlink->time_base);
00135 }
00136 setpts->var_values[VAR_PTS ] = TS2D(frame->pts);
00137 setpts->var_values[VAR_T ] = TS2T(frame->pts, inlink->time_base);
00138 setpts->var_values[VAR_POS ] = frame->pos == -1 ? NAN : frame->pos;
00139
00140 switch (inlink->type) {
00141 case AVMEDIA_TYPE_VIDEO:
00142 setpts->var_values[VAR_INTERLACED] = frame->video->interlaced;
00143 break;
00144
00145 case AVMEDIA_TYPE_AUDIO:
00146 setpts->var_values[VAR_NB_SAMPLES] = frame->audio->nb_samples;
00147 break;
00148 }
00149
00150 d = av_expr_eval(setpts->expr, setpts->var_values, NULL);
00151 frame->pts = D2TS(d);
00152
00153 setpts->var_values[VAR_PREV_INPTS ] = TS2D(in_pts);
00154 setpts->var_values[VAR_PREV_INT ] = TS2T(in_pts, inlink->time_base);
00155 setpts->var_values[VAR_PREV_OUTPTS] = TS2D(frame->pts);
00156 setpts->var_values[VAR_PREV_OUTT] = TS2T(frame->pts, inlink->time_base);
00157
00158 av_dlog(inlink->dst,
00159 "n:%"PRId64" interlaced:%d nb_samples:%d nb_consumed_samples:%d "
00160 "pos:%"PRId64" pts:%"PRId64" t:%f -> pts:%"PRId64" t:%f\n",
00161 (int64_t)setpts->var_values[VAR_N],
00162 (int)setpts->var_values[VAR_INTERLACED],
00163 (int)setpts->var_values[VAR_NB_SAMPLES],
00164 (int)setpts->var_values[VAR_NB_CONSUMED_SAMPLES],
00165 (int64_t)setpts->var_values[VAR_POS],
00166 (int64_t)setpts->var_values[VAR_PREV_INPTS],
00167 setpts->var_values[VAR_PREV_INT],
00168 (int64_t)setpts->var_values[VAR_PREV_OUTPTS],
00169 setpts->var_values[VAR_PREV_OUTT]);
00170
00171 setpts->var_values[VAR_N] += 1.0;
00172 if (setpts->type == AVMEDIA_TYPE_AUDIO) {
00173 setpts->var_values[VAR_NB_CONSUMED_SAMPLES] += frame->audio->nb_samples;
00174 }
00175 return ff_filter_frame(inlink->dst->outputs[0], frame);
00176 }
00177
00178 static av_cold void uninit(AVFilterContext *ctx)
00179 {
00180 SetPTSContext *setpts = ctx->priv;
00181 av_expr_free(setpts->expr);
00182 setpts->expr = NULL;
00183 }
00184
00185 #if CONFIG_ASETPTS_FILTER
00186 static const AVFilterPad avfilter_af_asetpts_inputs[] = {
00187 {
00188 .name = "default",
00189 .type = AVMEDIA_TYPE_AUDIO,
00190 .get_audio_buffer = ff_null_get_audio_buffer,
00191 .config_props = config_input,
00192 .filter_frame = filter_frame,
00193 },
00194 { NULL }
00195 };
00196
00197 static const AVFilterPad avfilter_af_asetpts_outputs[] = {
00198 {
00199 .name = "default",
00200 .type = AVMEDIA_TYPE_AUDIO,
00201 },
00202 { NULL }
00203 };
00204
00205 AVFilter avfilter_af_asetpts = {
00206 .name = "asetpts",
00207 .description = NULL_IF_CONFIG_SMALL("Set PTS for the output audio frame."),
00208 .init = init,
00209 .uninit = uninit,
00210 .priv_size = sizeof(SetPTSContext),
00211 .inputs = avfilter_af_asetpts_inputs,
00212 .outputs = avfilter_af_asetpts_outputs,
00213 };
00214 #endif
00215
00216 #if CONFIG_SETPTS_FILTER
00217 static const AVFilterPad avfilter_vf_setpts_inputs[] = {
00218 {
00219 .name = "default",
00220 .type = AVMEDIA_TYPE_VIDEO,
00221 .get_video_buffer = ff_null_get_video_buffer,
00222 .config_props = config_input,
00223 .filter_frame = filter_frame,
00224 },
00225 { NULL }
00226 };
00227
00228 static const AVFilterPad avfilter_vf_setpts_outputs[] = {
00229 {
00230 .name = "default",
00231 .type = AVMEDIA_TYPE_VIDEO,
00232 },
00233 { NULL }
00234 };
00235
00236 AVFilter avfilter_vf_setpts = {
00237 .name = "setpts",
00238 .description = NULL_IF_CONFIG_SMALL("Set PTS for the output video frame."),
00239 .init = init,
00240 .uninit = uninit,
00241
00242 .priv_size = sizeof(SetPTSContext),
00243
00244 .inputs = avfilter_vf_setpts_inputs,
00245 .outputs = avfilter_vf_setpts_outputs,
00246 };
00247 #endif