Moved QSV encoder implementation to QSVHelper

Notable improvements:
- fixes d3d11 mode on all tested configurations
- should improve compatibility with Optimus (untested)
This commit is contained in:
palana 2013-09-25 21:36:21 +02:00
parent 9ef424ade8
commit 134a13c80d
28 changed files with 3817 additions and 757 deletions

View File

@ -46,6 +46,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PSVPlugin", "PSVPlugin\PSVP
{11A35235-DD48-41E2-8F40-825C78024BC0} = {11A35235-DD48-41E2-8F40-825C78024BC0} {11A35235-DD48-41E2-8F40-825C78024BC0} = {11A35235-DD48-41E2-8F40-825C78024BC0}
EndProjectSection EndProjectSection
EndProject 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 Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32 Debug|Win32 = Debug|Win32
@ -136,12 +141,12 @@ Global
{5465C79D-01DF-406C-AB2D-9C0764917131}.Release|x64.Build.0 = Release|x64 {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.ActiveCfg = Debug|Win32
{9E7B3527-11AA-46BA-A82F-C58761F9B56F}.Debug|Win32.Build.0 = 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.ActiveCfg = Debug|Win32
{9E7B3527-11AA-46BA-A82F-C58761F9B56F}.Debug|x64.Build.0 = Debug|x64 {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.ActiveCfg = Release|Win32
{9E7B3527-11AA-46BA-A82F-C58761F9B56F}.Release|Win32.Build.0 = 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.ActiveCfg = Release|Win32
{9E7B3527-11AA-46BA-A82F-C58761F9B56F}.Release|x64.Build.0 = Release|x64 {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.ActiveCfg = Debug|Win32
{D13C4DA1-A806-49D0-9603-AF40D34D0EF3}.Debug|Win32.Build.0 = Debug|Win32 {D13C4DA1-A806-49D0-9603-AF40D34D0EF3}.Debug|Win32.Build.0 = Debug|Win32
{D13C4DA1-A806-49D0-9603-AF40D34D0EF3}.Debug|x64.ActiveCfg = Debug|x64 {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|Win32.Build.0 = Release|Win32
{D13C4DA1-A806-49D0-9603-AF40D34D0EF3}.Release|x64.ActiveCfg = Release|x64 {D13C4DA1-A806-49D0-9603-AF40D34D0EF3}.Release|x64.ActiveCfg = Release|x64
{D13C4DA1-A806-49D0-9603-AF40D34D0EF3}.Release|x64.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -112,10 +112,10 @@
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalOptions>/ignore:4049 /ignore:4217 %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/ignore:4049 /ignore:4217 %(AdditionalOptions)</AdditionalOptions>
<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;libmfx.lib;%(AdditionalDependencies)</AdditionalDependencies> <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)</AdditionalDependencies>
<Version> <Version>
</Version> </Version>
<AdditionalLibraryDirectories>libmfx/$(Platform)/$(Configuration);OBSApi/Debug;x264/libs/32bit;librtmp/debug;lame/output/32bit;libfaac/debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>OBSApi/Debug;x264/libs/32bit;librtmp/debug;lame/output/32bit;libfaac/debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalManifestDependencies>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)</AdditionalManifestDependencies> <AdditionalManifestDependencies>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)</AdditionalManifestDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>rundir\pdb32\$(TargetName).pdb</ProgramDatabaseFile> <ProgramDatabaseFile>rundir\pdb32\$(TargetName).pdb</ProgramDatabaseFile>
@ -147,10 +147,10 @@
<PrecompiledHeaderFile>Main.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>Main.h</PrecompiledHeaderFile>
</ClCompile> </ClCompile>
<Link> <Link>
<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;libmfx.lib;%(AdditionalDependencies)</AdditionalDependencies> <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)</AdditionalDependencies>
<Version> <Version>
</Version> </Version>
<AdditionalLibraryDirectories>libmfx/$(Platform)/$(Configuration);OBSApi/x64/Debug;x264/libs/64bit;librtmp/x64/debug;lame/output/64bit;libfaac/x64/debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>OBSApi/x64/Debug;x264/libs/64bit;librtmp/x64/debug;lame/output/64bit;libfaac/x64/debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalManifestDependencies>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)</AdditionalManifestDependencies> <AdditionalManifestDependencies>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)</AdditionalManifestDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>rundir\pdb64\$(TargetName).pdb</ProgramDatabaseFile> <ProgramDatabaseFile>rundir\pdb64\$(TargetName).pdb</ProgramDatabaseFile>
@ -180,10 +180,10 @@
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalOptions>/ignore:4049 /ignore:4217 %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/ignore:4049 /ignore:4217 %(AdditionalOptions)</AdditionalOptions>
<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;libmfx.lib;%(AdditionalDependencies)</AdditionalDependencies> <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)</AdditionalDependencies>
<Version> <Version>
</Version> </Version>
<AdditionalLibraryDirectories>libmfx/$(Platform)/$(Configuration);OBSApi/Release;x264/libs/32bit;librtmp/release;lame/output/32bit;libfaac/release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>OBSApi/Release;x264/libs/32bit;librtmp/release;lame/output/32bit;libfaac/release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalManifestDependencies>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)</AdditionalManifestDependencies> <AdditionalManifestDependencies>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)</AdditionalManifestDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>rundir\pdb32\$(TargetName).pdb</ProgramDatabaseFile> <ProgramDatabaseFile>rundir\pdb32\$(TargetName).pdb</ProgramDatabaseFile>
@ -218,10 +218,10 @@
<PrecompiledHeaderFile>Main.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>Main.h</PrecompiledHeaderFile>
</ClCompile> </ClCompile>
<Link> <Link>
<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;libmfx.lib;%(AdditionalDependencies)</AdditionalDependencies> <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)</AdditionalDependencies>
<Version> <Version>
</Version> </Version>
<AdditionalLibraryDirectories>libmfx/$(Platform)/$(Configuration);OBSApi/x64/Release;x264/libs/64bit;librtmp/x64/release;lame/output/64bit;libfaac/x64/release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>OBSApi/x64/Release;x264/libs/64bit;librtmp/x64/release;lame/output/64bit;libfaac/x64/release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalManifestDependencies>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)</AdditionalManifestDependencies> <AdditionalManifestDependencies>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)</AdditionalManifestDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>rundir\pdb64\$(TargetName).pdb</ProgramDatabaseFile> <ProgramDatabaseFile>rundir\pdb64\$(TargetName).pdb</ProgramDatabaseFile>

436
QSVHelper/Encoder.h Normal file
View File

@ -0,0 +1,436 @@
/********************************************************************************
Copyright (C) 2013 Ruwen Hahn <palana@stunned.de>
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 <mfxvideo++.h>
#include <algorithm>
#include <fstream>
#include <queue>
#include <vector>
#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_task> encode_tasks;
std::queue<size_t> idle_tasks, queued_tasks, encoded_tasks;
std::vector<mfxFrameSurface1> surfaces;
std::queue<mfxFrameSurface1*> idle_surfaces;
std::vector<std::pair<mfxFrameSurface1*, uint32_t>> msdk_locked_tasks;
std::vector<mfxFrameData> frames;
EncodeCtrl keyframe_ctrl, sei_ctrl;
std::wofstream &log_file;
operator bool() { return static_cast<mfxSession>(session) != nullptr; }
Encoder(IPCSignalledType<init_request> &init_req, std::wstring event_prefix, std::wofstream &log_file)
: use_cbr(init_req->use_cbr), first_frame(true), frame_time_ms(static_cast<unsigned>(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 <class T>
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<ID3D11Device*>(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(&params, &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<queued_frame*>(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<queued_frame*>(frame_queue)+frame_queue.size;
auto lock = lock_mutex(frame_queue);
auto oldest = min_element(static_cast<queued_frame*>(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();
}
}
};

64
QSVHelper/IPCInfo.h Normal file
View File

@ -0,0 +1,64 @@
/********************************************************************************
Copyright (C) 2013 Ruwen Hahn <palana@stunned.de>
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 <cstdint>
#include "IPCStructs.h"
#include "WindowsStuff.h"
#define INIT_REQUEST L"init_request"
typedef IPCSignalledType<init_request> ipc_init_request;
#define INIT_RESPONSE L"init_response"
typedef IPCSignalledType<init_response> ipc_init_response;
#define BITSTREAM_BUFF L"bitstream_buff"
typedef NamedSharedMemory ipc_bitstream_buff;
#define FILLED_BITSTREAM L"filled_bitstream"
typedef IPCLockedSignalledType<int32_t> ipc_filled_bitstream;
#define BITSTREAM_INFO L"bitstream_info"
typedef IPCArray<bitstream_info> ipc_bitstream_info;
#define FRAME_BUFF L"frame_buff"
typedef NamedSharedMemory ipc_frame_buff;
#define FRAME_BUFF_STATUS L"frame_buff_status"
typedef IPCLockedSignalledArray<uint32_t> ipc_frame_buff_status;
#define FRAME_QUEUE L"frame_queue"
typedef IPCLockedSignalledArray<queued_frame> ipc_frame_queue;
#define SPS_BUFF L"sps_buff"
typedef IPCArray<mfxU8> ipc_sps_buff;
#define PPS_BUFF L"pps_buff"
typedef IPCArray<mfxU8> ipc_pps_buff;
#define SPSPPS_SIZES L"spspps_size"
typedef IPCSignalledType<spspps_size> ipc_spspps_size;
#define STOP_REQUEST L"stop"
typedef IPCSignal ipc_stop;
#define EXIT_INCOMPATIBLE_CONFIGURATION 10

79
QSVHelper/IPCStructs.h Normal file
View File

@ -0,0 +1,79 @@
/********************************************************************************
Copyright (C) 2013 Ruwen Hahn <palana@stunned.de>
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 <mfxvideo++.h>
#include <cstdint>
#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)

View File

@ -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 <list>
#include <string.h>
#include <functional>
#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<mfxFrameAllocResponse>::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<mfxFrameAllocResponse> m_responses;
std::list<UniqueResponse> m_ExtResponses;
struct IsSame
: public std::binary_function<mfxFrameAllocResponse, mfxFrameAllocResponse, bool>
{
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 T>
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__

View File

@ -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"

View File

@ -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 <limits>
//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<uintptr_t>::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<mfxMedIdEx *>((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 <d3d11.h>
#include <vector>
#include <map>
struct ID3D11VideoDevice;
struct ID3D11VideoContext;
struct D3D11AllocatorParams : mfxAllocatorParams
{
ID3D11Device *pDevice;
bool bUseSingleTexture;
DWORD uncompressedResourceMiscFlags;
D3D11AllocatorParams()
: pDevice()
, bUseSingleTexture()
, uncompressedResourceMiscFlags()
{
}
};
class D3D11FrameAllocator: public BaseFrameAllocator
{
public:
D3D11FrameAllocator();
virtual ~D3D11FrameAllocator();
virtual mfxStatus Init(mfxAllocatorParams *pParams);
virtual mfxStatus Close();
virtual ID3D11Device * GetD3D11Device()
{
return m_initParams.pDevice;
};
virtual mfxStatus LockFrame(mfxMemId mid, mfxFrameData *ptr);
virtual mfxStatus UnlockFrame(mfxMemId mid, mfxFrameData *ptr);
virtual mfxStatus GetFrameHDL(mfxMemId mid, mfxHDL *handle);
protected:
static DXGI_FORMAT ConverColortFormat(mfxU32 fourcc);
virtual mfxStatus CheckRequestType(mfxFrameAllocRequest *request);
virtual mfxStatus ReleaseResponse(mfxFrameAllocResponse *response);
virtual mfxStatus AllocImpl(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response);
D3D11AllocatorParams m_initParams;
ID3D11DeviceContext *m_pDeviceContext;
struct TextureResource
{
std::vector<mfxMemId> outerMids;
std::vector<ID3D11Texture2D*> textures;
std::vector<ID3D11Texture2D*> stagingTexture;
bool bAlloc;
TextureResource()
: bAlloc(true)
{
}
static bool isAllocated (TextureResource & that)
{
return that.bAlloc;
}
ID3D11Texture2D* GetTexture(mfxMemId id)
{
if (outerMids.empty())
return NULL;
return textures[((uintptr_t)id - (uintptr_t)outerMids.front()) % textures.size()];
}
UINT GetSubResource(mfxMemId id)
{
if (outerMids.empty())
return NULL;
return (UINT)(((uintptr_t)id - (uintptr_t)outerMids.front()) / textures.size());
}
void Release()
{
size_t i = 0;
for(i = 0; i < textures.size(); i++)
{
textures[i]->Release();
}
textures.clear();
for(i = 0; i < stagingTexture.size(); i++)
{
stagingTexture[i]->Release();
}
stagingTexture.clear();
//marking texture as deallocated
bAlloc = false;
}
};
class TextureSubResource
{
TextureResource * m_pTarget;
ID3D11Texture2D * m_pTexture;
ID3D11Texture2D * m_pStaging;
UINT m_subResource;
public:
TextureSubResource(TextureResource * pTarget = NULL, mfxMemId id = 0)
: m_pTarget(pTarget)
, m_pTexture()
, m_subResource()
, m_pStaging(NULL)
{
if (NULL != m_pTarget && !m_pTarget->outerMids.empty())
{
ptrdiff_t idx = (uintptr_t)MFXReadWriteMid(id).raw() - (uintptr_t)m_pTarget->outerMids.front();
m_pTexture = m_pTarget->textures[idx % m_pTarget->textures.size()];
m_subResource = (UINT)(idx / m_pTarget->textures.size());
m_pStaging = m_pTarget->stagingTexture.empty() ? NULL : m_pTarget->stagingTexture[idx];
}
}
ID3D11Texture2D* GetStaging()const
{
return m_pStaging;
}
ID3D11Texture2D* GetTexture()const
{
return m_pTexture;
}
UINT GetSubResource()const
{
return m_subResource;
}
void Release()
{
if (NULL != m_pTarget)
m_pTarget->Release();
}
};
TextureSubResource GetResourceFromMid(mfxMemId);
std::list <TextureResource> m_resourcesByRequest;//each alloc request generates new item in list
typedef std::list <TextureResource>::iterator referenceType;
std::vector<referenceType> m_memIdMap;
};
#endif // #if MFX_D3D11_SUPPORT
#endif // __D3D11_ALLOCATOR_H__

View File

@ -0,0 +1,67 @@
/* ****************************************************************************** *\
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 - 2012 Intel Corporation. All Rights Reserved.
\* ****************************************************************************** */
#pragma once
#include "sample_defs.h" // defines MFX_D3D11_SUPPORT
#if MFX_D3D11_SUPPORT
#include "hw_device.h"
#include <windows.h>
#include <d3d11.h>
#include <atlbase.h>
#include <dxgi1_2.h>
class CD3D11Device: public CHWDevice
{
public:
CD3D11Device();
virtual ~CD3D11Device();
virtual mfxStatus Init(
mfxHDL hWindow,
mfxU16 nViews,
mfxU32 nAdapterNum);
virtual mfxStatus Reset();
virtual mfxStatus GetHandle(mfxHandleType type, mfxHDL *pHdl);
virtual mfxStatus SetHandle(mfxHandleType type, mfxHDL hdl);
virtual mfxStatus RenderFrame(mfxFrameSurface1 * pSurface, mfxFrameAllocator * pmfxAlloc);
virtual void Close();
protected:
virtual mfxStatus FillSCD(mfxHDL hWindow, DXGI_SWAP_CHAIN_DESC& scd);
mfxStatus CreateVideoProcessor(mfxFrameSurface1 * pSrf);
CComPtr<ID3D11Device> m_pD3D11Device;
CComPtr<ID3D11DeviceContext> m_pD3D11Ctx;
CComQIPtr<ID3D11VideoDevice> m_pDX11VideoDevice;
CComQIPtr<ID3D11VideoContext> m_pVideoContext;
CComPtr<ID3D11VideoProcessorEnumerator> m_VideoProcessorEnum;
CComQIPtr<IDXGIDevice1> m_pDXGIDev;
CComQIPtr<IDXGIAdapter> m_pAdapter;
CComPtr<IDXGIFactory2> m_pDXGIFactory;
CComPtr<IDXGISwapChain1> m_pSwapChain;
CComPtr<ID3D11VideoProcessor> m_pVideoProcessor;
private:
CComPtr<ID3D11VideoProcessorInputView> m_pInputViewLeft;
CComPtr<ID3D11VideoProcessorInputView> m_pInputViewRight;
CComPtr<ID3D11VideoProcessorOutputView> m_pOutputView;
CComPtr<ID3D11Texture2D> m_pDXGIBackBuffer;
CComPtr<ID3D11Texture2D> m_pTempTexture;
CComPtr<IDXGIDisplayControl> m_pDisplayControl;
CComPtr<IDXGIOutput> m_pDXGIOutput;
mfxU16 m_nViews;
BOOL m_bDefaultStereoEnabled;
};
#endif //#if MFX_D3D11_SUPPORT

