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,34 @@
#include "common.h"
#include <iostream>
#include <public/common/TraceAdapter.h>
#include <stdio.h>
#ifndef AMF_FACILITY
#define AMF_FACILITY L"AMFCommon"
#endif
static bool convert_api(amf::AMF_MEMORY_TYPE &rhs) {
// Always use DX11 since it's the only supported API
rhs = amf::AMF_MEMORY_DX11;
return true;
}
static bool convert_surface_format(SurfaceFormat lhs,
amf::AMF_SURFACE_FORMAT &rhs) {
switch (lhs) {
case SURFACE_FORMAT_NV12:
rhs = amf::AMF_SURFACE_NV12;
break;
case SURFACE_FORMAT_RGBA:
rhs = amf::AMF_SURFACE_RGBA;
break;
case SURFACE_FORMAT_BGRA:
rhs = amf::AMF_SURFACE_BGRA;
break;
default:
std::cerr << "unsupported surface format: " << static_cast<int>(lhs)
<< "\n";
return false;
}
return true;
}

View File

@@ -0,0 +1,451 @@
#include <public/common/AMFFactory.h>
#include <public/common/AMFSTL.h>
#include <public/common/ByteArray.h>
#include <public/common/Thread.h>
#include <public/common/TraceAdapter.h>
#include <public/include/components/VideoConverter.h>
#include <public/include/components/VideoDecoderUVD.h>
#include <cstring>
#include <iostream>
#include "callback.h"
#include "common.h"
#include "system.h"
#include "util.h"
#define LOG_MODULE "AMFDEC"
#include "log.h"
#define AMF_FACILITY L"AMFDecoder"
#define AMF_CHECK_RETURN(res, msg) \
if (res != AMF_OK) { \
LOG_ERROR(std::string(msg) + ", result code: " + std::to_string(int(res))); \
return res; \
}
namespace {
class AMFDecoder {
private:
// system
void *device_;
int64_t luid_;
std::unique_ptr<NativeDevice> nativeDevice_ = nullptr;
// amf
AMFFactoryHelper AMFFactory_;
amf::AMFContextPtr AMFContext_ = NULL;
amf::AMFComponentPtr AMFDecoder_ = NULL;
amf::AMF_MEMORY_TYPE AMFMemoryType_;
amf::AMF_SURFACE_FORMAT decodeFormatOut_ = amf::AMF_SURFACE_NV12;
amf::AMF_SURFACE_FORMAT textureFormatOut_;
amf::AMFComponentPtr AMFConverter_ = NULL;
int last_width_ = 0;
int last_height_ = 0;
amf_wstring codec_;
bool full_range_ = false;
bool bt709_ = false;
// buffer
std::vector<std::vector<uint8_t>> buffer_;
public:
AMFDecoder(void *device, int64_t luid, amf::AMF_MEMORY_TYPE memoryTypeOut,
amf_wstring codec, amf::AMF_SURFACE_FORMAT textureFormatOut) {
device_ = device;
luid_ = luid;
AMFMemoryType_ = memoryTypeOut;
textureFormatOut_ = textureFormatOut;
codec_ = codec;
}
~AMFDecoder() {}
AMF_RESULT decode(uint8_t *iData, uint32_t iDataSize, DecodeCallback callback,
void *obj) {
AMF_RESULT res = AMF_FAIL;
bool decoded = false;
amf::AMFBufferPtr iDataWrapBuffer = NULL;
res = AMFContext_->CreateBufferFromHostNative(iData, iDataSize,
&iDataWrapBuffer, NULL);
AMF_CHECK_RETURN(res, "CreateBufferFromHostNative failed");
res = AMFDecoder_->SubmitInput(iDataWrapBuffer);
if (res == AMF_RESOLUTION_CHANGED) {
iDataWrapBuffer = NULL;
LOG_INFO(std::string("resolution changed"));
res = AMFDecoder_->Drain();
AMF_CHECK_RETURN(res, "Drain failed");
res = AMFDecoder_->Terminate();
AMF_CHECK_RETURN(res, "Terminate failed");
res = AMFDecoder_->Init(decodeFormatOut_, 0, 0);
AMF_CHECK_RETURN(res, "Init failed");
res = AMFContext_->CreateBufferFromHostNative(iData, iDataSize,
&iDataWrapBuffer, NULL);
AMF_CHECK_RETURN(res, "CreateBufferFromHostNative failed");
res = AMFDecoder_->SubmitInput(iDataWrapBuffer);
}
AMF_CHECK_RETURN(res, "SubmitInput failed");
amf::AMFDataPtr oData = NULL;
auto start = util::now();
do {
res = AMFDecoder_->QueryOutput(&oData);
if (res == AMF_REPEAT) {
amf_sleep(1);
}
} while (res == AMF_REPEAT && util::elapsed_ms(start) < DECODE_TIMEOUT_MS);
if (res == AMF_OK && oData != NULL) {
amf::AMFSurfacePtr surface(oData);
AMF_RETURN_IF_INVALID_POINTER(surface, L"surface is NULL");
if (surface->GetPlanesCount() == 0)
return AMF_FAIL;
// convert texture
amf::AMFDataPtr convertData;
res = Convert(surface, convertData);
AMF_CHECK_RETURN(res, "Convert failed");
amf::AMFSurfacePtr convertSurface(convertData);
if (!convertSurface || convertSurface->GetPlanesCount() == 0)
return AMF_FAIL;
// For DirectX objects, when a pointer to a COM interface is returned,
// GetNative does not call IUnknown::AddRef on the interface being
// returned.
void *native = convertSurface->GetPlaneAt(0)->GetNative();
if (!native)
return AMF_FAIL;
switch (convertSurface->GetMemoryType()) {
case amf::AMF_MEMORY_DX11: {
{
ID3D11Texture2D *src = (ID3D11Texture2D *)native;
D3D11_TEXTURE2D_DESC desc;
src->GetDesc(&desc);
nativeDevice_->EnsureTexture(desc.Width, desc.Height);
nativeDevice_->next();
ID3D11Texture2D *dst = nativeDevice_->GetCurrentTexture();
nativeDevice_->context_->CopyResource(dst, src);
nativeDevice_->context_->Flush();
if (callback)
callback(dst, obj);
decoded = true;
}
break;
} break;
case amf::AMF_MEMORY_OPENCL: {
uint8_t *buf = (uint8_t *)native;
} break;
}
surface = NULL;
convertData = NULL;
convertSurface = NULL;
}
oData = NULL;
iDataWrapBuffer = NULL;
return decoded ? AMF_OK : AMF_FAIL;
return AMF_OK;
}
AMF_RESULT destroy() {
// Terminate converter before terminate decoder get "[AMFDeviceDX11Impl]
// Warning: Possible memory leak detected: DX11 device is being destroyed,
// but has 6 surfaces associated with it. This is OK if there are references
// to the device outside AMF"
if (AMFConverter_ != NULL) {
AMFConverter_->Drain();
AMFConverter_->Terminate();
AMFConverter_ = NULL;
}
if (AMFDecoder_ != NULL) {
AMFDecoder_->Drain();
AMFDecoder_->Terminate();
AMFDecoder_ = NULL;
}
if (AMFContext_ != NULL) {
AMFContext_->Terminate();
AMFContext_ = NULL; // context is the last
}
AMFFactory_.Terminate();
return AMF_OK;
}
AMF_RESULT initialize() {
AMF_RESULT res;
res = AMFFactory_.Init();
AMF_CHECK_RETURN(res, "AMFFactory Init failed");
amf::AMFSetCustomTracer(AMFFactory_.GetTrace());
amf::AMFTraceEnableWriter(AMF_TRACE_WRITER_CONSOLE, true);
amf::AMFTraceSetWriterLevel(AMF_TRACE_WRITER_CONSOLE, AMF_TRACE_WARNING);
res = AMFFactory_.GetFactory()->CreateContext(&AMFContext_);
AMF_CHECK_RETURN(res, "CreateContext failed");
switch (AMFMemoryType_) {
case amf::AMF_MEMORY_DX11:
nativeDevice_ = std::make_unique<NativeDevice>();
if (!nativeDevice_->Init(luid_, (ID3D11Device *)device_, 4)) {
LOG_ERROR(std::string("Init NativeDevice failed"));
return AMF_FAIL;
}
res = AMFContext_->InitDX11(
nativeDevice_->device_.Get()); // can be DX11 device
AMF_CHECK_RETURN(res, "InitDX11 failed");
break;
default:
LOG_ERROR(std::string("unsupported memory type: ") +
std::to_string((int)AMFMemoryType_));
return AMF_FAIL;
}
res = AMFFactory_.GetFactory()->CreateComponent(AMFContext_, codec_.c_str(),
&AMFDecoder_);
AMF_CHECK_RETURN(res, "CreateComponent failed");
res = setParameters();
AMF_CHECK_RETURN(res, "setParameters failed");
res = AMFDecoder_->Init(decodeFormatOut_, 0, 0);
AMF_CHECK_RETURN(res, "Init decoder failed");
return AMF_OK;
}
private:
AMF_RESULT setParameters() {
AMF_RESULT res;
res =
AMFDecoder_->SetProperty(AMF_TIMESTAMP_MODE, amf_int64(AMF_TS_DECODE));
AMF_RETURN_IF_FAILED(
res, L"SetProperty AMF_TIMESTAMP_MODE to AMF_TS_DECODE failed");
res =
AMFDecoder_->SetProperty(AMF_VIDEO_DECODER_REORDER_MODE,
amf_int64(AMF_VIDEO_DECODER_MODE_LOW_LATENCY));
AMF_CHECK_RETURN(res, "SetProperty AMF_VIDEO_DECODER_REORDER_MODE failed");
// color
res = AMFDecoder_->SetProperty<amf_int64>(
AMF_VIDEO_DECODER_COLOR_RANGE,
full_range_ ? AMF_COLOR_RANGE_FULL : AMF_COLOR_RANGE_STUDIO);
AMF_CHECK_RETURN(res, "SetProperty AMF_VIDEO_DECODER_COLOR_RANGE failed");
res = AMFDecoder_->SetProperty<amf_int64>(
AMF_VIDEO_DECODER_COLOR_PROFILE,
bt709_ ? (full_range_ ? AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_709
: AMF_VIDEO_CONVERTER_COLOR_PROFILE_709)
: (full_range_ ? AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_601
: AMF_VIDEO_CONVERTER_COLOR_PROFILE_601));
AMF_CHECK_RETURN(res, "SetProperty AMF_VIDEO_DECODER_COLOR_PROFILE failed");
// res = AMFDecoder_->SetProperty<amf_int64>(
// AMF_VIDEO_DECODER_COLOR_TRANSFER_CHARACTERISTIC,
// bt709_ ? AMF_COLOR_TRANSFER_CHARACTERISTIC_BT709
// : AMF_COLOR_TRANSFER_CHARACTERISTIC_SMPTE170M);
// AMF_CHECK_RETURN(
// res,
// "SetProperty AMF_VIDEO_DECODER_COLOR_TRANSFER_CHARACTERISTIC
// failed");
// res = AMFDecoder_->SetProperty<amf_int64>(
// AMF_VIDEO_DECODER_COLOR_PRIMARIES,
// bt709_ ? AMF_COLOR_PRIMARIES_BT709 : AMF_COLOR_PRIMARIES_SMPTE170M);
// AMF_CHECK_RETURN(res,
// "SetProperty AMF_VIDEO_DECODER_COLOR_PRIMARIES failed");
return AMF_OK;
}
AMF_RESULT Convert(IN amf::AMFSurfacePtr &surface,
OUT amf::AMFDataPtr &convertData) {
if (decodeFormatOut_ == textureFormatOut_)
return AMF_OK;
AMF_RESULT res;
int width = surface->GetPlaneAt(0)->GetWidth();
int height = surface->GetPlaneAt(0)->GetHeight();
if (AMFConverter_ != NULL) {
if (width != last_width_ || height != last_height_) {
LOG_INFO(std::string("Convert size changed, (") + std::to_string(last_width_) + "x" +
std::to_string(last_height_) + ") -> (" +
std::to_string(width) + "x" + std::to_string(width) + ")");
AMFConverter_->Terminate();
AMFConverter_ = NULL;
}
}
if (!AMFConverter_) {
res = AMFFactory_.GetFactory()->CreateComponent(
AMFContext_, AMFVideoConverter, &AMFConverter_);
AMF_CHECK_RETURN(res, "Convert CreateComponent failed");
res = AMFConverter_->SetProperty(AMF_VIDEO_CONVERTER_MEMORY_TYPE,
AMFMemoryType_);
AMF_CHECK_RETURN(res,
"SetProperty AMF_VIDEO_CONVERTER_MEMORY_TYPE failed");
res = AMFConverter_->SetProperty(AMF_VIDEO_CONVERTER_OUTPUT_FORMAT,
textureFormatOut_);
AMF_CHECK_RETURN(res,
"SetProperty AMF_VIDEO_CONVERTER_OUTPUT_FORMAT failed");
res = AMFConverter_->SetProperty(AMF_VIDEO_CONVERTER_OUTPUT_SIZE,
::AMFConstructSize(width, height));
AMF_CHECK_RETURN(res,
"SetProperty AMF_VIDEO_CONVERTER_OUTPUT_SIZE failed");
res = AMFConverter_->Init(decodeFormatOut_, width, height);
AMF_CHECK_RETURN(res, "Init converter failed");
// color
res = AMFConverter_->SetProperty<amf_int64>(
AMF_VIDEO_CONVERTER_INPUT_COLOR_RANGE,
full_range_ ? AMF_COLOR_RANGE_FULL : AMF_COLOR_RANGE_STUDIO);
AMF_CHECK_RETURN(
res, "SetProperty AMF_VIDEO_CONVERTER_INPUT_COLOR_RANGE failed");
res = AMFConverter_->SetProperty<amf_int64>(
AMF_VIDEO_CONVERTER_OUTPUT_COLOR_RANGE, AMF_COLOR_RANGE_FULL);
AMF_CHECK_RETURN(
res, "SetProperty AMF_VIDEO_CONVERTER_OUTPUT_COLOR_RANGE failed");
res = AMFConverter_->SetProperty<amf_int64>(
AMF_VIDEO_CONVERTER_COLOR_PROFILE,
bt709_ ? (full_range_ ? AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_709
: AMF_VIDEO_CONVERTER_COLOR_PROFILE_709)
: (full_range_ ? AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_601
: AMF_VIDEO_CONVERTER_COLOR_PROFILE_601));
AMF_CHECK_RETURN(res,
"SetProperty AMF_VIDEO_CONVERTER_COLOR_PROFILE failed");
res = AMFConverter_->SetProperty<amf_int64>(
AMF_VIDEO_CONVERTER_INPUT_TRANSFER_CHARACTERISTIC,
bt709_ ? AMF_COLOR_TRANSFER_CHARACTERISTIC_BT709
: AMF_COLOR_TRANSFER_CHARACTERISTIC_SMPTE170M);
AMF_CHECK_RETURN(
res, "SetProperty AMF_VIDEO_CONVERTER_INPUT_TRANSFER_CHARACTERISTIC "
"failed");
res = AMFConverter_->SetProperty<amf_int64>(
AMF_VIDEO_CONVERTER_INPUT_COLOR_PRIMARIES,
bt709_ ? AMF_COLOR_PRIMARIES_BT709 : AMF_COLOR_PRIMARIES_SMPTE170M);
AMF_CHECK_RETURN(
res, "SetProperty AMF_VIDEO_CONVERTER_INPUT_COLOR_PRIMARIES failed");
}
last_width_ = width;
last_height_ = height;
res = AMFConverter_->SubmitInput(surface);
AMF_CHECK_RETURN(res, "Convert SubmitInput failed");
res = AMFConverter_->QueryOutput(&convertData);
AMF_CHECK_RETURN(res, "Convert QueryOutput failed");
return AMF_OK;
}
};
bool convert_codec(DataFormat lhs, amf_wstring &rhs) {
switch (lhs) {
case H264:
rhs = AMFVideoDecoderUVD_H264_AVC;
break;
case H265:
rhs = AMFVideoDecoderHW_H265_HEVC;
break;
default:
LOG_ERROR(std::string("unsupported codec: ") + std::to_string(lhs));
return false;
}
return true;
}
} // namespace
#include "amf_common.cpp"
extern "C" {
int amf_destroy_decoder(void *decoder) {
try {
AMFDecoder *dec = (AMFDecoder *)decoder;
if (dec) {
dec->destroy();
delete dec;
dec = NULL;
return 0;
}
} catch (const std::exception &e) {
LOG_ERROR(std::string("destroy failed: ") + e.what());
}
return -1;
}
void *amf_new_decoder(void *device, int64_t luid,
DataFormat dataFormat) {
AMFDecoder *dec = NULL;
try {
amf_wstring codecStr;
amf::AMF_MEMORY_TYPE memory;
amf::AMF_SURFACE_FORMAT surfaceFormat;
if (!convert_api(memory)) {
return NULL;
}
if (!convert_codec(dataFormat, codecStr)) {
return NULL;
}
dec = new AMFDecoder(device, luid, memory, codecStr, amf::AMF_SURFACE_BGRA);
if (dec) {
if (dec->initialize() == AMF_OK) {
return dec;
}
}
} catch (const std::exception &e) {
LOG_ERROR(std::string("new failed: ") + e.what());
}
if (dec) {
dec->destroy();
delete dec;
dec = NULL;
}
return NULL;
}
int amf_decode(void *decoder, uint8_t *data, int32_t length,
DecodeCallback callback, void *obj) {
try {
AMFDecoder *dec = (AMFDecoder *)decoder;
if (dec->decode(data, length, callback, obj) == AMF_OK) {
return HWCODEC_SUCCESS;
}
} catch (const std::exception &e) {
LOG_ERROR(std::string("decode failed: ") + e.what());
}
return HWCODEC_ERR_COMMON;
}
int amf_test_decode(int64_t *outLuids, int32_t *outVendors, int32_t maxDescNum,
int32_t *outDescNum, DataFormat dataFormat,
uint8_t *data, int32_t length, const int64_t *excludedLuids, const int32_t *excludeFormats, int32_t excludeCount) {
try {
Adapters adapters;
if (!adapters.Init(ADAPTER_VENDOR_AMD))
return -1;
int count = 0;
for (auto &adapter : adapters.adapters_) {
int64_t currentLuid = LUID(adapter.get()->desc1_);
if (util::skip_test(excludedLuids, excludeFormats, excludeCount, currentLuid, dataFormat)) {
continue;
}
AMFDecoder *p = (AMFDecoder *)amf_new_decoder(
nullptr, currentLuid, dataFormat);
if (!p)
continue;
auto start = util::now();
bool succ = p->decode(data, length, nullptr, nullptr) == AMF_OK;
int64_t elapsed = util::elapsed_ms(start);
if (succ && elapsed < TEST_TIMEOUT_MS) {
outLuids[count] = currentLuid;
outVendors[count] = VENDOR_AMD;
count += 1;
}
p->destroy();
delete p;
p = nullptr;
if (count >= maxDescNum)
break;
}
*outDescNum = count;
return 0;
} catch (const std::exception &e) {
LOG_ERROR(std::string("test failed: ") + e.what());
}
return -1;
}
} // extern "C"

