obs-output-delay.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /******************************************************************************
  2. Copyright (C) 2015 by Hugh Bailey <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ******************************************************************************/
  14. #include <inttypes.h>
  15. #include "obs-internal.h"
  16. static inline void push_packet(struct obs_output *output,
  17. struct encoder_packet *packet, uint64_t t)
  18. {
  19. struct delay_data dd = {0};
  20. dd.msg = DELAY_MSG_PACKET;
  21. dd.ts = t;
  22. obs_duplicate_encoder_packet(&dd.packet, packet);
  23. pthread_mutex_lock(&output->delay_mutex);
  24. circlebuf_push_back(&output->delay_data, &dd, sizeof(dd));
  25. pthread_mutex_unlock(&output->delay_mutex);
  26. }
  27. static inline void process_delay_data(struct obs_output *output,
  28. struct delay_data *dd)
  29. {
  30. switch (dd->msg) {
  31. case DELAY_MSG_PACKET:
  32. if (!output->delay_active || !output->delay_capturing)
  33. obs_free_encoder_packet(&dd->packet);
  34. else
  35. output->delay_callback(output, &dd->packet);
  36. break;
  37. case DELAY_MSG_START:
  38. obs_output_actual_start(output);
  39. break;
  40. case DELAY_MSG_STOP:
  41. obs_output_actual_stop(output, false);
  42. break;
  43. }
  44. }
  45. void obs_output_cleanup_delay(obs_output_t *output)
  46. {
  47. struct delay_data dd;
  48. while (output->delay_data.size) {
  49. circlebuf_pop_front(&output->delay_data, &dd, sizeof(dd));
  50. if (dd.msg == DELAY_MSG_PACKET) {
  51. obs_free_encoder_packet(&dd.packet);
  52. }
  53. }
  54. output->active_delay_ns = 0;
  55. output->delay_restart_refs = 0;
  56. }
  57. static inline bool pop_packet(struct obs_output *output, uint64_t t)
  58. {
  59. uint64_t elapsed_time;
  60. struct delay_data dd;
  61. bool popped = false;
  62. bool preserve;
  63. /* ------------------------------------------------ */
  64. preserve = (output->delay_cur_flags & OBS_OUTPUT_DELAY_PRESERVE) != 0;
  65. pthread_mutex_lock(&output->delay_mutex);
  66. if (output->delay_data.size) {
  67. circlebuf_peek_front(&output->delay_data, &dd, sizeof(dd));
  68. elapsed_time = (t - dd.ts);
  69. if (preserve && output->reconnecting) {
  70. output->active_delay_ns = elapsed_time;
  71. } else if (elapsed_time > output->active_delay_ns) {
  72. circlebuf_pop_front(&output->delay_data, NULL,
  73. sizeof(dd));
  74. popped = true;
  75. }
  76. }
  77. pthread_mutex_unlock(&output->delay_mutex);
  78. /* ------------------------------------------------ */
  79. if (popped)
  80. process_delay_data(output, &dd);
  81. return popped;
  82. }
  83. void process_delay(void *data, struct encoder_packet *packet)
  84. {
  85. struct obs_output *output = data;
  86. uint64_t t = os_gettime_ns();
  87. push_packet(output, packet, t);
  88. while (pop_packet(output, t));
  89. }
  90. void obs_output_signal_delay(obs_output_t *output, const char *signal)
  91. {
  92. struct calldata params;
  93. uint8_t stack[128];
  94. calldata_init_fixed(&params, stack, sizeof(stack));
  95. calldata_set_ptr(&params, "output", output);
  96. calldata_set_int(&params, "sec", output->active_delay_ns / 1000000000);
  97. signal_handler_signal(output->context.signals, signal, &params);
  98. }
  99. bool obs_output_delay_start(obs_output_t *output)
  100. {
  101. struct delay_data dd = {
  102. .msg = DELAY_MSG_START,
  103. .ts = os_gettime_ns(),
  104. };
  105. if (!output->delay_active) {
  106. bool can_begin = obs_output_can_begin_data_capture(output, 0);
  107. if (!can_begin)
  108. return false;
  109. if (!obs_output_initialize_encoders(output, 0))
  110. return false;
  111. }
  112. pthread_mutex_lock(&output->delay_mutex);
  113. circlebuf_push_back(&output->delay_data, &dd, sizeof(dd));
  114. pthread_mutex_unlock(&output->delay_mutex);
  115. if (output->delay_active) {
  116. os_atomic_inc_long(&output->delay_restart_refs);
  117. do_output_signal(output, "starting");
  118. return true;
  119. }
  120. if (!obs_output_begin_data_capture(output, 0)) {
  121. obs_output_cleanup_delay(output);
  122. return false;
  123. }
  124. return true;
  125. }
  126. void obs_output_delay_stop(obs_output_t *output)
  127. {
  128. struct delay_data dd = {
  129. .msg = DELAY_MSG_STOP,
  130. .ts = os_gettime_ns(),
  131. };
  132. pthread_mutex_lock(&output->delay_mutex);
  133. circlebuf_push_back(&output->delay_data, &dd, sizeof(dd));
  134. pthread_mutex_unlock(&output->delay_mutex);
  135. do_output_signal(output, "stopping");
  136. }
  137. void obs_output_set_delay(obs_output_t *output, uint32_t delay_sec,
  138. uint32_t flags)
  139. {
  140. if (!obs_output_valid(output, "obs_output_set_delay"))
  141. return;
  142. if ((output->info.flags & OBS_OUTPUT_ENCODED) == 0) {
  143. blog(LOG_WARNING, "Output '%s': Tried to set a delay "
  144. "value on a non-encoded output",
  145. output->context.name);
  146. return;
  147. }
  148. output->delay_sec = delay_sec;
  149. output->delay_flags = flags;
  150. }
  151. uint32_t obs_output_get_delay(const obs_output_t *output)
  152. {
  153. return obs_output_valid(output, "obs_output_set_delay") ?
  154. output->delay_sec : 0;
  155. }
  156. uint32_t obs_output_get_active_delay(const obs_output_t *output)
  157. {
  158. return obs_output_valid(output, "obs_output_set_delay") ?
  159. (uint32_t)(output->active_delay_ns / 1000000000ULL) : 0;
  160. }