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

Quelle  video_window.c   Sprache: C

 

/*****************************************************************************
 * video_window.c: vout-specific window management
 *****************************************************************************
 * Copyright © 2014-2021 Rémi Denis-Courmont
 *
 * 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 <stdlib.h>

#include <vlc_common.h>
#include <vlc_threads.h>
#include <vlc_window.h>
#include <vlc_vout.h>
#include <vlc_vout_display.h>
#include <vlc_ancillary.h>
#include "video_window.h"
#include "vout_internal.h"

#define DOUBLE_CLICK_TIME VLC_TICK_FROM_MS(300)

struct vlc_window_ack_data {
    vlc_window_t *window;
    vlc_window_ack_cb callback;
    unsigned width;
    unsigned height;
    void *opaque;
};

static void vlc_window_Ack(void *data)
{
    struct vlc_window_ack_data *cb_data = data;

    if (cb_data->callback != NULL)
        cb_data->callback(cb_data->window, cb_data->width, cb_data->height,
                          cb_data->opaque);
}

typedef struct vout_display_window
{
    vout_thread_t *vout;

    video_format_t format;
    struct vout_display_placement display;
    vlc_mutex_t lock;

    struct {
        vlc_mouse_t window;
        vlc_mouse_t video;
        vlc_tick_t last_left_press;
        vlc_mouse_event event;
        void *opaque;
    } mouse;
} vout_display_window_t;

static void vout_display_window_ResizeNotify(vlc_window_t *window,
                                             unsigned width, unsigned height,
                                             vlc_window_ack_cb cb,
                                             void *opaque)
{
    vout_display_window_t *state = window->owner.sys;
    vout_thread_t *vout = state->vout;
    struct vlc_window_ack_data data = { window, cb, width, height, opaque };

    vlc_mutex_lock(&state->lock);
    state->display.width = width;
    state->display.height = height;
    vlc_mutex_unlock(&state->lock);

    msg_Dbg(window, "resized to %ux%u", width, height);
    vout_ChangeDisplaySize(vout, width, height, vlc_window_Ack, &data);
}

static void vout_display_window_CloseNotify(vlc_window_t *window)
{
    /* TODO: Nowhere to dispatch to currently.
     * Needs callback to ES output to deselect ES? */

    msg_Err(window, "window closed");
}

static void vout_display_window_StateNotify(vlc_window_t *window,
                                            unsigned window_state)
{
    vout_display_window_t *state = window->owner.sys;
    vout_thread_t *vout = state->vout;

    static const char states[][8] = {
        [VLC_WINDOW_STATE_NORMAL] = "normal",
        [VLC_WINDOW_STATE_ABOVE] = "above",
        [VLC_WINDOW_STATE_BELOW] = "below",
    };

    assert(window_state < ARRAY_SIZE(states));
    msg_Dbg(window, "window state changed: %s", states[window_state]);
    var_SetInteger(vout, "window-state", window_state);
}

static void vout_display_window_FullscreenNotify(vlc_window_t *window,
                                                 const char *id)
{
    vout_display_window_t *state = window->owner.sys;
    vout_thread_t *vout = state->vout;

    msg_Dbg(window, (id != NULL) ? "window set to fullscreen on %s"
                                 : "window set to fullscreen", id);
    var_SetString(vout, "window-fullscreen-output",
                  (id != NULL) ? id : "");
    var_SetBool(vout, "window-fullscreen", true);
}

static void vout_display_window_WindowingNotify(vlc_window_t *window)
{
    vout_display_window_t *state = window->owner.sys;
    vout_thread_t *vout = state->vout;

    msg_Dbg(window, "window set windowed");
    var_SetBool(vout, "window-fullscreen", false);
}

