diff --git a/src/media/Makefile.am b/src/media/Makefile.am
index c216e36c44eed10344795d781df40226c307127f..50944f3e09f0dda748ce50d67778c00730441aa5 100644
--- a/src/media/Makefile.am
+++ b/src/media/Makefile.am
@@ -33,7 +33,8 @@ noinst_HEADERS = \
 	media_codec.h \
 	system_codec_container.h \
 	srtp.h \
-	recordable.h
+	recordable.h \
+	decoder_finder.h
 
 libmedia_la_LIBADD = \
 	./audio/libaudio.la
diff --git a/src/media/video/decoder_finder.h b/src/media/decoder_finder.h
similarity index 96%
rename from src/media/video/decoder_finder.h
rename to src/media/decoder_finder.h
index 7fdcbbc614c703af295d592453c442048926485f..6ddac6d9cc30fd4886413ce9ea7b085efbb68c13 100644
--- a/src/media/video/decoder_finder.h
+++ b/src/media/decoder_finder.h
@@ -23,7 +23,7 @@ extern "C" {
 #include <libavcodec/avcodec.h>
 }
 
-namespace ring { namespace video {
+namespace ring {
 
 /**
  * Attempt to find standalone AVCodec decoder using AVCodecID,
@@ -57,4 +57,4 @@ findDecoder(const enum AVCodecID codec_id)
     return codec;
 }
 
-}} // namespace ring::video
+} // namespace ring
diff --git a/src/media/media_decoder.cpp b/src/media/media_decoder.cpp
index de1799ffc2655ccb6010a22c30c8615b503e1e7f..974833068086b9ab564577f49aea5515ef384adb 100644
--- a/src/media/media_decoder.cpp
+++ b/src/media/media_decoder.cpp
@@ -26,7 +26,7 @@
 #include "audio/audiobuffer.h"
 #include "audio/ringbuffer.h"
 #include "audio/resampler.h"
-#include "video/decoder_finder.h"
+#include "decoder_finder.h"
 #include "manager.h"
 
 #ifdef RING_ACCEL
@@ -148,169 +148,71 @@ void MediaDecoder::setIOContext(MediaIOHandle *ioctx)
 
 int MediaDecoder::setupFromAudioData(const AudioFormat format)
 {
-    int ret;
-
-    if (decoderCtx_)
-        avcodec_close(decoderCtx_);
-
-    // Increase analyze time to solve synchronization issues between callers.
-    static const unsigned MAX_ANALYZE_DURATION = 30; // time in seconds
-
-    inputCtx_->max_analyze_duration = MAX_ANALYZE_DURATION * AV_TIME_BASE;
-
-    RING_DBG("Finding stream info");
-    ret = avformat_find_stream_info(inputCtx_, NULL);
-    RING_DBG("Finding stream info DONE");
-
-    if (ret < 0) {
-        char errBuf[64] = {0};
-        // print nothing for unknown errors
-        if (av_strerror(ret, errBuf, sizeof errBuf) < 0)
-            errBuf[0] = '\0';
-
-        // always fail here
-        RING_ERR("Could not find stream info: %s", errBuf);
-        return -1;
-    }
-
-    // find the first audio stream from the input
-    for (size_t i = 0; streamIndex_ == -1 && i < inputCtx_->nb_streams; ++i)
-#ifndef _WIN32
-        if (inputCtx_->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
-#else
-        if (inputCtx_->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
-#endif
-            streamIndex_ = i;
-
-    if (streamIndex_ == -1) {
-        RING_ERR("Could not find audio stream");
-        return -1;
-    }
-
-    // Get a pointer to the codec context for the video stream
-    avStream_ = inputCtx_->streams[streamIndex_];
-#ifndef _WIN32
-    inputDecoder_ = avcodec_find_decoder(avStream_->codecpar->codec_id);
-    if (!inputDecoder_) {
-        RING_ERR("Unsupported codec");
-        return -1;
-    }
-
-    decoderCtx_ = avcodec_alloc_context3(inputDecoder_);
-    avcodec_parameters_to_context(decoderCtx_, avStream_->codecpar);
-#else
-    decoderCtx_ = avStream_->codec;
-    if (decoderCtx_ == 0) {
-        RING_ERR("Decoder context is NULL");
-        return -1;
-    }
-
-    // find the decoder for the audio stream
-    inputDecoder_ = avcodec_find_decoder(decoderCtx_->codec_id);
-    if (!inputDecoder_) {
-        RING_ERR("Unsupported codec");
-        return -1;
-    }
-#endif
-
-    decoderCtx_->thread_count = std::max(1u, std::min(8u, std::thread::hardware_concurrency()/2));
-    decoderCtx_->channels = format.nb_channels;
-    decoderCtx_->sample_rate = format.sample_rate;
-
-    RING_DBG("Audio decoding using %s with %s",
-             inputDecoder_->name, format.toString().c_str());
-
-    if (emulateRate_) {
-        RING_DBG("Using framerate emulation");
-        startTime_ = av_gettime();
-    }
-
-    ret = avcodec_open2(decoderCtx_, inputDecoder_, NULL);
-    if (ret) {
-        RING_ERR("Could not open codec");
-        return -1;
-    }
-
-    return 0;
+    // Use AVDictionary to send extra arguments to setupStream, since video setup doesn't need them
+    av_dict_set_int(&options_, "nb_channels", format.nb_channels, 0);
+    av_dict_set_int(&options_, "sample_rate", format.sample_rate, 0);
+    return setupStream(AVMEDIA_TYPE_AUDIO);
 }
 
-#ifdef RING_VIDEO
-int MediaDecoder::setupFromVideoData()
+int
+MediaDecoder::setupStream(AVMediaType mediaType)
 {
     int ret = 0;
+    std::string streamType = av_get_media_type_string(mediaType);
 
-    if (decoderCtx_)
-        avcodec_close(decoderCtx_);
+    avcodec_free_context(&decoderCtx_);
 
     // Increase analyze time to solve synchronization issues between callers.
-    static const unsigned MAX_ANALYZE_DURATION = 30; // time in seconds
-
+    static const unsigned MAX_ANALYZE_DURATION = 30;
     inputCtx_->max_analyze_duration = MAX_ANALYZE_DURATION * AV_TIME_BASE;
-    // if fallback from accel, don't check for stream info, it's already done
+
+    // If fallback from accel, don't check for stream info, it's already done
     if (!fallback_) {
-        RING_DBG("Finding stream info");
-        ret = avformat_find_stream_info(inputCtx_, NULL);
-    }
-    if (ret < 0) {
-        // workaround for this bug:
-        // http://patches.libav.org/patch/22541/
-        if (ret == -1)
-            ret = AVERROR_INVALIDDATA;
-        char errBuf[64] = {0};
-        // print nothing for unknown errors
-        if (av_strerror(ret, errBuf, sizeof errBuf) < 0)
-            errBuf[0] = '\0';
-
-        // always fail here
-        RING_ERR("Could not find stream info: %s", errBuf);
-        return -1;
+        RING_DBG() << "Finding " << streamType << " stream info";
+        if ((ret = avformat_find_stream_info(inputCtx_, nullptr)) < 0) {
+            char errBuf[64];
+            av_strerror(ret, errBuf, sizeof(errBuf));
+
+            // Always fail here
+            RING_ERR() << "Could not find " << streamType << " stream info: " << errBuf;
+            return -1;
+        }
     }
 
-    // find the first video stream from the input
-    for (size_t i = 0; streamIndex_ == -1 && i < inputCtx_->nb_streams; ++i)
-#ifndef _WIN32
-        if (inputCtx_->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
-#else
-        if (inputCtx_->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
-#endif
+    for (size_t i = 0; streamIndex_ == -1 && i < inputCtx_->nb_streams; ++i) {
+        if (inputCtx_->streams[i]->codecpar->codec_type == mediaType) {
             streamIndex_ = i;
+        }
+    }
 
-    if (streamIndex_ == -1) {
-        RING_ERR("Could not find video stream");
+    if (streamIndex_ < 0) {
+        RING_ERR() << "No " << streamType << " stream found";
         return -1;
     }
 
-    // Get a pointer to the codec context for the video stream
     avStream_ = inputCtx_->streams[streamIndex_];
-#ifndef _WIN32
-    inputDecoder_ = video::findDecoder(avStream_->codecpar->codec_id);
+
+    inputDecoder_ = findDecoder(avStream_->codecpar->codec_id);
     if (!inputDecoder_) {
-        RING_ERR("Unsupported codec");
+        RING_ERR() << "Unsupported codec";
         return -1;
     }
 
     decoderCtx_ = avcodec_alloc_context3(inputDecoder_);
-    avcodec_parameters_to_context(decoderCtx_, avStream_->codecpar);
-#else
-    decoderCtx_ = avStream_->codec;
-    if (decoderCtx_ == 0) {
-        RING_ERR("Decoder context is NULL");
+    if (!decoderCtx_) {
+        RING_ERR() << "Failed to create decoder context";
         return -1;
     }
-
-    // find the decoder for the video stream
-    inputDecoder_ = avcodec_find_decoder(decoderCtx_->codec_id);
-    if (!inputDecoder_) {
-        RING_ERR("Unsupported codec");
-        return -1;
-    }
-#endif
-    RING_DBG("Decoding video using %s (%s)", inputDecoder_->long_name, inputDecoder_->name);
+    avcodec_parameters_to_context(decoderCtx_, avStream_->codecpar);
 
     decoderCtx_->thread_count = std::max(1u, std::min(8u, std::thread::hardware_concurrency()/2));
+    if (mediaType == AVMEDIA_TYPE_AUDIO) {
+        decoderCtx_->channels = std::stoi(av_dict_get(options_, "nb_channels", nullptr, 0)->value);
+        decoderCtx_->sample_rate = std::stoi(av_dict_get(options_, "sample_rate", nullptr, 0)->value);
+    }
 
     if (emulateRate_) {
-        RING_DBG("Using framerate emulation");
+        RING_DBG() << "Using framerate emulation";
         startTime_ = av_gettime();
     }
 
@@ -319,21 +221,31 @@ int MediaDecoder::setupFromVideoData()
         accel_ = video::setupHardwareDecoding(decoderCtx_);
         decoderCtx_->opaque = &accel_;
     } else if (Manager::instance().getDecodingAccelerated()) {
-        RING_WARN("Hardware accelerated decoding disabled because of previous failure");
+        RING_WARN() << "Hardware accelerated decoding disabled because of previous failure";
     } else {
-        RING_WARN("Hardware accelerated decoding disabled by user preference");
+        RING_WARN() << "Hardware accelerated decoding disabled by user preference";
     }
 #endif
 
-    ret = avcodec_open2(decoderCtx_, inputDecoder_, NULL);
-    if (ret) {
-        RING_ERR("Could not open codec");
+    RING_DBG() << "Decoding " << streamType << " using " << inputDecoder_->long_name << " (" << inputDecoder_->name << ")";
+
+    ret = avcodec_open2(decoderCtx_, inputDecoder_, nullptr);
+    if (ret < 0) {
+        char errBuf[64];
+        av_strerror(ret, errBuf, sizeof(errBuf));
+        RING_ERR() << "Could not open codec: " << errBuf;
         return -1;
     }
 
     return 0;
 }
 
+#ifdef RING_VIDEO
+int MediaDecoder::setupFromVideoData()
+{
+    return setupStream(AVMEDIA_TYPE_VIDEO);
+}
+
 MediaDecoder::Status
 MediaDecoder::decode(VideoFrame& result)
 {
diff --git a/src/media/media_decoder.h b/src/media/media_decoder.h
index 524474f09a2e80c354a4286385a9784e174c5281..71fdcc0c02ded22d7eea3334d9b1880e673c978e 100644
--- a/src/media/media_decoder.h
+++ b/src/media/media_decoder.h
@@ -45,6 +45,7 @@ class AVStream;
 class AVDictionary;
 class AVFormatContext;
 class AVCodec;
+enum AVMediaType;
 
 namespace ring {
 
@@ -115,6 +116,7 @@ class MediaDecoder {
 
         void extract(const std::map<std::string, std::string>& map, const std::string& key);
         int correctPixFmt(int input_pix_fmt);
+        int setupStream(AVMediaType mediaType);
 
         bool fallback_ = false;
 
diff --git a/src/media/video/Makefile.am b/src/media/video/Makefile.am
index 4617b906d7e698f6ce63686920373c801f6236ea..bd3abf7337bbcbbcc42eb5324f5c32d7d6b2f25a 100644
--- a/src/media/video/Makefile.am
+++ b/src/media/video/Makefile.am
@@ -36,8 +36,7 @@ libvideo_la_SOURCES = \
 	video_receive_thread.cpp video_receive_thread.h \
 	video_sender.cpp video_sender.h \
 	video_rtp_session.cpp video_rtp_session.h \
-	sinkclient.cpp sinkclient.h \
-	decoder_finder.h
+	sinkclient.cpp sinkclient.h
 
 if RING_ACCEL
 libvideo_la_SOURCES += accel.cpp accel.h