Add native self-hosted instance connection to fluxer_desktop

Trimmed monorepo checkout (fluxer_desktop + packages/voice_engine_v2 +
tools/ci) with a "Connect to a Different Server" menu item and popout
that lets the desktop app switch to any self-hosted Fluxer instance,
plus fixes for well-known discovery on single-domain self-hosted
deployments and a false-positive ERR_ABORTED on same-origin client
redirects during the switch. Defaults to chat.fluxr.chat and uses an
isolated userData directory from the official build.
This commit is contained in:
2026-07-01 18:22:43 -04:00
commit 682afacd30
1763 changed files with 613720 additions and 0 deletions
@@ -0,0 +1,92 @@
# Project-level configuration.
cmake_minimum_required(VERSION 3.10)
project(runner LANGUAGES CXX C)
enable_language(ASM)
set(BINARY_NAME "h264_benchmark")
# Set the C++ standard to C++23.
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_BUILD_TYPE Debug)
add_definitions(-DWEBRTC_POSIX)
add_definitions(-DWEBRTC_LINUX)
add_definitions(-DUSE_UDEV)
add_definitions(-DUSE_AURA=1)
add_definitions(-DUSE_GLIB=1)
add_definitions(-DUSE_OZONE=1)
add_definitions(-D__STDC_CONSTANT_MACROS)
add_definitions(-D__STDC_FORMAT_MACROS)
add_definitions(-D_FILE_OFFSET_BITS=64)
add_definitions(-D_LARGEFILE_SOURCE)
add_definitions(-D_LARGEFILE64_SOURCE)
add_definitions(-D_GNU_SOURCE)
add_definitions(-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE)
add_definitions(-D_GLIBCXX_ASSERTIONS=1)
add_definitions(-DCR_CLANG_REVISION=\"llvmorg-19-init-8091-gab037c4f-1\")
add_definitions(-DCR_SYSROOT_KEY=20230611T210420Z-2)
add_definitions(-DDYNAMIC_ANNOTATIONS_ENABLED=1)
add_definitions(-DWEBRTC_ENABLE_PROTOBUF=0)
add_definitions(-DWEBRTC_STRICT_FIELD_TRIALS=0)
add_definitions(-DWEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE)
add_definitions(-DRTC_USE_LIBAOM_AV1_ENCODER)
add_definitions(-DRTC_ENABLE_VP9)
add_definitions(-DRTC_DAV1D_IN_INTERNAL_DECODER_FACTORY)
add_definitions(-DWEBRTC_HAVE_SCTP)
add_definitions(-DWEBRTC_USE_H264)
add_definitions(-DWEBRTC_ENABLE_LIBEVENT)
add_definitions(-DWEBRTC_LIBRARY_IMPL)
add_definitions(-DWEBRTC_ENABLE_AVX2)
include_directories(
"${CMAKE_CURRENT_SOURCE_DIR}/../libwebrtc/linux-x64-debug/include"
"${CMAKE_CURRENT_SOURCE_DIR}/../libwebrtc/linux-x64-release/include/third_party/abseil-cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/../libwebrtc/linux-x64-release/include/third_party/libyuv/include"
"${CMAKE_CURRENT_SOURCE_DIR}/../src/nvidia/NvCodec/include"
"${CMAKE_CURRENT_SOURCE_DIR}/../src/nvidia/NvCodec/NvCodec"
"${CMAKE_CURRENT_SOURCE_DIR}/../src"
)
link_libraries(
"${CMAKE_CURRENT_SOURCE_DIR}/../libwebrtc/linux-x64-release/lib/libwebrtc.a"
)
find_package (Threads)
add_executable(${BINARY_NAME}
"test_main.cc"
"benchmark.cc"
"benchmark_openh264.cc"
"video_source.cc"
"fileutils.cc"
"cpu/cpu_linux.cc"
"benchmark_nvidia.cc"
"../src/nvidia/NvCodec/NvCodec/NvDecoder/NvDecoder.cpp"
"../src/nvidia/NvCodec/NvCodec/NvEncoder/NvEncoder.cpp"
"../src/nvidia/NvCodec/NvCodec/NvEncoder/NvEncoderCuda.cpp"
"../src/nvidia/h264_encoder_impl.cpp"
"../src/nvidia/h264_decoder_impl.cpp"
"../src/nvidia/nvidia_decoder_factory.cpp"
"../src/nvidia/nvidia_encoder_factory.cpp"
"../src/nvidia/cuda_context.cpp"
"../src/nvidia/implib/libcuda.so.init.c"
"../src/nvidia/implib/libcuda.so.tramp.S"
"../src/nvidia/implib/libnvcuvid.so.init.c"
"../src/nvidia/implib/libnvcuvid.so.tramp.S"
"benchmark_vaapi.cc"
"../src/vaapi/vaapi_display_drm.cpp"
"../src/vaapi/vaapi_h264_encoder_wrapper.cpp"
"../src/vaapi/vaapi_encoder_factory.cpp"
"../src/vaapi/h264_encoder_impl.cpp"
"../src/vaapi/implib/libva-drm.so.init.c"
"../src/vaapi/implib/libva-drm.so.tramp.S"
"../src/vaapi/implib/libva.so.init.c"
"../src/vaapi/implib/libva.so.tramp.S"
)
target_link_libraries(${BINARY_NAME} ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(${BINARY_NAME} dl)
@@ -0,0 +1,451 @@
/*
* 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 "benchmark.h"
#include <cassert>
#include <iostream>
#include <sstream>
#include <vector>
#if defined(_WIN32)
#include <windows.h>
#endif
#include "api/video/i420_buffer.h"
#include "common_video/libyuv/include/webrtc_libyuv.h"
#include "fileutils.h"
#include "modules/video_coding/utility/simulcast_rate_allocator.h"
#include "rtc_base/event.h"
#include "video_source.h"
#define SSIM_CALC 0 // by default, don't compute SSIM
using namespace webrtc;
#define EXPECT_EQ (a, b)
FrameQueueTuple::~FrameQueueTuple() {
if (_codecSpecificInfo != NULL) {
delete _codecSpecificInfo;
}
if (_frame != NULL) {
delete _frame;
}
}
void FrameQueue::PushFrame(VideoFrame* frame,
webrtc::CodecSpecificInfo* codecSpecificInfo) {
webrtc::MutexLock cs(&_queueRWLock);
_frameBufferQueue.push(new FrameQueueTuple(frame, codecSpecificInfo));
}
FrameQueueTuple* FrameQueue::PopFrame() {
webrtc::MutexLock cs(&_queueRWLock);
if (_frameBufferQueue.empty()) {
return NULL;
}
FrameQueueTuple* tuple = _frameBufferQueue.front();
_frameBufferQueue.pop();
return tuple;
}
bool FrameQueue::Empty() {
webrtc::MutexLock cs(&_queueRWLock);
return _frameBufferQueue.empty();
}
uint32_t VideoEncodeCompleteCallback::EncodedBytes() {
return _encodedBytes;
}
webrtc::EncodedImageCallback::Result
VideoEncodeCompleteCallback::OnEncodedImage(
const webrtc::EncodedImage& encodedImage,
const webrtc::CodecSpecificInfo* codecSpecificInfo) {
_test.UpdateEncodedBytes(encodedImage.GetEncodedData()->size());
_encodedBytes += encodedImage.GetEncodedData()->size();
if (_encodedFile != NULL) {
if (fwrite(encodedImage.GetEncodedData()->data(), 1,
encodedImage.GetEncodedData()->size(),
_encodedFile) != encodedImage.GetEncodedData()->size()) {
fprintf(stderr, "Error writing to encoded file %s\n",
_test._outname.c_str());
}
}
return webrtc::EncodedImageCallback::Result(
webrtc::EncodedImageCallback::Result::OK);
}
Benchmark::Benchmark()
: _resultsFileName(webrtc::test::OutputPath() + "benchmark.txt"),
_codecName("Default"),
_env(webrtc::CreateEnvironment()) {}
Benchmark::Benchmark(std::string name, std::string description)
: _name(name),
_description(description),
_resultsFileName(webrtc::test::OutputPath() + "benchmark.txt"),
_codecName("Default"),
_env(webrtc::CreateEnvironment()) {}
Benchmark::Benchmark(std::string name,
std::string description,
std::string resultsFileName,
std::string codecName)
: _name(name),
_description(description),
_resultsFileName(resultsFileName),
_codecName(codecName),
_cpu(webrtc::CpuWrapper::CreateCpu()),
_env(webrtc::CreateEnvironment()) {}
void Benchmark::Perform() {
std::vector<const VideoSource*> sources;
std::vector<const VideoSource*>::iterator it;
// Configuration --------------------------
sources.push_back(new const VideoSource(
webrtc::test::ProjectRootPath() + "resources/FourPeople_1280x720_30.yuv",
kWHD));
//sources.push_back(
// new const VideoSource(webrtc::test::ProjectRootPath() +
// "resources/Big_Buck_Bunny_1920x1080_30.yuv",
// kWFullHD));
const VideoSize size[] = {kWHD};
const int frameRate[] = {30};
// Specifies the framerates for which to perform a speed test.
const bool speedTestMask[] = {true};
const int bitRate[] = {500, 1000, 2000, 3000, 4000};
// Determines the number of iterations to perform to arrive at the speed
// result.
enum { kSpeedTestIterations = 8 };
// ----------------------------------------
const int nFrameRates = sizeof(frameRate) / sizeof(*frameRate);
assert(sizeof(speedTestMask) / sizeof(*speedTestMask) == nFrameRates);
const int nBitrates = sizeof(bitRate) / sizeof(*bitRate);
int testIterations = 1;
double fps[nBitrates];
uint32_t cpuUsage[nBitrates];
double totalEncodeTime[nBitrates];
double totalDecodeTime[nBitrates];
_results.open(_resultsFileName.c_str(), std::fstream::out);
_results << GetMagicStr() << std::endl;
_results << _codecName << std::endl;
for (it = sources.begin(); it < sources.end(); it++) {
int i = 0;
for (int j = 0; j < nFrameRates; j++) {
_target = *it;
_inname = (*it)->GetFileName();
std::cout << (*it)->GetName() << ", "
<< VideoSource::GetSizeString(size[i]) << ", " << frameRate[j]
<< " fps" << ", " << _name << std::endl;
_results << (*it)->GetName() << "," << VideoSource::GetSizeString(size[i])
<< "," << frameRate[j] << " fps" << ", " << _name << std::endl
<< "Bitrate [kbps]";
if (speedTestMask[j]) {
testIterations = kSpeedTestIterations;
} else {
testIterations = 1;
}
for (int k = 0; k < nBitrates; k++) {
_bitRate = (bitRate[k]);
double avgFps = 0.0;
uint32_t currCpuUsage = 0;
totalEncodeTime[k] = 0;
std::cout << "TargetBitrate [kbps]:" << " " << _bitRate << std::endl;
for (int l = 0; l < testIterations; l++) {
PerformNormalTest();
uint32_t cpuUsage = _cpu->CpuUsage();
if (cpuUsage > 0) {
currCpuUsage += cpuUsage;
int coreCount = _cpu->GetNumCores();
std::string str = "CPU Usage[%]: cores ";
str += std::to_string(coreCount);
str += ", usage " + std::to_string(cpuUsage) + "%" +
", Test Iteration: " + std::to_string(l + 1) + "/" +
std::to_string(testIterations);
std::cout << str << std::flush;
for (int i = 0; i < str.length(); ++i) {
std::cout << "\b";
}
}
_appendNext = false;
avgFps += _framecnt / (_totalEncodeTime);
totalEncodeTime[k] += _totalEncodeTime;
}
avgFps /= testIterations;
totalEncodeTime[k] /= testIterations;
currCpuUsage /= testIterations;
double actualBitRate = ActualBitRate(_framecnt) / 1000.0;
std::cout << "ActualBitRate [kbps]:" << " " << actualBitRate
<< std::endl;
_results << "," << actualBitRate;
fps[k] = avgFps;
cpuUsage[k] = currCpuUsage;
}
std::cout << std::endl << "CpuUsage [%]:";
_results << std::endl << "CpuUsage [%]";
for (int k = 0; k < nBitrates; k++) {
std::cout << " " << cpuUsage[k] << "%";
_results << "," << cpuUsage[k] << "%";
}
std::cout << std::endl << "Encode Time[ms]:";
_results << std::endl << "Encode Time[ms]";
for (int k = 0; k < nBitrates; k++) {
std::cout << " " << totalEncodeTime[k];
_results << "," << totalEncodeTime[k];
}
if (speedTestMask[j]) {
std::cout << std::endl << "Speed [fps]:";
_results << std::endl << "Speed [fps]";
for (int k = 0; k < nBitrates; k++) {
std::cout << " " << static_cast<int>(fps[k] + 0.5);
_results << "," << static_cast<int>(fps[k] + 0.5);
}
}
std::cout << std::endl << std::endl;
_results << std::endl << std::endl;
}
i++;
delete *it;
}
_results.close();
}
void Benchmark::PerformNormalTest() {
_encoder = GetNewEncoder(_env);
_lengthSourceFrame = _target->GetFrameLength();
CodecSettings(_target->GetWidth(), _target->GetHeight(),
_target->GetFrameRate(), _bitRate);
Setup();
std::unique_ptr<webrtc::Event> waitEvent = std::make_unique<webrtc::Event>();
//_inputVideoBuffer.VerifyAndAllocate(_lengthSourceFrame);
_encoder->InitEncode(&_inst, 4, 1440);
CodecSpecific_InitBitrate();
//_decoder->InitDecode(&_inst,1);
FrameQueue frameQueue;
VideoEncodeCompleteCallback encCallback(_encodedFile, &frameQueue, *this);
_encoder->RegisterEncodeCompleteCallback(&encCallback);
_totalEncodeTime = _totalDecodeTime = 0;
_totalEncodePipeTime = _totalDecodePipeTime = 0;
bool complete = false;
_framecnt = 0;
_encFrameCnt = 0;
_sumEncBytes = 0;
_lengthEncFrame = 0;
while (!complete) {
complete = Encode();
_framecnt++;
_encFrameCnt++;
/*
if (!frameQueue.Empty() || complete) {
while (!frameQueue.Empty()) {
_frameToDecode = static_cast<FrameQueueTuple*>(frameQueue.PopFrame());
int ret = Decode();
delete _frameToDecode;
_frameToDecode = NULL;
if (ret < 0) {
fprintf(stderr, "\n\nError in decoder: %d\n\n", ret);
exit(EXIT_FAILURE);
} else if (ret == 0) {
_framecnt++;
} else {
fprintf(stderr, "\n\nPositive return value from decode!\n\n");
}
}
}*/
// waitEvent->Wait(webrtc::TimeDelta::Seconds(5));
}
//_inputVideoBuffer.Free();
//_encodedVideoBuffer.Free();
//_decodedVideoBuffer.Free();
Teardown();
}
void Benchmark::Teardown() {
// Use _sourceFile as a check to prevent multiple Teardown() calls.
if (_sourceFile == NULL) {
return;
}
_encoder->Release();
fclose(_sourceFile);
_sourceFile = NULL;
delete[] _sourceBuffer;
_sourceBuffer = NULL;
}
void Benchmark::CodecSpecific_InitBitrate() {
webrtc::SimulcastRateAllocator init_allocator(_env,_inst);
if (_bitRate == 0) {
VideoBitrateAllocation allocation =
init_allocator.Allocate(VideoBitrateAllocationParameters(
DataRate::KilobitsPerSec(600), _inst.maxFramerate));
_encoder->SetRates(webrtc::VideoEncoder::RateControlParameters(
allocation, _inst.maxFramerate));
} else {
VideoBitrateAllocation allocation =
init_allocator.Allocate(VideoBitrateAllocationParameters(
DataRate::BitsPerSec(_bitRate), _inst.maxFramerate));
_encoder->SetRates(webrtc::VideoEncoder::RateControlParameters(
allocation, _inst.maxFramerate));
}
}
bool Benchmark::Encode() {
_lengthEncFrame = 0;
if (_sourceBuffer == NULL) {
_sourceBuffer = new unsigned char[_lengthSourceFrame];
}
auto size = fread(_sourceBuffer, 1, _lengthSourceFrame, _sourceFile);
if (size <= 0) {
return true;
}
// TODO: build video frame from buffer ptr.
webrtc::scoped_refptr<webrtc::I420Buffer> buffer(
webrtc::I420Buffer::Create(_inst.width, _inst.height));
buffer->InitializeData();
memcpy(buffer->MutableDataY(), _sourceBuffer, _lengthSourceFrame);
webrtc::VideoFrame inputVideoBuffer =
webrtc::VideoFrame::Builder()
.set_video_frame_buffer(buffer)
.set_rtp_timestamp(
(unsigned int)(_encFrameCnt * 9e4 / _inst.maxFramerate))
.build();
if (feof(_sourceFile) != 0) {
return true;
}
_encodeCompleteTime = 0;
_encodeTimes[inputVideoBuffer.rtp_timestamp()] = tGetTime();
std::vector<VideoFrameType> frame_types(1, VideoFrameType::kVideoFrameDelta);
// check SLI queue
_hasReceivedSLI = false;
while (!_signalSLI.empty() && _signalSLI.front().delay == 0) {
// SLI message has arrived at sender side
_hasReceivedSLI = true;
_pictureIdSLI = _signalSLI.front().id;
_signalSLI.pop_front();
}
// decrement SLI queue times
for (std::list<fbSignal>::iterator it = _signalSLI.begin();
it != _signalSLI.end(); it++) {
(*it).delay--;
}
// check PLI queue
_hasReceivedPLI = false;
while (!_signalPLI.empty() && _signalPLI.front().delay == 0) {
// PLI message has arrived at sender side
_hasReceivedPLI = true;
_signalPLI.pop_front();
}
// decrement PLI queue times
for (std::list<fbSignal>::iterator it = _signalPLI.begin();
it != _signalPLI.end(); it++) {
(*it).delay--;
}
if (_hasReceivedPLI) {
// respond to PLI by encoding a key frame
frame_types[0] = VideoFrameType::kVideoFrameKey;
_hasReceivedPLI = false;
_hasReceivedSLI = false; // don't trigger both at once
}
int ret = _encoder->Encode(inputVideoBuffer, &frame_types);
if (_encodeCompleteTime > 0) {
_totalEncodeTime +=
_encodeCompleteTime - _encodeTimes[inputVideoBuffer.rtp_timestamp()];
} else {
_totalEncodeTime += tGetTime() - _encodeTimes[inputVideoBuffer.rtp_timestamp()];
}
assert(ret >= 0);
return false;
}
webrtc::CodecSpecificInfo* Benchmark::CopyCodecSpecificInfo(
const webrtc::CodecSpecificInfo* codecSpecificInfo) const {
webrtc::CodecSpecificInfo* info = new webrtc::CodecSpecificInfo;
*info = *codecSpecificInfo;
return info;
}
void Benchmark::Setup() {
// Use _sourceFile as a check to prevent multiple Setup() calls.
if (_sourceFile != NULL) {
return;
}
std::stringstream ss;
std::string strTestNo;
ss << "0";
ss >> strTestNo;
// Check if settings exist. Otherwise use defaults.
if (_outname == "") {
_outname =
webrtc::test::OutputPath() + "out_normaltest" + strTestNo + ".yuv";
}
if (_codecName == "") {
_codecName =
webrtc::test::OutputPath() + "encoded_normaltest" + strTestNo + ".yuv";
}
if ((_sourceFile = fopen(_inname.c_str(), "rb")) == NULL) {
printf("Cannot read file %s.\n", _inname.c_str());
exit(1);
}
if ((_encodedFile = fopen(_codecName.c_str(), "wb")) == NULL) {
printf("Cannot write encoded file.\n");
exit(1);
}
char mode[3] = "wb";
if (_appendNext) {
strncpy(mode, "ab", 3);
}
// if ((_decodedFile = fopen(_outname.c_str(), mode)) == NULL) {
// printf("Cannot write file %s.\n", _outname.c_str());
// exit(1);
// }
_appendNext = true;
}
@@ -0,0 +1,214 @@
; /*
* 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.
*/
#ifndef WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_FRAWEWORK_BENCHMARK_H_
#define WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_FRAWEWORK_BENCHMARK_H_
#include <cstdlib>
#include <fstream>
#include <list>
#include <queue>
#include <string>
#include "cpu/cpu_linux.h"
#include "api/environment/environment_factory.h"
#include "modules/include/module_common_types.h"
#include "modules/video_coding/include/video_codec_interface.h"
#include "rtc_base/synchronization/mutex.h"
#include "system_wrappers/include/clock.h"
class VideoSource;
class Benchmark;
// feedback signal to encoder
struct fbSignal {
fbSignal(int d, uint8_t pid) : delay(d), id(pid) {};
int delay;
uint8_t id;
};
class FrameQueueTuple {
public:
FrameQueueTuple(webrtc::VideoFrame* frame,
const webrtc::CodecSpecificInfo* codecSpecificInfo = NULL)
: _frame(frame), _codecSpecificInfo(codecSpecificInfo) {};
~FrameQueueTuple();
webrtc::VideoFrame* _frame;
const webrtc::CodecSpecificInfo* _codecSpecificInfo;
};
class FrameQueue {
public:
FrameQueue() {}
~FrameQueue() {}
void PushFrame(webrtc::VideoFrame* frame,
webrtc::CodecSpecificInfo* codecSpecificInfo = NULL);
FrameQueueTuple* PopFrame();
bool Empty();
private:
webrtc::Mutex _queueRWLock;
std::queue<FrameQueueTuple*> _frameBufferQueue;
};
class VideoEncodeCompleteCallback : public webrtc::EncodedImageCallback {
public:
VideoEncodeCompleteCallback(FILE* encodedFile,
FrameQueue* frameQueue,
Benchmark& test)
: _encodedFile(encodedFile),
_frameQueue(frameQueue),
_test(test),
_encodedBytes(0) {}
webrtc::EncodedImageCallback::Result OnEncodedImage(
const webrtc::EncodedImage& encoded_image,
const webrtc::CodecSpecificInfo* codec_specific_info) override;
uint32_t EncodedBytes();
private:
FILE* _encodedFile;
FrameQueue* _frameQueue;
Benchmark& _test;
uint32_t _encodedBytes;
};
class Benchmark {
public:
friend class VideoEncodeCompleteCallback;
public:
Benchmark();
virtual void Perform();
virtual bool IsSupported() = 0;
protected:
Benchmark(std::string name, std::string description);
Benchmark(std::string name,
std::string description,
std::string resultsFileName,
std::string codecName);
virtual webrtc::VideoEncoder* GetNewEncoder(webrtc::Environment &env) = 0;
virtual void PerformNormalTest();
virtual void CodecSpecific_InitBitrate();
static const char* GetMagicStr() { return "#!benchmark1.0"; }
double ActualBitRate(int nFrames) {
return 8.0 * _sumEncBytes / (nFrames / _inst.maxFramerate);
}
webrtc::CodecSpecificInfo* CopyCodecSpecificInfo(
const webrtc::CodecSpecificInfo* codecSpecificInfo) const;
bool Encode();
void Setup();
void Teardown();
void CodecSettings(int width,
int height,
uint32_t frameRate /*=30*/,
uint32_t bitRate /*=0*/) {
if (bitRate > 0) {
_bitRate = bitRate;
} else if (_bitRate == 0) {
_bitRate = 600;
}
_inst.codecType = webrtc::kVideoCodecH264;
_inst.maxFramerate = (unsigned char)frameRate;
_inst.minBitrate = (unsigned char)frameRate;
_inst.startBitrate = (int)_bitRate;
_inst.maxBitrate = 8000;
_inst.width = width;
_inst.height = height;
_inst.numberOfSimulcastStreams = 1;
_inst.simulcastStream[0].width = width;
_inst.simulcastStream[0].height = height;
_inst.simulcastStream[0].maxBitrate = 8000;
_inst.simulcastStream[0].minBitrate = _bitRate;
_inst.simulcastStream[0].targetBitrate = _bitRate;
_inst.simulcastStream[0].maxFramerate = frameRate;
_inst.simulcastStream[0].active = true;
_inst.SetScalabilityMode(webrtc::ScalabilityMode::kL1T1);
_inst.mode = webrtc::VideoCodecMode::kRealtimeVideo;
_inst.qpMax = 56;
_inst.SetFrameDropEnabled(true);
}
double tGetTime() {
// return time in sec
return ((double)(webrtc::Clock::GetRealTimeClock()->TimeInMilliseconds()) /
1000);
}
virtual webrtc::CodecSpecificInfo* CreateEncoderSpecificInfo() const {
return NULL;
};
void UpdateEncodedBytes(int encodedBytes) { _sumEncBytes += encodedBytes; }
const VideoSource* _target;
std::string _resultsFileName;
std::ofstream _results;
std::string _name;
std::string _description;
std::string _codecName;
std::string _inname;
std::string _outname;
webrtc::VideoEncoder* _encoder;
//webrtc::VideoDecoder* _decoder;
uint32_t _bitRate;
bool _appendNext = false;
int _framecnt;
int _encFrameCnt;
double _totalEncodeTime;
double _totalDecodeTime;
double _decodeCompleteTime;
double _encodeCompleteTime;
double _totalEncodePipeTime;
double _totalDecodePipeTime;
webrtc::VideoCodec _inst;
int _sumEncBytes;
unsigned int _lengthSourceFrame = 0;
unsigned char* _sourceBuffer = nullptr;
FILE* _encodedFile = nullptr;
unsigned int _lengthEncFrame = 0;
FrameQueueTuple* _frameToDecode = nullptr;
FILE* _sourceFile = nullptr;
FILE* _decodedFile = nullptr;
bool _hasReceivedPLI = false;
bool _waitForKey = false;
std::map<uint32_t, double> _encodeTimes;
std::map<uint32_t, double> _decodeTimes;
bool _missingFrames = false;
std::list<fbSignal> _signalSLI;
int _rttFrames = 0;
mutable bool _hasReceivedSLI = false;
mutable bool _hasReceivedRPSI = false;
uint8_t _pictureIdSLI = 0;
uint16_t _pictureIdRPSI = 0;
uint64_t _lastDecRefPictureId = 0;
uint64_t _lastDecPictureId = 0;
std::list<fbSignal> _signalPLI;
webrtc::CpuWrapper* _cpu;
webrtc::Environment _env;
};
#endif // WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_FRAWEWORK_BENCHMARK_H_
@@ -0,0 +1,51 @@
#include "benchmark_nvidia.h"
#include "api/environment/environment_factory.h"
#include "modules/video_coding/codecs/h264/include/h264.h"
#include "fileutils.h"
using namespace webrtc;
NvidiaBenchmark::NvidiaBenchmark()
: Benchmark("NvidiaBenchmark",
"Nvidia benchmark over a range of test cases",
webrtc::test::OutputPath() + "NvidiaBenchmark.txt",
"nvidia_bitstream_output.h264") {}
NvidiaBenchmark::NvidiaBenchmark(std::string name, std::string description)
: Benchmark(name,
description,
webrtc::test::OutputPath() + "NvidiaBenchmark.txt",
"nvidia_bitstream_output.h264") {}
NvidiaBenchmark::NvidiaBenchmark(std::string name,
std::string description,
std::string resultsFileName)
: Benchmark(name, description, resultsFileName, "nvidia_bitstream_output.h264") {}
VideoEncoder* NvidiaBenchmark::GetNewEncoder(webrtc::Environment &env) {
if (!NvidiaVideoEncoderFactory::IsSupported()) {
fprintf(stderr, "NVIDIA is not supported on this system.\n");
return nullptr;
}
if (!_factory) {
_factory = std::make_unique<NvidiaVideoEncoderFactory>();
}
std::map<std::string, std::string> baselineParameters = {
{"profile-level-id", "42e01f"},
{"level-asymmetry-allowed", "1"},
{"packetization-mode", "1"},
};
auto format = SdpVideoFormat("H264", baselineParameters);
auto enc = _factory->Create(env, format);
if (!enc) {
fprintf(stderr, "Failed to create H264 encoder.\n");
return nullptr;
}
_encoder = std::move(enc);
return _encoder.get();
}
@@ -0,0 +1,24 @@
#include "benchmark.h"
#include "nvidia/nvidia_encoder_factory.h"
class NvidiaBenchmark : public Benchmark {
public:
NvidiaBenchmark();
NvidiaBenchmark(std::string name, std::string description);
NvidiaBenchmark(std::string name,
std::string description,
std::string resultsFileName);
~NvidiaBenchmark() {}
bool IsSupported() override {
return webrtc::NvidiaVideoEncoderFactory::IsSupported();
}
protected:
webrtc::VideoEncoder* GetNewEncoder(webrtc::Environment &env) override;
private:
std::unique_ptr<webrtc::VideoEncoder> _encoder;
std::unique_ptr<webrtc::NvidiaVideoEncoderFactory> _factory;
};
@@ -0,0 +1,35 @@
#include "benchmark_openh264.h"
#include "api/environment/environment_factory.h"
#include "modules/video_coding/codecs/h264/include/h264.h"
#include "fileutils.h"
using namespace webrtc;
OpenH264Benchmark::OpenH264Benchmark()
: Benchmark("OpenH264Benchmark",
"OpenH264 benchmark over a range of test cases",
webrtc::test::OutputPath() + "OpenH264Benchmark.txt",
"openh264_bitstream_output.h264") {}
OpenH264Benchmark::OpenH264Benchmark(std::string name, std::string description)
: Benchmark(name,
description,
webrtc::test::OutputPath() + "OpenH264Benchmark.txt",
"openh264_bitstream_output.h264") {}
OpenH264Benchmark::OpenH264Benchmark(std::string name,
std::string description,
std::string resultsFileName)
: Benchmark(name, description, resultsFileName, "openh264_bitstream_output.h264") {}
VideoEncoder* OpenH264Benchmark::GetNewEncoder(webrtc::Environment &env) {
auto enc = CreateH264Encoder(env);
if (!enc) {
fprintf(stderr, "Failed to create H264 encoder.\n");
return nullptr;
}
_encoder = std::move(enc);
return _encoder.get();
}
@@ -0,0 +1,22 @@
#include "benchmark.h"
class OpenH264Benchmark : public Benchmark {
public:
OpenH264Benchmark();
OpenH264Benchmark(std::string name, std::string description);
OpenH264Benchmark(std::string name,
std::string description,
std::string resultsFileName);
~OpenH264Benchmark() {}
bool IsSupported() override {
return true;
}
protected:
webrtc::VideoEncoder* GetNewEncoder(webrtc::Environment &env) override;
private:
std::unique_ptr<webrtc::VideoEncoder> _encoder;
};
@@ -0,0 +1,49 @@
#include "benchmark_vaapi.h"
#include "api/environment/environment_factory.h"
#include "modules/video_coding/codecs/h264/include/h264.h"
#include "fileutils.h"
using namespace webrtc;
VaapiBenchmark::VaapiBenchmark()
: Benchmark("VaapiBenchmark",
"VAAPI benchmark over a range of test cases",
webrtc::test::OutputPath() + "VaapiBenchmark.txt",
"vaapi_bitstream_output.h264") {}
VaapiBenchmark::VaapiBenchmark(std::string name, std::string description)
: Benchmark(name,
description,
webrtc::test::OutputPath() + "VaapiBenchmark.txt",
"vaapi_bitstream_output.h264") {}
VaapiBenchmark::VaapiBenchmark(std::string name,
std::string description,
std::string resultsFileName)
: Benchmark(name, description, resultsFileName, "vaapi_bitstream_output.h264") {}
VideoEncoder* VaapiBenchmark::GetNewEncoder(webrtc::Environment &env) {
if (!VAAPIVideoEncoderFactory::IsSupported()) {
fprintf(stderr, "VAAPI is not supported on this system.\n");
return nullptr;
}
if (!_factory) {
_factory = std::make_unique<VAAPIVideoEncoderFactory>();
}
std::map<std::string, std::string> baselineParameters = {
{"profile-level-id", "4d0032"},
{"level-asymmetry-allowed", "1"},
{"packetization-mode", "1"},
};
auto format = SdpVideoFormat("H264", baselineParameters);
auto enc = _factory->Create(env, format);
if (!enc) {
fprintf(stderr, "Failed to create H264 encoder.\n");
return nullptr;
}
_encoder = std::move(enc);
return _encoder.get();
}
@@ -0,0 +1,24 @@
#include "benchmark.h"
#include "vaapi/vaapi_encoder_factory.h"
class VaapiBenchmark : public Benchmark {
public:
VaapiBenchmark();
VaapiBenchmark(std::string name, std::string description);
VaapiBenchmark(std::string name,
std::string description,
std::string resultsFileName);
~VaapiBenchmark() {}
bool IsSupported() override {
return webrtc::VAAPIVideoEncoderFactory::IsSupported();
}
protected:
webrtc::VideoEncoder* GetNewEncoder(webrtc::Environment &env) override;
private:
std::unique_ptr<webrtc::VideoEncoder> _encoder;
std::unique_ptr<webrtc::VAAPIVideoEncoderFactory> _factory;
};
@@ -0,0 +1,208 @@
/*
* 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 "cpu_linux.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
namespace webrtc {
CpuLinux::CpuLinux()
: m_oldBusyTime(0),
m_oldIdleTime(0),
m_oldBusyTimeMulti(NULL),
m_oldIdleTimeMulti(NULL),
m_idleArray(NULL),
m_busyArray(NULL),
m_resultArray(NULL),
m_numCores(0) {
const int result = GetNumCores();
if (result != -1) {
m_numCores = result;
m_oldBusyTimeMulti = new long long[m_numCores];
memset(m_oldBusyTimeMulti, 0, sizeof(long long) * m_numCores);
m_oldIdleTimeMulti = new long long[m_numCores];
memset(m_oldIdleTimeMulti, 0, sizeof(long long) * m_numCores);
m_idleArray = new long long[m_numCores];
memset(m_idleArray, 0, sizeof(long long) * m_numCores);
m_busyArray = new long long[m_numCores];
memset(m_busyArray, 0, sizeof(long long) * m_numCores);
m_resultArray = new uint32_t[m_numCores];
GetData(m_oldBusyTime, m_oldIdleTime, m_busyArray, m_idleArray);
}
}
CpuLinux::~CpuLinux()
{
delete [] m_oldBusyTimeMulti;
delete [] m_oldIdleTimeMulti;
delete [] m_idleArray;
delete [] m_busyArray;
delete [] m_resultArray;
}
int32_t CpuLinux::CpuUsage()
{
uint32_t dummy = 0;
uint32_t* dummyArray = NULL;
return CpuUsageMultiCore(dummy, dummyArray);
}
int32_t CpuLinux::CpuUsageMultiCore(uint32_t& numCores,
uint32_t*& coreArray)
{
coreArray = m_resultArray;
numCores = m_numCores;
long long busy = 0;
long long idle = 0;
if (GetData(busy, idle, m_busyArray, m_idleArray) != 0)
return -1;
long long deltaBusy = busy - m_oldBusyTime;
long long deltaIdle = idle - m_oldIdleTime;
m_oldBusyTime = busy;
m_oldIdleTime = idle;
int retVal = -1;
if (deltaBusy + deltaIdle == 0)
{
retVal = 0;
}
else
{
retVal = (int)(100 * (deltaBusy) / (deltaBusy + deltaIdle));
}
if (coreArray == NULL)
{
return retVal;
}
for (int32_t i = 0; i < m_numCores; i++)
{
deltaBusy = m_busyArray[i] - m_oldBusyTimeMulti[i];
deltaIdle = m_idleArray[i] - m_oldIdleTimeMulti[i];
m_oldBusyTimeMulti[i] = m_busyArray[i];
m_oldIdleTimeMulti[i] = m_idleArray[i];
if(deltaBusy + deltaIdle == 0)
{
coreArray[i] = 0;
}
else
{
coreArray[i] = (int)(100 * (deltaBusy) / (deltaBusy+deltaIdle));
}
}
return retVal;
}
int CpuLinux::GetData(long long& busy, long long& idle, long long*& busyArray,
long long*& idleArray)
{
FILE* fp = fopen("/proc/stat", "r");
if (!fp)
{
return -1;
}
char line[100];
if (fgets(line, 100, fp) == NULL) {
fclose(fp);
return -1;
}
char firstWord[100];
if (sscanf(line, "%s ", firstWord) != 1) {
fclose(fp);
return -1;
}
if (strncmp(firstWord, "cpu", 3) != 0) {
fclose(fp);
return -1;
}
char sUser[100];
char sNice[100];
char sSystem[100];
char sIdle[100];
if (sscanf(line, "%s %s %s %s %s ",
firstWord, sUser, sNice, sSystem, sIdle) != 5) {
fclose(fp);
return -1;
}
long long luser = atoll(sUser);
long long lnice = atoll(sNice);
long long lsystem = atoll(sSystem);
long long lidle = atoll (sIdle);
busy = luser + lnice + lsystem;
idle = lidle;
for (int32_t i = 0; i < m_numCores; i++)
{
if (fgets(line, 100, fp) == NULL) {
fclose(fp);
return -1;
}
if (sscanf(line, "%s %s %s %s %s ", firstWord, sUser, sNice, sSystem,
sIdle) != 5) {
fclose(fp);
return -1;
}
luser = atoll(sUser);
lnice = atoll(sNice);
lsystem = atoll(sSystem);
lidle = atoll (sIdle);
busyArray[i] = luser + lnice + lsystem;
idleArray[i] = lidle;
}
fclose(fp);
return 0;
}
int CpuLinux::GetNumCores()
{
FILE* fp = fopen("/proc/stat", "r");
if (!fp)
{
return -1;
}
// Skip first line
char line[100];
if (!fgets(line, 100, fp))
{
fclose(fp);
return -1;
}
int numCores = -1;
char firstWord[100];
do
{
numCores++;
if (fgets(line, 100, fp))
{
if (sscanf(line, "%s ", firstWord) != 1) {
firstWord[0] = '\0';
}
} else {
break;
}
} while (strncmp(firstWord, "cpu", 3) == 0);
fclose(fp);
return numCores;
}
CpuWrapper* CpuWrapper::CreateCpu()
{
return new CpuLinux();
}
} // namespace webrtc
@@ -0,0 +1,53 @@
/*
* 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.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_LINUX_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_LINUX_H_
#include "cpu_wrapper.h"
namespace webrtc {
class CpuLinux : public CpuWrapper {
public:
CpuLinux();
virtual ~CpuLinux();
int32_t CpuUsage() override;
int32_t CpuUsage(int8_t* pProcessName, uint32_t length) override { return 0; }
int32_t CpuUsage(uint32_t dwProcessID) override { return 0; }
int32_t CpuUsageMultiCore(uint32_t& numCores, uint32_t*& array) override;
void Reset() override { return; }
void Stop() override { return; }
int GetNumCores() override;
private:
int GetData(long long& busy,
long long& idle,
long long*& busyArray,
long long*& idleArray);
long long m_oldBusyTime;
long long m_oldIdleTime;
long long* m_oldBusyTimeMulti;
long long* m_oldIdleTimeMulti;
long long* m_idleArray;
long long* m_busyArray;
uint32_t* m_resultArray;
uint32_t m_numCores;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_LINUX_H_
@@ -0,0 +1,55 @@
/*
* 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.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_WRAPPER_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_WRAPPER_H_
#include <stdint.h>
namespace webrtc {
class CpuWrapper
{
public:
static CpuWrapper* CreateCpu();
virtual ~CpuWrapper() {}
// Returns the average CPU usage for all processors. The CPU usage can be
// between and including 0 to 100 (%)
virtual int32_t CpuUsage() = 0;
virtual int32_t CpuUsage(int8_t* processName,
uint32_t length) = 0;
virtual int32_t CpuUsage(uint32_t dwProcessID) = 0;
// The CPU usage per core is returned in cpu_usage. The CPU can be between
// and including 0 to 100 (%)
// Note that the pointer passed as cpu_usage is redirected to a local member
// of the CPU wrapper.
// numCores is the number of cores in the cpu_usage array.
// The return value is -1 for failure or 0-100, indicating the average
// CPU usage across all cores.
// Note: on some OSs this class is initialized lazy. This means that it
// might not yet be possible to retrieve any CPU metrics. When this happens
// the return value will be zero (indicating that there is not a failure),
// numCores will be 0 and cpu_usage will be set to NULL (indicating that
// no metrics are available yet). Once the initialization is completed,
// which can take in the order of seconds, CPU metrics can be retrieved.
virtual int32_t CpuUsageMultiCore(uint32_t& numCores,
uint32_t*& cpu_usage) = 0;
virtual void Reset() = 0;
virtual void Stop() = 0;
virtual int GetNumCores() = 0;
protected:
CpuWrapper() {}
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_WRAPPER_H_
@@ -0,0 +1,209 @@
/*
* 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 "fileutils.h"
#ifdef WIN32
#include <direct.h>
#define GET_CURRENT_DIR _getcwd
#else
#include <unistd.h>
#define GET_CURRENT_DIR getcwd
#endif
#include <sys/stat.h> // To check for directory existence.
#ifndef S_ISDIR // Not defined in stat.h on Windows.
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#endif
#include <cstdio>
#include <cstring>
namespace webrtc {
namespace test {
#ifdef WIN32
static const char* kPathDelimiter = "\\";
#else
static const char* kPathDelimiter = "/";
#endif
#ifdef WEBRTC_ANDROID
static const char* kRootDirName = "/sdcard/";
static const char* kResourcesDirName = "resources";
#else
// The file we're looking for to identify the project root dir.
static const char* kProjectRootFileName = "h264_benchmark";
static const char* kOutputDirName = "out";
static const char* kFallbackPath = "./";
static const char* kResourcesDirName = "resources";
#endif
const char* kCannotFindProjectRootDir = "ERROR_CANNOT_FIND_PROJECT_ROOT_DIR";
namespace {
char relative_dir_path[FILENAME_MAX];
bool relative_dir_path_set = false;
}
void SetExecutablePath(const std::string& path) {
std::string working_dir = WorkingDir();
std::string temp_path = path;
// Handle absolute paths; convert them to relative paths to the working dir.
if (path.find(working_dir) != std::string::npos) {
temp_path = path.substr(working_dir.length() + 1);
}
// Trim away the executable name; only store the relative dir path.
temp_path = temp_path.substr(0, temp_path.find_last_of(kPathDelimiter));
strncpy(relative_dir_path, temp_path.c_str(), FILENAME_MAX);
relative_dir_path_set = true;
}
bool FileExists(std::string& file_name) {
struct stat file_info = {0};
return stat(file_name.c_str(), &file_info) == 0;
}
#ifdef WEBRTC_ANDROID
std::string ProjectRootPath() {
return kRootDirName;
}
std::string OutputPath() {
return kRootDirName;
}
std::string WorkingDir() {
return kRootDirName;
}
#else // WEBRTC_ANDROID
std::string ProjectRootPath() {
std::string path = WorkingDir();
if (path == kFallbackPath) {
return kCannotFindProjectRootDir;
}
if (relative_dir_path_set) {
path = path + kPathDelimiter + relative_dir_path;
}
// Check for our file that verifies the root dir.
size_t path_delimiter_index = path.find_last_of(kPathDelimiter);
while (path_delimiter_index != std::string::npos) {
std::string root_filename = path + kPathDelimiter + kProjectRootFileName;
if (FileExists(root_filename)) {
return path + kPathDelimiter;
}
// Move up one directory in the directory tree.
path = path.substr(0, path_delimiter_index);
path_delimiter_index = path.find_last_of(kPathDelimiter);
}
// Reached the root directory.
fprintf(stderr, "Cannot find project root directory!\n");
return kCannotFindProjectRootDir;
}
std::string OutputPath() {
std::string path = ProjectRootPath();
if (path == kCannotFindProjectRootDir) {
return kFallbackPath;
}
path += kOutputDirName;
if (!CreateDirectory(path)) {
return kFallbackPath;
}
return path + kPathDelimiter;
}
std::string WorkingDir() {
char path_buffer[FILENAME_MAX];
if (!GET_CURRENT_DIR(path_buffer, sizeof(path_buffer))) {
fprintf(stderr, "Cannot get current directory!\n");
return kFallbackPath;
} else {
return std::string(path_buffer);
}
}
#endif // !WEBRTC_ANDROID
bool CreateDirectory(std::string directory_name) {
struct stat path_info = {0};
// Check if the path exists already:
if (stat(directory_name.c_str(), &path_info) == 0) {
if (!S_ISDIR(path_info.st_mode)) {
fprintf(stderr, "Path %s exists but is not a directory! Remove this "
"file and re-run to create the directory.\n",
directory_name.c_str());
return false;
}
} else {
#ifdef WIN32
return _mkdir(directory_name.c_str()) == 0;
#else
return mkdir(directory_name.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) == 0;
#endif
}
return true;
}
std::string ResourcePath(std::string name, std::string extension) {
std::string platform = "win";
#ifdef WEBRTC_LINUX
platform = "linux";
#endif // WEBRTC_LINUX
#ifdef WEBRTC_MAC
platform = "mac";
#endif // WEBRTC_MAC
#ifdef WEBRTC_ARCH_64_BITS
std::string architecture = "64";
#else
std::string architecture = "32";
#endif // WEBRTC_ARCH_64_BITS
std::string resources_path = ProjectRootPath() + kResourcesDirName +
kPathDelimiter;
std::string resource_file = resources_path + name + "_" + platform + "_" +
architecture + "." + extension;
if (FileExists(resource_file)) {
return resource_file;
}
// Try without architecture.
resource_file = resources_path + name + "_" + platform + "." + extension;
if (FileExists(resource_file)) {
return resource_file;
}
// Try without platform.
resource_file = resources_path + name + "_" + architecture + "." + extension;
if (FileExists(resource_file)) {
return resource_file;
}
// Fall back on name without architecture or platform.
return resources_path + name + "." + extension;
}
size_t GetFileSize(std::string filename) {
FILE* f = fopen(filename.c_str(), "rb");
size_t size = 0;
if (f != NULL) {
if (fseek(f, 0, SEEK_END) == 0) {
size = ftell(f);
}
fclose(f);
}
return size;
}
} // namespace test
} // namespace webrtc
@@ -0,0 +1,152 @@
/*
* 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 <cstdio>
// File utilities for testing purposes.
//
// The ProjectRootPath() method is a convenient way of getting an absolute
// path to the project source tree root directory. Using this, it is easy to
// refer to test resource files in a portable way.
//
// Notice that even if Windows platforms use backslash as path delimiter, it is
// also supported to use slash, so there's no need for #ifdef checks in test
// code for setting up the paths to the resource files.
//
// Example use:
// Assume we have the following code being used in a test source file:
// const std::string kInputFile = webrtc::test::ProjectRootPath() +
// "test/data/voice_engine/audio_long16.wav";
// // Use the kInputFile for the tests...
//
// Then here's some example outputs for different platforms:
// Linux:
// * Source tree located in /home/user/webrtc/trunk
// * Test project located in /home/user/webrtc/trunk/src/testproject
// * Test binary compiled as:
// /home/user/webrtc/trunk/out/Debug/testproject_unittests
// Then ProjectRootPath() will return /home/user/webrtc/trunk/ no matter if
// the test binary is executed from standing in either of:
// /home/user/webrtc/trunk
// or
// /home/user/webrtc/trunk/out/Debug
// (or any other directory below the trunk for that matter).
//
// Windows:
// * Source tree located in C:\Users\user\webrtc\trunk
// * Test project located in C:\Users\user\webrtc\trunk\src\testproject
// * Test binary compiled as:
// C:\Users\user\webrtc\trunk\src\testproject\Debug\testproject_unittests.exe
// Then ProjectRootPath() will return C:\Users\user\webrtc\trunk\ when the
// test binary is executed from inside Visual Studio.
// It will also return the same path if the test is executed from a command
// prompt standing in C:\Users\user\webrtc\trunk\src\testproject\Debug
//
// Mac:
// * Source tree located in /Users/user/webrtc/trunk
// * Test project located in /Users/user/webrtc/trunk/src/testproject
// * Test binary compiled as:
// /Users/user/webrtc/trunk/xcodebuild/Debug/testproject_unittests
// Then ProjectRootPath() will return /Users/user/webrtc/trunk/ no matter if
// the test binary is executed from standing in either of:
// /Users/user/webrtc/trunk
// or
// /Users/user/webrtc/trunk/out/Debug
// (or any other directory below the trunk for that matter).
#ifndef WEBRTC_TEST_TESTSUPPORT_FILEUTILS_H_
#define WEBRTC_TEST_TESTSUPPORT_FILEUTILS_H_
#include <string>
namespace webrtc {
namespace test {
// This is the "directory" returned if the ProjectPath() function fails
// to find the project root.
extern const char* kCannotFindProjectRootDir;
// Finds the root dir of the project, to be able to set correct paths to
// resource files used by tests.
// The implementation is simple: it just looks for the file defined by
// kProjectRootFileName, starting in the current directory (the working
// directory) and then steps upward until it is found (or it is at the root of
// the file system).
// If the current working directory is above the project root dir, it will not
// be found.
//
// If symbolic links occur in the path they will be resolved and the actual
// directory will be returned.
//
// Returns the absolute path to the project root dir (usually the trunk dir)
// WITH a trailing path delimiter.
// If the project root is not found, the string specified by
// kCannotFindProjectRootDir is returned.
std::string ProjectRootPath();
// Creates and returns the absolute path to the output directory where log files
// and other test artifacts should be put. The output directory is generally a
// directory named "out" at the top-level of the project, i.e. a subfolder to
// the path returned by ProjectRootPath(). The exception is Android where we use
// /sdcard/ instead.
//
// Details described for ProjectRootPath() apply here too.
//
// Returns the path WITH a trailing path delimiter. If the project root is not
// found, the current working directory ("./") is returned as a fallback.
std::string OutputPath();
// Returns a path to a resource file for the currently executing platform.
// Adapts to what filenames are currently present in the
// [project-root]/resources/ dir.
// Returns an absolute path according to this priority list (the directory
// part of the path is left out for readability):
// 1. [name]_[platform]_[architecture].[extension]
// 2. [name]_[platform].[extension]
// 3. [name]_[architecture].[extension]
// 4. [name].[extension]
// Where
// * platform is either of "win", "mac" or "linux".
// * architecture is either of "32" or "64".
//
// Arguments:
// name - Name of the resource file. If a plain filename (no directory path)
// is supplied, the file is assumed to be located in resources/
// If a directory path is prepended to the filename, a subdirectory
// hierarchy reflecting that path is assumed to be present.
// extension - File extension, without the dot, i.e. "bmp" or "yuv".
std::string ResourcePath(std::string name, std::string extension);
// Gets the current working directory for the executing program.
// Returns "./" if for some reason it is not possible to find the working
// directory.
std::string WorkingDir();
// Creates a directory if it not already exists.
// Returns true if successful. Will print an error message to stderr and return
// false if a file with the same name already exists.
bool CreateDirectory(std::string directory_name);
// File size of the supplied file in bytes. Will return 0 if the file is
// empty or if the file does not exist/is readable.
size_t GetFileSize(std::string filename);
// Sets the executable path, i.e. the path to the executable that is being used
// when launching it. This is usually the path relative to the working directory
// but can also be an absolute path. The intention with this function is to pass
// the argv[0] being sent into the main function to make it possible for
// fileutils.h to find the correct project paths even when the working directory
// is outside the project tree (which happens in some cases).
void SetExecutablePath(const std::string& path_to_executable);
} // namespace test
} // namespace webrtc
#endif // WEBRTC_TEST_TESTSUPPORT_FILEUTILS_H_
@@ -0,0 +1,20 @@
#include "benchmark_nvidia.h"
#include "benchmark_openh264.h"
#include "benchmark_vaapi.h"
#include "stdio.h"
int main(int argc, char** argv) {
std::vector<Benchmark*> benchmarks;
benchmarks.push_back(new NvidiaBenchmark());
//benchmarks.push_back(new VaapiBenchmark());
benchmarks.push_back(new OpenH264Benchmark());
for (auto benchmark : benchmarks) {
if (benchmark->IsSupported()) {
benchmark->Perform();
}
}
return 0;
}
@@ -0,0 +1,432 @@
/*
* 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 "video_source.h"
#include <stdio.h>
#include "fileutils.h"
#define ASSERT_TRUE(condition) \
do { \
if (!(condition)) { \
fprintf(stderr, "Assertion failed: %s\n", #condition); \
abort(); \
} \
} while (0)
VideoSource::VideoSource()
:
_fileName(webrtc::test::ProjectRootPath() + "resources/foreman_cif.yuv"),
_width(352),
_height(288),
_type(webrtc::VideoType::kI420),
_frameRate(30)
{
}
VideoSource::VideoSource(std::string fileName, VideoSize size,
int frameRate /*= 30*/, webrtc::VideoType type /*= webrtc::kI420*/)
:
_fileName(fileName),
_type(type),
_frameRate(frameRate)
{
assert(size != kUndefined && size != kNumberOfVideoSizes);
assert(type != webrtc::VideoType::kUnknown);
assert(frameRate > 0);
if (GetWidthHeight(size, _width, _height) != 0) {
assert(false);
}
}
VideoSource::VideoSource(std::string fileName, int width, int height,
int frameRate /*= 30*/, webrtc::VideoType type /*= webrtc::kI420*/)
:
_fileName(fileName),
_width(width),
_height(height),
_type(type),
_frameRate(frameRate)
{
assert(width > 0);
assert(height > 0);
assert(type != webrtc::VideoType::kUnknown);
assert(frameRate > 0);
}
VideoSize
VideoSource::GetSize() const
{
return GetSize(_width, _height);
}
VideoSize
VideoSource::GetSize(uint16_t width, uint16_t height)
{
if(width == 128 && height == 96)
{
return kSQCIF;
}else if(width == 160 && height == 120)
{
return kQQVGA;
}else if(width == 176 && height == 144)
{
return kQCIF;
}else if(width == 320 && height == 240)
{
return kQVGA;
}else if(width == 352 && height == 288)
{
return kCIF;
}else if(width == 640 && height == 480)
{
return kVGA;
}else if(width == 720 && height == 480)
{
return kNTSC;
}else if(width == 704 && height == 576)
{
return k4CIF;
}else if(width == 800 && height == 600)
{
return kSVGA;
}else if(width == 960 && height == 720)
{
return kHD;
}else if(width == 1024 && height == 768)
{
return kXGA;
}else if(width == 1440 && height == 1080)
{
return kFullHD;
}else if(width == 400 && height == 240)
{
return kWQVGA;
}else if(width == 800 && height == 480)
{
return kWVGA;
}else if(width == 1280 && height == 720)
{
return kWHD;
}else if(width == 1920 && height == 1080)
{
return kWFullHD;
}
return kUndefined;
}
unsigned int
VideoSource::GetFrameLength() const
{
return webrtc::CalcBufferSize(_type, _width, _height);
}
const char*
VideoSource::GetMySizeString() const
{
return VideoSource::GetSizeString(GetSize());
}
const char*
VideoSource::GetSizeString(VideoSize size)
{
switch (size)
{
case kSQCIF:
return "SQCIF";
case kQQVGA:
return "QQVGA";
case kQCIF:
return "QCIF";
case kQVGA:
return "QVGA";
case kCIF:
return "CIF";
case kVGA:
return "VGA";
case kNTSC:
return "NTSC";
case k4CIF:
return "4CIF";
case kSVGA:
return "SVGA";
case kHD:
return "HD";
case kXGA:
return "XGA";
case kFullHD:
return "Full_HD";
case kWQVGA:
return "WQVGA";
case kWHD:
return "WHD";
case kWFullHD:
return "WFull_HD";
default:
return "Undefined";
}
}
std::string
VideoSource::GetFilePath() const
{
size_t slashPos = _fileName.find_last_of("/\\");
if (slashPos == std::string::npos)
{
return ".";
}
return _fileName.substr(0, slashPos);
}
std::string
VideoSource::GetName() const
{
// Remove path.
size_t slashPos = _fileName.find_last_of("/\\");
if (slashPos == std::string::npos)
{
slashPos = 0;
}
else
{
slashPos++;
}
// Remove extension and underscored suffix if it exists.
return _fileName.substr(slashPos, std::min(_fileName.find_last_of("_"),
_fileName.find_last_of(".")) - slashPos);
}
void
VideoSource::Convert(const VideoSource &target, bool force /* = false */) const
{
// Ensure target rate is less than or equal to source
// (i.e. we are only temporally downsampling).
ASSERT_TRUE(target.GetFrameRate() <= _frameRate);
// Only supports YUV420 currently.
ASSERT_TRUE(_type == webrtc::VideoType::kI420 && target.GetType() == webrtc::VideoType::kI420);
if (!force && (FileExists(target.GetFileName().c_str()) ||
(target.GetWidth() == _width && target.GetHeight() == _height && target.GetFrameRate() == _frameRate)))
{
// Assume that the filename uniquely defines the content.
// If the file already exists, it is the correct file.
return;
}
FILE *inFile = NULL;
FILE *outFile = NULL;
inFile = fopen(_fileName.c_str(), "rb");
ASSERT_TRUE(inFile != NULL);
outFile = fopen(target.GetFileName().c_str(), "wb");
ASSERT_TRUE(outFile != NULL);
FrameDropper fd;
fd.SetFrameRate(target.GetFrameRate(), _frameRate);
const size_t lengthOutFrame = webrtc::CalcBufferSize(target.GetType(),
target.GetWidth(), target.GetHeight());
ASSERT_TRUE(lengthOutFrame > 0);
unsigned char *outFrame = new unsigned char[lengthOutFrame];
const size_t lengthInFrame = webrtc::CalcBufferSize(_type, _width, _height);
ASSERT_TRUE(lengthInFrame > 0);
unsigned char *inFrame = new unsigned char[lengthInFrame];
while (fread(inFrame, 1, lengthInFrame, inFile) == lengthInFrame)
{
if (!fd.DropFrame())
{
ASSERT_TRUE(target.GetWidth() == _width &&
target.GetHeight() == _height);
// Add video interpolator here!
if (fwrite(outFrame, 1, lengthOutFrame,
outFile) != lengthOutFrame) {
return;
}
}
}
delete inFrame;
delete outFrame;
fclose(inFile);
fclose(outFile);
}
bool VideoSource::FileExists(const char* fileName)
{
FILE* fp = NULL;
fp = fopen(fileName, "rb");
if(fp != NULL)
{
fclose(fp);
return true;
}
return false;
}
int
VideoSource::GetWidthHeight( VideoSize size, int & width, int& height)
{
switch(size)
{
case kSQCIF:
width = 128;
height = 96;
return 0;
case kQQVGA:
width = 160;
height = 120;
return 0;
case kQCIF:
width = 176;
height = 144;
return 0;
case kCGA:
width = 320;
height = 200;
return 0;
case kQVGA:
width = 320;
height = 240;
return 0;
case kSIF:
width = 352;
height = 240;
return 0;
case kWQVGA:
width = 400;
height = 240;
return 0;
case kCIF:
width = 352;
height = 288;
return 0;
case kW288p:
width = 512;
height = 288;
return 0;
case k448p:
width = 576;
height = 448;
return 0;
case kVGA:
width = 640;
height = 480;
return 0;
case k432p:
width = 720;
height = 432;
return 0;
case kW432p:
width = 768;
height = 432;
return 0;
case k4SIF:
width = 704;
height = 480;
return 0;
case kW448p:
width = 768;
height = 448;
return 0;
case kNTSC:
width = 720;
height = 480;
return 0;
case kFW448p:
width = 800;
height = 448;
return 0;
case kWVGA:
width = 800;
height = 480;
return 0;
case k4CIF:
width = 704;
height = 576;
return 0;
case kSVGA:
width = 800;
height = 600;
return 0;
case kW544p:
width = 960;
height = 544;
return 0;
case kW576p:
width = 1024;
height = 576;
return 0;
case kHD:
width = 960;
height = 720;
return 0;
case kXGA:
width = 1024;
height = 768;
return 0;
case kFullHD:
width = 1440;
height = 1080;
return 0;
case kWHD:
width = 1280;
height = 720;
return 0;
case kWFullHD:
width = 1920;
height = 1080;
return 0;
default:
return -1;
}
}
FrameDropper::FrameDropper()
:
_dropsBetweenRenders(0),
_frameCounter(0)
{
}
bool
FrameDropper::DropFrame()
{
_frameCounter++;
if (_frameCounter > _dropsBetweenRenders)
{
_frameCounter = 0;
return false;
}
return true;
}
unsigned int
FrameDropper::DropsBetweenRenders()
{
return _dropsBetweenRenders;
}
void
FrameDropper::SetFrameRate(double frameRate, double maxFrameRate)
{
if (frameRate >= 1.0)
{
_dropsBetweenRenders = static_cast<unsigned int>(maxFrameRate / frameRate + 0.5) - 1;
}
else
{
_dropsBetweenRenders = 0;
}
}
@@ -0,0 +1,109 @@
/*
* 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.
*/
#ifndef WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_FRAMEWORK_VIDEO_SOURCE_H_
#define WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_FRAMEWORK_VIDEO_SOURCE_H_
#include <string>
#include "common_video/libyuv/include/webrtc_libyuv.h"
enum VideoSize
{
kUndefined,
kSQCIF, // 128*96 = 12 288
kQQVGA, // 160*120 = 19 200
kQCIF, // 176*144 = 25 344
kCGA, // 320*200 = 64 000
kQVGA, // 320*240 = 76 800
kSIF, // 352*240 = 84 480
kWQVGA, // 400*240 = 96 000
kCIF, // 352*288 = 101 376
kW288p, // 512*288 = 147 456 (WCIF)
k448p, // 576*448 = 281 088
kVGA, // 640*480 = 307 200
k432p, // 720*432 = 311 040
kW432p, // 768*432 = 331 776
k4SIF, // 704*480 = 337 920
kW448p, // 768*448 = 344 064
kNTSC, // 720*480 = 345 600
kFW448p, // 800*448 = 358 400
kWVGA, // 800*480 = 384 000
k4CIF, // 704576 = 405 504
kSVGA, // 800*600 = 480 000
kW544p, // 960*544 = 522 240
kW576p, // 1024*576 = 589 824 (W4CIF)
kHD, // 960*720 = 691 200
kXGA, // 1024*768 = 786 432
kWHD, // 1280*720 = 921 600
kFullHD, // 1440*1080 = 1 555 200
kWFullHD, // 1920*1080 = 2 073 600
kNumberOfVideoSizes
};
class VideoSource
{
public:
VideoSource();
VideoSource(std::string fileName, VideoSize size, int frameRate = 30,
webrtc::VideoType type = webrtc::VideoType::kI420);
VideoSource(std::string fileName, int width, int height, int frameRate = 30,
webrtc::VideoType type = webrtc::VideoType::kI420);
std::string GetFileName() const { return _fileName; }
int GetWidth() const { return _width; }
int GetHeight() const { return _height; }
webrtc::VideoType GetType() const { return _type; }
int GetFrameRate() const { return _frameRate; }
// Returns the file path without a trailing slash.
std::string GetFilePath() const;
// Returns the filename with the path (including the leading slash) removed.
std::string GetName() const;
VideoSize GetSize() const;
static VideoSize GetSize(uint16_t width, uint16_t height);
unsigned int GetFrameLength() const;
// Returns a human-readable size string.
static const char* GetSizeString(VideoSize size);
const char* GetMySizeString() const;
// Opens the video source, converting and writing to the specified target.
// If force is true, the conversion will be done even if the target file
// already exists.
void Convert(const VideoSource& target, bool force = false) const;
static bool FileExists(const char* fileName);
private:
static int GetWidthHeight( VideoSize size, int& width, int& height);
std::string _fileName;
int _width;
int _height;
webrtc::VideoType _type;
int _frameRate;
};
class FrameDropper
{
public:
FrameDropper();
bool DropFrame();
unsigned int DropsBetweenRenders();
void SetFrameRate(double frameRate, double maxFrameRate);
private:
unsigned int _dropsBetweenRenders;
unsigned int _frameCounter;
};
#endif // WEBRTC_MODULES_VIDEO_CODING_CODECS_TEST_FRAMEWORK_VIDEO_SOURCE_H_