From 0c60f0daa4aae81c8a7402210e65e4fc36f9a7e2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 17 May 2013 16:22:46 +0200 Subject: [PATCH] video-chroma: add chroma resampler Add functions to up/downsample chroma in horizontal and vertical directions. These functions work in-placeand are meant to be used on the input/output of the pack/unpack functions. --- gst-libs/gst/video/video-chroma.c | 740 ++++++++++++++++++++++++++++++ gst-libs/gst/video/video-chroma.h | 40 ++ win32/common/libgstvideo.def | 6 + 3 files changed, 786 insertions(+) diff --git a/gst-libs/gst/video/video-chroma.c b/gst-libs/gst/video/video-chroma.c index 0799b1fabc..ed2eb0abf4 100644 --- a/gst-libs/gst/video/video-chroma.c +++ b/gst-libs/gst/video/video-chroma.c @@ -76,3 +76,743 @@ gst_video_chroma_to_string (GstVideoChromaSite site) } 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_1_1_1(a,b,c,d) ((a) + (b) + (c) + (d) + 2) >> 2 + +#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) + 3*(c) + 4*(d) + 3*(e) + 2*(f) + (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(type) \ +static void \ +video_chroma_up_h2_##type (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(type) \ +static void \ +video_chroma_up_v2_##type (GstVideoChromaResample *resample, \ + gpointer lines[], gint width) \ +{ \ + gint i; \ + type *l0 = lines[0]; \ + type *l1 = lines[1]; \ + type tr0, tr1; \ + type tb0, tb1; \ + \ + if (resample->h_resample) { \ + resample->h_resample (resample, l0, width); \ + if (l0 != l1) \ + resample->h_resample (resample, l1, width); \ + } \ + if (l0 != l1) { \ + for (i = 0; i < width; i++) { \ + tr0 = PR0(i), tr1 = PR1(i); \ + tb0 = PB0(i), tb1 = PB1(i); \ + \ + PR0(i) = FILT_3_1 (tr0, tr1); \ + PB0(i) = FILT_3_1 (tb0, tb1); \ + PR1(i) = FILT_1_3 (tr0, tr1); \ + PB1(i) = FILT_1_3 (tb0, tb1); \ + } \ + } \ +} +/* 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(type) \ +static void \ +video_chroma_up_vi2_##type (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(type) \ +static void \ +video_chroma_down_h2_##type (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(type) \ +static void \ +video_chroma_down_v2_##type (GstVideoChromaResample *resample, \ + gpointer lines[], gint width) \ +{ \ + gint i; \ + 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) { \ + for (i = 0; i < width; i++) { \ + type tr0 = PR0(i), tr1 = PR1(i); \ + type tb0 = PB0(i), tb1 = PB1(i); \ + \ + PR0(i) = FILT_1_1 (tr0, tr1); \ + PB0(i) = FILT_1_1 (tb0, tb1); \ + } \ + } \ +} + +MAKE_UPSAMPLE_H2 (guint16); +MAKE_UPSAMPLE_H2 (guint8); +MAKE_UPSAMPLE_V2 (guint16); +MAKE_UPSAMPLE_V2 (guint8); +MAKE_UPSAMPLE_VI2 (guint16); +MAKE_UPSAMPLE_VI2 (guint8); +MAKE_DOWNSAMPLE_H2 (guint16); +MAKE_DOWNSAMPLE_H2 (guint8); +MAKE_DOWNSAMPLE_V2 (guint16); +MAKE_DOWNSAMPLE_V2 (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(type) \ +static void \ +video_chroma_up_h4_##type (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(type) \ +static void \ +video_chroma_up_v4_##type (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 horizontal downsampling without cositing + * + * +------ (a + b + c + d + 2) >> 2 + * | + * v + * ---O-------O--- + * x x x x x x x x + * a b c d e f g h + */ +#define MAKE_DOWNSAMPLE_H4(type) \ +static void \ +video_chroma_down_h4_##type (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_1_1_1 (tr0, tr1, tr2, tr3); \ + PB(i) = FILT_1_1_1_1 (tb0, tb1, tb2, tb3); \ + } \ +} + +/* 4x vertical downsampling without cositing + * + * a x--x--x- + * b x--x--x- + * O O O <---- (a + b + c + d + 2) >> 2 + * 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(type) \ +static void \ +video_chroma_down_v4_##type (GstVideoChromaResample *resample, \ + gpointer lines[], gint width) \ +{ \ + gint i; \ + type *l0 = lines[0]; \ + type *l1 = lines[1]; \ + type *l2 = lines[2]; \ + type *l3 = lines[3]; \ + \ + if (resample->h_resample) { \ + resample->h_resample (resample, l0, width); \ + if (l0 != l1) \ + resample->h_resample (resample, l1, width); \ + if (l1 != l2) \ + resample->h_resample (resample, l2, width); \ + if (l2 != l3) \ + resample->h_resample (resample, l3, width); \ + } \ + for (i = 0; i < width; i++) { \ + type tr0 = PR0(i), tr1 = PR1(i); \ + type tr2 = PR2(i), tr3 = PR3(i); \ + type tb0 = PB0(i), tb1 = PB1(i); \ + type tb2 = PB2(i), tb3 = PB3(i); \ + \ + PR0(i) = FILT_1_1_1_1 (tr0, tr1, tr2, tr3); \ + PB0(i) = FILT_1_1_1_1 (tb0, tb1, tb2, tb3); \ + } \ +} + +MAKE_UPSAMPLE_H4 (guint16); +MAKE_UPSAMPLE_H4 (guint8); +MAKE_UPSAMPLE_V4 (guint16); +MAKE_UPSAMPLE_V4 (guint8); +MAKE_DOWNSAMPLE_H4 (guint16); +MAKE_DOWNSAMPLE_H4 (guint8); +MAKE_DOWNSAMPLE_V4 (guint16); +MAKE_DOWNSAMPLE_V4 (guint8); + +/* 2x upsampling with cositing + * + * a +------ (a + b + 1) >> 1 + * | | + * v v + * O-O-O-O + * x x + * a b + */ +#define MAKE_UPSAMPLE_H2_CS(type) \ +static void \ +video_chroma_up_h2_cs_##type (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 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(type) \ +static void \ +video_chroma_down_h2_cs_##type (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)); \ + } \ +} + +MAKE_UPSAMPLE_H2_CS (guint16); +MAKE_UPSAMPLE_H2_CS (guint8); +MAKE_DOWNSAMPLE_H2_CS (guint16); +MAKE_DOWNSAMPLE_H2_CS (guint8); + +/* 4x 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(type) \ +static void \ +video_chroma_up_h4_cs_##type (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 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(type) \ +static void \ +video_chroma_down_h4_cs_##type (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)); \ + } \ +} + +MAKE_UPSAMPLE_H4_CS (guint16); +MAKE_UPSAMPLE_H4_CS (guint8); +MAKE_DOWNSAMPLE_H4_CS (guint16); +MAKE_DOWNSAMPLE_H4_CS (guint8); + +typedef struct +{ + void (*resample) (GstVideoChromaResample * resample, gpointer pixels, + gint width); +} HorizResampler; + +static const HorizResampler h_resamplers[] = { + {NULL}, + {video_chroma_up_h2_guint8}, + {video_chroma_down_h2_guint8}, + {video_chroma_up_h2_guint16}, + {video_chroma_down_h2_guint16}, + {video_chroma_up_h2_cs_guint8}, + {video_chroma_down_h2_cs_guint8}, + {video_chroma_up_h2_cs_guint16}, + {video_chroma_down_h2_cs_guint16}, + {video_chroma_up_h4_guint8}, + {video_chroma_down_h4_guint8}, + {video_chroma_up_h4_guint16}, + {video_chroma_down_h4_guint16}, + {video_chroma_up_h4_cs_guint8}, + {video_chroma_down_h4_cs_guint8}, + {video_chroma_up_h4_cs_guint16}, + {video_chroma_down_h4_cs_guint16} +}; + +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_guint8, 2, -1}, + {video_chroma_down_v2_guint8, 2, 0}, + {video_chroma_up_v2_guint16, 2, -1}, + {video_chroma_down_v2_guint16, 2, 0}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {video_chroma_up_v4_guint8, 4, -2}, + {video_chroma_down_v4_guint8, 4, 0}, + {video_chroma_up_v4_guint16, 4, -2}, + {video_chroma_down_v4_guint16, 4, 0}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {video_chroma_up_vi2_guint8, 4, -2}, + {NULL}, + {video_chroma_up_vi2_guint16, 4, -2}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL} +}; + +/** + * gst_video_chroma_resample_new: + * @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_factoris > 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; + 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; + + 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 ("select resample %p %d, factor %d, " + "cosite %d, bits %d", result, h_index, h_factor, cosite, bits); + + 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); +} diff --git a/gst-libs/gst/video/video-chroma.h b/gst-libs/gst/video/video-chroma.h index 0dee38a6aa..63a31458e5 100644 --- a/gst-libs/gst/video/video-chroma.h +++ b/gst-libs/gst/video/video-chroma.h @@ -54,6 +54,46 @@ typedef enum { GstVideoChromaSite gst_video_chroma_from_string (const gchar * s); const gchar * gst_video_chroma_to_string (GstVideoChromaSite site); +/** + * GstVideoChromaMethod: + * @GST_VIDEO_CHROMA_METHOD_NEAREST: Duplicates the chroma samples when + * upsampling and drops when subsampling + * @GST_VIDEO_CHROMA_METHOD_LINEAR: Uses linear interpolation to reconstruct + * missing chroma and averaging to subsample + * + * Different subsampling and upsampling methods + */ +typedef enum { + GST_VIDEO_CHROMA_METHOD_NEAREST, + GST_VIDEO_CHROMA_METHOD_LINEAR +} GstVideoChromaMethod; + +/** + * GstVideoChromaFlags: + * @GST_VIDEO_CHROMA_FLAG_NONE: no flags + * + * Extra flags that influence the result from gst_video_chroma_resample_new() + * and extra features of the returned resampler. + */ +typedef enum { + GST_VIDEO_CHROMA_FLAG_NONE = 0, +} GstVideoChromaFlags; + +typedef struct _GstVideoChromaResample GstVideoChromaResample; + +GstVideoChromaResample * gst_video_chroma_resample_new (GstVideoChromaMethod method, + GstVideoChromaSite site, + GstVideoChromaFlags flags, + GstVideoFormat format, + gint h_factor, gint v_factor); +void gst_video_chroma_resample_free (GstVideoChromaResample *resample); + +void gst_video_chroma_resample_get_info (GstVideoChromaResample *resample, + guint * n_lines, gint *offset); + +void gst_video_chroma_resample (GstVideoChromaResample *resample, + gpointer lines[], gint width); + G_END_DECLS #endif /* __GST_VIDEO_CHROMA_H__ */ diff --git a/win32/common/libgstvideo.def b/win32/common/libgstvideo.def index e0008ee97b..15095f06f1 100644 --- a/win32/common/libgstvideo.def +++ b/win32/common/libgstvideo.def @@ -51,7 +51,13 @@ EXPORTS gst_video_buffer_pool_get_type gst_video_buffer_pool_new gst_video_calculate_display_ratio + gst_video_chroma_flags_get_type gst_video_chroma_from_string + gst_video_chroma_method_get_type + gst_video_chroma_resample + gst_video_chroma_resample_free + gst_video_chroma_resample_get_info + gst_video_chroma_resample_new gst_video_chroma_site_get_type gst_video_chroma_to_string gst_video_codec_frame_get_type