+gst-openmax (0.10.1-1slp2+22) unstable; urgency=low
+
+ * modify adapter memory leak and support dmabuf
+ * Git: pkgs/g/gst-openmax
+ * Tag: gst-openmax_0.10.1-1slp2+21
+
+ -- Sunghyun Eum <sunghyun.eum@samsung.com> Fri, 19 Oct 2012 18:33:12 +0900
+
gst-openmax (0.10.1-1slp2+21) unstable; urgency=low
* Initial Release.
Source: gst-openmax
Maintainer: Hyunseok Lee <hs7388.lee@samsung.com>, JongHyuk Choi <jhchoi.choi@samsung.com>
-Uploaders: Hyunseok Lee <hs7388.lee@samsung.com>, Dowan Kim <dowan2171.kim@samsung.com>, Sunghyun Eum <sunghyun.eum@samsung.com>, Seongho Jeong(sh33.jeong@samsung.com)
+Uploaders: Hyunseok Lee <hs7388.lee@samsung.com>, Dowan Kim <dowan2171.kim@samsung.com>, Sunghyun Eum <sunghyun.eum@samsung.com>
Section: libs
Priority: optional
Standards-Version: 3.7.3
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_" />
+ </request>
+</manifest>
gstomx_h264dec.c gstomx_h264dec.h \
gstomx_wmvdec.c gstomx_wmvdec.h \
gstomx_mpeg4enc.c gstomx_mpeg4enc.h \
- gstomx_h264enc.c gstomx_h264enc.h \
+ gstomx_h264enc.c gstomx_h264enc.h gstomx_h264.h \
gstomx_h263enc.c gstomx_h263enc.h \
gstomx_vorbisdec.c gstomx_vorbisdec.h \
gstomx_mp3dec.c gstomx_mp3dec.h \
static gchar *
get_config_path (void)
{
+/* MODIFICATION */
#if 1 /* Fix_config_path */
return g_build_filename (OMX_CONFIG_DIRPATH, OMX_CONFIG_FILENAME, NULL);
#else
const gchar *element_name = gst_structure_nth_field_name (element_table, i);
GstStructure *element = get_element_entry (element_name);
const gchar *type_name, *parent_type_name;
- const gchar *component_name, *component_role, *library_name;
+ const gchar *component_name, *library_name;
+// const gchar *component_role;
GType type;
gint rank;
parent_type_name = gst_structure_get_string (element, "parent-type");
type_name = gst_structure_get_string (element, "type");
component_name = gst_structure_get_string (element, "component-name");
- component_role = gst_structure_get_string (element, "component-role");
+// component_role = gst_structure_get_string (element, "component-role");
library_name = gst_structure_get_string (element, "library-name");
if (!type_name || !component_name || !library_name) {
#define GST_CAT_DEFAULT gstomx_debug
/* Fix_config_path */
-#define OMX_CONFIG_DIRPATH "/opt/etc"
+#define OMX_CONFIG_DIRPATH "/usr/etc"
#define OMX_CONFIG_FILENAME "gst-openmax.conf"
enum
#include "gstomx_base_audiodec.h"
#include "gstomx.h"
+enum
+{
+ ARG_0,
+ ARG_USE_STATETUNING, /* STATE_TUNING */
+};
+
GSTOMX_BOILERPLATE (GstOmxBaseAudioDec, gst_omx_base_audiodec, GstOmxBaseFilter,
GST_OMX_BASE_FILTER_TYPE);
{
}
+/* MODIFICATION: add state tuning property */
+static void
+set_property (GObject * obj,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstOmxBaseAudioDec *self;
+
+ self = GST_OMX_BASE_AUDIODEC (obj);
+
+ switch (prop_id) {
+ /* STATE_TUNING */
+ case ARG_USE_STATETUNING:
+ self->omx_base.use_state_tuning = g_value_get_boolean(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ GstOmxBaseAudioDec *self;
+
+ self = GST_OMX_BASE_AUDIODEC (obj);
+
+ switch (prop_id) {
+ /* STATE_TUNING */
+ case ARG_USE_STATETUNING:
+ g_value_set_boolean(value, self->omx_base.use_state_tuning);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
static void
type_class_init (gpointer g_class, gpointer class_data)
{
+ GObjectClass *gobject_class;
+// GstOmxBaseFilterClass *basefilter_class;
+
+ gobject_class = G_OBJECT_CLASS (g_class);
+// basefilter_class = GST_OMX_BASE_FILTER_CLASS (g_class);
+
+ /* Properties stuff */
+ {
+ gobject_class->set_property = set_property;
+ gobject_class->get_property = get_property;
+
+ /* STATE_TUNING */
+ g_object_class_install_property (gobject_class, ARG_USE_STATETUNING,
+ g_param_spec_boolean ("state-tuning", "start omx component in gst paused state",
+ "Whether or not to use state-tuning feature",
+ FALSE, G_PARAM_READWRITE));
+ }
}
static void
#include <string.h> /* for memcpy */
-/* STATE_TUNING */
+/* MODIFICATION: for state-tuning */
static void output_loop (gpointer data);
enum
ARG_USE_TIMESTAMPS = GSTOMX_NUM_COMMON_PROP,
ARG_NUM_INPUT_BUFFERS,
ARG_NUM_OUTPUT_BUFFERS,
- ARG_USE_STATETUNING, /* STATE_TUNING */
};
static void init_interfaces (GType type);
GST_TYPE_ELEMENT, init_interfaces);
static inline void
-log_buffer (GstOmxBaseFilter * self, OMX_BUFFERHEADERTYPE * omx_buffer)
+log_buffer (GstOmxBaseFilter * self, OMX_BUFFERHEADERTYPE * omx_buffer, const gchar *name)
{
- GST_DEBUG_OBJECT (self, "omx_buffer: "
+ GST_DEBUG_OBJECT (self, "%s: omx_buffer: "
"size=%lu, "
"len=%lu, "
"flags=%lu, "
"offset=%lu, "
"timestamp=%lld",
- omx_buffer->nAllocLen, omx_buffer->nFilledLen, omx_buffer->nFlags,
+ name, omx_buffer->nAllocLen, omx_buffer->nFilledLen, omx_buffer->nFlags,
omx_buffer->nOffset, omx_buffer->nTimeStamp);
}
case OMX_EXT_COLOR_FormatNV12TPhysicalAddress:
case OMX_EXT_COLOR_FormatNV12LPhysicalAddress:
case OMX_EXT_COLOR_FormatNV12Tiled:
+ case OMX_EXT_COLOR_FormatNV12TFdValue:
+ case OMX_EXT_COLOR_FormatNV12LFdValue:
return TRUE;
default:
return FALSE;
GST_DEBUG_OBJECT (self, "OMX_ALLOCATE_ON");
self->in_port->omx_allocate = TRUE;
self->out_port->omx_allocate = TRUE;
- self->share_input_buffer = FALSE;
- self->share_output_buffer = FALSE;
+ self->in_port->shared_buffer = FALSE;
+ self->out_port->shared_buffer = FALSE;
} else if (g_getenv ("OMX_SHARE_HACK_ON")) {
GST_DEBUG_OBJECT (self, "OMX_SHARE_HACK_ON");
- self->share_input_buffer = TRUE;
- self->share_output_buffer = TRUE;
+ self->in_port->shared_buffer = TRUE;
+ self->out_port->shared_buffer = TRUE;
} else if (g_getenv ("OMX_SHARE_HACK_OFF")) {
GST_DEBUG_OBJECT (self, "OMX_SHARE_HACK_OFF");
- self->share_input_buffer = FALSE;
- self->share_output_buffer = FALSE;
- /* Add extended_color_format */
+ self->in_port->shared_buffer = FALSE;
+ self->out_port->shared_buffer = FALSE;
+ /* MODIFICATION: Add extended_color_format */
} else if (self->gomx->component_vendor == GOMX_VENDOR_SLSI) {
- self->share_input_buffer = (is_extended_color_format(self, self->in_port))
+ self->in_port->shared_buffer = (is_extended_color_format(self, self->in_port))
? FALSE : TRUE;
- self->share_output_buffer = (is_extended_color_format(self, self->out_port))
+ self->out_port->shared_buffer = (is_extended_color_format(self, self->out_port))
? FALSE : TRUE;
+ } else if (self->gomx->component_vendor == GOMX_VENDOR_QCT) {
+ GST_DEBUG_OBJECT (self, "GOMX_VENDOR_QCT");
+ self->in_port->omx_allocate = TRUE;
+ self->out_port->omx_allocate = TRUE;
+ self->in_port->shared_buffer = FALSE;
+ self->out_port->shared_buffer = FALSE;
} else {
GST_DEBUG_OBJECT (self, "default sharing and allocation");
}
GST_DEBUG_OBJECT (self, "omx_allocate: in: %d, out: %d",
self->in_port->omx_allocate, self->out_port->omx_allocate);
GST_DEBUG_OBJECT (self, "share_buffer: in: %d, out: %d",
- self->share_input_buffer, self->share_output_buffer);
+ self->in_port->shared_buffer, self->out_port->shared_buffer);
+}
+
+static GstFlowReturn
+omx_change_state(GstOmxBaseFilter * self,GstOmxChangeState transition, GOmxPort *in_port, GstBuffer * buf)
+{
+ GOmxCore *gomx;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ gomx = self->gomx;
+
+ switch (transition) {
+ case GstOmx_LodedToIdle:
+ {
+ g_mutex_lock (self->ready_lock);
+
+ GST_INFO_OBJECT (self, "omx: prepare");
+
+ /** @todo this should probably go after doing preparations. */
+ if (self->omx_setup) {
+ self->omx_setup (self);
+ }
+
+ setup_ports (self);
+
+ g_omx_core_prepare (self->gomx);
+
+ if (gomx->omx_state == OMX_StateIdle) {
+ self->ready = TRUE;
+ gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
+ }
+
+ g_mutex_unlock (self->ready_lock);
+
+ if (gomx->omx_state != OMX_StateIdle)
+ goto out_flushing;
+ }
+ break;
+
+ case GstOmx_IdleToExcuting:
+ {
+ GST_INFO_OBJECT (self, "omx: play");
+ g_omx_core_start (gomx);
+
+ if (gomx->omx_state != OMX_StateExecuting)
+ goto out_flushing;
+
+ /* send buffer with codec data flag */
+ /** @todo move to util */
+ if (self->codec_data) {
+ OMX_BUFFERHEADERTYPE *omx_buffer;
+
+ GST_LOG_OBJECT (self, "request buffer");
+ omx_buffer = g_omx_port_request_buffer (in_port);
+
+ if (G_LIKELY (omx_buffer)) {
+ omx_buffer->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
+
+ omx_buffer->nFilledLen = GST_BUFFER_SIZE (self->codec_data);
+ memcpy (omx_buffer->pBuffer + omx_buffer->nOffset,
+ GST_BUFFER_DATA (self->codec_data), omx_buffer->nFilledLen);
+
+ GST_LOG_OBJECT (self, "release_buffer");
+ g_omx_port_release_buffer (in_port, omx_buffer);
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+leave:
+
+ GST_LOG_OBJECT (self, "end");
+ return ret;
+
+ /* special conditions */
+out_flushing:
+ {
+ const gchar *error_msg = NULL;
+
+ if (gomx->omx_error) {
+ error_msg = "Error from OpenMAX component";
+ } else if (gomx->omx_state != OMX_StateExecuting &&
+ gomx->omx_state != OMX_StatePause) {
+ error_msg = "OpenMAX component in wrong state";
+ }
+
+ if (error_msg) {
+ GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("%s", error_msg));
+ ret = GST_FLOW_ERROR;
+ }
+
+ if (buf)
+ gst_buffer_unref (buf);
+ goto leave;
+ }
}
static GstStateChangeReturn
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
+ GST_INFO_OBJECT (self, "GST_STATE_CHANGE_NULL_TO_READY");
if (core->omx_state != OMX_StateLoaded) {
ret = GST_STATE_CHANGE_FAILURE;
goto leave;
}
+
+ if (self->adapter_size > 0) {
+ GST_LOG_OBJECT (self, "gst_adapter_new. size: %d", self->adapter_size);
+ self->adapter = gst_adapter_new();
+ if (self->adapter == NULL)
+ GST_ERROR_OBJECT (self, "Failed to create adapter!!");
+ }
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
- /* STATE_TUNING */
- if (self->use_state_tuning) {
- GST_INFO_OBJECT (self, "use state-tuning feature");
- g_mutex_lock (self->ready_lock);
-
- self->sink_set_caps = (GstCaps *)gst_pad_peer_get_caps (self->sinkpad);
- if (self->sink_set_caps == NULL) {
- GST_ERROR_OBJECT (self, "Caps is NULL");
- }
-
- GST_INFO_OBJECT (self, "omx: prepare");
-
- /** @todo this should probably go after doing preparations. */
- if (self->omx_setup) {
- self->omx_setup (self);
- }
-
- setup_ports (self);
-
- g_omx_core_prepare (self->gomx);
-
- if (core->omx_state == OMX_StateIdle) {
- self->ready = TRUE;
- gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
- } else {
- GST_ERROR_OBJECT(self, "fail to move from OMX state Loaded to Idle");
- g_omx_port_finish(self->in_port);
- g_omx_port_finish(self->out_port);
- g_omx_core_stop(core);
- g_omx_core_unload(core);
- g_mutex_unlock(self->ready_lock);
- ret = GST_STATE_CHANGE_FAILURE;
- goto leave;
- }
-
- g_mutex_unlock (self->ready_lock);
+ GST_INFO_OBJECT (self, "GST_STATE_CHANGE_READY_TO_PAUSED");
+ /* MODIFICATION: state tuning */
+ if (self->use_state_tuning) {
+ GST_INFO_OBJECT (self, "use state-tuning feature");
+ /* to handle abnormal state change. */
+ if (self->gomx != self->in_port->core) {
+ GST_ERROR_OBJECT(self, "self->gomx != self->in_port->core. start new in_port");
+ self->in_port = g_omx_core_new_port (self->gomx, 0);
+ }
+ if (self->gomx != self->out_port->core) {
+ GST_ERROR_OBJECT(self, "self->gomx != self->out_port->core. start new out_port");
+ self->out_port = g_omx_core_new_port (self->gomx, 1);
+ }
+
+ omx_change_state(self, GstOmx_LodedToIdle, NULL, NULL);
+
+ if (core->omx_state != OMX_StateIdle) {
+ GST_ERROR_OBJECT(self, "fail to move from OMX state Loaded to Idle");
+ g_omx_port_finish(self->in_port);
+ g_omx_port_finish(self->out_port);
+ g_omx_core_stop(core);
+ g_omx_core_unload(core);
+ ret = GST_STATE_CHANGE_FAILURE;
+ goto leave;
+ }
}
break;
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
+ GST_INFO_OBJECT (self, "GST_STATE_CHANGE_PAUSED_TO_READY");
g_mutex_lock (self->ready_lock);
if (self->ready) {
- /* unlock */
g_omx_port_finish (self->in_port);
g_omx_port_finish (self->out_port);
}
break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ GST_INFO_OBJECT (self, "GST_STATE_CHANGE_READY_TO_NULL");
+ if (self->adapter) {
+ gst_adapter_clear(self->adapter);
+ g_object_unref(self->adapter);
+ self->adapter = NULL;
+ }
+ break;
+
default:
break;
}
self = GST_OMX_BASE_FILTER (obj);
+ if (self->adapter) {
+ gst_adapter_clear(self->adapter);
+ g_object_unref(self->adapter);
+ self->adapter = NULL;
+ }
+
if (self->codec_data) {
gst_buffer_unref (self->codec_data);
self->codec_data = NULL;
OMX_SetParameter (omx_handle, OMX_IndexParamPortDefinition, ¶m);
}
break;
- /* STATE_TUNING */
- case ARG_USE_STATETUNING:
- self->use_state_tuning = g_value_get_boolean(value);
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
break;
g_value_set_uint (value, param.nBufferCountActual);
}
break;
- /* STATE_TUNING */
- case ARG_USE_STATETUNING:
- g_value_set_boolean(value, self->use_state_tuning);
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
break;
"The number of OMX output buffers",
1, 10, 4, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- /* STATE_TUNING */
- g_object_class_install_property (gobject_class, ARG_USE_STATETUNING,
- g_param_spec_boolean ("state-tuning", "start omx component in gst paused state",
- "Whether or not to use state-tuning feature",
- FALSE, G_PARAM_READWRITE));
}
}
static inline GstFlowReturn
-push_buffer (GstOmxBaseFilter * self, GstBuffer * buf)
+push_buffer (GstOmxBaseFilter * self, GstBuffer * buf, OMX_BUFFERHEADERTYPE * omx_buffer)
{
- GstFlowReturn ret;
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstOmxBaseFilterClass *basefilter_class;
+
+ basefilter_class = GST_OMX_BASE_FILTER_GET_CLASS (self);
+ /* process output gst buffer before gst_pad_push */
+ if (basefilter_class->process_output_buf) {
+ GstOmxReturn ret = GSTOMX_RETURN_OK;
+ ret = basefilter_class->process_output_buf(self, &buf, omx_buffer);
+ if (ret == GSTOMX_RETURN_SKIP) {
+ gst_buffer_unref (buf);
+ goto leave;
+ }
+ }
- /** @todo check if tainted */
- GST_LOG_OBJECT (self, "begin");
+ GST_LOG_OBJECT (self, "OUT_BUFFER: timestamp = %" GST_TIME_FORMAT " size = %lu",
+ GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_SIZE (buf));
ret = gst_pad_push (self->srcpad, buf);
- GST_LOG_OBJECT (self, "end");
+ GST_LOG_OBJECT (self, "gst_pad_push end. ret = %d", ret);
+leave:
return ret;
}
goto leave;
}
- log_buffer (self, omx_buffer);
+ log_buffer (self, omx_buffer, "output_loop");
if (G_LIKELY (omx_buffer->nFilledLen > 0)) {
GstBuffer *buf;
/** @todo we need to move all the caps handling to one single
* place, in the output loop probably. */
if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) {
- GstCaps *caps = NULL;
- GstStructure *structure;
- GValue value = { 0, {{0}
- }
- };
-
- caps = gst_pad_get_negotiated_caps (self->srcpad);
- caps = gst_caps_make_writable (caps);
- structure = gst_caps_get_structure (caps, 0);
-
- g_value_init (&value, GST_TYPE_BUFFER);
- buf = gst_buffer_new_and_alloc (omx_buffer->nFilledLen);
- memcpy (GST_BUFFER_DATA (buf),
- omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
- gst_value_set_buffer (&value, buf);
- gst_buffer_unref (buf);
- gst_structure_set_value (structure, "codec_data", &value);
- g_value_unset (&value);
-
- gst_pad_set_caps (self->srcpad, caps);
+ /* modification: to handle both byte-stream and packetized codec_data */
+ GstOmxBaseFilterClass *basefilter_class;
+ basefilter_class = GST_OMX_BASE_FILTER_GET_CLASS (self);
+ if (basefilter_class->process_output_caps) {
+ basefilter_class->process_output_caps(self, omx_buffer);
+ }
+ /* MODIFICATION: to handle output ST12 HW addr (dec) */
} else if (is_extended_color_format(self, self->out_port)) {
GstCaps *caps = NULL;
GstStructure *structure;
gint width = 0, height = 0;
+ SCMN_IMGB *outbuf = NULL;
+
+ if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_DECODEONLY)) {
+ GST_INFO_OBJECT (self, "Decodeonly flag was set from component");
+ g_omx_port_release_buffer (out_port, omx_buffer);
+ goto leave;
+ }
caps = gst_pad_get_negotiated_caps(self->srcpad);
structure = gst_caps_get_structure(caps, 0);
gst_structure_get_int(structure, "height", &height);
if (G_LIKELY((width > 0) && (height > 0))) {
- buf = gst_buffer_new_and_alloc((width * height * 3) / 2);
+ buf = gst_buffer_new_and_alloc(width * height * 3 / 2);
} else {
GST_ERROR_OBJECT (self, "invalid buffer size");
ret = GST_FLOW_UNEXPECTED;
goto leave;
}
+ outbuf = (SCMN_IMGB*)(omx_buffer->pBuffer);
+ if (outbuf->buf_share_method == 1) {
+ GST_LOG_OBJECT (self, "dec output buf: fd[0]:%d fd[1]:%d fd[2]:%d w[0]:%d h[0]:%d buf_share_method:%d",
+ outbuf->fd[0], outbuf->fd[1], outbuf->fd[2], outbuf->w[0], outbuf->h[0], outbuf->buf_share_method);
+ } else if (outbuf->buf_share_method == 0) {
+ GST_LOG_OBJECT (self, "dec output uses hw addr");
+ } else {
+ GST_WARNING_OBJECT (self, "dec output buf has wrong buf_share_method");
+ }
memcpy (GST_BUFFER_MALLOCDATA(buf), omx_buffer->pBuffer, omx_buffer->nFilledLen);
if (self->use_timestamps) {
OMX_TICKS_PER_SECOND);
}
gst_buffer_set_caps(buf, GST_PAD_CAPS(self->srcpad));
+ gst_caps_unref (caps);
- ret = push_buffer (self, buf);
+ ret = push_buffer (self, buf, omx_buffer);
} else if (buf && !(omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) {
GST_BUFFER_SIZE (buf) = omx_buffer->nFilledLen;
if (self->use_timestamps) {
omx_buffer->pAppPrivate = NULL;
omx_buffer->pBuffer = NULL;
- /* Set sync frame info while encoding */
- if (omx_buffer->nFlags & OMX_BUFFERFLAG_SYNCFRAME) {
- GST_BUFFER_FLAG_UNSET(buf, GST_BUFFER_FLAG_DELTA_UNIT);
- } else {
- GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT);
- }
+ ret = push_buffer (self, buf, omx_buffer);
- ret = push_buffer (self, buf);
-
- gst_buffer_unref (buf);
} else {
/* This is only meant for the first OpenMAX buffers,
* which need to be pre-allocated. */
OMX_TICKS_PER_SECOND);
}
- if (self->share_output_buffer) {
+ if (self->out_port->shared_buffer) {
GST_WARNING_OBJECT (self, "couldn't zero-copy");
/* If pAppPrivate is NULL, it means it was a dummy
* allocation, free it. */
}
}
- /* Set sync frame info while encoding */
- if (omx_buffer->nFlags & OMX_BUFFERFLAG_SYNCFRAME) {
- GST_BUFFER_FLAG_UNSET(buf, GST_BUFFER_FLAG_DELTA_UNIT);
- } else {
- GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT);
- }
-
- ret = push_buffer (self, buf);
+ ret = push_buffer (self, buf, omx_buffer);
} else {
GST_WARNING_OBJECT (self, "couldn't allocate buffer of size %lu",
omx_buffer->nFilledLen);
GST_WARNING_OBJECT (self, "empty buffer");
}
- if (self->share_output_buffer &&
+ if (self->out_port->shared_buffer &&
!omx_buffer->pBuffer && omx_buffer->nOffset == 0) {
GstBuffer *buf;
GstFlowReturn result;
omx_buffer->nAllocLen, GST_PAD_CAPS (self->srcpad), &buf);
if (G_LIKELY (result == GST_FLOW_OK)) {
- gst_buffer_ref (buf);
omx_buffer->pAppPrivate = buf;
omx_buffer->pBuffer = GST_BUFFER_DATA (buf);
}
}
- if (self->share_output_buffer && !omx_buffer->pBuffer) {
+ if (self->out_port->shared_buffer && !omx_buffer->pBuffer) {
GST_ERROR_OBJECT (self, "no input buffer to share");
}
GOmxCore *gomx;
GOmxPort *in_port;
GstOmxBaseFilter *self;
+ GstOmxBaseFilterClass *basefilter_class;
GstFlowReturn ret = GST_FLOW_OK;
+ GstBuffer *adapter_buf = NULL;
self = GST_OMX_BASE_FILTER (GST_OBJECT_PARENT (pad));
gomx = self->gomx;
- GST_LOG_OBJECT (self, "begin");
- GST_LOG_OBJECT (self, "gst_buffer: size=%u", GST_BUFFER_SIZE (buf));
-
- GST_LOG_OBJECT (self, "state: %d", gomx->omx_state);
+ GST_LOG_OBJECT (self, "IN_BUFFER: timestamp = %" GST_TIME_FORMAT " size = %lu, state:%d",
+ GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_SIZE (buf), gomx->omx_state);
/* STATE_TUNING */
if (!self->use_state_tuning) {
- if (G_UNLIKELY (gomx->omx_state == OMX_StateLoaded)) {
- g_mutex_lock (self->ready_lock);
-
- GST_INFO_OBJECT (self, "omx: prepare");
-
- /** @todo this should probably go after doing preparations. */
- if (self->omx_setup) {
- self->omx_setup (self);
- }
-
- setup_ports (self);
-
- g_omx_core_prepare (self->gomx);
-
- if (gomx->omx_state == OMX_StateIdle) {
- self->ready = TRUE;
- gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
- }
-
- g_mutex_unlock (self->ready_lock);
-
- if (gomx->omx_state != OMX_StateIdle)
- goto out_flushing;
- }
+ if (G_UNLIKELY (gomx->omx_state == OMX_StateLoaded))
+ omx_change_state(self, GstOmx_LodedToIdle, NULL, NULL);
}
in_port = self->in_port;
if (G_LIKELY (in_port->enabled)) {
guint buffer_offset = 0;
+ guint8 *src_data = NULL;
+ guint src_size = 0;
+ GstClockTime src_timestamp = 0;
+ GstClockTime src_duration = 0;
- if (G_UNLIKELY (gomx->omx_state == OMX_StateIdle)) {
- GST_INFO_OBJECT (self, "omx: play");
- g_omx_core_start (gomx);
+ if (G_UNLIKELY (gomx->omx_state == OMX_StateIdle))
+ omx_change_state(self, GstOmx_IdleToExcuting,in_port, buf);
- if (gomx->omx_state != OMX_StateExecuting)
- goto out_flushing;
+ if (G_UNLIKELY (gomx->omx_state != OMX_StateExecuting)) {
+ GST_ERROR_OBJECT (self, "Whoa! very wrong");
+ }
- /* send buffer with codec data flag */
- /** @todo move to util */
- if (self->codec_data) {
- OMX_BUFFERHEADERTYPE *omx_buffer;
+ basefilter_class = GST_OMX_BASE_FILTER_GET_CLASS (self);
+ /* process input gst buffer before OMX_EmptyThisBuffer */
+ if (basefilter_class->process_input_buf)
+ {
+ GstOmxReturn ret = GSTOMX_RETURN_OK;
+ ret = basefilter_class->process_input_buf(self,&buf);
+ if (ret == GSTOMX_RETURN_SKIP) {
+ gst_buffer_unref(buf);
+ goto leave;
+ }
+ }
- GST_LOG_OBJECT (self, "request buffer");
- omx_buffer = g_omx_port_request_buffer (in_port);
+ if (self->adapter_size > 0) {
+ if (!self->adapter) {
+ GST_WARNING_OBJECT (self, "adapter is NULL. retry gst_adapter_new");
+ self->adapter = gst_adapter_new();
+ }
- if (G_LIKELY (omx_buffer)) {
- omx_buffer->nFlags |= OMX_BUFFERFLAG_CODECCONFIG; /* codec data flag */
+ if (GST_BUFFER_IS_DISCONT(buf))
+ {
+ GST_INFO_OBJECT (self, "got GST_BUFFER_IS_DISCONT.");
+ gst_adapter_clear(self->adapter);
+ }
- omx_buffer->nFilledLen = GST_BUFFER_SIZE (self->codec_data);
- memcpy (omx_buffer->pBuffer + omx_buffer->nOffset,
- GST_BUFFER_DATA (self->codec_data), omx_buffer->nFilledLen);
+ gst_adapter_push(self->adapter, buf);
- GST_LOG_OBJECT (self, "release_buffer");
- g_omx_port_release_buffer (in_port, omx_buffer);
- }
+ src_size = gst_adapter_available(self->adapter);
+ if (src_size < self->adapter_size) {
+ GST_LOG_OBJECT (self, "Not enough data in adapter to feed to decoder.");
+ goto leave;
}
- }
- if (G_UNLIKELY (gomx->omx_state != OMX_StateExecuting)) {
- GST_ERROR_OBJECT (self, "Whoa! very wrong");
+ if (src_size > self->adapter_size) {
+ src_size = src_size - GST_BUFFER_SIZE(buf);
+ GST_LOG_OBJECT (self, "take buffer from adapter. size=%d", src_size);
+ }
+
+ src_timestamp = gst_adapter_prev_timestamp(self->adapter, NULL);
+ adapter_buf = gst_adapter_take_buffer(self->adapter, src_size);
+ src_data = GST_BUFFER_DATA(adapter_buf);
+ src_duration = GST_BUFFER_TIMESTAMP (buf) - src_timestamp;
+ } else {
+ src_data = GST_BUFFER_DATA (buf);
+ src_size = GST_BUFFER_SIZE (buf);
+ src_timestamp = GST_BUFFER_TIMESTAMP (buf);
+ src_duration = GST_BUFFER_DURATION (buf);
}
- while (G_LIKELY (buffer_offset < GST_BUFFER_SIZE (buf))) {
+ while (G_LIKELY (buffer_offset < src_size)) {
OMX_BUFFERHEADERTYPE *omx_buffer;
if (self->last_pad_push_return != GST_FLOW_OK ||
GST_LOG_OBJECT (self, "omx_buffer: %p", omx_buffer);
if (G_LIKELY (omx_buffer)) {
- log_buffer (self, omx_buffer);
+ log_buffer (self, omx_buffer, "pad_chain");
+ /* MODIFICATION: to handle input SN12 HW addr. (enc) */
if (is_extended_color_format(self, self->in_port)) {
- if(!GST_BUFFER_MALLOCDATA(buf)) {
- GST_WARNING_OBJECT (self, "null MALLOCDATA in hw color format. skip this.");
- ret = GST_FLOW_OK;
- goto out_flushing;
- }
- /* Copy p[0], p[1] of SCMN_IMGB to pAddrY, pAddrC of MFC_ENC_ADDR_INFO */
- memcpy (omx_buffer->pBuffer,
- GST_BUFFER_MALLOCDATA(buf)
- + (sizeof (int) * 4 + sizeof (void*)) * 4, sizeof (void*));
- memcpy (omx_buffer->pBuffer + sizeof (void*),
- GST_BUFFER_MALLOCDATA(buf)
- + (sizeof (int) * 4 + sizeof (void*)) * 4 + sizeof (void*),
- sizeof (void*));
- omx_buffer->nAllocLen = sizeof (void*) * 2;
- omx_buffer->nFilledLen = sizeof (void*) * 2;
- } else if (omx_buffer->nOffset == 0 && self->share_input_buffer) {
+ SCMN_IMGB *inbuf = NULL;
+
+ if (!GST_BUFFER_MALLOCDATA(buf)) {
+ GST_WARNING_OBJECT (self, "null MALLOCDATA in hw color format. skip this.");
+ goto out_flushing;
+ }
+
+ inbuf = (SCMN_IMGB*)(GST_BUFFER_MALLOCDATA(buf));
+ if (inbuf != NULL && inbuf->buf_share_method == 1) {
+ GST_LOG_OBJECT (self, "enc. fd[0]:%d fd[1]:%d fd[2]:%d w[0]:%d h[0]:%d buf_share_method:%d",
+ inbuf->fd[0], inbuf->fd[1], inbuf->fd[2], inbuf->w[0], inbuf->h[0], inbuf->buf_share_method);
+ } else if (inbuf != NULL && inbuf->buf_share_method == 0) {
+ GST_LOG_OBJECT (self, "enc input buf uses hw addr");
+ } else {
+ GST_WARNING_OBJECT (self, "enc input buf has wrong buf_share_method");
+ }
+
+ memcpy (omx_buffer->pBuffer, GST_BUFFER_MALLOCDATA(buf), sizeof(SCMN_IMGB));
+ omx_buffer->nAllocLen = sizeof(SCMN_IMGB);
+ omx_buffer->nFilledLen = sizeof(SCMN_IMGB);
+ } else if (omx_buffer->nOffset == 0 && self->in_port->shared_buffer) {
{
GstBuffer *old_buf;
old_buf = omx_buffer->pAppPrivate;
if (old_buf) {
- gst_buffer_unref (old_buf);
+ gst_buffer_unref ((GstBuffer *)old_buf);
} else if (omx_buffer->pBuffer) {
g_free (omx_buffer->pBuffer);
+ omx_buffer->pBuffer = NULL;
}
}
- omx_buffer->pBuffer = GST_BUFFER_DATA (buf);
- omx_buffer->nAllocLen = GST_BUFFER_SIZE (buf);
- omx_buffer->nFilledLen = GST_BUFFER_SIZE (buf);
- omx_buffer->pAppPrivate = buf;
+ omx_buffer->pBuffer = src_data;
+ omx_buffer->nAllocLen = src_size;
+ omx_buffer->nFilledLen = src_size;
+ omx_buffer->pAppPrivate = (self->adapter_size > 0) ? (OMX_PTR)adapter_buf : (OMX_PTR)buf;
} else {
- omx_buffer->nFilledLen = MIN (GST_BUFFER_SIZE (buf) - buffer_offset,
+ omx_buffer->nFilledLen = MIN (src_size - buffer_offset,
omx_buffer->nAllocLen - omx_buffer->nOffset);
memcpy (omx_buffer->pBuffer + omx_buffer->nOffset,
- GST_BUFFER_DATA (buf) + buffer_offset, omx_buffer->nFilledLen);
+ src_data + buffer_offset, omx_buffer->nFilledLen);
}
if (self->use_timestamps) {
GstClockTime timestamp_offset = 0;
- if (buffer_offset && GST_BUFFER_DURATION (buf) != GST_CLOCK_TIME_NONE) {
+ if (buffer_offset && src_duration != GST_CLOCK_TIME_NONE) {
timestamp_offset = gst_util_uint64_scale_int (buffer_offset,
- GST_BUFFER_DURATION (buf), GST_BUFFER_SIZE (buf));
+ src_duration, src_size);
}
omx_buffer->nTimeStamp =
- gst_util_uint64_scale_int (GST_BUFFER_TIMESTAMP (buf) +
+ gst_util_uint64_scale_int (src_timestamp +
timestamp_offset, OMX_TICKS_PER_SECOND, GST_SECOND);
}
+ /* MODIFICATION: hw addr */
if (is_extended_color_format(self, self->in_port)) {
buffer_offset = GST_BUFFER_SIZE (buf);
} else {
ret = GST_FLOW_UNEXPECTED;
}
- if (!self->share_input_buffer) {
- gst_buffer_unref (buf);
+ if (!self->in_port->shared_buffer) {
+ if (self->adapter_size > 0 && adapter_buf) {
+ gst_buffer_unref (adapter_buf);
+ adapter_buf = NULL;
+ } else {
+ gst_buffer_unref (buf);
+ }
}
leave:
{
const gchar *error_msg = NULL;
+ GST_LOG_OBJECT(self, "out_flushing");
+
if (gomx->omx_error) {
error_msg = "Error from OpenMAX component";
} else if (gomx->omx_state != OMX_StateExecuting &&
ret = GST_FLOW_ERROR;
}
- gst_buffer_unref (buf);
+ if (self->adapter_size > 0 && adapter_buf) {
+ gst_buffer_unref (adapter_buf);
+ adapter_buf = NULL;
+ } else {
+ gst_buffer_unref (buf);
+ }
goto leave;
}
GST_INFO_OBJECT (self, "event: %s", GST_EVENT_TYPE_NAME (event));
+ if (self->pad_event) {
+ if (!self->pad_event(pad, event))
+ return TRUE;
+ }
+
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_EOS:
/* if we are init'ed, and there is a running loop; then
omx_buffer = g_omx_port_request_buffer (in_port);
if (G_LIKELY (omx_buffer)) {
+
+ if (self->adapter_size > 0 && self->adapter) {
+ guint src_len = 0;
+ GstBuffer *adapter_buf = NULL;
+
+ src_len = gst_adapter_available(self->adapter);
+ if (src_len > 0 && src_len < self->adapter_size) {
+ omx_buffer->nTimeStamp = gst_util_uint64_scale_int(
+ gst_adapter_prev_timestamp(self->adapter, NULL),
+ OMX_TICKS_PER_SECOND, GST_SECOND);
+ adapter_buf = gst_adapter_take_buffer(self->adapter, src_len);
+ omx_buffer->pBuffer = GST_BUFFER_DATA(adapter_buf);
+ omx_buffer->nAllocLen = src_len;
+ omx_buffer->nFilledLen = src_len;
+ omx_buffer->pAppPrivate = adapter_buf;
+ }
+ gst_adapter_clear(self->adapter);
+ }
omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
- GST_LOG_OBJECT (self, "release_buffer");
+ GST_LOG_OBJECT (self, "release_buffer in EOS. size=%d", omx_buffer->nFilledLen);
/* foo_buffer_untaint (omx_buffer); */
g_omx_port_release_buffer (in_port, omx_buffer);
/* loop handles EOS, eat it here */
break;
case GST_EVENT_FLUSH_START:
- if((gomx->omx_state == OMX_StatePause)||(gomx->omx_state == OMX_StateExecuting)) {
- gst_pad_push_event (self->srcpad, event);
- self->last_pad_push_return = GST_FLOW_WRONG_STATE;
+ if (gomx->omx_state == OMX_StatePause || gomx->omx_state == OMX_StateExecuting) {
+ gst_pad_push_event (self->srcpad, event);
+ self->last_pad_push_return = GST_FLOW_WRONG_STATE;
- g_omx_core_flush_start (gomx);
+ g_omx_core_flush_start (gomx);
- gst_pad_pause_task (self->srcpad);
+ gst_pad_pause_task (self->srcpad);
- ret = TRUE;
- } else {
- GST_WARNING_OBJECT (self, "flush start in wrong omx state");
- ret = FALSE;
- }
+ ret = TRUE;
+ } else {
+ GST_ERROR_OBJECT (self, "flush start in wrong omx state");
+ ret = FALSE;
+ }
break;
case GST_EVENT_FLUSH_STOP:
- if((gomx->omx_state == OMX_StatePause)||(gomx->omx_state == OMX_StateExecuting)) {
- gst_pad_push_event (self->srcpad, event);
- self->last_pad_push_return = GST_FLOW_OK;
+ if (gomx->omx_state == OMX_StatePause || gomx->omx_state == OMX_StateExecuting) {
+ gst_pad_push_event (self->srcpad, event);
+ self->last_pad_push_return = GST_FLOW_OK;
- g_omx_core_flush_stop (gomx);
+ g_omx_core_flush_stop (gomx);
- if (self->ready)
- gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
+ if (self->adapter_size > 0 && self->adapter) {
+ gst_adapter_clear(self->adapter);
+ }
- ret = TRUE;
- } else {
- GST_WARNING_OBJECT (self, "flush start in wrong omx state");
- ret = FALSE;
- }
+ if (self->ready)
+ gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
+
+ ret = TRUE;
+ } else {
+ GST_ERROR_OBJECT (self, "flush start in wrong omx state");
+ ret = FALSE;
+ }
break;
case GST_EVENT_NEWSEGMENT:
GST_LOG_OBJECT (self, "begin");
self->use_timestamps = TRUE;
- self->use_state_tuning = FALSE; /* STATE_TUNING */
+ self->use_state_tuning = FALSE;
+ self->adapter_size = 0;
+ self->adapter = NULL;
self->gomx = gstomx_core_new (self, G_TYPE_FROM_CLASS (g_class));
self->in_port = g_omx_core_new_port (self->gomx, 0);
#define GSTOMX_BASE_FILTER_H
#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include "gstomx_util.h"
+#include <async_queue.h>
G_BEGIN_DECLS
-#define GST_OMX_BASE_FILTER(obj) (GstOmxBaseFilter *) (obj)
#define GST_OMX_BASE_FILTER_TYPE (gst_omx_base_filter_get_type ())
-#define GST_OMX_BASE_FILTER_CLASS(obj) (GstOmxBaseFilterClass *) (obj)
+#define GST_OMX_BASE_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_OMX_BASE_FILTER_TYPE, GstOmxBaseFilter))
+#define GST_OMX_BASE_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_OMX_BASE_FILTER_TYPE, GstOmxBaseFilterClass))
+#define GST_OMX_BASE_FILTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_OMX_BASE_FILTER_TYPE, GstOmxBaseFilterClass))
typedef struct GstOmxBaseFilter GstOmxBaseFilter;
typedef struct GstOmxBaseFilterClass GstOmxBaseFilterClass;
typedef void (*GstOmxBaseFilterCb) (GstOmxBaseFilter * self);
+typedef gboolean (*GstOmxBaseFilterEventCb) (GstPad * pad, GstEvent * event);
-#include "gstomx_util.h"
-#include <async_queue.h>
-/* Add extended_color_format */
+/* using common scmn_imgb format */
+#define SCMN_IMGB_MAX_PLANE (4) /* max channel count */
+
+/* image buffer definition
+ +------------------------------------------+ ---
+ | | ^
+ | a[], p[] | |
+ | +---------------------------+ --- | |
+ | | | ^ | |
+ | |<---------- w[] ---------->| | | |
+ | | | | | |
+ | | | |
+ | | | h[] | e[]
+ | | | |
+ | | | | | |
+ | | | | | |
+ | | | v | |
+ | +---------------------------+ --- | |
+ | | v
+ +------------------------------------------+ ---
+
+ |<----------------- s[] ------------------>|
+*/
+
+typedef struct
+{
+ int w[SCMN_IMGB_MAX_PLANE]; /* width of each image plane */
+ int h[SCMN_IMGB_MAX_PLANE]; /* height of each image plane */
+ int s[SCMN_IMGB_MAX_PLANE]; /* stride of each image plane */
+ int e[SCMN_IMGB_MAX_PLANE]; /* elevation of each image plane */
+ void * a[SCMN_IMGB_MAX_PLANE]; /* user space address of each image plane */
+ void * p[SCMN_IMGB_MAX_PLANE]; /* physical address of each image plane, if needs */
+ int cs; /* color space type of image */
+ int x; /* left postion, if needs */
+ int y; /* top position, if needs */
+ int __dummy2; /* to align memory */
+ int data[16]; /* arbitrary data */
+
+ /* dmabuf fd */
+ int fd[SCMN_IMGB_MAX_PLANE];
+
+ /* flag for buffer share */
+ int buf_share_method;
+} SCMN_IMGB;
+
+/* MODIFICATION: Add extended_color_format */
typedef enum _EXT_OMX_COLOR_FORMATTYPE {
OMX_EXT_COLOR_FormatNV12TPhysicalAddress = 0x7F000001, /**< Reserved region for introducing Vendor Extensions */
OMX_EXT_COLOR_FormatNV12LPhysicalAddress = 0x7F000002,
- OMX_EXT_COLOR_FormatNV12Tiled = 0x7FC00002 /* 0x7FC00002 */
+ OMX_EXT_COLOR_FormatNV12Tiled = 0x7FC00002,
+ OMX_EXT_COLOR_FormatNV12TFdValue = 0x7F000012,
+ OMX_EXT_COLOR_FormatNV12LFdValue = 0x7F000013
}EXT_OMX_COLOR_FORMATTYPE;
+typedef enum GstOmxReturn
+{
+ GSTOMX_RETURN_OK,
+ GSTOMX_RETURN_SKIP,
+ GSTOMX_RETURN_ERROR
+}GstOmxReturn;
+
+typedef enum GstOmxChangeState
+{
+ GstOmx_ToLoaded,
+ GstOmx_LodedToIdle,
+ GstOmx_IdleToExcuting
+}GstOmxChangeState;
+
struct GstOmxBaseFilter
{
GstElement element;
GMutex *ready_lock;
GstOmxBaseFilterCb omx_setup;
+ GstOmxBaseFilterEventCb pad_event;
GstFlowReturn last_pad_push_return;
GstBuffer *codec_data;
- /** @todo these are hacks, OpenMAX IL spec should be revised. */
- gboolean share_input_buffer;
- gboolean share_output_buffer;
-
- /* STATE_TUNING */
- GstCaps *sink_set_caps;
+ /* MODIFICATION: state-tuning */
gboolean use_state_tuning;
+
+ GstAdapter *adapter; /* adapter */
+ guint adapter_size;
};
struct GstOmxBaseFilterClass
{
GstElementClass parent_class;
+
+ GstOmxReturn (*process_input_buf)(GstOmxBaseFilter *omx_base_filter, GstBuffer **buf);
+ GstOmxReturn (*process_output_buf)(GstOmxBaseFilter *omx_base_filter, GstBuffer **buf, OMX_BUFFERHEADERTYPE *omx_buffer);
+ void (*process_output_caps)(GstOmxBaseFilter *omx_base_filter, OMX_BUFFERHEADERTYPE *omx_buffer);
+
};
GType gst_omx_base_filter_get_type (void);
ARG_NUM_INPUT_BUFFERS = GSTOMX_NUM_COMMON_PROP,
};
-static gboolean share_input_buffer;
-
static inline gboolean omx_init (GstOmxBaseSink * self);
static void init_interfaces (GType type);
omx_buffer->nAllocLen, omx_buffer->nFilledLen, omx_buffer->nFlags,
omx_buffer->nOffset, omx_buffer->nTimeStamp);
- if (omx_buffer->nOffset == 0 && share_input_buffer) {
+ if (omx_buffer->nOffset == 0 && self->in_port->shared_buffer) {
{
GstBuffer *old_buf;
old_buf = omx_buffer->pAppPrivate;
gst_buffer_unref (old_buf);
} else if (omx_buffer->pBuffer) {
g_free (omx_buffer->pBuffer);
+ omx_buffer->pBuffer = NULL;
}
}
#include "gstomx_base_videodec.h"
#include "gstomx.h"
+enum
+{
+ ARG_0,
+ ARG_USE_STATETUNING, /* STATE_TUNING */
+};
+
GSTOMX_BOILERPLATE (GstOmxBaseVideoDec, gst_omx_base_videodec, GstOmxBaseFilter,
GST_OMX_BASE_FILTER_TYPE);
+static GstOmxReturn
+process_input_buf (GstOmxBaseFilter * omx_base_filter, GstBuffer **buf)
+{
+ return GSTOMX_RETURN_OK;
+}
+
static void
type_base_init (gpointer g_class)
{
}
+/* MODIFICATION: add state tuning property */
+static void
+set_property (GObject * obj,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstOmxBaseVideoDec *self;
+
+ self = GST_OMX_BASE_VIDEODEC (obj);
+
+ switch (prop_id) {
+ /* STATE_TUNING */
+ case ARG_USE_STATETUNING:
+ self->omx_base.use_state_tuning = g_value_get_boolean(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ GstOmxBaseVideoDec *self;
+
+ self = GST_OMX_BASE_VIDEODEC (obj);
+
+ switch (prop_id) {
+ /* STATE_TUNING */
+ case ARG_USE_STATETUNING:
+ g_value_set_boolean(value, self->omx_base.use_state_tuning);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
static void
type_class_init (gpointer g_class, gpointer class_data)
{
+ GObjectClass *gobject_class;
+ GstOmxBaseFilterClass *basefilter_class;
+
+ gobject_class = G_OBJECT_CLASS (g_class);
+ basefilter_class = GST_OMX_BASE_FILTER_CLASS (g_class);
+
+ /* Properties stuff */
+ {
+ gobject_class->set_property = set_property;
+ gobject_class->get_property = get_property;
+
+ /* STATE_TUNING */
+ g_object_class_install_property (gobject_class, ARG_USE_STATETUNING,
+ g_param_spec_boolean ("state-tuning", "start omx component in gst paused state",
+ "Whether or not to use state-tuning feature",
+ FALSE, G_PARAM_READWRITE));
+ }
+ basefilter_class->process_input_buf = process_input_buf;
}
static void
width = param.format.video.nFrameWidth;
height = param.format.video.nFrameHeight;
+
+ GST_LOG_OBJECT (omx_base, "settings changed: fourcc =0x%x", (guint)param.format.video.eColorFormat);
switch ((guint)param.format.video.eColorFormat) {
case OMX_COLOR_FormatYUV420Planar:
case OMX_COLOR_FormatYUV420PackedPlanar:
case OMX_COLOR_FormatCbYCrY:
format = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
break;
- /* Add extended_color_format */
+ /* MODIFICATION: Add extended_color_format */
+ case OMX_EXT_COLOR_FormatNV12TFdValue:
case OMX_EXT_COLOR_FormatNV12TPhysicalAddress:
format = GST_MAKE_FOURCC ('S', 'T', '1', '2');
break;
GST_INFO_OBJECT (omx_base, "caps are: %" GST_PTR_FORMAT, new_caps);
gst_pad_set_caps (omx_base->srcpad, new_caps);
+ gst_caps_unref (new_caps); /* Modification: unref caps */
}
}
}
}
- /* STATE_TUNING */
- if (omx_base->use_state_tuning && omx_base->sink_set_caps) {
- sink_setcaps(omx_base->sinkpad, omx_base->sink_set_caps);
- }
-
GST_INFO_OBJECT (omx_base, "end");
}
{
ARG_0,
ARG_BITRATE,
+ ARG_FORCE_KEY_FRAME,
};
#define DEFAULT_BITRATE 0
GSTOMX_BOILERPLATE (GstOmxBaseVideoEnc, gst_omx_base_videoenc, GstOmxBaseFilter,
GST_OMX_BASE_FILTER_TYPE);
+
+/* modification: user force I frame */
+static void
+add_force_key_frame(GstOmxBaseVideoEnc *enc)
+{
+ GstOmxBaseFilter *omx_base;
+ GOmxCore *gomx;
+ OMX_CONFIG_INTRAREFRESHVOPTYPE config;
+
+ omx_base = GST_OMX_BASE_FILTER (enc);
+ gomx = (GOmxCore *) omx_base->gomx;
+
+
+ GST_INFO_OBJECT (enc, "request forced key frame now.");
+
+ if (!omx_base->out_port || !gomx->omx_handle) {
+ GST_WARNING_OBJECT (enc, "failed to set force-i-frame...");
+ return;
+ }
+
+ G_OMX_INIT_PARAM (config);
+ config.nPortIndex = omx_base->out_port->port_index;
+
+ OMX_GetConfig (gomx->omx_handle, OMX_IndexConfigVideoIntraVOPRefresh, &config);
+ config.IntraRefreshVOP = OMX_TRUE;
+
+ OMX_SetConfig (gomx->omx_handle, OMX_IndexConfigVideoIntraVOPRefresh, &config);
+}
+
+
+static GstOmxReturn
+process_input_buf (GstOmxBaseFilter * omx_base_filter, GstBuffer **buf)
+{
+ GstOmxBaseVideoEnc *self;
+
+ self = GST_OMX_BASE_VIDEOENC (omx_base_filter);
+
+ GST_LOG_OBJECT (self, "base videoenc process_input_buf enter");
+
+
+ return GSTOMX_RETURN_OK;
+}
+
+/* modification: postprocess for outputbuf. in this videoenc case, set sync frame */
+static GstOmxReturn
+process_output_buf(GstOmxBaseFilter * omx_base, GstBuffer **buf, OMX_BUFFERHEADERTYPE *omx_buffer)
+{
+ GstOmxBaseVideoEnc *self;
+
+ self = GST_OMX_BASE_VIDEOENC (omx_base);
+
+ GST_LOG_OBJECT (self, "base videoenc process_output_buf enter");
+
+ /* modification: set sync frame info while encoding */
+ if (omx_buffer->nFlags & OMX_BUFFERFLAG_SYNCFRAME) {
+ GST_BUFFER_FLAG_UNSET(*buf, GST_BUFFER_FLAG_DELTA_UNIT);
+ } else {
+ GST_BUFFER_FLAG_SET(*buf, GST_BUFFER_FLAG_DELTA_UNIT);
+ }
+
+ return GSTOMX_RETURN_OK;
+}
+
+/* modification: get codec_data from omx component and set it caps */
+static void
+process_output_caps(GstOmxBaseFilter * self, OMX_BUFFERHEADERTYPE *omx_buffer)
+{
+ GstBuffer *buf;
+ GstCaps *caps = NULL;
+ GstStructure *structure;
+ GValue value = { 0, {{0}
+ }
+ };
+
+ caps = gst_pad_get_negotiated_caps (self->srcpad);
+ caps = gst_caps_make_writable (caps);
+ structure = gst_caps_get_structure (caps, 0);
+
+ g_value_init (&value, GST_TYPE_BUFFER);
+ buf = gst_buffer_new_and_alloc (omx_buffer->nFilledLen);
+ memcpy (GST_BUFFER_DATA (buf),
+ omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
+ gst_value_set_buffer (&value, buf);
+ gst_buffer_unref (buf);
+ gst_structure_set_value (structure, "codec_data", &value);
+ g_value_unset (&value);
+
+ gst_pad_set_caps (self->srcpad, caps);
+ gst_caps_unref (caps);
+}
+
static void
type_base_init (gpointer g_class)
{
case ARG_BITRATE:
self->bitrate = g_value_get_uint (value);
break;
+ /* modification: request to component to make key frame */
+ case ARG_FORCE_KEY_FRAME:
+ self->use_force_key_frame = g_value_get_boolean (value);
+ if (self->use_force_key_frame) {
+ add_force_key_frame (self);
+ self->use_force_key_frame = FALSE;
+ }
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
break;
type_class_init (gpointer g_class, gpointer class_data)
{
GObjectClass *gobject_class;
+ GstOmxBaseFilterClass *basefilter_class;
+// GstOmxBaseVideoEncClass *videoenc_class;
gobject_class = G_OBJECT_CLASS (g_class);
+ basefilter_class = GST_OMX_BASE_FILTER_CLASS (g_class);
+// videoenc_class = GST_OMX_BASE_VIDEOENC_CLASS (g_class);
/* Properties stuff */
{
"Encoding bit-rate",
0, G_MAXUINT, DEFAULT_BITRATE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class, ARG_FORCE_KEY_FRAME,
+ g_param_spec_boolean ("force-i-frame", "force the encoder to produce I frame",
+ "force the encoder to produce I frame",
+ FALSE,
+ G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
}
+ basefilter_class->process_input_buf = process_input_buf;
+ basefilter_class->process_output_buf = process_output_buf;
+ basefilter_class->process_output_caps = process_output_caps;
}
static gboolean
case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
color_format = OMX_COLOR_FormatCbYCrY;
break;
- /* Add extended_color_format */
+ /* MODIFICATION: Add extended_color_format */
case GST_MAKE_FOURCC ('S', 'T', '1', '2'):
color_format = OMX_EXT_COLOR_FormatNV12TPhysicalAddress;
break;
OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, ¶m);
}
+ /* modification: set nBufferSize */
G_OMX_INIT_PARAM (param);
param.nPortIndex = omx_base->out_port->port_index;
OMX_GetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, ¶m);
- param.nBufferSize = MAX(param.nBufferSize, width * height * 3 / 2);
+ param.nBufferSize = width * height * 3 / 2;
OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, ¶m);
}
param.format.video.eCompressionFormat = self->compression_format;
- if (self->bitrate != 0)
+ if (self->bitrate > 0)
param.format.video.nBitrate = self->bitrate;
OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, ¶m);
}
}
- /* STATE_TUNING */
- if (omx_base->use_state_tuning && omx_base->sink_set_caps) {
- sink_setcaps(omx_base->sinkpad, omx_base->sink_set_caps);
+ /* modification: set bitrate by using OMX_IndexParamVideoBitrate macro*/
+ if (self->bitrate > 0) {
+ OMX_VIDEO_PARAM_BITRATETYPE param;
+ G_OMX_INIT_PARAM (param);
+
+ param.nPortIndex = omx_base->out_port->port_index;
+ OMX_GetParameter (gomx->omx_handle, OMX_IndexParamVideoBitrate, ¶m);
+
+ param.nTargetBitrate = self->bitrate;
+ param.eControlRate = OMX_Video_ControlRateConstant;
+ GST_INFO_OBJECT (self, "set bitrate (OMX_Video_ControlRateConstant): %d", param.nTargetBitrate);
+
+ OMX_SetParameter (gomx->omx_handle, OMX_IndexParamVideoBitrate, ¶m);
}
GST_INFO_OBJECT (omx_base, "end");
gst_pad_set_setcaps_function (omx_base->sinkpad, sink_setcaps);
self->bitrate = DEFAULT_BITRATE;
+ self->use_force_key_frame = FALSE;
}
G_BEGIN_DECLS
#define GST_OMX_BASE_VIDEOENC(obj) (GstOmxBaseVideoEnc *) (obj)
#define GST_OMX_BASE_VIDEOENC_TYPE (gst_omx_base_videoenc_get_type ())
+#define GST_OMX_BASE_VIDEOENC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_OMX_BASE_VIDEOENC_TYPE, GstOmxBaseVideoEncClass))
typedef struct GstOmxBaseVideoEnc GstOmxBaseVideoEnc;
typedef struct GstOmxBaseVideoEncClass GstOmxBaseVideoEncClass;
struct GstOmxBaseVideoEnc
{
GstOmxBaseFilter omx_base;
-
OMX_VIDEO_CODINGTYPE compression_format;
+
guint bitrate;
gint framerate_num;
gint framerate_denom;
+ gboolean use_force_key_frame;
};
struct GstOmxBaseVideoEncClass
--- /dev/null
+/*
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Author: Sunghyun Eum <sunghyun.eum@samsung.com>
+ *
+ * This library 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; either version 2.1 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef GSTOMX_H264_H
+#define GSTOMX_H264_H
+
+G_BEGIN_DECLS
+
+/* modification: byte-stream(nal) - packetized (3gpp) converting (h264dec, h264enc) */
+#define GSTOMX_H264_MDATA 6 /* packtized meta data size. (ver, profile...) */
+#define GSTOMX_H264_A_DCI_LEN 4 /* 4-byte sps, pps size field in append dci*/
+#define GSTOMX_H264_C_DCI_LEN 2 /* 2-byte sps, pps size field in codec data*/
+#define GSTOMX_H264_CNT_LEN 1 /* 1-byte sps, pps count field */
+
+#define GSTOMX_H264_NAL_START_LEN 4
+#define GSTOMX_H264_SPSPPS_LEN 2
+
+typedef enum
+{
+ GSTOMX_H264_NUT_UNKNOWN = 0,
+ GSTOMX_H264_NUT_SLICE = 1,
+ GSTOMX_H264_NUT_DPA = 2,
+ GSTOMX_H264_NUT_DPB = 3,
+ GSTOMX_H264_NUT_DPC = 4,
+ GSTOMX_H264_NUT_IDR = 5,
+ GSTOMX_H264_NUT_SEI = 6,
+ GSTOMX_H264_NUT_SPS = 7,
+ GSTOMX_H264_NUT_PPS = 8,
+ GSTOMX_H264_NUT_AUD = 9,
+ GSTOMX_H264_NUT_EOSEQ = 10,
+ GSTOMX_H264_NUT_EOSTREAM = 11,
+ GSTOMX_H264_NUT_FILL = 12,
+ GSTOMX_H264_NUT_MIXED = 24,
+} GSTOMX_H264_NAL_UNIT_TYPE;
+
+typedef enum
+{
+ GSTOMX_H264_FORMAT_UNKNOWN,
+ GSTOMX_H264_FORMAT_PACKETIZED,
+ GSTOMX_H264_FORMAT_BYTE_STREAM,
+} GSTOMX_H264_STREAM_FORMAT;
+
+#define GSTOMX_H264_WB32(p, d) \
+ do { \
+ ((unsigned char*)(p))[3] = (d); \
+ ((unsigned char*)(p))[2] = (d)>>8; \
+ ((unsigned char*)(p))[1] = (d)>>16; \
+ ((unsigned char*)(p))[0] = (d)>>24; \
+ } while(0);
+
+#define GSTOMX_H264_WB16(p, d) \
+ do { \
+ ((unsigned char*)(p))[1] = (d); \
+ ((unsigned char*)(p))[0] = (d)>>8; \
+ } while(0);
+
+#define GSTOMX_H264_RB16(x) ((((const unsigned char*)(x))[0] << 8) | ((const unsigned char*)(x))[1])
+
+#define GSTOMX_H264_RB32(x) ((((const unsigned char*)(x))[0] << 24) | \
+ (((const unsigned char*)(x))[1] << 16) | \
+ (((const unsigned char*)(x))[2] << 8) | \
+ ((const unsigned char*)(x))[3])
+
+G_END_DECLS
+#endif /* GSTOMX_H264_H */
GSTOMX_BOILERPLATE (GstOmxH264Dec, gst_omx_h264dec, GstOmxBaseVideoDec,
GST_OMX_BASE_VIDEODEC_TYPE);
+/*
+ * description : find stream format(3gpp or nalu)
+ * params : @self : GstOmxH264Dec, @buf: input gstbuffer in pad_chain
+ * return : none
+ * comments : finding whether the stream format of input buf is 3GPP or Elementary Stream(nalu)
+ */
+static void
+check_frame (GstOmxH264Dec *self, GstBuffer * buf)
+{
+ guint buf_size = GST_BUFFER_SIZE (buf);
+ guint8 *buf_data = GST_BUFFER_DATA (buf);
+ guint nal_type = 0;
+ guint forbidden_zero_bit = 0;
+ guint check_byte= 0;
+
+ if (buf_data == NULL || buf_size < GSTOMX_H264_NAL_START_LEN + 1) {
+ self->h264Format = GSTOMX_H264_FORMAT_UNKNOWN;
+ GST_WARNING_OBJECT(self, "H264 format is unknown");
+ return;
+ }
+
+ self->h264Format = GSTOMX_H264_FORMAT_PACKETIZED;
+
+ if ((buf_data[0] == 0x00)&&(buf_data[1] == 0x00)&&
+ ((buf_data[2] == 0x01)||((buf_data[2] == 0x00)&&(buf_data[3] == 0x01)))) {
+ check_byte = (buf_data[2] == 0x01) ? 3 : 4;
+
+ nal_type = (guint)(buf_data[check_byte] & 0x1f);
+ forbidden_zero_bit = (guint)(buf_data[check_byte] & 0x80);
+ GST_LOG_OBJECT(self, "check first frame: nal_type=%d, forbidden_zero_bit=%d", nal_type, forbidden_zero_bit);
+
+ if (forbidden_zero_bit == 0) {
+ /* check nal_unit_type is invaild value: ex) slice, DPA,DPB... */
+ if ((0 < nal_type && nal_type <= 15) || nal_type == 19 || nal_type == 20) {
+ GST_INFO_OBJECT(self, "H264 format is Byte-stream format");
+ self->h264Format = GSTOMX_H264_FORMAT_BYTE_STREAM;
+ }
+ }
+ }
+
+ if (self->h264Format == GSTOMX_H264_FORMAT_PACKETIZED)
+ GST_INFO_OBJECT(self, "H264 format is Packetized format");
+}
+
+/*
+ * description : convert input 3gpp buffer to nalu based buffer
+ * params : @self : GstOmxH264Dec, @buf: buffer to be converted
+ * return : none
+ * comments : none
+ */
+static void
+convert_frame (GstOmxH264Dec *self, GstBuffer **buf)
+{
+ OMX_U8 frameType;
+ OMX_U32 nalSize = 0;
+ OMX_U32 cumulSize = 0;
+ OMX_U32 offset = 0;
+ OMX_U32 nalHeaderSize = 0;
+ OMX_U32 outSize = 0;
+ OMX_U8 *frame_3gpp = GST_BUFFER_DATA(*buf);
+ OMX_U32 frame_3gpp_size = GST_BUFFER_SIZE(*buf);
+ GstBuffer *nalu_next_buf = NULL;
+ GstBuffer *nalu_buf = NULL;
+
+ do {
+ /* get NAL Length based on length of length*/
+ if (self->h264NalLengthSize == 1) {
+ nalSize = frame_3gpp[0];
+ } else if (self->h264NalLengthSize == 2) {
+ nalSize = GSTOMX_H264_RB16(frame_3gpp);
+ } else {
+ nalSize = GSTOMX_H264_RB32(frame_3gpp);
+ }
+
+ GST_LOG_OBJECT(self, "packetized frame size = %d", nalSize);
+
+ frame_3gpp += self->h264NalLengthSize;
+
+ /* Checking frame type */
+ frameType = *frame_3gpp & 0x1f;
+
+ switch (frameType)
+ {
+ case GSTOMX_H264_NUT_SLICE:
+ GST_LOG_OBJECT(self, "Frame is non-IDR frame...");
+ break;
+ case GSTOMX_H264_NUT_IDR:
+ GST_LOG_OBJECT(self, "Frame is an IDR frame...");
+ break;
+ case GSTOMX_H264_NUT_SEI:
+ GST_LOG_OBJECT(self, "Found SEI Data...");
+ break;
+ case GSTOMX_H264_NUT_SPS:
+ GST_LOG_OBJECT(self, "Found SPS data...");
+ break;
+ case GSTOMX_H264_NUT_PPS:
+ GST_LOG_OBJECT(self, "Found PPS data...");
+ break;
+ case GSTOMX_H264_NUT_EOSEQ:
+ GST_LOG_OBJECT(self, "End of sequence...");
+ break;
+ case GSTOMX_H264_NUT_EOSTREAM:
+ GST_LOG_OBJECT(self, "End of stream...");
+ break;
+ case GSTOMX_H264_NUT_DPA:
+ case GSTOMX_H264_NUT_DPB:
+ case GSTOMX_H264_NUT_DPC:
+ case GSTOMX_H264_NUT_AUD:
+ case GSTOMX_H264_NUT_FILL:
+ case GSTOMX_H264_NUT_MIXED:
+ break;
+ default:
+ GST_INFO_OBJECT(self, "Unknown Frame type: %d. do check_frame one more time with next frame.", frameType);
+ self->h264Format = GSTOMX_H264_FORMAT_UNKNOWN;
+ goto EXIT;
+ }
+
+ /* if nal size is same, we can change only start code */
+ if((nalSize + GSTOMX_H264_NAL_START_LEN) == frame_3gpp_size) {
+ GST_LOG_OBJECT(self, "only change start code");
+ *buf = gst_buffer_make_writable(*buf); /* make writable to support memsrc */
+ GSTOMX_H264_WB32(GST_BUFFER_DATA(*buf), 1);
+ return;
+ }
+
+ /* Convert 3GPP Frame to NALU Frame */
+ offset = outSize;
+ nalHeaderSize = offset ? 3 : 4;
+
+ outSize += nalSize + nalHeaderSize;
+
+ if (nalSize > frame_3gpp_size) {
+ GST_ERROR_OBJECT(self, "out of bounds Error. frame_nalu_size=%d", outSize);
+ goto EXIT;
+ }
+
+ if (nalu_buf) {
+ nalu_next_buf= gst_buffer_new_and_alloc(nalSize + nalHeaderSize);
+ if (nalu_next_buf == NULL) {
+ GST_ERROR_OBJECT(self, "gst_buffer_new_and_alloc failed.(nalu_next_buf)");
+ goto EXIT;
+ }
+ } else {
+ nalu_buf = gst_buffer_new_and_alloc(outSize);
+ }
+
+ if (nalu_buf == NULL) {
+ GST_ERROR_OBJECT(self, "gst_buffer_new_and_alloc failed.(nalu_buf)");
+ goto EXIT;
+ }
+
+ if (!offset) {
+ memcpy(GST_BUFFER_DATA(nalu_buf)+nalHeaderSize, frame_3gpp, nalSize);
+ GSTOMX_H264_WB32(GST_BUFFER_DATA(nalu_buf), 1);
+ } else {
+ if (nalu_next_buf) {
+ GstBuffer *nalu_joined_buf = gst_buffer_join(nalu_buf,nalu_next_buf);
+ nalu_buf = nalu_joined_buf;
+ nalu_next_buf = NULL;
+ }
+ memcpy(GST_BUFFER_DATA(nalu_buf)+nalHeaderSize+offset, frame_3gpp, nalSize);
+ (GST_BUFFER_DATA(nalu_buf)+offset)[0] = (GST_BUFFER_DATA(nalu_buf)+offset)[1] = 0;
+ (GST_BUFFER_DATA(nalu_buf)+offset)[2] = 1;
+ }
+
+ frame_3gpp += nalSize;
+ cumulSize += nalSize + self->h264NalLengthSize;
+ GST_LOG_OBJECT(self, "frame_3gpp_size = %d => frame_nalu_size=%d", frame_3gpp_size, outSize);
+ } while (cumulSize < frame_3gpp_size);
+
+ gst_buffer_copy_metadata(nalu_buf, *buf, GST_BUFFER_COPY_ALL);
+
+ gst_buffer_unref (*buf);
+ *buf = nalu_buf;
+
+ return;
+
+EXIT:
+ if (nalu_buf) { gst_buffer_unref (nalu_buf); }
+ GST_ERROR_OBJECT(self, "converting frame error.");
+
+ return;
+}
+
+/*
+ * description : convert input 3gpp buffer(codec data) to nalu based buffer
+ * params : @self : GstOmxH264Dec, @buf: buffer to be converted, @dci_nalu: converted buffer
+ * return : true on successes / false on failure
+ * comments : none
+ */
+static gboolean
+convert_dci (GstOmxH264Dec *self, GstBuffer *buf, GstBuffer **dci_nalu)
+{
+ gboolean ret = FALSE;
+ OMX_U8 *out = NULL;
+ OMX_U16 unitSize = 0;
+ OMX_U32 totalSize = 0;
+ OMX_U8 unitNb = 0;
+ OMX_U8 spsDone = 0;
+
+ OMX_U8 *pInputStream = GST_BUFFER_DATA(buf);
+ OMX_U32 pBuffSize = GST_BUFFER_SIZE(buf);
+
+ const OMX_U8 *extraData = (guchar*)pInputStream + 4;
+ static const OMX_U8 naluHeader[GSTOMX_H264_NAL_START_LEN] = {0, 0, 0, 1};
+
+ if (pInputStream != NULL) {
+ /* retrieve Length of Length*/
+ self->h264NalLengthSize = (*extraData++ & 0x03) + 1;
+ GST_INFO("Length Of Length is %d", self->h264NalLengthSize);
+ if (self->h264NalLengthSize == 3)
+ {
+ GST_INFO("LengthOfLength is WRONG...");
+ goto EXIT;
+ }
+ /* retrieve sps and pps unit(s) */
+ unitNb = *extraData++ & 0x1f;
+ GST_INFO("No. of SPS units = %u", unitNb);
+ if (!unitNb) {
+ GST_INFO("SPS is not present...");
+ goto EXIT;
+ }
+
+ while (unitNb--) {
+ /* get SPS/PPS data Length*/
+ unitSize = GSTOMX_H264_RB16(extraData);
+
+ /* Extra 4 bytes for adding delimiter */
+ totalSize += unitSize + GSTOMX_H264_NAL_START_LEN;
+
+ /* Check if SPS/PPS Data Length crossed buffer Length */
+ if ((extraData + 2 + unitSize) > (pInputStream + pBuffSize)) {
+ GST_INFO("SPS length is wrong in DCI...");
+ goto EXIT;
+ }
+
+ if (out)
+ out = g_realloc(out, totalSize);
+ else
+ out = g_malloc(totalSize);
+
+ if (!out) {
+ GST_INFO("realloc failed...");
+ goto EXIT;
+ }
+
+ /* Copy NALU header */
+ memcpy(out + totalSize - unitSize - GSTOMX_H264_NAL_START_LEN,
+ naluHeader, GSTOMX_H264_NAL_START_LEN);
+
+ /* Copy SPS/PPS Length and data */
+ memcpy(out + totalSize - unitSize, extraData + GSTOMX_H264_SPSPPS_LEN, unitSize);
+
+ extraData += (GSTOMX_H264_SPSPPS_LEN + unitSize);
+
+ if (!unitNb && !spsDone++)
+ {
+ /* Completed reading SPS data, now read PPS data */
+ unitNb = *extraData++; /* number of pps unit(s) */
+ GST_INFO( "No. of PPS units = %d", unitNb);
+ }
+ }
+
+ *dci_nalu = gst_buffer_new_and_alloc(totalSize);
+ if (*dci_nalu == NULL) {
+ GST_ERROR_OBJECT(self, " gst_buffer_new_and_alloc failed...\n");
+ goto EXIT;
+ }
+
+ memcpy(GST_BUFFER_DATA(*dci_nalu), out, totalSize);
+ GST_INFO( "Total SPS+PPS size = %d", totalSize);
+ }
+
+ ret = TRUE;
+
+EXIT:
+ if (out) {
+ g_free(out);
+ }
+ return ret;
+}
+
+
+static GstOmxReturn
+process_input_buf (GstOmxBaseFilter * omx_base_filter, GstBuffer **buf)
+{
+ GstOmxH264Dec *h264_self;
+
+ h264_self = GST_OMX_H264DEC (omx_base_filter);
+
+ if (h264_self->h264Format == GSTOMX_H264_FORMAT_UNKNOWN) {
+ check_frame(h264_self, *buf);
+ }
+
+ if (h264_self->h264Format == GSTOMX_H264_FORMAT_PACKETIZED) {
+
+ if (omx_base_filter->last_pad_push_return != GST_FLOW_OK ||
+ !(omx_base_filter->gomx->omx_state == OMX_StateExecuting ||
+ omx_base_filter->gomx->omx_state == OMX_StatePause)) {
+ GST_LOG_OBJECT(h264_self, "this frame will not be converted and go to out_flushing");
+ return GSTOMX_RETURN_OK;
+ }
+
+ GST_LOG_OBJECT(h264_self, "H264 format is Packetized format. convert to Byte-stream format");
+ convert_frame(h264_self, buf);
+ }
+
+/* if you want to use commonly for videodec input, use this */
+/* GST_OMX_BASE_FILTER_CLASS (parent_class)->process_input_buf (omx_base_filter, buf); */
+
+ return GSTOMX_RETURN_OK;
+}
+
static void
type_base_init (gpointer g_class)
{
static void
type_class_init (gpointer g_class, gpointer class_data)
{
+ GstOmxBaseFilterClass *basefilter_class;
+
+ basefilter_class = GST_OMX_BASE_FILTER_CLASS (g_class);
+
+ basefilter_class->process_input_buf = process_input_buf;
+}
+
+/* h264 dec has its own sink_setcaps for supporting nalu convert codec data */
+static gboolean
+sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstStructure *structure;
+ GstOmxBaseVideoDec *self;
+ GstOmxH264Dec *h264_self;
+ GstOmxBaseFilter *omx_base;
+ GOmxCore *gomx;
+ OMX_PARAM_PORTDEFINITIONTYPE param;
+ gint width = 0;
+ gint height = 0;
+
+ self = GST_OMX_BASE_VIDEODEC (GST_PAD_PARENT (pad));
+ h264_self = GST_OMX_H264DEC (GST_PAD_PARENT (pad));
+ omx_base = GST_OMX_BASE_FILTER (self);
+
+ gomx = (GOmxCore *) omx_base->gomx;
+
+ GST_INFO_OBJECT (self, "setcaps (sink)(h264): %" GST_PTR_FORMAT, caps);
+
+ g_return_val_if_fail (gst_caps_get_size (caps) == 1, FALSE);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ gst_structure_get_int (structure, "width", &width);
+ gst_structure_get_int (structure, "height", &height);
+
+ {
+ const GValue *framerate = NULL;
+ framerate = gst_structure_get_value (structure, "framerate");
+ if (framerate) {
+ self->framerate_num = gst_value_get_fraction_numerator (framerate);
+ self->framerate_denom = gst_value_get_fraction_denominator (framerate);
+ }
+ }
+
+ G_OMX_INIT_PARAM (param);
+
+ {
+ const GValue *codec_data;
+ GstBuffer *buffer;
+ gboolean ret = FALSE;
+ guint8 *buf_data = NULL;
+
+ codec_data = gst_structure_get_value (structure, "codec_data");
+ if (codec_data) {
+ buffer = gst_value_get_buffer (codec_data);
+
+ buf_data = GST_BUFFER_DATA(buffer);
+
+ if (GST_BUFFER_SIZE(buffer) <= GSTOMX_H264_NAL_START_LEN) {
+ GST_ERROR("codec data size (%d) is less than start code length.", GST_BUFFER_SIZE(buffer));
+ } else {
+ if ((buf_data[0] == 0x00)&&(buf_data[1] == 0x00)&&
+ ((buf_data[2] == 0x01)||((buf_data[2] == 0x00)&&(buf_data[3] == 0x01)))) {
+ h264_self->h264Format = GSTOMX_H264_FORMAT_BYTE_STREAM;
+ GST_INFO_OBJECT(self, "H264 codec_data format is Byte-stream.");
+ } else {
+ h264_self->h264Format = GSTOMX_H264_FORMAT_PACKETIZED;
+ GST_INFO_OBJECT(self, "H264 codec_data format is Packetized.");
+ }
+
+ /* if codec data is 3gpp format, convert nalu format */
+ if(h264_self->h264Format == GSTOMX_H264_FORMAT_PACKETIZED) {
+ GstBuffer *nalu_dci = NULL;
+
+ ret = convert_dci(h264_self, buffer, &nalu_dci);
+ if (ret) {
+ omx_base->codec_data = nalu_dci;
+ } else {
+ GST_ERROR_OBJECT(h264_self, "converting dci error.");
+ if (nalu_dci) {
+ gst_buffer_unref (nalu_dci);
+ nalu_dci = NULL;
+ }
+ omx_base->codec_data = buffer;
+ gst_buffer_ref (buffer);
+ }
+
+ } else { /* not 3GPP format */
+ omx_base->codec_data = buffer;
+ gst_buffer_ref (buffer);
+ }
+ }
+ h264_self->h264Format = GSTOMX_H264_FORMAT_UNKNOWN;
+ }
+ }
+ /* Input port configuration. */
+ {
+ param.nPortIndex = omx_base->in_port->port_index;
+ OMX_GetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, ¶m);
+
+ param.format.video.nFrameWidth = width;
+ param.format.video.nFrameHeight = height;
+
+ OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, ¶m);
+ }
+ return gst_pad_set_caps (pad, caps);
}
static void
type_instance_init (GTypeInstance * instance, gpointer g_class)
{
GstOmxBaseVideoDec *omx_base;
+ GstOmxBaseFilter *omx_base_filter;
omx_base = GST_OMX_BASE_VIDEODEC (instance);
+ omx_base_filter = GST_OMX_BASE_FILTER (instance);
omx_base->compression_format = OMX_VIDEO_CodingAVC;
+
+ gst_pad_set_setcaps_function (omx_base_filter->sinkpad, sink_setcaps);
}
G_BEGIN_DECLS
#define GST_OMX_H264DEC(obj) (GstOmxH264Dec *) (obj)
#define GST_OMX_H264DEC_TYPE (gst_omx_h264dec_get_type ())
+
typedef struct GstOmxH264Dec GstOmxH264Dec;
typedef struct GstOmxH264DecClass GstOmxH264DecClass;
#include "gstomx_base_videodec.h"
+#include "gstomx_h264.h"
struct GstOmxH264Dec
{
GstOmxBaseVideoDec omx_base;
+ GSTOMX_H264_STREAM_FORMAT h264Format;
+ OMX_U32 h264NalLengthSize;
};
struct GstOmxH264DecClass
#include "gstomx_h264enc.h"
#include "gstomx.h"
+enum
+{
+ ARG_0,
+ ARG_APPEND_DCI,
+ ARG_BYTE_STREAM,
+ ARG_SLICE_MODE,
+ ARG_SLICE_SIZE,
+};
+
GSTOMX_BOILERPLATE (GstOmxH264Enc, gst_omx_h264enc, GstOmxBaseVideoEnc,
GST_OMX_BASE_VIDEOENC_TYPE);
+/*
+ * description : convert byte-stream format to packetized frame
+ * params : @self : GstOmxH264Enc, @buf: byte-stream buf, @sync: notify this buf is sync frame
+ * return : none
+ * comments :
+ */
+static void
+convert_to_packetized_frame (GstOmxH264Enc *self, GstBuffer **buf)
+{
+ unsigned char *data = GST_BUFFER_DATA (*buf);
+ unsigned int size = GST_BUFFER_SIZE(*buf);
+ int idx = 0;
+ gint start_idx = -1;
+ unsigned char *nalu_start = NULL;
+ GstOmxBaseFilter *omx_base = GST_OMX_BASE_FILTER(self);
+
+ GST_LOG_OBJECT (self, "convert_to_packtized format. size=%d sliceMode=%d",
+ GST_BUFFER_SIZE(*buf), self->slice_fmo.eSliceMode);
+
+ if (omx_base->gomx->component_vendor == GOMX_VENDOR_SLSI &&
+ self->slice_fmo.eSliceMode == OMX_VIDEO_SLICEMODE_AVCDefault) { /* 1 slice per frame */
+ GST_LOG_OBJECT (self, " handle single NALU per buffer");
+ while (idx < size - GSTOMX_H264_NAL_START_LEN) {
+ if (((data[idx] == 0x00) && (data[idx+1] == 0x00) && (data[idx+2] == 0x00)&& (data[idx+3] == 0x01)) ||
+ ((data[idx] == 0x00) && (data[idx+1] == 0x00) && (data[idx+2] == 0x01))) {
+ if (data[idx+2] == 0x01) {
+ GST_ERROR_OBJECT (self, "ERROR : NALU header is 3-bytes, yet to support !!");
+ } else {
+ GSTOMX_H264_WB32(data + idx, size - idx - GSTOMX_H264_NAL_START_LEN);
+ return;
+ }
+ }
+ idx++;
+ } /* while */
+ } else { /* handle multiple NALUs in one buffer */
+ GST_LOG_OBJECT (self, " handle multiple NALUs per buffer");
+ while (idx < size - GSTOMX_H264_NAL_START_LEN) {
+ if (((data[idx] == 0x00) && (data[idx+1] == 0x00) && (data[idx+2] == 0x00)&& (data[idx+3] == 0x01)) ||
+ ((data[idx] == 0x00) && (data[idx+1] == 0x00) && (data[idx+2] == 0x01))) {
+ if (data[idx+2] == 0x01) {
+ GST_ERROR_OBJECT (self, "ERROR : NALU header is 3-bytes, yet to support !!");
+ } else {
+ if (start_idx >= 0) {
+ if (idx <= start_idx) {
+ GST_ERROR_OBJECT (self, "ERROR : idx <= start_idx !!");
+ return;
+ }
+ GST_LOG_OBJECT (self, "size of current nal unit = %d", idx-start_idx);
+ GSTOMX_H264_WB32(nalu_start, idx - start_idx - GSTOMX_H264_NAL_START_LEN);
+ }
+ start_idx = idx;
+ nalu_start = data + idx;
+ idx++;
+ }
+ }
+ idx++;
+ } /* while */
+ idx += GSTOMX_H264_NAL_START_LEN;
+
+ /* converting last nal unit */
+ if (start_idx >= 0) {
+ GST_LOG_OBJECT (self, "size of current nal unit = %d", idx-start_idx);
+ GSTOMX_H264_WB32(nalu_start, idx - start_idx - GSTOMX_H264_NAL_START_LEN);
+ }
+ }
+}
+
+/*
+ * description : convert byte-stream codec data to packtized codec_data
+ * params : @self : GstOmxH264Enc, @inbuf: byte-stream codec data (omx buf), @outbuf: packetized codec_data
+ * return : true on successes / false on failure
+ * comments :
+ */
+static gboolean
+convert_to_packetized_dci (GstOmxH264Enc *self, unsigned char *nalu_dci, unsigned nalu_dci_len,
+ GstBuffer **packetized_dci, gint *out_sps_cnt, gint *out_pps_cnt)
+{
+ gint idx = 0;
+ gint sps_cnt = 0;
+ gint pps_cnt = 0;
+ GQueue *sps_queue = 0;
+ GQueue *pps_queue = 0;
+ unsigned char *packet_dci = NULL;
+ gint prev_nalu_start = 0;
+ gint prev_nalu_type = GSTOMX_H264_NUT_UNKNOWN;
+ gint sps_size = 0;
+ gint pps_size = 0;
+ GstBuffer *sps_data = NULL;
+ GstBuffer *pps_data = NULL;
+ GstBuffer *queue_data = NULL;
+ gint nal_type = GSTOMX_H264_NUT_UNKNOWN;
+ unsigned char profile = 0;
+ unsigned char level = 0;
+ unsigned char profile_comp = 0;
+ gboolean bret = TRUE;
+ gboolean single_sps_pps = FALSE; /* if there is only 1 sps, pps set, */
+
+ sps_queue = g_queue_new ();
+ pps_queue = g_queue_new ();
+
+ /* find no.of SPS & PPS units */
+ while (idx < nalu_dci_len) {
+ if ((nalu_dci[idx] == 0x00) && (nalu_dci[idx+1] == 0x00) && (nalu_dci[idx+2] == 0x01)) {
+ /* copy previous nal unit */
+ if (prev_nalu_start && prev_nalu_type == GSTOMX_H264_NUT_SPS) {
+ if (nalu_dci[idx -1] == 0x00) {
+ sps_size = idx -1 - prev_nalu_start;
+ } else {
+ sps_size = idx - prev_nalu_start;
+ }
+ sps_data = gst_buffer_new_and_alloc (sps_size + GSTOMX_H264_C_DCI_LEN);
+ if (!sps_data) {
+ GST_ERROR_OBJECT (self, "failed to allocate memory..");
+ bret = FALSE;
+ goto exit;
+ }
+ GSTOMX_H264_WB16(GST_BUFFER_DATA(sps_data), sps_size);
+ memcpy (GST_BUFFER_DATA(sps_data) + GSTOMX_H264_C_DCI_LEN, nalu_dci + prev_nalu_start, sps_size);
+ g_queue_push_tail (sps_queue, sps_data);
+ } else if (prev_nalu_start && prev_nalu_type == GSTOMX_H264_NUT_PPS) {
+ if (nalu_dci[idx -1] == 0x00) {
+ pps_size = idx -1 - prev_nalu_start;
+ } else {
+ pps_size = idx - prev_nalu_start;
+ }
+ pps_data = gst_buffer_new_and_alloc (pps_size + GSTOMX_H264_C_DCI_LEN);
+ if (!pps_data) {
+ GST_ERROR_OBJECT (self, "failed to allocate memory..");
+ bret = FALSE;
+ goto exit;
+ }
+ GSTOMX_H264_WB16(GST_BUFFER_DATA(pps_data), pps_size);
+ memcpy (GST_BUFFER_DATA(pps_data) + GSTOMX_H264_C_DCI_LEN, nalu_dci + prev_nalu_start, pps_size);
+ g_queue_push_tail (pps_queue, pps_data);
+ }
+ /* present nalu type */
+ nal_type = nalu_dci[idx+3] & 0x1f;
+
+ if (nal_type == GSTOMX_H264_NUT_SPS) {
+ sps_cnt++;
+ prev_nalu_start = idx + 3;
+ prev_nalu_type =GSTOMX_H264_NUT_SPS;
+ profile = nalu_dci[idx+4];
+ level = nalu_dci[idx+6];
+ GST_INFO_OBJECT (self, "Profile Number = %d and Level = %d...", nalu_dci[idx+4], level);
+ GST_INFO_OBJECT (self, "Profile is %s", (profile == 66) ? "BaseLine Profile": (profile == 77)? "Main Profile": profile==88 ?
+ "Extended Profile": profile==100 ? "High Profile": "Not Supported codec");
+ } else if ((nalu_dci[idx+3] & 0x1f) == GSTOMX_H264_NUT_PPS) {
+ pps_cnt++;
+ prev_nalu_start = idx + 3;
+ prev_nalu_type = GSTOMX_H264_NUT_PPS;
+ }
+ }
+ idx++;
+ }
+
+ /* copy previous nal unit */
+ if (prev_nalu_start && prev_nalu_type == GSTOMX_H264_NUT_SPS) {
+ sps_size = idx - prev_nalu_start;
+
+ sps_data = gst_buffer_new_and_alloc (sps_size + GSTOMX_H264_C_DCI_LEN);
+ if (!sps_data) {
+ GST_ERROR_OBJECT (self, "failed to allocate memory..");
+ bret = FALSE;
+ goto exit;
+ }
+
+ GSTOMX_H264_WB16(GST_BUFFER_DATA(sps_data), sps_size);
+ memcpy (GST_BUFFER_DATA(sps_data) + GSTOMX_H264_C_DCI_LEN, nalu_dci + prev_nalu_start, sps_size);
+ g_queue_push_tail (sps_queue, sps_data);
+
+ } else if (prev_nalu_start && prev_nalu_type == GSTOMX_H264_NUT_PPS) {
+ pps_size = idx - prev_nalu_start;
+
+ pps_data = gst_buffer_new_and_alloc (pps_size + GSTOMX_H264_C_DCI_LEN);
+ if (!pps_data) {
+ GST_ERROR_OBJECT (self, "failed to allocate memory..");
+ bret = FALSE;
+ goto exit;
+ }
+
+ GSTOMX_H264_WB16(GST_BUFFER_DATA(pps_data), pps_size);
+ memcpy (GST_BUFFER_DATA(pps_data) + GSTOMX_H264_C_DCI_LEN, nalu_dci + prev_nalu_start, pps_size);
+ g_queue_push_tail (pps_queue, pps_data);
+ }
+
+ /* make packetized codec data */
+ if (sps_cnt == 1 && pps_cnt == 1) {
+ single_sps_pps = TRUE;
+ *packetized_dci = gst_buffer_new_and_alloc(GSTOMX_H264_MDATA + GSTOMX_H264_C_DCI_LEN + sps_size + GSTOMX_H264_CNT_LEN + GSTOMX_H264_C_DCI_LEN + pps_size);
+ GST_LOG_OBJECT(self, "allocate packetized_dci in case of single sps, pps. (size=%d)", GST_BUFFER_SIZE(*packetized_dci));
+ } else {
+ *packetized_dci = gst_buffer_new_and_alloc(GSTOMX_H264_MDATA);
+ GST_LOG_OBJECT(self, "allocate packetized_dci in case of multi sps, pps");
+ }
+
+ if (*packetized_dci == NULL) {
+ GST_ERROR_OBJECT (self, "Failed to allocate memory..");
+ bret = FALSE;
+ goto exit;
+ }
+
+ packet_dci = GST_BUFFER_DATA(*packetized_dci);
+ packet_dci[0] = 0x01; /* configurationVersion */
+ packet_dci[1] = profile; /* AVCProfileIndication */
+ packet_dci[2] = profile_comp; /* profile_compatibility*/
+ packet_dci[3] = level; /* AVCLevelIndication */
+ packet_dci[4] = 0xff; /* Reserver (6bits.111111) + LengthSizeMinusOne (2bits). lengthoflength = 4 for present */
+ packet_dci[5] = 0xe0 | sps_cnt; /* Reserver (3bits. 111) + numOfSequenceParameterSets (5bits) */
+
+ /* copy SPS sets */
+ while (!g_queue_is_empty (sps_queue)) {
+ sps_data = g_queue_pop_head (sps_queue);
+
+ if (TRUE == single_sps_pps) {
+ memcpy(packet_dci + GSTOMX_H264_MDATA, GST_BUFFER_DATA(sps_data), GST_BUFFER_SIZE(sps_data));
+ gst_buffer_unref(sps_data);
+ sps_data = NULL;
+ } else {
+ *packetized_dci = gst_buffer_join(*packetized_dci, sps_data);
+ }
+ }
+
+ /* add number of PPS sets (1byte)*/
+ if (TRUE == single_sps_pps) {
+ packet_dci[GSTOMX_H264_MDATA + GSTOMX_H264_C_DCI_LEN + sps_size] = pps_cnt;
+ } else {
+ GstBuffer *next_data = gst_buffer_new_and_alloc(GSTOMX_H264_CNT_LEN);
+ if (!next_data) {
+ GST_ERROR_OBJECT (self, "Failed to allocate memory..");
+ bret = FALSE;
+ goto exit;
+ }
+ GST_BUFFER_DATA(next_data)[0] = pps_cnt;
+ *packetized_dci = gst_buffer_join(*packetized_dci, next_data);
+ }
+
+ /* copy PPS sets */
+ while (!g_queue_is_empty (pps_queue)) {
+ pps_data = g_queue_pop_head (pps_queue);
+
+ if (TRUE == single_sps_pps) {
+ memcpy(packet_dci + GSTOMX_H264_MDATA + GSTOMX_H264_C_DCI_LEN + sps_size + GSTOMX_H264_CNT_LEN,
+ GST_BUFFER_DATA(pps_data), GST_BUFFER_SIZE(pps_data));
+ gst_buffer_unref(pps_data);
+ pps_data = NULL;
+ } else {
+ *packetized_dci = gst_buffer_join(*packetized_dci, pps_data);
+ }
+ }
+
+exit:
+ while (!g_queue_is_empty (sps_queue)) {
+ queue_data = g_queue_pop_head (sps_queue);
+ gst_buffer_unref (queue_data);
+ queue_data = NULL;
+ }
+ g_queue_free (sps_queue);
+
+ while (!g_queue_is_empty (pps_queue)) {
+ queue_data = g_queue_pop_head (pps_queue);
+ gst_buffer_unref (queue_data);
+ queue_data = NULL;
+ }
+ g_queue_free (pps_queue);
+
+ *out_sps_cnt = sps_cnt;
+ *out_pps_cnt = sps_cnt;
+
+ return bret;
+}
+
+/*
+ * description : resotre packtized dci (codec_data)
+ * params : @self : GstOmxH264Enc, @inbuf: codec data, @outbuf: h264enc->dci
+ * return : none
+ * comments :
+ * from original packetized codec_data: METADATA(6) + SPS_CNT(0) + {SPS_SIZE(2)+SPS_DATA(sps_size)}*n +
+ PPS_CNT(1) + {PPS_SIZE(2)+PPS_DATA(pps_size)}*n
+ * to estore packetized dci: {SPS_SIZE(4)+SPS_DATA(sps_size)}*n + {PPS_SIZE(4)+PPS_DATA(pps_size)}*n
+ */
+static gboolean
+restore_packetized_dci (GstOmxH264Enc *self, GstBuffer *inbuf, GstBuffer **outbuf, gint sps_cnt, gint pps_cnt)
+{
+ unsigned char *indata = GST_BUFFER_DATA(inbuf);
+ guint sps_size =0;
+ guint pps_size =0;
+ gint i = 0;
+ GstBuffer *next_data = NULL;
+
+ GST_INFO_OBJECT (self, "restore_packetized_dci. sps_cnt=%d, pps_cnt=%d", sps_cnt, pps_cnt);
+
+ if (sps_cnt == 1 && pps_cnt == 1) {
+ sps_size = GSTOMX_H264_RB16(indata + GSTOMX_H264_MDATA);
+ pps_size = GSTOMX_H264_RB16(indata + GSTOMX_H264_MDATA + GSTOMX_H264_C_DCI_LEN + sps_size + GSTOMX_H264_CNT_LEN);
+
+ *outbuf = gst_buffer_new_and_alloc (GSTOMX_H264_A_DCI_LEN + sps_size + GSTOMX_H264_A_DCI_LEN + pps_size);
+ if (!*outbuf) {
+ GST_ERROR_OBJECT (self, "Failed to allocate memory in gst_buffer_new_and_alloc.");
+ goto error_exit;
+ }
+
+ GSTOMX_H264_WB32(GST_BUFFER_DATA(*outbuf), sps_size);
+ indata += GSTOMX_H264_MDATA + GSTOMX_H264_C_DCI_LEN;
+ memcpy (GST_BUFFER_DATA(*outbuf) + GSTOMX_H264_A_DCI_LEN, indata, sps_size);
+ indata += sps_size;
+
+ GSTOMX_H264_WB32(GST_BUFFER_DATA(*outbuf) + GSTOMX_H264_A_DCI_LEN + sps_size, pps_size);
+ indata += GSTOMX_H264_CNT_LEN + GSTOMX_H264_C_DCI_LEN;
+ memcpy (GST_BUFFER_DATA(*outbuf) + GSTOMX_H264_A_DCI_LEN + sps_size + GSTOMX_H264_A_DCI_LEN, indata, pps_size);
+ indata += pps_size;
+ } else {
+ /* in this case, dci has multi nalu. ex) sps + sps + sps + pps + pps */
+ indata += GSTOMX_H264_MDATA;
+ *outbuf = gst_buffer_new ();
+
+ for (i = 0; i < sps_cnt; i++) {
+ sps_size = GSTOMX_H264_RB16(indata); /* metadata(6) */
+
+ next_data = gst_buffer_new_and_alloc(GSTOMX_H264_A_DCI_LEN + sps_size);
+ if (!next_data) {
+ GST_ERROR_OBJECT (self, "Failed to allocate memory in gst_buffer_new_and_alloc.");
+ goto error_exit;
+ }
+ GSTOMX_H264_WB32(GST_BUFFER_DATA(next_data), sps_size);
+ indata += GSTOMX_H264_C_DCI_LEN; /* sps size field (2 byte) */
+ memcpy (GST_BUFFER_DATA(next_data) + GSTOMX_H264_A_DCI_LEN, indata, sps_size);
+
+ *outbuf = gst_buffer_join(*outbuf, next_data);
+ indata += sps_size;
+ }
+ indata += GSTOMX_H264_CNT_LEN; /* pps cnt field (1 byte) */
+
+ for (i = 0; i < pps_cnt; i++) {
+ pps_size = GSTOMX_H264_RB16(indata);
+
+ next_data = gst_buffer_new_and_alloc(GSTOMX_H264_A_DCI_LEN + pps_size);
+ if (!next_data) {
+ GST_ERROR_OBJECT (self, "Failed to allocate memory in gst_buffer_new_and_alloc.");
+ goto error_exit;
+ }
+ GSTOMX_H264_WB32(GST_BUFFER_DATA(next_data), pps_size);
+ indata += GSTOMX_H264_C_DCI_LEN;
+ memcpy (GST_BUFFER_DATA(next_data) + GSTOMX_H264_A_DCI_LEN, indata, pps_size);
+
+ *outbuf = gst_buffer_join(*outbuf, next_data);
+ indata += pps_size;
+ }
+ }
+
+ return TRUE;
+
+error_exit:
+ if (*outbuf) {
+ gst_buffer_unref(*outbuf);
+ *outbuf = NULL;
+ }
+ return FALSE;
+}
+
+/*
+ * description : set sync frame. if needed, convert output to packetized format, append dci every I frame.
+ * params : @self : GstOmxBaseFilter, @buf: encoder output frame, @omx_buffer: omx_buffer
+ * return : none
+ * comments :
+ */
+static GstOmxReturn
+process_output_buf(GstOmxBaseFilter * omx_base, GstBuffer **buf, OMX_BUFFERHEADERTYPE *omx_buffer)
+{
+ GstOmxH264Enc *self;
+ self = GST_OMX_H264ENC (omx_base);
+
+ if (!self->byte_stream) { /* Packtized Format */
+ convert_to_packetized_frame (self, buf); /* convert byte stream to packetized stream */
+ GST_LOG_OBJECT (self, "output buffer is converted to Packtized format.");
+ } else {
+ GST_LOG_OBJECT (self, "output buffer is Byte-stream format.");
+ }
+
+ if ((self->first_frame) ||(self->append_dci && omx_buffer->nFlags & OMX_BUFFERFLAG_SYNCFRAME)) {
+ GstBuffer *newbuf = NULL;
+ GST_LOG_OBJECT (self, "append dci at %s by gst-openmax.", (self->first_frame == TRUE) ? "first frame": "every I frame");
+
+ if (self->dci == NULL) {
+ GST_ERROR_OBJECT (self, "dci is null. can not append dci.");
+ self->append_dci = FALSE;
+ } else {
+ newbuf = gst_buffer_merge (self->dci, *buf);
+ if (newbuf == NULL) {
+ GST_ERROR_OBJECT (self, "Failed to gst_buffer_merge.");
+ return GSTOMX_RETURN_ERROR;
+ }
+ gst_buffer_copy_metadata(newbuf, *buf, GST_BUFFER_COPY_ALL);
+ gst_buffer_unref(*buf);
+ *buf = newbuf;
+ }
+ }
+
+ if (self->first_frame == TRUE)
+ self->first_frame = FALSE;
+
+ /* Set sync frame info while encoding */
+ if (omx_buffer->nFlags & OMX_BUFFERFLAG_SYNCFRAME) {
+ GST_BUFFER_FLAG_UNSET(*buf, GST_BUFFER_FLAG_DELTA_UNIT);
+ } else {
+ GST_BUFFER_FLAG_SET(*buf, GST_BUFFER_FLAG_DELTA_UNIT);
+ }
+
+ return GSTOMX_RETURN_OK;
+}
+
+/*
+ * description : if needed, convert byte-stream codec_data to packetized format, save dci.
+ * params : @self : GstOmxBaseFilter, @omx_buffer: omx_buffer
+ * return : none
+ * comments :
+ */
+static void
+process_output_caps(GstOmxBaseFilter * base, OMX_BUFFERHEADERTYPE *omx_buffer)
+{
+ GstOmxH264Enc *h264enc;
+ gboolean ret = FALSE;
+
+ h264enc = GST_OMX_H264ENC (base);
+
+ if (!h264enc->byte_stream) { /* Packtized Format */
+ GstCaps *caps = NULL;
+ GstStructure *structure;
+ GstBuffer *codec_data = NULL;
+ gint sps_cnt = 0;
+ gint pps_cnt = 0;
+ GValue value = { 0, {{0}
+ }
+ };
+ g_value_init (&value, GST_TYPE_BUFFER);
+
+ GST_INFO_OBJECT (h264enc, "Packtized Format: set src caps with codec-data");
+
+ /* convert codec_data to packtized format.. (metadata(cnt) + sps_size + sps + cnt + pps_size + pps) */
+ ret = convert_to_packetized_dci (h264enc, omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen,
+ &codec_data, &sps_cnt, &pps_cnt);
+
+ if (FALSE == ret) {
+ GST_ERROR_OBJECT (h264enc, "ERROR: convert to packetized dci");
+ if (codec_data) {
+ gst_buffer_unref(codec_data);
+ codec_data = NULL;
+ }
+ return;
+ }
+
+ /* restore packtized format sps, pps */
+ ret = restore_packetized_dci (h264enc, codec_data, &h264enc->dci, sps_cnt, pps_cnt);
+ if (ret == FALSE) {
+ GST_ERROR_OBJECT (h264enc, "ERROR: restore packetized dci");
+ return;
+ }
+
+ GST_DEBUG_OBJECT (h264enc, "adding codec_data in caps");
+ caps = gst_pad_get_negotiated_caps (base->srcpad);
+ caps = gst_caps_make_writable (caps);
+ structure = gst_caps_get_structure (caps, 0);
+
+ /* packetized format, set codec_data field in caps */
+ gst_value_set_buffer (&value,codec_data);
+ gst_buffer_unref (codec_data);
+ codec_data = NULL;
+ gst_structure_set_value (structure, "codec_data", &value);
+ g_value_unset (&value);
+
+ gst_pad_set_caps (base->srcpad, caps);
+ gst_caps_unref (caps);
+ } else {
+ /* byte-stream format */
+ GST_INFO_OBJECT (h264enc, "Byte-stream Format");
+ h264enc->dci = gst_buffer_new_and_alloc (omx_buffer->nFilledLen);
+ if (!h264enc->dci) {
+ GST_ERROR_OBJECT (h264enc, "failed to allocate memory...");
+ return;
+ }
+ memcpy (GST_BUFFER_DATA (h264enc->dci),
+ omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
+ }
+}
+
+static void
+finalize (GObject * obj)
+{
+ GstOmxH264Enc *h264enc;
+ h264enc = GST_OMX_H264ENC (obj);
+
+ GST_LOG_OBJECT (h264enc, "h264enc finalize enter");
+
+ if (h264enc->dci) {
+ gst_buffer_unref(h264enc->dci);
+ h264enc->dci = NULL;
+ }
+ G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
static void
type_base_init (gpointer g_class)
{
}
static void
+set_property (GObject * obj,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstOmxH264Enc *self;
+ GstOmxBaseFilter *omx_base;
+
+ self = GST_OMX_H264ENC (obj);
+ omx_base = GST_OMX_BASE_FILTER (obj);
+
+ switch (prop_id) {
+ case ARG_APPEND_DCI:
+ self->append_dci = g_value_get_boolean (value);
+ GST_INFO_OBJECT (self, "set Appending dci = %d", self->append_dci);
+ break;
+
+ case ARG_BYTE_STREAM:
+ self->byte_stream = g_value_get_boolean (value);
+ GST_INFO_OBJECT (self, "set Byte stream = %d", self->byte_stream);
+ break;
+
+ case ARG_SLICE_MODE:
+ {
+ OMX_VIDEO_PARAM_AVCSLICEFMO param;
+ OMX_ERRORTYPE ret;
+
+ self->slice_fmo.eSliceMode = g_value_get_uint (value);
+
+ G_OMX_INIT_PARAM (param);
+ param.nPortIndex = omx_base->out_port->port_index;
+ OMX_GetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoSliceFMO, ¶m);
+
+ param.eSliceMode = self->slice_fmo.eSliceMode;
+ param.nNumSliceGroups = 1;
+ param.nSliceGroupMapType = 1;
+ ret = OMX_SetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoSliceFMO, ¶m);
+ if (ret != OMX_ErrorNone)
+ GST_ERROR_OBJECT (self, "failed to set eSliceMode = %d", self->slice_fmo.eSliceMode);
+ else
+ GST_INFO_OBJECT (self, "set eSliceMode = %d", self->slice_fmo.eSliceMode);
+ }
+ break;
+
+ case ARG_SLICE_SIZE:
+ {
+ OMX_VIDEO_PARAM_AVCTYPE param;
+ OMX_ERRORTYPE ret;
+
+ self->h264type.nSliceHeaderSpacing = g_value_get_uint (value);
+
+ G_OMX_INIT_PARAM (param);
+ param.nPortIndex = omx_base->out_port->port_index;
+ OMX_GetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoAvc, ¶m);
+
+ param.nSliceHeaderSpacing = self->h264type.nSliceHeaderSpacing;
+ ret= OMX_SetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoAvc, ¶m);
+ if (ret != OMX_ErrorNone)
+ GST_ERROR_OBJECT (self, "failed to set nSliceHeaderSpacing = %d", self->h264type.nSliceHeaderSpacing);
+ else
+ GST_INFO_OBJECT (self, "nSliceHeaderSpacing = %d", self->h264type.nSliceHeaderSpacing);
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ GstOmxH264Enc *self;
+
+ self = GST_OMX_H264ENC (obj);
+
+ switch (prop_id) {
+ case ARG_APPEND_DCI:
+ g_value_set_boolean (value, self->append_dci);
+ break;
+ case ARG_BYTE_STREAM:
+ g_value_set_boolean (value, self->byte_stream);
+ break;
+ case ARG_SLICE_MODE:
+ g_value_set_int (value, self->slice_fmo.eSliceMode);
+ break;
+ case ARG_SLICE_SIZE:
+ g_value_set_uint (value, self->h264type.nSliceHeaderSpacing);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
type_class_init (gpointer g_class, gpointer class_data)
{
+ GObjectClass *gobject_class;
+ GstOmxBaseFilterClass *basefilter_class;
+
+ gobject_class = G_OBJECT_CLASS (g_class);
+ basefilter_class = GST_OMX_BASE_FILTER_CLASS (g_class);
+
+ {
+ gobject_class->set_property = set_property;
+ gobject_class->get_property = get_property;
+
+ g_object_class_install_property (gobject_class, ARG_APPEND_DCI,
+ g_param_spec_boolean ("append-dci", "append codec_data with every key frame for byte-stream format",
+ "append codec_data with every key frame for byte-stream format",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class, ARG_BYTE_STREAM,
+ g_param_spec_boolean ("byte-stream", "Output stream format",
+ "output stream format whether byte-stream format (TRUE) or packetized (FALSE)",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class, ARG_SLICE_MODE,
+ g_param_spec_int ("slice-mode", "H264 encoder slice mode",
+ "slice mode: 0-Disable, 1-Fixed MB num slice, 2-Fixed bit num slice",
+ 0, 4, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class, ARG_SLICE_SIZE,
+ g_param_spec_uint ("slice-size", "H264 encoder slice size",
+ "MB or bit num: MB number:1 ~ (MBCnt-1), Bit number: 1900 (bit) ~",
+ 0, G_MAXUINT, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ }
+
+ basefilter_class->process_output_buf = process_output_buf;
+ basefilter_class->process_output_caps = process_output_caps;
+
+ gobject_class->finalize = finalize;
+
}
static void
{
GstOmxBaseVideoEnc *omx_base;
GstOmxBaseFilter *omx_base_filter;
+ GstOmxH264Enc *self;
+
guint width;
guint height;
omx_base_filter = core->object;
omx_base = GST_OMX_BASE_VIDEOENC (omx_base_filter);
+ self = GST_OMX_H264ENC (omx_base_filter);
GST_DEBUG_OBJECT (omx_base, "settings changed");
}
{
- GstCaps *new_caps;
+ GstCaps *new_caps, *peer_caps;
+ gchar *format ;
+ int i =0;
new_caps = gst_caps_new_simple ("video/x-h264",
"width", G_TYPE_INT, width,
"framerate", GST_TYPE_FRACTION,
omx_base->framerate_num, omx_base->framerate_denom, NULL);
+ /* get peer pad caps */
+ peer_caps = gst_pad_peer_get_caps(omx_base_filter->srcpad);
+ if (peer_caps) {
+ GST_LOG_OBJECT (omx_base, "peer caps : %s\n", gst_caps_to_string(peer_caps));
+
+ for (i = 0; i < peer_caps->structs->len; i++) {
+ GstStructure *s;
+ s = gst_caps_get_structure (peer_caps, i);
+
+ if (g_strrstr (gst_structure_get_name (s), "video/x-h264")) {
+ if (!gst_structure_get (s, "stream-format", G_TYPE_STRING, &format, NULL)) {
+ GST_WARNING_OBJECT (self, "Failed to get stream-format from peer caps...");
+ } else {
+ GST_INFO_OBJECT (self, "format : %s", format);
+ gst_caps_set_simple (new_caps, "stream-format", G_TYPE_STRING, format, NULL);
+ if (g_strrstr(format, "byte-stream")) {
+ GST_INFO_OBJECT (self, "Mandatory BYTE_STREAM");
+ self->byte_stream = TRUE;
+ } else if (g_strrstr(format, "avc")){
+ GST_INFO_OBJECT (self, "Mandatory PACKETIZED");
+ self->byte_stream = FALSE;
+ } else {
+ GST_INFO_OBJECT (self, "Nothing mentioned about stream-format... use byte_stream property to decide");
+ if (self->byte_stream) {
+ GST_INFO_OBJECT (self, "Is in BYTE_STREAM");
+ } else {
+ GST_INFO_OBJECT (self, "Is in PACKETIZED");
+ }
+ }
+ }
+ }
+ }
+ }
+
GST_INFO_OBJECT (omx_base, "caps are: %" GST_PTR_FORMAT, new_caps);
gst_pad_set_caps (omx_base_filter->srcpad, new_caps);
}
{
GstOmxBaseFilter *omx_base_filter;
GstOmxBaseVideoEnc *omx_base;
+ GstOmxH264Enc *self;
omx_base_filter = GST_OMX_BASE_FILTER (instance);
omx_base = GST_OMX_BASE_VIDEOENC (instance);
+ self = GST_OMX_H264ENC (instance);
+
+ self->byte_stream = FALSE;
+ self->append_dci = FALSE;
+ self->first_frame = TRUE;
+ self->dci = NULL;
+ self->slice_fmo.eSliceMode = OMX_VIDEO_SLICEMODE_AVCLevelMax;
omx_base->compression_format = OMX_VIDEO_CodingAVC;
typedef struct GstOmxH264EncClass GstOmxH264EncClass;
#include "gstomx_base_videoenc.h"
+#include "gstomx_h264.h"
struct GstOmxH264Enc
{
GstOmxBaseVideoEnc omx_base;
+ gboolean byte_stream;
+
+ GstBuffer *dci;
+ gboolean append_dci;
+ gboolean first_frame;
+
+ OMX_VIDEO_PARAM_AVCTYPE h264type;
+ OMX_VIDEO_PARAM_AVCSLICEFMO slice_fmo;
};
struct GstOmxH264EncClass
GSTOMX_BOILERPLATE (GstOmxMpeg4Dec, gst_omx_mpeg4dec, GstOmxBaseVideoDec,
GST_OMX_BASE_VIDEODEC_TYPE);
+static gboolean init_divx_symbol (GstOmxMpeg4Dec * self)
+{
+ GST_LOG_OBJECT (self, "mpeg4dec load_divx_symbol enter");
+
+ self->divx_handle = dlopen (DIVX_SDK_PLUGIN_NAME, RTLD_LAZY);
+ if (!self->divx_handle) {
+ GST_ERROR_OBJECT (self, "dlopen failed [%s]", dlerror());
+ goto error_exit;
+ }
+
+ self->divx_sym_table.init_decrypt = dlsym (self->divx_handle, "divx_init_decrypt");
+ if (!self->divx_sym_table.init_decrypt) {
+ GST_ERROR_OBJECT (self, "loading divx_init_decrypt failed : %s", dlerror());
+ goto error_exit;
+ }
+ self->divx_sym_table.commit = dlsym (self->divx_handle, "divx_commit");
+ if (!self->divx_sym_table.commit) {
+ GST_ERROR_OBJECT (self, "loading divx_commit failed : %s", dlerror());
+ goto error_exit;
+ }
+ self->divx_sym_table.decrypt_video = dlsym (self->divx_handle, "divx_decrypt_video");
+ if (!self->divx_sym_table.decrypt_video) {
+ GST_ERROR_OBJECT (self, "loading divx_decrypt_video failed : %s", dlerror());
+ goto error_exit;
+ }
+ self->divx_sym_table.prepare_video_bitstream = dlsym (self->divx_handle, "divx_prepare_video_bitstream");
+ if (!self->divx_sym_table.prepare_video_bitstream) {
+ GST_ERROR_OBJECT (self, "loading divx_prepare_video_bitstream failed : %s", dlerror());
+ goto error_exit;
+ }
+ self->divx_sym_table.finalize = dlsym (self->divx_handle, "divx_finalize");
+ if (!self->divx_sym_table.finalize) {
+ GST_ERROR_OBJECT (self, "loading divx_finalize failed : %s", dlerror());
+ goto error_exit;
+ }
+
+ return TRUE;
+
+error_exit:
+
+ if (self->divx_handle) {
+ dlclose(self->divx_handle);
+ self->divx_handle = NULL;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+init_divx_drm (GstOmxMpeg4Dec * self)
+{
+ int error = 0;
+
+ GST_LOG_OBJECT (self, "mpeg4dec init_divx_drm enter");
+
+ if (init_divx_symbol(self) == FALSE) {
+ GST_ERROR_OBJECT (self, "loading symbol failed....");
+ goto error_exit;
+ }
+
+ self->drmContext = self->divx_sym_table.init_decrypt (&error);
+
+ if (self->drmContext) {
+ GST_DEBUG_OBJECT (self, "%s init success: drmContext = %p\n", __func__, self->drmContext);
+ } else {
+ GST_ERROR_OBJECT (self, "%s failed to init... error code = %d \n", __func__, error);
+ goto error_exit;
+ }
+
+ error = self->divx_sym_table.commit (self->drmContext);
+
+ if (error == DRM_SUCCESS) {
+ GST_DEBUG_OBJECT (self, "%s commit success: drmContext = %p\n", __func__, self->drmContext);
+ } else {
+ GST_ERROR_OBJECT (self, "%s failed to commit... error code = %d \n", __func__, error);
+ goto error_exit;
+ }
+
+ return TRUE;
+
+error_exit:
+
+ if (self->drmContext)
+ {
+ self->divx_sym_table.finalize (self->drmContext);
+ free(self->drmContext);
+ self->drmContext = NULL;
+ }
+
+ return FALSE;
+}
+
+static GstOmxReturn
+process_input_buf (GstOmxBaseFilter * omx_base_filter, GstBuffer **buf)
+{
+ GstOmxMpeg4Dec *self;
+
+ self = GST_OMX_MPEG4DEC (omx_base_filter);
+
+ GST_LOG_OBJECT (self, "mpeg4dec process_input_buf enter");
+
+ /* decrypt DivX DRM buffer if this is DRM */
+ if (self->drmContext) {
+ if (DRM_SUCCESS == self->divx_sym_table.decrypt_video (self->drmContext, GST_BUFFER_DATA(*buf), GST_BUFFER_SIZE(*buf))) {
+ GST_DEBUG_OBJECT (self, "##### DivX DRM Mode ##### decrypt video success : buffer = %d", GST_BUFFER_SIZE(*buf));
+ } else {
+ GST_ERROR_OBJECT (self, "##### DivX DRM Mode ##### decrypt video failed : buffer = %d", GST_BUFFER_SIZE(*buf));
+ }
+ }
+
+/* if you want to use commonly for videodec input, use this */
+/* GST_OMX_BASE_FILTER_CLASS (parent_class)->process_input_buf (omx_base_filter, buf); */
+
+ return GSTOMX_RETURN_OK;
+}
+
+static void
+print_tag (const GstTagList * list, const gchar * tag, gpointer data)
+{
+ gint i, count;
+ GstOmxMpeg4Dec *self;
+
+ self = GST_OMX_MPEG4DEC (data);
+
+ count = gst_tag_list_get_tag_size (list, tag);
+
+ for (i = 0; i < count; i++) {
+ gchar *str;
+
+ if (gst_tag_get_type (tag) == G_TYPE_STRING) {
+ if (!gst_tag_list_get_string_index (list, tag, i, &str))
+ g_assert_not_reached ();
+ } else if (gst_tag_get_type (tag) == GST_TYPE_BUFFER) {
+ GstBuffer *img;
+
+ img = gst_value_get_buffer (gst_tag_list_get_value_index (list, tag, i));
+ if (img) {
+ gchar *caps_str;
+
+ caps_str = GST_BUFFER_CAPS (img) ?
+ gst_caps_to_string (GST_BUFFER_CAPS (img)) : g_strdup ("unknown");
+ str = g_strdup_printf ("buffer of %u bytes, type: %s",
+ GST_BUFFER_SIZE (img), caps_str);
+ g_free (caps_str);
+ } else {
+ str = g_strdup ("NULL buffer");
+ }
+ } else {
+ str = g_strdup_value_contents (gst_tag_list_get_value_index (list, tag, i));
+ }
+
+ if (i == 0) {
+ GST_LOG_OBJECT(self, "%16s: %s", gst_tag_get_nick (tag), str);
+
+ if (strcmp (gst_tag_get_nick(tag), "DRM DivX") == 0) {
+ if (self->drmContext == NULL) {
+ GST_LOG_OBJECT(self, "Init divx drm !!!!!!!!!!!!!!!!!!!! [%s]", str);
+ if (init_divx_drm (self)) {
+ GST_LOG_OBJECT(self, "omx_printtag_init_divx_drm() success");
+ } else {
+ GST_ERROR_OBJECT(self, "omx_printtag_init_divx_drm() failed");
+ }
+ } else {
+ GST_LOG_OBJECT(self, "Init divx drm is DONE before. so do nothing [%s]", str);
+ }
+ }
+ } else {
+ GST_LOG_OBJECT(self, "tag is not DRM Divx");
+ }
+
+ g_free (str);
+ }
+
+ GST_LOG_OBJECT(self, "print_tag End");
+}
+
+static gboolean
+mpeg4_pad_event (GstPad * pad, GstEvent * event)
+{
+ GstOmxMpeg4Dec *self;
+ gboolean ret = TRUE;
+
+ self = GST_OMX_MPEG4DEC (GST_OBJECT_PARENT (pad));
+
+ GST_LOG_OBJECT (self, "begin");
+
+ GST_INFO_OBJECT (self, "event: %s", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_TAG:
+ {
+ GstTagList *taglist = NULL;
+
+ GST_LOG_OBJECT (self, "GST_EVENT_TAG");
+
+ gst_event_parse_tag (event, &taglist);
+ gst_tag_list_foreach (taglist, print_tag, self);
+ gst_event_unref (event);
+ ret= FALSE;
+ break;
+ }
+ default:
+ ret = TRUE;
+ break;
+ }
+ return ret;
+}
+
+static void
+finalize (GObject * obj)
+{
+ GstOmxMpeg4Dec *self;
+
+ self = GST_OMX_MPEG4DEC (obj);
+
+ GST_LOG_OBJECT (self, "mpeg4dec finalize enter");
+
+ if (self->drmContext)
+ {
+ self->divx_sym_table.finalize (self->drmContext);
+ free(self->drmContext);
+ self->drmContext = NULL;
+ }
+
+ if (self->divx_handle)
+ {
+ dlclose(self->divx_handle);
+ self->divx_handle = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
static void
type_base_init (gpointer g_class)
{
static void
type_class_init (gpointer g_class, gpointer class_data)
{
+ GObjectClass *gobject_class;
+ GstOmxBaseFilterClass *basefilter_class;
+
+ gobject_class = G_OBJECT_CLASS (g_class);
+ basefilter_class = GST_OMX_BASE_FILTER_CLASS (g_class);
+
+ gobject_class->finalize = finalize;
+ basefilter_class->process_input_buf = process_input_buf;
}
static void
type_instance_init (GTypeInstance * instance, gpointer g_class)
{
GstOmxBaseVideoDec *omx_base;
+ GstOmxBaseFilter *omx_base_filter;
omx_base = GST_OMX_BASE_VIDEODEC (instance);
+ omx_base_filter = GST_OMX_BASE_FILTER (instance);
+ omx_base_filter->pad_event = mpeg4_pad_event;
omx_base->compression_format = OMX_VIDEO_CodingMPEG4;
}
#define GSTOMX_MPEG4DEC_H
#include <gst/gst.h>
+#include <stdint.h>
+#include <dlfcn.h>
+#include <stdlib.h>
G_BEGIN_DECLS
#define GST_OMX_MPEG4DEC(obj) (GstOmxMpeg4Dec *) (obj)
#define GST_OMX_MPEG4DEC_TYPE (gst_omx_mpeg4dec_get_type ())
+typedef struct DivXSymbolTable DivXSymbolTable;
typedef struct GstOmxMpeg4Dec GstOmxMpeg4Dec;
typedef struct GstOmxMpeg4DecClass GstOmxMpeg4DecClass;
#include "gstomx_base_videodec.h"
+#define DIVX_SDK_PLUGIN_NAME "libmm_divxsdk.so"
+
+typedef enum drmErrorCodes
+{
+ DRM_SUCCESS = 0,
+ DRM_NOT_AUTHORIZED,
+ DRM_NOT_REGISTERED,
+ DRM_RENTAL_EXPIRED,
+ DRM_GENERAL_ERROR,
+ DRM_NEVER_REGISTERED,
+} drmErrorCodes_t;
+
+struct DivXSymbolTable
+{
+ uint8_t* (*init_decrypt) (int*);
+ int (*commit) (uint8_t *);
+ int (*decrypt_video) (uint8_t *, uint8_t *, uint32_t);
+ int (*prepare_video_bitstream) (uint8_t *, uint8_t * , uint32_t , uint8_t * , uint32_t * );
+ int (*finalize) (uint8_t *);
+};
+
struct GstOmxMpeg4Dec
{
GstOmxBaseVideoDec omx_base;
+ uint8_t* drmContext;
+ void *divx_handle;
+ DivXSymbolTable divx_sym_table;
};
struct GstOmxMpeg4DecClass
g_ptr_array_free (core->ports, TRUE);
g_free (core);
+ core = NULL;
}
void
G_OMX_INIT_PARAM (param);
strncpy ((char *) param.cRole, core->component_role,
- OMX_MAX_STRINGNAME_SIZE);
+ OMX_MAX_STRINGNAME_SIZE - 1);
OMX_SetParameter (core->omx_handle, OMX_IndexParamStandardComponentRole,
¶m);
}
- /* Add_component_vendor */
+ /* MODIFICATION: Add_component_vendor */
if (strncmp(core->component_name+4, "SEC", 3) == 0)
{
core->component_vendor = GOMX_VENDOR_SLSI;
}
+ else if (strncmp(core->component_name+4, "qcom", 4) == 0)
+ {
+ core->component_vendor = GOMX_VENDOR_QCT;
+ }
else
{
core->component_vendor = GOMX_VENDOR_DEFAULT;
g_free (core->library_name);
g_free (core->component_name);
g_free (core->component_role);
+ core->library_name = NULL;
+ core->component_name = NULL;
+ core->component_role = NULL;
release_imp (core->imp);
core->imp = NULL;
port->num_buffers = 0;
port->buffer_size = 0;
port->buffers = NULL;
+ port->shared_buffer = FALSE;
port->enabled = TRUE;
port->queue = async_queue_new ();
async_queue_free (port->queue);
g_free (port->buffers);
+ port->buffers = NULL;
g_free (port);
+ port = NULL;
}
void
{
guint i;
+ if (port->type == GOMX_PORT_INPUT) {
+ GST_INFO_OBJECT(port->core->object, "Input port free buffers.");
+ } else {
+ GST_INFO_OBJECT(port->core->object, "Output port free buffers.");
+ }
+
for (i = 0; i < port->num_buffers; i++) {
OMX_BUFFERHEADERTYPE *omx_buffer;
omx_buffer = port->buffers[i];
if (omx_buffer) {
-#if 0
- /** @todo how shall we free that buffer? */
- if (!port->omx_allocate) {
- g_free (omx_buffer->pBuffer);
- omx_buffer->pBuffer = NULL;
+
+ if (port->shared_buffer) {
+ /* Modification: free pAppPrivate when input/output buffer is shared */
+
+ if (!omx_buffer->pAppPrivate && port->type == GOMX_PORT_OUTPUT && omx_buffer->pBuffer) {
+ GST_INFO_OBJECT(port->core->object,
+ " %d: g_free shared buffer (pBuffer) %p", i, omx_buffer->pBuffer);
+ g_free (omx_buffer->pBuffer);
+ omx_buffer->pBuffer = NULL;
+ }
+
+ if (omx_buffer->pAppPrivate) {
+ GST_INFO_OBJECT(port->core->object,
+ " %d: unref shared buffer (pAppPrivate) %p", i, omx_buffer->pAppPrivate);
+ gst_buffer_unref(omx_buffer->pAppPrivate);
+ omx_buffer->pAppPrivate = NULL;
+ }
+
+ } else { /* this is not shared buffer */
+ if (!port->omx_allocate) {
+ /* Modification: free pBuffer allocated in plugin when OMX_UseBuffer.
+ * the component shall free only buffer header if it allocated only buffer header.*/
+ GST_INFO_OBJECT(port->core->object,
+ " %d: free buffer (pBuffer) %p", i, omx_buffer->pBuffer);
+ if (omx_buffer->pBuffer) {
+ g_free (omx_buffer->pBuffer);
+ omx_buffer->pBuffer = NULL;
+ }
+ }
}
-#endif
OMX_FreeBuffer (port->core->omx_handle, port->port_index, omx_buffer);
port->buffers[i] = NULL;
typedef struct GOmxImp GOmxImp;
typedef struct GOmxSymbolTable GOmxSymbolTable;
typedef enum GOmxPortType GOmxPortType;
+/* MODIFICATION: omx vender */
typedef enum GOmxVendor GOmxVendor;
typedef void (*GOmxCb) (GOmxCore * core);
enum GOmxVendor
{
GOMX_VENDOR_DEFAULT,
- GOMX_VENDOR_SLSI
+ GOMX_VENDOR_SLSI,
+ GOMX_VENDOR_QCT
};
/* Structures. */
gchar *library_name;
gchar *component_name;
gchar *component_role;
- GOmxVendor component_vendor; /* Add_component_vendor */
+ /* MODIFICATION: omx vender */
+ GOmxVendor component_vendor;
};
struct GOmxPort
gboolean enabled;
gboolean omx_allocate; /**< Setup with OMX_AllocateBuffer rather than OMX_UseBuffer */
AsyncQueue *queue;
+
+ gboolean shared_buffer; /* Modification */
};
/* Functions. */
-%define _optdir /opt
-%define _appdir %{_optdir}/apps
-
Name: gst-openmax
Summary: GStreamer plug-in that allows communication with OpenMAX IL components
Version: 0.10.1
-Release: 0
-Group: TO_BE/FILLED_IN
-License: TO BE FILLED IN
+Release: 4
+Group: Applications/Multimedia
+License: LGPLv2.1
Source0: %{name}-%{version}.tar.gz
BuildRequires: which
BuildRequires: pkgconfig(gstreamer-0.10)
%description
gst-openmax is a GStreamer plug-in that allows communication with OpenMAX IL components.
-Multiple OpenMAX IL implementations can be used, i
-including but not limited to Texas Instruments and Bellagio.
-
+Multiple OpenMAX IL implementations can be used.
%prep
%setup -q
%build
./autogen.sh --noconfigure
-%configure --disable-static --prefix=%{_prefix}
+%configure --disable-static --prefix=/usr
make %{?jobs:-j%jobs}
%make_install
%files
-%defattr(-,root,root,-)
+%manifest gst-openmax.manifest
%{_libdir}/gstreamer-0.10/libgstomx.so
g_cond_free (sem->condition);
g_mutex_free (sem->mutex);
g_free (sem);
+ sem = NULL;
}
void