diff --git a/webrtc/video_engine/include/vie_codec.h b/webrtc/video_engine/include/vie_codec.h index 47bc6861c..d9e09c9a2 100644 --- a/webrtc/video_engine/include/vie_codec.h +++ b/webrtc/video_engine/include/vie_codec.h @@ -66,6 +66,18 @@ class WEBRTC_DLLEXPORT ViEDecoderObserver { class WEBRTC_DLLEXPORT ViECodec { public: + enum ViEDecodeErrorMode { + kNoErrors, // Never decode with errors. Video will freeze + // if nack is disabled. + kSelectiveErrors, // Frames that are determined decodable in + // VCMSessionInfo may be decoded with missing + // packets. As not all incomplete frames will be + // decodable, video will freeze if nack is disabled. + kWithErrors // Release frames as needed. Errors may be + // introduced as some encoded frames may not be + // complete. + }; + // Factory for the ViECodec subā€API and increases an internal reference // counter if successful. Returns NULL if the API is not supported or if // construction fails. @@ -171,6 +183,10 @@ class WEBRTC_DLLEXPORT ViECodec { virtual int WaitForFirstKeyFrame(const int video_channel, const bool wait) = 0; + // Set the decode error mode. + virtual int SetDecodeErrorMode(const int video_channel, + const ViEDecodeErrorMode error_mode) = 0; + // Enables recording of debugging information. virtual int StartDebugRecording(int video_channel, const char* file_name_utf8) = 0; diff --git a/webrtc/video_engine/test/auto_test/source/vie_autotest_loopback.cc b/webrtc/video_engine/test/auto_test/source/vie_autotest_loopback.cc index 00b50d1cb..a1349dca2 100644 --- a/webrtc/video_engine/test/auto_test/source/vie_autotest_loopback.cc +++ b/webrtc/video_engine/test/auto_test/source/vie_autotest_loopback.cc @@ -40,274 +40,276 @@ #define VCM_RED_PAYLOAD_TYPE 96 #define VCM_ULPFEC_PAYLOAD_TYPE 97 -int VideoEngineSampleCode(void* window1, void* window2) -{ - //******************************************************** - // Begin create/initialize Video Engine for testing - //******************************************************** +DEFINE_int32(capture_device, -1, "Capture device to use.\n" + "\t1. Default"); +DEFINE_int32(codec, -1, "Available codecs:\n" + "\t1. VP8\n" + "\t2. I420"); +DEFINE_int32(frame_size, -1, "Frame size:\n" + "\t1. QCIF (176x144)\n" + "\t2. CIF (352x288)\n" + "\t3. VGA (640x480)\n" + "\t4. 4CIF (704x576)\n" + "\t5. WHD (1280x720)\n" + "\t6. FHD (1920x1080)"); +DEFINE_int32(temporal_layers, -1, "Number of temporal layers (1 to 4)."); +DEFINE_int32(start_rate, -1, "Start rate (in kbps)."); +DEFINE_int32(protection_method, -1, "Protection method:\n" + "\t0. None\n" + "\t1. FEC\n" + "\t2. NACK\n" + "\t3. NACK+FEC"); +DEFINE_int32(decode_error_mode, -1, "Decode error mode:\n" + "\t0. No Errors\n" + "\t1. Selective Errors\n" + "\t2. With Errors"); +DEFINE_int32(buffering_delay, -1, "Set buffering delay (ms)"); +DEFINE_int32(percent_loss, -1, "Packet loss percentage."); +DEFINE_int32(network_delay, -1, "Network delay value (ms)"); - int error = 0; - // - // Create a VideoEngine instance - // - webrtc::VideoEngine* ptrViE = NULL; - ptrViE = webrtc::VideoEngine::Create(); - if (ptrViE == NULL) - { - printf("ERROR in VideoEngine::Create\n"); - return -1; - } +// TEST = trybots, vie_auto_test --automated +int VideoEngineSampleCode(void* window1, void* window2) { + //******************************************************** + // Begin create/initialize Video Engine for testing + //******************************************************** - error = ptrViE->SetTraceFilter(webrtc::kTraceAll); - if (error == -1) - { - printf("ERROR in VideoEngine::SetTraceFilter\n"); - return -1; - } + int error = 0; - std::string trace_file = - ViETest::GetResultOutputPath() + "ViELoopbackCall_trace.txt"; - error = ptrViE->SetTraceFile(trace_file.c_str()); - if (error == -1) - { - printf("ERROR in VideoEngine::SetTraceFile\n"); - return -1; - } + // + // Create a VideoEngine instance + // + webrtc::VideoEngine* ptrViE = NULL; + ptrViE = webrtc::VideoEngine::Create(); + if (ptrViE == NULL) { + printf("ERROR in VideoEngine::Create\n"); + return -1; + } - // - // Init VideoEngine and create a channel - // - webrtc::ViEBase* ptrViEBase = webrtc::ViEBase::GetInterface(ptrViE); - if (ptrViEBase == NULL) - { - printf("ERROR in ViEBase::GetInterface\n"); - return -1; - } + error = ptrViE->SetTraceFilter(webrtc::kTraceAll); + if (error == -1) { + printf("ERROR in VideoEngine::SetTraceFilter\n"); + return -1; + } - error = ptrViEBase->Init(); - if (error == -1) - { - printf("ERROR in ViEBase::Init\n"); - return -1; - } + std::string trace_file = + ViETest::GetResultOutputPath() + "ViELoopbackCall_trace.txt"; + error = ptrViE->SetTraceFile(trace_file.c_str()); + if (error == -1) { + printf("ERROR in VideoEngine::SetTraceFile\n"); + return -1; + } - webrtc::ViERTP_RTCP* ptrViERtpRtcp = - webrtc::ViERTP_RTCP::GetInterface(ptrViE); - if (ptrViERtpRtcp == NULL) - { - printf("ERROR in ViERTP_RTCP::GetInterface\n"); - return -1; - } + // + // Init VideoEngine and create a channel + // + webrtc::ViEBase* ptrViEBase = webrtc::ViEBase::GetInterface(ptrViE); + if (ptrViEBase == NULL) { + printf("ERROR in ViEBase::GetInterface\n"); + return -1; + } - int videoChannel = -1; - error = ptrViEBase->CreateChannel(videoChannel); - if (error == -1) - { - printf("ERROR in ViEBase::CreateChannel\n"); - return -1; - } + error = ptrViEBase->Init(); + if (error == -1) { + printf("ERROR in ViEBase::Init\n"); + return -1; + } - // - // List available capture devices, allocate and connect. - // - webrtc::ViECapture* ptrViECapture = - webrtc::ViECapture::GetInterface(ptrViE); - if (ptrViEBase == NULL) - { - printf("ERROR in ViECapture::GetInterface\n"); - return -1; - } + webrtc::ViERTP_RTCP* ptrViERtpRtcp = + webrtc::ViERTP_RTCP::GetInterface(ptrViE); + if (ptrViERtpRtcp == NULL) { + printf("ERROR in ViERTP_RTCP::GetInterface\n"); + return -1; + } - const unsigned int KMaxDeviceNameLength = 128; - const unsigned int KMaxUniqueIdLength = 256; - char deviceName[KMaxDeviceNameLength]; - memset(deviceName, 0, KMaxDeviceNameLength); - char uniqueId[KMaxUniqueIdLength]; - memset(uniqueId, 0, KMaxUniqueIdLength); + int videoChannel = -1; + error = ptrViEBase->CreateChannel(videoChannel); + if (error == -1) { + printf("ERROR in ViEBase::CreateChannel\n"); + return -1; + } + // + // List available capture devices, allocate and connect. + // + webrtc::ViECapture* ptrViECapture = webrtc::ViECapture::GetInterface(ptrViE); + if (ptrViEBase == NULL) { + printf("ERROR in ViECapture::GetInterface\n"); + return -1; + } + + const unsigned int KMaxDeviceNameLength = 128; + const unsigned int KMaxUniqueIdLength = 256; + char deviceName[KMaxDeviceNameLength]; + memset(deviceName, 0, KMaxDeviceNameLength); + char uniqueId[KMaxUniqueIdLength]; + memset(uniqueId, 0, KMaxUniqueIdLength); + + int captureIdx = 0; + if (FLAGS_capture_device > 0) { + captureIdx = FLAGS_capture_device; + } else { printf("Available capture devices:\n"); - int captureIdx = 0; for (captureIdx = 0; captureIdx < ptrViECapture->NumberOfCaptureDevices(); - captureIdx++) - { - memset(deviceName, 0, KMaxDeviceNameLength); - memset(uniqueId, 0, KMaxUniqueIdLength); + captureIdx++) { + memset(deviceName, 0, KMaxDeviceNameLength); + memset(uniqueId, 0, KMaxUniqueIdLength); - error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName, - KMaxDeviceNameLength, uniqueId, - KMaxUniqueIdLength); - if (error == -1) - { - printf("ERROR in ViECapture::GetCaptureDevice\n"); - return -1; - } - printf("\t %d. %s\n", captureIdx + 1, deviceName); + error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName, + KMaxDeviceNameLength, uniqueId, KMaxUniqueIdLength); + if (error == -1) { + printf("ERROR in ViECapture::GetCaptureDevice\n"); + return -1; + } + printf("\t %d. %s\n", captureIdx + 1, deviceName); } printf("\nChoose capture device: "); #ifdef WEBRTC_ANDROID captureIdx = 0; printf("0\n"); #else - if (scanf("%d", &captureIdx) != 1) - { - printf("Error in scanf()\n"); - return -1; + if (scanf("%d", &captureIdx) != 1) { + printf("Error in scanf()\n"); + return -1; } getchar(); - captureIdx = captureIdx - 1; // Compensate for idx start at 1. + captureIdx = captureIdx - 1; // Compensate for idx start at 1. #endif - error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName, - KMaxDeviceNameLength, uniqueId, - KMaxUniqueIdLength); - if (error == -1) - { - printf("ERROR in ViECapture::GetCaptureDevice\n"); - return -1; - } + } + error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName, + KMaxDeviceNameLength, uniqueId, + KMaxUniqueIdLength); + if (error == -1) { + printf("ERROR in ViECapture::GetCaptureDevice\n"); + return -1; + } - int captureId = 0; - error = ptrViECapture->AllocateCaptureDevice(uniqueId, KMaxUniqueIdLength, - captureId); - if (error == -1) - { - printf("ERROR in ViECapture::AllocateCaptureDevice\n"); - return -1; - } + int captureId = 0; + error = ptrViECapture->AllocateCaptureDevice(uniqueId, KMaxUniqueIdLength, + captureId); + if (error == -1) { + printf("ERROR in ViECapture::AllocateCaptureDevice\n"); + return -1; + } - error = ptrViECapture->ConnectCaptureDevice(captureId, videoChannel); - if (error == -1) - { - printf("ERROR in ViECapture::ConnectCaptureDevice\n"); - return -1; - } + error = ptrViECapture->ConnectCaptureDevice(captureId, videoChannel); + if (error == -1) { + printf("ERROR in ViECapture::ConnectCaptureDevice\n"); + return -1; + } - error = ptrViECapture->StartCapture(captureId); - if (error == -1) - { - printf("ERROR in ViECapture::StartCapture\n"); - return -1; - } + error = ptrViECapture->StartCapture(captureId); + if (error == -1) { + printf("ERROR in ViECapture::StartCapture\n"); + return -1; + } - // - // RTP/RTCP settings - // + // + // RTP/RTCP settings + // - error = ptrViERtpRtcp->SetRTCPStatus(videoChannel, - webrtc::kRtcpCompound_RFC4585); - if (error == -1) - { - printf("ERROR in ViERTP_RTCP::SetRTCPStatus\n"); - return -1; - } + error = ptrViERtpRtcp->SetRTCPStatus(videoChannel, + webrtc::kRtcpCompound_RFC4585); + if (error == -1) { + printf("ERROR in ViERTP_RTCP::SetRTCPStatus\n"); + return -1; + } - error = ptrViERtpRtcp->SetKeyFrameRequestMethod( - videoChannel, webrtc::kViEKeyFrameRequestPliRtcp); - if (error == -1) - { - printf("ERROR in ViERTP_RTCP::SetKeyFrameRequestMethod\n"); - return -1; - } + error = ptrViERtpRtcp->SetKeyFrameRequestMethod( + videoChannel, webrtc::kViEKeyFrameRequestPliRtcp); + if (error == -1) { + printf("ERROR in ViERTP_RTCP::SetKeyFrameRequestMethod\n"); + return -1; + } - error = ptrViERtpRtcp->SetRembStatus(videoChannel, true, true); - if (error == -1) - { - printf("ERROR in ViERTP_RTCP::SetTMMBRStatus\n"); - return -1; - } + error = ptrViERtpRtcp->SetRembStatus(videoChannel, true, true); + if (error == -1) { + printf("ERROR in ViERTP_RTCP::SetTMMBRStatus\n"); + return -1; + } - // Setting SSRC manually (arbitrary value), as otherwise we will get a clash - // (loopback), and a new SSRC will be set, which will reset the receiver. - error = ptrViERtpRtcp->SetLocalSSRC(videoChannel, 0x01234567); - if (error == -1) - { - printf("ERROR in ViERTP_RTCP::SetLocalSSRC\n"); - return -1; - } + // Setting SSRC manually (arbitrary value), as otherwise we will get a clash + // (loopback), and a new SSRC will be set, which will reset the receiver. + error = ptrViERtpRtcp->SetLocalSSRC(videoChannel, 0x01234567); + if (error == -1) { + printf("ERROR in ViERTP_RTCP::SetLocalSSRC\n"); + return -1; + } - // - // Set up rendering - // - webrtc::ViERender* ptrViERender = webrtc::ViERender::GetInterface(ptrViE); - if (ptrViERender == NULL) - { - printf("ERROR in ViERender::GetInterface\n"); - return -1; - } + // + // Set up rendering + // + webrtc::ViERender* ptrViERender = webrtc::ViERender::GetInterface(ptrViE); + if (ptrViERender == NULL) { + printf("ERROR in ViERender::GetInterface\n"); + return -1; + } - error - = ptrViERender->AddRenderer(captureId, window1, 0, 0.0, 0.0, 1.0, 1.0); - if (error == -1) - { - printf("ERROR in ViERender::AddRenderer\n"); - return -1; - } + error = ptrViERender->AddRenderer(captureId, window1, 0, 0.0, 0.0, 1.0, 1.0); + if (error == -1) { + printf("ERROR in ViERender::AddRenderer\n"); + return -1; + } - error = ptrViERender->StartRender(captureId); - if (error == -1) - { - printf("ERROR in ViERender::StartRender\n"); - return -1; - } + error = ptrViERender->StartRender(captureId); + if (error == -1) { + printf("ERROR in ViERender::StartRender\n"); + return -1; + } - error = ptrViERender->AddRenderer(videoChannel, window2, 1, 0.0, 0.0, 1.0, - 1.0); - if (error == -1) - { - printf("ERROR in ViERender::AddRenderer\n"); - return -1; - } + error = ptrViERender->AddRenderer(videoChannel, window2, 1, 0.0, 0.0, 1.0, + 1.0); + if (error == -1) { + printf("ERROR in ViERender::AddRenderer\n"); + return -1; + } - error = ptrViERender->StartRender(videoChannel); - if (error == -1) - { - printf("ERROR in ViERender::StartRender\n"); - return -1; - } + error = ptrViERender->StartRender(videoChannel); + if (error == -1) { + printf("ERROR in ViERender::StartRender\n"); + return -1; + } - // - // Setup codecs - // - webrtc::ViECodec* ptrViECodec = webrtc::ViECodec::GetInterface(ptrViE); - if (ptrViECodec == NULL) - { - printf("ERROR in ViECodec::GetInterface\n"); - return -1; - } + // + // Setup codecs + // + webrtc::ViECodec* ptrViECodec = webrtc::ViECodec::GetInterface(ptrViE); + if (ptrViECodec == NULL) { + printf("ERROR in ViECodec::GetInterface\n"); + return -1; + } + int codecIdx = 0; + webrtc::VideoCodec videoCodec; + memset(&videoCodec, 0, sizeof(webrtc::VideoCodec)); + if (FLAGS_codec > 0) { + codecIdx = FLAGS_codec; + } else { // Check available codecs and prepare receive codecs printf("\nAvailable codecs:\n"); - webrtc::VideoCodec videoCodec; - memset(&videoCodec, 0, sizeof(webrtc::VideoCodec)); - int codecIdx = 0; - for (codecIdx = 0; codecIdx < ptrViECodec->NumberOfCodecs(); codecIdx++) - { - error = ptrViECodec->GetCodec(codecIdx, videoCodec); - if (error == -1) - { - printf("ERROR in ViECodec::GetCodec\n"); - return -1; - } + for (codecIdx = 0; codecIdx < ptrViECodec->NumberOfCodecs(); codecIdx++) { + error = ptrViECodec->GetCodec(codecIdx, videoCodec); + if (error == -1) { + printf("ERROR in ViECodec::GetCodec\n"); + return -1; + } - // try to keep the test frame size small when I420 - if (videoCodec.codecType == webrtc::kVideoCodecI420) - { - videoCodec.width = 176; - videoCodec.height = 144; - } + // try to keep the test frame size small when I420 + if (videoCodec.codecType == webrtc::kVideoCodecI420) { + videoCodec.width = 176; + videoCodec.height = 144; + } - error = ptrViECodec->SetReceiveCodec(videoChannel, videoCodec); - if (error == -1) - { - printf("ERROR in ViECodec::SetReceiveCodec\n"); - return -1; - } - if (videoCodec.codecType != webrtc::kVideoCodecRED - && videoCodec.codecType != webrtc::kVideoCodecULPFEC) - { - printf("\t %d. %s\n", codecIdx + 1, videoCodec.plName); - } + error = ptrViECodec->SetReceiveCodec(videoChannel, videoCodec); + if (error == -1) { + printf("ERROR in ViECodec::SetReceiveCodec\n"); + return -1; + } + if (videoCodec.codecType != webrtc::kVideoCodecRED + && videoCodec.codecType != webrtc::kVideoCodecULPFEC) { + printf("\t %d. %s\n", codecIdx + 1, videoCodec.plName); + } } printf("%d. VP8 over Generic.\n", ptrViECodec->NumberOfCodecs() + 1); @@ -316,47 +318,51 @@ int VideoEngineSampleCode(void* window1, void* window2) codecIdx = 0; printf("0\n"); #else - if (scanf("%d", &codecIdx) != 1) - { - printf("Error in scanf()\n"); - return -1; + if (scanf("%d", &codecIdx) != 1) { + printf("Error in scanf()\n"); + return -1; } getchar(); - codecIdx = codecIdx - 1; // Compensate for idx start at 1. + codecIdx = codecIdx - 1; // Compensate for idx start at 1. #endif - // VP8 over generic transport gets this special one. - if (codecIdx == ptrViECodec->NumberOfCodecs()) { - for (codecIdx = 0; codecIdx < ptrViECodec->NumberOfCodecs(); ++codecIdx) { - error = ptrViECodec->GetCodec(codecIdx, videoCodec); - assert(error != -1); - if (videoCodec.codecType == webrtc::kVideoCodecVP8) - break; - } - assert(videoCodec.codecType == webrtc::kVideoCodecVP8); - videoCodec.codecType = webrtc::kVideoCodecGeneric; - - // Any plName should work with generic - strcpy(videoCodec.plName, "VP8-GENERIC"); - uint8_t pl_type = 127; - videoCodec.plType = pl_type; - webrtc::ViEExternalCodec* external_codec = webrtc::ViEExternalCodec - ::GetInterface(ptrViE); - assert(external_codec != NULL); - error = external_codec->RegisterExternalSendCodec(videoChannel, pl_type, - webrtc::VP8Encoder::Create(), false); - assert(error != -1); - error = external_codec->RegisterExternalReceiveCodec(videoChannel, - pl_type, webrtc::VP8Decoder::Create(), false); - assert(error != -1); - } else { + } + // VP8 over generic transport gets this special one. + if (codecIdx == ptrViECodec->NumberOfCodecs()) { + for (codecIdx = 0; codecIdx < ptrViECodec->NumberOfCodecs(); ++codecIdx) { error = ptrViECodec->GetCodec(codecIdx, videoCodec); - if (error == -1) { - printf("ERROR in ViECodec::GetCodec\n"); - return -1; - } + assert(error != -1); + if (videoCodec.codecType == webrtc::kVideoCodecVP8) + break; } + assert(videoCodec.codecType == webrtc::kVideoCodecVP8); + videoCodec.codecType = webrtc::kVideoCodecGeneric; - // Set spatial resolution option + // Any plName should work with generic + strcpy(videoCodec.plName, "VP8-GENERIC"); + uint8_t pl_type = 127; + videoCodec.plType = pl_type; + webrtc::ViEExternalCodec* external_codec = webrtc::ViEExternalCodec + ::GetInterface(ptrViE); + assert(external_codec != NULL); + error = external_codec->RegisterExternalSendCodec(videoChannel, pl_type, + webrtc::VP8Encoder::Create(), false); + assert(error != -1); + error = external_codec->RegisterExternalReceiveCodec(videoChannel, + pl_type, webrtc::VP8Decoder::Create(), false); + assert(error != -1); + } else { + error = ptrViECodec->GetCodec(codecIdx, videoCodec); + if (error == -1) { + printf("ERROR in ViECodec::GetCodec\n"); + return -1; + } + } + + // Set spatial resolution option + int resolnOption; + if (FLAGS_frame_size > 0 && FLAGS_frame_size < 7) { + resolnOption = FLAGS_frame_size; + } else { std::string str; std::cout << std::endl; std::cout << "Enter frame size option (default is CIF):" << std::endl; @@ -367,64 +373,78 @@ int VideoEngineSampleCode(void* window1, void* window2) std::cout << "5. WHD (1280X720) " << std::endl; std::cout << "6. FHD (1920X1080) " << std::endl; std::getline(std::cin, str); - int resolnOption = atoi(str.c_str()); - switch (resolnOption) - { - case 1: - videoCodec.width = 176; - videoCodec.height = 144; - break; - case 2: - videoCodec.width = 352; - videoCodec.height = 288; - break; - case 3: - videoCodec.width = 640; - videoCodec.height = 480; - break; - case 4: - videoCodec.width = 704; - videoCodec.height = 576; - break; - case 5: - videoCodec.width = 1280; - videoCodec.height = 720; - break; - case 6: - videoCodec.width = 1920; - videoCodec.height = 1080; - break; - } + resolnOption = atoi(str.c_str()); + } + switch (resolnOption) { + case 1: + videoCodec.width = 176; + videoCodec.height = 144; + break; + case 2: + videoCodec.width = 352; + videoCodec.height = 288; + break; + case 3: + videoCodec.width = 640; + videoCodec.height = 480; + break; + case 4: + videoCodec.width = 704; + videoCodec.height = 576; + break; + case 5: + videoCodec.width = 1280; + videoCodec.height = 720; + break; + case 6: + videoCodec.width = 1920; + videoCodec.height = 1080; + break; + } - // Set number of temporal layers. + // Set number of temporal layers. + int numTemporalLayers; + if (FLAGS_temporal_layers >= 0 && FLAGS_temporal_layers < 5) { + numTemporalLayers = FLAGS_temporal_layers; + } else { + std::string str; std::cout << std::endl; std::cout << "Choose number of temporal layers (1 to 4)."; std::cout << "Press enter for default: \n"; std::getline(std::cin, str); - int numTemporalLayers = atoi(str.c_str()); - if(numTemporalLayers != 0) - { - videoCodec.codecSpecific.VP8.numberOfTemporalLayers = numTemporalLayers; - } + numTemporalLayers = atoi(str.c_str()); + } + if (numTemporalLayers != 0) { + videoCodec.codecSpecific.VP8.numberOfTemporalLayers = numTemporalLayers; + } - // Set start bit rate + // Set start bit rate + int startRate; + if (FLAGS_start_rate >= 0) { + startRate = FLAGS_start_rate; + } else { + std::string str; std::cout << std::endl; std::cout << "Choose start rate (in kbps). Press enter for default: "; std::getline(std::cin, str); - int startRate = atoi(str.c_str()); - if(startRate != 0) - { - videoCodec.startBitrate=startRate; - } + startRate = atoi(str.c_str()); + } + if (startRate != 0) { + videoCodec.startBitrate = startRate; + } - error = ptrViECodec->SetSendCodec(videoChannel, videoCodec); - assert(error != -1); - error = ptrViECodec->SetReceiveCodec(videoChannel, videoCodec); - assert(error != -1); + error = ptrViECodec->SetSendCodec(videoChannel, videoCodec); + assert(error != -1); + error = ptrViECodec->SetReceiveCodec(videoChannel, videoCodec); + assert(error != -1); - // - // Choose Protection Mode - // + // Choose Protection Mode + int protectionMethod; + error = 0; + if (FLAGS_protection_method >= 0) { + protectionMethod = FLAGS_protection_method; + } else { + std::string str; std::cout << std::endl; std::cout << "Enter Protection Method:" << std::endl; std::cout << "0. None" << std::endl; @@ -432,297 +452,321 @@ int VideoEngineSampleCode(void* window1, void* window2) std::cout << "2. NACK" << std::endl; std::cout << "3. NACK+FEC" << std::endl; std::getline(std::cin, str); - int protectionMethod = atoi(str.c_str()); - error = 0; - bool temporalToggling = true; - switch (protectionMethod) - { - case 0: // None: default is no protection - break; + protectionMethod = atoi(str.c_str()); + } + bool temporalToggling = true; + switch (protectionMethod) { + case 0: // None: default is no protection + break; - case 1: // FEC only - error = ptrViERtpRtcp->SetFECStatus(videoChannel, - true, - VCM_RED_PAYLOAD_TYPE, - VCM_ULPFEC_PAYLOAD_TYPE); - temporalToggling = false; - break; + case 1: // FEC only + error = ptrViERtpRtcp->SetFECStatus(videoChannel, + true, + VCM_RED_PAYLOAD_TYPE, + VCM_ULPFEC_PAYLOAD_TYPE); + temporalToggling = false; + break; - case 2: // Nack only - error = ptrViERtpRtcp->SetNACKStatus(videoChannel, true); + case 2: // Nack only + error = ptrViERtpRtcp->SetNACKStatus(videoChannel, true); - break; + break; - case 3: // Hybrid NAck and FEC - error = ptrViERtpRtcp->SetHybridNACKFECStatus( - videoChannel, - true, - VCM_RED_PAYLOAD_TYPE, - VCM_ULPFEC_PAYLOAD_TYPE); - temporalToggling = false; - break; - } + case 3: // Hybrid Nack and FEC + error = ptrViERtpRtcp->SetHybridNACKFECStatus( + videoChannel, + true, + VCM_RED_PAYLOAD_TYPE, + VCM_ULPFEC_PAYLOAD_TYPE); + temporalToggling = false; + break; + } - if (error < 0) - { - printf("ERROR in ViERTP_RTCP::SetProtectionStatus\n"); - } + if (error < 0) { + printf("ERROR in ViERTP_RTCP::SetProtectionStatus\n"); + } - // Set up buffering delay. + // Set up decode error mode. + int errorMode; + if (FLAGS_decode_error_mode >= 0) { + errorMode = FLAGS_decode_error_mode; + } else { + std::string str; + std::cout << std::endl; + std::cout << "Enter Decode Error mode:" << std::endl; + std::cout << "0. No Errors" << std::endl; + std::cout << "1. Selective Errors" << std::endl; + std::cout << "2. With Errors" << std::endl; + std::getline(std::cin, str); + errorMode = atoi(str.c_str()); + } + error = 0; + switch (errorMode) { + case 0: // No Errors + break; + case 1: // Selective Errors + error = ptrViECodec->SetDecodeErrorMode(videoChannel, + webrtc::ViECodec::kSelectiveErrors); + break; + case 2: // With Errors (missing packets never prevent decoding attempts) + error = ptrViECodec->SetDecodeErrorMode(videoChannel, + webrtc::ViECodec::kWithErrors); + break; + } + if (error < 0) { + printf("ERROR in ViERTP_RTCP::SetDecodeErrorMode\n"); + } + + // Set up buffering delay. + int buffering_delay; + if (FLAGS_buffering_delay >= 0) { + buffering_delay = FLAGS_buffering_delay; + } else { + std::string str; std::cout << std::endl; std::cout << "Set buffering delay (mS). Press enter for default(0mS): "; std::getline(std::cin, str); - int buffering_delay = atoi(str.c_str()); - if (buffering_delay != 0) { - error = ptrViERtpRtcp->SetSenderBufferingMode(videoChannel, + buffering_delay = atoi(str.c_str()); + } + if (buffering_delay != 0) { + error = ptrViERtpRtcp->SetSenderBufferingMode(videoChannel, + buffering_delay); + if (error < 0) + printf("ERROR in ViERTP_RTCP::SetSenderBufferingMode\n"); + + error = ptrViERtpRtcp->SetReceiverBufferingMode(videoChannel, buffering_delay); - if (error < 0) - printf("ERROR in ViERTP_RTCP::SetSenderBufferingMode\n"); + if (error < 0) + printf("ERROR in ViERTP_RTCP::SetReceiverBufferingMode\n"); + } - error = ptrViERtpRtcp->SetReceiverBufferingMode(videoChannel, - buffering_delay); - if (error < 0) - printf("ERROR in ViERTP_RTCP::SetReceiverBufferingMode\n"); - } + // Address settings + webrtc::ViENetwork* ptrViENetwork = + webrtc::ViENetwork::GetInterface(ptrViE); + if (ptrViENetwork == NULL) { + printf("ERROR in ViENetwork::GetInterface\n"); + return -1; + } - // - // Address settings - // - webrtc::ViENetwork* ptrViENetwork = - webrtc::ViENetwork::GetInterface(ptrViE); - if (ptrViENetwork == NULL) - { - printf("ERROR in ViENetwork::GetInterface\n"); - return -1; - } + // Setup transport. + TbExternalTransport* extTransport = NULL; + webrtc::test::VideoChannelTransport* video_channel_transport = NULL; - // Setup transport. - TbExternalTransport* extTransport = NULL; - webrtc::test::VideoChannelTransport* video_channel_transport = NULL; - - int testMode = 0; + int testMode = 0; + if (FLAGS_percent_loss == 0) { + testMode = 0; + } else if (FLAGS_percent_loss > 0) { + testMode = 1; + } else { std::cout << std::endl; std::cout << "Enter 1 for testing packet loss and delay with " "external transport: "; std::string test_str; std::getline(std::cin, test_str); testMode = atoi(test_str.c_str()); - if (testMode == 1) - { - // Avoid changing SSRC due to collision. - error = ptrViERtpRtcp->SetLocalSSRC(videoChannel, 1); + } + if (testMode == 1) { + // Avoid changing SSRC due to collision. + error = ptrViERtpRtcp->SetLocalSSRC(videoChannel, 1); - extTransport = new TbExternalTransport(*ptrViENetwork, videoChannel, - NULL); + extTransport = new TbExternalTransport(*ptrViENetwork, videoChannel, + NULL); - error = ptrViENetwork->RegisterSendTransport(videoChannel, - *extTransport); - if (error == -1) - { - printf("ERROR in ViECodec::RegisterSendTransport \n"); - return -1; - } - - // Setting uniform loss. Actual values will be set by user. - NetworkParameters network; - network.loss_model = kUniformLoss; - // Set up packet loss value - std::cout << "Enter Packet Loss Percentage" << std::endl; - std::string rate_str; - std::getline(std::cin, rate_str); - network.packet_loss_rate = atoi(rate_str.c_str()); - if (network.packet_loss_rate > 0) { - temporalToggling = false; - } - - // Set network delay value - std::cout << "Enter network delay value [mS]" << std::endl; - std::string delay_str; - std::getline(std::cin, delay_str); - network.mean_one_way_delay = atoi(delay_str.c_str()); - extTransport->SetNetworkParameters(network); - if (numTemporalLayers > 1 && temporalToggling) { - extTransport->SetTemporalToggle(numTemporalLayers); - } else { - // Disabled - extTransport->SetTemporalToggle(0); - } - } - else - { - video_channel_transport = new webrtc::test::VideoChannelTransport( - ptrViENetwork, videoChannel); - - const char* ipAddress = "127.0.0.1"; - const unsigned short rtpPort = 6000; - std::cout << std::endl; - std::cout << "Using rtp port: " << rtpPort << std::endl; - std::cout << std::endl; - - error = video_channel_transport->SetLocalReceiver(rtpPort); - if (error == -1) - { - printf("ERROR in SetLocalReceiver\n"); - return -1; - } - error = video_channel_transport->SetSendDestination(ipAddress, rtpPort); - if (error == -1) - { - printf("ERROR in SetSendDestination\n"); - return -1; - } + error = ptrViENetwork->RegisterSendTransport(videoChannel, + *extTransport); + if (error == -1) { + printf("ERROR in ViECodec::RegisterSendTransport \n"); + return -1; } - error = ptrViEBase->StartReceive(videoChannel); - if (error == -1) - { - printf("ERROR in ViENetwork::StartReceive\n"); - return -1; + // Setting uniform loss. Actual values will be set by user. + NetworkParameters network; + network.loss_model = kUniformLoss; + // Set up packet loss value + if (FLAGS_percent_loss > 0) { + network.packet_loss_rate = FLAGS_percent_loss; + } else { + std::cout << "Enter Packet Loss Percentage" << std::endl; + std::string rate_str; + std::getline(std::cin, rate_str); + network.packet_loss_rate = atoi(rate_str.c_str()); + } + if (network.packet_loss_rate > 0) { + temporalToggling = false; } - error = ptrViEBase->StartSend(videoChannel); - if (error == -1) - { - printf("ERROR in ViENetwork::StartSend\n"); - return -1; + // Set network delay value + int network_delay; + if (FLAGS_network_delay >= 0) { + network_delay = FLAGS_network_delay; + } else { + std::cout << "Enter network delay value [mS]" << std::endl; + std::string delay_str; + std::getline(std::cin, delay_str); + network_delay = atoi(delay_str.c_str()); } - - //******************************************************** - // Engine started - //******************************************************** - - - // Call started - printf("\nLoopback call started\n\n"); - printf("Press enter to stop..."); - while ((getchar()) != '\n') - ; - - //******************************************************** - // Testing finished. Tear down Video Engine - //******************************************************** - - error = ptrViEBase->StopReceive(videoChannel); - if (error == -1) - { - printf("ERROR in ViEBase::StopReceive\n"); - return -1; + network.mean_one_way_delay = network_delay; + extTransport->SetNetworkParameters(network); + if (numTemporalLayers > 1 && temporalToggling) { + extTransport->SetTemporalToggle(numTemporalLayers); + } else { + // Disabled + extTransport->SetTemporalToggle(0); } + } else { + video_channel_transport = new webrtc::test::VideoChannelTransport( + ptrViENetwork, videoChannel); - error = ptrViEBase->StopSend(videoChannel); - if (error == -1) - { - printf("ERROR in ViEBase::StopSend\n"); - return -1; + const char* ipAddress = "127.0.0.1"; + const unsigned short rtpPort = 6000; + std::cout << std::endl; + std::cout << "Using rtp port: " << rtpPort << std::endl; + std::cout << std::endl; + + error = video_channel_transport->SetLocalReceiver(rtpPort); + if (error == -1) { + printf("ERROR in SetLocalReceiver\n"); + return -1; } - - error = ptrViERender->StopRender(captureId); - if (error == -1) - { - printf("ERROR in ViERender::StopRender\n"); - return -1; + error = video_channel_transport->SetSendDestination(ipAddress, rtpPort); + if (error == -1) { + printf("ERROR in SetSendDestination\n"); + return -1; } + } - error = ptrViERender->RemoveRenderer(captureId); - if (error == -1) - { - printf("ERROR in ViERender::RemoveRenderer\n"); - return -1; - } + error = ptrViEBase->StartReceive(videoChannel); + if (error == -1) { + printf("ERROR in ViENetwork::StartReceive\n"); + return -1; + } - error = ptrViERender->StopRender(videoChannel); - if (error == -1) - { - printf("ERROR in ViERender::StopRender\n"); - return -1; - } + error = ptrViEBase->StartSend(videoChannel); + if (error == -1) { + printf("ERROR in ViENetwork::StartSend\n"); + return -1; + } - error = ptrViERender->RemoveRenderer(videoChannel); - if (error == -1) - { - printf("ERROR in ViERender::RemoveRenderer\n"); - return -1; - } + //******************************************************** + // Engine started + //******************************************************** - error = ptrViECapture->StopCapture(captureId); - if (error == -1) - { - printf("ERROR in ViECapture::StopCapture\n"); - return -1; - } - error = ptrViECapture->DisconnectCaptureDevice(videoChannel); - if (error == -1) - { - printf("ERROR in ViECapture::DisconnectCaptureDevice\n"); - return -1; - } + // Call started + printf("\nLoopback call started\n\n"); + printf("Press enter to stop..."); + while ((getchar()) != '\n') {} - error = ptrViECapture->ReleaseCaptureDevice(captureId); - if (error == -1) - { - printf("ERROR in ViECapture::ReleaseCaptureDevice\n"); - return -1; - } + //******************************************************** + // Testing finished. Tear down Video Engine + //******************************************************** - error = ptrViEBase->DeleteChannel(videoChannel); - if (error == -1) - { - printf("ERROR in ViEBase::DeleteChannel\n"); - return -1; - } + error = ptrViEBase->StopReceive(videoChannel); + if (error == -1) { + printf("ERROR in ViEBase::StopReceive\n"); + return -1; + } - delete video_channel_transport; - delete extTransport; + error = ptrViEBase->StopSend(videoChannel); + if (error == -1) { + printf("ERROR in ViEBase::StopSend\n"); + return -1; + } - int remainingInterfaces = 0; - remainingInterfaces = ptrViECodec->Release(); - remainingInterfaces += ptrViECapture->Release(); - remainingInterfaces += ptrViERtpRtcp->Release(); - remainingInterfaces += ptrViERender->Release(); - remainingInterfaces += ptrViENetwork->Release(); - remainingInterfaces += ptrViEBase->Release(); - if (remainingInterfaces > 0) - { - printf("ERROR: Could not release all interfaces\n"); - return -1; - } + error = ptrViERender->StopRender(captureId); + if (error == -1) { + printf("ERROR in ViERender::StopRender\n"); + return -1; + } - bool deleted = webrtc::VideoEngine::Delete(ptrViE); - if (deleted == false) - { - printf("ERROR in VideoEngine::Delete\n"); - return -1; - } + error = ptrViERender->RemoveRenderer(captureId); + if (error == -1) { + printf("ERROR in ViERender::RemoveRenderer\n"); + return -1; + } + + error = ptrViERender->StopRender(videoChannel); + if (error == -1) { + printf("ERROR in ViERender::StopRender\n"); + return -1; + } + + error = ptrViERender->RemoveRenderer(videoChannel); + if (error == -1) { + printf("ERROR in ViERender::RemoveRenderer\n"); + return -1; + } + + error = ptrViECapture->StopCapture(captureId); + if (error == -1) { + printf("ERROR in ViECapture::StopCapture\n"); + return -1; + } + + error = ptrViECapture->DisconnectCaptureDevice(videoChannel); + if (error == -1) { + printf("ERROR in ViECapture::DisconnectCaptureDevice\n"); + return -1; + } + + error = ptrViECapture->ReleaseCaptureDevice(captureId); + if (error == -1) { + printf("ERROR in ViECapture::ReleaseCaptureDevice\n"); + return -1; + } + + error = ptrViEBase->DeleteChannel(videoChannel); + if (error == -1) { + printf("ERROR in ViEBase::DeleteChannel\n"); + return -1; + } + + delete video_channel_transport; + delete extTransport; + + int remainingInterfaces = 0; + remainingInterfaces = ptrViECodec->Release(); + remainingInterfaces += ptrViECapture->Release(); + remainingInterfaces += ptrViERtpRtcp->Release(); + remainingInterfaces += ptrViERender->Release(); + remainingInterfaces += ptrViENetwork->Release(); + remainingInterfaces += ptrViEBase->Release(); + if (remainingInterfaces > 0) { + printf("ERROR: Could not release all interfaces\n"); + return -1; + } + + bool deleted = webrtc::VideoEngine::Delete(ptrViE); + if (deleted == false) { + printf("ERROR in VideoEngine::Delete\n"); + return -1; + } + + return 0; + + // + // END: VideoEngine 3.0 Sample Code + // + // =================================================================== +} + +int ViEAutoTest::ViELoopbackCall() { + ViETest::Log(" "); + ViETest::Log("========================================"); + ViETest::Log(" ViE Autotest Loopback Call\n"); + + if (VideoEngineSampleCode(_window1, _window2) == 0) { + ViETest::Log(" "); + ViETest::Log(" ViE Autotest Loopback Call Done"); + ViETest::Log("========================================"); + ViETest::Log(" "); return 0; + } - // - // END: VideoEngine 3.0 Sample Code - // - // =================================================================== -} - -int ViEAutoTest::ViELoopbackCall() -{ - ViETest::Log(" "); - ViETest::Log("========================================"); - ViETest::Log(" ViE Autotest Loopback Call\n"); - - if (VideoEngineSampleCode(_window1, _window2) == 0) - { - ViETest::Log(" "); - ViETest::Log(" ViE Autotest Loopback Call Done"); - ViETest::Log("========================================"); - ViETest::Log(" "); - - return 0; - } - - ViETest::Log(" "); - ViETest::Log(" ViE Autotest Loopback Call Failed"); - ViETest::Log("========================================"); - ViETest::Log(" "); - return 1; - + ViETest::Log(" "); + ViETest::Log(" ViE Autotest Loopback Call Failed"); + ViETest::Log("========================================"); + ViETest::Log(" "); + return 1; } diff --git a/webrtc/video_engine/test/auto_test/source/vie_autotest_main.cc b/webrtc/video_engine/test/auto_test/source/vie_autotest_main.cc index 0032678b3..505a1d96e 100644 --- a/webrtc/video_engine/test/auto_test/source/vie_autotest_main.cc +++ b/webrtc/video_engine/test/auto_test/source/vie_autotest_main.cc @@ -19,7 +19,17 @@ #include "webrtc/video_engine/test/auto_test/interface/vie_window_creator.h" DEFINE_bool(automated, false, "Run Video engine tests in noninteractive mode."); -DEFINE_bool(auto_custom_call, false, "Run custom call directly."); +DEFINE_int32(test_type, -1, "Test type:\n" + "\t1. All standard tests (delivery test)\n" + "\t2. All API tests\n" + "\t3. All extended tests\n" + "\t4. Specific standard test\n" + "\t5. Specific API test\n" + "\t6. Specific extended test\n" + "\t7. Simple loopback call\n" + "\t8. Custom configure a call\n" + "\t9. Simulcast in loopback\n" + "\t10. Record"); static const std::string kStandardTest = "ViEStandardIntegrationTest"; static const std::string kExtendedTest = "ViEExtendedIntegrationTest"; @@ -50,7 +60,7 @@ int ViEAutoTestMain::RunTests(int argc, char** argv) { if (FLAGS_automated) { // Run in automated mode. result = RUN_ALL_TESTS(); - } else if (FLAGS_auto_custom_call) { + } else if (FLAGS_test_type == 8) { // Run automated custom call. result = RunSpecialTestCase(8); } else { @@ -111,11 +121,10 @@ int ViEAutoTestMain::RunTestMatching(const std::string test_case, return RUN_ALL_TESTS(); } -int ViEAutoTestMain::RunSpecificTestCaseIn(const std::string test_case_name) -{ +int ViEAutoTestMain::RunSpecificTestCaseIn(const std::string test_case_name) { // If user says 0, it means don't run anything. int specific_choice = AskUserForTestCase(); - if (specific_choice != 0){ + if (specific_choice != 0) { return RunTestMatching(test_case_name, index_to_test_method_map_[specific_choice]); } @@ -154,36 +163,40 @@ int ViEAutoTestMain::RunInteractiveMode() { int choice = 0; int errors = 0; - do { - ViETest::Log("Test types: "); - ViETest::Log("\t 0. Quit"); - ViETest::Log("\t 1. All standard tests (delivery test)"); - ViETest::Log("\t 2. All API tests"); - ViETest::Log("\t 3. All extended test"); - ViETest::Log("\t 4. Specific standard test"); - ViETest::Log("\t 5. Specific API test"); - ViETest::Log("\t 6. Specific extended test"); - ViETest::Log("\t 7. Simple loopback call"); - ViETest::Log("\t 8. Custom configure a call"); - ViETest::Log("\t 9. Simulcast in loopback"); - ViETest::Log("\t 10. Record"); - ViETest::Log("Select type of test:"); + if (FLAGS_test_type > 0 && FLAGS_test_type < 11) { + choice = FLAGS_test_type; + } else { + do { + ViETest::Log("Test types: "); + ViETest::Log("\t 0. Quit"); + ViETest::Log("\t 1. All standard tests (delivery test)"); + ViETest::Log("\t 2. All API tests"); + ViETest::Log("\t 3. All extended test"); + ViETest::Log("\t 4. Specific standard test"); + ViETest::Log("\t 5. Specific API test"); + ViETest::Log("\t 6. Specific extended test"); + ViETest::Log("\t 7. Simple loopback call"); + ViETest::Log("\t 8. Custom configure a call"); + ViETest::Log("\t 9. Simulcast in loopback"); + ViETest::Log("\t 10. Record"); + ViETest::Log("Select type of test:"); - choice = AskUserForNumber(0, 10); - if (choice == kInvalidChoice) { - continue; - } - switch (choice) { - case 0: break; - case 1: errors = RunTestMatching(kStandardTest, "*"); break; - case 2: errors = RunTestMatching(kApiTest, "*"); break; - case 3: errors = RunTestMatching(kExtendedTest, "*"); break; - case 4: errors = RunSpecificTestCaseIn(kStandardTest); break; - case 5: errors = RunSpecificTestCaseIn(kApiTest); break; - case 6: errors = RunSpecificTestCaseIn(kExtendedTest); break; - default: errors = RunSpecialTestCase(choice); break; - } - } while (choice != 0); + choice = AskUserForNumber(0, 10); + if (choice == kInvalidChoice) { + continue; + } + } while (choice != 0); + } + + switch (choice) { + case 1: errors = RunTestMatching(kStandardTest, "*"); break; + case 2: errors = RunTestMatching(kApiTest, "*"); break; + case 3: errors = RunTestMatching(kExtendedTest, "*"); break; + case 4: errors = RunSpecificTestCaseIn(kStandardTest); break; + case 5: errors = RunSpecificTestCaseIn(kApiTest); break; + case 6: errors = RunSpecificTestCaseIn(kExtendedTest); break; + default: errors = RunSpecialTestCase(choice); break; + } if (errors) { ViETest::Log("Test done with errors, see ViEAutotestLog.txt for test " diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc index 476fde338..851d1c054 100644 --- a/webrtc/video_engine/vie_channel.cc +++ b/webrtc/video_engine/vie_channel.cc @@ -767,6 +767,20 @@ int32_t ViEChannel::SetHybridNACKFECStatus( return ProcessFECRequest(enable, payload_typeRED, payload_typeFEC); } +void ViEChannel::SetDecodeErrorMode(ViECodec::ViEDecodeErrorMode error_mode) { + switch (error_mode) { + case ViECodec::kNoErrors: + vcm_.SetDecodeErrorMode(kNoErrors); + break; + case ViECodec::kSelectiveErrors: + vcm_.SetDecodeErrorMode(kSelectiveErrors); + break; + case ViECodec::kWithErrors: + vcm_.SetDecodeErrorMode(kWithErrors); + break; + } +} + int ViEChannel::SetSenderBufferingMode(int target_delay_ms) { if ((target_delay_ms < 0) || (target_delay_ms > kMaxTargetDelayMs)) { WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_), diff --git a/webrtc/video_engine/vie_channel.h b/webrtc/video_engine/vie_channel.h index ce5e5fcb5..0d2e64b42 100644 --- a/webrtc/video_engine/vie_channel.h +++ b/webrtc/video_engine/vie_channel.h @@ -15,10 +15,12 @@ #include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h" +#include "webrtc/modules/video_coding/main/interface/video_coding.h" #include "webrtc/modules/video_coding/main/interface/video_coding_defines.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" #include "webrtc/system_wrappers/interface/tick_util.h" #include "webrtc/typedefs.h" +#include "webrtc/video_engine/include/vie_codec.h" #include "webrtc/video_engine/include/vie_network.h" #include "webrtc/video_engine/include/vie_rtp_rtcp.h" #include "webrtc/video_engine/vie_defines.h" @@ -115,6 +117,7 @@ class ViEChannel int32_t SetHybridNACKFECStatus(const bool enable, const unsigned char payload_typeRED, const unsigned char payload_typeFEC); + void SetDecodeErrorMode(ViECodec::ViEDecodeErrorMode error_mode); int SetSenderBufferingMode(int target_delay_ms); int SetReceiverBufferingMode(int target_delay_ms); int32_t SetKeyFrameRequestMethod(const KeyFrameRequestMethod method); diff --git a/webrtc/video_engine/vie_codec_impl.cc b/webrtc/video_engine/vie_codec_impl.cc index 61449db09..5cf5c636d 100644 --- a/webrtc/video_engine/vie_codec_impl.cc +++ b/webrtc/video_engine/vie_codec_impl.cc @@ -690,6 +690,25 @@ int ViECodecImpl::WaitForFirstKeyFrame(const int video_channel, return 0; } +int ViECodecImpl::SetDecodeErrorMode(const int video_channel, + const ViEDecodeErrorMode error_mode) { + WEBRTC_TRACE(kTraceApiCall, kTraceVideo, + ViEId(shared_data_->instance_id(), video_channel), + "%s(channel: %d)", __FUNCTION__, video_channel); + + ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); + ViEChannel* vie_channel = cs.Channel(video_channel); + if (!vie_channel) { + WEBRTC_TRACE(kTraceError, kTraceVideo, + ViEId(shared_data_->instance_id(), video_channel), + "%s: Channel %d does not exist", __FUNCTION__, video_channel); + shared_data_->SetLastError(kViEBaseInvalidChannelId); + return -1; + } + vie_channel->SetDecodeErrorMode(error_mode); + return 0; +} + int ViECodecImpl::StartDebugRecording(int video_channel, const char* file_name_utf8) { ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); diff --git a/webrtc/video_engine/vie_codec_impl.h b/webrtc/video_engine/vie_codec_impl.h index aa5cc71df..66cae9e4b 100644 --- a/webrtc/video_engine/vie_codec_impl.h +++ b/webrtc/video_engine/vie_codec_impl.h @@ -69,6 +69,8 @@ class ViECodecImpl virtual int WaitForFirstKeyFrame(const int video_channel, const bool wait); virtual int StartDebugRecording(int video_channel, const char* file_name_utf8); + virtual int SetDecodeErrorMode(const int video_channel, + const ViEDecodeErrorMode error_mode); virtual int StopDebugRecording(int video_channel); protected: