diff --git a/daemon/src/sip/sipvoiplink.cpp b/daemon/src/sip/sipvoiplink.cpp
index d24de327f2bbb5c0acde7fff637f250cd7f7a9b8..9004fe986f7497355f9a3f37e271d57b435ef335 100644
--- a/daemon/src/sip/sipvoiplink.cpp
+++ b/daemon/src/sip/sipvoiplink.cpp
@@ -1214,21 +1214,6 @@ void sendSIPInfo(const SIPCall &call, const char *const body, const char *const
         pjsip_dlg_send_request(call.inv->dlg, tdata, mod_ua_.id, NULL);
 }
 
-#ifdef SFL_VIDEO
-void
-requestFastPictureUpdate(const SIPCall &call)
-{
-    const char * const BODY =
-        "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
-        "<media_control><vc_primitive><to_encoder>"
-        "<picture_fast_update/>"
-        "</to_encoder></vc_primitive></media_control>";
-
-    DEBUG("Sending video keyframe request via SIP INFO");
-    sendSIPInfo(call, BODY, "media_control+xml");
-}
-#endif
-
 void
 dtmfSend(SIPCall &call, char code, const std::string &dtmf)
 {
@@ -1247,6 +1232,29 @@ dtmfSend(SIPCall &call, char code, const std::string &dtmf)
 }
 }
 
