天天看點

Intel Media SDK(四)

//

//               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.

//

#define ENABLE_OUTPUT  // Disabling this flag removes all YUV file writing

#define ENABLE_BENCHMARK

#include "common_utils.h"

#ifndef DX11_D3D

#include "common_directx.h"

#define DEVICE_MGR_TYPE MFX_HANDLE_DIRECT3D_DEVICE_MANAGER9

#else

#include "common_directx11.h"

#define DEVICE_MGR_TYPE MFX_HANDLE_D3D11_DEVICE

#endif

// Get free raw frame surface

int GetFreeSurfaceIndex(mfxFrameSurface1** pSurfacesPool, mfxU16 nPoolSize)

{   

    if (pSurfacesPool)

        for (mfxU16 i = 0; i < nPoolSize; i++)

            if (0 == pSurfacesPool[i]->Data.Locked)

                return i;

    return MFX_ERR_NOT_FOUND;

}

int main()

{

    mfxStatus sts = MFX_ERR_NONE;

    // =====================================================================

    // Intel Media SDK decode pipeline setup

    // - In this example we are decoding an AVC (H.264) stream

    // - Video memory surfaces are used to store the decoded frames

    //

    // Open input H.264 elementary stream (ES) file

    FILE* fSource;

    fopen_s(&fSource, "bbb1920x1080.264", "rb");

    MSDK_CHECK_POINTER(fSource, MFX_ERR_NULL_PTR);

    // Create output YUV file

    FILE* fSink;

    fopen_s(&fSink, "dectest_d3d.yuv", "wb");

    MSDK_CHECK_POINTER(fSink, MFX_ERR_NULL_PTR);

    // Initialize Media SDK session

    // - MFX_IMPL_AUTO_ANY selects HW accelaration if available (on any adapter)

    // - Version 1.0 is selected for greatest backwards compatibility.

    //   If more recent API features are needed, change the version accordingly

    mfxIMPL impl = MFX_IMPL_AUTO_ANY;

#ifdef DX11_D3D

    impl |= MFX_IMPL_VIA_D3D11;

#endif

    mfxVersion ver = {0, 1};

    MFXVideoSession mfxSession;

    sts = mfxSession.Init(impl, &ver);

    MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);

    // Create Media SDK decoder

    MFXVideoDECODE mfxDEC(mfxSession);

    // Create DirectX device context

    mfxHDL deviceHandle;

    sts = CreateHWDevice(mfxSession, &deviceHandle, NULL);

    MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);  

    // Provide device manager to Media SDK

    sts = mfxSession.SetHandle(DEVICE_MGR_TYPE, deviceHandle);

    MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);  

    mfxFrameAllocator mfxAllocator;

    mfxAllocator.Alloc = simple_alloc;

    mfxAllocator.Free = simple_free;

    mfxAllocator.Lock = simple_lock;

    mfxAllocator.Unlock = simple_unlock;

    mfxAllocator.GetHDL = simple_gethdl;

    // Since we are using video memory we must provide Media SDK with an external allocator

    sts = mfxSession.SetFrameAllocator(&mfxAllocator);

    MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);

    // Set required video parameters for decode

    mfxVideoParam mfxVideoParams;

    memset(&mfxVideoParams, 0, sizeof(mfxVideoParams));

    mfxVideoParams.mfx.CodecId = MFX_CODEC_AVC;

    mfxVideoParams.IOPattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY;

    // Prepare Media SDK bit stream buffer

    // - Arbitrary buffer size for this example

    mfxBitstream mfxBS;

    memset(&mfxBS, 0, sizeof(mfxBS));

    mfxBS.MaxLength = 1024 * 1024;

    mfxBS.Data = new mfxU8[mfxBS.MaxLength];

    MSDK_CHECK_POINTER(mfxBS.Data, MFX_ERR_MEMORY_ALLOC);

    // Read a chunk of data from stream file into bit stream buffer

    // - Parse bit stream, searching for header and fill video parameters structure

    // - Abort if bit stream header is not found in the first bit stream buffer chunk

    sts = ReadBitStreamData(&mfxBS, fSource);

    MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);

    sts = mfxDEC.DecodeHeader(&mfxBS, &mfxVideoParams);

    MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION);

    MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);

    // Validate video decode parameters (optional)

    // sts = mfxDEC.Query(&mfxVideoParams, &mfxVideoParams); 

    // Query number of required surfaces for decoder

    mfxFrameAllocRequest Request;

    memset(&Request, 0, sizeof(Request));

    sts = mfxDEC.QueryIOSurf(&mfxVideoParams, &Request);

    MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION);

    MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);

