summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--gnu/local.mk7
-rw-r--r--gnu/packages/jami.scm266
-rw-r--r--gnu/packages/patches/ffmpeg-jami-change-RTCP-ratio.patch27
-rw-r--r--gnu/packages/patches/ffmpeg-jami-libopusdec-enable-FEC.patch127
-rw-r--r--gnu/packages/patches/ffmpeg-jami-libopusenc-enable-FEC.patch50
-rw-r--r--gnu/packages/patches/ffmpeg-jami-libopusenc-reload-packet-loss-at-encode.patch44
-rw-r--r--gnu/packages/patches/ffmpeg-jami-remove-mjpeg-log.patch26
-rw-r--r--gnu/packages/patches/ffmpeg-jami-rtp_ext_abs_send_time.patch71
-rw-r--r--gnu/packages/patches/ffmpeg-jami-screen-sharing-x11-fix.patch302
-rw-r--r--gnu/packages/video.scm248
10 files changed, 901 insertions, 267 deletions
diff --git a/gnu/local.mk b/gnu/local.mk
index 5b59aba3af..63d2e333cf 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1167,6 +1167,13 @@ dist_patch_DATA =						\
   %D%/packages/patches/fenics-dolfin-demo-init.patch		\
   %D%/packages/patches/fenics-dolfin-boost.patch		\
   %D%/packages/patches/fenics-dolfin-config-slepc.patch		\
+  %D%/packages/patches/ffmpeg-jami-change-RTCP-ratio.patch	\
+  %D%/packages/patches/ffmpeg-jami-rtp_ext_abs_send_time.patch	\
+  %D%/packages/patches/ffmpeg-jami-libopusdec-enable-FEC.patch	\
+  %D%/packages/patches/ffmpeg-jami-libopusenc-enable-FEC.patch	\
+  %D%/packages/patches/ffmpeg-jami-libopusenc-reload-packet-loss-at-encode.patch \
+  %D%/packages/patches/ffmpeg-jami-remove-mjpeg-log.patch	\
+  %D%/packages/patches/ffmpeg-jami-screen-sharing-x11-fix.patch	\
   %D%/packages/patches/fifengine-boost-compat.patch		\
   %D%/packages/patches/fifengine-swig-compat.patch		\
   %D%/packages/patches/fifo-map-fix-flags-for-gcc.patch		\
diff --git a/gnu/packages/jami.scm b/gnu/packages/jami.scm
index 3037d090d3..c035a966c7 100644
--- a/gnu/packages/jami.scm
+++ b/gnu/packages/jami.scm
@@ -89,272 +89,6 @@
     (patches (search-patches "jami-disable-integration-tests.patch"
                              "jami-libjami-headers-search.patch"))))
 
