winks: performance improvements
authorOle André Vadla Ravnås <oravnas@cisco.com>
Mon, 7 Sep 2009 14:45:57 +0000 (16:45 +0200)
committerOle André Vadla Ravnås <oravnas@cisco.com>
Thu, 28 Oct 2010 15:08:35 +0000 (17:08 +0200)
* Make the driver write directly into each GstBuffer to avoid memcpy().
* Don't memset() the buffer before reusing it.
* Recycle memory by keeping two spare buffers. Two because the sink
  downstream may keep a ref to the previous buffer.

Note that we align buffers on highest possible byte boundary (4096) so we
don't have to take into account what kind of alignment the driver requires.

sys/winks/gstksvideodevice.c
sys/winks/gstksvideodevice.h
sys/winks/gstksvideosrc.c

index 3e59d2a..0b95e3d 100644 (file)
 #define READ_TIMEOUT           (10 * 1000)
 #define MJPEG_MAX_PADDING      128
 #define MAX_OUTSTANDING_FRAMES 128
-#define BUFFER_ALIGNMENT       512
+
+#define KS_BUFFER_ALIGNMENT    4096
 
 #define DEFAULT_DEVICE_PATH NULL
 
 GST_DEBUG_CATEGORY_EXTERN (gst_ks_debug);
 #define GST_CAT_DEFAULT gst_ks_debug
 
-#define GST_DEBUG_IS_ENABLED() \
+#define GST_DEBUG_IS_ENABLED()  \
     (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= GST_LEVEL_DEBUG)
+#define UNREF_BUFFER(b)         \
+  G_STMT_START {                \
+    if (*(b) != NULL) {         \
+      gst_buffer_unref (*(b));  \
+      *(b) = NULL;              \
+    }                           \
+  } G_STMT_END
 
 enum
 {
@@ -52,8 +60,7 @@ typedef struct
 typedef struct
 {
   KSSTREAM_READ_PARAMS params;
-  guint8 *buf_unaligned;
-  guint8 *buf;
+  GstBuffer *buf;
   OVERLAPPED overlapped;
 } ReadRequest;
 
@@ -84,8 +91,9 @@ struct _GstKsVideoDevicePrivate
   gulong num_requests;
   GArray *requests;
   GArray *request_events;
+  GstBuffer *spare_buffers[2];
   GstClockTime last_timestamp;
-} GstKsVideoDevicePrivate;
+};
 
 #define GST_KS_VIDEO_DEVICE_GET_PRIVATE(o) ((o)->priv)
 
@@ -96,6 +104,7 @@ static void gst_ks_video_device_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
 
 static void gst_ks_video_device_reset_caps (GstKsVideoDevice * self);
+static guint gst_ks_video_device_get_frame_size (GstKsVideoDevice * self);
 
 GST_BOILERPLATE (GstKsVideoDevice, gst_ks_video_device, GObject, G_TYPE_OBJECT);
 
@@ -258,11 +267,16 @@ gst_ks_video_device_clear_buffers (GstKsVideoDevice * self)
   }
 
   /* Clean up */
