2 * This file is part of FFmpeg.
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * Reliable Internet Streaming Transport protocol
24 #include "libavutil/avassert.h"
25 #include "libavutil/avstring.h"
26 #include "libavutil/opt.h"
27 #include "libavutil/parseutils.h"
28 #include "libavutil/time.h"
33 #include "os_support.h"
36 #include <librist/librist.h>
37 #include <librist/version.h>
39 // RIST_MAX_PACKET_SIZE - 28 minimum protocol overhead
40 #define MAX_PAYLOAD_SIZE (10000-28)
41 #define FIFO_SIZE_DEFAULT 8192
43 typedef struct RISTContext
{
55 struct rist_logging_settings logging_settings
;
56 struct rist_peer_config peer_config
;
58 struct rist_peer
*peer
;
62 #define D AV_OPT_FLAG_DECODING_PARAM
63 #define E AV_OPT_FLAG_ENCODING_PARAM
64 #define OFFSET(x) offsetof(RISTContext, x)
65 static const AVOption librist_options
[] = {
66 { "rist_profile","set profile", OFFSET(profile
), AV_OPT_TYPE_INT
, {.i64
=RIST_PROFILE_MAIN
}, 0, 2, .flags
= D
|E
, .unit
= "profile" },
67 { "simple", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=RIST_PROFILE_SIMPLE
}, 0, 0, .flags
= D
|E
, .unit
= "profile" },
68 { "main", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=RIST_PROFILE_MAIN
}, 0, 0, .flags
= D
|E
, .unit
= "profile" },
69 { "advanced", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=RIST_PROFILE_ADVANCED
}, 0, 0, .flags
= D
|E
, .unit
= "profile" },
70 { "buffer_size", "set buffer_size in ms", OFFSET(buffer_size
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 30000, .flags
= D
|E
},
71 { "fifo_size", "set fifo buffer size, must be a power of 2", OFFSET(fifo_size
), AV_OPT_TYPE_INT
, {.i64
=FIFO_SIZE_DEFAULT
}, 32, 262144, .flags
= D
|E
},
72 { "overrun_nonfatal", "survive in case of receiving fifo buffer overrun", OFFSET(overrun_nonfatal
), AV_OPT_TYPE_BOOL
, {.i64
= 0}, 0, 1, D
},
73 { "pkt_size", "set packet size", OFFSET(packet_size
), AV_OPT_TYPE_INT
, {.i64
=1316}, 1, MAX_PAYLOAD_SIZE
, .flags
= D
|E
},
74 { "log_level", "set loglevel", OFFSET(log_level
), AV_OPT_TYPE_INT
, {.i64
=RIST_LOG_INFO
}, -1, INT_MAX
, .flags
= D
|E
},
75 { "secret", "set encryption secret",OFFSET(secret
), AV_OPT_TYPE_STRING
,{.str
=NULL
}, 0, 0, .flags
= D
|E
},
76 { "encryption","set encryption type",OFFSET(encryption
), AV_OPT_TYPE_INT
,{.i64
=0}, 0, INT_MAX
, .flags
= D
|E
},
80 static int risterr2ret(int err
)
84 return AVERROR(ENOMEM
);
86 return AVERROR_EXTERNAL
;
90 static int log_cb(void *arg
, enum rist_log_level log_level
, const char *msg
)
95 case RIST_LOG_ERROR
: level
= AV_LOG_ERROR
; break;
96 case RIST_LOG_WARN
: level
= AV_LOG_WARNING
; break;
97 case RIST_LOG_NOTICE
: level
= AV_LOG_INFO
; break;
98 case RIST_LOG_INFO
: level
= AV_LOG_VERBOSE
; break;
99 case RIST_LOG_DEBUG
: level
= AV_LOG_DEBUG
; break;
100 case RIST_LOG_DISABLE
: level
= AV_LOG_QUIET
; break;
101 default: level
= AV_LOG_WARNING
;
104 av_log(arg
, level
, "%s", msg
);
109 static int librist_close(URLContext
*h
)
111 RISTContext
*s
= h
->priv_data
;
117 ret
= rist_destroy(s
->ctx
);
120 return risterr2ret(ret
);
123 static int librist_open(URLContext
*h
, const char *uri
, int flags
)
125 RISTContext
*s
= h
->priv_data
;
126 struct rist_logging_settings
*logging_settings
= &s
->logging_settings
;
127 struct rist_peer_config
*peer_config
= &s
->peer_config
;
130 if ((flags
& AVIO_FLAG_READ_WRITE
) == AVIO_FLAG_READ_WRITE
)
131 return AVERROR(EINVAL
);
133 s
->logging_settings
= (struct rist_logging_settings
)LOGGING_SETTINGS_INITIALIZER
;
134 ret
= rist_logging_set(&logging_settings
, s
->log_level
, log_cb
, h
, NULL
, NULL
);
136 return risterr2ret(ret
);
138 if (flags
& AVIO_FLAG_WRITE
) {
139 h
->max_packet_size
= s
->packet_size
;
140 ret
= rist_sender_create(&s
->ctx
, s
->profile
, 0, logging_settings
);
145 if (flags
& AVIO_FLAG_READ
) {
146 h
->max_packet_size
= MAX_PAYLOAD_SIZE
;
147 ret
= rist_receiver_create(&s
->ctx
, s
->profile
, logging_settings
);
152 ret
= rist_peer_config_defaults_set(peer_config
);
156 ret
= rist_parse_address2(uri
, &peer_config
);
160 if (flags
& AVIO_FLAG_READ
) {
161 ret
= rist_receiver_set_output_fifo_size(s
->ctx
, s
->fifo_size
);
166 if (((s
->encryption
== 128 || s
->encryption
== 256) && !s
->secret
) ||
167 ((peer_config
->key_size
== 128 || peer_config
->key_size
== 256) && !peer_config
->secret
[0])) {
168 av_log(h
, AV_LOG_ERROR
, "secret is mandatory if encryption is enabled\n");
170 return AVERROR(EINVAL
);
173 if (s
->secret
&& peer_config
->secret
[0] == 0)
174 av_strlcpy(peer_config
->secret
, s
->secret
, RIST_MAX_STRING_SHORT
);
176 if (s
->secret
&& (s
->encryption
== 128 || s
->encryption
== 256))
177 peer_config
->key_size
= s
->encryption
;
179 if (s
->buffer_size
) {
180 peer_config
->recovery_length_min
= s
->buffer_size
;
181 peer_config
->recovery_length_max
= s
->buffer_size
;
184 ret
= rist_peer_create(s
->ctx
, &s
->peer
, &s
->peer_config
);
188 ret
= rist_start(s
->ctx
);
197 return risterr2ret(ret
);
200 static int librist_read(URLContext
*h
, uint8_t *buf
, int size
)
202 RISTContext
*s
= h
->priv_data
;
205 struct rist_data_block
*data_block
;
206 ret
= rist_receiver_data_read2(s
->ctx
, &data_block
, POLLING_TIME
);
209 return risterr2ret(ret
);
212 return AVERROR(EAGAIN
);
214 if (data_block
->payload_len
> MAX_PAYLOAD_SIZE
) {
215 rist_receiver_data_block_free2(&data_block
);
216 return AVERROR_EXTERNAL
;
219 if (data_block
->flags
& RIST_DATA_FLAGS_OVERFLOW
) {
220 if (!s
->overrun_nonfatal
) {
221 av_log(h
, AV_LOG_ERROR
, "Fifo buffer overrun. "
222 "To avoid, increase fifo_size option. "
223 "To survive in such case, use overrun_nonfatal option\n");
229 size
= data_block
->payload_len
;
230 memcpy(buf
, data_block
->payload
, size
);
232 rist_receiver_data_block_free2(&data_block
);
236 static int librist_write(URLContext
*h
, const uint8_t *buf
, int size
)
238 RISTContext
*s
= h
->priv_data
;
239 struct rist_data_block data_block
= { 0 };
242 data_block
.ts_ntp
= 0;
243 data_block
.payload
= buf
;
244 data_block
.payload_len
= size
;
246 ret
= rist_sender_data_write(s
->ctx
, &data_block
);
248 return risterr2ret(ret
);
253 static const AVClass librist_class
= {
254 .class_name
= "librist",
255 .item_name
= av_default_item_name
,
256 .option
= librist_options
,
257 .version
= LIBAVUTIL_VERSION_INT
,
260 const URLProtocol ff_librist_protocol
= {
262 .url_open
= librist_open
,
263 .url_read
= librist_read
,
264 .url_write
= librist_write
,
265 .url_close
= librist_close
,
266 .priv_data_size
= sizeof(RISTContext
),
267 .flags
= URL_PROTOCOL_FLAG_NETWORK
,
268 .priv_data_class
= &librist_class
,