mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 01:00:37 +00:00
ext/theora/: Mark discontinuities of > 3/4 of a frame, reinit encoder.
Original commit message from CVS: * ext/theora/gsttheoraenc.h: * ext/theora/theoraenc.c: (gst_theora_enc_init), (theora_enc_reset), (theora_enc_clear), (theora_enc_sink_setcaps), (theora_buffer_from_packet), (theora_enc_is_discontinuous), (theora_enc_chain), (theora_enc_change_state): Mark discontinuities of > 3/4 of a frame, reinit encoder. * tests/check/pipelines/theoraenc.c: (check_buffer_granulepos), (GST_START_TEST), (theoraenc_suite): Enable discontinuity test, fix it.
This commit is contained in:
parent
60ad667761
commit
32500268de
4 changed files with 93 additions and 10 deletions
13
ChangeLog
13
ChangeLog
|
@ -1,3 +1,16 @@
|
||||||
|
2006-11-22 Michael Smith <msmith@fluendo.com>
|
||||||
|
|
||||||
|
* ext/theora/gsttheoraenc.h:
|
||||||
|
* ext/theora/theoraenc.c: (gst_theora_enc_init),
|
||||||
|
(theora_enc_reset), (theora_enc_clear), (theora_enc_sink_setcaps),
|
||||||
|
(theora_buffer_from_packet), (theora_enc_is_discontinuous),
|
||||||
|
(theora_enc_chain), (theora_enc_change_state):
|
||||||
|
Mark discontinuities of > 3/4 of a frame, reinit encoder.
|
||||||
|
|
||||||
|
* tests/check/pipelines/theoraenc.c: (check_buffer_granulepos),
|
||||||
|
(GST_START_TEST), (theoraenc_suite):
|
||||||
|
Enable discontinuity test, fix it.
|
||||||
|
|
||||||
2006-11-21 Tim-Philipp Müller <tim at centricular dot net>
|
2006-11-21 Tim-Philipp Müller <tim at centricular dot net>
|
||||||
|
|
||||||
* ext/pango/gsttextoverlay.c: (gst_text_overlay_init),
|
* ext/pango/gsttextoverlay.c: (gst_text_overlay_init),
|
||||||
|
|
|
@ -93,6 +93,9 @@ struct _GstTheoraEnc
|
||||||
gint fps_n, fps_d;
|
gint fps_n, fps_d;
|
||||||
GstClockTime next_ts;
|
GstClockTime next_ts;
|
||||||
|
|
||||||
|
GstClockTime expected_ts;
|
||||||
|
gboolean next_discont;
|
||||||
|
|
||||||
guint packetno;
|
guint packetno;
|
||||||
guint64 bytes_out;
|
guint64 bytes_out;
|
||||||
guint64 granulepos_offset;
|
guint64 granulepos_offset;
|
||||||
|
|
|
@ -292,6 +292,7 @@ gst_theora_enc_init (GstTheoraEnc * enc, GstTheoraEncClass * g_class)
|
||||||
GST_DEBUG_OBJECT (enc,
|
GST_DEBUG_OBJECT (enc,
|
||||||
"keyframe_frequency_force is %d, granule shift is %d",
|
"keyframe_frequency_force is %d, granule shift is %d",
|
||||||
enc->info.keyframe_frequency_force, enc->granule_shift);
|
enc->info.keyframe_frequency_force, enc->granule_shift);
|
||||||
|
enc->expected_ts = GST_CLOCK_TIME_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -307,6 +308,26 @@ theora_enc_finalize (GObject * object)
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
theora_enc_reset (GstTheoraEnc * enc)
|
||||||
|
{
|
||||||
|
theora_clear (&enc->state);
|
||||||
|
theora_encode_init (&enc->state, &enc->info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
theora_enc_clear (GstTheoraEnc * enc)
|
||||||
|
{
|
||||||
|
enc->packetno = 0;
|
||||||
|
enc->bytes_out = 0;
|
||||||
|
enc->granulepos_offset = 0;
|
||||||
|
enc->timestamp_offset = 0;
|
||||||
|
|
||||||
|
enc->next_ts = GST_CLOCK_TIME_NONE;
|
||||||
|
enc->next_discont = FALSE;
|
||||||
|
enc->expected_ts = GST_CLOCK_TIME_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
|
theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
{
|
{
|
||||||
|
@ -374,7 +395,7 @@ theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
"keyframe_frequency_force is %d, granule shift is %d",
|
"keyframe_frequency_force is %d, granule shift is %d",
|
||||||
enc->info.keyframe_frequency_force, enc->granule_shift);
|
enc->info.keyframe_frequency_force, enc->granule_shift);
|
||||||
|
|
||||||
theora_encode_init (&enc->state, &enc->info);
|
theora_enc_reset (enc);
|
||||||
|
|
||||||
gst_object_unref (enc);
|
gst_object_unref (enc);
|
||||||
|
|
||||||
|
@ -418,6 +439,11 @@ theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet,
|
||||||
GST_BUFFER_TIMESTAMP (buf) = timestamp + enc->timestamp_offset;
|
GST_BUFFER_TIMESTAMP (buf) = timestamp + enc->timestamp_offset;
|
||||||
GST_BUFFER_DURATION (buf) = duration;
|
GST_BUFFER_DURATION (buf) = duration;
|
||||||
|
|
||||||
|
if (enc->next_discont) {
|
||||||
|
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
|
||||||
|
enc->next_discont = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* the second most significant bit of the first data byte is cleared
|
/* the second most significant bit of the first data byte is cleared
|
||||||
* for keyframes */
|
* for keyframes */
|
||||||
if ((packet->packet[0] & 0x40) == 0) {
|
if ((packet->packet[0] & 0x40) == 0) {
|
||||||
|
@ -543,6 +569,34 @@ theora_enc_sink_event (GstPad * pad, GstEvent * event)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
theora_enc_is_discontinuous (GstTheoraEnc * enc, GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
GstClockTime ts = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
|
GstClockTimeDiff max_diff;
|
||||||
|
|
||||||
|
/* Allow 3/4 a frame off */
|
||||||
|
max_diff = (enc->info.fps_denominator * GST_SECOND * 3) /
|
||||||
|
(enc->info.fps_numerator * 4);
|
||||||
|
|
||||||
|
if (ts != GST_CLOCK_TIME_NONE && enc->expected_ts != GST_CLOCK_TIME_NONE) {
|
||||||
|
if ((GstClockTimeDiff) (ts - enc->expected_ts) > max_diff) {
|
||||||
|
GST_DEBUG_OBJECT (enc, "Incoming TS %" GST_TIME_FORMAT
|
||||||
|
" exceeds expected value %" GST_TIME_FORMAT
|
||||||
|
" by too much, marking discontinuity",
|
||||||
|
GST_TIME_ARGS (ts), GST_TIME_ARGS (enc->expected_ts));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)))
|
||||||
|
enc->expected_ts = ts + GST_BUFFER_DURATION (buffer);
|
||||||
|
else
|
||||||
|
enc->expected_ts = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
theora_enc_chain (GstPad * pad, GstBuffer * buffer)
|
theora_enc_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
|
@ -784,6 +838,16 @@ theora_enc_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
buffer = newbuf;
|
buffer = newbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (theora_enc_is_discontinuous (enc, buffer)) {
|
||||||
|
theora_enc_reset (enc);
|
||||||
|
enc->granulepos_offset =
|
||||||
|
gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buffer), enc->fps_n,
|
||||||
|
GST_SECOND * enc->fps_d);
|
||||||
|
enc->timestamp_offset = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
|
enc->next_ts = 0;
|
||||||
|
enc->next_discont = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
res = theora_encode_YUVin (&enc->state, &yuv);
|
res = theora_encode_YUVin (&enc->state, &yuv);
|
||||||
|
|
||||||
ret = GST_FLOW_OK;
|
ret = GST_FLOW_OK;
|
||||||
|
@ -863,6 +927,8 @@ theora_enc_change_state (GstElement * element, GstStateChange transition)
|
||||||
theora_clear (&enc->state);
|
theora_clear (&enc->state);
|
||||||
theora_comment_clear (&enc->comment);
|
theora_comment_clear (&enc->comment);
|
||||||
theora_info_clear (&enc->info);
|
theora_info_clear (&enc->info);
|
||||||
|
|
||||||
|
theora_enc_clear (enc);
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -62,6 +62,7 @@ static void
|
||||||
check_buffer_granulepos (GstBuffer * buffer, gint64 granulepos)
|
check_buffer_granulepos (GstBuffer * buffer, gint64 granulepos)
|
||||||
{
|
{
|
||||||
GstClockTime clocktime;
|
GstClockTime clocktime;
|
||||||
|
int framecount;
|
||||||
|
|
||||||
fail_unless (GST_BUFFER_OFFSET_END (buffer) == granulepos,
|
fail_unless (GST_BUFFER_OFFSET_END (buffer) == granulepos,
|
||||||
"expected granulepos %" G_GUINT64_FORMAT
|
"expected granulepos %" G_GUINT64_FORMAT
|
||||||
|
@ -70,8 +71,10 @@ check_buffer_granulepos (GstBuffer * buffer, gint64 granulepos)
|
||||||
|
|
||||||
/* contrary to what we record as TIMESTAMP, we can use OFFSET to check
|
/* contrary to what we record as TIMESTAMP, we can use OFFSET to check
|
||||||
* the granulepos correctly here */
|
* the granulepos correctly here */
|
||||||
clocktime = gst_util_uint64_scale (GST_BUFFER_OFFSET_END (buffer), GST_SECOND,
|
framecount = GST_BUFFER_OFFSET_END (buffer);
|
||||||
FRAMERATE);
|
framecount = granulepos >> GRANULEPOS_SHIFT;
|
||||||
|
framecount += granulepos & ((1 << GRANULEPOS_SHIFT) - 1);
|
||||||
|
clocktime = gst_util_uint64_scale (framecount, GST_SECOND, FRAMERATE);
|
||||||
|
|
||||||
fail_unless (clocktime == GST_BUFFER_OFFSET (buffer),
|
fail_unless (clocktime == GST_BUFFER_OFFSET (buffer),
|
||||||
"expected OFFSET set to clocktime %" GST_TIME_FORMAT
|
"expected OFFSET set to clocktime %" GST_TIME_FORMAT
|
||||||
|
@ -287,7 +290,6 @@ GST_START_TEST (test_continuity)
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
#if 0
|
|
||||||
static gboolean
|
static gboolean
|
||||||
drop_second_data_buffer (GstPad * droppad, GstBuffer * buffer, gpointer unused)
|
drop_second_data_buffer (GstPad * droppad, GstBuffer * buffer, gpointer unused)
|
||||||
{
|
{
|
||||||
|
@ -301,7 +303,6 @@ GST_START_TEST (test_discontinuity)
|
||||||
gchar *pipe_str;
|
gchar *pipe_str;
|
||||||
GstBuffer *buffer;
|
GstBuffer *buffer;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
GstClockTime timestamp;
|
|
||||||
guint drop_id;
|
guint drop_id;
|
||||||
|
|
||||||
pipe_str = g_strdup_printf ("videotestsrc"
|
pipe_str = g_strdup_printf ("videotestsrc"
|
||||||
|
@ -336,7 +337,8 @@ GST_START_TEST (test_discontinuity)
|
||||||
gst_object_unref (sink);
|
gst_object_unref (sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
drop_id = gst_pad_add_buffer_probe (droppad, drop_second_data_buffer, NULL);
|
drop_id = gst_pad_add_buffer_probe (droppad,
|
||||||
|
G_CALLBACK (drop_second_data_buffer), NULL);
|
||||||
gst_buffer_straw_start_pipeline (bin, pad);
|
gst_buffer_straw_start_pipeline (bin, pad);
|
||||||
|
|
||||||
/* header packets should have timestamp == NONE, granulepos 0 */
|
/* header packets should have timestamp == NONE, granulepos 0 */
|
||||||
|
@ -374,7 +376,9 @@ GST_START_TEST (test_discontinuity)
|
||||||
/* check discontinuity with the next buffer */
|
/* check discontinuity with the next buffer */
|
||||||
buffer = gst_buffer_straw_get_buffer (bin, pad);
|
buffer = gst_buffer_straw_get_buffer (bin, pad);
|
||||||
check_buffer_duration (buffer, GST_SECOND / 10);
|
check_buffer_duration (buffer, GST_SECOND / 10);
|
||||||
check_buffer_granulepos (buffer, 2);
|
/* After a discont, we'll always get a keyframe, so this one should be
|
||||||
|
* 2<<GRANULEPOS_SHIFT */
|
||||||
|
check_buffer_granulepos (buffer, 2 << GRANULEPOS_SHIFT);
|
||||||
check_buffer_is_header (buffer, FALSE);
|
check_buffer_is_header (buffer, FALSE);
|
||||||
fail_unless (GST_BUFFER_IS_DISCONT (buffer),
|
fail_unless (GST_BUFFER_IS_DISCONT (buffer),
|
||||||
"expected discontinuous buffer yo");
|
"expected discontinuous buffer yo");
|
||||||
|
@ -390,7 +394,6 @@ GST_START_TEST (test_discontinuity)
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
#endif /* 0 */
|
|
||||||
|
|
||||||
#endif /* #ifndef GST_DISABLE_PARSE */
|
#endif /* #ifndef GST_DISABLE_PARSE */
|
||||||
|
|
||||||
|
@ -405,9 +408,7 @@ theoraenc_suite (void)
|
||||||
#ifndef GST_DISABLE_PARSE
|
#ifndef GST_DISABLE_PARSE
|
||||||
tcase_add_test (tc_chain, test_granulepos_offset);
|
tcase_add_test (tc_chain, test_granulepos_offset);
|
||||||
tcase_add_test (tc_chain, test_continuity);
|
tcase_add_test (tc_chain, test_continuity);
|
||||||
#if 0
|
|
||||||
tcase_add_test (tc_chain, test_discontinuity);
|
tcase_add_test (tc_chain, test_discontinuity);
|
||||||
#endif /* 0 */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
|
|
Loading…
Reference in a new issue