Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/video_chroma/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 28 kB image not shown  

Quelle  swscale.c   Sprache: C

 

/*****************************************************************************
 * swscale.c: scaling and chroma conversion using libswscale
 *****************************************************************************
 * Copyright (C) 1999-2008 VLC authors and VideoLAN
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *          Gildas Bazin <gbazin@videolan.org>
 *
 * 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.
 *****************************************************************************/


/*****************************************************************************
 * Preamble
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <assert.h>

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_filter.h>
#include <vlc_picture.h>
#include <vlc_chroma_probe.h>
#include <vlc_cpu.h>

#include <libswscale/swscale.h>
#include <libswscale/version.h>

#ifdef __APPLE__
# include <TargetConditionals.h>
#endif

#include "../codec/avcodec/chroma.h" // Chroma Avutil <-> VLC conversion

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/

static int  OpenScaler( filter_t * );
static void CloseScaler( filter_t * );

#define SCALEMODE_TEXT N_("Scaling mode")
#define SCALEMODE_LONGTEXT NULL

static const int pi_mode_values[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
static const char *const ppsz_mode_descriptions[] =
{ N_("Fast bilinear"), N_("Bilinear"), N_("Bicubic (good quality)"),
  N_("Experimental"), N_("Nearest neighbor (bad quality)"),
  N_("Area"), N_("Luma bicubic / chroma bilinear"), N_("Gauss"),
  N_("SincR"), N_("Lanczos"), N_("Bicubic spline") };

static void ProbeChroma(vlc_chroma_conv_vec *vec)
{
#define COST_FACTOR 1
    size_t count;
    const struct vlc_chroma_ffmpeg *table = GetVlcChromaFfmpegTable(&count);
    assert(table != NULL && count > 0);

    for (size_t i = 0; i < count; i++)
    {
        vlc_fourcc_t cur_chroma = table[i].i_chroma;
        enum AVPixelFormat cur_avpf = table[i].i_chroma_id;
        bool cur_supported_input = sws_isSupportedInput(cur_avpf);
        bool cur_supported_output = sws_isSupportedOutput(cur_avpf);

        if (!cur_supported_input && !cur_supported_output)
            continue;

        for (size_t j = i + 1; j < count; j++)
        {
            vlc_fourcc_t next_chroma = table[j].i_chroma;

            if (next_chroma == cur_chroma)
                continue;

            enum AVPixelFormat next_avpf = table[j].i_chroma_id;
            bool next_supported_input = sws_isSupportedInput(next_avpf);
            bool next_supported_output = sws_isSupportedOutput(next_avpf);

            if (!next_supported_input && !next_supported_output)
                continue;

            if (cur_supported_input && cur_supported_output
             && next_supported_input && next_supported_output)
            {
                /* Likely case: add in <-> out two way conversion */
                vlc_chroma_conv_add(vec, COST_FACTOR, cur_chroma, next_chroma,
                                    true);
            }
            else
            {
                if (cur_supported_input && next_supported_output)
                    vlc_chroma_conv_add(vec, COST_FACTOR, cur_chroma, next_chroma,
                                        false);
                else if (cur_supported_output && next_supported_input)
                    vlc_chroma_conv_add(vec, COST_FACTOR, next_chroma, cur_chroma,
                                        false);
            }
        }
    }
}

vlc_module_begin ()
    set_description( N_("Video scaling filter") )
    set_shortname( N_("Swscale" ) )
    set_subcategory( SUBCAT_VIDEO_VFILTER )
    set_callback_video_converter( OpenScaler, 150 )
    add_integer( "swscale-mode", 2, SCALEMODE_TEXT, SCALEMODE_LONGTEXT )
        change_integer_list( pi_mode_values, ppsz_mode_descriptions )
    add_submodule()
        set_callback_chroma_conv_probe(ProbeChroma)
vlc_module_end ()

/* Version checking */
/****************************************************************************
 * Local prototypes
 ****************************************************************************/


/**
 * Internal swscale filter structure.
 */

