Skip to content

Commit

Permalink
cefsrc: Apply running time on audio buffers
Browse files Browse the repository at this point in the history
Also add an audio meta to buffers, for good measure, and set discont flag when
needed. This should help with A/V sync issues and audio cracks reported in centricular#59.
  • Loading branch information
philn committed Nov 25, 2022
1 parent cce144d commit a7c993f
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 19 deletions.
107 changes: 98 additions & 9 deletions gstcefdemux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#define CEF_VIDEO_CAPS "video/x-raw, format=BGRA, width=[1, 2147483647], height=[1, 2147483647], framerate=[1/1, 60/1], pixel-aspect-ratio=1/1"
#define CEF_AUDIO_CAPS "audio/x-raw, format=F32LE, rate=[1, 2147483647], channels=[1, 2147483647], layout=interleaved"

#define gst_cef_demux_parent_class parent_class
G_DEFINE_TYPE (GstCefDemux, gst_cef_demux, GST_TYPE_ELEMENT);

static GstStaticPadTemplate gst_cef_demux_sink_template =
Expand Down Expand Up @@ -58,6 +59,7 @@ gst_cef_demux_push_events (GstCefDemux *demux)
"channels", G_TYPE_INT, 2,
"layout", G_TYPE_STRING, "interleaved",
NULL);
gst_audio_info_from_caps (&demux->audio_info, audio_caps);
gst_pad_push_event (demux->asrcpad, gst_event_new_caps (audio_caps));
gst_caps_unref (audio_caps);

Expand All @@ -83,13 +85,76 @@ typedef struct
GstFlowReturn combined;
} AudioPushData;

#if !GST_CHECK_VERSION(1, 18, 0)
static GstClockTime
gst_element_get_current_clock_time (GstElement * element)
{
GstClock *clock = NULL;
GstClockTime ret;

g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_TIME_NONE);

clock = gst_element_get_clock (element);

if (!clock) {
GST_DEBUG_OBJECT (element, "Element has no clock");
return GST_CLOCK_TIME_NONE;
}

ret = gst_clock_get_time (clock);
gst_object_unref (clock);

return ret;
}

static GstClockTime
gst_element_get_current_running_time (GstElement * element)
{
GstClockTime base_time, clock_time;

g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_TIME_NONE);

base_time = gst_element_get_base_time (element);

if (!GST_CLOCK_TIME_IS_VALID (base_time)) {
GST_DEBUG_OBJECT (element, "Could not determine base time");
return GST_CLOCK_TIME_NONE;
}

clock_time = gst_element_get_current_clock_time (element);

if (!GST_CLOCK_TIME_IS_VALID (clock_time)) {
return GST_CLOCK_TIME_NONE;
}

if (clock_time < base_time) {
GST_DEBUG_OBJECT (element, "Got negative current running time");
return GST_CLOCK_TIME_NONE;
}

return clock_time - base_time;
}
#endif


static gboolean
gst_cef_demux_push_audio_buffer (GstBuffer **buffer, guint idx, AudioPushData *push_data)
{
GST_BUFFER_PTS (*buffer) += push_data->demux->ts_offset;
push_data->demux->last_audio_time = gst_element_get_current_running_time (GST_ELEMENT_CAST (push_data->demux));
GST_BUFFER_DTS (*buffer) = push_data->demux->last_audio_time;
GST_BUFFER_PTS (*buffer) = push_data->demux->last_audio_time;

gst_buffer_add_audio_meta (*buffer, &push_data->demux->audio_info, gst_buffer_get_size (*buffer), NULL);

GST_BUFFER_FLAG_UNSET (*buffer, GST_BUFFER_FLAG_DISCONT);
if (push_data->demux->need_discont) {
GST_BUFFER_FLAG_SET (*buffer, GST_BUFFER_FLAG_DISCONT);
push_data->demux->need_discont = FALSE;
}

push_data->combined = gst_flow_combiner_update_pad_flow (push_data->flow_combiner, push_data->demux->asrcpad,
gst_pad_push (push_data->demux->asrcpad, *buffer));
push_data->demux->last_audio_time = GST_BUFFER_PTS (*buffer) + GST_BUFFER_DURATION (*buffer);

*buffer = NULL;
return TRUE;
}
Expand Down Expand Up @@ -127,11 +192,6 @@ gst_cef_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)

gst_cef_demux_push_events (demux);


if (!GST_CLOCK_TIME_IS_VALID (demux->ts_offset)) {
demux->ts_offset = GST_BUFFER_PTS (buffer);
}

for (tmp = demux->cef_audio_stream_start_events; tmp; tmp = tmp->next) {
const GstStructure *s = gst_event_get_structure ((GstEvent *) tmp->data);

Expand Down Expand Up @@ -228,6 +288,31 @@ gst_cef_demux_sink_query (GstPad *pad, GstObject *parent, GstQuery *query)
return ret;
}


static GstStateChangeReturn
gst_cef_demux_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn result;
GstCefDemux *demux = (GstCefDemux *) element;

GST_DEBUG_OBJECT (demux, "%s", gst_state_change_get_name (transition));
result = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS , change_state, (element, transition), GST_STATE_CHANGE_FAILURE);

switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_flow_combiner_reset (demux->flow_combiner);
break;
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
demux->need_discont = TRUE;
break;
default:
break;
}

return result;
}


static void
gst_cef_demux_init (GstCefDemux * demux)
{
Expand All @@ -248,11 +333,13 @@ gst_cef_demux_init (GstCefDemux * demux)
gst_element_add_pad (GST_ELEMENT (demux), demux->asrcpad);
gst_flow_combiner_add_pad (demux->flow_combiner, demux->asrcpad);

gst_audio_info_init (&demux->audio_info);

demux->need_stream_start = TRUE;
demux->need_caps = TRUE;
demux->need_segment = TRUE;
demux->last_audio_time = 0;
demux->ts_offset = GST_CLOCK_TIME_NONE;
demux->need_discont = TRUE;
demux->last_audio_time = GST_CLOCK_TIME_NONE;
}

static void
Expand All @@ -273,6 +360,8 @@ gst_cef_demux_class_init (GstCefDemuxClass * klass)

gobject_class->finalize = gst_cef_demux_finalize;

gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_cef_demux_change_state);

gst_element_class_set_static_metadata (gstelement_class,
"Chromium Embedded Framework demuxer", "Demuxer/Audio/Video",
"Demuxes audio and video from cefsrc", "Mathieu Duponchelle <[email protected]>");
Expand Down
4 changes: 3 additions & 1 deletion gstcefdemux.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <gst/gst.h>
#include <gst/base/gstflowcombiner.h>
#include <gst/audio/audio.h>

G_BEGIN_DECLS

Expand All @@ -26,13 +27,14 @@ struct _GstCefDemux {
gboolean need_stream_start;
gboolean need_caps;
gboolean need_segment;
gboolean need_discont;
GstPad *vsrcpad;
GstPad *asrcpad;
GList *cef_audio_stream_start_events;
GstEvent *vcaps_event;
GstFlowCombiner *flow_combiner;
GstClockTime last_audio_time;
GstClockTime ts_offset;
GstAudioInfo audio_info;
};

struct _GstCefDemuxClass {
Expand Down
9 changes: 0 additions & 9 deletions gstcefsrc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ class AudioHandler : public CefAudioHandler

mRate = params.sample_rate;
mChannels = channels;
mCurrentTime = GST_CLOCK_TIME_NONE;

GST_OBJECT_LOCK (mElement);
mElement->audio_events = g_list_append (mElement->audio_events, event);
Expand Down Expand Up @@ -214,14 +213,7 @@ class AudioHandler : public CefAudioHandler

GST_OBJECT_LOCK (mElement);

if (!GST_CLOCK_TIME_IS_VALID (mCurrentTime)) {
mCurrentTime = gst_util_uint64_scale (mElement->n_frames,
mElement->vinfo.fps_d * GST_SECOND, mElement->vinfo.fps_n);
}

GST_BUFFER_PTS (buf) = mCurrentTime;
GST_BUFFER_DURATION (buf) = gst_util_uint64_scale (frames, GST_SECOND, mRate);
mCurrentTime += GST_BUFFER_DURATION (buf);

if (!mElement->audio_buffers) {
mElement->audio_buffers = gst_buffer_list_new();
Expand All @@ -245,7 +237,6 @@ class AudioHandler : public CefAudioHandler
private:

GstCefSrc *mElement;
GstClockTime mCurrentTime;
gint mRate;
gint mChannels;
IMPLEMENT_REFCOUNTING(AudioHandler);
Expand Down

0 comments on commit a7c993f

Please sign in to comment.