Update tizen 2.0 beta source 2.0alpha master 2.0_alpha submit/master/20120920.151055
authorHyunseok Lee <hs7388.lee@samsung.com>
Tue, 21 Aug 2012 08:58:13 +0000 (17:58 +0900)
committerHyunseok Lee <hs7388.lee@samsung.com>
Tue, 21 Aug 2012 08:58:13 +0000 (17:58 +0900)
20 files changed:
debian/control
omx/Makefile.am
omx/gstomx.c
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_util.c
omx/gstomx_util.h
packaging/gst-openmax.spec
util/sem.c

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
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..e04d09b 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
index 6f94b33..74f7dc1 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 8ae95ee..e737613 100644 (file)
@@ -25,7 +25,7 @@
 
 #include <string.h>             /* for memcpy */
 
-/* STATE_TUNING */
+/* MODIFICATION: for state-tuning */
 static void output_loop (gpointer data);
 
 enum
@@ -40,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);
 }
 
@@ -95,22 +95,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");
   }
@@ -118,7 +124,7 @@ 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
@@ -213,7 +219,8 @@ out_flushing:
       ret = GST_FLOW_ERROR;
     }
 
-    gst_buffer_unref (buf);
+    if (buf)
+      gst_buffer_unref (buf);
     goto leave;
   }
 }
@@ -236,6 +243,7 @@ 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;
@@ -243,23 +251,31 @@ change_state (GstElement * element, GstStateChange transition)
       break;
 
     case GST_STATE_CHANGE_READY_TO_PAUSED:
-      /* STATE_TUNING */
-       if (self->use_state_tuning) {
-         GST_INFO_OBJECT (self, "use state-tuning feature");
-         omx_change_state(self, GstOmx_LodedToIdle, NULL, NULL);
-
-         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);
-           ret = GST_STATE_CHANGE_FAILURE;
-           goto leave;
-         }
+      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;
 
@@ -274,6 +290,7 @@ 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 */
@@ -292,6 +309,10 @@ change_state (GstElement * element, GstStateChange transition)
       }
       break;
 
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      GST_INFO_OBJECT (self, "GST_STATE_CHANGE_READY_TO_NULL");
+      break;
+
     default:
       break;
   }
@@ -309,6 +330,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;
@@ -462,15 +489,14 @@ push_buffer (GstOmxBaseFilter * self, GstBuffer * buf, OMX_BUFFERHEADERTYPE * om
 
   basefilter_class = GST_OMX_BASE_FILTER_GET_CLASS (self);
   /* process output gst buffer before gst_pad_push */
-  if (basefilter_class->process_output_buf)
-  {
-    basefilter_class->process_output_buf(self, buf, omx_buffer);
+  if (basefilter_class->process_output_buf) {
+    basefilter_class->process_output_buf(self, &buf, omx_buffer);
   }
 
-  /** @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);
 
   return ret;
 }
@@ -515,7 +541,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;
@@ -545,32 +571,22 @@ 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;
 
+      if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_DECODEONLY))
+              goto leave;
+
         caps = gst_pad_get_negotiated_caps(self->srcpad);
         structure = gst_caps_get_structure(caps, 0);
 
@@ -578,7 +594,7 @@ 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;
@@ -593,6 +609,7 @@ 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, omx_buffer);
       } else if (buf && !(omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) {
@@ -627,7 +644,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. */
@@ -647,7 +664,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;
@@ -670,7 +687,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");
     }
 
@@ -716,10 +733,8 @@ pad_chain (GstPad * pad, GstBuffer * buf)
 
   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) {
@@ -747,7 +762,7 @@ pad_chain (GstPad * pad, GstBuffer * buf)
     /* process input gst buffer before OMX_EmptyThisBuffer */
     if (basefilter_class->process_input_buf)
     {
-      basefilter_class->process_input_buf(self,buf);
+      basefilter_class->process_input_buf(self,&buf);
     }
 
     if (self->adapter_size > 0) {
@@ -763,7 +778,6 @@ pad_chain (GstPad * pad, GstBuffer * buf)
       src_size = gst_adapter_available(self->adapter);
       if (src_size + GST_BUFFER_SIZE(buf) <= self->adapter_size) {
         gst_adapter_push(self->adapter, buf);
-        gst_buffer_ref(buf);
         goto leave;
       }
       src_data = (guint8*) gst_adapter_peek(self->adapter, src_size);
@@ -791,8 +805,9 @@ 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.");
@@ -808,7 +823,7 @@ pad_chain (GstPad * pad, GstBuffer * buf)
               sizeof (void*));
           omx_buffer->nAllocLen = sizeof (void*) * 2;
           omx_buffer->nFilledLen = sizeof (void*) * 2;
-        } else if (omx_buffer->nOffset == 0 && self->share_input_buffer) {
+        } else if (omx_buffer->nOffset == 0 && self->in_port->shared_buffer) {
           {
             GstBuffer *old_buf;
             old_buf = omx_buffer->pAppPrivate;
@@ -821,6 +836,7 @@ pad_chain (GstPad * pad, GstBuffer * buf)
               }
             } else if (omx_buffer->pBuffer) {
               g_free (omx_buffer->pBuffer);
+              omx_buffer->pBuffer = NULL;
             }
           }
 
