rtsp-server.rs 3.55 KB
Newer Older
1 2 3 4 5
// This example demonstrates how to set up a rtsp server using GStreamer.
// For this, the example parses an arbitrary pipeline in launch syntax
// from the cli and provides this pipeline's output as stream, served
// using GStreamers rtsp server.

6 7 8 9
use std::env;

use gst_rtsp_server::prelude::*;

10 11
use anyhow::Error;
use derive_more::{Display, Error};
12 13 14 15

#[path = "../examples-common.rs"]
mod examples_common;

16 17
#[derive(Debug, Display, Error)]
#[display(fmt = "Could not get mount points")]
18 19
struct NoMountPoints;

20 21 22
#[derive(Debug, Display, Error)]
#[display(fmt = "Usage: {} LAUNCH_LINE", _0)]
struct UsageError(#[error(not(source))] String);
23 24 25 26 27 28 29 30 31 32

fn main_loop() -> Result<(), Error> {
    let args: Vec<_> = env::args().collect();

    if args.len() != 2 {
        return Err(Error::from(UsageError(args[0].clone())));
    }

    let main_loop = glib::MainLoop::new(None, false);
    let server = gst_rtsp_server::RTSPServer::new();
33 34 35 36
    // Much like HTTP servers, RTSP servers have multiple endpoints that
    // provide different streams. Here, we ask our server to give
    // us a reference to his list of endpoints, so we can add our
    // test endpoint, providing the pipeline from the cli.
37 38
    let mounts = server.get_mount_points().ok_or(NoMountPoints)?;

39 40 41 42 43 44 45
    // Next, we create a factory for the endpoint we want to create.
    // The job of the factory is to create a new pipeline for each client that
    // connects, or (if configured to do so) to reuse an existing pipeline.
    let factory = gst_rtsp_server::RTSPMediaFactory::new();
    // Here we tell the media factory the media we want to serve.
    // This is done in the launch syntax. When the first client connects,
    // the factory will use this syntax to create a new pipeline instance.
46
    factory.set_launch(args[1].as_str());
47 48 49 50 51 52 53 54
    // This setting specifies whether each connecting client gets the output
    // of a new instance of the pipeline, or whether all connected clients share
    // the output of the same pipeline.
    // If you want to stream a fixed video you have stored on the server to any
    // client, you would not set this to shared here (since every client wants
    // to start at the beginning of the video). But if you want to distribute
    // a live source, you will probably want to set this to shared, to save
    // computing and memory capacity on the server.
55 56
    factory.set_shared(true);

57 58 59
    // Now we add a new mount-point and tell the RTSP server to serve the content
    // provided by the factory we configured above, when a client connects to
    // this specific path.
60 61
    mounts.add_factory("/test", &factory);

62 63 64 65 66 67 68
    // Attach the server to our main context.
    // A main context is the thing where other stuff is registering itself for its
    // events (e.g. sockets, GStreamer bus, ...) and the main loop is something that
    // polls the main context for its events and dispatches them to whoever is
    // interested in them. In this example, we only do have one, so we can
    // leave the context parameter empty, it will automatically select
    // the default one.
69
    let id = server.attach(None)?;
70

71 72 73 74
    println!(
        "Stream ready at rtsp://127.0.0.1:{}/test",
        server.get_bound_port()
    );
75

76 77
    // Start the mainloop. From this point on, the server will start to serve
    // our quality content to connecting clients.
78 79
    main_loop.run();

80 81
    glib::source_remove(id);

82 83 84 85 86 87 88 89 90 91 92 93 94 95
    Ok(())
}

fn example_main() -> Result<(), Error> {
    gst::init()?;
    main_loop()
}

fn main() {
    match examples_common::run(example_main) {
        Ok(r) => r,
        Err(e) => eprintln!("Error! {}", e),
    }
}