View File

@ -0,0 +1,39 @@
/* ****************************************************************************** *\
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 - 2012 Intel Corporation. All Rights Reserved.
\* ****************************************************************************** */
#pragma once
#include "mfxvideo++.h"
/// Base class for hw device
class CHWDevice
{
public:
virtual ~CHWDevice(){}
/** Initializes device for requested processing.
@param[in] hWindow Window handle to bundle device to.
@param[in] nViews Number of views to process.
@param[in] nAdapterNum Number of adapter to use
*/
virtual mfxStatus Init(
mfxHDL hWindow,
mfxU16 nViews,
mfxU32 nAdapterNum) = 0;
/// Reset device.
virtual mfxStatus Reset() = 0;
/// Get handle can be used for MFX session SetHandle calls
virtual mfxStatus GetHandle(mfxHandleType type, mfxHDL *pHdl) = 0;
/** Set handle.
Particular device implementation may require other objects to operate.
*/
virtual mfxStatus SetHandle(mfxHandleType type, mfxHDL hdl) = 0;
virtual mfxStatus RenderFrame(mfxFrameSurface1 * pSurface, mfxFrameAllocator * pmfxAlloc) = 0;
virtual void Close() = 0;
};

View File

@ -0,0 +1,92 @@
/* ////////////////////////////////////////////////////////////////////////////// */
/*
//
// 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) 2005-2013 Intel Corporation. All Rights Reserved.
//
//
*/
#ifndef __SAMPLE_DEFS_H__
#define __SAMPLE_DEFS_H__
#include <memory.h>
#include "mfxdefs.h"
#include "vm/strings_defs.h"
//#include "vm/file_defs.h"
#ifndef D3D_SURFACES_SUPPORT
#define D3D_SURFACES_SUPPORT 1
#endif
#if defined(_WIN32) && !defined(MFX_D3D11_SUPPORT)
#include <sdkddkver.h>
#if (NTDDI_VERSION >= NTDDI_VERSION_FROM_WIN32_WINNT2(0x0602)) // >= _WIN32_WINNT_WIN8
#define MFX_D3D11_SUPPORT 1 // Enable D3D11 support if SDK allows
#else
#define MFX_D3D11_SUPPORT 0
#endif
#endif //defined(WIN32) || defined(WIN64)
//affects win32 winnt version macro
#include "vm/time_defs.h"
//#include "sample_utils.h"
#define MSDK_DEC_WAIT_INTERVAL 60000
#define MSDK_ENC_WAIT_INTERVAL 10000
#define MSDK_VPP_WAIT_INTERVAL 60000
#define MSDK_WAIT_INTERVAL MSDK_DEC_WAIT_INTERVAL+3*MSDK_VPP_WAIT_INTERVAL+MSDK_ENC_WAIT_INTERVAL // an estimate for the longest pipeline we have in samples
#define MSDK_INVALID_SURF_IDX 0xFFFF
#define MSDK_MAX_FILENAME_LEN 1024
#define MSDK_PRINT_RET_MSG(ERR) {msdk_printf(MSDK_STRING("\nReturn on error: error code %d,\t%s\t%d\n\n"), ERR, MSDK_STRING(__FILE__), __LINE__);}
#define MSDK_CHECK_ERROR(P, X, ERR) {if ((X) == (P)) {MSDK_PRINT_RET_MSG(ERR); return ERR;}}
#define MSDK_CHECK_NOT_EQUAL(P, X, ERR) {if ((X) != (P)) {MSDK_PRINT_RET_MSG(ERR); return ERR;}}
#define MSDK_CHECK_RESULT(P, X, ERR) {if ((X) > (P)) {MSDK_PRINT_RET_MSG(ERR); return ERR;}}
#define MSDK_CHECK_PARSE_RESULT(P, X, ERR) {if ((X) > (P)) {return ERR;}}
#define MSDK_CHECK_RESULT_SAFE(P, X, ERR, ADD) {if ((X) > (P)) {ADD; MSDK_PRINT_RET_MSG(ERR); return ERR;}}
#define MSDK_IGNORE_MFX_STS(P, X) {if ((X) == (P)) {P = MFX_ERR_NONE;}}
#define MSDK_CHECK_POINTER(P, ...) {if (!(P)) {return __VA_ARGS__;}}
#define MSDK_CHECK_POINTER_NO_RET(P) {if (!(P)) {return;}}
#define MSDK_CHECK_POINTER_SAFE(P, ERR, ADD) {if (!(P)) {ADD; return ERR;}}
#define MSDK_BREAK_ON_ERROR(P) {if (MFX_ERR_NONE != (P)) break;}
#define MSDK_SAFE_DELETE_ARRAY(P) {if (P) {delete[] P; P = NULL;}}
#define MSDK_SAFE_RELEASE(X) {if (X) { X->Release(); X = NULL; }}
#ifndef MSDK_SAFE_DELETE
#define MSDK_SAFE_DELETE(P) {if (P) {delete P; P = NULL;}}
#endif // MSDK_SAFE_DELETE
#define MSDK_ZERO_MEMORY(VAR) {memset(&VAR, 0, sizeof(VAR));}
#define MSDK_MAX(A, B) (((A) > (B)) ? (A) : (B))
#define MSDK_MIN(A, B) (((A) < (B)) ? (A) : (B))
#define MSDK_ALIGN16(value) (((value + 15) >> 4) << 4) // round up to a multiple of 16
#define MSDK_ALIGN32(value) (((value + 31) >> 5) << 5) // round up to a multiple of 32
#define MSDK_ALIGN(value, alignment) (alignment) * ( (value) / (alignment) + (((value) % (alignment)) ? 1 : 0))
#define MSDK_ARRAY_LEN(value) (sizeof(value) / sizeof(value[0]))
#define MSDK_MEMCPY_BITSTREAM(bitstream, offset, src, count) memcpy_s((bitstream).Data + (offset), (bitstream).MaxLength - (offset), (src), (count))
#define MSDK_MEMCPY_BUF(bufptr, offset, maxsize, src, count) memcpy_s((bufptr)+ (offset), (maxsize) - (offset), (src), (count))
#define MSDK_MEMCPY_VAR(dstVarName, src, count) memcpy_s(&(dstVarName), sizeof(dstVarName), (src), (count))
#ifndef UNREFERENCED_PARAMETER
#define UNREFERENCED_PARAMETER(par) (par)
#endif
#ifndef MFX_PRODUCT_VERSION
#define MFX_PRODUCT_VERSION "4.0.760.60435"
#endif
#define MSDK_SAMPLE_VERSION MSDK_STRING(MFX_PRODUCT_VERSION)
#endif //__SAMPLE_DEFS_H__

