3333#include "url.h"
3434#include "libavutil/random_seed.h"
3535
36+ #define MAX_SDP_SIZE 8192
37+
3638typedef struct RTCContext {
3739 AVClass * av_class ;
3840
@@ -58,16 +60,16 @@ typedef struct RTCContext {
5860 /* The ICE username and pwd from remote server. */
5961 char * ice_ufrag_remote ;
6062 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+ */
6268 char * ice_protocol ;
63- int ice_priority ;
6469 char * ice_host ;
6570 int ice_port ;
6671 /* The SDP answer received from the WebRTC server. */
6772 char * sdp_answer ;
68-
69- /* The HTTP URL context is the transport layer for the WHIP protocol. */
70- URLContext * whip_uc ;
7173} RTCContext ;
7274
7375/**
@@ -186,9 +188,15 @@ static int check_codec(AVFormatContext *s)
186188 */
187189static int generate_sdp_offer (AVFormatContext * s )
188190{
189- int profile_iop ;
191+ int ret , profile_iop ;
190192 RTCContext * rtc = s -> priv_data ;
191193
194+ char * tmp = av_mallocz (MAX_SDP_SIZE );
195+ if (!tmp ) {
196+ av_log (s , AV_LOG_ERROR , "Failed to alloc answer: %s" , s -> url );
197+ return AVERROR (EINVAL );
198+ }
199+
192200 if (rtc -> sdp_offer ) {
193201 av_log (s , AV_LOG_ERROR , "SDP offer is already set\n" );
194202 return AVERROR (EINVAL );
@@ -207,7 +215,8 @@ static int generate_sdp_offer(AVFormatContext *s)
207215 rtc -> video_payload_type = 106 ;
208216
209217 profile_iop = rtc -> video_par -> profile & FF_PROFILE_H264_CONSTRAINED ? 0xe0 : 0x00 ;
210- rtc -> sdp_offer = av_asprintf (
218+
219+ ret = av_strlcatf (tmp , MAX_SDP_SIZE ,
211220 "v=0\r\n"
212221 "o=FFmpeg 4489045141692799359 2 IN IP4 127.0.0.1\r\n"
213222 "s=FFmpegPublishSession\r\n"
@@ -262,11 +271,19 @@ static int generate_sdp_offer(AVFormatContext *s)
262271 profile_iop ,
263272 rtc -> video_par -> level ,
264273 rtc -> video_ssrc ,
265- rtc -> video_ssrc
266- );
274+ rtc -> video_ssrc );
275+ if (ret >= MAX_SDP_SIZE ) {
276+ av_log (s , AV_LOG_ERROR , "Offer %d exceed max %d, %s" , ret , MAX_SDP_SIZE , tmp );
277+ ret = AVERROR (EINVAL );
278+ goto end ;
279+ }
280+
281+ rtc -> sdp_offer = av_strdup (tmp );
267282 av_log (s , AV_LOG_VERBOSE , "Generated offer: %s" , rtc -> sdp_offer );
268283
269- return 0 ;
284+ end :
285+ av_free (tmp );
286+ return ret ;
270287}
271288
272289/**
@@ -313,31 +330,38 @@ static int generate_sdp_offer(AVFormatContext *s)
313330static int exchange_sdp (AVFormatContext * s )
314331{
315332 int ret ;
316- char headers [MAX_URL_SIZE ], buf [MAX_URL_SIZE ];
317- char * p ;
333+ char buf [MAX_URL_SIZE ];
318334 RTCContext * rtc = s -> priv_data ;
335+ /* The URL context is an HTTP transport layer for the WHIP protocol. */
336+ URLContext * whip_uc = NULL ;
337+
338+ char * tmp = av_mallocz (MAX_SDP_SIZE );
339+ if (!tmp ) {
340+ av_log (s , AV_LOG_ERROR , "Failed to alloc answer: %s" , s -> url );
341+ return AVERROR (EINVAL );
342+ }
319343
320- ret = ffurl_alloc (& rtc -> whip_uc , s -> url , AVIO_FLAG_READ_WRITE , & s -> interrupt_callback );
344+ ret = ffurl_alloc (& whip_uc , s -> url , AVIO_FLAG_READ_WRITE , & s -> interrupt_callback );
321345 if (ret < 0 ) {
322346 av_log (s , AV_LOG_ERROR , "Failed to alloc HTTP context: %s" , s -> url );
323- return ret ;
347+ goto end ;
324348 }
325349
326- snprintf (headers , sizeof (headers ),
350+ snprintf (buf , sizeof (buf ),
327351 "Cache-Control: no-cache\r\n"
328352 "Content-Type: application/sdp\r\n" );
329- av_opt_set (rtc -> whip_uc -> priv_data , "headers" , headers , 0 );
330- av_opt_set (rtc -> whip_uc -> priv_data , "chunked_post" , "0" , 0 );
331- av_opt_set_bin (rtc -> whip_uc -> priv_data , "post_data" , rtc -> sdp_offer , (int )strlen (rtc -> sdp_offer ), 0 );
353+ av_opt_set (whip_uc -> priv_data , "headers" , buf , 0 );
354+ av_opt_set (whip_uc -> priv_data , "chunked_post" , "0" , 0 );
355+ av_opt_set_bin (whip_uc -> priv_data , "post_data" , rtc -> sdp_offer , (int )strlen (rtc -> sdp_offer ), 0 );
332356
333- ret = ffurl_connect (rtc -> whip_uc , NULL );
357+ ret = ffurl_connect (whip_uc , NULL );
334358 if (ret < 0 ) {
335359 av_log (s , AV_LOG_ERROR , "Failed to request url=%s, offer: %s" , s -> url , rtc -> sdp_offer );
336- return ret ;
360+ goto end ;
337361 }
338362
339- for (;; ) {
340- ret = ffurl_read (rtc -> whip_uc , buf , sizeof (buf ));
363+ while ( 1 ) {
364+ ret = ffurl_read (whip_uc , buf , sizeof (buf ));
341365 if (ret == AVERROR_EOF ) {
342366 /* Reset the error because we read all response as answer util EOF. */
343367 ret = 0 ;
@@ -346,15 +370,23 @@ static int exchange_sdp(AVFormatContext *s)
346370 if (ret <= 0 ) {
347371 av_log (s , AV_LOG_ERROR , "Failed to read response from url=%s, offer is %s, answer is %s" ,
348372 s -> url , rtc -> sdp_offer , rtc -> sdp_answer );
349- return ret ;
373+ goto end ;
350374 }
351375
352- p = rtc -> sdp_answer ;
353- rtc -> sdp_answer = av_asprintf ("%s%.*s" , p ? p : "" , ret , buf );
354- av_free (p );
376+ ret = av_strlcatf (tmp , MAX_SDP_SIZE , "%.*s" , ret , buf );
377+ if (ret >= MAX_SDP_SIZE ) {
378+ av_log (s , AV_LOG_ERROR , "Answer %d exceed max size %d, %s" , ret , MAX_SDP_SIZE , tmp );
379+ ret = AVERROR (EINVAL );
380+ goto end ;
381+ }
355382 }
383+
384+ rtc -> sdp_answer = av_strdup (tmp );
356385 av_log (s , AV_LOG_VERBOSE , "Got answer: %s" , rtc -> sdp_answer );
357386
387+ end :
388+ ffurl_closep (& whip_uc );
389+ av_free (tmp );
358390 return ret ;
359391}
360392
@@ -372,9 +404,7 @@ static int parse_answer(AVFormatContext *s)
372404 int i ;
373405 RTCContext * rtc = s -> priv_data ;
374406
375- pb = avio_alloc_context (
376- (unsigned char * )rtc -> sdp_answer , (int )strlen (rtc -> sdp_answer ),
377- AVIO_FLAG_READ , NULL , NULL , NULL , NULL );
407+ pb = avio_alloc_context (rtc -> sdp_answer , strlen (rtc -> sdp_answer ), AVIO_FLAG_READ , NULL , NULL , NULL , NULL );
378408 if (!pb ) {
379409 av_log (s , AV_LOG_ERROR , "Failed to alloc AVIOContext for answer: %s" , rtc -> sdp_answer );
380410 ret = AVERROR (ENOMEM );
@@ -383,13 +413,11 @@ static int parse_answer(AVFormatContext *s)
383413
384414 for (i = 0 ; !avio_feof (pb ); i ++ ) {
385415 ff_get_chomp_line (pb , line , sizeof (line ));
386- if (av_strstart (line , "a=ice-ufrag:" , & ptr )) {
387- av_freep (& rtc -> ice_ufrag_remote );
416+ if (av_strstart (line , "a=ice-ufrag:" , & ptr ) && !rtc -> ice_ufrag_remote ) {
388417 rtc -> ice_ufrag_remote = av_strdup (ptr );
389- } else if (av_strstart (line , "a=ice-pwd:" , & ptr )) {
390- av_freep (& rtc -> ice_pwd_remote );
418+ } else if (av_strstart (line , "a=ice-pwd:" , & ptr ) && !rtc -> ice_pwd_remote ) {
391419 rtc -> ice_pwd_remote = av_strdup (ptr );
392- } else if (av_strstart (line , "a=candidate:" , & ptr )) {
420+ } else if (av_strstart (line , "a=candidate:" , & ptr ) && ! rtc -> ice_protocol ) {
393421 ptr = av_stristr (ptr , "udp" );
394422 if (ptr && av_stristr (ptr , "host" )) {
395423 char protocol [17 ], host [129 ];
@@ -403,27 +431,29 @@ static int parse_answer(AVFormatContext *s)
403431 }
404432
405433 if (av_strcasecmp (protocol , "udp" )) {
406- av_log (s , AV_LOG_ERROR , "Protocol %s is not supported by RTC, choose udp" , protocol );
434+ av_log (s , AV_LOG_ERROR , "Protocol %s is not supported by RTC, choose udp, line %d %s of %s" ,
435+ protocol , i , line , rtc -> sdp_answer );
407436 ret = AVERROR (EINVAL );
408437 goto end ;
409438 }
410439
411- av_freep (& rtc -> ice_protocol );
412440 rtc -> ice_protocol = av_strdup (protocol );
413- av_freep (& rtc -> ice_host );
414441 rtc -> ice_host = av_strdup (host );
415- rtc -> ice_priority = priority ;
416442 rtc -> ice_port = port ;
417443 }
418444 }
419445 }
420446
447+ av_log (s , AV_LOG_VERBOSE , "SDP offer=%luB, answer=%luB, ufrag=%s, pwd=%luB, transport=%s://%s:%d\n" ,
448+ strlen (rtc -> sdp_offer ), strlen (rtc -> sdp_answer ), rtc -> ice_ufrag_remote , strlen (rtc -> ice_pwd_remote ),
449+ rtc -> ice_protocol , rtc -> ice_host , rtc -> ice_port );
450+
421451end :
422452 avio_context_free (& pb );
423453 return ret ;
424454}
425455
426- static int rtc_init (AVFormatContext * s )
456+ static av_cold int rtc_init (AVFormatContext * s )
427457{
428458 int ret ;
429459
@@ -457,12 +487,11 @@ static int rtc_write_trailer(AVFormatContext *s)
457487 return 0 ;
458488}
459489
460- static void rtc_deinit (AVFormatContext * s )
490+ static av_cold void rtc_deinit (AVFormatContext * s )
461491{
462492 RTCContext * rtc = s -> priv_data ;
463493 av_freep (& rtc -> sdp_offer );
464494 av_freep (& rtc -> sdp_answer );
465- ffurl_closep (& rtc -> whip_uc );
466495 av_freep (& rtc -> ice_ufrag_remote );
467496 av_freep (& rtc -> ice_pwd_remote );
468497 av_freep (& rtc -> ice_protocol );
0 commit comments