centricular / gstcefsrc

A simple gstreamer wrapper around Chromium Embedded Framework
84 stars 45 forks source link

Segfault with GStreamer 1.17 #12

Closed nazar-pc closed 3 years ago

nazar-pc commented 4 years ago

I'm using GStreamer from Git as of right now and trying to use this to render a web page.

Relevant part of pipeline looks like cefsrc -> cefdemux -> queue -> videoconvert just like in the readme.

However, for me it crashes like this:

[0121/112213.800301:FATAL:browser_host_impl.cc(265)] Check failed: false. called on invalid thread

Thread 17 "x" received signal SIGTRAP, Trace/breakpoint trap.
[Switching to Thread 0x7f25f0519700 (LWP 7187)]
0x00007f25f669487a in operator() () at ../../base/logging.cc:880
880     ../../base/logging.cc: No such file or directory.
(gdb) bt
#0  0x00007f25f669487a in operator() () at ../../base/logging.cc:880
#1  0x00007f25f669487a in ~LogMessage() () at ../../base/logging.cc:880
#2  0x00007f25f64f854e in CreateBrowserSync() () at ../../buildtools/third_party/libc++/trunk/include/ostream:864
#3  0x00007f25f3274eca in cef_browser_host_create_browser_sync() () at ../../cef/libcef_dll/cpptoc/browser_host_cpptoc.cc:103
#4  0x00007f2604d3f512 in CefBrowserHost::CreateBrowserSync(CefWindowInfo const&, scoped_refptr<CefClient>, CefStringBase<CefStringTraitsUTF16> const&, CefStructBase<CefBrowserSettingsTraits> const&, scoped_refptr<CefDictionaryValue>, scoped_refptr<CefRequestContext>)
    (windowInfo=..., client=..., url=..., settings=..., extra_info=..., request_context=...) at /gstcefsrc/third_party/cef/cef_binary_75.0.6+g90ecd35+chromium-75.0.3770.80_linux64/libcef_dll/ctocpp/browser_host_ctocpp.cc:71
#5  0x00007f2604d36d5c in gst_cef_src_start(GstBaseSrc*) (base_src=0x7f26300be170 [GstBaseSrc|cefsrc0]) at /gstcefsrc/gstcefsrc.cc:322
#6  0x00007f263ed664f2 in gst_base_src_start (basesrc=basesrc@entry=0x7f26300be170 [GstBaseSrc|cefsrc0]) at ../libs/gst/base/gstbasesrc.c:3465
#7  0x00007f263ed66aa0 in gst_base_src_activate_push (pad=0x7f26300ac840 [GstPad|src], active=1, parent=<optimized out>) at ../libs/gst/base/gstbasesrc.c:3839
#8  0x00007f263ed66aa0 in gst_base_src_activate_mode (pad=0x7f26300ac840 [GstPad|src], parent=<optimized out>, mode=<optimized out>, active=1) at ../libs/gst/base/gstbasesrc.c:3916
#9  0x00007f263ec5fbab in activate_mode_internal (pad=0x7f26300ac840 [GstPad|src], parent=0x7f26300be170 [GstObject|cefsrc0], mode=GST_PAD_MODE_PUSH, active=1) at ../gst/gstpad.c:1217
#10 0x00007f263ec602c8 in gst_pad_set_active (pad=pad@entry=0x7f26300ac840 [GstPad|src], active=1) at ../gst/gstpad.c:1100
#11 0x00007f263ec3aa85 in activate_pads (vpad=<optimized out>, ret=0x7f25f0518140, active=0x7f25f051819c) at ../gst/gstelement.c:3121
#12 0x00007f263ec4ff0c in gst_iterator_fold (it=it@entry=0x7f25e8001a90, func=func@entry=0x7f263ec3aa60 <activate_pads>, ret=ret@entry=0x7f25f0518140, user_data=user_data@entry=0x7f25f051819c) at ../gst/gstiterator.c:617
#13 0x00007f263ec3b4a6 in iterator_activate_fold_with_resync (iter=iter@entry=0x7f25e8001a90, user_data=user_data@entry=0x7f25f051819c, func=0x7f263ec3aa60 <activate_pads>) at ../gst/gstelement.c:3145
#14 0x00007f263ec3d758 in gst_element_pads_activate (element=element@entry=0x7f26300be170 [GstElement|cefsrc0], active=<optimized out>, active@entry=1) at ../gst/gstelement.c:3181
Segmentation fault (core dumped)

Is this an issue in gstcefsrc, gstreamer or chromium itself?

MathieuDuponchelle commented 4 years ago