View File

@ -0,0 +1,45 @@
/* ////////////////////////////////////////////////////////////////////////////// */
/*
//
// 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 __STRING_DEFS_H__
#define __STRING_DEFS_H__
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <tchar.h>
#define MSDK_STRING(x) _T(x)
#define MSDK_CHAR(x) _T(x)
typedef TCHAR msdk_char;
#define msdk_printf _tprintf
#define msdk_fprintf _ftprintf
#define msdk_sprintf _stprintf_s
#define msdk_vprintf _vtprintf
#define msdk_strlen _tcslen
#define msdk_strcmp _tcscmp
#define msdk_strncmp _tcsnicmp
#define msdk_strstr _tcsstr
#define msdk_sscanf _stscanf_s
#define msdk_atoi _ttoi
#define msdk_strtol _tcstol
#define msdk_strtod _tcstod
#define msdk_strchr _tcschr
#define msdk_itoa_decimal(value, str) _itow_s(value, str, 4, 10)
// msdk_strcopy is intended to be used with 2 parmeters, i.e. msdk_strcopy(dst, src)
// for _tcscpy_s that's possible if DST is declared as: TCHAR DST[n];
#define msdk_strcopy _tcscpy_s
#endif //__STRING_DEFS_H__

View File

@ -0,0 +1,19 @@
/* ****************************************************************************** *\
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) 2012 Intel Corporation. All Rights Reserved.
\* ****************************************************************************** */
#ifndef __TIME_DEFS_H__
#define __TIME_DEFS_H__
#include "mfxdefs.h"
#include <Windows.h>
#define MSDK_SLEEP(msec) Sleep(msec)
#endif // #ifndef __TIME_DEFS_H__

View File

