obs-output-delay.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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 bool delay_active(const struct obs_output *output)
  17. {
  18. return os_atomic_load_bool(&output->delay_active);
  19. }
  20. static inline bool delay_capturing(const struct obs_output *output)
  21. {
  22. return os_atomic_load_bool(&output->delay_capturing);
  23. }
  24. static inline void push_packet(struct obs_output *output,
  25. struct encoder_packet *packet, uint64_t t)
  26. {
  27. struct delay_data dd;
  28. dd.msg = DELAY_MSG_PACKET;
  29. dd.ts = t;
  30. obs_encoder_packet_create_instance(&dd.packet, packet);
  31. pthread_mutex_lock(&output->delay_mutex);
  32. circlebuf_push_back(&output->delay_data, &dd, sizeof(dd));
  33. pthread_mutex_unlock(&output->delay_mutex);
  34. }
  35. static inline void process_delay_data(struct obs_output *output,
  36. struct delay_data *dd)
  37. {
  38. switch (dd->msg) {
  39. case DELAY_MSG_PACKET:
  40. if (!delay_active(output) || !delay_capturing(output))
  41. obs_encoder_packet_release(&dd->packet);
  42. else
  43. output->delay_callback(output, &dd->packet);
  44. break;
  45. case DELAY_MSG_START:
  46. obs_output_actual_start(output);
  47. break;
  48. case DELAY_MSG_STOP:
  49. obs_output_actual_stop(output, false, dd->ts);
  50. break;
  51. }
  52. }
  53. void obs_output_cleanup_delay(obs_output_t *output)
  54. {
  55. struct delay_data dd;
  56. while (output->delay_data.size) {
  57. circlebuf_pop_front(&output->delay_data, &dd, sizeof(dd));
  58. if (dd.msg == DELAY_MSG_PACKET) {
  59. obs_encoder_packet_release(&dd.packet);
  60. }
  61. }
  62. output->active_delay_ns = 0;
  63. os_atomic_set_long(&output->delay_restart_refs, 0);
  64. }
  65. static inline bool pop_packet(struct obs_output *output, uint64_t t)
  66. {
  67. uint64_t elapsed_time;
  68. struct delay_data dd;
  69. bool popped = false;
  70. bool preserve;
  71. /* ------------------------------------------------ */
  72. preserve = (output->delay_cur_flags & OBS_OUTPUT_DELAY_PRESERVE) != 0;
  73. pthread_mutex_lock(&output->delay_mutex);
  74. if (output->delay_data.size) {
  75. circlebuf_peek_front(&output->delay_data, &dd, sizeof(dd));
  76. elapsed_time = (t - dd.ts);
  77. if (preserve && output->reconnecting) {
  78. output->active_delay_ns = elapsed_time;
  79. } else if (elapsed_time > output->active_delay_ns) {
  80. circlebuf_pop_front(&output->delay_data, NULL,
  81. sizeof(dd));
  82. popped = true;
  83. }
  84. }
  85. pthread_mutex_unlock(&output->delay_mutex);
  86. /* ------------------------------------------------ */
  87. if (popped)
  88. process_delay_data(output, &dd);
  89. return popped;
  90. }
  91. void process_delay(void *data, struct encoder_packet *packet)
  92. {
  93. struct obs_output *output = data;
  94. uint64_t t = os_gettime_ns();
  95. push_packet(output, packet, t);
  96. while (pop_packet(output, t))
  97. ;
  98. }
  99. void obs_output_signal_delay(obs_output_t *output, const char *signal)
  100. {
  101. struct calldata params;
  102. uint8_t stack[128];
  103. calldata_init_fixed(&params, stack, sizeof(stack));
  104. calldata_set_ptr(&params, "output", output);
  105. calldata_set_int(&params, "sec", output->active_delay_ns / 1000000000);
  106. signal_handler_signal(output->context.signals, signal, &params);
  107. }
  108. bool obs_output_delay_start(obs_output_t *output)
  109. {
  110. struct delay_data dd = {
  111. .msg = DELAY_MSG_START,
  112. .ts = os_gettime_ns(),
  113. };
  114. if (!delay_active(output)) {
  115. bool can_begin = obs_output_can_begin_data_capture(output, 0);
  116. if (!can_begin)
  117. return false;
  118. if (!obs_output_initialize_encoders(output, 0))
  119. return false;
  120. }
  121. pthread_mutex_lock(&output->delay_mutex);
  122. circlebuf_push_back(&output->delay_data, &dd, sizeof(dd));
  123. pthread_mutex_unlock(&output->delay_mutex);
  124. os_atomic_inc_long(&output->delay_restart_refs);
  125. if (delay_active(output)) {
  126. do_output_signal(output, "starting");
  127. return true;
  128. }
  129. if (!obs_output_begin_data_capture(output, 0)) {
  130. obs_output_cleanup_delay(output);
  131. return false;
  132. }
  133. return true;
  134. }
  135. void obs_output_delay_stop(obs_output_t *output)
  136. {
  137. struct delay_data dd = {
  138. .msg = DELAY_MSG_STOP,
  139. .ts = os_gettime_ns(),
  140. };
  141. pthread_mutex_lock(&output->delay_mutex);
  142. circlebuf_push_back(&output->delay_data, &dd, sizeof(dd));
  143. pthread_mutex_unlock(&output->delay_mutex);
  144. do_output_signal(output, "stopping");
  145. }
  146. void obs_output_set_delay(obs_output_t *output, uint32_t delay_sec,
  147. uint32_t flags)
  148. {
  149. if (!obs_output_valid(output, "obs_output_set_delay"))
  150. return;
  151. if ((output->info.flags & OBS_OUTPUT_ENCODED) == 0) {
  152. blog(LOG_WARNING,
  153. "Output '%s': Tried to set a delay "
  154. "value on a non-encoded output",
  155. output->context.name);
  156. return;
  157. }
  158. output->delay_sec = delay_sec;
  159. output->delay_flags = flags;
  160. }
  161. uint32_t obs_output_get_delay(const obs_output_t *output)
  162. {
  163. return obs_output_valid(output, "obs_output_set_delay")
  164. ? output->delay_sec
  165. : 0;
  166. }
  167. uint32_t obs_output_get_active_delay(const obs_output_t *output)
  168. {
  169. return obs_output_valid(output, "obs_output_set_delay")
  170. ? (uint32_t)(output->active_delay_ns / 1000000000ULL)
  171. : 0;
  172. }