| @@ -30,16 +30,20 @@ · 29 unmodified lines |
| 30 | 30 | #include "libavutil/mathematics.h" |
| 31 | 31 | #include "avfilter.h" |
| 32 | 32 | #include "internal.h" |
| 33 | +#include "audio.h" |
| 33 | 34 | #include "video.h" |
| 34 | 35 | |
| 35 | 36 | static const char *const var_names[] = { |
| 36 | 37 | "INTERLACED", ///< tell if the current frame is interlaced |
| 37 | 38 | "N", ///< frame number (starting at zero) |
| 39 | + "NB_CONSUMED_SAMPLES", ///< number of samples consumed by the filter (only audio) |
| 40 | + "NB_SAMPLES", ///< number of samples in the current frame (only audio) |
| 38 | 41 | "POS", ///< original position in the file of the frame |
| 39 | 42 | "PREV_INPTS", ///< previous input PTS |
| 40 | 43 | "PREV_OUTPTS", ///< previous output PTS |
| 41 | 44 | "PTS", ///< original pts in the file of the frame |
| 42 | | − "STARTPTS", ///< PTS at start of movie |
| 45 | + "SAMPLE_RATE", ///< sample rate (only audio) |
| 46 | + "STARTPTS", ///< PTS at start of movie |
| 43 | 47 | "TB", ///< timebase |
| 44 | 48 | NULL |
| 45 | 49 | }; |
| @@ -47,10 +51,13 @@ static const char *const var_names[] = { · 1 unmodified line |
| 47 | 51 | enum var_name { |
| 48 | 52 | VAR_INTERLACED, |
| 49 | 53 | VAR_N, |
| 54 | + VAR_NB_CONSUMED_SAMPLES, |
| 55 | + VAR_NB_SAMPLES, |
| 50 | 56 | VAR_POS, |
| 51 | 57 | VAR_PREV_INPTS, |
| 52 | 58 | VAR_PREV_OUTPTS, |
| 53 | 59 | VAR_PTS, |
| 60 | + VAR_SAMPLE_RATE, |
| 54 | 61 | VAR_STARTPTS, |
| 55 | 62 | VAR_TB, |
| 56 | 63 | VAR_VARS_NB |
| @@ -59,6 +66,7 @@ enum var_name { · 2 unmodified lines |
| 59 | 66 | typedef struct { |
| 60 | 67 | AVExpr *expr; |
| 61 | 68 | double var_values[VAR_VARS_NB]; |
| 69 | + enum AVMediaType type; |
| 62 | 70 | } SetPTSContext; |
| 63 | 71 | |
| 64 | 72 | static av_cold int init(AVFilterContext *ctx, const char *args) |
| @@ -81,18 +89,24 @@ static av_cold int init(AVFilterContext *ctx, const char *args) · 16 unmodified lines |
| 81 | 89 | |
| 82 | 90 | static int config_input(AVFilterLink *inlink) |
| 83 | 91 | { |
| 84 | | − SetPTSContext *setpts = inlink->dst->priv; |
| 92 | + AVFilterContext *ctx = inlink->dst; |
| 93 | + SetPTSContext *setpts = ctx->priv; |
| 85 | 94 | |
| 95 | + setpts->type = inlink->type; |
| 86 | 96 | setpts->var_values[VAR_TB] = av_q2d(inlink->time_base); |
| 87 | 97 | |
| 88 | | − av_log(inlink->src, AV_LOG_VERBOSE, "TB:%f\n", setpts->var_values[VAR_TB]); |
| 98 | + if (setpts->type == AVMEDIA_TYPE_AUDIO) |
| 99 | + setpts->var_values[VAR_SAMPLE_RATE] = inlink->sample_rate; |
| 100 | + |
| 101 | + av_log(inlink->src, AV_LOG_VERBOSE, "TB:%f SAMPLE_RATE:%f\n", |
| 102 | + setpts->var_values[VAR_TB], setpts->var_values[VAR_SAMPLE_RATE]); |
| 89 | 103 | return 0; |
| 90 | 104 | } |
| 91 | 105 | |
| 92 | 106 | #define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d)) |
| 93 | 107 | #define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts)) |
| 94 | 108 | |
| 95 | | −static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref) |
| 109 | +static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref) |
| 96 | 110 | { |
| 97 | 111 | SetPTSContext *setpts = inlink->dst->priv; |
| 98 | 112 | double d; |
| @@ -103,28 +117,45 @@ static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref) · 4 unmodified lines |
| 103 | 117 | |
| 104 | 118 | if (isnan(setpts->var_values[VAR_STARTPTS])) |
| 105 | 119 | setpts->var_values[VAR_STARTPTS] = TS2D(inpicref->pts); |
| 106 | | − |
| 107 | | − setpts->var_values[VAR_INTERLACED] = inpicref->video->interlaced; |
| 108 | 120 | setpts->var_values[VAR_PTS ] = TS2D(inpicref->pts); |
| 109 | 121 | setpts->var_values[VAR_POS ] = inpicref->pos == -1 ? NAN : inpicref->pos; |
| 110 | 122 | |
| 123 | + switch (inlink->type) { |
| 124 | + case AVMEDIA_TYPE_VIDEO: |
| 125 | + setpts->var_values[VAR_INTERLACED] = inpicref->video->interlaced; |
| 126 | + break; |
| 127 | + |
| 128 | + case AVMEDIA_TYPE_AUDIO: |
| 129 | + setpts->var_values[VAR_NB_SAMPLES] = inpicref->audio->nb_samples; |
| 130 | + break; |
| 131 | + } |
| 132 | + |
| 111 | 133 | d = av_expr_eval(setpts->expr, setpts->var_values, NULL); |
| 112 | 134 | outpicref->pts = D2TS(d); |
| 113 | 135 | |
| 114 | 136 | #ifdef DEBUG |
| 115 | 137 | av_log(inlink->dst, AV_LOG_DEBUG, |
| 116 | | − "n:%"PRId64" interlaced:%d pos:%"PRId64" pts:%"PRId64" t:%f -> pts:%"PRId64" t:%f\n", |
| 138 | + "n:%"PRId64" interlaced:%d nb_samples:%d nb_consumed_samples:%d " |
| 139 | + "pos:%"PRId64" pts:%"PRId64" t:%f -> pts:%"PRId64" t:%f\n", |
| 117 | 140 | (int64_t)setpts->var_values[VAR_N], |
| 118 | 141 | (int)setpts->var_values[VAR_INTERLACED], |
| 142 | + (int)setpts->var_values[VAR_NB_SAMPLES], |
| 143 | + (int)setpts->var_values[VAR_NB_CONSUMED_SAMPLES], |
| 119 | 144 | inpicref ->pos, |
| 120 | 145 | inpicref ->pts, inpicref ->pts * av_q2d(inlink->time_base), |
| 121 | 146 | outpicref->pts, outpicref->pts * av_q2d(inlink->time_base)); |
| 147 | + |
| 122 | 148 | #endif |
| 123 | 149 | |
| 124 | 150 | setpts->var_values[VAR_N] += 1.0; |
| 125 | 151 | setpts->var_values[VAR_PREV_INPTS ] = TS2D(inpicref ->pts); |
| 126 | 152 | setpts->var_values[VAR_PREV_OUTPTS] = TS2D(outpicref->pts); |
| 127 | | − return ff_start_frame(inlink->dst->outputs[0], outpicref); |
| 153 | + |
| 154 | + if (setpts->type == AVMEDIA_TYPE_AUDIO) { |
| 155 | + setpts->var_values[VAR_NB_CONSUMED_SAMPLES] += inpicref->audio->nb_samples; |
| 156 | + return ff_filter_samples(inlink->dst->outputs[0], outpicref); |
| 157 | + } else |
| 158 | + return ff_start_frame (inlink->dst->outputs[0], outpicref); |
| 128 | 159 | } |
| 129 | 160 | |
| 130 | 161 | static av_cold void uninit(AVFilterContext *ctx) |
| @@ -134,6 +165,36 @@ static av_cold void uninit(AVFilterContext *ctx) · 3 unmodified lines |
| 134 | 165 | setpts->expr = NULL; |
| 135 | 166 | } |
| 136 | 167 | |
| 168 | +#if CONFIG_ASETPTS_FILTER |
| 169 | +AVFilter avfilter_af_asetpts = { |
| 170 | + .name = "asetpts", |
| 171 | + .description = NULL_IF_CONFIG_SMALL("Set PTS for the output audio frame."), |
| 172 | + .init = init, |
| 173 | + .uninit = uninit, |
| 174 | + |
| 175 | + .priv_size = sizeof(SetPTSContext), |
| 176 | + |
| 177 | + .inputs = (const AVFilterPad[]) { |
| 178 | + { |
| 179 | + .name = "default", |
| 180 | + .type = AVMEDIA_TYPE_AUDIO, |
| 181 | + .get_audio_buffer = ff_null_get_audio_buffer, |
| 182 | + .config_props = config_input, |
| 183 | + .filter_samples = filter_frame, |
| 184 | + }, |
| 185 | + { .name = NULL } |
| 186 | + }, |
| 187 | + .outputs = (const AVFilterPad[]) { |
| 188 | + { |
| 189 | + .name = "default", |
| 190 | + .type = AVMEDIA_TYPE_AUDIO, |
| 191 | + }, |
| 192 | + { .name = NULL } |
| 193 | + }, |
| 194 | +}; |
| 195 | +#endif /* CONFIG_ASETPTS_FILTER */ |
| 196 | + |
| 197 | +#if CONFIG_SETPTS_FILTER |
| 137 | 198 | AVFilter avfilter_vf_setpts = { |
| 138 | 199 | .name = "setpts", |
| 139 | 200 | .description = NULL_IF_CONFIG_SMALL("Set PTS for the output video frame."), |
| @@ -146,9 +207,10 @@ AVFilter avfilter_vf_setpts = { · 6 unmodified lines |
| 146 | 207 | .type = AVMEDIA_TYPE_VIDEO, |
| 147 | 208 | .get_video_buffer = ff_null_get_video_buffer, |
| 148 | 209 | .config_props = config_input, |
| 149 | | − .start_frame = start_frame, }, |
| 210 | + .start_frame = filter_frame, }, |
| 150 | 211 | { .name = NULL }}, |
| 151 | 212 | .outputs = (const AVFilterPad[]) {{ .name = "default", |
| 152 | 213 | .type = AVMEDIA_TYPE_VIDEO, }, |
| 153 | 214 | { .name = NULL}}, |
| 154 | 215 | }; |
| 216 | +#endif /* CONFIG_SETPTS_FILTER */ |