static void rtmp_stream_destroy(void *data) { struct rtmp_stream *stream = data; if (stopping(stream) && !connecting(stream)) { pthread_join(stream->send_thread, NULL); } else if (connecting(stream) || active(stream)) { if (stream->connecting) pthread_join(stream->connect_thread, NULL); os_event_signal(stream->stop_event); if (active(stream)) { os_sem_post(stream->send_sem); obs_output_end_data_capture(stream->output); pthread_join(stream->send_thread, NULL); } } if (stream) { free_packets(stream); dstr_free(&stream->path); dstr_free(&stream->key); dstr_free(&stream->username); dstr_free(&stream->password); dstr_free(&stream->encoder_name); os_event_destroy(stream->stop_event); os_sem_destroy(stream->send_sem); pthread_mutex_destroy(&stream->packets_mutex); circlebuf_free(&stream->packets); bfree(stream); } }
static void clear_raw_frame_data(void) { struct obs_core_video *video = &obs->video; memset(video->textures_copied, 0, sizeof(video->textures_copied)); memset(video->textures_converted, 0, sizeof(video->textures_converted)); circlebuf_free(&video->vframe_info_buffer); }
static inline void free_audio_buffers(struct obs_encoder *encoder) { for (size_t i = 0; i < MAX_AV_PLANES; i++) { circlebuf_free(&encoder->audio_input_buffer[i]); bfree(encoder->audio_output_buffer[i]); encoder->audio_output_buffer[i] = NULL; } }
static void rtmp_stream_destroy(void *data) { struct rtmp_stream *stream = data; if (stopping(stream) && !connecting(stream)) { pthread_join(stream->send_thread, NULL); } else if (connecting(stream) || active(stream)) { if (stream->connecting) pthread_join(stream->connect_thread, NULL); stream->stop_ts = 0; os_event_signal(stream->stop_event); if (active(stream)) { os_sem_post(stream->send_sem); obs_output_end_data_capture(stream->output); pthread_join(stream->send_thread, NULL); } } free_packets(stream); dstr_free(&stream->path); dstr_free(&stream->key); dstr_free(&stream->username); dstr_free(&stream->password); dstr_free(&stream->encoder_name); dstr_free(&stream->bind_ip); os_event_destroy(stream->stop_event); os_sem_destroy(stream->send_sem); pthread_mutex_destroy(&stream->packets_mutex); circlebuf_free(&stream->packets); #ifdef TEST_FRAMEDROPS circlebuf_free(&stream->droptest_info); #endif os_event_destroy(stream->buffer_space_available_event); os_event_destroy(stream->buffer_has_data_event); os_event_destroy(stream->socket_available_event); os_event_destroy(stream->send_thread_signaled_exit); pthread_mutex_destroy(&stream->write_buf_mutex); if (stream->write_buf) bfree(stream->write_buf); bfree(stream); }
static void clear_frame_data(void) { struct obs_core_video *video = &obs->video; memset(video->textures_rendered, 0, sizeof(video->textures_rendered)); memset(video->textures_output, 0, sizeof(video->textures_output)); memset(video->textures_copied, 0, sizeof(video->textures_copied)); memset(video->textures_converted, 0, sizeof(video->textures_converted)); circlebuf_free(&video->vframe_info_buffer); video->cur_texture = 0; }
static inline void audio_line_destroy_data(struct audio_line *line) { for (size_t i = 0; i < MAX_AV_PLANES; i++) { circlebuf_free(&line->buffers[i]); da_free(line->volume_buffers[i]); } pthread_mutex_destroy(&line->mutex); bfree(line->name); bfree(line); }
static void drop_frames(struct rtmp_stream *stream, const char *name, int highest_priority, int64_t *p_min_dts_usec) { struct circlebuf new_buf = {0}; uint64_t last_drop_dts_usec = 0; int num_frames_dropped = 0; #ifdef _DEBUG int start_packets = (int)num_buffered_packets(stream); #else UNUSED_PARAMETER(name); #endif circlebuf_reserve(&new_buf, sizeof(struct encoder_packet) * 8); while (stream->packets.size) { struct encoder_packet packet; circlebuf_pop_front(&stream->packets, &packet, sizeof(packet)); last_drop_dts_usec = packet.dts_usec; /* do not drop audio data or video keyframes */ if (packet.type == OBS_ENCODER_AUDIO || packet.drop_priority >= highest_priority) { circlebuf_push_back(&new_buf, &packet, sizeof(packet)); } else { num_frames_dropped++; obs_free_encoder_packet(&packet); } } circlebuf_free(&stream->packets); stream->packets = new_buf; if (stream->min_priority < highest_priority) stream->min_priority = highest_priority; *p_min_dts_usec = last_drop_dts_usec; stream->dropped_frames += num_frames_dropped; #ifdef _DEBUG debug("Dropped %s, prev packet count: %d, new packet count: %d", name, start_packets, (int)num_buffered_packets(stream)); #endif }
static inline void audio_monitor_free(struct audio_monitor *monitor) { if (monitor->source) { obs_source_remove_audio_capture_callback( monitor->source, on_audio_playback, monitor); } if (monitor->client) monitor->client->lpVtbl->Stop(monitor->client); safe_release(monitor->device); safe_release(monitor->client); safe_release(monitor->render); audio_resampler_destroy(monitor->resampler); circlebuf_free(&monitor->delay_buffer); da_free(monitor->buf); }
void mp_decode_free(struct mp_decode *d) { mp_decode_clear_packets(d); circlebuf_free(&d->packets); if (d->decoder) { avcodec_close(d->decoder); #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 40, 101) av_free(d->decoder); #endif } if (d->frame) av_free(d->frame); memset(d, 0, sizeof(*d)); }
void obs_output_destroy(obs_output_t *output) { if (output) { obs_context_data_remove(&output->context); blog(LOG_INFO, "output '%s' destroyed", output->context.name); if (output->valid && active(output)) obs_output_actual_stop(output, true, 0); os_event_wait(output->stopping_event); if (data_capture_ending(output)) pthread_join(output->end_data_capture_thread, NULL); if (output->service) output->service->output = NULL; if (output->context.data) output->info.destroy(output->context.data); free_packets(output); if (output->video_encoder) { obs_encoder_remove_output(output->video_encoder, output); } for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) { if (output->audio_encoders[i]) { obs_encoder_remove_output( output->audio_encoders[i], output); } } os_event_destroy(output->stopping_event); pthread_mutex_destroy(&output->interleaved_mutex); pthread_mutex_destroy(&output->delay_mutex); os_event_destroy(output->reconnect_stop_event); obs_context_data_free(&output->context); circlebuf_free(&output->delay_data); if (output->owns_info_id) bfree((void*)output->info.id); bfree(output); } }
static void rtmp_stream_destroy(void *data) { struct rtmp_stream *stream = data; if (stream->active) rtmp_stream_stop(data); if (stream) { free_packets(stream); dstr_free(&stream->path); dstr_free(&stream->key); dstr_free(&stream->username); dstr_free(&stream->password); os_event_destroy(stream->stop_event); os_sem_destroy(stream->send_sem); pthread_mutex_destroy(&stream->packets_mutex); circlebuf_free(&stream->packets); bfree(stream); } }
static void obs_free_video(void) { struct obs_core_video *video = &obs->video; if (video->video) { obs_display_free(&video->main_display); video_output_close(video->video); video->video = NULL; if (!video->graphics) return; gs_enter_context(video->graphics); if (video->mapped_surface) { gs_stagesurface_unmap(video->mapped_surface); video->mapped_surface = NULL; } for (size_t i = 0; i < NUM_TEXTURES; i++) { gs_stagesurface_destroy(video->copy_surfaces[i]); gs_texture_destroy(video->render_textures[i]); gs_texture_destroy(video->convert_textures[i]); gs_texture_destroy(video->output_textures[i]); obs_source_frame_free(&video->convert_frames[i]); video->copy_surfaces[i] = NULL; video->render_textures[i] = NULL; video->convert_textures[i] = NULL; video->output_textures[i] = NULL; } gs_leave_context(); circlebuf_free(&video->timestamp_buffer); video->cur_texture = 0; } }
static void drop_frames(struct rtmp_stream *stream) { struct circlebuf new_buf = {0}; int drop_priority = 0; uint64_t last_drop_dts_usec = 0; int num_frames_dropped = 0; debug("Previous packet count: %d", (int)num_buffered_packets(stream)); circlebuf_reserve(&new_buf, sizeof(struct encoder_packet) * 8); while (stream->packets.size) { struct encoder_packet packet; circlebuf_pop_front(&stream->packets, &packet, sizeof(packet)); last_drop_dts_usec = packet.dts_usec; /* do not drop audio data or video keyframes */ if (packet.type == OBS_ENCODER_AUDIO || packet.drop_priority == OBS_NAL_PRIORITY_HIGHEST) { circlebuf_push_back(&new_buf, &packet, sizeof(packet)); } else { if (drop_priority < packet.drop_priority) drop_priority = packet.drop_priority; num_frames_dropped++; obs_free_encoder_packet(&packet); } } circlebuf_free(&stream->packets); stream->packets = new_buf; stream->min_priority = drop_priority; stream->min_drop_dts_usec = last_drop_dts_usec; stream->dropped_frames += num_frames_dropped; debug("New packet count: %d", (int)num_buffered_packets(stream)); }
static void drop_frames(struct rtmp_stream *stream) { struct circlebuf new_buf = {0}; int drop_priority = 0; uint64_t last_drop_dts_usec = 0; blog(LOG_DEBUG, "Previous packet count: %d", (int)num_buffered_packets(stream)); circlebuf_reserve(&new_buf, sizeof(struct encoder_packet) * 8); while (stream->packets.size) { struct encoder_packet packet; circlebuf_pop_front(&stream->packets, &packet, sizeof(packet)); last_drop_dts_usec = packet.dts_usec; if (packet.type == OBS_ENCODER_AUDIO) { circlebuf_push_back(&new_buf, &packet, sizeof(packet)); } else { if (drop_priority < packet.drop_priority) drop_priority = packet.drop_priority; obs_free_encoder_packet(&packet); } } circlebuf_free(&stream->packets); stream->packets = new_buf; stream->min_priority = drop_priority; stream->min_drop_dts_usec = last_drop_dts_usec; blog(LOG_DEBUG, "New packet count: %d", (int)num_buffered_packets(stream)); }
static void clear_gpu_frame_data(void) { struct obs_core_video *video = &obs->video; circlebuf_free(&video->vframe_info_buffer_gpu); }
inline ~CircleBuf() {circlebuf_free(&buf);}
static inline void audio_line_destroy_data(struct audio_line *line) { circlebuf_free(&line->buffer); bfree(line); }
static bool process_audio_delay(struct audio_monitor *monitor, float **data, uint32_t *frames, uint64_t ts, uint32_t pad) { obs_source_t *s = monitor->source; uint64_t last_frame_ts = s->last_frame_ts; uint64_t cur_time = os_gettime_ns(); uint64_t front_ts; uint64_t cur_ts; int64_t diff; uint32_t blocksize = monitor->channels * sizeof(float); /* cut off audio if long-since leftover audio in delay buffer */ if (cur_time - monitor->last_recv_time > 1000000000) circlebuf_free(&monitor->delay_buffer); monitor->last_recv_time = cur_time; ts += monitor->source->sync_offset; circlebuf_push_back(&monitor->delay_buffer, &ts, sizeof(ts)); circlebuf_push_back(&monitor->delay_buffer, frames, sizeof(*frames)); circlebuf_push_back(&monitor->delay_buffer, *data, *frames * blocksize); if (!monitor->prev_video_ts) { monitor->prev_video_ts = last_frame_ts; } else if (monitor->prev_video_ts == last_frame_ts) { monitor->time_since_prev += (uint64_t)*frames * 1000000000ULL / (uint64_t)monitor->sample_rate; } else { monitor->time_since_prev = 0; } while (monitor->delay_buffer.size != 0) { size_t size; bool bad_diff; circlebuf_peek_front(&monitor->delay_buffer, &cur_ts, sizeof(ts)); front_ts = cur_ts - ((uint64_t)pad * 1000000000ULL / (uint64_t)monitor->sample_rate); diff = (int64_t)front_ts - (int64_t)last_frame_ts; bad_diff = !last_frame_ts || llabs(diff) > 5000000000 || monitor->time_since_prev > 100000000ULL; /* delay audio if rushing */ if (!bad_diff && diff > 75000000) { #ifdef DEBUG_AUDIO blog(LOG_INFO, "audio rushing, cutting audio, " "diff: %lld, delay buffer size: %lu, " "v: %llu: a: %llu", diff, (int)monitor->delay_buffer.size, last_frame_ts, front_ts); #endif return false; } circlebuf_pop_front(&monitor->delay_buffer, NULL, sizeof(ts)); circlebuf_pop_front(&monitor->delay_buffer, frames, sizeof(*frames)); size = *frames * blocksize; da_resize(monitor->buf, size); circlebuf_pop_front(&monitor->delay_buffer, monitor->buf.array, size); /* cut audio if dragging */ if (!bad_diff && diff < -75000000 && monitor->delay_buffer.size > 0) { #ifdef DEBUG_AUDIO blog(LOG_INFO, "audio dragging, cutting audio, " "diff: %lld, delay buffer size: %lu, " "v: %llu: a: %llu", diff, (int)monitor->delay_buffer.size, last_frame_ts, front_ts); #endif continue; } *data = monitor->buf.array; return true; } return false; }
static void clear_audio(struct obs_encoder *encoder) { for (size_t i = 0; i < encoder->planes; i++) circlebuf_free(&encoder->audio_input_buffer[i]); }