Skip to content

Commit a1fee90

Browse files
funmancmassiot
authored andcommitted
RTP Ancillary: rfc 3831
1 parent eaa6cda commit a1fee90

File tree

4 files changed

+291
-0
lines changed

4 files changed

+291
-0
lines changed

include/upipe-modules/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,5 @@ myinclude_HEADERS = \
9393
uref_graph_flow.h \
9494
uref_graph.h \
9595
upipe_graph.h \
96+
upipe_rtp_anc_unpack.h \
9697
$(NULL)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright (C) 2025 Open Broadcast Systems Ltd
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining
5+
* a copy of this software and associated documentation files (the
6+
* "Software"), to deal in the Software without restriction, including
7+
* without limitation the rights to use, copy, modify, merge, publish,
8+
* distribute, sublicense, and/or sell copies of the Software, and to
9+
* permit persons to whom the Software is furnished to do so, subject
10+
* to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be
13+
* included in all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18+
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19+
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21+
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22+
*/
23+
24+
#ifndef _UPIPE_MODULES_UPIPE_RTP_ANC_UNPACK_H_
25+
# define _UPIPE_MODULES_UPIPE_RTP_ANC_UNPACK_H_
26+
27+
#ifdef __cplusplus
28+
extern "C" {
29+
#endif
30+
31+
#define UPIPE_RTP_ANC_UNPACK_SIGNATURE UBASE_FOURCC('r','t','p','a')
32+
33+
struct upipe_mgr *upipe_rtp_anc_unpack_mgr_alloc(void);
34+
35+
#ifdef __cplusplus
36+
}
37+
#endif
38+
39+
#endif