typedef struct
{
    SwsFilter *p_filter;
    int i_sws_flags;

    video_format_t fmt_in;
    video_format_t fmt_out;
    const vlc_chroma_description_t *desc_in;
    const vlc_chroma_description_t *desc_out;

    struct SwsContext *ctx;
    struct SwsContext *ctxA;
    picture_t *p_src_a;
    picture_t *p_dst_a;
    int i_extend_factor;
    picture_t *p_src_e;
    picture_t *p_dst_e;
    bool b_add_a;
    bool b_copy;
    bool b_swap_uvi;
    bool b_swap_uvo;
} filter_sys_t;

static picture_t *Filter( filter_t *, picture_t * );
static int  Init( filter_t * );
static void Clean( filter_t * );

typedef struct
{
    enum AVPixelFormat i_fmti;
    enum AVPixelFormat i_fmto;
    bool b_has_a;
    bool b_add_a;
    int  i_sws_flags;
    bool b_copy;
    bool b_swap_uvi;
    bool b_swap_uvo;
} ScalerConfiguration;

static int GetParameters( ScalerConfiguration *,
                          const video_format_t *p_fmti,
                          const video_format_t *p_fmto,
                          int i_sws_flags_default );

/* SwScaler point resize quality seems really bad, let our scale module do it
 * (change it to true to try) */

#define ALLOW_YUVP (false)
/* SwScaler does not like too small picture */
#define MINIMUM_WIDTH (32)

/* XXX is it always 3 even for BIG_ENDIAN (blend.c seems to think so) ? */
#define OFFSET_A (3)

static const struct vlc_filter_operations filter_ops = {
    .filter_video = Filter, .close = CloseScaler,
};

static int GetSwsColorspace( const video_format_t *format )
{
    /* We currently map bt2020, bt709 and bt601, all other are unspecified */
    switch( format->space )
    {
        case COLOR_SPACE_BT709:
            return SWS_CS_ITU709;
        case COLOR_SPACE_BT601:
            return SWS_CS_ITU601;
        case COLOR_SPACE_BT2020:
            return SWS_CS_BT2020;
        default:
            return SWS_CS_DEFAULT;
    }
}

static const char* GetColorspaceName( video_color_space_t space )
{
    switch( space )
    {
        case COLOR_SPACE_BT601:
            return "BT601";
        case COLOR_SPACE_BT709:
            return "BT709";
        case COLOR_SPACE_BT2020:
            return "BT2020";
        default:
            return "Undefined";
    }
}

static void SetColorspace( filter_sys_t *p_sys )
{
    int input_range, output_range;
    int brightness, contrast, saturation;
    const int *input_table, *output_table;

    sws_getColorspaceDetails( p_sys->ctx, (int **)&input_table, &input_range,
                              (int **)&output_table, &output_range,
                              &brightness, &contrast, &saturation );

    input_range = p_sys->fmt_in.color_range == COLOR_RANGE_FULL;
    output_range = p_sys->fmt_out.color_range == COLOR_RANGE_FULL;

    input_table = sws_getCoefficients( GetSwsColorspace( &p_sys->fmt_in ) );
    output_table = sws_getCoefficients( GetSwsColorspace( &p_sys->fmt_out ) );

    sws_setColorspaceDetails( p_sys->ctx, input_table, input_range,
                              output_table, output_range,
                              brightness, contrast, saturation );
}

/*****************************************************************************
 * OpenScaler: probe the filter and return score
 *****************************************************************************/

