summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorChen Jie <chenj@lemote.com>2013-11-13 18:41:33 +0800
committerSebastian Dröge <sebastian@centricular.com>2014-05-26 16:29:01 +0200
commit8e0bbc9e32aa99da981eb7396f491d0f4aef91d6 (patch)
treef90b02c6ba4ea033ddf72183b7eeb06862154b8f /sys
parent557d6b974fe98d09ddd0a500548b8a13211dab1c (diff)
downloadgstreamer-plugins-bad-8e0bbc9e32aa99da981eb7396f491d0f4aef91d6.tar.gz
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.
Diffstat (limited to 'sys')
-rw-r--r--sys/androidmedia/gstamc.c410
-rw-r--r--sys/androidmedia/gstamc.h24
-rw-r--r--sys/androidmedia/gstamcvideodec.c341
-rw-r--r--sys/androidmedia/gstamcvideodec.h5
-rw-r--r--sys/androidmedia/gstamcvideoenc.c184
-rw-r--r--sys/androidmedia/gstamcvideoenc.h5
6 files changed, 492 insertions, 477 deletions
diff --git a/sys/androidmedia/gstamc.c b/sys/androidmedia/gstamc.c
index e6f3d5f2d..0c8153341 100644
--- a/sys/androidmedia/gstamc.c
+++ b/sys/androidmedia/gstamc.c
@@ -22,6 +22,12 @@
#include "config.h"
#endif
+#ifdef HAVE_ORC
+#include <orc/orc.h>
+#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 f10943174..aa0ff4648 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 721318048..08370abd1 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 3353dc68e..e5efcaee4 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 f96ca4844..c17383b1d 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;
-
- 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;
- };
+ 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;
+
+ 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 db8821d45..8373ce3d5 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__ */