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.
This commit is contained in:
Chen Jie 2013-11-13 18:41:33 +08:00 committed by Sebastian Dröge
parent 557d6b974f
commit 8e0bbc9e32
6 changed files with 491 additions and 476 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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__ */