+#ifdef SFL_VIDEO
+void
+SIPVoIPLink::requestFastPictureUpdate(const std::string &callID)
+{
+    SIPCall *call;
+    try {
+         call = SIPVoIPLink::instance()->getSIPCall(callID);
+    } catch (const VoipLinkException &e) {
+        ERROR("%s", e.what());
+        return;
+    }
+
+    const char * const BODY =
+        "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
+        "<media_control><vc_primitive><to_encoder>"
+        "<picture_fast_update/>"
+        "</to_encoder></vc_primitive></media_control>";
+
+    DEBUG("Sending video keyframe request via SIP INFO");
+    sendSIPInfo(*call, BODY, "media_control+xml");
+}
+#endif
+
 void
 SIPVoIPLink::carryingDTMFdigits(const std::string& id, char code)
 {
diff --git a/daemon/src/sip/sipvoiplink.h b/daemon/src/sip/sipvoiplink.h
index 47f1c91dc607ad0635468e6bf4937f8047bfbf4a..b4706b411e9e733ce52c5bb729f7cb303ca47945 100644
--- a/daemon/src/sip/sipvoiplink.h
+++ b/daemon/src/sip/sipvoiplink.h
@@ -253,6 +253,10 @@ class SIPVoIPLink : public VoIPLink {
 
         SipTransport sipTransport;
 
+#ifdef SFL_VIDEO
+        static void requestFastPictureUpdate(const std::string &callID);
+#endif
+
     private:
 
         NON_COPYABLE(SIPVoIPLink);
diff --git a/daemon/src/video/video_receive_thread.cpp b/daemon/src/video/video_receive_thread.cpp
index 9f91482fb2b022b651a9052d0b89fa23f1a16719..48da041d975809b51580d60a9e6457fb72532381 100644
--- a/daemon/src/video/video_receive_thread.cpp
+++ b/daemon/src/video/video_receive_thread.cpp
@@ -141,6 +141,8 @@ void VideoReceiveThread::setup()
     EXIT_IF_FAIL(ret == 0, "Could not open input \"%s\"", input.c_str());
 
     DEBUG("Finding stream info");
+    if (requestKeyFrameCallback_)
+        requestKeyFrameCallback_(id_);
 #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 8, 0)
     ret = av_find_stream_info(inputCtx_);
 #else
@@ -178,8 +180,6 @@ void VideoReceiveThread::setup()
         dstHeight_ = decoderCtx_->height;
     }
 
-    // allocate video frame
-    rawFrame_ = avcodec_alloc_frame();
     // determine required buffer size and allocate buffer
     bufferSize_ = getBufferSize(dstWidth_, dstHeight_, VIDEO_RGB_FORMAT);
 
@@ -210,7 +210,7 @@ VideoReceiveThread::VideoReceiveThread(const std::string &id, const std::map<str
     args_(args), frameNumber_(0), decoderCtx_(0), rawFrame_(0),
     scaledPicture_(0), streamIndex_(-1), inputCtx_(0), imgConvertCtx_(0),
     dstWidth_(0), dstHeight_(0), sink_(), receiving_(false), sdpFilename_(),
-    bufferSize_(0), id_(id), interruptCb_()
+    bufferSize_(0), id_(id), interruptCb_(), requestKeyFrameCallback_(0)
 {
     interruptCb_.callback = interruptCb;
     interruptCb_.opaque = this;
@@ -241,22 +241,28 @@ void VideoReceiveThread::run()
 
     createScalingContext();
     const Callback cb(&VideoReceiveThread::fill_buffer);
+    AVFrame rawFrame;
+    rawFrame_ = &rawFrame;
+
     while (receiving_) {
         AVPacket inpacket;
 
         int ret = 0;
         if ((ret = av_read_frame(inputCtx_, &inpacket)) < 0) {
-            ERROR("Couldn't read frame : %s\n", strerror(ret));
+            ERROR("Couldn't read frame: %s\n", strerror(ret));
             break;
         }
         // Guarantee that we free the packet every iteration
         PacketHandle inpacket_handle(inpacket);
+        avcodec_get_frame_defaults(rawFrame_);
 
         // is this a packet from the video stream?
         if (inpacket.stream_index == streamIndex_) {
             int frameFinished = 0;
-            avcodec_decode_video2(decoderCtx_, rawFrame_, &frameFinished,
-                                  &inpacket);
+            const int len = avcodec_decode_video2(decoderCtx_, rawFrame_, &frameFinished,
+                                                  &inpacket);
+            if (len <= 0 and requestKeyFrameCallback_)
+                requestKeyFrameCallback_(id_);
 
             // we want our rendering code to be called by the shm_sink,
             // because it manages the shared memory synchronization
@@ -279,9 +285,6 @@ VideoReceiveThread::~VideoReceiveThread()
     if (scaledPicture_)
         av_free(scaledPicture_);
 
-    if (rawFrame_)
-        av_free(rawFrame_);
-
     if (decoderCtx_)
         avcodec_close(decoderCtx_);
 
@@ -293,4 +296,9 @@ VideoReceiveThread::~VideoReceiveThread()
 #endif
     }
 }
+
+void VideoReceiveThread::setRequestKeyFrameCallback(void (*cb)(const std::string &))
+{
+    requestKeyFrameCallback_ = cb;
+}
 } // end namespace sfl_video
diff --git a/daemon/src/video/video_receive_thread.h b/daemon/src/video/video_receive_thread.h
index f36126bec6df4d87bfcafe10994559fc17c53959..e0d03a4a7ee73c9998788e6a1f30d21d2a3cfab9 100644
--- a/daemon/src/video/video_receive_thread.h
+++ b/daemon/src/video/video_receive_thread.h
@@ -81,11 +81,13 @@ class VideoReceiveThread : public ost::Thread {
         void fill_buffer(void *data);
         static int interruptCb(void *ctx);
         AVIOInterruptCB interruptCb_;
+        void (* requestKeyFrameCallback_)(const std::string &);
 
     public:
         VideoReceiveThread(const std::string &id, const std::map<std::string, std::string> &args);
         virtual ~VideoReceiveThread();
         virtual void run();
+        void setRequestKeyFrameCallback(void (*)(const std::string &));
 };
 }
 
diff --git a/daemon/src/video/video_rtp_session.cpp b/daemon/src/video/video_rtp_session.cpp
index e6490cad9339112f666d0cdd30dda47be3b80a56..a1b755bc54f3ef1368790b45b761b989e33cb6b6 100644
--- a/daemon/src/video/video_rtp_session.cpp
+++ b/daemon/src/video/video_rtp_session.cpp
@@ -35,6 +35,7 @@
 #include "video_send_thread.h"
 #include "video_receive_thread.h"
 #include "sip/sdp.h"
+#include "sip/sipvoiplink.h"
 #include "libav_utils.h"
 #include "manager.h"
 #include "logger.h"
@@ -133,21 +134,19 @@ void VideoRtpSession::start()
             WARN("Restarting video sender");
         sendThread_.reset(new VideoSendThread(txArgs_));
         sendThread_->start();
-    }
-    else
+    } else {
         DEBUG("Video sending disabled");
+    }
 
     if (receiving_) {
-        if (receiveThread_.get()) {
-            // FIXME: this is just until we fix onhold/offhold
-            WARN("Not restarting video receiver");
-        } else {
-            receiveThread_.reset(new VideoReceiveThread(callID_, rxArgs_));
-            receiveThread_->start();
-        }
-    }
-    else
+        if (receiveThread_.get())
+            WARN("restarting video receiver");
+        receiveThread_.reset(new VideoReceiveThread(callID_, rxArgs_));
+        receiveThread_->setRequestKeyFrameCallback(&SIPVoIPLink::requestFastPictureUpdate);
+        receiveThread_->start();
+    } else {
         DEBUG("Video receiving disabled");
+    }
 }
 
 void VideoRtpSession::stop()