static int OpenScaler( filter_t *p_filter )
{
    filter_sys_t *p_sys;

    int i_sws_mode;

    if( GetParameters( NULL,
                       &p_filter->fmt_in.video,
                       &p_filter->fmt_out.video, 0 ) )
        return VLC_EGENERIC;

    /* Allocate the memory needed to store the decoder's structure */
    if( ( p_filter->p_sys = p_sys = calloc(1, sizeof(filter_sys_t)) ) == NULL )
        return VLC_ENOMEM;

    /* */
    i_sws_mode = var_CreateGetInteger( p_filter, "swscale-mode" );
    switch( i_sws_mode )
    {
    case 0:  p_sys->i_sws_flags = SWS_FAST_BILINEAR; break;
    case 1:  p_sys->i_sws_flags = SWS_BILINEAR; break;
    case 2:  p_sys->i_sws_flags = SWS_BICUBIC; break;
    case 3:  p_sys->i_sws_flags = SWS_X; break;
    case 4:  p_sys->i_sws_flags = SWS_POINT; break;
    case 5:  p_sys->i_sws_flags = SWS_AREA; break;
    case 6:  p_sys->i_sws_flags = SWS_BICUBLIN; break;
    case 7:  p_sys->i_sws_flags = SWS_GAUSS; break;
    case 8:  p_sys->i_sws_flags = SWS_SINC; break;
    case 9:  p_sys->i_sws_flags = SWS_LANCZOS; break;
    case 10: p_sys->i_sws_flags = SWS_SPLINE; break;
    default: p_sys->i_sws_flags = SWS_BICUBIC; i_sws_mode = 2; break;
    }

    /* Misc init */
    memset( &p_sys->fmt_in,  0, sizeof(p_sys->fmt_in) );
    memset( &p_sys->fmt_out, 0, sizeof(p_sys->fmt_out) );

    if( Init( p_filter ) )
    {
        if( p_sys->p_filter )
            sws_freeFilter( p_sys->p_filter );
        free( p_sys );
        return VLC_EGENERIC;
    }

    /* */
    p_filter->ops = &filter_ops;

    msg_Dbg( p_filter, "%ix%i (%ix%i) chroma: %4.4s colorspace: %s -> %ix%i (%ix%i) chroma: %4.4s colorspace: %s with scaling using %s",
             p_filter->fmt_in.video.i_visible_width, p_filter->fmt_in.video.i_visible_height,
             p_filter->fmt_in.video.i_width, p_filter->fmt_in.video.i_height,
             (char *)&p_filter->fmt_in.video.i_chroma, GetColorspaceName( p_filter->fmt_in.video.space ),
             p_filter->fmt_out.video.i_visible_width, p_filter->fmt_out.video.i_visible_height,
             p_filter->fmt_out.video.i_width, p_filter->fmt_out.video.i_height,
             (char *)&p_filter->fmt_out.video.i_chroma, GetColorspaceName( p_filter->fmt_out.video.space ),
             ppsz_mode_descriptions[i_sws_mode] );

    return VLC_SUCCESS;
}

/*****************************************************************************
 * CloseFilter: clean up the filter
 *****************************************************************************/

static void CloseScaler( filter_t *p_filter )
{
    filter_sys_t *p_sys = p_filter->p_sys;

    Clean( p_filter );
    if( p_sys->p_filter )
        sws_freeFilter( p_sys->p_filter );
    free( p_sys );
}

/*****************************************************************************
 * Helpers
 *****************************************************************************/

static void FixParameters( enum AVPixelFormat *pi_fmt, bool *pb_has_a, vlc_fourcc_t fmt )
{
    switch( fmt )
    {
    case VLC_CODEC_YUV422A:
        *pi_fmt = AV_PIX_FMT_YUVA422P;
        *pb_has_a = true;
        break;
    case VLC_CODEC_YUV420A:
        *pi_fmt = AV_PIX_FMT_YUVA420P;
        *pb_has_a = true;
        break;
    case VLC_CODEC_YUVA:
        *pi_fmt = AV_PIX_FMT_YUV444P;
        *pb_has_a = true;
        break;
    case VLC_CODEC_RGBA:
        *pi_fmt = AV_PIX_FMT_RGBA;
        *pb_has_a = true;
        break;
    case VLC_CODEC_ARGB:
        *pi_fmt = AV_PIX_FMT_ARGB;
        *pb_has_a = true;
        break;
    case VLC_CODEC_BGRA:
        *pi_fmt = AV_PIX_FMT_BGRA;
        *pb_has_a = true;
        break;
    case VLC_CODEC_ABGR:
        *pi_fmt = AV_PIX_FMT_ABGR;
        *pb_has_a = true;
        break;
    default:
        break;
    }
}

static int GetParameters( ScalerConfiguration *p_cfg,
                          const video_format_t *p_fmti,
                          const video_format_t *p_fmto,
                          int i_sws_flags_default )
{
    enum AVPixelFormat i_fmti;
    enum AVPixelFormat i_fmto;

    bool b_has_ai = false;
    bool b_has_ao = false;
    int i_sws_flags = i_sws_flags_default;
    bool b_swap_uvi = false;
    bool b_swap_uvo = false;

    i_fmti = FindFfmpegChroma( p_fmti->i_chroma, &b_swap_uvi );
    i_fmto = FindFfmpegChroma( p_fmto->i_chroma, &b_swap_uvo );

    if( p_fmti->i_chroma == p_fmto->i_chroma )
    {
        if( p_fmti->i_chroma == VLC_CODEC_YUVP && ALLOW_YUVP )
        {
            i_fmti = i_fmto = AV_PIX_FMT_GRAY8;
            i_sws_flags = SWS_POINT;
        }
    }

    FixParameters( &i_fmti, &b_has_ai, p_fmti->i_chroma );
    FixParameters( &i_fmto, &b_has_ao, p_fmto->i_chroma );

#if !defined (__ANDROID__) && !defined(TARGET_OS_IPHONE)
    /* FIXME TODO removed when ffmpeg is fixed
     * Without SWS_ACCURATE_RND the quality is really bad for some conversions */

    switch( i_fmto )
    {
    case AV_PIX_FMT_ARGB:
    case AV_PIX_FMT_RGBA:
    case AV_PIX_FMT_ABGR:
        i_sws_flags |= SWS_ACCURATE_RND;
        break;
    default:
        break;
    }
#endif

    if( p_cfg )
    {
        p_cfg->i_fmti = i_fmti;
        p_cfg->i_fmto = i_fmto;
        p_cfg->b_has_a = b_has_ai && b_has_ao;
        p_cfg->b_add_a = (!b_has_ai) && b_has_ao;
        p_cfg->b_copy = i_fmti == i_fmto &&
                        p_fmti->i_visible_width == p_fmto->i_visible_width &&
                        p_fmti->i_visible_height == p_fmto->i_visible_height;
        p_cfg->b_swap_uvi = b_swap_uvi;
        p_cfg->b_swap_uvo = b_swap_uvo;
        p_cfg->i_sws_flags = i_sws_flags;
    }

    if( i_fmti < 0 || i_fmto < 0 )
        return VLC_EGENERIC;

    return VLC_SUCCESS;
}

