Python send and receive RTP packets
I want to send multimedia data over RTP. What I wnat to know is how to send and receive RTP packets with Python. I found the python class DPKT. But couldn’t able to find a good reference to visualize how to generate each filed in RTP. I would appreciate if someone could help me generate and receive rtp packets at the server.
42.6k 19 19 gold badges 137 137 silver badges 179 179 bronze badges
asked Nov 26, 2012 at 12:25
Huá dé ní 華得尼 Huá dé ní 華得尼
1,260 2 2 gold badges 18 18 silver badges 34 34 bronze badges
I found out that GSteamer is a very good alternative. Had to read to understand the basics of pipeline. With gstreamer I could send a audio from one machine and listened from the other, through TCP. Now I am trying to send video through RTP. Any help is really appreciated.
Nov 28, 2012 at 4:27
After several days of studies I was able to use gstreamer in ubuntu terminal to achieve the above task. My main scope was to learn about synchronization of the streams. I used RTP and RTCP functionalities in gstreamer. I divided a video in to four parts vertically and send from one PC to another and displayed in the second PC. Following is the code used.
Dec 4, 2012 at 12:34
2 Answers 2
After several days of studies I was able to use gstreamer in ubuntu terminal to achieve the above task. My main scope was to learn about synchronization of the streams. I used RTP and RTCP functionalities in gstreamer. I divided a video in to four parts vertically and send from one PC to another and displayed in the second PC. Following is the code used.
Sender:
gst-launch -v \ \ gstrtpbin name=rtpbin1 \ filesrc location=/home/x101.avi ! decodebin ! x264enc ! rtph264pay ! rtpbin1.send_rtp_sink_0 \ rtpbin1.send_rtp_src_0 ! udpsink host=192.168.1.100 port=5011 \ rtpbin1.send_rtcp_src_0 ! udpsink host=192.168.1.100 port=5012 \ udpsrc port=5013 ! rtpbin1.recv_rtcp_sink_0 \ \ gstrtpbin name=rtpbin2 \ filesrc location=/home/x102.avi ! decodebin ! x264enc ! rtph264pay ! rtpbin2.send_rtp_sink_0 \ rtpbin2.send_rtp_src_0 ! udpsink host=192.168.1.100 port=5021 \ rtpbin2.send_rtcp_src_0 ! udpsink host=192.168.1.100 port=5022 \ udpsrc port=5023 ! rtpbin2.recv_rtcp_sink_0 \ \ gstrtpbin name=rtpbin3 \ filesrc location=/home/x103.avi ! decodebin ! x264enc ! rtph264pay ! rtpbin3.send_rtp_sink_0 \ rtpbin3.send_rtp_src_0 ! udpsink host=192.168.1.100 port=5031 \ rtpbin3.send_rtcp_src_0 ! udpsink host=192.168.1.100 port=5032 \ udpsrc port=5033 ! rtpbin3.recv_rtcp_sink_0 \ \ gstrtpbin name=rtpbin4 \ filesrc location=/home/x104.avi ! decodebin ! x264enc ! rtph264pay ! rtpbin4.send_rtp_sink_0 \ rtpbin4.send_rtp_src_0 ! udpsink host=192.168.1.100 port=5041 \ rtpbin4.send_rtcp_src_0 ! udpsink host=192.168.1.100 port=5042 \ udpsrc port=5043 ! rtpbin4.recv_rtcp_sink_0
Receiver:
gst-launch -v \ videomixer name=mix ! ffmpegcolorspace ! autovideosink sync=false async=false \ \ gstrtpbin name=rtpbin1 \ udpsrc port=5011 caps = "application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, sprop-parameter-sets=(string)\"Z01AFeygbCPNLgIgAAADAC7msoAB4sWywA\\=\\=\\,aOvssg\\=\\=\", payload=(int)96, ssrc=(uint)861153369, clock-base=(uint)4026289255, seqnum-base=(uint)30449" ! rtpbin1.recv_rtp_sink_0 rtpbin1. ! rtph264depay ! queue ! ffdec_h264 ! videobox border-alpha=0 top=0 left=0 ! mix. \ udpsrc port=5012 ! rtpbin1.recv_rtcp_sink_0 \ rtpbin1.send_rtcp_src_0 ! udpsink port=5013 host=192.168.1.104 \ \ gstrtpbin name=rtpbin2 \ udpsrc port=5021 caps = "application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, sprop-parameter-sets=(string)\"Z01AFeygbCPNLgIgAAADAC7msoAB4sWywA\\=\\=\\,aOvssg\\=\\=\", payload=(int)96, ssrc=(uint)861153369, clock-base=(uint)4026289255, seqnum-base=(uint)30449" ! rtpbin2.recv_rtp_sink_0 rtpbin2. ! rtph264depay ! queue ! ffdec_h264 ! videobox border-alpha=0 top=-120 left=0 ! mix. \ udpsrc port=5022 ! rtpbin2.recv_rtcp_sink_0 \ rtpbin2.send_rtcp_src_0 ! udpsink port=5023 host=192.168.1.104 \ \ gstrtpbin name=rtpbin3 \ udpsrc port=5031 caps = "application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, sprop-parameter-sets=(string)\"Z01AFeygbCPNLgIgAAADAC7msoAB4sWywA\\=\\=\\,aOvssg\\=\\=\", payload=(int)96, ssrc=(uint)861153369, clock-base=(uint)4026289255, seqnum-base=(uint)30449" ! rtpbin3.recv_rtp_sink_0 rtpbin3. ! rtph264depay ! queue ! ffdec_h264 ! videobox border-alpha=0 top=-240 left=0 ! mix. \ udpsrc port=5032 ! rtpbin3.recv_rtcp_sink_0 \ rtpbin3.send_rtcp_src_0 ! udpsink port=5033 host=192.168.1.104 \ \ gstrtpbin name=rtpbin4 \ udpsrc port=5041 caps = "application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, sprop-parameter-sets=(string)\"Z01AFeygbCPNLgIgAAADAC7msoAB4sWywA\\=\\=\\,aOvssg\\=\\=\", payload=(int)96, ssrc=(uint)861153369, clock-base=(uint)4026289255, seqnum-base=(uint)30449" ! rtpbin4.recv_rtp_sink_0 rtpbin4. ! rtph264depay ! queue ! ffdec_h264 ! videobox border-alpha=0 top=-360 left=0 ! mix. \ udpsrc port=5042 ! rtpbin4.recv_rtcp_sink_0 \ rtpbin4.send_rtcp_src_0 ! udpsink port=5043 host=192.168.1.104
I was able to receive the four streams in one window as expected. But still streams are not synchronized perfectly.
RTP (Real-time Transport Protocol): Python parsing library
The Real-time Transport Protocol (RTP) is a widely used network protocol for transmitting audio or video. It usually works with the RTP Control Protocol (RTCP). The transmission can be based on Transmission Control Protocol (TCP) or User Datagram Protocol (UDP).
KS implementation details
References
- RFC 3550
- RFC 3551
- Wikidata Q321213
- RTP in Just Solve the File Format Problem
This page hosts a formal specification of RTP (Real-time Transport Protocol) using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
Usage
Runtime library
The Python runtime library can be installed from PyPI:
python3 -m pip install kaitaistruct
Code
Parse a local file and get structure in memory:
data = RtpPacket.from_file("path/to/local/file.bin")
Or parse structure from a bytes:
from kaitaistruct import KaitaiStream, BytesIO raw = b"\x00\x01\x02. " data = RtpPacket(KaitaiStream(BytesIO(raw)))
After that, one can get various attributes from the structure by invoking getter methods like:
data.data # => Payload without padding. data.len_padding_if_exists # => If padding bit is enabled, last byte of data contains number of bytes appended to the payload as padding.
Python source code to parse RTP (Real-time Transport Protocol)
rtp_packet.py
# This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild import kaitaistruct from kaitaistruct import KaitaiStruct, KaitaiStream, BytesIO from enum import Enum if getattr(kaitaistruct, 'API_VERSION', (0, 9)) (0, 9): raise Exception("Incompatible Kaitai Struct Python API: 0.9 or later is required, but you have %s" % (kaitaistruct.__version__)) class RtpPacket(KaitaiStruct): """The Real-time Transport Protocol (RTP) is a widely used network protocol for transmitting audio or video. It usually works with the RTP Control Protocol (RTCP). The transmission can be based on Transmission Control Protocol (TCP) or User Datagram Protocol (UDP). """ class PayloadTypeEnum(Enum): pcmu = 0 reserved1 = 1 reserved2 = 2 gsm = 3 g723 = 4 dvi4_1 = 5 dvi4_2 = 6 lpc = 7 pcma = 8 g722 = 9 l16_1 = 10 l16_2 = 11 qcelp = 12 cn = 13 mpa = 14 g728 = 15 dvi4_3 = 16 dvi4_4 = 17 g729 = 18 reserved19 = 19 unassigned20 = 20 unassigned21 = 21 unassigned22 = 22 unassigned23 = 23 unassigned24 = 24 celb = 25 jpeg = 26 unassigned27 = 27 nv = 28 unassigned29 = 29 unassigned30 = 30 h261 = 31 mpv = 32 mp2t = 33 h263 = 34 mpeg_ps = 96 def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.version = self._io.read_bits_int_be(2) self.has_padding = self._io.read_bits_int_be(1) != 0 self.has_extension = self._io.read_bits_int_be(1) != 0 self.csrc_count = self._io.read_bits_int_be(4) self.marker = self._io.read_bits_int_be(1) != 0 self.payload_type = KaitaiStream.resolve_enum(RtpPacket.PayloadTypeEnum, self._io.read_bits_int_be(7)) self._io.align_to_byte() self.sequence_number = self._io.read_u2be() self.timestamp = self._io.read_u4be() self.ssrc = self._io.read_u4be() if self.has_extension: self.header_extension = RtpPacket.HeaderExtention(self._io, self, self._root) self.data = self._io.read_bytes(((self._io.size() - self._io.pos()) - self.len_padding)) self.padding = self._io.read_bytes(self.len_padding) class HeaderExtention(KaitaiStruct): def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.id = self._io.read_u2be() self.length = self._io.read_u2be() @property def len_padding_if_exists(self): """If padding bit is enabled, last byte of data contains number of bytes appended to the payload as padding. """ if hasattr(self, '_m_len_padding_if_exists'): return self._m_len_padding_if_exists if self.has_padding: _pos = self._io.pos() self._io.seek((self._io.size() - 1)) self._m_len_padding_if_exists = self._io.read_u1() self._io.seek(_pos) return getattr(self, '_m_len_padding_if_exists', None) @property def len_padding(self): """Always returns number of padding bytes to in the payload.""" if hasattr(self, '_m_len_padding'): return self._m_len_padding self._m_len_padding = (self.len_padding_if_exists if self.has_padding else 0) return getattr(self, '_m_len_padding', None)
rtp 0.0.4
This python library provides a means to decode, encode, and interact with RTP packets. It is intended to be used together with other libraries that decode, encode, and interact with the payload bitstreams. This library does not provide any network functionality.
Installation
pip install rtp
Example usage
We desire that contributors of pull requests have signed, and submitted via email, a Contributor Licence Agreement (CLA), which is based on the Apache CLA.
The purpose of this agreement is to clearly define the terms under which intellectual property has been contributed to the BBC and thereby allow us to defend the project should there be a legal dispute regarding the software at some future time.
If you haven’t signed and emailed the agreement yet then the project owners will contact you using the contact info with the pull request.
License
Authors
- James Sandford
Creating RTP packet with Python
I’m working on project at university. What I’m trying to do is that I want my program to be able to change bits in RTP packets’ payload. I’m trying to create a simple tool that would apply steganography on RTP packets’ payload — first it would «catch» rtp packets sent from my computer, then change payload section and send packets further to destination. First thing (while learning) what I’m trying to do is to create RTP packet stream. And i thought I managed, until I checked with Wireshark: All that we see is only UDP packets (python socket.SOCK_DGRAM )
And just simple data stream of bits.. I’m trying to create packet by the RCF 3550:
- Version — 2 bits;
- padding — 1 bit;
- extension — 1 bit;
- csrc_count — 4bits;
- marker — 1 bit;
- payload_type — 7 bits;
- sequence_number — 16 bits;
- timestamp — 32 bits;
- ssrc — 32 bits;
- payload — varies;
I’m creating a list of bits:
rtp_packet[0:2] = format(packet_data["version"], "b").zfill(2) rtp_packet[2:3] = format(packet_data["padding"], "b") rtp_packet[3:4] = format(packet_data["extension"], "b") rtp_packet[4:8] = format(packet_datas["csrc_count"], "b").zfill(4) rtp_packet[8:9] = format(packet_data["marker"], "b") rtp_packet[9:16] = format(packet_data["payload_type"], "b").zfill(7) rtp_packet[16:32] = format(packet_data["sequence_number"], "b").zfill(16) rtp_packet[32:64] = format(packet_datas["timestamp"], "b").zfill(32) # turi dideti po 160 rtp_packet[64:96] = format(packet_data["ssrc"], "b").zfill(32) rtp_packet[96:128] = format(packet_data["csrc_list"], "b").zfill(32) rtp_packet[128:] = bin(int.from_bytes(packet_data["payload"].encode(), "big"))[2:]
And then send those bytes through created socket. Didin’t work (the result is above). Then I found this PyRTP library and the result is the same as above.
I’m new in Python and all this packet thing, so maybe someone could help me with what I’m doing wrong or what I didn’t do that Wireshark still sees those packets as only UDP, but not RTP? Image below is what I hope to do (this was done with a SIP server at home). Thank you in advance!