Examples ======== .. note:: The :ref:`ffmpeg-sender` and :ref:`ffplay-receiver` examples both make use of UNIX pipes and will only work on supported operating systems. .. _ffmpeg-sender: Sender ------ Video frames are generated by `ffmpeg`_ running in a subprocess which outputs the raw data to its :attr:`~subprocess.Popen.stdout`. Audio samples of a continuous sine wave are generated as numpy arrays. A :class:`~cyndilib.sender.Sender` is created and instances of :class:`~cyndilib.video_frame.VideoSendFrame` and :class:`~cyndilib.audio_frame.AudioSendFrame` are added to it. The raw data from ffmpeg is then fed using the Sender's :meth:`~cyndilib.sender.Sender.write_video_async` method. The audio data is then fed to the sender using the :meth:`~cyndilib.sender.Sender.write_audio` method. Since the video frames are sent using the `asynchronous sending`_ method built into |NDI|, the sender will handle syncing the audio and video frames. .. literalinclude:: ../../examples/ffmpeg_sender.py :language: python :linenos: :name: ffmpeg_sender :caption: :github_permalink:`examples/ffmpeg_sender.py` .. _asynchronous sending: https://docs.ndi.video/all/developing-with-ndi/sdk/ndi-send#asynchronous-sending .. _audio-sender: Audio Sender ------------- This example sends audio frames using a sine wave generated by numpy. The video frames are blank frames generated manually. A :class:`~cyndilib.sender.Sender` is created and :class:`~cyndilib.audio_frame.AudioSendFrame` and :class:`~cyndilib.video_frame.VideoSendFrame` instances are added to it. The audio and video data are then written using the Sender's :meth:`~cyndilib.sender.Sender.write_video_and_audio` method. .. literalinclude:: ../../examples/audio_sender.py :language: python :linenos: :name: audio_sender :caption: :github_permalink:`examples/audio_sender.py` .. _ffplay-receiver: Receiver -------- This example receives video frames from an |NDI| :class:`~cyndilib.finder.Source` and shows them using `ffplay`_. :class:`~cyndilib.finder.Finder` is used to locate the :class:`~cyndilib.finder.Source` with the given name. A :class:`~cyndilib.receiver.Receiver` is then created and an instance of :class:`~cyndilib.video_frame.VideoFrameSync` is added to it. Video frames are then read using the :meth:`FrameSync.capture_video ` method which is available from the :attr:`~cyndilib.receiver.Receiver.frame_sync` attribute on the receiver. The data is then fed to the :attr:`~subprocess.Popen.stdin` of the `ffplay`_ subprocess directly from the video frame using the :ref:`buffer protocol `. .. literalinclude:: ../../examples/ffplay_receiver.py :language: python :linenos: :name: ffplay_receiver :caption: :github_permalink:`examples/ffplay_receiver.py` .. _audio-player: Audio Player ------------ This example receives audio frames from an |NDI| :class:`~cyndilib.finder.Source` and plays them using the `sounddevice`_ library. :class:`~cyndilib.finder.Finder` is used to locate the :class:`~cyndilib.finder.Source` with the given name. A :class:`~cyndilib.receiver.Receiver` is then created and an instance of :class:`~cyndilib.audio_frame.AudioFrameSync` is added to it. Audio frames are then read using the :meth:`FrameSync.capture_audio ` method which is available from the :attr:`~cyndilib.receiver.Receiver.frame_sync` attribute on the receiver. The audio data is then played using the `sounddevice`_ library. .. literalinclude:: ../../examples/audio_player.py :language: python :linenos: :name: audio_player :caption: :github_permalink:`examples/audio_player.py` .. _router: Router ------ This example demonstrates the use of the :mod:`~cyndilib.router` module to create virtual |NDI| sources on the network. A :class:`~cyndilib.router.RoutingMatrix` is created which manages multiple :class:`~cyndilib.router.Router` instances (specified by the command line arguments). .. literalinclude:: ../../examples/router.py :language: python :linenos: :name: router :caption: :github_permalink:`examples/router.py` .. _ffmpeg: https://ffmpeg.org .. _ffplay: https://ffmpeg.org/ffplay.html .. _sounddevice: https://python-sounddevice.readthedocs.io PTZ --- This example showcases the PTZ functions on an |NDI| :class:`~cyndilib.receiver.Receiver`. :class:`~cyndilib.finder.Finder` is used to locate a :class:`~cyndilib.finder.Source`. A :class:`~cyndilib.receiver.Receiver` is then created. Various PTZ methods are then invoked. .. literalinclude:: ../../examples/ptz.py :language: python :linenos: :name: ptz :caption: :github_permalink:`examples/ptz.py`