Bug 1660336 Add VP8/VP9 VAAPI HW decode code to bundled ffvpx and build it with MOZ_WAYLAND target, r=jya

- Update in-tree ffvpx library with VP8/VP9 VAAPI HW decode code from FFmpeg 4.2.
- Enable VP8/VP9 VAAPI HW decode on MOZ_WAYLAND target.

Differential Revision: https://phabricator.services.mozilla.com/D90554
This commit is contained in:
Martin Stransky 2020-12-04 09:41:38 +00:00
Родитель df75ae580c
Коммит 6780cbc0cd
15 изменённых файлов: 3220 добавлений и 0 удалений

Просмотреть файл

@ -131,6 +131,11 @@
./libavcodec/thread.h
./libavcodec/unary.h
./libavcodec/utils.c
./libavcodec/vaapi.h
./libavcodec/vaapi_decode.h
./libavcodec/vaapi_decode.c
./libavcodec/vaapi_vp8.c
./libavcodec/vaapi_vp9.c
./libavcodec/version.h
./libavcodec/videodsp.c
./libavcodec/videodsp.h
@ -264,6 +269,8 @@
./libavutil/hwcontext.c
./libavutil/hwcontext.h
./libavutil/hwcontext_internal.h
./libavutil/hwcontext_vaapi.h
./libavutil/hwcontext_vaapi.c
./libavutil/imgutils.c
./libavutil/imgutils.h
./libavutil/imgutils_internal.h

Просмотреть файл

@ -56,3 +56,5 @@ $ for i in `cat $PATH_CENTRAL/media/ffvpx/FILES`; do git diff $REV_LASTSYNC HEAD
Then apply patch.diff on the ffvpx tree.
Compilation will reveal if any files are missing.
Apply linux-vaapi-build.patch patch to enable build VA-API support for Linux.

Просмотреть файл

