summaryrefslogtreecommitdiff
path: root/libavfilter/formats.h
blob: 22224dce2d77af127483f1828d43b4888accda9c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
/*
 * 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
 */

#ifndef AVFILTER_FORMATS_H
#define AVFILTER_FORMATS_H

#include "avfilter.h"

/**
 * A list of supported formats for one end of a filter link. This is used
 * during the format negotiation process to try to pick the best format to
 * use to minimize the number of necessary conversions. Each filter gives a
 * list of the formats supported by each input and output pad. The list
 * given for each pad need not be distinct - they may be references to the
 * same list of formats, as is often the case when a filter supports multiple
 * formats, but will always output the same format as it is given in input.
 *
 * In this way, a list of possible input formats and a list of possible
 * output formats are associated with each link. When a set of formats is
 * negotiated over a link, the input and output lists are merged to form a
 * new list containing only the common elements of each list. In the case
 * that there were no common elements, a format conversion is necessary.
 * Otherwise, the lists are merged, and all other links which reference
 * either of the format lists involved in the merge are also affected.
 *
 * For example, consider the filter chain:
 * filter (a) --> (b) filter (b) --> (c) filter
 *
 * where the letters in parenthesis indicate a list of formats supported on
 * the input or output of the link. Suppose the lists are as follows:
 * (a) = {A, B}
 * (b) = {A, B, C}
 * (c) = {B, C}
 *
 * First, the first link's lists are merged, yielding:
 * filter (a) --> (a) filter (a) --> (c) filter
 *
 * Notice that format list (b) now refers to the same list as filter list (a).
 * Next, the lists for the second link are merged, yielding:
 * filter (a) --> (a) filter (a) --> (a) filter
 *
 * where (a) = {B}.
 *
 * Unfortunately, when the format lists at the two ends of a link are merged,
 * we must ensure that all links which reference either pre-merge format list
 * get updated as well. Therefore, we have the format list structure store a
 * pointer to each of the pointers to itself.
 */
struct AVFilterFormats {
    unsigned nb_formats;        ///< number of formats
    int *formats;               ///< list of media formats

    unsigned refcount;          ///< number of references to this list
    struct AVFilterFormats ***refs; ///< references to this list
};

/**
 * A list of supported channel layouts.
 *
 * The list works the same as AVFilterFormats, except for the following
 * differences:
 * - A list with all_layouts = 1 means all channel layouts with a known
 *   disposition; nb_channel_layouts must then be 0.
 * - A list with all_counts = 1 means all channel counts, with a known or
 *   unknown disposition; nb_channel_layouts must then be 0 and all_layouts 1.
 * - The list must not contain a layout with a known disposition and a
 *   channel count with unknown disposition with the same number of channels
 *   (e.g. AV_CH_LAYOUT_STEREO and FF_COUNT2LAYOUT(2).
 */
struct AVFilterChannelLayouts {
    AVChannelLayout *channel_layouts; ///< list of channel layouts
    int    nb_channel_layouts;  ///< number of channel layouts
    char all_layouts;           ///< accept any known channel layout
    char all_counts;            ///< accept any channel layout or count

    unsigned refcount;          ///< number of references to this list
    struct AVFilterChannelLayouts ***refs; ///< references to this list
};

/**
 * Encode a channel count as a channel layout.
 * FF_COUNT2LAYOUT(c) means any channel layout with c channels, with a known
 * or unknown disposition.
 * The result is only valid inside AVFilterChannelLayouts and immediately
 * related functions.
 */
#define FF_COUNT2LAYOUT(c) ((AVChannelLayout) { .order = AV_CHANNEL_ORDER_UNSPEC, .nb_channels = c })

/**
 * Decode a channel count encoded as a channel layout.
 * Return 0 if the channel layout was a real one.
 */
#define FF_LAYOUT2COUNT(l) (((l)->order == AV_CHANNEL_ORDER_UNSPEC) ? \
                            (l)->nb_channels : 0)

