Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * ColorMatrix v2.2 for Avisynth 2.5.x
  3.  *
  4.  * Copyright (C) 2006-2007 Kevin Stone
  5.  *
  6.  * ColorMatrix 1.x is Copyright (C) Wilbert Dijkhof
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify it
  9.  * under the terms of the GNU General Public License as published by the
  10.  * Free Software Foundation; either version 2 of the License, or (at your
  11.  * option) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful, but
  14.  * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  15.  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
  16.  * License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software Foundation,
  20.  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  21.  */
  22.  
  23. /**
  24.  * @file
  25.  * ColorMatrix 2.0 is based on the original ColorMatrix filter by Wilbert
  26.  * Dijkhof.  It adds the ability to convert between any of: Rec.709, FCC,
  27.  * Rec.601, and SMPTE 240M. It also makes pre and post clipping optional,
  28.  * adds an option to use scaled or non-scaled coefficients, and more...
  29.  */
  30.  
  31. #include <float.h>
  32. #include "avfilter.h"
  33. #include "formats.h"
  34. #include "internal.h"
  35. #include "video.h"
  36. #include "libavutil/opt.h"
  37. #include "libavutil/pixdesc.h"
  38. #include "libavutil/avstring.h"
  39.  
  40. #define NS(n) n < 0 ? (int)(n*65536.0-0.5+DBL_EPSILON) : (int)(n*65536.0+0.5)
  41. #define CB(n) av_clip_uint8(n)
  42.  
  43. static const double yuv_coeff[4][3][3] = {
  44.     { { +0.7152, +0.0722, +0.2126 }, // Rec.709 (0)
  45.       { -0.3850, +0.5000, -0.1150 },
  46.       { -0.4540, -0.0460, +0.5000 } },
  47.     { { +0.5900, +0.1100, +0.3000 }, // FCC (1)
  48.       { -0.3310, +0.5000, -0.1690 },
  49.       { -0.4210, -0.0790, +0.5000 } },
  50.     { { +0.5870, +0.1140, +0.2990 }, // Rec.601 (ITU-R BT.470-2/SMPTE 170M) (2)
  51.       { -0.3313, +0.5000, -0.1687 },
  52.       { -0.4187, -0.0813, +0.5000 } },
  53.     { { +0.7010, +0.0870, +0.2120 }, // SMPTE 240M (3)
  54.       { -0.3840, +0.5000, -0.1160 },
  55.       { -0.4450, -0.0550, +0.5000 } },
  56. };
  57.  
  58. enum ColorMode {
  59.     COLOR_MODE_NONE = -1,
  60.     COLOR_MODE_BT709,
  61.     COLOR_MODE_FCC,
  62.     COLOR_MODE_BT601,
  63.     COLOR_MODE_SMPTE240M,
  64.     COLOR_MODE_COUNT
  65. };
  66.  
  67. typedef struct {
  68.     const AVClass *class;
  69.     int yuv_convert[16][3][3];
  70.     int interlaced;
  71.     enum ColorMode source, dest;
  72.     int mode;
  73.     int hsub, vsub;
  74. } ColorMatrixContext;
  75.  
  76. #define OFFSET(x) offsetof(ColorMatrixContext, x)
  77. #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
  78.  
  79. static const AVOption colormatrix_options[] = {
  80.     { "src", "set source color matrix",      OFFSET(source), AV_OPT_TYPE_INT, {.i64=COLOR_MODE_NONE}, COLOR_MODE_NONE, COLOR_MODE_COUNT-1, .flags=FLAGS, .unit="color_mode" },
  81.     { "dst", "set destination color matrix", OFFSET(dest),   AV_OPT_TYPE_INT, {.i64=COLOR_MODE_NONE}, COLOR_MODE_NONE, COLOR_MODE_COUNT-1, .flags=FLAGS, .unit="color_mode" },
  82.     { "bt709",     "set BT.709 colorspace",      0, AV_OPT_TYPE_CONST, {.i64=COLOR_MODE_BT709},       .flags=FLAGS, .unit="color_mode" },
  83.     { "fcc",       "set FCC colorspace   ",      0, AV_OPT_TYPE_CONST, {.i64=COLOR_MODE_FCC},         .flags=FLAGS, .unit="color_mode" },
  84.     { "bt601",     "set BT.601 colorspace",      0, AV_OPT_TYPE_CONST, {.i64=COLOR_MODE_BT601},       .flags=FLAGS, .unit="color_mode" },
  85.     { "smpte240m", "set SMPTE-240M colorspace",  0, AV_OPT_TYPE_CONST, {.i64=COLOR_MODE_SMPTE240M},   .flags=FLAGS, .unit="color_mode" },
  86.     { NULL }
  87. };
  88.  
  89. AVFILTER_DEFINE_CLASS(colormatrix);
  90.  
  91. #define ma m[0][0]
  92. #define mb m[0][1]
  93. #define mc m[0][2]
  94. #define md m[1][0]
  95. #define me m[1][1]
  96. #define mf m[1][2]
  97. #define mg m[2][0]
  98. #define mh m[2][1]
  99. #define mi m[2][2]
  100.  
  101. #define ima im[0][0]
  102. #define imb im[0][1]
  103. #define imc im[0][2]
  104. #define imd im[1][0]
  105. #define ime im[1][1]
  106. #define imf im[1][2]
  107. #define img im[2][0]
  108. #define imh im[2][1]
  109. #define imi im[2][2]
  110.  
  111. static void inverse3x3(double im[3][3], const double m[3][3])
  112. {
  113.     double det = ma * (me * mi - mf * mh) - mb * (md * mi - mf * mg) + mc * (md * mh - me * mg);
  114.     det = 1.0 / det;
  115.     ima = det * (me * mi - mf * mh);
  116.     imb = det * (mc * mh - mb * mi);
  117.     imc = det * (mb * mf - mc * me);
  118.     imd = det * (mf * mg - md * mi);
  119.     ime = det * (ma * mi - mc * mg);
  120.     imf = det * (mc * md - ma * mf);
  121.     img = det * (md * mh - me * mg);
  122.     imh = det * (mb * mg - ma * mh);
  123.     imi = det * (ma * me - mb * md);
  124. }
  125.  
  126. static void solve_coefficients(double cm[3][3], double rgb[3][3], const double yuv[3][3])
  127. {
  128.     int i, j;
  129.     for (i = 0; i < 3; i++)
  130.         for (j = 0; j < 3; j++)
  131.             cm[i][j] = yuv[i][0] * rgb[0][j] + yuv[i][1] * rgb[1][j] + yuv[i][2] * rgb[2][j];
  132. }
  133.  
  134. static void calc_coefficients(AVFilterContext *ctx)
  135. {
  136.     ColorMatrixContext *color = ctx->priv;
  137.     double rgb_coeffd[4][3][3];
  138.     double yuv_convertd[16][3][3];
  139.     int v = 0;
  140.     int i, j, k;
  141.  
  142.     for (i = 0; i < 4; i++)
  143.         inverse3x3(rgb_coeffd[i], yuv_coeff[i]);
  144.     for (i = 0; i < 4; i++) {
  145.         for (j = 0; j < 4; j++) {
  146.             solve_coefficients(yuv_convertd[v], rgb_coeffd[i], yuv_coeff[j]);
  147.             for (k = 0; k < 3; k++) {
  148.                 color->yuv_convert[v][k][0] = NS(yuv_convertd[v][k][0]);
  149.                 color->yuv_convert[v][k][1] = NS(yuv_convertd[v][k][1]);
  150.                 color->yuv_convert[v][k][2] = NS(yuv_convertd[v][k][2]);
  151.             }
  152.             if (color->yuv_convert[v][0][0] != 65536 || color->yuv_convert[v][1][0] != 0 ||
  153.                 color->yuv_convert[v][2][0] != 0) {
  154.                 av_log(ctx, AV_LOG_ERROR, "error calculating conversion coefficients\n");
  155.             }
  156.             v++;
  157.         }
  158.     }
  159. }
  160.  
  161. static const char *color_modes[] = {"bt709", "fcc", "bt601", "smpte240m"};
  162.  
  163. static av_cold int init(AVFilterContext *ctx)
  164. {
  165.     ColorMatrixContext *color = ctx->priv;
  166.  
  167.     if (color->source == COLOR_MODE_NONE || color->dest == COLOR_MODE_NONE) {
  168.         av_log(ctx, AV_LOG_ERROR, "Unspecified source or destination color space\n");
  169.         return AVERROR(EINVAL);
  170.     }
  171.  
  172.     if (color->source == color->dest) {
  173.         av_log(ctx, AV_LOG_ERROR, "Source and destination color space must not be identical\n");
  174.         return AVERROR(EINVAL);
  175.     }
  176.  
  177.     color->mode = color->source * 4 + color->dest;
  178.  
  179.     calc_coefficients(ctx);
  180.  
  181.     return 0;
  182. }
  183.  
  184. static void process_frame_uyvy422(ColorMatrixContext *color,
  185.                                   AVFrame *dst, AVFrame *src)
  186. {
  187.     const unsigned char *srcp = src->data[0];
  188.     const int src_pitch = src->linesize[0];
  189.     const int height = src->height;
  190.     const int width = src->width*2;
  191.     unsigned char *dstp = dst->data[0];
  192.     const int dst_pitch = dst->linesize[0];
  193.     const int c2 = color->yuv_convert[color->mode][0][1];
  194.     const int c3 = color->yuv_convert[color->mode][0][2];
  195.     const int c4 = color->yuv_convert[color->mode][1][1];
  196.     const int c5 = color->yuv_convert[color->mode][1][2];
  197.     const int c6 = color->yuv_convert[color->mode][2][1];
  198.     const int c7 = color->yuv_convert[color->mode][2][2];
  199.     int x, y;
  200.  
  201.     for (y = 0; y < height; y++) {
  202.         for (x = 0; x < width; x += 4) {
  203.             const int u = srcp[x + 0] - 128;
  204.             const int v = srcp[x + 2] - 128;
  205.             const int uvval = c2 * u + c3 * v + 1081344;
  206.             dstp[x + 0] = CB((c4 * u + c5 * v + 8421376) >> 16);
  207.             dstp[x + 1] = CB((65536 * (srcp[x + 1] - 16) + uvval) >> 16);
  208.             dstp[x + 2] = CB((c6 * u + c7 * v + 8421376) >> 16);
  209.             dstp[x + 3] = CB((65536 * (srcp[x + 3] - 16) + uvval) >> 16);
  210.         }
  211.         srcp += src_pitch;
  212.         dstp += dst_pitch;
  213.     }
  214. }
  215.  
  216. static void process_frame_yuv422p(ColorMatrixContext *color,
  217.                                   AVFrame *dst, AVFrame *src)
  218. {
  219.     const unsigned char *srcpU = src->data[1];
  220.     const unsigned char *srcpV = src->data[2];
  221.     const unsigned char *srcpY = src->data[0];
  222.     const int src_pitchY  = src->linesize[0];
  223.     const int src_pitchUV = src->linesize[1];
  224.     const int height = src->height;
  225.     const int width = src->width;
  226.     unsigned char *dstpU = dst->data[1];
  227.     unsigned char *dstpV = dst->data[2];
  228.     unsigned char *dstpY = dst->data[0];
  229.     const int dst_pitchY  = dst->linesize[0];
  230.     const int dst_pitchUV = dst->linesize[1];
  231.     const int c2 = color->yuv_convert[color->mode][0][1];
  232.     const int c3 = color->yuv_convert[color->mode][0][2];
  233.     const int c4 = color->yuv_convert[color->mode][1][1];
  234.     const int c5 = color->yuv_convert[color->mode][1][2];
  235.     const int c6 = color->yuv_convert[color->mode][2][1];
  236.     const int c7 = color->yuv_convert[color->mode][2][2];
  237.     int x, y;
  238.  
  239.     for (y = 0; y < height; y++) {
  240.         for (x = 0; x < width; x += 2) {
  241.             const int u = srcpU[x >> 1] - 128;
  242.             const int v = srcpV[x >> 1] - 128;
  243.             const int uvval = c2 * u + c3 * v + 1081344;
  244.             dstpY[x + 0] = CB((65536 * (srcpY[x + 0] - 16) + uvval) >> 16);
  245.             dstpY[x + 1] = CB((65536 * (srcpY[x + 1] - 16) + uvval) >> 16);
  246.             dstpU[x >> 1] = CB((c4 * u + c5 * v + 8421376) >> 16);
  247.             dstpV[x >> 1] = CB((c6 * u + c7 * v + 8421376) >> 16);
  248.         }
  249.         srcpY += src_pitchY;
  250.         dstpY += dst_pitchY;
  251.         srcpU += src_pitchUV;
  252.         srcpV += src_pitchUV;
  253.         dstpU += dst_pitchUV;
  254.         dstpV += dst_pitchUV;
  255.     }
  256. }
  257.  
  258. static void process_frame_yuv420p(ColorMatrixContext *color,
  259.                                   AVFrame *dst, AVFrame *src)
  260. {
  261.     const unsigned char *srcpU = src->data[1];
  262.     const unsigned char *srcpV = src->data[2];
  263.     const unsigned char *srcpY = src->data[0];
  264.     const unsigned char *srcpN = src->data[0] + src->linesize[0];
  265.     const int src_pitchY  = src->linesize[0];
  266.     const int src_pitchUV = src->linesize[1];
  267.     const int height = src->height;
  268.     const int width = src->width;
  269.     unsigned char *dstpU = dst->data[1];
  270.     unsigned char *dstpV = dst->data[2];
  271.     unsigned char *dstpY = dst->data[0];
  272.     unsigned char *dstpN = dst->data[0] + dst->linesize[0];
  273.     const int dst_pitchY  = dst->linesize[0];
  274.     const int dst_pitchUV = dst->linesize[1];
  275.     const int c2 = color->yuv_convert[color->mode][0][1];
  276.     const int c3 = color->yuv_convert[color->mode][0][2];
  277.     const int c4 = color->yuv_convert[color->mode][1][1];
  278.     const int c5 = color->yuv_convert[color->mode][1][2];
  279.     const int c6 = color->yuv_convert[color->mode][2][1];
  280.     const int c7 = color->yuv_convert[color->mode][2][2];
  281.     int x, y;
  282.  
  283.     for (y = 0; y < height; y += 2) {
  284.         for (x = 0; x < width; x += 2) {
  285.             const int u = srcpU[x >> 1] - 128;
  286.             const int v = srcpV[x >> 1] - 128;
  287.             const int uvval = c2 * u + c3 * v + 1081344;
  288.             dstpY[x + 0] = CB((65536 * (srcpY[x + 0] - 16) + uvval) >> 16);
  289.             dstpY[x + 1] = CB((65536 * (srcpY[x + 1] - 16) + uvval) >> 16);
  290.             dstpN[x + 0] = CB((65536 * (srcpN[x + 0] - 16) + uvval) >> 16);
  291.             dstpN[x + 1] = CB((65536 * (srcpN[x + 1] - 16) + uvval) >> 16);
  292.             dstpU[x >> 1] = CB((c4 * u + c5 * v + 8421376) >> 16);
  293.             dstpV[x >> 1] = CB((c6 * u + c7 * v + 8421376) >> 16);
  294.         }
  295.         srcpY += src_pitchY << 1;
  296.         dstpY += dst_pitchY << 1;
  297.         srcpN += src_pitchY << 1;
  298.         dstpN += dst_pitchY << 1;
  299.         srcpU += src_pitchUV;
  300.         srcpV += src_pitchUV;
  301.         dstpU += dst_pitchUV;
  302.         dstpV += dst_pitchUV;
  303.     }
  304. }
  305.  
  306. static int config_input(AVFilterLink *inlink)
  307. {
  308.     AVFilterContext *ctx = inlink->dst;
  309.     ColorMatrixContext *color = ctx->priv;
  310.     const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
  311.  
  312.     color->hsub = pix_desc->log2_chroma_w;
  313.     color->vsub = pix_desc->log2_chroma_h;
  314.  
  315.     av_log(ctx, AV_LOG_VERBOSE, "%s -> %s\n",
  316.            color_modes[color->source], color_modes[color->dest]);
  317.  
  318.     return 0;
  319. }
  320.  
  321. static int query_formats(AVFilterContext *ctx)
  322. {
  323.     static const enum AVPixelFormat pix_fmts[] = {
  324.         AV_PIX_FMT_YUV422P,
  325.         AV_PIX_FMT_YUV420P,
  326.         AV_PIX_FMT_UYVY422,
  327.         AV_PIX_FMT_NONE
  328.     };
  329.  
  330.     ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
  331.  
  332.     return 0;
  333. }
  334.  
  335. static int filter_frame(AVFilterLink *link, AVFrame *in)
  336. {
  337.     AVFilterContext *ctx = link->dst;
  338.     ColorMatrixContext *color = ctx->priv;
  339.     AVFilterLink *outlink = ctx->outputs[0];
  340.     AVFrame *out;
  341.  
  342.     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
  343.     if (!out) {
  344.         av_frame_free(&in);
  345.         return AVERROR(ENOMEM);
  346.     }
  347.     av_frame_copy_props(out, in);
  348.  
  349.     if (in->format == AV_PIX_FMT_YUV422P)
  350.         process_frame_yuv422p(color, out, in);
  351.     else if (in->format == AV_PIX_FMT_YUV420P)
  352.         process_frame_yuv420p(color, out, in);
  353.     else
  354.         process_frame_uyvy422(color, out, in);
  355.  
  356.     av_frame_free(&in);
  357.     return ff_filter_frame(outlink, out);
  358. }
  359.  
  360. static const AVFilterPad colormatrix_inputs[] = {
  361.     {
  362.         .name         = "default",
  363.         .type         = AVMEDIA_TYPE_VIDEO,
  364.         .config_props = config_input,
  365.         .filter_frame = filter_frame,
  366.     },
  367.     { NULL }
  368. };
  369.  
  370. static const AVFilterPad colormatrix_outputs[] = {
  371.     {
  372.         .name = "default",
  373.         .type = AVMEDIA_TYPE_VIDEO,
  374.     },
  375.     { NULL }
  376. };
  377.  
  378. AVFilter avfilter_vf_colormatrix = {
  379.     .name          = "colormatrix",
  380.     .description   = NULL_IF_CONFIG_SMALL("Convert color matrix."),
  381.     .priv_size     = sizeof(ColorMatrixContext),
  382.     .init          = init,
  383.     .query_formats = query_formats,
  384.     .inputs        = colormatrix_inputs,
  385.     .outputs       = colormatrix_outputs,
  386.     .priv_class    = &colormatrix_class,
  387.     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
  388. };
  389.