mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-01-29 00:51:53 +08:00
init
This commit is contained in:
34
libs/hwcodec/cpp/amf/amf_common.cpp
Normal file
34
libs/hwcodec/cpp/amf/amf_common.cpp
Normal 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;
|
||||
}
|
||||
451
libs/hwcodec/cpp/amf/amf_decode.cpp
Normal file
451
libs/hwcodec/cpp/amf/amf_decode.cpp
Normal 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"
|
||||
611
libs/hwcodec/cpp/amf/amf_encode.cpp
Normal file
611
libs/hwcodec/cpp/amf/amf_encode.cpp
Normal 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"
|
||||
39
libs/hwcodec/cpp/amf/amf_ffi.h
Normal file
39
libs/hwcodec/cpp/amf/amf_ffi.h
Normal 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
|
||||
Reference in New Issue
Block a user