#define KNOWN(l) (!FF_LAYOUT2COUNT(l)) /* for readability */

/**
 * Construct an empty AVFilterChannelLayouts/AVFilterFormats struct --
 * representing any channel layout (with known disposition)/sample rate.
 */
av_warn_unused_result
AVFilterChannelLayouts *ff_all_channel_layouts(void);

av_warn_unused_result
AVFilterFormats *ff_all_samplerates(void);

/**
 * Construct an AVFilterChannelLayouts coding for any channel layout, with
 * known or unknown disposition.
 */
av_warn_unused_result
AVFilterChannelLayouts *ff_all_channel_counts(void);

av_warn_unused_result
AVFilterChannelLayouts *ff_make_channel_layout_list(const AVChannelLayout *fmts);

/**
 * Helpers for query_formats() which set all free audio links to the same list
 * of channel layouts/sample rates. If there are no links hooked to this list,
 * the list is freed.
 */
av_warn_unused_result
int ff_set_common_channel_layouts(AVFilterContext *ctx,
                                  AVFilterChannelLayouts *layouts);
/**
 * Equivalent to ff_set_common_channel_layouts(ctx, ff_make_channel_layout_list(fmts))
 */
av_warn_unused_result
int ff_set_common_channel_layouts_from_list(AVFilterContext *ctx,
                                            const AVChannelLayout *fmts);
/**
 * Equivalent to ff_set_common_channel_layouts(ctx, ff_all_channel_counts())
 */
av_warn_unused_result
int ff_set_common_all_channel_counts(AVFilterContext *ctx);

av_warn_unused_result
int ff_set_common_samplerates(AVFilterContext *ctx,
                              AVFilterFormats *samplerates);
/**
 * Equivalent to ff_set_common_samplerates(ctx, ff_make_format_list(samplerates))
 */
av_warn_unused_result
int ff_set_common_samplerates_from_list(AVFilterContext *ctx,
                                        const int *samplerates);
/**
 * Equivalent to ff_set_common_samplerates(ctx, ff_all_samplerates())
 */
av_warn_unused_result
int ff_set_common_all_samplerates(AVFilterContext *ctx);

/**
 * A helper for query_formats() which sets all links to the same list of
 * formats. If there are no links hooked to this filter, the list of formats is
 * freed.
 */
av_warn_unused_result
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats);

/**
 * Equivalent to ff_set_common_formats(ctx, ff_make_format_list(fmts))
 */
av_warn_unused_result
int ff_set_common_formats_from_list(AVFilterContext *ctx, const int *fmts);

av_warn_unused_result
int ff_add_channel_layout(AVFilterChannelLayouts **l,
                          const AVChannelLayout *channel_layout);

/**
 * Add *ref as a new reference to f.
 */
av_warn_unused_result
int ff_channel_layouts_ref(AVFilterChannelLayouts *f,
                           AVFilterChannelLayouts **ref);

/**
 * Remove a reference to a channel layouts list.
 */
void ff_channel_layouts_unref(AVFilterChannelLayouts **ref);

void ff_channel_layouts_changeref(AVFilterChannelLayouts **oldref,
                                  AVFilterChannelLayouts **newref);

av_warn_unused_result
int ff_default_query_formats(AVFilterContext *ctx);

/**
 * Create a list of supported formats. This is intended for use in
 * AVFilter->query_formats().
 *
 * @param fmts list of media formats, terminated by -1
 * @return the format list, with no existing references
 */
av_warn_unused_result
AVFilterFormats *ff_make_format_list(const int *fmts);

/**
 * Equivalent to ff_make_format_list({const int[]}{ fmt, -1 })
 */
av_warn_unused_result
AVFilterFormats *ff_make_formats_list_singleton(int fmt);

