Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  chroma.c   Sprache: C

 

/*****************************************************************************
 * chroma.c: VLC picture to VAAPI surface or vice versa
 *****************************************************************************
 * Copyright (C) 2017 VLC authors, VideoLAN and VideoLabs
 *
 * Author: Victorien Le Couviour--Tuffet <victorien.lecouviour.tuffet@gmail.com>
 *
 * This program 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.
 *
 * This program 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 this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <assert.h>

#include <va/va.h>

#include <vlc_common.h>
#include <vlc_filter.h>
#include <vlc_plugin.h>

#include "../../video_chroma/copy.h"
#include "filters.h"

# define DEST_PICS_POOL_SZ 3

typedef struct
{
    VADisplay           dpy;
    picture_pool_t *    dest_pics;
    VASurfaceID *       va_surface_ids;
    copy_cache_t        cache;

    bool                derive_failed;
    bool                image_fallback_failed;
} filter_sys_t;

static int CreateFallbackImage(filter_t *filter, picture_t *src_pic,
                               VADisplay va_dpy, VAImage *image_fallback)
{
    int count = vaMaxNumImageFormats(va_dpy);

    VAImageFormat *fmts = vlc_alloc(count, sizeof (*fmts));
    if (unlikely(fmts == NULL))
        return VLC_ENOMEM;

    if (vaQueryImageFormats(va_dpy, fmts, &count))
    {
        free(fmts);
        return VLC_EGENERIC;
    }

    int i;
    for (i = 0; i < count; i++)
        if (fmts[i].fourcc == VA_FOURCC_NV12
         || fmts[i].fourcc == VA_FOURCC_I420
         || fmts[i].fourcc == VA_FOURCC_P010)
            break;

    int ret;
    if ((fmts[i].fourcc == VA_FOURCC_NV12 || fmts[i].fourcc == VA_FOURCC_I420
      || fmts[i].fourcc == VA_FOURCC_P010)
     && !vlc_vaapi_CreateImage(VLC_OBJECT(filter), va_dpy, &fmts[i],
                               src_pic->format.i_width, src_pic->format.i_height,
                               image_fallback))
        ret = VLC_SUCCESS;
    else
        ret = VLC_EGENERIC;

    free(fmts);

    return ret;
}

static inline void
FillPictureFromVAImage(picture_t *dest,
                       VAImage *src_img, uint8_t *src_buf, copy_cache_t *cache)
{
    const uint8_t * src_planes[3] = { src_buf + src_img->offsets[0],
                                      src_buf + src_img->offsets[1],
                                      src_buf + src_img->offsets[2] };
    const size_t    src_pitches[3] = { src_img->pitches[0],
                                       src_img->pitches[1],
                                       src_img->pitches[2] };

    switch (src_img->format.fourcc)
    {
    case VA_FOURCC_NV12:
    {
        assert(dest->format.i_chroma == VLC_CODEC_I420);
        Copy420_SP_to_P(dest, src_planes, src_pitches, src_img->height, cache);
        break;
    }
    case VA_FOURCC_I420:
    {
        assert(dest->format.i_chroma == VLC_CODEC_I420);
        Copy420_P_to_P(dest, src_planes, src_pitches, src_img->height, cache);
        break;
    }
    case VA_FOURCC_P010:
    case VA_FOURCC_P012:
        switch (dest->format.i_chroma)
        {
            case VLC_CODEC_P010:
            case VLC_CODEC_P012:
                Copy420_SP_to_SP(dest, src_planes, src_pitches, src_img->height,
                                 cache);
                break;
            case VLC_CODEC_I420_10L:
                Copy420_16_SP_to_P(dest, src_planes, src_pitches,
                                   src_img->height, 6, cache);
                break;
            case VLC_CODEC_I420_12L:
                Copy420_16_SP_to_P(dest, src_planes, src_pitches,
                                   src_img->height, 4, cache);
                break;
            default:
                vlc_assert_unreachable();
        }
        break;
    case VA_FOURCC_Y210:
    case VA_FOURCC_Y212:
    case VA_FOURCC_XYUV:
    case VA_FOURCC_Y410:
    case VA_FOURCC_Y412:
        CopyPacked(dest, src_planes[0], src_pitches[0], src_img->height,
                   cache);
        break;
    default:
        vlc_assert_unreachable();
        break;
    }
}

static picture_t *
DownloadSurface(filter_t *filter, picture_t *src_pic)
{
    filter_sys_t *const filter_sys = filter->p_sys;
    VADisplay           va_dpy = vlc_vaapi_PicGetDisplay(src_pic);
    VAImage             src_img;
    void *              src_buf;

    picture_t *dest = filter_NewPicture(filter);
    if (!dest)
    {
        msg_Err(filter, "filter_NewPicture failed");
        goto ret;
    }

    VAImageID image_fallback_id = VA_INVALID_ID;
    VASurfaceID surface = vlc_vaapi_PicGetSurface(src_pic);
    if (vaSyncSurface(va_dpy, surface))
        goto error;

    if (filter_sys->derive_failed ||
        vlc_vaapi_DeriveImage(VLC_OBJECT(filter), va_dpy, surface, &src_img))
    {
        if (filter_sys->image_fallback_failed)
            goto error;

        filter_sys->derive_failed = true;

        VAImage image_fallback;
        if (CreateFallbackImage(filter, src_pic, va_dpy, &image_fallback))
        {
            filter_sys->image_fallback_failed = true;
            goto error;
        }
        image_fallback_id = image_fallback.image_id;

        if (vaGetImage(va_dpy, surface, 0, 0, src_pic->format.i_width,
                       src_pic->format.i_height, image_fallback_id))
        {
            filter_sys->image_fallback_failed = true;
            goto error;
        }
        src_img = image_fallback;
    }

    if (vlc_vaapi_MapBuffer(VLC_OBJECT(filter), va_dpy, src_img.buf, &src_buf))
        goto error;

    FillPictureFromVAImage(dest, &src_img, src_buf, &filter_sys->cache);

    vlc_vaapi_UnmapBuffer(VLC_OBJECT(filter), va_dpy, src_img.buf);
    vlc_vaapi_DestroyImage(VLC_OBJECT(filter), va_dpy, src_img.image_id);

    picture_CopyProperties(dest, src_pic);
ret:
    picture_Release(src_pic);
    return dest;

error:
    if (image_fallback_id != VA_INVALID_ID)
        vlc_vaapi_DestroyImage(VLC_OBJECT(filter), va_dpy, image_fallback_id);

    picture_Release(dest);
    dest = NULL;
    goto ret;
}

static inline void
FillVAImageFromPicture(VAImage *dest_img, uint8_t *dest_buf,
                       picture_t *dest_pic, picture_t *src,
                       copy_cache_t *cache)
{
    const uint8_t * src_planes[3] = { src->p[Y_PLANE].p_pixels,
                                      src->p[U_PLANE].p_pixels,
                                      src->p[V_PLANE].p_pixels };
    const size_t    src_pitches[3] = { src->p[Y_PLANE].i_pitch,
                                       src->p[U_PLANE].i_pitch,
                                       src->p[V_PLANE].i_pitch };
    void *const     tmp[2] = { dest_pic->p[0].p_pixels,
                               dest_pic->p[1].p_pixels };

    dest_pic->p[0].p_pixels = dest_buf + dest_img->offsets[0];
    dest_pic->p[1].p_pixels = dest_buf + dest_img->offsets[1];
    dest_pic->p[0].i_pitch = dest_img->pitches[0];
    dest_pic->p[1].i_pitch = dest_img->pitches[1];

    switch (src->format.i_chroma)
    {
    case VLC_CODEC_I420:
        assert(dest_pic->format.i_chroma == VLC_CODEC_VAAPI_420);
        Copy420_P_to_SP(dest_pic, src_planes, src_pitches,
                        src->format.i_height, cache);

        break;
    case VLC_CODEC_I420_10L:
        assert(dest_pic->format.i_chroma == VLC_CODEC_VAAPI_420_10BPP);
        Copy420_16_P_to_SP(dest_pic, src_planes, src_pitches,
                           src->format.i_height, -6, cache);
        break;
    case VLC_CODEC_I420_12L:
        assert(dest_pic->format.i_chroma == VLC_CODEC_VAAPI_420_12BPP);
        Copy420_16_P_to_SP(dest_pic, src_planes, src_pitches,
                           src->format.i_height, -4, cache);
        break;
    case VLC_CODEC_P010:
    case VLC_CODEC_P012:
    {
        assert(dest_pic->format.i_chroma == VLC_CODEC_VAAPI_420_10BPP
            || dest_pic->format.i_chroma == VLC_CODEC_VAAPI_420_12BPP);
        Copy420_SP_to_SP(dest_pic,  src_planes, src_pitches,
                         src->format.i_height, cache);
        break;
    }
    case VLC_CODEC_VUYX:
    case VLC_CODEC_Y410:
    case VLC_CODEC_Y412:
        CopyPacked(dest_pic, src_planes[0], src_pitches[0],
                   src->format.i_height, cache);
        break;
    default:
        vlc_assert_unreachable();
    }

    dest_pic->p[0].p_pixels = tmp[0];
    dest_pic->p[1].p_pixels = tmp[1];
}

static picture_t *
UploadSurface(filter_t *filter, picture_t *src)
{
    filter_sys_t   *p_sys = filter->p_sys;
    VADisplay const va_dpy = p_sys->dpy;
    VAImage         dest_img;
    void *          dest_buf;
    picture_t *     dest_pic = picture_pool_Wait(p_sys->dest_pics);

    if (!dest_pic)
    {
        msg_Err(filter, "cannot retrieve picture from the dest pics pool");
        goto ret;
    }
    vlc_vaapi_PicAttachContext(dest_pic);
    picture_CopyProperties(dest_pic, src);

    if (p_sys->derive_failed ||
        vlc_vaapi_DeriveImage(VLC_OBJECT(filter), va_dpy,
                              vlc_vaapi_PicGetSurface(dest_pic), &dest_img))
    {
        if (p_sys->image_fallback_failed)
            goto error;

        p_sys->derive_failed = true;

        if (CreateFallbackImage(filter, dest_pic, va_dpy, &dest_img))
        {
            p_sys->image_fallback_failed = true;
            goto error;
        }
    }

    if (vlc_vaapi_MapBuffer(VLC_OBJECT(filter), va_dpy,
                            dest_img.buf, &dest_buf))
        goto error;

    FillVAImageFromPicture(&dest_img, dest_buf, dest_pic,
                           src, &p_sys->cache);

    if (vlc_vaapi_UnmapBuffer(VLC_OBJECT(filter), va_dpy, dest_img.buf))
        goto error;

    if (p_sys->derive_failed &&
        vaPutImage(va_dpy, vlc_vaapi_PicGetSurface(dest_pic), dest_img.image_id,
                   0, 0, dest_pic->format.i_width, dest_pic->format.i_height,
                   0, 0, dest_pic->format.i_width, dest_pic->format.i_height))
        goto error;

    if (vlc_vaapi_DestroyImage(VLC_OBJECT(filter),
                               va_dpy, dest_img.image_id))
        goto error;

ret:
    picture_Release(src);
    return dest_pic;

error:
    picture_Release(dest_pic);
    dest_pic = NULL;
    goto ret;
}

static int CheckFmt(const video_format_t *in, const video_format_t *out,
                    bool *upload, uint8_t *pixel_bytes)
{
    *pixel_bytes = 1;
    *upload = false;
    switch (in->i_chroma)
    {
        case VLC_CODEC_VAAPI_420:
            if (out->i_chroma == VLC_CODEC_I420)
                return VLC_SUCCESS;
            break;
        case VLC_CODEC_VAAPI_420_10BPP:
            if (out->i_chroma == VLC_CODEC_P010
             || out->i_chroma == VLC_CODEC_I420_10L)
            {
                *pixel_bytes = 2;
                return VLC_SUCCESS;
            }
            break;
        case VLC_CODEC_VAAPI_420_12BPP:
            if (out->i_chroma == VLC_CODEC_P012
             || out->i_chroma == VLC_CODEC_I420_12L)
            {
                *pixel_bytes = 2;
                return VLC_SUCCESS;
            }
            break;
        case VLC_CODEC_VAAPI_422_10BPP:
            if (out->i_chroma == VLC_CODEC_Y210)
            {
                *pixel_bytes = 4;
                return VLC_SUCCESS;
            }
            break;
        case VLC_CODEC_VAAPI_422_12BPP:
            if (out->i_chroma == VLC_CODEC_Y212)
            {
                *pixel_bytes = 4;
                return VLC_SUCCESS;
            }
            break;
        case VLC_CODEC_VAAPI_444:
            if (out->i_chroma == VLC_CODEC_VUYX)
            {
                *pixel_bytes = 4;
                return VLC_SUCCESS;
            }
            break;
        case VLC_CODEC_VAAPI_444_10BPP:
            if (out->i_chroma == VLC_CODEC_Y410)
            {
                *pixel_bytes = 4;
                return VLC_SUCCESS;
            }
            break;
        case VLC_CODEC_VAAPI_444_12BPP:
            if (out->i_chroma == VLC_CODEC_Y412)
            {
                *pixel_bytes = 8;
                return VLC_SUCCESS;
            }
            break;
    }

    *upload = true;
    switch (out->i_chroma)
    {
        case VLC_CODEC_VAAPI_420:
            if (in->i_chroma == VLC_CODEC_I420)
                return VLC_SUCCESS;
            break;
        case VLC_CODEC_VAAPI_420_10BPP:
            if (in->i_chroma == VLC_CODEC_P010
             || in->i_chroma == VLC_CODEC_I420_10L)
            {
                *pixel_bytes = 2;
                return VLC_SUCCESS;
            }
            break;
        case VLC_CODEC_VAAPI_420_12BPP:
            if (in->i_chroma == VLC_CODEC_P012
             || in->i_chroma == VLC_CODEC_I420_12L)
            {
                *pixel_bytes = 2;
                return VLC_SUCCESS;
            }
            break;
        case VLC_CODEC_VAAPI_422_10BPP:
            if (in->i_chroma == VLC_CODEC_Y210)
            {
                *pixel_bytes = 4;
                return VLC_SUCCESS;
            }
            break;
        case VLC_CODEC_VAAPI_422_12BPP:
            if (in->i_chroma == VLC_CODEC_Y212)
            {
                *pixel_bytes = 4;
                return VLC_SUCCESS;
            }
            break;
        case VLC_CODEC_VAAPI_444:
            if (in->i_chroma == VLC_CODEC_VUYX)
            {
                *pixel_bytes = 4;
                return VLC_SUCCESS;
            }
            break;
        case VLC_CODEC_VAAPI_444_10BPP:
            if (in->i_chroma == VLC_CODEC_Y410)
            {
                *pixel_bytes = 4;
                return VLC_SUCCESS;
            }
            break;
        case VLC_CODEC_VAAPI_444_12BPP:
            if (in->i_chroma == VLC_CODEC_Y412)
            {
                *pixel_bytes = 8;
                return VLC_SUCCESS;
            }
            break;
    }
    return VLC_EGENERIC;
}

static const struct vlc_filter_operations filter_upload_ops = {
    .filter_video = UploadSurface,   .close = vlc_vaapi_CloseChroma,
};

static const struct vlc_filter_operations filter_download_ops = {
    .filter_video = DownloadSurface, .close = vlc_vaapi_CloseChroma,
};

int
vlc_vaapi_OpenChroma(filter_t *filter)
{
    filter_sys_t *      filter_sys;

    if (filter->fmt_in.video.i_height != filter->fmt_out.video.i_height
     || filter->fmt_in.video.i_width != filter->fmt_out.video.i_width
     || filter->fmt_in.video.orientation != filter->fmt_out.video.orientation)
        return VLC_EGENERIC;

    bool is_upload;
    uint8_t pixel_bytes;
    if (CheckFmt(&filter->fmt_in.video, &filter->fmt_out.video, &is_upload,
                 &pixel_bytes))
        return VLC_EGENERIC;

    filter->ops = is_upload ? &filter_upload_ops : &filter_download_ops;

    if (!(filter_sys = calloc(1, sizeof(filter_sys_t))))
    {
        return VLC_ENOMEM;
    }
    filter_sys->derive_failed = false;
    filter_sys->image_fallback_failed = false;
    if (is_upload)
    {
        vlc_decoder_device *dec_device = filter_HoldDecoderDeviceType( filter, VLC_DECODER_DEVICE_VAAPI );
        if (dec_device == NULL)
        {
            free(filter_sys);
            return VLC_EGENERIC;
        }

        filter->vctx_out = vlc_video_context_Create( dec_device, VLC_VIDEO_CONTEXT_VAAPI, 0, NULL );
        vlc_decoder_device_Release(dec_device);
        if (!filter->vctx_out)
        {
            free(filter_sys);
            return VLC_EGENERIC;
        }

        filter_sys->dpy = dec_device->opaque;

        filter_sys->dest_pics =
            vlc_vaapi_PoolNew(VLC_OBJECT(filter), filter->vctx_out, filter_sys->dpy,
                              DEST_PICS_POOL_SZ, &filter_sys->va_surface_ids,
                              &filter->fmt_out.video);
        if (!filter_sys->dest_pics)
        {
            vlc_video_context_Release(filter->vctx_out);
            filter->vctx_out = NULL;
            free(filter_sys);
            return VLC_EGENERIC;
        }
    }
    else
    {
        /* Don't fetch the vaapi instance since it may be not created yet at
         * this point (in case of cpu rendering) */

        filter_sys->dpy = NULL;
        filter_sys->dest_pics = NULL;
    }

    if (CopyInitCache(&filter_sys->cache, filter->fmt_in.video.i_width
                      * pixel_bytes))
    {
        if (is_upload)
        {
            picture_pool_Release(filter_sys->dest_pics);
            vlc_video_context_Release(filter->vctx_out);
            filter->vctx_out = NULL;
        }
        free(filter_sys);
        return VLC_EGENERIC;
    }

    filter->p_sys = filter_sys;
    msg_Warn(filter, "Using SW chroma filter for %dx%d %4.4s -> %4.4s",
             filter->fmt_in.video.i_width,
             filter->fmt_in.video.i_height,
             (const char *) &filter->fmt_in.video.i_chroma,
             (const char *) &filter->fmt_out.video.i_chroma);

    return VLC_SUCCESS;
}

void
vlc_vaapi_CloseChroma(filter_t *filter)
{
    filter_sys_t *const filter_sys = filter->p_sys;

    if (filter_sys->dest_pics)
        picture_pool_Release(filter_sys->dest_pics);
    CopyCleanCache(&filter_sys->cache);
    if (filter->vctx_out)
        vlc_video_context_Release(filter->vctx_out);

    free(filter_sys);
}

Messung
CHZG
829610092

¤ Dauer der Verarbeitung: 0.3 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104851
#Domains=417124