756 lines · 24.6 KB · C
RawDownload
/* * 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"#include "vaapi_hevc.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    MAP(YUY2, YUYV422),#ifdef VA_FOURCC_Y210    MAP(Y210,    Y210),#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;    VAProfile (*profile_parser)(AVCodecContext *avctx);} vaapi_profile_map[] = {#define MAP(c, p, v, ...) { AV_CODEC_ID_ ## c, FF_PROFILE_ ## p, VAProfile ## v, __VA_ARGS__ }    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  ),    MAP(HEVC,        HEVC_MAIN_STILL_PICTURE,                                      HEVCMain    ),#endif#if VA_CHECK_VERSION(1, 2, 0) && CONFIG_HEVC_VAAPI_HWACCEL    MAP(HEVC,        HEVC_REXT,       None,                 ff_vaapi_parse_hevc_rext_profile ),#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#if VA_CHECK_VERSION(1, 8, 0)    MAP(AV1,         AV1_MAIN,        AV1Profile0),    MAP(AV1,         AV1_HIGH,        AV1Profile1),#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, va_profile;    int profile_count, exact_match, matched_ff_profile, codec_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;         va_profile = vaapi_profile_map[i].profile_parser ?                     vaapi_profile_map[i].profile_parser(avctx) :                     vaapi_profile_map[i].va_profile;        codec_profile = vaapi_profile_map[i].codec_profile;         for (j = 0; j < profile_count; j++) {            if (va_profile == profile_list[j]) {                exact_match = profile_match;                break;            }        }        if (j < profile_count) {            matched_va_profile = va_profile;            matched_ff_profile = 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;    }

Lines 1–500 of 756.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t