fbosd.c 48.5 KB
Newer Older
1 2 3
/*****************************************************************************
 * fbosd.c : framebuffer osd plugin for vlc
 *****************************************************************************
4
 * Copyright (C) 2007-2008, the VideoLAN team
Pierre's avatar
Pierre committed
5
 * $Id$
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 * Authors: Jean-Paul Saman
 * Copied from modules/video_output/fb.c by Samuel Hocevar <sam@zoy.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU 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
 *****************************************************************************/
28 29 30 31
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

32
#include <vlc_common.h>
33
#include <vlc_plugin.h>
34
#include <vlc_fs.h>
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

#include <stdlib.h>                                                /* free() */
#include <string.h>                                            /* strerror() */
#include <fcntl.h>                                                 /* open() */
#include <unistd.h>                                               /* close() */

#include <sys/ioctl.h>
#include <sys/mman.h>                                              /* mmap() */

#include <linux/fb.h>

#include <vlc_image.h>
#include <vlc_interface.h>
#include <vlc_input.h>
#include <vlc_vout.h>
#include <vlc_filter.h>
#include <vlc_osd.h>
#include <vlc_strings.h>

Jean-Paul Saman's avatar
Jean-Paul Saman committed
54 55
#undef FBOSD_BLENDING
#undef FBOSD_DEBUG
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static int  Create    ( vlc_object_t * );
static void Destroy   ( vlc_object_t * );
static void Run       ( intf_thread_t * );

static int  Init      ( intf_thread_t * );
static void End       ( intf_thread_t * );

static int  OpenDisplay    ( intf_thread_t * );
static void CloseDisplay   ( intf_thread_t * );

/* Load modules needed for rendering and blending */
71
#if defined(FBOSD_BLENDING)
72 73 74 75 76 77 78 79 80 81
static int  OpenBlending     ( intf_thread_t * );
static void CloseBlending    ( intf_thread_t * );
#endif
static int  OpenTextRenderer ( intf_thread_t * );
static void CloseTextRenderer( intf_thread_t * );

/* Manipulate the overlay buffer */
static int  OverlayCallback( vlc_object_t *, char const *,
                             vlc_value_t, vlc_value_t, void * );

82 83
static picture_t *AllocatePicture( video_format_t * );
static void DeAllocatePicture( picture_t *, video_format_t * );
84
static void SetOverlayTransparency( intf_thread_t *,
85
                                    bool );
86 87 88
static picture_t *LoadImage( intf_thread_t *, video_format_t *,
                             char * );

89
#if defined(FBOSD_BLENDING)
90 91 92 93 94 95 96 97 98
static int BlendPicture( intf_thread_t *, video_format_t *,
                         video_format_t *, picture_t *, picture_t * );
#else
static picture_t *ConvertImage( intf_thread_t *, picture_t *,
                                video_format_t *, video_format_t * );
#endif
static int RenderPicture( intf_thread_t *, int, int,
                          picture_t *, picture_t * );
static picture_t *RenderText( intf_thread_t *, const char *,
99
                              text_style_t *, video_format_t * );
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159

#define DEVICE_TEXT N_("Framebuffer device")
#define DEVICE_LONGTEXT N_( \
    "Framebuffer device to use for rendering (usually /dev/fb0).")

#define ASPECT_RATIO_TEXT N_("Video aspect ratio")
#define ASPECT_RATIO_LONGTEXT N_( \
    "Aspect ratio of the video image (4:3, 16:9). Default is square pixels." )

#define FBOSD_IMAGE_TEXT N_("Image file")
#define FBOSD_IMAGE_LONGTEXT N_( \
    "Filename of image file to use on the overlay framebuffer." )

#define ALPHA_TEXT N_("Transparency of the image")
#define ALPHA_LONGTEXT N_( "Transparency value of the new image " \
    "used in blending. By default it set to fully opaque (255). " \
    "(from 0 for full transparency to 255 for full opacity)" )

#define FBOSD_TEXT N_("Text")
#define FBOSD_LONGTEXT N_( "Text to display on the overlay framebuffer." )

#define POSX_TEXT N_("X coordinate")
#define POSX_LONGTEXT N_("X coordinate of the rendered image")

#define POSY_TEXT N_("Y coordinate")
#define POSY_LONGTEXT N_("Y coordinate of the rendered image")

#define POS_TEXT N_("Position")
#define POS_LONGTEXT N_( \
  "You can enforce the picture position on the overlay " \
  "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \
  "also use combinations of these values, e.g. 6=top-right).")

#define OPACITY_TEXT N_("Opacity")
#define OPACITY_LONGTEXT N_("Opacity (inverse of transparency) of " \
    "overlayed text. 0 = transparent, 255 = totally opaque. " )

#define SIZE_TEXT N_("Font size, pixels")
#define SIZE_LONGTEXT N_("Font size, in pixels. Default is -1 (use default " \
    "font size)." )

#define COLOR_TEXT N_("Color")
#define COLOR_LONGTEXT N_("Color of the text that will be rendered on "\
    "the video. This must be an hexadecimal (like HTML colors). The first two "\
    "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
    " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )

#define CLEAR_TEXT N_( "Clear overlay framebuffer" )
#define CLEAR_LONGTEXT N_( "The displayed overlay images is cleared by " \
    "making the overlay completely transparent. All previously rendered " \
    "images and text will be cleared from the cache." )

#define RENDER_TEXT N_( "Render text or image" )
#define RENDER_LONGTEXT N_( "Render the image or text in current overlay " \
    "buffer." )

