This commit is contained in:
mofeng-git
2025-12-28 18:19:16 +08:00
commit d143d158e4
771 changed files with 220548 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
//
// Notice Regarding Standards. AMD does not provide a license or sublicense to
// any Intellectual Property Rights relating to any standards, including but not
// limited to any audio and/or video codec technologies such as MPEG-2, MPEG-4;
// AVC/H.264; HEVC/H.265; AAC decode/FFMPEG; AAC encode/FFMPEG; VC-1; and MP3
// (collectively, the "Media Technologies"). For clarity, you will pay any
// royalties due for such third party technologies, which may include the Media
// Technologies that are owed as a result of AMD providing the Software to you.
//
// MIT license
//
// Copyright (c) 2018 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///-------------------------------------------------------------------------
/// @file PulseAudioImprotTable.cpp
/// @brief pulseaudio import table
///-------------------------------------------------------------------------
#include "CairoImportTable.h"
#include "public/common/TraceAdapter.h"
#include "../Thread.h"
using namespace amf;
#define GET_SO_ENTRYPOINT(m, h, f) m = reinterpret_cast<decltype(&f)>(amf_get_proc_address(h, #f)); \
AMF_RETURN_IF_FALSE(nullptr != m, AMF_FAIL, L"Failed to acquire entrypoint %S", #f);
//-------------------------------------------------------------------------------------------------
CairoImportTable::CairoImportTable()
{}
//-------------------------------------------------------------------------------------------------
CairoImportTable::~CairoImportTable()
{
UnloadFunctionsTable();
}
//-------------------------------------------------------------------------------------------------
AMF_RESULT CairoImportTable::LoadFunctionsTable()
{
if (nullptr == m_hLibCairoSO)
{
m_hLibCairoSO = amf_load_library(L"libcairo.so.2");
AMF_RETURN_IF_FALSE(nullptr != m_hLibCairoSO, AMF_FAIL, L"Failed to load libcairo.so.2");
}
GET_SO_ENTRYPOINT(m_cairo_image_surface_create_from_png_stream, m_hLibCairoSO, cairo_image_surface_create_from_png_stream);
GET_SO_ENTRYPOINT(m_cairo_surface_destroy, m_hLibCairoSO, cairo_surface_destroy);
GET_SO_ENTRYPOINT(m_cairo_image_surface_get_width, m_hLibCairoSO, cairo_image_surface_get_width);
GET_SO_ENTRYPOINT(m_cairo_image_surface_get_height, m_hLibCairoSO, cairo_image_surface_get_height);
GET_SO_ENTRYPOINT(m_cairo_image_surface_get_stride, m_hLibCairoSO, cairo_image_surface_get_stride);
GET_SO_ENTRYPOINT(m_cairo_image_surface_get_format, m_hLibCairoSO, cairo_image_surface_get_format);
GET_SO_ENTRYPOINT(m_cairo_image_surface_get_data, m_hLibCairoSO, cairo_image_surface_get_data);
return AMF_OK;
}
void CairoImportTable::UnloadFunctionsTable()
{
if (nullptr != m_hLibCairoSO)
{
amf_free_library(m_hLibCairoSO);
m_hLibCairoSO = nullptr;
}
m_cairo_image_surface_create_from_png_stream = nullptr;
m_cairo_surface_destroy = nullptr;
m_cairo_image_surface_get_width = nullptr;
m_cairo_image_surface_get_height = nullptr;
m_cairo_image_surface_get_stride = nullptr;
m_cairo_image_surface_get_format = nullptr;
m_cairo_image_surface_get_data = nullptr;
}

View File

@@ -0,0 +1,63 @@
//
// Notice Regarding Standards. AMD does not provide a license or sublicense to
// any Intellectual Property Rights relating to any standards, including but not
// limited to any audio and/or video codec technologies such as MPEG-2, MPEG-4;
// AVC/H.264; HEVC/H.265; AAC decode/FFMPEG; AAC encode/FFMPEG; VC-1; and MP3
// (collectively, the "Media Technologies"). For clarity, you will pay any
// royalties due for such third party technologies, which may include the Media
// Technologies that are owed as a result of AMD providing the Software to you.
//
// MIT license
//
// Copyright (c) 2018 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///-------------------------------------------------------------------------
/// @file CairoImportTable.h
/// @brief Cairo import table
///-------------------------------------------------------------------------
#pragma once
#include "../../include/core/Result.h"
#include <memory>
#include <cairo.h>
struct CairoImportTable{
CairoImportTable();
~CairoImportTable();
AMF_RESULT LoadFunctionsTable();
void UnloadFunctionsTable();
decltype(&cairo_image_surface_create_from_png_stream) m_cairo_image_surface_create_from_png_stream = nullptr;
decltype(&cairo_surface_destroy) m_cairo_surface_destroy = nullptr;
decltype(&cairo_image_surface_get_width) m_cairo_image_surface_get_width = nullptr;
decltype(&cairo_image_surface_get_height) m_cairo_image_surface_get_height = nullptr;
decltype(&cairo_image_surface_get_stride) m_cairo_image_surface_get_stride = nullptr;
decltype(&cairo_image_surface_get_format) m_cairo_image_surface_get_format = nullptr;
decltype(&cairo_image_surface_get_data) m_cairo_image_surface_get_data = nullptr;
amf_handle m_hLibCairoSO = nullptr;
};
typedef std::shared_ptr<CairoImportTable> CairoImportTablePtr;

View File

@@ -0,0 +1,309 @@
//
// Notice Regarding Standards. AMD does not provide a license or sublicense to
// any Intellectual Property Rights relating to any standards, including but not
// limited to any audio and/or video codec technologies such as MPEG-2, MPEG-4;
// AVC/H.264; HEVC/H.265; AAC decode/FFMPEG; AAC encode/FFMPEG; VC-1; AV1; and MP3
// (collectively, the "Media Technologies"). For clarity, you will pay any
// royalties due for such third party technologies, which may include the Media
// Technologies that are owed as a result of AMD providing the Software to you.
//
// MIT license
//
// Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#include "DRMDevice.h"
#include <drm.h>
#include <drm_fourcc.h>
#include <drm_mode.h>
#include <amdgpu_drm.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#define AMF_FACILITY L"DRMDevice"
struct FormatMapEntry
{
amf::AMF_SURFACE_FORMAT formatAMF;
uint32_t formatDRM;
};
static const FormatMapEntry formatMap [] =
{
#ifdef DRM_FORMAT_R8
{ amf::AMF_SURFACE_GRAY8, DRM_FORMAT_R8 },
#endif
#ifdef DRM_FORMAT_R16
// { , DRM_FORMAT_R16 },
// { , DRM_FORMAT_R16 | DRM_FORMAT_BIG_ENDIAN },
#endif
// { , DRM_FORMAT_BGR233 },
// { , DRM_FORMAT_XRGB1555 },
// { , DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN },
// { , DRM_FORMAT_XBGR1555 },
// { , DRM_FORMAT_XBGR1555 | DRM_FORMAT_BIG_ENDIAN },
// { , DRM_FORMAT_RGB565 },
// { , DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN },
// { , DRM_FORMAT_BGR565 },
// { , DRM_FORMAT_BGR565 | DRM_FORMAT_BIG_ENDIAN },
// { , DRM_FORMAT_RGB888 },
// { , DRM_FORMAT_BGR888 },
{ amf::AMF_SURFACE_BGRA, DRM_FORMAT_BGRX8888 },
{ amf::AMF_SURFACE_RGBA, DRM_FORMAT_RGBX8888 },
{ amf::AMF_SURFACE_BGRA, DRM_FORMAT_XBGR8888 },
{ amf::AMF_SURFACE_BGRA /*AMF_SURFACE_ARGB*/, DRM_FORMAT_XRGB8888 },
{ amf::AMF_SURFACE_RGBA, DRM_FORMAT_BGRA8888 },
{ amf::AMF_SURFACE_ARGB, DRM_FORMAT_ARGB8888 },
{ amf::AMF_SURFACE_YUY2, DRM_FORMAT_YUYV },
// { , DRM_FORMAT_YVYU },
{ amf::AMF_SURFACE_UYVY, DRM_FORMAT_UYVY },
};
amf::AMF_SURFACE_FORMAT AMF_STD_CALL FromDRMtoAMF(uint32_t formatDRM)
{
for(int i = 0; i < amf_countof(formatMap); i++)
{
if(formatMap[i].formatDRM == formatDRM)
{
return formatMap[i].formatAMF;
}
}
return amf::AMF_SURFACE_UNKNOWN;
}
drmModeFB2Ptr AMF_STD_CALL AMFdrmModeGetFB2(int fd, uint32_t fb_id)
{
struct drm_mode_fb_cmd2 get = {
.fb_id = fb_id,
};
drmModeFB2Ptr ret;
int err;
err = drmIoctl(fd, DRM_IOCTL_MODE_GETFB2, &get);
if (err != 0)
return NULL;
ret = (drmModeFB2Ptr)drmMalloc(sizeof(drmModeFB2));
if (!ret)
return NULL;
ret->fb_id = fb_id;
ret->width = get.width;
ret->height = get.height;
ret->pixel_format = get.pixel_format;
ret->flags = get.flags;
ret->modifier = get.modifier[0];
memcpy(ret->handles, get.handles, sizeof(uint32_t) * 4);
memcpy(ret->pitches, get.pitches, sizeof(uint32_t) * 4);
memcpy(ret->offsets, get.offsets, sizeof(uint32_t) * 4);
return ret;
}
void AMF_STD_CALL AMFdrmModeFreeFB2(drmModeFB2Ptr ptr)
{
drmFree(ptr);
}
DRMDevice::DRMDevice() {}
DRMDevice::~DRMDevice()
{
Terminate();
}
AMF_RESULT AMF_STD_CALL DRMDevice::InitFromVulkan(int pciDomain, int pciBus, int pciDevice, int pciFunction)
{
int dirfd = open("/dev/dri/by-path", O_RDONLY);
AMF_RETURN_IF_FALSE(dirfd != -1, AMF_FAIL, L"Couldn't open /dev/dri/by-path")
DIR *pDir = fdopendir(dirfd);
if (pDir == nullptr)
{
close(dirfd);
return AMF_FAIL;
}
struct dirent *entry;
while ((entry = readdir(pDir)) != NULL)
{
int entryDomain = -1, entryBus = -1, entryDevice = -1, entryFunction = -1, length = -1;
int res = sscanf(entry->d_name, "pci-%x:%x:%x.%x-card%n",
&entryDomain, &entryBus, &entryDevice, &entryFunction, &length);
//check if matches pattern
if (res != 4 || length != strlen(entry->d_name))
{
continue;
}
if (entryDomain == pciDomain && entryBus == pciBus && entryDevice == pciDevice && entryFunction == pciFunction)
{
m_fd = openat(dirfd, entry->d_name, O_RDWR | O_CLOEXEC);
m_pathToCard = entry->d_name;
break;
}
}
closedir(pDir); //implicitly closes dirfd
if (m_fd < 0)
{
return AMF_FAIL;
}
return SetupDevice();
}
AMF_RESULT AMF_STD_CALL DRMDevice::InitFromPath(const char* pathToCard)
{
m_fd = open(pathToCard, O_RDWR | O_CLOEXEC);
m_pathToCard = pathToCard;
if (m_fd < 0)
{
return AMF_FAIL;
}
return SetupDevice();
}
AMF_RESULT DRMDevice::SetupDevice()
{
drmVersionPtr version = drmGetVersion(m_fd);
AMF_RETURN_IF_FALSE(version != nullptr, AMF_FAIL, L"drmGetVersion() failed from %S", m_pathToCard.c_str());
AMFTraceDebug(AMF_FACILITY, L"Opened DRM device %S: driver name %S version %d.%d.%d", m_pathToCard.c_str(), version->name,
version->version_major, version->version_minor, version->version_patchlevel);
drmFreeVersion(version);
uint64_t valueExport = 0;
int err = drmGetCap(m_fd, DRM_PRIME_CAP_EXPORT, &valueExport);
err = drmSetClientCap(m_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
if (err < 0)
{
AMFTraceWarning(AMF_FACILITY, L"drmSetClientCap(DRM_CLIENT_CAP_UNIVERSAL_PLANES) Failed with %d", err);
}
drmSetClientCap(m_fd, DRM_CLIENT_CAP_ATOMIC, 1);
return AMF_OK;
}
AMF_RESULT AMF_STD_CALL DRMDevice::Terminate()
{
if (m_fd >= 0)
{
close(m_fd);
m_fd = -1;
}
m_pathToCard = "";
return AMF_OK;
}
int AMF_STD_CALL DRMDevice::GetFD() const
{
return m_fd;
}
std::string AMF_STD_CALL DRMDevice::GetPathToCard() const
{
return m_pathToCard;
}
AMF_RESULT AMF_STD_CALL DRMDevice::GetCRTCs(std::vector<DRMCRTC>& crtcs) const
{
AMF_RETURN_IF_FALSE(m_fd >= 0, AMF_FAIL, L"Not Initialized");
AMFdrmModeResPtr resources = drmModeGetResources(m_fd);
AMF_RETURN_IF_FALSE(resources.p != nullptr, AMF_FAIL, L"drmModeGetResources() return nullptr");
crtcs.clear();
for(int i = 0; i < resources.p->count_crtcs; i ++)
{
AMFdrmModeCrtcPtr crtc = drmModeGetCrtc(m_fd, resources.p->crtcs[i]);
AMFRect crop = {};
amf::AMF_SURFACE_FORMAT formatAMF = amf::AMF_SURFACE_UNKNOWN;
int formatDRM = 0;
int handle = 0;
if(GetCrtcInfo(crtc, crop, formatDRM, formatAMF, handle) != AMF_OK)
{
continue;
}
AMFTraceDebug(AMF_FACILITY, L" CRTC id=%d fb=%d crop(%d,%d,%d,%d)", crtc.p->crtc_id, crtc.p->buffer_id, crop.left, crop.top, crop.right, crop.bottom);
DRMCRTC drmCrtc = {};
drmCrtc.crtcID = crtc.p->crtc_id;
drmCrtc.fbID = crtc.p->buffer_id;
drmCrtc.crop = crop;
drmCrtc.formatDRM = formatDRM;
drmCrtc.formatAMF = formatAMF;
drmCrtc.handle = handle;
crtcs.push_back(drmCrtc);
}
return AMF_OK;
}
AMF_RESULT AMF_STD_CALL DRMDevice::GetCrtcInfo(const AMFdrmModeCrtcPtr& crtc, AMFRect &crop, int& formatDRM, amf::AMF_SURFACE_FORMAT& formatAMF, int& handle) const
{
if(crtc.p == nullptr)
{
return AMF_FAIL;
}
if(crtc.p->buffer_id == 0)
{
return AMF_FAIL;
}
// check if active
AMFdrmModeObjectPropertiesPtr properties = drmModeObjectGetProperties (m_fd, crtc.p->crtc_id, DRM_MODE_OBJECT_CRTC);
if(properties.p == nullptr)
{
return AMF_FAIL;
}
for(int k = 0; k < properties.p->count_props; k++)
{
AMFdrmModePropertyPtr prop = drmModeGetProperty(m_fd, properties.p->props[k]);
if(std::string(prop.p->name) == "ACTIVE" && properties.p->prop_values[k] == 0)
{
return AMF_FAIL;
}
}
// check FB
AMFdrmModeFB2Ptr fb2 = AMFdrmModeGetFB2(m_fd, crtc.p->buffer_id);
if(fb2.p == nullptr)
{
return AMF_FAIL;
}
crop.left = crtc.p->x;
crop.top = crtc.p->y;
crop.right = crtc.p->x + crtc.p->width;
crop.bottom = crtc.p->y + crtc.p->height;
formatDRM = fb2.p->pixel_format;
formatAMF= FromDRMtoAMF(fb2.p->pixel_format);
handle = fb2.p->handles[0];
return AMF_OK;
}

View File

@@ -0,0 +1,123 @@
//
// Notice Regarding Standards. AMD does not provide a license or sublicense to
// any Intellectual Property Rights relating to any standards, including but not
// limited to any audio and/or video codec technologies such as MPEG-2, MPEG-4;
// AVC/H.264; HEVC/H.265; AAC decode/FFMPEG; AAC encode/FFMPEG; VC-1; AV1; and MP3
// (collectively, the "Media Technologies"). For clarity, you will pay any
// royalties due for such third party technologies, which may include the Media
// Technologies that are owed as a result of AMD providing the Software to you.
//
// MIT license
//
// Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#pragma once
#include <string>
#include <vector>
#include "public/common/TraceAdapter.h"
#include "public/include/core/Surface.h"
#include <drm.h>
#include <drm_fourcc.h>
#include <drm_mode.h>
#include <amdgpu_drm.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
// These classed provide a nice interface to a DRM card using libdrm
amf::AMF_SURFACE_FORMAT AMF_STD_CALL FromDRMtoAMF(uint32_t formatDRM);
drmModeFB2Ptr AMF_STD_CALL AMFdrmModeGetFB2(int fd, uint32_t fb_id);
void AMF_STD_CALL AMFdrmModeFreeFB2(drmModeFB2Ptr ptr);
template <class type, void function(type)>
class AMFAutoDRMPtr
{
public:
AMFAutoDRMPtr() : p(nullptr){}
AMFAutoDRMPtr(type ptr) : p(ptr){}
~AMFAutoDRMPtr()
{
Clear();
}
AMFAutoDRMPtr<type, function>& operator=(type ptr)
{
if(p != ptr)
{
Clear();
p = ptr;
}
return *this;
}
void Clear()
{
if(p != nullptr)
{
function(p);
p = nullptr;
}
}
type p;
private:
AMFAutoDRMPtr<type, function>& operator=(const AMFAutoDRMPtr<type, function>& other);
};
typedef AMFAutoDRMPtr<drmModePlanePtr, drmModeFreePlane> AMFdrmModePlanePtr;
typedef AMFAutoDRMPtr<drmModeFBPtr, drmModeFreeFB> AMFdrmModeFBPtr;
typedef AMFAutoDRMPtr<drmModeFB2Ptr, AMFdrmModeFreeFB2> AMFdrmModeFB2Ptr;
typedef AMFAutoDRMPtr<drmModePlaneResPtr, drmModeFreePlaneResources> AMFdrmModePlaneResPtr;
typedef AMFAutoDRMPtr<drmModeObjectPropertiesPtr, drmModeFreeObjectProperties> AMFdrmModeObjectPropertiesPtr;
typedef AMFAutoDRMPtr<drmModePropertyPtr, drmModeFreeProperty> AMFdrmModePropertyPtr;
typedef AMFAutoDRMPtr<drmModeCrtcPtr, drmModeFreeCrtc> AMFdrmModeCrtcPtr;
typedef AMFAutoDRMPtr<drmModeResPtr, drmModeFreeResources> AMFdrmModeResPtr;
struct DRMCRTC {
int crtcID;
int fbID;
AMFRect crop;
int formatDRM;
amf::AMF_SURFACE_FORMAT formatAMF;
int handle;
};
class DRMDevice {
public:
DRMDevice();
~DRMDevice();
AMF_RESULT AMF_STD_CALL InitFromVulkan(int pciDomain, int pciBus, int pciDevice, int pciFunction);
AMF_RESULT AMF_STD_CALL InitFromPath(const char* pathToCard);
AMF_RESULT AMF_STD_CALL Terminate();
int AMF_STD_CALL GetFD() const;
std::string AMF_STD_CALL GetPathToCard() const;
AMF_RESULT AMF_STD_CALL GetCRTCs(std::vector<DRMCRTC>& crtcs) const;
AMF_RESULT AMF_STD_CALL GetCrtcInfo(const AMFdrmModeCrtcPtr& crtc, AMFRect &crop, int& formatDRM, amf::AMF_SURFACE_FORMAT& formatAMF, int& handle) const;
private:
AMF_RESULT SetupDevice();
int m_fd = -1;
std::string m_pathToCard;
};

View File

@@ -0,0 +1,155 @@
//
// Notice Regarding Standards. AMD does not provide a license or sublicense to
// any Intellectual Property Rights relating to any standards, including but not
// limited to any audio and/or video codec technologies such as MPEG-2, MPEG-4;
// AVC/H.264; HEVC/H.265; AAC decode/FFMPEG; AAC encode/FFMPEG; VC-1; and MP3
// (collectively, the "Media Technologies"). For clarity, you will pay any
// royalties due for such third party technologies, which may include the Media
// Technologies that are owed as a result of AMD providing the Software to you.
//
// MIT license
//
// Copyright (c) 2018 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///-------------------------------------------------------------------------
/// @file PulseAudioImprotTable.cpp
/// @brief pulseaudio import table
///-------------------------------------------------------------------------
#include "PulseAudioImportTable.h"
#include "public/common/TraceAdapter.h"
#include "../Thread.h"
using namespace amf;
#define GET_SO_ENTRYPOINT(m, h, f) m = reinterpret_cast<decltype(&f)>(amf_get_proc_address(h, #f)); \
AMF_RETURN_IF_FALSE(nullptr != m, AMF_FAIL, L"Failed to acquire entrypoint %S", #f);
//-------------------------------------------------------------------------------------------------
PulseAudioImportTable::PulseAudioImportTable()
{}
//-------------------------------------------------------------------------------------------------
PulseAudioImportTable::~PulseAudioImportTable()
{
UnloadFunctionsTable();
}
//-------------------------------------------------------------------------------------------------
AMF_RESULT PulseAudioImportTable::LoadFunctionsTable()
{
// Load pulseaudio simple api shared library and pulseaudio shared library.
if (nullptr == m_hLibPulseSimpleSO)
{
m_hLibPulseSimpleSO = amf_load_library(L"libpulse-simple.so.0");
AMF_RETURN_IF_FALSE(nullptr != m_hLibPulseSimpleSO, AMF_FAIL, L"Failed to load libpulse-simple.so.0");
}
if (nullptr == m_hLibPulseSO)
{
m_hLibPulseSO = amf_load_library(L"libpulse.so.0");
AMF_RETURN_IF_FALSE(nullptr != m_hLibPulseSO, AMF_FAIL, L"Failed to load libpulse.so.0");
}
// Load pulseaudio mainloop functions.
GET_SO_ENTRYPOINT(m_pPA_Mainloop_Free, m_hLibPulseSO, pa_mainloop_free);
GET_SO_ENTRYPOINT(m_pPA_Mainloop_New, m_hLibPulseSO, pa_mainloop_new);
GET_SO_ENTRYPOINT(m_pPA_Mainloop_Quit, m_hLibPulseSO, pa_mainloop_quit);
GET_SO_ENTRYPOINT(m_pPA_Mainloop_Get_API, m_hLibPulseSO, pa_mainloop_get_api);
GET_SO_ENTRYPOINT(m_pPA_Mainloop_Run, m_hLibPulseSO, pa_mainloop_run);
// Load pulseaudio context functions.
GET_SO_ENTRYPOINT(m_pPA_Context_Unref, m_hLibPulseSO, pa_context_unref);
GET_SO_ENTRYPOINT(m_pPA_Context_Load_Module, m_hLibPulseSO, pa_context_load_module);
GET_SO_ENTRYPOINT(m_pPA_Context_Unload_Module, m_hLibPulseSO, pa_context_unload_module);
GET_SO_ENTRYPOINT(m_pPA_Context_New, m_hLibPulseSO, pa_context_new);
GET_SO_ENTRYPOINT(m_pPA_Context_Get_State, m_hLibPulseSO, pa_context_get_state);
GET_SO_ENTRYPOINT(m_pPA_Context_Set_State_Callback, m_hLibPulseSO, pa_context_set_state_callback);
GET_SO_ENTRYPOINT(m_pPA_Context_Get_Server_Info, m_hLibPulseSO, pa_context_get_server_info);
GET_SO_ENTRYPOINT(m_pPA_Context_Connect, m_hLibPulseSO, pa_context_connect);
GET_SO_ENTRYPOINT(m_pPA_Context_Disconnect, m_hLibPulseSO, pa_context_disconnect);
GET_SO_ENTRYPOINT(m_pPA_Context_Get_Sink_Info_By_Name, m_hLibPulseSO, pa_context_get_sink_info_by_name);
GET_SO_ENTRYPOINT(m_pPA_Context_Get_Sink_Info_List, m_hLibPulseSO, pa_context_get_sink_info_list);
GET_SO_ENTRYPOINT(m_pPA_Context_Get_Source_Info_List, m_hLibPulseSO, pa_context_get_source_info_list);
// Load other pulse audio functions.
GET_SO_ENTRYPOINT(m_pPA_Operation_Unref, m_hLibPulseSO, pa_operation_unref);
GET_SO_ENTRYPOINT(m_pPA_Strerror, m_hLibPulseSO, pa_strerror);
// Load pulse audio simple api functions.
GET_SO_ENTRYPOINT(m_pPA_Simple_New, m_hLibPulseSimpleSO, pa_simple_new);
GET_SO_ENTRYPOINT(m_pPA_Simple_Free, m_hLibPulseSimpleSO, pa_simple_free);
GET_SO_ENTRYPOINT(m_pPA_Simple_Write, m_hLibPulseSimpleSO, pa_simple_write);
GET_SO_ENTRYPOINT(m_pPA_Simple_Read, m_hLibPulseSimpleSO, pa_simple_read);
GET_SO_ENTRYPOINT(m_pPA_Simple_Flush, m_hLibPulseSimpleSO, pa_simple_flush);
GET_SO_ENTRYPOINT(m_pPA_Simple_Get_Latency, m_hLibPulseSimpleSO, pa_simple_get_latency);
return AMF_OK;
}
void PulseAudioImportTable::UnloadFunctionsTable()
{
if (nullptr != m_hLibPulseSimpleSO)
{
amf_free_library(m_hLibPulseSimpleSO);
m_hLibPulseSO = nullptr;
}
if (nullptr != m_hLibPulseSO)
{
amf_free_library(m_hLibPulseSO);
m_hLibPulseSO = nullptr;
}
m_pPA_Mainloop_Free = nullptr;
m_pPA_Mainloop_Quit = nullptr;
m_pPA_Mainloop_New = nullptr;
m_pPA_Mainloop_Get_API = nullptr;
m_pPA_Mainloop_Run = nullptr;
// Context functions.
m_pPA_Context_Unref = nullptr;
m_pPA_Context_Load_Module = nullptr;
m_pPA_Context_Unload_Module = nullptr;
m_pPA_Context_New = nullptr;
m_pPA_Context_Get_State = nullptr;
m_pPA_Context_Set_State_Callback = nullptr;
m_pPA_Context_Get_Server_Info = nullptr;
m_pPA_Context_Connect = nullptr;
m_pPA_Context_Disconnect = nullptr;
m_pPA_Context_Get_Sink_Info_By_Name = nullptr;
m_pPA_Context_Get_Sink_Info_List = nullptr;
m_pPA_Context_Get_Source_Info_List = nullptr;
// Others
m_pPA_Operation_Unref = nullptr;
m_pPA_Strerror = nullptr;
// PulseAudio Simple API functions.
m_pPA_Simple_New = nullptr;
m_pPA_Simple_Free = nullptr;
m_pPA_Simple_Write = nullptr;
m_pPA_Simple_Read = nullptr;
m_pPA_Simple_Flush = nullptr;
m_pPA_Simple_Get_Latency = nullptr;
}

View File

@@ -0,0 +1,91 @@
//
// Notice Regarding Standards. AMD does not provide a license or sublicense to
// any Intellectual Property Rights relating to any standards, including but not
// limited to any audio and/or video codec technologies such as MPEG-2, MPEG-4;
// AVC/H.264; HEVC/H.265; AAC decode/FFMPEG; AAC encode/FFMPEG; VC-1; and MP3
// (collectively, the "Media Technologies"). For clarity, you will pay any
// royalties due for such third party technologies, which may include the Media
// Technologies that are owed as a result of AMD providing the Software to you.
//
// MIT license
//
// Copyright (c) 2018 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///-------------------------------------------------------------------------
/// @file PulseAudioImportTable.h
/// @brief pulseaudio import table
///-------------------------------------------------------------------------
#pragma once
#include "../../include/core/Result.h"
#include <memory>
#include <pulse/simple.h>
#include <pulse/pulseaudio.h>
struct PulseAudioImportTable{
PulseAudioImportTable();
~PulseAudioImportTable();
AMF_RESULT LoadFunctionsTable();
void UnloadFunctionsTable();
// PulseAudio functions.
// Mainloop functions.
decltype(&pa_mainloop_free) m_pPA_Mainloop_Free = nullptr;
decltype(&pa_mainloop_quit) m_pPA_Mainloop_Quit = nullptr;
decltype(&pa_mainloop_new) m_pPA_Mainloop_New = nullptr;
decltype(&pa_mainloop_get_api) m_pPA_Mainloop_Get_API = nullptr;
decltype(&pa_mainloop_run) m_pPA_Mainloop_Run = nullptr;
// Context functions.
decltype(&pa_context_unref) m_pPA_Context_Unref = nullptr;
decltype(&pa_context_load_module) m_pPA_Context_Load_Module = nullptr;
decltype(&pa_context_unload_module) m_pPA_Context_Unload_Module = nullptr;
decltype(&pa_context_new) m_pPA_Context_New = nullptr;
decltype(&pa_context_get_state) m_pPA_Context_Get_State = nullptr;
decltype(&pa_context_set_state_callback) m_pPA_Context_Set_State_Callback = nullptr;
decltype(&pa_context_get_server_info) m_pPA_Context_Get_Server_Info = nullptr;
decltype(&pa_context_connect) m_pPA_Context_Connect = nullptr;
decltype(&pa_context_disconnect) m_pPA_Context_Disconnect = nullptr;
decltype(&pa_context_get_sink_info_by_name) m_pPA_Context_Get_Sink_Info_By_Name = nullptr;
decltype(&pa_context_get_sink_info_list) m_pPA_Context_Get_Sink_Info_List = nullptr;
decltype(&pa_context_get_source_info_list) m_pPA_Context_Get_Source_Info_List = nullptr;
// Others
decltype(&pa_operation_unref) m_pPA_Operation_Unref = nullptr;
decltype(&pa_strerror) m_pPA_Strerror = nullptr;
// PulseAudio Simple API functions.
decltype(&pa_simple_new) m_pPA_Simple_New = nullptr;
decltype(&pa_simple_free) m_pPA_Simple_Free = nullptr;
decltype(&pa_simple_write) m_pPA_Simple_Write = nullptr;
decltype(&pa_simple_read) m_pPA_Simple_Read = nullptr;
decltype(&pa_simple_flush) m_pPA_Simple_Flush = nullptr;
decltype(&pa_simple_get_latency) m_pPA_Simple_Get_Latency = nullptr;
amf_handle m_hLibPulseSO = nullptr;
amf_handle m_hLibPulseSimpleSO = nullptr;
};
typedef std::shared_ptr<PulseAudioImportTable> PulseAudioImportTablePtr;

View File

@@ -0,0 +1,757 @@
//
// Notice Regarding Standards. AMD does not provide a license or sublicense to
// any Intellectual Property Rights relating to any standards, including but not
// limited to any audio and/or video codec technologies such as MPEG-2, MPEG-4;
// AVC/H.264; HEVC/H.265; AAC decode/FFMPEG; AAC encode/FFMPEG; VC-1; and MP3
// (collectively, the "Media Technologies"). For clarity, you will pay any
// royalties due for such third party technologies, which may include the Media
// Technologies that are owed as a result of AMD providing the Software to you.
//
// MIT license
//
// Copyright (c) 2018 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#include "../Thread.h"
#if defined (__linux) || (__APPLE__)
#if defined(__GNUC__)
//disable gcc warinings on STL code
#pragma GCC diagnostic ignored "-Weffc++"
#endif
#define POSIX
#include <locale>
#include <algorithm>
#include <dirent.h>
#include <fnmatch.h>
#include <pwd.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <sys/time.h>
#include <fstream>
#if !defined(__APPLE__)
#include <malloc.h>
#endif
#if defined(__ANDROID__)
#include <android/log.h>
#endif
#include <sys/types.h>
#include <semaphore.h>
#include <pthread.h>
#include "../AMFSTL.h"
using namespace amf;
extern "C" void AMF_STD_CALL amf_debug_trace(const wchar_t* text);
void perror(const char* errorModule)
{
char buf[128];
#if defined(__ANDROID__) || (__APPLE__)
strerror_r(errno, buf, sizeof(buf));
fprintf(stderr, "%s: %s", buf, errorModule);
#else
char* err = strerror_r(errno, buf, sizeof(buf));
fprintf(stderr, "%s: %s", err, errorModule);
#endif
exit(1);
}
#if defined(__APPLE__)
amf_uint64 AMF_STD_CALL get_current_thread_id()
{
return reinterpret_cast<amf_uint64>(pthread_self());
}
#else
amf_uint32 AMF_STD_CALL get_current_thread_id()
{
return static_cast<amf_uint32>(pthread_self());
}
#endif
// int clock_gettime(clockid_t clk_id, struct timespec *tp);
//----------------------------------------------------------------------------------------
// threading
//----------------------------------------------------------------------------------------
amf_long AMF_STD_CALL amf_atomic_inc(amf_long* X)
{
return __sync_add_and_fetch(X, 1);
}
//----------------------------------------------------------------------------------------
amf_long AMF_STD_CALL amf_atomic_dec(amf_long* X)
{
return __sync_sub_and_fetch(X, 1);
}
//----------------------------------------------------------------------------------------
amf_handle AMF_STD_CALL amf_create_critical_section()
{
pthread_mutex_t* mutex = new pthread_mutex_t;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(mutex, &attr);
return (amf_handle)mutex;
}
//----------------------------------------------------------------------------------------
bool AMF_STD_CALL amf_delete_critical_section(amf_handle cs)
{
if(cs == NULL)
{
return false;
}
pthread_mutex_t* mutex = (pthread_mutex_t*)cs;
int err = pthread_mutex_destroy(mutex);
delete mutex;
return err == 0;
}
//----------------------------------------------------------------------------------------
bool AMF_STD_CALL amf_enter_critical_section(amf_handle cs)
{
if(cs == NULL)
{
return false;
}
pthread_mutex_t* mutex = (pthread_mutex_t*)cs;
return pthread_mutex_lock(mutex) == 0;
}
//----------------------------------------------------------------------------------------
bool AMF_CDECL_CALL amf_wait_critical_section(amf_handle cs, amf_ulong ulTimeout)
{
if(cs == NULL)
{
return false;
}
return amf_wait_for_mutex(cs, ulTimeout);
}
//----------------------------------------------------------------------------------------
bool AMF_STD_CALL amf_leave_critical_section(amf_handle cs)
{
if(cs == NULL)
{
return false;
}
pthread_mutex_t* mutex = (pthread_mutex_t*)cs;
return pthread_mutex_unlock(mutex) == 0;
}
//----------------------------------------------------------------------------------------
struct MyEvent
{
bool m_manual_reset;
pthread_cond_t m_cond;
pthread_mutex_t m_mutex;
bool m_triggered;
};
//----------------------------------------------------------------------------------------
amf_handle AMF_STD_CALL amf_create_event(bool initially_owned, bool manual_reset, const wchar_t* name)
{
MyEvent* event = new MyEvent;
// Linux does not natively support Named Condition variables
// so raise an error.
// Implement this using boost (NamedCondition), Qt, or some other framework.
if(name != NULL)
{
perror("Named Events not supported under Linux yet");
exit(1);
}
event->m_manual_reset = manual_reset;
pthread_cond_t cond_tmp = PTHREAD_COND_INITIALIZER;
event->m_cond = cond_tmp;
pthread_mutex_t mutex_tmp = PTHREAD_MUTEX_INITIALIZER;
event->m_mutex = mutex_tmp;
event->m_triggered = false;
if(initially_owned)
{
amf_set_event((amf_handle)event);
}
return (amf_handle)event;
}
//----------------------------------------------------------------------------------------
bool AMF_STD_CALL amf_delete_event(amf_handle hevent)
{
if(hevent == NULL)
{
return false;
}
MyEvent* event = (MyEvent*)hevent;
int err1 = pthread_mutex_destroy(&event->m_mutex);
int err2 = pthread_cond_destroy(&event->m_cond);
delete event;
return err1 == 0 && err2 == 0;
}
//----------------------------------------------------------------------------------------
bool AMF_STD_CALL amf_set_event(amf_handle hevent)
{
if(hevent == NULL)
{
return false;
}
MyEvent* event = (MyEvent*)hevent;
pthread_mutex_lock(&event->m_mutex);
event->m_triggered = true;
int err1 = pthread_cond_broadcast(&event->m_cond);
pthread_mutex_unlock(&event->m_mutex);
return err1 == 0;
}
//----------------------------------------------------------------------------------------
bool AMF_STD_CALL amf_reset_event(amf_handle hevent)
{
if(hevent == NULL)
{
return false;
}
MyEvent* event = (MyEvent*)hevent;
pthread_mutex_lock(&event->m_mutex);
event->m_triggered = false;
int err = pthread_mutex_unlock(&event->m_mutex);
return err == 0;
}
//----------------------------------------------------------------------------------------
static bool AMF_STD_CALL amf_wait_for_event_int(amf_handle hevent, unsigned long timeout, bool bTimeoutErr)
{
if(hevent == NULL)
{
return false;
}
bool ret = true;
int err = 0;
MyEvent* event = (MyEvent*)hevent;
pthread_mutex_lock(&event->m_mutex);
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
amf_uint64 start_time = ((amf_uint64)ts.tv_sec) * 1000 + ((amf_uint64)ts.tv_nsec) / 1000000; //to msec
if(event->m_manual_reset)
{
while(!event->m_triggered)
{
if(timeout == AMF_INFINITE)
{
err = pthread_cond_wait(&event->m_cond, &event->m_mutex); //MM todo - timeout is not supported
ret = err == 0;
}
else
{
clock_gettime(CLOCK_REALTIME, &ts);
amf_uint64 current_time = ((amf_uint64)ts.tv_sec) * 1000 + ((amf_uint64)ts.tv_nsec) / 1000000; //to msec
if(current_time - start_time > (amf_uint64)timeout)
{
ret = bTimeoutErr ? false : true;
break;
}
amf_uint64 to_wait = start_time + timeout;
timespec abstime;
abstime.tv_sec = (time_t)(to_wait / 1000); // timeout is in millisec
abstime.tv_nsec = (time_t)((to_wait - ((amf_uint64)abstime.tv_sec) * 1000) * 1000000); // the rest to nanosec
err = pthread_cond_timedwait(&event->m_cond, &event->m_mutex, &abstime);
ret = err == 0;
}
}
}
else
{
if(event->m_triggered)
{
ret = true;
}
else
{
if (timeout == AMF_INFINITE) {
err = pthread_cond_wait(&event->m_cond, &event->m_mutex);
} else {
start_time += timeout;
timespec abstime;
abstime.tv_sec = (time_t) (start_time / 1000); // timeout is in millisec
abstime.tv_nsec = (time_t) ((start_time - (amf_uint64) (abstime.tv_sec) * 1000) *
1000000); // the rest to nanosec
err = pthread_cond_timedwait(&event->m_cond, &event->m_mutex, &abstime);
}
if (bTimeoutErr) {
ret = (err == 0);
} else {
ret = (err == 0 || err == ETIMEDOUT);
}
}
if(ret == true)
{
event->m_triggered = false;
}
}
pthread_mutex_unlock(&event->m_mutex);
return ret;
}
//----------------------------------------------------------------------------------------
bool AMF_STD_CALL amf_wait_for_event(amf_handle hevent, unsigned long timeout)
{
return amf_wait_for_event_int(hevent, timeout, true);
}
//----------------------------------------------------------------------------------------
bool AMF_STD_CALL amf_wait_for_event_timeout(amf_handle hevent, amf_ulong ulTimeout)
{
return amf_wait_for_event_int(hevent, ulTimeout, false);
}
//----------------------------------------------------------------------------------------
amf_handle AMF_STD_CALL amf_create_mutex(bool initially_owned, const wchar_t* name)
{
pthread_mutex_t* mutex = new pthread_mutex_t;
pthread_mutex_t mutex_tmp = PTHREAD_MUTEX_INITIALIZER;
*mutex = mutex_tmp;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(mutex, &attr);
if(initially_owned)
{
pthread_mutex_lock(mutex);
}
return (amf_handle)mutex;
}
//----------------------------------------------------------------------------------------
amf_handle AMF_STD_CALL amf_open_mutex(const wchar_t* pName)
{
assert(false);
return 0;
}
//----------------------------------------------------------------------------------------
bool AMF_STD_CALL amf_delete_mutex(amf_handle hmutex)
{
if(hmutex == NULL)
{
return false;
}
pthread_mutex_t* mutex = (pthread_mutex_t*)hmutex;
int err = pthread_mutex_destroy(mutex);
delete mutex;
return err == 0;
}
//----------------------------------------------------------------------------------------
#if defined(__APPLE__)
int sem_timedwait1(sem_t* semaphore, const struct timespec* timeout)
{
struct timeval timenow;
struct timespec sleepytime;
int retcode;
/// This is just to avoid a completely busy wait
sleepytime.tv_sec = 0;
sleepytime.tv_nsec = 10000000; // 10ms
while((retcode = sem_trywait(semaphore)) != 0)
{
gettimeofday (&timenow, NULL);
if((timenow.tv_sec >= timeout->tv_sec) && ((timenow.tv_usec * 1000) >= timeout->tv_nsec))
{
return retcode;
}
nanosleep (&sleepytime, NULL);
}
return retcode;
}
#endif
#if defined(__ANDROID__) || defined(__APPLE__)
int pthread_mutex_timedlock1(pthread_mutex_t* mutex, const struct timespec* timeout)
{
struct timeval timenow;
struct timespec sleepytime;
int retcode;
/// This is just to avoid a completely busy wait
sleepytime.tv_sec = 0;
sleepytime.tv_nsec = 10000000; // 10ms
while((retcode = pthread_mutex_trylock (mutex)) == EBUSY)
{
gettimeofday (&timenow, NULL);
if((timenow.tv_sec >= timeout->tv_sec) && ((timenow.tv_usec * 1000) >= timeout->tv_nsec))
{
return ETIMEDOUT;
}
nanosleep (&sleepytime, NULL);
}
return retcode;
}
#endif
//----------------------------------------------------------------------------------------
bool AMF_STD_CALL amf_wait_for_mutex(amf_handle hmutex, unsigned long timeout)
{
if(hmutex == NULL)
{
return false;
}
pthread_mutex_t* mutex = (pthread_mutex_t*)hmutex;
if(timeout == AMF_INFINITE)
{
return pthread_mutex_lock(mutex) == 0;
}
// ulTimeout is in milliseconds
long timeout_sec = timeout / 1000; /* Seconds */;
long timeout_nsec = (timeout - (timeout / 1000) * 1000) * 1000000;
timespec wait_time; //absolute time
clock_gettime(CLOCK_REALTIME, &wait_time);
wait_time.tv_sec += timeout_sec;
wait_time.tv_nsec += timeout_nsec;
if (wait_time.tv_nsec >= 1000000000)
{
wait_time.tv_sec++;
wait_time.tv_nsec -= 1000000000;
}
#if defined(__ANDROID__) || defined (__APPLE__)
return pthread_mutex_timedlock1(mutex, &wait_time) == 0;
#else
return pthread_mutex_timedlock(mutex, &wait_time) == 0;
#endif
}
//----------------------------------------------------------------------------------------
bool AMF_STD_CALL amf_release_mutex(amf_handle hmutex)
{
if(hmutex == NULL)
{
return false;
}
pthread_mutex_t* mutex = (pthread_mutex_t*)hmutex;
return pthread_mutex_unlock(mutex) == 0;
}
//----------------------------------------------------------------------------------------
amf_handle AMF_STD_CALL amf_create_semaphore(amf_long iInitCount, amf_long iMaxCount, const wchar_t* /*pName*/)
{
if(iMaxCount == 0 || iInitCount > iMaxCount)
{
return NULL;
}
sem_t* semaphore = new sem_t;
if(sem_init(semaphore, 0, iInitCount) != 0)
{
delete semaphore;
return NULL;
}
return (amf_handle)semaphore;
}
//----------------------------------------------------------------------------------------
bool AMF_STD_CALL amf_delete_semaphore(amf_handle hsemaphore)
{
if(hsemaphore == NULL)
{
return false;
}
bool ret = true;
sem_t* semaphore = (sem_t*)hsemaphore;
ret = (0==sem_destroy(semaphore)) ? 1:0;
delete semaphore;
return ret;
}
//----------------------------------------------------------------------------------------
bool AMF_STD_CALL amf_wait_for_semaphore(amf_handle hsemaphore, amf_ulong timeout)
{
if(hsemaphore == NULL)
{
return true;
}
// ulTimeout is in milliseconds
long timeout_sec = timeout / 1000; /* Seconds */;
long timeout_nsec = (timeout - (timeout / 1000) * 1000) * 1000000;
timespec wait_time; //absolute time
clock_gettime(CLOCK_REALTIME, &wait_time);
wait_time.tv_sec += timeout_sec;
wait_time.tv_nsec += timeout_nsec;
if (wait_time.tv_nsec >= 1000000000)
{
wait_time.tv_sec++;
wait_time.tv_nsec -= 1000000000;
}
sem_t* semaphore = (sem_t*)hsemaphore;
if(timeout != AMF_INFINITE)
{
#if defined(__APPLE__)
return sem_timedwait1 (semaphore, &wait_time) == 0; // errno=ETIMEDOU
#else
return sem_timedwait (semaphore, &wait_time) == 0; // errno=ETIMEDOUT
#endif
}
else
{
return sem_wait(semaphore) == 0;
}
}
//----------------------------------------------------------------------------------------
bool AMF_STD_CALL amf_release_semaphore(amf_handle hsemaphore, amf_long iCount, amf_long* iOldCount)
{
if(hsemaphore == NULL)
{
return false;
}
sem_t* semaphore = (sem_t*)hsemaphore;
if(iOldCount != NULL)
{
int iTmp = 0;
sem_getvalue(semaphore, &iTmp);
*iOldCount = iTmp;
}
for(int i = 0; i < iCount; i++)
{
sem_post(semaphore);
}
return true;
}
//------------------------------------------------------------------------------
/*
* Delay is specified in milliseconds.
* Function will return prematurely if msDelay value is invalid.
*
* */
void AMF_STD_CALL amf_sleep(amf_ulong msDelay)
{
#if defined(NANOSLEEP_DONTUSE)
struct timespec sts, sts_remaining;
int iErrorCode;
ts.tv_sec = msDelay / 1000;
ts.tv_nsec = (msDelay - sts.tv_sec * 1000) * 1000000; // nanosec
// put in code to measure sleep clock jitter
do
{
iErrorCode = nanosleep(&sts, &sts_remaining);
if(iErrorCode)
{
switch(errno)
{
case EINTR:
sts = sts_remaining;
break;
case EFAULT:
case EINVAL:
case default:
perror("amf_sleep");
return;
/* TODO: how to log errors? */
}
}
} while(iErrorCode);
#else
usleep(msDelay * 1000);
#endif
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
// memory
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
void AMF_STD_CALL amf_debug_trace(const wchar_t* text)
{
#if defined(__ANDROID__)
__android_log_write(ANDROID_LOG_DEBUG, "AMF_TRACE", amf_from_unicode_to_multibyte(text).c_str());
#else
fprintf(stderr, "%ls", text);
#endif
}
void* AMF_STD_CALL amf_virtual_alloc(size_t size)
{
void* mem = NULL;
#if defined(__ANDROID__)
mem = memalign(sysconf(_SC_PAGESIZE), size);
if(mem == NULL)
{
amf_debug_trace(L"Failed to alloc memory using memalign() function.");
}
#else
int exitCode = posix_memalign(&mem, sysconf(_SC_PAGESIZE), size);
if(exitCode != 0)
{
amf_debug_trace(L"Failed to alloc memory using posix_memaling() function.");
}
#endif
return mem;
}
//-------------------------------------------------------------------------------------------------------
void AMF_STD_CALL amf_virtual_free(void* ptr)
{
free(ptr); // according to linux help memory allocated by memalign() must be freed by free()
}
//----------------------------------------------------------------------------------------
amf_handle AMF_STD_CALL amf_load_library(const wchar_t* filename)
{
void *ret = dlopen(amf_from_unicode_to_multibyte(filename).c_str(), RTLD_NOW | RTLD_GLOBAL);
if(ret ==0 )
{
const char *err = dlerror();
int a=1;
}
return ret;
}
amf_handle AMF_STD_CALL amf_load_library1(const wchar_t* filename, bool bGlobal)
{
void *ret;
if (bGlobal) {
ret = dlopen(amf_from_unicode_to_multibyte(filename).c_str(), RTLD_NOW | RTLD_GLOBAL);
} else {
#if defined(__ANDROID__) || (__APPLE__)
ret = dlopen(amf_from_unicode_to_multibyte(filename).c_str(), RTLD_NOW | RTLD_LOCAL);
#else
ret = dlopen(amf_from_unicode_to_multibyte(filename).c_str(), RTLD_NOW | RTLD_LOCAL| RTLD_DEEPBIND);
#endif
}
if(ret == 0)
{
const char *err = dlerror();
int a=1;
}
return ret;
}
void* AMF_STD_CALL amf_get_proc_address(amf_handle module, const char* procName)
{
return dlsym(module, procName);
}
//-------------------------------------------------------------------------------------------------
int AMF_STD_CALL amf_free_library(amf_handle module)
{
return dlclose(module) == 0;
}
void AMF_STD_CALL amf_increase_timer_precision()
{
}
void AMF_STD_CALL amf_restore_timer_precision()
{
}
//----------------------------------------------------------------------------------------
double AMF_STD_CALL amf_clock()
{
//MM: clock() Win32 - returns time from beginning of the program
//MM: clock() works different in Linux - returns consumed processor time
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
double cur_time = ((double)ts.tv_sec) + ((double)ts.tv_nsec) / 1000000000.; //to sec
return cur_time;
}
//----------------------------------------------------------------------------------------
amf_int64 AMF_STD_CALL get_time_in_seconds_with_fraction()
{
struct timeval tv;
gettimeofday(&tv, NULL);
amf_int64 ntp_time = ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
return ntp_time;
}
//---------------------------------------------------------------------------------------
amf_pts AMF_STD_CALL amf_high_precision_clock()
{
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return ts.tv_sec * 10000000LL + ts.tv_nsec / 100.; //to nanosec
}
//---------------------------------------------------------------------------------------
// Returns number of physical cores
amf_int32 AMF_STD_CALL amf_get_cpu_cores()
{
// NOTE: get_nprocs is preffered way to get online cores on linux but it will
// return number of logical cores. Uncomment line bellow if that's the behaviour needed
//return get_nprocs();
const char CPUINFO_CORES_COUNT[] = "cpu cores";
std::ifstream cpuinfo("/proc/cpuinfo");
std::string line;
while (std::getline(cpuinfo, line))
{
if (line.compare(0, strlen(CPUINFO_CORES_COUNT), CPUINFO_CORES_COUNT) == 0)
{
size_t pos = line.rfind(':') + 2;
if (pos == std::string::npos)
{
continue;
}
std::string tmp = line.substr(pos);
const char* value = tmp.c_str();
int cores_online = std::atoi(value);
// Make sure we always return at least 1
return std::max(1, cores_online);
}
}
// Failure, return default
return 1;
}
//--------------------------------------------------------------------------------
// the end
//--------------------------------------------------------------------------------
#endif

View File

@@ -0,0 +1,75 @@
//
// Notice Regarding Standards. AMD does not provide a license or sublicense to
// any Intellectual Property Rights relating to any standards, including but not
// limited to any audio and/or video codec technologies such as MPEG-2, MPEG-4;
// AVC/H.264; HEVC/H.265; AAC decode/FFMPEG; AAC encode/FFMPEG; VC-1; AV1; and MP3
// (collectively, the "Media Technologies"). For clarity, you will pay any
// royalties due for such third party technologies, which may include the Media
// Technologies that are owed as a result of AMD providing the Software to you.
//
// MIT license
//
// Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#pragma once
#include <memory>
#include <X11/X.h>
#include <X11/Xlib.h>
//this pattern makes it impossible to use the x11 Display* pointer without first calling XLockDisplay
class XDisplay {
public:
typedef std::shared_ptr<XDisplay> Ptr;
XDisplay()
: m_pDisplay(XOpenDisplay(nullptr))
, m_shouldClose(true)
{}
XDisplay(Display* dpy)
: m_pDisplay(dpy)
, m_shouldClose(false)
{}
~XDisplay() { if(IsValid() && m_shouldClose) XCloseDisplay(m_pDisplay); }
bool IsValid() { return m_pDisplay != nullptr; }
private:
Display* m_pDisplay;
bool m_shouldClose = false;
friend class XDisplayPtr;
};
class XDisplayPtr {
public:
XDisplayPtr() = delete;
XDisplayPtr(const XDisplayPtr&) = delete;
XDisplayPtr& operator=(const XDisplayPtr&) =delete;
explicit XDisplayPtr(std::shared_ptr<XDisplay> display) : m_pDisplay(display) { XLockDisplay(m_pDisplay->m_pDisplay); }
~XDisplayPtr() { XUnlockDisplay(m_pDisplay->m_pDisplay); }
//XDisplayPtr acts like a normal Display* pointer, but the only way to obtain it is by locking the Display
operator Display*() { return m_pDisplay->m_pDisplay; }
private:
XDisplay::Ptr m_pDisplay;
};

View File

@@ -0,0 +1,11 @@
///-------------------------------------------------------------------------
/// Copyright © 2020-2022 Advanced Micro Devices, Inc. All rights reserved.
///-------------------------------------------------------------------------
#pragma once
#include <memory>
#include <X11/extensions/Xrandr.h>
typedef std::shared_ptr<XRRScreenResources> XRRScreenResourcesPtr;
typedef std::shared_ptr<XRRCrtcInfo> XRRCrtcInfoPtr;