| /* GStreamer |
| * Copyright (C) 2013 Wim Taymans <wim.taymans@gmail.com> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| # include "config.h" |
| #endif |
| |
| #include <string.h> |
| #include <stdio.h> |
| |
| #include "video-orc.h" |
| #include "video-format.h" |
| |
| |
| /** |
| * SECTION:gstvideochroma |
| * @title: GstVideoChromaResample |
| * @short_description: Functions and utility object for operating on chroma video planes |
| * |
| * The functions gst_video_chroma_from_string() and gst_video_chroma_to_string() convert |
| * between #GstVideoChromaSite and string descriptions. |
| * |
| * #GstVideoChromaResample is a utility object for resampling chroma planes |
| * and converting between different chroma sampling sitings. |
| * |
| */ |
| |
| #ifndef GST_DISABLE_GST_DEBUG |
| #define GST_CAT_DEFAULT ensure_debug_category() |
| static GstDebugCategory * |
| ensure_debug_category (void) |
| { |
| static gsize cat_gonce = 0; |
| |
| if (g_once_init_enter (&cat_gonce)) { |
| gsize cat_done; |
| |
| cat_done = (gsize) _gst_debug_category_new ("video-chroma", 0, |
| "video-chroma object"); |
| |
| g_once_init_leave (&cat_gonce, cat_done); |
| } |
| |
| return (GstDebugCategory *) cat_gonce; |
| } |
| #else |
| #define ensure_debug_category() /* NOOP */ |
| #endif /* GST_DISABLE_GST_DEBUG */ |
| |
| typedef struct |
| { |
| const gchar *name; |
| GstVideoChromaSite site; |
| } ChromaSiteInfo; |
| |
| static const ChromaSiteInfo chromasite[] = { |
| {"jpeg", GST_VIDEO_CHROMA_SITE_JPEG}, |
| {"mpeg2", GST_VIDEO_CHROMA_SITE_MPEG2}, |
| {"dv", GST_VIDEO_CHROMA_SITE_DV} |
| }; |
| |
| /** |
| * gst_video_chroma_from_string: |
| * @s: a chromasite string |
| * |
| * Convert @s to a #GstVideoChromaSite |
| * |
| * Returns: a #GstVideoChromaSite or %GST_VIDEO_CHROMA_SITE_UNKNOWN when @s does |
| * not contain a valid chroma description. |
| */ |
| GstVideoChromaSite |
| gst_video_chroma_from_string (const gchar * s) |
| { |
| gint i; |
| for (i = 0; i < G_N_ELEMENTS (chromasite); i++) { |
| if (g_str_equal (chromasite[i].name, s)) |
| return chromasite[i].site; |
| } |
| return GST_VIDEO_CHROMA_SITE_UNKNOWN; |
| } |
| |
| /** |
| * gst_video_chroma_to_string: |
| * @site: a #GstVideoChromaSite |
| * |
| * Converts @site to its string representation. |
| * |
| * Returns: a string describing @site. |
| */ |
| const gchar * |
| gst_video_chroma_to_string (GstVideoChromaSite site) |
| { |
| gint i; |
| for (i = 0; i < G_N_ELEMENTS (chromasite); i++) { |
| if (chromasite[i].site == site) |
| return chromasite[i].name; |
| } |
| return NULL; |
| } |
| |
| struct _GstVideoChromaResample |
| { |
| GstVideoChromaMethod method; |
| GstVideoChromaSite site; |
| GstVideoChromaFlags flags; |
| GstVideoFormat format; |
| gint h_factor, v_factor; |
| guint n_lines; |
| gint offset; |
| void (*h_resample) (GstVideoChromaResample * resample, gpointer pixels, |
| gint width); |
| void (*v_resample) (GstVideoChromaResample * resample, gpointer lines[], |
| gint width); |
| }; |
| |
| #define PR(i) (p[2 + 4 * (i)]) |
| #define PB(i) (p[3 + 4 * (i)]) |
| |
| #define PR0(i) (l0[2 + 4 * (i)]) |
| #define PR1(i) (l1[2 + 4 * (i)]) |
| #define PR2(i) (l2[2 + 4 * (i)]) |
| #define PR3(i) (l3[2 + 4 * (i)]) |
| #define PB0(i) (l0[3 + 4 * (i)]) |
| #define PB1(i) (l1[3 + 4 * (i)]) |
| #define PB2(i) (l2[3 + 4 * (i)]) |
| #define PB3(i) (l3[3 + 4 * (i)]) |
| |
| #define FILT_1_1(a,b) ((a) + (b) + 1) >> 1 |
| #define FILT_1_3_3_1(a,b,c,d) ((a) + 3*((b)+(c)) + (d) + 4) >> 3 |
| |
| #define FILT_3_1(a,b) (3*(a) + (b) + 2) >> 2 |
| #define FILT_1_3(a,b) ((a) + 3*(b) + 2) >> 2 |
| #define FILT_1_2_1(a,b,c) ((a) + 2*(b) + (c) + 2) >> 2 |
| |
| #define FILT_7_1(a,b) (7*(a) + 1*(b) + 4) >> 3 |
| #define FILT_1_7(a,b) (1*(a) + 7*(b) + 4) >> 3 |
| |
| #define FILT_5_3(a,b) (5*(a) + 3*(b) + 4) >> 3 |
| #define FILT_3_5(a,b) (3*(a) + 5*(b) + 4) >> 3 |
| |
| #define FILT_10_3_2_1(a,b,c,d) (10*(a) + 3*(b) + 2*(c) + (d) + 8) >> 16 |
| #define FILT_1_2_3_10(a,b,c,d) ((a) + 2*(b) + 3*(c) + 10*(d) + 8) >> 16 |
| #define FILT_1_2_3_4_3_2_1(a,b,c,d,e,f,g) ((a) + 2*((b)+(f)) + 3*((c)+(e)) + 4*(d) + (g) + 8) >> 16 |
| |
| /* 2x horizontal upsampling without cositing |
| * |
| * +---------- a |
| * | +------ (3*a + b + 2) >> 2 |
| * | | +---- ( a + 3*b + 2) >> 2 |
| * v v v |
| * O-O-O-O- |
| * x x |
| * a b |
| */ |
| #define MAKE_UPSAMPLE_H2(name,type) \ |
| static void \ |
| video_chroma_up_h2_##name (GstVideoChromaResample *resample, \ |
| gpointer pixels, gint width) \ |
| { \ |
| type *p = pixels; \ |
| gint i; \ |
| type tr0, tr1; \ |
| type tb0, tb1; \ |
| \ |
| tr1 = PR(0); \ |
| tb1 = PB(0); \ |
| for (i = 1; i < width - 1; i += 2) { \ |
| tr0 = tr1, tr1 = PR(i+1); \ |
| tb0 = tb1, tb1 = PB(i+1); \ |
| \ |
| PR(i) = FILT_3_1 (tr0, tr1); \ |
| PB(i) = FILT_3_1 (tb0, tb1); \ |
| PR(i+1) = FILT_1_3 (tr0, tr1); \ |
| PB(i+1) = FILT_1_3 (tb0, tb1); \ |
| } \ |
| } |
| |
| /* 2x vertical upsampling without cositing |
| * |
| * O--O--O- <---- a |
| * a x x x |
| * O--O--O- <---- (3*a + b + 2) >> 2 |
| * O--O--O- <-----( a + 3*b + 2) >> 2 |
| * b x x x |
| * O--O--O- <---- b |
| */ |
| #define MAKE_UPSAMPLE_V2(name,type) \ |
| static void \ |
| video_chroma_up_v2_##name (GstVideoChromaResample *resample, \ |
| gpointer lines[], gint width) \ |
| { \ |
| type *l0 = lines[0]; \ |
| type *l1 = lines[1]; \ |
| \ |
| if (resample->h_resample) { \ |
| resample->h_resample (resample, l0, width); \ |
| if (l0 != l1) \ |
| resample->h_resample (resample, l1, width); \ |
| } \ |
| if (l0 != l1) { \ |
| video_orc_chroma_up_v2_##name (l0, l1, l0, l1, width); \ |
| } \ |
| } |
| /* 2x vertical upsampling interlaced without cositing |
| * |
| * even odd |
| * |
| * O--O--O--------------- <--- a |
| * a x x x |
| * --------------O--O--O- <--- c |
| * O--O--O--------------- <--- (5*a + 3*b + 4) >> 3 |
| * c x x x |
| * --------------O--O--O- <--- (7*c + d + 4) >> 3 |
| * O--O--O--------------- <--- ( a + 7*b + 4) >> 3 |
| * b x x x |
| * --------------O--O--O- <--- (3*c + 5*d + 4) >> 3 |
| * O--O--O--------------- |
| * d x x x |
| * --------------O--O--O- |
| */ |
| #define MAKE_UPSAMPLE_VI2(name,type) \ |
| static void \ |
| video_chroma_up_vi2_##name (GstVideoChromaResample *resample, \ |
| gpointer lines[], gint width) \ |
| { \ |
| gint i; \ |
| type *l0 = lines[0]; \ |
| type *l1 = lines[1]; \ |
| type *l2 = lines[2]; \ |
| type *l3 = lines[3]; \ |
| type tr0, tr1, tr2, tr3; \ |
| type tb0, tb1, tb2, tb3; \ |
| \ |
| if (resample->h_resample) { \ |
| if (l0 != l1) { \ |
| resample->h_resample (resample, l0, width); \ |
| resample->h_resample (resample, l1, width); \ |
| } \ |
| if (l2 != l3) { \ |
| resample->h_resample (resample, l2, width); \ |
| resample->h_resample (resample, l3, width); \ |
| } \ |
| } \ |
| if (l0 != l1 && l2 != l3) { \ |
| for (i = 0; i < width; i++) { \ |
| tr0 = PR0(i), tr2 = PR2(i); \ |
| tb0 = PB0(i), tb2 = PB2(i); \ |
| tr1 = PR1(i), tr3 = PR3(i); \ |
| tb1 = PB1(i), tb3 = PB3(i); \ |
| \ |
| PR0(i) = FILT_5_3 (tr0, tr2); \ |
| PB0(i) = FILT_5_3 (tb0, tb2); \ |
| PR1(i) = FILT_7_1 (tr1, tr3); \ |
| PB1(i) = FILT_7_1 (tb1, tb3); \ |
| PR2(i) = FILT_1_7 (tr0, tr2); \ |
| PB2(i) = FILT_1_7 (tb0, tb2); \ |
| PR3(i) = FILT_3_5 (tr1, tr3); \ |
| PB3(i) = FILT_3_5 (tb1, tb3); \ |
| } \ |
| } \ |
| } |
| |
| /* 2x horizontal downsampling without cositing |
| * |
| * +------ (a + b+ 1) >> 1 |
| * | |
| * v |
| * -O---O-- |
| * x x x x |
| * a b c d |
| */ |
| #define MAKE_DOWNSAMPLE_H2_ORC(name,type) \ |
| static void \ |
| video_chroma_down_h2_##name (GstVideoChromaResample *resample, \ |
| gpointer pixels, gint width) \ |
| { \ |
| type *p = pixels; \ |
| \ |
| video_orc_chroma_down_h2_##name (p, p, width / 2); \ |
| } |
| |
| #define MAKE_DOWNSAMPLE_H2(name,type) \ |
| static void \ |
| video_chroma_down_h2_##name (GstVideoChromaResample *resample, \ |
| gpointer pixels, gint width) \ |
| { \ |
| type *p = pixels; \ |
| gint i; \ |
| \ |
| for (i = 0; i < width - 1; i += 2) { \ |
| type tr0 = PR(i), tr1 = PR(i+1); \ |
| type tb0 = PB(i), tb1 = PB(i+1); \ |
| \ |
| PR(i) = FILT_1_1 (tr0, tr1); \ |
| PB(i) = FILT_1_1 (tb0, tb1); \ |
| } \ |
| } |
| /* 2x vertical downsampling without cositing |
| * |
| * a x--x--x- |
| * O O O <---- (a + b + 1) >> 1 |
| * b x--x--x- |
| * c x--x--x- |
| * O O O |
| * d x--x--x- |
| */ |
| #define MAKE_DOWNSAMPLE_V2(name,type) \ |
| static void \ |
| video_chroma_down_v2_##name (GstVideoChromaResample *resample, \ |
| gpointer lines[], gint width) \ |
| { \ |
| type *l0 = lines[0]; \ |
| type *l1 = lines[1]; \ |
| \ |
| if (l0 != l1) \ |
| video_orc_chroma_down_v2_##name (l0, l0, l1, width); \ |
| \ |
| if (resample->h_resample) \ |
| resample->h_resample (resample, l0, width); \ |
| } |
| /* 2x vertical downsampling interlaced without cositing |
| * |
| * even odd |
| * |
| * a x--x--x--------------- |
| * O O O <--- |
| * b --------------x--x--x- |
| * c x--x--x--------------- |
| * O O O <--- |
| * d --------------x--x--x- |
| */ |
| #define MAKE_DOWNSAMPLE_VI2(name,type) \ |
| static void \ |
| video_chroma_down_vi2_##name (GstVideoChromaResample *resample, \ |
| gpointer lines[], gint width) \ |
| { \ |
| /* FIXME */ \ |
| if (resample->h_resample) \ |
| resample->h_resample (resample, lines[0], width); \ |
| } |
| |
| MAKE_UPSAMPLE_H2 (u16, guint16); |
| MAKE_UPSAMPLE_H2 (u8, guint8); |
| MAKE_UPSAMPLE_V2 (u16, guint16); |
| MAKE_UPSAMPLE_V2 (u8, guint8); |
| MAKE_UPSAMPLE_VI2 (u16, guint16); |
| MAKE_UPSAMPLE_VI2 (u8, guint8); |
| MAKE_DOWNSAMPLE_H2 (u16, guint16); |
| MAKE_DOWNSAMPLE_H2_ORC (u8, guint8); |
| MAKE_DOWNSAMPLE_V2 (u16, guint16); |
| MAKE_DOWNSAMPLE_V2 (u8, guint8); |
| MAKE_DOWNSAMPLE_VI2 (u16, guint16); |
| MAKE_DOWNSAMPLE_VI2 (u8, guint8); |
| |
| /* 4x horizontal upsampling without cositing |
| * |
| * +---------- (7*a + b + 4) >> 3 |
| * | +-------- (5*a + 3*b + 4) >> 3 |
| * a a | | +------ (3*a + 5*b + 4) >> 3 |
| * | | | | | +---- ( a + 7*b + 4) >> 3 |
| * v v v v v v |
| * O-O-O-O-O-O-O-O- |
| * x x |
| * a b |
| */ |
| #define MAKE_UPSAMPLE_H4(name,type) \ |
| static void \ |
| video_chroma_up_h4_##name (GstVideoChromaResample *resample, \ |
| gpointer pixels, gint width) \ |
| { \ |
| type *p = pixels; \ |
| gint i; \ |
| type tr0, tr1; \ |
| type tb0, tb1; \ |
| \ |
| tr1 = PR(0); \ |
| tb1 = PB(0); \ |
| for (i = 2; i < width - 3; i += 4) { \ |
| tr0 = tr1, tr1 = PR(i+2); \ |
| tb0 = tb1, tb1 = PB(i+2); \ |
| \ |
| PR(i) = FILT_7_1 (tr0, tr1); \ |
| PB(i) = FILT_7_1 (tb0, tb1); \ |
| PR(i+1) = FILT_5_3 (tr0, tr1); \ |
| PB(i+1) = FILT_5_3 (tb0, tb1); \ |
| PR(i+2) = FILT_3_5 (tr0, tr1); \ |
| PB(i+2) = FILT_3_5 (tb0, tb1); \ |
| PR(i+3) = FILT_1_7 (tr0, tr1); \ |
| PB(i+3) = FILT_1_7 (tb0, tb1); \ |
| } \ |
| } |
| |
| /* 4x vertical upsampling without cositing |
| * |
| * O--O--O- <---- a |
| * O--O--O- <---- a |
| * a x x x |
| * O--O--O- <---- (7*a + b + 4) >> 3 |
| * O--O--O- <---- (5*a + 3*b + 4) >> 3 |
| * O--O--O- <---- (3*a + 5*b + 4) >> 3 |
| * O--O--O- <-----( a + 7*b + 4) >> 3 |
| * b x x x |
| * O--O--O- |
| * O--O--O- |
| */ |
| #define MAKE_UPSAMPLE_V4(name,type) \ |
| static void \ |
| video_chroma_up_v4_##name (GstVideoChromaResample *resample, \ |
| gpointer lines[], gint width) \ |
| { \ |
| gint i; \ |
| type *l0 = lines[0]; \ |
| type *l1 = lines[1]; \ |
| type *l2 = lines[2]; \ |
| type *l3 = lines[3]; \ |
| type tr0, tr1; \ |
| type tb0, tb1; \ |
| \ |
| if (resample->h_resample) { \ |
| if (l0 != l1) { \ |
| resample->h_resample (resample, l0, width); \ |
| resample->h_resample (resample, l1, width); \ |
| } \ |
| if (l2 != l3) { \ |
| resample->h_resample (resample, l2, width); \ |
| resample->h_resample (resample, l3, width); \ |
| } \ |
| } \ |
| if (l0 != l1 && l2 != l3) { \ |
| for (i = 0; i < width; i++) { \ |
| tr0 = PR0(i), tr1 = PR2(i); \ |
| tb0 = PB0(i), tb1 = PB2(i); \ |
| \ |
| PR0(i) = FILT_7_1 (tr0, tr1); \ |
| PB0(i) = FILT_7_1 (tb0, tb1); \ |
| PR1(i) = FILT_5_3 (tr0, tr1); \ |
| PB1(i) = FILT_5_3 (tb0, tb1); \ |
| PR2(i) = FILT_3_5 (tr0, tr1); \ |
| PB2(i) = FILT_3_5 (tb0, tb1); \ |
| PR3(i) = FILT_1_7 (tr0, tr1); \ |
| PB3(i) = FILT_1_7 (tb0, tb1); \ |
| } \ |
| } \ |
| } |
| /* 4x vertical upsampling interlaced without cositing |
| * |
| */ |
| #define MAKE_UPSAMPLE_VI4(name,type) \ |
| static void \ |
| video_chroma_up_vi4_##name (GstVideoChromaResample *resample, \ |
| gpointer lines[], gint width) \ |
| { \ |
| /* FIXME */ \ |
| if (resample->h_resample) { \ |
| resample->h_resample (resample, lines[0], width); \ |
| } \ |
| } |
| |
| /* 4x horizontal downsampling without cositing |
| * |
| * +------ (a + 3*b + 3*c + d + 4) >> 3 |
| * | |
| * v |
| * ---O-------O--- |
| * x x x x x x x x |
| * a b c d e f g h |
| */ |
| #define MAKE_DOWNSAMPLE_H4(name,type) \ |
| static void \ |
| video_chroma_down_h4_##name (GstVideoChromaResample *resample, \ |
| gpointer pixels, gint width) \ |
| { \ |
| type *p = pixels; \ |
| gint i; \ |
| \ |
| for (i = 0; i < width - 4; i += 4) { \ |
| type tr0 = PR(i), tr1 = PR(i+1), tr2 = PR(i+2), tr3 = PR(i+3); \ |
| type tb0 = PB(i), tb1 = PB(i+1), tb2 = PB(i+2), tb3 = PB(i+3); \ |
| \ |
| PR(i) = FILT_1_3_3_1 (tr0, tr1, tr2, tr3); \ |
| PB(i) = FILT_1_3_3_1 (tb0, tb1, tb2, tb3); \ |
| } \ |
| } |
| |
| /* 4x vertical downsampling without cositing |
| * |
| * a x--x--x- |
| * b x--x--x- |
| * O O O <---- (a + 3*b + 3*c + d + 4) >> 4 |
| * c x--x--x- |
| * d x--x--x- |
| * e x--x--x- |
| * f x--x--x- |
| * O O O |
| * g x--x--x- |
| * h x--x--x- |
| */ |
| #define MAKE_DOWNSAMPLE_V4(name,type) \ |
| static void \ |
| video_chroma_down_v4_##name (GstVideoChromaResample *resample, \ |
| gpointer lines[], gint width) \ |
| { \ |
| type *l0 = lines[0]; \ |
| type *l1 = lines[1]; \ |
| type *l2 = lines[2]; \ |
| type *l3 = lines[3]; \ |
| \ |
| video_orc_chroma_down_v4_##name(l0, l0, l1, l2, l3, width); \ |
| \ |
| if (resample->h_resample) \ |
| resample->h_resample (resample, l0, width); \ |
| } |
| /* 4x vertical downsampling interlaced without cositing |
| * |
| */ |
| #define MAKE_DOWNSAMPLE_VI4(name,type) \ |
| static void \ |
| video_chroma_down_vi4_##name (GstVideoChromaResample *resample, \ |
| gpointer lines[], gint width) \ |
| { \ |
| /* FIXME */ \ |
| if (resample->h_resample) { \ |
| resample->h_resample (resample, lines[0], width); \ |
| } \ |
| } |
| |
| MAKE_UPSAMPLE_H4 (u16, guint16); |
| MAKE_UPSAMPLE_H4 (u8, guint8); |
| MAKE_UPSAMPLE_V4 (u16, guint16); |
| MAKE_UPSAMPLE_V4 (u8, guint8); |
| MAKE_UPSAMPLE_VI4 (u16, guint16); |
| MAKE_UPSAMPLE_VI4 (u8, guint8); |
| MAKE_DOWNSAMPLE_H4 (u16, guint16); |
| MAKE_DOWNSAMPLE_H4 (u8, guint8); |
| MAKE_DOWNSAMPLE_V4 (u16, guint16); |
| MAKE_DOWNSAMPLE_V4 (u8, guint8); |
| MAKE_DOWNSAMPLE_VI4 (u16, guint16); |
| MAKE_DOWNSAMPLE_VI4 (u8, guint8); |
| |
| /* 2x horizontal upsampling with cositing |
| * |
| * a +------ (a + b + 1) >> 1 |
| * | | |
| * v v |
| * O-O-O-O |
| * x x |
| * a b |
| */ |
| #define MAKE_UPSAMPLE_H2_CS_ORC(name,type) \ |
| static void \ |
| video_chroma_up_h2_cs_##name (GstVideoChromaResample *resample, \ |
| gpointer pixels, gint width) \ |
| { \ |
| type *p = pixels; \ |
| /* ORC version is slower */ \ |
| video_orc_chroma_up_h2_cs_##name (p, p, p, width-1); \ |
| } |
| |
| #define MAKE_UPSAMPLE_H2_CS(name,type) \ |
| static void \ |
| video_chroma_up_h2_cs_##name (GstVideoChromaResample *resample, \ |
| gpointer pixels, gint width) \ |
| { \ |
| type *p = pixels; \ |
| gint i; \ |
| \ |
| for (i = 1; i < width - 1; i += 2) { \ |
| PR(i) = FILT_1_1 (PR(i-1), PR(i+1)); \ |
| PB(i) = FILT_1_1 (PB(i-1), PB(i+1)); \ |
| } \ |
| } |
| /* 2x vertical upsampling with cositing |
| * |
| * a x O--O--O- <---- a |
| * O--O--O- <---- (a + b + 1) >> 1 |
| * b x O--O--O- |
| * O--O--O- |
| */ |
| #define MAKE_UPSAMPLE_V2_CS(name,type) \ |
| static void \ |
| video_chroma_up_v2_cs_##name (GstVideoChromaResample *resample, \ |
| gpointer lines[], gint width) \ |
| { \ |
| /* FIXME */ \ |
| if (resample->h_resample) { \ |
| resample->h_resample (resample, lines[0], width); \ |
| } \ |
| } |
| /* 2x vertical upsampling interlaced with cositing |
| * |
| */ |
| #define MAKE_UPSAMPLE_VI2_CS(name,type) \ |
| static void \ |
| video_chroma_up_vi2_cs_##name (GstVideoChromaResample *resample, \ |
| gpointer lines[], gint width) \ |
| { \ |
| /* FIXME */ \ |
| if (resample->h_resample) { \ |
| resample->h_resample (resample, lines[0], width); \ |
| } \ |
| } |
| |
| /* 2x horizontal downsampling with cositing |
| * |
| * a |
| * | +------ (b + 2*c + d + 2) >> 2 |
| * v v |
| * O---O---O--- |
| * x x x x x x |
| * a b c d e f |
| */ |
| #define MAKE_DOWNSAMPLE_H2_CS(name,type) \ |
| static void \ |
| video_chroma_down_h2_cs_##name (GstVideoChromaResample *resample, \ |
| gpointer pixels, gint width) \ |
| { \ |
| type *p = pixels; \ |
| gint i; \ |
| \ |
| if (width < 2) \ |
| return; \ |
| \ |
| PR(0) = FILT_3_1 (PR(0), PR(1)); \ |
| PB(0) = FILT_3_1 (PB(0), PB(1)); \ |
| \ |
| for (i = 2; i < width - 2; i += 2) { \ |
| PR(i) = FILT_1_2_1 (PR(i-1), PR(i), PR(i+1)); \ |
| PB(i) = FILT_1_2_1 (PB(i-1), PB(i), PB(i+1)); \ |
| } \ |
| if (i < width) { \ |
| PR(i) = FILT_1_3 (PR(i-1), PR(i)); \ |
| PB(i) = FILT_1_3 (PB(i-1), PB(i)); \ |
| } \ |
| } |
| /* 2x vertical downsampling with cositing |
| * |
| * a x O--O--O- <---- a |
| * b x -------- |
| * c x O--O--O- <---- (b + 2*c + d + 2) >> 2 |
| * d x -------- |
| * e x O--O--O- |
| * f x -------- |
| */ |
| #define MAKE_DOWNSAMPLE_V2_CS(name,type) \ |
| static void \ |
| video_chroma_down_v2_cs_##name (GstVideoChromaResample *resample, \ |
| gpointer lines[], gint width) \ |
| { \ |
| /* FIXME */ \ |
| if (resample->h_resample) { \ |
| resample->h_resample (resample, lines[0], width); \ |
| } \ |
| } |
| /* 2x vertical downsampling interlaced with cositing |
| * |
| */ |
| #define MAKE_DOWNSAMPLE_VI2_CS(name,type) \ |
| static void \ |
| video_chroma_down_vi2_cs_##name (GstVideoChromaResample *resample, \ |
| gpointer lines[], gint width) \ |
| { \ |
| /* FIXME */ \ |
| if (resample->h_resample) { \ |
| resample->h_resample (resample, lines[0], width); \ |
| } \ |
| } |
| |
| MAKE_UPSAMPLE_H2_CS (u16, guint16); |
| MAKE_UPSAMPLE_H2_CS (u8, guint8); |
| MAKE_UPSAMPLE_V2_CS (u16, guint16); |
| MAKE_UPSAMPLE_V2_CS (u8, guint8); |
| MAKE_UPSAMPLE_VI2_CS (u16, guint16); |
| MAKE_UPSAMPLE_VI2_CS (u8, guint8); |
| MAKE_DOWNSAMPLE_H2_CS (u16, guint16); |
| MAKE_DOWNSAMPLE_H2_CS (u8, guint8); |
| MAKE_DOWNSAMPLE_V2_CS (u16, guint16); |
| MAKE_DOWNSAMPLE_V2_CS (u8, guint8); |
| MAKE_DOWNSAMPLE_VI2_CS (u16, guint16); |
| MAKE_DOWNSAMPLE_VI2_CS (u8, guint8); |
| |
| /* 4x horizontal upsampling with cositing |
| * |
| * +---------- (3*a + b + 2) >> 2 |
| * a | +-------- ( a + b + 1) >> 1 |
| * | | | +------ ( a + 3*b + 2) >> 2 |
| * v v v v |
| * O-O-O-O-O-O-O-O |
| * x x |
| * a b |
| */ |
| #define MAKE_UPSAMPLE_H4_CS(name,type) \ |
| static void \ |
| video_chroma_up_h4_cs_##name (GstVideoChromaResample *resample, \ |
| gpointer pixels, gint width) \ |
| { \ |
| type *p = pixels; \ |
| gint i; \ |
| \ |
| for (i = 0; i < width - 4; i += 4) { \ |
| type tr0 = PR(i), tr1 = PR(i+4); \ |
| type tb0 = PB(i), tb1 = PB(i+4); \ |
| \ |
| PR(i+1) = FILT_3_1 (tr0, tr1); \ |
| PB(i+1) = FILT_3_1 (tb0, tb1); \ |
| PR(i+2) = FILT_1_1 (tr0, tr1); \ |
| PB(i+2) = FILT_1_1 (tb0, tb1); \ |
| PR(i+3) = FILT_1_3 (tr0, tr1); \ |
| PB(i+3) = FILT_1_3 (tb0, tb1); \ |
| } \ |
| } |
| /* 4x vertical upsampling with cositing |
| * |
| * a x O--O--O- <---- a |
| * O--O--O- <---- (3*a + b + 2) >> 2 |
| * O--O--O- <---- ( a + b + 1) >> 1 |
| * O--O--O- <---- ( a + 3*b + 2) >> 2 |
| * b x O--O--O- |
| * O--O--O- |
| */ |
| #define MAKE_UPSAMPLE_V4_CS(name,type) \ |
| static void \ |
| video_chroma_up_v4_cs_##name (GstVideoChromaResample *resample, \ |
| gpointer lines[], gint width) \ |
| { \ |
| /* FIXME */ \ |
| if (resample->h_resample) { \ |
| resample->h_resample (resample, lines[0], width); \ |
| } \ |
| } |
| /* 4x vertical upsampling interlaced with cositing |
| * |
| */ |
| #define MAKE_UPSAMPLE_VI4_CS(name,type) \ |
| static void \ |
| video_chroma_up_vi4_cs_##name (GstVideoChromaResample *resample, \ |
| gpointer lines[], gint width) \ |
| { \ |
| /* FIXME */ \ |
| if (resample->h_resample) { \ |
| resample->h_resample (resample, lines[0], width); \ |
| } \ |
| } |
| /* 4x horizontal downsampling with cositing |
| * |
| * a |
| * | +------ (b + 2*c + 3*d + 4*e + 3*f + 2*g + h + 8) >> 16 |
| * v v |
| * O-------O------- |
| * x x x x x x x x |
| * a b c d e f g h |
| */ |
| #define MAKE_DOWNSAMPLE_H4_CS(name,type) \ |
| static void \ |
| video_chroma_down_h4_cs_##name (GstVideoChromaResample *resample, \ |
| gpointer pixels, gint width) \ |
| { \ |
| type *p = pixels; \ |
| gint i; \ |
| \ |
| if (width < 4) \ |
| return; \ |
| \ |
| PR(0) = FILT_10_3_2_1 (PR(0), PR(1), PR(2), PR(3)); \ |
| PB(0) = FILT_10_3_2_1 (PB(0), PB(1), PB(2), PB(3)); \ |
| \ |
| for (i = 4; i < width - 4; i += 4) { \ |
| PR(i) = FILT_1_2_3_4_3_2_1 (PR(i-3), PR(i-2), PR(i-1), PR(i), PR(i+1), PR(i+2), PR(i+3)); \ |
| PB(i) = FILT_1_2_3_4_3_2_1 (PB(i-3), PB(i-2), PB(i-1), PB(i), PB(i+1), PB(i+2), PB(i+3)); \ |
| } \ |
| if (i < width) { \ |
| PR(i) = FILT_1_2_3_10 (PR(i-3), PR(i-2), PR(i-1), PR(i)); \ |
| PB(i) = FILT_1_2_3_10 (PB(i-3), PB(i-2), PB(i-1), PB(i)); \ |
| } \ |
| } |
| /* 4x vertical downsampling with cositing |
| * |
| * a x O--O--O- <---- a |
| * b x -------- |
| * c x -------- |
| * d x -------- |
| * e x O--O--O- <---- (b + 2*c + 3*d + 4*e + 3*f + 2*g + h + 8) >> 16 |
| * f x -------- |
| * g x -------- |
| * h x -------- |
| * i x O--O--O- |
| * j x -------- |
| */ |
| #define MAKE_DOWNSAMPLE_V4_CS(name,type) \ |
| static void \ |
| video_chroma_down_v4_cs_##name (GstVideoChromaResample *resample, \ |
| gpointer lines[], gint width) \ |
| { \ |
| /* FIXME */ \ |
| if (resample->h_resample) { \ |
| resample->h_resample (resample, lines[0], width); \ |
| } \ |
| } |
| /* 4x vertical downsampling interlaced with cositing |
| * |
| */ |
| #define MAKE_DOWNSAMPLE_VI4_CS(name,type) \ |
| static void \ |
| video_chroma_down_vi4_cs_##name (GstVideoChromaResample *resample, \ |
| gpointer lines[], gint width) \ |
| { \ |
| /* FIXME */ \ |
| if (resample->h_resample) { \ |
| resample->h_resample (resample, lines[0], width); \ |
| } \ |
| } |
| |
| MAKE_UPSAMPLE_H4_CS (u16, guint16); |
| MAKE_UPSAMPLE_H4_CS (u8, guint8); |
| MAKE_UPSAMPLE_V4_CS (u16, guint16); |
| MAKE_UPSAMPLE_V4_CS (u8, guint8); |
| MAKE_UPSAMPLE_VI4_CS (u16, guint16); |
| MAKE_UPSAMPLE_VI4_CS (u8, guint8); |
| MAKE_DOWNSAMPLE_H4_CS (u16, guint16); |
| MAKE_DOWNSAMPLE_H4_CS (u8, guint8); |
| MAKE_DOWNSAMPLE_V4_CS (u16, guint16); |
| MAKE_DOWNSAMPLE_V4_CS (u8, guint8); |
| MAKE_DOWNSAMPLE_VI4_CS (u16, guint16); |
| MAKE_DOWNSAMPLE_VI4_CS (u8, guint8); |
| |
| typedef struct |
| { |
| void (*resample) (GstVideoChromaResample * resample, gpointer pixels, |
| gint width); |
| } HorizResampler; |
| |
| static const HorizResampler h_resamplers[] = { |
| {NULL}, |
| {video_chroma_up_h2_u8}, |
| {video_chroma_down_h2_u8}, |
| {video_chroma_up_h2_u16}, |
| {video_chroma_down_h2_u16}, |
| {video_chroma_up_h2_cs_u8}, |
| {video_chroma_down_h2_cs_u8}, |
| {video_chroma_up_h2_cs_u16}, |
| {video_chroma_down_h2_cs_u16}, |
| {video_chroma_up_h4_u8}, |
| {video_chroma_down_h4_u8}, |
| {video_chroma_up_h4_u16}, |
| {video_chroma_down_h4_u16}, |
| {video_chroma_up_h4_cs_u8}, |
| {video_chroma_down_h4_cs_u8}, |
| {video_chroma_up_h4_cs_u16}, |
| {video_chroma_down_h4_cs_u16} |
| }; |
| |
| typedef struct |
| { |
| void (*resample) (GstVideoChromaResample * resample, gpointer lines[], |
| gint width); |
| guint n_lines; |
| gint offset; |
| } VertResampler; |
| |
| static void |
| video_chroma_none (GstVideoChromaResample * resample, |
| gpointer lines[], gint width) |
| { |
| if (resample->h_resample) |
| resample->h_resample (resample, lines[0], width); |
| } |
| |
| static const VertResampler v_resamplers[] = { |
| {video_chroma_none, 1, 0}, |
| {video_chroma_up_v2_u8, 2, -1}, |
| {video_chroma_down_v2_u8, 2, 0}, |
| /* 16 bits */ |
| {video_chroma_up_v2_u16, 2, -1}, |
| {video_chroma_down_v2_u16, 2, 0}, |
| /* cosited */ |
| {video_chroma_up_v2_cs_u8, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_down_v2_cs_u8, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_up_v2_cs_u16, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_down_v2_cs_u16, 1, 0}, /* IMPLEMENT ME */ |
| /* 4x */ |
| {video_chroma_up_v4_u8, 4, -2}, |
| {video_chroma_down_v4_u8, 4, 0}, |
| {video_chroma_up_v4_u16, 4, -2}, |
| {video_chroma_down_v4_u16, 4, 0}, |
| {video_chroma_up_v4_cs_u8, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_down_v4_cs_u8, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_up_v4_cs_u16, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_down_v4_cs_u16, 1, 0}, /* IMPLEMENT ME */ |
| /* interlaced */ |
| {video_chroma_up_vi2_u8, 4, -2}, |
| {video_chroma_down_vi2_u8, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_up_vi2_u16, 4, -2}, |
| {video_chroma_down_vi2_u16, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_up_vi2_cs_u8, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_down_vi2_cs_u8, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_up_vi2_cs_u16, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_down_vi2_cs_u16, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_up_vi4_u8, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_down_vi4_u8, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_up_vi4_u16, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_down_vi4_u16, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_up_vi4_cs_u8, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_down_vi4_cs_u8, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_up_vi4_cs_u16, 1, 0}, /* IMPLEMENT ME */ |
| {video_chroma_down_vi4_cs_u16, 1, 0}, /* IMPLEMENT ME */ |
| }; |
| |
| /** |
| * gst_video_chroma_resample_new: (skip) |
| * @method: a #GstVideoChromaMethod |
| * @site: a #GstVideoChromaSite |
| * @flags: #GstVideoChromaFlags |
| * @format: the #GstVideoFormat |
| * @h_factor: horizontal resampling factor |
| * @v_factor: vertical resampling factor |
| * |
| * Create a new resampler object for the given parameters. When @h_factor or |
| * @v_factor is > 0, upsampling will be used, otherwise subsampling is |
| * performed. |
| * |
| * Returns: a new #GstVideoChromaResample that should be freed with |
| * gst_video_chroma_resample_free() after usage. |
| */ |
| GstVideoChromaResample * |
| gst_video_chroma_resample_new (GstVideoChromaMethod method, |
| GstVideoChromaSite site, GstVideoChromaFlags flags, |
| GstVideoFormat format, gint h_factor, gint v_factor) |
| { |
| GstVideoChromaResample *result; |
| guint cosite, h_index, v_index, bits; |
| |
| /* no resampling */ |
| if (h_factor == 0 && v_factor == 0) |
| return NULL; |
| |
| if (format == GST_VIDEO_FORMAT_AYUV) |
| bits = 8; |
| else if (format == GST_VIDEO_FORMAT_AYUV64) |
| bits = 16; |
| else |
| return NULL; |
| |
| cosite = (site & GST_VIDEO_CHROMA_SITE_H_COSITED ? 1 : 0); |
| if (h_factor == 0) |
| h_index = 0; |
| else |
| h_index = |
| ((ABS (h_factor) - 1) * 8) + (cosite ? 4 : 0) + (bits == |
| 16 ? 2 : 0) + (h_factor < 0 ? 1 : 0) + 1; |
| |
| GST_DEBUG ("h_resample %d, factor %d, cosite %d", h_index, h_factor, cosite); |
| |
| cosite = (site & GST_VIDEO_CHROMA_SITE_V_COSITED ? 1 : 0); |
| if (v_factor == 0) |
| v_index = 0; |
| else |
| v_index = |
| ((ABS (v_factor) - 1) * 8) + (cosite ? 4 : 0) + (bits == |
| 16 ? 2 : 0) + (v_factor < 0 ? 1 : 0) + 1; |
| |
| if (flags & GST_VIDEO_CHROMA_FLAG_INTERLACED) |
| v_index += 16; |
| |
| GST_DEBUG ("v_resample %d, factor %d, cosite %d", v_index, v_factor, cosite); |
| |
| result = g_slice_new (GstVideoChromaResample); |
| result->method = method; |
| result->site = site; |
| result->flags = flags; |
| result->format = format; |
| result->h_factor = h_factor; |
| result->v_factor = v_factor; |
| result->h_resample = h_resamplers[h_index].resample; |
| result->v_resample = v_resamplers[v_index].resample; |
| result->n_lines = v_resamplers[v_index].n_lines; |
| result->offset = v_resamplers[v_index].offset; |
| |
| GST_DEBUG ("resample %p, bits %d, n_lines %u, offset %d", result, bits, |
| result->n_lines, result->offset); |
| |
| return result; |
| } |
| |
| /** |
| * gst_video_chroma_resample_get_info: |
| * @resample: a #GstVideoChromaResample |
| * @n_lines: the number of input lines |
| * @offset: the first line |
| * |
| * The resampler must be fed @n_lines at a time. The first line should be |
| * at @offset. |
| */ |
| void |
| gst_video_chroma_resample_get_info (GstVideoChromaResample * resample, |
| guint * n_lines, gint * offset) |
| { |
| g_return_if_fail (resample != NULL); |
| |
| if (n_lines) |
| *n_lines = resample->n_lines; |
| if (offset) |
| *offset = resample->offset; |
| } |
| |
| /** |
| * gst_video_chroma_resample_free: |
| * @resample: a #GstVideoChromaResample |
| * |
| * Free @resample |
| */ |
| void |
| gst_video_chroma_resample_free (GstVideoChromaResample * resample) |
| { |
| g_return_if_fail (resample != NULL); |
| |
| g_slice_free (GstVideoChromaResample, resample); |
| } |
| |
| /** |
| * gst_video_chroma_resample: |
| * @resample: a #GstVideoChromaResample |
| * @lines: pixel lines |
| * @width: the number of pixels on one line |
| * |
| * Perform resampling of @width chroma pixels in @lines. |
| */ |
| void |
| gst_video_chroma_resample (GstVideoChromaResample * resample, |
| gpointer lines[], gint width) |
| { |
| g_return_if_fail (resample != NULL); |
| |
| resample->v_resample (resample, lines, width); |
| } |