Skip to content

Commit 63e7978

Browse files
committed
cefsrc: Add is-live=false - produces frames OnPaint
Defaults to is-live=true (previous functionality)
1 parent dde1e63 commit 63e7978

3 files changed

Lines changed: 118 additions & 16 deletions

File tree

gstcefsrc.cc

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "gst/gstelement.h"
33
#include "gst/gstinfo.h"
44
#include "gst/gstobject.h"
5+
#include "gst/gstpad.h"
56
#include <cstdio>
67
#include <glib-object.h>
78
#include <glib.h>
@@ -44,6 +45,7 @@ GST_DEBUG_CATEGORY_STATIC (cef_src_debug);
4445

4546
GST_DEBUG_CATEGORY_STATIC (cef_console_debug);
4647

48+
#define DEFAULT_IS_LIVE TRUE
4749
#define DEFAULT_WIDTH 1920
4850
#define DEFAULT_HEIGHT 1080
4951
#define DEFAULT_FPS_N 30
@@ -126,6 +128,7 @@ enum
126128
{
127129
PROP_0,
128130
PROP_URL,
131+
PROP_IS_LIVE,
129132
PROP_GPU,
130133
PROP_CHROMIUM_DEBUG_PORT,
131134
PROP_CHROME_EXTRA_FLAGS,
@@ -267,6 +270,14 @@ class RenderHandler : public CefRenderHandler
267270
gst_buffer_unref (new_buffer);
268271
GST_OBJECT_UNLOCK (src);
269272

273+
if (!src->is_live) {
274+
g_mutex_lock(&src->on_paint_lock);
275+
src->painted = TRUE;
276+
277+
g_cond_signal(&src->on_paint_cond);
278+
g_mutex_unlock(&src->on_paint_lock);
279+
}
280+
270281
GST_LOG_OBJECT (src, "done painting");
271282
}
272283

@@ -345,7 +356,7 @@ class AudioHandler : public CefAudioHandler
345356
// NB: audio latency is required because of the way the audio data is muxed into the video
346357
// buffers
347358
// TODO: is there a better way to determine the required audio latency here?
348-
GstClockTimeDiff audio_latency = (dt * 4);
359+
GstClockTimeDiff audio_latency = (dt * 10);
349360

350361
GstClockTime vpts = gst_util_uint64_scale (src->n_frames + 1, src->vinfo.fps_d * GST_SECOND, src->vinfo.fps_n);
351362
cefGstOffset = GST_CLOCK_DIFF (cef_pts, vpts) + audio_latency;
@@ -720,6 +731,25 @@ static GstFlowReturn gst_cef_src_create(GstPushSrc *push_src, GstBuffer **buf)
720731
GstCefSrc *src = GST_CEF_SRC (push_src);
721732
GList *tmp;
722733

734+
if (!src->is_live) {
735+
g_mutex_lock(&src->on_paint_lock);
736+
while (!src->painted && !src->flushing) {
737+
g_cond_wait(&src->on_paint_cond, &src->on_paint_lock);
738+
}
739+
740+
if (src->flushing) {
741+
g_mutex_unlock(&src->on_paint_lock);
742+
GST_DEBUG_OBJECT(src, "Flushing");
743+
return GST_FLOW_FLUSHING;
744+
}
745+
746+
if (src->painted) {
747+
src->painted = FALSE;
748+
}
749+
750+
g_mutex_unlock(&src->on_paint_lock);
751+
}
752+
723753
GST_OBJECT_LOCK (src);
724754

725755
if (src->audio_events) {
@@ -753,6 +783,27 @@ static GstFlowReturn gst_cef_src_create(GstPushSrc *push_src, GstBuffer **buf)
753783
return GST_FLOW_OK;
754784
}
755785

786+
static gboolean gst_cef_src_unlock(GstBaseSrc *bsrc) {
787+
GstCefSrc *src = GST_CEF_SRC (bsrc);
788+
789+
g_mutex_lock(&src->on_paint_lock);
790+
src->flushing = TRUE;
791+
g_cond_signal(&src->on_paint_cond);
792+
g_mutex_unlock(&src->on_paint_lock);
793+
794+
return TRUE;
795+
}
796+
797+
static gboolean gst_cef_src_unlock_stop(GstBaseSrc *bsrc) {
798+
GstCefSrc *src = GST_CEF_SRC (bsrc);
799+
800+
g_mutex_lock(&src->on_paint_lock);
801+
src->flushing = FALSE;
802+
g_mutex_unlock(&src->on_paint_lock);
803+
804+
return TRUE;
805+
}
806+
756807
/* Once we have started a first cefsrc for this process, we start
757808
* a UI thread and never shut it down. We could probably refine this
758809
* to stop and restart the thread as needed, but this updated approach
@@ -978,6 +1029,13 @@ gst_cef_src_start(GstBaseSrc *base_src)
9781029

9791030
GST_ELEMENT_PROGRESS(src, START, "open", ("Creating CEF browser client"));
9801031

1032+
if (!src->is_live) {
1033+
g_mutex_lock(&src->on_paint_lock);
1034+
src->flushing = FALSE;
1035+
g_cond_signal(&src->on_paint_cond);
1036+
g_mutex_unlock(&src->on_paint_lock);
1037+
}
1038+
9811039
CefRefPtr<BrowserClient> browserClient = new BrowserClient(src);
9821040

9831041
/* Make sure CEF is initialized before posting a task */
@@ -1055,6 +1113,13 @@ gst_cef_src_stop (GstBaseSrc *base_src)
10551113

10561114
GST_INFO_OBJECT (src, "Stopping");
10571115

