From 9838b08919267da21bd93f2ec496b63bae1713c2 Mon Sep 17 00:00:00 2001 From: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com> Date: Thu, 19 Mar 2020 12:02:23 -0400 Subject: [PATCH] video: fix incoming video for iOS During incoming calls to iOS, video input failed to open sometimes. It happens for two reasons: 1. Stopped by interrupt callback. 2. Keyframe callback was set two late. This patch: 1. Completes decoder configuration after video loop start running. 2. Sets keyframe callback for video session before starting. Change-Id: I00e1ace06a78ab2ec2fb3ce6fe6a5991c6593318 --- src/media/video/video_receive_thread.cpp | 76 ++++++++++++++---------- src/media/video/video_receive_thread.h | 2 + src/sip/sipcall.cpp | 18 +++--- 3 files changed, 57 insertions(+), 39 deletions(-) diff --git a/src/media/video/video_receive_thread.cpp b/src/media/video/video_receive_thread.cpp index 6a86e8f687..2924a326aa 100644 --- a/src/media/video/video_receive_thread.cpp +++ b/src/media/video/video_receive_thread.cpp @@ -52,6 +52,7 @@ VideoReceiveThread::VideoReceiveThread(const std::string& id, , stream_(sdp) , sdpContext_(stream_.str().size(), false, &readFunction, 0, 0, this) , sink_ {Manager::instance().createSinkClient(id)} + , isVideoConfigured_(false) , mtu_(mtu) , rotation_(0) , loop_(std::bind(&VideoReceiveThread::setup, this), @@ -119,36 +120,6 @@ bool VideoReceiveThread::setup() // Now replace our custom AVIOContext with one that will read packets videoDecoder_->setIOContext(demuxContext_.get()); } - - if (videoDecoder_->setupVideo()) { - JAMI_ERR("decoder IO startup failed"); - return false; - } - - // Default size from input video - if (dstWidth_ == 0 and dstHeight_ == 0) { - dstWidth_ = videoDecoder_->getWidth(); - dstHeight_ = videoDecoder_->getHeight(); - } - - if (not sink_->start()) { - JAMI_ERR("RX: sink startup failed"); - return false; - } - - auto conf = Manager::instance().getConferenceFromCallID(id_); - if (!conf) - exitConference(); - - // Send remote video codec in SmartInfo - Smartools::getInstance().setRemoteVideoCodec(videoDecoder_->getDecoderName(), id_); - - // Send the resolution in smartInfo - Smartools::getInstance().setResolution(id_, dstWidth_, dstHeight_); - - if (onSetupSuccess_) - onSetupSuccess_(MEDIA_VIDEO); - return true; } @@ -187,6 +158,9 @@ void VideoReceiveThread::addIOContext(SocketPair& socketPair) void VideoReceiveThread::decodeFrame() { + if (!configureVideoOutput()) { + return; + } auto status = videoDecoder_->decode(); if (status == MediaDemuxer::Status::EndOfFile || status == MediaDemuxer::Status::ReadError) { @@ -198,6 +172,48 @@ void VideoReceiveThread::decodeFrame() } } +bool VideoReceiveThread::configureVideoOutput() +{ + if (isVideoConfigured_) { + return true; + } + if (!loop_.isRunning()) { + return false; + } + if (videoDecoder_->setupVideo()) { + JAMI_ERR("decoder IO startup failed"); + loop_.stop(); + return false; + } + + // Default size from input video + if (dstWidth_ == 0 and dstHeight_ == 0) { + dstWidth_ = videoDecoder_->getWidth(); + dstHeight_ = videoDecoder_->getHeight(); + } + + if (not sink_->start()) { + JAMI_ERR("RX: sink startup failed"); + loop_.stop(); + return false; + } + + auto conf = Manager::instance().getConferenceFromCallID(id_); + if (!conf) + exitConference(); + + // Send remote video codec in SmartInfo + Smartools::getInstance().setRemoteVideoCodec(videoDecoder_->getDecoderName(), id_); + + // Send the resolution in smartInfo + Smartools::getInstance().setResolution(id_, dstWidth_, dstHeight_); + + if (onSetupSuccess_) + onSetupSuccess_(MEDIA_VIDEO); + isVideoConfigured_ = true; + return true; +} + void VideoReceiveThread::enterConference() { if (!loop_.isRunning()) diff --git a/src/media/video/video_receive_thread.h b/src/media/video/video_receive_thread.h index 757bd8829d..9f1379e8e1 100644 --- a/src/media/video/video_receive_thread.h +++ b/src/media/video/video_receive_thread.h @@ -91,6 +91,7 @@ private: std::unique_ptr<MediaIOHandle> demuxContext_; std::shared_ptr<SinkClient> sink_; bool isReset_; + bool isVideoConfigured_; uint16_t mtu_; int rotation_; std::shared_ptr<AVBufferRef> displayMatrix_; @@ -99,6 +100,7 @@ private: void decodeFrame(); static int interruptCb(void *ctx); static int readFunction(void *opaque, uint8_t *buf, int buf_size); + bool configureVideoOutput(); std::function<void(MediaType)> onSetupSuccess_; diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp index 174b149d4f..f90d5488b9 100644 --- a/src/sip/sipcall.cpp +++ b/src/sip/sipcall.cpp @@ -982,6 +982,15 @@ SIPCall::startAllMedia() rtp->setSuccessfulSetupCb([this](MediaType type){ rtpSetupSuccess(type); }); +#ifdef ENABLE_VIDEO + videortp_->setRequestKeyFrameCallback([wthis = weak()] { + runOnMainThread([wthis] { + if (auto this_ = wthis.lock()) + this_->requestKeyframe(); + }); + }); +#endif + // Not restarting media loop on hold as it's a huge waste of CPU ressources // because of the audio loop if (getState() != CallState::HOLD) { @@ -1006,15 +1015,6 @@ SIPCall::startAllMedia() } } -#ifdef ENABLE_VIDEO - videortp_->setRequestKeyFrameCallback([wthis = weak()] { - runOnMainThread([wthis] { - if (auto this_ = wthis.lock()) - this_->requestKeyframe(); - }); - }); -#endif - if (not isSubcall() and peerHolding_ != peer_holding) { peerHolding_ = peer_holding; emitSignal<DRing::CallSignal::PeerHold>(getCallId(), peerHolding_); -- GitLab