Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  display.c   Sprache: C

 

/*****************************************************************************
 * display.c: "vout display" management
 *****************************************************************************
 * Copyright (C) 2009 Laurent Aimar
 *
 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ 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 <stdatomic.h>

#include <vlc_common.h>
#include <vlc_vout_display.h>
#include <vlc_vout.h>
#include <vlc_block.h>
#include <vlc_modules.h>
#include <vlc_filter.h>
#include <vlc_picture_pool.h>
#include <vlc_codec.h>

#include "../libvlc.h"

#include "display.h"
#include "vout_internal.h"

static int UpdateSourceSAR(vout_display_t *, const video_format_t *);

/*****************************************************************************
 *
 *****************************************************************************/


/* */
void vout_display_GetDefaultDisplaySize(unsigned *width, unsigned *height,
                                        const video_format_t *source,
                                        const struct vout_display_placement *dp)
{
    /* Use the original video size */
    if (source->i_sar_num >= source->i_sar_den) {
        *width  = (uint64_t)source->i_visible_width * source->i_sar_num * dp->sar.den / source->i_sar_den / dp->sar.num;
        *height = source->i_visible_height;
    } else {
        *width  = source->i_visible_width;
        *height = (uint64_t)source->i_visible_height * source->i_sar_den * dp->sar.num / source->i_sar_num / dp->sar.den;
    }

    *width  = *width  * dp->zoom.num / dp->zoom.den;
    *height = *height * dp->zoom.num / dp->zoom.den;

    if (ORIENT_IS_SWAP(source->orientation)) {
        /* Apply the source orientation only if the dimensions are initialized
         * from the source format */

        unsigned store = *width;
        *width = *height;
        *height = store;
    }
}

static void vout_display_PlaceRotatedPicture(vout_display_place_t *restrict place,
                                             const video_format_t *restrict source,
                                             const struct vout_display_placement *restrict dp)
{
    memset(place, 0, sizeof(*place));
    if (dp->width == 0 || dp->height == 0)
        return;

    unsigned display_width;
    unsigned display_height;

    if (dp->fitting != VLC_VIDEO_FIT_NONE) {
        display_width  = dp->width;
        display_height = dp->height;
    } else
        vout_display_GetDefaultDisplaySize(&display_width, &display_height,
                                           source, dp);

    if (source->projection_mode == PROJECTION_MODE_RECTANGULAR) {
        /* Compute the height if we use the width to fill up display_width */
        const int64_t scaled_height =
            (int64_t)source->i_visible_height * source->i_sar_den * dp->sar.num * display_width /
                    (source->i_visible_width  * source->i_sar_num * dp->sar.den);
        /* And the same but switching width/height */
        const int64_t scaled_width  =
            (int64_t)source->i_visible_width  * source->i_sar_num * dp->sar.den * display_height /
                    (source->i_visible_height * source->i_sar_den * dp->sar.num);

        bool fit_height;

        switch (dp->fitting) {
            case VLC_VIDEO_FIT_NONE:
            case VLC_VIDEO_FIT_SMALLER:
                /* We keep the solution fitting within the display */
                fit_height = scaled_width <= dp->width;
                break;
            case VLC_VIDEO_FIT_LARGER:
                fit_height = scaled_width >= dp->width;
                break;
            case VLC_VIDEO_FIT_WIDTH:
                fit_height = false;
                break;
            case VLC_VIDEO_FIT_HEIGHT:
                fit_height = true;
                break;
        }

        if (fit_height) {
            place->width  = scaled_width;
            place->height = display_height;
        } else {
            place->width  = display_width;
            place->height = scaled_height;
        }
    } else {
        /* No need to preserve an aspect ratio for 360 video.
         * They can fill the display. */

        place->width  = display_width;
        place->height = display_height;
    }

    /*  Compute position */
    switch (dp->align.horizontal) {
    case VLC_VIDEO_ALIGN_LEFT:
        place->x = 0;
        break;
    case VLC_VIDEO_ALIGN_RIGHT:
        place->x = dp->width - place->width;
        break;
    default:
        place->x = ((int)dp->width - (int)place->width) / 2;
        break;
    }

    switch (dp->align.vertical) {
    case VLC_VIDEO_ALIGN_TOP:
        place->y = 0;
        break;
    case VLC_VIDEO_ALIGN_BOTTOM:
        place->y = dp->height - place->height;
        break;
    default:
        place->y = ((int)dp->height - (int)place->height) / 2;
        break;
    }

}