@@ -848,6 +864,7 @@ pad_chain (GstPad * pad, GstBuffer * buf)
               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 {
@@ -869,15 +886,14 @@ pad_chain (GstPad * pad, GstBuffer * buf)
   }
 
   if (self->adapter_size > 0) {
-    if (!self->share_input_buffer) {
+    if (!self->in_port->shared_buffer) {
       gst_adapter_clear(self->adapter);
     } else {
       self->adapter = gst_adapter_new();
     }
     gst_adapter_push(self->adapter, buf);
-    gst_buffer_ref(buf);
   } else {
-    if (!self->share_input_buffer) {
+    if (!self->in_port->shared_buffer) {
       gst_buffer_unref (buf);
     }
   }
@@ -927,8 +943,8 @@ pad_event (GstPad * pad, GstEvent * event)
 
   GST_INFO_OBJECT (self, "event: %s", GST_EVENT_TYPE_NAME (event));
 
-  if (self->omx_event) {
-    if (!self->omx_event(pad, event))
+  if (self->pad_event) {
+    if (!self->pad_event(pad, event))
       return TRUE;
   }
 
index 47b348c..1368217 100644 (file)
@@ -38,7 +38,7 @@ typedef void (*GstOmxBaseFilterCb) (GstOmxBaseFilter * self);
 typedef gboolean (*GstOmxBaseFilterEventCb) (GstPad * pad, GstEvent * event);
 
 
-/* Add extended_color_format */
+/* 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,
@@ -68,15 +68,11 @@ struct GstOmxBaseFilter
   GMutex *ready_lock;
 
   GstOmxBaseFilterCb omx_setup;
-  GstOmxBaseFilterEventCb omx_event;
+  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;
-
-
+  /* MODIFICATION: state-tuning */
   gboolean use_state_tuning;
 
   GstAdapter *adapter;  /* adapter */
@@ -87,8 +83,10 @@ struct GstOmxBaseFilterClass
 {
   GstElementClass parent_class;
 
-  void (*process_input_buf)(GstOmxBaseFilter * omx_base_filter, GstBuffer * buf);
-  void (*process_output_buf)(GstOmxBaseFilter * omx_base_filter, GstBuffer * buf, OMX_BUFFERHEADERTYPE *omx_buffer);
+  void (*process_input_buf)(GstOmxBaseFilter *omx_base_filter, GstBuffer **buf);
+  void (*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 6cd8236..e27fa14 100644 (file)
@@ -32,7 +32,7 @@ GSTOMX_BOILERPLATE (GstOmxBaseVideoDec, gst_omx_base_videodec, GstOmxBaseFilter,
     GST_OMX_BASE_FILTER_TYPE);
 
 static void
-process_input_buf (GstOmxBaseFilter * omx_base_filter, GstBuffer * buf)
+process_input_buf (GstOmxBaseFilter * omx_base_filter, GstBuffer **buf)
 {
 }
 
@@ -41,8 +41,7 @@ type_base_init (gpointer g_class)
 {
 }
 
-
-/* add state tuning property */
+/* MODIFICATION: add state tuning property */
 static void
 set_property (GObject * obj,
     guint prop_id, const GValue * value, GParamSpec * pspec)
@@ -139,7 +138,7 @@ 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_FormatNV12TPhysicalAddress:
         format = GST_MAKE_FOURCC ('S', 'T', '1', '2');
         break;
@@ -174,6 +173,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 */
   }
 }
 
index 25f8a51..7bb77bf 100644 (file)
@@ -28,6 +28,7 @@ enum
 {
   ARG_0,
   ARG_BITRATE,
+  ARG_FORCE_KEY_FRAME,
 };
 
 #define DEFAULT_BITRATE 0
@@ -35,8 +36,9 @@ enum
 GSTOMX_BOILERPLATE (GstOmxBaseVideoEnc, gst_omx_base_videoenc, GstOmxBaseFilter,
     GST_OMX_BASE_FILTER_TYPE);
 
+/* modification: postprocess for outputbuf. in this videoenc case, set sync frame */
 static void
-process_output_buf(GstOmxBaseFilter * omx_base, GstBuffer * buf, OMX_BUFFERHEADERTYPE *omx_buffer)
+process_output_buf(GstOmxBaseFilter * omx_base, GstBuffer **buf, OMX_BUFFERHEADERTYPE *omx_buffer)
 {
   GstOmxBaseVideoEnc *self;
 
@@ -44,14 +46,68 @@ process_output_buf(GstOmxBaseFilter * omx_base, GstBuffer * buf, OMX_BUFFERHEADE
 
   GST_LOG_OBJECT (self, "base videoenc process_output_buf enter");
 
-  /* MODIFICATION: Set sync frame info while encoding */
+  /* modification: set sync frame info while encoding */
   if (omx_buffer->nFlags & OMX_BUFFERFLAG_SYNCFRAME) {
-    GST_BUFFER_FLAG_UNSET(buf, GST_BUFFER_FLAG_DELTA_UNIT);
+    GST_BUFFER_FLAG_UNSET(*buf, GST_BUFFER_FLAG_DELTA_UNIT);
   } else {
-    GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT);
+    GST_BUFFER_FLAG_SET(*buf, GST_BUFFER_FLAG_DELTA_UNIT);
   }
 }
 
+/* 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, "set forcing I frame.");
+
+  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);
+}
+
+/* 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)
 {
@@ -69,6 +125,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;
@@ -98,9 +162,11 @@ 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 */
   {
@@ -112,8 +178,15 @@ 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_output_buf = process_output_buf;
+  basefilter_class->process_output_caps = process_output_caps;
 }
 
 static gboolean
@@ -162,7 +235,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;
@@ -196,12 +269,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);
   }
 
@@ -231,13 +305,28 @@ 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);
     }
   }
 
