[MPlayer-dev-eng] [RFC] Updated color management patch
Reimar Döffinger
Reimar.Doeffinger at gmx.de
Tue Jan 19 23:28:14 CET 2010
Sorry for not reviewing properly, it's just too large for that...
On Tue, Jan 19, 2010 at 10:59:27AM -0500, Yue Shi Lai wrote:
> @@ -911,6 +912,10 @@ VIDIX_OBJS = $(filter vidix/%,$(SRCS_MPL
>
> $(VIDIX_DEPS) $(VIDIX_OBJS): $(VIDIX_PCI_FILES)
>
> +PROFILEDIR = $(DATADIR)/icc
> +
> +libmpcodecs/vf_cm%: CFLAGS += -DPROFILEDIR=\"$(PROFILEDIR)\"
I suspect this belongs in config.h
> +echocheck "Little CMS"
> +if test "$_lcms" = auto ; then
> + _lcms=no
> + def_lcms='#undef LCMS'
Doesn't set def_lcms when --disable-lcms is used.
> +#include <lcms.h>
> +int main(void) { return 0; }
> +EOF
> + cc_check -llcms && _lcms=yes
No reliable, you should actually use a symbol from liblcms
> --- mplayer/libmpcodecs/vf.c 2010-01-18 17:52:31.000000000 +0000
> +++ mplayer-vf_cm/libmpcodecs/vf.c 2010-01-18 21:12:21.000000000 +0000
> @@ -48,6 +48,9 @@ extern const vf_info_t vf_info_yvu9;
> extern const vf_info_t vf_info_lavcdeint;
> extern const vf_info_t vf_info_eq;
> extern const vf_info_t vf_info_eq2;
> +#ifdef LCMS
> +extern const vf_info_t vf_info_cm;
> +#endif /* LCMS */
Use less ifdef
> +/*** Algorithmic behavior ******************************************/
> +
> +#ifndef PATH_MAX
> +#define PATH_MAX 4096 /* Maximum size of the file names */
> +#endif /* PATH_MAX */
I don't think that comment line fits quite there.
> +#define NGAMMA 1024 /* Sampling points for tone
> + reproduction curve (TRC) */
> +#define CMS_PIXELFMT TYPE_RGB_8 /* Pixel format used in CMS */
> +#define CMS_STRIDE 3 /* Size of CMS_PIXELFMT, >= 3 */
> +#define CLUT_STRIDE 3 /* Size per CLUT pixel, >= 3 */
> +/* The default CLUT used in this filter is an 65 point (per channel),
> + which is twice the (linear) size typically used by CMM */
> +#define CLUT_DECIMATION 4 /* Inexact CLUT spline decimation */
> +#define GAMUT_WARN_GRAY 153 /* Default gamut warning gray */
And since you already have comments you might as well make the doxygen-compatible.
E.g. by using ///<
> + * @param[out] trc the tone reproduction curve in Little CMS format
> + */
> +static void itu_rec709_trc(LPGAMMATABLE *trc)
Makes more sense to make this the return value than an argument.
> + pclut[stride] = av_clip_uint8(
> + (33 * pclut[0] +
> + 28 * pclut[4 * stride] +
> + 3 * pclut[8 * stride]) >> 6);
> + pclut[2 * stride] = av_clip_uint8(
> + (pclut[0] + 3 * pclut[4 * stride]) >> 2);
> + pclut[3 * stride] = av_clip_uint8(
> + ( 7 * pclut[0] +
> + 60 * pclut[4 * stride] -
> + 3 * pclut[8 * stride]) >> 6);
A few intermediate variables would probably help readability a lot.
> + /* Aligned body, 1st pass */
> + asm (
Better use
__asm__
> + /* End of loop */
> + "loop 1b"
Isn't loop generally considered one of the worst instructions to use?
> + : "=m" (factor[0]), "=m" (factor[1]), "=m" (factor[2]),
> + /* 3 */
> + "=m" (factor[3]), "=m" (factor[4])
> + : /* 5 */
> + "m" (factor[0]), "m" (factor[1]), "m" (factor[2]),
> + /* 8 */
> + "m" (factor[3]), "m" (factor[4]),
> + /* 10 */
> + "g" (pclut), "r" (stride), "g" (count)
> + : "%" REG_c, "%" REG_d, "%" REG_D,
> + "%xmm0", "%xmm1", "%xmm2", "%xmm3",
> + "%xmm4", "%xmm5", "%xmm6", "%xmm7");
I suspect you really need to hope for gcc to have a good day to be
able to compile this.
However you are specifying the same variable multiple time, even if
that's valid I doubt whether it means what you want it to.
I suspect something like
> + : "+&m" (factor[0]), "+&m" (factor[1]), "+&m" (factor[2]),
> + "+&m" (factor[3]), "+&m" (factor[4])
> + : "g" (pclut), "r" (stride), "g" (count)
or the for x86 needlessly verbose variant of
> + : "=m" (factor[0]), "=m" (factor[1]), "=m" (factor[2]),
> + /* 3 */
> + "=m" (factor[3]), "=m" (factor[4])
> + : /* 5 */
> + "0" (factor[0]), "1" (factor[1]), "2" (factor[2]),
> + /* 8 */
> + "3" (factor[3]), "4" (factor[4]),
> + /* 10 */
> + "g" (pclut), "r" (stride), "g" (count)
Are at least more correct.
> + : "%" REG_a, "%" REG_d, "%" REG_S, "%" REG_D,
And temporary variables with "=&r" contraints give more flexibilty
on 64 bit systems.
> + "g" (pclut), "r" (stride), "g" (count)
> + : "%" REG_a, "%" REG_c, "%" REG_d, "%" REG_S, "%" REG_D,
Has no chance to compile on x86 systems with PIC enabled.
While we don't really support them, breaking them is not so great still.
> + const size_t alignment = (size_t)clut & 7;
> + const unsigned int head = alignment == 0 ? 0 : 8 - alignment;
(8 - alignment) & 7
or quick and ugly
-clut & 7
> +static const char *trc_name(const unsigned int trc_type)
I consider that const kind of const for the argument a hindrance at
best, not that I mind much though.
However using a enum for the type might make sense...
> + /* Clip the source black point */
> + if(source_black_point.L > 50)
> + source_black_point.L = 50;
FFMIN?
> + a = sum_x * (sum_x3 * sum_y + sum_x2 * sum_x_y -
> + sum_x * sum_x2_y) +
> + n * (sum_x2 * sum_x2_y - sum_x3 * sum_x_y) -
> + sum_x2 * sum_x2 * sum_y;
> + b = sum_x * (sum_x2 * sum_x2_y - sum_x4 * sum_y) +
> + n * (sum_x4 * sum_x_y - sum_x3 * sum_x2_y) +
> + sum_x2 * (sum_x3 * sum_y - sum_x2 * sum_x_y);
> + c = sum_x3 * (sum_x * sum_x2_y + sum_x2 * sum_x_y -
> + sum_x3 * sum_y) +
> + sum_x2 * (sum_x4 * sum_y - sum_x2 * sum_x2_y) -
> + sum_x * sum_x4 * sum_x_y;
I'd suspect there might be a more human-readable way to write that.
> + static const char *suffix[] = {
static const char * const suffix[] = {
> + static const char *user_directory[] = {
static const char * const user_directory[] = {
> + char *path[] = {
> + directory[0], directory[1], directory[2],
const char *
and use directory[i] where you write then instead path[i]
> + snprintf(path[i], PATH_MAX, "%s/%s",
> + home_directory, user_directory[i]);
> + /* Enforce path string termination */
> + path[i][PATH_MAX - 1] = '\0';
snprintf does guarantee that already.
> + /* Wee need to intercept inaccessible ICC files now, or Little CMS
> + might terminate MPlayer abruptly, and corrupting the terminal
> + line. */
> + if(fp == NULL) {
That's a rather serious bug for a library and a workaround does not really belong
in MPlayer (a corrupted terminal is not exactly the end of the world).
> + default:
> + /* This should never happen */
The assert(0) is the most appropriate code for it.
> + if(p->lcms_src_profile == NULL)
> + if(!create_profile(&p->lcms_src_profile, p->src_prim,
> + p->src_trc_type, p->src_gamma, "Source"))
if(!p->lcms_src_profile)
would be more consitent
> + /* Print out the ICC intent of the transformation, see also
> + http://www.color.org/profile.html */
> + mp_msg(MSGT_VFILTER, MSGL_INFO, "[cm] "
> + "Using %s intent\n",
> + p->intent == INTENT_PERCEPTUAL ? "perceptual" :
> + p->intent == INTENT_RELATIVE_COLORIMETRIC ?
> + "media-relative colorimetric" :
> + p->intent == INTENT_SATURATION ? "saturation" :
> + p->intent == INTENT_ABSOLUTE_COLORIMETRIC ?
> + "ICC-absolute colorimetric" : "unknown");
Ugh, unreadable. Use a funtion, possibly with a lookup table or something
to get the string.
> + /* Compute the CLUT */
> + p->clut = (uint8_t *)malloc(
useless cast.
> + p->clut_resolution * p->clut_resolution * p->clut_resolution *
> + CLUT_STRIDE * sizeof(uint8_t));
* sizeof(uint8_t) is quite pointless, sizeof(*p->clut) might make sense.
> + /* For efficiency, generate one plane each time and
> + perform the CMM transform on the whole plane. */
> + uint8_t buf_in_rgb[planesize * CMS_STRIDE];
> + uint8_t buf_out_rgb[planesize * CMS_STRIDE];
I don't think that large arrays should be placed on the stack.
> + buf_pixel[1] = cb <= 255 ? cb : 255;
FFMIN(cb, 255)
And there are many like those.
> +#if 0
> + {
> + /* Test code: write out the CLUT */
#define DUMP_CLUT 0
if (DUMP_CLUT) {
...
will ensure that debug code will still compile by the time someone tries to use it.
> + uint16_t y_avg =
> + ((uint16_t)py_in[0] + (uint16_t)py_in[1] +
> + (uint16_t)py_in1[0] + (uint16_t)py_in1[1] + 2) >> 2;
What is supposed to be the point of those casts?
> + (*g_cm.clut_src_pixfmt == IMGFMT_YV12 ||
> + *g_cm.clut_src_pixfmt == IMGFMT_I420 ||
> + *g_cm.clut_src_pixfmt == IMGFMT_IYUV) &&
> + const uint8_t uint8_y =
> + av_clip_uint8(y * *g_cm.clut_resolution);
> + const uint8_t uint8_cb =
> + av_clip_uint8(cb * *g_cm.clut_resolution);
> + const uint8_t uint8_cr =
> + av_clip_uint8(cr * *g_cm.clut_resolution);
> + const size_t offset =
> + ((uint8_cb * *g_cm.clut_resolution +
> + uint8_cr) * *g_cm.clut_resolution +
> + uint8_y) * g_cm.clut_stride;
A local variable for those often-used values shoudl improve
readability.
And those uint8_cb etc. names make it really hard to read since
types and names are hardly distinguishable.
> + static opt_t opt[] = {
static const nowadays
> + if(optval.src_prim) {
> + if(optval.src_prim[0] != '\0') {
> + if(optval.src_trc) {
> + if(optval.src_trc[0] != '\0') {
> + if(optval.dest_prim) {
> + if(optval.dest_prim[0] != '\0') {
> + if(optval.dest_trc) {
> + if(optval.dest_trc[0] != '\0') {
> + if(optval.intent) {
> + if(optval.intent[0] != '\0') {
Merge the ifs, you can call free unconditionally.
> + vf->priv = malloc(sizeof(struct vf_priv_s));
calloc should make some of the explicit initializations unnecessary.
> @@ -1084,6 +1113,11 @@ static void create_conv_textures(gl_conv
> texs[0] = (*texu)++;
> ActiveTexture(GL_TEXTURE0 + texs[0]);
> lookup_data = malloc(3 * sz * sz * sz);
> +#ifdef LCMS
> + if(vf_cm_clut_is_ycbcr_to_rgb())
> + gen_yuv2rgb_map_cm(params, lookup_data, LOOKUP_3DRES);
> + else
> +#endif /* LCMS */
> mp_gen_yuv2rgb_map(¶ms->csp_params, lookup_data, LOOKUP_3DRES);
I think it would be better if mp_gen_yuv2rgb_map used gen_yuv2rgb_map_cm when requested.
> diff -urNp mplayer/libvo/vo_gl.c mplayer-vf_cm/libvo/vo_gl.c
> --- mplayer/libvo/vo_gl.c 2010-01-18 17:52:40.000000000 +0000
> +++ mplayer-vf_cm/libvo/vo_gl.c 2010-01-18 21:09:44.000000000 +0000
> @@ -36,6 +36,9 @@
> #endif
> #include "fastmemcpy.h"
> #include "libass/ass_mp.h"
> +#ifdef LCMS
> +#include "libmpcodecs/vf_cm.h"
> +#endif /* LCMS */
>
> static const vo_info_t info =
> {
> @@ -1160,6 +1163,9 @@ static int preinit(const char *arg)
> mp_msg(MSGT_VO, MSGL_V, "[gl] Using %d as slice height "
> "(0 means image height).\n", slice_height);
> if (!init_mpglcontext(&glctx, gltype)) return -1;
> +#ifdef LCMS
> + vf_cm_set_vo_clut_lookup();
> +#endif /* LCMS */
Can't that somehow be handled by gen_yuv2rgb_map_cm?
More information about the MPlayer-dev-eng
mailing list