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