@ -0,0 +1,263 @@
/* ****************************************************************************** *\
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.
\* ****************************************************************************** */
#include <assert.h>
#include <algorithm>
#include "base_allocator.h"
MFXFrameAllocator::MFXFrameAllocator()
{
pthis = this;
Alloc = Alloc_;
Lock = Lock_;
Free = Free_;
Unlock = Unlock_;
GetHDL = GetHDL_;
}
MFXFrameAllocator::~MFXFrameAllocator()
{
}
mfxStatus MFXFrameAllocator::Alloc_(mfxHDL pthis, mfxFrameAllocRequest *request, mfxFrameAllocResponse *response)
{
if (0 == pthis)
return MFX_ERR_MEMORY_ALLOC;
MFXFrameAllocator& self = *(MFXFrameAllocator *)pthis;
return self.AllocFrames(request, response);
}
mfxStatus MFXFrameAllocator::Lock_(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
{
if (0 == pthis)
return MFX_ERR_MEMORY_ALLOC;
MFXFrameAllocator& self = *(MFXFrameAllocator *)pthis;
return self.LockFrame(mid, ptr);
}
mfxStatus MFXFrameAllocator::Unlock_(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
{
if (0 == pthis)
return MFX_ERR_MEMORY_ALLOC;
MFXFrameAllocator& self = *(MFXFrameAllocator *)pthis;
return self.UnlockFrame(mid, ptr);
}
mfxStatus MFXFrameAllocator::Free_(mfxHDL pthis, mfxFrameAllocResponse *response)
{
if (0 == pthis)
return MFX_ERR_MEMORY_ALLOC;
MFXFrameAllocator& self = *(MFXFrameAllocator *)pthis;
return self.FreeFrames(response);
}
mfxStatus MFXFrameAllocator::GetHDL_(mfxHDL pthis, mfxMemId mid, mfxHDL *handle)
{
if (0 == pthis)
return MFX_ERR_MEMORY_ALLOC;
MFXFrameAllocator& self = *(MFXFrameAllocator *)pthis;
return self.GetFrameHDL(mid, handle);
}
BaseFrameAllocator::BaseFrameAllocator()
{
}
BaseFrameAllocator::~BaseFrameAllocator()
{
}
mfxStatus BaseFrameAllocator::CheckRequestType(mfxFrameAllocRequest *request)
{
if (0 == request)
return MFX_ERR_NULL_PTR;
// check that Media SDK component is specified in request
if ((request->Type & MEMTYPE_FROM_MASK) != 0)
return MFX_ERR_NONE;
else
return MFX_ERR_UNSUPPORTED;
}
mfxStatus BaseFrameAllocator::AllocFrames(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response)
{
if (0 == request || 0 == response || 0 == request->NumFrameSuggested)
return MFX_ERR_MEMORY_ALLOC;
if (MFX_ERR_NONE != CheckRequestType(request))
return MFX_ERR_UNSUPPORTED;
mfxStatus sts = MFX_ERR_NONE;
if ( (request->Type & MFX_MEMTYPE_EXTERNAL_FRAME) && (request->Type & MFX_MEMTYPE_FROM_DECODE) )
{
// external decoder allocations
std::list<UniqueResponse>::iterator it =
std::find_if( m_ExtResponses.begin()
, m_ExtResponses.end()
, UniqueResponse (*response, request->Info.CropW, request->Info.CropH, 0));
if (it != m_ExtResponses.end())
{
// check if enough frames were allocated
if (request->NumFrameMin > it->NumFrameActual)
return MFX_ERR_MEMORY_ALLOC;
it->m_refCount++;
// return existing response
*response = (mfxFrameAllocResponse&)*it;
}
else
{
sts = AllocImpl(request, response);
if (sts == MFX_ERR_NONE)
{
m_ExtResponses.push_back(UniqueResponse(*response, request->Info.CropW, request->Info.CropH, request->Type & MEMTYPE_FROM_MASK));
}
}
}
else
{
// internal allocations
// reserve space before allocation to avoid memory leak
m_responses.push_back(mfxFrameAllocResponse());
sts = AllocImpl(request, response);
if (sts == MFX_ERR_NONE)
{
m_responses.back() = *response;
}
else
{
m_responses.pop_back();
}
}
return sts;
}
mfxStatus BaseFrameAllocator::FreeFrames(mfxFrameAllocResponse *response)
{
if (response == 0)
return MFX_ERR_INVALID_HANDLE;
mfxStatus sts = MFX_ERR_NONE;
// check whether response is an external decoder response
std::list<UniqueResponse>::iterator i =
std::find_if( m_ExtResponses.begin(), m_ExtResponses.end(), std::bind1st(IsSame(), *response));
if (i != m_ExtResponses.end())
{
if ((--i->m_refCount) == 0)
{
sts = ReleaseResponse(response);
m_ExtResponses.erase(i);
}
return sts;
}
// if not found so far, then search in internal responses
std::list<mfxFrameAllocResponse>::iterator i2 =
std::find_if(m_responses.begin(), m_responses.end(), std::bind1st(IsSame(), *response));
if (i2 != m_responses.end())
{
sts = ReleaseResponse(response);
m_responses.erase(i2);
return sts;
}
// not found anywhere, report an error
return MFX_ERR_INVALID_HANDLE;
}
mfxStatus BaseFrameAllocator::Close()
{
std::list<UniqueResponse> ::iterator i;
for (i = m_ExtResponses.begin(); i!= m_ExtResponses.end(); i++)
{
ReleaseResponse(&*i);
}
m_ExtResponses.clear();
std::list<mfxFrameAllocResponse> ::iterator i2;
for (i2 = m_responses.begin(); i2!= m_responses.end(); i2++)
{
ReleaseResponse(&*i2);
}
return MFX_ERR_NONE;
}
MFXBufferAllocator::MFXBufferAllocator()
{
pthis = this;
Alloc = Alloc_;
Lock = Lock_;
Free = Free_;
Unlock = Unlock_;
}
MFXBufferAllocator::~MFXBufferAllocator()
{
}
mfxStatus MFXBufferAllocator::Alloc_(mfxHDL pthis, mfxU32 nbytes, mfxU16 type, mfxMemId *mid)
{
if (0 == pthis)
return MFX_ERR_MEMORY_ALLOC;
MFXBufferAllocator& self = *(MFXBufferAllocator *)pthis;
return self.AllocBuffer(nbytes, type, mid);
}
mfxStatus MFXBufferAllocator::Lock_(mfxHDL pthis, mfxMemId mid, mfxU8 **ptr)
{
if (0 == pthis)
return MFX_ERR_MEMORY_ALLOC;
MFXBufferAllocator& self = *(MFXBufferAllocator *)pthis;
return self.LockBuffer(mid, ptr);
}
mfxStatus MFXBufferAllocator::Unlock_(mfxHDL pthis, mfxMemId mid)
{
if (0 == pthis)
return MFX_ERR_MEMORY_ALLOC;
MFXBufferAllocator& self = *(MFXBufferAllocator *)pthis;
return self.UnlockBuffer(mid);
}
mfxStatus MFXBufferAllocator::Free_(mfxHDL pthis, mfxMemId mid)
{
if (0 == pthis)
return MFX_ERR_MEMORY_ALLOC;
MFXBufferAllocator& self = *(MFXBufferAllocator *)pthis;
return self.FreeBuffer(mid);
}

View File

@ -0,0 +1,450 @@
/* ****************************************************************************** *\
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.
\* ****************************************************************************** */
#include "d3d11_allocator.h"
#if MFX_D3D11_SUPPORT
#include <objbase.h>
#include <initguid.h>
#include <assert.h>
#include <algorithm>
#include <functional>
#include <iterator>
//#include "thread_defs.h"
#define D3DFMT_NV12 (DXGI_FORMAT)MAKEFOURCC('N','V','1','2')
#define D3DFMT_YV12 (DXGI_FORMAT)MAKEFOURCC('Y','V','1','2')
//for generating sequence of mfx handles
template <typename T>
struct sequence {
T x;
sequence(T seed) : x(seed) { }
};
template <>
struct sequence<mfxHDL> {
mfxHDL x;
sequence(mfxHDL seed) : x(seed) { }
mfxHDL operator ()()
{
mfxHDL y = x;
x = (mfxHDL)(1 + (size_t)(x));
return y;
}
};
D3D11FrameAllocator::D3D11FrameAllocator()
{
m_pDeviceContext = NULL;
}
D3D11FrameAllocator::~D3D11FrameAllocator()
{
Close();
}
D3D11FrameAllocator::TextureSubResource D3D11FrameAllocator::GetResourceFromMid(mfxMemId mid)
{
size_t index = (size_t)MFXReadWriteMid(mid).raw() - 1;
if(m_memIdMap.size() <= index)
return TextureSubResource();
//reverse iterator dereferencing
TextureResource * p = &(*m_memIdMap[index]);
if (!p->bAlloc)
return TextureSubResource();
return TextureSubResource(p, mid);
}
mfxStatus D3D11FrameAllocator::Init(mfxAllocatorParams *pParams)
{
D3D11AllocatorParams *pd3d11Params = 0;
pd3d11Params = dynamic_cast<D3D11AllocatorParams *>(pParams);
if (NULL == pd3d11Params ||
NULL == pd3d11Params->pDevice)
{
return MFX_ERR_NOT_INITIALIZED;
}
m_initParams = *pd3d11Params;
MSDK_SAFE_RELEASE(m_pDeviceContext);
pd3d11Params->pDevice->GetImmediateContext(&m_pDeviceContext);
return MFX_ERR_NONE;
}
mfxStatus D3D11FrameAllocator::Close()
{
mfxStatus sts = BaseFrameAllocator::Close();
for(referenceType i = m_resourcesByRequest.begin(); i != m_resourcesByRequest.end(); i++)
{
i->Release();
}
m_resourcesByRequest.clear();
m_memIdMap.clear();
MSDK_SAFE_RELEASE(m_pDeviceContext);
return sts;
}
mfxStatus D3D11FrameAllocator::LockFrame(mfxMemId mid, mfxFrameData *ptr)
{
HRESULT hRes = S_OK;
D3D11_TEXTURE2D_DESC desc = {0};
D3D11_MAPPED_SUBRESOURCE lockedRect = {0};
//check that texture exists
TextureSubResource sr = GetResourceFromMid(mid);
if (!sr.GetTexture())
return MFX_ERR_LOCK_MEMORY;
D3D11_MAP mapType = D3D11_MAP_READ;
UINT mapFlags = D3D11_MAP_FLAG_DO_NOT_WAIT;
{
if (NULL == sr.GetStaging())
{
hRes = m_pDeviceContext->Map(sr.GetTexture(), sr.GetSubResource(), D3D11_MAP_READ, D3D11_MAP_FLAG_DO_NOT_WAIT, &lockedRect);
desc.Format = DXGI_FORMAT_P8;
}
else
{
sr.GetTexture()->GetDesc(&desc);
if (DXGI_FORMAT_NV12 != desc.Format &&
DXGI_FORMAT_420_OPAQUE != desc.Format &&
DXGI_FORMAT_YUY2 != desc.Format &&
DXGI_FORMAT_P8 != desc.Format &&
DXGI_FORMAT_B8G8R8A8_UNORM != desc.Format)
{
return MFX_ERR_LOCK_MEMORY;
}
//coping data only in case user wants to read from stored surface
{
if (MFXReadWriteMid(mid, MFXReadWriteMid::reuse).isRead())
{
m_pDeviceContext->CopySubresourceRegion(sr.GetStaging(), 0, 0, 0, 0, sr.GetTexture(), sr.GetSubResource(), NULL);
}
do
{
hRes = m_pDeviceContext->Map(sr.GetStaging(), 0, mapType, mapFlags, &lockedRect);
if (S_OK != hRes && DXGI_ERROR_WAS_STILL_DRAWING != hRes)
{
msdk_printf(MSDK_STRING("ERROR: m_pDeviceContext->Map = 0x%08lx\n"), hRes);
}
}
while (DXGI_ERROR_WAS_STILL_DRAWING == hRes);
}
}
}
if (FAILED(hRes))
return MFX_ERR_LOCK_MEMORY;
switch (desc.Format)
{
case DXGI_FORMAT_NV12:
ptr->Pitch = (mfxU16)lockedRect.RowPitch;
ptr->Y = (mfxU8 *)lockedRect.pData;
ptr->U = (mfxU8 *)lockedRect.pData + desc.Height * lockedRect.RowPitch;
ptr->V = ptr->U + 1;
break;
case DXGI_FORMAT_420_OPAQUE: // can be unsupported by standard ms guid
ptr->Pitch = (mfxU16)lockedRect.RowPitch;
ptr->Y = (mfxU8 *)lockedRect.pData;
ptr->V = ptr->Y + desc.Height * lockedRect.RowPitch;
ptr->U = ptr->V + (desc.Height * lockedRect.RowPitch) / 4;
break;
case DXGI_FORMAT_YUY2:
ptr->Pitch = (mfxU16)lockedRect.RowPitch;
ptr->Y = (mfxU8 *)lockedRect.pData;
ptr->U = ptr->Y + 1;
ptr->V = ptr->Y + 3;
break;
case DXGI_FORMAT_P8 :
ptr->Pitch = (mfxU16)lockedRect.RowPitch;
ptr->Y = (mfxU8 *)lockedRect.pData;
ptr->U = 0;
ptr->V = 0;
break;
case DXGI_FORMAT_B8G8R8A8_UNORM :
ptr->Pitch = (mfxU16)lockedRect.RowPitch;
ptr->B = (mfxU8 *)lockedRect.pData;
ptr->G = ptr->B + 1;
ptr->R = ptr->B + 2;
ptr->A = ptr->B + 3;
break;
default:
return MFX_ERR_LOCK_MEMORY;
}
return MFX_ERR_NONE;
}
mfxStatus D3D11FrameAllocator::UnlockFrame(mfxMemId mid, mfxFrameData *ptr)
{
//check that texture exists
TextureSubResource sr = GetResourceFromMid(mid);
if (!sr.GetTexture())
return MFX_ERR_LOCK_MEMORY;
if (NULL == sr.GetStaging())
{
m_pDeviceContext->Unmap(sr.GetTexture(), sr.GetSubResource());
}
else
{
m_pDeviceContext->Unmap(sr.GetStaging(), 0);
//only if user wrote something to texture
if (MFXReadWriteMid(mid, MFXReadWriteMid::reuse).isWrite())
{
m_pDeviceContext->CopySubresourceRegion(sr.GetTexture(), sr.GetSubResource(), 0, 0, 0, sr.GetStaging(), 0, NULL);
}
}
if (ptr)
{
ptr->Pitch=0;
ptr->U=ptr->V=ptr->Y=0;
ptr->A=ptr->R=ptr->G=ptr->B=0;
}
return MFX_ERR_NONE;
}
mfxStatus D3D11FrameAllocator::GetFrameHDL(mfxMemId mid, mfxHDL *handle)
{
if (NULL == handle)
return MFX_ERR_INVALID_HANDLE;
TextureSubResource sr = GetResourceFromMid(mid);
if (!sr.GetTexture())
return MFX_ERR_INVALID_HANDLE;
mfxHDLPair *pPair = (mfxHDLPair*)handle;
pPair->first = sr.GetTexture();
pPair->second = (mfxHDL)(UINT_PTR)sr.GetSubResource();
return MFX_ERR_NONE;
}
mfxStatus D3D11FrameAllocator::CheckRequestType(mfxFrameAllocRequest *request)
{
mfxStatus sts = BaseFrameAllocator::CheckRequestType(request);
if (MFX_ERR_NONE != sts)
return sts;
if ((request->Type & (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET)) != 0)
return MFX_ERR_NONE;
else
return MFX_ERR_UNSUPPORTED;
}
mfxStatus D3D11FrameAllocator::ReleaseResponse(mfxFrameAllocResponse *response)
{
if (NULL == response)
return MFX_ERR_NULL_PTR;
if (response->mids && 0 != response->NumFrameActual)
{
//check whether texture exsist
TextureSubResource sr = GetResourceFromMid(response->mids[0]);
if (!sr.GetTexture())
return MFX_ERR_NULL_PTR;
sr.Release();
//if texture is last it is possible to remove also all handles from map to reduce fragmentation
//search for allocated chunk
if (m_resourcesByRequest.end() == std::find_if(m_resourcesByRequest.begin(), m_resourcesByRequest.end(), TextureResource::isAllocated))
{
m_resourcesByRequest.clear();
m_memIdMap.clear();
}
}
return MFX_ERR_NONE;
}
mfxStatus D3D11FrameAllocator::AllocImpl(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response)
{
HRESULT hRes;
DXGI_FORMAT colorFormat = ConverColortFormat(request->Info.FourCC);
if (DXGI_FORMAT_UNKNOWN == colorFormat)
{
return MFX_ERR_UNSUPPORTED;
}
TextureResource newTexture;
if (request->Info.FourCC == MFX_FOURCC_P8)
{
D3D11_BUFFER_DESC desc = { 0 };
desc.ByteWidth = request->Info.Width * request->Info.Height;
desc.Usage = D3D11_USAGE_STAGING;
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.MiscFlags = 0;
desc.StructureByteStride = 0;
ID3D11Buffer * buffer = 0;
hRes = m_initParams.pDevice->CreateBuffer(&desc, 0, &buffer);
if (FAILED(hRes))
return MFX_ERR_MEMORY_ALLOC;
newTexture.textures.push_back(reinterpret_cast<ID3D11Texture2D *>(buffer));
}
else
{
D3D11_TEXTURE2D_DESC desc = {0};
desc.Width = request->Info.Width;
desc.Height = request->Info.Height;
desc.MipLevels = 1;
//number of subresources is 1 in case of not single texture
desc.ArraySize = m_initParams.bUseSingleTexture ? request->NumFrameSuggested : 1;
desc.Format = ConverColortFormat(request->Info.FourCC);
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.MiscFlags = m_initParams.uncompressedResourceMiscFlags;
desc.BindFlags = D3D11_BIND_DECODER;
if ( (MFX_MEMTYPE_FROM_VPPIN & request->Type) && (DXGI_FORMAT_YUY2 == desc.Format) ||
(DXGI_FORMAT_B8G8R8A8_UNORM == desc.Format) )
{
desc.BindFlags = D3D11_BIND_RENDER_TARGET;
if (desc.ArraySize > 2)
return MFX_ERR_MEMORY_ALLOC;
}
if ( (MFX_MEMTYPE_FROM_VPPOUT & request->Type) ||
(MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET & request->Type))
{
desc.BindFlags = D3D11_BIND_RENDER_TARGET;
if (desc.ArraySize > 2)
return MFX_ERR_MEMORY_ALLOC;
}
if( DXGI_FORMAT_P8 == desc.Format )
{
desc.BindFlags = 0;
}
ID3D11Texture2D* pTexture2D;
for(size_t i = 0; i < request->NumFrameSuggested / desc.ArraySize; i++)
{
hRes = m_initParams.pDevice->CreateTexture2D(&desc, NULL, &pTexture2D);
if (FAILED(hRes))
{
msdk_printf(MSDK_STRING("CreateTexture2D(%d) failed, hr = 0x%08lx\n"), i, hRes);
return MFX_ERR_MEMORY_ALLOC;
}
newTexture.textures.push_back(pTexture2D);
}
desc.ArraySize = 1;
desc.Usage = D3D11_USAGE_STAGING;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.BindFlags = 0;
desc.MiscFlags = 0;
for(size_t i = 0; i < request->NumFrameSuggested; i++)
{
hRes = m_initParams.pDevice->CreateTexture2D(&desc, NULL, &pTexture2D);
if (FAILED(hRes))
{
printf("Create staging texture(%d) failed hr = 0x%X\n", i, hRes);
return MFX_ERR_MEMORY_ALLOC;
}
newTexture.stagingTexture.push_back(pTexture2D);
}
}
// mapping to self created handles array, starting from zero or from last assigned handle + 1
sequence<mfxHDL> seq_initializer(m_resourcesByRequest.empty() ? 0 : m_resourcesByRequest.back().outerMids.back());
//incrementing starting index
//1. 0(NULL) is invalid memid
//2. back is last index not new one
seq_initializer();
std::generate_n(std::back_inserter(newTexture.outerMids), request->NumFrameSuggested, seq_initializer);
//saving texture resources
m_resourcesByRequest.push_back(newTexture);
//providing pointer to mids externally
response->mids = &m_resourcesByRequest.back().outerMids.front();
response->NumFrameActual = request->NumFrameSuggested;
//iterator prior end()
std::list <TextureResource>::iterator it_last = m_resourcesByRequest.end();
//fill map
std::fill_n(std::back_inserter(m_memIdMap), request->NumFrameSuggested, --it_last);
return MFX_ERR_NONE;
}
DXGI_FORMAT D3D11FrameAllocator::ConverColortFormat(mfxU32 fourcc)
{
switch (fourcc)
{
case MFX_FOURCC_NV12:
return DXGI_FORMAT_NV12;
case MFX_FOURCC_YUY2:
return DXGI_FORMAT_YUY2;
case MFX_FOURCC_RGB4:
return DXGI_FORMAT_B8G8R8A8_UNORM;
case MFX_FOURCC_P8:
case MFX_FOURCC_P8_TEXTURE:
return DXGI_FORMAT_P8;
default:
return DXGI_FORMAT_UNKNOWN;
}
}
#endif // #if MFX_D3D11_SUPPORT

View File

@ -0,0 +1,334 @@
/* ****************************************************************************** *\
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 - 2012 Intel Corporation. All Rights Reserved.
\* ****************************************************************************** */
#include "d3d11_device.h"
#if MFX_D3D11_SUPPORT
#include "sample_defs.h"
CD3D11Device::CD3D11Device()
{
}
CD3D11Device::~CD3D11Device()
{
Close();
}
mfxStatus CD3D11Device::FillSCD(mfxHDL hWindow, DXGI_SWAP_CHAIN_DESC& scd)
{
scd.Windowed = TRUE;
scd.OutputWindow = (HWND)hWindow;
scd.SampleDesc.Count = 1;
scd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.BufferCount = 1;
return MFX_ERR_NONE;
}
mfxStatus CD3D11Device::Init(
mfxHDL hWindow,
mfxU16 nViews,
mfxU32 nAdapterNum)
{
mfxStatus sts = MFX_ERR_NONE;
HRESULT hres = S_OK;
m_nViews = nViews;
if (2 < nViews)
return MFX_ERR_UNSUPPORTED;
m_bDefaultStereoEnabled = FALSE;
static D3D_FEATURE_LEVEL FeatureLevels[] = {
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0
};
D3D_FEATURE_LEVEL pFeatureLevelsOut;
hres = CreateDXGIFactory(__uuidof(IDXGIFactory2), (void**)(&m_pDXGIFactory) );
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
if (m_nViews == 2 && hWindow)
{
hres = m_pDXGIFactory->QueryInterface(__uuidof(IDXGIDisplayControl), (void **)&m_pDisplayControl);
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
m_bDefaultStereoEnabled = m_pDisplayControl->IsStereoEnabled();
if (!m_bDefaultStereoEnabled)
m_pDisplayControl->SetStereoEnabled(TRUE);
}
hres = m_pDXGIFactory->EnumAdapters(nAdapterNum,&m_pAdapter);
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
hres = D3D11CreateDevice(m_pAdapter ,
D3D_DRIVER_TYPE_UNKNOWN,
NULL,
0,
FeatureLevels,
MSDK_ARRAY_LEN(FeatureLevels),
D3D11_SDK_VERSION,
&m_pD3D11Device,
&pFeatureLevelsOut,
&m_pD3D11Ctx);
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
m_pDXGIDev = m_pD3D11Device;
m_pDX11VideoDevice = m_pD3D11Device;
m_pVideoContext = m_pD3D11Ctx;
MSDK_CHECK_POINTER(m_pDXGIDev.p, MFX_ERR_NULL_PTR);
MSDK_CHECK_POINTER(m_pDX11VideoDevice.p, MFX_ERR_NULL_PTR);
MSDK_CHECK_POINTER(m_pVideoContext.p, MFX_ERR_NULL_PTR);
// turn on multithreading for the Context
CComQIPtr<ID3D10Multithread> p_mt(m_pVideoContext);
if (p_mt)
p_mt->SetMultithreadProtected(true);
else
return MFX_ERR_DEVICE_FAILED;
// create swap chain only for rendering use case (hWindow != 0)
DXGI_SWAP_CHAIN_DESC scd;
if (hWindow)
{
ZeroMemory(&scd, sizeof(scd));
sts = FillSCD(hWindow, scd);
MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
MSDK_CHECK_POINTER (m_pDXGIFactory.p, MFX_ERR_NULL_PTR);
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
swapChainDesc.Width = 0; // Use automatic sizing.
swapChainDesc.Height = 0;
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format.
swapChainDesc.Stereo = m_nViews == 2 ? TRUE : FALSE;
swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling.
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 2; // Use double buffering to minimize latency.
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
hres = m_pDXGIFactory->CreateSwapChainForHwnd(m_pD3D11Device,
(HWND)hWindow,
&swapChainDesc,
NULL,
NULL,
reinterpret_cast<IDXGISwapChain1**>(&m_pSwapChain) );
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
}
return sts;
}
mfxStatus CD3D11Device::CreateVideoProcessor(mfxFrameSurface1 * pSrf)
{
HRESULT hres = S_OK;
if (m_VideoProcessorEnum.p || NULL == pSrf)
return MFX_ERR_NONE;
//create video processor
D3D11_VIDEO_PROCESSOR_CONTENT_DESC ContentDesc;
MSDK_ZERO_MEMORY( ContentDesc );
ContentDesc.InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE;
ContentDesc.InputFrameRate.Numerator = 30000;
ContentDesc.InputFrameRate.Denominator = 1000;
ContentDesc.InputWidth = pSrf->Info.CropW;
ContentDesc.InputHeight = pSrf->Info.CropH;
ContentDesc.OutputWidth = pSrf->Info.CropW;
ContentDesc.OutputHeight = pSrf->Info.CropH;
ContentDesc.OutputFrameRate.Numerator = 30000;
ContentDesc.OutputFrameRate.Denominator = 1000;
ContentDesc.Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL;
hres = m_pDX11VideoDevice->CreateVideoProcessorEnumerator( &ContentDesc, &m_VideoProcessorEnum );
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
hres = m_pDX11VideoDevice->CreateVideoProcessor( m_VideoProcessorEnum, 0, &m_pVideoProcessor );
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
return MFX_ERR_NONE;
}
mfxStatus CD3D11Device::Reset()
{
// Changing video mode back to the original state
if (2 == m_nViews && !m_bDefaultStereoEnabled)
m_pDisplayControl->SetStereoEnabled(FALSE);
return MFX_ERR_NONE;
}
mfxStatus CD3D11Device::GetHandle(mfxHandleType type, mfxHDL *pHdl)
{
if (MFX_HANDLE_D3D11_DEVICE == type)
{
*pHdl = m_pD3D11Device.p;
return MFX_ERR_NONE;
}
return MFX_ERR_UNSUPPORTED;
}
mfxStatus CD3D11Device::SetHandle(mfxHandleType /*type*/, mfxHDL /*hdl*/)
{
return MFX_ERR_UNSUPPORTED;
}
mfxStatus CD3D11Device::RenderFrame(mfxFrameSurface1 * pSrf, mfxFrameAllocator * pAlloc)
{
HRESULT hres = S_OK;
mfxStatus sts;
sts = CreateVideoProcessor(pSrf);
MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
hres = m_pSwapChain->GetBuffer(0, __uuidof( ID3D11Texture2D ), (void**)&m_pDXGIBackBuffer.p);
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC OutputViewDesc;
if (2 == m_nViews)
{
m_pVideoContext->VideoProcessorSetStreamStereoFormat(m_pVideoProcessor, 0, TRUE,D3D11_VIDEO_PROCESSOR_STEREO_FORMAT_SEPARATE,
TRUE, TRUE, D3D11_VIDEO_PROCESSOR_STEREO_FLIP_NONE, NULL);
m_pVideoContext->VideoProcessorSetOutputStereoMode(m_pVideoProcessor,TRUE);
OutputViewDesc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2DARRAY;
OutputViewDesc.Texture2DArray.ArraySize = 2;
OutputViewDesc.Texture2DArray.MipSlice = 0;
OutputViewDesc.Texture2DArray.FirstArraySlice = 0;
}
else
{
OutputViewDesc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D;
OutputViewDesc.Texture2D.MipSlice = 0;
}
if (1 == m_nViews || 0 == pSrf->Info.FrameId.ViewId)
{
hres = m_pDX11VideoDevice->CreateVideoProcessorOutputView(
m_pDXGIBackBuffer,
m_VideoProcessorEnum,
&OutputViewDesc,
&m_pOutputView.p );
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
}
D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC InputViewDesc;
InputViewDesc.FourCC = 0;
InputViewDesc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D;
InputViewDesc.Texture2D.MipSlice = 0;
InputViewDesc.Texture2D.ArraySlice = 0;
mfxHDLPair pair = {NULL};
sts = pAlloc->GetHDL(pAlloc->pthis, pSrf->Data.MemId, (mfxHDL*)&pair);
MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
ID3D11Texture2D *pRTTexture2D = reinterpret_cast<ID3D11Texture2D*>(pair.first);
D3D11_TEXTURE2D_DESC RTTexture2DDesc;
if(!m_pTempTexture && m_nViews == 2)
{
pRTTexture2D->GetDesc(&RTTexture2DDesc);
hres = m_pD3D11Device->CreateTexture2D(&RTTexture2DDesc,NULL,&m_pTempTexture.p);
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
}
// Creating input views for left and righ eyes
if (1 == m_nViews)
{
hres = m_pDX11VideoDevice->CreateVideoProcessorInputView(
pRTTexture2D,
m_VideoProcessorEnum,
&InputViewDesc,
&m_pInputViewLeft.p );
}
else if (2 == m_nViews && 0 == pSrf->Info.FrameId.ViewId)
{
m_pD3D11Ctx->CopyResource(m_pTempTexture,pRTTexture2D);
hres = m_pDX11VideoDevice->CreateVideoProcessorInputView(
m_pTempTexture,
m_VideoProcessorEnum,
&InputViewDesc,
&m_pInputViewLeft.p );
}
else
{
hres = m_pDX11VideoDevice->CreateVideoProcessorInputView(
pRTTexture2D,
m_VideoProcessorEnum,
&InputViewDesc,
&m_pInputViewRight.p );
}
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
// NV12 surface to RGB backbuffer
RECT rect = {0};
rect.right = pSrf->Info.CropW;
rect.bottom = pSrf->Info.CropH;
D3D11_VIDEO_PROCESSOR_STREAM StreamData;
if (1 == m_nViews || pSrf->Info.FrameId.ViewId == 1)
{
StreamData.Enable = TRUE;
StreamData.OutputIndex = 0;
StreamData.InputFrameOrField = 0;
StreamData.PastFrames = 0;
StreamData.FutureFrames = 0;
StreamData.ppPastSurfaces = NULL;
StreamData.ppFutureSurfaces = NULL;
StreamData.pInputSurface = m_pInputViewLeft;
StreamData.ppPastSurfacesRight = NULL;
StreamData.ppFutureSurfacesRight = NULL;
StreamData.pInputSurfaceRight = m_nViews == 2 ? m_pInputViewRight : NULL;
m_pVideoContext->VideoProcessorSetStreamSourceRect(m_pVideoProcessor, 0, true, &rect);
m_pVideoContext->VideoProcessorSetStreamFrameFormat( m_pVideoProcessor, 0, D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE);
hres = m_pVideoContext->VideoProcessorBlt( m_pVideoProcessor, m_pOutputView, 0, 1, &StreamData );
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
}
if (1 == m_nViews || 1 == pSrf->Info.FrameId.ViewId)
{
DXGI_PRESENT_PARAMETERS parameters = {0};
hres = m_pSwapChain->Present1(0, 0, &parameters);
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
}
return MFX_ERR_NONE;
}
void CD3D11Device::Close()
{
Reset();
}
#endif // #if MFX_D3D11_SUPPORT

160
QSVHelper/QSVHelper.cpp Normal file
View File

@ -0,0 +1,160 @@
/********************************************************************************
Copyright (C) 2013 Ruwen Hahn <palana@stunned.de>
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.
********************************************************************************/
#include <stdio.h>
#include <windows.h>
#include <shellapi.h>
#include <fstream>
#include <sstream>
#include <utility>
#include <mfxvideo++.h>
#include "Encoder.h"
#include "IPCInfo.h"
#include "QSVStuff.h"
#include "SupportStuff.h"
#include "WindowsStuff.h"
namespace {
const struct impl_parameters
{
mfxIMPL type,
intf;
mfxVersion version;
} valid_impl[] = {
{ MFX_IMPL_HARDWARE_ANY, MFX_IMPL_VIA_D3D11, {6, 1} },
{ MFX_IMPL_HARDWARE, MFX_IMPL_VIA_D3D11, {6, 1} },
{ MFX_IMPL_HARDWARE_ANY, MFX_IMPL_VIA_D3D9, {6, 1} }, //Ivy Bridge+ with non-functional D3D11 support?
{ MFX_IMPL_HARDWARE, MFX_IMPL_VIA_D3D9, {6, 1} },
{ MFX_IMPL_HARDWARE_ANY, MFX_IMPL_VIA_D3D9, {4, 1} }, //Sandy Bridge
{ MFX_IMPL_HARDWARE, MFX_IMPL_VIA_D3D9, {4, 1} },
};
std::wofstream log_file;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nShowCmd)
{
using namespace std;
wstringstream cmdss(GetCommandLineW());
wstring wstr;
cmdss >> wstr;
wstringstream wss;
wss << wstr << GetCurrentProcessId();
wstring event_prefix;
wss >> event_prefix;
std::string log_path = GetCommandLineA();
log_path.erase(log_path.begin(), find(log_path.begin(), log_path.end(), ' ')+1);
log_path += "/pluginData/QSVHelper.log";
log_file.open(log_path, ios::out | ios::trunc);
if(!log_file.is_open())
return 200;
ipc_init_request init_req(event_prefix + INIT_REQUEST);
if(!init_req.is_signalled(INFINITE))
return 1;
if(init_req->mode == init_req->MODE_QUERY)
{
MFXVideoSession session;
for(auto impl = begin(valid_impl); impl != std::end(valid_impl); impl++)
{
auto ver = impl->version;
auto result = session.Init(impl->intf | impl->type, &ver);
if(result == MFX_ERR_NONE)
return 0;
}
return 3;
}
safe_handle obs_handle(OpenProcess(SYNCHRONIZE, false, init_req->obs_process_id));
if(!obs_handle)
return 2;
ipc_init_response init_res(event_prefix + INIT_RESPONSE);
zero(*&init_res);
Encoder encoder(init_req, event_prefix, log_file);
init_res->using_custom_impl = false;
if(init_req->use_custom_impl)
{
impl_parameters p;
p.intf = init_req->custom_intf;
p.type = init_req->custom_impl;
p.version = init_req->custom_version;
auto result = encoder.InitializeMFX(p, true);
if(result >= MFX_ERR_NONE)
{
init_res->using_custom_impl = true;
init_res->actual_impl = p.intf | p.type;
init_res->version = p.version;
}
}
if(!init_res->using_custom_impl || !encoder)
{
decltype(begin(valid_impl)) best = nullptr;
for(auto impl = begin(valid_impl); impl != std::end(valid_impl); impl++)
{
auto result = encoder.InitializeMFX(*impl);
if(result == MFX_WRN_PARTIAL_ACCELERATION && !best)
best = impl;
if(result == MFX_ERR_NONE)
break;
}
if(!encoder)
{
if(!best)
return 5;
auto ver = best->version;
encoder.InitializeMFX(*best);
log_file << "No valid implementation detected, using best implementation instead\n";
}
}
if(!encoder)
return 6;
init_res->version = encoder.version;
init_res->requested_impl = encoder.requested;
init_res->actual_impl = encoder.actual;
encoder.InitializeBuffers(init_res);
encoder.InitializeEncoder();
init_res.signal();
log_file << "Using " << encoder.encode_tasks.size() << " encode tasks and " << encoder.surfaces.size() << " internal frame buffers\n";
encoder.RequestSPSPPS();
ipc_stop stop(event_prefix + STOP_REQUEST);
return encoder.EncodeLoop(stop, obs_handle);
}

126
QSVHelper/QSVHelper.vcxproj Normal file
View File

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{F1C7033A-F050-46E3-9080-E129B9CD1010}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>QSVHelper</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v100</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v100</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(WindowsSDK80Path)Include\um;$(WindowsSDK80Path)Include\shared;$(DXSDK_DIR)Include;IntelSupport\include;IntelSupport\include\vm;$(IncludePath)</IncludePath>
<LibraryPath>$(WindowsSDK80Path)Lib\win8\um\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath)</LibraryPath>
<OutDir>$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(WindowsSDK80Path)Include\um;$(WindowsSDK80Path)Include\shared;$(DXSDK_DIR)Include;IntelSupport\include;IntelSupport\include\vm;$(IncludePath)</IncludePath>
<OutDir>$(Configuration)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>../libmfx/include/msdk/include</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>../libmfx/$(Platform)/$(Configuration)/libmfx.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<ProgramDatabaseFile>..\rundir\pdb32\$(TargetName).pdb</ProgramDatabaseFile>
<StripPrivateSymbols>..\rundir\pdb32\stripped\$(TargetName).pdb</StripPrivateSymbols>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)$(TargetName).exe" ..\rundir\</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>../libmfx/include/msdk/include</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>../libmfx/$(Platform)/$(Configuration)/libmfx.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ProgramDatabaseFile>..\rundir\pdb32\$(TargetName).pdb</ProgramDatabaseFile>
<StripPrivateSymbols>..\rundir\pdb32\stripped\$(TargetName).pdb</StripPrivateSymbols>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)$(TargetName).exe" ..\rundir\</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="IntelSupport\src\base_allocator.cpp" />
<ClCompile Include="IntelSupport\src\d3d11_allocator.cpp" />
<ClCompile Include="IntelSupport\src\d3d11_device.cpp" />
<ClCompile Include="QSVStuff.cpp" />
<ClCompile Include="QSVHelper.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Encoder.h" />
<ClInclude Include="IntelSupport\include\base_allocator.h" />
<ClInclude Include="IntelSupport\include\current_date.h" />
<ClInclude Include="IntelSupport\include\d3d11_allocator.h" />
<ClInclude Include="IntelSupport\include\d3d11_device.h" />
<ClInclude Include="IntelSupport\include\hw_device.h" />
<ClInclude Include="IntelSupport\include\sample_defs.h" />
<ClInclude Include="IntelSupport\include\vm\strings_defs.h" />
<ClInclude Include="IntelSupport\include\vm\time_defs.h" />
<ClInclude Include="IPCStructs.h" />
<ClInclude Include="IPCInfo.h" />
<ClInclude Include="SupportStuff.h" />
<ClInclude Include="Utilities.h" />
<ClInclude Include="WindowsStuff.h" />
<ClInclude Include="QSVStuff.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="IntelSupport">
<UniqueIdentifier>{ca840a93-0bea-4a93-83c9-0476c240c3a8}</UniqueIdentifier>
</Filter>
<Filter Include="IntelSupport\Headers">
<UniqueIdentifier>{fd95e3a4-45a3-40e5-a120-1e3a476e1fc0}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="QSVHelper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="QSVStuff.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="IntelSupport\src\base_allocator.cpp">
<Filter>IntelSupport</Filter>
</ClCompile>
<ClCompile Include="IntelSupport\src\d3d11_allocator.cpp">
<Filter>IntelSupport</Filter>
</ClCompile>
<ClCompile Include="IntelSupport\src\d3d11_device.cpp">
<Filter>IntelSupport</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="WindowsStuff.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="QSVStuff.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="SupportStuff.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Utilities.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IPCStructs.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Encoder.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IPCInfo.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IntelSupport\include\base_allocator.h">
<Filter>IntelSupport\Headers</Filter>
</ClInclude>
<ClInclude Include="IntelSupport\include\current_date.h">
<Filter>IntelSupport\Headers</Filter>
</ClInclude>
<ClInclude Include="IntelSupport\include\d3d11_allocator.h">
<Filter>IntelSupport\Headers</Filter>
</ClInclude>
<ClInclude Include="IntelSupport\include\d3d11_device.h">
<Filter>IntelSupport\Headers</Filter>
</ClInclude>
<ClInclude Include="IntelSupport\include\hw_device.h">
<Filter>IntelSupport\Headers</Filter>
</ClInclude>
<ClInclude Include="IntelSupport\include\sample_defs.h">
<Filter>IntelSupport\Headers</Filter>
</ClInclude>
<ClInclude Include="IntelSupport\include\vm\strings_defs.h">
<Filter>IntelSupport\Headers</Filter>
</ClInclude>
<ClInclude Include="IntelSupport\include\vm\time_defs.h">
<Filter>IntelSupport\Headers</Filter>
</ClInclude>
</ItemGroup>
</Project>

