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:
stefan@webrtc.org 2012-08-20 14:29:52 +00:00
parent 3994e0324d
commit 4e8eabaab1
7 changed files with 165 additions and 60 deletions

View File

@ -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 {

View File

@ -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)
{

View File

@ -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_),

View File

@ -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

View File

@ -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;
}

View File

@ -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'.

View File

@ -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;
}