Example #1
0
static gsize status_output_size (gchar *job)
{
        gsize size;
        gint i;
        gchar *pipeline;

        size = (strlen (job) / 8 + 1) * 8; /* job description, 64 bit alignment */
        size += sizeof (guint64); /* state */
        size += sizeof (gint64); /* duration for transcode */
        size += jobdesc_streams_count (job, "source") * sizeof (struct _SourceStreamState);
        for (i = 0; i < jobdesc_encoders_count (job); i++) {
                size += sizeof (GstClockTime); /* encoder output heartbeat */
                size += sizeof (gboolean); /* end of stream */
                pipeline = g_strdup_printf ("encoder.%d", i);
                size += jobdesc_streams_count (job, pipeline) * sizeof (struct _EncoderStreamState); /* encoder state */
                g_free (pipeline);
                size += sizeof (guint64); /* cache head */
                size += sizeof (guint64); /* cache tail */
                size += sizeof (guint64); /* last rap (random access point) */
                size += sizeof (guint64); /* total count */
                /* nonlive job has no output */
                if (!jobdesc_is_live (job)) {
                        continue;
                }
                /* output share memory */
                size += SHM_SIZE;
        }

        return size;
}
Example #2
0
/**
 * gstreamill_job_start:
 * @job: (in): json type of job description.
 *
 * Returns: json type of job execution result. 
 */
gchar * gstreamill_job_start (Gstreamill *gstreamill, gchar *job_desc)
{
        gchar *p, *name;
        Job *job;

        if (!jobdesc_is_valid (job_desc)) {
                p = g_strdup_printf ("{\n    \"result\": \"failure\",\n    \"reason\": \"invalid job\"\n}");
                return p;
        }

        if (jobdesc_is_live (job_desc)) {
                GST_ERROR ("live job arrived:\n%s", job_desc);

        } else {
                GST_ERROR ("transcode job arrived:\n%s", job_desc);
        }

        /* create job object */
        name = jobdesc_get_name (job_desc);
        if (get_job (gstreamill, name) != NULL) {
                GST_ERROR ("start job failure, duplicated name %s.", name);
                p = g_strdup_printf ("{\n    \"result\": \"failure\",\n    \"reason\": \"duplicated name\"\n}");
                g_free (name);
                return p;
        }
        job = job_new ("job", job_desc, "name", name, "exe_path", gstreamill->exe_path, NULL);
        g_free (name);

        /* job initialize */
        job->log_dir = gstreamill->log_dir;
        g_mutex_init (&(job->access_mutex));
        job->is_live = jobdesc_is_live (job_desc);
        job->eos = FALSE;
        job->current_access = 0;
        job->age = 0;
        job->last_start_time = NULL;
        if (job_initialize (job, gstreamill->daemon) != 0) {
                p = g_strdup_printf ("{\n    \"result\": \"failure\",\n    \"reason\": \"initialize job failure\"\n}");
                g_object_unref (job);
                return p;
        }

        if (job->is_live && (job_output_initialize (job) != 0)) {
                p = g_strdup_printf ("{\n    \"result\": \"failure\",\n    \"reason\": \"initialize job output failure\"\n}");
                g_object_unref (job);
                return p;
        }

        /* reset and start job */
        job_reset (job);
        if (gstreamill->daemon) {
                guint64 stat;

                stat = create_job_process (job);
                if (stat == JOB_STATE_PLAYING) {
                        GST_ERROR ("Start job %s success", job->name);
                        g_mutex_lock (&(gstreamill->job_list_mutex));
                        gstreamill->job_list = g_slist_append (gstreamill->job_list, job);
                        g_mutex_unlock (&(gstreamill->job_list_mutex));
                        p = g_strdup_printf ("{\n    \"name\": \"%s\",\n\"result\": \"success\"\n}", job->name);

                } else {
                        GST_ERROR ("Start job %s failure, return stat: %s", job->name, job_state_get_name (stat));
                        g_object_unref (job);
                        p = g_strdup_printf ("{\n    \"result\": \"failure\",\n    \"reason\": \"create process failure\"\n}");
                }

        } else {
                job_encoders_output_initialize (job);
                if (job_start (job) == 0) {
                        g_mutex_lock (&(gstreamill->job_list_mutex));
                        gstreamill->job_list = g_slist_append (gstreamill->job_list, job);
                        g_mutex_unlock (&(gstreamill->job_list_mutex));
                        p = g_strdup ("{\n    \"result\": \"success\"\n}");

                } else {
                        p = g_strdup_printf ("{\n    \"result\": \"failure\",\n    \"reason\": \"unknown\"\n}");
                }
        }

        return p;
}
Example #3
0
int main (int argc, char *argv[])
{
        HTTPMgmt *httpmgmt;
        HTTPStreaming *httpstreaming;
        GMainLoop *loop;
        GOptionContext *ctx;
        GError *err = NULL;
        gboolean foreground;
        struct rlimit rlim;
        GDateTime *datetime;
        gchar exe_path[512], *date;

        ctx = g_option_context_new (NULL);
        g_option_context_add_main_entries (ctx, options, NULL);
        g_option_context_add_group (ctx, gst_init_get_option_group ());
        if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
                g_print ("Error initializing: %s\n", GST_STR_NULL (err->message));
                exit (1);
        }
        g_option_context_free (ctx);
        GST_DEBUG_CATEGORY_INIT (GSTREAMILL, "gstreamill", 0, "gstreamill log");

        if (version) {
                print_version_info ();
                exit (0);
        }

        /* stop gstreamill. */
        if (stop) {
                gchar *pid_str;
                gint pid;

                g_file_get_contents (PID_FILE, &pid_str, NULL, NULL);
                if (pid_str == NULL) {
                        g_print ("File %s not found, check if gstreamill is running.\n", PID_FILE);
                        exit (1);
                }
                pid = atoi (pid_str);
                g_free (pid_str);
                g_print ("stoping gstreamill with pid %d ...\n", pid);
                kill (pid, SIGTERM);
                exit (0);
        }

        /* readlink exe path before setuid, on CentOS, readlink exe path after setgid/setuid failure on permission denied */
        memset (exe_path, '\0', sizeof (exe_path));
        if (readlink ("/proc/self/exe", exe_path, sizeof (exe_path)) == -1) {
                g_print ("Read /proc/self/exe error: %s", g_strerror (errno));
                exit (2);
        }

        if (prepare_gstreamill_run_dir () != 0) {
                g_print ("Can't create gstreamill run directory\n");
                exit (3);
        }
