obs-output-delay.c 6.2 KB

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