+/* makes sure that @buf is properly prepared and decorated for passing
+ * to baseclass, and an equally setup frame is returned setup with @buf.
+ * Takes ownership of @buf. */
+static GstBaseParseFrame *
+gst_base_parse_prepare_frame (GstBaseParse * parse, GstBuffer * buffer)
+{
+ GstBaseParseFrame *frame = NULL;
+
+ buffer = gst_buffer_make_writable (buffer);
+
+ GST_LOG_OBJECT (parse,
+ "preparing frame at offset %" G_GUINT64_FORMAT
+ " (%#" G_GINT64_MODIFIER "x) of size %" G_GSIZE_FORMAT,
+ GST_BUFFER_OFFSET (buffer), GST_BUFFER_OFFSET (buffer),
+ gst_buffer_get_size (buffer));
+
+ if (parse->priv->discont) {
+ GST_DEBUG_OBJECT (parse, "marking DISCONT");
+ GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
+ parse->priv->discont = FALSE;
+ }
+
+ GST_BUFFER_OFFSET (buffer) = parse->priv->offset;
+
+ if (parse->priv->prev_frame) {
+ if (parse->priv->prev_offset == parse->priv->offset) {
+ frame = parse->priv->prev_frame;
+ } else {
+ gst_base_parse_frame_free (parse->priv->prev_frame);
+ }
+ parse->priv->prev_frame = NULL;
+ }
+
+ if (!frame) {
+ frame = gst_base_parse_frame_new (buffer, 0, 0);
+ }
+
+ /* also ensure to update state flags */
+ gst_base_parse_frame_update (parse, frame, buffer);
+ gst_buffer_unref (buffer);
+
+ frame->offset = parse->priv->prev_offset = parse->priv->offset;
+
+ /* use default handler to provide initial (upstream) metadata */
+ gst_base_parse_parse_frame (parse, frame);
+
+ return frame;
+}
+
+static void
+gst_base_parse_unprepare_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
+{
+ g_assert (parse->priv->prev_frame == NULL);
+
+ parse->priv->prev_frame = frame;
+ gst_base_parse_frame_update (parse, frame, NULL);
+}
+
+/* takes ownership of @buffer */
+static GstFlowReturn
+gst_base_parse_handle_buffer (GstBaseParse * parse, GstBuffer * buffer,
+ gint * skip, gint * flushed)
+{
+ GstBaseParseClass *klass = GST_BASE_PARSE_GET_CLASS (parse);
+ GstBaseParseFrame *frame;
+ GstFlowReturn ret;
+
+ g_return_val_if_fail (skip != NULL || flushed != NULL, GST_FLOW_ERROR);
+
+ /* track what is being flushed during this single round of frame processing */
+ parse->priv->flushed = 0;
+ *skip = 0;
+
+ /* make it easy for _finish_frame to pick up input data */
+ if (parse->priv->pad_mode == GST_PAD_MODE_PULL) {
+ gst_buffer_ref (buffer);
+ gst_adapter_push (parse->priv->adapter, buffer);
+ }
+
+ frame = gst_base_parse_prepare_frame (parse, buffer);
+ ret = klass->handle_frame (parse, frame, skip);
+ gst_base_parse_unprepare_frame (parse, frame);
+
+ if (parse->priv->pad_mode == GST_PAD_MODE_PULL) {
+ gst_adapter_clear (parse->priv->adapter);
+ }
+
+ *flushed = parse->priv->flushed;
+
+ GST_LOG_OBJECT (parse, "handle_frame skipped %d, flushed %d",
+ *skip, *flushed);
+
+ /* subclass can only do one of these, or semantics are too unclear */
+ g_assert (*skip == 0 || *flushed == 0);
+
+ /* if it did something, clear frame state,
+ * though this should also trigger the offset check anyway */
+ if (*skip != 0 || *flushed != 0) {
+ GST_LOG_OBJECT (parse, "clearing prev frame");
+ gst_base_parse_frame_free (parse->priv->prev_frame);
+ parse->priv->prev_frame = NULL;
+ }
+
+ parse->priv->offset += *flushed;
+
+#ifndef GST_DISABLE_GST_DEBUG
+ if (ret != GST_FLOW_OK) {
+ GST_DEBUG_OBJECT (parse, "handle_frame returned %d", ret);
+ }
+#endif
+
+ return ret;
+}
+