centricular / gstcefsrc

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

Leaves 5 processes running after `stop` #55

Open philn opened 1 year ago

philn commented 1 year ago

The "UI" thread is at least one process. The 4 others I'm not sure yet what they're for. Stopping a source element should clean-up resources, it's currently not the case, until the app process is terminated.

philn commented 1 year ago

Test case:

use gst::prelude::*;
use gstreamer as gst;
use sysinfo::{ProcessExt, System, SystemExt};

fn create_pipeline() -> gst::Pipeline {
    let pipeline = gst::Pipeline::new(None);
    let src = gst::ElementFactory::make("cefsrc", None).unwrap();
    src.set_property(
        "url",
        &"https://webkit.org/blog-files/3d-transforms/poster-circle.html",
    );
    src.set_property("num-buffers", &100);
    let convert = gst::ElementFactory::make("videoconvert", None).unwrap();
    let queue = gst::ElementFactory::make("queue", None).unwrap();
    let sink = gst::ElementFactory::make("fakevideosink", None).unwrap();

    pipeline.add_many(&[&src, &convert, &queue, &sink]).unwrap();
    gst::Element::link_many(&[&src, &convert, &queue, &sink]).unwrap();
    pipeline.set_state(gst::State::Playing).unwrap();
    pipeline
}

fn run() {
    let mut sys = System::new_all();
    for i in 0..2 {
        println!("Creating pipeline #{}", i);
        let pipeline = create_pipeline();
        let bus = pipeline.bus().unwrap();
        for msg in bus.iter_timed(gst::ClockTime::NONE) {
            if let gst::MessageView::Eos(..) = msg.view() {
                break;
            }
        }

        bus.unset_sync_handler();
        println!("Destroying pipeline");
        pipeline.set_state(gst::State::Null).unwrap();

        drop(pipeline);
        sys.refresh_all();
        let mut total = 0;
        for (pid, process) in sys.processes() {
            let name = process.name();
            if name.starts_with("gstcefsub") {
                println!("[{}] {} {:?}", pid, &name, process.disk_usage());
                total += 1;
            }
        }
        println!("Total CEF processes: {}", total);
    }
}

fn main() {
    gst::init().unwrap();
    run();
    unsafe {
        gstreamer::deinit();
    }
}
philn commented 1 year ago

I wonder about reverting e2da7ea7f54cf797a0b7723ea431d6312801aa61 and spinning a GMainLoop in a new thread, tied to the src element.

MathieuDuponchelle commented 1 year ago

I get your point, but I'm afraid you can't simply revert that commit, prior to it the situation was really not optimal, and you could only really have one cefsrc per process, which is arguably worse than failure to clean things up :P Still as mentioned here: https://github.com/centricular/gstcefsrc/commit/e2da7ea7f54cf797a0b7723ea431d6312801aa61#diff-b511dd6555eaa8cc62167e0332cbbda8f626ad7900fa3a9b092292a6c07e1ac5R326 mentions we could refine the new approach to stop and restart the UI thread as needed, I would suggest digging in that direction :) Did you find out what those 4 other processes are, and what CEF calls would get us rid of them? :)

philn commented 1 year ago

we could refine the new approach to stop and restart the UI thread as needed, I would suggest digging in that direction :)

I tried that already kindof, but then the second time CefInitialize() is called, the process crashes deep in the chromium...

Did you find out what those 4 other processes are, and what CEF calls would get us rid of them? :)

Not yet... only hint so far that I've found is that people just kill those processess using usual OS syscalls...

MathieuDuponchelle commented 1 year ago

Crashes deep into chromium I'm afraid I will be little help with, however I'm curious, what happens if you only call CefQuitMessageLoop() (and not CefShutdown, which I believe is the pendant to CefInitialize)?

philn commented 1 year ago

Yes I tried moving the UI thread to element scope, not calling CefShutdown either, but then on second run the MakeBrowser task is not dispatched to the new UI thread... I suspect some global state in CEF is left dangling after the first UI thread was stopped and that messes up everything on subsequent runs...

MathieuDuponchelle commented 1 year ago

Hm, I see, I'm afraid I don't have too many pointers here but I'll happily review and merge something if you find a solution, just please bear in mind that prior to the patch you mentioned it was not possible to run multiple cefsrc instances concurrently in the same process, and we should try not to regress on that :)