|  | /* | 
|  | *  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 | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include "webrtc/common_types.h" | 
|  | #include "webrtc/engine_configurations.h" | 
|  | #include "webrtc/modules/video_coding/codecs/i420/main/interface/i420.h" | 
|  | #include "webrtc/system_wrappers/interface/scoped_ptr.h" | 
|  | #include "webrtc/test/channel_transport/include/channel_transport.h" | 
|  | #include "webrtc/video_engine/include/vie_base.h" | 
|  | #include "webrtc/video_engine/include/vie_capture.h" | 
|  | #include "webrtc/video_engine/include/vie_codec.h" | 
|  | #include "webrtc/video_engine/include/vie_external_codec.h" | 
|  | #include "webrtc/video_engine/include/vie_network.h" | 
|  | #include "webrtc/video_engine/include/vie_render.h" | 
|  | #include "webrtc/video_engine/include/vie_rtp_rtcp.h" | 
|  | #include "webrtc/video_engine/test/auto_test/interface/vie_autotest.h" | 
|  | #include "webrtc/video_engine/test/auto_test/interface/vie_autotest_defines.h" | 
|  | #include "webrtc/video_engine/test/libvietest/include/tb_I420_codec.h" | 
|  | #include "webrtc/video_engine/test/libvietest/include/tb_capture_device.h" | 
|  | #include "webrtc/video_engine/test/libvietest/include/tb_interfaces.h" | 
|  | #include "webrtc/video_engine/test/libvietest/include/tb_video_channel.h" | 
|  | #include "webrtc/voice_engine/include/voe_base.h" | 
|  |  | 
|  | class TestCodecObserver : public webrtc::ViEEncoderObserver, | 
|  | public webrtc::ViEDecoderObserver { | 
|  | public: | 
|  | int incoming_codec_called_; | 
|  | int incoming_rate_called_; | 
|  | int decoder_timing_called_; | 
|  | int outgoing_rate_called_; | 
|  |  | 
|  | unsigned char last_payload_type_; | 
|  | uint16_t last_width_; | 
|  | uint16_t last_height_; | 
|  |  | 
|  | unsigned int last_outgoing_framerate_; | 
|  | unsigned int last_outgoing_bitrate_; | 
|  | unsigned int last_incoming_framerate_; | 
|  | unsigned int last_incoming_bitrate_; | 
|  | unsigned int video_auto_muted_called_; | 
|  |  | 
|  | webrtc::VideoCodec incoming_codec_; | 
|  |  | 
|  | TestCodecObserver() | 
|  | : incoming_codec_called_(0), | 
|  | incoming_rate_called_(0), | 
|  | decoder_timing_called_(0), | 
|  | outgoing_rate_called_(0), | 
|  | last_payload_type_(0), | 
|  | last_width_(0), | 
|  | last_height_(0), | 
|  | last_outgoing_framerate_(0), | 
|  | last_outgoing_bitrate_(0), | 
|  | last_incoming_framerate_(0), | 
|  | last_incoming_bitrate_(0), | 
|  | video_auto_muted_called_(0) { | 
|  | memset(&incoming_codec_, 0, sizeof(incoming_codec_)); | 
|  | } | 
|  | virtual void IncomingCodecChanged(const int video_channel, | 
|  | const webrtc::VideoCodec& video_codec) { | 
|  | incoming_codec_called_++; | 
|  | last_payload_type_ = video_codec.plType; | 
|  | last_width_ = video_codec.width; | 
|  | last_height_ = video_codec.height; | 
|  |  | 
|  | memcpy(&incoming_codec_, &video_codec, sizeof(video_codec)); | 
|  | } | 
|  |  | 
|  | virtual void IncomingRate(const int video_channel, | 
|  | const unsigned int framerate, | 
|  | const unsigned int bitrate) { | 
|  | incoming_rate_called_++; | 
|  | last_incoming_framerate_ += framerate; | 
|  | last_incoming_bitrate_ += bitrate; | 
|  | } | 
|  |  | 
|  | virtual void DecoderTiming(int decode_ms, | 
|  | int max_decode_ms, | 
|  | int current_delay_ms, | 
|  | int target_delay_ms, | 
|  | int jitter_buffer_ms, | 
|  | int min_playout_delay_ms, | 
|  | int render_delay_ms) { | 
|  | ++decoder_timing_called_; | 
|  | // TODO(fischman): anything useful to be done with the data here? | 
|  | } | 
|  |  | 
|  | virtual void OutgoingRate(const int video_channel, | 
|  | const unsigned int framerate, | 
|  | const unsigned int bitrate) { | 
|  | outgoing_rate_called_++; | 
|  | last_outgoing_framerate_ += framerate; | 
|  | last_outgoing_bitrate_ += bitrate; | 
|  | } | 
|  |  | 
|  | virtual void VideoAutoMuted(int video_channel, bool is_muted) { | 
|  | video_auto_muted_called_++; | 
|  | } | 
|  |  | 
|  | virtual void RequestNewKeyFrame(const int video_channel) { | 
|  | } | 
|  | }; | 
|  |  | 
|  | class RenderFilter : public webrtc::ViEEffectFilter { | 
|  | public: | 
|  | int num_frames_; | 
|  | unsigned int last_render_width_; | 
|  | unsigned int last_render_height_; | 
|  |  | 
|  | RenderFilter() | 
|  | : num_frames_(0), | 
|  | last_render_width_(0), | 
|  | last_render_height_(0) { | 
|  | } | 
|  |  | 
|  | virtual ~RenderFilter() { | 
|  | } | 
|  | virtual int Transform(int size, | 
|  | unsigned char* frame_buffer, | 
|  | unsigned int time_stamp90KHz, | 
|  | unsigned int width, | 
|  | unsigned int height)  { | 
|  | num_frames_++; | 
|  | last_render_width_ = width; | 
|  | last_render_height_ = height; | 
|  | return 0; | 
|  | } | 
|  | }; | 
|  |  | 
|  | void ViEAutoTest::ViECodecStandardTest() { | 
|  | TbInterfaces interfaces("ViECodecStandardTest"); | 
|  |  | 
|  | TbCaptureDevice capture_device = TbCaptureDevice(interfaces); | 
|  | int capture_id = capture_device.captureId; | 
|  |  | 
|  | webrtc::VideoEngine* video_engine = interfaces.video_engine; | 
|  | webrtc::ViEBase* base = interfaces.base; | 
|  | webrtc::ViECapture* capture = interfaces.capture; | 
|  | webrtc::ViERender* render = interfaces.render; | 
|  | webrtc::ViECodec* codec = interfaces.codec; | 
|  | webrtc::ViERTP_RTCP* rtp_rtcp = interfaces.rtp_rtcp; | 
|  | webrtc::ViENetwork* network = interfaces.network; | 
|  |  | 
|  | int video_channel = -1; | 
|  | EXPECT_EQ(0, base->CreateChannel(video_channel)); | 
|  | EXPECT_EQ(0, capture->ConnectCaptureDevice(capture_id, video_channel)); | 
|  | EXPECT_EQ(0, rtp_rtcp->SetRTCPStatus( | 
|  | video_channel, webrtc::kRtcpCompound_RFC4585)); | 
|  |  | 
|  | EXPECT_EQ(0, rtp_rtcp->SetKeyFrameRequestMethod( | 
|  | video_channel, webrtc::kViEKeyFrameRequestPliRtcp)); | 
|  | EXPECT_EQ(0, rtp_rtcp->SetTMMBRStatus(video_channel, true)); | 
|  | EXPECT_EQ(0, render->AddRenderer(capture_id, _window1, 0, 0.0, 0.0, 1.0, | 
|  | 1.0)); | 
|  | EXPECT_EQ(0, render->AddRenderer(video_channel, _window2, 1, 0.0, 0.0, 1.0, | 
|  | 1.0)); | 
|  | EXPECT_EQ(0, render->StartRender(capture_id)); | 
|  | EXPECT_EQ(0, render->StartRender(video_channel)); | 
|  |  | 
|  | webrtc::VideoCodec video_codec; | 
|  | memset(&video_codec, 0, sizeof(webrtc::VideoCodec)); | 
|  | for (int idx = 0; idx < codec->NumberOfCodecs(); idx++) { | 
|  | EXPECT_EQ(0, codec->GetCodec(idx, video_codec)); | 
|  | if (video_codec.codecType != webrtc::kVideoCodecI420) { | 
|  | video_codec.width = 640; | 
|  | video_codec.height = 480; | 
|  | } | 
|  | if (video_codec.codecType == webrtc::kVideoCodecI420) { | 
|  | video_codec.width = 176; | 
|  | video_codec.height = 144; | 
|  | } | 
|  | EXPECT_EQ(0, codec->SetReceiveCodec(video_channel, video_codec)); | 
|  | } | 
|  |  | 
|  | for (int idx = 0; idx < codec->NumberOfCodecs(); idx++) { | 
|  | EXPECT_EQ(0, codec->GetCodec(idx, video_codec)); | 
|  | if (video_codec.codecType == webrtc::kVideoCodecVP8) { | 
|  | EXPECT_EQ(0, codec->SetSendCodec(video_channel, video_codec)); | 
|  | break; | 
|  | } | 
|  | } | 
|  | const char* ip_address = "127.0.0.1"; | 
|  | const uint16_t rtp_port = 6000; | 
|  |  | 
|  | webrtc::scoped_ptr<webrtc::test::VideoChannelTransport> | 
|  | video_channel_transport( | 
|  | new webrtc::test::VideoChannelTransport(network, video_channel)); | 
|  |  | 
|  | ASSERT_EQ(0, video_channel_transport->SetSendDestination(ip_address, | 
|  | rtp_port)); | 
|  | ASSERT_EQ(0, video_channel_transport->SetLocalReceiver(rtp_port)); | 
|  |  | 
|  | EXPECT_EQ(0, base->StartReceive(video_channel)); | 
|  | EXPECT_EQ(0, base->StartSend(video_channel)); | 
|  |  | 
|  | // Make sure all codecs runs | 
|  | { | 
|  | webrtc::ViEImageProcess* image_process = | 
|  | webrtc::ViEImageProcess::GetInterface(video_engine); | 
|  | TestCodecObserver codec_observer; | 
|  | EXPECT_EQ(0, codec->RegisterDecoderObserver(video_channel, codec_observer)); | 
|  | ViETest::Log("Loop through all codecs for %d seconds", | 
|  | kAutoTestSleepTimeMs / 1000); | 
|  |  | 
|  | for (int i = 0; i < codec->NumberOfCodecs() - 2; i++) { | 
|  | EXPECT_EQ(0, codec->GetCodec(i, video_codec)); | 
|  | if (video_codec.codecType == webrtc::kVideoCodecI420) { | 
|  | // Lower resolution to sockets keep up. | 
|  | video_codec.width = 176; | 
|  | video_codec.height = 144; | 
|  | video_codec.maxFramerate = 15; | 
|  | } | 
|  | EXPECT_EQ(0, codec->SetSendCodec(video_channel, video_codec)); | 
|  | ViETest::Log("\t %d. %s", i, video_codec.plName); | 
|  |  | 
|  | RenderFilter frame_counter; | 
|  | EXPECT_EQ(0, image_process->RegisterRenderEffectFilter(video_channel, | 
|  | frame_counter)); | 
|  | AutoTestSleep(kAutoTestSleepTimeMs); | 
|  |  | 
|  | // Verify we've received and decoded correct payload. | 
|  | EXPECT_EQ(video_codec.codecType, | 
|  | codec_observer.incoming_codec_.codecType); | 
|  |  | 
|  | // This requirement is quite relaxed, but it's hard to say what's an | 
|  | // acceptable number of received frames when we take into account the | 
|  | // wide variety of devices (and that we run under valgrind). | 
|  | EXPECT_GT(frame_counter.num_frames_, 0); | 
|  |  | 
|  | EXPECT_EQ(0, image_process->DeregisterRenderEffectFilter( | 
|  | video_channel)); | 
|  | } | 
|  | image_process->Release(); | 
|  | EXPECT_EQ(0, codec->DeregisterDecoderObserver(video_channel)); | 
|  | ViETest::Log("Done!"); | 
|  | } | 
|  |  | 
|  | // Test Callbacks | 
|  | TestCodecObserver codec_observer; | 
|  | EXPECT_EQ(0, codec->RegisterEncoderObserver(video_channel, codec_observer)); | 
|  | EXPECT_EQ(0, codec->RegisterDecoderObserver(video_channel, codec_observer)); | 
|  |  | 
|  | ViETest::Log("\nTesting codec callbacks..."); | 
|  |  | 
|  | for (int idx = 0; idx < codec->NumberOfCodecs(); idx++) { | 
|  | EXPECT_EQ(0, codec->GetCodec(idx, video_codec)); | 
|  | if (video_codec.codecType == webrtc::kVideoCodecVP8) { | 
|  | EXPECT_EQ(0, codec->SetSendCodec(video_channel, video_codec)); | 
|  | break; | 
|  | } | 
|  | } | 
|  | AutoTestSleep(kAutoTestSleepTimeMs); | 
|  |  | 
|  | // Verify the delay estimate is larger than 0. | 
|  | int delay_ms = 0; | 
|  | EXPECT_EQ(0, codec->GetReceiveSideDelay(video_channel, &delay_ms)); | 
|  | EXPECT_GT(delay_ms, 0); | 
|  |  | 
|  | EXPECT_EQ(0, base->StopSend(video_channel)); | 
|  | EXPECT_EQ(0, codec->DeregisterEncoderObserver(video_channel)); | 
|  | EXPECT_EQ(0, codec->DeregisterDecoderObserver(video_channel)); | 
|  |  | 
|  | EXPECT_GT(codec_observer.incoming_codec_called_, 0); | 
|  | EXPECT_GT(codec_observer.incoming_rate_called_, 0); | 
|  | EXPECT_GT(codec_observer.decoder_timing_called_, 0); | 
|  | EXPECT_GT(codec_observer.outgoing_rate_called_, 0); | 
|  |  | 
|  | EXPECT_EQ(0, base->StopReceive(video_channel)); | 
|  | EXPECT_EQ(0, render->StopRender(video_channel)); | 
|  | EXPECT_EQ(0, render->RemoveRenderer(capture_id)); | 
|  | EXPECT_EQ(0, render->RemoveRenderer(video_channel)); | 
|  | EXPECT_EQ(0, capture->DisconnectCaptureDevice(video_channel)); | 
|  | EXPECT_EQ(0, base->DeleteChannel(video_channel)); | 
|  | } | 
|  |  | 
|  | void ViEAutoTest::ViECodecExtendedTest() { | 
|  | { | 
|  | ViETest::Log(" "); | 
|  | ViETest::Log("========================================"); | 
|  | ViETest::Log(" ViECodec Extended Test\n"); | 
|  |  | 
|  | ViECodecExternalCodecTest(); | 
|  |  | 
|  | TbInterfaces interfaces("ViECodecExtendedTest"); | 
|  | webrtc::ViEBase* base = interfaces.base; | 
|  | webrtc::ViECapture* capture = interfaces.capture; | 
|  | webrtc::ViERender* render = interfaces.render; | 
|  | webrtc::ViECodec* codec = interfaces.codec; | 
|  | webrtc::ViERTP_RTCP* rtp_rtcp = interfaces.rtp_rtcp; | 
|  | webrtc::ViENetwork* network = interfaces.network; | 
|  |  | 
|  | TbCaptureDevice capture_device = TbCaptureDevice(interfaces); | 
|  | int capture_id = capture_device.captureId; | 
|  |  | 
|  | int video_channel = -1; | 
|  | EXPECT_EQ(0, base->CreateChannel(video_channel)); | 
|  | EXPECT_EQ(0, capture->ConnectCaptureDevice(capture_id, video_channel)); | 
|  | EXPECT_EQ(0, rtp_rtcp->SetRTCPStatus( | 
|  | video_channel, webrtc::kRtcpCompound_RFC4585)); | 
|  | EXPECT_EQ(0, rtp_rtcp->SetKeyFrameRequestMethod( | 
|  | video_channel, webrtc::kViEKeyFrameRequestPliRtcp)); | 
|  | EXPECT_EQ(0, rtp_rtcp->SetTMMBRStatus(video_channel, true)); | 
|  | EXPECT_EQ(0, render->AddRenderer(capture_id, _window1, 0, 0.0, 0.0, 1.0, | 
|  | 1.0)); | 
|  |  | 
|  | EXPECT_EQ(0, render->AddRenderer(video_channel, _window2, 1, 0.0, 0.0, 1.0, | 
|  | 1.0)); | 
|  | EXPECT_EQ(0, render->StartRender(capture_id)); | 
|  | EXPECT_EQ(0, render->StartRender(video_channel)); | 
|  |  | 
|  | webrtc::VideoCodec video_codec; | 
|  | memset(&video_codec, 0, sizeof(webrtc::VideoCodec)); | 
|  | for (int idx = 0; idx < codec->NumberOfCodecs(); idx++) { | 
|  | EXPECT_EQ(0, codec->GetCodec(idx, video_codec)); | 
|  | if (video_codec.codecType != webrtc::kVideoCodecI420) { | 
|  | video_codec.width = 640; | 
|  | video_codec.height = 480; | 
|  | } | 
|  | EXPECT_EQ(0, codec->SetReceiveCodec(video_channel, video_codec)); | 
|  | } | 
|  |  | 
|  | const char* ip_address = "127.0.0.1"; | 
|  | const uint16_t rtp_port = 6000; | 
|  |  | 
|  | webrtc::scoped_ptr<webrtc::test::VideoChannelTransport> | 
|  | video_channel_transport( | 
|  | new webrtc::test::VideoChannelTransport(network, video_channel)); | 
|  |  | 
|  | ASSERT_EQ(0, video_channel_transport->SetSendDestination(ip_address, | 
|  | rtp_port)); | 
|  | ASSERT_EQ(0, video_channel_transport->SetLocalReceiver(rtp_port)); | 
|  |  | 
|  | EXPECT_EQ(0, base->StartSend(video_channel)); | 
|  | EXPECT_EQ(0, base->StartReceive(video_channel)); | 
|  |  | 
|  | // Codec specific tests | 
|  | memset(&video_codec, 0, sizeof(webrtc::VideoCodec)); | 
|  | EXPECT_EQ(0, base->StopSend(video_channel)); | 
|  |  | 
|  | TestCodecObserver codec_observer; | 
|  | EXPECT_EQ(0, codec->RegisterEncoderObserver(video_channel, codec_observer)); | 
|  | EXPECT_EQ(0, codec->RegisterDecoderObserver(video_channel, codec_observer)); | 
|  | EXPECT_EQ(0, base->StopReceive(video_channel)); | 
|  |  | 
|  | EXPECT_EQ(0, render->StopRender(video_channel)); | 
|  | EXPECT_EQ(0, render->RemoveRenderer(capture_id)); | 
|  | EXPECT_EQ(0, render->RemoveRenderer(video_channel)); | 
|  | EXPECT_EQ(0, capture->DisconnectCaptureDevice(video_channel)); | 
|  | EXPECT_EQ(0, base->DeleteChannel(video_channel)); | 
|  | } | 
|  |  | 
|  | // Multiple send channels. | 
|  | { | 
|  | // Create two channels, where the second channel is created from the | 
|  | // first channel. Send different resolutions on the channels and verify | 
|  | // the received streams. | 
|  | TbInterfaces video_engine("ViECodecExtendedTest2"); | 
|  | TbCaptureDevice tb_capture(video_engine); | 
|  | webrtc::ViENetwork* network = video_engine.network; | 
|  |  | 
|  | // Create channel 1. | 
|  | int video_channel_1 = -1; | 
|  | EXPECT_EQ(0, video_engine.base->CreateChannel(video_channel_1)); | 
|  |  | 
|  | // Create channel 2 based on the first channel. | 
|  | int video_channel_2 = -1; | 
|  | EXPECT_EQ(0, video_engine.base->CreateChannel( | 
|  | video_channel_2, video_channel_1)); | 
|  | EXPECT_NE(video_channel_1, video_channel_2) | 
|  | << "Channel 2 should be unique."; | 
|  |  | 
|  | const char* ip_address = "127.0.0.1"; | 
|  | uint16_t rtp_port_1 = 12000; | 
|  | uint16_t rtp_port_2 = 13000; | 
|  |  | 
|  | webrtc::scoped_ptr<webrtc::test::VideoChannelTransport> | 
|  | video_channel_transport_1( | 
|  | new webrtc::test::VideoChannelTransport(network, video_channel_1)); | 
|  |  | 
|  | ASSERT_EQ(0, video_channel_transport_1->SetSendDestination(ip_address, | 
|  | rtp_port_1)); | 
|  | ASSERT_EQ(0, video_channel_transport_1->SetLocalReceiver(rtp_port_1)); | 
|  |  | 
|  | webrtc::scoped_ptr<webrtc::test::VideoChannelTransport> | 
|  | video_channel_transport_2( | 
|  | new webrtc::test::VideoChannelTransport(network, video_channel_2)); | 
|  |  | 
|  | ASSERT_EQ(0, video_channel_transport_2->SetSendDestination(ip_address, | 
|  | rtp_port_2)); | 
|  | ASSERT_EQ(0, video_channel_transport_2->SetLocalReceiver(rtp_port_2)); | 
|  |  | 
|  | EXPECT_EQ(0, video_engine.rtp_rtcp->SetLocalSSRC(video_channel_1, 1)); | 
|  | EXPECT_EQ(0, video_engine.rtp_rtcp->SetLocalSSRC(video_channel_2, 2)); | 
|  | tb_capture.ConnectTo(video_channel_1); | 
|  | tb_capture.ConnectTo(video_channel_2); | 
|  | EXPECT_EQ(0, video_engine.rtp_rtcp->SetKeyFrameRequestMethod( | 
|  | video_channel_1, webrtc::kViEKeyFrameRequestPliRtcp)); | 
|  | EXPECT_EQ(0, video_engine.rtp_rtcp->SetKeyFrameRequestMethod( | 
|  | video_channel_2, webrtc::kViEKeyFrameRequestPliRtcp)); | 
|  | EXPECT_EQ(0, video_engine.render->AddRenderer(video_channel_1, _window1, 0, | 
|  | 0.0, 0.0, 1.0, 1.0)); | 
|  | EXPECT_EQ(0, video_engine.render->StartRender(video_channel_1)); | 
|  | EXPECT_EQ(0, video_engine.render->AddRenderer(video_channel_2, _window2, 0, | 
|  | 0.0, 0.0, 1.0, 1.0)); | 
|  | EXPECT_EQ(0, video_engine.render->StartRender(video_channel_2)); | 
|  |  | 
|  | // Set Send codec. | 
|  | uint16_t codec_width = 320; | 
|  | uint16_t codec_height = 240; | 
|  | bool codec_set = false; | 
|  | webrtc::VideoCodec video_codec; | 
|  | webrtc::VideoCodec send_codec1; | 
|  | webrtc::VideoCodec send_codec2; | 
|  | for (int idx = 0; idx < video_engine.codec->NumberOfCodecs(); idx++) { | 
|  | EXPECT_EQ(0, video_engine.codec->GetCodec(idx, video_codec)); | 
|  | EXPECT_EQ(0, video_engine.codec->SetReceiveCodec(video_channel_1, | 
|  | video_codec)); | 
|  | if (video_codec.codecType == webrtc::kVideoCodecVP8) { | 
|  | memcpy(&send_codec1, &video_codec, sizeof(video_codec)); | 
|  | send_codec1.width = codec_width; | 
|  | send_codec1.height = codec_height; | 
|  | EXPECT_EQ(0, video_engine.codec->SetSendCodec( | 
|  | video_channel_1, send_codec1)); | 
|  | memcpy(&send_codec2, &video_codec, sizeof(video_codec)); | 
|  | send_codec2.width = 2 * codec_width; | 
|  | send_codec2.height = 2 * codec_height; | 
|  | EXPECT_EQ(0, video_engine.codec->SetSendCodec( | 
|  | video_channel_2, send_codec2)); | 
|  | codec_set = true; | 
|  | break; | 
|  | } | 
|  | } | 
|  | EXPECT_TRUE(codec_set); | 
|  |  | 
|  | // 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, video_engine.image_process->RegisterRenderEffectFilter( | 
|  | video_channel_1, filter1)); | 
|  | EXPECT_EQ(0, video_engine.image_process->RegisterRenderEffectFilter( | 
|  | video_channel_2, filter2)); | 
|  |  | 
|  | EXPECT_EQ(0, video_engine.base->StartReceive(video_channel_1)); | 
|  | EXPECT_EQ(0, video_engine.base->StartSend(video_channel_1)); | 
|  | EXPECT_EQ(0, video_engine.base->StartReceive(video_channel_2)); | 
|  | EXPECT_EQ(0, video_engine.base->StartSend(video_channel_2)); | 
|  |  | 
|  | AutoTestSleep(kAutoTestSleepTimeMs); | 
|  |  | 
|  | EXPECT_EQ(0, video_engine.base->StopReceive(video_channel_1)); | 
|  | EXPECT_EQ(0, video_engine.base->StopSend(video_channel_1)); | 
|  | EXPECT_EQ(0, video_engine.base->StopReceive(video_channel_2)); | 
|  | EXPECT_EQ(0, video_engine.base->StopSend(video_channel_2)); | 
|  |  | 
|  | EXPECT_EQ(0, video_engine.image_process->DeregisterRenderEffectFilter( | 
|  | video_channel_1)); | 
|  | EXPECT_EQ(0, video_engine.image_process->DeregisterRenderEffectFilter( | 
|  | video_channel_2)); | 
|  | EXPECT_EQ(send_codec1.width, filter1.last_render_width_); | 
|  | EXPECT_EQ(send_codec1.height, filter1.last_render_height_); | 
|  | EXPECT_EQ(send_codec2.width, filter2.last_render_width_); | 
|  | EXPECT_EQ(send_codec2.height, filter2.last_render_height_); | 
|  |  | 
|  | EXPECT_EQ(0, video_engine.base->DeleteChannel(video_channel_1)); | 
|  | EXPECT_EQ(0, video_engine.base->DeleteChannel(video_channel_2)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void ViEAutoTest::ViECodecAPITest() { | 
|  | webrtc::VideoEngine* video_engine = NULL; | 
|  | video_engine = webrtc::VideoEngine::Create(); | 
|  | EXPECT_TRUE(video_engine != NULL); | 
|  |  | 
|  | webrtc::ViEBase* base = webrtc::ViEBase::GetInterface(video_engine); | 
|  | EXPECT_EQ(0, base->Init()); | 
|  |  | 
|  | int video_channel = -1; | 
|  | EXPECT_EQ(0, base->CreateChannel(video_channel)); | 
|  |  | 
|  | webrtc::ViECodec* codec = webrtc::ViECodec::GetInterface(video_engine); | 
|  | EXPECT_TRUE(codec != NULL); | 
|  |  | 
|  | webrtc::VideoCodec video_codec; | 
|  | memset(&video_codec, 0, sizeof(webrtc::VideoCodec)); | 
|  |  | 
|  | const int number_of_codecs = codec->NumberOfCodecs(); | 
|  |  | 
|  | for (int i = 0; i < number_of_codecs; i++) { | 
|  | EXPECT_EQ(0, codec->GetCodec(i, video_codec)); | 
|  | if (video_codec.codecType == webrtc::kVideoCodecVP8) { | 
|  | video_codec.codecSpecific.VP8.automaticResizeOn = true; | 
|  | video_codec.codecSpecific.VP8.frameDroppingOn = true; | 
|  | video_codec.codecSpecific.VP8.keyFrameInterval = 300; | 
|  | EXPECT_EQ(0, codec->SetSendCodec(video_channel, video_codec)); | 
|  | break; | 
|  | } | 
|  | } | 
|  | memset(&video_codec, 0, sizeof(video_codec)); | 
|  | EXPECT_EQ(0, codec->GetSendCodec(video_channel, video_codec)); | 
|  | EXPECT_EQ(webrtc::kVideoCodecVP8, video_codec.codecType); | 
|  | EXPECT_TRUE(video_codec.codecSpecific.VP8.automaticResizeOn); | 
|  | EXPECT_TRUE(video_codec.codecSpecific.VP8.frameDroppingOn); | 
|  | EXPECT_EQ(300, video_codec.codecSpecific.VP8.keyFrameInterval); | 
|  |  | 
|  | for (int i = 0; i < number_of_codecs; i++) { | 
|  | EXPECT_EQ(0, codec->GetCodec(i, video_codec)); | 
|  | if (video_codec.codecType == webrtc::kVideoCodecI420) { | 
|  | EXPECT_EQ(0, codec->SetSendCodec(video_channel, video_codec)); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | memset(&video_codec, 0, sizeof(video_codec)); | 
|  | EXPECT_EQ(0, codec->GetSendCodec(video_channel, video_codec)); | 
|  | EXPECT_EQ(webrtc::kVideoCodecI420, video_codec.codecType); | 
|  |  | 
|  | // Register a generic codec | 
|  | memset(&video_codec, 0, sizeof(video_codec)); | 
|  | video_codec.codecType = webrtc::kVideoCodecGeneric; | 
|  | strcpy(video_codec.plName, "generic-codec"); | 
|  | uint8_t payload_type = 127; | 
|  | video_codec.plType = payload_type; | 
|  | video_codec.minBitrate = 100; | 
|  | video_codec.startBitrate = 500; | 
|  | video_codec.maxBitrate = 10000; | 
|  | video_codec.width = 1920; | 
|  | video_codec.height = 1080; | 
|  | video_codec.maxFramerate = 30; | 
|  | video_codec.qpMax = 50; | 
|  |  | 
|  | webrtc::ViEExternalCodec* external_codec = | 
|  | webrtc::ViEExternalCodec::GetInterface(video_engine); | 
|  | EXPECT_TRUE(external_codec != NULL); | 
|  |  | 
|  | // Any encoder will do. | 
|  | webrtc::I420Encoder encoder; | 
|  | EXPECT_EQ(0, external_codec->RegisterExternalSendCodec(video_channel, | 
|  | payload_type, &encoder, | 
|  | false)); | 
|  | EXPECT_EQ(0, codec->SetSendCodec(video_channel, video_codec)); | 
|  |  | 
|  | memset(&video_codec, 0, sizeof(video_codec)); | 
|  | EXPECT_EQ(0, codec->GetSendCodec(video_channel, video_codec)); | 
|  | EXPECT_EQ(webrtc::kVideoCodecGeneric, video_codec.codecType); | 
|  |  | 
|  | EXPECT_EQ(0, base->DeleteChannel(video_channel)); | 
|  |  | 
|  | EXPECT_EQ(0, external_codec->Release()); | 
|  | EXPECT_EQ(0, codec->Release()); | 
|  | EXPECT_EQ(0, base->Release()); | 
|  | EXPECT_TRUE(webrtc::VideoEngine::Delete(video_engine)); | 
|  | } | 
|  |  | 
|  | void ViEAutoTest::ViECodecExternalCodecTest() { | 
|  | ViETest::Log(" "); | 
|  | ViETest::Log("========================================"); | 
|  | ViETest::Log(" ViEExternalCodec Test\n"); | 
|  |  | 
|  | /// ************************************************************** | 
|  | //  Begin create/initialize WebRTC Video Engine for testing | 
|  | /// ************************************************************** | 
|  |  | 
|  | /// ************************************************************** | 
|  | //  Engine ready. Begin testing class | 
|  | /// ************************************************************** | 
|  |  | 
|  | #ifdef WEBRTC_VIDEO_ENGINE_EXTERNAL_CODEC_API | 
|  | int number_of_errors = 0; | 
|  | { | 
|  | int error = 0; | 
|  | TbInterfaces ViE("ViEExternalCodec"); | 
|  | TbCaptureDevice capture_device(ViE); | 
|  | TbVideoChannel channel(ViE, webrtc::kVideoCodecI420, 352, 288, 30, | 
|  | (352 * 288 * 3 * 8 * 30) / (2 * 1000)); | 
|  | capture_device.ConnectTo(channel.videoChannel); | 
|  |  | 
|  | error = ViE.render->AddRenderer(channel.videoChannel, _window1, 0, 0.0, 0.0, | 
|  | 1.0, 1.0); | 
|  | number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | error = ViE.render->StartRender(channel.videoChannel); | 
|  | number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  |  | 
|  | channel.StartReceive(); | 
|  | channel.StartSend(); | 
|  |  | 
|  | ViETest::Log("Using internal I420 codec"); | 
|  | AutoTestSleep(kAutoTestSleepTimeMs / 2); | 
|  |  | 
|  | webrtc::ViEExternalCodec* vie_external_codec = | 
|  | webrtc::ViEExternalCodec::GetInterface(ViE.video_engine); | 
|  | number_of_errors += ViETest::TestError(vie_external_codec != NULL, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | webrtc::VideoCodec codec; | 
|  | error = ViE.codec->GetSendCodec(channel.videoChannel, codec); | 
|  | number_of_errors += ViETest::TestError(vie_external_codec != NULL, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  |  | 
|  | // Use external encoder instead. | 
|  | { | 
|  | TbI420Encoder ext_encoder; | 
|  |  | 
|  | // Test to register on wrong channel. | 
|  | error = vie_external_codec->RegisterExternalSendCodec( | 
|  | channel.videoChannel + 5, codec.plType, &ext_encoder, false); | 
|  | number_of_errors += ViETest::TestError(error == -1, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | number_of_errors += ViETest::TestError( | 
|  | ViE.LastError() == kViECodecInvalidArgument, | 
|  | "ERROR: %s at line %d", __FUNCTION__, __LINE__); | 
|  |  | 
|  | error = vie_external_codec->RegisterExternalSendCodec( | 
|  | channel.videoChannel, codec.plType, &ext_encoder, false); | 
|  | number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  |  | 
|  | // Use new external encoder | 
|  | error = ViE.codec->SetSendCodec(channel.videoChannel, codec); | 
|  | number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  |  | 
|  | TbI420Decoder ext_decoder; | 
|  | error = vie_external_codec->RegisterExternalReceiveCodec( | 
|  | channel.videoChannel, codec.plType, &ext_decoder); | 
|  | number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  |  | 
|  | error = ViE.codec->SetReceiveCodec(channel.videoChannel, codec); | 
|  | number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  |  | 
|  | ViETest::Log("Using external I420 codec"); | 
|  | AutoTestSleep(kAutoTestSleepTimeMs); | 
|  |  | 
|  | // Test to deregister on wrong channel | 
|  | error = vie_external_codec->DeRegisterExternalSendCodec( | 
|  | channel.videoChannel + 5, codec.plType); | 
|  | number_of_errors += ViETest::TestError(error == -1, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | number_of_errors += ViETest::TestError( | 
|  | ViE.LastError() == kViECodecInvalidArgument, "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  |  | 
|  | // Test to deregister wrong payload type. | 
|  | error = vie_external_codec->DeRegisterExternalSendCodec( | 
|  | channel.videoChannel, codec.plType - 1); | 
|  | number_of_errors += ViETest::TestError(error == -1, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  |  | 
|  | // Deregister external send codec | 
|  | error = vie_external_codec->DeRegisterExternalSendCodec( | 
|  | channel.videoChannel, codec.plType); | 
|  | number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  |  | 
|  | error = vie_external_codec->DeRegisterExternalReceiveCodec( | 
|  | channel.videoChannel, codec.plType); | 
|  | number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  |  | 
|  | // Verify that the encoder and decoder has been used | 
|  | TbI420Encoder::FunctionCalls encode_calls = | 
|  | ext_encoder.GetFunctionCalls(); | 
|  | number_of_errors += ViETest::TestError(encode_calls.InitEncode == 1, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | number_of_errors += ViETest::TestError(encode_calls.Release == 1, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | number_of_errors += ViETest::TestError(encode_calls.Encode > 30, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | number_of_errors += ViETest::TestError( | 
|  | encode_calls.RegisterEncodeCompleteCallback == 1, | 
|  | "ERROR: %s at line %d", __FUNCTION__, __LINE__); | 
|  | number_of_errors += ViETest::TestError( | 
|  | encode_calls.SetChannelParameters > 1, "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | number_of_errors += ViETest::TestError(encode_calls.SetRates > 1, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  |  | 
|  | TbI420Decoder::FunctionCalls decode_calls = | 
|  | ext_decoder.GetFunctionCalls(); | 
|  | number_of_errors += ViETest::TestError(decode_calls.InitDecode == 1, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | number_of_errors += ViETest::TestError(decode_calls.Release == 1, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | number_of_errors += ViETest::TestError(decode_calls.Decode > 30, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | number_of_errors += ViETest::TestError( | 
|  | decode_calls.RegisterDecodeCompleteCallback == 1, | 
|  | "ERROR: %s at line %d", __FUNCTION__, __LINE__); | 
|  |  | 
|  | ViETest::Log("Changing payload type Using external I420 codec"); | 
|  |  | 
|  | codec.plType = codec.plType - 1; | 
|  | error = vie_external_codec->RegisterExternalReceiveCodec( | 
|  | channel.videoChannel, codec.plType, &ext_decoder); | 
|  | number_of_errors += ViETest::TestError(error == 0, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  |  | 
|  | error = ViE.codec->SetReceiveCodec(channel.videoChannel, | 
|  | codec); | 
|  | number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  |  | 
|  | error = vie_external_codec->RegisterExternalSendCodec( | 
|  | channel.videoChannel, codec.plType, &ext_encoder, false); | 
|  | number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  |  | 
|  | // Use new external encoder | 
|  | error = ViE.codec->SetSendCodec(channel.videoChannel, | 
|  | codec); | 
|  | number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  |  | 
|  | AutoTestSleep(kAutoTestSleepTimeMs / 2); | 
|  |  | 
|  | /// ************************************************************** | 
|  | //  Testing finished. Tear down Video Engine | 
|  | /// ************************************************************** | 
|  |  | 
|  | error = vie_external_codec->DeRegisterExternalSendCodec( | 
|  | channel.videoChannel, codec.plType); | 
|  | number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | error = vie_external_codec->DeRegisterExternalReceiveCodec( | 
|  | channel.videoChannel, codec.plType); | 
|  | number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  |  | 
|  | // Verify that the encoder and decoder has been used | 
|  | encode_calls = ext_encoder.GetFunctionCalls(); | 
|  | number_of_errors += ViETest::TestError(encode_calls.InitEncode == 2, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | number_of_errors += ViETest::TestError(encode_calls.Release == 2, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | number_of_errors += ViETest::TestError(encode_calls.Encode > 30, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | number_of_errors += ViETest::TestError( | 
|  | encode_calls.RegisterEncodeCompleteCallback == 2, | 
|  | "ERROR: %s at line %d", __FUNCTION__, __LINE__); | 
|  | number_of_errors += ViETest::TestError( | 
|  | encode_calls.SetChannelParameters > 1, "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | number_of_errors += ViETest::TestError(encode_calls.SetRates > 1, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | decode_calls = ext_decoder.GetFunctionCalls(); | 
|  | number_of_errors += ViETest::TestError(decode_calls.InitDecode == 2, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | number_of_errors += ViETest::TestError(decode_calls.Release == 2, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | number_of_errors += ViETest::TestError(decode_calls.Decode > 30, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | number_of_errors += ViETest::TestError( | 
|  | decode_calls.RegisterDecodeCompleteCallback == 2, | 
|  | "ERROR: %s at line %d", __FUNCTION__, __LINE__); | 
|  |  | 
|  | int remaining_interfaces = vie_external_codec->Release(); | 
|  | number_of_errors += ViETest::TestError(remaining_interfaces == 0, | 
|  | "ERROR: %s at line %d", | 
|  | __FUNCTION__, __LINE__); | 
|  | }  // tbI420Encoder and ext_decoder goes out of scope. | 
|  |  | 
|  | ViETest::Log("Using internal I420 codec"); | 
|  | AutoTestSleep(kAutoTestSleepTimeMs / 2); | 
|  | } | 
|  | if (number_of_errors > 0) { | 
|  | // Test failed | 
|  | ViETest::Log(" "); | 
|  | ViETest::Log(" ERROR ViEExternalCodec Test FAILED!"); | 
|  | ViETest::Log(" Number of errors: %d", number_of_errors); | 
|  | ViETest::Log("========================================"); | 
|  | ViETest::Log(" "); | 
|  | return; | 
|  | } | 
|  |  | 
|  | ViETest::Log(" "); | 
|  | ViETest::Log(" ViEExternalCodec Test PASSED!"); | 
|  | ViETest::Log("========================================"); | 
|  | ViETest::Log(" "); | 
|  | return; | 
|  |  | 
|  | #else | 
|  | ViETest::Log(" ViEExternalCodec not enabled\n"); | 
|  | return; | 
|  | #endif | 
|  | } |