diff --git a/OBS-All.sln b/OBS-All.sln
index 6d695367..b5db127e 100644
--- a/OBS-All.sln
+++ b/OBS-All.sln
@@ -46,6 +46,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PSVPlugin", "PSVPlugin\PSVP
{11A35235-DD48-41E2-8F40-825C78024BC0} = {11A35235-DD48-41E2-8F40-825C78024BC0}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QSVHelper", "QSVHelper\QSVHelper.vcxproj", "{F1C7033A-F050-46E3-9080-E129B9CD1010}"
+ ProjectSection(ProjectDependencies) = postProject
+ {9E7B3527-11AA-46BA-A82F-C58761F9B56F} = {9E7B3527-11AA-46BA-A82F-C58761F9B56F}
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -136,12 +141,12 @@ Global
{5465C79D-01DF-406C-AB2D-9C0764917131}.Release|x64.Build.0 = Release|x64
{9E7B3527-11AA-46BA-A82F-C58761F9B56F}.Debug|Win32.ActiveCfg = Debug|Win32
{9E7B3527-11AA-46BA-A82F-C58761F9B56F}.Debug|Win32.Build.0 = Debug|Win32
- {9E7B3527-11AA-46BA-A82F-C58761F9B56F}.Debug|x64.ActiveCfg = Debug|x64
- {9E7B3527-11AA-46BA-A82F-C58761F9B56F}.Debug|x64.Build.0 = Debug|x64
+ {9E7B3527-11AA-46BA-A82F-C58761F9B56F}.Debug|x64.ActiveCfg = Debug|Win32
+ {9E7B3527-11AA-46BA-A82F-C58761F9B56F}.Debug|x64.Build.0 = Debug|Win32
{9E7B3527-11AA-46BA-A82F-C58761F9B56F}.Release|Win32.ActiveCfg = Release|Win32
{9E7B3527-11AA-46BA-A82F-C58761F9B56F}.Release|Win32.Build.0 = Release|Win32
- {9E7B3527-11AA-46BA-A82F-C58761F9B56F}.Release|x64.ActiveCfg = Release|x64
- {9E7B3527-11AA-46BA-A82F-C58761F9B56F}.Release|x64.Build.0 = Release|x64
+ {9E7B3527-11AA-46BA-A82F-C58761F9B56F}.Release|x64.ActiveCfg = Release|Win32
+ {9E7B3527-11AA-46BA-A82F-C58761F9B56F}.Release|x64.Build.0 = Release|Win32
{D13C4DA1-A806-49D0-9603-AF40D34D0EF3}.Debug|Win32.ActiveCfg = Debug|Win32
{D13C4DA1-A806-49D0-9603-AF40D34D0EF3}.Debug|Win32.Build.0 = Debug|Win32
{D13C4DA1-A806-49D0-9603-AF40D34D0EF3}.Debug|x64.ActiveCfg = Debug|x64
@@ -150,6 +155,14 @@ Global
{D13C4DA1-A806-49D0-9603-AF40D34D0EF3}.Release|Win32.Build.0 = Release|Win32
{D13C4DA1-A806-49D0-9603-AF40D34D0EF3}.Release|x64.ActiveCfg = Release|x64
{D13C4DA1-A806-49D0-9603-AF40D34D0EF3}.Release|x64.Build.0 = Release|x64
+ {F1C7033A-F050-46E3-9080-E129B9CD1010}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F1C7033A-F050-46E3-9080-E129B9CD1010}.Debug|Win32.Build.0 = Debug|Win32
+ {F1C7033A-F050-46E3-9080-E129B9CD1010}.Debug|x64.ActiveCfg = Debug|Win32
+ {F1C7033A-F050-46E3-9080-E129B9CD1010}.Debug|x64.Build.0 = Debug|Win32
+ {F1C7033A-F050-46E3-9080-E129B9CD1010}.Release|Win32.ActiveCfg = Release|Win32
+ {F1C7033A-F050-46E3-9080-E129B9CD1010}.Release|Win32.Build.0 = Release|Win32
+ {F1C7033A-F050-46E3-9080-E129B9CD1010}.Release|x64.ActiveCfg = Release|Win32
+ {F1C7033A-F050-46E3-9080-E129B9CD1010}.Release|x64.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/OBS.vcxproj b/OBS.vcxproj
index 00cbbf51..f6d448ef 100644
--- a/OBS.vcxproj
+++ b/OBS.vcxproj
@@ -112,10 +112,10 @@
/ignore:4049 /ignore:4217 %(AdditionalOptions)
- Avrt.lib;dwmapi.lib;comctl32.lib;dxgi.lib;dxguid.lib;d3d10_1.lib;d3dx10.lib;ws2_32.lib;Iphlpapi.lib;Winmm.lib;librtmp.lib;libmp3lame-static.lib;libfaac.lib;dsound.lib;obsapi.lib;shell32.lib;gdiplus.lib;mfplat.lib;Mfuuid.lib;Winhttp.lib;libx264.lib;UxTheme.lib;libmfx.lib;%(AdditionalDependencies)
+ Avrt.lib;dwmapi.lib;comctl32.lib;dxgi.lib;dxguid.lib;d3d10_1.lib;d3dx10.lib;ws2_32.lib;Iphlpapi.lib;Winmm.lib;librtmp.lib;libmp3lame-static.lib;libfaac.lib;dsound.lib;obsapi.lib;shell32.lib;gdiplus.lib;mfplat.lib;Mfuuid.lib;Winhttp.lib;libx264.lib;UxTheme.lib;%(AdditionalDependencies)
- libmfx/$(Platform)/$(Configuration);OBSApi/Debug;x264/libs/32bit;librtmp/debug;lame/output/32bit;libfaac/debug;%(AdditionalLibraryDirectories)
+ OBSApi/Debug;x264/libs/32bit;librtmp/debug;lame/output/32bit;libfaac/debug;%(AdditionalLibraryDirectories)
type=%27win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27X86%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)
true
rundir\pdb32\$(TargetName).pdb
@@ -147,10 +147,10 @@
Main.h
- Avrt.lib;dwmapi.lib;comctl32.lib;dxgi.lib;dxguid.lib;d3d10_1.lib;d3dx10.lib;ws2_32.lib;Iphlpapi.lib;Winmm.lib;librtmp.lib;libmp3lame-static.lib;libfaac.lib;dsound.lib;obsapi.lib;shell32.lib;gdiplus.lib;mfplat.lib;Mfuuid.lib;Winhttp.lib;libx264.lib;UxTheme.lib;libmfx.lib;%(AdditionalDependencies)
+ Avrt.lib;dwmapi.lib;comctl32.lib;dxgi.lib;dxguid.lib;d3d10_1.lib;d3dx10.lib;ws2_32.lib;Iphlpapi.lib;Winmm.lib;librtmp.lib;libmp3lame-static.lib;libfaac.lib;dsound.lib;obsapi.lib;shell32.lib;gdiplus.lib;mfplat.lib;Mfuuid.lib;Winhttp.lib;libx264.lib;UxTheme.lib;%(AdditionalDependencies)
- libmfx/$(Platform)/$(Configuration);OBSApi/x64/Debug;x264/libs/64bit;librtmp/x64/debug;lame/output/64bit;libfaac/x64/debug;%(AdditionalLibraryDirectories)
+ OBSApi/x64/Debug;x264/libs/64bit;librtmp/x64/debug;lame/output/64bit;libfaac/x64/debug;%(AdditionalLibraryDirectories)
type=%27win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27amd64%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)
true
rundir\pdb64\$(TargetName).pdb
@@ -180,10 +180,10 @@
/ignore:4049 /ignore:4217 %(AdditionalOptions)
- Avrt.lib;dwmapi.lib;comctl32.lib;dxgi.lib;dxguid.lib;d3d10_1.lib;d3dx10.lib;ws2_32.lib;Iphlpapi.lib;Winmm.lib;librtmp.lib;libmp3lame-static.lib;libfaac.lib;dsound.lib;obsapi.lib;shell32.lib;gdiplus.lib;mfplat.lib;Mfuuid.lib;Winhttp.lib;libx264.lib;UxTheme.lib;libmfx.lib;%(AdditionalDependencies)
+ Avrt.lib;dwmapi.lib;comctl32.lib;dxgi.lib;dxguid.lib;d3d10_1.lib;d3dx10.lib;ws2_32.lib;Iphlpapi.lib;Winmm.lib;librtmp.lib;libmp3lame-static.lib;libfaac.lib;dsound.lib;obsapi.lib;shell32.lib;gdiplus.lib;mfplat.lib;Mfuuid.lib;Winhttp.lib;libx264.lib;UxTheme.lib;%(AdditionalDependencies)
- libmfx/$(Platform)/$(Configuration);OBSApi/Release;x264/libs/32bit;librtmp/release;lame/output/32bit;libfaac/release;%(AdditionalLibraryDirectories)
+ OBSApi/Release;x264/libs/32bit;librtmp/release;lame/output/32bit;libfaac/release;%(AdditionalLibraryDirectories)
type=%27Win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27X86%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)
true
rundir\pdb32\$(TargetName).pdb
@@ -218,10 +218,10 @@
Main.h
- Avrt.lib;dwmapi.lib;comctl32.lib;dxgi.lib;dxguid.lib;d3d10_1.lib;d3dx10.lib;ws2_32.lib;Iphlpapi.lib;Winmm.lib;librtmp.lib;libmp3lame-static.lib;libfaac.lib;dsound.lib;obsapi.lib;shell32.lib;gdiplus.lib;mfplat.lib;Mfuuid.lib;Winhttp.lib;libx264.lib;UxTheme.lib;libmfx.lib;%(AdditionalDependencies)
+ Avrt.lib;dwmapi.lib;comctl32.lib;dxgi.lib;dxguid.lib;d3d10_1.lib;d3dx10.lib;ws2_32.lib;Iphlpapi.lib;Winmm.lib;librtmp.lib;libmp3lame-static.lib;libfaac.lib;dsound.lib;obsapi.lib;shell32.lib;gdiplus.lib;mfplat.lib;Mfuuid.lib;Winhttp.lib;libx264.lib;UxTheme.lib;%(AdditionalDependencies)
- libmfx/$(Platform)/$(Configuration);OBSApi/x64/Release;x264/libs/64bit;librtmp/x64/release;lame/output/64bit;libfaac/x64/release;%(AdditionalLibraryDirectories)
+ OBSApi/x64/Release;x264/libs/64bit;librtmp/x64/release;lame/output/64bit;libfaac/x64/release;%(AdditionalLibraryDirectories)
type=%27win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27amd64%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)
true
rundir\pdb64\$(TargetName).pdb
diff --git a/QSVHelper/Encoder.h b/QSVHelper/Encoder.h
new file mode 100644
index 00000000..a18526af
--- /dev/null
+++ b/QSVHelper/Encoder.h
@@ -0,0 +1,436 @@
+/********************************************************************************
+ Copyright (C) 2013 Ruwen Hahn
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+********************************************************************************/
+
+#pragma once
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include "d3d11_allocator.h"
+#include "d3d11_device.h"
+
+#include "IPCInfo.h"
+#include "IPCStructs.h"
+#include "SupportStuff.h"
+#include "WindowsStuff.h"
+
+struct Encoder
+{
+ bool use_cbr;
+
+ bool first_frame;
+
+ unsigned frame_time_ms;
+
+ int exit_code;
+
+ mfxIMPL requested, actual;
+ mfxVersion version;
+
+
+ Parameters params;
+ mfxFrameAllocRequest req;
+ mfxFrameAllocResponse alloc_res;
+
+
+ bool using_d3d11;
+ CD3D11Device d3d11;
+ D3D11FrameAllocator d3d11_alloc;
+
+
+ MFXVideoSession session;
+ MFXVideoENCODE encoder;
+
+
+ std::wstring event_prefix;
+
+ ipc_bitstream_buff bitstream;
+ ipc_filled_bitstream filled_bitstream;
+ ipc_bitstream_info bs_info;
+
+ ipc_frame_buff frame_buff;
+ ipc_frame_buff_status frame_buff_status;
+ ipc_frame_queue frame_queue;
+
+ ipc_sps_buff sps_buffer;
+ ipc_pps_buff pps_buffer;
+ ipc_spspps_size spspps_queried_size;
+
+
+ std::vector encode_tasks;
+ std::queue idle_tasks, queued_tasks, encoded_tasks;
+
+ std::vector surfaces;
+ std::queue idle_surfaces;
+ std::vector> msdk_locked_tasks;
+
+ std::vector frames;
+
+
+ EncodeCtrl keyframe_ctrl, sei_ctrl;
+
+
+ std::wofstream &log_file;
+
+
+ operator bool() { return static_cast(session) != nullptr; }
+
+ Encoder(IPCSignalledType &init_req, std::wstring event_prefix, std::wofstream &log_file)
+ : use_cbr(init_req->use_cbr), first_frame(true), frame_time_ms(static_cast(1./init_req->fps*1000)), exit_code(0)
+ , using_d3d11(false), session(), encoder(session), event_prefix(event_prefix), log_file(log_file)
+ {
+ params.Init(init_req->fps, init_req->keyint, init_req->bframes, init_req->width, init_req->height, init_req->max_bitrate, init_req->buffer_size, init_req->use_cbr);
+ params.SetVideoSignalInfo(init_req->full_range, init_req->primaries, init_req->transfer, init_req->matrix);
+ }
+
+ template
+ mfxStatus InitializeMFX(T& impl, bool force=false)
+ {
+ session.Close();
+
+ version = impl.version;
+ requested = impl.type | impl.intf;
+ auto result = session.Init(requested, &version);
+ if(result < 0) return result;
+
+ session.QueryIMPL(&actual);
+
+ if(using_d3d11 = (actual & MFX_IMPL_VIA_D3D11) == MFX_IMPL_VIA_D3D11)
+ {
+ mfxU32 device = 0;
+ switch(MFX_IMPL_BASETYPE(actual))
+ {
+ case MFX_IMPL_HARDWARE: device = 0; break;
+ case MFX_IMPL_HARDWARE2: device = 1; break;
+ case MFX_IMPL_HARDWARE3: device = 2; break;
+ case MFX_IMPL_HARDWARE4: device = 3; break;
+ default: exit_code = 1000; return MFX_ERR_DEVICE_FAILED;
+ }
+
+ d3d11.Init(nullptr, 1, device);
+ mfxHDL hdl = nullptr;
+ d3d11.GetHandle(MFX_HANDLE_D3D11_DEVICE, &hdl);
+ session.SetHandle(MFX_HANDLE_D3D11_DEVICE, hdl);
+
+ D3D11AllocatorParams alloc_params;
+ alloc_params.pDevice = reinterpret_cast(hdl);
+ d3d11_alloc.Init(&alloc_params);
+ session.SetFrameAllocator(&d3d11_alloc);
+ params->IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY;
+ }
+
+ encoder = MFXVideoENCODE(session);
+
+ zero(req);
+ result = encoder.QueryIOSurf(¶ms, &req);
+ return result;
+ }
+
+ void InitializeBuffers(ipc_init_response &init_res)
+ {
+ using namespace std;
+ Parameters query = params;
+ encoder.GetVideoParam(query);
+
+ unsigned num_bitstreams = max(6, req.NumFrameSuggested + query->AsyncDepth)+3, //+NUM_OUT_BUFFERS
+ num_surf = num_bitstreams * (using_d3d11 ? 2 : 1),
+ num_frames = using_d3d11 ? num_bitstreams : num_surf,
+ num_d3d11_frames = num_surf;
+
+ encode_tasks.resize(num_bitstreams);
+
+ const unsigned bs_size = (max(query->mfx.BufferSizeInKB*1000, params->mfx.BufferSizeInKB*1000)+31)/32*32;
+ params->mfx.BufferSizeInKB = bs_size/1000;
+ init_res->bitstream_size = bs_size;
+
+ bitstream = ipc_bitstream_buff(event_prefix + BITSTREAM_BUFF, encode_tasks.size() * bs_size + 31);
+ mfxU8 *bs_start = (mfxU8*)(((size_t)&bitstream + 31)/32*32);
+ size_t index = 0;
+ for(auto task = begin(encode_tasks); task != end(encode_tasks); task++, index++)
+ {
+ task->Init(bs_start, bs_size);
+ idle_tasks.push(index);
+ bs_start += bs_size;
+ }
+
+ filled_bitstream = ipc_filled_bitstream(event_prefix + FILLED_BITSTREAM);
+ {
+ auto lock = lock_mutex(filled_bitstream);
+ *filled_bitstream = -1;
+ }
+
+ bs_info = ipc_bitstream_info(event_prefix + BITSTREAM_INFO, encode_tasks.size());
+
+
+ if(using_d3d11)
+ {
+ req.NumFrameSuggested = num_d3d11_frames;
+ d3d11_alloc.AllocFrames(&req, &alloc_res);
+ }
+
+ mfxFrameInfo &fi = params->mfx.FrameInfo;
+
+ surfaces.resize(num_surf);
+ for(size_t i = 0; i < surfaces.size(); i++)
+ {
+ idle_surfaces.emplace(&surfaces[i]);
+ memcpy(&surfaces[i].Info, &fi, sizeof(fi));
+ if(using_d3d11)
+ surfaces[i].Data.MemId = alloc_res.mids[i];
+ }
+
+ const unsigned lum_channel_size = fi.Width*fi.Height,
+ uv_channel_size = fi.Width*fi.Height,
+ frame_size = lum_channel_size + uv_channel_size;
+ init_res->frame_size = frame_size;
+ init_res->UV_offset = lum_channel_size;
+ init_res->V_offset = lum_channel_size+1;
+ init_res->frame_pitch = fi.Width;
+
+ frames.resize(num_frames);
+ frame_queue = ipc_frame_queue(event_prefix + FRAME_QUEUE, frames.size());
+ {
+ auto lock = lock_mutex(frame_queue);
+ zero(*static_cast(frame_queue), sizeof(queued_frame) * frame_queue.size);
+ }
+
+ frame_buff = ipc_frame_buff(event_prefix + FRAME_BUFF, frames.size() * frame_size + 15);
+ mfxU8 *frame_start = (mfxU8*)(((size_t)&frame_buff + 15)/16*16);
+ zero(*frame_start, frame_size * frames.size());
+ for(auto frame = begin(frames); frame != end(frames); frame++)
+ {
+ InitFrame(*frame, frame_start, frame_start + init_res->UV_offset, frame_start + init_res->V_offset, fi.Width);
+ frame_start += frame_size;
+ }
+
+ frame_buff_status = ipc_frame_buff_status(event_prefix + FRAME_BUFF_STATUS, frames.size());
+ {
+ auto lock = lock_mutex(frame_buff_status);
+ zero(frame_buff_status[0], frames.size() * sizeof(uint32_t));
+ }
+
+ init_res->target_usage = params->mfx.TargetUsage;
+ init_res->bitstream_num = encode_tasks.size();
+ init_res->frame_num = frames.size();
+
+ keyframe_ctrl.ctrl.FrameType = MFX_FRAMETYPE_I | MFX_FRAMETYPE_REF | MFX_FRAMETYPE_IDR;
+ sei_ctrl.AddSEIData(EncodeCtrl::SEI_USER_DATA_UNREGISTERED, InitSEIUserData(use_cbr, query, init_res->version));
+ }
+
+ mfxStatus InitializeEncoder()
+ {
+ return encoder.Init(params);
+ }
+
+ void RequestSPSPPS()
+ {
+ sps_buffer = ipc_sps_buff(event_prefix + SPS_BUFF, 100);
+ pps_buffer = ipc_pps_buff(event_prefix + PPS_BUFF, 100);
+ Parameters spspps_query;
+ spspps_query.SetCodingOptionSPSPPS(sps_buffer, sps_buffer.size, pps_buffer, pps_buffer.size);
+ encoder.GetVideoParam(spspps_query);
+ spspps_queried_size = ipc_spspps_size(event_prefix + SPSPPS_SIZES);
+ spspps_queried_size->sps_size = spspps_query.cospspps.SPSBufSize;
+ spspps_queried_size->pps_size = spspps_query.cospspps.PPSBufSize;
+ spspps_queried_size.signal();
+ }
+
+ void ProcessEncodedFrame()
+ {
+ if(encoded_tasks.size())
+ {
+ encode_task& task = encode_tasks[encoded_tasks.front()];
+ auto& sp = task.sp;
+
+ auto result = MFXVideoCORE_SyncOperation(session, sp, 0);
+ if(result == MFX_WRN_IN_EXECUTION)
+ return;
+
+ bitstream_info &info = bs_info[encoded_tasks.front()];
+ info.time_stamp = task.bs.TimeStamp;
+ info.data_length = task.bs.DataLength;
+ info.data_offset = task.bs.DataOffset;
+ info.pic_struct = task.bs.PicStruct;
+ info.frame_type = task.bs.FrameType;
+
+ {
+ auto lock = lock_mutex(filled_bitstream);
+ if(*filled_bitstream >= 0)
+ return;
+ *filled_bitstream = encoded_tasks.front();
+ }
+ filled_bitstream.signal();
+
+ msdk_locked_tasks.emplace_back(std::make_pair(task.surf, task.frame_index));
+ task.surf = nullptr;
+ idle_tasks.emplace(encoded_tasks.front());
+ encoded_tasks.pop();
+ }
+ }
+
+ void UnlockSurfaces()
+ {
+ for(size_t i = 0; i < msdk_locked_tasks.size();)
+ {
+ auto pair = msdk_locked_tasks[i];
+ if(pair.first->Data.Locked)
+ {
+ i += 1;
+ continue;
+ }
+
+ msdk_locked_tasks.erase(std::begin(msdk_locked_tasks)+i);
+
+ idle_surfaces.emplace(pair.first);
+
+ if(!using_d3d11)
+ {
+ auto lock = lock_mutex(frame_buff_status);
+ frame_buff_status[pair.second] -= 1;
+ }
+ }
+ }
+
+ void QueueTask()
+ {
+ using namespace std;
+
+ for(;;)
+ {
+ if(idle_tasks.empty())
+ {
+ log_file << "Warning: idle_tasks is empty (" << idle_tasks.size() << " idle, " << queued_tasks.size() << " queued, "
+ << encoded_tasks.size() << " encoded, " << msdk_locked_tasks.size() << " locked)\n";
+ return;
+ }
+
+ if(idle_surfaces.empty())
+ {
+ log_file << "Warning: idle_surfaces is empty (" << idle_tasks.size() << " idle, " << queued_tasks.size() << " queued, "
+ << encoded_tasks.size() << " encoded, " << msdk_locked_tasks.size() << " locked)\n";
+ return;
+ }
+
+ auto end = static_cast(frame_queue)+frame_queue.size;
+ auto lock = lock_mutex(frame_queue);
+ auto oldest = min_element(static_cast(frame_queue), end, [](const queued_frame &f1, const queued_frame &f2) -> bool
+ {
+ if(f1.is_new)
+ if(f2.is_new)
+ return f1.timestamp < f2.timestamp;
+ else
+ return true;
+ return false;
+ });
+ if(!oldest || !oldest->is_new)
+ return;
+
+ oldest->is_new = false;
+
+ auto index = idle_tasks.front();
+ queued_tasks.push(index);
+ idle_tasks.pop();
+
+ encode_task &task = encode_tasks[index];
+ task.bs.DataLength = 0;
+ task.bs.DataOffset = 0;
+
+ task.surf = idle_surfaces.front();
+ idle_surfaces.pop();
+
+ mfxFrameData &frame = frames[oldest->frame_index];
+ if(using_d3d11)
+ {
+ d3d11_alloc.LockFrame(task.surf->Data.MemId, &task.surf->Data);
+ for(size_t i = 0; i < task.surf->Info.Height; i++)
+ memcpy(task.surf->Data.Y+i*task.surf->Data.Pitch, frame.Y+i*frame.Pitch, task.surf->Info.Width);
+ for(size_t i = 0; i < (task.surf->Info.Height/2u); i++)
+ memcpy(task.surf->Data.UV+i*task.surf->Data.Pitch, frame.UV+i*frame.Pitch, task.surf->Info.Width);
+ d3d11_alloc.UnlockFrame(task.surf->Data.MemId, &task.surf->Data);
+ auto lock = lock_mutex(frame_buff_status);
+ frame_buff_status[oldest->frame_index] -= 1;
+ }
+ else
+ {
+ task.surf->Data.Y = frame.Y;
+ task.surf->Data.UV = frame.UV;
+ task.surf->Data.V = frame.V;
+ task.surf->Data.Pitch = frame.Pitch;
+ }
+ task.surf->Data.TimeStamp = oldest->timestamp;
+ task.frame_index = oldest->frame_index;
+
+ if(oldest->request_keyframe)
+ task.ctrl = &keyframe_ctrl;
+ else
+ task.ctrl = nullptr;
+
+ if(first_frame)
+ task.ctrl = &sei_ctrl;
+ first_frame = false;
+ }
+ }
+
+ void EncodeTasks()
+ {
+ while(queued_tasks.size())
+ {
+ encode_task& task = encode_tasks[queued_tasks.front()];
+ for(;;)
+ {
+ auto sts = encoder.EncodeFrameAsync(task.ctrl, task.surf, &task.bs, &task.sp);
+
+ if(sts == MFX_ERR_NONE || (MFX_ERR_NONE < sts && task.sp))
+ break;
+ if(sts == MFX_WRN_DEVICE_BUSY)
+ return;
+ if(sts == MFX_ERR_NOT_INITIALIZED) //returned after encoder.Init returns PARTIAL_ACCELERATION?
+ {
+ exit_code = EXIT_INCOMPATIBLE_CONFIGURATION;
+ return;
+ }
+ //if(!sp); //sts == MFX_ERR_MORE_DATA usually; retry the call (see MSDK examples)
+ //Log(TEXT("returned status %i, %u"), sts, insert);
+ }
+ encoded_tasks.push(queued_tasks.front());
+ queued_tasks.pop();
+ }
+ }
+
+ int EncodeLoop(IPCSignal &stop, safe_handle &obs_handle)
+ {
+ IPCWaiter waiter;
+ waiter.push_back(stop.signal_);
+ waiter.push_back(obs_handle);
+ waiter.push_back(frame_queue.signal_);
+
+ for(;;)
+ {
+ if(waiter.wait_for_two(0, 1, frame_time_ms/2) || exit_code)
+ return exit_code;
+ ProcessEncodedFrame();
+ UnlockSurfaces();
+ QueueTask();
+ EncodeTasks();
+ }
+ }
+};
\ No newline at end of file
diff --git a/QSVHelper/IPCInfo.h b/QSVHelper/IPCInfo.h
new file mode 100644
index 00000000..4f6a5126
--- /dev/null
+++ b/QSVHelper/IPCInfo.h
@@ -0,0 +1,64 @@
+/********************************************************************************
+ Copyright (C) 2013 Ruwen Hahn
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+********************************************************************************/
+
+#pragma once
+
+#include
+
+#include "IPCStructs.h"
+#include "WindowsStuff.h"
+
+
+#define INIT_REQUEST L"init_request"
+typedef IPCSignalledType ipc_init_request;
+
+#define INIT_RESPONSE L"init_response"
+typedef IPCSignalledType ipc_init_response;
+
+#define BITSTREAM_BUFF L"bitstream_buff"
+typedef NamedSharedMemory ipc_bitstream_buff;
+
+#define FILLED_BITSTREAM L"filled_bitstream"
+typedef IPCLockedSignalledType ipc_filled_bitstream;
+
+#define BITSTREAM_INFO L"bitstream_info"
+typedef IPCArray ipc_bitstream_info;
+
+#define FRAME_BUFF L"frame_buff"
+typedef NamedSharedMemory ipc_frame_buff;
+
+#define FRAME_BUFF_STATUS L"frame_buff_status"
+typedef IPCLockedSignalledArray ipc_frame_buff_status;
+
+#define FRAME_QUEUE L"frame_queue"
+typedef IPCLockedSignalledArray ipc_frame_queue;
+
+#define SPS_BUFF L"sps_buff"
+typedef IPCArray ipc_sps_buff;
+
+#define PPS_BUFF L"pps_buff"
+typedef IPCArray ipc_pps_buff;
+
+#define SPSPPS_SIZES L"spspps_size"
+typedef IPCSignalledType ipc_spspps_size;
+
+#define STOP_REQUEST L"stop"
+typedef IPCSignal ipc_stop;
+
+
+#define EXIT_INCOMPATIBLE_CONFIGURATION 10
\ No newline at end of file
diff --git a/QSVHelper/IPCStructs.h b/QSVHelper/IPCStructs.h
new file mode 100644
index 00000000..554c0b09
--- /dev/null
+++ b/QSVHelper/IPCStructs.h
@@ -0,0 +1,79 @@
+/********************************************************************************
+ Copyright (C) 2013 Ruwen Hahn
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+********************************************************************************/
+
+#pragma once
+
+#include
+
+#include
+
+#pragma pack(push)
+#pragma pack(1)
+
+struct init_request
+{
+ enum { MODE_QUERY, MODE_ENCODE } mode;
+ uint32_t obs_process_id;
+ int32_t fps, keyint, bframes, width, height, max_bitrate, buffer_size;
+ bool use_cbr;
+ int32_t full_range, matrix, primaries, transfer;
+ bool use_custom_impl;
+ mfxVersion custom_version;
+ mfxIMPL custom_impl, custom_intf;
+};
+
+struct init_response
+{
+ mfxU16 target_usage;
+ mfxVersion version;
+ mfxIMPL requested_impl,
+ actual_impl;
+
+ bool using_custom_impl;
+
+ uint16_t bitstream_num,
+ frame_num;
+ uint32_t bitstream_size,
+ frame_size,
+ UV_offset,
+ V_offset,
+ frame_pitch;
+};
+
+struct spspps_size
+{
+ mfxU16 sps_size,
+ pps_size;
+};
+
+struct queued_frame
+{
+ bool is_new;
+ bool request_keyframe;
+ mfxU64 timestamp;
+ uint32_t frame_index;
+};
+
+struct bitstream_info
+{
+ mfxU64 time_stamp;
+ mfxU32 data_offset, data_length;
+ mfxU16 pic_struct, frame_type;
+};
+
+#pragma pack(pop)
\ No newline at end of file
diff --git a/QSVHelper/IntelSupport/include/base_allocator.h b/QSVHelper/IntelSupport/include/base_allocator.h
new file mode 100644
index 00000000..19aa333d
--- /dev/null
+++ b/QSVHelper/IntelSupport/include/base_allocator.h
@@ -0,0 +1,177 @@
+/* ****************************************************************************** *\
+
+INTEL CORPORATION PROPRIETARY INFORMATION
+This software is supplied under the terms of a license agreement or nondisclosure
+agreement with Intel Corporation and may not be copied or disclosed except in
+accordance with the terms of that agreement
+Copyright(c) 2008-2012 Intel Corporation. All Rights Reserved.
+
+\* ****************************************************************************** */
+
+#ifndef __BASE_ALLOCATOR_H__
+#define __BASE_ALLOCATOR_H__
+
+#include
+#include
+#include
+#include "mfxvideo.h"
+
+struct mfxAllocatorParams
+{
+ virtual ~mfxAllocatorParams(){};
+};
+
+// this class implements methods declared in mfxFrameAllocator structure
+// simply redirecting them to virtual methods which should be overridden in derived classes
+class MFXFrameAllocator : public mfxFrameAllocator
+{
+public:
+ MFXFrameAllocator();
+ virtual ~MFXFrameAllocator();
+
+ // optional method, override if need to pass some parameters to allocator from application
+ virtual mfxStatus Init(mfxAllocatorParams *pParams) = 0;
+ virtual mfxStatus Close() = 0;
+
+ virtual mfxStatus AllocFrames(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response) = 0;
+ virtual mfxStatus LockFrame(mfxMemId mid, mfxFrameData *ptr) = 0;
+ virtual mfxStatus UnlockFrame(mfxMemId mid, mfxFrameData *ptr) = 0;
+ virtual mfxStatus GetFrameHDL(mfxMemId mid, mfxHDL *handle) = 0;
+ virtual mfxStatus FreeFrames(mfxFrameAllocResponse *response) = 0;
+
+private:
+ static mfxStatus MFX_CDECL Alloc_(mfxHDL pthis, mfxFrameAllocRequest *request, mfxFrameAllocResponse *response);
+ static mfxStatus MFX_CDECL Lock_(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr);
+ static mfxStatus MFX_CDECL Unlock_(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr);
+ static mfxStatus MFX_CDECL GetHDL_(mfxHDL pthis, mfxMemId mid, mfxHDL *handle);
+ static mfxStatus MFX_CDECL Free_(mfxHDL pthis, mfxFrameAllocResponse *response);
+};
+
+// This class implements basic logic of memory allocator
+// Manages responses for different components according to allocation request type
+// External frames of a particular component-related type are allocated in one call
+// Further calls return previously allocated response.
+// Ex. Preallocated frame chain with type=FROM_ENCODE | FROM_VPPIN will be returned when
+// request type contains either FROM_ENCODE or FROM_VPPIN
+
+// This class does not allocate any actual memory
+class BaseFrameAllocator: public MFXFrameAllocator
+{
+public:
+ BaseFrameAllocator();
+ virtual ~BaseFrameAllocator();
+
+ virtual mfxStatus Init(mfxAllocatorParams *pParams) = 0;
+ virtual mfxStatus Close();
+ virtual mfxStatus AllocFrames(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response);
+ virtual mfxStatus FreeFrames(mfxFrameAllocResponse *response);
+
+protected:
+ typedef std::list::iterator Iter;
+ static const mfxU32 MEMTYPE_FROM_MASK = MFX_MEMTYPE_FROM_ENCODE | MFX_MEMTYPE_FROM_DECODE | MFX_MEMTYPE_FROM_VPPIN | MFX_MEMTYPE_FROM_VPPOUT;
+
+ struct UniqueResponse
+ : mfxFrameAllocResponse
+ {
+ mfxU16 m_cropw;
+ mfxU16 m_croph;
+ mfxU32 m_refCount;
+ mfxU16 m_type;
+
+ UniqueResponse()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+
+ // compare responses by actual frame size, alignment (w and h) is up to application
+ UniqueResponse(const mfxFrameAllocResponse & response, mfxU16 cropw, mfxU16 croph, mfxU16 type)
+ : mfxFrameAllocResponse(response)
+ , m_type(type)
+ , m_refCount(1)
+ , m_cropw(cropw)
+ , m_croph(croph)
+ {
+ }
+ //compare by resolution
+ bool operator () (const UniqueResponse &response)const
+ {
+ return m_cropw == response.m_cropw && m_croph == response.m_croph;
+ }
+ };
+
+ std::list m_responses;
+ std::list m_ExtResponses;
+
+ struct IsSame
+ : public std::binary_function
+ {
+ bool operator () (const mfxFrameAllocResponse & l, const mfxFrameAllocResponse &r)const
+ {
+ return r.mids != 0 && l.mids != 0 &&
+ r.mids[0] == l.mids[0] &&
+ r.NumFrameActual == l.NumFrameActual;
+ }
+ };
+
+ // checks if request is supported
+ virtual mfxStatus CheckRequestType(mfxFrameAllocRequest *request);
+
+ // frees memory attached to response
+ virtual mfxStatus ReleaseResponse(mfxFrameAllocResponse *response) = 0;
+ // allocates memory
+ virtual mfxStatus AllocImpl(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response) = 0;
+
+ template
+ class safe_array
+ {
+ public:
+ safe_array(T *ptr = 0):m_ptr(ptr)
+ { // construct from object pointer
+ };
+ ~safe_array()
+ {
+ reset(0);
+ }
+ T* get()
+ { // return wrapped pointer
+ return m_ptr;
+ }
+ T* release()
+ { // return wrapped pointer and give up ownership
+ T* ptr = m_ptr;
+ m_ptr = 0;
+ return ptr;
+ }
+ void reset(T* ptr)
+ { // destroy designated object and store new pointer
+ if (m_ptr)
+ {
+ delete[] m_ptr;
+ }
+ m_ptr = ptr;
+ }
+ protected:
+ T* m_ptr; // the wrapped object pointer
+ };
+};
+
+class MFXBufferAllocator : public mfxBufferAllocator
+{
+public:
+ MFXBufferAllocator();
+ virtual ~MFXBufferAllocator();
+
+ virtual mfxStatus AllocBuffer(mfxU32 nbytes, mfxU16 type, mfxMemId *mid) = 0;
+ virtual mfxStatus LockBuffer(mfxMemId mid, mfxU8 **ptr) = 0;
+ virtual mfxStatus UnlockBuffer(mfxMemId mid) = 0;
+ virtual mfxStatus FreeBuffer(mfxMemId mid) = 0;
+
+private:
+ static mfxStatus MFX_CDECL Alloc_(mfxHDL pthis, mfxU32 nbytes, mfxU16 type, mfxMemId *mid);
+ static mfxStatus MFX_CDECL Lock_(mfxHDL pthis, mfxMemId mid, mfxU8 **ptr);
+ static mfxStatus MFX_CDECL Unlock_(mfxHDL pthis, mfxMemId mid);
+ static mfxStatus MFX_CDECL Free_(mfxHDL pthis, mfxMemId mid);
+};
+
+
+#endif // __BASE_ALLOCATOR_H__
\ No newline at end of file
diff --git a/QSVHelper/IntelSupport/include/current_date.h b/QSVHelper/IntelSupport/include/current_date.h
new file mode 100644
index 00000000..2dd2d029
--- /dev/null
+++ b/QSVHelper/IntelSupport/include/current_date.h
@@ -0,0 +1,18 @@
+
+#define CURRENT_DATE "Build_2013/6/27"
+
+#define PRODUCT_NAME "Intel® Media SDK"
+
+#define FILE_VERSION 4,13,6,27
+
+#define FILE_VERSION_STRING "4,13,6,27"
+
+#define FILTER_NAME_PREFIX "Intel® Media SDK"
+
+#define FILTER_NAME_SUFFIX ""
+
+#define PRODUCT_COPYRIGHT "Copyright© 2003-2013 Intel Corporation"
+
+#define PRODUCT_VERSION 4,0,760,0
+
+#define PRODUCT_VERSION_STRING "4,0,760,0"
diff --git a/QSVHelper/IntelSupport/include/d3d11_allocator.h b/QSVHelper/IntelSupport/include/d3d11_allocator.h
new file mode 100644
index 00000000..2a6029da
--- /dev/null
+++ b/QSVHelper/IntelSupport/include/d3d11_allocator.h
@@ -0,0 +1,253 @@
+/* ****************************************************************************** *\
+
+INTEL CORPORATION PROPRIETARY INFORMATION
+This software is supplied under the terms of a license agreement or nondisclosure
+agreement with Intel Corporation and may not be copied or disclosed except in
+accordance with the terms of that agreement
+Copyright(c) 2011-2013 Intel Corporation. All Rights Reserved.
+
+\* ****************************************************************************** */
+
+#ifndef __D3D11_ALLOCATOR_H__
+#define __D3D11_ALLOCATOR_H__
+
+// defines MFX_D3D11_SUPPORT
+#include "sample_defs.h"
+
+#include "base_allocator.h"
+#include
+
+//application can provide either generic mid from surface or this wrapper
+//wrapper distinguishes from generic mid by highest 1 bit
+//if it set then remained pointer points to extended structure of memid
+//64 bits system layout
+/*----+-----------------------------------------------------------+
+|b63=1|63 bits remained for pointer to extended structure of memid|
+|b63=0|63 bits from original mfxMemId |
++-----+----------------------------------------------------------*/
+//32 bits system layout
+/*--+---+--------------------------------------------+
+|b31=1|31 bits remained for pointer to extended memid|
+|b31=0|31 bits remained for surface pointer |
++---+---+-------------------------------------------*/
+//#pragma warning (disable:4293)
+class MFXReadWriteMid
+{
+ static const uintptr_t bits_offset = std::numeric_limits::digits - 1;
+ static const uintptr_t clear_mask = ~((uintptr_t)1 << bits_offset);
+public:
+ enum
+ {
+ //if flag not set it means that read and write
+ not_set = 0,
+ reuse = 1,
+ read = 2,
+ write = 4,
+ };
+ //here mfxmemid might be as MFXReadWriteMid or mfxMemId memid
+ MFXReadWriteMid(mfxMemId mid, mfxU8 flag = not_set)
+ {
+ //setup mid
+ m_mid_to_report = (mfxMemId)((uintptr_t)&m_mid | ((uintptr_t)1 << bits_offset));
+ if (0 != ((uintptr_t)mid >> bits_offset))
+ {
+ //it points to extended structure
+ mfxMedIdEx * pMemIdExt = reinterpret_cast((uintptr_t)mid & clear_mask);
+ m_mid.pId = pMemIdExt->pId;
+ if (reuse == flag)
+ {
+ m_mid.read_write = pMemIdExt->read_write;
+ }
+ else
+ {
+ m_mid.read_write = flag;
+ }
+ }
+ else
+ {
+ m_mid.pId = mid;
+ if (reuse == flag)
+ m_mid.read_write = not_set;
+ else
+ m_mid.read_write = flag;
+ }
+
+ }
+ bool isRead() const
+ {
+ return 0 != (m_mid.read_write & read) || !m_mid.read_write;
+ }
+ bool isWrite() const
+ {
+ return 0 != (m_mid.read_write & write) || !m_mid.read_write;
+ }
+ /// returns original memid without read write flags
+ mfxMemId raw() const
+ {
+ return m_mid.pId;
+ }
+ operator mfxMemId() const
+ {
+ return m_mid_to_report;
+ }
+
+private:
+ struct mfxMedIdEx
+ {
+ mfxMemId pId;
+ mfxU8 read_write;
+ };
+
+ mfxMedIdEx m_mid;
+ mfxMemId m_mid_to_report;
+};
+
+#if MFX_D3D11_SUPPORT
+
+#include
+#include
+#include