On 10/03/16 14:27, Anton Khirnov wrote:
> Quoting Mark Thompson (2016-03-08 00:21:45)
>> ---
>>  configure                      |   4 +
>>  libavutil/Makefile             |   3 +
>>  libavutil/hwcontext.c          |   3 +
>>  libavutil/hwcontext.h          |   1 +
>>  libavutil/hwcontext_internal.h |   1 +
>>  libavutil/hwcontext_vaapi.c    | 822 
>> +++++++++++++++++++++++++++++++++++++++++
>>  libavutil/hwcontext_vaapi.h    |  70 ++++
>>  7 files changed, 904 insertions(+)
>>  create mode 100644 libavutil/hwcontext_vaapi.c
>>  create mode 100644 libavutil/hwcontext_vaapi.h
>>
>> ...
>> diff --git a/libavutil/hwcontext_vaapi.c b/libavutil/hwcontext_vaapi.c
>> ...
>> +
>> +static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc)
>> +{
>> +    int i;
>> +    for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
>> +        if (vaapi_format_map[i].fourcc == fourcc)
>> +            return vaapi_format_map[i].pix_fmt;
>> +    return AV_PIX_FMT_NONE;
>> +}
>> +
>> +static unsigned int vaapi_fourcc_from_pix_fmt(enum AVPixelFormat pix_fmt)
> 
> This function seems to be unused.

It is, it was left in for symmetry and possible later use.  Still, I guess it's
sufficiently trivial that I might as well just remove it for now to get rid of
the compiler warning.

>> +{
>> +    int i;
>> +    for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
>> +        if (vaapi_format_map[i].pix_fmt == pix_fmt)
>> +            return vaapi_format_map[i].fourcc;
>> +    return 0;
>> +}
>> +
>> ...
>> +
>> +static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,
>> +                                        const void *hwconfig,
>> +                                        AVHWFramesConstraints *constraints)
>> +{
>> +    AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
>> +    const AVVAAPIHWConfig *config = hwconfig;
>> +    AVVAAPIHWConfig *tmp_config;
>> +    VASurfaceAttrib *attr_list = NULL;
>> +    VAStatus vas;
>> +    enum AVPixelFormat pix_fmt;
>> +    unsigned int fourcc;
>> +    int err, i, j, attr_count, pix_fmt_count;
>> +
>> +    if (!hwconfig) {
>> +        // No configuration was provided, so we create a temporary pipeline
>> +        // configuration in order to query all supported image formats.
>> +
>> +        tmp_config = av_mallocz(sizeof(*config));
>> +        if (!tmp_config)
>> +            return AVERROR(ENOMEM);
>> +
>> +        vas = vaCreateConfig(hwctx->display,
>> +                             VAProfileNone, VAEntrypointVideoProc,
>> +                             0, 0, &tmp_config->config_id);
>> +        if (vas != VA_STATUS_SUCCESS) {
>> +            // No vpp.  We might still be able to do something useful if
>> +            // codecs are supported, so try to make the most-commonly
>> +            // supported decoder configuration we can to query instead.
>> +            vas = vaCreateConfig(hwctx->display,
>> +                                 VAProfileH264ConstrainedBaseline,
>> +                                 VAEntrypointVLD, 0, 0,
>> +                                 &tmp_config->config_id);
>> +            if (vas != VA_STATUS_SUCCESS)
>> +                return AVERROR(ENOSYS);
> 
> leaking tmp_config here

Fixed.

> Also, one of those zeros should be NULL I think, some compilers might
> complain about that.

Ok.

>> +        }
>> +
>> +        config = tmp_config;
>> +    }
>> +
>> +    attr_count = 0;
>> +    vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
>> +                                   0, &attr_count);
>> +    if (vas != VA_STATUS_SUCCESS) {
>> +        av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
>> +               "%d (%s).\n", vas, vaErrorStr(vas));
>> +        err = AVERROR(ENOSYS);
>> +        goto fail;
>> +    }
>> +
>> +    attr_list = av_malloc(attr_count * sizeof(*attr_list));
>> +    if (!attr_list) {
>> +        err = AVERROR(ENOMEM);
>> +        goto fail;
>> +    }
>> +
>> +    vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
>> +                                   attr_list, &attr_count);
>> +    if (vas != VA_STATUS_SUCCESS) {
>> +        av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
>> +               "%d (%s).\n", vas, vaErrorStr(vas));
>> +        err = AVERROR(ENOSYS);
>> +        goto fail;
>> +    }
>> +
>> +    pix_fmt_count = 0;
>> +    for (i = 0; i < attr_count; i++) {
>> +        switch (attr_list[i].type) {
>> +        case VASurfaceAttribPixelFormat:
>> +            fourcc = attr_list[i].value.value.i;
>> +            pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
>> +            if (pix_fmt != AV_PIX_FMT_NONE) {
>> +                ++pix_fmt_count;
>> +            } else {
>> +                // Something unsupported - ignore.
>> +            }
>> +            break;
>> +        case VASurfaceAttribMinWidth:
>> +            constraints->min_width  = attr_list[i].value.value.i;
>> +            break;
>> +        case VASurfaceAttribMinHeight:
>> +            constraints->min_height = attr_list[i].value.value.i;
>> +            break;
>> +        case VASurfaceAttribMaxWidth:
>> +            constraints->max_width  = attr_list[i].value.value.i;
>> +            break;
>> +        case VASurfaceAttribMaxHeight:
>> +            constraints->max_height = attr_list[i].value.value.i;
>> +            break;
>> +        }
>> +    }
>> +    if (pix_fmt_count == 0) {
>> +        // Nothing usable found.  Presumably there exists something which
>> +        // works, so leave the set null to indicate unknown.
>> +        constraints->valid_sw_formats = NULL;
>> +    } else {
>> +        constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
>> +                                                        sizeof(pix_fmt));
>> +        if (!constraints->valid_sw_formats) {
>> +            err = AVERROR(ENOMEM);
>> +            goto fail;
>> +        }
>> +
>> +        for (i = j = 0; i < attr_count; i++) {
>> +            if (attr_list[i].type != VASurfaceAttribPixelFormat)
>> +                continue;
>> +            fourcc = attr_list[i].value.value.i;
>> +            pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
>> +            if (pix_fmt != AV_PIX_FMT_NONE)
>> +                constraints->valid_sw_formats[j++] = pix_fmt;
>> +        }
>> +        av_assert0(j == pix_fmt_count);
>> +        constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
>> +    }
>> +
>> +    constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
>> +    if (!constraints->valid_hw_formats) {
>> +        err = AVERROR(ENOMEM);
>> +        goto fail;
>> +    }
>> +    constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
>> +    constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
>> +
>> +    av_freep(&attr_list);
>> +    if (!hwconfig) {
>> +        vaDestroyConfig(hwctx->display, tmp_config->config_id);
>> +        av_freep(&tmp_config);
>> +    }
>> +
>> +    return 0;
>> +
>> +  fail:
>> +    av_freep(constraints->valid_sw_formats);
> 
> I don't think you need to free this. Especially as you don't free the
> formats either.