static int Init( filter_t *p_filter )
{
    filter_sys_t *p_sys = p_filter->p_sys;
    const video_format_t *p_fmti = &p_filter->fmt_in.video;
    video_format_t       *p_fmto = &p_filter->fmt_out.video;

    if( p_fmti->orientation != p_fmto->orientation )
        return VLC_EGENERIC;

    if( video_format_IsSimilar( p_fmti, &p_sys->fmt_in ) &&
        video_format_IsSimilar( p_fmto, &p_sys->fmt_out ) &&
        p_sys->ctx )
    {
        return VLC_SUCCESS;
    }

    Clean( p_filter );

    /* Init with new parameters */
    ScalerConfiguration cfg;
    if( GetParameters( &cfg, p_fmti, p_fmto, p_sys->i_sws_flags ) )
    {
        msg_Err( p_filter, "format not supported '%4.4s' %ux%u -> '%4.4s' %ux%u",
                 (const char *)&p_fmti->i_chroma, p_fmti->i_visible_width, p_fmti->i_visible_height,
                 (const char *)&p_fmto->i_chroma, p_fmto->i_visible_width, p_fmto->i_visible_height );
        return VLC_EGENERIC;
    }
    if( p_fmti->i_visible_width == 0 || p_fmti->i_visible_height == 0 ||
        p_fmto->i_visible_width == 0 || p_fmto->i_visible_height == 0 )
    {
        msg_Err( p_filter, "invalid scaling: %ix%i -> %ix%i",
                 p_fmti->i_visible_width, p_fmti->i_visible_height,
                 p_fmto->i_visible_width, p_fmto->i_visible_height);
        return VLC_EGENERIC;
    }

    p_sys->desc_in = vlc_fourcc_GetChromaDescription( p_fmti->i_chroma );
    p_sys->desc_out = vlc_fourcc_GetChromaDescription( p_fmto->i_chroma );
    if( p_sys->desc_in == NULL || p_sys->desc_out == NULL )
        return VLC_EGENERIC;

    if( p_sys->desc_in->plane_count == 0 || p_sys->desc_out->plane_count == 0 )
        return VLC_EGENERIC;

    /* swscale does not like too small width */
    p_sys->i_extend_factor = 1;
    while( __MIN( p_fmti->i_visible_width, p_fmto->i_visible_width ) * p_sys->i_extend_factor < MINIMUM_WIDTH)
        p_sys->i_extend_factor++;

    const unsigned i_fmti_visible_width = p_fmti->i_visible_width * p_sys->i_extend_factor;
    const unsigned i_fmto_visible_width = p_fmto->i_visible_width * p_sys->i_extend_factor;
    for( int n = 0; n < (cfg.b_has_a ? 2 : 1); n++ )
    {
        const int i_fmti = n == 0 ? cfg.i_fmti : AV_PIX_FMT_GRAY8;
        const int i_fmto = n == 0 ? cfg.i_fmto : AV_PIX_FMT_GRAY8;
        struct SwsContext *ctx;

        ctx = sws_getContext( i_fmti_visible_width, p_fmti->i_visible_height, i_fmti,
                              i_fmto_visible_width, p_fmto->i_visible_height, i_fmto,
                              cfg.i_sws_flags,
                              p_sys->p_filter, NULL, 0 );
        if( n == 0 )
            p_sys->ctx = ctx;
        else
            p_sys->ctxA = ctx;
    }
    if( p_sys->ctxA )
    {
        p_sys->p_src_a = picture_New( VLC_CODEC_GREY, i_fmti_visible_width, p_fmti->i_visible_height, 0, 1 );
        p_sys->p_dst_a = picture_New( VLC_CODEC_GREY, i_fmto_visible_width, p_fmto->i_visible_height, 0, 1 );
    }
    if( p_sys->i_extend_factor != 1 )
    {
        p_sys->p_src_e = picture_New( p_fmti->i_chroma, i_fmti_visible_width, p_fmti->i_visible_height, 0, 1 );
        p_sys->p_dst_e = picture_New( p_fmto->i_chroma, i_fmto_visible_width, p_fmto->i_visible_height, 0, 1 );

        if( p_sys->p_src_e )
            memset( p_sys->p_src_e->p[0].p_pixels, 0, p_sys->p_src_e->p[0].i_pitch * p_sys->p_src_e->p[0].i_lines );
        if( p_sys->p_dst_e )
            memset( p_sys->p_dst_e->p[0].p_pixels, 0, p_sys->p_dst_e->p[0].i_pitch * p_sys->p_dst_e->p[0].i_lines );
    }

    if( !p_sys->ctx ||
        ( cfg.b_has_a && ( !p_sys->ctxA || !p_sys->p_src_a || !p_sys->p_dst_a ) ) ||
        ( p_sys->i_extend_factor != 1 && ( !p_sys->p_src_e || !p_sys->p_dst_e ) ) )
    {
        msg_Err( p_filter, "could not init SwScaler and/or allocate memory" );
        Clean( p_filter );
        return VLC_EGENERIC;
    }

    if (p_filter->b_allow_fmt_out_change)
    {
        /*
         * If the transformation is not homothetic we must modify the
         * aspect ratio of the output format in order to have the
         * output picture displayed correctly and not stretched
         * horizontally or vertically.
         * WARNING: this is a hack, ideally this should not be needed
         * and the vout should update its video format instead.
         */

        unsigned i_sar_num = p_fmti->i_sar_num * p_fmti->i_visible_width;
        unsigned i_sar_den = p_fmti->i_sar_den * p_fmto->i_visible_width;
        vlc_ureduce(&i_sar_num, &i_sar_den, i_sar_num, i_sar_den, 65536);
        i_sar_num *= p_fmto->i_visible_height;
        i_sar_den *= p_fmti->i_visible_height;
        vlc_ureduce(&i_sar_num, &i_sar_den, i_sar_num, i_sar_den, 65536);
        p_fmto->i_sar_num = i_sar_num;
        p_fmto->i_sar_den = i_sar_den;
    }

    p_sys->b_add_a = cfg.b_add_a;
    p_sys->b_copy = cfg.b_copy;
    p_sys->fmt_in  = *p_fmti;
    p_sys->fmt_out = *p_fmto;
    p_sys->b_swap_uvi = cfg.b_swap_uvi;
    p_sys->b_swap_uvo = cfg.b_swap_uvo;

    SetColorspace( p_sys );

    return VLC_SUCCESS;
}