That's probably a CEF / chromium issue. I can't reproduce this with the master branch, the default CEF build and the latest version of gstreamer (in the gst-build devenv). Can you provide more information wrt OS / whether you can reproduce the issue with the example pipeline / whether you've modified your local checkout of gstcefsrc or use your own CEF build?

nazar-pc commented 4 years ago

I'm using Docker for development and I can confirm that gst-launch command from readme indeed works fine.

I've simplified it to this since I only care about video for now:

gst-launch-1.0 cefsrc url="https://soundcloud.com/platform/sama" ! queue ! cefdemux ! queue ! videoconvert ! autovideosink

Then I've tried to make reduced example, starting with above pipeline created programmatically, but it only shows black screen:

Cargo.toml: ```toml [package] name = "gstcefsrc-test" version = "0.1.0" authors = ["Nazar Mokrynskyi "] edition = "2018" [dependencies] gstreamer = "0.15.0" ``` src/main.rs: ```rust use gst::prelude::*; use gstreamer as gst; fn main() { gst::init().unwrap(); let pipeline = gst::Pipeline::new(None); let cefsrc = gst::ElementFactory::make("cefsrc", None).unwrap(); let queue = gst::ElementFactory::make("queue", None).unwrap(); let cefdemux = gst::ElementFactory::make("cefdemux", None).unwrap(); let queue2 = gst::ElementFactory::make("queue", None).unwrap(); let videoconvert = gst::ElementFactory::make("videoconvert", None).unwrap(); let autovideosink = gst::ElementFactory::make("autovideosink", None).unwrap(); cefsrc .set_property("url", &"https://soundcloud.com/platform/sama") .unwrap(); pipeline .add_many(&[ &cefsrc, &queue, &cefdemux, &queue2, &videoconvert, &autovideosink, ]) .unwrap(); gst::Element::link_many(&[ &cefsrc, &queue, &cefdemux, &queue2, &videoconvert, &autovideosink, ]) .unwrap(); pipeline.set_state(gst::State::Playing).unwrap(); let bus = pipeline.get_bus().unwrap(); for msg in bus.iter_timed(gst::CLOCK_TIME_NONE) { match msg.view() { gst::MessageView::Eos(..) => break, gst::MessageView::Error(err) => { println!( "Error from {:?}: {} ({:?})", err.get_src().map(|s| s.get_path_string()), err.get_error(), err.get_debug() ); break; } _ => (), } } pipeline.set_state(gst::State::Null).unwrap(); } ```

It seems to be literally the same thing.

Once I have that not showing black screen, I should be able to reduce my use case to a smaller demo. I'm using Rust, so getting segfaults is not quite what I expect :slightly_smiling_face:

You can reproduce my current environment by using this Dockerfile:

``` FROM restreamio/gstreamer:latest-dev RUN \ apt-get update && apt-get install -y cmake && \ git clone https://github.com/centricular/gstcefsrc.git && \ cd gstcefsrc && \ mkdir build && \ cd build && \ cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release .. && \ make -j$(nproc --all) USER 1000:1000 ENV XDG_RUNTIME_DIR=/run/user/1000 ENV DISPLAY=:0.0 ENV GST_PLUGIN_PATH=/gstcefsrc/build/Release ```

It uses the image I've built from here (which will have docs and stuff later): https://github.com/restreamio/docker-gstreamer

Build it with docker build -t gstcefsrc-test ..

Then you should be able to to use even your X session with it (Dockerfile above assumes you have user ID 1000 in Linux):

docker run --rm -it --net host -v /run:/run gstcefsrc-test

After that it should work (may occasionally fail with X errors, but most of the time it works fine).

UPD: OS is Ubuntu 19.10 and packages are as shipped in the repos except GStreamer, its plugins and libnice that are built from source.

sdroege commented 4 years ago

I'm using Rust, so getting segfaults is not quite what I expect :slightly_smiling_face:

There's https://github.com/servo/servo/tree/master/ports/gstplugin btw, which is a (more-or-less) pure Rust version of a browser source plugin based on Servo. If you feel like trying it :) It's probably not mature enough yet, but might be fun to try.

MathieuDuponchelle commented 4 years ago

Hey @nazar-pc , the difference between your application and gst-launch is the lack of a GMainLoop. cefsrc uses https://magpcss.org/ceforum/apidocs3/projects/(default)/(_globals).html#CefDoMessageLoopWork() , which is non-blocking but must be called from the main thread of the application, so the source uses g_timeout_add to do so. Without a main loop around, the timeout never gets triggered, hence the black screen.