#define DISPLAY_TEXT N_( "Display on overlay framebuffer" )
#define DISPLAY_LONGTEXT N_( "All rendered images and text will be " \
    "displayed on the overlay framebuffer." )

160 161
static const int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
static const char *const ppsz_pos_descriptions[] =
162 163 164
{ N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
  N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };

165 166
static const int pi_color_values[] = {
               0xf0000000, 0x00000000, 0x00808080, 0x00C0C0C0,
167 168 169
               0x00FFFFFF, 0x00800000, 0x00FF0000, 0x00FF00FF, 0x00FFFF00,
               0x00808000, 0x00008000, 0x00008080, 0x0000FF00, 0x00800080,
               0x00000080, 0x000000FF, 0x0000FFFF};
170 171
static const char *const ppsz_color_descriptions[] = {
               N_("Default"), N_("Black"),
172 173 174 175 176
               N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"), N_("Red"),
               N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"),
               N_("Teal"), N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"),
               N_("Aqua") };

177 178 179 180
vlc_module_begin ()
    set_shortname( "fbosd" )
    set_category( CAT_INTERFACE )
    set_subcategory( SUBCAT_INTERFACE_MAIN )
181

ivoire's avatar
fbosd:  
ivoire committed
182
    add_file( "fbosd-dev", "/dev/fb0", NULL, DEVICE_TEXT, DEVICE_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
183
              false )
184
    add_string( "fbosd-aspect-ratio", "", NULL, ASPECT_RATIO_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
185
                ASPECT_RATIO_LONGTEXT, true )
186 187

    add_string( "fbosd-image", NULL, NULL, FBOSD_IMAGE_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
188
                FBOSD_IMAGE_LONGTEXT, true )
189
    add_string( "fbosd-text", NULL, NULL, FBOSD_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
190
                FBOSD_LONGTEXT, true )
191 192

    add_integer_with_range( "fbosd-alpha", 255, 0, 255, NULL, ALPHA_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
193
                            ALPHA_LONGTEXT, true )
194

195
    set_section( N_("Position"), NULL )
196
    add_integer( "fbosd-x", 0, NULL, POSX_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
197
                 POSX_LONGTEXT, false )
198
    add_integer( "fbosd-y", 0, NULL, POSY_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
199
                 POSY_LONGTEXT, false )
200
    add_integer( "fbosd-position", 8, NULL, POS_TEXT, POS_LONGTEXT, true )
201
        change_integer_list( pi_pos_values, ppsz_pos_descriptions, NULL );
202

203
    set_section( N_("Font"), NULL )
204
    add_integer_with_range( "fbosd-font-opacity", 255, 0, 255, NULL,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
205
        OPACITY_TEXT, OPACITY_LONGTEXT, false )
206
    add_integer( "fbosd-font-color", 0x00FFFFFF, NULL, COLOR_TEXT, COLOR_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
207
                 false )
208
        change_integer_list( pi_color_values, ppsz_color_descriptions, NULL );
209
    add_integer( "fbosd-font-size", -1, NULL, SIZE_TEXT, SIZE_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
210
                 false )
211

212 213 214 215
    set_section( N_("Commands"), NULL )
    add_bool( "fbosd-clear", false, NULL, CLEAR_TEXT, CLEAR_LONGTEXT, true )
    add_bool( "fbosd-render", false, NULL, RENDER_TEXT, RENDER_LONGTEXT, true )
    add_bool( "fbosd-display", false, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, true )
216

217 218 219 220
    set_description( N_("GNU/Linux osd/overlay framebuffer interface") )
    set_capability( "interface", 10 )
    set_callbacks( Create, Destroy )
vlc_module_end ()
221

222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
/*****************************************************************************
 * fbosd_render_t: render descriptor
 *****************************************************************************/
struct fbosd_render_t
{
#define FBOSD_RENDER_IMAGE 0
#define FBOSD_RENDER_TEXT  1
    int             i_type;

#define FBOSD_STATE_FREE     0
#define FBOSD_STATE_RESERVED 1
#define FBOSD_STATE_RENDER   2
    int             i_state;

    /* Font style */
237
    text_style_t*   p_text_style;                            /* font control */
238 239
    char            *psz_string;

Rafaël Carré's avatar
Typo  
Rafaël Carré committed
240
    /* Position */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
241
    bool            b_absolute;
242 243 244 245 246 247 248
    int             i_x;
    int             i_y;
    int             i_pos;
    int             i_alpha;                      /* transparency for images */
};
#define FBOSD_RENDER_MAX 10

249 250 251 252 253 254 255 256
/*****************************************************************************
 * intf_sys_t: interface framebuffer method descriptor
 *****************************************************************************/
struct intf_sys_t
{
    /* Framebuffer information */
    int                         i_fd;                       /* device handle */
    struct fb_var_screeninfo    var_info;        /* current mode information */
257
    bool                  b_pan;     /* does device supports panning ? */
258 259 260 261 262 263 264 265 266 267 268 269 270 271
    struct fb_cmap              fb_cmap;                /* original colormap */
    uint16_t                    *p_palette;              /* original palette */

    /* Overlay framebuffer format */
    video_format_t  fmt_out;
    picture_t       *p_overlay;
    size_t          i_page_size;                                /* page size */
    int             i_width;
    int             i_height;
    int             i_aspect;
    int             i_bytes_per_pixel;

    /* Image and Picture rendering */
    image_handler_t *p_image;
272
#if defined(FBOSD_BLENDING)
273 274 275 276
    filter_t *p_blend;                              /* alpha blending module */
#endif
    filter_t *p_text;                                /* text renderer module */

277 278
    /* Render */
    struct fbosd_render_t render[FBOSD_RENDER_MAX];
279 280 281 282