View File

@@ -0,0 +1,611 @@
#include <public/common/AMFFactory.h>
#include <public/common/AMFSTL.h>
#include <public/common/Thread.h>
#include <public/common/TraceAdapter.h>
#include <public/include/components/VideoEncoderAV1.h>
#include <public/include/components/VideoEncoderHEVC.h>
#include <public/include/components/VideoEncoderVCE.h>
#include <public/include/core/Platform.h>
#include <stdio.h>
#include <cstring>
#include <iostream>
#include <math.h>
#include "callback.h"
#include "common.h"
#include "system.h"
#include "util.h"
#define LOG_MODULE "AMFENC"
#include "log.h"
#define AMF_FACILITY L"AMFEncoder"
#define MILLISEC_TIME 10000
namespace {
#define AMF_CHECK_RETURN(res, msg) \
if (res != AMF_OK) { \
LOG_ERROR(std::string(msg) + ", result code: " + std::to_string(int(res))); \
return res; \
}
/** Encoder output packet */
struct encoder_packet {
uint8_t *data; /**< Packet data */
size_t size; /**< Packet size */
int64_t pts; /**< Presentation timestamp */
int64_t dts; /**< Decode timestamp */
int32_t timebase_num; /**< Timebase numerator */
int32_t timebase_den; /**< Timebase denominator */
bool keyframe; /**< Is a keyframe */
/* ---------------------------------------------------------------- */
/* Internal video variables (will be parsed automatically) */
/* DTS in microseconds */
int64_t dts_usec;
/* System DTS in microseconds */
int64_t sys_dts_usec;
};
class AMFEncoder {
public:
DataFormat dataFormat_;
amf::AMFComponentPtr AMFEncoder_ = NULL;
amf::AMFContextPtr AMFContext_ = NULL;
private:
// system
void *handle_;
// AMF Internals
AMFFactoryHelper AMFFactory_;
amf::AMF_MEMORY_TYPE AMFMemoryType_;
amf::AMF_SURFACE_FORMAT AMFSurfaceFormat_ = amf::AMF_SURFACE_BGRA;
std::pair<int32_t, int32_t> resolution_;
amf_wstring codec_;
// const
AMF_COLOR_BIT_DEPTH_ENUM eDepth_ = AMF_COLOR_BIT_DEPTH_8;
int query_timeout_ = ENCODE_TIMEOUT_MS;
int32_t bitRateIn_;
int32_t frameRate_;
int32_t gop_;
bool enable4K_ = false;
bool full_range_ = false;
bool bt709_ = false;
// Buffers
std::vector<uint8_t> packetDataBuffer_;
public:
AMFEncoder(void *handle, amf::AMF_MEMORY_TYPE memoryType, amf_wstring codec,
DataFormat dataFormat, int32_t width, int32_t height,
int32_t bitrate, int32_t framerate, int32_t gop) {
handle_ = handle;
dataFormat_ = dataFormat;
AMFMemoryType_ = memoryType;
resolution_ = std::make_pair(width, height);
codec_ = codec;
bitRateIn_ = bitrate;
frameRate_ = framerate;
gop_ = (gop > 0 && gop < MAX_GOP) ? gop : MAX_GOP;
enable4K_ = width > 1920 && height > 1080;
}
~AMFEncoder() {}
AMF_RESULT encode(void *tex, EncodeCallback callback, void *obj, int64_t ms) {
amf::AMFSurfacePtr surface = NULL;
amf::AMFComputeSyncPointPtr pSyncPoint = NULL;
AMF_RESULT res;
bool encoded = false;
switch (AMFMemoryType_) {
case amf::AMF_MEMORY_DX11:
// https://github.com/GPUOpen-LibrariesAndSDKs/AMF/issues/280
// AMF will not copy the surface during the CreateSurfaceFromDX11Native
// call
res = AMFContext_->CreateSurfaceFromDX11Native(tex, &surface, NULL);
AMF_CHECK_RETURN(res, "CreateSurfaceFromDX11Native failed");
{
amf::AMFDataPtr data1;
surface->Duplicate(surface->GetMemoryType(), &data1);
surface = amf::AMFSurfacePtr(data1);
}
break;
default:
LOG_ERROR(std::string("Unsupported memory type"));
return AMF_NOT_IMPLEMENTED;
break;
}
surface->SetPts(ms * AMF_MILLISECOND);
res = AMFEncoder_->SubmitInput(surface);
AMF_CHECK_RETURN(res, "SubmitInput failed");
amf::AMFDataPtr data = NULL;
res = AMFEncoder_->QueryOutput(&data);
if (res == AMF_OK && data != NULL) {
struct encoder_packet packet;
PacketKeyframe(data, &packet);
amf::AMFBufferPtr pBuffer = amf::AMFBufferPtr(data);
packet.size = pBuffer->GetSize();
if (packet.size > 0) {
if (packetDataBuffer_.size() < packet.size) {
size_t newBufferSize = (size_t)exp2(ceil(log2((double)packet.size)));
packetDataBuffer_.resize(newBufferSize);
}
packet.data = packetDataBuffer_.data();
std::memcpy(packet.data, pBuffer->GetNative(), packet.size);
if (callback)
callback(packet.data, packet.size, packet.keyframe, obj, ms);
encoded = true;
}
pBuffer = NULL;
}
data = NULL;
pSyncPoint = NULL;
surface = NULL;
return encoded ? AMF_OK : AMF_FAIL;
}
AMF_RESULT destroy() {
if (AMFEncoder_) {
AMFEncoder_->Terminate();
AMFEncoder_ = NULL;
}
if (AMFContext_) {
AMFContext_->Terminate();
AMFContext_ = NULL; // AMFContext_ is the last
}
AMFFactory_.Terminate();
return AMF_OK;
}
AMF_RESULT test() {
AMF_RESULT res = AMF_OK;
amf::AMFSurfacePtr surface = nullptr;
res = AMFContext_->AllocSurface(AMFMemoryType_, AMFSurfaceFormat_,
resolution_.first, resolution_.second,
&surface);
AMF_CHECK_RETURN(res, "AllocSurface failed");
if (surface->GetPlanesCount() < 1)
return AMF_FAIL;
void *native = surface->GetPlaneAt(0)->GetNative();
if (!native)
return AMF_FAIL;
int32_t key_obj = 0;
auto start = util::now();
res = encode(native, util_encode::vram_encode_test_callback, &key_obj, 0);
int64_t elapsed = util::elapsed_ms(start);
if (res == AMF_OK && key_obj == 1 && elapsed < TEST_TIMEOUT_MS) {
return AMF_OK;
}
return AMF_FAIL;
}
AMF_RESULT initialize() {
AMF_RESULT res;
res = AMFFactory_.Init();
if (res != AMF_OK) {
std::cerr << "AMF init failed, error code = " << res << "\n";
return res;
}
amf::AMFSetCustomTracer(AMFFactory_.GetTrace());
amf::AMFTraceEnableWriter(AMF_TRACE_WRITER_CONSOLE, true);
amf::AMFTraceSetWriterLevel(AMF_TRACE_WRITER_CONSOLE, AMF_TRACE_WARNING);
// AMFContext_
res = AMFFactory_.GetFactory()->CreateContext(&AMFContext_);
AMF_CHECK_RETURN(res, "CreateContext failed");
switch (AMFMemoryType_) {
case amf::AMF_MEMORY_DX11:
res = AMFContext_->InitDX11(handle_); // can be DX11 device
AMF_CHECK_RETURN(res, "InitDX11 failed");
break;
default:
LOG_ERROR(std::string("unsupported amf memory type"));
return AMF_FAIL;
}
// component: encoder
res = AMFFactory_.GetFactory()->CreateComponent(AMFContext_, codec_.c_str(),
&AMFEncoder_);
AMF_CHECK_RETURN(res, "CreateComponent failed");
res = SetParams(codec_);
AMF_CHECK_RETURN(res, "Could not set params in encoder.");
res = AMFEncoder_->Init(AMFSurfaceFormat_, resolution_.first,
resolution_.second);
AMF_CHECK_RETURN(res, "encoder->Init() failed");
return AMF_OK;
}
private:
AMF_RESULT SetParams(const amf_wstring &codecStr) {
AMF_RESULT res;
if (codecStr == amf_wstring(AMFVideoEncoderVCE_AVC)) {
// ------------- Encoder params usage---------------
res = AMFEncoder_->SetProperty(
AMF_VIDEO_ENCODER_USAGE,
AMF_VIDEO_ENCODER_USAGE_LOW_LATENCY_HIGH_QUALITY);
AMF_CHECK_RETURN(res, "SetProperty AMF_VIDEO_ENCODER_USAGE failed");
// ------------- Encoder params static---------------
res = AMFEncoder_->SetProperty(
AMF_VIDEO_ENCODER_FRAMESIZE,
::AMFConstructSize(resolution_.first, resolution_.second));
AMF_CHECK_RETURN(res,
"SetProperty AMF_VIDEO_ENCODER_FRAMESIZE failed, (" +
std::to_string(resolution_.first) + "," +
std::to_string(resolution_.second) + ")");
res = AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_LOWLATENCY_MODE, true);
AMF_CHECK_RETURN(res,
"SetProperty AMF_VIDEO_ENCODER_LOWLATENCY_MODE failed");
res = AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_QUALITY_PRESET,
AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY);
AMF_CHECK_RETURN(res,
"SetProperty AMF_VIDEO_ENCODER_QUALITY_PRESET failed");
res =
AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_COLOR_BIT_DEPTH, eDepth_);
AMF_CHECK_RETURN(res,
"SetProperty(AMF_VIDEO_ENCODER_COLOR_BIT_DEPTH failed");
res = AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD,
AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR);
AMF_CHECK_RETURN(res,
"SetProperty AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD");
if (enable4K_) {
res = AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_PROFILE,
AMF_VIDEO_ENCODER_PROFILE_HIGH);
AMF_CHECK_RETURN(res, "SetProperty(AMF_VIDEO_ENCODER_PROFILE failed");
res = AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_PROFILE_LEVEL,
AMF_H264_LEVEL__5_1);
AMF_CHECK_RETURN(res,
"SetProperty AMF_VIDEO_ENCODER_PROFILE_LEVEL failed");
}
// color
res = AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_FULL_RANGE_COLOR,
full_range_);
AMF_CHECK_RETURN(res, "SetProperty AMF_VIDEO_ENCODER_FULL_RANGE_COLOR");
res = AMFEncoder_->SetProperty<amf_int64>(
AMF_VIDEO_ENCODER_OUTPUT_COLOR_PROFILE,
bt709_ ? (full_range_ ? AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_709
: AMF_VIDEO_CONVERTER_COLOR_PROFILE_709)
: (full_range_ ? AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_601
: AMF_VIDEO_CONVERTER_COLOR_PROFILE_601));
AMF_CHECK_RETURN(res,
"SetProperty AMF_VIDEO_ENCODER_OUTPUT_COLOR_PROFILE");
// https://github.com/obsproject/obs-studio/blob/e27b013d4754e0e81119ab237ffedce8fcebcbbf/plugins/obs-ffmpeg/texture-amf.cpp#L924
res = AMFEncoder_->SetProperty<amf_int64>(
AMF_VIDEO_ENCODER_OUTPUT_TRANSFER_CHARACTERISTIC,
bt709_ ? AMF_COLOR_TRANSFER_CHARACTERISTIC_BT709
: AMF_COLOR_TRANSFER_CHARACTERISTIC_SMPTE170M);
AMF_CHECK_RETURN(
res, "SetProperty AMF_VIDEO_ENCODER_OUTPUT_TRANSFER_CHARACTERISTIC");
res = AMFEncoder_->SetProperty<amf_int64>(
AMF_VIDEO_ENCODER_OUTPUT_COLOR_PRIMARIES,
bt709_ ? AMF_COLOR_PRIMARIES_BT709 : AMF_COLOR_PRIMARIES_SMPTE170M);
AMF_CHECK_RETURN(res,
"SetProperty AMF_VIDEO_ENCODER_OUTPUT_COLOR_PRIMARIES");
// ------------- Encoder params dynamic ---------------
AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_B_PIC_PATTERN, 0);
// do not check error for AMF_VIDEO_ENCODER_B_PIC_PATTERN
// - can be not supported - check Capability Manager
// sample
res = AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_QUERY_TIMEOUT,
query_timeout_); // ms
AMF_CHECK_RETURN(res,
"SetProperty AMF_VIDEO_ENCODER_QUERY_TIMEOUT failed");
res = AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_TARGET_BITRATE,
bitRateIn_);
AMF_CHECK_RETURN(res,
"SetProperty AMF_VIDEO_ENCODER_TARGET_BITRATE failed");
res = AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_FRAMERATE,
::AMFConstructRate(frameRate_, 1));
AMF_CHECK_RETURN(res, "SetProperty AMF_VIDEO_ENCODER_FRAMERATE failed");
res = AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_IDR_PERIOD, gop_);
AMF_CHECK_RETURN(res, "SetProperty AMF_VIDEO_ENCODER_IDR_PERIOD failed");
} else if (codecStr == amf_wstring(AMFVideoEncoder_HEVC)) {
// ------------- Encoder params usage---------------
res = AMFEncoder_->SetProperty(
AMF_VIDEO_ENCODER_HEVC_USAGE,
AMF_VIDEO_ENCODER_HEVC_USAGE_LOW_LATENCY_HIGH_QUALITY);
AMF_CHECK_RETURN(res, "SetProperty AMF_VIDEO_ENCODER_HEVC_USAGE failed");
// ------------- Encoder params static---------------
res = AMFEncoder_->SetProperty(
AMF_VIDEO_ENCODER_HEVC_FRAMESIZE,
::AMFConstructSize(resolution_.first, resolution_.second));
AMF_CHECK_RETURN(res,
"SetProperty AMF_VIDEO_ENCODER_HEVC_FRAMESIZE failed");
res = AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_HEVC_LOWLATENCY_MODE,
true);
AMF_CHECK_RETURN(res,
"SetProperty AMF_VIDEO_ENCODER_LOWLATENCY_MODE failed");
res = AMFEncoder_->SetProperty(
AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET,
AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_QUALITY);
AMF_CHECK_RETURN(
res, "SetProperty AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET failed");
res = AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_HEVC_COLOR_BIT_DEPTH,
eDepth_);
AMF_CHECK_RETURN(
res, "SetProperty AMF_VIDEO_ENCODER_HEVC_COLOR_BIT_DEPTH failed");
res = AMFEncoder_->SetProperty(
AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD,
AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR);
AMF_CHECK_RETURN(
res, "SetProperty AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD failed");
if (enable4K_) {
res = AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_HEVC_TIER,
AMF_VIDEO_ENCODER_HEVC_TIER_HIGH);
AMF_CHECK_RETURN(res, "SetProperty(AMF_VIDEO_ENCODER_HEVC_TIER failed");
res = AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_HEVC_PROFILE_LEVEL,
AMF_LEVEL_5_1);
AMF_CHECK_RETURN(
res, "SetProperty AMF_VIDEO_ENCODER_HEVC_PROFILE_LEVEL failed");
}
// color
res = AMFEncoder_->SetProperty<amf_int64>(
AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE,
full_range_ ? AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE_FULL
: AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE_STUDIO);
AMF_CHECK_RETURN(
res, "SetProperty AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE failed");
res = AMFEncoder_->SetProperty<amf_int64>(
AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PROFILE,
bt709_ ? (full_range_ ? AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_709
: AMF_VIDEO_CONVERTER_COLOR_PROFILE_709)
: (full_range_ ? AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_601
: AMF_VIDEO_CONVERTER_COLOR_PROFILE_601));
AMF_CHECK_RETURN(
res,
"SetProperty AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PROFILE failed");
res = AMFEncoder_->SetProperty<amf_int64>(
AMF_VIDEO_ENCODER_HEVC_OUTPUT_TRANSFER_CHARACTERISTIC,
bt709_ ? AMF_COLOR_TRANSFER_CHARACTERISTIC_BT709
: AMF_COLOR_TRANSFER_CHARACTERISTIC_SMPTE170M);
AMF_CHECK_RETURN(
res, "SetProperty "
"AMF_VIDEO_ENCODER_HEVC_OUTPUT_TRANSFER_CHARACTERISTIC failed");
res = AMFEncoder_->SetProperty<amf_int64>(
AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PRIMARIES,
bt709_ ? AMF_COLOR_PRIMARIES_BT709 : AMF_COLOR_PRIMARIES_SMPTE170M);
AMF_CHECK_RETURN(
res,
"SetProperty AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PRIMARIES failed");
// ------------- Encoder params dynamic ---------------
res = AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_HEVC_QUERY_TIMEOUT,
query_timeout_); // ms
AMF_CHECK_RETURN(
res, "SetProperty(AMF_VIDEO_ENCODER_HEVC_QUERY_TIMEOUT failed");
res = AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_HEVC_TARGET_BITRATE,
bitRateIn_);
AMF_CHECK_RETURN(
res, "SetProperty AMF_VIDEO_ENCODER_HEVC_TARGET_BITRATE failed");
res = AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_HEVC_FRAMERATE,
::AMFConstructRate(frameRate_, 1));
AMF_CHECK_RETURN(res,
"SetProperty AMF_VIDEO_ENCODER_HEVC_FRAMERATE failed");
res = AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_HEVC_GOP_SIZE,
gop_); // todo
AMF_CHECK_RETURN(res,
"SetProperty AMF_VIDEO_ENCODER_HEVC_GOP_SIZE failed");
} else {
return AMF_FAIL;
}
return AMF_OK;
}
void PacketKeyframe(amf::AMFDataPtr &pData, struct encoder_packet *packet) {
if (AMFVideoEncoderVCE_AVC == codec_) {
uint64_t pktType;
pData->GetProperty(AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE, &pktType);
packet->keyframe = AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_IDR == pktType ||
AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_I == pktType;
} else if (AMFVideoEncoder_HEVC == codec_) {
uint64_t pktType;
pData->GetProperty(AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE, &pktType);
packet->keyframe =
AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE_IDR == pktType ||
AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE_I == pktType;
}
}
};
bool convert_codec(DataFormat lhs, amf_wstring &rhs) {
switch (lhs) {
case H264:
rhs = AMFVideoEncoderVCE_AVC;
break;
case H265:
rhs = AMFVideoEncoder_HEVC;
break;
default:
LOG_ERROR(std::string("unsupported codec: ") + std::to_string((int)lhs));
return false;
}
return true;
}
} // namespace
#include "amf_common.cpp"
extern "C" {
int amf_destroy_encoder(void *encoder) {
try {
AMFEncoder *enc = (AMFEncoder *)encoder;
enc->destroy();
delete enc;
enc = NULL;
return 0;
} catch (const std::exception &e) {
LOG_ERROR(std::string("destroy failed: ") + e.what());
}
return -1;
}
void *amf_new_encoder(void *handle, int64_t luid,
DataFormat dataFormat, int32_t width, int32_t height,
int32_t kbs, int32_t framerate, int32_t gop) {
AMFEncoder *enc = NULL;
try {
amf_wstring codecStr;
if (!convert_codec(dataFormat, codecStr)) {
return NULL;
}
amf::AMF_MEMORY_TYPE memoryType;
if (!convert_api(memoryType)) {
return NULL;
}
enc = new AMFEncoder(handle, memoryType, codecStr, dataFormat, width,
height, kbs * 1000, framerate, gop);
if (enc) {
if (AMF_OK == enc->initialize()) {
return enc;
}
}
} catch (const std::exception &e) {
LOG_ERROR(std::string("new failed: ") + e.what());
}
if (enc) {
enc->destroy();
delete enc;
enc = NULL;
}
return NULL;
}
int amf_encode(void *encoder, void *tex, EncodeCallback callback, void *obj,
int64_t ms) {
try {
AMFEncoder *enc = (AMFEncoder *)encoder;
return -enc->encode(tex, callback, obj, ms);
} catch (const std::exception &e) {
LOG_ERROR(std::string("encode failed: ") + e.what());
}
return -1;
}
int amf_driver_support() {
try {
AMFFactoryHelper factory;
AMF_RESULT res = factory.Init();
if (res == AMF_OK) {
factory.Terminate();
return 0;
}
} catch (const std::exception &e) {
}
return -1;
}
int amf_test_encode(int64_t *outLuids, int32_t *outVendors, int32_t maxDescNum, int32_t *outDescNum,
DataFormat dataFormat, int32_t width,
int32_t height, int32_t kbs, int32_t framerate,
int32_t gop, const int64_t *excludedLuids, const int32_t *excludeFormats, int32_t excludeCount) {
try {
Adapters adapters;
if (!adapters.Init(ADAPTER_VENDOR_AMD))
return -1;
int count = 0;
for (auto &adapter : adapters.adapters_) {
int64_t currentLuid = LUID(adapter.get()->desc1_);
if (util::skip_test(excludedLuids, excludeFormats, excludeCount, currentLuid, dataFormat)) {
continue;
}
AMFEncoder *e = (AMFEncoder *)amf_new_encoder(
(void *)adapter.get()->device_.Get(), currentLuid,
dataFormat, width, height, kbs, framerate, gop);
if (!e)
continue;
if (e->test() == AMF_OK) {
outLuids[count] = currentLuid;
outVendors[count] = VENDOR_AMD;
count += 1;
}
e->destroy();
delete e;
e = nullptr;
if (count >= maxDescNum)
break;
}
*outDescNum = count;
return 0;
} catch (const std::exception &e) {
LOG_ERROR(std::string("test ") + std::to_string(kbs) + " failed: " + e.what());
}
return -1;
}
int amf_set_bitrate(void *encoder, int32_t kbs) {
try {
AMFEncoder *enc = (AMFEncoder *)encoder;
AMF_RESULT res = AMF_FAIL;
switch (enc->dataFormat_) {
case H264:
res = enc->AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_TARGET_BITRATE,
kbs * 1000);
break;
case H265:
res = enc->AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_HEVC_TARGET_BITRATE,
kbs * 1000);
break;
}
return res == AMF_OK ? 0 : -1;
} catch (const std::exception &e) {
LOG_ERROR(std::string("set bitrate to ") + std::to_string(kbs) +
"k failed: " + e.what());
}
return -1;
}
int amf_set_framerate(void *encoder, int32_t framerate) {
try {
AMFEncoder *enc = (AMFEncoder *)encoder;
AMF_RESULT res = AMF_FAIL;
AMFRate rate = ::AMFConstructRate(framerate, 1);
switch (enc->dataFormat_) {
case H264:
res = enc->AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_FRAMERATE, rate);
break;
case H265:
res =
enc->AMFEncoder_->SetProperty(AMF_VIDEO_ENCODER_HEVC_FRAMERATE, rate);
break;
}
return res == AMF_OK ? 0 : -1;
} catch (const std::exception &e) {
LOG_ERROR(std::string("set framerate to ") + std::to_string(framerate) +
" failed: " + e.what());
}
return -1;
}
} // extern "C"

