decklinkaudiosink: Re-implement around GstBaseSink instead of GstAudioBaseSink

The Decklink and GstAudioBaseSink APIs don't fit very well together,
which causes various problems due to inaccuracies in the clock
calculations and the actual ringbuffer and GStreamer's copy getting of
sync.

Problems are audio drop-outs and A/V sync getting wrong after
pausing/seeking.

https://bugzilla.gnome.org/show_bug.cgi?id=790114
This commit is contained in:
Sebastian Dröge 2017-11-08 19:31:37 +02:00
parent ef0497c149
commit 86888d9918
6 changed files with 596 additions and 637 deletions

View file

@ -1339,33 +1339,6 @@ gst_decklink_release_nth_output (gint n, GstElement * sink, gboolean is_audio)
g_mutex_unlock (&output->lock);
}
void
gst_decklink_output_set_audio_clock (GstDecklinkOutput * output,
GstClock * clock)
{
g_mutex_lock (&output->lock);
if (output->audio_clock)
gst_object_unref (output->audio_clock);
output->audio_clock = clock;
if (clock)
gst_object_ref (clock);
g_mutex_unlock (&output->lock);
}
GstClock *
gst_decklink_output_get_audio_clock (GstDecklinkOutput * output)
{
GstClock *ret = NULL;
g_mutex_lock (&output->lock);
if (output->audio_clock)
ret = GST_CLOCK_CAST (gst_object_ref (output->audio_clock));
g_mutex_unlock (&output->lock);
return ret;
}
GstDecklinkInput *
gst_decklink_acquire_nth_input (gint n, GstElement * src, gboolean is_audio)
{

View file

@ -226,9 +226,6 @@ struct _GstDecklinkOutput {
/* Configured mode or NULL */
const GstDecklinkMode *mode;
/* Set by the audio sink */
GstClock *audio_clock;
GstElement *audiosink;
gboolean audio_enabled;
GstElement *videosink;
@ -267,9 +264,6 @@ struct _GstDecklinkInput {
GstDecklinkOutput * gst_decklink_acquire_nth_output (gint n, GstElement * sink, gboolean is_audio);
void gst_decklink_release_nth_output (gint n, GstElement * sink, gboolean is_audio);
void gst_decklink_output_set_audio_clock (GstDecklinkOutput * output, GstClock * clock);
GstClock * gst_decklink_output_get_audio_clock (GstDecklinkOutput * output);
GstDecklinkInput * gst_decklink_acquire_nth_input (gint n, GstElement * src, gboolean is_audio);
void gst_decklink_release_nth_input (gint n, GstElement * src, gboolean is_audio);

File diff suppressed because it is too large Load diff

View file

@ -23,6 +23,7 @@
#define __GST_DECKLINK_AUDIO_SINK_H__
#include <gst/gst.h>
#include <gst/base/base.h>
#include <gst/audio/audio.h>
#include "gstdecklink.h"
@ -46,15 +47,20 @@ typedef struct _GstDecklinkAudioSinkClass GstDecklinkAudioSinkClass;
struct _GstDecklinkAudioSink
{
GstAudioBaseSink parent;
GstBaseSink parent;
GstDecklinkModeEnum mode;
gint device_number;
GstClockTime buffer_time;
GstDecklinkOutput *output;
GstAudioInfo info;
GstAudioStreamAlign *stream_align;
};
struct _GstDecklinkAudioSinkClass
{
GstAudioBaseSinkClass parent_class;
GstBaseSinkClass parent_class;
};
GType gst_decklink_audio_sink_get_type (void);

View file

@ -526,17 +526,16 @@ gst_decklink_video_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
return GST_FLOW_OK;
}
static void
convert_to_internal_clock (GstDecklinkVideoSink * self,
void
gst_decklink_video_sink_convert_to_internal_clock (GstDecklinkVideoSink * self,
GstClockTime * timestamp, GstClockTime * duration)
{
GstClock *clock, *audio_clock;
GstClock *clock;
g_assert (timestamp != NULL);
clock = gst_element_get_clock (GST_ELEMENT_CAST (self));
audio_clock = gst_decklink_output_get_audio_clock (self->output);
if (clock && clock != self->output->clock && clock != audio_clock) {
if (clock && clock != self->output->clock) {
GstClockTime internal, external, rate_n, rate_d;
gst_clock_get_calibration (self->output->clock, &internal, &external,
&rate_n, &rate_d);
@ -729,7 +728,7 @@ gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer)
g_free (tc_str);
}
convert_to_internal_clock (self, &running_time, &running_time_duration);
gst_decklink_video_sink_convert_to_internal_clock (self, &running_time, &running_time_duration);
if (!self->output->started) {
GST_LOG_OBJECT (self, "Showing video frame synchronously because PAUSED");
@ -882,7 +881,7 @@ gst_decklink_video_sink_start_scheduled_playback (GstElement * element)
gst_clock_get_internal_time (self->output->clock);
self->external_base_time = gst_clock_get_internal_time (clock);
convert_to_internal_clock (self, &start_time, NULL);
gst_decklink_video_sink_convert_to_internal_clock (self, &start_time, NULL);
g_mutex_lock (&self->output->lock);
// Check if someone else started in the meantime
@ -970,7 +969,7 @@ gst_decklink_video_sink_stop_scheduled_playback (GstDecklinkVideoSink * self)
if (start_time == GST_CLOCK_TIME_NONE)
start_time = 0;
convert_to_internal_clock (self, &start_time, NULL);
gst_decklink_video_sink_convert_to_internal_clock (self, &start_time, NULL);
// The start time is now the running time when we stopped
// playback
@ -1030,17 +1029,14 @@ gst_decklink_video_sink_change_state (GstElement * element,
self->output->clock, TRUE));
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:{
GstClock *clock, *audio_clock;
GstClock *clock;
clock = gst_element_get_clock (GST_ELEMENT_CAST (self));
if (clock) {
audio_clock = gst_decklink_output_get_audio_clock (self->output);
if (clock && clock != self->output->clock && clock != audio_clock) {
if (clock && clock != self->output->clock) {
gst_clock_set_master (self->output->clock, clock);
}
gst_object_unref (clock);
if (audio_clock)
gst_object_unref (audio_clock);
} else {
GST_ELEMENT_ERROR (self, STREAM, FAILED,
(NULL), ("Need a clock to go to PLAYING"));

View file

@ -71,6 +71,9 @@ struct _GstDecklinkVideoSinkClass
GType gst_decklink_video_sink_get_type (void);
void gst_decklink_video_sink_convert_to_internal_clock (GstDecklinkVideoSink * self,
GstClockTime * timestamp, GstClockTime * duration);
G_END_DECLS
#endif /* __GST_DECKLINK_VIDEO_SINK_H__ */