    /* Font style */
    text_style_t    *p_style;                                /* font control */

Rafaël Carré's avatar
Typo  
Rafaël Carré committed
283
    /* Position */
284
    bool      b_absolute;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
285 286 287
    int       i_x;
    int       i_y;
    int       i_pos;
288

Jean-Paul Saman's avatar
Jean-Paul Saman committed
289
    int       i_alpha;                      /* transparency for images */
290 291

    /* commands control */
292 293 294
    bool      b_need_update;    /* update display with \overlay buffer */
    bool      b_clear;      /* clear overlay buffer make it tranparent */
    bool      b_render;   /* render an image or text in overlay buffer */
295 296 297 298 299 300 301 302 303 304
};

/*****************************************************************************
 * Create: allocates FB interface thread output method
 *****************************************************************************/
static int Create( vlc_object_t *p_this )
{
    intf_thread_t *p_intf = (intf_thread_t *)p_this;
    intf_sys_t    *p_sys;
    char          *psz_aspect;
305 306 307
    char          *psz_tmp;
    int i;

308
    /* Allocate instance and initialize some members */
ivoire's avatar
fbosd:  
ivoire committed
309
    p_intf->p_sys = p_sys = calloc( 1, sizeof( intf_sys_t ) );
310 311 312
    if( !p_intf->p_sys )
        return VLC_ENOMEM;

basOS G's avatar
basOS G committed
313
    p_sys->p_style = text_style_New();
314 315 316 317 318 319 320 321 322 323 324
    if( !p_sys->p_style )
    {
        free( p_intf->p_sys );
        return VLC_ENOMEM;
    }

    p_intf->pf_run = Run;

    p_sys->p_image = image_HandlerCreate( p_this );
    if( !p_sys->p_image )
    {
basOS G's avatar
basOS G committed
325
        text_style_Delete( p_sys->p_style );
ivoire's avatar
fbosd:  
ivoire committed
326
        free( p_sys );
327 328 329 330 331
        return VLC_ENOMEM;
    }

    p_sys->i_alpha = var_CreateGetIntegerCommand( p_intf, "fbosd-alpha" );
    var_AddCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
332

Laurent Aimar's avatar
Laurent Aimar committed
333 334 335 336
    /* Use PAL by default */
    p_sys->i_width  = p_sys->fmt_out.i_width  = 704;
    p_sys->i_height = p_sys->fmt_out.i_height = 576;

337 338 339 340 341 342 343 344 345 346 347 348
    p_sys->i_aspect = -1;
    psz_aspect =
            var_CreateGetNonEmptyString( p_intf, "fbosd-aspect-ratio" );
    if( psz_aspect )
    {
        char *psz_parser = strchr( psz_aspect, ':' );

        if( psz_parser )
        {
            *psz_parser++ = '\0';
            p_sys->i_aspect = ( atoi( psz_aspect )
                              * VOUT_ASPECT_FACTOR ) / atoi( psz_parser );
Laurent Aimar's avatar
Laurent Aimar committed
349 350
            p_sys->fmt_out.i_sar_num = p_sys->i_aspect    * p_sys->i_height;
            p_sys->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR * p_sys->i_width;
351 352 353 354 355 356 357
        }
        msg_Dbg( p_intf, "using aspect ratio %d:%d",
                  atoi( psz_aspect ), atoi( psz_parser ) );

        free( psz_aspect );
    }

358
    psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-image" );
359
    var_AddCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
360 361 362 363 364 365 366
    if( psz_tmp && *psz_tmp )
    {
        p_sys->render[0].i_type = FBOSD_RENDER_IMAGE;
        p_sys->render[0].i_state = FBOSD_STATE_RENDER;
        p_sys->render[0].psz_string = strdup( psz_tmp );
    }
    free( psz_tmp );
367

368
    psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-text" );
369
    var_AddCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
370 371 372 373 374 375 376
    if( psz_tmp && *psz_tmp )
    {
        p_sys->render[1].i_type = FBOSD_RENDER_TEXT;
        p_sys->render[1].i_state = FBOSD_STATE_RENDER;
        p_sys->render[1].psz_string = strdup( psz_tmp );
    }
    free( psz_tmp );
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396

    p_sys->i_pos = var_CreateGetIntegerCommand( p_intf, "fbosd-position" );
    p_sys->i_x = var_CreateGetIntegerCommand( p_intf, "fbosd-x" );
    p_sys->i_y = var_CreateGetIntegerCommand( p_intf, "fbosd-y" );

    var_AddCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
    var_AddCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
    var_AddCallback( p_intf, "fbosd-y", OverlayCallback, NULL );

    p_sys->p_style->i_font_size =
            var_CreateGetIntegerCommand( p_intf, "fbosd-font-size" );
    p_sys->p_style->i_font_color =
            var_CreateGetIntegerCommand( p_intf, "fbosd-font-color" );
    p_sys->p_style->i_font_alpha = 255 -
            var_CreateGetIntegerCommand( p_intf, "fbosd-font-opacity" );

    var_AddCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
    var_AddCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
    var_AddCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );

397
    for( i = 0; i < FBOSD_RENDER_MAX; i++ )
398
        p_sys->render[i].p_text_style = text_style_New();
399

