summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2014-10-02 00:24:31 +0200
committerChristian Pointner <equinox@spreadspace.org>2014-10-02 00:24:31 +0200
commit9f2b989e2dd9c8e50a8b3accb2f5afdee045b89e (patch)
treea909466325338948933a732c83d015b4ce13b337 /src
parentsydra create bin now lets the caller control wheter to create ghost pads or not (diff)
source and sink are now same bin for video and audio
Diffstat (limited to 'src')
-rw-r--r--src/options.c33
-rw-r--r--src/options.h7
-rw-r--r--src/pipelines.c106
3 files changed, 92 insertions, 54 deletions
diff --git a/src/options.c b/src/options.c
index 532039b..c9d1af3 100644
--- a/src/options.c
+++ b/src/options.c
@@ -61,21 +61,22 @@ static void options_defaults(options_t* opt)
opt->appname_ = NULL;
opt->mode_ = SENDER;
- opt->video_src_ = g_strdup("v4l2src ! videoconvert ! videoscale ! video/x-raw,format=I420,width=864,height=480,framerate=25/1,pixel-aspect-ratio=1/1 ! identity");
+ opt->source_ = g_strdup("v4l2src ! videoconvert ! videoscale ! video/x-raw,format=I420,width=864,height=480,framerate=25/1,pixel-aspect-ratio=1/1 ! identity name=\"videosrc\" " \
+ "autoaudiosrc ! audio/x-raw,format=S16LE,channels=1,rate=48000 ! identity name=\"audiosrc\"");
+ opt->sink_ = g_strdup("videoconvert name=\"videosink\" ! videoscale add-borders=true ! xvimagesink " \
+ "audioconvert name=\"audiosink\" ! autoaudiosink");
+
opt->video_enc_ = g_strdup("vp8enc keyframe-max-dist=25 error-resilient=2 end-usage=1 target-bitrate=1200000 cpu-used=4 deadline=1000000 threads=2");
opt->video_payloader_ = g_strdup("rtpvp8pay");
opt->video_caps_ = g_strdup("application/x-rtp,media=video,clock-rate=90000,encoding-name=VP8-DRAFT-IETF-01,caps=\"video/x-vp8\"");
opt->video_depayloader_ = g_strdup("rtpvp8depay");
opt->video_dec_ = g_strdup("vp8dec");
- opt->video_sink_ = g_strdup("videoconvert ! videoscale add-borders=true ! xvimagesink");
- opt->audio_src_ = g_strdup("autoaudiosrc ! audio/x-raw,format=S16LE,channels=1,rate=48000 ! identity");
opt->audio_enc_ = g_strdup("opusenc bitrate=64000 cbr=true packet-loss-percentage=0 inband-fec=false");
opt->audio_payloader_ = g_strdup("rtpopuspay");
opt->audio_caps_ = g_strdup("application/x-rtp,media=audio,clock-rate=48000,payload=96,encoding-name=X-GST-OPUS-DRAFT-SPITTKA-00,caps=\"audio/x-opus\"");
opt->audio_depayloader_ = g_strdup("rtpopusdepay");
opt->audio_dec_ = g_strdup("opusdec");
- opt->audio_sink_ = g_strdup("audioconvert ! autoaudiosink");
opt->rtp_host_ = NULL;
opt->rtp_port_base_ = 5000;
@@ -104,16 +105,14 @@ static GQuark options_error_quark()
static GOptionGroup* options_get_avsend_group(options_t* opt)
{
GOptionEntry avsend_entries[] = {
- { "video-source", 0, 0, G_OPTION_ARG_STRING, &opt->video_src_,
- "pipeline for raw video (i.e. videotestsrc)", "BIN DESCRIPTION" },
+ { "source", 0, 0, G_OPTION_ARG_STRING, &opt->source_,
+ "pipeline for raw video and audio", "BIN DESCRIPTION" },
{ "video-encoder", 0, 0, G_OPTION_ARG_STRING, &opt->video_enc_,
"pipeline for video encoder (i.e. videoconvert ! vp8enc)", "BIN DESCRIPTION" },
{ "video-payloader", 0, 0, G_OPTION_ARG_STRING, &opt->video_payloader_,
"video RTP payloader element (i.e. rtpvp8pay)", "ELEMENT" },
{ "previewsink", 0, 0, G_OPTION_ARG_STRING, &opt->preview_videosink_,
"video sink element for local preview (i.e. textoverlay text=\" preview \" ! xvimagesink) - leave empty to disable preview", "BIN DESCRIPTION" },
- { "audio-source", 0, 0, G_OPTION_ARG_STRING, &opt->audio_src_,
- "pipeline for raw audio (i.e. audiotestsrc)", "BIN DESCRIPTION" },
{ "audio-encoder", 0, 0, G_OPTION_ARG_STRING, &opt->audio_enc_,
"pipeline for audio encoder (i.e. audioconvert ! opusenc)", "BIN DESCRIPTION" },
{ "audio-payloader", 0, 0, G_OPTION_ARG_STRING, &opt->audio_payloader_,
@@ -137,16 +136,14 @@ static GOptionGroup* options_get_avrecv_group(options_t* opt)
"video RTP depayloader element (i.e. rtpvp8depay)", "ELEMENT" },
{ "video-decoder", 0, 0, G_OPTION_ARG_STRING, &opt->video_dec_,
"pipeline for video decoder (i.e. vp8dec)", "BIN DESCRIPTION" },
- { "video-sink", 0, 0, G_OPTION_ARG_STRING, &opt->video_sink_,
- "video sink element (i.e. videoconvert ! xvimagesink)", "BIN DESCRIPTION" },
{ "audio-caps", 0, 0, G_OPTION_ARG_STRING, &opt->audio_caps_,
"Caps for incoming Audio RTP packets", "CAPS" },
{ "audio-depayloader", 0, 0, G_OPTION_ARG_STRING, &opt->audio_depayloader_,
"audio RTP depayloader element (i.e. rtpopusdepay)", "ELEMENT" },
{ "audio-decoder", 0, 0, G_OPTION_ARG_STRING, &opt->audio_dec_,
"pipeline for audio decoder (i.e. opusdnc)", "BIN DESCRIPTION" },
- { "audio-sink", 0, 0, G_OPTION_ARG_STRING, &opt->audio_sink_,
- "audio sink element (i.e. audioconvert ! autoaudiosink)", "BIN DESCRIPTION" },
+ { "sink", 0, 0, G_OPTION_ARG_STRING, &opt->sink_,
+ "video/audio sink element", "BIN DESCRIPTION" },
{ NULL }
};
GOptionGroup* avrecv_group = g_option_group_new ("avrecv", "Audio/Video Receiver Options",
@@ -342,20 +339,18 @@ void options_clear(options_t* opt)
g_free(opt->pid_file_);
g_strfreev(opt->log_targets_);
g_free(opt->appname_);
- g_free(opt->video_src_);
+ g_free(opt->source_);
+ g_free(opt->sink_);
g_free(opt->video_enc_);
g_free(opt->video_payloader_);
g_free(opt->video_caps_);
g_free(opt->video_depayloader_);
g_free(opt->video_dec_);
- g_free(opt->video_sink_);
- g_free(opt->audio_src_);
g_free(opt->audio_enc_);
g_free(opt->audio_payloader_);
g_free(opt->audio_caps_);
g_free(opt->audio_depayloader_);
g_free(opt->audio_dec_);
- g_free(opt->audio_sink_);
g_free(opt->rtp_host_);
g_free(opt->rtp_addr_local_);
g_free(opt->preview_videosink_);
@@ -407,20 +402,18 @@ void options_print(options_t* opt)
printf(" debug: %s\n", opt->debug_ ? "true" : "false");
printf(" appname: >>%s<<\n", opt->appname_);
printf(" mode: >>%s<<\n", opt->mode_ == SENDER ? "sender" : "receiver");
- printf(" video_src: >>%s<<\n", opt->video_src_);
+ printf(" source: >>%s<<\n", opt->source_);
+ printf(" sink: >>%s<<\n", opt->sink_);
printf(" video_enc: >>%s<<\n", opt->video_enc_);
printf(" video_payloader: >>%s<<\n", opt->video_payloader_);
printf(" video_caps: >>%s<<\n", opt->video_caps_);
printf(" video_depayloader: >>%s<<\n", opt->video_depayloader_);
printf(" video_dec: >>%s<<\n", opt->video_dec_);
- printf(" video_sink: >>%s<<\n", opt->video_sink_);
- printf(" audio_src: >>%s<<\n", opt->audio_src_);
printf(" audio_enc: >>%s<<\n", opt->audio_enc_);
printf(" audio_payloader: >>%s<<\n", opt->audio_payloader_);
printf(" audio_caps: >>%s<<\n", opt->audio_caps_);
printf(" audio_depayloader: >>%s<<\n", opt->audio_depayloader_);
printf(" audio_dec: >>%s<<\n", opt->audio_dec_);
- printf(" audio_sink: >>%s<<\n", opt->audio_sink_);
printf(" rtp_host: >>%s<<\n", opt->rtp_host_);
printf(" rtp_port_base: %d\n", opt->rtp_port_base_);
printf(" rtp_addr_local: >>%s<<\n", opt->rtp_addr_local_);
diff --git a/src/options.h b/src/options.h
index 30d7433..cf18b9f 100644
--- a/src/options.h
+++ b/src/options.h
@@ -51,21 +51,20 @@ struct options_struct {
gchar* appname_;
sydra_mode_t mode_;
- gchar* video_src_;
+ gchar* source_;
+ gchar* sink_;
+
gchar* video_enc_;
gchar* video_payloader_;
gchar* video_caps_;
gchar* video_depayloader_;
gchar* video_dec_;
- gchar* video_sink_;
- gchar* audio_src_;
gchar* audio_enc_;
gchar* audio_payloader_;
gchar* audio_caps_;
gchar* audio_depayloader_;
gchar* audio_dec_;
- gchar* audio_sink_;
gchar* rtp_host_;
gint rtp_port_base_;
diff --git a/src/pipelines.c b/src/pipelines.c
index abe6fca..c291549 100644
--- a/src/pipelines.c
+++ b/src/pipelines.c
@@ -43,14 +43,10 @@
#include "utils.h"
#include "log.h"
-
-
struct av_elements {
const char* name_;
- const char* srcsink_str_;
GstElement* srcsink_;
-
GstElement* tee_raw_;
const char* encdec_str_;
@@ -62,34 +58,58 @@ struct av_elements {
GstElement* payloader_;
};
-static gboolean create_avsend_elements(struct av_elements *ave, GstElement* pipeline, GstElement *rtp, uint32_t session)
+static GstElement* create_avsend_src(const char* desc, GstElement* pipeline)
{
- char bin_name[32];
+ GstElement* src = sydra_create_bin_from_desc("AV source", desc, FALSE);
+ if(!src) return NULL;
+ gst_bin_add(GST_BIN(pipeline), src);
+
+ GstElement* element = gst_bin_get_by_name(GST_BIN(src), "videosrc");
+ GstPad* pad = gst_element_get_static_pad(element, "src");
+ if(!gst_element_add_pad(src, gst_ghost_pad_new("video", pad))) {
+ log_printf(ERROR, "can't create video ghost pad for source bin");
+ return NULL;
+ }
+ gst_object_unref(GST_OBJECT(pad));
+ gst_object_unref(GST_OBJECT(element));
+
+ element = gst_bin_get_by_name(GST_BIN(src), "audiosrc");
+ pad = gst_element_get_static_pad(element, "src");
+ if(!gst_element_add_pad(src, gst_ghost_pad_new("audio", pad))) {
+ log_printf(ERROR, "can't create video ghost pad for source bin");
+ return NULL;
+ }
+ gst_object_unref(GST_OBJECT(pad));
+ gst_object_unref(GST_OBJECT(element));
+
+ return src;
+}
- snprintf(bin_name, sizeof(bin_name), "%s source", ave->name_);
- ave->srcsink_ = sydra_create_bin_from_desc(bin_name, ave->srcsink_str_, TRUE);
+static gboolean create_avsend_elements(struct av_elements *ave, GstElement* pipeline, GstElement *rtp, uint32_t session)
+{
ave->tee_raw_ = sydra_create_element("tee", NULL);
GstElement *qr = sydra_create_element("queue", NULL);
+ char bin_name[32];
snprintf(bin_name, sizeof(bin_name), "%s encoder", ave->name_);
ave->encdec_ = sydra_create_bin_from_desc(bin_name, ave->encdec_str_, TRUE);
ave->tee_enc_ = sydra_create_element("tee", NULL);
GstElement *qe = sydra_create_element("queue", NULL);
ave->payloader_ = sydra_create_element(ave->payloader_str_, NULL);
- if(!ave->srcsink_ || !ave->tee_raw_ || !qr || !ave->encdec_ || !ave->tee_enc_ || !qe || !ave->payloader_) {
+ if(!ave->tee_raw_ || !qr || !ave->encdec_ || !ave->tee_enc_ || !qe || !ave->payloader_) {
return FALSE;
}
log_printf(DEBUG, "%s path created successfully!", ave->name_);
- gst_bin_add_many (GST_BIN(pipeline), ave->srcsink_, ave->tee_raw_, qr, ave->encdec_, ave->tee_enc_, qe, ave->payloader_, NULL);
- gst_element_link(ave->srcsink_, ave->tee_raw_);
+ gst_bin_add_many(GST_BIN(pipeline), ave->tee_raw_, qr, ave->encdec_, ave->tee_enc_, qe, ave->payloader_, NULL);
+ if(!sydra_link_static_static(ave->srcsink_, ave->name_, ave->tee_raw_, "sink")) return FALSE;
gst_element_link_many(qr, ave->encdec_, ave->tee_enc_, NULL);
gst_element_link(qe, ave->payloader_);
char pad_name[32];
- snprintf(pad_name, sizeof(bin_name), "send_rtp_sink_%u", session);
+ snprintf(pad_name, sizeof(pad_name), "send_rtp_sink_%u", session);
if(!sydra_link_request_static(ave->tee_raw_, "src_%u", qr, "sink") ||
!sydra_link_request_static(ave->tee_enc_, "src_%u", qe, "sink") ||
!sydra_link_static_request(ave->payloader_, "src", rtp, pad_name)) {
@@ -100,29 +120,54 @@ static gboolean create_avsend_elements(struct av_elements *ave, GstElement* pipe
return TRUE;
}
-static gboolean create_avrecv_elements(struct av_elements *ave, GstElement* pipeline)
+static GstElement* create_avrecv_sink(const char* desc, GstElement* pipeline)
{
- char bin_name[32];
+ GstElement* sink = sydra_create_bin_from_desc("AV sink", desc, FALSE);
+ if(!sink) return NULL;
+ gst_bin_add(GST_BIN(pipeline), sink);
+
+ GstElement* element = gst_bin_get_by_name(GST_BIN(sink), "videosink");
+ GstPad* pad = gst_element_get_static_pad(element, "sink");
+ if(!gst_element_add_pad(sink, gst_ghost_pad_new("video", pad))) {
+ log_printf(ERROR, "can't create video ghost pad for source bin");
+ return NULL;
+ }
+ gst_object_unref(GST_OBJECT(pad));
+ gst_object_unref(GST_OBJECT(element));
+
+ element = gst_bin_get_by_name(GST_BIN(sink), "audiosink");
+ pad = gst_element_get_static_pad(element, "sink");
+ if(!gst_element_add_pad(sink, gst_ghost_pad_new("audio", pad))) {
+ log_printf(ERROR, "can't create video ghost pad for source bin");
+ return NULL;
+ }
+ gst_object_unref(GST_OBJECT(pad));
+ gst_object_unref(GST_OBJECT(element));
+
+ return sink;
+}
- snprintf(bin_name, sizeof(bin_name), "%s sink", ave->name_);
- ave->srcsink_ = sydra_create_bin_from_desc(bin_name, ave->srcsink_str_, TRUE);
+static gboolean create_avrecv_elements(struct av_elements *ave, GstElement* pipeline)
+{
ave->tee_raw_ = sydra_create_element("tee", NULL);
GstElement *qr = sydra_create_element("queue", NULL);
+ char bin_name[32];
snprintf(bin_name, sizeof(bin_name), "%s decoder", ave->name_);
ave->encdec_ = sydra_create_bin_from_desc(bin_name, ave->encdec_str_, TRUE);
ave->tee_enc_ = sydra_create_element("tee", NULL);
GstElement *qe = sydra_create_element("queue", NULL);
ave->payloader_ = sydra_create_element(ave->payloader_str_, NULL);
- if(!ave->srcsink_ || !ave->tee_raw_ || !qr || !ave->encdec_ || !ave->tee_enc_ || !qe || !ave->payloader_) {
+ if(!ave->tee_raw_ || !qr || !ave->encdec_ || !ave->tee_enc_ || !qe || !ave->payloader_) {
return FALSE;
}
log_printf(DEBUG, "%s path created successfully!", ave->name_);
- gst_bin_add_many (GST_BIN(pipeline), ave->srcsink_, ave->tee_raw_, qr, ave->encdec_, ave->tee_enc_, qe, ave->payloader_, NULL);
- gst_element_link_many(ave->payloader_, ave->tee_enc_, qe, ave->encdec_, ave->tee_raw_, qr, ave->srcsink_, NULL);
+ gst_bin_add_many (GST_BIN(pipeline), ave->tee_raw_, qr, ave->encdec_, ave->tee_enc_, qe, ave->payloader_, NULL);
+ gst_element_link_many(ave->payloader_, ave->tee_enc_, qe, ave->encdec_, ave->tee_raw_, qr, NULL);
+ if(!sydra_link_static_static(qr, "sink", ave->srcsink_, ave->name_)) return FALSE;
log_printf(DEBUG, "%s path linked successfully!", ave->name_);
return TRUE;
@@ -314,16 +359,16 @@ GstElement* create_sender_pipeline(options_t* opt, struct udp_sinks *udp)
return NULL;
}
GstElement *rtp = sydra_create_element("rtpbin", "rtpbin");
- if(!rtp || !gst_bin_add(GST_BIN(pipeline), rtp)) {
- return NULL;
- }
+ if(!rtp || !gst_bin_add(GST_BIN(pipeline), rtp)) return NULL;
log_printf(DEBUG, "rtpbin created successfully!");
- struct av_elements video = { "video", opt->video_src_, NULL, NULL,
- opt->video_enc_, NULL, NULL,
+ GstElement* src = create_avsend_src(opt->source_, pipeline);
+ if(!src) return NULL;
+ log_printf(DEBUG, "source bin created successfully!");
+
+ struct av_elements video = { "video", src, NULL, opt->video_enc_, NULL, NULL,
opt->video_payloader_, NULL };
- struct av_elements audio = { "audio", opt->audio_src_, NULL, NULL,
- opt->audio_enc_, NULL, NULL,
+ struct av_elements audio = { "audio", src, NULL, opt->audio_enc_, NULL, NULL,
opt->audio_payloader_, NULL };
if(!create_avsend_elements(&video, pipeline, rtp, 0) ||
!create_avsend_elements(&audio, pipeline, rtp, 1) ||
@@ -400,12 +445,13 @@ GstElement* create_receiver_pipeline(options_t* opt, struct udp_sources *udp)
}
log_printf(DEBUG, "rtpbin created successfully!");
+ GstElement* sink = create_avrecv_sink(opt->sink_, pipeline);
+ if(!sink) return NULL;
+ log_printf(DEBUG, "sink bin created successfully!");
- struct av_elements video = { "video", opt->video_sink_, NULL, NULL,
- opt->video_dec_, NULL, NULL,
+ struct av_elements video = { "video", sink, NULL, opt->video_dec_, NULL, NULL,
opt->video_depayloader_, NULL };
- struct av_elements audio = { "audio", opt->audio_sink_, NULL, NULL,
- opt->audio_dec_, NULL, NULL,
+ struct av_elements audio = { "audio", sink, NULL, opt->audio_dec_, NULL, NULL,
opt->audio_depayloader_, NULL };
if(!create_udp_sources(opt, pipeline, rtp, udp) ||
!create_avrecv_elements(&video, pipeline) ||