Commit eaf11d86 authored by Clement Guedez's avatar Clement Guedez

Remove file from Intel Media SDK

Remove memory allocator file from Intel Media SDK as we download it.
parent 093599cc
/* ****************************************************************************** *\
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-2013 Intel Corporation. All Rights Reserved.
\* ****************************************************************************** */
#pragma once
#if defined(WIN32) || defined(WIN64)
#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 // #if defined(WIN32) && !defined(MFX_D3D11_SUPPORT)
#endif // #if defined(WIN32) || defined(WIN64)
#include <list>
#include <string.h>
#include <functional>
#include "mfx/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() : m_cropw(0), m_croph(0), m_refCount(0), m_type(0) {
memset(static_cast<mfxFrameAllocResponse *>(this), 0, sizeof(mfxFrameAllocResponse));
}
// 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_cropw(cropw), m_croph(croph), m_refCount(1), m_type(type) {}
// 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
private:
safe_array(const safe_array &);
safe_array &operator=(const safe_array &);
};
};
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);
};
/*****************************************************************************
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) 2014 Intel Corporation. All Rights Reserved.
*****************************************************************************/
#ifndef __MFX_BUFFERING_H__
#define __MFX_BUFFERING_H__
#include <stdio.h>
#include "mfx/mfxstructures.h"
#include <atomic>
#include <mutex>
#include <iostream>
struct msdkFrameSurface {
mfxFrameSurface1 frame; // NOTE: this _should_ be the first item (see CBuffering::FindUsedSurface())
std::atomic_int_fast16_t render_lock;
msdkFrameSurface* prev;
msdkFrameSurface* next;
};
struct msdkOutputSurface {
msdkFrameSurface* surface;
mfxSyncPoint syncp;
msdkOutputSurface* next;
};
/** \brief Debug purpose macro to terminate execution if buggy situation happenned.
*
* Use this macro to check impossible, buggy condition which should not occur under
* normal circumstances. Macro should be used where check in release mode is not
* desirable and atually needed.
*/
#if 0 //_DEBUG
#define MSDK_SELF_CHECK(C) \
{ \
if (!(C)) { \
msdk_printf(MSDK_STRING("bug: %s:%d: self-check failed: '%s' is not true\n"), __FILE__, __LINE__, #C); \
exit(-1); \
} \
}
#else
#define MSDK_SELF_CHECK(C)
#endif
class CBuffering;
// LIFO list of frame surfaces
class msdkFreeSurfacesPool {
friend class CBuffering;
public:
msdkFreeSurfacesPool(std::mutex* mutex) : m_pSurfaces(NULL), m_pMutex(mutex) {}
~msdkFreeSurfacesPool() { m_pSurfaces = NULL; }
/** \brief The function adds free surface to the free surfaces array.
*
* @note That's caller responsibility to pass valid surface.
* @note We always add and get free surface from the array head. In case not all surfaces
* will be actually used we have good chance to avoid actual allocation of the surface memory.
*/
inline void AddSurface(msdkFrameSurface* surface) {
std::unique_lock<std::mutex> lock(*m_pMutex);
AddSurfaceUnsafe(surface);
}
/** \brief The function gets the next free surface from the free surfaces array.
*
* @note Surface is detached from the free surfaces array.
*/
inline msdkFrameSurface* GetSurface() {
std::unique_lock<std::mutex> lock(*m_pMutex);
return GetSurfaceUnsafe();
}
private:
inline void AddSurfaceUnsafe(msdkFrameSurface* surface) {
msdkFrameSurface* head;
MSDK_SELF_CHECK(surface);
MSDK_SELF_CHECK(!surface->prev);
MSDK_SELF_CHECK(!surface->next);
head = m_pSurfaces;
m_pSurfaces = surface;
m_pSurfaces->next = head;
}
inline msdkFrameSurface* GetSurfaceUnsafe() {
msdkFrameSurface* surface = NULL;
if (m_pSurfaces) {
surface = m_pSurfaces;
m_pSurfaces = m_pSurfaces->next;
surface->prev = surface->next = NULL;
MSDK_SELF_CHECK(!surface->prev);
MSDK_SELF_CHECK(!surface->next);
}
return surface;
}
protected:
msdkFrameSurface* m_pSurfaces;
std::mutex* m_pMutex;
private:
msdkFreeSurfacesPool(const msdkFreeSurfacesPool&);
void operator=(const msdkFreeSurfacesPool&);
};
// random access, predicted as FIFO
class msdkUsedSurfacesPool {
friend class CBuffering;
public:
msdkUsedSurfacesPool(std::mutex* mutex) : m_pSurfacesHead(NULL), m_pSurfacesTail(NULL), m_pMutex(mutex) {}
~msdkUsedSurfacesPool() {
m_pSurfacesHead = NULL;
m_pSurfacesTail = NULL;
}
/** \brief The function adds surface to the used surfaces array (m_pUsedSurfaces).
*
* @note That's caller responsibility to pass valid surface.
* @note We can't actually know which surface will be returned by the decoder or unlocked. However,
* we can make prediction that it will be the oldest surface. Thus, here the function adds new
* surface (youngest) to the tail of the least. Check operations for the list will run starting from
* head.
*/
inline void AddSurface(msdkFrameSurface* surface) {
std::unique_lock<std::mutex> lock(*m_pMutex);
AddSurfaceUnsafe(surface);
}
/** \brief The function detaches surface from the used surfaces array.
*
* @note That's caller responsibility to pass valid surface.
*/
inline void DetachSurface(msdkFrameSurface* surface) {
std::unique_lock<std::mutex> lock(*m_pMutex);
DetachSurfaceUnsafe(surface);
}
private:
inline msdkFrameSurface* DetachSurfaceUnsafe(msdkFrameSurface* surface) {
MSDK_SELF_CHECK(surface);
msdkFrameSurface* prev = surface->prev;
msdkFrameSurface* next = surface->next;
if (prev) {
prev->next = next;
} else {
MSDK_SELF_CHECK(surface == m_pSurfacesHead);
m_pSurfacesHead = next;
}
if (next) {
next->prev = prev;
} else {
MSDK_SELF_CHECK(surface == m_pSurfacesTail);
m_pSurfacesTail = prev;
}
surface->prev = surface->next = NULL;
MSDK_SELF_CHECK(!surface->prev);
MSDK_SELF_CHECK(!surface->next);
return next;
}
inline void AddSurfaceUnsafe(msdkFrameSurface* surface) {
MSDK_SELF_CHECK(surface);
MSDK_SELF_CHECK(!surface->prev);
MSDK_SELF_CHECK(!surface->next);
surface->prev = m_pSurfacesTail;
surface->next = NULL;
if (m_pSurfacesTail) {
m_pSurfacesTail->next = surface;
m_pSurfacesTail = m_pSurfacesTail->next;
} else {
m_pSurfacesHead = m_pSurfacesTail = surface;
}
}
protected:
msdkFrameSurface* m_pSurfacesHead; // oldest surface
msdkFrameSurface* m_pSurfacesTail; // youngest surface
std::mutex* m_pMutex;
private:
msdkUsedSurfacesPool(const msdkUsedSurfacesPool&);
void operator=(const msdkUsedSurfacesPool&);
};
// FIFO list of surfaces
class msdkOutputSurfacesPool {
friend class CBuffering;
public:
msdkOutputSurfacesPool(std::mutex* mutex)
: m_pSurfacesHead(NULL), m_pSurfacesTail(NULL), m_SurfacesCount(0), m_pMutex(mutex) {}
~msdkOutputSurfacesPool() {
m_pSurfacesHead = NULL;
m_pSurfacesTail = NULL;
}
inline void AddSurface(msdkOutputSurface* surface) {
std::unique_lock<std::mutex> lock(*m_pMutex);
AddSurfaceUnsafe(surface);
}
inline msdkOutputSurface* GetSurface() {
std::unique_lock<std::mutex> lock(*m_pMutex);
return GetSurfaceUnsafe();
}
inline mfxU32 GetSurfaceCount() { return m_SurfacesCount; }
private:
inline void AddSurfaceUnsafe(msdkOutputSurface* surface) {
MSDK_SELF_CHECK(surface);
MSDK_SELF_CHECK(!surface->next);
surface->next = NULL;
if (m_pSurfacesTail) {
m_pSurfacesTail->next = surface;
m_pSurfacesTail = m_pSurfacesTail->next;
} else {
m_pSurfacesHead = m_pSurfacesTail = surface;
}
++m_SurfacesCount;
}
inline msdkOutputSurface* GetSurfaceUnsafe() {
msdkOutputSurface* surface = NULL;
if (m_pSurfacesHead) {
surface = m_pSurfacesHead;
m_pSurfacesHead = m_pSurfacesHead->next;
if (!m_pSurfacesHead) {
// there was only one surface in the array...
m_pSurfacesTail = NULL;
}
--m_SurfacesCount;
surface->next = NULL;
MSDK_SELF_CHECK(!surface->next);
}
return surface;
}
protected:
msdkOutputSurface* m_pSurfacesHead; // oldest surface
msdkOutputSurface* m_pSurfacesTail; // youngest surface
mfxU32 m_SurfacesCount;
std::mutex* m_pMutex;
private:
msdkOutputSurfacesPool(const msdkOutputSurfacesPool&);
void operator=(const msdkOutputSurfacesPool&);
};
/** \brief Helper class defining optimal buffering operations for the Media SDK decoder.
*/
class CBuffering {
public:
CBuffering();
virtual ~CBuffering();
protected: // functions
mfxStatus AllocBuffers(mfxU32 SurfaceNumber);
void AllocOutputBuffer();
void FreeBuffers();
void ResetBuffers();
/** \brief The function syncs arrays of free and used surfaces.
*
* If Media SDK used surface for internal needs and unlocked it, the function moves such a surface
* back to the free surfaces array.
*/
void SyncFrameSurfaces();
/** \brief Returns surface which corresponds to the given one in Media SDK format (mfxFrameSurface1).
*
* @note This function will not detach the surface from the array, perform this explicitly.
*/
inline msdkFrameSurface* FindUsedSurface(mfxFrameSurface1* frame) { return (msdkFrameSurface*)(frame); }
inline void AddFreeOutputSurfaceUnsafe(msdkOutputSurface* surface) {
msdkOutputSurface* head = m_pFreeOutputSurfaces;
MSDK_SELF_CHECK(surface);
MSDK_SELF_CHECK(!surface->next);
m_pFreeOutputSurfaces = surface;
m_pFreeOutputSurfaces->next = head;
}
inline void AddFreeOutputSurface(msdkOutputSurface* surface) {
std::unique_lock<std::mutex> lock(m_Mutex);
AddFreeOutputSurfaceUnsafe(surface);
}
inline msdkOutputSurface* GetFreeOutputSurfaceUnsafe() {
msdkOutputSurface* surface = NULL;
if (!m_pFreeOutputSurfaces) {
m_Mutex.unlock();
AllocOutputBuffer();
m_Mutex.lock();
}
if (m_pFreeOutputSurfaces) {
surface = m_pFreeOutputSurfaces;
m_pFreeOutputSurfaces = m_pFreeOutputSurfaces->next;
surface->next = NULL;
MSDK_SELF_CHECK(!surface->next);
}
return surface;
}
inline msdkOutputSurface* GetFreeOutputSurface() {
std::unique_lock<std::mutex> lock(m_Mutex);
return GetFreeOutputSurfaceUnsafe();
}
/** \brief Function returns surface data to the corresponding buffers.
*/
inline void ReturnSurfaceToBuffers(msdkOutputSurface* output_surface) {
MSDK_SELF_CHECK(output_surface);
MSDK_SELF_CHECK(output_surface->surface);
MSDK_SELF_CHECK(output_surface->syncp);
--(output_surface->surface->render_lock);
output_surface->surface = NULL;
output_surface->syncp = NULL;
AddFreeOutputSurface(output_surface);
}
protected: // variables
mfxU32 m_SurfacesNumber;
mfxU32 m_OutputSurfacesNumber;
msdkFrameSurface* m_pSurfaces;
std::mutex m_Mutex;
// LIFO list of frame surfaces
msdkFreeSurfacesPool m_FreeSurfacesPool;
// random access, predicted as FIFO
msdkUsedSurfacesPool m_UsedSurfacesPool;
// LIFO list of output surfaces
msdkOutputSurface* m_pFreeOutputSurfaces;
// FIFO list of surfaces
msdkOutputSurfacesPool m_OutputSurfacesPool;
private:
CBuffering(const CBuffering&);
void operator=(const CBuffering&);
};
#endif // __MFX_BUFFERING_H__
/* ****************************************************************************** *\
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.
\* ****************************************************************************** */
#pragma once
#include "baseAllocator.hpp"
#include <limits>
#ifdef __gnu_linux__
#include <stdint.h> // for uintptr_t on Linux
#endif
// 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 (defined(_WIN32) || defined(_WIN64))
#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 defined(_WIN32) || defined(_WIN64)
/* ****************************************************************************** *\
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.
\* ****************************************************************************** */
#pragma once
#include "hwDevice.hpp"
#if defined(_WIN32) || defined(_WIN64)
#if MFX_D3D11_SUPPORT
#include "hwDevice.hpp"
#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 UpdateTitle(double /*fps*/) {}
virtual void Close();
void DefineFormat(bool isA2rgb10) { m_bIsA2rgb10 = (isA2rgb10) ? TRUE : FALSE; }
protected:
virtual mfxStatus FillSCD(mfxHDL hWindow, DXGI_SWAP_CHAIN_DESC& scd);
virtual mfxStatus FillSCD1(DXGI_SWAP_CHAIN_DESC1& 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;
BOOL m_bIsA2rgb10;
HWND m_HandleWindow;
};
#endif //#if defined( _WIN32 ) || defined ( _WIN64 )
#endif //#if MFX_D3D11_SUPPORT
#pragma once
#if defined(_WIN32) || defined(_WIN64)
#include "baseAllocator.hpp"
#include <atlbase.h>
#include <d3d9.h>
#include <dxva2api.h>
enum eTypeHandle { DXVA2_PROCESSOR = 0x00, DXVA2_DECODER = 0x01 };
struct D3DAllocatorParams : mfxAllocatorParams {
IDirect3DDeviceManager9 *pManager;
DWORD surfaceUsage;
D3DAllocatorParams() : pManager(), surfaceUsage() {}
};
class D3DFrameAllocator : public BaseFrameAllocator {
public:
D3DFrameAllocator();
virtual ~D3DFrameAllocator();
virtual mfxStatus Init(mfxAllocatorParams *pParams);
virtual mfxStatus Close();
virtual IDirect3DDeviceManager9 *GetDeviceManager() { return m_manager; };
virtual mfxStatus LockFrame(mfxMemId mid, mfxFrameData *ptr);
virtual mfxStatus UnlockFrame(mfxMemId mid, mfxFrameData *ptr);
virtual mfxStatus GetFrameHDL(mfxMemId mid, mfxHDL *handle);
protected:
virtual mfxStatus CheckRequestType(mfxFrameAllocRequest *request);
virtual mfxStatus ReleaseResponse(mfxFrameAllocResponse *response);
virtual mfxStatus AllocImpl(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response);
CComPtr<IDirect3DDeviceManager9> m_manager;
CComPtr<IDirectXVideoDecoderService> m_decoderService;
CComPtr<IDirectXVideoProcessorService> m_processorService;
HANDLE m_hDecoder;
HANDLE m_hProcessor;
DWORD m_surfaceUsage;
};
#endif // #if defined( _WIN32 ) || defined ( _WIN64 )
/*********************************************************************************
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-2014 Intel Corporation. All Rights Reserved.
**********************************************************************************/
#pragma once
#if defined(_WIN32) || defined(_WIN64)
#include "hwDevice.hpp"
#pragma warning(disable : 4201)
#include <d3d9.h>
#include <dxva2api.h>
#include <dxva.h>
#include <windows.h>
#define VIDEO_MAIN_FORMAT D3DFMT_YUY2
class IGFXS3DControl;
/** Direct3D 9 device implementation.
@note Can be initilized for only 1 or two 2 views. Handle to
MFX_HANDLE_GFXS3DCONTROL must be set prior if initializing for 2 views.
@note Device always set D3DPRESENT_PARAMETERS::Windowed to TRUE.
*/
class CD3D9Device : public CHWDevice {
public:
CD3D9Device();
virtual ~CD3D9Device();
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 UpdateTitle(double /*fps*/) {}
virtual void Close();
void DefineFormat(bool isA2rgb10) { m_bIsA2rgb10 = (isA2rgb10) ? TRUE : FALSE; }
protected:
mfxStatus CreateVideoProcessors();
bool CheckOverlaySupport();
virtual mfxStatus FillD3DPP(mfxHDL hWindow, mfxU16 nViews, D3DPRESENT_PARAMETERS& D3DPP);
private:
IDirect3D9Ex* m_pD3D9;
IDirect3DDevice9Ex* m_pD3DD9;
IDirect3DDeviceManager9* m_pDeviceManager9;
D3DPRESENT_PARAMETERS m_D3DPP;
UINT m_resetToken;
mfxU16 m_nViews;
IGFXS3DControl* m_pS3DControl;
D3DSURFACE_DESC m_backBufferDesc;
// service required to create video processors
IDirectXVideoProcessorService* m_pDXVAVPS;
// left channel processor
IDirectXVideoProcessor* m_pDXVAVP_Left;
// right channel processor
IDirectXVideoProcessor* m_pDXVAVP_Right;
// target rectangle
RECT m_targetRect;
// various structures for DXVA2 calls
DXVA2_VideoDesc m_VideoDesc;
DXVA2_VideoProcessBltParams m_BltParams;
DXVA2_VideoSample m_Sample;
BOOL m_bIsA2rgb10;
};
#endif // #if defined( _WIN32 ) || defined ( _WIN64 )
/* ****************************************************************************** *\
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) 2013 Intel Corporation. All Rights Reserved.
\* ****************************************************************************** */
#pragma once
#include "mfx/mfxvideo++.h"
#if defined(WIN32) || defined(WIN64)
#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 // #if defined(WIN32) && !defined(MFX_D3D11_SUPPORT)
#endif // #if defined(WIN32) || defined(WIN64)
#define MSDK_ZERO_MEMORY(VAR) \
{ memset(&VAR, 0, sizeof(VAR)); }
#define MSDK_MEMCPY_VAR(dstVarName, src, count) memcpy_s(&(dstVarName), sizeof(dstVarName), (src), (count))
#define MSDK_SAFE_RELEASE(X) \
{ \
if (X) { \
X->Release(); \
X = NULL; \
} \
}
#define MSDK_CHECK_POINTER(P, ...) \
{ \
if (!(P)) { \
return __VA_ARGS__; \
} \
}
#define MSDK_ARRAY_LEN(value) (sizeof(value) / sizeof(value[0]))
enum {
MFX_HANDLE_GFXS3DCONTROL = 0x100, /* A handle to the IGFXS3DControl instance */
MFX_HANDLE_DEVICEWINDOW = 0x101 /* A handle to the render window */
}; // mfxHandleType
/// 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 UpdateTitle(double fps) = 0;
virtual void Close() = 0;
};
/* ****************************************************************************** *\
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-2013 Intel Corporation. All Rights Reserved.
\* ****************************************************************************** */
#pragma once
#include <stdlib.h>
#include "baseAllocator.hpp"
struct sBuffer {
mfxU32 id;
mfxU32 nbytes;
mfxU16 type;
};
struct sFrame {
mfxU32 id;
mfxFrameInfo info;
};
struct SysMemAllocatorParams : mfxAllocatorParams {
SysMemAllocatorParams() : mfxAllocatorParams() {}
MFXBufferAllocator *pBufferAllocator;
};
class SysMemFrameAllocator : public BaseFrameAllocator {
public:
SysMemFrameAllocator();
virtual ~SysMemFrameAllocator();
virtual mfxStatus Init(mfxAllocatorParams *pParams);
virtual mfxStatus Close();
virtual mfxStatus LockFrame(mfxMemId mid, mfxFrameData *ptr);
virtual mfxStatus UnlockFrame(mfxMemId mid, mfxFrameData *ptr);
virtual mfxStatus GetFrameHDL(mfxMemId mid, mfxHDL *handle);
protected:
virtual mfxStatus CheckRequestType(mfxFrameAllocRequest *request);
virtual mfxStatus ReleaseResponse(mfxFrameAllocResponse *response);
virtual mfxStatus AllocImpl(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response);
MFXBufferAllocator *m_pBufferAllocator;
bool m_bOwnBufferAllocator;
};
class SysMemBufferAllocator : public MFXBufferAllocator {
public:
SysMemBufferAllocator();
virtual ~SysMemBufferAllocator();
virtual mfxStatus AllocBuffer(mfxU32 nbytes, mfxU16 type, mfxMemId *mid);
virtual mfxStatus LockBuffer(mfxMemId mid, mfxU8 **ptr);
virtual mfxStatus UnlockBuffer(mfxMemId mid);
virtual mfxStatus FreeBuffer(mfxMemId mid);
};
/* ****************************************************************************** *\
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.
\* ****************************************************************************** */
#pragma once
#include <stdlib.h>
#include "baseAllocator.hpp"
#include "vaapiUtils.hpp"
// VAAPI Allocator internal Mem ID
struct vaapiMemId {
VASurfaceID *m_surface;
VAImage m_image;
// variables for VAAPI Allocator inernal color convertion
unsigned int m_fourcc;
mfxU8 *m_sys_buffer;
mfxU8 *m_va_buffer;
};
struct vaapiAllocatorParams : mfxAllocatorParams {
VADisplay m_dpy;
};
class vaapiFrameAllocator : public BaseFrameAllocator {
public:
vaapiFrameAllocator();
virtual ~vaapiFrameAllocator();
virtual mfxStatus Init(mfxAllocatorParams *pParams);
virtual mfxStatus Close();
protected:
virtual mfxStatus LockFrame(mfxMemId mid, mfxFrameData *ptr);
virtual mfxStatus UnlockFrame(mfxMemId mid, mfxFrameData *ptr);
virtual mfxStatus GetFrameHDL(mfxMemId mid, mfxHDL *handle);
virtual mfxStatus CheckRequestType(mfxFrameAllocRequest *request);
virtual mfxStatus ReleaseResponse(mfxFrameAllocResponse *response);
virtual mfxStatus AllocImpl(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response);
VADisplay m_dpy;
};
/* ****************************************************************************** *\
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) 2013 Intel Corporation. All Rights Reserved.
\* ****************************************************************************** */
#include "hwDevice.hpp"
#include "vaapiUtils.hpp"
#include <va/va_drm.h>
CHWDevice* CreateVAAPIDevice(void);
class CLibVA {
public:
virtual ~CLibVA(void){};
VADisplay GetVADisplay(void) { return m_va_dpy; }
protected:
CLibVA(void) : m_va_dpy(nullptr) {}
VADisplay m_va_dpy;
};
class DRMLibVA : public CLibVA {
public:
DRMLibVA(void);
virtual ~DRMLibVA(void);
protected:
int m_fd;
};
/** VAAPI DRM implementation. */
class CVAAPIDeviceDRM : public CHWDevice {
public:
CVAAPIDeviceDRM() {}
virtual ~CVAAPIDeviceDRM(void) {}
virtual mfxStatus Init(mfxHDL hWindow, mfxU16 nViews, mfxU32 nAdapterNum) { return MFX_ERR_NONE; }
virtual mfxStatus Reset(void) { return MFX_ERR_NONE; }
virtual void Close(void) {}
virtual mfxStatus SetHandle(mfxHandleType type, mfxHDL hdl) { return MFX_ERR_UNSUPPORTED; }
virtual mfxStatus GetHandle(mfxHandleType type, mfxHDL* pHdl) {
if ((MFX_HANDLE_VA_DISPLAY == type) && (nullptr != pHdl)) {
*pHdl = m_DRMLibVA.GetVADisplay();
return MFX_ERR_NONE;
}
return MFX_ERR_UNSUPPORTED;
}
virtual mfxStatus RenderFrame(mfxFrameSurface1* pSurface, mfxFrameAllocator* pmfxAlloc) { return MFX_ERR_NONE; }
virtual void UpdateTitle(double fps) {}
protected:
DRMLibVA m_DRMLibVA;
};
CLibVA* CreateLibVA(void);
/* ****************************************************************************** *\
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) 2013 Intel Corporation. All Rights Reserved.
\* ****************************************************************************** */
#include <va/va.h>
mfxStatus va_to_mfx_status(VAStatus va_res);
/* ****************************************************************************** *\
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 "baseAllocator.hpp"
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->NumFrameSuggested > 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);
}
/*********************************************************************************
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) 2014 Intel Corporation. All Rights Reserved.
**********************************************************************************/
#include <stdlib.h>
#include "buffering.hpp"
CBuffering::CBuffering()
: m_SurfacesNumber(0),
m_OutputSurfacesNumber(0),
m_pSurfaces(NULL),
m_FreeSurfacesPool(&m_Mutex),
m_UsedSurfacesPool(&m_Mutex),
m_pFreeOutputSurfaces(NULL),
m_OutputSurfacesPool(&m_Mutex) {}
CBuffering::~CBuffering() {}
mfxStatus CBuffering::AllocBuffers(mfxU32 SurfaceNumber) {
if (!SurfaceNumber) return MFX_ERR_MEMORY_ALLOC;
if (!m_OutputSurfacesNumber) { // true - if Vpp isn't enabled
m_OutputSurfacesNumber = SurfaceNumber;
}
m_SurfacesNumber = SurfaceNumber;
m_pSurfaces = (msdkFrameSurface*)calloc(m_SurfacesNumber, sizeof(msdkFrameSurface));
if (!m_pSurfaces) return MFX_ERR_MEMORY_ALLOC;
msdkOutputSurface* p = NULL;
msdkOutputSurface* tail = NULL;
m_pFreeOutputSurfaces = (msdkOutputSurface*)calloc(1, sizeof(msdkOutputSurface));
if (!m_pFreeOutputSurfaces) return MFX_ERR_MEMORY_ALLOC;
tail = m_pFreeOutputSurfaces;
for (mfxU32 i = 1; i < m_OutputSurfacesNumber; ++i) {
p = (msdkOutputSurface*)calloc(1, sizeof(msdkOutputSurface));
if (!p) return MFX_ERR_MEMORY_ALLOC;
tail->next = p;
tail = p;
}
ResetBuffers();
return MFX_ERR_NONE;
}
void CBuffering::AllocOutputBuffer() {
std::unique_lock<std::mutex> lock(m_Mutex);
m_pFreeOutputSurfaces = (msdkOutputSurface*)calloc(1, sizeof(msdkOutputSurface));
}
static void FreeList(msdkOutputSurface*& head) {
msdkOutputSurface* next;
while (head) {
next = head->next;
free(head);
head = next;
}
}
void CBuffering::FreeBuffers() {
if (m_pSurfaces) {
free(m_pSurfaces);
m_pSurfaces = NULL;
}
FreeList(m_pFreeOutputSurfaces);
FreeList(m_OutputSurfacesPool.m_pSurfacesHead);
m_UsedSurfacesPool.m_pSurfacesHead = NULL;
m_UsedSurfacesPool.m_pSurfacesTail = NULL;
m_FreeSurfacesPool.m_pSurfaces = NULL;
}
void CBuffering::ResetBuffers() {
mfxU32 i;
msdkFrameSurface* pFreeSurf = m_FreeSurfacesPool.m_pSurfaces = m_pSurfaces;
for (i = 0; i < m_SurfacesNumber; ++i) {
if (i < (m_SurfacesNumber - 1)) {
pFreeSurf[i].next = &(pFreeSurf[i + 1]);
pFreeSurf[i + 1].prev = &(pFreeSurf[i]);
}
}
}
void CBuffering::SyncFrameSurfaces() {
std::unique_lock<std::mutex> lock(m_Mutex);
msdkFrameSurface* next = nullptr;
msdkFrameSurface* cur = m_UsedSurfacesPool.m_pSurfacesHead;
while (cur) {
if (cur->frame.Data.Locked || cur->render_lock.load() != 0) {
// frame is still locked: just moving to the next one
cur = cur->next;
} else {
// frame was unlocked: moving it to the free surfaces array
next = m_UsedSurfacesPool.DetachSurfaceUnsafe(cur);
m_FreeSurfacesPool.AddSurfaceUnsafe(cur);
cur = next;
}
}
}
/*********************************************************************************
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-2015 Intel Corporation. All Rights Reserved.
**********************************************************************************/
#include "d3d11Allocator.hpp"
#if defined(_WIN32) || defined(_WIN64)
#if MFX_D3D11_SUPPORT
#include <objbase.h>
#include <initguid.h>
#include <assert.h>
#include <algorithm>
#include <functional>
#include <iterator>
#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;
if (m_pDeviceContext) {
m_pDeviceContext->Release();
m_pDeviceContext = NULL;
}
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();
if (m_pDeviceContext) {
m_pDeviceContext->Release();
m_pDeviceContext = NULL;
}
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 &&
DXGI_FORMAT_R16_UINT != desc.Format && DXGI_FORMAT_R16_UNORM != desc.Format &&
DXGI_FORMAT_R10G10B10A2_UNORM != desc.Format && DXGI_FORMAT_AYUV != 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);
} 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_AYUV:
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;
case DXGI_FORMAT_R10G10B10A2_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;
case DXGI_FORMAT_R16_UNORM:
case DXGI_FORMAT_R16_UINT:
ptr->Pitch = (mfxU16)lockedRect.RowPitch;
ptr->Y16 = (mfxU16 *)lockedRect.pData;
ptr->U16 = 0;
ptr->V16 = 0;
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 | D3D11_RESOURCE_MISC_SHARED;
desc.BindFlags = D3D11_BIND_DECODER;
if ((MFX_MEMTYPE_FROM_VPPIN & request->Type) && (DXGI_FORMAT_YUY2 == desc.Format) ||
(DXGI_FORMAT_B8G8R8A8_UNORM == desc.Format) || (DXGI_FORMAT_R10G10B10A2_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)) {
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)) {
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;
// case MFX_FOURCC_R16:
// return DXGI_FORMAT_R16_UINT; // UNORM ??? kta
case MFX_FOURCC_P010:
return DXGI_FORMAT_P010;
case MFX_FOURCC_A2RGB10:
return DXGI_FORMAT_R10G10B10A2_UNORM;
case DXGI_FORMAT_AYUV:
return DXGI_FORMAT_AYUV;
default:
return DXGI_FORMAT_UNKNOWN;
}
}
#endif // #if MFX_D3D11_SUPPORT
#endif // #if defined(_WIN32) || defined(_WIN64)
/*********************************************************************************
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-2014 Intel Corporation. All Rights Reserved.
**********************************************************************************/
#include "d3d11Device.hpp"
#if defined(_WIN32) || defined(_WIN64)
#if MFX_D3D11_SUPPORT
CD3D11Device::CD3D11Device() : m_nViews(0), m_bDefaultStereoEnabled(FALSE), m_bIsA2rgb10(FALSE), m_HandleWindow(NULL) {}
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 = (m_bIsA2rgb10) ? DXGI_FORMAT_R10G10B10A2_UNORM : DXGI_FORMAT_B8G8R8A8_UNORM;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.BufferCount = 1;
return MFX_ERR_NONE;
}
mfxStatus CD3D11Device::FillSCD1(DXGI_SWAP_CHAIN_DESC1 &scd1) {
scd1.Width = 0; // Use automatic sizing.
scd1.Height = 0;
scd1.Format = (m_bIsA2rgb10) ? DXGI_FORMAT_R10G10B10A2_UNORM : DXGI_FORMAT_B8G8R8A8_UNORM;
scd1.Stereo = m_nViews == 2 ? TRUE : FALSE;
scd1.SampleDesc.Count = 1; // Don't use multi-sampling.
scd1.SampleDesc.Quality = 0;
scd1.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd1.BufferCount = 2; // Use double buffering to minimize latency.
scd1.Scaling = DXGI_SCALING_STRETCH;
scd1.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
scd1.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
return MFX_ERR_NONE;
}
mfxStatus CD3D11Device::Init(mfxHDL hWindow, mfxU16 nViews, mfxU32 nAdapterNum) {
m_HandleWindow = (HWND)hWindow;
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)
if (hWindow) {
MSDK_CHECK_POINTER(m_pDXGIFactory.p, MFX_ERR_NULL_PTR);
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
sts = FillSCD1(swapChainDesc);
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);
MSDK_CHECK_POINTER(m_pDXGIFactory.p, MFX_ERR_NULL_PTR);
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
FillSCD1(swapChainDesc);
HRESULT hres = S_OK;
hres = m_pDXGIFactory->CreateSwapChainForHwnd(m_pD3D11Device, (HWND)m_HandleWindow, &swapChainDesc, NULL, NULL,
reinterpret_cast<IDXGISwapChain1 **>(&m_pSwapChain));
if (FAILED(hres)) return MFX_ERR_DEVICE_FAILED;
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) {
if (MFX_HANDLE_DEVICEWINDOW == type && hdl != NULL) // for render window handle
{
m_HandleWindow = (HWND)hdl;
return MFX_ERR_NONE;
}
return MFX_ERR_UNSUPPORTED;
}
mfxStatus CD3D11Device::RenderFrame(mfxFrameSurface1 *pSrf, mfxFrameAllocator *pAlloc) {
HRESULT hres = S_OK;
mfxStatus sts;
sts = CreateVideoProcessor(pSrf);
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);
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() {
// Changing video mode back to the original state
if (2 == m_nViews && !m_bDefaultStereoEnabled) m_pDisplayControl->SetStereoEnabled(FALSE);
m_HandleWindow = NULL;
}
#endif // #if MFX_D3D11_SUPPORT
#endif // #if defined(_WIN32) || defined(_WIN64)
/*********************************************************************************
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-2015 Intel Corporation. All Rights Reserved.
**********************************************************************************/
#include "d3dAllocator.hpp"
#define MSDK_SAFE_FREE(X) \
{ \
if (X) { \
free(X); \
X = NULL; \
} \
}
#if defined(_WIN32) || defined(_WIN64)
#include <objbase.h>
#include <initguid.h>
#include <assert.h>
#include <d3d9.h>
#define D3DFMT_NV12 (D3DFORMAT) MAKEFOURCC('N', 'V', '1', '2')
#define D3DFMT_YV12 (D3DFORMAT) MAKEFOURCC('Y', 'V', '1', '2')
#define D3DFMT_P010 (D3DFORMAT) MAKEFOURCC('P', '0', '1', '0')
D3DFORMAT ConvertMfxFourccToD3dFormat(mfxU32 fourcc) {
switch (fourcc) {
case MFX_FOURCC_NV12:
return D3DFMT_NV12;
case MFX_FOURCC_YV12:
return D3DFMT_YV12;
case MFX_FOURCC_YUY2:
return D3DFMT_YUY2;
case MFX_FOURCC_RGB3:
return D3DFMT_R8G8B8;
case MFX_FOURCC_RGB4:
return D3DFMT_A8R8G8B8;
case MFX_FOURCC_P8:
return D3DFMT_P8;
case MFX_FOURCC_P010:
return D3DFMT_P010;
case MFX_FOURCC_A2RGB10:
return D3DFMT_A2R10G10B10;
default:
return D3DFMT_UNKNOWN;
}
}
D3DFrameAllocator::D3DFrameAllocator()
: m_decoderService(0), m_processorService(0), m_hDecoder(0), m_hProcessor(0), m_manager(0), m_surfaceUsage(0) {}
D3DFrameAllocator::~D3DFrameAllocator() { Close(); }
mfxStatus D3DFrameAllocator::Init(mfxAllocatorParams *pParams) {
D3DAllocatorParams *pd3dParams = 0;
pd3dParams = dynamic_cast<D3DAllocatorParams *>(pParams);
if (!pd3dParams) return MFX_ERR_NOT_INITIALIZED;
m_manager = pd3dParams->pManager;
m_surfaceUsage = pd3dParams->surfaceUsage;
return MFX_ERR_NONE;
}
mfxStatus D3DFrameAllocator::Close() {
if (m_manager && m_hDecoder) {
m_manager->CloseDeviceHandle(m_hDecoder);
m_manager = 0;
m_hDecoder = 0;
}
if (m_manager && m_hProcessor) {
m_manager->CloseDeviceHandle(m_hProcessor);
m_manager = 0;
m_hProcessor = 0;
}
return BaseFrameAllocator::Close();
}
mfxStatus D3DFrameAllocator::LockFrame(mfxMemId mid, mfxFrameData *ptr) {
if (!ptr || !mid) return MFX_ERR_NULL_PTR;
mfxHDLPair *dxmid = (mfxHDLPair *)mid;
IDirect3DSurface9 *pSurface = static_cast<IDirect3DSurface9 *>(dxmid->first);
if (pSurface == 0) return MFX_ERR_INVALID_HANDLE;
D3DSURFACE_DESC desc;
HRESULT hr = pSurface->GetDesc(&desc);
if (FAILED(hr)) return MFX_ERR_LOCK_MEMORY;
if (desc.Format != D3DFMT_NV12 && desc.Format != D3DFMT_YV12 && desc.Format != D3DFMT_YUY2 &&
desc.Format != D3DFMT_R8G8B8 && desc.Format != D3DFMT_A8R8G8B8 && desc.Format != D3DFMT_P8 &&
desc.Format != D3DFMT_P010 && desc.Format != D3DFMT_A2R10G10B10)
return MFX_ERR_LOCK_MEMORY;
D3DLOCKED_RECT locked;
hr = pSurface->LockRect(&locked, 0, D3DLOCK_NOSYSLOCK);
if (FAILED(hr)) return MFX_ERR_LOCK_MEMORY;
switch ((DWORD)desc.Format) {
case D3DFMT_NV12:
ptr->Pitch = (mfxU16)locked.Pitch;
ptr->Y = (mfxU8 *)locked.pBits;
ptr->U = (mfxU8 *)locked.pBits + desc.Height * locked.Pitch;
ptr->V = ptr->U + 1;
break;
case D3DFMT_YV12:
ptr->Pitch = (mfxU16)locked.Pitch;
ptr->Y = (mfxU8 *)locked.pBits;
ptr->V = ptr->Y + desc.Height * locked.Pitch;
ptr->U = ptr->V + (desc.Height * locked.Pitch) / 4;
break;
case D3DFMT_YUY2:
ptr->Pitch = (mfxU16)locked.Pitch;
ptr->Y = (mfxU8 *)locked.pBits;
ptr->U = ptr->Y + 1;
ptr->V = ptr->Y + 3;
break;
case D3DFMT_R8G8B8:
ptr->Pitch = (mfxU16)locked.Pitch;
ptr->B = (mfxU8 *)locked.pBits;
ptr->G = ptr->B + 1;
ptr->R = ptr->B + 2;
break;
case D3DFMT_A8R8G8B8:
case D3DFMT_A2R10G10B10:
ptr->Pitch = (mfxU16)locked.Pitch;
ptr->B = (mfxU8 *)locked.pBits;
ptr->G = ptr->B + 1;
ptr->R = ptr->B + 2;
ptr->A = ptr->B + 3;
break;
case D3DFMT_P8:
ptr->Pitch = (mfxU16)locked.Pitch;
ptr->Y = (mfxU8 *)locked.pBits;
ptr->U = 0;
ptr->V = 0;
break;
case D3DFMT_P010:
ptr->PitchHigh = (mfxU16)(locked.Pitch / (1 << 16));
ptr->PitchLow = (mfxU16)(locked.Pitch % (1 << 16));
ptr->Y = (mfxU8 *)locked.pBits;
ptr->U = (mfxU8 *)locked.pBits + desc.Height * locked.Pitch;
ptr->V = ptr->U + 1;
break;
}
return MFX_ERR_NONE;
}
mfxStatus D3DFrameAllocator::UnlockFrame(mfxMemId mid, mfxFrameData *ptr) {
if (!mid) return MFX_ERR_NULL_PTR;
mfxHDLPair *dxmid = (mfxHDLPair *)mid;
IDirect3DSurface9 *pSurface = static_cast<IDirect3DSurface9 *>(dxmid->first);
if (pSurface == 0) return MFX_ERR_INVALID_HANDLE;
pSurface->UnlockRect();
if (NULL != ptr) {
ptr->Pitch = 0;
ptr->Y = 0;
ptr->U = 0;
ptr->V = 0;
}
return MFX_ERR_NONE;
}
mfxStatus D3DFrameAllocator::GetFrameHDL(mfxMemId mid, mfxHDL *handle) {
if (!mid || !handle) return MFX_ERR_NULL_PTR;
mfxHDLPair *dxMid = (mfxHDLPair *)mid;
*handle = dxMid->first;
return MFX_ERR_NONE;
}
mfxStatus D3DFrameAllocator::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 D3DFrameAllocator::ReleaseResponse(mfxFrameAllocResponse *response) {
if (!response) return MFX_ERR_NULL_PTR;
mfxStatus sts = MFX_ERR_NONE;
if (response->mids) {
for (mfxU32 i = 0; i < response->NumFrameActual; i++) {
if (response->mids[i]) {
mfxHDLPair *dxMids = (mfxHDLPair *)response->mids[i];
static_cast<IDirect3DSurface9 *>(dxMids->first)->Release();
}
}
MSDK_SAFE_FREE(response->mids[0]);
}
MSDK_SAFE_FREE(response->mids);
return sts;
}
mfxStatus D3DFrameAllocator::AllocImpl(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response) {
HRESULT hr;
if (request->NumFrameSuggested == 0) return MFX_ERR_UNKNOWN;
D3DFORMAT format = ConvertMfxFourccToD3dFormat(request->Info.FourCC);
if (format == D3DFMT_UNKNOWN) return MFX_ERR_UNSUPPORTED;
DWORD target;
if (MFX_MEMTYPE_DXVA2_DECODER_TARGET & request->Type) {
target = DXVA2_VideoDecoderRenderTarget;
} else if (MFX_MEMTYPE_DXVA2_PROCESSOR_TARGET & request->Type) {
target = DXVA2_VideoProcessorRenderTarget;
} else
return MFX_ERR_UNSUPPORTED;
IDirectXVideoAccelerationService *videoService = NULL;
if (target == DXVA2_VideoProcessorRenderTarget) {
if (!m_hProcessor) {
hr = m_manager->OpenDeviceHandle(&m_hProcessor);
if (FAILED(hr)) return MFX_ERR_MEMORY_ALLOC;
hr = m_manager->GetVideoService(m_hProcessor, IID_IDirectXVideoProcessorService, (void **)&m_processorService);
if (FAILED(hr)) return MFX_ERR_MEMORY_ALLOC;
}
videoService = m_processorService;
} else {
if (!m_hDecoder) {
hr = m_manager->OpenDeviceHandle(&m_hDecoder);
if (FAILED(hr)) return MFX_ERR_MEMORY_ALLOC;
hr = m_manager->GetVideoService(m_hDecoder, IID_IDirectXVideoDecoderService, (void **)&m_decoderService);
if (FAILED(hr)) return MFX_ERR_MEMORY_ALLOC;
}
videoService = m_decoderService;
}
mfxHDLPair *dxMids = (mfxHDLPair *)calloc(request->NumFrameSuggested, sizeof(mfxHDLPair));
mfxHDLPair **dxMidPtrs = (mfxHDLPair **)calloc(request->NumFrameSuggested, sizeof(mfxHDLPair *));
if (!dxMids || !dxMidPtrs) {
MSDK_SAFE_FREE(dxMids);
MSDK_SAFE_FREE(dxMidPtrs);
return MFX_ERR_MEMORY_ALLOC;
}
response->mids = (mfxMemId *)dxMidPtrs;
response->NumFrameActual = request->NumFrameSuggested;
if (request->Type & MFX_MEMTYPE_EXTERNAL_FRAME) {
for (int i = 0; i < request->NumFrameSuggested; i++) {
hr = videoService->CreateSurface(request->Info.Width, request->Info.Height, 0, format, D3DPOOL_DEFAULT,
m_surfaceUsage, target, (IDirect3DSurface9 **)&dxMids[i].first,
&dxMids[i].second);
if (FAILED(hr)) {
ReleaseResponse(response);
MSDK_SAFE_FREE(dxMids);
return MFX_ERR_MEMORY_ALLOC;
}
dxMidPtrs[i] = &dxMids[i];
}
} else {
safe_array<IDirect3DSurface9 *> dxSrf(new IDirect3DSurface9 *[request->NumFrameSuggested]);
if (!dxSrf.get()) {
MSDK_SAFE_FREE(dxMids);
return MFX_ERR_MEMORY_ALLOC;
}
hr = videoService->CreateSurface(request->Info.Width, request->Info.Height, request->NumFrameSuggested - 1, format,
D3DPOOL_DEFAULT, m_surfaceUsage, target, dxSrf.get(), NULL);
if (FAILED(hr)) {
MSDK_SAFE_FREE(dxMids);
return MFX_ERR_MEMORY_ALLOC;
}
for (int i = 0; i < request->NumFrameSuggested; i++) {
dxMids[i].first = dxSrf.get()[i];
dxMidPtrs[i] = &dxMids[i];
}
}
return MFX_ERR_NONE;
}
#endif // #if defined(_WIN32) || defined(_WIN64)
/*********************************************************************************
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-2015 Intel Corporation. All Rights Reserved.
**********************************************************************************/
#include "libvideostitch/config.hpp"
#if defined(WIN32) || defined(WIN64)
// prefast singnature used in combaseapi.h
#ifndef _PREFAST_
#pragma warning(disable : 4068)
#endif
#include <Windows.h>
#include <initguid.h>
#include "d3dDevice.hpp"
#include "d3dAllocator.hpp"
#include "mfx/igfx_s3dcontrol.h"
#include "atlbase.h"
#include <algorithm>
CD3D9Device::CD3D9Device() {
m_pD3D9 = NULL;
m_pD3DD9 = NULL;
m_pDeviceManager9 = NULL;
MSDK_ZERO_MEMORY(m_D3DPP);
m_resetToken = 0;
m_nViews = 0;
m_pS3DControl = NULL;
MSDK_ZERO_MEMORY(m_backBufferDesc);
m_pDXVAVPS = NULL;
m_pDXVAVP_Left = NULL;
m_pDXVAVP_Right = NULL;
MSDK_ZERO_MEMORY(m_targetRect);
MSDK_ZERO_MEMORY(m_VideoDesc);
MSDK_ZERO_MEMORY(m_BltParams);
MSDK_ZERO_MEMORY(m_Sample);
// Initialize DXVA structures
DXVA2_AYUVSample16 color = {
0x8000, // Cr
0x8000, // Cb
0x1000, // Y
0xffff // Alpha
};
DXVA2_ExtendedFormat format = {
// DestFormat
DXVA2_SampleProgressiveFrame, // SampleFormat
DXVA2_VideoChromaSubsampling_MPEG2, // VideoChromaSubsampling
DXVA_NominalRange_0_255, // NominalRange
DXVA2_VideoTransferMatrix_BT709, // VideoTransferMatrix
DXVA2_VideoLighting_bright, // VideoLighting
DXVA2_VideoPrimaries_BT709, // VideoPrimaries
DXVA2_VideoTransFunc_709 // VideoTransferFunction
};
// init m_VideoDesc structure
MSDK_MEMCPY_VAR(m_VideoDesc.SampleFormat, &format, sizeof(DXVA2_ExtendedFormat));
m_VideoDesc.SampleWidth = 0;
m_VideoDesc.SampleHeight = 0;
m_VideoDesc.InputSampleFreq.Numerator = 60;
m_VideoDesc.InputSampleFreq.Denominator = 1;
m_VideoDesc.OutputFrameFreq.Numerator = 60;
m_VideoDesc.OutputFrameFreq.Denominator = 1;
// init m_BltParams structure
MSDK_MEMCPY_VAR(m_BltParams.DestFormat, &format, sizeof(DXVA2_ExtendedFormat));
MSDK_MEMCPY_VAR(m_BltParams.BackgroundColor, &color, sizeof(DXVA2_AYUVSample16));
// init m_Sample structure
m_Sample.Start = 0;
m_Sample.End = 1;
m_Sample.SampleFormat = format;
m_Sample.PlanarAlpha.Fraction = 0;
m_Sample.PlanarAlpha.Value = 1;
m_bIsA2rgb10 = FALSE;
}
bool CD3D9Device::CheckOverlaySupport() {
D3DCAPS9 d3d9caps;
D3DOVERLAYCAPS d3doverlaycaps = {0};
IDirect3D9ExOverlayExtension *d3d9overlay = NULL;
bool overlaySupported = false;
memset(&d3d9caps, 0, sizeof(d3d9caps));
HRESULT hr = m_pD3D9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3d9caps);
if (FAILED(hr) || !(d3d9caps.Caps & D3DCAPS_OVERLAY)) {
overlaySupported = false;
} else {
hr = m_pD3D9->QueryInterface(IID_PPV_ARGS(&d3d9overlay));
if (FAILED(hr) || (d3d9overlay == NULL)) {
overlaySupported = false;
} else {
hr = d3d9overlay->CheckDeviceOverlayType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_D3DPP.BackBufferWidth,
m_D3DPP.BackBufferHeight, m_D3DPP.BackBufferFormat, NULL,
D3DDISPLAYROTATION_IDENTITY, &d3doverlaycaps);
MSDK_SAFE_RELEASE(d3d9overlay);
if (FAILED(hr)) {
overlaySupported = false;
} else {
overlaySupported = true;
}
}
}
return overlaySupported;
}
mfxStatus CD3D9Device::FillD3DPP(mfxHDL hWindow, mfxU16 nViews, D3DPRESENT_PARAMETERS &D3DPP) {
mfxStatus sts = MFX_ERR_NONE;
D3DPP.Windowed = true;
D3DPP.hDeviceWindow = (HWND)hWindow;
D3DPP.Flags = D3DPRESENTFLAG_VIDEO;
D3DPP.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
D3DPP.PresentationInterval =
D3DPRESENT_INTERVAL_ONE; // note that this setting leads to an implicit timeBeginPeriod call
D3DPP.BackBufferCount = 1;
D3DPP.BackBufferFormat = (m_bIsA2rgb10) ? D3DFMT_A2R10G10B10 : D3DFMT_X8R8G8B8;
if (hWindow) {
RECT r;
GetClientRect((HWND)hWindow, &r);
int x = GetSystemMetrics(SM_CXSCREEN);
int y = GetSystemMetrics(SM_CYSCREEN);
D3DPP.BackBufferWidth = std::min(r.right - r.left, (long)x);
D3DPP.BackBufferHeight = std::min(r.bottom - r.top, (long)y);
} else {
D3DPP.BackBufferWidth = GetSystemMetrics(SM_CYSCREEN);
D3DPP.BackBufferHeight = GetSystemMetrics(SM_CYSCREEN);
}
//
// Mark the back buffer lockable if software DXVA2 could be used.
// This is because software DXVA2 device requires a lockable render target
// for the optimal performance.
//
{ D3DPP.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; }
bool isOverlaySupported = CheckOverlaySupport();
if (2 == nViews && !isOverlaySupported) return MFX_ERR_UNSUPPORTED;
bool needOverlay = (2 == nViews) ? true : false;
D3DPP.SwapEffect = needOverlay ? D3DSWAPEFFECT_OVERLAY : D3DSWAPEFFECT_DISCARD;
return sts;
}
mfxStatus CD3D9Device::Init(mfxHDL hWindow, mfxU16 nViews, mfxU32 nAdapterNum) {
mfxStatus sts = MFX_ERR_NONE;
if (2 < nViews) return MFX_ERR_UNSUPPORTED;
m_nViews = nViews;
HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3D9);
if (!m_pD3D9 || FAILED(hr)) return MFX_ERR_DEVICE_FAILED;
ZeroMemory(&m_D3DPP, sizeof(m_D3DPP));
sts = FillD3DPP(hWindow, nViews, m_D3DPP);
hr = m_pD3D9->CreateDeviceEx(nAdapterNum, D3DDEVTYPE_HAL, (HWND)hWindow,
D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
&m_D3DPP, NULL, &m_pD3DD9);
if (FAILED(hr)) return MFX_ERR_NULL_PTR;
if (hWindow) {
hr = m_pD3DD9->ResetEx(&m_D3DPP, NULL);
if (FAILED(hr)) return MFX_ERR_UNDEFINED_BEHAVIOR;
hr = m_pD3DD9->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
if (FAILED(hr)) return MFX_ERR_UNDEFINED_BEHAVIOR;
}
UINT resetToken = 0;
hr = DXVA2CreateDirect3DDeviceManager9(&resetToken, &m_pDeviceManager9);
if (FAILED(hr)) return MFX_ERR_NULL_PTR;
hr = m_pDeviceManager9->ResetDevice(m_pD3DD9, resetToken);
if (FAILED(hr)) return MFX_ERR_UNDEFINED_BEHAVIOR;
m_resetToken = resetToken;
return sts;
}
mfxStatus CD3D9Device::Reset() {
HRESULT hr = NO_ERROR;
MSDK_CHECK_POINTER(m_pD3DD9, MFX_ERR_NULL_PTR);
if (m_D3DPP.Windowed) {
RECT r;
GetClientRect((HWND)m_D3DPP.hDeviceWindow, &r);
int x = GetSystemMetrics(SM_CXSCREEN);
int y = GetSystemMetrics(SM_CYSCREEN);
m_D3DPP.BackBufferWidth = std::min(r.right - r.left, (long)x);
m_D3DPP.BackBufferHeight = std::min(r.bottom - r.top, (long)y);
} else {
m_D3DPP.BackBufferWidth = GetSystemMetrics(SM_CXSCREEN);
m_D3DPP.BackBufferHeight = GetSystemMetrics(SM_CYSCREEN);
}
// Reset will change the parameters, so use a copy instead.
D3DPRESENT_PARAMETERS d3dpp = m_D3DPP;
hr = m_pD3DD9->ResetEx(&d3dpp, NULL);
if (FAILED(hr)) return MFX_ERR_UNDEFINED_BEHAVIOR;
hr = m_pDeviceManager9->ResetDevice(m_pD3DD9, m_resetToken);
if (FAILED(hr)) return MFX_ERR_UNDEFINED_BEHAVIOR;
return MFX_ERR_NONE;
}
void CD3D9Device::Close() {
MSDK_SAFE_RELEASE(m_pDXVAVP_Left);
MSDK_SAFE_RELEASE(m_pDXVAVP_Right);
MSDK_SAFE_RELEASE(m_pDXVAVPS);
MSDK_SAFE_RELEASE(m_pDeviceManager9);
MSDK_SAFE_RELEASE(m_pD3DD9);
MSDK_SAFE_RELEASE(m_pD3D9);
m_pS3DControl = NULL;
}
CD3D9Device::~CD3D9Device() { Close(); }
mfxStatus CD3D9Device::GetHandle(mfxHandleType type, mfxHDL *pHdl) {
if (MFX_HANDLE_DIRECT3D_DEVICE_MANAGER9 == type && pHdl != NULL) {
*pHdl = m_pDeviceManager9;
return MFX_ERR_NONE;
} else if (MFX_HANDLE_GFXS3DCONTROL == type && pHdl != NULL) {
*pHdl = m_pS3DControl;
return MFX_ERR_NONE;
}
return MFX_ERR_UNSUPPORTED;
}
mfxStatus CD3D9Device::SetHandle(mfxHandleType type, mfxHDL hdl) {
if (MFX_HANDLE_GFXS3DCONTROL == type && hdl != NULL) {
m_pS3DControl = (IGFXS3DControl *)hdl;
return MFX_ERR_NONE;
} else if (MFX_HANDLE_DEVICEWINDOW == type && hdl != NULL) // for render window handle
{
m_D3DPP.hDeviceWindow = (HWND)hdl;
return MFX_ERR_NONE;
}
return MFX_ERR_UNSUPPORTED;
}
mfxStatus CD3D9Device::RenderFrame(mfxFrameSurface1 *pSurface, mfxFrameAllocator *pmfxAlloc) {
HRESULT hr = S_OK;
if (!(1 == m_nViews || (2 == m_nViews && NULL != m_pS3DControl))) return MFX_ERR_UNDEFINED_BEHAVIOR;
MSDK_CHECK_POINTER(pSurface, MFX_ERR_NULL_PTR);
MSDK_CHECK_POINTER(m_pDeviceManager9, MFX_ERR_NOT_INITIALIZED);
MSDK_CHECK_POINTER(pmfxAlloc, MFX_ERR_NULL_PTR);
// don't try to render second view if output rect changed since first view
if (2 == m_nViews && (0 != pSurface->Info.FrameId.ViewId)) return MFX_ERR_NONE;
hr = m_pD3DD9->TestCooperativeLevel();
switch (hr) {
case D3D_OK:
break;
case D3DERR_DEVICELOST: {
return MFX_ERR_DEVICE_LOST;
}
case D3DERR_DEVICENOTRESET: {
return MFX_ERR_UNKNOWN;
}
default: {
return MFX_ERR_UNKNOWN;
}
}
CComPtr<IDirect3DSurface9> pBackBuffer;
hr = m_pD3DD9->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
mfxHDLPair *dxMemId = (mfxHDLPair *)pSurface->Data.MemId;
hr = m_pD3DD9->StretchRect((IDirect3DSurface9 *)dxMemId->first, NULL, pBackBuffer, NULL, D3DTEXF_LINEAR);
if (FAILED(hr)) {
return MFX_ERR_UNKNOWN;
}
if (SUCCEEDED(hr) && (1 == m_nViews || pSurface->Info.FrameId.ViewId == 1)) {
hr = m_pD3DD9->Present(NULL, NULL, NULL, NULL);
}
return SUCCEEDED(hr) ? MFX_ERR_NONE : MFX_ERR_DEVICE_FAILED;
}
mfxStatus CD3D9Device::CreateVideoProcessors() {
if (!(1 == m_nViews || (2 == m_nViews && NULL != m_pS3DControl))) return MFX_ERR_UNDEFINED_BEHAVIOR;
MSDK_SAFE_RELEASE(m_pDXVAVP_Left);
MSDK_SAFE_RELEASE(m_pDXVAVP_Right);
HRESULT hr;
if (2 == m_nViews && NULL != m_pS3DControl) {
hr = m_pS3DControl->SetDevice(m_pDeviceManager9);
if (FAILED(hr)) {
return MFX_ERR_DEVICE_FAILED;
}
}
ZeroMemory(&m_backBufferDesc, sizeof(m_backBufferDesc));
IDirect3DSurface9 *backBufferTmp = NULL;
hr = m_pD3DD9->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backBufferTmp);
if (NULL != backBufferTmp) backBufferTmp->GetDesc(&m_backBufferDesc);
MSDK_SAFE_RELEASE(backBufferTmp);
if (SUCCEEDED(hr)) {
// Create DXVA2 Video Processor Service.
hr = DXVA2CreateVideoService(m_pD3DD9, IID_IDirectXVideoProcessorService, (void **)&m_pDXVAVPS);
}
if (2 == m_nViews) {
// Activate L channel
if (SUCCEEDED(hr)) {
hr = m_pS3DControl->SelectLeftView();
}
if (SUCCEEDED(hr)) {
// Create VPP device for the L channel
hr = m_pDXVAVPS->CreateVideoProcessor(DXVA2_VideoProcProgressiveDevice, &m_VideoDesc, m_D3DPP.BackBufferFormat, 1,
&m_pDXVAVP_Left);
}
// Activate R channel
if (SUCCEEDED(hr)) {
hr = m_pS3DControl->SelectRightView();
}
}
if (SUCCEEDED(hr)) {
hr = m_pDXVAVPS->CreateVideoProcessor(DXVA2_VideoProcProgressiveDevice, &m_VideoDesc, m_D3DPP.BackBufferFormat, 1,
&m_pDXVAVP_Right);
}
return SUCCEEDED(hr) ? MFX_ERR_NONE : MFX_ERR_DEVICE_FAILED;
}
#endif // #if defined(WIN32) || defined(WIN64)
/* ****************************************************************************** *\
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-2014 Intel Corporation. All Rights Reserved.
\* ****************************************************************************** */
#include "sysMemAllocator.hpp"
#define MSDK_ALIGN32(X) (((mfxU32)((X) + 31)) & (~(mfxU32)31))
#define ID_BUFFER MFX_MAKEFOURCC('B', 'U', 'F', 'F')
#define ID_FRAME MFX_MAKEFOURCC('F', 'R', 'M', 'E')
SysMemFrameAllocator::SysMemFrameAllocator() : m_pBufferAllocator(0), m_bOwnBufferAllocator(false) {}
SysMemFrameAllocator::~SysMemFrameAllocator() { Close(); }
mfxStatus SysMemFrameAllocator::Init(mfxAllocatorParams *pParams) {
// check if any params passed from application
if (pParams) {
SysMemAllocatorParams *pSysMemParams = 0;
pSysMemParams = dynamic_cast<SysMemAllocatorParams *>(pParams);
if (!pSysMemParams) return MFX_ERR_NOT_INITIALIZED;
m_pBufferAllocator = pSysMemParams->pBufferAllocator;
m_bOwnBufferAllocator = false;
}
// if buffer allocator wasn't passed from application create own
if (!m_pBufferAllocator) {
m_pBufferAllocator = new SysMemBufferAllocator;
if (!m_pBufferAllocator) return MFX_ERR_MEMORY_ALLOC;
m_bOwnBufferAllocator = true;
}
return MFX_ERR_NONE;
}
mfxStatus SysMemFrameAllocator::Close() {
mfxStatus sts = BaseFrameAllocator::Close();
if (m_bOwnBufferAllocator) {
delete m_pBufferAllocator;
m_pBufferAllocator = 0;
}
return sts;
}
mfxStatus SysMemFrameAllocator::LockFrame(mfxMemId mid, mfxFrameData *ptr) {
if (!m_pBufferAllocator) return MFX_ERR_NOT_INITIALIZED;
if (!ptr) return MFX_ERR_NULL_PTR;
sFrame *fs = 0;
mfxStatus sts = m_pBufferAllocator->Lock(m_pBufferAllocator->pthis, mid, (mfxU8 **)&fs);
if (MFX_ERR_NONE != sts) return sts;
if (ID_FRAME != fs->id) {
m_pBufferAllocator->Unlock(m_pBufferAllocator->pthis, mid);
return MFX_ERR_INVALID_HANDLE;
}
mfxU16 Width2 = (mfxU16)MSDK_ALIGN32(fs->info.Width);
mfxU16 Height2 = (mfxU16)MSDK_ALIGN32(fs->info.Height);
ptr->B = ptr->Y = (mfxU8 *)fs + MSDK_ALIGN32(sizeof(sFrame));
switch (fs->info.FourCC) {
case MFX_FOURCC_NV12:
ptr->U = ptr->Y + Width2 * Height2;
ptr->V = ptr->U + 1;
ptr->Pitch = Width2;
break;
case MFX_FOURCC_YV12:
ptr->V = ptr->Y + Width2 * Height2;
ptr->U = ptr->V + (Width2 >> 1) * (Height2 >> 1);
ptr->Pitch = Width2;
break;
case MFX_FOURCC_YUY2:
ptr->U = ptr->Y + 1;
ptr->V = ptr->Y + 3;
ptr->Pitch = 2 * Width2;
break;
case MFX_FOURCC_RGB3:
ptr->G = ptr->B + 1;
ptr->R = ptr->B + 2;
ptr->Pitch = 3 * Width2;
break;
case MFX_FOURCC_RGB4:
case MFX_FOURCC_A2RGB10:
ptr->G = ptr->B + 1;
ptr->R = ptr->B + 2;
ptr->A = ptr->B + 3;
ptr->Pitch = 4 * Width2;
break;
case MFX_FOURCC_R16:
ptr->Y16 = (mfxU16 *)ptr->B;
ptr->Pitch = 2 * Width2;
break;
case MFX_FOURCC_P010:
ptr->U = ptr->Y + Width2 * Height2 * 2;
ptr->V = ptr->U + 2;
ptr->Pitch = Width2 * 2;
break;
default:
return MFX_ERR_UNSUPPORTED;
}
return MFX_ERR_NONE;
}
mfxStatus SysMemFrameAllocator::UnlockFrame(mfxMemId mid, mfxFrameData *ptr) {
if (!m_pBufferAllocator) return MFX_ERR_NOT_INITIALIZED;
mfxStatus sts = m_pBufferAllocator->Unlock(m_pBufferAllocator->pthis, mid);
if (MFX_ERR_NONE != sts) return sts;
if (NULL != ptr) {
ptr->Pitch = 0;
ptr->Y = 0;
ptr->U = 0;
ptr->V = 0;
}
return MFX_ERR_NONE;
}
mfxStatus SysMemFrameAllocator::GetFrameHDL(mfxMemId /*mid*/, mfxHDL * /*handle*/) { return MFX_ERR_UNSUPPORTED; }
mfxStatus SysMemFrameAllocator::CheckRequestType(mfxFrameAllocRequest *request) {
mfxStatus sts = BaseFrameAllocator::CheckRequestType(request);
if (MFX_ERR_NONE != sts) return sts;
if ((request->Type & MFX_MEMTYPE_SYSTEM_MEMORY) != 0)
return MFX_ERR_NONE;
else
return MFX_ERR_UNSUPPORTED;
}
mfxStatus SysMemFrameAllocator::AllocImpl(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response) {
if (!m_pBufferAllocator) return MFX_ERR_NOT_INITIALIZED;
mfxU32 numAllocated = 0;
mfxU32 Width2 = MSDK_ALIGN32(request->Info.Width);
mfxU32 Height2 = MSDK_ALIGN32(request->Info.Height);
mfxU32 nbytes;
switch (request->Info.FourCC) {
case MFX_FOURCC_YV12:
case MFX_FOURCC_NV12:
nbytes = Width2 * Height2 + (Width2 >> 1) * (Height2 >> 1) + (Width2 >> 1) * (Height2 >> 1);
break;
case MFX_FOURCC_RGB3:
nbytes = Width2 * Height2 + Width2 * Height2 + Width2 * Height2;
break;
case MFX_FOURCC_RGB4:
nbytes = Width2 * Height2 + Width2 * Height2 + Width2 * Height2 + Width2 * Height2;
break;
case MFX_FOURCC_YUY2:
nbytes = Width2 * Height2 + (Width2 >> 1) * (Height2) + (Width2 >> 1) * (Height2);
break;
case MFX_FOURCC_R16:
nbytes = 2 * Width2 * Height2;
break;
case MFX_FOURCC_P010:
nbytes = Width2 * Height2 + (Width2 >> 1) * (Height2 >> 1) + (Width2 >> 1) * (Height2 >> 1);
nbytes *= 2;
break;
case MFX_FOURCC_A2RGB10:
nbytes = Width2 * Height2 * 4; // 4 bytes per pixel
break;
default:
return MFX_ERR_UNSUPPORTED;
}
safe_array<mfxMemId> mids(new mfxMemId[request->NumFrameSuggested]);
if (!mids.get()) return MFX_ERR_MEMORY_ALLOC;
// allocate frames
for (numAllocated = 0; numAllocated < request->NumFrameSuggested; numAllocated++) {
mfxStatus sts = m_pBufferAllocator->Alloc(m_pBufferAllocator->pthis, nbytes + MSDK_ALIGN32(sizeof(sFrame)),
request->Type, &(mids.get()[numAllocated]));
if (MFX_ERR_NONE != sts) break;
sFrame *fs;
sts = m_pBufferAllocator->Lock(m_pBufferAllocator->pthis, mids.get()[numAllocated], (mfxU8 **)&fs);
if (MFX_ERR_NONE != sts) break;
fs->id = ID_FRAME;
fs->info = request->Info;
m_pBufferAllocator->Unlock(m_pBufferAllocator->pthis, mids.get()[numAllocated]);
}
// check the number of allocated frames
if (numAllocated < request->NumFrameSuggested) {
return MFX_ERR_MEMORY_ALLOC;
}
response->NumFrameActual = (mfxU16)numAllocated;
response->mids = mids.release();
return MFX_ERR_NONE;
}
mfxStatus SysMemFrameAllocator::ReleaseResponse(mfxFrameAllocResponse *response) {
if (!response) return MFX_ERR_NULL_PTR;
if (!m_pBufferAllocator) return MFX_ERR_NOT_INITIALIZED;
mfxStatus sts = MFX_ERR_NONE;
if (response->mids) {
for (mfxU32 i = 0; i < response->NumFrameActual; i++) {
if (response->mids[i]) {
sts = m_pBufferAllocator->Free(m_pBufferAllocator->pthis, response->mids[i]);
if (MFX_ERR_NONE != sts) return sts;
}
}
}
delete[] response->mids;
response->mids = 0;
return sts;
}
SysMemBufferAllocator::SysMemBufferAllocator() {}
SysMemBufferAllocator::~SysMemBufferAllocator() {}
mfxStatus SysMemBufferAllocator::AllocBuffer(mfxU32 nbytes, mfxU16 type, mfxMemId *mid) {
if (!mid) return MFX_ERR_NULL_PTR;
if (0 == (type & MFX_MEMTYPE_SYSTEM_MEMORY)) return MFX_ERR_UNSUPPORTED;
mfxU32 header_size = MSDK_ALIGN32(sizeof(sBuffer));
mfxU8 *buffer_ptr = (mfxU8 *)calloc(header_size + nbytes + 32, 1);
if (!buffer_ptr) return MFX_ERR_MEMORY_ALLOC;
sBuffer *bs = (sBuffer *)buffer_ptr;
bs->id = ID_BUFFER;
bs->type = type;
bs->nbytes = nbytes;
*mid = (mfxHDL)bs;
return MFX_ERR_NONE;
}
mfxStatus SysMemBufferAllocator::LockBuffer(mfxMemId mid, mfxU8 **ptr) {
if (!ptr) return MFX_ERR_NULL_PTR;
sBuffer *bs = (sBuffer *)mid;
if (!bs) return MFX_ERR_INVALID_HANDLE;
if (ID_BUFFER != bs->id) return MFX_ERR_INVALID_HANDLE;
*ptr = (mfxU8 *)((size_t)((mfxU8 *)bs + MSDK_ALIGN32(sizeof(sBuffer)) + 31) & (~((size_t)31)));
return MFX_ERR_NONE;
}
mfxStatus SysMemBufferAllocator::UnlockBuffer(mfxMemId mid) {
sBuffer *bs = (sBuffer *)mid;
if (!bs || ID_BUFFER != bs->id) return MFX_ERR_INVALID_HANDLE;
return MFX_ERR_NONE;
}
mfxStatus SysMemBufferAllocator::FreeBuffer(mfxMemId mid) {
sBuffer *bs = (sBuffer *)mid;
if (!bs || ID_BUFFER != bs->id) return MFX_ERR_INVALID_HANDLE;
free(bs);
return MFX_ERR_NONE;
}
/* ****************************************************************************** *\
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-2015 Intel Corporation. All Rights Reserved.
\* ****************************************************************************** */
#include <stdio.h>
#include <assert.h>
#include "vaapiAllocator.hpp"
enum {
MFX_FOURCC_VP8_NV12 = MFX_MAKEFOURCC('V', 'P', '8', 'N'),
MFX_FOURCC_VP8_MBDATA = MFX_MAKEFOURCC('V', 'P', '8', 'M'),
MFX_FOURCC_VP8_SEGMAP = MFX_MAKEFOURCC('V', 'P', '8', 'S'),
};
unsigned int ConvertMfxFourccToVAFormat(mfxU32 fourcc) {
switch (fourcc) {
case MFX_FOURCC_NV12:
return VA_FOURCC_NV12;
case MFX_FOURCC_YUY2:
return VA_FOURCC_YUY2;
case MFX_FOURCC_YV12:
return VA_FOURCC_YV12;
case MFX_FOURCC_RGB4:
return VA_FOURCC_ARGB;
case MFX_FOURCC_P8:
return VA_FOURCC_P208;
default:
assert(!"unsupported fourcc");
return 0;
}
}
unsigned int ConvertVP8FourccToMfxFourcc(mfxU32 fourcc) {
switch (fourcc) {
case MFX_FOURCC_VP8_NV12:
case MFX_FOURCC_VP8_MBDATA:
return MFX_FOURCC_NV12;
case MFX_FOURCC_VP8_SEGMAP:
return MFX_FOURCC_P8;
default:
return fourcc;
}
}
vaapiFrameAllocator::vaapiFrameAllocator() : m_dpy(0) {}
vaapiFrameAllocator::~vaapiFrameAllocator() { Close(); }
mfxStatus vaapiFrameAllocator::Init(mfxAllocatorParams *pParams) {
vaapiAllocatorParams *p_vaapiParams = dynamic_cast<vaapiAllocatorParams *>(pParams);
if ((NULL == p_vaapiParams) || (NULL == p_vaapiParams->m_dpy)) return MFX_ERR_NOT_INITIALIZED;
m_dpy = p_vaapiParams->m_dpy;
return MFX_ERR_NONE;
}
mfxStatus vaapiFrameAllocator::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 vaapiFrameAllocator::Close() { return BaseFrameAllocator::Close(); }
mfxStatus vaapiFrameAllocator::AllocImpl(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response) {
mfxStatus mfx_res = MFX_ERR_NONE;
VAStatus va_res = VA_STATUS_SUCCESS;
unsigned int va_fourcc = 0;
VASurfaceID *surfaces = NULL;
VASurfaceAttrib attrib;
vaapiMemId *vaapi_mids = NULL, *vaapi_mid = NULL;
mfxMemId *mids = NULL;
mfxU32 fourcc = request->Info.FourCC;
mfxU16 surfaces_num = request->NumFrameSuggested, numAllocated = 0, i = 0;
bool bCreateSrfSucceeded = false;
memset(response, 0, sizeof(mfxFrameAllocResponse));
// VP8 hybrid driver has weird requirements for allocation of surfaces/buffers for VP8 encoding
// to comply with them additional logic is required to support regular and VP8 hybrid allocation pathes
mfxU32 mfx_fourcc = ConvertVP8FourccToMfxFourcc(fourcc);
va_fourcc = ConvertMfxFourccToVAFormat(mfx_fourcc);
if (!va_fourcc || ((VA_FOURCC_NV12 != va_fourcc) && (VA_FOURCC_YV12 != va_fourcc) && (VA_FOURCC_YUY2 != va_fourcc) &&
(VA_FOURCC_ARGB != va_fourcc) && (VA_FOURCC_P208 != va_fourcc))) {
return MFX_ERR_MEMORY_ALLOC;
}
if (!surfaces_num) {
return MFX_ERR_MEMORY_ALLOC;
}
if (MFX_ERR_NONE == mfx_res) {
surfaces = (VASurfaceID *)calloc(surfaces_num, sizeof(VASurfaceID));
vaapi_mids = (vaapiMemId *)calloc(surfaces_num, sizeof(vaapiMemId));
mids = (mfxMemId *)calloc(surfaces_num, sizeof(mfxMemId));
if ((NULL == surfaces) || (NULL == vaapi_mids) || (NULL == mids)) mfx_res = MFX_ERR_MEMORY_ALLOC;
}
if (MFX_ERR_NONE == mfx_res) {
if (VA_FOURCC_P208 != va_fourcc) {
unsigned int format;
attrib.type = VASurfaceAttribPixelFormat;
attrib.flags = VA_SURFACE_ATTRIB_SETTABLE;
attrib.value.type = VAGenericValueTypeInteger;
attrib.value.value.i = va_fourcc;
format = va_fourcc;
if (fourcc == MFX_FOURCC_VP8_NV12) {
// special configuration for NV12 surf allocation for VP8 hybrid encoder is required
attrib.type = (VASurfaceAttribType)VASurfaceAttribUsageHint;
attrib.value.value.i = VA_SURFACE_ATTRIB_USAGE_HINT_ENCODER;
} else if (fourcc == MFX_FOURCC_VP8_MBDATA) {
// special configuration for MB data surf allocation for VP8 hybrid encoder is required
attrib.value.value.i = VA_FOURCC_P208;
format = VA_FOURCC_P208;
} else if (va_fourcc == VA_FOURCC_NV12) {
format = VA_RT_FORMAT_YUV420;
}
va_res = vaCreateSurfaces(m_dpy, format, request->Info.Width, request->Info.Height, surfaces, surfaces_num,
&attrib, 1);
mfx_res = va_to_mfx_status(va_res);
bCreateSrfSucceeded = (MFX_ERR_NONE == mfx_res);
} else {
VAContextID context_id = request->reserved[0];
int codedbuf_size;
int width32 = 32 * ((request->Info.Width + 31) >> 5);
int height32 = 32 * ((request->Info.Height + 31) >> 5);
VABufferType codedbuf_type;
if (fourcc == MFX_FOURCC_VP8_SEGMAP) {
codedbuf_size = request->Info.Width * request->Info.Height;
codedbuf_type = (VABufferType)VAEncMacroblockMapBufferType;
} else {
codedbuf_size = static_cast<int>((width32 * height32) * 400LL / (16 * 16));
codedbuf_type = VAEncCodedBufferType;
}
for (numAllocated = 0; numAllocated < surfaces_num; numAllocated++) {
VABufferID coded_buf;
va_res = vaCreateBuffer(m_dpy, context_id, codedbuf_type, codedbuf_size, 1, NULL, &coded_buf);
mfx_res = va_to_mfx_status(va_res);
if (MFX_ERR_NONE != mfx_res) break;
surfaces[numAllocated] = coded_buf;
}
}
}
if (MFX_ERR_NONE == mfx_res) {
for (i = 0; i < surfaces_num; ++i) {
vaapi_mid = &(vaapi_mids[i]);
vaapi_mid->m_fourcc = fourcc;
vaapi_mid->m_surface = &(surfaces[i]);
mids[i] = vaapi_mid;
}
response->mids = mids;
response->NumFrameActual = surfaces_num;
} else // i.e. MFX_ERR_NONE != mfx_res
{
response->mids = NULL;
response->NumFrameActual = 0;
if (VA_FOURCC_P208 != va_fourcc || fourcc == MFX_FOURCC_VP8_MBDATA) {
if (bCreateSrfSucceeded) vaDestroySurfaces(m_dpy, surfaces, surfaces_num);
} else {
for (i = 0; i < numAllocated; i++) vaDestroyBuffer(m_dpy, surfaces[i]);
}
if (mids) {
free(mids);
mids = NULL;
}
if (vaapi_mids) {
free(vaapi_mids);
vaapi_mids = NULL;
}
if (surfaces) {
free(surfaces);
surfaces = NULL;
}
}
return mfx_res;
}
mfxStatus vaapiFrameAllocator::ReleaseResponse(mfxFrameAllocResponse *response) {
vaapiMemId *vaapi_mids = NULL;
mfxU32 i = 0;
if (!response) return MFX_ERR_NULL_PTR;
if (response->mids) {
VASurfaceID *surfaces = NULL;
vaapi_mids = (vaapiMemId *)(response->mids[0]);
mfxU32 mfx_fourcc = ConvertVP8FourccToMfxFourcc(vaapi_mids->m_fourcc);
bool isBitstreamMemory = (MFX_FOURCC_P8 == mfx_fourcc) ? true : false;
surfaces = vaapi_mids->m_surface;
for (i = 0; i < response->NumFrameActual; ++i) {
if (MFX_FOURCC_P8 == vaapi_mids[i].m_fourcc)
vaDestroyBuffer(m_dpy, surfaces[i]);
else if (vaapi_mids[i].m_sys_buffer)
free(vaapi_mids[i].m_sys_buffer);
}
free(vaapi_mids);
free(response->mids);
response->mids = NULL;
if (!isBitstreamMemory) {
vaDestroySurfaces(m_dpy, surfaces, response->NumFrameActual);
}
free(surfaces);
}
response->NumFrameActual = 0;
return MFX_ERR_NONE;
}
mfxStatus vaapiFrameAllocator::LockFrame(mfxMemId mid, mfxFrameData *ptr) {
mfxStatus mfx_res = MFX_ERR_NONE;
VAStatus va_res = VA_STATUS_SUCCESS;
vaapiMemId *vaapi_mid = (vaapiMemId *)mid;
mfxU8 *pBuffer = 0;
if (!vaapi_mid || !(vaapi_mid->m_surface)) return MFX_ERR_INVALID_HANDLE;
mfxU32 mfx_fourcc = ConvertVP8FourccToMfxFourcc(vaapi_mid->m_fourcc);
if (MFX_FOURCC_P8 == mfx_fourcc) // bitstream processing
{
VACodedBufferSegment *coded_buffer_segment;
if (vaapi_mid->m_fourcc == MFX_FOURCC_VP8_SEGMAP)
va_res = vaMapBuffer(m_dpy, *(vaapi_mid->m_surface), (void **)(&pBuffer));
else
va_res = vaMapBuffer(m_dpy, *(vaapi_mid->m_surface), (void **)(&coded_buffer_segment));
mfx_res = va_to_mfx_status(va_res);
if (MFX_ERR_NONE == mfx_res) {
if (vaapi_mid->m_fourcc == MFX_FOURCC_VP8_SEGMAP)
ptr->Y = pBuffer;
else
ptr->Y = (mfxU8 *)coded_buffer_segment->buf;
}
} else // Image processing
{
va_res = vaSyncSurface(m_dpy, *(vaapi_mid->m_surface));
mfx_res = va_to_mfx_status(va_res);
if (MFX_ERR_NONE == mfx_res) {
va_res = vaDeriveImage(m_dpy, *(vaapi_mid->m_surface), &(vaapi_mid->m_image));
mfx_res = va_to_mfx_status(va_res);
}
if (MFX_ERR_NONE == mfx_res) {
va_res = vaMapBuffer(m_dpy, vaapi_mid->m_image.buf, (void **)&pBuffer);
mfx_res = va_to_mfx_status(va_res);
}
if (MFX_ERR_NONE == mfx_res) {
switch (vaapi_mid->m_image.format.fourcc) {
case VA_FOURCC_NV12:
if (mfx_fourcc == MFX_FOURCC_NV12) {
ptr->Pitch = (mfxU16)vaapi_mid->m_image.pitches[0];
ptr->Y = pBuffer + vaapi_mid->m_image.offsets[0];
ptr->U = pBuffer + vaapi_mid->m_image.offsets[1];
ptr->V = ptr->U + 1;
} else
mfx_res = MFX_ERR_LOCK_MEMORY;
break;
case VA_FOURCC_YV12:
if (mfx_fourcc == MFX_FOURCC_YV12) {
ptr->Pitch = (mfxU16)vaapi_mid->m_image.pitches[0];
ptr->Y = pBuffer + vaapi_mid->m_image.offsets[0];
ptr->V = pBuffer + vaapi_mid->m_image.offsets[1];
ptr->U = pBuffer + vaapi_mid->m_image.offsets[2];
} else
mfx_res = MFX_ERR_LOCK_MEMORY;
break;
case VA_FOURCC_YUY2:
if (mfx_fourcc == MFX_FOURCC_YUY2) {
ptr->Pitch = (mfxU16)vaapi_mid->m_image.pitches[0];
ptr->Y = pBuffer + vaapi_mid->m_image.offsets[0];
ptr->U = ptr->Y + 1;
ptr->V = ptr->Y + 3;
} else
mfx_res = MFX_ERR_LOCK_MEMORY;
break;
case VA_FOURCC_ARGB:
if (mfx_fourcc == MFX_FOURCC_RGB4) {
ptr->Pitch = (mfxU16)vaapi_mid->m_image.pitches[0];
ptr->B = pBuffer + vaapi_mid->m_image.offsets[0];
ptr->G = ptr->B + 1;
ptr->R = ptr->B + 2;
ptr->A = ptr->B + 3;
} else
mfx_res = MFX_ERR_LOCK_MEMORY;
break;
case VA_FOURCC_P208:
if (mfx_fourcc == MFX_FOURCC_NV12) {
ptr->Pitch = (mfxU16)vaapi_mid->m_image.pitches[0];
ptr->Y = pBuffer + vaapi_mid->m_image.offsets[0];
} else
mfx_res = MFX_ERR_LOCK_MEMORY;
break;
default:
mfx_res = MFX_ERR_LOCK_MEMORY;
break;
}
}
}
return mfx_res;
}
mfxStatus vaapiFrameAllocator::UnlockFrame(mfxMemId mid, mfxFrameData *ptr) {
vaapiMemId *vaapi_mid = (vaapiMemId *)mid;
if (!vaapi_mid || !(vaapi_mid->m_surface)) return MFX_ERR_INVALID_HANDLE;
mfxU32 mfx_fourcc = ConvertVP8FourccToMfxFourcc(vaapi_mid->m_fourcc);
if (MFX_FOURCC_P8 == mfx_fourcc) // bitstream processing
{
vaUnmapBuffer(m_dpy, *(vaapi_mid->m_surface));
} else // Image processing
{
vaUnmapBuffer(m_dpy, vaapi_mid->m_image.buf);
vaDestroyImage(m_dpy, vaapi_mid->m_image.image_id);
if (NULL != ptr) {
ptr->Pitch = 0;
ptr->Y = NULL;
ptr->U = NULL;
ptr->V = NULL;
ptr->A = NULL;
}
}
return MFX_ERR_NONE;
}
mfxStatus vaapiFrameAllocator::GetFrameHDL(mfxMemId mid, mfxHDL *handle) {
vaapiMemId *vaapi_mid = (vaapiMemId *)mid;
if (!handle || !vaapi_mid || !(vaapi_mid->m_surface)) return MFX_ERR_INVALID_HANDLE;
*handle = vaapi_mid->m_surface; // VASurfaceID* <-> mfxHDL
return MFX_ERR_NONE;
}
/* ****************************************************************************** *\
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-2013 Intel Corporation. All Rights Reserved.
\* ****************************************************************************** */
#include "vaapiDevice.hpp"
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdexcept>
#include <string.h>
#define MFX_PCI_DIR "/sys/bus/pci/devices"
#define MFX_DRI_DIR "/dev/dri/"
#define MFX_PCI_DISPLAY_CONTROLLER_CLASS 0x03
mfxStatus va_to_mfx_status(VAStatus va_res) {
mfxStatus mfxRes = MFX_ERR_NONE;
switch (va_res) {
case VA_STATUS_SUCCESS:
mfxRes = MFX_ERR_NONE;
break;
case VA_STATUS_ERROR_ALLOCATION_FAILED:
mfxRes = MFX_ERR_MEMORY_ALLOC;
break;
case VA_STATUS_ERROR_ATTR_NOT_SUPPORTED:
case VA_STATUS_ERROR_UNSUPPORTED_PROFILE:
case VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT:
case VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT:
case VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE:
case VA_STATUS_ERROR_FLAG_NOT_SUPPORTED:
case VA_STATUS_ERROR_RESOLUTION_NOT_SUPPORTED:
mfxRes = MFX_ERR_UNSUPPORTED;
break;
case VA_STATUS_ERROR_INVALID_DISPLAY:
case VA_STATUS_ERROR_INVALID_CONFIG:
case VA_STATUS_ERROR_INVALID_CONTEXT:
case VA_STATUS_ERROR_INVALID_SURFACE:
case VA_STATUS_ERROR_INVALID_BUFFER:
case VA_STATUS_ERROR_INVALID_IMAGE:
case VA_STATUS_ERROR_INVALID_SUBPICTURE:
mfxRes = MFX_ERR_NOT_INITIALIZED;
break;
case VA_STATUS_ERROR_INVALID_PARAMETER:
mfxRes = MFX_ERR_INVALID_VIDEO_PARAM;
break;
default:
mfxRes = MFX_ERR_UNKNOWN;
break;
}
return mfxRes;
}
CLibVA* CreateLibVA(void) { return new DRMLibVA; }
CHWDevice* CreateVAAPIDevice(void) { return new CVAAPIDeviceDRM(); }
struct mfx_disp_adapters {
mfxU32 vendor_id;
mfxU32 device_id;
};
static int mfx_dir_filter(const struct dirent* dir_ent) {
if (!dir_ent) return 0;
if (!strcmp(dir_ent->d_name, ".")) return 0;
if (!strcmp(dir_ent->d_name, "..")) return 0;
return 1;
}
typedef int (*fsort)(const struct dirent**, const struct dirent**);
static mfxU32 mfx_init_adapters(struct mfx_disp_adapters** p_adapters) {
mfxU32 adapters_num = 0;
int i = 0;
struct mfx_disp_adapters* adapters = NULL;
struct dirent** dir_entries = NULL;
int entries_num = scandir(MFX_PCI_DIR, &dir_entries, mfx_dir_filter, (fsort)alphasort);
char file_name[300] = {};
char str[16] = {0};
FILE* file = NULL;
for (i = 0; i < entries_num; ++i) {
if (!dir_entries[i]) continue;
// obtaining device class id
snprintf(file_name, sizeof(file_name) / sizeof(file_name[0]), "%s/%s/%s", MFX_PCI_DIR, dir_entries[i]->d_name,
"class");
file = fopen(file_name, "r");
if (file) {
long int class_id = 0;
if (fgets(str, sizeof(str), file)) {
class_id = strtol(str, NULL, 16);
}
fclose(file);
if (MFX_PCI_DISPLAY_CONTROLLER_CLASS == (class_id >> 16)) {
long int device_id = 0;
long int vendor_id = 0;
// obtaining device vendor id
snprintf(file_name, sizeof(file_name) / sizeof(file_name[0]), "%s/%s/%s", MFX_PCI_DIR, dir_entries[i]->d_name,
"vendor");
file = fopen(file_name, "r");
if (file) {
if (fgets(str, sizeof(str), file)) {
vendor_id = strtol(str, NULL, 16);
}
fclose(file);
}
// obtaining device id
snprintf(file_name, sizeof(file_name) / sizeof(file_name[0]), "%s/%s/%s", MFX_PCI_DIR, dir_entries[i]->d_name,
"device");
file = fopen(file_name, "r");
if (file) {
if (fgets(str, sizeof(str), file)) {
device_id = strtol(str, NULL, 16);
}
fclose(file);
}
// adding valid adapter to the list
if (vendor_id && device_id) {
struct mfx_disp_adapters* tmp_adapters = reinterpret_cast<mfx_disp_adapters*>(
realloc(adapters, (adapters_num + 1) * sizeof(struct mfx_disp_adapters)));
if (tmp_adapters) {
adapters = tmp_adapters;
adapters[adapters_num].vendor_id = vendor_id;
adapters[adapters_num].device_id = device_id;
++adapters_num;
}
}
}
}
free(dir_entries[i]);
}
if (entries_num) free(dir_entries);
if (p_adapters) *p_adapters = adapters;
return adapters_num;
}
DRMLibVA::DRMLibVA(void) : m_fd(-1) {
const mfxU32 IntelVendorID = 0x8086;
// the first Intel adapter is only required now, the second - in the future
const mfxU32 numberOfRequiredIntelAdapter = 1;
const char nodesNames[][8] = {"renderD", "card"};
VAStatus va_res = VA_STATUS_SUCCESS;
mfxStatus sts = MFX_ERR_NONE;
int major_version = 0, minor_version = 0;
mfx_disp_adapters* adapters = NULL;
int adapters_num = mfx_init_adapters(&adapters);
// Search for the required display adapter
int i = 0, nFoundAdapters = 0;
int nodesNumbers[] = {0, 0};
while ((i < adapters_num) && (nFoundAdapters != numberOfRequiredIntelAdapter)) {
if (adapters[i].vendor_id == IntelVendorID) {
nFoundAdapters++;
nodesNumbers[0] = i + 128; // for render nodes
nodesNumbers[1] = i; // for card
}
i++;
}
if (adapters_num) free(adapters);
// If Intel adapter with specified number wasn't found, throws exception
if (nFoundAdapters != numberOfRequiredIntelAdapter)
throw std::range_error("The Intel adapter with a specified number wasn't found");
// Initialization of paths to the device nodes
char** adapterPaths = new char*[2];
for (int i = 0; i < 2; i++) {
adapterPaths[i] = new char[sizeof(MFX_DRI_DIR) + sizeof(nodesNames[i]) + 3];
sprintf(adapterPaths[i], "%s%s%d", MFX_DRI_DIR, nodesNames[i], nodesNumbers[i]);
}
// Loading display. At first trying to open render nodes, then card.
for (int i = 0; i < 2; i++) {
sts = MFX_ERR_NONE;
m_fd = open(adapterPaths[i], O_RDWR);
if (m_fd < 0) sts = MFX_ERR_NOT_INITIALIZED;
if (MFX_ERR_NONE == sts) {
m_va_dpy = vaGetDisplayDRM(m_fd);
if (!m_va_dpy) {
close(m_fd);
sts = MFX_ERR_NULL_PTR;
}
}
if (MFX_ERR_NONE == sts) {
va_res = vaInitialize(m_va_dpy, &major_version, &minor_version);
sts = va_to_mfx_status(va_res);
if (MFX_ERR_NONE != sts) {
close(m_fd);
m_fd = -1;
}
}
if (MFX_ERR_NONE == sts) break;
}
for (int i = 0; i < 2; i++) {
delete[] adapterPaths[i];
}
delete[] adapterPaths;
if (MFX_ERR_NONE != sts) throw std::invalid_argument("Loading of VA display was failed");
}
DRMLibVA::~DRMLibVA(void) {
if (m_va_dpy) {
vaTerminate(m_va_dpy);
}
if (m_fd >= 0) {
close(m_fd);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment