From ad21283f7532a768cc455e621510c07d11e776d6 Mon Sep 17 00:00:00 2001
From: Tristan Matthews <tristan.matthews@savoirfairelinux.com>
Date: Mon, 23 Jul 2012 16:03:41 -0400
Subject: [PATCH] * #13731: video: request key frame on error and before
 probing stream info

---
 daemon/src/sip/sipvoiplink.cpp            | 38 ++++++++++++++---------
 daemon/src/sip/sipvoiplink.h              |  4 +++
 daemon/src/video/video_receive_thread.cpp | 26 ++++++++++------
 daemon/src/video/video_receive_thread.h   |  2 ++
 daemon/src/video/video_rtp_session.cpp    | 21 ++++++-------
 5 files changed, 56 insertions(+), 35 deletions(-)

diff --git a/daemon/src/sip/sipvoiplink.cpp b/daemon/src/sip/sipvoiplink.cpp
index d24de327f2..9004fe986f 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 47f1c91dc6..b4706b411e 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 9f91482fb2..48da041d97 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 f36126bec6..e0d03a4a7e 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 e6490cad93..a1b755bc54 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()
-- 
GitLab