baseparse: introduce a baseparse frame to serve as context
authorMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
Mon, 10 Jan 2011 14:34:48 +0000 (15:34 +0100)
committerTim-Philipp Müller <tim.muller@collabora.co.uk>
Fri, 8 Apr 2011 14:44:54 +0000 (15:44 +0100)
... and adjust subclass parsers accordingly

gst/audioparsers/gstbaseparse.c
gst/audioparsers/gstbaseparse.h

index 8f7a5d5..9189846 100644 (file)
@@ -352,10 +352,9 @@ static GstFlowReturn gst_base_parse_chain (GstPad * pad, GstBuffer * buffer);
 static void gst_base_parse_loop (GstPad * pad);
 
 static gboolean gst_base_parse_check_frame (GstBaseParse * parse,
-    GstBuffer * buffer, guint * framesize, gint * skipsize);
-
+    GstBaseParseFrame * frame, guint * framesize, gint * skipsize);
 static GstFlowReturn gst_base_parse_parse_frame (GstBaseParse * parse,
-    GstBuffer * buffer);
+    GstBaseParseFrame * frame);
 
 static gboolean gst_base_parse_sink_eventfunc (GstBaseParse * parse,
     GstEvent * event);
@@ -504,6 +503,49 @@ gst_base_parse_init (GstBaseParse * parse, GstBaseParseClass * bclass)
   GST_DEBUG_OBJECT (parse, "init ok");
 }
 
+/**
+ * gst_base_parse_frame_init:
+ * @parse: #GstBaseParse.
+ * @fmt: #GstBaseParseFrame.
+ *
+ * Sets a #GstBaseParseFrame to initial state.  Currently this means
+ * all fields are zero-ed.
+ */
+void
+gst_base_parse_frame_init (GstBaseParse * parse, GstBaseParseFrame * frame)
+{
+  memset (frame, 0, sizeof (*frame));
+}
+
+/* clear == frame no longer to be used following this */
+static void
+gst_base_parse_frame_clear (GstBaseParse * parse, GstBaseParseFrame * frame)
+{
+  /* limited for now */
+  if (frame->buffer) {
+    gst_buffer_unref (frame->buffer);
+    frame->buffer = NULL;
+  }
+}
+
+static inline void
+gst_base_parse_frame_update (GstBaseParse * parse, GstBaseParseFrame * frame,
+    GstBuffer * buf)
+{
+  gst_buffer_replace (&frame->buffer, buf);
+  if (parse->priv->drain) {
+    frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DRAIN;
+  } else {
+    frame->flags &= ~(GST_BASE_PARSE_FRAME_FLAG_DRAIN);
+  }
+  /* losing sync is pretty much a discont (and vice versa), no ? */
+  if (!parse->priv->discont) {
+    frame->flags |= GST_BASE_PARSE_FRAME_FLAG_SYNC;
+  } else {
+    frame->flags &= ~(GST_BASE_PARSE_FRAME_FLAG_SYNC);
+  }
+}
+
 static void
 gst_base_parse_reset (GstBaseParse * parse)
 {
@@ -587,9 +629,9 @@ gst_base_parse_reset (GstBaseParse * parse)
  */
 static gboolean
 gst_base_parse_check_frame (GstBaseParse * parse,
-    GstBuffer * buffer, guint * framesize, gint * skipsize)
+    GstBaseParseFrame * frame, guint * framesize, gint * skipsize)
 {
-  *framesize = GST_BUFFER_SIZE (buffer);
+  *framesize = GST_BUFFER_SIZE (frame->buffer);
   *skipsize = 0;
   return TRUE;
 }