+  for (i = 0; i < G_N_ELEMENTS (priv->spare_buffers); i++) {
+    gst_buffer_unref (priv->spare_buffers[i]);
+    priv->spare_buffers[i] = NULL;
+  }
+
   for (i = 0; i < priv->requests->len; i++) {
     ReadRequest *req = &g_array_index (priv->requests, ReadRequest, i);
     HANDLE ev = g_array_index (priv->request_events, HANDLE, i);
 
-    g_free (req->buf_unaligned);
+    gst_buffer_unref (req->buf);
 
     if (ev)
       CloseHandle (ev);
@@ -293,12 +307,16 @@ gst_ks_video_device_prepare_buffers (GstKsVideoDevice * self)
 
   frame_size = gst_ks_video_device_get_frame_size (self);
 
+  for (i = 0; i < G_N_ELEMENTS (priv->spare_buffers); i++) {
+    priv->spare_buffers[i] = self->allocfunc (frame_size, KS_BUFFER_ALIGNMENT,
+        self->allocfunc_data);
+  }
+
   for (i = 0; i < priv->num_requests; i++) {
     ReadRequest req = { 0, };
 
-    req.buf_unaligned = g_malloc (frame_size + BUFFER_ALIGNMENT - 1);
-    req.buf = (guint8 *) (((gsize) req.buf_unaligned + BUFFER_ALIGNMENT - 1)
-        & ~(BUFFER_ALIGNMENT - 1));
+    req.buf = self->allocfunc (frame_size, KS_BUFFER_ALIGNMENT,
+        self->allocfunc_data);
 
     req.overlapped.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
 
@@ -332,6 +350,20 @@ gst_ks_video_device_dump_supported_property_sets (GstKsVideoDevice * self,
   }
 }
 
+GstKsVideoDevice *
+gst_ks_video_device_new (const gchar * device_path, GstKsClock * clock,
+    GstKsAllocFunction allocfunc, gpointer allocfunc_data)
+{
+  GstKsVideoDevice *device;
+
+  device = g_object_new (GST_TYPE_KS_VIDEO_DEVICE,
+      "device-path", device_path, "clock", clock, NULL);
+  device->allocfunc = allocfunc;
+  device->allocfunc_data = allocfunc_data;
+
+  return device;
+}
+
 gboolean
 gst_ks_video_device_open (GstKsVideoDevice * self)
 {
@@ -556,8 +588,8 @@ gst_ks_video_device_create_pin (GstKsVideoDevice * self,
   g_free (framing_ex);
 
   /*
-   * TODO: We also need to respect alignment, but for now we just align
-   *       on FILE_512_BYTE_ALIGNMENT.
+   * TODO: We also need to respect alignment, but for now we just assume
+   *       that allocfunc provides the appropriate alignment...
    */
 
   /* Set the memory transport to use. */
@@ -818,7 +850,7 @@ gst_ks_video_device_set_state (GstKsVideoDevice * self, KSSTATE state)
   return TRUE;
 }
 
-guint
+static guint
 gst_ks_video_device_get_frame_size (GstKsVideoDevice * self)
 {
   GstKsVideoDevicePrivate *priv = GST_KS_VIDEO_DEVICE_GET_PRIVATE (self);
@@ -855,6 +887,41 @@ gst_ks_video_device_get_latency (GstKsVideoDevice * self,
 }
 
 static gboolean
+gst_ks_read_request_pick_buffer (GstKsVideoDevice * self, ReadRequest * req)
+{
+  GstKsVideoDevicePrivate *priv = GST_KS_VIDEO_DEVICE_GET_PRIVATE (self);
+  gboolean buffer_found = FALSE;
+  guint i;
+
+  buffer_found = gst_buffer_is_writable (req->buf);
+
+  for (i = 0; !buffer_found && i < G_N_ELEMENTS (priv->spare_buffers); i++) {
+    if (gst_buffer_is_writable (priv->spare_buffers[i])) {
+      GstBuffer *hold;
+
+      hold = req->buf;
+      req->buf = priv->spare_buffers[i];
+      priv->spare_buffers[i] = hold;
+
+      buffer_found = TRUE;
+    }
+  }
+
+  if (!buffer_found) {
+    gst_buffer_unref (req->buf);
+    req->buf = self->allocfunc (gst_ks_video_device_get_frame_size (self),
+        KS_BUFFER_ALIGNMENT, self->allocfunc_data);
+  }
+
+  if (req->buf != NULL) {
+    GST_BUFFER_FLAGS (req->buf) = 0;
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+static gboolean
 gst_ks_video_device_request_frame (GstKsVideoDevice * self, ReadRequest * req,
     gulong * error_code, gchar ** error_str)
 {
@@ -864,6 +931,9 @@ gst_ks_video_device_request_frame (GstKsVideoDevice * self, ReadRequest * req,
   BOOL success;
   DWORD bytes_returned = 0;
 
+  if (!gst_ks_read_request_pick_buffer (self, req))
+    goto error_pick_buffer;
+
   /* Reset the OVERLAPPED structure */
   event = req->overlapped.hEvent;
   memset (&req->overlapped, 0, sizeof (OVERLAPPED));
@@ -877,18 +947,9 @@ gst_ks_video_device_request_frame (GstKsVideoDevice * self, ReadRequest * req,
   params->header.PresentationTime.Numerator = 1;
   params->header.PresentationTime.Denominator = 1;
   params->header.FrameExtent = gst_ks_video_device_get_frame_size (self);
-  params->header.Data = req->buf;
+  params->header.Data = GST_BUFFER_DATA (req->buf);
   params->frame_info.ExtendedHeaderSize = sizeof (KS_FRAME_INFO);
 
-  /*
-   * Clear the buffer like DirectShow does
-   *
-   * REVISIT: Could probably remove this later, for now it's here to help
-   *          track down the case where we capture old frames. This has been
-   *          observed with UVC cameras, presumably with some system load.
-   */
-  memset (params->header.Data, 0, params->header.FrameExtent);
-
   success = DeviceIoControl (priv->pin_handle, IOCTL_KS_READ_STREAM, NULL, 0,
       params, params->header.Size, &bytes_returned, &req->overlapped);
   if (!success && GetLastError () != ERROR_IO_PENDING)
@@ -897,6 +958,14 @@ gst_ks_video_device_request_frame (GstKsVideoDevice * self, ReadRequest * req,
   return TRUE;
 
   /* ERRORS */
+error_pick_buffer:
+  {
+    if (error_code != NULL)
+      *error_code = 0;
+    if (error_str != NULL)
+      *error_str = NULL;
+    return FALSE;
+  }
 error_ioctl:
   {
     gst_ks_video_device_parse_win32_error ("DeviceIoControl", GetLastError (),
@@ -905,10 +974,57 @@ error_ioctl:
   }
 }
 
+static void
+gst_ks_video_device_correct_or_drop_frame (GstKsVideoDevice * self,
+    GstBuffer ** frame_buf)
+{
+  GstKsVideoDevicePrivate *priv = GST_KS_VIDEO_DEVICE_GET_PRIVATE (self);
+  gboolean valid = FALSE;
+  guint padding = 0;
+  guint8 *data;
+  guint data_size;
+
+  if (!priv->is_mjpeg)
+    return;
+
+  /*
+   * Workaround for cameras/drivers that intermittently provide us
+   * with incomplete or corrupted MJPEG frames.
+   *
+   * Happens with for instance Microsoft LifeCam VX-7000.
+   */
+
+  data = GST_BUFFER_DATA (*frame_buf);
+  data_size = GST_BUFFER_SIZE (*frame_buf);
+
+  if (data_size > MJPEG_MAX_PADDING) {
+    /* JFIF SOI marker */
+    if (data[0] == 0xff && data[1] == 0xd8) {
+      guint8 *p = data + data_size - 2;
+
+      /* JFIF EOI marker (but skip any padding) */
+      while (padding < MJPEG_MAX_PADDING - 1 - 2 && !valid) {
+        if (p[0] == 0xff && p[1] == 0xd9) {
+          valid = TRUE;
+        } else {
+          padding++;
+          p--;
+        }
+      }
+    }
+  }
+
+  if (valid) {
+    GST_BUFFER_SIZE (*frame_buf) -= padding;
+  } else {
+    gst_buffer_unref (*frame_buf);
+    *frame_buf = NULL;
+  }
+}
+
 GstFlowReturn
-gst_ks_video_device_read_frame (GstKsVideoDevice * self, guint8 * buf,
-    gulong buf_size, gulong * bytes_read, GstClockTime * presentation_time,
-    gulong * error_code, gchar ** error_str)
+gst_ks_video_device_read_frame (GstKsVideoDevice * self, GstBuffer ** buf,
+    GstClockTime * presentation_time, gulong * error_code, gchar ** error_str)
 {
   GstKsVideoDevicePrivate *priv = GST_KS_VIDEO_DEVICE_GET_PRIVATE (self);
   guint req_idx;
@@ -930,6 +1046,8 @@ gst_ks_video_device_read_frame (GstKsVideoDevice * self, guint8 * buf,
     }
   }
 
+  *buf = NULL;
+
   do {
     /* Wait for either a request to complete, a cancel or a timeout */
     wait_ret = WaitForMultipleObjects (priv->request_events->len,
@@ -943,8 +1061,6 @@ gst_ks_video_device_read_frame (GstKsVideoDevice * self, guint8 * buf,
     if (WaitForSingleObject (priv->cancel_event, 0) == WAIT_OBJECT_0)
       goto error_cancel;
 
-    *bytes_read = 0;
-
     /* Find the last ReadRequest that finished and get the result, immediately
      * re-issuing each request that has completed. */
     for (req_idx = wait_ret - WAIT_OBJECT_0;
@@ -977,8 +1093,13 @@ gst_ks_video_device_read_frame (GstKsVideoDevice * self, guint8 * buf,
         if (hdr->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DURATIONVALID)
           duration = hdr->Duration * 100;
 
-        /* Assume it's a good frame */
-        *bytes_read = hdr->DataUsed;
+        UNREF_BUFFER (buf);
+
+        if (G_LIKELY (hdr->DataUsed != 0)) {
+          /* Assume it's a good frame */
+          GST_BUFFER_SIZE (req->buf) = hdr->DataUsed;
+          *buf = gst_buffer_ref (req->buf);
+        }
 
         if (G_LIKELY (presentation_time != NULL))
           *presentation_time = timestamp;
@@ -1006,64 +1127,31 @@ gst_ks_video_device_read_frame (GstKsVideoDevice * self, guint8 * buf,
                 ", timestamp=%" GST_TIME_FORMAT ")",
                 GST_TIME_ARGS (priv->last_timestamp),
                 GST_TIME_ARGS (timestamp));
-            *bytes_read = 0;
+            UNREF_BUFFER (buf);
           } else {
             priv->last_timestamp = timestamp;
           }
         }
 
-        if (*bytes_read > 0) {
-          /* Grab the frame data */
-          g_assert (buf_size >= hdr->DataUsed);
-          memcpy (buf, req->buf, hdr->DataUsed);
-
-          if (priv->is_mjpeg) {
-            /*
-             * Workaround for cameras/drivers that intermittently provide us
-             * with incomplete or corrupted MJPEG frames.
-             *
-             * Happens with for instance Microsoft LifeCam VX-7000.
-             */
-
-            gboolean valid = FALSE;
-            guint padding = 0;
-
-            /* JFIF SOI marker */
-            if (*bytes_read > MJPEG_MAX_PADDING
-                && buf[0] == 0xff && buf[1] == 0xd8) {
-              guint8 *p = buf + *bytes_read - 2;
-
-              /* JFIF EOI marker (but skip any padding) */
-              while (padding < MJPEG_MAX_PADDING - 1 - 2 && !valid) {
-                if (p[0] == 0xff && p[1] == 0xd9) {
-                  valid = TRUE;
-                } else {
-                  padding++;
-                  p--;
-                }
-              }
-            }
-
-            if (valid)
-              *bytes_read -= padding;
-            else
-              *bytes_read = 0;
-          }
-        }
-      } else if (GetLastError () != ERROR_OPERATION_ABORTED)
+        if (*buf != NULL)
+          gst_ks_video_device_correct_or_drop_frame (self, buf);
+      } else if (GetLastError () != ERROR_OPERATION_ABORTED) {
         goto error_get_result;
+      }
 
       /* Submit a new request immediately */
       if (!gst_ks_video_device_request_frame (self, req, error_code, error_str))
         goto error_request_failed;
     }
-  } while (*bytes_read == 0);
+  } while (*buf == NULL);
 
   return GST_FLOW_OK;
 
   /* ERRORS */
 error_request_failed:
   {
+    UNREF_BUFFER (buf);
+
     return GST_FLOW_ERROR;
   }
 error_timeout:
index e5d80da..1d110ad 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef __GST_KS_VIDEO_DEVICE_H__
 #define __GST_KS_VIDEO_DEVICE_H__
 
+#include "gstksclock.h"
+
 #include <gst/gst.h>
 
 #include <windows.h>
@@ -42,10 +44,15 @@ typedef struct _GstKsVideoDevice        GstKsVideoDevice;
 typedef struct _GstKsVideoDeviceClass   GstKsVideoDeviceClass;
 typedef struct _GstKsVideoDevicePrivate GstKsVideoDevicePrivate;
 
+typedef GstBuffer * (* GstKsAllocFunction)(guint buf_size, guint alignment, gpointer user_data);
+
 struct _GstKsVideoDevice
 {
   GObject parent;
 
+  GstKsAllocFunction allocfunc;
+  gpointer allocfunc_data;
+
   GstKsVideoDevicePrivate *priv;
 };
 
@@ -56,6 +63,7 @@ struct _GstKsVideoDeviceClass
 
 GType gst_ks_video_device_get_type (void);
 
+GstKsVideoDevice * gst_ks_video_device_new (const gchar * device_path, GstKsClock * clock, GstKsAllocFunction allocfunc, gpointer allocfunc_data);
 gboolean gst_ks_video_device_open (GstKsVideoDevice * self);
 void gst_ks_video_device_close (GstKsVideoDevice * self);
 
@@ -65,11 +73,10 @@ gboolean gst_ks_video_device_set_caps (GstKsVideoDevice * self, GstCaps * caps);
 
 gboolean gst_ks_video_device_set_state (GstKsVideoDevice * self, KSSTATE state);
 
-guint gst_ks_video_device_get_frame_size (GstKsVideoDevice * self);
 GstClockTime gst_ks_video_device_get_duration (GstKsVideoDevice * self);
 gboolean gst_ks_video_device_get_latency (GstKsVideoDevice * self, GstClockTime * min_latency, GstClockTime * max_latency);
 
-GstFlowReturn gst_ks_video_device_read_frame (GstKsVideoDevice * self, guint8 * buf, gulong buf_size, gulong * bytes_read, GstClockTime * presentation_time, gulong * error_code, gchar ** error_str);
+GstFlowReturn gst_ks_video_device_read_frame (GstKsVideoDevice * self, GstBuffer ** buf, GstClockTime * presentation_time, gulong * error_code, gchar ** error_str);
 void gst_ks_video_device_postprocess_frame (GstKsVideoDevice * self, guint8 * buf, guint buf_size);
 void gst_ks_video_device_cancel (GstKsVideoDevice * self);
 void gst_ks_video_device_cancel_stop (GstKsVideoDevice * self);
index de6d561..df920a1 100644 (file)
@@ -155,6 +155,8 @@ static gboolean gst_ks_video_src_unlock_stop (GstBaseSrc * basesrc);
 
 static GstFlowReturn gst_ks_video_src_create (GstPushSrc * pushsrc,
     GstBuffer ** buffer);
+static GstBuffer *gst_ks_video_src_alloc_buffer (guint size, guint alignment,
+    gpointer user_data);
 
 GST_BOILERPLATE_FULL (GstKsVideoSrc, gst_ks_video_src, GstPushSrc,
     GST_TYPE_PUSH_SRC, gst_ks_video_src_init_interfaces);
@@ -524,8 +526,8 @@ gst_ks_video_src_open_device (GstKsVideoSrc * self)
         priv->ksclock = NULL;
       }
 
-      device = g_object_new (GST_TYPE_KS_VIDEO_DEVICE,
-          "clock", priv->ksclock, "device-path", entry->path, NULL);
+      device = gst_ks_video_device_new (entry->path, priv->ksclock,
+          gst_ks_video_src_alloc_buffer, self);
     }
 
     ks_device_entry_free (entry);
@@ -991,13 +993,10 @@ gst_ks_video_src_update_statistics (GstKsVideoSrc * self)
 }
 
 static GstFlowReturn
-gst_ks_video_src_create (GstPushSrc * pushsrc, GstBuffer ** buffer)
+gst_ks_video_src_create (GstPushSrc * pushsrc, GstBuffer ** buf)
 {
   GstKsVideoSrc *self = GST_KS_VIDEO_SRC (pushsrc);
   GstKsVideoSrcPrivate *priv = GST_KS_VIDEO_SRC_GET_PRIVATE (self);
-  guint buf_size;
-  GstCaps *caps;
-  GstBuffer *buf = NULL;
   GstFlowReturn result;
   GstClockTime presentation_time;
   gulong error_code;
@@ -1008,18 +1007,6 @@ gst_ks_video_src_create (GstPushSrc * pushsrc, GstBuffer ** buffer)
   if (!gst_ks_video_device_has_caps (priv->device))
     goto error_no_caps;
 
-  buf_size = gst_ks_video_device_get_frame_size (priv->device);
-  g_assert (buf_size);
-
-  caps = gst_pad_get_negotiated_caps (GST_BASE_SRC_PAD (self));
-  if (caps == NULL)
-    goto error_no_caps;
-  result = gst_pad_alloc_buffer (GST_BASE_SRC_PAD (self), priv->offset,
-      buf_size, caps, &buf);
-  gst_caps_unref (caps);
-  if (G_UNLIKELY (result != GST_FLOW_OK))
-    goto error_alloc_buffer;
-
   if (G_UNLIKELY (!priv->running)) {
     KS_WORKER_LOCK (priv);
     priv->worker_pending_run = TRUE;
@@ -1034,25 +1021,24 @@ gst_ks_video_src_create (GstPushSrc * pushsrc, GstBuffer ** buffer)
   }
 
   do {
-    gulong bytes_read;
+    if (*buf != NULL) {
+      gst_buffer_unref (*buf);
+      *buf = NULL;
+    }
 
-    result = gst_ks_video_device_read_frame (priv->device,
-        GST_BUFFER_DATA (buf), buf_size, &bytes_read, &presentation_time,
-        &error_code, &error_str);
+    result = gst_ks_video_device_read_frame (priv->device, buf,
+        &presentation_time, &error_code, &error_str);
     if (G_UNLIKELY (result != GST_FLOW_OK))
       goto error_read_frame;
-
-    GST_BUFFER_SIZE (buf) = bytes_read;
   }
-  while (!gst_ks_video_src_timestamp_buffer (self, buf, presentation_time));
+  while (!gst_ks_video_src_timestamp_buffer (self, *buf, presentation_time));
 
   if (G_UNLIKELY (priv->do_stats))
     gst_ks_video_src_update_statistics (self);
 
   gst_ks_video_device_postprocess_frame (priv->device,
-      GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+      GST_BUFFER_DATA (*buf), GST_BUFFER_SIZE (*buf));
 
-  *buffer = buf;
   return GST_FLOW_OK;
 
   /* ERRORS */
@@ -1071,31 +1057,64 @@ error_start_capture:
 
     return GST_FLOW_ERROR;
   }
-error_alloc_buffer:
-  {
-    GST_ELEMENT_ERROR (self, CORE, PAD, ("alloc_buffer failed"), (NULL));
-
-    return result;
-  }
 error_read_frame:
   {
     if (result == GST_FLOW_ERROR) {
-      GST_ELEMENT_ERROR (self, RESOURCE, READ,
-          ("read failed: %s [0x%08x]", error_str, error_code),
-          ("gst_ks_video_device_read_frame failed"));
-    }
-    else if (result == GST_FLOW_UNEXPECTED) {
+      if (error_str != NULL) {
+        GST_ELEMENT_ERROR (self, RESOURCE, READ,
+            ("read failed: %s [0x%08x]", error_str, error_code),
+            ("gst_ks_video_device_read_frame failed"));
+      }
+    } else if (result == GST_FLOW_UNEXPECTED) {
       GST_ELEMENT_ERROR (self, RESOURCE, READ,
           ("read failed"), ("gst_ks_video_device_read_frame failed"));
     }
 
     g_free (error_str);
-    gst_buffer_unref (buf);
 
     return result;
   }
 }
 
+static GstBuffer *
+gst_ks_video_src_alloc_buffer (guint size, guint alignment, gpointer user_data)
+{
+  GstKsVideoSrc *self = GST_KS_VIDEO_SRC (user_data);
+  GstBuffer *buf;
+  GstCaps *caps;
+  GstFlowReturn flow_ret;
+
+  caps = gst_pad_get_negotiated_caps (GST_BASE_SRC_PAD (self));
+  if (caps == NULL)
+    goto error_no_caps;
+  flow_ret = gst_pad_alloc_buffer (GST_BASE_SRC_PAD (self), 0,
+      size + (alignment - 1), caps, &buf);
+  gst_caps_unref (caps);
+  if (G_UNLIKELY (flow_ret != GST_FLOW_OK))
+    goto error_alloc_buffer;
+
+  GST_BUFFER_DATA (buf) =
+      GSIZE_TO_POINTER ((GPOINTER_TO_SIZE (GST_BUFFER_DATA (buf)) + (alignment -
+              1)) & ~(alignment - 1));
+  GST_BUFFER_SIZE (buf) = size;
+
+  return buf;
+
+error_no_caps:
+  {
+    GST_ELEMENT_ERROR (self, CORE, NEGOTIATION,
+        ("not negotiated"), ("maybe setcaps failed?"));
+
+    return NULL;
+  }
+error_alloc_buffer:
+  {
+    GST_ELEMENT_ERROR (self, CORE, PAD, ("alloc_buffer failed"), (NULL));
+
+    return NULL;
+  }
+}
+
 static gboolean
 plugin_init (GstPlugin * plugin)
 {