diff --git a/facefusion/apis/stream_audio.py b/facefusion/apis/stream_audio.py index 17d78235..71c29d07 100644 --- a/facefusion/apis/stream_audio.py +++ b/facefusion/apis/stream_audio.py @@ -5,7 +5,7 @@ from typing import Optional, Tuple import numpy from facefusion import rtc -from facefusion.apis.stream_event import create_receive_event +from facefusion.apis.stream_event import create_receive_event, destroy_receive_event from facefusion.codecs import opus_decoder, opus_encoder from facefusion.types import AudioCodec, AudioFrame, Buffer, OpusDecoder, RtcPeer, RtcPeerAudio, Time @@ -35,6 +35,7 @@ def receive_audio_frames(rtc_peer_audio : RtcPeerAudio, audio_queue : Queue[Tupl audio_frame_handler = partial(handle_audio_frame, audio_codec, audio_decoder, audio_queue) receive_event = create_receive_event(audio_track, audio_frame_handler) receive_event.wait() + destroy_receive_event(audio_track) empty_audio_frame = numpy.empty(0) audio_queue.put((0.0, empty_audio_frame)) diff --git a/facefusion/apis/stream_event.py b/facefusion/apis/stream_event.py index 64655b2e..9a5a75c6 100644 --- a/facefusion/apis/stream_event.py +++ b/facefusion/apis/stream_event.py @@ -10,8 +10,8 @@ def create_receive_event(track : int, frame_handler : FrameHandler) -> threading datachannel_library = datachannel_module.create_static_library() receive_event = threading.Event() - frame_callback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p)(partial(dispatch_frame, frame_handler)) - close_callback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_void_p)(partial(dispatch_event, receive_event)) + frame_callback = datachannel_module.define_frame_callback()(partial(dispatch_frame, frame_handler)) + close_callback = datachannel_module.define_closed_callback()(partial(dispatch_event, receive_event)) datachannel_library.rtcSetFrameCallback(track, frame_callback) datachannel_library.rtcSetClosedCallback(track, close_callback) receive_event.frame_callback = frame_callback # type: ignore[attr-defined] @@ -20,6 +20,12 @@ def create_receive_event(track : int, frame_handler : FrameHandler) -> threading return receive_event +def destroy_receive_event(track : int) -> None: + datachannel_library = datachannel_module.create_static_library() + datachannel_library.rtcSetFrameCallback(track, datachannel_module.define_frame_callback()(0)) + datachannel_library.rtcSetClosedCallback(track, datachannel_module.define_closed_callback()(0)) + + def dispatch_frame(frame_handler : FrameHandler, track : int, data : ctypes.c_void_p, size : int, info : ctypes.c_void_p, pointer : ctypes.c_void_p) -> None: frame_handler(ctypes.string_at(data, size), ctypes.cast(info, ctypes.POINTER(ctypes.c_uint32)).contents.value) diff --git a/facefusion/apis/stream_video.py b/facefusion/apis/stream_video.py index 69e16657..b979380d 100644 --- a/facefusion/apis/stream_video.py +++ b/facefusion/apis/stream_video.py @@ -7,7 +7,7 @@ import cv2 import numpy from facefusion import rtc, state_manager, streamer -from facefusion.apis.stream_event import create_receive_event +from facefusion.apis.stream_event import create_receive_event, destroy_receive_event from facefusion.codecs import aom_decoder, aom_encoder, vpx_decoder, vpx_encoder from facefusion.content_analyser import analyse_stream from facefusion.types import AomDecoder, AomEncoder, BitRate, Buffer, BufferPack, Resolution, RtcPeer, RtcPeerVideo, Time, VideoCodec, VisionFrame, VpxDecoder, VpxEncoder @@ -66,6 +66,7 @@ def receive_video_frames(rtc_peer_video : RtcPeerVideo, video_queue : Queue[Tupl video_frame_handler = partial(handle_video_frame, source_vision_frames, video_codec, video_decoder, video_queue, video_executor) receive_event = create_receive_event(video_track, video_frame_handler) receive_event.wait() + destroy_receive_event(video_track) empty_future : Future[BufferPack] = Future() empty_future.set_result(BufferPack(buffer = bytes(), resolution = (0, 0))) diff --git a/facefusion/libraries/datachannel.py b/facefusion/libraries/datachannel.py index 15b6dc39..f8c3ecac 100644 --- a/facefusion/libraries/datachannel.py +++ b/facefusion/libraries/datachannel.py @@ -1,6 +1,7 @@ import ctypes +from _ctypes import CFuncPtr from functools import lru_cache -from typing import Optional +from typing import Optional, Type from facefusion.common_helper import is_linux, is_macos, is_windows from facefusion.download import conditional_download_hashes, conditional_download_sources, resolve_download_url_by_provider @@ -217,7 +218,7 @@ def init_ctypes(library : ctypes.CDLL) -> ctypes.CDLL: library.rtcChainRtcpReceivingSession.argtypes = [ ctypes.c_int ] library.rtcChainRtcpReceivingSession.restype = ctypes.c_int - library.rtcSetFrameCallback.argtypes = [ ctypes.c_int, ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p) ] + library.rtcSetFrameCallback.argtypes = [ ctypes.c_int, define_frame_callback() ] library.rtcSetFrameCallback.restype = ctypes.c_int library.rtcSetUserPointer.argtypes = [ ctypes.c_int, ctypes.c_void_p ] @@ -229,7 +230,7 @@ def init_ctypes(library : ctypes.CDLL) -> ctypes.CDLL: library.rtcRequestBitrate.argtypes = [ ctypes.c_int, ctypes.c_uint ] library.rtcRequestBitrate.restype = ctypes.c_int - library.rtcSetClosedCallback.argtypes = [ ctypes.c_int, ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_void_p) ] + library.rtcSetClosedCallback.argtypes = [ ctypes.c_int, define_closed_callback() ] library.rtcSetClosedCallback.restype = ctypes.c_int return library @@ -292,3 +293,11 @@ def define_rtc_packetizer_init() -> ctypes.Structure: ('obuPacketization', ctypes.c_int) ] })() + + +def define_frame_callback() -> Type[CFuncPtr]: + return ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p) + + +def define_closed_callback() -> Type[CFuncPtr]: + return ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_void_p)