/* * vim: set sts=2 sw=2 et : * * License: LGPL-2.1+ * Copyright (c) 2014 Nirbheek Chauhan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "local-play.h" static void pad_has_video_caps (TranscodeServerCtx *ctx, GstPad *decodebin_pad) { GstPad *sink_pad; GstElement *bin; GstElement *videoconv, *videoscale, *videosink; bin = gst_bin_new (NULL); videoconv = gst_element_factory_make ("videoconvert", "videoconv"); videoscale = gst_element_factory_make ("videoscale", "videoscale"); videosink = gst_element_factory_make ("autovideosink", "videosink"); gst_bin_add_many (GST_BIN (bin), videoconv, videoscale, videosink, NULL); gst_element_link_many (videoconv, videoscale, videosink, NULL); sink_pad = gst_element_get_static_pad (videoconv, "sink"); gst_element_add_pad (bin, gst_ghost_pad_new ("sink", sink_pad)); gst_object_unref (sink_pad); gst_bin_add (GST_BIN (ctx->pipeline), bin); sink_pad = gst_element_get_static_pad (bin, "sink"); if (gst_pad_link (decodebin_pad, sink_pad) != GST_PAD_LINK_OK) { g_critical ("ERROR: Unable to link video pads"); soup_message_set_status (ctx->msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); goto out; } /* Since these elements have been added to the pipeline after the state was * changed from GST_STATE_NULL, they have to be moved to PAUSED manually */ gst_element_set_state (bin, GST_STATE_PAUSED); out: gst_object_unref (sink_pad); return; } static void pad_has_audio_caps (TranscodeServerCtx *ctx, GstPad *decodebin_pad) { GstPad *sink_pad; GstElement *bin; GstElement *audioconv, *audioresample, *audiosink; bin = gst_bin_new (NULL); audioconv = gst_element_factory_make ("audioconvert", "audioconv"); audioresample = gst_element_factory_make ("audioresample", "audioresample"); audiosink = gst_element_factory_make ("autoaudiosink", "audiosink"); gst_bin_add_many (GST_BIN (bin), audioconv, audioresample, audiosink, NULL); gst_element_link_many (audioconv, audioresample, audiosink, NULL); sink_pad = gst_element_get_static_pad (audioconv, "sink"); gst_element_add_pad (bin, gst_ghost_pad_new ("sink", sink_pad)); gst_object_unref (sink_pad); gst_bin_add (GST_BIN (ctx->pipeline), bin); sink_pad = gst_element_get_static_pad (bin, "sink"); if (gst_pad_link (decodebin_pad, sink_pad) != GST_PAD_LINK_OK) { g_critical ("ERROR: Unable to link video pads"); soup_message_set_status (ctx->msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); goto out; } /* Since these elements have been added to the pipeline after the state was * changed from GST_STATE_NULL, they have to be moved to PAUSED manually */ gst_element_set_state (bin, GST_STATE_PAUSED); out: gst_object_unref (sink_pad); return; } static gboolean structure_printf (GQuark field_id, const GValue *value, gpointer user_data) { char *char_value; char_value = g_strdup_value_contents (value); g_print ("%s = %s\n", g_quark_to_string (field_id), char_value); g_free (char_value); return TRUE; } static void decodebin_pad_added (GstElement *decodebin, GstPad *src_pad, gpointer user_data) { GstCaps *pad_caps; GstStructure *structure; TranscodeServerCtx *ctx = user_data; if (!gst_pad_has_current_caps (src_pad)) { g_critical ("Decodebin pad doesn't have current caps"); soup_message_set_status (ctx->msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); return; } pad_caps = gst_pad_get_current_caps (src_pad); structure = gst_caps_get_structure (pad_caps, 0); gst_structure_foreach (structure, structure_printf, NULL); if (gst_structure_has_name (structure, "audio/x-raw")) pad_has_audio_caps (ctx, src_pad); else if (gst_structure_has_name (structure, "video/x-raw")) pad_has_video_caps (ctx, src_pad); else g_critical ("Found unsupported caps: %s", gst_structure_get_name (structure)); gst_caps_unref (pad_caps); } void stp_play_from_msg (TranscodeServerCtx *ctx) { GstBus *bus; GstElement *src, *decodebin; g_debug ("Constructing pipeline\n"); src = gst_element_factory_make ("appsrc", "src"); g_object_set (src, "is-live", TRUE, "stream-type", 0, NULL); ctx->appsrc = src; decodebin = gst_element_factory_make ("decodebin", "decodebin"); gst_bin_add_many (GST_BIN (ctx->pipeline), src, decodebin, NULL); gst_element_link (src, decodebin); g_signal_connect (decodebin, "pad-added", G_CALLBACK (decodebin_pad_added), ctx); bus = gst_pipeline_get_bus (GST_PIPELINE (ctx->pipeline)); gst_bus_add_signal_watch (bus); g_signal_connect (bus, "message", G_CALLBACK (stp_on_gst_bus_message), ctx); g_object_unref (bus); }