services_discovery: implement SD categories and use in Qt interface
[vlc.git] / src / video_output / video_epg.c
blob5bb6f0c2af4f596c33fcf3809def619c597ac3ab
1 /*****************************************************************************
2 * video_epg.c : EPG manipulation functions
3 *****************************************************************************
4 * Copyright (C) 2010 Adrien Maglo
6 * Author: Adrien Maglo <magsoft@videolan.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #include <vlc_common.h>
28 #include <vlc_vout.h>
29 #include <vlc_block.h>
30 #include <vlc_filter.h>
31 #include <vlc_osd.h>
32 #include <vlc_events.h>
33 #include <vlc_input_item.h>
34 #include <vlc_epg.h>
37 /* Layout percentage defines */
38 #define EPG_TOP 0.7
39 #define EPG_LEFT 0.1
40 #define EPG_NAME_SIZE 0.05
41 #define EPG_PROGRAM_SIZE 0.03
43 #define NO_EPG N_( "No EPG found for this program." )
46 static subpicture_region_t * vout_OSDEpgSlider( vout_thread_t *p_vout,
47 int i_x, int i_y,
48 int i_width, int i_height,
49 float f_ratio )
51 video_format_t fmt;
52 subpicture_region_t *p_region;
54 /* Create a new subpicture region */
55 video_format_Init( &fmt, VLC_CODEC_YUVA );
56 fmt.i_width = fmt.i_visible_width = i_width;
57 fmt.i_height = fmt.i_visible_height = i_height;
58 fmt.i_sar_num = 0;
59 fmt.i_sar_den = 1;
61 p_region = subpicture_region_New( &fmt );
62 if( !p_region )
64 msg_Err( p_vout, "Cannot allocate SPU region." );
65 return NULL;
68 p_region->i_x = i_x;
69 p_region->i_y = i_y;
71 picture_t *p_picture = p_region->p_picture;
73 f_ratio = __MIN( __MAX( f_ratio, 0 ), 1 );
74 int i_filled_part_width = f_ratio * i_width;
76 for( int j = 0; j < i_height; j++ )
78 for( int i = 0; i < i_width; i++ )
80 #define WRITE_COMP( plane, value ) \
81 p_picture->p[plane].p_pixels[p_picture->p[plane].i_pitch * j + i] = value
83 /* Draw the slider. */
84 bool is_outline = j == 0 || j == i_height - 1
85 || i == 0 || i == i_width - 1;
86 WRITE_COMP( 0, is_outline ? 0x00 : 0xff );
87 WRITE_COMP( 1, 0x80 );
88 WRITE_COMP( 2, 0x80 );
90 /* We can see the video through the part of the slider
91 which corresponds to the leaving time. */
92 bool is_border = j < 3 || j > i_height - 4
93 || i < 3 || i > i_width - 4
94 || i < i_filled_part_width;
95 WRITE_COMP( 3, is_border ? 0xff : 0x00 );
97 #undef WRITE_COMP
101 return p_region;
105 static subpicture_region_t * vout_OSDEpgText( vout_thread_t *p_vout,
106 const char *psz_string,
107 int i_x, int i_y,
108 int i_size, uint32_t i_color )
110 video_format_t fmt;
111 subpicture_region_t *p_region;
113 if( !psz_string )
114 return NULL;
116 /* Create a new subpicture region */
117 video_format_Init( &fmt, VLC_CODEC_TEXT );
118 fmt.i_sar_num = 0;
119 fmt.i_sar_den = 1;
121 p_region = subpicture_region_New( &fmt );
122 if( !p_region )
124 msg_Err( p_vout, "Cannot allocate SPU region." );
125 return NULL;
128 /* Set subpicture parameters */
129 p_region->psz_text = strdup( psz_string );
130 p_region->i_align = 0;
131 p_region->i_x = i_x;
132 p_region->i_y = i_y;
134 /* Set text style */
135 p_region->p_style = text_style_New();
136 if( p_region->p_style )
138 p_region->p_style->i_font_size = i_size;
139 p_region->p_style->i_font_color = i_color;
140 p_region->p_style->i_font_alpha = 0;
143 return p_region;
147 static subpicture_region_t * vout_BuildOSDEpg( vout_thread_t *p_vout,
148 vlc_epg_t *p_epg,
149 int i_visible_width,
150 int i_visible_height )
152 subpicture_region_t *p_region_ret;
153 subpicture_region_t **pp_region = &p_region_ret;
155 time_t i_test = time( NULL );
157 /* Display the name of the channel. */
158 *pp_region = vout_OSDEpgText( p_vout,
159 p_epg->psz_name,
160 i_visible_width * EPG_LEFT,
161 i_visible_height * EPG_TOP,
162 i_visible_height * EPG_NAME_SIZE,
163 0x00ffffff );
165 if( !*pp_region )
166 return p_region_ret;
168 /* Display the name of the current program. */
169 pp_region = &(* pp_region)->p_next;
170 *pp_region = vout_OSDEpgText( p_vout, p_epg->p_current->psz_name,
171 i_visible_width * ( EPG_LEFT + 0.025 ),
172 i_visible_height * ( EPG_TOP + 0.05 ),
173 i_visible_height * EPG_PROGRAM_SIZE,
174 0x00ffffff );
176 if( !*pp_region )
177 return p_region_ret;
179 /* Display the current program time slider. */
180 pp_region = &(* pp_region)->p_next;
181 *pp_region = vout_OSDEpgSlider( p_vout,
182 i_visible_width * EPG_LEFT,
183 i_visible_height * ( EPG_TOP + 0.1 ),
184 i_visible_width * ( 1 - 2 * EPG_LEFT ),
185 i_visible_height * 0.05,
186 ( i_test - p_epg->p_current->i_start )
187 / (float)p_epg->p_current->i_duration );
189 if( !*pp_region )
190 return p_region_ret;
192 /* Format the hours of the beginning and the end of the current program. */
193 struct tm tm_start, tm_end;
194 time_t t_start = p_epg->p_current->i_start;
195 time_t t_end = p_epg->p_current->i_start + p_epg->p_current->i_duration;
196 localtime_r( &t_start, &tm_start );
197 localtime_r( &t_end, &tm_end );
198 char psz_start[128];
199 char psz_end[128];
200 snprintf( psz_start, sizeof(psz_start), "%2.2d:%2.2d",
201 tm_start.tm_hour, tm_start.tm_min );
202 snprintf( psz_end, sizeof(psz_end), "%2.2d:%2.2d",
203 tm_end.tm_hour, tm_end.tm_min );
205 /* Display those hours. */
206 pp_region = &(* pp_region)->p_next;
207 *pp_region = vout_OSDEpgText( p_vout, psz_start,
208 i_visible_width * ( EPG_LEFT + 0.02 ),
209 i_visible_height * ( EPG_TOP + 0.15 ),
210 i_visible_height * EPG_PROGRAM_SIZE,
211 0x00ffffff );
213 if( !*pp_region )
214 return p_region_ret;
216 pp_region = &(* pp_region)->p_next;
217 *pp_region = vout_OSDEpgText( p_vout, psz_end,
218 i_visible_width * ( 1 - EPG_LEFT - 0.085 ),
219 i_visible_height * ( EPG_TOP + 0.15 ),
220 i_visible_height * EPG_PROGRAM_SIZE,
221 0x00ffffff );
223 return p_region_ret;
228 * \brief Show EPG information about the current program of an input item
229 * \param p_vout pointer to the vout the information is to be showed on
230 * \param p_input pointer to the input item the information is to be showed
232 int vout_OSDEpg( vout_thread_t *p_vout, input_item_t *p_input )
234 subpicture_t *p_spu;
235 mtime_t i_now = mdate();
237 char *psz_now_playing = input_item_GetNowPlaying( p_input );
238 vlc_epg_t *p_epg = NULL;
240 vlc_mutex_lock( &p_input->lock );
242 /* Look for the current program EPG event */
243 for( int i = 0; i < p_input->i_epg; i++ )
245 vlc_epg_t *p_tmp = p_input->pp_epg[i];
247 if( p_tmp->p_current && p_tmp->p_current->psz_name
248 && psz_now_playing != NULL
249 && !strcmp( p_tmp->p_current->psz_name, psz_now_playing ) )
251 p_epg = vlc_epg_New( p_tmp->psz_name );
252 vlc_epg_Merge( p_epg, p_tmp );
253 break;
257 vlc_mutex_unlock( &p_input->lock );
259 /* If no EPG event has been found. */
260 if( p_epg == NULL )
261 return VLC_EGENERIC;
263 p_spu = subpicture_New();
264 if( !p_spu )
266 vlc_epg_Delete( p_epg );
267 return VLC_EGENERIC;
270 p_spu->i_channel = DEFAULT_CHAN;
271 p_spu->i_start = i_now;
272 p_spu->i_stop = i_now + 3000 * INT64_C(1000);
273 p_spu->b_ephemer = true;
274 p_spu->b_absolute = true;
275 p_spu->b_fade = true;
277 /* Build the EPG event subpictures. */
278 p_spu->p_region = vout_BuildOSDEpg( p_vout, p_epg,
279 p_vout->fmt_in.i_width,
280 p_vout->fmt_in.i_height );
282 vlc_epg_Delete( p_epg );
283 spu_DisplaySubpicture( p_vout->p_spu, p_spu );
285 return VLC_SUCCESS;