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

Quelle  video_epg.c   Sprache: C

 

/*****************************************************************************
 * video_epg.c : EPG manipulation functions
 *****************************************************************************
 * Copyright (C) 2010 Adrien Maglo
 *               2017 VLC authors, VideoLAN and VideoLabs
 *
 * Author: Adrien Maglo <magsoft@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.
 *****************************************************************************/


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

#include <time.h>

#include <vlc_common.h>
#include <vlc_configuration.h>
#include <vlc_vout.h>
#include <vlc_vout_osd.h>
#include <vlc_input_item.h>
#include <vlc_epg.h>
#include <vlc_url.h>
#include "vout_spuregion_helper.h"

/* Layout percentage defines */
#define OSDEPG_MARGIN   0.025
#define OSDEPG_MARGINS  (OSDEPG_MARGIN * 2)
#define OSDEPG_PADDING  0.05 /* inner margins */
#define OSDEPG_WIDTH    (1.0 - OSDEPG_MARGINS)
#define OSDEPG_HEIGHT   0.25
#define OSDEPG_LEFT     OSDEPG_MARGIN
#define OSDEPG_TOP      (1.0 - OSDEPG_MARGINS - OSDEPG_HEIGHT + OSDEPG_MARGIN)

/* layout */
#define OSDEPG_ROWS_COUNT  10
#define OSDEPG_ROW_HEIGHT  (1.0 / OSDEPG_ROWS_COUNT)
#define OSDEPG_LOGO_SIZE (OSDEPG_HEIGHT)

/* shortcuts */
#define OSDEPG_RIGHT    (1.0 - OSDEPG_MARGIN)

#define OSDEPG_ROWS(x)  (OSDEPG_ROW_HEIGHT * x)
#define OSDEPG_ROW(x)   (OSDEPG_ROWS(x))

#define EPGOSD_TEXTSIZE_NAME    (OSDEPG_ROWS(2))
#define EPGOSD_TEXTSIZE_PROG    (OSDEPG_ROWS(2))
#define EPGOSD_TEXTSIZE_NTWK    (OSDEPG_ROWS(2))

#define RGB_COLOR1   0xf48b00
#define ARGB_BGCOLOR 0xC0333333

//#define RGB_COLOR1   0x2badde
//#define ARGB_BGCOLOR 0xc003182d

typedef struct
{
    vlc_epg_t *epg;
    int64_t    time;
    char      *art;
    vlc_object_t *obj;
} epg_spu_updater_sys_t;

static char * GetDefaultArtUri( void )
{
    char *psz_uri = NULL;
    char *psz_path = config_GetSysPath(VLC_SYSDATA_DIR, "icons/hicolor/"
                                       "128x128/"PACKAGE_NAME".png");
    if( psz_path != NULL )
    {
        psz_uri = vlc_path2uri( psz_path, NULL );
        free( psz_path );
    }
    return psz_uri;
}

#define GRADIENT_COLORS 40

static subpicture_region_t * vout_OSDBackground(int x, int y,
                                                int width, int height,
                                                uint32_t i_argb)
{
    /* Create a new subpicture region */
    video_palette_t palette;
    spuregion_CreateVGradientPalette( &palette, GRADIENT_COLORS, i_argb, 0xFF000000 );

    video_format_t fmt;
    video_format_Init(&fmt, VLC_CODEC_YUVP);
    fmt.i_width  = fmt.i_visible_width  = width;
    fmt.i_height = fmt.i_visible_height = height;
    fmt.i_sar_num = 1;
    fmt.i_sar_den = 1;
    fmt.p_palette = &palette;

    subpicture_region_t *region = subpicture_region_New(&fmt);
    if (!region)
        return NULL;

    region->b_absolute = false; region->b_in_window = false;
    region->i_align = SUBPICTURE_ALIGN_LEFT | SUBPICTURE_ALIGN_TOP;
    region->i_x = x;
    region->i_y = y;

    spuregion_CreateVGradientFill( region->p_picture->p, palette.i_entries );

    return region;
}

static subpicture_region_t * vout_OSDEpgSlider(int x, int y,
                                               int width, int height,
                                               float ratio)
{
    /* Create a new subpicture region */
    video_palette_t palette = {
        .i_entries = 4,
        .palette = {
            [0] = { HEX2YUV(RGB_COLOR1), 0x20 }, /* Bar fill remain/background */
            [1] = { HEX2YUV(0x00ff00), 0xff },
            [2] = { HEX2YUV(RGB_COLOR1), 0xC0 }, /* Bar fill */
            [3] = { HEX2YUV(0xffffff), 0xff }, /* Bar outline */
        },
    };

    video_format_t fmt;
    video_format_Init(&fmt, VLC_CODEC_YUVP);
    fmt.i_width  = fmt.i_visible_width  = width;
    fmt.i_height = fmt.i_visible_height = height;
    fmt.i_sar_num = 1;
    fmt.i_sar_den = 1;
    fmt.p_palette = &palette;

    subpicture_region_t *region = subpicture_region_New(&fmt);
    if (!region)
        return NULL;

    region->b_absolute = false; region->b_in_window = false;
    region->i_align = SUBPICTURE_ALIGN_LEFT | SUBPICTURE_ALIGN_TOP;
    region->i_x = x;
    region->i_y = y;

    picture_t *picture = region->p_picture;

    ratio = VLC_CLIP(ratio, 0, 1);
    int filled_part_width = ratio * width;

    for (int j = 0; j < height; j++) {
        for (int i = 0; i < width; ) {
            /* Slider border. */
            bool is_outline = j == 0 || j == height - 1 ||
                              i == 0 || i == width  - 1;
            /* We can see the video through the part of the slider
               which corresponds to the leaving time. */

            bool is_border = j < 3 || j > height - 4 ||
                             i < 3 || i > width  - 4 ||
                             i < filled_part_width;

            uint8_t color = 2 * is_border + is_outline;
            if(i >= 3 && i < width - 4)
            {
                if(filled_part_width > 4)
                    memset(&picture->p->p_pixels[picture->p->i_pitch * j + i],
                           color, filled_part_width - 4);
                if(width > filled_part_width + 4)
                    memset(&picture->p->p_pixels[picture->p->i_pitch * j + filled_part_width],
                           color, width - filled_part_width - 4);
                i = __MAX(i+1, filled_part_width - 1);
            }
            else
            {
                picture->p->p_pixels[picture->p->i_pitch * j + i] = color;
                i++;
            }
        }
    }

    return region;
}

static void vout_OSDSegmentSetNoWrap(text_segment_t *p_segment)
{
    for( ; p_segment; p_segment = p_segment->p_next )
    {
        p_segment->style->e_wrapinfo = STYLE_WRAP_NONE;
        p_segment->style->i_features |= STYLE_HAS_WRAP_INFO;
    }
}

static text_segment_t * vout_OSDSegment(const char *psz_text, int size, uint32_t color)
{
    text_segment_t *p_segment = text_segment_New(psz_text);
    if(unlikely(!p_segment))
        return NULL;

    /* Set text style */
    p_segment->style = text_style_Create(STYLE_NO_DEFAULTS);
    if (unlikely(!p_segment->style))
    {
        text_segment_Delete(p_segment);
        return NULL;
    }

    p_segment->style->i_font_size  = __MAX(size ,1 );
    p_segment->style->i_font_color = color;
    p_segment->style->i_font_alpha = STYLE_ALPHA_OPAQUE;
    p_segment->style->i_outline_alpha = STYLE_ALPHA_TRANSPARENT;
    p_segment->style->i_shadow_alpha = STYLE_ALPHA_TRANSPARENT;
    p_segment->style->i_features |= STYLE_HAS_FONT_ALPHA | STYLE_HAS_FONT_COLOR |
                                    STYLE_HAS_OUTLINE_ALPHA | STYLE_HAS_SHADOW_ALPHA;

    return p_segment;
}

static subpicture_region_t * vout_OSDImage( vlc_object_t *p_obj,
                                            int x, int y, int w, int h,
                                            const char *psz_uri )
{
    video_format_t fmt_out;
    video_format_Init( &fmt_out, VLC_CODEC_YUVA );
    fmt_out.i_width = fmt_out.i_visible_width = w;
    fmt_out.i_height = fmt_out.i_visible_height = h;

    subpicture_region_t *image =
            spuregion_CreateFromPicture( p_obj, &fmt_out, psz_uri );
    if( image )
    {
        image->b_absolute = false; image->b_in_window = false;
        image->i_x = x;
        image->i_y = y;
        image->i_align = SUBPICTURE_ALIGN_LEFT|SUBPICTURE_ALIGN_TOP;
    }
    return image;
}