172
QSVHelper/QSVStuff.cpp Normal file
View File

@ -0,0 +1,172 @@
/********************************************************************************
Copyright (C) 2013 Ruwen Hahn <palana@stunned.de>
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.
********************************************************************************/
#include "QSVStuff.h"
#include "Utilities.h"
using namespace std;
namespace {
void ConvertFrameRate(mfxF64 dFrameRate, mfxU32& pnFrameRateExtN, mfxU32& pnFrameRateExtD)
{
mfxU32 fr;
fr = (mfxU32)(dFrameRate + .5);
if(fabs(fr - dFrameRate) < 0.0001)
{
pnFrameRateExtN = fr;
pnFrameRateExtD = 1;
return;
}
fr = (mfxU32)(dFrameRate * 1.001 + .5);
if(fabs(fr * 1000 - dFrameRate * 1001) < 10)
{
pnFrameRateExtN = fr * 1000;
pnFrameRateExtD = 1001;
return;
}
pnFrameRateExtN = (mfxU32)(dFrameRate * 10000 + .5);
pnFrameRateExtD = 10000;
}
}
Parameters::Parameters()
{
zero(params);
}
void Parameters::Init(int fps, int keyframe_interval_frames, int bframes, int width, int height, int max_bitrate, int buffer_size, bool use_cbr)
{
params.mfx.CodecId = MFX_CODEC_AVC;
params.mfx.TargetUsage = MFX_TARGETUSAGE_BEST_QUALITY;
params.mfx.TargetKbps = max_bitrate;
params.mfx.MaxKbps = max_bitrate;
params.mfx.BufferSizeInKB = buffer_size/8;
params.mfx.GopOptFlag = MFX_GOP_CLOSED;
params.mfx.GopPicSize = keyframe_interval_frames;
params.mfx.GopRefDist = bframes+1;
params.mfx.NumSlice = 1;
params.mfx.RateControlMethod = use_cbr ? MFX_RATECONTROL_CBR : MFX_RATECONTROL_VBR;
params.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
auto& fi = params.mfx.FrameInfo;
ConvertFrameRate(fps, fi.FrameRateExtN, fi.FrameRateExtD);
fi.FourCC = MFX_FOURCC_NV12;
fi.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
fi.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
fi.Width = align16(width);
fi.Height = align16(height);
fi.CropX = 0;
fi.CropY = 0;
fi.CropW = width;
fi.CropH = height;
}
void Parameters::SetCodingOptionSPSPPS(mfxU8 *sps_buff, mfxU16 sps_size, mfxU8 *pps_buff, mfxU16 pps_size)
{
if(!FindExt(cospspps))
{
zero(cospspps);
cospspps.Header.BufferId = MFX_EXTBUFF_CODING_OPTION_SPSPPS;
cospspps.Header.BufferSz = sizeof(cospspps);
AddExt(cospspps);
}
cospspps.SPSBuffer = sps_buff;
cospspps.SPSBufSize = sps_size;
cospspps.PPSBuffer = pps_buff;
cospspps.PPSBufSize = pps_size;
}
void Parameters::SetVideoSignalInfo(int full_range, int primaries, int transfer, int matrix)
{
if(!FindExt(vsi))
{
zero(vsi);
vsi.Header.BufferId = MFX_EXTBUFF_VIDEO_SIGNAL_INFO;
vsi.Header.BufferSz = sizeof(vsi);
AddExt(vsi);
}
vsi.ColourDescriptionPresent = 1;
vsi.VideoFullRange = full_range;
vsi.ColourPrimaries = primaries;
vsi.TransferCharacteristics = transfer;
vsi.MatrixCoefficients = matrix;
vsi.VideoFormat = 5; //unspecified
}
void Parameters::UpdateExt()
{
params.ExtParam = &ext_buffers.front();
params.NumExtParam = ext_buffers.size();
}
void EncodeCtrl::AddSEIData(sei_type type, vector<mfxU8> data)
{
unsigned payload_size = data.size();
vector<mfxU8> buffer;
mfxU16 type_ = type;
while(type_ > 255)
{
buffer.emplace_back(0xff);
type_ -= 255;
}
buffer.emplace_back((mfxU8)type_);
while(payload_size > 255)
{
buffer.emplace_back(0xff);
payload_size -= 255;
}
buffer.emplace_back(payload_size);
buffer.insert(end(buffer), begin(data), end(data));
data_buffers.emplace_back(buffer);
payloads.emplace_back(mfxPayload());
mfxPayload &sei_payload = payloads.back();
zero(sei_payload);
sei_payload.Type = type;
sei_payload.BufSize = buffer.size();
sei_payload.NumBit = sei_payload.BufSize*8;
sei_payload.Data = &data_buffers.back().front();
payload_list.clear();
for(auto &payload = begin(payloads); payload != end(payloads); payload++)
payload_list.emplace_back(&*payload);
ctrl.Payload = &payload_list.front();
ctrl.NumPayload = payload_list.size();
}