/**
 * Add fmt to the list of media formats contained in *avff.
 * If *avff is NULL the function allocates the filter formats struct
 * and puts its pointer in *avff.
 *
 * @return a non negative value in case of success, or a negative
 * value corresponding to an AVERROR code in case of error
 */
av_warn_unused_result
int ff_add_format(AVFilterFormats **avff, int64_t fmt);

/**
 * Return a list of all formats supported by FFmpeg for the given media type.
 */
av_warn_unused_result
AVFilterFormats *ff_all_formats(enum AVMediaType type);

/**
 * Construct a formats list containing all pixel formats with certain
 * properties
 */
av_warn_unused_result
AVFilterFormats *ff_formats_pixdesc_filter(unsigned want, unsigned rej);

//* format is software, non-planar with sub-sampling
#define FF_PIX_FMT_FLAG_SW_FLAT_SUB (1 << 24)

/**
 * Construct a formats list containing all planar sample formats.
 */
av_warn_unused_result
AVFilterFormats *ff_planar_sample_fmts(void);

/**
 * Add *ref as a new reference to formats.
 * That is the pointers will point like in the ascii art below:
 *   ________
 *  |formats |<--------.
 *  |  ____  |     ____|___________________
 *  | |refs| |    |  __|_
 *  | |* * | |    | |  | |  AVFilterLink
 *  | |* *--------->|*ref|
 *  | |____| |    | |____|
 *  |________|    |________________________
 */
av_warn_unused_result
int ff_formats_ref(AVFilterFormats *formats, AVFilterFormats **ref);

/**
 * If *ref is non-NULL, remove *ref as a reference to the format list
 * it currently points to, deallocates that list if this was the last
 * reference, and sets *ref to NULL.
 *
 *         Before                                 After
 *   ________                               ________         NULL
 *  |formats |<--------.                   |formats |         ^
 *  |  ____  |     ____|________________   |  ____  |     ____|________________
 *  | |refs| |    |  __|_                  | |refs| |    |  __|_
 *  | |* * | |    | |  | |  AVFilterLink   | |* * | |    | |  | |  AVFilterLink
 *  | |* *--------->|*ref|                 | |*   | |    | |*ref|
 *  | |____| |    | |____|                 | |____| |    | |____|
 *  |________|    |_____________________   |________|    |_____________________
 */
void ff_formats_unref(AVFilterFormats **ref);

/**
 *         Before                                 After
 *   ________                         ________
 *  |formats |<---------.            |formats |<---------.
 *  |  ____  |       ___|___         |  ____  |       ___|___
 *  | |refs| |      |   |   |        | |refs| |      |   |   |   NULL
 *  | |* *--------->|*oldref|        | |* *--------->|*newref|     ^
 *  | |* * | |      |_______|        | |* * | |      |_______|  ___|___
 *  | |____| |                       | |____| |                |   |   |
 *  |________|                       |________|                |*oldref|
 *                                                             |_______|
 */
void ff_formats_changeref(AVFilterFormats **oldref, AVFilterFormats **newref);

/**
 * Check that fmts is a valid pixel formats list.
 *
 * In particular, check for duplicates.
 */
int ff_formats_check_pixel_formats(void *log, const AVFilterFormats *fmts);

/**
 * Check that fmts is a valid sample formats list.
 *
 * In particular, check for duplicates.
 */
int ff_formats_check_sample_formats(void *log, const AVFilterFormats *fmts);

/**
 * Check that fmts is a valid sample rates list.
 *
 * In particular, check for duplicates.
 */
int ff_formats_check_sample_rates(void *log, const AVFilterFormats *fmts);

/**
 * Check that fmts is a valid channel layouts list.
 *
 * In particular, check for duplicates.
 */
int ff_formats_check_channel_layouts(void *log, const AVFilterChannelLayouts *fmts);

typedef struct AVFilterFormatMerger {
    unsigned offset;
    int (*merge)(void *a, void *b);
    int (*can_merge)(const void *a, const void *b);
} AVFilterFormatsMerger;

