Tizen 2.1 base
authorJinkun Jang <jinkun.jang@samsung.com>
Tue, 12 Mar 2013 16:49:08 +0000 (01:49 +0900)
committerJinkun Jang <jinkun.jang@samsung.com>
Tue, 12 Mar 2013 16:49:08 +0000 (01:49 +0900)
24 files changed:
debian/changelog
debian/control
gst-openmax.manifest [new file with mode: 0755]
omx/Makefile.am
omx/gstomx.c
omx/gstomx.h
omx/gstomx_base_audiodec.c
omx/gstomx_base_filter.c
omx/gstomx_base_filter.h
omx/gstomx_base_sink.c
omx/gstomx_base_videodec.c
omx/gstomx_base_videoenc.c
omx/gstomx_base_videoenc.h
omx/gstomx_h264.h [new file with mode: 0644]
omx/gstomx_h264dec.c
omx/gstomx_h264dec.h
omx/gstomx_h264enc.c
omx/gstomx_h264enc.h
omx/gstomx_mpeg4dec.c
omx/gstomx_mpeg4dec.h
omx/gstomx_util.c
omx/gstomx_util.h
packaging/gst-openmax.spec
util/sem.c

index 7e1d203..889145c 100755 (executable)
@@ -1,3 +1,11 @@
+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.
index cf010c6..006aad7 100755 (executable)
@@ -1,6 +1,6 @@
 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
diff --git a/gst-openmax.manifest b/gst-openmax.manifest
new file mode 100755 (executable)
index 0000000..a76fdba
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_" />
+       </request>
+</manifest>
index 915b562..423d8d6 100644 (file)
@@ -14,7 +14,7 @@ libgstomx_la_SOURCES = gstomx.c gstomx.h \
                       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 \
index 7172077..12019e4 100644 (file)
@@ -104,6 +104,7 @@ gst_omx_volume_get_type,};
 static gchar *
 get_config_path (void)
 {
+/* MODIFICATION */
 #if 1     /* Fix_config_path */
   return g_build_filename (OMX_CONFIG_DIRPATH, OMX_CONFIG_FILENAME, NULL);
 #else
@@ -242,7 +243,8 @@ plugin_init (GstPlugin * plugin)
     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;
 
@@ -252,7 +254,7 @@ plugin_init (GstPlugin * plugin)
     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) {
index 3babcfa..136616f 100644 (file)
@@ -29,7 +29,7 @@ GST_DEBUG_CATEGORY_EXTERN (gstomx_util_debug);
 #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
index 6f94b33..5d1cf5b 100644 (file)
 #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);
 
@@ -30,9 +36,64 @@ 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)
+{
+  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
index b8a4841..4bf8111 100644 (file)
@@ -25,7 +25,7 @@
 
 #include <string.h>             /* for memcpy */
 
-/* STATE_TUNING */
+/* MODIFICATION: for state-tuning */
 static void output_loop (gpointer data);
 
 enum
@@ -33,7 +33,6 @@ 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);
@@ -41,15 +40,15 @@ GSTOMX_BOILERPLATE_FULL (GstOmxBaseFilter, gst_omx_base_filter, GstElement,
     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);
 }
 
@@ -74,6 +73,8 @@ is_extended_color_format(GstOmxBaseFilter * self, GOmxPort * port)
     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;
@@ -96,22 +97,28 @@ setup_ports (GstOmxBaseFilter * self)
     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");
   }
@@ -119,7 +126,105 @@ setup_ports (GstOmxBaseFilter * self)
   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
@@ -140,49 +245,46 @@ change_state (GstElement * element, GstStateChange transition)
 
   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;
 
@@ -197,9 +299,9 @@ change_state (GstElement * element, GstStateChange transition)
 
   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);
 
@@ -215,6 +317,15 @@ change_state (GstElement * element, GstStateChange transition)
       }
       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;
   }
@@ -232,6 +343,12 @@ finalize (GObject * obj)
 
   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;
@@ -288,10 +405,6 @@ set_property (GObject * obj,
       OMX_SetParameter (omx_handle, OMX_IndexParamPortDefinition, &param);
     }
       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;
@@ -334,10 +447,6 @@ get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec)
       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;
@@ -382,24 +491,32 @@ type_class_init (gpointer g_class, gpointer class_data)
             "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;
 }
 
@@ -443,7 +560,7 @@ output_loop (gpointer data)
       goto leave;
     }
 
-    log_buffer (self, omx_buffer);
+    log_buffer (self, omx_buffer, "output_loop");
 
     if (G_LIKELY (omx_buffer->nFilledLen > 0)) {
       GstBuffer *buf;
@@ -473,31 +590,25 @@ output_loop (gpointer data)
             /** @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);
@@ -506,13 +617,22 @@ output_loop (gpointer data)
         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) {
@@ -521,8 +641,9 @@ output_loop (gpointer data)
               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) {
@@ -534,16 +655,8 @@ output_loop (gpointer data)
         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. */
@@ -562,7 +675,7 @@ output_loop (gpointer data)
                 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. */
@@ -572,14 +685,7 @@ output_loop (gpointer data)
             }
           }
 
