33
33
#include "url.h"
34
34
#include "libavutil/random_seed.h"
35
35
36
+ #define MAX_SDP_SIZE 8192
37
+
36
38
typedef struct RTCContext {
37
39
AVClass * av_class ;
38
40
@@ -58,7 +60,11 @@ typedef struct RTCContext {
58
60
/* The ICE username and pwd from remote server. */
59
61
char * ice_ufrag_remote ;
60
62
char * ice_pwd_remote ;
61
- /* The ICE candidate protocol, priority, host and port. */
63
+ /**
64
+ * The ICE candidate protocol, priority, host and port. Note that only
65
+ * support one candidate for now. We will choose the first udp candidate.
66
+ * We will support multiple candidates in the future.
67
+ */
62
68
char * ice_protocol ;
63
69
int ice_priority ;
64
70
char * ice_host ;
@@ -186,9 +192,15 @@ static int check_codec(AVFormatContext *s)
186
192
*/
187
193
static int generate_sdp_offer (AVFormatContext * s )
188
194
{
189
- int profile_iop ;
195
+ int ret , profile_iop ;
190
196
RTCContext * rtc = s -> priv_data ;
191
197
198
+ char * tmp = av_mallocz (MAX_SDP_SIZE );
199
+ if (!tmp ) {
200
+ av_log (s , AV_LOG_ERROR , "Failed to alloc answer: %s" , s -> url );
201
+ return AVERROR (EINVAL );
202
+ }
203
+
192
204
if (rtc -> sdp_offer ) {
193
205
av_log (s , AV_LOG_ERROR , "SDP offer is already set\n" );
194
206
return AVERROR (EINVAL );
@@ -207,7 +219,8 @@ static int generate_sdp_offer(AVFormatContext *s)
207
219
rtc -> video_payload_type = 106 ;
208
220
209
221
profile_iop = rtc -> video_par -> profile & FF_PROFILE_H264_CONSTRAINED ? 0xe0 : 0x00 ;
210
- rtc -> sdp_offer = av_asprintf (
222
+
223
+ ret = av_strlcatf (tmp , MAX_SDP_SIZE ,
211
224
"v=0\r\n"
212
225
"o=FFmpeg 4489045141692799359 2 IN IP4 127.0.0.1\r\n"
213
226
"s=FFmpegPublishSession\r\n"
@@ -262,11 +275,19 @@ static int generate_sdp_offer(AVFormatContext *s)
262
275
profile_iop ,
263
276
rtc -> video_par -> level ,
264
277
rtc -> video_ssrc ,
265
- rtc -> video_ssrc
266
- );
278
+ rtc -> video_ssrc );
279
+ if (ret >= MAX_SDP_SIZE ) {
280
+ av_log (s , AV_LOG_ERROR , "Offer %d exceed max %d, %s" , ret , MAX_SDP_SIZE , tmp );
281
+ ret = AVERROR (EINVAL );
282
+ goto end ;
283
+ }
284
+
285
+ rtc -> sdp_offer = av_strdup (tmp );
267
286
av_log (s , AV_LOG_VERBOSE , "Generated offer: %s" , rtc -> sdp_offer );
268
287
269
- return 0 ;
288
+ end :
289
+ av_free (tmp );
290
+ return ret ;
270
291
}
271
292
272
293
/**
@@ -313,30 +334,35 @@ static int generate_sdp_offer(AVFormatContext *s)
313
334
static int exchange_sdp (AVFormatContext * s )
314
335
{
315
336
int ret ;
316
- char headers [MAX_URL_SIZE ], buf [MAX_URL_SIZE ];
317
- char * p ;
337
+ char buf [MAX_URL_SIZE ];
318
338
RTCContext * rtc = s -> priv_data ;
319
339
340
+ char * tmp = av_mallocz (MAX_SDP_SIZE );
341
+ if (!tmp ) {
342
+ av_log (s , AV_LOG_ERROR , "Failed to alloc answer: %s" , s -> url );
343
+ return AVERROR (EINVAL );
344
+ }
345
+
320
346
ret = ffurl_alloc (& rtc -> whip_uc , s -> url , AVIO_FLAG_READ_WRITE , & s -> interrupt_callback );
321
347
if (ret < 0 ) {
322
348
av_log (s , AV_LOG_ERROR , "Failed to alloc HTTP context: %s" , s -> url );
323
- return ret ;
349
+ goto end ;
324
350
}
325
351
326
- snprintf (headers , sizeof (headers ),
352
+ snprintf (buf , sizeof (buf ),
327
353
"Cache-Control: no-cache\r\n"
328
354
"Content-Type: application/sdp\r\n" );
329
- av_opt_set (rtc -> whip_uc -> priv_data , "headers" , headers , 0 );
355
+ av_opt_set (rtc -> whip_uc -> priv_data , "headers" , buf , 0 );
330
356
av_opt_set (rtc -> whip_uc -> priv_data , "chunked_post" , "0" , 0 );
331
357
av_opt_set_bin (rtc -> whip_uc -> priv_data , "post_data" , rtc -> sdp_offer , (int )strlen (rtc -> sdp_offer ), 0 );
332
358
333
359
ret = ffurl_connect (rtc -> whip_uc , NULL );
334
360
if (ret < 0 ) {
335
361
av_log (s , AV_LOG_ERROR , "Failed to request url=%s, offer: %s" , s -> url , rtc -> sdp_offer );
336
- return ret ;
362
+ goto end ;
337
363
}
338
364
339
- for (;; ) {
365
+ while ( 1 ) {
340
366
ret = ffurl_read (rtc -> whip_uc , buf , sizeof (buf ));
341
367
if (ret == AVERROR_EOF ) {
342
368
/* Reset the error because we read all response as answer util EOF. */
@@ -346,15 +372,22 @@ static int exchange_sdp(AVFormatContext *s)
346
372
if (ret <= 0 ) {
347
373
av_log (s , AV_LOG_ERROR , "Failed to read response from url=%s, offer is %s, answer is %s" ,
348
374
s -> url , rtc -> sdp_offer , rtc -> sdp_answer );
349
- return ret ;
375
+ goto end ;
350
376
}
351
377
352
- p = rtc -> sdp_answer ;
353
- rtc -> sdp_answer = av_asprintf ("%s%.*s" , p ? p : "" , ret , buf );
354
- av_free (p );
378
+ ret = av_strlcatf (tmp , MAX_SDP_SIZE , "%.*s" , ret , buf );
379
+ if (ret >= MAX_SDP_SIZE ) {
380
+ av_log (s , AV_LOG_ERROR , "Answer %d exceed max size %d, %s" , ret , MAX_SDP_SIZE , tmp );
381
+ ret = AVERROR (EINVAL );
382
+ goto end ;
383
+ }
355
384
}
385
+
386
+ rtc -> sdp_answer = av_strdup (tmp );
356
387
av_log (s , AV_LOG_VERBOSE , "Got answer: %s" , rtc -> sdp_answer );
357
388
389
+ end :
390
+ av_free (tmp );
358
391
return ret ;
359
392
}
360
393
@@ -372,9 +405,7 @@ static int parse_answer(AVFormatContext *s)
372
405
int i ;
373
406
RTCContext * rtc = s -> priv_data ;
374
407
375
- pb = avio_alloc_context (
376
- (unsigned char * )rtc -> sdp_answer , (int )strlen (rtc -> sdp_answer ),
377
- AVIO_FLAG_READ , NULL , NULL , NULL , NULL );
408
+ pb = avio_alloc_context (rtc -> sdp_answer , strlen (rtc -> sdp_answer ), AVIO_FLAG_READ , NULL , NULL , NULL , NULL );
378
409
if (!pb ) {
379
410
av_log (s , AV_LOG_ERROR , "Failed to alloc AVIOContext for answer: %s" , rtc -> sdp_answer );
380
411
ret = AVERROR (ENOMEM );
@@ -383,13 +414,11 @@ static int parse_answer(AVFormatContext *s)
383
414
384
415
for (i = 0 ; !avio_feof (pb ); i ++ ) {
385
416
ff_get_chomp_line (pb , line , sizeof (line ));
386
- if (av_strstart (line , "a=ice-ufrag:" , & ptr )) {
387
- av_freep (& rtc -> ice_ufrag_remote );
417
+ if (av_strstart (line , "a=ice-ufrag:" , & ptr ) && !rtc -> ice_ufrag_remote ) {
388
418
rtc -> ice_ufrag_remote = av_strdup (ptr );
389
- } else if (av_strstart (line , "a=ice-pwd:" , & ptr )) {
390
- av_freep (& rtc -> ice_pwd_remote );
419
+ } else if (av_strstart (line , "a=ice-pwd:" , & ptr ) && !rtc -> ice_pwd_remote ) {
391
420
rtc -> ice_pwd_remote = av_strdup (ptr );
392
- } else if (av_strstart (line , "a=candidate:" , & ptr )) {
421
+ } else if (av_strstart (line , "a=candidate:" , & ptr ) && ! rtc -> ice_protocol ) {
393
422
ptr = av_stristr (ptr , "udp" );
394
423
if (ptr && av_stristr (ptr , "host" )) {
395
424
char protocol [17 ], host [129 ];
@@ -403,14 +432,13 @@ static int parse_answer(AVFormatContext *s)
403
432
}
404
433
405
434
if (av_strcasecmp (protocol , "udp" )) {
406
- av_log (s , AV_LOG_ERROR , "Protocol %s is not supported by RTC, choose udp" , protocol );
435
+ av_log (s , AV_LOG_ERROR , "Protocol %s is not supported by RTC, choose udp, line %d %s of %s" ,
436
+ protocol , i , line , rtc -> sdp_answer );
407
437
ret = AVERROR (EINVAL );
408
438
goto end ;
409
439
}
410
440
411
- av_freep (& rtc -> ice_protocol );
412
441
rtc -> ice_protocol = av_strdup (protocol );
413
- av_freep (& rtc -> ice_host );
414
442
rtc -> ice_host = av_strdup (host );
415
443
rtc -> ice_priority = priority ;
416
444
rtc -> ice_port = port ;
@@ -423,7 +451,7 @@ static int parse_answer(AVFormatContext *s)
423
451
return ret ;
424
452
}
425
453
426
- static int rtc_init (AVFormatContext * s )
454
+ static av_cold int rtc_init (AVFormatContext * s )
427
455
{
428
456
int ret ;
429
457
@@ -457,7 +485,7 @@ static int rtc_write_trailer(AVFormatContext *s)
457
485
return 0 ;
458
486
}
459
487
460
- static void rtc_deinit (AVFormatContext * s )
488
+ static av_cold void rtc_deinit (AVFormatContext * s )
461
489
{
462
490
RTCContext * rtc = s -> priv_data ;
463
491
av_freep (& rtc -> sdp_offer );
0 commit comments