/**
 * Callbacks and properties to describe the steps of a format negotiation.
 *
 * The steps are:
 *
 * 1. query_formats(): call the callbacks on all filter to set lists of
 *                     supported formats.
 *                     When links on a filter must eventually have the same
 *                     format, the lists of supported formats are the same
 *                     object in memory.
 *                     See:
 *                     http://www.normalesup.org/~george/articles/format_negotiation_in_libavfilter/#12
 *
 *
 * 2. query_formats(): merge lists of supported formats or insert automatic
 *                     conversion filters.
 *                     Compute the intersection of the lists of supported
 *                     formats on the ends of links. If it succeeds, replace
 *                     both objects with the intersection everywhere they
 *                     are referenced.
 *                     If the intersection is empty, insert an automatic
 *                     conversion filter.
 *                     If several formats are negotiated at once (format,
 *                     rate, layout), only merge if all three can be, since
 *                     the conversion filter can convert all three at once.
 *                     This process goes on as long as progress is made.
 *                     See:
 *                     http://www.normalesup.org/~george/articles/format_negotiation_in_libavfilter/#14
 *                     http://www.normalesup.org/~george/articles/format_negotiation_in_libavfilter/#29
 *
 * 3. reduce_formats(): try to reduce format conversion within filters.
 *                      For each link where there is only one supported
 *                      formats on output, for each output of the connected
 *                      filter, if the media type is the same and said
 *                      format is supported, keep only this one.
 *                      This process goes on as long as progress is made.
 *                      Rationale: conversion filters will set a large list
 *                      of supported formats on outputs but users will
 *                      expect the output to be as close as possible as the
 *                      input (examples: scale without changing the pixel
 *                      format, resample without changint the layout).
 *                      FIXME: this can probably be done by merging the
 *                      input and output lists instead of re-implementing
 *                      the logic.
 *
 * 4. swap_sample_fmts():
 *    swap_samplerates():
 *    swap_channel_layouts(): For each filter with an input with only one
 *                            supported format, when outputs have several
 *                            supported formats, put the best one with
 *                            reference to the input at the beginning of the
 *                            list, to prepare it for being picked up by
 *                            pick_formats().
 *                            The best format is the one that is most
 *                            similar to the input while not losing too much
 *                            information.
 *                            This process need to run only once.
 *                            FIXME: reduce_formats() operates on all inputs
 *                            with a single format, swap_*() operates on the
 *                            first one only: check if the difference makes
 *                            sense.
 *                            TODO: the swapping done for one filter can
 *                            override the swapping done for another filter
 *                            connected to the same list of formats, maybe
 *                            it would be better to compute a total score
 *                            for all connected filters and use the score to
 *                            pick the format instead of just swapping.
 *                            TODO: make the similarity logic available as
 *                            public functions in libavutil.
 *
 * 5. pick_formats(): Choose one format from the lists of supported formats,
 *                    use it for the link and reduce the list to a single
 *                    element to force other filters connected to the same
 *                    list to use it.
 *                    First process all links where there is a single format
 *                    and the output links of all filters with an input,
 *                    trying to preserve similarity between input and
 *                    outputs.
 *                    Repeat as long as process is made.
 *                    Then do a final run for the remaining filters.
 *                    FIXME: the similarity logic (the ref argument to
 *                    pick_format()) added in FFmpeg duplicates and
 *                    overrides the swapping logic added in libav. Better
 *                    merge them into a score system.
 */
typedef struct AVFilterNegotiation {
    unsigned nb_mergers;
    const AVFilterFormatsMerger *mergers;
    const char *conversion_filter;
    unsigned conversion_opts_offset;
} AVFilterNegotiation;

const AVFilterNegotiation *ff_filter_get_negotiation(AVFilterLink *link);

#endif /* AVFILTER_FORMATS_H */