123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- /******************************************************************************
- Copyright (C) 2023 by Lain Bailey <[email protected]>
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- ******************************************************************************/
- #include <inttypes.h>
- #include "obs-internal.h"
- static inline bool delay_active(const struct obs_output *output)
- {
- return os_atomic_load_bool(&output->delay_active);
- }
- static inline bool delay_capturing(const struct obs_output *output)
- {
- return os_atomic_load_bool(&output->delay_capturing);
- }
- static inline bool flag_encoded(const struct obs_output *output)
- {
- return (output->info.flags & OBS_OUTPUT_ENCODED) != 0;
- }
- static inline bool log_flag_encoded(const struct obs_output *output,
- const char *func_name, bool inverse_log)
- {
- const char *prefix = inverse_log ? "n encoded" : " raw";
- bool ret = flag_encoded(output);
- if ((!inverse_log && !ret) || (inverse_log && ret))
- blog(LOG_WARNING, "Output '%s': Tried to use %s on a%s output",
- output->context.name, func_name, prefix);
- return ret;
- }
- static inline void push_packet(struct obs_output *output,
- struct encoder_packet *packet, uint64_t t)
- {
- struct delay_data dd;
- dd.msg = DELAY_MSG_PACKET;
- dd.ts = t;
- obs_encoder_packet_create_instance(&dd.packet, packet);
- pthread_mutex_lock(&output->delay_mutex);
- circlebuf_push_back(&output->delay_data, &dd, sizeof(dd));
- pthread_mutex_unlock(&output->delay_mutex);
- }
- static inline void process_delay_data(struct obs_output *output,
- struct delay_data *dd)
- {
- switch (dd->msg) {
- case DELAY_MSG_PACKET:
- if (!delay_active(output) || !delay_capturing(output))
- obs_encoder_packet_release(&dd->packet);
- else
- output->delay_callback(output, &dd->packet);
- break;
- case DELAY_MSG_START:
- obs_output_actual_start(output);
- break;
- case DELAY_MSG_STOP:
- obs_output_actual_stop(output, false, dd->ts);
- break;
- }
- }
- void obs_output_cleanup_delay(obs_output_t *output)
- {
- struct delay_data dd;
- while (output->delay_data.size) {
- circlebuf_pop_front(&output->delay_data, &dd, sizeof(dd));
- if (dd.msg == DELAY_MSG_PACKET) {
- obs_encoder_packet_release(&dd.packet);
- }
- }
- output->active_delay_ns = 0;
- os_atomic_set_long(&output->delay_restart_refs, 0);
- }
- static inline bool pop_packet(struct obs_output *output, uint64_t t)
- {
- uint64_t elapsed_time;
- struct delay_data dd;
- bool popped = false;
- bool preserve;
- /* ------------------------------------------------ */
- preserve = (output->delay_cur_flags & OBS_OUTPUT_DELAY_PRESERVE) != 0;
- pthread_mutex_lock(&output->delay_mutex);
- if (output->delay_data.size) {
- circlebuf_peek_front(&output->delay_data, &dd, sizeof(dd));
- elapsed_time = (t - dd.ts);
- if (preserve && output->reconnecting) {
- output->active_delay_ns = elapsed_time;
- } else if (elapsed_time > output->active_delay_ns) {
- circlebuf_pop_front(&output->delay_data, NULL,
- sizeof(dd));
- popped = true;
- }
- }
- pthread_mutex_unlock(&output->delay_mutex);
- /* ------------------------------------------------ */
- if (popped)
- process_delay_data(output, &dd);
- return popped;
- }
- void process_delay(void *data, struct encoder_packet *packet)
- {
- struct obs_output *output = data;
- uint64_t t = os_gettime_ns();
- push_packet(output, packet, t);
- while (pop_packet(output, t))
- ;
- }
- void obs_output_signal_delay(obs_output_t *output, const char *signal)
- {
- struct calldata params;
- uint8_t stack[128];
- calldata_init_fixed(¶ms, stack, sizeof(stack));
- calldata_set_ptr(¶ms, "output", output);
- calldata_set_int(¶ms, "sec", output->active_delay_ns / 1000000000);
- signal_handler_signal(output->context.signals, signal, ¶ms);
- }
- bool obs_output_delay_start(obs_output_t *output)
- {
- struct delay_data dd = {
- .msg = DELAY_MSG_START,
- .ts = os_gettime_ns(),
- };
- if (!delay_active(output)) {
- bool can_begin = obs_output_can_begin_data_capture2(output);
- if (!can_begin)
- return false;
- if (!obs_output_initialize_encoders2(output))
- return false;
- }
- pthread_mutex_lock(&output->delay_mutex);
- circlebuf_push_back(&output->delay_data, &dd, sizeof(dd));
- pthread_mutex_unlock(&output->delay_mutex);
- os_atomic_inc_long(&output->delay_restart_refs);
- if (delay_active(output)) {
- do_output_signal(output, "starting");
- return true;
- }
- if (!obs_output_begin_data_capture2(output)) {
- obs_output_cleanup_delay(output);
- return false;
- }
- return true;
- }
- void obs_output_delay_stop(obs_output_t *output)
- {
- struct delay_data dd = {
- .msg = DELAY_MSG_STOP,
- .ts = os_gettime_ns(),
- };
- pthread_mutex_lock(&output->delay_mutex);
- circlebuf_push_back(&output->delay_data, &dd, sizeof(dd));
- pthread_mutex_unlock(&output->delay_mutex);
- do_output_signal(output, "stopping");
- }
- void obs_output_set_delay(obs_output_t *output, uint32_t delay_sec,
- uint32_t flags)
- {
- if (!obs_output_valid(output, "obs_output_set_delay"))
- return;
- if (!log_flag_encoded(output, __FUNCTION__, false))
- return;
- output->delay_sec = delay_sec;
- output->delay_flags = flags;
- }
- uint32_t obs_output_get_delay(const obs_output_t *output)
- {
- return obs_output_valid(output, "obs_output_set_delay")
- ? output->delay_sec
- : 0;
- }
- uint32_t obs_output_get_active_delay(const obs_output_t *output)
- {
- return obs_output_valid(output, "obs_output_set_delay")
- ? (uint32_t)(output->active_delay_ns / 1000000000ULL)
- : 0;
- }
|