static GstFlowReturn gst_rsvg_dec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame) { GstRsvgDec *rsvg = GST_RSVG_DEC (decoder); gboolean ret; ret = gst_rsvg_decode_image (rsvg, frame->input_buffer, frame); switch (ret) { case GST_FLOW_OK: ret = gst_video_decoder_finish_frame (decoder, frame); break; default: gst_video_codec_frame_unref (frame); break; } GST_LOG_OBJECT (rsvg, "Handle frame done"); return ret; }
static GstFlowReturn gst_rsvg_dec_chain (GstPad * pad, GstBuffer * buffer) { GstRsvgDec *rsvg = GST_RSVG_DEC (GST_PAD_PARENT (pad)); gboolean completed = FALSE; const guint8 *data; guint size; gboolean ret = GST_FLOW_OK; /* first_timestamp is used slightly differently where a framerate is given or not. If there is a frame rate, it will be used as a base. If there is not, it will be used to keep track of the timestamp of the first buffer, to be used as the timestamp of the output buffer. When a buffer is output, first timestamp will resync to the next buffer's timestamp. */ if (rsvg->first_timestamp == GST_CLOCK_TIME_NONE) { if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) rsvg->first_timestamp = GST_BUFFER_TIMESTAMP (buffer); else if (rsvg->fps_n != 0) rsvg->first_timestamp = 0; } gst_adapter_push (rsvg->adapter, buffer); size = gst_adapter_available (rsvg->adapter); /* "<svg></svg>" */ while (size >= 5 + 6 && ret == GST_FLOW_OK) { guint i; data = gst_adapter_peek (rsvg->adapter, size); for (i = size - 6; i >= 5; i--) { if (memcmp (data + i, "</svg>", 6) == 0) { completed = TRUE; size = i + 6; break; } } if (completed) { GstBuffer *outbuf = NULL; GST_LOG_OBJECT (rsvg, "have complete svg of %u bytes", size); data = gst_adapter_peek (rsvg->adapter, size); ret = gst_rsvg_decode_image (rsvg, data, size, &outbuf); if (ret != GST_FLOW_OK) break; if (rsvg->first_timestamp != GST_CLOCK_TIME_NONE) { GST_BUFFER_TIMESTAMP (outbuf) = rsvg->first_timestamp; GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE; if (GST_BUFFER_DURATION_IS_VALID (buffer)) { GstClockTime end = GST_BUFFER_TIMESTAMP_IS_VALID (buffer) ? GST_BUFFER_TIMESTAMP (buffer) : rsvg->first_timestamp; end += GST_BUFFER_DURATION (buffer); GST_BUFFER_DURATION (outbuf) = end - GST_BUFFER_TIMESTAMP (outbuf); } if (rsvg->fps_n == 0) { rsvg->first_timestamp = GST_CLOCK_TIME_NONE; } else { GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale (rsvg->frame_count, rsvg->fps_d, rsvg->fps_n * GST_SECOND); } } else if (rsvg->fps_n != 0) { GST_BUFFER_TIMESTAMP (outbuf) = rsvg->first_timestamp + gst_util_uint64_scale (rsvg->frame_count, rsvg->fps_d, rsvg->fps_n * GST_SECOND); GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale (rsvg->frame_count, rsvg->fps_d, rsvg->fps_n * GST_SECOND); } else { GST_BUFFER_TIMESTAMP (outbuf) = rsvg->first_timestamp; GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE; } rsvg->frame_count++; if (rsvg->need_newsegment) { gst_pad_push_event (rsvg->srcpad, gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0)); rsvg->need_newsegment = FALSE; } if (rsvg->pending_events) { GList *l; for (l = rsvg->pending_events; l; l = l->next) gst_pad_push_event (rsvg->srcpad, l->data); g_list_free (rsvg->pending_events); rsvg->pending_events = NULL; } GST_LOG_OBJECT (rsvg, "image rendered okay"); ret = gst_pad_push (rsvg->srcpad, outbuf); if (ret != GST_FLOW_OK) break; gst_adapter_flush (rsvg->adapter, size); size = gst_adapter_available (rsvg->adapter); continue; } else { break; } } return GST_FLOW_OK; }
static GstFlowReturn gst_rsvg_dec_chain (GstPad * pad, GstBuffer * buffer) { GstRsvgDec *rsvg = GST_RSVG_DEC (gst_pad_get_parent (pad)); gboolean completed = FALSE; const guint8 *data; guint size; gboolean ret = GST_FLOW_OK; if (rsvg->timestamp_offset == GST_CLOCK_TIME_NONE) { if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) rsvg->timestamp_offset = GST_BUFFER_TIMESTAMP (buffer); else rsvg->timestamp_offset = 0; } gst_adapter_push (rsvg->adapter, buffer); size = gst_adapter_available (rsvg->adapter); /* "<svg></svg>" */ while (size >= 5 + 6 && ret == GST_FLOW_OK) { guint i; data = gst_adapter_peek (rsvg->adapter, size); for (i = size - 6; i >= 5; i--) { if (memcmp (data + i, "</svg>", 6) == 0) { completed = TRUE; size = i + 6; break; } } if (completed) { GstBuffer *outbuf = NULL; data = gst_adapter_peek (rsvg->adapter, size); ret = gst_rsvg_decode_image (rsvg, data, size, &outbuf); if (ret != GST_FLOW_OK) break; if (rsvg->fps_n != 0) { GST_BUFFER_TIMESTAMP (outbuf) = rsvg->timestamp_offset + gst_util_uint64_scale (rsvg->frame_count, rsvg->fps_d, rsvg->fps_n * GST_SECOND); GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale (rsvg->frame_count, rsvg->fps_d, rsvg->fps_n * GST_SECOND); } else { GST_BUFFER_TIMESTAMP (outbuf) = 0; } rsvg->frame_count++; if (rsvg->need_newsegment) { gst_pad_push_event (rsvg->srcpad, gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0)); rsvg->need_newsegment = FALSE; } if (rsvg->pending_events) { GList *l; for (l = rsvg->pending_events; l; l = l->next) gst_pad_push_event (rsvg->srcpad, l->data); g_list_free (rsvg->pending_events); rsvg->pending_events = NULL; } if (rsvg->pending_tags) { gst_element_found_tags (GST_ELEMENT_CAST (rsvg), rsvg->pending_tags); rsvg->pending_tags = NULL; } ret = gst_pad_push (rsvg->srcpad, outbuf); if (ret != GST_FLOW_OK) break; gst_adapter_flush (rsvg->adapter, size); size = gst_adapter_available (rsvg->adapter); continue; } else { break; } } gst_object_unref (rsvg); return GST_FLOW_OK; }