static gchar * render_master_m3u8_playlist (Job *job) { GString *master_m3u8_playlist; gchar *p, *value; gint i; master_m3u8_playlist = g_string_new (""); g_string_append_printf (master_m3u8_playlist, M3U8_HEADER_TAG); if (jobdesc_m3u8streaming_version (job->description) == 0) { g_string_append_printf (master_m3u8_playlist, M3U8_VERSION_TAG, 3); } else { g_string_append_printf (master_m3u8_playlist, M3U8_VERSION_TAG, jobdesc_m3u8streaming_version (job->description)); } for (i = 0; i < job->output->encoder_count; i++) { p = g_strdup_printf ("encoder.%d.elements.x264enc.property.bitrate", i); value = jobdesc_element_property_value (job->description, p); if (value != NULL) { GST_INFO ("job %s with m3u8 output, append end tag", job->name); g_string_append_printf (master_m3u8_playlist, M3U8_STREAM_INF_TAG, 1, value); g_string_append_printf (master_m3u8_playlist, "encoder/%d/playlist.m3u8<%%parameters%%>\n", i); g_free (value); } g_free (p); } p = master_m3u8_playlist->str; g_string_free (master_m3u8_playlist, FALSE); return p; }
static void job_check_func (gpointer data, gpointer user_data) { Job *job = (Job *)data; Gstreamill *gstreamill = (Gstreamill *)user_data; if (gstreamill->stop) { GST_ERROR ("waitting %s stopped", job->name); return; } /* stat report. */ if (gstreamill->daemon && (job->worker_pid != 0)) { job_stat_update (job); GST_INFO ("Job %s's average cpu: %d%%, cpu: %d%%, rss: %lu", job->name, job->cpu_average, job->cpu_current, job->memory); } if (*(job->output->state) != JOB_STATE_PLAYING) { return; } source_check (gstreamill, job); encoders_check (gstreamill, job); if (job->is_live) { sync_check (gstreamill, job); } /* check non live job eos */ if (!job->is_live) { gint i; gboolean eos = TRUE; for (i = 0; i < job->output->encoder_count; i++) { if (!(*(job->output->encoders[i].eos))) { eos = FALSE; break; } else { /* add #EXT-X-ENDLIST to playlist if output is m3u8 */ gchar *location, *property, *playlist1, *playlist2; property = g_strdup_printf ("encoder.%d.elements.hlssink.property.playlist-location", i); location = jobdesc_element_property_value (job->description, property); g_free (property); if (location != NULL) { g_file_get_contents (location, &playlist1, NULL, NULL); playlist2 = g_strdup_printf ("%s#EXT-X-ENDLIST\n", playlist1); g_file_set_contents (location, playlist2, strlen(playlist2), NULL); g_free (playlist1); g_free (playlist2); g_free (location); } } } if (eos) { stop_job (job, SIGTERM); job->eos = TRUE; } } }
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; }