@ -50,3 +50,27 @@ index 9fb8d0a..97ad3b9 100644
rgba_color[0] = rgba >> 24;
rgba_color[1] = rgba >> 16;
rgba_color[2] = rgba >> 8;
diff --git a/media/ffvpx/libavutil/hwcontext_vaapi.c b/media/ffvpx/libavutil/hwcontext_vaapi.c
--- a/media/ffvpx/libavutil/hwcontext_vaapi.c
+++ b/media/ffvpx/libavutil/hwcontext_vaapi.c
@@ -39,17 +39,19 @@
# include <unistd.h>
#endif
#include "avassert.h"
#include "buffer.h"
#include "common.h"
#include "hwcontext.h"
+#if CONFIG_LIBDRM
#include "hwcontext_drm.h"
+#endif
#include "hwcontext_internal.h"
#include "hwcontext_vaapi.h"
#include "mem.h"
#include "pixdesc.h"
#include "pixfmt.h"
typedef struct VAAPIDevicePriv {

Просмотреть файл

@ -18,4 +18,13 @@
#define CONFIG_RDFT 1
#endif
#ifdef MOZ_WAYLAND
#undef CONFIG_VAAPI
#undef CONFIG_VP8_VAAPI_HWACCEL
#undef CONFIG_VP9_VAAPI_HWACCEL
#define CONFIG_VAAPI 1
#define CONFIG_VP8_VAAPI_HWACCEL 1
#define CONFIG_VP9_VAAPI_HWACCEL 1
#endif
#endif

Просмотреть файл

@ -28,6 +28,11 @@ av_get_pcm_codec
av_get_profile_name
av_grow_packet
av_hwaccel_next
av_hwdevice_ctx_init
av_hwdevice_ctx_alloc
av_hwdevice_ctx_create_derived
av_hwframe_transfer_get_formats
av_hwframe_ctx_alloc
av_init_packet
av_lockmgr_register
av_new_packet
@ -93,6 +98,7 @@ avcodec_free_context
avcodec_get_class
avcodec_get_context_defaults3
avcodec_get_frame_class
avcodec_get_hw_config
avcodec_get_name
avcodec_get_subtitle_rect_class
avcodec_get_type

Просмотреть файл

@ -96,6 +96,13 @@ if not CONFIG['MOZ_FFVPX_AUDIOONLY']:
'vp9prob.c',
'vp9recon.c'
]
if CONFIG['MOZ_WAYLAND']:
SOURCES += [
'vaapi_decode.c',
'vaapi_vp8.c',
'vaapi_vp9.c',
]
USE_LIBS += ['mozva']
if CONFIG['MOZ_LIBAV_FFT']:
SOURCES += [

Просмотреть файл

@ -0,0 +1,86 @@
/*
* Video Acceleration API (shared data between FFmpeg and the video player)
* HW decode acceleration for MPEG-2, MPEG-4, H.264 and VC-1
*
* Copyright (C) 2008-2009 Splitted-Desktop Systems
*
* 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
*/
#ifndef AVCODEC_VAAPI_H
#define AVCODEC_VAAPI_H
/**
* @file
* @ingroup lavc_codec_hwaccel_vaapi
* Public libavcodec VA API header.
*/
#include <stdint.h>
#include "libavutil/attributes.h"
#include "version.h"
#if FF_API_STRUCT_VAAPI_CONTEXT
/**
* @defgroup lavc_codec_hwaccel_vaapi VA API Decoding
* @ingroup lavc_codec_hwaccel
* @{
*/
/**
* This structure is used to share data between the FFmpeg library and
* the client video application.
* This shall be zero-allocated and available as
* AVCodecContext.hwaccel_context. All user members can be set once
* during initialization or through each AVCodecContext.get_buffer()
* function call. In any case, they must be valid prior to calling
* decoding functions.
*
* Deprecated: use AVCodecContext.hw_frames_ctx instead.
*/
struct attribute_deprecated vaapi_context {
/**
* Window system dependent data
*
* - encoding: unused
* - decoding: Set by user
*/
void *display;
/**
* Configuration ID
*
* - encoding: unused
* - decoding: Set by user
*/
uint32_t config_id;
/**
* Context ID (video decode pipeline)
*
* - encoding: unused
* - decoding: Set by user
*/
uint32_t context_id;
};
/* @} */
#endif /* FF_API_STRUCT_VAAPI_CONTEXT */
#endif /* AVCODEC_VAAPI_H */

Просмотреть файл

@ -0,0 +1,732 @@
/*
* 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/common.h"
#include "libavutil/pixdesc.h"
#include "avcodec.h"
#include "decode.h"
#include "internal.h"
#include "vaapi_decode.h"
int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx,
VAAPIDecodePicture *pic,
int type,
const void *data,
size_t size)
{
VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
VAStatus vas;
VABufferID buffer;
av_assert0(pic->nb_param_buffers + 1 <= MAX_PARAM_BUFFERS);
vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
type, size, 1, (void*)data, &buffer);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to create parameter "
"buffer (type %d): %d (%s).\n",
type, vas, vaErrorStr(vas));
return AVERROR(EIO);
}
pic->param_buffers[pic->nb_param_buffers++] = buffer;
av_log(avctx, AV_LOG_DEBUG, "Param buffer (type %d, %zu bytes) "
"is %#x.\n", type, size, buffer);
return 0;
}
int ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx,
VAAPIDecodePicture *pic,
const void *params_data,
size_t params_size,
const void *slice_data,
size_t slice_size)
{
VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
VAStatus vas;
int index;
av_assert0(pic->nb_slices <= pic->slices_allocated);
if (pic->nb_slices == pic->slices_allocated) {
if (pic->slices_allocated > 0)
pic->slices_allocated *= 2;
else
pic->slices_allocated = 64;
pic->slice_buffers =
av_realloc_array(pic->slice_buffers,
pic->slices_allocated,
2 * sizeof(*pic->slice_buffers));
if (!pic->slice_buffers)
return AVERROR(ENOMEM);
}
av_assert0(pic->nb_slices + 1 <= pic->slices_allocated);
index = 2 * pic->nb_slices;
vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
VASliceParameterBufferType,
params_size, 1, (void*)params_data,
&pic->slice_buffers[index]);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to create slice "
"parameter buffer: %d (%s).\n", vas, vaErrorStr(vas));
return AVERROR(EIO);
}
av_log(avctx, AV_LOG_DEBUG, "Slice %d param buffer (%zu bytes) "
"is %#x.\n", pic->nb_slices, params_size,
pic->slice_buffers[index]);
vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
VASliceDataBufferType,
slice_size, 1, (void*)slice_data,
&pic->slice_buffers[index + 1]);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to create slice "
"data buffer (size %zu): %d (%s).\n",
slice_size, vas, vaErrorStr(vas));
vaDestroyBuffer(ctx->hwctx->display,
pic->slice_buffers[index]);
return AVERROR(EIO);
}
av_log(avctx, AV_LOG_DEBUG, "Slice %d data buffer (%zu bytes) "
"is %#x.\n", pic->nb_slices, slice_size,
pic->slice_buffers[index + 1]);
++pic->nb_slices;
return 0;
}
static void ff_vaapi_decode_destroy_buffers(AVCodecContext *avctx,
VAAPIDecodePicture *pic)
{
VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
VAStatus vas;
int i;
for (i = 0; i < pic->nb_param_buffers; i++) {
vas = vaDestroyBuffer(ctx->hwctx->display,
pic->param_buffers[i]);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to destroy "
"parameter buffer %#x: %d (%s).\n",
pic->param_buffers[i], vas, vaErrorStr(vas));
}
}
for (i = 0; i < 2 * pic->nb_slices; i++) {
vas = vaDestroyBuffer(ctx->hwctx->display,
pic->slice_buffers[i]);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to destroy slice "
"slice buffer %#x: %d (%s).\n",
pic->slice_buffers[i], vas, vaErrorStr(vas));
}
}
}
int ff_vaapi_decode_issue(AVCodecContext *avctx,
VAAPIDecodePicture *pic)
{
VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
VAStatus vas;
int err;
av_log(avctx, AV_LOG_DEBUG, "Decode to surface %#x.\n",
pic->output_surface);
vas = vaBeginPicture(ctx->hwctx->display, ctx->va_context,
pic->output_surface);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to begin picture decode "
"issue: %d (%s).\n", vas, vaErrorStr(vas));
err = AVERROR(EIO);
goto fail_with_picture;
}
vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context,
pic->param_buffers, pic->nb_param_buffers);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to upload decode "
"parameters: %d (%s).\n", vas, vaErrorStr(vas));
err = AVERROR(EIO);
goto fail_with_picture;
}
vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context,
pic->slice_buffers, 2 * pic->nb_slices);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to upload slices: "
"%d (%s).\n", vas, vaErrorStr(vas));
err = AVERROR(EIO);
goto fail_with_picture;
}
vas = vaEndPicture(ctx->hwctx->display, ctx->va_context);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to end picture decode "
"issue: %d (%s).\n", vas, vaErrorStr(vas));
err = AVERROR(EIO);
if (CONFIG_VAAPI_1 || ctx->hwctx->driver_quirks &
AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS)
goto fail;
else
goto fail_at_end;
}
if (CONFIG_VAAPI_1 || ctx->hwctx->driver_quirks &
AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS)
ff_vaapi_decode_destroy_buffers(avctx, pic);
err = 0;
goto exit;
fail_with_picture:
vas = vaEndPicture(ctx->hwctx->display, ctx->va_context);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to end picture decode "
"after error: %d (%s).\n", vas, vaErrorStr(vas));
}
fail:
ff_vaapi_decode_destroy_buffers(avctx, pic);
fail_at_end:
exit:
pic->nb_param_buffers = 0;
pic->nb_slices = 0;
pic->slices_allocated = 0;
av_freep(&pic->slice_buffers);
return err;
}
int ff_vaapi_decode_cancel(AVCodecContext *avctx,
VAAPIDecodePicture *pic)
{
ff_vaapi_decode_destroy_buffers(avctx, pic);
pic->nb_param_buffers = 0;
pic->nb_slices = 0;
pic->slices_allocated = 0;
av_freep(&pic->slice_buffers);
return 0;
}
static const struct {
uint32_t fourcc;
enum AVPixelFormat pix_fmt;
} vaapi_format_map[] = {
#define MAP(va, av) { VA_FOURCC_ ## va, AV_PIX_FMT_ ## av }
// 4:0:0
MAP(Y800, GRAY8),
// 4:2:0
MAP(NV12, NV12),
MAP(YV12, YUV420P),
MAP(IYUV, YUV420P),
#ifdef VA_FOURCC_I420
MAP(I420, YUV420P),
#endif
MAP(IMC3, YUV420P),
// 4:1:1
MAP(411P, YUV411P),
// 4:2:2
MAP(422H, YUV422P),
#ifdef VA_FOURCC_YV16
MAP(YV16, YUV422P),
#endif
// 4:4:0
MAP(422V, YUV440P),
// 4:4:4
MAP(444P, YUV444P),
// 4:2:0 10-bit
#ifdef VA_FOURCC_P010
MAP(P010, P010),
#endif
#ifdef VA_FOURCC_I010
MAP(I010, YUV420P10),
#endif
#undef MAP
};
static int vaapi_decode_find_best_format(AVCodecContext *avctx,
AVHWDeviceContext *device,
VAConfigID config_id,
AVHWFramesContext *frames)
{
AVVAAPIDeviceContext *hwctx = device->hwctx;
VAStatus vas;
VASurfaceAttrib *attr;
enum AVPixelFormat source_format, best_format, format;
uint32_t best_fourcc, fourcc;
int i, j, nb_attr;
source_format = avctx->sw_pix_fmt;
av_assert0(source_format != AV_PIX_FMT_NONE);
vas = vaQuerySurfaceAttributes(hwctx->display, config_id,
NULL, &nb_attr);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: "
"%d (%s).\n", vas, vaErrorStr(vas));
return AVERROR(ENOSYS);
}
attr = av_malloc_array(nb_attr, sizeof(*attr));
if (!attr)
return AVERROR(ENOMEM);
vas = vaQuerySurfaceAttributes(hwctx->display, config_id,
attr, &nb_attr);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: "
"%d (%s).\n", vas, vaErrorStr(vas));
av_freep(&attr);
return AVERROR(ENOSYS);
}
best_format = AV_PIX_FMT_NONE;
for (i = 0; i < nb_attr; i++) {
if (attr[i].type != VASurfaceAttribPixelFormat)
continue;
fourcc = attr[i].value.value.i;
for (j = 0; j < FF_ARRAY_ELEMS(vaapi_format_map); j++) {
if (fourcc == vaapi_format_map[j].fourcc)
break;
}
if (j >= FF_ARRAY_ELEMS(vaapi_format_map)) {
av_log(avctx, AV_LOG_DEBUG, "Ignoring unknown format %#x.\n",
fourcc);
continue;
}
format = vaapi_format_map[j].pix_fmt;
av_log(avctx, AV_LOG_DEBUG, "Considering format %#x -> %s.\n",
fourcc, av_get_pix_fmt_name(format));
best_format = av_find_best_pix_fmt_of_2(format, best_format,
source_format, 0, NULL);
if (format == best_format)
best_fourcc = fourcc;
}
av_freep(&attr);
if (best_format == AV_PIX_FMT_NONE) {
av_log(avctx, AV_LOG_ERROR, "No usable formats for decoding!\n");
return AVERROR(EINVAL);
}
av_log(avctx, AV_LOG_DEBUG, "Picked %s (%#x) as best match for %s.\n",
av_get_pix_fmt_name(best_format), best_fourcc,
av_get_pix_fmt_name(source_format));
frames->sw_format = best_format;
if (avctx->internal->hwaccel_priv_data) {
VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
AVVAAPIFramesContext *avfc = frames->hwctx;
ctx->pixel_format_attribute = (VASurfaceAttrib) {
.type = VASurfaceAttribPixelFormat,
.value.value.i = best_fourcc,
};
avfc->attributes = &ctx->pixel_format_attribute;
avfc->nb_attributes = 1;
}
return 0;
}
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_MAIN, H264Main ),
MAP(H264, H264_HIGH, H264High ),
#if VA_CHECK_VERSION(0, 37, 0)
MAP(HEVC, HEVC_MAIN, HEVCMain ),
MAP(HEVC, HEVC_MAIN_10, HEVCMain10 ),
#endif
MAP(MJPEG, MJPEG_HUFFMAN_BASELINE_DCT,
JPEGBaseline),
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 ),
MAP(VP8, UNKNOWN, VP8Version0_3 ),
#if VA_CHECK_VERSION(0, 38, 0)
MAP(VP9, VP9_0, VP9Profile0 ),
#endif
#if VA_CHECK_VERSION(0, 39, 0)
MAP(VP9, VP9_2, VP9Profile2 ),
#endif
#undef MAP
};
/*
* Set *va_config and the frames_ref fields from the current codec parameters
* in avctx.
*/
static int vaapi_decode_make_config(AVCodecContext *avctx,
AVBufferRef *device_ref,
VAConfigID *va_config,
AVBufferRef *frames_ref)
{
AVVAAPIHWConfig *hwconfig = NULL;
AVHWFramesConstraints *constraints = NULL;
VAStatus vas;
int err, i, j;
const AVCodecDescriptor *codec_desc;
VAProfile *profile_list = NULL, matched_va_profile;
int profile_count, exact_match, matched_ff_profile;
AVHWDeviceContext *device = (AVHWDeviceContext*)device_ref->data;
AVVAAPIDeviceContext *hwctx = device->hwctx;
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_array(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(avctx, AV_LOG_ERROR, "Failed to query profiles: "
"%d (%s).\n", vas, vaErrorStr(vas));
err = AVERROR(ENOSYS);
goto fail;
}
matched_va_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 ||
vaapi_profile_map[i].codec_profile == FF_PROFILE_UNKNOWN)
profile_match = 1;
for (j = 0; j < profile_count; j++) {
if (vaapi_profile_map[i].va_profile == profile_list[j]) {
exact_match = profile_match;
break;
}
}
if (j < profile_count) {
matched_va_profile = vaapi_profile_map[i].va_profile;
matched_ff_profile = vaapi_profile_map[i].codec_profile;
if (exact_match)
break;
}
}
av_freep(&profile_list);
if (matched_va_profile == VAProfileNone) {
av_log(avctx, AV_LOG_ERROR, "No support for codec %s "
"profile %d.\n", codec_desc->name, avctx->profile);
err = AVERROR(ENOSYS);
goto fail;
}
if (!exact_match) {
if (avctx->hwaccel_flags &
AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH) {
av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not "
"supported for hardware decode.\n",
codec_desc->name, avctx->profile);
av_log(avctx, AV_LOG_WARNING, "Using possibly-"
"incompatible profile %d instead.\n",
matched_ff_profile);
} else {
av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not "
"supported for hardware decode.\n",
codec_desc->name, avctx->profile);
err = AVERROR(EINVAL);
goto fail;
}
}
vas = vaCreateConfig(hwctx->display, matched_va_profile,
VAEntrypointVLD, NULL, 0,
va_config);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to create decode "
"configuration: %d (%s).\n", vas, vaErrorStr(vas));
err = AVERROR(EIO);
goto fail;
}
hwconfig = av_hwdevice_hwconfig_alloc(device_ref);
if (!hwconfig) {
err = AVERROR(ENOMEM);
goto fail;
}
hwconfig->config_id = *va_config;
constraints =
av_hwdevice_get_hwframe_constraints(device_ref, hwconfig);
if (!constraints) {
err = AVERROR(ENOMEM);
goto fail;
}
if (avctx->coded_width < constraints->min_width ||
avctx->coded_height < constraints->min_height ||
avctx->coded_width > constraints->max_width ||
avctx->coded_height > constraints->max_height) {
av_log(avctx, AV_LOG_ERROR, "Hardware does not support image "
"size %dx%d (constraints: width %d-%d height %d-%d).\n",
avctx->coded_width, avctx->coded_height,
constraints->min_width, constraints->max_width,
constraints->min_height, constraints->max_height);
err = AVERROR(EINVAL);
goto fail;
}
if (!constraints->valid_sw_formats ||
constraints->valid_sw_formats[0] == AV_PIX_FMT_NONE) {
av_log(avctx, AV_LOG_ERROR, "Hardware does not offer any "
"usable surface formats.\n");
err = AVERROR(EINVAL);
goto fail;
}
if (frames_ref) {
AVHWFramesContext *frames = (AVHWFramesContext *)frames_ref->data;
frames->format = AV_PIX_FMT_VAAPI;
frames->width = avctx->coded_width;
frames->height = avctx->coded_height;
err = vaapi_decode_find_best_format(avctx, device,
*va_config, frames);
if (err < 0)
goto fail;
frames->initial_pool_size = 1;
// Add per-codec number of surfaces used for storing reference frames.
switch (avctx->codec_id) {
case AV_CODEC_ID_H264:
case AV_CODEC_ID_HEVC:
frames->initial_pool_size += 16;
break;
case AV_CODEC_ID_VP9:
frames->initial_pool_size += 8;
break;
case AV_CODEC_ID_VP8:
frames->initial_pool_size += 3;
break;
default:
frames->initial_pool_size += 2;
}
}
av_hwframe_constraints_free(&constraints);
av_freep(&hwconfig);
return 0;
fail:
av_hwframe_constraints_free(&constraints);
av_freep(&hwconfig);
if (*va_config != VA_INVALID_ID) {
vaDestroyConfig(hwctx->display, *va_config);
*va_config = VA_INVALID_ID;
}
av_freep(&profile_list);
return err;
}
int ff_vaapi_common_frame_params(AVCodecContext *avctx,
AVBufferRef *hw_frames_ctx)
{
AVHWFramesContext *hw_frames = (AVHWFramesContext *)hw_frames_ctx->data;
AVHWDeviceContext *device_ctx = hw_frames->device_ctx;
AVVAAPIDeviceContext *hwctx;
VAConfigID va_config = VA_INVALID_ID;
int err;
if (device_ctx->type != AV_HWDEVICE_TYPE_VAAPI)
return AVERROR(EINVAL);
hwctx = device_ctx->hwctx;
err = vaapi_decode_make_config(avctx, hw_frames->device_ref, &va_config,
hw_frames_ctx);
if (err)
return err;
if (va_config != VA_INVALID_ID)
vaDestroyConfig(hwctx->display, va_config);
return 0;
}
int ff_vaapi_decode_init(AVCodecContext *avctx)
{
VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
VAStatus vas;
int err;
ctx->va_config = VA_INVALID_ID;
ctx->va_context = VA_INVALID_ID;
#if FF_API_STRUCT_VAAPI_CONTEXT
if (avctx->hwaccel_context) {
av_log(avctx, AV_LOG_WARNING, "Using deprecated struct "
"vaapi_context in decode.\n");
ctx->have_old_context = 1;
ctx->old_context = avctx->hwaccel_context;
// Really we only want the VAAPI device context, but this
// allocates a whole generic device context because we don't
// have any other way to determine how big it should be.
ctx->device_ref =
av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VAAPI);
if (!ctx->device_ref) {
err = AVERROR(ENOMEM);
goto fail;
}
ctx->device = (AVHWDeviceContext*)ctx->device_ref->data;
ctx->hwctx = ctx->device->hwctx;
ctx->hwctx->display = ctx->old_context->display;
// The old VAAPI decode setup assumed this quirk was always
// present, so set it here to avoid the behaviour changing.
ctx->hwctx->driver_quirks =
AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS;
}
#endif
#if FF_API_STRUCT_VAAPI_CONTEXT
if (ctx->have_old_context) {
ctx->va_config = ctx->old_context->config_id;
ctx->va_context = ctx->old_context->context_id;
av_log(avctx, AV_LOG_DEBUG, "Using user-supplied decoder "
"context: %#x/%#x.\n", ctx->va_config, ctx->va_context);
} else {
#endif
err = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_VAAPI);
if (err < 0)
goto fail;
ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
ctx->hwfc = ctx->frames->hwctx;
ctx->device = ctx->frames->device_ctx;
ctx->hwctx = ctx->device->hwctx;
err = vaapi_decode_make_config(avctx, ctx->frames->device_ref,
&ctx->va_config, avctx->hw_frames_ctx);
if (err)
goto fail;
vas = vaCreateContext(ctx->hwctx->display, ctx->va_config,
avctx->coded_width, avctx->coded_height,
VA_PROGRESSIVE,
ctx->hwfc->surface_ids,
ctx->hwfc->nb_surfaces,
&ctx->va_context);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to create decode "
"context: %d (%s).\n", vas, vaErrorStr(vas));
err = AVERROR(EIO);
goto fail;
}
av_log(avctx, AV_LOG_DEBUG, "Decode context initialised: "
"%#x/%#x.\n", ctx->va_config, ctx->va_context);
#if FF_API_STRUCT_VAAPI_CONTEXT
}
#endif
return 0;
fail:
ff_vaapi_decode_uninit(avctx);
return err;
}
int ff_vaapi_decode_uninit(AVCodecContext *avctx)
{
VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
VAStatus vas;
#if FF_API_STRUCT_VAAPI_CONTEXT
if (ctx->have_old_context) {
av_buffer_unref(&ctx->device_ref);
} else {
#endif
if (ctx->va_context != VA_INVALID_ID) {
vas = vaDestroyContext(ctx->hwctx->display, ctx->va_context);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode "
"context %#x: %d (%s).\n",
ctx->va_context, vas, vaErrorStr(vas));
}
}
if (ctx->va_config != VA_INVALID_ID) {
vas = vaDestroyConfig(ctx->hwctx->display, ctx->va_config);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode "
"configuration %#x: %d (%s).\n",
ctx->va_config, vas, vaErrorStr(vas));
}
}
#if FF_API_STRUCT_VAAPI_CONTEXT
}
#endif
return 0;
}

