From c5117e5b77a6840a4422e233f7c71ea42ff4ac4c Mon Sep 17 00:00:00 2001 From: hecomi Date: Mon, 9 Sep 2019 17:50:03 +0900 Subject: [PATCH] support multiple encoders. --- .../uNvEncoder/Examples/Scenes/Example.unity | 171 +++++++++++--- .../Examples/Scripts/TextureEncoder.cs | 15 +- ...rTexture => Render Camera 1.renderTexture} | 2 +- ...eta => Render Camera 1.renderTexture.meta} | 0 .../Textures/Render Camera 2.renderTexture | 36 +++ .../Render Camera 2.renderTexture.meta | 8 + Assets/uNvEncoder/Plugins/x86/uNvEncoder.dll | Bin 36864 -> 40960 bytes .../uNvEncoder/Plugins/x86_64/uNvEncoder.dll | Bin 44032 -> 48640 bytes .../Scripts/{uNvEncoder.cs => Encoder.cs} | 79 +++---- .../{uNvEncoder.cs.meta => Encoder.cs.meta} | 0 Assets/uNvEncoder/Scripts/Lib.cs | 51 ++++ .../{uNvEncoderLib.cs.meta => Lib.cs.meta} | 0 Assets/uNvEncoder/Scripts/uNvEncoderLib.cs | 49 ---- Plugins/uNvEncoder/uNvEncoder/Common.cpp | 5 +- Plugins/uNvEncoder/uNvEncoder/Common.h | 2 +- Plugins/uNvEncoder/uNvEncoder/Encoder.cpp | 65 ++++-- Plugins/uNvEncoder/uNvEncoder/Encoder.h | 4 + Plugins/uNvEncoder/uNvEncoder/Main.cpp | 129 ++++++----- Plugins/uNvEncoder/uNvEncoder/Nvenc.cpp | 219 ++++++++++-------- Plugins/uNvEncoder/uNvEncoder/Nvenc.h | 21 +- 20 files changed, 552 insertions(+), 304 deletions(-) rename Assets/uNvEncoder/Examples/Textures/{Render Camera.renderTexture => Render Camera 1.renderTexture} (96%) rename Assets/uNvEncoder/Examples/Textures/{Render Camera.renderTexture.meta => Render Camera 1.renderTexture.meta} (100%) create mode 100644 Assets/uNvEncoder/Examples/Textures/Render Camera 2.renderTexture create mode 100644 Assets/uNvEncoder/Examples/Textures/Render Camera 2.renderTexture.meta rename Assets/uNvEncoder/Scripts/{uNvEncoder.cs => Encoder.cs} (51%) rename Assets/uNvEncoder/Scripts/{uNvEncoder.cs.meta => Encoder.cs.meta} (100%) create mode 100644 Assets/uNvEncoder/Scripts/Lib.cs rename Assets/uNvEncoder/Scripts/{uNvEncoderLib.cs.meta => Lib.cs.meta} (100%) delete mode 100644 Assets/uNvEncoder/Scripts/uNvEncoderLib.cs diff --git a/Assets/uNvEncoder/Examples/Scenes/Example.unity b/Assets/uNvEncoder/Examples/Scenes/Example.unity index 489d9f9..72f519a 100644 --- a/Assets/uNvEncoder/Examples/Scenes/Example.unity +++ b/Assets/uNvEncoder/Examples/Scenes/Example.unity @@ -120,6 +120,127 @@ NavMeshSettings: debug: m_Flags: 0 m_NavMeshData: {fileID: 0} +--- !u!1 &512188855 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 512188856} + - component: {fileID: 512188859} + - component: {fileID: 512188858} + - component: {fileID: 512188857} + m_Layer: 0 + m_Name: Render Camera 2 + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &512188856 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 512188855} + m_LocalRotation: {x: 0.31189665, y: 0.20372555, z: 0.068658166, w: 0.92547417} + m_LocalPosition: {x: -1.03, y: 1.4, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 963194228} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 33.321003, y: 30.167002, z: 17.708} +--- !u!114 &512188857 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 512188855} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0833f6be5a296eb4fb05eca6ff7e6439, type: 3} + m_Name: + m_EditorClassIdentifier: + filePath: test-2.h264 +--- !u!114 &512188858 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 512188855} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 28d5e7ad59d1ad44f9e9ea9443db919c, type: 3} + m_Name: + m_EditorClassIdentifier: + encoder: + onEncoded: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 512188857} + m_MethodName: OnEncoded + m_Mode: 0 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + m_TypeName: uNvEncoder.Encoder+EncodedCallback, Assembly-CSharp, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + texture: {fileID: 8400000, guid: fdebf29a4668aa5438593de1aad273f3, type: 2} + frameRate: 60 + forceIdrFrame: 0 +--- !u!20 &512188859 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 512188855} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 8400000, guid: fdebf29a4668aa5438593de1aad273f3, type: 2} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 --- !u!1 &705507993 GameObject: m_ObjectHideFlags: 0 @@ -292,6 +413,7 @@ Transform: m_LocalScale: {x: 1, y: 1, z: 1} m_Children: - {fileID: 1076557919} + - {fileID: 512188856} m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -305,11 +427,10 @@ GameObject: m_Component: - component: {fileID: 1076557919} - component: {fileID: 1076557923} - - component: {fileID: 1076557922} - component: {fileID: 1076557921} - component: {fileID: 1076557920} m_Layer: 0 - m_Name: Render Camera + m_Name: Render Camera 1 m_TagString: MainCamera m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -354,38 +475,26 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 28d5e7ad59d1ad44f9e9ea9443db919c, type: 3} m_Name: m_EditorClassIdentifier: - encoder: {fileID: 1076557922} + encoder: + onEncoded: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1076557920} + m_MethodName: OnEncoded + m_Mode: 0 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + m_TypeName: uNvEncoder.Encoder+EncodedCallback, Assembly-CSharp, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null texture: {fileID: 8400000, guid: 314a1f1bf10d90f4eb4025543112bd83, type: 2} frameRate: 60 forceIdrFrame: 0 ---- !u!114 &1076557922 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1076557918} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 6ae92fb89500a024088102c416bc5426, type: 3} - m_Name: - m_EditorClassIdentifier: - onEncoded: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 1076557920} - m_MethodName: OnEncoded - m_Mode: 0 - m_Arguments: - m_ObjectArgument: {fileID: 0} - m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine - m_IntArgument: 0 - m_FloatArgument: 0 - m_StringArgument: - m_BoolArgument: 0 - m_CallState: 2 - m_TypeName: uNvEncoder.uNvEncoderEncode+EncodedCallback, Assembly-CSharp, Version=0.0.0.0, - Culture=neutral, PublicKeyToken=null --- !u!20 &1076557923 Camera: m_ObjectHideFlags: 0 diff --git a/Assets/uNvEncoder/Examples/Scripts/TextureEncoder.cs b/Assets/uNvEncoder/Examples/Scripts/TextureEncoder.cs index 2a673d0..5100fb2 100644 --- a/Assets/uNvEncoder/Examples/Scripts/TextureEncoder.cs +++ b/Assets/uNvEncoder/Examples/Scripts/TextureEncoder.cs @@ -7,23 +7,22 @@ namespace uNvEncoder.Examples public class TextureEncoder : MonoBehaviour { - public uNvEncoder encoder = null; + public Encoder encoder = new Encoder(); public Texture texture = null; public int frameRate = 60; public bool forceIdrFrame = true; void OnEnable() { - Assert.IsNotNull(encoder); Assert.IsNotNull(texture); - encoder.StartEncode(texture.width, texture.height, frameRate); + encoder.Create(texture.width, texture.height, frameRate); StartCoroutine(EncodeLoop()); } void OnDisable() { StopAllCoroutines(); - encoder.StopEncode(); + encoder.Destroy(); } IEnumerator EncodeLoop() @@ -37,14 +36,10 @@ IEnumerator EncodeLoop() void Encode() { - if (!encoder || !encoder.isValid) return; - if (!texture) return; - if (!encoder.Encode(texture, forceIdrFrame)) - { - Debug.LogError("Encode() failed."); - } + encoder.Update(); + encoder.Encode(texture, forceIdrFrame); } } diff --git a/Assets/uNvEncoder/Examples/Textures/Render Camera.renderTexture b/Assets/uNvEncoder/Examples/Textures/Render Camera 1.renderTexture similarity index 96% rename from Assets/uNvEncoder/Examples/Textures/Render Camera.renderTexture rename to Assets/uNvEncoder/Examples/Textures/Render Camera 1.renderTexture index d8b3b2d..ffb5b28 100644 --- a/Assets/uNvEncoder/Examples/Textures/Render Camera.renderTexture +++ b/Assets/uNvEncoder/Examples/Textures/Render Camera 1.renderTexture @@ -6,7 +6,7 @@ RenderTexture: m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_Name: Render Camera + m_Name: Render Camera 1 m_ImageContentsHash: serializedVersion: 2 Hash: 00000000000000000000000000000000 diff --git a/Assets/uNvEncoder/Examples/Textures/Render Camera.renderTexture.meta b/Assets/uNvEncoder/Examples/Textures/Render Camera 1.renderTexture.meta similarity index 100% rename from Assets/uNvEncoder/Examples/Textures/Render Camera.renderTexture.meta rename to Assets/uNvEncoder/Examples/Textures/Render Camera 1.renderTexture.meta diff --git a/Assets/uNvEncoder/Examples/Textures/Render Camera 2.renderTexture b/Assets/uNvEncoder/Examples/Textures/Render Camera 2.renderTexture new file mode 100644 index 0000000..ee7a166 --- /dev/null +++ b/Assets/uNvEncoder/Examples/Textures/Render Camera 2.renderTexture @@ -0,0 +1,36 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!84 &8400000 +RenderTexture: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Render Camera 2 + m_ImageContentsHash: + serializedVersion: 2 + Hash: 00000000000000000000000000000000 + m_ForcedFallbackFormat: 4 + m_DownscaleFallback: 0 + serializedVersion: 3 + m_Width: 1024 + m_Height: 1024 + m_AntiAliasing: 1 + m_DepthFormat: 0 + m_ColorFormat: 8 + m_MipMap: 0 + m_GenerateMips: 1 + m_SRGB: 0 + m_UseDynamicScale: 0 + m_BindMS: 0 + m_EnableCompatibleFormat: 1 + m_TextureSettings: + serializedVersion: 2 + m_FilterMode: 1 + m_Aniso: 0 + m_MipBias: 0 + m_WrapU: 1 + m_WrapV: 1 + m_WrapW: 1 + m_Dimension: 2 + m_VolumeDepth: 1 diff --git a/Assets/uNvEncoder/Examples/Textures/Render Camera 2.renderTexture.meta b/Assets/uNvEncoder/Examples/Textures/Render Camera 2.renderTexture.meta new file mode 100644 index 0000000..3f8c848 --- /dev/null +++ b/Assets/uNvEncoder/Examples/Textures/Render Camera 2.renderTexture.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fdebf29a4668aa5438593de1aad273f3 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 8400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/uNvEncoder/Plugins/x86/uNvEncoder.dll b/Assets/uNvEncoder/Plugins/x86/uNvEncoder.dll index 008d5b7d428cc4acf35c47695557d451c75ac759..fb383399c4149ac3b0c0186a477bb54886417ec8 100644 GIT binary patch literal 40960 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 literal 36864 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 diff --git a/Assets/uNvEncoder/Plugins/x86_64/uNvEncoder.dll b/Assets/uNvEncoder/Plugins/x86_64/uNvEncoder.dll index 6a9bd8ed0bc417be02d6f110e51784b5a3a32f61..1e5b6b6c201dd3fb020d9bf1f934190ca19969df 100644 GIT binary patch literal 48640 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 literal 44032 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 diff --git a/Assets/uNvEncoder/Scripts/uNvEncoder.cs b/Assets/uNvEncoder/Scripts/Encoder.cs similarity index 51% rename from Assets/uNvEncoder/Scripts/uNvEncoder.cs rename to Assets/uNvEncoder/Scripts/Encoder.cs index e8d0a45..f9d762d 100644 --- a/Assets/uNvEncoder/Scripts/uNvEncoder.cs +++ b/Assets/uNvEncoder/Scripts/Encoder.cs @@ -1,82 +1,77 @@ using UnityEngine; using UnityEngine.Events; -using UnityEngine.Assertions; -using System.Threading.Tasks; namespace uNvEncoder { -public class uNvEncoder : MonoBehaviour +[System.Serializable] +public class Encoder { - static uNvEncoder instance; - [System.Serializable] public class EncodedCallback : UnityEvent {}; public EncodedCallback onEncoded = new EncodedCallback(); - Task encodeTask_; + public int id { get; private set; } = -1; public bool isValid { - get { return Lib.IsValid(); } + get { return Lib.IsValid(id); } } public int width { - get { return Lib.GetWidth(); } + get { return Lib.GetWidth(id); } } public int height { - get { return Lib.GetHeight(); } + get { return Lib.GetHeight(id); } } public int frameRate { - get { return Lib.GetFrameRate(); } - } - - void OnDisable() - { + get { return Lib.GetFrameRate(id); } } - void Update() + public string error { - if (!isValid) return; - - Lib.CopyEncodedData(); + get + { + if (!Lib.HasError(id)) return ""; - int n = Lib.GetEncodedDataCount(); - for (int i = 0; i < n; ++i) - { - var size = Lib.GetEncodedDataSize(i); - var data = Lib.GetEncodedDataBuffer(i); - onEncoded.Invoke(data, size); + var str = Lib.GetError(id); + Lib.ClearError(id); + return str; } } - public void StartEncode(int width, int height, int frameRate) + public void Create(int width, int height, int frameRate) { - Assert.IsNull(instance, "Multiple uNvEncoderEncode instance not allowed."); - if (instance) return; - - instance = this; - - Lib.Initialize(width, height, frameRate); + id = Lib.CreateEncoder(width, height, frameRate); if (!isValid) { - Debug.LogError(Lib.GetLastError()); + Debug.LogError(error); } } - public void StopEncode() + public void Destroy() { - Lib.Finalize(); + Lib.DestroyEncoder(id); + } + + public void Update() + { + if (!isValid) return; + + Lib.CopyEncodedData(id); - if (instance == this) + int n = Lib.GetEncodedDataCount(id); + for (int i = 0; i < n; ++i) { - instance = null; + var size = Lib.GetEncodedDataSize(id, i); + var data = Lib.GetEncodedDataBuffer(id, i); + onEncoded.Invoke(data, size); } } @@ -89,7 +84,13 @@ public bool Encode(Texture texture, bool forceIdrFrame) } var ptr = texture.GetNativeTexturePtr(); - return Encode(ptr, forceIdrFrame); + if (!Encode(ptr, forceIdrFrame)) + { + Debug.LogError(error); + return false; + } + + return true; } public bool Encode(System.IntPtr ptr, bool forceIdrFrame) @@ -106,10 +107,10 @@ public bool Encode(System.IntPtr ptr, bool forceIdrFrame) return false; } - var result = Lib.Encode(ptr, forceIdrFrame); + var result = Lib.Encode(id, ptr, forceIdrFrame); if (!result) { - Debug.LogError(Lib.GetLastError()); + Debug.LogError(error); } return result; diff --git a/Assets/uNvEncoder/Scripts/uNvEncoder.cs.meta b/Assets/uNvEncoder/Scripts/Encoder.cs.meta similarity index 100% rename from Assets/uNvEncoder/Scripts/uNvEncoder.cs.meta rename to Assets/uNvEncoder/Scripts/Encoder.cs.meta diff --git a/Assets/uNvEncoder/Scripts/Lib.cs b/Assets/uNvEncoder/Scripts/Lib.cs new file mode 100644 index 0000000..43f5a0b --- /dev/null +++ b/Assets/uNvEncoder/Scripts/Lib.cs @@ -0,0 +1,51 @@ +using System; +using System.Runtime.InteropServices; + +#pragma warning disable CS0465 + +namespace uNvEncoder +{ + +public static class Lib +{ + public const string dllName = "uNvEncoder"; + + // --- + + [DllImport(dllName, EntryPoint = "uNvEncoderCreateEncoder")] + public static extern int CreateEncoder(int width, int height, int frameRate); + [DllImport(dllName, EntryPoint = "uNvEncoderDestroyEncoder")] + public static extern int DestroyEncoder(int id); + [DllImport(dllName, EntryPoint = "uNvEncoderIsValid")] + public static extern bool IsValid(int id); + [DllImport(dllName, EntryPoint = "uNvEncoderGetWidth")] + public static extern int GetWidth(int id); + [DllImport(dllName, EntryPoint = "uNvEncoderGetHeight")] + public static extern int GetHeight(int id); + [DllImport(dllName, EntryPoint = "uNvEncoderGetFrameRate")] + public static extern int GetFrameRate(int id); + [DllImport(dllName, EntryPoint = "uNvEncoderEncode")] + public static extern bool Encode(int id, IntPtr texturePtr, bool forceIdrFrame); + [DllImport(dllName, EntryPoint = "uNvEncoderCopyEncodedData")] + public static extern void CopyEncodedData(int id); + [DllImport(dllName, EntryPoint = "uNvEncoderGetEncodedDataCount")] + public static extern int GetEncodedDataCount(int id); + [DllImport(dllName, EntryPoint = "uNvEncoderGetEncodedDataSize")] + public static extern int GetEncodedDataSize(int id, int index); + [DllImport(dllName, EntryPoint = "uNvEncoderGetEncodedDataBuffer")] + public static extern IntPtr GetEncodedDataBuffer(int id, int index); + [DllImport(dllName, EntryPoint = "uNvEncoderGetError")] + private static extern IntPtr GetErrorInternal(int id); + [DllImport(dllName, EntryPoint = "uNvEncoderHasError")] + public static extern bool HasError(int id); + [DllImport(dllName, EntryPoint = "uNvEncoderClearError")] + public static extern void ClearError(int id); + + public static string GetError(int id) + { + var ptr = GetErrorInternal(id); + return Marshal.PtrToStringAnsi(ptr); + } +} + +} diff --git a/Assets/uNvEncoder/Scripts/uNvEncoderLib.cs.meta b/Assets/uNvEncoder/Scripts/Lib.cs.meta similarity index 100% rename from Assets/uNvEncoder/Scripts/uNvEncoderLib.cs.meta rename to Assets/uNvEncoder/Scripts/Lib.cs.meta diff --git a/Assets/uNvEncoder/Scripts/uNvEncoderLib.cs b/Assets/uNvEncoder/Scripts/uNvEncoderLib.cs deleted file mode 100644 index 4ad5e4b..0000000 --- a/Assets/uNvEncoder/Scripts/uNvEncoderLib.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -#pragma warning disable CS0465 - -namespace uNvEncoder -{ - -public static class Lib -{ - public const string dllName = "uNvEncoder"; - - // --- - - [DllImport(dllName, EntryPoint = "uNvEncoderInitialize")] - public static extern void Initialize(int width, int height, int frameRate); - [DllImport(dllName, EntryPoint = "uNvEncoderFinalize")] - public static extern void Finalize(); - [DllImport(dllName, EntryPoint = "uNvEncoderIsValid")] - public static extern bool IsValid(); - [DllImport(dllName, EntryPoint = "uNvEncoderGetWidth")] - public static extern int GetWidth(); - [DllImport(dllName, EntryPoint = "uNvEncoderGetHeight")] - public static extern int GetHeight(); - [DllImport(dllName, EntryPoint = "uNvEncoderGetFrameRate")] - public static extern int GetFrameRate(); - [DllImport(dllName, EntryPoint = "uNvEncoderEncode")] - public static extern bool Encode(IntPtr texturePtr, bool forceIdrFrame); - [DllImport(dllName, EntryPoint = "uNvEncoderCopyEncodedData")] - public static extern void CopyEncodedData(); - [DllImport(dllName, EntryPoint = "uNvEncoderGetEncodedDataCount")] - public static extern int GetEncodedDataCount(); - [DllImport(dllName, EntryPoint = "uNvEncoderGetEncodedDataSize")] - public static extern int GetEncodedDataSize(int i); - [DllImport(dllName, EntryPoint = "uNvEncoderGetEncodedDataBuffer")] - public static extern IntPtr GetEncodedDataBuffer(int i); - [DllImport(dllName, EntryPoint = "uNvEncoderGetEncodedDataIndex")] - public static extern int GetEncodedDataIndex(int i); - [DllImport(dllName, EntryPoint = "uNvEncoderGetLastError")] - private static extern IntPtr GetLastErrorInternal(); - - public static string GetLastError() - { - var ptr = GetLastErrorInternal(); - return Marshal.PtrToStringAnsi(ptr); - } -} - -} diff --git a/Plugins/uNvEncoder/uNvEncoder/Common.cpp b/Plugins/uNvEncoder/uNvEncoder/Common.cpp index efa6139..3106719 100644 --- a/Plugins/uNvEncoder/uNvEncoder/Common.cpp +++ b/Plugins/uNvEncoder/uNvEncoder/Common.cpp @@ -9,7 +9,6 @@ namespace uNvEncoder extern IUnityInterfaces *g_unity; -extern std::string g_error; IUnityInterfaces * GetUnity() @@ -24,10 +23,10 @@ ID3D11Device * GetUnityDevice() } -void DebugError(const std::string &error) +void ThrowError(const std::string &error) { ::OutputDebugStringA((error + "\n").c_str()); - g_error = error; + throw std::exception(error.c_str()); } diff --git a/Plugins/uNvEncoder/uNvEncoder/Common.h b/Plugins/uNvEncoder/uNvEncoder/Common.h index 0c9ad10..08cd2e1 100644 --- a/Plugins/uNvEncoder/uNvEncoder/Common.h +++ b/Plugins/uNvEncoder/uNvEncoder/Common.h @@ -18,7 +18,7 @@ using ComPtr = Microsoft::WRL::ComPtr; struct IUnityInterfaces * GetUnity(); struct ID3D11Device * GetUnityDevice(); -void DebugError(const std::string &error); +void ThrowError(const std::string &error); #define UNVENC_DEBUG_ON diff --git a/Plugins/uNvEncoder/uNvEncoder/Encoder.cpp b/Plugins/uNvEncoder/uNvEncoder/Encoder.cpp index ff9c089..58617aa 100644 --- a/Plugins/uNvEncoder/uNvEncoder/Encoder.cpp +++ b/Plugins/uNvEncoder/uNvEncoder/Encoder.cpp @@ -9,17 +9,31 @@ namespace uNvEncoder Encoder::Encoder(const EncoderDesc &desc) : desc_(desc) { - CreateDevice(); - CreateNvenc(); - StartThread(); + try + { + CreateDevice(); + CreateNvenc(); + StartThread(); + } + catch (const std::exception& e) + { + error_ = e.what(); + } } Encoder::~Encoder() { - StopThread(); - DestroyNvenc(); - DestroyDevice(); + try + { + StopThread(); + DestroyNvenc(); + DestroyDevice(); + } + catch (const std::exception& e) + { + error_ = e.what(); + } } @@ -34,14 +48,14 @@ void Encoder::CreateDevice() ComPtr dxgiDevice; if (FAILED(GetUnityDevice()->QueryInterface(IID_PPV_ARGS(&dxgiDevice)))) { - DebugError("Failed to get IDXGIDevice1."); + ThrowError("Failed to get IDXGIDevice1."); return; } ComPtr dxgiAdapter; if (FAILED(dxgiDevice->GetAdapter(&dxgiAdapter))) { - DebugError("Failed to get IDXGIAdapter."); + ThrowError("Failed to get IDXGIAdapter."); return; } @@ -88,11 +102,13 @@ void Encoder::CreateNvenc() desc.frameRate = desc_.frameRate; nvenc_ = std::make_unique(desc); + nvenc_->Initialize(); } void Encoder::DestroyNvenc() { + nvenc_->Finalize(); nvenc_.reset(); } @@ -124,13 +140,18 @@ void Encoder::StopThread() bool Encoder::Encode(const ComPtr &source, bool forceIdrFrame) { - if (nvenc_->Encode(source, forceIdrFrame)) + try + { + nvenc_->Encode(source, forceIdrFrame); + } + catch (const std::exception& e) { - RequestGetEncodedData(); - return true; + error_ = e.what(); + return false; } - return false; + RequestGetEncodedData(); + return true; } @@ -156,13 +177,21 @@ void Encoder::RequestGetEncodedData() void Encoder::UpdateGetEncodedData() { std::vector data; - if (nvenc_->GetEncodedData(data)) + + try { - std::lock_guard dataLock(encodeDataListMutex_); - for (auto &ed : data) - { - encodedDataList_.push_back(std::move(ed)); - } + nvenc_->GetEncodedData(data); + } + catch (const std::exception& e) + { + error_ = e.what(); + return; + } + + std::lock_guard dataLock(encodeDataListMutex_); + for (auto &ed : data) + { + encodedDataList_.push_back(std::move(ed)); } } diff --git a/Plugins/uNvEncoder/uNvEncoder/Encoder.h b/Plugins/uNvEncoder/uNvEncoder/Encoder.h index 321fd5b..67b7621 100644 --- a/Plugins/uNvEncoder/uNvEncoder/Encoder.h +++ b/Plugins/uNvEncoder/uNvEncoder/Encoder.h @@ -37,6 +37,9 @@ class Encoder final const uint32_t GetWidth() const { return desc_.width; } const uint32_t GetHeight() const { return desc_.height; } const uint32_t GetFrameRate() const { return desc_.frameRate; } + bool HasError() const { return !error_.empty(); } + const std::string & GetError() const { return error_; } + void ClearError() { error_.clear(); } private: void CreateDevice(); @@ -60,6 +63,7 @@ class Encoder final std::mutex encodeDataListMutex_; bool shouldStopEncodeThread_ = false; bool isEncodeRequested = false; + std::string error_; }; diff --git a/Plugins/uNvEncoder/uNvEncoder/Main.cpp b/Plugins/uNvEncoder/uNvEncoder/Main.cpp index b4bedb2..fb8e5b1 100644 --- a/Plugins/uNvEncoder/uNvEncoder/Main.cpp +++ b/Plugins/uNvEncoder/uNvEncoder/Main.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include "Encoder.h" @@ -10,13 +10,19 @@ using namespace uNvEncoder; +using EncoderId = int; namespace uNvEncoder { IUnityInterfaces *g_unity = nullptr; - std::string g_error; - std::unique_ptr g_encoder; +} + + +namespace +{ + std::map> g_encoders; + EncoderId g_encoderId = 0; } @@ -36,117 +42,134 @@ UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UnityPluginUnload() } -UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API uNvEncoderInitialize(int width, int height, int frameRate) +const std::unique_ptr & GetEncoder(EncoderId id) { - if (g_encoder || !g_unity) return; + static std::unique_ptr invalid; + const auto it = g_encoders.find(id); + return (it != g_encoders.end()) ? it->second : invalid; +} + + +UNITY_INTERFACE_EXPORT EncoderId UNITY_INTERFACE_API uNvEncoderCreateEncoder(int width, int height, int frameRate) +{ + const auto id = g_encoderId++; EncoderDesc desc; desc.width = width; desc.height = height; desc.frameRate = frameRate; - g_encoder = std::make_unique(desc); + auto encoder = std::make_unique(desc); + g_encoders.emplace(id, std::move(encoder)); + + return id; } -UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API uNvEncoderFinalize() +UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API uNvEncoderDestroyEncoder(EncoderId id) { - if (!g_encoder) return; - - g_encoder.reset(); + g_encoders.erase(id); } -UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API uNvEncoderIsValid() +UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API uNvEncoderIsValid(EncoderId id) { - return g_encoder && g_encoder->IsValid(); + const auto &encoder = GetEncoder(id); + return encoder ? encoder->IsValid() : false; } -UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API uNvEncoderGetWidth() +UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API uNvEncoderGetWidth(EncoderId id) { - if (!uNvEncoderIsValid()) return 0; - - return static_cast(g_encoder->GetWidth()); + const auto &encoder = GetEncoder(id); + return encoder ? static_cast(encoder->GetWidth()) : 0; } -UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API uNvEncoderGetHeight() +UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API uNvEncoderGetHeight(EncoderId id) { - if (!uNvEncoderIsValid()) return 0; - - return static_cast(g_encoder->GetHeight()); + const auto &encoder = GetEncoder(id); + return encoder ? static_cast(encoder->GetHeight()) : 0; } -UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API uNvEncoderGetFrameRate() +UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API uNvEncoderGetFrameRate(EncoderId id) { - if (!uNvEncoderIsValid()) return 0; - - return static_cast(g_encoder->GetFrameRate()); + const auto &encoder = GetEncoder(id); + return encoder ? static_cast(encoder->GetFrameRate()) : 0; } -UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API uNvEncoderEncode(ID3D11Texture2D *texture, bool forceIdrFrame) +UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API uNvEncoderEncode(EncoderId id, ID3D11Texture2D *texture, bool forceIdrFrame) { - if (!uNvEncoderIsValid()) return false; - - return g_encoder->Encode(texture, forceIdrFrame); + if (const auto &encoder = GetEncoder(id)) + { + return encoder->Encode(texture, forceIdrFrame); + } + return false; } -UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API uNvEncoderCopyEncodedData() +UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API uNvEncoderCopyEncodedData(EncoderId id) { - if (!uNvEncoderIsValid()) return; - - return g_encoder->CopyEncodedDataList(); + if (const auto &encoder = GetEncoder(id)) + { + encoder->CopyEncodedDataList(); + } } -UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API uNvEncoderGetEncodedDataCount() +UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API uNvEncoderGetEncodedDataCount(EncoderId id) { - if (!uNvEncoderIsValid()) return 0; - - return static_cast(g_encoder->GetEncodedDataList().size()); + const auto &encoder = GetEncoder(id); + return encoder ? static_cast(encoder->GetEncodedDataList().size()) : 0; } -UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API uNvEncoderGetEncodedDataSize(int i) +UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API uNvEncoderGetEncodedDataSize(EncoderId id, int index) { - if (!uNvEncoderIsValid()) return 0; + const auto &encoder = GetEncoder(id); + if (!encoder) return 0; - const auto &list = g_encoder->GetEncodedDataList(); - if (i < 0 || i >= static_cast(list.size())) return 0; + const auto &list = encoder->GetEncodedDataList(); + if (index < 0 || index >= static_cast(list.size())) return 0; - return static_cast(list.at(i).size); + return static_cast(list.at(index).size); } -UNITY_INTERFACE_EXPORT const void * UNITY_INTERFACE_API uNvEncoderGetEncodedDataBuffer(int i) +UNITY_INTERFACE_EXPORT const void * UNITY_INTERFACE_API uNvEncoderGetEncodedDataBuffer(EncoderId id, int index) { - if (!uNvEncoderIsValid()) return nullptr; + const auto &encoder = GetEncoder(id); + if (!encoder) return nullptr; - const auto &list = g_encoder->GetEncodedDataList(); - if (i < 0 || i >= static_cast(list.size())) return nullptr; + const auto &list = encoder->GetEncodedDataList(); + if (index < 0 || index >= static_cast(list.size())) return nullptr; - return list.at(i).buffer.get(); + return list.at(index).buffer.get(); } -UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API uNvEncoderGetEncodedDataIndex(int i) +UNITY_INTERFACE_EXPORT const char * UNITY_INTERFACE_API uNvEncoderGetError(EncoderId id) { - if (!uNvEncoderIsValid()) return -1; + const auto &encoder = GetEncoder(id); + return encoder ? encoder->GetError().c_str() : nullptr; +} - const auto &list = g_encoder->GetEncodedDataList(); - if (i < 0 || i >= static_cast(list.size())) return -1; - return static_cast(list.at(i).index); +UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API uNvEncoderHasError(EncoderId id) +{ + const auto &encoder = GetEncoder(id); + return encoder ? encoder->HasError() : false; } -UNITY_INTERFACE_EXPORT const char * UNITY_INTERFACE_API uNvEncoderGetLastError() +UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API uNvEncoderClearError(EncoderId id) { - return g_error.c_str(); + if (const auto &encoder = GetEncoder(id)) + { + encoder->ClearError(); + } } diff --git a/Plugins/uNvEncoder/uNvEncoder/Nvenc.cpp b/Plugins/uNvEncoder/uNvEncoder/Nvenc.cpp index 7eac77a..b3d6fcd 100644 --- a/Plugins/uNvEncoder/uNvEncoder/Nvenc.cpp +++ b/Plugins/uNvEncoder/uNvEncoder/Nvenc.cpp @@ -42,7 +42,7 @@ void OutputNvencApiError(const std::string &apiName, NVENCSTATUS status) const auto it = nvEncStatusErrorNameTable.find(status); const auto statusStr = it != nvEncStatusErrorNameTable.end() ? it->second : "Unknown"; - DebugError(apiName + " call failed: " + statusStr); + ThrowError(apiName + " call failed: " + statusStr); } @@ -62,15 +62,79 @@ NVENCSTATUS CallNvencApi(const std::string &apiName, const Api &api, const Args #define CALL_NVENC_API(Api, ...) CallNvencApi(#Api, Api, __VA_ARGS__) + +decltype(Nvenc::s_module) Nvenc::s_module = NULL; +decltype(Nvenc::s_nvenc) Nvenc::s_nvenc = { 0 }; +decltype(Nvenc::s_referenceCount) Nvenc::s_referenceCount = 0; + + +void Nvenc::LoadModule() +{ + ++s_referenceCount; + + if (s_module != NULL) return; + +#if defined(_WIN64) + s_module = ::LoadLibraryA("nvEncodeAPI64.dll"); +#else + s_module = ::LoadLibraryA("nvEncodeAPI.dll"); +#endif + if (s_module == NULL) ThrowError("NVENC is not available."); + + if (const auto funcAddress = ::GetProcAddress(s_module, "NvEncodeAPIGetMaxSupportedVersion")) + { + using FuncType = decltype(NvEncodeAPIGetMaxSupportedVersion); + const auto func = reinterpret_cast(funcAddress); + uint32_t version = 0; + const auto res = func(&version); + constexpr uint32_t currentVersion = (NVENCAPI_MAJOR_VERSION << 4) | NVENCAPI_MINOR_VERSION; + if (currentVersion > version) ThrowError("NVENC version is wrong."); + } + + if (const auto funcAddress = ::GetProcAddress(s_module, "NvEncodeAPICreateInstance")) + { + using FuncType = decltype(NvEncodeAPICreateInstance); + const auto func = reinterpret_cast(funcAddress); + s_nvenc = { NV_ENCODE_API_FUNCTION_LIST_VER }; + func(&s_nvenc); + + if (!s_nvenc.nvEncOpenEncodeSession) + { + ThrowError("Failed to load functions from DLL."); + } + } +} + + +void Nvenc::UnloadModule() +{ + if (--s_referenceCount > 0) return; + + if (s_module != NULL) + { + ::FreeLibrary(s_module); + s_module = NULL; + } +} + + Nvenc::Nvenc(const NvencDesc &desc) : desc_(desc) , resources_(1) { - if (!LoadModule()) - { - return; - } +} + +Nvenc::~Nvenc() +{ +} + + +void Nvenc::Initialize() +{ + if (isInitialized_) return; + + LoadModule(); OpenEncodeSession(); InitializeEncoder(); @@ -78,61 +142,29 @@ Nvenc::Nvenc(const NvencDesc &desc) CreateInputTextures(); RegisterResources(); CreateBitstreamBuffers(); + + isInitialized_ = true; } -Nvenc::~Nvenc() +void Nvenc::Finalize() { + if (!isInitialized_) return; + EndEncode(); DestroyBitstreamBuffers(); UnregisterResources(); DestroyCompletionEvents(); DestroyEncoder(); - UnloadModule(); -} - - -bool Nvenc::LoadModule() -{ -#if defined(_WIN64) - module_ = ::LoadLibraryA("nvEncodeAPI64.dll"); -#else - module_ = ::LoadLibraryA("nvEncodeAPI.dll"); -#endif - if (!module_) return false; -#define CALL_NVENC_API_FROM_DLL(API, ...) \ - using API##Func = decltype(API); \ - const auto API##Address = GetProcAddress(module_, #API); \ - if (!API##Address) return false; \ - const auto API = reinterpret_cast(API##Address); \ - const auto API##Result = API(__VA_ARGS__); \ - if (API##Result != NV_ENC_SUCCESS) return false; - - uint32_t version = 0; - CALL_NVENC_API_FROM_DLL(NvEncodeAPIGetMaxSupportedVersion, &version); - const uint32_t currentVersion = (NVENCAPI_MAJOR_VERSION << 4) | NVENCAPI_MINOR_VERSION; - if (currentVersion > version) return false; - - nvenc_ = { NV_ENCODE_API_FUNCTION_LIST_VER }; - CALL_NVENC_API_FROM_DLL(NvEncodeAPICreateInstance, &nvenc_); - - if (!nvenc_.nvEncOpenEncodeSession) - { - return false; - } - - return true; + isInitialized_ = false; } -void Nvenc::UnloadModule() +void Nvenc::ThrowErrorIfNotInitialized() { - if (!module_) return; - - ::FreeLibrary(module_); - module_ = nullptr; + if (!IsValid()) ThrowError("NVENC has not been initialized yet."); } @@ -142,7 +174,7 @@ void Nvenc::OpenEncodeSession() encSessionParams.device = desc_.d3d11Device.Get(); encSessionParams.deviceType = NV_ENC_DEVICE_TYPE_DIRECTX; encSessionParams.apiVersion = NVENCAPI_VERSION; - CALL_NVENC_API(nvenc_.nvEncOpenEncodeSessionEx, &encSessionParams, &encoder_); + CALL_NVENC_API(s_nvenc.nvEncOpenEncodeSessionEx, &encSessionParams, &encoder_); } @@ -167,7 +199,7 @@ void Nvenc::InitializeEncoder() initParams.enableEncodeAsync = true; NV_ENC_PRESET_CONFIG presetConfig = { NV_ENC_PRESET_CONFIG_VER, { NV_ENC_CONFIG_VER } }; - CALL_NVENC_API(nvenc_.nvEncGetEncodePresetConfig, encoder_, initParams.encodeGUID, initParams.presetGUID, &presetConfig); + CALL_NVENC_API(s_nvenc.nvEncGetEncodePresetConfig, encoder_, initParams.encodeGUID, initParams.presetGUID, &presetConfig); NV_ENC_CONFIG config = { NV_ENC_CONFIG_VER }; memcpy(&config, &presetConfig.presetCfg, sizeof(NV_ENC_CONFIG)); @@ -181,27 +213,27 @@ void Nvenc::InitializeEncoder() config.encodeCodecConfig.h264Config.maxNumRefFrames = 0; config.encodeCodecConfig.h264Config.idrPeriod = config.gopLength; - CALL_NVENC_API(nvenc_.nvEncInitializeEncoder, encoder_, &initParams); + CALL_NVENC_API(s_nvenc.nvEncInitializeEncoder, encoder_, &initParams); } void Nvenc::CreateCompletionEvents() { - if (!IsValid()) return; + ThrowErrorIfNotInitialized(); for (auto &resource : resources_) { resource.completionEvent_ = ::CreateEventA(NULL, FALSE, FALSE, NULL); NV_ENC_EVENT_PARAMS eventParams = { NV_ENC_EVENT_PARAMS_VER }; eventParams.completionEvent = resource.completionEvent_; - CALL_NVENC_API(nvenc_.nvEncRegisterAsyncEvent, encoder_, &eventParams); + CALL_NVENC_API(s_nvenc.nvEncRegisterAsyncEvent, encoder_, &eventParams); } } void Nvenc::DestroyCompletionEvents() { - if (!IsValid()) return; + ThrowErrorIfNotInitialized(); for (auto &resource : resources_) { @@ -209,7 +241,7 @@ void Nvenc::DestroyCompletionEvents() NV_ENC_EVENT_PARAMS eventParams = { NV_ENC_EVENT_PARAMS_VER }; eventParams.completionEvent = resource.completionEvent_; - CALL_NVENC_API(nvenc_.nvEncUnregisterAsyncEvent, encoder_, &eventParams); + CALL_NVENC_API(s_nvenc.nvEncUnregisterAsyncEvent, encoder_, &eventParams); ::CloseHandle(resource.completionEvent_); } } @@ -217,12 +249,12 @@ void Nvenc::DestroyCompletionEvents() void Nvenc::CreateBitstreamBuffers() { - if (!IsValid()) return; + ThrowErrorIfNotInitialized(); for (auto &resource : resources_) { NV_ENC_CREATE_BITSTREAM_BUFFER createBitstreamBuffer = { NV_ENC_CREATE_BITSTREAM_BUFFER_VER }; - CALL_NVENC_API(nvenc_.nvEncCreateBitstreamBuffer, encoder_, &createBitstreamBuffer); + CALL_NVENC_API(s_nvenc.nvEncCreateBitstreamBuffer, encoder_, &createBitstreamBuffer); resource.bitstreamBuffer_ = createBitstreamBuffer.bitstreamBuffer; } } @@ -230,7 +262,7 @@ void Nvenc::CreateBitstreamBuffers() void Nvenc::CreateInputTextures() { - if (!IsValid()) return; + ThrowErrorIfNotInitialized(); D3D11_TEXTURE2D_DESC desc = { 0 }; desc.Width = desc_.width; @@ -248,7 +280,7 @@ void Nvenc::CreateInputTextures() { if (FAILED(desc_.d3d11Device->CreateTexture2D(&desc, NULL, &resource.inputTexture_))) { - DebugError("Failed to create shared texture."); + ThrowError("Failed to create shared texture."); return; } @@ -256,7 +288,7 @@ void Nvenc::CreateInputTextures() resource.inputTexture_.As(&dxgiResource); if (FAILED(dxgiResource->GetSharedHandle(&resource.inputTextureSharedHandle_))) { - DebugError("Failed to get shared handle."); + ThrowError("Failed to get shared handle."); return; } } @@ -265,7 +297,7 @@ void Nvenc::CreateInputTextures() void Nvenc::RegisterResources() { - if (!IsValid()) return; + ThrowErrorIfNotInitialized(); for (auto &resource : resources_) { @@ -277,7 +309,7 @@ void Nvenc::RegisterResources() registerResource.pitch = 0; registerResource.bufferFormat = NV_ENC_BUFFER_FORMAT_ARGB; registerResource.bufferUsage = NV_ENC_INPUT_IMAGE; - CALL_NVENC_API(nvenc_.nvEncRegisterResource, encoder_, ®isterResource); + CALL_NVENC_API(s_nvenc.nvEncRegisterResource, encoder_, ®isterResource); resource.registeredResource_ = registerResource.registeredResource; } @@ -286,47 +318,46 @@ void Nvenc::RegisterResources() void Nvenc::UnregisterResources() { - if (!IsValid()) return; + ThrowErrorIfNotInitialized(); for (auto &resource : resources_) { if (!resource.registeredResource_) continue; - CALL_NVENC_API(nvenc_.nvEncUnregisterResource, encoder_, resource.registeredResource_); + CALL_NVENC_API(s_nvenc.nvEncUnregisterResource, encoder_, resource.registeredResource_); } } void Nvenc::DestroyBitstreamBuffers() { - if (!IsValid()) return; + ThrowErrorIfNotInitialized(); for (auto &resource : resources_) { if (!resource.bitstreamBuffer_) continue; - CALL_NVENC_API(nvenc_.nvEncDestroyBitstreamBuffer, encoder_, resource.bitstreamBuffer_); + CALL_NVENC_API(s_nvenc.nvEncDestroyBitstreamBuffer, encoder_, resource.bitstreamBuffer_); } } void Nvenc::DestroyEncoder() { - if (!IsValid()) return; + ThrowErrorIfNotInitialized(); - CALL_NVENC_API(nvenc_.nvEncDestroyEncoder, encoder_); + CALL_NVENC_API(s_nvenc.nvEncDestroyEncoder, encoder_); } -bool Nvenc::Encode(const ComPtr &source, bool forceIdrFrame) +void Nvenc::Encode(const ComPtr &source, bool forceIdrFrame) { - if (!IsValid()) return false; + ThrowErrorIfNotInitialized(); const auto index = GetInputIndex(); auto &resource = resources_[index]; if (resource.isEncoding_) { - DebugError("The previous encode is still continuing."); - return false; + ThrowError("The previous encode is still continuing."); } resource.isEncoding_ = true; @@ -336,19 +367,17 @@ bool Nvenc::Encode(const ComPtr &source, bool forceIdrFrame) if (EncodeInputTexture(index, forceIdrFrame)) { ++inputIndex_; - return true; } else { resource.isEncoding_ = false; - return false; } } void Nvenc::CopyToInputTexture(int index, const ComPtr &texture) { - if (!IsValid()) return; + ThrowErrorIfNotInitialized(); auto &resource = resources_[index]; ComPtr inputTexture; @@ -358,7 +387,7 @@ void Nvenc::CopyToInputTexture(int index, const ComPtr &texture __uuidof(ID3D11Texture2D), &inputTexture))) { - DebugError("Failed to open shared texture from shared handle."); + ThrowError("Failed to open shared texture from shared handle."); return; } @@ -371,7 +400,7 @@ void Nvenc::CopyToInputTexture(int index, const ComPtr &texture bool Nvenc::EncodeInputTexture(int index, bool forceIdrFrame) { - if (!IsValid()) return false; + ThrowErrorIfNotInitialized(); auto &resource = resources_[index]; @@ -389,7 +418,7 @@ bool Nvenc::EncodeInputTexture(int index, bool forceIdrFrame) picParams.encodePicFlags = NV_ENC_PIC_FLAG_FORCEIDR | NV_ENC_PIC_FLAG_OUTPUT_SPSPPS; } - const auto status = CALL_NVENC_API(nvenc_.nvEncEncodePicture, encoder_, &picParams); + const auto status = CALL_NVENC_API(s_nvenc.nvEncEncodePicture, encoder_, &picParams); if (status != NV_ENC_SUCCESS && status != NV_ENC_ERR_NEED_MORE_INPUT) { return false; @@ -401,32 +430,35 @@ bool Nvenc::EncodeInputTexture(int index, bool forceIdrFrame) void Nvenc::MapInputResource(int index) { - if (!IsValid()) return; + ThrowErrorIfNotInitialized(); auto &resource = resources_[index]; if (!resource.registeredResource_) return; NV_ENC_MAP_INPUT_RESOURCE mapInputResource = { NV_ENC_MAP_INPUT_RESOURCE_VER }; mapInputResource.registeredResource = resource.registeredResource_; - CALL_NVENC_API(nvenc_.nvEncMapInputResource, encoder_, &mapInputResource); + CALL_NVENC_API(s_nvenc.nvEncMapInputResource, encoder_, &mapInputResource); resource.inputResource_ = mapInputResource.mappedResource; } void Nvenc::UnmapInputResource(int index) { - if (!IsValid()) return; + ThrowErrorIfNotInitialized(); auto &resource = resources_[index]; - CALL_NVENC_API(nvenc_.nvEncUnmapInputResource, encoder_, resource.inputResource_); - resource.inputResource_ = nullptr; + if (!resource.inputResource_) + { + CALL_NVENC_API(s_nvenc.nvEncUnmapInputResource, encoder_, resource.inputResource_); + resource.inputResource_ = nullptr; + } } -bool Nvenc::GetEncodedData(std::vector &data) +void Nvenc::GetEncodedData(std::vector &data) { - if (!IsValid()) return false; + ThrowErrorIfNotInitialized(); for (;outputIndex_ < inputIndex_; ++outputIndex_) { @@ -435,21 +467,21 @@ bool Nvenc::GetEncodedData(std::vector &data) if (!resource.isEncoding_) { - DebugError("Try to get an invalid bitstream."); + ThrowError("Try to get an invalid bitstream."); continue; } constexpr DWORD duration = 10000; if (!WaitForCompletion(index, duration)) { - DebugError("Timeout when getting an encoded bitstream."); + ThrowError("Timeout when getting an encoded bitstream."); continue; } NV_ENC_LOCK_BITSTREAM lockBitstream = { NV_ENC_LOCK_BITSTREAM_VER }; lockBitstream.outputBitstream = resource.bitstreamBuffer_; lockBitstream.doNotWait = false; - CALL_NVENC_API(nvenc_.nvEncLockBitstream, encoder_, &lockBitstream); + CALL_NVENC_API(s_nvenc.nvEncLockBitstream, encoder_, &lockBitstream); NvencEncodedData ed; ed.index = outputIndex_; @@ -458,26 +490,24 @@ bool Nvenc::GetEncodedData(std::vector &data) ::memcpy(ed.buffer.get(), lockBitstream.bitstreamBufferPtr, ed.size); data.push_back(std::move(ed)); - CALL_NVENC_API(nvenc_.nvEncUnlockBitstream, encoder_, resource.bitstreamBuffer_); + CALL_NVENC_API(s_nvenc.nvEncUnlockBitstream, encoder_, resource.bitstreamBuffer_); UnmapInputResource(index); resource.isEncoding_ = false; } - - return !data.empty(); } bool Nvenc::WaitForCompletion(int index, DWORD duration) { - if (!IsValid()) return false; + ThrowErrorIfNotInitialized(); auto &resource = resources_[index]; if (::WaitForSingleObject(resource.completionEvent_, duration) == WAIT_FAILED) { - DebugError("Failed to wait for encode completion."); + ThrowError("Failed to wait for encode completion."); return false; } @@ -487,7 +517,9 @@ bool Nvenc::WaitForCompletion(int index, DWORD duration) void Nvenc::EndEncode() { - if (!IsValid() || inputIndex_ == 0U) return; + ThrowErrorIfNotInitialized(); + + if (inputIndex_ == 0U) return; SendEOS(); @@ -498,14 +530,15 @@ void Nvenc::EndEncode() void Nvenc::SendEOS() { - if (!IsValid()) return; + ThrowErrorIfNotInitialized(); auto &resource = resources_[GetInputIndex()]; + resource.isEncoding_ = true; NV_ENC_PIC_PARAMS picParams = { NV_ENC_PIC_PARAMS_VER }; picParams.encodePicFlags = NV_ENC_PIC_FLAG_EOS; picParams.completionEvent = resource.completionEvent_; - CALL_NVENC_API(nvenc_.nvEncEncodePicture, encoder_, &picParams); + CALL_NVENC_API(s_nvenc.nvEncEncodePicture, encoder_, &picParams); ++inputIndex_; } diff --git a/Plugins/uNvEncoder/uNvEncoder/Nvenc.h b/Plugins/uNvEncoder/uNvEncoder/Nvenc.h index 1531c8d..f352059 100644 --- a/Plugins/uNvEncoder/uNvEncoder/Nvenc.h +++ b/Plugins/uNvEncoder/uNvEncoder/Nvenc.h @@ -35,16 +35,17 @@ class Nvenc final public: explicit Nvenc(const NvencDesc &desc); ~Nvenc(); + void Initialize(); + void Finalize(); bool IsValid() const { return encoder_ != nullptr; } - bool Encode(const ComPtr &source, bool forceIdrFrame); - bool GetEncodedData(std::vector &data); + void Encode(const ComPtr &source, bool forceIdrFrame); + void GetEncodedData(std::vector &data); const uint32_t GetWidth() const { return desc_.width; } const uint32_t GetHeight() const { return desc_.height; } const uint32_t GetFrameRate() const { return desc_.frameRate; } private: - bool LoadModule(); - void UnloadModule(); + void ThrowErrorIfNotInitialized(); void OpenEncodeSession(); void InitializeEncoder(); @@ -70,8 +71,7 @@ class Nvenc final unsigned long GetOutputIndex() const { return outputIndex_ % GetResourceCount(); } const NvencDesc desc_; - HMODULE module_ = nullptr; - NV_ENCODE_API_FUNCTION_LIST nvenc_ = { 0 }; + bool isInitialized_ = false; void *encoder_ = nullptr; uint64_t inputIndex_ = 0U; uint64_t outputIndex_ = 0U; @@ -87,6 +87,15 @@ class Nvenc final std::atomic isEncoding_ = false; }; std::vector resources_; + +public: + static void LoadModule(); + static void UnloadModule(); + +private: + static HMODULE s_module; + static NV_ENCODE_API_FUNCTION_LIST s_nvenc; + static uint32_t s_referenceCount; };