On 22/11/17 23:28, mmironov wrote: > From c669277afd764903d3da09d92a263d0fb58e24b1 Mon Sep 17 00:00:00 2001 > From: mmironov <mikhail.miro...@amd.com> > Date: Tue, 14 Nov 2017 17:54:24 -0500 > Subject: [PATCH] Added HW H.264 and HEVC encoding for AMD GPUs based on AMF > SDK > > Signed-off-by: mmironov <mikhail.miro...@amd.com> > --- > Changelog | 1 + > compat/amd/amfsdkenc.h | 1755 > ++++++++++++++++++++++++++++++++++++++++++++++ > configure | 18 +- > libavcodec/Makefile | 4 + > libavcodec/allcodecs.c | 2 + > libavcodec/amfenc.c | 596 ++++++++++++++++ > libavcodec/amfenc.h | 143 ++++ > libavcodec/amfenc_h264.c | 397 +++++++++++ > libavcodec/amfenc_hevc.c | 327 +++++++++ > 9 files changed, 3242 insertions(+), 1 deletion(-) > create mode 100644 compat/amd/amfsdkenc.h > create mode 100644 libavcodec/amfenc.c > create mode 100644 libavcodec/amfenc.h > create mode 100644 libavcodec/amfenc_h264.c > create mode 100644 libavcodec/amfenc_hevc.c
A few minor fixups below. I would be happy to apply this if it didn't contain the external header. Thanks, - Mark > diff --git a/Changelog b/Changelog > index 68829f2..e5e5ffd 100644 > --- a/Changelog > +++ b/Changelog > @@ -15,6 +15,7 @@ version <next>: > - Raw aptX muxer and demuxer > - NVIDIA NVDEC-accelerated H.264, HEVC and VP9 hwaccel decoding > - Intel QSV-accelerated overlay filter > +- AMD NW H.264 and HEVC encoders NW? > > > version 3.4: > diff --git a/compat/amd/amfsdkenc.h b/compat/amd/amfsdkenc.h > new file mode 100644 > index 0000000..282656d > --- /dev/null > +++ b/compat/amd/amfsdkenc.h > @@ -0,0 +1,1755 @@ > ... > diff --git a/configure b/configure > index 3788f26..a562a2a 100755 > --- a/configure > +++ b/configure > @@ -303,6 +303,7 @@ External library support: > --disable-zlib disable zlib [autodetect] > > The following libraries provide various hardware acceleration features: > + --disable-amf disable AMF video encoding code [autodetect] > --disable-audiotoolbox disable Apple AudioToolbox code [autodetect] > --disable-cuda disable dynamically linked Nvidia CUDA code > [autodetect] > --enable-cuda-sdk enable CUDA features that require the CUDA SDK > [no] > @@ -1639,6 +1640,7 @@ EXTERNAL_LIBRARY_LIST=" > " > > HWACCEL_AUTODETECT_LIBRARY_LIST=" > + amf > audiotoolbox > crystalhd > cuda > @@ -2781,12 +2783,15 @@ scale_npp_filter_deps="cuda libnpp" > scale_cuda_filter_deps="cuda_sdk" > thumbnail_cuda_filter_deps="cuda_sdk" > > +amf_deps_any="libdl LoadLibrary" > + > nvenc_deps="cuda" > nvenc_deps_any="libdl LoadLibrary" > nvenc_encoder_deps="nvenc" > > h263_v4l2m2m_decoder_deps="v4l2_m2m h263_v4l2_m2m" > h263_v4l2m2m_encoder_deps="v4l2_m2m h263_v4l2_m2m" > +h264_amf_encoder_deps="amf" > h264_crystalhd_decoder_select="crystalhd h264_mp4toannexb_bsf h264_parser" > h264_cuvid_decoder_deps="cuvid" > h264_cuvid_decoder_select="h264_mp4toannexb_bsf" > @@ -2803,6 +2808,7 @@ > h264_vaapi_encoder_deps="VAEncPictureParameterBufferH264" > h264_vaapi_encoder_select="cbs_h264 vaapi_encode" > h264_v4l2m2m_decoder_deps="v4l2_m2m h264_v4l2_m2m" > h264_v4l2m2m_encoder_deps="v4l2_m2m h264_v4l2_m2m" > +hevc_amf_encoder_deps="amf" > hevc_cuvid_decoder_deps="cuvid" > hevc_cuvid_decoder_select="hevc_mp4toannexb_bsf" > hevc_mediacodec_decoder_deps="mediacodec" > @@ -6164,9 +6170,12 @@ if enabled x86; then > mingw32*|mingw64*|win32|win64|linux|cygwin*) > ;; > *) > - disable cuda cuvid nvdec nvenc > + disable cuda cuvid nvdec nvenc amf > ;; > esac > + if test $target_os = "linux"; then > + disable amf > + fi > else > disable cuda cuvid nvdec nvenc amf here too? > fi > @@ -6179,6 +6188,13 @@ void f(void) { struct { const GUID guid; } s[] = { { > NV_ENC_PRESET_HQ_GUID } }; > int main(void) { return 0; } > EOF > > +enabled amf && > + check_cc -I$source_path <<EOF || disable amf > +#include "compat/amd/amfsdkenc.h" > +AMFFactory *factory; > +int main(void) { return 0; } > +EOF > + > # Funny iconv installations are not unusual, so check it after all flags > have been set > if enabled libc_iconv; then > check_func_headers iconv.h iconv > diff --git a/libavcodec/Makefile b/libavcodec/Makefile > index 2476aec..9bbb60e 100644 > --- a/libavcodec/Makefile > +++ b/libavcodec/Makefile > @@ -55,6 +55,7 @@ OBJS = ac3_parser.o > \ > OBJS-$(CONFIG_AANDCTTABLES) += aandcttab.o > OBJS-$(CONFIG_AC3DSP) += ac3dsp.o ac3.o ac3tab.o > OBJS-$(CONFIG_ADTS_HEADER) += adts_header.o mpeg4audio.o > +OBJS-$(CONFIG_AMF) += amfenc.o > OBJS-$(CONFIG_AUDIO_FRAME_QUEUE) += audio_frame_queue.o > OBJS-$(CONFIG_AUDIODSP) += audiodsp.o > OBJS-$(CONFIG_BLOCKDSP) += blockdsp.o > @@ -332,6 +333,7 @@ OBJS-$(CONFIG_H263_ENCODER) += mpeg4videoenc.o > mpeg4video.o \ > h263.o ituh263enc.o flvenc.o > h263data.o > OBJS-$(CONFIG_H263_V4L2M2M_DECODER) += v4l2_m2m_dec.o > OBJS-$(CONFIG_H263_V4L2M2M_ENCODER) += v4l2_m2m_enc.o > +OBJS-$(CONFIG_H264_AMF_ENCODER) += amfenc_h264.o > OBJS-$(CONFIG_H264_DECODER) += h264dec.o h264_cabac.o > h264_cavlc.o \ > h264_direct.o h264_loopfilter.o \ > h264_mb.o h264_picture.o \ > @@ -353,6 +355,7 @@ OBJS-$(CONFIG_H264_V4L2M2M_DECODER) += v4l2_m2m_dec.o > OBJS-$(CONFIG_H264_V4L2M2M_ENCODER) += v4l2_m2m_enc.o > OBJS-$(CONFIG_HAP_DECODER) += hapdec.o hap.o > OBJS-$(CONFIG_HAP_ENCODER) += hapenc.o hap.o > +OBJS-$(CONFIG_HEVC_AMF_ENCODER) += amfenc_hevc.o > OBJS-$(CONFIG_HEVC_DECODER) += hevcdec.o hevc_mvs.o \ > hevc_cabac.o hevc_refs.o > hevcpred.o \ > hevcdsp.o hevc_filter.o hevc_data.o > @@ -1059,6 +1062,7 @@ SKIPHEADERS += %_tablegen.h > \ > aacenc_quantization_misc.h \ > $(ARCH)/vp56_arith.h \ > > +SKIPHEADERS-$(CONFIG_AMF) += amfenc.h > SKIPHEADERS-$(CONFIG_D3D11VA) += d3d11va.h dxva2_internal.h > SKIPHEADERS-$(CONFIG_DXVA2) += dxva2.h dxva2_internal.h > SKIPHEADERS-$(CONFIG_JNI) += ffjni.h > diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c > index 0781862..20c19ec 100644 > --- a/libavcodec/allcodecs.c > +++ b/libavcodec/allcodecs.c > @@ -653,6 +653,7 @@ static void register_all(void) > * above is available */ > REGISTER_ENCODER(H263_V4L2M2M, h263_v4l2m2m); > REGISTER_ENCDEC (LIBOPENH264, libopenh264); > + REGISTER_ENCODER(H264_AMF, h264_amf); > REGISTER_DECODER(H264_CUVID, h264_cuvid); > REGISTER_ENCODER(H264_NVENC, h264_nvenc); > REGISTER_ENCODER(H264_OMX, h264_omx); > @@ -665,6 +666,7 @@ static void register_all(void) > REGISTER_ENCODER(NVENC_H264, nvenc_h264); > REGISTER_ENCODER(NVENC_HEVC, nvenc_hevc); > #endif > + REGISTER_ENCODER(HEVC_AMF, hevc_amf); > REGISTER_DECODER(HEVC_CUVID, hevc_cuvid); > REGISTER_DECODER(HEVC_MEDIACODEC, hevc_mediacodec); > REGISTER_ENCODER(HEVC_NVENC, hevc_nvenc); > diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c > new file mode 100644 > index 0000000..6b23f64 > --- /dev/null > +++ b/libavcodec/amfenc.c > @@ -0,0 +1,596 @@ > +/* > + * This file is part of FFmpeg. > + * > + * FFmpeg is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * FFmpeg is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with FFmpeg; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + */ > + > +#include "libavutil/avassert.h" > +#include "libavutil/imgutils.h" > +#include "libavutil/hwcontext.h" > +#if CONFIG_D3D11VA > +#include "libavutil/hwcontext_d3d11va.h" > +#endif > +#include "libavutil/mem.h" > +#include "libavutil/pixdesc.h" > +#include "libavutil/time.h" > + > +#include "amfenc.h" > +#include "internal.h" > + > +#if CONFIG_D3D11VA > +#include <d3d11.h> > +#endif > + > +#ifdef _WIN32 > +#include "compat/w32dlfcn.h" > +#else > +#include <dlfcn.h> > +#endif > + > +#define FFMPEG_AMF_WRITER_ID L"ffmpeg_amf" > + > +#define PTS_PROP L"PtsProp" > + > +const enum AVPixelFormat ff_amf_pix_fmts[] = { > + AV_PIX_FMT_NV12, > + AV_PIX_FMT_YUV420P, > + AV_PIX_FMT_D3D11, > + AV_PIX_FMT_NONE > +}; > + > +typedef struct FormatMap { > + enum AVPixelFormat av_format; > + enum AMF_SURFACE_FORMAT amf_format; > +} FormatMap; > + > +static const FormatMap format_map[] = > +{ > + { AV_PIX_FMT_NONE, AMF_SURFACE_UNKNOWN }, > + { AV_PIX_FMT_NV12, AMF_SURFACE_NV12 }, > + { AV_PIX_FMT_BGR0, AMF_SURFACE_BGRA }, > + { AV_PIX_FMT_RGB0, AMF_SURFACE_RGBA }, > + { AV_PIX_FMT_GRAY8, AMF_SURFACE_GRAY8 }, > + { AV_PIX_FMT_YUV420P, AMF_SURFACE_YUV420P }, > + { AV_PIX_FMT_YUYV422, AMF_SURFACE_YUY2 }, > + { AV_PIX_FMT_D3D11, AMF_SURFACE_NV12 }, > +}; > + > + > +static int is_hwaccel_pix_fmt(enum AVPixelFormat pix_fmt) > +{ > + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); > + return desc->flags & AV_PIX_FMT_FLAG_HWACCEL; > +} > + > + > +static enum AMF_SURFACE_FORMAT amf_av_to_amf_format(enum AVPixelFormat fmt) > +{ > + int i; > + for (i = 0; i < amf_countof(format_map); i++) { > + if (format_map[i].av_format == fmt) { > + return format_map[i].amf_format; > + } > + } > + return AMF_SURFACE_UNKNOWN; > +} > + > +static void AMF_CDECL_CALL AMFTraceWriter_Write(AMFTraceWriter *pThis, > + const wchar_t *scope, const wchar_t *message) > +{ > + AmfTraceWriter *tracer = (AmfTraceWriter*)pThis; > + av_log(tracer->avctx, AV_LOG_DEBUG, "%ls: %ls", scope, message); // \n > is provided from AMF > +} > + > +static void AMF_CDECL_CALL AMFTraceWriter_Flush(AMFTraceWriter *pThis) > +{ > +} > + > +static AMFTraceWriterVtbl tracer_vtbl = > +{ > + .Write = AMFTraceWriter_Write, > + .Flush = AMFTraceWriter_Flush, > +}; > + > +static int amf_load_library(AVCodecContext *avctx) > +{ > + AmfContext *ctx = avctx->priv_data; > + AMFInit_Fn init_fun = NULL; > + AMFQueryVersion_Fn version_fun = NULL; > + AMF_RESULT res = AMF_OK; > + > + ctx->eof = 0; > + ctx->delayed_drain = 0; > + ctx->hw_frames_ctx = NULL; > + ctx->hw_device_ctx = NULL; > + ctx->delayed_surface = NULL; > + ctx->delayed_frame = av_frame_alloc(); > + if (!ctx->delayed_frame) { > + return AVERROR(ENOMEM); > + } > + // hardcoded to current HW queue size - will realloc in > timestamp_queue_enqueue() if too small > + ctx->timestamp_list = av_fifo_alloc((avctx->max_b_frames + 16) * > sizeof(int64_t)); > + if (!ctx->timestamp_list) { > + return AVERROR(ENOMEM); > + } > + ctx->dts_delay = 0; > + > + > + ctx->library = dlopen(AMF_DLL_NAMEA, RTLD_NOW | RTLD_LOCAL); > + AMF_RETURN_IF_FALSE(ctx, ctx->library != NULL, > + AVERROR_UNKNOWN, "DLL %s failed to open\n", AMF_DLL_NAMEA); > + > + init_fun = (AMFInit_Fn)dlsym(ctx->library, AMF_INIT_FUNCTION_NAME); > + AMF_RETURN_IF_FALSE(ctx, init_fun != NULL, AVERROR_UNKNOWN, "DLL %s > failed to find function %s\n", AMF_DLL_NAMEA, AMF_INIT_FUNCTION_NAME); > + > + version_fun = (AMFQueryVersion_Fn)dlsym(ctx->library, > AMF_QUERY_VERSION_FUNCTION_NAME); > + AMF_RETURN_IF_FALSE(ctx, version_fun != NULL, AVERROR_UNKNOWN, "DLL %s > failed to find function %s\n", AMF_DLL_NAMEA, > AMF_QUERY_VERSION_FUNCTION_NAME); > + > + res = version_fun(&ctx->version); > + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with > error %d\n", AMF_QUERY_VERSION_FUNCTION_NAME, res); > + res = init_fun(AMF_FULL_VERSION, &ctx->factory); > + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with > error %d\n", AMF_INIT_FUNCTION_NAME, res); > + res = ctx->factory->pVtbl->GetTrace(ctx->factory, &ctx->trace); > + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetTrace() > failed with error %d\n", res); > + res = ctx->factory->pVtbl->GetDebug(ctx->factory, &ctx->debug); > + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetDebug() > failed with error %d\n", res); > + return 0; > +} > + > +static int amf_init_context(AVCodecContext *avctx) > +{ > + AmfContext *ctx = avctx->priv_data; > + AMF_RESULT res = AMF_OK; > + > + // confugure AMF logger > + // the return of these functions indicates old state and do not affect > behaviour > + ctx->trace->pVtbl->EnableWriter(ctx->trace, > AMF_TRACE_WRITER_DEBUG_OUTPUT, ctx->log_to_dbg != 0 ); > + if (ctx->log_to_dbg) > + ctx->trace->pVtbl->SetWriterLevel(ctx->trace, > AMF_TRACE_WRITER_DEBUG_OUTPUT, AMF_TRACE_TRACE); > + ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_CONSOLE, 0); > + ctx->trace->pVtbl->SetGlobalLevel(ctx->trace, AMF_TRACE_TRACE); > + > + // connect AMF logger to av_log > + ctx->tracer.vtbl = &tracer_vtbl; > + ctx->tracer.avctx = avctx; > + ctx->trace->pVtbl->RegisterWriter(ctx->trace, > FFMPEG_AMF_WRITER_ID,(AMFTraceWriter*)&ctx->tracer, 1); > + ctx->trace->pVtbl->SetWriterLevel(ctx->trace, FFMPEG_AMF_WRITER_ID, > AMF_TRACE_TRACE); > + > + res = ctx->factory->pVtbl->CreateContext(ctx->factory, &ctx->context); > + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, > "CreateContext() failed with error %d\n", res); > + // try to reuse existing DX device > +#if CONFIG_D3D11VA > + if (avctx->hw_frames_ctx) { > + AVHWFramesContext *device_ctx = > (AVHWFramesContext*)avctx->hw_frames_ctx->data; > + if (device_ctx->device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA){ > + if (amf_av_to_amf_format(device_ctx->sw_format) != > AMF_SURFACE_UNKNOWN) { > + if (device_ctx->device_ctx->hwctx) { > + AVD3D11VADeviceContext *device_d3d11 = > (AVD3D11VADeviceContext *)device_ctx->device_ctx->hwctx; > + res = ctx->context->pVtbl->InitDX11(ctx->context, > device_d3d11->device, AMF_DX11_1); > + if (res == AMF_OK) { > + ctx->hw_frames_ctx = > av_buffer_ref(avctx->hw_frames_ctx); Return value should be checked. > + }else { > + if(res == AMF_NOT_SUPPORTED) > + av_log(avctx, AV_LOG_INFO, "amf_shared: > avctx->hw_frames_ctx has D3D11 device which doesn't have D3D11VA interface, > switching to default\n"); > + else > + av_log(avctx, AV_LOG_INFO, "amf_shared: > avctx->hw_frames_ctx has non-AMD device, switching to default\n"); > + } > + } > + }else { > + av_log(avctx, AV_LOG_INFO, "amf_shared: avctx->hw_frames_ctx > has format not uspported by AMF, switching to default\n"); > + } > + } > + } else if (avctx->hw_device_ctx) { > + AVHWDeviceContext *device_ctx = > (AVHWDeviceContext*)(avctx->hw_device_ctx->data); > + if (device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) { > + if (device_ctx->hwctx) { > + AVD3D11VADeviceContext *device_d3d11 = > (AVD3D11VADeviceContext *)device_ctx->hwctx; > + res = ctx->context->pVtbl->InitDX11(ctx->context, > device_d3d11->device, AMF_DX11_1); > + if (res == AMF_OK) { > + ctx->hw_device_ctx = av_buffer_ref(avctx->hw_device_ctx); And here. > + } else { > + if (res == AMF_NOT_SUPPORTED) > + av_log(avctx, AV_LOG_INFO, "amf_shared: > avctx->hw_device_ctx has D3D11 device which doesn't have D3D11VA interface, > switching to default\n"); > + else > + av_log(avctx, AV_LOG_INFO, "amf_shared: > avctx->hw_device_ctx has non-AMD device, switching to default\n"); I didn't notice this before, but the "amf_shared" tags probably aren't wanted - the logging context already carries where the message is coming from. > + } > + } > + } > + } > +#endif > + if (!ctx->hw_frames_ctx && !ctx->hw_device_ctx) { > + res = ctx->context->pVtbl->InitDX11(ctx->context, NULL, AMF_DX11_1); > + if (res != AMF_OK) { > + res = ctx->context->pVtbl->InitDX9(ctx->context, NULL); > + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, > "InitDX9() failed with error %d\n", res); > + } > + } > + return 0; > +} > + > +static int amf_init_encoder(AVCodecContext *avctx) > +{ > + AmfContext *ctx = avctx->priv_data; > + const wchar_t *codec_id = NULL; > + AMF_RESULT res = AMF_OK; > + > + switch (avctx->codec->id) { > + case AV_CODEC_ID_H264: > + codec_id = AMFVideoEncoderVCE_AVC; > + break; > + case AV_CODEC_ID_HEVC: > + codec_id = AMFVideoEncoder_HEVC; > + break; > + default: > + break; > + } > + AMF_RETURN_IF_FALSE(ctx, codec_id != NULL, AVERROR(EINVAL), "Codec %d is > not supported\n", avctx->codec->id); > + > + ctx->format = amf_av_to_amf_format(avctx->pix_fmt); > + AMF_RETURN_IF_FALSE(ctx, ctx->format != AMF_SURFACE_UNKNOWN, > AVERROR(EINVAL), "Format %d is not supported\n", avctx->pix_fmt); > + > + res = ctx->factory->pVtbl->CreateComponent(ctx->factory, ctx->context, > codec_id, &ctx->encoder); > + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_ENCODER_NOT_FOUND, > "CreateComponent(%ls) failed with error %d\n", codec_id, res); > + > + return 0; > +} > + > +int av_cold ff_amf_encode_close(AVCodecContext *avctx) > +{ > + AmfContext *ctx = avctx->priv_data; > + if (ctx->delayed_surface) > + { > + ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface); > + ctx->delayed_surface = NULL; > + } > + > + if (ctx->encoder) { > + ctx->encoder->pVtbl->Terminate(ctx->encoder); > + ctx->encoder->pVtbl->Release(ctx->encoder); > + ctx->encoder = NULL; > + } > + > + if (ctx->context) { > + ctx->context->pVtbl->Terminate(ctx->context); > + ctx->context->pVtbl->Release(ctx->context); > + ctx->context = NULL; > + } > + av_buffer_unref(&ctx->hw_device_ctx); > + av_buffer_unref(&ctx->hw_frames_ctx); > + > + if (ctx->trace) { > + ctx->trace->pVtbl->UnregisterWriter(ctx->trace, > FFMPEG_AMF_WRITER_ID); > + } > + if (ctx->library) { > + dlclose(ctx->library); > + ctx->library = NULL; > + } > + ctx->trace = NULL; > + ctx->debug = NULL; > + ctx->factory = NULL; > + ctx->version = 0; > + ctx->delayed_drain = 0; > + av_frame_free(&ctx->delayed_frame); > + av_fifo_freep(&ctx->timestamp_list); > + > + return 0; > +} > + > +static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame, > + AMFSurface* surface) > +{ > + AVFrame *sw_frame = NULL; > + AMFPlane *plane = NULL; > + uint8_t *dst_data[4]; > + int dst_linesize[4]; > + int ret = 0; > + int planes; > + > + if (frame->hw_frames_ctx && is_hwaccel_pix_fmt(frame->format)) { > + if (!(sw_frame = av_frame_alloc())) { > + av_log(avctx, AV_LOG_ERROR, "Can not alloc frame\n"); > + ret = AVERROR(ENOMEM); > + goto fail; > + } > + if ((ret = av_hwframe_transfer_data(sw_frame, frame, 0)) < 0) { > + av_log(avctx, AV_LOG_ERROR, "Error transferring the data to > system memory\n"); > + ret = AVERROR(EINVAL); ret is already set, no need to overwrite it. > + goto fail; > + } > + frame = sw_frame; > + } > + planes = (int)surface->pVtbl->GetPlanesCount(surface); > + if (planes > amf_countof(dst_data)) { > + av_log(avctx, AV_LOG_ERROR, "Invalid number of planes %d in > surface\n", planes); > + ret = AVERROR(EINVAL); > + goto fail; > + } > + > + for (int i = 0; i < planes; i++) { Declare at the start of the block. > + plane = surface->pVtbl->GetPlaneAt(surface, i); > + dst_data[i] = plane->pVtbl->GetNative(plane); > + dst_linesize[i] = plane->pVtbl->GetHPitch(plane); > + } > + av_image_copy(dst_data, dst_linesize, > + (const uint8_t**)frame->data, frame->linesize, frame->format, > + avctx->width, avctx->height); > + > +fail: > + if (sw_frame){ > + av_frame_free(&sw_frame); > + } > + return ret; > +} > + > +static inline int timestamp_queue_enqueue(AVCodecContext *avctx, int64_t > timestamp) > +{ > + AmfContext *ctx = avctx->priv_data; > + if (av_fifo_space(ctx->timestamp_list) < sizeof(timestamp)){ > + if (av_fifo_grow(ctx->timestamp_list, sizeof(timestamp)) < 0) { > + return AVERROR(ENOMEM); > + } > + } > + av_fifo_generic_write(ctx->timestamp_list, ×tamp, > sizeof(timestamp), NULL); > + return 0; > +} > + > +static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer > *buffer) > +{ > + AmfContext *ctx = avctx->priv_data; > + int ret; > + AMFVariantStruct var = {0}; > + int64_t timestamp = AV_NOPTS_VALUE; > + int64_t size = buffer->pVtbl->GetSize(buffer); > + > + if ((ret = ff_alloc_packet2(avctx, pkt, size, 0)) < 0) { > + return ret; > + } > + memcpy(pkt->data, buffer->pVtbl->GetNative(buffer), size); > + > + switch (avctx->codec->id) { > + case AV_CODEC_ID_H264: > + buffer->pVtbl->GetProperty(buffer, > AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE, &var); > + if(var.int64Value == AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_IDR) { > + pkt->flags = AV_PKT_FLAG_KEY; > + } > + break; > + case AV_CODEC_ID_HEVC: > + buffer->pVtbl->GetProperty(buffer, > AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE, &var); > + if (var.int64Value == > AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE_IDR) { > + pkt->flags = AV_PKT_FLAG_KEY; > + } > + break; > + default: > + break; > + } > + > + buffer->pVtbl->GetProperty(buffer, PTS_PROP, &var); > + > + pkt->pts = var.int64Value; // original pts > + > + > + AMF_RETURN_IF_FALSE(ctx, av_fifo_size(ctx->timestamp_list) > 0, > AVERROR_UNKNOWN, "timestamp_list is empty\n"); > + > + av_fifo_generic_read(ctx->timestamp_list, ×tamp, sizeof(timestamp), > NULL); > + > + // calc dts shift if max_b_frames > 0 > + if (avctx->max_b_frames > 0 && ctx->dts_delay == 0){ > + int64_t timestamp_last = AV_NOPTS_VALUE; > + AMF_RETURN_IF_FALSE(ctx, av_fifo_size(ctx->timestamp_list) > 0, > AVERROR_UNKNOWN, > + "timestamp_list is empty while max_b_frames = %d\n", > avctx->max_b_frames); > + av_fifo_generic_peek_at( > + ctx->timestamp_list, > + ×tamp_last, > + (av_fifo_size(ctx->timestamp_list) / sizeof(timestamp) - 1) * > sizeof(timestamp_last), > + sizeof(timestamp_last), Some trailing spaces here. > + NULL); > + if (timestamp < 0 || timestamp_last < AV_NOPTS_VALUE) { > + return AVERROR(ERANGE); > + } > + ctx->dts_delay = timestamp_last - timestamp; > + } > + pkt->dts = timestamp - ctx->dts_delay; > + return 0; > +} > ... _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel