mptsd reads mpegts streams from udp/multicast or http and combines them into one multiple program stream that is suitable for outputting to DVB-C modulator. Tested with Dektec DTE-3114 Quad QAM Modulator and used in production in small DVB-C networks. https://georgi.unixsol.org/programs/mptsd/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mptsd.c 3.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. * MPTS Generator
  3. * Reads MPEG TS over HTTP/UDP and generate MPTS
  4. * Copyright (C) 2010 Unix Solutions Ltd.
  5. */
  6. #include <stdlib.h>
  7. #include <unistd.h>
  8. #include <signal.h>
  9. #include <errno.h>
  10. #include "libfuncs/libfuncs.h"
  11. #include "libtsfuncs/tsfuncs.h"
  12. #include "iniparser.h"
  13. #include "data.h"
  14. #include "config.h"
  15. #include "network.h"
  16. #include "input.h"
  17. #include "output.h"
  18. #include "web_server.h"
  19. #define PROGRAM_NAME "ux-mptsd"
  20. const char *program_id = PROGRAM_NAME " " GIT_VER " build " BUILD_ID;
  21. char *server_sig = PROGRAM_NAME;
  22. char *server_ver = GIT_VER;
  23. char *copyright = "Copyright (C) 2010-2011 Unix Solutions Ltd.";
  24. CONFIG *config;
  25. int keep_going = 1;
  26. int rcvsig = 0;
  27. void spawn_input_threads(CONFIG *conf) {
  28. LNODE *lc, *lctmp;
  29. LNODE *lr, *lrtmp;
  30. int spawned = 0;
  31. list_for_each(conf->channels, lc, lctmp) {
  32. CHANNEL *c = lc->data;
  33. int restreamer_active = 0;
  34. list_lock(conf->inputs);
  35. list_for_each(conf->inputs, lr, lrtmp) {
  36. INPUT *r = lr->data;
  37. if (xstrcmp(r->name, c->name)==0) {
  38. restreamer_active = 1;
  39. break;
  40. }
  41. }
  42. list_unlock(conf->inputs);
  43. if (!restreamer_active) {
  44. INPUT *nr = input_new(c->name, c);
  45. if (nr) {
  46. list_add(conf->inputs, nr);
  47. // LOGf("SPAWN : %s thread.\n", c->name);
  48. if (pthread_create(&nr->thread, NULL, &input_stream, nr) == 0) {
  49. spawned++;
  50. pthread_detach(nr->thread);
  51. } else {
  52. LOGf("ERROR: Can't create proxy for %s\n", c->name);
  53. }
  54. } else {
  55. LOGf("ERROR: Error creating proxy for %s\n", c->name);
  56. }
  57. }
  58. }
  59. LOGf("INPUT : %d thread%s spawned.\n", spawned, spawned > 1 ? "s" : "");
  60. }
  61. void spawn_output_threads(CONFIG *conf) {
  62. if (pthread_create(&conf->output->psi_thread, NULL, &output_handle_psi, conf) == 0) {
  63. pthread_detach(conf->output->psi_thread);
  64. } else {
  65. LOGf("ERROR: Can't spawn PSI output thread: %s\n", strerror(errno));
  66. exit(1);
  67. }
  68. if (pthread_create(&conf->output->mix_thread, NULL, &output_handle_mix, conf) == 0) {
  69. pthread_detach(conf->output->mix_thread);
  70. } else {
  71. LOGf("ERROR: Can't spawn MIX output thread: %s\n", strerror(errno));
  72. exit(1);
  73. }
  74. if (pthread_create(&conf->output->write_thread, NULL, &output_handle_write, conf) == 0) {
  75. pthread_detach(conf->output->write_thread);
  76. } else {
  77. LOGf("ERROR: Can't spawn WRITE output thread: %s\n", strerror(errno));
  78. exit(1);
  79. }
  80. }
  81. void kill_threads(CONFIG *conf) {
  82. int loops = 0;
  83. conf->output->dienow = 1;
  84. while (conf->inputs->items || conf->output->dienow < 4) {
  85. usleep(50000);
  86. if (loops++ > 60) // 3 seconds
  87. exit(0);
  88. }
  89. }
  90. /*
  91. void do_reconnect(CONFIG *conf) {
  92. LNODE *l, *tmp;
  93. list_lock(conf->inputs);
  94. list_for_each(conf->inputs, l, tmp) {
  95. INPUT *r = l->data;
  96. r->reconnect = 1;
  97. }
  98. list_unlock(conf->inputs);
  99. }
  100. void do_reconf(CONFIG *conf) {
  101. // load_channels_config();
  102. spawn_input_threads(conf);
  103. }
  104. */
  105. void signal_quit(int sig) {
  106. rcvsig = sig;
  107. keep_going = 0;
  108. }
  109. void init_signals() {
  110. signal(SIGCHLD, SIG_IGN);
  111. signal(SIGPIPE, SIG_IGN);
  112. // signal(SIGHUP , do_reconf);
  113. // signal(SIGUSR1, do_reconnect);
  114. signal(SIGINT , signal_quit);
  115. signal(SIGTERM, signal_quit);
  116. }
  117. int main(int argc, char **argv) {
  118. set_http_response_server_ident(server_sig, server_ver);
  119. ts_set_log_func(LOG);
  120. config = config_alloc();
  121. config_load(config, argc, argv);
  122. output_psi_init(config, config->output);
  123. daemonize(config->pidfile);
  124. web_server_start(config);
  125. log_init(config->logident, config->syslog_active, config->pidfile == NULL, config->loghost, config->logport);
  126. init_signals(config);
  127. LOGf("INIT : %s %s (%s)\n" , server_sig, server_ver, config->ident);
  128. connect_output(config->output);
  129. spawn_input_threads(config);
  130. spawn_output_threads(config);
  131. do { usleep(50000); } while(keep_going);
  132. kill_threads(config);
  133. web_server_stop(config);
  134. LOGf("SHUTDOWN: Signal %d | %s %s (%s)\n", rcvsig, server_sig, server_ver, config->ident);
  135. config_free(&config);
  136. log_close();
  137. exit(0);
  138. }