78
QSVHelper/QSVStuff.h Normal file
View File

@ -0,0 +1,78 @@
/********************************************************************************
Copyright (C) 2013 Ruwen Hahn <palana@stunned.de>
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 <mfxvideo++.h>
#include <algorithm>
#include <vector>
#include "Utilities.h"
template <class T>
inline T align16(T t)
{
return (((t + 15) >> 4) << 4);
}
struct Parameters
{
private:
mfxVideoParam params;
std::vector<mfxExtBuffer*> ext_buffers;
public:
mfxExtCodingOptionSPSPPS cospspps;
mfxExtVideoSignalInfo vsi;
operator mfxVideoParam() { return params; }
operator mfxVideoParam*() { return &params; }
mfxVideoParam* operator&() { return &params; }
mfxVideoParam* operator->() { return &params; }
void Init(int fps, int keyframe_interval_frames, int bframes, int width, int height, int max_bitrate, int buffer_size, bool use_cbr);
void SetCodingOptionSPSPPS(mfxU8 *sps_buff, mfxU16 sps_size, mfxU8 *pps_buff, mfxU16 pps_size);
void SetVideoSignalInfo(int full_range, int primaries, int transfer, int matrix);
Parameters();
protected:
void UpdateExt();
template <class T>
bool FindExt(T& t) { return std::find(std::begin(ext_buffers), std::end(ext_buffers), reinterpret_cast<mfxExtBuffer*>(&t)) != std::end(ext_buffers); }
template <class T>
void AddExt(T& t) { ext_buffers.emplace_back(reinterpret_cast<mfxExtBuffer*>(&t)); UpdateExt(); }
};
struct EncodeCtrl
{
enum sei_type {SEI_USER_DATA_UNREGISTERED=0x5};
mfxEncodeCtrl ctrl;
std::vector<mfxPayload*> payload_list;
std::vector<mfxPayload> payloads;
std::vector<std::vector<mfxU8>> data_buffers;
operator mfxEncodeCtrl() { return ctrl; }
mfxEncodeCtrl *operator&() { return &ctrl; }
void AddSEIData(sei_type type, std::vector<mfxU8> payload);
EncodeCtrl() { zero(ctrl); }
};

76
QSVHelper/SupportStuff.h Normal file
View File

@ -0,0 +1,76 @@
/********************************************************************************
Copyright (C) 2013 Ruwen Hahn <palana@stunned.de>
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 <mfxvideo++.h>
#include "Utilities.h"
#include "QSVStuff.h"
struct encode_task
{
mfxFrameSurface1 *surf;
mfxBitstream bs;
mfxSyncPoint sp;
mfxEncodeCtrl *ctrl;
size_t frame_index;
void Init(mfxU8 *bs_start, mfxU32 bs_size)
{
sp = nullptr;
ctrl = nullptr;
surf = nullptr;
zero(bs);
bs.Data = bs_start;
bs.MaxLength = bs_size;
}
};
void InitFrame(mfxFrameData &frame, mfxU8 *Y, mfxU8 *UV, mfxU8 *V, mfxU16 pitch)
{
zero(frame);
frame.Y = Y;
frame.UV = UV;
frame.V = V;
frame.Pitch = pitch;
}
std::vector<mfxU8> InitSEIUserData(bool use_cbr, const mfxVideoParam& params, const mfxVersion& ver)
{
using namespace std;
vector<mfxU8> data;
const mfxU8 UUID[] = { 0x6d, 0x1a, 0x26, 0xa0, 0xbd, 0xdc, 0x11, 0xe2, //ISO-11578 UUID
0x90, 0x24, 0x00, 0x50, 0xc2, 0x49, 0x00, 0x48 }; //6d1a26a0-bddc-11e2-9024-0050c2490048
data.insert(end(data), begin(UUID), end(UUID));
ostringstream str;
str << "QSV hardware encoder options:"
<< " rate control: " << (use_cbr ? "cbr" : "vbr")
<< "; target bitrate: " << params.mfx.TargetKbps
<< "; max bitrate: " << params.mfx.MaxKbps
<< "; buffersize: " << params.mfx.BufferSizeInKB*8
<< "; API level: " << ver.Major << "." << ver.Minor;
string str_(str.str());
data.insert(end(data), begin(str_), end(str_));
return data;
}

25
QSVHelper/Utilities.h Normal file
View File

@ -0,0 +1,25 @@
/********************************************************************************
Copyright (C) 2013 Ruwen Hahn <palana@stunned.de>
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
template <class T>
void zero(T& t, size_t size=sizeof(T))
{
memset(&t, 0, size);
}

221
QSVHelper/WindowsStuff.h Normal file
View File

@ -0,0 +1,221 @@
/********************************************************************************
Copyright (C) 2013 Ruwen Hahn <palana@stunned.de>
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 <Windows.h>
#include <cassert>
#include <cstdint>
#include <fstream>
#include <memory>
#include <string>
#include <vector>
struct safe_handle
{
HANDLE h;
operator bool() const { return h != nullptr; }
operator HANDLE() { return h; }
void reset(HANDLE h_=nullptr) { if(h) CloseHandle(h); h = h_; }
bool operator!() const { return !h; }
safe_handle &operator=(safe_handle &&other) { reset(other.h); other.h = nullptr; return *this; }
safe_handle(HANDLE h=nullptr) : h(h) {}
~safe_handle() { if(h) CloseHandle(h); }
safe_handle(safe_handle &&other) : h(other.h) { other.h = nullptr; };
private:
safe_handle(const safe_handle&);
};
struct NamedSharedMemory
{
std::wstring name;
uint64_t size;
void *memory;
safe_handle file;
bool operator!() const { return !memory || !file; }
void *operator&() { return memory; }
template <class T>
T &as() { return *reinterpret_cast<T*>(memory); }
NamedSharedMemory &operator=(NamedSharedMemory &&other)
{ FreeMemory(); name = other.name; size = other.size; memory = other.memory; other.memory = nullptr; file = std::move(other.file); return *this; }
//NamedSharedMemory(const NamedSharedMemory& other) : name(other.name), size(other.size), memory(nullptr) { InitMemory(); }
NamedSharedMemory(NamedSharedMemory&& other)
: name(std::move(other.name)), size(std::move(other.size)), memory(std::move(other.memory)), file(std::move(other.file)) { other.memory = nullptr; }
~NamedSharedMemory() { FreeMemory(); }
NamedSharedMemory(std::wstring name, uint64_t size=1) : name(name), size(size), memory(nullptr) { InitMemory(); }
NamedSharedMemory() : memory(nullptr) {}
private:
void FreeMemory() { if(memory) UnmapViewOfFile(memory); memory = nullptr; }
void InitMemory()
{
if(!size)
size = 1;
file.reset(CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, size>>32, size & 0xffffffff, name.c_str()));
if(file)
memory = MapViewOfFile(file, FILE_MAP_ALL_ACCESS, 0, 0, 0);
}
};
struct IPCSignal
{
safe_handle signal_;
bool is_signalled(DWORD timeout=0) { return WaitForSingleObject(signal_, timeout) == WAIT_OBJECT_0; }
void signal() { SetEvent(signal_); }
bool operator!() const { return !signal_; }
IPCSignal &operator=(IPCSignal &&other) { signal_ = std::move(other.signal_); return *this; }
IPCSignal(std::wstring name) { signal_.reset(CreateEvent(nullptr, false, false, name.c_str())); }
IPCSignal() {}
};
struct IPCWaiter
{
std::vector<HANDLE> list;
void push_back(const HANDLE &h) { list.push_back(h); }
bool wait(DWORD timeout=0) { if(!list.size()) return false; auto res = wait_for_multiple_objects(timeout); return WAIT_OBJECT_0 <= res && res < (WAIT_OBJECT_0+list.size()); }
bool wait_for(DWORD object, DWORD timeout=0) { if(!list.size()) return false; return wait_for_multiple_objects(timeout) == (WAIT_OBJECT_0 + object); }
bool wait_for_two(DWORD first, DWORD second, DWORD timeout=0) { if(!list.size()) return false; auto res = wait_for_multiple_objects(timeout); return res == (WAIT_OBJECT_0 + first) || res == (WAIT_OBJECT_0 + second); }
bool wait_timeout(DWORD timeout=0) { if(!list.size()) return false; return wait_for_multiple_objects(timeout) == WAIT_TIMEOUT; }
private:
DWORD wait_for_multiple_objects(DWORD timeout) { return WaitForMultipleObjects(static_cast<DWORD>(list.size()), &list.front(), false, timeout); }
};
struct IPCMutex
{
safe_handle mutex_;
void lock() { if(mutex_) WaitForSingleObject(mutex_, INFINITE); }
void unlock() { if(mutex_) ReleaseMutex(mutex_); }
bool operator!() { return !mutex_; }
IPCMutex &operator=(IPCMutex &&other) { mutex_ = std::move(other.mutex_); return *this; }
IPCMutex(std::wstring name) { mutex_.reset(CreateMutex(nullptr, false, name.c_str())); }
IPCMutex() {}
};
template <class T>
struct IPCMutexLock
{
T& t;
bool enabled;
IPCMutexLock(T &t) : t(t), enabled(true) { t.lock(); }
~IPCMutexLock() { if(enabled) t.unlock(); }
IPCMutexLock(IPCMutexLock &&other) : t(other.t), enabled(other.enabled) { other.enabled = false; }
};
template <class T>
IPCMutexLock<T> lock_mutex(T &t) { return IPCMutexLock<T>(t); }
template <class T, class F>
void with_locked(T &t, F &f) { IPCMutexLock<T> lock(t); f(); }
template <class T>
struct IPCType
{
NamedSharedMemory memory;
bool operator!() const { return !memory; }
operator T() { return memory.as<T>(); }
T *operator&() { return &memory.as<T>(); }
T *operator->() { return &memory.as<T>(); }
T &operator*() { return memory.as<T>(); }
IPCType &operator=(IPCType &&other) { memory = std::move(other.memory); return *this; }
IPCType(std::wstring name) : memory(name, sizeof(T)) {}
IPCType() {}
};
template <class T>
struct IPCSignalledType : IPCType<T>, IPCSignal
{
bool operator!() const { return !memory || !signal_; }
IPCSignalledType &operator=(IPCSignalledType &&other) { memory = std::move(other.memory); signal_ = std::move(other.signal_); return *this; }
IPCSignalledType(std::wstring name) : IPCType(name), IPCSignal(name+L"Signal") {}
IPCSignalledType() {}
};
template <class T>
struct IPCLockedSignalledType : IPCSignalledType<T>, IPCMutex
{
bool operator!() const { return !memory || !signal_ || !mutex_; }
IPCLockedSignalledType &operator=(IPCLockedSignalledType &&other) { memory = std::move(other.memory); signal_ = std::move(other.signal_); mutex_ = std::move(other.mutex_); return *this; }
IPCLockedSignalledType(std::wstring name) : IPCSignalledType(name), IPCMutex(name+L"Lock") {}
IPCLockedSignalledType() {}
};
template <class T>
struct IPCArray
{
NamedSharedMemory memory;
size_t size;
bool operator!() const { return !memory; }
operator T*() { return static_cast<T*>(&memory); }
IPCArray &operator=(IPCArray &&other) { memory = std::move(other.memory); size = other.size; return *this; }
IPCArray(std::wstring name, size_t size) : memory(name, sizeof(T)*size), size(size) {}
IPCArray() {}
};
template <class T>
struct IPCSignalledArray : IPCArray<T>, IPCSignal
{
bool operator!() const { return !memory || !signal_; }
IPCSignalledArray &operator=(IPCSignalledArray &&other) { memory = std::move(other.memory); signal_ = std::move(other.signal_); size = other.size; return *this; }
IPCSignalledArray(std::wstring name, size_t size) : IPCArray(name, size), IPCSignal(name+L"Signal") {}
IPCSignalledArray() {}
};
template <class T>
struct IPCLockedSignalledArray : IPCSignalledArray<T>, IPCMutex
{
bool operator!() { return !memory || !signal_ || !mutex_; }
IPCLockedSignalledArray &operator=(IPCLockedSignalledArray &&other)
{ memory = std::move(other.memory); signal_ = std::move(other.signal_); mutex_ = std::move(other.mutex_); size = other.size; return *this; }
IPCLockedSignalledArray(std::wstring name, size_t size) : IPCSignalledArray(name, size), IPCMutex(name+L"Lock") {}
IPCLockedSignalledArray() {}
};

File diff suppressed because it is too large Load Diff

View File

@ -43,6 +43,7 @@ copy ..\graphicscapture\graphicscapturehook\release\graphicscapturehook.dll .\32
copy ..\graphicscapture\graphicscapturehook\x64\release\graphicscapturehook64.dll .\32bit\plugins\graphicscapture copy ..\graphicscapture\graphicscapturehook\x64\release\graphicscapturehook64.dll .\32bit\plugins\graphicscapture
copy ..\injectHelper\x64\release\injectHelper64.exe .\32bit\plugins\graphicscapture copy ..\injectHelper\x64\release\injectHelper64.exe .\32bit\plugins\graphicscapture
copy ..\x264\libs\32bit\libx264-136.dll .\32bit copy ..\x264\libs\32bit\libx264-136.dll .\32bit
copy ..\QSVHelper\Release\QSVHelper.exe .\32bit
copy "%WindowsSDK80Path%Debuggers\x86\dbghelp.dll" .\32bit copy "%WindowsSDK80Path%Debuggers\x86\dbghelp.dll" .\32bit
copy ..\x64\release\obs.exe .\64bit\ copy ..\x64\release\obs.exe .\64bit\
@ -63,6 +64,7 @@ copy ..\graphicscapture\graphicscapturehook\release\graphicscapturehook.dll .\64
copy ..\graphicscapture\graphicscapturehook\x64\release\graphicscapturehook64.dll .\64bit\plugins\graphicscapture copy ..\graphicscapture\graphicscapturehook\x64\release\graphicscapturehook64.dll .\64bit\plugins\graphicscapture
copy ..\injectHelper\release\injectHelper.exe .\64bit\plugins\graphicscapture copy ..\injectHelper\release\injectHelper.exe .\64bit\plugins\graphicscapture
copy ..\x264\libs\64bit\libx264-136.dll .\64bit copy ..\x264\libs\64bit\libx264-136.dll .\64bit
copy ..\QSVHelper\Release\QSVHelper.exe .\64bit
copy "%WindowsSDK80Path%Debuggers\x64\dbghelp.dll" .\64bit copy "%WindowsSDK80Path%Debuggers\x64\dbghelp.dll" .\64bit
copy ..\rundir\pdb32\*.pdb .\pdbs\32bit copy ..\rundir\pdb32\*.pdb .\pdbs\32bit
@ -128,6 +130,7 @@ copy ..\obsapi\release\obsapi.dll .\upload\OBS\32bit\
copy ..\OBSHelp\OBSHelp.chm .\upload\OBS\32bit\ copy ..\OBSHelp\OBSHelp.chm .\upload\OBS\32bit\
copy ..\rundir\pdb32\stripped\*.pdb .\upload\OBS\32bit\ copy ..\rundir\pdb32\stripped\*.pdb .\upload\OBS\32bit\
copy ..\x264\libs\32bit\libx264-136.dll .\upload\OBS\32bit copy ..\x264\libs\32bit\libx264-136.dll .\upload\OBS\32bit
copy ..\QSVHelper\Release\QSVHelper.exe .\upload\OBS\32bit
copy "%WindowsSDK80Path%Debuggers\x86\dbghelp.dll" .\upload\OBS\32bit copy "%WindowsSDK80Path%Debuggers\x86\dbghelp.dll" .\upload\OBS\32bit
copy ..\x64\release\obs.exe .\upload\OBS\64bit\ copy ..\x64\release\obs.exe .\upload\OBS\64bit\
@ -135,6 +138,7 @@ copy ..\obsapi\x64\release\obsapi.dll .\upload\OBS\64bit\
copy ..\OBSHelp\OBSHelp.chm .\upload\OBS\64bit\ copy ..\OBSHelp\OBSHelp.chm .\upload\OBS\64bit\
copy ..\rundir\pdb64\stripped\*.pdb .\upload\OBS\64bit\ copy ..\rundir\pdb64\stripped\*.pdb .\upload\OBS\64bit\
copy ..\x264\libs\64bit\libx264-136.dll .\upload\OBS\64bit copy ..\x264\libs\64bit\libx264-136.dll .\upload\OBS\64bit
copy ..\QSVHelper\Release\QSVHelper.exe .\upload\OBS\64bit
copy "%WindowsSDK80Path%Debuggers\x64\dbghelp.dll" .\upload\OBS\64bit copy "%WindowsSDK80Path%Debuggers\x64\dbghelp.dll" .\upload\OBS\64bit
copy ..\rundir\locale\*.txt .\upload\OBS\locale\ copy ..\rundir\locale\*.txt .\upload\OBS\locale\

View File

@ -44,6 +44,7 @@ copy ..\graphicscapture\graphicscapturehook\release\graphicscapturehook.dll .\32
copy ..\graphicscapture\graphicscapturehook\x64\release\graphicscapturehook64.dll .\32bit\plugins\graphicscapture copy ..\graphicscapture\graphicscapturehook\x64\release\graphicscapturehook64.dll .\32bit\plugins\graphicscapture
copy ..\injectHelper\x64\release\injectHelper64.exe .\32bit\plugins\graphicscapture copy ..\injectHelper\x64\release\injectHelper64.exe .\32bit\plugins\graphicscapture
copy ..\x264\libs\32bit\libx264-136.dll .\32bit copy ..\x264\libs\32bit\libx264-136.dll .\32bit
copy ..\QSVHelper\Release\QSVHelper.exe .\32bit
copy "%WindowsSDK80Path%Debuggers\x86\dbghelp.dll" .\32bit copy "%WindowsSDK80Path%Debuggers\x86\dbghelp.dll" .\32bit
copy ..\x64\release\obs.exe .\64bit\ copy ..\x64\release\obs.exe .\64bit\
@ -69,4 +70,5 @@ copy ..\graphicscapture\graphicscapturehook\release\graphicscapturehook.dll .\64
copy ..\graphicscapture\graphicscapturehook\x64\release\graphicscapturehook64.dll .\64bit\plugins\graphicscapture copy ..\graphicscapture\graphicscapturehook\x64\release\graphicscapturehook64.dll .\64bit\plugins\graphicscapture
copy ..\injectHelper\release\injectHelper.exe .\64bit\plugins\graphicscapture copy ..\injectHelper\release\injectHelper.exe .\64bit\plugins\graphicscapture
copy ..\x264\libs\64bit\libx264-136.dll .\64bit copy ..\x264\libs\64bit\libx264-136.dll .\64bit
copy ..\QSVHelper\Release\QSVHelper.exe .\64bit
copy "%WindowsSDK80Path%Debuggers\x64\dbghelp.dll" .\64bit copy "%WindowsSDK80Path%Debuggers\x64\dbghelp.dll" .\64bit

View File

@ -113,6 +113,7 @@ Section "Open Broadcaster Software" Section1
SetOutPath "$PROGRAMFILES32\OBS" SetOutPath "$PROGRAMFILES32\OBS"
File "..\Release\OBS.exe" File "..\Release\OBS.exe"
File "..\x264\libs\32bit\libx264-136.dll" File "..\x264\libs\32bit\libx264-136.dll"
File "..\QSVHelper\Release\QSVHelper.exe"
File "..\OBSAPI\Release\OBSApi.dll" File "..\OBSAPI\Release\OBSApi.dll"
File "..\rundir\services.xconfig" File "..\rundir\services.xconfig"
File "..\OBSHelp\OBSHelp.chm" File "..\OBSHelp\OBSHelp.chm"
@ -142,6 +143,7 @@ Section "Open Broadcaster Software" Section1
SetOutPath "$PROGRAMFILES64\OBS" SetOutPath "$PROGRAMFILES64\OBS"
File "..\x64\Release\OBS.exe" File "..\x64\Release\OBS.exe"
File "..\x264\libs\64bit\libx264-136.dll" File "..\x264\libs\64bit\libx264-136.dll"
File "..\QSVHelper\Release\QSVHelper.exe"
File "..\OBSAPI\x64\Release\OBSApi.dll" File "..\OBSAPI\x64\Release\OBSApi.dll"
File "..\rundir\services.xconfig" File "..\rundir\services.xconfig"
File "..\OBSHelp\OBSHelp.chm" File "..\OBSHelp\OBSHelp.chm"
@ -219,6 +221,7 @@ Section Uninstall
; Clean up Open Broadcaster Software ; Clean up Open Broadcaster Software
Delete "$PROGRAMFILES32\OBS\OBS.exe" Delete "$PROGRAMFILES32\OBS\OBS.exe"
Delete "$PROGRAMFILES32\OBS\libx264-136.dll" Delete "$PROGRAMFILES32\OBS\libx264-136.dll"
Delete "$PROGRAMFILES32\OBS\QSVHelper.exe"
Delete "$PROGRAMFILES32\OBS\OBSApi.dll" Delete "$PROGRAMFILES32\OBS\OBSApi.dll"
Delete "$PROGRAMFILES32\OBS\services.xconfig" Delete "$PROGRAMFILES32\OBS\services.xconfig"
Delete "$PROGRAMFILES32\OBS\*.chm" Delete "$PROGRAMFILES32\OBS\*.chm"
@ -238,6 +241,7 @@ Section Uninstall
${if} ${RunningX64} ${if} ${RunningX64}
Delete "$PROGRAMFILES64\OBS\OBS.exe" Delete "$PROGRAMFILES64\OBS\OBS.exe"
Delete "$PROGRAMFILES64\OBS\libx264-136.dll" Delete "$PROGRAMFILES64\OBS\libx264-136.dll"
Delete "$PROGRAMFILES64\OBS\QSVHelper.exe"
Delete "$PROGRAMFILES64\OBS\OBSApi.dll" Delete "$PROGRAMFILES64\OBS\OBSApi.dll"
Delete "$PROGRAMFILES64\OBS\services.xconfig" Delete "$PROGRAMFILES64\OBS\services.xconfig"
Delete "$PROGRAMFILES64\OBS\*.chm" Delete "$PROGRAMFILES64\OBS\*.chm"
@ -282,4 +286,4 @@ Section Uninstall
RMDir "$PROGRAMFILES32\OBS" RMDir "$PROGRAMFILES32\OBS"
SectionEnd SectionEnd
; eof ; eof