* commit 'a1e05b0487a1939334c2920fc7f9936bc9efe876': lavfi: add trim and atrim filters. Conflicts: Changelog doc/filters.texi libavfilter/Makefile libavfilter/allfilters.c Merged-by: Michael Niedermayer <michaelni@gmx.at>tags/n2.0
| @@ -34,6 +34,7 @@ version <next>: | |||||
| - vidstabdetect and vidstabtransform filters for video stabilization using | - vidstabdetect and vidstabtransform filters for video stabilization using | ||||
| the vid.stab library | the vid.stab library | ||||
| - astats filter | - astats filter | ||||
| - trim and atrim filters | |||||
| version 1.2: | version 1.2: | ||||
| @@ -1335,6 +1335,70 @@ with a negative pts due to encoder delay. | |||||
| @end table | @end table | ||||
| @section atrim | |||||
| Trim the input so that the output contains one continuous subpart of the input. | |||||
| This filter accepts the following options: | |||||
| @table @option | |||||
| @item start | |||||
| Timestamp (in seconds) of the start of the kept section. I.e. the audio sample | |||||
| with the timestamp @var{start} will be the first sample in the output. | |||||
| @item end | |||||
| Timestamp (in seconds) of the first audio sample that will be dropped. I.e. the | |||||
| audio sample immediately preceding the one with the timestamp @var{end} will be | |||||
| the last sample in the output. | |||||
| @item start_pts | |||||
| Same as @var{start}, except this option sets the start timestamp in samples | |||||
| instead of seconds. | |||||
| @item end_pts | |||||
| Same as @var{end}, except this option sets the end timestamp in samples instead | |||||
| of seconds. | |||||
| @item duration | |||||
| Maximum duration of the output in seconds. | |||||
| @item start_sample | |||||
| Number of the first sample that should be passed to output. | |||||
| @item end_sample | |||||
| Number of the first sample that should be dropped. | |||||
| @end table | |||||
| Note that the first two sets of the start/end options and the @option{duration} | |||||
| option look at the frame timestamp, while the _sample options simply count the | |||||
| samples that pass through the filter. So start/end_pts and start/end_sample will | |||||
| give different results when the timestamps are wrong, inexact or do not start at | |||||
| zero. Also note that this filter does not modify the timestamps. If you wish | |||||
| that the output timestamps start at zero, insert the asetpts filter after the | |||||
| atrim filter. | |||||
| If multiple start or end options are set, this filter tries to be greedy and | |||||
| keep all samples that match at least one of the specified constraints. To keep | |||||
| only the part that matches all the constraints at once, chain multiple atrim | |||||
| filters. | |||||
| The defaults are such that all the input is kept. So it is possible to set e.g. | |||||
| just the end values to keep everything before the specified time. | |||||
| Examples: | |||||
| @itemize | |||||
| @item | |||||
| drop everything except the second minute of input | |||||
| @example | |||||
| ffmpeg -i INPUT -af atrim=60:120 | |||||
| @end example | |||||
| @item | |||||
| keep only the first 1000 samples | |||||
| @example | |||||
| ffmpeg -i INPUT -af atrim=end_sample=1000 | |||||
| @end example | |||||
| @end itemize | |||||
| @section channelsplit | @section channelsplit | ||||
| Split each channel in input audio stream into a separate output stream. | Split each channel in input audio stream into a separate output stream. | ||||
| @@ -6278,6 +6342,69 @@ The command above can also be specified as: | |||||
| transpose=1:portrait | transpose=1:portrait | ||||
| @end example | @end example | ||||
| @section trim | |||||
| Trim the input so that the output contains one continuous subpart of the input. | |||||
| This filter accepts the following options: | |||||
| @table @option | |||||
| @item start | |||||
| Timestamp (in seconds) of the start of the kept section. I.e. the frame with the | |||||
| timestamp @var{start} will be the first frame in the output. | |||||
| @item end | |||||
| Timestamp (in seconds) of the first frame that will be dropped. I.e. the frame | |||||
| immediately preceding the one with the timestamp @var{end} will be the last | |||||
| frame in the output. | |||||
| @item start_pts | |||||
| Same as @var{start}, except this option sets the start timestamp in timebase | |||||
| units instead of seconds. | |||||
| @item end_pts | |||||
| Same as @var{end}, except this option sets the end timestamp in timebase units | |||||
| instead of seconds. | |||||
| @item duration | |||||
| Maximum duration of the output in seconds. | |||||
| @item start_frame | |||||
| Number of the first frame that should be passed to output. | |||||
| @item end_frame | |||||
| Number of the first frame that should be dropped. | |||||
| @end table | |||||
| Note that the first two sets of the start/end options and the @option{duration} | |||||
| option look at the frame timestamp, while the _frame variants simply count the | |||||
| frames that pass through the filter. Also note that this filter does not modify | |||||
| the timestamps. If you wish that the output timestamps start at zero, insert a | |||||
| setpts filter after the trim filter. | |||||
| If multiple start or end options are set, this filter tries to be greedy and | |||||
| keep all the frames that match at least one of the specified constraints. To keep | |||||
| only the part that matches all the constraints at once, chain multiple trim | |||||
| filters. | |||||
| The defaults are such that all the input is kept. So it is possible to set e.g. | |||||
| just the end values to keep everything before the specified time. | |||||
| Examples: | |||||
| @itemize | |||||
| @item | |||||
| drop everything except the second minute of input | |||||
| @example | |||||
| ffmpeg -i INPUT -vf trim=60:120 | |||||
| @end example | |||||
| @item | |||||
| keep only the first second | |||||
| @example | |||||
| ffmpeg -i INPUT -vf trim=duration=1 | |||||
| @end example | |||||
| @end itemize | |||||
| @section unsharp | @section unsharp | ||||
| Sharpen or blur the input video. | Sharpen or blur the input video. | ||||
| @@ -73,6 +73,7 @@ OBJS-$(CONFIG_ASTATS_FILTER) += af_astats.o | |||||
| OBJS-$(CONFIG_ASTREAMSYNC_FILTER) += af_astreamsync.o | OBJS-$(CONFIG_ASTREAMSYNC_FILTER) += af_astreamsync.o | ||||
| OBJS-$(CONFIG_ASYNCTS_FILTER) += af_asyncts.o | OBJS-$(CONFIG_ASYNCTS_FILTER) += af_asyncts.o | ||||
| OBJS-$(CONFIG_ATEMPO_FILTER) += af_atempo.o | OBJS-$(CONFIG_ATEMPO_FILTER) += af_atempo.o | ||||
| OBJS-$(CONFIG_ATRIM_FILTER) += trim.o | |||||
| OBJS-$(CONFIG_BANDPASS_FILTER) += af_biquads.o | OBJS-$(CONFIG_BANDPASS_FILTER) += af_biquads.o | ||||
| OBJS-$(CONFIG_BANDREJECT_FILTER) += af_biquads.o | OBJS-$(CONFIG_BANDREJECT_FILTER) += af_biquads.o | ||||
| OBJS-$(CONFIG_BASS_FILTER) += af_biquads.o | OBJS-$(CONFIG_BASS_FILTER) += af_biquads.o | ||||
| @@ -178,6 +179,7 @@ OBJS-$(CONFIG_THUMBNAIL_FILTER) += vf_thumbnail.o | |||||
| OBJS-$(CONFIG_TILE_FILTER) += vf_tile.o | OBJS-$(CONFIG_TILE_FILTER) += vf_tile.o | ||||
| OBJS-$(CONFIG_TINTERLACE_FILTER) += vf_tinterlace.o | OBJS-$(CONFIG_TINTERLACE_FILTER) += vf_tinterlace.o | ||||
| OBJS-$(CONFIG_TRANSPOSE_FILTER) += vf_transpose.o | OBJS-$(CONFIG_TRANSPOSE_FILTER) += vf_transpose.o | ||||
| OBJS-$(CONFIG_TRIM_FILTER) += trim.o | |||||
| OBJS-$(CONFIG_UNSHARP_FILTER) += vf_unsharp.o | OBJS-$(CONFIG_UNSHARP_FILTER) += vf_unsharp.o | ||||
| OBJS-$(CONFIG_VFLIP_FILTER) += vf_vflip.o | OBJS-$(CONFIG_VFLIP_FILTER) += vf_vflip.o | ||||
| OBJS-$(CONFIG_VIDSTABDETECT_FILTER) += vidstabutils.o vf_vidstabdetect.o | OBJS-$(CONFIG_VIDSTABDETECT_FILTER) += vidstabutils.o vf_vidstabdetect.o | ||||
| @@ -71,6 +71,7 @@ void avfilter_register_all(void) | |||||
| REGISTER_FILTER(ASTREAMSYNC, astreamsync, af); | REGISTER_FILTER(ASTREAMSYNC, astreamsync, af); | ||||
| REGISTER_FILTER(ASYNCTS, asyncts, af); | REGISTER_FILTER(ASYNCTS, asyncts, af); | ||||
| REGISTER_FILTER(ATEMPO, atempo, af); | REGISTER_FILTER(ATEMPO, atempo, af); | ||||
| REGISTER_FILTER(ATRIM, atrim, af); | |||||
| REGISTER_FILTER(BANDPASS, bandpass, af); | REGISTER_FILTER(BANDPASS, bandpass, af); | ||||
| REGISTER_FILTER(BANDREJECT, bandreject, af); | REGISTER_FILTER(BANDREJECT, bandreject, af); | ||||
| REGISTER_FILTER(BASS, bass, af); | REGISTER_FILTER(BASS, bass, af); | ||||
| @@ -175,6 +176,7 @@ void avfilter_register_all(void) | |||||
| REGISTER_FILTER(TILE, tile, vf); | REGISTER_FILTER(TILE, tile, vf); | ||||
| REGISTER_FILTER(TINTERLACE, tinterlace, vf); | REGISTER_FILTER(TINTERLACE, tinterlace, vf); | ||||
| REGISTER_FILTER(TRANSPOSE, transpose, vf); | REGISTER_FILTER(TRANSPOSE, transpose, vf); | ||||
| REGISTER_FILTER(TRIM, trim, vf); | |||||
| REGISTER_FILTER(UNSHARP, unsharp, vf); | REGISTER_FILTER(UNSHARP, unsharp, vf); | ||||
| REGISTER_FILTER(VFLIP, vflip, vf); | REGISTER_FILTER(VFLIP, vflip, vf); | ||||
| REGISTER_FILTER(VIDSTABDETECT, vidstabdetect, vf); | REGISTER_FILTER(VIDSTABDETECT, vidstabdetect, vf); | ||||
| @@ -0,0 +1,407 @@ | |||||
| /* | |||||
| * This file is part of FFmpeg. | |||||
| * | |||||
| * FFmpeg is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public | |||||
| * License as published by the Free Software Foundation; either | |||||
| * version 2.1 of the License, or (at your option) any later version. | |||||
| * | |||||
| * FFmpeg is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| * Lesser General Public License for more details. | |||||
| * | |||||
| * You should have received a copy of the GNU Lesser General Public | |||||
| * License along with FFmpeg; if not, write to the Free Software | |||||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||||
| */ | |||||
| #include <float.h> | |||||
| #include <math.h> | |||||
| #include "config.h" | |||||
| #include "libavutil/avassert.h" | |||||
| #include "libavutil/channel_layout.h" | |||||
| #include "libavutil/common.h" | |||||
| #include "libavutil/log.h" | |||||
| #include "libavutil/mathematics.h" | |||||
| #include "libavutil/opt.h" | |||||
| #include "libavutil/samplefmt.h" | |||||
| #include "audio.h" | |||||
| #include "avfilter.h" | |||||
| #include "internal.h" | |||||
| typedef struct TrimContext { | |||||
| const AVClass *class; | |||||
| /* | |||||
| * AVOptions | |||||
| */ | |||||
| double duration; | |||||
| double start_time, end_time; | |||||
| int64_t start_frame, end_frame; | |||||
| /* | |||||
| * in the link timebase for video, | |||||
| * in 1/samplerate for audio | |||||
| */ | |||||
| int64_t start_pts, end_pts; | |||||
| int64_t start_sample, end_sample; | |||||
| /* | |||||
| * number of video frames that arrived on this filter so far | |||||
| */ | |||||
| int64_t nb_frames; | |||||
| /* | |||||
| * number of audio samples that arrived on this filter so far | |||||
| */ | |||||
| int64_t nb_samples; | |||||
| /* | |||||
| * timestamp of the first frame in the output, in the timebase units | |||||
| */ | |||||
| int64_t first_pts; | |||||
| /* | |||||
| * duration in the timebase units | |||||
| */ | |||||
| int64_t duration_tb; | |||||
| int64_t next_pts; | |||||
| int eof; | |||||
| int got_output; | |||||
| } TrimContext; | |||||
| static int init(AVFilterContext *ctx) | |||||
| { | |||||
| TrimContext *s = ctx->priv; | |||||
| s->first_pts = AV_NOPTS_VALUE; | |||||
| return 0; | |||||
| } | |||||
| static int config_input(AVFilterLink *inlink) | |||||
| { | |||||
| AVFilterContext *ctx = inlink->dst; | |||||
| TrimContext *s = ctx->priv; | |||||
| AVRational tb = (inlink->type == AVMEDIA_TYPE_VIDEO) ? | |||||
| inlink->time_base : (AVRational){ 1, inlink->sample_rate }; | |||||
| if (s->start_time != DBL_MAX) { | |||||
| int64_t start_pts = lrintf(s->start_time / av_q2d(tb)); | |||||
| if (s->start_pts == AV_NOPTS_VALUE || start_pts < s->start_pts) | |||||
| s->start_pts = start_pts; | |||||
| } | |||||
| if (s->end_time != DBL_MAX) { | |||||
| int64_t end_pts = lrintf(s->end_time / av_q2d(tb)); | |||||
| if (s->end_pts == AV_NOPTS_VALUE || end_pts > s->end_pts) | |||||
| s->end_pts = end_pts; | |||||
| } | |||||
| if (s->duration) | |||||
| s->duration_tb = lrintf(s->duration / av_q2d(tb)); | |||||
| return 0; | |||||
| } | |||||
| static int request_frame(AVFilterLink *outlink) | |||||
| { | |||||
| AVFilterContext *ctx = outlink->src; | |||||
| TrimContext *s = ctx->priv; | |||||
| int ret; | |||||
| s->got_output = 0; | |||||
| while (!s->got_output) { | |||||
| if (s->eof) | |||||
| return AVERROR_EOF; | |||||
| ret = ff_request_frame(ctx->inputs[0]); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| #define OFFSET(x) offsetof(TrimContext, x) | |||||
| #define COMMON_OPTS \ | |||||
| { "start", "Timestamp in seconds of the first frame that " \ | |||||
| "should be passed", OFFSET(start_time), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS }, \ | |||||
| { "end", "Timestamp in seconds of the first frame that " \ | |||||
| "should be dropped again", OFFSET(end_time), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS }, \ | |||||
| { "start_pts", "Timestamp of the first frame that should be " \ | |||||
| " passed", OFFSET(start_pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, FLAGS }, \ | |||||
| { "end_pts", "Timestamp of the first frame that should be " \ | |||||
| "dropped again", OFFSET(end_pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, FLAGS }, \ | |||||
| { "duration", "Maximum duration of the output in seconds", OFFSET(duration), AV_OPT_TYPE_DOUBLE, { .dbl = 0 }, 0, DBL_MAX, FLAGS }, | |||||
| #if CONFIG_TRIM_FILTER | |||||
| static int trim_filter_frame(AVFilterLink *inlink, AVFrame *frame) | |||||
| { | |||||
| AVFilterContext *ctx = inlink->dst; | |||||
| TrimContext *s = ctx->priv; | |||||
| int drop; | |||||
| /* drop everything if EOF has already been returned */ | |||||
| if (s->eof) { | |||||
| av_frame_free(&frame); | |||||
| return 0; | |||||
| } | |||||
| if (s->start_frame >= 0 || s->start_pts != AV_NOPTS_VALUE) { | |||||
| drop = 1; | |||||
| if (s->start_frame >= 0 && s->nb_frames >= s->start_frame) | |||||
| drop = 0; | |||||
| if (s->start_pts != AV_NOPTS_VALUE && frame->pts != AV_NOPTS_VALUE && | |||||
| frame->pts >= s->start_pts) | |||||
| drop = 0; | |||||
| if (drop) | |||||
| goto drop; | |||||
| } | |||||
| if (s->first_pts == AV_NOPTS_VALUE && frame->pts != AV_NOPTS_VALUE) | |||||
| s->first_pts = frame->pts; | |||||
| if (s->end_frame != INT64_MAX || s->end_pts != AV_NOPTS_VALUE || s->duration_tb) { | |||||
| drop = 1; | |||||
| if (s->end_frame != INT64_MAX && s->nb_frames < s->end_frame) | |||||
| drop = 0; | |||||
| if (s->end_pts != AV_NOPTS_VALUE && frame->pts != AV_NOPTS_VALUE && | |||||
| frame->pts < s->end_pts) | |||||
| drop = 0; | |||||
| if (s->duration_tb && frame->pts != AV_NOPTS_VALUE && | |||||
| frame->pts - s->first_pts < s->duration_tb) | |||||
| drop = 0; | |||||
| if (drop) { | |||||
| s->eof = 1; | |||||
| goto drop; | |||||
| } | |||||
| } | |||||
| s->nb_frames++; | |||||
| s->got_output = 1; | |||||
| return ff_filter_frame(ctx->outputs[0], frame); | |||||
| drop: | |||||
| s->nb_frames++; | |||||
| av_frame_free(&frame); | |||||
| return 0; | |||||
| } | |||||
| #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | |||||
| static const AVOption trim_options[] = { | |||||
| COMMON_OPTS | |||||
| { "start_frame", "Number of the first frame that should be passed " | |||||
| "to the output", OFFSET(start_frame), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, FLAGS }, | |||||
| { "end_frame", "Number of the first frame that should be dropped " | |||||
| "again", OFFSET(end_frame), AV_OPT_TYPE_INT64, { .i64 = INT64_MAX }, 0, INT64_MAX, FLAGS }, | |||||
| { NULL }, | |||||
| }; | |||||
| #undef FLAGS | |||||
| static const AVClass trim_class = { | |||||
| .class_name = "trim", | |||||
| .item_name = av_default_item_name, | |||||
| .option = trim_options, | |||||
| .version = LIBAVUTIL_VERSION_INT, | |||||
| }; | |||||
| static const AVFilterPad trim_inputs[] = { | |||||
| { | |||||
| .name = "default", | |||||
| .type = AVMEDIA_TYPE_VIDEO, | |||||
| .filter_frame = trim_filter_frame, | |||||
| .config_props = config_input, | |||||
| }, | |||||
| { NULL } | |||||
| }; | |||||
| static const AVFilterPad trim_outputs[] = { | |||||
| { | |||||
| .name = "default", | |||||
| .type = AVMEDIA_TYPE_VIDEO, | |||||
| .request_frame = request_frame, | |||||
| }, | |||||
| { NULL } | |||||
| }; | |||||
| AVFilter avfilter_vf_trim = { | |||||
| .name = "trim", | |||||
| .description = NULL_IF_CONFIG_SMALL("Pick one continuous section from the input, drop the rest."), | |||||
| .init = init, | |||||
| .priv_size = sizeof(TrimContext), | |||||
| .priv_class = &trim_class, | |||||
| .inputs = trim_inputs, | |||||
| .outputs = trim_outputs, | |||||
| }; | |||||
| #endif // CONFIG_TRIM_FILTER | |||||
| #if CONFIG_ATRIM_FILTER | |||||
| static int atrim_filter_frame(AVFilterLink *inlink, AVFrame *frame) | |||||
| { | |||||
| AVFilterContext *ctx = inlink->dst; | |||||
| TrimContext *s = ctx->priv; | |||||
| int64_t start_sample, end_sample = frame->nb_samples; | |||||
| int64_t pts; | |||||
| int drop; | |||||
| /* drop everything if EOF has already been returned */ | |||||
| if (s->eof) { | |||||
| av_frame_free(&frame); | |||||
| return 0; | |||||
| } | |||||
| if (frame->pts != AV_NOPTS_VALUE) | |||||
| pts = av_rescale_q(frame->pts, inlink->time_base, | |||||
| (AVRational){ 1, inlink->sample_rate }); | |||||
| else | |||||
| pts = s->next_pts; | |||||
| s->next_pts = pts + frame->nb_samples; | |||||
| /* check if at least a part of the frame is after the start time */ | |||||
| if (s->start_sample < 0 && s->start_pts == AV_NOPTS_VALUE) { | |||||
| start_sample = 0; | |||||
| } else { | |||||
| drop = 1; | |||||
| start_sample = frame->nb_samples; | |||||
| if (s->start_sample >= 0 && | |||||
| s->nb_samples + frame->nb_samples > s->start_sample) { | |||||
| drop = 0; | |||||
| start_sample = FFMIN(start_sample, s->start_sample - s->nb_samples); | |||||
| } | |||||
| if (s->start_pts != AV_NOPTS_VALUE && pts != AV_NOPTS_VALUE && | |||||
| pts + frame->nb_samples > s->start_pts) { | |||||
| drop = 0; | |||||
| start_sample = FFMIN(start_sample, s->start_pts - pts); | |||||
| } | |||||
| if (drop) | |||||
| goto drop; | |||||
| } | |||||
| if (s->first_pts == AV_NOPTS_VALUE) | |||||
| s->first_pts = pts + start_sample; | |||||
| /* check if at least a part of the frame is before the end time */ | |||||
| if (s->end_sample == INT64_MAX && s->end_pts == AV_NOPTS_VALUE && !s->duration_tb) { | |||||
| end_sample = frame->nb_samples; | |||||
| } else { | |||||
| drop = 1; | |||||
| end_sample = 0; | |||||
| if (s->end_sample != INT64_MAX && | |||||
| s->nb_samples < s->end_sample) { | |||||
| drop = 0; | |||||
| end_sample = FFMAX(end_sample, s->end_sample - s->nb_samples); | |||||
| } | |||||
| if (s->end_pts != AV_NOPTS_VALUE && pts != AV_NOPTS_VALUE && | |||||
| pts < s->end_pts) { | |||||
| drop = 0; | |||||
| end_sample = FFMAX(end_sample, s->end_pts - pts); | |||||
| } | |||||
| if (s->duration_tb && pts - s->first_pts < s->duration_tb) { | |||||
| drop = 0; | |||||
| end_sample = FFMAX(end_sample, s->first_pts + s->duration_tb - pts); | |||||
| } | |||||
| if (drop) { | |||||
| s->eof = 1; | |||||
| goto drop; | |||||
| } | |||||
| } | |||||
| s->nb_samples += frame->nb_samples; | |||||
| start_sample = FFMAX(0, start_sample); | |||||
| end_sample = FFMIN(frame->nb_samples, end_sample); | |||||
| av_assert0(start_sample < end_sample); | |||||
| if (start_sample) { | |||||
| AVFrame *out = ff_get_audio_buffer(ctx->outputs[0], end_sample - start_sample); | |||||
| if (!out) { | |||||
| av_frame_free(&frame); | |||||
| return AVERROR(ENOMEM); | |||||
| } | |||||
| av_frame_copy_props(out, frame); | |||||
| av_samples_copy(out->extended_data, frame->extended_data, 0, start_sample, | |||||
| out->nb_samples, av_get_channel_layout_nb_channels(frame->channel_layout), | |||||
| frame->format); | |||||
| if (out->pts != AV_NOPTS_VALUE) | |||||
| out->pts += av_rescale_q(start_sample, (AVRational){ 1, out->sample_rate }, | |||||
| inlink->time_base); | |||||
| av_frame_free(&frame); | |||||
| frame = out; | |||||
| } else | |||||
| frame->nb_samples = end_sample; | |||||
| s->got_output = 1; | |||||
| return ff_filter_frame(ctx->outputs[0], frame); | |||||
| drop: | |||||
| s->nb_samples += frame->nb_samples; | |||||
| av_frame_free(&frame); | |||||
| return 0; | |||||
| } | |||||
| #define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | |||||
| static const AVOption atrim_options[] = { | |||||
| COMMON_OPTS | |||||
| { "start_sample", "Number of the first audio sample that should be " | |||||
| "passed to the output", OFFSET(start_sample), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, FLAGS }, | |||||
| { "end_sample", "Number of the first audio sample that should be " | |||||
| "dropped again", OFFSET(end_sample), AV_OPT_TYPE_INT64, { .i64 = INT64_MAX }, 0, INT64_MAX, FLAGS }, | |||||
| { NULL }, | |||||
| }; | |||||
| #undef FLAGS | |||||
| static const AVClass atrim_class = { | |||||
| .class_name = "atrim", | |||||
| .item_name = av_default_item_name, | |||||
| .option = atrim_options, | |||||
| .version = LIBAVUTIL_VERSION_INT, | |||||
| }; | |||||
| static const AVFilterPad atrim_inputs[] = { | |||||
| { | |||||
| .name = "default", | |||||
| .type = AVMEDIA_TYPE_AUDIO, | |||||
| .filter_frame = atrim_filter_frame, | |||||
| .config_props = config_input, | |||||
| }, | |||||
| { NULL } | |||||
| }; | |||||
| static const AVFilterPad atrim_outputs[] = { | |||||
| { | |||||
| .name = "default", | |||||
| .type = AVMEDIA_TYPE_AUDIO, | |||||
| .request_frame = request_frame, | |||||
| }, | |||||
| { NULL } | |||||
| }; | |||||
| AVFilter avfilter_af_atrim = { | |||||
| .name = "atrim", | |||||
| .description = NULL_IF_CONFIG_SMALL("Pick one continuous section from the input, drop the rest."), | |||||
| .init = init, | |||||
| .priv_size = sizeof(TrimContext), | |||||
| .priv_class = &atrim_class, | |||||
| .inputs = atrim_inputs, | |||||
| .outputs = atrim_outputs, | |||||
| }; | |||||
| #endif // CONFIG_ATRIM_FILTER | |||||
| @@ -31,6 +31,22 @@ fate-filter-aresample: CMD = pcm -i $(SRC) -af aresample=min_comp=0.001:min_hard | |||||
| fate-filter-aresample: CMP = oneoff | fate-filter-aresample: CMP = oneoff | ||||
| fate-filter-aresample: REF = $(SAMPLES)/nellymoser/nellymoser-discont.pcm | fate-filter-aresample: REF = $(SAMPLES)/nellymoser/nellymoser-discont.pcm | ||||
| FATE_ATRIM += fate-filter-atrim-duration | |||||
| fate-filter-atrim-duration: CMD = framecrc -i $(SRC) -af atrim=start=0.1:duration=0.01 | |||||
| FATE_ATRIM += fate-filter-atrim-mixed | |||||
| fate-filter-atrim-mixed: CMD = framecrc -i $(SRC) -af atrim=start=0.05:start_sample=1025:end=0.1:end_sample=4411 | |||||
| FATE_ATRIM += fate-filter-atrim-samples | |||||
| fate-filter-atrim-samples: CMD = framecrc -i $(SRC) -af atrim=start_sample=26:end_sample=80 | |||||
| FATE_ATRIM += fate-filter-atrim-time | |||||
| fate-filter-atrim-time: CMD = framecrc -i $(SRC) -af atrim=0.1:0.2 | |||||
| $(FATE_ATRIM): tests/data/asynth-44100-2.wav | |||||
| $(FATE_ATRIM): SRC = $(TARGET_PATH)/tests/data/asynth-44100-2.wav | |||||
| FATE_FILTER-$(call FILTERDEMDECENCMUX, ATRIM, WAV, PCM_S16LE, PCM_S16LE, WAV) += $(FATE_ATRIM) | |||||
| FATE_AFILTER-$(call FILTERDEMDECENCMUX, CHANNELMAP, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-channelmap | FATE_AFILTER-$(call FILTERDEMDECENCMUX, CHANNELMAP, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-channelmap | ||||
| fate-filter-channelmap: SRC = $(TARGET_PATH)/tests/data/asynth-44100-6.wav | fate-filter-channelmap: SRC = $(TARGET_PATH)/tests/data/asynth-44100-6.wav | ||||
| fate-filter-channelmap: tests/data/asynth-44100-6.wav | fate-filter-channelmap: tests/data/asynth-44100-6.wav | ||||
| @@ -73,6 +73,20 @@ fate-filter-telecine: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf telecine | |||||
| FATE_FILTER_VSYNTH-$(CONFIG_TRANSPOSE_FILTER) += fate-filter-transpose | FATE_FILTER_VSYNTH-$(CONFIG_TRANSPOSE_FILTER) += fate-filter-transpose | ||||
| fate-filter-transpose: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf transpose | fate-filter-transpose: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf transpose | ||||
| FATE_TRIM += fate-filter-trim-duration | |||||
| fate-filter-trim-duration: CMD = framecrc -i $(SRC) -vf trim=start=0.4:duration=0.05 | |||||
| FATE_TRIM += fate-filter-trim-frame | |||||
| fate-filter-trim-frame: CMD = framecrc -i $(SRC) -vf trim=start_frame=3:end_frame=10 | |||||
| FATE_TRIM += fate-filter-trim-mixed | |||||
| fate-filter-trim-mixed: CMD = framecrc -i $(SRC) -vf trim=start=0.2:end=0.4:start_frame=1:end_frame=3 | |||||
| FATE_TRIM += fate-filter-trim-time | |||||
| fate-filter-trim-time: CMD = framecrc -i $(SRC) -vf trim=0:0.1 | |||||
| FATE_FILTER_VSYNTH-$(CONFIG_TRIM_FILTER) += $(FATE_TRIM) | |||||
| FATE_FILTER_VSYNTH-$(CONFIG_UNSHARP_FILTER) += fate-filter-unsharp | FATE_FILTER_VSYNTH-$(CONFIG_UNSHARP_FILTER) += fate-filter-unsharp | ||||
| fate-filter-unsharp: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf unsharp=11:11:-1.5:11:11:-1.5 | fate-filter-unsharp: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf unsharp=11:11:-1.5:11:11:-1.5 | ||||
| @@ -0,0 +1,2 @@ | |||||
| #tb 0: 1/44100 | |||||
| 0, 4410, 4410, 441, 1764, 0x61e374f7 | |||||
| @@ -0,0 +1,5 @@ | |||||
| #tb 0: 1/44100 | |||||
| 0, 1025, 1025, 1023, 4092, 0x78560a4c | |||||
| 0, 2048, 2048, 1024, 4096, 0xc477fa99 | |||||
| 0, 3072, 3072, 1024, 4096, 0x3bc0f14f | |||||
| 0, 4096, 4096, 315, 1260, 0xe4b26b50 | |||||
| @@ -0,0 +1,2 @@ | |||||
| #tb 0: 1/44100 | |||||
| 0, 26, 26, 54, 216, 0x6b376c6c | |||||
| @@ -0,0 +1,6 @@ | |||||
| #tb 0: 1/44100 | |||||
| 0, 4410, 4410, 710, 2840, 0x658982a3 | |||||
| 0, 5120, 5120, 1024, 4096, 0xfd6a0070 | |||||
| 0, 6144, 6144, 1024, 4096, 0x0b01f4cf | |||||
| 0, 7168, 7168, 1024, 4096, 0x6716fd93 | |||||
| 0, 8192, 8192, 628, 2512, 0xda5ddff8 | |||||
| @@ -0,0 +1,2 @@ | |||||
| #tb 0: 1/25 | |||||
| 0, 10, 10, 1, 152064, 0xb45c4760 | |||||
| @@ -0,0 +1,8 @@ | |||||
| #tb 0: 1/25 | |||||
| 0, 3, 3, 1, 152064, 0xceb080b0 | |||||
| 0, 4, 4, 1, 152064, 0x473db652 | |||||
| 0, 5, 5, 1, 152064, 0x287da8e6 | |||||
| 0, 6, 6, 1, 152064, 0x68b47c23 | |||||
| 0, 7, 7, 1, 152064, 0xe9028bac | |||||
| 0, 8, 8, 1, 152064, 0x28ff8026 | |||||
| 0, 9, 9, 1, 152064, 0x2d7c3915 | |||||
| @@ -0,0 +1,10 @@ | |||||
| #tb 0: 1/25 | |||||
| 0, 1, 1, 1, 152064, 0x7f5f6551 | |||||
| 0, 2, 2, 1, 152064, 0xc566f64a | |||||
| 0, 3, 3, 1, 152064, 0xceb080b0 | |||||
| 0, 4, 4, 1, 152064, 0x473db652 | |||||
| 0, 5, 5, 1, 152064, 0x287da8e6 | |||||
| 0, 6, 6, 1, 152064, 0x68b47c23 | |||||
| 0, 7, 7, 1, 152064, 0xe9028bac | |||||
| 0, 8, 8, 1, 152064, 0x28ff8026 | |||||
| 0, 9, 9, 1, 152064, 0x2d7c3915 | |||||
| @@ -0,0 +1,3 @@ | |||||
| #tb 0: 1/25 | |||||
| 0, 0, 0, 1, 152064, 0x6e4f89ef | |||||
| 0, 1, 1, 1, 152064, 0x7f5f6551 | |||||