-        /* 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);
@@ -589,7 +695,7 @@ output_loop (gpointer data)
       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;
@@ -600,7 +706,6 @@ output_loop (gpointer data)
           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);
@@ -612,7 +717,7 @@ output_loop (gpointer data)
       }
     }
 
-    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");
     }
 
@@ -651,83 +756,88 @@ pad_chain (GstPad * pad, GstBuffer * buf)
   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 ||
@@ -742,60 +852,68 @@ pad_chain (GstPad * pad, GstBuffer * buf)
       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 {
@@ -816,8 +934,13 @@ pad_chain (GstPad * pad, GstBuffer * buf)
     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:
@@ -831,6 +954,8 @@ out_flushing:
   {
     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 &&
@@ -843,7 +968,12 @@ out_flushing:
       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;
   }
@@ -865,6 +995,11 @@ pad_event (GstPad * pad, GstEvent * event)
 
   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
@@ -880,9 +1015,27 @@ pad_event (GstPad * pad, GstEvent * event)
           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 */
@@ -897,36 +1050,40 @@ pad_event (GstPad * pad, GstEvent * event)
       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:
@@ -1006,7 +1163,9 @@ type_instance_init (GTypeInstance * instance, gpointer g_class)
   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);
index 5ade8e2..e7cdfb6 100644 (file)
 #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;
@@ -58,21 +122,25 @@ struct GstOmxBaseFilter
   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);
index 9c2d40b..9939c8d 100644 (file)
@@ -33,8 +33,6 @@ enum
   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);
@@ -161,7 +159,7 @@ render (GstBaseSink * gst_base, GstBuffer * buf)
             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;
@@ -170,6 +168,7 @@ render (GstBaseSink * gst_base, GstBuffer * buf)
               gst_buffer_unref (old_buf);
             } else if (omx_buffer->pBuffer) {
               g_free (omx_buffer->pBuffer);
+              omx_buffer->pBuffer = NULL;
             }
           }
 
index 827d51f..a253762 100644 (file)
 #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
@@ -60,6 +128,8 @@ settings_changed_cb (GOmxCore * core)
 
     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:
@@ -71,7 +141,8 @@ settings_changed_cb (GOmxCore * core)
       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;
@@ -106,6 +177,7 @@ settings_changed_cb (GOmxCore * core)
 
     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 */
   }
 }
 
@@ -198,11 +270,6 @@ omx_setup (GstOmxBaseFilter * omx_base)
     }
   }
 
-  /* 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");
 }
 
index aca21ec..f65269c 100644 (file)
@@ -28,6 +28,7 @@ enum
 {
   ARG_0,
   ARG_BITRATE,
+  ARG_FORCE_KEY_FRAME,
 };
 
 #define DEFAULT_BITRATE 0
@@ -35,6 +36,97 @@ enum
 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)
 {
@@ -52,6 +144,14 @@ set_property (GObject * obj,
     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;
@@ -80,8 +180,12 @@ static void
 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 */
   {
@@ -93,7 +197,16 @@ type_class_init (gpointer g_class, gpointer class_data)
             "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
@@ -142,7 +255,7 @@ sink_setcaps (GstPad * pad, GstCaps * caps)
         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;
@@ -176,12 +289,13 @@ sink_setcaps (GstPad * pad, GstCaps * caps)
       OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, &param);
     }
 
+    /* modification: set nBufferSize */
     G_OMX_INIT_PARAM (param);
 
     param.nPortIndex = omx_base->out_port->port_index;
     OMX_GetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, &param);
 
-    param.nBufferSize = MAX(param.nBufferSize, width * height * 3 / 2);
+    param.nBufferSize = width * height * 3 / 2;
     OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, &param);
   }
 
@@ -211,16 +325,26 @@ omx_setup (GstOmxBaseFilter * omx_base)
 
       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, &param);
     }
   }
 
-  /* 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, &param);
+
+    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, &param);
   }
 
   GST_INFO_OBJECT (omx_base, "end");
@@ -240,4 +364,5 @@ type_instance_init (GTypeInstance * instance, gpointer g_class)
   gst_pad_set_setcaps_function (omx_base->sinkpad, sink_setcaps);
 
   self->bitrate = DEFAULT_BITRATE;
+  self->use_force_key_frame = FALSE;
 }
index 96a1b07..4b0ac5b 100644 (file)
@@ -27,6 +27,7 @@
 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;
 
@@ -35,11 +36,12 @@ 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
diff --git a/omx/gstomx_h264.h b/omx/gstomx_h264.h
new file mode 100644 (file)
index 0000000..4401940
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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 */
index 0507952..0f2f825 100644 (file)
 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)
 {
@@ -49,14 +362,124 @@ 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, &param);
+
+    param.format.video.nFrameWidth = width;
+    param.format.video.nFrameHeight = height;
+
+    OMX_SetParameter (gomx->omx_handle, OMX_IndexParamPortDefinition, &param);
+  }
+  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);
 }