/* */
void vout_display_PlacePicture(vout_display_place_t *restrict place,
                               const video_format_t *restrict source,
                               const struct vout_display_placement *restrict dp)
{
    video_format_t source_rot;
    video_format_ApplyRotation(&source_rot, source);
    vout_display_PlaceRotatedPicture(place, &source_rot, dp);
}

/** Translates window coordinates to video coordinates */
void vout_display_TranslateCoordinates(int *restrict xp, int *restrict yp,
                                       const video_format_t *restrict source,
                                       const struct vout_display_placement *restrict dp)
{
    video_format_t source_rot;
    video_format_ApplyRotation(&source_rot, source);

    vout_display_place_t place;
    vout_display_PlaceRotatedPicture(&place, &source_rot, dp);

    if (place.width <= 0 || place.height <= 0)
        return;

    const int wx = *xp, wy = *yp;
    int x, y;

    switch (source->orientation) {
        case ORIENT_TOP_LEFT:
            x = wx;
            y = wy;
            break;
        case ORIENT_TOP_RIGHT:
            x = place.width - wx;
            y = wy;
            break;
        case ORIENT_BOTTOM_LEFT:
            x = wx;
            y = place.height - wy;
            break;
        case ORIENT_BOTTOM_RIGHT:
            x = place.width - wx;
            y = place.height - wy;
            break;
        case ORIENT_LEFT_TOP:
            x = wy;
            y = wx;
            break;
        case ORIENT_LEFT_BOTTOM:
            x = place.height - wy;
            y = wx;
            break;
        case ORIENT_RIGHT_TOP:
            x = wy;
            y = place.width - wx;
            break;
        case ORIENT_RIGHT_BOTTOM:
            x = place.height - wy;
            y = place.width - wx;
            break;
        default:
            vlc_assert_unreachable();
    }

    x = source_rot.i_x_offset
        + (int64_t)(x - place.x) * source_rot.i_visible_width / place.width;
    y = source_rot.i_y_offset
        + (int64_t)(y - place.y) * source_rot.i_visible_height / place.height;
    *xp = x;
    *yp = y;
}

struct pooled_filter_chain {
    filter_chain_t *filters;
    picture_pool_t *pool;
};

typedef struct {
    vout_display_t  display;

    /* */
    vout_display_cfg_t cfg;
    struct vout_crop crop;

    /* */
    vlc_rational_t dar;
    video_format_t source;          // format coming from the decoder
    video_format_t display_fmt;     // format required on the input of the display module
    vlc_video_context *src_vctx;

    vout_display_place_t src_place;

    // filters to convert the vout source to fmt, NULL means no conversion is needed
    struct pooled_filter_chain *converter;
} vout_display_priv_t;

static bool PlaceVideoInDisplay(vout_display_priv_t *osys)
{
    struct vout_display_placement place_cfg = osys->cfg.display;
    vout_display_place_t prev_place = osys->src_place;
    vout_display_PlacePicture(&osys->src_place, &osys->source, &place_cfg);
    return !vout_display_PlaceEquals(&prev_place, &osys->src_place);
}

/*****************************************************************************
 * FIXME/TODO see how to have direct rendering here (interact with vout.c)
 *****************************************************************************/

static picture_t *SourceConverterBuffer(filter_t *filter)
{
    vout_display_t *vd = filter->owner.sys;
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);
    const video_format_t *fmt = &filter->fmt_out.video;

    assert( video_format_IsSameChroma( &osys->display_fmt, fmt) &&
           osys->display_fmt.i_width  == fmt->i_width  &&
           osys->display_fmt.i_height == fmt->i_height);

    return picture_pool_Get(osys->converter->pool);
}

static vlc_decoder_device * DisplayHoldDecoderDevice(vlc_object_t *o, void *sys)
{
    VLC_UNUSED(o);
    vout_display_t *vd = sys;
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);
    return osys->src_vctx ? vlc_video_context_HoldDevice(osys->src_vctx) : NULL;
}

static const struct filter_video_callbacks vout_display_filter_cbs = {
    SourceConverterBuffer, DisplayHoldDecoderDevice,
};
static void VoutConverterRelease(struct pooled_filter_chain *conv)
{
    filter_chain_Delete(conv->filters);
    picture_pool_Release(conv->pool);
    free(conv);
}

static struct pooled_filter_chain *VoutSetupConverter(vlc_object_t *o,
                              filter_owner_t *owner,
                              const video_format_t *fmt_in,
                              vlc_video_context *vctx_in,
                              const video_format_t *fmt_out)
{
    struct pooled_filter_chain *conv = malloc(sizeof(*conv));
    if (unlikely(conv == NULL))
        return NULL;

    // 1 for current converter + 1 for previously displayed
    conv->pool = picture_pool_NewFromFormat(fmt_out, 1+1);
    if (unlikely(conv->pool == NULL))
    {
        msg_Err(o, "Failed to allocate converter pool");
        free(conv);
        return NULL;
    }

    conv->filters = filter_chain_NewVideo(o, false, owner);
    if (unlikely(conv->filters == NULL))
    {
        msg_Err(o, "Failed to create converter filter chain");
        picture_pool_Release(conv->pool);
        free(conv);
        return NULL;
    }

    /* */
    es_format_t src;
    es_format_InitFromVideo(&src, fmt_in);

    /* */
    es_format_t dst;
    es_format_InitFromVideo(&dst, fmt_out);
    dst.video.i_sar_num = 0;
    dst.video.i_sar_den = 0;

    filter_chain_Reset(conv->filters, &src, vctx_in, &dst);
    int ret = filter_chain_AppendConverter(conv->filters, &dst);
    es_format_Clean(&dst);
    es_format_Clean(&src);

    if (ret != VLC_SUCCESS)
    {
        VoutConverterRelease(conv);
        return NULL;
    }
    return conv;
}

static int VoutConverterCreate(vout_display_t *vd)
{
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);
    filter_owner_t owner = {
        .video = &vout_display_filter_cbs,
        .sys = vd,
    };

    video_format_t v_src = osys->source;
    v_src.i_sar_num = 0;
    v_src.i_sar_den = 0;

    video_format_t v_dst = osys->display_fmt;
    v_dst.i_sar_num = 0;
    v_dst.i_sar_den = 0;

    const bool convert = memcmp(&v_src, &v_dst, sizeof(v_src)) != 0;
    if (!convert)
        return VLC_SUCCESS;

    msg_Dbg(vd, "A filter to adapt decoder %4.4s to display %4.4s is needed",
            (const char *)&v_src.i_chroma, (const char *)&v_dst.i_chroma);

    osys->converter = VoutSetupConverter(VLC_OBJECT(vd), &owner,
                                 &v_src, osys->src_vctx, &osys->display_fmt);
    if (osys->converter == NULL) {
        msg_Err(vd, "Failed to adapt decoder format to display");
        return VLC_ENOTSUP;
    }
    return VLC_SUCCESS;
}

static void VoutDisplayCropRatio(unsigned *left, unsigned *top, unsigned *right, unsigned *bottom,
                                 const video_format_t *source,
                                 unsigned num, unsigned den)
{
    unsigned scaled_width  = (uint64_t)source->i_visible_height * num * source->i_sar_den / den / source->i_sar_num;
    unsigned scaled_height = (uint64_t)source->i_visible_width  * den * source->i_sar_num / num / source->i_sar_den;

    if (source->i_visible_width > scaled_width) {
        *left   = (source->i_visible_width - scaled_width) / 2;
        *top    = 0;
        *right  = *left + scaled_width;
        *bottom = *top  + source->i_visible_height;
    } else if (source->i_visible_height > scaled_height) {
        *left   = 0;
        *top    = (source->i_visible_height - scaled_height) / 2;
        *right  = *left + source->i_visible_width;
        *bottom = *top  + scaled_height;
    } else {
        *left   = 0;
        *top    = 0;
        *right  = source->i_visible_width;
        *bottom = source->i_visible_height;
    }
}

picture_t *vout_ConvertForDisplay(vout_display_t *vd, picture_t *picture)
{
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);

    if (osys->converter == NULL)
        return picture;

    return filter_chain_VideoFilter(osys->converter->filters, picture);
}