Просмотреть файл

@ -0,0 +1,105 @@
/*
* 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
*/
#ifndef AVCODEC_VAAPI_DECODE_H
#define AVCODEC_VAAPI_DECODE_H
#include <va/va.h>
#include <va/va_dec_vp9.h>
#include "libavutil/frame.h"
#include "libavutil/hwcontext.h"
#include "libavutil/hwcontext_vaapi.h"
#include "avcodec.h"
#include "version.h"
#if FF_API_STRUCT_VAAPI_CONTEXT
#include "vaapi.h"
#endif
static inline VASurfaceID ff_vaapi_get_surface_id(AVFrame *pic)
{
return (uintptr_t)pic->data[3];
}
enum {
MAX_PARAM_BUFFERS = 16,
};
typedef struct VAAPIDecodePicture {
VASurfaceID output_surface;
int nb_param_buffers;
VABufferID param_buffers[MAX_PARAM_BUFFERS];
int nb_slices;
VABufferID *slice_buffers;
int slices_allocated;
} VAAPIDecodePicture;
typedef struct VAAPIDecodeContext {
VAConfigID va_config;
VAContextID va_context;
#if FF_API_STRUCT_VAAPI_CONTEXT
FF_DISABLE_DEPRECATION_WARNINGS
int have_old_context;
struct vaapi_context *old_context;
AVBufferRef *device_ref;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
AVHWDeviceContext *device;
AVVAAPIDeviceContext *hwctx;
AVHWFramesContext *frames;
AVVAAPIFramesContext *hwfc;
enum AVPixelFormat surface_format;
int surface_count;
VASurfaceAttrib pixel_format_attribute;
} VAAPIDecodeContext;
int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx,
VAAPIDecodePicture *pic,
int type,
const void *data,
size_t size);
int ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx,
VAAPIDecodePicture *pic,
const void *params_data,
size_t params_size,
const void *slice_data,
size_t slice_size);
int ff_vaapi_decode_issue(AVCodecContext *avctx,
VAAPIDecodePicture *pic);
int ff_vaapi_decode_cancel(AVCodecContext *avctx,
VAAPIDecodePicture *pic);
int ff_vaapi_decode_init(AVCodecContext *avctx);
int ff_vaapi_decode_uninit(AVCodecContext *avctx);
int ff_vaapi_common_frame_params(AVCodecContext *avctx,
AVBufferRef *hw_frames_ctx);
#endif /* AVCODEC_VAAPI_DECODE_H */