lib/upipe-modules/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ libupipe_modules_la_SOURCES += \
103103
upipe_id3v2_decaps.c \
104104
upipe_id3v2_encaps.c \
105105
upipe_id3v2.c \
106+
upipe_rtp_anc_unpack.c \
106107
$(NULL)
107108
libupipe_modules_la_CFLAGS = $(AM_CFLAGS) $(BITSTREAM_CFLAGS)
108109
endif
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
/*
2+
* Copyright (C) 2025 Open Broadcast Systems Ltd
3+
*
4+
* Authors: Rafaël Carré
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining
7+
* a copy of this software and associated documentation files (the
8+
* "Software"), to deal in the Software without restriction, including
9+
* without limitation the rights to use, copy, modify, merge, publish,
10+
* distribute, sublicense, and/or sell copies of the Software, and to
11+
* permit persons to whom the Software is furnished to do so, subject
12+
* to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be
15+
* included in all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20+
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21+
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23+
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24+
*/
25+
26+
/** @file
27+
* @short Upipe module to decapsulate RTP Ancillary data (RFC8331)
28+
*/
29+
30+
31+
#include <stdlib.h>
32+
33+
#include <upipe/upipe.h>
34+
#include <upipe/uref_block.h>
35+
#include <upipe/uref_pic.h>
36+
#include <upipe/upipe_helper_upipe.h>
37+
#include <upipe/upipe_helper_urefcount.h>
38+
#include <upipe/upipe_helper_void.h>
39+
#include <upipe/upipe_helper_output.h>
40+
#include <upipe/upipe_helper_input.h>
41+
#include <upipe-modules/upipe_rtp_anc_unpack.h>
42+
43+
#include <bitstream/ietf/rtp.h>
44+
#include <bitstream/ietf/rfc8331.h>
45+
46+
struct upipe_rtp_anc_unpack {
47+
/** refcount management structure */
48+
struct urefcount urefcount;
49+
50+
/* output stuff */
51+
/** pipe acting as output */
52+
struct upipe *output;
53+
/** output flow definition packet */
54+
struct uref *flow_def;
55+
/** output state */
56+
enum upipe_helper_output_state output_state;
57+
/** list of output requests */
58+
struct uchain request_list;
59+
60+
/** temporary uref storage (used during urequest) */
61+
struct uchain urefs;
62+
/** nb urefs in storage */
63+
unsigned int nb_urefs;
64+
/** max urefs in storage */
65+
unsigned int max_urefs;
66+
/** list of blockers (used during urequest) */
67+
struct uchain blockers;
68+
69+
/** public upipe structure */
70+
struct upipe upipe;
71+
};
72+
73+
/** @hidden */
74+
static bool upipe_rtp_anc_unpack_handle(struct upipe *upipe, struct uref *uref,
75+
struct upump **upump_p);
76+
77+
UPIPE_HELPER_UPIPE(upipe_rtp_anc_unpack, upipe, UPIPE_RTP_ANC_UNPACK_SIGNATURE)
78+
UPIPE_HELPER_UREFCOUNT(upipe_rtp_anc_unpack, urefcount, upipe_rtp_anc_unpack_free)
79+
UPIPE_HELPER_VOID(upipe_rtp_anc_unpack)
80+
UPIPE_HELPER_OUTPUT(upipe_rtp_anc_unpack, output, flow_def, output_state,
81+
request_list)
82+
UPIPE_HELPER_INPUT(upipe_rtp_anc_unpack, urefs, nb_urefs, max_urefs, blockers,
83+
upipe_rtp_anc_unpack_handle)
84+
85+
static int upipe_rtp_anc_unpack_set_flow_def(struct upipe *upipe,
86+
struct uref *flow_def)
87+
{
88+
if (flow_def == NULL)
89+
return UBASE_ERR_INVALID;
90+
91+
flow_def = uref_dup(flow_def);
92+
if (unlikely(!flow_def)) {
93+
upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
94+
return UBASE_ERR_ALLOC;
95+
}
96+
97+
uref_flow_set_def(flow_def, "block.vanc.rfc8331.pic.");
98+
upipe_rtp_anc_unpack_store_flow_def(upipe, flow_def);
99+
100+
return UBASE_ERR_NONE;
101+
}
102+
103+
static int upipe_rtp_anc_unpack_control(struct upipe *upipe, int command,
104+
va_list args)
105+
{
106+
switch (command) {
107+
case UPIPE_REGISTER_REQUEST: {
108+
struct urequest *request = va_arg(args, struct urequest *);
109+
if (request->type == UREQUEST_FLOW_FORMAT ||
110+
request->type == UREQUEST_UBUF_MGR)
111+
return upipe_throw_provide_request(upipe, request);
112+
return upipe_rtp_anc_unpack_alloc_output_proxy(upipe, request);
113+
}
114+
case UPIPE_UNREGISTER_REQUEST: {
115+
struct urequest *request = va_arg(args, struct urequest *);
116+
if (request->type == UREQUEST_FLOW_FORMAT ||
117+
request->type == UREQUEST_UBUF_MGR)
118+
return UBASE_ERR_NONE;
119+
return upipe_rtp_anc_unpack_free_output_proxy(upipe, request);
120+
}
121+
case UPIPE_SET_FLOW_DEF: {
122+
struct uref *flow_def = va_arg(args, struct uref *);
123+
return upipe_rtp_anc_unpack_set_flow_def(upipe, flow_def);
124+
}
125+
case UPIPE_GET_OUTPUT:
126+
case UPIPE_SET_OUTPUT:
127+
case UPIPE_GET_FLOW_DEF:
128+
return upipe_rtp_anc_unpack_control_output(upipe, command, args);
129+
default:
130+
return UBASE_ERR_UNHANDLED;
131+
}
132+
}
133+
134+
static void upipe_rtp_anc_unpack_free(struct upipe *upipe)
135+
{
136+
upipe_throw_dead(upipe);
137+
138+
upipe_rtp_anc_unpack_clean_output(upipe);
139+
upipe_rtp_anc_unpack_clean_urefcount(upipe);
140+
upipe_rtp_anc_unpack_clean_input(upipe);
141+
upipe_rtp_anc_unpack_free_void(upipe);
142+
}
143+
144+
static struct upipe *upipe_rtp_anc_unpack_alloc(struct upipe_mgr *mgr,
145+
struct uprobe *uprobe,
146+
uint32_t signature,
147+
va_list args)
148+
{
149+
struct upipe *upipe =
150+
upipe_rtp_anc_unpack_alloc_void(mgr, uprobe, signature, args);
151+
if (unlikely(upipe == NULL))
152+
return NULL;
153+
154+
upipe_rtp_anc_unpack_init_urefcount(upipe);
155+
upipe_rtp_anc_unpack_init_input(upipe);
156+
upipe_rtp_anc_unpack_init_output(upipe);
157+
158+
upipe_throw_ready(upipe);
159+
160+
return upipe;
161+
}
162+
163+
static void upipe_rtp_anc_unpack_input(struct upipe *upipe, struct uref *uref,
164+
struct upump **upump_p)
165+
{
166+
if (!upipe_rtp_anc_unpack_check_input(upipe)) {
167+
upipe_rtp_anc_unpack_hold_input(upipe, uref);
168+
upipe_rtp_anc_unpack_block_input(upipe, upump_p);
169+
} else if (!upipe_rtp_anc_unpack_handle(upipe, uref, upump_p)) {
170+
upipe_rtp_anc_unpack_hold_input(upipe, uref);
171+
upipe_rtp_anc_unpack_block_input(upipe, upump_p);
172+
/* Increment upipe refcount to avoid disappearing before all unpackets
173+
* have been sent. */
174+
upipe_use(upipe);
175+
}
176+
}
177+
178+
static bool upipe_rtp_anc_unpack_handle(struct upipe *upipe, struct uref *uref,
179+
struct upump **upump_p)
180+
{
181+
const uint8_t *buf;
182+
int size = -1;
183+
184+
ubase_assert(uref_block_read(uref, 0, &size, &buf));
185+
186+
if (size < RFC_8331_HEADER_LEN) {
187+
upipe_err_va(upipe, "Invalid packet (%d < %d)",
188+
size, RFC_8331_HEADER_LEN);
189+
goto error;
190+
}
191+
192+
uint16_t ext_seq = rfc8331_get_extended_sequence_number(buf);
193+
uint16_t len = rfc8331_get_length(buf);
194+
uint8_t anc_count = rfc8331_get_anc_count(buf);
195+
uint8_t f = rfc8331_get_f(buf);
196+
197+
switch (f) {
198+
case RFC_8331_F_PROGRESSIVE:
199+
uref_pic_set_progressive(uref);
200+
break;
201+
case RFC_8331_F_FIELD_1:
202+
uref_pic_set_tf(uref);
203+
break;
204+
case RFC_8331_F_FIELD_2:
205+
uref_pic_set_bf(uref);
206+
break;
207+
default:
208+
upipe_err(upipe, "Invalid field");
209+
goto error;
210+
}
211+
212+
buf += RFC_8331_HEADER_LEN;
213+
size -= RFC_8331_HEADER_LEN;
214+
215+
if (size < len) {
216+
upipe_err_va(upipe, "Invalid packet (%d < %d)", size, len);
217+
goto error;
218+
}
219+
220+
(void)ext_seq; /* we don't have lower bits seqnum */
221+
(void)anc_count; /* next pipe will loop over data */
222+
223+
ubase_assert(uref_block_unmap(uref, 0));
224+
225+
uref_block_resize(uref, RFC_8331_HEADER_LEN, -1);
226+
227+
upipe_rtp_anc_unpack_output(upipe, uref, upump_p);
228+
return true;
229+
230+
error:
231+
ubase_assert(uref_block_unmap(uref, 0));
232+
uref_free(uref);
233+
return true;
234+
}
235+
236+
static struct upipe_mgr upipe_rtp_anc_unpack_mgr = {
237+
.refcount = NULL,
238+
.signature = UPIPE_RTP_ANC_UNPACK_SIGNATURE,
239+
240+
.upipe_alloc = upipe_rtp_anc_unpack_alloc,
241+
.upipe_input = upipe_rtp_anc_unpack_input,
242+
.upipe_control = upipe_rtp_anc_unpack_control,
243+
244+
.upipe_mgr_control = NULL,
245+
};
246+
247+
struct upipe_mgr *upipe_rtp_anc_unpack_mgr_alloc(void)
248+
{
249+
return &upipe_rtp_anc_unpack_mgr;
250+
}

0 commit comments

Comments
 (0)