I can't remember the exact reason why I didn't use CefRunMessageLoop() at the time but I could look into that, in the meantime you can work around this by running a main loop in your test application, instead of blocking on bus pops.

nazar-pc commented 4 years ago

I've tried Webkit WPE-based plugin first, but it requires EGL which was not available in my case, so I decided to try this one. I've seen that Servo has something that looks like a plugin, but it is not on crates.io from what I've seen, so probably not very usable. I'll probably give it a try later though.

I'll try to run the main loop and let you know how it goes.

MathieuDuponchelle commented 4 years ago

@nazar-pc , any news on that?

nazar-pc commented 4 years ago

Not yet, I was busy with other things, will get back to this as soon as I can

nazar-pc commented 4 years ago

OK, with this modification it runs indeed:

```rust use gstreamer as gst; use gstreamer::glib; use gstreamer::prelude::*; fn main() { gst::init().unwrap(); let pipeline = gst::Pipeline::new(None); let cefsrc = gst::ElementFactory::make("cefsrc", None).unwrap(); let queue = gst::ElementFactory::make("queue", None).unwrap(); let cefdemux = gst::ElementFactory::make("cefdemux", None).unwrap(); let queue2 = gst::ElementFactory::make("queue", None).unwrap(); let videoconvert = gst::ElementFactory::make("videoconvert", None).unwrap(); let autovideosink = gst::ElementFactory::make("autovideosink", None).unwrap(); cefsrc .set_property("url", &"https://soundcloud.com/platform/sama") .unwrap(); pipeline .add_many(&[ &cefsrc, &queue, &cefdemux, &queue2, &videoconvert, &autovideosink, ]) .unwrap(); gst::Element::link_many(&[ &cefsrc, &queue, &cefdemux, &queue2, &videoconvert, &autovideosink, ]) .unwrap(); pipeline.set_state(gst::State::Playing).unwrap(); let main_loop = glib::MainLoop::new(None, false); let bus = pipeline.get_bus().unwrap(); bus.add_watch({ let main_loop = main_loop.clone(); move |_, msg| { match msg.view() { gst::MessageView::Eos(..) => main_loop.quit(), gst::MessageView::Error(err) => { println!( "Error from {:?}: {} ({:?})", err.get_src().map(|s| s.get_path_string()), err.get_error(), err.get_debug() ); main_loop.quit(); } _ => (), } glib::Continue(true) } }) .unwrap(); main_loop.run(); pipeline.set_state(gst::State::Null).unwrap(); bus.remove_watch().unwrap(); } ```

Will work on reduced example now.

nazar-pc commented 4 years ago

Hm.. there is something weird going on. I'm not getting segfaults on this machine after a few hours trying. This machine is strange though. It reproduces other errors and warnings that the machine I had that segfault on didn't, probably because I'm running Ubuntu daily here.

I'll have to test again on the other machine where I got this segfault initially, probably tomorrow. Though it doesn't make any sense to me since it runs inside of a container...

MathieuDuponchelle commented 4 years ago

After some investigation, I found that I can reproduce a similar crash when cefsrc is built in Debug mode. The initial issue is fixed by setting locales_dir_path as such (hardcoded):

CefString(&settings.locales_dir_path).FromASCII("/home/meh/devel/gst-build/sandbox/gstcefsrc/build/Debug/locales");

There are however subsequent issues on shutdown. Some refactoring would be needed to address those, this will probably be best done when lifting the main loop requirement, as these tie in to the element's lifecycle as well.

MathieuDuponchelle commented 4 years ago

@nazar-pc , can you confirm you were seeing the issue with a Debug build?

nazar-pc commented 4 years ago

Yes, that is the difference! I was building it in Debug mode when it crashed and then spent 3 hours trying to find out why it doesn't crash in Release build yesterday.

philn commented 4 years ago

I've tried Webkit WPE-based plugin first, but it requires EGL which was not available in my case, so I decided to try this one.

This requirement is optional now, you need gst 1.17, wpebackend-fdo git master (upcoming 1.8.x) though. To use swrast, set LIBGL_ALWAYS_SOFTWARE=true at runtime.

nazar-pc commented 4 years ago

you need gst 1.17

Was the change actually merged to master though? https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1267 is still open.

philn commented 4 years ago

Yes it was. This MR is mostly about CI, I should rebase it at some point :)

philn commented 4 years ago

https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/commit/9ac798ae5e7ebefea626d796eac8d859c3dfdf60

MathieuDuponchelle commented 3 years ago

As of the latest commit, cefsrc is usable in Debug mode, including at program destruction :)