This also signals EOF to filter inlink so that unnecessary extra processing that is immediately dropped by this filter is not done any more.
Unified · Split
| @@ -31,6 +31,7 @@ · 30 unmodified lines | ||
| 31 | 31 | #include "audio.h" |
| 32 | 32 | #include "avfilter.h" |
| 33 | 33 | #include "internal.h" |
| 34 | +#include "filters.h" | |
| 34 | 35 | |
| 35 | 36 | typedef struct TrimContext { |
| 36 | 37 | const AVClass *class; |
| @@ -68,6 +69,8 @@ typedef struct TrimContext { · 31 unmodified lines | ||
| 68 | 69 | int64_t next_pts; |
| 69 | 70 | |
| 70 | 71 | int eof; |
| 72 | + | |
| 73 | + int (*filter_frame)(AVFilterLink *inlink, AVFrame *frame); | |
| 71 | 74 | } TrimContext; |
| 72 | 75 | |
| 73 | 76 | static av_cold int init(AVFilterContext *ctx) |
| @@ -79,47 +82,6 @@ static av_cold int init(AVFilterContext *ctx) · 5 unmodified lines | ||
| 79 | 82 | return 0; |
| 80 | 83 | } |
| 81 | 84 | |
| 82 | −static int config_input(AVFilterLink *inlink) | |
| 83 | −{ | |
| 84 | − AVFilterContext *ctx = inlink->dst; | |
| 85 | − TrimContext *s = ctx->priv; | |
| 86 | − AVRational tb = (inlink->type == AVMEDIA_TYPE_VIDEO) ? | |
| 87 | − inlink->time_base : (AVRational){ 1, inlink->sample_rate }; | |
| 88 | − | |
| 89 | − if (s->start_time != INT64_MAX) { | |
| 90 | − int64_t start_pts = av_rescale_q(s->start_time, AV_TIME_BASE_Q, tb); | |
| 91 | − if (s->start_pts == AV_NOPTS_VALUE || start_pts < s->start_pts) | |
| 92 | − s->start_pts = start_pts; | |
| 93 | − } | |
| 94 | − if (s->end_time != INT64_MAX) { | |
| 95 | − int64_t end_pts = av_rescale_q(s->end_time, AV_TIME_BASE_Q, tb); | |
| 96 | − if (s->end_pts == AV_NOPTS_VALUE || end_pts > s->end_pts) | |
| 97 | − s->end_pts = end_pts; | |
| 98 | − } | |
| 99 | − if (s->duration) | |
| 100 | − s->duration_tb = av_rescale_q(s->duration, AV_TIME_BASE_Q, tb); | |
| 101 | − | |
| 102 | − return 0; | |
| 103 | −} | |
| 104 | − | |
| 105 | −#define OFFSET(x) offsetof(TrimContext, x) | |
| 106 | −#define COMMON_OPTS \ | |
| 107 | − { "start", "Timestamp of the first frame that " \ | |
| 108 | − "should be passed", OFFSET(start_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \ | |
| 109 | − { "starti", "Timestamp of the first frame that " \ | |
| 110 | − "should be passed", OFFSET(start_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \ | |
| 111 | − { "end", "Timestamp of the first frame that " \ | |
| 112 | − "should be dropped again", OFFSET(end_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \ | |
| 113 | − { "endi", "Timestamp of the first frame that " \ | |
| 114 | − "should be dropped again", OFFSET(end_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \ | |
| 115 | − { "start_pts", "Timestamp of the first frame that should be " \ | |
| 116 | − " passed", OFFSET(start_pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, FLAGS }, \ | |
| 117 | − { "end_pts", "Timestamp of the first frame that should be " \ | |
| 118 | − "dropped again", OFFSET(end_pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, FLAGS }, \ | |
| 119 | − { "duration", "Maximum duration of the output", OFFSET(duration), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT64_MAX, FLAGS }, \ | |
| 120 | − { "durationi", "Maximum duration of the output", OFFSET(duration), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT64_MAX, FLAGS }, | |
| 121 | − | |
| 122 | − | |
| 123 | 85 | #if CONFIG_TRIM_FILTER |
| 124 | 86 | static int trim_filter_frame(AVFilterLink *inlink, AVFrame *frame) |
| 125 | 87 | { |
| @@ -161,7 +123,8 @@ static int trim_filter_frame(AVFilterLink *inlink, AVFrame *frame) · 35 unmodified lines | ||
| 161 | 123 | |
| 162 | 124 | if (drop) { |
| 163 | 125 | s->eof = 1; |
| 164 | − ff_avfilter_link_set_out_status(inlink, AVERROR_EOF, AV_NOPTS_VALUE); | |
| 126 | + ff_inlink_set_status(inlink, AVERROR_EOF); | |
| 127 | + ff_outlink_set_status(ctx->outputs[0], AVERROR_EOF, frame->pts); | |
| 165 | 128 | goto drop; |
| 166 | 129 | } |
| 167 | 130 | } |
| @@ -171,49 +134,12 @@ static int trim_filter_frame(AVFilterLink *inlink, AVFrame *frame) · 3 unmodified lines | ||
| 171 | 134 | return ff_filter_frame(ctx->outputs[0], frame); |
| 172 | 135 | |
| 173 | 136 | drop: |
| 137 | + if (!s->eof) | |
| 138 | + ff_filter_set_ready(ctx, 100); | |
| 174 | 139 | s->nb_frames++; |
| 175 | 140 | av_frame_free(&frame); |
| 176 | 141 | return 0; |
| 177 | 142 | } |
| 178 | − | |
| 179 | −#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | |
| 180 | −static const AVOption trim_options[] = { | |
| 181 | − COMMON_OPTS | |
| 182 | − { "start_frame", "Number of the first frame that should be passed " | |
| 183 | − "to the output", OFFSET(start_frame), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, FLAGS }, | |
| 184 | − { "end_frame", "Number of the first frame that should be dropped " | |
| 185 | − "again", OFFSET(end_frame), AV_OPT_TYPE_INT64, { .i64 = INT64_MAX }, 0, INT64_MAX, FLAGS }, | |
| 186 | − { NULL } | |
| 187 | −}; | |
| 188 | −#undef FLAGS | |
| 189 | − | |
| 190 | −AVFILTER_DEFINE_CLASS(trim); | |
| 191 | − | |
| 192 | −static const AVFilterPad trim_inputs[] = { | |
| 193 | − { | |
| 194 | − .name = "default", | |
| 195 | − .type = AVMEDIA_TYPE_VIDEO, | |
| 196 | − .filter_frame = trim_filter_frame, | |
| 197 | − .config_props = config_input, | |
| 198 | − }, | |
| 199 | −}; | |
| 200 | − | |
| 201 | −static const AVFilterPad trim_outputs[] = { | |
| 202 | − { | |
| 203 | − .name = "default", | |
| 204 | − .type = AVMEDIA_TYPE_VIDEO, | |
| 205 | − }, | |
| 206 | −}; | |
| 207 | − | |
| 208 | −const AVFilter ff_vf_trim = { | |
| 209 | − .name = "trim", | |
| 210 | − .description = NULL_IF_CONFIG_SMALL("Pick one continuous section from the input, drop the rest."), | |
| 211 | − .init = init, | |
| 212 | − .priv_size = sizeof(TrimContext), | |
| 213 | − .priv_class = &trim_class, | |
| 214 | − FILTER_INPUTS(trim_inputs), | |
| 215 | − FILTER_OUTPUTS(trim_outputs), | |
| 216 | −}; | |
| 217 | 143 | #endif // CONFIG_TRIM_FILTER |
| 218 | 144 | |
| 219 | 145 | #if CONFIG_ATRIM_FILTER |
| @@ -290,7 +216,8 @@ static int atrim_filter_frame(AVFilterLink *inlink, AVFrame *frame) · 70 unmodified lines | ||
| 290 | 216 | |
| 291 | 217 | if (drop) { |
| 292 | 218 | s->eof = 1; |
| 293 | − ff_avfilter_link_set_out_status(inlink, AVERROR_EOF, AV_NOPTS_VALUE); | |
| 219 | + ff_inlink_set_status(inlink, AVERROR_EOF); | |
| 220 | + ff_outlink_set_status(ctx->outputs[0], AVERROR_EOF, frame->pts); | |
| 294 | 221 | goto drop; |
| 295 | 222 | } |
| 296 | 223 | } |
| @@ -324,10 +251,131 @@ static int atrim_filter_frame(AVFilterLink *inlink, AVFrame *frame) · 27 unmodified lines | ||
| 324 | 251 | return ff_filter_frame(ctx->outputs[0], frame); |
| 325 | 252 | |
| 326 | 253 | drop: |
| 254 | + if (!s->eof) | |
| 255 | + ff_filter_set_ready(ctx, 100); | |
| 327 | 256 | s->nb_samples += frame->nb_samples; |
| 328 | 257 | av_frame_free(&frame); |
| 329 | 258 | return 0; |
| 330 | 259 | } |
| 260 | +#endif // CONFIG_ATRIM_FILTER | |
| 261 | + | |
| 262 | +static int config_input(AVFilterLink *inlink) | |
| 263 | +{ | |
| 264 | + AVFilterContext *ctx = inlink->dst; | |
| 265 | + TrimContext *s = ctx->priv; | |
| 266 | + AVRational tb = (inlink->type == AVMEDIA_TYPE_VIDEO) ? | |
| 267 | + inlink->time_base : (AVRational){ 1, inlink->sample_rate }; | |
| 268 | + | |
| 269 | +#if CONFIG_TRIM_FILTER | |
| 270 | + if (inlink->type == AVMEDIA_TYPE_VIDEO) | |
| 271 | + s->filter_frame = trim_filter_frame; | |
| 272 | +#endif | |
| 273 | +#if CONFIG_ATRIM_FILTER | |
| 274 | + if (inlink->type == AVMEDIA_TYPE_AUDIO) | |
| 275 | + s->filter_frame = atrim_filter_frame; | |
| 276 | +#endif | |
| 277 | + if (s->start_time != INT64_MAX) { | |
| 278 | + int64_t start_pts = av_rescale_q(s->start_time, AV_TIME_BASE_Q, tb); | |
| 279 | + if (s->start_pts == AV_NOPTS_VALUE || start_pts < s->start_pts) | |
| 280 | + s->start_pts = start_pts; | |
| 281 | + } | |
| 282 | + if (s->end_time != INT64_MAX) { | |
| 283 | + int64_t end_pts = av_rescale_q(s->end_time, AV_TIME_BASE_Q, tb); | |
| 284 | + if (s->end_pts == AV_NOPTS_VALUE || end_pts > s->end_pts) | |
| 285 | + s->end_pts = end_pts; | |
| 286 | + } | |
| 287 | + if (s->duration) | |
| 288 | + s->duration_tb = av_rescale_q(s->duration, AV_TIME_BASE_Q, tb); | |
| 289 | + | |
| 290 | + return 0; | |
| 291 | +} | |
| 292 | + | |
| 293 | +static int activate(AVFilterContext *ctx) | |
| 294 | +{ | |
| 295 | + TrimContext *s = ctx->priv; | |
| 296 | + AVFilterLink *inlink = ctx->inputs[0]; | |
| 297 | + AVFilterLink *outlink = ctx->outputs[0]; | |
| 298 | + | |
| 299 | + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); | |
| 300 | + | |
| 301 | + if (!s->eof && ff_inlink_queued_frames(inlink)) { | |
| 302 | + AVFrame *frame = NULL; | |
| 303 | + int ret; | |
| 304 | + | |
| 305 | + ret = ff_inlink_consume_frame(inlink, &frame); | |
| 306 | + if (ret < 0) | |
| 307 | + return ret; | |
| 308 | + if (ret > 0) | |
| 309 | + return s->filter_frame(inlink, frame); | |
| 310 | + } | |
| 311 | + | |
| 312 | + FF_FILTER_FORWARD_STATUS(inlink, outlink); | |
| 313 | + FF_FILTER_FORWARD_WANTED(outlink, inlink); | |
| 314 | + | |
| 315 | + return FFERROR_NOT_READY; | |
| 316 | +} | |
| 317 | + | |
| 318 | +#define OFFSET(x) offsetof(TrimContext, x) | |
| 319 | +#define COMMON_OPTS \ | |
| 320 | + { "start", "Timestamp of the first frame that " \ | |
| 321 | + "should be passed", OFFSET(start_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \ | |
| 322 | + { "starti", "Timestamp of the first frame that " \ | |
| 323 | + "should be passed", OFFSET(start_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \ | |
| 324 | + { "end", "Timestamp of the first frame that " \ | |
| 325 | + "should be dropped again", OFFSET(end_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \ | |
| 326 | + { "endi", "Timestamp of the first frame that " \ | |
| 327 | + "should be dropped again", OFFSET(end_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \ | |
| 328 | + { "start_pts", "Timestamp of the first frame that should be " \ | |
| 329 | + " passed", OFFSET(start_pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, FLAGS }, \ | |
| 330 | + { "end_pts", "Timestamp of the first frame that should be " \ | |
| 331 | + "dropped again", OFFSET(end_pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, FLAGS }, \ | |
| 332 | + { "duration", "Maximum duration of the output", OFFSET(duration), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT64_MAX, FLAGS }, \ | |
| 333 | + { "durationi", "Maximum duration of the output", OFFSET(duration), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT64_MAX, FLAGS }, | |
| 334 | + | |
| 335 | + | |
| 336 | +#if CONFIG_TRIM_FILTER | |
| 337 | + | |
| 338 | +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | |
| 339 | +static const AVOption trim_options[] = { | |
| 340 | + COMMON_OPTS | |
| 341 | + { "start_frame", "Number of the first frame that should be passed " | |
| 342 | + "to the output", OFFSET(start_frame), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, FLAGS }, | |
| 343 | + { "end_frame", "Number of the first frame that should be dropped " | |
| 344 | + "again", OFFSET(end_frame), AV_OPT_TYPE_INT64, { .i64 = INT64_MAX }, 0, INT64_MAX, FLAGS }, | |
| 345 | + { NULL } | |
| 346 | +}; | |
| 347 | +#undef FLAGS | |
| 348 | + | |
| 349 | +AVFILTER_DEFINE_CLASS(trim); | |
| 350 | + | |
| 351 | +static const AVFilterPad trim_inputs[] = { | |
| 352 | + { | |
| 353 | + .name = "default", | |
| 354 | + .type = AVMEDIA_TYPE_VIDEO, | |
| 355 | + .config_props = config_input, | |
| 356 | + }, | |
| 357 | +}; | |
| 358 | + | |
| 359 | +static const AVFilterPad trim_outputs[] = { | |
| 360 | + { | |
| 361 | + .name = "default", | |
| 362 | + .type = AVMEDIA_TYPE_VIDEO, | |
| 363 | + }, | |
| 364 | +}; | |
| 365 | + | |
| 366 | +const AVFilter ff_vf_trim = { | |
| 367 | + .name = "trim", | |
| 368 | + .description = NULL_IF_CONFIG_SMALL("Pick one continuous section from the input, drop the rest."), | |
| 369 | + .init = init, | |
| 370 | + .activate = activate, | |
| 371 | + .priv_size = sizeof(TrimContext), | |
| 372 | + .priv_class = &trim_class, | |
| 373 | + FILTER_INPUTS(trim_inputs), | |
| 374 | + FILTER_OUTPUTS(trim_outputs), | |
| 375 | +}; | |
| 376 | +#endif // CONFIG_TRIM_FILTER | |
| 377 | + | |
| 378 | +#if CONFIG_ATRIM_FILTER | |
| 331 | 379 | |
| 332 | 380 | #define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM |
| 333 | 381 | static const AVOption atrim_options[] = { |
| @@ -346,7 +394,6 @@ static const AVFilterPad atrim_inputs[] = { · 12 unmodified lines | ||
| 346 | 394 | { |
| 347 | 395 | .name = "default", |
| 348 | 396 | .type = AVMEDIA_TYPE_AUDIO, |
| 349 | − .filter_frame = atrim_filter_frame, | |
| 350 | 397 | .config_props = config_input, |
| 351 | 398 | }, |
| 352 | 399 | }; |
| @@ -362,6 +409,7 @@ const AVFilter ff_af_atrim = { · 9 unmodified lines | ||
| 362 | 409 | .name = "atrim", |
| 363 | 410 | .description = NULL_IF_CONFIG_SMALL("Pick one continuous section from the input, drop the rest."), |
| 364 | 411 | .init = init, |
| 412 | + .activate = activate, | |
| 365 | 413 | .priv_size = sizeof(TrimContext), |
| 366 | 414 | .priv_class = &atrim_class, |
| 367 | 415 | .flags = AVFILTER_FLAG_METADATA_ONLY, |