| /* |
| * 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 "common_types.h" // NOLINT |
| #include "engine_configurations.h" // NOLINT |
| #include "gflags/gflags.h" |
| #include "modules/video_capture/main/interface/video_capture_factory.h" |
| #include "system_wrappers/interface/tick_util.h" |
| #include "video_engine/include/vie_base.h" |
| #include "video_engine/include/vie_capture.h" |
| #include "video_engine/include/vie_codec.h" |
| #include "video_engine/include/vie_network.h" |
| #include "video_engine/include/vie_render.h" |
| #include "video_engine/include/vie_rtp_rtcp.h" |
| #include "video_engine/test/auto_test/interface/vie_autotest.h" |
| #include "video_engine/test/auto_test/interface/vie_autotest_defines.h" |
| #include "video_engine/test/libvietest/include/tb_interfaces.h" |
| #include "video_engine/test/libvietest/include/tb_video_channel.h" |
| #include "voice_engine/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), |
| frame_rate_(0) {} |
| |
| virtual void BrightnessAlarm(const int capture_id, |
| 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; |
| } |
| } |
| |
| virtual void CapturedFrameRate(const int capture_id, |
| const unsigned char frame_rate) { |
| ViETest::Log(" CapturedFrameRate %u", frame_rate); |
| frame_rate_ = frame_rate; |
| } |
| |
| virtual void NoPictureAlarm(const int capture_id, |
| 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 frame_rate_; |
| }; |
| |
| 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 video_engineEffectFilter. |
| virtual int Transform(int size, unsigned char* frame_buffer, |
| unsigned int time_stamp90KHz, unsigned int width, |
| unsigned int height) { |
| EXPECT_TRUE(frame_buffer != 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 video_engine("video_engineCaptureStandardTest"); |
| |
| webrtc::VideoCaptureModule::DeviceInfo* dev_info = |
| webrtc::VideoCaptureFactory::CreateDeviceInfo(0); |
| ASSERT_TRUE(dev_info != NULL); |
| |
| int number_of_capture_devices = dev_info->NumberOfDevices(); |
| ViETest::Log("Number of capture devices %d", |
| number_of_capture_devices); |
| ASSERT_GT(number_of_capture_devices, 0) |
| << "This test requires a capture device (i.e. a webcam)"; |
| |
| int capture_device_id[10]; |
| memset(capture_device_id, 0, sizeof(capture_device_id)); |
| webrtc::VideoCaptureModule* vcpms[10]; |
| memset(vcpms, 0, sizeof(vcpms)); |
| |
| // Check capabilities |
| for (int device_index = 0; device_index < number_of_capture_devices; |
| ++device_index) { |
| char device_name[128]; |
| char device_unique_name[512]; |
| |
| EXPECT_EQ(0, dev_info->GetDeviceName(device_index, |
| device_name, |
| sizeof(device_name), |
| device_unique_name, |
| sizeof(device_unique_name))); |
| ViETest::Log("Found capture device %s\nUnique name %s", |
| device_name, device_unique_name); |
| |
| #if !defined(WEBRTC_MAC) // these functions will return -1 |
| int number_of_capabilities = |
| dev_info->NumberOfCapabilities(device_unique_name); |
| EXPECT_GT(number_of_capabilities, 0); |
| |
| for (int cap_index = 0; cap_index < number_of_capabilities; ++cap_index) { |
| webrtc::VideoCaptureCapability capability; |
| EXPECT_EQ(0, dev_info->GetCapability(device_unique_name, cap_index, |
| capability)); |
| ViETest::Log("Capture capability %d (of %u)", cap_index + 1, |
| number_of_capabilities); |
| 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. |
| #if !defined(WEBRTC_MAC) |
| |
| // Check allocation. Try to allocate them all after each other. |
| for (int device_index = 0; device_index < number_of_capture_devices; |
| ++device_index) { |
| char device_name[128]; |
| char device_unique_name[512]; |
| EXPECT_EQ(0, dev_info->GetDeviceName(device_index, |
| device_name, |
| sizeof(device_name), |
| device_unique_name, |
| sizeof(device_unique_name))); |
| webrtc::VideoCaptureModule* vcpm = |
| webrtc::VideoCaptureFactory::Create(device_index, device_unique_name); |
| EXPECT_TRUE(vcpm != NULL); |
| vcpm->AddRef(); |
| vcpms[device_index] = vcpm; |
| |
| EXPECT_EQ(0, video_engine.capture->AllocateCaptureDevice( |
| *vcpm, capture_device_id[device_index])); |
| |
| webrtc::VideoCaptureCapability capability; |
| EXPECT_EQ(0, dev_info->GetCapability(device_unique_name, 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, video_engine.image_process->RegisterCaptureEffectFilter( |
| capture_device_id[device_index], filter)); |
| |
| ViETest::Log("Testing Device %s capability width %d height %d", |
| device_unique_name, 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 vie_capability; |
| vie_capability.width = capability.width; |
| vie_capability.height = capability.height; |
| vie_capability.codecType = capability.codecType; |
| vie_capability.maxFPS = capability.maxFPS; |
| vie_capability.rawType = capability.rawType; |
| |
| EXPECT_EQ(0, video_engine.capture->StartCapture( |
| capture_device_id[device_index], vie_capability)); |
| webrtc::TickTime start_time = webrtc::TickTime::Now(); |
| |
| while (filter.number_of_captured_frames_ < 10 && |
| (webrtc::TickTime::Now() - start_time).Milliseconds() < 10000) { |
| AutoTestSleep(100); |
| } |
| |
| EXPECT_GT(filter.number_of_captured_frames_, 9) |
| << "Should capture at least some frames"; |
| |
| EXPECT_EQ(0, video_engine.image_process->DeregisterCaptureEffectFilter( |
| capture_device_id[device_index])); |
| |
| #ifdef WEBRTC_ANDROID // Can only allocate one camera at the time on Android. |
| EXPECT_EQ(0, video_engine.capture->StopCapture( |
| capture_device_id[device_index])); |
| EXPECT_EQ(0, video_engine.capture->ReleaseCaptureDevice( |
| capture_device_id[device_index])); |
| #endif |
| } |
| |
| /// ************************************************************** |
| // Testing finished. Tear down Video Engine |
| /// ************************************************************** |
| delete dev_info; |
| |
| // Stop all started capture devices. |
| for (int device_index = 0; device_index < number_of_capture_devices; |
| ++device_index) { |
| #if !defined(WEBRTC_ANDROID) |
| // Don't stop on Android since we can only allocate one camera. |
| EXPECT_EQ(0, video_engine.capture->StopCapture( |
| capture_device_id[device_index])); |
| EXPECT_EQ(0, video_engine.capture->ReleaseCaptureDevice( |
| capture_device_id[device_index])); |
| #endif // !WEBRTC_ANDROID |
| vcpms[device_index]->Release(); |
| } |
| #endif // !WEBRTC_MAC |
| } |
| |
| void ViEAutoTest::ViECaptureExtendedTest() { |
| ViECaptureExternalCaptureTest(); |
| } |
| |
| void ViEAutoTest::ViECaptureAPITest() { |
| /// ************************************************************** |
| // Begin create/initialize WebRTC Video Engine for testing |
| /// ************************************************************** |
| |
| /// ************************************************************** |
| // Engine ready. Begin testing class |
| /// ************************************************************** |
| TbInterfaces video_engine("video_engineCaptureAPITest"); |
| |
| video_engine.capture->NumberOfCaptureDevices(); |
| |
| char device_name[128]; |
| char device_unique_name[512]; |
| int capture_id = 0; |
| |
| webrtc::VideoCaptureModule::DeviceInfo* dev_info = |
| webrtc::VideoCaptureFactory::CreateDeviceInfo(0); |
| ASSERT_TRUE(dev_info != NULL); |
| ASSERT_GT(dev_info->NumberOfDevices(), 0u) |
| << "This test requires a capture device (i.e. a webcam)"; |
| |
| // Get the first capture device |
| EXPECT_EQ(0, dev_info->GetDeviceName(0, device_name, |
| sizeof(device_name), |
| device_unique_name, |
| sizeof(device_unique_name))); |
| |
| webrtc::VideoCaptureModule* vcpm = |
| webrtc::VideoCaptureFactory::Create(0, device_unique_name); |
| vcpm->AddRef(); |
| EXPECT_TRUE(vcpm != NULL); |
| |
| // Allocate capture device. |
| EXPECT_EQ(0, video_engine.capture->AllocateCaptureDevice(*vcpm, capture_id)); |
| |
| // Start the capture device. |
| EXPECT_EQ(0, video_engine.capture->StartCapture(capture_id)); |
| |
| // Start again. Should fail. |
| EXPECT_NE(0, video_engine.capture->StartCapture(capture_id)); |
| EXPECT_EQ(kViECaptureDeviceAlreadyStarted, video_engine.LastError()); |
| |
| // Start invalid capture device. |
| EXPECT_NE(0, video_engine.capture->StartCapture(capture_id + 1)); |
| EXPECT_EQ(kViECaptureDeviceDoesNotExist, video_engine.LastError()); |
| |
| // Stop invalid capture device. |
| EXPECT_NE(0, video_engine.capture->StopCapture(capture_id + 1)); |
| EXPECT_EQ(kViECaptureDeviceDoesNotExist, video_engine.LastError()); |
| |
| // Stop the capture device. |
| EXPECT_EQ(0, video_engine.capture->StopCapture(capture_id)); |
| |
| // Stop the capture device again. |
| EXPECT_NE(0, video_engine.capture->StopCapture(capture_id)); |
| EXPECT_EQ(kViECaptureDeviceNotStarted, video_engine.LastError()); |
| |
| // Connect to invalid channel. |
| EXPECT_NE(0, video_engine.capture->ConnectCaptureDevice(capture_id, 0)); |
| EXPECT_EQ(kViECaptureDeviceInvalidChannelId, |
| video_engine.LastError()); |
| |
| TbVideoChannel channel(video_engine); |
| |
| // Connect invalid capture_id. |
| EXPECT_NE(0, video_engine.capture->ConnectCaptureDevice(capture_id + 1, |
| channel.videoChannel)); |
| EXPECT_EQ(kViECaptureDeviceDoesNotExist, video_engine.LastError()); |
| |
| // Connect the capture device to the channel. |
| EXPECT_EQ(0, video_engine.capture->ConnectCaptureDevice(capture_id, |
| channel.videoChannel)); |
| |
| // Connect the channel again. |
| EXPECT_NE(0, video_engine.capture->ConnectCaptureDevice(capture_id, |
| channel.videoChannel)); |
| EXPECT_EQ(kViECaptureDeviceAlreadyConnected, |
| video_engine.LastError()); |
| |
| // Start the capture device. |
| EXPECT_EQ(0, video_engine.capture->StartCapture(capture_id)); |
| |
| // Release invalid capture device. |
| EXPECT_NE(0, video_engine.capture->ReleaseCaptureDevice(capture_id + 1)); |
| EXPECT_EQ(kViECaptureDeviceDoesNotExist, video_engine.LastError()); |
| |
| // Release the capture device. |
| EXPECT_EQ(0, video_engine.capture->ReleaseCaptureDevice(capture_id)); |
| |
| // Release the capture device again. |
| EXPECT_NE(0, video_engine.capture->ReleaseCaptureDevice(capture_id)); |
| EXPECT_EQ(kViECaptureDeviceDoesNotExist, video_engine.LastError()); |
| |
| // Test GetOrientation. |
| webrtc::VideoCaptureRotation orientation; |
| char dummy_name[5]; |
| EXPECT_NE(0, dev_info->GetOrientation(dummy_name, orientation)); |
| |
| // Test SetRotation. |
| EXPECT_NE(0, video_engine.capture->SetRotateCapturedFrames( |
| capture_id, webrtc::RotateCapturedFrame_90)); |
| EXPECT_EQ(kViECaptureDeviceDoesNotExist, video_engine.LastError()); |
| |
| // Allocate capture device. |
| EXPECT_EQ(0, video_engine.capture->AllocateCaptureDevice(*vcpm, capture_id)); |
| |
| EXPECT_EQ(0, video_engine.capture->SetRotateCapturedFrames( |
| capture_id, webrtc::RotateCapturedFrame_0)); |
| EXPECT_EQ(0, video_engine.capture->SetRotateCapturedFrames( |
| capture_id, webrtc::RotateCapturedFrame_90)); |
| EXPECT_EQ(0, video_engine.capture->SetRotateCapturedFrames( |
| capture_id, webrtc::RotateCapturedFrame_180)); |
| EXPECT_EQ(0, video_engine.capture->SetRotateCapturedFrames( |
| capture_id, webrtc::RotateCapturedFrame_270)); |
| |
| // Release the capture device |
| EXPECT_EQ(0, video_engine.capture->ReleaseCaptureDevice(capture_id)); |
| |
| /// ************************************************************** |
| // Testing finished. Tear down Video Engine |
| /// ************************************************************** |
| delete dev_info; |
| vcpm->Release(); |
| } |
| |
| void ViEAutoTest::ViECaptureExternalCaptureTest() { |
| /// ************************************************************** |
| // Begin create/initialize WebRTC Video Engine for testing |
| /// ************************************************************** |
| |
| TbInterfaces video_engine("video_engineCaptureExternalCaptureTest"); |
| TbVideoChannel channel(video_engine); |
| channel.StartReceive(); |
| channel.StartSend(); |
| |
| webrtc::VideoCaptureExternal* external_capture = NULL; |
| int capture_id = 0; |
| |
| // Allocate the external capture device. |
| webrtc::VideoCaptureModule* vcpm = |
| webrtc::VideoCaptureFactory::Create(0, external_capture); |
| EXPECT_TRUE(vcpm != NULL); |
| EXPECT_TRUE(external_capture != NULL); |
| vcpm->AddRef(); |
| |
| EXPECT_EQ(0, video_engine.capture->AllocateCaptureDevice(*vcpm, capture_id)); |
| |
| // Connect the capture device to the channel. |
| EXPECT_EQ(0, video_engine.capture->ConnectCaptureDevice(capture_id, |
| channel.videoChannel)); |
| |
| // Render the local capture. |
| EXPECT_EQ(0, video_engine.render->AddRenderer(capture_id, _window1, 1, 0.0, |
| 0.0, 1.0, 1.0)); |
| |
| // Render the remote capture. |
| EXPECT_EQ(0, video_engine.render->AddRenderer(channel.videoChannel, _window2, |
| 1, 0.0, 0.0, 1.0, 1.0)); |
| EXPECT_EQ(0, video_engine.render->StartRender(capture_id)); |
| EXPECT_EQ(0, video_engine.render->StartRender(channel.videoChannel)); |
| |
| // Register observer. |
| CaptureObserver observer; |
| EXPECT_EQ(0, video_engine.capture->RegisterObserver(capture_id, observer)); |
| |
| // Enable brightness alarm. |
| EXPECT_EQ(0, video_engine.capture->EnableBrightnessAlarm(capture_id, true)); |
| |
| CaptureEffectFilter effect_filter(176, 144); |
| EXPECT_EQ(0, video_engine.image_process->RegisterCaptureEffectFilter( |
| capture_id, effect_filter)); |
| |
| // 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 video_frame_length = (176 * 144 * 3) / 2; |
| unsigned char* video_frame = new unsigned char[video_frame_length]; |
| memset(video_frame, 128, 176 * 144); |
| |
| int frame_count = 0; |
| webrtc::VideoCaptureCapability capability; |
| capability.width = 176; |
| capability.height = 144; |
| capability.rawType = webrtc::kVideoI420; |
| |
| ViETest::Log("Testing external capturing and frame rate callbacks."); |
| // TODO(mflodman) Change when using a real file! |
| // while (fread(video_frame, video_frame_length, 1, foreman) == 1) |
| while (frame_count < 120) { |
| external_capture->IncomingFrame( |
| video_frame, video_frame_length, capability, |
| webrtc::TickTime::Now().MillisecondTimestamp()); |
| AutoTestSleep(33); |
| |
| if (effect_filter.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."; |
| } |
| frame_count++; |
| } |
| |
| // Test brightness alarm. |
| // Test bright image. |
| for (int i = 0; i < 176 * 144; ++i) { |
| if (video_frame[i] <= 155) |
| video_frame[i] = video_frame[i] + 100; |
| else |
| video_frame[i] = 255; |
| } |
| ViETest::Log("Testing Brighness alarm"); |
| for (int frame = 0; frame < 30; ++frame) { |
| external_capture->IncomingFrame( |
| video_frame, video_frame_length, 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) { |
| video_frame[i] = video_frame[i] > 200 ? video_frame[i] - 200 : 0; |
| } |
| for (int frame = 0; frame < 30; ++frame) { |
| external_capture->IncomingFrame( |
| video_frame, video_frame_length, 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(effect_filter.number_of_captured_frames_, 150) << |
| "Frames should have been played."; |
| |
| EXPECT_GE(observer.frame_rate_, 29) << |
| "Frame rate callback should be approximately correct."; |
| EXPECT_LE(observer.frame_rate_, 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) { |
| external_capture->IncomingFrame( |
| video_frame, video_frame_length, capability, |
| webrtc::TickTime::Now().MillisecondTimestamp()); |
| AutoTestSleep(33); |
| } |
| EXPECT_EQ(webrtc::AlarmCleared, observer.alarm_) << |
| "Alarm should be cleared since ge just got some data."; |
| |
| delete video_frame; |
| |
| // Release the capture device |
| EXPECT_EQ(0, video_engine.capture->ReleaseCaptureDevice(capture_id)); |
| |
| // Release the capture device again |
| EXPECT_NE(0, video_engine.capture->ReleaseCaptureDevice(capture_id)); |
| EXPECT_EQ(kViECaptureDeviceDoesNotExist, video_engine.LastError()); |
| vcpm->Release(); |
| |
| /// ************************************************************** |
| // Testing finished. Tear down Video Engine |
| /// ************************************************************** |
| } |