The file now contains also an audio select implementation. Also move the
aselect/select documentation from video filters to the multimedia filters
section.
... | ... |
@@ -3506,140 +3506,6 @@ scale='min(500\, iw*3/2):-1' |
3506 | 3506 |
@end example |
3507 | 3507 |
@end itemize |
3508 | 3508 |
|
3509 |
-@section aselect, select |
|
3510 |
-Select frames to pass in output. |
|
3511 |
- |
|
3512 |
-It accepts in input an expression, which is evaluated for each input |
|
3513 |
-frame. If the expression is evaluated to a non-zero value, the frame |
|
3514 |
-is selected and passed to the output, otherwise it is discarded. |
|
3515 |
- |
|
3516 |
-The expression can contain the following constants: |
|
3517 |
- |
|
3518 |
-@table @option |
|
3519 |
-@item n |
|
3520 |
-the sequential number of the filtered frame, starting from 0 |
|
3521 |
- |
|
3522 |
-@item selected_n |
|
3523 |
-the sequential number of the selected frame, starting from 0 |
|
3524 |
- |
|
3525 |
-@item prev_selected_n |
|
3526 |
-the sequential number of the last selected frame, NAN if undefined |
|
3527 |
- |
|
3528 |
-@item TB |
|
3529 |
-timebase of the input timestamps |
|
3530 |
- |
|
3531 |
-@item pts |
|
3532 |
-the PTS (Presentation TimeStamp) of the filtered video frame, |
|
3533 |
-expressed in @var{TB} units, NAN if undefined |
|
3534 |
- |
|
3535 |
-@item t |
|
3536 |
-the PTS (Presentation TimeStamp) of the filtered video frame, |
|
3537 |
-expressed in seconds, NAN if undefined |
|
3538 |
- |
|
3539 |
-@item prev_pts |
|
3540 |
-the PTS of the previously filtered video frame, NAN if undefined |
|
3541 |
- |
|
3542 |
-@item prev_selected_pts |
|
3543 |
-the PTS of the last previously filtered video frame, NAN if undefined |
|
3544 |
- |
|
3545 |
-@item prev_selected_t |
|
3546 |
-the PTS of the last previously selected video frame, NAN if undefined |
|
3547 |
- |
|
3548 |
-@item start_pts |
|
3549 |
-the PTS of the first video frame in the video, NAN if undefined |
|
3550 |
- |
|
3551 |
-@item start_t |
|
3552 |
-the time of the first video frame in the video, NAN if undefined |
|
3553 |
- |
|
3554 |
-@item pict_type @emph{(video only)} |
|
3555 |
-the type of the filtered frame, can assume one of the following |
|
3556 |
-values: |
|
3557 |
-@table @option |
|
3558 |
-@item I |
|
3559 |
-@item P |
|
3560 |
-@item B |
|
3561 |
-@item S |
|
3562 |
-@item SI |
|
3563 |
-@item SP |
|
3564 |
-@item BI |
|
3565 |
-@end table |
|
3566 |
- |
|
3567 |
-@item interlace_type @emph{(video only)} |
|
3568 |
-the frame interlace type, can assume one of the following values: |
|
3569 |
-@table @option |
|
3570 |
-@item PROGRESSIVE |
|
3571 |
-the frame is progressive (not interlaced) |
|
3572 |
-@item TOPFIRST |
|
3573 |
-the frame is top-field-first |
|
3574 |
-@item BOTTOMFIRST |
|
3575 |
-the frame is bottom-field-first |
|
3576 |
-@end table |
|
3577 |
- |
|
3578 |
-@item consumed_sample_n @emph{(audio only)} |
|
3579 |
-the number of selected samples before the current frame |
|
3580 |
- |
|
3581 |
-@item samples_n @emph{(audio only)} |
|
3582 |
-the number of samples in the current frame |
|
3583 |
- |
|
3584 |
-@item sample_rate @emph{(audio only)} |
|
3585 |
-the input sample rate |
|
3586 |
- |
|
3587 |
-@item key |
|
3588 |
-1 if the filtered frame is a key-frame, 0 otherwise |
|
3589 |
- |
|
3590 |
-@item pos |
|
3591 |
-the position in the file of the filtered frame, -1 if the information |
|
3592 |
-is not available (e.g. for synthetic video) |
|
3593 |
- |
|
3594 |
-@item scene @emph{(video only)} |
|
3595 |
-value between 0 and 1 to indicate a new scene; a low value reflects a low |
|
3596 |
-probability for the current frame to introduce a new scene, while a higher |
|
3597 |
-value means the current frame is more likely to be one (see the example below) |
|
3598 |
- |
|
3599 |
-@end table |
|
3600 |
- |
|
3601 |
-The default value of the select expression is "1". |
|
3602 |
- |
|
3603 |
-Some examples follow: |
|
3604 |
- |
|
3605 |
-@example |
|
3606 |
-# select all frames in input |
|
3607 |
-select |
|
3608 |
- |
|
3609 |
-# the above is the same as: |
|
3610 |
-select=1 |
|
3611 |
- |
|
3612 |
-# skip all frames: |
|
3613 |
-select=0 |
|
3614 |
- |
|
3615 |
-# select only I-frames |
|
3616 |
-select='eq(pict_type\,I)' |
|
3617 |
- |
|
3618 |
-# select one frame every 100 |
|
3619 |
-select='not(mod(n\,100))' |
|
3620 |
- |
|
3621 |
-# select only frames contained in the 10-20 time interval |
|
3622 |
-select='gte(t\,10)*lte(t\,20)' |
|
3623 |
- |
|
3624 |
-# select only I frames contained in the 10-20 time interval |
|
3625 |
-select='gte(t\,10)*lte(t\,20)*eq(pict_type\,I)' |
|
3626 |
- |
|
3627 |
-# select frames with a minimum distance of 10 seconds |
|
3628 |
-select='isnan(prev_selected_t)+gte(t-prev_selected_t\,10)' |
|
3629 |
- |
|
3630 |
-# use aselect to select only audio frames with samples number > 100 |
|
3631 |
-aselect='gt(samples_n\,100)' |
|
3632 |
-@end example |
|
3633 |
- |
|
3634 |
-Complete example to create a mosaic of the first scenes: |
|
3635 |
- |
|
3636 |
-@example |
|
3637 |
-ffmpeg -i video.avi -vf select='gt(scene\,0.4)',scale=160:120,tile -frames:v 1 preview.png |
|
3638 |
-@end example |
|
3639 |
- |
|
3640 |
-Comparing @var{scene} against a value between 0.3 and 0.5 is generally a sane |
|
3641 |
-choice. |
|
3642 |
- |
|
3643 | 3509 |
@section setdar, setsar |
3644 | 3510 |
|
3645 | 3511 |
The @code{setdar} filter sets the Display Aspect Ratio for the filter |
... | ... |
@@ -4768,6 +4634,140 @@ tools. |
4768 | 4768 |
|
4769 | 4769 |
Below is a description of the currently available multimedia filters. |
4770 | 4770 |
|
4771 |
+@section aselect, select |
|
4772 |
+Select frames to pass in output. |
|
4773 |
+ |
|
4774 |
+It accepts in input an expression, which is evaluated for each input |
|
4775 |
+frame. If the expression is evaluated to a non-zero value, the frame |
|
4776 |
+is selected and passed to the output, otherwise it is discarded. |
|
4777 |
+ |
|
4778 |
+The expression can contain the following constants: |
|
4779 |
+ |
|
4780 |
+@table @option |
|
4781 |
+@item n |
|
4782 |
+the sequential number of the filtered frame, starting from 0 |
|
4783 |
+ |
|
4784 |
+@item selected_n |
|
4785 |
+the sequential number of the selected frame, starting from 0 |
|
4786 |
+ |
|
4787 |
+@item prev_selected_n |
|
4788 |
+the sequential number of the last selected frame, NAN if undefined |
|
4789 |
+ |
|
4790 |
+@item TB |
|
4791 |
+timebase of the input timestamps |
|
4792 |
+ |
|
4793 |
+@item pts |
|
4794 |
+the PTS (Presentation TimeStamp) of the filtered video frame, |
|
4795 |
+expressed in @var{TB} units, NAN if undefined |
|
4796 |
+ |
|
4797 |
+@item t |
|
4798 |
+the PTS (Presentation TimeStamp) of the filtered video frame, |
|
4799 |
+expressed in seconds, NAN if undefined |
|
4800 |
+ |
|
4801 |
+@item prev_pts |
|
4802 |
+the PTS of the previously filtered video frame, NAN if undefined |
|
4803 |
+ |
|
4804 |
+@item prev_selected_pts |
|
4805 |
+the PTS of the last previously filtered video frame, NAN if undefined |
|
4806 |
+ |
|
4807 |
+@item prev_selected_t |
|
4808 |
+the PTS of the last previously selected video frame, NAN if undefined |
|
4809 |
+ |
|
4810 |
+@item start_pts |
|
4811 |
+the PTS of the first video frame in the video, NAN if undefined |
|
4812 |
+ |
|
4813 |
+@item start_t |
|
4814 |
+the time of the first video frame in the video, NAN if undefined |
|
4815 |
+ |
|
4816 |
+@item pict_type @emph{(video only)} |
|
4817 |
+the type of the filtered frame, can assume one of the following |
|
4818 |
+values: |
|
4819 |
+@table @option |
|
4820 |
+@item I |
|
4821 |
+@item P |
|
4822 |
+@item B |
|
4823 |
+@item S |
|
4824 |
+@item SI |
|
4825 |
+@item SP |
|
4826 |
+@item BI |
|
4827 |
+@end table |
|
4828 |
+ |
|
4829 |
+@item interlace_type @emph{(video only)} |
|
4830 |
+the frame interlace type, can assume one of the following values: |
|
4831 |
+@table @option |
|
4832 |
+@item PROGRESSIVE |
|
4833 |
+the frame is progressive (not interlaced) |
|
4834 |
+@item TOPFIRST |
|
4835 |
+the frame is top-field-first |
|
4836 |
+@item BOTTOMFIRST |
|
4837 |
+the frame is bottom-field-first |
|
4838 |
+@end table |
|
4839 |
+ |
|
4840 |
+@item consumed_sample_n @emph{(audio only)} |
|
4841 |
+the number of selected samples before the current frame |
|
4842 |
+ |
|
4843 |
+@item samples_n @emph{(audio only)} |
|
4844 |
+the number of samples in the current frame |
|
4845 |
+ |
|
4846 |
+@item sample_rate @emph{(audio only)} |
|
4847 |
+the input sample rate |
|
4848 |
+ |
|
4849 |
+@item key |
|
4850 |
+1 if the filtered frame is a key-frame, 0 otherwise |
|
4851 |
+ |
|
4852 |
+@item pos |
|
4853 |
+the position in the file of the filtered frame, -1 if the information |
|
4854 |
+is not available (e.g. for synthetic video) |
|
4855 |
+ |
|
4856 |
+@item scene @emph{(video only)} |
|
4857 |
+value between 0 and 1 to indicate a new scene; a low value reflects a low |
|
4858 |
+probability for the current frame to introduce a new scene, while a higher |
|
4859 |
+value means the current frame is more likely to be one (see the example below) |
|
4860 |
+ |
|
4861 |
+@end table |
|
4862 |
+ |
|
4863 |
+The default value of the select expression is "1". |
|
4864 |
+ |
|
4865 |
+Some examples follow: |
|
4866 |
+ |
|
4867 |
+@example |
|
4868 |
+# select all frames in input |
|
4869 |
+select |
|
4870 |
+ |
|
4871 |
+# the above is the same as: |
|
4872 |
+select=1 |
|
4873 |
+ |
|
4874 |
+# skip all frames: |
|
4875 |
+select=0 |
|
4876 |
+ |
|
4877 |
+# select only I-frames |
|
4878 |
+select='eq(pict_type\,I)' |
|
4879 |
+ |
|
4880 |
+# select one frame every 100 |
|
4881 |
+select='not(mod(n\,100))' |
|
4882 |
+ |
|
4883 |
+# select only frames contained in the 10-20 time interval |
|
4884 |
+select='gte(t\,10)*lte(t\,20)' |
|
4885 |
+ |
|
4886 |
+# select only I frames contained in the 10-20 time interval |
|
4887 |
+select='gte(t\,10)*lte(t\,20)*eq(pict_type\,I)' |
|
4888 |
+ |
|
4889 |
+# select frames with a minimum distance of 10 seconds |
|
4890 |
+select='isnan(prev_selected_t)+gte(t-prev_selected_t\,10)' |
|
4891 |
+ |
|
4892 |
+# use aselect to select only audio frames with samples number > 100 |
|
4893 |
+aselect='gt(samples_n\,100)' |
|
4894 |
+@end example |
|
4895 |
+ |
|
4896 |
+Complete example to create a mosaic of the first scenes: |
|
4897 |
+ |
|
4898 |
+@example |
|
4899 |
+ffmpeg -i video.avi -vf select='gt(scene\,0.4)',scale=160:120,tile -frames:v 1 preview.png |
|
4900 |
+@end example |
|
4901 |
+ |
|
4902 |
+Comparing @var{scene} against a value between 0.3 and 0.5 is generally a sane |
|
4903 |
+choice. |
|
4904 |
+ |
|
4771 | 4905 |
@section asendcmd, sendcmd |
4772 | 4906 |
|
4773 | 4907 |
Send commands to filters in the filtergraph. |
... | ... |
@@ -54,7 +54,7 @@ OBJS-$(CONFIG_AMERGE_FILTER) += af_amerge.o |
54 | 54 |
OBJS-$(CONFIG_AMIX_FILTER) += af_amix.o |
55 | 55 |
OBJS-$(CONFIG_ANULL_FILTER) += af_anull.o |
56 | 56 |
OBJS-$(CONFIG_ARESAMPLE_FILTER) += af_aresample.o |
57 |
-OBJS-$(CONFIG_ASELECT_FILTER) += vf_select.o |
|
57 |
+OBJS-$(CONFIG_ASELECT_FILTER) += f_select.o |
|
58 | 58 |
OBJS-$(CONFIG_ASENDCMD_FILTER) += f_sendcmd.o |
59 | 59 |
OBJS-$(CONFIG_ASETNSAMPLES_FILTER) += af_asetnsamples.o |
60 | 60 |
OBJS-$(CONFIG_ASETPTS_FILTER) += f_setpts.o |
... | ... |
@@ -125,7 +125,7 @@ OBJS-$(CONFIG_PAD_FILTER) += vf_pad.o |
125 | 125 |
OBJS-$(CONFIG_PIXDESCTEST_FILTER) += vf_pixdesctest.o |
126 | 126 |
OBJS-$(CONFIG_REMOVELOGO_FILTER) += bbox.o lswsutils.o lavfutils.o vf_removelogo.o |
127 | 127 |
OBJS-$(CONFIG_SCALE_FILTER) += vf_scale.o |
128 |
-OBJS-$(CONFIG_SELECT_FILTER) += vf_select.o |
|
128 |
+OBJS-$(CONFIG_SELECT_FILTER) += f_select.o |
|
129 | 129 |
OBJS-$(CONFIG_SENDCMD_FILTER) += f_sendcmd.o |
130 | 130 |
OBJS-$(CONFIG_SETDAR_FILTER) += vf_aspect.o |
131 | 131 |
OBJS-$(CONFIG_SETFIELD_FILTER) += vf_setfield.o |
132 | 132 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,441 @@ |
0 |
+/* |
|
1 |
+ * Copyright (c) 2011 Stefano Sabatini |
|
2 |
+ * |
|
3 |
+ * This file is part of FFmpeg. |
|
4 |
+ * |
|
5 |
+ * FFmpeg is free software; you can redistribute it and/or |
|
6 |
+ * modify it under the terms of the GNU Lesser General Public |
|
7 |
+ * License as published by the Free Software Foundation; either |
|
8 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
9 |
+ * |
|
10 |
+ * FFmpeg is distributed in the hope that it will be useful, |
|
11 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 |
+ * Lesser General Public License for more details. |
|
14 |
+ * |
|
15 |
+ * You should have received a copy of the GNU Lesser General Public |
|
16 |
+ * License along with FFmpeg; if not, write to the Free Software |
|
17 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+/** |
|
21 |
+ * @file |
|
22 |
+ * filter for selecting which frame passes in the filterchain |
|
23 |
+ */ |
|
24 |
+ |
|
25 |
+#include "libavutil/eval.h" |
|
26 |
+#include "libavutil/fifo.h" |
|
27 |
+#include "libavutil/internal.h" |
|
28 |
+#include "avfilter.h" |
|
29 |
+#include "audio.h" |
|
30 |
+#include "formats.h" |
|
31 |
+#include "internal.h" |
|
32 |
+#include "video.h" |
|
33 |
+ |
|
34 |
+#if CONFIG_AVCODEC |
|
35 |
+#include "libavcodec/dsputil.h" |
|
36 |
+#endif |
|
37 |
+ |
|
38 |
+static const char *const var_names[] = { |
|
39 |
+ "TB", ///< timebase |
|
40 |
+ |
|
41 |
+ "pts", ///< original pts in the file of the frame |
|
42 |
+ "start_pts", ///< first PTS in the stream, expressed in TB units |
|
43 |
+ "prev_pts", ///< previous frame PTS |
|
44 |
+ "prev_selected_pts", ///< previous selected frame PTS |
|
45 |
+ |
|
46 |
+ "t", ///< first PTS in seconds |
|
47 |
+ "start_t", ///< first PTS in the stream, expressed in seconds |
|
48 |
+ "prev_t", ///< previous frame time |
|
49 |
+ "prev_selected_t", ///< previously selected time |
|
50 |
+ |
|
51 |
+ "pict_type", ///< the type of picture in the movie |
|
52 |
+ "I", |
|
53 |
+ "P", |
|
54 |
+ "B", |
|
55 |
+ "S", |
|
56 |
+ "SI", |
|
57 |
+ "SP", |
|
58 |
+ "BI", |
|
59 |
+ |
|
60 |
+ "interlace_type", ///< the frame interlace type |
|
61 |
+ "PROGRESSIVE", |
|
62 |
+ "TOPFIRST", |
|
63 |
+ "BOTTOMFIRST", |
|
64 |
+ |
|
65 |
+ "consumed_samples_n",///< number of samples consumed by the filter (only audio) |
|
66 |
+ "samples_n", ///< number of samples in the current frame (only audio) |
|
67 |
+ "sample_rate", ///< sample rate (only audio) |
|
68 |
+ |
|
69 |
+ "n", ///< frame number (starting from zero) |
|
70 |
+ "selected_n", ///< selected frame number (starting from zero) |
|
71 |
+ "prev_selected_n", ///< number of the last selected frame |
|
72 |
+ |
|
73 |
+ "key", ///< tell if the frame is a key frame |
|
74 |
+ "pos", ///< original position in the file of the frame |
|
75 |
+ |
|
76 |
+ "scene", |
|
77 |
+ |
|
78 |
+ NULL |
|
79 |
+}; |
|
80 |
+ |
|
81 |
+enum var_name { |
|
82 |
+ VAR_TB, |
|
83 |
+ |
|
84 |
+ VAR_PTS, |
|
85 |
+ VAR_START_PTS, |
|
86 |
+ VAR_PREV_PTS, |
|
87 |
+ VAR_PREV_SELECTED_PTS, |
|
88 |
+ |
|
89 |
+ VAR_T, |
|
90 |
+ VAR_START_T, |
|
91 |
+ VAR_PREV_T, |
|
92 |
+ VAR_PREV_SELECTED_T, |
|
93 |
+ |
|
94 |
+ VAR_PICT_TYPE, |
|
95 |
+ VAR_PICT_TYPE_I, |
|
96 |
+ VAR_PICT_TYPE_P, |
|
97 |
+ VAR_PICT_TYPE_B, |
|
98 |
+ VAR_PICT_TYPE_S, |
|
99 |
+ VAR_PICT_TYPE_SI, |
|
100 |
+ VAR_PICT_TYPE_SP, |
|
101 |
+ VAR_PICT_TYPE_BI, |
|
102 |
+ |
|
103 |
+ VAR_INTERLACE_TYPE, |
|
104 |
+ VAR_INTERLACE_TYPE_P, |
|
105 |
+ VAR_INTERLACE_TYPE_T, |
|
106 |
+ VAR_INTERLACE_TYPE_B, |
|
107 |
+ |
|
108 |
+ VAR_CONSUMED_SAMPLES_N, |
|
109 |
+ VAR_SAMPLES_N, |
|
110 |
+ VAR_SAMPLE_RATE, |
|
111 |
+ |
|
112 |
+ VAR_N, |
|
113 |
+ VAR_SELECTED_N, |
|
114 |
+ VAR_PREV_SELECTED_N, |
|
115 |
+ |
|
116 |
+ VAR_KEY, |
|
117 |
+ VAR_POS, |
|
118 |
+ |
|
119 |
+ VAR_SCENE, |
|
120 |
+ |
|
121 |
+ VAR_VARS_NB |
|
122 |
+}; |
|
123 |
+ |
|
124 |
+typedef struct { |
|
125 |
+ AVExpr *expr; |
|
126 |
+ double var_values[VAR_VARS_NB]; |
|
127 |
+ int do_scene_detect; ///< 1 if the expression requires scene detection variables, 0 otherwise |
|
128 |
+#if CONFIG_AVCODEC |
|
129 |
+ AVCodecContext *avctx; ///< codec context required for the DSPContext (scene detect only) |
|
130 |
+ DSPContext c; ///< context providing optimized SAD methods (scene detect only) |
|
131 |
+ double prev_mafd; ///< previous MAFD (scene detect only) |
|
132 |
+#endif |
|
133 |
+ AVFilterBufferRef *prev_picref; ///< previous frame (scene detect only) |
|
134 |
+ double select; |
|
135 |
+} SelectContext; |
|
136 |
+ |
|
137 |
+static av_cold int init(AVFilterContext *ctx, const char *args) |
|
138 |
+{ |
|
139 |
+ SelectContext *select = ctx->priv; |
|
140 |
+ int ret; |
|
141 |
+ |
|
142 |
+ if ((ret = av_expr_parse(&select->expr, args ? args : "1", |
|
143 |
+ var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) { |
|
144 |
+ av_log(ctx, AV_LOG_ERROR, "Error while parsing expression '%s'\n", args); |
|
145 |
+ return ret; |
|
146 |
+ } |
|
147 |
+ |
|
148 |
+ select->do_scene_detect = args && strstr(args, "scene"); |
|
149 |
+ if (select->do_scene_detect && !CONFIG_AVCODEC) { |
|
150 |
+ av_log(ctx, AV_LOG_ERROR, "Scene detection is not available without libavcodec.\n"); |
|
151 |
+ return AVERROR(EINVAL); |
|
152 |
+ } |
|
153 |
+ return 0; |
|
154 |
+} |
|
155 |
+ |
|
156 |
+#define INTERLACE_TYPE_P 0 |
|
157 |
+#define INTERLACE_TYPE_T 1 |
|
158 |
+#define INTERLACE_TYPE_B 2 |
|
159 |
+ |
|
160 |
+static int config_input(AVFilterLink *inlink) |
|
161 |
+{ |
|
162 |
+ SelectContext *select = inlink->dst->priv; |
|
163 |
+ |
|
164 |
+ select->var_values[VAR_N] = 0.0; |
|
165 |
+ select->var_values[VAR_SELECTED_N] = 0.0; |
|
166 |
+ |
|
167 |
+ select->var_values[VAR_TB] = av_q2d(inlink->time_base); |
|
168 |
+ |
|
169 |
+ select->var_values[VAR_PREV_PTS] = NAN; |
|
170 |
+ select->var_values[VAR_PREV_SELECTED_PTS] = NAN; |
|
171 |
+ select->var_values[VAR_PREV_SELECTED_T] = NAN; |
|
172 |
+ select->var_values[VAR_START_PTS] = NAN; |
|
173 |
+ select->var_values[VAR_START_T] = NAN; |
|
174 |
+ |
|
175 |
+ select->var_values[VAR_PICT_TYPE_I] = AV_PICTURE_TYPE_I; |
|
176 |
+ select->var_values[VAR_PICT_TYPE_P] = AV_PICTURE_TYPE_P; |
|
177 |
+ select->var_values[VAR_PICT_TYPE_B] = AV_PICTURE_TYPE_B; |
|
178 |
+ select->var_values[VAR_PICT_TYPE_SI] = AV_PICTURE_TYPE_SI; |
|
179 |
+ select->var_values[VAR_PICT_TYPE_SP] = AV_PICTURE_TYPE_SP; |
|
180 |
+ |
|
181 |
+ select->var_values[VAR_INTERLACE_TYPE_P] = INTERLACE_TYPE_P; |
|
182 |
+ select->var_values[VAR_INTERLACE_TYPE_T] = INTERLACE_TYPE_T; |
|
183 |
+ select->var_values[VAR_INTERLACE_TYPE_B] = INTERLACE_TYPE_B; |
|
184 |
+ |
|
185 |
+ select->var_values[VAR_SAMPLE_RATE] = |
|
186 |
+ inlink->type == AVMEDIA_TYPE_AUDIO ? inlink->sample_rate : NAN; |
|
187 |
+ |
|
188 |
+ if (CONFIG_AVCODEC && select->do_scene_detect) { |
|
189 |
+ select->avctx = avcodec_alloc_context3(NULL); |
|
190 |
+ if (!select->avctx) |
|
191 |
+ return AVERROR(ENOMEM); |
|
192 |
+ dsputil_init(&select->c, select->avctx); |
|
193 |
+ } |
|
194 |
+ return 0; |
|
195 |
+} |
|
196 |
+ |
|
197 |
+#if CONFIG_AVCODEC |
|
198 |
+static double get_scene_score(AVFilterContext *ctx, AVFilterBufferRef *picref) |
|
199 |
+{ |
|
200 |
+ double ret = 0; |
|
201 |
+ SelectContext *select = ctx->priv; |
|
202 |
+ AVFilterBufferRef *prev_picref = select->prev_picref; |
|
203 |
+ |
|
204 |
+ if (prev_picref && |
|
205 |
+ picref->video->h == prev_picref->video->h && |
|
206 |
+ picref->video->w == prev_picref->video->w && |
|
207 |
+ picref->linesize[0] == prev_picref->linesize[0]) { |
|
208 |
+ int x, y, nb_sad = 0; |
|
209 |
+ int64_t sad = 0; |
|
210 |
+ double mafd, diff; |
|
211 |
+ uint8_t *p1 = picref->data[0]; |
|
212 |
+ uint8_t *p2 = prev_picref->data[0]; |
|
213 |
+ const int linesize = picref->linesize[0]; |
|
214 |
+ |
|
215 |
+ for (y = 0; y < picref->video->h - 8; y += 8) { |
|
216 |
+ for (x = 0; x < picref->video->w*3 - 8; x += 8) { |
|
217 |
+ sad += select->c.sad[1](select, p1 + x, p2 + x, |
|
218 |
+ linesize, 8); |
|
219 |
+ nb_sad += 8 * 8; |
|
220 |
+ } |
|
221 |
+ p1 += 8 * linesize; |
|
222 |
+ p2 += 8 * linesize; |
|
223 |
+ } |
|
224 |
+ emms_c(); |
|
225 |
+ mafd = nb_sad ? sad / nb_sad : 0; |
|
226 |
+ diff = fabs(mafd - select->prev_mafd); |
|
227 |
+ ret = av_clipf(FFMIN(mafd, diff) / 100., 0, 1); |
|
228 |
+ select->prev_mafd = mafd; |
|
229 |
+ avfilter_unref_buffer(prev_picref); |
|
230 |
+ } |
|
231 |
+ select->prev_picref = avfilter_ref_buffer(picref, ~0); |
|
232 |
+ return ret; |
|
233 |
+} |
|
234 |
+#endif |
|
235 |
+ |
|
236 |
+#define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d)) |
|
237 |
+#define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts)) |
|
238 |
+ |
|
239 |
+static int select_frame(AVFilterContext *ctx, AVFilterBufferRef *picref) |
|
240 |
+{ |
|
241 |
+ SelectContext *select = ctx->priv; |
|
242 |
+ AVFilterLink *inlink = ctx->inputs[0]; |
|
243 |
+ double res; |
|
244 |
+ |
|
245 |
+ if (isnan(select->var_values[VAR_START_PTS])) |
|
246 |
+ select->var_values[VAR_START_PTS] = TS2D(picref->pts); |
|
247 |
+ if (isnan(select->var_values[VAR_START_T])) |
|
248 |
+ select->var_values[VAR_START_T] = TS2D(picref->pts) * av_q2d(inlink->time_base); |
|
249 |
+ |
|
250 |
+ select->var_values[VAR_PTS] = TS2D(picref->pts); |
|
251 |
+ select->var_values[VAR_T ] = TS2D(picref->pts) * av_q2d(inlink->time_base); |
|
252 |
+ select->var_values[VAR_POS] = picref->pos == -1 ? NAN : picref->pos; |
|
253 |
+ select->var_values[VAR_PREV_PTS] = TS2D(picref ->pts); |
|
254 |
+ |
|
255 |
+ switch (inlink->type) { |
|
256 |
+ case AVMEDIA_TYPE_AUDIO: |
|
257 |
+ select->var_values[VAR_SAMPLES_N] = picref->audio->nb_samples; |
|
258 |
+ break; |
|
259 |
+ |
|
260 |
+ case AVMEDIA_TYPE_VIDEO: |
|
261 |
+ select->var_values[VAR_INTERLACE_TYPE] = |
|
262 |
+ !picref->video->interlaced ? INTERLACE_TYPE_P : |
|
263 |
+ picref->video->top_field_first ? INTERLACE_TYPE_T : INTERLACE_TYPE_B; |
|
264 |
+ select->var_values[VAR_PICT_TYPE] = picref->video->pict_type; |
|
265 |
+ if (CONFIG_AVCODEC && select->do_scene_detect) { |
|
266 |
+ char buf[32]; |
|
267 |
+ select->var_values[VAR_SCENE] = get_scene_score(ctx, picref); |
|
268 |
+ // TODO: document metadata |
|
269 |
+ snprintf(buf, sizeof(buf), "%f", select->var_values[VAR_SCENE]); |
|
270 |
+ av_dict_set(&picref->metadata, "lavfi.scene_score", buf, 0); |
|
271 |
+ } |
|
272 |
+ break; |
|
273 |
+ } |
|
274 |
+ |
|
275 |
+ res = av_expr_eval(select->expr, select->var_values, NULL); |
|
276 |
+ av_log(inlink->dst, AV_LOG_DEBUG, |
|
277 |
+ "n:%d pts:%d t:%f pos:%d key:%d", |
|
278 |
+ (int)select->var_values[VAR_N], |
|
279 |
+ (int)select->var_values[VAR_PTS], |
|
280 |
+ select->var_values[VAR_T], |
|
281 |
+ (int)select->var_values[VAR_POS], |
|
282 |
+ (int)select->var_values[VAR_KEY]); |
|
283 |
+ |
|
284 |
+ switch (inlink->type) { |
|
285 |
+ case AVMEDIA_TYPE_VIDEO: |
|
286 |
+ av_log(inlink->dst, AV_LOG_DEBUG, " interlace_type:%c pict_type:%c", |
|
287 |
+ select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_P ? 'P' : |
|
288 |
+ select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_T ? 'T' : |
|
289 |
+ select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_B ? 'B' : '?', |
|
290 |
+ av_get_picture_type_char(select->var_values[VAR_PICT_TYPE])); |
|
291 |
+ break; |
|
292 |
+ case AVMEDIA_TYPE_AUDIO: |
|
293 |
+ av_log(inlink->dst, AV_LOG_DEBUG, " samples_n:%d consumed_samples_n:%d", |
|
294 |
+ (int)select->var_values[VAR_SAMPLES_N], |
|
295 |
+ (int)select->var_values[VAR_CONSUMED_SAMPLES_N]); |
|
296 |
+ break; |
|
297 |
+ } |
|
298 |
+ |
|
299 |
+ av_log(inlink->dst, AV_LOG_DEBUG, " -> select:%f\n", res); |
|
300 |
+ |
|
301 |
+ if (res) { |
|
302 |
+ select->var_values[VAR_PREV_SELECTED_N] = select->var_values[VAR_N]; |
|
303 |
+ select->var_values[VAR_PREV_SELECTED_PTS] = select->var_values[VAR_PTS]; |
|
304 |
+ select->var_values[VAR_PREV_SELECTED_T] = select->var_values[VAR_T]; |
|
305 |
+ select->var_values[VAR_SELECTED_N] += 1.0; |
|
306 |
+ if (inlink->type == AVMEDIA_TYPE_AUDIO) |
|
307 |
+ select->var_values[VAR_CONSUMED_SAMPLES_N] += picref->audio->nb_samples; |
|
308 |
+ } |
|
309 |
+ |
|
310 |
+ select->var_values[VAR_N] += 1.0; |
|
311 |
+ |
|
312 |
+ return res; |
|
313 |
+} |
|
314 |
+ |
|
315 |
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame) |
|
316 |
+{ |
|
317 |
+ SelectContext *select = inlink->dst->priv; |
|
318 |
+ |
|
319 |
+ select->select = select_frame(inlink->dst, frame); |
|
320 |
+ if (select->select) |
|
321 |
+ return ff_filter_frame(inlink->dst->outputs[0], frame); |
|
322 |
+ |
|
323 |
+ avfilter_unref_bufferp(&frame); |
|
324 |
+ return 0; |
|
325 |
+} |
|
326 |
+ |
|
327 |
+static int request_frame(AVFilterLink *outlink) |
|
328 |
+{ |
|
329 |
+ AVFilterContext *ctx = outlink->src; |
|
330 |
+ SelectContext *select = ctx->priv; |
|
331 |
+ AVFilterLink *inlink = outlink->src->inputs[0]; |
|
332 |
+ select->select = 0; |
|
333 |
+ |
|
334 |
+ do { |
|
335 |
+ int ret = ff_request_frame(inlink); |
|
336 |
+ if (ret < 0) |
|
337 |
+ return ret; |
|
338 |
+ } while (!select->select); |
|
339 |
+ |
|
340 |
+ return 0; |
|
341 |
+} |
|
342 |
+ |
|
343 |
+static av_cold void uninit(AVFilterContext *ctx) |
|
344 |
+{ |
|
345 |
+ SelectContext *select = ctx->priv; |
|
346 |
+ |
|
347 |
+ av_expr_free(select->expr); |
|
348 |
+ select->expr = NULL; |
|
349 |
+ |
|
350 |
+ if (select->do_scene_detect) { |
|
351 |
+ avfilter_unref_bufferp(&select->prev_picref); |
|
352 |
+ if (select->avctx) { |
|
353 |
+ avcodec_close(select->avctx); |
|
354 |
+ av_freep(&select->avctx); |
|
355 |
+ } |
|
356 |
+ } |
|
357 |
+} |
|
358 |
+ |
|
359 |
+static int query_formats(AVFilterContext *ctx) |
|
360 |
+{ |
|
361 |
+ SelectContext *select = ctx->priv; |
|
362 |
+ |
|
363 |
+ if (!select->do_scene_detect) { |
|
364 |
+ return ff_default_query_formats(ctx); |
|
365 |
+ } else { |
|
366 |
+ static const enum AVPixelFormat pix_fmts[] = { |
|
367 |
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, |
|
368 |
+ AV_PIX_FMT_NONE |
|
369 |
+ }; |
|
370 |
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); |
|
371 |
+ } |
|
372 |
+ return 0; |
|
373 |
+} |
|
374 |
+ |
|
375 |
+#if CONFIG_ASELECT_FILTER |
|
376 |
+static const AVFilterPad avfilter_af_aselect_inputs[] = { |
|
377 |
+ { |
|
378 |
+ .name = "default", |
|
379 |
+ .type = AVMEDIA_TYPE_AUDIO, |
|
380 |
+ .get_audio_buffer = ff_null_get_audio_buffer, |
|
381 |
+ .config_props = config_input, |
|
382 |
+ .filter_frame = filter_frame, |
|
383 |
+ }, |
|
384 |
+ { NULL } |
|
385 |
+}; |
|
386 |
+ |
|
387 |
+static const AVFilterPad avfilter_af_aselect_outputs[] = { |
|
388 |
+ { |
|
389 |
+ .name = "default", |
|
390 |
+ .type = AVMEDIA_TYPE_AUDIO, |
|
391 |
+ }, |
|
392 |
+ { NULL } |
|
393 |
+}; |
|
394 |
+ |
|
395 |
+AVFilter avfilter_af_aselect = { |
|
396 |
+ .name = "aselect", |
|
397 |
+ .description = NULL_IF_CONFIG_SMALL("Select audio frames to pass in output."), |
|
398 |
+ .init = init, |
|
399 |
+ .uninit = uninit, |
|
400 |
+ .priv_size = sizeof(SelectContext), |
|
401 |
+ .inputs = avfilter_af_aselect_inputs, |
|
402 |
+ .outputs = avfilter_af_aselect_outputs, |
|
403 |
+}; |
|
404 |
+#endif /* CONFIG_ASELECT_FILTER */ |
|
405 |
+ |
|
406 |
+#if CONFIG_SELECT_FILTER |
|
407 |
+static const AVFilterPad avfilter_vf_select_inputs[] = { |
|
408 |
+ { |
|
409 |
+ .name = "default", |
|
410 |
+ .type = AVMEDIA_TYPE_VIDEO, |
|
411 |
+ .get_video_buffer = ff_null_get_video_buffer, |
|
412 |
+ .min_perms = AV_PERM_PRESERVE, |
|
413 |
+ .config_props = config_input, |
|
414 |
+ .filter_frame = filter_frame, |
|
415 |
+ }, |
|
416 |
+ { NULL } |
|
417 |
+}; |
|
418 |
+ |
|
419 |
+static const AVFilterPad avfilter_vf_select_outputs[] = { |
|
420 |
+ { |
|
421 |
+ .name = "default", |
|
422 |
+ .type = AVMEDIA_TYPE_VIDEO, |
|
423 |
+ .request_frame = request_frame, |
|
424 |
+ }, |
|
425 |
+ { NULL } |
|
426 |
+}; |
|
427 |
+ |
|
428 |
+AVFilter avfilter_vf_select = { |
|
429 |
+ .name = "select", |
|
430 |
+ .description = NULL_IF_CONFIG_SMALL("Select video frames to pass in output."), |
|
431 |
+ .init = init, |
|
432 |
+ .uninit = uninit, |
|
433 |
+ .query_formats = query_formats, |
|
434 |
+ |
|
435 |
+ .priv_size = sizeof(SelectContext), |
|
436 |
+ |
|
437 |
+ .inputs = avfilter_vf_select_inputs, |
|
438 |
+ .outputs = avfilter_vf_select_outputs, |
|
439 |
+}; |
|
440 |
+#endif /* CONFIG_SELECT_FILTER */ |
0 | 441 |
deleted file mode 100644 |
... | ... |
@@ -1,441 +0,0 @@ |
1 |
-/* |
|
2 |
- * Copyright (c) 2011 Stefano Sabatini |
|
3 |
- * |
|
4 |
- * This file is part of FFmpeg. |
|
5 |
- * |
|
6 |
- * FFmpeg is free software; you can redistribute it and/or |
|
7 |
- * modify it under the terms of the GNU Lesser General Public |
|
8 |
- * License as published by the Free Software Foundation; either |
|
9 |
- * version 2.1 of the License, or (at your option) any later version. |
|
10 |
- * |
|
11 |
- * FFmpeg is distributed in the hope that it will be useful, |
|
12 |
- * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 |
- * Lesser General Public License for more details. |
|
15 |
- * |
|
16 |
- * You should have received a copy of the GNU Lesser General Public |
|
17 |
- * License along with FFmpeg; if not, write to the Free Software |
|
18 |
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
19 |
- */ |
|
20 |
- |
|
21 |
-/** |
|
22 |
- * @file |
|
23 |
- * filter for selecting which frame passes in the filterchain |
|
24 |
- */ |
|
25 |
- |
|
26 |
-#include "libavutil/eval.h" |
|
27 |
-#include "libavutil/fifo.h" |
|
28 |
-#include "libavutil/internal.h" |
|
29 |
-#include "avfilter.h" |
|
30 |
-#include "audio.h" |
|
31 |
-#include "formats.h" |
|
32 |
-#include "internal.h" |
|
33 |
-#include "video.h" |
|
34 |
- |
|
35 |
-#if CONFIG_AVCODEC |
|
36 |
-#include "libavcodec/dsputil.h" |
|
37 |
-#endif |
|
38 |
- |
|
39 |
-static const char *const var_names[] = { |
|
40 |
- "TB", ///< timebase |
|
41 |
- |
|
42 |
- "pts", ///< original pts in the file of the frame |
|
43 |
- "start_pts", ///< first PTS in the stream, expressed in TB units |
|
44 |
- "prev_pts", ///< previous frame PTS |
|
45 |
- "prev_selected_pts", ///< previous selected frame PTS |
|
46 |
- |
|
47 |
- "t", ///< first PTS in seconds |
|
48 |
- "start_t", ///< first PTS in the stream, expressed in seconds |
|
49 |
- "prev_t", ///< previous frame time |
|
50 |
- "prev_selected_t", ///< previously selected time |
|
51 |
- |
|
52 |
- "pict_type", ///< the type of picture in the movie |
|
53 |
- "I", |
|
54 |
- "P", |
|
55 |
- "B", |
|
56 |
- "S", |
|
57 |
- "SI", |
|
58 |
- "SP", |
|
59 |
- "BI", |
|
60 |
- |
|
61 |
- "interlace_type", ///< the frame interlace type |
|
62 |
- "PROGRESSIVE", |
|
63 |
- "TOPFIRST", |
|
64 |
- "BOTTOMFIRST", |
|
65 |
- |
|
66 |
- "consumed_samples_n",///< number of samples consumed by the filter (only audio) |
|
67 |
- "samples_n", ///< number of samples in the current frame (only audio) |
|
68 |
- "sample_rate", ///< sample rate (only audio) |
|
69 |
- |
|
70 |
- "n", ///< frame number (starting from zero) |
|
71 |
- "selected_n", ///< selected frame number (starting from zero) |
|
72 |
- "prev_selected_n", ///< number of the last selected frame |
|
73 |
- |
|
74 |
- "key", ///< tell if the frame is a key frame |
|
75 |
- "pos", ///< original position in the file of the frame |
|
76 |
- |
|
77 |
- "scene", |
|
78 |
- |
|
79 |
- NULL |
|
80 |
-}; |
|
81 |
- |
|
82 |
-enum var_name { |
|
83 |
- VAR_TB, |
|
84 |
- |
|
85 |
- VAR_PTS, |
|
86 |
- VAR_START_PTS, |
|
87 |
- VAR_PREV_PTS, |
|
88 |
- VAR_PREV_SELECTED_PTS, |
|
89 |
- |
|
90 |
- VAR_T, |
|
91 |
- VAR_START_T, |
|
92 |
- VAR_PREV_T, |
|
93 |
- VAR_PREV_SELECTED_T, |
|
94 |
- |
|
95 |
- VAR_PICT_TYPE, |
|
96 |
- VAR_PICT_TYPE_I, |
|
97 |
- VAR_PICT_TYPE_P, |
|
98 |
- VAR_PICT_TYPE_B, |
|
99 |
- VAR_PICT_TYPE_S, |
|
100 |
- VAR_PICT_TYPE_SI, |
|
101 |
- VAR_PICT_TYPE_SP, |
|
102 |
- VAR_PICT_TYPE_BI, |
|
103 |
- |
|
104 |
- VAR_INTERLACE_TYPE, |
|
105 |
- VAR_INTERLACE_TYPE_P, |
|
106 |
- VAR_INTERLACE_TYPE_T, |
|
107 |
- VAR_INTERLACE_TYPE_B, |
|
108 |
- |
|
109 |
- VAR_CONSUMED_SAMPLES_N, |
|
110 |
- VAR_SAMPLES_N, |
|
111 |
- VAR_SAMPLE_RATE, |
|
112 |
- |
|
113 |
- VAR_N, |
|
114 |
- VAR_SELECTED_N, |
|
115 |
- VAR_PREV_SELECTED_N, |
|
116 |
- |
|
117 |
- VAR_KEY, |
|
118 |
- VAR_POS, |
|
119 |
- |
|
120 |
- VAR_SCENE, |
|
121 |
- |
|
122 |
- VAR_VARS_NB |
|
123 |
-}; |
|
124 |
- |
|
125 |
-typedef struct { |
|
126 |
- AVExpr *expr; |
|
127 |
- double var_values[VAR_VARS_NB]; |
|
128 |
- int do_scene_detect; ///< 1 if the expression requires scene detection variables, 0 otherwise |
|
129 |
-#if CONFIG_AVCODEC |
|
130 |
- AVCodecContext *avctx; ///< codec context required for the DSPContext (scene detect only) |
|
131 |
- DSPContext c; ///< context providing optimized SAD methods (scene detect only) |
|
132 |
- double prev_mafd; ///< previous MAFD (scene detect only) |
|
133 |
-#endif |
|
134 |
- AVFilterBufferRef *prev_picref; ///< previous frame (scene detect only) |
|
135 |
- double select; |
|
136 |
-} SelectContext; |
|
137 |
- |
|
138 |
-static av_cold int init(AVFilterContext *ctx, const char *args) |
|
139 |
-{ |
|
140 |
- SelectContext *select = ctx->priv; |
|
141 |
- int ret; |
|
142 |
- |
|
143 |
- if ((ret = av_expr_parse(&select->expr, args ? args : "1", |
|
144 |
- var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) { |
|
145 |
- av_log(ctx, AV_LOG_ERROR, "Error while parsing expression '%s'\n", args); |
|
146 |
- return ret; |
|
147 |
- } |
|
148 |
- |
|
149 |
- select->do_scene_detect = args && strstr(args, "scene"); |
|
150 |
- if (select->do_scene_detect && !CONFIG_AVCODEC) { |
|
151 |
- av_log(ctx, AV_LOG_ERROR, "Scene detection is not available without libavcodec.\n"); |
|
152 |
- return AVERROR(EINVAL); |
|
153 |
- } |
|
154 |
- return 0; |
|
155 |
-} |
|
156 |
- |
|
157 |
-#define INTERLACE_TYPE_P 0 |
|
158 |
-#define INTERLACE_TYPE_T 1 |
|
159 |
-#define INTERLACE_TYPE_B 2 |
|
160 |
- |
|
161 |
-static int config_input(AVFilterLink *inlink) |
|
162 |
-{ |
|
163 |
- SelectContext *select = inlink->dst->priv; |
|
164 |
- |
|
165 |
- select->var_values[VAR_N] = 0.0; |
|
166 |
- select->var_values[VAR_SELECTED_N] = 0.0; |
|
167 |
- |
|
168 |
- select->var_values[VAR_TB] = av_q2d(inlink->time_base); |
|
169 |
- |
|
170 |
- select->var_values[VAR_PREV_PTS] = NAN; |
|
171 |
- select->var_values[VAR_PREV_SELECTED_PTS] = NAN; |
|
172 |
- select->var_values[VAR_PREV_SELECTED_T] = NAN; |
|
173 |
- select->var_values[VAR_START_PTS] = NAN; |
|
174 |
- select->var_values[VAR_START_T] = NAN; |
|
175 |
- |
|
176 |
- select->var_values[VAR_PICT_TYPE_I] = AV_PICTURE_TYPE_I; |
|
177 |
- select->var_values[VAR_PICT_TYPE_P] = AV_PICTURE_TYPE_P; |
|
178 |
- select->var_values[VAR_PICT_TYPE_B] = AV_PICTURE_TYPE_B; |
|
179 |
- select->var_values[VAR_PICT_TYPE_SI] = AV_PICTURE_TYPE_SI; |
|
180 |
- select->var_values[VAR_PICT_TYPE_SP] = AV_PICTURE_TYPE_SP; |
|
181 |
- |
|
182 |
- select->var_values[VAR_INTERLACE_TYPE_P] = INTERLACE_TYPE_P; |
|
183 |
- select->var_values[VAR_INTERLACE_TYPE_T] = INTERLACE_TYPE_T; |
|
184 |
- select->var_values[VAR_INTERLACE_TYPE_B] = INTERLACE_TYPE_B; |
|
185 |
- |
|
186 |
- select->var_values[VAR_SAMPLE_RATE] = |
|
187 |
- inlink->type == AVMEDIA_TYPE_AUDIO ? inlink->sample_rate : NAN; |
|
188 |
- |
|
189 |
- if (CONFIG_AVCODEC && select->do_scene_detect) { |
|
190 |
- select->avctx = avcodec_alloc_context3(NULL); |
|
191 |
- if (!select->avctx) |
|
192 |
- return AVERROR(ENOMEM); |
|
193 |
- dsputil_init(&select->c, select->avctx); |
|
194 |
- } |
|
195 |
- return 0; |
|
196 |
-} |
|
197 |
- |
|
198 |
-#if CONFIG_AVCODEC |
|
199 |
-static double get_scene_score(AVFilterContext *ctx, AVFilterBufferRef *picref) |
|
200 |
-{ |
|
201 |
- double ret = 0; |
|
202 |
- SelectContext *select = ctx->priv; |
|
203 |
- AVFilterBufferRef *prev_picref = select->prev_picref; |
|
204 |
- |
|
205 |
- if (prev_picref && |
|
206 |
- picref->video->h == prev_picref->video->h && |
|
207 |
- picref->video->w == prev_picref->video->w && |
|
208 |
- picref->linesize[0] == prev_picref->linesize[0]) { |
|
209 |
- int x, y, nb_sad = 0; |
|
210 |
- int64_t sad = 0; |
|
211 |
- double mafd, diff; |
|
212 |
- uint8_t *p1 = picref->data[0]; |
|
213 |
- uint8_t *p2 = prev_picref->data[0]; |
|
214 |
- const int linesize = picref->linesize[0]; |
|
215 |
- |
|
216 |
- for (y = 0; y < picref->video->h - 8; y += 8) { |
|
217 |
- for (x = 0; x < picref->video->w*3 - 8; x += 8) { |
|
218 |
- sad += select->c.sad[1](select, p1 + x, p2 + x, |
|
219 |
- linesize, 8); |
|
220 |
- nb_sad += 8 * 8; |
|
221 |
- } |
|
222 |
- p1 += 8 * linesize; |
|
223 |
- p2 += 8 * linesize; |
|
224 |
- } |
|
225 |
- emms_c(); |
|
226 |
- mafd = nb_sad ? sad / nb_sad : 0; |
|
227 |
- diff = fabs(mafd - select->prev_mafd); |
|
228 |
- ret = av_clipf(FFMIN(mafd, diff) / 100., 0, 1); |
|
229 |
- select->prev_mafd = mafd; |
|
230 |
- avfilter_unref_buffer(prev_picref); |
|
231 |
- } |
|
232 |
- select->prev_picref = avfilter_ref_buffer(picref, ~0); |
|
233 |
- return ret; |
|
234 |
-} |
|
235 |
-#endif |
|
236 |
- |
|
237 |
-#define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d)) |
|
238 |
-#define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts)) |
|
239 |
- |
|
240 |
-static int select_frame(AVFilterContext *ctx, AVFilterBufferRef *picref) |
|
241 |
-{ |
|
242 |
- SelectContext *select = ctx->priv; |
|
243 |
- AVFilterLink *inlink = ctx->inputs[0]; |
|
244 |
- double res; |
|
245 |
- |
|
246 |
- if (isnan(select->var_values[VAR_START_PTS])) |
|
247 |
- select->var_values[VAR_START_PTS] = TS2D(picref->pts); |
|
248 |
- if (isnan(select->var_values[VAR_START_T])) |
|
249 |
- select->var_values[VAR_START_T] = TS2D(picref->pts) * av_q2d(inlink->time_base); |
|
250 |
- |
|
251 |
- select->var_values[VAR_PTS] = TS2D(picref->pts); |
|
252 |
- select->var_values[VAR_T ] = TS2D(picref->pts) * av_q2d(inlink->time_base); |
|
253 |
- select->var_values[VAR_POS] = picref->pos == -1 ? NAN : picref->pos; |
|
254 |
- select->var_values[VAR_PREV_PTS] = TS2D(picref ->pts); |
|
255 |
- |
|
256 |
- switch (inlink->type) { |
|
257 |
- case AVMEDIA_TYPE_AUDIO: |
|
258 |
- select->var_values[VAR_SAMPLES_N] = picref->audio->nb_samples; |
|
259 |
- break; |
|
260 |
- |
|
261 |
- case AVMEDIA_TYPE_VIDEO: |
|
262 |
- select->var_values[VAR_INTERLACE_TYPE] = |
|
263 |
- !picref->video->interlaced ? INTERLACE_TYPE_P : |
|
264 |
- picref->video->top_field_first ? INTERLACE_TYPE_T : INTERLACE_TYPE_B; |
|
265 |
- select->var_values[VAR_PICT_TYPE] = picref->video->pict_type; |
|
266 |
- if (CONFIG_AVCODEC && select->do_scene_detect) { |
|
267 |
- char buf[32]; |
|
268 |
- select->var_values[VAR_SCENE] = get_scene_score(ctx, picref); |
|
269 |
- // TODO: document metadata |
|
270 |
- snprintf(buf, sizeof(buf), "%f", select->var_values[VAR_SCENE]); |
|
271 |
- av_dict_set(&picref->metadata, "lavfi.scene_score", buf, 0); |
|
272 |
- } |
|
273 |
- break; |
|
274 |
- } |
|
275 |
- |
|
276 |
- res = av_expr_eval(select->expr, select->var_values, NULL); |
|
277 |
- av_log(inlink->dst, AV_LOG_DEBUG, |
|
278 |
- "n:%d pts:%d t:%f pos:%d key:%d", |
|
279 |
- (int)select->var_values[VAR_N], |
|
280 |
- (int)select->var_values[VAR_PTS], |
|
281 |
- select->var_values[VAR_T], |
|
282 |
- (int)select->var_values[VAR_POS], |
|
283 |
- (int)select->var_values[VAR_KEY]); |
|
284 |
- |
|
285 |
- switch (inlink->type) { |
|
286 |
- case AVMEDIA_TYPE_VIDEO: |
|
287 |
- av_log(inlink->dst, AV_LOG_DEBUG, " interlace_type:%c pict_type:%c", |
|
288 |
- select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_P ? 'P' : |
|
289 |
- select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_T ? 'T' : |
|
290 |
- select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_B ? 'B' : '?', |
|
291 |
- av_get_picture_type_char(select->var_values[VAR_PICT_TYPE])); |
|
292 |
- break; |
|
293 |
- case AVMEDIA_TYPE_AUDIO: |
|
294 |
- av_log(inlink->dst, AV_LOG_DEBUG, " samples_n:%d consumed_samples_n:%d", |
|
295 |
- (int)select->var_values[VAR_SAMPLES_N], |
|
296 |
- (int)select->var_values[VAR_CONSUMED_SAMPLES_N]); |
|
297 |
- break; |
|
298 |
- } |
|
299 |
- |
|
300 |
- av_log(inlink->dst, AV_LOG_DEBUG, " -> select:%f\n", res); |
|
301 |
- |
|
302 |
- if (res) { |
|
303 |
- select->var_values[VAR_PREV_SELECTED_N] = select->var_values[VAR_N]; |
|
304 |
- select->var_values[VAR_PREV_SELECTED_PTS] = select->var_values[VAR_PTS]; |
|
305 |
- select->var_values[VAR_PREV_SELECTED_T] = select->var_values[VAR_T]; |
|
306 |
- select->var_values[VAR_SELECTED_N] += 1.0; |
|
307 |
- if (inlink->type == AVMEDIA_TYPE_AUDIO) |
|
308 |
- select->var_values[VAR_CONSUMED_SAMPLES_N] += picref->audio->nb_samples; |
|
309 |
- } |
|
310 |
- |
|
311 |
- select->var_values[VAR_N] += 1.0; |
|
312 |
- |
|
313 |
- return res; |
|
314 |
-} |
|
315 |
- |
|
316 |
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame) |
|
317 |
-{ |
|
318 |
- SelectContext *select = inlink->dst->priv; |
|
319 |
- |
|
320 |
- select->select = select_frame(inlink->dst, frame); |
|
321 |
- if (select->select) |
|
322 |
- return ff_filter_frame(inlink->dst->outputs[0], frame); |
|
323 |
- |
|
324 |
- avfilter_unref_bufferp(&frame); |
|
325 |
- return 0; |
|
326 |
-} |
|
327 |
- |
|
328 |
-static int request_frame(AVFilterLink *outlink) |
|
329 |
-{ |
|
330 |
- AVFilterContext *ctx = outlink->src; |
|
331 |
- SelectContext *select = ctx->priv; |
|
332 |
- AVFilterLink *inlink = outlink->src->inputs[0]; |
|
333 |
- select->select = 0; |
|
334 |
- |
|
335 |
- do { |
|
336 |
- int ret = ff_request_frame(inlink); |
|
337 |
- if (ret < 0) |
|
338 |
- return ret; |
|
339 |
- } while (!select->select); |
|
340 |
- |
|
341 |
- return 0; |
|
342 |
-} |
|
343 |
- |
|
344 |
-static av_cold void uninit(AVFilterContext *ctx) |
|
345 |
-{ |
|
346 |
- SelectContext *select = ctx->priv; |
|
347 |
- |
|
348 |
- av_expr_free(select->expr); |
|
349 |
- select->expr = NULL; |
|
350 |
- |
|
351 |
- if (select->do_scene_detect) { |
|
352 |
- avfilter_unref_bufferp(&select->prev_picref); |
|
353 |
- if (select->avctx) { |
|
354 |
- avcodec_close(select->avctx); |
|
355 |
- av_freep(&select->avctx); |
|
356 |
- } |
|
357 |
- } |
|
358 |
-} |
|
359 |
- |
|
360 |
-static int query_formats(AVFilterContext *ctx) |
|
361 |
-{ |
|
362 |
- SelectContext *select = ctx->priv; |
|
363 |
- |
|
364 |
- if (!select->do_scene_detect) { |
|
365 |
- return ff_default_query_formats(ctx); |
|
366 |
- } else { |
|
367 |
- static const enum AVPixelFormat pix_fmts[] = { |
|
368 |
- AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, |
|
369 |
- AV_PIX_FMT_NONE |
|
370 |
- }; |
|
371 |
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); |
|
372 |
- } |
|
373 |
- return 0; |
|
374 |
-} |
|
375 |
- |
|
376 |
-#if CONFIG_ASELECT_FILTER |
|
377 |
-static const AVFilterPad avfilter_af_aselect_inputs[] = { |
|
378 |
- { |
|
379 |
- .name = "default", |
|
380 |
- .type = AVMEDIA_TYPE_AUDIO, |
|
381 |
- .get_audio_buffer = ff_null_get_audio_buffer, |
|
382 |
- .config_props = config_input, |
|
383 |
- .filter_frame = filter_frame, |
|
384 |
- }, |
|
385 |
- { NULL } |
|
386 |
-}; |
|
387 |
- |
|
388 |
-static const AVFilterPad avfilter_af_aselect_outputs[] = { |
|
389 |
- { |
|
390 |
- .name = "default", |
|
391 |
- .type = AVMEDIA_TYPE_AUDIO, |
|
392 |
- }, |
|
393 |
- { NULL } |
|
394 |
-}; |
|
395 |
- |
|
396 |
-AVFilter avfilter_af_aselect = { |
|
397 |
- .name = "aselect", |
|
398 |
- .description = NULL_IF_CONFIG_SMALL("Select audio frames to pass in output."), |
|
399 |
- .init = init, |
|
400 |
- .uninit = uninit, |
|
401 |
- .priv_size = sizeof(SelectContext), |
|
402 |
- .inputs = avfilter_af_aselect_inputs, |
|
403 |
- .outputs = avfilter_af_aselect_outputs, |
|
404 |
-}; |
|
405 |
-#endif /* CONFIG_ASELECT_FILTER */ |
|
406 |
- |
|
407 |
-#if CONFIG_SELECT_FILTER |
|
408 |
-static const AVFilterPad avfilter_vf_select_inputs[] = { |
|
409 |
- { |
|
410 |
- .name = "default", |
|
411 |
- .type = AVMEDIA_TYPE_VIDEO, |
|
412 |
- .get_video_buffer = ff_null_get_video_buffer, |
|
413 |
- .min_perms = AV_PERM_PRESERVE, |
|
414 |
- .config_props = config_input, |
|
415 |
- .filter_frame = filter_frame, |
|
416 |
- }, |
|
417 |
- { NULL } |
|
418 |
-}; |
|
419 |
- |
|
420 |
-static const AVFilterPad avfilter_vf_select_outputs[] = { |
|
421 |
- { |
|
422 |
- .name = "default", |
|
423 |
- .type = AVMEDIA_TYPE_VIDEO, |
|
424 |
- .request_frame = request_frame, |
|
425 |
- }, |
|
426 |
- { NULL } |
|
427 |
-}; |
|
428 |
- |
|
429 |
-AVFilter avfilter_vf_select = { |
|
430 |
- .name = "select", |
|
431 |
- .description = NULL_IF_CONFIG_SMALL("Select video frames to pass in output."), |
|
432 |
- .init = init, |
|
433 |
- .uninit = uninit, |
|
434 |
- .query_formats = query_formats, |
|
435 |
- |
|
436 |
- .priv_size = sizeof(SelectContext), |
|
437 |
- |
|
438 |
- .inputs = avfilter_vf_select_inputs, |
|
439 |
- .outputs = avfilter_vf_select_outputs, |
|
440 |
-}; |
|
441 |
-#endif /* CONFIG_SELECT_FILTER */ |