Просмотреть файл

@ -0,0 +1,237 @@
/*
* 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 <va/va.h>
#include <va/va_dec_vp8.h>
#include "hwaccel.h"
#include "vaapi_decode.h"
#include "vp8.h"
static VASurfaceID vaapi_vp8_surface_id(VP8Frame *vf)
{
if (vf)
return ff_vaapi_get_surface_id(vf->tf.f);
else
return VA_INVALID_SURFACE;
}
static int vaapi_vp8_start_frame(AVCodecContext *avctx,
av_unused const uint8_t *buffer,
av_unused uint32_t size)
{
const VP8Context *s = avctx->priv_data;
VAAPIDecodePicture *pic = s->framep[VP56_FRAME_CURRENT]->hwaccel_picture_private;
VAPictureParameterBufferVP8 pp;
VAProbabilityDataBufferVP8 prob;
VAIQMatrixBufferVP8 quant;
int err, i, j, k;
pic->output_surface = vaapi_vp8_surface_id(s->framep[VP56_FRAME_CURRENT]);
pp = (VAPictureParameterBufferVP8) {
.frame_width = avctx->width,
.frame_height = avctx->height,
.last_ref_frame = vaapi_vp8_surface_id(s->framep[VP56_FRAME_PREVIOUS]),
.golden_ref_frame = vaapi_vp8_surface_id(s->framep[VP56_FRAME_GOLDEN]),
.alt_ref_frame = vaapi_vp8_surface_id(s->framep[VP56_FRAME_GOLDEN2]),
.out_of_loop_frame = VA_INVALID_SURFACE,
.pic_fields.bits = {
.key_frame = !s->keyframe,
.version = s->profile,
.segmentation_enabled = s->segmentation.enabled,
.update_mb_segmentation_map = s->segmentation.update_map,
.update_segment_feature_data = s->segmentation.update_feature_data,
.filter_type = s->filter.simple,
.sharpness_level = s->filter.sharpness,
.loop_filter_adj_enable = s->lf_delta.enabled,
.mode_ref_lf_delta_update = s->lf_delta.update,
.sign_bias_golden = s->sign_bias[VP56_FRAME_GOLDEN],
.sign_bias_alternate = s->sign_bias[VP56_FRAME_GOLDEN2],
.mb_no_coeff_skip = s->mbskip_enabled,
.loop_filter_disable = s->filter.level == 0,
},
.prob_skip_false = s->prob->mbskip,
.prob_intra = s->prob->intra,
.prob_last = s->prob->last,
.prob_gf = s->prob->golden,
};
for (i = 0; i < 3; i++)
pp.mb_segment_tree_probs[i] = s->prob->segmentid[i];
for (i = 0; i < 4; i++) {
if (s->segmentation.enabled) {
pp.loop_filter_level[i] = s->segmentation.filter_level[i];
if (!s->segmentation.absolute_vals)
pp.loop_filter_level[i] += s->filter.level;
} else {
pp.loop_filter_level[i] = s->filter.level;
}
pp.loop_filter_level[i] = av_clip_uintp2(pp.loop_filter_level[i], 6);
}
for (i = 0; i < 4; i++) {
pp.loop_filter_deltas_ref_frame[i] = s->lf_delta.ref[i];
pp.loop_filter_deltas_mode[i] = s->lf_delta.mode[i + 4];
}
if (s->keyframe) {
static const uint8_t keyframe_y_mode_probs[4] = {
145, 156, 163, 128
};
static const uint8_t keyframe_uv_mode_probs[3] = {
142, 114, 183
};
memcpy(pp.y_mode_probs, keyframe_y_mode_probs, 4);
memcpy(pp.uv_mode_probs, keyframe_uv_mode_probs, 3);
} else {
for (i = 0; i < 4; i++)
pp.y_mode_probs[i] = s->prob->pred16x16[i];
for (i = 0; i < 3; i++)
pp.uv_mode_probs[i] = s->prob->pred8x8c[i];
}
for (i = 0; i < 2; i++)
for (j = 0; j < 19; j++)
pp.mv_probs[i][j] = s->prob->mvc[i][j];
pp.bool_coder_ctx.range = s->coder_state_at_header_end.range;
pp.bool_coder_ctx.value = s->coder_state_at_header_end.value;
pp.bool_coder_ctx.count = s->coder_state_at_header_end.bit_count;
err = ff_vaapi_decode_make_param_buffer(avctx, pic,
VAPictureParameterBufferType,
&pp, sizeof(pp));
if (err < 0)
goto fail;
for (i = 0; i < 4; i++) {
for (j = 0; j < 8; j++) {
static const int coeff_bands_inverse[8] = {
0, 1, 2, 3, 5, 6, 4, 15
};
int coeff_pos = coeff_bands_inverse[j];
for (k = 0; k < 3; k++) {
memcpy(prob.dct_coeff_probs[i][j][k],
s->prob->token[i][coeff_pos][k], 11);
}
}
}
err = ff_vaapi_decode_make_param_buffer(avctx, pic,
VAProbabilityBufferType,
&prob, sizeof(prob));
if (err < 0)
goto fail;
for (i = 0; i < 4; i++) {
int base_qi = s->segmentation.base_quant[i];
if (!s->segmentation.absolute_vals)
base_qi += s->quant.yac_qi;
quant.quantization_index[i][0] = av_clip_uintp2(base_qi, 7);
quant.quantization_index[i][1] = av_clip_uintp2(base_qi + s->quant.ydc_delta, 7);
quant.quantization_index[i][2] = av_clip_uintp2(base_qi + s->quant.y2dc_delta, 7);
quant.quantization_index[i][3] = av_clip_uintp2(base_qi + s->quant.y2ac_delta, 7);
quant.quantization_index[i][4] = av_clip_uintp2(base_qi + s->quant.uvdc_delta, 7);
quant.quantization_index[i][5] = av_clip_uintp2(base_qi + s->quant.uvac_delta, 7);
}
err = ff_vaapi_decode_make_param_buffer(avctx, pic,
VAIQMatrixBufferType,
&quant, sizeof(quant));
if (err < 0)
goto fail;
return 0;
fail:
ff_vaapi_decode_cancel(avctx, pic);
return err;
}
static int vaapi_vp8_end_frame(AVCodecContext *avctx)
{
const VP8Context *s = avctx->priv_data;
VAAPIDecodePicture *pic = s->framep[VP56_FRAME_CURRENT]->hwaccel_picture_private;
return ff_vaapi_decode_issue(avctx, pic);
}
static int vaapi_vp8_decode_slice(AVCodecContext *avctx,
const uint8_t *buffer,
uint32_t size)
{
const VP8Context *s = avctx->priv_data;
VAAPIDecodePicture *pic = s->framep[VP56_FRAME_CURRENT]->hwaccel_picture_private;
VASliceParameterBufferVP8 sp;
int err, i;
unsigned int header_size = 3 + 7 * s->keyframe;
const uint8_t *data = buffer + header_size;
unsigned int data_size = size - header_size;
sp = (VASliceParameterBufferVP8) {
.slice_data_size = data_size,
.slice_data_offset = 0,
.slice_data_flag = VA_SLICE_DATA_FLAG_ALL,
.macroblock_offset = (8 * (s->coder_state_at_header_end.input - data) -
s->coder_state_at_header_end.bit_count - 8),
.num_of_partitions = s->num_coeff_partitions + 1,
};
sp.partition_size[0] = s->header_partition_size - ((sp.macroblock_offset + 7) / 8);
for (i = 0; i < 8; i++)
sp.partition_size[i+1] = s->coeff_partition_size[i];
err = ff_vaapi_decode_make_slice_buffer(avctx, pic, &sp, sizeof(sp), data, data_size);
if (err)
goto fail;
return 0;
fail:
ff_vaapi_decode_cancel(avctx, pic);
return err;
}
const AVHWAccel ff_vp8_vaapi_hwaccel = {
.name = "vp8_vaapi",
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_VP8,
.pix_fmt = AV_PIX_FMT_VAAPI,
.start_frame = &vaapi_vp8_start_frame,
.end_frame = &vaapi_vp8_end_frame,
.decode_slice = &vaapi_vp8_decode_slice,
.frame_priv_data_size = sizeof(VAAPIDecodePicture),
.init = &ff_vaapi_decode_init,
.uninit = &ff_vaapi_decode_uninit,
.frame_params = &ff_vaapi_common_frame_params,
.priv_data_size = sizeof(VAAPIDecodeContext),
.caps_internal = HWACCEL_CAP_ASYNC_SAFE,
};

Просмотреть файл

@ -0,0 +1,185 @@
/*
* VP9 HW decode acceleration through VA API
*
* Copyright (C) 2015 Timo Rothenpieler <timo@rothenpieler.org>
*
* 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/pixdesc.h"
#include "hwaccel.h"
#include "vaapi_decode.h"
#include "vp9shared.h"
static VASurfaceID vaapi_vp9_surface_id(const VP9Frame *vf)
{
if (vf)
return ff_vaapi_get_surface_id(vf->tf.f);
else
return VA_INVALID_SURFACE;
}
static int vaapi_vp9_start_frame(AVCodecContext *avctx,
av_unused const uint8_t *buffer,
av_unused uint32_t size)
{
const VP9SharedContext *h = avctx->priv_data;
VAAPIDecodePicture *pic = h->frames[CUR_FRAME].hwaccel_picture_private;
VADecPictureParameterBufferVP9 pic_param;
const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(avctx->sw_pix_fmt);
int err, i;
pic->output_surface = vaapi_vp9_surface_id(&h->frames[CUR_FRAME]);
pic_param = (VADecPictureParameterBufferVP9) {
.frame_width = avctx->width,
.frame_height = avctx->height,
.pic_fields.bits = {
.subsampling_x = pixdesc->log2_chroma_w,
.subsampling_y = pixdesc->log2_chroma_h,
.frame_type = !h->h.keyframe,
.show_frame = !h->h.invisible,
.error_resilient_mode = h->h.errorres,
.intra_only = h->h.intraonly,
.allow_high_precision_mv = h->h.keyframe ? 0 : h->h.highprecisionmvs,
.mcomp_filter_type = h->h.filtermode ^ (h->h.filtermode <= 1),
.frame_parallel_decoding_mode = h->h.parallelmode,
.reset_frame_context = h->h.resetctx,
.refresh_frame_context = h->h.refreshctx,
.frame_context_idx = h->h.framectxid,
.segmentation_enabled = h->h.segmentation.enabled,
.segmentation_temporal_update = h->h.segmentation.temporal,
.segmentation_update_map = h->h.segmentation.update_map,
.last_ref_frame = h->h.refidx[0],
.last_ref_frame_sign_bias = h->h.signbias[0],
.golden_ref_frame = h->h.refidx[1],
.golden_ref_frame_sign_bias = h->h.signbias[1],
.alt_ref_frame = h->h.refidx[2],
.alt_ref_frame_sign_bias = h->h.signbias[2],
.lossless_flag = h->h.lossless,
},
.filter_level = h->h.filter.level,
.sharpness_level = h->h.filter.sharpness,
.log2_tile_rows = h->h.tiling.log2_tile_rows,
.log2_tile_columns = h->h.tiling.log2_tile_cols,
.frame_header_length_in_bytes = h->h.uncompressed_header_size,
.first_partition_size = h->h.compressed_header_size,
.profile = h->h.profile,
.bit_depth = h->h.bpp,
};
for (i = 0; i < 7; i++)
pic_param.mb_segment_tree_probs[i] = h->h.segmentation.prob[i];
if (h->h.segmentation.temporal) {
for (i = 0; i < 3; i++)
pic_param.segment_pred_probs[i] = h->h.segmentation.pred_prob[i];
} else {
memset(pic_param.segment_pred_probs, 255, sizeof(pic_param.segment_pred_probs));
}
for (i = 0; i < 8; i++) {
if (h->refs[i].f->buf[0])
pic_param.reference_frames[i] = ff_vaapi_get_surface_id(h->refs[i].f);
else
pic_param.reference_frames[i] = VA_INVALID_ID;
}
err = ff_vaapi_decode_make_param_buffer(avctx, pic,
VAPictureParameterBufferType,
&pic_param, sizeof(pic_param));
if (err < 0) {
ff_vaapi_decode_cancel(avctx, pic);
return err;
}
return 0;
}
static int vaapi_vp9_end_frame(AVCodecContext *avctx)
{
const VP9SharedContext *h = avctx->priv_data;
VAAPIDecodePicture *pic = h->frames[CUR_FRAME].hwaccel_picture_private;
return ff_vaapi_decode_issue(avctx, pic);
}
static int vaapi_vp9_decode_slice(AVCodecContext *avctx,
const uint8_t *buffer,
uint32_t size)
{
const VP9SharedContext *h = avctx->priv_data;
VAAPIDecodePicture *pic = h->frames[CUR_FRAME].hwaccel_picture_private;
VASliceParameterBufferVP9 slice_param;
int err, i;
slice_param = (VASliceParameterBufferVP9) {
.slice_data_size = size,
.slice_data_offset = 0,
.slice_data_flag = VA_SLICE_DATA_FLAG_ALL,
};
for (i = 0; i < 8; i++) {
slice_param.seg_param[i] = (VASegmentParameterVP9) {
.segment_flags.fields = {
.segment_reference_enabled = h->h.segmentation.feat[i].ref_enabled,
.segment_reference = h->h.segmentation.feat[i].ref_val,
.segment_reference_skipped = h->h.segmentation.feat[i].skip_enabled,
},
.luma_dc_quant_scale = h->h.segmentation.feat[i].qmul[0][0],
.luma_ac_quant_scale = h->h.segmentation.feat[i].qmul[0][1],
.chroma_dc_quant_scale = h->h.segmentation.feat[i].qmul[1][0],
.chroma_ac_quant_scale = h->h.segmentation.feat[i].qmul[1][1],
};
memcpy(slice_param.seg_param[i].filter_level, h->h.segmentation.feat[i].lflvl, sizeof(slice_param.seg_param[i].filter_level));
}
err = ff_vaapi_decode_make_slice_buffer(avctx, pic,
&slice_param, sizeof(slice_param),
buffer, size);
if (err) {
ff_vaapi_decode_cancel(avctx, pic);
return err;
}
return 0;
}
const AVHWAccel ff_vp9_vaapi_hwaccel = {
.name = "vp9_vaapi",
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_VP9,
.pix_fmt = AV_PIX_FMT_VAAPI,
.start_frame = vaapi_vp9_start_frame,
.end_frame = vaapi_vp9_end_frame,
.decode_slice = vaapi_vp9_decode_slice,
.frame_priv_data_size = sizeof(VAAPIDecodePicture),
.init = ff_vaapi_decode_init,
.uninit = ff_vaapi_decode_uninit,
.frame_params = ff_vaapi_common_frame_params,
.priv_data_size = sizeof(VAAPIDecodeContext),
.caps_internal = HWACCEL_CAP_ASYNC_SAFE,
};

Просмотреть файл

@ -158,6 +158,9 @@ av_get_token
av_gettime
av_gettime_relative
av_gettime_relative_is_monotonic
av_hwdevice_get_hwframe_constraints
av_hwdevice_hwconfig_alloc
av_hwframe_constraints_free
av_hwframe_get_buffer
av_image_alloc
av_image_check_sar
@ -320,5 +323,9 @@ avpriv_slicethread_free
av_hwdevice_get_type_name
av_hwframe_ctx_alloc
av_hwframe_ctx_init
av_hwdevice_ctx_alloc
av_hwdevice_ctx_init
av_hwframe_transfer_get_formats
av_hwdevice_ctx_create_derived
av_malloc_array
av_mallocz_array

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,117 @@
/*
* 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
*/
#ifndef AVUTIL_HWCONTEXT_VAAPI_H
#define AVUTIL_HWCONTEXT_VAAPI_H
#include <va/va.h>
/**
* @file
* API-specific header for AV_HWDEVICE_TYPE_VAAPI.
*
* Dynamic frame pools are supported, but note that any pool used as a render
* target is required to be of fixed size in order to be be usable as an
* argument to vaCreateContext().
*
* For user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs
* with the data pointer set to a VASurfaceID.
*/
enum {
/**
* The quirks field has been set by the user and should not be detected
* automatically by av_hwdevice_ctx_init().
*/
AV_VAAPI_DRIVER_QUIRK_USER_SET = (1 << 0),
/**
* The driver does not destroy parameter buffers when they are used by
* vaRenderPicture(). Additional code will be required to destroy them
* separately afterwards.
*/
AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS = (1 << 1),
/**
* The driver does not support the VASurfaceAttribMemoryType attribute,
* so the surface allocation code will not try to use it.
*/
AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE = (1 << 2),
/**
* The driver does not support surface attributes at all.
* The surface allocation code will never pass them to surface allocation,
* and the results of the vaQuerySurfaceAttributes() call will be faked.
*/
AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES = (1 << 3),
};
/**
* VAAPI connection details.
*
* Allocated as AVHWDeviceContext.hwctx
*/
typedef struct AVVAAPIDeviceContext {
/**
* The VADisplay handle, to be filled by the user.
*/
VADisplay display;
/**
* Driver quirks to apply - this is filled by av_hwdevice_ctx_init(),
* with reference to a table of known drivers, unless the
* AV_VAAPI_DRIVER_QUIRK_USER_SET bit is already present. The user
* may need to refer to this field when performing any later
* operations using VAAPI with the same VADisplay.
*/
unsigned int driver_quirks;
} AVVAAPIDeviceContext;
/**
* VAAPI-specific data associated with a frame pool.
*
* Allocated as AVHWFramesContext.hwctx.
*/
typedef struct AVVAAPIFramesContext {
/**
* Set by the user to apply surface attributes to all surfaces in
* the frame pool. If null, default settings are used.
*/
VASurfaceAttrib *attributes;
int nb_attributes;
/**
* The surfaces IDs of all surfaces in the pool after creation.
* Only valid if AVHWFramesContext.initial_pool_size was positive.
* These are intended to be used as the render_targets arguments to
* vaCreateContext().
*/
VASurfaceID *surface_ids;
int nb_surfaces;
} AVVAAPIFramesContext;
/**
* VAAPI hardware pipeline configuration details.
*
* Allocated with av_hwdevice_hwconfig_alloc().
*/
typedef struct AVVAAPIHWConfig {
/**
* ID of a VAAPI pipeline configuration.
*/
VAConfigID config_id;
} AVVAAPIHWConfig;
#endif /* AVUTIL_HWCONTEXT_VAAPI_H */

Просмотреть файл

@ -45,6 +45,11 @@ SOURCES += [
'time.c',
'utils.c'
]
if CONFIG['MOZ_WAYLAND']:
SOURCES += [
'hwcontext_vaapi.c',
]
USE_LIBS += ['mozva']
if not CONFIG['MOZ_FFVPX_AUDIOONLY']:
SOURCES += [