#ifdef DX11_D3D

    Request.Type |= WILL_READ; // Hint to DX11 memory handler that application will read data from output surfaces

#endif 

    // Allocate required surfaces

    mfxFrameAllocResponse mfxResponse;

    sts = mfxAllocator.Alloc(mfxAllocator.pthis, &Request, &mfxResponse);

    MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);

    mfxU16 numSurfaces = mfxResponse.NumFrameActual;

    // Allocate surface headers (mfxFrameSurface1) for decoder

    mfxFrameSurface1** pmfxSurfaces = new mfxFrameSurface1*[numSurfaces];

    MSDK_CHECK_POINTER(pmfxSurfaces, MFX_ERR_MEMORY_ALLOC);      

    for (int i = 0; i < numSurfaces; i++)

    {      

        pmfxSurfaces[i] = new mfxFrameSurface1;

        memset(pmfxSurfaces[i], 0, sizeof(mfxFrameSurface1));

        memcpy(&(pmfxSurfaces[i]->Info), &(mfxVideoParams.mfx.FrameInfo), sizeof(mfxFrameInfo));

        pmfxSurfaces[i]->Data.MemId = mfxResponse.mids[i]; // MID (memory id) represent one D3D NV12 surface 

    } 

    // Initialize the Media SDK decoder

    sts = mfxDEC.Init(&mfxVideoParams);

    MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION);

    MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);

    // ===============================================================

    // Start decoding the frames from the stream

    //

#ifdef ENABLE_BENCHMARK

    LARGE_INTEGER tStart, tEnd;

    QueryPerformanceFrequency(&tStart);

    double freq = (double)tStart.QuadPart;

    QueryPerformanceCounter(&tStart);

