Media SDK with IDirect3DSurface9 + h.264 encoder

Media SDK with IDirect3DSurface9 + h.264 encoder

Hi,

  I want to do the screen capture(1920*1080) via DirectX function GetFrontBufferData, and use IDirect3DSurface9 with input for h.264 encoder,

but the encoder is without any output video file, here is the my code(modification by smaple code) and the log data by mediasdk_tracer.

Could you help to check which items I need to modify, thanks.

//Run Encoder

while (MFX_ERR_NONE <= sts || MFX_ERR_MORE_DATA == sts )
{
       sts = GetFreeTask(&pCurrentTask);
       MSDK_BREAK_ON_ERROR(sts);
       nEncSurfIdx = GetFreeSurface(m_pEncSurfaces, m_EncResponse.NumFrameActual);
       MSDK_CHECK_ERROR(nEncSurfIdx, MSDK_INVALID_SURF_IDX, MFX_ERR_MEMORY_ALLOC);
       pSurf = &m_pEncSurfaces[nEncSurfIdx];
       if (m_bExternalAlloc)
      {
          
           sts = m_pMFXAllocator->Lock(m_pMFXAllocator->pthis, pSurf->Data.MemId, &(pSurf->Data));
       }
        MSDK_BREAK_ON_ERROR(sts);
       pSurf->Info.FrameId.ViewId = currViewNum;

       g_pd3dDevice->GetFrontBufferData(0,pSurf->Data.MemId);
      
       if (m_bExternalAlloc)
       {
            sts = m_pMFXAllocator->Unlock(m_pMFXAllocator->pthis, pSurf->Data.MemId, &(pSurf->Data));
       }
       MSDK_BREAK_ON_ERROR(sts);
      for (;;)
      {
            sts = m_pmfxENC->EncodeFrameAsync(NULL, &m_pEncSurfaces[nEncSurfIdx], &pCurrentTask->mfxBS, &pCurrentTask->EncSyncP);
            if (MFX_ERR_NONE < sts && !pCurrentTask->EncSyncP)
            {
                 if (MFX_WRN_DEVICE_BUSY == sts)
                 MSDK_SLEEP(1);

            }

           else if (MFX_ERR_NONE < sts && pCurrentTask->EncSyncP)
          {
                sts = MFX_ERR_NONE; // ignore warnings if output is available
                break;
          }
          else if (MFX_ERR_NOT_ENOUGH_BUFFER == sts)
          {
               sts = AllocateSufficientBuffer(&pCurrentTask->mfxBS);
               MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
          }
         else
        {
              MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_BITSTREAM);
              break;
         }
    }
}

AnexoTamanho
Download hw-encode-0115-1.txt4.05 MB
14 posts / novo 0
Último post
Para obter mais informações sobre otimizações de compiladores, consulte Aviso sobre otimizações.

Hi Lu,

GetFrontBufferData captures the front buffer in native format which is: D3DFMT_A8R8G8B8
http://msdn.microsoft.com/en-us/library/windows/desktop/bb174388(v=vs.85).aspx

But Media SDK EncodeFrameAsync can only process surface types of type NV12.So from the code it appears that you are trying to have the GetFrontBufferData call do an implicit color conversion from RGB32 type surface to an NV12. This is very likely not supported. If you check the return value from GetFrontBufferData you will probably see that it returns an error.

So, to achieve what you want you will have to do color conversion before feeding to EncodeFrameAsync. RGB32 to NV12 converison can be done using Media SDK VPP component or via other custom color converison routines you may have.

Media SDK  sample_encode showcases how to use VPP ahead of encode,

Regards,
Petter

Hi Petter,

Thansk for your help.

So we may use VPP to do the surface color conversion(from RGB32 to NV12) , and use it as the input of EncodeFrameAsync,right?

As below:

IDirect3DSurface9* g_pSurface;

Surface_Lock();

g_pd3dDevice->GetFrontBufferData(0, g_pSurface); //RGB32 format

Vpp_color_convert(g_pSurface, NV12_Surface); //Vpp color convert function

EncodeFrameAsync(NV12_Surface); //Encode

Surface_UnLock();

But I have checked the sample_VPP, it seems not have the surface color conversion, could you give some suggstion or hint for the surface color conversion, thanks.

Hi Lu,

Correct, for RGB32 to NV12 color space conversion you can use VPP.

sample_vpp does showcase RGB32 to NV12 color converson.

Also sample_encode sample has functionality for VPP processing before encode. But the sample code only illustrates how to use it for resize. But it could easily be extended to support RGB32.

Regards,
Petter

Hi Petter,

Thanks.

I see the partial code for the read RGB4 file to memory, as below:

 Due to I don't see any others ,does it do the conversion from file(RGB4) to video memory(NV12)? 

if (pInfo->FourCC == MFX_FOURCC_RGB4) 
{
    ptr = MSDK_MIN( MSDK_MIN(pData->R, pData->G), pData->B );

    ptr = ptr + pInfo->CropX + pInfo->CropY * pitch;

  for(i = 0; i < h; i++)
  {
     nBytesRead = (mfxU32)fread(ptr + i * pitch, 1, 4*w, m_fSrc);  //File reader
   }

}

Hi Lu,

RGB4 to NV12 color space conversion happen inside Media SDK VPP component.

The code section you refer to is just the file reader that reads a RGB4 surface from file into D3D or system memory buffer. The next step performed by the sample code is to feed the RGB4 surface to VPP for processing into NV12 surface.

By the way. Some things to keep in mind when using "GetFrontBufferData" in this context:
- Not only does GetFrontBufferData require output surface to be of type D3DFMT_A8R8G8B8. The surface must also be stored in system memory (D3DPOOL_SYSTEMMEM)
- This forces you to store the surface retrieved from "GetFrontBufferData" in a intermediate surface. Such surface can be created using "CreateOffscreenPlainSurface".
- You can then copy the intermediate surface into the Media SDK RGB4 surface using "UpdateSurface".

Regards,
Petter

Hi Petter,

Thanks a lot, know how to do the color coversion.

And I have used "CreateOffscreenPlainSurface" to store the surface retrieved from "GetFrontBufferData".

But when I use the "UpdateSurface" for GetFrontBufferData-> VPP RGB4 surface, it will not succeed:

//************************************************************************************

Lock(VPP_surface);

GetFrontBufferData(0, Getfrontdata_surface); 

UpdateSurface(Getfrontdata_surface, NULL, (IDirect3DSurface9*)VPP_surface->Data.MemId, NULL);   // not succeed 

Unlock(VPP_surface);

RunFrameVPPAsync(&VPP_surface, &Encode_surface,NULL, &VppSyncPoint);  // Do VPP color conversion

EncodeFrameAsync(NULL, &Encode_surface, &pCurrentTask->mfxBS, &pCurrentTask->EncSyncP);  // Encode

//************************************************************************************

After check the Microsoft MSDN for UpdateSurface ,  this function has the some restriction, ex:

-The destination surface must have been created with D3DPOOL_DEFAULT => It seems the VPP_surface not created with  D3DPOOL_DEFAULT, does any other need to be modified, thanks.

Hi Lu,

"UpdateSurface" will likely fail since the surface is locked by the "Lock" call. For DirectX calls such as this you do not need to call the Media SDK locking operation.

Media SDK D3D surfaces are created using D3DPOOL_DEFAULT.

Also, I suggest you use DirectX control panel to enable DirectX debugging information. By enabling DirectX debug and singlestepping though your code you can get much more details on what and why specific DirectX calls fail.

Regards,
Petter 

Hi Petter and Lu.
I'm implementing IDirect3DSurface9 + h.264 program following your history.
I passed UpdateSurface() step successfully, but next step RunFrameVPPAsync() failed. This function returns MFX_ERR_INCOMPATIBLE_VIDEO_PARAM.
What is this error?

