1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-12-07 11:13:41 +02:00
FFmpeg/libavfilter/formats.c

969 lines
36 KiB
C
Raw Normal View History

/*
* Filter layer - format negotiation
* Copyright (c) 2007 Bobby Bingham
*
* 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
*/
#include "libavutil/avassert.h"
#include "libavutil/channel_layout.h"
#include "libavutil/common.h"
#include "libavutil/eval.h"
#include "libavutil/pixdesc.h"
#include "avfilter.h"
#include "internal.h"
#include "formats.h"
/**
* Add all refs from a to ret and destroy a.
*/
#define MERGE_REF(ret, a, fmts, type, fail_statement) \
do { \
type ***tmp; \
int i; \
\
if (!(tmp = av_realloc_array(ret->refs, ret->refcount + a->refcount, \
sizeof(*tmp)))) \
{ fail_statement } \
ret->refs = tmp; \
\
for (i = 0; i < a->refcount; i ++) { \
ret->refs[ret->refcount] = a->refs[i]; \
*ret->refs[ret->refcount++] = ret; \
} \
\
av_freep(&a->refs); \
av_freep(&a->fmts); \
av_freep(&a); \
} while (0)
/**
* Add all formats common to a and b to a, add b's refs to a and destroy b.
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
* If check is set, nothing is modified and it is only checked whether
* the formats are compatible.
* If empty_allowed is set and one of a,b->nb is zero, the lists are
* merged; otherwise, 0 (for nonmergeability) is returned.
*/
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
#define MERGE_FORMATS(a, b, fmts, nb, type, check, empty_allowed) \
do { \
int i, j, k = 0, skip = 0; \
\
if (empty_allowed) { \
if (!a->nb || !b->nb) { \
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
if (check) \
return 1; \
if (!a->nb) \
FFSWAP(type *, a, b); \
skip = 1; \
} \
} \
if (!skip) { \
for (i = 0; i < a->nb; i++) \
for (j = 0; j < b->nb; j++) \
if (a->fmts[i] == b->fmts[j]) { \
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
if (check) \
return 1; \
a->fmts[k++] = a->fmts[i]; \
break; \
} \
/* Check that there was at least one common format. \
* Notice that both a and b are unchanged if not. */ \
if (!k) \
return 0; \
av_assert2(!check); \
a->nb = k; \
} \
\
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
MERGE_REF(a, b, fmts, type, return AVERROR(ENOMEM);); \
} while (0)
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
static int merge_formats_internal(AVFilterFormats *a, AVFilterFormats *b,
enum AVMediaType type, int check)
{
int i, j;
int alpha1=0, alpha2=0;
int chroma1=0, chroma2=0;
av_assert2(check || (a->refcount && b->refcount));
if (a == b)
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
return 1;
/* Do not lose chroma or alpha in merging.
It happens if both lists have formats with chroma (resp. alpha), but
the only formats in common do not have it (e.g. YUV+gray vs.
RGB+gray): in that case, the merging would select the gray format,
possibly causing a lossy conversion elsewhere in the graph.
To avoid that, pretend that there are no common formats to force the
insertion of a conversion filter. */
if (type == AVMEDIA_TYPE_VIDEO)
for (i = 0; i < a->nb_formats; i++) {
const AVPixFmtDescriptor *const adesc = av_pix_fmt_desc_get(a->formats[i]);
for (j = 0; j < b->nb_formats; j++) {
const AVPixFmtDescriptor *bdesc = av_pix_fmt_desc_get(b->formats[j]);
alpha2 |= adesc->flags & bdesc->flags & AV_PIX_FMT_FLAG_ALPHA;
chroma2|= adesc->nb_components > 1 && bdesc->nb_components > 1;
if (a->formats[i] == b->formats[j]) {
alpha1 |= adesc->flags & AV_PIX_FMT_FLAG_ALPHA;
chroma1|= adesc->nb_components > 1;
}
}
}
// If chroma or alpha can be lost through merging then do not merge
if (alpha2 > alpha1 || chroma2 > chroma1)
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
return 0;
MERGE_FORMATS(a, b, formats, nb_formats, AVFilterFormats, check, 0);
return 1;
}
/**
* Check the formats lists for compatibility for merging without actually
* merging.
*
* @return 1 if they are compatible, 0 if not.
*/
static int can_merge_pix_fmts(const void *a, const void *b)
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
{
return merge_formats_internal((AVFilterFormats *)a,
(AVFilterFormats *)b, AVMEDIA_TYPE_VIDEO, 1);
}
/**
* Merge the formats lists if they are compatible and update all the
* references of a and b to point to the combined list and free the old
* lists as needed. The combined list usually contains the intersection of
* the lists of a and b.
*
* Both a and b must have owners (i.e. refcount > 0) for these functions.
*
* @return 1 if merging succeeded, 0 if a and b are incompatible
* and negative AVERROR code on failure.
* a and b are unmodified if 0 is returned.
*/
static int merge_pix_fmts(void *a, void *b)
{
return merge_formats_internal(a, b, AVMEDIA_TYPE_VIDEO, 0);
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
}
/**
* See can_merge_pix_fmts().
*/
static int can_merge_sample_fmts(const void *a, const void *b)
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
{
return merge_formats_internal((AVFilterFormats *)a,
(AVFilterFormats *)b, AVMEDIA_TYPE_AUDIO, 1);
}
/**
* See merge_pix_fmts().
*/
static int merge_sample_fmts(void *a, void *b)
{
return merge_formats_internal(a, b, AVMEDIA_TYPE_AUDIO, 0);
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
}
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
static int merge_samplerates_internal(AVFilterFormats *a,
AVFilterFormats *b, int check)
{
av_assert2(check || (a->refcount && b->refcount));
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
if (a == b) return 1;
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
MERGE_FORMATS(a, b, formats, nb_formats, AVFilterFormats, check, 1);
return 1;
}
/**
* See can_merge_pix_fmts().
*/
static int can_merge_samplerates(const void *a, const void *b)
{
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
return merge_samplerates_internal((AVFilterFormats *)a, (AVFilterFormats *)b, 1);
}
/**
* See merge_pix_fmts().
*/
static int merge_samplerates(void *a, void *b)
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
{
return merge_samplerates_internal(a, b, 0);
}
/**
* See merge_pix_fmts().
*/
static int merge_channel_layouts_internal(AVFilterChannelLayouts *a,
AVFilterChannelLayouts *b, int check)
{
AVChannelLayout *channel_layouts = NULL;
unsigned a_all = a->all_layouts + a->all_counts;
unsigned b_all = b->all_layouts + b->all_counts;
int ret_max, ret_nb = 0, i, j, round;
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
av_assert2(a->refcount && b->refcount);
if (a == b) return 1;
/* Put the most generic set in a, to avoid doing everything twice */
if (a_all < b_all) {
FFSWAP(AVFilterChannelLayouts *, a, b);
FFSWAP(unsigned, a_all, b_all);
}
if (a_all) {
if (a_all == 1 && !b_all) {
/* keep only known layouts in b; works also for b_all = 1 */
for (i = j = 0; i < b->nb_channel_layouts; i++)
if (KNOWN(&b->channel_layouts[i]) && i != j++) {
if (check)
return 1;
av_channel_layout_copy(&b->channel_layouts[j], &b->channel_layouts[i]);
}
/* Not optimal: the unknown layouts of b may become known after
another merge. */
if (!j)
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
return 0;
b->nb_channel_layouts = j;
}
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
MERGE_REF(b, a, channel_layouts, AVFilterChannelLayouts, return AVERROR(ENOMEM););
return 1;
}
ret_max = a->nb_channel_layouts + b->nb_channel_layouts;
if (!check && !(channel_layouts = av_calloc(ret_max, sizeof(*channel_layouts))))
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
return AVERROR(ENOMEM);
/* a[known] intersect b[known] */
for (i = 0; i < a->nb_channel_layouts; i++) {
if (!KNOWN(&a->channel_layouts[i]))
continue;
for (j = 0; j < b->nb_channel_layouts; j++) {
if (!av_channel_layout_compare(&a->channel_layouts[i], &b->channel_layouts[j])) {
if (check)
return 1;
av_channel_layout_copy(&channel_layouts[ret_nb++], &a->channel_layouts[i]);
av_channel_layout_uninit(&a->channel_layouts[i]);
av_channel_layout_uninit(&b->channel_layouts[j]);
avfilter/formats: Fix heap-buffer overflow when merging channel layouts The channel layouts accepted by ff_merge_channel_layouts() are of two types: Ordinary channel layouts and generic channel layouts. These are layouts that match all layouts with a certain number of channels. Therefore parsing these channel layouts is not done in one go; instead first the intersection of the ordinary layouts of the first input list of channel layouts with the ordinary layouts of the second list is determined, then the intersection of the ordinary layouts of the first one and the generic layouts of the second one etc. In order to mark the ordinary channel layouts that have already been matched as used they are zeroed. The inner loop that does this is as follows: for (j = 0; j < b->nb_channel_layouts; j++) { if (a->channel_layouts[i] == b->channel_layouts[j]) { ret->channel_layouts[ret_nb++] = a->channel_layouts[i]; a->channel_layouts[i] = b->channel_layouts[j] = 0; } } (Here ret->channel_layouts is the array containing the intersection of the two input arrays.) Yet the problem with this code is that after a match has been found, the loop continues the search with the new value a->channel_layouts[i]. The intention of zeroing these elements was to make sure that elements already paired at this stage are ignored later. And while they are indeed ignored when pairing ordinary and generic channel layouts later, it has the exact opposite effect when pairing ordinary channel layouts. To see this consider the channel layouts A B C D E and E D C B A. In the first round, A and A will be paired and added to ret->channel_layouts. In the second round, the input arrays are 0 B C D E and E D C B 0. At first B and B will be matched and zeroed, but after doing so matching continues, but this time it will search for 0, which will match with the last entry of the second array. ret->channel_layouts now contains A B 0. In the third round, C 0 0 will be added to ret->channel_layouts etc. This gives a quadratic amount of elements, yet the amount of elements allocated for said array is only the sum of the sizes of a and b. This issue can e.g. be reproduced by ffmpeg -f lavfi -i anullsrc=cl=7.1 \ -af 'aformat=cl=mono|stereo|2.1|3.0|4.0,aformat=cl=4.0|3.0|2.1|stereo|mono' \ -f null - The fix is easy: break out of the inner loop after having found a match. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-13 04:02:26 +02:00
break;
}
}
}
/* 1st round: a[known] intersect b[generic]
2nd round: a[generic] intersect b[known] */
for (round = 0; round < 2; round++) {
for (i = 0; i < a->nb_channel_layouts; i++) {
AVChannelLayout *fmt = &a->channel_layouts[i], bfmt = { 0 };
if (!av_channel_layout_check(fmt) || !KNOWN(fmt))
continue;
bfmt = FF_COUNT2LAYOUT(fmt->nb_channels);
for (j = 0; j < b->nb_channel_layouts; j++)
if (!av_channel_layout_compare(&b->channel_layouts[j], &bfmt)) {
if (check)
return 1;
av_channel_layout_copy(&channel_layouts[ret_nb++], fmt);
}
}
/* 1st round: swap to prepare 2nd round; 2nd round: put it back */
FFSWAP(AVFilterChannelLayouts *, a, b);
}
/* a[generic] intersect b[generic] */
for (i = 0; i < a->nb_channel_layouts; i++) {
if (KNOWN(&a->channel_layouts[i]))
continue;
for (j = 0; j < b->nb_channel_layouts; j++)
if (!av_channel_layout_compare(&a->channel_layouts[i], &b->channel_layouts[j])) {
if (check)
return 1;
av_channel_layout_copy(&channel_layouts[ret_nb++], &a->channel_layouts[i]);
}
}
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
if (!ret_nb) {
av_free(channel_layouts);
return 0;
}
avfilter/formats: Leave lists' ownership unchanged upon merge failure ff_merge_formats(), ff_merge_samplerates() and ff_merge_channel_layouts() share common semantics: If merging succeeds, a non-NULL pointer is returned and both input lists (of type AVFilterFormats resp. AVFilterChannelLayouts) are to be treated as if they had been freed; the owners of the input parameters (if any) become owners of the returned list. If merging does not succeed, NULL is returned and both input lists are supposed to be unchanged. The problem is that the functions did not abide by these semantics: In case of reallocation failure, it is possible for these functions to return NULL after having already freed one of the two input list. This happens because sometimes the refs-array of the destined output gets reallocated twice to its final size and if the second of these reallocations fails, the first of the two inputs has already been freed and its refs updated to point to the destined output which in this case will be freed immediately so that all of the already updated pointers are now dangling. This leads to use-after-frees and memory corruptions lateron (when these owners get cleaned up, the lists they own get unreferenced). Should the input lists don't have owners at all, the caller (namely can_merge_formats() in avfiltergraph.c) thinks that both the input lists are unchanged and need to be freed, leading to a double free. The solution to this is simple: Don't reallocate twice; do it just once. This also saves a reallocation. This commit fixes the issue behind Coverity issue #1452636. It might also make Coverity realize that the issue has been fixed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-07 03:41:18 +02:00
if (a->refcount > b->refcount)
FFSWAP(AVFilterChannelLayouts *, a, b);
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
MERGE_REF(b, a, channel_layouts, AVFilterChannelLayouts,
{ av_free(channel_layouts); return AVERROR(ENOMEM); });
av_freep(&b->channel_layouts);
b->channel_layouts = channel_layouts;
b->nb_channel_layouts = ret_nb;
avfilter/formats: Factor checking for mergeability out of ff_merge_* The callers of the ff_merge_*() functions fall into two categories with quite different needs: One caller is can_merge_formats() which only wants to test for mergeability without it merging anything. In order to do so, it duplicates the lists it intends to test and resets their owners so that they are not modified by ff_merge_*(). It also means that it needs to receive the merged list (and not only an int containing whether the lists are mergeable) to properly free it. The other callers want the lists to be actually merged. But given the fact that ff_merge_*() automatically updates the owners of the lists, they only want the information whether the merge succeeded or not; they don't want a link to the new list. Therefore this commit splits these functions in two: ff_merge_*() for the latter callers and ff_can_merge_*() for the former. ff_merge_*() doesn't need to return a pointer to the combined list at all and hence these functions have been modified to return an int, which allows to distinguish between incompability and memory allocation failures. ff_can_merge_*() meanwhile doesn't modify its arguments at all obviating the need for copies. This in turn implies that there is no reason to return a pointer to the new list, as nothing needs to be freed. These functions therefore return an int as well. This allowed to completely remove can_merge_formats() in avfiltergraph.c. Notice that no ff_can_merge_channel_layouts() has been created, because there is currently no caller for this. It could be added if needed. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-14 16:47:01 +02:00
return 1;
}
static int can_merge_channel_layouts(const void *a, const void *b)
{
return merge_channel_layouts_internal((AVFilterChannelLayouts *)a,
(AVFilterChannelLayouts *)b, 1);
}
static int merge_channel_layouts(void *a, void *b)
{
return merge_channel_layouts_internal(a, b, 0);
}
static const AVFilterFormatsMerger mergers_video[] = {
{
.offset = offsetof(AVFilterFormatsConfig, formats),
.merge = merge_pix_fmts,
.can_merge = can_merge_pix_fmts,
},
};
static const AVFilterFormatsMerger mergers_audio[] = {
{
.offset = offsetof(AVFilterFormatsConfig, channel_layouts),
.merge = merge_channel_layouts,
.can_merge = can_merge_channel_layouts,
},
{
.offset = offsetof(AVFilterFormatsConfig, samplerates),
.merge = merge_samplerates,
.can_merge = can_merge_samplerates,
},
{
.offset = offsetof(AVFilterFormatsConfig, formats),
.merge = merge_sample_fmts,
.can_merge = can_merge_sample_fmts,
},
};
static const AVFilterNegotiation negotiate_video = {
.nb_mergers = FF_ARRAY_ELEMS(mergers_video),
.mergers = mergers_video,
.conversion_filter = "scale",
.conversion_opts_offset = offsetof(AVFilterGraph, scale_sws_opts),
};
static const AVFilterNegotiation negotiate_audio = {
.nb_mergers = FF_ARRAY_ELEMS(mergers_audio),
.mergers = mergers_audio,
.conversion_filter = "aresample",
.conversion_opts_offset = offsetof(AVFilterGraph, aresample_swr_opts),
};
const AVFilterNegotiation *ff_filter_get_negotiation(AVFilterLink *link)
{
switch (link->type) {
case AVMEDIA_TYPE_VIDEO: return &negotiate_video;
case AVMEDIA_TYPE_AUDIO: return &negotiate_audio;
default: return NULL;
}
}
int ff_fmt_is_in(int fmt, const int *fmts)
{
const int *p;
for (p = fmts; *p != -1; p++) {
if (fmt == *p)
return 1;
}
return 0;
}
#define MAKE_FORMAT_LIST(type, field, count_field) \
type *formats; \
int count = 0; \
if (fmts) \
for (count = 0; fmts[count] != -1; count++) \
; \
formats = av_mallocz(sizeof(*formats)); \
if (!formats) \
return NULL; \
formats->count_field = count; \
if (count) { \
formats->field = av_malloc_array(count, sizeof(*formats->field)); \
if (!formats->field) { \
av_freep(&formats); \
return NULL; \
} \
}
AVFilterFormats *ff_make_format_list(const int *fmts)
{
MAKE_FORMAT_LIST(AVFilterFormats, formats, nb_formats);
while (count--)
formats->formats[count] = fmts[count];
return formats;
}
AVFilterChannelLayouts *ff_make_channel_layout_list(const AVChannelLayout *fmts)
{
AVFilterChannelLayouts *ch_layouts;
int count = 0;
if (fmts)
for (count = 0; fmts[count].nb_channels; count++)
;
ch_layouts = av_mallocz(sizeof(*ch_layouts));
if (!ch_layouts)
return NULL;
ch_layouts->nb_channel_layouts = count;
if (count) {
ch_layouts->channel_layouts =
av_calloc(count, sizeof(*ch_layouts->channel_layouts));
if (!ch_layouts->channel_layouts) {
av_freep(&ch_layouts);
return NULL;
}
for (int i = 0; i < count; i++) {
int ret = av_channel_layout_copy(&ch_layouts->channel_layouts[i], &fmts[i]);
if (ret < 0)
goto fail;
}
}
return ch_layouts;
fail:
for (int i = 0; i < count; i++)
av_channel_layout_uninit(&ch_layouts->channel_layouts[i]);
av_free(ch_layouts->channel_layouts);
av_freep(&ch_layouts);
return NULL;
}
#define ADD_FORMAT(f, fmt, unref_fn, type, list, nb) \
do { \
type *fmts; \
\
if (!(*f) && !(*f = av_mallocz(sizeof(**f)))) { \
return AVERROR(ENOMEM); \
} \
\
fmts = av_realloc_array((*f)->list, (*f)->nb + 1, \
sizeof(*(*f)->list)); \
if (!fmts) { \
unref_fn(f); \
return AVERROR(ENOMEM); \
} \
\
(*f)->list = fmts; \
ASSIGN_FMT(f, fmt, list, nb); \
} while (0)
#define ASSIGN_FMT(f, fmt, list, nb) \
do { \
(*f)->list[(*f)->nb++] = fmt; \
} while (0)
Merge remote-tracking branch 'qatar/master' * qatar/master: vorbis: Validate that the floor 1 X values contain no duplicates. avprobe: Identify codec probe failures rather than calling them unsupported codecs. avformat: Probe codecs at score 0 on buffer exhaustion conditions. avformat: Factorize codec probing. Indeo Audio decoder imc: make IMDCT support stereo output imc: move channel-specific data into separate context lavfi: remove request/poll and drawing functions from public API on next bump lavfi: make avfilter_insert_pad and pals private on next bump. lavfi: make formats API private on next bump. avplay: use buffersrc instead of custom input filter. avtools: move buffer management code from avconv to cmdutils. avconv: don't use InputStream in the buffer management code. avconv: fix exiting when max frames is reached. mpc8: fix maximum bands handling aacdec: Turn PS off when switching to stereo and turn it to implicit when switching to mono. Conflicts: Changelog cmdutils.h ffmpeg.c ffplay.c ffprobe.c libavcodec/avcodec.h libavcodec/mpc8.c libavcodec/v210dec.h libavcodec/version.h libavcodec/vorbisdec.c libavfilter/avfilter.c libavfilter/avfilter.h libavfilter/buffersrc.c libavfilter/formats.c libavfilter/src_movie.c libavfilter/vf_aspect.c libavfilter/vf_blackframe.c libavfilter/vf_boxblur.c libavfilter/vf_crop.c libavfilter/vf_cropdetect.c libavfilter/vf_delogo.c libavfilter/vf_drawbox.c libavfilter/vf_drawtext.c libavfilter/vf_fade.c libavfilter/vf_fifo.c libavfilter/vf_format.c libavfilter/vf_frei0r.c libavfilter/vf_gradfun.c libavfilter/vf_hflip.c libavfilter/vf_hqdn3d.c libavfilter/vf_libopencv.c libavfilter/vf_lut.c libavfilter/vf_overlay.c libavfilter/vf_pad.c libavfilter/vf_scale.c libavfilter/vf_select.c libavfilter/vf_showinfo.c libavfilter/vf_transpose.c libavfilter/vf_unsharp.c libavfilter/vf_yadif.c libavfilter/vsrc_color.c libavfilter/vsrc_testsrc.c libavformat/utils.c Merged-by: Michael Niedermayer <michaelni@gmx.at>
2012-06-05 23:43:44 +03:00
int ff_add_format(AVFilterFormats **avff, int64_t fmt)
{
ADD_FORMAT(avff, fmt, ff_formats_unref, int, formats, nb_formats);
return 0;
}
#undef ASSIGN_FMT
#define ASSIGN_FMT(f, fmt, list, nb) \
do { \
int ret; \
memset((*f)->list + (*f)->nb, 0, sizeof(*(*f)->list)); \
ret = av_channel_layout_copy(&(*f)->list[(*f)->nb], fmt); \
if (ret < 0) \
return ret; \
(*f)->nb++; \
} while (0)
int ff_add_channel_layout(AVFilterChannelLayouts **l,
const AVChannelLayout *channel_layout)
{
av_assert1(!(*l && (*l)->all_layouts));
ADD_FORMAT(l, channel_layout, ff_channel_layouts_unref, AVChannelLayout, channel_layouts, nb_channel_layouts);
return 0;
}
AVFilterFormats *ff_make_formats_list_singleton(int fmt)
{
int fmts[2] = { fmt, -1 };
return ff_make_format_list(fmts);
}
AVFilterFormats *ff_all_formats(enum AVMediaType type)
{
AVFilterFormats *ret = NULL;
if (type == AVMEDIA_TYPE_VIDEO) {
return ff_formats_pixdesc_filter(0, 0);
} else if (type == AVMEDIA_TYPE_AUDIO) {
enum AVSampleFormat fmt = 0;
while (av_get_sample_fmt_name(fmt)) {
if (ff_add_format(&ret, fmt) < 0)
return NULL;
fmt++;
}
}
return ret;
}
AVFilterFormats *ff_formats_pixdesc_filter(unsigned want, unsigned rej)
{
unsigned nb_formats, fmt, flags;
AVFilterFormats *formats = NULL;
while (1) {
nb_formats = 0;
for (fmt = 0;; fmt++) {
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
if (!desc)
break;
flags = desc->flags;
if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL) &&
!(desc->flags & AV_PIX_FMT_FLAG_PLANAR) &&
(desc->log2_chroma_w || desc->log2_chroma_h))
flags |= FF_PIX_FMT_FLAG_SW_FLAT_SUB;
if ((flags & (want | rej)) != want)
continue;
if (formats)
formats->formats[nb_formats] = fmt;
nb_formats++;
}
if (formats) {
av_assert0(formats->nb_formats == nb_formats);
return formats;
}
formats = av_mallocz(sizeof(*formats));
if (!formats)
return NULL;
formats->nb_formats = nb_formats;
if (nb_formats) {
formats->formats = av_malloc_array(nb_formats, sizeof(*formats->formats));
if (!formats->formats) {
av_freep(&formats);
return NULL;
}
}
}
}
2012-05-30 14:59:30 +03:00
AVFilterFormats *ff_planar_sample_fmts(void)
{
AVFilterFormats *ret = NULL;
int fmt;
for (fmt = 0; av_get_bytes_per_sample(fmt)>0; fmt++)
2012-05-30 14:59:30 +03:00
if (av_sample_fmt_is_planar(fmt))
if (ff_add_format(&ret, fmt) < 0)
return NULL;
2012-05-30 14:59:30 +03:00
return ret;
}
AVFilterFormats *ff_all_samplerates(void)
{
AVFilterFormats *ret = av_mallocz(sizeof(*ret));
return ret;
}
AVFilterChannelLayouts *ff_all_channel_layouts(void)
{
AVFilterChannelLayouts *ret = av_mallocz(sizeof(*ret));
if (!ret)
return NULL;
ret->all_layouts = 1;
return ret;
}
AVFilterChannelLayouts *ff_all_channel_counts(void)
{
AVFilterChannelLayouts *ret = av_mallocz(sizeof(*ret));
if (!ret)
return NULL;
ret->all_layouts = ret->all_counts = 1;
return ret;
}
#define FORMATS_REF(f, ref, unref_fn) \
void *tmp; \
\
if (!f) \
return AVERROR(ENOMEM); \
\
tmp = av_realloc_array(f->refs, sizeof(*f->refs), f->refcount + 1); \
if (!tmp) { \
unref_fn(&f); \
return AVERROR(ENOMEM); \
} \
f->refs = tmp; \
f->refs[f->refcount++] = ref; \
*ref = f; \
return 0
int ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref)
{
FORMATS_REF(f, ref, ff_channel_layouts_unref);
}
int ff_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
{
FORMATS_REF(f, ref, ff_formats_unref);
}
#define FIND_REF_INDEX(ref, idx) \
do { \
int i; \
for (i = 0; i < (*ref)->refcount; i ++) \
if((*ref)->refs[i] == ref) { \
idx = i; \
break; \
} \
} while (0)
#define FORMATS_UNREF(ref, list) \
do { \
int idx = -1; \
\
if (!*ref) \
return; \
\
FIND_REF_INDEX(ref, idx); \
\
avfilter/formats: Fix double frees and memleaks on error The formats API deals with lists of channel layouts, sample rates, pixel formats and sample formats. These lists are refcounted in a way in which the list structure itself contains pointers to all of its owners. Furthermore, it is possible for a list to be not owned by anyone yet; this status is temporary until the list has been attached to an owner. Adding an owner to a list involves reallocating the list's list of owners and can therefore fail. In order to reduce the amount of checks and cleanup code for the users of this API, the API is supposed to be lenient when faced with input lists that are NULL and it is supposed to clean up if adding an owner to a list fails, so that a simple use case like list = ff_make_format_list(foo_fmts); if ((ret = ff_formats_ref(list, &ctx->inputs[0]->out_formats)) < 0) return ret; needn't check whether list could be successfully allocated (ff_formats_ref() return AVERROR(ENOMEM) if it couldn't) and it also needn't free list if ff_formats_ref() couldn't add an owner for it. But the cleaning up after itself was broken. The root cause was that the refcount was decremented during unreferencing whether or not the element to be unreferenced was actually an owner of the list or not. This means that if the above sample code is continued by if ((ret = ff_formats_ref(list, &ctx->inputs[1]->out_formats)) < 0) return ret; and that if an error happens at the second ff_formats_ref() call, the automatic cleaning of list will decrement the refcount from 1 (the sole owner of list at this moment is ctx->input[0]->out_formats) to 0 and so the list will be freed; yet ctx->input[0]->out_formats still points to the list and this will lead to a double free/use-after-free when ctx->input[0] is freed later. Presumably in order to work around such an issue, commit 93afb338a405eac0f9e7b092bc26603378bfcca6 restricted unreferencing to lists with owners. This does not solve the root cause (the above example is not fixed by this) at all, but it solves some crashs. This commit fixes the API: The list's refcount is only decremented if an owner is removed from the list of owners and not if the unref-function is called with a pointer that is not among the owners of the list. Furtermore, the requirement for the list to have owners is dropped. This implies that if the first call to ff_formats_ref() in the above example fails, the refcount which is initially zero during unreferencing is not modified, so that the list will be freed automatically in said call to ff_formats_ref() as every list whose refcount reaches zero is. If on the other hand, the second call to ff_formats_ref() is the first to fail, the refcount would stay at one during the automatic unreferencing in ff_formats_ref(). The list would later be freed when its last (and in this case sole) owner (namely ctx->inputs[0]->out_formats) gets unreferenced. The issues described here for ff_formats_ref() also affected the other functions of this API. E.g. ff_add_format() failed to clean up after itself if adding an entry to an already existing list failed (the case of a freshly allocated list was handled specially and this commit also removes said code). E.g. ff_all_formats() inherited the flaw. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-07 19:43:20 +02:00
if (idx >= 0) { \
memmove((*ref)->refs + idx, (*ref)->refs + idx + 1, \
sizeof(*(*ref)->refs) * ((*ref)->refcount - idx - 1)); \
avfilter/formats: Fix double frees and memleaks on error The formats API deals with lists of channel layouts, sample rates, pixel formats and sample formats. These lists are refcounted in a way in which the list structure itself contains pointers to all of its owners. Furthermore, it is possible for a list to be not owned by anyone yet; this status is temporary until the list has been attached to an owner. Adding an owner to a list involves reallocating the list's list of owners and can therefore fail. In order to reduce the amount of checks and cleanup code for the users of this API, the API is supposed to be lenient when faced with input lists that are NULL and it is supposed to clean up if adding an owner to a list fails, so that a simple use case like list = ff_make_format_list(foo_fmts); if ((ret = ff_formats_ref(list, &ctx->inputs[0]->out_formats)) < 0) return ret; needn't check whether list could be successfully allocated (ff_formats_ref() return AVERROR(ENOMEM) if it couldn't) and it also needn't free list if ff_formats_ref() couldn't add an owner for it. But the cleaning up after itself was broken. The root cause was that the refcount was decremented during unreferencing whether or not the element to be unreferenced was actually an owner of the list or not. This means that if the above sample code is continued by if ((ret = ff_formats_ref(list, &ctx->inputs[1]->out_formats)) < 0) return ret; and that if an error happens at the second ff_formats_ref() call, the automatic cleaning of list will decrement the refcount from 1 (the sole owner of list at this moment is ctx->input[0]->out_formats) to 0 and so the list will be freed; yet ctx->input[0]->out_formats still points to the list and this will lead to a double free/use-after-free when ctx->input[0] is freed later. Presumably in order to work around such an issue, commit 93afb338a405eac0f9e7b092bc26603378bfcca6 restricted unreferencing to lists with owners. This does not solve the root cause (the above example is not fixed by this) at all, but it solves some crashs. This commit fixes the API: The list's refcount is only decremented if an owner is removed from the list of owners and not if the unref-function is called with a pointer that is not among the owners of the list. Furtermore, the requirement for the list to have owners is dropped. This implies that if the first call to ff_formats_ref() in the above example fails, the refcount which is initially zero during unreferencing is not modified, so that the list will be freed automatically in said call to ff_formats_ref() as every list whose refcount reaches zero is. If on the other hand, the second call to ff_formats_ref() is the first to fail, the refcount would stay at one during the automatic unreferencing in ff_formats_ref(). The list would later be freed when its last (and in this case sole) owner (namely ctx->inputs[0]->out_formats) gets unreferenced. The issues described here for ff_formats_ref() also affected the other functions of this API. E.g. ff_add_format() failed to clean up after itself if adding an entry to an already existing list failed (the case of a freshly allocated list was handled specially and this commit also removes said code). E.g. ff_all_formats() inherited the flaw. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-07 19:43:20 +02:00
--(*ref)->refcount; \
} \
if (!(*ref)->refcount) { \
FREE_LIST(ref, list); \
av_free((*ref)->list); \
av_free((*ref)->refs); \
av_free(*ref); \
} \
*ref = NULL; \
} while (0)
#define FREE_LIST(ref, list) do { } while(0)
void ff_formats_unref(AVFilterFormats **ref)
{
FORMATS_UNREF(ref, formats);
}
#undef FREE_LIST
#define FREE_LIST(ref, list) \
do { \
for (int i = 0; i < (*ref)->nb_channel_layouts; i++) \
av_channel_layout_uninit(&(*ref)->list[i]); \
} while(0)
void ff_channel_layouts_unref(AVFilterChannelLayouts **ref)
{
FORMATS_UNREF(ref, channel_layouts);
}
#define FORMATS_CHANGEREF(oldref, newref) \
do { \
int idx = -1; \
\
FIND_REF_INDEX(oldref, idx); \
\
if (idx >= 0) { \
(*oldref)->refs[idx] = newref; \
*newref = *oldref; \
*oldref = NULL; \
} \
} while (0)
void ff_channel_layouts_changeref(AVFilterChannelLayouts **oldref,
AVFilterChannelLayouts **newref)
{
FORMATS_CHANGEREF(oldref, newref);
}
void ff_formats_changeref(AVFilterFormats **oldref, AVFilterFormats **newref)
{
FORMATS_CHANGEREF(oldref, newref);
}
#define SET_COMMON_FORMATS(ctx, fmts, media_type, ref_fn, unref_fn) \
int i; \
\
if (!fmts) \
return AVERROR(ENOMEM); \
\
for (i = 0; i < ctx->nb_inputs; i++) { \
AVFilterLink *const link = ctx->inputs[i]; \
if (link && !link->outcfg.fmts && \
(media_type == AVMEDIA_TYPE_UNKNOWN || link->type == media_type)) { \
int ret = ref_fn(fmts, &ctx->inputs[i]->outcfg.fmts); \
if (ret < 0) { \
return ret; \
} \
} \
} \
for (i = 0; i < ctx->nb_outputs; i++) { \
AVFilterLink *const link = ctx->outputs[i]; \
if (link && !link->incfg.fmts && \
(media_type == AVMEDIA_TYPE_UNKNOWN || link->type == media_type)) { \
int ret = ref_fn(fmts, &ctx->outputs[i]->incfg.fmts); \
if (ret < 0) { \
return ret; \
} \
} \
} \
\
if (!fmts->refcount) \
avfilter/formats: Fix double frees and memleaks on error The formats API deals with lists of channel layouts, sample rates, pixel formats and sample formats. These lists are refcounted in a way in which the list structure itself contains pointers to all of its owners. Furthermore, it is possible for a list to be not owned by anyone yet; this status is temporary until the list has been attached to an owner. Adding an owner to a list involves reallocating the list's list of owners and can therefore fail. In order to reduce the amount of checks and cleanup code for the users of this API, the API is supposed to be lenient when faced with input lists that are NULL and it is supposed to clean up if adding an owner to a list fails, so that a simple use case like list = ff_make_format_list(foo_fmts); if ((ret = ff_formats_ref(list, &ctx->inputs[0]->out_formats)) < 0) return ret; needn't check whether list could be successfully allocated (ff_formats_ref() return AVERROR(ENOMEM) if it couldn't) and it also needn't free list if ff_formats_ref() couldn't add an owner for it. But the cleaning up after itself was broken. The root cause was that the refcount was decremented during unreferencing whether or not the element to be unreferenced was actually an owner of the list or not. This means that if the above sample code is continued by if ((ret = ff_formats_ref(list, &ctx->inputs[1]->out_formats)) < 0) return ret; and that if an error happens at the second ff_formats_ref() call, the automatic cleaning of list will decrement the refcount from 1 (the sole owner of list at this moment is ctx->input[0]->out_formats) to 0 and so the list will be freed; yet ctx->input[0]->out_formats still points to the list and this will lead to a double free/use-after-free when ctx->input[0] is freed later. Presumably in order to work around such an issue, commit 93afb338a405eac0f9e7b092bc26603378bfcca6 restricted unreferencing to lists with owners. This does not solve the root cause (the above example is not fixed by this) at all, but it solves some crashs. This commit fixes the API: The list's refcount is only decremented if an owner is removed from the list of owners and not if the unref-function is called with a pointer that is not among the owners of the list. Furtermore, the requirement for the list to have owners is dropped. This implies that if the first call to ff_formats_ref() in the above example fails, the refcount which is initially zero during unreferencing is not modified, so that the list will be freed automatically in said call to ff_formats_ref() as every list whose refcount reaches zero is. If on the other hand, the second call to ff_formats_ref() is the first to fail, the refcount would stay at one during the automatic unreferencing in ff_formats_ref(). The list would later be freed when its last (and in this case sole) owner (namely ctx->inputs[0]->out_formats) gets unreferenced. The issues described here for ff_formats_ref() also affected the other functions of this API. E.g. ff_add_format() failed to clean up after itself if adding an entry to an already existing list failed (the case of a freshly allocated list was handled specially and this commit also removes said code). E.g. ff_all_formats() inherited the flaw. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-07 19:43:20 +02:00
unref_fn(&fmts); \
\
return 0;
int ff_set_common_channel_layouts(AVFilterContext *ctx,
AVFilterChannelLayouts *channel_layouts)
{
SET_COMMON_FORMATS(ctx, channel_layouts, AVMEDIA_TYPE_AUDIO,
avfilter/formats: Fix double frees and memleaks on error The formats API deals with lists of channel layouts, sample rates, pixel formats and sample formats. These lists are refcounted in a way in which the list structure itself contains pointers to all of its owners. Furthermore, it is possible for a list to be not owned by anyone yet; this status is temporary until the list has been attached to an owner. Adding an owner to a list involves reallocating the list's list of owners and can therefore fail. In order to reduce the amount of checks and cleanup code for the users of this API, the API is supposed to be lenient when faced with input lists that are NULL and it is supposed to clean up if adding an owner to a list fails, so that a simple use case like list = ff_make_format_list(foo_fmts); if ((ret = ff_formats_ref(list, &ctx->inputs[0]->out_formats)) < 0) return ret; needn't check whether list could be successfully allocated (ff_formats_ref() return AVERROR(ENOMEM) if it couldn't) and it also needn't free list if ff_formats_ref() couldn't add an owner for it. But the cleaning up after itself was broken. The root cause was that the refcount was decremented during unreferencing whether or not the element to be unreferenced was actually an owner of the list or not. This means that if the above sample code is continued by if ((ret = ff_formats_ref(list, &ctx->inputs[1]->out_formats)) < 0) return ret; and that if an error happens at the second ff_formats_ref() call, the automatic cleaning of list will decrement the refcount from 1 (the sole owner of list at this moment is ctx->input[0]->out_formats) to 0 and so the list will be freed; yet ctx->input[0]->out_formats still points to the list and this will lead to a double free/use-after-free when ctx->input[0] is freed later. Presumably in order to work around such an issue, commit 93afb338a405eac0f9e7b092bc26603378bfcca6 restricted unreferencing to lists with owners. This does not solve the root cause (the above example is not fixed by this) at all, but it solves some crashs. This commit fixes the API: The list's refcount is only decremented if an owner is removed from the list of owners and not if the unref-function is called with a pointer that is not among the owners of the list. Furtermore, the requirement for the list to have owners is dropped. This implies that if the first call to ff_formats_ref() in the above example fails, the refcount which is initially zero during unreferencing is not modified, so that the list will be freed automatically in said call to ff_formats_ref() as every list whose refcount reaches zero is. If on the other hand, the second call to ff_formats_ref() is the first to fail, the refcount would stay at one during the automatic unreferencing in ff_formats_ref(). The list would later be freed when its last (and in this case sole) owner (namely ctx->inputs[0]->out_formats) gets unreferenced. The issues described here for ff_formats_ref() also affected the other functions of this API. E.g. ff_add_format() failed to clean up after itself if adding an entry to an already existing list failed (the case of a freshly allocated list was handled specially and this commit also removes said code). E.g. ff_all_formats() inherited the flaw. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-07 19:43:20 +02:00
ff_channel_layouts_ref, ff_channel_layouts_unref);
}
int ff_set_common_channel_layouts_from_list(AVFilterContext *ctx,
const AVChannelLayout *fmts)
{
return ff_set_common_channel_layouts(ctx, ff_make_channel_layout_list(fmts));
}
int ff_set_common_all_channel_counts(AVFilterContext *ctx)
{
return ff_set_common_channel_layouts(ctx, ff_all_channel_counts());
}
int ff_set_common_samplerates(AVFilterContext *ctx,
AVFilterFormats *samplerates)
{
SET_COMMON_FORMATS(ctx, samplerates, AVMEDIA_TYPE_AUDIO,
avfilter/formats: Fix double frees and memleaks on error The formats API deals with lists of channel layouts, sample rates, pixel formats and sample formats. These lists are refcounted in a way in which the list structure itself contains pointers to all of its owners. Furthermore, it is possible for a list to be not owned by anyone yet; this status is temporary until the list has been attached to an owner. Adding an owner to a list involves reallocating the list's list of owners and can therefore fail. In order to reduce the amount of checks and cleanup code for the users of this API, the API is supposed to be lenient when faced with input lists that are NULL and it is supposed to clean up if adding an owner to a list fails, so that a simple use case like list = ff_make_format_list(foo_fmts); if ((ret = ff_formats_ref(list, &ctx->inputs[0]->out_formats)) < 0) return ret; needn't check whether list could be successfully allocated (ff_formats_ref() return AVERROR(ENOMEM) if it couldn't) and it also needn't free list if ff_formats_ref() couldn't add an owner for it. But the cleaning up after itself was broken. The root cause was that the refcount was decremented during unreferencing whether or not the element to be unreferenced was actually an owner of the list or not. This means that if the above sample code is continued by if ((ret = ff_formats_ref(list, &ctx->inputs[1]->out_formats)) < 0) return ret; and that if an error happens at the second ff_formats_ref() call, the automatic cleaning of list will decrement the refcount from 1 (the sole owner of list at this moment is ctx->input[0]->out_formats) to 0 and so the list will be freed; yet ctx->input[0]->out_formats still points to the list and this will lead to a double free/use-after-free when ctx->input[0] is freed later. Presumably in order to work around such an issue, commit 93afb338a405eac0f9e7b092bc26603378bfcca6 restricted unreferencing to lists with owners. This does not solve the root cause (the above example is not fixed by this) at all, but it solves some crashs. This commit fixes the API: The list's refcount is only decremented if an owner is removed from the list of owners and not if the unref-function is called with a pointer that is not among the owners of the list. Furtermore, the requirement for the list to have owners is dropped. This implies that if the first call to ff_formats_ref() in the above example fails, the refcount which is initially zero during unreferencing is not modified, so that the list will be freed automatically in said call to ff_formats_ref() as every list whose refcount reaches zero is. If on the other hand, the second call to ff_formats_ref() is the first to fail, the refcount would stay at one during the automatic unreferencing in ff_formats_ref(). The list would later be freed when its last (and in this case sole) owner (namely ctx->inputs[0]->out_formats) gets unreferenced. The issues described here for ff_formats_ref() also affected the other functions of this API. E.g. ff_add_format() failed to clean up after itself if adding an entry to an already existing list failed (the case of a freshly allocated list was handled specially and this commit also removes said code). E.g. ff_all_formats() inherited the flaw. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-07 19:43:20 +02:00
ff_formats_ref, ff_formats_unref);
}
int ff_set_common_samplerates_from_list(AVFilterContext *ctx,
const int *samplerates)
{
return ff_set_common_samplerates(ctx, ff_make_format_list(samplerates));
}
int ff_set_common_all_samplerates(AVFilterContext *ctx)
{
return ff_set_common_samplerates(ctx, ff_all_samplerates());
}
/**
* 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.
*/
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
{
SET_COMMON_FORMATS(ctx, formats, AVMEDIA_TYPE_UNKNOWN,
avfilter/formats: Fix double frees and memleaks on error The formats API deals with lists of channel layouts, sample rates, pixel formats and sample formats. These lists are refcounted in a way in which the list structure itself contains pointers to all of its owners. Furthermore, it is possible for a list to be not owned by anyone yet; this status is temporary until the list has been attached to an owner. Adding an owner to a list involves reallocating the list's list of owners and can therefore fail. In order to reduce the amount of checks and cleanup code for the users of this API, the API is supposed to be lenient when faced with input lists that are NULL and it is supposed to clean up if adding an owner to a list fails, so that a simple use case like list = ff_make_format_list(foo_fmts); if ((ret = ff_formats_ref(list, &ctx->inputs[0]->out_formats)) < 0) return ret; needn't check whether list could be successfully allocated (ff_formats_ref() return AVERROR(ENOMEM) if it couldn't) and it also needn't free list if ff_formats_ref() couldn't add an owner for it. But the cleaning up after itself was broken. The root cause was that the refcount was decremented during unreferencing whether or not the element to be unreferenced was actually an owner of the list or not. This means that if the above sample code is continued by if ((ret = ff_formats_ref(list, &ctx->inputs[1]->out_formats)) < 0) return ret; and that if an error happens at the second ff_formats_ref() call, the automatic cleaning of list will decrement the refcount from 1 (the sole owner of list at this moment is ctx->input[0]->out_formats) to 0 and so the list will be freed; yet ctx->input[0]->out_formats still points to the list and this will lead to a double free/use-after-free when ctx->input[0] is freed later. Presumably in order to work around such an issue, commit 93afb338a405eac0f9e7b092bc26603378bfcca6 restricted unreferencing to lists with owners. This does not solve the root cause (the above example is not fixed by this) at all, but it solves some crashs. This commit fixes the API: The list's refcount is only decremented if an owner is removed from the list of owners and not if the unref-function is called with a pointer that is not among the owners of the list. Furtermore, the requirement for the list to have owners is dropped. This implies that if the first call to ff_formats_ref() in the above example fails, the refcount which is initially zero during unreferencing is not modified, so that the list will be freed automatically in said call to ff_formats_ref() as every list whose refcount reaches zero is. If on the other hand, the second call to ff_formats_ref() is the first to fail, the refcount would stay at one during the automatic unreferencing in ff_formats_ref(). The list would later be freed when its last (and in this case sole) owner (namely ctx->inputs[0]->out_formats) gets unreferenced. The issues described here for ff_formats_ref() also affected the other functions of this API. E.g. ff_add_format() failed to clean up after itself if adding an entry to an already existing list failed (the case of a freshly allocated list was handled specially and this commit also removes said code). E.g. ff_all_formats() inherited the flaw. Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2020-08-07 19:43:20 +02:00
ff_formats_ref, ff_formats_unref);
}
int ff_set_common_formats_from_list(AVFilterContext *ctx, const int *fmts)
{
return ff_set_common_formats(ctx, ff_make_format_list(fmts));
}
int ff_default_query_formats(AVFilterContext *ctx)
{
avfilter: Replace query_formats callback with union of list and callback If one looks at the many query_formats callbacks in existence, one will immediately recognize that there is one type of default callback for video and a slightly different default callback for audio: It is "return ff_set_common_formats_from_list(ctx, pix_fmts);" for video with a filter-specific pix_fmts list. For audio, it is the same with a filter-specific sample_fmts list together with ff_set_common_all_samplerates() and ff_set_common_all_channel_counts(). This commit allows to remove the boilerplate query_formats callbacks by replacing said callback with a union consisting the old callback and pointers for pixel and sample format arrays. For the not uncommon case in which these lists only contain a single entry (besides the sentinel) enum AVPixelFormat and enum AVSampleFormat fields are also added to the union to store them directly in the AVFilter, thereby avoiding a relocation. The state of said union will be contained in a new, dedicated AVFilter field (the nb_inputs and nb_outputs fields have been shrunk to uint8_t in order to create a hole for this new field; this is no problem, as the maximum of all the nb_inputs is four; for nb_outputs it is only two). The state's default value coincides with the earlier default of query_formats being unset, namely that the filter accepts all formats (and also sample rates and channel counts/layouts for audio) provided that these properties agree coincide for all inputs and outputs. By using different union members for audio and video filters the type-unsafety of using the same functions for audio and video lists will furthermore be more confined to formats.c than before. When the new fields are used, they will also avoid allocations: Currently something nearly equivalent to ff_default_query_formats() is called after every successful call to a query_formats callback; yet in the common case that the newly allocated AVFilterFormats are not used at all (namely if there are no free links) these newly allocated AVFilterFormats are freed again without ever being used. Filters no longer using the callback will not exhibit this any more. Reviewed-by: Paul B Mahol <onemda@gmail.com> Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2021-09-27 12:07:35 +02:00
const AVFilter *const f = ctx->filter;
AVFilterFormats *formats;
enum AVMediaType type;
int ret;
avfilter: Replace query_formats callback with union of list and callback If one looks at the many query_formats callbacks in existence, one will immediately recognize that there is one type of default callback for video and a slightly different default callback for audio: It is "return ff_set_common_formats_from_list(ctx, pix_fmts);" for video with a filter-specific pix_fmts list. For audio, it is the same with a filter-specific sample_fmts list together with ff_set_common_all_samplerates() and ff_set_common_all_channel_counts(). This commit allows to remove the boilerplate query_formats callbacks by replacing said callback with a union consisting the old callback and pointers for pixel and sample format arrays. For the not uncommon case in which these lists only contain a single entry (besides the sentinel) enum AVPixelFormat and enum AVSampleFormat fields are also added to the union to store them directly in the AVFilter, thereby avoiding a relocation. The state of said union will be contained in a new, dedicated AVFilter field (the nb_inputs and nb_outputs fields have been shrunk to uint8_t in order to create a hole for this new field; this is no problem, as the maximum of all the nb_inputs is four; for nb_outputs it is only two). The state's default value coincides with the earlier default of query_formats being unset, namely that the filter accepts all formats (and also sample rates and channel counts/layouts for audio) provided that these properties agree coincide for all inputs and outputs. By using different union members for audio and video filters the type-unsafety of using the same functions for audio and video lists will furthermore be more confined to formats.c than before. When the new fields are used, they will also avoid allocations: Currently something nearly equivalent to ff_default_query_formats() is called after every successful call to a query_formats callback; yet in the common case that the newly allocated AVFilterFormats are not used at all (namely if there are no free links) these newly allocated AVFilterFormats are freed again without ever being used. Filters no longer using the callback will not exhibit this any more. Reviewed-by: Paul B Mahol <onemda@gmail.com> Reviewed-by: Nicolas George <george@nsup.org> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2021-09-27 12:07:35 +02:00
switch (f->formats_state) {
case FF_FILTER_FORMATS_PIXFMT_LIST:
type = AVMEDIA_TYPE_VIDEO;
formats = ff_make_format_list(f->formats.pixels_list);
break;
case FF_FILTER_FORMATS_SAMPLEFMTS_LIST:
type = AVMEDIA_TYPE_AUDIO;
formats = ff_make_format_list(f->formats.samples_list);
break;
case FF_FILTER_FORMATS_SINGLE_PIXFMT:
type = AVMEDIA_TYPE_VIDEO;
formats = ff_make_formats_list_singleton(f->formats.pix_fmt);
break;
case FF_FILTER_FORMATS_SINGLE_SAMPLEFMT:
type = AVMEDIA_TYPE_AUDIO;
formats = ff_make_formats_list_singleton(f->formats.sample_fmt);
break;
default:
av_assert2(!"Unreachable");
/* Intended fallthrough */
case FF_FILTER_FORMATS_PASSTHROUGH:
case FF_FILTER_FORMATS_QUERY_FUNC:
type = ctx->nb_inputs ? ctx->inputs [0]->type :
ctx->nb_outputs ? ctx->outputs[0]->type : AVMEDIA_TYPE_VIDEO;
formats = ff_all_formats(type);
break;
}
ret = ff_set_common_formats(ctx, formats);
if (ret < 0)
return ret;
if (type == AVMEDIA_TYPE_AUDIO) {
ret = ff_set_common_all_channel_counts(ctx);
if (ret < 0)
return ret;
ret = ff_set_common_all_samplerates(ctx);
if (ret < 0)
return ret;
}
return 0;
}
/* internal functions for parsing audio format arguments */
Merge commit '716d413c13981da15323c7a3821860536eefdbbb' * commit '716d413c13981da15323c7a3821860536eefdbbb': Replace PIX_FMT_* -> AV_PIX_FMT_*, PixelFormat -> AVPixelFormat Conflicts: doc/examples/muxing.c ffmpeg.h ffmpeg_filter.c ffmpeg_opt.c ffplay.c ffprobe.c libavcodec/8bps.c libavcodec/aasc.c libavcodec/aura.c libavcodec/avcodec.h libavcodec/avs.c libavcodec/bfi.c libavcodec/bmp.c libavcodec/bmpenc.c libavcodec/c93.c libavcodec/cscd.c libavcodec/cyuv.c libavcodec/dpx.c libavcodec/dpxenc.c libavcodec/eatgv.c libavcodec/escape124.c libavcodec/ffv1.c libavcodec/flashsv.c libavcodec/fraps.c libavcodec/h264.c libavcodec/huffyuv.c libavcodec/iff.c libavcodec/imgconvert.c libavcodec/indeo3.c libavcodec/kmvc.c libavcodec/libopenjpegdec.c libavcodec/libopenjpegenc.c libavcodec/libx264.c libavcodec/ljpegenc.c libavcodec/mjpegdec.c libavcodec/mjpegenc.c libavcodec/motionpixels.c libavcodec/mpeg12.c libavcodec/mpeg12enc.c libavcodec/mpeg4videodec.c libavcodec/mpegvideo_enc.c libavcodec/pamenc.c libavcodec/pcxenc.c libavcodec/pgssubdec.c libavcodec/pngdec.c libavcodec/pngenc.c libavcodec/pnm.c libavcodec/pnmdec.c libavcodec/pnmenc.c libavcodec/ptx.c libavcodec/qdrw.c libavcodec/qpeg.c libavcodec/qtrleenc.c libavcodec/raw.c libavcodec/rawdec.c libavcodec/rl2.c libavcodec/sgidec.c libavcodec/sgienc.c libavcodec/snowdec.c libavcodec/snowenc.c libavcodec/sunrast.c libavcodec/targa.c libavcodec/targaenc.c libavcodec/tiff.c libavcodec/tiffenc.c libavcodec/tmv.c libavcodec/truemotion2.c libavcodec/utils.c libavcodec/vb.c libavcodec/vp3.c libavcodec/wnv1.c libavcodec/xl.c libavcodec/xwddec.c libavcodec/xwdenc.c libavcodec/yop.c libavdevice/v4l2.c libavdevice/x11grab.c libavfilter/avfilter.c libavfilter/avfilter.h libavfilter/buffersrc.c libavfilter/drawutils.c libavfilter/formats.c libavfilter/src_movie.c libavfilter/vf_ass.c libavfilter/vf_drawtext.c libavfilter/vf_fade.c libavfilter/vf_format.c libavfilter/vf_hflip.c libavfilter/vf_lut.c libavfilter/vf_overlay.c libavfilter/vf_pad.c libavfilter/vf_scale.c libavfilter/vf_transpose.c libavfilter/vf_yadif.c libavfilter/video.c libavfilter/vsrc_testsrc.c libavformat/movenc.c libavformat/mxf.h libavformat/utils.c libavformat/yuv4mpeg.c libavutil/imgutils.c libavutil/pixdesc.c libswscale/input.c libswscale/output.c libswscale/swscale_internal.h libswscale/swscale_unscaled.c libswscale/utils.c libswscale/x86/swscale_template.c libswscale/x86/yuv2rgb.c libswscale/x86/yuv2rgb_template.c libswscale/yuv2rgb.c Merged-by: Michael Niedermayer <michaelni@gmx.at>
2012-10-08 21:54:00 +03:00
int ff_parse_pixel_format(enum AVPixelFormat *ret, const char *arg, void *log_ctx)
{
char *tail;
int pix_fmt = av_get_pix_fmt(arg);
Merge commit '716d413c13981da15323c7a3821860536eefdbbb' * commit '716d413c13981da15323c7a3821860536eefdbbb': Replace PIX_FMT_* -> AV_PIX_FMT_*, PixelFormat -> AVPixelFormat Conflicts: doc/examples/muxing.c ffmpeg.h ffmpeg_filter.c ffmpeg_opt.c ffplay.c ffprobe.c libavcodec/8bps.c libavcodec/aasc.c libavcodec/aura.c libavcodec/avcodec.h libavcodec/avs.c libavcodec/bfi.c libavcodec/bmp.c libavcodec/bmpenc.c libavcodec/c93.c libavcodec/cscd.c libavcodec/cyuv.c libavcodec/dpx.c libavcodec/dpxenc.c libavcodec/eatgv.c libavcodec/escape124.c libavcodec/ffv1.c libavcodec/flashsv.c libavcodec/fraps.c libavcodec/h264.c libavcodec/huffyuv.c libavcodec/iff.c libavcodec/imgconvert.c libavcodec/indeo3.c libavcodec/kmvc.c libavcodec/libopenjpegdec.c libavcodec/libopenjpegenc.c libavcodec/libx264.c libavcodec/ljpegenc.c libavcodec/mjpegdec.c libavcodec/mjpegenc.c libavcodec/motionpixels.c libavcodec/mpeg12.c libavcodec/mpeg12enc.c libavcodec/mpeg4videodec.c libavcodec/mpegvideo_enc.c libavcodec/pamenc.c libavcodec/pcxenc.c libavcodec/pgssubdec.c libavcodec/pngdec.c libavcodec/pngenc.c libavcodec/pnm.c libavcodec/pnmdec.c libavcodec/pnmenc.c libavcodec/ptx.c libavcodec/qdrw.c libavcodec/qpeg.c libavcodec/qtrleenc.c libavcodec/raw.c libavcodec/rawdec.c libavcodec/rl2.c libavcodec/sgidec.c libavcodec/sgienc.c libavcodec/snowdec.c libavcodec/snowenc.c libavcodec/sunrast.c libavcodec/targa.c libavcodec/targaenc.c libavcodec/tiff.c libavcodec/tiffenc.c libavcodec/tmv.c libavcodec/truemotion2.c libavcodec/utils.c libavcodec/vb.c libavcodec/vp3.c libavcodec/wnv1.c libavcodec/xl.c libavcodec/xwddec.c libavcodec/xwdenc.c libavcodec/yop.c libavdevice/v4l2.c libavdevice/x11grab.c libavfilter/avfilter.c libavfilter/avfilter.h libavfilter/buffersrc.c libavfilter/drawutils.c libavfilter/formats.c libavfilter/src_movie.c libavfilter/vf_ass.c libavfilter/vf_drawtext.c libavfilter/vf_fade.c libavfilter/vf_format.c libavfilter/vf_hflip.c libavfilter/vf_lut.c libavfilter/vf_overlay.c libavfilter/vf_pad.c libavfilter/vf_scale.c libavfilter/vf_transpose.c libavfilter/vf_yadif.c libavfilter/video.c libavfilter/vsrc_testsrc.c libavformat/movenc.c libavformat/mxf.h libavformat/utils.c libavformat/yuv4mpeg.c libavutil/imgutils.c libavutil/pixdesc.c libswscale/input.c libswscale/output.c libswscale/swscale_internal.h libswscale/swscale_unscaled.c libswscale/utils.c libswscale/x86/swscale_template.c libswscale/x86/yuv2rgb.c libswscale/x86/yuv2rgb_template.c libswscale/yuv2rgb.c Merged-by: Michael Niedermayer <michaelni@gmx.at>
2012-10-08 21:54:00 +03:00
if (pix_fmt == AV_PIX_FMT_NONE) {
pix_fmt = strtol(arg, &tail, 0);
if (*tail || !av_pix_fmt_desc_get(pix_fmt)) {
av_log(log_ctx, AV_LOG_ERROR, "Invalid pixel format '%s'\n", arg);
return AVERROR(EINVAL);
}
}
*ret = pix_fmt;
return 0;
}
int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx)
{
char *tail;
double srate = av_strtod(arg, &tail);
if (*tail || srate < 1 || (int)srate != srate || srate > INT_MAX) {
av_log(log_ctx, AV_LOG_ERROR, "Invalid sample rate '%s'\n", arg);
return AVERROR(EINVAL);
}
*ret = srate;
return 0;
}
int ff_parse_channel_layout(AVChannelLayout *ret, int *nret, const char *arg,
void *log_ctx)
{
AVChannelLayout chlayout = { 0 };
int res;
res = av_channel_layout_from_string(&chlayout, arg);
if (res < 0) {
#if FF_API_OLD_CHANNEL_LAYOUT
int64_t mask;
int nb_channels;
FF_DISABLE_DEPRECATION_WARNINGS
if (av_get_extended_channel_layout(arg, &mask, &nb_channels) < 0) {
#endif
av_log(log_ctx, AV_LOG_ERROR, "Invalid channel layout '%s'\n", arg);
return AVERROR(EINVAL);
#if FF_API_OLD_CHANNEL_LAYOUT
}
FF_ENABLE_DEPRECATION_WARNINGS
av_log(log_ctx, AV_LOG_WARNING, "Channel layout '%s' uses a deprecated syntax.\n",
arg);
if (mask)
av_channel_layout_from_mask(&chlayout, mask);
else
chlayout = (AVChannelLayout) { .order = AV_CHANNEL_ORDER_UNSPEC, .nb_channels = nb_channels };
#endif
}
if (chlayout.order == AV_CHANNEL_ORDER_UNSPEC && !nret) {
av_log(log_ctx, AV_LOG_ERROR, "Unknown channel layout '%s' is not supported.\n", arg);
return AVERROR(EINVAL);
}
*ret = chlayout;
if (nret)
*nret = chlayout.nb_channels;
return 0;
}
static int check_list(void *log, const char *name, const AVFilterFormats *fmts)
{
unsigned i, j;
if (!fmts)
return 0;
if (!fmts->nb_formats) {
av_log(log, AV_LOG_ERROR, "Empty %s list\n", name);
return AVERROR(EINVAL);
}
for (i = 0; i < fmts->nb_formats; i++) {
for (j = i + 1; j < fmts->nb_formats; j++) {
if (fmts->formats[i] == fmts->formats[j]) {
av_log(log, AV_LOG_ERROR, "Duplicated %s\n", name);
return AVERROR(EINVAL);
}
}
}
return 0;
}
int ff_formats_check_pixel_formats(void *log, const AVFilterFormats *fmts)
{
return check_list(log, "pixel format", fmts);
}
int ff_formats_check_sample_formats(void *log, const AVFilterFormats *fmts)
{
return check_list(log, "sample format", fmts);
}
int ff_formats_check_sample_rates(void *log, const AVFilterFormats *fmts)
{
if (!fmts || !fmts->nb_formats)
return 0;
return check_list(log, "sample rate", fmts);
}
static int layouts_compatible(const AVChannelLayout *a, const AVChannelLayout *b)
{
return !av_channel_layout_compare(a, b) ||
(KNOWN(a) && !KNOWN(b) && a->nb_channels == b->nb_channels) ||
(KNOWN(b) && !KNOWN(a) && b->nb_channels == a->nb_channels);
}
int ff_formats_check_channel_layouts(void *log, const AVFilterChannelLayouts *fmts)
{
unsigned i, j;
if (!fmts)
return 0;
if (fmts->all_layouts < fmts->all_counts) {
av_log(log, AV_LOG_ERROR, "Inconsistent generic list\n");
return AVERROR(EINVAL);
}
if (!fmts->all_layouts && !fmts->nb_channel_layouts) {
av_log(log, AV_LOG_ERROR, "Empty channel layout list\n");
return AVERROR(EINVAL);
}
for (i = 0; i < fmts->nb_channel_layouts; i++) {
for (j = i + 1; j < fmts->nb_channel_layouts; j++) {
if (layouts_compatible(&fmts->channel_layouts[i], &fmts->channel_layouts[j])) {
av_log(log, AV_LOG_ERROR, "Duplicated or redundant channel layout\n");
return AVERROR(EINVAL);
}
}
}
return 0;
}