mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-07-04 13:45:52 +00:00
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:
parent
557d6b974f
commit
8e0bbc9e32
|
@ -22,6 +22,12 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_ORC
|
||||||
|
#include <orc/orc.h>
|
||||||
|
#else
|
||||||
|
#define orc_memcpy memcpy
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "gstamc.h"
|
#include "gstamc.h"
|
||||||
#include "gstamc-constants.h"
|
#include "gstamc-constants.h"
|
||||||
|
|
||||||
|
@ -2260,6 +2266,410 @@ gst_amc_video_format_to_color_format (const GstAmcCodecInfo * codec_info,
|
||||||
return -1;
|
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
|
static const struct
|
||||||
{
|
{
|
||||||
gint id;
|
gint id;
|
||||||
|
|
|
@ -34,6 +34,7 @@ typedef struct _GstAmcCodec GstAmcCodec;
|
||||||
typedef struct _GstAmcBufferInfo GstAmcBufferInfo;
|
typedef struct _GstAmcBufferInfo GstAmcBufferInfo;
|
||||||
typedef struct _GstAmcFormat GstAmcFormat;
|
typedef struct _GstAmcFormat GstAmcFormat;
|
||||||
typedef struct _GstAmcBuffer GstAmcBuffer;
|
typedef struct _GstAmcBuffer GstAmcBuffer;
|
||||||
|
typedef struct _GstAmcColorFormatInfo GstAmcColorFormatInfo;
|
||||||
|
|
||||||
struct _GstAmcCodecType {
|
struct _GstAmcCodecType {
|
||||||
gchar *mime;
|
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);
|
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);
|
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);
|
const gchar * gst_amc_avc_profile_to_string (gint profile, const gchar **alternative);
|
||||||
gint gst_amc_avc_profile_from_string (const gchar *profile);
|
gint gst_amc_avc_profile_from_string (const gchar *profile);
|
||||||
const gchar * gst_amc_avc_level_to_string (gint level);
|
const gchar * gst_amc_avc_level_to_string (gint level);
|
||||||
|
|
|
@ -504,15 +504,22 @@ gst_amc_video_dec_set_src_caps (GstAmcVideoDec * self, GstAmcFormat * format)
|
||||||
gst_format, width, height, self->input_state);
|
gst_format, width, height, self->input_state);
|
||||||
|
|
||||||
self->format = gst_format;
|
self->format = gst_format;
|
||||||
self->color_format = color_format;
|
if (!gst_amc_color_format_info_set (&self->color_format_info,
|
||||||
self->height = height;
|
klass->codec_info, mime, color_format, width, height, stride,
|
||||||
self->width = width;
|
slice_height, crop_left, crop_right, crop_top, crop_bottom)) {
|
||||||
self->stride = stride;
|
GST_ERROR_OBJECT (self, "Failed to set up GstAmcColorFormatInfo");
|
||||||
self->slice_height = slice_height;
|
return FALSE;
|
||||||
self->crop_left = crop_left;
|
}
|
||||||
self->crop_right = crop_right;
|
|
||||||
self->crop_top = crop_top;
|
GST_DEBUG_OBJECT (self,
|
||||||
self->crop_bottom = crop_bottom;
|
"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_decoder_negotiate (GST_VIDEO_DECODER (self));
|
||||||
gst_video_codec_state_unref (output_state);
|
gst_video_codec_state_unref (output_state);
|
||||||
|
@ -521,39 +528,11 @@ gst_amc_video_dec_set_src_caps (GstAmcVideoDec * self, GstAmcFormat * format)
|
||||||
return TRUE;
|
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
|
static gboolean
|
||||||
gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, gint idx,
|
gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, gint idx,
|
||||||
const GstAmcBufferInfo * buffer_info, GstBuffer * outbuf)
|
const GstAmcBufferInfo * buffer_info, GstBuffer * outbuf)
|
||||||
{
|
{
|
||||||
GstAmcVideoDecClass *klass = GST_AMC_VIDEO_DEC_GET_CLASS (self);
|
GstAmcBuffer *buf;
|
||||||
GstAmcBuffer *buf = &self->output_buffers[idx];
|
|
||||||
GstVideoCodecState *state =
|
GstVideoCodecState *state =
|
||||||
gst_video_decoder_get_output_state (GST_VIDEO_DECODER (self));
|
gst_video_decoder_get_output_state (GST_VIDEO_DECODER (self));
|
||||||
GstVideoInfo *info = &state->info;
|
GstVideoInfo *info = &state->info;
|
||||||
|
@ -564,285 +543,11 @@ gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, gint idx,
|
||||||
idx, self->n_output_buffers);
|
idx, self->n_output_buffers);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
buf = &self->output_buffers[idx];
|
||||||
|
|
||||||
/* Same video format */
|
ret =
|
||||||
if (buffer_info->size == gst_buffer_get_size (outbuf)) {
|
gst_amc_color_format_copy (&self->color_format_info, buf, buffer_info,
|
||||||
GstMapInfo minfo;
|
info, outbuf, COLOR_FORMAT_COPY_OUT);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
gst_video_codec_state_unref (state);
|
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
|
/* Check if the caps change is a real format change or if only irrelevant
|
||||||
* parts of the caps have changed or nothing at all.
|
* parts of the caps have changed or nothing at all.
|
||||||
*/
|
*/
|
||||||
is_format_change |= self->width != state->info.width;
|
is_format_change |= self->color_format_info.width != state->info.width;
|
||||||
is_format_change |= self->height != state->info.height;
|
is_format_change |= self->color_format_info.height != state->info.height;
|
||||||
if (state->codec_data) {
|
if (state->codec_data) {
|
||||||
GstMapInfo cminfo;
|
GstMapInfo cminfo;
|
||||||
|
|
||||||
|
|
|
@ -59,10 +59,7 @@ struct _GstAmcVideoDec
|
||||||
|
|
||||||
/* Output format of the codec */
|
/* Output format of the codec */
|
||||||
GstVideoFormat format;
|
GstVideoFormat format;
|
||||||
gint color_format;
|
GstAmcColorFormatInfo color_format_info;
|
||||||
gint width, height, stride, slice_height;
|
|
||||||
gint crop_left, crop_right;
|
|
||||||
gint crop_top, crop_bottom;
|
|
||||||
|
|
||||||
guint8 *codec_data;
|
guint8 *codec_data;
|
||||||
gsize codec_data_size;
|
gsize codec_data_size;
|
||||||
|
|
|
@ -257,24 +257,22 @@ create_amc_format (GstAmcVideoEnc * encoder, GstVideoCodecState * input_state,
|
||||||
((gfloat) info->fps_n) / info->fps_d);
|
((gfloat) info->fps_n) / info->fps_d);
|
||||||
|
|
||||||
encoder->format = info->finfo->format;
|
encoder->format = info->finfo->format;
|
||||||
encoder->height = info->height;
|
if (!gst_amc_color_format_info_set (&encoder->color_format_info,
|
||||||
encoder->width = info->width;
|
klass->codec_info, mime, color_format, info->width, info->height,
|
||||||
encoder->stride = stride;
|
stride, slice_height, 0, 0, 0, 0))
|
||||||
encoder->slice_height = slice_height;
|
goto color_format_info_failed_to_set;
|
||||||
|
|
||||||
switch (encoder->format) {
|
GST_DEBUG_OBJECT (encoder,
|
||||||
case GST_VIDEO_FORMAT_I420:
|
"Color format info: {color_format=%d, width=%d, height=%d, "
|
||||||
encoder->buffer_size =
|
"stride=%d, slice-height=%d, crop-left=%d, crop-top=%d, "
|
||||||
stride * slice_height + 2 * ((stride / 2) * (slice_height + 1) / 2);
|
"crop-right=%d, crop-bottom=%d, frame-size=%d}",
|
||||||
break;
|
encoder->color_format_info.color_format, encoder->color_format_info.width,
|
||||||
case GST_VIDEO_FORMAT_NV12:
|
encoder->color_format_info.height, encoder->color_format_info.stride,
|
||||||
case GST_VIDEO_FORMAT_NV21:
|
encoder->color_format_info.slice_height,
|
||||||
encoder->buffer_size =
|
encoder->color_format_info.crop_left, encoder->color_format_info.crop_top,
|
||||||
stride * slice_height + (stride * ((slice_height + 1) / 2));
|
encoder->color_format_info.crop_right,
|
||||||
break;
|
encoder->color_format_info.crop_bottom,
|
||||||
default:
|
encoder->color_format_info.frame_size);
|
||||||
goto unsupported_video_format;
|
|
||||||
};
|
|
||||||
|
|
||||||
return format;
|
return format;
|
||||||
|
|
||||||
|
@ -283,9 +281,8 @@ video_format_failed_to_convert:
|
||||||
gst_amc_format_free (format);
|
gst_amc_format_free (format);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
unsupported_video_format:
|
color_format_info_failed_to_set:
|
||||||
GST_ERROR_OBJECT (encoder, "Unsupported GstVideoFormat '%d'",
|
GST_ERROR_OBJECT (encoder, "Failed to set up GstAmcColorFormatInfo");
|
||||||
encoder->format);
|
|
||||||
gst_amc_format_free (format);
|
gst_amc_format_free (format);
|
||||||
return NULL;
|
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?
|
/* The fill_buffer runs in the same thread as set_format?
|
||||||
* then we can use state->info safely */
|
* then we can use state->info safely */
|
||||||
GstVideoInfo *info = &input_state->info;
|
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;
|
return FALSE;
|
||||||
|
|
||||||
/* Same video format */
|
return gst_amc_color_format_copy (&self->color_format_info, outbuf,
|
||||||
if (gst_buffer_get_size (inbuf) == self->buffer_size) {
|
buffer_info, info, inbuf, COLOR_FORMAT_COPY_IN);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
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
|
/* Check if the caps change is a real format change or if only irrelevant
|
||||||
* parts of the caps have changed or nothing at all.
|
* parts of the caps have changed or nothing at all.
|
||||||
*/
|
*/
|
||||||
is_format_change |= self->width != state->info.width;
|
is_format_change |= self->color_format_info.width != state->info.width;
|
||||||
is_format_change |= self->height != state->info.height;
|
is_format_change |= self->color_format_info.height != state->info.height;
|
||||||
needs_disable = self->started;
|
needs_disable = self->started;
|
||||||
|
|
||||||
/* If the component is not started and a real format change happens
|
/* If the component is not started and a real format change happens
|
||||||
|
@ -1544,11 +1419,14 @@ again:
|
||||||
|
|
||||||
memset (&buffer_info, 0, sizeof (buffer_info));
|
memset (&buffer_info, 0, sizeof (buffer_info));
|
||||||
buffer_info.offset = 0;
|
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,
|
if (!gst_amc_video_enc_fill_buffer (self, frame->input_buffer, buf,
|
||||||
&buffer_info))
|
&buffer_info)) {
|
||||||
goto buffer_fill_error; /* no way to release @buf ? */
|
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) {
|
if (timestamp != GST_CLOCK_TIME_NONE) {
|
||||||
buffer_info.presentation_time_us =
|
buffer_info.presentation_time_us =
|
||||||
|
@ -1593,8 +1471,8 @@ invalid_buffer_index:
|
||||||
buffer_fill_error:
|
buffer_fill_error:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (self, RESOURCE, WRITE, (NULL),
|
GST_ELEMENT_ERROR (self, RESOURCE, WRITE, (NULL),
|
||||||
("Failed to write input into the OpenMAX buffer(write %dB to a %dB buffer)",
|
("Failed to write input into the amc buffer(write %dB to a %dB buffer)",
|
||||||
self->buffer_size, buf->size));
|
self->color_format_info.frame_size, buf->size));
|
||||||
gst_video_codec_frame_unref (frame);
|
gst_video_codec_frame_unref (frame);
|
||||||
return GST_FLOW_ERROR;
|
return GST_FLOW_ERROR;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "gstamc.h"
|
#include "gstamc.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
#define GST_TYPE_AMC_VIDEO_ENC \
|
#define GST_TYPE_AMC_VIDEO_ENC \
|
||||||
(gst_amc_video_enc_get_type())
|
(gst_amc_video_enc_get_type())
|
||||||
#define GST_AMC_VIDEO_ENC(obj) \
|
#define GST_AMC_VIDEO_ENC(obj) \
|
||||||
|
@ -60,8 +61,7 @@ struct _GstAmcVideoEnc
|
||||||
|
|
||||||
/* Input format of the codec */
|
/* Input format of the codec */
|
||||||
GstVideoFormat format;
|
GstVideoFormat format;
|
||||||
gint width, height, stride, slice_height;
|
GstAmcColorFormatInfo color_format_info;
|
||||||
gint buffer_size;
|
|
||||||
|
|
||||||
guint bitrate;
|
guint bitrate;
|
||||||
guint i_frame_int;
|
guint i_frame_int;
|
||||||
|
@ -95,4 +95,5 @@ struct _GstAmcVideoEncClass
|
||||||
GType gst_amc_video_enc_get_type (void);
|
GType gst_amc_video_enc_get_type (void);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __GST_AMC_VIDEO_ENC_H__ */
|
#endif /* __GST_AMC_VIDEO_ENC_H__ */
|
||||||
|
|
Loading…
Reference in a new issue