static void vout_display_window_MouseEvent(vlc_window_t *window,
                                           const vlc_window_mouse_event_t *ev)
{
    vout_display_window_t *state = window->owner.sys;
    vout_thread_t *vout = state->vout;
    vlc_mouse_t *m = &state->mouse.window;

    m->b_double_click = false;

    switch (ev->type)
    {
        case VLC_WINDOW_MOUSE_MOVED:
            vlc_mouse_SetPosition(m, ev->x, ev->y);
            state->mouse.last_left_press = VLC_TICK_MIN;
            break;

        case VLC_WINDOW_MOUSE_PRESSED:
            if (!window->info.has_double_click
             && ev->button_mask == MOUSE_BUTTON_LEFT
             && !vlc_mouse_IsLeftPressed(m))
            {
                const vlc_tick_t now = vlc_tick_now();

                if (state->mouse.last_left_press != VLC_TICK_MIN
                 && now - state->mouse.last_left_press < DOUBLE_CLICK_TIME)
                {
                    m->b_double_click = true;
                    state->mouse.last_left_press = VLC_TICK_MIN;
                }
                else
                    state->mouse.last_left_press = now;
            }

            vlc_mouse_SetPressed(m, ev->button_mask);
            break;

        case VLC_WINDOW_MOUSE_RELEASED:
            vlc_mouse_SetReleased(m, ev->button_mask);
            break;

        case VLC_WINDOW_MOUSE_DOUBLE_CLICK:
            assert(window->info.has_double_click);
            m->b_double_click = true;
            vlc_mouse_SetPressed(m, ev->button_mask);
            break;

        default:
            vlc_assert_unreachable();
    }

    vlc_mouse_t video_mouse = *m;

    vlc_mutex_lock(&state->lock);
    if (likely(state->format.i_visible_width != 0
            && state->format.i_visible_height != 0
            && state->display.width != 0 && state->display.height != 0))
        vout_display_TranslateCoordinates(&video_mouse.i_x, &video_mouse.i_y,
                                          &state->format, &state->display);
    vlc_mutex_unlock(&state->lock);

    if (video_mouse.b_double_click && vlc_mouse_IsLeftPressed(&video_mouse))
        var_ToggleBool(vout, "fullscreen");

    /* Stop propagation if the event was consumed by a video filter */
    if (vout_FilterMouse(vout, &video_mouse))
        return;

    /* Check if the mouse state actually changed and emit events. */
    /* NOTE: sys->mouse is only used here, so no need to lock. */
    if (vlc_mouse_HasMoved(&state->mouse.video, &video_mouse))
        var_SetCoords(vout, "mouse-moved", m->i_x, m->i_y);
    if (vlc_mouse_HasButton(&state->mouse.video, &video_mouse))
        var_SetInteger(vout, "mouse-button-down", video_mouse.i_pressed);

    state->mouse.video = video_mouse;

    vlc_mutex_lock(&state->lock);
    /* Mouse events are only initialised if the display exists. */
    if (state->mouse.event != NULL)
        state->mouse.event(&video_mouse, state->mouse.opaque);
    vlc_mutex_unlock(&state->lock);
}

static void vout_display_window_KeyboardEvent(vlc_window_t *window,
                                              unsigned key)
{
    var_SetInteger(vlc_object_instance(window), "key-pressed", key);
}

static void vout_display_window_OutputEvent(vlc_window_t *window,
                                            const char *name, const char *desc)
{
    if (desc != NULL)
        msg_Dbg(window, "fullscreen output %s (%s) added", name, desc);
    else
        msg_Dbg(window, "fullscreen output %s removed", name);
}

static void vout_display_window_IccEvent(vlc_window_t *window,
                                         vlc_icc_profile_t *profile)
{
    vout_display_window_t *state = window->owner.sys;
    vout_thread_t *vout = state->vout;

    if (profile != NULL)
        msg_Dbg(window, "window got ICC profile (%zu bytes)", profile->size);
    else
        msg_Dbg(window, "window ICC profile cleared");

    vout_ChangeIccProfile(vout, profile);
}

static const struct vlc_window_callbacks vout_display_window_cbs = {
    .resized = vout_display_window_ResizeNotify,
    .closed = vout_display_window_CloseNotify,
    .state_changed = vout_display_window_StateNotify,
    .fullscreened = vout_display_window_FullscreenNotify,
    .windowed = vout_display_window_WindowingNotify,
    .mouse_event = vout_display_window_MouseEvent,
    .keyboard_event = vout_display_window_KeyboardEvent,
    .output_event = vout_display_window_OutputEvent,
    .icc_event = vout_display_window_IccEvent,
};

void vout_display_window_SetMouseHandler(vlc_window_t *window,
                                         vlc_mouse_event event, void *opaque)
{
    vout_display_window_t *state = window->owner.sys;

    /*
     * Note that the current implementation of this function is technically
     * reentrant, but better not rely on this in calling code.
     */

    vlc_mutex_lock(&state->lock);
    if (state->mouse.event != NULL)
        state->mouse.event(NULL, state->mouse.opaque);

    state->mouse.event = event;
    state->mouse.opaque = opaque;
    vlc_mutex_unlock(&state->lock);
}

