blob: 45d246b73231c823b8154cb14fa7ab0896c1c038
1 | /* |
2 | * This file is part of FFmpeg. |
3 | * |
4 | * FFmpeg is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2.1 of the License, or (at your option) any later version. |
8 | * |
9 | * FFmpeg is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with FFmpeg; if not, write to the Free Software |
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ |
18 | |
19 | /** |
20 | * @file |
21 | * filter for manipulating frame side data |
22 | */ |
23 | |
24 | #include "libavutil/avassert.h" |
25 | #include "libavutil/internal.h" |
26 | #include "libavutil/frame.h" |
27 | #include "libavutil/opt.h" |
28 | #include "avfilter.h" |
29 | #include "formats.h" |
30 | #include "internal.h" |
31 | |
32 | enum SideDataMode { |
33 | SIDEDATA_SELECT, |
34 | SIDEDATA_DELETE, |
35 | SIDEDATA_NB |
36 | }; |
37 | |
38 | typedef struct SideDataContext { |
39 | const AVClass *class; |
40 | |
41 | int mode; |
42 | enum AVFrameSideDataType type; |
43 | } SideDataContext; |
44 | |
45 | #define OFFSET(x) offsetof(SideDataContext, x) |
46 | #define DEFINE_OPTIONS(filt_name, FLAGS) \ |
47 | static const AVOption filt_name##_options[] = { \ |
48 | { "mode", "set a mode of operation", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, SIDEDATA_NB-1, FLAGS, "mode" }, \ |
49 | { "select", "select frame", 0, AV_OPT_TYPE_CONST, {.i64 = SIDEDATA_SELECT }, 0, 0, FLAGS, "mode" }, \ |
50 | { "delete", "delete side data", 0, AV_OPT_TYPE_CONST, {.i64 = SIDEDATA_DELETE }, 0, 0, FLAGS, "mode" }, \ |
51 | { "type", "set side data type", OFFSET(type), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, INT_MAX, FLAGS, "type" }, \ |
52 | { "PANSCAN", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_PANSCAN }, 0, 0, FLAGS, "type" }, \ |
53 | { "A53_CC", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_A53_CC }, 0, 0, FLAGS, "type" }, \ |
54 | { "STEREO3D", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_STEREO3D }, 0, 0, FLAGS, "type" }, \ |
55 | { "MATRIXENCODING", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_MATRIXENCODING }, 0, 0, FLAGS, "type" }, \ |
56 | { "DOWNMIX_INFO", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DOWNMIX_INFO }, 0, 0, FLAGS, "type" }, \ |
57 | { "REPLAYGAIN", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_REPLAYGAIN }, 0, 0, FLAGS, "type" }, \ |
58 | { "DISPLAYMATRIX", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DISPLAYMATRIX }, 0, 0, FLAGS, "type" }, \ |
59 | { "AFD", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_AFD }, 0, 0, FLAGS, "type" }, \ |
60 | { "MOTION_VECTORS", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_MOTION_VECTORS }, 0, 0, FLAGS, "type" }, \ |
61 | { "SKIP_SAMPLES", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_SKIP_SAMPLES }, 0, 0, FLAGS, "type" }, \ |
62 | { "AUDIO_SERVICE_TYPE", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_AUDIO_SERVICE_TYPE }, 0, 0, FLAGS, "type" }, \ |
63 | { "MASTERING_DISPLAY_METADATA", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_MASTERING_DISPLAY_METADATA }, 0, 0, FLAGS, "type" }, \ |
64 | { "GOP_TIMECODE", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_GOP_TIMECODE }, 0, 0, FLAGS, "type" }, \ |
65 | { NULL } \ |
66 | } |
67 | |
68 | static av_cold int init(AVFilterContext *ctx) |
69 | { |
70 | SideDataContext *s = ctx->priv; |
71 | |
72 | if (s->type == -1 && s->mode != SIDEDATA_DELETE) { |
73 | av_log(ctx, AV_LOG_ERROR, "Side data type must be set\n"); |
74 | return AVERROR(EINVAL); |
75 | } |
76 | |
77 | return 0; |
78 | } |
79 | |
80 | static int filter_frame(AVFilterLink *inlink, AVFrame *frame) |
81 | { |
82 | AVFilterContext *ctx = inlink->dst; |
83 | AVFilterLink *outlink = ctx->outputs[0]; |
84 | SideDataContext *s = ctx->priv; |
85 | AVFrameSideData *sd = NULL; |
86 | |
87 | if (s->type != -1) |
88 | sd = av_frame_get_side_data(frame, s->type); |
89 | |
90 | switch (s->mode) { |
91 | case SIDEDATA_SELECT: |
92 | if (sd) { |
93 | return ff_filter_frame(outlink, frame); |
94 | } |
95 | break; |
96 | case SIDEDATA_DELETE: |
97 | if (s->type == -1) { |
98 | while (frame->nb_side_data) |
99 | av_frame_remove_side_data(frame, frame->side_data[0]->type); |
100 | } else if (sd) { |
101 | av_frame_remove_side_data(frame, s->type); |
102 | } |
103 | return ff_filter_frame(outlink, frame); |
104 | break; |
105 | default: |
106 | av_assert0(0); |
107 | }; |
108 | |
109 | av_frame_free(&frame); |
110 | |
111 | return 0; |
112 | } |
113 | |
114 | #if CONFIG_ASIDEDATA_FILTER |
115 | |
116 | DEFINE_OPTIONS(asidedata, AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM); |
117 | AVFILTER_DEFINE_CLASS(asidedata); |
118 | |
119 | static const AVFilterPad ainputs[] = { |
120 | { |
121 | .name = "default", |
122 | .type = AVMEDIA_TYPE_AUDIO, |
123 | .filter_frame = filter_frame, |
124 | }, |
125 | { NULL } |
126 | }; |
127 | |
128 | static const AVFilterPad aoutputs[] = { |
129 | { |
130 | .name = "default", |
131 | .type = AVMEDIA_TYPE_AUDIO, |
132 | }, |
133 | { NULL } |
134 | }; |
135 | |
136 | AVFilter ff_af_asidedata = { |
137 | .name = "asidedata", |
138 | .description = NULL_IF_CONFIG_SMALL("Manipulate audio frame side data."), |
139 | .priv_size = sizeof(SideDataContext), |
140 | .priv_class = &asidedata_class, |
141 | .init = init, |
142 | .inputs = ainputs, |
143 | .outputs = aoutputs, |
144 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, |
145 | }; |
146 | #endif /* CONFIG_ASIDEDATA_FILTER */ |
147 | |
148 | #if CONFIG_SIDEDATA_FILTER |
149 | |
150 | DEFINE_OPTIONS(sidedata, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM); |
151 | AVFILTER_DEFINE_CLASS(sidedata); |
152 | |
153 | static const AVFilterPad inputs[] = { |
154 | { |
155 | .name = "default", |
156 | .type = AVMEDIA_TYPE_VIDEO, |
157 | .filter_frame = filter_frame, |
158 | }, |
159 | { NULL } |
160 | }; |
161 | |
162 | static const AVFilterPad outputs[] = { |
163 | { |
164 | .name = "default", |
165 | .type = AVMEDIA_TYPE_VIDEO, |
166 | }, |
167 | { NULL } |
168 | }; |
169 | |
170 | AVFilter ff_vf_sidedata = { |
171 | .name = "sidedata", |
172 | .description = NULL_IF_CONFIG_SMALL("Manipulate video frame side data."), |
173 | .priv_size = sizeof(SideDataContext), |
174 | .priv_class = &sidedata_class, |
175 | .init = init, |
176 | .inputs = inputs, |
177 | .outputs = outputs, |
178 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, |
179 | }; |
180 | #endif /* CONFIG_SIDEDATA_FILTER */ |
181 |