static void vout_OSDRegionConstrain(subpicture_region_t *p_region, int w, int h)
{
    p_region->i_max_width = w;
    p_region->i_max_height = h;
}

static subpicture_region_t * vout_OSDTextRegion(text_segment_t *p_segment,
                                                int x, int y )
{
    subpicture_region_t *region;

    if (!p_segment)
        return NULL;

    /* Create a new subpicture region */
    region = subpicture_region_NewText();
    if (!region)
        return NULL;

    region->b_absolute = false; region->b_in_window = false;
    region->fmt.i_sar_num = 1;
    region->fmt.i_sar_den = 1;
    region->p_text   = p_segment;
    region->i_align  = SUBPICTURE_ALIGN_LEFT | SUBPICTURE_ALIGN_TOP;
    region->text_flags |= SUBPICTURE_ALIGN_LEFT | SUBPICTURE_ALIGN_TOP;
    region->text_flags |= VLC_SUBPIC_TEXT_FLAG_TEXT_NOT_BALANCED;
    region->i_x      = x;
    region->i_y      = y;

    return region;
}

static subpicture_region_t * vout_OSDEpgText(const char *text,
                                             int x, int y,
                                             int size, uint32_t color)
{
    return vout_OSDTextRegion(vout_OSDSegment(text, size, color), x, y);
}

static char * vout_OSDPrintTime(time_t t)
{
    char *psz;
    struct tm tms;
    localtime_r(&t, &tms);
    if(asprintf(&psz, "%2.2d:%2.2d", tms.tm_hour, tms.tm_min) < 0)
       psz = NULL;
    return psz;
}

static subpicture_region_t * vout_OSDEpgEvent(const vlc_epg_event_t *p_evt,
                                              int x, int y, int size)
{
    text_segment_t *p_segment = NULL;
    char *psz_start = vout_OSDPrintTime(p_evt->i_start);
    char *psz_end = vout_OSDPrintTime(p_evt->i_start + p_evt->i_duration);
    char *psz_text;
    if( -1 < asprintf(&psz_text, "%s-%s ", psz_start, psz_end))
    {
        p_segment = vout_OSDSegment(psz_text, size, RGB_COLOR1);
        if( p_segment )
            p_segment->p_next = vout_OSDSegment(p_evt->psz_name, size, 0xffffff);
        vout_OSDSegmentSetNoWrap( p_segment );
    }
    free( psz_start );
    free( psz_end );
    if(!p_segment)
        return NULL;
    return vout_OSDTextRegion(p_segment, x, y);
}

static void vout_FillRightPanel(epg_spu_updater_sys_t *p_sys,
                                int x, int y,
                                int width, int height,
                                int rx, int ry,
                                vlc_spu_regions *regions)
{
    float f_progress = 0;
    VLC_UNUSED(ry);
    subpicture_region_t *last;

    /* Display the name of the channel. */
    last = vout_OSDEpgText(p_sys->epg->psz_name,
                                x,
                                y,
                                height * EPGOSD_TEXTSIZE_NAME,
                                0x00ffffff);
    if(last)
        vlc_spu_regions_push(regions, last);

    const vlc_epg_event_t *p_current = p_sys->epg->p_current;
    vlc_epg_event_t *p_next = NULL;
    if(!p_sys->epg->p_current && p_sys->epg->i_event)
        p_current = p_sys->epg->pp_event[0];

    for(size_t i=0; i<p_sys->epg->i_event; i++)
    {
        if( p_sys->epg->pp_event[i]->i_id != p_current->i_id )
        {
            p_next = p_sys->epg->pp_event[i];
            break;
        }
    }

    /* Display the name of the current program. */
    if(p_current)
    {
        last = vout_OSDEpgEvent(p_current,
                                     x,
                                     y + height * OSDEPG_ROW(2),
                                     height * EPGOSD_TEXTSIZE_PROG);
        if(last)
        {
            /* region rendering limits */
            vout_OSDRegionConstrain(last, width, 0);
            vlc_spu_regions_push(regions, last);
        }
    }

    /* NEXT EVENT */
    if(p_next)
    {
        last = vout_OSDEpgEvent(p_next,
                                     x,
                                     y + height * OSDEPG_ROW(5),
                                     height * EPGOSD_TEXTSIZE_PROG);
        if(last)
        {
            /* region rendering limits */
            vout_OSDRegionConstrain(last, width, 0);
            vlc_spu_regions_push(regions, last);
        }
    }

    if(p_sys->time && p_sys->epg->p_current)
    {
        f_progress = (p_sys->time - p_sys->epg->p_current->i_start) /
                     (float)p_sys->epg->p_current->i_duration;
    }

    /* Display the current program time slider. */
    last = vout_OSDEpgSlider(x + width * 0.05,
                                  y + height * OSDEPG_ROW(9),
                                  width  * 0.90,
                                  height * OSDEPG_ROWS(1),
                                  f_progress);
    if (last)
        vlc_spu_regions_push(regions, last);

    /* Format the hours */
    if(p_sys->time)
    {
        char *psz_network = vout_OSDPrintTime(p_sys->time);
        if(psz_network)
        {
            last = vout_OSDEpgText(psz_network,
                                        rx,
                                        y + height * OSDEPG_ROW(0),
                                        height * EPGOSD_TEXTSIZE_NTWK,
                                        RGB_COLOR1);
            free(psz_network);
            if(last)
            {
                last->i_align = SUBPICTURE_ALIGN_TOP|SUBPICTURE_ALIGN_RIGHT;
                vlc_spu_regions_push(regions, last);
            }
        }
    }
}

static void vout_BuildOSDEpg(epg_spu_updater_sys_t *p_sys,
                                              vlc_spu_regions *regions,
                                              int x, int y,
                                              int visible_width,
                                              int visible_height)
{
    subpicture_region_t *last;

    const int i_padding = visible_height * (OSDEPG_HEIGHT * OSDEPG_PADDING);

    last = vout_OSDBackground(x + visible_width * OSDEPG_LEFT,
                                   y + visible_height * OSDEPG_TOP,
                                   visible_width  * OSDEPG_WIDTH,
                                   visible_height * OSDEPG_HEIGHT,
                                   ARGB_BGCOLOR);
    if(last)
        vlc_spu_regions_push(regions, last);

    struct
    {
        int x;
        int y;
        int w;
        int h;
        int rx;
        int ry;
    } panel = {
        x + visible_width  * OSDEPG_LEFT + i_padding,
        y + visible_height * OSDEPG_TOP + i_padding,
        visible_width  * OSDEPG_WIDTH - 2 * i_padding,
        visible_height * OSDEPG_HEIGHT - 2 * i_padding,
        visible_width * OSDEPG_LEFT + i_padding,
        visible_height * (1.0 - OSDEPG_TOP - OSDEPG_HEIGHT) + i_padding,
    };


    if( p_sys->art )
    {
        struct
        {
            int x;
            int y;
            int w;
            int h;
        } logo = {
            panel.x,
            panel.y,
            panel.h,
            panel.h,
        };

        last = vout_OSDBackground(logo.x,
                                       logo.y,
                                       logo.w,
                                       logo.h,
                                       0xFF000000 | RGB_COLOR1);
        if(last)
            vlc_spu_regions_push(regions, last);

        int logo_padding = visible_height * (OSDEPG_LOGO_SIZE * OSDEPG_PADDING);
        last = vout_OSDImage( p_sys->obj,
                                   logo.x + logo_padding,
                                   logo.y + logo_padding,
                                   logo.w - 2 * logo_padding,
                                   logo.h - 2 * logo_padding,
                                   p_sys->art );
        if(last)
            vlc_spu_regions_push(regions, last);

        /* shrink */
        panel.x += logo.w + i_padding;
        panel.w -= logo.w + i_padding;
    }

    vout_FillRightPanel( p_sys,
                         panel.x,
                         panel.y,
                         panel.w,
                         panel.h,
                         panel.rx,
                         panel.ry,
                         regions );
}

static void OSDEpgUpdate(subpicture_t *subpic,
                         const struct vlc_spu_updater_configuration *cfg)
{
    epg_spu_updater_sys_t *sys = subpic->updater.sys;
    const video_format_t *fmt_dst = cfg->current.video_dst;

    if (video_format_IsSimilar(cfg->previous.video_dst, fmt_dst))
        return;

    vlc_spu_regions_Clear( &subpic->regions );

    unsigned i_x_offset = fmt_dst->i_x_offset * fmt_dst->i_sar_num / fmt_dst->i_sar_den;

    subpic->i_original_picture_width  = fmt_dst->i_visible_width * fmt_dst->i_sar_num / fmt_dst->i_sar_den;
    subpic->i_original_picture_height = fmt_dst->i_visible_height;

    vout_BuildOSDEpg(sys, &subpic->regions,
                                        i_x_offset,
                                        fmt_dst->i_y_offset,
                                        subpic->i_original_picture_width,
                                        subpic->i_original_picture_height);
}

