static guint64 create_job_process (Job *job) { GError *error = NULL; gchar *argv[16], *p; GPid pid; gint i, j; i = 0; argv[i++] = g_strdup (job->exe_path); argv[i++] = g_strdup ("-l"); argv[i++] = g_strdup (job->log_dir); argv[i++] = g_strdup ("-n"); argv[i++] = unicode_file_name_2_shm_name (job->name); argv[i++] = g_strdup ("-q"); argv[i++] = g_strdup_printf ("%ld", strlen (job->description)); p = jobdesc_get_debug (job->description); if (p != NULL) { argv[i++] = g_strdup_printf ("--gst-debug=%s", p); g_free (p); } argv[i++] = NULL; if (!g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error)) { GST_ERROR ("Start job %s error, reason: %s.", job->name, error->message); for (j = 0; j < i; j++) { if (argv[j] != NULL) { g_free (argv[j]); } } g_error_free (error); return JOB_STATE_START_FAILURE; } for (j = 0; j < i; j++) { if (argv[j] != NULL) { g_free (argv[j]); } } job->worker_pid = pid; g_child_watch_add (pid, (GChildWatchFunc)child_watch_cb, job); while ((*(job->output->state) == JOB_STATE_READY) || (*(job->output->state) == JOB_STATE_VOID_PENDING)) { GST_WARNING ("waiting job process creating ... state: %s", job_state_get_name (*(job->output->state))); g_usleep (50000); } return *(job->output->state); }
static void job_dispose (GObject *obj) { Job *job = JOB (obj); GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); JobOutput *output; gint i; gchar *name_hexstr; if (job->output == NULL) { return; } output = job->output; /* free semaphore */ if (output->semaphore != NULL) { if (sem_close (output->semaphore) == -1) { GST_ERROR ("sem_close failure: %s", g_strerror (errno)); } if (sem_unlink (output->semaphore_name) == -1) { GST_ERROR ("sem_unlink %s error: %s", job->name, g_strerror (errno)); } g_free (output->semaphore_name); } /* free encoders output */ if (job->is_live) { if (output->master_m3u8_playlist != NULL) { g_free (output->master_m3u8_playlist); for (i = 0; i < output->encoder_count; i++) { if (output->encoders[i].record_path != NULL) { g_free (output->encoders[i].record_path); } m3u8playlist_free (output->encoders[i].m3u8_playlist); } } } g_free (output->encoders); /* free share memory */ if (job->output_fd != -1) { g_close (job->output_fd, NULL); if (munmap (output->job_description, job->output_size) == -1) { GST_ERROR ("munmap %s error: %s", job->name, g_strerror (errno)); } name_hexstr = unicode_file_name_2_shm_name (job->name); if (shm_unlink (name_hexstr) == -1) { GST_ERROR ("shm_unlink %s error: %s", job->name, g_strerror (errno)); } g_free (name_hexstr); } g_free (output); if (job->description != NULL) { g_free (job->description); job->description = NULL; } if (job->exe_path != NULL) { g_free (job->exe_path); job->exe_path = NULL; } if (job->name != NULL) { g_free (job->name); job->name = NULL; } G_OBJECT_CLASS (parent_class)->dispose (obj); }
/** * 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; }
static void job_dispose (GObject *obj) { Job *job = JOB (obj); GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); JobOutput *output; gint i; gchar *name, *name_hexstr; if (job->output == NULL) { return; } output = job->output; if (output->semaphore != NULL) { if (sem_close (output->semaphore) == -1) { GST_ERROR ("sem_close failure: %s", g_strerror (errno)); } if (sem_unlink (output->semaphore_name) == -1) { GST_ERROR ("sem_unlink %s error: %s", job->name, g_strerror (errno)); } g_free (output->semaphore_name); } for (i = 0; i < output->encoder_count; i++) { /* message queue release */ name = g_strdup_printf ("/%s.%d", job->name, i); if ((output->encoders[i].mqdes != -1) && (mq_close (output->encoders[i].mqdes) == -1)) { GST_ERROR ("mq_close %s error: %s", name, g_strerror (errno)); } if ((output->encoders[i].mqdes != -1) && (mq_unlink (name) == -1)) { GST_ERROR ("mq_unlink %s error: %s", name, g_strerror (errno)); } if (job->is_live && (output->encoders[i].record_path != NULL)) { g_free (output->encoders[i].record_path); } g_free (name); } /* share memory release */ if (job->output_fd != -1) { g_close (job->output_fd, NULL); if (munmap (output->job_description, job->output_size) == -1) { GST_ERROR ("munmap %s error: %s", job->name, g_strerror (errno)); } name_hexstr = unicode_file_name_2_shm_name (job->name); if (shm_unlink (name_hexstr) == -1) { GST_ERROR ("shm_unlink %s error: %s", job->name, g_strerror (errno)); } g_free (name_hexstr); } g_free (output); if (job->name != NULL) { g_free (job->name); job->name = NULL; } if (job->description != NULL) { g_free (job->description); job->description = NULL; } if (job->exe_path != NULL) { g_free (job->exe_path); job->exe_path = NULL; } G_OBJECT_CLASS (parent_class)->dispose (obj); }