400 401 402 403 404 405 406 407 408
    p_sys->b_clear = var_CreateGetBoolCommand( p_intf, "fbosd-clear" );
    p_sys->b_render = var_CreateGetBoolCommand( p_intf, "fbosd-render" );
    p_sys->b_need_update = var_CreateGetBoolCommand( p_intf, "fbosd-display" );

    var_AddCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
    var_AddCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
    var_AddCallback( p_intf, "fbosd-display", OverlayCallback, NULL );

    /* Check if picture position was overridden */
409
    p_sys->b_absolute = true;
410 411
    if( ( p_sys->i_x >= 0 ) && ( p_sys->i_y >= 0 ) )
    {
412
        p_sys->b_absolute = false;
413 414 415 416 417 418
        p_sys->i_y = (p_sys->i_y < p_sys->i_height) ?
                        p_sys->i_y : p_sys->i_height;
        p_sys->i_x = (p_sys->i_x < p_sys->i_width) ?
                        p_sys->i_x : p_sys->i_width;
    }

419 420 421 422 423
    p_sys->render[0].i_x = p_sys->render[1].i_x = p_sys->i_x;
    p_sys->render[0].i_y = p_sys->render[1].i_y = p_sys->i_y;
    p_sys->render[0].i_pos = p_sys->render[1].i_pos = p_sys->i_pos;
    p_sys->render[0].i_alpha = p_sys->render[1].i_alpha = p_sys->i_alpha;

424 425 426 427 428 429 430 431 432
    /* Initialize framebuffer */
    if( OpenDisplay( p_intf ) )
    {
        Destroy( VLC_OBJECT(p_intf) );
        return VLC_EGENERIC;
    }

    Init( p_intf );

433
#if defined(FBOSD_BLENDING)
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
    /* Load the blending module */
    if( OpenBlending( p_intf ) )
    {
        msg_Err( p_intf, "Unable to load image blending module" );
        Destroy( VLC_OBJECT(p_intf) );
        return VLC_EGENERIC;
    }
#endif

    /* Load text renderer module */
    if( OpenTextRenderer( p_intf ) )
    {
        msg_Err( p_intf, "Unable to load text rendering module" );
        Destroy( VLC_OBJECT(p_intf) );
        return VLC_EGENERIC;
    }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
450

451 452
    p_sys->b_render = true;
    p_sys->b_need_update = true;
453 454 455 456 457 458 459 460 461 462 463 464

    return VLC_SUCCESS;
}

/*****************************************************************************
 * Destroy: destroy FB interface thread output method
 *****************************************************************************
 * Terminate an output method created by Create
 *****************************************************************************/
static void Destroy( vlc_object_t *p_this )
{
    intf_thread_t *p_intf = (intf_thread_t *)p_this;
ivoire's avatar
fbosd:  
ivoire committed
465
    intf_sys_t *p_sys = p_intf->p_sys;
466
    int i;
467

ivoire's avatar
fbosd:  
ivoire committed
468

469 470 471
    p_sys->b_need_update = false;
    p_sys->b_render = false;
    p_sys->b_clear = false;
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503

    var_DelCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
    var_Destroy( p_intf, "fbosd-alpha" );

    var_DelCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
    var_DelCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
    var_DelCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
    var_DelCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
    var_DelCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
    var_DelCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
    var_DelCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
    var_DelCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
    var_DelCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
    var_DelCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
    var_DelCallback( p_intf, "fbosd-display", OverlayCallback, NULL );

    var_Destroy( p_intf, "fbosd-x" );
    var_Destroy( p_intf, "fbosd-y" );
    var_Destroy( p_intf, "fbosd-position" );
    var_Destroy( p_intf, "fbosd-image" );
    var_Destroy( p_intf, "fbosd-text" );
    var_Destroy( p_intf, "fbosd-font-size" );
    var_Destroy( p_intf, "fbosd-font-color" );
    var_Destroy( p_intf, "fbosd-font-opacity" );
    var_Destroy( p_intf, "fbosd-clear" );
    var_Destroy( p_intf, "fbosd-render" );
    var_Destroy( p_intf, "fbosd-display" );

    var_Destroy( p_intf, "fbosd-aspect-ratio" );

    CloseDisplay( p_intf );

504 505 506 507
    for( i = 0; i < FBOSD_RENDER_MAX; i++ )
    {
        free( p_sys->render[i].psz_string );
        p_sys->render[i].i_state = FBOSD_STATE_FREE;
508
        text_style_Delete( p_sys->render[i].p_text_style );
509 510
    }

511
#if defined(FBOSD_BLENDING)
512 513 514
    if( p_sys->p_blend ) CloseBlending( p_intf );
#endif
    if( p_sys->p_text )  CloseTextRenderer( p_intf );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
515

516 517 518
    if( p_sys->p_image )
        image_HandlerDelete( p_sys->p_image );
    if( p_sys->p_overlay )
Laurent Aimar's avatar
Laurent Aimar committed
519
        picture_Release( p_sys->p_overlay );
520

basOS G's avatar
basOS G committed
521
    text_style_Delete( p_sys->p_style );
522 523 524
    free( p_sys );
}

