Line |
Branch |
Exec |
Source |
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 "config_components.h" |
25 |
|
|
|
26 |
|
|
#include "libavutil/avassert.h" |
27 |
|
|
#include "libavutil/internal.h" |
28 |
|
|
#include "libavutil/frame.h" |
29 |
|
|
#include "libavutil/opt.h" |
30 |
|
|
#include "audio.h" |
31 |
|
|
#include "avfilter.h" |
32 |
|
|
#include "filters.h" |
33 |
|
|
#include "video.h" |
34 |
|
|
|
35 |
|
|
enum SideDataMode { |
36 |
|
|
SIDEDATA_SELECT, |
37 |
|
|
SIDEDATA_DELETE, |
38 |
|
|
SIDEDATA_NB |
39 |
|
|
}; |
40 |
|
|
|
41 |
|
|
typedef struct SideDataContext { |
42 |
|
|
const AVClass *class; |
43 |
|
|
|
44 |
|
|
int mode; |
45 |
|
|
int type; // enum AVFrameSideDataType or -1 for delete side data mode |
46 |
|
|
} SideDataContext; |
47 |
|
|
|
48 |
|
|
#define OFFSET(x) offsetof(SideDataContext, x) |
49 |
|
|
#define DEFINE_OPTIONS(filt_name, FLAGS) \ |
50 |
|
|
static const AVOption filt_name##_options[] = { \ |
51 |
|
|
{ "mode", "set a mode of operation", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, SIDEDATA_NB-1, FLAGS, .unit = "mode" }, \ |
52 |
|
|
{ "select", "select frame", 0, AV_OPT_TYPE_CONST, {.i64 = SIDEDATA_SELECT }, 0, 0, FLAGS, .unit = "mode" }, \ |
53 |
|
|
{ "delete", "delete side data", 0, AV_OPT_TYPE_CONST, {.i64 = SIDEDATA_DELETE }, 0, 0, FLAGS, .unit = "mode" }, \ |
54 |
|
|
{ "type", "set side data type", OFFSET(type), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, INT_MAX, FLAGS, .unit = "type" }, \ |
55 |
|
|
{ "PANSCAN", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_PANSCAN }, 0, 0, FLAGS, .unit = "type" }, \ |
56 |
|
|
{ "A53_CC", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_A53_CC }, 0, 0, FLAGS, .unit = "type" }, \ |
57 |
|
|
{ "STEREO3D", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_STEREO3D }, 0, 0, FLAGS, .unit = "type" }, \ |
58 |
|
|
{ "MATRIXENCODING", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_MATRIXENCODING }, 0, 0, FLAGS, .unit = "type" }, \ |
59 |
|
|
{ "DOWNMIX_INFO", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DOWNMIX_INFO }, 0, 0, FLAGS, .unit = "type" }, \ |
60 |
|
|
{ "REPLAYGAIN", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_REPLAYGAIN }, 0, 0, FLAGS, .unit = "type" }, \ |
61 |
|
|
{ "DISPLAYMATRIX", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DISPLAYMATRIX }, 0, 0, FLAGS, .unit = "type" }, \ |
62 |
|
|
{ "AFD", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_AFD }, 0, 0, FLAGS, .unit = "type" }, \ |
63 |
|
|
{ "MOTION_VECTORS", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_MOTION_VECTORS }, 0, 0, FLAGS, .unit = "type" }, \ |
64 |
|
|
{ "SKIP_SAMPLES", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_SKIP_SAMPLES }, 0, 0, FLAGS, .unit = "type" }, \ |
65 |
|
|
{ "AUDIO_SERVICE_TYPE", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_AUDIO_SERVICE_TYPE }, 0, 0, FLAGS, .unit = "type" }, \ |
66 |
|
|
{ "MASTERING_DISPLAY_METADATA", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_MASTERING_DISPLAY_METADATA }, 0, 0, FLAGS, .unit = "type" }, \ |
67 |
|
|
{ "GOP_TIMECODE", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_GOP_TIMECODE }, 0, 0, FLAGS, .unit = "type" }, \ |
68 |
|
|
{ "SPHERICAL", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_SPHERICAL }, 0, 0, FLAGS, .unit = "type" }, \ |
69 |
|
|
{ "CONTENT_LIGHT_LEVEL", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_CONTENT_LIGHT_LEVEL }, 0, 0, FLAGS, .unit = "type" }, \ |
70 |
|
|
{ "ICC_PROFILE", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_ICC_PROFILE }, 0, 0, FLAGS, .unit = "type" }, \ |
71 |
|
|
{ "S12M_TIMECOD", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_S12M_TIMECODE }, 0, 0, FLAGS, .unit = "type" }, \ |
72 |
|
|
{ "DYNAMIC_HDR_PLUS", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DYNAMIC_HDR_PLUS }, 0, 0, FLAGS, .unit = "type" }, \ |
73 |
|
|
{ "REGIONS_OF_INTEREST", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_REGIONS_OF_INTEREST }, 0, 0, FLAGS, .unit = "type" }, \ |
74 |
|
|
{ "VIDEO_ENC_PARAMS", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_VIDEO_ENC_PARAMS }, 0, 0, FLAGS, .unit = "type" }, \ |
75 |
|
|
{ "SEI_UNREGISTERED", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_SEI_UNREGISTERED }, 0, 0, FLAGS, .unit = "type" }, \ |
76 |
|
|
{ "FILM_GRAIN_PARAMS", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_FILM_GRAIN_PARAMS }, 0, 0, FLAGS, .unit = "type" }, \ |
77 |
|
|
{ "DETECTION_BOUNDING_BOXES", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DETECTION_BBOXES }, 0, 0, FLAGS, .unit = "type" }, \ |
78 |
|
|
{ "DETECTION_BBOXES", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DETECTION_BBOXES }, 0, 0, FLAGS, .unit = "type" }, \ |
79 |
|
|
{ "DOVI_RPU_BUFFER", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DOVI_RPU_BUFFER }, 0, 0, FLAGS, .unit = "type" }, \ |
80 |
|
|
{ "DOVI_METADATA", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DOVI_METADATA }, 0, 0, FLAGS, .unit = "type" }, \ |
81 |
|
|
{ "DYNAMIC_HDR_VIVID", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DYNAMIC_HDR_VIVID }, 0, 0, FLAGS, .unit = "type" }, \ |
82 |
|
|
{ "AMBIENT_VIEWING_ENVIRONMENT","", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT}, 0, 0, FLAGS, .unit = "type" }, \ |
83 |
|
|
{ "VIDEO_HINT", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_VIDEO_HINT }, 0, 0, FLAGS, .unit = "type" }, \ |
84 |
|
|
{ NULL } \ |
85 |
|
|
} |
86 |
|
|
|
87 |
|
✗ |
static av_cold int init(AVFilterContext *ctx) |
88 |
|
|
{ |
89 |
|
✗ |
SideDataContext *s = ctx->priv; |
90 |
|
|
|
91 |
|
✗ |
if (s->type == -1 && s->mode != SIDEDATA_DELETE) { |
92 |
|
✗ |
av_log(ctx, AV_LOG_ERROR, "Side data type must be set\n"); |
93 |
|
✗ |
return AVERROR(EINVAL); |
94 |
|
|
} |
95 |
|
|
|
96 |
|
✗ |
return 0; |
97 |
|
|
} |
98 |
|
|
|
99 |
|
✗ |
static int filter_frame(AVFilterLink *inlink, AVFrame *frame) |
100 |
|
|
{ |
101 |
|
✗ |
AVFilterContext *ctx = inlink->dst; |
102 |
|
✗ |
AVFilterLink *outlink = ctx->outputs[0]; |
103 |
|
✗ |
SideDataContext *s = ctx->priv; |
104 |
|
✗ |
AVFrameSideData *sd = NULL; |
105 |
|
|
|
106 |
|
✗ |
if (s->type != -1) |
107 |
|
✗ |
sd = av_frame_get_side_data(frame, s->type); |
108 |
|
|
|
109 |
|
✗ |
switch (s->mode) { |
110 |
|
✗ |
case SIDEDATA_SELECT: |
111 |
|
✗ |
if (sd) { |
112 |
|
✗ |
return ff_filter_frame(outlink, frame); |
113 |
|
|
} |
114 |
|
✗ |
break; |
115 |
|
✗ |
case SIDEDATA_DELETE: |
116 |
|
✗ |
if (s->type == -1) { |
117 |
|
✗ |
while (frame->nb_side_data) |
118 |
|
✗ |
av_frame_remove_side_data(frame, frame->side_data[0]->type); |
119 |
|
✗ |
} else if (sd) { |
120 |
|
✗ |
av_frame_remove_side_data(frame, s->type); |
121 |
|
|
} |
122 |
|
✗ |
return ff_filter_frame(outlink, frame); |
123 |
|
|
break; |
124 |
|
✗ |
default: |
125 |
|
✗ |
av_assert0(0); |
126 |
|
|
}; |
127 |
|
|
|
128 |
|
✗ |
av_frame_free(&frame); |
129 |
|
|
|
130 |
|
✗ |
return 0; |
131 |
|
|
} |
132 |
|
|
|
133 |
|
|
#if CONFIG_ASIDEDATA_FILTER |
134 |
|
|
|
135 |
|
|
DEFINE_OPTIONS(asidedata, AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM); |
136 |
|
|
AVFILTER_DEFINE_CLASS(asidedata); |
137 |
|
|
|
138 |
|
|
static const AVFilterPad ainputs[] = { |
139 |
|
|
{ |
140 |
|
|
.name = "default", |
141 |
|
|
.type = AVMEDIA_TYPE_AUDIO, |
142 |
|
|
.filter_frame = filter_frame, |
143 |
|
|
}, |
144 |
|
|
}; |
145 |
|
|
|
146 |
|
|
const AVFilter ff_af_asidedata = { |
147 |
|
|
.name = "asidedata", |
148 |
|
|
.description = NULL_IF_CONFIG_SMALL("Manipulate audio frame side data."), |
149 |
|
|
.priv_size = sizeof(SideDataContext), |
150 |
|
|
.priv_class = &asidedata_class, |
151 |
|
|
.init = init, |
152 |
|
|
FILTER_INPUTS(ainputs), |
153 |
|
|
FILTER_OUTPUTS(ff_audio_default_filterpad), |
154 |
|
|
.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | |
155 |
|
|
AVFILTER_FLAG_METADATA_ONLY, |
156 |
|
|
}; |
157 |
|
|
#endif /* CONFIG_ASIDEDATA_FILTER */ |
158 |
|
|
|
159 |
|
|
#if CONFIG_SIDEDATA_FILTER |
160 |
|
|
|
161 |
|
|
DEFINE_OPTIONS(sidedata, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM); |
162 |
|
|
AVFILTER_DEFINE_CLASS(sidedata); |
163 |
|
|
|
164 |
|
|
static const AVFilterPad inputs[] = { |
165 |
|
|
{ |
166 |
|
|
.name = "default", |
167 |
|
|
.type = AVMEDIA_TYPE_VIDEO, |
168 |
|
|
.filter_frame = filter_frame, |
169 |
|
|
}, |
170 |
|
|
}; |
171 |
|
|
|
172 |
|
|
const AVFilter ff_vf_sidedata = { |
173 |
|
|
.name = "sidedata", |
174 |
|
|
.description = NULL_IF_CONFIG_SMALL("Manipulate video frame side data."), |
175 |
|
|
.priv_size = sizeof(SideDataContext), |
176 |
|
|
.priv_class = &sidedata_class, |
177 |
|
|
.init = init, |
178 |
|
|
FILTER_INPUTS(inputs), |
179 |
|
|
FILTER_OUTPUTS(ff_video_default_filterpad), |
180 |
|
|
.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | |
181 |
|
|
AVFILTER_FLAG_METADATA_ONLY, |
182 |
|
|
}; |
183 |
|
|
#endif /* CONFIG_SIDEDATA_FILTER */ |
184 |
|
|
|