View File

@@ -0,0 +1,39 @@
#ifndef AMF_FFI_H
#define AMF_FFI_H
#include "../common/callback.h"
#include <stdbool.h>
int amf_driver_support();
void *amf_new_encoder(void *handle, int64_t luid,
int32_t data_format, int32_t width, int32_t height,
int32_t bitrate, int32_t framerate, int32_t gop);
int amf_encode(void *encoder, void *texture, EncodeCallback callback, void *obj,
int64_t ms);
int amf_destroy_encoder(void *encoder);
void *amf_new_decoder(void *device, int64_t luid,
int32_t dataFormat);
int amf_decode(void *decoder, uint8_t *data, int32_t length,
DecodeCallback callback, void *obj);
int amf_destroy_decoder(void *decoder);
int amf_test_encode(int64_t *outLuids, int32_t *outVendors, int32_t maxDescNum, int32_t *outDescNum,
int32_t dataFormat, int32_t width,
int32_t height, int32_t kbs, int32_t framerate,
int32_t gop, const int64_t *excludedLuids, const int32_t *excludeFormats, int32_t excludeCount);
int amf_test_decode(int64_t *outLuids, int32_t *outVendors, int32_t maxDescNum, int32_t *outDescNum,
int32_t dataFormat, uint8_t *data,
int32_t length, const int64_t *excludedLuids, const int32_t *excludeFormats, int32_t excludeCount);
int amf_set_bitrate(void *encoder, int32_t kbs);
int amf_set_framerate(void *encoder, int32_t framerate);
#endif // AMF_FFI_H