static void Clean( filter_t *p_filter )
{
    filter_sys_t *p_sys = p_filter->p_sys;

    if( p_sys->p_src_e )
        picture_Release( p_sys->p_src_e );
    if( p_sys->p_dst_e )
        picture_Release( p_sys->p_dst_e );

    if( p_sys->p_src_a )
        picture_Release( p_sys->p_src_a );
    if( p_sys->p_dst_a )
        picture_Release( p_sys->p_dst_a );

    if( p_sys->ctxA )
        sws_freeContext( p_sys->ctxA );

    if( p_sys->ctx )
        sws_freeContext( p_sys->ctx );

    /* We have to set it to null has we call be called again :( */
    p_sys->ctx = NULL;
    p_sys->ctxA = NULL;
    p_sys->p_src_a = NULL;
    p_sys->p_dst_a = NULL;
    p_sys->p_src_e = NULL;
    p_sys->p_dst_e = NULL;
}

static void GetPixels( uint8_t *pp_pixel[4], int pi_pitch[4],
                       const vlc_chroma_description_t *desc,
                       const video_format_t *fmt,
                       const picture_t *p_picture, unsigned planes,
                       bool b_swap_uv )
{
    unsigned i = 0;

    if( planes > (unsigned)p_picture->i_planes )
        planes = p_picture->i_planes;
    assert( !b_swap_uv || planes >= 3 );

    for( ; i < planes; i++ )
    {
        const plane_t *p = p_picture->p + i;
        if( b_swap_uv && (i == 1 || i== 2) )
            p = p_picture->p + 3 - i;

        pp_pixel[i] = p->p_pixels
            + (((fmt->i_x_offset * desc->p[i].w.num) / desc->p[i].w.den)
                * p->i_pixel_pitch)
            + (((fmt->i_y_offset * desc->p[i].h.num) / desc->p[i].h.den)
                * p->i_pitch);
        pi_pitch[i] = p->i_pitch;
    }

    for( ; i < 4; i++ )
    {
        pp_pixel[i] = NULL;
        pi_pitch[i] = 0;
    }
}

static void ExtractA( picture_t *p_dst, const picture_t *restrict p_src,
                      unsigned x_offset, unsigned y_offset, unsigned offset )
{
    plane_t *d = &p_dst->p[0];
    const plane_t *s = &p_src->p[0];
    const uint8_t *src = s->p_pixels + y_offset * s->i_pitch
                       + x_offset * s->i_pixel_pitch + offset;

    for( unsigned y = 0; y < p_dst->format.i_height; y++ )
        for( unsigned x = 0; x < p_dst->format.i_width; x++ )
            d->p_pixels[y*d->i_pitch+x] = src[y*s->i_pitch+x*s->i_pixel_pitch];
}

static void InjectA( picture_t *p_dst, const picture_t *restrict p_src,
                     unsigned offset )
{
    plane_t *d = &p_dst->p[0];
    const plane_t *s = &p_src->p[0];

    for( unsigned y = 0; y < p_src->format.i_height; y++ )
        for( unsigned x = 0; x < p_src->format.i_width; x++ )
            d->p_pixels[y*d->i_pitch+4*x+offset] = s->p_pixels[y*s->i_pitch+x];
}

static void FillA( plane_t *d, unsigned i_offset )
{
    for( int y = 0; y < d->i_visible_lines; y++ )
        for( int x = 0; x < d->i_visible_pitch; x += d->i_pixel_pitch )
            d->p_pixels[y*d->i_pitch+x+i_offset] = 0xff;
}

