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:
@@ -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_
|
||||
+51
@@ -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();
|
||||
}
|
||||
+24
@@ -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;
|
||||
};
|
||||
+35
@@ -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();
|
||||
}
|
||||
+22
@@ -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;
|
||||
};
|
||||
+49
@@ -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, // 704�576 = 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_
|
||||
|
||||
Reference in New Issue
Block a user