summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libavutil/pixdesc.c31
-rw-r--r--libavutil/pixdesc.h15
-rw-r--r--libavutil/tests/pixfmt_best.c129
-rw-r--r--libavutil/version.h2
-rw-r--r--tests/ref/fate/pixfmt_best2
5 files changed, 151 insertions, 28 deletions
diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c
index d7c6ebfdc4..b472a94f60 100644
--- a/libavutil/pixdesc.c
+++ b/libavutil/pixdesc.c
@@ -3013,9 +3013,16 @@ static int get_pix_fmt_score(enum AVPixelFormat dst_pix_fmt,
for (i = 0; i < nb_components; i++) {
int depth_minus1 = (dst_pix_fmt == AV_PIX_FMT_PAL8) ? 7/nb_components : (dst_desc->comp[i].depth - 1);
- if (src_desc->comp[i].depth - 1 > depth_minus1 && (consider & FF_LOSS_DEPTH)) {
+ int depth_delta = src_desc->comp[i].depth - 1 - depth_minus1;
+ if (depth_delta > 0 && (consider & FF_LOSS_DEPTH)) {
loss |= FF_LOSS_DEPTH;
score -= 65536 >> depth_minus1;
+ } else if (depth_delta < 0 && (consider & FF_LOSS_EXCESS_DEPTH)) {
+ // Favour formats where bit depth exactly matches. If all other
+ // scoring is equal, we'd rather use the bit depth that most closely
+ // matches the source.
+ loss |= FF_LOSS_EXCESS_DEPTH;
+ score += depth_delta;
}
}
@@ -3035,6 +3042,28 @@ static int get_pix_fmt_score(enum AVPixelFormat dst_pix_fmt,
}
}
+ if (consider & FF_LOSS_EXCESS_RESOLUTION) {
+ // Favour formats where chroma subsampling exactly matches. If all other
+ // scoring is equal, we'd rather use the subsampling that most closely
+ // matches the source.
+ if (dst_desc->log2_chroma_w < src_desc->log2_chroma_w) {
+ loss |= FF_LOSS_EXCESS_RESOLUTION;
+ score -= 1 << (src_desc->log2_chroma_w - dst_desc->log2_chroma_w);
+ }
+
+ if (dst_desc->log2_chroma_h < src_desc->log2_chroma_h) {
+ loss |= FF_LOSS_EXCESS_RESOLUTION;
+ score -= 1 << (src_desc->log2_chroma_h - dst_desc->log2_chroma_h);
+ }
+
+ // don't favour 411 over 420, because 420 has much better support on the
+ // decoder side.
+ if (dst_desc->log2_chroma_w == 1 && src_desc->log2_chroma_w == 2 &&
+ dst_desc->log2_chroma_h == 1 && src_desc->log2_chroma_h == 2) {
+ score += 4;
+ }
+ }
+
if(consider & FF_LOSS_COLORSPACE)
switch(dst_color) {
case FF_COLOR_RGB:
diff --git a/libavutil/pixdesc.h b/libavutil/pixdesc.h
index f8a195ffcd..48d9300bfe 100644
--- a/libavutil/pixdesc.h
+++ b/libavutil/pixdesc.h
@@ -357,12 +357,15 @@ void av_write_image_line(const uint16_t *src, uint8_t *data[4],
*/
enum AVPixelFormat av_pix_fmt_swap_endianness(enum AVPixelFormat pix_fmt);
-#define FF_LOSS_RESOLUTION 0x0001 /**< loss due to resolution change */
-#define FF_LOSS_DEPTH 0x0002 /**< loss due to color depth change */
-#define FF_LOSS_COLORSPACE 0x0004 /**< loss due to color space conversion */
-#define FF_LOSS_ALPHA 0x0008 /**< loss of alpha bits */
-#define FF_LOSS_COLORQUANT 0x0010 /**< loss due to color quantization */
-#define FF_LOSS_CHROMA 0x0020 /**< loss of chroma (e.g. RGB to gray conversion) */
+#define FF_LOSS_RESOLUTION 0x0001 /**< loss due to resolution change */
+#define FF_LOSS_DEPTH 0x0002 /**< loss due to color depth change */
+#define FF_LOSS_COLORSPACE 0x0004 /**< loss due to color space conversion */
+#define FF_LOSS_ALPHA 0x0008 /**< loss of alpha bits */
+#define FF_LOSS_COLORQUANT 0x0010 /**< loss due to color quantization */
+#define FF_LOSS_CHROMA 0x0020 /**< loss of chroma (e.g. RGB to gray conversion) */
+#define FF_LOSS_EXCESS_RESOLUTION 0x0040 /**< loss due to unneeded extra resolution */
+#define FF_LOSS_EXCESS_DEPTH 0x0080 /**< loss due to unneeded extra color depth */
+
/**
* Compute what kind of losses will occur when converting from one specific
diff --git a/libavutil/tests/pixfmt_best.c b/libavutil/tests/pixfmt_best.c
index 0542af494f..d71b3cc2e8 100644
--- a/libavutil/tests/pixfmt_best.c
+++ b/libavutil/tests/pixfmt_best.c
@@ -39,32 +39,74 @@ static const enum AVPixelFormat pixfmt_list[] = {
AV_PIX_FMT_VAAPI,
};
-static enum AVPixelFormat find_best(enum AVPixelFormat pixfmt)
+static const enum AVPixelFormat semiplanar_list[] = {
+ AV_PIX_FMT_P016,
+ AV_PIX_FMT_P012,
+ AV_PIX_FMT_P010,
+ AV_PIX_FMT_NV12,
+};
+
+static const enum AVPixelFormat packed_list[] = {
+ AV_PIX_FMT_XV36,
+ AV_PIX_FMT_XV30,
+ AV_PIX_FMT_VUYX,
+ AV_PIX_FMT_Y212,
+ AV_PIX_FMT_Y210,
+ AV_PIX_FMT_YUYV422,
+};
+
+static const enum AVPixelFormat subsampled_list[] = {
+ AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_YUV444P,
+};
+
+static const enum AVPixelFormat depthchroma_list[] = {
+ AV_PIX_FMT_YUV420P14,
+ AV_PIX_FMT_YUV422P14,
+ AV_PIX_FMT_YUV444P16,
+};
+
+typedef enum AVPixelFormat (*find_best_t)(enum AVPixelFormat pixfmt);
+
+#define find_best_wrapper(name, list) \
+static enum AVPixelFormat find_best_ ## name (enum AVPixelFormat pixfmt) \
+{ \
+ enum AVPixelFormat best = AV_PIX_FMT_NONE; \
+ int i; \
+ for (i = 0; i < FF_ARRAY_ELEMS(list); i++) \
+ best = av_find_best_pix_fmt_of_2(best, list[i], \
+ pixfmt, 0, NULL); \
+ return best; \
+}
+
+find_best_wrapper(base, pixfmt_list)
+find_best_wrapper(seminplanar, semiplanar_list)
+find_best_wrapper(packed, packed_list)
+find_best_wrapper(subsampled, subsampled_list)
+find_best_wrapper(depthchroma, depthchroma_list)
+
+static void test(enum AVPixelFormat input, enum AVPixelFormat expected,
+ int *pass, int *fail, find_best_t find_best_fn)
{
- enum AVPixelFormat best = AV_PIX_FMT_NONE;
- int i;
- for (i = 0; i < FF_ARRAY_ELEMS(pixfmt_list); i++)
- best = av_find_best_pix_fmt_of_2(best, pixfmt_list[i],
- pixfmt, 0, NULL);
- return best;
+ enum AVPixelFormat output = find_best_fn(input);
+ if (output != expected) {
+ printf("Matching %s: got %s, expected %s\n",
+ av_get_pix_fmt_name(input),
+ av_get_pix_fmt_name(output),
+ av_get_pix_fmt_name(expected));
+ ++(*fail);
+ } else
+ ++(*pass);
}
int main(void)
{
- enum AVPixelFormat output;
int i, pass = 0, fail = 0;
-#define TEST(input, expected) do { \
- output = find_best(input); \
- if (output != expected) { \
- printf("Matching %s: got %s, expected %s\n", \
- av_get_pix_fmt_name(input), \
- av_get_pix_fmt_name(output), \
- av_get_pix_fmt_name(expected)); \
- ++fail; \
- } else \
- ++pass; \
- } while (0)
+#define TEST(input, expected) \
+ test(input, expected, &pass, &fail, find_best_base)
// Same formats.
for (i = 0; i < FF_ARRAY_ELEMS(pixfmt_list); i++)
@@ -137,6 +179,55 @@ int main(void)
// Opaque formats are least unlike each other.
TEST(AV_PIX_FMT_DXVA2_VLD, AV_PIX_FMT_VDPAU);
+#define TEST_SEMIPLANAR(input, expected) \
+ test(input, expected, &pass, &fail, find_best_seminplanar)
+
+ // Same formats.
+ for (i = 0; i < FF_ARRAY_ELEMS(semiplanar_list); i++)
+ TEST_SEMIPLANAR(semiplanar_list[i], semiplanar_list[i]);
+
+ // Formats containing the same data in different layouts.
+ TEST_SEMIPLANAR(AV_PIX_FMT_YUV420P, AV_PIX_FMT_NV12);
+ TEST_SEMIPLANAR(AV_PIX_FMT_YUV420P10, AV_PIX_FMT_P010);
+ TEST_SEMIPLANAR(AV_PIX_FMT_YUV420P12, AV_PIX_FMT_P012);
+ TEST_SEMIPLANAR(AV_PIX_FMT_YUV420P16, AV_PIX_FMT_P016);
+ TEST_SEMIPLANAR(AV_PIX_FMT_YUV420P9, AV_PIX_FMT_P010);
+
+#define TEST_PACKED(input, expected) \
+ test(input, expected, &pass, &fail, find_best_packed)
+
+ // Same formats.
+ for (i = 0; i < FF_ARRAY_ELEMS(packed_list); i++)
+ TEST_PACKED(packed_list[i], packed_list[i]);
+
+ // Formats containing the same data in different layouts.
+ TEST_PACKED(AV_PIX_FMT_YUV444P, AV_PIX_FMT_VUYX);
+ TEST_PACKED(AV_PIX_FMT_YUV444P10, AV_PIX_FMT_XV30);
+ TEST_PACKED(AV_PIX_FMT_YUV444P12, AV_PIX_FMT_XV36);
+ TEST_PACKED(AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUYV422);
+ TEST_PACKED(AV_PIX_FMT_YUV422P10, AV_PIX_FMT_Y210);
+ TEST_PACKED(AV_PIX_FMT_YUV422P12, AV_PIX_FMT_Y212);
+
+#define TEST_SUBSAMPLED(input, expected) \
+ test(input, expected, &pass, &fail, find_best_subsampled)
+
+ // Same formats.
+ for (i = 0; i < FF_ARRAY_ELEMS(subsampled_list); i++)
+ TEST_SUBSAMPLED(subsampled_list[i], subsampled_list[i]);
+
+ TEST_SUBSAMPLED(AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV420P);
+
+#define TEST_DEPTH_CHROMA(input, expected) \
+ test(input, expected, &pass, &fail, find_best_depthchroma)
+
+ // Same formats.
+ for (i = 0; i < FF_ARRAY_ELEMS(depthchroma_list); i++)
+ TEST_DEPTH_CHROMA(depthchroma_list[i], depthchroma_list[i]);
+
+ TEST_DEPTH_CHROMA(AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV444P16);
+ TEST_DEPTH_CHROMA(AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16);
+
+
printf("%d tests passed, %d tests failed.\n", pass, fail);
return !!fail;
}
diff --git a/libavutil/version.h b/libavutil/version.h
index 9b8462c705..0585fa7b80 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -80,7 +80,7 @@
#define LIBAVUTIL_VERSION_MAJOR 57
#define LIBAVUTIL_VERSION_MINOR 36
-#define LIBAVUTIL_VERSION_MICRO 101
+#define LIBAVUTIL_VERSION_MICRO 102
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
LIBAVUTIL_VERSION_MINOR, \
diff --git a/tests/ref/fate/pixfmt_best b/tests/ref/fate/pixfmt_best
index 783c5fe640..1bdc0e83f0 100644
--- a/tests/ref/fate/pixfmt_best
+++ b/tests/ref/fate/pixfmt_best
@@ -1 +1 @@
-75 tests passed, 0 tests failed.
+106 tests passed, 0 tests failed.