static void ConvertA( struct SwsContext *ctx, plane_t *dst_plane,
                      const plane_t *src_plane, int i_height )
{
    /* src/dst are GREY planes that already hold the cropped,
     * de-offset alpha. Feed swscale their raw pixels. */

    const uint8_t *src[4] = { src_plane->p_pixels, NULL, NULL, NULL };
    uint8_t *dst[4] = { dst_plane->p_pixels, NULL, NULL, NULL };
    const int src_stride[4] = { src_plane->i_pitch, 0, 0, 0 };
    const int dst_stride[4] = { dst_plane->i_pitch, 0, 0, 0 };

    sws_scale( ctx, src, src_stride, 0, i_height, dst, dst_stride );
}


static void CopyPad( picture_t *p_dst, const picture_t *p_src )
{
    picture_Copy( p_dst, p_src );
    for( int n = 0; n < p_dst->i_planes; n++ )
    {
        const plane_t *s = &p_src->p[n];
        plane_t *d = &p_dst->p[n];

        for( int y = 0; y < s->i_lines && y < d->i_lines; y++ )
        {
            for( int x = s->i_visible_pitch; x < d->i_visible_pitch; x += s->i_pixel_pitch )
                memcpy( &d->p_pixels[y*d->i_pitch + x], &d->p_pixels[y*d->i_pitch + s->i_visible_pitch - s->i_pixel_pitch], s->i_pixel_pitch );
        }
    }
}

static void SwapUV( picture_t *p_dst, const picture_t *p_src )
{
    picture_t tmp = *p_src;
    tmp.p[1] = p_src->p[2];
    tmp.p[2] = p_src->p[1];

    picture_CopyPixels( p_dst, &tmp );
}

static void Convert( filter_t *p_filter, struct SwsContext *ctx,
                     picture_t *p_dst, picture_t *p_src, int i_height,
                     int i_plane_count, bool b_swap_uvi, bool b_swap_uvo )
{
    filter_sys_t *p_sys = p_filter->p_sys;
    uint8_t palette[AVPALETTE_SIZE];
    uint8_t *src[4], *dst[4];
    const uint8_t *csrc[4];
    int src_stride[4], dst_stride[4];

    GetPixels( src, src_stride, p_sys->desc_in, &p_filter->fmt_in.video,
               p_src, i_plane_count, b_swap_uvi );
    if( p_filter->fmt_in.video.i_chroma == VLC_CODEC_RGBP )
    {
        /* The palette may change every picture, that's why we check it here. */
        const video_palette_t *p_palette = p_src->format.p_palette;
        if( p_palette )
        {
            static_assert(sizeof(p_palette->palette) == AVPALETTE_SIZE,
                          "Palette size mismatch between vlc and libavutil");
            uint8_t *dstp = palette;
            for(int i=0; i<p_palette->i_entries; i++)
            {
                // we want ARGB in host endianess from RGBA in byte order
#ifdef WORDS_BIGENDIAN
                dstp[0] = p_palette->palette[i][3];
                dstp[1] = p_palette->palette[i][0];
                dstp[2] = p_palette->palette[i][1];
                dstp[3] = p_palette->palette[i][2];
#else
                dstp[0] = p_palette->palette[i][2];
                dstp[1] = p_palette->palette[i][1];
                dstp[2] = p_palette->palette[i][0];
                dstp[3] = p_palette->palette[i][3];
#endif
                dstp += sizeof(p_palette->palette[0]);
            }
        }
        else
        {
            memset( &palette, 0, sizeof(palette) );
        }
        src[1] = palette;
        src_stride[1] = 4;
    }

    GetPixels( dst, dst_stride, p_sys->desc_out, &p_filter->fmt_out.video,
               p_dst, i_plane_count, b_swap_uvo );

    for (size_t i = 0; i < ARRAY_SIZE(src); i++)
        csrc[i] = src[i];

    sws_scale( ctx, csrc, src_stride, 0, i_height,
               dst, dst_stride );
}

/****************************************************************************
 * Filter: the whole thing
 ****************************************************************************
 * This function is called just after the thread is launched.
 ****************************************************************************/