index 8a771ac..d736fbd 100644 (file)
 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
index 4b2d59c..354336a 100644 (file)
 #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)
 {
@@ -47,8 +556,144 @@ 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, &param);
+
+        param.eSliceMode = self->slice_fmo.eSliceMode;
+        param.nNumSliceGroups = 1;
+        param.nSliceGroupMapType = 1;
+        ret = OMX_SetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoSliceFMO, &param);
+        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, &param);
+
+        param.nSliceHeaderSpacing = self->h264type.nSliceHeaderSpacing;
+        ret= OMX_SetParameter (omx_base->gomx->omx_handle, OMX_IndexParamVideoAvc, &param);
+        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
@@ -56,11 +701,14 @@ settings_changed_cb (GOmxCore * core)
 {
   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");
 
@@ -77,7 +725,9 @@ settings_changed_cb (GOmxCore * core)
   }
 
   {
-    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,
@@ -85,6 +735,40 @@ settings_changed_cb (GOmxCore * core)
         "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);
   }
@@ -95,9 +779,17 @@ type_instance_init (GTypeInstance * instance, gpointer g_class)
 {
   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;
 
index 05258a5..561faec 100644 (file)
@@ -31,10 +31,19 @@ typedef struct GstOmxH264Enc GstOmxH264Enc;
 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
index 1286f65..d424333 100644 (file)
 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)
 {
@@ -49,14 +282,25 @@ 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;
 }
index 1b5cce8..506de05 100644 (file)
 #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
index 438c41b..417c19d 100644 (file)
@@ -275,6 +275,7 @@ g_omx_core_free (GOmxCore * core)
   g_ptr_array_free (core->ports, TRUE);
 
   g_free (core);
+  core = NULL;
 }
 
 void
@@ -307,17 +308,21 @@ g_omx_core_init (GOmxCore * core)
       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,
           &param);
     }
 
-    /* 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;
@@ -345,6 +350,9 @@ core_deinit (GOmxCore * core)
   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;
@@ -477,6 +485,7 @@ g_omx_port_new (GOmxCore * core, guint index)
   port->num_buffers = 0;
   port->buffer_size = 0;
   port->buffers = NULL;
+  port->shared_buffer = FALSE;
 
   port->enabled = TRUE;
   port->queue = async_queue_new ();
@@ -492,7 +501,9 @@ g_omx_port_free (GOmxPort * port)
   async_queue_free (port->queue);
 
   g_free (port->buffers);
+  port->buffers = NULL;
   g_free (port);
+  port = NULL;
 }
 
 void
@@ -561,19 +572,48 @@ port_free_buffers (GOmxPort * port)
 {
   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;
index 9f1ac51..e547f63 100644 (file)
@@ -37,6 +37,7 @@ typedef struct GOmxPort GOmxPort;
 typedef struct GOmxImp GOmxImp;
 typedef struct GOmxSymbolTable GOmxSymbolTable;
 typedef enum GOmxPortType GOmxPortType;
+/* MODIFICATION: omx vender */
 typedef enum GOmxVendor GOmxVendor;
 
 typedef void (*GOmxCb) (GOmxCore * core);
@@ -54,7 +55,8 @@ enum GOmxPortType
 enum GOmxVendor
 {
   GOMX_VENDOR_DEFAULT,
-  GOMX_VENDOR_SLSI
+  GOMX_VENDOR_SLSI,
+  GOMX_VENDOR_QCT
 };
 
 /* Structures. */
@@ -101,7 +103,8 @@ struct GOmxCore
   gchar *library_name;
   gchar *component_name;
   gchar *component_role;
-  GOmxVendor component_vendor;    /* Add_component_vendor */
+  /* MODIFICATION: omx vender */
+  GOmxVendor component_vendor;
 };
 
 struct GOmxPort
@@ -118,6 +121,8 @@ struct GOmxPort
   gboolean enabled;
   gboolean omx_allocate;   /**< Setup with OMX_AllocateBuffer rather than OMX_UseBuffer */
   AsyncQueue *queue;
+
+  gboolean shared_buffer; /* Modification */
 };
 
 /* Functions. */
index 87a5e36..7b0525d 100644 (file)
@@ -1,13 +1,10 @@
-%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)
@@ -15,16 +12,14 @@ BuildRequires: pkgconfig(gstreamer-plugins-base-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}
 
@@ -34,6 +29,6 @@ rm -rf %{buildroot}
 %make_install
 
 %files
-%defattr(-,root,root,-) 
+%manifest gst-openmax.manifest
 %{_libdir}/gstreamer-0.10/libgstomx.so
 
index 3336024..e8ded7f 100644 (file)
@@ -42,6 +42,7 @@ g_sem_free (GSem * sem)
   g_cond_free (sem->condition);
   g_mutex_free (sem->mutex);
   g_free (sem);
+  sem = NULL;
 }
 
 void