1
0
Эх сурвалжийг харах

obs-qsv: Allow for multiple QSV encoders

Allow multiple QSV encoders, usefull for live + recorded parallel
sessions.  The first QSV encoder will create a DirectX device and return
a handle / pointer.  Any additional QSV encoder will use that same
pointer to the DirectX device.  We keep track of the number of open
QSV encoders so that we wait to close the DirectX resources after all
encoders are closed.

Closes obsproject/obs-studio#1341
Bird, Christopher 7 жил өмнө
parent
commit
3a08e858a6

+ 0 - 5
plugins/obs-qsv11/QSV_Encoder.cpp

@@ -81,11 +81,6 @@ void qsv_encoder_version(unsigned short *major, unsigned short *minor)
 qsv_t *qsv_encoder_open(qsv_param_t *pParams)
 qsv_t *qsv_encoder_open(qsv_param_t *pParams)
 {
 {
 	bool false_value = false;
 	bool false_value = false;
-	if (!is_active.compare_exchange_strong(false_value, true)) {
-		do_log(LOG_ERROR, "Cannot have more than one encoder "
-				"active at a time");
-		return NULL;
-	}
 
 
 	QSV_Encoder_Internal *pEncoder = new QSV_Encoder_Internal(impl, ver);
 	QSV_Encoder_Internal *pEncoder = new QSV_Encoder_Internal(impl, ver);
 	mfxStatus sts = pEncoder->Open(pParams);
 	mfxStatus sts = pEncoder->Open(pParams);

+ 15 - 5
plugins/obs-qsv11/QSV_Encoder_Internal.cpp

@@ -69,6 +69,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define info(format, ...)  do_log(LOG_INFO,    format, ##__VA_ARGS__)
 #define info(format, ...)  do_log(LOG_INFO,    format, ##__VA_ARGS__)
 #define debug(format, ...) do_log(LOG_DEBUG,   format, ##__VA_ARGS__)
 #define debug(format, ...) do_log(LOG_DEBUG,   format, ##__VA_ARGS__)
 
 
+mfxHDL QSV_Encoder_Internal::g_DX_Handle = NULL;
+mfxU16 QSV_Encoder_Internal::g_numEncodersOpen = 0;
+
 QSV_Encoder_Internal::QSV_Encoder_Internal(mfxIMPL& impl, mfxVersion& version) :
 QSV_Encoder_Internal::QSV_Encoder_Internal(mfxIMPL& impl, mfxVersion& version) :
 	m_pmfxENC(NULL),
 	m_pmfxENC(NULL),
 	m_nSPSBufferSize(100),
 	m_nSPSBufferSize(100),
@@ -152,10 +155,10 @@ mfxStatus QSV_Encoder_Internal::Open(qsv_param_t * pParams)
 
 
 	if (m_bUseD3D11)
 	if (m_bUseD3D11)
 		// Use D3D11 surface
 		// Use D3D11 surface
-		sts = Initialize(m_impl, m_ver, &m_session, &m_mfxAllocator, false, false);
+		sts = Initialize(m_impl, m_ver, &m_session, &m_mfxAllocator, &g_DX_Handle, false, false);
 	else if (m_bD3D9HACK)
 	else if (m_bD3D9HACK)
 		// Use hack
 		// Use hack
-		sts = Initialize(m_impl, m_ver, &m_session, &m_mfxAllocator, false, true);
+		sts = Initialize(m_impl, m_ver, &m_session, &m_mfxAllocator, &g_DX_Handle, false, true);
 	else
 	else
 		sts = Initialize(m_impl, m_ver, &m_session, NULL);
 		sts = Initialize(m_impl, m_ver, &m_session, NULL);
 
 
@@ -182,6 +185,9 @@ mfxStatus QSV_Encoder_Internal::Open(qsv_param_t * pParams)
 	sts = InitBitstream();
 	sts = InitBitstream();
 	MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
 	MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
 
 
+	if (sts >= MFX_ERR_NONE) {
+		g_numEncodersOpen++;
+	}
 	return sts;
 	return sts;
 }
 }
 
 
@@ -598,11 +604,15 @@ mfxStatus QSV_Encoder_Internal::ClearData()
 	delete m_pmfxENC;
 	delete m_pmfxENC;
 	m_pmfxENC = NULL;
 	m_pmfxENC = NULL;
 
 
-	if (m_bUseD3D11 || m_bD3D9HACK)
-		Release();
+	if (sts >= MFX_ERR_NONE) {
+		g_numEncodersOpen--;
+	}
 
 
+	if ((m_bUseD3D11 || m_bD3D9HACK) && (g_numEncodersOpen <= 0)) {
+		Release();
+		g_DX_Handle = NULL;
+	}
 	m_session.Close();
 	m_session.Close();
-
 	return sts;
 	return sts;
 }
 }
 
 

