I ended up getting this working using Janus and GStreamer (1.9) by following the suggestions of others in this thread including @nschoe (the OP) and @Benjamin Trent. I figured that I would include my code to make life easier for the next person who comes along since so much trial-and-error was involved for me:
First build/install GStreamer with all its needed plugins (for my setup I needed to ensure that two plugin directories were in the GST_PLUGIN_SYSTEM_PATH environment variable). Now initialize GStreamer when your Janus plugin initializes (init()
callback):
gst_init(NULL, NULL);
For each WebRTC session, you'll need to keep some GStreamer handles, so add the following to your Janus plugin session struct:
GstElement *pipeline, *appsrc, *multifilesink;
When a Janus plugin session is created (create_session()
callback), setup the GStreamer pipeline for that session (in my case I needed to lower the frame rate, hence the videorate/capsrate; you may not need these):
GstElement *conv, *vp8depay, *vp8dec, *videorate, *capsrate, *pngenc;
session->pipeline = gst_pipeline_new("pipeline");
session->appsrc = gst_element_factory_make("appsrc", "source");
vp8depay = gst_element_factory_make("rtpvp8depay", NULL);
vp8dec = gst_element_factory_make("vp8dec", NULL);
videorate = gst_element_factory_make("videorate", NULL);
capsrate = gst_element_factory_make("capsfilter", NULL);
conv = gst_element_factory_make("videoconvert", "conv");
pngenc = gst_element_factory_make("pngenc", NULL);
session->multifilesink = gst_element_factory_make("multifilesink", NULL);
GstCaps* capsRate = gst_caps_new_simple("video/x-raw", "framerate", GST_TYPE_FRACTION, 15, 1, NULL);
g_object_set(capsrate, "caps", capsRate, NULL);
gst_caps_unref(capsRate);
GstCaps* caps = gst_caps_new_simple ("application/x-rtp",
"media", G_TYPE_STRING, "video",
"encoding-name", G_TYPE_STRING, "VP8-DRAFT-IETF-01",
"payload", G_TYPE_INT, 96,
"clock-rate", G_TYPE_INT, 90000,
NULL);
g_object_set(G_OBJECT (session->appsrc), "caps", caps, NULL);
gst_caps_unref(caps);
gst_bin_add_many(GST_BIN(session->pipeline), session->appsrc, vp8depay, vp8dec, conv, videorate, capsrate, pngenc, session->multifilesink, NULL);
gst_element_link_many(session->appsrc, vp8depay, vp8dec, conv, videorate, capsrate, pngenc, session->multifilesink, NULL);
// Setup appsrc
g_object_set(G_OBJECT (session->appsrc), "stream-type", 0, NULL);
g_object_set(G_OBJECT (session->appsrc), "format", GST_FORMAT_TIME, NULL);
g_object_set(G_OBJECT (session->appsrc), "is-live", TRUE, NULL);
g_object_set(G_OBJECT (session->appsrc), "do-timestamp", TRUE, NULL);
g_object_set(session->multifilesink, "location", "/blah/some/dir/output-%d.png", NULL);
gst_element_set_state(session->pipeline, GST_STATE_PLAYING);
When an incoming RTP packet gets demultiplexed by Janus and is ready to read, (incoming_rtp()
callback), feed it into the GStreamer pipeline:
if(video && session->video_active) {
// Send to GStreamer
guchar* temp = NULL;
temp = (guchar*)malloc(len);
memcpy(temp, buf, len);
GstBuffer* buffer = gst_buffer_new_wrapped_full(0, temp, len, 0, len, temp, g_free);
gst_app_src_push_buffer(GST_APP_SRC(session->appsrc), buffer);
}
Finally, when the Janus plugin session is over (destroy_session()
callback), be sure to free up the GStreamer resources:
if(session->pipeline) {
gst_element_set_state(session->pipeline, GST_STATE_NULL);
gst_object_unref(session->pipeline);
session->pipeline = NULL;
}