mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 08:46:40 +00:00
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:
parent
ef0497c149
commit
86888d9918
6 changed files with 596 additions and 637 deletions
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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__ */
|
||||
|
|
Loading…
Reference in a new issue