diff --git a/daemon/src/account.cpp b/daemon/src/account.cpp
index 6ff8cc0c64908a2705c5f7ea046d7c3f7ea3343d..e4c2cbf89cae3e2cee8d394bf9c2e22765d92556 100644
--- a/daemon/src/account.cpp
+++ b/daemon/src/account.cpp
@@ -46,6 +46,7 @@ const char * const Account::AUDIO_CODECS_KEY =      "audioCodecs";  // 0/9/110/1
 const char * const Account::VIDEO_CODECS_KEY =      "videoCodecs";
 const char * const Account::VIDEO_CODEC_ENABLED =   "enabled";
 const char * const Account::VIDEO_CODEC_NAME =      "name";
+const char * const Account::VIDEO_CODEC_PARAMETERS ="parameters";
 const char * const Account::VIDEO_CODEC_BITRATE =   "bitrate";
 const char * const Account::RINGTONE_PATH_KEY =     "ringtonePath";
 const char * const Account::RINGTONE_ENABLED_KEY =  "ringtoneEnabled";
@@ -146,7 +147,7 @@ namespace {
 
     bool isCodecValid(const map<string, string> &codec, const vector<map<string, string> > &defaults)
     {
-        map<string, string>::const_iterator name(codec.find(Account::VIDEO_CODEC_NAME));
+        const map<string, string>::const_iterator name(codec.find(Account::VIDEO_CODEC_NAME));
         if (name == codec.end()) {
             ERROR("Field \"name\" missing in codec specification");
             return false;
@@ -154,7 +155,7 @@ namespace {
 
         // check that it's in the list of valid codecs and that it has all the required fields
         for (vector<map<string, string> >::const_iterator i = defaults.begin(); i != defaults.end(); ++i) {
-            map<string, string>::const_iterator defaultName = i->find(Account::VIDEO_CODEC_NAME);
+            const map<string, string>::const_iterator defaultName = i->find(Account::VIDEO_CODEC_NAME);
             if (defaultName->second == name->second) {
                 return isFieldValid(codec, Account::VIDEO_CODEC_BITRATE, isPositiveInteger)
                     and isFieldValid(codec, Account::VIDEO_CODEC_ENABLED, isBoolean);
diff --git a/daemon/src/account.h b/daemon/src/account.h
index ee42256d8d5b110ce96c659132b122a063a6609d..d6d5140ae606ba253371e94d14975f97885103d8 100644
--- a/daemon/src/account.h
+++ b/daemon/src/account.h
@@ -185,6 +185,7 @@ class Account : public Serializable {
 
         static const char * const VIDEO_CODEC_ENABLED;
         static const char * const VIDEO_CODEC_NAME;
+        static const char * const VIDEO_CODEC_PARAMETERS;
         static const char * const VIDEO_CODEC_BITRATE;
     private:
         NON_COPYABLE(Account);
diff --git a/daemon/src/sip/sdp.cpp b/daemon/src/sip/sdp.cpp
index 9dc555a8fc074704771623cbd975cddf121a9127..3d3f09dc787a7c853b07cb91551d35fcb8f1df95 100644
--- a/daemon/src/sip/sdp.cpp
+++ b/daemon/src/sip/sdp.cpp
@@ -220,13 +220,15 @@ pjmedia_sdp_media *Sdp::setMediaDescriptorLine(bool audio)
         pjmedia_sdp_rtpmap_to_attr(memPool_, &rtpmap, &attr);
 
         med->attr[med->attr_count++] = attr;
+#ifdef SFL_VIDEO
         if (enc_name == "H264") {
             std::ostringstream os;
             // FIXME: this should not be hardcoded, it will determine what profile and level
             // our peer will send us
-            os << "fmtp:" << dynamic_payload << " profile-level-id=428014";
+            os << "fmtp:" << dynamic_payload << " " << libav_utils::DEFAULT_H264_PROFILE_LEVEL_ID;
             med->attr[med->attr_count++] = pjmedia_sdp_attr_create(memPool_, os.str().c_str(), NULL);
         }
+#endif
         if (not audio)
             dynamic_payload++;
     }
diff --git a/daemon/src/sip/sipaccount.cpp b/daemon/src/sip/sipaccount.cpp
index 03d02cbd5b206fe096796b44e552bcb88f7889ac..5e04cb4ec87bc6160127d683c69ae3210c855e06 100644
--- a/daemon/src/sip/sipaccount.cpp
+++ b/daemon/src/sip/sipaccount.cpp
@@ -160,6 +160,7 @@ void SIPAccount::serialize(Conf::YamlEmitter &emitter)
         mapNode->setKeyValue(VIDEO_CODEC_NAME, new ScalarNode(codec[VIDEO_CODEC_NAME]));
         mapNode->setKeyValue(VIDEO_CODEC_BITRATE, new ScalarNode(codec[VIDEO_CODEC_BITRATE]));
         mapNode->setKeyValue(VIDEO_CODEC_ENABLED, new ScalarNode(codec[VIDEO_CODEC_ENABLED]));
+        mapNode->setKeyValue(VIDEO_CODEC_PARAMETERS, new ScalarNode(codec[VIDEO_CODEC_PARAMETERS]));
         videoCodecs.addNode(mapNode);
     }
 #endif
@@ -287,6 +288,7 @@ void SIPAccount::serialize(Conf::YamlEmitter &emitter)
         delete node->getValue(VIDEO_CODEC_NAME);
         delete node->getValue(VIDEO_CODEC_BITRATE);
         delete node->getValue(VIDEO_CODEC_ENABLED);
+        delete node->getValue(VIDEO_CODEC_PARAMETERS);
         delete node;
     }
 #endif
@@ -326,6 +328,7 @@ void SIPAccount::unserialize(const Conf::MappingNode &mapNode)
                 codec->getValue(VIDEO_CODEC_NAME, &codecMap[VIDEO_CODEC_NAME]);
                 codec->getValue(VIDEO_CODEC_BITRATE, &codecMap[VIDEO_CODEC_BITRATE]);
                 codec->getValue(VIDEO_CODEC_ENABLED, &codecMap[VIDEO_CODEC_ENABLED]);
+                codec->getValue(VIDEO_CODEC_PARAMETERS, &codecMap[VIDEO_CODEC_PARAMETERS]);
                 videoCodecDetails.push_back(codecMap);
             }
             // these must be validated
diff --git a/daemon/src/video/libav_utils.cpp b/daemon/src/video/libav_utils.cpp
index 52d842e86c77824b1c5187367b16e8bfffdba850..2258ae87e4a24188b5acc146f3227673daab47e2 100644
--- a/daemon/src/video/libav_utils.cpp
+++ b/daemon/src/video/libav_utils.cpp
@@ -52,7 +52,6 @@ vector<string> installed_video_codecs_;
 /* application wide mutex to protect concurrent access to avcodec */
 ost::Mutex avcodec_lock_;
 
-
 void findInstalledVideoCodecs()
 {
     vector<string> libav_codecs;
@@ -73,7 +72,6 @@ void findInstalledVideoCodecs()
 
 namespace libav_utils {
 
-
 vector<string> getVideoCodecList()
 {
     if (installed_video_codecs_.empty())
@@ -154,6 +152,9 @@ getDefaultCodecs()
         codec["name"] = *iter;
         codec["bitrate"] = DEFAULT_BITRATE;
         codec["enabled"] = "true";
+        // FIXME: make a nicer version of this
+        if (*iter == "H264")
+            codec["parameters"] = DEFAULT_H264_PROFILE_LEVEL_ID;
         result.push_back(codec);
     }
     return result;
diff --git a/daemon/src/video/libav_utils.h b/daemon/src/video/libav_utils.h
index a18714ec1bedffacc31fbe32ddb34ac5057b3fca..585d3201cb3ce1486dca1430c847dbbe40ad7c07 100644
--- a/daemon/src/video/libav_utils.h
+++ b/daemon/src/video/libav_utils.h
@@ -47,6 +47,7 @@ namespace libav_utils {
 
     std::vector<std::map<std::string, std::string> >
     getDefaultCodecs();
+    const char *const DEFAULT_H264_PROFILE_LEVEL_ID = "profile-level-id=428014";
 }
 
 #endif // __LIBAV_UTILS_H__
diff --git a/daemon/src/video/video_send_thread.cpp b/daemon/src/video/video_send_thread.cpp
index 1848e4e3c30d9b8208bf659772cb919dfe933146..f731fe81517987252a7ca14d6eb1821458e1f360 100644
--- a/daemon/src/video/video_send_thread.cpp
+++ b/daemon/src/video/video_send_thread.cpp
@@ -121,6 +121,53 @@ void VideoSendThread::prepareEncoderContext(AVCodec *encoder)
     // encoderCtx_->flags |= CODEC_FLAG_GLOBAL_HEADER;
 }
 
+namespace {
+void
+extractProfileLevelID(const std::string &parameters, AVCodecContext *ctx)
+{
+    // From RFC3984:
+    // If no profile-level-id is present, the Baseline Profile without
+    // additional constraints at Level 1 MUST be implied.
+    ctx->profile = FF_PROFILE_H264_BASELINE;
+    ctx->level = 0x1;
+    // ctx->level = 0x0d; // => 13 aka 1.3
+    if (parameters.empty())
+        return;
+
+    const std::string target("profile-level-id=");
+    size_t needle = parameters.find(target);
+    if (needle == std::string::npos)
+        return;
+
+    needle += target.length();
+    const size_t id_length = 6; /* digits */
+    const std::string profileLevelID(parameters.substr(needle, id_length));
+    if (profileLevelID.length() != id_length)
+        return;
+
+    int result;
+    std::stringstream ss;
+    ss << profileLevelID;
+    ss >> std::hex >> result;
+    // profile-level id consists of three bytes
+    const unsigned char profile_idc = result >> 16;             // 42xxxx -> 42
+    const unsigned char profile_iop = ((result >> 8) & 0xff);   // xx80xx -> 80
+    ctx->level = result & 0xff;                                 // xxxx0d -> 0d
+    switch (profile_idc) {
+        case FF_PROFILE_H264_BASELINE:
+            // check constraint_set_1_flag
+            ctx->profile |= (profile_iop & 0x40) >> 6 ? FF_PROFILE_H264_CONSTRAINED : 0;
+            break;
+        case FF_PROFILE_H264_HIGH_10:
+        case FF_PROFILE_H264_HIGH_422:
+        case FF_PROFILE_H264_HIGH_444_PREDICTIVE:
+            // check constraint_set_3_flag
+            ctx->profile |= (profile_iop & 0x10) >> 4 ? FF_PROFILE_H264_INTRA : 0;
+            break;
+    }
+    DEBUG("Using profile %x and level %d", ctx->profile, ctx->level);
+}
+}
 
 void VideoSendThread::setup()
 {
@@ -191,12 +238,11 @@ void VideoSendThread::setup()
 
     /* let x264 preset override our encoder settings */
     if (args_["codec"] == "libx264") {
-        forcePresetX264();
         // FIXME: this should be parsed from the fmtp:profile-level-id
         // attribute of our peer, it will determine what profile and
         // level we are sending (i.e. that they can accept).
-        encoderCtx_->profile = FF_PROFILE_H264_CONSTRAINED_BASELINE;
-        encoderCtx_->level = 0x0d; // => 13 aka 1.3
+        extractProfileLevelID(args_["parameters"], encoderCtx_);
+        forcePresetX264();
     }
 
     scaledPicture_ = avcodec_alloc_frame();