My pseudo code is below.
//************************************************************************************
CreateSurface Getfrontdata_surface (RGB4 format);
CreateSurface VPP_surface (RGB4 format);
CreateSurface Encode_surface (NV12 format);
GetFrontBufferData(0, Getfrontdata_surface); 
UpdateSurface(Getfrontdata_surface, NULL, (IDirect3DSurface9*)VPP_surface->Data.MemId, NULL);   // success!
RunFrameVPPAsync(&VPP_surface, &Encode_surface, NULL, &VppSyncPoint);  // Convert RGB4->NV12 by VPP, but failed!
EncodeFrameAsync(NULL, &Encode_surface, &pCurrentTask->mfxBS, &pCurrentTask->EncSyncP);  // Encode
//************************************************************************************

Thank you for your reply.

Hello there -

"I passed UpdateSurface() step successfully, but next step RunFrameVPPAsync() failed. This function returns MFX_ERR_INCOMPATIBLE_VIDEO_PARAM." --> Can you please give us more details on how you are setting (and the values of )mfx and vpp params? If you could follow this post for rephrasing your question, it would be really helpful for us to understand your question much better.

Hi Sravanthi.
I pasted Media SDK Analyzer's result below.

=====================================================
Intel Media SDK System Analyzer (64 bit)

The following versions of Media SDK API are supported by platform/driver:

        Version Target  Supported       Dec     Enc
        1.0     HW      Yes             X       X
        1.0     SW      Yes             X       X
        1.1     HW      Yes             X       X
        1.1     SW      Yes             X       X
        1.3     HW      Yes             X       X
        1.3     SW      Yes             X       X
        1.4     HW      Yes             X       X
        1.4     SW      Yes             X       X
        1.5     HW      Yes             X       X
        1.5     SW      Yes             X       X
        1.6     HW      Yes             X       X
        1.6     SW      Yes             X       X
        1.7     HW      Yes             X       X
        1.7     SW      Yes             X       X
        1.8     HW      Yes             X       X
        1.8     SW      Yes             X       X

Graphics Devices:
        Name                                         Version             State
        Intel(R) HD Graphics 4600                    10.18.10.3907       Active

System info:
        CPU:    Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
        OS:     Microsoft Windows 7 Professional K
        Arch:   64-bit

Installed Media SDK packages (be patient...processing takes some time):
        Intel?Media SDK Video Processing Sample 5.0.461.91752
        Intel?Media SDK Video Encoding Sample 5.0.461.91752
        Intel?Media SDK 2014 R2 for Clients (x64)

Installed Media SDK DirectShow filters:

Installed Intel Media Foundation Transforms:
  Intel?Hardware VC-1 Decoder MFT : {059A5BAE-5D7A-4C5E-8F7A-BFD57D1D6AAA}
  Intel?Hardware H.264 Decoder MFT : {45E5CE07-5AC7-4509-94E9-62DB27CF8F96}
  Intel?Hardware MPEG-2 Decoder MFT : {CD5BA7FF-9071-40E9-A462-8DC5152B1776}
  Intel?Quick Sync Video H.264 Encoder MFT : {4BE8D3C0-0515-4A37-AD55-E4BAE19AF471}
  Intel?Hardware Preprocessing MFT : {EE69B504-1CBF-4EA6-8137-BB10F806B014}
=====================================================

UpdateSurface() has the restriction that the source format must match the dest format.
So I changed VppParam's FourCC value from NV12 to RGB4 on InitMfxVppParams() of sample_encode sources.
I didn't touch the rest of VppParams setting except of FourCC value.

diff --git a/sample_encode/src/pipeline_encode.cpp b/sample_encode/src/pipeline_encode.cpp
index a6e0860..90d544a 100644
--- a/sample_encode/src/pipeline_encode.cpp
+++ b/sample_encode/src/pipeline_encode.cpp
@@ -426,7 +426,8 @@ mfxStatus CEncodingPipeline::InitMfxVppParams(sInputParams *pInParams)
     }

     // input frame info
-    m_mfxVppParams.vpp.In.FourCC    = MFX_FOURCC_NV12;
+    m_mfxVppParams.vpp.In.FourCC = MFX_FOURCC_RGB4;
     m_mfxVppParams.vpp.In.PicStruct = pInParams->nPicStruct;;
     ConvertFrameRate(pInParams->dFrameRate, &m_mfxVppParams.vpp.In.FrameRateExtN, &m_mfxVppParams.vpp.In.FrameRateExtD);

