]> git.sesse.net Git - ffmpeg/blob - libavcodec/filter_units_bsf.c
avformat/avio: Add Metacube support
[ffmpeg] / libavcodec / filter_units_bsf.c
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 #include <stdlib.h>
20
21 #include "libavutil/common.h"
22 #include "libavutil/opt.h"
23
24 #include "bsf.h"
25 #include "bsf_internal.h"
26 #include "cbs.h"
27
28
29 typedef struct FilterUnitsContext {
30     const AVClass *class;
31
32     CodedBitstreamContext *cbc;
33     CodedBitstreamFragment fragment;
34
35     const char *pass_types;
36     const char *remove_types;
37
38     enum {
39         NOOP,
40         PASS,
41         REMOVE,
42     } mode;
43     CodedBitstreamUnitType *type_list;
44     int nb_types;
45 } FilterUnitsContext;
46
47
48 static int filter_units_make_type_list(const char *list_string,
49                                        CodedBitstreamUnitType **type_list,
50                                        int *nb_types)
51 {
52     CodedBitstreamUnitType *list = NULL;
53     int pass, count;
54
55     for (pass = 1; pass <= 2; pass++) {
56         long value, range_start, range_end;
57         const char *str;
58         char *value_end;
59
60         count = 0;
61         for (str = list_string; *str;) {
62             value = strtol(str, &value_end, 0);
63             if (str == value_end)
64                 goto invalid;
65             str = (const char *)value_end;
66             if (*str == '-') {
67                 ++str;
68                 range_start = value;
69                 range_end   = strtol(str, &value_end, 0);
70                 if (str == value_end)
71                     goto invalid;
72
73                 for (value = range_start; value < range_end; value++) {
74                     if (pass == 2)
75                         list[count] = value;
76                     ++count;
77                 }
78             } else {
79                 if (pass == 2)
80                     list[count] = value;
81                 ++count;
82             }
83             if (*str == '|')
84                 ++str;
85         }
86         if (pass == 1) {
87             list = av_malloc_array(count, sizeof(*list));
88             if (!list)
89                 return AVERROR(ENOMEM);
90         }
91     }
92
93     *type_list = list;
94     *nb_types  = count;
95     return 0;
96
97 invalid:
98     av_freep(&list);
99     return AVERROR(EINVAL);
100 }
101
102 static int filter_units_filter(AVBSFContext *bsf, AVPacket *pkt)
103 {
104     FilterUnitsContext      *ctx = bsf->priv_data;
105     CodedBitstreamFragment *frag = &ctx->fragment;
106     int err, i, j;
107
108     err = ff_bsf_get_packet_ref(bsf, pkt);
109     if (err < 0)
110         return err;
111
112     if (ctx->mode == NOOP)
113         return 0;
114
115     err = ff_cbs_read_packet(ctx->cbc, frag, pkt);
116     if (err < 0) {
117         av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n");
118         goto fail;
119     }
120
121     for (i = frag->nb_units - 1; i >= 0; i--) {
122         for (j = 0; j < ctx->nb_types; j++) {
123             if (frag->units[i].type == ctx->type_list[j])
124                 break;
125         }
126         if (ctx->mode == REMOVE ? j <  ctx->nb_types
127                                 : j >= ctx->nb_types)
128             ff_cbs_delete_unit(frag, i);
129     }
130
131     if (frag->nb_units == 0) {
132         // Don't return packets with nothing in them.
133         err = AVERROR(EAGAIN);
134         goto fail;
135     }
136
137     err = ff_cbs_write_packet(ctx->cbc, pkt, frag);
138     if (err < 0) {
139         av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n");
140         goto fail;
141     }
142
143 fail:
144     if (err < 0)
145         av_packet_unref(pkt);
146     ff_cbs_fragment_reset(frag);
147
148     return err;
149 }
150
151 static int filter_units_init(AVBSFContext *bsf)
152 {
153     FilterUnitsContext *ctx = bsf->priv_data;
154     int err;
155
156     if (ctx->pass_types && ctx->remove_types) {
157         av_log(bsf, AV_LOG_ERROR, "Exactly one of pass_types or "
158                "remove_types is required.\n");
159         return AVERROR(EINVAL);
160     }
161
162     if (ctx->pass_types) {
163         ctx->mode = PASS;
164         err = filter_units_make_type_list(ctx->pass_types,
165                                           &ctx->type_list, &ctx->nb_types);
166         if (err < 0) {
167             av_log(bsf, AV_LOG_ERROR, "Failed to parse pass_types.\n");
168             return err;
169         }
170     } else if (ctx->remove_types) {
171         ctx->mode = REMOVE;
172         err = filter_units_make_type_list(ctx->remove_types,
173                                           &ctx->type_list, &ctx->nb_types);
174         if (err < 0) {
175             av_log(bsf, AV_LOG_ERROR, "Failed to parse remove_types.\n");
176             return err;
177         }
178     } else {
179         return 0;
180     }
181
182     err = ff_cbs_init(&ctx->cbc, bsf->par_in->codec_id, bsf);
183     if (err < 0)
184         return err;
185
186     // Don't actually decompose anything, we only want the unit data.
187     ctx->cbc->decompose_unit_types    = ctx->type_list;
188     ctx->cbc->nb_decompose_unit_types = 0;
189
190     if (bsf->par_in->extradata) {
191         CodedBitstreamFragment *frag = &ctx->fragment;
192
193         err = ff_cbs_read_extradata(ctx->cbc, frag, bsf->par_in);
194         if (err < 0) {
195             av_log(bsf, AV_LOG_ERROR, "Failed to read extradata.\n");
196         } else {
197             err = ff_cbs_write_extradata(ctx->cbc, bsf->par_out, frag);
198             if (err < 0)
199                 av_log(bsf, AV_LOG_ERROR, "Failed to write extradata.\n");
200         }
201
202         ff_cbs_fragment_reset(frag);
203     }
204
205     return err;
206 }
207
208 static void filter_units_close(AVBSFContext *bsf)
209 {
210     FilterUnitsContext *ctx = bsf->priv_data;
211
212     av_freep(&ctx->type_list);
213
214     ff_cbs_fragment_free(&ctx->fragment);
215     ff_cbs_close(&ctx->cbc);
216 }
217
218 #define OFFSET(x) offsetof(FilterUnitsContext, x)
219 #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM)
220 static const AVOption filter_units_options[] = {
221     { "pass_types",   "List of unit types to pass through the filter.",
222         OFFSET(pass_types),   AV_OPT_TYPE_STRING,
223         { .str = NULL }, .flags = FLAGS },
224     { "remove_types", "List of unit types to remove in the filter.",
225         OFFSET(remove_types), AV_OPT_TYPE_STRING,
226         { .str = NULL }, .flags = FLAGS },
227
228     { NULL }
229 };
230
231 static const AVClass filter_units_class = {
232     .class_name = "filter_units",
233     .item_name  = av_default_item_name,
234     .option     = filter_units_options,
235     .version    = LIBAVUTIL_VERSION_INT,
236 };
237
238 const AVBitStreamFilter ff_filter_units_bsf = {
239     .name           = "filter_units",
240     .priv_data_size = sizeof(FilterUnitsContext),
241     .priv_class     = &filter_units_class,
242     .init           = &filter_units_init,
243     .close          = &filter_units_close,
244     .filter         = &filter_units_filter,
245     .codec_ids      = ff_cbs_all_codec_ids,
246 };