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 | #include "audio.h" | 31 | #include "audio.h" |
| 32 | #include "avfilter.h" | 32 | #include "avfilter.h" |
| 33 | #include "internal.h" | 33 | #include "internal.h" |
| 34 | #include "filters.h" | ||
| 34 | 35 | ||
| 35 | typedef struct TrimContext { | 36 | typedef struct TrimContext { |
| 36 | const AVClass *class; | 37 | const AVClass *class; |
| @@ -68,6 +69,8 @@ typedef struct TrimContext { · 31 unmodified lines | |||
| 68 | int64_t next_pts; | 69 | int64_t next_pts; |
| 69 | 70 | ||
| 70 | int eof; | 71 | int eof; |
| 72 | |||
| 73 | int (*filter_frame)(AVFilterLink *inlink, AVFrame *frame); | ||
| 71 | } TrimContext; | 74 | } TrimContext; |
| 72 | 75 | ||
| 73 | static av_cold int init(AVFilterContext *ctx) | 76 | static av_cold int init(AVFilterContext *ctx) |
| @@ -79,47 +82,6 @@ static av_cold int init(AVFilterContext *ctx) · 5 unmodified lines | |||
| 79 | return 0; | 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 | #if CONFIG_TRIM_FILTER | 85 | #if CONFIG_TRIM_FILTER |
| 124 | static int trim_filter_frame(AVFilterLink *inlink, AVFrame *frame) | 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 | if (drop) { | 124 | if (drop) { |
| 163 | s->eof = 1; | 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 | goto drop; | 128 | goto drop; |
| 166 | } | 129 | } |
| 167 | } | 130 | } |
| @@ -171,49 +134,12 @@ static int trim_filter_frame(AVFilterLink *inlink, AVFrame *frame) · 3 unmodified lines | |||
| 171 | return ff_filter_frame(ctx->outputs[0], frame); | 134 | return ff_filter_frame(ctx->outputs[0], frame); |
| 172 | 135 | ||
| 173 | drop: | 136 | drop: |
| 137 | if (!s->eof) | ||
| 138 | ff_filter_set_ready(ctx, 100); | ||
| 174 | s->nb_frames++; | 139 | s->nb_frames++; |
| 175 | av_frame_free(&frame); | 140 | av_frame_free(&frame); |
| 176 | return 0; | 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 | #endif // CONFIG_TRIM_FILTER | 143 | #endif // CONFIG_TRIM_FILTER |
| 218 | 144 | ||
| 219 | #if CONFIG_ATRIM_FILTER | 145 | #if CONFIG_ATRIM_FILTER |
| @@ -290,7 +216,8 @@ static int atrim_filter_frame(AVFilterLink *inlink, AVFrame *frame) · 70 unmodified lines | |||
| 290 | 216 | ||
| 291 | if (drop) { | 217 | if (drop) { |
| 292 | s->eof = 1; | 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 | goto drop; | 221 | goto drop; |
| 295 | } | 222 | } |
| 296 | } | 223 | } |
| @@ -324,10 +251,131 @@ static int atrim_filter_frame(AVFilterLink *inlink, AVFrame *frame) · 27 unmodified lines | |||
| 324 | return ff_filter_frame(ctx->outputs[0], frame); | 251 | return ff_filter_frame(ctx->outputs[0], frame); |
| 325 | 252 | ||
| 326 | drop: | 253 | drop: |
| 254 | if (!s->eof) | ||
| 255 | ff_filter_set_ready(ctx, 100); | ||
| 327 | s->nb_samples += frame->nb_samples; | 256 | s->nb_samples += frame->nb_samples; |
| 328 | av_frame_free(&frame); | 257 | av_frame_free(&frame); |
| 329 | return 0; | 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 | #define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | 380 | #define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM |
| 333 | static const AVOption atrim_options[] = { | 381 | static const AVOption atrim_options[] = { |
| @@ -346,7 +394,6 @@ static const AVFilterPad atrim_inputs[] = { · 12 unmodified lines | |||
| 346 | { | 394 | { |
| 347 | .name = "default", | 395 | .name = "default", |
| 348 | .type = AVMEDIA_TYPE_AUDIO, | 396 | .type = AVMEDIA_TYPE_AUDIO, |
| 349 | .filter_frame = atrim_filter_frame, | ||
| 350 | .config_props = config_input, | 397 | .config_props = config_input, |
| 351 | }, | 398 | }, |
| 352 | }; | 399 | }; |
| @@ -362,6 +409,7 @@ const AVFilter ff_af_atrim = { · 9 unmodified lines | |||
| 362 | .name = "atrim", | 409 | .name = "atrim", |
| 363 | .description = NULL_IF_CONFIG_SMALL("Pick one continuous section from the input, drop the rest."), | 410 | .description = NULL_IF_CONFIG_SMALL("Pick one continuous section from the input, drop the rest."), |
| 364 | .init = init, | 411 | .init = init, |
| 412 | .activate = activate, | ||
| 365 | .priv_size = sizeof(TrimContext), | 413 | .priv_size = sizeof(TrimContext), |
| 366 | .priv_class = &atrim_class, | 414 | .priv_class = &atrim_class, |
| 367 | .flags = AVFILTER_FLAG_METADATA_ONLY, | 415 | .flags = AVFILTER_FLAG_METADATA_ONLY, |