I printed the D3DSURFACE_DESC of each surface before RunFrameVPPAsync() for debug.

diff --git a/sample_encode/src/pipeline_encode.cpp b/sample_encode/src/pipeline_encode.cpp
index a6e0860..23149e7 100644
--- a/sample_encode/src/pipeline_encode.cpp
+++ b/sample_encode/src/pipeline_encode.cpp
@@ -1255,6 +1256,12 @@ mfxStatus CEncodingPipeline::Run()
             bVppMultipleOutput = false; // reset the flag before a call to VPP
             for (;;)
             {
+                D3DSURFACE_DESC pVppSurfaceDesc;
+                D3DSURFACE_DESC pEncSurfaceDesc;
+
+                ((IDirect3DSurface9*)(&m_pVppSurfaces[nVppSurfIdx])->Data.MemId)->GetDesc(&pVppSurfaceDesc);
+                ((IDirect3DSurface9*)(&m_pEncSurfaces[nEncSurfIdx])->Data.MemId)->GetDesc(&pEncSurfaceDesc);
+
                 sts = m_pmfxVPP->RunFrameVPPAsync(&m_pVppSurfaces[nVppSurfIdx], &m_pEncSurfaces[nEncSurfIdx],
                     NULL, &VppSyncPoint);

How can I convert colorspace from RGB4 to NV12 using RunFrameVPPAsync() ?

I found a solution from this link!
http://www.briancbecker.com/blog/2011/intel-quick-sync-hardware-encoding/

diff --git a/sample_encode/src/pipeline_encode.cpp b/sample_encode/src/pipeline_encode.cpp
index 352b27c..840da73 100644
--- a/sample_encode/src/pipeline_encode.cpp
+++ b/sample_encode/src/pipeline_encode.cpp
@@ -426,7 +426,7 @@ mfxStatus CEncodingPipeline::InitMfxVppParams(sInputParams *pInParams)
     }

     // input frame info
-    m_mfxVppParams.vpp.In.FourCC    = MFX_FOURCC_NV12;
+    m_mfxVppParams.vpp.In.FourCC = MFX_FOURCC_RGB4;
     m_mfxVppParams.vpp.In.PicStruct = pInParams->nPicStruct;;
     ConvertFrameRate(pInParams->dFrameRate, &m_mfxVppParams.vpp.In.FrameRateExtN, &m_mfxVppParams.vpp.In.FrameRateExtD);

@@ -444,6 +444,8 @@ mfxStatus CEncodingPipeline::InitMfxVppParams(sInputParams *pInParams)
     // fill output frame info
     MSDK_MEMCPY_VAR(m_mfxVppParams.vpp.Out,&m_mfxVppParams.vpp.In, sizeof(mfxFrameInfo));

+    m_mfxVppParams.vpp.Out.FourCC = MFX_FOURCC_NV12;
+
     // only resizing is supported
     m_mfxVppParams.vpp.Out.Width = MSDK_ALIGN16(pInParams->nDstWidth);
     m_mfxVppParams.vpp.Out.Height = (MFX_PICSTRUCT_PROGRESSIVE == m_mfxVppParams.vpp.Out.PicStruct)?

Then I won the success to convert colorspace from RGB4 to NV12 using RunFrameVPPAsync().
Thank you! :)

That sounds great - glad your issue is fixed! 

-Harsh

Hello there - Glad you found the workaround. Looking at your solution, it seems like all you were missing was explicitly setting the vpp.Out.FourCC to NV12. The current samples simply memcopy the input VPP params to out VPP params (and in mfx) - which does not work when input is non NV12, and causes issue (like yours) and we saw another case as well.

Thanks for reporting this behavior - the sample should reflect this change, and we hope to fix this. Thanks.

Deixar um comentário

Faça login para adicionar um comentário. Não é membro? Inscreva-se hoje mesmo!