@@ -603,8 +645,10 @@ gst_base_parse_check_frame (GstBaseParse * parse,
  * Default callback for parse_frame.
  */
 static GstFlowReturn
-gst_base_parse_parse_frame (GstBaseParse * parse, GstBuffer * buffer)
+gst_base_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
 {
+  GstBuffer *buffer = frame->buffer;
+
   if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
       GST_CLOCK_TIME_IS_VALID (parse->priv->next_ts)) {
     GST_BUFFER_TIMESTAMP (buffer) = parse->priv->next_ts;
@@ -1114,23 +1158,22 @@ gst_base_parse_post_bitrates (GstBaseParse * parse, gboolean post_min,
  * running average bitrate of the stream so far.
  */
 static void
-gst_base_parse_update_bitrates (GstBaseParse * parse, GstBuffer * buffer)
+gst_base_parse_update_bitrates (GstBaseParse * parse, GstBaseParseFrame * frame)
 {
   /* Only update the tag on a 10 kbps delta */
   static const gint update_threshold = 10000;
 
   GstBaseParseClass *klass;
   guint64 data_len, frame_dur;
-  gint overhead = 0, frame_bitrate, old_avg_bitrate;
+  gint overhead, frame_bitrate, old_avg_bitrate;
   gboolean update_min = FALSE, update_avg = FALSE, update_max = FALSE;
+  GstBuffer *buffer = frame->buffer;
 
   klass = GST_BASE_PARSE_GET_CLASS (parse);
 
-  if (klass->get_frame_overhead) {
-    overhead = klass->get_frame_overhead (parse, buffer);
-    if (overhead == -1)
-      return;
-  }
+  overhead = frame->overhead;
+  if (overhead == -1)
+    return;
 
   data_len = GST_BUFFER_SIZE (buffer) - overhead;
   parse->priv->data_bytecount += data_len;
@@ -1391,11 +1434,16 @@ gst_base_parse_check_media (GstBaseParse * parse)
  * Returns: #GstFlowReturn
  */
 static GstFlowReturn
-gst_base_parse_handle_and_push_buffer (GstBaseParse * parse,
-    GstBaseParseClass * klass, GstBuffer * buffer)
+gst_base_parse_handle_and_push_frame (GstBaseParse * parse,
+    GstBaseParseClass * klass, GstBaseParseFrame * frame)
 {
   GstFlowReturn ret;
   gint64 offset;
+  GstBuffer *buffer;
+
+  g_return_val_if_fail (frame != NULL, GST_FLOW_ERROR);
+
+  buffer = frame->buffer;
 
   if (parse->priv->discont) {
     GST_DEBUG_OBJECT (parse, "marking DISCONT");
@@ -1417,7 +1465,11 @@ gst_base_parse_handle_and_push_buffer (GstBaseParse * parse,
 
   /* store offset as it might get overwritten */
   offset = GST_BUFFER_OFFSET (buffer);
-  ret = klass->parse_frame (parse, buffer);
+  ret = klass->parse_frame (parse, frame);
+  /* sync */
+  buffer = frame->buffer;
+  /* subclass must play nice */
+  g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
 
   /* check initial frame to determine if subclass/format can provide ts.
    * If so, that allows and enables extra seek and duration determining options */
@@ -1446,7 +1498,7 @@ gst_base_parse_handle_and_push_buffer (GstBaseParse * parse,
   }
 
   /* re-use default handler to add missing metadata as-much-as-possible */
-  gst_base_parse_parse_frame (parse, buffer);
+  gst_base_parse_parse_frame (parse, frame);
   if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
       GST_BUFFER_DURATION_IS_VALID (buffer)) {
     parse->priv->next_ts =
@@ -1468,34 +1520,40 @@ gst_base_parse_handle_and_push_buffer (GstBaseParse * parse,
    * frames to decide on the format and queues them internally */
   /* convert internal flow to OK and mark discont for the next buffer. */
   if (ret == GST_BASE_PARSE_FLOW_DROPPED) {
-    gst_buffer_unref (buffer);
+    gst_base_parse_frame_clear (parse, frame);
     return GST_FLOW_OK;
   } else if (ret != GST_FLOW_OK) {
     return ret;
   }
 
-  return gst_base_parse_push_buffer (parse, buffer);
+  return gst_base_parse_push_frame (parse, frame);
 }
 
 /**
- * gst_base_parse_push_buffer:
+ * gst_base_parse_push_frame:
  * @parse: #GstBaseParse.
- * @buffer: #GstBuffer.
+ * @frame: #GstBaseParseFrame.
  *
- * Pushes the buffer downstream, sends any pending events and
+ * Pushes the frame downstream, sends any pending events and
  * does some timestamp and segment handling.
  *
- * This must be called with srcpad STREAM_LOCK held.
+ * This must be called with sinkpad STREAM_LOCK held.
  *
  * Returns: #GstFlowReturn
  */
 GstFlowReturn
-gst_base_parse_push_buffer (GstBaseParse * parse, GstBuffer * buffer)
+gst_base_parse_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
 {
   GstFlowReturn ret = GST_FLOW_OK;
   GstClockTime last_start = GST_CLOCK_TIME_NONE;
   GstClockTime last_stop = GST_CLOCK_TIME_NONE;
   GstBaseParseClass *klass = GST_BASE_PARSE_GET_CLASS (parse);
+  GstBuffer *buffer;
+
+  g_return_val_if_fail (frame != NULL, GST_FLOW_ERROR);
+  g_return_val_if_fail (frame->buffer != NULL, GST_FLOW_ERROR);
+
+  buffer = frame->buffer;
 
   GST_LOG_OBJECT (parse,
       "processing buffer of size %d with ts %" GST_TIME_FORMAT
@@ -1505,13 +1563,12 @@ gst_base_parse_push_buffer (GstBaseParse * parse, GstBuffer * buffer)
 
   /* update stats */
   parse->priv->bytecount += GST_BUFFER_SIZE (buffer);
-  if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BASE_PARSE_BUFFER_FLAG_NO_FRAME)) {
+  if (G_LIKELY (!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_NO_FRAME))) {
     parse->priv->framecount++;
     if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
       parse->priv->acc_duration += GST_BUFFER_DURATION (buffer);
     }
   }
-  GST_BUFFER_FLAG_UNSET (buffer, GST_BASE_PARSE_BUFFER_FLAG_NO_FRAME);
   if (parse->priv->update_interval &&
       (parse->priv->framecount % parse->priv->update_interval) == 0)
     gst_base_parse_update_duration (parse);
@@ -1525,8 +1582,6 @@ gst_base_parse_push_buffer (GstBaseParse * parse, GstBuffer * buffer)
   /* should have caps by now */
   g_return_val_if_fail (GST_PAD_CAPS (parse->srcpad), GST_FLOW_ERROR);
 
-  gst_buffer_set_caps (buffer, GST_PAD_CAPS (parse->srcpad));
-
   /* segment adjustment magic; only if we are running the whole show */
   if (!parse->priv->passthrough && parse->segment.rate > 0.0 &&
       (parse->priv->pad_mode == GST_ACTIVATE_PULL ||
@@ -1615,7 +1670,7 @@ gst_base_parse_push_buffer (GstBaseParse * parse, GstBuffer * buffer)
 
   /* update bitrates and optionally post corresponding tags
    * (following newsegment) */
-  gst_base_parse_update_bitrates (parse, buffer);
+  gst_base_parse_update_bitrates (parse, frame);
 
   if (G_UNLIKELY (parse->priv->pending_events)) {
     GList *l;
@@ -1627,15 +1682,26 @@ gst_base_parse_push_buffer (GstBaseParse * parse, GstBuffer * buffer)
     parse->priv->pending_events = NULL;
   }
 
-  if (klass->pre_push_buffer)
-    ret = klass->pre_push_buffer (parse, buffer);
-  else
-    ret = GST_BASE_PARSE_FLOW_CLIP;
+  if (klass->pre_push_frame) {
+    ret = klass->pre_push_frame (parse, frame);
+  } else {
+    frame->flags |= GST_BASE_PARSE_FRAME_FLAG_CLIP;
+  }
+
+  /* take final ownership of frame buffer */
+  buffer = frame->buffer;
+  frame->buffer = NULL;
+
+  /* subclass must play nice */
+  g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
+
+  /* decorate */
+  gst_buffer_set_caps (buffer, GST_PAD_CAPS (parse->srcpad));
 
   parse->priv->seen_keyframe |= parse->priv->is_video &&
       !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
 
-  if (ret == GST_BASE_PARSE_FLOW_CLIP) {
+  if (frame->flags & GST_BASE_PARSE_FRAME_FLAG_CLIP) {
     if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
         GST_CLOCK_TIME_IS_VALID (parse->segment.stop) &&
         GST_BUFFER_TIMESTAMP (buffer) >
@@ -1693,6 +1759,8 @@ gst_base_parse_push_buffer (GstBaseParse * parse, GstBuffer * buffer)
       parse->segment.last_stop < last_stop)
     gst_segment_set_last_stop (&parse->segment, GST_FORMAT_TIME, last_stop);
 
+  gst_base_parse_frame_clear (parse, frame);
+
   return ret;
 }
 
@@ -1879,16 +1947,19 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer)
   const guint8 *data;
   guint old_min_size = 0, min_size, av;
   GstClockTime timestamp;
+  GstBaseParseFrame _frame = { 0, };
+  GstBaseParseFrame *frame;
 
   parse = GST_BASE_PARSE (GST_OBJECT_PARENT (pad));
   bclass = GST_BASE_PARSE_GET_CLASS (parse);
+  frame = &_frame;
 
   if (G_LIKELY (buffer)) {
     GST_LOG_OBJECT (parse, "buffer size: %d, offset = %" G_GINT64_FORMAT,
         GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer));
     if (G_UNLIKELY (parse->priv->passthrough)) {
-      buffer = gst_buffer_make_metadata_writable (buffer);
-      return gst_base_parse_push_buffer (parse, buffer);
+      frame->buffer = gst_buffer_make_metadata_writable (buffer);
+      return gst_base_parse_push_frame (parse, frame);
     }
     /* upstream feeding us in reverse playback;
      * gather each fragment, then process it in single run */
@@ -1906,6 +1977,8 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer)
   /* Parse and push as many frames as possible */
   /* Stop either when adapter is empty or we are flushing */
   while (!parse->priv->flushing) {
+    gboolean res;
+
     tmpbuf = gst_buffer_new ();
 
     old_min_size = 0;
@@ -1949,7 +2022,10 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer)
       }
 
       skip = -1;
-      if (bclass->check_valid_frame (parse, tmpbuf, &fsize, &skip)) {
+      gst_base_parse_frame_update (parse, frame, tmpbuf);
+      res = bclass->check_valid_frame (parse, frame, &fsize, &skip);
+      gst_buffer_replace (&frame->buffer, NULL);
+      if (res) {
         if (gst_adapter_available (parse->adapter) < fsize) {
           GST_DEBUG_OBJECT (parse,
               "found valid frame but not enough data available (only %d bytes)",
@@ -2031,7 +2107,8 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer)
       parse->priv->prev_ts = parse->priv->next_ts = timestamp;
     }
 
-    ret = gst_base_parse_handle_and_push_buffer (parse, bclass, outbuf);
+    frame->buffer = outbuf;
+    ret = gst_base_parse_handle_and_push_frame (parse, bclass, frame);
     GST_PAD_STREAM_UNLOCK (parse->srcpad);
 
     if (ret != GST_FLOW_OK) {
@@ -2195,19 +2272,20 @@ exit:
  * ajusts sync, drain and offset going along */
 static GstFlowReturn
 gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass,
-    GstBuffer ** buf, gboolean full)
+    GstBaseParseFrame * frame, gboolean full)
 {
   GstBuffer *buffer, *outbuf;
   GstFlowReturn ret = GST_FLOW_OK;
   guint fsize = 0, min_size, old_min_size = 0;
   gint skip = 0;
 
-  g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
+  g_return_val_if_fail (frame != NULL, GST_FLOW_ERROR);
 
   GST_LOG_OBJECT (parse, "scanning for frame at offset %" G_GUINT64_FORMAT
       " (%#" G_GINT64_MODIFIER "x)", parse->priv->offset, parse->priv->offset);
 
   while (TRUE) {
+    gboolean res;
 
     min_size = MAX (parse->priv->min_frame_size, fsize);
     /* loop safety check */
@@ -2230,7 +2308,10 @@ gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass,
       parse->priv->drain = TRUE;
 
     skip = -1;
-    if (klass->check_valid_frame (parse, buffer, &fsize, &skip)) {
+    gst_base_parse_frame_update (parse, frame, buffer);
+    res = klass->check_valid_frame (parse, frame, &fsize, &skip);
+    gst_buffer_replace (&frame->buffer, NULL);
+    if (res) {
       parse->priv->drain = FALSE;
       GST_LOG_OBJECT (parse, "valid frame of size %d at pos %d", fsize, skip);
       break;
@@ -2289,7 +2370,7 @@ gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass,
 
   parse->priv->offset += fsize;
 
-  *buf = outbuf;
+  frame->buffer = outbuf;
 
 done:
   return ret;
@@ -2315,8 +2396,8 @@ gst_base_parse_loop (GstPad * pad)
 {
   GstBaseParse *parse;
   GstBaseParseClass *klass;
-  GstBuffer *outbuf;
   GstFlowReturn ret = GST_FLOW_OK;
+  GstBaseParseFrame frame = { 0, };
 
   parse = GST_BASE_PARSE (gst_pad_get_parent (pad));
   klass = GST_BASE_PARSE_GET_CLASS (parse);
@@ -2333,12 +2414,12 @@ gst_base_parse_loop (GstPad * pad)
     }
   }
 
-  ret = gst_base_parse_scan_frame (parse, klass, &outbuf, TRUE);
+  ret = gst_base_parse_scan_frame (parse, klass, &frame, TRUE);
   if (ret != GST_FLOW_OK)
     goto done;
 
-  /* This always unrefs the outbuf, even if error occurs */
-  ret = gst_base_parse_handle_and_push_buffer (parse, klass, outbuf);
+  /* This always cleans up frame, even if error occurs */
+  ret = gst_base_parse_handle_and_push_frame (parse, klass, &frame);
 
   /* eat expected eos signalling past segment in reverse playback */
   if (parse->segment.rate < 0.0 && ret == GST_FLOW_UNEXPECTED &&
@@ -2708,48 +2789,6 @@ gst_base_parse_set_frame_props (GstBaseParse * parse, guint fps_num,
       lead_out, parse->priv->lead_out_ts / GST_MSECOND);
 }
 
-/**
- * gst_base_parse_get_sync:
- * @parse: the #GstBaseParse to query
- *
- * Returns: TRUE if parser is considered 'in sync'.  That is, frames have been
- * continuously successfully parsed and pushed.
- */
-gboolean
-gst_base_parse_get_sync (GstBaseParse * parse)
-{
-  gboolean ret;
-
-  g_return_val_if_fail (parse != NULL, FALSE);
-
-  /* losing sync is pretty much a discont (and vice versa), no ? */
-  ret = !parse->priv->discont;
-
-  GST_DEBUG_OBJECT (parse, "sync: %d", ret);
-  return ret;
-}
-
-/**
- * gst_base_parse_get_drain:
- * @parse: the #GstBaseParse to query
- *
- * Returns: TRUE if parser is currently 'draining'.  That is, leftover data
- * (e.g. in FLUSH or EOS situation) is being parsed.
- */
-gboolean
-gst_base_parse_get_drain (GstBaseParse * parse)
-{
-  gboolean ret;
-
-  g_return_val_if_fail (parse != NULL, FALSE);
-
-  /* losing sync is pretty much a discont (and vice versa), no ? */
-  ret = parse->priv->drain;
-
-  GST_DEBUG_OBJECT (parse, "drain: %d", ret);
-  return ret;
-}
-
 static gboolean
 gst_base_parse_get_duration (GstBaseParse * parse, GstFormat format,
     GstClockTime * duration)
@@ -2941,6 +2980,7 @@ gst_base_parse_find_frame (GstBaseParse * parse, gint64 * pos,
   gboolean orig_drain, orig_discont;
   GstFlowReturn ret = GST_FLOW_OK;
   GstBuffer *buf = NULL;
+  GstBaseParseFrame frame = { 0, };
 
   g_return_val_if_fail (GST_FLOW_ERROR, pos != NULL);
   g_return_val_if_fail (GST_FLOW_ERROR, time != NULL);
@@ -2961,10 +3001,11 @@ gst_base_parse_find_frame (GstBaseParse * parse, gint64 * pos,
 
   /* jump elsewhere and locate next frame */
   parse->priv->offset = *pos;
-  ret = gst_base_parse_scan_frame (parse, klass, &buf, FALSE);
+  ret = gst_base_parse_scan_frame (parse, klass, &frame, FALSE);
   if (ret != GST_FLOW_OK)
     goto done;
 
+  buf = frame.buffer;
   GST_LOG_OBJECT (parse,
       "peek parsing frame at offset %" G_GUINT64_FORMAT
       " (%#" G_GINT64_MODIFIER "x) of size %d",
@@ -2972,12 +3013,13 @@ gst_base_parse_find_frame (GstBaseParse * parse, gint64 * pos,
 
   /* get offset first, subclass parsing might dump other stuff in there */
   *pos = GST_BUFFER_OFFSET (buf);
-  ret = klass->parse_frame (parse, buf);
+  ret = klass->parse_frame (parse, &frame);
+  buf = frame.buffer;
 
   /* but it should provide proper time */
   *time = GST_BUFFER_TIMESTAMP (buf);
   *duration = GST_BUFFER_DURATION (buf);
-  gst_buffer_unref (buf);
+  gst_base_parse_frame_clear (parse, &frame);
 
   GST_LOG_OBJECT (parse,
       "frame with time %" GST_TIME_FORMAT " at offset %" G_GINT64_FORMAT,
index 5a4b674..d5d4415 100644 (file)
@@ -90,25 +90,78 @@ G_BEGIN_DECLS
 #define GST_BASE_PARSE_FLOW_DROPPED   GST_FLOW_CUSTOM_SUCCESS
 
 /**
- * GST_BASE_PARSE_FLOW_CLIP:
+ * GstBaseParseFrameFlags:
+ * @GST_BASE_PARSE_FRAME_FLAG_NONE: no flag
+ * @GST_BASE_PARSE_FRAME_FLAG_SYNC: indicates if parsing is 'in sync'
+ * @GST_BASE_PARSE_FRAME_FLAG_DRAIN: indicates if parser is 'draining'.
+ *   That is, leftover data (e.g. in FLUSH or EOS situation) is being parsed.
+ * @GST_BASE_PARSE_FRAME_FLAG_NO_FRAME: set to indicate this buffer should not be
+ *   counted as frame, e.g. if this frame is dependent on a previous one.
+ *   As it is not counted as a frame, bitrate increases but frame to time
+ *   conversions are maintained.
+ * @GST_BASE_PARSE_FRAME_FLAG_CLIP: @pre_push_buffer can set this to indicate
+ *    that regular segment clipping can still be performed (as opposed to
+ *    any custom one having been done).
  *
- * A #GstFlowReturn that can be returned from pre_push_buffer to
- * indicate that regular segment clipping should be performed.
+ * Flags to be used in a #GstBaseParseFrame.
  *
  * Since: 0.10.x
  */
-#define GST_BASE_PARSE_FLOW_CLIP      GST_FLOW_CUSTOM_SUCCESS_1
+typedef enum {
+  GST_BASE_PARSE_FRAME_FLAG_NONE         = 0,
+  GST_BASE_PARSE_FRAME_FLAG_SYNC         = (1 << 0),
+  GST_BASE_PARSE_FRAME_FLAG_DRAIN        = (1 << 1),
+  GST_BASE_PARSE_FRAME_FLAG_NO_FRAME     = (1 << 2),
+  GST_BASE_PARSE_FRAME_FLAG_CLIP         = (1 << 3)
+} GstBaseParseFrameFlags;
 
 /**
- * GST_BASE_PARSE_BUFFER_FLAG_NO_FRAME:
+ * GstBaseParseFrame:
+ * @buffer: data to check for valid frame or parsed frame.
+ *   Subclass is allowed to replace this buffer.
+ * @overhead: subclass can set this to indicates the metadata overhead
+ *   for the given frame, which is then used to enable more accurate bitrate
+ *   computations. If this is -1, it is assumed that this frame should be
+ *   skipped in bitrate calculation.
+ * @flags: a combination of input and output #GstBaseParseFrameFlags that
+ *  convey additional context to subclass or allow subclass to tune
+ *  subsequent #GstBaseParse actions.
  *
- * A #GstBufferFlag that can be set to have this buffer not counted as frame,
- * e.g. if this frame is dependent on a previous one.  As it is not counted as
- * a frame, bitrate increases but frame to time conversions are maintained.
+ * Frame (context) data passed to each frame parsing virtual methods.  In
+ * addition to providing the data to be checked for a valid frame or an already
+ * identified frame, it conveys additional metadata or control information
+ * from and to the subclass w.r.t. the particular frame in question (rather
+ * than global parameters).  Some of these may apply to each parsing stage, others
+ * only to some a particular one.  These parameters are effectively zeroed at start
+ * of each frame's processing, i.e. parsing virtual method invocation sequence.
  *
  * Since: 0.10.x
  */
-#define GST_BASE_PARSE_BUFFER_FLAG_NO_FRAME     GST_BUFFER_FLAG_LAST
+typedef struct {
+  GstBuffer       *buffer;
+  guint           flags;
+  gint            overhead;
+} GstBaseParseFrame;
+
+/**
+ * GST_BASE_PARSE_FRAME_SYNC:
+ * @frame: base parse frame instance
+ *
+ * Obtains current sync status indicated in frame.
+ *
+ * Since: 0.10.x
+ */
+#define GST_BASE_PARSE_FRAME_SYNC(frame)     (!!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_SYNC))
+
+/**
+ * GST_BASE_PARSE_FRAME_DRAIN:
+ * @frame: base parse frame instance
+ *
+ * Obtains current drain status indicated in frame.
+ *
+ * Since: 0.10.x
+ */
+#define GST_BASE_PARSE_FRAME_DRAIN(frame)    (!!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_DRAIN))
 
 
 /**
@@ -118,6 +171,8 @@ G_BEGIN_DECLS
  * GST_BASE_PARSE_SEEK_TABLE: Additional metadata provides more accurate seeking.
  *
  * Indicates what level (of quality) of seeking is possible.
+ *
+ * Since: 0.10.x
  */
 typedef enum _GstBaseParseSeekable {
   GST_BASE_PARSE_SEEK_NONE,
@@ -221,12 +276,15 @@ struct _GstBaseParseClass {
                                        GstCaps *caps);
 
   gboolean      (*check_valid_frame)  (GstBaseParse *parse,
-                                       GstBuffer *buffer,
+                                       GstBaseParseFrame *frame,
                                        guint *framesize,
                                        gint *skipsize);
 
   GstFlowReturn (*parse_frame)        (GstBaseParse *parse,
-                                       GstBuffer *buffer);
+                                       GstBaseParseFrame *frame);
+
+  GstFlowReturn (*pre_push_frame)     (GstBaseParse *parse,
+                                       GstBaseParseFrame *frame);
 
   gboolean      (*convert)            (GstBaseParse * parse,
                                        GstFormat src_format,
@@ -240,21 +298,16 @@ struct _GstBaseParseClass {
   gboolean      (*src_event)          (GstBaseParse *parse,
                                        GstEvent *event);
 
-  gint          (*get_frame_overhead) (GstBaseParse *parse,
-                                       GstBuffer *buf);
-
-  GstFlowReturn (*pre_push_buffer)    (GstBaseParse *parse,
-                                       GstBuffer *buf);
-
   /*< private >*/
-  gpointer       _gst_reserved[GST_PADDING_LARGE];  
+  gpointer       _gst_reserved[GST_PADDING_LARGE];
 };
 
 GType           gst_base_parse_get_type         (void);
 
+void gst_base_parse_frame_init (GstBaseParse * parse, GstBaseParseFrame * frame);
 
-GstFlowReturn gst_base_parse_push_buffer (GstBaseParse *parse,
-                                          GstBuffer *buffer);
+GstFlowReturn gst_base_parse_push_frame (GstBaseParse *parse,
+                                          GstBaseParseFrame *frame);
 
 void gst_base_parse_set_duration (GstBaseParse *parse,
                                   GstFormat fmt, gint64 duration, gint interval);
@@ -262,17 +315,13 @@ void gst_base_parse_set_duration (GstBaseParse *parse,
 void gst_base_parse_set_seek (GstBaseParse * parse,
                               GstBaseParseSeekable seek, guint bitrate);
 
-void gst_base_parse_set_min_frame_size (GstBaseParse *parse,
-                                        guint min_size);
+void gst_base_parse_set_min_frame_size (GstBaseParse *parse, guint min_size);
+
 void gst_base_parse_set_passthrough (GstBaseParse * parse, gboolean passthrough);
 
 void gst_base_parse_set_frame_props (GstBaseParse * parse, guint fps_num,
                                      guint fps_den, guint lead_in, guint lead_out);
 
-gboolean gst_base_parse_get_sync (GstBaseParse * parse);
-
-gboolean gst_base_parse_get_drain (GstBaseParse * parse);
-
 gboolean gst_base_parse_convert_default (GstBaseParse * parse,
                                          GstFormat src_format, gint64 src_value,
                                          GstFormat dest_format, gint64 * dest_value);