diff --git a/daemon/configure.ac b/daemon/configure.ac
index f6eeb1c8dc5a40c0237244b6c841407182b5999d..6f6ef4a9a7e697d25f75db38114fc348aefc7aee 100644
--- a/daemon/configure.ac
+++ b/daemon/configure.ac
@@ -354,7 +354,7 @@ AS_IF([test "x$enable_video" != "xno"],
         PKG_CHECK_MODULES(LIBAVCODEC, libavcodec >= 53.5.0,, AC_MSG_ERROR([Missing libavcodec development files]))
         LIBAVCODEC_CFLAGS="${LIBAVCODEC_CFLAGS} -D__STDC_CONSTANT_MACROS"
 
-        PKG_CHECK_MODULES(LIBAVFORMAT, libavformat >= 53.2.0,, AC_MSG_ERROR([Missing libavformat development files]))
+        PKG_CHECK_MODULES(LIBAVFORMAT, libavformat >= 54.20.3,, AC_MSG_ERROR([Missing libavformat development files]))
 
         PKG_CHECK_MODULES(LIBSWSCALE, libswscale >= 1.1.0,, AC_MSG_ERROR([Missing libswscale development files]))
 
diff --git a/daemon/contrib/src/libav/rules.mak b/daemon/contrib/src/libav/rules.mak
index 0d594b69791d7dc8cf558dc11086f2719d937351..db962b67486710ffd12440ae0279c4bfc387fb37 100644
--- a/daemon/contrib/src/libav/rules.mak
+++ b/daemon/contrib/src/libav/rules.mak
@@ -110,7 +110,8 @@ ifndef HAVE_ANDROID
 PKGS += libav
 endif
 endif
-ifeq ($(call need_pkg,"libavcodec >= 53.5.0 libavformat >= 53.2.0 libswscale libavdevice >= 53.0.0 libavutil >= 51.0.0"),)
+
+ifeq ($(call need_pkg,"libavcodec >= 53.5.0 libavformat >= 54.20.3 libswscale libavdevice >= 53.0.0 libavutil >= 51.0.0"),)
 PKGS_FOUND += libav
 endif
 
diff --git a/daemon/src/video/libav_deps.h b/daemon/src/video/libav_deps.h
index dd938a29449c7744c8596af274a2eb6a87164015..2f9e9af8ab81673c26993c55f99f11f2a2a506e7 100644
--- a/daemon/src/video/libav_deps.h
+++ b/daemon/src/video/libav_deps.h
@@ -55,8 +55,6 @@
     ( (LIBAVUTIL_VERSION_MICRO <  100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT( a, b, c ) ) || \
       (LIBAVUTIL_VERSION_MICRO >= 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT( a, d, e ) ) )
 
-#define HAVE_SDP_CUSTOM_IO LIBAVFORMAT_VERSION_CHECK(54,20,3,59,103)
-
 extern "C" {
 #include <libavcodec/avcodec.h>
 #include <libavformat/avformat.h>
@@ -75,6 +73,10 @@ extern "C" {
 
 #include "libav_utils.h"
 
+#if !LIBAVFORMAT_VERSION_CHECK(54,20,3,59,103)
+#error "Used libavformat doesn't support sdp custom_io"
+#endif
+
 #if !LIBAVUTIL_VERSION_CHECK(51, 42, 0, 74, 100) && !defined(FF_API_PIX_FMT)
 #define AVPixelFormat PixelFormat
 #define PIXEL_FORMAT(FMT) PIX_FMT_ ## FMT
diff --git a/daemon/src/video/socket_pair.cpp b/daemon/src/video/socket_pair.cpp
index 6c50ff5466f0db1fd0b1c2b59ebcd106eecc0a24..2371630bb766641f7d259b131612b3e95d41d3b7 100644
--- a/daemon/src/video/socket_pair.cpp
+++ b/daemon/src/video/socket_pair.cpp
@@ -118,7 +118,6 @@ udp_socket_create(sockaddr_storage *addr, socklen_t *addr_len, int local_port)
     memcpy(addr, res->ai_addr, res->ai_addrlen);
     *addr_len = res->ai_addrlen;
 
-#if HAVE_SDP_CUSTOM_IO
     // bind socket so that we send from and receive
     // on local port
     if (bind(udp_fd, reinterpret_cast<sockaddr*>(addr), *addr_len) < 0) {
@@ -127,7 +126,6 @@ udp_socket_create(sockaddr_storage *addr, socklen_t *addr_len, int local_port)
         close(udp_fd);
         udp_fd = -1;
     }
-#endif
 
     freeaddrinfo(res0);
 
@@ -180,14 +178,7 @@ void SocketPair::openSockets(const char *uri, int local_rtp_port)
                   sizeof(path));
 
     const int rtcp_port = rtp_port + 1;
-
-#if HAVE_SDP_CUSTOM_IO
     const int local_rtcp_port = local_rtp_port + 1;
-#else
-    SFL_WARN("libavformat too old for socket reuse, using random source ports");
-    local_rtp_port = 0;
-    const int local_rtcp_port = 0;
-#endif
 
     sockaddr_storage rtp_addr, rtcp_addr;
     socklen_t rtp_len, rtcp_len;
diff --git a/daemon/src/video/video_decoder.cpp b/daemon/src/video/video_decoder.cpp
index bb67e29b873b6814b98ace41d2d1d050b88ba0b0..faa29befbc30071fcc9c6fa61baa844796b33dd7 100644
--- a/daemon/src/video/video_decoder.cpp
+++ b/daemon/src/video/video_decoder.cpp
@@ -78,9 +78,7 @@ VideoDecoder::setOptions(const std::map<std::string, std::string>& options)
     extract(options, "video_size");
     extract(options, "channel");
     extract(options, "loop");
-#if HAVE_SDP_CUSTOM_IO
     extract(options, "sdp_flags");
-#endif
 }
 
 int VideoDecoder::openInput(const std::string &source_str,
diff --git a/daemon/src/video/video_receive_thread.cpp b/daemon/src/video/video_receive_thread.cpp
index fac2c2fb997896fdb1664d4d66cc86255fed59ca..01229a12cdca086e69275de849f6b5157d46374b 100644
--- a/daemon/src/video/video_receive_thread.cpp
+++ b/daemon/src/video/video_receive_thread.cpp
@@ -102,12 +102,9 @@ bool VideoReceiveThread::setup()
     videoDecoder_->setInterruptCallback(interruptCb, this);
 
     if (input == SDP_FILENAME) {
-#if HAVE_SDP_CUSTOM_IO
-        // custom_io so the SDP demuxer will not open any UDP connections
+        // Force custom_io so the SDP demuxer will not open any UDP connections
+        // We need it to use ICE transport.
         args_["sdp_flags"] = "custom_io";
-#else
-        SFL_WARN("libavformat too old for custom SDP demuxing");
-#endif
 
         EXIT_IF_FAIL(not stream_.str().empty(), "No SDP loaded");
         videoDecoder_->setIOContext(&sdpContext_);
@@ -119,10 +116,8 @@ bool VideoReceiveThread::setup()
                  "Could not open input \"%s\"", input.c_str());
 
     if (input == SDP_FILENAME) {
-#if HAVE_SDP_CUSTOM_IO
         // Now replace our custom AVIOContext with one that will read packets
         videoDecoder_->setIOContext(demuxContext_);
-#endif
     }
 
     // FIXME: this is a hack because our peer sends us RTP before
@@ -182,9 +177,7 @@ int VideoReceiveThread::readFunction(void *opaque, uint8_t *buf, int buf_size)
 
 void VideoReceiveThread::addIOContext(SocketPair &socketPair)
 {
-#if HAVE_SDP_CUSTOM_IO
     demuxContext_ = socketPair.createIOContext();
-#endif
 }
 
 bool VideoReceiveThread::decodeFrame()