525
#if defined(FBOSD_BLENDING)
526 527 528 529 530
static int OpenBlending( intf_thread_t *p_intf )
{
    if( p_intf->p_sys->p_blend ) return VLC_EGENERIC;

    p_intf->p_sys->p_blend =
531
            vlc_object_create( p_intf, sizeof(filter_t) );
532 533 534
    vlc_object_attach( p_intf->p_sys->p_blend, p_intf );
    p_intf->p_sys->p_blend->fmt_out.video.i_x_offset =
        p_intf->p_sys->p_blend->fmt_out.video.i_y_offset = 0;
Laurent Aimar's avatar
Laurent Aimar committed
535 536 537 538
    p_intf->p_sys->p_blend->fmt_out.video.i_sar_num =
            p_intf->p_sys->fmt_out.i_sar_num;
    p_intf->p_sys->p_blend->fmt_out.video.i_sar_den =
            p_intf->p_sys->fmt_out.i_sar_den;
539 540
    p_intf->p_sys->p_blend->fmt_out.video.i_chroma =
            p_intf->p_sys->fmt_out.i_chroma;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
541
    if( var_InheritInteger( p_intf, "freetype-yuvp" ) )
542
        p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
543
                VLC_CODEC_YUVP;
544 545
    else
        p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
546
                VLC_CODEC_YUVA;
547 548

    p_intf->p_sys->p_blend->p_module =
549
        module_need( p_intf->p_sys->p_blend, "video blending", NULL, false );
550 551 552 553 554 555 556 557 558 559 560 561

    if( !p_intf->p_sys->p_blend->p_module )
        return VLC_EGENERIC;

    return VLC_SUCCESS;
}

static void CloseBlending( intf_thread_t *p_intf )
{
    if( p_intf->p_sys->p_blend )
    {
        if( p_intf->p_sys->p_blend->p_module )
562
            module_unneed( p_intf->p_sys->p_blend,
563 564
                           p_intf->p_sys->p_blend->p_module );

565
        vlc_object_release( p_intf->p_sys->p_blend );
566 567 568 569 570 571 572 573 574 575 576
    }
}
#endif

static int OpenTextRenderer( intf_thread_t *p_intf )
{
    char *psz_modulename = NULL;

    if( p_intf->p_sys->p_text ) return VLC_EGENERIC;

    p_intf->p_sys->p_text =
577
            vlc_object_create( p_intf, sizeof(filter_t) );
578 579 580 581 582 583 584 585 586 587 588 589 590
    vlc_object_attach( p_intf->p_sys->p_text, p_intf );

    p_intf->p_sys->p_text->fmt_out.video.i_width =
        p_intf->p_sys->p_text->fmt_out.video.i_visible_width =
        p_intf->p_sys->i_width;
    p_intf->p_sys->p_text->fmt_out.video.i_height =
        p_intf->p_sys->p_text->fmt_out.video.i_visible_height =
        p_intf->p_sys->i_height;

    psz_modulename = var_CreateGetString( p_intf, "text-renderer" );
    if( psz_modulename && *psz_modulename )
    {
        p_intf->p_sys->p_text->p_module =
591
            module_need( p_intf->p_sys->p_text, "text renderer",
592
                            psz_modulename, true );
593 594 595 596
    }
    if( !p_intf->p_sys->p_text->p_module )
    {
        p_intf->p_sys->p_text->p_module =
597
            module_need( p_intf->p_sys->p_text, "text renderer", NULL, false );
598
    }
599
    free( psz_modulename );
600 601 602 603 604 605 606 607 608 609 610 611

    if( !p_intf->p_sys->p_text->p_module )
        return VLC_EGENERIC;

    return VLC_SUCCESS;
}

static void CloseTextRenderer( intf_thread_t *p_intf )
{
    if( p_intf->p_sys->p_text )
    {
        if( p_intf->p_sys->p_text->p_module )
612
            module_unneed( p_intf->p_sys->p_text,
613 614
                           p_intf->p_sys->p_text->p_module );

615
        vlc_object_release( p_intf->p_sys->p_text );
616 617 618 619 620 621 622
    }
}

/*****************************************************************************
 * AllocatePicture:
 * allocate a picture buffer for use with the overlay fb.
 *****************************************************************************/
623
static picture_t *AllocatePicture( video_format_t *p_fmt )
624
{
625
    picture_t *p_picture = picture_NewFromFormat( p_fmt );
Laurent Aimar's avatar
Laurent Aimar committed
626 627
    if( !p_picture )
        return NULL;
628 629

    if( !p_fmt->p_palette &&
630
        ( p_fmt->i_chroma == VLC_CODEC_YUVP ) )
631 632 633 634
    {
        p_fmt->p_palette = malloc( sizeof(video_palette_t) );
        if( !p_fmt->p_palette )
        {
Laurent Aimar's avatar
Laurent Aimar committed
635
            picture_Release( p_picture );
636 637 638
            return NULL;
        }
    }
Laurent Aimar's avatar
Laurent Aimar committed
639
    else
640
    {
Laurent Aimar's avatar
Laurent Aimar committed
641
        p_fmt->p_palette = NULL;
642
    }
Laurent Aimar's avatar
Laurent Aimar committed
643 644

    return p_picture;
645 646 647 648 649 650
}

/*****************************************************************************
 * DeAllocatePicture:
 * Deallocate a picture buffer and free all associated memory.
 *****************************************************************************/
651
static void DeAllocatePicture( picture_t *p_pic, video_format_t *p_fmt )
652
{
653
    if( p_fmt )
654 655 656 657
    {
        free( p_fmt->p_palette );
        p_fmt->p_palette = NULL;
    }
Laurent Aimar's avatar
Laurent Aimar committed
658 659 660

    if( p_pic )
        picture_Release( p_pic );
661 662 663 664
}

/*****************************************************************************
 * SetOverlayTransparency: Set the transparency for this overlay fb,
665 666
 * - true is make transparent
 * - false is make non tranparent
667 668
 *****************************************************************************/
static void SetOverlayTransparency( intf_thread_t *p_intf,
669
                                    bool b_transparent )
