From 531c6fb462ae0a770cc5abd9eee54a1e019fa093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 9 May 2008 08:34:52 +0000 Subject: [PATCH] gst/ffmpegcolorspace/: Add conversions from/to NV12 and NV21 and conversions between those two formats. Fixes bug #53... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Original commit message from CVS: Based on a patch by: Björn Benderius * gst/ffmpegcolorspace/avcodec.h: * gst/ffmpegcolorspace/gstffmpegcodecmap.c: (gst_ffmpeg_pixfmt_to_caps), (gst_ffmpeg_caps_to_pixfmt), (gst_ffmpegcsp_avpicture_fill): * gst/ffmpegcolorspace/imgconvert.c: (nv12_to_nv21): * gst/ffmpegcolorspace/imgconvert_template.h: Add conversions from/to NV12 and NV21 and conversions between those two formats. Fixes bug #532166. --- ChangeLog | 14 + common | 2 +- gst/ffmpegcolorspace/avcodec.h | 6 +- gst/ffmpegcolorspace/gstffmpegcodecmap.c | 28 ++ gst/ffmpegcolorspace/imgconvert.c | 121 +++++++ gst/ffmpegcolorspace/imgconvert_template.h | 384 ++++++++++++++++++++- 6 files changed, 551 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8592f51e43..139a9a1936 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2008-05-09 Sebastian Dröge + + Based on a patch by: + Björn Benderius + + * gst/ffmpegcolorspace/avcodec.h: + * gst/ffmpegcolorspace/gstffmpegcodecmap.c: + (gst_ffmpeg_pixfmt_to_caps), (gst_ffmpeg_caps_to_pixfmt), + (gst_ffmpegcsp_avpicture_fill): + * gst/ffmpegcolorspace/imgconvert.c: (nv12_to_nv21): + * gst/ffmpegcolorspace/imgconvert_template.h: + Add conversions from/to NV12 and NV21 and conversions between those + two formats. Fixes bug #532166. + 2008-05-08 Edward Hervey * gst/typefind/gsttypefindfunctions.c: (h264_video_type_find): diff --git a/common b/common index ba3dd2882b..dbf8f3aece 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit ba3dd2882b1611f8115f9664e3b85e1fd956b53d +Subproject commit dbf8f3aeceb6e57de097951a670cd853b4886ad8 diff --git a/gst/ffmpegcolorspace/avcodec.h b/gst/ffmpegcolorspace/avcodec.h index 58eb9770b5..942ef24e30 100644 --- a/gst/ffmpegcolorspace/avcodec.h +++ b/gst/ffmpegcolorspace/avcodec.h @@ -53,6 +53,8 @@ enum CodecType { */ enum PixelFormat { PIX_FMT_YUV420P, ///< Planar YUV 4:2:0 (1 Cr & Cb sample per 2x2 Y samples) (I420) + PIX_FMT_NV12, ///< Packed YUV 4:2:0 (separate Y plane, interleaved Cb & Cr planes) + PIX_FMT_NV21, ///< Packed YUV 4:2:0 (separate Y plane, interleaved Cb & Cr planes) PIX_FMT_YVU420P, ///< Planar YUV 4:2:0 (1 Cb & Cr sample per 2x2 Y samples) (YV12) PIX_FMT_YUV422, ///< Packed pixel, Y0 Cb Y1 Cr PIX_FMT_RGB24, ///< Packed pixel, 3 bytes per pixel, RGBRGB... @@ -60,9 +62,9 @@ enum PixelFormat { PIX_FMT_YUV422P, ///< Planar YUV 4:2:2 (1 Cr & Cb sample per 2x1 Y samples) PIX_FMT_YUV444P, ///< Planar YUV 4:4:4 (1 Cr & Cb sample per 1x1 Y samples) PIX_FMT_RGBA32, ///< Packed pixel, 4 bytes per pixel, BGRABGRA..., stored in cpu endianness - PIX_FMT_BGRA32, ///< Packed pixel, 4 bytes per pixel, ARGBARGB... + PIX_FMT_BGRA32, ///< Packed pixel, 4 bytes per pixel, ARGBARGB... PIX_FMT_ARGB32, ///< Packed pixel, 4 bytes per pixel, ABGRABGR..., stored in cpu endianness - PIX_FMT_ABGR32, ///< Packed pixel, 4 bytes per pixel, RGBARGBA... + PIX_FMT_ABGR32, ///< Packed pixel, 4 bytes per pixel, RGBARGBA... PIX_FMT_RGB32, ///< Packed pixel, 4 bytes per pixel, BGRxBGRx..., stored in cpu endianness PIX_FMT_xRGB32, ///< Packed pixel, 4 bytes per pixel, xBGRxBGR..., stored in cpu endianness PIX_FMT_BGR32, ///< Packed pixel, 4 bytes per pixel, xRGBxRGB... diff --git a/gst/ffmpegcolorspace/gstffmpegcodecmap.c b/gst/ffmpegcolorspace/gstffmpegcodecmap.c index 96e1a640d6..9d32221ef2 100644 --- a/gst/ffmpegcolorspace/gstffmpegcodecmap.c +++ b/gst/ffmpegcolorspace/gstffmpegcodecmap.c @@ -167,6 +167,12 @@ gst_ffmpeg_pixfmt_to_caps (enum PixelFormat pix_fmt, AVCodecContext * context) case PIX_FMT_YUV420P: fmt = GST_MAKE_FOURCC ('I', '4', '2', '0'); break; + case PIX_FMT_NV12: + fmt = GST_MAKE_FOURCC ('N', 'V', '1', '2'); + break; + case PIX_FMT_NV21: + fmt = GST_MAKE_FOURCC ('N', 'V', '2', '1'); + break; case PIX_FMT_YVU420P: fmt = GST_MAKE_FOURCC ('Y', 'V', '1', '2'); break; @@ -593,6 +599,12 @@ gst_ffmpeg_caps_to_pixfmt (const GstCaps * caps, case GST_MAKE_FOURCC ('I', '4', '2', '0'): context->pix_fmt = PIX_FMT_YUV420P; break; + case GST_MAKE_FOURCC ('N', 'V', '1', '2'): + context->pix_fmt = PIX_FMT_NV12; + break; + case GST_MAKE_FOURCC ('N', 'V', '2', '1'): + context->pix_fmt = PIX_FMT_NV21; + break; case GST_MAKE_FOURCC ('Y', 'V', '1', '2'): context->pix_fmt = PIX_FMT_YVU420P; break; @@ -799,6 +811,22 @@ gst_ffmpegcsp_avpicture_fill (AVPicture * picture, picture->linesize[1] = stride2; picture->linesize[2] = stride2; return size + 2 * size2; + case PIX_FMT_NV12: + case PIX_FMT_NV21: + stride = GST_ROUND_UP_4 (width); + h2 = ROUND_UP_X (height, pinfo->y_chroma_shift); + size = stride * h2; + w2 = 2 * DIV_ROUND_UP_X (width, pinfo->x_chroma_shift); + stride2 = GST_ROUND_UP_4 (w2); + h2 = DIV_ROUND_UP_X (height, pinfo->y_chroma_shift); + size2 = stride2 * h2; + picture->data[0] = ptr; + picture->data[1] = picture->data[0] + size; + picture->data[2] = NULL; + picture->linesize[0] = stride; + picture->linesize[1] = stride2; + picture->linesize[2] = 0; + return size + size2; case PIX_FMT_RGB24: case PIX_FMT_BGR24: stride = GST_ROUND_UP_4 (width * 3); diff --git a/gst/ffmpegcolorspace/imgconvert.c b/gst/ffmpegcolorspace/imgconvert.c index b7d47cbc36..9c6ad0e7dc 100644 --- a/gst/ffmpegcolorspace/imgconvert.c +++ b/gst/ffmpegcolorspace/imgconvert.c @@ -64,6 +64,28 @@ static PixFmtInfo pix_fmt_info[PIX_FMT_NB] = { /* .y_chroma_shift = */ 1, /* .depth = */ 8, }, + /* [PIX_FMT_NV12] = */ { + /* .format = */ PIX_FMT_NV12, + /* .name = */ "nv12", + /* .nb_channels = */ 2, + /* .color_type = */ FF_COLOR_YUV, + /* .pixel_type = */ FF_PIXEL_PACKED, + /* .is_alpha = */ 0, + /* .x_chroma_shift = */ 1, + /* .y_chroma_shift = */ 1, + /* .depth = */ 8, + }, + /* [PIX_FMT_NV21] = */ { + /* .format = */ PIX_FMT_NV21, + /* .name = */ "nv21", + /* .nb_channels = */ 2, + /* .color_type = */ FF_COLOR_YUV, + /* .pixel_type = */ FF_PIXEL_PACKED, + /* .is_alpha = */ 0, + /* .x_chroma_shift = */ 1, + /* .y_chroma_shift = */ 1, + /* .depth = */ 8, + }, /* [PIX_FMT_YUV422P] = */ { /* .format = */ PIX_FMT_YUV422P, /* .name = */ "yuv422p", @@ -1082,6 +1104,53 @@ yuv420p_to_yuv422 (AVPicture * dst, const AVPicture * src, } } +static void +nv12_to_nv21 (AVPicture * dst, const AVPicture * src, int width, int height) +{ + const uint8_t *s_c_ptr; + uint8_t *d_c_ptr; + int w; + + s_c_ptr = src->data[1]; + d_c_ptr = dst->data[1]; + + for (; height >= 2; height -= 2) { + for (w = width; w >= 2; w -= 2) { + d_c_ptr[0] = s_c_ptr[1]; + d_c_ptr[1] = s_c_ptr[0]; + s_c_ptr += 2; + d_c_ptr += 2; + } + + /* handle odd width */ + if (w) { + d_c_ptr[0] = s_c_ptr[1]; + d_c_ptr[1] = s_c_ptr[0]; + s_c_ptr += 2; + d_c_ptr += 2; + } + } + /* handle odd height */ + if (height) { + for (w = width; w >= 2; w -= 2) { + d_c_ptr[0] = s_c_ptr[1]; + d_c_ptr[1] = s_c_ptr[0]; + s_c_ptr += 2; + d_c_ptr += 2; + } + + /* handle odd width */ + if (w) { + d_c_ptr[0] = s_c_ptr[1]; + d_c_ptr[1] = s_c_ptr[0]; + s_c_ptr += 2; + d_c_ptr += 2; + } + } +} + +#define nv21_to_nv12 nv12_to_nv21 + #define SCALEBITS 10 #define ONE_HALF (1 << (SCALEBITS - 1)) #define FIX(x) ((int) ((x) * (1<data[0]; + y1_ptr = src->data[0]; + c_ptr = src->data[1]; + for(;height >= 2; height -= 2) { + d1 = d; + d2 = d + dst->linesize[0]; + y2_ptr = y1_ptr + src->linesize[0]; + for(w = width; w >= 2; w -= 2) { + YUV_TO_RGB1_CCIR(c_ptr[0], c_ptr[1]); + /* output 4 pixels */ + YUV_TO_RGB2_CCIR(r, g, b, y1_ptr[0]); + RGB_OUT(d1, r, g, b); + + YUV_TO_RGB2_CCIR(r, g, b, y1_ptr[1]); + RGB_OUT(d1 + BPP, r, g, b); + + YUV_TO_RGB2_CCIR(r, g, b, y2_ptr[0]); + RGB_OUT(d2, r, g, b); + + YUV_TO_RGB2_CCIR(r, g, b, y2_ptr[1]); + RGB_OUT(d2 + BPP, r, g, b); + + d1 += 2 * BPP; + d2 += 2 * BPP; + + y1_ptr += 2; + y2_ptr += 2; + c_ptr += 2; + } + /* handle odd width */ + if (w) { + YUV_TO_RGB1_CCIR(c_ptr[0], c_ptr[1]); + YUV_TO_RGB2_CCIR(r, g, b, y1_ptr[0]); + RGB_OUT(d1, r, g, b); + + YUV_TO_RGB2_CCIR(r, g, b, y2_ptr[0]); + RGB_OUT(d2, r, g, b); + d1 += BPP; + d2 += BPP; + y1_ptr++; + y2_ptr++; + c_ptr += 2; + } + d += 2 * dst->linesize[0]; + y1_ptr += 2 * src->linesize[0] - width; + c_ptr += src->linesize[1] - width; + } + /* handle odd height */ + if (height) { + d1 = d; + for(w = width; w >= 2; w -= 2) { + YUV_TO_RGB1_CCIR(c_ptr[0], c_ptr[1]); + /* output 2 pixels */ + YUV_TO_RGB2_CCIR(r, g, b, y1_ptr[0]); + RGB_OUT(d1, r, g, b); + + YUV_TO_RGB2_CCIR(r, g, b, y1_ptr[1]); + RGB_OUT(d1 + BPP, r, g, b); + + d1 += 2 * BPP; + + y1_ptr += 2; + c_ptr += 2; + } + /* handle odd width */ + if (w) { + YUV_TO_RGB1_CCIR(c_ptr[0], c_ptr[1]); + /* output 1 pixel */ + YUV_TO_RGB2_CCIR(r, g, b, y1_ptr[0]); + RGB_OUT(d1, r, g, b); + d1 += BPP; + + y1_ptr++; + c_ptr += 2; + } + } +} + +static void glue(nv21_to_, RGB_NAME)(AVPicture *dst, const AVPicture *src, + int width, int height) +{ + const uint8_t *y1_ptr, *y2_ptr, *c_ptr; + uint8_t *d, *d1, *d2; + int w, y, cb, cr, r_add, g_add, b_add; + uint8_t *cm = cropTbl + MAX_NEG_CROP; + unsigned int r, g, b; + + d = dst->data[0]; + y1_ptr = src->data[0]; + c_ptr = src->data[1]; + for(;height >= 2; height -= 2) { + d1 = d; + d2 = d + dst->linesize[0]; + y2_ptr = y1_ptr + src->linesize[0]; + for(w = width; w >= 2; w -= 2) { + YUV_TO_RGB1_CCIR(c_ptr[1], c_ptr[0]); + /* output 4 pixels */ + YUV_TO_RGB2_CCIR(r, g, b, y1_ptr[0]); + RGB_OUT(d1, r, g, b); + + YUV_TO_RGB2_CCIR(r, g, b, y1_ptr[1]); + RGB_OUT(d1 + BPP, r, g, b); + + YUV_TO_RGB2_CCIR(r, g, b, y2_ptr[0]); + RGB_OUT(d2, r, g, b); + + YUV_TO_RGB2_CCIR(r, g, b, y2_ptr[1]); + RGB_OUT(d2 + BPP, r, g, b); + + d1 += 2 * BPP; + d2 += 2 * BPP; + + y1_ptr += 2; + y2_ptr += 2; + c_ptr += 2; + } + /* handle odd width */ + if (w) { + YUV_TO_RGB1_CCIR(c_ptr[1], c_ptr[0]); + YUV_TO_RGB2_CCIR(r, g, b, y1_ptr[0]); + RGB_OUT(d1, r, g, b); + + YUV_TO_RGB2_CCIR(r, g, b, y2_ptr[0]); + RGB_OUT(d2, r, g, b); + d1 += BPP; + d2 += BPP; + y1_ptr++; + y2_ptr++; + c_ptr += 2; + } + d += 2 * dst->linesize[0]; + y1_ptr += 2 * src->linesize[0] - width; + c_ptr += src->linesize[1] - width; + } + /* handle odd height */ + if (height) { + d1 = d; + for(w = width; w >= 2; w -= 2) { + YUV_TO_RGB1_CCIR(c_ptr[1], c_ptr[0]); + /* output 2 pixels */ + YUV_TO_RGB2_CCIR(r, g, b, y1_ptr[0]); + RGB_OUT(d1, r, g, b); + + YUV_TO_RGB2_CCIR(r, g, b, y1_ptr[1]); + RGB_OUT(d1 + BPP, r, g, b); + + d1 += 2 * BPP; + + y1_ptr += 2; + c_ptr += 2; + } + /* handle odd width */ + if (w) { + YUV_TO_RGB1_CCIR(c_ptr[1], c_ptr[0]); + /* output 1 pixel */ + YUV_TO_RGB2_CCIR(r, g, b, y1_ptr[0]); + RGB_OUT(d1, r, g, b); + d1 += BPP; + + y1_ptr++; + c_ptr += 2; + } + } +} + static void glue(yuvj420p_to_, RGB_NAME)(AVPicture *dst, const AVPicture *src, int width, int height) { @@ -317,6 +491,214 @@ static void glue(RGB_NAME, _to_yuv420p)(AVPicture *dst, const AVPicture *src, } } +static void glue(RGB_NAME, _to_nv12)(AVPicture *dst, const AVPicture *src, + int width, int height) +{ + int wrap, wrap3; + int r, g, b, r1, g1, b1, w; + uint8_t *lum, *c; + const uint8_t *p; + + lum = dst->data[0]; + c = dst->data[1]; + + wrap = dst->linesize[0]; + wrap3 = src->linesize[0]; + p = src->data[0]; + for(;height>=2;height -= 2) { + for(w = width; w >= 2; w -= 2) { + RGB_IN(r, g, b, p); + r1 = r; + g1 = g; + b1 = b; + lum[0] = RGB_TO_Y_CCIR(r, g, b); + + RGB_IN(r, g, b, p + BPP); + r1 += r; + g1 += g; + b1 += b; + lum[1] = RGB_TO_Y_CCIR(r, g, b); + p += wrap3; + lum += wrap; + + RGB_IN(r, g, b, p); + r1 += r; + g1 += g; + b1 += b; + lum[0] = RGB_TO_Y_CCIR(r, g, b); + + RGB_IN(r, g, b, p + BPP); + r1 += r; + g1 += g; + b1 += b; + lum[1] = RGB_TO_Y_CCIR(r, g, b); + + c[0] = RGB_TO_U_CCIR(r1, g1, b1, 2); + c[1] = RGB_TO_V_CCIR(r1, g1, b1, 2); + + + c += 2; + p += -wrap3 + 2 * BPP; + lum += -wrap + 2; + } + /* handle odd width */ + if (w) { + RGB_IN(r, g, b, p); + r1 = r; + g1 = g; + b1 = b; + lum[0] = RGB_TO_Y_CCIR(r, g, b); + p += wrap3; + lum += wrap; + RGB_IN(r, g, b, p); + r1 += r; + g1 += g; + b1 += b; + lum[0] = RGB_TO_Y_CCIR(r, g, b); + c[0] = RGB_TO_U_CCIR(r1, g1, b1, 1); + c[1] = RGB_TO_V_CCIR(r1, g1, b1, 1); + c += 2; + p += -wrap3 + BPP; + lum += -wrap + 1; + } + p += wrap3 + (wrap3 - width * BPP); + lum += wrap + (wrap - width); + c += dst->linesize[1] - width; + } + /* handle odd height */ + if (height) { + for(w = width; w >= 2; w -= 2) { + RGB_IN(r, g, b, p); + r1 = r; + g1 = g; + b1 = b; + lum[0] = RGB_TO_Y_CCIR(r, g, b); + + RGB_IN(r, g, b, p + BPP); + r1 += r; + g1 += g; + b1 += b; + lum[1] = RGB_TO_Y_CCIR(r, g, b); + c[0] = RGB_TO_U_CCIR(r1, g1, b1, 1); + c[1] = RGB_TO_V_CCIR(r1, g1, b1, 1); + c += 2; + p += 2 * BPP; + lum += 2; + } + /* handle odd width */ + if (w) { + RGB_IN(r, g, b, p); + lum[0] = RGB_TO_Y_CCIR(r, g, b); + c[0] = RGB_TO_U_CCIR(r, g, b, 0); + c[1] = RGB_TO_V_CCIR(r, g, b, 0); + } + } +} + +static void glue(RGB_NAME, _to_nv21)(AVPicture *dst, const AVPicture *src, + int width, int height) +{ + int wrap, wrap3; + int r, g, b, r1, g1, b1, w; + uint8_t *lum, *c; + const uint8_t *p; + + lum = dst->data[0]; + c = dst->data[1]; + + wrap = dst->linesize[0]; + wrap3 = src->linesize[0]; + p = src->data[0]; + for(;height>=2;height -= 2) { + for(w = width; w >= 2; w -= 2) { + RGB_IN(r, g, b, p); + r1 = r; + g1 = g; + b1 = b; + lum[0] = RGB_TO_Y_CCIR(r, g, b); + + RGB_IN(r, g, b, p + BPP); + r1 += r; + g1 += g; + b1 += b; + lum[1] = RGB_TO_Y_CCIR(r, g, b); + p += wrap3; + lum += wrap; + + RGB_IN(r, g, b, p); + r1 += r; + g1 += g; + b1 += b; + lum[0] = RGB_TO_Y_CCIR(r, g, b); + + RGB_IN(r, g, b, p + BPP); + r1 += r; + g1 += g; + b1 += b; + lum[1] = RGB_TO_Y_CCIR(r, g, b); + + c[1] = RGB_TO_U_CCIR(r1, g1, b1, 2); + c[0] = RGB_TO_V_CCIR(r1, g1, b1, 2); + + + c += 2; + p += -wrap3 + 2 * BPP; + lum += -wrap + 2; + } + /* handle odd width */ + if (w) { + RGB_IN(r, g, b, p); + r1 = r; + g1 = g; + b1 = b; + lum[0] = RGB_TO_Y_CCIR(r, g, b); + p += wrap3; + lum += wrap; + RGB_IN(r, g, b, p); + r1 += r; + g1 += g; + b1 += b; + lum[0] = RGB_TO_Y_CCIR(r, g, b); + c[1] = RGB_TO_U_CCIR(r1, g1, b1, 1); + c[0] = RGB_TO_V_CCIR(r1, g1, b1, 1); + c += 2; + p += -wrap3 + BPP; + lum += -wrap + 1; + } + p += wrap3 + (wrap3 - width * BPP); + lum += wrap + (wrap - width); + c += dst->linesize[1] - width; + } + /* handle odd height */ + if (height) { + for(w = width; w >= 2; w -= 2) { + RGB_IN(r, g, b, p); + r1 = r; + g1 = g; + b1 = b; + lum[0] = RGB_TO_Y_CCIR(r, g, b); + + RGB_IN(r, g, b, p + BPP); + r1 += r; + g1 += g; + b1 += b; + lum[1] = RGB_TO_Y_CCIR(r, g, b); + c[1] = RGB_TO_U_CCIR(r1, g1, b1, 1); + c[0] = RGB_TO_V_CCIR(r1, g1, b1, 1); + c += 2; + p += 2 * BPP; + lum += 2; + } + /* handle odd width */ + if (w) { + RGB_IN(r, g, b, p); + lum[0] = RGB_TO_Y_CCIR(r, g, b); + c[1] = RGB_TO_U_CCIR(r, g, b, 0); + c[0] = RGB_TO_V_CCIR(r, g, b, 0); + } + } +} + static void glue(RGB_NAME, _to_gray)(AVPicture *dst, const AVPicture *src, int width, int height) {