picture_t *vout_display_Prepare(vout_display_t *vd, picture_t *picture,
                                const vlc_render_subpicture *subpic, vlc_tick_t date)
{
    assert(subpic == NULL); /* TODO */
    picture = vout_ConvertForDisplay(vd, picture);

    if (picture != NULL && vd->ops->prepare != NULL)
        vd->ops->prepare(vd, picture, subpic, date);
    return picture;
}

void vout_FilterFlush(vout_display_t *vd)
{
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);

    if (osys->converter != NULL)
        filter_chain_VideoFlush(osys->converter->filters);
}

static void vout_display_Reset(vout_display_t *vd)
{
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);

    if (osys->converter != NULL)
    {
        VoutConverterRelease(osys->converter);
        osys->converter = NULL;
    }

    assert(vd->ops->reset_pictures);
    if (vd->ops->reset_pictures(vd, &osys->display_fmt) != VLC_SUCCESS
     || VoutConverterCreate(vd) != VLC_SUCCESS)
        msg_Err(vd, "Failed to adjust render format");
}

static int vout_UpdateSourceCrop(vout_display_t *vd)
{
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);
    unsigned left, top, right, bottom;
    int err1 = VLC_SUCCESS, err2;

    video_format_Print(VLC_OBJECT(vd), "SOURCE ", &osys->source);

    switch (osys->crop.mode) {
        case VOUT_CROP_NONE:
            left = top = 0;
            right = osys->source.i_visible_width;
            bottom = osys->source.i_visible_height;
            break;
        case VOUT_CROP_RATIO:
            VoutDisplayCropRatio(&left, &top, &right, &bottom, &osys->source,
                                 osys->crop.ratio.num, osys->crop.ratio.den);
            break;
        case VOUT_CROP_WINDOW:
            left = osys->crop.window.x;
            top = osys->crop.window.y;
            right = left + osys->crop.window.width;
            bottom = top + osys->crop.window.height;
            break;
        case VOUT_CROP_BORDER:
            left = osys->crop.border.left;
            top = osys->crop.border.top;
            right = osys->source.i_visible_width - osys->crop.border.right;
            bottom = osys->source.i_visible_height - osys->crop.border.bottom;
            break;
        default:
            /* left/top/right/bottom must be initialized */
            vlc_assert_unreachable();
    }

    if (left >= right)
        left = right - 1;
    if (top >= bottom)
        top = bottom - 1;
    if (right > osys->source.i_visible_width)
        right = osys->source.i_visible_width;
    if (bottom > osys->source.i_visible_height)
        bottom = osys->source.i_visible_height;

    osys->source.i_x_offset += left;
    osys->source.i_y_offset += top;
    osys->source.i_visible_width = right - left;
    osys->source.i_visible_height = bottom - top;
    video_format_Print(VLC_OBJECT(vd), "CROPPED ", &osys->source);

    err1 = UpdateSourceSAR(vd, vd->source);

    bool place_changed = PlaceVideoInDisplay(osys);

    if (vd->ops->set_source_crop != NULL)
    {
        err2 = vd->ops->set_source_crop(vd, vd->source);
        if (err2 != VLC_SUCCESS)
            err1 = err2;
    }

    if (place_changed && vd->ops->video_place_changed != NULL)
    {
        err2 = vd->ops->video_place_changed(vd, vd->place);
        if (err2 != VLC_SUCCESS)
            err1 = err2;
    }
    return err1;
}

static int vout_SetSourceAspect(vout_display_t *vd,
                                unsigned sar_num, unsigned sar_den)
{
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);
    int err1 = VLC_SUCCESS, err2;

    assert(sar_num > 0 && sar_den > 0);
    if (osys->source.i_sar_num * sar_den == osys->source.i_sar_den * sar_num)
        // value unchanged
        return err1;

    osys->source.i_sar_num = sar_num;
    osys->source.i_sar_den = sar_den;

    bool place_changed = PlaceVideoInDisplay(osys);

    if (vd->ops->set_source_aspect != NULL)
    {
        err2 = vd->ops->set_source_aspect(vd, vd->source);
        if (err2 != VLC_SUCCESS)
            err1 = err2;
    }

    /* If a crop ratio is requested, recompute the parameters */
    if (osys->crop.mode != VOUT_CROP_NONE)
    {
        err2 = vout_UpdateSourceCrop(vd);
        if (err2 != VLC_SUCCESS)
            err1 = err2;
    }

    if (place_changed && vd->ops->video_place_changed != NULL)
    {
        err2 = vd->ops->video_place_changed(vd, vd->place);
        if (err2 != VLC_SUCCESS)
            err1 = err2;
    }

    return err1;
}