670
{
ivoire's avatar
fbosd:  
ivoire committed
671
    intf_sys_t *p_sys = p_intf->p_sys;
672 673 674 675 676 677 678 679 680 681 682
    size_t i_size = p_sys->fmt_out.i_width * p_sys->fmt_out.i_height
                        * p_sys->i_bytes_per_pixel;
    size_t i_page_size = (p_sys->i_page_size > i_size) ?
                            i_size : p_sys->i_page_size;

    if( p_sys->p_overlay )
    {
        msg_Dbg( p_intf, "Make overlay %s",
                 b_transparent ? "transparent" : "opaque" );
        if( b_transparent )
            memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, i_page_size );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
683 684
        else
            memset( p_sys->p_overlay->p[0].p_pixels, 0x00, i_page_size );
685 686 687
    }
}

688
#if defined(FBOSD_BLENDING)
689 690 691 692 693 694 695
/*****************************************************************************
 * BlendPicture: Blend two pictures together..
 *****************************************************************************/
static int BlendPicture( intf_thread_t *p_intf, video_format_t *p_fmt_src,
                         video_format_t *p_fmt_dst, picture_t *p_pic_src,
                         picture_t *p_pic_dst )
{
ivoire's avatar
fbosd:  
ivoire committed
696
    intf_sys_t *p_sys = p_intf->p_sys;
697 698 699 700 701 702
    if( p_sys->p_blend && p_sys->p_blend->p_module )
    {
        int i_x_offset = p_sys->i_x;
        int i_y_offset = p_sys->i_y;

        memcpy( &p_sys->p_blend->fmt_in.video, p_fmt_src, sizeof( video_format_t ) );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
703

704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723
        /* Update the output picture size */
        p_sys->p_blend->fmt_out.video.i_width =
            p_sys->p_blend->fmt_out.video.i_visible_width =
                p_fmt_dst->i_width;
        p_sys->p_blend->fmt_out.video.i_height =
            p_sys->p_blend->fmt_out.video.i_visible_height =
                p_fmt_dst->i_height;

        i_x_offset = __MAX( i_x_offset, 0 );
        i_y_offset = __MAX( i_y_offset, 0 );

        p_sys->p_blend->pf_video_blend( p_sys->p_blend, p_pic_dst,
            p_pic_src, p_pic_dst, i_x_offset, i_y_offset,
            p_sys->i_alpha );

        return VLC_SUCCESS;
    }
    return VLC_EGENERIC;
}

724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
static int InvertAlpha( intf_thread_t *p_intf, picture_t **p_pic, video_format_t fmt )
{
    uint8_t *p_begin = NULL, *p_end = NULL;
    uint8_t i_skip = 0;

    if( *p_pic && ((*p_pic)->i_planes != 1) )
    {
        msg_Err( p_intf,
                 "cannot invert alpha channel too many planes %d (only 1 supported)",
                 (*p_pic)->i_planes );
        return VLC_EGENERIC;
    }

    switch( fmt.i_chroma )
    {
739
        case VLC_CODEC_RGB24:
740 741 742 743 744
            p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
            p_end   = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
                      ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
            i_skip = 3;
            break;
745
        case VLC_CODEC_RGB32:
746 747 748 749 750 751 752 753 754 755 756 757 758
            p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
            p_end   = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
                      ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
            i_skip = 4;
            break;
        default:
            msg_Err( p_intf, "cannot invert alpha channel chroma not supported %4.4s",
                    (char *)&fmt.i_chroma );
            return VLC_EGENERIC;
    }

    for( ; p_begin < p_end; p_begin += i_skip )
    {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
759
        uint8_t i_opacity = 0;
760

Jean-Paul Saman's avatar
Jean-Paul Saman committed
761
        if( *p_begin != 0xFF )
762 763 764 765 766 767
            i_opacity = 255 - *p_begin;
        *p_begin = i_opacity;
    }
    /* end of kludge */
    return VLC_SUCCESS;
}
Jean-Paul Saman's avatar
Jean-Paul Saman committed
768
#endif
769

770 771 772 773 774 775 776 777 778
/*****************************************************************************
 * RenderPicture: Render the picture into the p_dest buffer.
 * We don't take transparent pixels into account, so we don't have to blend
 * the two images together.
 *****************************************************************************/
static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
                          picture_t *p_src, picture_t *p_dest )
{
    int i;
779
    VLC_UNUSED( p_intf );
780 781 782 783 784 785 786 787

    if( !p_dest && !p_src ) return VLC_EGENERIC;

    for( i = 0; i < p_src->i_planes ; i++ )
    {
        if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
        {
            /* There are margins, but with the same width : perfect ! */
788 789
            vlc_memcpy( p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
                        p_src->p[i].i_pitch * p_src->p[i].i_visible_lines );
790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805
        }
        else
        {
            /* We need to proceed line by line */
            uint8_t *p_in  = p_src->p[i].p_pixels;
            uint8_t *p_out = p_dest->p[i].p_pixels;

            int i_x = i_x_offset * p_src->p[i].i_pixel_pitch;
            int i_x_clip, i_y_clip;

            /* Check boundaries, clip the image if necessary */
            i_x_clip = ( i_x + p_src->p[i].i_visible_pitch ) - p_dest->p[i].i_visible_pitch;
            i_x_clip = ( i_x_clip > 0 ) ? i_x_clip : 0;

            i_y_clip = ( i_y_offset + p_src->p[i].i_visible_lines ) - p_dest->p[i].i_visible_lines;
            i_y_clip = ( i_y_clip > 0 ) ? i_y_clip : 0;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
806
#if defined(FBOSD_DEBUG)
807 808 809 810 811 812 813 814 815 816 817 818
            msg_Dbg( p_intf, "i_pitch (%d,%d), (%d,%d)/(%d,%d)",
                     p_dest->p[i].i_visible_pitch, p_src->p[i].i_visible_pitch,
                     i_x_offset, i_y_offset, i_x, i_x_clip );
#endif
            if( ( i_y_offset <= p_dest->p[i].i_visible_lines ) &&
                ( i_x <= p_dest->p[i].i_visible_pitch ) )
            {
                int i_line;

                p_out += ( i_y_offset * p_dest->p[i].i_pitch );
                for( i_line = 0; i_line < ( p_src->p[i].i_visible_lines - i_y_clip ); i_line++ )
                {
819 820
                    vlc_memcpy( p_out + i_x, p_in,
                                p_src->p[i].i_visible_pitch - i_x_clip );
821 822 823 824 825 826 827 828 829 830 831 832
                    p_in += p_src->p[i].i_pitch;
                    p_out += p_dest->p[i].i_pitch;
                }
            }
        }
    }
    return VLC_SUCCESS;
}

