From 8379d20ec6c9b31943d49a86b2bb530ce242a08a Mon Sep 17 00:00:00 2001 From: David Schleef Date: Mon, 15 Mar 2010 01:26:25 -0700 Subject: [PATCH] cog: implement chroma-site Determine chroma site position from the caps and use it when upsampling/downsampling chroma. --- ext/cog/cog.orc | 63 +++++++++++++++ ext/cog/cogframe.c | 3 +- ext/cog/cogframe.h | 6 ++ ext/cog/cogvirtframe.c | 160 ++++++++++++++++++++++++++++++++----- ext/cog/cogvirtframe.h | 3 +- ext/cog/gstcogcolorspace.c | 37 +++++++-- ext/cog/gstcolorconvert.c | 12 ++- ext/cog/gstlogoinsert.c | 6 +- 8 files changed, 256 insertions(+), 34 deletions(-) diff --git a/ext/cog/cog.orc b/ext/cog/cog.orc index fa8d2d43a6..2322312499 100644 --- a/ext/cog/cog.orc +++ b/ext/cog/cog.orc @@ -32,6 +32,69 @@ shrsw t4, t4, 2 convsuswb d1, t4 +.function cogorc_downsample_420_jpeg +.dest 1 d1 +.source 2 s1 +.source 2 s2 +.temp 2 t1 +.temp 1 t2 +.temp 1 t3 +.temp 1 t4 +.temp 1 t5 + +copyw t1, s1 +select0wb t2, t1 +select1wb t3, t1 +avgub t2, t2, t3 +copyw t1, s2 +select0wb t4, t1 +select1wb t5, t1 +avgub t4, t4, t5 +avgub d1, t2, t4 + + +.function cogorc_downsample_420_mpeg2 +.dest 1 d1 +.source 2 s1 +.source 2 s2 +.source 2 s3 +.source 2 s4 +.temp 1 t1 +.temp 1 t2 +.temp 1 t3 +.temp 2 t4 +.temp 2 t5 +.temp 2 t6 +.temp 2 t7 + +copyw t4, s1 +select0wb t1, t4 +select1wb t2, t4 +select0wb t3, s2 +convubw t4, t1 +convubw t5, t2 +convubw t6, t3 +mullw t5, t5, 2 +addw t4, t4, t6 +addw t7, t4, t5 +copyw t4, s3 + +select0wb t1, t4 +select1wb t2, t4 +select0wb t3, s4 +convubw t4, t1 +convubw t5, t2 +convubw t6, t3 +mullw t5, t5, 2 +addw t4, t4, t6 +addw t4, t4, t5 + +addw t7, t7, t4 +addw t7, t7, 4 +shrsw t7, t7, 3 +convsuswb d1, t7 + + .function cogorc_downsample_vert_halfsite_2tap .dest 1 d1 .source 1 s1 diff --git a/ext/cog/cogframe.c b/ext/cog/cogframe.c index 50a21891d0..10210b0027 100644 --- a/ext/cog/cogframe.c +++ b/ext/cog/cogframe.c @@ -864,7 +864,8 @@ cog_frame_convert (CogFrame * dest, CogFrame * src) } if ((dest_format & 3) != (frame->format & 3)) { - frame = cog_virt_frame_new_subsample (frame, dest_format, 2); + frame = cog_virt_frame_new_subsample (frame, dest_format, + COG_CHROMA_SITE_MPEG2, 2); GST_DEBUG ("subsample %p", frame); } diff --git a/ext/cog/cogframe.h b/ext/cog/cogframe.h index 2aa7a02f57..a1b013ed18 100644 --- a/ext/cog/cogframe.h +++ b/ext/cog/cogframe.h @@ -19,6 +19,12 @@ typedef enum _CogColorMatrix { COG_COLOR_MATRIX_SDTV } CogColorMatrix; +typedef enum _CogChromaSite { + COG_CHROMA_SITE_UNKNOWN = 0, + COG_CHROMA_SITE_MPEG2 = 1, + COG_CHROMA_SITE_JPEG +} CogChromaSite; + /* bit pattern: * 0x100 - 0: normal, 1: indirect (packed) * 0x001 - horizontal chroma subsampling: 0: 1, 1: 2 diff --git a/ext/cog/cogvirtframe.c b/ext/cog/cogvirtframe.c index f8b3cef906..1adfef4044 100644 --- a/ext/cog/cogvirtframe.c +++ b/ext/cog/cogvirtframe.c @@ -1524,6 +1524,9 @@ cog_virt_frame_new_color_matrix_YCbCr_to_YCbCr (CogFrame * vf, { CogFrame *virt_frame; + if (in_color_matrix == out_color_matrix) + return vf; + virt_frame = cog_frame_new_virtual (NULL, COG_FRAME_FORMAT_U8_444, vf->width, vf->height); virt_frame->virt_frame1 = vf; @@ -1593,8 +1596,132 @@ convert_422_420 (CogFrame * frame, void *_dest, int component, int i) } } +static void +convert_444_420_mpeg2 (CogFrame * frame, void *_dest, int component, int i) +{ + uint8_t *dest = _dest; + uint8_t *src; + + if (component == 0) { + src = cog_virt_frame_get_line (frame->virt_frame1, component, i); + orc_memcpy (dest, src, frame->components[component].width); + } else { + uint8_t *dest = _dest; + uint8_t *src1; + uint8_t *src2; + int n_src; + + n_src = frame->virt_frame1->components[component].height; + src1 = cog_virt_frame_get_line (frame->virt_frame1, component, + CLAMP (i * 2 + 0, 0, n_src - 1)); + src2 = cog_virt_frame_get_line (frame->virt_frame1, component, + CLAMP (i * 2 + 1, 0, n_src - 1)); + + cogorc_downsample_420_mpeg2 (dest + 1, + (uint16_t *) src1, (uint16_t *) (src1 + 2), + (uint16_t *) src2, (uint16_t *) (src2 + 2), + frame->components[component].width - 1); + { + int j; + int x; + + j = 0; + x = 1 * src1[CLAMP (j * 2 - 1, 0, n_src - 1)]; + x += 2 * src1[CLAMP (j * 2 + 0, 0, n_src - 1)]; + x += 1 * src1[CLAMP (j * 2 + 1, 0, n_src - 1)]; + x += 1 * src2[CLAMP (j * 2 - 1, 0, n_src - 1)]; + x += 2 * src2[CLAMP (j * 2 + 0, 0, n_src - 1)]; + x += 1 * src2[CLAMP (j * 2 + 1, 0, n_src - 1)]; + dest[j] = CLAMP ((x + 4) >> 3, 0, 255); + } + } +} + +static void +convert_444_420_jpeg (CogFrame * frame, void *_dest, int component, int i) +{ + uint8_t *dest = _dest; + uint8_t *src; + + if (component == 0) { + src = cog_virt_frame_get_line (frame->virt_frame1, component, i); + orc_memcpy (dest, src, frame->components[component].width); + } else { + uint8_t *dest = _dest; + uint8_t *src1; + uint8_t *src2; + int n_src; + + n_src = frame->virt_frame1->components[component].height; + src1 = cog_virt_frame_get_line (frame->virt_frame1, component, + CLAMP (i * 2 + 0, 0, n_src - 1)); + src2 = cog_virt_frame_get_line (frame->virt_frame1, component, + CLAMP (i * 2 + 1, 0, n_src - 1)); + + cogorc_downsample_420_jpeg (dest, + (uint16_t *) src1, (uint16_t *) src2, + frame->components[component].width); + } +} + /* up */ +static void +convert_420_444_mpeg2 (CogFrame * frame, void *_dest, int component, int i) +{ + uint8_t *dest = _dest; + uint8_t *src; + int n_taps = frame->param1; + + if (component == 0) { + src = cog_virt_frame_get_line (frame->virt_frame1, component, i); + + orc_memcpy (dest, src, frame->width); + } else { + src = cog_virt_frame_get_line (frame->virt_frame1, component, i / 2); + + switch (n_taps) { + default: + case 2: + cogorc_upsample_horiz_cosite (dest, src, src + 1, + frame->components[component].width / 2 - 1); + break; + } + dest[frame->components[component].width - 2] = + src[frame->components[component].width / 2 - 1]; + dest[frame->components[component].width - 1] = + src[frame->components[component].width / 2 - 1]; + } +} + +static void +convert_420_444_jpeg (CogFrame * frame, void *_dest, int component, int i) +{ + uint8_t *dest = _dest; + uint8_t *src; + int n_taps = frame->param1; + + if (component == 0) { + src = cog_virt_frame_get_line (frame->virt_frame1, component, i); + + orc_memcpy (dest, src, frame->width); + } else { + src = cog_virt_frame_get_line (frame->virt_frame1, component, i / 2); + + switch (n_taps) { + default: + case 1: + cogorc_upsample_horiz_cosite_1tap (dest, src, + frame->components[component].width / 2 - 1); + break; + } + dest[frame->components[component].width - 2] = + src[frame->components[component].width / 2 - 1]; + dest[frame->components[component].width - 1] = + src[frame->components[component].width / 2 - 1]; + } +} + static void convert_422_444 (CogFrame * frame, void *_dest, int component, int i) { @@ -1609,10 +1736,6 @@ convert_422_444 (CogFrame * frame, void *_dest, int component, int i) } else { switch (n_taps) { default: - case 1: - cogorc_upsample_horiz_cosite_1tap (dest, src, - frame->components[component].width / 2 - 1); - break; case 2: cogorc_upsample_horiz_cosite (dest, src, src + 1, frame->components[component].width / 2 - 1); @@ -1661,7 +1784,8 @@ convert_420_422 (CogFrame * frame, void *_dest, int component, int i) } CogFrame * -cog_virt_frame_new_subsample (CogFrame * vf, CogFrameFormat format, int n_taps) +cog_virt_frame_new_subsample (CogFrame * vf, CogFrameFormat format, + CogChromaSite chroma_site, int n_taps) { CogFrame *virt_frame; CogFrameRenderFunc render_line; @@ -1674,14 +1798,11 @@ cog_virt_frame_new_subsample (CogFrame * vf, CogFrameFormat format, int n_taps) render_line = convert_422_420; } else if (vf->format == COG_FRAME_FORMAT_U8_444 && format == COG_FRAME_FORMAT_U8_420) { - virt_frame = cog_frame_new_virtual (NULL, COG_FRAME_FORMAT_U8_422, - vf->width, vf->height); - virt_frame->virt_frame1 = vf; - virt_frame->render_line = convert_444_422; - virt_frame->param1 = n_taps; - vf = virt_frame; - - render_line = convert_422_420; + if (chroma_site == COG_CHROMA_SITE_MPEG2) { + render_line = convert_444_420_mpeg2; + } else { + render_line = convert_444_420_jpeg; + } } else if (vf->format == COG_FRAME_FORMAT_U8_444 && format == COG_FRAME_FORMAT_U8_422) { render_line = convert_444_422; @@ -1690,14 +1811,11 @@ cog_virt_frame_new_subsample (CogFrame * vf, CogFrameFormat format, int n_taps) render_line = convert_420_422; } else if (vf->format == COG_FRAME_FORMAT_U8_420 && format == COG_FRAME_FORMAT_U8_444) { - virt_frame = cog_frame_new_virtual (NULL, COG_FRAME_FORMAT_U8_422, - vf->width, vf->height); - virt_frame->virt_frame1 = vf; - virt_frame->render_line = convert_420_422; - virt_frame->param1 = n_taps; - vf = virt_frame; - - render_line = convert_422_444; + if (chroma_site == COG_CHROMA_SITE_MPEG2) { + render_line = convert_420_444_mpeg2; + } else { + render_line = convert_420_444_jpeg; + } } else if (vf->format == COG_FRAME_FORMAT_U8_422 && format == COG_FRAME_FORMAT_U8_444) { render_line = convert_422_444; diff --git a/ext/cog/cogvirtframe.h b/ext/cog/cogvirtframe.h index 2054e9586f..afd5736b8d 100644 --- a/ext/cog/cogvirtframe.h +++ b/ext/cog/cogvirtframe.h @@ -32,7 +32,8 @@ CogFrame * cog_virt_frame_new_color_matrix_RGB_to_YCbCr (CogFrame * vf, CogColor CogFrame * cog_virt_frame_new_color_matrix_YCbCr_to_YCbCr (CogFrame * vf, CogColorMatrix in_color_matrix, CogColorMatrix out_color_matrix, int bits); -CogFrame *cog_virt_frame_new_subsample (CogFrame *vf, CogFrameFormat format, int n_taps); +CogFrame *cog_virt_frame_new_subsample (CogFrame *vf, CogFrameFormat format, + CogChromaSite site, int n_taps); CogFrame * cog_virt_frame_new_convert_u8 (CogFrame *vf); CogFrame * cog_virt_frame_new_convert_s16 (CogFrame *vf); diff --git a/ext/cog/gstcogcolorspace.c b/ext/cog/gstcogcolorspace.c index 5f9d38ea8b..ede5d53846 100644 --- a/ext/cog/gstcogcolorspace.c +++ b/ext/cog/gstcogcolorspace.c @@ -275,6 +275,7 @@ gst_cogcolorspace_caps_remove_format_info (GstCaps * caps) gst_structure_remove_field (structure, "alpha_mask"); gst_structure_remove_field (structure, "palette_data"); gst_structure_remove_field (structure, "color-matrix"); + gst_structure_remove_field (structure, "chroma-site"); } gst_caps_do_simplify (caps); @@ -365,6 +366,25 @@ gst_cogcolorspace_caps_get_color_matrix (GstCaps * caps) return COG_COLOR_MATRIX_SDTV; } +static CogChromaSite +gst_cogcolorspace_caps_get_chroma_site (GstCaps * caps) +{ + const char *s; + + s = gst_video_parse_caps_chroma_site (caps); + + if (s == NULL) + return COG_COLOR_MATRIX_SDTV; + + if (strcmp (s, "jpeg") == 0) { + return COG_CHROMA_SITE_JPEG; + } else if (strcmp (s, "mpeg2") == 0) { + return COG_CHROMA_SITE_MPEG2; + } + + return COG_CHROMA_SITE_MPEG2; +} + static GstFlowReturn gst_cogcolorspace_transform (GstBaseTransform * base_transform, GstBuffer * inbuf, GstBuffer * outbuf) @@ -379,6 +399,8 @@ gst_cogcolorspace_transform (GstBaseTransform * base_transform, gboolean ret; CogColorMatrix in_color_matrix; CogColorMatrix out_color_matrix; + CogChromaSite in_chroma_site; + CogChromaSite out_chroma_site; g_return_val_if_fail (GST_IS_COGCOLORSPACE (base_transform), GST_FLOW_ERROR); compress = GST_COGCOLORSPACE (base_transform); @@ -393,6 +415,9 @@ gst_cogcolorspace_transform (GstBaseTransform * base_transform, in_color_matrix = gst_cogcolorspace_caps_get_color_matrix (inbuf->caps); out_color_matrix = gst_cogcolorspace_caps_get_color_matrix (outbuf->caps); + in_chroma_site = gst_cogcolorspace_caps_get_chroma_site (inbuf->caps); + out_chroma_site = gst_cogcolorspace_caps_get_chroma_site (outbuf->caps); + frame = gst_cog_buffer_wrap (gst_buffer_ref (inbuf), in_format, width, height); out_frame = gst_cog_buffer_wrap (gst_buffer_ref (outbuf), @@ -431,22 +456,24 @@ gst_cogcolorspace_transform (GstBaseTransform * base_transform, gst_video_format_is_rgb (in_format)) { frame = cog_virt_frame_new_color_matrix_RGB_to_YCbCr (frame, out_color_matrix, 8); + frame = cog_virt_frame_new_subsample (frame, new_subsample, + out_chroma_site, (compress->quality >= 3) ? 2 : 1); } if (gst_video_format_is_yuv (out_format) && gst_video_format_is_yuv (in_format) && - in_color_matrix != out_color_matrix) { + (in_color_matrix != out_color_matrix || + in_chroma_site != out_chroma_site)) { frame = cog_virt_frame_new_subsample (frame, COG_FRAME_FORMAT_U8_444, - (compress->quality >= 5) ? 8 : 6); + in_chroma_site, (compress->quality >= 5) ? 8 : 6); frame = cog_virt_frame_new_color_matrix_YCbCr_to_YCbCr (frame, in_color_matrix, out_color_matrix, 8); } - frame = cog_virt_frame_new_subsample (frame, new_subsample, - (compress->quality >= 3) ? 2 : 1); - if (gst_video_format_is_rgb (out_format) && gst_video_format_is_yuv (in_format)) { + frame = cog_virt_frame_new_subsample (frame, new_subsample, + in_chroma_site, (compress->quality >= 3) ? 2 : 1); frame = cog_virt_frame_new_color_matrix_YCbCr_to_RGB (frame, in_color_matrix, (compress->quality >= 5) ? 8 : 6); } diff --git a/ext/cog/gstcolorconvert.c b/ext/cog/gstcolorconvert.c index f04583a059..9309ceb330 100644 --- a/ext/cog/gstcolorconvert.c +++ b/ext/cog/gstcolorconvert.c @@ -238,18 +238,22 @@ gst_colorconvert_transform_ip (GstBaseTransform * base_transform, li->format, li->width, li->height); vf = cog_virt_frame_new_unpack (cog_frame_ref (frame)); - vf = cog_virt_frame_new_subsample (vf, COG_FRAME_FORMAT_U8_444, 2); + vf = cog_virt_frame_new_subsample (vf, COG_FRAME_FORMAT_U8_444, + COG_CHROMA_SITE_MPEG2, 2); vf = cog_virt_frame_new_color_transform (vf); if (frame->format == COG_FRAME_FORMAT_YUYV) { - vf = cog_virt_frame_new_subsample (vf, COG_FRAME_FORMAT_U8_422, 2); + vf = cog_virt_frame_new_subsample (vf, COG_FRAME_FORMAT_U8_422, + COG_CHROMA_SITE_MPEG2, 2); vf = cog_virt_frame_new_pack_YUY2 (vf); } else if (frame->format == COG_FRAME_FORMAT_UYVY) { - vf = cog_virt_frame_new_subsample (vf, COG_FRAME_FORMAT_U8_422, 2); + vf = cog_virt_frame_new_subsample (vf, COG_FRAME_FORMAT_U8_422, + COG_CHROMA_SITE_MPEG2, 2); vf = cog_virt_frame_new_pack_UYVY (vf); } else if (frame->format == COG_FRAME_FORMAT_AYUV) { vf = cog_virt_frame_new_pack_AYUV (vf); } else if (frame->format == COG_FRAME_FORMAT_U8_420) { - vf = cog_virt_frame_new_subsample (vf, COG_FRAME_FORMAT_U8_420, 2); + vf = cog_virt_frame_new_subsample (vf, COG_FRAME_FORMAT_U8_420, + COG_CHROMA_SITE_MPEG2, 2); } else { g_assert_not_reached (); } diff --git a/ext/cog/gstlogoinsert.c b/ext/cog/gstlogoinsert.c index 97e7ac406f..d49ad49896 100644 --- a/ext/cog/gstlogoinsert.c +++ b/ext/cog/gstlogoinsert.c @@ -261,13 +261,15 @@ gst_logoinsert_transform_ip (GstBaseTransform * base_transform, GstBuffer * buf) CogFrame *f; f = cog_virt_frame_extract_alpha (cog_frame_ref (li->argb_frame)); - f = cog_virt_frame_new_subsample (f, frame->format, 2); + f = cog_virt_frame_new_subsample (f, frame->format, + COG_CHROMA_SITE_MPEG2, 2); li->alpha_frame = cog_frame_realize (f); f = cog_virt_frame_new_unpack (cog_frame_ref (li->argb_frame)); f = cog_virt_frame_new_color_matrix_RGB_to_YCbCr (f, COG_COLOR_MATRIX_SDTV, 8); - f = cog_virt_frame_new_subsample (f, frame->format, 2); + f = cog_virt_frame_new_subsample (f, frame->format, + COG_CHROMA_SITE_MPEG2, 2); li->overlay_frame = cog_frame_realize (f); }