FFmpeg
whip.c
Go to the documentation of this file.
1 /*
2  * WebRTC-HTTP ingestion protocol (WHIP) muxer
3  * Copyright (c) 2023 The FFmpeg Project
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include "libavcodec/avcodec.h"
23 #include "libavcodec/codec_desc.h"
24 #include "libavcodec/h264.h"
25 #include "libavcodec/startcode.h"
26 #include "libavutil/base64.h"
27 #include "libavutil/bprint.h"
28 #include "libavutil/crc.h"
29 #include "libavutil/hmac.h"
30 #include "libavutil/intreadwrite.h"
31 #include "libavutil/lfg.h"
32 #include "libavutil/opt.h"
33 #include "libavutil/mem.h"
34 #include "libavutil/random_seed.h"
35 #include "libavutil/time.h"
36 #include "avc.h"
37 #include "nal.h"
38 #include "avio_internal.h"
39 #include "http.h"
40 #include "internal.h"
41 #include "mux.h"
42 #include "network.h"
43 #include "srtp.h"
44 #include "tls.h"
45 
46 /**
47  * Maximum size limit of a Session Description Protocol (SDP),
48  * be it an offer or answer.
49  */
50 #define MAX_SDP_SIZE 8192
51 
52 /**
53  * The size of the Secure Real-time Transport Protocol (SRTP) master key material
54  * that is exported by Secure Sockets Layer (SSL) after a successful Datagram
55  * Transport Layer Security (DTLS) handshake. This material consists of a key
56  * of 16 bytes and a salt of 14 bytes.
57  */
58 #define DTLS_SRTP_KEY_LEN 16
59 #define DTLS_SRTP_SALT_LEN 14
60 
61 /**
62  * The maximum size of the Secure Real-time Transport Protocol (SRTP) HMAC checksum
63  * and padding that is appended to the end of the packet. To calculate the maximum
64  * size of the User Datagram Protocol (UDP) packet that can be sent out, subtract
65  * this size from the `pkt_size`.
66  */
67 #define DTLS_SRTP_CHECKSUM_LEN 16
68 
69 /**
70  * When sending ICE or DTLS messages, responses are received via UDP. However, the peer
71  * may not be ready and return EAGAIN, in which case we should wait for a short duration
72  * and retry reading.
73  * For instance, if we try to read from UDP and get EAGAIN, we sleep for 5ms and retry.
74  * This macro is used to limit the total duration in milliseconds (e.g., 50ms), so we
75  * will try at most 5 times.
76  * Keep in mind that this macro should have a minimum duration of 5 ms.
77  */
78 #define ICE_DTLS_READ_INTERVAL 50
79 
80 /* The magic cookie for Session Traversal Utilities for NAT (STUN) messages. */
81 #define STUN_MAGIC_COOKIE 0x2112A442
82 
83 /**
84  * Refer to RFC 8445 5.1.2
85  * priority = (2^24)*(type preference) + (2^8)*(local preference) + (2^0)*(256 - component ID)
86  * host candidate priority is 126 << 24 | 65535 << 8 | 255
87  */
88 #define STUN_HOST_CANDIDATE_PRIORITY 126 << 24 | 65535 << 8 | 255
89 
90 /**
91  * The DTLS content type.
92  * See https://tools.ietf.org/html/rfc2246#section-6.2.1
93  * change_cipher_spec(20), alert(21), handshake(22), application_data(23)
94  */
95 #define DTLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC 20
96 
97 /**
98  * The DTLS record layer header has a total size of 13 bytes, consisting of
99  * ContentType (1 byte), ProtocolVersion (2 bytes), Epoch (2 bytes),
100  * SequenceNumber (6 bytes), and Length (2 bytes).
101  * See https://datatracker.ietf.org/doc/html/rfc9147#section-4
102  */
103 #define DTLS_RECORD_LAYER_HEADER_LEN 13
104 
105 /**
106  * The DTLS version number, which is 0xfeff for DTLS 1.0, or 0xfefd for DTLS 1.2.
107  * See https://datatracker.ietf.org/doc/html/rfc9147#name-the-dtls-record-layer
108  */
109 #define DTLS_VERSION_10 0xfeff
110 #define DTLS_VERSION_12 0xfefd
111 
112 /**
113  * Maximum size of the buffer for sending and receiving UDP packets.
114  * Please note that this size does not limit the size of the UDP packet that can be sent.
115  * To set the limit for packet size, modify the `pkt_size` parameter.
116  * For instance, it is possible to set the UDP buffer to 4096 to send or receive packets,
117  * but please keep in mind that the `pkt_size` option limits the packet size to 1400.
118  */
119 #define MAX_UDP_BUFFER_SIZE 4096
120 
121 /* Referring to Chrome's definition of RTP payload types. */
122 #define WHIP_RTP_PAYLOAD_TYPE_H264 106
123 #define WHIP_RTP_PAYLOAD_TYPE_OPUS 111
124 
125 /**
126  * The STUN message header, which is 20 bytes long, comprises the
127  * STUNMessageType (1B), MessageLength (2B), MagicCookie (4B),
128  * and TransactionID (12B).
129  * See https://datatracker.ietf.org/doc/html/rfc5389#section-6
130  */
131 #define ICE_STUN_HEADER_SIZE 20
132 
133 /**
134  * The RTP header is 12 bytes long, comprising the Version(1B), PT(1B),
135  * SequenceNumber(2B), Timestamp(4B), and SSRC(4B).
136  * See https://www.rfc-editor.org/rfc/rfc3550#section-5.1
137  */
138 #define WHIP_RTP_HEADER_SIZE 12
139 
140 /**
141  * For RTCP, PT is [128, 223] (or without marker [0, 95]). Literally, RTCP starts
142  * from 64 not 0, so PT is [192, 223] (or without marker [64, 95]), see "RTCP Control
143  * Packet Types (PT)" at
144  * https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-4
145  *
146  * For RTP, the PT is [96, 127], or [224, 255] with marker. See "RTP Payload Types (PT)
147  * for standard audio and video encodings" at
148  * https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-1
149  */
150 #define WHIP_RTCP_PT_START 192
151 #define WHIP_RTCP_PT_END 223
152 
153 /**
154  * In the case of ICE-LITE, these fields are not used; instead, they are defined
155  * as constant values.
156  */
157 #define WHIP_SDP_SESSION_ID "4489045141692799359"
158 #define WHIP_SDP_CREATOR_IP "127.0.0.1"
159 
160 /* Calculate the elapsed time from starttime to endtime in milliseconds. */
161 #define ELAPSED(starttime, endtime) ((float)(endtime - starttime) / 1000)
162 
163 /* STUN Attribute, comprehension-required range (0x0000-0x7FFF) */
164 enum STUNAttr {
165  STUN_ATTR_USERNAME = 0x0006, /// shared secret response/bind request
166  STUN_ATTR_PRIORITY = 0x0024, /// must be included in a Binding request
167  STUN_ATTR_USE_CANDIDATE = 0x0025, /// bind request
168  STUN_ATTR_MESSAGE_INTEGRITY = 0x0008, /// bind request/response
169  STUN_ATTR_FINGERPRINT = 0x8028, /// rfc5389
170  STUN_ATTR_ICE_CONTROLLING = 0x802A, /// ICE controlling role
171 };
172 
173 enum WHIPState {
175 
176  /* The initial state. */
178  /* The muxer has sent the offer to the peer. */
180  /* The muxer has received the answer from the peer. */
182  /**
183  * After parsing the answer received from the peer, the muxer negotiates the abilities
184  * in the offer that it generated.
185  */
187  /* The muxer has connected to the peer via UDP. */
189  /* The muxer has sent the ICE request to the peer. */
191  /* The muxer has received the ICE response from the peer. */
193  /* The muxer starts attempting the DTLS handshake. */
195  /* The muxer has finished the DTLS handshake with the peer. */
197  /* The muxer has finished the SRTP setup. */
199  /* The muxer is ready to send/receive media frames. */
201  /* The muxer is failed. */
203 };
204 
205 typedef struct WHIPContext {
207 
208  /* The state of the RTC connection. */
210 
211  /* Parameters for the input audio and video codecs. */
214 
215  /**
216  * The h264_mp4toannexb Bitstream Filter (BSF) bypasses the AnnexB packet;
217  * therefore, it is essential to insert the SPS and PPS before each IDR frame
218  * in such cases.
219  */
221 
222  /* The random number generator. */
224 
225  /* The ICE username and pwd fragment generated by the muxer. */
227  char ice_pwd_local[33];
228  /* The SSRC of the audio and video stream, generated by the muxer. */
229  uint32_t audio_ssrc;
230  uint32_t video_ssrc;
231 
232  uint16_t audio_first_seq;
233  uint16_t video_first_seq;
234  /* The PT(Payload Type) of stream, generated by the muxer. */
237  /**
238  * This is the SDP offer generated by the muxer based on the codec parameters,
239  * DTLS, and ICE information.
240  */
241  char *sdp_offer;
242 
243  uint64_t ice_tie_breaker; // random 64 bit, for ICE-CONTROLLING
244  /* The ICE username and pwd from remote server. */
247  /**
248  * This represents the ICE candidate protocol, priority, host and port.
249  * Currently, we only support one candidate and choose the first UDP candidate.
250  * However, we plan to support multiple candidates in the future.
251  */
253  char *ice_host;
254  int ice_port;
255 
256  /* The SDP answer received from the WebRTC server. */
257  char *sdp_answer;
258  /* The resource URL returned in the Location header of WHIP HTTP response. */
260 
261  /* These variables represent timestamps used for calculating and tracking the cost. */
270 
271  /* The certificate and private key content used for DTLS handshake */
274  /* The fingerprint of certificate, used in SDP offer. */
276  /**
277  * This represents the material used to build the SRTP master key. It is
278  * generated by DTLS and has the following layout:
279  * 16B 16B 14B 14B
280  * client_key | server_key | client_salt | server_salt
281  */
283 
284  char ssl_error_message[256];
285 
286  /* TODO: Use AVIOContext instead of URLContext */
288 
289  /* The SRTP send context, to encrypt outgoing packets. */
293  /* The SRTP receive context, to decrypt incoming packets. */
295 
296  /* The UDP transport is used for delivering ICE, DTLS and SRTP packets. */
298  /* The buffer for UDP transmission. */
300 
301  /* The timeout in milliseconds for ICE and DTLS handshake. */
303  /**
304  * The size of RTP packet, should generally be set to MTU.
305  * Note that pion requires a smaller value, for example, 1200.
306  */
307  int pkt_size;
308  /**
309  * The optional Bearer token for WHIP Authorization.
310  * See https://www.ietf.org/archive/id/draft-ietf-wish-whip-08.html#name-authentication-and-authoriz
311  */
313  /* The certificate and private key used for DTLS handshake. */
314  char* cert_file;
315  char* key_file;
316 } WHIPContext;
317 
318 /**
319  * Whether the packet is a DTLS packet.
320  */
321 static int is_dtls_packet(uint8_t *b, int size) {
322  uint16_t version = AV_RB16(&b[1]);
326 }
327 
328 
329 /**
330  * Get or Generate a self-signed certificate and private key for DTLS,
331  * fingerprint for SDP
332  */
334 {
335  int ret = 0;
336  WHIPContext *whip = s->priv_data;
337 
338  if (whip->cert_file && whip->key_file) {
339  /* Read the private key and certificate from the file. */
340  if ((ret = ff_ssl_read_key_cert(whip->key_file, whip->cert_file,
341  whip->key_buf, sizeof(whip->key_buf),
342  whip->cert_buf, sizeof(whip->cert_buf),
343  &whip->dtls_fingerprint)) < 0) {
344  av_log(s, AV_LOG_ERROR, "Failed to read DTLS certificate from cert=%s, key=%s\n",
345  whip->cert_file, whip->key_file);
346  return ret;
347  }
348  } else {
349  /* Generate a private key to ctx->dtls_pkey and self-signed certificate. */
350  if ((ret = ff_ssl_gen_key_cert(whip->key_buf, sizeof(whip->key_buf),
351  whip->cert_buf, sizeof(whip->cert_buf),
352  &whip->dtls_fingerprint)) < 0) {
353  av_log(s, AV_LOG_ERROR, "Failed to generate DTLS private key and certificate\n");
354  return ret;
355  }
356  }
357 
358  return ret;
359 }
360 
362 {
363  WHIPContext *whip = s->priv_data;
364  /* reuse the udp created by whip */
365  ff_tls_set_external_socket(whip->dtls_uc, whip->udp);
366 
367  /* Make the socket non-blocking */
369  whip->dtls_uc->flags |= AVIO_FLAG_NONBLOCK;
370 
371  return 0;
372 }
373 
374 /**
375  * Initialize and check the options for the WebRTC muxer.
376  */
378 {
379  int ret, ideal_pkt_size = 532;
380  WHIPContext *whip = s->priv_data;
381  uint32_t seed;
382 
384 
386  if (ret < 0) {
387  av_log(whip, AV_LOG_ERROR, "Failed to init certificate and key\n");
388  return ret;
389  }
390 
391  /* Initialize the random number generator. */
393  av_lfg_init(&whip->rnd, seed);
394 
395  /* 64 bit tie breaker for ICE-CONTROLLING (RFC 8445 16.1) */
396  ret = av_random_bytes((uint8_t *)&whip->ice_tie_breaker, sizeof(whip->ice_tie_breaker));
397  if (ret < 0) {
398  av_log(whip, AV_LOG_ERROR, "Couldn't generate random bytes for ICE tie breaker\n");
399  return ret;
400  }
401 
402  whip->audio_first_seq = av_lfg_get(&whip->rnd) & 0x0fff;
403  whip->video_first_seq = whip->audio_first_seq + 1;
404 
405  if (whip->pkt_size < ideal_pkt_size)
406  av_log(whip, AV_LOG_WARNING, "pkt_size=%d(<%d) is too small, may cause packet loss\n",
407  whip->pkt_size, ideal_pkt_size);
408 
409  if (whip->state < WHIP_STATE_INIT)
410  whip->state = WHIP_STATE_INIT;
412  av_log(whip, AV_LOG_VERBOSE, "Init state=%d, handshake_timeout=%dms, pkt_size=%d, seed=%d, elapsed=%.2fms\n",
414 
415  return 0;
416 }
417 
418 /**
419  * When duplicating a stream, the demuxer has already set the extradata, profile, and
420  * level of the par. Keep in mind that this function will not be invoked since the
421  * profile and level are set.
422  *
423  * When utilizing an encoder, such as libx264, to encode a stream, the extradata in
424  * par->extradata contains the SPS, which includes profile and level information.
425  * However, the profile and level of par remain unspecified. Therefore, it is necessary
426  * to extract the profile and level data from the extradata and assign it to the par's
427  * profile and level. Keep in mind that AVFMT_GLOBALHEADER must be enabled; otherwise,
428  * the extradata will remain empty.
429  */
431 {
432  int ret = 0;
433  const uint8_t *r = par->extradata, *r1, *end = par->extradata + par->extradata_size;
434  H264SPS seq, *const sps = &seq;
435  uint32_t state;
436  WHIPContext *whip = s->priv_data;
437 
438  if (par->codec_id != AV_CODEC_ID_H264)
439  return ret;
440 
441  if (par->profile != AV_PROFILE_UNKNOWN && par->level != AV_LEVEL_UNKNOWN)
442  return ret;
443 
444  if (!par->extradata || par->extradata_size <= 0) {
445  av_log(whip, AV_LOG_ERROR, "Unable to parse profile from empty extradata=%p, size=%d\n",
446  par->extradata, par->extradata_size);
447  return AVERROR(EINVAL);
448  }
449 
450  while (1) {
451  r = avpriv_find_start_code(r, end, &state);
452  if (r >= end)
453  break;
454 
455  r1 = ff_nal_find_startcode(r, end);
456  if ((state & 0x1f) == H264_NAL_SPS) {
457  ret = ff_avc_decode_sps(sps, r, r1 - r);
458  if (ret < 0) {
459  av_log(whip, AV_LOG_ERROR, "Failed to decode SPS, state=%x, size=%d\n",
460  state, (int)(r1 - r));
461  return ret;
462  }
463 
464  av_log(whip, AV_LOG_VERBOSE, "Parse profile=%d, level=%d from SPS\n",
465  sps->profile_idc, sps->level_idc);
466  par->profile = sps->profile_idc;
467  par->level = sps->level_idc;
468  }
469 
470  r = r1;
471  }
472 
473  return ret;
474 }
475 
476 /**
477  * Parses video SPS/PPS from the extradata of codecpar and checks the codec.
478  * Currently only supports video(h264) and audio(opus). Note that only baseline
479  * and constrained baseline profiles of h264 are supported.
480  *
481  * If the profile is less than 0, the function considers the profile as baseline.
482  * It may need to parse the profile from SPS/PPS. This situation occurs when ingesting
483  * desktop and transcoding.
484  *
485  * @param s Pointer to the AVFormatContext
486  * @returns Returns 0 if successful or AVERROR_xxx in case of an error.
487  *
488  * TODO: FIXME: There is an issue with the timestamp of OPUS audio, especially when
489  * the input is an MP4 file. The timestamp deviates from the expected value of 960,
490  * causing Chrome to play the audio stream with noise. This problem can be replicated
491  * by transcoding a specific file into MP4 format and publishing it using the WHIP
492  * muxer. However, when directly transcoding and publishing through the WHIP muxer,
493  * the issue is not present, and the audio timestamp remains consistent. The root
494  * cause is still unknown, and this comment has been added to address this issue
495  * in the future. Further research is needed to resolve the problem.
496  */
498 {
499  int i, ret = 0;
500  WHIPContext *whip = s->priv_data;
501 
502  for (i = 0; i < s->nb_streams; i++) {
503  AVCodecParameters *par = s->streams[i]->codecpar;
505  switch (par->codec_type) {
506  case AVMEDIA_TYPE_VIDEO:
507  if (whip->video_par) {
508  av_log(whip, AV_LOG_ERROR, "Only one video stream is supported by RTC\n");
509  return AVERROR(EINVAL);
510  }
511  whip->video_par = par;
512 
513  if (par->codec_id != AV_CODEC_ID_H264) {
514  av_log(whip, AV_LOG_ERROR, "Unsupported video codec %s by RTC, choose h264\n",
515  desc ? desc->name : "unknown");
516  return AVERROR_PATCHWELCOME;
517  }
518 
519  if (par->video_delay > 0) {
520  av_log(whip, AV_LOG_ERROR, "Unsupported B frames by RTC\n");
521  return AVERROR_PATCHWELCOME;
522  }
523 
524  if ((ret = parse_profile_level(s, par)) < 0) {
525  av_log(whip, AV_LOG_ERROR, "Failed to parse SPS/PPS from extradata\n");
526  return AVERROR(EINVAL);
527  }
528 
529  if (par->profile == AV_PROFILE_UNKNOWN) {
530  av_log(whip, AV_LOG_WARNING, "No profile found in extradata, consider baseline\n");
531  return AVERROR(EINVAL);
532  }
533  if (par->level == AV_LEVEL_UNKNOWN) {
534  av_log(whip, AV_LOG_WARNING, "No level found in extradata, consider 3.1\n");
535  return AVERROR(EINVAL);
536  }
537  break;
538  case AVMEDIA_TYPE_AUDIO:
539  if (whip->audio_par) {
540  av_log(whip, AV_LOG_ERROR, "Only one audio stream is supported by RTC\n");
541  return AVERROR(EINVAL);
542  }
543  whip->audio_par = par;
544 
545  if (par->codec_id != AV_CODEC_ID_OPUS) {
546  av_log(whip, AV_LOG_ERROR, "Unsupported audio codec %s by RTC, choose opus\n",
547  desc ? desc->name : "unknown");
548  return AVERROR_PATCHWELCOME;
549  }
550 
551  if (par->ch_layout.nb_channels != 2) {
552  av_log(whip, AV_LOG_ERROR, "Unsupported audio channels %d by RTC, choose stereo\n",
553  par->ch_layout.nb_channels);
554  return AVERROR_PATCHWELCOME;
555  }
556 
557  if (par->sample_rate != 48000) {
558  av_log(whip, AV_LOG_ERROR, "Unsupported audio sample rate %d by RTC, choose 48000\n", par->sample_rate);
559  return AVERROR_PATCHWELCOME;
560  }
561  break;
562  default:
563  av_log(whip, AV_LOG_ERROR, "Codec type '%s' for stream %d is not supported by RTC\n",
565  return AVERROR_PATCHWELCOME;
566  }
567  }
568 
569  return ret;
570 }
571 
572 /**
573  * Generate SDP offer according to the codec parameters, DTLS and ICE information.
574  *
575  * Note that we don't use av_sdp_create to generate SDP offer because it doesn't
576  * support DTLS and ICE information.
577  *
578  * @return 0 if OK, AVERROR_xxx on error
579  */
581 {
582  int ret = 0, profile_idc = 0, level, profile_iop = 0;
583  const char *acodec_name = NULL, *vcodec_name = NULL;
584  AVBPrint bp;
585  WHIPContext *whip = s->priv_data;
586 
587  /* To prevent a crash during cleanup, always initialize it. */
588  av_bprint_init(&bp, 1, MAX_SDP_SIZE);
589 
590  if (whip->sdp_offer) {
591  av_log(whip, AV_LOG_ERROR, "SDP offer is already set\n");
592  ret = AVERROR(EINVAL);
593  goto end;
594  }
595 
596  snprintf(whip->ice_ufrag_local, sizeof(whip->ice_ufrag_local), "%08x",
597  av_lfg_get(&whip->rnd));
598  snprintf(whip->ice_pwd_local, sizeof(whip->ice_pwd_local), "%08x%08x%08x%08x",
599  av_lfg_get(&whip->rnd), av_lfg_get(&whip->rnd), av_lfg_get(&whip->rnd),
600  av_lfg_get(&whip->rnd));
601 
602  whip->audio_ssrc = av_lfg_get(&whip->rnd);
603  whip->video_ssrc = whip->audio_ssrc + 1;
604 
607 
608  av_bprintf(&bp, ""
609  "v=0\r\n"
610  "o=FFmpeg %s 2 IN IP4 %s\r\n"
611  "s=FFmpegPublishSession\r\n"
612  "t=0 0\r\n"
613  "a=group:BUNDLE 0 1\r\n"
614  "a=extmap-allow-mixed\r\n"
615  "a=msid-semantic: WMS\r\n",
618 
619  if (whip->audio_par) {
620  if (whip->audio_par->codec_id == AV_CODEC_ID_OPUS)
621  acodec_name = "opus";
622 
623  av_bprintf(&bp, ""
624  "m=audio 9 UDP/TLS/RTP/SAVPF %u\r\n"
625  "c=IN IP4 0.0.0.0\r\n"
626  "a=ice-ufrag:%s\r\n"
627  "a=ice-pwd:%s\r\n"
628  "a=fingerprint:sha-256 %s\r\n"
629  "a=setup:passive\r\n"
630  "a=mid:0\r\n"
631  "a=sendonly\r\n"
632  "a=msid:FFmpeg audio\r\n"
633  "a=rtcp-mux\r\n"
634  "a=rtpmap:%u %s/%d/%d\r\n"
635  "a=ssrc:%u cname:FFmpeg\r\n"
636  "a=ssrc:%u msid:FFmpeg audio\r\n",
637  whip->audio_payload_type,
638  whip->ice_ufrag_local,
639  whip->ice_pwd_local,
640  whip->dtls_fingerprint,
641  whip->audio_payload_type,
642  acodec_name,
643  whip->audio_par->sample_rate,
645  whip->audio_ssrc,
646  whip->audio_ssrc);
647  }
648 
649  if (whip->video_par) {
650  level = whip->video_par->level;
651  if (whip->video_par->codec_id == AV_CODEC_ID_H264) {
652  vcodec_name = "H264";
653  profile_iop |= whip->video_par->profile & AV_PROFILE_H264_CONSTRAINED ? 1 << 6 : 0;
654  profile_iop |= whip->video_par->profile & AV_PROFILE_H264_INTRA ? 1 << 4 : 0;
655  profile_idc = whip->video_par->profile & 0x00ff;
656  }
657 
658  av_bprintf(&bp, ""
659  "m=video 9 UDP/TLS/RTP/SAVPF %u\r\n"
660  "c=IN IP4 0.0.0.0\r\n"
661  "a=ice-ufrag:%s\r\n"
662  "a=ice-pwd:%s\r\n"
663  "a=fingerprint:sha-256 %s\r\n"
664  "a=setup:passive\r\n"
665  "a=mid:1\r\n"
666  "a=sendonly\r\n"
667  "a=msid:FFmpeg video\r\n"
668  "a=rtcp-mux\r\n"
669  "a=rtcp-rsize\r\n"
670  "a=rtpmap:%u %s/90000\r\n"
671  "a=fmtp:%u level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=%02x%02x%02x\r\n"
672  "a=ssrc:%u cname:FFmpeg\r\n"
673  "a=ssrc:%u msid:FFmpeg video\r\n",
674  whip->video_payload_type,
675  whip->ice_ufrag_local,
676  whip->ice_pwd_local,
677  whip->dtls_fingerprint,
678  whip->video_payload_type,
679  vcodec_name,
680  whip->video_payload_type,
681  profile_idc,
682  profile_iop,
683  level,
684  whip->video_ssrc,
685  whip->video_ssrc);
686  }
687 
688  if (!av_bprint_is_complete(&bp)) {
689  av_log(whip, AV_LOG_ERROR, "Offer exceed max %d, %s\n", MAX_SDP_SIZE, bp.str);
690  ret = AVERROR(EIO);
691  goto end;
692  }
693 
694  whip->sdp_offer = av_strdup(bp.str);
695  if (!whip->sdp_offer) {
696  ret = AVERROR(ENOMEM);
697  goto end;
698  }
699 
700  if (whip->state < WHIP_STATE_OFFER)
701  whip->state = WHIP_STATE_OFFER;
703  av_log(whip, AV_LOG_VERBOSE, "Generated state=%d, offer: %s\n", whip->state, whip->sdp_offer);
704 
705 end:
706  av_bprint_finalize(&bp, NULL);
707  return ret;
708 }
709 
710 /**
711  * Exchange SDP offer with WebRTC peer to get the answer.
712  *
713  * @return 0 if OK, AVERROR_xxx on error
714  */
716 {
717  int ret;
718  char buf[MAX_URL_SIZE];
719  AVBPrint bp;
720  WHIPContext *whip = s->priv_data;
721  /* The URL context is an HTTP transport layer for the WHIP protocol. */
722  URLContext *whip_uc = NULL;
724  char *hex_data = NULL;
725  const char *proto_name = avio_find_protocol_name(s->url);
726 
727  /* To prevent a crash during cleanup, always initialize it. */
728  av_bprint_init(&bp, 1, MAX_SDP_SIZE);
729 
730  if (!av_strstart(proto_name, "http", NULL)) {
731  av_log(whip, AV_LOG_ERROR, "Protocol %s is not supported by RTC, choose http, url is %s\n",
732  proto_name, s->url);
733  ret = AVERROR(EINVAL);
734  goto end;
735  }
736 
737  if (!whip->sdp_offer || !strlen(whip->sdp_offer)) {
738  av_log(whip, AV_LOG_ERROR, "No offer to exchange\n");
739  ret = AVERROR(EINVAL);
740  goto end;
741  }
742 
743  ret = snprintf(buf, sizeof(buf), "Cache-Control: no-cache\r\nContent-Type: application/sdp\r\n");
744  if (whip->authorization)
745  ret += snprintf(buf + ret, sizeof(buf) - ret, "Authorization: Bearer %s\r\n", whip->authorization);
746  if (ret <= 0 || ret >= sizeof(buf)) {
747  av_log(whip, AV_LOG_ERROR, "Failed to generate headers, size=%d, %s\n", ret, buf);
748  ret = AVERROR(EINVAL);
749  goto end;
750  }
751 
752  av_dict_set(&opts, "headers", buf, 0);
753  av_dict_set_int(&opts, "chunked_post", 0, 0);
754 
755  hex_data = av_mallocz(2 * strlen(whip->sdp_offer) + 1);
756  if (!hex_data) {
757  ret = AVERROR(ENOMEM);
758  goto end;
759  }
760  ff_data_to_hex(hex_data, whip->sdp_offer, strlen(whip->sdp_offer), 0);
761  av_dict_set(&opts, "post_data", hex_data, 0);
762 
763  ret = ffurl_open_whitelist(&whip_uc, s->url, AVIO_FLAG_READ_WRITE, &s->interrupt_callback,
764  &opts, s->protocol_whitelist, s->protocol_blacklist, NULL);
765  if (ret < 0) {
766  av_log(whip, AV_LOG_ERROR, "Failed to request url=%s, offer: %s\n", s->url, whip->sdp_offer);
767  goto end;
768  }
769 
770  if (ff_http_get_new_location(whip_uc)) {
772  if (!whip->whip_resource_url) {
773  ret = AVERROR(ENOMEM);
774  goto end;
775  }
776  }
777 
778  while (1) {
779  ret = ffurl_read(whip_uc, buf, sizeof(buf));
780  if (ret == AVERROR_EOF) {
781  /* Reset the error because we read all response as answer util EOF. */
782  ret = 0;
783  break;
784  }
785  if (ret <= 0) {
786  av_log(whip, AV_LOG_ERROR, "Failed to read response from url=%s, offer is %s, answer is %s\n",
787  s->url, whip->sdp_offer, whip->sdp_answer);
788  goto end;
789  }
790 
791  av_bprintf(&bp, "%.*s", ret, buf);
792  if (!av_bprint_is_complete(&bp)) {
793  av_log(whip, AV_LOG_ERROR, "Answer exceed max size %d, %.*s, %s\n", MAX_SDP_SIZE, ret, buf, bp.str);
794  ret = AVERROR(EIO);
795  goto end;
796  }
797  }
798 
799  if (!av_strstart(bp.str, "v=", NULL)) {
800  av_log(whip, AV_LOG_ERROR, "Invalid answer: %s\n", bp.str);
801  ret = AVERROR(EINVAL);
802  goto end;
803  }
804 
805  whip->sdp_answer = av_strdup(bp.str);
806  if (!whip->sdp_answer) {
807  ret = AVERROR(ENOMEM);
808  goto end;
809  }
810 
811  if (whip->state < WHIP_STATE_ANSWER)
812  whip->state = WHIP_STATE_ANSWER;
813  av_log(whip, AV_LOG_VERBOSE, "Got state=%d, answer: %s\n", whip->state, whip->sdp_answer);
814 
815 end:
816  ffurl_closep(&whip_uc);
817  av_bprint_finalize(&bp, NULL);
818  av_dict_free(&opts);
819  av_freep(&hex_data);
820  return ret;
821 }
822 
823 /**
824  * Parses the ICE ufrag, pwd, and candidates from the SDP answer.
825  *
826  * This function is used to extract the ICE ufrag, pwd, and candidates from the SDP answer.
827  * It returns an error if any of these fields is NULL. The function only uses the first
828  * candidate if there are multiple candidates. However, support for multiple candidates
829  * will be added in the future.
830  *
831  * @param s Pointer to the AVFormatContext
832  * @returns Returns 0 if successful or AVERROR_xxx if an error occurs.
833  */
835 {
836  int ret = 0;
837  AVIOContext *pb;
838  char line[MAX_URL_SIZE];
839  const char *ptr;
840  int i;
841  WHIPContext *whip = s->priv_data;
842 
843  if (!whip->sdp_answer || !strlen(whip->sdp_answer)) {
844  av_log(whip, AV_LOG_ERROR, "No answer to parse\n");
845  ret = AVERROR(EINVAL);
846  goto end;
847  }
848 
849  pb = avio_alloc_context(whip->sdp_answer, strlen(whip->sdp_answer), 0, NULL, NULL, NULL, NULL);
850  if (!pb)
851  return AVERROR(ENOMEM);
852 
853  for (i = 0; !avio_feof(pb); i++) {
854  ff_get_chomp_line(pb, line, sizeof(line));
855  if (av_strstart(line, "a=ice-ufrag:", &ptr) && !whip->ice_ufrag_remote) {
856  whip->ice_ufrag_remote = av_strdup(ptr);
857  if (!whip->ice_ufrag_remote) {
858  ret = AVERROR(ENOMEM);
859  goto end;
860  }
861  } else if (av_strstart(line, "a=ice-pwd:", &ptr) && !whip->ice_pwd_remote) {
862  whip->ice_pwd_remote = av_strdup(ptr);
863  if (!whip->ice_pwd_remote) {
864  ret = AVERROR(ENOMEM);
865  goto end;
866  }
867  } else if (av_strstart(line, "a=candidate:", &ptr) && !whip->ice_protocol) {
868  if (ptr && av_stristr(ptr, "host")) {
869  /* Refer to RFC 5245 15.1 */
870  char foundation[33], protocol[17], host[129];
871  int component_id, priority, port;
872  ret = sscanf(ptr, "%32s %d %16s %d %128s %d typ host", foundation, &component_id, protocol, &priority, host, &port);
873  if (ret != 6) {
874  av_log(whip, AV_LOG_ERROR, "Failed %d to parse line %d %s from %s\n",
875  ret, i, line, whip->sdp_answer);
876  ret = AVERROR(EIO);
877  goto end;
878  }
879 
880  if (av_strcasecmp(protocol, "udp")) {
881  av_log(whip, AV_LOG_ERROR, "Protocol %s is not supported by RTC, choose udp, line %d %s of %s\n",
882  protocol, i, line, whip->sdp_answer);
883  ret = AVERROR(EIO);
884  goto end;
885  }
886 
887  whip->ice_protocol = av_strdup(protocol);
888  whip->ice_host = av_strdup(host);
889  whip->ice_port = port;
890  if (!whip->ice_protocol || !whip->ice_host) {
891  ret = AVERROR(ENOMEM);
892  goto end;
893  }
894  }
895  }
896  }
897 
898  if (!whip->ice_pwd_remote || !strlen(whip->ice_pwd_remote)) {
899  av_log(whip, AV_LOG_ERROR, "No remote ice pwd parsed from %s\n", whip->sdp_answer);
900  ret = AVERROR(EINVAL);
901  goto end;
902  }
903 
904  if (!whip->ice_ufrag_remote || !strlen(whip->ice_ufrag_remote)) {
905  av_log(whip, AV_LOG_ERROR, "No remote ice ufrag parsed from %s\n", whip->sdp_answer);
906  ret = AVERROR(EINVAL);
907  goto end;
908  }
909 
910  if (!whip->ice_protocol || !whip->ice_host || !whip->ice_port) {
911  av_log(whip, AV_LOG_ERROR, "No ice candidate parsed from %s\n", whip->sdp_answer);
912  ret = AVERROR(EINVAL);
913  goto end;
914  }
915 
916  if (whip->state < WHIP_STATE_NEGOTIATED)
919  av_log(whip, AV_LOG_VERBOSE, "SDP state=%d, offer=%zuB, answer=%zuB, ufrag=%s, pwd=%zuB, transport=%s://%s:%d, elapsed=%.2fms\n",
920  whip->state, strlen(whip->sdp_offer), strlen(whip->sdp_answer), whip->ice_ufrag_remote, strlen(whip->ice_pwd_remote),
922 
923 end:
924  avio_context_free(&pb);
925  return ret;
926 }
927 
928 /**
929  * Creates and marshals an ICE binding request packet.
930  *
931  * This function creates and marshals an ICE binding request packet. The function only
932  * generates the username attribute and does not include goog-network-info,
933  * use-candidate. However, some of these attributes may be added in the future.
934  *
935  * @param s Pointer to the AVFormatContext
936  * @param buf Pointer to memory buffer to store the request packet
937  * @param buf_size Size of the memory buffer
938  * @param request_size Pointer to an integer that receives the size of the request packet
939  * @return Returns 0 if successful or AVERROR_xxx if an error occurs.
940  */
941 static int ice_create_request(AVFormatContext *s, uint8_t *buf, int buf_size, int *request_size)
942 {
943  int ret, size, crc32;
944  char username[128];
945  AVIOContext *pb = NULL;
946  AVHMAC *hmac = NULL;
947  WHIPContext *whip = s->priv_data;
948 
949  pb = avio_alloc_context(buf, buf_size, 1, NULL, NULL, NULL, NULL);
950  if (!pb)
951  return AVERROR(ENOMEM);
952 
953  hmac = av_hmac_alloc(AV_HMAC_SHA1);
954  if (!hmac) {
955  ret = AVERROR(ENOMEM);
956  goto end;
957  }
958 
959  /* Write 20 bytes header */
960  avio_wb16(pb, 0x0001); /* STUN binding request */
961  avio_wb16(pb, 0); /* length */
962  avio_wb32(pb, STUN_MAGIC_COOKIE); /* magic cookie */
963  avio_wb32(pb, av_lfg_get(&whip->rnd)); /* transaction ID */
964  avio_wb32(pb, av_lfg_get(&whip->rnd)); /* transaction ID */
965  avio_wb32(pb, av_lfg_get(&whip->rnd)); /* transaction ID */
966 
967  /* The username is the concatenation of the two ICE ufrag */
968  ret = snprintf(username, sizeof(username), "%s:%s", whip->ice_ufrag_remote, whip->ice_ufrag_local);
969  if (ret <= 0 || ret >= sizeof(username)) {
970  av_log(whip, AV_LOG_ERROR, "Failed to build username %s:%s, max=%zu, ret=%d\n",
971  whip->ice_ufrag_remote, whip->ice_ufrag_local, sizeof(username), ret);
972  ret = AVERROR(EIO);
973  goto end;
974  }
975 
976  /* Write the username attribute */
977  avio_wb16(pb, STUN_ATTR_USERNAME); /* attribute type username */
978  avio_wb16(pb, ret); /* size of username */
979  avio_write(pb, username, ret); /* bytes of username */
980  ffio_fill(pb, 0, (4 - (ret % 4)) % 4); /* padding */
981 
982  /* Write the use-candidate attribute */
983  avio_wb16(pb, STUN_ATTR_USE_CANDIDATE); /* attribute type use-candidate */
984  avio_wb16(pb, 0); /* size of use-candidate */
985 
987  avio_wb16(pb, 4);
989 
991  avio_wb16(pb, 8);
992  avio_wb64(pb, whip->ice_tie_breaker);
993 
994  /* Build and update message integrity */
995  avio_wb16(pb, STUN_ATTR_MESSAGE_INTEGRITY); /* attribute type message integrity */
996  avio_wb16(pb, 20); /* size of message integrity */
997  ffio_fill(pb, 0, 20); /* fill with zero to directly write and skip it */
998  size = avio_tell(pb);
999  buf[2] = (size - 20) >> 8;
1000  buf[3] = (size - 20) & 0xFF;
1001  av_hmac_init(hmac, whip->ice_pwd_remote, strlen(whip->ice_pwd_remote));
1002  av_hmac_update(hmac, buf, size - 24);
1003  av_hmac_final(hmac, buf + size - 20, 20);
1004 
1005  /* Write the fingerprint attribute */
1006  avio_wb16(pb, STUN_ATTR_FINGERPRINT); /* attribute type fingerprint */
1007  avio_wb16(pb, 4); /* size of fingerprint */
1008  ffio_fill(pb, 0, 4); /* fill with zero to directly write and skip it */
1009  size = avio_tell(pb);
1010  buf[2] = (size - 20) >> 8;
1011  buf[3] = (size - 20) & 0xFF;
1012  /* Refer to the av_hash_alloc("CRC32"), av_hash_init and av_hash_final */
1013  crc32 = av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), 0xFFFFFFFF, buf, size - 8) ^ 0xFFFFFFFF;
1014  avio_skip(pb, -4);
1015  avio_wb32(pb, crc32 ^ 0x5354554E); /* xor with "STUN" */
1016 
1017  *request_size = size;
1018 
1019 end:
1020  avio_context_free(&pb);
1021  av_hmac_free(hmac);
1022  return ret;
1023 }
1024 
1025 /**
1026  * Create an ICE binding response.
1027  *
1028  * This function generates an ICE binding response and writes it to the provided
1029  * buffer. The response is signed using the local password for message integrity.
1030  *
1031  * @param s Pointer to the AVFormatContext structure.
1032  * @param tid Pointer to the transaction ID of the binding request. The tid_size should be 12.
1033  * @param tid_size The size of the transaction ID, should be 12.
1034  * @param buf Pointer to the buffer where the response will be written.
1035  * @param buf_size The size of the buffer provided for the response.
1036  * @param response_size Pointer to an integer that will store the size of the generated response.
1037  * @return Returns 0 if successful or AVERROR_xxx if an error occurs.
1038  */
1039 static int ice_create_response(AVFormatContext *s, char *tid, int tid_size, uint8_t *buf, int buf_size, int *response_size)
1040 {
1041  int ret = 0, size, crc32;
1042  AVIOContext *pb = NULL;
1043  AVHMAC *hmac = NULL;
1044  WHIPContext *whip = s->priv_data;
1045 
1046  if (tid_size != 12) {
1047  av_log(whip, AV_LOG_ERROR, "Invalid transaction ID size. Expected 12, got %d\n", tid_size);
1048  return AVERROR(EINVAL);
1049  }
1050 
1051  pb = avio_alloc_context(buf, buf_size, 1, NULL, NULL, NULL, NULL);
1052  if (!pb)
1053  return AVERROR(ENOMEM);
1054 
1055  hmac = av_hmac_alloc(AV_HMAC_SHA1);
1056  if (!hmac) {
1057  ret = AVERROR(ENOMEM);
1058  goto end;
1059  }
1060 
1061  /* Write 20 bytes header */
1062  avio_wb16(pb, 0x0101); /* STUN binding response */
1063  avio_wb16(pb, 0); /* length */
1064  avio_wb32(pb, STUN_MAGIC_COOKIE); /* magic cookie */
1065  avio_write(pb, tid, tid_size); /* transaction ID */
1066 
1067  /* Build and update message integrity */
1068  avio_wb16(pb, STUN_ATTR_MESSAGE_INTEGRITY); /* attribute type message integrity */
1069  avio_wb16(pb, 20); /* size of message integrity */
1070  ffio_fill(pb, 0, 20); /* fill with zero to directly write and skip it */
1071  size = avio_tell(pb);
1072  buf[2] = (size - 20) >> 8;
1073  buf[3] = (size - 20) & 0xFF;
1074  av_hmac_init(hmac, whip->ice_pwd_local, strlen(whip->ice_pwd_local));
1075  av_hmac_update(hmac, buf, size - 24);
1076  av_hmac_final(hmac, buf + size - 20, 20);
1077 
1078  /* Write the fingerprint attribute */
1079  avio_wb16(pb, STUN_ATTR_FINGERPRINT); /* attribute type fingerprint */
1080  avio_wb16(pb, 4); /* size of fingerprint */
1081  ffio_fill(pb, 0, 4); /* fill with zero to directly write and skip it */
1082  size = avio_tell(pb);
1083  buf[2] = (size - 20) >> 8;
1084  buf[3] = (size - 20) & 0xFF;
1085  /* Refer to the av_hash_alloc("CRC32"), av_hash_init and av_hash_final */
1086  crc32 = av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), 0xFFFFFFFF, buf, size - 8) ^ 0xFFFFFFFF;
1087  avio_skip(pb, -4);
1088  avio_wb32(pb, crc32 ^ 0x5354554E); /* xor with "STUN" */
1089 
1090  *response_size = size;
1091 
1092 end:
1093  avio_context_free(&pb);
1094  av_hmac_free(hmac);
1095  return ret;
1096 }
1097 
1098 /**
1099  * A Binding request has class=0b00 (request) and method=0b000000000001 (Binding)
1100  * and is encoded into the first 16 bits as 0x0001.
1101  * See https://datatracker.ietf.org/doc/html/rfc5389#section-6
1102  */
1103 static int ice_is_binding_request(uint8_t *b, int size)
1104 {
1105  return size >= ICE_STUN_HEADER_SIZE && AV_RB16(&b[0]) == 0x0001;
1106 }
1107 
1108 /**
1109  * A Binding response has class=0b10 (success response) and method=0b000000000001,
1110  * and is encoded into the first 16 bits as 0x0101.
1111  */
1112 static int ice_is_binding_response(uint8_t *b, int size)
1113 {
1114  return size >= ICE_STUN_HEADER_SIZE && AV_RB16(&b[0]) == 0x0101;
1115 }
1116 
1117 /**
1118  * In RTP packets, the first byte is represented as 0b10xxxxxx, where the initial
1119  * two bits (0b10) indicate the RTP version,
1120  * see https://www.rfc-editor.org/rfc/rfc3550#section-5.1
1121  * The RTCP packet header is similar to RTP,
1122  * see https://www.rfc-editor.org/rfc/rfc3550#section-6.4.1
1123  */
1124 static int media_is_rtp_rtcp(const uint8_t *b, int size)
1125 {
1126  return size >= WHIP_RTP_HEADER_SIZE && (b[0] & 0xC0) == 0x80;
1127 }
1128 
1129 /* Whether the packet is RTCP. */
1130 static int media_is_rtcp(const uint8_t *b, int size)
1131 {
1132  return size >= WHIP_RTP_HEADER_SIZE && b[1] >= WHIP_RTCP_PT_START && b[1] <= WHIP_RTCP_PT_END;
1133 }
1134 
1135 /**
1136  * This function handles incoming binding request messages by responding to them.
1137  * If the message is not a binding request, it will be ignored.
1138  */
1139 static int ice_handle_binding_request(AVFormatContext *s, char *buf, int buf_size)
1140 {
1141  int ret = 0, size;
1142  char tid[12];
1143  WHIPContext *whip = s->priv_data;
1144 
1145  /* Ignore if not a binding request. */
1146  if (!ice_is_binding_request(buf, buf_size))
1147  return ret;
1148 
1149  if (buf_size < ICE_STUN_HEADER_SIZE) {
1150  av_log(whip, AV_LOG_ERROR, "Invalid STUN message, expected at least %d, got %d\n",
1151  ICE_STUN_HEADER_SIZE, buf_size);
1152  return AVERROR(EINVAL);
1153  }
1154 
1155  /* Parse transaction id from binding request in buf. */
1156  memcpy(tid, buf + 8, 12);
1157 
1158  /* Build the STUN binding response. */
1159  ret = ice_create_response(s, tid, sizeof(tid), whip->buf, sizeof(whip->buf), &size);
1160  if (ret < 0) {
1161  av_log(whip, AV_LOG_ERROR, "Failed to create STUN binding response, size=%d\n", size);
1162  return ret;
1163  }
1164 
1165  ret = ffurl_write(whip->udp, whip->buf, size);
1166  if (ret < 0) {
1167  av_log(whip, AV_LOG_ERROR, "Failed to send STUN binding response, size=%d\n", size);
1168  return ret;
1169  }
1170 
1171  return 0;
1172 }
1173 
1174 /**
1175  * To establish a connection with the UDP server, we utilize ICE-LITE in a Client-Server
1176  * mode. In this setup, FFmpeg acts as the UDP client, while the peer functions as the
1177  * UDP server.
1178  */
1180 {
1181  int ret = 0;
1182  char url[256];
1183  AVDictionary *opts = NULL;
1184  WHIPContext *whip = s->priv_data;
1185 
1186  /* Build UDP URL and create the UDP context as transport. */
1187  ff_url_join(url, sizeof(url), "udp", NULL, whip->ice_host, whip->ice_port, NULL);
1188 
1189  av_dict_set_int(&opts, "connect", 1, 0);
1190  av_dict_set_int(&opts, "fifo_size", 0, 0);
1191  /* Set the max packet size to the buffer size. */
1192  av_dict_set_int(&opts, "pkt_size", whip->pkt_size, 0);
1193 
1194  ret = ffurl_open_whitelist(&whip->udp, url, AVIO_FLAG_WRITE, &s->interrupt_callback,
1195  &opts, s->protocol_whitelist, s->protocol_blacklist, NULL);
1196  if (ret < 0) {
1197  av_log(whip, AV_LOG_ERROR, "Failed to connect udp://%s:%d\n", whip->ice_host, whip->ice_port);
1198  goto end;
1199  }
1200 
1201  /* Make the socket non-blocking, set to READ and WRITE mode after connected */
1204 
1205  if (whip->state < WHIP_STATE_UDP_CONNECTED)
1208  av_log(whip, AV_LOG_VERBOSE, "UDP state=%d, elapsed=%.2fms, connected to udp://%s:%d\n",
1209  whip->state, ELAPSED(whip->whip_starttime, av_gettime_relative()), whip->ice_host, whip->ice_port);
1210 
1211 end:
1212  av_dict_free(&opts);
1213  return ret;
1214 }
1215 
1217 {
1218  int ret = 0, size, i;
1219  int64_t starttime = av_gettime_relative(), now;
1220  WHIPContext *whip = s->priv_data;
1221  AVDictionary *opts = NULL;
1222  char buf[256], *cert_buf = NULL, *key_buf = NULL;
1223 
1224  if (whip->state < WHIP_STATE_UDP_CONNECTED || !whip->udp) {
1225  av_log(whip, AV_LOG_ERROR, "UDP not connected, state=%d, udp=%p\n", whip->state, whip->udp);
1226  return AVERROR(EINVAL);
1227  }
1228 
1229  while (1) {
1230  if (whip->state <= WHIP_STATE_ICE_CONNECTING) {
1231  /* Build the STUN binding request. */
1232  ret = ice_create_request(s, whip->buf, sizeof(whip->buf), &size);
1233  if (ret < 0) {
1234  av_log(whip, AV_LOG_ERROR, "Failed to create STUN binding request, size=%d\n", size);
1235  goto end;
1236  }
1237 
1238  ret = ffurl_write(whip->udp, whip->buf, size);
1239  if (ret < 0) {
1240  av_log(whip, AV_LOG_ERROR, "Failed to send STUN binding request, size=%d\n", size);
1241  goto end;
1242  }
1243 
1244  if (whip->state < WHIP_STATE_ICE_CONNECTING)
1246  }
1247 
1248 next_packet:
1249  if (whip->state >= WHIP_STATE_DTLS_FINISHED)
1250  /* DTLS handshake is done, exit the loop. */
1251  break;
1252 
1253  now = av_gettime_relative();
1254  if (now - starttime >= whip->handshake_timeout * 1000) {
1255  av_log(whip, AV_LOG_ERROR, "DTLS handshake timeout=%dms, cost=%.2fms, elapsed=%.2fms, state=%d\n",
1256  whip->handshake_timeout, ELAPSED(starttime, now), ELAPSED(whip->whip_starttime, now), whip->state);
1257  ret = AVERROR(ETIMEDOUT);
1258  goto end;
1259  }
1260 
1261  /* Read the STUN or DTLS messages from peer. */
1262  for (i = 0; i < ICE_DTLS_READ_INTERVAL / 5 && whip->state < WHIP_STATE_DTLS_CONNECTING; i++) {
1263  ret = ffurl_read(whip->udp, whip->buf, sizeof(whip->buf));
1264  if (ret > 0)
1265  break;
1266  if (ret == AVERROR(EAGAIN)) {
1267  av_usleep(5 * 1000);
1268  continue;
1269  }
1270  av_log(whip, AV_LOG_ERROR, "Failed to read message\n");
1271  goto end;
1272  }
1273 
1274  /* Got nothing, continue to process handshake. */
1275  if (ret <= 0 && whip->state < WHIP_STATE_DTLS_CONNECTING)
1276  continue;
1277 
1278  /* Handle the ICE binding response. */
1279  if (ice_is_binding_response(whip->buf, ret)) {
1280  if (whip->state < WHIP_STATE_ICE_CONNECTED) {
1283  av_log(whip, AV_LOG_VERBOSE, "ICE STUN ok, state=%d, url=udp://%s:%d, location=%s, username=%s:%s, res=%dB, elapsed=%.2fms\n",
1284  whip->state, whip->ice_host, whip->ice_port, whip->whip_resource_url ? whip->whip_resource_url : "",
1286 
1287  ff_url_join(buf, sizeof(buf), "dtls", NULL, whip->ice_host, whip->ice_port, NULL);
1288  av_dict_set_int(&opts, "mtu", whip->pkt_size, 0);
1289  if (whip->cert_file) {
1290  av_dict_set(&opts, "cert_file", whip->cert_file, 0);
1291  } else
1292  av_dict_set(&opts, "cert_pem", whip->cert_buf, 0);
1293 
1294  if (whip->key_file) {
1295  av_dict_set(&opts, "key_file", whip->key_file, 0);
1296  } else
1297  av_dict_set(&opts, "key_pem", whip->key_buf, 0);
1298  av_dict_set_int(&opts, "external_sock", 1, 0);
1299  av_dict_set_int(&opts, "use_srtp", 1, 0);
1300  av_dict_set_int(&opts, "listen", 1, 0);
1301  /* If got the first binding response, start DTLS handshake. */
1302  ret = ffurl_open_whitelist(&whip->dtls_uc, buf, AVIO_FLAG_READ_WRITE, &s->interrupt_callback,
1303  &opts, s->protocol_whitelist, s->protocol_blacklist, NULL);
1304  av_dict_free(&opts);
1305  if (ret < 0)
1306  goto end;
1307  dtls_initialize(s);
1308  }
1309  goto next_packet;
1310  }
1311 
1312  /* When a binding request is received, it is necessary to respond immediately. */
1313  if (ice_is_binding_request(whip->buf, ret)) {
1314  if ((ret = ice_handle_binding_request(s, whip->buf, ret)) < 0)
1315  goto end;
1316  goto next_packet;
1317  }
1318 
1319  /* If got any DTLS messages, handle it. */
1322  ret = ffurl_handshake(whip->dtls_uc);
1323  if (ret < 0) {
1324  whip->state = WHIP_STATE_FAILED;
1325  av_log(whip, AV_LOG_VERBOSE, "DTLS session failed\n");
1326  goto end;
1327  }
1328  if (!ret) {
1331  av_log(whip, AV_LOG_VERBOSE, "DTLS handshake is done, elapsed=%.2fms\n",
1332  ELAPSED(whip->whip_starttime, whip->whip_dtls_time));
1333  }
1334  goto next_packet;
1335  }
1336  }
1337 
1338 end:
1339  if (cert_buf)
1340  av_free(cert_buf);
1341  if (key_buf)
1342  av_free(key_buf);
1343  return ret;
1344 }
1345 
1346 /**
1347  * Establish the SRTP context using the keying material exported from DTLS.
1348  *
1349  * Create separate SRTP contexts for sending video and audio, as their sequences differ
1350  * and should not share a single context. Generate a single SRTP context for receiving
1351  * RTCP only.
1352  *
1353  * @return 0 if OK, AVERROR_xxx on error
1354  */
1356 {
1357  int ret;
1358  char recv_key[DTLS_SRTP_KEY_LEN + DTLS_SRTP_SALT_LEN];
1359  char send_key[DTLS_SRTP_KEY_LEN + DTLS_SRTP_SALT_LEN];
1361  /**
1362  * The profile for OpenSSL's SRTP is SRTP_AES128_CM_SHA1_80, see ssl/d1_srtp.c.
1363  * The profile for FFmpeg's SRTP is SRTP_AES128_CM_HMAC_SHA1_80, see libavformat/srtp.c.
1364  */
1365  const char* suite = "SRTP_AES128_CM_HMAC_SHA1_80";
1366  WHIPContext *whip = s->priv_data;
1368  if (ret < 0)
1369  goto end;
1370  /**
1371  * This represents the material used to build the SRTP master key. It is
1372  * generated by DTLS and has the following layout:
1373  * 16B 16B 14B 14B
1374  * client_key | server_key | client_salt | server_salt
1375  */
1376  char *client_key = whip->dtls_srtp_materials;
1377  char *server_key = whip->dtls_srtp_materials + DTLS_SRTP_KEY_LEN;
1378  char *client_salt = server_key + DTLS_SRTP_KEY_LEN;
1379  char *server_salt = client_salt + DTLS_SRTP_SALT_LEN;
1380 
1381  /* As DTLS server, the recv key is client master key plus salt. */
1382  memcpy(recv_key, client_key, DTLS_SRTP_KEY_LEN);
1383  memcpy(recv_key + DTLS_SRTP_KEY_LEN, client_salt, DTLS_SRTP_SALT_LEN);
1384 
1385  /* As DTLS server, the send key is server master key plus salt. */
1386  memcpy(send_key, server_key, DTLS_SRTP_KEY_LEN);
1387  memcpy(send_key + DTLS_SRTP_KEY_LEN, server_salt, DTLS_SRTP_SALT_LEN);
1388 
1389  /* Setup SRTP context for outgoing packets */
1390  if (!av_base64_encode(buf, sizeof(buf), send_key, sizeof(send_key))) {
1391  av_log(whip, AV_LOG_ERROR, "Failed to encode send key\n");
1392  ret = AVERROR(EIO);
1393  goto end;
1394  }
1395 
1396  ret = ff_srtp_set_crypto(&whip->srtp_audio_send, suite, buf);
1397  if (ret < 0) {
1398  av_log(whip, AV_LOG_ERROR, "Failed to set crypto for audio send\n");
1399  goto end;
1400  }
1401 
1402  ret = ff_srtp_set_crypto(&whip->srtp_video_send, suite, buf);
1403  if (ret < 0) {
1404  av_log(whip, AV_LOG_ERROR, "Failed to set crypto for video send\n");
1405  goto end;
1406  }
1407 
1408  ret = ff_srtp_set_crypto(&whip->srtp_rtcp_send, suite, buf);
1409  if (ret < 0) {
1410  av_log(whip, AV_LOG_ERROR, "Failed to set crypto for rtcp send\n");
1411  goto end;
1412  }
1413 
1414  /* Setup SRTP context for incoming packets */
1415  if (!av_base64_encode(buf, sizeof(buf), recv_key, sizeof(recv_key))) {
1416  av_log(whip, AV_LOG_ERROR, "Failed to encode recv key\n");
1417  ret = AVERROR(EIO);
1418  goto end;
1419  }
1420 
1421  ret = ff_srtp_set_crypto(&whip->srtp_recv, suite, buf);
1422  if (ret < 0) {
1423  av_log(whip, AV_LOG_ERROR, "Failed to set crypto for recv\n");
1424  goto end;
1425  }
1426 
1427  if (whip->state < WHIP_STATE_SRTP_FINISHED)
1430  av_log(whip, AV_LOG_VERBOSE, "SRTP setup done, state=%d, suite=%s, key=%zuB, elapsed=%.2fms\n",
1431  whip->state, suite, sizeof(send_key), ELAPSED(whip->whip_starttime, av_gettime_relative()));
1432 
1433 end:
1434  return ret;
1435 }
1436 
1437 /**
1438  * Callback triggered by the RTP muxer when it creates and sends out an RTP packet.
1439  *
1440  * This function modifies the video STAP packet, removing the markers, and updating the
1441  * NRI of the first NALU. Additionally, it uses the corresponding SRTP context to encrypt
1442  * the RTP packet, where the video packet is handled by the video SRTP context.
1443  */
1444 static int on_rtp_write_packet(void *opaque, const uint8_t *buf, int buf_size)
1445 {
1446  int ret, cipher_size, is_rtcp, is_video;
1447  uint8_t payload_type;
1448  AVFormatContext *s = opaque;
1449  WHIPContext *whip = s->priv_data;
1450  SRTPContext *srtp;
1451 
1452  /* Ignore if not RTP or RTCP packet. */
1453  if (!media_is_rtp_rtcp(buf, buf_size))
1454  return 0;
1455 
1456  /* Only support audio, video and rtcp. */
1457  is_rtcp = media_is_rtcp(buf, buf_size);
1458  payload_type = buf[1] & 0x7f;
1459  is_video = payload_type == whip->video_payload_type;
1460  if (!is_rtcp && payload_type != whip->video_payload_type && payload_type != whip->audio_payload_type)
1461  return 0;
1462 
1463  /* Get the corresponding SRTP context. */
1464  srtp = is_rtcp ? &whip->srtp_rtcp_send : (is_video? &whip->srtp_video_send : &whip->srtp_audio_send);
1465 
1466  /* Encrypt by SRTP and send out. */
1467  cipher_size = ff_srtp_encrypt(srtp, buf, buf_size, whip->buf, sizeof(whip->buf));
1468  if (cipher_size <= 0 || cipher_size < buf_size) {
1469  av_log(whip, AV_LOG_WARNING, "Failed to encrypt packet=%dB, cipher=%dB\n", buf_size, cipher_size);
1470  return 0;
1471  }
1472 
1473  ret = ffurl_write(whip->udp, whip->buf, cipher_size);
1474  if (ret < 0) {
1475  av_log(whip, AV_LOG_ERROR, "Failed to write packet=%dB, ret=%d\n", cipher_size, ret);
1476  return ret;
1477  }
1478 
1479  return ret;
1480 }
1481 
1482 /**
1483  * Creates dedicated RTP muxers for each stream in the AVFormatContext to build RTP
1484  * packets from the encoded frames.
1485  *
1486  * The corresponding SRTP context is utilized to encrypt each stream's RTP packets. For
1487  * example, a video SRTP context is used for the video stream. Additionally, the
1488  * "on_rtp_write_packet" callback function is set as the write function for each RTP
1489  * muxer to send out encrypted RTP packets.
1490  *
1491  * @return 0 if OK, AVERROR_xxx on error
1492  */
1494 {
1495  int ret, i, is_video, buffer_size, max_packet_size;
1496  AVFormatContext *rtp_ctx = NULL;
1497  AVDictionary *opts = NULL;
1498  uint8_t *buffer = NULL;
1499  char buf[64];
1500  WHIPContext *whip = s->priv_data;
1501  whip->udp->flags |= AVIO_FLAG_NONBLOCK;
1502 
1503  const AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
1504  if (!rtp_format) {
1505  av_log(whip, AV_LOG_ERROR, "Failed to guess rtp muxer\n");
1506  ret = AVERROR(ENOSYS);
1507  goto end;
1508  }
1509 
1510  /* The UDP buffer size, may greater than MTU. */
1511  buffer_size = MAX_UDP_BUFFER_SIZE;
1512  /* The RTP payload max size. Reserved some bytes for SRTP checksum and padding. */
1513  max_packet_size = whip->pkt_size - DTLS_SRTP_CHECKSUM_LEN;
1514 
1515  for (i = 0; i < s->nb_streams; i++) {
1516  rtp_ctx = avformat_alloc_context();
1517  if (!rtp_ctx) {
1518  ret = AVERROR(ENOMEM);
1519  goto end;
1520  }
1521 
1522  rtp_ctx->oformat = rtp_format;
1523  if (!avformat_new_stream(rtp_ctx, NULL)) {
1524  ret = AVERROR(ENOMEM);
1525  goto end;
1526  }
1527  /* Pass the interrupt callback on */
1528  rtp_ctx->interrupt_callback = s->interrupt_callback;
1529  /* Copy the max delay setting; the rtp muxer reads this. */
1530  rtp_ctx->max_delay = s->max_delay;
1531  /* Copy other stream parameters. */
1532  rtp_ctx->streams[0]->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio;
1533  rtp_ctx->flags |= s->flags & AVFMT_FLAG_BITEXACT;
1534  rtp_ctx->strict_std_compliance = s->strict_std_compliance;
1535 
1536  /* Set the synchronized start time. */
1537  rtp_ctx->start_time_realtime = s->start_time_realtime;
1538 
1539  avcodec_parameters_copy(rtp_ctx->streams[0]->codecpar, s->streams[i]->codecpar);
1540  rtp_ctx->streams[0]->time_base = s->streams[i]->time_base;
1541 
1542  /**
1543  * For H.264, consistently utilize the annexb format through the Bitstream Filter (BSF);
1544  * therefore, we deactivate the extradata detection for the RTP muxer.
1545  */
1546  if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_H264) {
1547  av_freep(&rtp_ctx->streams[i]->codecpar->extradata);
1548  rtp_ctx->streams[i]->codecpar->extradata_size = 0;
1549  }
1550 
1551  buffer = av_malloc(buffer_size);
1552  if (!buffer) {
1553  ret = AVERROR(ENOMEM);
1554  goto end;
1555  }
1556 
1557  rtp_ctx->pb = avio_alloc_context(buffer, buffer_size, 1, s, NULL, on_rtp_write_packet, NULL);
1558  if (!rtp_ctx->pb) {
1559  ret = AVERROR(ENOMEM);
1560  goto end;
1561  }
1562  rtp_ctx->pb->max_packet_size = max_packet_size;
1563  rtp_ctx->pb->av_class = &ff_avio_class;
1564 
1565  is_video = s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO;
1566  snprintf(buf, sizeof(buf), "%d", is_video? whip->video_payload_type : whip->audio_payload_type);
1567  av_dict_set(&opts, "payload_type", buf, 0);
1568  snprintf(buf, sizeof(buf), "%d", is_video? whip->video_ssrc : whip->audio_ssrc);
1569  av_dict_set(&opts, "ssrc", buf, 0);
1570  av_dict_set_int(&opts, "seq", is_video ? whip->video_first_seq : whip->audio_first_seq, 0);
1571 
1572  ret = avformat_write_header(rtp_ctx, &opts);
1573  if (ret < 0) {
1574  av_log(whip, AV_LOG_ERROR, "Failed to write rtp header\n");
1575  goto end;
1576  }
1577 
1578  ff_format_set_url(rtp_ctx, av_strdup(s->url));
1579  s->streams[i]->time_base = rtp_ctx->streams[0]->time_base;
1580  s->streams[i]->priv_data = rtp_ctx;
1581  rtp_ctx = NULL;
1582  }
1583 
1584  if (whip->state < WHIP_STATE_READY)
1585  whip->state = WHIP_STATE_READY;
1586  av_log(whip, AV_LOG_INFO, "Muxer state=%d, buffer_size=%d, max_packet_size=%d, "
1587  "elapsed=%.2fms(init:%.2f,offer:%.2f,answer:%.2f,udp:%.2f,ice:%.2f,dtls:%.2f,srtp:%.2f)\n",
1588  whip->state, buffer_size, max_packet_size, ELAPSED(whip->whip_starttime, av_gettime_relative()),
1589  ELAPSED(whip->whip_starttime, whip->whip_init_time),
1590  ELAPSED(whip->whip_init_time, whip->whip_offer_time),
1592  ELAPSED(whip->whip_answer_time, whip->whip_udp_time),
1593  ELAPSED(whip->whip_udp_time, whip->whip_ice_time),
1594  ELAPSED(whip->whip_ice_time, whip->whip_dtls_time),
1595  ELAPSED(whip->whip_dtls_time, whip->whip_srtp_time));
1596 
1597 end:
1598  if (rtp_ctx)
1599  avio_context_free(&rtp_ctx->pb);
1600  avformat_free_context(rtp_ctx);
1601  av_dict_free(&opts);
1602  return ret;
1603 }
1604 
1605 /**
1606  * RTC is connectionless, for it's based on UDP, so it check whether sesison is
1607  * timeout. In such case, publishers can't republish the stream util the session
1608  * is timeout.
1609  * This function is called to notify the server that the stream is ended, server
1610  * should expire and close the session immediately, so that publishers can republish
1611  * the stream quickly.
1612  */
1614 {
1615  int ret;
1616  char buf[MAX_URL_SIZE];
1617  URLContext *whip_uc = NULL;
1618  AVDictionary *opts = NULL;
1619  WHIPContext *whip = s->priv_data;
1620 
1621  if (!whip->whip_resource_url)
1622  return 0;
1623 
1624  ret = snprintf(buf, sizeof(buf), "Cache-Control: no-cache\r\n");
1625  if (whip->authorization)
1626  ret += snprintf(buf + ret, sizeof(buf) - ret, "Authorization: Bearer %s\r\n", whip->authorization);
1627  if (ret <= 0 || ret >= sizeof(buf)) {
1628  av_log(whip, AV_LOG_ERROR, "Failed to generate headers, size=%d, %s\n", ret, buf);
1629  ret = AVERROR(EINVAL);
1630  goto end;
1631  }
1632 
1633  av_dict_set(&opts, "headers", buf, 0);
1634  av_dict_set_int(&opts, "chunked_post", 0, 0);
1635  av_dict_set(&opts, "method", "DELETE", 0);
1636  ret = ffurl_open_whitelist(&whip_uc, whip->whip_resource_url, AVIO_FLAG_READ_WRITE, &s->interrupt_callback,
1637  &opts, s->protocol_whitelist, s->protocol_blacklist, NULL);
1638  if (ret < 0) {
1639  av_log(whip, AV_LOG_ERROR, "Failed to DELETE url=%s\n", whip->whip_resource_url);
1640  goto end;
1641  }
1642 
1643  while (1) {
1644  ret = ffurl_read(whip_uc, buf, sizeof(buf));
1645  if (ret == AVERROR_EOF) {
1646  ret = 0;
1647  break;
1648  }
1649  if (ret < 0) {
1650  av_log(whip, AV_LOG_ERROR, "Failed to read response from DELETE url=%s\n", whip->whip_resource_url);
1651  goto end;
1652  }
1653  }
1654 
1655  av_log(whip, AV_LOG_INFO, "Dispose resource %s ok\n", whip->whip_resource_url);
1656 
1657 end:
1658  ffurl_closep(&whip_uc);
1659  av_dict_free(&opts);
1660  return ret;
1661 }
1662 
1663 /**
1664  * Since the h264_mp4toannexb filter only processes the MP4 ISOM format and bypasses
1665  * the annexb format, it is necessary to manually insert encoder metadata before each
1666  * IDR when dealing with annexb format packets. For instance, in the case of H.264,
1667  * we must insert SPS and PPS before the IDR frame.
1668  */
1670 {
1671  int ret = 0;
1672  AVPacket *in = NULL;
1673  AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar;
1674  uint32_t nal_size = 0, out_size = par ? par->extradata_size : 0;
1675  uint8_t unit_type, sps_seen = 0, pps_seen = 0, idr_seen = 0, *out;
1676  const uint8_t *buf, *buf_end, *r1;
1677 
1678  if (!par || !par->extradata || par->extradata_size <= 0)
1679  return ret;
1680 
1681  /* Discover NALU type from packet. */
1682  buf_end = pkt->data + pkt->size;
1683  for (buf = ff_nal_find_startcode(pkt->data, buf_end); buf < buf_end; buf += nal_size) {
1684  while (!*(buf++));
1685  r1 = ff_nal_find_startcode(buf, buf_end);
1686  if ((nal_size = r1 - buf) > 0) {
1687  unit_type = *buf & 0x1f;
1688  if (unit_type == H264_NAL_SPS) {
1689  sps_seen = 1;
1690  } else if (unit_type == H264_NAL_PPS) {
1691  pps_seen = 1;
1692  } else if (unit_type == H264_NAL_IDR_SLICE) {
1693  idr_seen = 1;
1694  }
1695 
1696  out_size += 3 + nal_size;
1697  }
1698  }
1699 
1700  if (!idr_seen || (sps_seen && pps_seen))
1701  return ret;
1702 
1703  /* See av_bsf_send_packet */
1704  in = av_packet_alloc();
1705  if (!in)
1706  return AVERROR(ENOMEM);
1707 
1709  if (ret < 0)
1710  goto fail;
1711 
1712  av_packet_move_ref(in, pkt);
1713 
1714  /* Create a new packet with sps/pps inserted. */
1716  if (ret < 0)
1717  goto fail;
1718 
1719  ret = av_packet_copy_props(pkt, in);
1720  if (ret < 0)
1721  goto fail;
1722 
1723  memcpy(pkt->data, par->extradata, par->extradata_size);
1724  out = pkt->data + par->extradata_size;
1725  buf_end = in->data + in->size;
1726  for (buf = ff_nal_find_startcode(in->data, buf_end); buf < buf_end; buf += nal_size) {
1727  while (!*(buf++));
1728  r1 = ff_nal_find_startcode(buf, buf_end);
1729  if ((nal_size = r1 - buf) > 0) {
1730  AV_WB24(out, 0x00001);
1731  memcpy(out + 3, buf, nal_size);
1732  out += 3 + nal_size;
1733  }
1734  }
1735 
1736 fail:
1737  if (ret < 0)
1739  av_packet_free(&in);
1740 
1741  return ret;
1742 }
1743 
1745 {
1746  int ret;
1747  WHIPContext *whip = s->priv_data;
1748 
1749  if ((ret = initialize(s)) < 0)
1750  goto end;
1751 
1752  if ((ret = parse_codec(s)) < 0)
1753  goto end;
1754 
1755  if ((ret = generate_sdp_offer(s)) < 0)
1756  goto end;
1757 
1758  if ((ret = exchange_sdp(s)) < 0)
1759  goto end;
1760 
1761  if ((ret = parse_answer(s)) < 0)
1762  goto end;
1763 
1764  if ((ret = udp_connect(s)) < 0)
1765  goto end;
1766 
1767  if ((ret = ice_dtls_handshake(s)) < 0)
1768  goto end;
1769 
1770  if ((ret = setup_srtp(s)) < 0)
1771  goto end;
1772 
1773  if ((ret = create_rtp_muxer(s)) < 0)
1774  goto end;
1775 
1776 end:
1777  if (ret < 0)
1778  whip->state = WHIP_STATE_FAILED;
1779  return ret;
1780 }
1781 
1783 {
1784  int ret;
1785  WHIPContext *whip = s->priv_data;
1786  AVStream *st = s->streams[pkt->stream_index];
1787  AVFormatContext *rtp_ctx = st->priv_data;
1788 
1789  /* TODO: Send binding request every 1s as WebRTC heartbeat. */
1790 
1791  /**
1792  * Receive packets from the server such as ICE binding requests, DTLS messages,
1793  * and RTCP like PLI requests, then respond to them.
1794  */
1795  ret = ffurl_read(whip->udp, whip->buf, sizeof(whip->buf));
1796  if (ret < 0) {
1797  if (ret == AVERROR(EAGAIN))
1798  goto write_packet;
1799  av_log(whip, AV_LOG_ERROR, "Failed to read from UDP socket\n");
1800  goto end;
1801  }
1802  if (!ret) {
1803  av_log(whip, AV_LOG_ERROR, "Receive EOF from UDP socket\n");
1804  goto end;
1805  }
1806  if (is_dtls_packet(whip->buf, ret)) {
1807  if ((ret = ffurl_write(whip->dtls_uc, whip->buf, ret)) < 0) {
1808  av_log(whip, AV_LOG_ERROR, "Failed to handle DTLS message\n");
1809  goto end;
1810  }
1811  }
1812 write_packet:
1814  if ((ret = h264_annexb_insert_sps_pps(s, pkt)) < 0) {
1815  av_log(whip, AV_LOG_ERROR, "Failed to insert SPS/PPS before IDR\n");
1816  goto end;
1817  }
1818  }
1819 
1820  ret = ff_write_chained(rtp_ctx, 0, pkt, s, 0);
1821  if (ret < 0) {
1822  if (ret == AVERROR(EINVAL)) {
1823  av_log(whip, AV_LOG_WARNING, "Ignore failed to write packet=%dB, ret=%d\n", pkt->size, ret);
1824  ret = 0;
1825  } else
1826  av_log(whip, AV_LOG_ERROR, "Failed to write packet, size=%d\n", pkt->size);
1827  goto end;
1828  }
1829 
1830 end:
1831  if (ret < 0)
1832  whip->state = WHIP_STATE_FAILED;
1833  return ret;
1834 }
1835 
1837 {
1838  int i, ret;
1839  WHIPContext *whip = s->priv_data;
1840 
1841  ret = dispose_session(s);
1842  if (ret < 0)
1843  av_log(whip, AV_LOG_WARNING, "Failed to dispose resource, ret=%d\n", ret);
1844 
1845  for (i = 0; i < s->nb_streams; i++) {
1846  AVFormatContext* rtp_ctx = s->streams[i]->priv_data;
1847  if (!rtp_ctx)
1848  continue;
1849 
1850  av_write_trailer(rtp_ctx);
1851  /**
1852  * Keep in mind that it is necessary to free the buffer of pb since we allocate
1853  * it and pass it to pb using avio_alloc_context, while avio_context_free does
1854  * not perform this action.
1855  */
1856  av_freep(&rtp_ctx->pb->buffer);
1857  avio_context_free(&rtp_ctx->pb);
1858  avformat_free_context(rtp_ctx);
1859  s->streams[i]->priv_data = NULL;
1860  }
1861 
1862  av_freep(&whip->sdp_offer);
1863  av_freep(&whip->sdp_answer);
1864  av_freep(&whip->whip_resource_url);
1865  av_freep(&whip->ice_ufrag_remote);
1866  av_freep(&whip->ice_pwd_remote);
1867  av_freep(&whip->ice_protocol);
1868  av_freep(&whip->ice_host);
1869  av_freep(&whip->authorization);
1870  av_freep(&whip->cert_file);
1871  av_freep(&whip->key_file);
1872  ff_srtp_free(&whip->srtp_audio_send);
1873  ff_srtp_free(&whip->srtp_video_send);
1874  ff_srtp_free(&whip->srtp_rtcp_send);
1875  ff_srtp_free(&whip->srtp_recv);
1876  ffurl_close(whip->dtls_uc);
1877  ffurl_closep(&whip->udp);
1878 }
1879 
1881 {
1882  int ret = 1, extradata_isom = 0;
1883  uint8_t *b = pkt->data;
1884  WHIPContext *whip = s->priv_data;
1885 
1886  if (st->codecpar->codec_id == AV_CODEC_ID_H264) {
1887  extradata_isom = st->codecpar->extradata_size > 0 && st->codecpar->extradata[0] == 1;
1888  if (pkt->size >= 5 && AV_RB32(b) != 0x0000001 && (AV_RB24(b) != 0x000001 || extradata_isom)) {
1889  ret = ff_stream_add_bitstream_filter(st, "h264_mp4toannexb", NULL);
1890  av_log(whip, AV_LOG_VERBOSE, "Enable BSF h264_mp4toannexb, packet=[%x %x %x %x %x ...], extradata_isom=%d\n",
1891  b[0], b[1], b[2], b[3], b[4], extradata_isom);
1892  } else
1893  whip->h264_annexb_insert_sps_pps = 1;
1894  }
1895 
1896  return ret;
1897 }
1898 
1899 #define OFFSET(x) offsetof(WHIPContext, x)
1900 #define ENC AV_OPT_FLAG_ENCODING_PARAM
1901 static const AVOption options[] = {
1902  { "handshake_timeout", "Timeout in milliseconds for ICE and DTLS handshake.", OFFSET(handshake_timeout), AV_OPT_TYPE_INT, { .i64 = 5000 }, -1, INT_MAX, ENC },
1903  { "pkt_size", "The maximum size, in bytes, of RTP packets that send out", OFFSET(pkt_size), AV_OPT_TYPE_INT, { .i64 = 1200 }, -1, INT_MAX, ENC },
1904  { "authorization", "The optional Bearer token for WHIP Authorization", OFFSET(authorization), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, ENC },
1905  { "cert_file", "The optional certificate file path for DTLS", OFFSET(cert_file), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, ENC },
1906  { "key_file", "The optional private key file path for DTLS", OFFSET(key_file), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, ENC },
1907  { NULL },
1908 };
1909 
1910 static const AVClass whip_muxer_class = {
1911  .class_name = "WHIP muxer",
1912  .item_name = av_default_item_name,
1913  .option = options,
1914  .version = LIBAVUTIL_VERSION_INT,
1915 };
1916 
1918  .p.name = "whip",
1919  .p.long_name = NULL_IF_CONFIG_SMALL("WHIP(WebRTC-HTTP ingestion protocol) muxer"),
1920  .p.audio_codec = AV_CODEC_ID_OPUS,
1921  .p.video_codec = AV_CODEC_ID_H264,
1923  .p.priv_class = &whip_muxer_class,
1924  .priv_data_size = sizeof(WHIPContext),
1925  .init = whip_init,
1927  .deinit = whip_deinit,
1929 };
H264SPS
Definition: avc.h:32
WHIPContext::whip_udp_time
int64_t whip_udp_time
Definition: whip.c:266
ICE_DTLS_READ_INTERVAL
#define ICE_DTLS_READ_INTERVAL
When sending ICE or DTLS messages, responses are received via UDP.
Definition: whip.c:78
on_rtp_write_packet
static int on_rtp_write_packet(void *opaque, const uint8_t *buf, int buf_size)
Callback triggered by the RTP muxer when it creates and sends out an RTP packet.
Definition: whip.c:1444
ff_get_chomp_line
int ff_get_chomp_line(AVIOContext *s, char *buf, int maxlen)
Same as ff_get_line but strip the white-space characters in the text tail.
Definition: aviobuf.c:789
AVHMAC
Definition: hmac.c:40
av_packet_unref
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: packet.c:433
av_gettime_relative
int64_t av_gettime_relative(void)
Get the current time in microseconds since some unspecified starting point.
Definition: time.c:56
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
AVCodecParameters::extradata
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: codec_par.h:69
level
uint8_t level
Definition: svq3.c:208
whip_deinit
static av_cold void whip_deinit(AVFormatContext *s)
Definition: whip.c:1836
AVOutputFormat::name
const char * name
Definition: avformat.h:506
av_bprint_is_complete
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:218
r
const char * r
Definition: vf_curves.c:127
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
WHIPContext::sdp_offer
char * sdp_offer
This is the SDP offer generated by the muxer based on the codec parameters, DTLS, and ICE information...
Definition: whip.c:241
AV_PROFILE_H264_INTRA
#define AV_PROFILE_H264_INTRA
Definition: defs.h:108
AVCodecParameters::codec_type
enum AVMediaType codec_type
General type of the encoded data.
Definition: codec_par.h:51
STUN_MAGIC_COOKIE
#define STUN_MAGIC_COOKIE
Definition: whip.c:81
WHIP_STATE_ANSWER
@ WHIP_STATE_ANSWER
Definition: whip.c:181
out
FILE * out
Definition: movenc.c:55
av_lfg_init
av_cold void av_lfg_init(AVLFG *c, unsigned int seed)
Definition: lfg.c:32
dtls_initialize
static av_cold int dtls_initialize(AVFormatContext *s)
Definition: whip.c:361
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
AVCodecParameters
This struct describes the properties of an encoded stream.
Definition: codec_par.h:47
av_stristr
char * av_stristr(const char *s1, const char *s2)
Locate the first case-independent occurrence in the string haystack of the string needle.
Definition: avstring.c:58
avformat_new_stream
AVStream * avformat_new_stream(AVFormatContext *s, const struct AVCodec *c)
Add a new stream to a media file.
AVStream::priv_data
void * priv_data
Definition: avformat.h:769
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
AVIO_FLAG_READ_WRITE
#define AVIO_FLAG_READ_WRITE
read-write pseudo flag
Definition: avio.h:619
STUN_ATTR_FINGERPRINT
@ STUN_ATTR_FINGERPRINT
bind request/response
Definition: whip.c:169
WHIP_STATE_DTLS_FINISHED
@ WHIP_STATE_DTLS_FINISHED
Definition: whip.c:196
avio_context_free
void avio_context_free(AVIOContext **s)
Free the supplied IO context and everything associated with it.
Definition: aviobuf.c:126
int64_t
long long int64_t
Definition: coverity.c:34
WHIPContext::ice_pwd_remote
char * ice_pwd_remote
Definition: whip.c:246
WHIPContext::dtls_uc
URLContext * dtls_uc
Definition: whip.c:287
ffurl_write
static int ffurl_write(URLContext *h, const uint8_t *buf, int size)
Write size bytes from buf to the resource accessed by h.
Definition: url.h:202
av_strcasecmp
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition: avstring.c:208
initialize
static av_cold int initialize(AVFormatContext *s)
Initialize and check the options for the WebRTC muxer.
Definition: whip.c:377
out_size
int out_size
Definition: movenc.c:56
WHIPContext::video_ssrc
uint32_t video_ssrc
Definition: whip.c:230
AVFormatContext::streams
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1332
deinit
static void deinit(AVFormatContext *s)
Definition: chromaprint.c:52
AVFormatContext::strict_std_compliance
int strict_std_compliance
Allow non-standard and experimental extension.
Definition: avformat.h:1618
AVPacket::data
uint8_t * data
Definition: packet.h:558
avio_alloc_context
AVIOContext * avio_alloc_context(unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int(*read_packet)(void *opaque, uint8_t *buf, int buf_size), int(*write_packet)(void *opaque, const uint8_t *buf, int buf_size), int64_t(*seek)(void *opaque, int64_t offset, int whence))
Allocate and initialize an AVIOContext for buffered I/O.
Definition: aviobuf.c:109
AVOption
AVOption.
Definition: opt.h:429
srtp.h
b
#define b
Definition: input.c:42
WHIPContext::audio_first_seq
uint16_t audio_first_seq
Definition: whip.c:232
ICE_STUN_HEADER_SIZE
#define ICE_STUN_HEADER_SIZE
The STUN message header, which is 20 bytes long, comprises the STUNMessageType (1B),...
Definition: whip.c:131
WHIPContext::handshake_timeout
int handshake_timeout
Definition: whip.c:302
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:226
is_dtls_packet
static int is_dtls_packet(uint8_t *b, int size)
Whether the packet is a DTLS packet.
Definition: whip.c:321
ffurl_close
int ffurl_close(URLContext *h)
Definition: avio.c:612
AVIOContext::max_packet_size
int max_packet_size
Definition: avio.h:241
ice_create_request
static int ice_create_request(AVFormatContext *s, uint8_t *buf, int buf_size, int *request_size)
Creates and marshals an ICE binding request packet.
Definition: whip.c:941
AVDictionary
Definition: dict.c:32
WHIPContext::srtp_video_send
SRTPContext srtp_video_send
Definition: whip.c:291
WHIPContext::udp
URLContext * udp
Definition: whip.c:297
SRTPContext
Definition: srtp.h:30
AVChannelLayout::nb_channels
int nb_channels
Number of channels in this layout.
Definition: channel_layout.h:329
WHIP_SDP_CREATOR_IP
#define WHIP_SDP_CREATOR_IP
Definition: whip.c:158
WHIPContext::h264_annexb_insert_sps_pps
int h264_annexb_insert_sps_pps
The h264_mp4toannexb Bitstream Filter (BSF) bypasses the AnnexB packet; therefore,...
Definition: whip.c:220
udp_connect
static int udp_connect(AVFormatContext *s)
To establish a connection with the UDP server, we utilize ICE-LITE in a Client-Server mode.
Definition: whip.c:1179
av_packet_free
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition: packet.c:75
av_hmac_final
int av_hmac_final(AVHMAC *c, uint8_t *out, unsigned int outlen)
Finish hashing and output the HMAC digest.
Definition: hmac.c:181
DTLS_SRTP_CHECKSUM_LEN
#define DTLS_SRTP_CHECKSUM_LEN
The maximum size of the Secure Real-time Transport Protocol (SRTP) HMAC checksum and padding that is ...
Definition: whip.c:67
WHIPContext::ssl_error_message
char ssl_error_message[256]
Definition: whip.c:284
WHIP_STATE_ICE_CONNECTED
@ WHIP_STATE_ICE_CONNECTED
Definition: whip.c:192
FFOutputFormat::p
AVOutputFormat p
The public AVOutputFormat.
Definition: mux.h:65
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
av_get_random_seed
uint32_t av_get_random_seed(void)
Get a seed to use in conjunction with random functions.
Definition: random_seed.c:196
WHIPContext::ice_port
int ice_port
Definition: whip.c:254
WHIP_SDP_SESSION_ID
#define WHIP_SDP_SESSION_ID
In the case of ICE-LITE, these fields are not used; instead, they are defined as constant values.
Definition: whip.c:157
crc.h
WHIPContext::key_file
char * key_file
Definition: whip.c:315
AVFormatContext::interrupt_callback
AVIOInterruptCB interrupt_callback
Custom interrupt callbacks for the I/O layer.
Definition: avformat.h:1534
ff_whip_muxer
const FFOutputFormat ff_whip_muxer
Definition: whip.c:1917
WHIPContext::cert_buf
char cert_buf[MAX_CERTIFICATE_SIZE]
Definition: whip.c:272
fail
#define fail()
Definition: checkasm.h:200
ff_avc_decode_sps
int ff_avc_decode_sps(H264SPS *sps, const uint8_t *buf, int buf_size)
Definition: avc.c:208
WHIP_STATE_SRTP_FINISHED
@ WHIP_STATE_SRTP_FINISHED
Definition: whip.c:198
avio_tell
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:494
WHIPContext::whip_ice_time
int64_t whip_ice_time
Definition: whip.c:267
WHIPContext
Definition: whip.c:205
parse_answer
static int parse_answer(AVFormatContext *s)
Parses the ICE ufrag, pwd, and candidates from the SDP answer.
Definition: whip.c:834
STUN_HOST_CANDIDATE_PRIORITY
#define STUN_HOST_CANDIDATE_PRIORITY
Refer to RFC 8445 5.1.2 priority = (2^24)*(type preference) + (2^8)*(local preference) + (2^0)*(256 -...
Definition: whip.c:88
ff_data_to_hex
char * ff_data_to_hex(char *buf, const uint8_t *src, int size, int lowercase)
Write hexadecimal string corresponding to given binary data.
Definition: utils.c:454
ff_srtp_encrypt
int ff_srtp_encrypt(struct SRTPContext *s, const uint8_t *in, int len, uint8_t *out, int outlen)
Definition: srtp.c:239
WHIP_RTP_PAYLOAD_TYPE_H264
#define WHIP_RTP_PAYLOAD_TYPE_H264
Definition: whip.c:122
ice_handle_binding_request
static int ice_handle_binding_request(AVFormatContext *s, char *buf, int buf_size)
This function handles incoming binding request messages by responding to them.
Definition: whip.c:1139
h264_annexb_insert_sps_pps
static int h264_annexb_insert_sps_pps(AVFormatContext *s, AVPacket *pkt)
Since the h264_mp4toannexb filter only processes the MP4 ISOM format and bypasses the annexb format,...
Definition: whip.c:1669
pkt
AVPacket * pkt
Definition: movenc.c:60
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
av_cold
#define av_cold
Definition: attributes.h:90
AV_PROFILE_UNKNOWN
#define AV_PROFILE_UNKNOWN
Definition: defs.h:65
WHIPContext::sdp_answer
char * sdp_answer
Definition: whip.c:257
ice_dtls_handshake
static int ice_dtls_handshake(AVFormatContext *s)
Definition: whip.c:1216
ffurl_open_whitelist
int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options, const char *whitelist, const char *blacklist, URLContext *parent)
Create an URLContext for accessing to the resource indicated by url, and open it.
Definition: avio.c:363
WHIP_STATE_OFFER
@ WHIP_STATE_OFFER
Definition: whip.c:179
ice_is_binding_request
static int ice_is_binding_request(uint8_t *b, int size)
A Binding request has class=0b00 (request) and method=0b000000000001 (Binding) and is encoded into th...
Definition: whip.c:1103
AVCodecDescriptor
This struct describes the properties of a single codec described by an AVCodecID.
Definition: codec_desc.h:38
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:198
DTLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC
#define DTLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC
The DTLS content type.
Definition: whip.c:95
av_new_packet
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: packet.c:99
av_lfg_get
static unsigned int av_lfg_get(AVLFG *c)
Get the next random unsigned 32-bit number using an ALFG.
Definition: lfg.h:53
WHIPContext::srtp_audio_send
SRTPContext srtp_audio_send
Definition: whip.c:290
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1415
WHIPContext::whip_dtls_time
int64_t whip_dtls_time
Definition: whip.c:268
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:201
WHIPContext::ice_ufrag_remote
char * ice_ufrag_remote
Definition: whip.c:245
STUN_ATTR_USE_CANDIDATE
@ STUN_ATTR_USE_CANDIDATE
must be included in a Binding request
Definition: whip.c:167
lfg.h
URLContext::flags
int flags
Definition: url.h:40
ff_url_join
int ff_url_join(char *str, int size, const char *proto, const char *authorization, const char *hostname, int port, const char *fmt,...)
Definition: url.c:40
WHIPContext::ice_ufrag_local
char ice_ufrag_local[9]
Definition: whip.c:226
AVIO_FLAG_WRITE
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:618
av_usleep
int av_usleep(unsigned usec)
Sleep for a period of time.
Definition: time.c:84
AV_CODEC_ID_H264
@ AV_CODEC_ID_H264
Definition: codec_id.h:79
H264_NAL_SPS
@ H264_NAL_SPS
Definition: h264.h:41
DTLS_SRTP_SALT_LEN
#define DTLS_SRTP_SALT_LEN
Definition: whip.c:59
avformat_write_header
av_warn_unused_result int avformat_write_header(AVFormatContext *s, AVDictionary **options)
Allocate the stream private data and write the stream header to an output media file.
Definition: mux.c:467
WHIPContext::whip_srtp_time
int64_t whip_srtp_time
Definition: whip.c:269
STUNAttr
STUNAttr
Definition: whip.c:164
ice_create_response
static int ice_create_response(AVFormatContext *s, char *tid, int tid_size, uint8_t *buf, int buf_size, int *response_size)
Create an ICE binding response.
Definition: whip.c:1039
parse_codec
static int parse_codec(AVFormatContext *s)
Parses video SPS/PPS from the extradata of codecpar and checks the codec.
Definition: whip.c:497
WHIP_STATE_READY
@ WHIP_STATE_READY
Definition: whip.c:200
AVFormatContext
Format I/O context.
Definition: avformat.h:1264
dispose_session
static int dispose_session(AVFormatContext *s)
RTC is connectionless, for it's based on UDP, so it check whether sesison is timeout.
Definition: whip.c:1613
internal.h
crc32
static unsigned crc32(const uint8_t *data, unsigned size)
Definition: crypto_bench.c:575
opts
AVDictionary * opts
Definition: movenc.c:51
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:767
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
STUN_ATTR_USERNAME
@ STUN_ATTR_USERNAME
Definition: whip.c:165
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:76
AVStream::time_base
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented.
Definition: avformat.h:783
WHIPContext::whip_init_time
int64_t whip_init_time
Definition: whip.c:263
NULL
#define NULL
Definition: coverity.c:32
AVERROR_PATCHWELCOME
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:64
profile_idc
int profile_idc
Definition: h264_levels.c:53
AV_LEVEL_UNKNOWN
#define AV_LEVEL_UNKNOWN
Definition: defs.h:209
WHIPContext::srtp_recv
SRTPContext srtp_recv
Definition: whip.c:294
DTLS_VERSION_12
#define DTLS_VERSION_12
Definition: whip.c:110
certificate_key_init
static av_cold int certificate_key_init(AVFormatContext *s)
Get or Generate a self-signed certificate and private key for DTLS, fingerprint for SDP.
Definition: whip.c:333
WHIPContext::video_payload_type
uint8_t video_payload_type
Definition: whip.c:236
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:241
AVFormatContext::pb
AVIOContext * pb
I/O context.
Definition: avformat.h:1306
avc.h
DTLS_SRTP_KEY_LEN
#define DTLS_SRTP_KEY_LEN
The size of the Secure Real-time Transport Protocol (SRTP) master key material that is exported by Se...
Definition: whip.c:58
options
Definition: swscale.c:43
av_hmac_update
void av_hmac_update(AVHMAC *c, const uint8_t *data, unsigned int len)
Hash data with the HMAC.
Definition: hmac.c:176
WHIPContext::key_buf
char key_buf[MAX_CERTIFICATE_SIZE]
Definition: whip.c:273
avpriv_find_start_code
const uint8_t * avpriv_find_start_code(const uint8_t *p, const uint8_t *end, uint32_t *state)
FFOutputFormat
Definition: mux.h:61
WHIP_STATE_FAILED
@ WHIP_STATE_FAILED
Definition: whip.c:202
whip_init
static av_cold int whip_init(AVFormatContext *s)
Definition: whip.c:1744
time.h
WHIPContext::ice_tie_breaker
uint64_t ice_tie_breaker
Definition: whip.c:243
ffio_fill
void ffio_fill(AVIOContext *s, int b, int64_t count)
Definition: aviobuf.c:192
AVCodecParameters::ch_layout
AVChannelLayout ch_layout
Audio only.
Definition: codec_par.h:180
av_packet_move_ref
void av_packet_move_ref(AVPacket *dst, AVPacket *src)
Move every field in src to dst and reset src.
Definition: packet.c:490
seed
static unsigned int seed
Definition: videogen.c:78
base64.h
media_is_rtp_rtcp
static int media_is_rtp_rtcp(const uint8_t *b, int size)
In RTP packets, the first byte is represented as 0b10xxxxxx, where the initial two bits (0b10) indica...
Definition: whip.c:1124
AVCodecParameters::level
int level
Definition: codec_par.h:129
WHIPContext::ice_host
char * ice_host
Definition: whip.c:253
AVCodecParameters::sample_rate
int sample_rate
Audio only.
Definition: codec_par.h:184
AV_HMAC_SHA1
@ AV_HMAC_SHA1
Definition: hmac.h:34
AVCodecParameters::extradata_size
int extradata_size
Size of the extradata content in bytes.
Definition: codec_par.h:73
whip_muxer_class
static const AVClass whip_muxer_class
Definition: whip.c:1910
DTLS_RECORD_LAYER_HEADER_LEN
#define DTLS_RECORD_LAYER_HEADER_LEN
The DTLS record layer header has a total size of 13 bytes, consisting of ContentType (1 byte),...
Definition: whip.c:103
suite
FFmpeg currently uses a custom build this text attempts to document some of its obscure features and options Makefile the full command issued by make and its output will be shown on the screen DBG Preprocess x86 external assembler files to a dbg asm file in the object which then gets compiled Helps in developing those assembler files DESTDIR Destination directory for the install useful to prepare packages or install FFmpeg in cross environments GEN Set to ‘1’ to generate the missing or mismatched references Makefile builds all the libraries and the executables fate Run the fate test suite
Definition: build_system.txt:28
startcode.h
MAX_UDP_BUFFER_SIZE
#define MAX_UDP_BUFFER_SIZE
Maximum size of the buffer for sending and receiving UDP packets.
Definition: whip.c:119
WHIP_RTCP_PT_START
#define WHIP_RTCP_PT_START
For RTCP, PT is [128, 223] (or without marker [0, 95]).
Definition: whip.c:150
AVLFG
Context structure for the Lagged Fibonacci PRNG.
Definition: lfg.h:33
AVIOContext
Bytestream IO Context.
Definition: avio.h:160
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:368
AVPacket::size
int size
Definition: packet.h:559
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:94
avformat_alloc_context
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
Definition: options.c:162
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
STUN_ATTR_ICE_CONTROLLING
@ STUN_ATTR_ICE_CONTROLLING
rfc5389
Definition: whip.c:170
H264_NAL_PPS
@ H264_NAL_PPS
Definition: h264.h:42
size
int size
Definition: twinvq_data.h:10344
WHIPContext::cert_file
char * cert_file
Definition: whip.c:314
AV_RB32
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_RB32
Definition: bytestream.h:96
STUN_ATTR_MESSAGE_INTEGRITY
@ STUN_ATTR_MESSAGE_INTEGRITY
bind request
Definition: whip.c:168
AVCodecParameters::profile
int profile
Codec-specific bitstream restrictions that the stream conforms to.
Definition: codec_par.h:128
AV_CODEC_ID_OPUS
@ AV_CODEC_ID_OPUS
Definition: codec_id.h:511
AVFMT_NOFILE
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition: avformat.h:468
AV_WB24
#define AV_WB24(p, d)
Definition: intreadwrite.h:446
AVStream::sample_aspect_ratio
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown)
Definition: avformat.h:822
options
static const AVOption options[]
Definition: whip.c:1901
ff_socket_nonblock
int ff_socket_nonblock(int socket, int enable)
avio_write
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:206
avio_wb32
void avio_wb32(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:368
WHIPContext::audio_par
AVCodecParameters * audio_par
Definition: whip.c:212
parse_profile_level
static int parse_profile_level(AVFormatContext *s, AVCodecParameters *par)
When duplicating a stream, the demuxer has already set the extradata, profile, and level of the par.
Definition: whip.c:430
ff_srtp_free
void ff_srtp_free(struct SRTPContext *s)
Definition: srtp.c:32
av_crc_get_table
const AVCRC * av_crc_get_table(AVCRCId crc_id)
Get an initialized standard CRC table.
Definition: crc.c:374
line
Definition: graph2dot.c:48
WHIPContext::dtls_fingerprint
char * dtls_fingerprint
Definition: whip.c:275
av_packet_make_refcounted
int av_packet_make_refcounted(AVPacket *pkt)
Ensure the data described by a given packet is reference counted.
Definition: packet.c:496
av_packet_alloc
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition: packet.c:64
av_dict_free
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition: dict.c:233
av_strstart
int av_strstart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str.
Definition: avstring.c:36
WHIPContext::rnd
AVLFG rnd
Definition: whip.c:223
version
version
Definition: libkvazaar.c:315
WHIPContext::whip_resource_url
char * whip_resource_url
Definition: whip.c:259
WHIP_STATE_INIT
@ WHIP_STATE_INIT
Definition: whip.c:177
av_hmac_alloc
AVHMAC * av_hmac_alloc(enum AVHMACType type)
Allocate an AVHMAC context.
Definition: hmac.c:82
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:221
WHIP_STATE_NONE
@ WHIP_STATE_NONE
Definition: whip.c:174
WHIPState
WHIPState
Definition: whip.c:173
ENC
#define ENC
Definition: whip.c:1900
ELAPSED
#define ELAPSED(starttime, endtime)
Definition: whip.c:161
av_hmac_free
void av_hmac_free(AVHMAC *c)
Free an AVHMAC context.
Definition: hmac.c:147
av_write_trailer
int av_write_trailer(AVFormatContext *s)
Write the stream trailer to an output media file and free the file private data.
Definition: mux.c:1238
av_packet_copy_props
int av_packet_copy_props(AVPacket *dst, const AVPacket *src)
Copy only "properties" fields from src to dst.
Definition: packet.c:396
generate_sdp_offer
static int generate_sdp_offer(AVFormatContext *s)
Generate SDP offer according to the codec parameters, DTLS and ICE information.
Definition: whip.c:580
bprint.h
AV_BASE64_SIZE
#define AV_BASE64_SIZE(x)
Calculate the output size needed to base64-encode x bytes to a null-terminated string.
Definition: base64.h:66
URLContext
Definition: url.h:35
AVFMT_GLOBALHEADER
#define AVFMT_GLOBALHEADER
Format wants global header.
Definition: avformat.h:477
AVOutputFormat
Definition: avformat.h:505
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
avio_internal.h
STUN_ATTR_PRIORITY
@ STUN_ATTR_PRIORITY
shared secret response/bind request
Definition: whip.c:166
check_bitstream
static int check_bitstream(AVFormatContext *s, FFStream *sti, AVPacket *pkt)
Definition: mux.c:1056
WHIPContext::video_first_seq
uint16_t video_first_seq
Definition: whip.c:233
av_hmac_init
void av_hmac_init(AVHMAC *c, const uint8_t *key, unsigned int keylen)
Initialize an AVHMAC context with an authentication key.
Definition: hmac.c:155
exchange_sdp
static int exchange_sdp(AVFormatContext *s)
Exchange SDP offer with WebRTC peer to get the answer.
Definition: whip.c:715
whip_check_bitstream
static int whip_check_bitstream(AVFormatContext *s, AVStream *st, const AVPacket *pkt)
Definition: whip.c:1880
WHIPContext::state
enum WHIPState state
Definition: whip.c:209
create_rtp_muxer
static int create_rtp_muxer(AVFormatContext *s)
Creates dedicated RTP muxers for each stream in the AVFormatContext to build RTP packets from the enc...
Definition: whip.c:1493
ff_avio_class
const AVClass ff_avio_class
Definition: avio.c:98
av_random_bytes
int av_random_bytes(uint8_t *buf, size_t len)
Generate cryptographically secure random data, i.e.
Definition: random_seed.c:159
AVFormatContext::max_delay
int max_delay
Definition: avformat.h:1409
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:256
AVFMT_EXPERIMENTAL
#define AVFMT_EXPERIMENTAL
The muxer/demuxer is experimental and should be used with caution.
Definition: avformat.h:475
setup_srtp
static int setup_srtp(AVFormatContext *s)
Establish the SRTP context using the keying material exported from DTLS.
Definition: whip.c:1355
OFFSET
#define OFFSET(x)
Definition: whip.c:1899
WHIPContext::whip_offer_time
int64_t whip_offer_time
Definition: whip.c:264
ff_srtp_set_crypto
int ff_srtp_set_crypto(struct SRTPContext *s, const char *suite, const char *params)
Definition: srtp.c:66
nal.h
WHIP_STATE_DTLS_CONNECTING
@ WHIP_STATE_DTLS_CONNECTING
Definition: whip.c:194
write_packet
static int write_packet(Muxer *mux, OutputStream *ost, AVPacket *pkt)
Definition: ffmpeg_mux.c:209
WHIPContext::whip_starttime
int64_t whip_starttime
Definition: whip.c:262
avcodec.h
ffurl_closep
int ffurl_closep(URLContext **hh)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition: avio.c:589
AVFMT_FLAG_BITEXACT
#define AVFMT_FLAG_BITEXACT
When muxing, try to avoid writing any random/volatile data to the output.
Definition: avformat.h:1432
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:744
ff_http_get_new_location
const char * ff_http_get_new_location(URLContext *h)
Definition: http.c:565
AVClass::class_name
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:81
AVFormatContext::oformat
const struct AVOutputFormat * oformat
The output container format.
Definition: avformat.h:1283
sps
static int FUNC() sps(CodedBitstreamContext *ctx, RWContext *rw, H264RawSPS *current)
Definition: cbs_h264_syntax_template.c:260
whip_write_packet
static int whip_write_packet(AVFormatContext *s, AVPacket *pkt)
Definition: whip.c:1782
WHIPContext::buf
char buf[MAX_UDP_BUFFER_SIZE]
Definition: whip.c:299
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:122
WHIPContext::dtls_srtp_materials
uint8_t dtls_srtp_materials[(DTLS_SRTP_KEY_LEN+DTLS_SRTP_SALT_LEN) *2]
This represents the material used to build the SRTP master key.
Definition: whip.c:282
AV_PROFILE_H264_CONSTRAINED
#define AV_PROFILE_H264_CONSTRAINED
Definition: defs.h:107
network.h
tls.h
av_get_media_type_string
const char * av_get_media_type_string(enum AVMediaType media_type)
Return a string describing the media_type enum, NULL if media_type is unknown.
Definition: utils.c:28
ff_dtls_export_materials
int ff_dtls_export_materials(URLContext *h, char *dtls_srtp_materials, size_t materials_sz)
Definition: tls_openssl.c:464
random_seed.h
MAX_URL_SIZE
#define MAX_URL_SIZE
Definition: internal.h:30
state
static struct @521 state
WHIP_STATE_UDP_CONNECTED
@ WHIP_STATE_UDP_CONNECTED
Definition: whip.c:188
buffer
the frame and frame reference mechanism is intended to as much as expensive copies of that data while still allowing the filters to produce correct results The data is stored in buffers represented by AVFrame structures Several references can point to the same frame buffer
Definition: filter_design.txt:49
media_is_rtcp
static int media_is_rtcp(const uint8_t *b, int size)
Definition: whip.c:1130
av_crc
uint32_t av_crc(const AVCRC *ctx, uint32_t crc, const uint8_t *buffer, size_t length)
Calculate the CRC of a block.
Definition: crc.c:392
WHIPContext::av_class
AVClass * av_class
Definition: whip.c:206
WHIP_STATE_ICE_CONNECTING
@ WHIP_STATE_ICE_CONNECTING
Definition: whip.c:190
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition: opt.h:259
avformat_free_context
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Definition: avformat.c:141
WHIP_RTP_PAYLOAD_TYPE_OPUS
#define WHIP_RTP_PAYLOAD_TYPE_OPUS
Definition: whip.c:123
av_base64_encode
char * av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size)
Encode data to base64 and null-terminate.
Definition: base64.c:147
AVPacket::stream_index
int stream_index
Definition: packet.h:560
WHIPContext::whip_answer_time
int64_t whip_answer_time
Definition: whip.c:265
ff_tls_set_external_socket
int ff_tls_set_external_socket(URLContext *h, URLContext *sock)
Definition: tls_openssl.c:451
WHIPContext::ice_protocol
char * ice_protocol
This represents the ICE candidate protocol, priority, host and port.
Definition: whip.c:252
WHIP_RTP_HEADER_SIZE
#define WHIP_RTP_HEADER_SIZE
The RTP header is 12 bytes long, comprising the Version(1B), PT(1B), SequenceNumber(2B),...
Definition: whip.c:138
avio_skip
int64_t avio_skip(AVIOContext *s, int64_t offset)
Skip given number of bytes forward.
Definition: aviobuf.c:321
avio_wb64
void avio_wb64(AVIOContext *s, uint64_t val)
Definition: aviobuf.c:434
AV_CRC_32_IEEE_LE
@ AV_CRC_32_IEEE_LE
Definition: crc.h:53
av_dict_set_int
int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags)
Convenience wrapper for av_dict_set() that converts the value to a string and stores it.
Definition: dict.c:177
AVIO_FLAG_READ
#define AVIO_FLAG_READ
read-only
Definition: avio.h:617
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:272
desc
const char * desc
Definition: libsvtav1.c:79
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:200
av_guess_format
const AVOutputFormat * av_guess_format(const char *short_name, const char *filename, const char *mime_type)
Return the output format in the list of registered output formats which best matches the provided par...
Definition: format.c:79
ff_ssl_read_key_cert
int ff_ssl_read_key_cert(char *key_url, char *cert_url, char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint)
Definition: tls_openssl.c:116
mem.h
AVCodecParameters::video_delay
int video_delay
Video only.
Definition: codec_par.h:175
MAX_CERTIFICATE_SIZE
#define MAX_CERTIFICATE_SIZE
Maximum size limit of a certificate and private key size.
Definition: tls.h:35
AVFormatContext::start_time_realtime
int64_t start_time_realtime
Start time of the stream in real world time, in microseconds since the Unix epoch (00:00 1st January ...
Definition: avformat.h:1509
AVIOContext::buffer
unsigned char * buffer
Start of the buffer.
Definition: avio.h:225
ff_ssl_gen_key_cert
int ff_ssl_gen_key_cert(char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint)
Definition: tls_openssl.c:341
WHIPContext::authorization
char * authorization
The optional Bearer token for WHIP Authorization.
Definition: whip.c:312
WHIPContext::srtp_rtcp_send
SRTPContext srtp_rtcp_send
Definition: whip.c:292
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
ffurl_handshake
int ffurl_handshake(URLContext *c)
Perform one step of the protocol handshake to accept a new client.
Definition: avio.c:284
AVCodecParameters::codec_id
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:55
WHIP_RTCP_PT_END
#define WHIP_RTCP_PT_END
Definition: whip.c:151
AVPacket
This structure stores compressed data.
Definition: packet.h:535
WHIPContext::ice_pwd_local
char ice_pwd_local[33]
Definition: whip.c:227
AVIO_FLAG_NONBLOCK
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition: avio.h:636
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
av_dict_set
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:86
avio_find_protocol_name
const char * avio_find_protocol_name(const char *url)
Return the name of the protocol that will handle the passed URL.
Definition: avio.c:658
h264.h
avio_wb16
void avio_wb16(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:446
DTLS_VERSION_10
#define DTLS_VERSION_10
The DTLS version number, which is 0xfeff for DTLS 1.0, or 0xfefd for DTLS 1.2.
Definition: whip.c:109
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
ice_is_binding_response
static int ice_is_binding_response(uint8_t *b, int size)
A Binding response has class=0b10 (success response) and method=0b000000000001, and is encoded into t...
Definition: whip.c:1112
avcodec_descriptor_get
const AVCodecDescriptor * avcodec_descriptor_get(enum AVCodecID id)
Definition: codec_desc.c:3815
WHIPContext::audio_ssrc
uint32_t audio_ssrc
Definition: whip.c:229
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition: opt.h:276
AV_RB24
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_RB24
Definition: bytestream.h:97
WHIPContext::audio_payload_type
uint8_t audio_payload_type
Definition: whip.c:235
http.h
codec_desc.h
ff_nal_find_startcode
const uint8_t * ff_nal_find_startcode(const uint8_t *p, const uint8_t *end)
Definition: nal.c:68
snprintf
#define snprintf
Definition: snprintf.h:34
H264_NAL_IDR_SLICE
@ H264_NAL_IDR_SLICE
Definition: h264.h:39
ff_stream_add_bitstream_filter
int ff_stream_add_bitstream_filter(AVStream *st, const char *name, const char *args)
Add a bitstream filter to a stream.
Definition: mux.c:1294
ff_format_set_url
void ff_format_set_url(AVFormatContext *s, char *url)
Set AVFormatContext url field to the provided pointer.
Definition: avformat.c:861
WHIPContext::video_par
AVCodecParameters * video_par
Definition: whip.c:213
hmac.h
WHIP_STATE_NEGOTIATED
@ WHIP_STATE_NEGOTIATED
After parsing the answer received from the peer, the muxer negotiates the abilities in the offer that...
Definition: whip.c:186
ffurl_get_file_handle
int ffurl_get_file_handle(URLContext *h)
Return the file descriptor associated with this URL.
Definition: avio.c:815
avcodec_parameters_copy
int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src)
Copy the contents of src to dst.
Definition: codec_par.c:107
WHIPContext::pkt_size
int pkt_size
The size of RTP packet, should generally be set to MTU.
Definition: whip.c:307
AVIOContext::av_class
const AVClass * av_class
A class for private options.
Definition: avio.h:173
AV_RB16
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_WB24 unsigned int_TMPL AV_RB16
Definition: bytestream.h:98
MAX_SDP_SIZE
#define MAX_SDP_SIZE
Maximum size limit of a Session Description Protocol (SDP), be it an offer or answer.
Definition: whip.c:50
avio_feof
int avio_feof(AVIOContext *s)
Similar to feof() but also returns nonzero on read errors.
Definition: aviobuf.c:349
ffurl_read
static int ffurl_read(URLContext *h, uint8_t *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf.
Definition: url.h:181
mux.h
ff_write_chained
int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt, AVFormatContext *src, int interleave)
Write a packet to another muxer than the one the user originally intended.
Definition: mux.c:1337