/*****************************************************************************
 * RenderText - Render text to the desired picture format
 *****************************************************************************/
833 834
static picture_t *RenderText( intf_thread_t *p_intf, const char *psz_string,
                              text_style_t *p_style, video_format_t *p_fmt )
835
{
ivoire's avatar
fbosd:  
ivoire committed
836
    intf_sys_t *p_sys = p_intf->p_sys;
837 838 839
    subpicture_region_t *p_region;
    picture_t *p_dest = NULL;

840
    if( !psz_string ) return p_dest;
841 842 843

    if( p_sys->p_text && p_sys->p_text->p_module )
    {
844 845 846
        video_format_t fmt;

        memset( &fmt, 0, sizeof(fmt) );
847
        fmt.i_chroma = VLC_CODEC_TEXT;
848 849 850 851 852 853
        fmt.i_width  = fmt.i_visible_width = 0;
        fmt.i_height = fmt.i_visible_height = 0;
        fmt.i_x_offset = 0;
        fmt.i_y_offset = 0;

        p_region = subpicture_region_New( &fmt );
854 855 856
        if( !p_region )
            return p_dest;

857
        p_region->psz_text = strdup( psz_string );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
858 859
        if( !p_region->psz_text )
        {
860
            subpicture_region_Delete( p_region );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
861 862
            return NULL;
        }
basOS G's avatar
basOS G committed
863
        p_region->p_style = text_style_Duplicate( p_style );
864 865 866 867 868 869 870 871 872 873 874
        p_region->i_align = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;

        if( p_sys->p_text->pf_render_text )
        {
            video_format_t fmt_out;

            memset( &fmt_out, 0, sizeof(video_format_t) );

            p_sys->p_text->pf_render_text( p_sys->p_text,
                                           p_region, p_region );

875
#if defined(FBOSD_BLENDING)
876 877
            fmt_out = p_region->fmt;
            fmt_out.i_bits_per_pixel = 32;
878
            vlc_memcpy( p_fmt, &fmt_out, sizeof(video_format_t) );
879

880
            /* FIXME not needed to copy the picture anymore no ? */
881 882 883
            p_dest = AllocatePicture( VLC_OBJECT(p_intf), &fmt_out );
            if( !p_dest )
            {
884
                subpicture_region_Delete( p_region );
885 886
                return NULL;
            }
887
            picture_Copy( p_dest, p_region->p_picture );
888 889
#else
            fmt_out.i_chroma = p_fmt->i_chroma;
ivoire's avatar
fbosd:  
ivoire committed
890
            p_dest = ConvertImage( p_intf, p_region->p_picture,
891
                                   &p_region->fmt, &fmt_out );
892
#endif
893
            subpicture_region_Delete( p_region );
894 895
            return p_dest;
        }
896
        subpicture_region_Delete( p_region );
897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926
    }
    return p_dest;
}

/*****************************************************************************
 * LoadImage: Load an image from file into a picture buffer.
 *****************************************************************************/
static picture_t *LoadImage( intf_thread_t *p_intf, video_format_t *p_fmt,
                             char *psz_file )
{
    picture_t  *p_pic = NULL;

    if( psz_file && p_intf->p_sys->p_image )
    {
        video_format_t fmt_in, fmt_out;

        memset( &fmt_in, 0, sizeof(fmt_in) );
        memset( &fmt_out, 0, sizeof(fmt_out) );

        fmt_out.i_chroma = p_fmt->i_chroma;
        p_pic = image_ReadUrl( p_intf->p_sys->p_image, psz_file,
                               &fmt_in, &fmt_out );

        msg_Dbg( p_intf, "image size %dx%d chroma %4.4s",
                 fmt_out.i_width, fmt_out.i_height,
                 (char *)&p_fmt->i_chroma );
    }
    return p_pic;
}

927
#if ! defined(FBOSD_BLENDING)
928 929 930 931 932 933
/*****************************************************************************
 * Convertmage: Convert image to another fourcc
 *****************************************************************************/
static picture_t *ConvertImage( intf_thread_t *p_intf, picture_t *p_pic,
                         video_format_t *p_fmt_in, video_format_t *p_fmt_out )
{
ivoire's avatar
fbosd:  
ivoire committed
934
    intf_sys_t *p_sys = p_intf->p_sys;
935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953
    picture_t  *p_old = NULL;

    if( p_sys->p_image )
    {
        p_old = image_Convert( p_sys->p_image, p_pic, p_fmt_in, p_fmt_out );

        msg_Dbg( p_intf, "converted image size %dx%d chroma %4.4s",
                 p_fmt_out->i_width, p_fmt_out->i_height,
                 (char *)&p_fmt_out->i_chroma );
    }
    return p_old;
}
#endif