#endif

    mfxSyncPoint syncp;

    mfxFrameSurface1* pmfxOutSurface = NULL;

    int nIndex = 0; 

    mfxU32 nFrame = 0;

    //

    // Stage 1: Main decoding loop

    //

    while (MFX_ERR_NONE <= sts || MFX_ERR_MORE_DATA == sts || MFX_ERR_MORE_SURFACE == sts)         

    {

        if (MFX_WRN_DEVICE_BUSY == sts)

            Sleep(1); // Wait if device is busy, then repeat the same call to DecodeFrameAsync

        if (MFX_ERR_MORE_DATA == sts)

        {

            sts = ReadBitStreamData(&mfxBS, fSource); // Read more data into input bit stream

            MSDK_BREAK_ON_ERROR(sts);           

        }

        if (MFX_ERR_MORE_SURFACE == sts || MFX_ERR_NONE == sts)

        {

            nIndex = GetFreeSurfaceIndex(pmfxSurfaces, numSurfaces); // Find free frame surface

            if (MFX_ERR_NOT_FOUND == nIndex)

                return MFX_ERR_MEMORY_ALLOC;

        }

        // Decode a frame asychronously (returns immediately)

        //  - If input bitstream contains multiple frames DecodeFrameAsync will start decoding multiple frames, and remove them from bitstream

        sts = mfxDEC.DecodeFrameAsync(&mfxBS, pmfxSurfaces[nIndex], &pmfxOutSurface, &syncp);

        // Ignore warnings if output is available,

        // if no output and no action required just repeat the DecodeFrameAsync call

        if (MFX_ERR_NONE < sts && syncp)

            sts = MFX_ERR_NONE;

        if (MFX_ERR_NONE == sts)

            sts = mfxSession.SyncOperation(syncp, 60000); // Synchronize. Wait until decoded frame is ready

        if (MFX_ERR_NONE == sts)

        {

            ++nFrame;

#ifdef ENABLE_OUTPUT

            // Surface locking required when read/write D3D surfaces

            sts = mfxAllocator.Lock(mfxAllocator.pthis, pmfxOutSurface->Data.MemId, &(pmfxOutSurface->Data));

            MSDK_BREAK_ON_ERROR(sts);

            sts = WriteRawFrame(pmfxOutSurface, fSink);

            MSDK_BREAK_ON_ERROR(sts);

            sts = mfxAllocator.Unlock(mfxAllocator.pthis, pmfxOutSurface->Data.MemId, &(pmfxOutSurface->Data));

            MSDK_BREAK_ON_ERROR(sts);

            printf("Frame number: %d\r", nFrame);

#endif

        }           

    }  

    // MFX_ERR_MORE_DATA means that file has ended, need to go to buffering loop, exit in case of other errors

    MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA);

    MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);         

    //

    // Stage 2: Retrieve the buffered decoded frames

    //

    while (MFX_ERR_NONE <= sts || MFX_ERR_MORE_SURFACE == sts)       

    {       

        if (MFX_WRN_DEVICE_BUSY == sts)

            Sleep(1); // Wait if device is busy, then repeat the same call to DecodeFrameAsync

        nIndex = GetFreeSurfaceIndex(pmfxSurfaces, numSurfaces); // Find free frame surface

        if (MFX_ERR_NOT_FOUND == nIndex)

            return MFX_ERR_MEMORY_ALLOC;           

        // Decode a frame asychronously (returns immediately)

        sts = mfxDEC.DecodeFrameAsync(NULL, pmfxSurfaces[nIndex], &pmfxOutSurface, &syncp);

        // Ignore warnings if output is available,

        // if no output and no action required just repeat the DecodeFrameAsync call       

        if (MFX_ERR_NONE < sts && syncp)

            sts = MFX_ERR_NONE;

        if (MFX_ERR_NONE == sts)

            sts = mfxSession.SyncOperation(syncp, 60000); // Synchronize. Waits until decoded frame is ready

        if (MFX_ERR_NONE == sts)

        {

            ++nFrame;

#ifdef ENABLE_OUTPUT

            // Surface locking required when read/write D3D surfaces

            sts = mfxAllocator.Lock(mfxAllocator.pthis, pmfxOutSurface->Data.MemId, &(pmfxOutSurface->Data));

            MSDK_BREAK_ON_ERROR(sts);

            sts = WriteRawFrame(pmfxOutSurface, fSink);

            MSDK_BREAK_ON_ERROR(sts);

            sts = mfxAllocator.Unlock(mfxAllocator.pthis, pmfxOutSurface->Data.MemId, &(pmfxOutSurface->Data));

            MSDK_BREAK_ON_ERROR(sts);

            printf("Frame number: %d\r", nFrame);

#endif

        }

    }

    // MFX_ERR_MORE_DATA indicates that all buffers has been fetched, exit in case of other errors

    MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA);

    MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);

#ifdef ENABLE_BENCHMARK

    QueryPerformanceCounter(&tEnd);

    double duration = ((double)tEnd.QuadPart - (double)tStart.QuadPart)  / freq;

    printf("\nExecution time: %3.2fs (%3.2ffps)\n", duration, nFrame/duration);

#endif

    // ===================================================================

    // Clean up resources

    //  - It is recommended to close Media SDK components first, before releasing allocated surfaces, since

    //    some surfaces may still be locked by internal Media SDK resources.

    mfxDEC.Close();

    // mfxSession closed automatically on destruction

    for (int i = 0; i < numSurfaces; i++)

        delete pmfxSurfaces[i];

    MSDK_SAFE_DELETE_ARRAY(pmfxSurfaces);

    MSDK_SAFE_DELETE_ARRAY(mfxBS.Data);

    fclose(fSource);

    fclose(fSink);

    CleanupHWDevice();

    return 0;

}