void VoutFixFormatAR(video_format_t *fmt)
{
    vlc_ureduce( &fmt->i_sar_num, &fmt->i_sar_den,
                 fmt->i_sar_num,  fmt->i_sar_den, 50000 );
    if (fmt->i_sar_num <= 0 || fmt->i_sar_den <= 0) {
        fmt->i_sar_num = 1;
        fmt->i_sar_den = 1;
    }
}

void vout_UpdateDisplaySourceProperties(vout_display_t *vd, const video_format_t *source)
{
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);
    int err1 = VLC_SUCCESS, err2;

    if (VLC_DAR_IS_FROM_SOURCE(osys->dar)) {
        err2 = UpdateSourceSAR(vd, source);
        if (err2 != VLC_SUCCESS)
            err1 = err2;
    }
    if (source->i_x_offset       != osys->source.i_x_offset ||
        source->i_y_offset       != osys->source.i_y_offset ||
        source->i_visible_width  != osys->source.i_visible_width ||
        source->i_visible_height != osys->source.i_visible_height) {

        video_format_CopyCrop(&osys->source, source);

        /* Force the vout to reapply the current user crop settings
         * over the new decoder crop settings. */

        err2 = vout_UpdateSourceCrop(vd);
        if (err2 != VLC_SUCCESS)
            err1 = err2;
    }

    if (err1 != VLC_SUCCESS)
        vout_display_Reset(vd);
}

void vout_display_SetSize(vout_display_t *vd, unsigned width, unsigned height)
{
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);
    int err1 = VLC_SUCCESS, err2;

    osys->cfg.display.width  = width;
    osys->cfg.display.height = height;

    err1 = UpdateSourceSAR(vd, vd->source);

    bool place_changed = PlaceVideoInDisplay(osys);

    err2 = vd->ops->set_display_size == NULL ? VLC_SUCCESS :
        vd->ops->set_display_size(vd, vd->cfg->display.width, vd->cfg->display.height);
    if (err2 != VLC_SUCCESS)
        err1 = err2;

    if (place_changed && vd->ops->video_place_changed != NULL)
    {
        err2 = vd->ops->video_place_changed(vd, vd->place);
        if (err2 != VLC_SUCCESS)
            err1 = err2;
    }

    if (err1 != VLC_SUCCESS)
        vout_display_Reset(vd);
}

void vout_SetDisplayFitting(vout_display_t *vd, enum vlc_video_fitting fit)
{
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);

    if (fit == osys->cfg.display.fitting)
        return; /* nothing to do */

    osys->cfg.display.fitting = fit;

    bool place_changed = PlaceVideoInDisplay(osys);
    if (place_changed && vd->ops->video_place_changed != NULL)
    {
        int err1 = vd->ops->video_place_changed(vd, vd->place);
        if (err1 != VLC_SUCCESS)
            vout_display_Reset(vd);
    }
}

void vout_SetDisplayZoom(vout_display_t *vd, unsigned num, unsigned den)
{
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);
    unsigned onum = osys->cfg.display.zoom.num;
    unsigned oden = osys->cfg.display.zoom.den;

    osys->cfg.display.zoom.num = num;
    osys->cfg.display.zoom.den = den;

    if (osys->cfg.display.fitting != VLC_VIDEO_FIT_NONE)
        return; /* zoom has no effects */
    if (onum * den == num * oden)
        return; /* zoom has not changed */

    bool place_changed = PlaceVideoInDisplay(osys);
    if (place_changed && vd->ops->video_place_changed != NULL)
    {
        int err1 = vd->ops->video_place_changed(vd, vd->place);
        if (err1 != VLC_SUCCESS)
            vout_display_Reset(vd);
    }
}

