aboutsummaryrefslogtreecommitdiff
path: root/gnu/packages
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/packages')
-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
9 files changed, 894 insertions, 267 deletions
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")