diff options
author | don.darling <don.darling@24075187-2e39-4e88-bbb8-bc8aa768f540> | 2010-11-16 20:47:21 +0000 |
---|---|---|
committer | don.darling <don.darling@24075187-2e39-4e88-bbb8-bc8aa768f540> | 2010-11-16 20:47:21 +0000 |
commit | 5f81c118dd4b80cb05f2402bc25fb3977ccd5300 (patch) | |
tree | 56b410b857699a828ce2c3f68865fadedf768f0b | |
parent | 4f733b9abf04da6dc5c6cc5ec49835107873955f (diff) |
Add the TIPrepEncBuf element
This element prepares input buffers for use by the TIVidenc1 encoder.
Typically it would be placed in the pipeline just before TIVidenc1 and perform
a hardware-accelerated copy or color-conversion into a physically contiguous
buffer, which is required by the codecs in TIVidenc1.
The hardware accelerated copies can be done in parallel with the encode by
placing a "queue" element between TIPrepEncBuf and TIVidenc1.
Targets that support zero-copy capture+encode (currently only DM365) do not
need this element when v4l2src is uses with always-copy=FALSE.
Example usage on DM6467 to capture, color convert, and encode to H.264:
gst-launch v4l2src num-buffers=600 always-copy=FALSE ! 'video/x-raw-yuv, format=(fourcc)NV16, framerate=(fraction)30/1, width=(int)1280, height=(int)720' ! TIPrepEncBuf contiguousInputFrame=TRUE ! 'video/x-raw-yuv, format=(fourcc)NV12, framerate=(fraction)30/1, width=(int)1280, height=(int)720' ! queue ! TIVidenc1 engineName="codecServer" codecName="h264enc" bitRate=3000000 ! filesink location="./sample.264"
Example usage on DM6446 to capture, copy, and encode to H.264:
gst-launch v4l2src always-copy=FALSE input-src=s-video num-buffers=600 ! 'video/x-raw-yuv, format=(fourcc)UYVY, framerate=(fraction)30000/1001, width=(int)720, height=(int)480' ! TIPrepEncBuf contiguousInputFrame=TRUE ! queue ! TIVidenc1 engineName="encode" codecName="h264enc" bitRate=1000000 ! queue max-size-buffers=2 max-size-time=0 max-size-bytes=0 ! filesink location="./sample.264"
Example usage on DM355 to capture, copy, and encode to MPEG-4:
gst-launch v4l2src input-src=s-video always-copy=FALSE num-buffers=600 ! TIPrepEncBuf contiguousInputFrame=TRUE ! queue ! TIVidenc1 codecName=mpeg4enc engineName=codecServer encodingPreset=2 bitRate=3000000 ! filesink location=sample.m4v
git-svn-id: https://gstreamer.ti.com/svn/gstreamer_ti/trunk@873 24075187-2e39-4e88-bbb8-bc8aa768f540
4 files changed, 897 insertions, 2 deletions
diff --git a/gstreamer_ti/ti_build/ticodecplugin/src/Makefile.am b/gstreamer_ti/ti_build/ticodecplugin/src/Makefile.am index 02e6d0a..e55ceb2 100644 --- a/gstreamer_ti/ti_build/ticodecplugin/src/Makefile.am +++ b/gstreamer_ti/ti_build/ticodecplugin/src/Makefile.am @@ -12,7 +12,7 @@ endif # sources used to compile this plug-in -libgstticodecplugin_la_SOURCES = gstticodecplugin.c gsttiauddec1.c gsttividdec2.c gsttiimgenc1.c gsttiimgdec1.c gsttidmaibuffertransport.c gsttidmaibuftab.c gstticircbuffer.c gsttidmaivideosink.c gstticodecs.c gstticodecs_platform.c gsttiquicktime_aac.c gsttiquicktime_h264.c gsttividenc1.c gsttiaudenc1.c gstticommonutils.c gsttividresize.c gsttidmaiperf.c gsttiquicktime_mpeg4.c $(C6ACCEL_SRC) +libgstticodecplugin_la_SOURCES = gstticodecplugin.c gsttiauddec1.c gsttividdec2.c gsttiimgenc1.c gsttiimgdec1.c gsttidmaibuffertransport.c gsttidmaibuftab.c gstticircbuffer.c gsttidmaivideosink.c gstticodecs.c gstticodecs_platform.c gsttiquicktime_aac.c gsttiquicktime_h264.c gsttividenc1.c gsttiaudenc1.c gstticommonutils.c gsttividresize.c gsttiprepencbuf.c gsttidmaiperf.c gsttiquicktime_mpeg4.c $(C6ACCEL_SRC) # flags used to compile this plugin # add other _CFLAGS and _LIBS as needed @@ -21,7 +21,7 @@ libgstticodecplugin_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE libgstticodecplugin_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -Wl,$(XDC_CONFIG_BASENAME)/linker.cmd -Wl,$(C6ACCEL_LIB) # headers we need but don't want installed -noinst_HEADERS = gsttiauddec1.h gsttividdec2.h gsttiimgenc1.h gsttiimgdec1.h gsttidmaibuffertransport.h gsttidmaibuftab.h gstticircbuffer.h gsttidmaivideosink.h gsttithreadprops.h gstticodecs.h gsttiquicktime_aac.h gsttiquicktime_h264.h gsttividenc1.h gsttiaudenc1.h gstticommonutils.h gsttividresize.h gsttiquicktime_mpeg4.h $(C6ACCEL_HEAD) +noinst_HEADERS = gsttiauddec1.h gsttividdec2.h gsttiimgenc1.h gsttiimgdec1.h gsttidmaibuffertransport.h gsttidmaibuftab.h gstticircbuffer.h gsttidmaivideosink.h gsttithreadprops.h gstticodecs.h gsttiquicktime_aac.h gsttiquicktime_h264.h gsttividenc1.h gsttiaudenc1.h gstticommonutils.h gsttividresize.h gsttiprepencbuf.h gsttiquicktime_mpeg4.h $(C6ACCEL_HEAD) # XDC Configuration CONFIGURO = $(XDC_INSTALL_DIR)/xs xdc.tools.configuro diff --git a/gstreamer_ti/ti_build/ticodecplugin/src/gstticodecplugin.c b/gstreamer_ti/ti_build/ticodecplugin/src/gstticodecplugin.c index 8772fc1..8c21fc6 100644 --- a/gstreamer_ti/ti_build/ticodecplugin/src/gstticodecplugin.c +++ b/gstreamer_ti/ti_build/ticodecplugin/src/gstticodecplugin.c @@ -41,6 +41,7 @@ #include "gsttividenc1.h" #include "gsttiaudenc1.h" #include "gsttividresize.h" +#include "gsttiprepencbuf.h" #include "gsttidmaiperf.h" #ifdef HAVE_C6ACCEL @@ -118,6 +119,13 @@ TICodecPlugin_init (GstPlugin * TICodecPlugin) GST_TYPE_TIVIDRESIZE)) return FALSE; + env_value = getenv("GST_TI_TIPrepEncBuf_DISABLE"); + + if ((!env_value || strcmp(env_value,"1")) && !gst_element_register( + TICodecPlugin, "TIPrepEncBuf", GST_RANK_PRIMARY, + GST_TYPE_TIPREPENCBUF)) + return FALSE; + env_value = getenv("GST_TI_TIDmaiPerf_DISABLE"); if ((!env_value || strcmp(env_value,"1")) && !gst_element_register( diff --git a/gstreamer_ti/ti_build/ticodecplugin/src/gsttiprepencbuf.c b/gstreamer_ti/ti_build/ticodecplugin/src/gsttiprepencbuf.c new file mode 100644 index 0000000..20a223b --- /dev/null +++ b/gstreamer_ti/ti_build/ticodecplugin/src/gsttiprepencbuf.c @@ -0,0 +1,781 @@ +/* + * gsttiprepencbuf.c + * + * This file defines the "TIPrepEncBuf" element, which prepares a GstBuffer + * for use with the encoders used by the TIVidenc1 element. Typically this + * means copying the buffer into a physically contiguous buffer, and performing + * a color conversion on platforms like DM6467. Hardware acceleration is used + * for a copy. + * + * Platforms where TIVidenc1 supports zero-copy encode (such as DM365) should + * not use this element when performing capture+encode. In these cases, the + * encoder can process buffers directly from MMAP capture buffers. + * + * Original Author: + * Don Darling, Texas Instruments, Inc. + * + * Example usage: + * gst-launch v4l2src ! TIPrepEncBuf ! queue ! TIVidenc1 ! ... + * + * Note: Buffers of type TIDMAIBUFFERTRANSPORT are pushed to the source pad. + * Downstream elements can detect this and obtain the DMAI buffers for use + * with hardware-accelerated operations. + * + * Copyright (C) 2008-2010 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation version 2.1 of the License. + * + * This program is distributed #as is# WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gst/gst.h> +#include <gst/video/video.h> + +#include <ti/sdo/dmai/BufferGfx.h> + +#include "gsttiprepencbuf.h" +#include "gsttidmaibuffertransport.h" +#include "gstticommonutils.h" + +/* Declare variable used to categorize GST_LOG output */ +GST_DEBUG_CATEGORY_STATIC (gst_tiprepencbuf_debug); +#define GST_CAT_DEFAULT gst_tiprepencbuf_debug + +/* Element properties */ +enum { + PROP_0, + PROP_CONTIG_INPUT_FRAME, /* contiguousInputFrame (boolean) */ + PROP_NUM_OUTPUT_BUFS, /* numOutputBufs (gint) */ +}; + +/* Define property default */ +#define DEFAULT_NUM_OUTPUT_BUFS 2 +#define DEFAULT_CONTIGUOUS_INPUT_FRAME FALSE +#define gst_tiprepencbuf_invalid_device Cpu_Device_COUNT + +/* Define static caps for the sink and src pads */ +static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE( + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS + ( GST_VIDEO_CAPS_YUV("UYVY")";" + GST_VIDEO_CAPS_YUV("NV16")";" + GST_VIDEO_CAPS_YUV("Y8C8")";" + GST_VIDEO_CAPS_YUV("NV12") + ) +); + +static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE( + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS + ( GST_VIDEO_CAPS_YUV("UYVY")";" + GST_VIDEO_CAPS_YUV("NV16")";" + GST_VIDEO_CAPS_YUV("Y8C8")";" + GST_VIDEO_CAPS_YUV("NV12") + ) +); + +/* Declare a global pointer to our element base class */ +static GstElementClass *parent_class = NULL; + +/* Static Function Declarations */ +static void + gst_tiprepencbuf_init(GstTIPrepEncBuf *object); +static void + gst_tiprepencbuf_base_init(gpointer gclass); +static void + gst_tiprepencbuf_class_init(GstTIPrepEncBufClass *g_class); +static GstFlowReturn + gst_tiprepencbuf_prepare_output_buffer (GstBaseTransform *trans, + GstBuffer *inBuf, gint size, GstCaps *caps, GstBuffer **outBuf); +static void + gst_tiprepencbuf_set_property(GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec); +static gboolean + gst_tiprepencbuf_transform_size (GstBaseTransform *trans, + GstPadDirection direction, GstCaps *caps, guint size, GstCaps *othercaps, + guint *othersize); +static Buffer_Handle + gst_tiprepencbuf_convert_gst_to_dmai(GstTIPrepEncBuf *prepencbuf, + GstBuffer *buf, gboolean reference); +static Int + gst_tiprepencbuf_422psemi_420psemi(Buffer_Handle hDstBuf, GstBuffer *src, + GstTIPrepEncBuf *prepencbuf); +static Int + gst_tiprepencbuf_copy_input(GstTIPrepEncBuf *prepencbuf, + Buffer_Handle hDstBuf, GstBuffer *src); +static GstFlowReturn + gst_tiprepencbuf_transform (GstBaseTransform *trans, GstBuffer *inBuf, + GstBuffer *outBuf); +static GstCaps* + gst_tiprepencbuf_transform_caps (GstBaseTransform *trans, + GstPadDirection direction, GstCaps *caps); +static gboolean + gst_tiprepencbuf_parse_caps (GstCaps *cap, gint *width, gint *height, + guint32 *fourcc); +static ColorSpace_Type + gst_tiprepencbuf_get_colorSpace (guint32 fourcc); +static gboolean + gst_tiprepencbuf_set_caps (GstBaseTransform *trans, GstCaps *in, + GstCaps *out); +static gboolean + gst_tiprepencbuf_exit(GstTIPrepEncBuf *prepencbuf); + +/****************************************************************************** + * gst_tiprepencbuf_get_type + * Boiler-plate function auto-generated by "make_element" script. + * Defines function pointers for initialization routines for this element. + ******************************************************************************/ +GType gst_tiprepencbuf_get_type(void) +{ + static GType object_type = 0; + + if (G_UNLIKELY(object_type == 0)) { + static const GTypeInfo object_info = { + sizeof(GstTIPrepEncBufClass), + gst_tiprepencbuf_base_init, + NULL, + (GClassInitFunc) gst_tiprepencbuf_class_init, + NULL, + NULL, + sizeof(GstTIPrepEncBuf), + 0, + (GInstanceInitFunc) gst_tiprepencbuf_init + }; + + object_type = g_type_register_static(GST_TYPE_BASE_TRANSFORM, + "GstTIPrepEncBuf", &object_info, (GTypeFlags) 0); + + /* Initialize GST_LOG for this object */ + GST_DEBUG_CATEGORY_INIT(gst_tiprepencbuf_debug, "TIPrepEncBuf", + 0, "Prepare GstBuffer for Encoding"); + + GST_LOG("initialized get_type\n"); + } + + return object_type; +} + +/****************************************************************************** + * gst_tiprepencbuf_init + *****************************************************************************/ +static void gst_tiprepencbuf_init(GstTIPrepEncBuf * prepencbuf) +{ + gst_base_transform_set_qos_enabled(GST_BASE_TRANSFORM(prepencbuf), TRUE); + + prepencbuf->contiguousInputFrame = DEFAULT_CONTIGUOUS_INPUT_FRAME; + prepencbuf->numOutputBufs = DEFAULT_NUM_OUTPUT_BUFS; + prepencbuf->hFc = NULL; + + /* Determine target board type */ + if (Cpu_getDevice(NULL, &prepencbuf->device) < 0) { + GST_ELEMENT_ERROR(prepencbuf, RESOURCE, FAILED, + ("Failed to determine target board\n"), (NULL)); + prepencbuf->device = gst_tiprepencbuf_invalid_device; + } + +} + +/****************************************************************************** + * gst_tiprepencbuf_base_init + * Boiler-plate function auto-generated by "make_element" script. + * Initializes element base class. + ******************************************************************************/ +static void gst_tiprepencbuf_base_init(gpointer gclass) +{ + static GstElementDetails element_details = { + "TI Physically Contiguous Buffer", + "Filter/Copy", + "Copy buffer into physically contigous buffer", + "Don Darling; Texas Instruments, Inc." + }; + + GstElementClass *element_class = GST_ELEMENT_CLASS(gclass); + + gst_element_class_add_pad_template(element_class, + gst_static_pad_template_get(&src_factory)); + gst_element_class_add_pad_template(element_class, + gst_static_pad_template_get(&sink_factory)); + gst_element_class_set_details(element_class, &element_details); +} + +/****************************************************************************** + * gst_tiprepencbuf_class_init + * Boiler-plate function auto-generated by "make_element" script. + * Initializes the TIPrepEncBuf class. + ******************************************************************************/ +static void gst_tiprepencbuf_class_init(GstTIPrepEncBufClass * klass) +{ + GObjectClass *gobject_class; + GstBaseTransformClass *trans_class; + + parent_class = g_type_class_peek_parent(klass); + gobject_class = (GObjectClass *) klass; + trans_class = (GstBaseTransformClass *) klass; + + gobject_class->set_property = gst_tiprepencbuf_set_property; + gobject_class->finalize = (GObjectFinalizeFunc) gst_tiprepencbuf_exit; + + trans_class->passthrough_on_same_caps = FALSE; + + trans_class->set_caps = + GST_DEBUG_FUNCPTR(gst_tiprepencbuf_set_caps); + trans_class->transform_caps = + GST_DEBUG_FUNCPTR(gst_tiprepencbuf_transform_caps); + trans_class->transform_size = + GST_DEBUG_FUNCPTR(gst_tiprepencbuf_transform_size); + trans_class->transform = + GST_DEBUG_FUNCPTR(gst_tiprepencbuf_transform); + trans_class->prepare_output_buffer = + GST_DEBUG_FUNCPTR(gst_tiprepencbuf_prepare_output_buffer); + + g_object_class_install_property(gobject_class, PROP_CONTIG_INPUT_FRAME, + g_param_spec_boolean("contiguousInputFrame", "Contiguous input buffer", + "Set this if element recieves contiguous input frame from" + " upstream.", DEFAULT_CONTIGUOUS_INPUT_FRAME, G_PARAM_WRITABLE)); + + g_object_class_install_property(gobject_class, PROP_NUM_OUTPUT_BUFS, + g_param_spec_int("numOutputBufs", "Number of Output buffers", + "Number of output buffers to allocate", 1, G_MAXINT32, + DEFAULT_NUM_OUTPUT_BUFS, G_PARAM_WRITABLE)); + + GST_LOG("initialized class init\n"); +} + +/***************************************************************************** + * gst_tiprepencbuf_prepare_output_buffer + * Function is used to allocate output buffer + *****************************************************************************/ +static GstFlowReturn +gst_tiprepencbuf_prepare_output_buffer(GstBaseTransform * trans, + GstBuffer * inBuf, gint size, GstCaps * caps, GstBuffer ** outBuf) +{ + GstTIPrepEncBuf *prepencbuf = GST_TIPREPENCBUF(trans); + Buffer_Handle hOutBuf; + + GST_LOG("begin prepare output buffer\n"); + + /* Get free buffer from buftab */ + if (!(hOutBuf = gst_tidmaibuftab_get_buf(prepencbuf->hOutBufTab))) { + GST_ELEMENT_ERROR(prepencbuf, RESOURCE, READ, + ("failed to get free buffer\n"), (NULL)); + return GST_FLOW_ERROR; + } + + /* Create a DMAI transport buffer object to carry a DMAI buffer to + * the source pad. The transport buffer knows how to release the + * buffer for re-use in this element when the source pad calls + * gst_buffer_unref(). + */ + GST_LOG("creating dmai transport buffer\n"); + *outBuf = gst_tidmaibuffertransport_new(hOutBuf, prepencbuf->hOutBufTab); + gst_buffer_set_data(*outBuf, (guint8 *) Buffer_getUserPtr(hOutBuf), + Buffer_getSize(hOutBuf)); + gst_buffer_set_caps(*outBuf, GST_PAD_CAPS(trans->srcpad)); + + GST_LOG("end prepare output buffer\n"); + + return GST_FLOW_OK; +} + +/****************************************************************************** + * gst_tividenc_set_property + * Set element properties when requested. + ******************************************************************************/ +static void +gst_tiprepencbuf_set_property(GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstTIPrepEncBuf *prepencbuf = GST_TIPREPENCBUF(object); + + GST_LOG("begin set_property\n"); + + switch (prop_id) { + case PROP_CONTIG_INPUT_FRAME: + prepencbuf->contiguousInputFrame = g_value_get_boolean(value); + GST_LOG("setting \"contiguousInputFrame\" to \"%s\"\n", + prepencbuf->contiguousInputFrame ? "TRUE" : "FALSE"); + break; + case PROP_NUM_OUTPUT_BUFS: + prepencbuf->numOutputBufs = g_value_get_int(value); + GST_LOG("setting \"numOutputBufs\" to \"%d\"\n", + prepencbuf->numOutputBufs); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } + + GST_LOG("end set_property\n"); +} + +/****************************************************************************** + * gst_tiprepencbuf_transform_size + * The output buffer will always be the same size as the input buffer + *****************************************************************************/ +static gboolean +gst_tiprepencbuf_transform_size(GstBaseTransform * trans, + GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps, + guint * othersize) +{ + GstTIPrepEncBuf *prepencbuf = GST_TIPREPENCBUF(trans); + + switch (direction) { + case GST_PAD_SINK: + *othersize = gst_ti_calc_buffer_size(prepencbuf->dstWidth, + prepencbuf->dstHeight, 0, prepencbuf->dstColorSpace); + break; + case GST_PAD_SRC: + *othersize = gst_ti_calc_buffer_size(prepencbuf->srcWidth, + prepencbuf->srcHeight, 0, prepencbuf->srcColorSpace); + break; + case GST_PAD_UNKNOWN: + return FALSE; + } + + return TRUE; +} + +/****************************************************************************** + * gst_tiprepencbuf_convert_gst_to_dmai + * This function convert gstreamer buffer into DMAI graphics buffer. + *****************************************************************************/ +static Buffer_Handle +gst_tiprepencbuf_convert_gst_to_dmai(GstTIPrepEncBuf * prepencbuf, + GstBuffer * buf, gboolean reference) +{ + BufferGfx_Attrs gfxAttrs = BufferGfx_Attrs_DEFAULT; + Buffer_Handle hBuf = NULL; + + gfxAttrs.bAttrs.reference = reference; + gfxAttrs.dim.width = prepencbuf->srcWidth; + gfxAttrs.dim.height = prepencbuf->srcHeight; + gfxAttrs.colorSpace = prepencbuf->srcColorSpace; + gfxAttrs.dim.lineLength = BufferGfx_calcLineLength(gfxAttrs.dim.width, + prepencbuf->srcColorSpace); + + hBuf = Buffer_create(GST_BUFFER_SIZE(buf), + BufferGfx_getBufferAttrs(&gfxAttrs)); + + if (hBuf == NULL) { + GST_ERROR("failed to create buffer\n"); + return NULL; + } + Buffer_setUserPtr(hBuf, (Int8 *) GST_BUFFER_DATA(buf)); + Buffer_setNumBytesUsed(hBuf, GST_BUFFER_SIZE(buf)); + return hBuf; +} + +/****************************************************************************** + * gst_tiprepencbuf_422psemi_420psemi + * this function color convert YUV422PSEMI to YUV420PSEMI. + *****************************************************************************/ +static Int +gst_tiprepencbuf_422psemi_420psemi(Buffer_Handle hDstBuf, GstBuffer * src, + GstTIPrepEncBuf * prepencbuf) +{ + Ccv_Attrs ccvAttrs = Ccv_Attrs_DEFAULT; + gboolean accel = FALSE; + Buffer_Handle hInBuf = NULL; + Int ret = -1; + + GST_LOG("gst_tiprepencbuf_422psemi_420psemi - begin\n"); + + /* create ccv handle */ + if (prepencbuf->hCcv == NULL) { + /* Enable the accel ccv based on contiguousInputFrame. + * If accel is set to FALSE then DMAI will use software ccv function + * else will use HW accelerated ccv engine. + */ + + /* If we are getting dmai transport buffer then enable HW + * acceleration */ + if (GST_IS_TIDMAIBUFFERTRANSPORT(src)) { + accel = TRUE; + } + else { + accel = prepencbuf->contiguousInputFrame; + } + + ccvAttrs.accel = prepencbuf->contiguousInputFrame; + prepencbuf->hCcv = Ccv_create(&ccvAttrs); + if (prepencbuf->hCcv == NULL) { + GST_ERROR("failed to create CCV handle\n"); + goto exit; + } + + GST_INFO("HW accel CCV: %s\n", accel ? "enabled" : "disabled"); + } + + /* Prepare input buffer */ + hInBuf = gst_tiprepencbuf_convert_gst_to_dmai(prepencbuf, src, TRUE); + if (hInBuf == NULL) { + GST_ERROR("failed to get dmai buffer\n"); + goto exit; + } + + /* Prepare output buffer */ + if (Ccv_config(prepencbuf->hCcv, hInBuf, hDstBuf) < 0) { + GST_ERROR("failed to config CCV handle\n"); + goto exit; + } + + if (Ccv_execute(prepencbuf->hCcv, hInBuf, hDstBuf) < 0) { + GST_ERROR("failed to execute Ccv handle\n"); + goto exit; + } + + ret = GST_BUFFER_SIZE(src); + + GST_LOG("gst_tiprepencbuf_422psemi_420psemi - end\n"); + +exit: + if (hInBuf) { + Buffer_delete(hInBuf); + } + + return ret; +} + +/***************************************************************************** + * gst_tiprepencbuf_copy_input + * Make the input data in src available in the physically contiguous memory + * in dst in the best way possible. Preferably an accelerated copy or + * color conversion. + ****************************************************************************/ +static Int +gst_tiprepencbuf_copy_input(GstTIPrepEncBuf * prepencbuf, + Buffer_Handle hDstBuf, GstBuffer * src) +{ + Framecopy_Attrs fcAttrs = Framecopy_Attrs_DEFAULT; + gboolean accel = FALSE; + Buffer_Handle hInBuf = NULL; + Int ret = -1; + +#if defined(Platform_dm365) + BufferGfx_Dimensions dim; +#endif + + /* Check to see if we need to execute ccv on dm6467 */ + if (prepencbuf->device == Cpu_Device_DM6467 && + prepencbuf->srcColorSpace == ColorSpace_YUV422PSEMI) { + return gst_tiprepencbuf_422psemi_420psemi(hDstBuf, src, prepencbuf); + } + + GST_LOG("gst_tiphyscontig_copy_input - begin\n"); + + if (prepencbuf->hFc == NULL) { + /* Enable the accel framecopy based on contiguousInputFrame. + * If accel is set to FALSE then DMAI will use regular memcpy function + * else will use HW accelerated framecopy. + */ + + /* If we are getting dmai transport buffer then enable HW + * acceleration */ + if (GST_IS_TIDMAIBUFFERTRANSPORT(src)) { + accel = TRUE; + } + else { + accel = prepencbuf->contiguousInputFrame; + } + + fcAttrs.accel = prepencbuf->contiguousInputFrame; + + prepencbuf->hFc = Framecopy_create(&fcAttrs); + if (prepencbuf->hFc == NULL) { + GST_ERROR("failed to create framecopy handle\n"); + goto exit; + } + + GST_INFO("HW accel framecopy: %s\n", accel ? "enabled" : "disabled"); + } + + /* Prepare input buffer */ + hInBuf = gst_tiprepencbuf_convert_gst_to_dmai(prepencbuf, src, TRUE); + if (hInBuf == NULL) { + GST_ERROR("failed to get dmai buffer\n"); + goto exit; + } + +#if defined(Platform_dm365) + /* Handle resizer 32-byte issue on DM365 platform */ + if (prepencbuf->device == Cpu_Device_DM365) { + if ((prepencbuf->srcColorSpace == ColorSpace_YUV420PSEMI)) { + BufferGfx_getDimensions(hInBuf, &dim); + dim.lineLength = Dmai_roundUp(dim.lineLength, 32); + BufferGfx_setDimensions(hInBuf, &dim); + } + } +#endif + + /* Prepare output buffer */ + if (Framecopy_config(prepencbuf->hFc, hInBuf, hDstBuf) < 0) { + GST_ERROR("failed to configure framecopy\n"); + goto exit; + } + + if (Framecopy_execute(prepencbuf->hFc, hInBuf, hDstBuf) < 0) { + GST_ERROR("failed to execute framecopy\n"); + goto exit; + } + + ret = GST_BUFFER_SIZE(src); + +exit: + if (hInBuf) { + Buffer_delete(hInBuf); + } + + GST_LOG("gst_tiprepencbuf_copy_input - end\n"); + return ret; +} + +/****************************************************************************** + * gst_tiprepencbuf_transform + * Transforms one incoming buffer to one outgoing buffer. + *****************************************************************************/ +static GstFlowReturn +gst_tiprepencbuf_transform(GstBaseTransform * trans, GstBuffer * src, + GstBuffer * dst) +{ + GstTIPrepEncBuf *prepencbuf = GST_TIPREPENCBUF(trans); + + /* If the input buffer is a physically contiguous DMAI buffer, it can + * be passed directly to the codec. + */ + if (GST_IS_TIDMAIBUFFERTRANSPORT(src)) { + gst_buffer_unref(dst); + dst = gst_buffer_ref(src); + return GST_FLOW_OK; + } + + /* Otherwise, copy the buffer contents into our local physically contiguous + * DMAI buffer. The gst_tiprepencbuf_copy_input function will copy + * using hardware acceleration if possible. + */ + if (!(gst_tiprepencbuf_copy_input(prepencbuf, + GST_TIDMAIBUFFERTRANSPORT_DMAIBUF(dst), src))) { + return GST_FLOW_ERROR; + } + return GST_FLOW_OK; +} + +/****************************************************************************** + * gst_tiprepencbuf_transform_caps + * Most platforms require that the exact same caps are used on both ends. + * DM6467 can also convert from Y8C8/NV16 to NV12. + *****************************************************************************/ +static GstCaps* +gst_tiprepencbuf_transform_caps(GstBaseTransform * trans, + GstPadDirection direction, GstCaps * caps) +{ + GstTIPrepEncBuf *prepencbuf = GST_TIPREPENCBUF(trans); + GstCaps *supported_caps; + GstStructure *caps_struct; + + g_return_val_if_fail(GST_IS_CAPS(caps), NULL); + + /* We always support the same caps on both sides */ + supported_caps = gst_caps_copy(caps); + + /* On DM6467, we also support conversion from Y8C8/NV16 to NV12 */ + if (prepencbuf->device == Cpu_Device_DM6467) { + switch (direction) { + case GST_PAD_SINK: + caps_struct = + gst_structure_copy(gst_caps_get_structure(caps, 0)); + gst_structure_set(caps_struct, "format", GST_TYPE_FOURCC, + GST_MAKE_FOURCC('N', 'V', '1', '2'), (gchar *) NULL); + gst_caps_append_structure(supported_caps, caps_struct); + break; + case GST_PAD_SRC: + caps_struct = + gst_structure_copy(gst_caps_get_structure(caps, 0)); + gst_structure_set(caps_struct, "format", GST_TYPE_FOURCC, + GST_MAKE_FOURCC('N', 'V', '1', '6'), (gchar *) NULL); + gst_caps_append_structure(supported_caps, caps_struct); + break; + case GST_PAD_UNKNOWN: + break; + } + } + + return supported_caps; +} + +/****************************************************************************** + * gst_tiprepencbuf_parse_caps + *****************************************************************************/ +static gboolean +gst_tiprepencbuf_parse_caps(GstCaps * cap, gint * width, gint * height, + guint32 * format) +{ + GstStructure *structure = gst_caps_get_structure(cap, 0); + + GST_LOG("begin parse caps\n"); + + if (!gst_structure_get_int(structure, "width", width)) { + GST_ERROR("Failed to get width \n"); + return FALSE; + } + + if (!gst_structure_get_int(structure, "height", height)) { + GST_ERROR("Failed to get height \n"); + return FALSE; + } + + if (!gst_structure_get_fourcc(structure, "format", format)) { + GST_ERROR("failed to get fourcc from cap\n"); + return FALSE; + } + + GST_LOG("end parse caps\n"); + + return TRUE; +} + +/***************************************************************************** + * gst_tiprepencbuf_get_colorSpace + ****************************************************************************/ +ColorSpace_Type gst_tiprepencbuf_get_colorSpace(guint32 fourcc) +{ + switch (fourcc) { + case GST_MAKE_FOURCC('U', 'Y', 'V', 'Y'): + return ColorSpace_UYVY; + case GST_MAKE_FOURCC('N', 'V', '1', '6'): + case GST_MAKE_FOURCC('Y', '8', 'C', '8'): + return ColorSpace_YUV422PSEMI; + case GST_MAKE_FOURCC('N', 'V', '1', '2'): + return ColorSpace_YUV420PSEMI; + default: + GST_ERROR("failed to get colorspace\n"); + return ColorSpace_NOTSET; + } +} + +/****************************************************************************** + * gst_tiprepencbuf_set_caps + *****************************************************************************/ +static gboolean +gst_tiprepencbuf_set_caps(GstBaseTransform * trans, GstCaps * in, + GstCaps * out) +{ + GstTIPrepEncBuf *prepencbuf = GST_TIPREPENCBUF(trans); + BufferGfx_Attrs gfxAttrs = BufferGfx_Attrs_DEFAULT; + gboolean ret = FALSE; + guint32 fourcc; + guint outBufSize; + + GST_LOG("begin set caps\n"); + + /* parse input cap */ + if (!gst_tiprepencbuf_parse_caps(in, &prepencbuf->srcWidth, + &prepencbuf->srcHeight, &fourcc)) { + GST_ELEMENT_ERROR(prepencbuf, RESOURCE, FAILED, + ("failed to get input resolution\n"), (NULL)); + goto exit; + } + + GST_LOG("input fourcc %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS(fourcc)); + + /* map fourcc with its corresponding dmai colorspace type */ + prepencbuf->srcColorSpace = gst_tiprepencbuf_get_colorSpace(fourcc); + + /* parse output cap */ + if (!gst_tiprepencbuf_parse_caps(out, &prepencbuf->dstWidth, + &prepencbuf->dstHeight, &fourcc)) { + GST_ELEMENT_ERROR(prepencbuf, RESOURCE, FAILED, + ("failed to get output resolution\n"), (NULL)); + goto exit; + } + + GST_LOG("output fourcc %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS(fourcc)); + + /* map fourcc with its corresponding dmai colorspace type */ + prepencbuf->dstColorSpace = gst_tiprepencbuf_get_colorSpace(fourcc); + + /* calculate output buffer size */ + outBufSize = gst_ti_calc_buffer_size(prepencbuf->dstWidth, + prepencbuf->dstHeight, 0, prepencbuf->dstColorSpace); + + /* allocate output buffer */ + gfxAttrs.bAttrs.useMask = gst_tidmaibuffer_GST_FREE; + gfxAttrs.colorSpace = prepencbuf->dstColorSpace; + gfxAttrs.dim.width = prepencbuf->dstWidth; + gfxAttrs.dim.height = prepencbuf->dstHeight; + gfxAttrs.dim.lineLength = + BufferGfx_calcLineLength(gfxAttrs.dim.width, gfxAttrs.colorSpace); + + if (prepencbuf->numOutputBufs == 0) { + prepencbuf->numOutputBufs = 2; + } + + prepencbuf->hOutBufTab = gst_tidmaibuftab_new(prepencbuf->numOutputBufs, + outBufSize, BufferGfx_getBufferAttrs (&gfxAttrs)); + + if (prepencbuf->hOutBufTab == NULL) { + GST_ELEMENT_ERROR(prepencbuf, RESOURCE, NO_SPACE_LEFT, + ("failed to create output bufTab\n"), (NULL)); + goto exit; + } + + ret = TRUE; + +exit: + GST_LOG("end set caps\n"); + return ret; +} + +/****************************************************************************** + * gst_tiprepencbuf_exit + * Shut down any running framecopy, and reset the element state. + ******************************************************************************/ +static gboolean gst_tiprepencbuf_exit(GstTIPrepEncBuf * prepencbuf) +{ + GST_LOG("begin exit_video\n"); + + /* Shut down remaining items */ + if (prepencbuf->hCcv) { + GST_LOG("deleting Ccv instance\n"); + Ccv_delete(prepencbuf->hCcv); + prepencbuf->hCcv = NULL; + } + + if (prepencbuf->hFc) { + GST_LOG("deleting framecopy instance\n"); + Framecopy_delete(prepencbuf->hFc); + prepencbuf->hFc = NULL; + } + + if (prepencbuf->hOutBufTab) { + GST_LOG("freeing output buffers\n"); + gst_tidmaibuftab_unref(prepencbuf->hOutBufTab); + prepencbuf->hOutBufTab = NULL; + } + + GST_LOG("end exit_video\n"); + return TRUE; +} + +/****************************************************************************** + * Custom ViM Settings for editing this file + ******************************************************************************/ +#if 0 + Tabs (use 4 spaces for indentation) + vim:set tabstop=4: /* Use 4 spaces for tabs */ + vim:set shiftwidth=4: /* Use 4 spaces for >> operations */ + vim:set expandtab: /* Expand tabs into white spaces */ +#endif diff --git a/gstreamer_ti/ti_build/ticodecplugin/src/gsttiprepencbuf.h b/gstreamer_ti/ti_build/ticodecplugin/src/gsttiprepencbuf.h new file mode 100644 index 0000000..5757866 --- /dev/null +++ b/gstreamer_ti/ti_build/ticodecplugin/src/gsttiprepencbuf.h @@ -0,0 +1,106 @@ +/* + * gsttiprepencbuf.h + * + * This file declares the "TIPrepEncBuf" element, which prepares a GstBuffer + * for use with the encoders used by the TIVidenc1 element. Typically this + * means copying the buffer into a physically contiguous buffer, and performing + * a color conversion on platforms like DM6467. Hardware acceleration is used + * for a copy. + * + * Platforms where TIVidenc1 supports zero-copy encode (such as DM365) should + * not use this element when performing capture+encode. In these cases, the + * encoder can process buffers directly from MMAP capture buffers. + * + * Original Author: + * Don Darling, Texas Instruments, Inc. + * + * Copyright (C) 2008-2010 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation version 2.1 of the License. + * + * This program is distributed #as is# WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ + +#ifndef __GST_TIPREPENCBUF_H__ +#define __GST_TIPREPENCBUF_H__ + +#include <gst/gst.h> +#include <gst/base/gstbasetransform.h> + +#include <ti/sdo/dmai/Framecopy.h> +#include <ti/sdo/dmai/Ccv.h> +#include <ti/sdo/dmai/Cpu.h> + +#include "gsttidmaibuftab.h" + +G_BEGIN_DECLS + +/* Standard macros for maniuplating TIPrepEncBuf objects */ +#define GST_TYPE_TIPREPENCBUF \ + (gst_tiprepencbuf_get_type()) +#define GST_TIPREPENCBUF(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TIPREPENCBUF,GstTIPrepEncBuf)) +#define GST_TIPREPENCBUF_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TIPREPENCBUF,GstTIPrepEncBufClass)) +#define GST_IS_TIPREPENCBUF(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TIPREPENCBUF)) +#define GST_IS_TIPREPENCBUF_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TIPREPENCBUF)) + +typedef struct _GstTIPrepEncBuf GstTIPrepEncBuf; +typedef struct _GstTIPrepEncBufClass GstTIPrepEncBufClass; + +/* _GstTIPrepEncBuf object */ +struct _GstTIPrepEncBuf +{ + /* gStreamer infrastructure */ + GstBaseTransform element; + GstPad *sinkpad; + GstPad *srcpad; + + /* Element property */ + gboolean contiguousInputFrame; + gint numOutputBufs; + + /* Element state */ + gint srcWidth; + gint srcHeight; + ColorSpace_Type srcColorSpace; + gint dstWidth; + gint dstHeight; + ColorSpace_Type dstColorSpace; + Framecopy_Handle hFc; + Ccv_Handle hCcv; + GstTIDmaiBufTab *hOutBufTab; + Cpu_Device device; +}; + +/* _GstTIPrepEncBufClass object */ +struct _GstTIPrepEncBufClass +{ + GstBaseTransformClass parent_class; +}; + +/* External function enclarations */ +GType gst_tiprepencbuf_get_type(void); + +G_END_DECLS + +#endif /* __GST_TIPREPENCBUF_H__ */ + + +/****************************************************************************** + * Custom ViM Settings for editing this file + ******************************************************************************/ +#if 0 + Tabs (use 4 spaces for indentation) + vim:set tabstop=4: /* Use 4 spaces for tabs */ + vim:set shiftwidth=4: /* Use 4 spaces for >> operations */ + vim:set expandtab: /* Expand tabs into white spaces */ +#endif |