Yeah, it isn't needed now that there is an explicit destructor.  I'll remove it.

>> +    av_freep(&attr_list);
>> +    if (!hwconfig) {
>> +        vaDestroyConfig(hwctx->display, tmp_config->config_id);
>> +        av_freep(&tmp_config);
>> +    }
>> +    return err;
>> +}
>> +
>> ...
>> +
>> +static AVBufferRef *vaapi_pool_alloc(void *opaque, int size)
>> +{
>> +    AVHWFramesContext     *hwfc = opaque;
>> +    VAAPIFramesContext     *ctx = hwfc->internal->priv;
>> +    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
>> +    AVVAAPIFramesContext  *avfc = hwfc->hwctx;
>> +    VASurfaceID surface_id;
>> +    VAStatus vas;
>> +    AVBufferRef *ref;
>> +
>> +    vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
>> +                           hwfc->width, hwfc->height,
>> +                           &surface_id, 1,
>> +                           ctx->attributes, ctx->nb_attributes);
>> +    if (vas != VA_STATUS_SUCCESS) {
>> +        av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
>> +               "%d (%s).\n", vas, vaErrorStr(vas));
>> +        return NULL;
>> +    }
>> +    av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
>> +
>> +    ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
>> +                           sizeof(surface_id), &vaapi_buffer_free,
>> +                           hwfc, AV_BUFFER_FLAG_READONLY);
>> +    if (!ref) {
>> +        vaDestroySurfaces(hwctx->display, &surface_id, 1);
>> +        return NULL;
>> +    }
>> +
>> +    if (hwfc->initial_pool_size > 0) {
>> +        av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
>> +        avfc->surface_ids[avfc->nb_surfaces] = surface_id;
>> +    }
>> +    ++avfc->nb_surfaces;
>> +    if (avfc->nb_surfaces == 1) {
>> +        // Test whether vaDeriveImage() works for this type of surface.
>> +        VAImageFormat *expected_format;
>> +        VAImage test_image;
>> +        int err;
>> +
>> +        ctx->derive_works = 0;
> 
> I think this is unsafe, since this variable is also accessed in
> mapping the frame, which can easily happen concurrently with this
> function. So it would be better to make this test in frames_init.
> Also, this function won't be called at all if the caller supplies his
> own frame pool. The mapping function should work even then.

So call get_buffer() at the end of frames_init() and try the mapping there?
That might be slightly surprising to the user supplying their own pool, but
otherwise seems entirely reasonable.

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to