From 8e0bbc9e32aa99da981eb7396f491d0f4aef91d6 Mon Sep 17 00:00:00 2001 From: Chen Jie Date: Wed, 13 Nov 2013 18:41:33 +0800 Subject: [PATCH] androidmedia: add gst_amc_color_format_copy gst_amc_color_format_copy will copy in/out a frame resides at a GstAmcBuffer. Lots of codes in gst_amc_video_*_fill_buffer are moved to this new function. --- sys/androidmedia/gstamc.c | 410 ++++++++++++++++++++++++++++++ sys/androidmedia/gstamc.h | 24 ++ sys/androidmedia/gstamcvideodec.c | 341 ++----------------------- sys/androidmedia/gstamcvideodec.h | 5 +- sys/androidmedia/gstamcvideoenc.c | 182 +++---------- sys/androidmedia/gstamcvideoenc.h | 5 +- 6 files changed, 491 insertions(+), 476 deletions(-) diff --git a/sys/androidmedia/gstamc.c b/sys/androidmedia/gstamc.c index e6f3d5f2d9..0c81533417 100644 --- a/sys/androidmedia/gstamc.c +++ b/sys/androidmedia/gstamc.c @@ -22,6 +22,12 @@ #include "config.h" #endif +#ifdef HAVE_ORC +#include +#else +#define orc_memcpy memcpy +#endif + #include "gstamc.h" #include "gstamc-constants.h" @@ -2260,6 +2266,410 @@ gst_amc_video_format_to_color_format (const GstAmcCodecInfo * codec_info, return -1; } +/* + * The format is called QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka. + * Which is actually NV12 (interleaved U&V). + */ +#define TILE_WIDTH 64 +#define TILE_HEIGHT 32 +#define TILE_SIZE (TILE_WIDTH * TILE_HEIGHT) +#define TILE_GROUP_SIZE (4 * TILE_SIZE) + +/* get frame tile coordinate. XXX: nothing to be understood here, don't try. */ +static size_t +tile_pos (size_t x, size_t y, size_t w, size_t h) +{ + size_t flim = x + (y & ~1) * w; + + if (y & 1) { + flim += (x & ~3) + 2; + } else if ((h & 1) == 0 || y != (h - 1)) { + flim += (x + 2) & ~3; + } + + return flim; +} + +gboolean +gst_amc_color_format_info_set (GstAmcColorFormatInfo * color_format_info, + const GstAmcCodecInfo * codec_info, const gchar * mime, gint color_format, + gint width, gint height, gint stride, gint slice_height, gint crop_left, + gint crop_right, gint crop_top, gint crop_bottom) +{ + gint frame_size = 0; + + if (color_format == COLOR_FormatYCbYCr) { + if (strcmp (codec_info->name, "OMX.k3.video.decoder.avc") == 0) + color_format = COLOR_FormatYUV420SemiPlanar; + } + + /* Samsung Galaxy S3 seems to report wrong strides. + * I.e. BigBuckBunny 854x480 H264 reports a stride of 864 when it is + * actually 854, so we use width instead of stride here. + * This is obviously bound to break in the future. */ + if (g_str_has_prefix (codec_info->name, "OMX.SEC.")) { + stride = width; + } + + if (strcmp (codec_info->name, "OMX.k3.video.decoder.avc") == 0) { + stride = width; + slice_height = height; + } + + if (slice_height == 0) { + /* NVidia Tegra 3 on Nexus 7 does not set this */ + if (g_str_has_prefix (codec_info->name, "OMX.Nvidia.")) + slice_height = GST_ROUND_UP_32 (height); + } + + if (width == 0 || height == 0) { + GST_ERROR ("Width or height is 0"); + return FALSE; + } + + switch (color_format) { + case COLOR_FormatYUV420Planar:{ + if (stride == 0 || slice_height == 0) { + GST_ERROR ("Stride or slice height is 0"); + return FALSE; + } + + frame_size = + stride * slice_height + 2 * (((stride + 1) / 2) * (slice_height + + 1) / 2); + break; + } + case COLOR_TI_FormatYUV420PackedSemiPlanar: + case COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced:{ + if (stride == 0 || slice_height == 0) { + GST_ERROR ("Stride or slice height is 0"); + return FALSE; + } + + frame_size = + stride * (slice_height - crop_top / 2) + + (GST_ROUND_UP_2 (stride) * ((slice_height + 1) / 2)); + break; + } + case COLOR_QCOM_FormatYUV420SemiPlanar: + case COLOR_FormatYUV420SemiPlanar:{ + if (stride == 0 || slice_height == 0) { + GST_ERROR ("Stride or slice height is 0"); + return FALSE; + } + + frame_size = stride * slice_height + stride * ((slice_height + 1) / 2); + break; + } + case COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka:{ + const size_t tile_w = (width - 1) / TILE_WIDTH + 1; + const size_t tile_w_align = (tile_w + 1) & ~1; + const size_t tile_h_luma = (height - 1) / TILE_HEIGHT + 1; + frame_size = + tile_pos (tile_w, tile_h_luma, tile_w_align, tile_h_luma) * TILE_SIZE; + break; + } + default: + GST_ERROR ("Unsupported color format %d", color_format); + return FALSE; + break; + } + + color_format_info->color_format = color_format; + color_format_info->width = width; + color_format_info->height = height; + color_format_info->stride = stride; + color_format_info->slice_height = slice_height; + color_format_info->crop_left = crop_left; + color_format_info->crop_right = crop_right; + color_format_info->crop_top = crop_top; + color_format_info->crop_bottom = crop_bottom; + color_format_info->frame_size = frame_size; + + return TRUE; +} + +/* The weird handling of cropping, alignment and everything is taken from + * platform/frameworks/media/libstagefright/colorconversion/ColorConversion.cpp + */ +gboolean +gst_amc_color_format_copy (GstAmcColorFormatInfo * cinfo, + GstAmcBuffer * cbuffer, const GstAmcBufferInfo * cbuffer_info, + GstVideoInfo * vinfo, GstBuffer * vbuffer, + GstAmcColorFormatCopyDirection direction) +{ + gboolean ret = FALSE; + guint8 *cptr = NULL, *vptr = NULL; + guint8 **src, **dest; + + if (direction == COLOR_FORMAT_COPY_OUT) { + src = &cptr; + dest = &vptr; + } else { + src = &vptr; + dest = &cptr; + } + + /* Same video format */ + if (cbuffer_info->size == gst_buffer_get_size (vbuffer)) { + GstMapInfo minfo; + + GST_DEBUG ("Buffer sizes equal, doing fast copy"); + gst_buffer_map (vbuffer, &minfo, GST_MAP_WRITE); + + cptr = cbuffer->data + cbuffer_info->offset; + vptr = minfo.data; + orc_memcpy (*dest, *src, cbuffer_info->size); + + gst_buffer_unmap (vbuffer, &minfo); + ret = TRUE; + goto done; + } + + GST_DEBUG ("Sizes not equal (%d vs %d), doing slow line-by-line copying", + cbuffer_info->size, gst_buffer_get_size (vbuffer)); + + /* Different video format, try to convert */ + switch (cinfo->color_format) { + case COLOR_FormatYUV420Planar:{ + GstVideoFrame vframe; + gint i, j, height; + gint stride, slice_height; + gint c_stride, v_stride; + gint row_length; + + stride = cinfo->stride; + slice_height = cinfo->slice_height; + g_assert (stride > 0 && slice_height > 0); + + gst_video_frame_map (&vframe, vinfo, vbuffer, GST_MAP_WRITE); + + for (i = 0; i < 3; i++) { + if (i == 0) { + c_stride = stride; + v_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); + } else { + c_stride = (stride + 1) / 2; + v_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); + } + + cptr = cbuffer->data + cbuffer_info->offset; + + if (i == 0) { + cptr += cinfo->crop_top * stride; + cptr += cinfo->crop_left; + row_length = cinfo->width; + } else if (i > 0) { + /* skip the Y plane */ + cptr += slice_height * stride; + + /* crop_top/crop_left divided by two + * because one byte of the U/V planes + * corresponds to two pixels horizontally/vertically */ + cptr += cinfo->crop_top / 2 * c_stride; + cptr += cinfo->crop_left / 2; + row_length = (cinfo->width + 1) / 2; + } + if (i == 2) { + /* skip the U plane */ + cptr += ((slice_height + 1) / 2) * ((stride + 1) / 2); + } + + vptr = GST_VIDEO_FRAME_COMP_DATA (&vframe, i); + height = GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i); + + for (j = 0; j < height; j++) { + orc_memcpy (*dest, *src, row_length); + cptr += c_stride; + vptr += v_stride; + } + } + gst_video_frame_unmap (&vframe); + ret = TRUE; + break; + } + case COLOR_TI_FormatYUV420PackedSemiPlanar: + case COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced:{ + gint i, j, height; + gint c_stride, v_stride; + gint row_length; + GstVideoFrame vframe; + + /* This should always be set */ + g_assert (cinfo->stride > 0 && cinfo->slice_height > 0); + + /* FIXME: This does not work for odd widths or heights + * but might as well be a bug in the codec */ + gst_video_frame_map (&vframe, vinfo, vbuffer, GST_MAP_WRITE); + for (i = 0; i < 2; i++) { + if (i == 0) { + c_stride = cinfo->stride; + v_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); + } else { + c_stride = GST_ROUND_UP_2 (cinfo->stride); + v_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); + } + + cptr = cbuffer->data + cbuffer_info->offset; + if (i == 0) { + row_length = cinfo->width; + } else if (i == 1) { + cptr += (cinfo->slice_height - cinfo->crop_top / 2) * cinfo->stride; + row_length = GST_ROUND_UP_2 (cinfo->width); + } + + vptr = GST_VIDEO_FRAME_COMP_DATA (&vframe, i); + height = GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i); + + for (j = 0; j < height; j++) { + orc_memcpy (*dest, *src, row_length); + cptr += c_stride; + vptr += v_stride; + } + } + gst_video_frame_unmap (&vframe); + ret = TRUE; + break; + } + case COLOR_QCOM_FormatYUV420SemiPlanar: + case COLOR_FormatYUV420SemiPlanar:{ + gint i, j, height; + gint c_stride, v_stride; + gint row_length; + GstVideoFrame vframe; + + /* This should always be set */ + g_assert (cinfo->stride > 0 && cinfo->slice_height > 0); + + gst_video_frame_map (&vframe, vinfo, vbuffer, GST_MAP_WRITE); + + for (i = 0; i < 2; i++) { + c_stride = cinfo->stride; + v_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); + + cptr = cbuffer->data + cbuffer_info->offset; + if (i == 0) { + cptr += cinfo->crop_top * cinfo->stride; + cptr += cinfo->crop_left; + row_length = cinfo->width; + } else if (i == 1) { + cptr += cinfo->slice_height * cinfo->stride; + cptr += cinfo->crop_top * cinfo->stride; + cptr += cinfo->crop_left; + row_length = cinfo->width; + } + + vptr = GST_VIDEO_FRAME_COMP_DATA (&vframe, i); + height = GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i); + + for (j = 0; j < height; j++) { + orc_memcpy (*dest, *src, row_length); + cptr += c_stride; + vptr += v_stride; + } + } + gst_video_frame_unmap (&vframe); + ret = TRUE; + break; + } + /* FIXME: This should be in libgstvideo as MT12 or similar, see v4l2 */ + case COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka:{ + GstVideoFrame vframe; + gint width = cinfo->width; + gint height = cinfo->height; + gint v_luma_stride, v_chroma_stride; + guint8 *cdata = cbuffer->data + cbuffer_info->offset; + guint8 *v_luma, *v_chroma; + gint y; + const size_t tile_w = (width - 1) / TILE_WIDTH + 1; + const size_t tile_w_align = (tile_w + 1) & ~1; + const size_t tile_h_luma = (height - 1) / TILE_HEIGHT + 1; + const size_t tile_h_chroma = (height / 2 - 1) / TILE_HEIGHT + 1; + size_t luma_size = tile_w_align * tile_h_luma * TILE_SIZE; + + gst_video_frame_map (&vframe, vinfo, vbuffer, GST_MAP_WRITE); + v_luma = GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0); + v_chroma = GST_VIDEO_FRAME_PLANE_DATA (&vframe, 1); + v_luma_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, 0); + v_chroma_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, 1); + + if ((luma_size % TILE_GROUP_SIZE) != 0) + luma_size = (((luma_size - 1) / TILE_GROUP_SIZE) + 1) * TILE_GROUP_SIZE; + + for (y = 0; y < tile_h_luma; y++) { + size_t row_width = width; + gint x; + + for (x = 0; x < tile_w; x++) { + size_t tile_width = row_width; + size_t tile_height = height; + gint luma_idx; + gint chroma_idx; + /* luma source pointer for this tile */ + uint8_t *c_luma = + cdata + tile_pos (x, y, tile_w_align, tile_h_luma) * TILE_SIZE; + + /* chroma source pointer for this tile */ + uint8_t *c_chroma = + cdata + luma_size + tile_pos (x, y / 2, tile_w_align, + tile_h_chroma) * TILE_SIZE; + if (y & 1) + c_chroma += TILE_SIZE / 2; + + /* account for right columns */ + if (tile_width > TILE_WIDTH) + tile_width = TILE_WIDTH; + + /* account for bottom rows */ + if (tile_height > TILE_HEIGHT) + tile_height = TILE_HEIGHT; + + /* vptr luma memory index for this tile */ + luma_idx = y * TILE_HEIGHT * v_luma_stride + x * TILE_WIDTH; + + /* vptr chroma memory index for this tile */ + /* XXX: remove divisions */ + chroma_idx = y * TILE_HEIGHT / 2 * v_chroma_stride + x * TILE_WIDTH; + + tile_height /= 2; // we copy 2 luma lines at once + while (tile_height--) { + vptr = v_luma + luma_idx; + cptr = c_luma; + memcpy (*dest, *src, tile_width); + c_luma += TILE_WIDTH; + luma_idx += v_luma_stride; + + vptr = v_luma + luma_idx; + cptr = c_luma; + memcpy (*dest, *src, tile_width); + c_luma += TILE_WIDTH; + luma_idx += v_luma_stride; + + vptr = v_chroma + chroma_idx; + cptr = c_chroma; + memcpy (*dest, *src, tile_width); + c_chroma += TILE_WIDTH; + chroma_idx += v_chroma_stride; + } + row_width -= TILE_WIDTH; + } + height -= TILE_HEIGHT; + } + gst_video_frame_unmap (&vframe); + ret = TRUE; + break; + + } + default: + GST_ERROR ("Unsupported color format %d", cinfo->color_format); + goto done; + break; + } + +done: + return ret; +} + static const struct { gint id; diff --git a/sys/androidmedia/gstamc.h b/sys/androidmedia/gstamc.h index f109431745..aa0ff4648f 100644 --- a/sys/androidmedia/gstamc.h +++ b/sys/androidmedia/gstamc.h @@ -34,6 +34,7 @@ typedef struct _GstAmcCodec GstAmcCodec; typedef struct _GstAmcBufferInfo GstAmcBufferInfo; typedef struct _GstAmcFormat GstAmcFormat; typedef struct _GstAmcBuffer GstAmcBuffer; +typedef struct _GstAmcColorFormatInfo GstAmcColorFormatInfo; struct _GstAmcCodecType { gchar *mime; @@ -122,6 +123,29 @@ void gst_amc_format_set_buffer (GstAmcFormat *format, const gchar *key, guint8 * GstVideoFormat gst_amc_color_format_to_video_format (const GstAmcCodecInfo * codec_info, const gchar * mime, gint color_format); gint gst_amc_video_format_to_color_format (const GstAmcCodecInfo * codec_info, const gchar * mime, GstVideoFormat video_format); +struct _GstAmcColorFormatInfo { + gint color_format; + gint width, height, stride, slice_height; + gint crop_left, crop_right; + gint crop_top, crop_bottom; + gint frame_size; +}; + +gboolean gst_amc_color_format_info_set (GstAmcColorFormatInfo * color_format_info, + const GstAmcCodecInfo * codec_info, const gchar * mime, + gint color_format, gint width, gint height, gint stride, gint slice_height, + gint crop_left, gint crop_right, gint crop_top, gint crop_bottom); + +typedef enum +{ + COLOR_FORMAT_COPY_OUT, + COLOR_FORMAT_COPY_IN +} GstAmcColorFormatCopyDirection; + +gboolean gst_amc_color_format_copy ( + GstAmcColorFormatInfo * cinfo, GstAmcBuffer * cbuffer, const GstAmcBufferInfo * cbuffer_info, + GstVideoInfo * vinfo, GstBuffer * vbuffer, GstAmcColorFormatCopyDirection direction); + const gchar * gst_amc_avc_profile_to_string (gint profile, const gchar **alternative); gint gst_amc_avc_profile_from_string (const gchar *profile); const gchar * gst_amc_avc_level_to_string (gint level); diff --git a/sys/androidmedia/gstamcvideodec.c b/sys/androidmedia/gstamcvideodec.c index 721318048b..08370abd11 100644 --- a/sys/androidmedia/gstamcvideodec.c +++ b/sys/androidmedia/gstamcvideodec.c @@ -504,15 +504,22 @@ gst_amc_video_dec_set_src_caps (GstAmcVideoDec * self, GstAmcFormat * format) gst_format, width, height, self->input_state); self->format = gst_format; - self->color_format = color_format; - self->height = height; - self->width = width; - self->stride = stride; - self->slice_height = slice_height; - self->crop_left = crop_left; - self->crop_right = crop_right; - self->crop_top = crop_top; - self->crop_bottom = crop_bottom; + if (!gst_amc_color_format_info_set (&self->color_format_info, + klass->codec_info, mime, color_format, width, height, stride, + slice_height, crop_left, crop_right, crop_top, crop_bottom)) { + GST_ERROR_OBJECT (self, "Failed to set up GstAmcColorFormatInfo"); + return FALSE; + } + + GST_DEBUG_OBJECT (self, + "Color format info: {color_format=%d, width=%d, height=%d, " + "stride=%d, slice-height=%d, crop-left=%d, crop-top=%d, " + "crop-right=%d, crop-bottom=%d, frame-size=%d}", + self->color_format_info.color_format, self->color_format_info.width, + self->color_format_info.height, self->color_format_info.stride, + self->color_format_info.slice_height, self->color_format_info.crop_left, + self->color_format_info.crop_top, self->color_format_info.crop_right, + self->color_format_info.crop_bottom, self->color_format_info.frame_size); gst_video_decoder_negotiate (GST_VIDEO_DECODER (self)); gst_video_codec_state_unref (output_state); @@ -521,39 +528,11 @@ gst_amc_video_dec_set_src_caps (GstAmcVideoDec * self, GstAmcFormat * format) return TRUE; } -/* - * The format is called QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka. - * Which is actually NV12 (interleaved U&V). - */ -#define TILE_WIDTH 64 -#define TILE_HEIGHT 32 -#define TILE_SIZE (TILE_WIDTH * TILE_HEIGHT) -#define TILE_GROUP_SIZE (4 * TILE_SIZE) - -/* get frame tile coordinate. XXX: nothing to be understood here, don't try. */ -static size_t -tile_pos (size_t x, size_t y, size_t w, size_t h) -{ - size_t flim = x + (y & ~1) * w; - - if (y & 1) { - flim += (x & ~3) + 2; - } else if ((h & 1) == 0 || y != (h - 1)) { - flim += (x + 2) & ~3; - } - - return flim; -} - -/* The weird handling of cropping, alignment and everything is taken from - * platform/frameworks/media/libstagefright/colorconversion/ColorConversion.cpp - */ static gboolean gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, gint idx, const GstAmcBufferInfo * buffer_info, GstBuffer * outbuf) { - GstAmcVideoDecClass *klass = GST_AMC_VIDEO_DEC_GET_CLASS (self); - GstAmcBuffer *buf = &self->output_buffers[idx]; + GstAmcBuffer *buf; GstVideoCodecState *state = gst_video_decoder_get_output_state (GST_VIDEO_DECODER (self)); GstVideoInfo *info = &state->info; @@ -564,285 +543,11 @@ gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, gint idx, idx, self->n_output_buffers); goto done; } + buf = &self->output_buffers[idx]; - /* Same video format */ - if (buffer_info->size == gst_buffer_get_size (outbuf)) { - GstMapInfo minfo; - - GST_DEBUG_OBJECT (self, "Buffer sizes equal, doing fast copy"); - gst_buffer_map (outbuf, &minfo, GST_MAP_WRITE); - orc_memcpy (minfo.data, buf->data + buffer_info->offset, buffer_info->size); - gst_buffer_unmap (outbuf, &minfo); - ret = TRUE; - goto done; - } - - GST_DEBUG_OBJECT (self, - "Sizes not equal (%d vs %d), doing slow line-by-line copying", - buffer_info->size, gst_buffer_get_size (outbuf)); - - /* Different video format, try to convert */ - switch (self->color_format) { - case COLOR_FormatYUV420Planar:{ - GstVideoFrame vframe; - gint i, j, height; - guint8 *src, *dest; - gint stride, slice_height; - gint src_stride, dest_stride; - gint row_length; - - stride = self->stride; - if (stride == 0) { - GST_ERROR_OBJECT (self, "Stride not set"); - goto done; - } - - slice_height = self->slice_height; - if (slice_height == 0) { - /* NVidia Tegra 3 on Nexus 7 does not set this */ - if (g_str_has_prefix (klass->codec_info->name, "OMX.Nvidia.")) { - slice_height = GST_ROUND_UP_32 (self->height); - } else { - GST_ERROR_OBJECT (self, "Slice height not set"); - goto done; - } - } - - gst_video_frame_map (&vframe, info, outbuf, GST_MAP_WRITE); - for (i = 0; i < 3; i++) { - if (i == 0) { - src_stride = stride; - dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); - } else { - src_stride = (stride + 1) / 2; - dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); - } - - src = buf->data + buffer_info->offset; - - if (i == 0) { - src += self->crop_top * stride; - src += self->crop_left; - row_length = self->width; - } else if (i > 0) { - /* skip the Y plane */ - src += slice_height * stride; - - /* crop_top/crop_left divided by two - * because one byte of the U/V planes - * corresponds to two pixels horizontally/vertically */ - src += self->crop_top / 2 * src_stride; - src += self->crop_left / 2; - row_length = (self->width + 1) / 2; - } - if (i == 2) { - /* skip the U plane */ - src += ((slice_height + 1) / 2) * ((stride + 1) / 2); - } - - dest = GST_VIDEO_FRAME_COMP_DATA (&vframe, i); - height = GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i); - - for (j = 0; j < height; j++) { - orc_memcpy (dest, src, row_length); - src += src_stride; - dest += dest_stride; - } - } - gst_video_frame_unmap (&vframe); - ret = TRUE; - break; - } - case COLOR_TI_FormatYUV420PackedSemiPlanar: - case COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced:{ - gint i, j, height; - guint8 *src, *dest; - gint src_stride, dest_stride; - gint row_length; - GstVideoFrame vframe; - - /* This should always be set */ - if (self->stride == 0 || self->slice_height == 0) { - GST_ERROR_OBJECT (self, "Stride or slice height not set"); - goto done; - } - - /* FIXME: This does not work for odd widths or heights - * but might as well be a bug in the codec */ - gst_video_frame_map (&vframe, info, outbuf, GST_MAP_WRITE); - for (i = 0; i < 2; i++) { - if (i == 0) { - src_stride = self->stride; - dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); - } else { - src_stride = GST_ROUND_UP_2 (self->stride); - dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); - } - - src = buf->data + buffer_info->offset; - if (i == 0) { - row_length = self->width; - } else if (i == 1) { - src += (self->slice_height - self->crop_top / 2) * self->stride; - row_length = GST_ROUND_UP_2 (self->width); - } - - dest = GST_VIDEO_FRAME_COMP_DATA (&vframe, i); - height = GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i); - - for (j = 0; j < height; j++) { - orc_memcpy (dest, src, row_length); - src += src_stride; - dest += dest_stride; - } - } - gst_video_frame_unmap (&vframe); - ret = TRUE; - break; - } - case COLOR_QCOM_FormatYUV420SemiPlanar: - case COLOR_FormatYUV420SemiPlanar:{ - gint i, j, height; - guint8 *src, *dest; - gint src_stride, dest_stride, fixed_stride; - gint row_length; - GstVideoFrame vframe; - - /* This should always be set */ - if (self->stride == 0 || self->slice_height == 0) { - GST_ERROR_OBJECT (self, "Stride or slice height not set"); - goto done; - } - - /* Samsung Galaxy S3 seems to report wrong strides. - I.e. BigBuckBunny 854x480 H264 reports a stride of 864 when it is - actually 854, so we use width instead of stride here. - This is obviously bound to break in the future. */ - if (g_str_has_prefix (klass->codec_info->name, "OMX.SEC.")) { - fixed_stride = self->width; - } else { - fixed_stride = self->stride; - } - - gst_video_frame_map (&vframe, info, outbuf, GST_MAP_WRITE); - - for (i = 0; i < 2; i++) { - src_stride = fixed_stride; - dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); - - src = buf->data + buffer_info->offset; - if (i == 0) { - src += self->crop_top * fixed_stride; - src += self->crop_left; - row_length = self->width; - } else if (i == 1) { - src += self->slice_height * fixed_stride; - src += self->crop_top * fixed_stride; - src += self->crop_left; - row_length = self->width; - } - - dest = GST_VIDEO_FRAME_COMP_DATA (&vframe, i); - height = GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i); - - for (j = 0; j < height; j++) { - orc_memcpy (dest, src, row_length); - src += src_stride; - dest += dest_stride; - } - } - gst_video_frame_unmap (&vframe); - ret = TRUE; - break; - } - /* FIXME: This should be in libgstvideo as MT12 or similar, see v4l2 */ - case COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka:{ - GstVideoFrame vframe; - gint width = self->width; - gint height = self->height; - gint dest_luma_stride, dest_chroma_stride; - guint8 *src = buf->data + buffer_info->offset; - guint8 *dest_luma, *dest_chroma; - gint y; - const size_t tile_w = (width - 1) / TILE_WIDTH + 1; - const size_t tile_w_align = (tile_w + 1) & ~1; - const size_t tile_h_luma = (height - 1) / TILE_HEIGHT + 1; - const size_t tile_h_chroma = (height / 2 - 1) / TILE_HEIGHT + 1; - size_t luma_size = tile_w_align * tile_h_luma * TILE_SIZE; - - gst_video_frame_map (&vframe, info, outbuf, GST_MAP_WRITE); - dest_luma = GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0); - dest_chroma = GST_VIDEO_FRAME_PLANE_DATA (&vframe, 1); - dest_luma_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, 0); - dest_chroma_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, 1); - - if ((luma_size % TILE_GROUP_SIZE) != 0) - luma_size = (((luma_size - 1) / TILE_GROUP_SIZE) + 1) * TILE_GROUP_SIZE; - - for (y = 0; y < tile_h_luma; y++) { - size_t row_width = width; - gint x; - - for (x = 0; x < tile_w; x++) { - size_t tile_width = row_width; - size_t tile_height = height; - gint luma_idx; - gint chroma_idx; - /* luma source pointer for this tile */ - const uint8_t *src_luma = src - + tile_pos (x, y, tile_w_align, tile_h_luma) * TILE_SIZE; - - /* chroma source pointer for this tile */ - const uint8_t *src_chroma = src + luma_size - + tile_pos (x, y / 2, tile_w_align, tile_h_chroma) * TILE_SIZE; - if (y & 1) - src_chroma += TILE_SIZE / 2; - - /* account for right columns */ - if (tile_width > TILE_WIDTH) - tile_width = TILE_WIDTH; - - /* account for bottom rows */ - if (tile_height > TILE_HEIGHT) - tile_height = TILE_HEIGHT; - - /* dest luma memory index for this tile */ - luma_idx = y * TILE_HEIGHT * dest_luma_stride + x * TILE_WIDTH; - - /* dest chroma memory index for this tile */ - /* XXX: remove divisions */ - chroma_idx = - y * TILE_HEIGHT / 2 * dest_chroma_stride + x * TILE_WIDTH; - - tile_height /= 2; // we copy 2 luma lines at once - while (tile_height--) { - memcpy (dest_luma + luma_idx, src_luma, tile_width); - src_luma += TILE_WIDTH; - luma_idx += dest_luma_stride; - - memcpy (dest_luma + luma_idx, src_luma, tile_width); - src_luma += TILE_WIDTH; - luma_idx += dest_luma_stride; - - memcpy (dest_chroma + chroma_idx, src_chroma, tile_width); - src_chroma += TILE_WIDTH; - chroma_idx += dest_chroma_stride; - } - row_width -= TILE_WIDTH; - } - height -= TILE_HEIGHT; - } - gst_video_frame_unmap (&vframe); - ret = TRUE; - break; - - } - default: - GST_ERROR_OBJECT (self, "Unsupported color format %d", - self->color_format); - goto done; - break; - } + ret = + gst_amc_color_format_copy (&self->color_format_info, buf, buffer_info, + info, outbuf, COLOR_FORMAT_COPY_OUT); done: gst_video_codec_state_unref (state); @@ -1191,8 +896,8 @@ gst_amc_video_dec_set_format (GstVideoDecoder * decoder, /* Check if the caps change is a real format change or if only irrelevant * parts of the caps have changed or nothing at all. */ - is_format_change |= self->width != state->info.width; - is_format_change |= self->height != state->info.height; + is_format_change |= self->color_format_info.width != state->info.width; + is_format_change |= self->color_format_info.height != state->info.height; if (state->codec_data) { GstMapInfo cminfo; diff --git a/sys/androidmedia/gstamcvideodec.h b/sys/androidmedia/gstamcvideodec.h index 3353dc68ea..e5efcaee4d 100644 --- a/sys/androidmedia/gstamcvideodec.h +++ b/sys/androidmedia/gstamcvideodec.h @@ -59,10 +59,7 @@ struct _GstAmcVideoDec /* Output format of the codec */ GstVideoFormat format; - gint color_format; - gint width, height, stride, slice_height; - gint crop_left, crop_right; - gint crop_top, crop_bottom; + GstAmcColorFormatInfo color_format_info; guint8 *codec_data; gsize codec_data_size; diff --git a/sys/androidmedia/gstamcvideoenc.c b/sys/androidmedia/gstamcvideoenc.c index f96ca4844b..c17383b1d4 100644 --- a/sys/androidmedia/gstamcvideoenc.c +++ b/sys/androidmedia/gstamcvideoenc.c @@ -257,24 +257,22 @@ create_amc_format (GstAmcVideoEnc * encoder, GstVideoCodecState * input_state, ((gfloat) info->fps_n) / info->fps_d); encoder->format = info->finfo->format; - encoder->height = info->height; - encoder->width = info->width; - encoder->stride = stride; - encoder->slice_height = slice_height; + if (!gst_amc_color_format_info_set (&encoder->color_format_info, + klass->codec_info, mime, color_format, info->width, info->height, + stride, slice_height, 0, 0, 0, 0)) + goto color_format_info_failed_to_set; - switch (encoder->format) { - case GST_VIDEO_FORMAT_I420: - encoder->buffer_size = - stride * slice_height + 2 * ((stride / 2) * (slice_height + 1) / 2); - break; - case GST_VIDEO_FORMAT_NV12: - case GST_VIDEO_FORMAT_NV21: - encoder->buffer_size = - stride * slice_height + (stride * ((slice_height + 1) / 2)); - break; - default: - goto unsupported_video_format; - }; + GST_DEBUG_OBJECT (encoder, + "Color format info: {color_format=%d, width=%d, height=%d, " + "stride=%d, slice-height=%d, crop-left=%d, crop-top=%d, " + "crop-right=%d, crop-bottom=%d, frame-size=%d}", + encoder->color_format_info.color_format, encoder->color_format_info.width, + encoder->color_format_info.height, encoder->color_format_info.stride, + encoder->color_format_info.slice_height, + encoder->color_format_info.crop_left, encoder->color_format_info.crop_top, + encoder->color_format_info.crop_right, + encoder->color_format_info.crop_bottom, + encoder->color_format_info.frame_size); return format; @@ -283,9 +281,8 @@ video_format_failed_to_convert: gst_amc_format_free (format); return NULL; -unsupported_video_format: - GST_ERROR_OBJECT (encoder, "Unsupported GstVideoFormat '%d'", - encoder->format); +color_format_info_failed_to_set: + GST_ERROR_OBJECT (encoder, "Failed to set up GstAmcColorFormatInfo"); gst_amc_format_free (format); return NULL; @@ -787,134 +784,12 @@ gst_amc_video_enc_fill_buffer (GstAmcVideoEnc * self, GstBuffer * inbuf, /* The fill_buffer runs in the same thread as set_format? * then we can use state->info safely */ GstVideoInfo *info = &input_state->info; - gpointer dest_data; - gboolean ret = FALSE; - if (buffer_info->size < self->buffer_size) + if (buffer_info->size < self->color_format_info.frame_size) return FALSE; - /* Same video format */ - if (gst_buffer_get_size (inbuf) == self->buffer_size) { - GST_DEBUG_OBJECT (self, "Buffer sizes equal, doing fast copy"); - gst_buffer_extract (inbuf, 0, outbuf->data + buffer_info->offset, - self->buffer_size); - - ret = TRUE; - - goto done; - } - - GST_DEBUG_OBJECT (self, - "Sizes not equal (%d vs %d), doing slow line-by-line copying", - gst_buffer_get_size (inbuf), self->buffer_size); - - dest_data = outbuf->data + buffer_info->offset; - - /* Different video format, try to convert */ - switch (self->format) { - case GST_VIDEO_FORMAT_I420:{ - gint i, j, height; - guint8 *src, *dest; - gint slice_height; - gint src_stride, dest_stride; - gint row_length; - GstVideoFrame vframe; - - slice_height = self->slice_height; - - gst_video_frame_map (&vframe, info, inbuf, GST_MAP_READ); - for (i = 0; i < 3; i++) { - if (i == 0) { - dest_stride = self->stride; - src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); - /* XXX: Try this if no stride was set */ - if (dest_stride == 0) - dest_stride = src_stride; - } else { - dest_stride = (self->stride + 1) / 2; - src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); - /* XXX: Try this if no stride was set */ - if (dest_stride == 0) - dest_stride = src_stride; - } - - dest = dest_data; - - if (i == 0) { - row_length = self->width; - } else if (i > 0) { - dest += slice_height * self->stride; - row_length = (self->width + 1) / 2; - } - if (i == 2) - dest += ((slice_height + 1) / 2) * ((self->stride + 1) / 2); - - src = GST_VIDEO_FRAME_COMP_DATA (&vframe, i); - height = GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i); - - for (j = 0; j < height; j++) { - orc_memcpy (dest, src, row_length); - src += src_stride; - dest += dest_stride; - } - } - gst_video_frame_unmap (&vframe); - ret = TRUE; - break; - } - case GST_VIDEO_FORMAT_NV21: - case GST_VIDEO_FORMAT_NV12:{ - gint i, j, height; - guint8 *src, *dest; - gint src_stride, dest_stride; - gint row_length; - GstVideoFrame vframe; - - gst_video_frame_map (&vframe, info, inbuf, GST_MAP_READ); - for (i = 0; i < 2; i++) { - if (i == 0) { - dest_stride = self->stride; - src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); - /* XXX: Try this if no stride was set */ - if (dest_stride == 0) - dest_stride = src_stride; - } else { - dest_stride = GST_ROUND_UP_2 (self->stride); - src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); - /* XXX: Try this if no stride was set */ - if (dest_stride == 0) - dest_stride = src_stride; - } - - dest = dest_data; - if (i == 0) { - row_length = self->width; - } else if (i == 1) { - dest += self->slice_height * self->stride; - row_length = GST_ROUND_UP_2 (self->width); - } - - src = GST_VIDEO_FRAME_COMP_DATA (&vframe, i); - height = GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i); - - for (j = 0; j < height; j++) { - orc_memcpy (dest, src, row_length); - src += src_stride; - dest += dest_stride; - } - } - gst_video_frame_unmap (&vframe); - ret = TRUE; - break; - } - default: - GST_ERROR_OBJECT (self, "Unsupported video format %d", self->format); - goto done; - break; - } - -done: - return ret; + return gst_amc_color_format_copy (&self->color_format_info, outbuf, + buffer_info, info, inbuf, COLOR_FORMAT_COPY_IN); } static GstFlowReturn @@ -1317,8 +1192,8 @@ gst_amc_video_enc_set_format (GstVideoEncoder * encoder, /* Check if the caps change is a real format change or if only irrelevant * parts of the caps have changed or nothing at all. */ - is_format_change |= self->width != state->info.width; - is_format_change |= self->height != state->info.height; + is_format_change |= self->color_format_info.width != state->info.width; + is_format_change |= self->color_format_info.height != state->info.height; needs_disable = self->started; /* If the component is not started and a real format change happens @@ -1544,11 +1419,14 @@ again: memset (&buffer_info, 0, sizeof (buffer_info)); buffer_info.offset = 0; - buffer_info.size = MIN (self->buffer_size, buf->size); + buffer_info.size = MIN (self->color_format_info.frame_size, buf->size); if (!gst_amc_video_enc_fill_buffer (self, frame->input_buffer, buf, - &buffer_info)) - goto buffer_fill_error; /* no way to release @buf ? */ + &buffer_info)) { + memset (&buffer_info, 0, sizeof (buffer_info)); + gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info); + goto buffer_fill_error; + } if (timestamp != GST_CLOCK_TIME_NONE) { buffer_info.presentation_time_us = @@ -1593,8 +1471,8 @@ invalid_buffer_index: buffer_fill_error: { GST_ELEMENT_ERROR (self, RESOURCE, WRITE, (NULL), - ("Failed to write input into the OpenMAX buffer(write %dB to a %dB buffer)", - self->buffer_size, buf->size)); + ("Failed to write input into the amc buffer(write %dB to a %dB buffer)", + self->color_format_info.frame_size, buf->size)); gst_video_codec_frame_unref (frame); return GST_FLOW_ERROR; } diff --git a/sys/androidmedia/gstamcvideoenc.h b/sys/androidmedia/gstamcvideoenc.h index db8821d451..8373ce3d52 100644 --- a/sys/androidmedia/gstamcvideoenc.h +++ b/sys/androidmedia/gstamcvideoenc.h @@ -31,6 +31,7 @@ #include "gstamc.h" G_BEGIN_DECLS + #define GST_TYPE_AMC_VIDEO_ENC \ (gst_amc_video_enc_get_type()) #define GST_AMC_VIDEO_ENC(obj) \ @@ -60,8 +61,7 @@ struct _GstAmcVideoEnc /* Input format of the codec */ GstVideoFormat format; - gint width, height, stride, slice_height; - gint buffer_size; + GstAmcColorFormatInfo color_format_info; guint bitrate; guint i_frame_int; @@ -95,4 +95,5 @@ struct _GstAmcVideoEncClass GType gst_amc_video_enc_get_type (void); G_END_DECLS + #endif /* __GST_AMC_VIDEO_ENC_H__ */