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; }
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->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; 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; } } /* 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 */ if (jobdesc_m3u8streaming (job)) { gchar *mq_name; mq_name = g_strdup_printf ("/%s.%d", job_name, i); encoder->mqdes = mq_open (mq_name, O_WRONLY); if (encoder->mqdes == -1) { g_free (job_name); g_free (pipeline); GST_ERROR ("mq_open %s error: %s", mq_name, g_strerror (errno)); return 1; } g_free (mq_name); } else { encoder->mqdes = -1; } g_free (pipeline); g_array_append_val (earray, encoder); } g_free (job_name); return 0; }
/** * job_initialize: * @job: (in): the job to be initialized. * @daemon: (in): is gstreamill run in background. * * Initialize the output of the job, the output of the job include the status of source and encoders and * the output stream. * * Returns: 0 on success. */ gint job_initialize (Job *job, gboolean daemon) { gint i, fd; JobOutput *output; gchar *name, *p, *name_hexstr, *semaphore_name; struct timespec ts; sem_t *semaphore; job->output_size = status_output_size (job->description); name_hexstr = unicode_file_name_2_shm_name (job->name); semaphore_name = g_strdup_printf ("/%s", name_hexstr); semaphore = sem_open (semaphore_name, O_CREAT, 0644, 1); if (semaphore == SEM_FAILED) { GST_ERROR ("open semaphore failed: %s", g_strerror (errno)); g_free (semaphore_name); return 1; } if (clock_gettime (CLOCK_REALTIME, &ts) == -1) { GST_ERROR ("clock_gettime error: %s", g_strerror (errno)); g_free (semaphore_name); return 1; } ts.tv_sec += 2; while (sem_timedwait (semaphore, &ts) == -1) { if (errno == EINTR) { continue; } GST_ERROR ("sem_timedwait failure: %s", g_strerror (errno)); g_free (semaphore_name); return 1; } if (daemon) { /* daemon, use share memory */ fd = shm_open (name_hexstr, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); if (fd == -1) { GST_ERROR ("shm_open %s failure: %s", name_hexstr, g_strerror (errno)); job->output = NULL; g_free (name_hexstr); sem_post (semaphore); return 1; } g_free (name_hexstr); if (ftruncate (fd, job->output_size) == -1) { GST_ERROR ("ftruncate error: %s", g_strerror (errno)); job->output = NULL; sem_post (semaphore); return 1; } p = mmap (NULL, job->output_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); job->output_fd = fd; } else { p = g_malloc (job->output_size); job->output_fd = -1; } output = (JobOutput *)g_malloc (sizeof (JobOutput)); output->job_description = (gchar *)p; output->semaphore = semaphore; output->semaphore_name = semaphore_name; g_stpcpy (output->job_description, job->description); p += (strlen (job->description) / 8 + 1) * 8; output->state = (guint64 *)p; p += sizeof (guint64); /* state */ output->source.duration = (gint64 *)p; p += sizeof (gint64); /* duration for transcode */ output->source.sync_error_times = 0; output->source.stream_count = jobdesc_streams_count (job->description, "source"); output->source.streams = (struct _SourceStreamState *)p; for (i = 0; i < output->source.stream_count; i++) { output->source.streams[i].last_heartbeat = gst_clock_get_time (job->system_clock); } p += output->source.stream_count * sizeof (struct _SourceStreamState); output->encoder_count = jobdesc_encoders_count (job->description); if (output->encoder_count == 0) { GST_ERROR ("Invalid job without encoders, initialize job failure"); sem_post (semaphore); return 1; } output->encoders = (struct _EncoderOutput *)g_malloc (output->encoder_count * sizeof (struct _EncoderOutput)); for (i = 0; i < output->encoder_count; i++) { name = g_strdup_printf ("%s.encoder.%d", job->name, i); g_strlcpy (output->encoders[i].name, name, STREAM_NAME_LEN); g_free (name); name = g_strdup_printf ("encoder.%d", i); output->encoders[i].stream_count = jobdesc_streams_count (job->description, name); g_free (name); output->encoders[i].semaphore = output->semaphore; output->encoders[i].heartbeat = (GstClockTime *)p; p += sizeof (GstClockTime); /* encoder heartbeat */ output->encoders[i].eos = (gboolean *)p; p += sizeof (gboolean); output->encoders[i].streams = (struct _EncoderStreamState *)p; p += output->encoders[i].stream_count * sizeof (struct _EncoderStreamState); /* encoder state */ output->encoders[i].total_count = (guint64 *)p; p += sizeof (guint64); /* total count size */ /* non live job has no output */ if (!job->is_live) { continue; } output->encoders[i].is_first_buffer = TRUE; output->encoders[i].cache_addr = p; p += SHM_SIZE; output->encoders[i].cache_size = SHM_SIZE; output->encoders[i].head_addr = (guint64 *)p; p += sizeof (guint64); /* cache head */ output->encoders[i].tail_addr = (guint64 *)p; p += sizeof (guint64); /* cache tail */ output->encoders[i].last_rap_addr = (guint64 *)p; p += sizeof (guint64); /* last rap addr */ } job->output = output; sem_post (semaphore); return 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; }