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>
|
||||
|
||||
* ext/pango/gsttextoverlay.c: (gst_text_overlay_init),
|
||||
|
|
|
@ -93,6 +93,9 @@ struct _GstTheoraEnc
|
|||
gint fps_n, fps_d;
|
||||
GstClockTime next_ts;
|
||||
|
||||
GstClockTime expected_ts;
|
||||
gboolean next_discont;
|
||||
|
||||
guint packetno;
|
||||
guint64 bytes_out;
|
||||
guint64 granulepos_offset;
|
||||
|
|
|
@ -292,6 +292,7 @@ gst_theora_enc_init (GstTheoraEnc * enc, GstTheoraEncClass * g_class)
|
|||
GST_DEBUG_OBJECT (enc,
|
||||
"keyframe_frequency_force is %d, granule shift is %d",
|
||||
enc->info.keyframe_frequency_force, enc->granule_shift);
|
||||
enc->expected_ts = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -307,6 +308,26 @@ theora_enc_finalize (GObject * 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
|
||||
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",
|
||||
enc->info.keyframe_frequency_force, enc->granule_shift);
|
||||
|
||||
theora_encode_init (&enc->state, &enc->info);
|
||||
theora_enc_reset (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_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
|
||||
* for keyframes */
|
||||
if ((packet->packet[0] & 0x40) == 0) {
|
||||
|
@ -543,6 +569,34 @@ theora_enc_sink_event (GstPad * pad, GstEvent * event)
|
|||
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
|
||||
theora_enc_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
|
@ -784,6 +838,16 @@ theora_enc_chain (GstPad * pad, GstBuffer * buffer)
|
|||
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);
|
||||
|
||||
ret = GST_FLOW_OK;
|
||||
|
@ -863,6 +927,8 @@ theora_enc_change_state (GstElement * element, GstStateChange transition)
|
|||
theora_clear (&enc->state);
|
||||
theora_comment_clear (&enc->comment);
|
||||
theora_info_clear (&enc->info);
|
||||
|
||||
theora_enc_clear (enc);
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
break;
|
||||
|
|
|
@ -62,6 +62,7 @@ static void
|
|||
check_buffer_granulepos (GstBuffer * buffer, gint64 granulepos)
|
||||
{
|
||||
GstClockTime clocktime;
|
||||
int framecount;
|
||||
|
||||
fail_unless (GST_BUFFER_OFFSET_END (buffer) == granulepos,
|
||||
"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
|
||||
* the granulepos correctly here */
|
||||
clocktime = gst_util_uint64_scale (GST_BUFFER_OFFSET_END (buffer), GST_SECOND,
|
||||
FRAMERATE);
|
||||
framecount = GST_BUFFER_OFFSET_END (buffer);
|
||||
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),
|
||||
"expected OFFSET set to clocktime %" GST_TIME_FORMAT
|
||||
|
@ -287,7 +290,6 @@ GST_START_TEST (test_continuity)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
#if 0
|
||||
static gboolean
|
||||
drop_second_data_buffer (GstPad * droppad, GstBuffer * buffer, gpointer unused)
|
||||
{
|
||||
|
@ -301,7 +303,6 @@ GST_START_TEST (test_discontinuity)
|
|||
gchar *pipe_str;
|
||||
GstBuffer *buffer;
|
||||
GError *error = NULL;
|
||||
GstClockTime timestamp;
|
||||
guint drop_id;
|
||||
|
||||
pipe_str = g_strdup_printf ("videotestsrc"
|
||||
|
@ -336,7 +337,8 @@ GST_START_TEST (test_discontinuity)
|
|||
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);
|
||||
|
||||
/* header packets should have timestamp == NONE, granulepos 0 */
|
||||
|
@ -374,7 +376,9 @@ GST_START_TEST (test_discontinuity)
|
|||
/* check discontinuity with the next buffer */
|
||||
buffer = gst_buffer_straw_get_buffer (bin, pad);
|
||||
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);
|
||||
fail_unless (GST_BUFFER_IS_DISCONT (buffer),
|
||||
"expected discontinuous buffer yo");
|
||||
|
@ -390,7 +394,6 @@ GST_START_TEST (test_discontinuity)
|
|||
}
|
||||
|
||||
GST_END_TEST;
|
||||
#endif /* 0 */
|
||||
|
||||
#endif /* #ifndef GST_DISABLE_PARSE */
|
||||
|
||||
|
@ -405,9 +408,7 @@ theoraenc_suite (void)
|
|||
#ifndef GST_DISABLE_PARSE
|
||||
tcase_add_test (tc_chain, test_granulepos_offset);
|
||||
tcase_add_test (tc_chain, test_continuity);
|
||||
#if 0
|
||||
tcase_add_test (tc_chain, test_discontinuity);
|
||||
#endif /* 0 */
|
||||
#endif
|
||||
|
||||
return s;
|
||||
|
|
Loading…
Reference in a new issue