| /* |
| * Copyright (c) 2011 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 "vie_autotest.h" |
| |
| #include "common_types.h" |
| #include "engine_configurations.h" |
| #include "gflags/gflags.h" |
| #include "tb_interfaces.h" |
| #include "tb_video_channel.h" |
| #include "tick_util.h" |
| #include "vie_autotest_defines.h" |
| #include "video_capture_factory.h" |
| #include "vie_base.h" |
| #include "vie_capture.h" |
| #include "vie_codec.h" |
| #include "vie_network.h" |
| #include "vie_render.h" |
| #include "vie_rtp_rtcp.h" |
| #include "voe_base.h" |
| |
| DEFINE_bool(capture_test_ensure_resolution_alignment_in_capture_device, true, |
| "If true, we will give resolutions slightly below a reasonable " |
| "value to test the camera's ability to choose a good resolution. " |
| "If false, we will provide reasonable resolutions instead."); |
| |
| class CaptureObserver: public webrtc::ViECaptureObserver |
| { |
| public: |
| CaptureObserver() : |
| _brightness(webrtc::Normal), |
| _alarm(webrtc::AlarmCleared), |
| _frameRate(0) {} |
| |
| virtual void BrightnessAlarm(const int captureId, |
| const webrtc::Brightness brightness) |
| { |
| _brightness = brightness; |
| switch (brightness) |
| { |
| case webrtc::Normal: |
| ViETest::Log(" BrightnessAlarm Normal"); |
| break; |
| case webrtc::Bright: |
| ViETest::Log(" BrightnessAlarm Bright"); |
| break; |
| case webrtc::Dark: |
| ViETest::Log(" BrightnessAlarm Dark"); |
| break; |
| default: |
| assert(!"Unknown brightness alarm"); |
| } |
| } |
| |
| virtual void CapturedFrameRate(const int captureId, |
| const unsigned char frameRate) |
| { |
| ViETest::Log(" CapturedFrameRate %u", frameRate); |
| _frameRate = frameRate; |
| } |
| |
| virtual void NoPictureAlarm(const int captureId, |
| const webrtc::CaptureAlarm alarm) |
| { |
| _alarm = alarm; |
| if (alarm == webrtc::AlarmRaised) |
| { |
| ViETest::Log("NoPictureAlarm CARaised."); |
| } |
| else |
| { |
| ViETest::Log("NoPictureAlarm CACleared."); |
| } |
| } |
| |
| webrtc::Brightness _brightness; |
| webrtc::CaptureAlarm _alarm; |
| unsigned char _frameRate; |
| }; |
| |
| class CaptureEffectFilter: public webrtc::ViEEffectFilter { |
| public: |
| CaptureEffectFilter(unsigned int expected_width, unsigned int expected_height) |
| : number_of_captured_frames_(0), |
| expected_width_(expected_width), |
| expected_height_(expected_height) { |
| } |
| |
| // Implements ViEEffectFilter |
| virtual int Transform(int size, unsigned char* frameBuffer, |
| unsigned int timeStamp90KHz, unsigned int width, |
| unsigned int height) { |
| EXPECT_TRUE(frameBuffer != NULL); |
| EXPECT_EQ(expected_width_, width); |
| EXPECT_EQ(expected_height_, height); |
| ++number_of_captured_frames_; |
| return 0; |
| } |
| |
| int number_of_captured_frames_; |
| |
| protected: |
| unsigned int expected_width_; |
| unsigned int expected_height_; |
| }; |
| |
| void ViEAutoTest::ViECaptureStandardTest() |
| { |
| //*************************************************************** |
| // Begin create/initialize WebRTC Video Engine for testing |
| //*************************************************************** |
| |
| //*************************************************************** |
| // Engine ready. Begin testing class |
| //*************************************************************** |
| |
| TbInterfaces ViE("ViECaptureStandardTest"); |
| |
| webrtc::VideoCaptureModule::DeviceInfo* devInfo = |
| webrtc::VideoCaptureFactory::CreateDeviceInfo(0); |
| |
| int numberOfCaptureDevices = devInfo->NumberOfDevices(); |
| ViETest::Log("Number of capture devices %d", numberOfCaptureDevices); |
| EXPECT_GT(numberOfCaptureDevices, 0); |
| |
| int captureDeviceId[10]; |
| memset(captureDeviceId, 0, sizeof(captureDeviceId)); |
| webrtc::VideoCaptureModule* vcpms[10]; |
| memset(vcpms, 0, sizeof(vcpms)); |
| |
| // Check capabilities |
| for (int deviceIndex = 0; |
| deviceIndex < numberOfCaptureDevices; |
| ++deviceIndex) |
| { |
| WebRtc_UWord8 deviceName[128]; |
| WebRtc_UWord8 deviceUniqueName[512]; |
| |
| EXPECT_EQ(0, devInfo->GetDeviceName(deviceIndex, |
| deviceName, |
| sizeof(deviceName), |
| deviceUniqueName, |
| sizeof(deviceUniqueName))); |
| ViETest::Log("Found capture device %s\nUnique name %s", deviceName, |
| deviceUniqueName); |
| |
| #if !defined(WEBRTC_MAC_INTEL) // these functions will return -1 |
| int numberOfCapabilities = |
| devInfo->NumberOfCapabilities(deviceUniqueName); |
| EXPECT_GT(numberOfCapabilities, 0); |
| |
| for (int capIndex = 0; capIndex < numberOfCapabilities; ++capIndex) |
| { |
| webrtc::VideoCaptureCapability capability; |
| EXPECT_EQ(0, devInfo->GetCapability(deviceUniqueName, capIndex, |
| capability)); |
| ViETest::Log("Capture capability %d (of %u)", capIndex + 1, |
| numberOfCapabilities); |
| ViETest::Log("witdh %d, height %d, frame rate %d", |
| capability.width, capability.height, capability.maxFPS); |
| ViETest::Log("expected delay %d, color type %d, encoding %d", |
| capability.expectedCaptureDelay, capability.rawType, |
| capability.codecType); |
| |
| EXPECT_GT(capability.width, 0); |
| EXPECT_GT(capability.height, 0); |
| EXPECT_GT(capability.maxFPS, -1); // >= 0 |
| EXPECT_GT(capability.expectedCaptureDelay, 0); |
| } |
| #endif |
| } |
| // Capture Capability Functions are not supported on WEBRTC_MAC_INTEL. |
| #if !defined(WEBRTC_MAC_INTEL) |
| |
| // Check allocation. Try to allocate them all after each other. |
| for (int deviceIndex = 0; |
| deviceIndex < numberOfCaptureDevices; |
| ++deviceIndex) |
| { |
| WebRtc_UWord8 deviceName[128]; |
| WebRtc_UWord8 deviceUniqueName[512]; |
| |
| EXPECT_EQ(0, devInfo->GetDeviceName(deviceIndex, |
| deviceName, |
| sizeof(deviceName), |
| deviceUniqueName, |
| sizeof(deviceUniqueName))); |
| |
| webrtc::VideoCaptureModule* vcpm = |
| webrtc::VideoCaptureFactory::Create( |
| deviceIndex, deviceUniqueName); |
| EXPECT_TRUE(vcpm != NULL); |
| vcpm->AddRef(); |
| vcpms[deviceIndex] = vcpm; |
| |
| EXPECT_EQ(0, ViE.capture->AllocateCaptureDevice( |
| *vcpm, captureDeviceId[deviceIndex])); |
| |
| webrtc::VideoCaptureCapability capability; |
| EXPECT_EQ(0, devInfo->GetCapability(deviceUniqueName, 0, capability)); |
| |
| // Test that the camera select the closest capability to the selected |
| // width and height. |
| CaptureEffectFilter filter(capability.width, capability.height); |
| EXPECT_EQ(0, ViE.image_process->RegisterCaptureEffectFilter( |
| captureDeviceId[deviceIndex], filter)); |
| |
| ViETest::Log("Testing Device %s capability width %d height %d", |
| deviceUniqueName, capability.width, capability.height); |
| |
| if (FLAGS_capture_test_ensure_resolution_alignment_in_capture_device) { |
| // This tests that the capture device properly aligns to a |
| // multiple of 16 (or at least 8). |
| capability.height = capability.height - 2; |
| capability.width = capability.width - 2; |
| } |
| |
| webrtc::CaptureCapability vieCapability; |
| vieCapability.width = capability.width; |
| vieCapability.height = capability.height; |
| vieCapability.codecType = capability.codecType; |
| vieCapability.maxFPS = capability.maxFPS; |
| vieCapability.rawType = capability.rawType; |
| |
| EXPECT_EQ(0, ViE.capture->StartCapture(captureDeviceId[deviceIndex], |
| vieCapability)); |
| webrtc::TickTime startTime = webrtc::TickTime::Now(); |
| |
| while (filter.number_of_captured_frames_ < 10 |
| && (webrtc::TickTime::Now() - startTime).Milliseconds() < 10000) |
| { |
| AutoTestSleep(100); |
| } |
| |
| EXPECT_GT(filter.number_of_captured_frames_, 9) << |
| "Should capture at least some frames"; |
| |
| EXPECT_EQ(0, ViE.image_process->DeregisterCaptureEffectFilter( |
| captureDeviceId[deviceIndex])); |
| |
| #ifdef WEBRTC_ANDROID // Can only allocate one camera at the time on Android. |
| EXPECT_EQ(0, ViE.capture->StopCapture(captureDeviceId[deviceIndex])); |
| EXPECT_EQ(0, ViE.capture->ReleaseCaptureDevice( |
| captureDeviceId[deviceIndex])); |
| #endif |
| } |
| |
| //*************************************************************** |
| // Testing finished. Tear down Video Engine |
| //*************************************************************** |
| |
| |
| // Stop all started capture devices. |
| for (int deviceIndex = 0; |
| deviceIndex < numberOfCaptureDevices; |
| ++deviceIndex) { |
| #if !defined(WEBRTC_ANDROID) |
| // Don't stop on Android since we can only allocate one camera. |
| EXPECT_EQ(0, ViE.capture->StopCapture( |
| captureDeviceId[deviceIndex])); |
| EXPECT_EQ(0, ViE.capture->ReleaseCaptureDevice( |
| captureDeviceId[deviceIndex])); |
| #endif // !WEBRTC_ANDROID |
| vcpms[deviceIndex]->Release(); |
| } |
| #endif // !WEBRTC_MAC_INTEL |
| } |
| |
| void ViEAutoTest::ViECaptureExtendedTest() { |
| ViECaptureStandardTest(); |
| ViECaptureAPITest(); |
| ViECaptureExternalCaptureTest(); |
| } |
| |
| void ViEAutoTest::ViECaptureAPITest() |
| { |
| //*************************************************************** |
| // Begin create/initialize WebRTC Video Engine for testing |
| //*************************************************************** |
| |
| //*************************************************************** |
| // Engine ready. Begin testing class |
| //*************************************************************** |
| TbInterfaces ViE("ViECaptureAPITest"); |
| |
| ViE.capture->NumberOfCaptureDevices(); |
| |
| WebRtc_UWord8 deviceName[128]; |
| WebRtc_UWord8 deviceUniqueName[512]; |
| int captureId = 0; |
| |
| webrtc::VideoCaptureModule::DeviceInfo* devInfo = |
| webrtc::VideoCaptureFactory::CreateDeviceInfo(0); |
| EXPECT_TRUE(devInfo != NULL); |
| |
| // Get the first capture device |
| EXPECT_EQ(0, devInfo->GetDeviceName(0, deviceName, |
| sizeof(deviceName), |
| deviceUniqueName, |
| sizeof(deviceUniqueName))); |
| |
| webrtc::VideoCaptureModule* vcpm = |
| webrtc::VideoCaptureFactory::Create(0, deviceUniqueName); |
| vcpm->AddRef(); |
| EXPECT_TRUE(vcpm != NULL); |
| |
| // Allocate capture device. |
| EXPECT_EQ(0, ViE.capture->AllocateCaptureDevice(*vcpm, captureId)); |
| |
| // Start the capture device. |
| EXPECT_EQ(0, ViE.capture->StartCapture(captureId)); |
| |
| // Start again. Should fail. |
| EXPECT_NE(0, ViE.capture->StartCapture(captureId)); |
| EXPECT_EQ(kViECaptureDeviceAlreadyStarted, ViE.LastError()); |
| |
| // Start invalid capture device. |
| EXPECT_NE(0, ViE.capture->StartCapture(captureId + 1)); |
| EXPECT_EQ(kViECaptureDeviceDoesNotExist, ViE.LastError()); |
| |
| // Stop invalid capture device. |
| EXPECT_NE(0, ViE.capture->StopCapture(captureId + 1)); |
| EXPECT_EQ(kViECaptureDeviceDoesNotExist, ViE.LastError()); |
| |
| // Stop the capture device. |
| EXPECT_EQ(0, ViE.capture->StopCapture(captureId)); |
| |
| // Stop the capture device again. |
| EXPECT_NE(0, ViE.capture->StopCapture(captureId)); |
| EXPECT_EQ(kViECaptureDeviceNotStarted, ViE.LastError()); |
| |
| // Connect to invalid channel. |
| EXPECT_NE(0, ViE.capture->ConnectCaptureDevice(captureId, 0)); |
| EXPECT_EQ(kViECaptureDeviceInvalidChannelId, ViE.LastError()); |
| |
| TbVideoChannel channel(ViE); |
| |
| // Connect invalid captureId. |
| EXPECT_NE(0, ViE.capture->ConnectCaptureDevice(captureId + 1, |
| channel.videoChannel)); |
| EXPECT_EQ(kViECaptureDeviceDoesNotExist, ViE.LastError()); |
| |
| // Connect the capture device to the channel. |
| EXPECT_EQ(0, ViE.capture->ConnectCaptureDevice(captureId, |
| channel.videoChannel)); |
| |
| // Connect the channel again. |
| EXPECT_NE(0, ViE.capture->ConnectCaptureDevice(captureId, |
| channel.videoChannel)); |
| EXPECT_EQ(kViECaptureDeviceAlreadyConnected, ViE.LastError()); |
| |
| // Start the capture device. |
| EXPECT_EQ(0, ViE.capture->StartCapture(captureId)); |
| |
| // Release invalid capture device. |
| EXPECT_NE(0, ViE.capture->ReleaseCaptureDevice(captureId + 1)); |
| EXPECT_EQ(kViECaptureDeviceDoesNotExist, ViE.LastError()); |
| |
| // Release the capture device. |
| EXPECT_EQ(0, ViE.capture->ReleaseCaptureDevice(captureId)); |
| |
| // Release the capture device again. |
| EXPECT_NE(0, ViE.capture->ReleaseCaptureDevice(captureId)); |
| EXPECT_EQ(kViECaptureDeviceDoesNotExist, ViE.LastError()); |
| |
| // Test GetOrientation. |
| webrtc::VideoCaptureRotation orientation; |
| WebRtc_UWord8 dummy_name[5]; |
| EXPECT_NE(0, devInfo->GetOrientation(dummy_name, orientation)); |
| |
| // Test SetRotation. |
| EXPECT_NE(0, ViE.capture->SetRotateCapturedFrames( |
| captureId, webrtc::RotateCapturedFrame_90)); |
| EXPECT_EQ(kViECaptureDeviceDoesNotExist, ViE.LastError()); |
| |
| // Allocate capture device. |
| EXPECT_EQ(0, ViE.capture->AllocateCaptureDevice(*vcpm, captureId)); |
| |
| EXPECT_EQ(0, ViE.capture->SetRotateCapturedFrames( |
| captureId, webrtc::RotateCapturedFrame_0)); |
| EXPECT_EQ(0, ViE.capture->SetRotateCapturedFrames( |
| captureId, webrtc::RotateCapturedFrame_90)); |
| EXPECT_EQ(0, ViE.capture->SetRotateCapturedFrames( |
| captureId, webrtc::RotateCapturedFrame_180)); |
| EXPECT_EQ(0, ViE.capture->SetRotateCapturedFrames( |
| captureId, webrtc::RotateCapturedFrame_270)); |
| |
| // Release the capture device |
| EXPECT_EQ(0, ViE.capture->ReleaseCaptureDevice(captureId)); |
| |
| //*************************************************************** |
| // Testing finished. Tear down Video Engine |
| //*************************************************************** |
| delete devInfo; |
| vcpm->Release(); |
| } |
| |
| void ViEAutoTest::ViECaptureExternalCaptureTest() |
| { |
| //*************************************************************** |
| // Begin create/initialize WebRTC Video Engine for testing |
| //*************************************************************** |
| |
| TbInterfaces ViE("ViECaptureExternalCaptureTest"); |
| TbVideoChannel channel(ViE); |
| channel.StartReceive(); |
| channel.StartSend(); |
| |
| webrtc::VideoCaptureExternal* externalCapture; |
| int captureId = 0; |
| |
| // Allocate the external capture device. |
| webrtc::VideoCaptureModule* vcpm = webrtc::VideoCaptureFactory::Create( |
| 0, externalCapture); |
| EXPECT_TRUE(vcpm != NULL); |
| EXPECT_TRUE(externalCapture != NULL); |
| vcpm->AddRef(); |
| |
| EXPECT_EQ(0, ViE.capture->AllocateCaptureDevice(*vcpm, captureId)); |
| |
| // Connect the capture device to the channel. |
| EXPECT_EQ(0, ViE.capture->ConnectCaptureDevice(captureId, |
| channel.videoChannel)); |
| |
| // Render the local capture. |
| EXPECT_EQ(0, ViE.render->AddRenderer(captureId, _window1, 1, 0.0, 0.0, |
| 1.0, 1.0)); |
| |
| // Render the remote capture. |
| EXPECT_EQ(0, ViE.render->AddRenderer(channel.videoChannel, _window2, 1, |
| 0.0, 0.0, 1.0, 1.0)); |
| EXPECT_EQ(0, ViE.render->StartRender(captureId)); |
| EXPECT_EQ(0, ViE.render->StartRender(channel.videoChannel)); |
| |
| // Register observer. |
| CaptureObserver observer; |
| EXPECT_EQ(0, ViE.capture->RegisterObserver(captureId, observer)); |
| |
| // Enable brightness alarm. |
| EXPECT_EQ(0, ViE.capture->EnableBrightnessAlarm(captureId, true)); |
| |
| CaptureEffectFilter effectFilter(176, 144); |
| EXPECT_EQ(0, ViE.image_process->RegisterCaptureEffectFilter(captureId, |
| effectFilter)); |
| |
| // Call started. |
| ViETest::Log("You should see local preview from external capture\n" |
| "in window 1 and the remote video in window 2.\n"); |
| |
| //*************************************************************** |
| // Engine ready. Begin testing class |
| //*************************************************************** |
| const unsigned int videoFrameLength = (176 * 144 * 3) / 2; |
| unsigned char* videoFrame = new unsigned char[videoFrameLength]; |
| memset(videoFrame, 128, 176 * 144); |
| |
| // TODO: Find a file to use for testing. |
| // FILE* foreman = OpenTestFile("akiyo_qcif.yuv"); |
| // if (foreman == NULL) |
| // { |
| // ViETest::Log("Failed to open file akiyo_qcif.yuv"); |
| // } |
| |
| int frameCount = 0; |
| webrtc::VideoCaptureCapability capability; |
| capability.width = 176; |
| capability.height = 144; |
| capability.rawType = webrtc::kVideoI420; |
| |
| ViETest::Log("Testing external capturing and frame rate callbacks."); |
| // TODO: Change when using a real file! |
| // while (fread(videoFrame, videoFrameLength, 1, foreman) == 1) |
| while (frameCount < 120) |
| { |
| externalCapture->IncomingFrame( |
| videoFrame, videoFrameLength, capability, |
| webrtc::TickTime::Now().MillisecondTimestamp()); |
| AutoTestSleep(33); |
| |
| if (effectFilter.number_of_captured_frames_ > 2) |
| { |
| EXPECT_EQ(webrtc::Normal, observer._brightness) << |
| "Brightness or picture alarm should not have been called yet."; |
| EXPECT_EQ(webrtc::AlarmCleared, observer._alarm) << |
| "Brightness or picture alarm should not have been called yet."; |
| } |
| frameCount++; |
| } |
| |
| // Test brightness alarm |
| // Test bright image |
| for (int i = 0; i < 176 * 144; ++i) |
| { |
| if (videoFrame[i] <= 155) |
| videoFrame[i] = videoFrame[i] + 100; |
| else |
| videoFrame[i] = 255; |
| } |
| ViETest::Log("Testing Brighness alarm"); |
| for (int frame = 0; frame < 30; ++frame) |
| { |
| externalCapture->IncomingFrame( |
| videoFrame, videoFrameLength, capability, |
| webrtc::TickTime::Now().MillisecondTimestamp()); |
| AutoTestSleep(33); |
| } |
| EXPECT_EQ(webrtc::Bright, observer._brightness) << |
| "Should be bright at this point since we are using a bright image."; |
| |
| // Test Dark image |
| for (int i = 0; i < 176 * 144; ++i) |
| { |
| videoFrame[i] = videoFrame[i] > 200 ? videoFrame[i] - 200 : 0; |
| } |
| for (int frame = 0; frame < 30; ++frame) |
| { |
| externalCapture->IncomingFrame( |
| videoFrame, videoFrameLength, capability, |
| webrtc::TickTime::Now().MillisecondTimestamp()); |
| AutoTestSleep(33); |
| } |
| EXPECT_EQ(webrtc::Dark, observer._brightness) << |
| "Should be dark at this point since we are using a dark image."; |
| EXPECT_GT(effectFilter.number_of_captured_frames_, 150) << |
| "Frames should have been played."; |
| |
| EXPECT_GE(observer._frameRate, 29) << |
| "Frame rate callback should be approximately correct."; |
| EXPECT_LE(observer._frameRate, 30) << |
| "Frame rate callback should be approximately correct."; |
| |
| // Test no picture alarm |
| ViETest::Log("Testing NoPictureAlarm."); |
| AutoTestSleep(1050); |
| |
| EXPECT_EQ(webrtc::AlarmRaised, observer._alarm) << |
| "No picture alarm should be raised."; |
| for (int frame = 0; frame < 10; ++frame) |
| { |
| externalCapture->IncomingFrame( |
| videoFrame, videoFrameLength, capability, |
| webrtc::TickTime::Now().MillisecondTimestamp()); |
| AutoTestSleep(33); |
| } |
| EXPECT_EQ(webrtc::AlarmCleared, observer._alarm) << |
| "Alarm should be cleared since ge just got some data."; |
| |
| delete videoFrame; |
| |
| // Release the capture device |
| EXPECT_EQ(0, ViE.capture->ReleaseCaptureDevice(captureId)); |
| |
| // Release the capture device again |
| EXPECT_NE(0, ViE.capture->ReleaseCaptureDevice(captureId)); |
| EXPECT_EQ(kViECaptureDeviceDoesNotExist, ViE.LastError()); |
| vcpm->Release(); |
| |
| //*************************************************************** |
| // Testing finished. Tear down Video Engine |
| //*************************************************************** |
| } |