static int UpdateSourceSAR(vout_display_t *vd, const video_format_t *source)
{
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);
    unsigned sar_num, sar_den;

    if (VLC_DAR_IS_FROM_SOURCE(osys->dar)) {
        video_format_t fixed_src = *source;
        VoutFixFormatAR( &fixed_src );
        sar_num = fixed_src.i_sar_num;
        sar_den = fixed_src.i_sar_den;
    } else if (VLC_DAR_IS_FILL_DISPLAY(osys->dar)) {
        // trick vout_display_PlacePicture to fill the display
        vlc_ureduce(&sar_num, &sar_den,
                    (uint64_t)osys->cfg.display.width  * osys->source.i_visible_height,
                    (uint64_t)osys->cfg.display.height * osys->source.i_visible_width, 0);
    } else if (unlikely(osys->dar.num == 0 || osys->dar.den == 0)) {
        // bogus values should be filtered in GetAspectRatio()
        vlc_assert_unreachable();
    } else {
        vlc_ureduce(&sar_num, &sar_den,
                    (uint64_t)osys->dar.num * osys->source.i_visible_height,
                    (uint64_t)osys->dar.den * osys->source.i_visible_width, 0);
    }

    return vout_SetSourceAspect(vd, sar_num, sar_den);
}

void vout_SetDisplayAspect(vout_display_t *vd, vlc_rational_t dar)
{
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);
    osys->dar = dar;

    int err1 = UpdateSourceSAR(vd, vd->source);
    if (err1 != VLC_SUCCESS)
        vout_display_Reset(vd);
}

void vout_SetDisplayCrop(vout_display_t *vd,
                         const struct vout_crop *restrict crop)
{
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);

    if (!vout_CropEqual(crop, &osys->crop)) {
        osys->crop = *crop;

        int err1 = vout_UpdateSourceCrop(vd);
        if (err1 != VLC_SUCCESS)
            vout_display_Reset(vd);
    }
}

void vout_SetDisplayViewpoint(vout_display_t *vd,
                              const vlc_viewpoint_t *p_viewpoint)
{
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);
    vlc_viewpoint_t old_vp = osys->cfg.viewpoint;
    osys->cfg.viewpoint = *p_viewpoint;

    if (vd->ops->set_viewpoint)
    {
        if (vd->ops->set_viewpoint(vd, &osys->cfg.viewpoint)) {
            msg_Err(vd, "Failed to change Viewpoint");
            osys->cfg.viewpoint = old_vp;
        }
    }
}

void vout_SetDisplayIccProfile(vout_display_t *vd,
                               const vlc_icc_profile_t *profile)
{
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);

    osys->cfg.icc_profile = (vlc_icc_profile_t *) profile;
    if (vd->ops->set_icc_profile)
        vd->ops->set_icc_profile(vd, profile);
}

int vout_SetDisplayFormat(vout_display_t *vd, const video_format_t *fmt,
                          vlc_video_context *vctx)
{
    if (!vd->ops->update_format)
        return VLC_EGENERIC;

    int ret = vd->ops->update_format(vd, fmt, vctx);
    if (ret != VLC_SUCCESS)
        return ret;

    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);

    /* Update source format */
    assert(!fmt->p_palette);
    video_format_Clean(&osys->source);
    osys->source = *fmt;
    if (vctx)
        vlc_video_context_Hold(vctx);
    if (osys->src_vctx)
        vlc_video_context_Release(osys->src_vctx);
    osys->src_vctx = vctx;

    /* On update_format success, the vout display accepts the target format, so
     * no display converters are needed. */

    if (osys->converter != NULL)
    {
        VoutConverterRelease(osys->converter);
        osys->converter = NULL;
    }

    bool place_changed = PlaceVideoInDisplay(osys);
    if (place_changed && vd->ops->video_place_changed != NULL)
    {
        int ret = vd->ops->video_place_changed(vd, &osys->src_place);
        if (ret != VLC_SUCCESS)
        {
            msg_Dbg(vd, "update format update place change failed");
            return ret;
        }
    }

    return VLC_SUCCESS;
}

int vout_display_SetFormat(vout_display_t *vd, const video_format_t *fmt,
                            vlc_video_context *vctx)
{
    return vout_SetDisplayFormat(vd, fmt, vctx);
}

void vout_SetDisplayProjection(vout_display_t *vd,
                               video_projection_mode_t projection)
{
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);
    osys->cfg.projection = projection;
    vout_display_ChangeProjection(vd, projection);
}