static
void vout_display_SizeWindow(unsigned *restrict width,
                             unsigned *restrict height,
                             const video_format_t *restrict original,
                             const vlc_rational_t *restrict dar,
                             const struct vout_crop *restrict crop,
                             const struct vout_display_placement *restrict dp)
{
    unsigned w = original->i_visible_width;
    unsigned h = original->i_visible_height;
    unsigned sar_num = original->i_sar_num;
    unsigned sar_den = original->i_sar_den;

    if (dar->num > 0 && dar->den > 0) {
        unsigned num = dar->num * h;
        unsigned den = dar->den * w;

        vlc_ureduce(&sar_num, &sar_den, num, den, 0);
    }

    switch (crop->mode) {
        case VOUT_CROP_NONE:
            break;

        case VOUT_CROP_RATIO: {
            unsigned num = crop->ratio.num;
            unsigned den = crop->ratio.den;

            if (w * den > h * num)
                w = h * num / den;
            else
                h = w * den / num;
            break;
        }

        case VOUT_CROP_WINDOW:
            w = crop->window.width;
            h = crop->window.height;
            break;

        case VOUT_CROP_BORDER:
            w = crop->border.right - crop->border.left;
            h = crop->border.bottom - crop->border.top;
            break;
    }

    *width = dp->width;
    *height = dp->height;

    /* If both width and height are forced, keep them as is. */
    if (*width != 0 && *height != 0)
        return;

    /* Compute intended video resolution from source. */
    assert(sar_num > 0 && sar_den > 0);
    w = (w * sar_num) / sar_den;

    /* Adjust video size for orientation and pixel A/R. */
    if (ORIENT_IS_SWAP(original->orientation)) {
        unsigned x = w;

        w = h;
        h = x;
    }

    if (dp->sar.num > 0 && dp->sar.den > 0)
        w = (w * dp->sar.den) / dp->sar.num;

    /* If width is forced, adjust height according to the aspect ratio */
    if (*width != 0) {
        *height = (*width * h) / w;
        return;
    }

    /* If height is forced, adjust width according to the aspect ratio */
    if (*height != 0) {
        *width = (*height * w) / h;
        return;
    }

    /* If neither width nor height are forced, use the requested zoom. */
    *width = (w * dp->zoom.num) / dp->zoom.den;
    *height = (h * dp->zoom.num) / dp->zoom.den;
}

void vout_display_ResizeWindow(struct vlc_window *window,
                               const video_format_t *restrict original,
                               const vlc_rational_t *restrict dar,
                               const struct vout_crop *restrict crop,
                               const struct vout_display_placement *restrict dp)
{
    vout_display_window_t *state = window->owner.sys;
    unsigned width, height;

    vlc_mutex_lock(&state->lock);
    video_format_Clean(&state->format);
    video_format_Copy(&state->format, original);
    width = state->display.width;
    height = state->display.height;
    state->display = *dp;
    state->display.width = width;
    state->display.height = height;
    vlc_mutex_unlock(&state->lock);

    vout_display_SizeWindow(&width, &height, original, dar, crop, dp);
    msg_Dbg(window, "requested window size: %ux%u", width, height);
    vlc_window_SetSize(window, width, height);
}

/**
 * Creates a video window, initially without any attached display.
 */

vlc_window_t *vout_display_window_New(vout_thread_t *vout)
{
    vout_display_window_t *state = malloc(sizeof (*state));
    if (state == NULL)
        return NULL;

    video_format_Init(&state->format, 0);
    state->display.width = state->display.height = 0;
    vlc_mutex_init(&state->lock);
    vlc_mouse_Init(&state->mouse.window);
    vlc_mouse_Init(&state->mouse.video);
    state->mouse.last_left_press = VLC_TICK_MIN;
    state->mouse.event = NULL;
    state->vout = vout;

    char *modlist = var_InheritString(vout, "window");
    vlc_window_owner_t owner = {
        .cbs = &vout_display_window_cbs,
        .sys = state,
    };
    vlc_window_cfg_t cfg = {
        .is_fullscreen = var_GetBool(&vout->obj, "fullscreen"),
        .is_decorated = var_InheritBool(&vout->obj, "video-deco"),
#if defined(__APPLE__) || defined(_WIN32)
        .x = var_InheritInteger(&vout->obj, "video-x"),
        .y = var_InheritInteger(&vout->obj, "video-y"),
#endif
    };
    vlc_window_t *window;

    var_Create(vout, "window-state", VLC_VAR_INTEGER);
    var_Create(vout, "window-fullscreen", VLC_VAR_BOOL);
    var_Create(vout, "window-fullscreen-output", VLC_VAR_STRING);

    window = vlc_window_New(VLC_OBJECT(vout), modlist, &owner, &cfg);
    free(modlist);
    if (window == NULL)
        free(state);
    return window;
}

/**
 * Destroys a video window.
 * \note The window must be detached.
 */

void vout_display_window_Delete(vlc_window_t *window)
{
    vout_display_window_t *state = window->owner.sys;
    vout_thread_t *vout = state->vout;

    vlc_window_Delete(window);
    var_Destroy(vout, "window-fullscreen-output");
    var_Destroy(vout, "window-fullscreen");
    var_Destroy(vout, "window-state");
    video_format_Clean(&state->format);
    free(state);
}

Messung
CHZG
839710093

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