/*****************************************************************************
 * Init: initialize framebuffer video thread output method
 *****************************************************************************/
static int Init( intf_thread_t *p_intf )
{
ivoire's avatar
fbosd:  
ivoire committed
954
    intf_sys_t *p_sys = p_intf->p_sys;
955 956 957 958 959 960

    /* Initialize the output structure: RGB with square pixels, whatever
     * the input format is, since it's the only format we know */
    switch( p_sys->var_info.bits_per_pixel )
    {
    case 8: /* FIXME: set the palette */
961
        p_sys->fmt_out.i_chroma = VLC_CODEC_RGB8; break;
962
    case 15:
963
        p_sys->fmt_out.i_chroma = VLC_CODEC_RGB15; break;
964
    case 16:
965
        p_sys->fmt_out.i_chroma = VLC_CODEC_RGB16; break;
966
    case 24:
967
        p_sys->fmt_out.i_chroma = VLC_CODEC_RGB24; break;
968
    case 32:
969
        p_sys->fmt_out.i_chroma = VLC_CODEC_RGB32; break;
970 971 972 973 974 975 976 977 978 979 980 981 982
    default:
        msg_Err( p_intf, "unknown screen depth %i",
                 p_sys->var_info.bits_per_pixel );
        return VLC_EGENERIC;
    }

    p_sys->fmt_out.i_bits_per_pixel = p_sys->var_info.bits_per_pixel;
    p_sys->fmt_out.i_width  = p_sys->i_width;
    p_sys->fmt_out.i_height = p_sys->i_height;

    /* Assume we have square pixels */
    if( p_sys->i_aspect < 0 )
    {
Laurent Aimar's avatar
Laurent Aimar committed
983 984 985 986 987 988 989
        p_sys->fmt_out.i_sar_num = 1;
        p_sys->fmt_out.i_sar_den = 1;
    }
    else
    {
        p_sys->fmt_out.i_sar_num = p_sys->i_aspect    * p_sys->i_height;
        p_sys->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR * p_sys->i_width;
990 991 992
    }

    /* Allocate overlay buffer */
993
    p_sys->p_overlay = AllocatePicture( &p_sys->fmt_out );
994 995
    if( !p_sys->p_overlay ) return VLC_EGENERIC;

996
    SetOverlayTransparency( p_intf, true );
997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027

    /* We know the chroma, allocate a buffer which will be used
     * to write to the overlay framebuffer */
    p_sys->p_overlay->p->i_pixel_pitch = p_sys->i_bytes_per_pixel;
    p_sys->p_overlay->p->i_lines = p_sys->var_info.yres;
    p_sys->p_overlay->p->i_visible_lines = p_sys->var_info.yres;

    if( p_sys->var_info.xres_virtual )
    {
        p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres_virtual
                             * p_sys->i_bytes_per_pixel;
    }
    else
    {
        p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres
                             * p_sys->i_bytes_per_pixel;
    }

    p_sys->p_overlay->p->i_visible_pitch = p_sys->var_info.xres
                                 * p_sys->i_bytes_per_pixel;

    p_sys->p_overlay->i_planes = 1;

    return VLC_SUCCESS;
}

/*****************************************************************************
 * End: terminate framebuffer interface
 *****************************************************************************/
static void End( intf_thread_t *p_intf )
{
ivoire's avatar
fbosd:  
ivoire committed
1028
    intf_sys_t *p_sys = p_intf->p_sys;
1029 1030

    /* CleanUp */
1031
    SetOverlayTransparency( p_intf, false );
1032 1033
    if( p_sys->p_overlay )
    {
1034
        int ret;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
1035 1036
        ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
                     p_sys->i_page_size );
1037 1038
        if( ret < 0 )
            msg_Err( p_intf, "unable to clear overlay" );
1039 1040
    }

1041
    DeAllocatePicture( p_intf->p_sys->p_overlay,
1042 1043 1044 1045 1046 1047 1048 1049 1050
                       &p_intf->p_sys->fmt_out );
    p_intf->p_sys->p_overlay = NULL;
}

/*****************************************************************************
 * OpenDisplay: initialize framebuffer
 *****************************************************************************/
static int OpenDisplay( intf_thread_t *p_intf )
{
ivoire's avatar
fbosd:  
ivoire committed
1051
    intf_sys_t *p_sys = p_intf->p_sys;
1052 1053 1054 1055
    char *psz_device;                             /* framebuffer device path */
    struct fb_fix_screeninfo    fix_info;     /* framebuffer fix information */

    /* Open framebuffer device */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
1056
    if( !(psz_device = var_InheritString( p_intf, "fbosd-dev" )) )
1057 1058 1059 1060 1061
    {
        msg_Err( p_intf, "don't know which fb osd/overlay device to open" );
        return VLC_EGENERIC;
    }

1062
    p_sys->i_fd = utf8_open( psz_device, O_RDWR );
1063 1064
    if( p_sys->i_fd == -1 )
    {
1065
        msg_Err( p_intf, "cannot open %s (%m)", psz_device );
1066 1067 1068 1069 1070 1071 1072 1073
        free( psz_device );
        return VLC_EGENERIC;
    }
    free( psz_device );

    /* Get framebuffer device information */
    if( ioctl( p_sys->i_fd, FBIOGET_VSCREENINFO, &p_sys->var_info ) )
    {
1074
        msg_Err( p_intf, "cannot get fb info (%m)" );
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112