diff --git a/src/video_engine/test/auto_test/source/vie_autotest_codec.cc b/src/video_engine/test/auto_test/source/vie_autotest_codec.cc index ad32761e1..1fbc1cdf0 100644 --- a/src/video_engine/test/auto_test/source/vie_autotest_codec.cc +++ b/src/video_engine/test/auto_test/source/vie_autotest_codec.cc @@ -19,6 +19,25 @@ #include "tb_video_channel.h" #include "vie_autotest_defines.h" +class RenderFilter : public webrtc::ViEEffectFilter { + public: + RenderFilter() + : last_render_width_(0), + last_render_height_(0) {} + + ~RenderFilter() {} + + virtual int Transform(int size, unsigned char* frame_buffer, + unsigned int time_stamp, unsigned int width, + unsigned int height) { + last_render_width_ = width; + last_render_height_ = height; + return 0; + } + unsigned int last_render_width_; + unsigned int last_render_height_; +}; + void ViEAutoTest::ViECodecStandardTest() { TbInterfaces interfaces = TbInterfaces("ViECodecStandardTest"); @@ -174,6 +193,8 @@ void ViEAutoTest::ViECodecExtendedTest() } } EXPECT_TRUE(codecSet); + webrtc::VideoCodec send_codec; + memcpy(&send_codec, &videoCodec, sizeof(videoCodec)); EXPECT_EQ(0, ViE.base->StartSend(videoChannel1)); EXPECT_EQ(0, ViE.base->StartReceive(videoChannel1)); @@ -215,13 +236,40 @@ void ViEAutoTest::ViECodecExtendedTest() AutoTestSleep(KAutoTestSleepTimeMs); - // Check that we received H.263 on both channels EXPECT_EQ(webrtc::kVideoCodecVP8, codecObserver1.incomingCodec.codecType); - EXPECT_EQ(176, codecObserver1.incomingCodec.width); + EXPECT_EQ(send_codec.width, codecObserver1.incomingCodec.width); EXPECT_EQ(webrtc::kVideoCodecVP8, codecObserver2.incomingCodec.codecType); - EXPECT_EQ(176, codecObserver2.incomingCodec.width); + EXPECT_EQ(send_codec.width, codecObserver2.incomingCodec.width); + + // Change resolution on one of the channels and verify it changes for + // the other channel too. + send_codec.width = 2 * codecWidth; + send_codec.height = 2 * codecHeight; + EXPECT_EQ(0, ViE.codec->SetSendCodec(videoChannel1, send_codec)); + + // We need to verify using render effect filter since we won't trigger + // a decode reset in loopback (due to using the same SSRC). + RenderFilter filter1; + RenderFilter filter2; + EXPECT_EQ(0, + ViE.image_process->RegisterRenderEffectFilter(videoChannel1, + filter1)); + EXPECT_EQ(0, + ViE.image_process->RegisterRenderEffectFilter(videoChannel2, + filter2)); + + AutoTestSleep(KAutoTestSleepTimeMs); + + EXPECT_EQ(0, ViE.image_process->DeregisterRenderEffectFilter( + videoChannel1)); + EXPECT_EQ(0, ViE.image_process->DeregisterRenderEffectFilter( + videoChannel2)); + EXPECT_EQ(send_codec.width, filter1.last_render_width_); + EXPECT_EQ(send_codec.height, filter1.last_render_height_); + EXPECT_EQ(send_codec.width, filter2.last_render_width_); + EXPECT_EQ(send_codec.height, filter2.last_render_height_); // Delete the first channel and keep the second EXPECT_EQ(0, ViE.base->DeleteChannel(videoChannel1)); diff --git a/src/video_engine/vie_channel_manager.cc b/src/video_engine/vie_channel_manager.cc index 6bfdde211..7bd22003e 100644 --- a/src/video_engine/vie_channel_manager.cc +++ b/src/video_engine/vie_channel_manager.cc @@ -470,6 +470,20 @@ bool ViEChannelManager::ChannelUsingViEEncoder(int channel_id) const { return false; } +void ViEChannelManager::ChannelsUsingViEEncoder(int channel_id, + ChannelList* channels) const { + CriticalSectionScoped cs(*channel_id_critsect_); + MapItem* encoder_item = vie_encoder_map_.Find(channel_id); + assert(encoder_item); + MapItem* channel_item = channel_map_.First(); + while (channel_item) { + if (vie_encoder_map_.Find(channel_item->GetId())) { + channels->push_back(static_cast(channel_item->GetItem())); + } + channel_item = channel_map_.Next(channel_item); + } +} + ViEChannelManagerScoped::ViEChannelManagerScoped( const ViEChannelManager& vie_channel_manager) : ViEManagerScopedBase(vie_channel_manager) { @@ -489,4 +503,10 @@ bool ViEChannelManagerScoped::ChannelUsingViEEncoder(int channel_id) const { ChannelUsingViEEncoder(channel_id); } +void ViEChannelManagerScoped::ChannelsUsingViEEncoder( + int channel_id, ChannelList* channels) const { + (static_cast(vie_manager_))-> + ChannelsUsingViEEncoder(channel_id, channels); +} + } // namespace webrtc diff --git a/src/video_engine/vie_channel_manager.h b/src/video_engine/vie_channel_manager.h index d4a9ef149..87737fc65 100644 --- a/src/video_engine/vie_channel_manager.h +++ b/src/video_engine/vie_channel_manager.h @@ -11,6 +11,8 @@ #ifndef WEBRTC_VIDEO_ENGINE_VIE_CHANNEL_MANAGER_H_ #define WEBRTC_VIDEO_ENGINE_VIE_CHANNEL_MANAGER_H_ +#include + #include "engine_configurations.h" #include "system_wrappers/interface/map_wrapper.h" #include "system_wrappers/interface/scoped_ptr.h" @@ -29,6 +31,8 @@ class VieRemb; class VoEVideoSync; class VoiceEngine; +typedef std::list ChannelList; + class ViEChannelManager: private ViEManagerBase { friend class ViEChannelManagerScoped; public: @@ -84,6 +88,7 @@ class ViEChannelManager: private ViEManagerBase { // Returns true if at least one other channels uses the same ViEEncoder as // channel_id. bool ChannelUsingViEEncoder(int channel_id) const; + void ChannelsUsingViEEncoder(int channel_id, ChannelList* channels) const; // Protects channel_map_ and free_channel_ids_. CriticalSectionWrapper* channel_id_critsect_; @@ -109,9 +114,13 @@ class ViEChannelManagerScoped: private ViEManagerScopedBase { ViEChannel* Channel(int vie_channel_id) const; ViEEncoder* Encoder(int vie_channel_id) const; - // Returns true if at lease one other channels uses the same ViEEncoder as + // Returns true if at least one other channels uses the same ViEEncoder as // channel_id. bool ChannelUsingViEEncoder(int channel_id) const; + + // Returns a list with pointers to all channels using the same encoder as the + // channel with |channel_id|, including the one with the specified id. + void ChannelsUsingViEEncoder(int channel_id, ChannelList* channels) const; }; } // namespace webrtc diff --git a/src/video_engine/vie_codec_impl.cc b/src/video_engine/vie_codec_impl.cc index 72b6f155f..bdfb4ad41 100644 --- a/src/video_engine/vie_codec_impl.cc +++ b/src/video_engine/vie_codec_impl.cc @@ -106,12 +106,23 @@ int ViECodecImpl::SetSendCodec(const int video_channel, video_channel, video_codec.codecType); WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(instance_id_, video_channel), "%s: codec: %d, pl_type: %d, width: %d, height: %d, bitrate: %d" - "maxBr: %d, min_br: %d, frame_rate: %d)", __FUNCTION__, + "maxBr: %d, min_br: %d, frame_rate: %d, qpMax: %u," + "numberOfSimulcastStreams: %u )", __FUNCTION__, video_codec.codecType, video_codec.plType, video_codec.width, video_codec.height, video_codec.startBitrate, video_codec.maxBitrate, video_codec.minBitrate, - video_codec.maxFramerate); - + video_codec.maxFramerate, video_codec.qpMax, + video_codec.numberOfSimulcastStreams); + if (video_codec.codecType == kVideoCodecVP8) { + WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(instance_id_, video_channel), + "pictureLossIndicationOn: %d, feedbackModeOn: %d, " + "complexity: %d, resilience: %d, numberOfTemporalLayers: %u", + video_codec.codecSpecific.VP8.pictureLossIndicationOn, + video_codec.codecSpecific.VP8.feedbackModeOn, + video_codec.codecSpecific.VP8.complexity, + video_codec.codecSpecific.VP8.resilience, + video_codec.codecSpecific.VP8.numberOfTemporalLayers); + } if (!CodecValid(video_codec)) { // Error logged. SetLastError(kViECodecInvalidCodec); @@ -154,23 +165,23 @@ int ViECodecImpl::SetSendCodec(const int video_channel, return -1; } - // We need to check if the codec settings changed, then we need a new SSRC. - bool new_rtp_stream = false; - VideoCodec encoder; vie_encoder->GetEncoder(encoder); - if (encoder.codecType != video_codec_internal.codecType || - encoder.width != video_codec_internal.width || - encoder.height != video_codec_internal.height) { - if (cs.ChannelUsingViEEncoder(video_channel)) { - // We don't allow changing codec type or size when several - // channels share encoder. + if (encoder.codecType != video_codec_internal.codecType && + cs.ChannelUsingViEEncoder(video_channel)) { + // We don't allow changing codec type when several channels share encoder. WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(instance_id_, video_channel), "%s: Settings differs from other channels using encoder", __FUNCTION__); SetLastError(kViECodecInUse); return -1; - } + } + // 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) { new_rtp_stream = true; } if (video_codec_internal.numberOfSimulcastStreams > 1) { @@ -219,13 +230,22 @@ int ViECodecImpl::SetSendCodec(const int video_channel, return -1; } - // Give the channel the new information. - if (vie_channel->SetSendCodec(video_codec_internal, new_rtp_stream) != 0) { - WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel), - "%s: Could not set send codec for channel %d", __FUNCTION__, - video_channel); - SetLastError(kViECodecUnknownError); - return -1; + // Give the channel(s) the new information. + ChannelList channels; + cs.ChannelsUsingViEEncoder(video_channel, &channels); + for (ChannelList::iterator it = channels.begin(); it != channels.end(); + ++it) { + bool ret = true; + if ((*it)->SetSendCodec(video_codec_internal, new_rtp_stream) != 0) { + WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(instance_id_, video_channel), + "%s: Could not set send codec for channel %d", __FUNCTION__, + video_channel); + ret = false; + } + if (!ret) { + SetLastError(kViECodecUnknownError); + return -1; + } } // Update the protection mode, we might be switching NACK/FEC.