/*
        if (set_user_and_group () != 0) {
                g_print ("set user and group failure\n");
                exit (4);
        }
*/
        if (job_file != NULL) {
                /* gstreamill command with job, run in foreground */
                foreground = TRUE;

        } else {
                /* gstreamill command without job, run in background */
                foreground = FALSE;
        }

        if (gst_debug_get_default_threshold () < GST_LEVEL_WARNING) {
                gst_debug_set_default_threshold (GST_LEVEL_WARNING);
        }

        /* initialize ts segment static plugin */
        if (!gst_plugin_register_static (GST_VERSION_MAJOR,
                                         GST_VERSION_MINOR,
                                         "tssegment",
                                         "ts segment plugin",
                                         ts_segment_plugin_init,
                                         "0.1.0",
                                         "GPL",
                                         "GStreamer",
                                         "GStreamer",
                                         "http://gstreamer.net/")) {
                GST_ERROR ("registe tssegment error");
                exit (17);
        }

        /* subprocess, create_job_process */
        if (shm_name != NULL) {
                gint fd;
                gchar *job_desc, *p;
                Job *job;
                gchar *log_path, *name;
                gint ret;

                /* set subprocess maximum of core file */
                rlim.rlim_cur = 0;
                rlim.rlim_max = 0;
                if (setrlimit (RLIMIT_CORE, &rlim) == -1) {
                        GST_ERROR ("setrlimit error: %s", g_strerror (errno));
                }

                /* read job description from share memory */
                job_desc = NULL;
                fd = shm_open (shm_name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
                if (ftruncate (fd, job_length) == -1) {
                        exit (5);
                }
                p = mmap (NULL, job_length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
                job_desc = g_strdup (p);

                if ((job_desc != NULL) && (!jobdesc_is_valid (job_desc))) {
                        exit (6);
                }

                /* initialize log */
                name = (gchar *)jobdesc_get_name (job_desc);
                if (!jobdesc_is_live (job_desc)) {
                        gchar *p;

                        p = jobdesc_get_log_path (job_desc);
                        log_path = g_build_filename (p, "gstreamill.log", NULL);
                        g_free (p);

                } else {
                        log_path = g_build_filename (log_dir, name, "gstreamill.log", NULL);
                }
                ret = init_log (log_path);
                g_free (log_path);
                if (ret != 0) {
                        exit (7);
                }

                /* launch a job. */
                datetime = g_date_time_new_now_local ();
                date = g_date_time_format (datetime, "%b %d %H:%M:%S");
                fprintf (_log->log_hd, "\n*** %s : job %s starting ***\n\n", date, name);
                g_date_time_unref (datetime);
                g_free (date);
                job = job_new ("name", name, "job", job_desc, NULL);
                job->is_live = jobdesc_is_live (job_desc);
                job->eos = FALSE;
                loop = g_main_loop_new (NULL, FALSE);

                GST_INFO ("Initializing job ...");
                if (job_initialize (job, TRUE) != 0) {
                        GST_ERROR ("initialize job failure, exit");
                        exit (8);
                }
                GST_INFO ("Initializing job done");

                GST_INFO ("Initializing job's encoders output ...");
                if (job_encoders_output_initialize (job) != 0) {
                        GST_ERROR ("initialize job encoders' output failure, exit");
                        exit (8);
                }
                GST_INFO ("Initializing job's encoders output done");

                GST_INFO ("Starting job ...");
                if (job_start (job) != 0) {
                        GST_ERROR ("start livejob failure, exit");
                        exit (9);
                }
                datetime = g_date_time_new_now_local ();
                date = g_date_time_format (datetime, "%b %d %H:%M:%S");
                fprintf (_log->log_hd, "\n*** %s : job %s started ***\n\n", date, name);
                g_date_time_unref (datetime);
                g_free (date);
                g_free (name);
                g_free (job_desc);

                signal (SIGPIPE, SIG_IGN);
                signal (SIGUSR1, sighandler);
                signal (SIGTERM, stop_job);

                g_main_loop_run (loop);

        } else {
                /* set parent process maximum of core file */
                rlim.rlim_cur = RLIM_INFINITY;
                rlim.rlim_max = RLIM_INFINITY;
                if (setrlimit (RLIMIT_CORE, &rlim) == -1) {
                        GST_ERROR ("setrlimit error: %s", g_strerror (errno));
                }
        }

        /* run in background? */
        if (!foreground) {
                gchar *path;
                gint ret;

                /* pid file exist? */
                if (g_file_test (PID_FILE, G_FILE_TEST_EXISTS)) {
                        g_print ("file %s found, gstreamill already running !!!\n", PID_FILE);
                        exit (10);
                }

                /* media directory */
                path = g_strdup_printf ("%s/dvr", MEDIA_LOCATION);
                if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
                        g_printf ("Create DVR directory: %s", path);
                        if (g_mkdir_with_parents (path, 0755) != 0) {
                                g_printf ("Create DVR directory failure: %s", path);
                        }
                }
                g_free (path);
                path = g_strdup_printf ("%s/transcode/in", MEDIA_LOCATION);
                if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
                        g_printf ("Create transcode directory: %s", path);
                        if (g_mkdir_with_parents (path, 0755) != 0) {
                                g_printf ("Create transcode directory failure: %s", path);
                        }
                }
                g_free (path);
                path = g_strdup_printf ("%s/transcode/out", MEDIA_LOCATION);
                if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
                        g_printf ("Create transcode directory: %s", path);
                        if (g_mkdir_with_parents (path, 0755) != 0) {
                                g_printf ("Create transcode directory failure: %s", path);
                        }
                }
                g_free (path);

                /* log to file */
                path = g_build_filename (log_dir, "gstreamill.log", NULL);
                ret = init_log (path);
                g_free (path);
                if (ret != 0) {
                        g_print ("Init log error, ret %d.\n", ret);
                        exit (11);
                }

                /* daemonize */
                if (daemon (0, 0) != 0) {
                        fprintf (_log->log_hd, "Failed to daemonize");
                        remove_pid_file ();
                        exit (1);
                }

                /* create pid file */
                if (create_pid_file () != 0) {
                        exit (1);
                }

                /* customize signal */
                signal (SIGUSR1, sighandler);
                signal (SIGTERM, stop_gstreamill);

                datetime = g_date_time_new_now_local ();
                date = g_date_time_format (datetime, "%b %d %H:%M:%S");
                fprintf (_log->log_hd, "\n*** %s : gstreamill started ***\n\n", date);
                g_free (date);
                g_date_time_unref (datetime);
        }

        /* ignore SIGPIPE */
        signal (SIGPIPE, SIG_IGN);

        loop = g_main_loop_new (NULL, FALSE);

        /* gstreamill */
        gstreamill = gstreamill_new ("daemon", !foreground, "log_dir", log_dir, "exe_path", exe_path, NULL);
        if (gstreamill_start (gstreamill) != 0) {
                GST_ERROR ("start gstreamill error, exit.");
                remove_pid_file ();
                exit (12);
        }

        /* httpstreaming, pull */
        httpstreaming = httpstreaming_new ("gstreamill", gstreamill, "address", http_streaming, NULL);
        if (httpstreaming_start (httpstreaming, 10) != 0) {
                GST_ERROR ("start httpstreaming error, exit.");
                remove_pid_file ();
                exit (13);
        }

        if (!foreground) {
                /* run in background, management via http */
                httpmgmt = httpmgmt_new ("gstreamill", gstreamill, "address", http_mgmt, NULL);
                if (httpmgmt_start (httpmgmt) != 0) {
                        GST_ERROR ("start http mangment error, exit.");
                        remove_pid_file ();
                        exit (14);
                }

        } else {
                /* run in foreground, start job */
                gchar *job, *p, *result;
                JSON_Value *val;
                JSON_Object *obj;

                /* ctrl-c, stop gstreamill */
                signal (SIGINT, stop_gstreamill);

                /* ctrl-\, stop gstreamill */
                signal (SIGQUIT, stop_gstreamill);

                if (!g_file_get_contents (job_file, &job, NULL, NULL)) {
                        GST_ERROR ("Read job file %s error.", job_file);
                        exit (15);
                }
                p = gstreamill_job_start (gstreamill, job);
                val = json_parse_string (p);
                obj = json_value_get_object (val);
                result = (gchar *)json_object_get_string (obj, "result");
                GST_INFO ("start job result: %s.", result);
                if (g_strcmp0 (result, "success") != 0) {
                        exit (16);
                }
                json_value_free (val);
                g_free (p);
        }

        g_main_loop_run (loop);

        return 0;
}
Example #4
0
guint encoder_initialize (GArray *earray, gchar *job, EncoderOutput *encoders, Source *source)
{
    gint i, j, k;
    gchar *job_name, *pipeline;
    Encoder *encoder;
    EncoderStream *estream;
    SourceStream *sstream;
    gchar **bins;
    gsize count;

    job_name = jobdesc_get_name (job);
    count = jobdesc_encoders_count (job);
    for (i = 0; i < count; i++) {
        pipeline = g_strdup_printf ("encoder.%d", i);
        encoder = encoder_new ("name", pipeline, NULL);
        encoder->job_name = g_strdup (job_name);
        encoder->id = i;
        encoder->last_running_time = GST_CLOCK_TIME_NONE;
        encoder->output = &(encoders[i]);
        encoder->segment_duration = jobdesc_m3u8streaming_segment_duration (job);
        encoder->duration_accumulation = 0;
        encoder->last_segment_duration = 0;
        encoder->force_key_count = 0;
        encoder->has_video = FALSE;
        encoder->has_audio_only = FALSE;
        encoder->has_tssegment = FALSE;

        bins = jobdesc_bins (job, pipeline);
        if (encoder_extract_streams (encoder, bins) != 0) {
            GST_ERROR ("extract encoder %s streams failure", encoder->name);
            g_free (job_name);
            g_free (pipeline);
            g_strfreev (bins);
            return 1;
        }
        g_strfreev (bins);

        for (j = 0; j < encoder->streams->len; j++) {
            estream = g_array_index (encoder->streams, gpointer, j);
            estream->state = &(encoders[i].streams[j]);
            g_strlcpy (encoders[i].streams[j].name, estream->name, STREAM_NAME_LEN);
            estream->encoder = encoder;
            estream->source = NULL;
            for (k = 0; k < source->streams->len; k++) {
                sstream = g_array_index (source->streams, gpointer, k);
                if (g_strcmp0 (sstream->name, estream->name) == 0) {
                    estream->source = sstream;
                    estream->current_position = -1;
                    estream->system_clock = encoder->system_clock;
                    g_array_append_val (sstream->encoders, estream);
                    break;
                }
            }
            if (estream->source == NULL) {
                GST_ERROR ("cant find job %s source %s.", job_name, estream->name);
                g_free (job_name);
                g_free (pipeline);
                return 1;
            }
        }

        /* mkdir for transcode job. */
        if (!jobdesc_is_live (job)) {
            gchar *locations[] = {"%s.elements.filesink.property.location", "%s.elements.hlssink.property.location", NULL};
            gchar *p, *value, **location;

            location = locations;
            while (*location != NULL) {
                p = g_strdup_printf (*location, pipeline);
                value = jobdesc_element_property_value (job, p);
                g_free (p);
                if (value != NULL) {
                    break;
                }
                location += 1;
            }
            if (*location == NULL) {
                GST_ERROR ("No location found for transcode");
                return 1;
            }
            p = g_path_get_dirname (value);
            g_free (value);
            if (g_mkdir_with_parents (p, 0755) != 0) {
                GST_ERROR ("Can't open or create directory: %s.", p);
                g_free (p);
                return 1;
            }
            g_free (p);
        }

        /* parse bins and create pipeline. */
        encoder->bins = bins_parse (job, pipeline);
        if (encoder->bins == NULL) {
            GST_ERROR ("parse job %s bins error", job_name);
            g_free (job_name);
            g_free (pipeline);
            return 1;
        }
        complete_request_element (encoder->bins);
        if (create_encoder_pipeline (encoder) != 0) {
            GST_ERROR ("create encoder %s pipeline failure", encoder->name);
            g_free (job_name);
            g_free (pipeline);
            return 1;
        }

        /* parse udpstreaming */
        udpstreaming_parse (job, encoder);

        /* m3u8 playlist */
        encoder->is_first_key = TRUE;
        if (jobdesc_m3u8streaming (job)) {
            memset (&(encoder->msg_sock_addr), 0, sizeof (struct sockaddr_un));
            encoder->msg_sock_addr.sun_family = AF_UNIX;
            strncpy (encoder->msg_sock_addr.sun_path, MSG_SOCK_PATH, sizeof (encoder->msg_sock_addr.sun_path) - 1);
            encoder->msg_sock = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0);
            encoder->has_m3u8_output = TRUE;

        } else {
            encoder->has_m3u8_output = FALSE;
        }

        g_free (pipeline);
        g_array_append_val (earray, encoder);
    }
    g_free (job_name);

    return 0;
}
Example #5
0
/**
 * gstreamill_job_start:
 * @job: (in): json type of job description.
 *
 * Returns: json type of job execution result. 
 */
