Commit ac29054f authored by Janne Grunau's avatar Janne Grunau

imgconvert: add avcodec_find_best_pix_fmt2()

The number of pixel formats outgrew the number of available bits in
the bitmask used in avcodec_find_best_pix_fmt().
avcodec_find_best_pix_fmt2() uses a PIX_FMT_NONE terminated list
of pixel formats instead.
parent 39bb27bf
...@@ -4227,6 +4227,27 @@ int avcodec_get_pix_fmt_loss(enum PixelFormat dst_pix_fmt, enum PixelFormat src_ ...@@ -4227,6 +4227,27 @@ int avcodec_get_pix_fmt_loss(enum PixelFormat dst_pix_fmt, enum PixelFormat src_
enum PixelFormat avcodec_find_best_pix_fmt(int64_t pix_fmt_mask, enum PixelFormat src_pix_fmt, enum PixelFormat avcodec_find_best_pix_fmt(int64_t pix_fmt_mask, enum PixelFormat src_pix_fmt,
int has_alpha, int *loss_ptr); int has_alpha, int *loss_ptr);
/**
* Find the best pixel format to convert to given a certain source pixel
* format. When converting from one pixel format to another, information loss
* may occur. For example, when converting from RGB24 to GRAY, the color
* information will be lost. Similarly, other losses occur when converting from
* some formats to other formats. avcodec_find_best_pix_fmt2() searches which of
* the given pixel formats should be used to suffer the least amount of loss.
* The pixel formats from which it chooses one, are determined by the
* pix_fmt_list parameter.
*
*
* @param[in] pix_fmt_list PIX_FMT_NONE terminated array of pixel formats to choose from
* @param[in] src_pix_fmt source pixel format
* @param[in] has_alpha Whether the source pixel format alpha channel is used.
* @param[out] loss_ptr Combination of flags informing you what kind of losses will occur.
* @return The best pixel format to convert to or -1 if none was found.
*/
enum PixelFormat avcodec_find_best_pix_fmt2(enum PixelFormat *pix_fmt_list,
enum PixelFormat src_pix_fmt,
int has_alpha, int *loss_ptr);
enum PixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum PixelFormat * fmt); enum PixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum PixelFormat * fmt);
/** /**
......
...@@ -588,7 +588,7 @@ static int avg_bits_per_pixel(enum PixelFormat pix_fmt) ...@@ -588,7 +588,7 @@ static int avg_bits_per_pixel(enum PixelFormat pix_fmt)
return bits; return bits;
} }
static enum PixelFormat avcodec_find_best_pix_fmt1(int64_t pix_fmt_mask, static enum PixelFormat avcodec_find_best_pix_fmt1(enum PixelFormat *pix_fmt_list,
enum PixelFormat src_pix_fmt, enum PixelFormat src_pix_fmt,
int has_alpha, int has_alpha,
int loss_mask) int loss_mask)
...@@ -599,24 +599,48 @@ static enum PixelFormat avcodec_find_best_pix_fmt1(int64_t pix_fmt_mask, ...@@ -599,24 +599,48 @@ static enum PixelFormat avcodec_find_best_pix_fmt1(int64_t pix_fmt_mask,
/* find exact color match with smallest size */ /* find exact color match with smallest size */
dst_pix_fmt = PIX_FMT_NONE; dst_pix_fmt = PIX_FMT_NONE;
min_dist = 0x7fffffff; min_dist = 0x7fffffff;
/* test only the first 64 pixel formats to avoid undefined behaviour */ i = 0;
for (i = 0; i < 64; i++) { while (pix_fmt_list[i] != PIX_FMT_NONE) {
if (pix_fmt_mask & (1ULL << i)) { enum PixelFormat pix_fmt = pix_fmt_list[i];
loss = avcodec_get_pix_fmt_loss(i, src_pix_fmt, has_alpha) & loss_mask;
if (loss == 0) { if (i > PIX_FMT_NB) {
dist = avg_bits_per_pixel(i); av_log(NULL, AV_LOG_ERROR, "Pixel format list longer than expected, "
if (dist < min_dist) { "it is either not properly terminated or contains duplicates\n");
min_dist = dist; return PIX_FMT_NONE;
dst_pix_fmt = i; }
}
loss = avcodec_get_pix_fmt_loss(pix_fmt, src_pix_fmt, has_alpha) & loss_mask;
if (loss == 0) {
dist = avg_bits_per_pixel(pix_fmt);
if (dist < min_dist) {
min_dist = dist;
dst_pix_fmt = pix_fmt;
} }
} }
i++;
} }
return dst_pix_fmt; return dst_pix_fmt;
} }
enum PixelFormat avcodec_find_best_pix_fmt(int64_t pix_fmt_mask, enum PixelFormat src_pix_fmt, enum PixelFormat avcodec_find_best_pix_fmt(int64_t pix_fmt_mask, enum PixelFormat src_pix_fmt,
int has_alpha, int *loss_ptr) int has_alpha, int *loss_ptr)
{
enum PixelFormat list[64];
int i, j = 0;
// test only the first 64 pixel formats to avoid undefined behaviour
for (i = 0; i < 64; i++) {
if (pix_fmt_mask & (1ULL << i))
list[j++] = i;
}
list[j] = PIX_FMT_NONE;
return avcodec_find_best_pix_fmt2(list, src_pix_fmt, has_alpha, loss_ptr);
}
enum PixelFormat avcodec_find_best_pix_fmt2(enum PixelFormat *pix_fmt_list,
enum PixelFormat src_pix_fmt,
int has_alpha, int *loss_ptr)
{ {
enum PixelFormat dst_pix_fmt; enum PixelFormat dst_pix_fmt;
int loss_mask, i; int loss_mask, i;
...@@ -634,7 +658,7 @@ enum PixelFormat avcodec_find_best_pix_fmt(int64_t pix_fmt_mask, enum PixelForma ...@@ -634,7 +658,7 @@ enum PixelFormat avcodec_find_best_pix_fmt(int64_t pix_fmt_mask, enum PixelForma
i = 0; i = 0;
for(;;) { for(;;) {
loss_mask = loss_mask_order[i++]; loss_mask = loss_mask_order[i++];
dst_pix_fmt = avcodec_find_best_pix_fmt1(pix_fmt_mask, src_pix_fmt, dst_pix_fmt = avcodec_find_best_pix_fmt1(pix_fmt_list, src_pix_fmt,
has_alpha, loss_mask); has_alpha, loss_mask);
if (dst_pix_fmt >= 0) if (dst_pix_fmt >= 0)
goto found; goto found;
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
*/ */
#define LIBAVCODEC_VERSION_MAJOR 54 #define LIBAVCODEC_VERSION_MAJOR 54
#define LIBAVCODEC_VERSION_MINOR 20 #define LIBAVCODEC_VERSION_MINOR 21
#define LIBAVCODEC_VERSION_MICRO 0 #define LIBAVCODEC_VERSION_MICRO 0
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment