Properly handle switching between simulcast and unicast streams.
BUG= Review URL: https://webrtc-codereview.appspot.com/733010 git-svn-id: http://webrtc.googlecode.com/svn/trunk@2644 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
3994e0324d
commit
4e8eabaab1
@ -834,11 +834,22 @@ WebRtc_Word32 ModuleRtpRtcpImpl::SendOutgoingData(
|
||||
int idx = 0;
|
||||
CriticalSectionScoped lock(_criticalSectionModulePtrs.get());
|
||||
std::list<ModuleRtpRtcpImpl*>::iterator it = _childModules.begin();
|
||||
for (; idx < rtpVideoHdr->simulcastIdx; idx++) {
|
||||
it++;
|
||||
for (; idx < rtpVideoHdr->simulcastIdx; ++it) {
|
||||
if (it == _childModules.end()) {
|
||||
return -1;
|
||||
}
|
||||
if ((*it)->SendingMedia()) {
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
for (; it != _childModules.end(); ++it) {
|
||||
if ((*it)->SendingMedia()) {
|
||||
break;
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
if (it == _childModules.end()) {
|
||||
return -1;
|
||||
}
|
||||
RTPSender& rtpSender = (*it)->_rtpSender;
|
||||
WEBRTC_TRACE(kTraceModuleCall,
|
||||
@ -1632,17 +1643,20 @@ void ModuleRtpRtcpImpl::SetTargetSendBitrate(const uint32_t bitrate) {
|
||||
uint32_t bitrate_remainder = bitrate;
|
||||
std::list<ModuleRtpRtcpImpl*>::iterator it = _childModules.begin();
|
||||
for (int i = 0; it != _childModules.end() &&
|
||||
i < _sendVideoCodec.numberOfSimulcastStreams; ++it, ++i) {
|
||||
RTPSender& rtpSender = (*it)->_rtpSender;
|
||||
if (_sendVideoCodec.simulcastStream[i].maxBitrate * 1000 >
|
||||
bitrate_remainder) {
|
||||
rtpSender.SetTargetSendBitrate(bitrate_remainder);
|
||||
bitrate_remainder = 0;
|
||||
} else {
|
||||
rtpSender.SetTargetSendBitrate(
|
||||
_sendVideoCodec.simulcastStream[i].maxBitrate * 1000);
|
||||
bitrate_remainder -=
|
||||
_sendVideoCodec.simulcastStream[i].maxBitrate * 1000;
|
||||
i < _sendVideoCodec.numberOfSimulcastStreams; ++it) {
|
||||
if ((*it)->SendingMedia()) {
|
||||
++i;
|
||||
RTPSender& rtpSender = (*it)->_rtpSender;
|
||||
if (_sendVideoCodec.simulcastStream[i].maxBitrate * 1000 >
|
||||
bitrate_remainder) {
|
||||
rtpSender.SetTargetSendBitrate(bitrate_remainder);
|
||||
bitrate_remainder = 0;
|
||||
} else {
|
||||
rtpSender.SetTargetSendBitrate(
|
||||
_sendVideoCodec.simulcastStream[i].maxBitrate * 1000);
|
||||
bitrate_remainder -=
|
||||
_sendVideoCodec.simulcastStream[i].maxBitrate * 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
@ -25,6 +25,46 @@
|
||||
#define VCM_RED_PAYLOAD_TYPE 96
|
||||
#define VCM_ULPFEC_PAYLOAD_TYPE 97
|
||||
|
||||
void InitialSingleStreamSettings(webrtc::VideoCodec* video_codec) {
|
||||
video_codec->numberOfSimulcastStreams = 0;
|
||||
video_codec->width = 1200;
|
||||
video_codec->height = 800;
|
||||
}
|
||||
|
||||
void SetSimulcastSettings(webrtc::VideoCodec* video_codec) {
|
||||
video_codec->width = 1280;
|
||||
video_codec->height = 720;
|
||||
// simulcast settings
|
||||
video_codec->numberOfSimulcastStreams = 3;
|
||||
video_codec->simulcastStream[0].width = 320;
|
||||
video_codec->simulcastStream[0].height = 180;
|
||||
video_codec->simulcastStream[0].numberOfTemporalLayers = 0;
|
||||
video_codec->simulcastStream[0].maxBitrate = 100;
|
||||
video_codec->simulcastStream[0].qpMax = video_codec->qpMax;
|
||||
|
||||
video_codec->simulcastStream[1].width = 640;
|
||||
video_codec->simulcastStream[1].height = 360;
|
||||
video_codec->simulcastStream[1].numberOfTemporalLayers = 0;
|
||||
video_codec->simulcastStream[1].maxBitrate = 500;
|
||||
video_codec->simulcastStream[1].qpMax = video_codec->qpMax;
|
||||
|
||||
video_codec->simulcastStream[2].width = 1280;
|
||||
video_codec->simulcastStream[2].height = 720;
|
||||
video_codec->simulcastStream[2].numberOfTemporalLayers = 0;
|
||||
video_codec->simulcastStream[2].maxBitrate = 1200;
|
||||
video_codec->simulcastStream[2].qpMax = video_codec->qpMax;
|
||||
}
|
||||
|
||||
void RuntimeSingleStreamSettings(webrtc::VideoCodec* video_codec) {
|
||||
SetSimulcastSettings(video_codec);
|
||||
video_codec->width = 1200;
|
||||
video_codec->height = 800;
|
||||
video_codec->numberOfSimulcastStreams = 3;
|
||||
video_codec->simulcastStream[0].maxBitrate = 0;
|
||||
video_codec->simulcastStream[1].maxBitrate = 0;
|
||||
video_codec->simulcastStream[2].maxBitrate = 0;
|
||||
}
|
||||
|
||||
int VideoEngineSimulcastTest(void* window1, void* window2)
|
||||
{
|
||||
//********************************************************
|
||||
@ -283,29 +323,16 @@ int VideoEngineSimulcastTest(void* window1, void* window2)
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool simulcast_mode = true;
|
||||
int num_streams = 1;
|
||||
// Set spatial resolution option
|
||||
videoCodec.width = 1280;
|
||||
videoCodec.height = 720;
|
||||
|
||||
// simulcast settings
|
||||
videoCodec.numberOfSimulcastStreams = 3;
|
||||
videoCodec.simulcastStream[0].width = 320;
|
||||
videoCodec.simulcastStream[0].height = 180;
|
||||
videoCodec.simulcastStream[0].numberOfTemporalLayers = 0;
|
||||
videoCodec.simulcastStream[0].maxBitrate = 100;
|
||||
videoCodec.simulcastStream[0].qpMax = videoCodec.qpMax;
|
||||
|
||||
videoCodec.simulcastStream[1].width = 640;
|
||||
videoCodec.simulcastStream[1].height = 360;
|
||||
videoCodec.simulcastStream[1].numberOfTemporalLayers = 0;
|
||||
videoCodec.simulcastStream[1].maxBitrate = 500;
|
||||
videoCodec.simulcastStream[1].qpMax = videoCodec.qpMax;
|
||||
|
||||
videoCodec.simulcastStream[2].width = 1280;
|
||||
videoCodec.simulcastStream[2].height = 720;
|
||||
videoCodec.simulcastStream[2].numberOfTemporalLayers = 0;
|
||||
videoCodec.simulcastStream[2].maxBitrate = 1200;
|
||||
videoCodec.simulcastStream[2].qpMax = videoCodec.qpMax;
|
||||
if (simulcast_mode) {
|
||||
SetSimulcastSettings(&videoCodec);
|
||||
num_streams = videoCodec.numberOfSimulcastStreams;
|
||||
} else {
|
||||
InitialSingleStreamSettings(&videoCodec);
|
||||
num_streams = 1;
|
||||
}
|
||||
|
||||
// Set start bit rate
|
||||
std::string str;
|
||||
@ -351,20 +378,21 @@ int VideoEngineSimulcastTest(void* window1, void* window2)
|
||||
// Set network delay value
|
||||
extTransport.SetNetworkDelay(10);
|
||||
|
||||
extTransport.SetSSRCFilter(3);
|
||||
|
||||
for (int idx = 0; idx < 3; idx++)
|
||||
for (int idx = 0; idx < num_streams; idx++)
|
||||
{
|
||||
error = ptrViERtpRtcp->SetLocalSSRC(videoChannel,
|
||||
idx+1, // SSRC
|
||||
webrtc::kViEStreamTypeNormal,
|
||||
idx);
|
||||
error = ptrViERtpRtcp->SetLocalSSRC(
|
||||
videoChannel,
|
||||
idx+1, // SSRC
|
||||
webrtc::kViEStreamTypeNormal,
|
||||
idx);
|
||||
if (error == -1)
|
||||
{
|
||||
printf("ERROR in ViERTP_RTCP::SetLocalSSRC(idx:%d)\n", idx);
|
||||
printf("ERROR in ViERTP_RTCP::SetLocalSSRC(idx:%d)\n",
|
||||
idx);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
extTransport.SetSSRCFilter(num_streams);
|
||||
|
||||
error = ptrViEBase->StartReceive(videoChannel);
|
||||
if (error == -1)
|
||||
@ -380,6 +408,15 @@ int VideoEngineSimulcastTest(void* window1, void* window2)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create a receive channel to verify that it doesn't mess up toggling
|
||||
// between single stream and simulcast.
|
||||
int videoChannel2 = -1;
|
||||
error = ptrViEBase->CreateReceiveChannel(videoChannel2, videoChannel);
|
||||
if (error == -1) {
|
||||
printf("ERROR in ViEBase::CreateReceiveChannel\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//********************************************************
|
||||
// Engine started
|
||||
//********************************************************
|
||||
@ -388,13 +425,46 @@ int VideoEngineSimulcastTest(void* window1, void* window2)
|
||||
do
|
||||
{
|
||||
printf("Enter new SSRC filter 1,2 or 3\n");
|
||||
printf("... or 0 to switch between simulcast and a single stream\n");
|
||||
printf("Press enter to stop...");
|
||||
str.clear();
|
||||
std::getline(std::cin, str);
|
||||
if (!str.empty())
|
||||
{
|
||||
int ssrc = atoi(str.c_str());
|
||||
if (ssrc > 0 && ssrc < 4)
|
||||
if (ssrc == 0) {
|
||||
// Toggle between simulcast and a single stream with different
|
||||
// resolution.
|
||||
if (simulcast_mode) {
|
||||
RuntimeSingleStreamSettings(&videoCodec);
|
||||
num_streams = 1;
|
||||
printf("Disabling simulcast\n");
|
||||
} else {
|
||||
SetSimulcastSettings(&videoCodec);
|
||||
num_streams = videoCodec.numberOfSimulcastStreams;
|
||||
printf("Enabling simulcast\n");
|
||||
}
|
||||
simulcast_mode = !simulcast_mode;
|
||||
if (ptrViECodec->SetSendCodec(videoChannel, videoCodec) != 0) {
|
||||
printf("ERROR switching between simulcast and single stream\n");
|
||||
return -1;
|
||||
}
|
||||
for (int idx = 0; idx < num_streams; idx++)
|
||||
{
|
||||
error = ptrViERtpRtcp->SetLocalSSRC(
|
||||
videoChannel,
|
||||
idx+1, // SSRC
|
||||
webrtc::kViEStreamTypeNormal,
|
||||
idx);
|
||||
if (error == -1)
|
||||
{
|
||||
printf("ERROR in ViERTP_RTCP::SetLocalSSRC(idx:%d)\n",
|
||||
idx);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
extTransport.SetSSRCFilter(num_streams);
|
||||
} else if (ssrc > 0 && ssrc < 4)
|
||||
{
|
||||
extTransport.SetSSRCFilter(ssrc);
|
||||
} else
|
||||
@ -411,6 +481,13 @@ int VideoEngineSimulcastTest(void* window1, void* window2)
|
||||
// Testing finished. Tear down Video Engine
|
||||
//********************************************************
|
||||
|
||||
error = ptrViEBase->DeleteChannel(videoChannel2);
|
||||
if (error == -1)
|
||||
{
|
||||
printf("ERROR in ViEBase::DeleteChannel\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
error = ptrViEBase->StopReceive(videoChannel);
|
||||
if (error == -1)
|
||||
{
|
||||
|
@ -40,7 +40,8 @@ ViEChannel::ViEChannel(WebRtc_Word32 channel_id,
|
||||
RtcpIntraFrameObserver* intra_frame_observer,
|
||||
RtcpBandwidthObserver* bandwidth_observer,
|
||||
RemoteBitrateEstimator* remote_bitrate_estimator,
|
||||
RtpRtcp* default_rtp_rtcp)
|
||||
RtpRtcp* default_rtp_rtcp,
|
||||
bool sender)
|
||||
: ViEFrameProviderBase(channel_id, engine_id),
|
||||
channel_id_(channel_id),
|
||||
engine_id_(engine_id),
|
||||
@ -78,7 +79,8 @@ ViEChannel::ViEChannel(WebRtc_Word32 channel_id,
|
||||
color_enhancement_(false),
|
||||
vcm_rttreported_(TickTime::Now()),
|
||||
file_recorder_(channel_id),
|
||||
mtu_(0) {
|
||||
mtu_(0),
|
||||
sender_(sender) {
|
||||
WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id, channel_id),
|
||||
"ViEChannel::ViEChannel(channel_id: %d, engine_id: %d)",
|
||||
channel_id, engine_id);
|
||||
@ -204,6 +206,9 @@ WebRtc_Word32 ViEChannel::SetSendCodec(const VideoCodec& video_codec,
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
|
||||
"%s: codec_type: %d", __FUNCTION__, video_codec.codecType);
|
||||
|
||||
if (!sender_) {
|
||||
return 0;
|
||||
}
|
||||
if (video_codec.codecType == kVideoCodecRED ||
|
||||
video_codec.codecType == kVideoCodecULPFEC) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
|
||||
|
@ -63,7 +63,8 @@ class ViEChannel
|
||||
RtcpIntraFrameObserver* intra_frame_observer,
|
||||
RtcpBandwidthObserver* bandwidth_observer,
|
||||
RemoteBitrateEstimator* remote_bitrate_estimator,
|
||||
RtpRtcp* default_rtp_rtcp);
|
||||
RtpRtcp* default_rtp_rtcp,
|
||||
bool sender);
|
||||
~ViEChannel();
|
||||
|
||||
WebRtc_Word32 Init();
|
||||
@ -396,6 +397,7 @@ class ViEChannel
|
||||
|
||||
// User set MTU, -1 if not set.
|
||||
uint16_t mtu_;
|
||||
const bool sender_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -104,7 +104,7 @@ int ViEChannelManager::CreateChannel(int* channel_id) {
|
||||
|
||||
if (!(vie_encoder->Init() &&
|
||||
CreateChannelObject(new_channel_id, vie_encoder, bandwidth_observer,
|
||||
remote_bitrate_estimator))) {
|
||||
remote_bitrate_estimator, true))) {
|
||||
delete vie_encoder;
|
||||
vie_encoder = NULL;
|
||||
ReturnChannelId(new_channel_id);
|
||||
@ -149,7 +149,8 @@ int ViEChannelManager::CreateChannel(int* channel_id,
|
||||
if (!(vie_encoder->Init() &&
|
||||
CreateChannelObject(new_channel_id, vie_encoder,
|
||||
bandwidth_observer,
|
||||
remote_bitrate_estimator))) {
|
||||
remote_bitrate_estimator,
|
||||
sender))) {
|
||||
delete vie_encoder;
|
||||
vie_encoder = NULL;
|
||||
}
|
||||
@ -157,7 +158,7 @@ int ViEChannelManager::CreateChannel(int* channel_id,
|
||||
vie_encoder = ViEEncoderPtr(original_channel);
|
||||
assert(vie_encoder);
|
||||
if (!CreateChannelObject(new_channel_id, vie_encoder, bandwidth_observer,
|
||||
remote_bitrate_estimator)) {
|
||||
remote_bitrate_estimator, sender)) {
|
||||
vie_encoder = NULL;
|
||||
}
|
||||
}
|
||||
@ -329,7 +330,8 @@ bool ViEChannelManager::CreateChannelObject(
|
||||
int channel_id,
|
||||
ViEEncoder* vie_encoder,
|
||||
RtcpBandwidthObserver* bandwidth_observer,
|
||||
RemoteBitrateEstimator* remote_bitrate_estimator) {
|
||||
RemoteBitrateEstimator* remote_bitrate_estimator,
|
||||
bool sender) {
|
||||
// Register the channel at the encoder.
|
||||
RtpRtcp* send_rtp_rtcp_module = vie_encoder->SendRtpRtcpModule();
|
||||
|
||||
@ -339,7 +341,8 @@ bool ViEChannelManager::CreateChannelObject(
|
||||
vie_encoder,
|
||||
bandwidth_observer,
|
||||
remote_bitrate_estimator,
|
||||
send_rtp_rtcp_module);
|
||||
send_rtp_rtcp_module,
|
||||
sender);
|
||||
if (vie_channel->Init() != 0) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_),
|
||||
"%s could not init channel", __FUNCTION__, channel_id);
|
||||
@ -347,10 +350,15 @@ bool ViEChannelManager::CreateChannelObject(
|
||||
return false;
|
||||
}
|
||||
VideoCodec encoder;
|
||||
if (vie_encoder->GetEncoder(&encoder) != 0 ||
|
||||
vie_channel->SetSendCodec(encoder) != 0) {
|
||||
if (vie_encoder->GetEncoder(&encoder) != 0) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id),
|
||||
"%s: Could not GetEncoder or SetSendCodec.", __FUNCTION__);
|
||||
"%s: Could not GetEncoder.", __FUNCTION__);
|
||||
delete vie_channel;
|
||||
return false;
|
||||
}
|
||||
if (sender && vie_channel->SetSendCodec(encoder) != 0) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id),
|
||||
"%s: Could not SetSendCodec.", __FUNCTION__);
|
||||
delete vie_channel;
|
||||
return false;
|
||||
}
|
||||
|
@ -79,7 +79,8 @@ class ViEChannelManager: private ViEManagerBase {
|
||||
// protected.
|
||||
bool CreateChannelObject(int channel_id, ViEEncoder* vie_encoder,
|
||||
RtcpBandwidthObserver* bandwidth_observer,
|
||||
RemoteBitrateEstimator* remote_bitrate_estimator);
|
||||
RemoteBitrateEstimator* remote_bitrate_estimator,
|
||||
bool sender);
|
||||
|
||||
// Used by ViEChannelScoped, forcing a manager user to use scoped.
|
||||
// Returns a pointer to the channel with id 'channel_id'.
|
||||
|
@ -179,9 +179,7 @@ int ViECodecImpl::SetSendCodec(const int video_channel,
|
||||
// Make sure to generate a new SSRC if the codec type and/or resolution has
|
||||
// changed. This won't have any effect if the user has set an SSRC.
|
||||
bool new_rtp_stream = false;
|
||||
if (encoder.codecType != video_codec_internal.codecType ||
|
||||
encoder.width != video_codec_internal.width ||
|
||||
encoder.height != video_codec_internal.height) {
|
||||
if (encoder.codecType != video_codec_internal.codecType) {
|
||||
new_rtp_stream = true;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user