+  /* 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");
 }
 
@@ -255,4 +344,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..24e903e 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;
 
@@ -40,6 +41,7 @@ struct GstOmxBaseVideoEnc
   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..a9e37d9
--- /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_3GPP,
+    GSTOMX_H264_FORMAT_NALU
+} 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..6e19592 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);
+  unsigned int checklen = 0;
+
+  if (buf_data == NULL || buf_size < GSTOMX_H264_NAL_START_LEN) {
+    self->h264Format = GSTOMX_H264_FORMAT_UNKNOWN;
+    GST_INFO_OBJECT(self, "H264 format is unknown");
+    return;
+  }
+
+  self->h264Format = GSTOMX_H264_FORMAT_3GPP;
+
+  do
+  {
+    if (buf_data[checklen] == 0x00 &&
+      buf_data[checklen+1] == 0x00 &&
+      buf_data[checklen+2] == 0x00 &&
+      buf_data[checklen+3] == 0x01) {
+        self->h264Format = GSTOMX_H264_FORMAT_NALU;
+        GST_INFO_OBJECT(self, "H264 format is NALU");
+        break;
+    } else {
+            checklen++;
+    }
+  } while(checklen < (buf_size - GSTOMX_H264_NAL_START_LEN));
+
+  if (GSTOMX_H264_FORMAT_3GPP == self->h264Format)
+    GST_INFO_OBJECT(self, "H264 format is 3GPP");
+}
+
+/*
+ *  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\n", frameType);
+              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");
+          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)||(outSize < 0)) {
+          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);
+
+  if (*buf) { 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 void
+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_3GPP) {
+
+    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;
+    }
+
+    GST_LOG_OBJECT(h264_self, "H264 format is 3GPP. convert to NALU");
+    convert_frame(h264_self, buf);
+  }
+
+  GST_OMX_BASE_FILTER_CLASS (parent_class)->process_input_buf (omx_base_filter, buf);
+}
+
 static void
 type_base_init (gpointer g_class)
 {
@@ -49,14 +352,121 @@ 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) < 4) GST_ERROR("codec data size is less than 4!!"); //check this.
+
+      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_NALU;
+           GST_INFO_OBJECT(self, "H264 format is NALU");
+      } else {
+         h264_self->h264Format = GSTOMX_H264_FORMAT_3GPP;
+         GST_INFO_OBJECT(self, "H264 format is 3GPP");
+      }
+
+
+      /* if codec data is 3gpp format, convert nalu format */
+      if(h264_self->h264Format == GSTOMX_H264_FORMAT_3GPP) {
+        GstBuffer *nalu_dci = NULL;
+
+        ret = convert_dci(h264_self, buffer, &nalu_dci);
+
+        if (ret) {
+          omx_base->codec_data = nalu_dci;
+        } else {
+          if (nalu_dci) { gst_buffer_unref (nalu_dci); }
+          GST_ERROR_OBJECT(h264_self, "converting dci error.");
+          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..f8910b1 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 void
+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;
+      }
+      gst_buffer_copy_metadata(newbuf, *buf, GST_BUFFER_COPY_ALL);
+      if (*buf)
+        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);
+  }
+}
+
+/*
+ *  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 +555,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, "Appending dci = %d", self->append_dci);
+      break;
+
+    case ARG_BYTE_STREAM:
+      self->byte_stream = g_value_get_boolean (value);
+      GST_INFO_OBJECT (self, "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, "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_uint (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_uint ("slice-mode", "H264 encoder slice mode",
+            "slice mode: 0-Disable, 1-Fixed MB num slice, 2-Fixed bit num slice",
+            0, G_MAXUINT, 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 +700,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 +724,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 +734,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 +778,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 0a11bb7..d99b9c2 100644 (file)
@@ -118,7 +118,7 @@ error_exit:
 }
 
 static void
-process_input_buf (GstOmxBaseFilter * omx_base_filter, GstBuffer * buf)
+process_input_buf (GstOmxBaseFilter * omx_base_filter, GstBuffer **buf)
 {
   GstOmxMpeg4Dec *self;
 
@@ -128,10 +128,10 @@ process_input_buf (GstOmxBaseFilter * omx_base_filter, GstBuffer * buf)
 
   /* 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));
+    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));
+      GST_ERROR_OBJECT (self, "##### DivX DRM Mode ##### decrypt video failed : buffer = %d", GST_BUFFER_SIZE(*buf));
     }
   }
 
@@ -174,7 +174,7 @@ print_tag (const GstTagList * list, const gchar * tag, gpointer data)
     }
 
     if (i == 0) {
-      g_print ("%16s: %s\n", gst_tag_get_nick (tag), str);
+      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) {
@@ -190,7 +190,6 @@ print_tag (const GstTagList * list, const gchar * tag, gpointer data)
       }
     } else {
       GST_LOG_OBJECT(self, "tag is not DRM Divx");
-      g_print ("%16s: %s\n", "", str);
     }
 
     g_free (str);
@@ -299,6 +298,6 @@ type_instance_init (GTypeInstance * instance, gpointer g_class)
   omx_base = GST_OMX_BASE_VIDEODEC (instance);
   omx_base_filter = GST_OMX_BASE_FILTER (instance);
 
-  omx_base_filter->omx_event = mpeg4_pad_event;
+  omx_base_filter->pad_event = mpeg4_pad_event;
   omx_base->compression_format = OMX_VIDEO_CodingMPEG4;
 }
index 438c41b..e6cf228 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
@@ -313,11 +314,15 @@ g_omx_core_init (GOmxCore * core)
           &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,40 @@ 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 */
+        GST_INFO_OBJECT(port->core->object,
+            " %d: unref shared buffer (pAppPrivate) %p", i, omx_buffer->pAppPrivate);
+        if(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 d3af874..874db25 100644 (file)
@@ -1,7 +1,7 @@
 Name:       gst-openmax
 Summary:    GStreamer plug-in that allows communication with OpenMAX IL components
 Version:    0.10.1
-Release:    0
+Release:    1
 Group:      TO_BE/FILLED_IN
 License:    LGPLv2.1
 Source0:    %{name}-%{version}.tar.gz
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