|
2 | 2 | #include "gst/gstelement.h" |
3 | 3 | #include "gst/gstinfo.h" |
4 | 4 | #include "gst/gstobject.h" |
| 5 | +#include "gst/gstpad.h" |
5 | 6 | #include <cstdio> |
6 | 7 | #include <glib-object.h> |
7 | 8 | #include <glib.h> |
@@ -44,6 +45,7 @@ GST_DEBUG_CATEGORY_STATIC (cef_src_debug); |
44 | 45 |
|
45 | 46 | GST_DEBUG_CATEGORY_STATIC (cef_console_debug); |
46 | 47 |
|
| 48 | +#define DEFAULT_IS_LIVE TRUE |
47 | 49 | #define DEFAULT_WIDTH 1920 |
48 | 50 | #define DEFAULT_HEIGHT 1080 |
49 | 51 | #define DEFAULT_FPS_N 30 |
|
126 | 128 | { |
127 | 129 | PROP_0, |
128 | 130 | PROP_URL, |
| 131 | + PROP_IS_LIVE, |
129 | 132 | PROP_GPU, |
130 | 133 | PROP_CHROMIUM_DEBUG_PORT, |
131 | 134 | PROP_CHROME_EXTRA_FLAGS, |
@@ -267,6 +270,14 @@ class RenderHandler : public CefRenderHandler |
267 | 270 | gst_buffer_unref (new_buffer); |
268 | 271 | GST_OBJECT_UNLOCK (src); |
269 | 272 |
|
| 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 | + |
270 | 281 | GST_LOG_OBJECT (src, "done painting"); |
271 | 282 | } |
272 | 283 |
|
@@ -345,7 +356,7 @@ class AudioHandler : public CefAudioHandler |
345 | 356 | // NB: audio latency is required because of the way the audio data is muxed into the video |
346 | 357 | // buffers |
347 | 358 | // 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); |
349 | 360 |
|
350 | 361 | GstClockTime vpts = gst_util_uint64_scale (src->n_frames + 1, src->vinfo.fps_d * GST_SECOND, src->vinfo.fps_n); |
351 | 362 | cefGstOffset = GST_CLOCK_DIFF (cef_pts, vpts) + audio_latency; |
@@ -720,6 +731,25 @@ static GstFlowReturn gst_cef_src_create(GstPushSrc *push_src, GstBuffer **buf) |
720 | 731 | GstCefSrc *src = GST_CEF_SRC (push_src); |
721 | 732 | GList *tmp; |
722 | 733 |
|
| 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 | + |
723 | 753 | GST_OBJECT_LOCK (src); |
724 | 754 |
|
725 | 755 | if (src->audio_events) { |
@@ -753,6 +783,27 @@ static GstFlowReturn gst_cef_src_create(GstPushSrc *push_src, GstBuffer **buf) |
753 | 783 | return GST_FLOW_OK; |
754 | 784 | } |
755 | 785 |
|
| 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 | + |
756 | 807 | /* Once we have started a first cefsrc for this process, we start |
757 | 808 | * a UI thread and never shut it down. We could probably refine this |
758 | 809 | * to stop and restart the thread as needed, but this updated approach |
@@ -978,6 +1029,13 @@ gst_cef_src_start(GstBaseSrc *base_src) |
978 | 1029 |
|
979 | 1030 | GST_ELEMENT_PROGRESS(src, START, "open", ("Creating CEF browser client")); |
980 | 1031 |
|
| 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 | + |
981 | 1039 | CefRefPtr<BrowserClient> browserClient = new BrowserClient(src); |
982 | 1040 |
|
983 | 1041 | /* Make sure CEF is initialized before posting a task */ |
@@ -1055,6 +1113,13 @@ gst_cef_src_stop (GstBaseSrc *base_src) |
1055 | 1113 |
|
1056 | 1114 | GST_INFO_OBJECT (src, "Stopping"); |
1057 | 1115 |
|
| 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 | + |
1058 | 1123 | if (src->browser) { |
1059 | 1124 | gst_cef_src_close_browser(src); |
1060 | 1125 | #ifdef __APPLE__ |
@@ -1193,6 +1258,11 @@ gst_cef_src_set_property (GObject * object, guint prop_id, const GValue * value, |
1193 | 1258 | src->chrome_extra_flags = g_value_dup_string (value); |
1194 | 1259 | break; |
1195 | 1260 | } |
| 1261 | + case PROP_IS_LIVE: |
| 1262 | + { |
| 1263 | + src->is_live = g_value_get_boolean (value); |
| 1264 | + break; |
| 1265 | + } |
1196 | 1266 | case PROP_GPU: |
1197 | 1267 | { |
1198 | 1268 | GST_WARNING_OBJECT( |
@@ -1279,6 +1349,9 @@ gst_cef_src_get_property (GObject * object, guint prop_id, GValue * value, |
1279 | 1349 | case PROP_CHROME_EXTRA_FLAGS: |
1280 | 1350 | g_value_set_string (value, src->chrome_extra_flags); |
1281 | 1351 | break; |
| 1352 | + case PROP_IS_LIVE: |
| 1353 | + g_value_set_boolean (value, src->is_live); |
| 1354 | + break; |
1282 | 1355 | case PROP_GPU: |
1283 | 1356 | g_value_set_boolean (value, src->gpu); |
1284 | 1357 | break; |
@@ -1324,13 +1397,22 @@ gst_cef_src_finalize (GObject *object) |
1324 | 1397 |
|
1325 | 1398 | g_cond_clear(&src->state_cond); |
1326 | 1399 | g_mutex_clear(&src->state_lock); |
| 1400 | + |
| 1401 | + g_cond_clear (&src->on_paint_cond); |
| 1402 | + g_mutex_clear (&src->on_paint_lock); |
1327 | 1403 | } |
1328 | 1404 |
|
1329 | 1405 | static void |
1330 | 1406 | gst_cef_src_init (GstCefSrc * src) |
1331 | 1407 | { |
1332 | 1408 | GstBaseSrc *base_src = GST_BASE_SRC (src); |
1333 | 1409 |
|
| 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 | + |
1334 | 1416 | src->n_frames = 0; |
1335 | 1417 | src->current_buffer = NULL; |
1336 | 1418 | src->audio_buffers = NULL; |
@@ -1367,6 +1449,11 @@ gst_cef_src_class_init (GstCefSrcClass * klass) |
1367 | 1449 | "The URL to display", |
1368 | 1450 | DEFAULT_URL, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT))); |
1369 | 1451 |
|
| 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 | + |
1370 | 1457 | g_object_class_install_property (gobject_class, PROP_GPU, |
1371 | 1458 | g_param_spec_boolean ("gpu", "gpu", |
1372 | 1459 | "Enable GPU usage in chromium (Improves performance if you have GPU) - " |
@@ -1435,6 +1522,9 @@ gst_cef_src_class_init (GstCefSrcClass * klass) |
1435 | 1522 | base_src_class->get_times = GST_DEBUG_FUNCPTR(gst_cef_src_get_times); |
1436 | 1523 | base_src_class->query = GST_DEBUG_FUNCPTR(gst_cef_src_query); |
1437 | 1524 |
|
| 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 | + |
1438 | 1528 | gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_cef_src_change_state); |
1439 | 1529 |
|
1440 | 1530 | push_src_class->create = GST_DEBUG_FUNCPTR(gst_cef_src_create); |
|
0 commit comments