gchar * gstreamill_job_start (Gstreamill *gstreamill, gchar *job_desc)
{
        gchar *p, *name;
        Job *job;

        if (!jobdesc_is_valid (job_desc)) {
                p = g_strdup ("Invalid job");
                return p;
        }

        if (jobdesc_is_live (job_desc)) {
                GST_ERROR ("live job arrived");

        } else {
                GST_ERROR ("transcode job arrived");
        }

        /* create job object */
        name = jobdesc_get_name (job_desc);
        if (get_job (gstreamill, name) != NULL) {
                GST_ERROR ("start live job failure, duplicated name %s.", name);
                p = g_strdup_printf ("start live job failure, duplicated name %s.", name);
                g_free (name);
                return p;
        }
        job = job_new ("job", job_desc, "name", name, NULL);
        g_free (name);

        /* job initialize */
        job->log_dir = gstreamill->log_dir;
        g_mutex_init (&(job->access_mutex));
        job->is_live = jobdesc_is_live (job_desc);
        job->eos = FALSE;
        job->current_access = 0;
        job->age = 0;
        job->last_start_time = NULL;
        if (job_initialize (job, gstreamill->daemon) != 0) {
                p = g_strdup ("initialize job failure");
                g_object_unref (job);
                return p;
        }

        /* reset and start job */
        job_reset (job);
        if (gstreamill->daemon) {
                p = create_job_process (job);
                GST_ERROR ("%s: %s", p, job->name);
                if (g_str_has_suffix (p, "success")) {
                        g_mutex_lock (&(gstreamill->job_list_mutex));
                        gstreamill->job_list = g_slist_append (gstreamill->job_list, job);
                        g_mutex_unlock (&(gstreamill->job_list_mutex));

                } else {
                        g_object_unref (job);
                }

        } else {
                if (job_start (job) == 0) {
                        g_mutex_lock (&(gstreamill->job_list_mutex));
                        gstreamill->job_list = g_slist_append (gstreamill->job_list, job);
                        g_mutex_unlock (&(gstreamill->job_list_mutex));
                        p = g_strdup ("success");

                } else {
                        p = g_strdup ("failure");
                }
        }

        return p;
}