+ 2 - 0
plugins/obs-qsv11/QSV_Encoder_Internal.h

@@ -109,5 +109,7 @@ private:
 	bool                           m_bIsWindows8OrGreater;
 	bool                           m_bIsWindows8OrGreater;
 	bool                           m_bUseD3D11;
 	bool                           m_bUseD3D11;
 	bool                           m_bD3D9HACK;
 	bool                           m_bD3D9HACK;
+	static mfxU16                  g_numEncodersOpen;
+	static mfxHDL                  g_DX_Handle; // we only want one handle for all instances to use;
 };
 };
 
 

+ 1 - 1
plugins/obs-qsv11/common_utils.h

@@ -95,7 +95,7 @@ typedef struct {
 int GetFreeTaskIndex(Task* pTaskPool, mfxU16 nPoolSize);
 int GetFreeTaskIndex(Task* pTaskPool, mfxU16 nPoolSize);
 
 
 // Initialize Intel Media SDK Session, device/display and memory manager
 // Initialize Intel Media SDK Session, device/display and memory manager
-mfxStatus Initialize(mfxIMPL impl, mfxVersion ver, MFXVideoSession* pSession, mfxFrameAllocator* pmfxAllocator, bool bCreateSharedHandles = false, bool dx9hack = false);
+mfxStatus Initialize(mfxIMPL impl, mfxVersion ver, MFXVideoSession* pSession, mfxFrameAllocator* pmfxAllocator, mfxHDL *deviceHandle = NULL, bool bCreateSharedHandles = false, bool dx9hack = false);
 
 
 // Release resources (device/display)
 // Release resources (device/display)
 void Release();
 void Release();

+ 14 - 9
plugins/obs-qsv11/common_utils_windows.cpp

@@ -23,7 +23,7 @@ Copyright(c) 2005-2014 Intel Corporation. All Rights Reserved.
  * Windows implementation of OS-specific utility functions
  * Windows implementation of OS-specific utility functions
  */
  */
 
 
-mfxStatus Initialize(mfxIMPL impl, mfxVersion ver, MFXVideoSession* pSession, mfxFrameAllocator* pmfxAllocator, bool bCreateSharedHandles, bool dx9hack)
+mfxStatus Initialize(mfxIMPL impl, mfxVersion ver, MFXVideoSession* pSession, mfxFrameAllocator* pmfxAllocator, mfxHDL *deviceHandle, bool bCreateSharedHandles, bool dx9hack)
 {
 {
     bCreateSharedHandles; // (Hugh) Currently unused
     bCreateSharedHandles; // (Hugh) Currently unused
     pmfxAllocator; // (Hugh) Currently unused
     pmfxAllocator; // (Hugh) Currently unused
@@ -37,12 +37,15 @@ mfxStatus Initialize(mfxIMPL impl, mfxVersion ver, MFXVideoSession* pSession, mf
         MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
         MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
 
 
         // Create DirectX device context
         // Create DirectX device context
-        mfxHDL deviceHandle;
-        sts = CreateHWDevice(*pSession, &deviceHandle, NULL, bCreateSharedHandles);
-        MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
+        if (deviceHandle == NULL || *deviceHandle == NULL) {
+            sts = CreateHWDevice(*pSession, deviceHandle, NULL, bCreateSharedHandles);
+            MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
+        }
+
+        if (deviceHandle == NULL || *deviceHandle == NULL) return MFX_ERR_DEVICE_FAILED;
 
 
         // Provide device manager to Media SDK
         // Provide device manager to Media SDK
-        sts = pSession->SetHandle(DEVICE_MGR_TYPE, deviceHandle);
+        sts = pSession->SetHandle(DEVICE_MGR_TYPE, *deviceHandle);
         MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
         MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
 
 
         pmfxAllocator->pthis  = *pSession; // We use Media SDK session ID as the allocation identifier
         pmfxAllocator->pthis  = *pSession; // We use Media SDK session ID as the allocation identifier
@@ -62,12 +65,14 @@ mfxStatus Initialize(mfxIMPL impl, mfxVersion ver, MFXVideoSession* pSession, mf
         MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
         MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
 
 
         // Create DirectX device context
         // Create DirectX device context
-        mfxHDL deviceHandle;
-        sts = DX9_CreateHWDevice(*pSession, &deviceHandle, NULL, bCreateSharedHandles);
-        MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
+        if (deviceHandle == NULL || *deviceHandle == NULL ) {
+            sts = DX9_CreateHWDevice(*pSession, deviceHandle, NULL, false);
+            MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
+        }
+        if (*deviceHandle == NULL) return MFX_ERR_DEVICE_FAILED;
 
 
         // Provide device manager to Media SDK
         // Provide device manager to Media SDK
-        sts = pSession->SetHandle(MFX_HANDLE_D3D9_DEVICE_MANAGER, deviceHandle);
+        sts = pSession->SetHandle(MFX_HANDLE_D3D9_DEVICE_MANAGER, *deviceHandle);
         MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
         MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
 
 
         pmfxAllocator->pthis  = *pSession; // We use Media SDK session ID as the allocation identifier
         pmfxAllocator->pthis  = *pSession; // We use Media SDK session ID as the allocation identifier

+ 6 - 0
plugins/obs-qsv11/obs-qsv11.c

@@ -104,6 +104,7 @@ static int64_t          g_pts2dtsShift;
 static int64_t          g_prevDts;
 static int64_t          g_prevDts;
 static bool             g_bFirst;
 static bool             g_bFirst;
 
 
+
 static const char *obs_qsv_getname(void *type_data)
 static const char *obs_qsv_getname(void *type_data)
 {
 {
 	UNUSED_PARAMETER(type_data);
 	UNUSED_PARAMETER(type_data);
@@ -115,7 +116,10 @@ static void obs_qsv_stop(void *data);
 static void clear_data(struct obs_qsv *obsqsv)
 static void clear_data(struct obs_qsv *obsqsv)
 {
 {
 	if (obsqsv->context) {
 	if (obsqsv->context) {
+		EnterCriticalSection(&g_QsvCs);
 		qsv_encoder_close(obsqsv->context);
 		qsv_encoder_close(obsqsv->context);
+		LeaveCriticalSection(&g_QsvCs);
+
 		// bfree(obsqsv->sei);
 		// bfree(obsqsv->sei);
 		bfree(obsqsv->extra_data);
 		bfree(obsqsv->extra_data);
 
 
@@ -463,7 +467,9 @@ static void *obs_qsv_create(obs_data_t *settings, obs_encoder_t *encoder)
 	obsqsv->encoder = encoder;
 	obsqsv->encoder = encoder;
 
 
 	if (update_settings(obsqsv, settings)) {
 	if (update_settings(obsqsv, settings)) {
+		EnterCriticalSection(&g_QsvCs);
 		obsqsv->context = qsv_encoder_open(&obsqsv->params);
 		obsqsv->context = qsv_encoder_open(&obsqsv->params);
+		LeaveCriticalSection(&g_QsvCs);
 
 
 		if (obsqsv->context == NULL)
 		if (obsqsv->context == NULL)
 			warn("qsv failed to load");
 			warn("qsv failed to load");