static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
{
    filter_sys_t *p_sys = p_filter->p_sys;
    const video_format_t *p_fmti = &p_filter->fmt_in.video;
    const video_format_t *p_fmto = &p_filter->fmt_out.video;
    picture_t *p_pic_dst;

    /* Check if format properties changed */
    if( Init( p_filter ) )
    {
        picture_Release( p_pic );
        return NULL;
    }

    /* Request output picture */
    p_pic_dst = filter_NewPicture( p_filter );
    if( !p_pic_dst )
    {
        picture_Release( p_pic );
        return NULL;
    }

    /* */
    picture_t *p_src = p_pic;
    picture_t *p_dst = p_pic_dst;
    if( p_sys->i_extend_factor != 1 )
    {
        p_src = p_sys->p_src_e;
        p_dst = p_sys->p_dst_e;

        CopyPad( p_src, p_pic );
    }

    if( p_sys->b_copy && p_sys->b_swap_uvi == p_sys->b_swap_uvo )
        picture_CopyPixels( p_dst, p_src );
    else if( p_sys->b_copy )
        SwapUV( p_dst, p_src );
    else
    {
        /* Even if alpha is unused, swscale expects the pointer to be set */
        const int n_planes = !p_sys->ctxA && (p_src->i_planes == 4 ||
                             p_dst->i_planes == 4) ? 4 : 3;
        Convert( p_filter, p_sys->ctx, p_dst, p_src, p_fmti->i_visible_height,
                 n_planes, p_sys->b_swap_uvi, p_sys->b_swap_uvo );
    }
    if( p_sys->ctxA )
    {
        /* We extract the A plane to rescale it, and then we reinject it. */
        if( p_fmti->i_chroma == VLC_CODEC_RGBA || p_fmti->i_chroma == VLC_CODEC_BGRA )
            ExtractA( p_sys->p_src_a, p_src, p_fmti->i_x_offset, p_fmti->i_y_offset, OFFSET_A );
        else if( p_fmti->i_chroma == VLC_CODEC_ARGB || p_fmti->i_chroma == VLC_CODEC_ABGR )
            ExtractA( p_sys->p_src_a, p_src, p_fmti->i_x_offset, p_fmti->i_y_offset, 0 );
        else
        {
            plane_t a = p_src->p[A_PLANE];
            a.p_pixels += p_fmti->i_y_offset * a.i_pitch
                        + p_fmti->i_x_offset * a.i_pixel_pitch;
            plane_CopyPixels( p_sys->p_src_a->p, &a );
        }

        ConvertA( p_sys->ctxA, &p_sys->p_dst_a->p[0], &p_sys->p_src_a->p[0],
                  p_fmti->i_visible_height );
        if( p_fmto->i_chroma == VLC_CODEC_RGBA || p_fmto->i_chroma == VLC_CODEC_BGRA )
            InjectA( p_dst, p_sys->p_dst_a, OFFSET_A );
        else if( p_fmto->i_chroma == VLC_CODEC_ARGB || p_fmto->i_chroma == VLC_CODEC_ABGR )
            InjectA( p_dst, p_sys->p_dst_a, 0 );
        else
            plane_CopyPixels( p_dst->p+A_PLANE, p_sys->p_dst_a->p );
    }
    else if( p_sys->b_add_a )
    {
        /* We inject a complete opaque alpha plane */
        if( p_fmto->i_chroma == VLC_CODEC_RGBA || p_fmto->i_chroma == VLC_CODEC_BGRA )
            FillA( &p_dst->p[0], OFFSET_A );
        else if( p_fmto->i_chroma == VLC_CODEC_ARGB || p_fmto->i_chroma == VLC_CODEC_ABGR )
            FillA( &p_dst->p[0], 0 );
        else
            FillA( &p_dst->p[A_PLANE], 0 );
    }

    if( p_sys->i_extend_factor != 1 )
    {
        picture_CopyPixels( p_pic_dst, p_dst );
    }

    picture_CopyProperties( p_pic_dst, p_pic );
    picture_Release( p_pic );
    return p_pic_dst;
}

Messung
CHZG
829610092

¤ Dauer der Verarbeitung: 0.14 Sekunden  ¤

*© 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.