From 48b8dfdb8c99d4ddf3d12f83d9f86ffeacf9add7 Mon Sep 17 00:00:00 2001 From: Harsha Raghu Date: Tue, 22 Dec 2020 15:52:33 +0530 Subject: [PATCH 1/2] PVRffmpeg New class PVRffmpeg New class for handling PVR <-> FFmpeg interaction. --- .../PhoneVR/PVRffmpegBackgroundProcess.cpp | 331 ++++++++++++++++++ .../PhoneVR/PVRffmpegBackgroundProcess.h | 63 ++++ 2 files changed, 394 insertions(+) create mode 100644 code/windows/PhoneVR/PhoneVR/PVRffmpegBackgroundProcess.cpp create mode 100644 code/windows/PhoneVR/PhoneVR/PVRffmpegBackgroundProcess.h diff --git a/code/windows/PhoneVR/PhoneVR/PVRffmpegBackgroundProcess.cpp b/code/windows/PhoneVR/PhoneVR/PVRffmpegBackgroundProcess.cpp new file mode 100644 index 00000000..52c75f64 --- /dev/null +++ b/code/windows/PhoneVR/PhoneVR/PVRffmpegBackgroundProcess.cpp @@ -0,0 +1,331 @@ +#include "PVRffmpegBackgroundProcess.h" +/* +int PVRffmpegBackgroundProcess::initffmpeg() +{ + return 0; +} + +int PVRffmpegBackgroundProcess::Resample() +{ + // Source and Target WxH will be same in PVR + struct SwsContext* scaler = sws_getContext( + width, height, AV_PIX_FMT_YUYV422, + width, height, AV_PIX_FMT_YUV422P, + SWS_BICUBIC, NULL, NULL, NULL + ); + + AVFrame* scaled_frame = av_frame_alloc(); + + scaled_frame->format = AV_PIX_FMT_YUV422P; + scaled_frame->width = width; + scaled_frame->height = height; + + av_image_alloc( scaled_frame->data, scaled_frame->linesize, scaled_frame->width, scaled_frame->height, + (AVPixelFormat) scaled_frame->format, 16); + + /*sws_scale(scaler, + (const uint8_t * const*)source_data, source_linesize, + 0, source_height, + scaled_frame->data, scaled_frame->linesize); + + av_frame_free(&scaled_frame); + return 0; +} + +int PVRffmpegBackgroundProcess::Encode(AVFrame* scaled_frame) +{ + avformat_network_init(); + avcodec_register_all(); + + AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264); + + AVCodecContext* encoder = avcodec_alloc_context3(codec); + + encoder->bit_rate = 10 * 1000 * 10000; + encoder->width = 1920; + encoder->height = 1080; + encoder->time_base = AVRational { 1, 60 }; + encoder->gop_size = 30; + encoder->max_b_frames = 1; + encoder->pix_fmt = AV_PIX_FMT_YUV422P; + +// av_opt_set(encoder->av_codec_context->priv_data, "preset", "ultrafast", 0); + + avcodec_open2(encoder, codec, NULL); + + AVFrame* raw_frame = scaled_frame; + + raw_frame->pts = pts++; + avcodec_send_frame(encoder, raw_frame); + + av_freep(&raw_frame->data[0]); + av_frame_free(&raw_frame); + + return 0; +} + +int PVRffmpegBackgroundProcess::MuxAV(AVCodecContext* encoder) +{ + AVFormatContext* muxer = avformat_alloc_context(); + + muxer->oformat = av_guess_format("matroska", "rtp://127.0.0.1:40000", NULL); + + AVStream* video_track = avformat_new_stream(muxer, NULL); + AVStream* audio_track = avformat_new_stream(muxer, NULL); + muxer->oformat->video_codec = AV_CODEC_ID_H264; + muxer->oformat->audio_codec = AV_CODEC_ID_OPUS; + + avcodec_parameters_from_context(video_track->codecpar, encoder); + video_track->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + + video_track->time_base = AVRational { 1, 60 }; + video_track->avg_frame_rate = AVRational { 60, 1 }; + + AVDictionary *options = NULL; + av_dict_set(&options, "live", "1", 0); + avformat_write_header(muxer, &options); + return 0; +} + +int PVRffmpegBackgroundProcess::startStream() +{ + return 0; +} +*/ + +int PVRffmpegBackgroundProcess::initFFMPEGChildProcess() +{ + //int main(int argc, char *argv[]) { + SECURITY_ATTRIBUTES sa; + printf("\n->Start of parent execution.\n"); + // Set the bInheritHandle flag so pipe handles are inherited. + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + + // Create a pipe for the child process's STDERR. + if (!CreatePipe(&g_hChildStd_ERR_Rd, &g_hChildStd_ERR_Wr, &sa, 0)) { + exit(1); + } + // Ensure the read handle to the pipe for STDERR is not inherited. + if (!SetHandleInformation(g_hChildStd_ERR_Rd, HANDLE_FLAG_INHERIT, 0)) { + exit(1); + } + + // Create a pipe for the child process's STDOUT. + if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &sa, 0)) { + exit(1); + } + // Ensure the read handle to the pipe for STDOUT is not inherited + if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) { + exit(1); + } + + if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &sa, 16358400)) { + exit(1); + } + if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) { + exit(1); + } + return 0; +} + +void PVRffmpegBackgroundProcess::startSTDOutPipeReader() +{ + PVR_DB("PVRffmpegBackgroundProcess::startSTDOutPipeReader() Starting ..."); + std::thread* iCProcessReader = new std::thread([=] { + ReadFromSTDOutPipe(piProcInfo); + }); +} + +void PVRffmpegBackgroundProcess::startSTDErrPipeReader() +{ + PVR_DB("PVRffmpegBackgroundProcess::startSTDErrPipeReader() Starting ..."); + std::thread* iCProcessReader = new std::thread([=] { + ReadFromSTDErrPipe(piProcInfo); + }); +} + +int PVRffmpegBackgroundProcess::CreateFFMPEGChildProcess() +{ + if (bProcessStarted) + return 1; + // Create the child process. + piProcInfo = CreateChildProcess(); + bProcessStarted = true; + + // Read from pipe that is the standard output for child process. + //printf("\n->Contents of child process STDOUT:\n\n", argv[1]); + + PVR_DB("PVRffmpegBackgroundProcess::CreateFFMPEGChildProcess() Created child Process"); + + // The remaining open handles are cleaned up when this process terminates. + // To avoid resource leaks in a larger application, + // close handles explicitly. + return 0; + //} +} + +bool PVRffmpegBackgroundProcess::isChildProcessRunning() +{ + return bProcessStarted; +} + + +// Create a child process that uses the previously created pipes +// for STDERR and STDOUT. +PROCESS_INFORMATION PVRffmpegBackgroundProcess::CreateChildProcess() +{ + std::wstring szPath = L"C:\\Program Files\\ffmpeg\\bin\\ffmpeg.exe"; + std::wstring szCmdline = L"ffmpeg -re -f rawvideo -i pipe: -vcodec H264 -an -f rtp rtp://127.0.0.1:40000"; + + PROCESS_INFORMATION piProcInfo; + STARTUPINFO siStartInfo; + bool bSuccess = FALSE; + + // Set up members of the PROCESS_INFORMATION structure. + ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); + + // Set up members of the STARTUPINFO structure. + // This structure specifies the STDERR and STDOUT handles for redirection. + ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.hStdError = g_hChildStd_ERR_Wr; + siStartInfo.hStdOutput = g_hChildStd_OUT_Wr; + siStartInfo.hStdInput = g_hChildStd_IN_Rd; + siStartInfo.dwFlags |= STARTF_USESTDHANDLES; + + // Create the child process. + bSuccess = CreateProcess(szPath.c_str(), + L"ffmpeg -re -f rawvideo -video_size 1704x960 -r 60 -i pipe:0 -vcodec h264 -an -f rtp rtp://127.0.0.1:40000", // command line + NULL, // process security attributes + NULL, // primary thread security attributes + TRUE, // handles are inherited + 0, // creation flags + NULL, // use parent's environment + NULL, // use parent's current directory + &siStartInfo, // STARTUPINFO pointer + &piProcInfo); // receives PROCESS_INFORMATION + CloseHandle(g_hChildStd_ERR_Wr); + CloseHandle(g_hChildStd_OUT_Wr); + CloseHandle(g_hChildStd_IN_Rd); + // If an error occurs, exit the application. + if (!bSuccess) { + PVR_DB("PVRffmpegBackgroundProcess::CreateChildProcess(): Could not create PVRffmpeg Child Process... Exiting... Error: " + GetLastErrorAsString()); + exit(1); + } + return piProcInfo; +} + +//Returns the last Win32 error, in string format. Returns an empty string if there is no error. +std::string PVRffmpegBackgroundProcess::GetLastErrorAsString() +{ + //Get the error message, if any. + DWORD errorMessageID = ::GetLastError(); + if (errorMessageID == 0) + return std::string(); //No error message has been recorded + + LPSTR messageBuffer = nullptr; + size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); + + std::string message(messageBuffer, size); + + //Free the buffer. + LocalFree(messageBuffer); + + return (std::to_string(errorMessageID) + ": " + message); +} + +// Read output from the child process's pipe for STDOUT +// and write to the parent process's pipe for STDOUT. +// Stop when there is no more data. +void PVRffmpegBackgroundProcess::ReadFromSTDOutPipe(PROCESS_INFORMATION piProcInfo) +{ + DWORD dwRead; + CHAR chBuf[BUFSIZE]; + bool bSuccess = FALSE; + std::string out = "", err = ""; + while (1) + { + for (;;) + { + bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL); + if (!bSuccess || dwRead == 0) break; + + std::string s(chBuf, dwRead); + + PVR_DB("stdout: " + s); + out += s; + } + //std::cout << "stdout:" << out << std::endl; + //std::cout << "stderr:" << err << std::endl; + //PVR_DB("stdout: " + out); + //PVR_DB("stderr: " + err); + } +} + +void PVRffmpegBackgroundProcess::ReadFromSTDErrPipe(PROCESS_INFORMATION piProcInfo) +{ + DWORD dwRead; + CHAR chBuf[64]; + bool bSuccess = FALSE; + std::string out = "";//, err = ""; + while (1) + { + for (;;) + { + bSuccess = ReadFile(g_hChildStd_ERR_Rd, chBuf, 64, &dwRead, NULL); + if (!bSuccess || dwRead == 0) break; + + std::string s(chBuf, dwRead); + + PVR_DB(s + " -- Child:stderr" ); + //err += s; + + } + //std::cout << "stdout:" << out << std::endl; + //std::cout << "stderr:" << err << std::endl; + //PVR_DB("stdout: " + out); + //PVR_DB("stderr: " + err); + } +} + +int PVRffmpegBackgroundProcess::WriteToPipe(void* data, int datalen) +{ + DWORD dwWritten; + bool bSuccess = FALSE; + bSuccess = WriteFile(g_hChildStd_IN_Wr, data, datalen, &dwWritten, NULL); + + return bSuccess ? dwWritten : -1; +} + +float PVRffmpegBackgroundProcess::WriteToPipe(x264_picture_t* pic, int dataPerStride /*height, should be <= 65,535 bytes */) +{ + DWORD dwWritten; + bool bSuccess = FALSE; + + int totalData = dataPerStride * (pic->img.i_stride[0] + pic->img.i_stride[1] + pic->img.i_stride[2]); + int dataWritten = 0; + for (int i = 0; i < pic->img.i_plane; i++) + { + for (int j = 0; j < pic->img.i_stride[i]; j++) + { + bSuccess = WriteFile(g_hChildStd_IN_Wr, pic->img.plane[i] + (j*dataPerStride), dataPerStride, &dwWritten, NULL); + if (bSuccess) + { + dataWritten += (int)dwWritten; + } + else + { + PVR_DB("PVRffmpegBackgroundProcess::WriteToPipe() Writing .. Plane : " + std::to_string(i) + + ", Stride: " + std::to_string(j) + ", DataperString: " + + std::to_string(dataPerStride) + ", Retrun: " + + std::to_string(bSuccess) + ", Written: " + + std::to_string(dwWritten) + ", Last Error: " + GetLastErrorAsString()); + } + } + } + + return ((float)dataWritten/totalData); +} diff --git a/code/windows/PhoneVR/PhoneVR/PVRffmpegBackgroundProcess.h b/code/windows/PhoneVR/PhoneVR/PVRffmpegBackgroundProcess.h new file mode 100644 index 00000000..a2a491d4 --- /dev/null +++ b/code/windows/PhoneVR/PhoneVR/PVRffmpegBackgroundProcess.h @@ -0,0 +1,63 @@ + +/*#include "libswscale/swscale.h" +#include "libavcodec/avcodec.h" +#include "libavformat/avformat.h" + +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" +*/ +#include +#include +#include +#include +#include + +extern "C" +{ +#include "x264.h" +} + +#include +#pragma warning( disable : 4800 ) // stupid warning about bool +#define BUFSIZE 256 + +class PVRffmpegBackgroundProcess +{ + int width = 1920, height = 1080; + int64_t pts = 0; + PROCESS_INFORMATION piProcInfo; + + HANDLE g_hChildStd_OUT_Rd = NULL; + HANDLE g_hChildStd_OUT_Wr = NULL; + HANDLE g_hChildStd_ERR_Rd = NULL; + HANDLE g_hChildStd_ERR_Wr = NULL; + HANDLE g_hChildStd_IN_Rd = NULL; + HANDLE g_hChildStd_IN_Wr = NULL; + + bool bProcessStarted = false; + + PROCESS_INFORMATION CreateChildProcess(void); +public: + PVRffmpegBackgroundProcess() {} + ~PVRffmpegBackgroundProcess() {} + /*int initffmpeg(); + int Resample(); + int Encode(AVFrame* scaled_frame); + int MuxAV(AVCodecContext* encoder); + int Encode(); + int MuxAV(); + int startStream();*/ + + int initFFMPEGChildProcess(); + void startSTDOutPipeReader(); + void startSTDErrPipeReader(); + int CreateFFMPEGChildProcess(); + + bool isChildProcessRunning(); + std::string GetLastErrorAsString(); + + void ReadFromSTDOutPipe(PROCESS_INFORMATION piProcInfo); + void ReadFromSTDErrPipe(PROCESS_INFORMATION piProcInfo); + int WriteToPipe(void * data, int datalen); + float WriteToPipe(x264_picture_t * pic, int dataPerPlane); +}; \ No newline at end of file From 4936ad42f2085e46d9a1018336f3427991e535bd Mon Sep 17 00:00:00 2001 From: Harsha Raghu Date: Sat, 26 Dec 2020 20:39:08 +0530 Subject: [PATCH 2/2] Intermediate Commit That code is not yet complete --- code/common/src/PVRGlobals.cpp | 4 + code/common/src/PVRGlobals.h | 4 +- .../PhoneVR/AMP Crashes WorkArround.txt | 5 + code/windows/PhoneVR/PhoneVR.sln | 6 +- code/windows/PhoneVR/PhoneVR/PVRGraphics.cpp | 37 +- code/windows/PhoneVR/PhoneVR/PVRGraphics.h | 32 ++ code/windows/PhoneVR/PhoneVR/PVRSockets.cpp | 429 +++++++++++------- code/windows/PhoneVR/PhoneVR/PVRSockets.h | 4 +- code/windows/PhoneVR/PhoneVR/PVRffmpeg.cpp | 350 ++++++++++++++ code/windows/PhoneVR/PhoneVR/PVRffmpeg.h | 68 +++ code/windows/PhoneVR/PhoneVR/PhoneVR.vcxproj | 28 +- .../PhoneVR/PhoneVR/PhoneVR.vcxproj.filters | 12 + code/windows/PhoneVR/PhoneVR/driver.cpp | 93 +++- code/windows/PhoneVR/PhoneVR/post_build.cmd | 3 + code/windows/PhoneVR/post_build_debug.cmd | 19 + code/windows/PhoneVR/post_build_release.cmd | 19 + 16 files changed, 886 insertions(+), 227 deletions(-) create mode 100644 code/windows/PhoneVR/AMP Crashes WorkArround.txt create mode 100644 code/windows/PhoneVR/PhoneVR/PVRffmpeg.cpp create mode 100644 code/windows/PhoneVR/PhoneVR/PVRffmpeg.h create mode 100644 code/windows/PhoneVR/PhoneVR/post_build.cmd create mode 100644 code/windows/PhoneVR/post_build_debug.cmd create mode 100644 code/windows/PhoneVR/post_build_release.cmd diff --git a/code/common/src/PVRGlobals.cpp b/code/common/src/PVRGlobals.cpp index d4f3141f..00f12331 100644 --- a/code/common/src/PVRGlobals.cpp +++ b/code/common/src/PVRGlobals.cpp @@ -47,6 +47,10 @@ void pvrdebug(string msg) GetLocalTime(&t); ofstream of(std::wstring(_GetExePath() + logFileDebug).c_str(), ios_base::app); auto ms = system_clock::now().time_since_epoch() / 1ms; + + //std::replace(msg.begin(), msg.end(), '\n', ' '); + std::replace(msg.begin(), msg.end(), '\r', ' '); + string elapsed = (ms - pvrdebug_oldMs < 1000 ? to_string(ms - pvrdebug_oldMs) : "max"); of << t.wMinute << ":" << setfill('0') << setw(2) << t.wSecond << " " << setfill('0') << setw(3) << elapsed << " " << msg << endl; diff --git a/code/common/src/PVRGlobals.h b/code/common/src/PVRGlobals.h index 730956ee..4ed88043 100644 --- a/code/common/src/PVRGlobals.h +++ b/code/common/src/PVRGlobals.h @@ -67,13 +67,13 @@ void pvrInfo(T i) { void pvrdebugClear(); // PVR_DB only to Debug Log file, PVR_DB_I both to Log file and Info file -#if defined _DEBUG +#if defined PVR_DEBUG #define PVR_DB(msg) pvrdebug(msg) #else #define PVR_DB(msg) #endif -#if defined _DEBUG +#if defined PVR_DEBUG #define PVR_DB_I(msg) {pvrdebug(msg);pvrInfo(msg);} #else #define PVR_DB_I(msg) pvrInfo(msg); diff --git a/code/windows/PhoneVR/AMP Crashes WorkArround.txt b/code/windows/PhoneVR/AMP Crashes WorkArround.txt new file mode 100644 index 00000000..cadd434d --- /dev/null +++ b/code/windows/PhoneVR/AMP Crashes WorkArround.txt @@ -0,0 +1,5 @@ +in Debug Build, + +Replace _DEBUG preProcessor with NDEBUG & PVR_DEBUG + +Code Generation RuntimeLibrary -> MultiThreaded DLL (/MD) (initially was /MDd) \ No newline at end of file diff --git a/code/windows/PhoneVR/PhoneVR.sln b/code/windows/PhoneVR/PhoneVR.sln index d964fec1..83be20cc 100644 --- a/code/windows/PhoneVR/PhoneVR.sln +++ b/code/windows/PhoneVR/PhoneVR.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26228.9 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PhoneVR", "PhoneVR\PhoneVR.vcxproj", "{EECAFA17-E17D-4D6A-898F-DA593C98D0E2}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "driver_PVRServer", "PhoneVR\PhoneVR.vcxproj", "{EECAFA17-E17D-4D6A-898F-DA593C98D0E2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -14,7 +14,6 @@ Global EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {EECAFA17-E17D-4D6A-898F-DA593C98D0E2}.Debug|x64.ActiveCfg = Debug|x64 - {EECAFA17-E17D-4D6A-898F-DA593C98D0E2}.Debug|x64.Build.0 = Debug|x64 {EECAFA17-E17D-4D6A-898F-DA593C98D0E2}.Debug|x86.ActiveCfg = Debug|Win32 {EECAFA17-E17D-4D6A-898F-DA593C98D0E2}.Debug|x86.Build.0 = Debug|Win32 {EECAFA17-E17D-4D6A-898F-DA593C98D0E2}.Release|x64.ActiveCfg = Release|x64 @@ -25,4 +24,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {019DA038-36FE-4F25-AAF0-53EFA125B5D8} + EndGlobalSection EndGlobal diff --git a/code/windows/PhoneVR/PhoneVR/PVRGraphics.cpp b/code/windows/PhoneVR/PhoneVR/PVRGraphics.cpp index 996b5335..b0e76496 100644 --- a/code/windows/PhoneVR/PhoneVR/PVRGraphics.cpp +++ b/code/windows/PhoneVR/PhoneVR/PVRGraphics.cpp @@ -1,24 +1,5 @@ #include "PVRGraphics.h" -#include - -#include -#include "PVRGlobals.h" -#include - - -#pragma comment(lib, "d3d11.lib") -#pragma comment(lib, "dxgi.lib") -#pragma comment(lib, "d3dcompiler.lib") - - -using namespace std; -using namespace this_thread; -using namespace concurrency; -using namespace concurrency::direct3d; -using namespace concurrency::graphics; -using namespace concurrency::graphics::direct3d; - namespace { ID3D11Device *dxDev; ID3D11DeviceContext *dxDevCtx; @@ -38,21 +19,6 @@ namespace { thread *gThr; } -#define RELEASE(obj) if(obj) { obj->Release(); obj = nullptr; } -#define OK_OR_EXEC(call, func) if(FAILED(call)) func() -#define OK_OR_DEBUG(call) { HRESULT hr = call; OK_OR_EXEC(hr, [hr] { PVR_DB_I("######### DirectX Error: #########"); debugHr(hr); }); } -#define QUERY(from, to) OK_OR_DEBUG(from->QueryInterface(__uuidof(to), reinterpret_cast(&to))) -//#define PARENT(child, parent) OK_OR_DEBUG(child->GetParent(__uuidof(parent), reinterpret_cast(&parent))) -//#define OK_OR_REINIT(call) OK_OR_EXEC(call, [] { PVRReleaseDX(); PVRInitDX(outID); }) - -// RGB to YUV constants -#define wr 0.299f -#define wb 0.114f -#define wg 0.587f // 1.0 - wr - wb; -#define ku 0.492f //0.436 / (1.0 - wb); -#define kv 0.877f //0.615 / (1.0 - wr); - - void PVRInitDX() { auto fl = D3D_FEATURE_LEVEL_11_0; OK_OR_DEBUG(D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, &fl, 1, D3D11_SDK_VERSION, &dxDev, nullptr, &dxDevCtx)); @@ -72,7 +38,8 @@ void PVRUpdTexHdl(uint64_t texHdl, int whichBuf) { void PVRStartGraphics(vector> vvbuf, uint32_t inpWidth, uint32_t inpHeight) { gRunning = true; - gThr = new thread([=] { + gThr = new std::thread([=] { + vector>> yuvBufViews; // output for (auto vbuf : vvbuf) // divide width by 4: store 4 bytes in an uint diff --git a/code/windows/PhoneVR/PhoneVR/PVRGraphics.h b/code/windows/PhoneVR/PhoneVR/PVRGraphics.h index 9535709b..331167d8 100644 --- a/code/windows/PhoneVR/PhoneVR/PVRGraphics.h +++ b/code/windows/PhoneVR/PhoneVR/PVRGraphics.h @@ -1,5 +1,37 @@ #pragma once #include +#include + +#include +#include "PVRGlobals.h" +#include + + +#pragma comment(lib, "d3d11.lib") +#pragma comment(lib, "dxgi.lib") +#pragma comment(lib, "d3dcompiler.lib") + + +using namespace std; +using namespace this_thread; +using namespace concurrency; +using namespace concurrency::direct3d; +using namespace concurrency::graphics; +using namespace concurrency::graphics::direct3d; + +#define RELEASE(obj) if(obj) { obj->Release(); obj = nullptr; } +#define OK_OR_EXEC(call, func) if(FAILED(call)) func() +#define OK_OR_DEBUG(call) { HRESULT hr = call; OK_OR_EXEC(hr, [hr] { PVR_DB_I("######### DirectX Error: #########"); debugHr(hr); }); } +#define QUERY(from, to) OK_OR_DEBUG(from->QueryInterface(__uuidof(to), reinterpret_cast(&to))) +//#define PARENT(child, parent) OK_OR_DEBUG(child->GetParent(__uuidof(parent), reinterpret_cast(&parent))) +//#define OK_OR_REINIT(call) OK_OR_EXEC(call, [] { PVRReleaseDX(); PVRInitDX(outID); }) + +// RGB to YUV constants +#define wr 0.299f +#define wb 0.114f +#define wg 0.587f // 1.0 - wr - wb; +#define ku 0.492f //0.436 / (1.0 - wb); +#define kv 0.877f //0.615 / (1.0 - wr); void PVRInitDX(); void PVRUpdTexHdl(uint64_t texHdl, int whichBuffer); diff --git a/code/windows/PhoneVR/PhoneVR/PVRSockets.cpp b/code/windows/PhoneVR/PhoneVR/PVRSockets.cpp index 2bc43c1b..42c8cfd2 100644 --- a/code/windows/PhoneVR/PhoneVR/PVRSockets.cpp +++ b/code/windows/PhoneVR/PhoneVR/PVRSockets.cpp @@ -121,223 +121,310 @@ void PVRStopConnectionListener() { void PVRStartStreamer(string ip, uint16_t width, uint16_t height, function)> headerCb, function onErrCb) { videoRunning = true; + /* videoThr = new std::thread([=] { - PVR_DB("[PVRStartStreamer th] Setting encoder"); - auto S = ENCODER_SECT; - int fps = PVRProp({ GAME_FPS_KEY }); - //auto wait = 1'000'000us / fps / 5; + PVR_DB("[PVRStartStreamer FF th] Setting encoder"); + int fps = PVRProp({ GAME_FPS_KEY }); vFrameDtUs = (1'000'000us / fps).count(); - x264_param_t par; - x264_picture_t outPic; - auto res = x264_param_default_preset(&par, PVRProp({ S, PRESET_KEY }).c_str(), PVRProp({ S, TUNE_KEY }).c_str()); + auto S = ENCODER_SECT; - { - par.i_csp = FMT; - par.i_width = width; - par.i_height = height; - par.b_vfr_input = 0; // disable variable frame rate, ignore pts - par.b_repeat_headers = 1; - par.b_annexb = 1; - par.i_fps_num = fps; - - par.rc.i_rc_method = PVRProp({ S, RC_METHOD_KEY }); // 0->X264_RC_CQP, 2->X264_RC_ABR; - - auto qcomp = PVRProp({ S, QCOMP_KEY }); - if (qcomp >= 0) - par.rc.f_qcompress = qcomp; - - auto qp = PVRProp({ S, QP_KEY }); - if (qp > 0) { - par.rc.i_qp_constant = qp; - par.rc.i_qp_min = qp - 5; - par.rc.i_qp_max = qp + 5; - } + PVR_DB("[PVRStartStreamer FF th] Inint PVRffmpeg class and start reading Pipes..."); + PVRffmpeg ffmpeg = PVRffmpeg(); + ffmpeg.initFFMPEGChildProcess(); - auto br = PVRProp({ S, BITRATE_KEY }); - if (br > 0) - par.rc.i_bitrate = br; + ffmpeg.startPipeReader(); - auto ki_max = PVRProp({ S, KEYINT_MAX_KEY }); - if (ki_max > 0) - par.i_keyint_max = ki_max; + PVR_DB("[PVRStartStreamer FF th] FFMPEGChildProcess Created"); + + vector> vvbuf; + for (size_t i = 0; i < nVFrames; i++) { + x264_picture_alloc(&vFrames[i], FMT, width, height); + vvbuf.push_back({ vFrames[i].img.plane[0], vFrames[i].img.plane[1], vFrames[i].img.plane[2] }); + } - par.b_intra_refresh = PVRProp({ S, I_REFRESH_KEY }) ? 1 : 0; + PVR_DB("[PVRStartStreamer FF th] Starting graphics"); + PVRStartGraphics(vvbuf, width, height); + + int lastWhichFrame = 0; + + while ((whichFrame == lastWhichFrame || quatQueue.size() == 0) && videoRunning) // for first frame + sleep_for(500us); + while (videoRunning) + { + if ((lastWhichFrame + 1) % nVFrames != whichFrame) + PVR_DB_I("[PVRStartStreamer FF th] Skipped frame! Please re-tune the encoder parameters lWf:" + to_string(lastWhichFrame) + ", nVfs:" + to_string(nVFrames) + ", wF:" + to_string(whichFrame)); + lastWhichFrame = whichFrame; + whichFrameMtxs[lastWhichFrame].lock(); // LOCK + + PVR_DB("[PVRStartStreamer FF th] Writing to Pipe of frame: " + + to_string(lastWhichFrame) + + " DataWritten: " + + to_string(ffmpeg.WriteToPipe(&vFrames[lastWhichFrame], height)) ); + + if (!ffmpeg.isChildProcessRunning()) ffmpeg.CreateFFMPEGChildProcess(); + whichFrameMtxs[lastWhichFrame].unlock(); // UNLOCK + + while ((whichFrame == lastWhichFrame || quatQueue.size() == 0) && videoRunning) + sleep_for(500us); } - res = x264_param_apply_profile(&par, PVRProp({ S, PROFILE_KEY }).c_str()); + PVRStopGraphics(); + //outp.close();////////////////////////////////////////////////////////////////////////////////////////// - par.rc.i_rc_method = 1; + for (auto frame : vFrames) + x264_picture_clean(&frame); + });*/ + + /* Piping Video Frames Code + { + videoThr = new std::thread([=] { + PVR_DB("[PVRStartStreamer th] Setting encoder"); + auto S = ENCODER_SECT; + int fps = PVRProp({ GAME_FPS_KEY }); - par.rc.i_bitrate = 1000; - par.rc.i_vbv_max_bitrate = 1200; - par.rc.i_vbv_buffer_size = 20000; - par.rc.f_vbv_buffer_init = 0.9f; + //auto wait = 1'000'000us / fps / 5; + vFrameDtUs = (1'000'000us / fps).count(); - //par.rc.i_qp_constant = 25; - //par.rc.i_qp_min = par.rc.i_qp_constant - 1; - //par.rc.i_qp_max = par.rc.i_qp_constant + 1; - //par.rc.f_qcompress = 0.0f; + x264_param_t par; + x264_picture_t outPic; + auto res = x264_param_default_preset(&par, PVRProp({ S, PRESET_KEY }).c_str(), PVRProp({ S, TUNE_KEY }).c_str()); - //par.rc.f_rf_constant = 12; - //par.rc.f_rf_constant_max = 13; - par.rc.f_rf_constant = 24; - par.rc.f_rf_constant_max = 26; + { + par.i_csp = FMT; + par.i_width = width; + par.i_height = height; + par.b_vfr_input = 0; // disable variable frame rate, ignore pts + par.b_repeat_headers = 1; + par.b_annexb = 1; + par.i_fps_num = fps; + + par.rc.i_rc_method = PVRProp({ S, RC_METHOD_KEY }); // 0->X264_RC_CQP, 2->X264_RC_ABR; + + auto qcomp = PVRProp({ S, QCOMP_KEY }); + if (qcomp >= 0) + par.rc.f_qcompress = qcomp; + + auto qp = PVRProp({ S, QP_KEY }); + if (qp > 0) { + par.rc.i_qp_constant = qp; + par.rc.i_qp_min = qp - 5; + par.rc.i_qp_max = qp + 5; + } + auto br = PVRProp({ S, BITRATE_KEY }); + if (br > 0) + par.rc.i_bitrate = br; - //par.nalu_process TODO: callback available!!!!!!!!! manage a udp thread inside here, then dispatch sends - // use opaque pointer to know from which frame a nal belongs - // use i_first_mb to sort slice nals - // still need to find out how to sort non-slice nals + auto ki_max = PVRProp({ S, KEYINT_MAX_KEY }); + if (ki_max > 0) + par.i_keyint_max = ki_max; - vector> vvbuf; - for (size_t i = 0; i < nVFrames; i++) { - x264_picture_alloc(&vFrames[i], FMT, width, height); - vvbuf.push_back({ vFrames[i].img.plane[0], vFrames[i].img.plane[1], vFrames[i].img.plane[2] }); - } - PVRStartGraphics(vvbuf, width, height); + par.b_intra_refresh = PVRProp({ S, I_REFRESH_KEY }) ? 1 : 0; + } + res = x264_param_apply_profile(&par, PVRProp({ S, PROFILE_KEY }).c_str()); - auto *enc = x264_encoder_open(&par); - x264_param_t outPar; - x264_encoder_parameters(enc, &outPar); - PVR_DB("[PVRStartStreamer th] Render size: " + to_string(width) + "x" + to_string(height)); - PVR_DB("[PVRStartStreamer th] Using encoding level: " + to_string(outPar.i_level_idc)); + par.rc.i_rc_method = 1; - x264_nal_t *nals; - int nNals; - res = x264_encoder_headers(enc, &nals, &nNals); - vector vheader; - for (size_t i = 0; i < nNals; i++) - vheader.insert(vheader.end(), nals[i].p_payload, nals[i].p_payload + nals[i].i_payload); // WARNING: including SEI nal - headerCb(vheader); + par.rc.i_bitrate = 1000; + par.rc.i_vbv_max_bitrate = 1200; + par.rc.i_vbv_buffer_size = 20000; + par.rc.f_vbv_buffer_init = 0.9f; - io_service svc; - tcp::socket skt(svc); - tcp::acceptor acc(svc, { tcp::v4(), PVRProp({ VIDEO_PORT_KEY }) }); - acc.accept(skt); + //par.rc.i_qp_constant = 25; + //par.rc.i_qp_min = par.rc.i_qp_constant - 1; + //par.rc.i_qp_max = par.rc.i_qp_constant + 1; + //par.rc.f_qcompress = 0.0f; - //udp::socket skt(svc); - //udp::endpoint remEP(address::from_string(ip), port); - //skt.open(udp::v4()); + //par.rc.f_rf_constant = 12; + //par.rc.f_rf_constant_max = 13; + par.rc.f_rf_constant = 24; + par.rc.f_rf_constant_max = 26; - int lastWhichFrame = 0; - //uint8_t buf[256 * 256]; - uint8_t extraBuf[8 + 16 + 4 + 20 + 8 + 8]; - auto pbuf = reinterpret_cast(&extraBuf[0]); // pts buf ref - auto qbuf = reinterpret_cast(&extraBuf[8]); // quat buf ref - auto nbuf = reinterpret_cast(&extraBuf[8 + 16]); - auto fpsbuf = reinterpret_cast(&extraBuf[8 + 16 + 4]); - auto tDelaysBuf = reinterpret_cast(&extraBuf[8 + 16 + 4 + 20]); - auto timestamp = reinterpret_cast(&extraBuf[8 + 16 + 4 + 20 + 8]); - - asio::error_code ec; - //ofstream outp("C:\\Users\\narni\\mystream.h264", ofstream::binary);///////////////////////////////////////////// - while ((whichFrame == lastWhichFrame || quatQueue.size() == 0) && videoRunning) // for first frame - sleep_for(500us); - while (videoRunning) - { - //PVRUpdTexWraps(); - static Clk::time_point oldtime, oldtimeStreamer; - oldtime = Clk::now(); - oldtimeStreamer = Clk::now(); - if ((lastWhichFrame + 1) % nVFrames != whichFrame) - PVR_DB_I("[PVRStartStreamer th] Skipped frame! Please re-tune the encoder parameters lWf:"+to_string(lastWhichFrame)+", nVfs:"+ to_string(nVFrames)+ ", wF:"+to_string(whichFrame)); - lastWhichFrame = whichFrame; - whichFrameMtxs[lastWhichFrame].lock(); // LOCK - auto totSz = x264_encoder_encode(enc, &nals, &nNals, &vFrames[lastWhichFrame], &outPic); - whichFrameMtxs[lastWhichFrame].unlock(); // UNLOCK - fpsEncoder = (1000000000.0 / (Clk::now() - oldtime).count()); + //par.nalu_process TODO: callback available!!!!!!!!! manage a udp thread inside here, then dispatch sends + // use opaque pointer to know from which frame a nal belongs + // use i_first_mb to sort slice nals + // still need to find out how to sort non-slice nals - oldtime = Clk::now(); + vector> vvbuf; + for (size_t i = 0; i < nVFrames; i++) { + x264_picture_alloc(&vFrames[i], FMT, width, height); + vvbuf.push_back({ vFrames[i].img.plane[0], vFrames[i].img.plane[1], vFrames[i].img.plane[2] }); + } + PVRStartGraphics(vvbuf, width, height); + + auto *enc = x264_encoder_open(&par); + + x264_param_t outPar; + x264_encoder_parameters(enc, &outPar); + PVR_DB("[PVRStartStreamer th] Render size: " + to_string(width) + "x" + to_string(height)); + PVR_DB("[PVRStartStreamer th] Using encoding level: " + to_string(outPar.i_level_idc)); + + x264_nal_t *nals; + int nNals; + res = x264_encoder_headers(enc, &nals, &nNals); + vector vheader; + for (size_t i = 0; i < nNals; i++) + vheader.insert(vheader.end(), nals[i].p_payload, nals[i].p_payload + nals[i].i_payload); // WARNING: including SEI nal + headerCb(vheader); - if (totSz > 0) + io_service svc; + tcp::socket skt(svc); + tcp::acceptor acc(svc, { tcp::v4(), PVRProp({ VIDEO_PORT_KEY }) }); + acc.accept(skt); + + //udp::socket skt(svc); + //udp::endpoint remEP(address::from_string(ip), port); + //skt.open(udp::v4()); + + int lastWhichFrame = 0; + //uint8_t buf[256 * 256]; + uint8_t extraBuf[8 + 16 + 4 + 20 + 8 + 8]; + auto pbuf = reinterpret_cast(&extraBuf[0]); // pts buf ref + auto qbuf = reinterpret_cast(&extraBuf[8]); // quat buf ref + auto nbuf = reinterpret_cast(&extraBuf[8 + 16]); + auto fpsbuf = reinterpret_cast(&extraBuf[8 + 16 + 4]); + auto tDelaysBuf = reinterpret_cast(&extraBuf[8 + 16 + 4 + 20]); + auto timestamp = reinterpret_cast(&extraBuf[8 + 16 + 4 + 20 + 8]); + + PVR_DB("[PVRStartStreamer FF th] Inint PVRffmpeg class and start reading Pipes..."); + + PVRffmpeg ffmpeg = PVRffmpeg(); + ffmpeg.initFFMPEGChildProcess(); + + ffmpeg.startSTDErrPipeReader(); + ffmpeg.startSTDOutPipeReader(); + + asio::error_code ec; + //ofstream outp("C:\\Users\\narni\\mystream.h264", ofstream::binary);///////////////////////////////////////////// + while ((whichFrame == lastWhichFrame || quatQueue.size() == 0) && videoRunning) // for first frame + sleep_for(500us); + while (videoRunning) { - PVR_DB("[PVRStartStreamer th] Rendering lWf:"+to_string(lastWhichFrame)+", wF:"+to_string(whichFrame)); - quatQueueMutex.lock(); // LOCK - while ((quatQueue.size() != 0) && (quatQueue.front().first.first < outPic.i_pts)) // handle skipped frames + //PVRUpdTexWraps(); + static Clk::time_point oldtime, oldtimeStreamer; + oldtime = Clk::now(); + oldtimeStreamer = Clk::now(); + + //if ((lastWhichFrame + 1) % nVFrames != whichFrame) + //PVR_DB_I("[PVRStartStreamer th] Skipped frame! Please re-tune the encoder parameters lWf:" + to_string(lastWhichFrame) + ", nVfs:" + to_string(nVFrames) + ", wF:" + to_string(whichFrame)); + lastWhichFrame = whichFrame; + + if (!ffmpeg.isChildProcessRunning()) { - PVR_DB("[PVRStartStreamer th] handle skipped frames qPts:" + to_string(quatQueue.front().first.first) + ", outpicPts:" + to_string(outPic.i_pts)); - quatQueue.pop(); + ffmpeg.CreateFFMPEGChildProcess(); + PVR_DB("[PVRStartStreamer FF th] FFMPEGChildProcess Created"); } - quatQueueMutex.unlock(); // UNLOCK - if (quatQueue.size() != 0) + whichFrameMtxs[lastWhichFrame].lock(); // LOCK + + PVR_DB("[PVRStartStreamer FF th] Writing to Pipe of frame: " + + to_string(lastWhichFrame) + + " DataWritten: " + + to_string(100*ffmpeg.WriteToPipe(&vFrames[lastWhichFrame], height)) + "%" ); + + auto totSz = 5; + //auto totSz = x264_encoder_encode(enc, &nals, &nNals, &vFrames[lastWhichFrame], &outPic); + + whichFrameMtxs[lastWhichFrame].unlock(); // UNLOCK + + fpsEncoder = (1000000000.0 / (Clk::now() - oldtime).count()); + + oldtime = Clk::now(); + + if (totSz > 0) { - quatQueueMutex.lock(); - auto outPts = quatQueue.front().first.first; - auto time = quatQueue.front().first.second.first; - auto renderDur = quatQueue.front().first.second.second; - auto quat = quatQueue.front().second; - quatQueue.pop(); - quatQueueMutex.unlock(); - - *pbuf = outPts; - qbuf[0] = quat.w(); - qbuf[1] = quat.x(); - qbuf[2] = quat.y(); - qbuf[3] = quat.z(); - *nbuf = totSz; - fpsbuf[0] = fpsSteamVRApp; // VRApp FPS - fpsbuf[1] = fpsEncoder; // Encoder FPS - fpsbuf[2] = fpsStreamWriter; // StreamWriter FPS - fpsbuf[3] = fpsStreamer; // Streamer FPS - fpsbuf[4] = fpsRenderer; - tDelaysBuf[0] = renderDur; // Renderer Delay - tDelaysBuf[1] = (float)((Clk::now() - time).count() / 1000000.0); // Encoder Delay - *timestamp = (int64_t)duration_cast(system_clock::now().time_since_epoch()).count(); // FrameSent TimeStamp - - write(skt, buffer(extraBuf), ec); - write(skt, buffer(nals->p_payload, totSz), ec); - - PVR_DB("[PVRStartStreamer th] wrote render to socket: Pts:[Tenc:" - + str_fmt("%.2f", tDelaysBuf[1]) - +" ms, Trend:" - + str_fmt("%.2f", renderDur) - +" ms]" - + to_string(outPts) + ", Size: " - +to_string(sizeof(extraBuf))+","+to_string(totSz)); - - if (ec.value() != 0 && videoRunning) - PVR_DB("Write failed: " + ec.message() + " Code: " + to_string(ec.value())); - if (ec == error::connection_aborted || ec == error::connection_reset) + //PVR_DB("[PVRStartStreamer th] Rendering lWf:" + to_string(lastWhichFrame) + ", wF:" + to_string(whichFrame)); + quatQueueMutex.lock(); // LOCK + //while ((quatQueue.size() != 0) && (quatQueue.front().first.first < outPic.i_pts)) // handle skipped frames + //{ + //PVR_DB("[PVRStartStreamer th] handle skipped frames qPts:" + to_string(quatQueue.front().first.first) + ", outpicPts:" + to_string(outPic.i_pts)); + //quatQueue.pop(); + //} + quatQueueMutex.unlock(); // UNLOCK + + if (quatQueue.size() != 0) { - videoRunning = false; - //onErrCb(); - } + quatQueueMutex.lock(); + auto outPts = quatQueue.front().first.first; + auto time = quatQueue.front().first.second.first; + auto renderDur = quatQueue.front().first.second.second; + auto quat = quatQueue.front().second; + quatQueue.pop(); + quatQueueMutex.unlock(); + + *pbuf = outPts; + qbuf[0] = quat.w(); + qbuf[1] = quat.x(); + qbuf[2] = quat.y(); + qbuf[3] = quat.z(); + *nbuf = totSz; + fpsbuf[0] = fpsSteamVRApp; // VRApp FPS + fpsbuf[1] = fpsEncoder; // Encoder FPS + fpsbuf[2] = fpsStreamWriter; // StreamWriter FPS + fpsbuf[3] = fpsStreamer; // Streamer FPS + fpsbuf[4] = fpsRenderer; + tDelaysBuf[0] = renderDur; // Renderer Delay + tDelaysBuf[1] = (float)((Clk::now() - time).count() / 1000000.0); // Encoder Delay + *timestamp = (int64_t)duration_cast(system_clock::now().time_since_epoch()).count(); // FrameSent TimeStamp + + write(skt, buffer(extraBuf), ec); + //write(skt, buffer(nals->p_payload, totSz), ec); + write(skt, buffer("00000", 5), ec); + + PVR_DB("[PVRStartStreamer th] wrote render to socket: Pts:[Tenc:" + + str_fmt("%.2f", tDelaysBuf[1]) + + " ms, Trend:" + + str_fmt("%.2f", renderDur) + + " ms]" + + to_string(outPts) + ", Size: " + + to_string(sizeof(extraBuf)) + "," + to_string(totSz)); + + if (ec.value() != 0 && videoRunning) + PVR_DB("Write failed: " + ec.message() + " Code: " + to_string(ec.value())); + if (ec == error::connection_aborted || ec == error::connection_reset) + { + videoRunning = false; + //onErrCb(); + } - //outp.write((char*)nals->p_payload, totSz);///////////////////////////////////////////////////////// + //outp.write((char*)nals->p_payload, totSz);///////////////////////////////////////////////////////// + } } - } - fpsStreamWriter = (1000000000.0 / (Clk::now() - oldtime).count()); - PVR_DB("[PVRStartStreamer th] ------------------- StreamWriting @ FPS: " + to_string(fpsStreamWriter) + " Encoding @ FPS : " + to_string(fpsEncoder) + " VRApp Running @ FPS : " + to_string(fpsSteamVRApp)); - oldtime = Clk::now(); + fpsStreamWriter = (1000000000.0 / (Clk::now() - oldtime).count()); + //PVR_DB("[PVRStartStreamer th] ------------------- StreamWriting @ FPS: " + to_string(fpsStreamWriter) + " Encoding @ FPS : " + to_string(fpsEncoder) + " VRApp Running @ FPS : " + to_string(fpsSteamVRApp)); + oldtime = Clk::now(); - while ((whichFrame == lastWhichFrame || quatQueue.size() == 0) && videoRunning) - sleep_for(500us); + while ((whichFrame == lastWhichFrame || quatQueue.size() == 0) && videoRunning) + sleep_for(500us); - fpsStreamer = (1000000000.0 / (Clk::now() - oldtimeStreamer).count()); - oldtimeStreamer = Clk::now(); - } - x264_encoder_close(enc); + fpsStreamer = (1000000000.0 / (Clk::now() - oldtimeStreamer).count()); + oldtimeStreamer = Clk::now(); + } + x264_encoder_close(enc); - PVRStopGraphics(); + PVRStopGraphics(); - //outp.close();////////////////////////////////////////////////////////////////////////////////////////// + //outp.close();////////////////////////////////////////////////////////////////////////////////////////// - for (auto frame : vFrames) - x264_picture_clean(&frame); - }); + for (auto frame : vFrames) + x264_picture_clean(&frame); + }); + }*/ } -void PVRProcessFrame(uint64_t hdl, Quaternionf quat) { +void PVRProcessFrame(PVRffmpeg* mPVRffmpeg, SharedTextureHandle_t hdl, Quaternionf quat) { + + mPVRffmpeg->ProcessSharedHandle(hdl, quat); + if (videoRunning) { static Clk::time_point oldtimeVRApp = Clk::now(); diff --git a/code/windows/PhoneVR/PhoneVR/PVRSockets.h b/code/windows/PhoneVR/PhoneVR/PVRSockets.h index 809cfd00..e0ab62d2 100644 --- a/code/windows/PhoneVR/PhoneVR/PVRSockets.h +++ b/code/windows/PhoneVR/PhoneVR/PVRSockets.h @@ -6,11 +6,13 @@ #include "PVRGlobals.h" #include "PVRSocketUtils.h" +#include "PVRffmpeg.h" + void PVRStartConnectionListener(std::function callback); void PVRStopConnectionListener(); void PVRStartStreamer(std::string ip, uint16_t width, uint16_t height, std::function)> headerCb, std::function onErrCb); -void PVRProcessFrame(uint64_t hdl, Eigen::Quaternionf quat); +void PVRProcessFrame(PVRffmpeg *ff, SharedTextureHandle_t hdl, Eigen::Quaternionf quat); void PVRStopStreamer(); void PVRStartReceiveData(std::string ip, vr::DriverPose_t *pose, uint32_t *objId); diff --git a/code/windows/PhoneVR/PhoneVR/PVRffmpeg.cpp b/code/windows/PhoneVR/PhoneVR/PVRffmpeg.cpp new file mode 100644 index 00000000..b4f0ce5d --- /dev/null +++ b/code/windows/PhoneVR/PhoneVR/PVRffmpeg.cpp @@ -0,0 +1,350 @@ +#include "PVRffmpeg.h" + +void ffmpeg_log_callback(void* classptr, int LogLevel, const char* printfString, va_list args) +{ + char buffer[256]; + buffer[0] = '\0'; + + vsprintf(buffer, printfString, args); + PVR_DB("FFMPEG LOG: " + string(buffer)); +} + +PVRffmpeg::PVRffmpeg() +{ + av_log_set_flags(AV_LOG_INFO); + av_log_set_callback(&ffmpeg_log_callback); + + /* Calling SetDllDirectory with the empty string (but not NULL) removes the + * current working directory from the DLL search path as a security pre-caution. */ + //SetDllDirectory(L""); + + avdevice_register_all(); + avformat_network_init(); +} + +PVRffmpeg::~PVRffmpeg() +{ + avformat_network_deinit(); +} + +void PVRffmpeg::setSettings(int width, int height, string remoteIP, int port) +{ + this->width = width; + this->height = height; + this->remoteIP = remoteIP; + this->remotePort = port; + //AVCodec *avc = avcodec_find_encoder_by_name("H264"); +} + +extern "C" +{ +#include "libavutil/pixdesc.h" +#include "libavutil/imgutils.h" +} + +void PVRffmpeg::ProcessSharedHandle(SharedTextureHandle_t igfxSharedHandle, Quaternionf iquat) +{ + mgfxSharedHandle.lock(); + + gfxSharedHandle = igfxSharedHandle; + quat = iquat; + + if (OutputEncoderContext) + { + AVPacket *pkt = av_packet_alloc(); + if (!pkt) + { + PVR_DB("PVRffmpeg::ProcessSharedHandle() Could not allocate pkt"); + //exit(1); + } + + AVFrame* frame = av_frame_alloc(); + if (!frame) { + PVR_DB("PVRffmpeg::ProcessSharedHandle() Could not allocate video frame"); + //exit(1); + } + frame->format = OutputEncoderContext->pix_fmt; + frame->width = OutputEncoderContext->width; + frame->height = OutputEncoderContext->height; + + //int ret = av_frame_get_buffer(frame, 0); + /*int align = 0; + + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get((AVPixelFormat)frame->format); + int ret, i, padded_height, total_size; + int plane_padding = 32; + ptrdiff_t linesizes[4]; + size_t sizes[4]; + + if (!desc) + { + PVR_DB("av_pix_fmt_desc_get failed : " + to_string( AVERROR(EINVAL) ) ); + } + + if ((ret = av_image_check_size(frame->width, frame->height, 0, NULL)) < 0) + { + PVR_DB("av_image_check_size failed : " + to_string(ret)); + } + + if (!frame->linesize[0]) { + if (align <= 0) + align = 32; + + for (i = 1; i <= align; i += i) { + ret = av_image_fill_linesizes(frame->linesize, (AVPixelFormat)frame->format, + FFALIGN(frame->width, i)); + if (ret < 0) + { + PVR_DB("av_image_fill_linesizes failed : " + to_string(ret)); + } + if (!(frame->linesize[0] & (align - 1))) + break; + } + + for (i = 0; i < 4 && frame->linesize[i]; i++) + frame->linesize[i] = FFALIGN(frame->linesize[i], align); + } + + for (i = 0; i < 4; i++) + linesizes[i] = frame->linesize[i]; + + padded_height = FFALIGN(frame->height, 32); + if ((ret = av_image_fill_plane_sizes(sizes, (AVPixelFormat)frame->format, + padded_height, linesizes)) < 0) + { + PVR_DB("av_image_fill_plane_sizes failed : " + to_string(ret)); + } + + total_size = 4 * plane_padding; + for (i = 0; i < 4; i++) { + if (sizes[i] > INT_MAX - total_size) + { + PVR_DB("total_size plane_padding failed : " + to_string(AVERROR(EINVAL))); + } + total_size += sizes[i]; + } + + frame->buf[0] = av_buffer_alloc(total_size); + if (!frame->buf[0]) { + ret = AVERROR(ENOMEM); + goto fail; + } + + if ((ret = av_image_fill_pointers(frame->data, (AVPixelFormat)frame->format, padded_height, + frame->buf[0]->data, frame->linesize)) < 0) + goto fail; + + for (i = 1; i < 4; i++) { + if (frame->data[i]) + frame->data[i] += i * plane_padding; + } + + frame->extended_data = frame->data; + + if (ret < 0) { + char errbuf[124]; + + av_strerror(AVERROR(ret), errbuf, 124); + PVR_DB("PVRffmpeg::Stream() Could not allocate the frame data Error (" + to_string(ret) + "): " + errbuf ); + //exit(1); + }*/ + int ret = av_frame_make_writable(frame); + if (ret < 0) + { + PVR_DB("PVRffmpeg::ProcessSharedHandle() Could not make AV_FRame Writable"); + //exit(1); + } + + //ID3D11Texture2D* hwTexture = (ID3D11Texture2D *)(frame->data[0]); + //DXGI_FORMAT_NV12 + //**** Loop This for fps Times + + ID3D11Texture2D *inpTex; + HRESULT hr = avHWDevice->OpenSharedResource((HANDLE)gfxSharedHandle, __uuidof(ID3D11Texture2D), (void **)&inpTex); + if (FAILED(hr)) + { + PVR_DB("PVRffmpeg::ProcessSharedHandle() Failed to OpenSharedResource, D3DHWDevFeatureLevel: " + to_string(avHWDevice->GetFeatureLevel()) ); + debugHr(hr); + //return; + } + + IDXGIKeyedMutex *dxMtx; + hr = inpTex->QueryInterface(__uuidof(dxMtx), reinterpret_cast(&dxMtx)); + if (FAILED(hr)) + { + PVR_DB("PVRffmpeg::ProcessSharedHandle() Failed to QueryInterface"); + debugHr(hr); + //return; + } + + if (SUCCEEDED(dxMtx->AcquireSync(0, 500))) { + avHWDevice_context->CopyResource(stagingTex, inpTex); //texAmp is automatically updated + dxMtx->ReleaseSync(0); + } + + //ID3D11Texture2D* hwTexture = (ID3D11Texture2D *)(frame->data[0]); + frame->data[0] = (uint8_t *)stagingTex; + frame->data[1] = 0; + + RELEASE(dxMtx); + RELEASE(inpTex); + + //**** + + //(*hwTexture).GetDevice(&hwDevice); + + /*ID3D11DeviceContext* hwDeviceCtx; + hwDevice->GetImmediateContext(&hwDeviceCtx); + + ID3D11Texture2D* sharedTexture; + + HRESULT hr = hwDevice->OpenSharedResource((HANDLE) gfxSharedHandle, __uuidof(ID3D11Texture2D), (void**)&inpTex); + if (FAILED(hr)) + { + PVR_DB("PVRffmpeg::Stream() Failed to obtaion open shared resource."); + return; + } + + int index = *frame->data[1]; + hwDeviceCtx->CopySubresourceRegion(sharedTexture, 0, 0, 0, 0, hwTexture, index, NULL);*/ + + /* flush the encoder */ + encode(OutputEncoderContext, frame, pkt, OutputContext); + + /* add sequence end code to have a real MPEG file */ + //fwrite(endcode, 1, sizeof(endcode), f); + //fclose(f); + + //avcodec_free_context(&OutputEncoderContext); + + fail: + av_frame_unref(frame); + { + PVR_DB("failed : " + to_string(ret)); + } + av_frame_free(&frame); + av_packet_free(&pkt); + } + + mgfxSharedHandle.unlock(); +} + +void PVRffmpeg::debugHr(HRESULT hr) +{ + LPWSTR output; + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&output, 0, NULL); + PVR_DB_I(wstring(output)); +} + +void PVRffmpeg::Stream() +{ + // av_dict_set(&sws_dict, "flags", "bicubic", 0); + int result = avformat_alloc_output_context2(&OutputContext, NULL, "rtp", "rtp://127.0.0.1"); + + // Using SW libx264 Codec + //vVideoCodech264 = avcodec_find_encoder(AV_CODEC_ID_H264); + vVideoCodecNVENC = avcodec_find_encoder_by_name("h264_nvenc"); // Type 2 Encoder + OutputVideoStream = avformat_new_stream(OutputContext, vVideoCodecNVENC); + + OutputEncoderContext = avcodec_alloc_context3(vVideoCodecNVENC); + + result = av_hwdevice_ctx_create(&nvencD3D11DeviceContext, AV_HWDEVICE_TYPE_D3D11VA, "d3d11va", NULL, 0); + nvencD3D11DeviceCtx = (AVHWDeviceContext*)nvencD3D11DeviceContext->data; + + nvencHWFramesContext = av_hwframe_ctx_alloc(nvencD3D11DeviceContext); + + AVHWFramesContext* AVHWFramesCTx = (AVHWFramesContext *)nvencHWFramesContext->data; + AVHWFramesCTx->format = AV_PIX_FMT_D3D11; + + OutputEncoderContext->hw_frames_ctx = nvencHWFramesContext; + + if (!OutputEncoderContext) + { + PVR_DB("PVRffmpeg::Stream() Could not allocate video codec context"); + exit(1); + } + + OutputEncoderContext->bit_rate = 400000; + OutputEncoderContext->width = width; + OutputEncoderContext->height = height; + + OutputEncoderContext->time_base = AVRational { 1, 60 }; + OutputEncoderContext->framerate = AVRational { 60, 1 }; + + OutputEncoderContext->gop_size = 10; + OutputEncoderContext->max_b_frames = 1; + OutputEncoderContext->pix_fmt = AV_PIX_FMT_D3D11; + + PVR_DB("PVRffmpeg::Stream(): AVHWFramesPixFormate : " + to_string(AVHWFramesCTx->format) + " & OutputEncoderContext PixFmt: " + to_string(AV_PIX_FMT_D3D11)); + + if (vVideoCodecNVENC->id == AV_CODEC_ID_H264) + av_opt_set(OutputEncoderContext->priv_data, "preset", "slow", 0); + + /* open it */ + + int ret = avcodec_open2(OutputEncoderContext, vVideoCodecNVENC, NULL); + if (ret < 0) { + PVR_DB("PVRffmpeg::Stream() Could not open codec: %s"+ to_string(ret)); + //exit(1); + } + + AVD3DhwDevice = (AVD3D11VADeviceContext *)nvencD3D11DeviceCtx->hwctx; + + avHWDevice = AVD3DhwDevice->device; + avHWDevice_context = AVD3DhwDevice->device_context; + + D3D11_TEXTURE2D_DESC texDesc = {}; + texDesc.Width = width; + texDesc.Height = height; + texDesc.MipLevels = 1; + texDesc.ArraySize = 1; + texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + texDesc.SampleDesc.Count = 1; + texDesc.Usage = D3D11_USAGE_DEFAULT; + texDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; + texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED; + + HRESULT hr = avHWDevice->CreateTexture2D(&texDesc, nullptr, &stagingTex); + if (FAILED(hr)) + { + PVR_DB_I("######### DirectX Error: #########"); + debugHr(hr); + } +} + +void PVRffmpeg::encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt, AVFormatContext *outputContext) +{ + int ret; + /* send the frame to the encoder */ + if (frame) + { + PVR_DB("PVRffmpeg::encode() Send frame %d" + to_string(frame->pts)); + } + + ret = avcodec_send_frame(enc_ctx, frame); + if (ret < 0) { + PVR_DB("PVRffmpeg::encode() Error sending a frame for encoding"); + //exit(1); + } + while (ret >= 0) { + ret = avcodec_receive_packet(enc_ctx, pkt); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + return; + else if (ret < 0) { + PVR_DB("PVRffmpeg::encode() Error during encoding"); + //exit(1); + } + PVR_DB("PVRffmpeg::encode() Write packet "+to_string(pkt->pts)+" (size=" + to_string(pkt->size)+ ")\n" ); + + av_write_frame(outputContext, pkt); + + //fwrite(pkt->data, 1, pkt->size, outfile); + av_packet_unref(pkt); + } +} + +void PVRffmpeg::StopStreaming() +{ + +} diff --git a/code/windows/PhoneVR/PhoneVR/PVRffmpeg.h b/code/windows/PhoneVR/PhoneVR/PVRffmpeg.h new file mode 100644 index 00000000..16d9068b --- /dev/null +++ b/code/windows/PhoneVR/PhoneVR/PVRffmpeg.h @@ -0,0 +1,68 @@ +#pragma once +#include +#include + +extern "C" +{ +#include "libavutil/avutil.h" +#include "libavformat/avformat.h" +#include "libavdevice/avdevice.h" +#include "libavutil/hwcontext_d3d11va.h" +} + +#pragma comment(lib, "avcodec.lib") +#pragma comment(lib, "avutil.lib") +#pragma comment(lib, "avformat.lib") +#pragma comment(lib, "avdevice.lib") + +#include "PVRMath.h" + +#define WIN32_LEAN_AND_MEAN +#include +#include "openvr_driver.h" + +#define RELEASE(obj) if(obj) { obj->Release(); obj = nullptr; } +#define OK_OR_EXEC(call, func) if(FAILED(call)) func() + +using namespace std; +using namespace Eigen; +using namespace vr; + +class PVRffmpeg +{ + int width, height, remotePort; + string remoteIP; + + mutex mgfxSharedHandle; + SharedTextureHandle_t gfxSharedHandle = INVALID_SHARED_TEXTURE_HANDLE; + Quaternionf quat; + + AVFormatContext *OutputContext; + AVCodec *vVideoCodech264; + AVCodec *vVideoCodecNVENC; // This is Encoder + AVStream *OutputVideoStream; + AVCodecContext *OutputEncoderContext; + + AVBufferRef *nvencD3D11DeviceContext = NULL; + AVBufferRef *nvencHWFramesContext = NULL; + + AVHWDeviceContext *nvencD3D11DeviceCtx = NULL; + AVD3D11VADeviceContext* AVD3DhwDevice = NULL; + + ID3D11Device *avHWDevice = NULL; + ID3D11DeviceContext *avHWDevice_context = NULL; + + ID3D11Texture2D* stagingTex = NULL; + + void encode(AVCodecContext * enc_ctx, AVFrame * frame, AVPacket * pkt, AVFormatContext * outputContext); + +public: + PVRffmpeg(); + ~PVRffmpeg(); + + void setSettings(int width, int height, string remoteIP, int port); + void Stream(); + void StopStreaming(); + void ProcessSharedHandle(SharedTextureHandle_t gfxSharedHandle, Quaternionf quat); + void debugHr(HRESULT hr); +}; diff --git a/code/windows/PhoneVR/PhoneVR/PhoneVR.vcxproj b/code/windows/PhoneVR/PhoneVR/PhoneVR.vcxproj index 2e84d30f..06543c51 100644 --- a/code/windows/PhoneVR/PhoneVR/PhoneVR.vcxproj +++ b/code/windows/PhoneVR/PhoneVR/PhoneVR.vcxproj @@ -50,7 +50,7 @@ DynamicLibrary false v141 - true + false Unicode @@ -78,6 +78,8 @@ true $(SolutionDir)$(Configuration)\$(Platform)\ + $(FFMPEG_MASTER)\include;$(IncludePath) + $(FFMPEG_MASTER)\lib;$(LibraryPath) false @@ -108,16 +110,20 @@ Disabled - _WIN32_WINNT=0x0601;_DEBUG;_WINDOWS;_USRDLL;PHONEVR_EXPORTS;%(PreprocessorDefinitions) + _WIN32_WINNT=0x0601;NDEBUG;PVR_DEBUG;_WINDOWS;_USRDLL;PHONEVR_EXPORTS;%(PreprocessorDefinitions) $(SolutionDir)\$(ProjectName);$(SolutionDir)\..\..\common\src;$(SolutionDir)\..\libs\json;$(SolutionDir)\..\libs\x264\include;$(SolutionDir)\..\..\common\libs\asio;$(SolutionDir)\..\..\common\libs\eigen;$(SolutionDir)\..\..\common\src\Utils;%(AdditionalIncludeDirectories) stdcpplatest + MultiThreadedDLL Windows $(SolutionDir)\..\libs\x264\lib\x64;%(AdditionalLibraryDirectories) + + + DebugFull - xcopy "$(SolutionDir)$(Configuration)\$(Platform)" "C:\Program Files (x86)\Steam\steamapps\common\SteamVR\drivers\PVRServer\bin\win64" /h /i /c /k /e /r /y + $(SolutionDir)post_build_debug.cmd @@ -144,12 +150,16 @@ Level1 - MaxSpeed + Disabled true - true + false _WIN32_WINNT=0x0601;NDEBUG;_WINDOWS;_USRDLL;PHONEVR_EXPORTS;%(PreprocessorDefinitions) $(SolutionDir)\$(ProjectName);$(SolutionDir)\..\..\common\src;$(SolutionDir)\..\libs\json;$(SolutionDir)\..\libs\x264\include;$(SolutionDir)\..\..\common\libs\asio;$(SolutionDir)\..\..\common\libs\eigen;$(SolutionDir)\..\..\common\src\Utils;%(AdditionalIncludeDirectories) stdcpplatest + EditAndContinue + true + Default + MultiThreaded Windows @@ -158,13 +168,17 @@ $(SolutionDir)\..\libs\x264\lib\x64;%(AdditionalLibraryDirectories) - xcopy "$(SolutionDir)$(Configuration)\$(Platform)" "C:\Program Files (x86)\Steam\steamapps\common\SteamVR\drivers\PVRServer\bin\win64" /h /i /c /k /e /r /y + $(SolutionDir)post_build_release.cmd + + CompileAsCpp + + @@ -175,6 +189,8 @@ + + diff --git a/code/windows/PhoneVR/PhoneVR/PhoneVR.vcxproj.filters b/code/windows/PhoneVR/PhoneVR/PhoneVR.vcxproj.filters index bfd82685..29e0413f 100644 --- a/code/windows/PhoneVR/PhoneVR/PhoneVR.vcxproj.filters +++ b/code/windows/PhoneVR/PhoneVR/PhoneVR.vcxproj.filters @@ -33,6 +33,12 @@ Source Files + + Source Files + + + Source Files + @@ -62,5 +68,11 @@ Header Files + + Header Files + + + Header Files + \ No newline at end of file diff --git a/code/windows/PhoneVR/PhoneVR/driver.cpp b/code/windows/PhoneVR/PhoneVR/driver.cpp index 5585a3f8..8ab2580e 100644 --- a/code/windows/PhoneVR/PhoneVR/driver.cpp +++ b/code/windows/PhoneVR/PhoneVR/driver.cpp @@ -35,8 +35,10 @@ class HMD : public ITrackedDeviceServerDriver, public IVRDisplayComponent, publi Clk::time_point oldTime = Clk::now(); uint64_t frmCount = 0; bool waitForPresent = false; +#if defined NOT_DEV + //TCPTalker talker; +#endif - TCPTalker talker; unique_ptr addDataBomb; DriverPose_t pose = {}; @@ -53,8 +55,12 @@ class HMD : public ITrackedDeviceServerDriver, public IVRDisplayComponent, publi VRServerDriverHost()->VendorSpecificEvent(objId, VREvent_DriverRequestedQuit, { 0, 0 }, 0); } + PVRffmpeg* gPVRffmpeg = new PVRffmpeg(); + public: - HMD(string ip) : talker(PVRProp({ CONN_PORT_KEY }), [=](auto msgType, auto data) + HMD(string ip) +#if defined NOT_DEV + : talker(PVRProp({ CONN_PORT_KEY }), [=](auto msgType, auto data) { if (msgType == PVR_MSG::DISCONNECT) { // TODO: send remove device event @@ -103,7 +109,9 @@ class HMD : public ITrackedDeviceServerDriver, public IVRDisplayComponent, publi if (err.value() == 104) { terminate(); } - }, false, ip), devIP(ip) + }, false, ip), +#endif + : devIP(ip) { PVR_DB_I("HMD initializing"); @@ -120,9 +128,9 @@ class HMD : public ITrackedDeviceServerDriver, public IVRDisplayComponent, publi vstreamDT = 1'000'000us / PVRProp({ GAME_FPS_KEY }); - +#if defined NOT_DEV talker.send(PVR_MSG::PAIR_ACCEPT); - +#endif PVRInitDX(); PVR_DB_I("HMD initialized"); @@ -132,7 +140,9 @@ class HMD : public ITrackedDeviceServerDriver, public IVRDisplayComponent, publi PVR_DB_I("HMD destroying"); //PVRCloseStreamer(); PVRReleaseDX(); +#if defined NOT_DEV talker.send(PVR_MSG::DISCONNECT); +#endif PVR_DB_I("HMD destroyed"); } @@ -189,6 +199,7 @@ class HMD : public ITrackedDeviceServerDriver, public IVRDisplayComponent, publi //addDataBomb->ignite(false); objId = objectId; + /* Commented for Bypassing Negotiation : FFMPEG auto oldTime = Clk::now(); PVR_DB_I("[Activating HMD]: waiting for additionalData from Client..."); @@ -224,6 +235,39 @@ class HMD : public ITrackedDeviceServerDriver, public IVRDisplayComponent, publi PVR_DB_I("[Activating HMD]: Timeout didnt recv additionalData... for " + to_string(timeout.count()) + "secs"); return VRInitError_Unknown; } + //[HMD::talker] : addData : Viewport : left : -1.440970 top : 2.207398 right : 1.767124 bottom : -1.549411 + //[HMD::talker] : IPD : 0.064000, 1704x960 + */ + + // DEV: Overriting Additonal Data + rdrW = 1704; + rdrH = 960; + projRect[0] = -1.440970; + projRect[1] = 2.207398; + projRect[2] = 1.767124; + projRect[3] = -1.549411; + + PVR_DB_I("[DEV][HMD::talker]: addData: Viewport: left: " + to_string(projRect[0]) + " top: " + to_string(projRect[1]) + + " right: " + to_string(projRect[2]) + " bottom: " + to_string(projRect[3])); + ipd = 0.064000; + PVR_DB_I("[DEV][HMD::talker]: IPD: " + to_string(ipd)); + + //Executing Success Activate (); + PVR_DB_I("[DEV][Activating HMD]: Rcvd addotionalData... Starting PVRStartStreamer with [WxH]:" + to_string(rdrW) + "x" + to_string(rdrH)); + + VRProperties()->SetFloatProperty(propCont, Prop_UserIpdMeters_Float, ipd); + + /*PVRStartStreamer(devIP, rdrW, rdrH, [=](auto v) { + talker.send(PVR_MSG::HEADER_NALS, v); + }, [=] { terminate(); });*/ + //PVRStartReceiveData(devIP, &pose, &objId); + // DEV END + gPVRffmpeg->setSettings(rdrW, rdrH, devIP, 40000); + gPVRffmpeg->Stream(); + //PVRffmpeg.init(devIP, rdrW, rdrH); + + PVR_DB_I("[DEV][Activating HMD]: HMD activated with id: " + to_string(objectId)); + return VRInitError_None; } virtual void Deactivate() override { @@ -327,7 +371,7 @@ class HMD : public ITrackedDeviceServerDriver, public IVRDisplayComponent, publi auto now = Clk::now(); //if (now - oldTime > vstreamDT) { - PVRProcessFrame(backBuffer, newFrameQuat); + PVRProcessFrame(gPVRffmpeg, backBuffer, newFrameQuat); oldTime = now; //} @@ -337,7 +381,7 @@ class HMD : public ITrackedDeviceServerDriver, public IVRDisplayComponent, publi //newFrameQuat = Quaternionf(latestQuat); // poll here the quaternion used in the next frame //VRServerDriverHost()->TrackedDevicePoseUpdated(objId, GetPose(), sizeof(DriverPose_t)); //waitForPresent = false; - //VRServerDriverHost()->VsyncEvent(0.0028); + //VRServerDriverHost()->VsyncEvent(0.0028); } /** Block until the last presented buffer start scanning out. */ @@ -364,7 +408,7 @@ class ServerProvider : public IServerTrackedDeviceProvider { public: virtual EVRInitError Init(IVRDriverContext *drvCtx) override { - PVR_DB_I("[ServerProvider::Init] Initializing server"); + PVR_DB_I("[ServerProvider::Init] Initializing IServerTrackedDeviceProvider server"); bool hmdPaired = false; auto timeout = (seconds)(PVRProp({ CONN_TIMEOUT })); @@ -373,6 +417,8 @@ class ServerProvider : public IServerTrackedDeviceProvider { // any exception is handled by the called method // Start Listening for any incoming connection on CONN_PORT(def:33333) + + /* Commented for Dev Testing : FFMPEG PVRStartConnectionListener([&](auto ip, auto msgType) { if (msgType == PVR_MSG::PAIR_HMD && !hmd) { //VR_INIT_SERVER_DRIVER_CONTEXT(drvCtx); @@ -416,7 +462,26 @@ class ServerProvider : public IServerTrackedDeviceProvider { PVRStopConnectionListener(); PVR_DB_I("[ServerProvider::Init] Pairing failed! Cause: timeout ... for " + to_string(timeout.count()) + "secs"); return VRInitError_Init_HmdNotFound; + }*/ + + // DEV + vr::EVRInitError eError = vr::InitServerDriverContext(drvCtx); + if (eError == vr::VRInitError_None) + { + hmd = new HMD("127.0.0.1"); + hmdPaired = VRServerDriverHost()->TrackedDeviceAdded("0", TrackedDeviceClass_HMD, hmd); + if (!hmdPaired) + { + PVR_DB_I("[ServerProvider::Init::PVRStartConnectionListener] Error: could not activate HMD"); + } + else + hmdBomb.defuse(); + } + else + { + PVR_DB_I("[ServerProvider::Init::PVRStartConnectionListener] Error: could not InitServerDriverContext"); } + // DEV PVR_DB_I("[ServerProvider::Init] Server initialized"); return VRInitError_None; @@ -448,8 +513,8 @@ class ServerProvider : public IServerTrackedDeviceProvider { } virtual bool ShouldBlockStandbyMode() override { - //PVR_DB("Block standby mode: false"); - return false; + PVR_DB("Block standby mode: True"); + return true; } virtual void EnterStandby() override { @@ -470,6 +535,14 @@ void *HmdDriverFactory(const char *iName, int *retCode) { *retCode = VRInitError_Driver_Failed; return nullptr; }*/ + + PVR_DB("------------------------------------"); + while (!::IsDebuggerPresent()) + { + PVR_DB("Waiting for debugger to attach..."); + ::Sleep(100); + } + if (!PVRProp({ ENABLE_KEY })) { PVR_DB_I("PhoneVR server disabled!"); *retCode = VRInitError_Driver_Failed; diff --git a/code/windows/PhoneVR/PhoneVR/post_build.cmd b/code/windows/PhoneVR/PhoneVR/post_build.cmd new file mode 100644 index 00000000..d083ac9c --- /dev/null +++ b/code/windows/PhoneVR/PhoneVR/post_build.cmd @@ -0,0 +1,3 @@ +xcopy "C:\Users\narni\Documents\GitHub\PhoneVR\code\windows\PhoneVR\Debug\x64" "C:\Program Files (x86)\Steam\steamapps\common\SteamVR\drivers\PVRServer\bin\win64" /h /i /c /k /e /r /y + +explorer "steam://rungameid/250820" \ No newline at end of file diff --git a/code/windows/PhoneVR/post_build_debug.cmd b/code/windows/PhoneVR/post_build_debug.cmd new file mode 100644 index 00000000..437651af --- /dev/null +++ b/code/windows/PhoneVR/post_build_debug.cmd @@ -0,0 +1,19 @@ +@ECHO OFF + +xcopy "C:\Users\narni\Documents\GitHub\PhoneVR\code\windows\PhoneVR\Debug\x64" "C:\Program Files (x86)\Steam\steamapps\common\SteamVR\drivers\PVRServer\bin\win64" /h /i /c /k /e /r /y + +::CALL explorer "steam://rungameid/250820" + +:::LOOP +::tasklist | find /i "vrserver" >nul 2>&1 +::IF ERRORLEVEL 1 ( +:: ECHO vrserver is still starting +:: GOTO LOOP +::) ELSE ( +:: ECHO vrserver started +:: GOTO CONTINUE +::) + +:CONTINUE + +exit 0 \ No newline at end of file diff --git a/code/windows/PhoneVR/post_build_release.cmd b/code/windows/PhoneVR/post_build_release.cmd new file mode 100644 index 00000000..d913dc01 --- /dev/null +++ b/code/windows/PhoneVR/post_build_release.cmd @@ -0,0 +1,19 @@ +@ECHO OFF + +xcopy "C:\Users\narni\Documents\GitHub\PhoneVR\code\windows\PhoneVR\Release\x64" "C:\Program Files (x86)\Steam\steamapps\common\SteamVR\drivers\PVRServer\bin\win64" /h /i /c /k /e /r /y + +CALL explorer "steam://rungameid/250820" + +:LOOP +tasklist | find /i "vrserver" >nul 2>&1 +IF ERRORLEVEL 1 ( + ECHO vrserver is still starting + GOTO LOOP +) ELSE ( + ECHO vrserver started + GOTO CONTINUE +) + +:CONTINUE + +exit 0 \ No newline at end of file