From patchwork Sun Jan 8 18:13:52 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Thompson X-Patchwork-Id: 2113 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.89.21 with SMTP id n21csp6754044vsb; Sun, 8 Jan 2017 10:14:03 -0800 (PST) X-Received: by 10.223.166.106 with SMTP id k97mr10508335wrc.170.1483899243543; Sun, 08 Jan 2017 10:14:03 -0800 (PST) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id t3si67151613wjw.25.2017.01.08.10.14.03; Sun, 08 Jan 2017 10:14:03 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@jkqxz-net.20150623.gappssmtp.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 67C6568A56F; Sun, 8 Jan 2017 20:13:54 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm0-f48.google.com (mail-wm0-f48.google.com [74.125.82.48]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id C2F93689D47 for ; Sun, 8 Jan 2017 20:13:47 +0200 (EET) Received: by mail-wm0-f48.google.com with SMTP id c206so4495330wme.0 for ; Sun, 08 Jan 2017 10:13:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jkqxz-net.20150623.gappssmtp.com; s=20150623; h=subject:to:references:from:message-id:date:user-agent:mime-version :in-reply-to:content-transfer-encoding; bh=ik9dEvNaRsaBLz14wV78B4bFxpQcEy78W3NMDwma5fE=; b=l8jwVp2lvJFTIlXPHi1WMt4FFvWyVhc/ZPf3Z7tvvAdzdiJu36zdN5cA2zg0pL0464 vJr3CZOLBVUYm4Tcxazrzb0fcnRYUDa4CbfGf0rg2RoelhnkWBoFEF2zy0fNpR/mpiGp Xfd3vKHu9nDoHm1hoLlnxIBS5r+2XGkfIFnNtJV5B/SxstX/L3fT1neApQsJGyfIopeo ChNWF8kxyw5VprUUqkTgemc4ujwA/4Rt7TGXxq5BzrZEogJCf+kF90FjfWAM5kzEM/EC 3rozR27m982WG+ZfpLicjF6oHMemBz7FMv2cYHklMfXKrx+pdmBPGWTODEdDQ/hF3aKv zbQA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-transfer-encoding; bh=ik9dEvNaRsaBLz14wV78B4bFxpQcEy78W3NMDwma5fE=; b=N1/uVddxzF6q5RVvSzpVWhIEvFxquOcR8t5f5RemV7uJtZ1sXQYncp+FHPNCW5SyZ6 tw1eL04XU5kSm30d9JxXJXygolAaj/cKFe9zbcz7OiRMw+Tip3oXVMju7sw4ePOPABf+ pza/deDmjM6emzdndliQ8nm7FHV2C2aZcm1fmJ0IOJC0KJi1JHkLEpFiaeJTiaXPeMIh AGGZDS09kDioXbi3oTOVGYA17pmFyrf/+7cht0+wjEvd4IrjjwttJlkZEUOiI/GaJ7h4 13SSzeWF42dTjQOoHxA5gTWesLjq+K6vCNeADMRurEe/E87lxaPqeVkwPVUspQfJgGbi OtYw== X-Gm-Message-State: AIkVDXIwBS8hv22jDuYQ3ZYXIGbxd6vZpKdbwFFMy5CgbUDg0e9R9TuQZLF1QdSncnSHog== X-Received: by 10.28.188.9 with SMTP id m9mr2856184wmf.79.1483899233769; Sun, 08 Jan 2017 10:13:53 -0800 (PST) Received: from [192.168.0.8] (cpc91242-cmbg18-2-0-cust650.5-4.cable.virginm.net. [82.8.130.139]) by smtp.gmail.com with ESMTPSA id x188sm14601560wmx.4.2017.01.08.10.13.52 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 08 Jan 2017 10:13:53 -0800 (PST) To: FFmpeg development discussions and patches References: <320e2652-f3d9-5509-11ac-fbd84e22db6a@jkqxz.net> From: Mark Thompson Message-ID: <46b874aa-7da6-ae25-a54b-b19c93ec92cc@jkqxz.net> Date: Sun, 8 Jan 2017 18:13:52 +0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Icedove/45.4.0 MIME-Version: 1.0 In-Reply-To: <320e2652-f3d9-5509-11ac-fbd84e22db6a@jkqxz.net> Subject: [FFmpeg-devel] [PATCH 12/16] ffmpeg_vaapi: Convert to use hw_frames_ctx only X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Most of the functionality here has moved into lavc. (cherry picked from commit 3e8651a7ccd8e89cc2f162cf614a3c9f7f4d9fcf) --- ffmpeg_vaapi.c | 353 ++++----------------------------------------------------- 1 file changed, 23 insertions(+), 330 deletions(-) diff --git a/ffmpeg_vaapi.c b/ffmpeg_vaapi.c index f1e7c76f38..b9ad7adee9 100644 --- a/ffmpeg_vaapi.c +++ b/ffmpeg_vaapi.c @@ -18,28 +18,10 @@ #include "config.h" -#include -#include - -#include -#if HAVE_VAAPI_X11 -# include -#endif -#if HAVE_VAAPI_DRM -# include -#endif - #include "libavutil/avassert.h" -#include "libavutil/avconfig.h" -#include "libavutil/buffer.h" #include "libavutil/frame.h" #include "libavutil/hwcontext.h" -#include "libavutil/hwcontext_vaapi.h" -#include "libavutil/imgutils.h" -#include "libavutil/opt.h" -#include "libavutil/pixfmt.h" - -#include "libavcodec/vaapi.h" +#include "libavutil/log.h" #include "ffmpeg.h" @@ -60,23 +42,11 @@ typedef struct VAAPIDecoderContext { AVBufferRef *frames_ref; AVHWFramesContext *frames; - VAProfile va_profile; - VAEntrypoint va_entrypoint; - VAConfigID va_config; - VAContextID va_context; - - enum AVPixelFormat decode_format; - int decode_width; - int decode_height; - int decode_surfaces; - // The output need not have the same format, width and height as the // decoded frames - the copy for non-direct-mapped access is actually // a whole vpp instance which can do arbitrary scaling and format // conversion. enum AVPixelFormat output_format; - - struct vaapi_context decoder_vaapi_context; } VAAPIDecoderContext; @@ -144,257 +114,12 @@ fail: return err; } - -static const struct { - enum AVCodecID codec_id; - int codec_profile; - VAProfile va_profile; -} vaapi_profile_map[] = { -#define MAP(c, p, v) { AV_CODEC_ID_ ## c, FF_PROFILE_ ## p, VAProfile ## v } - MAP(MPEG2VIDEO, MPEG2_SIMPLE, MPEG2Simple ), - MAP(MPEG2VIDEO, MPEG2_MAIN, MPEG2Main ), - MAP(H263, UNKNOWN, H263Baseline), - MAP(MPEG4, MPEG4_SIMPLE, MPEG4Simple ), - MAP(MPEG4, MPEG4_ADVANCED_SIMPLE, - MPEG4AdvancedSimple), - MAP(MPEG4, MPEG4_MAIN, MPEG4Main ), - MAP(H264, H264_CONSTRAINED_BASELINE, - H264ConstrainedBaseline), - MAP(H264, H264_BASELINE, H264Baseline), - MAP(H264, H264_MAIN, H264Main ), - MAP(H264, H264_HIGH, H264High ), -#if VA_CHECK_VERSION(0, 37, 0) - MAP(HEVC, HEVC_MAIN, HEVCMain ), -#endif - MAP(WMV3, VC1_SIMPLE, VC1Simple ), - MAP(WMV3, VC1_MAIN, VC1Main ), - MAP(WMV3, VC1_COMPLEX, VC1Advanced ), - MAP(WMV3, VC1_ADVANCED, VC1Advanced ), - MAP(VC1, VC1_SIMPLE, VC1Simple ), - MAP(VC1, VC1_MAIN, VC1Main ), - MAP(VC1, VC1_COMPLEX, VC1Advanced ), - MAP(VC1, VC1_ADVANCED, VC1Advanced ), -#if VA_CHECK_VERSION(0, 35, 0) - MAP(VP8, UNKNOWN, VP8Version0_3 ), -#endif -#if VA_CHECK_VERSION(0, 37, 1) - MAP(VP9, VP9_0, VP9Profile0 ), -#endif -#undef MAP -}; - -static int vaapi_build_decoder_config(VAAPIDecoderContext *ctx, - AVCodecContext *avctx, - int fallback_allowed) -{ - AVVAAPIDeviceContext *hwctx = ctx->device->hwctx; - AVVAAPIHWConfig *hwconfig = NULL; - AVHWFramesConstraints *constraints = NULL; - VAStatus vas; - int err, i, j; - int loglevel = fallback_allowed ? AV_LOG_VERBOSE : AV_LOG_ERROR; - const AVCodecDescriptor *codec_desc; - const AVPixFmtDescriptor *pix_desc; - enum AVPixelFormat pix_fmt; - VAProfile profile, *profile_list = NULL; - int profile_count, exact_match, alt_profile; - - codec_desc = avcodec_descriptor_get(avctx->codec_id); - if (!codec_desc) { - err = AVERROR(EINVAL); - goto fail; - } - - profile_count = vaMaxNumProfiles(hwctx->display); - profile_list = av_malloc(profile_count * sizeof(VAProfile)); - if (!profile_list) { - err = AVERROR(ENOMEM); - goto fail; - } - - vas = vaQueryConfigProfiles(hwctx->display, - profile_list, &profile_count); - if (vas != VA_STATUS_SUCCESS) { - av_log(ctx, loglevel, "Failed to query profiles: %d (%s).\n", - vas, vaErrorStr(vas)); - err = AVERROR(EIO); - goto fail; - } - - profile = VAProfileNone; - exact_match = 0; - - for (i = 0; i < FF_ARRAY_ELEMS(vaapi_profile_map); i++) { - int profile_match = 0; - if (avctx->codec_id != vaapi_profile_map[i].codec_id) - continue; - if (avctx->profile == vaapi_profile_map[i].codec_profile) - profile_match = 1; - profile = vaapi_profile_map[i].va_profile; - for (j = 0; j < profile_count; j++) { - if (profile == profile_list[j]) { - exact_match = profile_match; - break; - } - } - if (j < profile_count) { - if (exact_match) - break; - alt_profile = vaapi_profile_map[i].codec_profile; - } - } - av_freep(&profile_list); - - if (profile == VAProfileNone) { - av_log(ctx, loglevel, "No VAAPI support for codec %s.\n", - codec_desc->name); - err = AVERROR(ENOSYS); - goto fail; - } - if (!exact_match) { - if (fallback_allowed || !hwaccel_lax_profile_check) { - av_log(ctx, loglevel, "No VAAPI support for codec %s " - "profile %d.\n", codec_desc->name, avctx->profile); - if (!fallback_allowed) { - av_log(ctx, AV_LOG_WARNING, "If you want attempt decoding " - "anyway with a possibly-incompatible profile, add " - "the option -hwaccel_lax_profile_check.\n"); - } - err = AVERROR(EINVAL); - goto fail; - } else { - av_log(ctx, AV_LOG_WARNING, "No VAAPI support for codec %s " - "profile %d: trying instead with profile %d.\n", - codec_desc->name, avctx->profile, alt_profile); - av_log(ctx, AV_LOG_WARNING, "This may fail or give " - "incorrect results, depending on your hardware.\n"); - } - } - - ctx->va_profile = profile; - ctx->va_entrypoint = VAEntrypointVLD; - - vas = vaCreateConfig(hwctx->display, ctx->va_profile, - ctx->va_entrypoint, 0, 0, &ctx->va_config); - if (vas != VA_STATUS_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Failed to create decode pipeline " - "configuration: %d (%s).\n", vas, vaErrorStr(vas)); - err = AVERROR(EIO); - goto fail; - } - - hwconfig = av_hwdevice_hwconfig_alloc(ctx->device_ref); - if (!hwconfig) { - err = AVERROR(ENOMEM); - goto fail; - } - hwconfig->config_id = ctx->va_config; - - constraints = av_hwdevice_get_hwframe_constraints(ctx->device_ref, - hwconfig); - if (!constraints) - goto fail; - - // Decide on the decoder target format. - // If the user specified something with -hwaccel_output_format then - // try to use that to minimise conversions later. - ctx->decode_format = AV_PIX_FMT_NONE; - if (ctx->output_format != AV_PIX_FMT_NONE && - ctx->output_format != AV_PIX_FMT_VAAPI) { - for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) { - if (constraints->valid_sw_formats[i] == ctx->output_format) { - ctx->decode_format = ctx->output_format; - av_log(ctx, AV_LOG_DEBUG, "Using decode format %s (output " - "format).\n", av_get_pix_fmt_name(ctx->decode_format)); - break; - } - } - } - // Otherwise, we would like to try to choose something which matches the - // decoder output, but there isn't enough information available here to - // do so. Assume for now that we are always dealing with YUV 4:2:0, so - // pick a format which does that. - if (ctx->decode_format == AV_PIX_FMT_NONE) { - for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) { - pix_fmt = constraints->valid_sw_formats[i]; - pix_desc = av_pix_fmt_desc_get(pix_fmt); - if (pix_desc->nb_components == 3 && - pix_desc->log2_chroma_w == 1 && - pix_desc->log2_chroma_h == 1) { - ctx->decode_format = pix_fmt; - av_log(ctx, AV_LOG_DEBUG, "Using decode format %s (format " - "matched).\n", av_get_pix_fmt_name(ctx->decode_format)); - break; - } - } - } - // Otherwise pick the first in the list and hope for the best. - if (ctx->decode_format == AV_PIX_FMT_NONE) { - ctx->decode_format = constraints->valid_sw_formats[0]; - av_log(ctx, AV_LOG_DEBUG, "Using decode format %s (first in list).\n", - av_get_pix_fmt_name(ctx->decode_format)); - if (i > 1) { - // There was a choice, and we picked randomly. Warn the user - // that they might want to choose intelligently instead. - av_log(ctx, AV_LOG_WARNING, "Using randomly chosen decode " - "format %s.\n", av_get_pix_fmt_name(ctx->decode_format)); - } - } - - // Ensure the picture size is supported by the hardware. - ctx->decode_width = avctx->coded_width; - ctx->decode_height = avctx->coded_height; - if (ctx->decode_width < constraints->min_width || - ctx->decode_height < constraints->min_height || - ctx->decode_width > constraints->max_width || - ctx->decode_height >constraints->max_height) { - av_log(ctx, AV_LOG_ERROR, "VAAPI hardware does not support image " - "size %dx%d (constraints: width %d-%d height %d-%d).\n", - ctx->decode_width, ctx->decode_height, - constraints->min_width, constraints->max_width, - constraints->min_height, constraints->max_height); - err = AVERROR(EINVAL); - goto fail; - } - - av_hwframe_constraints_free(&constraints); - av_freep(&hwconfig); - - // Decide how many reference frames we need. This might be doable more - // nicely based on the codec and input stream? - ctx->decode_surfaces = DEFAULT_SURFACES; - // For frame-threaded decoding, one additional surfaces is needed for - // each thread. - if (avctx->active_thread_type & FF_THREAD_FRAME) - ctx->decode_surfaces += avctx->thread_count; - - return 0; - -fail: - av_hwframe_constraints_free(&constraints); - av_freep(&hwconfig); - vaDestroyConfig(hwctx->display, ctx->va_config); - av_freep(&profile_list); - return err; -} - static void vaapi_decode_uninit(AVCodecContext *avctx) { InputStream *ist = avctx->opaque; VAAPIDecoderContext *ctx = ist->hwaccel_ctx; if (ctx) { - AVVAAPIDeviceContext *hwctx = ctx->device->hwctx; - - if (ctx->va_context != VA_INVALID_ID) { - vaDestroyContext(hwctx->display, ctx->va_context); - ctx->va_context = VA_INVALID_ID; - } - if (ctx->va_config != VA_INVALID_ID) { - vaDestroyConfig(hwctx->display, ctx->va_config); - ctx->va_config = VA_INVALID_ID; - } - av_buffer_unref(&ctx->frames_ref); av_buffer_unref(&ctx->device_ref); av_free(ctx); @@ -402,19 +127,16 @@ static void vaapi_decode_uninit(AVCodecContext *avctx) av_buffer_unref(&ist->hw_frames_ctx); - ist->hwaccel_ctx = 0; - ist->hwaccel_uninit = 0; - ist->hwaccel_get_buffer = 0; - ist->hwaccel_retrieve_data = 0; + ist->hwaccel_ctx = NULL; + ist->hwaccel_uninit = NULL; + ist->hwaccel_get_buffer = NULL; + ist->hwaccel_retrieve_data = NULL; } int vaapi_decode_init(AVCodecContext *avctx) { InputStream *ist = avctx->opaque; - AVVAAPIDeviceContext *hwctx; - AVVAAPIFramesContext *avfc; VAAPIDecoderContext *ctx; - VAStatus vas; int err; int loglevel = (ist->hwaccel_id != HWACCEL_VAAPI ? AV_LOG_VERBOSE : AV_LOG_ERROR); @@ -439,20 +161,7 @@ int vaapi_decode_init(AVCodecContext *avctx) ctx->device_ref = av_buffer_ref(hw_device_ctx); ctx->device = (AVHWDeviceContext*)ctx->device_ref->data; - ctx->va_config = VA_INVALID_ID; - ctx->va_context = VA_INVALID_ID; - - hwctx = ctx->device->hwctx; - ctx->output_format = ist->hwaccel_output_format; - - err = vaapi_build_decoder_config(ctx, avctx, - ist->hwaccel_id != HWACCEL_VAAPI); - if (err < 0) { - av_log(ctx, loglevel, "No supported configuration for this codec."); - goto fail; - } - avctx->pix_fmt = ctx->output_format; ctx->frames_ref = av_hwframe_ctx_alloc(ctx->device_ref); @@ -464,11 +173,21 @@ int vaapi_decode_init(AVCodecContext *avctx) ctx->frames = (AVHWFramesContext*)ctx->frames_ref->data; - ctx->frames->format = AV_PIX_FMT_VAAPI; - ctx->frames->sw_format = ctx->decode_format; - ctx->frames->width = ctx->decode_width; - ctx->frames->height = ctx->decode_height; - ctx->frames->initial_pool_size = ctx->decode_surfaces; + ctx->frames->format = AV_PIX_FMT_VAAPI; + ctx->frames->width = avctx->coded_width; + ctx->frames->height = avctx->coded_height; + + // It would be nice if we could query the available formats here, + // but unfortunately we don't have a VAConfigID to do it with. + // For now, just assume an NV12 format (or P010 if 10-bit). + ctx->frames->sw_format = (avctx->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ? + AV_PIX_FMT_P010 : AV_PIX_FMT_NV12); + + // For frame-threaded decoding, at least one additional surface + // is needed for each thread. + ctx->frames->initial_pool_size = DEFAULT_SURFACES; + if (avctx->active_thread_type & FF_THREAD_FRAME) + ctx->frames->initial_pool_size += avctx->thread_count; err = av_hwframe_ctx_init(ctx->frames_ref); if (err < 0) { @@ -477,27 +196,6 @@ int vaapi_decode_init(AVCodecContext *avctx) goto fail; } - avfc = ctx->frames->hwctx; - - vas = vaCreateContext(hwctx->display, ctx->va_config, - ctx->decode_width, ctx->decode_height, - VA_PROGRESSIVE, - avfc->surface_ids, avfc->nb_surfaces, - &ctx->va_context); - if (vas != VA_STATUS_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Failed to create decode pipeline " - "context: %d (%s).\n", vas, vaErrorStr(vas)); - err = AVERROR(EINVAL); - goto fail; - } - - av_log(ctx, AV_LOG_DEBUG, "VAAPI decoder (re)init complete.\n"); - - // We would like to set this on the AVCodecContext for use by whoever gets - // the frames from the decoder, but unfortunately the AVCodecContext we - // have here need not be the "real" one (H.264 makes many copies for - // threading purposes). To avoid the problem, we instead store it in the - // InputStream and propagate it from there. ist->hw_frames_ctx = av_buffer_ref(ctx->frames_ref); if (!ist->hw_frames_ctx) { err = AVERROR(ENOMEM); @@ -505,14 +203,9 @@ int vaapi_decode_init(AVCodecContext *avctx) } ist->hwaccel_ctx = ctx; - ist->hwaccel_uninit = vaapi_decode_uninit; - ist->hwaccel_get_buffer = vaapi_get_buffer; - ist->hwaccel_retrieve_data = vaapi_retrieve_data; - - ctx->decoder_vaapi_context.display = hwctx->display; - ctx->decoder_vaapi_context.config_id = ctx->va_config; - ctx->decoder_vaapi_context.context_id = ctx->va_context; - avctx->hwaccel_context = &ctx->decoder_vaapi_context; + ist->hwaccel_uninit = &vaapi_decode_uninit; + ist->hwaccel_get_buffer = &vaapi_get_buffer; + ist->hwaccel_retrieve_data = &vaapi_retrieve_data; return 0;