1116+
if (!src->is_live) {
1117+
g_mutex_lock(&src->on_paint_lock);
1118+
src->flushing = TRUE;
1119+
g_cond_signal(&src->on_paint_cond);
1120+
g_mutex_unlock(&src->on_paint_lock);
1121+
}
1122+
10581123
if (src->browser) {
10591124
gst_cef_src_close_browser(src);
10601125
#ifdef __APPLE__
@@ -1193,6 +1258,11 @@ gst_cef_src_set_property (GObject * object, guint prop_id, const GValue * value,
11931258
src->chrome_extra_flags = g_value_dup_string (value);
11941259
break;
11951260
}
1261+
case PROP_IS_LIVE:
1262+
{
1263+
src->is_live = g_value_get_boolean (value);
1264+
break;
1265+
}
11961266
case PROP_GPU:
11971267
{
11981268
GST_WARNING_OBJECT(
@@ -1279,6 +1349,9 @@ gst_cef_src_get_property (GObject * object, guint prop_id, GValue * value,
12791349
case PROP_CHROME_EXTRA_FLAGS:
12801350
g_value_set_string (value, src->chrome_extra_flags);
12811351
break;
1352+
case PROP_IS_LIVE:
1353+
g_value_set_boolean (value, src->is_live);
1354+
break;
12821355
case PROP_GPU:
12831356
g_value_set_boolean (value, src->gpu);
12841357
break;
@@ -1324,13 +1397,22 @@ gst_cef_src_finalize (GObject *object)
13241397

13251398
g_cond_clear(&src->state_cond);
13261399
g_mutex_clear(&src->state_lock);
1400+
1401+
g_cond_clear (&src->on_paint_cond);
1402+
g_mutex_clear (&src->on_paint_lock);
13271403
}
13281404

13291405
static void
13301406
gst_cef_src_init (GstCefSrc * src)
13311407
{
13321408
GstBaseSrc *base_src = GST_BASE_SRC (src);
13331409

1410+
src->is_live = DEFAULT_IS_LIVE;
1411+
g_cond_init (&src->on_paint_cond);
1412+
g_mutex_init (&src->on_paint_lock);
1413+
src->flushing = FALSE;
1414+
src->painted = FALSE;
1415+
13341416
src->n_frames = 0;
13351417
src->current_buffer = NULL;
13361418
src->audio_buffers = NULL;
@@ -1367,6 +1449,11 @@ gst_cef_src_class_init (GstCefSrcClass * klass)
13671449
"The URL to display",
13681450
DEFAULT_URL, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT)));
13691451

1452+
g_object_class_install_property (gobject_class, PROP_IS_LIVE,
1453+
g_param_spec_boolean ("is-live", "is-live",
1454+
"Operate in live mode (if true, we only sample the cef video buffer, if false we produce one frame per OnPaint)",
1455+
DEFAULT_IS_LIVE, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
1456+
13701457
g_object_class_install_property (gobject_class, PROP_GPU,
13711458
g_param_spec_boolean ("gpu", "gpu",
13721459
"Enable GPU usage in chromium (Improves performance if you have GPU) - "
@@ -1435,6 +1522,9 @@ gst_cef_src_class_init (GstCefSrcClass * klass)
14351522
base_src_class->get_times = GST_DEBUG_FUNCPTR(gst_cef_src_get_times);
14361523
base_src_class->query = GST_DEBUG_FUNCPTR(gst_cef_src_query);
14371524

1525+
base_src_class->unlock = GST_DEBUG_FUNCPTR(gst_cef_src_unlock);
1526+
base_src_class->unlock_stop = GST_DEBUG_FUNCPTR(gst_cef_src_unlock_stop);
1527+
14381528
gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_cef_src_change_state);
14391529

14401530
push_src_class->create = GST_DEBUG_FUNCPTR(gst_cef_src_create);

gstcefsrc.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ struct _GstCefSrc {
6464
CefRefPtr<CefBrowser> browser;
6565
CefRefPtr<CefApp> app;
6666

67+
gboolean is_live;
68+
GCond on_paint_cond;
69+
GMutex on_paint_lock;
70+
gboolean painted;
71+
gboolean flushing;
72+
6773
GCond state_cond;
6874
GMutex state_lock;
6975
CefSrcState state;

html/raf_test.html

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
}
3333
</style>
3434
<script language="JavaScript">
35+
const params = new URLSearchParams(window.location.search);
36+
3537
let frameNum = 0; // s
3638
let fps = 0;
3739
let t = undefined;
@@ -72,21 +74,25 @@
7274
requestAnimationFrame(animate);
7375
}
7476

75-
const audioDelay = 1000;
76-
77-
document.addEventListener("DOMContentLoaded", () => {
78-
setTimeout(() => {
79-
const audio = new Audio("sounds/test.mp3");
80-
// audio.loop = true;
81-
audio.play();
82-
audio.onended = () => {
83-
setTimeout(() => {
84-
audio.currentTime = 0;
85-
audio.play();
86-
}, audioDelay);
87-
}
88-
}, audioDelay);
89-
});
77+
const audioDelayStr = params.get("audioDelay") ?? "1000";
78+
const audioDelay = parseInt(audioDelayStr);
79+
console.log("audioDelay:", audioDelay);
80+
if (audioDelay >= 0) {
81+
82+
document.addEventListener("DOMContentLoaded", () => {
83+
setTimeout(() => {
84+
const audio = new Audio("sounds/test.mp3");
85+
// audio.loop = true;
86+
audio.play();
87+
audio.onended = () => {
88+
setTimeout(() => {
89+
audio.currentTime = 0;
90+
audio.play();
91+
}, audioDelay);
92+
}
93+
}, audioDelay);
94+
});
95+
}
9096

9197
requestAnimationFrame(animate);
9298
</script>

0 commit comments

Comments
 (0)