diff --git a/src/media/media_encoder.cpp b/src/media/media_encoder.cpp
index b1fbb3c6ffde51804f632d74dfcfe0f3bb2c9e7e..f4e6220b3aeed6ee855a2726e6bf37bfde4c7149 100644
--- a/src/media/media_encoder.cpp
+++ b/src/media/media_encoder.cpp
@@ -107,7 +107,12 @@ MediaEncoder::setOptions(const MediaStream& opts)
 void
 MediaEncoder::setOptions(const MediaDescription& args)
 {
-    libav_utils::setDictValue(&options_, "payload_type", std::to_string(args.payload_type));
+    int ret;
+    if ((ret = av_opt_set_int(reinterpret_cast<void*>(outputCtx_),
+        "payload_type", args.payload_type, AV_OPT_SEARCH_CHILDREN)) < 0)
+        JAMI_ERR() << "Failed to set payload type: " << libav_utils::getError(ret);
+
+    // NOTE none of these are format options, and we don't have a codec context yet
     libav_utils::setDictValue(&options_, "max_rate", std::to_string(args.codec->bitrate));
     libav_utils::setDictValue(&options_, "crf", std::to_string(args.codec->quality));
 
@@ -203,7 +208,7 @@ MediaEncoder::initStream(const SystemCodecInfo& systemCodecInfo, AVBufferRef* fr
 
     currentStreamIdx_ = stream->index;
 
-    readConfig(&options_, encoderCtx);
+    readConfig(encoderCtx);
     if (avcodec_open2(encoderCtx, outputCodec_, &options_) < 0)
         throw MediaEncoderException("Could not open encoder");
 
@@ -846,7 +851,7 @@ MediaEncoder::stopEncoder()
 }
 
 void
-MediaEncoder::readConfig(AVDictionary** dict, AVCodecContext* encoderCtx)
+MediaEncoder::readConfig(AVCodecContext* encoderCtx)
 {
     std::string path = fileutils::get_config_dir() + DIR_SEPARATOR_STR + "encoder.json";
     std::string name = encoderCtx->codec->name;
@@ -868,7 +873,6 @@ MediaEncoder::readConfig(AVDictionary** dict, AVCodecContext* encoderCtx)
                 JAMI_ERR() << "Invalid encoder configuration: '" << name << "' is not an object";
                 return;
             }
-            // If users want to change these, they should use the settings page.
             for (Json::Value::const_iterator it = config.begin(); it != config.end(); ++it) {
                 Json::Value v = *it;
                 if (!it.key().isConvertibleTo(Json::ValueType::stringValue)
@@ -878,29 +882,12 @@ MediaEncoder::readConfig(AVDictionary** dict, AVCodecContext* encoderCtx)
                 }
                 const auto& key = it.key().asString();
                 const auto& value = v.asString();
-                // provides a way to override all AVCodecContext fields MediaEncoder sets
-                if (key == "parameters") // Used by MediaEncoder for profile-level-id, ignore
-                    continue;
-                else if (value.empty())
-                    libav_utils::setDictValue(dict, key, nullptr);
-                else if (key == "profile")
-                    encoderCtx->profile = v.asInt();
-                else if (key == "level")
-                    encoderCtx->level = v.asInt();
-                else if (key == "bit_rate")
-                    encoderCtx->bit_rate = v.asInt();
-                else if (key == "rc_buffer_size")
-                    encoderCtx->rc_buffer_size = v.asInt();
-                else if (key == "rc_min_rate")
-                    encoderCtx->rc_min_rate = v.asInt();
-                else if (key == "rc_max_rate")
-                    encoderCtx->rc_max_rate = v.asInt();
-                else if (key == "qmin")
-                    encoderCtx->qmin = v.asInt();
-                else if (key == "qmax")
-                    encoderCtx->qmax = v.asInt();
-                else
-                    libav_utils::setDictValue(dict, key, value);
+                int ret = av_opt_set(reinterpret_cast<void*>(encoderCtx),
+                                     key.c_str(), value.c_str(), AV_OPT_SEARCH_CHILDREN);
+                if (ret < 0) {
+                    JAMI_ERR() << "Failed to set option " << key << " in encoder context: "
+                        << libav_utils::getError(ret) << "\n";
+                }
             }
         } catch (const Json::Exception& e) {
             JAMI_ERR() << "Failed to load encoder configuration file: " << e.what();
diff --git a/src/media/media_encoder.h b/src/media/media_encoder.h
index 5dc9d5df10f54d2026443150f6923ac1d9f895a9..800ec4bc955fced8035156a4b8af11ef828e1daa 100644
--- a/src/media/media_encoder.h
+++ b/src/media/media_encoder.h
@@ -152,7 +152,7 @@ private:
 #endif
 
 protected:
-    void readConfig(AVDictionary** dict, AVCodecContext* encoderCtx);
+    void readConfig(AVCodecContext* encoderCtx);
     AVDictionary* options_ = nullptr;
     MediaStream videoOpts_;
     MediaStream audioOpts_;