imgconvert: add get_pix_fmt_score()
authorMichael Niedermayer <michaelni@gmx.at>
Sun, 10 Feb 2013 00:04:57 +0000 (01:04 +0100)
committerMichael Niedermayer <michaelni@gmx.at>
Sun, 10 Feb 2013 01:14:52 +0000 (02:14 +0100)
get_pix_fmt_score() returns a score representing the amount
of loss when converting a pixel format

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
libavcodec/imgconvert.c

index 5c3ec39..e5d5d70 100644 (file)
@@ -104,24 +104,25 @@ static int get_pix_fmt_depth(int *min, int *max, enum AVPixelFormat pix_fmt)
     return 0;
 }
 
-int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt,
-                             enum AVPixelFormat src_pix_fmt,
-                             int has_alpha)
+static int get_pix_fmt_score(enum AVPixelFormat dst_pix_fmt,
+                              enum AVPixelFormat src_pix_fmt,
+                              unsigned *lossp, unsigned consider)
 {
     const AVPixFmtDescriptor *src_desc = av_pix_fmt_desc_get(src_pix_fmt);
     const AVPixFmtDescriptor *dst_desc = av_pix_fmt_desc_get(dst_pix_fmt);
     int src_color, dst_color;
     int src_min_depth, src_max_depth, dst_min_depth, dst_max_depth;
     int ret, loss, i, nb_components;
+    int score = INT_MAX;
 
     if (dst_pix_fmt >= AV_PIX_FMT_NB || dst_pix_fmt <= AV_PIX_FMT_NONE)
         return ~0;
 
     /* compute loss */
-    loss = 0;
+    *lossp = loss = 0;
 
     if (dst_pix_fmt == src_pix_fmt)
-        return 0;
+        return INT_MAX;
 
     if ((ret = get_pix_fmt_depth(&src_min_depth, &src_max_depth, src_pix_fmt)) < 0)
         return ret;
@@ -133,13 +134,28 @@ int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt,
     nb_components = FFMIN(src_desc->nb_components, dst_desc->nb_components);
 
     for (i = 0; i < nb_components; i++)
-        if (src_desc->comp[i].depth_minus1 > dst_desc->comp[i].depth_minus1)
+        if (src_desc->comp[i].depth_minus1 > dst_desc->comp[i].depth_minus1 && (consider & FF_LOSS_DEPTH)) {
             loss |= FF_LOSS_DEPTH;
+            score -= 65536 >> dst_desc->comp[i].depth_minus1;
+        }
 
-    if (dst_desc->log2_chroma_w > src_desc->log2_chroma_w ||
-        dst_desc->log2_chroma_h > src_desc->log2_chroma_h)
-        loss |= FF_LOSS_RESOLUTION;
+    if (consider & FF_LOSS_RESOLUTION) {
+        if (dst_desc->log2_chroma_w > src_desc->log2_chroma_w) {
+            loss |= FF_LOSS_RESOLUTION;
+            score -= 256 << dst_desc->log2_chroma_w;
+        }
+        if (dst_desc->log2_chroma_h > src_desc->log2_chroma_h) {
+            loss |= FF_LOSS_RESOLUTION;
+            score -= 256 << dst_desc->log2_chroma_h;
+        }
+        // dont favor 422 over 420 if downsampling is needed, because 420 has much better support on the decoder side
+        if (dst_desc->log2_chroma_w == 1 && src_desc->log2_chroma_w == 0 &&
+            dst_desc->log2_chroma_h == 1 && src_desc->log2_chroma_h == 0 ) {
+            score += 512;
+        }
+    }
 
+    if(consider & FF_LOSS_COLORSPACE)
     switch(dst_color) {
     case FF_COLOR_RGB:
         if (src_color != FF_COLOR_RGB &&
@@ -166,15 +182,36 @@ int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt,
             loss |= FF_LOSS_COLORSPACE;
         break;
     }
+    if(loss & FF_LOSS_COLORSPACE)
+        score -= (nb_components * 65536) >> FFMIN(dst_desc->comp[0].depth_minus1, src_desc->comp[0].depth_minus1);
+
     if (dst_color == FF_COLOR_GRAY &&
-        src_color != FF_COLOR_GRAY)
+        src_color != FF_COLOR_GRAY && (consider & FF_LOSS_CHROMA)) {
         loss |= FF_LOSS_CHROMA;
-    if (!pixdesc_has_alpha(dst_desc) && (pixdesc_has_alpha(src_desc) && has_alpha))
+        score -= 2 * 65536;
+    }
+    if (!pixdesc_has_alpha(dst_desc) && (pixdesc_has_alpha(src_desc) && (consider & FF_LOSS_ALPHA))) {
         loss |= FF_LOSS_ALPHA;
-    if (dst_pix_fmt == AV_PIX_FMT_PAL8 &&
-        (src_pix_fmt != AV_PIX_FMT_PAL8 && (src_color != FF_COLOR_GRAY || (pixdesc_has_alpha(src_desc) && has_alpha))))
+        score -= 65536;
+    }
+    if (dst_pix_fmt == AV_PIX_FMT_PAL8 && (consider & FF_LOSS_COLORQUANT) &&
+        (src_pix_fmt != AV_PIX_FMT_PAL8 && (src_color != FF_COLOR_GRAY || (pixdesc_has_alpha(src_desc) && (consider & FF_LOSS_ALPHA))))) {
         loss |= FF_LOSS_COLORQUANT;
+        score -= 65536;
+    }
+
+    *lossp = loss;
+    return score;
+}
 
+int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt,
+                             enum AVPixelFormat src_pix_fmt,
+                             int has_alpha)
+{
+    int loss;
+    int ret = get_pix_fmt_score(dst_pix_fmt, src_pix_fmt, &loss, has_alpha ? ~0 : ~FF_LOSS_ALPHA);
+    if (ret < 0)
+        return ret;
     return loss;
 }