...and also clear all existing frames when resetting the decoder or encoder.
static GstStateChangeReturn gst_base_video_codec_change_state (GstElement *
element, GstStateChange transition);
+G_DEFINE_BOXED_TYPE (GstVideoState, gst_video_frame,
+ (GBoxedCopyFunc) gst_video_frame_ref,
+ (GBoxedFreeFunc) gst_video_frame_unref);
GST_BOILERPLATE (GstBaseVideoCodec, gst_base_video_codec, GstElement,
GST_TYPE_ELEMENT);
GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_codec);
for (g = base_video_codec->frames; g; g = g_list_next (g)) {
- gst_base_video_codec_free_frame ((GstVideoFrame *) g->data);
+ gst_video_frame_unref ((GstVideoFrame *) g->data);
}
g_list_free (base_video_codec->frames);
base_video_codec->frames = NULL;
frame = g_slice_new0 (GstVideoFrame);
+ frame->ref_count = 1;
+
GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_codec);
frame->system_frame_number = base_video_codec->system_frame_number;
base_video_codec->system_frame_number++;
GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_codec);
+ GST_LOG_OBJECT (base_video_codec, "Created new frame %p (sfn:%d)",
+ frame, frame->system_frame_number);
+
return frame;
}
-void
-gst_base_video_codec_free_frame (GstVideoFrame * frame)
+static void
+_gst_video_frame_free (GstVideoFrame * frame)
{
g_return_if_fail (frame != NULL);
g_slice_free (GstVideoFrame, frame);
}
+
+GstVideoFrame *
+gst_video_frame_ref (GstVideoFrame * frame)
+{
+ g_return_val_if_fail (frame != NULL, NULL);
+
+ g_atomic_int_inc (&frame->ref_count);
+
+ return frame;
+}
+
+void
+gst_video_frame_unref (GstVideoFrame * frame)
+{
+ g_return_if_fail (frame != NULL);
+ g_return_if_fail (frame->ref_count > 0);
+
+ if (g_atomic_int_dec_and_test (&frame->ref_count)) {
+ _gst_video_frame_free (frame);
+ }
+}
struct _GstVideoFrame
{
+ gint ref_count;
+
GstClockTime decode_timestamp;
GstClockTime presentation_timestamp;
GstClockTime presentation_duration;
void *padding[GST_PADDING_LARGE];
};
+GType gst_video_frame_get_type (void);
GType gst_base_video_codec_get_type (void);
GstVideoFrame * gst_base_video_codec_new_frame (GstBaseVideoCodec *base_video_codec);
-void gst_base_video_codec_free_frame (GstVideoFrame *frame);
+
+GstVideoFrame * gst_video_frame_ref (GstVideoFrame * frame);
+void gst_video_frame_unref (GstVideoFrame * frame);
G_END_DECLS
g_list_foreach (dec->gather, (GFunc) gst_mini_object_unref, NULL);
g_list_free (dec->gather);
dec->gather = NULL;
- g_list_foreach (dec->decode, (GFunc) gst_base_video_codec_free_frame, NULL);
+ g_list_foreach (dec->decode, (GFunc) gst_video_frame_unref, NULL);
g_list_free (dec->decode);
dec->decode = NULL;
g_list_foreach (dec->parse, (GFunc) gst_mini_object_unref, NULL);
g_list_free (dec->parse);
dec->parse = NULL;
- g_list_foreach (dec->parse_gather, (GFunc) gst_base_video_codec_free_frame,
- NULL);
+ g_list_foreach (dec->parse_gather, (GFunc) gst_video_frame_unref, NULL);
g_list_free (dec->parse_gather);
dec->parse_gather = NULL;
+ g_list_foreach (GST_BASE_VIDEO_CODEC (dec)->frames,
+ (GFunc) gst_video_frame_unref, NULL);
+ g_list_free (GST_BASE_VIDEO_CODEC (dec)->frames);
+ GST_BASE_VIDEO_CODEC (dec)->frames = NULL;
}
static void
base_video_decoder->timestamps = NULL;
if (base_video_decoder->current_frame) {
- gst_base_video_codec_free_frame (base_video_decoder->current_frame);
+ gst_video_frame_unref (base_video_decoder->current_frame);
base_video_decoder->current_frame = NULL;
}
next = g_list_next (walk);
if (dec->current_frame)
- gst_base_video_codec_free_frame (dec->current_frame);
+ gst_video_frame_unref (dec->current_frame);
dec->current_frame = frame;
+ gst_video_frame_ref (dec->current_frame);
+
/* decode buffer, resulting data prepended to queue */
res = gst_base_video_decoder_have_frame_2 (dec);
GST_BASE_VIDEO_CODEC (dec)->frames =
g_list_remove (GST_BASE_VIDEO_CODEC (dec)->frames, frame);
- if (frame->src_buffer)
- gst_buffer_unref (frame->src_buffer);
-
- gst_base_video_codec_free_frame (frame);
+ gst_video_frame_unref (frame);
}
/**
}
exit:
+ /* current frame has either been added to parse_gather or sent to
+ handle frame so there is no need to unref it */
+
/* create new frame */
base_video_decoder->current_frame =
gst_base_video_decoder_new_frame (base_video_decoder);
/* everything should be away now */
if (codec->frames) {
/* not fatal/impossible though if subclass/codec eats stuff */
- GST_WARNING_OBJECT (enc, "still %d frames left after draining",
- g_list_length (codec->frames));
-#if 0
- /* FIXME should do this, but subclass may come up with it later on ?
- * and would then need refcounting or so on frames */
- g_list_foreach (codec->frames,
- (GFunc) gst_base_video_codec_free_frame, NULL);
-#endif
+ g_list_foreach (codec->frames, (GFunc) gst_video_frame_unref, NULL);
+ g_list_free (codec->frames);
+ codec->frames = NULL;
}
return ret;
GST_BASE_VIDEO_CODEC (base_video_encoder)->frames =
g_list_remove (GST_BASE_VIDEO_CODEC (base_video_encoder)->frames, frame);
- gst_base_video_codec_free_frame (frame);
+ gst_video_frame_unref (frame);
GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_encoder);