static void OSDEpgDestroy(subpicture_t *subpic)
{
    epg_spu_updater_sys_t *sys = subpic->updater.sys;
    if( sys->epg )
        vlc_epg_Delete(sys->epg);
    free( sys->art );
    free(sys);
}

int vout_OSDEpg(vout_thread_t *vout, input_item_t *input)
{
    vlc_epg_t *epg = NULL;
    int64_t epg_time;

    /* Look for the current program EPG event */
    vlc_mutex_lock(&input->lock);

    const vlc_epg_t *tmp = input->p_epg_table;
    if ( tmp )
    {
        /* Pick table designated event, or first/next one */
        const vlc_epg_event_t *p_current_event = tmp->p_current;
        epg = vlc_epg_New(tmp->i_id, tmp->i_source_id);
        if(epg)
        {
            if( p_current_event )
            {
                vlc_epg_event_t *p_event = vlc_epg_event_Duplicate(p_current_event);
                if(p_event)
                {
                    if(!vlc_epg_AddEvent(epg, p_event))
                        vlc_epg_event_Delete(p_event);
                    else
                        vlc_epg_SetCurrent(epg, p_event->i_start);
                }
            }

            /* Add next event if any */
            vlc_epg_event_t *p_next = NULL;
            for(size_t i=0; i<tmp->i_event; i++)
            {
                vlc_epg_event_t *p_evt = tmp->pp_event[i];
                if((!p_next || p_next->i_start > p_evt->i_start) &&
                   (!p_current_event || (p_evt->i_id != p_current_event->i_id &&
                                         p_evt->i_start >= p_current_event->i_start +
                                                           p_current_event->i_duration )))
                {
                    p_next = tmp->pp_event[i];
                }
            }
            if( p_next )
            {
                vlc_epg_event_t *p_event = vlc_epg_event_Duplicate(p_next);
                if(!vlc_epg_AddEvent(epg, p_event))
                    vlc_epg_event_Delete(p_event);
            }

            if(epg->i_event > 0)
            {
                epg->psz_name = strdup(tmp->psz_name);
            }
            else
            {
                vlc_epg_Delete(epg);
                epg = NULL;
            }
        }
    }
    epg_time = input->i_epg_time;
    vlc_mutex_unlock(&input->lock);

    /* If no EPG event has been found. */
    if (epg == NULL)
        return VLC_EGENERIC;

    if(epg->psz_name == NULL) /* Fallback (title == channel name) */
        epg->psz_name = input_item_GetMeta( input, vlc_meta_Title );

    epg_spu_updater_sys_t *sys = malloc(sizeof(*sys));
    if (!sys) {
        vlc_epg_Delete(epg);
        return VLC_EGENERIC;
    }
    sys->epg = epg;
    sys->obj = VLC_OBJECT(vout);
    sys->time = epg_time;
    sys->art = input_item_GetMeta( input, vlc_meta_ArtworkURL );
    if( !sys->art )
        sys->art = GetDefaultArtUri();

    static const struct vlc_spu_updater_ops spu_ops =
    {
        .update   = OSDEpgUpdate,
        .destroy  = OSDEpgDestroy,
    };

    subpicture_updater_t updater = {
        .sys = sys,
        .ops = &spu_ops,
    };

    const vlc_tick_t now = vlc_tick_now();
    subpicture_t *subpic = subpicture_New(&updater);
    if (!subpic) {
        vlc_epg_Delete(sys->epg);
        free(sys);
        return VLC_EGENERIC;
    }

    subpic->i_channel  = VOUT_SPU_CHANNEL_OSD;
    subpic->i_start    = now;
    subpic->i_stop     = now + VLC_TICK_FROM_SEC(3);
    subpic->b_ephemer  = true;
    subpic->b_fade     = true;
    subpic->b_subtitle = false;

    vout_PutSubpicture(vout, subpic);

    return VLC_SUCCESS;
}

Messung
CHZG
849310092

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