void vout_SetDisplayStereo(vout_display_t *vd, vlc_stereoscopic_mode_t mode)
{
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);

    if (osys->cfg.stereo_mode != mode) {
        osys->cfg.stereo_mode = mode;
        int err;
        if (vd->ops->set_stereo)
            err = vd->ops->set_stereo(vd, mode);
        else
            err = VLC_ENOTSUP; // not handled, we need to do it in the core
        if (err != VLC_SUCCESS)
        {
            msg_Err(vd, "Failed to change multiview display mode");
        }
    }
}

vout_display_t *vout_display_New(vlc_object_t *parent,
                                 const video_format_t *source,
                                 vlc_video_context *vctx,
                                 const vout_display_cfg_t *cfg,
                                 const char *module,
                                 const vout_display_owner_t *owner)
{
    vout_display_priv_t *osys = vlc_custom_create(parent, sizeof (*osys),
                                                  "vout display");
    if (unlikely(osys == NULL))
        return NULL;

    osys->cfg = *cfg;

    if (cfg->display.width == 0 || cfg->display.height == 0) {
        /* Work around buggy window provider */
        msg_Warn(parent, "window size missing");
        vout_display_GetDefaultDisplaySize(&osys->cfg.display.width,
                                           &osys->cfg.display.height,
                                           source, &cfg->display);
    }

    osys->converter = NULL;

    video_format_Copy(&osys->source, source);
    osys->crop.mode = VOUT_CROP_NONE;

    osys->src_vctx = vctx ? vlc_video_context_Hold( vctx ) : NULL;

    osys->cfg.stereo_mode = cfg->stereo_mode;

    /* */
    vout_display_t *vd = &osys->display;
    vd->source = &osys->source;
    vd->fmt = &osys->display_fmt;
    vd->info = (vout_display_info_t){ 0 };
    vd->cfg = &osys->cfg;
    vd->ops = NULL;
    vd->sys = NULL;
    if (owner)
        vd->owner = *owner;

    PlaceVideoInDisplay(osys);
    vd->place = &osys->src_place;

    if (module == NULL || module[0] == '\0')
        module = "any";

    module_t **mods;
    size_t strict;
    ssize_t n = vlc_module_match("vout display", module, true, &mods, &strict);

    msg_Dbg(vd, "looking for %s module matching \"%s\": %zd candidates",
            "vout display", module, n);

    for (ssize_t i = 0; i < n; i++) {
        vout_display_open_cb cb = vlc_module_map(vlc_object_logger(vd),
                                                 mods[i]);
        if (cb == NULL)
            continue;

        /* Picture buffer does not have the concept of aspect ratio */
        video_format_Copy(&osys->display_fmt, vd->source);
        vd->obj.force = i < (ssize_t)strict; /* TODO: pass to cb() instead? */

        int ret = cb(vd, &osys->display_fmt, vctx);
        if (ret == VLC_SUCCESS) {
            assert(vd->ops->prepare != NULL || vd->ops->display != NULL);
            if (VoutConverterCreate(vd) == VLC_SUCCESS) {
                msg_Dbg(vd, "using %s module \"%s\"", "vout display",
                        module_get_object(mods[i]));
                free(mods);
                return vd;
            }

            if (vd->ops->close != NULL)
                vd->ops->close(vd);
        }

        vlc_objres_clear(VLC_OBJECT(vd));
        video_format_Clean(&osys->display_fmt);
        osys->display.info = (vout_display_info_t){};
    }

    msg_Dbg(vd, "no %s modules matched with name %s", "vout display", module);
    free(mods);
    video_format_Clean(&osys->source);
    vlc_object_delete(vd);
    return NULL;
}

void vout_display_Delete(vout_display_t *vd)
{
    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);

    if (osys->src_vctx)
    {
        vlc_video_context_Release( osys->src_vctx );
        osys->src_vctx = NULL;
    }

    if (osys->converter != NULL)
    {
        VoutConverterRelease(osys->converter);
    }

    if (vd->ops->close != NULL)
        vd->ops->close(vd);
    vlc_objres_clear(VLC_OBJECT(vd));

    video_format_Clean(&osys->source);
    video_format_Clean(&osys->display_fmt);
    vlc_object_delete(vd);
}

Messung
CHZG
829710093

¤ Dauer der Verarbeitung: 0.12 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104848
#Domains=416967