| @@ -30,16 +30,20 @@ · 29 unmodified lines |
| 30 | #include "libavutil/mathematics.h" | 30 | #include "libavutil/mathematics.h" |
| 31 | #include "avfilter.h" | 31 | #include "avfilter.h" |
| 32 | #include "internal.h" | 32 | #include "internal.h" |
| | 33 | #include "audio.h" |
| 33 | #include "video.h" | 34 | #include "video.h" |
| 34 | | 35 | |
| 35 | static const char *const var_names[] = { | 36 | static const char *const var_names[] = { |
| 36 | "INTERLACED", ///< tell if the current frame is interlaced | 37 | "INTERLACED", ///< tell if the current frame is interlaced |
| 37 | "N", ///< frame number (starting at zero) | 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 | "POS", ///< original position in the file of the frame | 41 | "POS", ///< original position in the file of the frame |
| 39 | "PREV_INPTS", ///< previous input PTS | 42 | "PREV_INPTS", ///< previous input PTS |
| 40 | "PREV_OUTPTS", ///< previous output PTS | 43 | "PREV_OUTPTS", ///< previous output PTS |
| 41 | "PTS", ///< original pts in the file of the frame | 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 | "TB", ///< timebase | 47 | "TB", ///< timebase |
| 44 | NULL | 48 | NULL |
| 45 | }; | 49 | }; |
| @@ -47,10 +51,13 @@ static const char *const var_names[] = { · 1 unmodified line |
| 47 | enum var_name { | 51 | enum var_name { |
| 48 | VAR_INTERLACED, | 52 | VAR_INTERLACED, |
| 49 | VAR_N, | 53 | VAR_N, |
| | 54 | VAR_NB_CONSUMED_SAMPLES, |
| | 55 | VAR_NB_SAMPLES, |
| 50 | VAR_POS, | 56 | VAR_POS, |
| 51 | VAR_PREV_INPTS, | 57 | VAR_PREV_INPTS, |
| 52 | VAR_PREV_OUTPTS, | 58 | VAR_PREV_OUTPTS, |
| 53 | VAR_PTS, | 59 | VAR_PTS, |
| | 60 | VAR_SAMPLE_RATE, |
| 54 | VAR_STARTPTS, | 61 | VAR_STARTPTS, |
| 55 | VAR_TB, | 62 | VAR_TB, |
| 56 | VAR_VARS_NB | 63 | VAR_VARS_NB |
| @@ -59,6 +66,7 @@ enum var_name { · 2 unmodified lines |
| 59 | typedef struct { | 66 | typedef struct { |
| 60 | AVExpr *expr; | 67 | AVExpr *expr; |
| 61 | double var_values[VAR_VARS_NB]; | 68 | double var_values[VAR_VARS_NB]; |
| | 69 | enum AVMediaType type; |
| 62 | } SetPTSContext; | 70 | } SetPTSContext; |
| 63 | | 71 | |
| 64 | static av_cold int init(AVFilterContext *ctx, const char *args) | 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 | static int config_input(AVFilterLink *inlink) | 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 | setpts->var_values[VAR_TB] = av_q2d(inlink->time_base); | 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 | return 0; | 103 | return 0; |
| 90 | } | 104 | } |
| 91 | | 105 | |
| 92 | #define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d)) | 106 | #define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d)) |
| 93 | #define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts)) | 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 | SetPTSContext *setpts = inlink->dst->priv; | 111 | SetPTSContext *setpts = inlink->dst->priv; |
| 98 | double d; | 112 | double d; |
| @@ -103,28 +117,45 @@ static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref) · 4 unmodified lines |
| 103 | | 117 | |
| 104 | if (isnan(setpts->var_values[VAR_STARTPTS])) | 118 | if (isnan(setpts->var_values[VAR_STARTPTS])) |
| 105 | setpts->var_values[VAR_STARTPTS] = TS2D(inpicref->pts); | 119 | setpts->var_values[VAR_STARTPTS] = TS2D(inpicref->pts); |
| 106 | | | |
| 107 | setpts->var_values[VAR_INTERLACED] = inpicref->video->interlaced; | | |
| 108 | setpts->var_values[VAR_PTS ] = TS2D(inpicref->pts); | 120 | setpts->var_values[VAR_PTS ] = TS2D(inpicref->pts); |
| 109 | setpts->var_values[VAR_POS ] = inpicref->pos == -1 ? NAN : inpicref->pos; | 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 | d = av_expr_eval(setpts->expr, setpts->var_values, NULL); | 133 | d = av_expr_eval(setpts->expr, setpts->var_values, NULL); |
| 112 | outpicref->pts = D2TS(d); | 134 | outpicref->pts = D2TS(d); |
| 113 | | 135 | |
| 114 | #ifdef DEBUG | 136 | #ifdef DEBUG |
| 115 | av_log(inlink->dst, AV_LOG_DEBUG, | 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 | (int64_t)setpts->var_values[VAR_N], | 140 | (int64_t)setpts->var_values[VAR_N], |
| 118 | (int)setpts->var_values[VAR_INTERLACED], | 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 | inpicref ->pos, | 144 | inpicref ->pos, |
| 120 | inpicref ->pts, inpicref ->pts * av_q2d(inlink->time_base), | 145 | inpicref ->pts, inpicref ->pts * av_q2d(inlink->time_base), |
| 121 | outpicref->pts, outpicref->pts * av_q2d(inlink->time_base)); | 146 | outpicref->pts, outpicref->pts * av_q2d(inlink->time_base)); |
| | 147 | |
| 122 | #endif | 148 | #endif |
| 123 | | 149 | |
| 124 | setpts->var_values[VAR_N] += 1.0; | 150 | setpts->var_values[VAR_N] += 1.0; |
| 125 | setpts->var_values[VAR_PREV_INPTS ] = TS2D(inpicref ->pts); | 151 | setpts->var_values[VAR_PREV_INPTS ] = TS2D(inpicref ->pts); |
| 126 | setpts->var_values[VAR_PREV_OUTPTS] = TS2D(outpicref->pts); | 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 | static av_cold void uninit(AVFilterContext *ctx) | 161 | static av_cold void uninit(AVFilterContext *ctx) |
| @@ -134,6 +165,36 @@ static av_cold void uninit(AVFilterContext *ctx) · 3 unmodified lines |
| 134 | setpts->expr = NULL; | 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 | AVFilter avfilter_vf_setpts = { | 198 | AVFilter avfilter_vf_setpts = { |
| 138 | .name = "setpts", | 199 | .name = "setpts", |
| 139 | .description = NULL_IF_CONFIG_SMALL("Set PTS for the output video frame."), | 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 | .type = AVMEDIA_TYPE_VIDEO, | 207 | .type = AVMEDIA_TYPE_VIDEO, |
| 147 | .get_video_buffer = ff_null_get_video_buffer, | 208 | .get_video_buffer = ff_null_get_video_buffer, |
| 148 | .config_props = config_input, | 209 | .config_props = config_input, |
| 149 | .start_frame = start_frame, }, | 210 | .start_frame = filter_frame, }, |
| 150 | { .name = NULL }}, | 211 | { .name = NULL }}, |
| 151 | .outputs = (const AVFilterPad[]) {{ .name = "default", | 212 | .outputs = (const AVFilterPad[]) {{ .name = "default", |
| 152 | .type = AVMEDIA_TYPE_VIDEO, }, | 213 | .type = AVMEDIA_TYPE_VIDEO, }, |
| 153 | { .name = NULL}}, | 214 | { .name = NULL}}, |
| 154 | }; | 215 | }; |
| | 216 | #endif /* CONFIG_SETPTS_FILTER */ |