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