-;; Jami maintains a set of patches for some key dependencies (currently
-;; pjproject and ffmpeg) of Jami that haven't yet been integrated upstream.
-;; This procedure simplifies the process of applying them.
-(define jami-apply-custom-patches
-  #~(lambda* (#:key dep-name patches)
-      (let ((patches-directory "patches"))
-        (mkdir-p patches-directory)
-        (invoke "tar" "-xvf" #$%jami-sources
-                "-C" patches-directory
-                "--strip-components=5"
-                "--wildcards"
-                (string-append "jami-*/daemon/contrib/src/" dep-name))
-        (for-each (lambda (f)
-                    (invoke "patch" "--force" "--ignore-whitespace" "-p1" "-i"
-                            (string-append patches-directory "/" f ".patch")))
-                  patches))))
-
-;; The following variables are configure flags used by ffmpeg-jami.  They're
-;; from the jami/daemon/contrib/src/ffmpeg/rules.mak file.  We try to keep it
-;; as close to the official Jami package as possible, to provide all the
-;; codecs and extra features that are expected (see:
-;; https://review.jami.net/plugins/gitiles/jami-daemon/+/refs/heads/master/contrib/src/ffmpeg/rules.mak).
-;; An exception are the ffnvcodec-related switches, which is not packaged in
-;; Guix and would not work with Mesa.
-(define %ffmpeg-default-configure-flags
-  '("--disable-everything"
-    "--enable-zlib"
-    "--enable-gpl"
-    "--enable-swscale"
-    "--enable-bsfs"
-    "--disable-filters"
-    "--disable-programs"
-    "--disable-postproc"
-    "--disable-protocols"
-    "--enable-protocol=crypto"
-    "--enable-protocol=file"
-    "--enable-protocol=rtp"
-    "--enable-protocol=srtp"
-    "--enable-protocol=tcp"
-    "--enable-protocol=udp"
-    "--enable-protocol=unix"
-    "--enable-protocol=pipe"
-
-    ;; Enable muxers/demuxers.
-    "--disable-demuxers"
-    "--disable-muxers"
-    "--enable-muxer=rtp"
-    "--enable-muxer=g722"
-    "--enable-muxer=g726"
-    "--enable-muxer=g726le"
-    "--enable-muxer=h263"
-    "--enable-muxer=h264"
-    "--enable-muxer=hevc"
-    "--enable-muxer=matroska"
-    "--enable-muxer=wav"
-    "--enable-muxer=webm"
-    "--enable-muxer=ogg"
-    "--enable-muxer=pcm_s16be"
-    "--enable-muxer=pcm_s16le"
-    "--enable-demuxer=rtp"
-    "--enable-demuxer=mjpeg"
-    "--enable-demuxer=mjpeg_2000"
-    "--enable-demuxer=mpegvideo"
-    "--enable-demuxer=gif"
-    "--enable-demuxer=image_jpeg_pipe"
-    "--enable-demuxer=image_png_pipe"
-    "--enable-demuxer=image_webp_pipe"
-    "--enable-demuxer=matroska"
-    "--enable-demuxer=m4v"
-    "--enable-demuxer=mp3"
-    "--enable-demuxer=ogg"
-    "--enable-demuxer=flac"
-    "--enable-demuxer=wav"
-    "--enable-demuxer=ac3"
-    "--enable-demuxer=g722"
-    "--enable-demuxer=g723_1"
-    "--enable-demuxer=g726"
-    "--enable-demuxer=g726le"
-    "--enable-demuxer=pcm_mulaw"
-    "--enable-demuxer=pcm_alaw"
-    "--enable-demuxer=pcm_s16be"
-    "--enable-demuxer=pcm_s16le"
-    "--enable-demuxer=h263"
-    "--enable-demuxer=h264"
-    "--enable-demuxer=hevc"
-
-    ;; Enable parsers.
-    "--enable-parser=h263"
-    "--enable-parser=h264"
-    "--enable-parser=hevc"
-    "--enable-parser=mpeg4video"
-    "--enable-parser=vp8"
-    "--enable-parser=vp9"
-    "--enable-parser=opus"
-
-    ;; Encoders/decoders.
-    "--enable-encoder=adpcm_g722"
-    "--enable-decoder=adpcm_g722"
-    "--enable-encoder=adpcm_g726"
-    "--enable-decoder=adpcm_g726"
-    "--enable-encoder=adpcm_g726le"
-    "--enable-decoder=adpcm_g726le"
-    "--enable-decoder=g729"
-    "--enable-encoder=g723_1"
-    "--enable-decoder=g723_1"
-    "--enable-encoder=rawvideo"
-    "--enable-decoder=rawvideo"
-    "--enable-encoder=libx264"
-    "--enable-decoder=h264"
-    "--enable-encoder=pcm_alaw"
-    "--enable-decoder=pcm_alaw"
-    "--enable-encoder=pcm_mulaw"
-    "--enable-decoder=pcm_mulaw"
-    "--enable-encoder=mpeg4"
-    "--enable-decoder=mpeg4"
-    "--enable-encoder=libvpx_vp8"
-    "--enable-decoder=vp8"
-    "--enable-decoder=vp9"
-    "--enable-encoder=h263"
-    "--enable-encoder=h263p"
-    "--enable-decoder=h263"
-    "--enable-encoder=mjpeg"
-    "--enable-decoder=mjpeg"
-    "--enable-decoder=mjpegb"
-    "--enable-libspeex"
-    "--enable-libopus"
-    "--enable-libvpx"
-    "--enable-libx264"
-    "--enable-encoder=libspeex"
-    "--enable-decoder=libspeex"
-    "--enable-encoder=libopus"
-    "--enable-decoder=libopus"
-
-    ;; Encoders/decoders for ringtones and audio streaming.
-    "--enable-decoder=flac"
-    "--enable-decoder=vorbis"
-    "--enable-decoder=aac"
-    "--enable-decoder=ac3"
-    "--enable-decoder=eac3"
-    "--enable-decoder=mp3"
-    "--enable-decoder=pcm_u24le"
-    "--enable-decoder=pcm_u32le"
-    "--enable-decoder=pcm_u8"
-    "--enable-decoder=pcm_f16le"
-    "--enable-decoder=pcm_f32le"
-    "--enable-decoder=pcm_f64le"
-    "--enable-decoder=pcm_s16le"
-    "--enable-decoder=pcm_s24le"
-    "--enable-decoder=pcm_s32le"
-    "--enable-decoder=pcm_s64le"
-    "--enable-decoder=pcm_u16le"
-    "--enable-encoder=pcm_u8"
-    "--enable-encoder=pcm_f32le"
-    "--enable-encoder=pcm_f64le"
-    "--enable-encoder=pcm_s16le"
-    "--enable-encoder=pcm_s32le"
-    "--enable-encoder=pcm_s64le"
-
-    "--enable-decoder=pcm_s16be"
-    "--enable-decoder=pcm_s16be_planar"
-    "--enable-decoder=pcm_s16le_planar"
-    "--enable-decoder=pcm_s24be"
-    "--enable-decoder=pcm_s24le_planar"
-    "--enable-decoder=pcm_s32be"
-    "--enable-decoder=pcm_s32le_planar"
-    "--enable-decoder=pcm_s64be"
-    "--enable-decoder=pcm_s8"
-    "--enable-decoder=pcm_s8_planar"
-    "--enable-decoder=pcm_u16be"
-
-    ;; Encoders/decoders for images.
-    "--enable-encoder=gif"
-    "--enable-decoder=gif"
-    "--enable-encoder=jpegls"
-    "--enable-decoder=jpegls"
-    "--enable-encoder=ljpeg"
-    "--enable-decoder=jpeg2000"
-    "--enable-encoder=png"
-    "--enable-decoder=png"
-    "--enable-encoder=bmp"
-    "--enable-decoder=bmp"
-    "--enable-encoder=tiff"
-    "--enable-decoder=tiff"
-
-    ;; Filters.
-    "--enable-filter=scale"
-    "--enable-filter=overlay"
-    "--enable-filter=amix"
-    "--enable-filter=amerge"
-    "--enable-filter=aresample"
-    "--enable-filter=format"
-    "--enable-filter=aformat"
-    "--enable-filter=fps"
-    "--enable-filter=transpose"
-    "--enable-filter=pad"
-
-    "--enable-filter=afir"
-    "--enable-filter=split"
-    "--enable-filter=drawbox"
-    "--enable-filter=drawtext"
-    "--enable-filter=rotate"
-    "--enable-filter=loop"
-    "--enable-filter=setpts"
-    "--enable-filter=movie"
-    "--enable-filter=alphamerge"
-    "--enable-filter=boxblur"
-    "--enable-filter=lut"
-    "--enable-filter=negate"
-    "--enable-filter=colorkey"
-    "--enable-filter=transpose"))
-
-(define %ffmpeg-linux-configure-flags
-  '("--enable-pic"
-    "--extra-cxxflags=-fPIC"
-    "--extra-cflags=-fPIC"
-    "--target-os=linux"
-    "--enable-indev=v4l2"
-    "--enable-indev=xcbgrab"
-    "--enable-vdpau"
-    "--enable-hwaccel=h264_vdpau"
-    "--enable-hwaccel=mpeg4_vdpau"
-    "--enable-vaapi"
-    "--enable-hwaccel=h264_vaapi"
-    "--enable-hwaccel=mpeg4_vaapi"
-    "--enable-hwaccel=h263_vaapi"
-    "--enable-hwaccel=vp8_vaapi"
-    "--enable-hwaccel=mjpeg_vaapi"
-    "--enable-hwaccel=hevc_vaapi"
-    "--enable-encoder=h264_vaapi"
-    "--enable-encoder=vp8_vaapi"
-    "--enable-encoder=mjpeg_vaapi"
-    "--enable-encoder=hevc_vaapi"))
-
-(define (ffmpeg-compose-configure-flags)
-  "Compose the configure flag lists of ffmpeg-jami."
-  #~(append '#$%ffmpeg-default-configure-flags
-            (if (string-contains #$(%current-system) "linux")
-                '#$%ffmpeg-linux-configure-flags
-                '())))
-
-(define-public ffmpeg-jami
-  (package
-    (inherit ffmpeg)
-    (name "ffmpeg-jami")
-    (arguments
-     (substitute-keyword-arguments (package-arguments ffmpeg)
-       ((#:configure-flags _ '())
-        #~(cons* "--disable-static"
-                 "--enable-shared"
-                 "--disable-stripping"
-                 #$(ffmpeg-compose-configure-flags)))
-       ((#:phases phases)
-        #~(modify-phases #$phases
-            (add-after 'unpack 'apply-patches
-              (lambda _
-                ;; These patches come from:
-                ;; "jami-project/daemon/contrib/src/ffmpeg/rules.mak".
-                (#$jami-apply-custom-patches
-                 #:dep-name "ffmpeg"
-                 #:patches '("remove-mjpeg-log"
-                             "change-RTCP-ratio"
-                             "rtp_ext_abs_send_time"
-                             "libopusdec-enable-FEC"
-                             "libopusenc-reload-packet-loss-at-encode"
-                             "screen-sharing-x11-fix"))))))))))
-
 (define-public libjami
   (package
     (name "libjami")
diff --git a/gnu/packages/patches/ffmpeg-jami-change-RTCP-ratio.patch b/gnu/packages/patches/ffmpeg-jami-change-RTCP-ratio.patch
new file mode 100644
index 0000000000..6248165d8c
--- /dev/null
+++ b/gnu/packages/patches/ffmpeg-jami-change-RTCP-ratio.patch
@@ -0,0 +1,27 @@
+From a884b62c9e6f23b9f4369d724e25db2f42dad28d Mon Sep 17 00:00:00 2001
+From: Pierre LESPAGNOL <pierre.lespagnol@savoirfairelinux.com>
+Date: Tue, 28 May 2019 16:18:20 -0400
+Subject: [PATCH] Changement du ratio de 0.5% a 5%
+
+---
+ libavformat/rtp.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/libavformat/rtp.h b/libavformat/rtp.h
+index 54512c6f71..16916ff86a 100644
+--- a/libavformat/rtp.h
++++ b/libavformat/rtp.h
+@@ -78,8 +78,8 @@ enum AVCodecID ff_rtp_codec_id(const char *buf, enum AVMediaType codec_type);
+ #define RTP_VERSION 2
+ #define RTP_MAX_SDES 256   /**< maximum text length for SDES */
+ 
+-/* RTCP packets use 0.5% of the bandwidth */
+-#define RTCP_TX_RATIO_NUM 5
++/* RTCP packets use 2.5% of the bandwidth */
++#define RTCP_TX_RATIO_NUM 25
+ #define RTCP_TX_RATIO_DEN 1000
+ 
+ /* An arbitrary id value for RTP Xiph streams - only relevant to indicate
+-- 
+2.17.1
+
diff --git a/gnu/packages/patches/ffmpeg-jami-libopusdec-enable-FEC.patch b/gnu/packages/patches/ffmpeg-jami-libopusdec-enable-FEC.patch
new file mode 100644
index 0000000000..fb9466a4fc
--- /dev/null
+++ b/gnu/packages/patches/ffmpeg-jami-libopusdec-enable-FEC.patch
@@ -0,0 +1,127 @@
+diff --git a/libavcodec/libopusdec.c b/libavcodec/libopusdec.c
+index 9b9a610343..8ec5bfc1ad 100644
+--- a/libavcodec/libopusdec.c
++++ b/libavcodec/libopusdec.c
+@@ -45,6 +45,8 @@ struct libopus_context {
+ #ifdef OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST
+     int apply_phase_inv;
+ #endif
++    int decode_fec;
++    int64_t expected_next_pts;
+ };
+ 
+ #define OPUS_HEAD_SIZE 19
+@@ -141,6 +143,8 @@ static av_cold int libopus_decode_init(AVCodecContext *avc)
+     /* Decoder delay (in samples) at 48kHz */
+     avc->delay = avc->internal->skip_samples = opus->pre_skip;
+ 
++    opus->expected_next_pts = AV_NOPTS_VALUE;
++
+     return 0;
+ }
+ 
+@@ -161,27 +165,82 @@ static int libopus_decode(AVCodecContext *avc, AVFrame *frame,
+                           int *got_frame_ptr, AVPacket *pkt)
+ {
+     struct libopus_context *opus = avc->priv_data;
+-    int ret, nb_samples;
++    uint8_t *outptr;
++    int ret, nb_samples = 0, nb_lost_samples = 0, nb_samples_left;
++
++    // If FEC is enabled, calculate number of lost samples
++    if (opus->decode_fec &&
++        opus->expected_next_pts != AV_NOPTS_VALUE &&
++        pkt->pts != AV_NOPTS_VALUE &&
++        pkt->pts != opus->expected_next_pts) {
++        // Cap at recovering 120 ms of lost audio.
++        nb_lost_samples = pkt->pts - opus->expected_next_pts;
++        nb_lost_samples = FFMIN(nb_lost_samples, MAX_FRAME_SIZE);
++    }
+ 
+-    frame->nb_samples = MAX_FRAME_SIZE;
++    frame->nb_samples = MAX_FRAME_SIZE + nb_lost_samples;
+     if ((ret = ff_get_buffer(avc, frame, 0)) < 0)
+         return ret;
+ 
++    outptr = frame->data[0];
++    nb_samples_left = frame->nb_samples;
++
++    if (opus->decode_fec && nb_lost_samples) {
++        // Try to recover the lost samples with FEC data from this one.
++        // If there's no FEC data, the decoder will do loss concealment instead.
++        if (avc->sample_fmt == AV_SAMPLE_FMT_S16)
++             nb_samples = opus_multistream_decode(opus->dec, pkt->data, pkt->size,
++                                                  (opus_int16 *)outptr,
++                                                  nb_lost_samples, 1);
++        else
++            nb_samples = opus_multistream_decode_float(opus->dec, pkt->data, pkt->size,
++                                                       (float *)outptr,
++                                                       nb_lost_samples, 1);
++
++        if (nb_samples < 0) {
++            av_log(avc, AV_LOG_ERROR, "Decoding error: %s\n",
++                   opus_strerror(nb_samples));
++            return ff_opus_error_to_averror(nb_samples);
++        }
++
++        av_log(avc, AV_LOG_WARNING, "Recovered %d samples with FEC/PLC\n",
++                   nb_samples);
++
++        outptr += nb_samples * avc->channels * av_get_bytes_per_sample(avc->sample_fmt);
++        nb_samples_left -= nb_samples;
++        if (pkt->pts != AV_NOPTS_VALUE) {
++            pkt->pts -= nb_samples;
++            frame->pts = pkt->pts;
++        }
++    }
++
++    // Decode the actual, non-lost data.
+     if (avc->sample_fmt == AV_SAMPLE_FMT_S16)
+-        nb_samples = opus_multistream_decode(opus->dec, pkt->data, pkt->size,
+-                                             (opus_int16 *)frame->data[0],
+-                                             frame->nb_samples, 0);
++        ret = opus_multistream_decode(opus->dec, pkt->data, pkt->size,
++                                      (opus_int16 *)outptr,
++                                      nb_samples_left, 0);
+     else
+-        nb_samples = opus_multistream_decode_float(opus->dec, pkt->data, pkt->size,
+-                                                   (float *)frame->data[0],
+-                                                   frame->nb_samples, 0);
++        ret = opus_multistream_decode_float(opus->dec, pkt->data, pkt->size,
++                                            (float *)outptr,
++                                            nb_samples_left, 0);
+ 
+-    if (nb_samples < 0) {
++    if (ret < 0) {
+         av_log(avc, AV_LOG_ERROR, "Decoding error: %s\n",
+-               opus_strerror(nb_samples));
+-        return ff_opus_error_to_averror(nb_samples);
++               opus_strerror(ret));
++        return ff_opus_error_to_averror(ret);
+     }
+ 
++    nb_samples += ret;
++
++    if (opus->decode_fec)
++    {
++        // Calculate the next expected pts
++        if (pkt->pts == AV_NOPTS_VALUE) {
++            opus->expected_next_pts = AV_NOPTS_VALUE;
++        } else {
++            opus->expected_next_pts = pkt->pts + nb_samples;
++        }
++    }
+ #ifndef OPUS_SET_GAIN
+     {
+         int i = avc->ch_layout.nb_channels * nb_samples;
+@@ -220,6 +279,7 @@ static const AVOption libopusdec_options[] = {
+ #ifdef OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST
+     { "apply_phase_inv", "Apply intensity stereo phase inversion", OFFSET(apply_phase_inv), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS },
+ #endif
++    { "decode_fec", "Decode FEC data or use PLC", OFFSET(decode_fec), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
+     { NULL },
+ };
+ 
+-- 
+2.34.1
+
diff --git a/gnu/packages/patches/ffmpeg-jami-libopusenc-enable-FEC.patch b/gnu/packages/patches/ffmpeg-jami-libopusenc-enable-FEC.patch
new file mode 100644
index 0000000000..43b786c567
--- /dev/null
+++ b/gnu/packages/patches/ffmpeg-jami-libopusenc-enable-FEC.patch
@@ -0,0 +1,50 @@
+diff --git a/libavcodec/libopusencc.c b/libavcodec/libopusencc.c
+index 2a97811d18..40ee7b8fec 100644
+--- a/libavcodec/libopusenc.c
++++ b/libavcodec/libopusenc.c
+@@ -33,6 +33,7 @@
+ typedef struct LibopusEncOpts {
+     int vbr;
+     int application;
++    int enable_fec;
+     int packet_loss;
+     int complexity;
+     float frame_duration;
+@@ -143,6 +144,13 @@
+                "Unable to set constrained VBR: %s\n", opus_strerror(ret));
+
+     ret = opus_multistream_encoder_ctl(enc,
++                                       OPUS_SET_INBAND_FEC(opts->enable_fec));
++    if (ret != OPUS_OK)
++        av_log(avctx, AV_LOG_WARNING,
++               "Unable to set enable FEC flag percentage: %s\n",
++               opus_strerror(ret));
++
++    ret = opus_multistream_encoder_ctl(enc,
+                                        OPUS_SET_PACKET_LOSS_PERC(opts->packet_loss));
+     if (ret != OPUS_OK)
+         av_log(avctx, AV_LOG_WARNING,
+@@ -452,6 +460,15 @@
+     int ret;
+     int discard_padding;
+ 
++    // Reload packet loss setting
++    ret = opus_multistream_encoder_ctl(opus->enc,
++                                       OPUS_SET_PACKET_LOSS_PERC(opus->opts.packet_loss));
++    if (ret != OPUS_OK)
++        av_log(avctx, AV_LOG_WARNING,
++               "Unable to set expected packet loss percentage: %s\n",
++               opus_strerror(ret));
++
++
+     if (frame) {
+         ret = ff_af_queue_add(&opus->afq, frame);
+         if (ret < 0)
+@@ -543,6 +560,7 @@
+         { "audio",          "Favor faithfulness to the input",         0, AV_OPT_TYPE_CONST, { .i64 = OPUS_APPLICATION_AUDIO },               0, 0, FLAGS, "application" },
+         { "lowdelay",       "Restrict to only the lowest delay modes", 0, AV_OPT_TYPE_CONST, { .i64 = OPUS_APPLICATION_RESTRICTED_LOWDELAY }, 0, 0, FLAGS, "application" },
+     { "frame_duration", "Duration of a frame in milliseconds", OFFSET(frame_duration), AV_OPT_TYPE_FLOAT, { .dbl = 20.0 }, 2.5, 120.0, FLAGS },
++    { "enable_fec",     "Enable forward error correction",     OFFSET(enable_fec),     AV_OPT_TYPE_BOOL,  { .i64 = 0 },    0,   1,     FLAGS },
+     { "packet_loss",    "Expected packet loss percentage",     OFFSET(packet_loss),    AV_OPT_TYPE_INT,   { .i64 = 0 },    0,   100,  FLAGS },
+     { "vbr",            "Variable bit rate mode",              OFFSET(vbr),            AV_OPT_TYPE_INT,   { .i64 = 1 },    0,   2,    FLAGS, "vbr" },
+         { "off",            "Use constant bit rate", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FLAGS, "vbr" },
diff --git a/gnu/packages/patches/ffmpeg-jami-libopusenc-reload-packet-loss-at-encode.patch b/gnu/packages/patches/ffmpeg-jami-libopusenc-reload-packet-loss-at-encode.patch
new file mode 100644
index 0000000000..5c4bd4d3eb
--- /dev/null
+++ b/gnu/packages/patches/ffmpeg-jami-libopusenc-reload-packet-loss-at-encode.patch
@@ -0,0 +1,44 @@
+From dba13d03bc8e827fededc20b0ab1f574a1500f2a Mon Sep 17 00:00:00 2001
+From: Philip-Dylan Gleonec <philip-dylan.gleonec@savoirfairelinux.com>
+Date: Thu, 11 Feb 2021 12:25:14 +0100
+Subject: [PATCH 2/2] avcodec/libopusenc: reload packet loss at encode
+
+An estimation of packet loss is required by libopus to compute its FEC
+data. Currently, this estimation is constant, and can not be changed
+after configuration. This means an application using libopus through
+ffmpeg can not adapt the packet loss estimation when the network
+quality degrades.
+
+This patch makes the encoder reload the packet_loss AVOption before
+encoding samples, if fec is enabled. This way an application can modify
+the packet loss estimation by changing the AVOption. Typical use-case
+is a RTP stream, where packet loss can be estimated from RTCP packets.
+
+Signed-off-by: Philip-Dylan Gleonec <philip-dylan.gleonec@savoirfairelinux.com>
+---
+ libavcodec/libopusenc.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/libavcodec/libopusenc.c b/libavcodec/libopusenc.c
+index 70d17f802b..c18e8ae7fa 100644
+--- a/libavcodec/libopusenc.c
++++ b/libavcodec/libopusenc.c
+@@ -460,6 +460,15 @@ static int libopus_encode(AVCodecContext *avctx, AVPacket *avpkt,
+     int ret;
+     int discard_padding;
+ 
++    if (opus->opts.fec) {
++        ret = opus_multistream_encoder_ctl(opus->enc,
++                                           OPUS_SET_PACKET_LOSS_PERC(opus->opts.packet_loss));
++        if (ret != OPUS_OK)
++            av_log(avctx, AV_LOG_WARNING,
++                   "Unable to set expected packet loss percentage: %s\n",
++                   opus_strerror(ret));
++    }
++
+     if (frame) {
+         ret = ff_af_queue_add(&opus->afq, frame);
+         if (ret < 0)
+-- 
+2.25.1
+
diff --git a/gnu/packages/patches/ffmpeg-jami-remove-mjpeg-log.patch b/gnu/packages/patches/ffmpeg-jami-remove-mjpeg-log.patch
new file mode 100644
index 0000000000..595baea9c9
--- /dev/null
+++ b/gnu/packages/patches/ffmpeg-jami-remove-mjpeg-log.patch
@@ -0,0 +1,26 @@
+From c557a6211f5a29d89fc2ab561e0fb3d8878fb6ad Mon Sep 17 00:00:00 2001
+From: philippegorley <gorley.philippe@gmail.com>
+Date: Mon, 17 Dec 2018 15:27:57 -0500
+Subject: [PATCH] remove mjpeg log
+
+---
+ libavcodec/mjpegdec.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c
+index d1dca84d36..4a26c23cd4 100644
+--- a/libavcodec/mjpegdec.c
++++ b/libavcodec/mjpegdec.c
+@@ -2294,9 +2294,7 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
+                    "restart marker: %d\n", start_code & 0x0f);
+             /* APP fields */
+         } else if (start_code >= APP0 && start_code <= APP15) {
+-            if ((ret = mjpeg_decode_app(s)) < 0)
+-                av_log(avctx, AV_LOG_ERROR, "unable to decode APP fields: %s\n",
+-                       av_err2str(ret));
++            ret = mjpeg_decode_app(s);
+             /* Comment */
+         } else if (start_code == COM) {
+             ret = mjpeg_decode_com(s);
+--
+2.17.1
diff --git a/gnu/packages/patches/ffmpeg-jami-rtp_ext_abs_send_time.patch b/gnu/packages/patches/ffmpeg-jami-rtp_ext_abs_send_time.patch
new file mode 100644
index 0000000000..cf52cf972a
--- /dev/null
+++ b/gnu/packages/patches/ffmpeg-jami-rtp_ext_abs_send_time.patch
@@ -0,0 +1,71 @@
+diff --git a/libavformat/rtpenc.c b/libavformat/rtpenc.c
+index 63047beccc..d59ec3dc8c 100644
+--- a/libavformat/rtpenc.c
++++ b/libavformat/rtpenc.c
+@@ -28,6 +28,8 @@
+ 
+ #include "rtpenc.h"
+ 
++#define EXT_ABS_SEND_TIME
++
+ static const AVOption options[] = {
+     FF_RTP_FLAG_OPTS(RTPMuxContext, flags),
+     { "payload_type", "Specify RTP payload type", offsetof(RTPMuxContext, payload_type), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 127, AV_OPT_FLAG_ENCODING_PARAM },
+@@ -146,7 +148,11 @@ static int rtp_write_header(AVFormatContext *s1)
+                                     s1->pb->max_packet_size);
+     } else
+         s1->packet_size = s1->pb->max_packet_size;
++#ifdef EXT_ABS_SEND_TIME
++    if (s1->packet_size <= 20) {
++#else
+     if (s1->packet_size <= 12) {
++#endif
+         av_log(s1, AV_LOG_ERROR, "Max packet size %u too low\n", s1->packet_size);
+         return AVERROR(EIO);
+     }
+@@ -154,7 +160,11 @@ static int rtp_write_header(AVFormatContext *s1)
+     if (!s->buf) {
+         return AVERROR(ENOMEM);
+     }
++#ifdef EXT_ABS_SEND_TIME
++    s->max_payload_size = s1->packet_size - 20;
++#else
+     s->max_payload_size = s1->packet_size - 12;
++#endif
+ 
+     if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+         avpriv_set_pts_info(st, 32, 1, st->codecpar->sample_rate);
+@@ -332,16 +342,34 @@ static void rtcp_send_sr(AVFormatContext *s1, int64_t ntp_time, int bye)
+ void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m)
+ {
+     RTPMuxContext *s = s1->priv_data;
++    uint64_t ntp64_time;
++    uint32_t absoluteSendTime;
+ 
+     av_log(s1, AV_LOG_TRACE, "rtp_send_data size=%d\n", len);
+ 
+     /* build the RTP header */
++#ifdef EXT_ABS_SEND_TIME
++    avio_w8(s1->pb, RTP_VERSION << 6 | 0x10); // extention bit
++#else
+     avio_w8(s1->pb, RTP_VERSION << 6);
++#endif
+     avio_w8(s1->pb, (s->payload_type & 0x7f) | ((m & 0x01) << 7));
+     avio_wb16(s1->pb, s->seq);
+     avio_wb32(s1->pb, s->timestamp);
+     avio_wb32(s1->pb, s->ssrc);
+ 
++#ifdef EXT_ABS_SEND_TIME
++    avio_wb16(s1->pb, 0xBEDE);      // magic word
++    avio_wb16(s1->pb, 0x0001);      // length=1
++    avio_w8(s1->pb, 0x32);         // ID=3 and lenght=2
++    ntp64_time = ff_get_formatted_ntp_time(ff_ntp_time());
++    absoluteSendTime = (uint32_t)((ntp64_time>> 14) & 0x00ffffff);
++    av_log(s1, AV_LOG_TRACE, "ntp64:%lu, abs_time:%u\n", ntp64_time, absoluteSendTime);
++    avio_w8(s1->pb, (uint8_t)(absoluteSendTime >> 16));
++    avio_w8(s1->pb, (uint8_t)(absoluteSendTime >> 8 & 0xff));
++    avio_w8(s1->pb, (uint8_t)(absoluteSendTime & 0xff));
++#endif
++
+     avio_write(s1->pb, buf1, len);
+     avio_flush(s1->pb);
diff --git a/gnu/packages/patches/ffmpeg-jami-screen-sharing-x11-fix.patch b/gnu/packages/patches/ffmpeg-jami-screen-sharing-x11-fix.patch
new file mode 100644
index 0000000000..e54a346706
--- /dev/null
+++ b/gnu/packages/patches/ffmpeg-jami-screen-sharing-x11-fix.patch
@@ -0,0 +1,302 @@
+From c1b210534b15188c964b31dc47e172f8ed4aca55 Mon Sep 17 00:00:00 2001
+From: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
+Date: Tue, 19 Jul 2022 13:35:19 -0300
+Subject: [PATCH] Screen sharing x11 fixes
+
++ We can now have a single stream in the x11grab, which can be updated to follow window resizing
++ Due to stream reinit, shm may cause memory issues and was removed
++ Adds one option (is_area) that defines if we are grabing a region of the display/window or the hole screen/window.
+
+note: This is a custom patch for later rebase
+---
+ libavdevice/xcbgrab.c | 186 ++++++++++--------------------------------
+ 1 file changed, 45 insertions(+), 141 deletions(-)
+
+diff --git a/libavdevice/xcbgrab.c b/libavdevice/xcbgrab.c
+index 64a68ba497..76e654b424 100644
+--- a/libavdevice/xcbgrab.c
++++ b/libavdevice/xcbgrab.c
+@@ -29,11 +29,6 @@
+ #include <xcb/xfixes.h>
+ #endif
+ 
+-#if CONFIG_LIBXCB_SHM
+-#include <sys/shm.h>
+-#include <xcb/shm.h>
+-#endif
+-
+ #if CONFIG_LIBXCB_SHAPE
+ #include <xcb/shape.h>
+ #endif
+@@ -53,9 +48,6 @@ typedef struct XCBGrabContext {
+     xcb_connection_t *conn;
+     xcb_screen_t *screen;
+     xcb_window_t window;
+-#if CONFIG_LIBXCB_SHM
+-    AVBufferPool *shm_pool;
+-#endif
+     int64_t time_frame;
+     AVRational time_base;
+     int64_t frame_duration;
+@@ -72,10 +64,9 @@ typedef struct XCBGrabContext {
+     int region_border;
+     int centered;
+     int select_region;
++    int is_area;
+ 
+     const char *framerate;
+-
+-    int has_shm;
+ } XCBGrabContext;
+ 
+ #define FOLLOW_CENTER -1
+@@ -97,6 +88,7 @@ static const AVOption options[] = {
+     { "show_region", "Show the grabbing region.", OFFSET(show_region), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D },
+     { "region_border", "Set the region border thickness.", OFFSET(region_border), AV_OPT_TYPE_INT, { .i64 = 3 }, 1, 128, D },
+     { "select_region", "Select the grabbing region graphically using the pointer.", OFFSET(select_region), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D },
++    { "is_area", "Define if we are grabing a region of the display/window.", OFFSET(is_area), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, D },
+     { NULL },
+ };
+ 
+@@ -216,99 +208,6 @@ static int64_t wait_frame(AVFormatContext *s, AVPacket *pkt)
+     return curtime;
+ }
+ 
+-#if CONFIG_LIBXCB_SHM
+-static int check_shm(xcb_connection_t *conn)
+-{
+-    xcb_shm_query_version_cookie_t cookie = xcb_shm_query_version(conn);
+-    xcb_shm_query_version_reply_t *reply;
+-
+-    reply = xcb_shm_query_version_reply(conn, cookie, NULL);
+-    if (reply) {
+-        free(reply);
+-        return 1;
+-    }
+-
+-    return 0;
+-}
+-
+-static void free_shm_buffer(void *opaque, uint8_t *data)
+-{
+-    shmdt(data);
+-}
+-
+-static AVBufferRef *allocate_shm_buffer(void *opaque, size_t size)
+-{
+-    xcb_connection_t *conn = opaque;
+-    xcb_shm_seg_t segment;
+-    AVBufferRef *ref;
+-    uint8_t *data;
+-    int id;
+-
+-    id = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777);
+-    if (id == -1)
+-        return NULL;
+-
+-    segment = xcb_generate_id(conn);
+-    xcb_shm_attach(conn, segment, id, 0);
+-    data = shmat(id, NULL, 0);
+-    shmctl(id, IPC_RMID, 0);
+-    if ((intptr_t)data == -1 || !data)
+-        return NULL;
+-
+-    ref = av_buffer_create(data, size, free_shm_buffer, (void *)(ptrdiff_t)segment, 0);
+-    if (!ref)
+-        shmdt(data);
+-
+-    return ref;
+-}
+-
+-static int xcbgrab_frame_shm(AVFormatContext *s, AVPacket *pkt)
+-{
+-    XCBGrabContext *c = s->priv_data;
+-    xcb_shm_get_image_cookie_t iq;
+-    xcb_shm_get_image_reply_t *img;
+-    xcb_drawable_t drawable = c->window_id;
+-    xcb_generic_error_t *e = NULL;
+-    AVBufferRef *buf;
+-    xcb_shm_seg_t segment;
+-
+-    buf = av_buffer_pool_get(c->shm_pool);
+-    if (!buf) {
+-        av_log(s, AV_LOG_ERROR, "Could not get shared memory buffer.\n");
+-        return AVERROR(ENOMEM);
+-    }
+-    segment = (xcb_shm_seg_t)(uintptr_t)av_buffer_pool_buffer_get_opaque(buf);
+-
+-    iq = xcb_shm_get_image(c->conn, drawable,
+-                           c->x, c->y, c->width, c->height, ~0,
+-                           XCB_IMAGE_FORMAT_Z_PIXMAP, segment, 0);
+-    img = xcb_shm_get_image_reply(c->conn, iq, &e);
+-
+-    xcb_flush(c->conn);
+-
+-    if (e) {
+-        av_log(s, AV_LOG_ERROR,
+-               "Cannot get the image data "
+-               "event_error: response_type:%u error_code:%u "
+-               "sequence:%u resource_id:%u minor_code:%u major_code:%u.\n",
+-               e->response_type, e->error_code,
+-               e->sequence, e->resource_id, e->minor_code, e->major_code);
+-
+-        free(e);
+-        av_buffer_unref(&buf);
+-        return AVERROR(EACCES);
+-    }
+-
+-    free(img);
+-
+-    pkt->buf = buf;
+-    pkt->data = buf->data;
+-    pkt->size = c->frame_size;
+-
+-    return 0;
+-}
+-#endif /* CONFIG_LIBXCB_SHM */
+-
+ #if CONFIG_LIBXCB_XFIXES
+ static int check_xfixes(xcb_connection_t *conn)
+ {
+@@ -462,14 +361,7 @@ static int xcbgrab_read_packet(AVFormatContext *s, AVPacket *pkt)
+     if (c->show_region)
+         xcbgrab_update_region(s, win_x, win_y);
+ 
+-#if CONFIG_LIBXCB_SHM
+-    if (c->has_shm && xcbgrab_frame_shm(s, pkt) < 0) {
+-        av_log(s, AV_LOG_WARNING, "Continuing without shared memory.\n");
+-        c->has_shm = 0;
+-    }
+-#endif
+-    if (!c->has_shm)
+-        ret = xcbgrab_frame(s, pkt);
++    ret = xcbgrab_frame(s, pkt);
+     pkt->dts = pkt->pts = pts;
+     pkt->duration = c->frame_duration;
+ 
+@@ -488,11 +380,8 @@ static av_cold int xcbgrab_read_close(AVFormatContext *s)
+ {
+     XCBGrabContext *ctx = s->priv_data;
+ 
+-#if CONFIG_LIBXCB_SHM
+-    av_buffer_pool_uninit(&ctx->shm_pool);
+-#endif
+-
+     xcb_disconnect(ctx->conn);
++    ctx->conn = NULL;
+ 
+     return 0;
+ }
+@@ -572,7 +461,15 @@ static int pixfmt_from_pixmap_format(AVFormatContext *s, int depth,
+ static int create_stream(AVFormatContext *s)
+ {
+     XCBGrabContext *c = s->priv_data;
+-    AVStream *st      = avformat_new_stream(s, NULL);
++
++    // If we try to open another stream to x11grab, there is no reason
++    // to keep more than one stream in the context.
++    AVStream *st;
++    if (!s->nb_streams) {
++        st = avformat_new_stream(s, NULL);
++    } else {
++        st = s->streams[0];
++    }
+     xcb_get_geometry_cookie_t gc;
+     xcb_get_geometry_reply_t *geo;
+     int64_t frame_size_bits;
+@@ -594,11 +491,26 @@ static int create_stream(AVFormatContext *s)
+         return AVERROR_EXTERNAL;
+     }
+ 
++    // av_log(s, AV_LOG_ERROR, "Capture is_area %d\n", c->is_area);
++    // Width and Height are not 0 only when we set a window area to share
++    // This if may be valid only in  the first call to create_stream
+     if (!c->width || !c->height) {
++        // av_log(s, AV_LOG_ERROR, "Capture area!\n");
++        c->is_area = 0;
++        c->width = geo->width;
++        c->height = geo->height;
++    }
++    // If not a predefined area, then we should follow geometry changes
++    // This can be valid only on the second call onwards
++    if (!c->is_area && (c->width != geo->width || c->height != geo->height)) {
+         c->width = geo->width;
+         c->height = geo->height;
+     }
+ 
++    // av_log(s, AV_LOG_ERROR, "Capture area %dx%d at position %d.%d\n",
++    //            c->width, c->height,
++    //            c->x, c->y);
++
+     if (c->x + c->width > geo->width ||
+         c->y + c->height > geo->height) {
+         av_log(s, AV_LOG_ERROR,
+@@ -628,13 +540,6 @@ static int create_stream(AVFormatContext *s)
+     }
+     c->frame_size = frame_size_bits / 8;
+ 
+-#if CONFIG_LIBXCB_SHM
+-    c->shm_pool = av_buffer_pool_init2(c->frame_size + AV_INPUT_BUFFER_PADDING_SIZE,
+-                                           c->conn, allocate_shm_buffer, NULL);
+-    if (!c->shm_pool)
+-        return AVERROR(ENOMEM);
+-#endif
+-
+     st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+     st->codecpar->codec_id   = AV_CODEC_ID_RAWVIDEO;
+     st->codecpar->width      = c->width;
+@@ -829,23 +734,26 @@ static av_cold int xcbgrab_read_header(AVFormatContext *s)
+         sscanf(s->url, "+%d,%d", &c->x, &c->y);
+     }
+ 
+-    c->conn = xcb_connect(display_name[0] ? display_name : NULL, &screen_num);
+-    av_freep(&display_name);
++    if (!c->conn || !c->screen) {
++        xcbgrab_read_close(s);
++        c->conn = xcb_connect(display_name[0] ? display_name : NULL, &screen_num);
++        av_freep(&display_name);
+ 
+-    if ((ret = xcb_connection_has_error(c->conn))) {
+-        av_log(s, AV_LOG_ERROR, "Cannot open display %s, error %d.\n",
+-               s->url[0] ? s->url : "default", ret);
+-        return AVERROR(EIO);
+-    }
++        if ((ret = xcb_connection_has_error(c->conn))) {
++            av_log(s, AV_LOG_ERROR, "Cannot open display %s, error %d.\n",
++                s->url[0] ? s->url : "default", ret);
++            return AVERROR(EIO);
++        }
+ 
+-    setup = xcb_get_setup(c->conn);
++       setup = xcb_get_setup(c->conn);
+ 
+-    c->screen = get_screen(setup, screen_num);
+-    if (!c->screen) {
+-        av_log(s, AV_LOG_ERROR, "The screen %d does not exist.\n",
+-               screen_num);
+-        xcbgrab_read_close(s);
+-        return AVERROR(EIO);
++        c->screen = get_screen(setup, screen_num);
++        if (!c->screen) {
++            av_log(s, AV_LOG_ERROR, "The screen %d does not exist.\n",
++                screen_num);
++            xcbgrab_read_close(s);
++            return AVERROR(EIO);
++        }
+     }
+ 
+     if (c->window_id == XCB_NONE)
+@@ -876,10 +784,6 @@ static av_cold int xcbgrab_read_header(AVFormatContext *s)
+         return ret;
+     }
+ 
+-#if CONFIG_LIBXCB_SHM
+-    c->has_shm = check_shm(c->conn);
+-#endif
+-
+ #if CONFIG_LIBXCB_XFIXES
+     if (c->draw_mouse) {
+         if (!(c->draw_mouse = check_xfixes(c->conn))) {
+-- 
+2.34.1
+
diff --git a/gnu/packages/video.scm b/gnu/packages/video.scm
index de812ac762..d751442561 100644
--- a/gnu/packages/video.scm
+++ b/gnu/packages/video.scm
@@ -50,7 +50,7 @@
 ;;; Copyright © 2021 Alexey Abramov <levenson@mmer.org>
 ;;; Copyright © 2021, 2022, 2023 Andrew Tropin <andrew@trop.in>
 ;;; Copyright © 2021 David Wilson <david@daviwil.com>
-;;; Copyright © 2021, 2022, 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
+;;; Copyright © 2021, 2022, 2023, 2024 Maxim Cournoyer <maxim.cournoyer@gmail.com>
 ;;; Copyright © 2020 Hartmut Goebel <h.goebel@crazy-compilers.com>
 ;;; Copyright © 2021 Raghav Gururajan <rg@raghavgururajan.name>
 ;;; Copyright © 2021 Thiago Jung Bauermann <bauermann@kolabnow.com>
@@ -2000,6 +2000,252 @@ audio/video codec library.")
                  "--enable-static"))))
      (inputs '()))))
 
+;;; Custom ffmpeg package used by Jami, which incorporates custom patches.
+(define-public ffmpeg-jami
+  (package
+    (inherit ffmpeg)
+    (name "ffmpeg-jami")
+    (source (let ((ffmpeg-origin (package-source ffmpeg)))
+              (origin
+                (inherit ffmpeg-origin)
+                ;; These patches originate come from
+                ;; <https://review.jami.net/plugins/gitiles/jami-daemon/+/refs/heads/master/contrib/src/ffmpeg/>.
+                ;; Make sure to keep them update and/or register any new ones
+                ;; here.
+                (patches
+                 (append
+                  (origin-patches ffmpeg-origin)
+                  (search-patches
+                   "ffmpeg-jami-remove-mjpeg-log.patch"
+                   "ffmpeg-jami-change-RTCP-ratio.patch"
+                   "ffmpeg-jami-rtp_ext_abs_send_time.patch"
+                   "ffmpeg-jami-libopusdec-enable-FEC.patch"
+                   "ffmpeg-jami-libopusenc-reload-packet-loss-at-encode.patch"
+                   "ffmpeg-jami-screen-sharing-x11-fix.patch"))))))
+    (arguments
+     (substitute-keyword-arguments (package-arguments ffmpeg)
+       ((#:configure-flags _ '())
+        #~(list "--disable-static"
+                "--enable-shared"
+                "--disable-stripping"
+                ;; The following variables are configure flags used by
+                ;; ffmpeg-jami.  They're from the
+                ;; jami/daemon/contrib/src/ffmpeg/rules.mak file.  We try to
+                ;; keep it as close to the official Jami package as possible,
+                ;; to provide all the codecs and extra features that are
+                ;; expected (see:
+                ;; https://review.jami.net/plugins/gitiles/jami-daemon/+/
+                ;; refs/heads/master/contrib/src/ffmpeg/rules.mak).
+                ;; An exception are the ffnvcodec-related switches, which is
+                ;; not packaged in Guix and would not work with Mesa.
+                #$@(if (string-contains (%current-system) "linux")
+                       '("--enable-pic"
+                         "--extra-cxxflags=-fPIC"
+                         "--extra-cflags=-fPIC"
+                         "--target-os=linux"
+                         "--enable-indev=v4l2"
+                         "--enable-indev=xcbgrab"
+                         "--enable-vdpau"
+                         "--enable-hwaccel=h264_vdpau"
+                         "--enable-hwaccel=mpeg4_vdpau"
+                         "--enable-vaapi"
+                         "--enable-hwaccel=h264_vaapi"
+                         "--enable-hwaccel=mpeg4_vaapi"
+                         "--enable-hwaccel=h263_vaapi"
+                         "--enable-hwaccel=vp8_vaapi"
+                         "--enable-hwaccel=mjpeg_vaapi"
+                         "--enable-hwaccel=hevc_vaapi"
+                         "--enable-encoder=h264_vaapi"
+                         "--enable-encoder=vp8_vaapi"
+                         "--enable-encoder=mjpeg_vaapi"
+                         "--enable-encoder=hevc_vaapi")
+                       '())
+                "--disable-everything"
+                "--enable-zlib"
+                "--enable-gpl"
+                "--enable-swscale"
+                "--enable-bsfs"
+                "--disable-filters"
+                "--disable-programs"
+                "--disable-postproc"
+                "--disable-protocols"
+                "--enable-protocol=crypto"
+                "--enable-protocol=file"
+                "--enable-protocol=rtp"
+                "--enable-protocol=srtp"
+                "--enable-protocol=tcp"
+                "--enable-protocol=udp"
+                "--enable-protocol=unix"
+                "--enable-protocol=pipe"
+
+                ;; Enable muxers/demuxers.
+                "--disable-demuxers"
+                "--disable-muxers"
+                "--enable-muxer=rtp"
+                "--enable-muxer=g722"
+                "--enable-muxer=g726"
+                "--enable-muxer=g726le"
+                "--enable-muxer=h263"
+                "--enable-muxer=h264"
+                "--enable-muxer=hevc"
+                "--enable-muxer=matroska"
+                "--enable-muxer=wav"
+                "--enable-muxer=webm"
+                "--enable-muxer=ogg"
+                "--enable-muxer=pcm_s16be"
+                "--enable-muxer=pcm_s16le"
+                "--enable-demuxer=rtp"
+                "--enable-demuxer=mjpeg"
+                "--enable-demuxer=mjpeg_2000"
+                "--enable-demuxer=mpegvideo"
+                "--enable-demuxer=gif"
+                "--enable-demuxer=image_jpeg_pipe"
+                "--enable-demuxer=image_png_pipe"
+                "--enable-demuxer=image_webp_pipe"
+                "--enable-demuxer=matroska"
+                "--enable-demuxer=m4v"
+                "--enable-demuxer=mp3"
+                "--enable-demuxer=ogg"
+                "--enable-demuxer=flac"
+                "--enable-demuxer=wav"
+                "--enable-demuxer=ac3"
+                "--enable-demuxer=g722"
+                "--enable-demuxer=g723_1"
+                "--enable-demuxer=g726"
+                "--enable-demuxer=g726le"
+                "--enable-demuxer=pcm_mulaw"
+                "--enable-demuxer=pcm_alaw"
+                "--enable-demuxer=pcm_s16be"
+                "--enable-demuxer=pcm_s16le"
+                "--enable-demuxer=h263"
+                "--enable-demuxer=h264"
+                "--enable-demuxer=hevc"
+
+                ;; Enable parsers.
+                "--enable-parser=h263"
+                "--enable-parser=h264"
+                "--enable-parser=hevc"
+                "--enable-parser=mpeg4video"
+                "--enable-parser=vp8"
+                "--enable-parser=vp9"
+                "--enable-parser=opus"
+
+                ;; Encoders/decoders.
+                "--enable-encoder=adpcm_g722"
+                "--enable-decoder=adpcm_g722"
+                "--enable-encoder=adpcm_g726"
+                "--enable-decoder=adpcm_g726"
+                "--enable-encoder=adpcm_g726le"
+                "--enable-decoder=adpcm_g726le"
+                "--enable-decoder=g729"
+                "--enable-encoder=g723_1"
+                "--enable-decoder=g723_1"
+                "--enable-encoder=rawvideo"
+                "--enable-decoder=rawvideo"
+                "--enable-encoder=libx264"
+                "--enable-decoder=h264"
+                "--enable-encoder=pcm_alaw"
+                "--enable-decoder=pcm_alaw"
+                "--enable-encoder=pcm_mulaw"
+                "--enable-decoder=pcm_mulaw"
+                "--enable-encoder=mpeg4"
+                "--enable-decoder=mpeg4"
+                "--enable-encoder=libvpx_vp8"
+                "--enable-decoder=vp8"
+                "--enable-decoder=vp9"
+                "--enable-encoder=h263"
+                "--enable-encoder=h263p"
+                "--enable-decoder=h263"
+                "--enable-encoder=mjpeg"
+                "--enable-decoder=mjpeg"
+                "--enable-decoder=mjpegb"
+                "--enable-libspeex"
+                "--enable-libopus"
+                "--enable-libvpx"
+                "--enable-libx264"
+                "--enable-encoder=libspeex"
+                "--enable-decoder=libspeex"
+                "--enable-encoder=libopus"
+                "--enable-decoder=libopus"
+
+                ;; Encoders/decoders for ringtones and audio streaming.
+                "--enable-decoder=flac"
+                "--enable-decoder=vorbis"
+                "--enable-decoder=aac"
+                "--enable-decoder=ac3"
+                "--enable-decoder=eac3"
+                "--enable-decoder=mp3"
+                "--enable-decoder=pcm_u24le"
+                "--enable-decoder=pcm_u32le"
+                "--enable-decoder=pcm_u8"
+                "--enable-decoder=pcm_f16le"
+                "--enable-decoder=pcm_f32le"
+                "--enable-decoder=pcm_f64le"
+                "--enable-decoder=pcm_s16le"
+                "--enable-decoder=pcm_s24le"
+                "--enable-decoder=pcm_s32le"
+                "--enable-decoder=pcm_s64le"
+                "--enable-decoder=pcm_u16le"
+                "--enable-encoder=pcm_u8"
+                "--enable-encoder=pcm_f32le"
+                "--enable-encoder=pcm_f64le"
+                "--enable-encoder=pcm_s16le"
+                "--enable-encoder=pcm_s32le"
+                "--enable-encoder=pcm_s64le"
+
+                "--enable-decoder=pcm_s16be"
+                "--enable-decoder=pcm_s16be_planar"
+                "--enable-decoder=pcm_s16le_planar"
+                "--enable-decoder=pcm_s24be"
+                "--enable-decoder=pcm_s24le_planar"
+                "--enable-decoder=pcm_s32be"
+                "--enable-decoder=pcm_s32le_planar"
+                "--enable-decoder=pcm_s64be"
+                "--enable-decoder=pcm_s8"
+                "--enable-decoder=pcm_s8_planar"
+                "--enable-decoder=pcm_u16be"
+
+                ;; Encoders/decoders for images.
+                "--enable-encoder=gif"
+                "--enable-decoder=gif"
+                "--enable-encoder=jpegls"
+                "--enable-decoder=jpegls"
+                "--enable-encoder=ljpeg"
+                "--enable-decoder=jpeg2000"
+                "--enable-encoder=png"
+                "--enable-decoder=png"
+                "--enable-encoder=bmp"
+                "--enable-decoder=bmp"
+                "--enable-encoder=tiff"
+                "--enable-decoder=tiff"
+
+                ;; Filters.
+                "--enable-filter=scale"
+                "--enable-filter=overlay"
+                "--enable-filter=amix"
+                "--enable-filter=amerge"
+                "--enable-filter=aresample"
+                "--enable-filter=format"
+                "--enable-filter=aformat"
+                "--enable-filter=fps"
+                "--enable-filter=transpose"
+                "--enable-filter=pad"
+
+                "--enable-filter=afir"
+                "--enable-filter=split"
+                "--enable-filter=drawbox"
+                "--enable-filter=drawtext"
+                "--enable-filter=rotate"
+                "--enable-filter=loop"
+                "--enable-filter=setpts"
+                "--enable-filter=movie"
+                "--enable-filter=alphamerge"
+                "--enable-filter=boxblur"
+                "--enable-filter=lut"
+                "--enable-filter=negate"
+                "--enable-filter=colorkey"
+                "--enable-filter=transpose"))))))
+
 (define-public ffmpegthumbnailer
   (package
     (name "ffmpegthumbnailer")