summaryrefslogtreecommitdiff
path: root/gst/rtp/rtpulpfeccommon.h
blob: f44174a9529eb874d0f5afabfefed0389da96b81 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/* GStreamer plugin for forward error correction
 * Copyright (C) 2017 Pexip
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Author: Mikhail Fludkov <misha@pexip.com>
 */

#ifndef __RTP_ULPFEC_COMMON_H__
#define __RTP_ULPFEC_COMMON_H__

#include <gst/gst.h>
#include <gst/rtp/rtp.h>

G_BEGIN_DECLS

#define GST_WARNING_RTP_PACKET(obj, name, pkt) rtp_ulpfec_log_rtppacket (GST_CAT_DEFAULT, GST_LEVEL_WARNING, obj, name, pkt)
#define GST_LOG_RTP_PACKET(obj, name, pkt)     rtp_ulpfec_log_rtppacket (GST_CAT_DEFAULT, GST_LEVEL_LOG, obj, name, pkt)
#define GST_DEBUG_RTP_PACKET(obj, name, pkt)   rtp_ulpfec_log_rtppacket (GST_CAT_DEFAULT, GST_LEVEL_DEBUG, obj, name, pkt)
#define GST_INFO_RTP_PACKET(obj, name, pkt)    rtp_ulpfec_log_rtppacket (GST_CAT_DEFAULT, GST_LEVEL_INFO, obj, name, pkt)
#define GST_WARNING_FEC_PACKET(obj, pkt)       rtp_ulpfec_log_fec_packet (GST_CAT_DEFAULT, GST_LEVEL_WARNING, obj, pkt)
#define GST_DEBUG_FEC_PACKET(obj, pkt)         rtp_ulpfec_log_fec_packet (GST_CAT_DEFAULT, GST_LEVEL_DEBUG, obj, pkt)
#define GST_INFO_FEC_PACKET(obj, pkt)          rtp_ulpfec_log_fec_packet (GST_CAT_DEFAULT, GST_LEVEL_INFO, obj, pkt)

#define RTP_ULPFEC_PROTECTED_PACKETS_MAX(L)    ((L) ? 48 : 16)
#define RTP_ULPFEC_SEQ_BASE_OFFSET_MAX(L)      (RTP_ULPFEC_PROTECTED_PACKETS_MAX(L) - 1)

/**
 * RtpUlpFecMapInfo: Helper wrapper around GstRTPBuffer
 *
 * @rtp: mapped RTP buffer
 **/
typedef struct {
  // FIXME: it used to contain more fields now we are left with only GstRTPBuffer.
  //        it will be nice to use it directly
  GstRTPBuffer rtp;
} RtpUlpFecMapInfo;

/* FIXME: parse/write these properly instead of relying in packed structs */
#ifdef _MSC_VER
#pragma pack(push, 1)
#define ATTRIBUTE_PACKED
#else
#define ATTRIBUTE_PACKED __attribute__ ((packed))
#endif

/* RFC 5109 */
/*
    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |E|L|P|X|  CC   |M| PT recovery |            SN base            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                          TS recovery                          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |        length recovery        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                  Figure 3: FEC Header Format
*/
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
typedef struct {
  guint8 CC:4;
  guint8 X:1;
  guint8 P:1;
  guint8 L:1;
  guint8 E:1;

  guint8 pt:7;
  guint8 M:1;

  guint16 seq;
  guint32 timestamp;
  guint16 len;
} ATTRIBUTE_PACKED RtpUlpFecHeader;
#else
typedef struct {
  guint8 E:1;
  guint8 L:1;
  guint8 P:1;
  guint8 X:1;
  guint8 CC:4;

  guint8 M:1;
  guint8 pt:7;

  guint16 seq;
  guint32 timestamp;
  guint16 len;
} ATTRIBUTE_PACKED RtpUlpFecHeader;
#endif

/*
    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |       Protection Length       |             mask              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |              mask cont. (present only when L = 1)             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                  Figure 4: ULP Level Header Format
*/
typedef struct
{
  guint16 protection_len;
  guint16 mask;
  guint32 mask_continued;
} ATTRIBUTE_PACKED RtpUlpFecLevelHeader;

#ifdef _MSC_VER
#pragma pack(pop)
#else
#undef ATTRIBUTE_PACKED
#endif

gboolean          rtp_ulpfec_map_info_map                  (GstBuffer *buffer, RtpUlpFecMapInfo *info);
void              rtp_ulpfec_map_info_unmap                (RtpUlpFecMapInfo *info);
void              rtp_buffer_to_ulpfec_bitstring           (GstRTPBuffer *rtp, GArray *dst_arr,
                                                            gboolean fec_buffer, gboolean fec_mask_long);
GstBuffer       * rtp_ulpfec_bitstring_to_media_rtp_buffer (GArray *arr,
                                                            gboolean fec_mask_long, guint32 ssrc, guint16 seq);
GstBuffer       * rtp_ulpfec_bitstring_to_fec_rtp_buffer   (GArray *arr, guint16 seq_base, gboolean fec_mask_long,
                                                            guint64 fec_mask, gboolean marker, guint8 pt, guint16 seq,
                                                            guint32 timestamp, guint32 ssrc);

#ifndef GST_DISABLE_GST_DEBUG
void              rtp_ulpfec_log_rtppacket                 (GstDebugCategory * cat, GstDebugLevel level,
                                                            gpointer object, const gchar *name,
                                                            GstRTPBuffer *rtp);

void              rtp_ulpfec_log_fec_packet                (GstDebugCategory * cat, GstDebugLevel level,
                                                            gpointer object, GstRTPBuffer *fecrtp);
#else
#define rtp_ulpfec_log_rtppacket(cat,level,obj,name,rtp) /* NOOP */
#define rtp_ulpfec_log_fec_packet(cat,level,obj,fecrtp)  /* NOOP */
#endif

RtpUlpFecHeader * rtp_ulpfec_buffer_get_fechdr             (GstRTPBuffer *rtp);
guint             rtp_ulpfec_get_headers_len               (gboolean fec_mask_long);
guint16           rtp_ulpfec_hdr_get_protection_len        (RtpUlpFecHeader const *fec_hdr);
guint64           rtp_ulpfec_packet_mask_from_seqnum       (guint16 seq, guint16 fec_seq_base, gboolean fec_mask_long);
guint64           rtp_ulpfec_buffer_get_mask               (GstRTPBuffer *rtp);
guint16           rtp_ulpfec_buffer_get_seq_base           (GstRTPBuffer *rtp);
gboolean          rtp_ulpfec_mask_is_long                  (guint64 mask);
gboolean          rtp_ulpfec_buffer_is_valid               (GstRTPBuffer * rtp);

G_END_DECLS

#endif